![]() |
VR-Forces 4.0.4 Class Documentation
|
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 ®ion) 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 ®ion) 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