1 // File: NCollection_UBTree.hxx
2 // Created: 30.07.02 09:51:33
3 // Author: Michael SAZONOV
4 // Copyright: Open CASCADE 2002
6 #ifndef NCollection_UBTree_HeaderFile
7 #define NCollection_UBTree_HeaderFile
9 #include <NCollection_BaseAllocator.hxx>
12 // Disable the warning: "operator new unmatched by delete"
13 #pragma warning (push)
14 #pragma warning (disable:4291)
18 * The algorithm of unbalanced binary tree of overlapped bounding boxes.
20 * Once the tree of boxes of geometric objects is constructed, the algorithm
21 * is capable of fast geometric selection of objects. The tree can be easily
22 * updated by adding to it a new object with bounding box.
24 * The time of adding to the tree of one object is O(log(N)), where N is the
25 * total number of objects, so the time of building a tree of N objects is
26 * O(N(log(N)). The search time of one object is O(log(N)).
28 * Defining various classes inheriting NCollection_UBTree::Selector we can
29 * perform various kinds of selection over the same b-tree object
31 * The object may be of any type allowing copying. Among the best suitable
32 * solutions there can be a pointer to an object, handled object or integer
33 * index of object inside some collection. The bounding object may have any
34 * dimension and geometry. The minimal interface of TheBndType (besides
35 * public empty and copy constructor and operator =) used in UBTree algorithm
36 * is as the following:
41 * inline void Add (const MyBndType& other);
42 * // Updates me with other bounding
44 * inline Standard_Boolean IsOut (const MyBndType& other) const;
45 * // Classifies other bounding relatively me
47 * inline Standard_Real SquareExtent() const;
48 * // Computes the squared maximal linear extent of me.
49 * // (For box it is the squared diagonal of box)
52 * To select objects you need to define a class derived from UBTree::Selector
53 * that should redefine the necessary virtual methods to maintain the
54 * selection condition. The object of this class is also used to retrieve
55 * selected objects after search.
58 template <class TheObjType, class TheBndType> class NCollection_UBTree
61 // ---------- PUBLIC TYPES ----------
64 * Class defining the minimal interface of selector.
72 Selector () : myStop(Standard_False) {}
75 * Rejection base on the bounding type.
77 * True if the bounding box does not conform to some selection conditions
79 virtual Standard_Boolean Reject (const TheBndType&) const = 0;
82 * Confirm the object while making necessary tests on it. This method is
83 * called when the bounding box of the object conforms to the conditions
84 * (see Reject()). It is also supposed to keep record of accepted objects.
86 * True if the object is accepted
88 virtual Standard_Boolean Accept (const TheObjType&) = 0;
91 * This condition is checked after each call to Accept().
93 * True signals that the selection process is stopped
95 Standard_Boolean Stop () const { return myStop; }
100 virtual ~Selector () {}
104 * The method Accept() should set this flag if the selection process
107 Standard_Boolean myStop;
111 * Class describing the node of the tree.
112 * Initially the tree consists of one leaf. A node can grow to a branch
113 * holding two childs:
114 * - one correspondent to initial node
115 * - the new one with a new object and bounding box
120 TreeNode (const TheObjType& theObj, const TheBndType& theBnd)
121 : myBnd(theBnd), myObject(theObj), myChildren(0), myParent(0) {}
123 Standard_Boolean IsLeaf () const { return !myChildren; }
124 Standard_Boolean IsRoot () const { return !myParent; }
125 const TheBndType& Bnd () const { return myBnd; }
126 TheBndType& ChangeBnd () { return myBnd; }
127 const TheObjType& Object () const { return myObject; }
128 const TreeNode& Child (const Standard_Integer i) const
129 { return myChildren[i]; }
130 TreeNode& ChangeChild (const Standard_Integer i)
131 { return myChildren[i]; }
132 const TreeNode& Parent () const { return *myParent; }
133 TreeNode& ChangeParent () { return *myParent; }
136 * Forces *this node being gemmated such a way that it becomes
137 * a branch holding the previous content of *this node at the
138 * first child and theObj at the second child.
140 * new bounding box comprizing both child nodes.
144 * bounding box of theObj.
146 * allocator providing memory to the new child nodes, provided by the
147 * calling Tree instance.
149 void Gemmate (const TheBndType& theNewBnd,
150 const TheObjType& theObj,
151 const TheBndType& theBnd,
152 const Handle(NCollection_BaseAllocator)& theAlloc)
154 //TreeNode *children = new TreeNode [2];
155 TreeNode *children = (TreeNode *) theAlloc->Allocate (2*sizeof(TreeNode));
156 new (&children[0]) TreeNode;
157 new (&children[1]) TreeNode;
159 children[1].myObject = theObj;
160 children[1].myBnd = theBnd;
161 children[0].myParent = children[1].myParent = this;
163 myChildren[0].myParent = children;
164 myChildren[1].myParent = children;
166 myChildren = children;
168 myObject = TheObjType(); // nullify myObject
172 * Kills the i-th child, and *this accepts the content of another child
174 void Kill (const Standard_Integer i,
175 const Handle(NCollection_BaseAllocator)& theAlloc)
178 TreeNode *oldChildren = myChildren;
179 const Standard_Integer iopp = 1 - i;
180 myBnd = oldChildren[iopp].myBnd;
181 myObject = oldChildren[iopp].myObject;
182 myChildren = oldChildren[iopp].myChildren;
184 myChildren[0].myParent = this;
185 myChildren[1].myParent = this;
187 // oldChildren[0].myChildren = oldChildren[1].myChildren = 0L;
188 // delete [] oldChildren;
189 oldChildren[iopp].~TreeNode();
190 delNode(&oldChildren[i], theAlloc); // remove the whole branch
191 theAlloc->Free(oldChildren);
195 // ~TreeNode () { if (myChildren) delete [] myChildren; }
196 ~TreeNode () { myChildren = 0L; }
199 * Allocator of a tree node.
201 void * operator new (size_t theSize,
202 const Handle(NCollection_BaseAllocator)& theAllocator)
203 { return theAllocator->Allocate(theSize); }
206 * Allocator of a tree node.
208 void * operator new (size_t,
213 * Deleter of tree node. The whole hierarchy of its children also deleted.
214 * This method should be used instead of operator delete.
216 static void delNode (TreeNode * theNode,
217 Handle(NCollection_BaseAllocator)& theAlloc)
220 if (theNode -> myChildren) {
221 delNode (&theNode -> myChildren[0], theAlloc);
222 delNode (&theNode -> myChildren[1], theAlloc);
223 theAlloc->Free(theNode -> myChildren);
225 theNode->~TreeNode();
230 TreeNode () : myChildren(0L), myParent(0L) {}
232 TheBndType myBnd; ///< bounding geometry
233 TheObjType myObject; ///< the object
234 TreeNode *myChildren; ///< 2 children forming a b-tree
235 TreeNode *myParent; ///< the pointer to a parent node
238 // ---------- PUBLIC METHODS ----------
244 (const Handle(NCollection_BaseAllocator)& theAllocator=0L)
245 : myRoot(0L), myLastNode(0L)
247 if (theAllocator.IsNull())
248 myAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
250 myAlloc = theAllocator;
254 * Update the tree with a new object and its bounding box.
258 * bounding box of the object.
262 Standard_EXPORT virtual Standard_Boolean Add (const TheObjType& theObj,
263 const TheBndType& theBnd);
266 * Searches in the tree all objects conforming to the given selector.
268 * Number of objects accepted
270 virtual Standard_Integer Select (Selector& theSelector) const
271 { return (IsEmpty() ? 0 : Select (Root(), theSelector)); }
274 * Clears the contents of the tree.
276 * Optional: a new allocator that will be used when the tree is rebuilt
277 * anew. This makes sense if the memory allocator needs re-initialisation
278 * (like NCollection_IncAllocator). By default the previous allocator is
281 virtual void Clear (const Handle(NCollection_BaseAllocator)& aNewAlloc = 0L)
282 // { if (myRoot) delete myRoot; myRoot = 0L; }
285 TreeNode::delNode (myRoot, this->myAlloc);
286 this->myAlloc->Free (myRoot);
289 if (aNewAlloc.IsNull() == Standard_False)
293 Standard_Boolean IsEmpty () const { return !myRoot; }
297 * the root node of the tree
299 const TreeNode& Root () const { return *myRoot; }
304 virtual ~NCollection_UBTree () { Clear(); }
307 * Recommended to be used only in sub-classes.
309 * Allocator object used in this instance of UBTree.
311 const Handle(NCollection_BaseAllocator)& Allocator () const
315 // ---------- PROTECTED METHODS ----------
319 * the last added node
321 TreeNode& ChangeLastNode () { return *myLastNode; }
324 * Searches in the branch all objects conforming to the given selector.
326 * the number of objects accepted
328 Standard_EXPORT Standard_Integer Select (const TreeNode& theBranch,
329 Selector& theSelector) const;
332 // ---------- PRIVATE METHODS ----------
334 /// Copy constructor (prohibited).
335 NCollection_UBTree (const NCollection_UBTree&);
337 /// Assignment operator (prohibited).
338 NCollection_UBTree& operator = (const NCollection_UBTree&);
340 // ---------- PRIVATE FIELDS ----------
342 TreeNode *myRoot; ///< root of the tree
343 TreeNode *myLastNode;///< the last added node
344 Handle(NCollection_BaseAllocator) myAlloc; ///< Allocator for TreeNode
347 // ================== METHODS TEMPLATES =====================
348 //=======================================================================
350 //purpose : Updates the tree with a new object and its bounding box
351 //=======================================================================
353 template <class TheObjType, class TheBndType>
354 Standard_Boolean NCollection_UBTree<TheObjType,TheBndType>::Add
355 (const TheObjType& theObj,
356 const TheBndType& theBnd)
359 // Accepting first object
360 myRoot = new (this->myAlloc) TreeNode (theObj, theBnd);
362 return Standard_True;
365 TreeNode *pBranch = myRoot;
366 Standard_Boolean isOutOfBranch = pBranch->Bnd().IsOut (theBnd);
369 // condition of stopping the search
370 if (isOutOfBranch || pBranch->IsLeaf()) {
371 TheBndType aNewBnd = theBnd;
372 aNewBnd.Add (pBranch->Bnd());
373 // put the new leaf aside on the level of pBranch
374 pBranch->Gemmate (aNewBnd, theObj, theBnd, this->myAlloc);
375 myLastNode = &pBranch->ChangeChild(1);
379 // Update the bounding box of the branch
380 pBranch->ChangeBnd().Add (theBnd);
382 // Select the best child branch to accept the object:
383 // 1. First check if one branch is out and another one is not.
384 // 2. Else select the child having the least union with theBnd
385 Standard_Integer iBest = 0;
386 Standard_Boolean isOut[] = { pBranch->Child(0).Bnd().IsOut (theBnd),
387 pBranch->Child(1).Bnd().IsOut (theBnd) };
388 if (isOut[0] != isOut[1])
389 iBest = (isOut[0] ? 1 : 0);
391 TheBndType aUnion[] = { theBnd, theBnd };
392 aUnion[0].Add (pBranch->Child(0).Bnd());
393 aUnion[1].Add (pBranch->Child(1).Bnd());
394 const Standard_Real d1 = aUnion[0].SquareExtent();
395 const Standard_Real d2 = aUnion[1].SquareExtent();
400 // Continue with the selected branch
401 isOutOfBranch = isOut[iBest];
402 pBranch = &pBranch->ChangeChild(iBest);
404 return Standard_True;
407 //=======================================================================
409 //purpose : Recursively searches in the branch all objects conforming
410 // to the given selector.
411 // Returns the number of objects found.
412 //=======================================================================
414 template <class TheObjType, class TheBndType>
415 Standard_Integer NCollection_UBTree<TheObjType,TheBndType>::Select
416 (const TreeNode& theBranch,
417 Selector& theSelector) const
419 // Try to reject the branch by bounding box
420 if (theSelector.Reject (theBranch.Bnd()))
423 Standard_Integer nSel = 0;
425 if (theBranch.IsLeaf()) {
426 // It is a leaf => try to accept the object
427 if (theSelector.Accept (theBranch.Object()))
431 // It is a branch => select from its children
432 nSel += Select (theBranch.Child(0), theSelector);
433 if (!theSelector.Stop())
434 nSel += Select (theBranch.Child(1), theSelector);
440 // ======================================================================
442 * Declaration of handled version of NCollection_UBTree.
443 * In the macros below the arguments are:
444 * _HUBTREE - the desired name of handled class
445 * _OBJTYPE - the name of the object type
446 * _BNDTYPE - the name of the bounding box type
447 * _HPARENT - the name of parent class (usually MMgt_TShared)
449 #define DEFINE_HUBTREE(_HUBTREE, _OBJTYPE, _BNDTYPE, _HPARENT) \
450 class _HUBTREE : public _HPARENT \
453 typedef NCollection_UBTree <_OBJTYPE, _BNDTYPE> UBTree; \
455 _HUBTREE () : myTree(new UBTree) {} \
456 /* Empty constructor */ \
457 _HUBTREE (const Handle_NCollection_BaseAllocator& theAlloc) \
458 : myTree(new UBTree(theAlloc)) {} \
461 /* Access to the methods of UBTree */ \
463 Standard_Boolean Add (const _OBJTYPE& theObj, \
464 const _BNDTYPE& theBnd) \
465 { return ChangeTree().Add (theObj, theBnd); } \
467 Standard_Integer Select (UBTree::Selector& theSelector) const \
468 { return Tree().Select (theSelector); } \
470 void Clear () { ChangeTree().Clear (); } \
472 Standard_Boolean IsEmpty () const { return Tree().IsEmpty(); } \
474 const UBTree::TreeNode& Root () const { return Tree().Root(); } \
477 /* Access to the tree algorithm */ \
479 const UBTree& Tree () const { return *myTree; } \
480 UBTree& ChangeTree () { return *myTree; } \
482 ~_HUBTREE () { delete myTree; } \
485 DEFINE_STANDARD_RTTI (_HUBTREE) \
486 /* Type management */ \
489 /* Copying and assignment are prohibited */ \
490 _HUBTREE (UBTree*); \
491 _HUBTREE (const _HUBTREE&); \
492 void operator = (const _HUBTREE&); \
495 UBTree *myTree; /* pointer to the tree algorithm */ \
497 DEFINE_STANDARD_HANDLE (_HUBTREE, _HPARENT)
499 #define IMPLEMENT_HUBTREE(_HUBTREE, _HPARENT) \
500 IMPLEMENT_STANDARD_HANDLE (_HUBTREE, _HPARENT) \
501 IMPLEMENT_STANDARD_RTTIEXT(_HUBTREE, _HPARENT)
504 #pragma warning (pop)