Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-14 10:34:24

0001 // Created on: 2016-06-20
0002 // Created by: Denis BOGOLEPOV
0003 // Copyright (c) 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_BinaryTree_Header
0017 #define _BVH_BinaryTree_Header
0018 
0019 #include <BVH_QuadTree.hxx>
0020 #include <NCollection_DynamicArray.hxx>
0021 
0022 #include <deque>
0023 #include <tuple>
0024 
0025 //! Specialization of binary BVH tree.
0026 template <class T, int N>
0027 class BVH_Tree<T, N, BVH_BinaryTree> : public BVH_TreeBase<T, N>
0028 {
0029 public: //! @name custom data types
0030   typedef typename BVH_TreeBase<T, N>::BVH_VecNt BVH_VecNt;
0031 
0032 public: //! @name methods for accessing individual nodes
0033   //! Creates new empty BVH tree.
0034   BVH_Tree()
0035       : BVH_TreeBase<T, N>()
0036   {
0037   }
0038 
0039   //! Sets node type to 'outer'.
0040   void SetOuter(const int theNodeIndex)
0041   {
0042     BVH::Array<int, 4>::ChangeValue(this->myNodeInfoBuffer, theNodeIndex).x() = 1;
0043   }
0044 
0045   //! Sets node type to 'inner'.
0046   void SetInner(const int theNodeIndex)
0047   {
0048     BVH::Array<int, 4>::ChangeValue(this->myNodeInfoBuffer, theNodeIndex).x() = 0;
0049   }
0050 
0051   //! Returns index of the K-th child of the given inner node.
0052   //! \tparam K the index of node child (0 or 1)
0053   template <int K>
0054   int Child(const int theNodeIndex) const
0055   {
0056     return BVH::Array<int, 4>::Value(this->myNodeInfoBuffer, theNodeIndex)[K + 1];
0057   }
0058 
0059   //! Returns index of the K-th child of the given inner node.
0060   //! \tparam K the index of node child (0 or 1)
0061   template <int K>
0062   int& ChangeChild(const int theNodeIndex)
0063   {
0064     return BVH::Array<int, 4>::ChangeValue(this->myNodeInfoBuffer, theNodeIndex)[K + 1];
0065   }
0066 
0067   //! Returns index of the K-th child of the given inner node.
0068   //! \tparam K the index of node child (0 or 1)
0069   template <int K>
0070   int& Child(const int theNodeIndex)
0071   {
0072     return BVH::Array<int, 4>::ChangeValue(this->myNodeInfoBuffer, theNodeIndex)[K + 1];
0073   }
0074 
0075 public: //! @name methods for adding/removing tree nodes
0076   //! Removes all nodes from the tree.
0077   void Clear()
0078   {
0079     this->myDepth = 0;
0080     BVH::Array<T, N>::Clear(this->myMinPointBuffer);
0081     BVH::Array<T, N>::Clear(this->myMaxPointBuffer);
0082     BVH::Array<int, 4>::Clear(this->myNodeInfoBuffer);
0083   }
0084 
0085   //! Reserves internal BVH storage, so that it
0086   //! can contain the given number of BVH nodes.
0087   void Reserve(const int theNbNodes)
0088   {
0089     BVH::Array<T, N>::Reserve(this->myMinPointBuffer, theNbNodes);
0090     BVH::Array<T, N>::Reserve(this->myMaxPointBuffer, theNbNodes);
0091     BVH::Array<int, 4>::Reserve(this->myNodeInfoBuffer, theNbNodes);
0092   }
0093 
0094   //! Adds new leaf node to the BVH.
0095   int AddLeafNode(const BVH_VecNt& theMinPoint,
0096                   const BVH_VecNt& theMaxPoint,
0097                   const int        theBegElem,
0098                   const int        theEndElem)
0099   {
0100     BVH::Array<T, N>::Append(this->myMinPointBuffer, theMinPoint);
0101     BVH::Array<T, N>::Append(this->myMaxPointBuffer, theMaxPoint);
0102     BVH::Array<int, 4>::Append(this->myNodeInfoBuffer, BVH_Vec4i(1, theBegElem, theEndElem, 0));
0103     return BVH::Array<int, 4>::Size(this->myNodeInfoBuffer) - 1;
0104   }
0105 
0106   //! Adds new inner node to the BVH.
0107   int AddInnerNode(const BVH_VecNt& theMinPoint,
0108                    const BVH_VecNt& theMaxPoint,
0109                    const int        theLftChild,
0110                    const int        theRghChild)
0111   {
0112     BVH::Array<T, N>::Append(this->myMinPointBuffer, theMinPoint);
0113     BVH::Array<T, N>::Append(this->myMaxPointBuffer, theMaxPoint);
0114     BVH::Array<int, 4>::Append(this->myNodeInfoBuffer, BVH_Vec4i(0, theLftChild, theRghChild, 0));
0115     return BVH::Array<int, 4>::Size(this->myNodeInfoBuffer) - 1;
0116   }
0117 
0118   //! Adds new leaf node to the BVH.
0119   int AddLeafNode(const BVH_Box<T, N>& theAABB, const int theBegElem, const int theEndElem)
0120   {
0121     return AddLeafNode(theAABB.CornerMin(), theAABB.CornerMax(), theBegElem, theEndElem);
0122   }
0123 
0124   //! Adds new inner node to the BVH.
0125   int AddInnerNode(const BVH_Box<T, N>& theAABB, const int theLftChild, const int theRghChild)
0126   {
0127     return AddInnerNode(theAABB.CornerMin(), theAABB.CornerMax(), theLftChild, theRghChild);
0128   }
0129 
0130   //! Adds new leaf node to the BVH with UNINITIALIZED bounds.
0131   int AddLeafNode(const int theBegElem, const int theEndElem)
0132   {
0133     BVH::Array<int, 4>::Append(this->myNodeInfoBuffer, BVH_Vec4i(1, theBegElem, theEndElem, 0));
0134     return BVH::Array<int, 4>::Size(this->myNodeInfoBuffer) - 1;
0135   }
0136 
0137   //! Adds new inner node to the BVH with UNINITIALIZED bounds.
0138   int AddInnerNode(const int theLftChild, const int theRghChild)
0139   {
0140     BVH::Array<int, 4>::Append(this->myNodeInfoBuffer, BVH_Vec4i(0, theLftChild, theRghChild, 0));
0141     return BVH::Array<int, 4>::Size(this->myNodeInfoBuffer) - 1;
0142   }
0143 
0144 public: //! @name methods specific to binary BVH
0145   //! Returns value of SAH (surface area heuristic).
0146   //! Allows to compare the quality of BVH trees constructed for
0147   //! the same sets of geometric objects with different methods.
0148   T EstimateSAH() const;
0149 
0150   //! Collapses the tree into QBVH an returns it. As a result, each
0151   //! 2-nd level of current tree is kept and the rest are discarded.
0152   BVH_Tree<T, N, BVH_QuadTree>* CollapseToQuadTree() const;
0153 };
0154 
0155 namespace BVH
0156 {
0157 //! Internal function for recursive calculation of
0158 //! surface area heuristic (SAH) of the given tree.
0159 template <class T, int N>
0160 void EstimateSAH(const BVH_Tree<T, N, BVH_BinaryTree>* theTree,
0161                  const int                             theNode,
0162                  T                                     theProb,
0163                  T&                                    theSAH)
0164 {
0165   BVH_Box<T, N> aBox(theTree->MinPoint(theNode), theTree->MaxPoint(theNode));
0166 
0167   if (theTree->IsOuter(theNode))
0168   {
0169     theSAH += theProb * (theTree->EndPrimitive(theNode) - theTree->BegPrimitive(theNode) + 1);
0170   }
0171   else
0172   {
0173     theSAH += theProb * static_cast<T>(2.0);
0174 
0175     BVH_Box<T, N> aLftBox(theTree->MinPoint(theTree->template Child<0>(theNode)),
0176                           theTree->MaxPoint(theTree->template Child<0>(theNode)));
0177 
0178     if (theProb > 0.0)
0179     {
0180       EstimateSAH(theTree,
0181                   theTree->template Child<0>(theNode),
0182                   theProb * aLftBox.Area() / aBox.Area(),
0183                   theSAH);
0184     }
0185 
0186     BVH_Box<T, N> aRghBox(theTree->MinPoint(theTree->template Child<1>(theNode)),
0187                           theTree->MaxPoint(theTree->template Child<1>(theNode)));
0188 
0189     if (theProb > 0.0)
0190     {
0191       EstimateSAH(theTree,
0192                   theTree->template Child<1>(theNode),
0193                   theProb * aRghBox.Area() / aBox.Area(),
0194                   theSAH);
0195     }
0196   }
0197 }
0198 } // namespace BVH
0199 
0200 //=================================================================================================
0201 
0202 template <class T, int N>
0203 T BVH_Tree<T, N, BVH_BinaryTree>::EstimateSAH() const
0204 {
0205   T aSAH = static_cast<T>(0.0);
0206   BVH::EstimateSAH<T, N>(this, 0, static_cast<T>(1.0), aSAH);
0207   return aSAH;
0208 }
0209 
0210 //=================================================================================================
0211 
0212 template <class T, int N>
0213 BVH_Tree<T, N, BVH_QuadTree>* BVH_Tree<T, N, BVH_BinaryTree>::CollapseToQuadTree() const
0214 {
0215   BVH_Tree<T, N, BVH_QuadTree>* aQBVH = new BVH_Tree<T, N, BVH_QuadTree>;
0216 
0217   if (this->Length() == 0)
0218   {
0219     return aQBVH;
0220   }
0221 
0222   std::deque<std::pair<int, int>> aQueue(1, std::make_pair(0, 0));
0223 
0224   for (int aNbNodes = 1; !aQueue.empty();)
0225   {
0226     const std::pair<int, int> aNode = aQueue.front();
0227 
0228     BVH::Array<T, N>::Append(aQBVH->myMinPointBuffer,
0229                              BVH::Array<T, N>::Value(this->myMinPointBuffer, std::get<0>(aNode)));
0230     BVH::Array<T, N>::Append(aQBVH->myMaxPointBuffer,
0231                              BVH::Array<T, N>::Value(this->myMaxPointBuffer, std::get<0>(aNode)));
0232 
0233     BVH_Vec4i aNodeInfo;
0234     if (this->IsOuter(std::get<0>(aNode))) // is leaf node
0235     {
0236       aNodeInfo = BVH_Vec4i(1 /* leaf flag */,
0237                             this->BegPrimitive(std::get<0>(aNode)),
0238                             this->EndPrimitive(std::get<0>(aNode)),
0239                             std::get<1>(aNode) /* level */);
0240     }
0241     else
0242     {
0243       NCollection_DynamicArray<int> aGrandChildNodes;
0244 
0245       const int aLftChild = Child<0>(std::get<0>(aNode));
0246       const int aRghChild = Child<1>(std::get<0>(aNode));
0247       if (this->IsOuter(aLftChild)) // is leaf node
0248       {
0249         aGrandChildNodes.Append(aLftChild);
0250       }
0251       else
0252       {
0253         aGrandChildNodes.Append(Child<0>(aLftChild));
0254         aGrandChildNodes.Append(Child<1>(aLftChild));
0255       }
0256 
0257       if (this->IsOuter(aRghChild)) // is leaf node
0258       {
0259         aGrandChildNodes.Append(aRghChild);
0260       }
0261       else
0262       {
0263         aGrandChildNodes.Append(Child<0>(aRghChild));
0264         aGrandChildNodes.Append(Child<1>(aRghChild));
0265       }
0266 
0267       for (int aNodeIdx = 0; aNodeIdx < aGrandChildNodes.Length(); ++aNodeIdx)
0268       {
0269         aQueue.emplace_back(aGrandChildNodes(aNodeIdx), std::get<1>(aNode) + 1);
0270       }
0271 
0272       aNodeInfo = BVH_Vec4i(0 /* inner flag */,
0273                             aNbNodes,
0274                             aGrandChildNodes.Length() - 1,
0275                             std::get<1>(aNode) /* level */);
0276 
0277       aQBVH->myDepth = (std::max)(aQBVH->myDepth, std::get<1>(aNode) + 1);
0278 
0279       aNbNodes += aGrandChildNodes.Length();
0280     }
0281 
0282     BVH::Array<int, 4>::Append(aQBVH->myNodeInfoBuffer, aNodeInfo);
0283     aQueue.pop_front(); // node processing completed
0284   }
0285 
0286   return aQBVH;
0287 }
0288 
0289 #endif // _BVH_BinaryTree_Header