1 // Created on: 2014-09-11
2 // Created by: Danila ULYANOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <Standard_Assert.hxx>
18 // =======================================================================
19 // function : BVH_LinearBuilder
21 // =======================================================================
22 template<class T, int N>
23 BVH_LinearBuilder<T, N>::BVH_LinearBuilder (const Standard_Integer theLeafNodeSize,
24 const Standard_Integer theMaxTreeDepth)
25 : BVH_Builder<T, N> (theLeafNodeSize,
31 // =======================================================================
32 // function : ~BVH_LinearBuilder
34 // =======================================================================
35 template<class T, int N>
36 BVH_LinearBuilder<T, N>::~BVH_LinearBuilder()
41 // =======================================================================
42 // function : LowerBound
43 // purpose : Returns index of first element greater than the given one
44 // =======================================================================
45 template<class T, int N>
46 Standard_Integer BVH_LinearBuilder<T, N>::LowerBound (Standard_Integer theStart,
47 Standard_Integer theFinal,
48 Standard_Integer theDigit)
50 Standard_Integer aNbPrims = theFinal - theStart;
54 const Standard_Integer aStep = aNbPrims / 2;
56 if (myRadixSorter->EncodedLinks().Value (theStart + aStep).first & (1 << theDigit))
62 theStart += aStep + 1;
63 aNbPrims -= aStep + 1;
70 // =======================================================================
71 // function : EmitHierachy
72 // purpose : Emits hierarchy from sorted Morton codes
73 // =======================================================================
74 template<class T, int N>
75 Standard_Integer BVH_LinearBuilder<T, N>::EmitHierachy (BVH_Tree<T, N>* theBVH,
76 const Standard_Integer theBit,
77 const Standard_Integer theShift,
78 const Standard_Integer theStart,
79 const Standard_Integer theFinal)
81 if (theFinal - theStart > BVH_Builder<T, N>::myLeafNodeSize)
83 const Standard_Integer aPosition = theBit < 0 ?
84 (theStart + theFinal) / 2 : LowerBound (theStart, theFinal, theBit);
86 if (aPosition == theStart || aPosition == theFinal)
88 return EmitHierachy (theBVH, theBit - 1, theShift, theStart, theFinal);
92 const Standard_Integer aNode = theBVH->AddInnerNode (0, 0);
94 const Standard_Integer aRghNode = theShift + aPosition - theStart;
96 const Standard_Integer aLftChild = EmitHierachy (theBVH, theBit - 1, theShift, theStart, aPosition);
97 const Standard_Integer aRghChild = EmitHierachy (theBVH, theBit - 1, aRghNode, aPosition, theFinal);
99 theBVH->NodeInfoBuffer()[aNode].y() = aLftChild;
100 theBVH->NodeInfoBuffer()[aNode].z() = aRghChild;
107 return theBVH->AddLeafNode (theShift, theShift + theFinal - theStart - 1);
113 //! Calculates bounding boxes (AABBs) for the given BVH tree.
114 template<class T, int N>
115 Standard_Integer UpdateBounds (BVH_Set<T, N>* theSet, BVH_Tree<T, N>* theTree, const Standard_Integer theNode = 0)
117 const BVH_Vec4i aData = theTree->NodeInfoBuffer()[theNode];
121 const Standard_Integer aLftChild = theTree->NodeInfoBuffer()[theNode].y();
122 const Standard_Integer aRghChild = theTree->NodeInfoBuffer()[theNode].z();
124 const Standard_Integer aLftDepth = UpdateBounds (theSet, theTree, aLftChild);
125 const Standard_Integer aRghDepth = UpdateBounds (theSet, theTree, aRghChild);
127 typename BVH_Box<T, N>::BVH_VecNt aLftMinPoint = theTree->MinPointBuffer()[aLftChild];
128 typename BVH_Box<T, N>::BVH_VecNt aLftMaxPoint = theTree->MaxPointBuffer()[aLftChild];
129 typename BVH_Box<T, N>::BVH_VecNt aRghMinPoint = theTree->MinPointBuffer()[aRghChild];
130 typename BVH_Box<T, N>::BVH_VecNt aRghMaxPoint = theTree->MaxPointBuffer()[aRghChild];
132 BVH::BoxMinMax<T, N>::CwiseMin (aLftMinPoint, aRghMinPoint);
133 BVH::BoxMinMax<T, N>::CwiseMax (aLftMaxPoint, aRghMaxPoint);
135 theTree->MinPointBuffer()[theNode] = aLftMinPoint;
136 theTree->MaxPointBuffer()[theNode] = aLftMaxPoint;
138 return Max (aLftDepth, aRghDepth) + 1;
142 typename BVH_Box<T, N>::BVH_VecNt& aMinPoint = theTree->MinPointBuffer()[theNode];
143 typename BVH_Box<T, N>::BVH_VecNt& aMaxPoint = theTree->MaxPointBuffer()[theNode];
145 for (Standard_Integer aPrimIdx = aData.y(); aPrimIdx <= aData.z(); ++aPrimIdx)
147 const BVH_Box<T, N> aBox = theSet->Box (aPrimIdx);
149 if (aPrimIdx == aData.y())
151 aMinPoint = aBox.CornerMin();
152 aMaxPoint = aBox.CornerMax();
156 BVH::BoxMinMax<T, N>::CwiseMin (aMinPoint, aBox.CornerMin());
157 BVH::BoxMinMax<T, N>::CwiseMax (aMaxPoint, aBox.CornerMax());
167 //! TBB task for parallel bounds updating.
168 template<class T, int N>
169 class UpdateBoundTask: public tbb::task
171 //! Set of geometric objects.
172 BVH_Set<T, N>* mySet;
174 //! BVH tree built over the set.
175 BVH_Tree<T, N>* myBVH;
177 //! BVH node to update bounding box.
178 Standard_Integer myNode;
180 //! Level of the processed BVH node.
181 Standard_Integer myLevel;
183 //! Height of the processed BVH node.
184 Standard_Integer* myHeight;
188 //! Creates new TBB parallel bound update task.
189 UpdateBoundTask (BVH_Set<T, N>* theSet,
190 BVH_Tree<T, N>* theBVH,
191 Standard_Integer theNode,
192 Standard_Integer theLevel,
193 Standard_Integer* theHeight)
203 //! Executes the task.
206 if (myBVH->IsOuter (myNode) || myLevel > 2)
208 *myHeight = BVH::UpdateBounds (mySet, myBVH, myNode);
212 Standard_Integer aLftHeight = 0;
213 Standard_Integer aRghHeight = 0;
215 tbb::task_list aList;
217 const Standard_Integer aLftChild = myBVH->NodeInfoBuffer()[myNode].y();
218 const Standard_Integer aRghChild = myBVH->NodeInfoBuffer()[myNode].z();
220 Standard_Integer aCount = 1;
222 if (!myBVH->IsOuter (aLftChild))
225 aList.push_back (*new ( allocate_child() )
226 UpdateBoundTask (mySet, myBVH, aLftChild, myLevel + 1, &aLftHeight));
230 aLftHeight = BVH::UpdateBounds (mySet, myBVH, aLftChild);
233 if (!myBVH->IsOuter (aRghChild))
236 aList.push_back (*new( allocate_child() )
237 UpdateBoundTask (mySet, myBVH, aRghChild, myLevel + 1, &aRghHeight));
241 aRghHeight = BVH::UpdateBounds (mySet, myBVH, aRghChild);
246 set_ref_count (aCount);
247 spawn_and_wait_for_all (aList);
250 typename BVH_Box<T, N>::BVH_VecNt aLftMinPoint = myBVH->MinPointBuffer()[aLftChild];
251 typename BVH_Box<T, N>::BVH_VecNt aLftMaxPoint = myBVH->MaxPointBuffer()[aLftChild];
252 typename BVH_Box<T, N>::BVH_VecNt aRghMinPoint = myBVH->MinPointBuffer()[aRghChild];
253 typename BVH_Box<T, N>::BVH_VecNt aRghMaxPoint = myBVH->MaxPointBuffer()[aRghChild];
255 BVH::BoxMinMax<T, N>::CwiseMin (aLftMinPoint, aRghMinPoint);
256 BVH::BoxMinMax<T, N>::CwiseMax (aLftMaxPoint, aRghMaxPoint);
258 myBVH->MinPointBuffer()[myNode] = aLftMinPoint;
259 myBVH->MaxPointBuffer()[myNode] = aLftMaxPoint;
261 *myHeight = Max (aLftHeight, aRghHeight) + 1;
271 // =======================================================================
274 // =======================================================================
275 template<class T, int N>
276 void BVH_LinearBuilder<T, N>::Build (BVH_Set<T, N>* theSet,
277 BVH_Tree<T, N>* theBVH,
278 const BVH_Box<T, N>& theBox)
280 Standard_STATIC_ASSERT (N == 3 || N == 4);
281 const Standard_Integer aSetSize = theSet->Size();
282 if (theBVH == NULL || aSetSize == 0)
289 // Step 0 -- Initialize parameter of virtual grid
290 myRadixSorter = new BVH_RadixSorter<T, N> (theBox);
292 // Step 1 - Perform radix sorting of primitive set
293 myRadixSorter->Perform (theSet);
295 // Step 2 -- Emitting BVH hierarchy from sorted Morton codes
296 EmitHierachy (theBVH, 29, 0, 0, theSet->Size());
298 // Step 3 -- Compute bounding boxes of BVH nodes
299 theBVH->MinPointBuffer().resize (theBVH->NodeInfoBuffer().size());
300 theBVH->MaxPointBuffer().resize (theBVH->NodeInfoBuffer().size());
302 Standard_Integer aHeight = 0;
306 // Note: Although TBB tasks are allocated using placement
307 // new, we do not need to delete them explicitly
308 BVH::UpdateBoundTask<T, N>& aRootTask = *new ( tbb::task::allocate_root() )
309 BVH::UpdateBoundTask<T, N> (theSet, theBVH, 0, 0, &aHeight);
311 tbb::task::spawn_root_and_wait (aRootTask);
315 aHeight = BVH::UpdateBounds (theSet, theBVH, 0);
319 BVH_Builder<T, N>::UpdateDepth (theBVH, aHeight);