VR-Forces 4.0.4 Class Documentation
include/vrfobjcore/octree.h
Go to the documentation of this file.
00001 /*******************************************************************************
00002 ** Copyright (c) 2008 MAK Technologies, Inc.
00003 ** All rights reserved.
00004 *******************************************************************************/
00005 /*******************************************************************************
00006 ** $RCSfile: octree.h,v $ $Revision: 1.4 $ $State: Exp $
00007 *******************************************************************************/
00008 
00011 
00031 
00032 #ifndef octree_H_
00033 #define octree_H_
00034 
00035 #include <stdarg.h>
00036 #include <map>
00037 #include <vector>
00038 
00039 #include <cmdLine/cmdStdOutput.h>
00040 
00041 #include "vrfobjcore/spatialVrfObjectManager.h"
00042 #include "geometry/tdbextent.h"
00043 
00044 template<class T> class DtOctreeNode;
00045 
00048 
00049 #define OCTREE_DEBUG 0
00050 
00051 #if OCTREE_DEBUG
00052 
00053 static int octree_debug_level = 0;
00054 
00056 
00057 static void DEBUG(const char* fmt, ...)
00058 {
00059    char buffer[8192];
00060    va_list ap;
00061    va_start(ap, fmt);
00062    vsprintf(buffer, fmt, ap);
00063    va_end(ap);
00064 
00065    DtInfo("OCT %*s%s\n", octree_debug_level*2, "", buffer);
00066 }
00067 
00068 #  define DEBUG_PUSH do { octree_debug_level++; } while(0)
00069 #  define DEBUG_POP do { octree_debug_level--; } while(0)
00070 #else
00071 
00072 static inline void DEBUG(const char* fmt, ...)
00073 { }
00074 
00075 #  define DEBUG_PUSH do { } while(0)
00076 #  define DEBUG_POP do { } while(0)
00077 #endif
00078 
00079 #define EXT_FMT "[%lf, %lf, %lf] - [%lf, %lf, %lf]"
00080 #define EXT_ARGS(x) (x).minX(), (x).minY(), (x).minZ(), (x).maxX(), (x).maxY(), (x).maxZ()
00081 #define OBJ_ARGS(x) ((const char*) (x)->objectName())
00082 
00088 
00089 template<class T> class DtOctreeMember
00090 {
00091 public:
00092    DtOctreeMember(T* object, const DtExtent& extent)
00093       : myObject(object)
00094       , myExtent(extent)
00095       , boundNode(0)
00096    {
00097    }
00098 
00100    void bind(DtOctreeNode<T>* node);
00101    
00103    void unbind();
00104 
00105 public:
00107    T* myObject;
00108 
00110    DtExtent myExtent;
00111 
00113    DtOctreeNode<T>* boundNode;
00114 
00117    typename std::list<DtOctreeMember*>::iterator boundIterator;
00118 };
00119 
00146 
00147 template<class T> class DtOctreeNode
00148 {
00149 protected: 
00150 
00151    typedef          std::list<DtOctreeMember<T>*>           MemberContainer;
00152    typedef typename std::list<DtOctreeMember<T>*>::iterator MemberIterator;
00153 
00155    static const int NUM_BRANCHES = 8;
00156 
00158    static const int MAX_CHILD_MEMBERS = 10;
00159 
00161    DtOctreeNode(const DtExtent &region)
00162       : myRegion(region)
00163       , myCenter(region.center())
00164       , myChildren(0)
00165    { 
00166       DEBUG("Create node " EXT_FMT, EXT_ARGS(region));
00167    }
00168 
00170    ~DtOctreeNode()
00171    {
00172       DEBUG("Destroy node " EXT_FMT, EXT_ARGS(myRegion));
00173       DEBUG_PUSH;
00174 
00175       if (myChildren)
00176       {
00177          for(int i=0; i<NUM_BRANCHES; i++)
00178             delete myChildren[i];
00179       }
00180       delete[] myChildren;
00181 
00182       DEBUG_POP;
00183    }
00184 
00193    
00194    virtual void visitObjects(const DtExtent& extent, DtSpatialSelectionFunctor &callback)
00195    {
00196       DEBUG(EXT_FMT "::visit(" EXT_FMT ", cb)", EXT_ARGS(myRegion), EXT_ARGS(extent));
00197       DEBUG_PUSH;
00198 
00199       MemberIterator iter, end;
00200 
00201       for(iter = myMembers.begin(), end = myMembers.end(); iter != end; ++iter)
00202       {
00203          DEBUG("Member %s " EXT_FMT, OBJ_ARGS((*iter)->myObject), EXT_ARGS((*iter)->myExtent));
00204          callback((*iter)->myObject);
00205       }
00206 
00207       if (myChildren)
00208       {
00209          int mask = intersectionMask(extent);
00210          for(int i=0; i<NUM_BRANCHES; i++)
00211          {
00212             if (myChildren[i] && (mask & (1<<i)))
00213                myChildren[i]->visitObjects(extent, callback);
00214          }
00215       }
00216 
00217       DEBUG_POP;
00218    }
00219    
00221    virtual void addMember(DtOctreeMember<T>* member)
00222    {
00223       DEBUG(EXT_FMT "::addMember(%s)", EXT_ARGS(myRegion), OBJ_ARGS(member->myObject));
00224       DEBUG_PUSH;
00225       
00226 #if OCTREE_DEBUG
00227       if (!myRegion.contains(member->myExtent))
00228       {
00229          DEBUG("FAIL!  " EXT_FMT " does not contain " EXT_FMT, EXT_ARGS(myRegion), EXT_ARGS(member->myExtent));
00230       }
00231 #endif
00232 
00233       if (myChildren)
00234       {
00235          int mask = intersectionMask(member->myExtent);
00236          int childIndex = childIndexFor(mask);
00237 
00238          if (childIndex == -1) {
00239             DEBUG("add as member (children, but won't fit)");
00240             member->bind(this);
00241          } else {
00242             addMemberToChild(member, childIndex);
00243          }
00244       } else {
00245          DEBUG("add as child member (not enough child members yet)");
00246 
00247          member->bind(this);
00248 
00249          if (numChildCandidates() >= MAX_CHILD_MEMBERS)
00250          {
00251             split();
00252          }
00253       }
00254 
00255       DEBUG_POP;
00256    }
00257 
00260    bool coalesceEmptyChildren()
00261    {
00262       DEBUG(EXT_FMT "::coalesceEmptyChildren()", EXT_ARGS(myRegion));
00263       DEBUG_PUSH;
00264 
00265       bool retVal = (myMembers.size() == 0);
00266       
00267       if (myChildren)
00268       {
00269          for(int i=0; i<NUM_BRANCHES; i++)
00270          {
00271             if (myChildren[i])
00272             {
00273                if (myChildren[i]->coalesceEmptyChildren())
00274                {
00275                   DEBUG("Deleting child %d\n", i);
00276                   delete myChildren[i];
00277                   myChildren[i] = 0;
00278                } else {
00279                   retVal = false;
00280                }
00281             }
00282          }
00283       }
00284 
00285       DEBUG_POP;
00286 
00287       return retVal;
00288    }
00289 
00291    int numChildCandidates()
00292    {
00293       int retVal = 0;
00294       
00295       MemberIterator iter, end;
00296       for(iter = myMembers.begin(), end = myMembers.end(); iter != end; ++iter)
00297       {
00298          if (childIndexFor(intersectionMask((*iter)->myExtent)) != -1)
00299          {
00300             retVal++;
00301          }
00302       }
00303 
00304       return retVal;
00305    }
00306 
00312    int intersectionMask(const DtExtent &extent) const
00313    {
00314       int result = 0xff;                  
00315 
00316       if (extent.minX() >= myCenter.x())
00317          result &= 0xf0;                  
00318       if (extent.maxX() <= myCenter.x())
00319          result &= 0x0f;                  
00320 
00321       if (extent.minY() >= myCenter.y())
00322          result &= 0xcc;                  
00323       if (extent.maxY() <= myCenter.y())
00324          result &= 0x33;                  
00325 
00326       if (extent.minZ() >= myCenter.z())
00327          result &= 0xaa;                  
00328       if (extent.maxZ() <= myCenter.z())
00329          result &= 0x55;                  
00330 
00331       if (result == 0)
00332       {
00333          DtWarn("Can't happen!  Octree intersection mask is 0!");
00334       }
00335 
00336       return result;
00337    }
00338 
00342    int childIndexFor(int mask)
00343    {
00344       if (!mask || (mask & (mask-1))) 
00345       {
00346          return -1;
00347       }
00348 
00349       int childIndex;
00350       for(childIndex=0; childIndex<NUM_BRANCHES; childIndex++)
00351       {
00352          if (mask & (1<<childIndex))
00353             return childIndex;
00354       }
00355 
00356       DtWarn("Can't happen: no valid child index in octree code.");
00357       return -1;
00358    }
00359 
00363 
00364    void addMemberToChild(DtOctreeMember<T>* member, int childIndex)
00365    {
00366       DEBUG(EXT_FMT "::addMemberToChild(%s, %d)", EXT_ARGS(myRegion), OBJ_ARGS(member->myObject), childIndex);
00367       DEBUG_PUSH;
00368 
00369       if (myChildren[childIndex] == 0)
00370       {
00371          DtPoint childCorner;
00372 
00373          if (childIndex & 4)
00374             childCorner.setX(myRegion.maxX());
00375          else
00376             childCorner.setX(myRegion.minX());
00377 
00378          if (childIndex & 2)
00379             childCorner.setY(myRegion.maxY());
00380          else
00381             childCorner.setY(myRegion.minY());
00382 
00383          if (childIndex & 1)
00384             childCorner.setZ(myRegion.maxZ());
00385          else
00386             childCorner.setZ(myRegion.minZ());
00387 
00388          myChildren[childIndex] = new DtOctreeNode(DtExtent(childCorner, myCenter));
00389       }
00390 
00391       myChildren[childIndex]->addMember(member);
00392 
00393       DEBUG_POP;
00394    }
00395 
00398 
00399    void split()
00400    {
00401       DEBUG(EXT_FMT "::split()", EXT_ARGS(myRegion));
00402       DEBUG_PUSH;
00403 
00404       myChildren = new DtOctreeNode<T>* [NUM_BRANCHES];
00405 
00406       for(int i=0; i<NUM_BRANCHES; i++)
00407       {
00408          myChildren[i] = 0;
00409       }
00410 
00411       MemberIterator iter, next, end;
00412       for(iter = myMembers.begin(), end = myMembers.end(); iter != end; iter = next)
00413       {
00414          next = iter;
00415          ++next;
00416 
00417          DtOctreeMember<T>* member = *iter;
00418          int childIndex = childIndexFor(intersectionMask(member->myExtent));
00419 
00420          if (childIndex != -1)
00421          {
00422             member->unbind();
00423             addMemberToChild(member, childIndex);
00424          }
00425       }
00426 
00427       DEBUG_POP;
00428    }
00429 
00431    const DtExtent myRegion;
00432    
00434    const DtPoint myCenter;
00435 
00439    DtOctreeNode<T> **myChildren;
00440 
00443    MemberContainer myMembers;
00444 
00445    template<class U> friend class DtOctree;
00446    template<class U> friend class DtOctreeMember;
00447    template<class U> friend class DtOctreeDebugger;
00448 };
00449 
00461 
00462 template<class T> class DtOctree
00463 {
00464 public:
00465 
00467    typedef          std::map<T*, DtOctreeMember<T>*>           MemberContainer;
00468    typedef typename std::map<T*, DtOctreeMember<T>*>::iterator MemberIterator;
00469 
00470    typedef          std::list<T*>                            OutsideAreaContainer;
00471    typedef typename std::list<T*>::iterator                  OutsideAreaIterator;
00472 
00474    DtOctree(const DtExtent &region)
00475    {
00476       myRootNode = new DtOctreeNode<T>(region);
00477    }
00478 
00480    virtual ~DtOctree()
00481    {
00482       delete myRootNode;
00483 
00484       MemberIterator iter, end;
00485       for(iter = myMemberMap.begin(), end = myMemberMap.end(); iter != end; ++iter)
00486       {
00487          delete (*iter).second;
00488       }
00489    }
00490 
00494    virtual void visitObjects(const DtExtent& extent, DtSpatialSelectionFunctor &callback)
00495    {
00496       if (myRootNode->myRegion.intersects(extent))
00497       {
00498          myRootNode->visitObjects(extent, callback);
00499       }
00500 
00501       OutsideAreaIterator iter, end;
00502       for(iter = myObjectsOutsideArea.begin(), end = myObjectsOutsideArea.end(); iter != end; ++iter)
00503       {
00504          callback(*iter);
00505       }
00506    }
00507 
00509    virtual void addObject(T* object, const DtExtent& extent)
00510    {
00511       DEBUG("DtOctree::addObject(%s, " EXT_FMT ")", OBJ_ARGS(object), EXT_ARGS(extent));
00512       DEBUG_PUSH;
00513 
00514       if (myRootNode->myRegion.contains(extent))
00515       {
00516          DtOctreeMember<T>* newMember = new DtOctreeMember<T>(object, extent);
00517          myRootNode->addMember(newMember);
00518          myMemberMap[object] = newMember;
00519       } else {
00520          DtWarn("Member %s (" EXT_FMT ") added outside octree (" EXT_FMT ")",
00521                 OBJ_ARGS(object), EXT_ARGS(extent), EXT_ARGS(myRootNode->myRegion));
00522          myObjectsOutsideArea.push_back(object);
00523       }
00524 
00525       DEBUG_POP;
00526    }
00527 
00529    virtual void removeObject(T* object)
00530    {
00531       DEBUG("DtOctree::removeObject(%s)", OBJ_ARGS(object));
00532       DEBUG_PUSH;
00533 
00534       MemberIterator iter;
00535       iter = myMemberMap.find(object);
00536       if (iter != myMemberMap.end())
00537       {
00538          DtOctreeMember<T>* member = (*iter).second;
00539          member->unbind();
00540          myMemberMap.erase(iter);
00541          delete member;
00542       } else if (!removeObjectOutsideArea(object)) {
00546 
00547          //DtWarn("Tried to remove %s from octree, but couldn't find!\n", OBJ_ARGS(object));
00548       }
00549 
00550       DEBUG_POP;
00551    }
00552 
00558    virtual void updatePositions()
00559    {
00560       MemberIterator iter, end;
00561 
00562       for(iter = myMemberMap.begin(), end = myMemberMap.end(); iter != end; ++iter)
00563       {
00564          T* object = (*iter).first;
00565          DtOctreeMember<T>* member = (*iter).second;
00566 
00567          member->myExtent = object->extent();
00568 
00569          if (!myRootNode->myRegion.contains(member->myExtent))
00570          {
00572 
00573             DtWarn("Object %s (" EXT_FMT ") moving outside octree (" EXT_FMT ")",
00574                   OBJ_ARGS(object), EXT_ARGS(member->myExtent), EXT_ARGS(myRootNode->myRegion));
00575             removeObject(object);
00576             myObjectsOutsideArea.push_back(object);
00577          } else if (!member->boundNode->myRegion.contains(member->myExtent)) {
00579 
00580             member->unbind();
00581             myRootNode->addMember(member);
00582          } else {
00584          }            
00585       }
00586 
00587       myRootNode->coalesceEmptyChildren();
00588    }
00589 
00590    bool containsObject(T* object)
00591    {
00592       return myMemberMap.find(object) != myMemberMap.end();
00593    }
00594 
00595    int numObjects()
00596    {
00597       return myMemberMap.size();
00598    }
00599 
00600 protected:
00601    bool removeObjectOutsideArea(T* object)
00602    {
00603       OutsideAreaIterator iter, end;
00604       for(iter = myObjectsOutsideArea.begin(), end = myObjectsOutsideArea.end(); iter != end; ++iter)
00605       {
00606          if (*iter == object)
00607          {
00608             myObjectsOutsideArea.erase(iter);
00609             return true;
00610          }
00611       }
00612 
00613       return false;
00614    }
00615 
00617    DtOctreeNode<T>* myRootNode;
00618    
00620    OutsideAreaContainer myObjectsOutsideArea;
00621    
00623    MemberContainer myMemberMap;
00624 };
00625 
00629 
00630 #if OCTREE_DEBUG
00631 
00632 class DtDebugOctreeFunctor : public DtSpatialSelectionFunctor
00633 {
00634 public:
00635    DtDebugOctreeFunctor(DtSpatialSelectionFunctor& inner)
00636       : myInner(inner)
00637    {
00638    }  
00639 
00641    virtual bool operator()(const DtVrfObject* object)
00642    {
00643       mySeenObjects.insert(object);
00644       return myInner(object);
00645    }
00646 
00647    std::set<const DtVrfObject*> mySeenObjects;
00648    DtSpatialSelectionFunctor& myInner;
00649 };
00650 
00651 template<class T> class DtOctreeDebugger : public DtOctree<T>
00652 {
00653 public:
00654    DtOctreeDebugger(const DtExtent& extent)
00655       : DtOctree<T>(extent)
00656    { }
00657 
00658    void addObject(T* object, const DtExtent& extent)
00659    {
00660       allObjects[object] = extent;
00661       DtOctree<T>::addObject(object, extent);
00662    }
00663 
00664    void removeObject(T* object)
00665    {
00666       allObjects.erase(object);
00667       DtOctree<T>::removeObject(object);
00668    }
00669 
00670    void updatePositions()
00671    {
00672       std::map<T*, DtExtent>::iterator iter = allObjects.begin();
00673       std::map<T*, DtExtent>::iterator end  = allObjects.end();
00674 
00675       for(; iter != end; ++iter)
00676       {
00677          T* object = (*iter).first;
00678          DtExtent& extent = (*iter).second;
00679 
00680          extent = object->extent();
00681       }
00682 
00683       DtOctree<T>::updatePositions();
00684    }
00685 
00686    void visitObjects(const DtExtent& extent, DtSpatialSelectionFunctor &callback)
00687    {
00688       DtDebugOctreeFunctor debugFunctor(callback);
00689       DtOctree<T>::visitObjects(extent, debugFunctor);
00690 
00691       std::map<T*, DtExtent>::iterator iter = allObjects.begin();
00692       std::map<T*, DtExtent>::iterator end  = allObjects.end();
00693 
00694       for(; iter != end; ++iter)
00695       {
00696          T* object = (*iter).first;
00697          const DtExtent& objectExtent = (*iter).second;
00698 
00699          if (objectExtent.intersects(extent) && debugFunctor.mySeenObjects.count(object) == 0)
00700          {
00701             DEBUG("FAILED to visit object %s", OBJ_ARGS(object));
00702             DEBUG_PUSH;
00703             DEBUG("Old extent is " EXT_FMT, EXT_ARGS(objectExtent));
00704             DEBUG("New extent is " EXT_FMT, EXT_ARGS(object->extent()));
00705             DEBUG_POP;
00706          }
00707       }
00708    }
00709 protected:
00710    std::map<T*, DtExtent> allObjects;
00711 };
00712 
00714 
00715 static DtOctree<DtVrfObject>* createOctree(const DtExtent& extent)
00716 {
00717    return new DtOctreeDebugger<DtVrfObject>(extent);
00718 }
00719 
00720 #else
00721 
00722 static DtOctree<DtVrfObject>* createOctree(const DtExtent& extent)
00723 {
00724    return new DtOctree<DtVrfObject>(extent);
00725 }
00726 
00727 #endif
00728 
00730 
00731 template<class T> void DtOctreeMember<T>::bind(DtOctreeNode<T>* node)
00732 {
00733    if (boundNode)
00734    {
00735       DtWarn("Octree binding node for %s when already bound!", OBJ_ARGS(myObject));
00736       unbind();
00737    }
00738 
00739    boundNode = node;
00740    boundIterator = node->myMembers.insert(node->myMembers.end(), this);
00741 }
00742 
00743 template<class T> void DtOctreeMember<T>::unbind()
00744 {
00745    if (boundNode)
00746    {
00747       boundNode->myMembers.erase(boundIterator);
00748       boundNode = NULL;
00749    }
00750 }
00751 
00752 #endif

Document ID: Generated on Fri Jun 29 16:33:32 EDT 2012 from SVN revision 116588
Copyright © 2005-2012 VT MÄK Inc. All Rights Reserved (www.mak.com)