43 #ifndef OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED 44 #define OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED 57 #include <tbb/blocked_range.h> 58 #include <tbb/enumerable_thread_specific.h> 59 #include <tbb/parallel_for.h> 60 #include <tbb/parallel_reduce.h> 61 #include <tbb/partitioner.h> 62 #include <tbb/task_group.h> 63 #include <tbb/task_scheduler_init.h> 65 #include <boost/mpl/at.hpp> 66 #include <boost/mpl/int.hpp> 67 #include <boost/mpl/size.hpp> 75 #include <type_traits> 140 template <
typename Gr
idType,
typename MeshDataAdapter>
141 inline typename GridType::Ptr
145 float exteriorBandWidth = 3.0f,
146 float interiorBandWidth = 3.0f,
166 template <
typename Gr
idType,
typename MeshDataAdapter,
typename Interrupter>
167 inline typename GridType::Ptr
169 Interrupter& interrupter,
172 float exteriorBandWidth = 3.0f,
173 float interiorBandWidth = 3.0f,
191 template<
typename Po
intType,
typename PolygonType>
195 const std::vector<PolygonType>& polygons)
196 : mPointArray(points.empty() ? nullptr : &points[0])
197 , mPointArraySize(points.size())
198 , mPolygonArray(polygons.empty() ? nullptr : &polygons[0])
199 , mPolygonArraySize(polygons.size())
204 const PolygonType* polygonArray,
size_t polygonArraySize)
205 : mPointArray(pointArray)
206 , mPointArraySize(pointArraySize)
207 , mPolygonArray(polygonArray)
208 , mPolygonArraySize(polygonArraySize)
217 return (PolygonType::size == 3 || mPolygonArray[n][3] ==
util::INVALID_IDX) ? 3 : 4;
223 const PointType& p = mPointArray[mPolygonArray[n][int(v)]];
224 pos[0] = double(p[0]);
225 pos[1] = double(p[1]);
226 pos[2] = double(p[2]);
230 PointType
const *
const mPointArray;
231 size_t const mPointArraySize;
232 PolygonType
const *
const mPolygonArray;
233 size_t const mPolygonArraySize;
261 template<
typename Gr
idType>
262 inline typename GridType::Ptr
264 const openvdb::math::Transform& xform,
265 const std::vector<Vec3s>& points,
266 const std::vector<Vec3I>& triangles,
270 template<
typename Gr
idType,
typename Interrupter>
271 inline typename GridType::Ptr
273 Interrupter& interrupter,
274 const openvdb::math::Transform& xform,
275 const std::vector<Vec3s>& points,
276 const std::vector<Vec3I>& triangles,
295 template<
typename Gr
idType>
296 inline typename GridType::Ptr
298 const openvdb::math::Transform& xform,
299 const std::vector<Vec3s>& points,
300 const std::vector<Vec4I>& quads,
304 template<
typename Gr
idType,
typename Interrupter>
305 inline typename GridType::Ptr
307 Interrupter& interrupter,
308 const openvdb::math::Transform& xform,
309 const std::vector<Vec3s>& points,
310 const std::vector<Vec4I>& quads,
330 template<
typename Gr
idType>
331 inline typename GridType::Ptr
333 const openvdb::math::Transform& xform,
334 const std::vector<Vec3s>& points,
335 const std::vector<Vec3I>& triangles,
336 const std::vector<Vec4I>& quads,
340 template<
typename Gr
idType,
typename Interrupter>
341 inline typename GridType::Ptr
343 Interrupter& interrupter,
344 const openvdb::math::Transform& xform,
345 const std::vector<Vec3s>& points,
346 const std::vector<Vec3I>& triangles,
347 const std::vector<Vec4I>& quads,
369 template<
typename Gr
idType>
370 inline typename GridType::Ptr
372 const openvdb::math::Transform& xform,
373 const std::vector<Vec3s>& points,
374 const std::vector<Vec3I>& triangles,
375 const std::vector<Vec4I>& quads,
380 template<
typename Gr
idType,
typename Interrupter>
381 inline typename GridType::Ptr
383 Interrupter& interrupter,
384 const openvdb::math::Transform& xform,
385 const std::vector<Vec3s>& points,
386 const std::vector<Vec3I>& triangles,
387 const std::vector<Vec4I>& quads,
406 template<
typename Gr
idType>
407 inline typename GridType::Ptr
409 const openvdb::math::Transform& xform,
410 const std::vector<Vec3s>& points,
411 const std::vector<Vec3I>& triangles,
412 const std::vector<Vec4I>& quads,
416 template<
typename Gr
idType,
typename Interrupter>
417 inline typename GridType::Ptr
419 Interrupter& interrupter,
420 const openvdb::math::Transform& xform,
421 const std::vector<Vec3s>& points,
422 const std::vector<Vec3I>& triangles,
423 const std::vector<Vec4I>& quads,
436 template<
typename Gr
idType,
typename VecType>
437 inline typename GridType::Ptr
439 const openvdb::math::Transform& xform,
452 template <
typename FloatTreeT>
470 : mXDist(dist), mYDist(dist), mZDist(dist)
513 void convert(
const std::vector<Vec3s>& pointList,
const std::vector<Vec4I>& polygonList);
519 std::vector<Vec3d>& points, std::vector<Index32>& primitives);
538 namespace mesh_to_volume_internal {
540 template<
typename Po
intType>
545 : mPointsIn(pointsIn), mPointsOut(pointsOut), mXform(&xform)
549 void operator()(
const tbb::blocked_range<size_t>& range)
const {
553 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
555 const PointType& wsP = mPointsIn[n];
556 pos[0] = double(wsP[0]);
557 pos[1] = double(wsP[1]);
558 pos[2] = double(wsP[2]);
560 pos = mXform->worldToIndex(pos);
562 PointType& isP = mPointsOut[n];
563 isP[0] =
typename PointType::value_type(pos[0]);
564 isP[1] =
typename PointType::value_type(pos[1]);
565 isP[2] =
typename PointType::value_type(pos[2]);
575 template<
typename ValueType>
578 static ValueType
epsilon() {
return ValueType(1e-7); }
586 template<
typename TreeType>
598 : mDistTree(&lhsDistTree)
599 , mIdxTree(&lhsIdxTree)
600 , mRhsDistNodes(rhsDistNodes)
601 , mRhsIdxNodes(rhsIdxNodes)
605 void operator()(
const tbb::blocked_range<size_t>& range)
const {
610 using DistValueType =
typename LeafNodeType::ValueType;
611 using IndexValueType =
typename Int32LeafNodeType::ValueType;
613 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
615 const Coord& origin = mRhsDistNodes[n]->origin();
620 DistValueType* lhsDistData = lhsDistNode->buffer().data();
621 IndexValueType* lhsIdxData = lhsIdxNode->buffer().data();
623 const DistValueType* rhsDistData = mRhsDistNodes[n]->buffer().data();
624 const IndexValueType* rhsIdxData = mRhsIdxNodes[n]->buffer().data();
627 for (
Index32 offset = 0; offset < LeafNodeType::SIZE; ++offset) {
631 const DistValueType& lhsValue = lhsDistData[offset];
632 const DistValueType& rhsValue = rhsDistData[offset];
634 if (rhsValue < lhsValue) {
635 lhsDistNode->setValueOn(offset, rhsValue);
636 lhsIdxNode->setValueOn(offset, rhsIdxData[offset]);
638 lhsIdxNode->setValueOn(offset,
639 std::min(lhsIdxData[offset], rhsIdxData[offset]));
644 delete mRhsDistNodes[n];
645 delete mRhsIdxNodes[n];
651 TreeType *
const mDistTree;
652 Int32TreeType *
const mIdxTree;
654 LeafNodeType **
const mRhsDistNodes;
655 Int32LeafNodeType **
const mRhsIdxNodes;
662 template<
typename TreeType>
668 : mNodes(nodes.empty() ? nullptr : &nodes[0]), mCoordinates(coordinates)
672 void operator()(
const tbb::blocked_range<size_t>& range)
const {
673 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
674 Coord& origin = const_cast<Coord&>(mNodes[n]->origin());
675 mCoordinates[n] = origin;
676 origin[0] = static_cast<int>(n);
685 template<
typename TreeType>
691 : mNodes(nodes.empty() ? nullptr : &nodes[0]), mCoordinates(coordinates)
695 void operator()(
const tbb::blocked_range<size_t>& range)
const {
696 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
697 Coord& origin = const_cast<Coord&>(mNodes[n]->origin());
698 origin[0] = mCoordinates[n][0];
707 template<
typename TreeType>
714 size_t* offsets,
size_t numNodes,
const CoordBBox& bbox)
716 , mCoordinates(coordinates)
718 , mNumNodes(numNodes)
728 void operator()(
const tbb::blocked_range<size_t>& range)
const {
730 size_t* offsetsNextX = mOffsets;
731 size_t* offsetsPrevX = mOffsets + mNumNodes;
732 size_t* offsetsNextY = mOffsets + mNumNodes * 2;
733 size_t* offsetsPrevY = mOffsets + mNumNodes * 3;
734 size_t* offsetsNextZ = mOffsets + mNumNodes * 4;
735 size_t* offsetsPrevZ = mOffsets + mNumNodes * 5;
740 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
741 const Coord& origin = mCoordinates[n];
742 offsetsNextX[n] = findNeighbourNode(acc, origin,
Coord(LeafNodeType::DIM, 0, 0));
743 offsetsPrevX[n] = findNeighbourNode(acc, origin,
Coord(-LeafNodeType::DIM, 0, 0));
744 offsetsNextY[n] = findNeighbourNode(acc, origin,
Coord(0, LeafNodeType::DIM, 0));
745 offsetsPrevY[n] = findNeighbourNode(acc, origin,
Coord(0, -LeafNodeType::DIM, 0));
746 offsetsNextZ[n] = findNeighbourNode(acc, origin,
Coord(0, 0, LeafNodeType::DIM));
747 offsetsPrevZ[n] = findNeighbourNode(acc, origin,
Coord(0, 0, -LeafNodeType::DIM));
754 Coord ijk = start + step;
759 if (node)
return static_cast<size_t>(node->origin()[0]);
768 TreeType
const *
const mTree;
769 Coord const *
const mCoordinates;
770 size_t *
const mOffsets;
772 const size_t mNumNodes;
777 template<
typename TreeType>
786 mLeafNodes.reserve(tree.leafCount());
787 tree.getNodes(mLeafNodes);
789 if (mLeafNodes.empty())
return;
792 tree.evalLeafBoundingBox(bbox);
794 const tbb::blocked_range<size_t> range(0, mLeafNodes.size());
798 std::unique_ptr<Coord[]> coordinates{
new Coord[mLeafNodes.size()]};
799 tbb::parallel_for(range,
803 mOffsets.reset(
new size_t[mLeafNodes.size() * 6]);
807 tree, coordinates.get(), mOffsets.get(), mLeafNodes.size(), bbox));
813 size_t size()
const {
return mLeafNodes.size(); }
815 std::vector<LeafNodeType*>&
nodes() {
return mLeafNodes; }
816 const std::vector<LeafNodeType*>&
nodes()
const {
return mLeafNodes; }
820 const size_t*
offsetsPrevX()
const {
return mOffsets.get() + mLeafNodes.size(); }
822 const size_t*
offsetsNextY()
const {
return mOffsets.get() + mLeafNodes.size() * 2; }
823 const size_t*
offsetsPrevY()
const {
return mOffsets.get() + mLeafNodes.size() * 3; }
825 const size_t*
offsetsNextZ()
const {
return mOffsets.get() + mLeafNodes.size() * 4; }
826 const size_t*
offsetsPrevZ()
const {
return mOffsets.get() + mLeafNodes.size() * 5; }
829 std::vector<LeafNodeType*> mLeafNodes;
830 std::unique_ptr<size_t[]> mOffsets;
834 template<
typename TreeType>
847 : mStartNodeIndices(startNodeIndices.empty() ? nullptr : &startNodeIndices[0])
848 , mConnectivity(&connectivity)
853 void operator()(
const tbb::blocked_range<size_t>& range)
const {
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();
868 step = LeafNodeType::DIM;
870 nextOffsets = mConnectivity->offsetsNextY();
871 prevOffsets = mConnectivity->offsetsPrevY();
873 }
else if (mAxis ==
X_AXIS) {
877 step = LeafNodeType::DIM * LeafNodeType::DIM;
879 nextOffsets = mConnectivity->offsetsNextX();
880 prevOffsets = mConnectivity->offsetsPrevX();
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 < int(LeafNodeType::DIM); ++a) {
896 for (b = 0; b < int(LeafNodeType::DIM); ++b) {
898 pos = 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 * (LeafNodeType::DIM - 1);
919 while ( offset != ConnectivityTable::INVALID_OFFSET &&
920 traceVoxelLine(*nodes[offset], pos, -step)) {
921 offset = prevOffsets[offset];
933 bool isOutside =
true;
935 for (
Index i = 0; i < LeafNodeType::DIM; ++i) {
943 if (!(dist >
ValueType(0.75))) isOutside =
false;
956 size_t const *
const mStartNodeIndices;
957 ConnectivityTable *
const mConnectivity;
963 template<
typename LeafNodeType>
967 using ValueType =
typename LeafNodeType::ValueType;
968 using Queue = std::deque<Index>;
971 ValueType* data = node.buffer().data();
975 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
976 if (data[pos] < 0.0) seedPoints.push_back(pos);
979 if (seedPoints.empty())
return;
982 for (Queue::iterator it = seedPoints.begin(); it != seedPoints.end(); ++it) {
983 ValueType& dist = data[*it];
990 Index pos(0), nextPos(0);
992 while (!seedPoints.empty()) {
994 pos = seedPoints.back();
995 seedPoints.pop_back();
997 ValueType& dist = data[pos];
999 if (!(dist < ValueType(0.0))) {
1003 ijk = LeafNodeType::offsetToLocalCoord(pos);
1006 nextPos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
1007 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1010 if (ijk[0] != (LeafNodeType::DIM - 1)) {
1011 nextPos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
1012 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1016 nextPos = pos - LeafNodeType::DIM;
1017 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1020 if (ijk[1] != (LeafNodeType::DIM - 1)) {
1021 nextPos = pos + LeafNodeType::DIM;
1022 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1027 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1030 if (ijk[2] != (LeafNodeType::DIM - 1)) {
1032 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1039 template<
typename LeafNodeType>
1043 bool updatedNode =
false;
1045 using ValueType =
typename LeafNodeType::ValueType;
1046 ValueType* data = node.buffer().data();
1050 bool updatedSign =
true;
1051 while (updatedSign) {
1053 updatedSign =
false;
1055 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
1057 ValueType& dist = data[pos];
1059 if (!(dist < ValueType(0.0)) && dist > ValueType(0.75)) {
1061 ijk = LeafNodeType::offsetToLocalCoord(pos);
1064 if (ijk[2] != 0 && data[pos - 1] < ValueType(0.0)) {
1066 dist = ValueType(-dist);
1069 }
else if (ijk[2] != (LeafNodeType::DIM - 1) && data[pos + 1] < ValueType(0.0)) {
1071 dist = ValueType(-dist);
1074 }
else if (ijk[1] != 0 && data[pos - LeafNodeType::DIM] < ValueType(0.0)) {
1076 dist = ValueType(-dist);
1079 }
else if (ijk[1] != (LeafNodeType::DIM - 1)
1080 && data[pos + LeafNodeType::DIM] < ValueType(0.0))
1083 dist = ValueType(-dist);
1086 }
else if (ijk[0] != 0
1087 && data[pos - LeafNodeType::DIM * LeafNodeType::DIM] < ValueType(0.0))
1090 dist = ValueType(-dist);
1093 }
else if (ijk[0] != (LeafNodeType::DIM - 1)
1094 && data[pos + LeafNodeType::DIM * LeafNodeType::DIM] < ValueType(0.0))
1097 dist = ValueType(-dist);
1102 updatedNode |= updatedSign;
1109 template<
typename TreeType>
1117 : mNodes(nodes.empty() ? nullptr : &nodes[0])
1118 , mChangedNodeMask(changedNodeMask)
1123 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1124 if (mChangedNodeMask[n]) {
1126 mChangedNodeMask[n] =
scanFill(*mNodes[n]);
1136 template<
typename ValueType>
1139 FillArray(ValueType* array,
const ValueType v) : mArray(array), mValue(v) { }
1142 const ValueType v = mValue;
1143 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1153 template<
typename ValueType>
1155 fillArray(ValueType* array,
const ValueType val,
const size_t length)
1157 const auto grainSize = std::max<size_t>(
1158 length / tbb::task_scheduler_init::default_num_threads(), 1024);
1159 const tbb::blocked_range<size_t> range(0, length, grainSize);
1164 template<
typename TreeType>
1172 const bool* changedNodeMask,
bool* changedVoxelMask)
1173 : mNodes(nodes.empty() ? nullptr : &nodes[0])
1174 , mChangedNodeMask(changedNodeMask)
1175 , mChangedVoxelMask(changedVoxelMask)
1180 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1182 if (mChangedNodeMask[n]) {
1183 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1185 ValueType* data = mNodes[n]->buffer().data();
1187 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
1203 template<
typename TreeType>
1212 bool* changedNodeMask,
bool* nodeMask,
bool* changedVoxelMask)
1213 : mConnectivity(&connectivity)
1214 , mChangedNodeMask(changedNodeMask)
1215 , mNodeMask(nodeMask)
1216 , mChangedVoxelMask(changedVoxelMask)
1222 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1224 if (!mChangedNodeMask[n]) {
1226 bool changedValue =
false;
1228 changedValue |= processZ(n,
true);
1229 changedValue |= processZ(n,
false);
1231 changedValue |= processY(n,
true);
1232 changedValue |= processY(n,
false);
1234 changedValue |= processX(n,
true);
1235 changedValue |= processX(n,
false);
1237 mNodeMask[n] = changedValue;
1245 const size_t offset =
1246 firstFace ? mConnectivity->offsetsPrevZ()[n] : mConnectivity->offsetsNextZ()[n];
1247 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1249 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1251 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1252 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1254 const Index lastOffset = LeafNodeType::DIM - 1;
1255 const Index lhsOffset =
1256 firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1258 Index tmpPos(0), pos(0);
1259 bool changedValue =
false;
1261 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
1262 tmpPos = x << (2 * LeafNodeType::LOG2DIM);
1263 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
1264 pos = tmpPos + (y << LeafNodeType::LOG2DIM);
1266 if (lhsData[pos + lhsOffset] >
ValueType(0.75)) {
1267 if (rhsData[pos + rhsOffset] <
ValueType(0.0)) {
1268 changedValue =
true;
1269 mask[pos + lhsOffset] =
true;
1275 return changedValue;
1283 const size_t offset =
1284 firstFace ? mConnectivity->offsetsPrevY()[n] : mConnectivity->offsetsNextY()[n];
1285 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1287 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1289 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1290 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1292 const Index lastOffset = LeafNodeType::DIM * (LeafNodeType::DIM - 1);
1293 const Index lhsOffset =
1294 firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1296 Index tmpPos(0), pos(0);
1297 bool changedValue =
false;
1299 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
1300 tmpPos = x << (2 * LeafNodeType::LOG2DIM);
1301 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
1304 if (lhsData[pos + lhsOffset] >
ValueType(0.75)) {
1305 if (rhsData[pos + rhsOffset] <
ValueType(0.0)) {
1306 changedValue =
true;
1307 mask[pos + lhsOffset] =
true;
1313 return changedValue;
1321 const size_t offset =
1322 firstFace ? mConnectivity->offsetsPrevX()[n] : mConnectivity->offsetsNextX()[n];
1323 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1325 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1327 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1328 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1330 const Index lastOffset = LeafNodeType::DIM * LeafNodeType::DIM * (LeafNodeType::DIM-1);
1331 const Index lhsOffset =
1332 firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1334 Index tmpPos(0), pos(0);
1335 bool changedValue =
false;
1337 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
1338 tmpPos = y << LeafNodeType::LOG2DIM;
1339 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
1342 if (lhsData[pos + lhsOffset] >
ValueType(0.75)) {
1343 if (rhsData[pos + rhsOffset] <
ValueType(0.0)) {
1344 changedValue =
true;
1345 mask[pos + lhsOffset] =
true;
1351 return changedValue;
1366 template<
typename TreeType,
typename MeshDataAdapter>
1380 std::vector<LeafNodeType*>& distNodes,
1381 const TreeType& distTree,
1384 : mDistNodes(distNodes.empty() ? nullptr : &distNodes[0])
1385 , mDistTree(&distTree)
1386 , mIndexTree(&indexTree)
1400 Index xPos(0), yPos(0);
1401 Coord ijk, nijk, nodeMin, nodeMax;
1402 Vec3d cp, xyz, nxyz, dir1, dir2;
1404 LocalData& localData = mLocalDataTable->local();
1407 if (!points) points.reset(
new Vec3d[LeafNodeType::SIZE * 2]);
1410 if (!mask) mask.reset(
new bool[LeafNodeType::SIZE]);
1413 typename LeafNodeType::ValueOnCIter it;
1415 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1421 const Int32* idxData = idxNode->buffer().data();
1423 nodeMin = node.origin();
1424 nodeMax = nodeMin.
offsetBy(LeafNodeType::DIM - 1);
1427 memset(mask.get(), 0,
sizeof(bool) * LeafNodeType::SIZE);
1429 for (it = node.cbeginValueOn(); it; ++it) {
1430 Index pos = it.pos();
1433 if (dist < 0.0 || dist > 0.75)
continue;
1435 ijk = node.offsetToGlobalCoord(pos);
1437 xyz[0] = double(ijk[0]);
1438 xyz[1] = double(ijk[1]);
1439 xyz[2] = double(ijk[2]);
1445 bool flipSign =
false;
1447 for (nijk[0] = bbox.
min()[0]; nijk[0] <= bbox.
max()[0] && !flipSign; ++nijk[0]) {
1448 xPos = (nijk[0] & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
1449 for (nijk[1]=bbox.
min()[1]; nijk[1] <= bbox.
max()[1] && !flipSign; ++nijk[1]) {
1450 yPos = xPos + ((nijk[1] & (LeafNodeType::DIM-1u)) << LeafNodeType::LOG2DIM);
1451 for (nijk[2] = bbox.
min()[2]; nijk[2] <= bbox.
max()[2]; ++nijk[2]) {
1452 pos = yPos + (nijk[2] & (LeafNodeType::DIM - 1u));
1454 const Int32& polyIdx = idxData[pos];
1459 const Index pointIndex = pos * 2;
1465 nxyz[0] = double(nijk[0]);
1466 nxyz[1] = double(nijk[1]);
1467 nxyz[2] = double(nijk[2]);
1469 Vec3d& point = points[pointIndex];
1471 point = closestPoint(nxyz, polyIdx);
1473 Vec3d& direction = points[pointIndex + 1];
1474 direction = nxyz - point;
1475 direction.normalize();
1478 dir1 = xyz - points[pointIndex];
1481 if (points[pointIndex + 1].dot(dir1) > 0.0) {
1492 for (
Int32 m = 0; m < 26; ++m) {
1496 nxyz[0] = double(nijk[0]);
1497 nxyz[1] = double(nijk[1]);
1498 nxyz[2] = double(nijk[2]);
1500 cp = closestPoint(nxyz, idxAcc.
getValue(nijk));
1508 if (dir2.dot(dir1) > 0.0) {
1524 Vec3d a, b, c, cp, uvw;
1526 const size_t polygon = size_t(polyIdx);
1527 mMesh->getIndexSpacePoint(polygon, 0, a);
1528 mMesh->getIndexSpacePoint(polygon, 1, b);
1529 mMesh->getIndexSpacePoint(polygon, 2, c);
1533 if (4 == mMesh->vertexCount(polygon)) {
1535 mMesh->getIndexSpacePoint(polygon, 3, b);
1539 if ((center - c).lengthSqr() < (center - cp).lengthSqr()) {
1548 LeafNodeType **
const mDistNodes;
1549 TreeType
const *
const mDistTree;
1550 Int32TreeType
const *
const mIndexTree;
1560 template<
typename LeafNodeType>
1564 using NodeT = LeafNodeType;
1566 const Coord ijk = NodeT::offsetToLocalCoord(pos);
1570 mask[0] = ijk[0] != (NodeT::DIM - 1);
1572 mask[1] = ijk[0] != 0;
1574 mask[2] = ijk[1] != (NodeT::DIM - 1);
1576 mask[3] = ijk[1] != 0;
1578 mask[4] = ijk[2] != (NodeT::DIM - 1);
1580 mask[5] = ijk[2] != 0;
1584 mask[6] = mask[0] && mask[5];
1586 mask[7] = mask[1] && mask[5];
1588 mask[8] = mask[0] && mask[4];
1590 mask[9] = mask[1] && mask[4];
1592 mask[10] = mask[0] && mask[2];
1594 mask[11] = mask[1] && mask[2];
1596 mask[12] = mask[0] && mask[3];
1598 mask[13] = mask[1] && mask[3];
1600 mask[14] = mask[3] && mask[4];
1602 mask[15] = mask[3] && mask[5];
1604 mask[16] = mask[2] && mask[4];
1606 mask[17] = mask[2] && mask[5];
1610 mask[18] = mask[1] && mask[3] && mask[5];
1612 mask[19] = mask[1] && mask[3] && mask[4];
1614 mask[20] = mask[0] && mask[3] && mask[4];
1616 mask[21] = mask[0] && mask[3] && mask[5];
1618 mask[22] = mask[1] && mask[2] && mask[5];
1620 mask[23] = mask[1] && mask[2] && mask[4];
1622 mask[24] = mask[0] && mask[2] && mask[4];
1624 mask[25] = mask[0] && mask[2] && mask[5];
1628 template<
typename Compare,
typename LeafNodeType>
1632 using NodeT = LeafNodeType;
1635 if (mask[5] && Compare::check(data[pos - 1]))
return true;
1637 if (mask[4] && Compare::check(data[pos + 1]))
return true;
1639 if (mask[3] && Compare::check(data[pos - NodeT::DIM]))
return true;
1641 if (mask[2] && Compare::check(data[pos + NodeT::DIM]))
return true;
1643 if (mask[1] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM]))
return true;
1645 if (mask[0] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM]))
return true;
1647 if (mask[6] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM]))
return true;
1649 if (mask[7] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - 1]))
return true;
1651 if (mask[8] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + 1]))
return true;
1653 if (mask[9] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + 1]))
return true;
1655 if (mask[10] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM]))
return true;
1657 if (mask[11] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM]))
return true;
1659 if (mask[12] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM]))
return true;
1661 if (mask[13] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM]))
return true;
1663 if (mask[14] && Compare::check(data[pos - NodeT::DIM + 1]))
return true;
1665 if (mask[15] && Compare::check(data[pos - NodeT::DIM - 1]))
return true;
1667 if (mask[16] && Compare::check(data[pos + NodeT::DIM + 1]))
return true;
1669 if (mask[17] && Compare::check(data[pos + NodeT::DIM - 1]))
return true;
1671 if (mask[18] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM - 1]))
return true;
1673 if (mask[19] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM + 1]))
return true;
1675 if (mask[20] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM + 1]))
return true;
1677 if (mask[21] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM - 1]))
return true;
1679 if (mask[22] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM - 1]))
return true;
1681 if (mask[23] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM + 1]))
return true;
1683 if (mask[24] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM + 1]))
return true;
1685 if (mask[25] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM - 1]))
return true;
1691 template<
typename Compare,
typename AccessorType>
1695 for (
Int32 m = 0; m < 26; ++m) {
1705 template<
typename TreeType>
1715 , mNodes(nodes.empty() ? nullptr : &nodes[0])
1722 bool neighbourMask[26];
1724 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1729 typename LeafNodeType::ValueOnCIter it;
1730 for (it = node.cbeginValueOn(); it; ++it) {
1732 const Index pos = it.pos();
1735 if (dist < 0.0 || dist > 0.75)
continue;
1738 maskNodeInternalNeighbours<LeafNodeType>(pos, neighbourMask);
1740 const bool hasNegativeNeighbour =
1741 checkNeighbours<IsNegative, LeafNodeType>(pos, data, neighbourMask) ||
1742 checkNeighbours<IsNegative>(node.offsetToGlobalCoord(pos), acc, neighbourMask);
1744 if (!hasNegativeNeighbour) {
1757 template<
typename TreeType>
1768 : mNodes(nodes.empty() ? nullptr : &nodes[0])
1769 , mDistTree(&distTree)
1770 , mIndexTree(&indexTree)
1778 bool neighbourMask[26];
1780 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1783 ValueType* data = distNode.buffer().data();
1785 typename Int32TreeType::LeafNodeType* idxNode =
1788 typename LeafNodeType::ValueOnCIter it;
1789 for (it = distNode.cbeginValueOn(); it; ++it) {
1791 const Index pos = it.pos();
1793 if (!(data[pos] > 0.75))
continue;
1796 maskNodeInternalNeighbours<LeafNodeType>(pos, neighbourMask);
1798 const bool hasBoundaryNeighbour =
1799 checkNeighbours<Comp, LeafNodeType>(pos, data, neighbourMask) ||
1800 checkNeighbours<Comp>(distNode.offsetToGlobalCoord(pos),distAcc,neighbourMask);
1802 if (!hasBoundaryNeighbour) {
1803 distNode.setValueOff(pos);
1804 idxNode->setValueOff(pos);
1819 template<
typename NodeType>
1826 using NodeMaskType =
typename NodeType::NodeMaskType;
1828 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1829 const_cast<NodeMaskType&>(mNodes[n]->getChildMask()).setOff();
1837 template<
typename TreeType>
1841 using RootNodeType =
typename TreeType::RootNodeType;
1842 using NodeChainType =
typename RootNodeType::NodeChainType;
1843 using InternalNodeType =
typename boost::mpl::at<NodeChainType, boost::mpl::int_<1> >::type;
1845 std::vector<InternalNodeType*> nodes;
1846 tree.getNodes(nodes);
1848 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
1853 template<
typename TreeType>
1859 std::vector<LeafNodeType*>& overlappingNodes)
1860 : mLhsTree(&lhsTree)
1861 , mRhsTree(&rhsTree)
1862 , mNodes(&overlappingNodes)
1868 std::vector<LeafNodeType*> rhsLeafNodes;
1870 rhsLeafNodes.reserve(mRhsTree->leafCount());
1873 mRhsTree->stealNodes(rhsLeafNodes);
1877 for (
size_t n = 0, N = rhsLeafNodes.size(); n < N; ++n) {
1878 if (!acc.
probeLeaf(rhsLeafNodes[n]->origin())) {
1881 mNodes->push_back(rhsLeafNodes[n]);
1887 TreeType *
const mLhsTree;
1888 TreeType *
const mRhsTree;
1889 std::vector<LeafNodeType*> *
const mNodes;
1893 template<
typename DistTreeType,
typename IndexTreeType>
1896 DistTreeType& rhsDist, IndexTreeType& rhsIdx)
1898 using DistLeafNodeType =
typename DistTreeType::LeafNodeType;
1899 using IndexLeafNodeType =
typename IndexTreeType::LeafNodeType;
1901 std::vector<DistLeafNodeType*> overlappingDistNodes;
1902 std::vector<IndexLeafNodeType*> overlappingIdxNodes;
1905 tbb::task_group tasks;
1911 if (!overlappingDistNodes.empty() && !overlappingIdxNodes.empty()) {
1912 tbb::parallel_for(tbb::blocked_range<size_t>(0, overlappingDistNodes.size()),
1914 &overlappingDistNodes[0], &overlappingIdxNodes[0]));
1924 template<
typename TreeType>
1927 using Ptr = std::unique_ptr<VoxelizationData>;
1931 using UCharTreeType =
typename TreeType::template ValueConverter<unsigned char>::Type;
1942 , indexAcc(indexTree)
1943 , primIdTree(MaxPrimId)
1944 , primIdAcc(primIdTree)
1960 if (mPrimCount == MaxPrimId || primIdTree.leafCount() > 1000) {
1965 return mPrimCount++;
1970 enum { MaxPrimId = 100 };
1972 unsigned char mPrimCount;
1976 template<
typename TreeType,
typename MeshDataAdapter,
typename Interrupter = util::NullInterrupter>
1982 using DataTable = tbb::enumerable_thread_specific<typename VoxelizationDataType::Ptr>;
1986 Interrupter* interrupter =
nullptr)
1987 : mDataTable(&dataTable)
1989 , mInterrupter(interrupter)
2000 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2003 tbb::task::self().cancel_group_execution();
2007 const size_t numVerts = mMesh->vertexCount(n);
2010 if (numVerts == 3 || numVerts == 4) {
2012 prim.index =
Int32(n);
2014 mMesh->getIndexSpacePoint(n, 0, prim.a);
2015 mMesh->getIndexSpacePoint(n, 1, prim.b);
2016 mMesh->getIndexSpacePoint(n, 2, prim.c);
2018 evalTriangle(prim, *dataPtr);
2020 if (numVerts == 4) {
2021 mMesh->getIndexSpacePoint(n, 3, prim.b);
2022 evalTriangle(prim, *dataPtr);
2030 bool wasInterrupted()
const {
return mInterrupter && mInterrupter->wasInterrupted(); }
2032 struct Triangle {
Vec3d a, b, c;
Int32 index; };
2036 enum { POLYGON_LIMIT = 1000 };
2038 SubTask(
const Triangle& prim, DataTable& dataTable,
2039 int subdivisionCount,
size_t polygonCount,
2040 Interrupter* interrupter =
nullptr)
2041 : mLocalDataTable(&dataTable)
2043 , mSubdivisionCount(subdivisionCount)
2044 , mPolygonCount(polygonCount)
2045 , mInterrupter(interrupter)
2049 void operator()()
const 2051 if (mSubdivisionCount <= 0 || mPolygonCount >= POLYGON_LIMIT) {
2053 typename VoxelizationDataType::Ptr& dataPtr = mLocalDataTable->local();
2054 if (!dataPtr) dataPtr.reset(
new VoxelizationDataType());
2056 voxelizeTriangle(mPrim, *dataPtr);
2058 }
else if (!(mInterrupter && mInterrupter->wasInterrupted())) {
2059 spawnTasks(mPrim, *mLocalDataTable, mSubdivisionCount, mPolygonCount, mInterrupter);
2063 DataTable *
const mLocalDataTable;
2064 Triangle
const mPrim;
2065 int const mSubdivisionCount;
2066 size_t const mPolygonCount;
2067 Interrupter *
const mInterrupter;
2070 inline static int evalSubdivisionCount(
const Triangle& prim)
2072 const double ax = prim.a[0], bx = prim.b[0], cx = prim.c[0];
2075 const double ay = prim.a[1], by = prim.b[1], cy = prim.c[1];
2078 const double az = prim.a[2], bz = prim.b[2], cz = prim.c[2];
2081 return int(
std::max(dx,
std::max(dy, dz)) /
double(TreeType::LeafNodeType::DIM * 2));
2084 void evalTriangle(
const Triangle& prim, VoxelizationDataType& data)
const 2086 const size_t polygonCount = mMesh->polygonCount();
2087 const int subdivisionCount =
2088 polygonCount < SubTask::POLYGON_LIMIT ? evalSubdivisionCount(prim) : 0;
2090 if (subdivisionCount <= 0) {
2091 voxelizeTriangle(prim, data);
2093 spawnTasks(prim, *mDataTable, subdivisionCount, polygonCount, mInterrupter);
2097 static void spawnTasks(
2098 const Triangle& mainPrim,
2099 DataTable& dataTable,
2100 int subdivisionCount,
2101 size_t polygonCount,
2102 Interrupter*
const interrupter)
2104 subdivisionCount -= 1;
2107 tbb::task_group tasks;
2109 const Vec3d ac = (mainPrim.a + mainPrim.c) * 0.5;
2110 const Vec3d bc = (mainPrim.b + mainPrim.c) * 0.5;
2111 const Vec3d ab = (mainPrim.a + mainPrim.b) * 0.5;
2114 prim.index = mainPrim.index;
2116 prim.a = mainPrim.a;
2119 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount, interrupter));
2124 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount, interrupter));
2127 prim.b = mainPrim.b;
2129 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount, interrupter));
2133 prim.c = mainPrim.c;
2134 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount, interrupter));
2139 static void voxelizeTriangle(
const Triangle& prim, VoxelizationDataType& data)
2141 std::deque<Coord> coordList;
2145 coordList.push_back(ijk);
2147 computeDistance(ijk, prim, data);
2149 unsigned char primId = data.getNewPrimId();
2150 data.primIdAcc.setValueOnly(ijk, primId);
2152 while (!coordList.empty()) {
2153 ijk = coordList.back();
2154 coordList.pop_back();
2156 for (
Int32 i = 0; i < 26; ++i) {
2158 if (primId != data.primIdAcc.getValue(nijk)) {
2159 data.primIdAcc.setValueOnly(nijk, primId);
2160 if(computeDistance(nijk, prim, data)) coordList.push_back(nijk);
2166 static bool computeDistance(
const Coord& ijk,
const Triangle& prim, VoxelizationDataType& data)
2168 Vec3d uvw, voxelCenter(ijk[0], ijk[1], ijk[2]);
2170 using ValueType =
typename TreeType::ValueType;
2172 const ValueType dist = ValueType((voxelCenter -
2175 const ValueType oldDist = data.distAcc.getValue(ijk);
2177 if (dist < oldDist) {
2178 data.distAcc.setValue(ijk, dist);
2179 data.indexAcc.setValue(ijk, prim.index);
2183 data.indexAcc.setValueOnly(ijk,
std::min(prim.index, data.indexAcc.getValue(ijk)));
2186 return !(dist > 0.75);
2189 DataTable *
const mDataTable;
2191 Interrupter *
const mInterrupter;
2198 template<
typename TreeType>
2204 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2208 std::vector<BoolLeafNodeType*>& lhsNodes)
2209 : mRhsTree(&rhsTree), mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes[0])
2217 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2222 if (rhsNode) lhsNode->topologyDifference(*rhsNode,
false);
2227 TreeType
const *
const mRhsTree;
2228 BoolLeafNodeType **
const mLhsNodes;
2232 template<
typename LeafNodeTypeA,
typename LeafNodeTypeB>
2236 : mNodesA(nodesA.empty() ? nullptr : &nodesA[0])
2237 , mNodesB(nodesB.empty() ? nullptr : &nodesB[0])
2242 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2243 mNodesA[n]->topologyUnion(*mNodesB[n]);
2248 LeafNodeTypeA **
const mNodesA;
2249 LeafNodeTypeB **
const mNodesB;
2253 template<
typename TreeType>
2258 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2262 std::vector<LeafNodeType*>& nodes)
2264 , mNodes(nodes.empty() ? nullptr : &nodes[0])
2265 , mLocalMaskTree(false)
2266 , mMaskTree(&maskTree)
2272 , mNodes(rhs.mNodes)
2273 , mLocalMaskTree(false)
2274 , mMaskTree(&mLocalMaskTree)
2280 using Iterator =
typename LeafNodeType::ValueOnCIter;
2285 Coord ijk, nijk, localCorod;
2288 for (
size_t n = range.begin(); n != range.end(); ++n) {
2292 CoordBBox bbox = node.getNodeBoundingBox();
2297 for (Iterator it = node.cbeginValueOn(); it; ++it) {
2298 ijk = it.getCoord();
2301 localCorod = LeafNodeType::offsetToLocalCoord(pos);
2303 if (localCorod[2] <
int(LeafNodeType::DIM - 1)) {
2305 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2311 if (localCorod[2] > 0) {
2313 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2319 if (localCorod[1] <
int(LeafNodeType::DIM - 1)) {
2320 npos = pos + LeafNodeType::DIM;
2321 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2327 if (localCorod[1] > 0) {
2328 npos = pos - LeafNodeType::DIM;
2329 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2335 if (localCorod[0] <
int(LeafNodeType::DIM - 1)) {
2336 npos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
2337 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2343 if (localCorod[0] > 0) {
2344 npos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
2345 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2357 TreeType
const *
const mTree;
2358 LeafNodeType **
const mNodes;
2360 BoolTreeType mLocalMaskTree;
2361 BoolTreeType *
const mMaskTree;
2366 template<
typename TreeType,
typename MeshDataAdapter>
2374 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2385 : idx(idx_), x(x_), y(y_), z(z_), dist(dist_)
2395 std::vector<BoolLeafNodeType*>& maskNodes,
2403 : mMaskNodes(maskNodes.empty() ? nullptr : &maskNodes[0])
2404 , mMaskTree(&maskTree)
2405 , mDistTree(&distTree)
2406 , mIndexTree(&indexTree)
2408 , mNewMaskTree(false)
2410 , mUpdatedDistNodes()
2412 , mUpdatedIndexNodes()
2413 , mExteriorBandWidth(exteriorBandWidth)
2414 , mInteriorBandWidth(interiorBandWidth)
2415 , mVoxelSize(voxelSize)
2420 : mMaskNodes(rhs.mMaskNodes)
2421 , mMaskTree(rhs.mMaskTree)
2422 , mDistTree(rhs.mDistTree)
2423 , mIndexTree(rhs.mIndexTree)
2425 , mNewMaskTree(false)
2427 , mUpdatedDistNodes()
2429 , mUpdatedIndexNodes()
2430 , mExteriorBandWidth(rhs.mExteriorBandWidth)
2431 , mInteriorBandWidth(rhs.mInteriorBandWidth)
2432 , mVoxelSize(rhs.mVoxelSize)
2438 mDistNodes.insert(mDistNodes.end(), rhs.mDistNodes.begin(), rhs.mDistNodes.end());
2439 mIndexNodes.insert(mIndexNodes.end(), rhs.mIndexNodes.begin(), rhs.mIndexNodes.end());
2441 mUpdatedDistNodes.insert(mUpdatedDistNodes.end(),
2442 rhs.mUpdatedDistNodes.begin(), rhs.mUpdatedDistNodes.end());
2444 mUpdatedIndexNodes.insert(mUpdatedIndexNodes.end(),
2445 rhs.mUpdatedIndexNodes.begin(), rhs.mUpdatedIndexNodes.end());
2447 mNewMaskTree.merge(rhs.mNewMaskTree);
2456 std::vector<Fragment> fragments;
2457 fragments.reserve(256);
2459 std::unique_ptr<LeafNodeType> newDistNodePt;
2460 std::unique_ptr<Int32LeafNodeType> newIndexNodePt;
2462 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2465 if (maskNode.isEmpty())
continue;
2469 const Coord& origin = maskNode.origin();
2474 assert(!distNodePt == !indexNodePt);
2476 bool usingNewNodes =
false;
2478 if (!distNodePt && !indexNodePt) {
2482 if (!newDistNodePt.get() && !newIndexNodePt.get()) {
2483 newDistNodePt.reset(
new LeafNodeType(origin, backgroundDist));
2487 if ((backgroundDist <
ValueType(0.0)) !=
2488 (newDistNodePt->getValue(0) <
ValueType(0.0))) {
2489 newDistNodePt->buffer().fill(backgroundDist);
2492 newDistNodePt->setOrigin(origin);
2493 newIndexNodePt->setOrigin(origin);
2496 distNodePt = newDistNodePt.get();
2497 indexNodePt = newIndexNodePt.get();
2499 usingNewNodes =
true;
2506 for (
typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
2507 bbox.
expand(it.getCoord());
2512 gatherFragments(fragments, bbox, distAcc, indexAcc);
2517 bbox = maskNode.getNodeBoundingBox();
2519 bool updatedLeafNodes =
false;
2521 for (
typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
2523 const Coord ijk = it.getCoord();
2525 if (updateVoxel(ijk, 5, fragments, *distNodePt, *indexNodePt, &updatedLeafNodes)) {
2527 for (
Int32 i = 0; i < 6; ++i) {
2530 mask.setOn(BoolLeafNodeType::coordToOffset(nijk));
2536 for (
Int32 i = 6; i < 26; ++i) {
2539 mask.setOn(BoolLeafNodeType::coordToOffset(nijk));
2545 if (updatedLeafNodes) {
2548 mask -= indexNodePt->getValueMask();
2550 for (
typename NodeMaskType::OnIterator it = mask.beginOn(); it; ++it) {
2552 const Index pos = it.pos();
2553 const Coord ijk = maskNode.origin() + LeafNodeType::offsetToLocalCoord(pos);
2555 if (updateVoxel(ijk, 6, fragments, *distNodePt, *indexNodePt)) {
2556 for (
Int32 i = 0; i < 6; ++i) {
2563 if (usingNewNodes) {
2564 newDistNodePt->topologyUnion(*newIndexNodePt);
2565 mDistNodes.push_back(newDistNodePt.release());
2566 mIndexNodes.push_back(newIndexNodePt.release());
2568 mUpdatedDistNodes.push_back(distNodePt);
2569 mUpdatedIndexNodes.push_back(indexNodePt);
2589 gatherFragments(std::vector<Fragment>& fragments,
const CoordBBox& bbox,
2593 const Coord nodeMin = bbox.
min() & ~(LeafNodeType::DIM - 1);
2594 const Coord nodeMax = bbox.
max() & ~(LeafNodeType::DIM - 1);
2599 for (ijk[0] = nodeMin[0]; ijk[0] <= nodeMax[0]; ijk[0] += LeafNodeType::DIM) {
2600 for (ijk[1] = nodeMin[1]; ijk[1] <= nodeMax[1]; ijk[1] += LeafNodeType::DIM) {
2601 for (ijk[2] = nodeMin[2]; ijk[2] <= nodeMax[2]; ijk[2] += LeafNodeType::DIM) {
2602 if (LeafNodeType* distleaf = distAcc.
probeLeaf(ijk)) {
2605 ijk.
offsetBy(LeafNodeType::DIM - 1));
2606 gatherFragments(fragments, region, *distleaf, *indexAcc.
probeLeaf(ijk));
2612 std::sort(fragments.begin(), fragments.end());
2616 gatherFragments(std::vector<Fragment>& fragments,
const CoordBBox& bbox,
2617 const LeafNodeType& distLeaf,
const Int32LeafNodeType& idxLeaf)
const 2619 const typename LeafNodeType::NodeMaskType& mask = distLeaf.getValueMask();
2620 const ValueType* distData = distLeaf.buffer().data();
2621 const Int32* idxData = idxLeaf.buffer().data();
2623 for (
int x = bbox.min()[0]; x <= bbox.max()[0]; ++x) {
2624 const Index xPos = (x & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
2625 for (
int y = bbox.min()[1]; y <= bbox.max()[1]; ++y) {
2626 const Index yPos = xPos + ((y & (LeafNodeType::DIM - 1u)) << LeafNodeType::LOG2DIM);
2627 for (
int z = bbox.min()[2]; z <= bbox.max()[2]; ++z) {
2628 const Index pos = yPos + (z & (LeafNodeType::DIM - 1u));
2629 if (mask.isOn(pos)) {
2630 fragments.push_back(Fragment(idxData[pos],x,y,z, std::abs(distData[pos])));
2640 computeDistance(
const Coord& ijk,
const Int32 manhattanLimit,
2641 const std::vector<Fragment>& fragments,
Int32& closestPrimIdx)
const 2643 Vec3d a, b, c, uvw, voxelCenter(ijk[0], ijk[1], ijk[2]);
2647 for (
size_t n = 0, N = fragments.size(); n < N; ++n) {
2649 const Fragment& fragment = fragments[n];
2650 if (lastIdx == fragment.idx)
continue;
2652 const Int32 dx = std::abs(fragment.x - ijk[0]);
2653 const Int32 dy = std::abs(fragment.y - ijk[1]);
2654 const Int32 dz = std::abs(fragment.z - ijk[2]);
2656 const Int32 manhattan = dx + dy + dz;
2657 if (manhattan > manhattanLimit)
continue;
2659 lastIdx = fragment.idx;
2661 const size_t polygon = size_t(lastIdx);
2663 mMesh->getIndexSpacePoint(polygon, 0, a);
2664 mMesh->getIndexSpacePoint(polygon, 1, b);
2665 mMesh->getIndexSpacePoint(polygon, 2, c);
2667 primDist = (voxelCenter -
2671 if (4 == mMesh->vertexCount(polygon)) {
2673 mMesh->getIndexSpacePoint(polygon, 3, b);
2676 a, b, c, voxelCenter, uvw)).lengthSqr();
2678 if (tmpDist < primDist) primDist = tmpDist;
2681 if (primDist < dist) {
2683 closestPrimIdx = lastIdx;
2687 return ValueType(std::sqrt(dist)) * mVoxelSize;
2693 updateVoxel(
const Coord& ijk,
const Int32 manhattanLimit,
2694 const std::vector<Fragment>& fragments,
2695 LeafNodeType& distLeaf, Int32LeafNodeType& idxLeaf,
bool* updatedLeafNodes =
nullptr)
2697 Int32 closestPrimIdx = 0;
2698 const ValueType distance = computeDistance(ijk, manhattanLimit, fragments, closestPrimIdx);
2700 const Index pos = LeafNodeType::coordToOffset(ijk);
2701 const bool inside = distLeaf.getValue(pos) < ValueType(0.0);
2703 bool activateNeighbourVoxels =
false;
2705 if (!inside && distance < mExteriorBandWidth) {
2706 if (updatedLeafNodes) *updatedLeafNodes =
true;
2707 activateNeighbourVoxels = (distance + mVoxelSize) < mExteriorBandWidth;
2708 distLeaf.setValueOnly(pos, distance);
2709 idxLeaf.setValueOn(pos, closestPrimIdx);
2710 }
else if (inside && distance < mInteriorBandWidth) {
2711 if (updatedLeafNodes) *updatedLeafNodes =
true;
2712 activateNeighbourVoxels = (distance + mVoxelSize) < mInteriorBandWidth;
2713 distLeaf.setValueOnly(pos, -distance);
2714 idxLeaf.setValueOn(pos, closestPrimIdx);
2717 return activateNeighbourVoxels;
2722 BoolLeafNodeType **
const mMaskNodes;
2723 BoolTreeType *
const mMaskTree;
2724 TreeType *
const mDistTree;
2725 Int32TreeType *
const mIndexTree;
2729 BoolTreeType mNewMaskTree;
2731 std::vector<LeafNodeType*> mDistNodes, mUpdatedDistNodes;
2732 std::vector<Int32LeafNodeType*> mIndexNodes, mUpdatedIndexNodes;
2734 const ValueType mExteriorBandWidth, mInteriorBandWidth, mVoxelSize;
2738 template<
typename TreeType>
2742 AddNodes(TreeType& tree, std::vector<LeafNodeType*>& nodes)
2743 : mTree(&tree) , mNodes(&nodes)
2749 std::vector<LeafNodeType*>& nodes = *mNodes;
2750 for (
size_t n = 0, N = nodes.size(); n < N; ++n) {
2760 template<
typename TreeType,
typename Int32TreeType,
typename BoolTreeType,
typename MeshDataAdapter>
2764 Int32TreeType& indexTree,
2765 BoolTreeType& maskTree,
2766 std::vector<typename BoolTreeType::LeafNodeType*>& maskNodes,
2768 typename TreeType::ValueType exteriorBandWidth,
2769 typename TreeType::ValueType interiorBandWidth,
2770 typename TreeType::ValueType voxelSize)
2773 distTree, indexTree, mesh, exteriorBandWidth, interiorBandWidth, voxelSize);
2775 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, maskNodes.size()), expandOp);
2777 tbb::parallel_for(tbb::blocked_range<size_t>(0, expandOp.
updatedIndexNodes().size()),
2781 tbb::task_group tasks;
2795 template<
typename TreeType>
2804 , mVoxelSize(voxelSize)
2805 , mUnsigned(unsignedDist)
2811 typename LeafNodeType::ValueOnIter iter;
2813 const bool udf = mUnsigned;
2814 const ValueType w[2] = { -mVoxelSize, mVoxelSize };
2816 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2818 for (iter = mNodes[n]->beginValueOn(); iter; ++iter) {
2819 ValueType& val = const_cast<ValueType&>(iter.getValue());
2820 val = w[udf || (val <
ValueType(0.0))] * std::sqrt(std::abs(val));
2826 LeafNodeType * *
const mNodes;
2827 const ValueType mVoxelSize;
2828 const bool mUnsigned;
2833 template<
typename TreeType>
2841 : mNodes(nodes.empty() ? nullptr : &nodes[0])
2842 , mExBandWidth(exBandWidth)
2843 , mInBandWidth(inBandWidth)
2849 typename LeafNodeType::ValueOnIter iter;
2853 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2855 for (iter = mNodes[n]->beginValueOn(); iter; ++iter) {
2857 ValueType& val = const_cast<ValueType&>(iter.getValue());
2859 const bool inside = val <
ValueType(0.0);
2861 if (inside && !(val > inVal)) {
2864 }
else if (!inside && !(val < exVal)) {
2873 LeafNodeType * *
const mNodes;
2874 const ValueType mExBandWidth, mInBandWidth;
2878 template<
typename TreeType>
2885 : mNodes(nodes.empty() ? nullptr : &nodes[0]), mOffset(offset)
2893 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2895 typename LeafNodeType::ValueOnIter iter = mNodes[n]->beginValueOn();
2897 for (; iter; ++iter) {
2898 ValueType& val = const_cast<ValueType&>(iter.getValue());
2905 LeafNodeType * *
const mNodes;
2906 const ValueType mOffset;
2910 template<
typename TreeType>
2916 Renormalize(
const TreeType& tree,
const std::vector<LeafNodeType*>& nodes,
2919 , mNodes(nodes.empty() ? nullptr : &nodes[0])
2921 , mVoxelSize(voxelSize)
2936 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2938 ValueType* bufferData = &mBuffer[n * LeafNodeType::SIZE];
2940 typename LeafNodeType::ValueOnCIter iter = mNodes[n]->cbeginValueOn();
2941 for (; iter; ++iter) {
2945 ijk = iter.getCoord();
2960 bufferData[iter.pos()] = phi0 - dx * S * diff;
2966 TreeType
const *
const mTree;
2967 LeafNodeType
const *
const *
const mNodes;
2968 ValueType *
const mBuffer;
2970 const ValueType mVoxelSize;
2974 template<
typename TreeType>
2981 : mNodes(nodes.empty() ? nullptr : &nodes[0]), mBuffer(buffer)
2987 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2989 const ValueType* bufferData = &mBuffer[n * LeafNodeType::SIZE];
2991 typename LeafNodeType::ValueOnIter iter = mNodes[n]->beginValueOn();
2993 for (; iter; ++iter) {
2994 ValueType& val = const_cast<ValueType&>(iter.getValue());
2995 val =
std::min(val, bufferData[iter.pos()]);
3001 LeafNodeType * *
const mNodes;
3002 ValueType
const *
const mBuffer;
3014 template <
typename FloatTreeT>
3020 ConnectivityTable nodeConnectivity(tree);
3022 std::vector<size_t> zStartNodes, yStartNodes, xStartNodes;
3024 for (
size_t n = 0; n < nodeConnectivity.size(); ++n) {
3025 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevX()[n]) {
3026 xStartNodes.push_back(n);
3029 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevY()[n]) {
3030 yStartNodes.push_back(n);
3033 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevZ()[n]) {
3034 zStartNodes.push_back(n);
3040 tbb::parallel_for(tbb::blocked_range<size_t>(0, zStartNodes.size()),
3043 tbb::parallel_for(tbb::blocked_range<size_t>(0, yStartNodes.size()),
3046 tbb::parallel_for(tbb::blocked_range<size_t>(0, xStartNodes.size()),
3049 const size_t numLeafNodes = nodeConnectivity.size();
3050 const size_t numVoxels = numLeafNodes * FloatTreeT::LeafNodeType::SIZE;
3052 std::unique_ptr<bool[]> changedNodeMaskA{
new bool[numLeafNodes]};
3053 std::unique_ptr<bool[]> changedNodeMaskB{
new bool[numLeafNodes]};
3054 std::unique_ptr<bool[]> changedVoxelMask{
new bool[numVoxels]};
3060 const tbb::blocked_range<size_t> nodeRange(0, numLeafNodes);
3062 bool nodesUpdated =
false;
3065 nodeConnectivity.nodes(), changedNodeMaskA.get()));
3068 nodeConnectivity, changedNodeMaskA.get(), changedNodeMaskB.get(),
3069 changedVoxelMask.get()));
3071 changedNodeMaskA.swap(changedNodeMaskB);
3073 nodesUpdated =
false;
3074 for (
size_t n = 0; n < numLeafNodes; ++n) {
3075 nodesUpdated |= changedNodeMaskA[n];
3076 if (nodesUpdated)
break;
3081 nodeConnectivity.nodes(), changedNodeMaskA.get(), changedVoxelMask.get()));
3083 }
while (nodesUpdated);
3091 template <
typename Gr
idType,
typename MeshDataAdapter,
typename Interrupter>
3092 inline typename GridType::Ptr
3094 Interrupter& interrupter,
3097 float exteriorBandWidth,
3098 float interiorBandWidth,
3102 using GridTypePtr =
typename GridType::Ptr;
3103 using TreeType =
typename GridType::TreeType;
3104 using LeafNodeType =
typename TreeType::LeafNodeType;
3105 using ValueType =
typename GridType::ValueType;
3108 using Int32TreeType =
typename Int32GridType::TreeType;
3110 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
3117 distGrid->setTransform(transform.
copy());
3119 ValueType exteriorWidth = ValueType(exteriorBandWidth);
3120 ValueType interiorWidth = ValueType(interiorBandWidth);
3124 if (!std::isfinite(exteriorWidth) || std::isnan(interiorWidth)) {
3125 std::stringstream msg;
3126 msg <<
"Illegal narrow band width: exterior = " << exteriorWidth
3127 <<
", interior = " << interiorWidth;
3132 const ValueType voxelSize = ValueType(transform.
voxelSize()[0]);
3134 if (!std::isfinite(voxelSize) ||
math::isZero(voxelSize)) {
3135 std::stringstream msg;
3136 msg <<
"Illegal transform, voxel size = " << voxelSize;
3142 exteriorWidth *= voxelSize;
3146 interiorWidth *= voxelSize;
3154 Int32GridType* indexGrid =
nullptr;
3156 typename Int32GridType::Ptr temporaryIndexGrid;
3158 if (polygonIndexGrid) {
3159 indexGrid = polygonIndexGrid;
3162 indexGrid = temporaryIndexGrid.get();
3165 indexGrid->newTree();
3166 indexGrid->setTransform(transform.
copy());
3168 if (computeSignedDistanceField) {
3172 interiorWidth = ValueType(0.0);
3175 TreeType& distTree = distGrid->tree();
3176 Int32TreeType& indexTree = indexGrid->tree();
3185 using DataTable = tbb::enumerable_thread_specific<typename VoxelizationDataType::Ptr>;
3191 const tbb::blocked_range<size_t> polygonRange(0, mesh.polygonCount());
3193 tbb::parallel_for(polygonRange, Voxelizer(data, mesh, &interrupter));
3195 for (
typename DataTable::iterator i = data.begin(); i != data.end(); ++i) {
3196 VoxelizationDataType& dataItem = **i;
3198 distTree, indexTree, dataItem.distTree, dataItem.indexTree);
3204 if (interrupter.wasInterrupted(30))
return distGrid;
3211 if (computeSignedDistanceField) {
3216 std::vector<LeafNodeType*> nodes;
3217 nodes.reserve(distTree.leafCount());
3218 distTree.getNodes(nodes);
3220 const tbb::blocked_range<size_t> nodeRange(0, nodes.size());
3225 tbb::parallel_for(nodeRange, SignOp(nodes, distTree, indexTree, mesh));
3227 if (interrupter.wasInterrupted(45))
return distGrid;
3230 if (removeIntersectingVoxels) {
3232 tbb::parallel_for(nodeRange,
3235 tbb::parallel_for(nodeRange,
3237 nodes, distTree, indexTree));
3244 if (interrupter.wasInterrupted(50))
return distGrid;
3246 if (distTree.activeVoxelCount() == 0) {
3248 distTree.root().setBackground(exteriorWidth,
false);
3254 std::vector<LeafNodeType*> nodes;
3255 nodes.reserve(distTree.leafCount());
3256 distTree.getNodes(nodes);
3258 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3260 nodes, voxelSize, !computeSignedDistanceField));
3264 if (computeSignedDistanceField) {
3265 distTree.root().setBackground(exteriorWidth,
false);
3271 if (interrupter.wasInterrupted(54))
return distGrid;
3278 const ValueType minBandWidth = voxelSize * ValueType(2.0);
3280 if (interiorWidth > minBandWidth || exteriorWidth > minBandWidth) {
3283 BoolTreeType maskTree(
false);
3286 std::vector<LeafNodeType*> nodes;
3287 nodes.reserve(distTree.leafCount());
3288 distTree.getNodes(nodes);
3291 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), op);
3297 float progress = 54.0f, step = 0.0f;
3299 2.0 * std::ceil((
std::max(interiorWidth, exteriorWidth) - minBandWidth) / voxelSize);
3301 if (estimated <
double(maxIterations)) {
3302 maxIterations = unsigned(estimated);
3303 step = 40.0f / float(maxIterations);
3306 std::vector<typename BoolTreeType::LeafNodeType*> maskNodes;
3311 if (interrupter.wasInterrupted(
int(progress)))
return distGrid;
3313 const size_t maskNodeCount = maskTree.leafCount();
3314 if (maskNodeCount == 0)
break;
3317 maskNodes.reserve(maskNodeCount);
3318 maskTree.getNodes(maskNodes);
3320 const tbb::blocked_range<size_t> range(0, maskNodes.size());
3322 tbb::parallel_for(range,
3326 mesh, exteriorWidth, interiorWidth, voxelSize);
3328 if ((++count) >= maxIterations)
break;
3333 if (interrupter.wasInterrupted(94))
return distGrid;
3335 if (!polygonIndexGrid) indexGrid->clear();
3343 if (computeSignedDistanceField && renormalizeValues) {
3345 std::vector<LeafNodeType*> nodes;
3346 nodes.reserve(distTree.leafCount());
3347 distTree.getNodes(nodes);
3349 std::unique_ptr<ValueType[]> buffer{
new ValueType[LeafNodeType::SIZE * nodes.size()]};
3351 const ValueType offset = ValueType(0.8 * voxelSize);
3353 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3356 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3358 distTree, nodes, buffer.get(), voxelSize));
3360 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3363 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3368 if (interrupter.wasInterrupted(99))
return distGrid;
3375 if (trimNarrowBand &&
std::min(interiorWidth, exteriorWidth) < voxelSize * ValueType(4.0)) {
3377 std::vector<LeafNodeType*> nodes;
3378 nodes.reserve(distTree.leafCount());
3379 distTree.getNodes(nodes);
3381 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3383 nodes, exteriorWidth, computeSignedDistanceField ? interiorWidth : exteriorWidth));
3386 distTree, exteriorWidth, computeSignedDistanceField ? -interiorWidth : -exteriorWidth);
3393 template <
typename Gr
idType,
typename MeshDataAdapter>
3394 inline typename GridType::Ptr
3398 float exteriorBandWidth,
3399 float interiorBandWidth,
3404 return meshToVolume<GridType>(nullInterrupter, mesh, transform,
3405 exteriorBandWidth, interiorBandWidth, flags, polygonIndexGrid);
3416 template<
typename Gr
idType,
typename Interrupter>
3417 inline typename std::enable_if<std::is_floating_point<typename GridType::ValueType>::value,
3418 typename GridType::Ptr>::type
3420 Interrupter& interrupter,
3421 const openvdb::math::Transform& xform,
3422 const std::vector<Vec3s>& points,
3423 const std::vector<Vec3I>& triangles,
3424 const std::vector<Vec4I>& quads,
3427 bool unsignedDistanceField =
false)
3429 if (points.empty()) {
3430 return typename GridType::Ptr(
new GridType(
typename GridType::ValueType(exBandWidth)));
3433 const size_t numPoints = points.size();
3434 std::unique_ptr<Vec3s[]> indexSpacePoints{
new Vec3s[numPoints]};
3437 tbb::parallel_for(tbb::blocked_range<size_t>(0, numPoints),
3438 mesh_to_volume_internal::TransformPoints<Vec3s>(
3439 &points[0], indexSpacePoints.get(), xform));
3443 if (quads.empty()) {
3445 QuadAndTriangleDataAdapter<Vec3s, Vec3I>
3446 mesh(indexSpacePoints.get(), numPoints, &triangles[0], triangles.size());
3448 return meshToVolume<GridType>(
3449 interrupter, mesh, xform, exBandWidth, inBandWidth, conversionFlags);
3451 }
else if (triangles.empty()) {
3453 QuadAndTriangleDataAdapter<Vec3s, Vec4I>
3454 mesh(indexSpacePoints.get(), numPoints, &quads[0], quads.size());
3456 return meshToVolume<GridType>(
3457 interrupter, mesh, xform, exBandWidth, inBandWidth, conversionFlags);
3462 const size_t numPrimitives = triangles.size() + quads.size();
3463 std::unique_ptr<Vec4I[]> prims{
new Vec4I[numPrimitives]};
3465 for (
size_t n = 0, N = triangles.size(); n < N; ++n) {
3466 const Vec3I& triangle = triangles[n];
3467 Vec4I& prim = prims[n];
3468 prim[0] = triangle[0];
3469 prim[1] = triangle[1];
3470 prim[2] = triangle[2];
3474 const size_t offset = triangles.size();
3475 for (
size_t n = 0, N = quads.size(); n < N; ++n) {
3476 prims[offset + n] = quads[n];
3479 QuadAndTriangleDataAdapter<Vec3s, Vec4I>
3480 mesh(indexSpacePoints.get(), numPoints, prims.get(), numPrimitives);
3482 return meshToVolume<GridType>(interrupter, mesh, xform,
3483 exBandWidth, inBandWidth, conversionFlags);
3489 template<
typename Gr
idType,
typename Interrupter>
3490 inline typename std::enable_if<!std::is_floating_point<typename GridType::ValueType>::value,
3491 typename GridType::Ptr>::type
3494 const math::Transform& ,
3495 const std::vector<Vec3s>& ,
3496 const std::vector<Vec3I>& ,
3497 const std::vector<Vec4I>& ,
3503 "mesh to volume conversion is supported only for scalar floating-point grids");
3513 template<
typename Gr
idType>
3514 inline typename GridType::Ptr
3516 const openvdb::math::Transform& xform,
3517 const std::vector<Vec3s>& points,
3518 const std::vector<Vec3I>& triangles,
3522 std::vector<Vec4I> quads(0);
3523 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles, quads,
3524 halfWidth, halfWidth);
3528 template<
typename Gr
idType,
typename Interrupter>
3529 inline typename GridType::Ptr
3531 Interrupter& interrupter,
3532 const openvdb::math::Transform& xform,
3533 const std::vector<Vec3s>& points,
3534 const std::vector<Vec3I>& triangles,
3537 std::vector<Vec4I> quads(0);
3538 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3539 halfWidth, halfWidth);
3543 template<
typename Gr
idType>
3544 inline typename GridType::Ptr
3546 const openvdb::math::Transform& xform,
3547 const std::vector<Vec3s>& points,
3548 const std::vector<Vec4I>& quads,
3552 std::vector<Vec3I> triangles(0);
3553 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles, quads,
3554 halfWidth, halfWidth);
3558 template<
typename Gr
idType,
typename Interrupter>
3559 inline typename GridType::Ptr
3561 Interrupter& interrupter,
3562 const openvdb::math::Transform& xform,
3563 const std::vector<Vec3s>& points,
3564 const std::vector<Vec4I>& quads,
3567 std::vector<Vec3I> triangles(0);
3568 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3569 halfWidth, halfWidth);
3573 template<
typename Gr
idType>
3574 inline typename GridType::Ptr
3576 const openvdb::math::Transform& xform,
3577 const std::vector<Vec3s>& points,
3578 const std::vector<Vec3I>& triangles,
3579 const std::vector<Vec4I>& quads,
3583 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles, quads,
3584 halfWidth, halfWidth);
3588 template<
typename Gr
idType,
typename Interrupter>
3589 inline typename GridType::Ptr
3591 Interrupter& interrupter,
3592 const openvdb::math::Transform& xform,
3593 const std::vector<Vec3s>& points,
3594 const std::vector<Vec3I>& triangles,
3595 const std::vector<Vec4I>& quads,
3598 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3599 halfWidth, halfWidth);
3603 template<
typename Gr
idType>
3604 inline typename GridType::Ptr
3606 const openvdb::math::Transform& xform,
3607 const std::vector<Vec3s>& points,
3608 const std::vector<Vec3I>& triangles,
3609 const std::vector<Vec4I>& quads,
3614 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles,
3615 quads, exBandWidth, inBandWidth);
3619 template<
typename Gr
idType,
typename Interrupter>
3620 inline typename GridType::Ptr
3622 Interrupter& interrupter,
3623 const openvdb::math::Transform& xform,
3624 const std::vector<Vec3s>& points,
3625 const std::vector<Vec3I>& triangles,
3626 const std::vector<Vec4I>& quads,
3630 return doMeshConversion<GridType>(interrupter, xform, points, triangles,
3631 quads, exBandWidth, inBandWidth);
3635 template<
typename Gr
idType>
3636 inline typename GridType::Ptr
3638 const openvdb::math::Transform& xform,
3639 const std::vector<Vec3s>& points,
3640 const std::vector<Vec3I>& triangles,
3641 const std::vector<Vec4I>& quads,
3645 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles, quads,
3646 bandWidth, bandWidth,
true);
3650 template<
typename Gr
idType,
typename Interrupter>
3651 inline typename GridType::Ptr
3653 Interrupter& interrupter,
3654 const openvdb::math::Transform& xform,
3655 const std::vector<Vec3s>& points,
3656 const std::vector<Vec3I>& triangles,
3657 const std::vector<Vec4I>& quads,
3660 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3661 bandWidth, bandWidth,
true);
3669 inline std::ostream&
3672 ostr <<
"{[ " << rhs.
mXPrim <<
", " << rhs.
mXDist <<
"]";
3673 ostr <<
" [ " << rhs.
mYPrim <<
", " << rhs.
mYDist <<
"]";
3674 ostr <<
" [ " << rhs.
mZPrim <<
", " << rhs.
mZDist <<
"]}";
3679 inline MeshToVoxelEdgeData::EdgeData
3694 const std::vector<Vec3s>& pointList,
3695 const std::vector<Vec4I>& polygonList);
3697 void run(
bool threaded =
true);
3700 inline void operator() (
const tbb::blocked_range<size_t> &range);
3708 struct Primitive {
Vec3d a, b, c, d;
Int32 index; };
3710 template<
bool IsQuad>
3711 inline void voxelize(
const Primitive&);
3713 template<
bool IsQuad>
3714 inline bool evalPrimitive(
const Coord&,
const Primitive&);
3716 inline bool rayTriangleIntersection(
const Vec3d& origin,
const Vec3d& dir,
3723 const std::vector<Vec3s>& mPointList;
3724 const std::vector<Vec4I>& mPolygonList;
3727 using IntTreeT = TreeType::ValueConverter<Int32>::Type;
3728 IntTreeT mLastPrimTree;
3734 MeshToVoxelEdgeData::GenEdgeData::GenEdgeData(
3735 const std::vector<Vec3s>& pointList,
3736 const std::vector<Vec4I>& polygonList)
3739 , mPointList(pointList)
3740 , mPolygonList(polygonList)
3742 , mLastPrimAccessor(mLastPrimTree)
3751 , mPointList(rhs.mPointList)
3752 , mPolygonList(rhs.mPolygonList)
3754 , mLastPrimAccessor(mLastPrimTree)
3763 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, mPolygonList.size()), *
this);
3765 (*this)(tbb::blocked_range<size_t>(0, mPolygonList.size()));
3774 using NodeChainType = RootNodeType::NodeChainType;
3775 static_assert(boost::mpl::size<NodeChainType>::value > 1,
"expected tree height > 1");
3776 using InternalNodeType = boost::mpl::at<NodeChainType, boost::mpl::int_<1> >::type;
3784 for ( ; leafIt; ++leafIt) {
3785 ijk = leafIt->origin();
3791 mAccessor.addLeaf(rhs.mAccessor.
probeLeaf(ijk));
3792 InternalNodeType* node = rhs.mAccessor.
getNode<InternalNodeType>();
3794 rhs.mAccessor.
clear();
3804 if (!lhsLeafPt->isValueOn(offset)) {
3805 lhsLeafPt->setValueOn(offset, rhsValue);
3808 EdgeData& lhsValue = const_cast<EdgeData&>(lhsLeafPt->getValue(offset));
3837 for (
size_t n = range.begin(); n < range.end(); ++n) {
3839 const Vec4I& verts = mPolygonList[n];
3841 prim.index =
Int32(n);
3842 prim.a =
Vec3d(mPointList[verts[0]]);
3843 prim.b =
Vec3d(mPointList[verts[1]]);
3844 prim.c =
Vec3d(mPointList[verts[2]]);
3847 prim.d =
Vec3d(mPointList[verts[3]]);
3848 voxelize<true>(prim);
3850 voxelize<false>(prim);
3856 template<
bool IsQuad>
3858 MeshToVoxelEdgeData::GenEdgeData::voxelize(
const Primitive& prim)
3860 std::deque<Coord> coordList;
3864 coordList.push_back(ijk);
3866 evalPrimitive<IsQuad>(ijk, prim);
3868 while (!coordList.empty()) {
3870 ijk = coordList.back();
3871 coordList.pop_back();
3873 for (
Int32 i = 0; i < 26; ++i) {
3876 if (prim.index != mLastPrimAccessor.getValue(nijk)) {
3877 mLastPrimAccessor.setValue(nijk, prim.index);
3878 if(evalPrimitive<IsQuad>(nijk, prim)) coordList.push_back(nijk);
3885 template<
bool IsQuad>
3887 MeshToVoxelEdgeData::GenEdgeData::evalPrimitive(
const Coord& ijk,
const Primitive& prim)
3889 Vec3d uvw, org(ijk[0], ijk[1], ijk[2]);
3890 bool intersecting =
false;
3894 mAccessor.probeValue(ijk, edgeData);
3897 double dist = (org -
3900 if (rayTriangleIntersection(org,
Vec3d(1.0, 0.0, 0.0), prim.a, prim.c, prim.b, t)) {
3901 if (t < edgeData.mXDist) {
3902 edgeData.mXDist = float(t);
3903 edgeData.mXPrim = prim.index;
3904 intersecting =
true;
3908 if (rayTriangleIntersection(org,
Vec3d(0.0, 1.0, 0.0), prim.a, prim.c, prim.b, t)) {
3909 if (t < edgeData.mYDist) {
3910 edgeData.mYDist = float(t);
3911 edgeData.mYPrim = prim.index;
3912 intersecting =
true;
3916 if (rayTriangleIntersection(org,
Vec3d(0.0, 0.0, 1.0), prim.a, prim.c, prim.b, t)) {
3917 if (t < edgeData.mZDist) {
3918 edgeData.mZDist = float(t);
3919 edgeData.mZPrim = prim.index;
3920 intersecting =
true;
3926 double secondDist = (org -
3929 if (secondDist < dist) dist = secondDist;
3931 if (rayTriangleIntersection(org,
Vec3d(1.0, 0.0, 0.0), prim.a, prim.d, prim.c, t)) {
3932 if (t < edgeData.mXDist) {
3933 edgeData.mXDist = float(t);
3934 edgeData.mXPrim = prim.index;
3935 intersecting =
true;
3939 if (rayTriangleIntersection(org,
Vec3d(0.0, 1.0, 0.0), prim.a, prim.d, prim.c, t)) {
3940 if (t < edgeData.mYDist) {
3941 edgeData.mYDist = float(t);
3942 edgeData.mYPrim = prim.index;
3943 intersecting =
true;
3947 if (rayTriangleIntersection(org,
Vec3d(0.0, 0.0, 1.0), prim.a, prim.d, prim.c, t)) {
3948 if (t < edgeData.mZDist) {
3949 edgeData.mZDist = float(t);
3950 edgeData.mZPrim = prim.index;
3951 intersecting =
true;
3956 if (intersecting) mAccessor.setValue(ijk, edgeData);
3958 return (dist < 0.86602540378443861);
3963 MeshToVoxelEdgeData::GenEdgeData::rayTriangleIntersection(
3974 double divisor = s1.
dot(e1);
3975 if (!(std::abs(divisor) > 0.0))
return false;
3979 double inv_divisor = 1.0 / divisor;
3980 Vec3d d = origin - a;
3981 double b1 = d.
dot(s1) * inv_divisor;
3983 if (b1 < 0.0 || b1 > 1.0)
return false;
3986 double b2 = dir.
dot(s2) * inv_divisor;
3988 if (b2 < 0.0 || (b1 + b2) > 1.0)
return false;
3992 t = e2.dot(s2) * inv_divisor;
3993 return (t < 0.0) ? false :
true;
4009 const std::vector<Vec3s>& pointList,
4010 const std::vector<Vec4I>& polygonList)
4024 std::vector<Vec3d>& points,
4025 std::vector<Index32>& primitives)
4035 point[0] = double(coord[0]) + data.
mXDist;
4036 point[1] = double(coord[1]);
4037 point[2] = double(coord[2]);
4039 points.push_back(point);
4040 primitives.push_back(data.
mXPrim);
4044 point[0] = double(coord[0]);
4045 point[1] = double(coord[1]) + data.
mYDist;
4046 point[2] = double(coord[2]);
4048 points.push_back(point);
4049 primitives.push_back(data.
mYPrim);
4053 point[0] = double(coord[0]);
4054 point[1] = double(coord[1]);
4055 point[2] = double(coord[2]) + data.
mZDist;
4057 points.push_back(point);
4058 primitives.push_back(data.
mZPrim);
4068 point[0] = double(coord[0]);
4069 point[1] = double(coord[1]) + data.
mYDist;
4070 point[2] = double(coord[2]);
4072 points.push_back(point);
4073 primitives.push_back(data.
mYPrim);
4077 point[0] = double(coord[0]);
4078 point[1] = double(coord[1]);
4079 point[2] = double(coord[2]) + data.
mZDist;
4081 points.push_back(point);
4082 primitives.push_back(data.
mZPrim);
4090 point[0] = double(coord[0]);
4091 point[1] = double(coord[1]) + data.
mYDist;
4092 point[2] = double(coord[2]);
4094 points.push_back(point);
4095 primitives.push_back(data.
mYPrim);
4104 point[0] = double(coord[0]) + data.
mXDist;
4105 point[1] = double(coord[1]);
4106 point[2] = double(coord[2]);
4108 points.push_back(point);
4109 primitives.push_back(data.
mXPrim);
4113 point[0] = double(coord[0]);
4114 point[1] = double(coord[1]) + data.
mYDist;
4115 point[2] = double(coord[2]);
4117 points.push_back(point);
4118 primitives.push_back(data.
mYPrim);
4128 point[0] = double(coord[0]) + data.
mXDist;
4129 point[1] = double(coord[1]);
4130 point[2] = double(coord[2]);
4132 points.push_back(point);
4133 primitives.push_back(data.
mXPrim);
4142 point[0] = double(coord[0]) + data.
mXDist;
4143 point[1] = double(coord[1]);
4144 point[2] = double(coord[2]);
4146 points.push_back(point);
4147 primitives.push_back(data.
mXPrim);
4151 point[0] = double(coord[0]);
4152 point[1] = double(coord[1]);
4153 point[2] = double(coord[2]) + data.
mZDist;
4155 points.push_back(point);
4156 primitives.push_back(data.
mZPrim);
4165 point[0] = double(coord[0]);
4166 point[1] = double(coord[1]);
4167 point[2] = double(coord[2]) + data.
mZDist;
4169 points.push_back(point);
4170 primitives.push_back(data.
mZPrim);
4176 template<
typename Gr
idType,
typename VecType>
4177 inline typename GridType::Ptr
4179 const openvdb::math::Transform& xform,
4180 typename VecType::ValueType halfWidth)
4186 points[0] =
Vec3s(pmin[0], pmin[1], pmin[2]);
4187 points[1] =
Vec3s(pmin[0], pmin[1], pmax[2]);
4188 points[2] =
Vec3s(pmax[0], pmin[1], pmax[2]);
4189 points[3] =
Vec3s(pmax[0], pmin[1], pmin[2]);
4190 points[4] =
Vec3s(pmin[0], pmax[1], pmin[2]);
4191 points[5] =
Vec3s(pmin[0], pmax[1], pmax[2]);
4192 points[6] =
Vec3s(pmax[0], pmax[1], pmax[2]);
4193 points[7] =
Vec3s(pmax[0], pmax[1], pmin[2]);
4196 faces[0] =
Vec4I(0, 1, 2, 3);
4197 faces[1] =
Vec4I(7, 6, 5, 4);
4198 faces[2] =
Vec4I(4, 5, 1, 0);
4199 faces[3] =
Vec4I(6, 7, 3, 2);
4200 faces[4] =
Vec4I(0, 3, 7, 4);
4201 faces[5] =
Vec4I(1, 5, 6, 2);
4205 return meshToVolume<GridType>(mesh, xform, halfWidth, halfWidth);
4213 #endif // OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED 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:417
T dot(const Vec3< T > &v) const
Dot product.
Definition: Vec3.h:216
Index32 Index
Definition: Types.h:61
LeafNodeType * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists,...
Definition: Tree.h:1734
Base class for tree-traversal iterators over all leaf nodes (but not leaf voxels)
Definition: TreeIterator.h:1235
#define OPENVDB_LOG_DEBUG(message)
In debug builds only, log a debugging message of the form 'someVar << "text" << .....
Definition: logging.h:290
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:293
static Coord floor(const Vec3< T > &xyz)
Return the largest integer coordinates that are not greater than xyz (node centered conversion).
Definition: Coord.h:83
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:715
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...
Base class for tree-traversal iterators over tile and voxel values.
Definition: TreeIterator.h:665
Convert polygonal meshes that consist of quads and/or triangles into signed or unsigned distance fiel...
Real GodunovsNormSqrd(bool isOutside, Real dP_xm, Real dP_xp, Real dP_ym, Real dP_yp, Real dP_zm, Real dP_zp)
Definition: FiniteDifference.h:353
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:264
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
Definition: ValueAccessor.h:267
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
Definition: BBox.h:91
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:395
math::Vec4< Index32 > Vec4I
Definition: Types.h:95
Vec3< double > Vec3d
Definition: Vec3.h:679
Efficient multi-threaded replacement of the background values in tree.
const Coord & max() const
Definition: Coord.h:338
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
Vec3< T > cross(const Vec3< T > &v) const
Return the cross product of "this" vector and v;.
Definition: Vec3.h:245
const ValueT & getValue() const
Return the tile or voxel value to which this iterator is currently pointing.
Definition: TreeIterator.h:741
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:51
int32_t Int32
Definition: Types.h:63
bool operator<(const Tuple< SIZE, T0 > &t0, const Tuple< SIZE, T1 > &t1)
Definition: Tuple.h:207
Defined various multi-threaded utility functions for trees.
bool isInside(const Coord &xyz) const
Return true if point (x, y, z) is inside this bounding box.
Definition: Coord.h:404
Tree< typename RootNodeType::template ValueConverter< Int32 >::Type > Type
Definition: Tree.h:224
uint32_t Index32
Definition: Types.h:59
static const Real LEVEL_SET_HALF_WIDTH
Definition: Types.h:283
void clear() override
Remove all nodes from this cache, then reinsert the root node.
Definition: ValueAccessor.h:431
Axis
Definition: Math.h:856
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:136
OPENVDB_API const Coord COORD_OFFSETS[26]
coordinate offset table for neighboring voxels
bool isZero(const Type &x)
Return true if x is exactly equal to zero.
Definition: Math.h:308
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
const Coord & min() const
Definition: Coord.h:337
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:257
Definition: Exceptions.h:40
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:264
void maxComponent(const Coord &other)
Perform a component-wise maximum with the other Coord.
Definition: Coord.h:210
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition: Coord.h:422
void clearAllAccessors()
Clear all registered accessors.
Definition: Tree.h:1547
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:52
LeafIter beginLeaf()
Return an iterator over all leaf nodes in this tree.
Definition: Tree.h:1179
Axis-aligned bounding box.
Definition: BBox.h:50
static Coord min()
Return the smallest possible coordinate.
Definition: Coord.h:70
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
Definition: BBox.h:89
LeafNodeT * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists,...
Definition: ValueAccessor.h:386
std::shared_ptr< T > SharedPtr
Definition: Types.h:139
typename RootNodeType::LeafNodeType LeafNodeType
Definition: Tree.h:212
math::Vec3< Index32 > Vec3I
Definition: Types.h:80
static Coord max()
Return the largest possible coordinate.
Definition: Coord.h:73
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:422
bool operator>(const Tuple< SIZE, T0 > &t0, const Tuple< SIZE, T1 > &t1)
Definition: Tuple.h:219
void addLeaf(LeafNodeT *leaf)
Add the specified leaf to this tree, possibly creating a child branch in the process....
Definition: ValueAccessor.h:367
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:188
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition: Coord.h:202
Vec3< float > Vec3s
Definition: Vec3.h:678
_RootNodeType RootNodeType
Definition: Tree.h:209
OPENVDB_API const Index32 INVALID_IDX
void merge(Tree &other, MergePolicy=MERGE_ACTIVE_STATES)
Efficiently merge another tree into this tree using one of several schemes.
Definition: Tree.h:1864
NodeType * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
Definition: ValueAccessor.h:342
void clear()
Remove all tiles from this tree and all nodes other than the root node.
Definition: Tree.h:1488
Partitions points into BucketLog2Dim aligned buckets using a parallel radix-based sorting algorithm.
Type Pow2(Type x)
Return x2.
Definition: Math.h:502
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition: Coord.h:118