45 #ifndef OPENVDB_TOOLS_POINT_PARTITIONER_HAS_BEEN_INCLUDED 46 #define OPENVDB_TOOLS_POINT_PARTITIONER_HAS_BEEN_INCLUDED 51 #include <boost/integer.hpp> 52 #include <boost/scoped_array.hpp> 54 #include <tbb/blocked_range.h> 55 #include <tbb/parallel_for.h> 56 #include <tbb/task_scheduler_init.h> 105 template<
typename Po
intIndexType = u
int32_t, Index BucketLog2Dim = 3>
109 enum { LOG2DIM = BucketLog2Dim };
133 template<
typename Po
intArray>
135 bool voxelOrder =
false,
bool recordVoxelOffsets =
false,
136 bool cellCenteredTransform =
true);
148 template<
typename Po
intArray>
150 bool voxelOrder =
false,
bool recordVoxelOffsets =
false,
151 bool cellCenteredTransform =
true);
155 size_t size()
const {
return mPageCount; }
158 bool empty()
const {
return mPageCount == 0; }
167 IndexIterator indices(
size_t n)
const;
175 const Coord&
origin(
size_t n)
const {
return mPageCoordinates[n]; }
191 boost::scoped_array<IndexType> mPointIndices;
192 VoxelOffsetArray mVoxelOffsets;
194 boost::scoped_array<IndexType> mPageOffsets;
195 boost::scoped_array<Coord> mPageCoordinates;
196 IndexType mPageCount;
197 bool mUsingCellCenteredTransform;
204 template<
typename Po
intIndexType, Index BucketLog2Dim>
211 : mBegin(begin), mEnd(end), mItem(begin) {}
217 size_t size()
const {
return mEnd - mBegin; }
224 operator bool()
const {
return mItem < mEnd; }
225 bool test()
const {
return mItem < mEnd; }
231 bool next() { this->operator++();
return this->test(); }
250 namespace point_partitioner_internal {
253 template<
typename Po
intIndexType>
257 const PointIndexType* bucketCounters,
const PointIndexType* bucketOffsets)
258 : mPointOrder(pointOrder)
259 , mBucketCounters(bucketCounters)
260 , mBucketOffsets(bucketOffsets)
264 void operator()(
const tbb::blocked_range<size_t>& range)
const {
265 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
266 mPointOrder[n] += mBucketCounters[mBucketOffsets[n]];
276 template<
typename Po
intIndexType>
280 const PointIndexType* pointOrder,
const PointIndexType* indices)
281 : mOrderedIndexArray(orderedIndexArray)
282 , mPointOrder(pointOrder)
287 void operator()(
const tbb::blocked_range<size_t>& range)
const {
288 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
289 mOrderedIndexArray[mPointOrder[n]] = mIndices[n];
299 template<
typename Po
intIndexType, Index BucketLog2Dim>
307 : mIndices(indices.get())
308 , mPages(pages.get())
309 , mVoxelOffsets(offsets.get())
313 void operator()(
const tbb::blocked_range<size_t>& range)
const {
316 for (
size_t n(range.begin()), N(range.end()); n != N; ++n) {
320 const PointIndexType voxelCount = 1 << (3 * BucketLog2Dim);
324 boost::scoped_array<PointIndexType> sortedIndices(
new PointIndexType[
pointCount]);
325 boost::scoped_array<PointIndexType>
histogram(
new PointIndexType[voxelCount]);
327 for (
size_t n(range.begin()), N(range.end()); n != N; ++n) {
329 PointIndexType *
const indices = mIndices + mPages[n];
333 for (PointIndexType i = 0; i <
pointCount; ++i) {
334 offsets[i] = mVoxelOffsets[ indices[i] ];
338 memset(&
histogram[0], 0, voxelCount *
sizeof(PointIndexType));
341 for (PointIndexType i = 0; i <
pointCount; ++i) {
345 PointIndexType count = 0, startOffset;
346 for (
int i = 0; i < int(voxelCount); ++i) {
355 for (PointIndexType i = 0; i <
pointCount; ++i) {
356 sortedIndices[
histogram[ offsets[i] ]++ ] = indices[i];
359 memcpy(&indices[0], &sortedIndices[0],
sizeof(PointIndexType) *
pointCount);
369 template<
typename Po
intArray,
typename Po
intIndexType>
378 : mCoordinates(coordinates.get())
379 , mIndices(indices.get())
380 , mPages(pages.get())
384 , mCellCenteredTransform(cellCenteredTransform)
388 void operator()(
const tbb::blocked_range<size_t>& range)
const {
390 using PosType =
typename PointArray::PosType;
392 const bool cellCentered = mCellCenteredTransform;
393 const int mask = ~((1 << mLog2Dim) - 1);
397 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
399 mPoints->getPos(mIndices[mPages[n]], pos);
401 if (std::isfinite(pos[0]) && std::isfinite(pos[1]) && std::isfinite(pos[2])) {
402 ijk = cellCentered ? mXForm.worldToIndexCellCentered(pos) :
403 mXForm.worldToIndexNodeCentered(pos);
409 mCoordinates[n] = ijk;
432 Array(
size_t size) : mSize(size), mData(new T[size]) { }
434 size_t size()
const {
return mSize; }
436 T*
data() {
return mData.get(); }
437 const T*
data()
const {
return mData.get(); }
439 void clear() { mSize = 0; mData.reset(); }
443 boost::scoped_array<T> mData;
447 template<
typename Po
intIndexType>
454 : mIndexLists(&indexLists[0]), mSegments(segments)
458 void operator()(
const tbb::blocked_range<size_t>& range)
const {
459 for (
size_t n(range.begin()), N(range.end()); n != N; ++n) {
460 PointIndexType* indices = mIndexLists[n];
463 tbb::parallel_for(tbb::blocked_range<size_t>(0, segment->size()),
464 CopyData(indices, segment->data()));
474 CopyData(PointIndexType* lhs,
const PointIndexType* rhs) : mLhs(lhs), mRhs(rhs) { }
476 void operator()(
const tbb::blocked_range<size_t>& range)
const {
477 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
482 PointIndexType *
const mLhs;
483 PointIndexType
const *
const mRhs;
486 PointIndexType *
const *
const mIndexLists;
487 SegmentPtr *
const mSegments;
491 template<
typename Po
intIndexType>
497 using IndexPair = std::pair<PointIndexType, PointIndexType>;
509 , mIndexSegments(indexSegments)
510 , mOffsetSegments(offsetSegments)
512 , mNumSegments(numSegments)
516 void operator()(
const tbb::blocked_range<size_t>& range)
const {
518 std::vector<IndexPairListPtr*> data;
519 std::vector<PointIndexType> arrayOffsets;
521 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
523 const Coord& ijk = mCoords[n];
524 size_t numIndices = 0;
528 for (
size_t i = 0, I = mNumSegments; i < I; ++i) {
531 typename IndexPairListMap::iterator iter = idxMap.find(ijk);
533 if (iter != idxMap.end() && iter->second) {
536 data.push_back(&idxListPtr);
537 numIndices += idxListPtr->size();
541 if (data.empty() || numIndices == 0)
continue;
544 SegmentPtr& offsetSegment = mOffsetSegments[n];
549 arrayOffsets.clear();
550 arrayOffsets.reserve(data.size());
552 for (
size_t i = 0, count = 0, I = data.size(); i < I; ++i) {
553 arrayOffsets.push_back(PointIndexType(count));
554 count += (*data[i])->size();
557 tbb::parallel_for(tbb::blocked_range<size_t>(0, data.size()),
558 CopyData(&data[0], &arrayOffsets[0], indexSegment->data(), offsetSegment->data()));
566 CopyData(IndexPairListPtr** indexLists,
567 const PointIndexType* arrayOffsets,
568 PointIndexType* indices,
569 PointIndexType* offsets)
570 : mIndexLists(indexLists)
571 , mArrayOffsets(arrayOffsets)
577 void operator()(
const tbb::blocked_range<size_t>& range)
const {
579 using CIter =
typename IndexPairList::const_iterator;
581 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
583 const PointIndexType arrayOffset = mArrayOffsets[n];
584 PointIndexType* indexPtr = &mIndices[arrayOffset];
585 PointIndexType* offsetPtr = &mOffsets[arrayOffset];
587 IndexPairListPtr& list = *mIndexLists[n];
589 for (CIter it = list->begin(), end = list->end(); it != end; ++it) {
591 *indexPtr++ = data.first;
592 *offsetPtr++ = data.second;
599 IndexPairListPtr *
const *
const mIndexLists;
600 PointIndexType
const *
const mArrayOffsets;
601 PointIndexType *
const mIndices;
602 PointIndexType *
const mOffsets;
605 IndexPairListMapPtr *
const mBins;
606 SegmentPtr *
const mIndexSegments;
607 SegmentPtr *
const mOffsetSegments;
608 Coord
const *
const mCoords;
609 size_t const mNumSegments;
613 template<
typename Po
intArray,
typename Po
intIndexType,
typename VoxelOffsetType>
617 using IndexPair = std::pair<PointIndexType, PointIndexType>;
625 VoxelOffsetType* voxelOffsets,
630 bool cellCenteredTransform)
633 , mVoxelOffsets(voxelOffsets)
635 , mBinLog2Dim(binLog2Dim)
636 , mBucketLog2Dim(bucketLog2Dim)
637 , mNumSegments(numSegments)
638 , mCellCenteredTransform(cellCenteredTransform)
642 void operator()(
const tbb::blocked_range<size_t>& range)
const {
644 const Index log2dim = mBucketLog2Dim;
645 const Index log2dim2 = 2 * log2dim;
646 const Index bucketMask = (1u << log2dim) - 1u;
648 const Index binLog2dim = mBinLog2Dim;
649 const Index binLog2dim2 = 2 * binLog2dim;
651 const Index binMask = (1u << (log2dim + binLog2dim)) - 1u;
652 const Index invBinMask = ~binMask;
655 Coord ijk(0, 0, 0), loc(0, 0, 0), binCoord(0, 0, 0), lastBinCoord(1, 2, 3);
658 PointIndexType bucketOffset = 0;
659 VoxelOffsetType voxelOffset = 0;
661 const bool cellCentered = mCellCenteredTransform;
663 const size_t numPoints = mPoints->size();
664 const size_t segmentSize = numPoints / mNumSegments;
666 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
672 const bool isLastSegment = (n + 1) >= mNumSegments;
674 const size_t start = n * segmentSize;
675 const size_t end = isLastSegment ? numPoints : (start + segmentSize);
677 for (
size_t i = start; i != end; ++i) {
679 mPoints->getPos(i, pos);
681 if (std::isfinite(pos[0]) && std::isfinite(pos[1]) && std::isfinite(pos[2])) {
682 ijk = cellCentered ? mXForm.worldToIndexCellCentered(pos) :
683 mXForm.worldToIndexNodeCentered(pos);
686 loc[0] = ijk[0] & bucketMask;
687 loc[1] = ijk[1] & bucketMask;
688 loc[2] = ijk[2] & bucketMask;
689 voxelOffset = VoxelOffsetType(
690 (loc[0] << log2dim2) + (loc[1] << log2dim) + loc[2]);
693 binCoord[0] = ijk[0] & invBinMask;
694 binCoord[1] = ijk[1] & invBinMask;
695 binCoord[2] = ijk[2] & invBinMask;
705 bucketOffset = PointIndexType(
706 (ijk[0] << binLog2dim2) + (ijk[1] << binLog2dim) + ijk[2]);
708 if (lastBinCoord != binCoord) {
709 lastBinCoord = binCoord;
712 idxList = idxListPtr.get();
715 idxList->push_back(
IndexPair(PointIndexType(i), bucketOffset));
716 if (mVoxelOffsets) mVoxelOffsets[i] = voxelOffset;
733 template<
typename Po
intIndexType>
741 : mIndexSegments(indexSegments)
742 , mOffsetSegments(offestSegments)
743 , mPageOffsetArrays(pageOffsetArrays)
744 , mBinVolume(binVolume)
748 void operator()(
const tbb::blocked_range<size_t>& range)
const {
750 const size_t bucketCountersSize = size_t(mBinVolume);
751 IndexArray bucketCounters(
new PointIndexType[bucketCountersSize]);
753 size_t maxSegmentSize = 0;
754 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
755 maxSegmentSize =
std::max(maxSegmentSize, mIndexSegments[n]->size());
758 IndexArray bucketIndices(
new PointIndexType[maxSegmentSize]);
761 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
763 memset(bucketCounters.get(), 0,
sizeof(PointIndexType) * bucketCountersSize);
765 const size_t segmentSize = mOffsetSegments[n]->size();
766 PointIndexType* offsets = mOffsetSegments[n]->data();
770 for (
size_t i = 0; i < segmentSize; ++i) {
771 bucketIndices[i] = bucketCounters[offsets[i]]++;
774 PointIndexType nonemptyBucketCount = 0;
775 for (
size_t i = 0; i < bucketCountersSize; ++i) {
776 nonemptyBucketCount += static_cast<PointIndexType>(bucketCounters[i] != 0);
780 IndexArray& pageOffsets = mPageOffsetArrays[n];
781 pageOffsets.reset(
new PointIndexType[nonemptyBucketCount + 1]);
782 pageOffsets[0] = nonemptyBucketCount + 1;
785 PointIndexType count = 0, idx = 1;
786 for (
size_t i = 0; i < bucketCountersSize; ++i) {
787 if (bucketCounters[i] != 0) {
788 pageOffsets[idx] = bucketCounters[i];
789 bucketCounters[i] = count;
790 count += pageOffsets[idx];
795 PointIndexType* indices = mIndexSegments[n]->data();
796 const tbb::blocked_range<size_t> segmentRange(0, segmentSize);
801 bucketIndices.get(), bucketCounters.get(), offsets));
804 offsets, bucketIndices.get(), indices));
806 mIndexSegments[n]->clear();
821 template<
typename Po
intIndexType,
typename VoxelOffsetType,
typename Po
intArray>
827 size_t& segmentCount,
828 const Index binLog2Dim,
829 const Index bucketLog2Dim,
830 VoxelOffsetType* voxelOffsets =
nullptr,
831 bool cellCenteredTransform =
true)
833 using IndexPair = std::pair<PointIndexType, PointIndexType>;
834 using IndexPairList = std::deque<IndexPair>;
836 using IndexPairListMap = std::map<Coord, IndexPairListPtr>;
839 size_t numTasks = 1, numThreads = size_t(tbb::task_scheduler_init::default_num_threads());
840 if (points.size() > (numThreads * 2)) numTasks = numThreads * 2;
841 else if (points.size() > numThreads) numTasks = numThreads;
843 boost::scoped_array<IndexPairListMapPtr> bins(
new IndexPairListMapPtr[numTasks]);
847 tbb::parallel_for(tbb::blocked_range<size_t>(0, numTasks),
848 BinOp(bins.get(), points, voxelOffsets, xform, binLog2Dim, bucketLog2Dim,
849 numTasks, cellCenteredTransform));
851 std::set<Coord> uniqueCoords;
853 for (
size_t i = 0; i < numTasks; ++i) {
854 IndexPairListMap& idxMap = *bins[i];
855 for (
typename IndexPairListMap::iterator it = idxMap.begin(); it != idxMap.end(); ++it) {
856 uniqueCoords.insert(it->first);
860 std::vector<Coord> coords(uniqueCoords.begin(), uniqueCoords.end());
861 uniqueCoords.clear();
863 segmentCount = coords.size();
867 indexSegments.reset(
new SegmentPtr[segmentCount]);
868 offsetSegments.reset(
new SegmentPtr[segmentCount]);
872 tbb::parallel_for(tbb::blocked_range<size_t>(0, segmentCount),
873 MergeOp(bins.get(), indexSegments.get(), offsetSegments.get(), &coords[0], numTasks));
877 template<
typename Po
intIndexType,
typename VoxelOffsetType,
typename Po
intArray>
881 const Index bucketLog2Dim,
882 boost::scoped_array<PointIndexType>& pointIndices,
883 boost::scoped_array<PointIndexType>& pageOffsets,
884 PointIndexType& pageCount,
885 boost::scoped_array<VoxelOffsetType>& voxelOffsets,
886 bool recordVoxelOffsets,
887 bool cellCenteredTransform)
889 if (recordVoxelOffsets) voxelOffsets.reset(
new VoxelOffsetType[points.size()]);
890 else voxelOffsets.reset();
892 const Index binLog2Dim = 5u;
898 size_t numSegments = 0;
900 boost::scoped_array<typename Array<PointIndexType>::Ptr> indexSegments;
901 boost::scoped_array<typename Array<PointIndexType>::Ptr> offestSegments;
903 binAndSegment<PointIndexType, VoxelOffsetType, PointArray>(points, xform,
904 indexSegments, offestSegments, numSegments, binLog2Dim, bucketLog2Dim,
905 voxelOffsets.get(), cellCenteredTransform);
907 const tbb::blocked_range<size_t> segmentRange(0, numSegments);
909 using IndexArray = boost::scoped_array<PointIndexType>;
910 boost::scoped_array<IndexArray> pageOffsetArrays(
new IndexArray[numSegments]);
912 const Index binVolume = 1u << (3u * binLog2Dim);
915 (indexSegments.get(), offestSegments.get(), pageOffsetArrays.get(), binVolume));
917 indexSegments.reset();
920 for (
size_t n = 0; n < numSegments; ++n) {
921 pageCount += pageOffsetArrays[n][0] - 1;
924 pageOffsets.reset(
new PointIndexType[pageCount + 1]);
926 PointIndexType count = 0;
927 for (
size_t n = 0, idx = 0; n < numSegments; ++n) {
929 PointIndexType* offsets = pageOffsetArrays[n].get();
930 size_t size = size_t(offsets[0]);
932 for (
size_t i = 1; i < size; ++i) {
933 pageOffsets[idx++] = count;
938 pageOffsets[pageCount] = count;
940 pointIndices.reset(
new PointIndexType[points.size()]);
942 std::vector<PointIndexType*> indexArray;
943 indexArray.reserve(numSegments);
945 PointIndexType* index = pointIndices.get();
946 for (
size_t n = 0; n < numSegments; ++n) {
947 indexArray.push_back(index);
948 index += offestSegments[n]->size();
951 tbb::parallel_for(segmentRange,
962 template<
typename Po
intIndexType, Index BucketLog2Dim>
964 : mPointIndices(nullptr)
965 , mVoxelOffsets(nullptr)
966 , mPageOffsets(nullptr)
967 , mPageCoordinates(nullptr)
969 , mUsingCellCenteredTransform(true)
974 template<
typename Po
intIndexType, Index BucketLog2Dim>
979 mUsingCellCenteredTransform =
true;
980 mPointIndices.reset();
981 mVoxelOffsets.reset();
982 mPageOffsets.reset();
983 mPageCoordinates.reset();
987 template<
typename Po
intIndexType, Index BucketLog2Dim>
991 const IndexType tmpLhsPageCount = mPageCount;
992 mPageCount = rhs.mPageCount;
993 rhs.mPageCount = tmpLhsPageCount;
995 mPointIndices.swap(rhs.mPointIndices);
996 mVoxelOffsets.swap(rhs.mVoxelOffsets);
997 mPageOffsets.swap(rhs.mPageOffsets);
998 mPageCoordinates.swap(rhs.mPageCoordinates);
1000 bool lhsCellCenteredTransform = mUsingCellCenteredTransform;
1001 mUsingCellCenteredTransform = rhs.mUsingCellCenteredTransform;
1002 rhs.mUsingCellCenteredTransform = lhsCellCenteredTransform;
1006 template<
typename Po
intIndexType, Index BucketLog2Dim>
1010 assert(
bool(mPointIndices) &&
bool(mPageCount));
1012 mPointIndices.get() + mPageOffsets[n],
1013 mPointIndices.get() + mPageOffsets[n + 1]);
1017 template<
typename Po
intIndexType, Index BucketLog2Dim>
1018 template<
typename Po
intArray>
1024 bool recordVoxelOffsets,
1025 bool cellCenteredTransform)
1027 mUsingCellCenteredTransform = cellCenteredTransform;
1030 mPointIndices, mPageOffsets, mPageCount, mVoxelOffsets,
1031 (voxelOrder || recordVoxelOffsets), cellCenteredTransform);
1033 const tbb::blocked_range<size_t> pageRange(0, mPageCount);
1034 mPageCoordinates.reset(
new Coord[mPageCount]);
1036 tbb::parallel_for(pageRange,
1038 (mPageCoordinates, mPointIndices, mPageOffsets, points, xform,
1039 BucketLog2Dim, cellCenteredTransform));
1041 if (mVoxelOffsets && voxelOrder) {
1043 IndexType, BucketLog2Dim>(mPointIndices, mPageOffsets, mVoxelOffsets));
1046 if (mVoxelOffsets && !recordVoxelOffsets) {
1047 mVoxelOffsets.reset();
1052 template<
typename Po
intIndexType, Index BucketLog2Dim>
1053 template<
typename Po
intArray>
1059 bool recordVoxelOffsets,
1060 bool cellCenteredTransform)
1063 ret->construct(points, xform, voxelOrder, recordVoxelOffsets, cellCenteredTransform);
1076 #endif // OPENVDB_TOOLS_POINT_PARTITIONER_HAS_BEEN_INCLUDED
Index32 Index
Definition: Types.h:61
std::vector< Index > IndexArray
Definition: PointMove.h:198
Mat3< typename promote< T0, T1 >::type > operator *(const Mat3< T0 > &m0, const Mat3< T1 > &m1)
Multiply m0 by m1 and return the resulting matrix.
Definition: Mat3.h:645
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:51
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition: Vec3.h:488
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:136
Definition: Exceptions.h:40
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:264
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Count the total number of points in a PointDataTree.
Definition: PointCount.h:115
std::shared_ptr< T > SharedPtr
Definition: Types.h:139
Coord & reset(Int32 x, Int32 y, Int32 z)
Reset all three coordinates with the specified arguments.
Definition: Coord.h:96
std::pair< Index, Index > IndexPair
Definition: PointMove.h:194
static CoordBBox createCube(const Coord &min, ValueType dim)
Definition: Coord.h:329
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:188