OpenVDB: VolumeToMesh.h Source File

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
42 #include <openvdb/tree/ValueAccessor.h>
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 {
62 OPENVDB_USE_VERSION_NAMESPACE
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
83 volumeToMesh(
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
104 volumeToMesh(
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
118 enum { POLYFLAG_EXTERIOR = 0x1, POLYFLAG_FRACTURE_SEAM = 0x2, POLYFLAG_SUBDIVIDED = 0x4 };
119
120
122 class PolygonPool
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
189 struct VolumeToMesh
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
296 inline Vec3d findFeaturePoint(
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
548 isPlanarQuad(
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,
640 math::Tuple<8, typename AccessorT::ValueType>& values)
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,
663 math::Tuple<8, typename LeafT::ValueType>& values)
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>
1475 struct ComputePoints
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>
1520 ComputePoints<InputTreeType>::ComputePoints(
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
1545 ComputePoints<InputTreeType>::setRefData(
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 {
1682 OPENVDB_THROW(ValueError,
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>
1764 struct SeamLineWeights
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>
1881 struct SetSeamLineFlags
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>
1931 struct TransferSeamLineFlags
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>
1978 struct MaskSeamLineVoxels
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
1993 MaskSeamLineVoxels(MaskSeamLineVoxels& rhs, tbb::split)
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
2092 MaskSeamLineVoxels<SignDataTreeType>
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>
2106 struct MergeVoxelRegions
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;
2114 using FloatGridType = Grid<FloatTreeType>;
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
2133 void setSpatialAdaptivity(const FloatGridType& grid)
2134 {
2135 mSpatialAdaptivityTree = &grid.tree();
2136 mSpatialAdaptivityTransform = &grid.transform();
2137 }
2138
2139 void setAdaptivityMask(const BoolTreeType& mask)
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>
2172 MergeVoxelRegions<InputGridType>::MergeVoxelRegions(
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
2401 struct UniformPrimBuilder
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
2440 struct AdaptivePrimBuilder
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
2539 constructPolygons(
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>
2659 struct MaskTileBorders
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
2675 MaskTileBorders(MaskTileBorders& rhs, tbb::split)
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
2871 class PointListCopy
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
2896 struct LeafNodeVoxelOffsets
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
2946 LeafNodeVoxelOffsets::constructOffsetList()
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>
3087 struct VoxelEdgeAccessor {
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>
3243 struct IdentifyIntersectingVoxels
3244 {
3245 using InputLeafNodeType = typename InputTreeType::LeafNodeType;
3246 using InputValueType = typename InputLeafNodeType::ValueType;
3247
3248 using BoolTreeType = typename InputTreeType::template ValueConverter<bool>::Type;
3249
3250 IdentifyIntersectingVoxels(
3251 const InputTreeType& inputTree,
3252 const std::vector<const InputLeafNodeType*>& inputLeafNodes,
3253 BoolTreeType& intersectionTree,
3254 InputValueType iso);
3255
3256 IdentifyIntersectingVoxels(IdentifyIntersectingVoxels&, tbb::split);
3257 void operator()(const tbb::blocked_range<size_t>&);
3258 void join(const IdentifyIntersectingVoxels& rhs) {
3259 mIntersectionAccessor.tree().merge(rhs.mIntersectionAccessor.tree());
3260 }
3261
3262 private:
3263 tree::ValueAccessor<const InputTreeType> mInputAccessor;
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>
3277 IdentifyIntersectingVoxels<InputTreeType>::IdentifyIntersectingVoxels(
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>
3295 IdentifyIntersectingVoxels<InputTreeType>::IdentifyIntersectingVoxels(
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
3349 identifySurfaceIntersectingVoxels(
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
3359 IdentifyIntersectingVoxels<InputTreeType> op(
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>
3372 struct MaskIntersectingVoxels
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
3380 MaskIntersectingVoxels(
3381 const InputTreeType& inputTree,
3382 const std::vector<BoolLeafNodeType*>& nodes,
3383 BoolTreeType& intersectionTree,
3384 InputValueType iso);
3385
3386 MaskIntersectingVoxels(MaskIntersectingVoxels&, tbb::split);
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:
3393 tree::ValueAccessor<const InputTreeType> mInputAccessor;
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>
3404 MaskIntersectingVoxels<InputTreeType>::MaskIntersectingVoxels(
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>
3419 MaskIntersectingVoxels<InputTreeType>::MaskIntersectingVoxels(
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>
3471 struct MaskBorderVoxels
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
3485 MaskBorderVoxels(MaskBorderVoxels& rhs, tbb::split)
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>
3554 struct SyncMaskValues
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>
3597 struct MaskSurface
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
3676 applySurfaceMask(
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()),
3706 MaskSurface<BoolTreeType>(
3707 intersectionLeafNodes, maskTree, transform, maskTransform, invertMask));
3708
3709
3710 // mask surface-mask border
3711
3712 MaskBorderVoxels<BoolTreeType> borderOp(
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
3721 MaskIntersectingVoxels<InputTreeType> op(
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>
3742 struct ComputeAuxiliaryData
3743 {
3744 using InputLeafNodeType = typename InputTreeType::LeafNodeType;
3745 using InputValueType = typename InputLeafNodeType::ValueType;
3746
3747 using BoolLeafNodeType = tree::LeafNode<bool, InputLeafNodeType::LOG2DIM>;
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
3759 ComputeAuxiliaryData(ComputeAuxiliaryData&, tbb::split);
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:
3767 tree::ValueAccessor<const InputTreeType> mInputAccessor;
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>
3780 ComputeAuxiliaryData<InputTreeType>::ComputeAuxiliaryData(
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>
3799 ComputeAuxiliaryData<InputTreeType>::ComputeAuxiliaryData(ComputeAuxiliaryData& rhs, tbb::split)
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
3891 computeAuxiliaryData(
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
3904 ComputeAuxiliaryData<InputTreeType> op(
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>
3915 struct LeafNodePointCount
3916 {
3917 using Int16LeafNodeType = tree::LeafNode<Int16, LeafNodeLog2Dim>;
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>
3951 struct AdaptiveLeafNodePointCount
3952 {
3953 using Int16LeafNodeType = tree::LeafNode<Int16, PointIndexLeafNode::LOG2DIM>;
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>
4000 struct MapPoints
4001 {
4002 using Int16LeafNodeType = tree::LeafNode<Int16, PointIndexLeafNode::LOG2DIM>;
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>
4041 struct ComputePolygons
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
4050 ComputePolygons(
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>
4072 ComputePolygons<TreeType, PrimBuilder>::ComputePolygons(
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>
4178 struct CopyArray
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
4200 struct FlagAndCountQuadsToSubdivide
4201 {
4202 FlagAndCountQuadsToSubdivide(PolygonPoolList& polygons,
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
4259 struct SubdivideQuads
4260 {
4261 SubdivideQuads(PolygonPoolList& polygons,
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
4394 subdivideNonplanarSeamLineQuads(
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
4446 struct ReviseSeamLineFlags
4447 {
4448 ReviseSeamLineFlags(PolygonPoolList& polygons,
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>
4519 struct MaskDisorientedTrianglePoints
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
4596 relaxDisorientedTriangles(
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,
4611 MaskDisorientedTrianglePoints<InputTree>(
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
4675 PolygonPool::PolygonPool()
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
4699 PolygonPool::copy(const PolygonPool& rhs)
4700 {
4701 resetQuads(rhs.numQuads());
4702 resetTriangles(rhs.numTriangles());
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
4717 PolygonPool::resetQuads(size_t size)
4718 {
4719 mNumQuads = size;
4720 mQuads.reset(new openvdb::Vec4I[mNumQuads]);
4721 mQuadFlags.reset(new char[mNumQuads]);
4722 }
4723
4724
4725 inline void
4726 PolygonPool::clearQuads()
4727 {
4728 mNumQuads = 0;
4729 mQuads.reset(nullptr);
4730 mQuadFlags.reset(nullptr);
4731 }
4732
4733
4734 inline void
4735 PolygonPool::resetTriangles(size_t size)
4736 {
4737 mNumTriangles = size;
4738 mTriangles.reset(new openvdb::Vec3I[mNumTriangles]);
4739 mTriangleFlags.reset(new char[mNumTriangles]);
4740 }
4741
4742
4743 inline void
4744 PolygonPool::clearTriangles()
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&
4838 VolumeToMesh::pointList()
4839 {
4840 return mPoints;
4841 }
4842
4843
4844 inline const size_t&
4845 VolumeToMesh::pointListSize() const
4846 {
4847 return mPointListSize;
4848 }
4849
4850
4851 inline PolygonPoolList&
4852 VolumeToMesh::polygonPoolList()
4853 {
4854 return mPolygons;
4855 }
4856
4857
4858 inline const PolygonPoolList&
4859 VolumeToMesh::polygonPoolList() const
4860 {
4861 return mPolygons;
4862 }
4863
4864
4865 inline const size_t&
4866 VolumeToMesh::polygonPoolListSize() const
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
4887 VolumeToMesh::setSurfaceMask(const GridBase::ConstPtr& mask, bool invertMask)
4888 {
4889 mSurfaceMaskGrid = mask;
4890 mInvertSurfaceMask = invertMask;
4891 }
4892
4893
4894 inline void
4895 VolumeToMesh::setSpatialAdaptivity(const GridBase::ConstPtr& grid)
4896 {
4897 mAdaptivityGrid = grid;
4898 }
4899
4900
4901 inline void
4902 VolumeToMesh::setAdaptivityMask(const TreeBase::ConstPtr& tree)
4903 {
4904 mAdaptivityMaskTree = tree;
4905 }
4906
4907
4908 inline std::vector<uint8_t>&
4909 VolumeToMesh::pointFlags()
4910 {
4911 return mPointFlags;
4912 }
4913
4914
4915 inline const std::vector<uint8_t>&
4916 VolumeToMesh::pointFlags() const
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
4981 volume_to_mesh_internal::identifySurfaceIntersectingVoxels(
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
4989 volume_to_mesh_internal::computeAuxiliaryData(
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
5024 volume_to_mesh_internal::identifySurfaceIntersectingVoxels(
5025 refIntersectionTree, *refInputTree, isovalue);
5026
5027 volume_to_mesh_internal::computeAuxiliaryData(*refSignFlagsTreePt,
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()),
5060 volume_to_mesh_internal::LeafNodePointCount<Int16LeafNodeType::LOG2DIM>(
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()),
5083 volume_to_mesh_internal::MapPoints<Index32LeafNodeType>(
5084 refPointIndexLeafNodes, refSignFlagsLeafNodes, leafNodeOffsets));
5085 }
5086 }
5087
5088 if (mSeamPointListSize != 0) {
5089
5090 tbb::parallel_for(auxiliaryLeafNodeRange,
5091 volume_to_mesh_internal::SeamLineWeights<InputTreeType>(
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) {
5106 volume_to_mesh_internal::MergeVoxelRegions<InputGridType> mergeOp(
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
5126 volume_to_mesh_internal::AdaptiveLeafNodePointCount<Index32LeafNodeType>
5127 op(pointIndexLeafNodes, signFlagsLeafNodes, leafNodeOffsets);
5128
5129 tbb::parallel_for(auxiliaryLeafNodeRange, op);
5130
5131 } else {
5132
5133 volume_to_mesh_internal::LeafNodePointCount<Int16LeafNodeType::LOG2DIM>
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 {
5157 volume_to_mesh_internal::ComputePoints<InputTreeType>
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
5178 using PrimBuilder = volume_to_mesh_internal::AdaptivePrimBuilder;
5179
5180 volume_to_mesh_internal::ComputePolygons<Int16TreeType, PrimBuilder>
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
5194 volume_to_mesh_internal::ComputePolygons<Int16TreeType, PrimBuilder>
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) {
5217 volume_to_mesh_internal::subdivideNonplanarSeamLineQuads(
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,
5242 bool relaxDisorientedTriangles)
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
5309 volumeToMesh(
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,
5316 bool relaxDisorientedTriangles)
5317 {
5318 doVolumeToMesh(grid, points, triangles, quads, isovalue, adaptivity, relaxDisorientedTriangles);
5319 }
5320
5321
5322 template<typename GridType>
5323 inline void
5324 volumeToMesh(
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/ )
openvdb::v4_0_2::tools::volume_to_mesh_internal::unpackPoint
Vec3d unpackPoint(uint32_t data)
Utility methods for point quantization.
Definition: VolumeToMesh.h:606
openvdb::v4_0_2::math::Mat3::transpose
Mat3 transpose() const
returns transpose of this
Definition: Mat3.h:508
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets::internalNeighborsX
const IndexVector & internalNeighborsX() const
Return voxel offsets with internal neighbours in x + 1.
Definition: VolumeToMesh.h:2929
openvdb::v4_0_2::math::Coord::offsetBy
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition: Coord.h:115
openvdb::v4_0_2::GridBase::ConstPtr
SharedPtr< const GridBase > ConstPtr
Definition: Grid.h:108
openvdb::v4_0_2::tools::POLYFLAG_FRACTURE_SEAM
Definition: VolumeToMesh.h:118
openvdb::v4_0_2::tools::volume_to_mesh_internal::IdentifyIntersectingVoxels::join
void join(const IdentifyIntersectingVoxels &rhs)
Definition: VolumeToMesh.h:3258
openvdb::v4_0_2::tools::volume_to_mesh_internal::VoxelEdgeAccessor::set
void set(Coord ijk)
Definition: VolumeToMesh.h:3094
openvdb::v4_0_2::tools::volume_to_mesh_internal::AdaptivePrimBuilder::init
void init(const size_t upperBound, PolygonPool &polygonPool)
Definition: VolumeToMesh.h:2444
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskIntersectingVoxels::InputLeafNodeType
typename InputTreeType::LeafNodeType InputLeafNodeType
Definition: VolumeToMesh.h:3374
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskTileBorders::InputValueType
typename InputTreeType::ValueType InputValueType
Definition: VolumeToMesh.h:2661
openvdb::v4_0_2::tools::PointIndexLeafNode::cbeginValueOn
ValueOnCIter cbeginValueOn() const
Definition: PointIndexGrid.h:1636
openvdb::v4_0_2::tools::volume_to_mesh_internal::SubdivideQuads
Definition: VolumeToMesh.h:4259
openvdb::v4_0_2::tree::TreeBase::ConstPtr
SharedPtr< const TreeBase > ConstPtr
Definition: Tree.h:68
openvdb::v4_0_2::tools::volume_to_mesh_internal::IdentifyIntersectingVoxels::InputLeafNodeType
typename InputTreeType::LeafNodeType InputLeafNodeType
Definition: VolumeToMesh.h:3245
openvdb::v4_0_2::tools::PolygonPoolList
boost::scoped_array< PolygonPool > PolygonPoolList
Point and primitive list types.
Definition: VolumeToMesh.h:181
openvdb::v4_0_2::tools::volume_to_mesh_internal::sEdgeGroupTable
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::v4_0_2::util::INVALID_IDX
OPENVDB_API const Index32 INVALID_IDX
openvdb::v4_0_2::tools::volume_to_mesh_internal::MapPoints::MapPoints
MapPoints(const std::vector< PointIndexLeafNode *> &pointIndexNodes, const std::vector< Int16LeafNodeType *> &signDataNodes, boost::scoped_array< Index32 > &leafNodeCount)
Definition: VolumeToMesh.h:4004
openvdb::v4_0_2::tools::volume_to_mesh_internal::sAdaptable
const bool sAdaptable[256]
Used to quickly determine if a given cell is adaptable.
Definition: VolumeToMesh.h:430
openvdb::v4_0_2::tools::volume_to_mesh_internal::collectCornerValues
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::setSpatialAdaptivity
void setSpatialAdaptivity(const FloatGridType &grid)
Definition: VolumeToMesh.h:2133
openvdb::v4_0_2::math::Vec4
Definition: Mat4.h:51
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskSurface::MaskSurface
MaskSurface(const std::vector< BoolLeafNodeType *> &nodes, const BoolTreeType &mask, const math::Transform &inputTransform, const math::Transform &maskTransform, bool invert)
Definition: VolumeToMesh.h:3601
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskIntersectingVoxels::join
void join(const MaskIntersectingVoxels &rhs)
Definition: VolumeToMesh.h:3388
openvdb::v4_0_2::tools::POLYFLAG_EXTERIOR
Definition: VolumeToMesh.h:118
openvdb::v4_0_2::tools::volume_to_mesh_internal::SyncMaskValues::BoolLeafNodeType
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: VolumeToMesh.h:3556
openvdb::v4_0_2::Grid::tree
TreeType & tree()
Return a reference to this grid&#39;s tree, which might be shared with other grids.
Definition: Grid.h:797
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::setAdaptivityMask
void setAdaptivityMask(const BoolTreeType &mask)
Definition: VolumeToMesh.h:2139
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputeAuxiliaryData
Definition: VolumeToMesh.h:3742
openvdb::v4_0_2::tools::volume_to_mesh_internal::mergeVoxels
void mergeVoxels(LeafType &leaf, const Coord &start, int dim, int regionId)
Definition: VolumeToMesh.h:947
openvdb::v4_0_2::tools::volume_to_mesh_internal::fillArray
void fillArray(ValueType *array, const ValueType &val, const size_t length)
Definition: VolumeToMesh.h:415
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodePointCount
Definition: VolumeToMesh.h:3915
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePoints::operator()
void operator()(const tbb::blocked_range< size_t > &) const
Definition: VolumeToMesh.h:1561
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::setRefSignFlagsData
void setRefSignFlagsData(const Int16TreeType &signFlagsData, float internalAdaptivity)
Definition: VolumeToMesh.h:2144
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePolygons::operator()
void operator()(const tbb::blocked_range< size_t > &) const
Definition: VolumeToMesh.h:4089
openvdb::v4_0_2::tools::volume_to_mesh_internal::SeamLineWeights
Definition: VolumeToMesh.h:1764
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::MergeVoxelRegions
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets::minX
const IndexVector & minX() const
Return front face voxel offsets.
Definition: VolumeToMesh.h:2908
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskDisorientedTrianglePoints::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:4533
openvdb::v4_0_2::tools::PolygonPool::triangle
const openvdb::Vec3I & triangle(size_t n) const
Definition: VolumeToMesh.h:149
openvdb::v4_0_2::tools::volume_to_mesh_internal::isInsideValue
bool isInsideValue(T value, T isovalue)
Definition: VolumeToMesh.h:631
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets::core
const IndexVector & core() const
Return internal core voxel offsets.
Definition: VolumeToMesh.h:2904
openvdb::v4_0_2::tools::PolygonPool::quadFlags
char & quadFlags(size_t n)
Definition: VolumeToMesh.h:154
openvdb::v4_0_2::tools::volume_to_mesh_internal::VoxelEdgeAccessor::VoxelEdgeAccessor
VoxelEdgeAccessor(AccessorT &_acc)
Definition: VolumeToMesh.h:3092
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskTileBorders
Definition: VolumeToMesh.h:2659
openvdb::v4_0_2::math::Vec3::dot
T dot(const Vec3< T > &v) const
Dot product.
Definition: Vec3.h:215
openvdb::v4_0_2::tools::volume_to_mesh_internal::MASK_FIRST_10_BITS
Definition: VolumeToMesh.h:584
openvdb::v4_0_2::tools::volume_to_mesh_internal::SeamLineWeights::Int16TreeType
typename InputTreeType::template ValueConverter< Int16 >::Type Int16TreeType
Definition: VolumeToMesh.h:1769
openvdb::v4_0_2::tools::volume_to_mesh_internal::SetSeamLineFlags
Definition: VolumeToMesh.h:1881
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets::minZ
const IndexVector & minZ() const
Return left face voxel offsets.
Definition: VolumeToMesh.h:2922
openvdb::v4_0_2::tools::volume_to_mesh_internal::SyncMaskValues
Definition: VolumeToMesh.h:3554
openvdb::v4_0_2::tools::VolumeToMesh::pointListSize
const size_t & pointListSize() const
Definition: VolumeToMesh.h:4845
openvdb::v4_0_2::tools::volume_to_mesh_internal::isBoolValue< bool >
bool isBoolValue< bool >()
Definition: VolumeToMesh.h:626
openvdb::v4_0_2::math::Transform::worldToIndexCellCentered
Coord worldToIndexCellCentered(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:138
openvdb::v4_0_2::math::Vec3::z
T & z()
Definition: Vec3.h:111
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputeAuxiliaryData::ComputeAuxiliaryData
ComputeAuxiliaryData(const InputTreeType &inputTree, const std::vector< const BoolLeafNodeType *> &intersectionLeafNodes, Int16TreeType &signFlagsTree, Index32TreeType &pointIndexTree, InputValueType iso)
Definition: VolumeToMesh.h:3780
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:101
openvdb::v4_0_2::math::Mat3d
Mat3< double > Mat3d
Definition: Mat3.h:708
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputeAuxiliaryData::BoolLeafNodeType
tree::LeafNode< bool, InputLeafNodeType::LOG2DIM > BoolLeafNodeType
Definition: VolumeToMesh.h:3747
openvdb::v4_0_2::Index32
uint32_t Index32
Definition: Types.h:55
openvdb::v4_0_2::tools::volume_to_mesh_internal::TransferSeamLineFlags::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:1945
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePoints::InputLeafNodeType
typename InputTreeType::LeafNodeType InputLeafNodeType
Definition: VolumeToMesh.h:1477
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskBorderVoxels::join
void join(MaskBorderVoxels &rhs)
Definition: VolumeToMesh.h:3493
openvdb::v4_0_2::tools::volume_to_mesh_internal::CopyArray::operator()
void operator()(const tbb::blocked_range< size_t > &inputArrayRange) const
Definition: VolumeToMesh.h:4185
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskTileBorders::MaskTileBorders
MaskTileBorders(const InputTreeType &inputTree, InputValueType iso, BoolTreeType &mask, const Vec4i *tileArray)
Definition: VolumeToMesh.h:2665
openvdb::v4_0_2::tools::VolumeToMesh::setRefGrid
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::evalInternalVoxelEdges
void evalInternalVoxelEdges(VoxelEdgeAcc &edgeAcc, const LeafNode &leafnode, const LeafNodeVoxelOffsets &voxels, const typename LeafNode::ValueType iso)
Definition: VolumeToMesh.h:3129
openvdb::v4_0_2::tools::VolumeToMesh::pointList
PointList & pointList()
Definition: VolumeToMesh.h:4838
i
tbb::atomic< Index32 > i
Definition: LeafBuffer.h:71
openvdb::v4_0_2::tools::volume_to_mesh_internal::IdentifyIntersectingVoxels::BoolTreeType
typename InputTreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: VolumeToMesh.h:3248
openvdb::v4_0_2::tools::volume_to_mesh_internal::isPlanarQuad
bool isPlanarQuad(const Vec3d &p0, const Vec3d &p1, const Vec3d &p2, const Vec3d &p3, double epsilon=0.001)
Definition: VolumeToMesh.h:548
openvdb::v4_0_2::tools::volume_to_mesh_internal::SeamLineWeights::InputValueType
typename InputLeafNodeType::ValueType InputValueType
Definition: VolumeToMesh.h:1767
openvdb::v4_0_2::tools::volume_to_mesh_internal::SyncMaskValues::SyncMaskValues
SyncMaskValues(const std::vector< BoolLeafNodeType *> &nodes, const BoolTreeType &mask)
Definition: VolumeToMesh.h:3558
openvdb::v4_0_2::tools::volume_to_mesh_internal::identifySurfaceIntersectingVoxels
void identifySurfaceIntersectingVoxels(typename InputTreeType::template ValueConverter< bool >::Type &intersectionTree, const InputTreeType &inputTree, typename InputTreeType::ValueType isovalue)
Definition: VolumeToMesh.h:3349
openvdb::v4_0_2::tools::PolygonPool::resetTriangles
void resetTriangles(size_t size)
Definition: VolumeToMesh.h:4735
openvdb::v4_0_2::math::Mat3< double >
openvdb::v4_0_2::tools::volume_to_mesh_internal::FillArray
Definition: VolumeToMesh.h:397
openvdb::v4_0_2::math::CoordBBox
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:261
data
T * data
Definition: LeafBuffer.h:71
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePolygons::ComputePolygons
ComputePolygons(const std::vector< Int16LeafNodeType *> &signFlagsLeafNodes, const Int16TreeType &signFlagsTree, const Index32TreeType &idxTree, PolygonPoolList &polygons, bool invertSurfaceOrientation)
Definition: VolumeToMesh.h:4072
openvdb::v4_0_2::tools::volume_to_mesh_internal::UniformPrimBuilder
Definition: VolumeToMesh.h:2401
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskSeamLineVoxels::operator()
void operator()(const tbb::blocked_range< size_t > &range)
Definition: VolumeToMesh.h:2003
openvdb::v4_0_2::tools::volume_to_mesh_internal::SeamLineWeights::InputLeafNodeType
typename InputTreeType::LeafNodeType InputLeafNodeType
Definition: VolumeToMesh.h:1766
openvdb::v4_0_2::tree::ValueAccessor::addLeaf
void addLeaf(LeafNodeT *leaf)
Add the specified leaf to this tree, possibly creating a child branch in the process. If the leaf node already exists, replace it.
Definition: ValueAccessor.h:374
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets
Definition: VolumeToMesh.h:2896
openvdb::v4_0_2::math::CoordBBox::expand
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition: Coord.h:419
openvdb::v4_0_2::tools::volume_to_mesh_internal::AdaptivePrimBuilder::AdaptivePrimBuilder
AdaptivePrimBuilder()
Definition: VolumeToMesh.h:2442
openvdb::v4_0_2::tree::ValueAccessor::probeConstLeaf
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets::internalNeighborsZ
const IndexVector & internalNeighborsZ() const
Return voxel offsets with internal neighbours in z + 1.
Definition: VolumeToMesh.h:2935
openvdb::v4_0_2::tools::VolumeToMesh::polygonPoolListSize
const size_t & polygonPoolListSize() const
Definition: VolumeToMesh.h:4866
openvdb::v4_0_2::tools::PolygonPool::clearTriangles
void clearTriangles()
Definition: VolumeToMesh.h:4744
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskSeamLineVoxels::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: VolumeToMesh.h:1980
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskSurface::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:3611
openvdb::v4_0_2::tools::volume_to_mesh_internal::computeWeightedPoint
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskIntersectingVoxels::InputValueType
typename InputLeafNodeType::ValueType InputValueType
Definition: VolumeToMesh.h:3375
openvdb::v4_0_2::tools::PolygonPool::triangleFlags
const char & triangleFlags(size_t n) const
Definition: VolumeToMesh.h:158
openvdb::v4_0_2::tools::volume_to_mesh_internal::reviseSeamLineFlags
void reviseSeamLineFlags(PolygonPoolList &polygonPoolList, size_t polygonPoolListSize, std::vector< uint8_t > &pointFlags)
Definition: VolumeToMesh.h:4507
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePolygons::Index32LeafNodeType
typename Index32TreeType::LeafNodeType Index32LeafNodeType
Definition: VolumeToMesh.h:4047
openvdb::v4_0_2::tools::volume_to_mesh_internal::PointListCopy
Definition: VolumeToMesh.h:2871
openvdb::v4_0_2::tools::VolumeToMesh::VolumeToMesh
VolumeToMesh(double isovalue=0, double adaptivity=0, bool relaxDisorientedTriangles=true)
Definition: VolumeToMesh.h:4814
openvdb::v4_0_2::tools::volume_to_mesh_internal::constructPolygons
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::EDGES
Definition: VolumeToMesh.h:425
openvdb::v4_0_2::tools::PolygonPool
Collection of quads and triangles.
Definition: VolumeToMesh.h:122
openvdb::v4_0_2::math::Vec3i
Vec3< int32_t > Vec3i
Definition: Vec3.h:675
openvdb::v4_0_2::Index
Index32 Index
Definition: Types.h:57
openvdb::v4_0_2::tools::volume_to_mesh_internal::collectCornerValues
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
openvdb::v4_0_2::math::Vec3
Definition: Mat.h:195
openvdb::v4_0_2::tree::LeafNode::cbeginValueOn
ValueOnCIter cbeginValueOn() const
Definition: LeafNode.h:317
openvdb::v4_0_2::math::Vec3s
Vec3< float > Vec3s
Definition: Vec3.h:677
openvdb::v4_0_2::tools::volume_to_mesh_internal::IdentifyIntersectingVoxels::IdentifyIntersectingVoxels
IdentifyIntersectingVoxels(const InputTreeType &inputTree, const std::vector< const InputLeafNodeType *> &inputLeafNodes, BoolTreeType &intersectionTree, InputValueType iso)
Definition: VolumeToMesh.h:3277
openvdb::v4_0_2::tree::ValueAccessor::touchLeaf
LeafNodeT * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, create one, but preserve the values and active states of all voxels.
Definition: ValueAccessor.h:393
openvdb::v4_0_2::tree::LeafNode::getValue
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:1084
openvdb::v4_0_2::tools::volume_to_mesh_internal::INSIDE
Definition: VolumeToMesh.h:425
openvdb::v4_0_2::tools::volume_to_mesh_internal::MASK_DIRTY_BIT
Definition: VolumeToMesh.h:585
openvdb::v4_0_2::tools::volume_to_mesh_internal::TransferSeamLineFlags::SignDataLeafNodeType
typename SignDataTreeType::LeafNodeType SignDataLeafNodeType
Definition: VolumeToMesh.h:1936
openvdb::v4_0_2::tools::volume_to_mesh_internal::FlagAndCountQuadsToSubdivide::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:4213
openvdb::v4_0_2::tree::ValueAccessor::setValue
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::CopyArray
Definition: VolumeToMesh.h:4178
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets::IndexVector
std::vector< Index > IndexVector
Definition: VolumeToMesh.h:2898
openvdb::v4_0_2::tree::ValueAccessor::getValueDepth
int getValueDepth(const Coord &xyz) const
Definition: ValueAccessor.h:275
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::operator()
void operator()(const tbb::blocked_range< size_t > &) const
Definition: VolumeToMesh.h:2199
openvdb::v4_0_2::tools::volume_to_mesh_internal::SeamLineWeights::Int16LeafNodeType
typename Int16TreeType::LeafNodeType Int16LeafNodeType
Definition: VolumeToMesh.h:1770
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets::maxY
const IndexVector & maxY() const
Return top face voxel offsets.
Definition: VolumeToMesh.h:2918
openvdb::v4_0_2::tools::VolumeToMesh::operator()
void operator()(const InputGridType &)
Main call.
Definition: VolumeToMesh.h:4924
openvdb::v4_0_2::tools::volume_to_mesh_internal::SeamLineWeights::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:1790
openvdb::v4_0_2::tools::volume_to_mesh_internal::UniformPrimBuilder::init
void init(const size_t upperBound, PolygonPool &quadPool)
Definition: VolumeToMesh.h:2405
openvdb::v4_0_2::tools::volume_to_mesh_internal::TransferSeamLineFlags::TransferSeamLineFlags
TransferSeamLineFlags(const std::vector< SignDataLeafNodeType *> &signFlagsLeafNodes, const BoolTreeType &maskTree)
Definition: VolumeToMesh.h:1938
openvdb::v4_0_2::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets::internalNeighborsY
const IndexVector & internalNeighborsY() const
Return voxel offsets with internal neighbours in y + 1.
Definition: VolumeToMesh.h:2932
openvdb::v4_0_2::tools::volume_to_mesh_internal::MapPoints::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:4013
openvdb::v4_0_2::tools::findFeaturePoint
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
openvdb::v4_0_2::tools::PolygonPool::triangleFlags
char & triangleFlags(size_t n)
Definition: VolumeToMesh.h:157
openvdb::v4_0_2::tools::volume_to_mesh_internal::computeAuxiliaryData
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::v4_0_2::tools::PolygonPool::triangle
openvdb::Vec3I & triangle(size_t n)
Definition: VolumeToMesh.h:148
openvdb::v4_0_2::tools::composite::min
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
openvdb::v4_0_2::tools::PointIndexLeafNode::ValueOnCIter
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointIndexLeafNode, const ValueType, ValueOn > ValueOnCIter
Definition: PointIndexGrid.h:1613
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskSeamLineVoxels::MaskSeamLineVoxels
MaskSeamLineVoxels(MaskSeamLineVoxels &rhs, tbb::split)
Definition: VolumeToMesh.h:1993
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskBorderVoxels::MaskBorderVoxels
MaskBorderVoxels(const BoolTreeType &maskTree, const std::vector< BoolLeafNodeType *> &maskNodes, BoolTreeType &borderTree)
Definition: VolumeToMesh.h:3475
openvdb::v4_0_2::tree::LeafNode
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:61
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskTileBorders::join
void join(MaskTileBorders &rhs)
Definition: VolumeToMesh.h:2684
openvdb::v4_0_2::math::Transform
Calculate an axis-aligned bounding box in index space from a bounding sphere in world space...
Definition: Transform.h:66
openvdb::v4_0_2::tools::PointIndexLeafNode::beginValueOn
ValueOnCIter beginValueOn() const
Definition: PointIndexGrid.h:1637
openvdb::v4_0_2::tools::volume_to_mesh_internal::isBoolValue
bool isBoolValue()
Definition: VolumeToMesh.h:623
openvdb::v4_0_2::tools::volume_to_mesh_internal::MASK_INVALID_BIT
Definition: VolumeToMesh.h:586
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskSeamLineVoxels::BoolTreeType
typename TreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: VolumeToMesh.h:1981
openvdb::v4_0_2::tools::volume_to_mesh_internal::SubdivideQuads::SubdivideQuads
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::SyncMaskValues::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:3564
openvdb::v4_0_2::tools::volume_to_mesh_internal::markSeamLineData
void markSeamLineData(SignDataTreeType &signFlagsTree, const SignDataTreeType &refSignFlagsTree)
Definition: VolumeToMesh.h:2076
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskSeamLineVoxels::MaskSeamLineVoxels
MaskSeamLineVoxels(const std::vector< LeafNodeType *> &signFlagsLeafNodes, const TreeType &signFlagsTree, BoolTreeType &mask)
Definition: VolumeToMesh.h:1983
openvdb::v4_0_2::tools::volume_to_mesh_internal::ReviseSeamLineFlags::ReviseSeamLineFlags
ReviseSeamLineFlags(PolygonPoolList &polygons, const std::vector< uint8_t > &pointFlags)
Definition: VolumeToMesh.h:4448
openvdb::v4_0_2::tools::POLYFLAG_SUBDIVIDED
Definition: VolumeToMesh.h:118
openvdb::v4_0_2::tools::volume_to_mesh_internal::AdaptivePrimBuilder
Definition: VolumeToMesh.h:2440
openvdb::v4_0_2::math::Vec4i
Vec4< int32_t > Vec4i
Definition: Vec4.h:585
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
Definition: version.h:43
openvdb::v4_0_2::tree::LeafNode::origin
const Coord & origin() const
Return the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:198
openvdb::v4_0_2::tools::volume_to_mesh_internal::CopyArray::CopyArray
CopyArray(T *outputArray, const T *inputArray, size_t outputOffset=0)
Definition: VolumeToMesh.h:4180
openvdb::v4_0_2::tools::PolygonPool::numQuads
const size_t & numQuads() const
Definition: VolumeToMesh.h:140
openvdb::v4_0_2::tools::volume_to_mesh_internal::MapPoints
Definition: VolumeToMesh.h:4000
openvdb::v4_0_2::tools::volume_to_mesh_internal::computePoint
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::FillArray::mValue
const ValueType mValue
Definition: VolumeToMesh.h:409
openvdb::v4_0_2::Int16
int16_t Int16
Definition: Types.h:58
openvdb::v4_0_2::tools::volume_to_mesh_internal::maskActiveTileBorders
void maskActiveTileBorders(const InputTreeType &inputTree, typename InputTreeType::ValueType iso, typename InputTreeType::template ValueConverter< bool >::Type &mask)
Definition: VolumeToMesh.h:2832
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePoints::Int16LeafNodeType
typename Int16TreeType::LeafNodeType Int16LeafNodeType
Definition: VolumeToMesh.h:1481
openvdb::v4_0_2::tools::VolumeToMesh::setSpatialAdaptivity
void setSpatialAdaptivity(const GridBase::ConstPtr &grid)
Definition: VolumeToMesh.h:4895
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputeAuxiliaryData::Index32TreeType
typename InputTreeType::template ValueConverter< Index32 >::Type Index32TreeType
Definition: VolumeToMesh.h:3750
openvdb::v4_0_2::tools::PointIndexLeafNode
Definition: PointIndexGrid.h:79
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodePointCount::LeafNodePointCount
LeafNodePointCount(const std::vector< Int16LeafNodeType *> &leafNodes, boost::scoped_array< Index32 > &leafNodeCount)
Definition: VolumeToMesh.h:3919
openvdb::v4_0_2::tools::PolygonPool::resetQuads
void resetQuads(size_t size)
Definition: VolumeToMesh.h:4717
openvdb::v4_0_2::tools::volume_to_mesh_internal::SubdivideQuads::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:4276
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::FloatTreeType
typename InputTreeType::template ValueConverter< float >::Type FloatTreeType
Definition: VolumeToMesh.h:2112
openvdb::v4_0_2::tools::volume_to_mesh_internal::TransferSeamLineFlags
Definition: VolumeToMesh.h:1931
openvdb::v4_0_2::tree::LeafNode::offsetToLocalCoord
static Coord offsetToLocalCoord(Index n)
Return the local coordinates for a linear table offset, where offset 0 has coordinates (0...
Definition: LeafNode.h:1059
openvdb::v4_0_2::tools::volume_to_mesh_internal::UniformPrimBuilder::addPrim
void addPrim(const math::Vec4< IndexType > &verts, bool reverse, char flags=0)
Definition: VolumeToMesh.h:2413
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskTileBorders::operator()
void operator()(const tbb::blocked_range< size_t > &)
Definition: VolumeToMesh.h:2699
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskIntersectingVoxels::MaskIntersectingVoxels
MaskIntersectingVoxels(const InputTreeType &inputTree, const std::vector< BoolLeafNodeType *> &nodes, BoolTreeType &intersectionTree, InputValueType iso)
Definition: VolumeToMesh.h:3404
openvdb::v4_0_2::math::diagonalizeSymmetricMatrix
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::TransferSeamLineFlags::BoolLeafNodeType
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: VolumeToMesh.h:1933
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskTileBorders::MaskTileBorders
MaskTileBorders(MaskTileBorders &rhs, tbb::split)
Definition: VolumeToMesh.h:2675
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePolygons::Index32TreeType
typename TreeType::template ValueConverter< Index32 >::Type Index32TreeType
Definition: VolumeToMesh.h:4046
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskTileBorders::BoolTreeType
typename InputTreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: VolumeToMesh.h:2662
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskSurface::BoolLeafNodeType
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: VolumeToMesh.h:3599
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePoints::Int16TreeType
typename InputTreeType::template ValueConverter< Int16 >::Type Int16TreeType
Definition: VolumeToMesh.h:1480
openvdb::v4_0_2::tools::PolygonPool::copy
void copy(const PolygonPool &rhs)
Definition: VolumeToMesh.h:4699
openvdb::v4_0_2::math::Vec3::normalize
bool normalize(T eps=T(1.0e-7))
this = normalized this
Definition: Vec3.h:376
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputeAuxiliaryData::InputLeafNodeType
typename InputTreeType::LeafNodeType InputLeafNodeType
Definition: VolumeToMesh.h:3744
openvdb
Definition: Exceptions.h:39
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodePointCount::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:3926
openvdb::v4_0_2::tools::volume_to_mesh_internal::AdaptiveLeafNodePointCount::AdaptiveLeafNodePointCount
AdaptiveLeafNodePointCount(const std::vector< PointIndexLeafNode *> &pointIndexNodes, const std::vector< Int16LeafNodeType *> &signDataNodes, boost::scoped_array< Index32 > &leafNodeCount)
Definition: VolumeToMesh.h:3955
openvdb::v4_0_2::tools::volume_to_mesh_internal::FlagAndCountQuadsToSubdivide
Definition: VolumeToMesh.h:4200
openvdb::v4_0_2::math::Coord::offset
Coord & offset(Int32 dx, Int32 dy, Int32 dz)
Definition: Coord.h:107
openvdb::v4_0_2::math::CoordBBox::max
const Coord & max() const
Definition: Coord.h:335
openvdb::v4_0_2::tools::volume_to_mesh_internal::ReviseSeamLineFlags
Definition: VolumeToMesh.h:4446
openvdb::v4_0_2::tools::volumeToMesh
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::AdaptiveLeafNodePointCount
Definition: VolumeToMesh.h:3951
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets::minY
const IndexVector & minY() const
Return bottom face voxel offsets.
Definition: VolumeToMesh.h:2915
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputeAuxiliaryData::Int16TreeType
typename InputTreeType::template ValueConverter< Int16 >::Type Int16TreeType
Definition: VolumeToMesh.h:3749
openvdb::v4_0_2::tools::volume_to_mesh_internal::XEDGE
Definition: VolumeToMesh.h:426
openvdb::v4_0_2::tools::volume_to_mesh_internal::ReviseSeamLineFlags::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:4455
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePolygons::Int16TreeType
typename TreeType::template ValueConverter< Int16 >::Type Int16TreeType
Definition: VolumeToMesh.h:4043
openvdb::v4_0_2::math::Vec3d
Vec3< double > Vec3d
Definition: Vec3.h:678
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::InputTreeType
typename InputGridType::TreeType InputTreeType
Definition: VolumeToMesh.h:2108
openvdb::v4_0_2::tools::volume_to_mesh_internal::computeCellPoints
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
openvdb::v4_0_2::tree::ValueAccessor< const InputTreeType >
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::InputLeafNodeType
typename InputTreeType::LeafNodeType InputLeafNodeType
Definition: VolumeToMesh.h:2109
openvdb::v4_0_2::math::ISGradient
Gradient operators defined in index space of various orders.
Definition: Operators.h:122
openvdb::v4_0_2::tools::VolumeToMesh::polygonPoolList
PolygonPoolList & polygonPoolList()
Definition: VolumeToMesh.h:4852
openvdb::v4_0_2::tools::volume_to_mesh_internal::computeCellPoints
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePolygons::setRefSignTree
void setRefSignTree(const Int16TreeType *r)
Definition: VolumeToMesh.h:4057
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskIntersectingVoxels::BoolLeafNodeType
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: VolumeToMesh.h:3378
Util.h
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputeAuxiliaryData::InputValueType
typename InputLeafNodeType::ValueType InputValueType
Definition: VolumeToMesh.h:3745
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePoints::InputValueType
typename InputLeafNodeType::ValueType InputValueType
Definition: VolumeToMesh.h:1478
openvdb::v4_0_2::tools::volume_to_mesh_internal::AdaptivePrimBuilder::addPrim
void addPrim(const math::Vec4< IndexType > &verts, bool reverse, char flags=0)
Definition: VolumeToMesh.h:2455
openvdb::v4_0_2::tools::PolygonPool::quad
openvdb::Vec4I & quad(size_t n)
Definition: VolumeToMesh.h:142
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePoints
Definition: VolumeToMesh.h:1475
openvdb::v4_0_2::tools::volume_to_mesh_internal::computeMaskedPoint
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
openvdb::v4_0_2::ValueError
Definition: Exceptions.h:92
openvdb::v4_0_2::tools::volume_to_mesh_internal::SeamLineWeights::SeamLineWeights
SeamLineWeights(const std::vector< Int16LeafNodeType *> &signFlagsLeafNodes, const InputTreeType &inputTree, const Index32TreeType &refPointIndexTree, const Int16TreeType &refSignFlagsTree, uint32_t *quantizedPoints, InputValueType iso)
Definition: VolumeToMesh.h:1775
openvdb::v4_0_2::tools::volume_to_mesh_internal::getCellVertexValues
void getCellVertexValues(const LeafT &leaf, const Index offset, math::Tuple< 8, typename LeafT::ValueType > &values)
Definition: VolumeToMesh.h:662
openvdb::v4_0_2::tools::volume_to_mesh_internal::evalZeroCrossing
double evalZeroCrossing(double v0, double v1, double iso)
linear interpolation.
Definition: VolumeToMesh.h:1006
openvdb::v4_0_2::tools::volume_to_mesh_internal::PointListCopy::PointListCopy
PointListCopy(const PointList &pointsIn, std::vector< Vec3s > &pointsOut)
Definition: VolumeToMesh.h:2874
openvdb::v4_0_2::tools::PolygonPool::numTriangles
const size_t & numTriangles() const
Definition: VolumeToMesh.h:146
openvdb::v4_0_2::tools::volume_to_mesh_internal::applySurfaceMask
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::SIGNS
Definition: VolumeToMesh.h:425
ValueAccessor.h
openvdb::v4_0_2::math::Transform::indexToWorld
Vec3d indexToWorld(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:135
openvdb::v4_0_2::tools::volume_to_mesh_internal::evalExtrenalVoxelEdgesInv
void evalExtrenalVoxelEdgesInv(VoxelEdgeAcc &edgeAcc, TreeAcc &acc, const LeafNode &leafnode, const LeafNodeVoxelOffsets &voxels, const typename LeafNode::ValueType iso)
Definition: VolumeToMesh.h:3207
openvdb::v4_0_2::tools::VolumeToMesh
Mesh any scalar grid that has a continuous isosurface.
Definition: VolumeToMesh.h:189
openvdb::v4_0_2::tools::volume_to_mesh_internal::YEDGE
Definition: VolumeToMesh.h:426
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::Int16TreeType
typename InputTreeType::template ValueConverter< Int16 >::Type Int16TreeType
Definition: VolumeToMesh.h:2116
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::InputValueType
typename InputLeafNodeType::ValueType InputValueType
Definition: VolumeToMesh.h:2110
openvdb::v4_0_2::tools::volume_to_mesh_internal::VoxelEdgeAccessor::acc
AccessorT & acc
Definition: VolumeToMesh.h:3090
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets::maxX
const IndexVector & maxX() const
Return back face voxel offsets.
Definition: VolumeToMesh.h:2911
openvdb::v4_0_2::tools::volume_to_mesh_internal::FillArray::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:401
openvdb::v4_0_2::tools::volumeToMesh
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets::maxZ
const IndexVector & maxZ() const
Return right face voxel offsets.
Definition: VolumeToMesh.h:2925
openvdb::v4_0_2::tools::VolumeToMesh::setSurfaceMask
void setSurfaceMask(const GridBase::ConstPtr &mask, bool invertMask=false)
Definition: VolumeToMesh.h:4887
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePolygons::Int16LeafNodeType
typename Int16TreeType::LeafNodeType Int16LeafNodeType
Definition: VolumeToMesh.h:4044
openvdb::v4_0_2::math::Coord::reset
Coord & reset(Int32 x, Int32 y, Int32 z)
Reset all three coordinates with the specified arguments.
Definition: Coord.h:93
openvdb::v4_0_2::tools::volume_to_mesh_internal::UniformPrimBuilder::done
void done()
Definition: VolumeToMesh.h:2428
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::FloatLeafNodeType
typename FloatTreeType::LeafNodeType FloatLeafNodeType
Definition: VolumeToMesh.h:2113
openvdb::v4_0_2::tools::PolygonPool::trimQuads
bool trimQuads(const size_t n, bool reallocate=false)
Definition: VolumeToMesh.h:4753
openvdb::v4_0_2::tools::volume_to_mesh_internal::isMergable
bool isMergable(LeafType &leaf, const Coord &start, int dim, typename LeafType::ValueType::value_type adaptivity)
Definition: VolumeToMesh.h:968
openvdb::v4_0_2::tools::volume_to_mesh_internal::FlagAndCountQuadsToSubdivide::FlagAndCountQuadsToSubdivide
FlagAndCountQuadsToSubdivide(PolygonPoolList &polygons, const std::vector< uint8_t > &pointFlags, boost::scoped_array< openvdb::Vec3s > &points, boost::scoped_array< unsigned > &numQuadsToDivide)
Definition: VolumeToMesh.h:4202
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskSeamLineVoxels
Definition: VolumeToMesh.h:1978
openvdb::v4_0_2::tools::volume_to_mesh_internal::FillArray::mArray
ValueType *const mArray
Definition: VolumeToMesh.h:408
openvdb::v4_0_2::tools::volume_to_mesh_internal::relaxDisorientedTriangles
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
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::Index32TreeType
typename InputTreeType::template ValueConverter< Index32 >::Type Index32TreeType
Definition: VolumeToMesh.h:2119
openvdb::v4_0_2::tools::volume_to_mesh_internal::correctCellSigns
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
openvdb::v4_0_2::tree::ValueAccessor::probeValue
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
Definition: ValueAccessor.h:266
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskBorderVoxels::operator()
void operator()(const tbb::blocked_range< size_t > &range)
Definition: VolumeToMesh.h:3495
openvdb::v4_0_2::tools::volume_to_mesh_internal::evalExtrenalVoxelEdges
void evalExtrenalVoxelEdges(VoxelEdgeAcc &edgeAcc, TreeAcc &acc, const LeafNode &lhsNode, const LeafNodeVoxelOffsets &voxels, const typename LeafNode::ValueType iso)
Definition: VolumeToMesh.h:3159
openvdb::v4_0_2::GridBase
Abstract base class for typed grids.
Definition: Grid.h:104
openvdb::v4_0_2::tools::volume_to_mesh_internal::AdaptivePrimBuilder::done
void done()
Definition: VolumeToMesh.h:2493
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskBorderVoxels::MaskBorderVoxels
MaskBorderVoxels(MaskBorderVoxels &rhs, tbb::split)
Definition: VolumeToMesh.h:3485
openvdb::v4_0_2::tools::volume_to_mesh_internal::sAmbiguousFace
const unsigned char sAmbiguousFace[256]
Contains the ambiguous face index for certain cell configuration.
Definition: VolumeToMesh.h:442
openvdb::v4_0_2::tree::ValueAccessorBase::tree
TreeType & tree() const
Return a reference to the tree associated with this accessor.
Definition: ValueAccessor.h:147
openvdb::v4_0_2::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:48
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskIntersectingVoxels::BoolTreeType
typename InputTreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: VolumeToMesh.h:3377
openvdb::v4_0_2::tools::volume_to_mesh_internal::matchEdgeGroup
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
openvdb::v4_0_2::tools::VolumeToMesh::pointFlags
std::vector< uint8_t > & pointFlags()
Definition: VolumeToMesh.h:4909
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePoints::setRefData
void setRefData(const InputTreeType &refInputTree, const Index32TreeType &refPointIndexTree, const Int16TreeType &refSignFlagsTree, const uint32_t *quantizedSeamLinePoints, uint8_t *seamLinePointsFlags)
Definition: VolumeToMesh.h:1545
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePoints::Index32TreeType
typename InputTreeType::template ValueConverter< Index32 >::Type Index32TreeType
Definition: VolumeToMesh.h:1483
openvdb::v4_0_2::tools::PointList
boost::scoped_array< openvdb::Vec3s > PointList
Point and primitive list types.
Definition: VolumeToMesh.h:180
openvdb::v4_0_2::tools::volume_to_mesh_internal::subdivideNonplanarSeamLineQuads
void subdivideNonplanarSeamLineQuads(PolygonPoolList &polygonPoolList, size_t polygonPoolListSize, PointList &pointList, size_t &pointListSize, std::vector< uint8_t > &pointFlags)
Definition: VolumeToMesh.h:4394
openvdb::v4_0_2::tools::volume_to_mesh_internal::computeSignFlags
uint8_t computeSignFlags(const math::Tuple< 8, ValueType > &values, const ValueType iso)
Definition: VolumeToMesh.h:678
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodeVoxelOffsets::constructOffsetList
void constructOffsetList()
Definition: VolumeToMesh.h:2946
openvdb::v4_0_2::tools::volume_to_mesh_internal::SeamLineWeights::Index32LeafNodeType
typename Index32TreeType::LeafNodeType Index32LeafNodeType
Definition: VolumeToMesh.h:1773
openvdb::v4_0_2::tree::ValueAccessor::getValue
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:256
openvdb::v4_0_2::TypeError
Definition: Exceptions.h:91
openvdb::v4_0_2::tools::volume_to_mesh_internal::AdaptiveLeafNodePointCount::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:3964
openvdb::v4_0_2::tools::PolygonPool::clearQuads
void clearQuads()
Definition: VolumeToMesh.h:4726
openvdb::v4_0_2::tools::volume_to_mesh_internal::VoxelEdgeAccessor
Utility method to marks all voxels that share an edge.
Definition: VolumeToMesh.h:3087
openvdb::v4_0_2::Grid
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:55
openvdb::v4_0_2::math::Tuple
Definition: Tuple.h:54
openvdb::v4_0_2::tools::volume_to_mesh_internal::IdentifyIntersectingVoxels::operator()
void operator()(const tbb::blocked_range< size_t > &)
Definition: VolumeToMesh.h:3310
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
openvdb::v4_0_2::tools::volume_to_mesh_internal::SeamLineWeights::Index32TreeType
typename InputTreeType::template ValueConverter< Index32 >::Type Index32TreeType
Definition: VolumeToMesh.h:1772
openvdb::v4_0_2::tools::volume_to_mesh_internal::SEAM
Definition: VolumeToMesh.h:426
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::BoolTreeType
typename InputTreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: VolumeToMesh.h:2122
openvdb::v4_0_2::math::CoordBBox::min
const Coord & min() const
Definition: Coord.h:334
openvdb::v4_0_2::tools::volume_to_mesh_internal::SetSeamLineFlags::SetSeamLineFlags
SetSeamLineFlags(const std::vector< LeafNodeType *> &signFlagsLeafNodes, const TreeType &refSignFlagsTree)
Definition: VolumeToMesh.h:1885
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::BoolLeafNodeType
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: VolumeToMesh.h:2123
openvdb::v4_0_2::tools::PolygonPool::quadFlags
const char & quadFlags(size_t n) const
Definition: VolumeToMesh.h:155
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions
Definition: VolumeToMesh.h:2106
openvdb::v4_0_2::tree::TreeBase
Base class for typed trees.
Definition: Tree.h:64
openvdb::v4_0_2::tools::PolygonPool::PolygonPool
PolygonPool()
Definition: VolumeToMesh.h:4675
openvdb::v4_0_2::tools::volume_to_mesh_internal::IdentifyIntersectingVoxels
Definition: VolumeToMesh.h:3243
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePolygons
Definition: VolumeToMesh.h:4041
openvdb::v4_0_2::tools::PolygonPool::quad
const openvdb::Vec4I & quad(size_t n) const
Definition: VolumeToMesh.h:143
openvdb::v4_0_2::tools::volume_to_mesh_internal::packPoint
uint32_t packPoint(const Vec3d &v)
Utility methods for point quantization.
Definition: VolumeToMesh.h:590
openvdb::v4_0_2::tree::TreeBase::Ptr
SharedPtr< TreeBase > Ptr
Definition: Tree.h:67
openvdb::v4_0_2::tools::volume_to_mesh_internal::FillArray::FillArray
FillArray(ValueType *array, const ValueType &v)
Definition: VolumeToMesh.h:399
openvdb::v4_0_2::tools::volume_to_mesh_internal::ZEDGE
Definition: VolumeToMesh.h:426
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskSurface
Definition: VolumeToMesh.h:3597
size
static constexpr size_t size
The size of a LeafBuffer when LeafBuffer::mOutOfCore is atomic.
Definition: LeafBuffer.h:85
openvdb::v4_0_2::tools::volume_to_mesh_internal::isNonManifold
bool isNonManifold(const AccessorT &accessor, const Coord &ijk, typename AccessorT::ValueType isovalue, const int dim)
Definition: VolumeToMesh.h:796
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::Int16LeafNodeType
typename Int16TreeType::LeafNodeType Int16LeafNodeType
Definition: VolumeToMesh.h:2117
openvdb::v4_0_2::GridBase::transform
math::Transform & transform()
Return a reference to this grid&#39;s transform, which might be shared with other grids.
Definition: Grid.h:347
openvdb::v4_0_2::tools::volume_to_mesh_internal::IdentifyIntersectingVoxels::InputValueType
typename InputLeafNodeType::ValueType InputValueType
Definition: VolumeToMesh.h:3246
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskSeamLineVoxels::join
void join(MaskSeamLineVoxels &rhs)
Definition: VolumeToMesh.h:2001
openvdb::v4_0_2::tools::volume_to_mesh_internal::TransferSeamLineFlags::SignDataTreeType
typename BoolTreeType::template ValueConverter< SignDataType >::Type SignDataTreeType
Definition: VolumeToMesh.h:1935
openvdb::v4_0_2::tree::ValueAccessor::isValueOn
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:263
openvdb::v4_0_2::points::pointCount
Index64 pointCount(const PointDataTreeT &tree, const bool inCoreOnly=false)
Total points in the PointDataTree.
Definition: PointCount.h:198
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputeAuxiliaryData::join
void join(const ComputeAuxiliaryData &rhs)
Definition: VolumeToMesh.h:3761
openvdb::v4_0_2::tools::PointIndexLeafNode::setValueOnly
void setValueOnly(const Coord &, const ValueType &)
Definition: PointIndexGrid.h:1533
openvdb::v4_0_2::tools::volume_to_mesh_internal::getCellVertexValues
void getCellVertexValues(const AccessorT &accessor, Coord ijk, math::Tuple< 8, typename AccessorT::ValueType > &values)
Definition: VolumeToMesh.h:639
openvdb::v4_0_2::tools::PolygonPool::trimTrinagles
bool trimTrinagles(const size_t n, bool reallocate=false)
Definition: VolumeToMesh.h:4782
openvdb::v4_0_2::GRID_LEVEL_SET
Definition: Types.h:264
openvdb::v4_0_2::tools::volume_to_mesh_internal::SetSeamLineFlags::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: VolumeToMesh.h:1883
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskBorderVoxels::BoolLeafNodeType
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: VolumeToMesh.h:3473
openvdb::v4_0_2::tree::LeafNode::DIM
static const Index DIM
Definition: LeafNode.h:74
openvdb::v4_0_2::tools::volume_to_mesh_internal::evalCellSigns
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
openvdb::v4_0_2::tree::LeafNode::ValueIter
Definition: LeafNode.h:233
openvdb::v4_0_2::tools::volume_to_mesh_internal::PointListCopy::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:2879
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePoints::Index32LeafNodeType
typename Index32TreeType::LeafNodeType Index32LeafNodeType
Definition: VolumeToMesh.h:1484
openvdb::v4_0_2::tools::PointIndexLeafNode::ValueType
T ValueType
Definition: PointIndexGrid.h:1386
openvdb::v4_0_2::tools::volume_to_mesh_internal::UniformPrimBuilder::UniformPrimBuilder
UniformPrimBuilder()
Definition: VolumeToMesh.h:2403
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskIntersectingVoxels::operator()
void operator()(const tbb::blocked_range< size_t > &)
Definition: VolumeToMesh.h:3432
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskDisorientedTrianglePoints
Definition: VolumeToMesh.h:4519
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskBorderVoxels
Definition: VolumeToMesh.h:3471
openvdb::v4_0_2::tools::volume_to_mesh_internal::isInsideValue< bool >
bool isInsideValue< bool >(bool value, bool)
Definition: VolumeToMesh.h:634
Operators.h
Platform.h
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskIntersectingVoxels
Definition: VolumeToMesh.h:3372
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputeAuxiliaryData::operator()
void operator()(const tbb::blocked_range< size_t > &)
Definition: VolumeToMesh.h:3813
openvdb::v4_0_2::tools::volume_to_mesh_internal::SetSeamLineFlags::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: VolumeToMesh.h:1892
openvdb::v4_0_2::tools::volume_to_mesh_internal::MergeVoxelRegions::Index32LeafNodeType
typename Index32TreeType::LeafNodeType Index32LeafNodeType
Definition: VolumeToMesh.h:2120
openvdb::v4_0_2::tools::volume_to_mesh_internal::MaskDisorientedTrianglePoints::MaskDisorientedTrianglePoints
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
openvdb::v4_0_2::tools::VolumeToMesh::setAdaptivityMask
void setAdaptivityMask(const TreeBase::ConstPtr &tree)
Definition: VolumeToMesh.h:4902