File indexing completed on 2026-09-17 09:20:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #ifndef _BVH_RadixSorter_Header
0017 #define _BVH_RadixSorter_Header
0018
0019 #include <BVH_Sorter.hxx>
0020 #include <BVH_Builder.hxx>
0021 #include <NCollection_Array1.hxx>
0022 #include <NCollection_Shared.hxx>
0023 #include <OSD_Parallel.hxx>
0024
0025 #include <algorithm>
0026
0027
0028 typedef std::pair<unsigned int, int> BVH_EncodedLink;
0029
0030 namespace BVH
0031 {
0032
0033
0034 constexpr unsigned int THE_MORTON_LUT[256] = {
0035 0x000000, 0x000001, 0x000008, 0x000009, 0x000040, 0x000041, 0x000048, 0x000049, 0x000200,
0036 0x000201, 0x000208, 0x000209, 0x000240, 0x000241, 0x000248, 0x000249, 0x001000, 0x001001,
0037 0x001008, 0x001009, 0x001040, 0x001041, 0x001048, 0x001049, 0x001200, 0x001201, 0x001208,
0038 0x001209, 0x001240, 0x001241, 0x001248, 0x001249, 0x008000, 0x008001, 0x008008, 0x008009,
0039 0x008040, 0x008041, 0x008048, 0x008049, 0x008200, 0x008201, 0x008208, 0x008209, 0x008240,
0040 0x008241, 0x008248, 0x008249, 0x009000, 0x009001, 0x009008, 0x009009, 0x009040, 0x009041,
0041 0x009048, 0x009049, 0x009200, 0x009201, 0x009208, 0x009209, 0x009240, 0x009241, 0x009248,
0042 0x009249, 0x040000, 0x040001, 0x040008, 0x040009, 0x040040, 0x040041, 0x040048, 0x040049,
0043 0x040200, 0x040201, 0x040208, 0x040209, 0x040240, 0x040241, 0x040248, 0x040249, 0x041000,
0044 0x041001, 0x041008, 0x041009, 0x041040, 0x041041, 0x041048, 0x041049, 0x041200, 0x041201,
0045 0x041208, 0x041209, 0x041240, 0x041241, 0x041248, 0x041249, 0x048000, 0x048001, 0x048008,
0046 0x048009, 0x048040, 0x048041, 0x048048, 0x048049, 0x048200, 0x048201, 0x048208, 0x048209,
0047 0x048240, 0x048241, 0x048248, 0x048249, 0x049000, 0x049001, 0x049008, 0x049009, 0x049040,
0048 0x049041, 0x049048, 0x049049, 0x049200, 0x049201, 0x049208, 0x049209, 0x049240, 0x049241,
0049 0x049248, 0x049249, 0x200000, 0x200001, 0x200008, 0x200009, 0x200040, 0x200041, 0x200048,
0050 0x200049, 0x200200, 0x200201, 0x200208, 0x200209, 0x200240, 0x200241, 0x200248, 0x200249,
0051 0x201000, 0x201001, 0x201008, 0x201009, 0x201040, 0x201041, 0x201048, 0x201049, 0x201200,
0052 0x201201, 0x201208, 0x201209, 0x201240, 0x201241, 0x201248, 0x201249, 0x208000, 0x208001,
0053 0x208008, 0x208009, 0x208040, 0x208041, 0x208048, 0x208049, 0x208200, 0x208201, 0x208208,
0054 0x208209, 0x208240, 0x208241, 0x208248, 0x208249, 0x209000, 0x209001, 0x209008, 0x209009,
0055 0x209040, 0x209041, 0x209048, 0x209049, 0x209200, 0x209201, 0x209208, 0x209209, 0x209240,
0056 0x209241, 0x209248, 0x209249, 0x240000, 0x240001, 0x240008, 0x240009, 0x240040, 0x240041,
0057 0x240048, 0x240049, 0x240200, 0x240201, 0x240208, 0x240209, 0x240240, 0x240241, 0x240248,
0058 0x240249, 0x241000, 0x241001, 0x241008, 0x241009, 0x241040, 0x241041, 0x241048, 0x241049,
0059 0x241200, 0x241201, 0x241208, 0x241209, 0x241240, 0x241241, 0x241248, 0x241249, 0x248000,
0060 0x248001, 0x248008, 0x248009, 0x248040, 0x248041, 0x248048, 0x248049, 0x248200, 0x248201,
0061 0x248208, 0x248209, 0x248240, 0x248241, 0x248248, 0x248249, 0x249000, 0x249001, 0x249008,
0062 0x249009, 0x249040, 0x249041, 0x249048, 0x249049, 0x249200, 0x249201, 0x249208, 0x249209,
0063 0x249240, 0x249241, 0x249248, 0x249249};
0064
0065
0066
0067
0068
0069
0070 constexpr unsigned int EncodeMortonCode(unsigned int theVoxelX,
0071 unsigned int theVoxelY,
0072 unsigned int theVoxelZ)
0073 {
0074
0075
0076 return (THE_MORTON_LUT[theVoxelX & 0xFF] | (THE_MORTON_LUT[(theVoxelX >> 8) & 0x03] << 24))
0077 | ((THE_MORTON_LUT[theVoxelY & 0xFF] | (THE_MORTON_LUT[(theVoxelY >> 8) & 0x03] << 24))
0078 << 1)
0079 | ((THE_MORTON_LUT[theVoxelZ & 0xFF] | (THE_MORTON_LUT[(theVoxelZ >> 8) & 0x03] << 24))
0080 << 2);
0081 }
0082 }
0083
0084
0085
0086 template <class T, int N>
0087 class BVH_RadixSorter : public BVH_Sorter<T, N>
0088 {
0089 public:
0090 typedef typename BVH::VectorType<T, N>::Type BVH_VecNt;
0091
0092 public:
0093
0094 BVH_RadixSorter(const BVH_Box<T, N>& theBox)
0095 : myBox(theBox)
0096 {
0097 }
0098
0099
0100 void Perform(BVH_Set<T, N>* theSet) override { Perform(theSet, 0, theSet->Size() - 1); }
0101
0102
0103 void Perform(BVH_Set<T, N>* theSet, const int theStart, const int theFinal) override;
0104
0105
0106 const NCollection_Array1<BVH_EncodedLink>& EncodedLinks() const { return *myEncodedLinks; }
0107
0108 protected:
0109
0110 BVH_Box<T, N> myBox;
0111
0112
0113 Handle(NCollection_Shared<NCollection_Array1<BVH_EncodedLink>>) myEncodedLinks;
0114 };
0115
0116 namespace BVH
0117 {
0118
0119 struct BitPredicate
0120 {
0121 unsigned int myBit;
0122
0123
0124 BitPredicate(const int theDigit)
0125 : myBit(1U << theDigit)
0126 {
0127 }
0128
0129
0130 bool operator()(const BVH_EncodedLink theLink) const
0131 {
0132 return !(theLink.first & myBit);
0133 }
0134 };
0135
0136
0137 struct BitComparator
0138 {
0139 unsigned int myBit;
0140
0141
0142 BitComparator(const int theDigit)
0143 : myBit(1U << theDigit)
0144 {
0145 }
0146
0147
0148 bool operator()(BVH_EncodedLink theLink1, BVH_EncodedLink )
0149 {
0150 return !(theLink1.first & myBit);
0151 }
0152 };
0153
0154
0155 class RadixSorter
0156 {
0157 public:
0158 typedef NCollection_Array1<BVH_EncodedLink>::iterator LinkIterator;
0159
0160 private:
0161
0162 struct SortRange
0163 {
0164 LinkIterator myStart;
0165 LinkIterator myFinal;
0166 int myDigit;
0167 };
0168
0169
0170 class Functor
0171 {
0172 public:
0173 Functor(const SortRange (&aSplits)[2], const bool isParallel)
0174 : mySplits(aSplits),
0175 myIsParallel(isParallel)
0176 {
0177 }
0178
0179
0180 void operator()(const int theIndex) const
0181 {
0182 RadixSorter::Sort(mySplits[theIndex].myStart,
0183 mySplits[theIndex].myFinal,
0184 mySplits[theIndex].myDigit,
0185 myIsParallel);
0186 }
0187
0188 private:
0189 void operator=(const Functor&) = delete;
0190
0191 private:
0192 const SortRange (&mySplits)[2];
0193 bool myIsParallel;
0194 };
0195
0196 public:
0197 static void Sort(LinkIterator theStart,
0198 LinkIterator theFinal,
0199 int theDigit,
0200 const bool isParallel)
0201 {
0202 if (theDigit < 24)
0203 {
0204 BVH::RadixSorter::perform(theStart, theFinal, theDigit);
0205 }
0206 else
0207 {
0208 LinkIterator anOffset = std::partition(theStart, theFinal, BitPredicate(theDigit));
0209 SortRange aSplits[2] = {{theStart, anOffset, theDigit - 1},
0210 {anOffset, theFinal, theDigit - 1}};
0211
0212 OSD_Parallel::For(0, 2, Functor(aSplits, isParallel), !isParallel);
0213 }
0214 }
0215
0216 protected:
0217
0218 static void perform(LinkIterator theStart, LinkIterator theFinal, int theDigit = 29)
0219 {
0220 while (theStart != theFinal && theDigit >= 0)
0221 {
0222 LinkIterator anOffset = std::partition(theStart, theFinal, BitPredicate(theDigit--));
0223 perform(theStart, anOffset, theDigit);
0224 theStart = anOffset;
0225 }
0226 }
0227 };
0228 }
0229
0230
0231
0232 template <class T, int N>
0233 void BVH_RadixSorter<T, N>::Perform(BVH_Set<T, N>* theSet, const int theStart, const int theFinal)
0234 {
0235 Standard_STATIC_ASSERT(N == 2 || N == 3 || N == 4);
0236
0237 const int aDimension = 1024;
0238 const int aNbEffComp = N == 2 ? 2 : 3;
0239
0240 const BVH_VecNt aSceneMin = myBox.CornerMin();
0241 const BVH_VecNt aSceneMax = myBox.CornerMax();
0242
0243 BVH_VecNt aNodeMinSizeVecT(static_cast<T>(BVH::THE_NODE_MIN_SIZE));
0244 BVH::BoxMinMax<T, N>::CwiseMax(aNodeMinSizeVecT, aSceneMax - aSceneMin);
0245
0246 const BVH_VecNt aReverseSize = BVH_VecNt(static_cast<T>(aDimension)) / aNodeMinSizeVecT;
0247
0248 myEncodedLinks = new NCollection_Shared<NCollection_Array1<BVH_EncodedLink>>(theStart, theFinal);
0249
0250
0251 for (int aPrimIdx = theStart; aPrimIdx <= theFinal; ++aPrimIdx)
0252 {
0253 const BVH_VecNt aCenter = theSet->Box(aPrimIdx).Center();
0254 const BVH_VecNt aVoxelF = (aCenter - aSceneMin) * aReverseSize;
0255
0256
0257 const int aVoxelX =
0258 std::clamp(BVH::IntFloor(BVH::VecComp<T, N>::Get(aVoxelF, 0)), 0, aDimension - 1);
0259 const int aVoxelY =
0260 std::clamp(BVH::IntFloor(BVH::VecComp<T, N>::Get(aVoxelF, 1)), 0, aDimension - 1);
0261 const int aVoxelZ =
0262 (aNbEffComp > 2)
0263 ? std::clamp(BVH::IntFloor(BVH::VecComp<T, N>::Get(aVoxelF, 2)), 0, aDimension - 1)
0264 : 0;
0265
0266
0267 const unsigned int aMortonCode = BVH::EncodeMortonCode(static_cast<unsigned int>(aVoxelX),
0268 static_cast<unsigned int>(aVoxelY),
0269 static_cast<unsigned int>(aVoxelZ));
0270
0271 myEncodedLinks->ChangeValue(aPrimIdx) = BVH_EncodedLink(aMortonCode, aPrimIdx);
0272 }
0273
0274
0275 BVH::RadixSorter::Sort(myEncodedLinks->begin(), myEncodedLinks->end(), 29, this->IsParallel());
0276
0277 NCollection_Array1<int> aLinkMap(theStart, theFinal);
0278 for (int aLinkIdx = theStart; aLinkIdx <= theFinal; ++aLinkIdx)
0279 {
0280 aLinkMap(myEncodedLinks->Value(aLinkIdx).second) = aLinkIdx;
0281 }
0282
0283
0284 int aPrimIdx = theStart;
0285 while (aPrimIdx <= theFinal)
0286 {
0287 const int aSortIdx = aLinkMap(aPrimIdx);
0288 if (aPrimIdx != aSortIdx)
0289 {
0290 theSet->Swap(aPrimIdx, aSortIdx);
0291 std::swap(aLinkMap(aPrimIdx), aLinkMap(aSortIdx));
0292 }
0293 else
0294 {
0295 ++aPrimIdx;
0296 }
0297 }
0298 }
0299
0300 #endif