OpenVDB: MeshToVolume.h Source File

OpenVDB 4.0.2

MeshToVolume.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
42
43 #ifndef OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED
44 #define OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED
45
46 #include <openvdb/Platform.h> // for OPENVDB_HAS_CXX11
47 #include <openvdb/Types.h>
48 #include <openvdb/math/FiniteDifference.h> // for GodunovsNormSqrd
49 #include <openvdb/math/Proximity.h> // for closestPointOnTriangleToPoint
50 #include <openvdb/util/NullInterrupter.h>
51 #include <openvdb/util/Util.h>
52
53 #include "ChangeBackground.h"
54 #include "Prune.h" // for pruneInactive and pruneLevelSet
55 #include "SignedFloodFill.h" // for signedFloodFillWithValues
56
57 #include <tbb/blocked_range.h>
58 #include <tbb/enumerable_thread_specific.h>
59 #include <tbb/parallel_for.h>
60 #include <tbb/parallel_reduce.h>
61 #include <tbb/partitioner.h>
62 #include <tbb/task_group.h>
63 #include <tbb/task_scheduler_init.h>
64
65 #include <boost/integer_traits.hpp> // for const_max
66 #include <boost/scoped_array.hpp>
67
68 #include <algorithm> // for std::sort()
69 #include <cmath> // for std::isfinite(), std::isnan()
70 #include <deque>
71 #include <limits>
72 #include <memory>
73 #include <sstream>
74 #include <type_traits>
75 #include <vector>
76
77 namespace openvdb {
78 OPENVDB_USE_VERSION_NAMESPACE
79 namespace OPENVDB_VERSION_NAME {
80 namespace tools {
81
82
84
85
87 enum MeshToVolumeFlags {
88
93 UNSIGNED_DISTANCE_FIELD = 0x1,
94
97 DISABLE_INTERSECTING_VOXEL_REMOVAL = 0x2,
98
101 DISABLE_RENORMALIZATION = 0x4,
102
105 DISABLE_NARROW_BAND_TRIMMING = 0x8
106 };
107
108
139 template <typename GridType, typename MeshDataAdapter>
140 inline typename GridType::Ptr
141 meshToVolume(
142 const MeshDataAdapter& mesh,
143 const math::Transform& transform,
144 float exteriorBandWidth = 3.0f,
145 float interiorBandWidth = 3.0f,
146 int flags = 0,
147 typename GridType::template ValueConverter<Int32>::Type * polygonIndexGrid = nullptr);
148
149
165 template <typename GridType, typename MeshDataAdapter, typename Interrupter>
166 inline typename GridType::Ptr
167 meshToVolume(
168 Interrupter& interrupter,
169 const MeshDataAdapter& mesh,
170 const math::Transform& transform,
171 float exteriorBandWidth = 3.0f,
172 float interiorBandWidth = 3.0f,
173 int flags = 0,
174 typename GridType::template ValueConverter<Int32>::Type * polygonIndexGrid = nullptr);
175
176
178
179
190 template<typename PointType, typename PolygonType>
191 struct QuadAndTriangleDataAdapter {
192
193 QuadAndTriangleDataAdapter(const std::vector<PointType>& points,
194 const std::vector<PolygonType>& polygons)
195 : mPointArray(points.empty() ? nullptr : &points[0])
196 , mPointArraySize(points.size())
197 , mPolygonArray(polygons.empty() ? nullptr : &polygons[0])
198 , mPolygonArraySize(polygons.size())
199 {
200 }
201
202 QuadAndTriangleDataAdapter(const PointType * pointArray, size_t pointArraySize,
203 const PolygonType* polygonArray, size_t polygonArraySize)
204 : mPointArray(pointArray)
205 , mPointArraySize(pointArraySize)
206 , mPolygonArray(polygonArray)
207 , mPolygonArraySize(polygonArraySize)
208 {
209 }
210
211 size_t polygonCount() const { return mPolygonArraySize; }
212 size_t pointCount() const { return mPointArraySize; }
213
215 size_t vertexCount(size_t n) const {
216 return (PolygonType::size == 3 || mPolygonArray[n][3] == util::INVALID_IDX) ? 3 : 4;
217 }
218
221 void getIndexSpacePoint(size_t n, size_t v, Vec3d& pos) const {
222 const PointType& p = mPointArray[mPolygonArray[n][int(v)]];
223 pos[0] = double(p[0]);
224 pos[1] = double(p[1]);
225 pos[2] = double(p[2]);
226 }
227
228 private:
229 PointType const * const mPointArray;
230 size_t const mPointArraySize;
231 PolygonType const * const mPolygonArray;
232 size_t const mPolygonArraySize;
233 }; // struct QuadAndTriangleDataAdapter
234
235
237
238
239 // Convenience functions for the mesh to volume converter that wrap stl containers.
240 //
241 // Note the meshToVolume() method declared above is more flexible and better suited
242 // for arbitrary data structures.
243
244
260 template<typename GridType>
261 inline typename GridType::Ptr
262 meshToLevelSet(
263 const openvdb::math::Transform& xform,
264 const std::vector<Vec3s>& points,
265 const std::vector<Vec3I>& triangles,
266 float halfWidth = float(LEVEL_SET_HALF_WIDTH));
267
269 template<typename GridType, typename Interrupter>
270 inline typename GridType::Ptr
271 meshToLevelSet(
272 Interrupter& interrupter,
273 const openvdb::math::Transform& xform,
274 const std::vector<Vec3s>& points,
275 const std::vector<Vec3I>& triangles,
276 float halfWidth = float(LEVEL_SET_HALF_WIDTH));
277
278
294 template<typename GridType>
295 inline typename GridType::Ptr
296 meshToLevelSet(
297 const openvdb::math::Transform& xform,
298 const std::vector<Vec3s>& points,
299 const std::vector<Vec4I>& quads,
300 float halfWidth = float(LEVEL_SET_HALF_WIDTH));
301
303 template<typename GridType, typename Interrupter>
304 inline typename GridType::Ptr
305 meshToLevelSet(
306 Interrupter& interrupter,
307 const openvdb::math::Transform& xform,
308 const std::vector<Vec3s>& points,
309 const std::vector<Vec4I>& quads,
310 float halfWidth = float(LEVEL_SET_HALF_WIDTH));
311
312
329 template<typename GridType>
330 inline typename GridType::Ptr
331 meshToLevelSet(
332 const openvdb::math::Transform& xform,
333 const std::vector<Vec3s>& points,
334 const std::vector<Vec3I>& triangles,
335 const std::vector<Vec4I>& quads,
336 float halfWidth = float(LEVEL_SET_HALF_WIDTH));
337
339 template<typename GridType, typename Interrupter>
340 inline typename GridType::Ptr
341 meshToLevelSet(
342 Interrupter& interrupter,
343 const openvdb::math::Transform& xform,
344 const std::vector<Vec3s>& points,
345 const std::vector<Vec3I>& triangles,
346 const std::vector<Vec4I>& quads,
347 float halfWidth = float(LEVEL_SET_HALF_WIDTH));
348
349
368 template<typename GridType>
369 inline typename GridType::Ptr
370 meshToSignedDistanceField(
371 const openvdb::math::Transform& xform,
372 const std::vector<Vec3s>& points,
373 const std::vector<Vec3I>& triangles,
374 const std::vector<Vec4I>& quads,
375 float exBandWidth,
376 float inBandWidth);
377
379 template<typename GridType, typename Interrupter>
380 inline typename GridType::Ptr
381 meshToSignedDistanceField(
382 Interrupter& interrupter,
383 const openvdb::math::Transform& xform,
384 const std::vector<Vec3s>& points,
385 const std::vector<Vec3I>& triangles,
386 const std::vector<Vec4I>& quads,
387 float exBandWidth,
388 float inBandWidth);
389
390
405 template<typename GridType>
406 inline typename GridType::Ptr
407 meshToUnsignedDistanceField(
408 const openvdb::math::Transform& xform,
409 const std::vector<Vec3s>& points,
410 const std::vector<Vec3I>& triangles,
411 const std::vector<Vec4I>& quads,
412 float bandWidth);
413
415 template<typename GridType, typename Interrupter>
416 inline typename GridType::Ptr
417 meshToUnsignedDistanceField(
418 Interrupter& interrupter,
419 const openvdb::math::Transform& xform,
420 const std::vector<Vec3s>& points,
421 const std::vector<Vec3I>& triangles,
422 const std::vector<Vec4I>& quads,
423 float bandWidth);
424
425
427
428
435 template<typename GridType, typename VecType>
436 inline typename GridType::Ptr
437 createLevelSetBox(const math::BBox<VecType>& bbox,
438 const openvdb::math::Transform& xform,
439 typename VecType::ValueType halfWidth = LEVEL_SET_HALF_WIDTH);
440
441
443
444
451 template <typename FloatTreeT>
452 inline void
453 traceExteriorBoundaries(FloatTreeT& tree);
454
455
457
458
460 class MeshToVoxelEdgeData
461 {
462 public:
463
465
467 struct EdgeData {
468 EdgeData(float dist = 1.0)
469 : mXDist(dist), mYDist(dist), mZDist(dist)
470 , mXPrim(util::INVALID_IDX)
471 , mYPrim(util::INVALID_IDX)
472 , mZPrim(util::INVALID_IDX)
473 {
474 }
475
477 bool operator< (const EdgeData&) const { return false; }
480 bool operator> (const EdgeData&) const { return false; }
481 template<class T> EdgeData operator+(const T&) const { return *this; }
482 template<class T> EdgeData operator-(const T&) const { return *this; }
483 EdgeData operator-() const { return *this; }
485
486 bool operator==(const EdgeData& rhs) const
487 {
488 return mXPrim == rhs.mXPrim && mYPrim == rhs.mYPrim && mZPrim == rhs.mZPrim;
489 }
490
491 float mXDist, mYDist, mZDist;
492 Index32 mXPrim, mYPrim, mZPrim;
493 };
494
495 using TreeType = tree::Tree4<EdgeData, 5, 4, 3>::Type;
496 using Accessor = tree::ValueAccessor<TreeType>;
497
498
500
501
502 MeshToVoxelEdgeData();
503
504
512 void convert(const std::vector<Vec3s>& pointList, const std::vector<Vec4I>& polygonList);
513
514
517 void getEdgeData(Accessor& acc, const Coord& ijk,
518 std::vector<Vec3d>& points, std::vector<Index32>& primitives);
519
522 Accessor getAccessor() { return Accessor(mTree); }
523
524 private:
525 void operator=(const MeshToVoxelEdgeData&) {}
526 TreeType mTree;
527 class GenEdgeData;
528 };
529
530
533
534
535 // Internal utility objects and implementation details
536
537 namespace mesh_to_volume_internal {
538
539 template<typename PointType>
540 struct TransformPoints {
541
542 TransformPoints(const PointType* pointsIn, PointType* pointsOut,
543 const math::Transform& xform)
544 : mPointsIn(pointsIn), mPointsOut(pointsOut), mXform(&xform)
545 {
546 }
547
548 void operator()(const tbb::blocked_range<size_t>& range) const {
549
550 Vec3d pos;
551
552 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
553
554 const PointType& wsP = mPointsIn[n];
555 pos[0] = double(wsP[0]);
556 pos[1] = double(wsP[1]);
557 pos[2] = double(wsP[2]);
558
559 pos = mXform->worldToIndex(pos);
560
561 PointType& isP = mPointsOut[n];
562 isP[0] = typename PointType::value_type(pos[0]);
563 isP[1] = typename PointType::value_type(pos[1]);
564 isP[2] = typename PointType::value_type(pos[2]);
565 }
566 }
567
568 PointType const * const mPointsIn;
569 PointType * const mPointsOut;
570 math::Transform const * const mXform;
571 }; // TransformPoints
572
573
574 template<typename ValueType>
575 struct Tolerance
576 {
577 static ValueType epsilon() { return ValueType(1e-7); }
578 static ValueType minNarrowBandWidth() { return ValueType(1.0 + 1e-6); }
579 };
580
581
583
584
585 template<typename TreeType>
586 class CombineLeafNodes
587 {
588 public:
589
590 using Int32TreeType = typename TreeType::template ValueConverter<Int32>::Type;
591
592 using LeafNodeType = typename TreeType::LeafNodeType;
593 using Int32LeafNodeType = typename Int32TreeType::LeafNodeType;
594
595 CombineLeafNodes(TreeType& lhsDistTree, Int32TreeType& lhsIdxTree,
596 LeafNodeType ** rhsDistNodes, Int32LeafNodeType ** rhsIdxNodes)
597 : mDistTree(&lhsDistTree)
598 , mIdxTree(&lhsIdxTree)
599 , mRhsDistNodes(rhsDistNodes)
600 , mRhsIdxNodes(rhsIdxNodes)
601 {
602 }
603
604 void operator()(const tbb::blocked_range<size_t>& range) const {
605
606 tree::ValueAccessor<TreeType> distAcc(*mDistTree);
607 tree::ValueAccessor<Int32TreeType> idxAcc(*mIdxTree);
608
609 using DistValueType = typename LeafNodeType::ValueType;
610 using IndexValueType = typename Int32LeafNodeType::ValueType;
611
612 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
613
614 const Coord& origin = mRhsDistNodes[n]->origin();
615
616 LeafNodeType* lhsDistNode = distAcc.probeLeaf(origin);
617 Int32LeafNodeType* lhsIdxNode = idxAcc.probeLeaf(origin);
618
619 DistValueType* lhsDistData = lhsDistNode->buffer().data();
620 IndexValueType* lhsIdxData = lhsIdxNode->buffer().data();
621
622 const DistValueType* rhsDistData = mRhsDistNodes[n]->buffer().data();
623 const IndexValueType* rhsIdxData = mRhsIdxNodes[n]->buffer().data();
624
625
626 for (Index32 offset = 0; offset < LeafNodeType::SIZE; ++offset) {
627
628 if (rhsIdxData[offset] != Int32(util::INVALID_IDX)) {
629
630 const DistValueType& lhsValue = lhsDistData[offset];
631 const DistValueType& rhsValue = rhsDistData[offset];
632
633 if (rhsValue < lhsValue) {
634 lhsDistNode->setValueOn(offset, rhsValue);
635 lhsIdxNode->setValueOn(offset, rhsIdxData[offset]);
636 } else if (math::isExactlyEqual(rhsValue, lhsValue)) {
637 lhsIdxNode->setValueOn(offset,
638 std::min(lhsIdxData[offset], rhsIdxData[offset]));
639 }
640 }
641 }
642
643 delete mRhsDistNodes[n];
644 delete mRhsIdxNodes[n];
645 }
646 }
647
648 private:
649
650 TreeType * const mDistTree;
651 Int32TreeType * const mIdxTree;
652
653 LeafNodeType ** const mRhsDistNodes;
654 Int32LeafNodeType ** const mRhsIdxNodes;
655 }; // class CombineLeafNodes
656
657
659
660
661 template<typename TreeType>
662 struct StashOriginAndStoreOffset
663 {
664 using LeafNodeType = typename TreeType::LeafNodeType;
665
666 StashOriginAndStoreOffset(std::vector<LeafNodeType*>& nodes, Coord* coordinates)
667 : mNodes(nodes.empty() ? nullptr : &nodes[0]), mCoordinates(coordinates)
668 {
669 }
670
671 void operator()(const tbb::blocked_range<size_t>& range) const {
672 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
673 Coord& origin = const_cast<Coord&>(mNodes[n]->origin());
674 mCoordinates[n] = origin;
675 origin[0] = static_cast<int>(n);
676 }
677 }
678
679 LeafNodeType ** const mNodes;
680 Coord * const mCoordinates;
681 };
682
683
684 template<typename TreeType>
685 struct RestoreOrigin
686 {
687 using LeafNodeType = typename TreeType::LeafNodeType;
688
689 RestoreOrigin(std::vector<LeafNodeType*>& nodes, const Coord* coordinates)
690 : mNodes(nodes.empty() ? nullptr : &nodes[0]), mCoordinates(coordinates)
691 {
692 }
693
694 void operator()(const tbb::blocked_range<size_t>& range) const {
695 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
696 Coord& origin = const_cast<Coord&>(mNodes[n]->origin());
697 origin[0] = mCoordinates[n][0];
698 }
699 }
700
701 LeafNodeType ** const mNodes;
702 Coord const * const mCoordinates;
703 };
704
705
706 template<typename TreeType>
707 class ComputeNodeConnectivity
708 {
709 public:
710 using LeafNodeType = typename TreeType::LeafNodeType;
711
712 ComputeNodeConnectivity(const TreeType& tree, const Coord* coordinates,
713 size_t* offsets, size_t numNodes, const CoordBBox& bbox)
714 : mTree(&tree)
715 , mCoordinates(coordinates)
716 , mOffsets(offsets)
717 , mNumNodes(numNodes)
718 , mBBox(bbox)
719 {
720 }
721
722 ComputeNodeConnectivity(const ComputeNodeConnectivity&) = default;
723
724 // Disallow assignment
725 ComputeNodeConnectivity& operator=(const ComputeNodeConnectivity&) = delete;
726
727 void operator()(const tbb::blocked_range<size_t>& range) const {
728
729 size_t* offsetsNextX = mOffsets;
730 size_t* offsetsPrevX = mOffsets + mNumNodes;
731 size_t* offsetsNextY = mOffsets + mNumNodes * 2;
732 size_t* offsetsPrevY = mOffsets + mNumNodes * 3;
733 size_t* offsetsNextZ = mOffsets + mNumNodes * 4;
734 size_t* offsetsPrevZ = mOffsets + mNumNodes * 5;
735
736 tree::ValueAccessor<const TreeType> acc(*mTree);
737 Coord ijk;
738
739 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
740 const Coord& origin = mCoordinates[n];
741 offsetsNextX[n] = findNeighbourNode(acc, origin, Coord(LeafNodeType::DIM, 0, 0));
742 offsetsPrevX[n] = findNeighbourNode(acc, origin, Coord(-LeafNodeType::DIM, 0, 0));
743 offsetsNextY[n] = findNeighbourNode(acc, origin, Coord(0, LeafNodeType::DIM, 0));
744 offsetsPrevY[n] = findNeighbourNode(acc, origin, Coord(0, -LeafNodeType::DIM, 0));
745 offsetsNextZ[n] = findNeighbourNode(acc, origin, Coord(0, 0, LeafNodeType::DIM));
746 offsetsPrevZ[n] = findNeighbourNode(acc, origin, Coord(0, 0, -LeafNodeType::DIM));
747 }
748 }
749
750 size_t findNeighbourNode(tree::ValueAccessor<const TreeType>& acc,
751 const Coord& start, const Coord& step) const
752 {
753 Coord ijk = start + step;
754 CoordBBox bbox(mBBox);
755
756 while (bbox.isInside(ijk)) {
757 const LeafNodeType* node = acc.probeConstLeaf(ijk);
758 if (node) return static_cast<size_t>(node->origin()[0]);
759 ijk += step;
760 }
761
762 return boost::integer_traits<size_t>::const_max;
763 }
764
765
766 private:
767 TreeType const * const mTree;
768 Coord const * const mCoordinates;
769 size_t * const mOffsets;
770
771 const size_t mNumNodes;
772 const CoordBBox mBBox;
773 }; // class ComputeNodeConnectivity
774
775
776 template<typename TreeType>
777 struct LeafNodeConnectivityTable {
778
779 enum { INVALID_OFFSET = boost::integer_traits<size_t>::const_max };
780
781 using LeafNodeType = typename TreeType::LeafNodeType;
782
783 LeafNodeConnectivityTable(TreeType& tree)
784 : mLeafNodes()
785 , mOffsets(nullptr)
786 {
787 mLeafNodes.reserve(tree.leafCount());
788 tree.getNodes(mLeafNodes);
789
790 if (mLeafNodes.empty()) return;
791
792 CoordBBox bbox;
793 tree.evalLeafBoundingBox(bbox);
794
795 const tbb::blocked_range<size_t> range(0, mLeafNodes.size());
796
797 // stash the leafnode origin coordinate and temporarily store the
798 // linear offset in the origin.x variable.
799 boost::scoped_array<Coord> coordinates(new Coord[mLeafNodes.size()]);
800 tbb::parallel_for(range,
801 StashOriginAndStoreOffset<TreeType>(mLeafNodes, coordinates.get()));
802
803 // build the leafnode offset table
804 mOffsets.reset(new size_t[mLeafNodes.size() * 6]);
805
806
807 tbb::parallel_for(range, ComputeNodeConnectivity<TreeType>(
808 tree, coordinates.get(), mOffsets.get(), mLeafNodes.size(), bbox));
809
810 // restore the leafnode origin coordinate
811 tbb::parallel_for(range, RestoreOrigin<TreeType>(mLeafNodes, coordinates.get()));
812 }
813
814 size_t size() const { return mLeafNodes.size(); }
815
816 std::vector<LeafNodeType*>& nodes() { return mLeafNodes; }
817 const std::vector<LeafNodeType*>& nodes() const { return mLeafNodes; }
818
819
820 const size_t* offsetsNextX() const { return mOffsets.get(); }
821 const size_t* offsetsPrevX() const { return mOffsets.get() + mLeafNodes.size(); }
822
823 const size_t* offsetsNextY() const { return mOffsets.get() + mLeafNodes.size() * 2; }
824 const size_t* offsetsPrevY() const { return mOffsets.get() + mLeafNodes.size() * 3; }
825
826 const size_t* offsetsNextZ() const { return mOffsets.get() + mLeafNodes.size() * 4; }
827 const size_t* offsetsPrevZ() const { return mOffsets.get() + mLeafNodes.size() * 5; }
828
829 private:
830 std::vector<LeafNodeType*> mLeafNodes;
831 boost::scoped_array<size_t> mOffsets;
832 }; // struct LeafNodeConnectivityTable
833
834
835 template<typename TreeType>
836 class SweepExteriorSign
837 {
838 public:
839
840 enum Axis { X_AXIS = 0, Y_AXIS = 1, Z_AXIS = 2 };
841
842 using ValueType = typename TreeType::ValueType;
843 using LeafNodeType = typename TreeType::LeafNodeType;
844 using ConnectivityTable = LeafNodeConnectivityTable<TreeType>;
845
846 SweepExteriorSign(Axis axis, const std::vector<size_t>& startNodeIndices,
847 ConnectivityTable& connectivity)
848 : mStartNodeIndices(startNodeIndices.empty() ? nullptr : &startNodeIndices[0])
849 , mConnectivity(&connectivity)
850 , mAxis(axis)
851 {
852 }
853
854 void operator()(const tbb::blocked_range<size_t>& range) const {
855
856 std::vector<LeafNodeType*>& nodes = mConnectivity->nodes();
857
858 // Z Axis
859 size_t idxA = 0, idxB = 1;
860 Index step = 1;
861
862 const size_t* nextOffsets = mConnectivity->offsetsNextZ();
863 const size_t* prevOffsets = mConnectivity->offsetsPrevZ();
864
865 if (mAxis == Y_AXIS) {
866
867 idxA = 0;
868 idxB = 2;
869 step = LeafNodeType::DIM;
870
871 nextOffsets = mConnectivity->offsetsNextY();
872 prevOffsets = mConnectivity->offsetsPrevY();
873
874 } else if (mAxis == X_AXIS) {
875
876 idxA = 1;
877 idxB = 2;
878 step = LeafNodeType::DIM * LeafNodeType::DIM;
879
880 nextOffsets = mConnectivity->offsetsNextX();
881 prevOffsets = mConnectivity->offsetsPrevX();
882 }
883
884 Coord ijk(0, 0, 0);
885
886 int& a = ijk[idxA];
887 int& b = ijk[idxB];
888
889 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
890
891 size_t startOffset = mStartNodeIndices[n];
892 size_t lastOffset = startOffset;
893
894 Index pos(0);
895
896 for (a = 0; a < int(LeafNodeType::DIM); ++a) {
897 for (b = 0; b < int(LeafNodeType::DIM); ++b) {
898
899 pos = LeafNodeType::coordToOffset(ijk);
900 size_t offset = startOffset;
901
902 // sweep in +axis direction until a boundary voxel is hit.
903 while ( offset != ConnectivityTable::INVALID_OFFSET &&
904 traceVoxelLine(*nodes[offset], pos, step) ) {
905
906 lastOffset = offset;
907 offset = nextOffsets[offset];
908 }
909
910 // find last leafnode in +axis direction
911 offset = lastOffset;
912 while (offset != ConnectivityTable::INVALID_OFFSET) {
913 lastOffset = offset;
914 offset = nextOffsets[offset];
915 }
916
917 // sweep in -axis direction until a boundary voxel is hit.
918 offset = lastOffset;
919 pos += step * (LeafNodeType::DIM - 1);
920 while ( offset != ConnectivityTable::INVALID_OFFSET &&
921 traceVoxelLine(*nodes[offset], pos, -step)) {
922 offset = prevOffsets[offset];
923 }
924 }
925 }
926 }
927 }
928
929
930 bool traceVoxelLine(LeafNodeType& node, Index pos, Index step) const {
931
932 ValueType* data = node.buffer().data();
933
934 bool isOutside = true;
935
936 for (Index i = 0; i < LeafNodeType::DIM; ++i) {
937
938 ValueType& dist = data[pos];
939
940 if (dist < ValueType(0.0)) {
941 isOutside = true;
942 } else {
943 // Boundary voxel check. (Voxel that intersects the surface)
944 if (!(dist > ValueType(0.75))) isOutside = false;
945
946 if (isOutside) dist = ValueType(-dist);
947 }
948
949 pos += step;
950 }
951
952 return isOutside;
953 }
954
955
956 private:
957 size_t const * const mStartNodeIndices;
958 ConnectivityTable * const mConnectivity;
959
960 const Axis mAxis;
961 }; // class SweepExteriorSign
962
963
964 template<typename LeafNodeType>
965 inline void
966 seedFill(LeafNodeType& node)
967 {
968 using ValueType = typename LeafNodeType::ValueType;
969 using Queue = std::deque<Index>;
970
971
972 ValueType* data = node.buffer().data();
973
974 // find seed points
975 Queue seedPoints;
976 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
977 if (data[pos] < 0.0) seedPoints.push_back(pos);
978 }
979
980 if (seedPoints.empty()) return;
981
982 // clear sign information
983 for (Queue::iterator it = seedPoints.begin(); it != seedPoints.end(); ++it) {
984 ValueType& dist = data[*it];
985 dist = -dist;
986 }
987
988 // flood fill
989
990 Coord ijk(0, 0, 0);
991 Index pos(0), nextPos(0);
992
993 while (!seedPoints.empty()) {
994
995 pos = seedPoints.back();
996 seedPoints.pop_back();
997
998 ValueType& dist = data[pos];
999
1000 if (!(dist < ValueType(0.0))) {
1001
1002 dist = -dist; // flip sign
1003
1004 ijk = LeafNodeType::offsetToLocalCoord(pos);
1005
1006 if (ijk[0] != 0) { // i - 1, j, k
1007 nextPos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
1008 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1009 }
1010
1011 if (ijk[0] != (LeafNodeType::DIM - 1)) { // i + 1, j, k
1012 nextPos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
1013 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1014 }
1015
1016 if (ijk[1] != 0) { // i, j - 1, k
1017 nextPos = pos - LeafNodeType::DIM;
1018 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1019 }
1020
1021 if (ijk[1] != (LeafNodeType::DIM - 1)) { // i, j + 1, k
1022 nextPos = pos + LeafNodeType::DIM;
1023 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1024 }
1025
1026 if (ijk[2] != 0) { // i, j, k - 1
1027 nextPos = pos - 1;
1028 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1029 }
1030
1031 if (ijk[2] != (LeafNodeType::DIM - 1)) { // i, j, k + 1
1032 nextPos = pos + 1;
1033 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1034 }
1035 }
1036 }
1037 } // seedFill()
1038
1039
1040 template<typename LeafNodeType>
1041 inline bool
1042 scanFill(LeafNodeType& node)
1043 {
1044 bool updatedNode = false;
1045
1046 using ValueType = typename LeafNodeType::ValueType;
1047 ValueType* data = node.buffer().data();
1048
1049 Coord ijk(0, 0, 0);
1050
1051 bool updatedSign = true;
1052 while (updatedSign) {
1053
1054 updatedSign = false;
1055
1056 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
1057
1058 ValueType& dist = data[pos];
1059
1060 if (!(dist < ValueType(0.0)) && dist > ValueType(0.75)) {
1061
1062 ijk = LeafNodeType::offsetToLocalCoord(pos);
1063
1064 // i, j, k - 1
1065 if (ijk[2] != 0 && data[pos - 1] < ValueType(0.0)) {
1066 updatedSign = true;
1067 dist = ValueType(-dist);
1068
1069 // i, j, k + 1
1070 } else if (ijk[2] != (LeafNodeType::DIM - 1) && data[pos + 1] < ValueType(0.0)) {
1071 updatedSign = true;
1072 dist = ValueType(-dist);
1073
1074 // i, j - 1, k
1075 } else if (ijk[1] != 0 && data[pos - LeafNodeType::DIM] < ValueType(0.0)) {
1076 updatedSign = true;
1077 dist = ValueType(-dist);
1078
1079 // i, j + 1, k
1080 } else if (ijk[1] != (LeafNodeType::DIM - 1)
1081 && data[pos + LeafNodeType::DIM] < ValueType(0.0))
1082 {
1083 updatedSign = true;
1084 dist = ValueType(-dist);
1085
1086 // i - 1, j, k
1087 } else if (ijk[0] != 0
1088 && data[pos - LeafNodeType::DIM * LeafNodeType::DIM] < ValueType(0.0))
1089 {
1090 updatedSign = true;
1091 dist = ValueType(-dist);
1092
1093 // i + 1, j, k
1094 } else if (ijk[0] != (LeafNodeType::DIM - 1)
1095 && data[pos + LeafNodeType::DIM * LeafNodeType::DIM] < ValueType(0.0))
1096 {
1097 updatedSign = true;
1098 dist = ValueType(-dist);
1099 }
1100 }
1101 } // end value loop
1102
1103 updatedNode |= updatedSign;
1104 } // end update loop
1105
1106 return updatedNode;
1107 } // scanFill()
1108
1109
1110 template<typename TreeType>
1111 class SeedFillExteriorSign
1112 {
1113 public:
1114 using ValueType = typename TreeType::ValueType;
1115 using LeafNodeType = typename TreeType::LeafNodeType;
1116
1117 SeedFillExteriorSign(std::vector<LeafNodeType*>& nodes, bool* changedNodeMask)
1118 : mNodes(nodes.empty() ? nullptr : &nodes[0])
1119 , mChangedNodeMask(changedNodeMask)
1120 {
1121 }
1122
1123 void operator()(const tbb::blocked_range<size_t>& range) const {
1124 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1125 if (mChangedNodeMask[n]) {
1126 //seedFill(*mNodes[n]);
1127 mChangedNodeMask[n] = scanFill(*mNodes[n]);
1128 }
1129 }
1130 }
1131
1132 LeafNodeType ** const mNodes;
1133 bool * const mChangedNodeMask;
1134 };
1135
1136
1137 template<typename ValueType>
1138 struct FillArray
1139 {
1140 FillArray(ValueType* array, const ValueType v) : mArray(array), mValue(v) { }
1141
1142 void operator()(const tbb::blocked_range<size_t>& range) const {
1143 const ValueType v = mValue;
1144 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1145 mArray[n] = v;
1146 }
1147 }
1148
1149 ValueType * const mArray;
1150 const ValueType mValue;
1151 };
1152
1153
1154 template<typename ValueType>
1155 inline void
1156 fillArray(ValueType* array, const ValueType val, const size_t length)
1157 {
1158 const auto grainSize = std::max<size_t>(
1159 length / tbb::task_scheduler_init::default_num_threads(), 1024);
1160 const tbb::blocked_range<size_t> range(0, length, grainSize);
1161 tbb::parallel_for(range, FillArray<ValueType>(array, val), tbb::simple_partitioner());
1162 }
1163
1164
1165 template<typename TreeType>
1166 class SyncVoxelMask
1167 {
1168 public:
1169 using ValueType = typename TreeType::ValueType;
1170 using LeafNodeType = typename TreeType::LeafNodeType;
1171
1172 SyncVoxelMask(std::vector<LeafNodeType*>& nodes,
1173 const bool* changedNodeMask, bool* changedVoxelMask)
1174 : mNodes(nodes.empty() ? nullptr : &nodes[0])
1175 , mChangedNodeMask(changedNodeMask)
1176 , mChangedVoxelMask(changedVoxelMask)
1177 {
1178 }
1179
1180 void operator()(const tbb::blocked_range<size_t>& range) const {
1181 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1182
1183 if (mChangedNodeMask[n]) {
1184 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1185
1186 ValueType* data = mNodes[n]->buffer().data();
1187
1188 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
1189 if (mask[pos]) {
1190 data[pos] = ValueType(-data[pos]);
1191 mask[pos] = false;
1192 }
1193 }
1194 }
1195 }
1196 }
1197
1198 LeafNodeType ** const mNodes;
1199 bool const * const mChangedNodeMask;
1200 bool * const mChangedVoxelMask;
1201 };
1202
1203
1204 template<typename TreeType>
1205 class SeedPoints
1206 {
1207 public:
1208 using ValueType = typename TreeType::ValueType;
1209 using LeafNodeType = typename TreeType::LeafNodeType;
1210 using ConnectivityTable = LeafNodeConnectivityTable<TreeType>;
1211
1212 SeedPoints(ConnectivityTable& connectivity,
1213 bool* changedNodeMask, bool* nodeMask, bool* changedVoxelMask)
1214 : mConnectivity(&connectivity)
1215 , mChangedNodeMask(changedNodeMask)
1216 , mNodeMask(nodeMask)
1217 , mChangedVoxelMask(changedVoxelMask)
1218 {
1219 }
1220
1221 void operator()(const tbb::blocked_range<size_t>& range) const {
1222
1223 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1224
1225 if (!mChangedNodeMask[n]) {
1226
1227 bool changedValue = false;
1228
1229 changedValue |= processZ(n, /*firstFace=*/true);
1230 changedValue |= processZ(n, /*firstFace=*/false);
1231
1232 changedValue |= processY(n, /*firstFace=*/true);
1233 changedValue |= processY(n, /*firstFace=*/false);
1234
1235 changedValue |= processX(n, /*firstFace=*/true);
1236 changedValue |= processX(n, /*firstFace=*/false);
1237
1238 mNodeMask[n] = changedValue;
1239 }
1240 }
1241 }
1242
1243
1244 bool processZ(const size_t n, bool firstFace) const
1245 {
1246 const size_t offset =
1247 firstFace ? mConnectivity->offsetsPrevZ()[n] : mConnectivity->offsetsNextZ()[n];
1248 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1249
1250 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1251
1252 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1253 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1254
1255 const Index lastOffset = LeafNodeType::DIM - 1;
1256 const Index lhsOffset =
1257 firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1258
1259 Index tmpPos(0), pos(0);
1260 bool changedValue = false;
1261
1262 for (Index x = 0; x < LeafNodeType::DIM; ++x) {
1263 tmpPos = x << (2 * LeafNodeType::LOG2DIM);
1264 for (Index y = 0; y < LeafNodeType::DIM; ++y) {
1265 pos = tmpPos + (y << LeafNodeType::LOG2DIM);
1266
1267 if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1268 if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1269 changedValue = true;
1270 mask[pos + lhsOffset] = true;
1271 }
1272 }
1273 }
1274 }
1275
1276 return changedValue;
1277 }
1278
1279 return false;
1280 }
1281
1282 bool processY(const size_t n, bool firstFace) const
1283 {
1284 const size_t offset =
1285 firstFace ? mConnectivity->offsetsPrevY()[n] : mConnectivity->offsetsNextY()[n];
1286 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1287
1288 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1289
1290 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1291 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1292
1293 const Index lastOffset = LeafNodeType::DIM * (LeafNodeType::DIM - 1);
1294 const Index lhsOffset =
1295 firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1296
1297 Index tmpPos(0), pos(0);
1298 bool changedValue = false;
1299
1300 for (Index x = 0; x < LeafNodeType::DIM; ++x) {
1301 tmpPos = x << (2 * LeafNodeType::LOG2DIM);
1302 for (Index z = 0; z < LeafNodeType::DIM; ++z) {
1303 pos = tmpPos + z;
1304
1305 if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1306 if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1307 changedValue = true;
1308 mask[pos + lhsOffset] = true;
1309 }
1310 }
1311 }
1312 }
1313
1314 return changedValue;
1315 }
1316
1317 return false;
1318 }
1319
1320 bool processX(const size_t n, bool firstFace) const
1321 {
1322 const size_t offset =
1323 firstFace ? mConnectivity->offsetsPrevX()[n] : mConnectivity->offsetsNextX()[n];
1324 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1325
1326 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1327
1328 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1329 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1330
1331 const Index lastOffset = LeafNodeType::DIM * LeafNodeType::DIM * (LeafNodeType::DIM-1);
1332 const Index lhsOffset =
1333 firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1334
1335 Index tmpPos(0), pos(0);
1336 bool changedValue = false;
1337
1338 for (Index y = 0; y < LeafNodeType::DIM; ++y) {
1339 tmpPos = y << LeafNodeType::LOG2DIM;
1340 for (Index z = 0; z < LeafNodeType::DIM; ++z) {
1341 pos = tmpPos + z;
1342
1343 if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1344 if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1345 changedValue = true;
1346 mask[pos + lhsOffset] = true;
1347 }
1348 }
1349 }
1350 }
1351
1352 return changedValue;
1353 }
1354
1355 return false;
1356 }
1357
1358 ConnectivityTable * const mConnectivity;
1359 bool * const mChangedNodeMask;
1360 bool * const mNodeMask;
1361 bool * const mChangedVoxelMask;
1362 };
1363
1364
1366
1367 template<typename TreeType, typename MeshDataAdapter>
1368 struct ComputeIntersectingVoxelSign
1369 {
1370 using ValueType = typename TreeType::ValueType;
1371 using LeafNodeType = typename TreeType::LeafNodeType;
1372 using Int32TreeType = typename TreeType::template ValueConverter<Int32>::Type;
1373 using Int32LeafNodeType = typename Int32TreeType::LeafNodeType;
1374
1375 using LocalData = std::pair<boost::shared_array<Vec3d>, boost::shared_array<bool> >;
1376 using LocalDataTable = tbb::enumerable_thread_specific<LocalData>;
1377
1378 ComputeIntersectingVoxelSign(
1379 std::vector<LeafNodeType*>& distNodes,
1380 const TreeType& distTree,
1381 const Int32TreeType& indexTree,
1382 const MeshDataAdapter& mesh)
1383 : mDistNodes(distNodes.empty() ? nullptr : &distNodes[0])
1384 , mDistTree(&distTree)
1385 , mIndexTree(&indexTree)
1386 , mMesh(&mesh)
1387 , mLocalDataTable(new LocalDataTable())
1388 {
1389 }
1390
1391
1392 void operator()(const tbb::blocked_range<size_t>& range) const {
1393
1394 tree::ValueAccessor<const TreeType> distAcc(*mDistTree);
1395 tree::ValueAccessor<const Int32TreeType> idxAcc(*mIndexTree);
1396
1397 ValueType nval;
1398 CoordBBox bbox;
1399 Index xPos(0), yPos(0);
1400 Coord ijk, nijk, nodeMin, nodeMax;
1401 Vec3d cp, xyz, nxyz, dir1, dir2;
1402
1403 LocalData& localData = mLocalDataTable->local();
1404
1405 boost::shared_array<Vec3d>& points = localData.first;
1406 if (!points) points.reset(new Vec3d[LeafNodeType::SIZE * 2]);
1407
1408 boost::shared_array<bool>& mask = localData.second;
1409 if (!mask) mask.reset(new bool[LeafNodeType::SIZE]);
1410
1411
1412 typename LeafNodeType::ValueOnCIter it;
1413
1414 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1415
1416 LeafNodeType& node = *mDistNodes[n];
1417 ValueType* data = node.buffer().data();
1418
1419 const Int32LeafNodeType* idxNode = idxAcc.probeConstLeaf(node.origin());
1420 const Int32* idxData = idxNode->buffer().data();
1421
1422 nodeMin = node.origin();
1423 nodeMax = nodeMin.offsetBy(LeafNodeType::DIM - 1);
1424
1425 // reset computed voxel mask.
1426 memset(mask.get(), 0, sizeof(bool) * LeafNodeType::SIZE);
1427
1428 for (it = node.cbeginValueOn(); it; ++it) {
1429 Index pos = it.pos();
1430
1431 ValueType& dist = data[pos];
1432 if (dist < 0.0 || dist > 0.75) continue;
1433
1434 ijk = node.offsetToGlobalCoord(pos);
1435
1436 xyz[0] = double(ijk[0]);
1437 xyz[1] = double(ijk[1]);
1438 xyz[2] = double(ijk[2]);
1439
1440
1441 bbox.min() = Coord::maxComponent(ijk.offsetBy(-1), nodeMin);
1442 bbox.max() = Coord::minComponent(ijk.offsetBy(1), nodeMax);
1443
1444 bool flipSign = false;
1445
1446 for (nijk[0] = bbox.min()[0]; nijk[0] <= bbox.max()[0] && !flipSign; ++nijk[0]) {
1447 xPos = (nijk[0] & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
1448 for (nijk[1]=bbox.min()[1]; nijk[1] <= bbox.max()[1] && !flipSign; ++nijk[1]) {
1449 yPos = xPos + ((nijk[1] & (LeafNodeType::DIM-1u)) << LeafNodeType::LOG2DIM);
1450 for (nijk[2] = bbox.min()[2]; nijk[2] <= bbox.max()[2]; ++nijk[2]) {
1451 pos = yPos + (nijk[2] & (LeafNodeType::DIM - 1u));
1452
1453 const Int32& polyIdx = idxData[pos];
1454
1455 if (polyIdx == Int32(util::INVALID_IDX) || !(data[pos] < -0.75))
1456 continue;
1457
1458 const Index pointIndex = pos * 2;
1459
1460 if (!mask[pos]) {
1461
1462 mask[pos] = true;
1463
1464 nxyz[0] = double(nijk[0]);
1465 nxyz[1] = double(nijk[1]);
1466 nxyz[2] = double(nijk[2]);
1467
1468 Vec3d& point = points[pointIndex];
1469
1470 point = closestPoint(nxyz, polyIdx);
1471
1472 Vec3d& direction = points[pointIndex + 1];
1473 direction = nxyz - point;
1474 direction.normalize();
1475 }
1476
1477 dir1 = xyz - points[pointIndex];
1478 dir1.normalize();
1479
1480 if (points[pointIndex + 1].dot(dir1) > 0.0) {
1481 flipSign = true;
1482 break;
1483 }
1484 }
1485 }
1486 }
1487
1488 if (flipSign) {
1489 dist = -dist;
1490 } else {
1491 for (Int32 m = 0; m < 26; ++m) {
1492 nijk = ijk + util::COORD_OFFSETS[m];
1493
1494 if (!bbox.isInside(nijk) && distAcc.probeValue(nijk, nval) && nval<-0.75) {
1495 nxyz[0] = double(nijk[0]);
1496 nxyz[1] = double(nijk[1]);
1497 nxyz[2] = double(nijk[2]);
1498
1499 cp = closestPoint(nxyz, idxAcc.getValue(nijk));
1500
1501 dir1 = xyz - cp;
1502 dir1.normalize();
1503
1504 dir2 = nxyz - cp;
1505 dir2.normalize();
1506
1507 if (dir2.dot(dir1) > 0.0) {
1508 dist = -dist;
1509 break;
1510 }
1511 }
1512 }
1513 }
1514
1515 } // active voxel loop
1516 } // leaf node loop
1517 }
1518
1519 private:
1520
1521 Vec3d closestPoint(const Vec3d& center, Int32 polyIdx) const
1522 {
1523 Vec3d a, b, c, cp, uvw;
1524
1525 const size_t polygon = size_t(polyIdx);
1526 mMesh->getIndexSpacePoint(polygon, 0, a);
1527 mMesh->getIndexSpacePoint(polygon, 1, b);
1528 mMesh->getIndexSpacePoint(polygon, 2, c);
1529
1530 cp = closestPointOnTriangleToPoint(a, c, b, center, uvw);
1531
1532 if (4 == mMesh->vertexCount(polygon)) {
1533
1534 mMesh->getIndexSpacePoint(polygon, 3, b);
1535
1536 c = closestPointOnTriangleToPoint(a, b, c, center, uvw);
1537
1538 if ((center - c).lengthSqr() < (center - cp).lengthSqr()) {
1539 cp = c;
1540 }
1541 }
1542
1543 return cp;
1544 }
1545
1546
1547 LeafNodeType ** const mDistNodes;
1548 TreeType const * const mDistTree;
1549 Int32TreeType const * const mIndexTree;
1550 MeshDataAdapter const * const mMesh;
1551
1552 SharedPtr<LocalDataTable> mLocalDataTable;
1553 }; // ComputeIntersectingVoxelSign
1554
1555
1557
1558
1559 template<typename LeafNodeType>
1560 inline void
1561 maskNodeInternalNeighbours(const Index pos, bool (&mask)[26])
1562 {
1563 using NodeT = LeafNodeType;
1564
1565 const Coord ijk = NodeT::offsetToLocalCoord(pos);
1566
1567 // Face adjacent neighbours
1568 // i+1, j, k
1569 mask[0] = ijk[0] != (NodeT::DIM - 1);
1570 // i-1, j, k
1571 mask[1] = ijk[0] != 0;
1572 // i, j+1, k
1573 mask[2] = ijk[1] != (NodeT::DIM - 1);
1574 // i, j-1, k
1575 mask[3] = ijk[1] != 0;
1576 // i, j, k+1
1577 mask[4] = ijk[2] != (NodeT::DIM - 1);
1578 // i, j, k-1
1579 mask[5] = ijk[2] != 0;
1580
1581 // Edge adjacent neighbour
1582 // i+1, j, k-1
1583 mask[6] = mask[0] && mask[5];
1584 // i-1, j, k-1
1585 mask[7] = mask[1] && mask[5];
1586 // i+1, j, k+1
1587 mask[8] = mask[0] && mask[4];
1588 // i-1, j, k+1
1589 mask[9] = mask[1] && mask[4];
1590 // i+1, j+1, k
1591 mask[10] = mask[0] && mask[2];
1592 // i-1, j+1, k
1593 mask[11] = mask[1] && mask[2];
1594 // i+1, j-1, k
1595 mask[12] = mask[0] && mask[3];
1596 // i-1, j-1, k
1597 mask[13] = mask[1] && mask[3];
1598 // i, j-1, k+1
1599 mask[14] = mask[3] && mask[4];
1600 // i, j-1, k-1
1601 mask[15] = mask[3] && mask[5];
1602 // i, j+1, k+1
1603 mask[16] = mask[2] && mask[4];
1604 // i, j+1, k-1
1605 mask[17] = mask[2] && mask[5];
1606
1607 // Corner adjacent neighbours
1608 // i-1, j-1, k-1
1609 mask[18] = mask[1] && mask[3] && mask[5];
1610 // i-1, j-1, k+1
1611 mask[19] = mask[1] && mask[3] && mask[4];
1612 // i+1, j-1, k+1
1613 mask[20] = mask[0] && mask[3] && mask[4];
1614 // i+1, j-1, k-1
1615 mask[21] = mask[0] && mask[3] && mask[5];
1616 // i-1, j+1, k-1
1617 mask[22] = mask[1] && mask[2] && mask[5];
1618 // i-1, j+1, k+1
1619 mask[23] = mask[1] && mask[2] && mask[4];
1620 // i+1, j+1, k+1
1621 mask[24] = mask[0] && mask[2] && mask[4];
1622 // i+1, j+1, k-1
1623 mask[25] = mask[0] && mask[2] && mask[5];
1624 }
1625
1626
1627 template<typename Compare, typename LeafNodeType>
1628 inline bool
1629 checkNeighbours(const Index pos, const typename LeafNodeType::ValueType * data, bool (&mask)[26])
1630 {
1631 using NodeT = LeafNodeType;
1632
1633 // i, j, k - 1
1634 if (mask[5] && Compare::check(data[pos - 1])) return true;
1635 // i, j, k + 1
1636 if (mask[4] && Compare::check(data[pos + 1])) return true;
1637 // i, j - 1, k
1638 if (mask[3] && Compare::check(data[pos - NodeT::DIM])) return true;
1639 // i, j + 1, k
1640 if (mask[2] && Compare::check(data[pos + NodeT::DIM])) return true;
1641 // i - 1, j, k
1642 if (mask[1] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM])) return true;
1643 // i + 1, j, k
1644 if (mask[0] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM])) return true;
1645 // i+1, j, k-1
1646 if (mask[6] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM])) return true;
1647 // i-1, j, k-1
1648 if (mask[7] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - 1])) return true;
1649 // i+1, j, k+1
1650 if (mask[8] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + 1])) return true;
1651 // i-1, j, k+1
1652 if (mask[9] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + 1])) return true;
1653 // i+1, j+1, k
1654 if (mask[10] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM])) return true;
1655 // i-1, j+1, k
1656 if (mask[11] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM])) return true;
1657 // i+1, j-1, k
1658 if (mask[12] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM])) return true;
1659 // i-1, j-1, k
1660 if (mask[13] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM])) return true;
1661 // i, j-1, k+1
1662 if (mask[14] && Compare::check(data[pos - NodeT::DIM + 1])) return true;
1663 // i, j-1, k-1
1664 if (mask[15] && Compare::check(data[pos - NodeT::DIM - 1])) return true;
1665 // i, j+1, k+1
1666 if (mask[16] && Compare::check(data[pos + NodeT::DIM + 1])) return true;
1667 // i, j+1, k-1
1668 if (mask[17] && Compare::check(data[pos + NodeT::DIM - 1])) return true;
1669 // i-1, j-1, k-1
1670 if (mask[18] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM - 1])) return true;
1671 // i-1, j-1, k+1
1672 if (mask[19] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM + 1])) return true;
1673 // i+1, j-1, k+1
1674 if (mask[20] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM + 1])) return true;
1675 // i+1, j-1, k-1
1676 if (mask[21] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM - 1])) return true;
1677 // i-1, j+1, k-1
1678 if (mask[22] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM - 1])) return true;
1679 // i-1, j+1, k+1
1680 if (mask[23] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM + 1])) return true;
1681 // i+1, j+1, k+1
1682 if (mask[24] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM + 1])) return true;
1683 // i+1, j+1, k-1
1684 if (mask[25] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM - 1])) return true;
1685
1686 return false;
1687 }
1688
1689
1690 template<typename Compare, typename AccessorType>
1691 inline bool
1692 checkNeighbours(const Coord& ijk, AccessorType& acc, bool (&mask)[26])
1693 {
1694 for (Int32 m = 0; m < 26; ++m) {
1695 if (!mask[m] && Compare::check(acc.getValue(ijk + util::COORD_OFFSETS[m]))) {
1696 return true;
1697 }
1698 }
1699
1700 return false;
1701 }
1702
1703
1704 template<typename TreeType>
1705 struct ValidateIntersectingVoxels
1706 {
1707 using ValueType = typename TreeType::ValueType;
1708 using LeafNodeType = typename TreeType::LeafNodeType;
1709
1710 struct IsNegative { static bool check(const ValueType v) { return v < ValueType(0.0); } };
1711
1712 ValidateIntersectingVoxels(TreeType& tree, std::vector<LeafNodeType*>& nodes)
1713 : mTree(&tree)
1714 , mNodes(nodes.empty() ? nullptr : &nodes[0])
1715 {
1716 }
1717
1718 void operator()(const tbb::blocked_range<size_t>& range) const
1719 {
1720 tree::ValueAccessor<const TreeType> acc(*mTree);
1721 bool neighbourMask[26];
1722
1723 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1724
1725 LeafNodeType& node = *mNodes[n];
1726 ValueType* data = node.buffer().data();
1727
1728 typename LeafNodeType::ValueOnCIter it;
1729 for (it = node.cbeginValueOn(); it; ++it) {
1730
1731 const Index pos = it.pos();
1732
1733 ValueType& dist = data[pos];
1734 if (dist < 0.0 || dist > 0.75) continue;
1735
1736 // Mask node internal neighbours
1737 maskNodeInternalNeighbours<LeafNodeType>(pos, neighbourMask);
1738
1739 const bool hasNegativeNeighbour =
1740 checkNeighbours<IsNegative, LeafNodeType>(pos, data, neighbourMask) ||
1741 checkNeighbours<IsNegative>(node.offsetToGlobalCoord(pos), acc, neighbourMask);
1742
1743 if (!hasNegativeNeighbour) {
1744 // push over boundary voxel distance
1745 dist = ValueType(0.75) + Tolerance<ValueType>::epsilon();
1746 }
1747 }
1748 }
1749 }
1750
1751 TreeType * const mTree;
1752 LeafNodeType ** const mNodes;
1753 }; // ValidateIntersectingVoxels
1754
1755
1756 template<typename TreeType>
1757 struct RemoveSelfIntersectingSurface
1758 {
1759 using ValueType = typename TreeType::ValueType;
1760 using LeafNodeType = typename TreeType::LeafNodeType;
1761 using Int32TreeType = typename TreeType::template ValueConverter<Int32>::Type;
1762
1763 struct Comp { static bool check(const ValueType v) { return !(v > ValueType(0.75)); } };
1764
1765 RemoveSelfIntersectingSurface(std::vector<LeafNodeType*>& nodes,
1766 TreeType& distTree, Int32TreeType& indexTree)
1767 : mNodes(nodes.empty() ? nullptr : &nodes[0])
1768 , mDistTree(&distTree)
1769 , mIndexTree(&indexTree)
1770 {
1771 }
1772
1773 void operator()(const tbb::blocked_range<size_t>& range) const
1774 {
1775 tree::ValueAccessor<const TreeType> distAcc(*mDistTree);
1776 tree::ValueAccessor<Int32TreeType> idxAcc(*mIndexTree);
1777 bool neighbourMask[26];
1778
1779 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1780
1781 LeafNodeType& distNode = *mNodes[n];
1782 ValueType* data = distNode.buffer().data();
1783
1784 typename Int32TreeType::LeafNodeType* idxNode =
1785 idxAcc.probeLeaf(distNode.origin());
1786
1787 typename LeafNodeType::ValueOnCIter it;
1788 for (it = distNode.cbeginValueOn(); it; ++it) {
1789
1790 const Index pos = it.pos();
1791
1792 if (!(data[pos] > 0.75)) continue;
1793
1794 // Mask node internal neighbours
1795 maskNodeInternalNeighbours<LeafNodeType>(pos, neighbourMask);
1796
1797 const bool hasBoundaryNeighbour =
1798 checkNeighbours<Comp, LeafNodeType>(pos, data, neighbourMask) ||
1799 checkNeighbours<Comp>(distNode.offsetToGlobalCoord(pos),distAcc,neighbourMask);
1800
1801 if (!hasBoundaryNeighbour) {
1802 distNode.setValueOff(pos);
1803 idxNode->setValueOff(pos);
1804 }
1805 }
1806 }
1807 }
1808
1809 LeafNodeType * * const mNodes;
1810 TreeType * const mDistTree;
1811 Int32TreeType * const mIndexTree;
1812 }; // RemoveSelfIntersectingSurface
1813
1814
1816
1817
1818 template<typename NodeType>
1819 struct ReleaseChildNodes
1820 {
1821 ReleaseChildNodes(NodeType ** nodes) : mNodes(nodes) {}
1822
1823 void operator()(const tbb::blocked_range<size_t>& range) const {
1824
1825 using NodeMaskType = typename NodeType::NodeMaskType;
1826
1827 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1828 const_cast<NodeMaskType&>(mNodes[n]->getChildMask()).setOff();
1829 }
1830 }
1831
1832 NodeType ** const mNodes;
1833 };
1834
1835
1836 template<typename TreeType>
1837 inline void
1838 releaseLeafNodes(TreeType& tree)
1839 {
1840 using RootNodeType = typename TreeType::RootNodeType;
1841 using NodeChainType = typename RootNodeType::NodeChainType;
1842 using InternalNodeType = typename boost::mpl::at<NodeChainType, boost::mpl::int_<1> >::type;
1843
1844 std::vector<InternalNodeType*> nodes;
1845 tree.getNodes(nodes);
1846
1847 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
1848 ReleaseChildNodes<InternalNodeType>(nodes.empty() ? nullptr : &nodes[0]));
1849 }
1850
1851
1852 template<typename TreeType>
1853 struct StealUniqueLeafNodes
1854 {
1855 using LeafNodeType = typename TreeType::LeafNodeType;
1856
1857 StealUniqueLeafNodes(TreeType& lhsTree, TreeType& rhsTree,
1858 std::vector<LeafNodeType*>& overlappingNodes)
1859 : mLhsTree(&lhsTree)
1860 , mRhsTree(&rhsTree)
1861 , mNodes(&overlappingNodes)
1862 {
1863 }
1864
1865 void operator()() const {
1866
1867 std::vector<LeafNodeType*> rhsLeafNodes;
1868
1869 rhsLeafNodes.reserve(mRhsTree->leafCount());
1870 //mRhsTree->getNodes(rhsLeafNodes);
1871 //releaseLeafNodes(*mRhsTree);
1872 mRhsTree->stealNodes(rhsLeafNodes);
1873
1874 tree::ValueAccessor<TreeType> acc(*mLhsTree);
1875
1876 for (size_t n = 0, N = rhsLeafNodes.size(); n < N; ++n) {
1877 if (!acc.probeLeaf(rhsLeafNodes[n]->origin())) {
1878 acc.addLeaf(rhsLeafNodes[n]);
1879 } else {
1880 mNodes->push_back(rhsLeafNodes[n]);
1881 }
1882 }
1883 }
1884
1885 private:
1886 TreeType * const mLhsTree;
1887 TreeType * const mRhsTree;
1888 std::vector<LeafNodeType*> * const mNodes;
1889 };
1890
1891
1892 template<typename DistTreeType, typename IndexTreeType>
1893 inline void
1894 combineData(DistTreeType& lhsDist, IndexTreeType& lhsIdx,
1895 DistTreeType& rhsDist, IndexTreeType& rhsIdx)
1896 {
1897 using DistLeafNodeType = typename DistTreeType::LeafNodeType;
1898 using IndexLeafNodeType = typename IndexTreeType::LeafNodeType;
1899
1900 std::vector<DistLeafNodeType*> overlappingDistNodes;
1901 std::vector<IndexLeafNodeType*> overlappingIdxNodes;
1902
1903 // Steal unique leafnodes
1904 tbb::task_group tasks;
1905 tasks.run(StealUniqueLeafNodes<DistTreeType>(lhsDist, rhsDist, overlappingDistNodes));
1906 tasks.run(StealUniqueLeafNodes<IndexTreeType>(lhsIdx, rhsIdx, overlappingIdxNodes));
1907 tasks.wait();
1908
1909 // Combine overlapping leaf nodes
1910 if (!overlappingDistNodes.empty() && !overlappingIdxNodes.empty()) {
1911 tbb::parallel_for(tbb::blocked_range<size_t>(0, overlappingDistNodes.size()),
1912 CombineLeafNodes<DistTreeType>(lhsDist, lhsIdx,
1913 &overlappingDistNodes[0], &overlappingIdxNodes[0]));
1914 }
1915 }
1916
1923 template<typename TreeType>
1924 struct VoxelizationData {
1925
1926 using Ptr = std::unique_ptr<VoxelizationData>;
1927 using ValueType = typename TreeType::ValueType;
1928
1929 using Int32TreeType = typename TreeType::template ValueConverter<Int32>::Type;
1930 using UCharTreeType = typename TreeType::template ValueConverter<unsigned char>::Type;
1931
1932 using FloatTreeAcc = tree::ValueAccessor<TreeType>;
1933 using Int32TreeAcc = tree::ValueAccessor<Int32TreeType>;
1934 using UCharTreeAcc = tree::ValueAccessor<UCharTreeType>;
1935
1936
1937 VoxelizationData()
1938 : distTree(std::numeric_limits<ValueType>::max())
1939 , distAcc(distTree)
1940 , indexTree(Int32(util::INVALID_IDX))
1941 , indexAcc(indexTree)
1942 , primIdTree(MaxPrimId)
1943 , primIdAcc(primIdTree)
1944 , mPrimCount(0)
1945 {
1946 }
1947
1948 TreeType distTree;
1949 FloatTreeAcc distAcc;
1950
1951 Int32TreeType indexTree;
1952 Int32TreeAcc indexAcc;
1953
1954 UCharTreeType primIdTree;
1955 UCharTreeAcc primIdAcc;
1956
1957 unsigned char getNewPrimId() {
1958
1959 if (mPrimCount == MaxPrimId || primIdTree.leafCount() > 1000) {
1960 mPrimCount = 0;
1961 primIdTree.clear();
1962 }
1963
1964 return mPrimCount++;
1965 }
1966
1967 private:
1968
1969 enum { MaxPrimId = 100 };
1970
1971 unsigned char mPrimCount;
1972 };
1973
1974
1975 template<typename TreeType, typename MeshDataAdapter, typename Interrupter = util::NullInterrupter>
1976 class VoxelizePolygons
1977 {
1978 public:
1979
1980 using VoxelizationDataType = VoxelizationData<TreeType>;
1981 using DataTable = tbb::enumerable_thread_specific<typename VoxelizationDataType::Ptr>;
1982
1983 VoxelizePolygons(DataTable& dataTable,
1984 const MeshDataAdapter& mesh,
1985 Interrupter* interrupter = nullptr)
1986 : mDataTable(&dataTable)
1987 , mMesh(&mesh)
1988 , mInterrupter(interrupter)
1989 {
1990 }
1991
1992 void operator()(const tbb::blocked_range<size_t>& range) const {
1993
1994 typename VoxelizationDataType::Ptr& dataPtr = mDataTable->local();
1995 if (!dataPtr) dataPtr.reset(new VoxelizationDataType());
1996
1997 Triangle prim;
1998
1999 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
2000
2001 if (this->wasInterrupted()) {
2002 tbb::task::self().cancel_group_execution();
2003 break;
2004 }
2005
2006 const size_t numVerts = mMesh->vertexCount(n);
2007
2008 // rasterize triangles and quads.
2009 if (numVerts == 3 || numVerts == 4) {
2010
2011 prim.index = Int32(n);
2012
2013 mMesh->getIndexSpacePoint(n, 0, prim.a);
2014 mMesh->getIndexSpacePoint(n, 1, prim.b);
2015 mMesh->getIndexSpacePoint(n, 2, prim.c);
2016
2017 evalTriangle(prim, *dataPtr);
2018
2019 if (numVerts == 4) {
2020 mMesh->getIndexSpacePoint(n, 3, prim.b);
2021 evalTriangle(prim, *dataPtr);
2022 }
2023 }
2024 }
2025 }
2026
2027 private:
2028
2029 bool wasInterrupted() const { return mInterrupter && mInterrupter->wasInterrupted(); }
2030
2031 struct Triangle { Vec3d a, b, c; Int32 index; };
2032
2033 struct SubTask
2034 {
2035 enum { POLYGON_LIMIT = 1000 };
2036
2037 SubTask(const Triangle& prim, DataTable& dataTable,
2038 int subdivisionCount, size_t polygonCount)
2039 : mLocalDataTable(&dataTable)
2040 , mPrim(prim)
2041 , mSubdivisionCount(subdivisionCount)
2042 , mPolygonCount(polygonCount)
2043 {
2044 }
2045
2046 void operator()() const
2047 {
2048 if (mSubdivisionCount <= 0 || mPolygonCount >= POLYGON_LIMIT) {
2049
2050 typename VoxelizationDataType::Ptr& dataPtr = mLocalDataTable->local();
2051 if (!dataPtr) dataPtr.reset(new VoxelizationDataType());
2052
2053 voxelizeTriangle(mPrim, *dataPtr);
2054
2055 } else {
2056 spawnTasks(mPrim, *mLocalDataTable, mSubdivisionCount, mPolygonCount);
2057 }
2058 }
2059
2060 DataTable * const mLocalDataTable;
2061 Triangle const mPrim;
2062 int const mSubdivisionCount;
2063 size_t const mPolygonCount;
2064 }; // struct SubTask
2065
2066 inline static int evalSubdivisionCount(const Triangle& prim)
2067 {
2068 const double ax = prim.a[0], bx = prim.b[0], cx = prim.c[0];
2069 const double dx = std::max(ax, std::max(bx, cx)) - std::min(ax, std::min(bx, cx));
2070
2071 const double ay = prim.a[1], by = prim.b[1], cy = prim.c[1];
2072 const double dy = std::max(ay, std::max(by, cy)) - std::min(ay, std::min(by, cy));
2073
2074 const double az = prim.a[2], bz = prim.b[2], cz = prim.c[2];
2075 const double dz = std::max(az, std::max(bz, cz)) - std::min(az, std::min(bz, cz));
2076
2077 return int(std::max(dx, std::max(dy, dz)) / double(TreeType::LeafNodeType::DIM * 2));
2078 }
2079
2080 void evalTriangle(const Triangle& prim, VoxelizationDataType& data) const
2081 {
2082 const size_t polygonCount = mMesh->polygonCount();
2083 const int subdivisionCount =
2084 polygonCount < SubTask::POLYGON_LIMIT ? evalSubdivisionCount(prim) : 0;
2085
2086 if (subdivisionCount <= 0) {
2087 voxelizeTriangle(prim, data);
2088 } else {
2089 spawnTasks(prim, *mDataTable, subdivisionCount, polygonCount);
2090 }
2091 }
2092
2093 static void spawnTasks(
2094 const Triangle& mainPrim, DataTable& dataTable, int subdivisionCount, size_t polygonCount)
2095 {
2096 subdivisionCount -= 1;
2097 polygonCount *= 4;
2098
2099 tbb::task_group tasks;
2100
2101 const Vec3d ac = (mainPrim.a + mainPrim.c) * 0.5;
2102 const Vec3d bc = (mainPrim.b + mainPrim.c) * 0.5;
2103 const Vec3d ab = (mainPrim.a + mainPrim.b) * 0.5;
2104
2105 Triangle prim;
2106 prim.index = mainPrim.index;
2107
2108 prim.a = mainPrim.a;
2109 prim.b = ab;
2110 prim.c = ac;
2111 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount));
2112
2113 prim.a = ab;
2114 prim.b = bc;
2115 prim.c = ac;
2116 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount));
2117
2118 prim.a = ab;
2119 prim.b = mainPrim.b;
2120 prim.c = bc;
2121 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount));
2122
2123 prim.a = ac;
2124 prim.b = bc;
2125 prim.c = mainPrim.c;
2126 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount));
2127
2128 tasks.wait();
2129 }
2130
2131 static void voxelizeTriangle(const Triangle& prim, VoxelizationDataType& data)
2132 {
2133 std::deque<Coord> coordList;
2134 Coord ijk, nijk;
2135
2136 ijk = Coord::floor(prim.a);
2137 coordList.push_back(ijk);
2138
2139 computeDistance(ijk, prim, data);
2140
2141 unsigned char primId = data.getNewPrimId();
2142 data.primIdAcc.setValueOnly(ijk, primId);
2143
2144 while (!coordList.empty()) {
2145 ijk = coordList.back();
2146 coordList.pop_back();
2147
2148 for (Int32 i = 0; i < 26; ++i) {
2149 nijk = ijk + util::COORD_OFFSETS[i];
2150 if (primId != data.primIdAcc.getValue(nijk)) {
2151 data.primIdAcc.setValueOnly(nijk, primId);
2152 if(computeDistance(nijk, prim, data)) coordList.push_back(nijk);
2153 }
2154 }
2155 }
2156 }
2157
2158 static bool computeDistance(const Coord& ijk, const Triangle& prim, VoxelizationDataType& data)
2159 {
2160 Vec3d uvw, voxelCenter(ijk[0], ijk[1], ijk[2]);
2161
2162 using ValueType = typename TreeType::ValueType;
2163
2164 const ValueType dist = ValueType((voxelCenter -
2165 closestPointOnTriangleToPoint(prim.a, prim.c, prim.b, voxelCenter, uvw)).lengthSqr());
2166
2167 const ValueType oldDist = data.distAcc.getValue(ijk);
2168
2169 if (dist < oldDist) {
2170 data.distAcc.setValue(ijk, dist);
2171 data.indexAcc.setValue(ijk, prim.index);
2172 } else if (math::isExactlyEqual(dist, oldDist)) {
2173 // makes reduction deterministic when different polygons
2174 // produce the same distance value.
2175 data.indexAcc.setValueOnly(ijk, std::min(prim.index, data.indexAcc.getValue(ijk)));
2176 }
2177
2178 return !(dist > 0.75); // true if the primitive intersects the voxel.
2179 }
2180
2181 DataTable * const mDataTable;
2182 MeshDataAdapter const * const mMesh;
2183 Interrupter * const mInterrupter;
2184 }; // VoxelizePolygons
2185
2186
2188
2189
2190 template<typename TreeType>
2191 struct DiffLeafNodeMask
2192 {
2193 using AccessorType = typename tree::ValueAccessor<TreeType>;
2194 using LeafNodeType = typename TreeType::LeafNodeType;
2195
2196 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
2197 using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
2198
2199 DiffLeafNodeMask(const TreeType& rhsTree,
2200 std::vector<BoolLeafNodeType*>& lhsNodes)
2201 : mRhsTree(&rhsTree), mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes[0])
2202 {
2203 }
2204
2205 void operator()(const tbb::blocked_range<size_t>& range) const {
2206
2207 tree::ValueAccessor<const TreeType> acc(*mRhsTree);
2208
2209 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
2210
2211 BoolLeafNodeType* lhsNode = mLhsNodes[n];
2212 const LeafNodeType* rhsNode = acc.probeConstLeaf(lhsNode->origin());
2213
2214 if (rhsNode) lhsNode->topologyDifference(*rhsNode, false);
2215 }
2216 }
2217
2218 private:
2219 TreeType const * const mRhsTree;
2220 BoolLeafNodeType ** const mLhsNodes;
2221 };
2222
2223
2224 template<typename LeafNodeTypeA, typename LeafNodeTypeB>
2225 struct UnionValueMasks
2226 {
2227 UnionValueMasks(std::vector<LeafNodeTypeA*>& nodesA, std::vector<LeafNodeTypeB*>& nodesB)
2228 : mNodesA(nodesA.empty() ? nullptr : &nodesA[0])
2229 , mNodesB(nodesB.empty() ? nullptr : &nodesB[0])
2230 {
2231 }
2232
2233 void operator()(const tbb::blocked_range<size_t>& range) const {
2234 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
2235 mNodesA[n]->topologyUnion(*mNodesB[n]);
2236 }
2237 }
2238
2239 private:
2240 LeafNodeTypeA ** const mNodesA;
2241 LeafNodeTypeB ** const mNodesB;
2242 };
2243
2244
2245 template<typename TreeType>
2246 struct ConstructVoxelMask
2247 {
2248 using LeafNodeType = typename TreeType::LeafNodeType;
2249
2250 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
2251 using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
2252
2253 ConstructVoxelMask(BoolTreeType& maskTree, const TreeType& tree,
2254 std::vector<LeafNodeType*>& nodes)
2255 : mTree(&tree)
2256 , mNodes(nodes.empty() ? nullptr : &nodes[0])
2257 , mLocalMaskTree(false)
2258 , mMaskTree(&maskTree)
2259 {
2260 }
2261
2262 ConstructVoxelMask(ConstructVoxelMask& rhs, tbb::split)
2263 : mTree(rhs.mTree)
2264 , mNodes(rhs.mNodes)
2265 , mLocalMaskTree(false)
2266 , mMaskTree(&mLocalMaskTree)
2267 {
2268 }
2269
2270 void operator()(const tbb::blocked_range<size_t>& range)
2271 {
2272 using Iterator = typename LeafNodeType::ValueOnCIter;
2273
2274 tree::ValueAccessor<const TreeType> acc(*mTree);
2275 tree::ValueAccessor<BoolTreeType> maskAcc(*mMaskTree);
2276
2277 Coord ijk, nijk, localCorod;
2278 Index pos, npos;
2279
2280 for (size_t n = range.begin(); n != range.end(); ++n) {
2281
2282 LeafNodeType& node = *mNodes[n];
2283
2284 CoordBBox bbox = node.getNodeBoundingBox();
2285 bbox.expand(-1);
2286
2287 BoolLeafNodeType& maskNode = *maskAcc.touchLeaf(node.origin());
2288
2289 for (Iterator it = node.cbeginValueOn(); it; ++it) {
2290 ijk = it.getCoord();
2291 pos = it.pos();
2292
2293 localCorod = LeafNodeType::offsetToLocalCoord(pos);
2294
2295 if (localCorod[2] < int(LeafNodeType::DIM - 1)) {
2296 npos = pos + 1;
2297 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2298 } else {
2299 nijk = ijk.offsetBy(0, 0, 1);
2300 if (!acc.isValueOn(nijk)) maskAcc.setValueOn(nijk);
2301 }
2302
2303 if (localCorod[2] > 0) {
2304 npos = pos - 1;
2305 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2306 } else {
2307 nijk = ijk.offsetBy(0, 0, -1);
2308 if (!acc.isValueOn(nijk)) maskAcc.setValueOn(nijk);
2309 }
2310
2311 if (localCorod[1] < int(LeafNodeType::DIM - 1)) {
2312 npos = pos + LeafNodeType::DIM;
2313 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2314 } else {
2315 nijk = ijk.offsetBy(0, 1, 0);
2316 if (!acc.isValueOn(nijk)) maskAcc.setValueOn(nijk);
2317 }
2318
2319 if (localCorod[1] > 0) {
2320 npos = pos - LeafNodeType::DIM;
2321 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2322 } else {
2323 nijk = ijk.offsetBy(0, -1, 0);
2324 if (!acc.isValueOn(nijk)) maskAcc.setValueOn(nijk);
2325 }
2326
2327 if (localCorod[0] < int(LeafNodeType::DIM - 1)) {
2328 npos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
2329 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2330 } else {
2331 nijk = ijk.offsetBy(1, 0, 0);
2332 if (!acc.isValueOn(nijk)) maskAcc.setValueOn(nijk);
2333 }
2334
2335 if (localCorod[0] > 0) {
2336 npos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
2337 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2338 } else {
2339 nijk = ijk.offsetBy(-1, 0, 0);
2340 if (!acc.isValueOn(nijk)) maskAcc.setValueOn(nijk);
2341 }
2342 }
2343 }
2344 }
2345
2346 void join(ConstructVoxelMask& rhs) { mMaskTree->merge(*rhs.mMaskTree); }
2347
2348 private:
2349 TreeType const * const mTree;
2350 LeafNodeType ** const mNodes;
2351
2352 BoolTreeType mLocalMaskTree;
2353 BoolTreeType * const mMaskTree;
2354 };
2355
2356
2358 template<typename TreeType, typename MeshDataAdapter>
2359 struct ExpandNarrowband
2360 {
2361 using ValueType = typename TreeType::ValueType;
2362 using LeafNodeType = typename TreeType::LeafNodeType;
2363 using NodeMaskType = typename LeafNodeType::NodeMaskType;
2364 using Int32TreeType = typename TreeType::template ValueConverter<Int32>::Type;
2365 using Int32LeafNodeType = typename Int32TreeType::LeafNodeType;
2366 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
2367 using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
2368
2369 struct Fragment
2370 {
2371 Int32 idx, x, y, z;
2372 ValueType dist;
2373
2374 Fragment() : idx(0), x(0), y(0), z(0), dist(0.0) {}
2375
2376 Fragment(Int32 idx_, Int32 x_, Int32 y_, Int32 z_, ValueType dist_)
2377 : idx(idx_), x(x_), y(y_), z(z_), dist(dist_)
2378 {
2379 }
2380
2381 bool operator<(const Fragment& rhs) const { return idx < rhs.idx; }
2382 }; // struct Fragment
2383
2385
2386 ExpandNarrowband(
2387 std::vector<BoolLeafNodeType*>& maskNodes,
2388 BoolTreeType& maskTree,
2389 TreeType& distTree,
2390 Int32TreeType& indexTree,
2391 const MeshDataAdapter& mesh,
2392 ValueType exteriorBandWidth,
2393 ValueType interiorBandWidth,
2394 ValueType voxelSize)
2395 : mMaskNodes(maskNodes.empty() ? nullptr : &maskNodes[0])
2396 , mMaskTree(&maskTree)
2397 , mDistTree(&distTree)
2398 , mIndexTree(&indexTree)
2399 , mMesh(&mesh)
2400 , mNewMaskTree(false)
2401 , mDistNodes()
2402 , mUpdatedDistNodes()
2403 , mIndexNodes()
2404 , mUpdatedIndexNodes()
2405 , mExteriorBandWidth(exteriorBandWidth)
2406 , mInteriorBandWidth(interiorBandWidth)
2407 , mVoxelSize(voxelSize)
2408 {
2409 }
2410
2411 ExpandNarrowband(const ExpandNarrowband& rhs, tbb::split)
2412 : mMaskNodes(rhs.mMaskNodes)
2413 , mMaskTree(rhs.mMaskTree)
2414 , mDistTree(rhs.mDistTree)
2415 , mIndexTree(rhs.mIndexTree)
2416 , mMesh(rhs.mMesh)
2417 , mNewMaskTree(false)
2418 , mDistNodes()
2419 , mUpdatedDistNodes()
2420 , mIndexNodes()
2421 , mUpdatedIndexNodes()
2422 , mExteriorBandWidth(rhs.mExteriorBandWidth)
2423 , mInteriorBandWidth(rhs.mInteriorBandWidth)
2424 , mVoxelSize(rhs.mVoxelSize)
2425 {
2426 }
2427
2428 void join(ExpandNarrowband& rhs)
2429 {
2430 mDistNodes.insert(mDistNodes.end(), rhs.mDistNodes.begin(), rhs.mDistNodes.end());
2431 mIndexNodes.insert(mIndexNodes.end(), rhs.mIndexNodes.begin(), rhs.mIndexNodes.end());
2432
2433 mUpdatedDistNodes.insert(mUpdatedDistNodes.end(),
2434 rhs.mUpdatedDistNodes.begin(), rhs.mUpdatedDistNodes.end());
2435
2436 mUpdatedIndexNodes.insert(mUpdatedIndexNodes.end(),
2437 rhs.mUpdatedIndexNodes.begin(), rhs.mUpdatedIndexNodes.end());
2438
2439 mNewMaskTree.merge(rhs.mNewMaskTree);
2440 }
2441
2442 void operator()(const tbb::blocked_range<size_t>& range)
2443 {
2444 tree::ValueAccessor<BoolTreeType> newMaskAcc(mNewMaskTree);
2445 tree::ValueAccessor<TreeType> distAcc(*mDistTree);
2446 tree::ValueAccessor<Int32TreeType> indexAcc(*mIndexTree);
2447
2448 std::vector<Fragment> fragments;
2449 fragments.reserve(256);
2450
2451 std::unique_ptr<LeafNodeType> newDistNodePt;
2452 std::unique_ptr<Int32LeafNodeType> newIndexNodePt;
2453
2454 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
2455
2456 BoolLeafNodeType& maskNode = *mMaskNodes[n];
2457 if (maskNode.isEmpty()) continue;
2458
2459 // Setup local caches
2460
2461 const Coord& origin = maskNode.origin();
2462
2463 LeafNodeType * distNodePt = distAcc.probeLeaf(origin);
2464 Int32LeafNodeType * indexNodePt = indexAcc.probeLeaf(origin);
2465
2466 assert(!distNodePt == !indexNodePt);
2467
2468 bool usingNewNodes = false;
2469
2470 if (!distNodePt && !indexNodePt) {
2471
2472 const ValueType backgroundDist = distAcc.getValue(origin);
2473
2474 if (!newDistNodePt.get() && !newIndexNodePt.get()) {
2475 newDistNodePt.reset(new LeafNodeType(origin, backgroundDist));
2476 newIndexNodePt.reset(new Int32LeafNodeType(origin, indexAcc.getValue(origin)));
2477 } else {
2478
2479 if ((backgroundDist < ValueType(0.0)) !=
2480 (newDistNodePt->getValue(0) < ValueType(0.0))) {
2481 newDistNodePt->buffer().fill(backgroundDist);
2482 }
2483
2484 newDistNodePt->setOrigin(origin);
2485 newIndexNodePt->setOrigin(origin);
2486 }
2487
2488 distNodePt = newDistNodePt.get();
2489 indexNodePt = newIndexNodePt.get();
2490
2491 usingNewNodes = true;
2492 }
2493
2494
2495 // Gather neighbour information
2496
2497 CoordBBox bbox(Coord::max(), Coord::min());
2498 for (typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
2499 bbox.expand(it.getCoord());
2500 }
2501
2502 bbox.expand(1);
2503
2504 gatherFragments(fragments, bbox, distAcc, indexAcc);
2505
2506
2507 // Compute first voxel layer
2508
2509 bbox = maskNode.getNodeBoundingBox();
2510 NodeMaskType mask;
2511 bool updatedLeafNodes = false;
2512
2513 for (typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
2514
2515 const Coord ijk = it.getCoord();
2516
2517 if (updateVoxel(ijk, 5, fragments, *distNodePt, *indexNodePt, &updatedLeafNodes)) {
2518
2519 for (Int32 i = 0; i < 6; ++i) {
2520 const Coord nijk = ijk + util::COORD_OFFSETS[i];
2521 if (bbox.isInside(nijk)) {
2522 mask.setOn(BoolLeafNodeType::coordToOffset(nijk));
2523 } else {
2524 newMaskAcc.setValueOn(nijk);
2525 }
2526 }
2527
2528 for (Int32 i = 6; i < 26; ++i) {
2529 const Coord nijk = ijk + util::COORD_OFFSETS[i];
2530 if (bbox.isInside(nijk)) {
2531 mask.setOn(BoolLeafNodeType::coordToOffset(nijk));
2532 }
2533 }
2534 }
2535 }
2536
2537 if (updatedLeafNodes) {
2538
2539 // Compute second voxel layer
2540 mask -= indexNodePt->getValueMask();
2541
2542 for (typename NodeMaskType::OnIterator it = mask.beginOn(); it; ++it) {
2543
2544 const Index pos = it.pos();
2545 const Coord ijk = maskNode.origin() + LeafNodeType::offsetToLocalCoord(pos);
2546
2547 if (updateVoxel(ijk, 6, fragments, *distNodePt, *indexNodePt)) {
2548 for (Int32 i = 0; i < 6; ++i) {
2549 newMaskAcc.setValueOn(ijk + util::COORD_OFFSETS[i]);
2550 }
2551 }
2552 }
2553
2554 // Export new distance values
2555 if (usingNewNodes) {
2556 newDistNodePt->topologyUnion(*newIndexNodePt);
2557 mDistNodes.push_back(newDistNodePt.release());
2558 mIndexNodes.push_back(newIndexNodePt.release());
2559 } else {
2560 mUpdatedDistNodes.push_back(distNodePt);
2561 mUpdatedIndexNodes.push_back(indexNodePt);
2562 }
2563 }
2564 } // end leafnode loop
2565 }
2566
2568
2569 BoolTreeType& newMaskTree() { return mNewMaskTree; }
2570
2571 std::vector<LeafNodeType*>& newDistNodes() { return mDistNodes; }
2572 std::vector<LeafNodeType*>& updatedDistNodes() { return mUpdatedDistNodes; }
2573
2574 std::vector<Int32LeafNodeType*>& newIndexNodes() { return mIndexNodes; }
2575 std::vector<Int32LeafNodeType*>& updatedIndexNodes() { return mUpdatedIndexNodes; }
2576
2577 private:
2578
2580 void
2581 gatherFragments(std::vector<Fragment>& fragments, const CoordBBox& bbox,
2582 tree::ValueAccessor<TreeType>& distAcc, tree::ValueAccessor<Int32TreeType>& indexAcc)
2583 {
2584 fragments.clear();
2585 const Coord nodeMin = bbox.min() & ~(LeafNodeType::DIM - 1);
2586 const Coord nodeMax = bbox.max() & ~(LeafNodeType::DIM - 1);
2587
2588 CoordBBox region;
2589 Coord ijk;
2590
2591 for (ijk[0] = nodeMin[0]; ijk[0] <= nodeMax[0]; ijk[0] += LeafNodeType::DIM) {
2592 for (ijk[1] = nodeMin[1]; ijk[1] <= nodeMax[1]; ijk[1] += LeafNodeType::DIM) {
2593 for (ijk[2] = nodeMin[2]; ijk[2] <= nodeMax[2]; ijk[2] += LeafNodeType::DIM) {
2594 if (LeafNodeType* distleaf = distAcc.probeLeaf(ijk)) {
2595 region.min() = Coord::maxComponent(bbox.min(), ijk);
2596 region.max() = Coord::minComponent(bbox.max(),
2597 ijk.offsetBy(LeafNodeType::DIM - 1));
2598 gatherFragments(fragments, region, *distleaf, *indexAcc.probeLeaf(ijk));
2599 }
2600 }
2601 }
2602 }
2603
2604 std::sort(fragments.begin(), fragments.end());
2605 }
2606
2607 void
2608 gatherFragments(std::vector<Fragment>& fragments, const CoordBBox& bbox,
2609 const LeafNodeType& distLeaf, const Int32LeafNodeType& idxLeaf) const
2610 {
2611 const typename LeafNodeType::NodeMaskType& mask = distLeaf.getValueMask();
2612 const ValueType* distData = distLeaf.buffer().data();
2613 const Int32* idxData = idxLeaf.buffer().data();
2614
2615 for (int x = bbox.min()[0]; x <= bbox.max()[0]; ++x) {
2616 const Index xPos = (x & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
2617 for (int y = bbox.min()[1]; y <= bbox.max()[1]; ++y) {
2618 const Index yPos = xPos + ((y & (LeafNodeType::DIM - 1u)) << LeafNodeType::LOG2DIM);
2619 for (int z = bbox.min()[2]; z <= bbox.max()[2]; ++z) {
2620 const Index pos = yPos + (z & (LeafNodeType::DIM - 1u));
2621 if (mask.isOn(pos)) {
2622 fragments.push_back(Fragment(idxData[pos],x,y,z, std::abs(distData[pos])));
2623 }
2624 }
2625 }
2626 }
2627 }
2628
2631 ValueType
2632 computeDistance(const Coord& ijk, const Int32 manhattanLimit,
2633 const std::vector<Fragment>& fragments, Int32& closestPrimIdx) const
2634 {
2635 Vec3d a, b, c, uvw, voxelCenter(ijk[0], ijk[1], ijk[2]);
2636 double primDist, tmpDist, dist = std::numeric_limits<double>::max();
2637 Int32 lastIdx = Int32(util::INVALID_IDX);
2638
2639 for (size_t n = 0, N = fragments.size(); n < N; ++n) {
2640
2641 const Fragment& fragment = fragments[n];
2642 if (lastIdx == fragment.idx) continue;
2643
2644 const Int32 dx = std::abs(fragment.x - ijk[0]);
2645 const Int32 dy = std::abs(fragment.y - ijk[1]);
2646 const Int32 dz = std::abs(fragment.z - ijk[2]);
2647
2648 const Int32 manhattan = dx + dy + dz;
2649 if (manhattan > manhattanLimit) continue;
2650
2651 lastIdx = fragment.idx;
2652
2653 const size_t polygon = size_t(lastIdx);
2654
2655 mMesh->getIndexSpacePoint(polygon, 0, a);
2656 mMesh->getIndexSpacePoint(polygon, 1, b);
2657 mMesh->getIndexSpacePoint(polygon, 2, c);
2658
2659 primDist = (voxelCenter -
2660 closestPointOnTriangleToPoint(a, c, b, voxelCenter, uvw)).lengthSqr();
2661
2662 // Split quad into a second triangle
2663 if (4 == mMesh->vertexCount(polygon)) {
2664
2665 mMesh->getIndexSpacePoint(polygon, 3, b);
2666
2667 tmpDist = (voxelCenter - closestPointOnTriangleToPoint(
2668 a, b, c, voxelCenter, uvw)).lengthSqr();
2669
2670 if (tmpDist < primDist) primDist = tmpDist;
2671 }
2672
2673 if (primDist < dist) {
2674 dist = primDist;
2675 closestPrimIdx = lastIdx;
2676 }
2677 }
2678
2679 return ValueType(std::sqrt(dist)) * mVoxelSize;
2680 }
2681
2684 bool
2685 updateVoxel(const Coord& ijk, const Int32 manhattanLimit,
2686 const std::vector<Fragment>& fragments,
2687 LeafNodeType& distLeaf, Int32LeafNodeType& idxLeaf, bool* updatedLeafNodes = nullptr)
2688 {
2689 Int32 closestPrimIdx = 0;
2690 const ValueType distance = computeDistance(ijk, manhattanLimit, fragments, closestPrimIdx);
2691
2692 const Index pos = LeafNodeType::coordToOffset(ijk);
2693 const bool inside = distLeaf.getValue(pos) < ValueType(0.0);
2694
2695 bool activateNeighbourVoxels = false;
2696
2697 if (!inside && distance < mExteriorBandWidth) {
2698 if (updatedLeafNodes) *updatedLeafNodes = true;
2699 activateNeighbourVoxels = (distance + mVoxelSize) < mExteriorBandWidth;
2700 distLeaf.setValueOnly(pos, distance);
2701 idxLeaf.setValueOn(pos, closestPrimIdx);
2702 } else if (inside && distance < mInteriorBandWidth) {
2703 if (updatedLeafNodes) *updatedLeafNodes = true;
2704 activateNeighbourVoxels = (distance + mVoxelSize) < mInteriorBandWidth;
2705 distLeaf.setValueOnly(pos, -distance);
2706 idxLeaf.setValueOn(pos, closestPrimIdx);
2707 }
2708
2709 return activateNeighbourVoxels;
2710 }
2711
2713
2714 BoolLeafNodeType ** const mMaskNodes;
2715 BoolTreeType * const mMaskTree;
2716 TreeType * const mDistTree;
2717 Int32TreeType * const mIndexTree;
2718
2719 MeshDataAdapter const * const mMesh;
2720
2721 BoolTreeType mNewMaskTree;
2722
2723 std::vector<LeafNodeType*> mDistNodes, mUpdatedDistNodes;
2724 std::vector<Int32LeafNodeType*> mIndexNodes, mUpdatedIndexNodes;
2725
2726 const ValueType mExteriorBandWidth, mInteriorBandWidth, mVoxelSize;
2727 }; // struct ExpandNarrowband
2728
2729
2730 template<typename TreeType>
2731 struct AddNodes {
2732 using LeafNodeType = typename TreeType::LeafNodeType;
2733
2734 AddNodes(TreeType& tree, std::vector<LeafNodeType*>& nodes)
2735 : mTree(&tree) , mNodes(&nodes)
2736 {
2737 }
2738
2739 void operator()() const {
2740 tree::ValueAccessor<TreeType> acc(*mTree);
2741 std::vector<LeafNodeType*>& nodes = *mNodes;
2742 for (size_t n = 0, N = nodes.size(); n < N; ++n) {
2743 acc.addLeaf(nodes[n]);
2744 }
2745 }
2746
2747 TreeType * const mTree;
2748 std::vector<LeafNodeType*> * const mNodes;
2749 }; // AddNodes
2750
2751
2752 template<typename TreeType, typename Int32TreeType, typename BoolTreeType, typename MeshDataAdapter>
2753 inline void
2754 expandNarrowband(
2755 TreeType& distTree,
2756 Int32TreeType& indexTree,
2757 BoolTreeType& maskTree,
2758 std::vector<typename BoolTreeType::LeafNodeType*>& maskNodes,
2759 const MeshDataAdapter& mesh,
2760 typename TreeType::ValueType exteriorBandWidth,
2761 typename TreeType::ValueType interiorBandWidth,
2762 typename TreeType::ValueType voxelSize)
2763 {
2764 ExpandNarrowband<TreeType, MeshDataAdapter> expandOp(maskNodes, maskTree,
2765 distTree, indexTree, mesh, exteriorBandWidth, interiorBandWidth, voxelSize);
2766
2767 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, maskNodes.size()), expandOp);
2768
2769 tbb::parallel_for(tbb::blocked_range<size_t>(0, expandOp.updatedIndexNodes().size()),
2770 UnionValueMasks<typename TreeType::LeafNodeType, typename Int32TreeType::LeafNodeType>(
2771 expandOp.updatedDistNodes(), expandOp.updatedIndexNodes()));
2772
2773 tbb::task_group tasks;
2774 tasks.run(AddNodes<TreeType>(distTree, expandOp.newDistNodes()));
2775 tasks.run(AddNodes<Int32TreeType>(indexTree, expandOp.newIndexNodes()));
2776 tasks.wait();
2777
2778 maskTree.clear();
2779 maskTree.merge(expandOp.newMaskTree());
2780 }
2781
2782
2784
2785
2786 // Transform values (sqrt, world space scaling and sign flip if sdf)
2787 template<typename TreeType>
2788 struct TransformValues
2789 {
2790 using LeafNodeType = typename TreeType::LeafNodeType;
2791 using ValueType = typename TreeType::ValueType;
2792
2793 TransformValues(std::vector<LeafNodeType*>& nodes,
2794 ValueType voxelSize, bool unsignedDist)
2795 : mNodes(&nodes[0])
2796 , mVoxelSize(voxelSize)
2797 , mUnsigned(unsignedDist)
2798 {
2799 }
2800
2801 void operator()(const tbb::blocked_range<size_t>& range) const {
2802
2803 typename LeafNodeType::ValueOnIter iter;
2804
2805 const bool udf = mUnsigned;
2806 const ValueType w[2] = { -mVoxelSize, mVoxelSize };
2807
2808 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
2809
2810 for (iter = mNodes[n]->beginValueOn(); iter; ++iter) {
2811 ValueType& val = const_cast<ValueType&>(iter.getValue());
2812 val = w[udf || (val < ValueType(0.0))] * std::sqrt(std::abs(val));
2813 }
2814 }
2815 }
2816
2817 private:
2818 LeafNodeType * * const mNodes;
2819 const ValueType mVoxelSize;
2820 const bool mUnsigned;
2821 };
2822
2823
2824 // Inactivate values outside the (exBandWidth, inBandWidth) range.
2825 template<typename TreeType>
2826 struct InactivateValues
2827 {
2828 using LeafNodeType = typename TreeType::LeafNodeType;
2829 using ValueType = typename TreeType::ValueType;
2830
2831 InactivateValues(std::vector<LeafNodeType*>& nodes,
2832 ValueType exBandWidth, ValueType inBandWidth)
2833 : mNodes(nodes.empty() ? nullptr : &nodes[0])
2834 , mExBandWidth(exBandWidth)
2835 , mInBandWidth(inBandWidth)
2836 {
2837 }
2838
2839 void operator()(const tbb::blocked_range<size_t>& range) const {
2840
2841 typename LeafNodeType::ValueOnIter iter;
2842 const ValueType exVal = mExBandWidth;
2843 const ValueType inVal = -mInBandWidth;
2844
2845 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
2846
2847 for (iter = mNodes[n]->beginValueOn(); iter; ++iter) {
2848
2849 ValueType& val = const_cast<ValueType&>(iter.getValue());
2850
2851 const bool inside = val < ValueType(0.0);
2852
2853 if (inside && !(val > inVal)) {
2854 val = inVal;
2855 iter.setValueOff();
2856 } else if (!inside && !(val < exVal)) {
2857 val = exVal;
2858 iter.setValueOff();
2859 }
2860 }
2861 }
2862 }
2863
2864 private:
2865 LeafNodeType * * const mNodes;
2866 const ValueType mExBandWidth, mInBandWidth;
2867 };
2868
2869
2870 template<typename TreeType>
2871 struct OffsetValues
2872 {
2873 using LeafNodeType = typename TreeType::LeafNodeType;
2874 using ValueType = typename TreeType::ValueType;
2875
2876 OffsetValues(std::vector<LeafNodeType*>& nodes, ValueType offset)
2877 : mNodes(nodes.empty() ? nullptr : &nodes[0]), mOffset(offset)
2878 {
2879 }
2880
2881 void operator()(const tbb::blocked_range<size_t>& range) const {
2882
2883 const ValueType offset = mOffset;
2884
2885 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
2886
2887 typename LeafNodeType::ValueOnIter iter = mNodes[n]->beginValueOn();
2888
2889 for (; iter; ++iter) {
2890 ValueType& val = const_cast<ValueType&>(iter.getValue());
2891 val += offset;
2892 }
2893 }
2894 }
2895
2896 private:
2897 LeafNodeType * * const mNodes;
2898 const ValueType mOffset;
2899 };
2900
2901
2902 template<typename TreeType>
2903 struct Renormalize
2904 {
2905 using LeafNodeType = typename TreeType::LeafNodeType;
2906 using ValueType = typename TreeType::ValueType;
2907
2908 Renormalize(const TreeType& tree, const std::vector<LeafNodeType*>& nodes,
2909 ValueType* buffer, ValueType voxelSize)
2910 : mTree(&tree)
2911 , mNodes(nodes.empty() ? nullptr : &nodes[0])
2912 , mBuffer(buffer)
2913 , mVoxelSize(voxelSize)
2914 {
2915 }
2916
2917 void operator()(const tbb::blocked_range<size_t>& range) const
2918 {
2919 using Vec3Type = math::Vec3<ValueType>;
2920
2921 tree::ValueAccessor<const TreeType> acc(*mTree);
2922
2923 Coord ijk;
2924 Vec3Type up, down;
2925
2926 const ValueType dx = mVoxelSize, invDx = ValueType(1.0) / mVoxelSize;
2927
2928 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
2929
2930 ValueType* bufferData = &mBuffer[n * LeafNodeType::SIZE];
2931
2932 typename LeafNodeType::ValueOnCIter iter = mNodes[n]->cbeginValueOn();
2933 for (; iter; ++iter) {
2934
2935 const ValueType phi0 = *iter;
2936
2937 ijk = iter.getCoord();
2938
2939 up[0] = acc.getValue(ijk.offsetBy(1, 0, 0)) - phi0;
2940 up[1] = acc.getValue(ijk.offsetBy(0, 1, 0)) - phi0;
2941 up[2] = acc.getValue(ijk.offsetBy(0, 0, 1)) - phi0;
2942
2943 down[0] = phi0 - acc.getValue(ijk.offsetBy(-1, 0, 0));
2944 down[1] = phi0 - acc.getValue(ijk.offsetBy(0, -1, 0));
2945 down[2] = phi0 - acc.getValue(ijk.offsetBy(0, 0, -1));
2946
2947 const ValueType normSqGradPhi = math::GodunovsNormSqrd(phi0 > 0.0, down, up);
2948
2949 const ValueType diff = math::Sqrt(normSqGradPhi) * invDx - ValueType(1.0);
2950 const ValueType S = phi0 / (math::Sqrt(math::Pow2(phi0) + normSqGradPhi));
2951
2952 bufferData[iter.pos()] = phi0 - dx * S * diff;
2953 }
2954 }
2955 }
2956
2957 private:
2958 TreeType const * const mTree;
2959 LeafNodeType const * const * const mNodes;
2960 ValueType * const mBuffer;
2961
2962 const ValueType mVoxelSize;
2963 };
2964
2965
2966 template<typename TreeType>
2967 struct MinCombine
2968 {
2969 using LeafNodeType = typename TreeType::LeafNodeType;
2970 using ValueType = typename TreeType::ValueType;
2971
2972 MinCombine(std::vector<LeafNodeType*>& nodes, const ValueType* buffer)
2973 : mNodes(nodes.empty() ? nullptr : &nodes[0]), mBuffer(buffer)
2974 {
2975 }
2976
2977 void operator()(const tbb::blocked_range<size_t>& range) const {
2978
2979 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
2980
2981 const ValueType* bufferData = &mBuffer[n * LeafNodeType::SIZE];
2982
2983 typename LeafNodeType::ValueOnIter iter = mNodes[n]->beginValueOn();
2984
2985 for (; iter; ++iter) {
2986 ValueType& val = const_cast<ValueType&>(iter.getValue());
2987 val = std::min(val, bufferData[iter.pos()]);
2988 }
2989 }
2990 }
2991
2992 private:
2993 LeafNodeType * * const mNodes;
2994 ValueType const * const mBuffer;
2995 };
2996
2997
2998 } // mesh_to_volume_internal namespace
2999
3000
3002
3003 // Utility method implementation
3004
3005
3006 template <typename FloatTreeT>
3007 inline void
3008 traceExteriorBoundaries(FloatTreeT& tree)
3009 {
3010 using ConnectivityTable = mesh_to_volume_internal::LeafNodeConnectivityTable<FloatTreeT>;
3011
3012 ConnectivityTable nodeConnectivity(tree);
3013
3014 std::vector<size_t> zStartNodes, yStartNodes, xStartNodes;
3015
3016 for (size_t n = 0; n < nodeConnectivity.size(); ++n) {
3017 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevX()[n]) {
3018 xStartNodes.push_back(n);
3019 }
3020
3021 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevY()[n]) {
3022 yStartNodes.push_back(n);
3023 }
3024
3025 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevZ()[n]) {
3026 zStartNodes.push_back(n);
3027 }
3028 }
3029
3030 using SweepingOp = mesh_to_volume_internal::SweepExteriorSign<FloatTreeT>;
3031
3032 tbb::parallel_for(tbb::blocked_range<size_t>(0, zStartNodes.size()),
3033 SweepingOp(SweepingOp::Z_AXIS, zStartNodes, nodeConnectivity));
3034
3035 tbb::parallel_for(tbb::blocked_range<size_t>(0, yStartNodes.size()),
3036 SweepingOp(SweepingOp::Y_AXIS, yStartNodes, nodeConnectivity));
3037
3038 tbb::parallel_for(tbb::blocked_range<size_t>(0, xStartNodes.size()),
3039 SweepingOp(SweepingOp::X_AXIS, xStartNodes, nodeConnectivity));
3040
3041 const size_t numLeafNodes = nodeConnectivity.size();
3042 const size_t numVoxels = numLeafNodes * FloatTreeT::LeafNodeType::SIZE;
3043
3044 boost::scoped_array<bool> changedNodeMaskA(new bool[numLeafNodes]);
3045 boost::scoped_array<bool> changedNodeMaskB(new bool[numLeafNodes]);
3046 boost::scoped_array<bool> changedVoxelMask(new bool[numVoxels]);
3047
3048 mesh_to_volume_internal::fillArray(changedNodeMaskA.get(), true, numLeafNodes);
3049 mesh_to_volume_internal::fillArray(changedNodeMaskB.get(), false, numLeafNodes);
3050 mesh_to_volume_internal::fillArray(changedVoxelMask.get(), false, numVoxels);
3051
3052 const tbb::blocked_range<size_t> nodeRange(0, numLeafNodes);
3053
3054 bool nodesUpdated = false;
3055 do {
3056 tbb::parallel_for(nodeRange, mesh_to_volume_internal::SeedFillExteriorSign<FloatTreeT>(
3057 nodeConnectivity.nodes(), changedNodeMaskA.get()));
3058
3059 tbb::parallel_for(nodeRange, mesh_to_volume_internal::SeedPoints<FloatTreeT>(
3060 nodeConnectivity, changedNodeMaskA.get(), changedNodeMaskB.get(),
3061 changedVoxelMask.get()));
3062
3063 changedNodeMaskA.swap(changedNodeMaskB);
3064
3065 nodesUpdated = false;
3066 for (size_t n = 0; n < numLeafNodes; ++n) {
3067 nodesUpdated |= changedNodeMaskA[n];
3068 if (nodesUpdated) break;
3069 }
3070
3071 if (nodesUpdated) {
3072 tbb::parallel_for(nodeRange, mesh_to_volume_internal::SyncVoxelMask<FloatTreeT>(
3073 nodeConnectivity.nodes(), changedNodeMaskA.get(), changedVoxelMask.get()));
3074 }
3075 } while (nodesUpdated);
3076
3077 } // void traceExteriorBoundaries()
3078
3079
3081
3082
3083 template <typename GridType, typename MeshDataAdapter, typename Interrupter>
3084 inline typename GridType::Ptr
3085 meshToVolume(
3086 Interrupter& interrupter,
3087 const MeshDataAdapter& mesh,
3088 const math::Transform& transform,
3089 float exteriorBandWidth,
3090 float interiorBandWidth,
3091 int flags,
3092 typename GridType::template ValueConverter<Int32>::Type * polygonIndexGrid)
3093 {
3094 using GridTypePtr = typename GridType::Ptr;
3095 using TreeType = typename GridType::TreeType;
3096 using LeafNodeType = typename TreeType::LeafNodeType;
3097 using ValueType = typename GridType::ValueType;
3098
3099 using Int32GridType = typename GridType::template ValueConverter<Int32>::Type;
3100 using Int32TreeType = typename Int32GridType::TreeType;
3101
3102 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
3103
3105
3106 // Setup
3107
3108 GridTypePtr distGrid(new GridType(std::numeric_limits<ValueType>::max()));
3109 distGrid->setTransform(transform.copy());
3110
3111 ValueType exteriorWidth = ValueType(exteriorBandWidth);
3112 ValueType interiorWidth = ValueType(interiorBandWidth);
3113
3114 // Note: inf interior width is all right, this value makes the converter fill
3115 // interior regions with distance values.
3116 if (!std::isfinite(exteriorWidth) || std::isnan(interiorWidth)) {
3117 std::stringstream msg;
3118 msg << "Illegal narrow band width: exterior = " << exteriorWidth
3119 << ", interior = " << interiorWidth;
3120 OPENVDB_LOG_DEBUG(msg.str());
3121 return distGrid;
3122 }
3123
3124 const ValueType voxelSize = ValueType(transform.voxelSize()[0]);
3125
3126 if (!std::isfinite(voxelSize) || math::isZero(voxelSize)) {
3127 std::stringstream msg;
3128 msg << "Illegal transform, voxel size = " << voxelSize;
3129 OPENVDB_LOG_DEBUG(msg.str());
3130 return distGrid;
3131 }
3132
3133 // Convert narrow band width from voxel units to world space units.
3134 exteriorWidth *= voxelSize;
3135 // Avoid the unit conversion if the interior band width is set to
3136 // inf or std::numeric_limits<float>::max().
3137 if (interiorWidth < std::numeric_limits<ValueType>::max()) {
3138 interiorWidth *= voxelSize;
3139 }
3140
3141 const bool computeSignedDistanceField = (flags & UNSIGNED_DISTANCE_FIELD) == 0;
3142 const bool removeIntersectingVoxels = (flags & DISABLE_INTERSECTING_VOXEL_REMOVAL) == 0;
3143 const bool renormalizeValues = (flags & DISABLE_RENORMALIZATION) == 0;
3144 const bool trimNarrowBand = (flags & DISABLE_NARROW_BAND_TRIMMING) == 0;
3145
3146 Int32GridType* indexGrid = nullptr;
3147
3148 typename Int32GridType::Ptr temporaryIndexGrid;
3149
3150 if (polygonIndexGrid) {
3151 indexGrid = polygonIndexGrid;
3152 } else {
3153 temporaryIndexGrid.reset(new Int32GridType(Int32(util::INVALID_IDX)));
3154 indexGrid = temporaryIndexGrid.get();
3155 }
3156
3157 indexGrid->newTree();
3158 indexGrid->setTransform(transform.copy());
3159
3160 if (computeSignedDistanceField) {
3161 distGrid->setGridClass(GRID_LEVEL_SET);
3162 } else {
3163 distGrid->setGridClass(GRID_UNKNOWN);
3164 interiorWidth = ValueType(0.0);
3165 }
3166
3167 TreeType& distTree = distGrid->tree();
3168 Int32TreeType& indexTree = indexGrid->tree();
3169
3170
3172
3173 // Voxelize mesh
3174
3175 {
3176 using VoxelizationDataType = mesh_to_volume_internal::VoxelizationData<TreeType>;
3177 using DataTable = tbb::enumerable_thread_specific<typename VoxelizationDataType::Ptr>;
3178
3179 DataTable data;
3180 using Voxelizer =
3181 mesh_to_volume_internal::VoxelizePolygons<TreeType, MeshDataAdapter, Interrupter>;
3182
3183 const tbb::blocked_range<size_t> polygonRange(0, mesh.polygonCount());
3184
3185 tbb::parallel_for(polygonRange, Voxelizer(data, mesh, &interrupter));
3186
3187 for (typename DataTable::iterator i = data.begin(); i != data.end(); ++i) {
3188 VoxelizationDataType& dataItem = **i;
3189 mesh_to_volume_internal::combineData(
3190 distTree, indexTree, dataItem.distTree, dataItem.indexTree);
3191 }
3192 }
3193
3194 // The progress estimates are based on the observed average time for a few different
3195 // test cases and is only intended to provide some rough progression feedback to the user.
3196 if (interrupter.wasInterrupted(30)) return distGrid;
3197
3198
3200
3201 // Classify interior and exterior regions
3202
3203 if (computeSignedDistanceField) {
3204
3205 // Determines the inside/outside state for the narrow band of voxels.
3206 traceExteriorBoundaries(distTree);
3207
3208 std::vector<LeafNodeType*> nodes;
3209 nodes.reserve(distTree.leafCount());
3210 distTree.getNodes(nodes);
3211
3212 const tbb::blocked_range<size_t> nodeRange(0, nodes.size());
3213
3214 using SignOp =
3215 mesh_to_volume_internal::ComputeIntersectingVoxelSign<TreeType, MeshDataAdapter>;
3216
3217 tbb::parallel_for(nodeRange, SignOp(nodes, distTree, indexTree, mesh));
3218
3219 if (interrupter.wasInterrupted(45)) return distGrid;
3220
3221 // Remove voxels created by self intersecting portions of the mesh.
3222 if (removeIntersectingVoxels) {
3223
3224 tbb::parallel_for(nodeRange,
3225 mesh_to_volume_internal::ValidateIntersectingVoxels<TreeType>(distTree, nodes));
3226
3227 tbb::parallel_for(nodeRange,
3228 mesh_to_volume_internal::RemoveSelfIntersectingSurface<TreeType>(
3229 nodes, distTree, indexTree));
3230
3231 tools::pruneInactive(distTree, /*threading=*/true);
3232 tools::pruneInactive(indexTree, /*threading=*/true);
3233 }
3234 }
3235
3236 if (interrupter.wasInterrupted(50)) return distGrid;
3237
3238 if (distTree.activeVoxelCount() == 0) {
3239 distTree.clear();
3240 distTree.root().setBackground(exteriorWidth, /*updateChildNodes=*/false);
3241 return distGrid;
3242 }
3243
3244 // Transform values (world space scaling etc.).
3245 {
3246 std::vector<LeafNodeType*> nodes;
3247 nodes.reserve(distTree.leafCount());
3248 distTree.getNodes(nodes);
3249
3250 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3251 mesh_to_volume_internal::TransformValues<TreeType>(
3252 nodes, voxelSize, !computeSignedDistanceField));
3253 }
3254
3255 // Propagate sign information into tile regions.
3256 if (computeSignedDistanceField) {
3257 distTree.root().setBackground(exteriorWidth, /*updateChildNodes=*/false);
3258 tools::signedFloodFillWithValues(distTree, exteriorWidth, -interiorWidth);
3259 } else {
3260 tools::changeBackground(distTree, exteriorWidth);
3261 }
3262
3263 if (interrupter.wasInterrupted(54)) return distGrid;
3264
3265
3267
3268 // Expand the narrow band region
3269
3270 const ValueType minBandWidth = voxelSize * ValueType(2.0);
3271
3272 if (interiorWidth > minBandWidth || exteriorWidth > minBandWidth) {
3273
3274 // Create the initial voxel mask.
3275 BoolTreeType maskTree(false);
3276
3277 {
3278 std::vector<LeafNodeType*> nodes;
3279 nodes.reserve(distTree.leafCount());
3280 distTree.getNodes(nodes);
3281
3282 mesh_to_volume_internal::ConstructVoxelMask<TreeType> op(maskTree, distTree, nodes);
3283 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), op);
3284 }
3285
3286 // Progress estimation
3287 unsigned maxIterations = std::numeric_limits<unsigned>::max();
3288
3289 float progress = 54.0f, step = 0.0f;
3290 double estimated =
3291 2.0 * std::ceil((std::max(interiorWidth, exteriorWidth) - minBandWidth) / voxelSize);
3292
3293 if (estimated < double(maxIterations)) {
3294 maxIterations = unsigned(estimated);
3295 step = 40.0f / float(maxIterations);
3296 }
3297
3298 std::vector<typename BoolTreeType::LeafNodeType*> maskNodes;
3299
3300 unsigned count = 0;
3301 while (true) {
3302
3303 if (interrupter.wasInterrupted(int(progress))) return distGrid;
3304
3305 const size_t maskNodeCount = maskTree.leafCount();
3306 if (maskNodeCount == 0) break;
3307
3308 maskNodes.clear();
3309 maskNodes.reserve(maskNodeCount);
3310 maskTree.getNodes(maskNodes);
3311
3312 const tbb::blocked_range<size_t> range(0, maskNodes.size());
3313
3314 tbb::parallel_for(range,
3315 mesh_to_volume_internal::DiffLeafNodeMask<TreeType>(distTree, maskNodes));
3316
3317 mesh_to_volume_internal::expandNarrowband(distTree, indexTree, maskTree, maskNodes,
3318 mesh, exteriorWidth, interiorWidth, voxelSize);
3319
3320 if ((++count) >= maxIterations) break;
3321 progress += step;
3322 }
3323 }
3324
3325 if (interrupter.wasInterrupted(94)) return distGrid;
3326
3327 if (!polygonIndexGrid) indexGrid->clear();
3328
3329
3331
3332 // Renormalize distances to smooth out bumps caused by self intersecting
3333 // and overlapping portions of the mesh and renormalize the level set.
3334
3335 if (computeSignedDistanceField && renormalizeValues) {
3336
3337 std::vector<LeafNodeType*> nodes;
3338 nodes.reserve(distTree.leafCount());
3339 distTree.getNodes(nodes);
3340
3341 boost::scoped_array<ValueType> buffer(new ValueType[LeafNodeType::SIZE * nodes.size()]);
3342
3343 const ValueType offset = ValueType(0.8 * voxelSize);
3344
3345 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3346 mesh_to_volume_internal::OffsetValues<TreeType>(nodes, -offset));
3347
3348 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3349 mesh_to_volume_internal::Renormalize<TreeType>(
3350 distTree, nodes, buffer.get(), voxelSize));
3351
3352 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3353 mesh_to_volume_internal::MinCombine<TreeType>(nodes, buffer.get()));
3354
3355 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3356 mesh_to_volume_internal::OffsetValues<TreeType>(
3357 nodes, offset - mesh_to_volume_internal::Tolerance<ValueType>::epsilon()));
3358 }
3359
3360 if (interrupter.wasInterrupted(99)) return distGrid;
3361
3362
3364
3365 // Remove active voxels that exceed the narrow band limits
3366
3367 if (trimNarrowBand && std::min(interiorWidth, exteriorWidth) < voxelSize * ValueType(4.0)) {
3368
3369 std::vector<LeafNodeType*> nodes;
3370 nodes.reserve(distTree.leafCount());
3371 distTree.getNodes(nodes);
3372
3373 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3374 mesh_to_volume_internal::InactivateValues<TreeType>(
3375 nodes, exteriorWidth, computeSignedDistanceField ? interiorWidth : exteriorWidth));
3376
3377 tools::pruneLevelSet(
3378 distTree, exteriorWidth, computeSignedDistanceField ? -interiorWidth : -exteriorWidth);
3379 }
3380
3381 return distGrid;
3382 }
3383
3384
3385 template <typename GridType, typename MeshDataAdapter>
3386 inline typename GridType::Ptr
3387 meshToVolume(
3388 const MeshDataAdapter& mesh,
3389 const math::Transform& transform,
3390 float exteriorBandWidth,
3391 float interiorBandWidth,
3392 int flags,
3393 typename GridType::template ValueConverter<Int32>::Type * polygonIndexGrid)
3394 {
3395 util::NullInterrupter nullInterrupter;
3396 return meshToVolume<GridType>(nullInterrupter, mesh, transform,
3397 exteriorBandWidth, interiorBandWidth, flags, polygonIndexGrid);
3398 }
3399
3400
3402
3403
3404 //{
3406
3408 template<typename GridType, typename Interrupter>
3409 inline typename std::enable_if<std::is_floating_point<typename GridType::ValueType>::value,
3410 typename GridType::Ptr>::type
3411 doMeshConversion(
3412 Interrupter& interrupter,
3413 const openvdb::math::Transform& xform,
3414 const std::vector<Vec3s>& points,
3415 const std::vector<Vec3I>& triangles,
3416 const std::vector<Vec4I>& quads,
3417 float exBandWidth,
3418 float inBandWidth,
3419 bool unsignedDistanceField = false)
3420 {
3421 if (points.empty()) {
3422 return typename GridType::Ptr(new GridType(typename GridType::ValueType(exBandWidth)));
3423 }
3424
3425 const size_t numPoints = points.size();
3426 boost::scoped_array<Vec3s> indexSpacePoints(new Vec3s[numPoints]);
3427
3428 // transform points to local grid index space
3429 tbb::parallel_for(tbb::blocked_range<size_t>(0, numPoints),
3430 mesh_to_volume_internal::TransformPoints<Vec3s>(
3431 &points[0], indexSpacePoints.get(), xform));
3432
3433 const int conversionFlags = unsignedDistanceField ? UNSIGNED_DISTANCE_FIELD : 0;
3434
3435 if (quads.empty()) {
3436
3437 QuadAndTriangleDataAdapter<Vec3s, Vec3I>
3438 mesh(indexSpacePoints.get(), numPoints, &triangles[0], triangles.size());
3439
3440 return meshToVolume<GridType>(mesh, xform, exBandWidth, inBandWidth, conversionFlags);
3441
3442 } else if (triangles.empty()) {
3443
3444 QuadAndTriangleDataAdapter<Vec3s, Vec4I>
3445 mesh(indexSpacePoints.get(), numPoints, &quads[0], quads.size());
3446
3447 return meshToVolume<GridType>(mesh, xform, exBandWidth, inBandWidth, conversionFlags);
3448 }
3449
3450 // pack primitives
3451
3452 const size_t numPrimitives = triangles.size() + quads.size();
3453 boost::scoped_array<Vec4I> prims(new Vec4I[numPrimitives]);
3454
3455 for (size_t n = 0, N = triangles.size(); n < N; ++n) {
3456 const Vec3I& triangle = triangles[n];
3457 Vec4I& prim = prims[n];
3458 prim[0] = triangle[0];
3459 prim[1] = triangle[1];
3460 prim[2] = triangle[2];
3461 prim[3] = util::INVALID_IDX;
3462 }
3463
3464 const size_t offset = triangles.size();
3465 for (size_t n = 0, N = quads.size(); n < N; ++n) {
3466 prims[offset + n] = quads[n];
3467 }
3468
3469 QuadAndTriangleDataAdapter<Vec3s, Vec4I>
3470 mesh(indexSpacePoints.get(), numPoints, prims.get(), numPrimitives);
3471
3472 return meshToVolume<GridType>(interrupter, mesh, xform,
3473 exBandWidth, inBandWidth, conversionFlags);
3474 }
3475
3476
3479 template<typename GridType, typename Interrupter>
3480 inline typename std::enable_if<!std::is_floating_point<typename GridType::ValueType>::value,
3481 typename GridType::Ptr>::type
3482 doMeshConversion(
3483 Interrupter&,
3484 const math::Transform& /*xform*/,
3485 const std::vector<Vec3s>& /*points*/,
3486 const std::vector<Vec3I>& /*triangles*/,
3487 const std::vector<Vec4I>& /*quads*/,
3488 float /*exBandWidth*/,
3489 float /*inBandWidth*/,
3490 bool /*unsignedDistanceField*/ = false)
3491 {
3492 OPENVDB_THROW(TypeError,
3493 "mesh to volume conversion is supported only for scalar floating-point grids");
3494 }
3495
3497 //}
3498
3499
3501
3502
3503 template<typename GridType>
3504 inline typename GridType::Ptr
3505 meshToLevelSet(
3506 const openvdb::math::Transform& xform,
3507 const std::vector<Vec3s>& points,
3508 const std::vector<Vec3I>& triangles,
3509 float halfWidth)
3510 {
3511 util::NullInterrupter nullInterrupter;
3512 std::vector<Vec4I> quads(0);
3513 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles, quads,
3514 halfWidth, halfWidth);
3515 }
3516
3517
3518 template<typename GridType, typename Interrupter>
3519 inline typename GridType::Ptr
3520 meshToLevelSet(
3521 Interrupter& interrupter,
3522 const openvdb::math::Transform& xform,
3523 const std::vector<Vec3s>& points,
3524 const std::vector<Vec3I>& triangles,
3525 float halfWidth)
3526 {
3527 std::vector<Vec4I> quads(0);
3528 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3529 halfWidth, halfWidth);
3530 }
3531
3532
3533 template<typename GridType>
3534 inline typename GridType::Ptr
3535 meshToLevelSet(
3536 const openvdb::math::Transform& xform,
3537 const std::vector<Vec3s>& points,
3538 const std::vector<Vec4I>& quads,
3539 float halfWidth)
3540 {
3541 util::NullInterrupter nullInterrupter;
3542 std::vector<Vec3I> triangles(0);
3543 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles, quads,
3544 halfWidth, halfWidth);
3545 }
3546
3547
3548 template<typename GridType, typename Interrupter>
3549 inline typename GridType::Ptr
3550 meshToLevelSet(
3551 Interrupter& interrupter,
3552 const openvdb::math::Transform& xform,
3553 const std::vector<Vec3s>& points,
3554 const std::vector<Vec4I>& quads,
3555 float halfWidth)
3556 {
3557 std::vector<Vec3I> triangles(0);
3558 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3559 halfWidth, halfWidth);
3560 }
3561
3562
3563 template<typename GridType>
3564 inline typename GridType::Ptr
3565 meshToLevelSet(
3566 const openvdb::math::Transform& xform,
3567 const std::vector<Vec3s>& points,
3568 const std::vector<Vec3I>& triangles,
3569 const std::vector<Vec4I>& quads,
3570 float halfWidth)
3571 {
3572 util::NullInterrupter nullInterrupter;
3573 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles, quads,
3574 halfWidth, halfWidth);
3575 }
3576
3577
3578 template<typename GridType, typename Interrupter>
3579 inline typename GridType::Ptr
3580 meshToLevelSet(
3581 Interrupter& interrupter,
3582 const openvdb::math::Transform& xform,
3583 const std::vector<Vec3s>& points,
3584 const std::vector<Vec3I>& triangles,
3585 const std::vector<Vec4I>& quads,
3586 float halfWidth)
3587 {
3588 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3589 halfWidth, halfWidth);
3590 }
3591
3592
3593 template<typename GridType>
3594 inline typename GridType::Ptr
3595 meshToSignedDistanceField(
3596 const openvdb::math::Transform& xform,
3597 const std::vector<Vec3s>& points,
3598 const std::vector<Vec3I>& triangles,
3599 const std::vector<Vec4I>& quads,
3600 float exBandWidth,
3601 float inBandWidth)
3602 {
3603 util::NullInterrupter nullInterrupter;
3604 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles,
3605 quads, exBandWidth, inBandWidth);
3606 }
3607
3608
3609 template<typename GridType, typename Interrupter>
3610 inline typename GridType::Ptr
3611 meshToSignedDistanceField(
3612 Interrupter& interrupter,
3613 const openvdb::math::Transform& xform,
3614 const std::vector<Vec3s>& points,
3615 const std::vector<Vec3I>& triangles,
3616 const std::vector<Vec4I>& quads,
3617 float exBandWidth,
3618 float inBandWidth)
3619 {
3620 return doMeshConversion<GridType>(interrupter, xform, points, triangles,
3621 quads, exBandWidth, inBandWidth);
3622 }
3623
3624
3625 template<typename GridType>
3626 inline typename GridType::Ptr
3627 meshToUnsignedDistanceField(
3628 const openvdb::math::Transform& xform,
3629 const std::vector<Vec3s>& points,
3630 const std::vector<Vec3I>& triangles,
3631 const std::vector<Vec4I>& quads,
3632 float bandWidth)
3633 {
3634 util::NullInterrupter nullInterrupter;
3635 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles, quads,
3636 bandWidth, bandWidth, true);
3637 }
3638
3639
3640 template<typename GridType, typename Interrupter>
3641 inline typename GridType::Ptr
3642 meshToUnsignedDistanceField(
3643 Interrupter& interrupter,
3644 const openvdb::math::Transform& xform,
3645 const std::vector<Vec3s>& points,
3646 const std::vector<Vec3I>& triangles,
3647 const std::vector<Vec4I>& quads,
3648 float bandWidth)
3649 {
3650 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3651 bandWidth, bandWidth, true);
3652 }
3653
3654
3656
3657
3658 // Required by several of the tree nodes
3659 inline std::ostream&
3660 operator<<(std::ostream& ostr, const MeshToVoxelEdgeData::EdgeData& rhs)
3661 {
3662 ostr << "{[ " << rhs.mXPrim << ", " << rhs.mXDist << "]";
3663 ostr << " [ " << rhs.mYPrim << ", " << rhs.mYDist << "]";
3664 ostr << " [ " << rhs.mZPrim << ", " << rhs.mZDist << "]}";
3665 return ostr;
3666 }
3667
3668 // Required by math::Abs
3669 inline MeshToVoxelEdgeData::EdgeData
3670 Abs(const MeshToVoxelEdgeData::EdgeData& x)
3671 {
3672 return x;
3673 }
3674
3675
3677
3678
3679 class MeshToVoxelEdgeData::GenEdgeData
3680 {
3681 public:
3682
3683 GenEdgeData(
3684 const std::vector<Vec3s>& pointList,
3685 const std::vector<Vec4I>& polygonList);
3686
3687 void run(bool threaded = true);
3688
3689 GenEdgeData(GenEdgeData& rhs, tbb::split);
3690 inline void operator() (const tbb::blocked_range<size_t> &range);
3691 inline void join(GenEdgeData& rhs);
3692
3693 inline TreeType& tree() { return mTree; }
3694
3695 private:
3696 void operator=(const GenEdgeData&) {}
3697
3698 struct Primitive { Vec3d a, b, c, d; Int32 index; };
3699
3700 template<bool IsQuad>
3701 inline void voxelize(const Primitive&);
3702
3703 template<bool IsQuad>
3704 inline bool evalPrimitive(const Coord&, const Primitive&);
3705
3706 inline bool rayTriangleIntersection( const Vec3d& origin, const Vec3d& dir,
3707 const Vec3d& a, const Vec3d& b, const Vec3d& c, double& t);
3708
3709
3710 TreeType mTree;
3711 Accessor mAccessor;
3712
3713 const std::vector<Vec3s>& mPointList;
3714 const std::vector<Vec4I>& mPolygonList;
3715
3716 // Used internally for acceleration
3717 using IntTreeT = TreeType::ValueConverter<Int32>::Type;
3718 IntTreeT mLastPrimTree;
3719 tree::ValueAccessor<IntTreeT> mLastPrimAccessor;
3720 }; // class MeshToVoxelEdgeData::GenEdgeData
3721
3722
3723 inline
3724 MeshToVoxelEdgeData::GenEdgeData::GenEdgeData(
3725 const std::vector<Vec3s>& pointList,
3726 const std::vector<Vec4I>& polygonList)
3727 : mTree(EdgeData())
3728 , mAccessor(mTree)
3729 , mPointList(pointList)
3730 , mPolygonList(polygonList)
3731 , mLastPrimTree(Int32(util::INVALID_IDX))
3732 , mLastPrimAccessor(mLastPrimTree)
3733 {
3734 }
3735
3736
3737 inline
3738 MeshToVoxelEdgeData::GenEdgeData::GenEdgeData(GenEdgeData& rhs, tbb::split)
3739 : mTree(EdgeData())
3740 , mAccessor(mTree)
3741 , mPointList(rhs.mPointList)
3742 , mPolygonList(rhs.mPolygonList)
3743 , mLastPrimTree(Int32(util::INVALID_IDX))
3744 , mLastPrimAccessor(mLastPrimTree)
3745 {
3746 }
3747
3748
3749 inline void
3750 MeshToVoxelEdgeData::GenEdgeData::run(bool threaded)
3751 {
3752 if (threaded) {
3753 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, mPolygonList.size()), *this);
3754 } else {
3755 (*this)(tbb::blocked_range<size_t>(0, mPolygonList.size()));
3756 }
3757 }
3758
3759
3760 inline void
3761 MeshToVoxelEdgeData::GenEdgeData::join(GenEdgeData& rhs)
3762 {
3763 using RootNodeType = TreeType::RootNodeType;
3764 using NodeChainType = RootNodeType::NodeChainType;
3765 static_assert(boost::mpl::size<NodeChainType>::value > 1, "expected tree height > 1");
3766 using InternalNodeType = boost::mpl::at<NodeChainType, boost::mpl::int_<1> >::type;
3767
3768 Coord ijk;
3769 Index offset;
3770
3771 rhs.mTree.clearAllAccessors();
3772
3773 TreeType::LeafIter leafIt = rhs.mTree.beginLeaf();
3774 for ( ; leafIt; ++leafIt) {
3775 ijk = leafIt->origin();
3776
3777 TreeType::LeafNodeType* lhsLeafPt = mTree.probeLeaf(ijk);
3778
3779 if (!lhsLeafPt) {
3780
3781 mAccessor.addLeaf(rhs.mAccessor.probeLeaf(ijk));
3782 InternalNodeType* node = rhs.mAccessor.getNode<InternalNodeType>();
3783 node->stealNode<TreeType::LeafNodeType>(ijk, EdgeData(), false);
3784 rhs.mAccessor.clear();
3785
3786 } else {
3787
3788 TreeType::LeafNodeType::ValueOnCIter it = leafIt->cbeginValueOn();
3789 for ( ; it; ++it) {
3790
3791 offset = it.pos();
3792 const EdgeData& rhsValue = it.getValue();
3793
3794 if (!lhsLeafPt->isValueOn(offset)) {
3795 lhsLeafPt->setValueOn(offset, rhsValue);
3796 } else {
3797
3798 EdgeData& lhsValue = const_cast<EdgeData&>(lhsLeafPt->getValue(offset));
3799
3800 if (rhsValue.mXDist < lhsValue.mXDist) {
3801 lhsValue.mXDist = rhsValue.mXDist;
3802 lhsValue.mXPrim = rhsValue.mXPrim;
3803 }
3804
3805 if (rhsValue.mYDist < lhsValue.mYDist) {
3806 lhsValue.mYDist = rhsValue.mYDist;
3807 lhsValue.mYPrim = rhsValue.mYPrim;
3808 }
3809
3810 if (rhsValue.mZDist < lhsValue.mZDist) {
3811 lhsValue.mZDist = rhsValue.mZDist;
3812 lhsValue.mZPrim = rhsValue.mZPrim;
3813 }
3814
3815 }
3816 } // end value iteration
3817 }
3818 } // end leaf iteration
3819 }
3820
3821
3822 inline void
3823 MeshToVoxelEdgeData::GenEdgeData::operator()(const tbb::blocked_range<size_t> &range)
3824 {
3825 Primitive prim;
3826
3827 for (size_t n = range.begin(); n < range.end(); ++n) {
3828
3829 const Vec4I& verts = mPolygonList[n];
3830
3831 prim.index = Int32(n);
3832 prim.a = Vec3d(mPointList[verts[0]]);
3833 prim.b = Vec3d(mPointList[verts[1]]);
3834 prim.c = Vec3d(mPointList[verts[2]]);
3835
3836 if (util::INVALID_IDX != verts[3]) {
3837 prim.d = Vec3d(mPointList[verts[3]]);
3838 voxelize<true>(prim);
3839 } else {
3840 voxelize<false>(prim);
3841 }
3842 }
3843 }
3844
3845
3846 template<bool IsQuad>
3847 inline void
3848 MeshToVoxelEdgeData::GenEdgeData::voxelize(const Primitive& prim)
3849 {
3850 std::deque<Coord> coordList;
3851 Coord ijk, nijk;
3852
3853 ijk = Coord::floor(prim.a);
3854 coordList.push_back(ijk);
3855
3856 evalPrimitive<IsQuad>(ijk, prim);
3857
3858 while (!coordList.empty()) {
3859
3860 ijk = coordList.back();
3861 coordList.pop_back();
3862
3863 for (Int32 i = 0; i < 26; ++i) {
3864 nijk = ijk + util::COORD_OFFSETS[i];
3865
3866 if (prim.index != mLastPrimAccessor.getValue(nijk)) {
3867 mLastPrimAccessor.setValue(nijk, prim.index);
3868 if(evalPrimitive<IsQuad>(nijk, prim)) coordList.push_back(nijk);
3869 }
3870 }
3871 }
3872 }
3873
3874
3875 template<bool IsQuad>
3876 inline bool
3877 MeshToVoxelEdgeData::GenEdgeData::evalPrimitive(const Coord& ijk, const Primitive& prim)
3878 {
3879 Vec3d uvw, org(ijk[0], ijk[1], ijk[2]);
3880 bool intersecting = false;
3881 double t;
3882
3883 EdgeData edgeData;
3884 mAccessor.probeValue(ijk, edgeData);
3885
3886 // Evaluate first triangle
3887 double dist = (org -
3888 closestPointOnTriangleToPoint(prim.a, prim.c, prim.b, org, uvw)).lengthSqr();
3889
3890 if (rayTriangleIntersection(org, Vec3d(1.0, 0.0, 0.0), prim.a, prim.c, prim.b, t)) {
3891 if (t < edgeData.mXDist) {
3892 edgeData.mXDist = float(t);
3893 edgeData.mXPrim = prim.index;
3894 intersecting = true;
3895 }
3896 }
3897
3898 if (rayTriangleIntersection(org, Vec3d(0.0, 1.0, 0.0), prim.a, prim.c, prim.b, t)) {
3899 if (t < edgeData.mYDist) {
3900 edgeData.mYDist = float(t);
3901 edgeData.mYPrim = prim.index;
3902 intersecting = true;
3903 }
3904 }
3905
3906 if (rayTriangleIntersection(org, Vec3d(0.0, 0.0, 1.0), prim.a, prim.c, prim.b, t)) {
3907 if (t < edgeData.mZDist) {
3908 edgeData.mZDist = float(t);
3909 edgeData.mZPrim = prim.index;
3910 intersecting = true;
3911 }
3912 }
3913
3914 if (IsQuad) {
3915 // Split quad into a second triangle and calculate distance.
3916 double secondDist = (org -
3917 closestPointOnTriangleToPoint(prim.a, prim.d, prim.c, org, uvw)).lengthSqr();
3918
3919 if (secondDist < dist) dist = secondDist;
3920
3921 if (rayTriangleIntersection(org, Vec3d(1.0, 0.0, 0.0), prim.a, prim.d, prim.c, t)) {
3922 if (t < edgeData.mXDist) {
3923 edgeData.mXDist = float(t);
3924 edgeData.mXPrim = prim.index;
3925 intersecting = true;
3926 }
3927 }
3928
3929 if (rayTriangleIntersection(org, Vec3d(0.0, 1.0, 0.0), prim.a, prim.d, prim.c, t)) {
3930 if (t < edgeData.mYDist) {
3931 edgeData.mYDist = float(t);
3932 edgeData.mYPrim = prim.index;
3933 intersecting = true;
3934 }
3935 }
3936
3937 if (rayTriangleIntersection(org, Vec3d(0.0, 0.0, 1.0), prim.a, prim.d, prim.c, t)) {
3938 if (t < edgeData.mZDist) {
3939 edgeData.mZDist = float(t);
3940 edgeData.mZPrim = prim.index;
3941 intersecting = true;
3942 }
3943 }
3944 }
3945
3946 if (intersecting) mAccessor.setValue(ijk, edgeData);
3947
3948 return (dist < 0.86602540378443861);
3949 }
3950
3951
3952 inline bool
3953 MeshToVoxelEdgeData::GenEdgeData::rayTriangleIntersection(
3954 const Vec3d& origin, const Vec3d& dir,
3955 const Vec3d& a, const Vec3d& b, const Vec3d& c,
3956 double& t)
3957 {
3958 // Check if ray is parallel with triangle
3959
3960 Vec3d e1 = b - a;
3961 Vec3d e2 = c - a;
3962 Vec3d s1 = dir.cross(e2);
3963
3964 double divisor = s1.dot(e1);
3965 if (!(std::abs(divisor) > 0.0)) return false;
3966
3967 // Compute barycentric coordinates
3968
3969 double inv_divisor = 1.0 / divisor;
3970 Vec3d d = origin - a;
3971 double b1 = d.dot(s1) * inv_divisor;
3972
3973 if (b1 < 0.0 || b1 > 1.0) return false;
3974
3975 Vec3d s2 = d.cross(e1);
3976 double b2 = dir.dot(s2) * inv_divisor;
3977
3978 if (b2 < 0.0 || (b1 + b2) > 1.0) return false;
3979
3980 // Compute distance to intersection point
3981
3982 t = e2.dot(s2) * inv_divisor;
3983 return (t < 0.0) ? false : true;
3984 }
3985
3986
3988
3989
3990 inline
3991 MeshToVoxelEdgeData::MeshToVoxelEdgeData()
3992 : mTree(EdgeData())
3993 {
3994 }
3995
3996
3997 inline void
3998 MeshToVoxelEdgeData::convert(
3999 const std::vector<Vec3s>& pointList,
4000 const std::vector<Vec4I>& polygonList)
4001 {
4002 GenEdgeData converter(pointList, polygonList);
4003 converter.run();
4004
4005 mTree.clear();
4006 mTree.merge(converter.tree());
4007 }
4008
4009
4010 inline void
4011 MeshToVoxelEdgeData::getEdgeData(
4012 Accessor& acc,
4013 const Coord& ijk,
4014 std::vector<Vec3d>& points,
4015 std::vector<Index32>& primitives)
4016 {
4017 EdgeData data;
4018 Vec3d point;
4019
4020 Coord coord = ijk;
4021
4022 if (acc.probeValue(coord, data)) {
4023
4024 if (data.mXPrim != util::INVALID_IDX) {
4025 point[0] = double(coord[0]) + data.mXDist;
4026 point[1] = double(coord[1]);
4027 point[2] = double(coord[2]);
4028
4029 points.push_back(point);
4030 primitives.push_back(data.mXPrim);
4031 }
4032
4033 if (data.mYPrim != util::INVALID_IDX) {
4034 point[0] = double(coord[0]);
4035 point[1] = double(coord[1]) + data.mYDist;
4036 point[2] = double(coord[2]);
4037
4038 points.push_back(point);
4039 primitives.push_back(data.mYPrim);
4040 }
4041
4042 if (data.mZPrim != util::INVALID_IDX) {
4043 point[0] = double(coord[0]);
4044 point[1] = double(coord[1]);
4045 point[2] = double(coord[2]) + data.mZDist;
4046
4047 points.push_back(point);
4048 primitives.push_back(data.mZPrim);
4049 }
4050
4051 }
4052
4053 coord[0] += 1;
4054
4055 if (acc.probeValue(coord, data)) {
4056
4057 if (data.mYPrim != util::INVALID_IDX) {
4058 point[0] = double(coord[0]);
4059 point[1] = double(coord[1]) + data.mYDist;
4060 point[2] = double(coord[2]);
4061
4062 points.push_back(point);
4063 primitives.push_back(data.mYPrim);
4064 }
4065
4066 if (data.mZPrim != util::INVALID_IDX) {
4067 point[0] = double(coord[0]);
4068 point[1] = double(coord[1]);
4069 point[2] = double(coord[2]) + data.mZDist;
4070
4071 points.push_back(point);
4072 primitives.push_back(data.mZPrim);
4073 }
4074 }
4075
4076 coord[2] += 1;
4077
4078 if (acc.probeValue(coord, data)) {
4079 if (data.mYPrim != util::INVALID_IDX) {
4080 point[0] = double(coord[0]);
4081 point[1] = double(coord[1]) + data.mYDist;
4082 point[2] = double(coord[2]);
4083
4084 points.push_back(point);
4085 primitives.push_back(data.mYPrim);
4086 }
4087 }
4088
4089 coord[0] -= 1;
4090
4091 if (acc.probeValue(coord, data)) {
4092
4093 if (data.mXPrim != util::INVALID_IDX) {
4094 point[0] = double(coord[0]) + data.mXDist;
4095 point[1] = double(coord[1]);
4096 point[2] = double(coord[2]);
4097
4098 points.push_back(point);
4099 primitives.push_back(data.mXPrim);
4100 }
4101
4102 if (data.mYPrim != util::INVALID_IDX) {
4103 point[0] = double(coord[0]);
4104 point[1] = double(coord[1]) + data.mYDist;
4105 point[2] = double(coord[2]);
4106
4107 points.push_back(point);
4108 primitives.push_back(data.mYPrim);
4109 }
4110 }
4111
4112
4113 coord[1] += 1;
4114
4115 if (acc.probeValue(coord, data)) {
4116
4117 if (data.mXPrim != util::INVALID_IDX) {
4118 point[0] = double(coord[0]) + data.mXDist;
4119 point[1] = double(coord[1]);
4120 point[2] = double(coord[2]);
4121
4122 points.push_back(point);
4123 primitives.push_back(data.mXPrim);
4124 }
4125 }
4126
4127 coord[2] -= 1;
4128
4129 if (acc.probeValue(coord, data)) {
4130
4131 if (data.mXPrim != util::INVALID_IDX) {
4132 point[0] = double(coord[0]) + data.mXDist;
4133 point[1] = double(coord[1]);
4134 point[2] = double(coord[2]);
4135
4136 points.push_back(point);
4137 primitives.push_back(data.mXPrim);
4138 }
4139
4140 if (data.mZPrim != util::INVALID_IDX) {
4141 point[0] = double(coord[0]);
4142 point[1] = double(coord[1]);
4143 point[2] = double(coord[2]) + data.mZDist;
4144
4145 points.push_back(point);
4146 primitives.push_back(data.mZPrim);
4147 }
4148 }
4149
4150 coord[0] += 1;
4151
4152 if (acc.probeValue(coord, data)) {
4153
4154 if (data.mZPrim != util::INVALID_IDX) {
4155 point[0] = double(coord[0]);
4156 point[1] = double(coord[1]);
4157 point[2] = double(coord[2]) + data.mZDist;
4158
4159 points.push_back(point);
4160 primitives.push_back(data.mZPrim);
4161 }
4162 }
4163 }
4164
4165
4166 template<typename GridType, typename VecType>
4167 inline typename GridType::Ptr
4168 createLevelSetBox(const math::BBox<VecType>& bbox,
4169 const openvdb::math::Transform& xform,
4170 typename VecType::ValueType halfWidth)
4171 {
4172 const Vec3s pmin = Vec3s(xform.worldToIndex(bbox.min()));
4173 const Vec3s pmax = Vec3s(xform.worldToIndex(bbox.max()));
4174
4175 Vec3s points[8];
4176 points[0] = Vec3s(pmin[0], pmin[1], pmin[2]);
4177 points[1] = Vec3s(pmin[0], pmin[1], pmax[2]);
4178 points[2] = Vec3s(pmax[0], pmin[1], pmax[2]);
4179 points[3] = Vec3s(pmax[0], pmin[1], pmin[2]);
4180 points[4] = Vec3s(pmin[0], pmax[1], pmin[2]);
4181 points[5] = Vec3s(pmin[0], pmax[1], pmax[2]);
4182 points[6] = Vec3s(pmax[0], pmax[1], pmax[2]);
4183 points[7] = Vec3s(pmax[0], pmax[1], pmin[2]);
4184
4185 Vec4I faces[6];
4186 faces[0] = Vec4I(0, 1, 2, 3); // bottom
4187 faces[1] = Vec4I(7, 6, 5, 4); // top
4188 faces[2] = Vec4I(4, 5, 1, 0); // front
4189 faces[3] = Vec4I(6, 7, 3, 2); // back
4190 faces[4] = Vec4I(0, 3, 7, 4); // left
4191 faces[5] = Vec4I(1, 5, 6, 2); // right
4192
4193 QuadAndTriangleDataAdapter<Vec3s, Vec4I> mesh(points, 8, faces, 6);
4194
4195 return meshToVolume<GridType>(mesh, xform, halfWidth, halfWidth);
4196 }
4197
4198
4199 } // namespace tools
4200 } // namespace OPENVDB_VERSION_NAME
4201 } // namespace openvdb
4202
4203 #endif // OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED
4204
4205 // Copyright (c) 2012-2017 DreamWorks Animation LLC
4206 // All rights reserved. This software is distributed under the
4207 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
openvdb::v4_0_2::math::Coord::offsetBy
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition: Coord.h:115
FiniteDifference.h
openvdb::v4_0_2::tools::mesh_to_volume_internal::ReleaseChildNodes
Definition: MeshToVolume.h:1819
openvdb::v4_0_2::Vec3I
math::Vec3< Index32 > Vec3I
Definition: Types.h:76
openvdb::v4_0_2::tools::mesh_to_volume_internal::StashOriginAndStoreOffset::mNodes
LeafNodeType **const mNodes
Definition: MeshToVolume.h:679
openvdb::v4_0_2::tools::mesh_to_volume_internal::TransformValues
Definition: MeshToVolume.h:2788
openvdb::v4_0_2::tree::Tree
Definition: Tree.h:205
openvdb::v4_0_2::math::operator>
bool operator>(const Tuple< SIZE, T0 > &t0, const Tuple< SIZE, T1 > &t1)
Definition: Tuple.h:218
openvdb::v4_0_2::tools::mesh_to_volume_internal::StashOriginAndStoreOffset::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:671
openvdb::v4_0_2::tools::meshToLevelSet
GridType::Ptr meshToLevelSet(Interrupter &interrupter, const openvdb::math::Transform &xform, const std::vector< Vec3s > &points, const std::vector< Vec3I > &triangles, const std::vector< Vec4I > &quads, float halfWidth=float(LEVEL_SET_HALF_WIDTH))
Adds support for a interrupter callback used to cancel the conversion.
Definition: MeshToVolume.h:3580
openvdb::v4_0_2::tools::mesh_to_volume_internal::ValidateIntersectingVoxels::IsNegative::check
static bool check(const ValueType v)
Definition: MeshToVolume.h:1710
openvdb::v4_0_2::tools::mesh_to_volume_internal::OffsetValues::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:2874
openvdb::v4_0_2::tools::Abs
MeshToVoxelEdgeData::EdgeData Abs(const MeshToVoxelEdgeData::EdgeData &x)
Definition: MeshToVolume.h:3670
openvdb::v4_0_2::tools::mesh_to_volume_internal::ComputeIntersectingVoxelSign::Int32LeafNodeType
typename Int32TreeType::LeafNodeType Int32LeafNodeType
Definition: MeshToVolume.h:1373
openvdb::v4_0_2::math::Coord::floor
static Coord floor(const Vec3< T > &xyz)
Return the largest integer coordinates that are not greater than xyz (node centered conversion)...
Definition: Coord.h:80
openvdb::v4_0_2::tools::mesh_to_volume_internal::DiffLeafNodeMask
Definition: MeshToVolume.h:2191
openvdb::v4_0_2::tools::signedFloodFillWithValues
void signedFloodFillWithValues(TreeOrLeafManagerT &tree, const typename TreeOrLeafManagerT::ValueType &outsideWidth, const typename TreeOrLeafManagerT::ValueType &insideWidth, bool threaded=true, size_t grainSize=1, Index minLevel=0)
Set the values of all inactive voxels and tiles of a narrow-band level set from the signs of the acti...
Definition: SignedFloodFill.h:279
openvdb::v4_0_2::tools::mesh_to_volume_internal::RemoveSelfIntersectingSurface::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1759
openvdb::v4_0_2::tools::mesh_to_volume_internal::TransformPoints::mXform
math::Transform const *const mXform
Definition: MeshToVolume.h:570
openvdb::v4_0_2::tools::mesh_to_volume_internal::SweepExteriorSign::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:842
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::EdgeData::mYPrim
Index32 mYPrim
Definition: MeshToVolume.h:492
openvdb::v4_0_2::tools::mesh_to_volume_internal::RemoveSelfIntersectingSurface::mDistTree
TreeType *const mDistTree
Definition: MeshToVolume.h:1810
openvdb::v4_0_2::tools::mesh_to_volume_internal::RemoveSelfIntersectingSurface::mIndexTree
Int32TreeType *const mIndexTree
Definition: MeshToVolume.h:1811
Types.h
openvdb::v4_0_2::util::INVALID_IDX
OPENVDB_API const Index32 INVALID_IDX
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::Int32LeafNodeType
typename Int32TreeType::LeafNodeType Int32LeafNodeType
Definition: MeshToVolume.h:2365
openvdb::v4_0_2::tools::mesh_to_volume_internal::RemoveSelfIntersectingSurface::Int32TreeType
typename TreeType::template ValueConverter< Int32 >::Type Int32TreeType
Definition: MeshToVolume.h:1761
openvdb::v4_0_2::tools::mesh_to_volume_internal::ComputeNodeConnectivity::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:727
openvdb::v4_0_2::math::Vec4
Definition: Mat4.h:51
openvdb::v4_0_2::SharedPtr
std::shared_ptr< T > SharedPtr
Definition: Types.h:130
NullInterrupter.h
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1927
openvdb::v4_0_2::tree::Tree::ValueConverter< Int32 >::Type
Tree< typename RootNodeType::template ValueConverter< Int32 >::Type > Type
Definition: Tree.h:226
openvdb::v4_0_2::tools::mesh_to_volume_internal::SweepExteriorSign::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:843
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData::Int32TreeType
typename TreeType::template ValueConverter< Int32 >::Type Int32TreeType
Definition: MeshToVolume.h:1929
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:2361
openvdb::v4_0_2::tools::MeshToVoxelEdgeData
Extracts and stores voxel edge intersection data from a mesh.
Definition: MeshToVolume.h:460
OPENVDB_LOG_DEBUG
#define OPENVDB_LOG_DEBUG(message)
In debug builds only, log a debugging message of the form &#39;someVar << "text" << ...&#39;.
Definition: logging.h:289
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::join
void join(ExpandNarrowband &rhs)
Definition: MeshToVolume.h:2428
openvdb::v4_0_2::tools::mesh_to_volume_internal::ComputeNodeConnectivity
Definition: MeshToVolume.h:707
openvdb::v4_0_2::tools::MeshToVolumeFlags
MeshToVolumeFlags
Mesh to volume conversion flags.
Definition: MeshToVolume.h:87
openvdb::v4_0_2::tools::mesh_to_volume_internal::TransformPoints::mPointsOut
PointType *const mPointsOut
Definition: MeshToVolume.h:569
openvdb::v4_0_2::tools::QuadAndTriangleDataAdapter::polygonCount
size_t polygonCount() const
Definition: MeshToVolume.h:211
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::ExpandNarrowband
ExpandNarrowband(const ExpandNarrowband &rhs, tbb::split)
Definition: MeshToVolume.h:2411
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::mesh_to_volume_internal::SyncVoxelMask
Definition: MeshToVolume.h:1166
openvdb::v4_0_2::tools::mesh_to_volume_internal::LeafNodeConnectivityTable::size
size_t size() const
Definition: MeshToVolume.h:814
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedPoints::processY
bool processY(const size_t n, bool firstFace) const
Definition: MeshToVolume.h:1282
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedFillExteriorSign::SeedFillExteriorSign
SeedFillExteriorSign(std::vector< LeafNodeType *> &nodes, bool *changedNodeMask)
Definition: MeshToVolume.h:1117
MeshDataAdapter
Convert polygonal meshes that consist of quads and/or triangles into signed or unsigned distance fiel...
openvdb::v4_0_2::tools::changeBackground
void changeBackground(TreeOrLeafManagerT &tree, const typename TreeOrLeafManagerT::ValueType &background, bool threaded=true, size_t grainSize=32)
Replace the background value in all the nodes of a tree.
Definition: ChangeBackground.h:230
openvdb::v4_0_2::tools::mesh_to_volume_internal::MinCombine::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2977
openvdb::v4_0_2::tools::mesh_to_volume_internal::DiffLeafNodeMask::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2194
openvdb::v4_0_2::math::Coord::min
static Coord min()
Return the smallest possible coordinate.
Definition: Coord.h:67
openvdb::v4_0_2::math::Transform::copy
Ptr copy() const
Definition: Transform.h:77
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:101
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::GenEdgeData::GenEdgeData
GenEdgeData(const std::vector< Vec3s > &pointList, const std::vector< Vec4I > &polygonList)
Definition: MeshToVolume.h:3724
openvdb::v4_0_2::tools::mesh_to_volume_internal::StealUniqueLeafNodes::operator()
void operator()() const
Definition: MeshToVolume.h:1865
openvdb::v4_0_2::tools::mesh_to_volume_internal::ComputeNodeConnectivity::findNeighbourNode
size_t findNeighbourNode(tree::ValueAccessor< const TreeType > &acc, const Coord &start, const Coord &step) const
Definition: MeshToVolume.h:750
openvdb::v4_0_2::tools::mesh_to_volume_internal::ConstructVoxelMask
Definition: MeshToVolume.h:2246
openvdb::v4_0_2::Index32
uint32_t Index32
Definition: Types.h:55
openvdb::v4_0_2::math::isExactlyEqual
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:391
ChangeBackground.h
Efficient multi-threaded replacement of the background values in tree.
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData::VoxelizationData
VoxelizationData()
Definition: MeshToVolume.h:1937
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedPoints::processZ
bool processZ(const size_t n, bool firstFace) const
Definition: MeshToVolume.h:1244
openvdb::v4_0_2::tools::mesh_to_volume_internal::ComputeNodeConnectivity::ComputeNodeConnectivity
ComputeNodeConnectivity(const TreeType &tree, const Coord *coordinates, size_t *offsets, size_t numNodes, const CoordBBox &bbox)
Definition: MeshToVolume.h:712
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData::primIdAcc
UCharTreeAcc primIdAcc
Definition: MeshToVolume.h:1955
openvdb::v4_0_2::tools::mesh_to_volume_internal::ComputeIntersectingVoxelSign::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1370
openvdb::v4_0_2::tools::mesh_to_volume_internal::TransformPoints::TransformPoints
TransformPoints(const PointType *pointsIn, PointType *pointsOut, const math::Transform &xform)
Definition: MeshToVolume.h:542
i
tbb::atomic< Index32 > i
Definition: LeafBuffer.h:71
openvdb::v4_0_2::tools::mesh_to_volume_internal::ComputeIntersectingVoxelSign::LocalData
std::pair< boost::shared_array< Vec3d >, boost::shared_array< bool > > LocalData
Definition: MeshToVolume.h:1375
openvdb::v4_0_2::tools::mesh_to_volume_internal::expandNarrowband
void expandNarrowband(TreeType &distTree, Int32TreeType &indexTree, BoolTreeType &maskTree, std::vector< typename BoolTreeType::LeafNodeType *> &maskNodes, const MeshDataAdapter &mesh, typename TreeType::ValueType exteriorBandWidth, typename TreeType::ValueType interiorBandWidth, typename TreeType::ValueType voxelSize)
Definition: MeshToVolume.h:2754
openvdb::v4_0_2::tools::UNSIGNED_DISTANCE_FIELD
Definition: MeshToVolume.h:93
openvdb::v4_0_2::tools::mesh_to_volume_internal::CombineLeafNodes
Definition: MeshToVolume.h:586
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedPoints::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1208
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::operator()
void operator()(const tbb::blocked_range< size_t > &range)
Definition: MeshToVolume.h:2442
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::GenEdgeData::join
void join(GenEdgeData &rhs)
Definition: MeshToVolume.h:3761
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::mesh_to_volume_internal::ComputeIntersectingVoxelSign::LocalDataTable
tbb::enumerable_thread_specific< LocalData > LocalDataTable
Definition: MeshToVolume.h:1376
openvdb::v4_0_2::tools::mesh_to_volume_internal::LeafNodeConnectivityTable::offsetsPrevY
const size_t * offsetsPrevY() const
Definition: MeshToVolume.h:824
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::math::CoordBBox::expand
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition: Coord.h:419
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::mesh_to_volume_internal::TransformPoints::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:548
openvdb::v4_0_2::tools::mesh_to_volume_internal::SyncVoxelMask::SyncVoxelMask
SyncVoxelMask(std::vector< LeafNodeType *> &nodes, const bool *changedNodeMask, bool *changedVoxelMask)
Definition: MeshToVolume.h:1172
openvdb::v4_0_2::tools::mesh_to_volume_internal::DiffLeafNodeMask::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2205
openvdb::v4_0_2::tools::mesh_to_volume_internal::AddNodes
Definition: MeshToVolume.h:2731
openvdb::v4_0_2::tools::mesh_to_volume_internal::InactivateValues::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2839
openvdb::v4_0_2::tools::mesh_to_volume_internal::ReleaseChildNodes::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1823
openvdb::v4_0_2::GRID_UNKNOWN
Definition: Types.h:263
openvdb::v4_0_2::tools::mesh_to_volume_internal::AddNodes::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2732
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedFillExteriorSign
Definition: MeshToVolume.h:1111
openvdb::v4_0_2::Index
Index32 Index
Definition: Types.h:57
openvdb::v4_0_2::tools::mesh_to_volume_internal::Tolerance
Definition: MeshToVolume.h:575
openvdb::v4_0_2::math::Vec3
Definition: Mat.h:195
openvdb::v4_0_2::tools::mesh_to_volume_internal::StealUniqueLeafNodes::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1855
openvdb::v4_0_2::tools::mesh_to_volume_internal::ComputeNodeConnectivity::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:710
openvdb::v4_0_2::math::Vec3s
Vec3< float > Vec3s
Definition: Vec3.h:677
openvdb::v4_0_2::tools::pruneLevelSet
void pruneLevelSet(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing nodes whose values are all inactive with inactive ...
Definition: Prune.h:416
openvdb::v4_0_2::tools::mesh_to_volume_internal::ConstructVoxelMask::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2248
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::tools::mesh_to_volume_internal::SeedFillExteriorSign::mNodes
LeafNodeType **const mNodes
Definition: MeshToVolume.h:1132
openvdb::v4_0_2::math::Y_AXIS
Definition: Math.h:854
openvdb::v4_0_2::tools::createLevelSetBox
GridType::Ptr createLevelSetBox(const math::BBox< VecType > &bbox, const openvdb::math::Transform &xform, typename VecType::ValueType halfWidth=LEVEL_SET_HALF_WIDTH)
Return a grid of type GridType containing a narrow-band level set representation of a box...
Definition: MeshToVolume.h:4168
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::EdgeData::mXPrim
Index32 mXPrim
Definition: MeshToVolume.h:492
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedFillExteriorSign::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1115
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::GenEdgeData
Definition: MeshToVolume.h:3679
openvdb::v4_0_2::tools::mesh_to_volume_internal::CombineLeafNodes::Int32LeafNodeType
typename Int32TreeType::LeafNodeType Int32LeafNodeType
Definition: MeshToVolume.h:593
openvdb::v4_0_2::tools::mesh_to_volume_internal::ValidateIntersectingVoxels::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1707
openvdb::v4_0_2::tools::mesh_to_volume_internal::ConstructVoxelMask::operator()
void operator()(const tbb::blocked_range< size_t > &range)
Definition: MeshToVolume.h:2270
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::EdgeData
Internal edge data type.
Definition: MeshToVolume.h:467
openvdb::v4_0_2::tools::mesh_to_volume_internal::InactivateValues
Definition: MeshToVolume.h:2826
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::newIndexNodes
std::vector< Int32LeafNodeType * > & newIndexNodes()
Definition: MeshToVolume.h:2574
openvdb::v4_0_2::tools::mesh_to_volume_internal::AddNodes::mTree
TreeType *const mTree
Definition: MeshToVolume.h:2747
openvdb::v4_0_2::tools::operator<<
std::ostream & operator<<(std::ostream &ostr, const MeshToVoxelEdgeData::EdgeData &rhs)
Definition: MeshToVolume.h:3660
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::EdgeData::mYDist
float mYDist
Definition: MeshToVolume.h:491
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::Int32TreeType
typename TreeType::template ValueConverter< Int32 >::Type Int32TreeType
Definition: MeshToVolume.h:2364
Prune.h
Defined various multi-threaded utility functions for trees.
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::EdgeData::operator+
EdgeData operator+(const T &) const
Definition: MeshToVolume.h:481
openvdb::v4_0_2::tools::mesh_to_volume_internal::TransformPoints::mPointsIn
PointType const *const mPointsIn
Definition: MeshToVolume.h:568
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::mesh_to_volume_internal::ComputeIntersectingVoxelSign::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1371
openvdb::v4_0_2::tools::mesh_to_volume_internal::SyncVoxelMask::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1170
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedPoints::mNodeMask
bool *const mNodeMask
Definition: MeshToVolume.h:1360
openvdb::v4_0_2::tools::mesh_to_volume_internal::TransformValues::TransformValues
TransformValues(std::vector< LeafNodeType *> &nodes, ValueType voxelSize, bool unsignedDist)
Definition: MeshToVolume.h:2793
openvdb::v4_0_2::tools::mesh_to_volume_internal::ConstructVoxelMask::join
void join(ConstructVoxelMask &rhs)
Definition: MeshToVolume.h:2346
openvdb::v4_0_2::tools::mesh_to_volume_internal::scanFill
bool scanFill(LeafNodeType &node)
Definition: MeshToVolume.h:1042
openvdb::v4_0_2::tools::mesh_to_volume_internal::SweepExteriorSign::Axis
Axis
Definition: MeshToVolume.h:840
openvdb::v4_0_2::tools::mesh_to_volume_internal::RestoreOrigin::mNodes
LeafNodeType **const mNodes
Definition: MeshToVolume.h:701
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::MeshToVoxelEdgeData::EdgeData::mXDist
float mXDist
Definition: MeshToVolume.h:491
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedPoints::processX
bool processX(const size_t n, bool firstFace) const
Definition: MeshToVolume.h:1320
openvdb::v4_0_2::tree::ValueAccessor::clear
virtual void clear()
Remove all nodes from this cache, then reinsert the root node.
Definition: ValueAccessor.h:438
openvdb::v4_0_2::tools::mesh_to_volume_internal::LeafNodeConnectivityTable::LeafNodeConnectivityTable
LeafNodeConnectivityTable(TreeType &tree)
Definition: MeshToVolume.h:783
openvdb::v4_0_2::tree::ValueAccessor::probeLeaf
LeafNodeT * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists...
Definition: ValueAccessor.h:424
openvdb::v4_0_2::tools::mesh_to_volume_internal::ComputeIntersectingVoxelSign::Int32TreeType
typename TreeType::template ValueConverter< Int32 >::Type Int32TreeType
Definition: MeshToVolume.h:1372
openvdb::v4_0_2::tools::mesh_to_volume_internal::TransformValues::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2801
openvdb::v4_0_2::util::wasInterrupted
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
openvdb::v4_0_2::tools::mesh_to_volume_internal::LeafNodeConnectivityTable::offsetsPrevZ
const size_t * offsetsPrevZ() const
Definition: MeshToVolume.h:827
openvdb::v4_0_2::math::X_AXIS
Definition: Math.h:853
openvdb::v4_0_2::tools::mesh_to_volume_internal::FillArray::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1142
openvdb::v4_0_2::tools::mesh_to_volume_internal::SyncVoxelMask::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1169
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::GenEdgeData::operator()
void operator()(const tbb::blocked_range< size_t > &range)
Definition: MeshToVolume.h:3823
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::MeshToVoxelEdgeData::getAccessor
Accessor getAccessor()
Definition: MeshToVolume.h:522
openvdb::v4_0_2::tools::mesh_to_volume_internal::RestoreOrigin::mCoordinates
Coord const *const mCoordinates
Definition: MeshToVolume.h:702
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData::distTree
TreeType distTree
Definition: MeshToVolume.h:1948
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedPoints
Definition: MeshToVolume.h:1205
openvdb::v4_0_2::tools::mesh_to_volume_internal::RemoveSelfIntersectingSurface::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1773
openvdb::v4_0_2::tools::mesh_to_volume_internal::AddNodes::AddNodes
AddNodes(TreeType &tree, std::vector< LeafNodeType *> &nodes)
Definition: MeshToVolume.h:2734
openvdb::v4_0_2::tools::traceExteriorBoundaries
void traceExteriorBoundaries(FloatTreeT &tree)
Traces the exterior voxel boundary of closed objects in the input volume tree. Exterior voxels are ma...
Definition: MeshToVolume.h:3008
openvdb::v4_0_2::tools::mesh_to_volume_internal::LeafNodeConnectivityTable
Definition: MeshToVolume.h:777
openvdb::v4_0_2::tools::mesh_to_volume_internal::LeafNodeConnectivityTable::offsetsNextX
const size_t * offsetsNextX() const
Definition: MeshToVolume.h:820
openvdb::v4_0_2::tools::mesh_to_volume_internal::MinCombine::MinCombine
MinCombine(std::vector< LeafNodeType *> &nodes, const ValueType *buffer)
Definition: MeshToVolume.h:2972
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::Fragment::z
Int32 z
Definition: MeshToVolume.h:2371
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
Definition: version.h:43
openvdb::v4_0_2::tools::mesh_to_volume_internal::RestoreOrigin::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:694
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData::primIdTree
UCharTreeType primIdTree
Definition: MeshToVolume.h:1954
openvdb::v4_0_2::tools::mesh_to_volume_internal::UnionValueMasks::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2233
openvdb::v4_0_2::tools::mesh_to_volume_internal::StashOriginAndStoreOffset::StashOriginAndStoreOffset
StashOriginAndStoreOffset(std::vector< LeafNodeType *> &nodes, Coord *coordinates)
Definition: MeshToVolume.h:666
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData
TBB body object to voxelize a mesh of triangles and/or quads into a collection of VDB grids...
Definition: MeshToVolume.h:1924
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData::distAcc
FloatTreeAcc distAcc
Definition: MeshToVolume.h:1949
openvdb::v4_0_2::tools::mesh_to_volume_internal::ReleaseChildNodes::ReleaseChildNodes
ReleaseChildNodes(NodeType **nodes)
Definition: MeshToVolume.h:1821
openvdb::v4_0_2::tools::DISABLE_INTERSECTING_VOXEL_REMOVAL
Definition: MeshToVolume.h:97
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::NodeMaskType
typename LeafNodeType::NodeMaskType NodeMaskType
Definition: MeshToVolume.h:2363
openvdb::v4_0_2::math::isZero
bool isZero(const Type &x)
Return true if x is exactly equal to zero.
Definition: Math.h:308
openvdb::v4_0_2::tools::mesh_to_volume_internal::InactivateValues::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2828
openvdb::v4_0_2::tools::mesh_to_volume_internal::LeafNodeConnectivityTable::offsetsPrevX
const size_t * offsetsPrevX() const
Definition: MeshToVolume.h:821
openvdb::v4_0_2::tools::meshToUnsignedDistanceField
GridType::Ptr meshToUnsignedDistanceField(Interrupter &interrupter, const openvdb::math::Transform &xform, const std::vector< Vec3s > &points, const std::vector< Vec3I > &triangles, const std::vector< Vec4I > &quads, float bandWidth)
Adds support for a interrupter callback used to cancel the conversion.
Definition: MeshToVolume.h:3642
openvdb::v4_0_2::tools::mesh_to_volume_internal::RemoveSelfIntersectingSurface::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1760
openvdb::v4_0_2::tools::mesh_to_volume_internal::FillArray
Definition: MeshToVolume.h:1138
openvdb::v4_0_2::tools::mesh_to_volume_internal::fillArray
void fillArray(ValueType *array, const ValueType val, const size_t length)
Definition: MeshToVolume.h:1156
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::BoolTreeType
typename TreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: MeshToVolume.h:2366
openvdb::v4_0_2::tools::mesh_to_volume_internal::RestoreOrigin::RestoreOrigin
RestoreOrigin(std::vector< LeafNodeType *> &nodes, const Coord *coordinates)
Definition: MeshToVolume.h:689
openvdb::v4_0_2::tools::mesh_to_volume_internal::SweepExteriorSign
Definition: MeshToVolume.h:836
SignedFloodFill.h
Propagates the sign of distance values from the active voxels in the narrow band to the inactive valu...
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedPoints::mChangedVoxelMask
bool *const mChangedVoxelMask
Definition: MeshToVolume.h:1361
openvdb::v4_0_2::math::BBox::min
const Vec3T & min() const
Return a const reference to the minimum point of the BBox.
Definition: BBox.h:84
openvdb::v4_0_2::tools::mesh_to_volume_internal::InactivateValues::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:2829
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::ExpandNarrowband
ExpandNarrowband(std::vector< BoolLeafNodeType *> &maskNodes, BoolTreeType &maskTree, TreeType &distTree, Int32TreeType &indexTree, const MeshDataAdapter &mesh, ValueType exteriorBandWidth, ValueType interiorBandWidth, ValueType voxelSize)
Definition: MeshToVolume.h:2386
openvdb::v4_0_2::tools::mesh_to_volume_internal::DiffLeafNodeMask::DiffLeafNodeMask
DiffLeafNodeMask(const TreeType &rhsTree, std::vector< BoolLeafNodeType *> &lhsNodes)
Definition: MeshToVolume.h:2199
openvdb::v4_0_2::tools::mesh_to_volume_internal::MinCombine
Definition: MeshToVolume.h:2967
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::newDistNodes
std::vector< LeafNodeType * > & newDistNodes()
Definition: MeshToVolume.h:2571
openvdb::v4_0_2::math::Coord::max
static Coord max()
Return the largest possible coordinate.
Definition: Coord.h:70
openvdb::v4_0_2::tools::mesh_to_volume_internal::RemoveSelfIntersectingSurface::RemoveSelfIntersectingSurface
RemoveSelfIntersectingSurface(std::vector< LeafNodeType *> &nodes, TreeType &distTree, Int32TreeType &indexTree)
Definition: MeshToVolume.h:1765
openvdb::v4_0_2::tools::QuadAndTriangleDataAdapter::pointCount
size_t pointCount() const
Definition: MeshToVolume.h:212
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::EdgeData::mZPrim
Index32 mZPrim
Definition: MeshToVolume.h:492
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::GenEdgeData::run
void run(bool threaded=true)
Definition: MeshToVolume.h:3750
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedPoints::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1209
openvdb::v4_0_2::math::operator<
bool operator<(const Tuple< SIZE, T0 > &t0, const Tuple< SIZE, T1 > &t1)
Definition: Tuple.h:206
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::mesh_to_volume_internal::ValidateIntersectingVoxels::mNodes
LeafNodeType **const mNodes
Definition: MeshToVolume.h:1752
openvdb::v4_0_2::math::CoordBBox::isInside
bool isInside(const Coord &xyz) const
Return true if point (x, y, z) is inside this bounding box.
Definition: Coord.h:401
openvdb::v4_0_2::math::BBox::max
const Vec3T & max() const
Return a const reference to the maximum point of the BBox.
Definition: BBox.h:87
openvdb::v4_0_2::tools::mesh_to_volume_internal::StashOriginAndStoreOffset::mCoordinates
Coord *const mCoordinates
Definition: MeshToVolume.h:680
openvdb::v4_0_2::tools::mesh_to_volume_internal::SyncVoxelMask::mChangedVoxelMask
bool *const mChangedVoxelMask
Definition: MeshToVolume.h:1200
openvdb
Definition: Exceptions.h:39
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedFillExteriorSign::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1114
openvdb::v4_0_2::math::GodunovsNormSqrd
Real GodunovsNormSqrd(bool isOutside, Real dP_xm, Real dP_xp, Real dP_ym, Real dP_yp, Real dP_zm, Real dP_zp)
Definition: FiniteDifference.h:353
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizePolygons::DataTable
tbb::enumerable_thread_specific< typename VoxelizationDataType::Ptr > DataTable
Definition: MeshToVolume.h:1981
openvdb::v4_0_2::math::Coord::minComponent
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition: Coord.h:199
openvdb::v4_0_2::tree::LeafIteratorBase
Base class for tree-traversal iterators over all leaf nodes (but not leaf voxels) ...
Definition: TreeIterator.h:1228
openvdb::v4_0_2::tools::mesh_to_volume_internal::ValidateIntersectingVoxels::IsNegative
Definition: MeshToVolume.h:1710
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData::indexAcc
Int32TreeAcc indexAcc
Definition: MeshToVolume.h:1952
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2362
openvdb::v4_0_2::tools::DISABLE_RENORMALIZATION
Definition: MeshToVolume.h:101
openvdb::v4_0_2::tools::mesh_to_volume_internal::CombineLeafNodes::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:604
openvdb::v4_0_2::tools::mesh_to_volume_internal::LeafNodeConnectivityTable::offsetsNextY
const size_t * offsetsNextY() const
Definition: MeshToVolume.h:823
openvdb::v4_0_2::tree::Tree::clear
void clear()
Remove all tiles from this tree and all nodes other than the root node.
Definition: Tree.h:1489
openvdb::v4_0_2::math::CoordBBox::max
const Coord & max() const
Definition: Coord.h:335
openvdb::v4_0_2::math::Vec3::cross
Vec3< T > cross(const Vec3< T > &v) const
Return the cross product of "this" vector and v;.
Definition: Vec3.h:244
openvdb::v4_0_2::tools::mesh_to_volume_internal::ReleaseChildNodes::mNodes
NodeType **const mNodes
Definition: MeshToVolume.h:1832
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedFillExteriorSign::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1123
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::Fragment::idx
Int32 idx
Definition: MeshToVolume.h:2371
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::Fragment::dist
ValueType dist
Definition: MeshToVolume.h:2372
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData::Ptr
std::unique_ptr< VoxelizationData > Ptr
Definition: MeshToVolume.h:1926
openvdb::v4_0_2::tools::mesh_to_volume_internal::FillArray::mArray
ValueType *const mArray
Definition: MeshToVolume.h:1149
openvdb::v4_0_2::tools::mesh_to_volume_internal::UnionValueMasks::UnionValueMasks
UnionValueMasks(std::vector< LeafNodeTypeA *> &nodesA, std::vector< LeafNodeTypeB *> &nodesB)
Definition: MeshToVolume.h:2227
openvdb::v4_0_2::tools::mesh_to_volume_internal::ValidateIntersectingVoxels::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1708
openvdb::v4_0_2::tools::mesh_to_volume_internal::ConstructVoxelMask::BoolTreeType
typename TreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: MeshToVolume.h:2250
openvdb::v4_0_2::tools::mesh_to_volume_internal::Tolerance::epsilon
static ValueType epsilon()
Definition: MeshToVolume.h:577
openvdb::v4_0_2::tree::TreeValueIteratorBase
Base class for tree-traversal iterators over tile and voxel values.
Definition: TreeIterator.h:658
openvdb::v4_0_2::tools::mesh_to_volume_internal::ValidateIntersectingVoxels::ValidateIntersectingVoxels
ValidateIntersectingVoxels(TreeType &tree, std::vector< LeafNodeType *> &nodes)
Definition: MeshToVolume.h:1712
openvdb::v4_0_2::math::Vec3d
Vec3< double > Vec3d
Definition: Vec3.h:678
openvdb::v4_0_2::tools::mesh_to_volume_internal::TransformValues::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2790
openvdb::v4_0_2::tools::QuadAndTriangleDataAdapter::QuadAndTriangleDataAdapter
QuadAndTriangleDataAdapter(const PointType *pointArray, size_t pointArraySize, const PolygonType *polygonArray, size_t polygonArraySize)
Definition: MeshToVolume.h:202
openvdb::v4_0_2::tree::ValueAccessor< TreeType >
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedPoints::mConnectivity
ConnectivityTable *const mConnectivity
Definition: MeshToVolume.h:1358
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedFillExteriorSign::mChangedNodeMask
bool *const mChangedNodeMask
Definition: MeshToVolume.h:1133
openvdb::v4_0_2::tree::Tree::LeafNodeType
typename RootNodeType::LeafNodeType LeafNodeType
Definition: Tree.h:214
openvdb::v4_0_2::tree::Tree::clearAllAccessors
void clearAllAccessors()
Clear all registered accessors.
Definition: Tree.h:1548
openvdb::v4_0_2::tools::mesh_to_volume_internal::LeafNodeConnectivityTable::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:781
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::Fragment::Fragment
Fragment(Int32 idx_, Int32 x_, Int32 y_, Int32 z_, ValueType dist_)
Definition: MeshToVolume.h:2376
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::updatedDistNodes
std::vector< LeafNodeType * > & updatedDistNodes()
Definition: MeshToVolume.h:2572
openvdb::v4_0_2::tools::mesh_to_volume_internal::seedFill
void seedFill(LeafNodeType &node)
Definition: MeshToVolume.h:966
openvdb::v4_0_2::tools::QuadAndTriangleDataAdapter
Contiguous quad and triangle data adapter class.
Definition: MeshToVolume.h:191
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::Fragment::operator<
bool operator<(const Fragment &rhs) const
Definition: MeshToVolume.h:2381
openvdb::v4_0_2::tools::mesh_to_volume_internal::RemoveSelfIntersectingSurface::Comp
Definition: MeshToVolume.h:1763
openvdb::v4_0_2::tools::meshToSignedDistanceField
GridType::Ptr meshToSignedDistanceField(Interrupter &interrupter, const openvdb::math::Transform &xform, const std::vector< Vec3s > &points, const std::vector< Vec3I > &triangles, const std::vector< Vec4I > &quads, float exBandWidth, float inBandWidth)
Adds support for a interrupter callback used to cancel the conversion.
Definition: MeshToVolume.h:3611
Util.h
openvdb::v4_0_2::tools::mesh_to_volume_internal::UnionValueMasks
Definition: MeshToVolume.h:2225
openvdb::v4_0_2::math::Z_AXIS
Definition: Math.h:855
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::EdgeData::mZDist
float mZDist
Definition: MeshToVolume.h:491
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::EdgeData::operator-
EdgeData operator-(const T &) const
Definition: MeshToVolume.h:482
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedPoints::SeedPoints
SeedPoints(ConnectivityTable &connectivity, bool *changedNodeMask, bool *nodeMask, bool *changedVoxelMask)
Definition: MeshToVolume.h:1212
openvdb::v4_0_2::tools::mesh_to_volume_internal::releaseLeafNodes
void releaseLeafNodes(TreeType &tree)
Definition: MeshToVolume.h:1838
openvdb::v4_0_2::tools::mesh_to_volume_internal::StealUniqueLeafNodes::StealUniqueLeafNodes
StealUniqueLeafNodes(TreeType &lhsTree, TreeType &rhsTree, std::vector< LeafNodeType *> &overlappingNodes)
Definition: MeshToVolume.h:1857
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::EdgeData::operator==
bool operator==(const EdgeData &rhs) const
Definition: MeshToVolume.h:486
openvdb::v4_0_2::tools::mesh_to_volume_internal::Renormalize::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:2906
openvdb::v4_0_2::tools::DISABLE_NARROW_BAND_TRIMMING
Definition: MeshToVolume.h:105
openvdb::v4_0_2::tree::ValueAccessor::setValueOn
void setValueOn(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:292
openvdb::v4_0_2::tools::QuadAndTriangleDataAdapter::vertexCount
size_t vertexCount(size_t n) const
Vertex count for polygon n.
Definition: MeshToVolume.h:215
openvdb::v4_0_2::LEVEL_SET_HALF_WIDTH
static const Real LEVEL_SET_HALF_WIDTH
Definition: Types.h:270
openvdb::v4_0_2::tools::mesh_to_volume_internal::Renormalize
Definition: MeshToVolume.h:2903
openvdb::v4_0_2::math::closestPointOnTriangleToPoint
OPENVDB_API Vec3d closestPointOnTriangleToPoint(const Vec3d &a, const Vec3d &b, const Vec3d &c, const Vec3d &p, Vec3d &uvw)
Closest Point on Triangle to Point. Given a triangle abc and a point p, return the point on abc close...
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizePolygons::VoxelizePolygons
VoxelizePolygons(DataTable &dataTable, const MeshDataAdapter &mesh, Interrupter *interrupter=nullptr)
Definition: MeshToVolume.h:1983
openvdb::v4_0_2::tools::mesh_to_volume_internal::Tolerance::minNarrowBandWidth
static ValueType minNarrowBandWidth()
Definition: MeshToVolume.h:578
openvdb::v4_0_2::tools::mesh_to_volume_internal::FillArray::mValue
const ValueType mValue
Definition: MeshToVolume.h:1150
openvdb::v4_0_2::tree::ValueAccessor::getNode
NodeType * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
Definition: ValueAccessor.h:349
openvdb::v4_0_2::tools::mesh_to_volume_internal::InactivateValues::InactivateValues
InactivateValues(std::vector< LeafNodeType *> &nodes, ValueType exBandWidth, ValueType inBandWidth)
Definition: MeshToVolume.h:2831
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::BoolLeafNodeType
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: MeshToVolume.h:2367
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::GenEdgeData::tree
TreeType & tree()
Definition: MeshToVolume.h:3693
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizePolygons::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1992
openvdb::v4_0_2::tools::mesh_to_volume_internal::RemoveSelfIntersectingSurface
Definition: MeshToVolume.h:1757
openvdb::v4_0_2::tools::mesh_to_volume_internal::OffsetValues::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2873
openvdb::v4_0_2::tools::mesh_to_volume_internal::combineData
void combineData(DistTreeType &lhsDist, IndexTreeType &lhsIdx, DistTreeType &rhsDist, IndexTreeType &rhsIdx)
Definition: MeshToVolume.h:1894
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::Fragment::Fragment
Fragment()
Definition: MeshToVolume.h:2374
openvdb::v4_0_2::tools::mesh_to_volume_internal::RestoreOrigin::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:687
openvdb::v4_0_2::tools::mesh_to_volume_internal::maskNodeInternalNeighbours
void maskNodeInternalNeighbours(const Index pos, bool(&mask)[26])
Definition: MeshToVolume.h:1561
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::MeshToVoxelEdgeData
MeshToVoxelEdgeData()
Definition: MeshToVolume.h:3991
openvdb::v4_0_2::tools::mesh_to_volume_internal::ComputeIntersectingVoxelSign::ComputeIntersectingVoxelSign
ComputeIntersectingVoxelSign(std::vector< LeafNodeType *> &distNodes, const TreeType &distTree, const Int32TreeType &indexTree, const MeshDataAdapter &mesh)
Definition: MeshToVolume.h:1378
openvdb::v4_0_2::tools::mesh_to_volume_internal::LeafNodeConnectivityTable::nodes
const std::vector< LeafNodeType * > & nodes() const
Definition: MeshToVolume.h:817
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::mesh_to_volume_internal::MinCombine::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:2970
openvdb::v4_0_2::tools::mesh_to_volume_internal::SyncVoxelMask::mNodes
LeafNodeType **const mNodes
Definition: MeshToVolume.h:1198
openvdb::v4_0_2::tools::mesh_to_volume_internal::Renormalize::Renormalize
Renormalize(const TreeType &tree, const std::vector< LeafNodeType *> &nodes, ValueType *buffer, ValueType voxelSize)
Definition: MeshToVolume.h:2908
openvdb::v4_0_2::tools::mesh_to_volume_internal::ValidateIntersectingVoxels
Definition: MeshToVolume.h:1705
openvdb::v4_0_2::tools::mesh_to_volume_internal::CombineLeafNodes::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:592
openvdb::v4_0_2::tools::mesh_to_volume_internal::StashOriginAndStoreOffset::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:664
openvdb::v4_0_2::util::NullInterrupter
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:52
openvdb::v4_0_2::tools::mesh_to_volume_internal::SweepExteriorSign::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:854
openvdb::v4_0_2::tools::mesh_to_volume_internal::Renormalize::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2917
openvdb::v4_0_2::tree::Tree::beginLeaf
LeafIter beginLeaf()
Return an iterator over all leaf nodes in this tree.
Definition: Tree.h:1180
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData::UCharTreeType
typename TreeType::template ValueConverter< unsigned char >::Type UCharTreeType
Definition: MeshToVolume.h:1930
openvdb::v4_0_2::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:48
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizePolygons
Definition: MeshToVolume.h:1976
openvdb::v4_0_2::tools::mesh_to_volume_internal::CombineLeafNodes::Int32TreeType
typename TreeType::template ValueConverter< Int32 >::Type Int32TreeType
Definition: MeshToVolume.h:590
openvdb::v4_0_2::math::Sqrt
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:711
openvdb::v4_0_2::tools::mesh_to_volume_internal::StealUniqueLeafNodes
Definition: MeshToVolume.h:1853
openvdb::v4_0_2::tools::mesh_to_volume_internal::LeafNodeConnectivityTable::nodes
std::vector< LeafNodeType * > & nodes()
Definition: MeshToVolume.h:816
openvdb::v4_0_2::tree::Tree::probeLeaf
LeafNodeType * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, return nullptr.
Definition: Tree.h:1735
openvdb::v4_0_2::tools::mesh_to_volume_internal::SyncVoxelMask::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1180
openvdb::v4_0_2::tree::Tree::merge
void merge(Tree &other, MergePolicy=MERGE_ACTIVE_STATES)
Efficiently merge another tree into this tree using one of several schemes.
Definition: Tree.h:1865
openvdb::v4_0_2::tools::QuadAndTriangleDataAdapter::QuadAndTriangleDataAdapter
QuadAndTriangleDataAdapter(const std::vector< PointType > &points, const std::vector< PolygonType > &polygons)
Definition: MeshToVolume.h:193
openvdb::v4_0_2::math::Pow2
Type Pow2(Type x)
Return .
Definition: Math.h:498
openvdb::v4_0_2::Int32
int32_t Int32
Definition: Types.h:59
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData::indexTree
Int32TreeType indexTree
Definition: MeshToVolume.h:1951
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::EdgeData::operator-
EdgeData operator-() const
Definition: MeshToVolume.h:483
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::tools::mesh_to_volume_internal::StashOriginAndStoreOffset
Definition: MeshToVolume.h:662
openvdb::v4_0_2::Vec4I
math::Vec4< Index32 > Vec4I
Definition: Types.h:91
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::Fragment
Definition: MeshToVolume.h:2369
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::EdgeData::EdgeData
EdgeData(float dist=1.0)
Definition: MeshToVolume.h:468
Proximity.h
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband
Definition: MeshToVolume.h:2359
openvdb::v4_0_2::tools::mesh_to_volume_internal::RestoreOrigin
Definition: MeshToVolume.h:685
openvdb::v4_0_2::tools::mesh_to_volume_internal::ValidateIntersectingVoxels::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1718
openvdb::v4_0_2::tools::mesh_to_volume_internal::VoxelizationData::getNewPrimId
unsigned char getNewPrimId()
Definition: MeshToVolume.h:1957
openvdb::v4_0_2::tools::mesh_to_volume_internal::AddNodes::operator()
void operator()() const
Definition: MeshToVolume.h:2739
openvdb::v4_0_2::tools::mesh_to_volume_internal::RemoveSelfIntersectingSurface::mNodes
LeafNodeType **const mNodes
Definition: MeshToVolume.h:1809
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
openvdb::v4_0_2::tools::mesh_to_volume_internal::ConstructVoxelMask::ConstructVoxelMask
ConstructVoxelMask(BoolTreeType &maskTree, const TreeType &tree, std::vector< LeafNodeType *> &nodes)
Definition: MeshToVolume.h:2253
openvdb::v4_0_2::math::Axis
Axis
Definition: Math.h:852
openvdb::v4_0_2::tree::TreeValueIteratorBase::getValue
const ValueT & getValue() const
Return the tile or voxel value to which this iterator is currently pointing.
Definition: TreeIterator.h:734
openvdb::v4_0_2::tools::mesh_to_volume_internal::DiffLeafNodeMask::BoolLeafNodeType
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: MeshToVolume.h:2197
openvdb::v4_0_2::tools::mesh_to_volume_internal::SweepExteriorSign::SweepExteriorSign
SweepExteriorSign(Axis axis, const std::vector< size_t > &startNodeIndices, ConnectivityTable &connectivity)
Definition: MeshToVolume.h:846
openvdb::v4_0_2::tools::mesh_to_volume_internal::ComputeIntersectingVoxelSign
Definition: MeshToVolume.h:1368
openvdb::v4_0_2::math::Coord::maxComponent
void maxComponent(const Coord &other)
Perform a component-wise maximum with the other Coord.
Definition: Coord.h:207
openvdb::v4_0_2::tools::mesh_to_volume_internal::TransformPoints
Definition: MeshToVolume.h:540
openvdb::v4_0_2::tools::mesh_to_volume_internal::FillArray::FillArray
FillArray(ValueType *array, const ValueType v)
Definition: MeshToVolume.h:1140
openvdb::v4_0_2::tools::mesh_to_volume_internal::AddNodes::mNodes
std::vector< LeafNodeType * > *const mNodes
Definition: MeshToVolume.h:2748
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::updatedIndexNodes
std::vector< Int32LeafNodeType * > & updatedIndexNodes()
Definition: MeshToVolume.h:2575
openvdb::v4_0_2::tools::mesh_to_volume_internal::ValidateIntersectingVoxels::mTree
TreeType *const mTree
Definition: MeshToVolume.h:1751
openvdb::v4_0_2::tools::mesh_to_volume_internal::ConstructVoxelMask::ConstructVoxelMask
ConstructVoxelMask(ConstructVoxelMask &rhs, tbb::split)
Definition: MeshToVolume.h:2262
openvdb::v4_0_2::math::CoordBBox::min
const Coord & min() const
Definition: Coord.h:334
openvdb::v4_0_2::tools::mesh_to_volume_internal::OffsetValues
Definition: MeshToVolume.h:2871
openvdb::v4_0_2::math::Transform::voxelSize
Vec3d voxelSize() const
Return the size of a voxel using the linear component of the map.
Definition: Transform.h:120
openvdb::v4_0_2::tools::mesh_to_volume_internal::RemoveSelfIntersectingSurface::Comp::check
static bool check(const ValueType v)
Definition: MeshToVolume.h:1763
openvdb::v4_0_2::util::COORD_OFFSETS
OPENVDB_API const Coord COORD_OFFSETS[26]
coordinate offset table for neighboring voxels
openvdb::v4_0_2::tools::mesh_to_volume_internal::DiffLeafNodeMask::AccessorType
typename tree::ValueAccessor< TreeType > AccessorType
Definition: MeshToVolume.h:2193
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::mesh_to_volume_internal::SeedPoints::mChangedNodeMask
bool *const mChangedNodeMask
Definition: MeshToVolume.h:1359
openvdb::v4_0_2::tools::mesh_to_volume_internal::Renormalize::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2905
openvdb::v4_0_2::tools::mesh_to_volume_internal::MinCombine::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2969
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::tools::mesh_to_volume_internal::ConstructVoxelMask::BoolLeafNodeType
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: MeshToVolume.h:2251
openvdb::v4_0_2::tools::mesh_to_volume_internal::SyncVoxelMask::mChangedNodeMask
bool const *const mChangedNodeMask
Definition: MeshToVolume.h:1199
openvdb::v4_0_2::tools::mesh_to_volume_internal::LeafNodeConnectivityTable::offsetsNextZ
const size_t * offsetsNextZ() const
Definition: MeshToVolume.h:826
openvdb::v4_0_2::tree::Tree::RootNodeType
_RootNodeType RootNodeType
Definition: Tree.h:211
openvdb::v4_0_2::tools::QuadAndTriangleDataAdapter::getIndexSpacePoint
void getIndexSpacePoint(size_t n, size_t v, Vec3d &pos) const
Returns position pos in local grid index space for polygon n and vertex v.
Definition: MeshToVolume.h:221
openvdb::v4_0_2::GRID_LEVEL_SET
Definition: Types.h:264
openvdb::v4_0_2::tools::mesh_to_volume_internal::SeedPoints::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1221
openvdb::v4_0_2::tools::mesh_to_volume_internal::ComputeIntersectingVoxelSign::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1392
openvdb::v4_0_2::tools::mesh_to_volume_internal::ExpandNarrowband::newMaskTree
BoolTreeType & newMaskTree()
Definition: MeshToVolume.h:2569
openvdb::v4_0_2::tools::mesh_to_volume_internal::CombineLeafNodes::CombineLeafNodes
CombineLeafNodes(TreeType &lhsDistTree, Int32TreeType &lhsIdxTree, LeafNodeType **rhsDistNodes, Int32LeafNodeType **rhsIdxNodes)
Definition: MeshToVolume.h:595
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::getEdgeData
void getEdgeData(Accessor &acc, const Coord &ijk, std::vector< Vec3d > &points, std::vector< Index32 > &primitives)
Returns intersection points with corresponding primitive indices for the given ijk voxel...
Definition: MeshToVolume.h:4011
openvdb::v4_0_2::tools::pruneInactive
void pruneInactive(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with background tiles any nodes whose values are a...
Definition: Prune.h:381
openvdb::v4_0_2::tools::mesh_to_volume_internal::TransformValues::ValueType
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:2791
openvdb::v4_0_2::tools::mesh_to_volume_internal::OffsetValues::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2881
openvdb::v4_0_2::tools::mesh_to_volume_internal::OffsetValues::OffsetValues
OffsetValues(std::vector< LeafNodeType *> &nodes, ValueType offset)
Definition: MeshToVolume.h:2876
openvdb::v4_0_2::math::BBox
Axis-aligned bounding box.
Definition: BBox.h:47
openvdb::v4_0_2::tools::MeshToVoxelEdgeData::convert
void convert(const std::vector< Vec3s > &pointList, const std::vector< Vec4I > &polygonList)
Threaded method to extract voxel edge data, the closest intersection point and corresponding primitiv...
Definition: MeshToVolume.h:3998
openvdb::v4_0_2::tools::mesh_to_volume_internal::SweepExteriorSign::traceVoxelLine
bool traceVoxelLine(LeafNodeType &node, Index pos, Index step) const
Definition: MeshToVolume.h:930
Platform.h
openvdb::v4_0_2::tools::mesh_to_volume_internal::DiffLeafNodeMask::BoolTreeType
typename TreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: MeshToVolume.h:2196
openvdb::v4_0_2::tools::mesh_to_volume_internal::checkNeighbours
bool checkNeighbours(const Coord &ijk, AccessorType &acc, bool(&mask)[26])
Definition: MeshToVolume.h:1692
openvdb::v4_0_2::tools::meshToVolume
GridType::Ptr meshToVolume(Interrupter &interrupter, const MeshDataAdapter &mesh, const math::Transform &transform, float exteriorBandWidth=3.0f, float interiorBandWidth=3.0f, int flags=0, typename GridType::template ValueConverter< Int32 >::Type *polygonIndexGrid=nullptr)
Convert polygonal meshes that consist of quads and/or triangles into signed or unsigned distance fiel...
Definition: MeshToVolume.h:3085