45 #ifndef OPENVDB_TOOLS_POINT_PARTITIONER_HAS_BEEN_INCLUDED 46 #define OPENVDB_TOOLS_POINT_PARTITIONER_HAS_BEEN_INCLUDED 58 #include <boost/integer.hpp> 59 #include <boost/scoped_array.hpp> 60 #include <boost/shared_ptr.hpp> 61 #include <boost/math/special_functions/fpclassify.hpp> 63 #include <tbb/blocked_range.h> 64 #include <tbb/parallel_for.h> 65 #include <tbb/task_scheduler_init.h> 106 template<
typename Po
intIndexType = u
int32_t, Index BucketLog2Dim = 3>
110 enum { LOG2DIM = BucketLog2Dim };
112 typedef boost::shared_ptr<PointPartitioner>
Ptr;
113 typedef boost::shared_ptr<const PointPartitioner>
ConstPtr;
134 template<
typename Po
intArray>
136 bool voxelOrder =
false,
bool recordVoxelOffsets =
false,
bool cellCenteredTransform =
true);
148 template<
typename Po
intArray>
150 bool voxelOrder =
false,
bool recordVoxelOffsets =
false,
bool cellCenteredTransform =
true);
154 size_t size()
const {
return mPageCount; }
157 bool empty()
const {
return mPageCount == 0; }
174 const Coord&
origin(
size_t n)
const {
return mPageCoordinates[n]; }
190 boost::scoped_array<IndexType> mPointIndices;
191 VoxelOffsetArray mVoxelOffsets;
193 boost::scoped_array<IndexType> mPageOffsets;
194 boost::scoped_array<Coord> mPageCoordinates;
195 IndexType mPageCount;
196 bool mUsingCellCenteredTransform;
203 template<
typename Po
intIndexType, Index BucketLog2Dim>
210 : mBegin(begin), mEnd(end), mItem(begin) {}
216 size_t size()
const {
return mEnd - mBegin; }
219 IndexType&
operator*() { assert(mItem != NULL);
return *mItem; }
220 const IndexType&
operator*()
const { assert(mItem != NULL);
return *mItem; }
223 operator bool()
const {
return mItem < mEnd; }
224 bool test()
const {
return mItem < mEnd; }
230 bool next() { this->operator++();
return this->test(); }
238 IndexType *
const mBegin, *
const mEnd;
249 namespace point_partitioner_internal {
252 template<
typename Po
intIndexType>
256 const PointIndexType* bucketCounters,
const PointIndexType* bucketOffsets)
257 : mPointOrder(pointOrder)
258 , mBucketCounters(bucketCounters)
259 , mBucketOffsets(bucketOffsets)
263 void operator()(
const tbb::blocked_range<size_t>& range)
const {
264 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
265 mPointOrder[n] += mBucketCounters[mBucketOffsets[n]];
275 template<
typename Po
intIndexType>
279 const PointIndexType* pointOrder,
const PointIndexType* indices)
280 : mOrderedIndexArray(orderedIndexArray)
281 , mPointOrder(pointOrder)
286 void operator()(
const tbb::blocked_range<size_t>& range)
const {
287 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
288 mOrderedIndexArray[mPointOrder[n]] = mIndices[n];
298 template<
typename Po
intIndexType, Index BucketLog2Dim>
305 VoxelOrderOp(IndexArray& indices,
const IndexArray& pages,
const VoxelOffsetArray& offsets)
306 : mIndices(indices.get())
307 , mPages(pages.get())
308 , mVoxelOffsets(offsets.get())
312 void operator()(
const tbb::blocked_range<size_t>& range)
const {
314 PointIndexType pointCount = 0;
315 for (
size_t n(range.begin()), N(range.end()); n != N; ++n) {
316 pointCount =
std::max(pointCount, (mPages[n + 1] - mPages[n]));
319 const PointIndexType voxelCount = 1 << (3 * BucketLog2Dim);
322 boost::scoped_array<VoxelOffsetType> offsets(
new VoxelOffsetType[pointCount]);
323 boost::scoped_array<PointIndexType> sortedIndices(
new PointIndexType[pointCount]);
324 boost::scoped_array<PointIndexType>
histogram(
new PointIndexType[voxelCount]);
326 for (
size_t n(range.begin()), N(range.end()); n != N; ++n) {
328 PointIndexType *
const indices = mIndices + mPages[n];
329 pointCount = mPages[n + 1] - mPages[n];
332 for (PointIndexType i = 0; i < pointCount; ++i) {
333 offsets[i] = mVoxelOffsets[ indices[i] ];
337 memset(&histogram[0], 0, voxelCount *
sizeof(PointIndexType));
340 for (PointIndexType i = 0; i < pointCount; ++i) {
341 ++histogram[ offsets[i] ];
344 PointIndexType count = 0, startOffset;
345 for (
int i = 0; i < int(voxelCount); ++i) {
346 if (histogram[i] > 0) {
348 count += histogram[i];
349 histogram[i] = startOffset;
354 for (PointIndexType i = 0; i < pointCount; ++i) {
355 sortedIndices[ histogram[ offsets[i] ]++ ] = indices[i];
358 memcpy(&indices[0], &sortedIndices[0],
sizeof(PointIndexType) * pointCount);
368 template<
typename Po
intArray,
typename Po
intIndexType>
375 const IndexArray& indices,
const IndexArray& pages,
377 : mCoordinates(coordinates.get())
378 , mIndices(indices.get())
379 , mPages(pages.get())
383 , mCellCenteredTransform(cellCenteredTransform)
387 void operator()(
const tbb::blocked_range<size_t>& range)
const {
389 typedef typename PointArray::PosType PosType;
391 const bool cellCentered = mCellCenteredTransform;
392 const int mask = ~((1 << mLog2Dim) - 1);
396 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
398 mPoints->getPos(mIndices[mPages[n]], pos);
400 if (boost::math::isfinite(pos[0]) &&
401 boost::math::isfinite(pos[1]) &&
402 boost::math::isfinite(pos[2])) {
404 ijk = cellCentered ? mXForm.worldToIndexCellCentered(pos) :
405 mXForm.worldToIndexNodeCentered(pos);
411 mCoordinates[n] = ijk;
432 typedef boost::shared_ptr<Array>
Ptr;
434 Array(
size_t size) : mSize(size), mData(new T[size]) { }
436 size_t size()
const {
return mSize; }
438 T*
data() {
return mData.get(); }
439 const T*
data()
const {
return mData.get(); }
441 void clear() { mSize = 0; mData.reset(); }
445 boost::scoped_array<T> mData;
449 template<
typename Po
intIndexType>
456 : mIndexLists(&indexLists[0]), mSegments(segments)
460 void operator()(
const tbb::blocked_range<size_t>& range)
const {
461 for (
size_t n(range.begin()), N(range.end()); n != N; ++n) {
462 PointIndexType* indices = mIndexLists[n];
463 SegmentPtr& segment = mSegments[n];
465 tbb::parallel_for(tbb::blocked_range<size_t>(0, segment->size()),
466 CopyData(indices, segment->data()));
476 CopyData(PointIndexType* lhs,
const PointIndexType* rhs) : mLhs(lhs), mRhs(rhs) { }
478 void operator()(
const tbb::blocked_range<size_t>& range)
const {
479 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
484 PointIndexType *
const mLhs;
485 PointIndexType
const *
const mRhs;
488 PointIndexType *
const *
const mIndexLists;
489 SegmentPtr *
const mSegments;
493 template<
typename Po
intIndexType>
499 typedef std::pair<PointIndexType, PointIndexType>
IndexPair;
506 SegmentPtr* indexSegments,
507 SegmentPtr* offsetSegments,
511 , mIndexSegments(indexSegments)
512 , mOffsetSegments(offsetSegments)
514 , mNumSegments(numSegments)
518 void operator()(
const tbb::blocked_range<size_t>& range)
const {
520 std::vector<IndexPairListPtr*> data;
521 std::vector<PointIndexType> arrayOffsets;
523 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
525 const Coord& ijk = mCoords[n];
526 size_t numIndices = 0;
530 for (
size_t i = 0, I = mNumSegments; i < I; ++i) {
532 IndexPairListMap& idxMap = *mBins[i];
533 typename IndexPairListMap::iterator iter = idxMap.find(ijk);
535 if (iter != idxMap.end() && iter->second) {
536 IndexPairListPtr& idxListPtr = iter->second;
538 data.push_back(&idxListPtr);
539 numIndices += idxListPtr->size();
543 if (data.empty() || numIndices == 0)
continue;
545 SegmentPtr& indexSegment = mIndexSegments[n];
546 SegmentPtr& offsetSegment = mOffsetSegments[n];
548 indexSegment.
reset(
new Segment(numIndices));
549 offsetSegment.
reset(
new Segment(numIndices));
551 arrayOffsets.clear();
552 arrayOffsets.reserve(data.size());
554 for (
size_t i = 0, count = 0, I = data.size(); i < I; ++i) {
555 arrayOffsets.push_back(PointIndexType(count));
556 count += (*data[i])->size();
559 tbb::parallel_for(tbb::blocked_range<size_t>(0, data.size()),
560 CopyData(&data[0], &arrayOffsets[0], indexSegment->data(), offsetSegment->data()));
568 CopyData(IndexPairListPtr** indexLists,
569 const PointIndexType* arrayOffsets,
570 PointIndexType* indices,
571 PointIndexType* offsets)
572 : mIndexLists(indexLists)
573 , mArrayOffsets(arrayOffsets)
579 void operator()(
const tbb::blocked_range<size_t>& range)
const {
581 typedef typename IndexPairList::const_iterator CIter;
583 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
585 const PointIndexType arrayOffset = mArrayOffsets[n];
586 PointIndexType* indexPtr = &mIndices[arrayOffset];
587 PointIndexType* offsetPtr = &mOffsets[arrayOffset];
589 IndexPairListPtr& list = *mIndexLists[n];
591 for (CIter it = list->begin(), end = list->end(); it != end; ++it) {
592 const IndexPair& data = *it;
593 *indexPtr++ = data.first;
594 *offsetPtr++ = data.second;
601 IndexPairListPtr *
const *
const mIndexLists;
602 PointIndexType
const *
const mArrayOffsets;
603 PointIndexType *
const mIndices;
604 PointIndexType *
const mOffsets;
607 IndexPairListMapPtr *
const mBins;
608 SegmentPtr *
const mIndexSegments;
609 SegmentPtr *
const mOffsetSegments;
610 Coord const *
const mCoords;
611 size_t const mNumSegments;
615 template<
typename Po
intArray,
typename Po
intIndexType,
typename VoxelOffsetType>
619 typedef std::pair<PointIndexType, PointIndexType>
IndexPair;
627 VoxelOffsetType* voxelOffsets,
632 bool cellCenteredTransform)
635 , mVoxelOffsets(voxelOffsets)
637 , mBinLog2Dim(binLog2Dim)
638 , mBucketLog2Dim(bucketLog2Dim)
639 , mNumSegments(numSegments)
640 , mCellCenteredTransform(cellCenteredTransform)
644 void operator()(
const tbb::blocked_range<size_t>& range)
const {
646 const Index log2dim = mBucketLog2Dim;
647 const Index log2dim2 = 2 * log2dim;
648 const Index bucketMask = (1u << log2dim) - 1u;
650 const Index binLog2dim = mBinLog2Dim;
651 const Index binLog2dim2 = 2 * binLog2dim;
653 const Index binMask = (1u << (log2dim + binLog2dim)) - 1u;
654 const Index invBinMask = ~binMask;
656 IndexPairList * idxList = NULL;
657 Coord ijk(0, 0, 0), loc(0, 0, 0), binCoord(0, 0, 0), lastBinCoord(1, 2, 3);
660 PointIndexType bucketOffset = 0;
661 VoxelOffsetType voxelOffset = 0;
663 const bool cellCentered = mCellCenteredTransform;
665 const size_t numPoints = mPoints->size();
666 const size_t segmentSize = numPoints / mNumSegments;
668 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
670 IndexPairListMapPtr& dataPtr = mData[n];
671 if (!dataPtr) dataPtr.reset(
new IndexPairListMap());
672 IndexPairListMap& idxMap = *dataPtr;
674 const bool isLastSegment = (n + 1) >= mNumSegments;
676 const size_t start = n * segmentSize;
677 const size_t end = isLastSegment ? numPoints : (start + segmentSize);
679 for (
size_t i = start; i != end; ++i) {
681 mPoints->getPos(i, pos);
683 if (boost::math::isfinite(pos[0]) &&
684 boost::math::isfinite(pos[1]) &&
685 boost::math::isfinite(pos[2])) {
687 ijk = cellCentered ? mXForm.worldToIndexCellCentered(pos) :
688 mXForm.worldToIndexNodeCentered(pos);
691 loc[0] = ijk[0] & bucketMask;
692 loc[1] = ijk[1] & bucketMask;
693 loc[2] = ijk[2] & bucketMask;
694 voxelOffset = VoxelOffsetType((loc[0] << log2dim2) + (loc[1] << log2dim) + loc[2]);
697 binCoord[0] = ijk[0] & invBinMask;
698 binCoord[1] = ijk[1] & invBinMask;
699 binCoord[2] = ijk[2] & invBinMask;
709 bucketOffset = PointIndexType((ijk[0] << binLog2dim2) + (ijk[1] << binLog2dim) + ijk[2]);
711 if (lastBinCoord != binCoord) {
712 lastBinCoord = binCoord;
713 IndexPairListPtr& idxListPtr = idxMap[lastBinCoord];
714 if (!idxListPtr) idxListPtr.
reset(
new IndexPairList());
715 idxList = idxListPtr.get();
718 idxList->push_back(IndexPair(PointIndexType(i), bucketOffset));
719 if (mVoxelOffsets) mVoxelOffsets[i] = voxelOffset;
736 template<
typename Po
intIndexType>
743 IndexArray* pageOffsetArrays,
Index binVolume)
744 : mIndexSegments(indexSegments)
745 , mOffsetSegments(offestSegments)
746 , mPageOffsetArrays(pageOffsetArrays)
747 , mBinVolume(binVolume)
751 void operator()(
const tbb::blocked_range<size_t>& range)
const {
753 const size_t bucketCountersSize = size_t(mBinVolume);
754 IndexArray bucketCounters(
new PointIndexType[bucketCountersSize]);
756 size_t maxSegmentSize = 0;
757 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
758 maxSegmentSize =
std::max(maxSegmentSize, mIndexSegments[n]->size());
761 IndexArray bucketIndices(
new PointIndexType[maxSegmentSize]);
764 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
766 memset(bucketCounters.get(), 0,
sizeof(PointIndexType) * bucketCountersSize);
768 const size_t segmentSize = mOffsetSegments[n]->size();
769 PointIndexType* offsets = mOffsetSegments[n]->data();
773 for (
size_t i = 0; i < segmentSize; ++i) {
774 bucketIndices[i] = bucketCounters[offsets[i]]++;
777 PointIndexType nonemptyBucketCount = 0;
778 for (
size_t i = 0; i < bucketCountersSize; ++i) {
779 nonemptyBucketCount +=
static_cast<PointIndexType
>(bucketCounters[i] != 0);
783 IndexArray& pageOffsets = mPageOffsetArrays[n];
784 pageOffsets.reset(
new PointIndexType[nonemptyBucketCount + 1]);
785 pageOffsets[0] = nonemptyBucketCount + 1;
788 PointIndexType count = 0, idx = 1;
789 for (
size_t i = 0; i < bucketCountersSize; ++i) {
790 if (bucketCounters[i] != 0) {
791 pageOffsets[idx] = bucketCounters[i];
792 bucketCounters[i] = count;
793 count += pageOffsets[idx];
798 PointIndexType* indices = mIndexSegments[n]->data();
799 const tbb::blocked_range<size_t> segmentRange(0, segmentSize);
804 bucketIndices.get(), bucketCounters.get(), offsets));
807 offsets, bucketIndices.get(), indices));
809 mIndexSegments[n]->clear();
824 template<
typename Po
intIndexType,
typename VoxelOffsetType,
typename Po
intArray>
830 size_t& segmentCount,
831 const Index binLog2Dim,
832 const Index bucketLog2Dim,
833 VoxelOffsetType* voxelOffsets = NULL,
834 bool cellCenteredTransform =
true)
836 typedef std::pair<PointIndexType, PointIndexType> IndexPair;
837 typedef std::deque<IndexPair> IndexPairList;
838 typedef boost::shared_ptr<IndexPairList> IndexPairListPtr;
839 typedef std::map<Coord, IndexPairListPtr> IndexPairListMap;
840 typedef boost::shared_ptr<IndexPairListMap> IndexPairListMapPtr;
842 size_t numTasks = 1, numThreads = size_t(tbb::task_scheduler_init::default_num_threads());
843 if (points.size() > (numThreads * 2)) numTasks = numThreads * 2;
844 else if (points.size() > numThreads) numTasks = numThreads;
846 boost::scoped_array<IndexPairListMapPtr> bins(
new IndexPairListMapPtr[numTasks]);
850 tbb::parallel_for(tbb::blocked_range<size_t>(0, numTasks),
851 BinOp(bins.get(), points, voxelOffsets, xform, binLog2Dim, bucketLog2Dim,
852 numTasks, cellCenteredTransform));
854 std::set<Coord> uniqueCoords;
856 for (
size_t i = 0; i < numTasks; ++i) {
857 IndexPairListMap& idxMap = *bins[i];
858 for (
typename IndexPairListMap::iterator it = idxMap.begin(); it != idxMap.end(); ++it) {
859 uniqueCoords.insert(it->first);
863 std::vector<Coord> coords(uniqueCoords.begin(), uniqueCoords.end());
864 uniqueCoords.clear();
866 segmentCount = coords.size();
870 indexSegments.reset(
new SegmentPtr[segmentCount]);
871 offsetSegments.reset(
new SegmentPtr[segmentCount]);
875 tbb::parallel_for(tbb::blocked_range<size_t>(0, segmentCount),
876 MergeOp(bins.get(), indexSegments.get(), offsetSegments.get(), &coords[0], numTasks));
880 template<
typename Po
intIndexType,
typename VoxelOffsetType,
typename Po
intArray>
884 const Index bucketLog2Dim,
885 boost::scoped_array<PointIndexType>& pointIndices,
886 boost::scoped_array<PointIndexType>& pageOffsets,
887 PointIndexType& pageCount,
888 boost::scoped_array<VoxelOffsetType>& voxelOffsets,
889 bool recordVoxelOffsets,
890 bool cellCenteredTransform)
892 if (recordVoxelOffsets) voxelOffsets.reset(
new VoxelOffsetType[points.size()]);
893 else voxelOffsets.reset();
895 const Index binLog2Dim = 5u;
901 size_t numSegments = 0;
903 boost::scoped_array<typename Array<PointIndexType>::Ptr> indexSegments;
904 boost::scoped_array<typename Array<PointIndexType>::Ptr> offestSegments;
906 binAndSegment<PointIndexType, VoxelOffsetType, PointArray>(points, xform,
907 indexSegments, offestSegments, numSegments, binLog2Dim, bucketLog2Dim,
908 voxelOffsets.get(), cellCenteredTransform);
910 const tbb::blocked_range<size_t> segmentRange(0, numSegments);
912 typedef boost::scoped_array<PointIndexType> IndexArray;
913 boost::scoped_array<IndexArray> pageOffsetArrays(
new IndexArray[numSegments]);
915 const Index binVolume = 1u << (3u * binLog2Dim);
918 (indexSegments.get(), offestSegments.get(), pageOffsetArrays.get(), binVolume));
920 indexSegments.reset();
923 for (
size_t n = 0; n < numSegments; ++n) {
924 pageCount += pageOffsetArrays[n][0] - 1;
927 pageOffsets.reset(
new PointIndexType[pageCount + 1]);
929 PointIndexType count = 0;
930 for (
size_t n = 0, idx = 0; n < numSegments; ++n) {
932 PointIndexType* offsets = pageOffsetArrays[n].get();
933 size_t size = size_t(offsets[0]);
935 for (
size_t i = 1; i < size; ++i) {
936 pageOffsets[idx++] = count;
941 pageOffsets[pageCount] = count;
943 pointIndices.reset(
new PointIndexType[points.size()]);
945 std::vector<PointIndexType*> indexArray;
946 indexArray.reserve(numSegments);
948 PointIndexType* index = pointIndices.get();
949 for (
size_t n = 0; n < numSegments; ++n) {
950 indexArray.push_back(index);
951 index += offestSegments[n]->size();
964 template<
typename Po
intIndexType, Index BucketLog2Dim>
966 : mPointIndices(NULL)
967 , mVoxelOffsets(NULL)
969 , mPageCoordinates(NULL)
971 , mUsingCellCenteredTransform(true)
976 template<
typename Po
intIndexType, Index BucketLog2Dim>
981 mUsingCellCenteredTransform =
true;
982 mPointIndices.reset();
983 mVoxelOffsets.reset();
984 mPageOffsets.reset();
985 mPageCoordinates.reset();
989 template<
typename Po
intIndexType, Index BucketLog2Dim>
993 const IndexType tmpLhsPageCount = mPageCount;
994 mPageCount = rhs.mPageCount;
995 rhs.mPageCount = tmpLhsPageCount;
997 mPointIndices.swap(rhs.mPointIndices);
998 mVoxelOffsets.swap(rhs.mVoxelOffsets);
999 mPageOffsets.swap(rhs.mPageOffsets);
1000 mPageCoordinates.swap(rhs.mPageCoordinates);
1002 bool lhsCellCenteredTransform = mUsingCellCenteredTransform;
1003 mUsingCellCenteredTransform = rhs.mUsingCellCenteredTransform;
1004 rhs.mUsingCellCenteredTransform = lhsCellCenteredTransform;
1008 template<
typename Po
intIndexType, Index BucketLog2Dim>
1012 assert(
bool(mPointIndices) &&
bool(mPageCount));
1014 mPointIndices.get() + mPageOffsets[n],
1015 mPointIndices.get() + mPageOffsets[n + 1]);
1019 template<
typename Po
intIndexType, Index BucketLog2Dim>
1020 template<
typename Po
intArray>
1023 const math::Transform& xform,
bool voxelOrder,
bool recordVoxelOffsets,
bool cellCenteredTransform)
1025 mUsingCellCenteredTransform = cellCenteredTransform;
1028 mPointIndices, mPageOffsets, mPageCount, mVoxelOffsets,
1029 (voxelOrder || recordVoxelOffsets), cellCenteredTransform);
1031 const tbb::blocked_range<size_t> pageRange(0, mPageCount);
1032 mPageCoordinates.reset(
new Coord[mPageCount]);
1034 tbb::parallel_for(pageRange,
1036 (mPageCoordinates, mPointIndices, mPageOffsets, points, xform,
1037 BucketLog2Dim, cellCenteredTransform));
1039 if (mVoxelOffsets && voxelOrder) {
1041 IndexType, BucketLog2Dim>(mPointIndices, mPageOffsets, mVoxelOffsets));
1044 if (mVoxelOffsets && !recordVoxelOffsets) {
1045 mVoxelOffsets.reset();
1050 template<
typename Po
intIndexType, Index BucketLog2Dim>
1051 template<
typename Po
intArray>
1054 bool voxelOrder,
bool recordVoxelOffsets,
bool cellCenteredTransform)
1057 ret->construct(points, xform, voxelOrder, recordVoxelOffsets, cellCenteredTransform);
1070 #endif // OPENVDB_TOOLS_POINT_PARTITIONER_HAS_BEEN_INCLUDED
Coord & reset(Int32 x, Int32 y, Int32 z)
Definition: Coord.h:94
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:47
Index32 Index
Definition: Types.h:58
#define OPENVDB_VERSION_NAME
Definition: version.h:43
Definition: Exceptions.h:39
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition: Vec3.h:450
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:259
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
static CoordBBox createCube(const Coord &min, ValueType dim)
Definition: Coord.h:324