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