Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:03:19

0001 // Created on: 2016-04-13
0002 // Created by: Denis BOGOLEPOV
0003 // Copyright (c) 2013-2016 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
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 //! Pair of Morton code and primitive ID.
0028 typedef std::pair<unsigned int, Standard_Integer> BVH_EncodedLink;
0029 
0030 //! Performs radix sort of a BVH primitive set using
0031 //! 10-bit Morton codes (or 1024 x 1024 x 1024 grid).
0032 template<class T, int N>
0033 class BVH_RadixSorter : public BVH_Sorter<T, N>
0034 {
0035 public:
0036 
0037   typedef typename BVH::VectorType<T, N>::Type BVH_VecNt;
0038 
0039 public:
0040 
0041   //! Creates new BVH radix sorter for the given AABB.
0042   BVH_RadixSorter (const BVH_Box<T, N>& theBox) : myBox (theBox) { }
0043 
0044   //! Sorts the set.
0045   virtual void Perform (BVH_Set<T, N>* theSet) Standard_OVERRIDE { Perform (theSet, 0, theSet->Size() - 1); }
0046 
0047   //! Sorts the given (inclusive) range in the set.
0048   virtual void Perform (BVH_Set<T, N>* theSet, const Standard_Integer theStart, const Standard_Integer theFinal) Standard_OVERRIDE;
0049 
0050   //! Returns Morton codes assigned to BVH primitives.
0051   const NCollection_Array1<BVH_EncodedLink>& EncodedLinks() const { return *myEncodedLinks; }
0052 
0053 protected:
0054 
0055   //! Axis-aligned bounding box (AABB) to perform sorting.
0056   BVH_Box<T, N> myBox;
0057 
0058   //! Morton codes assigned to BVH primitives.
0059   Handle(NCollection_Shared<NCollection_Array1<BVH_EncodedLink> >) myEncodedLinks;
0060 
0061 };
0062 
0063 namespace BVH
0064 {
0065   // Radix sort STL predicate for 32-bit integer.
0066   struct BitPredicate
0067   {
0068     unsigned int myBit;
0069 
0070     //! Creates new radix sort predicate.
0071     BitPredicate (const Standard_Integer theDigit) : myBit (1U << theDigit) {}
0072 
0073     //! Returns predicate value.
0074     bool operator() (const BVH_EncodedLink theLink) const
0075     {
0076       return !(theLink.first & myBit); // 0-bit to the left side
0077     }
0078   };
0079 
0080   //! STL compare tool used in binary search algorithm.
0081   struct BitComparator
0082   {
0083     unsigned int myBit;
0084 
0085     //! Creates new STL comparator.
0086     BitComparator (const Standard_Integer theDigit) : myBit (1U << theDigit) {}
0087 
0088     //! Checks left value for the given bit.
0089     bool operator() (BVH_EncodedLink theLink1, BVH_EncodedLink /*theLink2*/)
0090     {
0091       return !(theLink1.first & myBit);
0092     }
0093   };
0094 
0095   //! Tool object for sorting link array using radix sort algorithm.
0096   class RadixSorter
0097   {
0098   public:
0099 
0100     typedef NCollection_Array1<BVH_EncodedLink>::iterator LinkIterator;
0101 
0102   private:
0103 
0104     //! Structure defining sorting range.
0105     struct SortRange
0106     {
0107       LinkIterator     myStart; //!< Start element of exclusive sorting range
0108       LinkIterator     myFinal; //!< Final element of exclusive sorting range
0109       Standard_Integer myDigit; //!< Bit number used for partition operation
0110     };
0111 
0112     //! Functor class to run sorting in parallel.
0113     class Functor
0114     {
0115     public:
0116       Functor(const SortRange (&aSplits)[2], const Standard_Boolean isParallel)
0117       : mySplits     (aSplits),
0118         myIsParallel (isParallel)
0119       {
0120       }
0121       
0122       //! Runs sorting function for the given range.
0123       void operator()(const Standard_Integer theIndex) const
0124       {
0125         RadixSorter::Sort (mySplits[theIndex].myStart, mySplits[theIndex].myFinal,
0126                            mySplits[theIndex].myDigit, myIsParallel);
0127       }
0128 
0129     private:
0130       void operator=(const Functor&);
0131       
0132     private:
0133       const SortRange (&mySplits)[2];
0134       Standard_Boolean myIsParallel;
0135     };
0136 
0137   public:
0138 
0139     static void Sort (LinkIterator theStart, LinkIterator theFinal, Standard_Integer theDigit, const Standard_Boolean isParallel)
0140     {
0141       if (theDigit < 24)
0142       {
0143         BVH::RadixSorter::perform (theStart, theFinal, theDigit);
0144       }
0145       else
0146       {
0147         LinkIterator anOffset = std::partition (theStart, theFinal, BitPredicate (theDigit));
0148         SortRange aSplits[2] = {
0149           {theStart, anOffset, theDigit - 1},
0150           {anOffset, theFinal, theDigit - 1}
0151         };
0152 
0153         OSD_Parallel::For (0, 2, Functor (aSplits, isParallel), !isParallel);
0154       }
0155     }
0156 
0157   protected:
0158 
0159     // Performs MSD (most significant digit) radix sort.
0160     static void perform (LinkIterator theStart, LinkIterator theFinal, Standard_Integer theDigit = 29)
0161     {
0162       while (theStart != theFinal && theDigit >= 0)
0163       {
0164         LinkIterator anOffset = std::partition (theStart, theFinal, BitPredicate (theDigit--));
0165         perform (theStart, anOffset, theDigit);
0166         theStart = anOffset;
0167       }
0168     }
0169   };
0170 }
0171 
0172 // =======================================================================
0173 // function : Perform
0174 // purpose  :
0175 // =======================================================================
0176 template<class T, int N>
0177 void BVH_RadixSorter<T, N>::Perform (BVH_Set<T, N>* theSet, const Standard_Integer theStart, const Standard_Integer theFinal)
0178 {
0179   Standard_STATIC_ASSERT (N == 2 || N == 3 || N == 4);
0180 
0181   const Standard_Integer aDimension = 1024;
0182   const Standard_Integer aNbEffComp = N == 2 ? 2 : 3; // 4th component is ignored
0183 
0184   const BVH_VecNt aSceneMin = myBox.CornerMin();
0185   const BVH_VecNt aSceneMax = myBox.CornerMax();
0186 
0187   BVH_VecNt aNodeMinSizeVecT (static_cast<T>(BVH::THE_NODE_MIN_SIZE));
0188   BVH::BoxMinMax<T, N>::CwiseMax (aNodeMinSizeVecT, aSceneMax - aSceneMin);
0189 
0190   const BVH_VecNt aReverseSize = BVH_VecNt (static_cast<T>(aDimension)) / aNodeMinSizeVecT;
0191 
0192   myEncodedLinks = new NCollection_Shared<NCollection_Array1<BVH_EncodedLink> >(theStart, theFinal);
0193 
0194   // Step 1 -- Assign Morton code to each primitive
0195   for (Standard_Integer aPrimIdx = theStart; aPrimIdx <= theFinal; ++aPrimIdx)
0196   {
0197     const BVH_VecNt aCenter = theSet->Box (aPrimIdx).Center();
0198     const BVH_VecNt aVoxelF = (aCenter - aSceneMin) * aReverseSize;
0199 
0200     unsigned int aMortonCode = 0;
0201     for (Standard_Integer aCompIter = 0; aCompIter < aNbEffComp; ++aCompIter)
0202     {
0203       const Standard_Integer aVoxelI = BVH::IntFloor (BVH::VecComp<T, N>::Get (aVoxelF, aCompIter));
0204 
0205       unsigned int aVoxel = static_cast<unsigned int>(Max (0, Min (aVoxelI, aDimension - 1)));
0206 
0207       aVoxel = (aVoxel | (aVoxel << 16)) & 0x030000FF;
0208       aVoxel = (aVoxel | (aVoxel <<  8)) & 0x0300F00F;
0209       aVoxel = (aVoxel | (aVoxel <<  4)) & 0x030C30C3;
0210       aVoxel = (aVoxel | (aVoxel <<  2)) & 0x09249249;
0211 
0212       aMortonCode |= (aVoxel << aCompIter);
0213     }
0214 
0215     myEncodedLinks->ChangeValue (aPrimIdx) = BVH_EncodedLink (aMortonCode, aPrimIdx);
0216   }
0217 
0218   // Step 2 -- Sort primitives by their Morton codes using radix sort
0219   BVH::RadixSorter::Sort (myEncodedLinks->begin(), myEncodedLinks->end(), 29, this->IsParallel());
0220 
0221   NCollection_Array1<Standard_Integer> aLinkMap (theStart, theFinal);
0222   for (Standard_Integer aLinkIdx = theStart; aLinkIdx <= theFinal; ++aLinkIdx)
0223   {
0224     aLinkMap (myEncodedLinks->Value (aLinkIdx).second) = aLinkIdx;
0225   }
0226 
0227   // Step 3 -- Rearranging primitive list according to Morton codes (in place)
0228   Standard_Integer aPrimIdx = theStart;
0229   while (aPrimIdx <= theFinal)
0230   {
0231     const Standard_Integer aSortIdx = aLinkMap (aPrimIdx);
0232     if (aPrimIdx != aSortIdx)
0233     {
0234       theSet->Swap (aPrimIdx, aSortIdx);
0235       std::swap (aLinkMap (aPrimIdx),
0236                  aLinkMap (aSortIdx));
0237     }
0238     else
0239     {
0240       ++aPrimIdx;
0241     }
0242   }
0243 }
0244 
0245 #endif // _BVH_RadixSorter_Header