44 #ifndef OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED 45 #define OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED 58 #include <tbb/blocked_range.h> 59 #include <tbb/enumerable_thread_specific.h> 60 #include <tbb/parallel_for.h> 61 #include <tbb/parallel_reduce.h> 62 #include <tbb/partitioner.h> 63 #include <tbb/task_group.h> 64 #include <tbb/task_scheduler_init.h> 66 #include <boost/integer_traits.hpp> 67 #include <boost/math/special_functions/fpclassify.hpp> 68 #include <boost/scoped_array.hpp> 139 template <
typename Gr
idType,
typename MeshDataAdapter>
140 inline typename GridType::Ptr
144 float exteriorBandWidth = 3.0f,
145 float interiorBandWidth = 3.0f,
165 template <
typename Gr
idType,
typename MeshDataAdapter,
typename Interrupter>
166 inline typename GridType::Ptr
168 Interrupter& interrupter,
171 float exteriorBandWidth = 3.0f,
172 float interiorBandWidth = 3.0f,
190 template<
typename Po
intType,
typename PolygonType>
194 const std::vector<PolygonType>& polygons)
195 : mPointArray(points.empty() ? NULL : &points[0])
196 , mPointArraySize(points.size())
197 , mPolygonArray(polygons.empty() ? NULL : &polygons[0])
198 , mPolygonArraySize(polygons.size())
203 const PolygonType* polygonArray,
size_t polygonArraySize)
204 : mPointArray(pointArray)
205 , mPointArraySize(pointArraySize)
206 , mPolygonArray(polygonArray)
207 , mPolygonArraySize(polygonArraySize)
216 return (PolygonType::size == 3 || mPolygonArray[n][3] ==
util::INVALID_IDX) ? 3 : 4;
222 const PointType& p = mPointArray[mPolygonArray[n][int(v)]];
223 pos[0] = double(p[0]);
224 pos[1] = double(p[1]);
225 pos[2] = double(p[2]);
229 PointType
const *
const mPointArray;
230 size_t const mPointArraySize;
231 PolygonType
const *
const mPolygonArray;
232 size_t const mPolygonArraySize;
260 template<
typename Gr
idType>
261 inline typename GridType::Ptr
263 const openvdb::math::Transform& xform,
264 const std::vector<Vec3s>& points,
265 const std::vector<Vec3I>& triangles,
269 template<
typename Gr
idType,
typename Interrupter>
270 inline typename GridType::Ptr
272 Interrupter& interrupter,
273 const openvdb::math::Transform& xform,
274 const std::vector<Vec3s>& points,
275 const std::vector<Vec3I>& triangles,
294 template<
typename Gr
idType>
295 inline typename GridType::Ptr
297 const openvdb::math::Transform& xform,
298 const std::vector<Vec3s>& points,
299 const std::vector<Vec4I>& quads,
303 template<
typename Gr
idType,
typename Interrupter>
304 inline typename GridType::Ptr
306 Interrupter& interrupter,
307 const openvdb::math::Transform& xform,
308 const std::vector<Vec3s>& points,
309 const std::vector<Vec4I>& quads,
329 template<
typename Gr
idType>
330 inline typename GridType::Ptr
332 const openvdb::math::Transform& xform,
333 const std::vector<Vec3s>& points,
334 const std::vector<Vec3I>& triangles,
335 const std::vector<Vec4I>& quads,
339 template<
typename Gr
idType,
typename Interrupter>
340 inline typename GridType::Ptr
342 Interrupter& interrupter,
343 const openvdb::math::Transform& xform,
344 const std::vector<Vec3s>& points,
345 const std::vector<Vec3I>& triangles,
346 const std::vector<Vec4I>& quads,
368 template<
typename Gr
idType>
369 inline typename GridType::Ptr
371 const openvdb::math::Transform& xform,
372 const std::vector<Vec3s>& points,
373 const std::vector<Vec3I>& triangles,
374 const std::vector<Vec4I>& quads,
379 template<
typename Gr
idType,
typename Interrupter>
380 inline typename GridType::Ptr
382 Interrupter& interrupter,
383 const openvdb::math::Transform& xform,
384 const std::vector<Vec3s>& points,
385 const std::vector<Vec3I>& triangles,
386 const std::vector<Vec4I>& quads,
405 template<
typename Gr
idType>
406 inline typename GridType::Ptr
408 const openvdb::math::Transform& xform,
409 const std::vector<Vec3s>& points,
410 const std::vector<Vec3I>& triangles,
411 const std::vector<Vec4I>& quads,
415 template<
typename Gr
idType,
typename Interrupter>
416 inline typename GridType::Ptr
418 Interrupter& interrupter,
419 const openvdb::math::Transform& xform,
420 const std::vector<Vec3s>& points,
421 const std::vector<Vec3I>& triangles,
422 const std::vector<Vec4I>& quads,
435 template<
typename Gr
idType,
typename VecType>
436 inline typename GridType::Ptr
438 const openvdb::math::Transform& xform,
451 template <
typename FloatTreeT>
469 : mXDist(dist), mYDist(dist), mZDist(dist)
512 void convert(
const std::vector<Vec3s>& pointList,
const std::vector<Vec4I>& polygonList);
517 void getEdgeData(Accessor& acc,
const Coord& ijk,
518 std::vector<Vec3d>& points, std::vector<Index32>& primitives);
537 namespace mesh_to_volume_internal {
543 #ifdef OPENVDB_HAS_CXX11 544 typedef std::unique_ptr<T>
type;
551 template<
typename Po
intType>
556 : mPointsIn(pointsIn), mPointsOut(pointsOut), mXform(&xform)
560 void operator()(
const tbb::blocked_range<size_t>& range)
const {
564 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
566 const PointType& wsP = mPointsIn[n];
567 pos[0] = double(wsP[0]);
568 pos[1] = double(wsP[1]);
569 pos[2] = double(wsP[2]);
571 pos = mXform->worldToIndex(pos);
573 PointType& isP = mPointsOut[n];
574 isP[0] =
typename PointType::value_type(pos[0]);
575 isP[1] =
typename PointType::value_type(pos[1]);
576 isP[2] =
typename PointType::value_type(pos[2]);
586 template<
typename ValueType>
589 static ValueType
epsilon() {
return ValueType(1e-7); }
597 template<
typename TreeType>
608 LeafNodeType ** rhsDistNodes, Int32LeafNodeType ** rhsIdxNodes)
609 : mDistTree(&lhsDistTree)
610 , mIdxTree(&lhsIdxTree)
611 , mRhsDistNodes(rhsDistNodes)
612 , mRhsIdxNodes(rhsIdxNodes)
616 void operator()(
const tbb::blocked_range<size_t>& range)
const {
621 typedef typename LeafNodeType::ValueType DistValueType;
622 typedef typename Int32LeafNodeType::ValueType IndexValueType;
624 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
626 const Coord& origin = mRhsDistNodes[n]->origin();
628 LeafNodeType* lhsDistNode = distAcc.
probeLeaf(origin);
629 Int32LeafNodeType* lhsIdxNode = idxAcc.
probeLeaf(origin);
631 DistValueType* lhsDistData = lhsDistNode->buffer().data();
632 IndexValueType* lhsIdxData = lhsIdxNode->buffer().data();
634 const DistValueType* rhsDistData = mRhsDistNodes[n]->buffer().data();
635 const IndexValueType* rhsIdxData = mRhsIdxNodes[n]->buffer().data();
638 for (
Index32 offset = 0; offset < LeafNodeType::SIZE; ++offset) {
642 const DistValueType& lhsValue = lhsDistData[offset];
643 const DistValueType& rhsValue = rhsDistData[offset];
645 if (rhsValue < lhsValue) {
646 lhsDistNode->setValueOn(offset, rhsValue);
647 lhsIdxNode->setValueOn(offset, rhsIdxData[offset]);
649 lhsIdxNode->setValueOn(offset,
650 std::min(lhsIdxData[offset], rhsIdxData[offset]));
655 delete mRhsDistNodes[n];
656 delete mRhsIdxNodes[n];
662 TreeType *
const mDistTree;
663 Int32TreeType *
const mIdxTree;
665 LeafNodeType **
const mRhsDistNodes;
666 Int32LeafNodeType **
const mRhsIdxNodes;
673 template<
typename TreeType>
679 : mNodes(nodes.empty() ? NULL : &nodes[0]), mCoordinates(coordinates)
683 void operator()(
const tbb::blocked_range<size_t>& range)
const {
684 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
685 Coord& origin =
const_cast<Coord&
>(mNodes[n]->origin());
686 mCoordinates[n] = origin;
687 origin[0] =
static_cast<int>(n);
696 template<
typename TreeType>
702 : mNodes(nodes.empty() ? NULL : &nodes[0]), mCoordinates(coordinates)
706 void operator()(
const tbb::blocked_range<size_t>& range)
const {
707 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
708 Coord& origin =
const_cast<Coord&
>(mNodes[n]->origin());
709 origin[0] = mCoordinates[n][0];
718 template<
typename TreeType>
725 size_t* offsets,
size_t numNodes,
const CoordBBox& bbox)
727 , mCoordinates(coordinates)
729 , mNumNodes(numNodes)
734 void operator()(
const tbb::blocked_range<size_t>& range)
const {
736 size_t* offsetsNextX = mOffsets;
737 size_t* offsetsPrevX = mOffsets + mNumNodes;
738 size_t* offsetsNextY = mOffsets + mNumNodes * 2;
739 size_t* offsetsPrevY = mOffsets + mNumNodes * 3;
740 size_t* offsetsNextZ = mOffsets + mNumNodes * 4;
741 size_t* offsetsPrevZ = mOffsets + mNumNodes * 5;
746 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
747 const Coord& origin = mCoordinates[n];
748 offsetsNextX[n] = findNeighbourNode(acc, origin,
Coord(LeafNodeType::DIM, 0, 0));
749 offsetsPrevX[n] = findNeighbourNode(acc, origin,
Coord(-LeafNodeType::DIM, 0, 0));
750 offsetsNextY[n] = findNeighbourNode(acc, origin,
Coord(0, LeafNodeType::DIM, 0));
751 offsetsPrevY[n] = findNeighbourNode(acc, origin,
Coord(0, -LeafNodeType::DIM, 0));
752 offsetsNextZ[n] = findNeighbourNode(acc, origin,
Coord(0, 0, LeafNodeType::DIM));
753 offsetsPrevZ[n] = findNeighbourNode(acc, origin,
Coord(0, 0, -LeafNodeType::DIM));
759 Coord ijk = start + step;
764 if (node)
return static_cast<size_t>(node->origin()[0]);
768 return boost::integer_traits<size_t>::const_max;
776 TreeType
const *
const mTree;
777 Coord const *
const mCoordinates;
778 size_t *
const mOffsets;
780 const size_t mNumNodes;
785 template<
typename TreeType>
788 enum { INVALID_OFFSET = boost::integer_traits<size_t>::const_max };
796 mLeafNodes.reserve(tree.leafCount());
797 tree.getNodes(mLeafNodes);
799 if (mLeafNodes.empty())
return;
802 tree.evalLeafBoundingBox(bbox);
804 const tbb::blocked_range<size_t> range(0, mLeafNodes.size());
808 boost::scoped_array<Coord> coordinates(
new Coord[mLeafNodes.size()]);
812 mOffsets.reset(
new size_t[mLeafNodes.size() * 6]);
815 tbb::parallel_for(range,
822 size_t size()
const {
return mLeafNodes.size(); }
824 std::vector<LeafNodeType*>&
nodes() {
return mLeafNodes; }
825 const std::vector<LeafNodeType*>&
nodes()
const {
return mLeafNodes; }
829 const size_t*
offsetsPrevX()
const {
return mOffsets.get() + mLeafNodes.size(); }
831 const size_t*
offsetsNextY()
const {
return mOffsets.get() + mLeafNodes.size() * 2; }
832 const size_t*
offsetsPrevY()
const {
return mOffsets.get() + mLeafNodes.size() * 3; }
834 const size_t*
offsetsNextZ()
const {
return mOffsets.get() + mLeafNodes.size() * 4; }
835 const size_t*
offsetsPrevZ()
const {
return mOffsets.get() + mLeafNodes.size() * 5; }
838 std::vector<LeafNodeType*> mLeafNodes;
839 boost::scoped_array<size_t> mOffsets;
843 template<
typename TreeType>
855 : mStartNodeIndices(startNodeIndices.empty() ? NULL : &startNodeIndices[0])
856 , mConnectivity(&connectivity)
861 void operator()(
const tbb::blocked_range<size_t>& range)
const {
863 std::vector<LeafNodeType*>& nodes = mConnectivity->nodes();
866 size_t idxA = 0, idxB = 1;
869 const size_t* nextOffsets = mConnectivity->offsetsNextZ();
870 const size_t* prevOffsets = mConnectivity->offsetsPrevZ();
876 step = LeafNodeType::DIM;
878 nextOffsets = mConnectivity->offsetsNextY();
879 prevOffsets = mConnectivity->offsetsPrevY();
881 }
else if (mAxis ==
X_AXIS) {
885 step = LeafNodeType::DIM * LeafNodeType::DIM;
887 nextOffsets = mConnectivity->offsetsNextX();
888 prevOffsets = mConnectivity->offsetsPrevX();
896 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
898 size_t startOffset = mStartNodeIndices[n];
899 size_t lastOffset = startOffset;
903 for (a = 0; a < int(LeafNodeType::DIM); ++a) {
904 for (b = 0; b < int(LeafNodeType::DIM); ++b) {
906 pos = LeafNodeType::coordToOffset(ijk);
907 size_t offset = startOffset;
910 while ( offset != ConnectivityTable::INVALID_OFFSET &&
911 traceVoxelLine(*nodes[offset], pos, step) ) {
914 offset = nextOffsets[offset];
919 while (offset != ConnectivityTable::INVALID_OFFSET) {
921 offset = nextOffsets[offset];
926 pos += step * (LeafNodeType::DIM - 1);
927 while ( offset != ConnectivityTable::INVALID_OFFSET &&
928 traceVoxelLine(*nodes[offset], pos, -step)) {
929 offset = prevOffsets[offset];
939 ValueType* data = node.buffer().data();
941 bool isOutside =
true;
943 for (
Index i = 0; i < LeafNodeType::DIM; ++i) {
945 ValueType& dist = data[pos];
947 if (dist < ValueType(0.0)) {
951 if (!(dist > ValueType(0.75))) isOutside =
false;
953 if (isOutside) dist = ValueType(-dist);
964 size_t const *
const mStartNodeIndices;
965 ConnectivityTable *
const mConnectivity;
971 template<
typename LeafNodeType>
975 typedef typename LeafNodeType::ValueType ValueType;
976 typedef std::deque<Index> Queue;
979 ValueType* data = node.buffer().data();
983 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
984 if (data[pos] < 0.0) seedPoints.push_back(pos);
987 if (seedPoints.empty())
return;
990 for (Queue::iterator it = seedPoints.begin(); it != seedPoints.end(); ++it) {
991 ValueType& dist = data[*it];
998 Index pos(0), nextPos(0);
1000 while (!seedPoints.empty()) {
1002 pos = seedPoints.back();
1003 seedPoints.pop_back();
1005 ValueType& dist = data[pos];
1007 if (!(dist < ValueType(0.0))) {
1011 ijk = LeafNodeType::offsetToLocalCoord(pos);
1014 nextPos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
1015 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1018 if (ijk[0] != (LeafNodeType::DIM - 1)) {
1019 nextPos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
1020 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1024 nextPos = pos - LeafNodeType::DIM;
1025 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1028 if (ijk[1] != (LeafNodeType::DIM - 1)) {
1029 nextPos = pos + LeafNodeType::DIM;
1030 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1035 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1038 if (ijk[2] != (LeafNodeType::DIM - 1)) {
1040 if (data[nextPos] > ValueType(0.75)) seedPoints.push_back(nextPos);
1047 template<
typename LeafNodeType>
1051 bool updatedNode =
false;
1053 typedef typename LeafNodeType::ValueType ValueType;
1054 ValueType* data = node.buffer().data();
1058 bool updatedSign =
true;
1059 while (updatedSign) {
1061 updatedSign =
false;
1063 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
1065 ValueType& dist = data[pos];
1067 if (!(dist < ValueType(0.0)) && dist > ValueType(0.75)) {
1069 ijk = LeafNodeType::offsetToLocalCoord(pos);
1072 if (ijk[2] != 0 && data[pos - 1] < ValueType(0.0)) {
1074 dist = ValueType(-dist);
1077 }
else if (ijk[2] != (LeafNodeType::DIM - 1) && data[pos + 1] < ValueType(0.0)) {
1079 dist = ValueType(-dist);
1082 }
else if (ijk[1] != 0 && data[pos - LeafNodeType::DIM] < ValueType(0.0)) {
1084 dist = ValueType(-dist);
1087 }
else if (ijk[1] != (LeafNodeType::DIM - 1) && data[pos + LeafNodeType::DIM] < ValueType(0.0)) {
1089 dist = ValueType(-dist);
1092 }
else if (ijk[0] != 0 && data[pos - LeafNodeType::DIM * LeafNodeType::DIM] < ValueType(0.0)) {
1094 dist = ValueType(-dist);
1097 }
else if (ijk[0] != (LeafNodeType::DIM - 1) && data[pos + LeafNodeType::DIM * LeafNodeType::DIM] < ValueType(0.0)) {
1099 dist = ValueType(-dist);
1104 updatedNode |= updatedSign;
1111 template<
typename TreeType>
1119 : mNodes(nodes.empty() ? NULL : &nodes[0])
1120 , mChangedNodeMask(changedNodeMask)
1125 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1126 if (mChangedNodeMask[n]) {
1128 mChangedNodeMask[n] =
scanFill(*mNodes[n]);
1138 template<
typename ValueType>
1141 FillArray(ValueType* array,
const ValueType v) : mArray(array), mValue(v) { }
1144 const ValueType v = mValue;
1145 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1155 template<
typename ValueType>
1157 fillArray(ValueType* array,
const ValueType val,
const size_t length)
1159 const size_t grainSize = length / tbb::task_scheduler_init::default_num_threads();
1160 const tbb::blocked_range<size_t> range(0, length, grainSize);
1165 template<
typename TreeType>
1172 SyncVoxelMask(std::vector<LeafNodeType*>& nodes,
const bool* changedNodeMask,
bool* changedVoxelMask)
1173 : mNodes(nodes.empty() ? NULL : &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) {
1189 data[pos] = ValueType(-data[pos]);
1203 template<
typename TreeType>
1211 SeedPoints(ConnectivityTable& connectivity,
bool* changedNodeMask,
bool* nodeMask,
bool* changedVoxelMask)
1212 : mConnectivity(&connectivity)
1213 , mChangedNodeMask(changedNodeMask)
1214 , mNodeMask(nodeMask)
1215 , mChangedVoxelMask(changedVoxelMask)
1221 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1223 if (!mChangedNodeMask[n]) {
1225 bool changedValue =
false;
1227 changedValue |= processZ(n,
true);
1228 changedValue |= processZ(n,
false);
1230 changedValue |= processY(n,
true);
1231 changedValue |= processY(n,
false);
1233 changedValue |= processX(n,
true);
1234 changedValue |= processX(n,
false);
1236 mNodeMask[n] = changedValue;
1244 const size_t offset = firstFace ? mConnectivity->offsetsPrevZ()[n] : mConnectivity->offsetsNextZ()[n];
1245 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1247 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1249 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1250 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1252 const Index lastOffset = LeafNodeType::DIM - 1;
1253 const Index lhsOffset = firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1255 Index tmpPos(0), pos(0);
1256 bool changedValue =
false;
1258 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
1259 tmpPos = x << (2 * LeafNodeType::LOG2DIM);
1260 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
1261 pos = tmpPos + (y << LeafNodeType::LOG2DIM);
1263 if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1264 if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1265 changedValue =
true;
1266 mask[pos + lhsOffset] =
true;
1272 return changedValue;
1280 const size_t offset = firstFace ? mConnectivity->offsetsPrevY()[n] : mConnectivity->offsetsNextY()[n];
1281 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1283 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1285 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1286 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1288 const Index lastOffset = LeafNodeType::DIM * (LeafNodeType::DIM - 1);
1289 const Index lhsOffset = firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1291 Index tmpPos(0), pos(0);
1292 bool changedValue =
false;
1294 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
1295 tmpPos = x << (2 * LeafNodeType::LOG2DIM);
1296 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
1299 if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1300 if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1301 changedValue =
true;
1302 mask[pos + lhsOffset] =
true;
1308 return changedValue;
1316 const size_t offset = firstFace ? mConnectivity->offsetsPrevX()[n] : mConnectivity->offsetsNextX()[n];
1317 if (offset != ConnectivityTable::INVALID_OFFSET && mChangedNodeMask[offset]) {
1319 bool* mask = &mChangedVoxelMask[n * LeafNodeType::SIZE];
1321 const ValueType* lhsData = mConnectivity->nodes()[n]->buffer().data();
1322 const ValueType* rhsData = mConnectivity->nodes()[offset]->buffer().data();
1324 const Index lastOffset = LeafNodeType::DIM * LeafNodeType::DIM * (LeafNodeType::DIM - 1);
1325 const Index lhsOffset = firstFace ? 0 : lastOffset, rhsOffset = firstFace ? lastOffset : 0;
1327 Index tmpPos(0), pos(0);
1328 bool changedValue =
false;
1330 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
1331 tmpPos = y << LeafNodeType::LOG2DIM;
1332 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
1335 if (lhsData[pos + lhsOffset] > ValueType(0.75)) {
1336 if (rhsData[pos + rhsOffset] < ValueType(0.0)) {
1337 changedValue =
true;
1338 mask[pos + lhsOffset] =
true;
1344 return changedValue;
1359 template<
typename TreeType,
typename MeshDataAdapter>
1367 typedef std::pair<boost::shared_array<Vec3d>, boost::shared_array<bool> >
LocalData;
1371 std::vector<LeafNodeType*>& distNodes,
1372 const TreeType& distTree,
1373 const Int32TreeType& indexTree,
1375 : mDistNodes(distNodes.empty() ? NULL : &distNodes[0])
1376 , mDistTree(&distTree)
1377 , mIndexTree(&indexTree)
1379 , mLocalDataTable(new LocalDataTable())
1391 Index xPos(0), yPos(0);
1392 Coord ijk, nijk, nodeMin, nodeMax;
1393 Vec3d cp, xyz, nxyz, dir1, dir2;
1395 LocalData& localData = mLocalDataTable->local();
1397 boost::shared_array<Vec3d>& points = localData.first;
1398 if (!points) points.reset(
new Vec3d[LeafNodeType::SIZE * 2]);
1400 boost::shared_array<bool>& mask = localData.second;
1401 if (!mask) mask.reset(
new bool[LeafNodeType::SIZE]);
1404 typename LeafNodeType::ValueOnCIter it;
1406 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1408 LeafNodeType& node = *mDistNodes[n];
1409 ValueType* data = node.buffer().data();
1411 const Int32LeafNodeType* idxNode = idxAcc.
probeConstLeaf(node.origin());
1412 const Int32* idxData = idxNode->buffer().data();
1414 nodeMin = node.origin();
1415 nodeMax = nodeMin.
offsetBy(LeafNodeType::DIM - 1);
1418 memset(mask.get(), 0,
sizeof(bool) * LeafNodeType::SIZE);
1420 for (it = node.cbeginValueOn(); it; ++it) {
1421 Index pos = it.pos();
1423 ValueType& dist = data[pos];
1424 if (dist < 0.0 || dist > 0.75)
continue;
1426 ijk = node.offsetToGlobalCoord(pos);
1428 xyz[0] = double(ijk[0]);
1429 xyz[1] = double(ijk[1]);
1430 xyz[2] = double(ijk[2]);
1436 bool flipSign =
false;
1438 for (nijk[0] = bbox.
min()[0]; nijk[0] <= bbox.
max()[0] && !flipSign; ++nijk[0]) {
1439 xPos = (nijk[0] & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
1440 for (nijk[1] = bbox.
min()[1]; nijk[1] <= bbox.
max()[1] && !flipSign; ++nijk[1]) {
1441 yPos = xPos + ((nijk[1] & (LeafNodeType::DIM - 1u)) << LeafNodeType::LOG2DIM);
1442 for (nijk[2] = bbox.
min()[2]; nijk[2] <= bbox.
max()[2]; ++nijk[2]) {
1443 pos = yPos + (nijk[2] & (LeafNodeType::DIM - 1u));
1445 const Int32& polyIdx = idxData[pos];
1449 const Index pointIndex = pos * 2;
1455 nxyz[0] = double(nijk[0]);
1456 nxyz[1] = double(nijk[1]);
1457 nxyz[2] = double(nijk[2]);
1459 Vec3d& point = points[pointIndex];
1461 point = closestPoint(nxyz, polyIdx);
1463 Vec3d& direction = points[pointIndex + 1];
1464 direction = nxyz - point;
1468 dir1 = xyz - points[pointIndex];
1471 if (points[pointIndex + 1].dot(dir1) > 0.0) {
1482 for (
Int32 m = 0; m < 26; ++m) {
1486 nxyz[0] = double(nijk[0]);
1487 nxyz[1] = double(nijk[1]);
1488 nxyz[2] = double(nijk[2]);
1490 cp = closestPoint(nxyz, idxAcc.
getValue(nijk));
1498 if (dir2.dot(dir1) > 0.0) {
1514 Vec3d a, b, c, cp, uvw;
1516 const size_t polygon = size_t(polyIdx);
1517 mMesh->getIndexSpacePoint(polygon, 0, a);
1518 mMesh->getIndexSpacePoint(polygon, 1, b);
1519 mMesh->getIndexSpacePoint(polygon, 2, c);
1523 if (4 == mMesh->vertexCount(polygon)) {
1525 mMesh->getIndexSpacePoint(polygon, 3, b);
1529 if ((center - c).lengthSqr() < (center - cp).lengthSqr()) {
1538 LeafNodeType **
const mDistNodes;
1539 TreeType
const *
const mDistTree;
1540 Int32TreeType
const *
const mIndexTree;
1543 boost::shared_ptr<LocalDataTable> mLocalDataTable;
1550 template<
typename LeafNodeType>
1554 typedef LeafNodeType NodeT;
1556 const Coord ijk = NodeT::offsetToLocalCoord(pos);
1560 mask[0] = ijk[0] != (NodeT::DIM - 1);
1562 mask[1] = ijk[0] != 0;
1564 mask[2] = ijk[1] != (NodeT::DIM - 1);
1566 mask[3] = ijk[1] != 0;
1568 mask[4] = ijk[2] != (NodeT::DIM - 1);
1570 mask[5] = ijk[2] != 0;
1574 mask[6] = mask[0] && mask[5];
1576 mask[7] = mask[1] && mask[5];
1578 mask[8] = mask[0] && mask[4];
1580 mask[9] = mask[1] && mask[4];
1582 mask[10] = mask[0] && mask[2];
1584 mask[11] = mask[1] && mask[2];
1586 mask[12] = mask[0] && mask[3];
1588 mask[13] = mask[1] && mask[3];
1590 mask[14] = mask[3] && mask[4];
1592 mask[15] = mask[3] && mask[5];
1594 mask[16] = mask[2] && mask[4];
1596 mask[17] = mask[2] && mask[5];
1600 mask[18] = mask[1] && mask[3] && mask[5];
1602 mask[19] = mask[1] && mask[3] && mask[4];
1604 mask[20] = mask[0] && mask[3] && mask[4];
1606 mask[21] = mask[0] && mask[3] && mask[5];
1608 mask[22] = mask[1] && mask[2] && mask[5];
1610 mask[23] = mask[1] && mask[2] && mask[4];
1612 mask[24] = mask[0] && mask[2] && mask[4];
1614 mask[25] = mask[0] && mask[2] && mask[5];
1618 template<
typename Compare,
typename LeafNodeType>
1622 typedef LeafNodeType NodeT;
1625 if (mask[5] && Compare::check(data[pos - 1]))
return true;
1627 if (mask[4] && Compare::check(data[pos + 1]))
return true;
1629 if (mask[3] && Compare::check(data[pos - NodeT::DIM]))
return true;
1631 if (mask[2] && Compare::check(data[pos + NodeT::DIM]))
return true;
1633 if (mask[1] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM]))
return true;
1635 if (mask[0] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM]))
return true;
1637 if (mask[6] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM]))
return true;
1639 if (mask[7] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - 1]))
return true;
1641 if (mask[8] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + 1]))
return true;
1643 if (mask[9] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + 1]))
return true;
1645 if (mask[10] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM]))
return true;
1647 if (mask[11] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM]))
return true;
1649 if (mask[12] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM]))
return true;
1651 if (mask[13] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM]))
return true;
1653 if (mask[14] && Compare::check(data[pos - NodeT::DIM + 1]))
return true;
1655 if (mask[15] && Compare::check(data[pos - NodeT::DIM - 1]))
return true;
1657 if (mask[16] && Compare::check(data[pos + NodeT::DIM + 1]))
return true;
1659 if (mask[17] && Compare::check(data[pos + NodeT::DIM - 1]))
return true;
1661 if (mask[18] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM - 1]))
return true;
1663 if (mask[19] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM - NodeT::DIM + 1]))
return true;
1665 if (mask[20] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM + 1]))
return true;
1667 if (mask[21] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM - NodeT::DIM - 1]))
return true;
1669 if (mask[22] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM - 1]))
return true;
1671 if (mask[23] && Compare::check(data[pos - NodeT::DIM * NodeT::DIM + NodeT::DIM + 1]))
return true;
1673 if (mask[24] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM + 1]))
return true;
1675 if (mask[25] && Compare::check(data[pos + NodeT::DIM * NodeT::DIM + NodeT::DIM - 1]))
return true;
1681 template<
typename Compare,
typename AccessorType>
1685 for (
Int32 m = 0; m < 26; ++m) {
1695 template<
typename TreeType>
1701 struct IsNegative {
static bool check(
const ValueType v) {
return v < ValueType(0.0); } };
1705 , mNodes(nodes.empty() ? NULL : &nodes[0])
1712 bool neighbourMask[26];
1714 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1716 LeafNodeType& node = *mNodes[n];
1717 ValueType* data = node.buffer().data();
1719 typename LeafNodeType::ValueOnCIter it;
1720 for (it = node.cbeginValueOn(); it; ++it) {
1722 const Index pos = it.pos();
1724 ValueType& dist = data[pos];
1725 if (dist < 0.0 || dist > 0.75)
continue;
1728 maskNodeInternalNeighbours<LeafNodeType>(pos, neighbourMask);
1730 const bool hasNegativeNeighbour =
1731 checkNeighbours<IsNegative, LeafNodeType>(pos, data, neighbourMask) ||
1732 checkNeighbours<IsNegative>(node.offsetToGlobalCoord(pos), acc, neighbourMask);
1734 if (!hasNegativeNeighbour) {
1747 template<
typename TreeType>
1754 struct Comp {
static bool check(
const ValueType v) {
return !(v > ValueType(0.75)); } };
1757 TreeType& distTree, Int32TreeType& indexTree)
1758 : mNodes(nodes.empty() ? NULL : &nodes[0])
1759 , mDistTree(&distTree)
1760 , mIndexTree(&indexTree)
1768 bool neighbourMask[26];
1770 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1772 LeafNodeType& distNode = *mNodes[n];
1773 ValueType* data = distNode.buffer().data();
1775 typename Int32TreeType::LeafNodeType* idxNode =
1778 typename LeafNodeType::ValueOnCIter it;
1779 for (it = distNode.cbeginValueOn(); it; ++it) {
1781 const Index pos = it.pos();
1783 if (!(data[pos] > 0.75))
continue;
1786 maskNodeInternalNeighbours<LeafNodeType>(pos, neighbourMask);
1788 const bool hasBoundaryNeighbour =
1789 checkNeighbours<Comp, LeafNodeType>(pos, data, neighbourMask) ||
1790 checkNeighbours<Comp>(distNode.offsetToGlobalCoord(pos), distAcc, neighbourMask);
1792 if (!hasBoundaryNeighbour) {
1793 distNode.setValueOff(pos);
1794 idxNode->setValueOff(pos);
1809 template<
typename NodeType>
1816 typedef typename NodeType::NodeMaskType NodeMaskType;
1818 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1819 const_cast<NodeMaskType&
>(mNodes[n]->getChildMask()).setOff();
1827 template<
typename TreeType>
1831 typedef typename TreeType::RootNodeType RootNodeType;
1832 typedef typename RootNodeType::NodeChainType NodeChainType;
1833 typedef typename boost::mpl::at<NodeChainType, boost::mpl::int_<1> >::type InternalNodeType;
1835 std::vector<InternalNodeType*> nodes;
1836 tree.getNodes(nodes);
1838 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
1843 template<
typename TreeType>
1849 std::vector<LeafNodeType*>& overlappingNodes)
1850 : mLhsTree(&lhsTree)
1851 , mRhsTree(&rhsTree)
1852 , mNodes(&overlappingNodes)
1858 std::vector<LeafNodeType*> rhsLeafNodes;
1860 rhsLeafNodes.reserve(mRhsTree->leafCount());
1863 mRhsTree->stealNodes(rhsLeafNodes);
1867 for (
size_t n = 0, N = rhsLeafNodes.size(); n < N; ++n) {
1868 if (!acc.
probeLeaf(rhsLeafNodes[n]->origin())) {
1871 mNodes->push_back(rhsLeafNodes[n]);
1877 TreeType *
const mLhsTree;
1878 TreeType *
const mRhsTree;
1879 std::vector<LeafNodeType*> *
const mNodes;
1883 template<
typename DistTreeType,
typename IndexTreeType>
1886 DistTreeType& rhsDist, IndexTreeType& rhsIdx)
1888 typedef typename DistTreeType::LeafNodeType DistLeafNodeType;
1889 typedef typename IndexTreeType::LeafNodeType IndexLeafNodeType;
1891 std::vector<DistLeafNodeType*> overlappingDistNodes;
1892 std::vector<IndexLeafNodeType*> overlappingIdxNodes;
1895 tbb::task_group tasks;
1901 if (!overlappingDistNodes.empty() && !overlappingIdxNodes.empty()) {
1902 tbb::parallel_for(tbb::blocked_range<size_t>(0, overlappingDistNodes.size()),
1913 template<
typename TreeType>
1916 typedef boost::scoped_ptr<VoxelizationData>
Ptr;
1920 typedef typename TreeType::template ValueConverter<unsigned char>::Type
UCharTreeType;
1928 : distTree(std::numeric_limits<ValueType>::
max())
1931 , indexAcc(indexTree)
1932 , primIdTree(MaxPrimId)
1933 , primIdAcc(primIdTree)
1949 if (mPrimCount == MaxPrimId || primIdTree.leafCount() > 1000) {
1954 return mPrimCount++;
1959 enum { MaxPrimId = 100 };
1961 unsigned char mPrimCount;
1965 template<
typename TreeType,
typename MeshDataAdapter,
typename Interrupter = util::NullInterrupter>
1971 typedef tbb::enumerable_thread_specific<typename VoxelizationDataType::Ptr>
DataTable;
1975 Interrupter* interrupter = NULL)
1976 : mDataTable(&dataTable)
1978 , mInterrupter(interrupter)
1985 if (!dataPtr) dataPtr.reset(
new VoxelizationDataType());
1989 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1992 tbb::task::self().cancel_group_execution();
1996 const size_t numVerts = mMesh->vertexCount(n);
1999 if (numVerts == 3 || numVerts == 4) {
2001 prim.index =
Int32(n);
2003 mMesh->getIndexSpacePoint(n, 0, prim.a);
2004 mMesh->getIndexSpacePoint(n, 1, prim.b);
2005 mMesh->getIndexSpacePoint(n, 2, prim.c);
2007 evalTriangle(prim, *dataPtr);
2009 if (numVerts == 4) {
2010 mMesh->getIndexSpacePoint(n, 3, prim.b);
2011 evalTriangle(prim, *dataPtr);
2019 bool wasInterrupted()
const {
return mInterrupter && mInterrupter->wasInterrupted(); }
2021 struct Triangle {
Vec3d a, b, c;
Int32 index; };
2025 enum { POLYGON_LIMIT = 1000 };
2027 SubTask(
const Triangle& prim, DataTable& dataTable,
int subdivisionCount,
size_t polygonCount)
2028 : mLocalDataTable(&dataTable)
2030 , mSubdivisionCount(subdivisionCount)
2031 , mPolygonCount(polygonCount)
2035 void operator()()
const 2037 if (mSubdivisionCount <= 0 || mPolygonCount >= POLYGON_LIMIT) {
2040 if (!dataPtr) dataPtr.reset(
new VoxelizationDataType());
2042 voxelizeTriangle(mPrim, *dataPtr);
2045 spawnTasks(mPrim, *mLocalDataTable, mSubdivisionCount, mPolygonCount);
2049 DataTable *
const mLocalDataTable;
2050 Triangle
const mPrim;
2051 int const mSubdivisionCount;
2052 size_t const mPolygonCount;
2055 inline static int evalSubdivisionCount(
const Triangle& prim)
2057 const double ax = prim.a[0], bx = prim.b[0], cx = prim.c[0];
2060 const double ay = prim.a[1], by = prim.b[1], cy = prim.c[1];
2063 const double az = prim.a[2], bz = prim.b[2], cz = prim.c[2];
2066 return int(
std::max(dx,
std::max(dy, dz)) /
double(TreeType::LeafNodeType::DIM * 2));
2069 void evalTriangle(
const Triangle& prim, VoxelizationDataType& data)
const 2071 const size_t polygonCount = mMesh->polygonCount();
2072 const int subdivisionCount = polygonCount < SubTask::POLYGON_LIMIT ? evalSubdivisionCount(prim) : 0;
2074 if (subdivisionCount <= 0) {
2075 voxelizeTriangle(prim, data);
2077 spawnTasks(prim, *mDataTable, subdivisionCount, polygonCount);
2081 static void spawnTasks(
2082 const Triangle& mainPrim, DataTable& dataTable,
int subdivisionCount,
size_t polygonCount)
2084 subdivisionCount -= 1;
2087 tbb::task_group tasks;
2089 const Vec3d ac = (mainPrim.a + mainPrim.c) * 0.5;
2090 const Vec3d bc = (mainPrim.b + mainPrim.c) * 0.5;
2091 const Vec3d ab = (mainPrim.a + mainPrim.b) * 0.5;
2094 prim.index = mainPrim.index;
2096 prim.a = mainPrim.a;
2099 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount));
2104 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount));
2107 prim.b = mainPrim.b;
2109 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount));
2113 prim.c = mainPrim.c;
2114 tasks.run(SubTask(prim, dataTable, subdivisionCount, polygonCount));
2119 static void voxelizeTriangle(
const Triangle& prim, VoxelizationDataType& data)
2121 std::deque<Coord> coordList;
2125 coordList.push_back(ijk);
2127 computeDistance(ijk, prim, data);
2132 while (!coordList.empty()) {
2133 ijk = coordList.back();
2134 coordList.pop_back();
2136 for (
Int32 i = 0; i < 26; ++i) {
2140 if(computeDistance(nijk, prim, data)) coordList.push_back(nijk);
2146 static bool computeDistance(
const Coord& ijk,
const Triangle& prim, VoxelizationDataType& data)
2148 Vec3d uvw, voxelCenter(ijk[0], ijk[1], ijk[2]);
2150 typedef typename TreeType::ValueType ValueType;
2152 const ValueType dist = ValueType((voxelCenter -
2157 if (dist < oldDist) {
2166 return !(dist > 0.75);
2169 DataTable *
const mDataTable;
2171 Interrupter *
const mInterrupter;
2178 template<
typename TreeType>
2184 typedef typename TreeType::template ValueConverter<bool>::Type
BoolTreeType;
2188 std::vector<BoolLeafNodeType*>& lhsNodes)
2189 : mRhsTree(&rhsTree), mLhsNodes(lhsNodes.empty() ? NULL : &lhsNodes[0])
2197 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2199 BoolLeafNodeType* lhsNode = mLhsNodes[n];
2200 const LeafNodeType* rhsNode = acc.
probeConstLeaf(lhsNode->origin());
2202 if (rhsNode) lhsNode->topologyDifference(*rhsNode,
false);
2207 TreeType
const *
const mRhsTree;
2208 BoolLeafNodeType **
const mLhsNodes;
2212 template<
typename LeafNodeTypeA,
typename LeafNodeTypeB>
2216 : mNodesA(nodesA.empty() ? NULL : &nodesA[0])
2217 , mNodesB(nodesB.empty() ? NULL : &nodesB[0])
2222 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2223 mNodesA[n]->topologyUnion(*mNodesB[n]);
2228 LeafNodeTypeA **
const mNodesA;
2229 LeafNodeTypeB **
const mNodesB;
2233 template<
typename TreeType>
2238 typedef typename TreeType::template ValueConverter<bool>::Type
BoolTreeType;
2243 , mNodes(nodes.empty() ? NULL : &nodes[0])
2244 , mLocalMaskTree(false)
2245 , mMaskTree(&maskTree)
2251 , mNodes(rhs.mNodes)
2252 , mLocalMaskTree(false)
2253 , mMaskTree(&mLocalMaskTree)
2259 typedef typename LeafNodeType::ValueOnCIter Iterator;
2264 Coord ijk, nijk, localCorod;
2267 for (
size_t n = range.begin(); n != range.end(); ++n) {
2269 LeafNodeType& node = *mNodes[n];
2271 CoordBBox bbox = node.getNodeBoundingBox();
2274 BoolLeafNodeType& maskNode = *maskAcc.
touchLeaf(node.origin());
2276 for (Iterator it = node.cbeginValueOn(); it; ++it) {
2277 ijk = it.getCoord();
2280 localCorod = LeafNodeType::offsetToLocalCoord(pos);
2282 if (localCorod[2] <
int(LeafNodeType::DIM - 1)) {
2284 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2290 if (localCorod[2] > 0) {
2292 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2298 if (localCorod[1] <
int(LeafNodeType::DIM - 1)) {
2299 npos = pos + LeafNodeType::DIM;
2300 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2306 if (localCorod[1] > 0) {
2307 npos = pos - LeafNodeType::DIM;
2308 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2314 if (localCorod[0] <
int(LeafNodeType::DIM - 1)) {
2315 npos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
2316 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2322 if (localCorod[0] > 0) {
2323 npos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
2324 if (!node.isValueOn(npos)) maskNode.setValueOn(npos);
2336 TreeType
const *
const mTree;
2337 LeafNodeType **
const mNodes;
2339 BoolTreeType mLocalMaskTree;
2340 BoolTreeType *
const mMaskTree;
2345 template<
typename TreeType,
typename MeshDataAdapter>
2353 typedef typename TreeType::template ValueConverter<bool>::Type
BoolTreeType;
2364 : idx(idx_), x(x_), y(y_), z(z_), dist(dist_)
2374 std::vector<BoolLeafNodeType*>& maskNodes,
2375 BoolTreeType& maskTree,
2377 Int32TreeType& indexTree,
2379 ValueType exteriorBandWidth,
2380 ValueType interiorBandWidth,
2381 ValueType voxelSize)
2382 : mMaskNodes(maskNodes.empty() ? NULL : &maskNodes[0])
2383 , mMaskTree(&maskTree)
2384 , mDistTree(&distTree)
2385 , mIndexTree(&indexTree)
2387 , mNewMaskTree(false)
2389 , mUpdatedDistNodes()
2391 , mUpdatedIndexNodes()
2392 , mExteriorBandWidth(exteriorBandWidth)
2393 , mInteriorBandWidth(interiorBandWidth)
2394 , mVoxelSize(voxelSize)
2399 : mMaskNodes(rhs.mMaskNodes)
2400 , mMaskTree(rhs.mMaskTree)
2401 , mDistTree(rhs.mDistTree)
2402 , mIndexTree(rhs.mIndexTree)
2404 , mNewMaskTree(false)
2406 , mUpdatedDistNodes()
2408 , mUpdatedIndexNodes()
2409 , mExteriorBandWidth(rhs.mExteriorBandWidth)
2410 , mInteriorBandWidth(rhs.mInteriorBandWidth)
2411 , mVoxelSize(rhs.mVoxelSize)
2417 mDistNodes.insert(mDistNodes.end(), rhs.mDistNodes.begin(), rhs.mDistNodes.end());
2418 mIndexNodes.insert(mIndexNodes.end(), rhs.mIndexNodes.begin(), rhs.mIndexNodes.end());
2420 mUpdatedDistNodes.insert(mUpdatedDistNodes.end(),
2421 rhs.mUpdatedDistNodes.begin(), rhs.mUpdatedDistNodes.end());
2423 mUpdatedIndexNodes.insert(mUpdatedIndexNodes.end(),
2424 rhs.mUpdatedIndexNodes.begin(), rhs.mUpdatedIndexNodes.end());
2426 mNewMaskTree.merge(rhs.mNewMaskTree);
2435 std::vector<Fragment> fragments;
2436 fragments.reserve(256);
2441 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2443 BoolLeafNodeType& maskNode = *mMaskNodes[n];
2444 if (maskNode.isEmpty())
continue;
2448 const Coord& origin = maskNode.origin();
2450 LeafNodeType * distNodePt = distAcc.
probeLeaf(origin);
2451 Int32LeafNodeType * indexNodePt = indexAcc.
probeLeaf(origin);
2453 assert(!distNodePt == !indexNodePt);
2455 bool usingNewNodes =
false;
2457 if (!distNodePt && !indexNodePt) {
2459 const ValueType backgroundDist = distAcc.
getValue(origin);
2461 if (!newDistNodePt.get() && !newIndexNodePt.get()) {
2462 newDistNodePt.reset(
new LeafNodeType(origin, backgroundDist));
2463 newIndexNodePt.reset(
new Int32LeafNodeType(origin, indexAcc.
getValue(origin)));
2466 if ((backgroundDist < ValueType(0.0)) !=
2467 (newDistNodePt->getValue(0) < ValueType(0.0))) {
2468 newDistNodePt->buffer().fill(backgroundDist);
2471 newDistNodePt->setOrigin(origin);
2472 newIndexNodePt->setOrigin(origin);
2475 distNodePt = newDistNodePt.get();
2476 indexNodePt = newIndexNodePt.get();
2478 usingNewNodes =
true;
2485 for (
typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
2486 bbox.
expand(it.getCoord());
2491 gatherFragments(fragments, bbox, distAcc, indexAcc);
2496 bbox = maskNode.getNodeBoundingBox();
2498 bool updatedLeafNodes =
false;
2500 for (
typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
2502 const Coord ijk = it.getCoord();
2504 if (updateVoxel(ijk, 5, fragments, *distNodePt, *indexNodePt, &updatedLeafNodes)) {
2506 for (
Int32 i = 0; i < 6; ++i) {
2509 mask.setOn(BoolLeafNodeType::coordToOffset(nijk));
2515 for (
Int32 i = 6; i < 26; ++i) {
2518 mask.setOn(BoolLeafNodeType::coordToOffset(nijk));
2524 if (updatedLeafNodes) {
2527 mask -= indexNodePt->getValueMask();
2529 for (
typename NodeMaskType::OnIterator it = mask.beginOn(); it; ++it) {
2531 const Index pos = it.pos();
2532 const Coord ijk = maskNode.origin() + LeafNodeType::offsetToLocalCoord(pos);
2534 if (updateVoxel(ijk, 6, fragments, *distNodePt, *indexNodePt)) {
2535 for (
Int32 i = 0; i < 6; ++i) {
2542 if (usingNewNodes) {
2543 newDistNodePt->topologyUnion(*newIndexNodePt);
2544 mDistNodes.push_back(newDistNodePt.release());
2545 mIndexNodes.push_back(newIndexNodePt.release());
2547 mUpdatedDistNodes.push_back(distNodePt);
2548 mUpdatedIndexNodes.push_back(indexNodePt);
2568 gatherFragments(std::vector<Fragment>& fragments,
const CoordBBox& bbox,
2572 const Coord nodeMin = bbox.
min() & ~(LeafNodeType::DIM - 1);
2573 const Coord nodeMax = bbox.
max() & ~(LeafNodeType::DIM - 1);
2578 for (ijk[0] = nodeMin[0]; ijk[0] <= nodeMax[0]; ijk[0] += LeafNodeType::DIM) {
2579 for (ijk[1] = nodeMin[1]; ijk[1] <= nodeMax[1]; ijk[1] += LeafNodeType::DIM) {
2580 for (ijk[2] = nodeMin[2]; ijk[2] <= nodeMax[2]; ijk[2] += LeafNodeType::DIM) {
2581 if (LeafNodeType* distleaf = distAcc.
probeLeaf(ijk)) {
2584 ijk.
offsetBy(LeafNodeType::DIM - 1));
2585 gatherFragments(fragments, region, *distleaf, *indexAcc.
probeLeaf(ijk));
2591 std::sort(fragments.begin(), fragments.end());
2595 gatherFragments(std::vector<Fragment>& fragments,
const CoordBBox& bbox,
2596 const LeafNodeType& distLeaf,
const Int32LeafNodeType& idxLeaf)
const 2598 const typename LeafNodeType::NodeMaskType& mask = distLeaf.getValueMask();
2599 const ValueType* distData = distLeaf.buffer().data();
2600 const Int32* idxData = idxLeaf.buffer().data();
2602 for (
int x = bbox.
min()[0]; x <= bbox.
max()[0]; ++x) {
2603 const Index xPos = (x & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
2604 for (
int y = bbox.
min()[1]; y <= bbox.
max()[1]; ++y) {
2605 const Index yPos = xPos + ((y & (LeafNodeType::DIM - 1u)) << LeafNodeType::LOG2DIM);
2606 for (
int z = bbox.
min()[2]; z <= bbox.
max()[2]; ++z) {
2607 const Index pos = yPos + (z & (LeafNodeType::DIM - 1u));
2608 if (mask.isOn(pos)) {
2609 fragments.push_back(
Fragment(idxData[pos],x,y,z, std::abs(distData[pos])));
2619 computeDistance(
const Coord& ijk,
const Int32 manhattanLimit,
2620 const std::vector<Fragment>& fragments,
Int32& closestPrimIdx)
const 2622 Vec3d a, b, c, uvw, voxelCenter(ijk[0], ijk[1], ijk[2]);
2626 for (
size_t n = 0, N = fragments.size(); n < N; ++n) {
2628 const Fragment& fragment = fragments[n];
2629 if (lastIdx == fragment.
idx)
continue;
2631 const Int32 dx = std::abs(fragment.
x - ijk[0]);
2632 const Int32 dy = std::abs(fragment.
y - ijk[1]);
2633 const Int32 dz = std::abs(fragment.
z - ijk[2]);
2635 const Int32 manhattan = dx + dy + dz;
2636 if (manhattan > manhattanLimit)
continue;
2638 lastIdx = fragment.
idx;
2640 const size_t polygon = size_t(lastIdx);
2642 mMesh->getIndexSpacePoint(polygon, 0, a);
2643 mMesh->getIndexSpacePoint(polygon, 1, b);
2644 mMesh->getIndexSpacePoint(polygon, 2, c);
2646 primDist = (voxelCenter -
2650 if (4 == mMesh->vertexCount(polygon)) {
2652 mMesh->getIndexSpacePoint(polygon, 3, b);
2655 a, b, c, voxelCenter, uvw)).lengthSqr();
2657 if (tmpDist < primDist) primDist = tmpDist;
2660 if (primDist < dist) {
2662 closestPrimIdx = lastIdx;
2666 return ValueType(std::sqrt(dist)) * mVoxelSize;
2672 updateVoxel(
const Coord& ijk,
const Int32 manhattanLimit,
2673 const std::vector<Fragment>& fragments,
2674 LeafNodeType& distLeaf, Int32LeafNodeType& idxLeaf,
bool* updatedLeafNodes = NULL)
2676 Int32 closestPrimIdx = 0;
2677 const ValueType distance = computeDistance(ijk, manhattanLimit, fragments, closestPrimIdx);
2679 const Index pos = LeafNodeType::coordToOffset(ijk);
2680 const bool inside = distLeaf.getValue(pos) < ValueType(0.0);
2682 bool activateNeighbourVoxels =
false;
2684 if (!inside && distance < mExteriorBandWidth) {
2685 if (updatedLeafNodes) *updatedLeafNodes =
true;
2686 activateNeighbourVoxels = (distance + mVoxelSize) < mExteriorBandWidth;
2687 distLeaf.setValueOnly(pos, distance);
2688 idxLeaf.setValueOn(pos, closestPrimIdx);
2689 }
else if (inside && distance < mInteriorBandWidth) {
2690 if (updatedLeafNodes) *updatedLeafNodes =
true;
2691 activateNeighbourVoxels = (distance + mVoxelSize) < mInteriorBandWidth;
2692 distLeaf.setValueOnly(pos, -distance);
2693 idxLeaf.setValueOn(pos, closestPrimIdx);
2696 return activateNeighbourVoxels;
2701 BoolLeafNodeType **
const mMaskNodes;
2702 BoolTreeType *
const mMaskTree;
2703 TreeType *
const mDistTree;
2704 Int32TreeType *
const mIndexTree;
2708 BoolTreeType mNewMaskTree;
2710 std::vector<LeafNodeType*> mDistNodes, mUpdatedDistNodes;
2711 std::vector<Int32LeafNodeType*> mIndexNodes, mUpdatedIndexNodes;
2713 const ValueType mExteriorBandWidth, mInteriorBandWidth, mVoxelSize;
2717 template<
typename TreeType>
2721 AddNodes(TreeType& tree, std::vector<LeafNodeType*>& nodes)
2722 : mTree(&tree) , mNodes(&nodes)
2728 std::vector<LeafNodeType*>& nodes = *mNodes;
2729 for (
size_t n = 0, N = nodes.size(); n < N; ++n) {
2739 template<
typename TreeType,
typename Int32TreeType,
typename BoolTreeType,
typename MeshDataAdapter>
2743 Int32TreeType& indexTree,
2744 BoolTreeType& maskTree,
2745 std::vector<typename BoolTreeType::LeafNodeType*>& maskNodes,
2747 typename TreeType::ValueType exteriorBandWidth,
2748 typename TreeType::ValueType interiorBandWidth,
2749 typename TreeType::ValueType voxelSize)
2752 distTree, indexTree, mesh, exteriorBandWidth, interiorBandWidth, voxelSize);
2754 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, maskNodes.size()), expandOp);
2756 tbb::parallel_for(tbb::blocked_range<size_t>(0, expandOp.
updatedIndexNodes().size()),
2760 tbb::task_group tasks;
2774 template<
typename TreeType>
2781 ValueType voxelSize,
bool unsignedDist)
2783 , mVoxelSize(voxelSize)
2784 , mUnsigned(unsignedDist)
2790 typename LeafNodeType::ValueOnIter iter;
2792 const bool udf = mUnsigned;
2793 const ValueType w[2] = { -mVoxelSize, mVoxelSize };
2795 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2797 for (iter = mNodes[n]->beginValueOn(); iter; ++iter) {
2798 ValueType& val =
const_cast<ValueType&
>(iter.getValue());
2799 val = w[udf || (val < ValueType(0.0))] * std::sqrt(std::abs(val));
2805 LeafNodeType * *
const mNodes;
2806 const ValueType mVoxelSize;
2807 const bool mUnsigned;
2812 template<
typename TreeType>
2819 ValueType exBandWidth, ValueType inBandWidth)
2820 : mNodes(nodes.empty() ? NULL : &nodes[0])
2821 , mExBandWidth(exBandWidth)
2822 , mInBandWidth(inBandWidth)
2828 typename LeafNodeType::ValueOnIter iter;
2829 const ValueType exVal = mExBandWidth;
2830 const ValueType inVal = -mInBandWidth;
2832 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2834 for (iter = mNodes[n]->beginValueOn(); iter; ++iter) {
2836 ValueType& val =
const_cast<ValueType&
>(iter.getValue());
2838 const bool inside = val < ValueType(0.0);
2840 if (inside && !(val > inVal)) {
2843 }
else if (!inside && !(val < exVal)) {
2852 LeafNodeType * *
const mNodes;
2853 const ValueType mExBandWidth, mInBandWidth;
2857 template<
typename TreeType>
2864 : mNodes(nodes.empty() ? NULL : &nodes[0]), mOffset(offset)
2870 const ValueType offset = mOffset;
2872 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2874 typename LeafNodeType::ValueOnIter iter = mNodes[n]->beginValueOn();
2876 for (; iter; ++iter) {
2877 ValueType& val =
const_cast<ValueType&
>(iter.getValue());
2884 LeafNodeType * *
const mNodes;
2885 const ValueType mOffset;
2889 template<
typename TreeType>
2895 Renormalize(
const TreeType& tree,
const std::vector<LeafNodeType*>& nodes, ValueType* buffer, ValueType voxelSize)
2897 , mNodes(nodes.empty() ? NULL : &nodes[0])
2899 , mVoxelSize(voxelSize)
2912 const ValueType dx = mVoxelSize, invDx = ValueType(1.0) / mVoxelSize;
2914 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2916 ValueType* bufferData = &mBuffer[n * LeafNodeType::SIZE];
2918 typename LeafNodeType::ValueOnCIter iter = mNodes[n]->cbeginValueOn();
2919 for (; iter; ++iter) {
2921 const ValueType phi0 = *iter;
2923 ijk = iter.getCoord();
2935 const ValueType diff =
math::Sqrt(normSqGradPhi) * invDx - ValueType(1.0);
2938 bufferData[iter.pos()] = phi0 - dx * S * diff;
2944 TreeType
const *
const mTree;
2945 LeafNodeType
const *
const *
const mNodes;
2946 ValueType *
const mBuffer;
2948 const ValueType mVoxelSize;
2952 template<
typename TreeType>
2958 MinCombine(std::vector<LeafNodeType*>& nodes,
const ValueType* buffer)
2959 : mNodes(nodes.empty() ? NULL : &nodes[0]), mBuffer(buffer)
2965 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2967 const ValueType* bufferData = &mBuffer[n * LeafNodeType::SIZE];
2969 typename LeafNodeType::ValueOnIter iter = mNodes[n]->beginValueOn();
2971 for (; iter; ++iter) {
2972 ValueType& val =
const_cast<ValueType&
>(iter.getValue());
2973 val =
std::min(val, bufferData[iter.pos()]);
2979 LeafNodeType * *
const mNodes;
2980 ValueType
const *
const mBuffer;
2992 template <
typename FloatTreeT>
2998 ConnectivityTable nodeConnectivity(tree);
3000 std::vector<size_t> zStartNodes, yStartNodes, xStartNodes;
3002 for (
size_t n = 0; n < nodeConnectivity.size(); ++n) {
3003 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevX()[n]) {
3004 xStartNodes.push_back(n);
3007 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevY()[n]) {
3008 yStartNodes.push_back(n);
3011 if (ConnectivityTable::INVALID_OFFSET == nodeConnectivity.offsetsPrevZ()[n]) {
3012 zStartNodes.push_back(n);
3018 tbb::parallel_for(tbb::blocked_range<size_t>(0, zStartNodes.size()),
3021 tbb::parallel_for(tbb::blocked_range<size_t>(0, yStartNodes.size()),
3024 tbb::parallel_for(tbb::blocked_range<size_t>(0, xStartNodes.size()),
3027 const size_t numLeafNodes = nodeConnectivity.size();
3028 const size_t numVoxels = numLeafNodes * FloatTreeT::LeafNodeType::SIZE;
3030 boost::scoped_array<bool> changedNodeMaskA(
new bool[numLeafNodes]);
3031 boost::scoped_array<bool> changedNodeMaskB(
new bool[numLeafNodes]);
3032 boost::scoped_array<bool> changedVoxelMask(
new bool[numVoxels]);
3034 memset(changedNodeMaskA.get(), 1,
sizeof(bool) * numLeafNodes);
3037 const tbb::blocked_range<size_t> nodeRange(0, numLeafNodes);
3039 bool nodesUpdated =
false;
3042 nodeConnectivity.nodes(), changedNodeMaskA.get()));
3045 changedNodeMaskA.get(), changedNodeMaskB.get(), changedVoxelMask.get()));
3047 changedNodeMaskA.swap(changedNodeMaskB);
3049 nodesUpdated =
false;
3050 for (
size_t n = 0; n < numLeafNodes; ++n) {
3051 nodesUpdated |= changedNodeMaskA[n];
3052 if (nodesUpdated)
break;
3057 nodeConnectivity.nodes(), changedNodeMaskA.get(), changedVoxelMask.get()));
3059 }
while (nodesUpdated);
3067 template <
typename Gr
idType,
typename MeshDataAdapter,
typename Interrupter>
3068 inline typename GridType::Ptr
3070 Interrupter& interrupter,
3073 float exteriorBandWidth,
3074 float interiorBandWidth,
3078 typedef typename GridType::Ptr GridTypePtr;
3079 typedef typename GridType::TreeType TreeType;
3080 typedef typename TreeType::LeafNodeType LeafNodeType;
3081 typedef typename GridType::ValueType ValueType;
3084 typedef typename Int32GridType::TreeType Int32TreeType;
3086 typedef typename TreeType::template ValueConverter<bool>::Type BoolTreeType;
3093 distGrid->setTransform(transform.
copy());
3095 ValueType exteriorWidth = ValueType(exteriorBandWidth);
3096 ValueType interiorWidth = ValueType(interiorBandWidth);
3100 if (!boost::math::isfinite(exteriorWidth) || boost::math::isnan(interiorWidth)) {
3101 std::stringstream msg;
3102 msg <<
"Illegal narrow band width: exterior = " << exteriorWidth
3103 <<
", interior = " << interiorWidth;
3108 const ValueType voxelSize = ValueType(transform.
voxelSize()[0]);
3110 if (!boost::math::isfinite(voxelSize) ||
math::isZero(voxelSize)) {
3111 std::stringstream msg;
3112 msg <<
"Illegal transform, voxel size = " << voxelSize;
3118 exteriorWidth *= voxelSize;
3122 interiorWidth *= voxelSize;
3130 Int32GridType* indexGrid = NULL;
3132 typename Int32GridType::Ptr temporaryIndexGrid;
3134 if (polygonIndexGrid) {
3135 indexGrid = polygonIndexGrid;
3138 indexGrid = temporaryIndexGrid.get();
3141 indexGrid->newTree();
3142 indexGrid->setTransform(transform.
copy());
3144 if (computeSignedDistanceField) {
3148 interiorWidth = ValueType(0.0);
3151 TreeType& distTree = distGrid->tree();
3152 Int32TreeType& indexTree = indexGrid->tree();
3161 typedef tbb::enumerable_thread_specific<typename VoxelizationDataType::Ptr> DataTable;
3166 const tbb::blocked_range<size_t> polygonRange(0, mesh.polygonCount());
3168 tbb::parallel_for(polygonRange, Voxelizer(data, mesh, &interrupter));
3170 for (
typename DataTable::iterator i = data.begin(); i != data.end(); ++i) {
3171 VoxelizationDataType& dataItem = **i;
3173 distTree, indexTree, dataItem.distTree, dataItem.indexTree);
3179 if (interrupter.wasInterrupted(30))
return distGrid;
3186 if (computeSignedDistanceField) {
3191 std::vector<LeafNodeType*> nodes;
3192 nodes.reserve(distTree.leafCount());
3193 distTree.getNodes(nodes);
3195 const tbb::blocked_range<size_t> nodeRange(0, nodes.size());
3199 tbb::parallel_for(nodeRange, SignOp(nodes, distTree, indexTree, mesh));
3201 if (interrupter.wasInterrupted(45))
return distGrid;
3204 if (removeIntersectingVoxels) {
3206 tbb::parallel_for(nodeRange,
3209 tbb::parallel_for(nodeRange,
3211 nodes, distTree, indexTree));
3218 if (interrupter.wasInterrupted(50))
return distGrid;
3220 if (distTree.activeVoxelCount() == 0) {
3222 distTree.root().setBackground(exteriorWidth,
false);
3228 std::vector<LeafNodeType*> nodes;
3229 nodes.reserve(distTree.leafCount());
3230 distTree.getNodes(nodes);
3232 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3234 nodes, voxelSize, !computeSignedDistanceField));
3238 if (computeSignedDistanceField) {
3239 distTree.root().setBackground(exteriorWidth,
false);
3245 if (interrupter.wasInterrupted(54))
return distGrid;
3252 const ValueType minBandWidth = voxelSize * ValueType(2.0);
3254 if (interiorWidth > minBandWidth || exteriorWidth > minBandWidth) {
3257 BoolTreeType maskTree(
false);
3260 std::vector<LeafNodeType*> nodes;
3261 nodes.reserve(distTree.leafCount());
3262 distTree.getNodes(nodes);
3265 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), op);
3271 float progress = 54.0f, step = 0.0f;
3273 2.0 * std::ceil((
std::max(interiorWidth, exteriorWidth) - minBandWidth) / voxelSize);
3275 if (estimated <
double(maxIterations)) {
3276 maxIterations = unsigned(estimated);
3277 step = 40.0f / float(maxIterations);
3280 std::vector<typename BoolTreeType::LeafNodeType*> maskNodes;
3285 if (interrupter.wasInterrupted(
int(progress)))
return distGrid;
3287 const size_t maskNodeCount = maskTree.leafCount();
3288 if (maskNodeCount == 0)
break;
3291 maskNodes.reserve(maskNodeCount);
3292 maskTree.getNodes(maskNodes);
3294 const tbb::blocked_range<size_t> range(0, maskNodes.size());
3296 tbb::parallel_for(range,
3300 mesh, exteriorWidth, interiorWidth, voxelSize);
3302 if ((++count) >= maxIterations)
break;
3307 if (interrupter.wasInterrupted(94))
return distGrid;
3309 if (!polygonIndexGrid) indexGrid->clear();
3317 if (computeSignedDistanceField && renormalizeValues) {
3319 std::vector<LeafNodeType*> nodes;
3320 nodes.reserve(distTree.leafCount());
3321 distTree.getNodes(nodes);
3323 boost::scoped_array<ValueType> buffer(
new ValueType[LeafNodeType::SIZE * nodes.size()]);
3325 const ValueType offset = ValueType(0.8 * voxelSize);
3327 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3330 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3332 distTree, nodes, buffer.get(), voxelSize));
3334 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3337 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3342 if (interrupter.wasInterrupted(99))
return distGrid;
3349 if (trimNarrowBand &&
std::min(interiorWidth, exteriorWidth) < voxelSize * ValueType(4.0)) {
3351 std::vector<LeafNodeType*> nodes;
3352 nodes.reserve(distTree.leafCount());
3353 distTree.getNodes(nodes);
3355 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
3357 nodes, exteriorWidth, computeSignedDistanceField ? interiorWidth : exteriorWidth));
3360 distTree, exteriorWidth, computeSignedDistanceField ? -interiorWidth : -exteriorWidth);
3367 template <
typename Gr
idType,
typename MeshDataAdapter>
3368 inline typename GridType::Ptr
3372 float exteriorBandWidth,
3373 float interiorBandWidth,
3378 return meshToVolume<GridType>(nullInterrupter, mesh, transform,
3379 exteriorBandWidth, interiorBandWidth, flags, polygonIndexGrid);
3387 template<
typename Gr
idType,
typename Interrupter>
3388 inline typename boost::enable_if<boost::is_floating_point<typename GridType::ValueType>,
3389 typename GridType::Ptr>::type
3391 Interrupter& interrupter,
3392 const openvdb::math::Transform& xform,
3393 const std::vector<Vec3s>& points,
3394 const std::vector<Vec3I>& triangles,
3395 const std::vector<Vec4I>& quads,
3398 bool unsignedDistanceField =
false)
3400 if (points.empty()) {
3401 return typename GridType::Ptr(
new GridType(
typename GridType::ValueType(exBandWidth)));
3404 const size_t numPoints = points.size();
3405 boost::scoped_array<Vec3s> indexSpacePoints(
new Vec3s[numPoints]);
3408 tbb::parallel_for(tbb::blocked_range<size_t>(0, numPoints),
3410 &points[0], indexSpacePoints.get(), xform));
3414 if (quads.empty()) {
3417 mesh(indexSpacePoints.get(), numPoints, &triangles[0], triangles.size());
3419 return meshToVolume<GridType>(mesh, xform, exBandWidth, inBandWidth, conversionFlags);
3421 }
else if (triangles.empty()) {
3424 mesh(indexSpacePoints.get(), numPoints, &quads[0], quads.size());
3426 return meshToVolume<GridType>(mesh, xform, exBandWidth, inBandWidth, conversionFlags);
3431 const size_t numPrimitives = triangles.size() + quads.size();
3432 boost::scoped_array<Vec4I> prims(
new Vec4I[numPrimitives]);
3434 for (
size_t n = 0, N = triangles.size(); n < N; ++n) {
3435 const Vec3I& triangle = triangles[n];
3436 Vec4I& prim = prims[n];
3437 prim[0] = triangle[0];
3438 prim[1] = triangle[1];
3439 prim[2] = triangle[2];
3443 const size_t offset = triangles.size();
3444 for (
size_t n = 0, N = quads.size(); n < N; ++n) {
3445 prims[offset + n] = quads[n];
3449 mesh(indexSpacePoints.get(), numPoints, prims.get(), numPrimitives);
3451 return meshToVolume<GridType>(interrupter, mesh, xform, exBandWidth, inBandWidth, conversionFlags);
3457 template<
typename Gr
idType,
typename Interrupter>
3458 inline typename boost::disable_if<boost::is_floating_point<typename GridType::ValueType>,
3459 typename GridType::Ptr>::type
3463 const std::vector<Vec3s>& ,
3464 const std::vector<Vec3I>& ,
3465 const std::vector<Vec4I>& ,
3471 "mesh to volume conversion is supported only for scalar floating-point grids");
3478 template<
typename Gr
idType>
3479 inline typename GridType::Ptr
3481 const openvdb::math::Transform& xform,
3482 const std::vector<Vec3s>& points,
3483 const std::vector<Vec3I>& triangles,
3487 std::vector<Vec4I> quads(0);
3488 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles, quads,
3489 halfWidth, halfWidth);
3493 template<
typename Gr
idType,
typename Interrupter>
3494 inline typename GridType::Ptr
3496 Interrupter& interrupter,
3497 const openvdb::math::Transform& xform,
3498 const std::vector<Vec3s>& points,
3499 const std::vector<Vec3I>& triangles,
3502 std::vector<Vec4I> quads(0);
3503 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3504 halfWidth, halfWidth);
3508 template<
typename Gr
idType>
3509 inline typename GridType::Ptr
3511 const openvdb::math::Transform& xform,
3512 const std::vector<Vec3s>& points,
3513 const std::vector<Vec4I>& quads,
3517 std::vector<Vec3I> triangles(0);
3518 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles, quads,
3519 halfWidth, halfWidth);
3523 template<
typename Gr
idType,
typename Interrupter>
3524 inline typename GridType::Ptr
3526 Interrupter& interrupter,
3527 const openvdb::math::Transform& xform,
3528 const std::vector<Vec3s>& points,
3529 const std::vector<Vec4I>& quads,
3532 std::vector<Vec3I> triangles(0);
3533 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3534 halfWidth, halfWidth);
3538 template<
typename Gr
idType>
3539 inline typename GridType::Ptr
3541 const openvdb::math::Transform& xform,
3542 const std::vector<Vec3s>& points,
3543 const std::vector<Vec3I>& triangles,
3544 const std::vector<Vec4I>& quads,
3548 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles, quads,
3549 halfWidth, halfWidth);
3553 template<
typename Gr
idType,
typename Interrupter>
3554 inline typename GridType::Ptr
3556 Interrupter& interrupter,
3557 const openvdb::math::Transform& xform,
3558 const std::vector<Vec3s>& points,
3559 const std::vector<Vec3I>& triangles,
3560 const std::vector<Vec4I>& quads,
3563 return doMeshConversion<GridType>(interrupter, xform, points, triangles, quads,
3564 halfWidth, halfWidth);
3568 template<
typename Gr
idType>
3569 inline typename GridType::Ptr
3571 const openvdb::math::Transform& xform,
3572 const std::vector<Vec3s>& points,
3573 const std::vector<Vec3I>& triangles,
3574 const std::vector<Vec4I>& quads,
3579 return doMeshConversion<GridType>(nullInterrupter, xform, points, triangles,
3580 quads, exBandWidth, inBandWidth);
3584 template<
typename Gr
idType,
typename Interrupter>
3585 inline typename GridType::Ptr
3587 Interrupter& interrupter,
3588 const openvdb::math::Transform& xform,
3589 const std::vector<Vec3s>& points,
3590 const std::vector<Vec3I>& triangles,
3591 const std::vector<Vec4I>& quads,
3595 return doMeshConversion<GridType>(interrupter, xform, points, triangles,
3596 quads, exBandWidth, inBandWidth);
3600 template<
typename Gr
idType>
3601 inline 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 doMeshConversion<GridType>(nullInterrupter, xform, points, triangles, quads,
3611 bandWidth, bandWidth,
true);
3615 template<
typename Gr
idType,
typename Interrupter>
3616 inline 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 bandWidth, bandWidth,
true);
3634 inline std::ostream&
3637 ostr <<
"{[ " << rhs.
mXPrim <<
", " << rhs.
mXDist <<
"]";
3638 ostr <<
" [ " << rhs.
mYPrim <<
", " << rhs.
mYDist <<
"]";
3639 ostr <<
" [ " << rhs.
mZPrim <<
", " << rhs.
mZDist <<
"]}";
3659 const std::vector<Vec3s>& pointList,
3660 const std::vector<Vec4I>& polygonList);
3662 void run(
bool threaded =
true);
3665 inline void operator() (
const tbb::blocked_range<size_t> &range);
3673 struct Primitive {
Vec3d a, b, c, d;
Int32 index; };
3675 template<
bool IsQuad>
3676 inline void voxelize(
const Primitive&);
3678 template<
bool IsQuad>
3679 inline bool evalPrimitive(
const Coord&,
const Primitive&);
3681 inline bool rayTriangleIntersection(
const Vec3d& origin,
const Vec3d& dir,
3688 const std::vector<Vec3s>& mPointList;
3689 const std::vector<Vec4I>& mPolygonList;
3693 IntTreeT mLastPrimTree;
3699 MeshToVoxelEdgeData::GenEdgeData::GenEdgeData(
3700 const std::vector<Vec3s>& pointList,
3701 const std::vector<Vec4I>& polygonList)
3704 , mPointList(pointList)
3705 , mPolygonList(polygonList)
3707 , mLastPrimAccessor(mLastPrimTree)
3716 , mPointList(rhs.mPointList)
3717 , mPolygonList(rhs.mPolygonList)
3719 , mLastPrimAccessor(mLastPrimTree)
3728 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, mPolygonList.size()), *
this);
3730 (*this)(tbb::blocked_range<size_t>(0, mPolygonList.size()));
3739 typedef RootNodeType::NodeChainType NodeChainType;
3740 BOOST_STATIC_ASSERT(boost::mpl::size<NodeChainType>::value > 1);
3741 typedef boost::mpl::at<NodeChainType, boost::mpl::int_<1> >::type InternalNodeType;
3749 for ( ; leafIt; ++leafIt) {
3750 ijk = leafIt->origin();
3757 InternalNodeType* node = rhs.mAccessor.
getNode<InternalNodeType>();
3759 rhs.mAccessor.
clear();
3769 if (!lhsLeafPt->isValueOn(offset)) {
3770 lhsLeafPt->setValueOn(offset, rhsValue);
3802 for (
size_t n = range.begin(); n < range.end(); ++n) {
3804 const Vec4I& verts = mPolygonList[n];
3806 prim.index =
Int32(n);
3807 prim.a =
Vec3d(mPointList[verts[0]]);
3808 prim.b =
Vec3d(mPointList[verts[1]]);
3809 prim.c =
Vec3d(mPointList[verts[2]]);
3812 prim.d =
Vec3d(mPointList[verts[3]]);
3813 voxelize<true>(prim);
3815 voxelize<false>(prim);
3821 template<
bool IsQuad>
3823 MeshToVoxelEdgeData::GenEdgeData::voxelize(
const Primitive& prim)
3825 std::deque<Coord> coordList;
3829 coordList.push_back(ijk);
3831 evalPrimitive<IsQuad>(ijk, prim);
3833 while (!coordList.empty()) {
3835 ijk = coordList.back();
3836 coordList.pop_back();
3838 for (
Int32 i = 0; i < 26; ++i) {
3841 if (prim.index != mLastPrimAccessor.
getValue(nijk)) {
3842 mLastPrimAccessor.
setValue(nijk, prim.index);
3843 if(evalPrimitive<IsQuad>(nijk, prim)) coordList.push_back(nijk);
3850 template<
bool IsQuad>
3852 MeshToVoxelEdgeData::GenEdgeData::evalPrimitive(
const Coord& ijk,
const Primitive& prim)
3854 Vec3d uvw, org(ijk[0], ijk[1], ijk[2]);
3855 bool intersecting =
false;
3862 double dist = (org -
3865 if (rayTriangleIntersection(org,
Vec3d(1.0, 0.0, 0.0), prim.a, prim.c, prim.b, t)) {
3866 if (t < edgeData.
mXDist) {
3867 edgeData.
mXDist = float(t);
3868 edgeData.
mXPrim = prim.index;
3869 intersecting =
true;
3873 if (rayTriangleIntersection(org,
Vec3d(0.0, 1.0, 0.0), prim.a, prim.c, prim.b, t)) {
3874 if (t < edgeData.
mYDist) {
3875 edgeData.
mYDist = float(t);
3876 edgeData.
mYPrim = prim.index;
3877 intersecting =
true;
3881 if (rayTriangleIntersection(org,
Vec3d(0.0, 0.0, 1.0), prim.a, prim.c, prim.b, t)) {
3882 if (t < edgeData.
mZDist) {
3883 edgeData.
mZDist = float(t);
3884 edgeData.
mZPrim = prim.index;
3885 intersecting =
true;
3891 double secondDist = (org -
3894 if (secondDist < dist) dist = secondDist;
3896 if (rayTriangleIntersection(org,
Vec3d(1.0, 0.0, 0.0), prim.a, prim.d, prim.c, t)) {
3897 if (t < edgeData.
mXDist) {
3898 edgeData.
mXDist = float(t);
3899 edgeData.
mXPrim = prim.index;
3900 intersecting =
true;
3904 if (rayTriangleIntersection(org,
Vec3d(0.0, 1.0, 0.0), prim.a, prim.d, prim.c, t)) {
3905 if (t < edgeData.
mYDist) {
3906 edgeData.
mYDist = float(t);
3907 edgeData.
mYPrim = prim.index;
3908 intersecting =
true;
3912 if (rayTriangleIntersection(org,
Vec3d(0.0, 0.0, 1.0), prim.a, prim.d, prim.c, t)) {
3913 if (t < edgeData.
mZDist) {
3914 edgeData.
mZDist = float(t);
3915 edgeData.
mZPrim = prim.index;
3916 intersecting =
true;
3921 if (intersecting) mAccessor.
setValue(ijk, edgeData);
3923 return (dist < 0.86602540378443861);
3928 MeshToVoxelEdgeData::GenEdgeData::rayTriangleIntersection(
3939 double divisor = s1.
dot(e1);
3940 if (!(std::abs(divisor) > 0.0))
return false;
3944 double inv_divisor = 1.0 / divisor;
3945 Vec3d d = origin - a;
3946 double b1 = d.
dot(s1) * inv_divisor;
3948 if (b1 < 0.0 || b1 > 1.0)
return false;
3951 double b2 = dir.
dot(s2) * inv_divisor;
3953 if (b2 < 0.0 || (b1 + b2) > 1.0)
return false;
3957 t = e2.dot(s2) * inv_divisor;
3958 return (t < 0.0) ?
false :
true;
3974 const std::vector<Vec3s>& pointList,
3975 const std::vector<Vec4I>& polygonList)
3989 std::vector<Vec3d>& points,
3990 std::vector<Index32>& primitives)
4000 point[0] = double(coord[0]) + data.
mXDist;
4001 point[1] = double(coord[1]);
4002 point[2] = double(coord[2]);
4004 points.push_back(point);
4005 primitives.push_back(data.
mXPrim);
4009 point[0] = double(coord[0]);
4010 point[1] = double(coord[1]) + data.
mYDist;
4011 point[2] = double(coord[2]);
4013 points.push_back(point);
4014 primitives.push_back(data.
mYPrim);
4018 point[0] = double(coord[0]);
4019 point[1] = double(coord[1]);
4020 point[2] = double(coord[2]) + data.
mZDist;
4022 points.push_back(point);
4023 primitives.push_back(data.
mZPrim);
4033 point[0] = double(coord[0]);
4034 point[1] = double(coord[1]) + data.
mYDist;
4035 point[2] = double(coord[2]);
4037 points.push_back(point);
4038 primitives.push_back(data.
mYPrim);
4042 point[0] = double(coord[0]);
4043 point[1] = double(coord[1]);
4044 point[2] = double(coord[2]) + data.
mZDist;
4046 points.push_back(point);
4047 primitives.push_back(data.
mZPrim);
4055 point[0] = double(coord[0]);
4056 point[1] = double(coord[1]) + data.
mYDist;
4057 point[2] = double(coord[2]);
4059 points.push_back(point);
4060 primitives.push_back(data.
mYPrim);
4069 point[0] = double(coord[0]) + data.
mXDist;
4070 point[1] = double(coord[1]);
4071 point[2] = double(coord[2]);
4073 points.push_back(point);
4074 primitives.push_back(data.
mXPrim);
4078 point[0] = double(coord[0]);
4079 point[1] = double(coord[1]) + data.
mYDist;
4080 point[2] = double(coord[2]);
4082 points.push_back(point);
4083 primitives.push_back(data.
mYPrim);
4093 point[0] = double(coord[0]) + data.
mXDist;
4094 point[1] = double(coord[1]);
4095 point[2] = double(coord[2]);
4097 points.push_back(point);
4098 primitives.push_back(data.
mXPrim);
4107 point[0] = double(coord[0]) + data.
mXDist;
4108 point[1] = double(coord[1]);
4109 point[2] = double(coord[2]);
4111 points.push_back(point);
4112 primitives.push_back(data.
mXPrim);
4116 point[0] = double(coord[0]);
4117 point[1] = double(coord[1]);
4118 point[2] = double(coord[2]) + data.
mZDist;
4120 points.push_back(point);
4121 primitives.push_back(data.
mZPrim);
4130 point[0] = double(coord[0]);
4131 point[1] = double(coord[1]);
4132 point[2] = double(coord[2]) + data.
mZDist;
4134 points.push_back(point);
4135 primitives.push_back(data.
mZPrim);
4141 template<
typename Gr
idType,
typename VecType>
4142 inline typename GridType::Ptr
4144 const openvdb::math::Transform& xform,
4145 typename VecType::ValueType halfWidth)
4151 points[0] =
Vec3s(pmin[0], pmin[1], pmin[2]);
4152 points[1] =
Vec3s(pmin[0], pmin[1], pmax[2]);
4153 points[2] =
Vec3s(pmax[0], pmin[1], pmax[2]);
4154 points[3] =
Vec3s(pmax[0], pmin[1], pmin[2]);
4155 points[4] =
Vec3s(pmin[0], pmax[1], pmin[2]);
4156 points[5] =
Vec3s(pmin[0], pmax[1], pmax[2]);
4157 points[6] =
Vec3s(pmax[0], pmax[1], pmax[2]);
4158 points[7] =
Vec3s(pmax[0], pmax[1], pmin[2]);
4161 faces[0] =
Vec4I(0, 1, 2, 3);
4162 faces[1] =
Vec4I(7, 6, 5, 4);
4163 faces[2] =
Vec4I(4, 5, 1, 0);
4164 faces[3] =
Vec4I(6, 7, 3, 2);
4165 faces[4] =
Vec4I(0, 3, 7, 4);
4166 faces[5] =
Vec4I(1, 5, 6, 2);
4170 return meshToVolume<GridType>(mesh, xform, halfWidth, halfWidth);
4178 #endif // OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED void addLeaf(LeafNodeT *leaf)
Add the specified leaf to this tree, possibly creating a child branch in the process. If the leaf node already exists, replace it.
Definition: ValueAccessor.h:374
OPENVDB_API const Index32 INVALID_IDX
OPENVDB_API const Coord COORD_OFFSETS[26]
coordinate offset table for neighboring voxels
Vec3< float > Vec3s
Definition: Vec3.h:650
static Coord max()
Return the largest possible coordinate.
Definition: Coord.h:72
LeafNodeT * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z), or NULL if no such node exists...
Definition: ValueAccessor.h:424
T dot(const Vec3< T > &v) const
Dot product.
Definition: Vec3.h:203
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition: Coord.h:191
math::Vec4< Index32 > Vec4I
Definition: Types.h:90
const ValueT & getValue() const
Return the tile or voxel value to which this iterator is currently pointing.
Definition: TreeIterator.h:734
NodeType * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
Definition: ValueAccessor.h:349
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:407
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
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:52
void merge(Tree &other, MergePolicy=MERGE_ACTIVE_STATES)
Efficiently merge another tree into this tree using one of several schemes.
Definition: Tree.h:1850
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
Definition: ValueAccessor.h:266
#define OPENVDB_LOG_DEBUG(message)
In debug builds only, log a debugging message of the form 'someVar << "text" << ...'.
Definition: logging.h:45
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:727
Convert polygonal meshes that consist of quads and/or triangles into signed or unsigned distance fiel...
Type Pow2(Type x)
Return .
Definition: Math.h:514
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
ValueConverter<T>::Type is the type of a tree having the same hierarchy as this tree but a different ...
Definition: Tree.h:225
Efficient multi-threaded replacement of the background values in tree.
static const Real LEVEL_SET_HALF_WIDTH
Definition: Types.h:219
bool isZero(const Type &x)
Return true if x is exactly equal to zero.
Definition: Math.h:324
Tree< typename RootNodeType::template ValueConverter< Int32 >::Type > Type
Definition: Tree.h:226
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:47
void maxComponent(const Coord &other)
Perform a component-wise maximum with the other Coord.
Definition: Coord.h:199
Base class for tree-traversal iterators over tile and voxel values.
Definition: TreeIterator.h:658
Axis-aligned bounding box.
Definition: BBox.h:47
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinate but don't change its active state.
Definition: ValueAccessor.h:296
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:292
Defined various multi-threaded utility functions for trees.
Index32 Index
Definition: Types.h:58
_RootNodeType RootNodeType
Definition: Tree.h:211
int32_t Int32
Definition: Types.h:60
bool operator<(const Tuple< SIZE, T0 > &t0, const Tuple< SIZE, T1 > &t1)
Definition: Tuple.h:158
#define OPENVDB_VERSION_NAME
Definition: version.h:43
Vec3< double > Vec3d
Definition: Vec3.h:651
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition: Coord.h:401
void clear()
Remove all tiles from this tree and all nodes other than the root node.
Definition: Tree.h:1486
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:256
Propagates the sign of distance values from the active voxels in the narrow band to the inactive valu...
void clearAllAccessors()
Clear all registered accessors.
Definition: Tree.h:1545
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition: Coord.h:111
static Coord floor(const Vec3< T > &xyz)
Return the largest integer coordinates that are not greater than xyz (node centered conversion)...
Definition: Coord.h:82
Definition: Exceptions.h:39
uint32_t Index32
Definition: Types.h:56
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:263
const Vec3T & min() const
Return a const reference to the minimum point of the BBox.
Definition: BBox.h:81
Base class for tree-traversal iterators over all leaf nodes (but not leaf voxels) ...
Definition: TreeIterator.h:1228
const Vec3T & max() const
Return a const reference to the maximum point of the BBox.
Definition: BBox.h:84
virtual void clear()
Remove all nodes from this cache, then reinsert the root node.
Definition: ValueAccessor.h:438
bool normalize(T eps=T(1.0e-7))
this = normalized this
Definition: Vec3.h:348
LeafNodeT * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, create one, but preserve the values and active states of all voxels.
Definition: ValueAccessor.h:393
Definition: Exceptions.h:87
Vec3< T > cross(const Vec3< T > &v) const
Return the cross product of "this" vector and v;.
Definition: Vec3.h:232
const Coord & min() const
Definition: Coord.h:332
static Coord min()
Return the smallest possible coordinate.
Definition: Coord.h:69
const Coord & max() const
Definition: Coord.h:333
LeafNodeType * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, return NULL.
Definition: Tree.h:1732
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:259
bool operator>(const Tuple< SIZE, T0 > &t0, const Tuple< SIZE, T1 > &t1)
Definition: Tuple.h:170
bool isInside(const Coord &xyz) const
Return true if point (x, y, z) is inside this bounding box.
Definition: Coord.h:383
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
RootNodeType::LeafNodeType LeafNodeType
Definition: Tree.h:214
LeafIter beginLeaf()
Return an iterator over all leaf nodes in this tree.
Definition: Tree.h:1174
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains voxel (x, y, z), or NULL if no such node exists...
Definition: ValueAccessor.h:429
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 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:287
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76