OpenVDB  4.0.2
VolumeToMesh.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2017 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
30 
36 
37 #ifndef OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED
38 #define OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED
39 
40 #include <openvdb/Platform.h> // for OPENVDB_HAS_CXX11
41 #include <openvdb/math/Operators.h> // for ISGradient
43 #include <openvdb/util/Util.h> // for INVALID_IDX
44 
45 #include <boost/integer_traits.hpp>
46 #include <boost/scoped_array.hpp>
47 
48 #include <tbb/blocked_range.h>
49 #include <tbb/parallel_for.h>
50 #include <tbb/parallel_reduce.h>
51 #include <tbb/task_scheduler_init.h>
52 
53 #include <cmath> // for std::isfinite()
54 #include <map>
55 #include <memory> // for auto_ptr/unique_ptr
56 #include <set>
57 #include <type_traits>
58 #include <vector>
59 
60 
61 namespace openvdb {
63 namespace OPENVDB_VERSION_NAME {
64 namespace tools {
65 
66 
68 
69 
70 // Wrapper functions for the VolumeToMesh converter
71 
72 
81 template<typename GridType>
82 inline void
84  const GridType& grid,
85  std::vector<Vec3s>& points,
86  std::vector<Vec4I>& quads,
87  double isovalue = 0.0);
88 
89 
102 template<typename GridType>
103 inline void
105  const GridType& grid,
106  std::vector<Vec3s>& points,
107  std::vector<Vec3I>& triangles,
108  std::vector<Vec4I>& quads,
109  double isovalue = 0.0,
110  double adaptivity = 0.0,
111  bool relaxDisorientedTriangles = true);
112 
113 
115 
116 
119 
120 
123 {
124 public:
125 
126  inline PolygonPool();
127  inline PolygonPool(const size_t numQuads, const size_t numTriangles);
128 
129  inline void copy(const PolygonPool& rhs);
130 
131  inline void resetQuads(size_t size);
132  inline void clearQuads();
133 
134  inline void resetTriangles(size_t size);
135  inline void clearTriangles();
136 
137 
138  // polygon accessor methods
139 
140  const size_t& numQuads() const { return mNumQuads; }
141 
142  openvdb::Vec4I& quad(size_t n) { return mQuads[n]; }
143  const openvdb::Vec4I& quad(size_t n) const { return mQuads[n]; }
144 
145 
146  const size_t& numTriangles() const { return mNumTriangles; }
147 
148  openvdb::Vec3I& triangle(size_t n) { return mTriangles[n]; }
149  const openvdb::Vec3I& triangle(size_t n) const { return mTriangles[n]; }
150 
151 
152  // polygon flags accessor methods
153 
154  char& quadFlags(size_t n) { return mQuadFlags[n]; }
155  const char& quadFlags(size_t n) const { return mQuadFlags[n]; }
156 
157  char& triangleFlags(size_t n) { return mTriangleFlags[n]; }
158  const char& triangleFlags(size_t n) const { return mTriangleFlags[n]; }
159 
160 
161  // reduce the polygon containers, n has to
162  // be smaller than the current container size.
163 
164  inline bool trimQuads(const size_t n, bool reallocate = false);
165  inline bool trimTrinagles(const size_t n, bool reallocate = false);
166 
167 private:
168  // disallow copy by assignment
169  void operator=(const PolygonPool&) {}
170 
171  size_t mNumQuads, mNumTriangles;
172  boost::scoped_array<openvdb::Vec4I> mQuads;
173  boost::scoped_array<openvdb::Vec3I> mTriangles;
174  boost::scoped_array<char> mQuadFlags, mTriangleFlags;
175 };
176 
177 
180 using PointList = boost::scoped_array<openvdb::Vec3s>;
181 using PolygonPoolList = boost::scoped_array<PolygonPool>;
183 
184 
186 
187 
190 {
191 
196  VolumeToMesh(double isovalue = 0, double adaptivity = 0, bool relaxDisorientedTriangles = true);
197 
199 
200  // Mesh data accessors
201 
202  const size_t& pointListSize() const;
203  PointList& pointList();
204 
205  const size_t& polygonPoolListSize() const;
206  PolygonPoolList& polygonPoolList();
207  const PolygonPoolList& polygonPoolList() const;
208 
209  std::vector<uint8_t>& pointFlags();
210  const std::vector<uint8_t>& pointFlags() const;
211 
212 
214 
215 
218  template<typename InputGridType>
219  void operator()(const InputGridType&);
220 
221 
223 
224 
246  void setRefGrid(const GridBase::ConstPtr& grid, double secAdaptivity = 0);
247 
248 
252  void setSurfaceMask(const GridBase::ConstPtr& mask, bool invertMask = false);
253 
256  void setSpatialAdaptivity(const GridBase::ConstPtr& grid);
257 
258 
261  void setAdaptivityMask(const TreeBase::ConstPtr& tree);
262 
263 private:
264  // Disallow copying
265  VolumeToMesh(const VolumeToMesh&);
266  VolumeToMesh& operator=(const VolumeToMesh&);
267 
268 
269  PointList mPoints;
270  PolygonPoolList mPolygons;
271 
272  size_t mPointListSize, mSeamPointListSize, mPolygonPoolListSize;
273  double mIsovalue, mPrimAdaptivity, mSecAdaptivity;
274 
275  GridBase::ConstPtr mRefGrid, mSurfaceMaskGrid, mAdaptivityGrid;
276  TreeBase::ConstPtr mAdaptivityMaskTree;
277 
278  TreeBase::Ptr mRefSignTree, mRefIdxTree;
279 
280  bool mInvertSurfaceMask, mRelaxDisorientedTriangles;
281 
282  boost::scoped_array<uint32_t> mQuantizedSeamPoints;
283  std::vector<uint8_t> mPointFlags;
284 }; // struct VolumeToMesh
285 
286 
288 
289 
297  const std::vector<Vec3d>& points,
298  const std::vector<Vec3d>& normals)
299 {
300  using Mat3d = math::Mat3d;
301 
302  Vec3d avgPos(0.0);
303 
304  if (points.empty()) return avgPos;
305 
306  for (size_t n = 0, N = points.size(); n < N; ++n) {
307  avgPos += points[n];
308  }
309 
310  avgPos /= double(points.size());
311 
312  // Unique components of the 3x3 A^TA matrix, where A is
313  // the matrix of normals.
314  double m00=0,m01=0,m02=0,
315  m11=0,m12=0,
316  m22=0;
317 
318  // The rhs vector, A^Tb, where b = n dot p
319  Vec3d rhs(0.0);
320 
321  for (size_t n = 0, N = points.size(); n < N; ++n) {
322 
323  const Vec3d& n_ref = normals[n];
324 
325  // A^TA
326  m00 += n_ref[0] * n_ref[0]; // diagonal
327  m11 += n_ref[1] * n_ref[1];
328  m22 += n_ref[2] * n_ref[2];
329 
330  m01 += n_ref[0] * n_ref[1]; // Upper-tri
331  m02 += n_ref[0] * n_ref[2];
332  m12 += n_ref[1] * n_ref[2];
333 
334  // A^Tb (centered around the origin)
335  rhs += n_ref * n_ref.dot(points[n] - avgPos);
336  }
337 
338  Mat3d A(m00,m01,m02,
339  m01,m11,m12,
340  m02,m12,m22);
341 
342  /*
343  // Inverse
344  const double det = A.det();
345  if (det > 0.01) {
346  Mat3d A_inv = A.adjoint();
347  A_inv *= (1.0 / det);
348 
349  return avgPos + A_inv * rhs;
350  }
351  */
352 
353  // Compute the pseudo inverse
354 
355  math::Mat3d eigenVectors;
356  Vec3d eigenValues;
357 
358  diagonalizeSymmetricMatrix(A, eigenVectors, eigenValues, 300);
359 
360  Mat3d D = Mat3d::identity();
361 
362 
363  double tolerance = std::max(std::abs(eigenValues[0]), std::abs(eigenValues[1]));
364  tolerance = std::max(tolerance, std::abs(eigenValues[2]));
365  tolerance *= 0.01;
366 
367  int clamped = 0;
368  for (int i = 0; i < 3; ++i ) {
369  if (std::abs(eigenValues[i]) < tolerance) {
370  D[i][i] = 0.0;
371  ++clamped;
372  } else {
373  D[i][i] = 1.0 / eigenValues[i];
374  }
375  }
376 
377  // Assemble the pseudo inverse and calc. the intersection point
378  if (clamped < 3) {
379  Mat3d pseudoInv = eigenVectors * D * eigenVectors.transpose();
380  return avgPos + pseudoInv * rhs;
381  }
382 
383  return avgPos;
384 }
385 
386 
389 
390 
391 // Internal utility objects and implementation details
392 
393 
394 namespace volume_to_mesh_internal {
395 
396 template<typename ValueType>
397 struct FillArray
398 {
399  FillArray(ValueType* array, const ValueType& v) : mArray(array), mValue(v) { }
400 
401  void operator()(const tbb::blocked_range<size_t>& range) const {
402  const ValueType v = mValue;
403  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
404  mArray[n] = v;
405  }
406  }
407 
408  ValueType * const mArray;
409  const ValueType mValue;
410 };
411 
412 
413 template<typename ValueType>
414 inline void
415 fillArray(ValueType* array, const ValueType& val, const size_t length)
416 {
417  const auto grainSize = std::max<size_t>(
418  length / tbb::task_scheduler_init::default_num_threads(), 1024);
419  const tbb::blocked_range<size_t> range(0, length, grainSize);
420  tbb::parallel_for(range, FillArray<ValueType>(array, val), tbb::simple_partitioner());
421 }
422 
423 
425 enum { SIGNS = 0xFF, EDGES = 0xE00, INSIDE = 0x100,
426  XEDGE = 0x200, YEDGE = 0x400, ZEDGE = 0x800, SEAM = 0x1000};
427 
428 
430 const bool sAdaptable[256] = {
431  1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,
432  1,0,1,1,0,0,1,1,0,0,0,1,0,0,1,1,1,1,1,1,0,0,1,1,0,1,0,1,0,0,0,1,
433  1,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
434  1,0,1,1,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0,1,
435  1,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,0,1,1,0,1,1,1,0,1,
436  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,0,0,1,
437  1,0,0,0,1,0,1,0,1,1,0,0,1,1,1,1,1,1,0,0,1,0,0,0,1,1,0,0,1,1,0,1,
438  1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1};
439 
440 
442 const unsigned char sAmbiguousFace[256] = {
443  0,0,0,0,0,5,0,0,0,0,5,0,0,0,0,0,0,0,1,0,0,5,1,0,4,0,0,0,4,0,0,0,
444  0,1,0,0,2,0,0,0,0,1,5,0,2,0,0,0,0,0,0,0,2,0,0,0,4,0,0,0,0,0,0,0,
445  0,0,2,2,0,5,0,0,3,3,0,0,0,0,0,0,6,6,0,0,6,0,0,0,0,0,0,0,0,0,0,0,
446  0,1,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
447  0,4,0,4,3,0,3,0,0,0,5,0,0,0,0,0,0,0,1,0,3,0,0,0,0,0,0,0,0,0,0,0,
448  6,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
449  0,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
450  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
451 
452 
456 const unsigned char sEdgeGroupTable[256][13] = {
457  {0,0,0,0,0,0,0,0,0,0,0,0,0},{1,1,0,0,1,0,0,0,0,1,0,0,0},{1,1,1,0,0,0,0,0,0,0,1,0,0},
458  {1,0,1,0,1,0,0,0,0,1,1,0,0},{1,0,1,1,0,0,0,0,0,0,0,1,0},{1,1,1,1,1,0,0,0,0,1,0,1,0},
459  {1,1,0,1,0,0,0,0,0,0,1,1,0},{1,0,0,1,1,0,0,0,0,1,1,1,0},{1,0,0,1,1,0,0,0,0,0,0,0,1},
460  {1,1,0,1,0,0,0,0,0,1,0,0,1},{1,1,1,1,1,0,0,0,0,0,1,0,1},{1,0,1,1,0,0,0,0,0,1,1,0,1},
461  {1,0,1,0,1,0,0,0,0,0,0,1,1},{1,1,1,0,0,0,0,0,0,1,0,1,1},{1,1,0,0,1,0,0,0,0,0,1,1,1},
462  {1,0,0,0,0,0,0,0,0,1,1,1,1},{1,0,0,0,0,1,0,0,1,1,0,0,0},{1,1,0,0,1,1,0,0,1,0,0,0,0},
463  {1,1,1,0,0,1,0,0,1,1,1,0,0},{1,0,1,0,1,1,0,0,1,0,1,0,0},{2,0,1,1,0,2,0,0,2,2,0,1,0},
464  {1,1,1,1,1,1,0,0,1,0,0,1,0},{1,1,0,1,0,1,0,0,1,1,1,1,0},{1,0,0,1,1,1,0,0,1,0,1,1,0},
465  {1,0,0,1,1,1,0,0,1,1,0,0,1},{1,1,0,1,0,1,0,0,1,0,0,0,1},{2,2,1,1,2,1,0,0,1,2,1,0,1},
466  {1,0,1,1,0,1,0,0,1,0,1,0,1},{1,0,1,0,1,1,0,0,1,1,0,1,1},{1,1,1,0,0,1,0,0,1,0,0,1,1},
467  {2,1,0,0,1,2,0,0,2,1,2,2,2},{1,0,0,0,0,1,0,0,1,0,1,1,1},{1,0,0,0,0,1,1,0,0,0,1,0,0},
468  {1,1,0,0,1,1,1,0,0,1,1,0,0},{1,1,1,0,0,1,1,0,0,0,0,0,0},{1,0,1,0,1,1,1,0,0,1,0,0,0},
469  {1,0,1,1,0,1,1,0,0,0,1,1,0},{2,2,2,1,1,1,1,0,0,1,2,1,0},{1,1,0,1,0,1,1,0,0,0,0,1,0},
470  {1,0,0,1,1,1,1,0,0,1,0,1,0},{2,0,0,2,2,1,1,0,0,0,1,0,2},{1,1,0,1,0,1,1,0,0,1,1,0,1},
471  {1,1,1,1,1,1,1,0,0,0,0,0,1},{1,0,1,1,0,1,1,0,0,1,0,0,1},{1,0,1,0,1,1,1,0,0,0,1,1,1},
472  {2,1,1,0,0,2,2,0,0,2,1,2,2},{1,1,0,0,1,1,1,0,0,0,0,1,1},{1,0,0,0,0,1,1,0,0,1,0,1,1},
473  {1,0,0,0,0,0,1,0,1,1,1,0,0},{1,1,0,0,1,0,1,0,1,0,1,0,0},{1,1,1,0,0,0,1,0,1,1,0,0,0},
474  {1,0,1,0,1,0,1,0,1,0,0,0,0},{1,0,1,1,0,0,1,0,1,1,1,1,0},{2,1,1,2,2,0,2,0,2,0,1,2,0},
475  {1,1,0,1,0,0,1,0,1,1,0,1,0},{1,0,0,1,1,0,1,0,1,0,0,1,0},{1,0,0,1,1,0,1,0,1,1,1,0,1},
476  {1,1,0,1,0,0,1,0,1,0,1,0,1},{2,1,2,2,1,0,2,0,2,1,0,0,2},{1,0,1,1,0,0,1,0,1,0,0,0,1},
477  {2,0,2,0,2,0,1,0,1,2,2,1,1},{2,2,2,0,0,0,1,0,1,0,2,1,1},{2,2,0,0,2,0,1,0,1,2,0,1,1},
478  {1,0,0,0,0,0,1,0,1,0,0,1,1},{1,0,0,0,0,0,1,1,0,0,0,1,0},{2,1,0,0,1,0,2,2,0,1,0,2,0},
479  {1,1,1,0,0,0,1,1,0,0,1,1,0},{1,0,1,0,1,0,1,1,0,1,1,1,0},{1,0,1,1,0,0,1,1,0,0,0,0,0},
480  {1,1,1,1,1,0,1,1,0,1,0,0,0},{1,1,0,1,0,0,1,1,0,0,1,0,0},{1,0,0,1,1,0,1,1,0,1,1,0,0},
481  {1,0,0,1,1,0,1,1,0,0,0,1,1},{1,1,0,1,0,0,1,1,0,1,0,1,1},{2,1,2,2,1,0,1,1,0,0,1,2,1},
482  {2,0,1,1,0,0,2,2,0,2,2,1,2},{1,0,1,0,1,0,1,1,0,0,0,0,1},{1,1,1,0,0,0,1,1,0,1,0,0,1},
483  {1,1,0,0,1,0,1,1,0,0,1,0,1},{1,0,0,0,0,0,1,1,0,1,1,0,1},{1,0,0,0,0,1,1,1,1,1,0,1,0},
484  {1,1,0,0,1,1,1,1,1,0,0,1,0},{2,1,1,0,0,2,2,1,1,1,2,1,0},{2,0,2,0,2,1,1,2,2,0,1,2,0},
485  {1,0,1,1,0,1,1,1,1,1,0,0,0},{2,2,2,1,1,2,2,1,1,0,0,0,0},{2,2,0,2,0,1,1,2,2,2,1,0,0},
486  {2,0,0,1,1,2,2,1,1,0,2,0,0},{2,0,0,1,1,1,1,2,2,1,0,1,2},{2,2,0,2,0,2,2,1,1,0,0,2,1},
487  {4,3,2,2,3,4,4,1,1,3,4,2,1},{3,0,2,2,0,1,1,3,3,0,1,2,3},{2,0,2,0,2,2,2,1,1,2,0,0,1},
488  {2,1,1,0,0,1,1,2,2,0,0,0,2},{3,1,0,0,1,2,2,3,3,1,2,0,3},{2,0,0,0,0,1,1,2,2,0,1,0,2},
489  {1,0,0,0,0,1,0,1,0,0,1,1,0},{1,1,0,0,1,1,0,1,0,1,1,1,0},{1,1,1,0,0,1,0,1,0,0,0,1,0},
490  {1,0,1,0,1,1,0,1,0,1,0,1,0},{1,0,1,1,0,1,0,1,0,0,1,0,0},{2,1,1,2,2,2,0,2,0,2,1,0,0},
491  {1,1,0,1,0,1,0,1,0,0,0,0,0},{1,0,0,1,1,1,0,1,0,1,0,0,0},{1,0,0,1,1,1,0,1,0,0,1,1,1},
492  {2,2,0,2,0,1,0,1,0,1,2,2,1},{2,2,1,1,2,2,0,2,0,0,0,1,2},{2,0,2,2,0,1,0,1,0,1,0,2,1},
493  {1,0,1,0,1,1,0,1,0,0,1,0,1},{2,2,2,0,0,1,0,1,0,1,2,0,1},{1,1,0,0,1,1,0,1,0,0,0,0,1},
494  {1,0,0,0,0,1,0,1,0,1,0,0,1},{1,0,0,0,0,0,0,1,1,1,1,1,0},{1,1,0,0,1,0,0,1,1,0,1,1,0},
495  {1,1,1,0,0,0,0,1,1,1,0,1,0},{1,0,1,0,1,0,0,1,1,0,0,1,0},{1,0,1,1,0,0,0,1,1,1,1,0,0},
496  {2,2,2,1,1,0,0,1,1,0,2,0,0},{1,1,0,1,0,0,0,1,1,1,0,0,0},{1,0,0,1,1,0,0,1,1,0,0,0,0},
497  {2,0,0,2,2,0,0,1,1,2,2,2,1},{2,1,0,1,0,0,0,2,2,0,1,1,2},{3,2,1,1,2,0,0,3,3,2,0,1,3},
498  {2,0,1,1,0,0,0,2,2,0,0,1,2},{2,0,1,0,1,0,0,2,2,1,1,0,2},{2,1,1,0,0,0,0,2,2,0,1,0,2},
499  {2,1,0,0,1,0,0,2,2,1,0,0,2},{1,0,0,0,0,0,0,1,1,0,0,0,1},{1,0,0,0,0,0,0,1,1,0,0,0,1},
500  {1,1,0,0,1,0,0,1,1,1,0,0,1},{2,1,1,0,0,0,0,2,2,0,1,0,2},{1,0,1,0,1,0,0,1,1,1,1,0,1},
501  {1,0,1,1,0,0,0,1,1,0,0,1,1},{2,1,1,2,2,0,0,1,1,1,0,1,2},{1,1,0,1,0,0,0,1,1,0,1,1,1},
502  {2,0,0,1,1,0,0,2,2,2,2,2,1},{1,0,0,1,1,0,0,1,1,0,0,0,0},{1,1,0,1,0,0,0,1,1,1,0,0,0},
503  {1,1,1,1,1,0,0,1,1,0,1,0,0},{1,0,1,1,0,0,0,1,1,1,1,0,0},{1,0,1,0,1,0,0,1,1,0,0,1,0},
504  {1,1,1,0,0,0,0,1,1,1,0,1,0},{1,1,0,0,1,0,0,1,1,0,1,1,0},{1,0,0,0,0,0,0,1,1,1,1,1,0},
505  {1,0,0,0,0,1,0,1,0,1,0,0,1},{1,1,0,0,1,1,0,1,0,0,0,0,1},{1,1,1,0,0,1,0,1,0,1,1,0,1},
506  {1,0,1,0,1,1,0,1,0,0,1,0,1},{1,0,1,1,0,1,0,1,0,1,0,1,1},{2,2,2,1,1,2,0,2,0,0,0,2,1},
507  {2,1,0,1,0,2,0,2,0,1,2,2,1},{2,0,0,2,2,1,0,1,0,0,1,1,2},{1,0,0,1,1,1,0,1,0,1,0,0,0},
508  {1,1,0,1,0,1,0,1,0,0,0,0,0},{2,1,2,2,1,2,0,2,0,1,2,0,0},{1,0,1,1,0,1,0,1,0,0,1,0,0},
509  {1,0,1,0,1,1,0,1,0,1,0,1,0},{1,1,1,0,0,1,0,1,0,0,0,1,0},{2,2,0,0,2,1,0,1,0,2,1,1,0},
510  {1,0,0,0,0,1,0,1,0,0,1,1,0},{1,0,0,0,0,1,1,1,1,0,1,0,1},{2,1,0,0,1,2,1,1,2,2,1,0,1},
511  {1,1,1,0,0,1,1,1,1,0,0,0,1},{2,0,2,0,2,1,2,2,1,1,0,0,2},{2,0,1,1,0,1,2,2,1,0,1,2,1},
512  {4,1,1,3,3,2,4,4,2,2,1,4,3},{2,2,0,2,0,2,1,1,2,0,0,1,2},{3,0,0,1,1,2,3,3,2,2,0,3,1},
513  {1,0,0,1,1,1,1,1,1,0,1,0,0},{2,2,0,2,0,1,2,2,1,1,2,0,0},{2,2,1,1,2,2,1,1,2,0,0,0,0},
514  {2,0,1,1,0,2,1,1,2,2,0,0,0},{2,0,2,0,2,2,1,1,2,0,2,1,0},{3,1,1,0,0,3,2,2,3,3,1,2,0},
515  {2,1,0,0,1,1,2,2,1,0,0,2,0},{2,0,0,0,0,2,1,1,2,2,0,1,0},{1,0,0,0,0,0,1,1,0,1,1,0,1},
516  {1,1,0,0,1,0,1,1,0,0,1,0,1},{1,1,1,0,0,0,1,1,0,1,0,0,1},{1,0,1,0,1,0,1,1,0,0,0,0,1},
517  {2,0,2,2,0,0,1,1,0,2,2,1,2},{3,1,1,2,2,0,3,3,0,0,1,3,2},{2,1,0,1,0,0,2,2,0,1,0,2,1},
518  {2,0,0,1,1,0,2,2,0,0,0,2,1},{1,0,0,1,1,0,1,1,0,1,1,0,0},{1,1,0,1,0,0,1,1,0,0,1,0,0},
519  {2,2,1,1,2,0,1,1,0,2,0,0,0},{1,0,1,1,0,0,1,1,0,0,0,0,0},{2,0,1,0,1,0,2,2,0,1,1,2,0},
520  {2,1,1,0,0,0,2,2,0,0,1,2,0},{2,1,0,0,1,0,2,2,0,1,0,2,0},{1,0,0,0,0,0,1,1,0,0,0,1,0},
521  {1,0,0,0,0,0,1,0,1,0,0,1,1},{1,1,0,0,1,0,1,0,1,1,0,1,1},{1,1,1,0,0,0,1,0,1,0,1,1,1},
522  {2,0,2,0,2,0,1,0,1,1,1,2,2},{1,0,1,1,0,0,1,0,1,0,0,0,1},{2,2,2,1,1,0,2,0,2,2,0,0,1},
523  {1,1,0,1,0,0,1,0,1,0,1,0,1},{2,0,0,2,2,0,1,0,1,1,1,0,2},{1,0,0,1,1,0,1,0,1,0,0,1,0},
524  {1,1,0,1,0,0,1,0,1,1,0,1,0},{2,2,1,1,2,0,2,0,2,0,2,1,0},{2,0,2,2,0,0,1,0,1,1,1,2,0},
525  {1,0,1,0,1,0,1,0,1,0,0,0,0},{1,1,1,0,0,0,1,0,1,1,0,0,0},{1,1,0,0,1,0,1,0,1,0,1,0,0},
526  {1,0,0,0,0,0,1,0,1,1,1,0,0},{1,0,0,0,0,1,1,0,0,1,0,1,1},{1,1,0,0,1,1,1,0,0,0,0,1,1},
527  {2,2,2,0,0,1,1,0,0,2,1,2,2},{2,0,1,0,1,2,2,0,0,0,2,1,1},{1,0,1,1,0,1,1,0,0,1,0,0,1},
528  {2,1,1,2,2,1,1,0,0,0,0,0,2},{2,1,0,1,0,2,2,0,0,1,2,0,1},{2,0,0,2,2,1,1,0,0,0,1,0,2},
529  {1,0,0,1,1,1,1,0,0,1,0,1,0},{1,1,0,1,0,1,1,0,0,0,0,1,0},{3,1,2,2,1,3,3,0,0,1,3,2,0},
530  {2,0,1,1,0,2,2,0,0,0,2,1,0},{1,0,1,0,1,1,1,0,0,1,0,0,0},{1,1,1,0,0,1,1,0,0,0,0,0,0},
531  {2,2,0,0,2,1,1,0,0,2,1,0,0},{1,0,0,0,0,1,1,0,0,0,1,0,0},{1,0,0,0,0,1,0,0,1,0,1,1,1},
532  {2,2,0,0,2,1,0,0,1,1,2,2,2},{1,1,1,0,0,1,0,0,1,0,0,1,1},{2,0,1,0,1,2,0,0,2,2,0,1,1},
533  {1,0,1,1,0,1,0,0,1,0,1,0,1},{3,1,1,3,3,2,0,0,2,2,1,0,3},{1,1,0,1,0,1,0,0,1,0,0,0,1},
534  {2,0,0,2,2,1,0,0,1,1,0,0,2},{1,0,0,1,1,1,0,0,1,0,1,1,0},{2,1,0,1,0,2,0,0,2,2,1,1,0},
535  {2,1,2,2,1,1,0,0,1,0,0,2,0},{2,0,1,1,0,2,0,0,2,2,0,1,0},{1,0,1,0,1,1,0,0,1,0,1,0,0},
536  {2,1,1,0,0,2,0,0,2,2,1,0,0},{1,1,0,0,1,1,0,0,1,0,0,0,0},{1,0,0,0,0,1,0,0,1,1,0,0,0},
537  {1,0,0,0,0,0,0,0,0,1,1,1,1},{1,1,0,0,1,0,0,0,0,0,1,1,1},{1,1,1,0,0,0,0,0,0,1,0,1,1},
538  {1,0,1,0,1,0,0,0,0,0,0,1,1},{1,0,1,1,0,0,0,0,0,1,1,0,1},{2,1,1,2,2,0,0,0,0,0,1,0,2},
539  {1,1,0,1,0,0,0,0,0,1,0,0,1},{1,0,0,1,1,0,0,0,0,0,0,0,1},{1,0,0,1,1,0,0,0,0,1,1,1,0},
540  {1,1,0,1,0,0,0,0,0,0,1,1,0},{2,1,2,2,1,0,0,0,0,1,0,2,0},{1,0,1,1,0,0,0,0,0,0,0,1,0},
541  {1,0,1,0,1,0,0,0,0,1,1,0,0},{1,1,1,0,0,0,0,0,0,0,1,0,0},{1,1,0,0,1,0,0,0,0,1,0,0,0},
542  {0,0,0,0,0,0,0,0,0,0,0,0,0}};
543 
544 
546 
547 inline bool
549  const Vec3d& p0, const Vec3d& p1,
550  const Vec3d& p2, const Vec3d& p3,
551  double epsilon = 0.001)
552 {
553  // compute representative plane
554  Vec3d normal = (p2-p0).cross(p1-p3);
555  normal.normalize();
556  const Vec3d centroid = (p0 + p1 + p2 + p3);
557  const double d = centroid.dot(normal) * 0.25;
558 
559 
560  // test vertice distance to plane
561  double absDist = std::abs(p0.dot(normal) - d);
562  if (absDist > epsilon) return false;
563 
564  absDist = std::abs(p1.dot(normal) - d);
565  if (absDist > epsilon) return false;
566 
567  absDist = std::abs(p2.dot(normal) - d);
568  if (absDist > epsilon) return false;
569 
570  absDist = std::abs(p3.dot(normal) - d);
571  if (absDist > epsilon) return false;
572 
573  return true;
574 }
575 
576 
578 
579 
582 
583 enum {
584  MASK_FIRST_10_BITS = 0x000003FF,
585  MASK_DIRTY_BIT = 0x80000000,
586  MASK_INVALID_BIT = 0x40000000
587 };
588 
589 inline uint32_t
590 packPoint(const Vec3d& v)
591 {
592  uint32_t data = 0;
593 
594  // values are expected to be in the [0.0 to 1.0] range.
595  assert(!(v.x() > 1.0) && !(v.y() > 1.0) && !(v.z() > 1.0));
596  assert(!(v.x() < 0.0) && !(v.y() < 0.0) && !(v.z() < 0.0));
597 
598  data |= (uint32_t(v.x() * 1023.0) & MASK_FIRST_10_BITS) << 20;
599  data |= (uint32_t(v.y() * 1023.0) & MASK_FIRST_10_BITS) << 10;
600  data |= (uint32_t(v.z() * 1023.0) & MASK_FIRST_10_BITS);
601 
602  return data;
603 }
604 
605 inline Vec3d
606 unpackPoint(uint32_t data)
607 {
608  Vec3d v;
609  v.z() = double(data & MASK_FIRST_10_BITS) * 0.0009775171;
610  data = data >> 10;
611  v.y() = double(data & MASK_FIRST_10_BITS) * 0.0009775171;
612  data = data >> 10;
613  v.x() = double(data & MASK_FIRST_10_BITS) * 0.0009775171;
614 
615  return v;
616 }
617 
619 
621 
622 template<typename T>
623 inline bool isBoolValue() { return false; }
624 
625 template<>
626 inline bool isBoolValue<bool>() { return true; }
627 
628 
629 
630 template<typename T>
631 inline bool isInsideValue(T value, T isovalue) { return value < isovalue; }
632 
633 template<>
634 inline bool isInsideValue<bool>(bool value, bool /*isovalue*/) { return value; }
635 
636 
637 template<typename AccessorT>
638 inline void
639 getCellVertexValues(const AccessorT& accessor, Coord ijk,
641 {
642  values[0] = accessor.getValue(ijk); // i, j, k
643  ++ijk[0];
644  values[1] = accessor.getValue(ijk); // i+1, j, k
645  ++ijk[2];
646  values[2] = accessor.getValue(ijk); // i+1, j, k+1
647  --ijk[0];
648  values[3] = accessor.getValue(ijk); // i, j, k+1
649  --ijk[2]; ++ijk[1];
650  values[4] = accessor.getValue(ijk); // i, j+1, k
651  ++ijk[0];
652  values[5] = accessor.getValue(ijk); // i+1, j+1, k
653  ++ijk[2];
654  values[6] = accessor.getValue(ijk); // i+1, j+1, k+1
655  --ijk[0];
656  values[7] = accessor.getValue(ijk); // i, j+1, k+1
657 }
658 
659 
660 template<typename LeafT>
661 inline void
662 getCellVertexValues(const LeafT& leaf, const Index offset,
664 {
665  values[0] = leaf.getValue(offset); // i, j, k
666  values[3] = leaf.getValue(offset + 1); // i, j, k+1
667  values[4] = leaf.getValue(offset + LeafT::DIM); // i, j+1, k
668  values[7] = leaf.getValue(offset + LeafT::DIM + 1); // i, j+1, k+1
669  values[1] = leaf.getValue(offset + (LeafT::DIM * LeafT::DIM)); // i+1, j, k
670  values[2] = leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + 1); // i+1, j, k+1
671  values[5] = leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM); // i+1, j+1, k
672  values[6] = leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM + 1); // i+1, j+1, k+1
673 }
674 
675 
676 template<typename ValueType>
677 inline uint8_t
678 computeSignFlags(const math::Tuple<8, ValueType>& values, const ValueType iso)
679 {
680  unsigned signs = 0;
681  signs |= isInsideValue(values[0], iso) ? 1u : 0u;
682  signs |= isInsideValue(values[1], iso) ? 2u : 0u;
683  signs |= isInsideValue(values[2], iso) ? 4u : 0u;
684  signs |= isInsideValue(values[3], iso) ? 8u : 0u;
685  signs |= isInsideValue(values[4], iso) ? 16u : 0u;
686  signs |= isInsideValue(values[5], iso) ? 32u : 0u;
687  signs |= isInsideValue(values[6], iso) ? 64u : 0u;
688  signs |= isInsideValue(values[7], iso) ? 128u : 0u;
689  return uint8_t(signs);
690 }
691 
692 
695 template<typename AccessorT>
696 inline uint8_t
697 evalCellSigns(const AccessorT& accessor, const Coord& ijk, typename AccessorT::ValueType iso)
698 {
699  unsigned signs = 0;
700  Coord coord = ijk; // i, j, k
701  if (isInsideValue(accessor.getValue(coord), iso)) signs |= 1u;
702  coord[0] += 1; // i+1, j, k
703  if (isInsideValue(accessor.getValue(coord), iso)) signs |= 2u;
704  coord[2] += 1; // i+1, j, k+1
705  if (isInsideValue(accessor.getValue(coord), iso)) signs |= 4u;
706  coord[0] = ijk[0]; // i, j, k+1
707  if (isInsideValue(accessor.getValue(coord), iso)) signs |= 8u;
708  coord[1] += 1; coord[2] = ijk[2]; // i, j+1, k
709  if (isInsideValue(accessor.getValue(coord), iso)) signs |= 16u;
710  coord[0] += 1; // i+1, j+1, k
711  if (isInsideValue(accessor.getValue(coord), iso)) signs |= 32u;
712  coord[2] += 1; // i+1, j+1, k+1
713  if (isInsideValue(accessor.getValue(coord), iso)) signs |= 64u;
714  coord[0] = ijk[0]; // i, j+1, k+1
715  if (isInsideValue(accessor.getValue(coord), iso)) signs |= 128u;
716  return uint8_t(signs);
717 }
718 
719 
722 template<typename LeafT>
723 inline uint8_t
724 evalCellSigns(const LeafT& leaf, const Index offset, typename LeafT::ValueType iso)
725 {
726  unsigned signs = 0;
727 
728  // i, j, k
729  if (isInsideValue(leaf.getValue(offset), iso)) signs |= 1u;
730 
731  // i, j, k+1
732  if (isInsideValue(leaf.getValue(offset + 1), iso)) signs |= 8u;
733 
734  // i, j+1, k
735  if (isInsideValue(leaf.getValue(offset + LeafT::DIM), iso)) signs |= 16u;
736 
737  // i, j+1, k+1
738  if (isInsideValue(leaf.getValue(offset + LeafT::DIM + 1), iso)) signs |= 128u;
739 
740  // i+1, j, k
741  if (isInsideValue(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) ), iso)) signs |= 2u;
742 
743  // i+1, j, k+1
744  if (isInsideValue(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + 1), iso)) signs |= 4u;
745 
746  // i+1, j+1, k
747  if (isInsideValue(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM), iso)) signs |= 32u;
748 
749  // i+1, j+1, k+1
750  if (isInsideValue(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM + 1), iso)) signs |= 64u;
751 
752  return uint8_t(signs);
753 }
754 
755 
758 template<class AccessorT>
759 inline void
760 correctCellSigns(uint8_t& signs, uint8_t face,
761  const AccessorT& acc, Coord ijk, typename AccessorT::ValueType iso)
762 {
763  switch (int(face)) {
764  case 1:
765  ijk[2] -= 1;
766  if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 3) signs = uint8_t(~signs);
767  break;
768  case 2:
769  ijk[0] += 1;
770  if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 4) signs = uint8_t(~signs);
771  break;
772  case 3:
773  ijk[2] += 1;
774  if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 1) signs = uint8_t(~signs);
775  break;
776  case 4:
777  ijk[0] -= 1;
778  if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 2) signs = uint8_t(~signs);
779  break;
780  case 5:
781  ijk[1] -= 1;
782  if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 6) signs = uint8_t(~signs);
783  break;
784  case 6:
785  ijk[1] += 1;
786  if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 5) signs = uint8_t(~signs);
787  break;
788  default:
789  break;
790  }
791 }
792 
793 
794 template<class AccessorT>
795 inline bool
796 isNonManifold(const AccessorT& accessor, const Coord& ijk,
797  typename AccessorT::ValueType isovalue, const int dim)
798 {
799  int hDim = dim >> 1;
800  bool m, p[8]; // Corner signs
801 
802  Coord coord = ijk; // i, j, k
803  p[0] = isInsideValue(accessor.getValue(coord), isovalue);
804  coord[0] += dim; // i+dim, j, k
805  p[1] = isInsideValue(accessor.getValue(coord), isovalue);
806  coord[2] += dim; // i+dim, j, k+dim
807  p[2] = isInsideValue(accessor.getValue(coord), isovalue);
808  coord[0] = ijk[0]; // i, j, k+dim
809  p[3] = isInsideValue(accessor.getValue(coord), isovalue);
810  coord[1] += dim; coord[2] = ijk[2]; // i, j+dim, k
811  p[4] = isInsideValue(accessor.getValue(coord), isovalue);
812  coord[0] += dim; // i+dim, j+dim, k
813  p[5] = isInsideValue(accessor.getValue(coord), isovalue);
814  coord[2] += dim; // i+dim, j+dim, k+dim
815  p[6] = isInsideValue(accessor.getValue(coord), isovalue);
816  coord[0] = ijk[0]; // i, j+dim, k+dim
817  p[7] = isInsideValue(accessor.getValue(coord), isovalue);
818 
819  // Check if the corner sign configuration is ambiguous
820  unsigned signs = 0;
821  if (p[0]) signs |= 1u;
822  if (p[1]) signs |= 2u;
823  if (p[2]) signs |= 4u;
824  if (p[3]) signs |= 8u;
825  if (p[4]) signs |= 16u;
826  if (p[5]) signs |= 32u;
827  if (p[6]) signs |= 64u;
828  if (p[7]) signs |= 128u;
829  if (!sAdaptable[signs]) return true;
830 
831  // Manifold check
832 
833  // Evaluate edges
834  int i = ijk[0], ip = ijk[0] + hDim, ipp = ijk[0] + dim;
835  int j = ijk[1], jp = ijk[1] + hDim, jpp = ijk[1] + dim;
836  int k = ijk[2], kp = ijk[2] + hDim, kpp = ijk[2] + dim;
837 
838  // edge 1
839  coord.reset(ip, j, k);
840  m = isInsideValue(accessor.getValue(coord), isovalue);
841  if (p[0] != m && p[1] != m) return true;
842 
843  // edge 2
844  coord.reset(ipp, j, kp);
845  m = isInsideValue(accessor.getValue(coord), isovalue);
846  if (p[1] != m && p[2] != m) return true;
847 
848  // edge 3
849  coord.reset(ip, j, kpp);
850  m = isInsideValue(accessor.getValue(coord), isovalue);
851  if (p[2] != m && p[3] != m) return true;
852 
853  // edge 4
854  coord.reset(i, j, kp);
855  m = isInsideValue(accessor.getValue(coord), isovalue);
856  if (p[0] != m && p[3] != m) return true;
857 
858  // edge 5
859  coord.reset(ip, jpp, k);
860  m = isInsideValue(accessor.getValue(coord), isovalue);
861  if (p[4] != m && p[5] != m) return true;
862 
863  // edge 6
864  coord.reset(ipp, jpp, kp);
865  m = isInsideValue(accessor.getValue(coord), isovalue);
866  if (p[5] != m && p[6] != m) return true;
867 
868  // edge 7
869  coord.reset(ip, jpp, kpp);
870  m = isInsideValue(accessor.getValue(coord), isovalue);
871  if (p[6] != m && p[7] != m) return true;
872 
873  // edge 8
874  coord.reset(i, jpp, kp);
875  m = isInsideValue(accessor.getValue(coord), isovalue);
876  if (p[7] != m && p[4] != m) return true;
877 
878  // edge 9
879  coord.reset(i, jp, k);
880  m = isInsideValue(accessor.getValue(coord), isovalue);
881  if (p[0] != m && p[4] != m) return true;
882 
883  // edge 10
884  coord.reset(ipp, jp, k);
885  m = isInsideValue(accessor.getValue(coord), isovalue);
886  if (p[1] != m && p[5] != m) return true;
887 
888  // edge 11
889  coord.reset(ipp, jp, kpp);
890  m = isInsideValue(accessor.getValue(coord), isovalue);
891  if (p[2] != m && p[6] != m) return true;
892 
893 
894  // edge 12
895  coord.reset(i, jp, kpp);
896  m = isInsideValue(accessor.getValue(coord), isovalue);
897  if (p[3] != m && p[7] != m) return true;
898 
899 
900  // Evaluate faces
901 
902  // face 1
903  coord.reset(ip, jp, k);
904  m = isInsideValue(accessor.getValue(coord), isovalue);
905  if (p[0] != m && p[1] != m && p[4] != m && p[5] != m) return true;
906 
907  // face 2
908  coord.reset(ipp, jp, kp);
909  m = isInsideValue(accessor.getValue(coord), isovalue);
910  if (p[1] != m && p[2] != m && p[5] != m && p[6] != m) return true;
911 
912  // face 3
913  coord.reset(ip, jp, kpp);
914  m = isInsideValue(accessor.getValue(coord), isovalue);
915  if (p[2] != m && p[3] != m && p[6] != m && p[7] != m) return true;
916 
917  // face 4
918  coord.reset(i, jp, kp);
919  m = isInsideValue(accessor.getValue(coord), isovalue);
920  if (p[0] != m && p[3] != m && p[4] != m && p[7] != m) return true;
921 
922  // face 5
923  coord.reset(ip, j, kp);
924  m = isInsideValue(accessor.getValue(coord), isovalue);
925  if (p[0] != m && p[1] != m && p[2] != m && p[3] != m) return true;
926 
927  // face 6
928  coord.reset(ip, jpp, kp);
929  m = isInsideValue(accessor.getValue(coord), isovalue);
930  if (p[4] != m && p[5] != m && p[6] != m && p[7] != m) return true;
931 
932  // test cube center
933  coord.reset(ip, jp, kp);
934  m = isInsideValue(accessor.getValue(coord), isovalue);
935  if (p[0] != m && p[1] != m && p[2] != m && p[3] != m &&
936  p[4] != m && p[5] != m && p[6] != m && p[7] != m) return true;
937 
938  return false;
939 }
940 
941 
943 
944 
945 template <class LeafType>
946 inline void
947 mergeVoxels(LeafType& leaf, const Coord& start, int dim, int regionId)
948 {
949  Coord ijk, end = start;
950  end[0] += dim;
951  end[1] += dim;
952  end[2] += dim;
953 
954  for (ijk[0] = start[0]; ijk[0] < end[0]; ++ijk[0]) {
955  for (ijk[1] = start[1]; ijk[1] < end[1]; ++ijk[1]) {
956  for (ijk[2] = start[2]; ijk[2] < end[2]; ++ijk[2]) {
957  leaf.setValueOnly(ijk, regionId);
958  }
959  }
960  }
961 }
962 
963 
964 // Note that we must use ValueType::value_type or else Visual C++ gets confused
965 // thinking that it is a constructor.
966 template <class LeafType>
967 inline bool
968 isMergable(LeafType& leaf, const Coord& start, int dim,
969  typename LeafType::ValueType::value_type adaptivity)
970 {
971  if (adaptivity < 1e-6) return false;
972 
973  using VecT = typename LeafType::ValueType;
974  Coord ijk, end = start;
975  end[0] += dim;
976  end[1] += dim;
977  end[2] += dim;
978 
979  std::vector<VecT> norms;
980  for (ijk[0] = start[0]; ijk[0] < end[0]; ++ijk[0]) {
981  for (ijk[1] = start[1]; ijk[1] < end[1]; ++ijk[1]) {
982  for (ijk[2] = start[2]; ijk[2] < end[2]; ++ijk[2]) {
983 
984  if(!leaf.isValueOn(ijk)) continue;
985  norms.push_back(leaf.getValue(ijk));
986  }
987  }
988  }
989 
990  size_t N = norms.size();
991  for (size_t ni = 0; ni < N; ++ni) {
992  VecT n_i = norms[ni];
993  for (size_t nj = 0; nj < N; ++nj) {
994  VecT n_j = norms[nj];
995  if ((1.0 - n_i.dot(n_j)) > adaptivity) return false;
996  }
997  }
998  return true;
999 }
1000 
1001 
1003 
1004 
1006 inline double evalZeroCrossing(double v0, double v1, double iso) { return (iso - v0) / (v1 - v0); }
1007 
1008 
1010 template<typename LeafT>
1011 inline void
1012 collectCornerValues(const LeafT& leaf, const Index offset, std::vector<double>& values)
1013 {
1014  values[0] = double(leaf.getValue(offset)); // i, j, k
1015  values[3] = double(leaf.getValue(offset + 1)); // i, j, k+1
1016  values[4] = double(leaf.getValue(offset + LeafT::DIM)); // i, j+1, k
1017  values[7] = double(leaf.getValue(offset + LeafT::DIM + 1)); // i, j+1, k+1
1018  values[1] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM))); // i+1, j, k
1019  values[2] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + 1)); // i+1, j, k+1
1020  values[5] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM)); // i+1, j+1, k
1021  values[6] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM + 1)); // i+1, j+1, k+1
1022 }
1023 
1024 
1026 template<typename AccessorT>
1027 inline void
1028 collectCornerValues(const AccessorT& acc, const Coord& ijk, std::vector<double>& values)
1029 {
1030  Coord coord = ijk;
1031  values[0] = double(acc.getValue(coord)); // i, j, k
1032 
1033  coord[0] += 1;
1034  values[1] = double(acc.getValue(coord)); // i+1, j, k
1035 
1036  coord[2] += 1;
1037  values[2] = double(acc.getValue(coord)); // i+i, j, k+1
1038 
1039  coord[0] = ijk[0];
1040  values[3] = double(acc.getValue(coord)); // i, j, k+1
1041 
1042  coord[1] += 1; coord[2] = ijk[2];
1043  values[4] = double(acc.getValue(coord)); // i, j+1, k
1044 
1045  coord[0] += 1;
1046  values[5] = double(acc.getValue(coord)); // i+1, j+1, k
1047 
1048  coord[2] += 1;
1049  values[6] = double(acc.getValue(coord)); // i+1, j+1, k+1
1050 
1051  coord[0] = ijk[0];
1052  values[7] = double(acc.getValue(coord)); // i, j+1, k+1
1053 }
1054 
1055 
1057 inline Vec3d
1058 computePoint(const std::vector<double>& values, unsigned char signs,
1059  unsigned char edgeGroup, double iso)
1060 {
1061  Vec3d avg(0.0, 0.0, 0.0);
1062  int samples = 0;
1063 
1064  if (sEdgeGroupTable[signs][1] == edgeGroup) { // Edged: 0 - 1
1065  avg[0] += evalZeroCrossing(values[0], values[1], iso);
1066  ++samples;
1067  }
1068 
1069  if (sEdgeGroupTable[signs][2] == edgeGroup) { // Edged: 1 - 2
1070  avg[0] += 1.0;
1071  avg[2] += evalZeroCrossing(values[1], values[2], iso);
1072  ++samples;
1073  }
1074 
1075  if (sEdgeGroupTable[signs][3] == edgeGroup) { // Edged: 3 - 2
1076  avg[0] += evalZeroCrossing(values[3], values[2], iso);
1077  avg[2] += 1.0;
1078  ++samples;
1079  }
1080 
1081  if (sEdgeGroupTable[signs][4] == edgeGroup) { // Edged: 0 - 3
1082  avg[2] += evalZeroCrossing(values[0], values[3], iso);
1083  ++samples;
1084  }
1085 
1086  if (sEdgeGroupTable[signs][5] == edgeGroup) { // Edged: 4 - 5
1087  avg[0] += evalZeroCrossing(values[4], values[5], iso);
1088  avg[1] += 1.0;
1089  ++samples;
1090  }
1091 
1092  if (sEdgeGroupTable[signs][6] == edgeGroup) { // Edged: 5 - 6
1093  avg[0] += 1.0;
1094  avg[1] += 1.0;
1095  avg[2] += evalZeroCrossing(values[5], values[6], iso);
1096  ++samples;
1097  }
1098 
1099  if (sEdgeGroupTable[signs][7] == edgeGroup) { // Edged: 7 - 6
1100  avg[0] += evalZeroCrossing(values[7], values[6], iso);
1101  avg[1] += 1.0;
1102  avg[2] += 1.0;
1103  ++samples;
1104  }
1105 
1106  if (sEdgeGroupTable[signs][8] == edgeGroup) { // Edged: 4 - 7
1107  avg[1] += 1.0;
1108  avg[2] += evalZeroCrossing(values[4], values[7], iso);
1109  ++samples;
1110  }
1111 
1112  if (sEdgeGroupTable[signs][9] == edgeGroup) { // Edged: 0 - 4
1113  avg[1] += evalZeroCrossing(values[0], values[4], iso);
1114  ++samples;
1115  }
1116 
1117  if (sEdgeGroupTable[signs][10] == edgeGroup) { // Edged: 1 - 5
1118  avg[0] += 1.0;
1119  avg[1] += evalZeroCrossing(values[1], values[5], iso);
1120  ++samples;
1121  }
1122 
1123  if (sEdgeGroupTable[signs][11] == edgeGroup) { // Edged: 2 - 6
1124  avg[0] += 1.0;
1125  avg[1] += evalZeroCrossing(values[2], values[6], iso);
1126  avg[2] += 1.0;
1127  ++samples;
1128  }
1129 
1130  if (sEdgeGroupTable[signs][12] == edgeGroup) { // Edged: 3 - 7
1131  avg[1] += evalZeroCrossing(values[3], values[7], iso);
1132  avg[2] += 1.0;
1133  ++samples;
1134  }
1135 
1136  if (samples > 1) {
1137  double w = 1.0 / double(samples);
1138  avg[0] *= w;
1139  avg[1] *= w;
1140  avg[2] *= w;
1141  }
1142 
1143  return avg;
1144 }
1145 
1146 
1149 inline int
1150 computeMaskedPoint(Vec3d& avg, const std::vector<double>& values, unsigned char signs,
1151  unsigned char signsMask, unsigned char edgeGroup, double iso)
1152 {
1153  avg = Vec3d(0.0, 0.0, 0.0);
1154  int samples = 0;
1155 
1156  if (sEdgeGroupTable[signs][1] == edgeGroup
1157  && sEdgeGroupTable[signsMask][1] == 0) { // Edged: 0 - 1
1158  avg[0] += evalZeroCrossing(values[0], values[1], iso);
1159  ++samples;
1160  }
1161 
1162  if (sEdgeGroupTable[signs][2] == edgeGroup
1163  && sEdgeGroupTable[signsMask][2] == 0) { // Edged: 1 - 2
1164  avg[0] += 1.0;
1165  avg[2] += evalZeroCrossing(values[1], values[2], iso);
1166  ++samples;
1167  }
1168 
1169  if (sEdgeGroupTable[signs][3] == edgeGroup
1170  && sEdgeGroupTable[signsMask][3] == 0) { // Edged: 3 - 2
1171  avg[0] += evalZeroCrossing(values[3], values[2], iso);
1172  avg[2] += 1.0;
1173  ++samples;
1174  }
1175 
1176  if (sEdgeGroupTable[signs][4] == edgeGroup
1177  && sEdgeGroupTable[signsMask][4] == 0) { // Edged: 0 - 3
1178  avg[2] += evalZeroCrossing(values[0], values[3], iso);
1179  ++samples;
1180  }
1181 
1182  if (sEdgeGroupTable[signs][5] == edgeGroup
1183  && sEdgeGroupTable[signsMask][5] == 0) { // Edged: 4 - 5
1184  avg[0] += evalZeroCrossing(values[4], values[5], iso);
1185  avg[1] += 1.0;
1186  ++samples;
1187  }
1188 
1189  if (sEdgeGroupTable[signs][6] == edgeGroup
1190  && sEdgeGroupTable[signsMask][6] == 0) { // Edged: 5 - 6
1191  avg[0] += 1.0;
1192  avg[1] += 1.0;
1193  avg[2] += evalZeroCrossing(values[5], values[6], iso);
1194  ++samples;
1195  }
1196 
1197  if (sEdgeGroupTable[signs][7] == edgeGroup
1198  && sEdgeGroupTable[signsMask][7] == 0) { // Edged: 7 - 6
1199  avg[0] += evalZeroCrossing(values[7], values[6], iso);
1200  avg[1] += 1.0;
1201  avg[2] += 1.0;
1202  ++samples;
1203  }
1204 
1205  if (sEdgeGroupTable[signs][8] == edgeGroup
1206  && sEdgeGroupTable[signsMask][8] == 0) { // Edged: 4 - 7
1207  avg[1] += 1.0;
1208  avg[2] += evalZeroCrossing(values[4], values[7], iso);
1209  ++samples;
1210  }
1211 
1212  if (sEdgeGroupTable[signs][9] == edgeGroup
1213  && sEdgeGroupTable[signsMask][9] == 0) { // Edged: 0 - 4
1214  avg[1] += evalZeroCrossing(values[0], values[4], iso);
1215  ++samples;
1216  }
1217 
1218  if (sEdgeGroupTable[signs][10] == edgeGroup
1219  && sEdgeGroupTable[signsMask][10] == 0) { // Edged: 1 - 5
1220  avg[0] += 1.0;
1221  avg[1] += evalZeroCrossing(values[1], values[5], iso);
1222  ++samples;
1223  }
1224 
1225  if (sEdgeGroupTable[signs][11] == edgeGroup
1226  && sEdgeGroupTable[signsMask][11] == 0) { // Edged: 2 - 6
1227  avg[0] += 1.0;
1228  avg[1] += evalZeroCrossing(values[2], values[6], iso);
1229  avg[2] += 1.0;
1230  ++samples;
1231  }
1232 
1233  if (sEdgeGroupTable[signs][12] == edgeGroup
1234  && sEdgeGroupTable[signsMask][12] == 0) { // Edged: 3 - 7
1235  avg[1] += evalZeroCrossing(values[3], values[7], iso);
1236  avg[2] += 1.0;
1237  ++samples;
1238  }
1239 
1240  if (samples > 1) {
1241  double w = 1.0 / double(samples);
1242  avg[0] *= w;
1243  avg[1] *= w;
1244  avg[2] *= w;
1245  }
1246 
1247  return samples;
1248 }
1249 
1250 
1253 inline Vec3d
1254 computeWeightedPoint(const Vec3d& p, const std::vector<double>& values,
1255  unsigned char signs, unsigned char edgeGroup, double iso)
1256 {
1257  std::vector<Vec3d> samples;
1258  samples.reserve(8);
1259 
1260  std::vector<double> weights;
1261  weights.reserve(8);
1262 
1263  Vec3d avg(0.0, 0.0, 0.0);
1264 
1265  if (sEdgeGroupTable[signs][1] == edgeGroup) { // Edged: 0 - 1
1266  avg[0] = evalZeroCrossing(values[0], values[1], iso);
1267  avg[1] = 0.0;
1268  avg[2] = 0.0;
1269 
1270  samples.push_back(avg);
1271  weights.push_back((avg-p).lengthSqr());
1272  }
1273 
1274  if (sEdgeGroupTable[signs][2] == edgeGroup) { // Edged: 1 - 2
1275  avg[0] = 1.0;
1276  avg[1] = 0.0;
1277  avg[2] = evalZeroCrossing(values[1], values[2], iso);
1278 
1279  samples.push_back(avg);
1280  weights.push_back((avg-p).lengthSqr());
1281  }
1282 
1283  if (sEdgeGroupTable[signs][3] == edgeGroup) { // Edged: 3 - 2
1284  avg[0] = evalZeroCrossing(values[3], values[2], iso);
1285  avg[1] = 0.0;
1286  avg[2] = 1.0;
1287 
1288  samples.push_back(avg);
1289  weights.push_back((avg-p).lengthSqr());
1290  }
1291 
1292  if (sEdgeGroupTable[signs][4] == edgeGroup) { // Edged: 0 - 3
1293  avg[0] = 0.0;
1294  avg[1] = 0.0;
1295  avg[2] = evalZeroCrossing(values[0], values[3], iso);
1296 
1297  samples.push_back(avg);
1298  weights.push_back((avg-p).lengthSqr());
1299  }
1300 
1301  if (sEdgeGroupTable[signs][5] == edgeGroup) { // Edged: 4 - 5
1302  avg[0] = evalZeroCrossing(values[4], values[5], iso);
1303  avg[1] = 1.0;
1304  avg[2] = 0.0;
1305 
1306  samples.push_back(avg);
1307  weights.push_back((avg-p).lengthSqr());
1308  }
1309 
1310  if (sEdgeGroupTable[signs][6] == edgeGroup) { // Edged: 5 - 6
1311  avg[0] = 1.0;
1312  avg[1] = 1.0;
1313  avg[2] = evalZeroCrossing(values[5], values[6], iso);
1314 
1315  samples.push_back(avg);
1316  weights.push_back((avg-p).lengthSqr());
1317  }
1318 
1319  if (sEdgeGroupTable[signs][7] == edgeGroup) { // Edged: 7 - 6
1320  avg[0] = evalZeroCrossing(values[7], values[6], iso);
1321  avg[1] = 1.0;
1322  avg[2] = 1.0;
1323 
1324  samples.push_back(avg);
1325  weights.push_back((avg-p).lengthSqr());
1326  }
1327 
1328  if (sEdgeGroupTable[signs][8] == edgeGroup) { // Edged: 4 - 7
1329  avg[0] = 0.0;
1330  avg[1] = 1.0;
1331  avg[2] = evalZeroCrossing(values[4], values[7], iso);
1332 
1333  samples.push_back(avg);
1334  weights.push_back((avg-p).lengthSqr());
1335  }
1336 
1337  if (sEdgeGroupTable[signs][9] == edgeGroup) { // Edged: 0 - 4
1338  avg[0] = 0.0;
1339  avg[1] = evalZeroCrossing(values[0], values[4], iso);
1340  avg[2] = 0.0;
1341 
1342  samples.push_back(avg);
1343  weights.push_back((avg-p).lengthSqr());
1344  }
1345 
1346  if (sEdgeGroupTable[signs][10] == edgeGroup) { // Edged: 1 - 5
1347  avg[0] = 1.0;
1348  avg[1] = evalZeroCrossing(values[1], values[5], iso);
1349  avg[2] = 0.0;
1350 
1351  samples.push_back(avg);
1352  weights.push_back((avg-p).lengthSqr());
1353  }
1354 
1355  if (sEdgeGroupTable[signs][11] == edgeGroup) { // Edged: 2 - 6
1356  avg[0] = 1.0;
1357  avg[1] = evalZeroCrossing(values[2], values[6], iso);
1358  avg[2] = 1.0;
1359 
1360  samples.push_back(avg);
1361  weights.push_back((avg-p).lengthSqr());
1362  }
1363 
1364  if (sEdgeGroupTable[signs][12] == edgeGroup) { // Edged: 3 - 7
1365  avg[0] = 0.0;
1366  avg[1] = evalZeroCrossing(values[3], values[7], iso);
1367  avg[2] = 1.0;
1368 
1369  samples.push_back(avg);
1370  weights.push_back((avg-p).lengthSqr());
1371  }
1372 
1373 
1374  double minWeight = std::numeric_limits<double>::max();
1375  double maxWeight = -std::numeric_limits<double>::max();
1376 
1377  for (size_t i = 0, I = weights.size(); i < I; ++i) {
1378  minWeight = std::min(minWeight, weights[i]);
1379  maxWeight = std::max(maxWeight, weights[i]);
1380  }
1381 
1382  const double offset = maxWeight + minWeight * 0.1;
1383  for (size_t i = 0, I = weights.size(); i < I; ++i) {
1384  weights[i] = offset - weights[i];
1385  }
1386 
1387 
1388  double weightSum = 0.0;
1389  for (size_t i = 0, I = weights.size(); i < I; ++i) {
1390  weightSum += weights[i];
1391  }
1392 
1393  avg[0] = 0.0;
1394  avg[1] = 0.0;
1395  avg[2] = 0.0;
1396 
1397  if (samples.size() > 1) {
1398  for (size_t i = 0, I = samples.size(); i < I; ++i) {
1399  avg += samples[i] * (weights[i] / weightSum);
1400  }
1401  } else {
1402  avg = samples.front();
1403  }
1404 
1405  return avg;
1406 }
1407 
1408 
1411 inline void
1412 computeCellPoints(std::vector<Vec3d>& points,
1413  const std::vector<double>& values, unsigned char signs, double iso)
1414 {
1415  for (size_t n = 1, N = sEdgeGroupTable[signs][0] + 1; n < N; ++n) {
1416  points.push_back(computePoint(values, signs, uint8_t(n), iso));
1417  }
1418 }
1419 
1420 
1424 inline int
1425 matchEdgeGroup(unsigned char groupId, unsigned char lhsSigns, unsigned char rhsSigns)
1426 {
1427  int id = -1;
1428  for (size_t i = 1; i <= 12; ++i) {
1429  if (sEdgeGroupTable[lhsSigns][i] == groupId && sEdgeGroupTable[rhsSigns][i] != 0) {
1430  id = sEdgeGroupTable[rhsSigns][i];
1431  break;
1432  }
1433  }
1434  return id;
1435 }
1436 
1437 
1442 inline void
1443 computeCellPoints(std::vector<Vec3d>& points, std::vector<bool>& weightedPointMask,
1444  const std::vector<double>& lhsValues, const std::vector<double>& rhsValues,
1445  unsigned char lhsSigns, unsigned char rhsSigns,
1446  double iso, size_t pointIdx, const uint32_t * seamPointArray)
1447 {
1448  for (size_t n = 1, N = sEdgeGroupTable[lhsSigns][0] + 1; n < N; ++n) {
1449 
1450  int id = matchEdgeGroup(uint8_t(n), lhsSigns, rhsSigns);
1451 
1452  if (id != -1) {
1453 
1454  const unsigned char e = uint8_t(id);
1455  const uint32_t& quantizedPoint = seamPointArray[pointIdx + (id - 1)];
1456 
1457  if ((quantizedPoint & MASK_DIRTY_BIT) && !(quantizedPoint & MASK_INVALID_BIT)) {
1458  Vec3d p = unpackPoint(quantizedPoint);
1459  points.push_back(computeWeightedPoint(p, rhsValues, rhsSigns, e, iso));
1460  weightedPointMask.push_back(true);
1461  } else {
1462  points.push_back(computePoint(rhsValues, rhsSigns, e, iso));
1463  weightedPointMask.push_back(false);
1464  }
1465 
1466  } else {
1467  points.push_back(computePoint(lhsValues, lhsSigns, uint8_t(n), iso));
1468  weightedPointMask.push_back(false);
1469  }
1470  }
1471 }
1472 
1473 
1474 template <typename InputTreeType>
1476 {
1477  using InputLeafNodeType = typename InputTreeType::LeafNodeType;
1478  using InputValueType = typename InputLeafNodeType::ValueType;
1479 
1480  using Int16TreeType = typename InputTreeType::template ValueConverter<Int16>::Type;
1481  using Int16LeafNodeType = typename Int16TreeType::LeafNodeType;
1482 
1483  using Index32TreeType = typename InputTreeType::template ValueConverter<Index32>::Type;
1484  using Index32LeafNodeType = typename Index32TreeType::LeafNodeType;
1485 
1486  ComputePoints(Vec3s * pointArray,
1487  const InputTreeType& inputTree,
1488  const std::vector<Index32LeafNodeType*>& pointIndexLeafNodes,
1489  const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
1490  const boost::scoped_array<Index32>& leafNodeOffsets,
1491  const math::Transform& xform,
1492  double iso);
1493 
1494  void setRefData(const InputTreeType& refInputTree,
1495  const Index32TreeType& refPointIndexTree,
1496  const Int16TreeType& refSignFlagsTree,
1497  const uint32_t * quantizedSeamLinePoints,
1498  uint8_t * seamLinePointsFlags);
1499 
1500  void operator()(const tbb::blocked_range<size_t>&) const;
1501 
1502 private:
1503  Vec3s * const mPoints;
1504  InputTreeType const * const mInputTree;
1505  Index32LeafNodeType * const * const mPointIndexNodes;
1506  Int16LeafNodeType const * const * const mSignFlagsNodes;
1507  Index32 const * const mNodeOffsets;
1508  math::Transform const mTransform;
1509  double const mIsovalue;
1510  // reference meshing data
1511  InputTreeType const * mRefInputTree;
1512  Index32TreeType const * mRefPointIndexTree;
1513  Int16TreeType const * mRefSignFlagsTree;
1514  uint32_t const * mQuantizedSeamLinePoints;
1515  uint8_t * mSeamLinePointsFlags;
1516 }; // struct ComputePoints
1517 
1518 
1519 template <typename InputTreeType>
1521  Vec3s * pointArray,
1522  const InputTreeType& inputTree,
1523  const std::vector<Index32LeafNodeType*>& pointIndexLeafNodes,
1524  const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
1525  const boost::scoped_array<Index32>& leafNodeOffsets,
1526  const math::Transform& xform,
1527  double iso)
1528  : mPoints(pointArray)
1529  , mInputTree(&inputTree)
1530  , mPointIndexNodes(pointIndexLeafNodes.empty() ? nullptr : &pointIndexLeafNodes.front())
1531  , mSignFlagsNodes(signFlagsLeafNodes.empty() ? nullptr : &signFlagsLeafNodes.front())
1532  , mNodeOffsets(leafNodeOffsets.get())
1533  , mTransform(xform)
1534  , mIsovalue(iso)
1535  , mRefInputTree(nullptr)
1536  , mRefPointIndexTree(nullptr)
1537  , mRefSignFlagsTree(nullptr)
1538  , mQuantizedSeamLinePoints(nullptr)
1539  , mSeamLinePointsFlags(nullptr)
1540 {
1541 }
1542 
1543 template <typename InputTreeType>
1544 void
1546  const InputTreeType& refInputTree,
1547  const Index32TreeType& refPointIndexTree,
1548  const Int16TreeType& refSignFlagsTree,
1549  const uint32_t * quantizedSeamLinePoints,
1550  uint8_t * seamLinePointsFlags)
1551 {
1552  mRefInputTree = &refInputTree;
1553  mRefPointIndexTree = &refPointIndexTree;
1554  mRefSignFlagsTree = &refSignFlagsTree;
1555  mQuantizedSeamLinePoints = quantizedSeamLinePoints;
1556  mSeamLinePointsFlags = seamLinePointsFlags;
1557 }
1558 
1559 template <typename InputTreeType>
1560 void
1561 ComputePoints<InputTreeType>::operator()(const tbb::blocked_range<size_t>& range) const
1562 {
1563  using InputTreeAccessor = tree::ValueAccessor<const InputTreeType>;
1564  using Index32TreeAccessor = tree::ValueAccessor<const Index32TreeType>;
1565  using Int16TreeAccessor = tree::ValueAccessor<const Int16TreeType>;
1566 
1567  using IndexType = typename Index32TreeType::ValueType;
1568 
1569  using IndexArray = std::vector<Index>;
1570  using IndexArrayMap = std::map<IndexType, IndexArray>;
1571 
1572  InputTreeAccessor inputAcc(*mInputTree);
1573 
1574  Vec3d xyz;
1575  Coord ijk;
1576  std::vector<Vec3d> points(4);
1577  std::vector<bool> weightedPointMask(4);
1578  std::vector<double> values(8), refValues(8);
1579  const double iso = mIsovalue;
1580 
1581  // reference data accessors
1582 
1583  std::unique_ptr<InputTreeAccessor> refInputAcc;
1584  std::unique_ptr<Index32TreeAccessor> refPointIndexAcc;
1585  std::unique_ptr<Int16TreeAccessor> refSignFlagsAcc;
1586 
1587  const bool hasReferenceData = mRefInputTree && mRefPointIndexTree && mRefSignFlagsTree;
1588 
1589  if (hasReferenceData) {
1590  refInputAcc.reset(new InputTreeAccessor(*mRefInputTree));
1591  refPointIndexAcc.reset(new Index32TreeAccessor(*mRefPointIndexTree));
1592  refSignFlagsAcc.reset(new Int16TreeAccessor(*mRefSignFlagsTree));
1593  }
1594 
1595  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
1596 
1597  Index32LeafNodeType& pointIndexNode = *mPointIndexNodes[n];
1598  const Coord& origin = pointIndexNode.origin();
1599 
1600  const Int16LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1601  const InputLeafNodeType * inputNode = inputAcc.probeConstLeaf(origin);
1602 
1603  // get reference data
1604  const InputLeafNodeType * refInputNode = nullptr;
1605  const Index32LeafNodeType * refPointIndexNode = nullptr;
1606  const Int16LeafNodeType * refSignFlagsNode = nullptr;
1607 
1608  if (hasReferenceData) {
1609  refInputNode = refInputAcc->probeConstLeaf(origin);
1610  refPointIndexNode = refPointIndexAcc->probeConstLeaf(origin);
1611  refSignFlagsNode = refSignFlagsAcc->probeConstLeaf(origin);
1612  }
1613 
1614  IndexType pointOffset = IndexType(mNodeOffsets[n]);
1615  IndexArrayMap regions;
1616 
1617  for (auto it = pointIndexNode.beginValueOn(); it; ++it) {
1618  const Index offset = it.pos();
1619 
1620  const IndexType id = it.getValue();
1621  if (id != 0) {
1622  if (id != IndexType(util::INVALID_IDX)) {
1623  regions[id].push_back(offset);
1624  }
1625  continue;
1626  }
1627 
1628  pointIndexNode.setValueOnly(offset, pointOffset);
1629 
1630  const Int16 flags = signFlagsNode.getValue(offset);
1631  uint8_t signs = uint8_t(SIGNS & flags);
1632  uint8_t refSigns = 0;
1633 
1634  if ((flags & SEAM) && refPointIndexNode && refSignFlagsNode) {
1635  if (refSignFlagsNode->isValueOn(offset)) {
1636  refSigns = uint8_t(SIGNS & refSignFlagsNode->getValue(offset));
1637  }
1638  }
1639 
1640  ijk = Index32LeafNodeType::offsetToLocalCoord(offset);
1641 
1642  const bool inclusiveCell = inputNode &&
1643  ijk[0] < int(Index32LeafNodeType::DIM - 1) &&
1644  ijk[1] < int(Index32LeafNodeType::DIM - 1) &&
1645  ijk[2] < int(Index32LeafNodeType::DIM - 1);
1646 
1647  ijk += origin;
1648 
1649  if (inclusiveCell) collectCornerValues(*inputNode, offset, values);
1650  else collectCornerValues(inputAcc, ijk, values);
1651 
1652  points.clear();
1653  weightedPointMask.clear();
1654 
1655  if (refSigns == 0) {
1656 
1657  computeCellPoints(points, values, signs, iso);
1658 
1659  } else {
1660  if (inclusiveCell && refInputNode) {
1661  collectCornerValues(*refInputNode, offset, refValues);
1662  } else {
1663  collectCornerValues(*refInputAcc, ijk, refValues);
1664  }
1665  computeCellPoints(points, weightedPointMask, values, refValues, signs, refSigns,
1666  iso, refPointIndexNode->getValue(offset), mQuantizedSeamLinePoints);
1667  }
1668 
1669  xyz[0] = double(ijk[0]);
1670  xyz[1] = double(ijk[1]);
1671  xyz[2] = double(ijk[2]);
1672 
1673  for (size_t i = 0, I = points.size(); i < I; ++i) {
1674 
1675  Vec3d& point = points[i];
1676 
1677  // Checks for both NaN and inf vertex positions, i.e. any value that is not finite.
1678  if (!std::isfinite(point[0]) ||
1679  !std::isfinite(point[1]) ||
1680  !std::isfinite(point[2]))
1681  {
1683  "VolumeToMesh encountered NaNs or infs in the input VDB!"
1684  " Hint: Check the input and consider using the \"Diagnostics\" tool "
1685  "to detect and resolve the NaNs.");
1686  }
1687 
1688  point += xyz;
1689  point = mTransform.indexToWorld(point);
1690 
1691  Vec3s& pos = mPoints[pointOffset];
1692  pos[0] = float(point[0]);
1693  pos[1] = float(point[1]);
1694  pos[2] = float(point[2]);
1695 
1696  if (mSeamLinePointsFlags && !weightedPointMask.empty() && weightedPointMask[i]) {
1697  mSeamLinePointsFlags[pointOffset] = uint8_t(1);
1698  }
1699 
1700  ++pointOffset;
1701  }
1702  }
1703 
1704  // generate collapsed region points
1705  for (typename IndexArrayMap::iterator it = regions.begin(); it != regions.end(); ++it) {
1706 
1707  Vec3d avg(0.0), point(0.0);
1708  int count = 0;
1709 
1710  const IndexArray& voxels = it->second;
1711  for (size_t i = 0, I = voxels.size(); i < I; ++i) {
1712 
1713  const Index offset = voxels[i];
1714  ijk = Index32LeafNodeType::offsetToLocalCoord(offset);
1715 
1716  const bool inclusiveCell = inputNode &&
1717  ijk[0] < int(Index32LeafNodeType::DIM - 1) &&
1718  ijk[1] < int(Index32LeafNodeType::DIM - 1) &&
1719  ijk[2] < int(Index32LeafNodeType::DIM - 1);
1720 
1721  ijk += origin;
1722 
1723  pointIndexNode.setValueOnly(offset, pointOffset);
1724 
1725  uint8_t signs = uint8_t(SIGNS & signFlagsNode.getValue(offset));
1726 
1727  if (inclusiveCell) collectCornerValues(*inputNode, offset, values);
1728  else collectCornerValues(inputAcc, ijk, values);
1729 
1730  points.clear();
1731  computeCellPoints(points, values, signs, iso);
1732 
1733  avg[0] += double(ijk[0]) + points[0][0];
1734  avg[1] += double(ijk[1]) + points[0][1];
1735  avg[2] += double(ijk[2]) + points[0][2];
1736 
1737  ++count;
1738  }
1739 
1740  if (count > 1) {
1741  double w = 1.0 / double(count);
1742  avg[0] *= w;
1743  avg[1] *= w;
1744  avg[2] *= w;
1745  }
1746 
1747  avg = mTransform.indexToWorld(avg);
1748 
1749  Vec3s& pos = mPoints[pointOffset];
1750  pos[0] = float(avg[0]);
1751  pos[1] = float(avg[1]);
1752  pos[2] = float(avg[2]);
1753 
1754  ++pointOffset;
1755  }
1756  }
1757 } // ComputePoints::operator()
1758 
1759 
1761 
1762 
1763 template <typename InputTreeType>
1765 {
1766  using InputLeafNodeType = typename InputTreeType::LeafNodeType;
1767  using InputValueType = typename InputLeafNodeType::ValueType;
1768 
1769  using Int16TreeType = typename InputTreeType::template ValueConverter<Int16>::Type;
1770  using Int16LeafNodeType = typename Int16TreeType::LeafNodeType;
1771 
1772  using Index32TreeType = typename InputTreeType::template ValueConverter<Index32>::Type;
1773  using Index32LeafNodeType = typename Index32TreeType::LeafNodeType;
1774 
1775  SeamLineWeights(const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
1776  const InputTreeType& inputTree,
1777  const Index32TreeType& refPointIndexTree,
1778  const Int16TreeType& refSignFlagsTree,
1779  uint32_t * quantizedPoints,
1780  InputValueType iso)
1781  : mSignFlagsNodes(signFlagsLeafNodes.empty() ? nullptr : &signFlagsLeafNodes.front())
1782  , mInputTree(&inputTree)
1783  , mRefPointIndexTree(&refPointIndexTree)
1784  , mRefSignFlagsTree(&refSignFlagsTree)
1785  , mQuantizedPoints(quantizedPoints)
1786  , mIsovalue(iso)
1787  {
1788  }
1789 
1790  void operator()(const tbb::blocked_range<size_t>& range) const
1791  {
1792  tree::ValueAccessor<const InputTreeType> inputTreeAcc(*mInputTree);
1793  tree::ValueAccessor<const Index32TreeType> pointIndexTreeAcc(*mRefPointIndexTree);
1794  tree::ValueAccessor<const Int16TreeType> signFlagsTreeAcc(*mRefSignFlagsTree);
1795 
1796  std::vector<double> values(8);
1797  const double iso = double(mIsovalue);
1798  Coord ijk;
1799  Vec3d pos;
1800 
1801  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
1802 
1803  const Int16LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1804  const Coord& origin = signFlagsNode.origin();
1805 
1806  const Int16LeafNodeType * refSignNode = signFlagsTreeAcc.probeConstLeaf(origin);
1807  if (!refSignNode) continue;
1808 
1809  const Index32LeafNodeType* refPointIndexNode =
1810  pointIndexTreeAcc.probeConstLeaf(origin);
1811  if (!refPointIndexNode) continue;
1812 
1813  const InputLeafNodeType * inputNode = inputTreeAcc.probeConstLeaf(origin);
1814 
1815  for (typename Int16LeafNodeType::ValueOnCIter it = signFlagsNode.cbeginValueOn();
1816  it; ++it)
1817  {
1818  const Index offset = it.pos();
1819 
1820  ijk = Index32LeafNodeType::offsetToLocalCoord(offset);
1821 
1822  const bool inclusiveCell = inputNode &&
1823  ijk[0] < int(Index32LeafNodeType::DIM - 1) &&
1824  ijk[1] < int(Index32LeafNodeType::DIM - 1) &&
1825  ijk[2] < int(Index32LeafNodeType::DIM - 1);
1826 
1827  ijk += origin;
1828 
1829  if ((it.getValue() & SEAM) && refSignNode->isValueOn(offset)) {
1830 
1831  uint8_t lhsSigns = uint8_t(SIGNS & it.getValue());
1832  uint8_t rhsSigns = uint8_t(SIGNS & refSignNode->getValue(offset));
1833 
1834 
1835  if (inclusiveCell) {
1836  collectCornerValues(*inputNode, offset, values);
1837  } else {
1838  collectCornerValues(inputTreeAcc, ijk, values);
1839  }
1840 
1841 
1842  for (unsigned i = 1, I = sEdgeGroupTable[lhsSigns][0] + 1; i < I; ++i) {
1843 
1844  int id = matchEdgeGroup(uint8_t(i), lhsSigns, rhsSigns);
1845 
1846  if (id != -1) {
1847 
1848  uint32_t& data = mQuantizedPoints[
1849  refPointIndexNode->getValue(offset) + (id - 1)];
1850 
1851  if (!(data & MASK_DIRTY_BIT)) {
1852 
1853  int smaples = computeMaskedPoint(
1854  pos, values, lhsSigns, rhsSigns, uint8_t(i), iso);
1855 
1856  if (smaples > 0) data = packPoint(pos);
1857  else data = MASK_INVALID_BIT;
1858 
1859  data |= MASK_DIRTY_BIT;
1860  }
1861  }
1862  } // end point group loop
1863  }
1864 
1865  } // end value on loop
1866 
1867  } // end leaf node loop
1868  }
1869 
1870 private:
1871  Int16LeafNodeType const * const * const mSignFlagsNodes;
1872  InputTreeType const * const mInputTree;
1873  Index32TreeType const * const mRefPointIndexTree;
1874  Int16TreeType const * const mRefSignFlagsTree;
1875  uint32_t * const mQuantizedPoints;
1876  InputValueType const mIsovalue;
1877 }; // struct SeamLineWeights
1878 
1879 
1880 template <typename TreeType>
1882 {
1883  using LeafNodeType = typename TreeType::LeafNodeType;
1884 
1885  SetSeamLineFlags(const std::vector<LeafNodeType*>& signFlagsLeafNodes,
1886  const TreeType& refSignFlagsTree)
1887  : mSignFlagsNodes(signFlagsLeafNodes.empty() ? nullptr : &signFlagsLeafNodes.front())
1888  , mRefSignFlagsTree(&refSignFlagsTree)
1889  {
1890  }
1891 
1892  void operator()(const tbb::blocked_range<size_t>& range) const
1893  {
1894  tree::ValueAccessor<const TreeType> refSignFlagsTreeAcc(*mRefSignFlagsTree);
1895 
1896  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
1897 
1898  LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1899  const Coord& origin = signFlagsNode.origin();
1900 
1901  const LeafNodeType * refSignNode = refSignFlagsTreeAcc.probeConstLeaf(origin);
1902  if (!refSignNode) continue;
1903 
1904  for (auto it = signFlagsNode.cbeginValueOn(); it; ++it) {
1905  const Index offset = it.pos();
1906 
1907  uint8_t rhsSigns = uint8_t(refSignNode->getValue(offset) & SIGNS);
1908 
1909  if (sEdgeGroupTable[rhsSigns][0] > 0) {
1910 
1911  const typename LeafNodeType::ValueType value = it.getValue();
1912  uint8_t lhsSigns = uint8_t(value & SIGNS);
1913 
1914  if (rhsSigns != lhsSigns) {
1915  signFlagsNode.setValueOnly(offset, value | SEAM);
1916  }
1917  }
1918 
1919  } // end value on loop
1920 
1921  } // end leaf node loop
1922  }
1923 
1924 private:
1925  LeafNodeType * const * const mSignFlagsNodes;
1926  TreeType const * const mRefSignFlagsTree;
1927 }; // struct SetSeamLineFlags
1928 
1929 
1930 template <typename BoolTreeType, typename SignDataType>
1932 {
1933  using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
1934 
1935  using SignDataTreeType = typename BoolTreeType::template ValueConverter<SignDataType>::Type;
1936  using SignDataLeafNodeType = typename SignDataTreeType::LeafNodeType;
1937 
1938  TransferSeamLineFlags(const std::vector<SignDataLeafNodeType*>& signFlagsLeafNodes,
1939  const BoolTreeType& maskTree)
1940  : mSignFlagsNodes(signFlagsLeafNodes.empty() ? nullptr : &signFlagsLeafNodes.front())
1941  , mMaskTree(&maskTree)
1942  {
1943  }
1944 
1945  void operator()(const tbb::blocked_range<size_t>& range) const
1946  {
1947  tree::ValueAccessor<const BoolTreeType> maskAcc(*mMaskTree);
1948 
1949  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
1950 
1951  SignDataLeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1952  const Coord& origin = signFlagsNode.origin();
1953 
1954  const BoolLeafNodeType * maskNode = maskAcc.probeConstLeaf(origin);
1955  if (!maskNode) continue;
1956 
1957  using ValueOnCIter = typename SignDataLeafNodeType::ValueOnCIter;
1958 
1959  for (ValueOnCIter it = signFlagsNode.cbeginValueOn(); it; ++it) {
1960  const Index offset = it.pos();
1961 
1962  if (maskNode->isValueOn(offset)) {
1963  signFlagsNode.setValueOnly(offset, it.getValue() | SEAM);
1964  }
1965 
1966  } // end value on loop
1967 
1968  } // end leaf node loop
1969  }
1970 
1971 private:
1972  SignDataLeafNodeType * const * const mSignFlagsNodes;
1973  BoolTreeType const * const mMaskTree;
1974 }; // struct TransferSeamLineFlags
1975 
1976 
1977 template <typename TreeType>
1979 {
1980  using LeafNodeType = typename TreeType::LeafNodeType;
1981  using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
1982 
1983  MaskSeamLineVoxels(const std::vector<LeafNodeType*>& signFlagsLeafNodes,
1984  const TreeType& signFlagsTree,
1985  BoolTreeType& mask)
1986  : mSignFlagsNodes(signFlagsLeafNodes.empty() ? nullptr : &signFlagsLeafNodes.front())
1987  , mSignFlagsTree(&signFlagsTree)
1988  , mTempMask(false)
1989  , mMask(&mask)
1990  {
1991  }
1992 
1994  : mSignFlagsNodes(rhs.mSignFlagsNodes)
1995  , mSignFlagsTree(rhs.mSignFlagsTree)
1996  , mTempMask(false)
1997  , mMask(&mTempMask)
1998  {
1999  }
2000 
2001  void join(MaskSeamLineVoxels& rhs) { mMask->merge(*rhs.mMask); }
2002 
2003  void operator()(const tbb::blocked_range<size_t>& range)
2004  {
2005  using ValueOnCIter = typename LeafNodeType::ValueOnCIter;
2006  using ValueType = typename LeafNodeType::ValueType;
2007 
2008  tree::ValueAccessor<const TreeType> signFlagsAcc(*mSignFlagsTree);
2009  tree::ValueAccessor<BoolTreeType> maskAcc(*mMask);
2010  Coord ijk(0, 0, 0);
2011 
2012  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
2013 
2014  LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
2015 
2016 
2017  for (ValueOnCIter it = signFlagsNode.cbeginValueOn(); it; ++it) {
2018 
2019  const ValueType flags = it.getValue();
2020 
2021  if (!(flags & SEAM) && (flags & EDGES)) {
2022 
2023  ijk = it.getCoord();
2024 
2025  bool isSeamLineVoxel = false;
2026 
2027  if (flags & XEDGE) {
2028  ijk[1] -= 1;
2029  isSeamLineVoxel = (signFlagsAcc.getValue(ijk) & SEAM);
2030  ijk[2] -= 1;
2031  isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
2032  ijk[1] += 1;
2033  isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
2034  ijk[2] += 1;
2035  }
2036 
2037  if (!isSeamLineVoxel && flags & YEDGE) {
2038  ijk[2] -= 1;
2039  isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
2040  ijk[0] -= 1;
2041  isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
2042  ijk[2] += 1;
2043  isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
2044  ijk[0] += 1;
2045  }
2046 
2047  if (!isSeamLineVoxel && flags & ZEDGE) {
2048  ijk[1] -= 1;
2049  isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
2050  ijk[0] -= 1;
2051  isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
2052  ijk[1] += 1;
2053  isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
2054  ijk[0] += 1;
2055  }
2056 
2057  if (isSeamLineVoxel) {
2058  maskAcc.setValue(it.getCoord(), true);
2059  }
2060  }
2061  } // end value on loop
2062 
2063  } // end leaf node loop
2064  }
2065 
2066 private:
2067  LeafNodeType * const * const mSignFlagsNodes;
2068  TreeType const * const mSignFlagsTree;
2069  BoolTreeType mTempMask;
2070  BoolTreeType * const mMask;
2071 }; // struct MaskSeamLineVoxels
2072 
2073 
2074 template<typename SignDataTreeType>
2075 inline void
2076 markSeamLineData(SignDataTreeType& signFlagsTree, const SignDataTreeType& refSignFlagsTree)
2077 {
2078  using SignDataType = typename SignDataTreeType::ValueType;
2079  using SignDataLeafNodeType = typename SignDataTreeType::LeafNodeType;
2080  using BoolTreeType = typename SignDataTreeType::template ValueConverter<bool>::Type;
2081 
2082  std::vector<SignDataLeafNodeType*> signFlagsLeafNodes;
2083  signFlagsTree.getNodes(signFlagsLeafNodes);
2084 
2085  const tbb::blocked_range<size_t> nodeRange(0, signFlagsLeafNodes.size());
2086 
2087  tbb::parallel_for(nodeRange,
2088  SetSeamLineFlags<SignDataTreeType>(signFlagsLeafNodes, refSignFlagsTree));
2089 
2090  BoolTreeType seamLineMaskTree(false);
2091 
2093  maskSeamLine(signFlagsLeafNodes, signFlagsTree, seamLineMaskTree);
2094 
2095  tbb::parallel_reduce(nodeRange, maskSeamLine);
2096 
2097  tbb::parallel_for(nodeRange,
2098  TransferSeamLineFlags<BoolTreeType, SignDataType>(signFlagsLeafNodes, seamLineMaskTree));
2099 }
2100 
2101 
2103 
2104 
2105 template <typename InputGridType>
2107 {
2108  using InputTreeType = typename InputGridType::TreeType;
2109  using InputLeafNodeType = typename InputTreeType::LeafNodeType;
2110  using InputValueType = typename InputLeafNodeType::ValueType;
2111 
2112  using FloatTreeType = typename InputTreeType::template ValueConverter<float>::Type;
2113  using FloatLeafNodeType = typename FloatTreeType::LeafNodeType;
2115 
2116  using Int16TreeType = typename InputTreeType::template ValueConverter<Int16>::Type;
2117  using Int16LeafNodeType = typename Int16TreeType::LeafNodeType;
2118 
2119  using Index32TreeType = typename InputTreeType::template ValueConverter<Index32>::Type;
2120  using Index32LeafNodeType = typename Index32TreeType::LeafNodeType;
2121 
2122  using BoolTreeType = typename InputTreeType::template ValueConverter<bool>::Type;
2123  using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
2124 
2125  MergeVoxelRegions(const InputGridType& inputGrid,
2126  const Index32TreeType& pointIndexTree,
2127  const std::vector<Index32LeafNodeType*>& pointIndexLeafNodes,
2128  const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
2129  InputValueType iso,
2130  float adaptivity,
2131  bool invertSurfaceOrientation);
2132 
2134  {
2135  mSpatialAdaptivityTree = &grid.tree();
2136  mSpatialAdaptivityTransform = &grid.transform();
2137  }
2138 
2140  {
2141  mMaskTree = &mask;
2142  }
2143 
2144  void setRefSignFlagsData(const Int16TreeType& signFlagsData, float internalAdaptivity)
2145  {
2146  mRefSignFlagsTree = &signFlagsData;
2147  mInternalAdaptivity = internalAdaptivity;
2148  }
2149 
2150  void operator()(const tbb::blocked_range<size_t>&) const;
2151 
2152 private:
2153  InputTreeType const * const mInputTree;
2154  math::Transform const * const mInputTransform;
2155 
2156  Index32TreeType const * const mPointIndexTree;
2157  Index32LeafNodeType * const * const mPointIndexNodes;
2158  Int16LeafNodeType const * const * const mSignFlagsNodes;
2159 
2160  InputValueType mIsovalue;
2161  float mSurfaceAdaptivity, mInternalAdaptivity;
2162  bool mInvertSurfaceOrientation;
2163 
2164  FloatTreeType const * mSpatialAdaptivityTree;
2165  BoolTreeType const * mMaskTree;
2166  Int16TreeType const * mRefSignFlagsTree;
2167  math::Transform const * mSpatialAdaptivityTransform;
2168 }; // struct MergeVoxelRegions
2169 
2170 
2171 template <typename InputGridType>
2173  const InputGridType& inputGrid,
2174  const Index32TreeType& pointIndexTree,
2175  const std::vector<Index32LeafNodeType*>& pointIndexLeafNodes,
2176  const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
2177  InputValueType iso,
2178  float adaptivity,
2179  bool invertSurfaceOrientation)
2180  : mInputTree(&inputGrid.tree())
2181  , mInputTransform(&inputGrid.transform())
2182  , mPointIndexTree(&pointIndexTree)
2183  , mPointIndexNodes(pointIndexLeafNodes.empty() ? nullptr : &pointIndexLeafNodes.front())
2184  , mSignFlagsNodes(signFlagsLeafNodes.empty() ? nullptr : &signFlagsLeafNodes.front())
2185  , mIsovalue(iso)
2186  , mSurfaceAdaptivity(adaptivity)
2187  , mInternalAdaptivity(adaptivity)
2188  , mInvertSurfaceOrientation(invertSurfaceOrientation)
2189  , mSpatialAdaptivityTree(nullptr)
2190  , mMaskTree(nullptr)
2191  , mRefSignFlagsTree(nullptr)
2192  , mSpatialAdaptivityTransform(nullptr)
2193 {
2194 }
2195 
2196 
2197 template <typename InputGridType>
2198 void
2199 MergeVoxelRegions<InputGridType>::operator()(const tbb::blocked_range<size_t>& range) const
2200 {
2201  using Vec3sType = math::Vec3<float>;
2202  using Vec3sLeafNodeType = typename InputLeafNodeType::template ValueConverter<Vec3sType>::Type;
2203 
2204  using InputTreeAccessor = tree::ValueAccessor<const InputTreeType>;
2205  using FloatTreeAccessor = tree::ValueAccessor<const FloatTreeType>;
2206  using Index32TreeAccessor = tree::ValueAccessor<const Index32TreeType>;
2207  using Int16TreeAccessor = tree::ValueAccessor<const Int16TreeType>;
2208  using BoolTreeAccessor = tree::ValueAccessor<const BoolTreeType>;
2209 
2210  std::unique_ptr<FloatTreeAccessor> spatialAdaptivityAcc;
2211  if (mSpatialAdaptivityTree && mSpatialAdaptivityTransform) {
2212  spatialAdaptivityAcc.reset(new FloatTreeAccessor(*mSpatialAdaptivityTree));
2213  }
2214 
2215  std::unique_ptr<BoolTreeAccessor> maskAcc;
2216  if (mMaskTree) {
2217  maskAcc.reset(new BoolTreeAccessor(*mMaskTree));
2218  }
2219 
2220  std::unique_ptr<Int16TreeAccessor> refSignFlagsAcc;
2221  if (mRefSignFlagsTree) {
2222  refSignFlagsAcc.reset(new Int16TreeAccessor(*mRefSignFlagsTree));
2223  }
2224 
2225  InputTreeAccessor inputAcc(*mInputTree);
2226  Index32TreeAccessor pointIndexAcc(*mPointIndexTree);
2227 
2228  BoolLeafNodeType mask;
2229 
2230  const bool invertGradientDir = mInvertSurfaceOrientation || isBoolValue<InputValueType>();
2231  std::unique_ptr<Vec3sLeafNodeType> gradientNode;
2232 
2233  Coord ijk, end;
2234  const int LeafDim = InputLeafNodeType::DIM;
2235 
2236  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
2237 
2238  mask.setValuesOff();
2239 
2240  const Int16LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
2241  Index32LeafNodeType& pointIndexNode = *mPointIndexNodes[n];
2242 
2243  const Coord& origin = pointIndexNode.origin();
2244 
2245  end[0] = origin[0] + LeafDim;
2246  end[1] = origin[1] + LeafDim;
2247  end[2] = origin[2] + LeafDim;
2248 
2249  // Mask off seam line adjacent voxels
2250  if (maskAcc) {
2251  const BoolLeafNodeType* maskLeaf = maskAcc->probeConstLeaf(origin);
2252  if (maskLeaf != nullptr) {
2253  for (typename BoolLeafNodeType::ValueOnCIter it = maskLeaf->cbeginValueOn();
2254  it; ++it)
2255  {
2256  mask.setActiveState(it.getCoord() & ~1u, true);
2257  }
2258  }
2259  }
2260 
2261  float adaptivity = (refSignFlagsAcc && !refSignFlagsAcc->probeConstLeaf(origin)) ?
2262  mInternalAdaptivity : mSurfaceAdaptivity;
2263 
2264  bool useGradients = adaptivity < 1.0f;
2265 
2266  // Set region adaptivity
2267  FloatLeafNodeType adaptivityLeaf(origin, adaptivity);
2268 
2269  if (spatialAdaptivityAcc) {
2270  useGradients = false;
2271  for (Index offset = 0; offset < FloatLeafNodeType::NUM_VALUES; ++offset) {
2272  ijk = adaptivityLeaf.offsetToGlobalCoord(offset);
2273  ijk = mSpatialAdaptivityTransform->worldToIndexCellCentered(
2274  mInputTransform->indexToWorld(ijk));
2275  float weight = spatialAdaptivityAcc->getValue(ijk);
2276  float adaptivityValue = weight * adaptivity;
2277  if (adaptivityValue < 1.0f) useGradients = true;
2278  adaptivityLeaf.setValueOnly(offset, adaptivityValue);
2279  }
2280  }
2281 
2282  // Mask off ambiguous voxels
2283  for (auto it = signFlagsNode.cbeginValueOn(); it; ++it) {
2284  const Int16 flags = it.getValue();
2285  const unsigned char signs = static_cast<unsigned char>(SIGNS & int(flags));
2286 
2287  if ((flags & SEAM) || !sAdaptable[signs] || sEdgeGroupTable[signs][0] > 1) {
2288 
2289  mask.setActiveState(it.getCoord() & ~1u, true);
2290 
2291  } else if (flags & EDGES) {
2292 
2293  bool maskRegion = false;
2294 
2295  ijk = it.getCoord();
2296  if (!pointIndexAcc.isValueOn(ijk)) maskRegion = true;
2297 
2298  if (!maskRegion && flags & XEDGE) {
2299  ijk[1] -= 1;
2300  if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion = true;
2301  ijk[2] -= 1;
2302  if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion = true;
2303  ijk[1] += 1;
2304  if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion = true;
2305  ijk[2] += 1;
2306  }
2307 
2308  if (!maskRegion && flags & YEDGE) {
2309  ijk[2] -= 1;
2310  if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion = true;
2311  ijk[0] -= 1;
2312  if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion = true;
2313  ijk[2] += 1;
2314  if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion = true;
2315  ijk[0] += 1;
2316  }
2317 
2318  if (!maskRegion && flags & ZEDGE) {
2319  ijk[1] -= 1;
2320  if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion = true;
2321  ijk[0] -= 1;
2322  if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion = true;
2323  ijk[1] += 1;
2324  if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion = true;
2325  ijk[0] += 1;
2326  }
2327 
2328  if (maskRegion) {
2329  mask.setActiveState(it.getCoord() & ~1u, true);
2330  }
2331  }
2332  }
2333 
2334  // Mask off topologically ambiguous 2x2x2 voxel sub-blocks
2335  int dim = 2;
2336  for (ijk[0] = origin[0]; ijk[0] < end[0]; ijk[0] += dim) {
2337  for (ijk[1] = origin[1]; ijk[1] < end[1]; ijk[1] += dim) {
2338  for (ijk[2] = origin[2]; ijk[2] < end[2]; ijk[2] += dim) {
2339  if (!mask.isValueOn(ijk) & isNonManifold(inputAcc, ijk, mIsovalue, dim)) {
2340  mask.setActiveState(ijk, true);
2341  }
2342  }
2343  }
2344  }
2345 
2346  // Compute the gradient for the remaining voxels
2347 
2348  if (useGradients) {
2349 
2350  if (gradientNode) {
2351  gradientNode->setValuesOff();
2352  } else {
2353  gradientNode.reset(new Vec3sLeafNodeType());
2354  }
2355 
2356  for (auto it = signFlagsNode.cbeginValueOn(); it; ++it) {
2357  ijk = it.getCoord();
2358  if (!mask.isValueOn(ijk & ~1u)) {
2359  Vec3sType dir(math::ISGradient<math::CD_2ND>::result(inputAcc, ijk));
2360  dir.normalize();
2361 
2362  if (invertGradientDir) {
2363  dir = -dir;
2364  }
2365 
2366  gradientNode->setValueOn(it.pos(), dir);
2367  }
2368  }
2369  }
2370 
2371  // Merge regions
2372  int regionId = 1;
2373  for ( ; dim <= LeafDim; dim = dim << 1) {
2374  const unsigned coordMask = ~((dim << 1) - 1);
2375  for (ijk[0] = origin[0]; ijk[0] < end[0]; ijk[0] += dim) {
2376  for (ijk[1] = origin[1]; ijk[1] < end[1]; ijk[1] += dim) {
2377  for (ijk[2] = origin[2]; ijk[2] < end[2]; ijk[2] += dim) {
2378 
2379  adaptivity = adaptivityLeaf.getValue(ijk);
2380 
2381  if (mask.isValueOn(ijk)
2382  || isNonManifold(inputAcc, ijk, mIsovalue, dim)
2383  || (useGradients && !isMergable(*gradientNode, ijk, dim, adaptivity)))
2384  {
2385  mask.setActiveState(ijk & coordMask, true);
2386  } else {
2387  mergeVoxels(pointIndexNode, ijk, dim, regionId++);
2388  }
2389  }
2390  }
2391  }
2392  }
2393  }
2394 } // MergeVoxelRegions::operator()
2395 
2396 
2398 
2399 
2400 // Constructs qudas
2402 {
2403  UniformPrimBuilder(): mIdx(0), mPolygonPool(nullptr) {}
2404 
2405  void init(const size_t upperBound, PolygonPool& quadPool)
2406  {
2407  mPolygonPool = &quadPool;
2408  mPolygonPool->resetQuads(upperBound);
2409  mIdx = 0;
2410  }
2411 
2412  template<typename IndexType>
2413  void addPrim(const math::Vec4<IndexType>& verts, bool reverse, char flags = 0)
2414  {
2415  if (!reverse) {
2416  mPolygonPool->quad(mIdx) = verts;
2417  } else {
2418  Vec4I& quad = mPolygonPool->quad(mIdx);
2419  quad[0] = verts[3];
2420  quad[1] = verts[2];
2421  quad[2] = verts[1];
2422  quad[3] = verts[0];
2423  }
2424  mPolygonPool->quadFlags(mIdx) = flags;
2425  ++mIdx;
2426  }
2427 
2428  void done()
2429  {
2430  mPolygonPool->trimQuads(mIdx);
2431  }
2432 
2433 private:
2434  size_t mIdx;
2435  PolygonPool* mPolygonPool;
2436 };
2437 
2438 
2439 // Constructs qudas and triangles
2441 {
2442  AdaptivePrimBuilder() : mQuadIdx(0), mTriangleIdx(0), mPolygonPool(nullptr) {}
2443 
2444  void init(const size_t upperBound, PolygonPool& polygonPool)
2445  {
2446  mPolygonPool = &polygonPool;
2447  mPolygonPool->resetQuads(upperBound);
2448  mPolygonPool->resetTriangles(upperBound);
2449 
2450  mQuadIdx = 0;
2451  mTriangleIdx = 0;
2452  }
2453 
2454  template<typename IndexType>
2455  void addPrim(const math::Vec4<IndexType>& verts, bool reverse, char flags = 0)
2456  {
2457  if (verts[0] != verts[1] && verts[0] != verts[2] && verts[0] != verts[3]
2458  && verts[1] != verts[2] && verts[1] != verts[3] && verts[2] != verts[3]) {
2459  mPolygonPool->quadFlags(mQuadIdx) = flags;
2460  addQuad(verts, reverse);
2461  } else if (
2462  verts[0] == verts[3] &&
2463  verts[1] != verts[2] &&
2464  verts[1] != verts[0] &&
2465  verts[2] != verts[0]) {
2466  mPolygonPool->triangleFlags(mTriangleIdx) = flags;
2467  addTriangle(verts[0], verts[1], verts[2], reverse);
2468  } else if (
2469  verts[1] == verts[2] &&
2470  verts[0] != verts[3] &&
2471  verts[0] != verts[1] &&
2472  verts[3] != verts[1]) {
2473  mPolygonPool->triangleFlags(mTriangleIdx) = flags;
2474  addTriangle(verts[0], verts[1], verts[3], reverse);
2475  } else if (
2476  verts[0] == verts[1] &&
2477  verts[2] != verts[3] &&
2478  verts[2] != verts[0] &&
2479  verts[3] != verts[0]) {
2480  mPolygonPool->triangleFlags(mTriangleIdx) = flags;
2481  addTriangle(verts[0], verts[2], verts[3], reverse);
2482  } else if (
2483  verts[2] == verts[3] &&
2484  verts[0] != verts[1] &&
2485  verts[0] != verts[2] &&
2486  verts[1] != verts[2]) {
2487  mPolygonPool->triangleFlags(mTriangleIdx) = flags;
2488  addTriangle(verts[0], verts[1], verts[2], reverse);
2489  }
2490  }
2491 
2492 
2493  void done()
2494  {
2495  mPolygonPool->trimQuads(mQuadIdx, /*reallocate=*/true);
2496  mPolygonPool->trimTrinagles(mTriangleIdx, /*reallocate=*/true);
2497  }
2498 
2499 private:
2500 
2501  template<typename IndexType>
2502  void addQuad(const math::Vec4<IndexType>& verts, bool reverse)
2503  {
2504  if (!reverse) {
2505  mPolygonPool->quad(mQuadIdx) = verts;
2506  } else {
2507  Vec4I& quad = mPolygonPool->quad(mQuadIdx);
2508  quad[0] = verts[3];
2509  quad[1] = verts[2];
2510  quad[2] = verts[1];
2511  quad[3] = verts[0];
2512  }
2513  ++mQuadIdx;
2514  }
2515 
2516  void addTriangle(unsigned v0, unsigned v1, unsigned v2, bool reverse)
2517  {
2518  Vec3I& prim = mPolygonPool->triangle(mTriangleIdx);
2519 
2520  prim[1] = v1;
2521 
2522  if (!reverse) {
2523  prim[0] = v0;
2524  prim[2] = v2;
2525  } else {
2526  prim[0] = v2;
2527  prim[2] = v0;
2528  }
2529  ++mTriangleIdx;
2530  }
2531 
2532  size_t mQuadIdx, mTriangleIdx;
2533  PolygonPool *mPolygonPool;
2534 };
2535 
2536 
2537 template<typename SignAccT, typename IdxAccT, typename PrimBuilder>
2538 inline void
2540  bool invertSurfaceOrientation,
2541  Int16 flags,
2542  Int16 refFlags,
2543  const Vec3i& offsets,
2544  const Coord& ijk,
2545  const SignAccT& signAcc,
2546  const IdxAccT& idxAcc,
2547  PrimBuilder& mesher)
2548 {
2549  using IndexType = typename IdxAccT::ValueType;
2550 
2551  IndexType v0 = IndexType(util::INVALID_IDX);
2552  const bool isActive = idxAcc.probeValue(ijk, v0);
2553  if (isActive == false || v0 == IndexType(util::INVALID_IDX)) return;
2554 
2555  char tag[2];
2556  tag[0] = (flags & SEAM) ? POLYFLAG_FRACTURE_SEAM : 0;
2557  tag[1] = tag[0] | char(POLYFLAG_EXTERIOR);
2558 
2559  bool isInside = flags & INSIDE;
2560 
2561  isInside = invertSurfaceOrientation ? !isInside : isInside;
2562 
2563  Coord coord = ijk;
2564  math::Vec4<IndexType> quad(0,0,0,0);
2565 
2566  if (flags & XEDGE) {
2567 
2568  quad[0] = v0 + offsets[0];
2569 
2570  // i, j-1, k
2571  coord[1]--;
2572  bool activeValues = idxAcc.probeValue(coord, quad[1]);
2573  uint8_t cell = uint8_t(SIGNS & signAcc.getValue(coord));
2574  quad[1] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][5] - 1 : 0;
2575 
2576  // i, j-1, k-1
2577  coord[2]--;
2578  activeValues = activeValues && idxAcc.probeValue(coord, quad[2]);
2579  cell = uint8_t(SIGNS & signAcc.getValue(coord));
2580  quad[2] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][7] - 1 : 0;
2581 
2582  // i, j, k-1
2583  coord[1]++;
2584  activeValues = activeValues && idxAcc.probeValue(coord, quad[3]);
2585  cell = uint8_t(SIGNS & signAcc.getValue(coord));
2586  quad[3] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][3] - 1 : 0;
2587 
2588  if (activeValues) {
2589  mesher.addPrim(quad, isInside, tag[bool(refFlags & XEDGE)]);
2590  }
2591 
2592  coord[2]++; // i, j, k
2593  }
2594 
2595 
2596  if (flags & YEDGE) {
2597 
2598  quad[0] = v0 + offsets[1];
2599 
2600  // i, j, k-1
2601  coord[2]--;
2602  bool activeValues = idxAcc.probeValue(coord, quad[1]);
2603  uint8_t cell = uint8_t(SIGNS & signAcc.getValue(coord));
2604  quad[1] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][12] - 1 : 0;
2605 
2606  // i-1, j, k-1
2607  coord[0]--;
2608  activeValues = activeValues && idxAcc.probeValue(coord, quad[2]);
2609  cell = uint8_t(SIGNS & signAcc.getValue(coord));
2610  quad[2] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][11] - 1 : 0;
2611 
2612  // i-1, j, k
2613  coord[2]++;
2614  activeValues = activeValues && idxAcc.probeValue(coord, quad[3]);
2615  cell = uint8_t(SIGNS & signAcc.getValue(coord));
2616  quad[3] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][10] - 1 : 0;
2617 
2618  if (activeValues) {
2619  mesher.addPrim(quad, isInside, tag[bool(refFlags & YEDGE)]);
2620  }
2621 
2622  coord[0]++; // i, j, k
2623  }
2624 
2625 
2626  if (flags & ZEDGE) {
2627 
2628  quad[0] = v0 + offsets[2];
2629 
2630  // i, j-1, k
2631  coord[1]--;
2632  bool activeValues = idxAcc.probeValue(coord, quad[1]);
2633  uint8_t cell = uint8_t(SIGNS & signAcc.getValue(coord));
2634  quad[1] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][8] - 1 : 0;
2635 
2636  // i-1, j-1, k
2637  coord[0]--;
2638  activeValues = activeValues && idxAcc.probeValue(coord, quad[2]);
2639  cell = uint8_t(SIGNS & signAcc.getValue(coord));
2640  quad[2] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][6] - 1 : 0;
2641 
2642  // i-1, j, k
2643  coord[1]++;
2644  activeValues = activeValues && idxAcc.probeValue(coord, quad[3]);
2645  cell = uint8_t(SIGNS & signAcc.getValue(coord));
2646  quad[3] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][2] - 1 : 0;
2647 
2648  if (activeValues) {
2649  mesher.addPrim(quad, !isInside, tag[bool(refFlags & ZEDGE)]);
2650  }
2651  }
2652 }
2653 
2654 
2656 
2657 
2658 template<typename InputTreeType>
2660 {
2661  using InputValueType = typename InputTreeType::ValueType;
2662  using BoolTreeType = typename InputTreeType::template ValueConverter<bool>::Type;
2663 
2664 
2665  MaskTileBorders(const InputTreeType& inputTree, InputValueType iso,
2666  BoolTreeType& mask, const Vec4i* tileArray)
2667  : mInputTree(&inputTree)
2668  , mIsovalue(iso)
2669  , mTempMask(false)
2670  , mMask(&mask)
2671  , mTileArray(tileArray)
2672  {
2673  }
2674 
2676  : mInputTree(rhs.mInputTree)
2677  , mIsovalue(rhs.mIsovalue)
2678  , mTempMask(false)
2679  , mMask(&mTempMask)
2680  , mTileArray(rhs.mTileArray)
2681  {
2682  }
2683 
2684  void join(MaskTileBorders& rhs) { mMask->merge(*rhs.mMask); }
2685 
2686  void operator()(const tbb::blocked_range<size_t>&);
2687 
2688 private:
2689  InputTreeType const * const mInputTree;
2690  InputValueType const mIsovalue;
2691  BoolTreeType mTempMask;
2692  BoolTreeType * const mMask;
2693  Vec4i const * const mTileArray;
2694 }; // MaskTileBorders
2695 
2696 
2697 template<typename InputTreeType>
2698 void
2699 MaskTileBorders<InputTreeType>::operator()(const tbb::blocked_range<size_t>& range)
2700 {
2701  tree::ValueAccessor<const InputTreeType> inputTreeAcc(*mInputTree);
2702 
2703  CoordBBox region, bbox;
2704  Coord ijk, nijk;
2705 
2706  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
2707 
2708  const Vec4i& tile = mTileArray[n];
2709 
2710  bbox.min()[0] = tile[0];
2711  bbox.min()[1] = tile[1];
2712  bbox.min()[2] = tile[2];
2713  bbox.max() = bbox.min();
2714  bbox.max().offset(tile[3]);
2715 
2716  InputValueType value = mInputTree->background();
2717 
2718  const bool isInside = isInsideValue(inputTreeAcc.getValue(bbox.min()), mIsovalue);
2719  const int valueDepth = inputTreeAcc.getValueDepth(bbox.min());
2720 
2721  // eval x-edges
2722 
2723  ijk = bbox.max();
2724  nijk = ijk;
2725  ++nijk[0];
2726 
2727  bool processRegion = true;
2728  if (valueDepth >= inputTreeAcc.getValueDepth(nijk)) {
2729  processRegion = isInside != isInsideValue(inputTreeAcc.getValue(nijk), mIsovalue);
2730  }
2731 
2732  if (processRegion) {
2733  region = bbox;
2734  region.expand(1);
2735  region.min()[0] = region.max()[0] = ijk[0];
2736  mMask->fill(region, false);
2737  }
2738 
2739 
2740  ijk = bbox.min();
2741  --ijk[0];
2742 
2743  processRegion = true;
2744  if (valueDepth >= inputTreeAcc.getValueDepth(ijk)) {
2745  processRegion = (!inputTreeAcc.probeValue(ijk, value)
2746  && isInside != isInsideValue(value, mIsovalue));
2747  }
2748 
2749  if (processRegion) {
2750  region = bbox;
2751  region.expand(1);
2752  region.min()[0] = region.max()[0] = ijk[0];
2753  mMask->fill(region, false);
2754  }
2755 
2756 
2757  // eval y-edges
2758 
2759  ijk = bbox.max();
2760  nijk = ijk;
2761  ++nijk[1];
2762 
2763  processRegion = true;
2764  if (valueDepth >= inputTreeAcc.getValueDepth(nijk)) {
2765  processRegion = isInside != isInsideValue(inputTreeAcc.getValue(nijk), mIsovalue);
2766  }
2767 
2768  if (processRegion) {
2769  region = bbox;
2770  region.expand(1);
2771  region.min()[1] = region.max()[1] = ijk[1];
2772  mMask->fill(region, false);
2773  }
2774 
2775 
2776  ijk = bbox.min();
2777  --ijk[1];
2778 
2779  processRegion = true;
2780  if (valueDepth >= inputTreeAcc.getValueDepth(ijk)) {
2781  processRegion = (!inputTreeAcc.probeValue(ijk, value)
2782  && isInside != isInsideValue(value, mIsovalue));
2783  }
2784 
2785  if (processRegion) {
2786  region = bbox;
2787  region.expand(1);
2788  region.min()[1] = region.max()[1] = ijk[1];
2789  mMask->fill(region, false);
2790  }
2791 
2792 
2793  // eval z-edges
2794 
2795  ijk = bbox.max();
2796  nijk = ijk;
2797  ++nijk[2];
2798 
2799  processRegion = true;
2800  if (valueDepth >= inputTreeAcc.getValueDepth(nijk)) {
2801  processRegion = isInside != isInsideValue(inputTreeAcc.getValue(nijk), mIsovalue);
2802  }
2803 
2804  if (processRegion) {
2805  region = bbox;
2806  region.expand(1);
2807  region.min()[2] = region.max()[2] = ijk[2];
2808  mMask->fill(region, false);
2809  }
2810 
2811  ijk = bbox.min();
2812  --ijk[2];
2813 
2814  processRegion = true;
2815  if (valueDepth >= inputTreeAcc.getValueDepth(ijk)) {
2816  processRegion = (!inputTreeAcc.probeValue(ijk, value)
2817  && isInside != isInsideValue(value, mIsovalue));
2818  }
2819 
2820  if (processRegion) {
2821  region = bbox;
2822  region.expand(1);
2823  region.min()[2] = region.max()[2] = ijk[2];
2824  mMask->fill(region, false);
2825  }
2826  }
2827 } // MaskTileBorders::operator()
2828 
2829 
2830 template<typename InputTreeType>
2831 inline void
2832 maskActiveTileBorders(const InputTreeType& inputTree, typename InputTreeType::ValueType iso,
2833  typename InputTreeType::template ValueConverter<bool>::Type& mask)
2834 {
2835  typename InputTreeType::ValueOnCIter tileIter(inputTree);
2836  tileIter.setMaxDepth(InputTreeType::ValueOnCIter::LEAF_DEPTH - 1);
2837 
2838  size_t tileCount = 0;
2839  for ( ; tileIter; ++tileIter) {
2840  ++tileCount;
2841  }
2842 
2843  if (tileCount > 0) {
2844  boost::scoped_array<Vec4i> tiles(new Vec4i[tileCount]);
2845 
2846  CoordBBox bbox;
2847  size_t index = 0;
2848 
2849  tileIter = inputTree.cbeginValueOn();
2850  tileIter.setMaxDepth(InputTreeType::ValueOnCIter::LEAF_DEPTH - 1);
2851 
2852  for (; tileIter; ++tileIter) {
2853  Vec4i& tile = tiles[index++];
2854  tileIter.getBoundingBox(bbox);
2855  tile[0] = bbox.min()[0];
2856  tile[1] = bbox.min()[1];
2857  tile[2] = bbox.min()[2];
2858  tile[3] = bbox.max()[0] - bbox.min()[0];
2859  }
2860 
2861  MaskTileBorders<InputTreeType> op(inputTree, iso, mask, tiles.get());
2862  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, tileCount), op);
2863  }
2864 }
2865 
2866 
2868 
2869 
2870 // Utility class for the volumeToMesh wrapper
2872 {
2873 public:
2874  PointListCopy(const PointList& pointsIn, std::vector<Vec3s>& pointsOut)
2875  : mPointsIn(pointsIn) , mPointsOut(pointsOut)
2876  {
2877  }
2878 
2879  void operator()(const tbb::blocked_range<size_t>& range) const
2880  {
2881  for (size_t n = range.begin(); n < range.end(); ++n) {
2882  mPointsOut[n] = mPointsIn[n];
2883  }
2884  }
2885 
2886 private:
2887  const PointList& mPointsIn;
2888  std::vector<Vec3s>& mPointsOut;
2889 };
2890 
2891 
2894 
2895 
2897 {
2898  using IndexVector = std::vector<Index>;
2899 
2900  template<typename LeafNodeType>
2901  void constructOffsetList();
2902 
2904  const IndexVector& core() const { return mCore; }
2905 
2906 
2908  const IndexVector& minX() const { return mMinX; }
2909 
2911  const IndexVector& maxX() const { return mMaxX; }
2912 
2913 
2915  const IndexVector& minY() const { return mMinY; }
2916 
2918  const IndexVector& maxY() const { return mMaxY; }
2919 
2920 
2922  const IndexVector& minZ() const { return mMinZ; }
2923 
2925  const IndexVector& maxZ() const { return mMaxZ; }
2926 
2927 
2929  const IndexVector& internalNeighborsX() const { return mInternalNeighborsX; }
2930 
2932  const IndexVector& internalNeighborsY() const { return mInternalNeighborsY; }
2933 
2935  const IndexVector& internalNeighborsZ() const { return mInternalNeighborsZ; }
2936 
2937 
2938 private:
2939  IndexVector mCore, mMinX, mMaxX, mMinY, mMaxY, mMinZ, mMaxZ,
2940  mInternalNeighborsX, mInternalNeighborsY, mInternalNeighborsZ;
2941 }; // struct LeafNodeOffsets
2942 
2943 
2944 template<typename LeafNodeType>
2945 inline void
2947 {
2948  // internal core voxels
2949  mCore.clear();
2950  mCore.reserve((LeafNodeType::DIM - 2) * (LeafNodeType::DIM - 2));
2951 
2952  for (Index x = 1; x < (LeafNodeType::DIM - 1); ++x) {
2953  const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2954  for (Index y = 1; y < (LeafNodeType::DIM - 1); ++y) {
2955  const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2956  for (Index z = 1; z < (LeafNodeType::DIM - 1); ++z) {
2957  mCore.push_back(offsetXY + z);
2958  }
2959  }
2960  }
2961 
2962  // internal neighbors in x + 1
2963  mInternalNeighborsX.clear();
2964  mInternalNeighborsX.reserve(LeafNodeType::SIZE - (LeafNodeType::DIM * LeafNodeType::DIM));
2965 
2966  for (Index x = 0; x < (LeafNodeType::DIM - 1); ++x) {
2967  const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2968  for (Index y = 0; y < LeafNodeType::DIM; ++y) {
2969  const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2970  for (Index z = 0; z < LeafNodeType::DIM; ++z) {
2971  mInternalNeighborsX.push_back(offsetXY + z);
2972  }
2973  }
2974  }
2975 
2976  // internal neighbors in y + 1
2977  mInternalNeighborsY.clear();
2978  mInternalNeighborsY.reserve(LeafNodeType::SIZE - (LeafNodeType::DIM * LeafNodeType::DIM));
2979 
2980  for (Index x = 0; x < LeafNodeType::DIM; ++x) {
2981  const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2982  for (Index y = 0; y < (LeafNodeType::DIM - 1); ++y) {
2983  const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2984  for (Index z = 0; z < LeafNodeType::DIM; ++z) {
2985  mInternalNeighborsY.push_back(offsetXY + z);
2986  }
2987  }
2988  }
2989 
2990  // internal neighbors in z + 1
2991  mInternalNeighborsZ.clear();
2992  mInternalNeighborsZ.reserve(LeafNodeType::SIZE - (LeafNodeType::DIM * LeafNodeType::DIM));
2993 
2994  for (Index x = 0; x < LeafNodeType::DIM; ++x) {
2995  const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2996  for (Index y = 0; y < LeafNodeType::DIM; ++y) {
2997  const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2998  for (Index z = 0; z < (LeafNodeType::DIM - 1); ++z) {
2999  mInternalNeighborsZ.push_back(offsetXY + z);
3000  }
3001  }
3002  }
3003 
3004  // min x
3005  mMinX.clear();
3006  mMinX.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3007  {
3008  for (Index y = 0; y < LeafNodeType::DIM; ++y) {
3009  const Index offsetXY = (y << LeafNodeType::LOG2DIM);
3010  for (Index z = 0; z < LeafNodeType::DIM; ++z) {
3011  mMinX.push_back(offsetXY + z);
3012  }
3013  }
3014  }
3015 
3016  // max x
3017  mMaxX.clear();
3018  mMaxX.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3019  {
3020  const Index offsetX = (LeafNodeType::DIM - 1) << (2 * LeafNodeType::LOG2DIM);
3021  for (Index y = 0; y < LeafNodeType::DIM; ++y) {
3022  const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
3023  for (Index z = 0; z < LeafNodeType::DIM; ++z) {
3024  mMaxX.push_back(offsetXY + z);
3025  }
3026  }
3027  }
3028 
3029  // min y
3030  mMinY.clear();
3031  mMinY.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3032  {
3033  for (Index x = 0; x < LeafNodeType::DIM; ++x) {
3034  const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
3035  for (Index z = 0; z < (LeafNodeType::DIM - 1); ++z) {
3036  mMinY.push_back(offsetX + z);
3037  }
3038  }
3039  }
3040 
3041  // max y
3042  mMaxY.clear();
3043  mMaxY.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3044  {
3045  const Index offsetY = (LeafNodeType::DIM - 1) << LeafNodeType::LOG2DIM;
3046  for (Index x = 0; x < LeafNodeType::DIM; ++x) {
3047  const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
3048  for (Index z = 0; z < (LeafNodeType::DIM - 1); ++z) {
3049  mMaxY.push_back(offsetX + offsetY + z);
3050  }
3051  }
3052  }
3053 
3054  // min z
3055  mMinZ.clear();
3056  mMinZ.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3057  {
3058  for (Index x = 0; x < LeafNodeType::DIM; ++x) {
3059  const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
3060  for (Index y = 0; y < LeafNodeType::DIM; ++y) {
3061  const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
3062  mMinZ.push_back(offsetXY);
3063  }
3064  }
3065  }
3066 
3067  // max z
3068  mMaxZ.clear();
3069  mMaxZ.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3070  {
3071  for (Index x = 0; x < LeafNodeType::DIM; ++x) {
3072  const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
3073  for (Index y = 0; y < LeafNodeType::DIM; ++y) {
3074  const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
3075  mMaxZ.push_back(offsetXY + (LeafNodeType::DIM - 1));
3076  }
3077  }
3078  }
3079 }
3080 
3081 
3083 
3084 
3086 template<typename AccessorT, int _AXIS>
3088 
3089  enum { AXIS = _AXIS };
3090  AccessorT& acc;
3091 
3092  VoxelEdgeAccessor(AccessorT& _acc) : acc(_acc) {}
3093 
3094  void set(Coord ijk) {
3095  if (_AXIS == 0) { // x + 1 edge
3096  acc.setActiveState(ijk);
3097  --ijk[1]; // set i, j-1, k
3098  acc.setActiveState(ijk);
3099  --ijk[2]; // set i, j-1, k-1
3100  acc.setActiveState(ijk);
3101  ++ijk[1]; // set i, j, k-1
3102  acc.setActiveState(ijk);
3103  } else if (_AXIS == 1) { // y + 1 edge
3104  acc.setActiveState(ijk);
3105  --ijk[2]; // set i, j, k-1
3106  acc.setActiveState(ijk);
3107  --ijk[0]; // set i-1, j, k-1
3108  acc.setActiveState(ijk);
3109  ++ijk[2]; // set i-1, j, k
3110  acc.setActiveState(ijk);
3111  } else { // z + 1 edge
3112  acc.setActiveState(ijk);
3113  --ijk[1]; // set i, j-1, k
3114  acc.setActiveState(ijk);
3115  --ijk[0]; // set i-1, j-1, k
3116  acc.setActiveState(ijk);
3117  ++ijk[1]; // set i-1, j, k
3118  acc.setActiveState(ijk);
3119  }
3120  }
3121 };
3122 
3123 
3127 template<typename VoxelEdgeAcc, typename LeafNode>
3128 void
3129 evalInternalVoxelEdges(VoxelEdgeAcc& edgeAcc, const LeafNode& leafnode,
3130  const LeafNodeVoxelOffsets& voxels, const typename LeafNode::ValueType iso)
3131 {
3132  Index nvo = 1; // neighbour voxel offset, z + 1 direction assumed initially.
3133  const std::vector<Index>* offsets = &voxels.internalNeighborsZ();
3134 
3135  if (VoxelEdgeAcc::AXIS == 0) { // x + 1 direction
3136  nvo = LeafNode::DIM * LeafNode::DIM;
3137  offsets = &voxels.internalNeighborsX();
3138  } else if (VoxelEdgeAcc::AXIS == 1) { // y + 1 direction
3139  nvo = LeafNode::DIM;
3140  offsets = &voxels.internalNeighborsY();
3141  }
3142 
3143  for (size_t n = 0, N = offsets->size(); n < N; ++n) {
3144  const Index& pos = (*offsets)[n];
3145  bool isActive = leafnode.isValueOn(pos) || leafnode.isValueOn(pos + nvo);
3146  if (isActive && (isInsideValue(leafnode.getValue(pos), iso) !=
3147  isInsideValue(leafnode.getValue(pos + nvo), iso))) {
3148  edgeAcc.set(leafnode.offsetToGlobalCoord(pos));
3149  }
3150  }
3151 }
3152 
3153 
3157 template<typename LeafNode, typename TreeAcc, typename VoxelEdgeAcc>
3158 void
3159 evalExtrenalVoxelEdges(VoxelEdgeAcc& edgeAcc, TreeAcc& acc, const LeafNode& lhsNode,
3160  const LeafNodeVoxelOffsets& voxels, const typename LeafNode::ValueType iso)
3161 {
3162  const std::vector<Index>* lhsOffsets = &voxels.maxX();
3163  const std::vector<Index>* rhsOffsets = &voxels.minX();
3164  Coord ijk = lhsNode.origin();
3165 
3166  if (VoxelEdgeAcc::AXIS == 0) { // back leafnode face
3167  ijk[0] += LeafNode::DIM;
3168  } else if (VoxelEdgeAcc::AXIS == 1) { // top leafnode face
3169  ijk[1] += LeafNode::DIM;
3170  lhsOffsets = &voxels.maxY();
3171  rhsOffsets = &voxels.minY();
3172  } else if (VoxelEdgeAcc::AXIS == 2) { // right leafnode face
3173  ijk[2] += LeafNode::DIM;
3174  lhsOffsets = &voxels.maxZ();
3175  rhsOffsets = &voxels.minZ();
3176  }
3177 
3178  typename LeafNode::ValueType value;
3179  const LeafNode* rhsNodePt = acc.probeConstLeaf(ijk);
3180 
3181  if (rhsNodePt) {
3182  for (size_t n = 0, N = lhsOffsets->size(); n < N; ++n) {
3183  const Index& pos = (*lhsOffsets)[n];
3184  bool isActive = lhsNode.isValueOn(pos) || rhsNodePt->isValueOn((*rhsOffsets)[n]);
3185  if (isActive && (isInsideValue(lhsNode.getValue(pos), iso) !=
3186  isInsideValue(rhsNodePt->getValue((*rhsOffsets)[n]), iso))) {
3187  edgeAcc.set(lhsNode.offsetToGlobalCoord(pos));
3188  }
3189  }
3190  } else if (!acc.probeValue(ijk, value)) {
3191  const bool inside = isInsideValue(value, iso);
3192  for (size_t n = 0, N = lhsOffsets->size(); n < N; ++n) {
3193  const Index& pos = (*lhsOffsets)[n];
3194  if (lhsNode.isValueOn(pos) && (inside != isInsideValue(lhsNode.getValue(pos), iso))) {
3195  edgeAcc.set(lhsNode.offsetToGlobalCoord(pos));
3196  }
3197  }
3198  }
3199 }
3200 
3201 
3205 template<typename LeafNode, typename TreeAcc, typename VoxelEdgeAcc>
3206 void
3207 evalExtrenalVoxelEdgesInv(VoxelEdgeAcc& edgeAcc, TreeAcc& acc, const LeafNode& leafnode,
3208  const LeafNodeVoxelOffsets& voxels, const typename LeafNode::ValueType iso)
3209 {
3210  Coord ijk = leafnode.origin();
3211  if (VoxelEdgeAcc::AXIS == 0) --ijk[0]; // front leafnode face
3212  else if (VoxelEdgeAcc::AXIS == 1) --ijk[1]; // bottom leafnode face
3213  else if (VoxelEdgeAcc::AXIS == 2) --ijk[2]; // left leafnode face
3214 
3215  typename LeafNode::ValueType value;
3216  if (!acc.probeConstLeaf(ijk) && !acc.probeValue(ijk, value)) {
3217 
3218  const std::vector<Index>* offsets = &voxels.internalNeighborsX();
3219  if (VoxelEdgeAcc::AXIS == 1) offsets = &voxels.internalNeighborsY();
3220  else if (VoxelEdgeAcc::AXIS == 2) offsets = &voxels.internalNeighborsZ();
3221 
3222  const bool inside = isInsideValue(value, iso);
3223  for (size_t n = 0, N = offsets->size(); n < N; ++n) {
3224 
3225  const Index& pos = (*offsets)[n];
3226  if (leafnode.isValueOn(pos)
3227  && (inside != isInsideValue(leafnode.getValue(pos), iso)))
3228  {
3229  ijk = leafnode.offsetToGlobalCoord(pos);
3230  if (VoxelEdgeAcc::AXIS == 0) --ijk[0];
3231  else if (VoxelEdgeAcc::AXIS == 1) --ijk[1];
3232  else if (VoxelEdgeAcc::AXIS == 2) --ijk[2];
3233 
3234  edgeAcc.set(ijk);
3235  }
3236  }
3237  }
3238 }
3239 
3240 
3241 
3242 template<typename InputTreeType>
3244 {
3245  using InputLeafNodeType = typename InputTreeType::LeafNodeType;
3246  using InputValueType = typename InputLeafNodeType::ValueType;
3247 
3248  using BoolTreeType = typename InputTreeType::template ValueConverter<bool>::Type;
3249 
3251  const InputTreeType& inputTree,
3252  const std::vector<const InputLeafNodeType*>& inputLeafNodes,
3253  BoolTreeType& intersectionTree,
3254  InputValueType iso);
3255 
3257  void operator()(const tbb::blocked_range<size_t>&);
3259  mIntersectionAccessor.tree().merge(rhs.mIntersectionAccessor.tree());
3260  }
3261 
3262 private:
3264  InputLeafNodeType const * const * const mInputNodes;
3265 
3266  BoolTreeType mIntersectionTree;
3267  tree::ValueAccessor<BoolTreeType> mIntersectionAccessor;
3268 
3269  LeafNodeVoxelOffsets mOffsetData;
3270  const LeafNodeVoxelOffsets* mOffsets;
3271 
3272  InputValueType mIsovalue;
3273 }; // struct IdentifyIntersectingVoxels
3274 
3275 
3276 template<typename InputTreeType>
3278  const InputTreeType& inputTree,
3279  const std::vector<const InputLeafNodeType*>& inputLeafNodes,
3280  BoolTreeType& intersectionTree,
3281  InputValueType iso)
3282  : mInputAccessor(inputTree)
3283  , mInputNodes(inputLeafNodes.empty() ? nullptr : &inputLeafNodes.front())
3284  , mIntersectionTree(false)
3285  , mIntersectionAccessor(intersectionTree)
3286  , mOffsetData()
3287  , mOffsets(&mOffsetData)
3288  , mIsovalue(iso)
3289 {
3290  mOffsetData.constructOffsetList<InputLeafNodeType>();
3291 }
3292 
3293 
3294 template<typename InputTreeType>
3296  IdentifyIntersectingVoxels& rhs, tbb::split)
3297  : mInputAccessor(rhs.mInputAccessor.tree())
3298  , mInputNodes(rhs.mInputNodes)
3299  , mIntersectionTree(false)
3300  , mIntersectionAccessor(mIntersectionTree) // use local tree.
3301  , mOffsetData()
3302  , mOffsets(rhs.mOffsets) // reference data from main instance.
3303  , mIsovalue(rhs.mIsovalue)
3304 {
3305 }
3306 
3307 
3308 template<typename InputTreeType>
3309 void
3310 IdentifyIntersectingVoxels<InputTreeType>::operator()(const tbb::blocked_range<size_t>& range)
3311 {
3312  VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 0> xEdgeAcc(mIntersectionAccessor);
3313  VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 1> yEdgeAcc(mIntersectionAccessor);
3314  VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 2> zEdgeAcc(mIntersectionAccessor);
3315 
3316  for (size_t n = range.begin(); n != range.end(); ++n) {
3317 
3318  const InputLeafNodeType& node = *mInputNodes[n];
3319 
3320  // internal x + 1 voxel edges
3321  evalInternalVoxelEdges(xEdgeAcc, node, *mOffsets, mIsovalue);
3322  // internal y + 1 voxel edges
3323  evalInternalVoxelEdges(yEdgeAcc, node, *mOffsets, mIsovalue);
3324  // internal z + 1 voxel edges
3325  evalInternalVoxelEdges(zEdgeAcc, node, *mOffsets, mIsovalue);
3326 
3327  // external x + 1 voxels edges (back face)
3328  evalExtrenalVoxelEdges(xEdgeAcc, mInputAccessor, node, *mOffsets, mIsovalue);
3329  // external y + 1 voxels edges (top face)
3330  evalExtrenalVoxelEdges(yEdgeAcc, mInputAccessor, node, *mOffsets, mIsovalue);
3331  // external z + 1 voxels edges (right face)
3332  evalExtrenalVoxelEdges(zEdgeAcc, mInputAccessor, node, *mOffsets, mIsovalue);
3333 
3334  // The remaining edges are only checked if the leafnode neighbour, in the
3335  // corresponding direction, is an inactive tile.
3336 
3337  // external x - 1 voxels edges (front face)
3338  evalExtrenalVoxelEdgesInv(xEdgeAcc, mInputAccessor, node, *mOffsets, mIsovalue);
3339  // external y - 1 voxels edges (bottom face)
3340  evalExtrenalVoxelEdgesInv(yEdgeAcc, mInputAccessor, node, *mOffsets, mIsovalue);
3341  // external z - 1 voxels edges (left face)
3342  evalExtrenalVoxelEdgesInv(zEdgeAcc, mInputAccessor, node, *mOffsets, mIsovalue);
3343  }
3344 } // IdentifyIntersectingVoxels::operator()
3345 
3346 
3347 template<typename InputTreeType>
3348 inline void
3350  typename InputTreeType::template ValueConverter<bool>::Type& intersectionTree,
3351  const InputTreeType& inputTree,
3352  typename InputTreeType::ValueType isovalue)
3353 {
3354  using InputLeafNodeType = typename InputTreeType::LeafNodeType;
3355 
3356  std::vector<const InputLeafNodeType*> inputLeafNodes;
3357  inputTree.getNodes(inputLeafNodes);
3358 
3360  inputTree, inputLeafNodes, intersectionTree, isovalue);
3361 
3362  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, inputLeafNodes.size()), op);
3363 
3364  maskActiveTileBorders(inputTree, isovalue, intersectionTree);
3365 }
3366 
3367 
3369 
3370 
3371 template<typename InputTreeType>
3373 {
3374  using InputLeafNodeType = typename InputTreeType::LeafNodeType;
3375  using InputValueType = typename InputLeafNodeType::ValueType;
3376 
3377  using BoolTreeType = typename InputTreeType::template ValueConverter<bool>::Type;
3378  using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
3379 
3381  const InputTreeType& inputTree,
3382  const std::vector<BoolLeafNodeType*>& nodes,
3383  BoolTreeType& intersectionTree,
3384  InputValueType iso);
3385 
3387  void operator()(const tbb::blocked_range<size_t>&);
3388  void join(const MaskIntersectingVoxels& rhs) {
3389  mIntersectionAccessor.tree().merge(rhs.mIntersectionAccessor.tree());
3390  }
3391 
3392 private:
3394  BoolLeafNodeType const * const * const mNodes;
3395 
3396  BoolTreeType mIntersectionTree;
3397  tree::ValueAccessor<BoolTreeType> mIntersectionAccessor;
3398 
3399  InputValueType mIsovalue;
3400 }; // struct MaskIntersectingVoxels
3401 
3402 
3403 template<typename InputTreeType>
3405  const InputTreeType& inputTree,
3406  const std::vector<BoolLeafNodeType*>& nodes,
3407  BoolTreeType& intersectionTree,
3408  InputValueType iso)
3409  : mInputAccessor(inputTree)
3410  , mNodes(nodes.empty() ? nullptr : &nodes.front())
3411  , mIntersectionTree(false)
3412  , mIntersectionAccessor(intersectionTree)
3413  , mIsovalue(iso)
3414 {
3415 }
3416 
3417 
3418 template<typename InputTreeType>
3420  MaskIntersectingVoxels& rhs, tbb::split)
3421  : mInputAccessor(rhs.mInputAccessor.tree())
3422  , mNodes(rhs.mNodes)
3423  , mIntersectionTree(false)
3424  , mIntersectionAccessor(mIntersectionTree) // use local tree.
3425  , mIsovalue(rhs.mIsovalue)
3426 {
3427 }
3428 
3429 
3430 template<typename InputTreeType>
3431 void
3432 MaskIntersectingVoxels<InputTreeType>::operator()(const tbb::blocked_range<size_t>& range)
3433 {
3434  VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 0> xEdgeAcc(mIntersectionAccessor);
3435  VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 1> yEdgeAcc(mIntersectionAccessor);
3436  VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 2> zEdgeAcc(mIntersectionAccessor);
3437 
3438  Coord ijk(0, 0, 0);
3439  InputValueType iso(mIsovalue);
3440 
3441  for (size_t n = range.begin(); n != range.end(); ++n) {
3442 
3443  const BoolLeafNodeType& node = *mNodes[n];
3444 
3445  for (typename BoolLeafNodeType::ValueOnCIter it = node.cbeginValueOn(); it; ++it) {
3446 
3447  if (!it.getValue()) {
3448 
3449  ijk = it.getCoord();
3450 
3451  const bool inside = isInsideValue(mInputAccessor.getValue(ijk), iso);
3452 
3453  if (inside != isInsideValue(mInputAccessor.getValue(ijk.offsetBy(1, 0, 0)), iso)) {
3454  xEdgeAcc.set(ijk);
3455  }
3456 
3457  if (inside != isInsideValue(mInputAccessor.getValue(ijk.offsetBy(0, 1, 0)), iso)) {
3458  yEdgeAcc.set(ijk);
3459  }
3460 
3461  if (inside != isInsideValue(mInputAccessor.getValue(ijk.offsetBy(0, 0, 1)), iso)) {
3462  zEdgeAcc.set(ijk);
3463  }
3464  }
3465  }
3466  }
3467 } // MaskIntersectingVoxels::operator()
3468 
3469 
3470 template<typename BoolTreeType>
3472 {
3473  using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
3474 
3475  MaskBorderVoxels(const BoolTreeType& maskTree,
3476  const std::vector<BoolLeafNodeType*>& maskNodes,
3477  BoolTreeType& borderTree)
3478  : mMaskTree(&maskTree)
3479  , mMaskNodes(maskNodes.empty() ? nullptr : &maskNodes.front())
3480  , mTmpBorderTree(false)
3481  , mBorderTree(&borderTree)
3482  {
3483  }
3484 
3486  : mMaskTree(rhs.mMaskTree)
3487  , mMaskNodes(rhs.mMaskNodes)
3488  , mTmpBorderTree(false)
3489  , mBorderTree(&mTmpBorderTree)
3490  {
3491  }
3492 
3493  void join(MaskBorderVoxels& rhs) { mBorderTree->merge(*rhs.mBorderTree); }
3494 
3495  void operator()(const tbb::blocked_range<size_t>& range)
3496  {
3497  tree::ValueAccessor<const BoolTreeType> maskAcc(*mMaskTree);
3498  tree::ValueAccessor<BoolTreeType> borderAcc(*mBorderTree);
3499  Coord ijk(0, 0, 0);
3500 
3501  for (size_t n = range.begin(); n != range.end(); ++n) {
3502 
3503  const BoolLeafNodeType& node = *mMaskNodes[n];
3504 
3505  for (typename BoolLeafNodeType::ValueOnCIter it = node.cbeginValueOn(); it; ++it) {
3506 
3507  ijk = it.getCoord();
3508 
3509  const bool lhs = it.getValue();
3510  bool rhs = lhs;
3511 
3512  bool isEdgeVoxel = false;
3513 
3514  ijk[2] += 1; // i, j, k+1
3515  isEdgeVoxel = (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3516 
3517  ijk[1] += 1; // i, j+1, k+1
3518  isEdgeVoxel = isEdgeVoxel || (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3519 
3520  ijk[0] += 1; // i+1, j+1, k+1
3521  isEdgeVoxel = isEdgeVoxel || (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3522 
3523  ijk[1] -= 1; // i+1, j, k+1
3524  isEdgeVoxel = isEdgeVoxel || (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3525 
3526 
3527  ijk[2] -= 1; // i+1, j, k
3528  isEdgeVoxel = isEdgeVoxel || (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3529 
3530  ijk[1] += 1; // i+1, j+1, k
3531  isEdgeVoxel = isEdgeVoxel || (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3532 
3533  ijk[0] -= 1; // i, j+1, k
3534  isEdgeVoxel = isEdgeVoxel || (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3535 
3536  if (isEdgeVoxel) {
3537  ijk[1] -= 1; // i, j, k
3538  borderAcc.setValue(ijk, true);
3539  }
3540  }
3541  }
3542  }
3543 
3544 private:
3545  BoolTreeType const * const mMaskTree;
3546  BoolLeafNodeType const * const * const mMaskNodes;
3547 
3548  BoolTreeType mTmpBorderTree;
3549  BoolTreeType * const mBorderTree;
3550 }; // struct MaskBorderVoxels
3551 
3552 
3553 template<typename BoolTreeType>
3555 {
3556  using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
3557 
3558  SyncMaskValues(const std::vector<BoolLeafNodeType*>& nodes, const BoolTreeType& mask)
3559  : mNodes(nodes.empty() ? nullptr : &nodes.front())
3560  , mMaskTree(&mask)
3561  {
3562  }
3563 
3564  void operator()(const tbb::blocked_range<size_t>& range) const
3565  {
3566  using ValueOnIter = typename BoolLeafNodeType::ValueOnIter;
3567 
3568  tree::ValueAccessor<const BoolTreeType> maskTreeAcc(*mMaskTree);
3569 
3570  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
3571 
3572  BoolLeafNodeType& node = *mNodes[n];
3573 
3574  const BoolLeafNodeType * maskNode = maskTreeAcc.probeConstLeaf(node.origin());
3575 
3576  if (maskNode) {
3577  for (ValueOnIter it = node.beginValueOn(); it; ++it) {
3578  const Index pos = it.pos();
3579  if (maskNode->getValue(pos)) {
3580  node.setValueOnly(pos, true);
3581  }
3582  }
3583  }
3584  }
3585  }
3586 
3587 private:
3588  BoolLeafNodeType * const * const mNodes;
3589  BoolTreeType const * const mMaskTree;
3590 }; // struct SyncMaskValues
3591 
3592 
3594 
3595 
3596 template<typename BoolTreeType>
3598 {
3599  using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
3600 
3601  MaskSurface(const std::vector<BoolLeafNodeType*>& nodes, const BoolTreeType& mask,
3602  const math::Transform& inputTransform, const math::Transform& maskTransform, bool invert)
3603  : mNodes(nodes.empty() ? nullptr : &nodes.front())
3604  , mMaskTree(&mask)
3605  , mInputTransform(inputTransform)
3606  , mMaskTransform(maskTransform)
3607  , mInvertMask(invert)
3608  {
3609  }
3610 
3611  void operator()(const tbb::blocked_range<size_t>& range) const
3612  {
3613  using ValueOnIter = typename BoolLeafNodeType::ValueOnIter;
3614 
3615  tree::ValueAccessor<const BoolTreeType> maskTreeAcc(*mMaskTree);
3616 
3617  const bool matchingTransforms = mInputTransform == mMaskTransform;
3618  const bool maskState = mInvertMask;
3619 
3620  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
3621 
3622  BoolLeafNodeType& node = *mNodes[n];
3623 
3624  if (matchingTransforms) {
3625 
3626  const BoolLeafNodeType * maskNode = maskTreeAcc.probeConstLeaf(node.origin());
3627 
3628  if (maskNode) {
3629 
3630  for (ValueOnIter it = node.beginValueOn(); it; ++it) {
3631  const Index pos = it.pos();
3632  if (maskNode->isValueOn(pos) == maskState) {
3633  node.setValueOnly(pos, true);
3634  }
3635  }
3636 
3637  } else {
3638 
3639  if (maskTreeAcc.isValueOn(node.origin()) == maskState) {
3640  for (ValueOnIter it = node.beginValueOn(); it; ++it) {
3641  node.setValueOnly(it.pos(), true);
3642  }
3643  }
3644 
3645  }
3646 
3647  } else {
3648 
3649  Coord ijk(0, 0, 0);
3650 
3651  for (ValueOnIter it = node.beginValueOn(); it; ++it) {
3652 
3653  ijk = mMaskTransform.worldToIndexCellCentered(
3654  mInputTransform.indexToWorld(it.getCoord()));
3655 
3656  if (maskTreeAcc.isValueOn(ijk) == maskState) {
3657  node.setValueOnly(it.pos(), true);
3658  }
3659  }
3660 
3661  }
3662  }
3663  }
3664 
3665 private:
3666  BoolLeafNodeType * const * const mNodes;
3667  BoolTreeType const * const mMaskTree;
3668  math::Transform const mInputTransform;
3669  math::Transform const mMaskTransform;
3670  bool const mInvertMask;
3671 }; // struct MaskSurface
3672 
3673 
3674 template<typename InputGridType>
3675 inline void
3677  typename InputGridType::TreeType::template ValueConverter<bool>::Type& intersectionTree,
3678  typename InputGridType::TreeType::template ValueConverter<bool>::Type& borderTree,
3679  const InputGridType& inputGrid,
3680  const GridBase::ConstPtr& maskGrid,
3681  bool invertMask,
3682  typename InputGridType::ValueType isovalue)
3683 {
3684  using InputTreeType = typename InputGridType::TreeType;
3685  using BoolTreeType = typename InputTreeType::template ValueConverter<bool>::Type;
3686  using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
3687  using BoolGridType = Grid<BoolTreeType>;
3688 
3689  if (maskGrid && maskGrid->type() == BoolGridType::gridType()) {
3690 
3691  const math::Transform& transform = inputGrid.transform();
3692  const InputTreeType& inputTree = inputGrid.tree();
3693 
3694  const BoolGridType * surfaceMask = static_cast<const BoolGridType*>(maskGrid.get());
3695 
3696  const BoolTreeType& maskTree = surfaceMask->tree();
3697  const math::Transform& maskTransform = surfaceMask->transform();
3698 
3699 
3700  // mark masked voxels
3701 
3702  std::vector<BoolLeafNodeType*> intersectionLeafNodes;
3703  intersectionTree.getNodes(intersectionLeafNodes);
3704 
3705  tbb::parallel_for(tbb::blocked_range<size_t>(0, intersectionLeafNodes.size()),
3707  intersectionLeafNodes, maskTree, transform, maskTransform, invertMask));
3708 
3709 
3710  // mask surface-mask border
3711 
3713  intersectionTree, intersectionLeafNodes, borderTree);
3714  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, intersectionLeafNodes.size()), borderOp);
3715 
3716 
3717  // recompute isosurface intersection mask
3718 
3719  BoolTreeType tmpIntersectionTree(false);
3720 
3722  inputTree, intersectionLeafNodes, tmpIntersectionTree, isovalue);
3723 
3724  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, intersectionLeafNodes.size()), op);
3725 
3726  std::vector<BoolLeafNodeType*> tmpIntersectionLeafNodes;
3727  tmpIntersectionTree.getNodes(tmpIntersectionLeafNodes);
3728 
3729  tbb::parallel_for(tbb::blocked_range<size_t>(0, tmpIntersectionLeafNodes.size()),
3730  SyncMaskValues<BoolTreeType>(tmpIntersectionLeafNodes, intersectionTree));
3731 
3732  intersectionTree.clear();
3733  intersectionTree.merge(tmpIntersectionTree);
3734  }
3735 }
3736 
3737 
3739 
3740 
3741 template<typename InputTreeType>
3743 {
3744  using InputLeafNodeType = typename InputTreeType::LeafNodeType;
3745  using InputValueType = typename InputLeafNodeType::ValueType;
3746 
3748 
3749  using Int16TreeType = typename InputTreeType::template ValueConverter<Int16>::Type;
3750  using Index32TreeType = typename InputTreeType::template ValueConverter<Index32>::Type;
3751 
3752 
3753  ComputeAuxiliaryData(const InputTreeType& inputTree,
3754  const std::vector<const BoolLeafNodeType*>& intersectionLeafNodes,
3755  Int16TreeType& signFlagsTree,
3756  Index32TreeType& pointIndexTree,
3757  InputValueType iso);
3758 
3760  void operator()(const tbb::blocked_range<size_t>&);
3761  void join(const ComputeAuxiliaryData& rhs) {
3762  mSignFlagsAccessor.tree().merge(rhs.mSignFlagsAccessor.tree());
3763  mPointIndexAccessor.tree().merge(rhs.mPointIndexAccessor.tree());
3764  }
3765 
3766 private:
3768  BoolLeafNodeType const * const * const mIntersectionNodes;
3769 
3770  Int16TreeType mSignFlagsTree;
3771  tree::ValueAccessor<Int16TreeType> mSignFlagsAccessor;
3772  Index32TreeType mPointIndexTree;
3773  tree::ValueAccessor<Index32TreeType> mPointIndexAccessor;
3774 
3775  const InputValueType mIsovalue;
3776 };
3777 
3778 
3779 template<typename InputTreeType>
3781  const InputTreeType& inputTree,
3782  const std::vector<const BoolLeafNodeType*>& intersectionLeafNodes,
3783  Int16TreeType& signFlagsTree,
3784  Index32TreeType& pointIndexTree,
3785  InputValueType iso)
3786  : mInputAccessor(inputTree)
3787  , mIntersectionNodes(&intersectionLeafNodes.front())
3788  , mSignFlagsTree(0)
3789  , mSignFlagsAccessor(signFlagsTree)
3790  , mPointIndexTree(boost::integer_traits<Index32>::const_max)
3791  , mPointIndexAccessor(pointIndexTree)
3792  , mIsovalue(iso)
3793 {
3794  pointIndexTree.root().setBackground(boost::integer_traits<Index32>::const_max, false);
3795 }
3796 
3797 
3798 template<typename InputTreeType>
3800  : mInputAccessor(rhs.mInputAccessor.tree())
3801  , mIntersectionNodes(rhs.mIntersectionNodes)
3802  , mSignFlagsTree(0)
3803  , mSignFlagsAccessor(mSignFlagsTree)
3804  , mPointIndexTree(boost::integer_traits<Index32>::const_max)
3805  , mPointIndexAccessor(mPointIndexTree)
3806  , mIsovalue(rhs.mIsovalue)
3807 {
3808 }
3809 
3810 
3811 template<typename InputTreeType>
3812 void
3813 ComputeAuxiliaryData<InputTreeType>::operator()(const tbb::blocked_range<size_t>& range)
3814 {
3815  using Int16LeafNodeType = typename Int16TreeType::LeafNodeType;
3816 
3817  Coord ijk;
3818  math::Tuple<8, InputValueType> cellVertexValues;
3819  typename std::unique_ptr<Int16LeafNodeType> signsNodePt(new Int16LeafNodeType(ijk, 0));
3820 
3821  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
3822 
3823  const BoolLeafNodeType& maskNode = *mIntersectionNodes[n];
3824  const Coord& origin = maskNode.origin();
3825 
3826  const InputLeafNodeType *leafPt = mInputAccessor.probeConstLeaf(origin);
3827 
3828  if (!signsNodePt.get()) signsNodePt.reset(new Int16LeafNodeType(origin, 0));
3829  else signsNodePt->setOrigin(origin);
3830 
3831  bool updatedNode = false;
3832 
3833  for (typename BoolLeafNodeType::ValueOnCIter it = maskNode.cbeginValueOn(); it; ++it) {
3834 
3835  const Index pos = it.pos();
3836  ijk = BoolLeafNodeType::offsetToLocalCoord(pos);
3837 
3838  if (leafPt &&
3839  ijk[0] < int(BoolLeafNodeType::DIM - 1) &&
3840  ijk[1] < int(BoolLeafNodeType::DIM - 1) &&
3841  ijk[2] < int(BoolLeafNodeType::DIM - 1) ) {
3842  getCellVertexValues(*leafPt, pos, cellVertexValues);
3843  } else {
3844  getCellVertexValues(mInputAccessor, origin + ijk, cellVertexValues);
3845  }
3846 
3847  uint8_t signFlags = computeSignFlags(cellVertexValues, mIsovalue);
3848 
3849  if (signFlags != 0 && signFlags != 0xFF) {
3850 
3851  const bool inside = signFlags & 0x1;
3852 
3853  int edgeFlags = inside ? INSIDE : 0;
3854 
3855  if (!it.getValue()) {
3856  edgeFlags |= inside != ((signFlags & 0x02) != 0) ? XEDGE : 0;
3857  edgeFlags |= inside != ((signFlags & 0x10) != 0) ? YEDGE : 0;
3858  edgeFlags |= inside != ((signFlags & 0x08) != 0) ? ZEDGE : 0;
3859  }
3860 
3861  const uint8_t ambiguousCellFlags = sAmbiguousFace[signFlags];
3862  if (ambiguousCellFlags != 0) {
3863  correctCellSigns(signFlags, ambiguousCellFlags, mInputAccessor,
3864  origin + ijk, mIsovalue);
3865  }
3866 
3867  edgeFlags |= int(signFlags);
3868 
3869  signsNodePt->setValueOn(pos, Int16(edgeFlags));
3870  updatedNode = true;
3871  }
3872  }
3873 
3874  if (updatedNode) {
3875  typename Index32TreeType::LeafNodeType* idxNode = mPointIndexAccessor.touchLeaf(origin);
3876  idxNode->topologyUnion(*signsNodePt);
3877 
3878  // zero fill
3879  for (auto it = idxNode->beginValueOn(); it; ++it) {
3880  idxNode->setValueOnly(it.pos(), 0);
3881  }
3882 
3883  mSignFlagsAccessor.addLeaf(signsNodePt.release());
3884  }
3885  }
3886 } // ComputeAuxiliaryData::operator()
3887 
3888 
3889 template<typename InputTreeType>
3890 inline void
3892  typename InputTreeType::template ValueConverter<Int16>::Type& signFlagsTree,
3893  typename InputTreeType::template ValueConverter<Index32>::Type& pointIndexTree,
3894  const typename InputTreeType::template ValueConverter<bool>::Type& intersectionTree,
3895  const InputTreeType& inputTree,
3896  typename InputTreeType::ValueType isovalue)
3897 {
3898  using BoolTreeType = typename InputTreeType::template ValueConverter<bool>::Type;
3899  using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
3900 
3901  std::vector<const BoolLeafNodeType*> intersectionLeafNodes;
3902  intersectionTree.getNodes(intersectionLeafNodes);
3903 
3905  inputTree, intersectionLeafNodes, signFlagsTree, pointIndexTree, isovalue);
3906 
3907  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, intersectionLeafNodes.size()), op);
3908 }
3909 
3910 
3912 
3913 
3914 template<Index32 LeafNodeLog2Dim>
3916 {
3918 
3919  LeafNodePointCount(const std::vector<Int16LeafNodeType*>& leafNodes,
3920  boost::scoped_array<Index32>& leafNodeCount)
3921  : mLeafNodes(leafNodes.empty() ? nullptr : &leafNodes.front())
3922  , mData(leafNodeCount.get())
3923  {
3924  }
3925 
3926  void operator()(const tbb::blocked_range<size_t>& range) const {
3927 
3928  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
3929 
3930  Index32 count = 0;
3931 
3932  Int16 const * p = mLeafNodes[n]->buffer().data();
3933  Int16 const * const endP = p + Int16LeafNodeType::SIZE;
3934 
3935  while (p < endP) {
3936  count += Index32(sEdgeGroupTable[(SIGNS & *p)][0]);
3937  ++p;
3938  }
3939 
3940  mData[n] = count;
3941  }
3942  }
3943 
3944 private:
3945  Int16LeafNodeType * const * const mLeafNodes;
3946  Index32 *mData;
3947 }; // struct LeafNodePointCount
3948 
3949 
3950 template<typename PointIndexLeafNode>
3952 {
3954 
3955  AdaptiveLeafNodePointCount(const std::vector<PointIndexLeafNode*>& pointIndexNodes,
3956  const std::vector<Int16LeafNodeType*>& signDataNodes,
3957  boost::scoped_array<Index32>& leafNodeCount)
3958  : mPointIndexNodes(pointIndexNodes.empty() ? nullptr : &pointIndexNodes.front())
3959  , mSignDataNodes(signDataNodes.empty() ? nullptr : &signDataNodes.front())
3960  , mData(leafNodeCount.get())
3961  {
3962  }
3963 
3964  void operator()(const tbb::blocked_range<size_t>& range) const
3965  {
3966  using IndexType = typename PointIndexLeafNode::ValueType;
3967 
3968  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
3969 
3970  const PointIndexLeafNode& node = *mPointIndexNodes[n];
3971  const Int16LeafNodeType& signNode = *mSignDataNodes[n];
3972 
3973  size_t count = 0;
3974 
3975  std::set<IndexType> uniqueRegions;
3976 
3977  for (typename PointIndexLeafNode::ValueOnCIter it = node.cbeginValueOn(); it; ++it) {
3978 
3979  IndexType id = it.getValue();
3980 
3981  if (id == 0) {
3982  count += size_t(sEdgeGroupTable[(SIGNS & signNode.getValue(it.pos()))][0]);
3983  } else if (id != IndexType(util::INVALID_IDX)) {
3984  uniqueRegions.insert(id);
3985  }
3986  }
3987 
3988  mData[n] = Index32(count + uniqueRegions.size());
3989  }
3990  }
3991 
3992 private:
3993  PointIndexLeafNode const * const * const mPointIndexNodes;
3994  Int16LeafNodeType const * const * const mSignDataNodes;
3995  Index32 *mData;
3996 }; // struct AdaptiveLeafNodePointCount
3997 
3998 
3999 template<typename PointIndexLeafNode>
4001 {
4003 
4004  MapPoints(const std::vector<PointIndexLeafNode*>& pointIndexNodes,
4005  const std::vector<Int16LeafNodeType*>& signDataNodes,
4006  boost::scoped_array<Index32>& leafNodeCount)
4007  : mPointIndexNodes(pointIndexNodes.empty() ? nullptr : &pointIndexNodes.front())
4008  , mSignDataNodes(signDataNodes.empty() ? nullptr : &signDataNodes.front())
4009  , mData(leafNodeCount.get())
4010  {
4011  }
4012 
4013  void operator()(const tbb::blocked_range<size_t>& range) const {
4014 
4015  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
4016 
4017  const Int16LeafNodeType& signNode = *mSignDataNodes[n];
4018  PointIndexLeafNode& indexNode = *mPointIndexNodes[n];
4019 
4020  Index32 pointOffset = mData[n];
4021 
4022  for (auto it = indexNode.beginValueOn(); it; ++it) {
4023  const Index pos = it.pos();
4024  indexNode.setValueOnly(pos, pointOffset);
4025  const int signs = SIGNS & int(signNode.getValue(pos));
4026  pointOffset += Index32(sEdgeGroupTable[signs][0]);
4027  }
4028  }
4029  }
4030 
4031 private:
4032  PointIndexLeafNode * const * const mPointIndexNodes;
4033  Int16LeafNodeType const * const * const mSignDataNodes;
4034  Index32 * const mData;
4035 }; // struct MapPoints
4036 
4037 
4038 
4039 
4040 template<typename TreeType, typename PrimBuilder>
4042 {
4043  using Int16TreeType = typename TreeType::template ValueConverter<Int16>::Type;
4044  using Int16LeafNodeType = typename Int16TreeType::LeafNodeType;
4045 
4046  using Index32TreeType = typename TreeType::template ValueConverter<Index32>::Type;
4047  using Index32LeafNodeType = typename Index32TreeType::LeafNodeType;
4048 
4049 
4051  const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
4052  const Int16TreeType& signFlagsTree,
4053  const Index32TreeType& idxTree,
4054  PolygonPoolList& polygons,
4055  bool invertSurfaceOrientation);
4056 
4057  void setRefSignTree(const Int16TreeType * r) { mRefSignFlagsTree = r; }
4058 
4059  void operator()(const tbb::blocked_range<size_t>&) const;
4060 
4061 private:
4062  Int16LeafNodeType * const * const mSignFlagsLeafNodes;
4063  Int16TreeType const * const mSignFlagsTree;
4064  Int16TreeType const * mRefSignFlagsTree;
4065  Index32TreeType const * const mIndexTree;
4066  PolygonPoolList * const mPolygonPoolList;
4067  bool const mInvertSurfaceOrientation;
4068 }; // struct ComputePolygons
4069 
4070 
4071 template<typename TreeType, typename PrimBuilder>
4073  const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
4074  const Int16TreeType& signFlagsTree,
4075  const Index32TreeType& idxTree,
4076  PolygonPoolList& polygons,
4077  bool invertSurfaceOrientation)
4078  : mSignFlagsLeafNodes(signFlagsLeafNodes.empty() ? nullptr : &signFlagsLeafNodes.front())
4079  , mSignFlagsTree(&signFlagsTree)
4080  , mRefSignFlagsTree(nullptr)
4081  , mIndexTree(&idxTree)
4082  , mPolygonPoolList(&polygons)
4083  , mInvertSurfaceOrientation(invertSurfaceOrientation)
4084 {
4085 }
4086 
4087 template<typename InputTreeType, typename PrimBuilder>
4088 void
4089 ComputePolygons<InputTreeType, PrimBuilder>::operator()(const tbb::blocked_range<size_t>& range) const
4090 {
4091  using Int16ValueAccessor = tree::ValueAccessor<const Int16TreeType>;
4092  Int16ValueAccessor signAcc(*mSignFlagsTree);
4093 
4094  tree::ValueAccessor<const Index32TreeType> idxAcc(*mIndexTree);
4095 
4096  const bool invertSurfaceOrientation = mInvertSurfaceOrientation;
4097 
4098  PrimBuilder mesher;
4099  size_t edgeCount;
4100  Coord ijk, origin;
4101 
4102  // reference data
4103  std::unique_ptr<Int16ValueAccessor> refSignAcc;
4104  if (mRefSignFlagsTree) refSignAcc.reset(new Int16ValueAccessor(*mRefSignFlagsTree));
4105 
4106  for (size_t n = range.begin(); n != range.end(); ++n) {
4107 
4108  const Int16LeafNodeType& node = *mSignFlagsLeafNodes[n];
4109  origin = node.origin();
4110 
4111  // Get an upper bound on the number of primitives.
4112  edgeCount = 0;
4113  typename Int16LeafNodeType::ValueOnCIter iter = node.cbeginValueOn();
4114  for (; iter; ++iter) {
4115  if (iter.getValue() & XEDGE) ++edgeCount;
4116  if (iter.getValue() & YEDGE) ++edgeCount;
4117  if (iter.getValue() & ZEDGE) ++edgeCount;
4118  }
4119 
4120  if(edgeCount == 0) continue;
4121 
4122  mesher.init(edgeCount, (*mPolygonPoolList)[n]);
4123 
4124  const Int16LeafNodeType *signleafPt = signAcc.probeConstLeaf(origin);
4125  const Index32LeafNodeType *idxLeafPt = idxAcc.probeConstLeaf(origin);
4126 
4127  if (!signleafPt || !idxLeafPt) continue;
4128 
4129 
4130  const Int16LeafNodeType *refSignLeafPt = nullptr;
4131  if (refSignAcc) refSignLeafPt = refSignAcc->probeConstLeaf(origin);
4132 
4133  Vec3i offsets;
4134 
4135  for (iter = node.cbeginValueOn(); iter; ++iter) {
4136  ijk = iter.getCoord();
4137 
4138  Int16 flags = iter.getValue();
4139 
4140  if (!(flags & 0xE00)) continue;
4141 
4142  Int16 refFlags = 0;
4143  if (refSignLeafPt) {
4144  refFlags = refSignLeafPt->getValue(iter.pos());
4145  }
4146 
4147  offsets[0] = 0;
4148  offsets[1] = 0;
4149  offsets[2] = 0;
4150 
4151  const uint8_t cell = uint8_t(SIGNS & flags);
4152 
4153  if (sEdgeGroupTable[cell][0] > 1) {
4154  offsets[0] = (sEdgeGroupTable[cell][1] - 1);
4155  offsets[1] = (sEdgeGroupTable[cell][9] - 1);
4156  offsets[2] = (sEdgeGroupTable[cell][4] - 1);
4157  }
4158 
4159  if (ijk[0] > origin[0] && ijk[1] > origin[1] && ijk[2] > origin[2]) {
4160  constructPolygons(invertSurfaceOrientation,
4161  flags, refFlags, offsets, ijk, *signleafPt, *idxLeafPt, mesher);
4162  } else {
4163  constructPolygons(invertSurfaceOrientation,
4164  flags, refFlags, offsets, ijk, signAcc, idxAcc, mesher);
4165  }
4166  }
4167 
4168  mesher.done();
4169  }
4170 
4171 } // ComputePolygons::operator()
4172 
4173 
4175 
4176 
4177 template<typename T>
4179 {
4180  CopyArray(T * outputArray, const T * inputArray, size_t outputOffset = 0)
4181  : mOutputArray(outputArray), mInputArray(inputArray), mOutputOffset(outputOffset)
4182  {
4183  }
4184 
4185  void operator()(const tbb::blocked_range<size_t>& inputArrayRange) const
4186  {
4187  const size_t offset = mOutputOffset;
4188  for (size_t n = inputArrayRange.begin(), N = inputArrayRange.end(); n < N; ++n) {
4189  mOutputArray[offset + n] = mInputArray[n];
4190  }
4191  }
4192 
4193 private:
4194  T * const mOutputArray;
4195  T const * const mInputArray;
4196  size_t const mOutputOffset;
4197 }; // struct CopyArray
4198 
4199 
4201 {
4203  const std::vector<uint8_t>& pointFlags,
4204  boost::scoped_array<openvdb::Vec3s>& points,
4205  boost::scoped_array<unsigned>& numQuadsToDivide)
4206  : mPolygonPoolList(&polygons)
4207  , mPointFlags(pointFlags.empty() ? nullptr : &pointFlags.front())
4208  , mPoints(points.get())
4209  , mNumQuadsToDivide(numQuadsToDivide.get())
4210  {
4211  }
4212 
4213  void operator()(const tbb::blocked_range<size_t>& range) const
4214  {
4215  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
4216 
4217  PolygonPool& polygons = (*mPolygonPoolList)[n];
4218 
4219  unsigned count = 0;
4220 
4221  // count and tag nonplanar seam line quads.
4222  for (size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
4223 
4224  char& flags = polygons.quadFlags(i);
4225 
4226  if ((flags & POLYFLAG_FRACTURE_SEAM) && !(flags & POLYFLAG_EXTERIOR)) {
4227 
4228  Vec4I& quad = polygons.quad(i);
4229 
4230  const bool edgePoly = mPointFlags[quad[0]] || mPointFlags[quad[1]]
4231  || mPointFlags[quad[2]] || mPointFlags[quad[3]];
4232 
4233  if (!edgePoly) continue;
4234 
4235  const Vec3s& p0 = mPoints[quad[0]];
4236  const Vec3s& p1 = mPoints[quad[1]];
4237  const Vec3s& p2 = mPoints[quad[2]];
4238  const Vec3s& p3 = mPoints[quad[3]];
4239 
4240  if (!isPlanarQuad(p0, p1, p2, p3, 1e-6f)) {
4241  flags |= POLYFLAG_SUBDIVIDED;
4242  count++;
4243  }
4244  }
4245  }
4246 
4247  mNumQuadsToDivide[n] = count;
4248  }
4249  }
4250 
4251 private:
4252  PolygonPoolList * const mPolygonPoolList;
4253  uint8_t const * const mPointFlags;
4254  Vec3s const * const mPoints;
4255  unsigned * const mNumQuadsToDivide;
4256 }; // struct FlagAndCountQuadsToSubdivide
4257 
4258 
4260 {
4262  const boost::scoped_array<openvdb::Vec3s>& points,
4263  size_t pointCount,
4264  boost::scoped_array<openvdb::Vec3s>& centroids,
4265  boost::scoped_array<unsigned>& numQuadsToDivide,
4266  boost::scoped_array<unsigned>& centroidOffsets)
4267  : mPolygonPoolList(&polygons)
4268  , mPoints(points.get())
4269  , mCentroids(centroids.get())
4270  , mNumQuadsToDivide(numQuadsToDivide.get())
4271  , mCentroidOffsets(centroidOffsets.get())
4272  , mPointCount(pointCount)
4273  {
4274  }
4275 
4276  void operator()(const tbb::blocked_range<size_t>& range) const
4277  {
4278  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
4279 
4280  PolygonPool& polygons = (*mPolygonPoolList)[n];
4281 
4282  const size_t nonplanarCount = size_t(mNumQuadsToDivide[n]);
4283 
4284  if (nonplanarCount > 0) {
4285 
4286  PolygonPool tmpPolygons;
4287  tmpPolygons.resetQuads(polygons.numQuads() - nonplanarCount);
4288  tmpPolygons.resetTriangles(polygons.numTriangles() + size_t(4) * nonplanarCount);
4289 
4290  size_t offset = mCentroidOffsets[n];
4291 
4292  size_t triangleIdx = 0;
4293 
4294  for (size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
4295 
4296  const char quadFlags = polygons.quadFlags(i);
4297  if (!(quadFlags & POLYFLAG_SUBDIVIDED)) continue;
4298 
4299  unsigned newPointIdx = unsigned(offset + mPointCount);
4300 
4301  openvdb::Vec4I& quad = polygons.quad(i);
4302 
4303  mCentroids[offset] = (mPoints[quad[0]] + mPoints[quad[1]] +
4304  mPoints[quad[2]] + mPoints[quad[3]]) * 0.25f;
4305 
4306  ++offset;
4307 
4308  {
4309  Vec3I& triangle = tmpPolygons.triangle(triangleIdx);
4310 
4311  triangle[0] = quad[0];
4312  triangle[1] = newPointIdx;
4313  triangle[2] = quad[3];
4314 
4315  tmpPolygons.triangleFlags(triangleIdx) = quadFlags;
4316  }
4317 
4318  ++triangleIdx;
4319 
4320  {
4321  Vec3I& triangle = tmpPolygons.triangle(triangleIdx);
4322 
4323  triangle[0] = quad[0];
4324  triangle[1] = quad[1];
4325  triangle[2] = newPointIdx;
4326 
4327  tmpPolygons.triangleFlags(triangleIdx) = quadFlags;
4328  }
4329 
4330  ++triangleIdx;
4331 
4332  {
4333  Vec3I& triangle = tmpPolygons.triangle(triangleIdx);
4334 
4335  triangle[0] = quad[1];
4336  triangle[1] = quad[2];
4337  triangle[2] = newPointIdx;
4338 
4339  tmpPolygons.triangleFlags(triangleIdx) = quadFlags;
4340  }
4341 
4342 
4343  ++triangleIdx;
4344 
4345  {
4346  Vec3I& triangle = tmpPolygons.triangle(triangleIdx);
4347 
4348  triangle[0] = quad[2];
4349  triangle[1] = quad[3];
4350  triangle[2] = newPointIdx;
4351 
4352  tmpPolygons.triangleFlags(triangleIdx) = quadFlags;
4353  }
4354 
4355  ++triangleIdx;
4356 
4357  quad[0] = util::INVALID_IDX; // mark for deletion
4358  }
4359 
4360 
4361  for (size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
4362  tmpPolygons.triangle(triangleIdx) = polygons.triangle(i);
4363  tmpPolygons.triangleFlags(triangleIdx) = polygons.triangleFlags(i);
4364  ++triangleIdx;
4365  }
4366 
4367  size_t quadIdx = 0;
4368  for (size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
4369  openvdb::Vec4I& quad = polygons.quad(i);
4370 
4371  if (quad[0] != util::INVALID_IDX) { // ignore invalid quads
4372  tmpPolygons.quad(quadIdx) = quad;
4373  tmpPolygons.quadFlags(quadIdx) = polygons.quadFlags(i);
4374  ++quadIdx;
4375  }
4376  }
4377 
4378  polygons.copy(tmpPolygons);
4379  }
4380  }
4381  }
4382 
4383 private:
4384  PolygonPoolList * const mPolygonPoolList;
4385  Vec3s const * const mPoints;
4386  Vec3s * const mCentroids;
4387  unsigned * const mNumQuadsToDivide;
4388  unsigned * const mCentroidOffsets;
4389  size_t const mPointCount;
4390 }; // struct SubdivideQuads
4391 
4392 
4393 inline void
4395  PolygonPoolList& polygonPoolList,
4396  size_t polygonPoolListSize,
4397  PointList& pointList,
4398  size_t& pointListSize,
4399  std::vector<uint8_t>& pointFlags)
4400 {
4401  const tbb::blocked_range<size_t> polygonPoolListRange(0, polygonPoolListSize);
4402 
4403  boost::scoped_array<unsigned> numQuadsToDivide(new unsigned[polygonPoolListSize]);
4404 
4405  tbb::parallel_for(polygonPoolListRange,
4406  FlagAndCountQuadsToSubdivide(polygonPoolList, pointFlags, pointList, numQuadsToDivide));
4407 
4408  boost::scoped_array<unsigned> centroidOffsets(new unsigned[polygonPoolListSize]);
4409 
4410  size_t centroidCount = 0;
4411 
4412  {
4413  unsigned sum = 0;
4414  for (size_t n = 0, N = polygonPoolListSize; n < N; ++n) {
4415  centroidOffsets[n] = sum;
4416  sum += numQuadsToDivide[n];
4417  }
4418  centroidCount = size_t(sum);
4419  }
4420 
4421  boost::scoped_array<Vec3s> centroidList(new Vec3s[centroidCount]);
4422 
4423  tbb::parallel_for(polygonPoolListRange,
4424  SubdivideQuads(polygonPoolList, pointList, pointListSize,
4425  centroidList, numQuadsToDivide, centroidOffsets));
4426 
4427  if (centroidCount > 0) {
4428 
4429  const size_t newPointListSize = centroidCount + pointListSize;
4430 
4431  boost::scoped_array<openvdb::Vec3s> newPointList(new openvdb::Vec3s[newPointListSize]);
4432 
4433  tbb::parallel_for(tbb::blocked_range<size_t>(0, pointListSize),
4434  CopyArray<Vec3s>(newPointList.get(), pointList.get()));
4435 
4436  tbb::parallel_for(tbb::blocked_range<size_t>(0, newPointListSize - pointListSize),
4437  CopyArray<Vec3s>(newPointList.get(), centroidList.get(), pointListSize));
4438 
4439  pointListSize = newPointListSize;
4440  pointList.swap(newPointList);
4441  pointFlags.resize(pointListSize, 0);
4442  }
4443 }
4444 
4445 
4447 {
4449  const std::vector<uint8_t>& pointFlags)
4450  : mPolygonPoolList(&polygons)
4451  , mPointFlags(pointFlags.empty() ? nullptr : &pointFlags.front())
4452  {
4453  }
4454 
4455  void operator()(const tbb::blocked_range<size_t>& range) const
4456  {
4457  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
4458 
4459  PolygonPool& polygons = (*mPolygonPoolList)[n];
4460 
4461  for (size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
4462 
4463  char& flags = polygons.quadFlags(i);
4464 
4465  if (flags & POLYFLAG_FRACTURE_SEAM) {
4466 
4467  openvdb::Vec4I& verts = polygons.quad(i);
4468 
4469  const bool hasSeamLinePoint =
4470  mPointFlags[verts[0]] || mPointFlags[verts[1]] ||
4471  mPointFlags[verts[2]] || mPointFlags[verts[3]];
4472 
4473  if (!hasSeamLinePoint) {
4474  flags &= ~POLYFLAG_FRACTURE_SEAM;
4475  }
4476  }
4477  } // end quad loop
4478 
4479  for (size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
4480 
4481  char& flags = polygons.triangleFlags(i);
4482 
4483  if (flags & POLYFLAG_FRACTURE_SEAM) {
4484 
4485  openvdb::Vec3I& verts = polygons.triangle(i);
4486 
4487  const bool hasSeamLinePoint =
4488  mPointFlags[verts[0]] || mPointFlags[verts[1]] || mPointFlags[verts[2]];
4489 
4490  if (!hasSeamLinePoint) {
4491  flags &= ~POLYFLAG_FRACTURE_SEAM;
4492  }
4493 
4494  }
4495  } // end triangle loop
4496 
4497  } // end polygon pool loop
4498  }
4499 
4500 private:
4501  PolygonPoolList * const mPolygonPoolList;
4502  uint8_t const * const mPointFlags;
4503 }; // struct ReviseSeamLineFlags
4504 
4505 
4506 inline void
4507 reviseSeamLineFlags(PolygonPoolList& polygonPoolList, size_t polygonPoolListSize,
4508  std::vector<uint8_t>& pointFlags)
4509 {
4510  tbb::parallel_for(tbb::blocked_range<size_t>(0, polygonPoolListSize),
4511  ReviseSeamLineFlags(polygonPoolList, pointFlags));
4512 }
4513 
4514 
4516 
4517 
4518 template<typename InputTreeType>
4520 {
4521  MaskDisorientedTrianglePoints(const InputTreeType& inputTree, const PolygonPoolList& polygons,
4522  const PointList& pointList, boost::scoped_array<uint8_t>& pointMask,
4523  const math::Transform& transform, bool invertSurfaceOrientation)
4524  : mInputTree(&inputTree)
4525  , mPolygonPoolList(&polygons)
4526  , mPointList(&pointList)
4527  , mPointMask(pointMask.get())
4528  , mTransform(transform)
4529  , mInvertSurfaceOrientation(invertSurfaceOrientation)
4530  {
4531  }
4532 
4533  void operator()(const tbb::blocked_range<size_t>& range) const
4534  {
4535  using ValueType = typename InputTreeType::LeafNodeType::ValueType;
4536 
4537  tree::ValueAccessor<const InputTreeType> inputAcc(*mInputTree);
4538  Vec3s centroid, normal;
4539  Coord ijk;
4540 
4541  const bool invertGradientDir = mInvertSurfaceOrientation || isBoolValue<ValueType>();
4542 
4543  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
4544 
4545  const PolygonPool& polygons = (*mPolygonPoolList)[n];
4546 
4547  for (size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
4548 
4549  const Vec3I& verts = polygons.triangle(i);
4550 
4551  const Vec3s& v0 = (*mPointList)[verts[0]];
4552  const Vec3s& v1 = (*mPointList)[verts[1]];
4553  const Vec3s& v2 = (*mPointList)[verts[2]];
4554 
4555  normal = (v2 - v0).cross((v1 - v0));
4556  normal.normalize();
4557 
4558  centroid = (v0 + v1 + v2) * (1.0f / 3.0f);
4559  ijk = mTransform.worldToIndexCellCentered(centroid);
4560 
4561  Vec3s dir( math::ISGradient<math::CD_2ND>::result(inputAcc, ijk) );
4562  dir.normalize();
4563 
4564  if (invertGradientDir) {
4565  dir = -dir;
4566  }
4567 
4568  // check if the angle is obtuse
4569  if (dir.dot(normal) < -0.5f) {
4570  // Concurrent writes to same memory address can occur, but
4571  // all threads are writing the same value and char is atomic.
4572  // (It is extremely rare that disoriented triangles share points,
4573  // false sharing related performance impacts are not a concern.)
4574  mPointMask[verts[0]] = 1;
4575  mPointMask[verts[1]] = 1;
4576  mPointMask[verts[2]] = 1;
4577  }
4578 
4579  } // end triangle loop
4580 
4581  } // end polygon pool loop
4582  }
4583 
4584 private:
4585  InputTreeType const * const mInputTree;
4586  PolygonPoolList const * const mPolygonPoolList;
4587  PointList const * const mPointList;
4588  uint8_t * const mPointMask;
4589  math::Transform const mTransform;
4590  bool const mInvertSurfaceOrientation;
4591 }; // struct MaskDisorientedTrianglePoints
4592 
4593 
4594 template<typename InputTree>
4595 inline void
4597  bool invertSurfaceOrientation,
4598  const InputTree& inputTree,
4599  const math::Transform& transform,
4600  PolygonPoolList& polygonPoolList,
4601  size_t polygonPoolListSize,
4602  PointList& pointList,
4603  const size_t pointListSize)
4604 {
4605  const tbb::blocked_range<size_t> polygonPoolListRange(0, polygonPoolListSize);
4606 
4607  boost::scoped_array<uint8_t> pointMask(new uint8_t[pointListSize]);
4608  fillArray(pointMask.get(), uint8_t(0), pointListSize);
4609 
4610  tbb::parallel_for(polygonPoolListRange,
4612  inputTree, polygonPoolList, pointList, pointMask, transform, invertSurfaceOrientation));
4613 
4614  boost::scoped_array<uint8_t> pointUpdates(new uint8_t[pointListSize]);
4615  fillArray(pointUpdates.get(), uint8_t(0), pointListSize);
4616 
4617  boost::scoped_array<Vec3s> newPoints(new Vec3s[pointListSize]);
4618  fillArray(newPoints.get(), Vec3s(0.0f, 0.0f, 0.0f), pointListSize);
4619 
4620  for (size_t n = 0, N = polygonPoolListSize; n < N; ++n) {
4621 
4622  PolygonPool& polygons = polygonPoolList[n];
4623 
4624  for (size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
4625  openvdb::Vec4I& verts = polygons.quad(i);
4626 
4627  for (int v = 0; v < 4; ++v) {
4628 
4629  const unsigned pointIdx = verts[v];
4630 
4631  if (pointMask[pointIdx] == 1) {
4632 
4633  newPoints[pointIdx] +=
4634  pointList[verts[0]] + pointList[verts[1]] +
4635  pointList[verts[2]] + pointList[verts[3]];
4636 
4637  pointUpdates[pointIdx] = uint8_t(pointUpdates[pointIdx] + 4);
4638  }
4639  }
4640  }
4641 
4642  for (size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
4643  openvdb::Vec3I& verts = polygons.triangle(i);
4644 
4645  for (int v = 0; v < 3; ++v) {
4646 
4647  const unsigned pointIdx = verts[v];
4648 
4649  if (pointMask[pointIdx] == 1) {
4650  newPoints[pointIdx] +=
4651  pointList[verts[0]] + pointList[verts[1]] + pointList[verts[2]];
4652 
4653  pointUpdates[pointIdx] = uint8_t(pointUpdates[pointIdx] + 3);
4654  }
4655  }
4656  }
4657  }
4658 
4659  for (size_t n = 0, N = pointListSize; n < N; ++n) {
4660  if (pointUpdates[n] > 0) {
4661  const double weight = 1.0 / double(pointUpdates[n]);
4662  pointList[n] = newPoints[n] * float(weight);
4663  }
4664  }
4665 }
4666 
4667 
4668 } // volume_to_mesh_internal namespace
4669 
4670 
4672 
4673 
4674 inline
4676  : mNumQuads(0)
4677  , mNumTriangles(0)
4678  , mQuads(nullptr)
4679  , mTriangles(nullptr)
4680  , mQuadFlags(nullptr)
4681  , mTriangleFlags(nullptr)
4682 {
4683 }
4684 
4685 
4686 inline
4687 PolygonPool::PolygonPool(const size_t numQuads, const size_t numTriangles)
4688  : mNumQuads(numQuads)
4689  , mNumTriangles(numTriangles)
4690  , mQuads(new openvdb::Vec4I[mNumQuads])
4691  , mTriangles(new openvdb::Vec3I[mNumTriangles])
4692  , mQuadFlags(new char[mNumQuads])
4693  , mTriangleFlags(new char[mNumTriangles])
4694 {
4695 }
4696 
4697 
4698 inline void
4700 {
4701  resetQuads(rhs.numQuads());
4703 
4704  for (size_t i = 0; i < mNumQuads; ++i) {
4705  mQuads[i] = rhs.mQuads[i];
4706  mQuadFlags[i] = rhs.mQuadFlags[i];
4707  }
4708 
4709  for (size_t i = 0; i < mNumTriangles; ++i) {
4710  mTriangles[i] = rhs.mTriangles[i];
4711  mTriangleFlags[i] = rhs.mTriangleFlags[i];
4712  }
4713 }
4714 
4715 
4716 inline void
4718 {
4719  mNumQuads = size;
4720  mQuads.reset(new openvdb::Vec4I[mNumQuads]);
4721  mQuadFlags.reset(new char[mNumQuads]);
4722 }
4723 
4724 
4725 inline void
4727 {
4728  mNumQuads = 0;
4729  mQuads.reset(nullptr);
4730  mQuadFlags.reset(nullptr);
4731 }
4732 
4733 
4734 inline void
4736 {
4737  mNumTriangles = size;
4738  mTriangles.reset(new openvdb::Vec3I[mNumTriangles]);
4739  mTriangleFlags.reset(new char[mNumTriangles]);
4740 }
4741 
4742 
4743 inline void
4745 {
4746  mNumTriangles = 0;
4747  mTriangles.reset(nullptr);
4748  mTriangleFlags.reset(nullptr);
4749 }
4750 
4751 
4752 inline bool
4753 PolygonPool::trimQuads(const size_t n, bool reallocate)
4754 {
4755  if (!(n < mNumQuads)) return false;
4756 
4757  if (reallocate) {
4758 
4759  if (n == 0) {
4760  mQuads.reset(nullptr);
4761  } else {
4762 
4763  boost::scoped_array<openvdb::Vec4I> quads(new openvdb::Vec4I[n]);
4764  boost::scoped_array<char> flags(new char[n]);
4765 
4766  for (size_t i = 0; i < n; ++i) {
4767  quads[i] = mQuads[i];
4768  flags[i] = mQuadFlags[i];
4769  }
4770 
4771  mQuads.swap(quads);
4772  mQuadFlags.swap(flags);
4773  }
4774  }
4775 
4776  mNumQuads = n;
4777  return true;
4778 }
4779 
4780 
4781 inline bool
4782 PolygonPool::trimTrinagles(const size_t n, bool reallocate)
4783 {
4784  if (!(n < mNumTriangles)) return false;
4785 
4786  if (reallocate) {
4787 
4788  if (n == 0) {
4789  mTriangles.reset(nullptr);
4790  } else {
4791 
4792  boost::scoped_array<openvdb::Vec3I> triangles(new openvdb::Vec3I[n]);
4793  boost::scoped_array<char> flags(new char[n]);
4794 
4795  for (size_t i = 0; i < n; ++i) {
4796  triangles[i] = mTriangles[i];
4797  flags[i] = mTriangleFlags[i];
4798  }
4799 
4800  mTriangles.swap(triangles);
4801  mTriangleFlags.swap(flags);
4802  }
4803  }
4804 
4805  mNumTriangles = n;
4806  return true;
4807 }
4808 
4809 
4811 
4812 
4813 inline
4814 VolumeToMesh::VolumeToMesh(double isovalue, double adaptivity, bool relaxDisorientedTriangles)
4815  : mPoints(nullptr)
4816  , mPolygons()
4817  , mPointListSize(0)
4818  , mSeamPointListSize(0)
4819  , mPolygonPoolListSize(0)
4820  , mIsovalue(isovalue)
4821  , mPrimAdaptivity(adaptivity)
4822  , mSecAdaptivity(0.0)
4823  , mRefGrid(GridBase::ConstPtr())
4824  , mSurfaceMaskGrid(GridBase::ConstPtr())
4825  , mAdaptivityGrid(GridBase::ConstPtr())
4826  , mAdaptivityMaskTree(TreeBase::ConstPtr())
4827  , mRefSignTree(TreeBase::Ptr())
4828  , mRefIdxTree(TreeBase::Ptr())
4829  , mInvertSurfaceMask(false)
4830  , mRelaxDisorientedTriangles(relaxDisorientedTriangles)
4831  , mQuantizedSeamPoints(nullptr)
4832  , mPointFlags(0)
4833 {
4834 }
4835 
4836 
4837 inline PointList&
4839 {
4840  return mPoints;
4841 }
4842 
4843 
4844 inline const size_t&
4846 {
4847  return mPointListSize;
4848 }
4849 
4850 
4851 inline PolygonPoolList&
4853 {
4854  return mPolygons;
4855 }
4856 
4857 
4858 inline const PolygonPoolList&
4860 {
4861  return mPolygons;
4862 }
4863 
4864 
4865 inline const size_t&
4867 {
4868  return mPolygonPoolListSize;
4869 }
4870 
4871 
4872 inline void
4873 VolumeToMesh::setRefGrid(const GridBase::ConstPtr& grid, double secAdaptivity)
4874 {
4875  mRefGrid = grid;
4876  mSecAdaptivity = secAdaptivity;
4877 
4878  // Clear out old auxiliary data
4879  mRefSignTree = TreeBase::Ptr();
4880  mRefIdxTree = TreeBase::Ptr();
4881  mSeamPointListSize = 0;
4882  mQuantizedSeamPoints.reset(nullptr);
4883 }
4884 
4885 
4886 inline void
4888 {
4889  mSurfaceMaskGrid = mask;
4890  mInvertSurfaceMask = invertMask;
4891 }
4892 
4893 
4894 inline void
4896 {
4897  mAdaptivityGrid = grid;
4898 }
4899 
4900 
4901 inline void
4903 {
4904  mAdaptivityMaskTree = tree;
4905 }
4906 
4907 
4908 inline std::vector<uint8_t>&
4910 {
4911  return mPointFlags;
4912 }
4913 
4914 
4915 inline const std::vector<uint8_t>&
4917 {
4918  return mPointFlags;
4919 }
4920 
4921 
4922 template<typename InputGridType>
4923 inline void
4924 VolumeToMesh::operator()(const InputGridType& inputGrid)
4925 {
4926  // input data types
4927 
4928  using InputTreeType = typename InputGridType::TreeType;
4929  using InputLeafNodeType = typename InputTreeType::LeafNodeType;
4930  using InputValueType = typename InputLeafNodeType::ValueType;
4931 
4932  // auxiliary data types
4933 
4934  using FloatTreeType = typename InputTreeType::template ValueConverter<float>::Type;
4935  using FloatGridType = Grid<FloatTreeType>;
4936  using BoolTreeType = typename InputTreeType::template ValueConverter<bool>::Type;
4937  using Int16TreeType = typename InputTreeType::template ValueConverter<Int16>::Type;
4938  using Int16LeafNodeType = typename Int16TreeType::LeafNodeType;
4939  using Index32TreeType = typename InputTreeType::template ValueConverter<Index32>::Type;
4940  using Index32LeafNodeType = typename Index32TreeType::LeafNodeType;
4941 
4942  // clear old data
4943  mPointListSize = 0;
4944  mPoints.reset();
4945  mPolygonPoolListSize = 0;
4946  mPolygons.reset();
4947  mPointFlags.clear();
4948 
4949  // settings
4950 
4951  const math::Transform& transform = inputGrid.transform();
4952  const InputValueType isovalue = InputValueType(mIsovalue);
4953  const float adaptivityThreshold = float(mPrimAdaptivity);
4954  const bool adaptive = mPrimAdaptivity > 1e-7 || mSecAdaptivity > 1e-7;
4955 
4956  // The default surface orientation is setup for level set and bool/mask grids.
4957  // Boolean grids are handled correctly by their value type. Signed distance fields,
4958  // unsigned distance fields and fog volumes have the same value type but use different
4959  // inside value classifications.
4960  const bool invertSurfaceOrientation = (!volume_to_mesh_internal::isBoolValue<InputValueType>()
4961  && (inputGrid.getGridClass() != openvdb::GRID_LEVEL_SET));
4962 
4963  // references, masks and auxiliary data
4964 
4965  const InputTreeType& inputTree = inputGrid.tree();
4966 
4967  BoolTreeType intersectionTree(false), adaptivityMask(false);
4968 
4969  if (mAdaptivityMaskTree && mAdaptivityMaskTree->type() == BoolTreeType::treeType()) {
4970  const BoolTreeType *refAdaptivityMask=
4971  static_cast<const BoolTreeType*>(mAdaptivityMaskTree.get());
4972  adaptivityMask.topologyUnion(*refAdaptivityMask);
4973  }
4974 
4975  Int16TreeType signFlagsTree(0);
4976  Index32TreeType pointIndexTree(boost::integer_traits<Index32>::const_max);
4977 
4978 
4979  // collect auxiliary data
4980 
4982  intersectionTree, inputTree, isovalue);
4983 
4984  volume_to_mesh_internal::applySurfaceMask(intersectionTree, adaptivityMask,
4985  inputGrid, mSurfaceMaskGrid, mInvertSurfaceMask, isovalue);
4986 
4987  if (intersectionTree.empty()) return;
4988 
4990  signFlagsTree, pointIndexTree, intersectionTree, inputTree, isovalue);
4991 
4992  intersectionTree.clear();
4993 
4994  std::vector<Index32LeafNodeType*> pointIndexLeafNodes;
4995  pointIndexTree.getNodes(pointIndexLeafNodes);
4996 
4997  std::vector<Int16LeafNodeType*> signFlagsLeafNodes;
4998  signFlagsTree.getNodes(signFlagsLeafNodes);
4999 
5000  const tbb::blocked_range<size_t> auxiliaryLeafNodeRange(0, signFlagsLeafNodes.size());
5001 
5002 
5003  // optionally collect auxiliary data from a reference volume.
5004 
5005  Int16TreeType* refSignFlagsTree = nullptr;
5006  Index32TreeType* refPointIndexTree = nullptr;
5007  InputTreeType const* refInputTree = nullptr;
5008 
5009  if (mRefGrid && mRefGrid->type() == InputGridType::gridType()) {
5010 
5011  const InputGridType* refGrid = static_cast<const InputGridType*>(mRefGrid.get());
5012  refInputTree = &refGrid->tree();
5013 
5014  if (!mRefSignTree && !mRefIdxTree) {
5015 
5016  // first time, collect and cache auxiliary data.
5017 
5018  typename Int16TreeType::Ptr refSignFlagsTreePt(new Int16TreeType(0));
5019  typename Index32TreeType::Ptr refPointIndexTreePt(
5020  new Index32TreeType(boost::integer_traits<Index32>::const_max));
5021 
5022  BoolTreeType refIntersectionTree(false);
5023 
5025  refIntersectionTree, *refInputTree, isovalue);
5026 
5028  *refPointIndexTreePt, refIntersectionTree, *refInputTree, isovalue);
5029 
5030  mRefSignTree = refSignFlagsTreePt;
5031  mRefIdxTree = refPointIndexTreePt;
5032  }
5033 
5034  if (mRefSignTree && mRefIdxTree) {
5035 
5036  // get cached auxiliary data
5037 
5038  refSignFlagsTree = static_cast<Int16TreeType*>(mRefSignTree.get());
5039  refPointIndexTree = static_cast<Index32TreeType*>(mRefIdxTree.get());
5040  }
5041 
5042 
5043  if (refSignFlagsTree && refPointIndexTree) {
5044 
5045  // generate seam line sample points
5046 
5047  volume_to_mesh_internal::markSeamLineData(signFlagsTree, *refSignFlagsTree);
5048 
5049  if (mSeamPointListSize == 0) {
5050 
5051  // count unique points on reference surface
5052 
5053  std::vector<Int16LeafNodeType*> refSignFlagsLeafNodes;
5054  refSignFlagsTree->getNodes(refSignFlagsLeafNodes);
5055 
5056  boost::scoped_array<Index32> leafNodeOffsets(
5057  new Index32[refSignFlagsLeafNodes.size()]);
5058 
5059  tbb::parallel_for(tbb::blocked_range<size_t>(0, refSignFlagsLeafNodes.size()),
5061  refSignFlagsLeafNodes, leafNodeOffsets));
5062 
5063  {
5064  Index32 count = 0;
5065  for (size_t n = 0, N = refSignFlagsLeafNodes.size(); n < N; ++n) {
5066  const Index32 tmp = leafNodeOffsets[n];
5067  leafNodeOffsets[n] = count;
5068  count += tmp;
5069  }
5070  mSeamPointListSize = size_t(count);
5071  }
5072 
5073  if (mSeamPointListSize != 0) {
5074 
5075  mQuantizedSeamPoints.reset(new uint32_t[mSeamPointListSize]);
5076 
5077  memset(mQuantizedSeamPoints.get(), 0, sizeof(uint32_t) * mSeamPointListSize);
5078 
5079  std::vector<Index32LeafNodeType*> refPointIndexLeafNodes;
5080  refPointIndexTree->getNodes(refPointIndexLeafNodes);
5081 
5082  tbb::parallel_for(tbb::blocked_range<size_t>(0, refPointIndexLeafNodes.size()),
5084  refPointIndexLeafNodes, refSignFlagsLeafNodes, leafNodeOffsets));
5085  }
5086  }
5087 
5088  if (mSeamPointListSize != 0) {
5089 
5090  tbb::parallel_for(auxiliaryLeafNodeRange,
5092  signFlagsLeafNodes, inputTree, *refPointIndexTree, *refSignFlagsTree,
5093  mQuantizedSeamPoints.get(), isovalue));
5094  }
5095  }
5096  }
5097 
5098  const bool referenceMeshing = refSignFlagsTree && refPointIndexTree && refInputTree;
5099 
5100 
5101  // adapt and count unique points
5102 
5103  boost::scoped_array<Index32> leafNodeOffsets(new Index32[signFlagsLeafNodes.size()]);
5104 
5105  if (adaptive) {
5107  inputGrid, pointIndexTree, pointIndexLeafNodes, signFlagsLeafNodes,
5108  isovalue, adaptivityThreshold, invertSurfaceOrientation);
5109 
5110  if (mAdaptivityGrid && mAdaptivityGrid->type() == FloatGridType::gridType()) {
5111  const FloatGridType* adaptivityGrid =
5112  static_cast<const FloatGridType*>(mAdaptivityGrid.get());
5113  mergeOp.setSpatialAdaptivity(*adaptivityGrid);
5114  }
5115 
5116  if (!adaptivityMask.empty()) {
5117  mergeOp.setAdaptivityMask(adaptivityMask);
5118  }
5119 
5120  if (referenceMeshing) {
5121  mergeOp.setRefSignFlagsData(*refSignFlagsTree, float(mSecAdaptivity));
5122  }
5123 
5124  tbb::parallel_for(auxiliaryLeafNodeRange, mergeOp);
5125 
5127  op(pointIndexLeafNodes, signFlagsLeafNodes, leafNodeOffsets);
5128 
5129  tbb::parallel_for(auxiliaryLeafNodeRange, op);
5130 
5131  } else {
5132 
5134  op(signFlagsLeafNodes, leafNodeOffsets);
5135 
5136  tbb::parallel_for(auxiliaryLeafNodeRange, op);
5137  }
5138 
5139 
5140  {
5141  Index32 pointCount = 0;
5142  for (size_t n = 0, N = signFlagsLeafNodes.size(); n < N; ++n) {
5143  const Index32 tmp = leafNodeOffsets[n];
5144  leafNodeOffsets[n] = pointCount;
5145  pointCount += tmp;
5146  }
5147 
5148  mPointListSize = size_t(pointCount);
5149  mPoints.reset(new openvdb::Vec3s[mPointListSize]);
5150  mPointFlags.clear();
5151  }
5152 
5153 
5154  // compute points
5155 
5156  {
5158  op(mPoints.get(), inputTree, pointIndexLeafNodes,
5159  signFlagsLeafNodes, leafNodeOffsets, transform, mIsovalue);
5160 
5161  if (referenceMeshing) {
5162  mPointFlags.resize(mPointListSize);
5163  op.setRefData(*refInputTree, *refPointIndexTree, *refSignFlagsTree,
5164  mQuantizedSeamPoints.get(), &mPointFlags.front());
5165  }
5166 
5167  tbb::parallel_for(auxiliaryLeafNodeRange, op);
5168  }
5169 
5170 
5171  // compute polygons
5172 
5173  mPolygonPoolListSize = signFlagsLeafNodes.size();
5174  mPolygons.reset(new PolygonPool[mPolygonPoolListSize]);
5175 
5176  if (adaptive) {
5177 
5179 
5181  op(signFlagsLeafNodes, signFlagsTree, pointIndexTree,
5182  mPolygons, invertSurfaceOrientation);
5183 
5184  if (referenceMeshing) {
5185  op.setRefSignTree(refSignFlagsTree);
5186  }
5187 
5188  tbb::parallel_for(auxiliaryLeafNodeRange, op);
5189 
5190  } else {
5191 
5192  using PrimBuilder = volume_to_mesh_internal::UniformPrimBuilder;
5193 
5195  op(signFlagsLeafNodes, signFlagsTree, pointIndexTree,
5196  mPolygons, invertSurfaceOrientation);
5197 
5198  if (referenceMeshing) {
5199  op.setRefSignTree(refSignFlagsTree);
5200  }
5201 
5202  tbb::parallel_for(auxiliaryLeafNodeRange, op);
5203  }
5204 
5205 
5206  signFlagsTree.clear();
5207  pointIndexTree.clear();
5208 
5209 
5210  if (adaptive && mRelaxDisorientedTriangles) {
5211  volume_to_mesh_internal::relaxDisorientedTriangles(invertSurfaceOrientation,
5212  inputTree, transform, mPolygons, mPolygonPoolListSize, mPoints, mPointListSize);
5213  }
5214 
5215 
5216  if (referenceMeshing) {
5218  mPolygons, mPolygonPoolListSize, mPoints, mPointListSize, mPointFlags);
5219 
5220  volume_to_mesh_internal::reviseSeamLineFlags(mPolygons, mPolygonPoolListSize, mPointFlags);
5221  }
5222 
5223 }
5224 
5225 
5227 
5228 
5229 //{
5231 
5233 template<typename GridType>
5234 inline typename std::enable_if<std::is_scalar<typename GridType::ValueType>::value, void>::type
5235 doVolumeToMesh(
5236  const GridType& grid,
5237  std::vector<Vec3s>& points,
5238  std::vector<Vec3I>& triangles,
5239  std::vector<Vec4I>& quads,
5240  double isovalue,
5241  double adaptivity,
5243 {
5244  VolumeToMesh mesher(isovalue, adaptivity, relaxDisorientedTriangles);
5245  mesher(grid);
5246 
5247  // Preallocate the point list
5248  points.clear();
5249  points.resize(mesher.pointListSize());
5250 
5251  { // Copy points
5252  volume_to_mesh_internal::PointListCopy ptnCpy(mesher.pointList(), points);
5253  tbb::parallel_for(tbb::blocked_range<size_t>(0, points.size()), ptnCpy);
5254  mesher.pointList().reset(nullptr);
5255  }
5256 
5257  PolygonPoolList& polygonPoolList = mesher.polygonPoolList();
5258 
5259  { // Preallocate primitive lists
5260  size_t numQuads = 0, numTriangles = 0;
5261  for (size_t n = 0, N = mesher.polygonPoolListSize(); n < N; ++n) {
5262  openvdb::tools::PolygonPool& polygons = polygonPoolList[n];
5263  numTriangles += polygons.numTriangles();
5264  numQuads += polygons.numQuads();
5265  }
5266 
5267  triangles.clear();
5268  triangles.resize(numTriangles);
5269  quads.clear();
5270  quads.resize(numQuads);
5271  }
5272 
5273  // Copy primitives
5274  size_t qIdx = 0, tIdx = 0;
5275  for (size_t n = 0, N = mesher.polygonPoolListSize(); n < N; ++n) {
5276  openvdb::tools::PolygonPool& polygons = polygonPoolList[n];
5277 
5278  for (size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
5279  quads[qIdx++] = polygons.quad(i);
5280  }
5281 
5282  for (size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
5283  triangles[tIdx++] = polygons.triangle(i);
5284  }
5285  }
5286 }
5287 
5289 template<typename GridType>
5290 inline typename std::enable_if<!std::is_scalar<typename GridType::ValueType>::value, void>::type
5291 doVolumeToMesh(
5292  const GridType&,
5293  std::vector<Vec3s>&,
5294  std::vector<Vec3I>&,
5295  std::vector<Vec4I>&,
5296  double,
5297  double,
5298  bool)
5299 {
5300  OPENVDB_THROW(TypeError, "volume to mesh conversion is supported only for scalar grids");
5301 }
5302 
5304 //}
5305 
5306 
5307 template<typename GridType>
5308 inline void
5310  const GridType& grid,
5311  std::vector<Vec3s>& points,
5312  std::vector<Vec3I>& triangles,
5313  std::vector<Vec4I>& quads,
5314  double isovalue,
5315  double adaptivity,
5317 {
5318  doVolumeToMesh(grid, points, triangles, quads, isovalue, adaptivity, relaxDisorientedTriangles);
5319 }
5320 
5321 
5322 template<typename GridType>
5323 inline void
5325  const GridType& grid,
5326  std::vector<Vec3s>& points,
5327  std::vector<Vec4I>& quads,
5328  double isovalue)
5329 {
5330  std::vector<Vec3I> triangles;
5331  doVolumeToMesh(grid, points, triangles, quads, isovalue, 0.0, true);
5332 }
5333 
5334 } // namespace tools
5335 } // namespace OPENVDB_VERSION_NAME
5336 } // namespace openvdb
5337 
5338 #endif // OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED
5339 
5340 // Copyright (c) 2012-2017 DreamWorks Animation LLC
5341 // All rights reserved. This software is distributed under the
5342 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
Vec3d unpackPoint(uint32_t data)
Utility methods for point quantization.
Definition: VolumeToMesh.h:606
Mat3 transpose() const
returns transpose of this
Definition: Mat3.h:508
const IndexVector & internalNeighborsX() const
Return voxel offsets with internal neighbours in x + 1.
Definition: VolumeToMesh.h:2929
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition: Coord.h:115
const Buffer & buffer() const
Definition: LeafNode.h:365
SharedPtr< const GridBase > ConstPtr
Definition: Grid.h:108
void join(const IdentifyIntersectingVoxels &rhs)
Definition: VolumeToMesh.h:3258
void set(Coord ijk)
Definition: VolumeToMesh.h:3094
void init(const size_t upperBound, PolygonPool &polygonPool)
Definition: VolumeToMesh.h:2444
typename InputTreeType::LeafNodeType InputLeafNodeType
Definition: VolumeToMesh.h:3374
typename InputTreeType::ValueType InputValueType
Definition: VolumeToMesh.h:2661
ValueOnCIter cbeginValueOn() const
Definition: PointIndexGrid.h:1636
SharedPtr< const TreeBase > ConstPtr
Definition: Tree.h:68
typename InputTreeType::LeafNodeType InputLeafNodeType
Definition: VolumeToMesh.h:3245
boost::scoped_array< PolygonPool > PolygonPoolList
Point and primitive list types.
Definition: VolumeToMesh.h:181
const unsigned char sEdgeGroupTable[256][13]
Lookup table for different cell sign configurations. The first entry specifies the total number of po...
Definition: VolumeToMesh.h:456
OPENVDB_API const Index32 INVALID_IDX
MapPoints(const std::vector< PointIndexLeafNode *> &pointIndexNodes, const std::vector< Int16LeafNodeType *> &signDataNodes, boost::scoped_array< Index32 > &leafNodeCount)
Definition: VolumeToMesh.h:4004
const bool sAdaptable[256]
Used to quickly determine if a given cell is adaptable.
Definition: VolumeToMesh.h:430
void collectCornerValues(const LeafT &leaf, const Index offset, std::vector< double > &values)
Extracts the eight corner values for leaf inclusive cells.
Definition: VolumeToMesh.h:1012
void setSpatialAdaptivity(const FloatGridType &grid)
Definition: VolumeToMesh.h:2133
Definition: Mat4.h:51
MaskSurface(const std::vector< BoolLeafNodeType *> &nodes, const BoolTreeType &mask, const math::Transform &inputTransform, const math::Transform &maskTransform, bool invert)
Definition: VolumeToMesh.h:3601
void join(const MaskIntersectingVoxels &rhs)
Definition: VolumeToMesh.h:3388
Definition: VolumeToMesh.h:118
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: VolumeToMesh.h:3556
TreeType & tree()
Return a reference to this grid&#39;s tree, which might be shared with other grids.
Definition: Grid.h:797
void setAdaptivityMask(const BoolTreeType &mask)
Definition: VolumeToMesh.h:2139
void mergeVoxels(LeafType &leaf, const Coord &start, int dim, int regionId)
Definition: VolumeToMesh.h:947
void fillArray(ValueType *array, const ValueType &val, const size_t length)
Definition: VolumeToMesh.h:415
void operator()(const tbb::blocked_range< size_t > &) const
Definition: VolumeToMesh.h:1561
void setRefSignFlagsData(const Int16TreeType &signFlagsData, float internalAdaptivity)
Definition: VolumeToMesh.h:2144
void operator()(const tbb::blocked_range< size_t > &) const
Definition: VolumeToMesh.h:4089
MergeVoxelRegions(const InputGridType &inputGrid, const Index32TreeType &pointIndexTree, const std::vector< Index32LeafNodeType *> &pointIndexLeafNodes, const std::vector< Int16LeafNodeType *> &signFlagsLeafNodes, InputValueType iso, float adaptivity, bool invertSurfaceOrientation)
Definition: VolumeToMesh.h:2172
const IndexVector & minX() const
Return front face voxel offsets.
Definition: VolumeToMesh.h:2908
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:4533
const openvdb::Vec3I & triangle(size_t n) const
Definition: VolumeToMesh.h:149
bool isInsideValue(T value, T isovalue)
Definition: VolumeToMesh.h:631
const IndexVector & core() const
Return internal core voxel offsets.
Definition: VolumeToMesh.h:2904
char & quadFlags(size_t n)
Definition: VolumeToMesh.h:154
VoxelEdgeAccessor(AccessorT &_acc)
Definition: VolumeToMesh.h:3092
T dot(const Vec3< T > &v) const
Dot product.
Definition: Vec3.h:215
typename InputTreeType::template ValueConverter< Int16 >::Type Int16TreeType
Definition: VolumeToMesh.h:1769
const IndexVector & minZ() const
Return left face voxel offsets.
Definition: VolumeToMesh.h:2922
const size_t & pointListSize() const
Definition: VolumeToMesh.h:4845
bool isBoolValue< bool >()
Definition: VolumeToMesh.h:626
Coord worldToIndexCellCentered(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:138
T & z()
Definition: Vec3.h:111
ComputeAuxiliaryData(const InputTreeType &inputTree, const std::vector< const BoolLeafNodeType *> &intersectionLeafNodes, Int16TreeType &signFlagsTree, Index32TreeType &pointIndexTree, InputValueType iso)
Definition: VolumeToMesh.h:3780
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:101
Mat3< double > Mat3d
Definition: Mat3.h:708
tree::LeafNode< bool, InputLeafNodeType::LOG2DIM > BoolLeafNodeType
Definition: VolumeToMesh.h:3747
uint32_t Index32
Definition: Types.h:55
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:1945
typename InputTreeType::LeafNodeType InputLeafNodeType
Definition: VolumeToMesh.h:1477
void join(MaskBorderVoxels &rhs)
Definition: VolumeToMesh.h:3493
void operator()(const tbb::blocked_range< size_t > &inputArrayRange) const
Definition: VolumeToMesh.h:4185
MaskTileBorders(const InputTreeType &inputTree, InputValueType iso, BoolTreeType &mask, const Vec4i *tileArray)
Definition: VolumeToMesh.h:2665
void setRefGrid(const GridBase::ConstPtr &grid, double secAdaptivity=0)
When surfacing fractured SDF fragments, the original unfractured SDF grid can be used to eliminate se...
Definition: VolumeToMesh.h:4873
void evalInternalVoxelEdges(VoxelEdgeAcc &edgeAcc, const LeafNode &leafnode, const LeafNodeVoxelOffsets &voxels, const typename LeafNode::ValueType iso)
Definition: VolumeToMesh.h:3129
tree::LeafNode< Int16, PointIndexLeafNode::LOG2DIM > Int16LeafNodeType
Definition: VolumeToMesh.h:4002
PointList & pointList()
Definition: VolumeToMesh.h:4838
tbb::atomic< Index32 > i
Definition: LeafBuffer.h:71
typename InputTreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: VolumeToMesh.h:3248
bool isPlanarQuad(const Vec3d &p0, const Vec3d &p1, const Vec3d &p2, const Vec3d &p3, double epsilon=0.001)
Definition: VolumeToMesh.h:548
typename InputLeafNodeType::ValueType InputValueType
Definition: VolumeToMesh.h:1767
SyncMaskValues(const std::vector< BoolLeafNodeType *> &nodes, const BoolTreeType &mask)
Definition: VolumeToMesh.h:3558
void identifySurfaceIntersectingVoxels(typename InputTreeType::template ValueConverter< bool >::Type &intersectionTree, const InputTreeType &inputTree, typename InputTreeType::ValueType isovalue)
Definition: VolumeToMesh.h:3349
void resetTriangles(size_t size)
Definition: VolumeToMesh.h:4735
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:261
T * data
Definition: LeafBuffer.h:71
ComputePolygons(const std::vector< Int16LeafNodeType *> &signFlagsLeafNodes, const Int16TreeType &signFlagsTree, const Index32TreeType &idxTree, PolygonPoolList &polygons, bool invertSurfaceOrientation)
Definition: VolumeToMesh.h:4072
void operator()(const tbb::blocked_range< size_t > &range)
Definition: VolumeToMesh.h:2003
typename InputTreeType::LeafNodeType InputLeafNodeType
Definition: VolumeToMesh.h:1766
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition: Coord.h:419
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists...
Definition: ValueAccessor.h:429
const IndexVector & internalNeighborsZ() const
Return voxel offsets with internal neighbours in z + 1.
Definition: VolumeToMesh.h:2935
const size_t & polygonPoolListSize() const
Definition: VolumeToMesh.h:4866
void clearTriangles()
Definition: VolumeToMesh.h:4744
typename TreeType::LeafNodeType LeafNodeType
Definition: VolumeToMesh.h:1980
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:3611
Vec3d computeWeightedPoint(const Vec3d &p, const std::vector< double > &values, unsigned char signs, unsigned char edgeGroup, double iso)
Computes the average cell point for a given edge group, by computing convex weights based on the dist...
Definition: VolumeToMesh.h:1254
typename InputLeafNodeType::ValueType InputValueType
Definition: VolumeToMesh.h:3375
const char & triangleFlags(size_t n) const
Definition: VolumeToMesh.h:158
void reviseSeamLineFlags(PolygonPoolList &polygonPoolList, size_t polygonPoolListSize, std::vector< uint8_t > &pointFlags)
Definition: VolumeToMesh.h:4507
typename Index32TreeType::LeafNodeType Index32LeafNodeType
Definition: VolumeToMesh.h:4047
VolumeToMesh(double isovalue=0, double adaptivity=0, bool relaxDisorientedTriangles=true)
Definition: VolumeToMesh.h:4814
void constructPolygons(bool invertSurfaceOrientation, Int16 flags, Int16 refFlags, const Vec3i &offsets, const Coord &ijk, const SignAccT &signAcc, const IdxAccT &idxAcc, PrimBuilder &mesher)
Definition: VolumeToMesh.h:2539
Collection of quads and triangles.
Definition: VolumeToMesh.h:122
Vec3< int32_t > Vec3i
Definition: Vec3.h:675
Index32 Index
Definition: Types.h:57
void collectCornerValues(const AccessorT &acc, const Coord &ijk, std::vector< double > &values)
Extracts the eight corner values for a cell starting at the given coordinate.
Definition: VolumeToMesh.h:1028
Definition: Mat.h:195
ValueOnCIter cbeginValueOn() const
Definition: LeafNode.h:317
Vec3< float > Vec3s
Definition: Vec3.h:677
IdentifyIntersectingVoxels(const InputTreeType &inputTree, const std::vector< const InputLeafNodeType *> &inputLeafNodes, BoolTreeType &intersectionTree, InputValueType iso)
Definition: VolumeToMesh.h:3277
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:1084
typename SignDataTreeType::LeafNodeType SignDataLeafNodeType
Definition: VolumeToMesh.h:1936
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:4213
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:287
const ValueType * data() const
Return a const pointer to the array of voxel values.
Definition: LeafBuffer.h:392
std::vector< Index > IndexVector
Definition: VolumeToMesh.h:2898
int getValueDepth(const Coord &xyz) const
Definition: ValueAccessor.h:275
void operator()(const tbb::blocked_range< size_t > &) const
Definition: VolumeToMesh.h:2199
typename Int16TreeType::LeafNodeType Int16LeafNodeType
Definition: VolumeToMesh.h:1770
const IndexVector & maxY() const
Return top face voxel offsets.
Definition: VolumeToMesh.h:2918
void operator()(const InputGridType &)
Main call.
Definition: VolumeToMesh.h:4924
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:1790
void init(const size_t upperBound, PolygonPool &quadPool)
Definition: VolumeToMesh.h:2405
TransferSeamLineFlags(const std::vector< SignDataLeafNodeType *> &signFlagsLeafNodes, const BoolTreeType &maskTree)
Definition: VolumeToMesh.h:1938
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
const IndexVector & internalNeighborsY() const
Return voxel offsets with internal neighbours in y + 1.
Definition: VolumeToMesh.h:2932
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:4013
Vec3d findFeaturePoint(const std::vector< Vec3d > &points, const std::vector< Vec3d > &normals)
Given a set of tangent elements, points with corresponding normals, this method returns the intersect...
Definition: VolumeToMesh.h:296
char & triangleFlags(size_t n)
Definition: VolumeToMesh.h:157
void computeAuxiliaryData(typename InputTreeType::template ValueConverter< Int16 >::Type &signFlagsTree, typename InputTreeType::template ValueConverter< Index32 >::Type &pointIndexTree, const typename InputTreeType::template ValueConverter< bool >::Type &intersectionTree, const InputTreeType &inputTree, typename InputTreeType::ValueType isovalue)
Definition: VolumeToMesh.h:3891
openvdb::Vec3I & triangle(size_t n)
Definition: VolumeToMesh.h:148
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointIndexLeafNode, const ValueType, ValueOn > ValueOnCIter
Definition: PointIndexGrid.h:1613
MaskSeamLineVoxels(MaskSeamLineVoxels &rhs, tbb::split)
Definition: VolumeToMesh.h:1993
MaskBorderVoxels(const BoolTreeType &maskTree, const std::vector< BoolLeafNodeType *> &maskNodes, BoolTreeType &borderTree)
Definition: VolumeToMesh.h:3475
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:61
void join(MaskTileBorders &rhs)
Definition: VolumeToMesh.h:2684
Calculate an axis-aligned bounding box in index space from a bounding sphere in world space...
Definition: Transform.h:66
ValueOnCIter beginValueOn() const
Definition: PointIndexGrid.h:1637
bool isBoolValue()
Definition: VolumeToMesh.h:623
typename TreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: VolumeToMesh.h:1981
SubdivideQuads(PolygonPoolList &polygons, const boost::scoped_array< openvdb::Vec3s > &points, size_t pointCount, boost::scoped_array< openvdb::Vec3s > &centroids, boost::scoped_array< unsigned > &numQuadsToDivide, boost::scoped_array< unsigned > &centroidOffsets)
Definition: VolumeToMesh.h:4261
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:3564
void markSeamLineData(SignDataTreeType &signFlagsTree, const SignDataTreeType &refSignFlagsTree)
Definition: VolumeToMesh.h:2076
MaskSeamLineVoxels(const std::vector< LeafNodeType *> &signFlagsLeafNodes, const TreeType &signFlagsTree, BoolTreeType &mask)
Definition: VolumeToMesh.h:1983
ReviseSeamLineFlags(PolygonPoolList &polygons, const std::vector< uint8_t > &pointFlags)
Definition: VolumeToMesh.h:4448
Definition: VolumeToMesh.h:118
Vec4< int32_t > Vec4i
Definition: Vec4.h:585
#define OPENVDB_VERSION_NAME
Definition: version.h:43
const Coord & origin() const
Return the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:198
CopyArray(T *outputArray, const T *inputArray, size_t outputOffset=0)
Definition: VolumeToMesh.h:4180
const size_t & numQuads() const
Definition: VolumeToMesh.h:140
Vec3d computePoint(const std::vector< double > &values, unsigned char signs, unsigned char edgeGroup, double iso)
Computes the average cell point for a given edge group.
Definition: VolumeToMesh.h:1058
const ValueType mValue
Definition: VolumeToMesh.h:409
int16_t Int16
Definition: Types.h:58
void maskActiveTileBorders(const InputTreeType &inputTree, typename InputTreeType::ValueType iso, typename InputTreeType::template ValueConverter< bool >::Type &mask)
Definition: VolumeToMesh.h:2832
typename Int16TreeType::LeafNodeType Int16LeafNodeType
Definition: VolumeToMesh.h:1481
void setSpatialAdaptivity(const GridBase::ConstPtr &grid)
Definition: VolumeToMesh.h:4895
typename InputTreeType::template ValueConverter< Index32 >::Type Index32TreeType
Definition: VolumeToMesh.h:3750
Definition: PointIndexGrid.h:79
LeafNodePointCount(const std::vector< Int16LeafNodeType *> &leafNodes, boost::scoped_array< Index32 > &leafNodeCount)
Definition: VolumeToMesh.h:3919
void resetQuads(size_t size)
Definition: VolumeToMesh.h:4717
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:4276
typename InputTreeType::template ValueConverter< float >::Type FloatTreeType
Definition: VolumeToMesh.h:2112
void addPrim(const math::Vec4< IndexType > &verts, bool reverse, char flags=0)
Definition: VolumeToMesh.h:2413
void operator()(const tbb::blocked_range< size_t > &)
Definition: VolumeToMesh.h:2699
MaskIntersectingVoxels(const InputTreeType &inputTree, const std::vector< BoolLeafNodeType *> &nodes, BoolTreeType &intersectionTree, InputValueType iso)
Definition: VolumeToMesh.h:3404
bool diagonalizeSymmetricMatrix(const Mat3< T > &input, Mat3< T > &Q, Vec3< T > &D, unsigned int MAX_ITERATIONS=250)
Use Jacobi iterations to decompose a symmetric 3x3 matrix (diagonalize and compute eigenvectors) ...
Definition: Mat3.h:794
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: VolumeToMesh.h:1933
MaskTileBorders(MaskTileBorders &rhs, tbb::split)
Definition: VolumeToMesh.h:2675
typename TreeType::template ValueConverter< Index32 >::Type Index32TreeType
Definition: VolumeToMesh.h:4046
typename InputTreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: VolumeToMesh.h:2662
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: VolumeToMesh.h:3599
typename InputTreeType::template ValueConverter< Int16 >::Type Int16TreeType
Definition: VolumeToMesh.h:1480
void copy(const PolygonPool &rhs)
Definition: VolumeToMesh.h:4699
bool normalize(T eps=T(1.0e-7))
this = normalized this
Definition: Vec3.h:376
typename InputTreeType::LeafNodeType InputLeafNodeType
Definition: VolumeToMesh.h:3744
Definition: Exceptions.h:39
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:3926
AdaptiveLeafNodePointCount(const std::vector< PointIndexLeafNode *> &pointIndexNodes, const std::vector< Int16LeafNodeType *> &signDataNodes, boost::scoped_array< Index32 > &leafNodeCount)
Definition: VolumeToMesh.h:3955
Coord & offset(Int32 dx, Int32 dy, Int32 dz)
Definition: Coord.h:107
const Coord & max() const
Definition: Coord.h:335
void volumeToMesh(const GridType &grid, std::vector< Vec3s > &points, std::vector< Vec3I > &triangles, std::vector< Vec4I > &quads, double isovalue=0.0, double adaptivity=0.0, bool relaxDisorientedTriangles=true)
Adaptively mesh any scalar grid that has a continuous isosurface.
Definition: VolumeToMesh.h:5309
const IndexVector & minY() const
Return bottom face voxel offsets.
Definition: VolumeToMesh.h:2915
typename InputTreeType::template ValueConverter< Int16 >::Type Int16TreeType
Definition: VolumeToMesh.h:3749
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:4455
typename TreeType::template ValueConverter< Int16 >::Type Int16TreeType
Definition: VolumeToMesh.h:4043
Vec3< double > Vec3d
Definition: Vec3.h:678
typename InputGridType::TreeType InputTreeType
Definition: VolumeToMesh.h:2108
void computeCellPoints(std::vector< Vec3d > &points, std::vector< bool > &weightedPointMask, const std::vector< double > &lhsValues, const std::vector< double > &rhsValues, unsigned char lhsSigns, unsigned char rhsSigns, double iso, size_t pointIdx, const uint32_t *seamPointArray)
Computes the average cell points defined by the sign configuration signs and the given corner values ...
Definition: VolumeToMesh.h:1443
typename InputTreeType::LeafNodeType InputLeafNodeType
Definition: VolumeToMesh.h:2109
Gradient operators defined in index space of various orders.
Definition: Operators.h:122
PolygonPoolList & polygonPoolList()
Definition: VolumeToMesh.h:4852
void computeCellPoints(std::vector< Vec3d > &points, const std::vector< double > &values, unsigned char signs, double iso)
Computes the average cell points defined by the sign configuration signs and the given corner values ...
Definition: VolumeToMesh.h:1412
void setRefSignTree(const Int16TreeType *r)
Definition: VolumeToMesh.h:4057
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: VolumeToMesh.h:3378
static const Index SIZE
Definition: LeafNode.h:77
typename InputLeafNodeType::ValueType InputValueType
Definition: VolumeToMesh.h:3745
typename InputLeafNodeType::ValueType InputValueType
Definition: VolumeToMesh.h:1478
void addPrim(const math::Vec4< IndexType > &verts, bool reverse, char flags=0)
Definition: VolumeToMesh.h:2455
openvdb::Vec4I & quad(size_t n)
Definition: VolumeToMesh.h:142
int computeMaskedPoint(Vec3d &avg, const std::vector< double > &values, unsigned char signs, unsigned char signsMask, unsigned char edgeGroup, double iso)
Computes the average cell point for a given edge group, ignoring edge samples present in the signsMas...
Definition: VolumeToMesh.h:1150
Definition: Exceptions.h:92
SeamLineWeights(const std::vector< Int16LeafNodeType *> &signFlagsLeafNodes, const InputTreeType &inputTree, const Index32TreeType &refPointIndexTree, const Int16TreeType &refSignFlagsTree, uint32_t *quantizedPoints, InputValueType iso)
Definition: VolumeToMesh.h:1775
void getCellVertexValues(const LeafT &leaf, const Index offset, math::Tuple< 8, typename LeafT::ValueType > &values)
Definition: VolumeToMesh.h:662
double evalZeroCrossing(double v0, double v1, double iso)
linear interpolation.
Definition: VolumeToMesh.h:1006
PointListCopy(const PointList &pointsIn, std::vector< Vec3s > &pointsOut)
Definition: VolumeToMesh.h:2874
const size_t & numTriangles() const
Definition: VolumeToMesh.h:146
void applySurfaceMask(typename InputGridType::TreeType::template ValueConverter< bool >::Type &intersectionTree, typename InputGridType::TreeType::template ValueConverter< bool >::Type &borderTree, const InputGridType &inputGrid, const GridBase::ConstPtr &maskGrid, bool invertMask, typename InputGridType::ValueType isovalue)
Definition: VolumeToMesh.h:3676
Vec3d indexToWorld(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:135
void evalExtrenalVoxelEdgesInv(VoxelEdgeAcc &edgeAcc, TreeAcc &acc, const LeafNode &leafnode, const LeafNodeVoxelOffsets &voxels, const typename LeafNode::ValueType iso)
Definition: VolumeToMesh.h:3207
Mesh any scalar grid that has a continuous isosurface.
Definition: VolumeToMesh.h:189
typename InputTreeType::template ValueConverter< Int16 >::Type Int16TreeType
Definition: VolumeToMesh.h:2116
typename InputLeafNodeType::ValueType InputValueType
Definition: VolumeToMesh.h:2110
const IndexVector & maxX() const
Return back face voxel offsets.
Definition: VolumeToMesh.h:2911
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:401
void volumeToMesh(const GridType &grid, std::vector< Vec3s > &points, std::vector< Vec4I > &quads, double isovalue=0.0)
Uniformly mesh any scalar grid that has a continuous isosurface.
Definition: VolumeToMesh.h:5324
const IndexVector & maxZ() const
Return right face voxel offsets.
Definition: VolumeToMesh.h:2925
void setSurfaceMask(const GridBase::ConstPtr &mask, bool invertMask=false)
Definition: VolumeToMesh.h:4887
typename Int16TreeType::LeafNodeType Int16LeafNodeType
Definition: VolumeToMesh.h:4044
Coord & reset(Int32 x, Int32 y, Int32 z)
Reset all three coordinates with the specified arguments.
Definition: Coord.h:93
typename FloatTreeType::LeafNodeType FloatLeafNodeType
Definition: VolumeToMesh.h:2113
bool trimQuads(const size_t n, bool reallocate=false)
Definition: VolumeToMesh.h:4753
tree::LeafNode< Int16, PointIndexLeafNode::LOG2DIM > Int16LeafNodeType
Definition: VolumeToMesh.h:3953
bool isMergable(LeafType &leaf, const Coord &start, int dim, typename LeafType::ValueType::value_type adaptivity)
Definition: VolumeToMesh.h:968
FlagAndCountQuadsToSubdivide(PolygonPoolList &polygons, const std::vector< uint8_t > &pointFlags, boost::scoped_array< openvdb::Vec3s > &points, boost::scoped_array< unsigned > &numQuadsToDivide)
Definition: VolumeToMesh.h:4202
tree::LeafNode< Int16, LeafNodeLog2Dim > Int16LeafNodeType
Definition: VolumeToMesh.h:3917
ValueType *const mArray
Definition: VolumeToMesh.h:408
void relaxDisorientedTriangles(bool invertSurfaceOrientation, const InputTree &inputTree, const math::Transform &transform, PolygonPoolList &polygonPoolList, size_t polygonPoolListSize, PointList &pointList, const size_t pointListSize)
Definition: VolumeToMesh.h:4596
typename InputTreeType::template ValueConverter< Index32 >::Type Index32TreeType
Definition: VolumeToMesh.h:2119
void correctCellSigns(uint8_t &signs, uint8_t face, const AccessorT &acc, Coord ijk, typename AccessorT::ValueType iso)
Used to correct topological ambiguities related to two adjacent cells that share an ambiguous face...
Definition: VolumeToMesh.h:760
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
Definition: ValueAccessor.h:266
void operator()(const tbb::blocked_range< size_t > &range)
Definition: VolumeToMesh.h:3495
void evalExtrenalVoxelEdges(VoxelEdgeAcc &edgeAcc, TreeAcc &acc, const LeafNode &lhsNode, const LeafNodeVoxelOffsets &voxels, const typename LeafNode::ValueType iso)
Definition: VolumeToMesh.h:3159
Abstract base class for typed grids.
Definition: Grid.h:104
MaskBorderVoxels(MaskBorderVoxels &rhs, tbb::split)
Definition: VolumeToMesh.h:3485
const unsigned char sAmbiguousFace[256]
Contains the ambiguous face index for certain cell configuration.
Definition: VolumeToMesh.h:442
TreeType & tree() const
Return a reference to the tree associated with this accessor.
Definition: ValueAccessor.h:147
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:48
typename InputTreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: VolumeToMesh.h:3377
int matchEdgeGroup(unsigned char groupId, unsigned char lhsSigns, unsigned char rhsSigns)
Given a sign configuration lhsSigns and an edge group groupId, finds the corresponding edge group in ...
Definition: VolumeToMesh.h:1425
std::vector< uint8_t > & pointFlags()
Definition: VolumeToMesh.h:4909
void setRefData(const InputTreeType &refInputTree, const Index32TreeType &refPointIndexTree, const Int16TreeType &refSignFlagsTree, const uint32_t *quantizedSeamLinePoints, uint8_t *seamLinePointsFlags)
Definition: VolumeToMesh.h:1545
typename InputTreeType::template ValueConverter< Index32 >::Type Index32TreeType
Definition: VolumeToMesh.h:1483
boost::scoped_array< openvdb::Vec3s > PointList
Point and primitive list types.
Definition: VolumeToMesh.h:180
void subdivideNonplanarSeamLineQuads(PolygonPoolList &polygonPoolList, size_t polygonPoolListSize, PointList &pointList, size_t &pointListSize, std::vector< uint8_t > &pointFlags)
Definition: VolumeToMesh.h:4394
uint8_t computeSignFlags(const math::Tuple< 8, ValueType > &values, const ValueType iso)
Definition: VolumeToMesh.h:678
typename Index32TreeType::LeafNodeType Index32LeafNodeType
Definition: VolumeToMesh.h:1773
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:256
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:3964
void clearQuads()
Definition: VolumeToMesh.h:4726
Utility method to marks all voxels that share an edge.
Definition: VolumeToMesh.h:3087
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:55
Definition: Tuple.h:54
void operator()(const tbb::blocked_range< size_t > &)
Definition: VolumeToMesh.h:3310
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
typename InputTreeType::template ValueConverter< Index32 >::Type Index32TreeType
Definition: VolumeToMesh.h:1772
typename InputTreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: VolumeToMesh.h:2122
const Coord & min() const
Definition: Coord.h:334
SetSeamLineFlags(const std::vector< LeafNodeType *> &signFlagsLeafNodes, const TreeType &refSignFlagsTree)
Definition: VolumeToMesh.h:1885
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: VolumeToMesh.h:2123
const char & quadFlags(size_t n) const
Definition: VolumeToMesh.h:155
Base class for typed trees.
Definition: Tree.h:64
PolygonPool()
Definition: VolumeToMesh.h:4675
const openvdb::Vec4I & quad(size_t n) const
Definition: VolumeToMesh.h:143
uint32_t packPoint(const Vec3d &v)
Utility methods for point quantization.
Definition: VolumeToMesh.h:590
SharedPtr< TreeBase > Ptr
Definition: Tree.h:67
FillArray(ValueType *array, const ValueType &v)
Definition: VolumeToMesh.h:399
static constexpr size_t size
The size of a LeafBuffer when LeafBuffer::mOutOfCore is atomic.
Definition: LeafBuffer.h:85
bool isNonManifold(const AccessorT &accessor, const Coord &ijk, typename AccessorT::ValueType isovalue, const int dim)
Definition: VolumeToMesh.h:796
typename Int16TreeType::LeafNodeType Int16LeafNodeType
Definition: VolumeToMesh.h:2117
math::Transform & transform()
Return a reference to this grid&#39;s transform, which might be shared with other grids.
Definition: Grid.h:347
typename InputLeafNodeType::ValueType InputValueType
Definition: VolumeToMesh.h:3246
void join(MaskSeamLineVoxels &rhs)
Definition: VolumeToMesh.h:2001
typename BoolTreeType::template ValueConverter< SignDataType >::Type SignDataTreeType
Definition: VolumeToMesh.h:1935
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:263
Index64 pointCount(const PointDataTreeT &tree, const bool inCoreOnly=false)
Total points in the PointDataTree.
Definition: PointCount.h:198
void join(const ComputeAuxiliaryData &rhs)
Definition: VolumeToMesh.h:3761
void setValueOnly(const Coord &, const ValueType &)
Definition: PointIndexGrid.h:1533
void getCellVertexValues(const AccessorT &accessor, Coord ijk, math::Tuple< 8, typename AccessorT::ValueType > &values)
Definition: VolumeToMesh.h:639
bool trimTrinagles(const size_t n, bool reallocate=false)
Definition: VolumeToMesh.h:4782
Definition: Types.h:264
typename TreeType::LeafNodeType LeafNodeType
Definition: VolumeToMesh.h:1883
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: VolumeToMesh.h:3473
uint8_t evalCellSigns(const LeafT &leaf, const Index offset, typename LeafT::ValueType iso)
Leaf node optimized method that computes the cell-sign configuration at the given local offset...
Definition: VolumeToMesh.h:724
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:2879
typename Index32TreeType::LeafNodeType Index32LeafNodeType
Definition: VolumeToMesh.h:1484
T ValueType
Definition: PointIndexGrid.h:1386
void operator()(const tbb::blocked_range< size_t > &)
Definition: VolumeToMesh.h:3432
bool isInsideValue< bool >(bool value, bool)
Definition: VolumeToMesh.h:634
void operator()(const tbb::blocked_range< size_t > &)
Definition: VolumeToMesh.h:3813
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:1892
typename Index32TreeType::LeafNodeType Index32LeafNodeType
Definition: VolumeToMesh.h:2120
MaskDisorientedTrianglePoints(const InputTreeType &inputTree, const PolygonPoolList &polygons, const PointList &pointList, boost::scoped_array< uint8_t > &pointMask, const math::Transform &transform, bool invertSurfaceOrientation)
Definition: VolumeToMesh.h:4521
void setAdaptivityMask(const TreeBase::ConstPtr &tree)
Definition: VolumeToMesh.h:4902