OpenVDB  5.0.0
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
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/shared_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 {
79 namespace OPENVDB_VERSION_NAME {
80 namespace tools {
81 
82 
84 
85 
88 
94 
98 
102 
106 };
107 
108 
139 template <typename GridType, typename MeshDataAdapter>
140 inline typename GridType::Ptr
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
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>
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
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
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
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
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
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
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
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
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
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
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
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 
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 
497 
498 
500 
501 
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>
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>
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>
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 
681 };
682 
683 
684 template<typename TreeType>
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 
702  Coord const * const mCoordinates;
703 };
704 
705 
706 template<typename TreeType>
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 
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 
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 
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>
778 {
779  enum { INVALID_OFFSET = boost::integer_traits<size_t>::const_max };
780 
781  using LeafNodeType = typename TreeType::LeafNodeType;
782 
784  {
785  mLeafNodes.reserve(tree.leafCount());
786  tree.getNodes(mLeafNodes);
787 
788  if (mLeafNodes.empty()) return;
789 
790  CoordBBox bbox;
791  tree.evalLeafBoundingBox(bbox);
792 
793  const tbb::blocked_range<size_t> range(0, mLeafNodes.size());
794 
795  // stash the leafnode origin coordinate and temporarily store the
796  // linear offset in the origin.x variable.
797  std::unique_ptr<Coord[]> coordinates{new Coord[mLeafNodes.size()]};
798  tbb::parallel_for(range,
799  StashOriginAndStoreOffset<TreeType>(mLeafNodes, coordinates.get()));
800 
801  // build the leafnode offset table
802  mOffsets.reset(new size_t[mLeafNodes.size() * 6]);
803 
804 
805  tbb::parallel_for(range, ComputeNodeConnectivity<TreeType>(
806  tree, coordinates.get(), mOffsets.get(), mLeafNodes.size(), bbox));
807 
808  // restore the leafnode origin coordinate
809  tbb::parallel_for(range, RestoreOrigin<TreeType>(mLeafNodes, coordinates.get()));
810  }
811 
812  size_t size() const { return mLeafNodes.size(); }
813 
814  std::vector<LeafNodeType*>& nodes() { return mLeafNodes; }
815  const std::vector<LeafNodeType*>& nodes() const { return mLeafNodes; }
816 
817 
818  const size_t* offsetsNextX() const { return mOffsets.get(); }
819  const size_t* offsetsPrevX() const { return mOffsets.get() + mLeafNodes.size(); }
820 
821  const size_t* offsetsNextY() const { return mOffsets.get() + mLeafNodes.size() * 2; }
822  const size_t* offsetsPrevY() const { return mOffsets.get() + mLeafNodes.size() * 3; }
823 
824  const size_t* offsetsNextZ() const { return mOffsets.get() + mLeafNodes.size() * 4; }
825  const size_t* offsetsPrevZ() const { return mOffsets.get() + mLeafNodes.size() * 5; }
826 
827 private:
828  std::vector<LeafNodeType*> mLeafNodes;
829  std::unique_ptr<size_t[]> mOffsets;
830 }; // struct LeafNodeConnectivityTable
831 
832 
833 template<typename TreeType>
835 {
836 public:
837 
838  enum Axis { X_AXIS = 0, Y_AXIS = 1, Z_AXIS = 2 };
839 
840  using ValueType = typename TreeType::ValueType;
841  using LeafNodeType = typename TreeType::LeafNodeType;
843 
844  SweepExteriorSign(Axis axis, const std::vector<size_t>& startNodeIndices,
845  ConnectivityTable& connectivity)
846  : mStartNodeIndices(startNodeIndices.empty() ? nullptr : &startNodeIndices[0])
847  , mConnectivity(&connectivity)
848  , mAxis(axis)
849  {
850  }
851 
852  void operator()(const tbb::blocked_range<size_t>& range) const {
853 
854  std::vector<LeafNodeType*>& nodes = mConnectivity->nodes();
855 
856  // Z Axis
857  size_t idxA = 0, idxB = 1;
858  Index step = 1;
859 
860  const size_t* nextOffsets = mConnectivity->offsetsNextZ();
861  const size_t* prevOffsets = mConnectivity->offsetsPrevZ();
862 
863  if (mAxis == Y_AXIS) {
864 
865  idxA = 0;
866  idxB = 2;
867  step = LeafNodeType::DIM;
868 
869  nextOffsets = mConnectivity->offsetsNextY();
870  prevOffsets = mConnectivity->offsetsPrevY();
871 
872  } else if (mAxis == X_AXIS) {
873 
874  idxA = 1;
875  idxB = 2;
876  step = LeafNodeType::DIM * LeafNodeType::DIM;
877 
878  nextOffsets = mConnectivity->offsetsNextX();
879  prevOffsets = mConnectivity->offsetsPrevX();
880  }
881 
882  Coord ijk(0, 0, 0);
883 
884  int& a = ijk[idxA];
885  int& b = ijk[idxB];
886 
887  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
888 
889  size_t startOffset = mStartNodeIndices[n];
890  size_t lastOffset = startOffset;
891 
892  Index pos(0);
893 
894  for (a = 0; a < int(LeafNodeType::DIM); ++a) {
895  for (b = 0; b < int(LeafNodeType::DIM); ++b) {
896 
897  pos = LeafNodeType::coordToOffset(ijk);
898  size_t offset = startOffset;
899 
900  // sweep in +axis direction until a boundary voxel is hit.
901  while ( offset != ConnectivityTable::INVALID_OFFSET &&
902  traceVoxelLine(*nodes[offset], pos, step) ) {
903 
904  lastOffset = offset;
905  offset = nextOffsets[offset];
906  }
907 
908  // find last leafnode in +axis direction
909  offset = lastOffset;
910  while (offset != ConnectivityTable::INVALID_OFFSET) {
911  lastOffset = offset;
912  offset = nextOffsets[offset];
913  }
914 
915  // sweep in -axis direction until a boundary voxel is hit.
916  offset = lastOffset;
917  pos += step * (LeafNodeType::DIM - 1);
918  while ( offset != ConnectivityTable::INVALID_OFFSET &&
919  traceVoxelLine(*nodes[offset], pos, -step)) {
920  offset = prevOffsets[offset];
921  }
922  }
923  }
924  }
925  }
926 
927 
928  bool traceVoxelLine(LeafNodeType& node, Index pos, Index step) const {
929 
930  ValueType* data = node.buffer().data();
931 
932  bool isOutside = true;
933 
934  for (Index i = 0; i < LeafNodeType::DIM; ++i) {
935 
936  ValueType& dist = data[pos];
937 
938  if (dist < ValueType(0.0)) {
939  isOutside = true;
940  } else {
941  // Boundary voxel check. (Voxel that intersects the surface)
942  if (!(dist > ValueType(0.75))) isOutside = false;
943 
944  if (isOutside) dist = ValueType(-dist);
945  }
946 
947  pos += step;
948  }
949 
950  return isOutside;
951  }
952 
953 
954 private:
955  size_t const * const mStartNodeIndices;
956  ConnectivityTable * const mConnectivity;
957 
958  const Axis mAxis;
959 }; // class SweepExteriorSign
960 
961 
962 template<typename LeafNodeType>
963 inline void
964 seedFill(LeafNodeType& node)
965 {
966  using ValueType = typename LeafNodeType::ValueType;
967  using Queue = std::deque<Index>;
968 
969 
970  ValueType* data = node.buffer().data();
971 
972  // find seed points
973  Queue seedPoints;
974  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
975  if (data[pos] < 0.0) seedPoints.push_back(pos);
976  }
977 
978  if (seedPoints.empty()) return;
979 
980  // clear sign information
981  for (Queue::iterator it = seedPoints.begin(); it != seedPoints.end(); ++it) {
982  ValueType& dist = data[*it];
983  dist = -dist;
984  }
985 
986  // flood fill
987 
988  Coord ijk(0, 0, 0);
989  Index pos(0), nextPos(0);
990 
991  while (!seedPoints.empty()) {
992 
993  pos = seedPoints.back();
994  seedPoints.pop_back();
995 
996  ValueType& dist = data[pos];
997 
998  if (!(dist < ValueType(0.0))) {
999 
1000  dist = -dist; // flip sign
1001 
1002  ijk = LeafNodeType::offsetToLocalCoord(pos);
1003 
1004  if (ijk[0] != 0) { // i - 1, j, k
1005  nextPos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
1006  if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1007  }
1008 
1009  if (ijk[0] != (LeafNodeType::DIM - 1)) { // i + 1, j, k
1010  nextPos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
1011  if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1012  }
1013 
1014  if (ijk[1] != 0) { // i, j - 1, k
1015  nextPos = pos - LeafNodeType::DIM;
1016  if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1017  }
1018 
1019  if (ijk[1] != (LeafNodeType::DIM - 1)) { // i, j + 1, k
1020  nextPos = pos + LeafNodeType::DIM;
1021  if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1022  }
1023 
1024  if (ijk[2] != 0) { // i, j, k - 1
1025  nextPos = pos - 1;
1026  if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1027  }
1028 
1029  if (ijk[2] != (LeafNodeType::DIM - 1)) { // i, j, k + 1
1030  nextPos = pos + 1;
1031  if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1032  }
1033  }
1034  }
1035 } // seedFill()
1036 
1037 
1038 template<typename LeafNodeType>
1039 inline bool
1040 scanFill(LeafNodeType& node)
1041 {
1042  bool updatedNode = false;
1043 
1044  using ValueType = typename LeafNodeType::ValueType;
1045  ValueType* data = node.buffer().data();
1046 
1047  Coord ijk(0, 0, 0);
1048 
1049  bool updatedSign = true;
1050  while (updatedSign) {
1051 
1052  updatedSign = false;
1053 
1054  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
1055 
1056  ValueType& dist = data[pos];
1057 
1058  if (!(dist < ValueType(0.0)) && dist > ValueType(0.75)) {
1059 
1060  ijk = LeafNodeType::offsetToLocalCoord(pos);
1061 
1062  // i, j, k - 1
1063  if (ijk[2] != 0 && data[pos - 1] < ValueType(0.0)) {
1064  updatedSign = true;
1065  dist = ValueType(-dist);
1066 
1067  // i, j, k + 1
1068  } else if (ijk[2] != (LeafNodeType::DIM - 1) && data[pos + 1] < ValueType(0.0)) {
1069  updatedSign = true;
1070  dist = ValueType(-dist);
1071 
1072  // i, j - 1, k
1073  } else if (ijk[1] != 0 && data[pos - LeafNodeType::DIM] < ValueType(0.0)) {
1074  updatedSign = true;
1075  dist = ValueType(-dist);
1076 
1077  // i, j + 1, k
1078  } else if (ijk[1] != (LeafNodeType::DIM - 1)
1079  && data[pos + LeafNodeType::DIM] < ValueType(0.0))
1080  {
1081  updatedSign = true;
1082  dist = ValueType(-dist);
1083 
1084  // i - 1, j, k
1085  } else if (ijk[0] != 0
1086  && data[pos - LeafNodeType::DIM * LeafNodeType::DIM] < ValueType(0.0))
1087  {
1088  updatedSign = true;
1089  dist = ValueType(-dist);
1090 
1091  // i + 1, j, k
1092  } else if (ijk[0] != (LeafNodeType::DIM - 1)
1093  && data[pos + LeafNodeType::DIM * LeafNodeType::DIM] < ValueType(0.0))
1094  {
1095  updatedSign = true;
1096  dist = ValueType(-dist);
1097  }
1098  }
1099  } // end value loop
1100 
1101  updatedNode |= updatedSign;
1102  } // end update loop
1103 
1104  return updatedNode;
1105 } // scanFill()
1106 
1107 
1108 template<typename TreeType>
1110 {
1111 public:
1112  using ValueType = typename TreeType::ValueType;
1113  using LeafNodeType = typename TreeType::LeafNodeType;
1114 
1115  SeedFillExteriorSign(std::vector<LeafNodeType*>& nodes, bool* changedNodeMask)
1116  : mNodes(nodes.empty() ? nullptr : &nodes[0])
1117  , mChangedNodeMask(changedNodeMask)
1118  {
1119  }
1120 
1121  void operator()(const tbb::blocked_range<size_t>& range) const {
1122  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1123  if (mChangedNodeMask[n]) {
1124  //seedFill(*mNodes[n]);
1125  mChangedNodeMask[n] = scanFill(*mNodes[n]);
1126  }
1127  }
1128  }
1129 
1131  bool * const mChangedNodeMask;
1132 };
1133 
1134 
1135 template<typename ValueType>
1137 {
1138  FillArray(ValueType* array, const ValueType v) : mArray(array), mValue(v) { }
1139 
1140  void operator()(const tbb::blocked_range<size_t>& range) const {
1141  const ValueType v = mValue;
1142  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1143  mArray[n] = v;
1144  }
1145  }
1146 
1147  ValueType * const mArray;
1148  const ValueType mValue;
1149 };
1150 
1151 
1152 template<typename ValueType>
1153 inline void
1154 fillArray(ValueType* array, const ValueType val, const size_t length)
1155 {
1156  const auto grainSize = std::max<size_t>(
1157  length / tbb::task_scheduler_init::default_num_threads(), 1024);
1158  const tbb::blocked_range<size_t> range(0, length, grainSize);
1159  tbb::parallel_for(range, FillArray<ValueType>(array, val), tbb::simple_partitioner());
1160 }
1161 
1162 
1163 template<typename TreeType>
1165 {
1166 public:
1167  using ValueType = typename TreeType::ValueType;
1168  using LeafNodeType = typename TreeType::LeafNodeType;
1169 
1170  SyncVoxelMask(std::vector<LeafNodeType*>& nodes,
1171  const bool* changedNodeMask, bool* changedVoxelMask)
1172  : mNodes(nodes.empty() ? nullptr : &nodes[0])
1173  , mChangedNodeMask(changedNodeMask)
1174  , mChangedVoxelMask(changedVoxelMask)
1175  {
1176  }
1177 
1178  void operator()(const tbb::blocked_range<size_t>& range) const {
1179  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1180 
1181  if (mChangedNodeMask[n]) {
1182  bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1183 
1184  ValueType* data = mNodes[n]->buffer().data();
1185 
1186  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
1187  if (mask[pos]) {
1188  data[pos] = ValueType(-data[pos]);
1189  mask[pos] = false;
1190  }
1191  }
1192  }
1193  }
1194  }
1195 
1197  bool const * const mChangedNodeMask;
1198  bool * const mChangedVoxelMask;
1199 };
1200 
1201 
1202 template<typename TreeType>
1204 {
1205 public:
1206  using ValueType = typename TreeType::ValueType;
1207  using LeafNodeType = typename TreeType::LeafNodeType;
1209 
1211  bool* changedNodeMask, bool* nodeMask, bool* changedVoxelMask)
1212  : mConnectivity(&connectivity)
1213  , mChangedNodeMask(changedNodeMask)
1214  , mNodeMask(nodeMask)
1215  , mChangedVoxelMask(changedVoxelMask)
1216  {
1217  }
1218 
1219  void operator()(const tbb::blocked_range<size_t>& range) const {
1220 
1221  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1222 
1223  if (!mChangedNodeMask[n]) {
1224 
1225  bool changedValue = false;
1226 
1227  changedValue |= processZ(n, /*firstFace=*/true);
1228  changedValue |= processZ(n, /*firstFace=*/false);
1229 
1230  changedValue |= processY(n, /*firstFace=*/true);
1231  changedValue |= processY(n, /*firstFace=*/false);
1232 
1233  changedValue |= processX(n, /*firstFace=*/true);
1234  changedValue |= processX(n, /*firstFace=*/false);
1235 
1236  mNodeMask[n] = changedValue;
1237  }
1238  }
1239  }
1240 
1241 
1242  bool processZ(const size_t n, bool firstFace) const
1243  {
1244  const size_t offset =
1245  firstFace ? mConnectivity->offsetsPrevZ()[n] : mConnectivity->offsetsNextZ()[n];
1246  if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1247 
1248  bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1249 
1250  const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1251  const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1252 
1253  const Index lastOffset = LeafNodeType::DIM - 1;
1254  const Index lhsOffset =
1255  firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1256 
1257  Index tmpPos(0), pos(0);
1258  bool changedValue = false;
1259 
1260  for (Index x = 0; x < LeafNodeType::DIM; ++x) {
1261  tmpPos = x << (2 * LeafNodeType::LOG2DIM);
1262  for (Index y = 0; y < LeafNodeType::DIM; ++y) {
1263  pos = tmpPos + (y << LeafNodeType::LOG2DIM);
1264 
1265  if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1266  if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1267  changedValue = true;
1268  mask[pos + lhsOffset] = true;
1269  }
1270  }
1271  }
1272  }
1273 
1274  return changedValue;
1275  }
1276 
1277  return false;
1278  }
1279 
1280  bool processY(const size_t n, bool firstFace) const
1281  {
1282  const size_t offset =
1283  firstFace ? mConnectivity->offsetsPrevY()[n] : mConnectivity->offsetsNextY()[n];
1284  if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1285 
1286  bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1287 
1288  const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1289  const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1290 
1291  const Index lastOffset = LeafNodeType::DIM * (LeafNodeType::DIM - 1);
1292  const Index lhsOffset =
1293  firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1294 
1295  Index tmpPos(0), pos(0);
1296  bool changedValue = false;
1297 
1298  for (Index x = 0; x < LeafNodeType::DIM; ++x) {
1299  tmpPos = x << (2 * LeafNodeType::LOG2DIM);
1300  for (Index z = 0; z < LeafNodeType::DIM; ++z) {
1301  pos = tmpPos + z;
1302 
1303  if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1304  if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1305  changedValue = true;
1306  mask[pos + lhsOffset] = true;
1307  }
1308  }
1309  }
1310  }
1311 
1312  return changedValue;
1313  }
1314 
1315  return false;
1316  }
1317 
1318  bool processX(const size_t n, bool firstFace) const
1319  {
1320  const size_t offset =
1321  firstFace ? mConnectivity->offsetsPrevX()[n] : mConnectivity->offsetsNextX()[n];
1322  if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1323 
1324  bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1325 
1326  const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1327  const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1328 
1329  const Index lastOffset = LeafNodeType::DIM * LeafNodeType::DIM * (LeafNodeType::DIM-1);
1330  const Index lhsOffset =
1331  firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1332 
1333  Index tmpPos(0), pos(0);
1334  bool changedValue = false;
1335 
1336  for (Index y = 0; y < LeafNodeType::DIM; ++y) {
1337  tmpPos = y << LeafNodeType::LOG2DIM;
1338  for (Index z = 0; z < LeafNodeType::DIM; ++z) {
1339  pos = tmpPos + z;
1340 
1341  if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1342  if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1343  changedValue = true;
1344  mask[pos + lhsOffset] = true;
1345  }
1346  }
1347  }
1348  }
1349 
1350  return changedValue;
1351  }
1352 
1353  return false;
1354  }
1355 
1357  bool * const mChangedNodeMask;
1358  bool * const mNodeMask;
1359  bool * const mChangedVoxelMask;
1360 };
1361 
1362 
1364 
1365 template<typename TreeType, typename MeshDataAdapter>
1367 {
1368  using ValueType = typename TreeType::ValueType;
1369  using LeafNodeType = typename TreeType::LeafNodeType;
1370  using Int32TreeType = typename TreeType::template ValueConverter<Int32>::Type;
1371  using Int32LeafNodeType = typename Int32TreeType::LeafNodeType;
1372 
1373  using PointArray = boost::shared_array<Vec3d>;
1374  using MaskArray = boost::shared_array<bool>;
1375  using LocalData = std::pair<PointArray, MaskArray>;
1376  using LocalDataTable = tbb::enumerable_thread_specific<LocalData>;
1377 
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  PointArray& points = localData.first;
1406  if (!points) points.reset(new Vec3d[LeafNodeType::SIZE * 2]);
1407 
1408  MaskArray& 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>
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  {
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;
1753 }; // ValidateIntersectingVoxels
1754 
1755 
1756 template<typename TreeType>
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 
1810  TreeType * const mDistTree;
1812 }; // RemoveSelfIntersectingSurface
1813 
1814 
1816 
1817 
1818 template<typename NodeType>
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>
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>
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 
1935 
1936 
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;
1950 
1953 
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>
1977 {
1978 public:
1979 
1981  using DataTable = tbb::enumerable_thread_specific<typename VoxelizationDataType::Ptr>;
1982 
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>
2192 {
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>
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>
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 
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 
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>
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;
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 
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 
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,
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
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()),
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>
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>
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>
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>
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 
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>
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 {
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 
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  std::unique_ptr<bool[]> changedNodeMaskA{new bool[numLeafNodes]};
3045  std::unique_ptr<bool[]> changedNodeMaskB{new bool[numLeafNodes]};
3046  std::unique_ptr<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
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 =
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;
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 =
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,
3226 
3227  tbb::parallel_for(nodeRange,
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()),
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,
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  std::unique_ptr<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()),
3347 
3348  tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
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()),
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()),
3375  nodes, exteriorWidth, computeSignedDistanceField ? interiorWidth : exteriorWidth));
3376 
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
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  std::unique_ptr<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  std::unique_ptr<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
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
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
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
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
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
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
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
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
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
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
3671 {
3672  return x;
3673 }
3674 
3675 
3677 
3678 
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
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
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
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
3992  : mTree(EdgeData())
3993 {
3994 }
3995 
3996 
3997 inline void
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
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
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/ )
std::vector< Int32LeafNodeType * > & newIndexNodes()
Definition: MeshToVolume.h:2574
typename tree::ValueAccessor< TreeType > AccessorType
Definition: MeshToVolume.h:2193
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
tbb::enumerable_thread_specific< LocalData > LocalDataTable
Definition: MeshToVolume.h:1376
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:2361
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1206
typename RootNodeType::LeafNodeType LeafNodeType
Definition: Tree.h:212
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
const size_t * offsetsPrevZ() const
Definition: MeshToVolume.h:825
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:52
Int32TreeAcc indexAcc
Definition: MeshToVolume.h:1952
size_t polygonCount() const
Definition: MeshToVolume.h:211
void operator()(const tbb::blocked_range< size_t > &range)
Definition: MeshToVolume.h:2270
LeafIter beginLeaf()
Return an iterator over all leaf nodes in this tree.
Definition: Tree.h:1179
bool processX(const size_t n, bool firstFace) const
Definition: MeshToVolume.h:1318
AddNodes(TreeType &tree, std::vector< LeafNodeType *> &nodes)
Definition: MeshToVolume.h:2734
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
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:391
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2205
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:664
Definition: Types.h:269
void run(bool threaded=true)
Definition: MeshToVolume.h:3750
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:264
tbb::enumerable_thread_specific< typename VoxelizationDataType::Ptr > DataTable
Definition: MeshToVolume.h:1981
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1219
static Coord min()
Return the smallest possible coordinate.
Definition: Coord.h:70
typename TreeType::template ValueConverter< unsigned char >::Type UCharTreeType
Definition: MeshToVolume.h:1930
typename Int32TreeType::LeafNodeType Int32LeafNodeType
Definition: MeshToVolume.h:1371
static ValueType epsilon()
Definition: MeshToVolume.h:577
EdgeData(float dist=1.0)
Definition: MeshToVolume.h:468
unsigned char getNewPrimId()
Definition: MeshToVolume.h:1957
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1707
void fillArray(ValueType *array, const ValueType val, const size_t length)
Definition: MeshToVolume.h:1154
static bool check(const ValueType v)
Definition: MeshToVolume.h:1763
bool operator<(const Tuple< SIZE, T0 > &t0, const Tuple< SIZE, T1 > &t1)
Definition: Tuple.h:206
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
SyncVoxelMask(std::vector< LeafNodeType *> &nodes, const bool *changedNodeMask, bool *changedVoxelMask)
Definition: MeshToVolume.h:1170
LeafNodeType **const mNodes
Definition: MeshToVolume.h:1196
size_t findNeighbourNode(tree::ValueAccessor< const TreeType > &acc, const Coord &start, const Coord &step) const
Definition: MeshToVolume.h:750
std::vector< LeafNodeType * > *const mNodes
Definition: MeshToVolume.h:2748
#define OPENVDB_LOG_DEBUG(message)
In debug builds only, log a debugging message of the form &#39;someVar << "text" << ...&#39;.
Definition: logging.h:289
const size_t * offsetsPrevY() const
Definition: MeshToVolume.h:822
StashOriginAndStoreOffset(std::vector< LeafNodeType *> &nodes, Coord *coordinates)
Definition: MeshToVolume.h:666
boost::shared_array< bool > MaskArray
Definition: MeshToVolume.h:1374
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
static Coord max()
Return the largest possible coordinate.
Definition: Coord.h:73
Index32 mXPrim
Definition: MeshToVolume.h:492
typename TreeType::template ValueConverter< Int32 >::Type Int32TreeType
Definition: MeshToVolume.h:1761
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2362
Convert polygonal meshes that consist of quads and/or triangles into signed or unsigned distance fiel...
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:781
Vec3d voxelSize() const
Return the size of a voxel using the linear component of the map.
Definition: Transform.h:120
void operator()() const
Definition: MeshToVolume.h:1865
float mZDist
Definition: MeshToVolume.h:491
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
Definition: BBox.h:89
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1167
Fragment(Int32 idx_, Int32 x_, Int32 y_, Int32 z_, ValueType dist_)
Definition: MeshToVolume.h:2376
bool traceVoxelLine(LeafNodeType &node, Index pos, Index step) const
Definition: MeshToVolume.h:928
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1140
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:263
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:108
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:710
FillArray(ValueType *array, const ValueType v)
Definition: MeshToVolume.h:1138
LeafNodeType **const mNodes
Definition: MeshToVolume.h:701
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
Definition: ValueAccessor.h:266
Efficient multi-threaded replacement of the background values in tree.
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:548
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1760
static Coord floor(const Vec3< T > &xyz)
Return the largest integer coordinates that are not greater than xyz (node centered conversion)...
Definition: Coord.h:83
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
bool *const mChangedNodeMask
Definition: MeshToVolume.h:1131
void merge(Tree &other, MergePolicy=MERGE_ACTIVE_STATES)
Efficiently merge another tree into this tree using one of several schemes.
Definition: Tree.h:1864
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:727
math::Vec4< Index32 > Vec4I
Definition: Types.h:94
void join(ExpandNarrowband &rhs)
Definition: MeshToVolume.h:2428
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
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: MeshToVolume.h:2367
typename TreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: MeshToVolume.h:2196
void join(ConstructVoxelMask &rhs)
Definition: MeshToVolume.h:2346
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1369
LeafNodeType **const mNodes
Definition: MeshToVolume.h:1130
ConstructVoxelMask(BoolTreeType &maskTree, const TreeType &tree, std::vector< LeafNodeType *> &nodes)
Definition: MeshToVolume.h:2253
NodeType **const mNodes
Definition: MeshToVolume.h:1832
Type Pow2(Type x)
Return x2.
Definition: Math.h:498
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2969
Vec3< double > Vec3d
Definition: Vec3.h:679
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:852
SeedFillExteriorSign(std::vector< LeafNodeType *> &nodes, bool *changedNodeMask)
Definition: MeshToVolume.h:1115
TBB body object to voxelize a mesh of triangles and/or quads into a collection of VDB grids...
Definition: MeshToVolume.h:1924
LeafNodeType **const mNodes
Definition: MeshToVolume.h:679
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
CombineLeafNodes(TreeType &lhsDistTree, Int32TreeType &lhsIdxTree, LeafNodeType **rhsDistNodes, Int32LeafNodeType **rhsIdxNodes)
Definition: MeshToVolume.h:595
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:841
FloatTreeAcc distAcc
Definition: MeshToVolume.h:1949
Definition: Types.h:268
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
void operator()(const tbb::blocked_range< size_t > &range)
Definition: MeshToVolume.h:2442
const Coord & min() const
Definition: Coord.h:337
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:51
Index32 mYPrim
Definition: MeshToVolume.h:492
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1368
Tree< typename RootNodeType::template ValueConverter< Int32 >::Type > Type
Definition: Tree.h:224
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition: Coord.h:422
void operator()(const tbb::blocked_range< size_t > &range)
Definition: MeshToVolume.h:3823
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2917
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1178
static bool check(const ValueType v)
Definition: MeshToVolume.h:1710
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:687
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1121
bool operator>(const Tuple< SIZE, T0 > &t0, const Tuple< SIZE, T1 > &t1)
Definition: Tuple.h:218
const size_t * offsetsNextZ() const
Definition: MeshToVolume.h:824
Axis-aligned bounding box.
Definition: BBox.h:50
Defined various multi-threaded utility functions for trees.
bool *const mChangedNodeMask
Definition: MeshToVolume.h:1357
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1113
EdgeData operator+(const T &) const
Definition: MeshToVolume.h:481
Base class for tree-traversal iterators over tile and voxel values.
Definition: TreeIterator.h:658
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1718
float mXDist
Definition: MeshToVolume.h:491
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:604
Definition: Transform.h:66
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:671
void clearAllAccessors()
Clear all registered accessors.
Definition: Tree.h:1547
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1823
const size_t * offsetsNextX() const
Definition: MeshToVolume.h:818
EdgeData operator-() const
Definition: MeshToVolume.h:483
Renormalize(const TreeType &tree, const std::vector< LeafNodeType *> &nodes, ValueType *buffer, ValueType voxelSize)
Definition: MeshToVolume.h:2908
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
uint32_t Index32
Definition: Types.h:58
typename TreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: MeshToVolume.h:2250
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1759
ExpandNarrowband(std::vector< BoolLeafNodeType *> &maskNodes, BoolTreeType &maskTree, TreeType &distTree, Int32TreeType &indexTree, const MeshDataAdapter &mesh, ValueType exteriorBandWidth, ValueType interiorBandWidth, ValueType voxelSize)
Definition: MeshToVolume.h:2386
TreeType & tree()
Definition: MeshToVolume.h:3693
SweepExteriorSign(Axis axis, const std::vector< size_t > &startNodeIndices, ConnectivityTable &connectivity)
Definition: MeshToVolume.h:844
bool processY(const size_t n, bool firstFace) const
Definition: MeshToVolume.h:1280
BoolTreeType & newMaskTree()
Definition: MeshToVolume.h:2569
Index32 Index
Definition: Types.h:60
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2248
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1207
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:136
const ValueType mValue
Definition: MeshToVolume.h:1148
bool operator<(const Fragment &rhs) const
Definition: MeshToVolume.h:2381
bool *const mChangedVoxelMask
Definition: MeshToVolume.h:1359
Axis
Definition: Math.h:852
T dot(const Vec3< T > &v) const
Dot product.
Definition: Vec3.h:216
virtual void clear()
Remove all nodes from this cache, then reinsert the root node.
Definition: ValueAccessor.h:438
OPENVDB_API const Coord COORD_OFFSETS[26]
coordinate offset table for neighboring voxels
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2881
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:840
Accessor getAccessor()
Definition: MeshToVolume.h:522
typename LeafNodeType::NodeMaskType NodeMaskType
Definition: MeshToVolume.h:2363
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1773
Internal edge data type.
Definition: MeshToVolume.h:467
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:592
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:694
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition: Coord.h:202
typename Int32TreeType::LeafNodeType Int32LeafNodeType
Definition: MeshToVolume.h:2365
MeshToVoxelEdgeData()
Definition: MeshToVolume.h:3991
Definition: Tree.h:203
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1855
static const Real LEVEL_SET_HALF_WIDTH
Definition: Types.h:275
_RootNodeType RootNodeType
Definition: Tree.h:209
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
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1112
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:256
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
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:711
Contiguous quad and triangle data adapter class.
Definition: MeshToVolume.h:191
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: MeshToVolume.h:2197
Definition: Exceptions.h:39
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2977
Int32TreeType indexTree
Definition: MeshToVolume.h:1951
std::ostream & operator<<(std::ostream &ostr, const MeshToVoxelEdgeData::EdgeData &rhs)
Definition: MeshToVolume.h:3660
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:2829
bool scanFill(LeafNodeType &node)
Definition: MeshToVolume.h:1040
Extracts and stores voxel edge intersection data from a mesh.
Definition: MeshToVolume.h:460
PointType const *const mPointsIn
Definition: MeshToVolume.h:568
ValueType *const mArray
Definition: MeshToVolume.h:1147
void operator()() const
Definition: MeshToVolume.h:2739
void seedFill(LeafNodeType &node)
Definition: MeshToVolume.h:964
void join(GenEdgeData &rhs)
Definition: MeshToVolume.h:3761
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:2791
InactivateValues(std::vector< LeafNodeType *> &nodes, ValueType exBandWidth, ValueType inBandWidth)
Definition: MeshToVolume.h:2831
typename TreeType::template ValueConverter< Int32 >::Type Int32TreeType
Definition: MeshToVolume.h:2364
ValidateIntersectingVoxels(TreeType &tree, std::vector< LeafNodeType *> &nodes)
Definition: MeshToVolume.h:1712
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2801
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2839
typename TreeType::template ValueConverter< Int32 >::Type Int32TreeType
Definition: MeshToVolume.h:1929
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:1927
bool processZ(const size_t n, bool firstFace) const
Definition: MeshToVolume.h:1242
void combineData(DistTreeType &lhsDist, IndexTreeType &lhsIdx, DistTreeType &rhsDist, IndexTreeType &rhsIdx)
Definition: MeshToVolume.h:1894
typename Int32TreeType::LeafNodeType Int32LeafNodeType
Definition: MeshToVolume.h:593
typename BoolTreeType::LeafNodeType BoolLeafNodeType
Definition: MeshToVolume.h:2251
Int32TreeType *const mIndexTree
Definition: MeshToVolume.h:1811
Definition: Math.h:855
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition: Coord.h:118
Definition: Mat4.h:51
GenEdgeData(const std::vector< Vec3s > &pointList, const std::vector< Vec4I > &polygonList)
Definition: MeshToVolume.h:3724
bool checkNeighbours(const Coord &ijk, AccessorType &acc, bool(&mask)[26])
Definition: MeshToVolume.h:1692
StealUniqueLeafNodes(TreeType &lhsTree, TreeType &rhsTree, std::vector< LeafNodeType *> &overlappingNodes)
Definition: MeshToVolume.h:1857
QuadAndTriangleDataAdapter(const PointType *pointArray, size_t pointArraySize, const PolygonType *polygonArray, size_t polygonArraySize)
Definition: MeshToVolume.h:202
std::vector< Int32LeafNodeType * > & updatedIndexNodes()
Definition: MeshToVolume.h:2575
EdgeData operator-(const T &) const
Definition: MeshToVolume.h:482
bool const *const mChangedNodeMask
Definition: MeshToVolume.h:1197
typename TreeType::template ValueConverter< Int32 >::Type Int32TreeType
Definition: MeshToVolume.h:590
Definition: Math.h:854
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
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2790
void maxComponent(const Coord &other)
Perform a component-wise maximum with the other Coord.
Definition: Coord.h:210
TransformPoints(const PointType *pointsIn, PointType *pointsOut, const math::Transform &xform)
Definition: MeshToVolume.h:542
bool isZero(const Type &x)
Return true if x is exactly equal to zero.
Definition: Math.h:308
std::vector< LeafNodeType * > & newDistNodes()
Definition: MeshToVolume.h:2571
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
static ValueType minNarrowBandWidth()
Definition: MeshToVolume.h:578
std::shared_ptr< T > SharedPtr
Definition: Types.h:134
LeafNodeType **const mNodes
Definition: MeshToVolume.h:1809
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2828
Definition: MeshToVolume.h:101
void clear()
Remove all tiles from this tree and all nodes other than the root node.
Definition: Tree.h:1488
Vec3< T > cross(const Vec3< T > &v) const
Return the cross product of "this" vector and v;.
Definition: Vec3.h:245
size_t vertexCount(size_t n) const
Vertex count for polygon n.
Definition: MeshToVolume.h:215
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
VoxelizePolygons(DataTable &dataTable, const MeshDataAdapter &mesh, Interrupter *interrupter=nullptr)
Definition: MeshToVolume.h:1983
LeafNodeConnectivityTable(TreeType &tree)
Definition: MeshToVolume.h:783
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
Definition: BBox.h:91
LeafNodeType **const mNodes
Definition: MeshToVolume.h:1752
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
void maskNodeInternalNeighbours(const Index pos, bool(&mask)[26])
Definition: MeshToVolume.h:1561
DiffLeafNodeMask(const TreeType &rhsTree, std::vector< BoolLeafNodeType *> &lhsNodes)
Definition: MeshToVolume.h:2199
float mYDist
Definition: MeshToVolume.h:491
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2873
ComputeIntersectingVoxelSign(std::vector< LeafNodeType *> &distNodes, const TreeType &distTree, const Int32TreeType &indexTree, const MeshDataAdapter &mesh)
Definition: MeshToVolume.h:1378
std::unique_ptr< VoxelizationData > Ptr
Definition: MeshToVolume.h:1926
Base class for tree-traversal iterators over all leaf nodes (but not leaf voxels) ...
Definition: TreeIterator.h:1228
Index32 mZPrim
Definition: MeshToVolume.h:492
Coord const *const mCoordinates
Definition: MeshToVolume.h:702
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...
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1392
TreeType *const mTree
Definition: MeshToVolume.h:2747
UCharTreeType primIdTree
Definition: MeshToVolume.h:1954
bool operator==(const EdgeData &rhs) const
Definition: MeshToVolume.h:486
math::Transform const *const mXform
Definition: MeshToVolume.h:570
typename TreeType::template ValueConverter< bool >::Type BoolTreeType
Definition: MeshToVolume.h:2366
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:2906
const std::vector< LeafNodeType * > & nodes() const
Definition: MeshToVolume.h:815
ExpandNarrowband(const ExpandNarrowband &rhs, tbb::split)
Definition: MeshToVolume.h:2411
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2732
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
void releaseLeafNodes(TreeType &tree)
Definition: MeshToVolume.h:1838
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
std::pair< PointArray, MaskArray > LocalData
Definition: MeshToVolume.h:1375
math::Vec3< Index32 > Vec3I
Definition: Types.h:79
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
Definition: Math.h:853
bool *const mChangedVoxelMask
Definition: MeshToVolume.h:1198
UnionValueMasks(std::vector< LeafNodeTypeA *> &nodesA, std::vector< LeafNodeTypeB *> &nodesB)
Definition: MeshToVolume.h:2227
RestoreOrigin(std::vector< LeafNodeType *> &nodes, const Coord *coordinates)
Definition: MeshToVolume.h:689
std::vector< LeafNodeType * > & updatedDistNodes()
Definition: MeshToVolume.h:2572
ConnectivityTable *const mConnectivity
Definition: MeshToVolume.h:1356
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:1734
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
Definition: Mat.h:197
const ValueT & getValue() const
Return the tile or voxel value to which this iterator is currently pointing.
Definition: TreeIterator.h:734
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2905
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:188
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1168
Ptr copy() const
Definition: Transform.h:77
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:280
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
SeedPoints(ConnectivityTable &connectivity, bool *changedNodeMask, bool *nodeMask, bool *changedVoxelMask)
Definition: MeshToVolume.h:1210
const Coord & max() const
Definition: Coord.h:338
Vec3< float > Vec3s
Definition: Vec3.h:678
PointType *const mPointsOut
Definition: MeshToVolume.h:569
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
const size_t * offsetsNextY() const
Definition: MeshToVolume.h:821
typename TreeType::template ValueConverter< Int32 >::Type Int32TreeType
Definition: MeshToVolume.h:1370
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:1708
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:1992
MeshToVoxelEdgeData::EdgeData Abs(const MeshToVoxelEdgeData::EdgeData &x)
Definition: MeshToVolume.h:3670
const size_t * offsetsPrevX() const
Definition: MeshToVolume.h:819
typename TreeType::LeafNodeType LeafNodeType
Definition: MeshToVolume.h:2194
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:2970
QuadAndTriangleDataAdapter(const std::vector< PointType > &points, const std::vector< PolygonType > &polygons)
Definition: MeshToVolume.h:193
int32_t Int32
Definition: Types.h:62
ComputeNodeConnectivity(const TreeType &tree, const Coord *coordinates, size_t *offsets, size_t numNodes, const CoordBBox &bbox)
Definition: MeshToVolume.h:712
bool isInside(const Coord &xyz) const
Return true if point (x, y, z) is inside this bounding box.
Definition: Coord.h:404
ReleaseChildNodes(NodeType **nodes)
Definition: MeshToVolume.h:1821
MeshToVolumeFlags
Mesh to volume conversion flags.
Definition: MeshToVolume.h:87
ConstructVoxelMask(ConstructVoxelMask &rhs, tbb::split)
Definition: MeshToVolume.h:2262
NodeType * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
Definition: ValueAccessor.h:349
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: MeshToVolume.h:2233
UCharTreeAcc primIdAcc
Definition: MeshToVolume.h:1955
RemoveSelfIntersectingSurface(std::vector< LeafNodeType *> &nodes, TreeType &distTree, Int32TreeType &indexTree)
Definition: MeshToVolume.h:1765
OffsetValues(std::vector< LeafNodeType *> &nodes, ValueType offset)
Definition: MeshToVolume.h:2876
Partitions points into BucketLog2Dim aligned buckets using a parallel radix-based sorting algorithm...
std::vector< LeafNodeType * > & nodes()
Definition: MeshToVolume.h:814
MinCombine(std::vector< LeafNodeType *> &nodes, const ValueType *buffer)
Definition: MeshToVolume.h:2972
bool *const mNodeMask
Definition: MeshToVolume.h:1358
size_t pointCount() const
Definition: MeshToVolume.h:212
TransformValues(std::vector< LeafNodeType *> &nodes, ValueType voxelSize, bool unsignedDist)
Definition: MeshToVolume.h:2793
typename TreeType::ValueType ValueType
Definition: MeshToVolume.h:2874
OPENVDB_API const Index32 INVALID_IDX