diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmath/lloctree.h | |
parent | README.txt (diff) | |
download | meta-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.h | 712 |
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 | |||
44 | template <class T> class LLOctreeState; | ||
45 | template <class T> class LLOctreeNode; | ||
46 | |||
47 | template <class T> | ||
48 | class LLOctreeListener: public LLTreeListener<T> | ||
49 | { | ||
50 | public: | ||
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 | |||
60 | template <class T> | ||
61 | class LLOctreeNode : public LLTreeNode<T> | ||
62 | { | ||
63 | public: | ||
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 ¢er, 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 | |||
213 | protected: | ||
214 | oct_node* mParent; | ||
215 | LLVector3d mCenter; | ||
216 | LLVector3d mSize; | ||
217 | LLVector3d mMax; | ||
218 | LLVector3d mMin; | ||
219 | U8 mOctant; | ||
220 | }; | ||
221 | |||
222 | template <class T> | ||
223 | class LLOctreeTraveler : public LLTreeTraveler<T> | ||
224 | { | ||
225 | public: | ||
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 | ||
232 | template <class T> | ||
233 | class LLOctreeState : public LLTreeState<T> | ||
234 | { | ||
235 | public: | ||
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 | |||
575 | protected: | ||
576 | child_list mChild; | ||
577 | element_list mData; | ||
578 | }; | ||
579 | |||
580 | //just like a branch, except it might expand the node it points to | ||
581 | template <class T> | ||
582 | class LLOctreeRoot : public LLOctreeState<T> | ||
583 | { | ||
584 | public: | ||
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 | //======================== | ||
701 | template <class T> | ||
702 | void 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 | ||