aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llmath/lloctree.h
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmath/lloctree.h
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r--linden/indra/llmath/lloctree.h712
1 files changed, 712 insertions, 0 deletions
diff --git a/linden/indra/llmath/lloctree.h b/linden/indra/llmath/lloctree.h
new file mode 100644
index 0000000..6e068cd
--- /dev/null
+++ b/linden/indra/llmath/lloctree.h
@@ -0,0 +1,712 @@
1/**
2 * @file lloctree.h
3 * @brief Octree declaration.
4 *
5 * Copyright (c) 2005-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLOCTREE_H
29#define LL_LLOCTREE_H
30
31#include "lltreenode.h"
32#include "v3math.h"
33#include <vector>
34#include <set>
35
36#ifdef LL_RELEASE_FOR_DOWNLOAD
37#define OCT_ERRS llwarns
38#else
39#define OCT_ERRS llerrs
40#endif
41
42#define LL_OCTREE_PARANOIA_CHECK 0
43
44template <class T> class LLOctreeState;
45template <class T> class LLOctreeNode;
46
47template <class T>
48class LLOctreeListener: public LLTreeListener<T>
49{
50public:
51 typedef LLTreeListener<T> BaseType;
52 typedef LLOctreeNode<T> oct_node;
53
54 virtual ~LLOctreeListener() { };
55 virtual void handleChildAddition(const oct_node* parent, oct_node* child) = 0;
56 virtual void handleChildRemoval(const oct_node* parent, const oct_node* child) = 0;
57};
58
59
60template <class T>
61class LLOctreeNode : public LLTreeNode<T>
62{
63public:
64
65 typedef LLTreeNode<T> BaseType;
66 typedef LLTreeState<T> tree_state;
67 typedef LLOctreeState<T> oct_state;
68 typedef LLOctreeNode<T> oct_node;
69 typedef LLOctreeListener<T> oct_listener;
70
71 static const U8 OCTANT_POSITIVE_X = 0x01;
72 static const U8 OCTANT_POSITIVE_Y = 0x02;
73 static const U8 OCTANT_POSITIVE_Z = 0x04;
74
75 LLOctreeNode( LLVector3d center,
76 LLVector3d size,
77 tree_state* state,
78 BaseType* parent,
79 U8 octant = 255)
80 : BaseType(state),
81 mParent((oct_node*)parent),
82 mCenter(center),
83 mSize(size),
84 mOctant(octant)
85 {
86 updateMinMax();
87 if ((mOctant == 255) && mParent)
88 {
89 mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV);
90 }
91 }
92
93 virtual ~LLOctreeNode() { BaseType::destroyListeners(); delete this->mState; }
94
95 virtual const BaseType* getParent() const { return mParent; }
96 virtual void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
97 virtual const LLVector3d& getCenter() const { return mCenter; }
98 virtual const LLVector3d& getSize() const { return mSize; }
99 virtual void setCenter(LLVector3d center) { mCenter = center; }
100 virtual void setSize(LLVector3d size) { mSize = size; }
101 virtual bool balance() { return getOctState()->balance(); }
102 virtual void validate() { getOctState()->validate(); }
103 virtual U32 getChildCount() const { return getOctState()->getChildCount(); }
104 virtual oct_node* getChild(U32 index) { return getOctState()->getChild(index); }
105 virtual const oct_node* getChild(U32 index) const { return getOctState()->getChild(index); }
106 virtual U32 getElementCount() const { return getOctState()->getElementCount(); }
107 virtual void removeByAddress(T* data) { getOctState()->removeByAddress(data); }
108 virtual bool hasLeafState() const { return getOctState()->isLeaf(); }
109 virtual void destroy() { getOctState()->destroy(); }
110 virtual oct_node* getNodeAt(T* data) { return getOctState()->getNodeAt(data); }
111 virtual U8 getOctant() const { return mOctant; }
112 virtual void setOctant(U8 octant) { mOctant = octant; }
113 virtual const oct_state* getOctState() const { return (const oct_state*) BaseType::mState; }
114 virtual oct_state* getOctState() { return (oct_state*) BaseType::mState; }
115 virtual const oct_node* getOctParent() const { return (const oct_node*) getParent(); }
116 virtual oct_node* getOctParent() { return (oct_node*) getParent(); }
117 virtual void deleteChild(oct_node* child) { getOctState()->deleteChild(child); }
118
119 virtual U8 getOctant(const F64 pos[]) const //get the octant pos is in
120 {
121 U8 ret = 0;
122
123 if (pos[0] > mCenter.mdV[0])
124 {
125 ret |= OCTANT_POSITIVE_X;
126 }
127 if (pos[1] > mCenter.mdV[1])
128 {
129 ret |= OCTANT_POSITIVE_Y;
130 }
131 if (pos[2] > mCenter.mdV[2])
132 {
133 ret |= OCTANT_POSITIVE_Z;
134 }
135
136 return ret;
137 }
138
139 virtual bool isInside(T* data) const
140 {
141 return data->getBinRadius() <= mSize.mdV[0]*2.0 && isInside(data->getPositionGroup());
142 }
143
144 virtual bool isInside(const LLVector3d& pos) const
145 {
146 const F64& x = pos.mdV[0];
147 const F64& y = pos.mdV[1];
148 const F64& z = pos.mdV[2];
149
150 if (x > mMax.mdV[0] || x <= mMin.mdV[0] ||
151 y > mMax.mdV[1] || y <= mMin.mdV[1] ||
152 z > mMax.mdV[2] || z <= mMin.mdV[2])
153 {
154 return false;
155 }
156
157 return true;
158 }
159
160 virtual void updateMinMax()
161 {
162 for (U32 i = 0; i < 3; i++)
163 {
164 mMax.mdV[i] = mCenter.mdV[i] + mSize.mdV[i];
165 mMin.mdV[i] = mCenter.mdV[i] - mSize.mdV[i];
166 mCenter.mdV[i] = mCenter.mdV[i];
167 }
168 }
169
170 virtual oct_listener* getOctListener(U32 index)
171 {
172 return (oct_listener*) BaseType::getListener(index);
173 }
174
175 bool contains(T* xform)
176 {
177 if (mParent == NULL)
178 { //root node contains nothing
179 return false;
180 }
181
182 F64 size = mSize.mdV[0];
183 F64 p_size = size * 2.0;
184 F64 radius = xform->getBinRadius();
185
186 return (radius <= 0.001 && size <= 0.001) ||
187 (radius <= p_size && radius > size);
188 }
189
190 static void pushCenter(LLVector3d &center, LLVector3d &size, T* data)
191 {
192 LLVector3 pos(data->getPositionGroup());
193 F64 p[] =
194 {
195 (F64) pos.mV[0],
196 (F64) pos.mV[1],
197 (F64) pos.mV[2]
198 };
199
200 for (U32 i = 0; i < 3; i++)
201 {
202 if (p[i] > center.mdV[i])
203 {
204 center.mdV[i] += size.mdV[i];
205 }
206 else
207 {
208 center.mdV[i] -= size.mdV[i];
209 }
210 }
211 }
212
213protected:
214 oct_node* mParent;
215 LLVector3d mCenter;
216 LLVector3d mSize;
217 LLVector3d mMax;
218 LLVector3d mMin;
219 U8 mOctant;
220};
221
222template <class T>
223class LLOctreeTraveler : public LLTreeTraveler<T>
224{
225public:
226 virtual void traverse(const LLTreeNode<T>* node);
227 virtual void visit(const LLTreeState<T>* state) { }
228 virtual void visit(const LLOctreeState<T>* branch) = 0;
229};
230
231//will pass requests to a child, might make a new child
232template <class T>
233class LLOctreeState : public LLTreeState<T>
234{
235public:
236 typedef LLTreeState<T> BaseType;
237 typedef LLOctreeTraveler<T> oct_traveler;
238 typedef LLOctreeNode<T> oct_node;
239 typedef LLOctreeListener<T> oct_listener;
240 typedef LLTreeTraveler<T> tree_traveler;
241 typedef typename std::set<LLPointer<T> > element_list;
242 typedef typename std::set<LLPointer<T> >::iterator element_iter;
243 typedef typename std::set<LLPointer<T> >::const_iterator const_element_iter;
244 typedef typename std::vector<LLTreeListener<T>*>::iterator tree_listener_iter;
245 typedef typename std::vector<LLOctreeNode<T>* > child_list;
246
247 LLOctreeState(oct_node* node = NULL): BaseType(node) { this->clearChildren(); }
248 virtual ~LLOctreeState()
249 {
250 for (U32 i = 0; i < getChildCount(); i++)
251 {
252 delete getChild(i);
253 }
254 }
255
256
257 virtual void accept(oct_traveler* visitor) { visitor->visit(this); }
258 virtual bool isLeaf() const { return mChild.empty(); }
259
260 virtual U32 getElementCount() const { return mData.size(); }
261 virtual element_list& getData() { return mData; }
262 virtual const element_list& getData() const { return mData; }
263
264 virtual U32 getChildCount() const { return mChild.size(); }
265 virtual oct_node* getChild(U32 index) { return mChild[index]; }
266 virtual const oct_node* getChild(U32 index) const { return mChild[index]; }
267 virtual child_list& getChildren() { return mChild; }
268 virtual const child_list& getChildren() const { return mChild; }
269
270 virtual void accept(tree_traveler* visitor) const { visitor->visit(this); }
271 virtual void accept(oct_traveler* visitor) const { visitor->visit(this); }
272 const oct_node* getOctNode() const { return (const oct_node*) BaseType::getNode(); }
273 oct_node* getOctNode() { return (oct_node*) BaseType::getNode(); }
274
275 virtual oct_node* getNodeAt(T* data)
276 {
277 const LLVector3d& pos = data->getPositionGroup();
278 LLOctreeNode<T>* node = getOctNode();
279
280 if (node->isInside(data))
281 {
282 //do a quick search by octant
283 U8 octant = node->getOctant(pos.mdV);
284 BOOL keep_going = TRUE;
285
286 //traverse the tree until we find a node that has no node
287 //at the appropriate octant or is smaller than the object.
288 //by definition, that node is the smallest node that contains
289 // the data
290 while (keep_going && node->getSize().mdV[0] >= data->getBinRadius())
291 {
292 keep_going = FALSE;
293 for (U32 i = 0; i < node->getChildCount() && !keep_going; i++)
294 {
295 if (node->getChild(i)->getOctant() == octant)
296 {
297 node = node->getChild(i);
298 octant = node->getOctant(pos.mdV);
299 keep_going = TRUE;
300 }
301 }
302 }
303 }
304 else if (!node->contains(data) && node->getParent())
305 { //if we got here, data does not exist in this node
306 return ((LLOctreeNode<T>*) node->getParent())->getNodeAt(data);
307 }
308
309 return node;
310 }
311
312 virtual bool insert(T* data)
313 {
314 if (data == NULL)
315 {
316 OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
317 return false;
318 }
319 LLOctreeNode<T>* node = getOctNode();
320
321 if (data->getBinRadius() <= node->getSize().mdV[0])
322 {
323 oct_node* dest = getNodeAt(data);
324
325 if (dest != node)
326 {
327 dest->insert(data);
328 return false;
329 }
330 }
331
332 //no kid found, is it even here?
333 if (node->isInside(data))
334 {
335 if (node->contains(data))
336 { //it belongs here
337 if (data == NULL)
338 {
339 OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE LEAF !!!" << llendl;
340 return false;
341 }
342
343#if LL_OCTREE_PARANOIA_CHECK
344 //if this is a redundant insertion, error out (should never happen)
345 if (mData.find(data) != mData.end())
346 {
347 llwarns << "Redundant octree insertion detected. " << data << llendl;
348 return false;
349 }
350#endif
351
352 mData.insert(data);
353 return true;
354 }
355 else
356 {
357 //it's here, but no kids are in the right place, make a new kid
358 LLVector3d center(node->getCenter());
359 LLVector3d size(node->getSize()*0.5);
360
361 //push center in direction of data
362 LLOctreeNode<T>::pushCenter(center, size, data);
363
364#if LL_OCTREE_PARANOIA_CHECK
365 if (getChildCount() == 8)
366 {
367 //this really isn't possible, something bad has happened
368 OCT_ERRS << "Octree detected floating point error and gave up." << llendl;
369 //bool check = node->isInside(data);
370 return false;
371 }
372
373 //make sure no existing node matches this position
374 for (U32 i = 0; i < getChildCount(); i++)
375 {
376 if (mChild[i]->getCenter() == center)
377 {
378 OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl;
379 //bool check = node->isInside(data);
380 //check = getChild(i)->isInside(data);
381 return false;
382 }
383 }
384#endif
385
386 //make the new kid
387 LLOctreeState<T>* newstate = new LLOctreeState<T>();
388 oct_node* child = new LLOctreeNode<T>(center, size, newstate, node);
389 addChild(child);
390
391 child->insert(data);
392 }
393 }
394 else
395 {
396 //it's not in here, give it to the parent
397 node->getOctParent()->insert(data);
398 }
399
400 return false;
401 }
402
403 virtual bool remove(T* data)
404 {
405 oct_node* node = getOctNode();
406
407 if (mData.find(data) != mData.end())
408 { //we have data
409 mData.erase(data);
410 node->notifyRemoval(data);
411 checkAlive();
412 return true;
413 }
414 else if (node->isInside(data))
415 {
416 oct_node* dest = getNodeAt(data);
417
418 if (dest != node)
419 {
420 return dest->remove(data);
421 }
422 }
423
424 //SHE'S GONE MISSING...
425 //none of the children have it, let's just brute force this bastard out
426 //starting with the root node (UGLY CODE COMETH!)
427 oct_node* parent = node->getOctParent();
428 while (parent != NULL)
429 {
430 node = parent;
431 parent = node->getOctParent();
432 }
433
434 //node is now root
435 llwarns << "!!! OCTREE REMOVING FACE BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << llendl;
436 node->removeByAddress(data);
437 return true;
438 }
439
440 virtual void removeByAddress(T* data)
441 {
442 if (mData.find(data) != mData.end())
443 {
444 mData.erase(data);
445 getOctNode()->notifyRemoval(data);
446 llwarns << "FOUND!" << llendl;
447 checkAlive();
448 return;
449 }
450
451 for (U32 i = 0; i < getChildCount(); i++)
452 { //we don't contain data, so pass this guy down
453 LLOctreeNode<T>* child = (LLOctreeNode<T>*) getChild(i);
454 child->removeByAddress(data);
455 }
456 }
457
458 virtual void clearChildren()
459 {
460 mChild.clear();
461 }
462
463 virtual void validate()
464 {
465#if LL_OCTREE_PARANOIA_CHECK
466 LLOctreeNode<T>* node = this->getOctNode();
467
468 for (U32 i = 0; i < getChildCount(); i++)
469 {
470 mChild[i]->validate();
471 if (mChild[i]->getParent() != node)
472 {
473 llerrs << "Octree child has invalid parent." << llendl;
474 }
475 }
476#endif
477 }
478
479 virtual bool balance()
480 {
481 return false;
482 }
483
484 virtual void destroy()
485 {
486 for (U32 i = 0; i < getChildCount(); i++)
487 {
488 mChild[i]->destroy();
489 delete mChild[i];
490 }
491 }
492
493 virtual void addChild(oct_node* child, BOOL silent = FALSE)
494 {
495#if LL_OCTREE_PARANOIA_CHECK
496 for (U32 i = 0; i < getChildCount(); i++)
497 {
498 if(mChild[i]->getSize() != child->getSize())
499 {
500 OCT_ERRS <<"Invalid octree child size." << llendl;
501 }
502 if (mChild[i]->getCenter() == child->getCenter())
503 {
504 OCT_ERRS <<"Duplicate octree child position." << llendl;
505 }
506 }
507
508 if (mChild.size() >= 8)
509 {
510 OCT_ERRS <<"Octree node has too many children... why?" << llendl;
511 }
512#endif
513
514 mChild.push_back(child);
515 child->setParent(getOctNode());
516
517 if (!silent)
518 {
519 oct_node* node = getOctNode();
520
521 for (U32 i = 0; i < node->getListenerCount(); i++)
522 {
523 oct_listener* listener = node->getOctListener(i);
524 listener->handleChildAddition(node, child);
525 }
526 }
527 }
528
529 virtual void removeChild(U8 index, BOOL destroy = FALSE)
530 {
531 oct_node* node = getOctNode();
532 for (U32 i = 0; i < node->getListenerCount(); i++)
533 {
534 oct_listener* listener = node->getOctListener(i);
535 listener->handleChildRemoval(node, getChild(index));
536 }
537
538 if (destroy)
539 {
540 mChild[index]->destroy();
541 delete mChild[index];
542 }
543 mChild.erase(mChild.begin() + index);
544
545 checkAlive();
546 }
547
548 virtual void checkAlive()
549 {
550 if (getChildCount() == 0 && getElementCount() == 0)
551 {
552 oct_node* node = getOctNode();
553 oct_node* parent = node->getOctParent();
554 if (parent)
555 {
556 parent->deleteChild(node);
557 }
558 }
559 }
560
561 virtual void deleteChild(oct_node* node)
562 {
563 for (U32 i = 0; i < getChildCount(); i++)
564 {
565 if (getChild(i) == node)
566 {
567 removeChild(i, TRUE);
568 return;
569 }
570 }
571
572 OCT_ERRS << "Octree failed to delete requested child." << llendl;
573 }
574
575protected:
576 child_list mChild;
577 element_list mData;
578};
579
580//just like a branch, except it might expand the node it points to
581template <class T>
582class LLOctreeRoot : public LLOctreeState<T>
583{
584public:
585 typedef LLOctreeState<T> BaseType;
586 typedef LLOctreeNode<T> oct_node;
587
588 LLOctreeRoot(oct_node* node = NULL) : BaseType(node) { }
589
590 oct_node* getOctNode() { return BaseType::getOctNode(); }
591 virtual bool isLeaf() { return false; }
592
593 virtual bool balance()
594 {
595 //the cached node might be invalid, so don't reference it
596 if (this->getChildCount() == 1 &&
597 !(this->mChild[0]->hasLeafState()) &&
598 this->mChild[0]->getElementCount() == 0)
599 { //if we have only one child and that child is an empty branch, make that child the root
600 BaseType* state = this->mChild[0]->getOctState();
601 oct_node* child = this->mChild[0];
602 oct_node* root = getOctNode();
603
604 //make the root node look like the child
605 root->setCenter(this->mChild[0]->getCenter());
606 root->setSize(this->mChild[0]->getSize());
607 root->updateMinMax();
608
609 //reset root node child list
610 this->clearChildren();
611
612 //copy the child's children into the root node silently
613 //(don't notify listeners of addition)
614 for (U32 i = 0; i < state->getChildCount(); i++)
615 {
616 addChild(state->getChild(i), TRUE);
617 }
618
619 //destroy child
620 state->clearChildren();
621 delete child;
622 }
623
624 return true;
625 }
626
627 // LLOctreeRoot::insert
628 virtual bool insert(T* data)
629 {
630 if (data == NULL)
631 {
632 OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
633 return false;
634 }
635
636 if (data->getBinRadius() > 4096.0)
637 {
638 OCT_ERRS << "!!! ELEMENT EXCEDES MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
639 }
640
641 LLOctreeNode<T>* node = getOctNode();
642 if (node->getSize().mdV[0] > data->getBinRadius() && node->isInside(data->getPositionGroup()))
643 {
644 //we got it, just act like a branch
645 LLOctreeState<T>::insert(data);
646 }
647 else if (this->getChildCount() == 0)
648 {
649 //first object being added, just wrap it up
650 while (!(node->getSize().mdV[0] > data->getBinRadius() && node->isInside(data->getPositionGroup())))
651 {
652 LLVector3d center, size;
653 center = node->getCenter();
654 size = node->getSize();
655 LLOctreeNode<T>::pushCenter(center, size, data);
656 node->setCenter(center);
657 node->setSize(size*2);
658 node->updateMinMax();
659 }
660 LLOctreeState<T>::insert(data);
661 }
662 else
663 {
664 //the data is outside the root node, we need to grow
665 LLVector3d center(node->getCenter());
666 LLVector3d size(node->getSize());
667
668 //expand this node
669 LLVector3d newcenter(center);
670 LLOctreeNode<T>::pushCenter(newcenter, size, data);
671 node->setCenter(newcenter);
672 node->setSize(size*2);
673 node->updateMinMax();
674
675 //copy our children to a new branch
676 LLOctreeState<T>* newstate = new LLOctreeState<T>();
677 LLOctreeNode<T>* newnode = new LLOctreeNode<T>(center, size, newstate, node);
678
679 for (U32 i = 0; i < this->getChildCount(); i++)
680 {
681 LLOctreeNode<T>* child = this->getChild(i);
682 newstate->addChild(child);
683 }
684
685 //clear our children and add the root copy
686 this->clearChildren();
687 addChild(newnode);
688
689 //insert the data
690 node->insert(data);
691 }
692
693 return false;
694 }
695};
696
697
698//========================
699// LLOctreeTraveler
700//========================
701template <class T>
702void LLOctreeTraveler<T>::traverse(const LLTreeNode<T>* node)
703{
704 const LLOctreeState<T>* state = (const LLOctreeState<T>*) node->getState();
705 state->accept(this);
706 for (U32 i = 0; i < state->getChildCount(); i++)
707 {
708 traverse(state->getChild(i));
709 }
710}
711
712#endif