1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 /*!
34   \class SbOctTree SbOctTree.h Inventor/SbOctTree.h
35   \brief The SbOctTree class defines a generic oct tree for fast geometry searches.
36 
37   \ingroup base
38 
39   \COIN_CLASS_EXTENSION
40 */
41 
42 // *************************************************************************
43 
44 #include <cassert>
45 #include <cfloat>
46 #include <cstddef>
47 
48 #include <Inventor/SbOctTree.h>
49 #include <Inventor/SbSphere.h>
50 #include <Inventor/SbPlane.h>
51 #include <Inventor/errors/SoDebugError.h>
52 
53 // *************************************************************************
54 
55 /*!
56   \struct SbOctTreeFuncs SbOctTree.h Inventor/SbOctTree.h
57 
58   The SbOctTreeFuncs struct is used to specify callback functions for
59   working with items in an SbOctTree.
60 
61   The only function pointer that \e must be set up is \c
62   insideboxfunc. The other functions must be set if you intend to use
63   the corresponding find methods in SbOctTree.
64 */
65 
66 /*!
67   \var SbOctTreeFuncs::ptinsidefunc
68   Should return whether a point is inside item.
69 */
70 /*!
71   \var SbOctTreeFuncs::insideboxfunc
72   Should return whether item is either fully or partly inside a box.
73  */
74 /*!
75   \var SbOctTreeFuncs::insidespherefunc
76   Should return whether item is either fully or partly inside a
77   sphere.
78  */
79 /*!
80   \var SbOctTreeFuncs::insideplanesfunc
81   Should return whether item is either fully or partly inside a set of
82   planes.
83 */
84 
85 // *************************************************************************
86 
87 //
88 // got to have unique intersection funcs, therefore the standard
89 // Inventor intersection functions won't do. E.g. SbBox3f::pointInside()
90 // will return TRUE for all eight child-boxes if the center point of the
91 // parent box is tested, which is correct, but not really usable for an
92 // oct tree.
93 //
94 
95 static SbBool
intersect_box_sphere(const SbBox3f & box,const SbSphere & sphere)96 intersect_box_sphere(const SbBox3f & box,
97                      const SbSphere & sphere)
98 {
99   const SbVec3f &C = sphere.getCenter();
100   const SbVec3f &Bmin = box.getMin();
101   const SbVec3f &Bmax = box.getMax();
102   float dmin = 0;
103   for (int i = 0; i < 3; i++) {
104     if (C[i] < Bmin[i]) dmin += SbSqr(C[i] - Bmin[i]);
105     else if (C[i] > Bmax[i]) dmin += SbSqr(C[i] - Bmax[i]);
106   }
107   return (dmin <= SbSqr(sphere.getRadius()));
108 }
109 
110 static SbBool
intersect_box_box(const SbBox3f & box1,const SbBox3f & box2)111 intersect_box_box(const SbBox3f & box1, const SbBox3f & box2)
112 {
113   return ! (box1.getMin()[0] >= box2.getMax()[0] ||
114             box1.getMax()[0] < box2.getMin()[0] ||
115             box1.getMin()[1] >= box2.getMax()[1] ||
116             box1.getMax()[1] < box2.getMin()[1] ||
117             box1.getMin()[2] >= box2.getMax()[2] ||
118             box1.getMax()[2] < box2.getMin()[2]);
119 }
120 
121 static SbBool
point_inside_box(const SbVec3f & pt,const SbBox3f & box)122 point_inside_box(const SbVec3f & pt, const SbBox3f & box)
123 {
124   return ! (pt[0] < box.getMin()[0] ||
125             pt[0] >= box.getMax()[0] ||
126             pt[1] < box.getMin()[1] ||
127             pt[1] >= box.getMax()[1] ||
128             pt[2] < box.getMin()[2] ||
129             pt[2] >= box.getMax()[2]);
130 }
131 
132 static SbBool
box_inside_planes(const SbBox3f & box,const SbPlane * const planes,const int numplanes)133 box_inside_planes(const SbBox3f & box, const SbPlane * const planes,
134                   const int numplanes)
135 {
136   // Uses box "radius" for speed.
137   // FIXME: consider just checking all 8 points of the box. pederb, 20000811
138   SbVec3f size = (box.getMax() - box.getMin()) * 0.5f;
139   float radius = static_cast<float>(sqrt(size[0]*size[0] + size[1]*size[1] + size[2]*size[2]));
140 
141   SbVec3f center = (box.getMin() + box.getMax()) * 0.5f;
142 
143   for (int i = 0; i < numplanes; i++) {
144     if (planes[i].getDistance(center) < -radius) return FALSE;
145   }
146   return TRUE;
147 }
148 
149 // *************************************************************************
150 
151 class SbOctTreeNode
152 {
153 public:
154   SbOctTreeNode(const SbBox3f & b);
155   ~SbOctTreeNode();
156 
157   void addItem(void * const item,
158                const SbOctTreeFuncs & itemfuncs,
159                const int maxitems);
160   void removeItem(void * const item,
161                   const SbOctTreeFuncs & itemfuncs);
162   void findItems(const SbVec3f &pos,
163                  SbList <void*> &destarray,
164                  const SbOctTreeFuncs &itemfuncs,
165                  const SbBool removeduplicates) const;
166   void findItems(const SbBox3f &box,
167                  SbList <void*> &destarray,
168                  const SbOctTreeFuncs &itemfuncs,
169                  const SbBool removeduplicates) const;
170   void findItems(const SbSphere &sphere,
171                  SbList <void*> &destarray,
172                  const SbOctTreeFuncs &itemfuncs,
173                  const SbBool removeduplicates) const;
174   void findItems(const SbPlane * const planes,
175                  const int numPlanes,
176                  SbList <void*> &destarray,
177                  const SbOctTreeFuncs &itemfuncs,
178                  const SbBool removeduplicates) const;
179 
getBBox(void) const180   const SbBox3f & getBBox(void) const { return this->nodesize; }
181 
182   void debugTree(FILE *fp, const int indent) const;
183 
184 private:
isLeaf(void) const185   SbBool isLeaf(void) const { return this->children[0] == NULL; }
isGroup(void) const186   SbBool isGroup(void) const { return ! this->isLeaf(); }
187 
188   unsigned int totalNumberOfItems(void) const;
189 
190   static void split3Way(const SbBox3f & box, SbBox3f * destarray);
191   SbBool splitNode(const SbOctTreeFuncs & funcs);
192 
193   SbOctTreeNode * children[8];
194   SbList <void*> items;
195   SbBox3f nodesize;
196 };
197 
198 // Returns all items of the node, including all items in child nodes
199 // if we're not a leaf node.
200 unsigned int
totalNumberOfItems(void) const201 SbOctTreeNode::totalNumberOfItems(void) const
202 {
203   unsigned int nr = this->items.getLength();
204 
205   if (this->isGroup()) {
206     for (int i = 0; i < 8; i++) {
207       nr += this->children[i]->totalNumberOfItems();
208     }
209   }
210   return nr;
211 }
212 
213 void
debugTree(FILE * fp,const int indent) const214 SbOctTreeNode::debugTree(FILE *fp, const int indent) const
215 {
216   (void)fprintf(fp, "%02d", indent - 1);
217 
218   int i;
219   for (i = 0; i < indent; i++) { (void)fprintf(fp, "  "); }
220 
221   const SbVec3f & vmin = this->nodesize.getMin();
222   const SbVec3f & vmax = this->nodesize.getMax();
223 
224   (void)fprintf(fp, "%s, %u items, ",
225                 this->isLeaf() ? "Leaf" : "Group", this->totalNumberOfItems());
226   (void)fprintf(fp, "box==<%.2f, %.2f, %.2f>-<%.2f, %.2f, %.2f>",
227                 vmin[0], vmin[1], vmin[2], vmax[0], vmax[1], vmax[2]);
228   (void)fprintf(fp, "\n");
229 
230   if (this->isGroup()) {
231     for (i = 0; i < 8; i++) {
232       this->children[i]->debugTree(fp, indent+1);
233     }
234   }
235 }
236 
237 static void
add_to_array(SbList<void * > & array,void * ptr)238 add_to_array(SbList<void *> & array, void * ptr)
239 {
240   // FIXME: this is rather awful, resulting in n^2 algorithm time.
241   // Should change to using the array as a sorted set. 20050512 mortene.
242   if (array.find(ptr) == -1) { array.append(ptr); }
243 }
244 
SbOctTreeNode(const SbBox3f & b)245 SbOctTreeNode::SbOctTreeNode(const SbBox3f & b)
246 {
247   for (int i = 0; i < 8; i++) {
248     this->children[i] = NULL;
249   }
250   this->nodesize = b;
251 }
252 
~SbOctTreeNode()253 SbOctTreeNode::~SbOctTreeNode()
254 {
255   if (this->isGroup()) {
256     for (int i = 0; i < 8; i++) delete children[i];
257   }
258 }
259 
260 void
addItem(void * const item,const SbOctTreeFuncs & itemfuncs,const int maxitems)261 SbOctTreeNode::addItem(void * const item,
262                        const SbOctTreeFuncs & itemfuncs,
263                        const int maxitems)
264 {
265   if (this->isGroup()) { // node has been split
266     for (int i = 0; i < 8; i++) {
267       if (itemfuncs.insideboxfunc(item, this->children[i]->nodesize)) {
268         this->children[i]->addItem(item, itemfuncs, maxitems);
269       }
270     }
271   }
272   else if (this->items.getLength() >= maxitems) {
273     // avoid trying a split too often by using a modulo
274     if ((this->items.getLength() % (maxitems+1) == maxitems) &&
275         this->splitNode(itemfuncs)) {
276       this->addItem(item, itemfuncs, maxitems);
277     }
278     else {
279       this->items.append(item);
280     }
281   }
282   else {
283     this->items.append(item);
284   }
285 }
286 
287 void
removeItem(void * const item,const SbOctTreeFuncs & itemfuncs)288 SbOctTreeNode::removeItem(void * const item, const SbOctTreeFuncs & itemfuncs)
289 {
290   if (children[0]) {
291     for (int i = 0; i < 8; i++) {
292       if (itemfuncs.insideboxfunc(item, this->children[i]->nodesize)) {
293         this->children[i]->removeItem(item, itemfuncs);
294       }
295     }
296   }
297   else {
298     int n = this->items.getLength();
299     for (int i = 0; i < n; i++) {
300       if (this->items[i] == item) {
301         this->items.removeFast(i);
302         n--;
303       }
304     }
305   }
306 }
307 
308 void
findItems(const SbVec3f & pos,SbList<void * > & destarray,const SbOctTreeFuncs & itemfuncs,const SbBool removeduplicates) const309 SbOctTreeNode::findItems(const SbVec3f & pos,
310                          SbList <void*> & destarray,
311                          const SbOctTreeFuncs & itemfuncs,
312                          const SbBool removeduplicates) const
313 {
314   if (this->isGroup()) {
315     for (int i = 0; i < 8; i++) {
316       if (point_inside_box(pos, this->children[i]->nodesize)) {
317         this->children[i]->findItems(pos, destarray,
318                                      itemfuncs, removeduplicates);
319       }
320     }
321   }
322   else {
323     int n = this->items.getLength();
324     for (int i = 0; i < n; i++) {
325       void *item = this->items[i];
326       if (itemfuncs.ptinsidefunc(item, pos)) {
327         if (removeduplicates)
328           add_to_array(destarray, item);
329         else
330           destarray.append(item);
331       }
332     }
333   }
334 }
335 
336 void
findItems(const SbBox3f & box,SbList<void * > & destarray,const SbOctTreeFuncs & itemfuncs,const SbBool removeduplicates) const337 SbOctTreeNode::findItems(const SbBox3f & box,
338                          SbList <void*> & destarray,
339                          const SbOctTreeFuncs & itemfuncs,
340                          const SbBool removeduplicates) const
341 {
342   if (this->isGroup()) {
343     for (int i = 0; i < 8; i++) {
344       if (intersect_box_box(box, this->children[i]->nodesize))
345         this->children[i]->findItems(box, destarray,
346                                      itemfuncs, removeduplicates);
347     }
348   }
349   else {
350     int n = this->items.getLength();
351     for (int i = 0; i < n; i++) {
352       void *item = this->items[i];
353       if (itemfuncs.insideboxfunc(item, box)) {
354         if (removeduplicates)
355           add_to_array(destarray, item);
356         else
357           destarray.append(item);
358       }
359     }
360   }
361 }
362 
363 void
findItems(const SbSphere & sphere,SbList<void * > & destarray,const SbOctTreeFuncs & itemfuncs,const SbBool removeduplicates) const364 SbOctTreeNode::findItems(const SbSphere & sphere,
365                          SbList <void*> & destarray,
366                          const SbOctTreeFuncs & itemfuncs,
367                          const SbBool removeduplicates) const
368 {
369   if (this->isGroup()) {
370     for (int i = 0; i < 8; i++) {
371       if (intersect_box_sphere(this->children[i]->nodesize, sphere))
372         this->children[i]->findItems(sphere, destarray,
373                                      itemfuncs, removeduplicates);
374     }
375   }
376   else {
377     int n = this->items.getLength();
378     for (int i = 0; i < n; i++) {
379       void * item = this->items[i];
380       if (itemfuncs.insidespherefunc(item, sphere)) {
381         if (removeduplicates)
382           add_to_array(destarray, item);
383         else
384           destarray.append(item);
385       }
386     }
387   }
388 }
389 
390 void
findItems(const SbPlane * const planes,const int numplanes,SbList<void * > & destarray,const SbOctTreeFuncs & itemfuncs,const SbBool removeduplicates) const391 SbOctTreeNode::findItems(const SbPlane * const planes,
392                          const int numplanes,
393                          SbList <void*> & destarray,
394                          const SbOctTreeFuncs & itemfuncs,
395                          const SbBool removeduplicates) const
396 {
397   if (this->isGroup()) {
398     for (int i = 0; i < 8; i++) {
399       if (box_inside_planes(this->children[i]->nodesize, planes, numplanes)) {
400         this->children[i]->findItems(planes, numplanes,
401                                      destarray, itemfuncs, removeduplicates);
402       }
403     }
404   }
405   else {
406     int n = this->items.getLength();
407     for (int i = 0; i < n; i++) {
408       void *item = this->items[i];
409       if (itemfuncs.insideplanesfunc(item, planes, numplanes)) {
410         if (removeduplicates)
411           add_to_array(destarray, item);
412         else
413           destarray.append(item);
414       }
415     }
416   }
417 }
418 
419 void
split3Way(const SbBox3f & box,SbBox3f * dest)420 SbOctTreeNode::split3Way(const SbBox3f & box, SbBox3f * dest)
421 {
422   SbVec3f mid = (box.getMin() + box.getMax()) * 0.5f;
423 
424   for (int i = 0; i < 8; i++) {
425     dest[i].setBounds((i & 4) ? box.getMin()[0] : mid[0],
426                       (i & 2) ? box.getMin()[1] : mid[1],
427                       (i & 1) ? box.getMin()[2] : mid[2],
428                       (i & 4) ? mid[0] : box.getMax()[0],
429                       (i & 2) ? mid[1] : box.getMax()[1],
430                       (i & 1) ? mid[2] : box.getMax()[2]);
431   }
432 }
433 
434 SbBool
splitNode(const SbOctTreeFuncs & itemfuncs)435 SbOctTreeNode::splitNode(const SbOctTreeFuncs & itemfuncs)
436 {
437   SbBox3f childbox[8];
438   SbOctTreeNode::split3Way(this->nodesize, childbox);
439   int i;
440   for (i = 0; i < 8; i++) {
441     this->children[i] = new SbOctTreeNode(childbox[i]);
442   }
443 
444   const int n = this->items.getLength();
445   for (i = 0; i < n; i++) {
446     void *item = this->items[i];
447     for (int j = 0; j < 8; j++) {
448       if (itemfuncs.insideboxfunc(item, childbox[j])) {
449         this->children[j]->items.append(item);
450       }
451     }
452   }
453 
454   // Check to see if one or more of the new nodes contains *all* items
455   // from the parent node (i.e. this node). If so, the split won't
456   // gain us any in processing time (it will likely be hurtful), so
457   // decide against splitting.
458 
459   for (i = 0; i < 8; i++) {
460     if (this->children[i]->items.getLength() == n) {
461       for (int j = 0; j < 8; j++) {
462         delete this->children[j];
463         this->children[j] = NULL;
464       }
465       return FALSE;
466     }
467   }
468 
469   // Box was indeed split, we're now a group node, so truncate our
470   // list of items and carry on with new tree structure.
471 
472   this->items.truncate(0, TRUE);
473   return TRUE;
474 }
475 
476 // *************************************************************************
477 
478 /*!
479   Constructor.
480 */
SbOctTree(const SbBox3f & bbox,const SbOctTreeFuncs & itemfuncs,const int maxitems)481 SbOctTree::SbOctTree(const SbBox3f & bbox,
482                      const SbOctTreeFuncs & itemfuncs,
483                      const int maxitems)
484   : topnode(new SbOctTreeNode(bbox)),
485     itemfuncs(itemfuncs),
486     maxitemspernode(maxitems)
487 {
488 }
489 
490 /*!
491   Destructor.
492 */
~SbOctTree()493 SbOctTree::~SbOctTree()
494 {
495   delete this->topnode;
496 }
497 
498 /*!
499   Restores this oct tree to an empty oct tree. The bounding
500   box will still be the same though.
501 */
502 void
clear(void)503 SbOctTree::clear(void)
504 {
505   SbBox3f bbox = this->topnode->getBBox();
506   delete this->topnode;
507   this->topnode = new SbOctTreeNode(bbox);
508 }
509 
510 /*!
511   Adds an item to this oct tree.
512 */
513 void
addItem(void * const item)514 SbOctTree::addItem(void * const item)
515 {
516   // Note that the assert() below can hit due to floating point
517   // inaccuracies.
518   //
519   // When that happens, an easy and fairly decent fix is usually to
520   // add a bit of slack on the caller side to the input bbox argument
521   // to SbOctTree::SbOctTree().
522 
523   // FIXME: a better solution would be to not force an static bbox
524   // upon the SbOctTree through its constructor, but let it
525   // dynamically expand / re-structure itself as items are added.
526   //
527   // An easy, but a bit inefficient, way to do that would be to simply
528   // store a copy of all items in the octtree structure, destruct it,
529   // restore a new top-level node, and then re-add all items to let a
530   // new octtree structure build itself.
531   //
532   // 20050512 mortene.
533 #if COIN_DEBUG && 0 // debug
534   const SbBox3f & b = this->topnode->getBBox();
535   if (!this->itemfuncs.insideboxfunc(item, b)) {
536     const SbVec3f & bmin = b.getMin();
537     const SbVec3f & bmax = b.getMax();
538     SoDebugError::post("SbOctTree::addItem",
539                        "tree bbox==<%f, %f, %f>, <%f, %f, %f>",
540                        bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2]);
541   }
542 #endif // debug
543   assert(this->itemfuncs.insideboxfunc(item, this->topnode->getBBox()) &&
544          "bbox of item outside the octtree top-level bbox");
545 
546   this->topnode->addItem(item, this->itemfuncs, this->maxitemspernode);
547 }
548 
549 /*!
550   Removes the item from the octtree. The octtree will not be
551   modified/simplified even when all items are removed.
552 */
553 void
removeItem(void * const item)554 SbOctTree::removeItem(void * const item)
555 {
556   this->topnode->removeItem(item, this->itemfuncs);
557 }
558 
559 /*!
560   Finds all items which contains the point \a pos. Items are
561   returned in \a destarray.
562 
563   If \a removeduplicates is TRUE (the default), \a destarray will not
564   contain duplicate items. This is not an optimized process, so if
565   you're looking for speed you should set this to FALSE and do
566   your own postprocessing of the array of returned items.
567 
568   \DANGEROUS_ALLOC_RETURN
569 */
570 void
findItems(const SbVec3f & pos,SbList<void * > & destarray,const SbBool removeduplicates) const571 SbOctTree::findItems(const SbVec3f & pos,
572                      SbList <void*> & destarray,
573                      const SbBool removeduplicates) const
574 {
575   // FIXME: passing in an SbList is dangerous under MS Windows, as
576   // allocation and deallocation can then happen on different
577   // C-library's heaps. The other findItems() functions below have the
578   // same problem. 20050512 mortene.
579 
580   // FIXME: should be straightforward to drop the removeduplicates
581   // argument -- it's a hack. We just need to optimize the
582   // add_to_array() function above to keep a _sorted_ array.
583   //
584   // This also goes for the other findItems() functions below, of
585   // course.
586   //
587   // 20050512 mortene.
588 
589   assert(this->itemfuncs.ptinsidefunc);
590   topnode->findItems(pos, destarray, this->itemfuncs, removeduplicates);
591 }
592 
593 /*!
594   Finds all items inside \a box. Items are returned in \a destarray.
595 
596   If \a removeduplicates is TRUE (the default), \a destarray will not
597   contain duplicate items. This is not an optimized process, so if
598   you're looking for speed you should set this to FALSE and do
599   your own postprocessing of the array of returned items.
600 
601   \DANGEROUS_ALLOC_RETURN
602 */
603 void
findItems(const SbBox3f & box,SbList<void * > & destarray,const SbBool removeduplicates) const604 SbOctTree::findItems(const SbBox3f & box, SbList <void*> & destarray,
605                      const SbBool removeduplicates) const
606 {
607   assert(this->itemfuncs.insideboxfunc);
608   this->topnode->findItems(box, destarray, this->itemfuncs, removeduplicates);
609 }
610 
611 /*!
612   Finds all items inside \a sphere. Items are returned in \a destarray.
613 
614   If \a removeduplicates is TRUE (the default), \a destarray will not
615   contain duplicate items. This is not an optimized process, so if
616   you're looking for speed you should set this to FALSE and do
617   your own postprocessing of the array of returned items.
618 
619   \DANGEROUS_ALLOC_RETURN
620 */
621 void
findItems(const SbSphere & sphere,SbList<void * > & destarray,const SbBool removeduplicates) const622 SbOctTree::findItems(const SbSphere & sphere,
623                      SbList <void*> & destarray,
624                      const SbBool removeduplicates) const
625 {
626   assert(this->itemfuncs.insidespherefunc);
627   this->topnode->findItems(sphere, destarray, this->itemfuncs, removeduplicates);
628 }
629 
630 /*!
631   Finds all items inside \a planes. The method
632   SbPlane::isInHalfSpace() should be used, and only items which are
633   (partly) inside \e all planes are returned. Items are returned in \a
634   destarray.
635 
636   If \a removeduplicates is TRUE (the default), \a destarray will not
637   contain duplicate items. This is not an optimized process, so if
638   you're looking for speed you should set this to FALSE and do
639   your own postprocessing of the array of returned items.
640 
641   \DANGEROUS_ALLOC_RETURN
642 */
643 void
findItems(const SbPlane * const planes,const int numplanes,SbList<void * > & destarray,const SbBool removeduplicates) const644 SbOctTree::findItems(const SbPlane * const planes,
645                      const int numplanes,
646                      SbList <void*> & destarray,
647                      const SbBool removeduplicates) const
648 {
649   assert(this->itemfuncs.insideplanesfunc);
650   this->topnode->findItems(planes, numplanes, destarray, this->itemfuncs,
651                            removeduplicates);
652 }
653 
654 /*!
655   Returns a bounding box enclosing all the elements in the tree.
656   This is just the same bounding box which was supplied to the
657   constructor.
658 */
659 const SbBox3f &
getBoundingBox(void) const660 SbOctTree::getBoundingBox(void) const
661 {
662   return this->topnode->getBBox();
663 }
664 
665 void
debugTree(FILE * fp)666 SbOctTree::debugTree(FILE * fp)
667 {
668   fprintf(fp, "Oct Tree:\n");
669   if (this->topnode) { this->topnode->debugTree(fp, 1); }
670 }
671