16#ifndef OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED
17#define OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED
26#include <openvdb/thread/Threading.h>
33#include <tbb/blocked_range.h>
34#include <tbb/enumerable_thread_specific.h>
35#include <tbb/parallel_for.h>
36#include <tbb/parallel_reduce.h>
37#include <tbb/partitioner.h>
38#include <tbb/task_group.h>
39#include <tbb/task_arena.h>
128template <
typename Gr
idType,
typename MeshDataAdapter,
typename InteriorTest = std::
nullptr_t>
129typename GridType::Ptr
132 const math::Transform& transform,
133 float exteriorBandWidth = 3.0f,
134 float interiorBandWidth = 3.0f,
136 typename GridType::template ValueConverter<Int32>::Type * polygonIndexGrid =
nullptr,
137 InteriorTest interiorTest =
nullptr,
138 InteriorTestStrategy interiorTestStrat = EVAL_EVERY_VOXEL);
159template <
typename Gr
idType,
typename MeshDataAdapter,
typename Interrupter,
typename InteriorTest = std::
nullptr_t>
160typename GridType::Ptr
162 Interrupter& interrupter,
164 const math::Transform& transform,
165 float exteriorBandWidth = 3.0f,
166 float interiorBandWidth = 3.0f,
168 typename GridType::template ValueConverter<Int32>::Type * polygonIndexGrid =
nullptr,
169 InteriorTest interiorTest =
nullptr,
170 InteriorTestStrategy interiorTestStrategy = EVAL_EVERY_VOXEL);
186template<
typename Po
intType,
typename PolygonType>
190 const std::vector<PolygonType>& polygons)
192 , mPointArraySize(
points.size())
193 , mPolygonArray(polygons.empty() ? nullptr : &polygons[0])
194 , mPolygonArraySize(polygons.size())
199 const PolygonType* polygonArray,
size_t polygonArraySize)
200 : mPointArray(pointArray)
201 , mPointArraySize(pointArraySize)
202 , mPolygonArray(polygonArray)
203 , mPolygonArraySize(polygonArraySize)
212 return (PolygonType::size == 3 || mPolygonArray[n][3] ==
util::INVALID_IDX) ? 3 : 4;
218 const PointType& p = mPointArray[mPolygonArray[n][int(v)]];
219 pos[0] = double(p[0]);
220 pos[1] = double(p[1]);
221 pos[2] = double(p[2]);
225 PointType
const *
const mPointArray;
226 size_t const mPointArraySize;
227 PolygonType
const *
const mPolygonArray;
228 size_t const mPolygonArraySize;
256template<
typename Gr
idType>
257typename GridType::Ptr
259 const openvdb::math::Transform& xform,
260 const std::vector<Vec3s>&
points,
261 const std::vector<Vec3I>& triangles,
265template<
typename Gr
idType,
typename Interrupter>
266typename GridType::Ptr
268 Interrupter& interrupter,
269 const openvdb::math::Transform& xform,
270 const std::vector<Vec3s>&
points,
271 const std::vector<Vec3I>& triangles,
290template<
typename Gr
idType>
291typename GridType::Ptr
293 const openvdb::math::Transform& xform,
294 const std::vector<Vec3s>&
points,
295 const std::vector<Vec4I>& quads,
299template<
typename Gr
idType,
typename Interrupter>
300typename GridType::Ptr
302 Interrupter& interrupter,
303 const openvdb::math::Transform& xform,
304 const std::vector<Vec3s>&
points,
305 const std::vector<Vec4I>& quads,
325template<
typename Gr
idType>
326typename GridType::Ptr
328 const openvdb::math::Transform& xform,
329 const std::vector<Vec3s>&
points,
330 const std::vector<Vec3I>& triangles,
331 const std::vector<Vec4I>& quads,
335template<
typename Gr
idType,
typename Interrupter>
336typename GridType::Ptr
338 Interrupter& interrupter,
339 const openvdb::math::Transform& xform,
340 const std::vector<Vec3s>&
points,
341 const std::vector<Vec3I>& triangles,
342 const std::vector<Vec4I>& quads,
364template<
typename Gr
idType>
365typename GridType::Ptr
366meshToSignedDistanceField(
367 const openvdb::math::Transform& xform,
368 const std::vector<Vec3s>&
points,
369 const std::vector<Vec3I>& triangles,
370 const std::vector<Vec4I>& quads,
375template<
typename Gr
idType,
typename Interrupter>
376typename GridType::Ptr
377meshToSignedDistanceField(
378 Interrupter& interrupter,
379 const openvdb::math::Transform& xform,
380 const std::vector<Vec3s>&
points,
381 const std::vector<Vec3I>& triangles,
382 const std::vector<Vec4I>& quads,
401template<
typename Gr
idType>
402typename GridType::Ptr
403meshToUnsignedDistanceField(
404 const openvdb::math::Transform& xform,
405 const std::vector<Vec3s>&
points,
406 const std::vector<Vec3I>& triangles,
407 const std::vector<Vec4I>& quads,
411template<
typename Gr
idType,
typename Interrupter>
412typename GridType::Ptr
413meshToUnsignedDistanceField(
414 Interrupter& interrupter,
415 const openvdb::math::Transform& xform,
416 const std::vector<Vec3s>&
points,
417 const std::vector<Vec3I>& triangles,
418 const std::vector<Vec4I>& quads,
431template<
typename Gr
idType,
typename VecType>
432typename GridType::Ptr
434 const openvdb::math::Transform& xform,
447template <
typename FloatTreeT>
449traceExteriorBoundaries(FloatTreeT&
tree);
475 bool operator< (
const EdgeData&)
const {
return false; }
476 bool operator> (
const EdgeData&)
const {
return false; }
508 void convert(
const std::vector<Vec3s>& pointList,
const std::vector<Vec4I>& polygonList);
514 std::vector<Vec3d>&
points, std::vector<Index32>& primitives);
535namespace mesh_to_volume_internal {
537template<
typename Po
intType>
538struct TransformPoints {
540 TransformPoints(
const PointType* pointsIn, PointType* pointsOut,
542 : mPointsIn(pointsIn), mPointsOut(pointsOut), mXform(&xform)
546 void operator()(
const tbb::blocked_range<size_t>& range)
const {
550 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
552 const PointType& wsP = mPointsIn[n];
553 pos[0] = double(wsP[0]);
554 pos[1] = double(wsP[1]);
555 pos[2] = double(wsP[2]);
557 pos = mXform->worldToIndex(pos);
559 PointType& isP = mPointsOut[n];
560 isP[0] =
typename PointType::value_type(pos[0]);
561 isP[1] =
typename PointType::value_type(pos[1]);
562 isP[2] =
typename PointType::value_type(pos[2]);
568 math::Transform
const *
const mXform;
572template<
typename ValueType>
575 static ValueType epsilon() {
return ValueType(1e-7); }
576 static ValueType minNarrowBandWidth() {
return ValueType(1.0 + 1e-6); }
583template<
typename TreeType>
584class CombineLeafNodes
588 using Int32TreeType =
typename TreeType::template ValueConverter<Int32>::Type;
590 using LeafNodeType =
typename TreeType::LeafNodeType;
591 using Int32LeafNodeType =
typename Int32TreeType::LeafNodeType;
593 CombineLeafNodes(TreeType& lhsDistTree, Int32TreeType& lhsIdxTree,
594 LeafNodeType ** rhsDistNodes, Int32LeafNodeType ** rhsIdxNodes)
595 : mDistTree(&lhsDistTree)
596 , mIdxTree(&lhsIdxTree)
597 , mRhsDistNodes(rhsDistNodes)
598 , mRhsIdxNodes(rhsIdxNodes)
602 void operator()(
const tbb::blocked_range<size_t>& range)
const {
604 tree::ValueAccessor<TreeType> distAcc(*mDistTree);
605 tree::ValueAccessor<Int32TreeType> idxAcc(*mIdxTree);
607 using DistValueType =
typename LeafNodeType::ValueType;
608 using IndexValueType =
typename Int32LeafNodeType::ValueType;
610 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
612 const Coord& origin = mRhsDistNodes[n]->origin();
614 LeafNodeType* lhsDistNode = distAcc.probeLeaf(origin);
615 Int32LeafNodeType* lhsIdxNode = idxAcc.probeLeaf(origin);
617 DistValueType* lhsDistData = lhsDistNode->buffer().data();
618 IndexValueType* lhsIdxData = lhsIdxNode->buffer().data();
620 const DistValueType* rhsDistData = mRhsDistNodes[n]->buffer().data();
621 const IndexValueType* rhsIdxData = mRhsIdxNodes[n]->buffer().data();
624 for (Index32 offset = 0; offset < LeafNodeType::SIZE; ++offset) {
626 if (rhsIdxData[offset] !=
Int32(util::INVALID_IDX)) {
628 const DistValueType& lhsValue = lhsDistData[offset];
629 const DistValueType& rhsValue = rhsDistData[offset];
631 if (rhsValue < lhsValue) {
632 lhsDistNode->setValueOn(offset, rhsValue);
633 lhsIdxNode->setValueOn(offset, rhsIdxData[offset]);
634 }
else if (math::isExactlyEqual(rhsValue, lhsValue)) {
635 lhsIdxNode->setValueOn(offset,
636 std::min(lhsIdxData[offset], rhsIdxData[offset]));
641 delete mRhsDistNodes[n];
642 delete mRhsIdxNodes[n];
648 TreeType *
const mDistTree;
649 Int32TreeType *
const mIdxTree;
651 LeafNodeType **
const mRhsDistNodes;
652 Int32LeafNodeType **
const mRhsIdxNodes;
659template<
typename TreeType>
660struct StashOriginAndStoreOffset
662 using LeafNodeType =
typename TreeType::LeafNodeType;
664 StashOriginAndStoreOffset(std::vector<LeafNodeType*>& nodes, Coord* coordinates)
665 : mNodes(nodes.
empty() ? nullptr : &nodes[0]), mCoordinates(coordinates)
669 void operator()(
const tbb::blocked_range<size_t>& range)
const {
670 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
671 Coord& origin =
const_cast<Coord&
>(mNodes[n]->origin());
672 mCoordinates[n] = origin;
673 origin[0] =
static_cast<int>(n);
677 LeafNodeType **
const mNodes;
678 Coord *
const mCoordinates;
682template<
typename TreeType>
685 using LeafNodeType =
typename TreeType::LeafNodeType;
687 RestoreOrigin(std::vector<LeafNodeType*>& nodes,
const Coord* coordinates)
688 : mNodes(nodes.
empty() ? nullptr : &nodes[0]), mCoordinates(coordinates)
692 void operator()(
const tbb::blocked_range<size_t>& range)
const {
693 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
694 Coord& origin =
const_cast<Coord&
>(mNodes[n]->origin());
695 origin[0] = mCoordinates[n][0];
699 LeafNodeType **
const mNodes;
700 Coord
const *
const mCoordinates;
704template<
typename TreeType>
705class ComputeNodeConnectivity
708 using LeafNodeType =
typename TreeType::LeafNodeType;
710 ComputeNodeConnectivity(
const TreeType& tree,
const Coord* coordinates,
711 size_t* offsets,
size_t numNodes,
const CoordBBox& bbox)
713 , mCoordinates(coordinates)
715 , mNumNodes(numNodes)
720 ComputeNodeConnectivity(
const ComputeNodeConnectivity&) =
default;
723 ComputeNodeConnectivity& operator=(
const ComputeNodeConnectivity&) =
delete;
725 void operator()(
const tbb::blocked_range<size_t>& range)
const {
727 size_t* offsetsNextX = mOffsets;
728 size_t* offsetsPrevX = mOffsets + mNumNodes;
729 size_t* offsetsNextY = mOffsets + mNumNodes * 2;
730 size_t* offsetsPrevY = mOffsets + mNumNodes * 3;
731 size_t* offsetsNextZ = mOffsets + mNumNodes * 4;
732 size_t* offsetsPrevZ = mOffsets + mNumNodes * 5;
734 tree::ValueAccessor<const TreeType> acc(*mTree);
736 const Int32 DIM =
static_cast<Int32>(LeafNodeType::DIM);
738 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
739 const Coord& origin = mCoordinates[n];
740 offsetsNextX[n] = findNeighbourNode(acc, origin, Coord(DIM, 0, 0));
741 offsetsPrevX[n] = findNeighbourNode(acc, origin, Coord(-DIM, 0, 0));
742 offsetsNextY[n] = findNeighbourNode(acc, origin, Coord(0, DIM, 0));
743 offsetsPrevY[n] = findNeighbourNode(acc, origin, Coord(0, -DIM, 0));
744 offsetsNextZ[n] = findNeighbourNode(acc, origin, Coord(0, 0, DIM));
745 offsetsPrevZ[n] = findNeighbourNode(acc, origin, Coord(0, 0, -DIM));
749 size_t findNeighbourNode(tree::ValueAccessor<const TreeType>& acc,
750 const Coord& start,
const Coord& step)
const
752 Coord ijk = start + step;
753 CoordBBox bbox(mBBox);
755 while (bbox.isInside(ijk)) {
756 const LeafNodeType* node = acc.probeConstLeaf(ijk);
757 if (node)
return static_cast<size_t>(node->origin()[0]);
761 return std::numeric_limits<size_t>::max();
766 TreeType
const *
const mTree;
767 Coord
const *
const mCoordinates;
768 size_t *
const mOffsets;
770 const size_t mNumNodes;
771 const CoordBBox mBBox;
775template<
typename TreeType>
776struct LeafNodeConnectivityTable
778 enum { INVALID_OFFSET = std::numeric_limits<size_t>::max() };
780 using LeafNodeType =
typename TreeType::LeafNodeType;
782 LeafNodeConnectivityTable(TreeType& tree)
784 mLeafNodes.reserve(tree.leafCount());
785 tree.getNodes(mLeafNodes);
787 if (mLeafNodes.empty())
return;
790 tree.evalLeafBoundingBox(bbox);
792 const tbb::blocked_range<size_t> range(0, mLeafNodes.size());
796 std::unique_ptr<Coord[]> coordinates{
new Coord[mLeafNodes.size()]};
797 tbb::parallel_for(range,
798 StashOriginAndStoreOffset<TreeType>(mLeafNodes, coordinates.get()));
801 mOffsets.reset(
new size_t[mLeafNodes.size() * 6]);
804 tbb::parallel_for(range, ComputeNodeConnectivity<TreeType>(
805 tree, coordinates.get(), mOffsets.get(), mLeafNodes.size(), bbox));
808 tbb::parallel_for(range, RestoreOrigin<TreeType>(mLeafNodes, coordinates.get()));
811 size_t size()
const {
return mLeafNodes.size(); }
813 std::vector<LeafNodeType*>& nodes() {
return mLeafNodes; }
814 const std::vector<LeafNodeType*>& nodes()
const {
return mLeafNodes; }
817 const size_t* offsetsNextX()
const {
return mOffsets.get(); }
818 const size_t* offsetsPrevX()
const {
return mOffsets.get() + mLeafNodes.size(); }
820 const size_t* offsetsNextY()
const {
return mOffsets.get() + mLeafNodes.size() * 2; }
821 const size_t* offsetsPrevY()
const {
return mOffsets.get() + mLeafNodes.size() * 3; }
823 const size_t* offsetsNextZ()
const {
return mOffsets.get() + mLeafNodes.size() * 4; }
824 const size_t* offsetsPrevZ()
const {
return mOffsets.get() + mLeafNodes.size() * 5; }
827 std::vector<LeafNodeType*> mLeafNodes;
828 std::unique_ptr<size_t[]> mOffsets;
832template<
typename TreeType>
833class SweepExteriorSign
839 using ValueType =
typename TreeType::ValueType;
840 using LeafNodeType =
typename TreeType::LeafNodeType;
841 using ConnectivityTable = LeafNodeConnectivityTable<TreeType>;
843 SweepExteriorSign(Axis axis,
const std::vector<size_t>& startNodeIndices,
844 ConnectivityTable& connectivity)
845 : mStartNodeIndices(startNodeIndices.
empty() ? nullptr : &startNodeIndices[0])
846 , mConnectivity(&connectivity)
851 void operator()(
const tbb::blocked_range<size_t>& range)
const {
853 constexpr Int32 DIM =
static_cast<Int32>(LeafNodeType::DIM);
855 std::vector<LeafNodeType*>& nodes = mConnectivity->nodes();
858 size_t idxA = 0, idxB = 1;
861 const size_t* nextOffsets = mConnectivity->offsetsNextZ();
862 const size_t* prevOffsets = mConnectivity->offsetsPrevZ();
864 if (mAxis == Y_AXIS) {
870 nextOffsets = mConnectivity->offsetsNextY();
871 prevOffsets = mConnectivity->offsetsPrevY();
873 }
else if (mAxis == X_AXIS) {
879 nextOffsets = mConnectivity->offsetsNextX();
880 prevOffsets = mConnectivity->offsetsPrevX();
885 Int32& a = ijk[idxA];
886 Int32& b = ijk[idxB];
888 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
890 size_t startOffset = mStartNodeIndices[n];
891 size_t lastOffset = startOffset;
895 for (a = 0; a < DIM; ++a) {
896 for (b = 0; b < DIM; ++b) {
898 pos =
static_cast<Int32>(LeafNodeType::coordToOffset(ijk));
899 size_t offset = startOffset;
902 while ( offset != ConnectivityTable::INVALID_OFFSET &&
903 traceVoxelLine(*nodes[offset], pos, step) ) {
906 offset = nextOffsets[offset];
911 while (offset != ConnectivityTable::INVALID_OFFSET) {
913 offset = nextOffsets[offset];
918 pos += step * (DIM - 1);
919 while ( offset != ConnectivityTable::INVALID_OFFSET &&
920 traceVoxelLine(*nodes[offset], pos, -step)) {
921 offset = prevOffsets[offset];
929 bool traceVoxelLine(LeafNodeType& node, Int32 pos,
const Int32 step)
const {
931 ValueType* data = node.buffer().data();
933 bool isOutside =
true;
935 for (Index i = 0; i < LeafNodeType::DIM; ++i) {
938 ValueType& dist = data[pos];
940 if (dist < ValueType(0.0)) {
944 if (!(dist > ValueType(0.75))) isOutside =
false;
946 if (isOutside) dist = ValueType(-dist);
957 size_t const *
const mStartNodeIndices;
958 ConnectivityTable *
const mConnectivity;
964template<
typename LeafNodeType>
966seedFill(LeafNodeType& node)
968 using ValueType =
typename LeafNodeType::ValueType;
969 using Queue = std::deque<Index>;
972 ValueType* data = node.buffer().data();
976 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
977 if (data[pos] < 0.0) seedPoints.push_back(pos);
980 if (seedPoints.empty())
return;
983 for (Queue::iterator it = seedPoints.begin(); it != seedPoints.end(); ++it) {
984 ValueType& dist = data[*it];
991 Index pos(0), nextPos(0);
993 while (!seedPoints.empty()) {
995 pos = seedPoints.back();
996 seedPoints.pop_back();
998 ValueType& dist = data[pos];
1000 if (!(dist < ValueType(0.0))) {
1004 ijk = LeafNodeType::offsetToLocalCoord(pos);
1007 nextPos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
1008 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1011 if (ijk[0] != (LeafNodeType::DIM - 1)) {
1012 nextPos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
1013 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1017 nextPos = pos - LeafNodeType::DIM;
1018 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1021 if (ijk[1] != (LeafNodeType::DIM - 1)) {
1022 nextPos = pos + LeafNodeType::DIM;
1023 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1028 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1031 if (ijk[2] != (LeafNodeType::DIM - 1)) {
1033 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1040template<
typename LeafNodeType>
1042scanFill(LeafNodeType& node)
1044 bool updatedNode =
false;
1046 using ValueType =
typename LeafNodeType::ValueType;
1047 ValueType* data = node.buffer().data();
1051 bool updatedSign =
true;
1052 while (updatedSign) {
1054 updatedSign =
false;
1056 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
1058 ValueType& dist = data[pos];
1060 if (!(dist < ValueType(0.0)) && dist > ValueType(0.75)) {
1062 ijk = LeafNodeType::offsetToLocalCoord(pos);
1065 if (ijk[2] != 0 && data[pos - 1] < ValueType(0.0)) {
1067 dist = ValueType(-dist);
1070 }
else if (ijk[2] != (LeafNodeType::DIM - 1) && data[pos + 1] < ValueType(0.0)) {
1072 dist = ValueType(-dist);
1075 }
else if (ijk[1] != 0 && data[pos - LeafNodeType::DIM] < ValueType(0.0)) {
1077 dist = ValueType(-dist);
1080 }
else if (ijk[1] != (LeafNodeType::DIM - 1)
1081 && data[pos + LeafNodeType::DIM] < ValueType(0.0))
1084 dist = ValueType(-dist);
1087 }
else if (ijk[0] != 0
1088 && data[pos - LeafNodeType::DIM * LeafNodeType::DIM] < ValueType(0.0))
1091 dist = ValueType(-dist);
1094 }
else if (ijk[0] != (LeafNodeType::DIM - 1)
1095 && data[pos + LeafNodeType::DIM * LeafNodeType::DIM] < ValueType(0.0))
1098 dist = ValueType(-dist);
1103 updatedNode |= updatedSign;
1110template<
typename TreeType>
1111class SeedFillExteriorSign
1114 using ValueType =
typename TreeType::ValueType;
1115 using LeafNodeType =
typename TreeType::LeafNodeType;
1117 SeedFillExteriorSign(std::vector<LeafNodeType*>& nodes,
const bool* changedNodeMask)
1118 : mNodes(nodes.
empty() ? nullptr : &nodes[0])
1119 , mChangedNodeMask(changedNodeMask)
1123 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1124 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1125 if (mChangedNodeMask[n]) {
1131 scanFill(*mNodes[n]);
1136 LeafNodeType **
const mNodes;
1137 const bool *
const mChangedNodeMask;
1141template<
typename ValueType>
1144 FillArray(ValueType* array,
const ValueType v) : mArray(array), mValue(v) { }
1146 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1147 const ValueType v = mValue;
1148 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1153 ValueType *
const mArray;
1154 const ValueType mValue;
1158template<
typename ValueType>
1160fillArray(ValueType* array,
const ValueType val,
const size_t length)
1162 const auto grainSize = std::max<size_t>(
1163 length / tbb::this_task_arena::max_concurrency(), 1024);
1164 const tbb::blocked_range<size_t> range(0, length, grainSize);
1165 tbb::parallel_for(range, FillArray<ValueType>(array, val), tbb::simple_partitioner());
1169template<
typename TreeType>
1173 using ValueType =
typename TreeType::ValueType;
1174 using LeafNodeType =
typename TreeType::LeafNodeType;
1176 SyncVoxelMask(std::vector<LeafNodeType*>& nodes,
1177 const bool* changedNodeMask,
bool* changedVoxelMask)
1178 : mNodes(nodes.
empty() ? nullptr : &nodes[0])
1179 , mChangedNodeMask(changedNodeMask)
1180 , mChangedVoxelMask(changedVoxelMask)
1184 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1185 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1187 if (mChangedNodeMask[n]) {
1188 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1190 ValueType* data = mNodes[n]->buffer().data();
1192 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
1194 data[pos] = ValueType(-data[pos]);
1202 LeafNodeType **
const mNodes;
1203 bool const *
const mChangedNodeMask;
1204 bool *
const mChangedVoxelMask;
1208template<
typename TreeType>
1212 using ValueType =
typename TreeType::ValueType;
1213 using LeafNodeType =
typename TreeType::LeafNodeType;
1214 using ConnectivityTable = LeafNodeConnectivityTable<TreeType>;
1216 SeedPoints(ConnectivityTable& connectivity,
1217 bool* changedNodeMask,
bool* nodeMask,
bool* changedVoxelMask)
1218 : mConnectivity(&connectivity)
1219 , mChangedNodeMask(changedNodeMask)
1220 , mNodeMask(nodeMask)
1221 , mChangedVoxelMask(changedVoxelMask)
1225 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1227 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1228 bool changedValue =
false;
1230 changedValue |= processZ(n,
true);
1231 changedValue |= processZ(n,
false);
1233 changedValue |= processY(n,
true);
1234 changedValue |= processY(n,
false);
1236 changedValue |= processX(n,
true);
1237 changedValue |= processX(n,
false);
1239 mNodeMask[n] = changedValue;
1244 bool processZ(
const size_t n,
bool firstFace)
const
1246 const size_t offset =
1247 firstFace ? mConnectivity->offsetsPrevZ()[n] : mConnectivity->offsetsNextZ()[n];
1248 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1250 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1252 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1253 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1255 const Index lastOffset = LeafNodeType::DIM - 1;
1256 const Index lhsOffset =
1257 firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1259 Index tmpPos(0), pos(0);
1260 bool changedValue =
false;
1262 for (Index x = 0; x < LeafNodeType::DIM; ++x) {
1263 tmpPos = x << (2 * LeafNodeType::LOG2DIM);
1264 for (Index y = 0; y < LeafNodeType::DIM; ++y) {
1265 pos = tmpPos + (y << LeafNodeType::LOG2DIM);
1267 if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1268 if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1269 changedValue =
true;
1270 mask[pos + lhsOffset] =
true;
1276 return changedValue;
1282 bool processY(
const size_t n,
bool firstFace)
const
1284 const size_t offset =
1285 firstFace ? mConnectivity->offsetsPrevY()[n] : mConnectivity->offsetsNextY()[n];
1286 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1288 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1290 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1291 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1293 const Index lastOffset = LeafNodeType::DIM * (LeafNodeType::DIM - 1);
1294 const Index lhsOffset =
1295 firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1297 Index tmpPos(0), pos(0);
1298 bool changedValue =
false;
1300 for (Index x = 0; x < LeafNodeType::DIM; ++x) {
1301 tmpPos = x << (2 * LeafNodeType::LOG2DIM);
1302 for (Index z = 0; z < LeafNodeType::DIM; ++z) {
1305 if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1306 if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1307 changedValue =
true;
1308 mask[pos + lhsOffset] =
true;
1314 return changedValue;
1320 bool processX(
const size_t n,
bool firstFace)
const
1322 const size_t offset =
1323 firstFace ? mConnectivity->offsetsPrevX()[n] : mConnectivity->offsetsNextX()[n];
1324 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1326 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1328 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1329 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1331 const Index lastOffset = LeafNodeType::DIM * LeafNodeType::DIM * (LeafNodeType::DIM-1);
1332 const Index lhsOffset =
1333 firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1335 Index tmpPos(0), pos(0);
1336 bool changedValue =
false;
1338 for (Index y = 0; y < LeafNodeType::DIM; ++y) {
1339 tmpPos = y << LeafNodeType::LOG2DIM;
1340 for (Index z = 0; z < LeafNodeType::DIM; ++z) {
1343 if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1344 if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1345 changedValue =
true;
1346 mask[pos + lhsOffset] =
true;
1352 return changedValue;
1358 ConnectivityTable *
const mConnectivity;
1359 bool *
const mChangedNodeMask;
1360 bool *
const mNodeMask;
1361 bool *
const mChangedVoxelMask;
1367template<
typename TreeType,
typename MeshDataAdapter>
1368struct ComputeIntersectingVoxelSign
1370 using ValueType =
typename TreeType::ValueType;
1371 using LeafNodeType =
typename TreeType::LeafNodeType;
1372 using Int32TreeType =
typename TreeType::template ValueConverter<Int32>::Type;
1373 using Int32LeafNodeType =
typename Int32TreeType::LeafNodeType;
1375 using PointArray = std::unique_ptr<Vec3d[]>;
1376 using MaskArray = std::unique_ptr<bool[]>;
1377 using LocalData = std::pair<PointArray, MaskArray>;
1378 using LocalDataTable = tbb::enumerable_thread_specific<LocalData>;
1380 ComputeIntersectingVoxelSign(
1381 std::vector<LeafNodeType*>& distNodes,
1382 const TreeType& distTree,
1383 const Int32TreeType& indexTree,
1384 const MeshDataAdapter& mesh)
1385 : mDistNodes(distNodes.
empty() ? nullptr : &distNodes[0])
1386 , mDistTree(&distTree)
1387 , mIndexTree(&indexTree)
1389 , mLocalDataTable(new LocalDataTable())
1394 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1396 tree::ValueAccessor<const TreeType> distAcc(*mDistTree);
1397 tree::ValueAccessor<const Int32TreeType> idxAcc(*mIndexTree);
1401 Index xPos(0), yPos(0);
1402 Coord ijk, nijk, nodeMin, nodeMax;
1403 Vec3d cp, xyz, nxyz, dir1, dir2;
1405 LocalData& localData = mLocalDataTable->local();
1407 PointArray& points = localData.first;
1408 if (!points) points.reset(
new Vec3d[LeafNodeType::SIZE * 2]);
1410 MaskArray& mask = localData.second;
1411 if (!mask) mask.reset(
new bool[LeafNodeType::SIZE]);
1414 typename LeafNodeType::ValueOnCIter it;
1416 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1418 LeafNodeType& node = *mDistNodes[n];
1419 ValueType* data = node.buffer().data();
1421 const Int32LeafNodeType* idxNode = idxAcc.probeConstLeaf(node.origin());
1422 const Int32* idxData = idxNode->buffer().data();
1424 nodeMin = node.origin();
1425 nodeMax = nodeMin.offsetBy(LeafNodeType::DIM - 1);
1428 memset(mask.get(), 0,
sizeof(
bool) * LeafNodeType::SIZE);
1430 for (it = node.cbeginValueOn(); it; ++it) {
1431 Index pos = it.pos();
1433 ValueType& dist = data[pos];
1434 if (dist < 0.0 || dist > 0.75)
continue;
1436 ijk = node.offsetToGlobalCoord(pos);
1438 xyz[0] = double(ijk[0]);
1439 xyz[1] = double(ijk[1]);
1440 xyz[2] = double(ijk[2]);
1443 bbox.min() = Coord::maxComponent(ijk.offsetBy(-1), nodeMin);
1444 bbox.max() = Coord::minComponent(ijk.offsetBy(1), nodeMax);
1446 bool flipSign =
false;
1448 for (nijk[0] = bbox.min()[0]; nijk[0] <= bbox.max()[0] && !flipSign; ++nijk[0]) {
1449 xPos = (nijk[0] & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
1450 for (nijk[1]=bbox.min()[1]; nijk[1] <= bbox.max()[1] && !flipSign; ++nijk[1]) {
1451 yPos = xPos + ((nijk[1] & (LeafNodeType::DIM-1u)) << LeafNodeType::LOG2DIM);
1452 for (nijk[2] = bbox.min()[2]; nijk[2] <= bbox.max()[2]; ++nijk[2]) {
1453 pos = yPos + (nijk[2] & (LeafNodeType::DIM - 1u));
1455 const Int32& polyIdx = idxData[pos];
1457 if (polyIdx ==
Int32(util::INVALID_IDX) || !(data[pos] < -0.75))
1460 const Index pointIndex = pos * 2;
1466 nxyz[0] = double(nijk[0]);
1467 nxyz[1] = double(nijk[1]);
1468 nxyz[2] = double(nijk[2]);
1470 Vec3d& point = points[pointIndex];
1472 point = closestPoint(nxyz, polyIdx);
1474 Vec3d& direction = points[pointIndex + 1];
1475 direction = nxyz - point;
1476 direction.normalize();
1479 dir1 = xyz - points[pointIndex];
1482 if (points[pointIndex + 1].dot(dir1) > 0.0) {
1493 for (Int32 m = 0; m < 26; ++m) {
1494 nijk = ijk + util::COORD_OFFSETS[m];
1496 if (!bbox.isInside(nijk) && distAcc.probeValue(nijk, nval) && nval<-0.75) {
1497 nxyz[0] = double(nijk[0]);
1498 nxyz[1] = double(nijk[1]);
1499 nxyz[2] = double(nijk[2]);
1501 cp = closestPoint(nxyz, idxAcc.getValue(nijk));
1509 if (dir2.dot(dir1) > 0.0) {
1523 Vec3d closestPoint(
const Vec3d& center, Int32 polyIdx)
const
1525 Vec3d a, b, c, cp, uvw;
1527 const size_t polygon = size_t(polyIdx);
1528 mMesh->getIndexSpacePoint(polygon, 0, a);
1529 mMesh->getIndexSpacePoint(polygon, 1, b);
1530 mMesh->getIndexSpacePoint(polygon, 2, c);
1534 if (4 == mMesh->vertexCount(polygon)) {
1536 mMesh->getIndexSpacePoint(polygon, 3, b);
1540 if ((center - c).lengthSqr() < (center - cp).lengthSqr()) {
1549 LeafNodeType **
const mDistNodes;
1550 TreeType
const *
const mDistTree;
1551 Int32TreeType
const *
const mIndexTree;
1552 MeshDataAdapter
const *
const mMesh;
1554 SharedPtr<LocalDataTable> mLocalDataTable;
1561template<
typename LeafNodeType>
1563maskNodeInternalNeighbours(
const Index pos,
bool (&mask)[26])
1565 using NodeT = LeafNodeType;
1567 const Coord ijk = NodeT::offsetToLocalCoord(pos);
1571 mask[0] = ijk[0] != (NodeT::DIM - 1);
1573 mask[1] = ijk[0] != 0;
1575 mask[2] = ijk[1] != (NodeT::DIM - 1);
1577 mask[3] = ijk[1] != 0;
1579 mask[4] = ijk[2] != (NodeT::DIM - 1);
1581 mask[5] = ijk[2] != 0;
1585 mask[6] = mask[0] && mask[5];
1587 mask[7] = mask[1] && mask[5];
1589 mask[8] = mask[0] && mask[4];
1591 mask[9] = mask[1] && mask[4];
1593 mask[10] = mask[0] && mask[2];
1595 mask[11] = mask[1] && mask[2];
1597 mask[12] = mask[0] && mask[3];
1599 mask[13] = mask[1] && mask[3];
1601 mask[14] = mask[3] && mask[4];
1603 mask[15] = mask[3] && mask[5];
1605 mask[16] = mask[2] && mask[4];
1607 mask[17] = mask[2] && mask[5];
1611 mask[18] = mask[1] && mask[3] && mask[5];
1613 mask[19] = mask[1] && mask[3] && mask[4];
1615 mask[20] = mask[0] && mask[3] && mask[4];
1617 mask[21] = mask[0] && mask[3] && mask[5];
1619 mask[22] = mask[1] && mask[2] && mask[5];
1621 mask[23] = mask[1] && mask[2] && mask[4];
1623 mask[24] = mask[0] && mask[2] && mask[4];
1625 mask[25] = mask[0] && mask[2] && mask[5];
1629template<
typename Compare,
typename LeafNodeType>
1631checkNeighbours(
const Index pos,
const typename LeafNodeType::ValueType * data,
bool (&mask)[26])
1633 using NodeT = LeafNodeType;
1636 if (mask[5] && Compare::check(data[pos - 1]))
return true;
1638 if (mask[4] && Compare::check(data[pos + 1]))
return true;
1640 if (mask[3] && Compare::check(data[pos - NodeT::DIM]))
return true;
1642 if (mask[2] && Compare::check(data[pos + NodeT::DIM]))
return true;
1644 if (mask[1] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM]))
return true;
1646 if (mask[0] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM]))
return true;
1648 if (mask[6] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM]))
return true;
1650 if (mask[7] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - 1]))
return true;
1652 if (mask[8] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + 1]))
return true;
1654 if (mask[9] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + 1]))
return true;
1656 if (mask[10] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM]))
return true;
1658 if (mask[11] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM]))
return true;
1660 if (mask[12] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM]))
return true;
1662 if (mask[13] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM]))
return true;
1664 if (mask[14] && Compare::check(data[pos - NodeT::DIM + 1]))
return true;
1666 if (mask[15] && Compare::check(data[pos - NodeT::DIM - 1]))
return true;
1668 if (mask[16] && Compare::check(data[pos + NodeT::DIM + 1]))
return true;
1670 if (mask[17] && Compare::check(data[pos + NodeT::DIM - 1]))
return true;
1672 if (mask[18] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM - 1]))
return true;
1674 if (mask[19] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM + 1]))
return true;
1676 if (mask[20] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM + 1]))
return true;
1678 if (mask[21] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM - 1]))
return true;
1680 if (mask[22] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM - 1]))
return true;
1682 if (mask[23] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM + 1]))
return true;
1684 if (mask[24] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM + 1]))
return true;
1686 if (mask[25] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM - 1]))
return true;
1692template<
typename Compare,
typename AccessorType>
1694checkNeighbours(
const Coord& ijk, AccessorType& acc,
bool (&mask)[26])
1696 for (Int32 m = 0; m < 26; ++m) {
1697 if (!mask[m] && Compare::check(acc.getValue(ijk + util::COORD_OFFSETS[m]))) {
1706template<
typename TreeType>
1707struct ValidateIntersectingVoxels
1709 using ValueType =
typename TreeType::ValueType;
1710 using LeafNodeType =
typename TreeType::LeafNodeType;
1712 struct IsNegative {
static bool check(
const ValueType v) {
return v < ValueType(0.0); } };
1714 ValidateIntersectingVoxels(TreeType& tree, std::vector<LeafNodeType*>& nodes)
1716 , mNodes(nodes.
empty() ? nullptr : &nodes[0])
1720 void operator()(
const tbb::blocked_range<size_t>& range)
const
1722 tree::ValueAccessor<const TreeType> acc(*mTree);
1723 bool neighbourMask[26];
1725 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1727 LeafNodeType& node = *mNodes[n];
1728 ValueType* data = node.buffer().data();
1730 typename LeafNodeType::ValueOnCIter it;
1731 for (it = node.cbeginValueOn(); it; ++it) {
1733 const Index pos = it.pos();
1735 ValueType& dist = data[pos];
1736 if (dist < 0.0 || dist > 0.75)
continue;
1739 maskNodeInternalNeighbours<LeafNodeType>(pos, neighbourMask);
1741 const bool hasNegativeNeighbour =
1742 checkNeighbours<IsNegative, LeafNodeType>(pos, data, neighbourMask) ||
1743 checkNeighbours<IsNegative>(node.offsetToGlobalCoord(pos), acc, neighbourMask);
1745 if (!hasNegativeNeighbour) {
1747 dist = ValueType(0.75) + Tolerance<ValueType>::epsilon();
1753 TreeType *
const mTree;
1754 LeafNodeType **
const mNodes;
1758template<
typename TreeType>
1759struct RemoveSelfIntersectingSurface
1761 using ValueType =
typename TreeType::ValueType;
1762 using LeafNodeType =
typename TreeType::LeafNodeType;
1763 using Int32TreeType =
typename TreeType::template ValueConverter<Int32>::Type;
1765 struct Comp {
static bool check(
const ValueType v) {
return !(v > ValueType(0.75)); } };
1767 RemoveSelfIntersectingSurface(std::vector<LeafNodeType*>& nodes,
1768 TreeType& distTree, Int32TreeType& indexTree)
1769 : mNodes(nodes.
empty() ? nullptr : &nodes[0])
1770 , mDistTree(&distTree)
1771 , mIndexTree(&indexTree)
1775 void operator()(
const tbb::blocked_range<size_t>& range)
const
1777 tree::ValueAccessor<const TreeType> distAcc(*mDistTree);
1778 tree::ValueAccessor<Int32TreeType> idxAcc(*mIndexTree);
1779 bool neighbourMask[26];
1781 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1783 LeafNodeType& distNode = *mNodes[n];
1784 ValueType* data = distNode.buffer().data();
1786 typename Int32TreeType::LeafNodeType* idxNode =
1787 idxAcc.probeLeaf(distNode.origin());
1789 typename LeafNodeType::ValueOnCIter it;
1790 for (it = distNode.cbeginValueOn(); it; ++it) {
1792 const Index pos = it.pos();
1794 if (!(data[pos] > 0.75))
continue;
1797 maskNodeInternalNeighbours<LeafNodeType>(pos, neighbourMask);
1799 const bool hasBoundaryNeighbour =
1800 checkNeighbours<Comp, LeafNodeType>(pos, data, neighbourMask) ||
1801 checkNeighbours<Comp>(distNode.offsetToGlobalCoord(pos),distAcc,neighbourMask);
1803 if (!hasBoundaryNeighbour) {
1804 distNode.setValueOff(pos);
1805 idxNode->setValueOff(pos);
1811 LeafNodeType * *
const mNodes;
1812 TreeType *
const mDistTree;
1813 Int32TreeType *
const mIndexTree;
1820template<
typename NodeType>
1821struct ReleaseChildNodes
1823 ReleaseChildNodes(NodeType ** nodes) : mNodes(nodes) {}
1825 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1827 using NodeMaskType =
typename NodeType::NodeMaskType;
1829 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1830 const_cast<NodeMaskType&
>(mNodes[n]->getChildMask()).setOff();
1834 NodeType **
const mNodes;
1838template<
typename TreeType>
1840releaseLeafNodes(TreeType& tree)
1842 using RootNodeType =
typename TreeType::RootNodeType;
1843 using NodeChainType =
typename RootNodeType::NodeChainType;
1844 using InternalNodeType =
typename NodeChainType::template Get<1>;
1846 std::vector<InternalNodeType*> nodes;
1847 tree.getNodes(nodes);
1849 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
1850 ReleaseChildNodes<InternalNodeType>(nodes.empty() ?
nullptr : &nodes[0]));
1854template<
typename TreeType>
1855struct StealUniqueLeafNodes
1857 using LeafNodeType =
typename TreeType::LeafNodeType;
1859 StealUniqueLeafNodes(TreeType& lhsTree, TreeType& rhsTree,
1860 std::vector<LeafNodeType*>& overlappingNodes)
1861 : mLhsTree(&lhsTree)
1862 , mRhsTree(&rhsTree)
1863 , mNodes(&overlappingNodes)
1867 void operator()()
const {
1869 std::vector<LeafNodeType*> rhsLeafNodes;
1871 rhsLeafNodes.reserve(mRhsTree->leafCount());
1874 mRhsTree->stealNodes(rhsLeafNodes);
1876 tree::ValueAccessor<TreeType> acc(*mLhsTree);
1878 for (
size_t n = 0, N = rhsLeafNodes.size(); n < N; ++n) {
1879 if (!acc.probeLeaf(rhsLeafNodes[n]->origin())) {
1880 acc.addLeaf(rhsLeafNodes[n]);
1882 mNodes->push_back(rhsLeafNodes[n]);
1888 TreeType *
const mLhsTree;
1889 TreeType *
const mRhsTree;
1890 std::vector<LeafNodeType*> *
const mNodes;
1894template<
typename DistTreeType,
typename IndexTreeType>
1896combineData(DistTreeType& lhsDist, IndexTreeType& lhsIdx,
1897 DistTreeType& rhsDist, IndexTreeType& rhsIdx)
1899 using DistLeafNodeType =
typename DistTreeType::LeafNodeType;
1900 using IndexLeafNodeType =
typename IndexTreeType::LeafNodeType;
1902 std::vector<DistLeafNodeType*> overlappingDistNodes;
1903 std::vector<IndexLeafNodeType*> overlappingIdxNodes;
1906 tbb::task_group tasks;
1907 tasks.run(StealUniqueLeafNodes<DistTreeType>(lhsDist, rhsDist, overlappingDistNodes));
1908 tasks.run(StealUniqueLeafNodes<IndexTreeType>(lhsIdx, rhsIdx, overlappingIdxNodes));
1912 if (!overlappingDistNodes.empty() && !overlappingIdxNodes.empty()) {
1913 tbb::parallel_for(tbb::blocked_range<size_t>(0, overlappingDistNodes.size()),
1914 CombineLeafNodes<DistTreeType>(lhsDist, lhsIdx,
1915 &overlappingDistNodes[0], &overlappingIdxNodes[0]));
1925template<
typename TreeType>
1926struct VoxelizationData {
1928 using Ptr = std::unique_ptr<VoxelizationData>;
1929 using ValueType =
typename TreeType::ValueType;
1931 using Int32TreeType =
typename TreeType::template ValueConverter<Int32>::Type;
1932 using UCharTreeType =
typename TreeType::template ValueConverter<unsigned char>::Type;
1934 using FloatTreeAcc = tree::ValueAccessor<TreeType>;
1935 using Int32TreeAcc = tree::ValueAccessor<Int32TreeType>;
1936 using UCharTreeAcc = tree::ValueAccessor<UCharTreeType>;
1940 : distTree(std::numeric_limits<ValueType>::
max())
1943 , indexAcc(indexTree)
1944 , primIdTree(MaxPrimId)
1945 , primIdAcc(primIdTree)
1951 FloatTreeAcc distAcc;
1953 Int32TreeType indexTree;
1954 Int32TreeAcc indexAcc;
1956 UCharTreeType primIdTree;
1957 UCharTreeAcc primIdAcc;
1959 unsigned char getNewPrimId() {
1975 if (mPrimCount == MaxPrimId || primIdTree.leafCount() > 1000) {
1977 primIdTree.root().clear();
1978 primIdTree.clearAllAccessors();
1982 return mPrimCount++;
1987 enum { MaxPrimId = 100 };
1989 unsigned char mPrimCount;
1993template<
typename TreeType,
typename MeshDataAdapter,
typename Interrupter = util::NullInterrupter>
1994class VoxelizePolygons
1998 using VoxelizationDataType = VoxelizationData<TreeType>;
1999 using DataTable = tbb::enumerable_thread_specific<typename VoxelizationDataType::Ptr>;
2001 VoxelizePolygons(DataTable& dataTable,
2002 const MeshDataAdapter& mesh,
2003 Interrupter* interrupter =
nullptr)
2004 : mDataTable(&dataTable)
2006 , mInterrupter(interrupter)
2010 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2012 typename VoxelizationDataType::Ptr& dataPtr = mDataTable->local();
2013 if (!dataPtr) dataPtr.reset(
new VoxelizationDataType());
2017 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2020 thread::cancelGroupExecution();
2024 const size_t numVerts = mMesh->vertexCount(n);
2027 if (numVerts == 3 || numVerts == 4) {
2029 prim.index =
Int32(n);
2031 mMesh->getIndexSpacePoint(n, 0, prim.a);
2032 mMesh->getIndexSpacePoint(n, 1, prim.b);
2033 mMesh->getIndexSpacePoint(n, 2, prim.c);
2035 evalTriangle(prim, *dataPtr);
2037 if (numVerts == 4) {
2038 mMesh->getIndexSpacePoint(n, 3, prim.b);
2039 evalTriangle(prim, *dataPtr);
2047 bool wasInterrupted()
const {
return mInterrupter && mInterrupter->wasInterrupted(); }
2049 struct Triangle {
Vec3d a, b, c;
Int32 index; };
2053 enum { POLYGON_LIMIT = 1000 };
2055 SubTask(
const Triangle& prim, DataTable& dataTable,
2056 int subdivisionCount,
size_t polygonCount,
2057 Interrupter* interrupter =
nullptr)
2058 : mLocalDataTable(&dataTable)
2060 , mSubdivisionCount(subdivisionCount)
2061 , mPolygonCount(polygonCount)
2062 , mInterrupter(interrupter)
2066 void operator()()
const
2068 if (mSubdivisionCount <= 0 || mPolygonCount >= POLYGON_LIMIT) {
2070 typename VoxelizationDataType::Ptr& dataPtr = mLocalDataTable->local();
2071 if (!dataPtr) dataPtr.reset(
new VoxelizationDataType());
2073 voxelizeTriangle(mPrim, *dataPtr, mInterrupter);
2075 }
else if (!(mInterrupter && mInterrupter->wasInterrupted())) {
2076 spawnTasks(mPrim, *mLocalDataTable, mSubdivisionCount, mPolygonCount, mInterrupter);
2080 DataTable *
const mLocalDataTable;
2081 Triangle
const mPrim;
2082 int const mSubdivisionCount;
2083 size_t const mPolygonCount;
2084 Interrupter *
const mInterrupter;
2087 inline static int evalSubdivisionCount(
const Triangle& prim)
2089 const double ax = prim.a[0], bx = prim.b[0], cx = prim.c[0];
2090 const double dx = std::max(ax, std::max(bx, cx)) - std::min(ax, std::min(bx, cx));
2092 const double ay = prim.a[1], by = prim.b[1], cy = prim.c[1];
2093 const double dy = std::max(ay, std::max(by, cy)) - std::min(ay, std::min(by, cy));
2095 const double az = prim.a[2], bz = prim.b[2], cz = prim.c[2];
2096 const double dz = std::max(az, std::max(bz, cz)) - std::min(az, std::min(bz, cz));
2098 return int(std::max(dx, std::max(dy, dz)) /
double(TreeType::LeafNodeType::DIM * 2));
2101 void evalTriangle(
const Triangle& prim, VoxelizationDataType& data)
const
2103 const size_t polygonCount = mMesh->polygonCount();
2104 const int subdivisionCount =
2105 polygonCount < SubTask::POLYGON_LIMIT ? evalSubdivisionCount(prim) : 0;
2107 if (subdivisionCount <= 0) {
2108 voxelizeTriangle(prim, data, mInterrupter);
2110 spawnTasks(prim, *mDataTable, subdivisionCount, polygonCount, mInterrupter);
2114 static void spawnTasks(
2115 const Triangle& mainPrim,
2116 DataTable& dataTable,
2117 int subdivisionCount,
2118 size_t polygonCount,
2119 Interrupter*
const interrupter)
2121 subdivisionCount -= 1;
2124 tbb::task_group tasks;
2126 const Vec3d ac = (mainPrim.a + mainPrim.c) * 0.5;
2127 const Vec3d bc = (mainPrim.b + mainPrim.c) * 0.5;
2128 const Vec3d ab = (mainPrim.a + mainPrim.b) * 0.5;
2131 prim.index = mainPrim.index;
2133 prim.a = mainPrim.a;
2136 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount, interrupter));
2141 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount, interrupter));
2144 prim.b = mainPrim.b;
2146 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount, interrupter));
2150 prim.c = mainPrim.c;
2151 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount, interrupter));
2156 static void voxelizeTriangle(
const Triangle& prim, VoxelizationDataType& data, Interrupter*
const interrupter)
2158 std::deque<Coord> coordList;
2161 ijk = Coord::floor(prim.a);
2162 coordList.push_back(ijk);
2167 updateDistance(ijk, prim, data);
2169 unsigned char primId = data.getNewPrimId();
2170 data.primIdAcc.setValueOnly(ijk, primId);
2172 while (!coordList.empty()) {
2173 if (interrupter && interrupter->wasInterrupted()) {
2174 thread::cancelGroupExecution();
2177 for (Int32 pass = 0; pass < 1048576 && !coordList.empty(); ++pass) {
2178 ijk = coordList.back();
2179 coordList.pop_back();
2181 for (Int32 i = 0; i < 26; ++i) {
2182 nijk = ijk + util::COORD_OFFSETS[i];
2183 if (primId != data.primIdAcc.getValue(nijk)) {
2184 data.primIdAcc.setValueOnly(nijk, primId);
2185 if(updateDistance(nijk, prim, data)) coordList.push_back(nijk);
2192 static bool updateDistance(
const Coord& ijk,
const Triangle& prim, VoxelizationDataType& data)
2194 Vec3d uvw, voxelCenter(ijk[0], ijk[1], ijk[2]);
2196 using ValueType =
typename TreeType::ValueType;
2198 const ValueType dist = ValueType((voxelCenter -
2203 if (std::isnan(dist))
2206 const ValueType oldDist = data.distAcc.getValue(ijk);
2208 if (dist < oldDist) {
2209 data.distAcc.setValue(ijk, dist);
2210 data.indexAcc.setValue(ijk, prim.index);
2211 }
else if (math::isExactlyEqual(dist, oldDist)) {
2214 data.indexAcc.setValueOnly(ijk, std::min(prim.index, data.indexAcc.getValue(ijk)));
2217 return !(dist > 0.75);
2220 DataTable *
const mDataTable;
2221 MeshDataAdapter
const *
const mMesh;
2222 Interrupter *
const mInterrupter;
2229template<
typename TreeType>
2230struct DiffLeafNodeMask
2232 using AccessorType =
typename tree::ValueAccessor<TreeType>;
2233 using LeafNodeType =
typename TreeType::LeafNodeType;
2235 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2236 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
2238 DiffLeafNodeMask(
const TreeType& rhsTree,
2239 std::vector<BoolLeafNodeType*>& lhsNodes)
2240 : mRhsTree(&rhsTree), mLhsNodes(lhsNodes.
empty() ? nullptr : &lhsNodes[0])
2244 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2246 tree::ValueAccessor<const TreeType> acc(*mRhsTree);
2248 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2250 BoolLeafNodeType* lhsNode = mLhsNodes[n];
2251 const LeafNodeType* rhsNode = acc.probeConstLeaf(lhsNode->origin());
2253 if (rhsNode) lhsNode->topologyDifference(*rhsNode,
false);
2258 TreeType
const *
const mRhsTree;
2259 BoolLeafNodeType **
const mLhsNodes;
2263template<
typename LeafNodeTypeA,
typename LeafNodeTypeB>
2264struct UnionValueMasks
2266 UnionValueMasks(std::vector<LeafNodeTypeA*>& nodesA, std::vector<LeafNodeTypeB*>& nodesB)
2267 : mNodesA(nodesA.
empty() ? nullptr : &nodesA[0])
2268 , mNodesB(nodesB.
empty() ? nullptr : &nodesB[0])
2272 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2273 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2274 mNodesA[n]->topologyUnion(*mNodesB[n]);
2279 LeafNodeTypeA **
const mNodesA;
2280 LeafNodeTypeB **
const mNodesB;
2284template<
typename TreeType>
2285struct ConstructVoxelMask
2287 using LeafNodeType =
typename TreeType::LeafNodeType;
2289 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2290 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
2292 ConstructVoxelMask(BoolTreeType& maskTree,
const TreeType& tree,
2293 std::vector<LeafNodeType*>& nodes)
2295 , mNodes(nodes.
empty() ? nullptr : &nodes[0])
2296 , mLocalMaskTree(false)
2297 , mMaskTree(&maskTree)
2301 ConstructVoxelMask(ConstructVoxelMask& rhs, tbb::split)
2303 , mNodes(rhs.mNodes)
2304 , mLocalMaskTree(false)
2305 , mMaskTree(&mLocalMaskTree)
2309 void operator()(
const tbb::blocked_range<size_t>& range)
2311 using Iterator =
typename LeafNodeType::ValueOnCIter;
2313 tree::ValueAccessor<const TreeType> acc(*mTree);
2314 tree::ValueAccessor<BoolTreeType> maskAcc(*mMaskTree);
2316 Coord ijk, nijk, localCorod;
2319 for (
size_t n = range.begin(); n != range.end(); ++n) {
2321 LeafNodeType& node = *mNodes[n];
2323 CoordBBox bbox = node.getNodeBoundingBox();
2326 BoolLeafNodeType& maskNode = *maskAcc.touchLeaf(node.origin());
2328 for (Iterator it = node.cbeginValueOn(); it; ++it) {
2329 ijk = it.getCoord();
2332 localCorod = LeafNodeType::offsetToLocalCoord(pos);
2334 if (localCorod[2] <
int(LeafNodeType::DIM - 1)) {
2336 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2338 nijk = ijk.offsetBy(0, 0, 1);
2339 if (!acc.isValueOn(nijk)) maskAcc.setValueOn(nijk);
2342 if (localCorod[2] > 0) {
2344 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2346 nijk = ijk.offsetBy(0, 0, -1);
2347 if (!acc.isValueOn(nijk)) maskAcc.setValueOn(nijk);
2350 if (localCorod[1] <
int(LeafNodeType::DIM - 1)) {
2351 npos = pos + LeafNodeType::DIM;
2352 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2354 nijk = ijk.offsetBy(0, 1, 0);
2355 if (!acc.isValueOn(nijk)) maskAcc.setValueOn(nijk);
2358 if (localCorod[1] > 0) {
2359 npos = pos - LeafNodeType::DIM;
2360 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2362 nijk = ijk.offsetBy(0, -1, 0);
2363 if (!acc.isValueOn(nijk)) maskAcc.setValueOn(nijk);
2366 if (localCorod[0] <
int(LeafNodeType::DIM - 1)) {
2367 npos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
2368 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2370 nijk = ijk.offsetBy(1, 0, 0);
2371 if (!acc.isValueOn(nijk)) maskAcc.setValueOn(nijk);
2374 if (localCorod[0] > 0) {
2375 npos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
2376 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2378 nijk = ijk.offsetBy(-1, 0, 0);
2379 if (!acc.isValueOn(nijk)) maskAcc.setValueOn(nijk);
2385 void join(ConstructVoxelMask& rhs) { mMaskTree->merge(*rhs.mMaskTree); }
2388 TreeType
const *
const mTree;
2389 LeafNodeType **
const mNodes;
2391 BoolTreeType mLocalMaskTree;
2392 BoolTreeType *
const mMaskTree;
2397template<
typename TreeType,
typename MeshDataAdapter>
2398struct ExpandNarrowband
2400 using ValueType =
typename TreeType::ValueType;
2401 using LeafNodeType =
typename TreeType::LeafNodeType;
2402 using NodeMaskType =
typename LeafNodeType::NodeMaskType;
2403 using Int32TreeType =
typename TreeType::template ValueConverter<Int32>::Type;
2404 using Int32LeafNodeType =
typename Int32TreeType::LeafNodeType;
2405 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2406 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
2413 Fragment() : idx(0), x(0), y(0), z(0), dist(0.0) {}
2415 Fragment(Int32 idx_, Int32 x_, Int32 y_, Int32 z_, ValueType dist_)
2416 : idx(idx_), x(x_), y(y_), z(z_), dist(dist_)
2420 bool operator<(
const Fragment& rhs)
const {
return idx < rhs.idx; }
2426 std::vector<BoolLeafNodeType*>& maskNodes,
2427 BoolTreeType& maskTree,
2429 Int32TreeType& indexTree,
2430 const MeshDataAdapter& mesh,
2431 ValueType exteriorBandWidth,
2432 ValueType interiorBandWidth,
2433 ValueType voxelSize)
2434 : mMaskNodes(maskNodes.
empty() ? nullptr : &maskNodes[0])
2435 , mMaskTree(&maskTree)
2436 , mDistTree(&distTree)
2437 , mIndexTree(&indexTree)
2439 , mNewMaskTree(false)
2441 , mUpdatedDistNodes()
2443 , mUpdatedIndexNodes()
2444 , mExteriorBandWidth(exteriorBandWidth)
2445 , mInteriorBandWidth(interiorBandWidth)
2446 , mVoxelSize(voxelSize)
2450 ExpandNarrowband(
const ExpandNarrowband& rhs, tbb::split)
2451 : mMaskNodes(rhs.mMaskNodes)
2452 , mMaskTree(rhs.mMaskTree)
2453 , mDistTree(rhs.mDistTree)
2454 , mIndexTree(rhs.mIndexTree)
2456 , mNewMaskTree(false)
2458 , mUpdatedDistNodes()
2460 , mUpdatedIndexNodes()
2461 , mExteriorBandWidth(rhs.mExteriorBandWidth)
2462 , mInteriorBandWidth(rhs.mInteriorBandWidth)
2463 , mVoxelSize(rhs.mVoxelSize)
2467 void join(ExpandNarrowband& rhs)
2469 mDistNodes.insert(mDistNodes.end(), rhs.mDistNodes.begin(), rhs.mDistNodes.end());
2470 mIndexNodes.insert(mIndexNodes.end(), rhs.mIndexNodes.begin(), rhs.mIndexNodes.end());
2472 mUpdatedDistNodes.insert(mUpdatedDistNodes.end(),
2473 rhs.mUpdatedDistNodes.begin(), rhs.mUpdatedDistNodes.end());
2475 mUpdatedIndexNodes.insert(mUpdatedIndexNodes.end(),
2476 rhs.mUpdatedIndexNodes.begin(), rhs.mUpdatedIndexNodes.end());
2478 mNewMaskTree.merge(rhs.mNewMaskTree);
2481 void operator()(
const tbb::blocked_range<size_t>& range)
2483 tree::ValueAccessor<BoolTreeType> newMaskAcc(mNewMaskTree);
2484 tree::ValueAccessor<TreeType> distAcc(*mDistTree);
2485 tree::ValueAccessor<Int32TreeType> indexAcc(*mIndexTree);
2487 std::vector<Fragment> fragments;
2488 fragments.reserve(256);
2490 std::unique_ptr<LeafNodeType> newDistNodePt;
2491 std::unique_ptr<Int32LeafNodeType> newIndexNodePt;
2493 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2495 BoolLeafNodeType& maskNode = *mMaskNodes[n];
2496 if (maskNode.isEmpty())
continue;
2500 const Coord& origin = maskNode.origin();
2502 LeafNodeType * distNodePt = distAcc.probeLeaf(origin);
2503 Int32LeafNodeType * indexNodePt = indexAcc.probeLeaf(origin);
2507 bool usingNewNodes =
false;
2509 if (!distNodePt && !indexNodePt) {
2511 const ValueType backgroundDist = distAcc.getValue(origin);
2513 if (!newDistNodePt.get() && !newIndexNodePt.get()) {
2514 newDistNodePt.reset(
new LeafNodeType(origin, backgroundDist));
2515 newIndexNodePt.reset(
new Int32LeafNodeType(origin, indexAcc.getValue(origin)));
2518 if ((backgroundDist < ValueType(0.0)) !=
2519 (newDistNodePt->getValue(0) < ValueType(0.0))) {
2520 newDistNodePt->buffer().fill(backgroundDist);
2523 newDistNodePt->setOrigin(origin);
2524 newIndexNodePt->setOrigin(origin);
2527 distNodePt = newDistNodePt.get();
2528 indexNodePt = newIndexNodePt.get();
2530 usingNewNodes =
true;
2536 CoordBBox bbox(Coord::max(), Coord::min());
2537 for (
typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
2538 bbox.expand(it.getCoord());
2543 gatherFragments(fragments, bbox, distAcc, indexAcc);
2548 bbox = maskNode.getNodeBoundingBox();
2550 bool updatedLeafNodes =
false;
2552 for (
typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
2554 const Coord ijk = it.getCoord();
2556 if (updateVoxel(ijk, 5, fragments, *distNodePt, *indexNodePt, &updatedLeafNodes)) {
2558 for (Int32 i = 0; i < 6; ++i) {
2559 const Coord nijk = ijk + util::COORD_OFFSETS[i];
2560 if (bbox.isInside(nijk)) {
2561 mask.setOn(BoolLeafNodeType::coordToOffset(nijk));
2563 newMaskAcc.setValueOn(nijk);
2567 for (Int32 i = 6; i < 26; ++i) {
2568 const Coord nijk = ijk + util::COORD_OFFSETS[i];
2569 if (bbox.isInside(nijk)) {
2570 mask.setOn(BoolLeafNodeType::coordToOffset(nijk));
2576 if (updatedLeafNodes) {
2579 mask -= indexNodePt->getValueMask();
2581 for (
typename NodeMaskType::OnIterator it = mask.beginOn(); it; ++it) {
2583 const Index pos = it.pos();
2584 const Coord ijk = maskNode.origin() + LeafNodeType::offsetToLocalCoord(pos);
2586 if (updateVoxel(ijk, 6, fragments, *distNodePt, *indexNodePt)) {
2587 for (Int32 i = 0; i < 6; ++i) {
2588 newMaskAcc.setValueOn(ijk + util::COORD_OFFSETS[i]);
2594 if (usingNewNodes) {
2595 newDistNodePt->topologyUnion(*newIndexNodePt);
2596 mDistNodes.push_back(newDistNodePt.release());
2597 mIndexNodes.push_back(newIndexNodePt.release());
2599 mUpdatedDistNodes.push_back(distNodePt);
2600 mUpdatedIndexNodes.push_back(indexNodePt);
2608 BoolTreeType& newMaskTree() {
return mNewMaskTree; }
2610 std::vector<LeafNodeType*>& newDistNodes() {
return mDistNodes; }
2611 std::vector<LeafNodeType*>& updatedDistNodes() {
return mUpdatedDistNodes; }
2613 std::vector<Int32LeafNodeType*>& newIndexNodes() {
return mIndexNodes; }
2614 std::vector<Int32LeafNodeType*>& updatedIndexNodes() {
return mUpdatedIndexNodes; }
2620 gatherFragments(std::vector<Fragment>& fragments,
const CoordBBox& bbox,
2621 tree::ValueAccessor<TreeType>& distAcc, tree::ValueAccessor<Int32TreeType>& indexAcc)
2624 const Coord nodeMin = bbox.min() & ~(LeafNodeType::DIM - 1);
2625 const Coord nodeMax = bbox.max() & ~(LeafNodeType::DIM - 1);
2630 for (ijk[0] = nodeMin[0]; ijk[0] <= nodeMax[0]; ijk[0] += LeafNodeType::DIM) {
2631 for (ijk[1] = nodeMin[1]; ijk[1] <= nodeMax[1]; ijk[1] += LeafNodeType::DIM) {
2632 for (ijk[2] = nodeMin[2]; ijk[2] <= nodeMax[2]; ijk[2] += LeafNodeType::DIM) {
2633 if (LeafNodeType* distleaf = distAcc.probeLeaf(ijk)) {
2634 region.min() = Coord::maxComponent(bbox.min(), ijk);
2635 region.max() = Coord::minComponent(bbox.max(),
2636 ijk.offsetBy(LeafNodeType::DIM - 1));
2637 gatherFragments(fragments, region, *distleaf, *indexAcc.probeLeaf(ijk));
2643 std::sort(fragments.begin(), fragments.end());
2647 gatherFragments(std::vector<Fragment>& fragments,
const CoordBBox& bbox,
2648 const LeafNodeType& distLeaf,
const Int32LeafNodeType& idxLeaf)
const
2650 const typename LeafNodeType::NodeMaskType& mask = distLeaf.getValueMask();
2651 const ValueType* distData = distLeaf.buffer().data();
2652 const Int32* idxData = idxLeaf.buffer().data();
2654 for (
int x = bbox.min()[0]; x <= bbox.max()[0]; ++x) {
2655 const Index xPos = (x & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
2656 for (
int y = bbox.min()[1]; y <= bbox.max()[1]; ++y) {
2657 const Index yPos = xPos + ((y & (LeafNodeType::DIM - 1u)) << LeafNodeType::LOG2DIM);
2658 for (
int z = bbox.min()[2]; z <= bbox.max()[2]; ++z) {
2659 const Index pos = yPos + (z & (LeafNodeType::DIM - 1u));
2660 if (mask.isOn(pos)) {
2661 fragments.push_back(Fragment(idxData[pos],x,y,z, std::abs(distData[pos])));
2671 computeDistance(
const Coord& ijk,
const Int32 manhattanLimit,
2672 const std::vector<Fragment>& fragments, Int32& closestPrimIdx)
const
2674 Vec3d a, b, c, uvw, voxelCenter(ijk[0], ijk[1], ijk[2]);
2675 double primDist, tmpDist, dist = std::numeric_limits<double>::max();
2678 for (
size_t n = 0, N = fragments.size(); n < N; ++n) {
2680 const Fragment& fragment = fragments[n];
2681 if (lastIdx == fragment.idx)
continue;
2683 const Int32 dx = std::abs(fragment.x - ijk[0]);
2684 const Int32 dy = std::abs(fragment.y - ijk[1]);
2685 const Int32 dz = std::abs(fragment.z - ijk[2]);
2687 const Int32 manhattan = dx + dy + dz;
2688 if (manhattan > manhattanLimit)
continue;
2690 lastIdx = fragment.idx;
2692 const size_t polygon = size_t(lastIdx);
2694 mMesh->getIndexSpacePoint(polygon, 0, a);
2695 mMesh->getIndexSpacePoint(polygon, 1, b);
2696 mMesh->getIndexSpacePoint(polygon, 2, c);
2698 primDist = (voxelCenter -
2702 if (4 == mMesh->vertexCount(polygon)) {
2704 mMesh->getIndexSpacePoint(polygon, 3, b);
2707 a, b, c, voxelCenter, uvw)).lengthSqr();
2709 if (tmpDist < primDist) primDist = tmpDist;
2712 if (primDist < dist) {
2714 closestPrimIdx = lastIdx;
2718 return ValueType(std::sqrt(dist)) * mVoxelSize;
2724 updateVoxel(
const Coord& ijk,
const Int32 manhattanLimit,
2725 const std::vector<Fragment>& fragments,
2726 LeafNodeType& distLeaf, Int32LeafNodeType& idxLeaf,
bool* updatedLeafNodes =
nullptr)
2728 Int32 closestPrimIdx = 0;
2729 const ValueType distance = computeDistance(ijk, manhattanLimit, fragments, closestPrimIdx);
2731 const Index pos = LeafNodeType::coordToOffset(ijk);
2732 const bool inside = distLeaf.getValue(pos) < ValueType(0.0);
2734 bool activateNeighbourVoxels =
false;
2736 if (!inside && distance < mExteriorBandWidth) {
2737 if (updatedLeafNodes) *updatedLeafNodes =
true;
2738 activateNeighbourVoxels = (distance + mVoxelSize) < mExteriorBandWidth;
2739 distLeaf.setValueOnly(pos, distance);
2740 idxLeaf.setValueOn(pos, closestPrimIdx);
2741 }
else if (inside && distance < mInteriorBandWidth) {
2742 if (updatedLeafNodes) *updatedLeafNodes =
true;
2743 activateNeighbourVoxels = (distance + mVoxelSize) < mInteriorBandWidth;
2744 distLeaf.setValueOnly(pos, -distance);
2745 idxLeaf.setValueOn(pos, closestPrimIdx);
2748 return activateNeighbourVoxels;
2753 BoolLeafNodeType **
const mMaskNodes;
2754 BoolTreeType *
const mMaskTree;
2755 TreeType *
const mDistTree;
2756 Int32TreeType *
const mIndexTree;
2758 MeshDataAdapter
const *
const mMesh;
2760 BoolTreeType mNewMaskTree;
2762 std::vector<LeafNodeType*> mDistNodes, mUpdatedDistNodes;
2763 std::vector<Int32LeafNodeType*> mIndexNodes, mUpdatedIndexNodes;
2765 const ValueType mExteriorBandWidth, mInteriorBandWidth, mVoxelSize;
2769template<
typename TreeType>
2771 using LeafNodeType =
typename TreeType::LeafNodeType;
2773 AddNodes(TreeType& tree, std::vector<LeafNodeType*>& nodes)
2774 : mTree(&tree) , mNodes(&nodes)
2778 void operator()()
const {
2779 tree::ValueAccessor<TreeType> acc(*mTree);
2780 std::vector<LeafNodeType*>& nodes = *mNodes;
2781 for (
size_t n = 0, N = nodes.size(); n < N; ++n) {
2782 acc.addLeaf(nodes[n]);
2786 TreeType *
const mTree;
2787 std::vector<LeafNodeType*> *
const mNodes;
2791template<
typename TreeType,
typename Int32TreeType,
typename BoolTreeType,
typename MeshDataAdapter>
2795 Int32TreeType& indexTree,
2796 BoolTreeType& maskTree,
2797 std::vector<typename BoolTreeType::LeafNodeType*>& maskNodes,
2798 const MeshDataAdapter& mesh,
2799 typename TreeType::ValueType exteriorBandWidth,
2800 typename TreeType::ValueType interiorBandWidth,
2801 typename TreeType::ValueType voxelSize)
2803 ExpandNarrowband<TreeType, MeshDataAdapter> expandOp(maskNodes, maskTree,
2804 distTree, indexTree, mesh, exteriorBandWidth, interiorBandWidth, voxelSize);
2806 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, maskNodes.size()), expandOp);
2808 tbb::parallel_for(tbb::blocked_range<size_t>(0, expandOp.updatedIndexNodes().size()),
2809 UnionValueMasks<typename TreeType::LeafNodeType, typename Int32TreeType::LeafNodeType>(
2810 expandOp.updatedDistNodes(), expandOp.updatedIndexNodes()));
2812 tbb::task_group tasks;
2813 tasks.run(AddNodes<TreeType>(distTree, expandOp.newDistNodes()));
2814 tasks.run(AddNodes<Int32TreeType>(indexTree, expandOp.newIndexNodes()));
2818 maskTree.merge(expandOp.newMaskTree());
2826template<
typename TreeType>
2827struct TransformValues
2829 using LeafNodeType =
typename TreeType::LeafNodeType;
2830 using ValueType =
typename TreeType::ValueType;
2832 TransformValues(std::vector<LeafNodeType*>& nodes,
2833 ValueType voxelSize,
bool unsignedDist)
2835 , mVoxelSize(voxelSize)
2836 , mUnsigned(unsignedDist)
2840 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2842 typename LeafNodeType::ValueOnIter iter;
2844 const bool udf = mUnsigned;
2845 const ValueType w[2] = { -mVoxelSize, mVoxelSize };
2847 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2849 for (iter = mNodes[n]->beginValueOn(); iter; ++iter) {
2850 ValueType& val =
const_cast<ValueType&
>(iter.getValue());
2851 val = w[udf || (val < ValueType(0.0))] * std::sqrt(std::abs(val));
2857 LeafNodeType * *
const mNodes;
2858 const ValueType mVoxelSize;
2859 const bool mUnsigned;
2864template<
typename TreeType>
2865struct InactivateValues
2867 using LeafNodeType =
typename TreeType::LeafNodeType;
2868 using ValueType =
typename TreeType::ValueType;
2870 InactivateValues(std::vector<LeafNodeType*>& nodes,
2871 ValueType exBandWidth, ValueType inBandWidth)
2872 : mNodes(nodes.
empty() ? nullptr : &nodes[0])
2873 , mExBandWidth(exBandWidth)
2874 , mInBandWidth(inBandWidth)
2878 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2880 typename LeafNodeType::ValueOnIter iter;
2881 const ValueType exVal = mExBandWidth;
2882 const ValueType inVal = -mInBandWidth;
2884 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2886 for (iter = mNodes[n]->beginValueOn(); iter; ++iter) {
2888 ValueType& val =
const_cast<ValueType&
>(iter.getValue());
2890 const bool inside = val < ValueType(0.0);
2892 if (inside && !(val > inVal)) {
2895 }
else if (!inside && !(val < exVal)) {
2904 LeafNodeType * *
const mNodes;
2905 const ValueType mExBandWidth, mInBandWidth;
2909template<
typename TreeType>
2912 using LeafNodeType =
typename TreeType::LeafNodeType;
2913 using ValueType =
typename TreeType::ValueType;
2915 OffsetValues(std::vector<LeafNodeType*>& nodes, ValueType offset)
2916 : mNodes(nodes.
empty() ? nullptr : &nodes[0]), mOffset(offset)
2920 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2922 const ValueType offset = mOffset;
2924 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2926 typename LeafNodeType::ValueOnIter iter = mNodes[n]->beginValueOn();
2928 for (; iter; ++iter) {
2929 ValueType& val =
const_cast<ValueType&
>(iter.getValue());
2936 LeafNodeType * *
const mNodes;
2937 const ValueType mOffset;
2941template<
typename TreeType>
2944 using LeafNodeType =
typename TreeType::LeafNodeType;
2945 using ValueType =
typename TreeType::ValueType;
2947 Renormalize(
const TreeType& tree,
const std::vector<LeafNodeType*>& nodes,
2948 ValueType* buffer, ValueType voxelSize)
2950 , mNodes(nodes.
empty() ? nullptr : &nodes[0])
2952 , mVoxelSize(voxelSize)
2956 void operator()(
const tbb::blocked_range<size_t>& range)
const
2958 using Vec3Type = math::Vec3<ValueType>;
2960 tree::ValueAccessor<const TreeType> acc(*mTree);
2965 const ValueType dx = mVoxelSize, invDx = ValueType(1.0) / mVoxelSize;
2967 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2969 ValueType* bufferData = &mBuffer[n * LeafNodeType::SIZE];
2971 typename LeafNodeType::ValueOnCIter iter = mNodes[n]->cbeginValueOn();
2972 for (; iter; ++iter) {
2974 const ValueType phi0 = *iter;
2976 ijk = iter.getCoord();
2978 up[0] = acc.getValue(ijk.offsetBy(1, 0, 0)) - phi0;
2979 up[1] = acc.getValue(ijk.offsetBy(0, 1, 0)) - phi0;
2980 up[2] = acc.getValue(ijk.offsetBy(0, 0, 1)) - phi0;
2982 down[0] = phi0 - acc.getValue(ijk.offsetBy(-1, 0, 0));
2983 down[1] = phi0 - acc.getValue(ijk.offsetBy(0, -1, 0));
2984 down[2] = phi0 - acc.getValue(ijk.offsetBy(0, 0, -1));
2986 const ValueType normSqGradPhi = math::GodunovsNormSqrd(phi0 > 0.0, down, up);
2988 const ValueType diff = math::Sqrt(normSqGradPhi) * invDx - ValueType(1.0);
2989 const ValueType S = phi0 / (math::Sqrt(math::Pow2(phi0) + normSqGradPhi));
2991 bufferData[iter.pos()] = phi0 - dx * S * diff;
2997 TreeType
const *
const mTree;
2998 LeafNodeType
const *
const *
const mNodes;
2999 ValueType *
const mBuffer;
3001 const ValueType mVoxelSize;
3005template<
typename TreeType>
3008 using LeafNodeType =
typename TreeType::LeafNodeType;
3009 using ValueType =
typename TreeType::ValueType;
3011 MinCombine(std::vector<LeafNodeType*>& nodes,
const ValueType* buffer)
3012 : mNodes(nodes.
empty() ? nullptr : &nodes[0]), mBuffer(buffer)
3016 void operator()(
const tbb::blocked_range<size_t>& range)
const {
3018 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
3020 const ValueType* bufferData = &mBuffer[n * LeafNodeType::SIZE];
3022 typename LeafNodeType::ValueOnIter iter = mNodes[n]->beginValueOn();
3024 for (; iter; ++iter) {
3025 ValueType& val =
const_cast<ValueType&
>(iter.getValue());
3026 val = std::min(val, bufferData[iter.pos()]);
3032 LeafNodeType * *
const mNodes;
3033 ValueType
const *
const mBuffer;
3047template <
typename FloatTreeT>
3051 using ConnectivityTable = mesh_to_volume_internal::LeafNodeConnectivityTable<FloatTreeT>;
3056 ConnectivityTable nodeConnectivity(
tree);
3058 std::vector<size_t> zStartNodes, yStartNodes, xStartNodes;
3063 for (
size_t n = 0; n < nodeConnectivity.size(); ++n) {
3064 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevX()[n]) {
3065 xStartNodes.push_back(n);
3068 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevY()[n]) {
3069 yStartNodes.push_back(n);
3072 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevZ()[n]) {
3073 zStartNodes.push_back(n);
3077 using SweepingOp = mesh_to_volume_internal::SweepExteriorSign<FloatTreeT>;
3082 tbb::parallel_for(tbb::blocked_range<size_t>(0, zStartNodes.size()),
3083 SweepingOp(SweepingOp::Z_AXIS, zStartNodes, nodeConnectivity));
3085 tbb::parallel_for(tbb::blocked_range<size_t>(0, yStartNodes.size()),
3086 SweepingOp(SweepingOp::Y_AXIS, yStartNodes, nodeConnectivity));
3088 tbb::parallel_for(tbb::blocked_range<size_t>(0, xStartNodes.size()),
3089 SweepingOp(SweepingOp::X_AXIS, xStartNodes, nodeConnectivity));
3091 const size_t numLeafNodes = nodeConnectivity.size();
3092 const size_t numVoxels = numLeafNodes * FloatTreeT::LeafNodeType::SIZE;
3094 std::unique_ptr<bool[]> changedNodeMaskA{
new bool[numLeafNodes]};
3095 std::unique_ptr<bool[]> changedNodeMaskB{
new bool[numLeafNodes]};
3096 std::unique_ptr<bool[]> changedVoxelMask{
new bool[numVoxels]};
3098 mesh_to_volume_internal::fillArray(changedNodeMaskA.get(),
true, numLeafNodes);
3099 mesh_to_volume_internal::fillArray(changedNodeMaskB.get(),
false, numLeafNodes);
3100 mesh_to_volume_internal::fillArray(changedVoxelMask.get(),
false, numVoxels);
3102 const tbb::blocked_range<size_t> nodeRange(0, numLeafNodes);
3104 bool nodesUpdated =
false;
3109 tbb::parallel_for(nodeRange, mesh_to_volume_internal::SeedFillExteriorSign<FloatTreeT>(
3110 nodeConnectivity.nodes(), changedNodeMaskA.get()));
3118 tbb::parallel_for(nodeRange, mesh_to_volume_internal::SeedPoints<FloatTreeT>(
3119 nodeConnectivity, changedNodeMaskA.get(), changedNodeMaskB.get(),
3120 changedVoxelMask.get()));
3124 changedNodeMaskA.swap(changedNodeMaskB);
3126 nodesUpdated =
false;
3127 for (
size_t n = 0; n < numLeafNodes; ++n) {
3128 nodesUpdated |= changedNodeMaskA[n];
3129 if (nodesUpdated)
break;
3135 tbb::parallel_for(nodeRange, mesh_to_volume_internal::SyncVoxelMask<FloatTreeT>(
3136 nodeConnectivity.nodes(), changedNodeMaskA.get(), changedVoxelMask.get()));
3138 }
while (nodesUpdated);
3145template <
typename T, Index Log2Dim,
typename InteriorTest>
3168 const auto DIM = leafNode.
DIM;
3169 const auto SIZE = leafNode.
SIZE;
3171 std::vector<VoxelState> voxelState(SIZE, NOT_VISITED);
3173 std::vector<std::pair<Index, VoxelState>> offsetStack;
3174 offsetStack.reserve(SIZE);
3176 for (
Index offset=0; offset<SIZE; offset++) {
3177 const auto value = leafNode.
getValue(offset);
3181 if (std::abs(value) <= 0.75) {
3182 voxelState[offset] = NOT_ASSIGNED;
3183 }
else if (voxelState[offset] == NOT_VISITED) {
3187 if (interiorTest(coord)){
3190 offsetStack.push_back({offset, POSITIVE});
3191 voxelState[offset] = POSITIVE;
3193 offsetStack.push_back({offset, NEGATIVE});
3194 voxelState[offset] = NEGATIVE;
3197 while(!offsetStack.empty()){
3199 auto [off, state] = offsetStack[offsetStack.size()-1];
3200 offsetStack.pop_back();
3202 if (state == NEGATIVE) {
3209 for (
int dim=2; dim>=0; dim--){
3210 for (
int i = -1; i <=1; ++(++i)){
3211 int dimIdx = (off >> dim * Log2Dim) % DIM;
3212 auto neighOff = off + (1 << dim * Log2Dim) * i;
3214 (dimIdx < (
int)DIM - 1) &&
3215 (voxelState[neighOff] == NOT_VISITED)) {
3217 if (std::abs(leafNode.
getValue(neighOff)) <= 0.75) {
3218 voxelState[neighOff] = NOT_ASSIGNED;
3220 offsetStack.push_back({neighOff, state});
3221 voxelState[neighOff] = state;
3251template <
typename FloatTreeT,
typename InteriorTest>
3255 static_assert(std::is_invocable_r<bool, InteriorTest, Coord>::value,
3256 "InteriorTest has to be a function `Coord -> bool`!");
3257 static_assert(std::is_copy_constructible_v<InteriorTest>,
3258 "InteriorTest has to be copyable!");
3260 using LeafT =
typename FloatTreeT::LeafNodeType;
3264 auto op = [interiorTest](
auto& node) {
3265 using Node = std::decay_t<
decltype(node)>;
3267 if constexpr (std::is_same_v<Node, LeafT>) {
3269 for (
auto iter = node.beginValueAll(); iter; ++iter) {
3270 if (!interiorTest(iter.getCoord())) {
3271 iter.setValue(-*iter);
3276 for (
auto iter = node.beginChildOff(); iter; ++iter) {
3277 if (!interiorTest(iter.getCoord())) {
3278 iter.setValue(-*iter);
3284 openvdb::tree::NodeManager nodes(
tree);
3285 nodes.foreachBottomUp(
op);
3290 auto op = [interiorTest](
auto& node) {
3291 using Node = std::decay_t<
decltype(node)>;
3293 if constexpr (std::is_same_v<Node, LeafT>) {
3295 LeafT& leaf =
static_cast<LeafT&
>(node);
3300 for (
auto iter = node.beginChildOff(); iter; ++iter) {
3301 if (!interiorTest(iter.getCoord())) {
3302 iter.setValue(-*iter);
3308 openvdb::tree::NodeManager nodes(
tree);
3309 nodes.foreachBottomUp(
op);
3316template <
typename Gr
idType,
typename MeshDataAdapter,
typename Interrupter,
typename InteriorTest>
3317typename GridType::Ptr
3319 Interrupter& interrupter,
3322 float exteriorBandWidth,
3323 float interiorBandWidth,
3325 typename GridType::template ValueConverter<Int32>::Type * polygonIndexGrid,
3326 InteriorTest interiorTest,
3329 using GridTypePtr =
typename GridType::Ptr;
3330 using TreeType =
typename GridType::TreeType;
3331 using LeafNodeType =
typename TreeType::LeafNodeType;
3332 using ValueType =
typename GridType::ValueType;
3334 using Int32GridType =
typename GridType::template ValueConverter<Int32>::Type;
3335 using Int32TreeType =
typename Int32GridType::TreeType;
3337 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
3343 GridTypePtr distGrid(
new GridType(std::numeric_limits<ValueType>::max()));
3344 distGrid->setTransform(transform.
copy());
3346 ValueType exteriorWidth = ValueType(exteriorBandWidth);
3347 ValueType interiorWidth = ValueType(interiorBandWidth);
3351 if (!std::isfinite(exteriorWidth) || std::isnan(interiorWidth)) {
3352 std::stringstream msg;
3353 msg <<
"Illegal narrow band width: exterior = " << exteriorWidth
3354 <<
", interior = " << interiorWidth;
3359 const ValueType voxelSize = ValueType(transform.
voxelSize()[0]);
3361 if (!std::isfinite(voxelSize) ||
math::isZero(voxelSize)) {
3362 std::stringstream msg;
3363 msg <<
"Illegal transform, voxel size = " << voxelSize;
3369 exteriorWidth *= voxelSize;
3372 if (interiorWidth < std::numeric_limits<ValueType>::max()) {
3373 interiorWidth *= voxelSize;
3381 Int32GridType* indexGrid =
nullptr;
3383 typename Int32GridType::Ptr temporaryIndexGrid;
3385 if (polygonIndexGrid) {
3386 indexGrid = polygonIndexGrid;
3389 indexGrid = temporaryIndexGrid.get();
3392 indexGrid->newTree();
3393 indexGrid->setTransform(transform.
copy());
3395 if (computeSignedDistanceField) {
3399 interiorWidth = ValueType(0.0);
3402 TreeType& distTree = distGrid->tree();
3403 Int32TreeType& indexTree = indexGrid->tree();
3411 using VoxelizationDataType = mesh_to_volume_internal::VoxelizationData<TreeType>;
3412 using DataTable = tbb::enumerable_thread_specific<typename VoxelizationDataType::Ptr>;
3416 mesh_to_volume_internal::VoxelizePolygons<TreeType, MeshDataAdapter, Interrupter>;
3418 const tbb::blocked_range<size_t> polygonRange(0, mesh.polygonCount());
3420 tbb::parallel_for(polygonRange, Voxelizer(data, mesh, &interrupter));
3422 for (
typename DataTable::iterator i = data.begin(); i != data.end(); ++i) {
3423 VoxelizationDataType& dataItem = **i;
3424 mesh_to_volume_internal::combineData(
3425 distTree, indexTree, dataItem.distTree, dataItem.indexTree);
3431 if (interrupter.wasInterrupted(30))
return distGrid;
3438 if (computeSignedDistanceField) {
3441 if constexpr (std::is_same_v<InteriorTest, std::nullptr_t>) {
3443 (void) interiorTest;
3450 bool signInitializedForEveryVoxel =
3452 !std::is_same_v<InteriorTest, std::nullptr_t> &&
3456 if (!signInitializedForEveryVoxel) {
3458 std::vector<LeafNodeType*> nodes;
3459 nodes.reserve(distTree.leafCount());
3460 distTree.getNodes(nodes);
3462 const tbb::blocked_range<size_t> nodeRange(0, nodes.size());
3465 mesh_to_volume_internal::ComputeIntersectingVoxelSign<TreeType, MeshDataAdapter>;
3467 tbb::parallel_for(nodeRange, SignOp(nodes, distTree, indexTree, mesh));
3469 if (interrupter.wasInterrupted(45))
return distGrid;
3472 if (removeIntersectingVoxels) {
3474 tbb::parallel_for(nodeRange,
3475 mesh_to_volume_internal::ValidateIntersectingVoxels<TreeType>(distTree, nodes));
3477 tbb::parallel_for(nodeRange,
3478 mesh_to_volume_internal::RemoveSelfIntersectingSurface<TreeType>(
3479 nodes, distTree, indexTree));
3487 if (interrupter.wasInterrupted(50))
return distGrid;
3489 if (distTree.activeVoxelCount() == 0) {
3491 distTree.root().setBackground(exteriorWidth,
false);
3497 std::vector<LeafNodeType*> nodes;
3498 nodes.reserve(distTree.leafCount());
3499 distTree.getNodes(nodes);
3501 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3502 mesh_to_volume_internal::TransformValues<TreeType>(
3503 nodes, voxelSize, !computeSignedDistanceField));
3507 if (computeSignedDistanceField) {
3508 distTree.root().setBackground(exteriorWidth,
false);
3514 if (interrupter.wasInterrupted(54))
return distGrid;
3521 const ValueType minBandWidth = voxelSize * ValueType(2.0);
3523 if (interiorWidth > minBandWidth || exteriorWidth > minBandWidth) {
3526 BoolTreeType maskTree(
false);
3529 std::vector<LeafNodeType*> nodes;
3530 nodes.reserve(distTree.leafCount());
3531 distTree.getNodes(nodes);
3533 mesh_to_volume_internal::ConstructVoxelMask<TreeType>
op(maskTree, distTree, nodes);
3534 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()),
op);
3538 unsigned maxIterations = std::numeric_limits<unsigned>::max();
3540 float progress = 54.0f, step = 0.0f;
3542 2.0 * std::ceil((std::max(interiorWidth, exteriorWidth) - minBandWidth) / voxelSize);
3544 if (estimated <
double(maxIterations)) {
3545 maxIterations = unsigned(estimated);
3546 step = 40.0f / float(maxIterations);
3549 std::vector<typename BoolTreeType::LeafNodeType*> maskNodes;
3554 if (interrupter.wasInterrupted(
int(progress)))
return distGrid;
3556 const size_t maskNodeCount = maskTree.leafCount();
3557 if (maskNodeCount == 0)
break;
3560 maskNodes.reserve(maskNodeCount);
3561 maskTree.getNodes(maskNodes);
3563 const tbb::blocked_range<size_t> range(0, maskNodes.size());
3565 tbb::parallel_for(range,
3566 mesh_to_volume_internal::DiffLeafNodeMask<TreeType>(distTree, maskNodes));
3568 mesh_to_volume_internal::expandNarrowband(distTree, indexTree, maskTree, maskNodes,
3569 mesh, exteriorWidth, interiorWidth, voxelSize);
3571 if ((++count) >= maxIterations)
break;
3576 if (interrupter.wasInterrupted(94))
return distGrid;
3578 if (!polygonIndexGrid) indexGrid->clear();
3586 if (computeSignedDistanceField && renormalizeValues) {
3588 std::vector<LeafNodeType*> nodes;
3589 nodes.reserve(distTree.leafCount());
3590 distTree.getNodes(nodes);
3592 std::unique_ptr<ValueType[]> buffer{
new ValueType[LeafNodeType::SIZE * nodes.size()]};
3594 const ValueType offset = ValueType(0.8 * voxelSize);
3596 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3597 mesh_to_volume_internal::OffsetValues<TreeType>(nodes, -offset));
3599 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3600 mesh_to_volume_internal::Renormalize<TreeType>(
3601 distTree, nodes, buffer.get(), voxelSize));
3603 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3604 mesh_to_volume_internal::MinCombine<TreeType>(nodes, buffer.get()));
3606 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3607 mesh_to_volume_internal::OffsetValues<TreeType>(
3608 nodes, offset - mesh_to_volume_internal::Tolerance<ValueType>::epsilon()));
3611 if (interrupter.wasInterrupted(99))
return distGrid;
3618 if (trimNarrowBand && std::min(interiorWidth, exteriorWidth) < voxelSize * ValueType(4.0)) {
3620 std::vector<LeafNodeType*> nodes;
3621 nodes.reserve(distTree.leafCount());
3622 distTree.getNodes(nodes);
3624 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3625 mesh_to_volume_internal::InactivateValues<TreeType>(
3626 nodes, exteriorWidth, computeSignedDistanceField ? interiorWidth : exteriorWidth));
3629 distTree, exteriorWidth, computeSignedDistanceField ? -interiorWidth : -exteriorWidth);
3636template <
typename Gr
idType,
typename MeshDataAdapter,
typename InteriorTest>
3637typename GridType::Ptr
3641 float exteriorBandWidth,
3642 float interiorBandWidth,
3644 typename GridType::template ValueConverter<Int32>::Type * polygonIndexGrid,
3650 exteriorBandWidth, interiorBandWidth, flags, polygonIndexGrid);
3661template<
typename Gr
idType,
typename Interrupter>
3662inline typename std::enable_if<std::is_floating_point<typename GridType::ValueType>::value,
3663 typename GridType::Ptr>::type
3665 Interrupter& interrupter,
3666 const openvdb::math::Transform& xform,
3667 const std::vector<Vec3s>&
points,
3668 const std::vector<Vec3I>& triangles,
3669 const std::vector<Vec4I>& quads,
3672 bool unsignedDistanceField =
false)
3675 return typename GridType::Ptr(
new GridType(
typename GridType::ValueType(exBandWidth)));
3678 const size_t numPoints =
points.size();
3679 std::unique_ptr<Vec3s[]> indexSpacePoints{
new Vec3s[numPoints]};
3682 tbb::parallel_for(tbb::blocked_range<size_t>(0, numPoints),
3683 mesh_to_volume_internal::TransformPoints<Vec3s>(
3684 &points[0], indexSpacePoints.get(), xform));
3686 const int conversionFlags = unsignedDistanceField ? UNSIGNED_DISTANCE_FIELD : 0;
3688 if (quads.empty()) {
3690 QuadAndTriangleDataAdapter<Vec3s, Vec3I>
3691 mesh(indexSpacePoints.get(), numPoints, &triangles[0], triangles.size());
3693 return meshToVolume<GridType>(
3694 interrupter, mesh, xform, exBandWidth, inBandWidth, conversionFlags);
3696 }
else if (triangles.empty()) {
3698 QuadAndTriangleDataAdapter<Vec3s, Vec4I>
3699 mesh(indexSpacePoints.get(), numPoints, &quads[0], quads.size());
3701 return meshToVolume<GridType>(
3702 interrupter, mesh, xform, exBandWidth, inBandWidth, conversionFlags);
3707 const size_t numPrimitives = triangles.size() + quads.size();
3708 std::unique_ptr<Vec4I[]> prims{
new Vec4I[numPrimitives]};
3710 for (
size_t n = 0, N = triangles.size(); n < N; ++n) {
3711 const Vec3I& triangle = triangles[n];
3712 Vec4I& prim = prims[n];
3713 prim[0] = triangle[0];
3714 prim[1] = triangle[1];
3715 prim[2] = triangle[2];
3716 prim[3] = util::INVALID_IDX;
3719 const size_t offset = triangles.size();
3720 for (
size_t n = 0, N = quads.size(); n < N; ++n) {
3721 prims[offset + n] = quads[n];
3724 QuadAndTriangleDataAdapter<Vec3s, Vec4I>
3725 mesh(indexSpacePoints.get(), numPoints, prims.get(), numPrimitives);
3727 return meshToVolume<GridType>(interrupter, mesh, xform,
3728 exBandWidth, inBandWidth, conversionFlags);
3734template<
typename Gr
idType,
typename Interrupter>
3735inline typename std::enable_if<!std::is_floating_point<typename GridType::ValueType>::value,
3736 typename GridType::Ptr>::type
3739 const math::Transform& ,
3740 const std::vector<Vec3s>& ,
3741 const std::vector<Vec3I>& ,
3742 const std::vector<Vec4I>& ,
3748 "mesh to volume conversion is supported only for scalar floating-point grids");
3758template<
typename Gr
idType>
3759typename GridType::Ptr
3761 const openvdb::math::Transform& xform,
3762 const std::vector<Vec3s>&
points,
3763 const std::vector<Vec3I>& triangles,
3771template<
typename Gr
idType,
typename Interrupter>
3772typename GridType::Ptr
3774 Interrupter& interrupter,
3775 const openvdb::math::Transform& xform,
3776 const std::vector<Vec3s>&
points,
3777 const std::vector<Vec3I>& triangles,
3780 std::vector<Vec4I> quads(0);
3781 return doMeshConversion<GridType>(interrupter, xform,
points, triangles, quads,
3782 halfWidth, halfWidth);
3786template<
typename Gr
idType>
3787typename GridType::Ptr
3789 const openvdb::math::Transform& xform,
3790 const std::vector<Vec3s>&
points,
3791 const std::vector<Vec4I>& quads,
3799template<
typename Gr
idType,
typename Interrupter>
3800typename GridType::Ptr
3802 Interrupter& interrupter,
3803 const openvdb::math::Transform& xform,
3804 const std::vector<Vec3s>&
points,
3805 const std::vector<Vec4I>& quads,
3808 std::vector<Vec3I> triangles(0);
3809 return doMeshConversion<GridType>(interrupter, xform,
points, triangles, quads,
3810 halfWidth, halfWidth);
3814template<
typename Gr
idType>
3815typename GridType::Ptr
3817 const openvdb::math::Transform& xform,
3818 const std::vector<Vec3s>&
points,
3819 const std::vector<Vec3I>& triangles,
3820 const std::vector<Vec4I>& quads,
3825 nullInterrupter, xform,
points, triangles, quads, halfWidth);
3829template<
typename Gr
idType,
typename Interrupter>
3830typename GridType::Ptr
3832 Interrupter& interrupter,
3833 const openvdb::math::Transform& xform,
3834 const std::vector<Vec3s>&
points,
3835 const std::vector<Vec3I>& triangles,
3836 const std::vector<Vec4I>& quads,
3839 return doMeshConversion<GridType>(interrupter, xform,
points, triangles, quads,
3840 halfWidth, halfWidth);
3844template<
typename Gr
idType>
3845typename GridType::Ptr
3847 const openvdb::math::Transform& xform,
3848 const std::vector<Vec3s>&
points,
3849 const std::vector<Vec3I>& triangles,
3850 const std::vector<Vec4I>& quads,
3856 nullInterrupter, xform,
points, triangles, quads, exBandWidth, inBandWidth);
3860template<
typename Gr
idType,
typename Interrupter>
3861typename GridType::Ptr
3863 Interrupter& interrupter,
3864 const openvdb::math::Transform& xform,
3865 const std::vector<Vec3s>&
points,
3866 const std::vector<Vec3I>& triangles,
3867 const std::vector<Vec4I>& quads,
3871 return doMeshConversion<GridType>(interrupter, xform,
points, triangles,
3872 quads, exBandWidth, inBandWidth);
3876template<
typename Gr
idType>
3877typename GridType::Ptr
3879 const openvdb::math::Transform& xform,
3880 const std::vector<Vec3s>&
points,
3881 const std::vector<Vec3I>& triangles,
3882 const std::vector<Vec4I>& quads,
3887 nullInterrupter, xform,
points, triangles, quads, bandWidth);
3891template<
typename Gr
idType,
typename Interrupter>
3892typename GridType::Ptr
3894 Interrupter& interrupter,
3895 const openvdb::math::Transform& xform,
3896 const std::vector<Vec3s>&
points,
3897 const std::vector<Vec3I>& triangles,
3898 const std::vector<Vec4I>& quads,
3901 return doMeshConversion<GridType>(interrupter, xform,
points, triangles, quads,
3902 bandWidth, bandWidth,
true);
3913 ostr <<
"{[ " << rhs.
mXPrim <<
", " << rhs.
mXDist <<
"]";
3914 ostr <<
" [ " << rhs.
mYPrim <<
", " << rhs.
mYDist <<
"]";
3915 ostr <<
" [ " << rhs.
mZPrim <<
", " << rhs.
mZDist <<
"]}";
3920inline MeshToVoxelEdgeData::EdgeData
3935 const std::vector<Vec3s>& pointList,
3936 const std::vector<Vec4I>& polygonList);
3941 inline void operator() (
const tbb::blocked_range<size_t> &range);
3949 struct Primitive {
Vec3d a, b, c, d;
Int32 index; };
3951 template<
bool IsQuad>
3952 inline void voxelize(
const Primitive&);
3954 template<
bool IsQuad>
3955 inline bool evalPrimitive(
const Coord&,
const Primitive&);
3957 inline bool rayTriangleIntersection(
const Vec3d& origin,
const Vec3d& dir,
3964 const std::vector<Vec3s>& mPointList;
3965 const std::vector<Vec4I>& mPolygonList;
3968 using IntTreeT = TreeType::ValueConverter<Int32>::Type;
3969 IntTreeT mLastPrimTree;
3976 const std::vector<Vec3s>& pointList,
3977 const std::vector<Vec4I>& polygonList)
3980 , mPointList(pointList)
3981 , mPolygonList(polygonList)
3982 , mLastPrimTree(
Int32(
util::INVALID_IDX))
3983 , mLastPrimAccessor(mLastPrimTree)
3992 , mPointList(rhs.mPointList)
3993 , mPolygonList(rhs.mPolygonList)
3994 , mLastPrimTree(
Int32(
util::INVALID_IDX))
3995 , mLastPrimAccessor(mLastPrimTree)
4004 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, mPolygonList.size()), *
this);
4006 (*this)(tbb::blocked_range<size_t>(0, mPolygonList.size()));
4015 using NodeChainType = RootNodeType::NodeChainType;
4016 static_assert(NodeChainType::Size > 1,
"expected tree height > 1");
4017 using InternalNodeType =
typename NodeChainType::template Get<1>;
4025 for ( ; leafIt; ++leafIt) {
4026 ijk = leafIt->origin();
4032 mAccessor.addLeaf(rhs.mAccessor.
probeLeaf(ijk));
4033 InternalNodeType* node = rhs.mAccessor.
getNode<InternalNodeType>();
4035 rhs.mAccessor.
clear();
4045 if (!lhsLeafPt->isValueOn(offset)) {
4046 lhsLeafPt->setValueOn(offset, rhsValue);
4078 for (
size_t n = range.begin(); n < range.end(); ++n) {
4080 const Vec4I& verts = mPolygonList[n];
4082 prim.index =
Int32(n);
4083 prim.a =
Vec3d(mPointList[verts[0]]);
4084 prim.b =
Vec3d(mPointList[verts[1]]);
4085 prim.c =
Vec3d(mPointList[verts[2]]);
4088 prim.d =
Vec3d(mPointList[verts[3]]);
4089 voxelize<true>(prim);
4091 voxelize<false>(prim);
4097template<
bool IsQuad>
4099MeshToVoxelEdgeData::GenEdgeData::voxelize(
const Primitive& prim)
4101 std::deque<Coord> coordList;
4105 coordList.push_back(ijk);
4107 evalPrimitive<IsQuad>(ijk, prim);
4109 while (!coordList.empty()) {
4111 ijk = coordList.back();
4112 coordList.pop_back();
4114 for (
Int32 i = 0; i < 26; ++i) {
4117 if (prim.index != mLastPrimAccessor.getValue(nijk)) {
4118 mLastPrimAccessor.setValue(nijk, prim.index);
4119 if(evalPrimitive<IsQuad>(nijk, prim)) coordList.push_back(nijk);
4126template<
bool IsQuad>
4128MeshToVoxelEdgeData::GenEdgeData::evalPrimitive(
const Coord& ijk,
const Primitive& prim)
4130 Vec3d uvw, org(ijk[0], ijk[1], ijk[2]);
4131 bool intersecting =
false;
4135 mAccessor.probeValue(ijk, edgeData);
4138 double dist = (org -
4139 closestPointOnTriangleToPoint(prim.a, prim.c, prim.b, org, uvw)).lengthSqr();
4141 if (rayTriangleIntersection(org,
Vec3d(1.0, 0.0, 0.0), prim.a, prim.c, prim.b, t)) {
4142 if (t < edgeData.mXDist) {
4143 edgeData.mXDist = float(t);
4144 edgeData.mXPrim = prim.index;
4145 intersecting =
true;
4149 if (rayTriangleIntersection(org,
Vec3d(0.0, 1.0, 0.0), prim.a, prim.c, prim.b, t)) {
4150 if (t < edgeData.mYDist) {
4151 edgeData.mYDist = float(t);
4152 edgeData.mYPrim = prim.index;
4153 intersecting =
true;
4157 if (rayTriangleIntersection(org,
Vec3d(0.0, 0.0, 1.0), prim.a, prim.c, prim.b, t)) {
4158 if (t < edgeData.mZDist) {
4159 edgeData.mZDist = float(t);
4160 edgeData.mZPrim = prim.index;
4161 intersecting =
true;
4167 double secondDist = (org -
4170 if (secondDist < dist) dist = secondDist;
4172 if (rayTriangleIntersection(org,
Vec3d(1.0, 0.0, 0.0), prim.a, prim.d, prim.c, t)) {
4173 if (t < edgeData.mXDist) {
4174 edgeData.mXDist = float(t);
4175 edgeData.mXPrim = prim.index;
4176 intersecting =
true;
4180 if (rayTriangleIntersection(org,
Vec3d(0.0, 1.0, 0.0), prim.a, prim.d, prim.c, t)) {
4181 if (t < edgeData.mYDist) {
4182 edgeData.mYDist = float(t);
4183 edgeData.mYPrim = prim.index;
4184 intersecting =
true;
4188 if (rayTriangleIntersection(org,
Vec3d(0.0, 0.0, 1.0), prim.a, prim.d, prim.c, t)) {
4189 if (t < edgeData.mZDist) {
4190 edgeData.mZDist = float(t);
4191 edgeData.mZPrim = prim.index;
4192 intersecting =
true;
4197 if (intersecting) mAccessor.setValue(ijk, edgeData);
4199 return (dist < 0.86602540378443861);
4204MeshToVoxelEdgeData::GenEdgeData::rayTriangleIntersection(
4215 double divisor = s1.
dot(e1);
4216 if (!(std::abs(divisor) > 0.0))
return false;
4220 double inv_divisor = 1.0 / divisor;
4221 Vec3d d = origin - a;
4222 double b1 = d.
dot(s1) * inv_divisor;
4224 if (b1 < 0.0 || b1 > 1.0)
return false;
4227 double b2 = dir.
dot(s2) * inv_divisor;
4229 if (b2 < 0.0 || (b1 + b2) > 1.0)
return false;
4233 t = e2.dot(s2) * inv_divisor;
4234 return (t < 0.0) ? false :
true;
4250 const std::vector<Vec3s>& pointList,
4251 const std::vector<Vec4I>& polygonList)
4257 mTree.merge(converter.
tree());
4265 std::vector<Vec3d>&
points,
4266 std::vector<Index32>& primitives)
4276 point[0] = double(coord[0]) + data.
mXDist;
4277 point[1] = double(coord[1]);
4278 point[2] = double(coord[2]);
4281 primitives.push_back(data.
mXPrim);
4285 point[0] = double(coord[0]);
4286 point[1] = double(coord[1]) + data.
mYDist;
4287 point[2] = double(coord[2]);
4290 primitives.push_back(data.
mYPrim);
4294 point[0] = double(coord[0]);
4295 point[1] = double(coord[1]);
4296 point[2] = double(coord[2]) + data.
mZDist;
4299 primitives.push_back(data.
mZPrim);
4309 point[0] = double(coord[0]);
4310 point[1] = double(coord[1]) + data.
mYDist;
4311 point[2] = double(coord[2]);
4314 primitives.push_back(data.
mYPrim);
4318 point[0] = double(coord[0]);
4319 point[1] = double(coord[1]);
4320 point[2] = double(coord[2]) + data.
mZDist;
4323 primitives.push_back(data.
mZPrim);
4331 point[0] = double(coord[0]);
4332 point[1] = double(coord[1]) + data.
mYDist;
4333 point[2] = double(coord[2]);
4336 primitives.push_back(data.
mYPrim);
4345 point[0] = double(coord[0]) + data.
mXDist;
4346 point[1] = double(coord[1]);
4347 point[2] = double(coord[2]);
4350 primitives.push_back(data.
mXPrim);
4354 point[0] = double(coord[0]);
4355 point[1] = double(coord[1]) + data.
mYDist;
4356 point[2] = double(coord[2]);
4359 primitives.push_back(data.
mYPrim);
4369 point[0] = double(coord[0]) + data.
mXDist;
4370 point[1] = double(coord[1]);
4371 point[2] = double(coord[2]);
4374 primitives.push_back(data.
mXPrim);
4383 point[0] = double(coord[0]) + data.
mXDist;
4384 point[1] = double(coord[1]);
4385 point[2] = double(coord[2]);
4388 primitives.push_back(data.
mXPrim);
4392 point[0] = double(coord[0]);
4393 point[1] = double(coord[1]);
4394 point[2] = double(coord[2]) + data.
mZDist;
4397 primitives.push_back(data.
mZPrim);
4406 point[0] = double(coord[0]);
4407 point[1] = double(coord[1]);
4408 point[2] = double(coord[2]) + data.
mZDist;
4411 primitives.push_back(data.
mZPrim);
4417template<
typename Gr
idType,
typename VecType>
4418typename GridType::Ptr
4420 const openvdb::math::Transform& xform,
4421 typename VecType::ValueType halfWidth)
4437 faces[0] =
Vec4I(0, 1, 2, 3);
4438 faces[1] =
Vec4I(7, 6, 5, 4);
4439 faces[2] =
Vec4I(4, 5, 1, 0);
4440 faces[3] =
Vec4I(6, 7, 3, 2);
4441 faces[4] =
Vec4I(0, 3, 7, 4);
4442 faces[5] =
Vec4I(1, 5, 6, 2);
4446 return meshToVolume<GridType>(mesh, xform,
static_cast<float>(halfWidth),
static_cast<float>(halfWidth));
4455#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
4457#ifdef OPENVDB_INSTANTIATE_MESHTOVOLUME
4461#define _FUNCTION(TreeT) \
4462 Grid<TreeT>::Ptr meshToVolume<Grid<TreeT>>(util::NullInterrupter&, \
4463 const QuadAndTriangleDataAdapter<Vec3s, Vec3I>&, const openvdb::math::Transform&, \
4464 float, float, int, Grid<TreeT>::ValueConverter<Int32>::Type*, std::nullptr_t, InteriorTestStrategy)
4468#define _FUNCTION(TreeT) \
4469 Grid<TreeT>::Ptr meshToVolume<Grid<TreeT>>(util::NullInterrupter&, \
4470 const QuadAndTriangleDataAdapter<Vec3s, Vec4I>&, const openvdb::math::Transform&, \
4471 float, float, int, Grid<TreeT>::ValueConverter<Int32>::Type*, std::nullptr_t, InteriorTestStrategy)
4475#define _FUNCTION(TreeT) \
4476 Grid<TreeT>::Ptr meshToLevelSet<Grid<TreeT>>(util::NullInterrupter&, \
4477 const openvdb::math::Transform&, const std::vector<Vec3s>&, const std::vector<Vec3I>&, \
4482#define _FUNCTION(TreeT) \
4483 Grid<TreeT>::Ptr meshToLevelSet<Grid<TreeT>>(util::NullInterrupter&, \
4484 const openvdb::math::Transform&, const std::vector<Vec3s>&, const std::vector<Vec4I>&, \
4489#define _FUNCTION(TreeT) \
4490 Grid<TreeT>::Ptr meshToLevelSet<Grid<TreeT>>(util::NullInterrupter&, \
4491 const openvdb::math::Transform&, const std::vector<Vec3s>&, \
4492 const std::vector<Vec3I>&, const std::vector<Vec4I>&, float)
4496#define _FUNCTION(TreeT) \
4497 Grid<TreeT>::Ptr meshToSignedDistanceField<Grid<TreeT>>(util::NullInterrupter&, \
4498 const openvdb::math::Transform&, const std::vector<Vec3s>&, \
4499 const std::vector<Vec3I>&, const std::vector<Vec4I>&, float, float)
4503#define _FUNCTION(TreeT) \
4504 Grid<TreeT>::Ptr meshToUnsignedDistanceField<Grid<TreeT>>(util::NullInterrupter&, \
4505 const openvdb::math::Transform&, const std::vector<Vec3s>&, \
4506 const std::vector<Vec3I>&, const std::vector<Vec4I>&, float)
4510#define _FUNCTION(TreeT) \
4511 Grid<TreeT>::Ptr createLevelSetBox<Grid<TreeT>>(const math::BBox<Vec3s>&, \
4512 const openvdb::math::Transform&, float)
4516#define _FUNCTION(TreeT) \
4517 Grid<TreeT>::Ptr createLevelSetBox<Grid<TreeT>>(const math::BBox<Vec3d>&, \
4518 const openvdb::math::Transform&, double)
4522#define _FUNCTION(TreeT) \
4523 void traceExteriorBoundaries(TreeT&)
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
Efficient multi-threaded replacement of the background values in tree.
OPENVDB_API std::ostream & operator<<(std::ostream &os, half h)
Output h to os, formatted as a float.
Defined various multi-threaded utility functions for trees.
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
static Coord floor(const Vec3< T > &xyz)
Return the largest integer coordinates that are not greater than xyz (node centered conversion).
Definition Coord.h:57
Axis-aligned bounding box.
Definition BBox.h:24
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
Definition BBox.h:64
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
Definition BBox.h:62
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
T dot(const Vec3< T > &v) const
Dot product.
Definition Vec3.h:192
Vec3< T > cross(const Vec3< T > &v) const
Return the cross product of "this" vector and v;.
Definition Vec3.h:221
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim....
Definition LeafNode.h:39
void setValueOnly(const Coord &xyz, const ValueType &val)
Set the value of the voxel at the given coordinates but don't change its active state.
Definition LeafNode.h:1133
static const Index DIM
Definition LeafNode.h:51
Coord offsetToGlobalCoord(Index n) const
Return the global coordinates for a linear table offset.
Definition LeafNode.h:1064
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition LeafNode.h:1075
static const Index SIZE
Definition LeafNode.h:54
const ValueT & getValue() const
Return the tile or voxel value to which this iterator is currently pointing.
Definition TreeIterator.h:693
void clearAllAccessors()
Clear all registered accessors.
Definition Tree.h:1461
_RootNodeType RootNodeType
Definition Tree.h:200
TreeValueIteratorBase< const Tree, typename RootNodeType::ValueOnCIter > ValueOnCIter
Definition Tree.h:1053
LeafIteratorBase< Tree, typename RootNodeType::ChildOnIter > LeafIter
Iterator over all leaf nodes in this tree.
Definition Tree.h:1032
typename RootNodeType::LeafNodeType LeafNodeType
Definition Tree.h:203
LeafIter beginLeaf()
Return an iterator over all leaf nodes in this tree.
Definition Tree.h:1045
void clear() override final
Remove all the cached nodes and invalidate the corresponding hash-keys.
Definition ValueAccessor.h:880
LeafNodeT * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains the voxel coordinate xyz. If no LeafNode exists,...
Definition ValueAccessor.h:836
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the value at a given coordinate as well as its value.
Definition ValueAccessor.h:492
NodeT * getNode()
Return the node of type NodeT that has been cached on this accessor. If this accessor does not cache ...
Definition ValueAccessor.h:848
Convert polygonal meshes that consist of quads and/or triangles into signed or unsigned distance fiel...
#define OPENVDB_LOG_DEBUG(message)
In debug builds only, log a debugging message of the form 'someVar << "text" << .....
Definition logging.h:266
bool empty(const char *str)
tests if a c-string str is empty, that is its first value is '\0'
Definition Util.h:144
PointType
Definition NanoVDB.h:401
bool operator<(const Tuple< SIZE, T0 > &t0, const Tuple< SIZE, T1 > &t1)
Definition Tuple.h:175
Vec3< double > Vec3d
Definition Vec3.h:665
bool isZero(const Type &x)
Return true if x is exactly equal to zero.
Definition Math.h:337
Axis
Definition Math.h:901
@ Z_AXIS
Definition Math.h:904
@ X_AXIS
Definition Math.h:902
@ Y_AXIS
Definition Math.h:903
Vec3< float > Vec3s
Definition Vec3.h:664
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...
Definition AttributeArray.h:42
Definition PointDataGrid.h:170
ValueAccessorImpl< TreeType, IsSafe, MutexType, openvdb::make_index_sequence< CacheLevels > > ValueAccessor
Default alias for a ValueAccessor. This is simply a helper alias for the generic definition but takes...
Definition ValueAccessor.h:86
constexpr Index32 INVALID_IDX
Definition Util.h:19
constexpr Coord COORD_OFFSETS[26]
coordinate offset table for neighboring voxels
Definition Util.h:22
bool wasInterrupted(T *i, int percent=-1)
Definition NullInterrupter.h:49
static const Real LEVEL_SET_HALF_WIDTH
Definition Types.h:461
Index32 Index
Definition Types.h:54
math::Vec4< Index32 > Vec4I
Definition Types.h:88
@ GRID_LEVEL_SET
Definition Types.h:455
@ GRID_UNKNOWN
Definition Types.h:454
uint32_t Index32
Definition Types.h:52
math::Vec3< Index32 > Vec3I
Definition Types.h:73
int32_t Int32
Definition Types.h:56
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
Tree< RootNode< InternalNode< InternalNode< LeafNode< T, N3 >, N2 >, N1 > > > Type
Definition Tree.h:1130
Base class for interrupters.
Definition NullInterrupter.h:26
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition version.h.in:162