16 #ifndef OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED 17 #define OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED 25 #include "openvdb/thread/Threading.h" 32 #include <tbb/blocked_range.h> 33 #include <tbb/enumerable_thread_specific.h> 34 #include <tbb/parallel_for.h> 35 #include <tbb/parallel_reduce.h> 36 #include <tbb/partitioner.h> 37 #include <tbb/task_group.h> 38 #include <tbb/task_arena.h> 46 #include <type_traits> 111 template <
typename Gr
idType,
typename MeshDataAdapter>
112 typename GridType::Ptr
116 float exteriorBandWidth = 3.0f,
117 float interiorBandWidth = 3.0f,
137 template <
typename Gr
idType,
typename MeshDataAdapter,
typename Interrupter>
138 typename GridType::Ptr
140 Interrupter& interrupter,
143 float exteriorBandWidth = 3.0f,
144 float interiorBandWidth = 3.0f,
162 template<
typename Po
intType,
typename PolygonType>
166 const std::vector<PolygonType>& polygons)
167 : mPointArray(points.empty() ? nullptr : &points[0])
168 , mPointArraySize(points.size())
169 , mPolygonArray(polygons.empty() ? nullptr : &polygons[0])
170 , mPolygonArraySize(polygons.size())
175 const PolygonType* polygonArray,
size_t polygonArraySize)
176 : mPointArray(pointArray)
177 , mPointArraySize(pointArraySize)
178 , mPolygonArray(polygonArray)
179 , mPolygonArraySize(polygonArraySize)
188 return (PolygonType::size == 3 || mPolygonArray[n][3] ==
util::INVALID_IDX) ? 3 : 4;
194 const PointType& p = mPointArray[mPolygonArray[n][int(v)]];
195 pos[0] = double(p[0]);
196 pos[1] = double(p[1]);
197 pos[2] = double(p[2]);
201 PointType
const *
const mPointArray;
202 size_t const mPointArraySize;
203 PolygonType
const *
const mPolygonArray;
204 size_t const mPolygonArraySize;
232 template<
typename Gr
idType>
233 typename GridType::Ptr
235 const openvdb::math::Transform& xform,
236 const std::vector<Vec3s>& points,
237 const std::vector<Vec3I>& triangles,
241 template<
typename Gr
idType,
typename Interrupter>
242 typename GridType::Ptr
244 Interrupter& interrupter,
245 const openvdb::math::Transform& xform,
246 const std::vector<Vec3s>& points,
247 const std::vector<Vec3I>& triangles,
266 template<
typename Gr
idType>
267 typename GridType::Ptr
269 const openvdb::math::Transform& xform,
270 const std::vector<Vec3s>& points,
271 const std::vector<Vec4I>& quads,
275 template<
typename Gr
idType,
typename Interrupter>
276 typename GridType::Ptr
278 Interrupter& interrupter,
279 const openvdb::math::Transform& xform,
280 const std::vector<Vec3s>& points,
281 const std::vector<Vec4I>& quads,
301 template<
typename Gr
idType>
302 typename GridType::Ptr
304 const openvdb::math::Transform& xform,
305 const std::vector<Vec3s>& points,
306 const std::vector<Vec3I>& triangles,
307 const std::vector<Vec4I>& quads,
311 template<
typename Gr
idType,
typename Interrupter>
312 typename GridType::Ptr
314 Interrupter& interrupter,
315 const openvdb::math::Transform& xform,
316 const std::vector<Vec3s>& points,
317 const std::vector<Vec3I>& triangles,
318 const std::vector<Vec4I>& quads,
340 template<
typename Gr
idType>
341 typename GridType::Ptr
343 const openvdb::math::Transform& xform,
344 const std::vector<Vec3s>& points,
345 const std::vector<Vec3I>& triangles,
346 const std::vector<Vec4I>& quads,
351 template<
typename Gr
idType,
typename Interrupter>
352 typename GridType::Ptr
354 Interrupter& interrupter,
355 const openvdb::math::Transform& xform,
356 const std::vector<Vec3s>& points,
357 const std::vector<Vec3I>& triangles,
358 const std::vector<Vec4I>& quads,
377 template<
typename Gr
idType>
378 typename GridType::Ptr
380 const openvdb::math::Transform& xform,
381 const std::vector<Vec3s>& points,
382 const std::vector<Vec3I>& triangles,
383 const std::vector<Vec4I>& quads,
387 template<
typename Gr
idType,
typename Interrupter>
388 typename GridType::Ptr
390 Interrupter& interrupter,
391 const openvdb::math::Transform& xform,
392 const std::vector<Vec3s>& points,
393 const std::vector<Vec3I>& triangles,
394 const std::vector<Vec4I>& quads,
407 template<
typename Gr
idType,
typename VecType>
408 typename GridType::Ptr
410 const openvdb::math::Transform& xform,
423 template <
typename FloatTreeT>
441 : mXDist(dist), mYDist(dist), mZDist(dist)
484 void convert(
const std::vector<Vec3s>& pointList,
const std::vector<Vec4I>& polygonList);
489 void getEdgeData(
Accessor& acc,
const Coord& ijk,
490 std::vector<Vec3d>& points, std::vector<Index32>& primitives);
511 namespace mesh_to_volume_internal {
513 template<
typename Po
intType>
514 struct TransformPoints {
516 TransformPoints(
const PointType* pointsIn, PointType* pointsOut,
518 : mPointsIn(pointsIn), mPointsOut(pointsOut), mXform(&xform)
522 void operator()(
const tbb::blocked_range<size_t>& range)
const {
526 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
528 const PointType& wsP = mPointsIn[n];
529 pos[0] = double(wsP[0]);
530 pos[1] = double(wsP[1]);
531 pos[2] = double(wsP[2]);
533 pos = mXform->worldToIndex(pos);
535 PointType& isP = mPointsOut[n];
536 isP[0] =
typename PointType::value_type(pos[0]);
537 isP[1] =
typename PointType::value_type(pos[1]);
538 isP[2] =
typename PointType::value_type(pos[2]);
542 PointType
const *
const mPointsIn;
543 PointType *
const mPointsOut;
548 template<
typename ValueType>
551 static ValueType epsilon() {
return ValueType(1e-7); }
552 static ValueType minNarrowBandWidth() {
return ValueType(1.0 + 1e-6); }
559 template<
typename TreeType>
560 class CombineLeafNodes
567 using Int32LeafNodeType =
typename Int32TreeType::LeafNodeType;
569 CombineLeafNodes(
TreeType& lhsDistTree, Int32TreeType& lhsIdxTree,
570 LeafNodeType ** rhsDistNodes, Int32LeafNodeType ** rhsIdxNodes)
571 : mDistTree(&lhsDistTree)
572 , mIdxTree(&lhsIdxTree)
573 , mRhsDistNodes(rhsDistNodes)
574 , mRhsIdxNodes(rhsIdxNodes)
578 void operator()(
const tbb::blocked_range<size_t>& range)
const {
583 using DistValueType =
typename LeafNodeType::ValueType;
584 using IndexValueType =
typename Int32LeafNodeType::ValueType;
586 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
588 const Coord& origin = mRhsDistNodes[n]->origin();
590 LeafNodeType* lhsDistNode = distAcc.
probeLeaf(origin);
591 Int32LeafNodeType* lhsIdxNode = idxAcc.
probeLeaf(origin);
593 DistValueType* lhsDistData = lhsDistNode->buffer().data();
594 IndexValueType* lhsIdxData = lhsIdxNode->buffer().data();
596 const DistValueType* rhsDistData = mRhsDistNodes[n]->buffer().data();
597 const IndexValueType* rhsIdxData = mRhsIdxNodes[n]->buffer().data();
600 for (
Index32 offset = 0; offset < LeafNodeType::SIZE; ++offset) {
604 const DistValueType& lhsValue = lhsDistData[offset];
605 const DistValueType& rhsValue = rhsDistData[offset];
607 if (rhsValue < lhsValue) {
608 lhsDistNode->setValueOn(offset, rhsValue);
609 lhsIdxNode->setValueOn(offset, rhsIdxData[offset]);
611 lhsIdxNode->setValueOn(offset,
612 std::min(lhsIdxData[offset], rhsIdxData[offset]));
617 delete mRhsDistNodes[n];
618 delete mRhsIdxNodes[n];
625 Int32TreeType *
const mIdxTree;
627 LeafNodeType **
const mRhsDistNodes;
628 Int32LeafNodeType **
const mRhsIdxNodes;
635 template<
typename TreeType>
636 struct StashOriginAndStoreOffset
640 StashOriginAndStoreOffset(std::vector<LeafNodeType*>& nodes, Coord* coordinates)
641 : mNodes(nodes.empty() ?
nullptr : &nodes[0]), mCoordinates(coordinates)
645 void operator()(
const tbb::blocked_range<size_t>& range)
const {
646 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
647 Coord& origin =
const_cast<Coord&
>(mNodes[n]->origin());
648 mCoordinates[n] = origin;
649 origin[0] =
static_cast<int>(n);
653 LeafNodeType **
const mNodes;
654 Coord *
const mCoordinates;
658 template<
typename TreeType>
663 RestoreOrigin(std::vector<LeafNodeType*>& nodes,
const Coord* coordinates)
664 : mNodes(nodes.empty() ?
nullptr : &nodes[0]), mCoordinates(coordinates)
668 void operator()(
const tbb::blocked_range<size_t>& range)
const {
669 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
670 Coord& origin =
const_cast<Coord&
>(mNodes[n]->origin());
671 origin[0] = mCoordinates[n][0];
675 LeafNodeType **
const mNodes;
676 Coord
const *
const mCoordinates;
680 template<
typename TreeType>
681 class ComputeNodeConnectivity
686 ComputeNodeConnectivity(
const TreeType& tree,
const Coord* coordinates,
687 size_t* offsets,
size_t numNodes,
const CoordBBox& bbox)
689 , mCoordinates(coordinates)
691 , mNumNodes(numNodes)
696 ComputeNodeConnectivity(
const ComputeNodeConnectivity&) =
default;
699 ComputeNodeConnectivity& operator=(
const ComputeNodeConnectivity&) =
delete;
701 void operator()(
const tbb::blocked_range<size_t>& range)
const {
703 size_t* offsetsNextX = mOffsets;
704 size_t* offsetsPrevX = mOffsets + mNumNodes;
705 size_t* offsetsNextY = mOffsets + mNumNodes * 2;
706 size_t* offsetsPrevY = mOffsets + mNumNodes * 3;
707 size_t* offsetsNextZ = mOffsets + mNumNodes * 4;
708 size_t* offsetsPrevZ = mOffsets + mNumNodes * 5;
712 const Int32 DIM =
static_cast<Int32>(LeafNodeType::DIM);
714 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
715 const Coord& origin = mCoordinates[n];
716 offsetsNextX[n] = findNeighbourNode(acc, origin, Coord(DIM, 0, 0));
717 offsetsPrevX[n] = findNeighbourNode(acc, origin, Coord(-DIM, 0, 0));
718 offsetsNextY[n] = findNeighbourNode(acc, origin, Coord(0, DIM, 0));
719 offsetsPrevY[n] = findNeighbourNode(acc, origin, Coord(0, -DIM, 0));
720 offsetsNextZ[n] = findNeighbourNode(acc, origin, Coord(0, 0, DIM));
721 offsetsPrevZ[n] = findNeighbourNode(acc, origin, Coord(0, 0, -DIM));
726 const Coord& start,
const Coord& step)
const 728 Coord ijk = start + step;
731 while (bbox.isInside(ijk)) {
733 if (node)
return static_cast<size_t>(node->origin()[0]);
743 Coord
const *
const mCoordinates;
744 size_t *
const mOffsets;
746 const size_t mNumNodes;
751 template<
typename TreeType>
752 struct LeafNodeConnectivityTable
758 LeafNodeConnectivityTable(
TreeType& tree)
763 if (mLeafNodes.empty())
return;
768 const tbb::blocked_range<size_t> range(0, mLeafNodes.size());
772 std::unique_ptr<Coord[]> coordinates{
new Coord[mLeafNodes.size()]};
773 tbb::parallel_for(range,
774 StashOriginAndStoreOffset<TreeType>(mLeafNodes, coordinates.get()));
777 mOffsets.reset(
new size_t[mLeafNodes.size() * 6]);
780 tbb::parallel_for(range, ComputeNodeConnectivity<TreeType>(
781 tree, coordinates.get(), mOffsets.get(), mLeafNodes.size(), bbox));
784 tbb::parallel_for(range, RestoreOrigin<TreeType>(mLeafNodes, coordinates.get()));
787 size_t size()
const {
return mLeafNodes.size(); }
789 std::vector<LeafNodeType*>& nodes() {
return mLeafNodes; }
790 const std::vector<LeafNodeType*>& nodes()
const {
return mLeafNodes; }
793 const size_t* offsetsNextX()
const {
return mOffsets.get(); }
794 const size_t* offsetsPrevX()
const {
return mOffsets.get() + mLeafNodes.size(); }
796 const size_t* offsetsNextY()
const {
return mOffsets.get() + mLeafNodes.size() * 2; }
797 const size_t* offsetsPrevY()
const {
return mOffsets.get() + mLeafNodes.size() * 3; }
799 const size_t* offsetsNextZ()
const {
return mOffsets.get() + mLeafNodes.size() * 4; }
800 const size_t* offsetsPrevZ()
const {
return mOffsets.get() + mLeafNodes.size() * 5; }
803 std::vector<LeafNodeType*> mLeafNodes;
804 std::unique_ptr<size_t[]> mOffsets;
808 template<
typename TreeType>
809 class SweepExteriorSign
817 using ConnectivityTable = LeafNodeConnectivityTable<TreeType>;
819 SweepExteriorSign(
Axis axis,
const std::vector<size_t>& startNodeIndices,
820 ConnectivityTable& connectivity)
821 : mStartNodeIndices(startNodeIndices.empty() ?
nullptr : &startNodeIndices[0])
822 , mConnectivity(&connectivity)
827 void operator()(
const tbb::blocked_range<size_t>& range)
const {
829 constexpr
Int32 DIM =
static_cast<Int32>(LeafNodeType::DIM);
831 std::vector<LeafNodeType*>& nodes = mConnectivity->nodes();
834 size_t idxA = 0, idxB = 1;
837 const size_t* nextOffsets = mConnectivity->offsetsNextZ();
838 const size_t* prevOffsets = mConnectivity->offsetsPrevZ();
846 nextOffsets = mConnectivity->offsetsNextY();
847 prevOffsets = mConnectivity->offsetsPrevY();
849 }
else if (mAxis ==
X_AXIS) {
855 nextOffsets = mConnectivity->offsetsNextX();
856 prevOffsets = mConnectivity->offsetsPrevX();
861 Int32& a = ijk[idxA];
862 Int32& b = ijk[idxB];
864 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
866 size_t startOffset = mStartNodeIndices[n];
867 size_t lastOffset = startOffset;
871 for (a = 0; a < DIM; ++a) {
872 for (b = 0; b < DIM; ++b) {
874 pos =
static_cast<Int32>(LeafNodeType::coordToOffset(ijk));
875 size_t offset = startOffset;
878 while ( offset != ConnectivityTable::INVALID_OFFSET &&
879 traceVoxelLine(*nodes[offset], pos, step) ) {
882 offset = nextOffsets[offset];
887 while (offset != ConnectivityTable::INVALID_OFFSET) {
889 offset = nextOffsets[offset];
894 pos += step * (DIM - 1);
895 while ( offset != ConnectivityTable::INVALID_OFFSET &&
896 traceVoxelLine(*nodes[offset], pos, -step)) {
897 offset = prevOffsets[offset];
905 bool traceVoxelLine(LeafNodeType& node,
Int32 pos,
const Int32 step)
const {
907 ValueType* data = node.buffer().data();
909 bool isOutside =
true;
911 for (
Index i = 0; i < LeafNodeType::DIM; ++i) {
914 ValueType& dist = data[pos];
916 if (dist < ValueType(0.0)) {
920 if (!(dist > ValueType(0.75))) isOutside =
false;
922 if (isOutside) dist = ValueType(-dist);
933 size_t const *
const mStartNodeIndices;
934 ConnectivityTable *
const mConnectivity;
940 template<
typename LeafNodeType>
942 seedFill(LeafNodeType& node)
944 using ValueType =
typename LeafNodeType::ValueType;
945 using Queue = std::deque<Index>;
948 ValueType* data = node.buffer().data();
952 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
953 if (data[pos] < 0.0) seedPoints.push_back(pos);
956 if (seedPoints.empty())
return;
959 for (Queue::iterator it = seedPoints.begin(); it != seedPoints.end(); ++it) {
960 ValueType& dist = data[*it];
967 Index pos(0), nextPos(0);
969 while (!seedPoints.empty()) {
971 pos = seedPoints.back();
972 seedPoints.pop_back();
974 ValueType& dist = data[pos];
976 if (!(dist < ValueType(0.0))) {
980 ijk = LeafNodeType::offsetToLocalCoord(pos);
983 nextPos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
984 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
987 if (ijk[0] != (LeafNodeType::DIM - 1)) {
988 nextPos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
989 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
993 nextPos = pos - LeafNodeType::DIM;
994 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
997 if (ijk[1] != (LeafNodeType::DIM - 1)) {
998 nextPos = pos + LeafNodeType::DIM;
999 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1004 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1007 if (ijk[2] != (LeafNodeType::DIM - 1)) {
1009 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1016 template<
typename LeafNodeType>
1018 scanFill(LeafNodeType& node)
1020 bool updatedNode =
false;
1022 using ValueType =
typename LeafNodeType::ValueType;
1023 ValueType* data = node.buffer().data();
1027 bool updatedSign =
true;
1028 while (updatedSign) {
1030 updatedSign =
false;
1032 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
1034 ValueType& dist = data[pos];
1036 if (!(dist < ValueType(0.0)) && dist > ValueType(0.75)) {
1038 ijk = LeafNodeType::offsetToLocalCoord(pos);
1041 if (ijk[2] != 0 && data[pos - 1] < ValueType(0.0)) {
1043 dist = ValueType(-dist);
1046 }
else if (ijk[2] != (LeafNodeType::DIM - 1) && data[pos + 1] < ValueType(0.0)) {
1048 dist = ValueType(-dist);
1051 }
else if (ijk[1] != 0 && data[pos - LeafNodeType::DIM] < ValueType(0.0)) {
1053 dist = ValueType(-dist);
1056 }
else if (ijk[1] != (LeafNodeType::DIM - 1)
1057 && data[pos + LeafNodeType::DIM] < ValueType(0.0))
1060 dist = ValueType(-dist);
1063 }
else if (ijk[0] != 0
1064 && data[pos - LeafNodeType::DIM * LeafNodeType::DIM] < ValueType(0.0))
1067 dist = ValueType(-dist);
1070 }
else if (ijk[0] != (LeafNodeType::DIM - 1)
1071 && data[pos + LeafNodeType::DIM * LeafNodeType::DIM] < ValueType(0.0))
1074 dist = ValueType(-dist);
1079 updatedNode |= updatedSign;
1086 template<
typename TreeType>
1087 class SeedFillExteriorSign
1093 SeedFillExteriorSign(std::vector<LeafNodeType*>& nodes,
const bool* changedNodeMask)
1094 : mNodes(nodes.empty() ?
nullptr : &nodes[0])
1095 , mChangedNodeMask(changedNodeMask)
1099 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1100 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1101 if (mChangedNodeMask[n]) {
1107 scanFill(*mNodes[n]);
1112 LeafNodeType **
const mNodes;
1113 const bool *
const mChangedNodeMask;
1117 template<
typename ValueType>
1120 FillArray(ValueType* array,
const ValueType v) : mArray(array), mValue(v) { }
1122 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1123 const ValueType v = mValue;
1124 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1129 ValueType *
const mArray;
1130 const ValueType mValue;
1134 template<
typename ValueType>
1136 fillArray(ValueType* array,
const ValueType val,
const size_t length)
1138 const auto grainSize = std::max<size_t>(
1139 length / tbb::this_task_arena::max_concurrency(), 1024);
1140 const tbb::blocked_range<size_t> range(0, length, grainSize);
1141 tbb::parallel_for(range, FillArray<ValueType>(array, val), tbb::simple_partitioner());
1145 template<
typename TreeType>
1152 SyncVoxelMask(std::vector<LeafNodeType*>& nodes,
1153 const bool* changedNodeMask,
bool* changedVoxelMask)
1154 : mNodes(nodes.empty() ?
nullptr : &nodes[0])
1155 , mChangedNodeMask(changedNodeMask)
1156 , mChangedVoxelMask(changedVoxelMask)
1160 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1161 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1163 if (mChangedNodeMask[n]) {
1164 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1166 ValueType* data = mNodes[n]->buffer().data();
1168 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
1170 data[pos] = ValueType(-data[pos]);
1178 LeafNodeType **
const mNodes;
1179 bool const *
const mChangedNodeMask;
1180 bool *
const mChangedVoxelMask;
1184 template<
typename TreeType>
1190 using ConnectivityTable = LeafNodeConnectivityTable<TreeType>;
1192 SeedPoints(ConnectivityTable& connectivity,
1193 bool* changedNodeMask,
bool* nodeMask,
bool* changedVoxelMask)
1194 : mConnectivity(&connectivity)
1195 , mChangedNodeMask(changedNodeMask)
1196 , mNodeMask(nodeMask)
1197 , mChangedVoxelMask(changedVoxelMask)
1201 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1203 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1204 bool changedValue =
false;
1206 changedValue |= processZ(n,
true);
1207 changedValue |= processZ(n,
false);
1209 changedValue |= processY(n,
true);
1210 changedValue |= processY(n,
false);
1212 changedValue |= processX(n,
true);
1213 changedValue |= processX(n,
false);
1215 mNodeMask[n] = changedValue;
1220 bool processZ(
const size_t n,
bool firstFace)
const 1222 const size_t offset =
1223 firstFace ? mConnectivity->offsetsPrevZ()[n] : mConnectivity->offsetsNextZ()[n];
1224 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1226 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1228 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1229 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1231 const Index lastOffset = LeafNodeType::DIM - 1;
1232 const Index lhsOffset =
1233 firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1235 Index tmpPos(0), pos(0);
1236 bool changedValue =
false;
1238 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
1239 tmpPos = x << (2 * LeafNodeType::LOG2DIM);
1240 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
1241 pos = tmpPos + (y << LeafNodeType::LOG2DIM);
1243 if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1244 if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1245 changedValue =
true;
1246 mask[pos + lhsOffset] =
true;
1252 return changedValue;
1258 bool processY(
const size_t n,
bool firstFace)
const 1260 const size_t offset =
1261 firstFace ? mConnectivity->offsetsPrevY()[n] : mConnectivity->offsetsNextY()[n];
1262 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1264 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1266 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1267 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1269 const Index lastOffset = LeafNodeType::DIM * (LeafNodeType::DIM - 1);
1270 const Index lhsOffset =
1271 firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1273 Index tmpPos(0), pos(0);
1274 bool changedValue =
false;
1276 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
1277 tmpPos = x << (2 * LeafNodeType::LOG2DIM);
1278 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
1281 if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1282 if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1283 changedValue =
true;
1284 mask[pos + lhsOffset] =
true;
1290 return changedValue;
1296 bool processX(
const size_t n,
bool firstFace)
const 1298 const size_t offset =
1299 firstFace ? mConnectivity->offsetsPrevX()[n] : mConnectivity->offsetsNextX()[n];
1300 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1302 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1304 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1305 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1307 const Index lastOffset = LeafNodeType::DIM * LeafNodeType::DIM * (LeafNodeType::DIM-1);
1308 const Index lhsOffset =
1309 firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1311 Index tmpPos(0), pos(0);
1312 bool changedValue =
false;
1314 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
1315 tmpPos = y << LeafNodeType::LOG2DIM;
1316 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
1319 if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1320 if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1321 changedValue =
true;
1322 mask[pos + lhsOffset] =
true;
1328 return changedValue;
1334 ConnectivityTable *
const mConnectivity;
1335 bool *
const mChangedNodeMask;
1336 bool *
const mNodeMask;
1337 bool *
const mChangedVoxelMask;
1343 template<
typename TreeType,
typename MeshDataAdapter>
1344 struct ComputeIntersectingVoxelSign
1349 using Int32LeafNodeType =
typename Int32TreeType::LeafNodeType;
1352 using MaskArray = std::unique_ptr<bool[]>;
1353 using LocalData = std::pair<PointArray, MaskArray>;
1354 using LocalDataTable = tbb::enumerable_thread_specific<LocalData>;
1356 ComputeIntersectingVoxelSign(
1357 std::vector<LeafNodeType*>& distNodes,
1359 const Int32TreeType& indexTree,
1361 : mDistNodes(distNodes.empty() ?
nullptr : &distNodes[0])
1362 , mDistTree(&distTree)
1363 , mIndexTree(&indexTree)
1365 , mLocalDataTable(
new LocalDataTable())
1370 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1377 Index xPos(0), yPos(0);
1378 Coord ijk, nijk, nodeMin, nodeMax;
1379 Vec3d cp, xyz, nxyz, dir1, dir2;
1381 LocalData& localData = mLocalDataTable->local();
1384 if (!points) points.reset(
new Vec3d[LeafNodeType::SIZE * 2]);
1386 MaskArray& mask = localData.second;
1387 if (!mask) mask.reset(
new bool[LeafNodeType::SIZE]);
1390 typename LeafNodeType::ValueOnCIter it;
1392 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1394 LeafNodeType& node = *mDistNodes[n];
1395 ValueType* data = node.buffer().data();
1397 const Int32LeafNodeType* idxNode = idxAcc.
probeConstLeaf(node.origin());
1398 const Int32* idxData = idxNode->buffer().data();
1400 nodeMin = node.origin();
1401 nodeMax = nodeMin.offsetBy(LeafNodeType::DIM - 1);
1404 memset(mask.get(), 0,
sizeof(bool) * LeafNodeType::SIZE);
1406 for (it = node.cbeginValueOn(); it; ++it) {
1407 Index pos = it.pos();
1409 ValueType& dist = data[pos];
1410 if (dist < 0.0 || dist > 0.75)
continue;
1412 ijk = node.offsetToGlobalCoord(pos);
1414 xyz[0] = double(ijk[0]);
1415 xyz[1] = double(ijk[1]);
1416 xyz[2] = double(ijk[2]);
1422 bool flipSign =
false;
1424 for (nijk[0] = bbox.min()[0]; nijk[0] <= bbox.max()[0] && !flipSign; ++nijk[0]) {
1425 xPos = (nijk[0] & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
1426 for (nijk[1]=bbox.min()[1]; nijk[1] <= bbox.max()[1] && !flipSign; ++nijk[1]) {
1427 yPos = xPos + ((nijk[1] & (LeafNodeType::DIM-1u)) << LeafNodeType::LOG2DIM);
1428 for (nijk[2] = bbox.min()[2]; nijk[2] <= bbox.max()[2]; ++nijk[2]) {
1429 pos = yPos + (nijk[2] & (LeafNodeType::DIM - 1u));
1431 const Int32& polyIdx = idxData[pos];
1436 const Index pointIndex = pos * 2;
1442 nxyz[0] = double(nijk[0]);
1443 nxyz[1] = double(nijk[1]);
1444 nxyz[2] = double(nijk[2]);
1446 Vec3d& point = points[pointIndex];
1448 point = closestPoint(nxyz, polyIdx);
1450 Vec3d& direction = points[pointIndex + 1];
1451 direction = nxyz - point;
1452 direction.normalize();
1455 dir1 = xyz - points[pointIndex];
1458 if (points[pointIndex + 1].dot(dir1) > 0.0) {
1469 for (
Int32 m = 0; m < 26; ++m) {
1472 if (!bbox.isInside(nijk) && distAcc.
probeValue(nijk, nval) && nval<-0.75) {
1473 nxyz[0] = double(nijk[0]);
1474 nxyz[1] = double(nijk[1]);
1475 nxyz[2] = double(nijk[2]);
1477 cp = closestPoint(nxyz, idxAcc.
getValue(nijk));
1485 if (dir2.dot(dir1) > 0.0) {
1499 Vec3d closestPoint(
const Vec3d& center,
Int32 polyIdx)
const 1501 Vec3d a, b, c, cp, uvw;
1503 const size_t polygon = size_t(polyIdx);
1504 mMesh->getIndexSpacePoint(polygon, 0, a);
1505 mMesh->getIndexSpacePoint(polygon, 1, b);
1506 mMesh->getIndexSpacePoint(polygon, 2, c);
1510 if (4 == mMesh->vertexCount(polygon)) {
1512 mMesh->getIndexSpacePoint(polygon, 3, b);
1516 if ((center - c).lengthSqr() < (center - cp).lengthSqr()) {
1525 LeafNodeType **
const mDistNodes;
1527 Int32TreeType
const *
const mIndexTree;
1537 template<
typename LeafNodeType>
1539 maskNodeInternalNeighbours(
const Index pos,
bool (&mask)[26])
1541 using NodeT = LeafNodeType;
1543 const Coord ijk = NodeT::offsetToLocalCoord(pos);
1547 mask[0] = ijk[0] != (NodeT::DIM - 1);
1549 mask[1] = ijk[0] != 0;
1551 mask[2] = ijk[1] != (NodeT::DIM - 1);
1553 mask[3] = ijk[1] != 0;
1555 mask[4] = ijk[2] != (NodeT::DIM - 1);
1557 mask[5] = ijk[2] != 0;
1561 mask[6] = mask[0] && mask[5];
1563 mask[7] = mask[1] && mask[5];
1565 mask[8] = mask[0] && mask[4];
1567 mask[9] = mask[1] && mask[4];
1569 mask[10] = mask[0] && mask[2];
1571 mask[11] = mask[1] && mask[2];
1573 mask[12] = mask[0] && mask[3];
1575 mask[13] = mask[1] && mask[3];
1577 mask[14] = mask[3] && mask[4];
1579 mask[15] = mask[3] && mask[5];
1581 mask[16] = mask[2] && mask[4];
1583 mask[17] = mask[2] && mask[5];
1587 mask[18] = mask[1] && mask[3] && mask[5];
1589 mask[19] = mask[1] && mask[3] && mask[4];
1591 mask[20] = mask[0] && mask[3] && mask[4];
1593 mask[21] = mask[0] && mask[3] && mask[5];
1595 mask[22] = mask[1] && mask[2] && mask[5];
1597 mask[23] = mask[1] && mask[2] && mask[4];
1599 mask[24] = mask[0] && mask[2] && mask[4];
1601 mask[25] = mask[0] && mask[2] && mask[5];
1605 template<
typename Compare,
typename LeafNodeType>
1607 checkNeighbours(
const Index pos,
const typename LeafNodeType::ValueType * data,
bool (&mask)[26])
1609 using NodeT = LeafNodeType;
1612 if (mask[5] && Compare::check(data[pos - 1]))
return true;
1614 if (mask[4] && Compare::check(data[pos + 1]))
return true;
1616 if (mask[3] && Compare::check(data[pos - NodeT::DIM]))
return true;
1618 if (mask[2] && Compare::check(data[pos + NodeT::DIM]))
return true;
1620 if (mask[1] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM]))
return true;
1622 if (mask[0] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM]))
return true;
1624 if (mask[6] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM]))
return true;
1626 if (mask[7] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - 1]))
return true;
1628 if (mask[8] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + 1]))
return true;
1630 if (mask[9] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + 1]))
return true;
1632 if (mask[10] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM]))
return true;
1634 if (mask[11] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM]))
return true;
1636 if (mask[12] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM]))
return true;
1638 if (mask[13] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM]))
return true;
1640 if (mask[14] && Compare::check(data[pos - NodeT::DIM + 1]))
return true;
1642 if (mask[15] && Compare::check(data[pos - NodeT::DIM - 1]))
return true;
1644 if (mask[16] && Compare::check(data[pos + NodeT::DIM + 1]))
return true;
1646 if (mask[17] && Compare::check(data[pos + NodeT::DIM - 1]))
return true;
1648 if (mask[18] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM - 1]))
return true;
1650 if (mask[19] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM + 1]))
return true;
1652 if (mask[20] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM + 1]))
return true;
1654 if (mask[21] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM - 1]))
return true;
1656 if (mask[22] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM - 1]))
return true;
1658 if (mask[23] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM + 1]))
return true;
1660 if (mask[24] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM + 1]))
return true;
1662 if (mask[25] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM - 1]))
return true;
1668 template<
typename Compare,
typename AccessorType>
1670 checkNeighbours(
const Coord& ijk, AccessorType& acc,
bool (&mask)[26])
1672 for (
Int32 m = 0; m < 26; ++m) {
1682 template<
typename TreeType>
1683 struct ValidateIntersectingVoxels
1688 struct IsNegative {
static bool check(
const ValueType v) {
return v < ValueType(0.0); } };
1690 ValidateIntersectingVoxels(
TreeType& tree, std::vector<LeafNodeType*>& nodes)
1692 , mNodes(nodes.empty() ?
nullptr : &nodes[0])
1696 void operator()(
const tbb::blocked_range<size_t>& range)
const 1699 bool neighbourMask[26];
1701 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1703 LeafNodeType& node = *mNodes[n];
1704 ValueType* data = node.buffer().data();
1706 typename LeafNodeType::ValueOnCIter it;
1707 for (it = node.cbeginValueOn(); it; ++it) {
1709 const Index pos = it.pos();
1711 ValueType& dist = data[pos];
1712 if (dist < 0.0 || dist > 0.75)
continue;
1715 maskNodeInternalNeighbours<LeafNodeType>(pos, neighbourMask);
1717 const bool hasNegativeNeighbour =
1718 checkNeighbours<IsNegative, LeafNodeType>(pos, data, neighbourMask) ||
1719 checkNeighbours<IsNegative>(node.offsetToGlobalCoord(pos), acc, neighbourMask);
1721 if (!hasNegativeNeighbour) {
1723 dist = ValueType(0.75) + Tolerance<ValueType>::epsilon();
1730 LeafNodeType **
const mNodes;
1734 template<
typename TreeType>
1735 struct RemoveSelfIntersectingSurface
1741 struct Comp {
static bool check(
const ValueType v) {
return !(v > ValueType(0.75)); } };
1743 RemoveSelfIntersectingSurface(std::vector<LeafNodeType*>& nodes,
1744 TreeType& distTree, Int32TreeType& indexTree)
1745 : mNodes(nodes.empty() ?
nullptr : &nodes[0])
1746 , mDistTree(&distTree)
1747 , mIndexTree(&indexTree)
1751 void operator()(
const tbb::blocked_range<size_t>& range)
const 1755 bool neighbourMask[26];
1757 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1759 LeafNodeType& distNode = *mNodes[n];
1760 ValueType* data = distNode.buffer().data();
1762 typename Int32TreeType::LeafNodeType* idxNode =
1765 typename LeafNodeType::ValueOnCIter it;
1766 for (it = distNode.cbeginValueOn(); it; ++it) {
1768 const Index pos = it.pos();
1770 if (!(data[pos] > 0.75))
continue;
1773 maskNodeInternalNeighbours<LeafNodeType>(pos, neighbourMask);
1775 const bool hasBoundaryNeighbour =
1776 checkNeighbours<Comp, LeafNodeType>(pos, data, neighbourMask) ||
1777 checkNeighbours<Comp>(distNode.offsetToGlobalCoord(pos),distAcc,neighbourMask);
1779 if (!hasBoundaryNeighbour) {
1780 distNode.setValueOff(pos);
1781 idxNode->setValueOff(pos);
1787 LeafNodeType * *
const mNodes;
1789 Int32TreeType *
const mIndexTree;
1796 template<
typename NodeType>
1797 struct ReleaseChildNodes
1799 ReleaseChildNodes(NodeType ** nodes) : mNodes(nodes) {}
1801 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1803 using NodeMaskType =
typename NodeType::NodeMaskType;
1805 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1806 const_cast<NodeMaskType&
>(mNodes[n]->getChildMask()).setOff();
1810 NodeType **
const mNodes;
1814 template<
typename TreeType>
1819 using NodeChainType =
typename RootNodeType::NodeChainType;
1820 using InternalNodeType =
typename NodeChainType::template Get<1>;
1822 std::vector<InternalNodeType*> nodes;
1825 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
1826 ReleaseChildNodes<InternalNodeType>(nodes.empty() ?
nullptr : &nodes[0]));
1830 template<
typename TreeType>
1831 struct StealUniqueLeafNodes
1836 std::vector<LeafNodeType*>& overlappingNodes)
1837 : mLhsTree(&lhsTree)
1838 , mRhsTree(&rhsTree)
1839 , mNodes(&overlappingNodes)
1843 void operator()()
const {
1845 std::vector<LeafNodeType*> rhsLeafNodes;
1847 rhsLeafNodes.reserve(mRhsTree->leafCount());
1850 mRhsTree->stealNodes(rhsLeafNodes);
1854 for (
size_t n = 0, N = rhsLeafNodes.size(); n < N; ++n) {
1855 if (!acc.
probeLeaf(rhsLeafNodes[n]->origin())) {
1858 mNodes->push_back(rhsLeafNodes[n]);
1866 std::vector<LeafNodeType*> *
const mNodes;
1870 template<
typename DistTreeType,
typename IndexTreeType>
1872 combineData(DistTreeType& lhsDist, IndexTreeType& lhsIdx,
1873 DistTreeType& rhsDist, IndexTreeType& rhsIdx)
1875 using DistLeafNodeType =
typename DistTreeType::LeafNodeType;
1876 using IndexLeafNodeType =
typename IndexTreeType::LeafNodeType;
1878 std::vector<DistLeafNodeType*> overlappingDistNodes;
1879 std::vector<IndexLeafNodeType*> overlappingIdxNodes;
1882 tbb::task_group tasks;
1883 tasks.run(StealUniqueLeafNodes<DistTreeType>(lhsDist, rhsDist, overlappingDistNodes));
1884 tasks.run(StealUniqueLeafNodes<IndexTreeType>(lhsIdx, rhsIdx, overlappingIdxNodes));
1888 if (!overlappingDistNodes.empty() && !overlappingIdxNodes.empty()) {
1889 tbb::parallel_for(tbb::blocked_range<size_t>(0, overlappingDistNodes.size()),
1890 CombineLeafNodes<DistTreeType>(lhsDist, lhsIdx,
1891 &overlappingDistNodes[0], &overlappingIdxNodes[0]));
1901 template<
typename TreeType>
1902 struct VoxelizationData {
1904 using Ptr = std::unique_ptr<VoxelizationData>;
1908 using UCharTreeType =
typename TreeType::template ValueConverter<unsigned char>::Type;
1919 , indexAcc(indexTree)
1920 , primIdTree(MaxPrimId)
1921 , primIdAcc(primIdTree)
1927 FloatTreeAcc distAcc;
1929 Int32TreeType indexTree;
1930 Int32TreeAcc indexAcc;
1932 UCharTreeType primIdTree;
1933 UCharTreeAcc primIdAcc;
1935 unsigned char getNewPrimId() {
1951 if (mPrimCount == MaxPrimId || primIdTree.leafCount() > 1000) {
1953 primIdTree.
root().clear();
1954 primIdTree.clearAllAccessors();
1955 assert(mPrimCount == 0);
1958 return mPrimCount++;
1963 enum { MaxPrimId = 100 };
1965 unsigned char mPrimCount;
1969 template<
typename TreeType,
typename MeshDataAdapter,
typename Interrupter = util::NullInterrupter>
1970 class VoxelizePolygons
1974 using VoxelizationDataType = VoxelizationData<TreeType>;
1975 using DataTable = tbb::enumerable_thread_specific<typename VoxelizationDataType::Ptr>;
1977 VoxelizePolygons(DataTable& dataTable,
1979 Interrupter* interrupter =
nullptr)
1980 : mDataTable(&dataTable)
1982 , mInterrupter(interrupter)
1986 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1988 typename VoxelizationDataType::Ptr& dataPtr = mDataTable->local();
1989 if (!dataPtr) dataPtr.reset(
new VoxelizationDataType());
1993 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1996 thread::cancelGroupExecution();
2000 const size_t numVerts = mMesh->vertexCount(n);
2003 if (numVerts == 3 || numVerts == 4) {
2005 prim.index =
Int32(n);
2007 mMesh->getIndexSpacePoint(n, 0, prim.a);
2008 mMesh->getIndexSpacePoint(n, 1, prim.b);
2009 mMesh->getIndexSpacePoint(n, 2, prim.c);
2011 evalTriangle(prim, *dataPtr);
2013 if (numVerts == 4) {
2014 mMesh->getIndexSpacePoint(n, 3, prim.b);
2015 evalTriangle(prim, *dataPtr);
2023 bool wasInterrupted()
const {
return mInterrupter && mInterrupter->wasInterrupted(); }
2025 struct Triangle { Vec3d a, b, c;
Int32 index; };
2029 enum { POLYGON_LIMIT = 1000 };
2031 SubTask(
const Triangle& prim, DataTable& dataTable,
2032 int subdivisionCount,
size_t polygonCount,
2033 Interrupter* interrupter =
nullptr)
2034 : mLocalDataTable(&dataTable)
2036 , mSubdivisionCount(subdivisionCount)
2037 , mPolygonCount(polygonCount)
2038 , mInterrupter(interrupter)
2042 void operator()()
const 2044 if (mSubdivisionCount <= 0 || mPolygonCount >= POLYGON_LIMIT) {
2046 typename VoxelizationDataType::Ptr& dataPtr = mLocalDataTable->local();
2047 if (!dataPtr) dataPtr.reset(
new VoxelizationDataType());
2049 voxelizeTriangle(mPrim, *dataPtr, mInterrupter);
2051 }
else if (!(mInterrupter && mInterrupter->wasInterrupted())) {
2052 spawnTasks(mPrim, *mLocalDataTable, mSubdivisionCount, mPolygonCount, mInterrupter);
2056 DataTable *
const mLocalDataTable;
2057 Triangle
const mPrim;
2058 int const mSubdivisionCount;
2059 size_t const mPolygonCount;
2060 Interrupter *
const mInterrupter;
2063 inline static int evalSubdivisionCount(
const Triangle& prim)
2065 const double ax = prim.a[0], bx = prim.b[0], cx = prim.c[0];
2068 const double ay = prim.a[1], by = prim.b[1], cy = prim.c[1];
2071 const double az = prim.a[2], bz = prim.b[2], cz = prim.c[2];
2074 return int(
std::max(dx,
std::max(dy, dz)) /
double(TreeType::LeafNodeType::DIM * 2));
2077 void evalTriangle(
const Triangle& prim, VoxelizationDataType& data)
const 2079 const size_t polygonCount = mMesh->polygonCount();
2080 const int subdivisionCount =
2081 polygonCount < SubTask::POLYGON_LIMIT ? evalSubdivisionCount(prim) : 0;
2083 if (subdivisionCount <= 0) {
2084 voxelizeTriangle(prim, data, mInterrupter);
2086 spawnTasks(prim, *mDataTable, subdivisionCount, polygonCount, mInterrupter);
2090 static void spawnTasks(
2091 const Triangle& mainPrim,
2092 DataTable& dataTable,
2093 int subdivisionCount,
2094 size_t polygonCount,
2095 Interrupter*
const interrupter)
2097 subdivisionCount -= 1;
2100 tbb::task_group tasks;
2102 const Vec3d ac = (mainPrim.a + mainPrim.c) * 0.5;
2103 const Vec3d bc = (mainPrim.b + mainPrim.c) * 0.5;
2104 const Vec3d ab = (mainPrim.a + mainPrim.b) * 0.5;
2107 prim.index = mainPrim.index;
2109 prim.a = mainPrim.a;
2112 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount, interrupter));
2117 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount, interrupter));
2120 prim.b = mainPrim.b;
2122 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount, interrupter));
2126 prim.c = mainPrim.c;
2127 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount, interrupter));
2132 static void voxelizeTriangle(
const Triangle& prim, VoxelizationDataType& data, Interrupter*
const interrupter)
2134 std::deque<Coord> coordList;
2137 ijk = Coord::floor(prim.a);
2138 coordList.push_back(ijk);
2143 updateDistance(ijk, prim, data);
2145 unsigned char primId = data.getNewPrimId();
2146 data.primIdAcc.setValueOnly(ijk, primId);
2148 while (!coordList.empty()) {
2149 if (interrupter && interrupter->wasInterrupted()) {
2150 thread::cancelGroupExecution();
2153 for (
Int32 pass = 0; pass < 1048576 && !coordList.empty(); ++pass) {
2154 ijk = coordList.back();
2155 coordList.pop_back();
2157 for (
Int32 i = 0; i < 26; ++i) {
2159 if (primId != data.primIdAcc.getValue(nijk)) {
2160 data.primIdAcc.setValueOnly(nijk, primId);
2161 if(updateDistance(nijk, prim, data)) coordList.push_back(nijk);
2168 static bool updateDistance(
const Coord& ijk,
const Triangle& prim, VoxelizationDataType& data)
2170 Vec3d uvw, voxelCenter(ijk[0], ijk[1], ijk[2]);
2174 const ValueType dist = ValueType((voxelCenter -
2179 if (std::isnan(dist))
2182 const ValueType oldDist = data.distAcc.getValue(ijk);
2184 if (dist < oldDist) {
2185 data.distAcc.setValue(ijk, dist);
2186 data.indexAcc.setValue(ijk, prim.index);
2190 data.indexAcc.setValueOnly(ijk,
std::min(prim.index, data.indexAcc.getValue(ijk)));
2193 return !(dist > 0.75);
2196 DataTable *
const mDataTable;
2198 Interrupter *
const mInterrupter;
2205 template<
typename TreeType>
2206 struct DiffLeafNodeMask
2211 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2212 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
2214 DiffLeafNodeMask(
const TreeType& rhsTree,
2215 std::vector<BoolLeafNodeType*>& lhsNodes)
2216 : mRhsTree(&rhsTree), mLhsNodes(lhsNodes.empty() ?
nullptr : &lhsNodes[0])
2220 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2224 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2226 BoolLeafNodeType* lhsNode = mLhsNodes[n];
2227 const LeafNodeType* rhsNode = acc.
probeConstLeaf(lhsNode->origin());
2229 if (rhsNode) lhsNode->topologyDifference(*rhsNode,
false);
2235 BoolLeafNodeType **
const mLhsNodes;
2239 template<
typename LeafNodeTypeA,
typename LeafNodeTypeB>
2240 struct UnionValueMasks
2242 UnionValueMasks(std::vector<LeafNodeTypeA*>& nodesA, std::vector<LeafNodeTypeB*>& nodesB)
2243 : mNodesA(nodesA.empty() ?
nullptr : &nodesA[0])
2244 , mNodesB(nodesB.empty() ?
nullptr : &nodesB[0])
2248 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2249 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2250 mNodesA[n]->topologyUnion(*mNodesB[n]);
2255 LeafNodeTypeA **
const mNodesA;
2256 LeafNodeTypeB **
const mNodesB;
2260 template<
typename TreeType>
2261 struct ConstructVoxelMask
2265 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2266 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
2268 ConstructVoxelMask(BoolTreeType& maskTree,
const TreeType& tree,
2269 std::vector<LeafNodeType*>& nodes)
2271 , mNodes(nodes.empty() ?
nullptr : &nodes[0])
2272 , mLocalMaskTree(
false)
2273 , mMaskTree(&maskTree)
2277 ConstructVoxelMask(ConstructVoxelMask& rhs, tbb::split)
2279 , mNodes(rhs.mNodes)
2280 , mLocalMaskTree(
false)
2281 , mMaskTree(&mLocalMaskTree)
2285 void operator()(
const tbb::blocked_range<size_t>& range)
2287 using Iterator =
typename LeafNodeType::ValueOnCIter;
2292 Coord ijk, nijk, localCorod;
2295 for (
size_t n = range.begin(); n != range.end(); ++n) {
2297 LeafNodeType& node = *mNodes[n];
2299 CoordBBox bbox = node.getNodeBoundingBox();
2302 BoolLeafNodeType& maskNode = *maskAcc.
touchLeaf(node.origin());
2304 for (Iterator it = node.cbeginValueOn(); it; ++it) {
2305 ijk = it.getCoord();
2308 localCorod = LeafNodeType::offsetToLocalCoord(pos);
2310 if (localCorod[2] <
int(LeafNodeType::DIM - 1)) {
2312 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2314 nijk = ijk.offsetBy(0, 0, 1);
2318 if (localCorod[2] > 0) {
2320 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2322 nijk = ijk.offsetBy(0, 0, -1);
2326 if (localCorod[1] <
int(LeafNodeType::DIM - 1)) {
2327 npos = pos + LeafNodeType::DIM;
2328 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2330 nijk = ijk.offsetBy(0, 1, 0);
2334 if (localCorod[1] > 0) {
2335 npos = pos - LeafNodeType::DIM;
2336 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2338 nijk = ijk.offsetBy(0, -1, 0);
2342 if (localCorod[0] <
int(LeafNodeType::DIM - 1)) {
2343 npos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
2344 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2346 nijk = ijk.offsetBy(1, 0, 0);
2350 if (localCorod[0] > 0) {
2351 npos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
2352 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2354 nijk = ijk.offsetBy(-1, 0, 0);
2361 void join(ConstructVoxelMask& rhs) { mMaskTree->merge(*rhs.mMaskTree); }
2365 LeafNodeType **
const mNodes;
2367 BoolTreeType mLocalMaskTree;
2368 BoolTreeType *
const mMaskTree;
2373 template<
typename TreeType,
typename MeshDataAdapter>
2374 struct ExpandNarrowband
2378 using NodeMaskType =
typename LeafNodeType::NodeMaskType;
2380 using Int32LeafNodeType =
typename Int32TreeType::LeafNodeType;
2381 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2382 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
2389 Fragment() : idx(0), x(0), y(0), z(0), dist(0.0) {}
2392 : idx(idx_), x(x_), y(y_), z(z_), dist(dist_)
2396 bool operator<(
const Fragment& rhs)
const {
return idx < rhs.idx; }
2402 std::vector<BoolLeafNodeType*>& maskNodes,
2403 BoolTreeType& maskTree,
2405 Int32TreeType& indexTree,
2407 ValueType exteriorBandWidth,
2408 ValueType interiorBandWidth,
2409 ValueType voxelSize)
2410 : mMaskNodes(maskNodes.empty() ?
nullptr : &maskNodes[0])
2411 , mMaskTree(&maskTree)
2412 , mDistTree(&distTree)
2413 , mIndexTree(&indexTree)
2415 , mNewMaskTree(
false)
2417 , mUpdatedDistNodes()
2419 , mUpdatedIndexNodes()
2420 , mExteriorBandWidth(exteriorBandWidth)
2421 , mInteriorBandWidth(interiorBandWidth)
2422 , mVoxelSize(voxelSize)
2426 ExpandNarrowband(
const ExpandNarrowband& rhs, tbb::split)
2427 : mMaskNodes(rhs.mMaskNodes)
2428 , mMaskTree(rhs.mMaskTree)
2429 , mDistTree(rhs.mDistTree)
2430 , mIndexTree(rhs.mIndexTree)
2432 , mNewMaskTree(
false)
2434 , mUpdatedDistNodes()
2436 , mUpdatedIndexNodes()
2437 , mExteriorBandWidth(rhs.mExteriorBandWidth)
2438 , mInteriorBandWidth(rhs.mInteriorBandWidth)
2439 , mVoxelSize(rhs.mVoxelSize)
2443 void join(ExpandNarrowband& rhs)
2445 mDistNodes.insert(mDistNodes.end(), rhs.mDistNodes.begin(), rhs.mDistNodes.end());
2446 mIndexNodes.insert(mIndexNodes.end(), rhs.mIndexNodes.begin(), rhs.mIndexNodes.end());
2448 mUpdatedDistNodes.insert(mUpdatedDistNodes.end(),
2449 rhs.mUpdatedDistNodes.begin(), rhs.mUpdatedDistNodes.end());
2451 mUpdatedIndexNodes.insert(mUpdatedIndexNodes.end(),
2452 rhs.mUpdatedIndexNodes.begin(), rhs.mUpdatedIndexNodes.end());
2454 mNewMaskTree.merge(rhs.mNewMaskTree);
2457 void operator()(
const tbb::blocked_range<size_t>& range)
2463 std::vector<Fragment> fragments;
2464 fragments.reserve(256);
2466 std::unique_ptr<LeafNodeType> newDistNodePt;
2467 std::unique_ptr<Int32LeafNodeType> newIndexNodePt;
2469 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2471 BoolLeafNodeType& maskNode = *mMaskNodes[n];
2472 if (maskNode.isEmpty())
continue;
2476 const Coord& origin = maskNode.origin();
2478 LeafNodeType * distNodePt = distAcc.
probeLeaf(origin);
2479 Int32LeafNodeType * indexNodePt = indexAcc.
probeLeaf(origin);
2481 assert(!distNodePt == !indexNodePt);
2483 bool usingNewNodes =
false;
2485 if (!distNodePt && !indexNodePt) {
2487 const ValueType backgroundDist = distAcc.
getValue(origin);
2489 if (!newDistNodePt.get() && !newIndexNodePt.get()) {
2490 newDistNodePt.reset(
new LeafNodeType(origin, backgroundDist));
2491 newIndexNodePt.reset(
new Int32LeafNodeType(origin, indexAcc.
getValue(origin)));
2494 if ((backgroundDist < ValueType(0.0)) !=
2495 (newDistNodePt->getValue(0) < ValueType(0.0))) {
2496 newDistNodePt->buffer().fill(backgroundDist);
2499 newDistNodePt->setOrigin(origin);
2500 newIndexNodePt->setOrigin(origin);
2503 distNodePt = newDistNodePt.get();
2504 indexNodePt = newIndexNodePt.get();
2506 usingNewNodes =
true;
2513 for (
typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
2514 bbox.expand(it.getCoord());
2519 gatherFragments(fragments, bbox, distAcc, indexAcc);
2524 bbox = maskNode.getNodeBoundingBox();
2526 bool updatedLeafNodes =
false;
2528 for (
typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
2530 const Coord ijk = it.getCoord();
2532 if (updateVoxel(ijk, 5, fragments, *distNodePt, *indexNodePt, &updatedLeafNodes)) {
2534 for (
Int32 i = 0; i < 6; ++i) {
2536 if (bbox.isInside(nijk)) {
2537 mask.setOn(BoolLeafNodeType::coordToOffset(nijk));
2543 for (
Int32 i = 6; i < 26; ++i) {
2545 if (bbox.isInside(nijk)) {
2546 mask.setOn(BoolLeafNodeType::coordToOffset(nijk));
2552 if (updatedLeafNodes) {
2555 mask -= indexNodePt->getValueMask();
2557 for (
typename NodeMaskType::OnIterator it = mask.beginOn(); it; ++it) {
2559 const Index pos = it.pos();
2560 const Coord ijk = maskNode.origin() + LeafNodeType::offsetToLocalCoord(pos);
2562 if (updateVoxel(ijk, 6, fragments, *distNodePt, *indexNodePt)) {
2563 for (
Int32 i = 0; i < 6; ++i) {
2570 if (usingNewNodes) {
2571 newDistNodePt->topologyUnion(*newIndexNodePt);
2572 mDistNodes.push_back(newDistNodePt.release());
2573 mIndexNodes.push_back(newIndexNodePt.release());
2575 mUpdatedDistNodes.push_back(distNodePt);
2576 mUpdatedIndexNodes.push_back(indexNodePt);
2584 BoolTreeType& newMaskTree() {
return mNewMaskTree; }
2586 std::vector<LeafNodeType*>& newDistNodes() {
return mDistNodes; }
2587 std::vector<LeafNodeType*>& updatedDistNodes() {
return mUpdatedDistNodes; }
2589 std::vector<Int32LeafNodeType*>& newIndexNodes() {
return mIndexNodes; }
2590 std::vector<Int32LeafNodeType*>& updatedIndexNodes() {
return mUpdatedIndexNodes; }
2596 gatherFragments(std::vector<Fragment>& fragments,
const CoordBBox& bbox,
2600 const Coord nodeMin = bbox.min() & ~(LeafNodeType::DIM - 1);
2601 const Coord nodeMax = bbox.max() & ~(LeafNodeType::DIM - 1);
2606 for (ijk[0] = nodeMin[0]; ijk[0] <= nodeMax[0]; ijk[0] += LeafNodeType::DIM) {
2607 for (ijk[1] = nodeMin[1]; ijk[1] <= nodeMax[1]; ijk[1] += LeafNodeType::DIM) {
2608 for (ijk[2] = nodeMin[2]; ijk[2] <= nodeMax[2]; ijk[2] += LeafNodeType::DIM) {
2609 if (LeafNodeType* distleaf = distAcc.
probeLeaf(ijk)) {
2612 ijk.offsetBy(LeafNodeType::DIM - 1));
2613 gatherFragments(fragments, region, *distleaf, *indexAcc.
probeLeaf(ijk));
2619 std::sort(fragments.begin(), fragments.end());
2623 gatherFragments(std::vector<Fragment>& fragments,
const CoordBBox& bbox,
2624 const LeafNodeType& distLeaf,
const Int32LeafNodeType& idxLeaf)
const 2626 const typename LeafNodeType::NodeMaskType& mask = distLeaf.getValueMask();
2627 const ValueType* distData = distLeaf.buffer().data();
2628 const Int32* idxData = idxLeaf.buffer().data();
2630 for (
int x = bbox.min()[0]; x <= bbox.max()[0]; ++x) {
2631 const Index xPos = (x & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
2632 for (
int y = bbox.min()[1]; y <= bbox.max()[1]; ++y) {
2633 const Index yPos = xPos + ((y & (LeafNodeType::DIM - 1u)) << LeafNodeType::LOG2DIM);
2634 for (
int z = bbox.min()[2]; z <= bbox.max()[2]; ++z) {
2635 const Index pos = yPos + (z & (LeafNodeType::DIM - 1u));
2636 if (mask.isOn(pos)) {
2637 fragments.push_back(Fragment(idxData[pos],x,y,z, std::abs(distData[pos])));
2647 computeDistance(
const Coord& ijk,
const Int32 manhattanLimit,
2648 const std::vector<Fragment>& fragments,
Int32& closestPrimIdx)
const 2650 Vec3d a, b, c, uvw, voxelCenter(ijk[0], ijk[1], ijk[2]);
2654 for (
size_t n = 0, N = fragments.size(); n < N; ++n) {
2656 const Fragment& fragment = fragments[n];
2657 if (lastIdx == fragment.idx)
continue;
2659 const Int32 dx = std::abs(fragment.x - ijk[0]);
2660 const Int32 dy = std::abs(fragment.y - ijk[1]);
2661 const Int32 dz = std::abs(fragment.z - ijk[2]);
2663 const Int32 manhattan = dx + dy + dz;
2664 if (manhattan > manhattanLimit)
continue;
2666 lastIdx = fragment.idx;
2668 const size_t polygon = size_t(lastIdx);
2670 mMesh->getIndexSpacePoint(polygon, 0, a);
2671 mMesh->getIndexSpacePoint(polygon, 1, b);
2672 mMesh->getIndexSpacePoint(polygon, 2, c);
2674 primDist = (voxelCenter -
2678 if (4 == mMesh->vertexCount(polygon)) {
2680 mMesh->getIndexSpacePoint(polygon, 3, b);
2683 a, b, c, voxelCenter, uvw)).lengthSqr();
2685 if (tmpDist < primDist) primDist = tmpDist;
2688 if (primDist < dist) {
2690 closestPrimIdx = lastIdx;
2694 return ValueType(std::sqrt(dist)) * mVoxelSize;
2700 updateVoxel(
const Coord& ijk,
const Int32 manhattanLimit,
2701 const std::vector<Fragment>& fragments,
2702 LeafNodeType& distLeaf, Int32LeafNodeType& idxLeaf,
bool* updatedLeafNodes =
nullptr)
2704 Int32 closestPrimIdx = 0;
2705 const ValueType distance = computeDistance(ijk, manhattanLimit, fragments, closestPrimIdx);
2707 const Index pos = LeafNodeType::coordToOffset(ijk);
2708 const bool inside = distLeaf.getValue(pos) < ValueType(0.0);
2710 bool activateNeighbourVoxels =
false;
2712 if (!inside && distance < mExteriorBandWidth) {
2713 if (updatedLeafNodes) *updatedLeafNodes =
true;
2714 activateNeighbourVoxels = (distance + mVoxelSize) < mExteriorBandWidth;
2715 distLeaf.setValueOnly(pos, distance);
2716 idxLeaf.setValueOn(pos, closestPrimIdx);
2717 }
else if (inside && distance < mInteriorBandWidth) {
2718 if (updatedLeafNodes) *updatedLeafNodes =
true;
2719 activateNeighbourVoxels = (distance + mVoxelSize) < mInteriorBandWidth;
2720 distLeaf.setValueOnly(pos, -distance);
2721 idxLeaf.setValueOn(pos, closestPrimIdx);
2724 return activateNeighbourVoxels;
2729 BoolLeafNodeType **
const mMaskNodes;
2730 BoolTreeType *
const mMaskTree;
2732 Int32TreeType *
const mIndexTree;
2736 BoolTreeType mNewMaskTree;
2738 std::vector<LeafNodeType*> mDistNodes, mUpdatedDistNodes;
2739 std::vector<Int32LeafNodeType*> mIndexNodes, mUpdatedIndexNodes;
2741 const ValueType mExteriorBandWidth, mInteriorBandWidth, mVoxelSize;
2745 template<
typename TreeType>
2749 AddNodes(
TreeType& tree, std::vector<LeafNodeType*>& nodes)
2750 : mTree(&tree) , mNodes(&nodes)
2754 void operator()()
const {
2756 std::vector<LeafNodeType*>& nodes = *mNodes;
2757 for (
size_t n = 0, N = nodes.size(); n < N; ++n) {
2763 std::vector<LeafNodeType*> *
const mNodes;
2767 template<
typename TreeType,
typename Int32TreeType,
typename BoolTreeType,
typename MeshDataAdapter>
2771 Int32TreeType& indexTree,
2772 BoolTreeType& maskTree,
2773 std::vector<typename BoolTreeType::LeafNodeType*>& maskNodes,
2779 ExpandNarrowband<TreeType, MeshDataAdapter> expandOp(maskNodes, maskTree,
2780 distTree, indexTree, mesh, exteriorBandWidth, interiorBandWidth, voxelSize);
2782 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, maskNodes.size()), expandOp);
2784 tbb::parallel_for(tbb::blocked_range<size_t>(0, expandOp.updatedIndexNodes().size()),
2785 UnionValueMasks<typename TreeType::LeafNodeType, typename Int32TreeType::LeafNodeType>(
2786 expandOp.updatedDistNodes(), expandOp.updatedIndexNodes()));
2788 tbb::task_group tasks;
2789 tasks.run(AddNodes<TreeType>(distTree, expandOp.newDistNodes()));
2790 tasks.run(AddNodes<Int32TreeType>(indexTree, expandOp.newIndexNodes()));
2794 maskTree.merge(expandOp.newMaskTree());
2802 template<
typename TreeType>
2803 struct TransformValues
2808 TransformValues(std::vector<LeafNodeType*>& nodes,
2809 ValueType voxelSize,
bool unsignedDist)
2811 , mVoxelSize(voxelSize)
2812 , mUnsigned(unsignedDist)
2816 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2818 typename LeafNodeType::ValueOnIter iter;
2820 const bool udf = mUnsigned;
2821 const ValueType w[2] = { -mVoxelSize, mVoxelSize };
2823 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2825 for (iter = mNodes[n]->beginValueOn(); iter; ++iter) {
2826 ValueType& val =
const_cast<ValueType&
>(iter.getValue());
2827 val = w[udf || (val < ValueType(0.0))] * std::sqrt(std::abs(val));
2833 LeafNodeType * *
const mNodes;
2834 const ValueType mVoxelSize;
2835 const bool mUnsigned;
2840 template<
typename TreeType>
2841 struct InactivateValues
2846 InactivateValues(std::vector<LeafNodeType*>& nodes,
2847 ValueType exBandWidth, ValueType inBandWidth)
2848 : mNodes(nodes.empty() ?
nullptr : &nodes[0])
2849 , mExBandWidth(exBandWidth)
2850 , mInBandWidth(inBandWidth)
2854 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2856 typename LeafNodeType::ValueOnIter iter;
2857 const ValueType exVal = mExBandWidth;
2858 const ValueType inVal = -mInBandWidth;
2860 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2862 for (iter = mNodes[n]->beginValueOn(); iter; ++iter) {
2864 ValueType& val =
const_cast<ValueType&
>(iter.getValue());
2866 const bool inside = val < ValueType(0.0);
2868 if (inside && !(val > inVal)) {
2871 }
else if (!inside && !(val < exVal)) {
2880 LeafNodeType * *
const mNodes;
2881 const ValueType mExBandWidth, mInBandWidth;
2885 template<
typename TreeType>
2891 OffsetValues(std::vector<LeafNodeType*>& nodes, ValueType offset)
2892 : mNodes(nodes.empty() ?
nullptr : &nodes[0]), mOffset(offset)
2896 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2898 const ValueType offset = mOffset;
2900 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2902 typename LeafNodeType::ValueOnIter iter = mNodes[n]->beginValueOn();
2904 for (; iter; ++iter) {
2905 ValueType& val =
const_cast<ValueType&
>(iter.getValue());
2912 LeafNodeType * *
const mNodes;
2913 const ValueType mOffset;
2917 template<
typename TreeType>
2923 Renormalize(
const TreeType& tree,
const std::vector<LeafNodeType*>& nodes,
2924 ValueType* buffer, ValueType voxelSize)
2926 , mNodes(nodes.empty() ?
nullptr : &nodes[0])
2928 , mVoxelSize(voxelSize)
2932 void operator()(
const tbb::blocked_range<size_t>& range)
const 2941 const ValueType dx = mVoxelSize, invDx = ValueType(1.0) / mVoxelSize;
2943 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2945 ValueType* bufferData = &mBuffer[n * LeafNodeType::SIZE];
2947 typename LeafNodeType::ValueOnCIter iter = mNodes[n]->cbeginValueOn();
2948 for (; iter; ++iter) {
2950 const ValueType phi0 = *iter;
2952 ijk = iter.getCoord();
2954 up[0] = acc.
getValue(ijk.offsetBy(1, 0, 0)) - phi0;
2955 up[1] = acc.
getValue(ijk.offsetBy(0, 1, 0)) - phi0;
2956 up[2] = acc.
getValue(ijk.offsetBy(0, 0, 1)) - phi0;
2958 down[0] = phi0 - acc.
getValue(ijk.offsetBy(-1, 0, 0));
2959 down[1] = phi0 - acc.
getValue(ijk.offsetBy(0, -1, 0));
2960 down[2] = phi0 - acc.
getValue(ijk.offsetBy(0, 0, -1));
2964 const ValueType diff =
math::Sqrt(normSqGradPhi) * invDx - ValueType(1.0);
2967 bufferData[iter.pos()] = phi0 - dx * S * diff;
2974 LeafNodeType
const *
const *
const mNodes;
2975 ValueType *
const mBuffer;
2977 const ValueType mVoxelSize;
2981 template<
typename TreeType>
2987 MinCombine(std::vector<LeafNodeType*>& nodes,
const ValueType* buffer)
2988 : mNodes(nodes.empty() ?
nullptr : &nodes[0]), mBuffer(buffer)
2992 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2994 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2996 const ValueType* bufferData = &mBuffer[n * LeafNodeType::SIZE];
2998 typename LeafNodeType::ValueOnIter iter = mNodes[n]->beginValueOn();
3000 for (; iter; ++iter) {
3001 ValueType& val =
const_cast<ValueType&
>(iter.getValue());
3002 val =
std::min(val, bufferData[iter.pos()]);
3008 LeafNodeType * *
const mNodes;
3009 ValueType
const *
const mBuffer;
3023 template <
typename FloatTreeT>
3027 using ConnectivityTable = mesh_to_volume_internal::LeafNodeConnectivityTable<FloatTreeT>;
3032 ConnectivityTable nodeConnectivity(tree);
3034 std::vector<size_t> zStartNodes, yStartNodes, xStartNodes;
3039 for (
size_t n = 0; n < nodeConnectivity.size(); ++n) {
3040 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevX()[n]) {
3041 xStartNodes.push_back(n);
3044 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevY()[n]) {
3045 yStartNodes.push_back(n);
3048 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevZ()[n]) {
3049 zStartNodes.push_back(n);
3053 using SweepingOp = mesh_to_volume_internal::SweepExteriorSign<FloatTreeT>;
3058 tbb::parallel_for(tbb::blocked_range<size_t>(0, zStartNodes.size()),
3061 tbb::parallel_for(tbb::blocked_range<size_t>(0, yStartNodes.size()),
3064 tbb::parallel_for(tbb::blocked_range<size_t>(0, xStartNodes.size()),
3067 const size_t numLeafNodes = nodeConnectivity.size();
3068 const size_t numVoxels = numLeafNodes * FloatTreeT::LeafNodeType::SIZE;
3070 std::unique_ptr<bool[]> changedNodeMaskA{
new bool[numLeafNodes]};
3071 std::unique_ptr<bool[]> changedNodeMaskB{
new bool[numLeafNodes]};
3072 std::unique_ptr<bool[]> changedVoxelMask{
new bool[numVoxels]};
3074 mesh_to_volume_internal::fillArray(changedNodeMaskA.get(),
true, numLeafNodes);
3075 mesh_to_volume_internal::fillArray(changedNodeMaskB.get(),
false, numLeafNodes);
3076 mesh_to_volume_internal::fillArray(changedVoxelMask.get(),
false, numVoxels);
3078 const tbb::blocked_range<size_t> nodeRange(0, numLeafNodes);
3080 bool nodesUpdated =
false;
3085 tbb::parallel_for(nodeRange, mesh_to_volume_internal::SeedFillExteriorSign<FloatTreeT>(
3086 nodeConnectivity.nodes(), changedNodeMaskA.get()));
3094 tbb::parallel_for(nodeRange, mesh_to_volume_internal::SeedPoints<FloatTreeT>(
3095 nodeConnectivity, changedNodeMaskA.get(), changedNodeMaskB.get(),
3096 changedVoxelMask.get()));
3100 changedNodeMaskA.swap(changedNodeMaskB);
3102 nodesUpdated =
false;
3103 for (
size_t n = 0; n < numLeafNodes; ++n) {
3104 nodesUpdated |= changedNodeMaskA[n];
3105 if (nodesUpdated)
break;
3111 tbb::parallel_for(nodeRange, mesh_to_volume_internal::SyncVoxelMask<FloatTreeT>(
3112 nodeConnectivity.nodes(), changedNodeMaskA.get(), changedVoxelMask.get()));
3114 }
while (nodesUpdated);
3122 template <
typename Gr
idType,
typename MeshDataAdapter,
typename Interrupter>
3123 typename GridType::Ptr
3125 Interrupter& interrupter,
3128 float exteriorBandWidth,
3129 float interiorBandWidth,
3133 using GridTypePtr =
typename GridType::Ptr;
3134 using TreeType =
typename GridType::TreeType;
3135 using LeafNodeType =
typename TreeType::LeafNodeType;
3136 using ValueType =
typename GridType::ValueType;
3139 using Int32TreeType =
typename Int32GridType::TreeType;
3141 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
3148 distGrid->setTransform(transform.
copy());
3150 ValueType exteriorWidth = ValueType(exteriorBandWidth);
3151 ValueType interiorWidth = ValueType(interiorBandWidth);
3155 if (!std::isfinite(exteriorWidth) || std::isnan(interiorWidth)) {
3156 std::stringstream msg;
3157 msg <<
"Illegal narrow band width: exterior = " << exteriorWidth
3158 <<
", interior = " << interiorWidth;
3163 const ValueType voxelSize = ValueType(transform.
voxelSize()[0]);
3165 if (!std::isfinite(voxelSize) ||
math::isZero(voxelSize)) {
3166 std::stringstream msg;
3167 msg <<
"Illegal transform, voxel size = " << voxelSize;
3173 exteriorWidth *= voxelSize;
3177 interiorWidth *= voxelSize;
3185 Int32GridType* indexGrid =
nullptr;
3187 typename Int32GridType::Ptr temporaryIndexGrid;
3189 if (polygonIndexGrid) {
3190 indexGrid = polygonIndexGrid;
3193 indexGrid = temporaryIndexGrid.get();
3196 indexGrid->newTree();
3197 indexGrid->setTransform(transform.
copy());
3199 if (computeSignedDistanceField) {
3203 interiorWidth = ValueType(0.0);
3206 TreeType& distTree = distGrid->tree();
3207 Int32TreeType& indexTree = indexGrid->tree();
3215 using VoxelizationDataType = mesh_to_volume_internal::VoxelizationData<TreeType>;
3216 using DataTable = tbb::enumerable_thread_specific<typename VoxelizationDataType::Ptr>;
3220 mesh_to_volume_internal::VoxelizePolygons<TreeType, MeshDataAdapter, Interrupter>;
3222 const tbb::blocked_range<size_t> polygonRange(0, mesh.polygonCount());
3224 tbb::parallel_for(polygonRange, Voxelizer(data, mesh, &interrupter));
3226 for (
typename DataTable::iterator i = data.begin(); i != data.end(); ++i) {
3227 VoxelizationDataType& dataItem = **i;
3228 mesh_to_volume_internal::combineData(
3229 distTree, indexTree, dataItem.distTree, dataItem.indexTree);
3235 if (interrupter.wasInterrupted(30))
return distGrid;
3242 if (computeSignedDistanceField) {
3247 std::vector<LeafNodeType*> nodes;
3248 nodes.reserve(distTree.leafCount());
3249 distTree.getNodes(nodes);
3251 const tbb::blocked_range<size_t> nodeRange(0, nodes.size());
3254 mesh_to_volume_internal::ComputeIntersectingVoxelSign<TreeType, MeshDataAdapter>;
3256 tbb::parallel_for(nodeRange, SignOp(nodes, distTree, indexTree, mesh));
3258 if (interrupter.wasInterrupted(45))
return distGrid;
3261 if (removeIntersectingVoxels) {
3263 tbb::parallel_for(nodeRange,
3264 mesh_to_volume_internal::ValidateIntersectingVoxels<TreeType>(distTree, nodes));
3266 tbb::parallel_for(nodeRange,
3267 mesh_to_volume_internal::RemoveSelfIntersectingSurface<TreeType>(
3268 nodes, distTree, indexTree));
3275 if (interrupter.wasInterrupted(50))
return distGrid;
3277 if (distTree.activeVoxelCount() == 0) {
3279 distTree.root().setBackground(exteriorWidth,
false);
3285 std::vector<LeafNodeType*> nodes;
3286 nodes.reserve(distTree.leafCount());
3287 distTree.getNodes(nodes);
3289 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3290 mesh_to_volume_internal::TransformValues<TreeType>(
3291 nodes, voxelSize, !computeSignedDistanceField));
3295 if (computeSignedDistanceField) {
3296 distTree.root().setBackground(exteriorWidth,
false);
3302 if (interrupter.wasInterrupted(54))
return distGrid;
3309 const ValueType minBandWidth = voxelSize * ValueType(2.0);
3311 if (interiorWidth > minBandWidth || exteriorWidth > minBandWidth) {
3314 BoolTreeType maskTree(
false);
3317 std::vector<LeafNodeType*> nodes;
3318 nodes.reserve(distTree.leafCount());
3319 distTree.getNodes(nodes);
3321 mesh_to_volume_internal::ConstructVoxelMask<TreeType> op(maskTree, distTree, nodes);
3322 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), op);
3328 float progress = 54.0f, step = 0.0f;
3330 2.0 * std::ceil((
std::max(interiorWidth, exteriorWidth) - minBandWidth) / voxelSize);
3332 if (estimated <
double(maxIterations)) {
3333 maxIterations = unsigned(estimated);
3334 step = 40.0f / float(maxIterations);
3337 std::vector<typename BoolTreeType::LeafNodeType*> maskNodes;
3342 if (interrupter.wasInterrupted(
int(progress)))
return distGrid;
3344 const size_t maskNodeCount = maskTree.leafCount();
3345 if (maskNodeCount == 0)
break;
3348 maskNodes.reserve(maskNodeCount);
3349 maskTree.getNodes(maskNodes);
3351 const tbb::blocked_range<size_t> range(0, maskNodes.size());
3353 tbb::parallel_for(range,
3354 mesh_to_volume_internal::DiffLeafNodeMask<TreeType>(distTree, maskNodes));
3356 mesh_to_volume_internal::expandNarrowband(distTree, indexTree, maskTree, maskNodes,
3357 mesh, exteriorWidth, interiorWidth, voxelSize);
3359 if ((++count) >= maxIterations)
break;
3364 if (interrupter.wasInterrupted(94))
return distGrid;
3366 if (!polygonIndexGrid) indexGrid->clear();
3374 if (computeSignedDistanceField && renormalizeValues) {
3376 std::vector<LeafNodeType*> nodes;
3377 nodes.reserve(distTree.leafCount());
3378 distTree.getNodes(nodes);
3380 std::unique_ptr<ValueType[]> buffer{
new ValueType[LeafNodeType::SIZE * nodes.size()]};
3382 const ValueType offset = ValueType(0.8 * voxelSize);
3384 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3385 mesh_to_volume_internal::OffsetValues<TreeType>(nodes, -offset));
3387 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3388 mesh_to_volume_internal::Renormalize<TreeType>(
3389 distTree, nodes, buffer.get(), voxelSize));
3391 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3392 mesh_to_volume_internal::MinCombine<TreeType>(nodes, buffer.get()));
3394 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3395 mesh_to_volume_internal::OffsetValues<TreeType>(
3396 nodes, offset - mesh_to_volume_internal::Tolerance<ValueType>::epsilon()));
3399 if (interrupter.wasInterrupted(99))
return distGrid;
3406 if (trimNarrowBand &&
std::min(interiorWidth, exteriorWidth) < voxelSize * ValueType(4.0)) {
3408 std::vector<LeafNodeType*> nodes;
3409 nodes.reserve(distTree.leafCount());
3410 distTree.getNodes(nodes);
3412 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3413 mesh_to_volume_internal::InactivateValues<TreeType>(
3414 nodes, exteriorWidth, computeSignedDistanceField ? interiorWidth : exteriorWidth));
3417 distTree, exteriorWidth, computeSignedDistanceField ? -interiorWidth : -exteriorWidth);
3424 template <
typename Gr
idType,
typename MeshDataAdapter>
3425 typename GridType::Ptr
3429 float exteriorBandWidth,
3430 float interiorBandWidth,
3435 return meshToVolume<GridType>(nullInterrupter, mesh, transform,
3436 exteriorBandWidth, interiorBandWidth, flags, polygonIndexGrid);
3447 template<
typename Gr
idType,
typename Interrupter>
3449 typename GridType::Ptr>::type
3451 Interrupter& interrupter,
3452 const openvdb::math::Transform& xform,
3453 const std::vector<Vec3s>& points,
3454 const std::vector<Vec3I>& triangles,
3455 const std::vector<Vec4I>& quads,
3458 bool unsignedDistanceField =
false)
3460 if (points.empty()) {
3461 return typename GridType::Ptr(
new GridType(
typename GridType::ValueType(exBandWidth)));
3464 const size_t numPoints = points.size();
3465 std::unique_ptr<Vec3s[]> indexSpacePoints{
new Vec3s[numPoints]};
3468 tbb::parallel_for(tbb::blocked_range<size_t>(0, numPoints),
3469 mesh_to_volume_internal::TransformPoints<Vec3s>(
3470 &points[0], indexSpacePoints.get(), xform));
3474 if (quads.empty()) {
3477 mesh(indexSpacePoints.get(), numPoints, &triangles[0], triangles.size());
3479 return meshToVolume<GridType>(
3480 interrupter, mesh, xform, exBandWidth, inBandWidth, conversionFlags);
3482 }
else if (triangles.empty()) {
3485 mesh(indexSpacePoints.get(), numPoints, &quads[0], quads.size());
3487 return meshToVolume<GridType>(
3488 interrupter, mesh, xform, exBandWidth, inBandWidth, conversionFlags);
3493 const size_t numPrimitives = triangles.size() + quads.size();
3494 std::unique_ptr<Vec4I[]> prims{
new Vec4I[numPrimitives]};
3496 for (
size_t n = 0, N = triangles.size(); n < N; ++n) {
3497 const Vec3I& triangle = triangles[n];
3498 Vec4I& prim = prims[n];
3499 prim[0] = triangle[0];
3500 prim[1] = triangle[1];
3501 prim[2] = triangle[2];
3505 const size_t offset = triangles.size();
3506 for (
size_t n = 0, N = quads.size(); n < N; ++n) {
3507 prims[offset + n] = quads[n];
3511 mesh(indexSpacePoints.get(), numPoints, prims.get(), numPrimitives);
3513 return meshToVolume<GridType>(interrupter, mesh, xform,
3514 exBandWidth, inBandWidth, conversionFlags);
3520 template<
typename Gr
idType,
typename Interrupter>
3522 typename GridType::Ptr>::type
3526 const std::vector<Vec3s>& ,
3527 const std::vector<Vec3I>& ,
3528 const std::vector<Vec4I>& ,
3534 "mesh to volume conversion is supported only for scalar floating-point grids");
3544 template<
typename Gr
idType>
3545 typename GridType::Ptr
3547 const openvdb::math::Transform& xform,
3548 const std::vector<Vec3s>& points,
3549 const std::vector<Vec3I>& triangles,
3553 return meshToLevelSet<GridType>(nullInterrupter, xform, points, triangles, halfWidth);
3557 template<
typename Gr
idType,
typename Interrupter>
3558 typename GridType::Ptr
3560 Interrupter& interrupter,
3561 const openvdb::math::Transform& xform,
3562 const std::vector<Vec3s>& points,
3563 const std::vector<Vec3I>& triangles,
3566 std::vector<Vec4I> quads(0);
3567 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3568 halfWidth, halfWidth);
3572 template<
typename Gr
idType>
3573 typename GridType::Ptr
3575 const openvdb::math::Transform& xform,
3576 const std::vector<Vec3s>& points,
3577 const std::vector<Vec4I>& quads,
3581 return meshToLevelSet<GridType>(nullInterrupter, xform, points, quads, halfWidth);
3585 template<
typename Gr
idType,
typename Interrupter>
3586 typename GridType::Ptr
3588 Interrupter& interrupter,
3589 const openvdb::math::Transform& xform,
3590 const std::vector<Vec3s>& points,
3591 const std::vector<Vec4I>& quads,
3594 std::vector<Vec3I> triangles(0);
3595 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3596 halfWidth, halfWidth);
3600 template<
typename Gr
idType>
3601 typename GridType::Ptr
3603 const openvdb::math::Transform& xform,
3604 const std::vector<Vec3s>& points,
3605 const std::vector<Vec3I>& triangles,
3606 const std::vector<Vec4I>& quads,
3610 return meshToLevelSet<GridType>(
3611 nullInterrupter, xform, points, triangles, quads, halfWidth);
3615 template<
typename Gr
idType,
typename Interrupter>
3616 typename GridType::Ptr
3618 Interrupter& interrupter,
3619 const openvdb::math::Transform& xform,
3620 const std::vector<Vec3s>& points,
3621 const std::vector<Vec3I>& triangles,
3622 const std::vector<Vec4I>& quads,
3625 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3626 halfWidth, halfWidth);
3630 template<
typename Gr
idType>
3631 typename GridType::Ptr
3633 const openvdb::math::Transform& xform,
3634 const std::vector<Vec3s>& points,
3635 const std::vector<Vec3I>& triangles,
3636 const std::vector<Vec4I>& quads,
3641 return meshToSignedDistanceField<GridType>(
3642 nullInterrupter, xform, points, triangles, quads, exBandWidth, inBandWidth);
3646 template<
typename Gr
idType,
typename Interrupter>
3647 typename GridType::Ptr
3649 Interrupter& interrupter,
3650 const openvdb::math::Transform& xform,
3651 const std::vector<Vec3s>& points,
3652 const std::vector<Vec3I>& triangles,
3653 const std::vector<Vec4I>& quads,
3657 return doMeshConversion<GridType>(interrupter, xform, points, triangles,
3658 quads, exBandWidth, inBandWidth);
3662 template<
typename Gr
idType>
3663 typename GridType::Ptr
3665 const openvdb::math::Transform& xform,
3666 const std::vector<Vec3s>& points,
3667 const std::vector<Vec3I>& triangles,
3668 const std::vector<Vec4I>& quads,
3672 return meshToUnsignedDistanceField<GridType>(
3673 nullInterrupter, xform, points, triangles, quads, bandWidth);
3677 template<
typename Gr
idType,
typename Interrupter>
3678 typename GridType::Ptr
3680 Interrupter& interrupter,
3681 const openvdb::math::Transform& xform,
3682 const std::vector<Vec3s>& points,
3683 const std::vector<Vec3I>& triangles,
3684 const std::vector<Vec4I>& quads,
3687 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3688 bandWidth, bandWidth,
true);
3696 inline std::ostream&
3699 ostr <<
"{[ " << rhs.
mXPrim <<
", " << rhs.
mXDist <<
"]";
3700 ostr <<
" [ " << rhs.
mYPrim <<
", " << rhs.
mYDist <<
"]";
3701 ostr <<
" [ " << rhs.
mZPrim <<
", " << rhs.
mZDist <<
"]}";
3721 const std::vector<Vec3s>& pointList,
3722 const std::vector<Vec4I>& polygonList);
3724 void run(
bool threaded =
true);
3727 inline void operator() (
const tbb::blocked_range<size_t> &range);
3735 struct Primitive { Vec3d a, b, c, d;
Int32 index; };
3737 template<
bool IsQuad>
3738 inline void voxelize(
const Primitive&);
3740 template<
bool IsQuad>
3741 inline bool evalPrimitive(
const Coord&,
const Primitive&);
3743 inline bool rayTriangleIntersection(
const Vec3d& origin,
const Vec3d& dir,
3744 const Vec3d& a,
const Vec3d& b,
const Vec3d& c,
double& t);
3750 const std::vector<Vec3s>& mPointList;
3751 const std::vector<Vec4I>& mPolygonList;
3755 IntTreeT mLastPrimTree;
3761 MeshToVoxelEdgeData::GenEdgeData::GenEdgeData(
3762 const std::vector<Vec3s>& pointList,
3763 const std::vector<Vec4I>& polygonList)
3766 , mPointList(pointList)
3767 , mPolygonList(polygonList)
3769 , mLastPrimAccessor(mLastPrimTree)
3778 , mPointList(rhs.mPointList)
3779 , mPolygonList(rhs.mPolygonList)
3781 , mLastPrimAccessor(mLastPrimTree)
3790 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, mPolygonList.size()), *
this);
3792 (*this)(tbb::blocked_range<size_t>(0, mPolygonList.size()));
3801 using NodeChainType = RootNodeType::NodeChainType;
3802 static_assert(NodeChainType::Size > 1,
"expected tree height > 1");
3803 using InternalNodeType =
typename NodeChainType::template Get<1>;
3811 for ( ; leafIt; ++leafIt) {
3812 ijk = leafIt->origin();
3819 InternalNodeType* node = rhs.mAccessor.
getNode<InternalNodeType>();
3821 rhs.mAccessor.
clear();
3831 if (!lhsLeafPt->isValueOn(offset)) {
3832 lhsLeafPt->setValueOn(offset, rhsValue);
3864 for (
size_t n = range.begin(); n < range.end(); ++n) {
3866 const Vec4I& verts = mPolygonList[n];
3868 prim.index =
Int32(n);
3869 prim.a = Vec3d(mPointList[verts[0]]);
3870 prim.b = Vec3d(mPointList[verts[1]]);
3871 prim.c = Vec3d(mPointList[verts[2]]);
3874 prim.d = Vec3d(mPointList[verts[3]]);
3875 voxelize<true>(prim);
3877 voxelize<false>(prim);
3883 template<
bool IsQuad>
3885 MeshToVoxelEdgeData::GenEdgeData::voxelize(
const Primitive& prim)
3887 std::deque<Coord> coordList;
3890 ijk = Coord::floor(prim.a);
3891 coordList.push_back(ijk);
3893 evalPrimitive<IsQuad>(ijk, prim);
3895 while (!coordList.empty()) {
3897 ijk = coordList.back();
3898 coordList.pop_back();
3900 for (
Int32 i = 0; i < 26; ++i) {
3903 if (prim.index != mLastPrimAccessor.
getValue(nijk)) {
3904 mLastPrimAccessor.
setValue(nijk, prim.index);
3905 if(evalPrimitive<IsQuad>(nijk, prim)) coordList.push_back(nijk);
3912 template<
bool IsQuad>
3914 MeshToVoxelEdgeData::GenEdgeData::evalPrimitive(
const Coord& ijk,
const Primitive& prim)
3916 Vec3d uvw, org(ijk[0], ijk[1], ijk[2]);
3917 bool intersecting =
false;
3924 double dist = (org -
3927 if (rayTriangleIntersection(org, Vec3d(1.0, 0.0, 0.0), prim.a, prim.c, prim.b, t)) {
3928 if (t < edgeData.
mXDist) {
3929 edgeData.
mXDist = float(t);
3930 edgeData.
mXPrim = prim.index;
3931 intersecting =
true;
3935 if (rayTriangleIntersection(org, Vec3d(0.0, 1.0, 0.0), prim.a, prim.c, prim.b, t)) {
3936 if (t < edgeData.
mYDist) {
3937 edgeData.
mYDist = float(t);
3938 edgeData.
mYPrim = prim.index;
3939 intersecting =
true;
3943 if (rayTriangleIntersection(org, Vec3d(0.0, 0.0, 1.0), prim.a, prim.c, prim.b, t)) {
3944 if (t < edgeData.
mZDist) {
3945 edgeData.
mZDist = float(t);
3946 edgeData.
mZPrim = prim.index;
3947 intersecting =
true;
3953 double secondDist = (org -
3956 if (secondDist < dist) dist = secondDist;
3958 if (rayTriangleIntersection(org, Vec3d(1.0, 0.0, 0.0), prim.a, prim.d, prim.c, t)) {
3959 if (t < edgeData.
mXDist) {
3960 edgeData.
mXDist = float(t);
3961 edgeData.
mXPrim = prim.index;
3962 intersecting =
true;
3966 if (rayTriangleIntersection(org, Vec3d(0.0, 1.0, 0.0), prim.a, prim.d, prim.c, t)) {
3967 if (t < edgeData.
mYDist) {
3968 edgeData.
mYDist = float(t);
3969 edgeData.
mYPrim = prim.index;
3970 intersecting =
true;
3974 if (rayTriangleIntersection(org, Vec3d(0.0, 0.0, 1.0), prim.a, prim.d, prim.c, t)) {
3975 if (t < edgeData.
mZDist) {
3976 edgeData.
mZDist = float(t);
3977 edgeData.
mZPrim = prim.index;
3978 intersecting =
true;
3983 if (intersecting) mAccessor.
setValue(ijk, edgeData);
3985 return (dist < 0.86602540378443861);
3990 MeshToVoxelEdgeData::GenEdgeData::rayTriangleIntersection(
3991 const Vec3d& origin,
const Vec3d& dir,
3992 const Vec3d& a,
const Vec3d& b,
const Vec3d& c,
3999 Vec3d s1 = dir.
cross(e2);
4001 double divisor = s1.
dot(e1);
4002 if (!(std::abs(divisor) > 0.0))
return false;
4006 double inv_divisor = 1.0 / divisor;
4007 Vec3d d = origin - a;
4008 double b1 = d.
dot(s1) * inv_divisor;
4010 if (b1 < 0.0 || b1 > 1.0)
return false;
4012 Vec3d s2 = d.
cross(e1);
4013 double b2 = dir.
dot(s2) * inv_divisor;
4015 if (b2 < 0.0 || (b1 + b2) > 1.0)
return false;
4019 t = e2.dot(s2) * inv_divisor;
4020 return (t < 0.0) ?
false :
true;
4036 const std::vector<Vec3s>& pointList,
4037 const std::vector<Vec4I>& polygonList)
4051 std::vector<Vec3d>& points,
4052 std::vector<Index32>& primitives)
4062 point[0] = double(coord[0]) + data.
mXDist;
4063 point[1] = double(coord[1]);
4064 point[2] = double(coord[2]);
4066 points.push_back(point);
4067 primitives.push_back(data.
mXPrim);
4071 point[0] = double(coord[0]);
4072 point[1] = double(coord[1]) + data.
mYDist;
4073 point[2] = double(coord[2]);
4075 points.push_back(point);
4076 primitives.push_back(data.
mYPrim);
4080 point[0] = double(coord[0]);
4081 point[1] = double(coord[1]);
4082 point[2] = double(coord[2]) + data.
mZDist;
4084 points.push_back(point);
4085 primitives.push_back(data.
mZPrim);
4095 point[0] = double(coord[0]);
4096 point[1] = double(coord[1]) + data.
mYDist;
4097 point[2] = double(coord[2]);
4099 points.push_back(point);
4100 primitives.push_back(data.
mYPrim);
4104 point[0] = double(coord[0]);
4105 point[1] = double(coord[1]);
4106 point[2] = double(coord[2]) + data.
mZDist;
4108 points.push_back(point);
4109 primitives.push_back(data.
mZPrim);
4117 point[0] = double(coord[0]);
4118 point[1] = double(coord[1]) + data.
mYDist;
4119 point[2] = double(coord[2]);
4121 points.push_back(point);
4122 primitives.push_back(data.
mYPrim);
4131 point[0] = double(coord[0]) + data.
mXDist;
4132 point[1] = double(coord[1]);
4133 point[2] = double(coord[2]);
4135 points.push_back(point);
4136 primitives.push_back(data.
mXPrim);
4140 point[0] = double(coord[0]);
4141 point[1] = double(coord[1]) + data.
mYDist;
4142 point[2] = double(coord[2]);
4144 points.push_back(point);
4145 primitives.push_back(data.
mYPrim);
4155 point[0] = double(coord[0]) + data.
mXDist;
4156 point[1] = double(coord[1]);
4157 point[2] = double(coord[2]);
4159 points.push_back(point);
4160 primitives.push_back(data.
mXPrim);
4169 point[0] = double(coord[0]) + data.
mXDist;
4170 point[1] = double(coord[1]);
4171 point[2] = double(coord[2]);
4173 points.push_back(point);
4174 primitives.push_back(data.
mXPrim);
4178 point[0] = double(coord[0]);
4179 point[1] = double(coord[1]);
4180 point[2] = double(coord[2]) + data.
mZDist;
4182 points.push_back(point);
4183 primitives.push_back(data.
mZPrim);
4192 point[0] = double(coord[0]);
4193 point[1] = double(coord[1]);
4194 point[2] = double(coord[2]) + data.
mZDist;
4196 points.push_back(point);
4197 primitives.push_back(data.
mZPrim);
4203 template<
typename Gr
idType,
typename VecType>
4204 typename GridType::Ptr
4206 const openvdb::math::Transform& xform,
4207 typename VecType::ValueType halfWidth)
4213 points[0] =
Vec3s(pmin[0], pmin[1], pmin[2]);
4214 points[1] =
Vec3s(pmin[0], pmin[1], pmax[2]);
4215 points[2] =
Vec3s(pmax[0], pmin[1], pmax[2]);
4216 points[3] =
Vec3s(pmax[0], pmin[1], pmin[2]);
4217 points[4] =
Vec3s(pmin[0], pmax[1], pmin[2]);
4218 points[5] =
Vec3s(pmin[0], pmax[1], pmax[2]);
4219 points[6] =
Vec3s(pmax[0], pmax[1], pmax[2]);
4220 points[7] =
Vec3s(pmax[0], pmax[1], pmin[2]);
4223 faces[0] =
Vec4I(0, 1, 2, 3);
4224 faces[1] =
Vec4I(7, 6, 5, 4);
4225 faces[2] =
Vec4I(4, 5, 1, 0);
4226 faces[3] =
Vec4I(6, 7, 3, 2);
4227 faces[4] =
Vec4I(0, 3, 7, 4);
4228 faces[5] =
Vec4I(1, 5, 6, 2);
4232 return meshToVolume<GridType>(mesh, xform,
static_cast<float>(halfWidth), static_cast<float>(halfWidth));
4241 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION 4243 #ifdef OPENVDB_INSTANTIATE_MESHTOVOLUME 4247 #define _FUNCTION(TreeT) \ 4248 Grid<TreeT>::Ptr meshToVolume<Grid<TreeT>>(util::NullInterrupter&, \ 4249 const QuadAndTriangleDataAdapter<Vec3s, Vec3I>&, const openvdb::math::Transform&, \ 4250 float, float, int, Grid<TreeT>::ValueConverter<Int32>::Type*) 4254 #define _FUNCTION(TreeT) \ 4255 Grid<TreeT>::Ptr meshToVolume<Grid<TreeT>>(util::NullInterrupter&, \ 4256 const QuadAndTriangleDataAdapter<Vec3s, Vec4I>&, const openvdb::math::Transform&, \ 4257 float, float, int, Grid<TreeT>::ValueConverter<Int32>::Type*) 4261 #define _FUNCTION(TreeT) \ 4262 Grid<TreeT>::Ptr meshToLevelSet<Grid<TreeT>>(util::NullInterrupter&, \ 4263 const openvdb::math::Transform&, const std::vector<Vec3s>&, const std::vector<Vec3I>&, \ 4268 #define _FUNCTION(TreeT) \ 4269 Grid<TreeT>::Ptr meshToLevelSet<Grid<TreeT>>(util::NullInterrupter&, \ 4270 const openvdb::math::Transform&, const std::vector<Vec3s>&, const std::vector<Vec4I>&, \ 4275 #define _FUNCTION(TreeT) \ 4276 Grid<TreeT>::Ptr meshToLevelSet<Grid<TreeT>>(util::NullInterrupter&, \ 4277 const openvdb::math::Transform&, const std::vector<Vec3s>&, \ 4278 const std::vector<Vec3I>&, const std::vector<Vec4I>&, float) 4282 #define _FUNCTION(TreeT) \ 4283 Grid<TreeT>::Ptr meshToSignedDistanceField<Grid<TreeT>>(util::NullInterrupter&, \ 4284 const openvdb::math::Transform&, const std::vector<Vec3s>&, \ 4285 const std::vector<Vec3I>&, const std::vector<Vec4I>&, float, float) 4289 #define _FUNCTION(TreeT) \ 4290 Grid<TreeT>::Ptr meshToUnsignedDistanceField<Grid<TreeT>>(util::NullInterrupter&, \ 4291 const openvdb::math::Transform&, const std::vector<Vec3s>&, \ 4292 const std::vector<Vec3I>&, const std::vector<Vec4I>&, float) 4296 #define _FUNCTION(TreeT) \ 4297 Grid<TreeT>::Ptr createLevelSetBox<Grid<TreeT>>(const math::BBox<Vec3s>&, \ 4298 const openvdb::math::Transform&, float) 4302 #define _FUNCTION(TreeT) \ 4303 Grid<TreeT>::Ptr createLevelSetBox<Grid<TreeT>>(const math::BBox<Vec3d>&, \ 4304 const openvdb::math::Transform&, double) 4308 #define _FUNCTION(TreeT) \ 4309 void traceExteriorBoundaries(TreeT&) 4313 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION 4320 #endif // OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:49
Index32 leafCount() const override
Return the number of leaf nodes.
Definition: Tree.h:338
LeafNodeT * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists...
Definition: ValueAccessor.h:379
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:226
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:444
typename RootNodeType::ValueType ValueType
Definition: Tree.h:182
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
OPENVDB_API const Index32 INVALID_IDX
Real GodunovsNormSqrd(bool isOutside, Real dP_xm, Real dP_xp, Real dP_ym, Real dP_yp, Real dP_zm, Real dP_zp)
Definition: FiniteDifference.h:326
#define OPENVDB_LOG_DEBUG(message)
In debug builds only, log a debugging message of the form 'someVar << "text" << ...'.
Definition: logging.h:266
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:255
Base class for interrupters.
Definition: NullInterrupter.h:25
Convert polygonal meshes that consist of quads and/or triangles into signed or unsigned distance fiel...
Axis-aligned bounding box.
Definition: BBox.h:23
Vec3< T > cross(const Vec3< T > &v) const
Return the cross product of "this" vector and v;.
Definition: Vec3.h:224
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
Definition: BBox.h:62
void expand(ElementType padding)
Pad this bounding box.
Definition: BBox.h:321
RootNodeType & root()
Return this tree's root node.
Definition: Tree.h:279
Efficient multi-threaded replacement of the background values in tree.
void clearAllAccessors()
Clear all registered accessors.
Definition: Tree.h:1377
typename RootNodeType::LeafNodeType LeafNodeType
Definition: Tree.h:184
LeafIter beginLeaf()
Return an iterator over all leaf nodes in this tree.
Definition: Tree.h:1015
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:219
ValueConverter<T>::Type is the type of a tree having the same hierarchy as this tree but a different ...
Definition: Tree.h:195
std::shared_ptr< T > SharedPtr
Definition: Types.h:114
_RootNodeType RootNodeType
Definition: Tree.h:181
Defined various multi-threaded utility functions for trees.
Axis
Definition: Math.h:904
OPENVDB_API const Coord COORD_OFFSETS[26]
coordinate offset table for neighboring voxels
BBox< Coord > CoordBBox
Definition: NanoVDB.h:1658
OPENVDB_API Vec3d closestPointOnTriangleToPoint(const Vec3d &a, const Vec3d &b, const Vec3d &c, const Vec3d &p, Vec3d &uvw)
Closest Point on Triangle to Point. Given a triangle abc and a point p, return the point on abc close...
void merge(Tree &other, MergePolicy=MERGE_ACTIVE_STATES)
Efficiently merge another tree into this tree using one of several schemes.
Definition: Tree.h:1690
void clear() override
Remove all nodes from this cache, then reinsert the root node.
Definition: ValueAccessor.h:393
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:764
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:250
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
Definition: BBox.h:64
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
Base class for tree-traversal iterators over tile and voxel values.
Definition: TreeIterator.h:616
void clear()
Remove all tiles from this tree and all nodes other than the root node.
Definition: Tree.h:1318
T dot(const Vec3< T > &v) const
Dot product.
Definition: Vec3.h:195
Definition: Exceptions.h:13
Base class for tree-traversal iterators over all leaf nodes (but not leaf voxels) ...
Definition: TreeIterator.h:1186
ValueT value
Definition: GridBuilder.h:1287
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists...
Definition: ValueAccessor.h:384
const ValueT & getValue() const
Return the tile or voxel value to which this iterator is currently pointing.
Definition: TreeIterator.h:692
Index32 Index
Definition: Types.h:54
math::Vec4< Index32 > Vec4I
Definition: Types.h:88
LeafNodeType * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, return nullptr.
Definition: Tree.h:1564
bool operator<(const Tuple< SIZE, T0 > &t0, const Tuple< SIZE, T1 > &t1)
Definition: Tuple.h:189
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216
LeafNodeT * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, create one, but preserve the values and active states of all voxels.
Definition: ValueAccessor.h:348
int32_t Int32
Definition: Types.h:56
Tree< typename RootNodeType::template ValueConverter< Int32 >::Type > Type
Definition: Tree.h:196
Definition: Exceptions.h:64
bool evalLeafBoundingBox(CoordBBox &bbox) const override
Return in bbox the axis-aligned bounding box of all active tiles and leaf nodes with active values...
Definition: Tree.h:1977
void run(const char *ax, openvdb::GridBase &grid, const AttributeBindings &bindings={})
Run a full AX pipeline (parse, compile and execute) on a single OpenVDB Grid.
bool operator>(const Tuple< SIZE, T0 > &t0, const Tuple< SIZE, T1 > &t1)
Definition: Tuple.h:201
Vec3< float > Vec3s
Definition: Vec3.h:667
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:147
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition: Vec2.h:508
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
Definition: ValueAccessor.h:229
uint32_t Index32
Definition: Types.h:52
void addLeaf(LeafNodeT *leaf)
Add the specified leaf to this tree, possibly creating a child branch in the process. If the leaf node already exists, replace it.
Definition: ValueAccessor.h:329
Type Pow2(Type x)
Return x2.
Definition: Math.h:551
bool isZero(const Type &x)
Return true if x is exactly equal to zero.
Definition: Math.h:338
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
Vec2< T > maxComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise maximum of the two vectors.
Definition: Vec2.h:517
static const Real LEVEL_SET_HALF_WIDTH
Definition: Types.h:422
NodeType * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
Definition: ValueAccessor.h:304
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202
void getNodes(ArrayT &array)
Adds all nodes of a certain type to a container with the following API:
Definition: Tree.h:578