lloctree.h

Go to the documentation of this file.
00001 
00032 #ifndef LL_LLOCTREE_H
00033 #define LL_LLOCTREE_H
00034 
00035 #include "lltreenode.h"
00036 #include "v3math.h"
00037 #include <vector>
00038 #include <set>
00039 
00040 #ifdef LL_RELEASE_FOR_DOWNLOAD
00041 #define OCT_ERRS LL_WARNS("OctreeErrors")
00042 #else
00043 #define OCT_ERRS LL_ERRS("OctreeErrors")
00044 #endif
00045 
00046 #define LL_OCTREE_PARANOIA_CHECK 0
00047 #if LL_DARWIN
00048 #define LL_OCTREE_MAX_CAPACITY 32
00049 #else
00050 #define LL_OCTREE_MAX_CAPACITY 128
00051 #endif
00052 
00053 template <class T> class LLOctreeNode;
00054 
00055 template <class T>
00056 class LLOctreeListener: public LLTreeListener<T>
00057 {
00058 public:
00059         typedef LLTreeListener<T> BaseType;
00060         typedef LLOctreeNode<T> oct_node;
00061 
00062         virtual void handleChildAddition(const oct_node* parent, oct_node* child) = 0;
00063         virtual void handleChildRemoval(const oct_node* parent, const oct_node* child) = 0;
00064 };
00065 
00066 template <class T>
00067 class LLOctreeTraveler : public LLTreeTraveler<T>
00068 {
00069 public:
00070         virtual void traverse(const LLTreeNode<T>* node);
00071         virtual void visit(const LLTreeNode<T>* state) { }
00072         virtual void visit(const LLOctreeNode<T>* branch) = 0;
00073 };
00074 
00075 template <class T>
00076 class LLOctreeNode : public LLTreeNode<T>
00077 {
00078 public:
00079         typedef LLOctreeTraveler<T>                                                                     oct_traveler;
00080         typedef LLTreeTraveler<T>                                                                       tree_traveler;
00081         typedef typename std::set<LLPointer<T> >                                        element_list;
00082         typedef typename std::set<LLPointer<T> >::iterator                      element_iter;
00083         typedef typename std::set<LLPointer<T> >::const_iterator        const_element_iter;
00084         typedef typename std::vector<LLTreeListener<T>*>::iterator      tree_listener_iter;
00085         typedef typename std::vector<LLOctreeNode<T>* >                         child_list;
00086         typedef LLTreeNode<T>           BaseType;
00087         typedef LLOctreeNode<T>         oct_node;
00088         typedef LLOctreeListener<T>     oct_listener;
00089 
00090         static const U8 OCTANT_POSITIVE_X = 0x01;
00091         static const U8 OCTANT_POSITIVE_Y = 0x02;
00092         static const U8 OCTANT_POSITIVE_Z = 0x04;
00093                 
00094         LLOctreeNode(   LLVector3d center, 
00095                                         LLVector3d size, 
00096                                         BaseType* parent, 
00097                                         U8 octant = 255)
00098         :       mParent((oct_node*)parent), 
00099                 mCenter(center), 
00100                 mSize(size), 
00101                 mOctant(octant) 
00102         { 
00103                 updateMinMax();
00104                 if ((mOctant == 255) && mParent)
00105                 {
00106                         mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV);
00107                 }
00108 
00109                 clearChildren();
00110         }
00111 
00112         virtual ~LLOctreeNode()                                                         
00113         { 
00114                 BaseType::destroyListeners(); 
00115                 
00116                 for (U32 i = 0; i < getChildCount(); i++)
00117                 {
00118                         delete getChild(i);
00119                 } 
00120         }
00121 
00122         inline const BaseType* getParent()      const                   { return mParent; }
00123         inline void setParent(BaseType* parent)                 { mParent = (oct_node*) parent; }
00124         inline const LLVector3d& getCenter() const                      { return mCenter; }
00125         inline const LLVector3d& getSize() const                        { return mSize; }
00126         inline void setCenter(LLVector3d center)                        { mCenter = center; }
00127         inline void setSize(LLVector3d size)                            { mSize = size; }
00128     inline oct_node* getNodeAt(T* data)                         { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
00129         inline U8 getOctant() const                                             { return mOctant; }
00130         inline void setOctant(U8 octant)                                        { mOctant = octant; }
00131         inline const oct_node*  getOctParent() const            { return (const oct_node*) getParent(); }
00132         inline oct_node* getOctParent()                                         { return (oct_node*) getParent(); }
00133         
00134         U8 getOctant(const F64 pos[]) const     //get the octant pos is in
00135         {
00136                 U8 ret = 0;
00137 
00138                 if (pos[0] > mCenter.mdV[0])
00139                 {
00140                         ret |= OCTANT_POSITIVE_X;
00141                 }
00142                 if (pos[1] > mCenter.mdV[1])
00143                 {
00144                         ret |= OCTANT_POSITIVE_Y;
00145                 }
00146                 if (pos[2] > mCenter.mdV[2])
00147                 {
00148                         ret |= OCTANT_POSITIVE_Z;
00149                 }
00150 
00151                 return ret;
00152         }
00153         
00154         inline bool isInside(const LLVector3d& pos, const F64& rad) const
00155         {
00156                 return rad <= mSize.mdV[0]*2.0 && isInside(pos); 
00157         }
00158 
00159         inline bool isInside(T* data) const                     
00160         { 
00161                 return isInside(data->getPositionGroup(), data->getBinRadius());
00162         }
00163 
00164         bool isInside(const LLVector3d& pos) const
00165         {
00166                 const F64& x = pos.mdV[0];
00167                 const F64& y = pos.mdV[1];
00168                 const F64& z = pos.mdV[2];
00169                         
00170                 if (x > mMax.mdV[0] || x <= mMin.mdV[0] ||
00171                         y > mMax.mdV[1] || y <= mMin.mdV[1] ||
00172                         z > mMax.mdV[2] || z <= mMin.mdV[2])
00173                 {
00174                         return false;
00175                 }
00176                 
00177                 return true;
00178         }
00179         
00180         void updateMinMax()
00181         {
00182                 for (U32 i = 0; i < 3; i++)
00183                 {
00184                         mMax.mdV[i] = mCenter.mdV[i] + mSize.mdV[i];
00185                         mMin.mdV[i] = mCenter.mdV[i] - mSize.mdV[i];
00186                         mCenter.mdV[i] = mCenter.mdV[i];
00187                 }
00188         }
00189 
00190         inline oct_listener* getOctListener(U32 index) 
00191         { 
00192                 return (oct_listener*) BaseType::getListener(index); 
00193         }
00194 
00195         inline bool contains(T* xform)
00196         {
00197                 return contains(xform->getBinRadius());
00198         }
00199 
00200         bool contains(F64 radius)
00201         {
00202                 if (mParent == NULL)
00203                 {       //root node contains nothing
00204                         return false;
00205                 }
00206 
00207                 F64 size = mSize.mdV[0];
00208                 F64 p_size = size * 2.0;
00209 
00210                 return (radius <= 0.001 && size <= 0.001) ||
00211                                 (radius <= p_size && radius > size);
00212         }
00213 
00214         static void pushCenter(LLVector3d &center, const LLVector3d &size, const T* data)
00215         {
00216                 const LLVector3d& pos = data->getPositionGroup();
00217                 for (U32 i = 0; i < 3; i++)
00218                 {
00219                         if (pos.mdV[i] > center.mdV[i])
00220                         {
00221                                 center.mdV[i] += size.mdV[i];
00222                         }
00223                         else 
00224                         {
00225                                 center.mdV[i] -= size.mdV[i];
00226                         }
00227                 }
00228         }
00229 
00230         void accept(oct_traveler* visitor)                              { visitor->visit(this); }
00231         virtual bool isLeaf() const                                             { return mChild.empty(); }
00232         
00233         U32 getElementCount() const                                             { return mData.size(); }
00234         element_list& getData()                                                 { return mData; }
00235         const element_list& getData() const                             { return mData; }
00236         
00237         U32 getChildCount()     const                                           { return mChild.size(); }
00238         oct_node* getChild(U32 index)                                   { return mChild[index]; }
00239         const oct_node* getChild(U32 index) const               { return mChild[index]; }
00240         child_list& getChildren()                                               { return mChild; }
00241         const child_list& getChildren() const                   { return mChild; }
00242         
00243         void accept(tree_traveler* visitor) const               { visitor->visit(this); }
00244         void accept(oct_traveler* visitor) const                { visitor->visit(this); }
00245         
00246         oct_node* getNodeAt(const LLVector3d& pos, const F64& rad)
00247         { 
00248                 LLOctreeNode<T>* node = this;
00249 
00250                 if (node->isInside(pos, rad))
00251                 {               
00252                         //do a quick search by octant
00253                         U8 octant = node->getOctant(pos.mdV);
00254                         BOOL keep_going = TRUE;
00255 
00256                         //traverse the tree until we find a node that has no node
00257                         //at the appropriate octant or is smaller than the object.  
00258                         //by definition, that node is the smallest node that contains 
00259                         // the data
00260                         while (keep_going && node->getSize().mdV[0] >= rad)
00261                         {       
00262                                 keep_going = FALSE;
00263                                 for (U32 i = 0; i < node->getChildCount() && !keep_going; i++)
00264                                 {
00265                                         if (node->getChild(i)->getOctant() == octant)
00266                                         {
00267                                                 node = node->getChild(i);
00268                                                 octant = node->getOctant(pos.mdV);
00269                                                 keep_going = TRUE;
00270                                         }
00271                                 }
00272                         }
00273                 }
00274                 else if (!node->contains(rad) && node->getParent())
00275                 { //if we got here, data does not exist in this node
00276                         return ((LLOctreeNode<T>*) node->getParent())->getNodeAt(pos, rad);
00277                 }
00278 
00279                 return node;
00280         }
00281         
00282         virtual bool insert(T* data)
00283         {
00284                 if (data == NULL)
00285                 {
00286                         //OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
00287                         return false;
00288                 }
00289                 LLOctreeNode<T>* parent = getOctParent();
00290 
00291                 //is it here?
00292                 if (isInside(data->getPositionGroup()))
00293                 {
00294                         if (getElementCount() < LL_OCTREE_MAX_CAPACITY &&
00295                                 (contains(data->getBinRadius()) ||
00296                                 (data->getBinRadius() > getSize().mdV[0] &&
00297                                 parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY))) 
00298                         { //it belongs here
00299 #if LL_OCTREE_PARANOIA_CHECK
00300                                 //if this is a redundant insertion, error out (should never happen)
00301                                 if (mData.find(data) != mData.end())
00302                                 {
00303                                         llwarns << "Redundant octree insertion detected. " << data << llendl;
00304                                         return false;
00305                                 }
00306 #endif
00307 
00308                                 mData.insert(data);
00309                                 BaseType::insert(data);
00310                                 return true;
00311                         }
00312                         else
00313                         {       
00314                                 //find a child to give it to
00315                                 oct_node* child = NULL;
00316                                 for (U32 i = 0; i < getChildCount(); i++)
00317                                 {
00318                                         child = getChild(i);
00319                                         if (child->isInside(data->getPositionGroup()))
00320                                         {
00321                                                 child->insert(data);
00322                                                 return false;
00323                                         }
00324                                 }
00325                                 
00326                                 //it's here, but no kids are in the right place, make a new kid
00327                                 LLVector3d center(getCenter());
00328                                 LLVector3d size(getSize()*0.5);
00329                                         
00330                                 //push center in direction of data
00331                                 LLOctreeNode<T>::pushCenter(center, size, data);
00332 
00333 #if LL_OCTREE_PARANOIA_CHECK
00334                                 if (getChildCount() == 8)
00335                                 {
00336                                         //this really isn't possible, something bad has happened
00337                                         OCT_ERRS << "Octree detected floating point error and gave up." << llendl;
00338                                         return false;
00339                                 }
00340                                 
00341                                 //make sure no existing node matches this position
00342                                 for (U32 i = 0; i < getChildCount(); i++)
00343                                 {
00344                                         if (mChild[i]->getCenter() == center)
00345                                         {
00346                                                 OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl;
00347                                                 return false;
00348                                         }
00349                                 }
00350 #endif
00351 
00352                                 //make the new kid
00353                                 child = new LLOctreeNode<T>(center, size, this);
00354                                 addChild(child);
00355                                                                 
00356                                 child->insert(data);
00357                         }
00358                 }
00359                 else 
00360                 {
00361                         //it's not in here, give it to the root
00362                         //OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl;
00363 
00364                         oct_node* node = this;
00365 
00366                         while (parent)
00367                         {
00368                                 node = parent;
00369                                 parent = node->getOctParent();
00370                         }
00371 
00372                         node->insert(data);
00373                 }
00374 
00375                 return false;
00376         }
00377 
00378         bool remove(T* data)
00379         {
00380                 if (mData.find(data) != mData.end())
00381                 {       //we have data
00382                         mData.erase(data);
00383                         notifyRemoval(data);
00384                         checkAlive();
00385                         return true;
00386                 }
00387                 else if (isInside(data))
00388                 {
00389                         oct_node* dest = getNodeAt(data);
00390 
00391                         if (dest != this)
00392                         {
00393                                 return dest->remove(data);
00394                         }
00395                 }
00396 
00397                 //SHE'S GONE MISSING...
00398                 //none of the children have it, let's just brute force this bastard out
00399                 //starting with the root node (UGLY CODE COMETH!)
00400                 oct_node* parent = getOctParent();
00401                 oct_node* node = this;
00402 
00403                 while (parent != NULL)
00404                 {
00405                         node = parent;
00406                         parent = node->getOctParent();
00407                 }
00408 
00409                 //node is now root
00410                 llwarns << "!!! OCTREE REMOVING FACE BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << llendl;
00411                 node->removeByAddress(data);
00412                 return true;
00413         }
00414 
00415         void removeByAddress(T* data)
00416         {
00417         if (mData.find(data) != mData.end())
00418                 {
00419                         mData.erase(data);
00420                         notifyRemoval(data);
00421                         llwarns << "FOUND!" << llendl;
00422                         checkAlive();
00423                         return;
00424                 }
00425                 
00426                 for (U32 i = 0; i < getChildCount(); i++)
00427                 {       //we don't contain data, so pass this guy down
00428                         LLOctreeNode<T>* child = (LLOctreeNode<T>*) getChild(i);
00429                         child->removeByAddress(data);
00430                 }
00431         }
00432 
00433         void clearChildren()
00434         {
00435                 mChild.clear();
00436         }
00437 
00438         void validate()
00439         {
00440 #if LL_OCTREE_PARANOIA_CHECK
00441                 for (U32 i = 0; i < getChildCount(); i++)
00442                 {
00443                         mChild[i]->validate();
00444                         if (mChild[i]->getParent() != this)
00445                         {
00446                                 llerrs << "Octree child has invalid parent." << llendl;
00447                         }
00448                 }
00449 #endif
00450         }
00451 
00452         virtual bool balance()
00453         {       
00454                 return false;
00455         }
00456 
00457         void destroy()
00458         {
00459                 for (U32 i = 0; i < getChildCount(); i++) 
00460                 {       
00461                         mChild[i]->destroy();
00462                         delete mChild[i];
00463                 }
00464         }
00465 
00466         void addChild(oct_node* child, BOOL silent = FALSE) 
00467         {
00468 #if LL_OCTREE_PARANOIA_CHECK
00469                 for (U32 i = 0; i < getChildCount(); i++)
00470                 {
00471                         if(mChild[i]->getSize() != child->getSize()) 
00472                         {
00473                                 OCT_ERRS <<"Invalid octree child size." << llendl;
00474                         }
00475                         if (mChild[i]->getCenter() == child->getCenter())
00476                         {
00477                                 OCT_ERRS <<"Duplicate octree child position." << llendl;
00478                         }
00479                 }
00480 
00481                 if (mChild.size() >= 8)
00482                 {
00483                         OCT_ERRS <<"Octree node has too many children... why?" << llendl;
00484                 }
00485 #endif
00486 
00487                 mChild.push_back(child);
00488                 child->setParent(this);
00489 
00490                 if (!silent)
00491                 {
00492                         for (U32 i = 0; i < this->getListenerCount(); i++)
00493                         {
00494                                 oct_listener* listener = getOctListener(i);
00495                                 listener->handleChildAddition(this, child);
00496                         }
00497                 }
00498         }
00499 
00500         void removeChild(U8 index, BOOL destroy = FALSE)
00501         {
00502                 for (U32 i = 0; i < this->getListenerCount(); i++)
00503                 {
00504                         oct_listener* listener = getOctListener(i);
00505                         listener->handleChildRemoval(this, getChild(index));
00506                 }
00507 
00508                 if (destroy)
00509                 {
00510                         mChild[index]->destroy();
00511                         delete mChild[index];
00512                 }
00513                 mChild.erase(mChild.begin() + index);
00514 
00515                 checkAlive();
00516         }
00517 
00518         void checkAlive()
00519         {
00520                 if (getChildCount() == 0 && getElementCount() == 0)
00521                 {
00522                         oct_node* parent = getOctParent();
00523                         if (parent)
00524                         {
00525                                 parent->deleteChild(this);
00526                         }
00527                 }
00528         }
00529 
00530         void deleteChild(oct_node* node)
00531         {
00532                 for (U32 i = 0; i < getChildCount(); i++)
00533                 {
00534                         if (getChild(i) == node)
00535                         {
00536                                 removeChild(i, TRUE);
00537                                 return;
00538                         }
00539                 }
00540 
00541                 //OCT_ERRS << "Octree failed to delete requested child." << llendl;
00542         }
00543 
00544 protected:      
00545         child_list mChild;
00546         element_list mData;
00547         oct_node* mParent;
00548         LLVector3d mCenter;
00549         LLVector3d mSize;
00550         LLVector3d mMax;
00551         LLVector3d mMin;
00552         U8 mOctant;
00553 };
00554 
00555 //just like a regular node, except it might expand on insert and compress on balance
00556 template <class T>
00557 class LLOctreeRoot : public LLOctreeNode<T>
00558 {
00559 public:
00560         typedef LLOctreeNode<T> BaseType;
00561         typedef LLOctreeNode<T>         oct_node;
00562 
00563         LLOctreeRoot(   LLVector3d center, 
00564                                         LLVector3d size, 
00565                                         BaseType* parent)
00566         :       BaseType(center, size, parent)
00567         {
00568         }
00569         
00570         bool balance()
00571         {       
00572                 if (this->getChildCount() == 1 && 
00573                         !(this->mChild[0]->isLeaf()) &&
00574                         this->mChild[0]->getElementCount() == 0) 
00575                 { //if we have only one child and that child is an empty branch, make that child the root
00576                         oct_node* child = this->mChild[0];
00577                                         
00578                         //make the root node look like the child
00579                         this->setCenter(this->mChild[0]->getCenter());
00580                         this->setSize(this->mChild[0]->getSize());
00581                         this->updateMinMax();
00582 
00583                         //reset root node child list
00584                         this->clearChildren();
00585 
00586                         //copy the child's children into the root node silently 
00587                         //(don't notify listeners of addition)
00588                         for (U32 i = 0; i < child->getChildCount(); i++)
00589                         {
00590                                 addChild(child->getChild(i), TRUE);
00591                         }
00592 
00593                         //destroy child
00594                         child->clearChildren();
00595                         delete child;
00596                 }
00597                 
00598                 return true;
00599         }
00600 
00601         // LLOctreeRoot::insert
00602         bool insert(T* data)
00603         {
00604                 if (data == NULL) 
00605                 {
00606                         //OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
00607                         return false;
00608                 }
00609                 
00610                 if (data->getBinRadius() > 4096.0)
00611                 {
00612                         //OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
00613                         return false;
00614                 }
00615                 
00616                 const F64 MAX_MAG = 1024.0*1024.0;
00617 
00618                 const LLVector3d& v = data->getPositionGroup();
00619                 if (!(fabs(v.mdV[0]-this->mCenter.mdV[0]) < MAX_MAG &&
00620                       fabs(v.mdV[1]-this->mCenter.mdV[1]) < MAX_MAG &&
00621                       fabs(v.mdV[2]-this->mCenter.mdV[2]) < MAX_MAG))
00622                 {
00623                         //OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
00624                         return false;
00625                 }
00626 
00627                 if (this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
00628                 {
00629                         //we got it, just act like a branch
00630                         oct_node* node = getNodeAt(data);
00631                         if (node == this)
00632                         {
00633                                 LLOctreeNode<T>::insert(data);
00634                         }
00635                         else
00636                         {
00637                                 node->insert(data);
00638                         }
00639                 }
00640                 else if (this->getChildCount() == 0)
00641                 {
00642                         //first object being added, just wrap it up
00643                         while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
00644                         {
00645                                 LLVector3d center, size;
00646                                 center = this->getCenter();
00647                                 size = this->getSize();
00648                                 LLOctreeNode<T>::pushCenter(center, size, data);
00649                                 this->setCenter(center);
00650                                 this->setSize(size*2);
00651                                 this->updateMinMax();
00652                         }
00653                         LLOctreeNode<T>::insert(data);
00654                 }
00655                 else
00656                 {
00657                         while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
00658                         {
00659                                 //the data is outside the root node, we need to grow
00660                                 LLVector3d center(this->getCenter());
00661                                 LLVector3d size(this->getSize());
00662 
00663                                 //expand this node
00664                                 LLVector3d newcenter(center);
00665                                 LLOctreeNode<T>::pushCenter(newcenter, size, data);
00666                                 this->setCenter(newcenter);
00667                                 this->setSize(size*2);
00668                                 this->updateMinMax();
00669 
00670                                 //copy our children to a new branch
00671                                 LLOctreeNode<T>* newnode = new LLOctreeNode<T>(center, size, this);
00672                                 
00673                                 for (U32 i = 0; i < this->getChildCount(); i++)
00674                                 {
00675                                         LLOctreeNode<T>* child = this->getChild(i);
00676                                         newnode->addChild(child);
00677                                 }
00678 
00679                                 //clear our children and add the root copy
00680                                 this->clearChildren();
00681                                 addChild(newnode);
00682                         }
00683 
00684                         //insert the data
00685                         insert(data);
00686                 }
00687 
00688                 return false;
00689         }
00690 };
00691 
00692 
00693 //========================
00694 //              LLOctreeTraveler
00695 //========================
00696 template <class T>
00697 void LLOctreeTraveler<T>::traverse(const LLTreeNode<T>* tree_node)
00698 {
00699         const LLOctreeNode<T>* node = (const LLOctreeNode<T>*) tree_node;
00700         node->accept(this);
00701         for (U32 i = 0; i < node->getChildCount(); i++)
00702         {
00703                 traverse(node->getChild(i));
00704         }
00705 }
00706 
00707 #endif

Generated on Fri May 16 08:32:15 2008 for SecondLife by  doxygen 1.5.5