VR-Forces 4.6 Class Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
octree.h
Go to the documentation of this file.
1 /*******************************************************************************
2 ** Copyright (c) 2008 MAK Technologies, Inc.
3 ** All rights reserved.
4 *******************************************************************************/
5 /*******************************************************************************
6 ** $RCSfile: octree.h,v $ $Revision: 1.4 $ $State: Exp $
7 *******************************************************************************/
8 
11 
31 
32 #ifndef octree_H_
33 #define octree_H_
34 
35 #include <stdarg.h>
36 #include <map>
37 #include <vector>
38 
39 #include <cmdLine/cmdStdOutput.h>
40 
42 #include "geometry/extent.h"
43 
44 template<class T> class DtOctreeNode;
45 
48 
49 #define OCTREE_DEBUG 0
50 
51 #if OCTREE_DEBUG
52 
53 static int octree_debug_level = 0;
54 
56 
57 static void DEBUG(const char* fmt, ...)
58 {
59  char buffer[8192];
60  va_list ap;
61  va_start(ap, fmt);
62  vsprintf(buffer, fmt, ap);
63  va_end(ap);
64 
65  DtInfo("OCT %*s%s\n", octree_debug_level*2, "", buffer);
66 }
67 
68 # define DEBUG_PUSH do { octree_debug_level++; } while(0)
69 # define DEBUG_POP do { octree_debug_level--; } while(0)
70 #else
71 
72 static inline void DEBUG(const char* fmt, ...)
73 { }
74 
75 # define DEBUG_PUSH do { } while(0)
76 # define DEBUG_POP do { } while(0)
77 #endif
78 
79 #define EXT_FMT "[%lf, %lf, %lf] - [%lf, %lf, %lf]"
80 #define EXT_ARGS(x) (x).minX(), (x).minY(), (x).minZ(), (x).maxX(), (x).maxY(), (x).maxZ()
81 #define OBJ_ARGS(x) ((const char*) (x)->markingText())
82 
88 
89 template<class T> class DtOctreeMember
90 {
91 public:
92  DtOctreeMember(T* object, const DtExtent& extent)
93  : myObject(object)
94  , myExtent(extent)
95  , mySearchKey(0)
96  {
97  }
98 
100  void bind(DtOctreeNode<T>* node);
101 
103  void unbind(DtOctreeNode<T>* node);
104 
106  void unbind();
107 
108  bool testKey(const unsigned int key)
109  {
110  if (key == mySearchKey)
111  {
112  return false;
113  }
115  mySearchKey = key;
116  return true;
117  }
118 
119 protected:
120  template<class U> friend class DtOctreeNode;
121  template<class U> friend class DtOctree;
122 
125 
128 
129  typedef std::pair<DtOctreeNode<T>*, typename std::list<DtOctreeMember*>::iterator> NodeBinding;
130 
133  std::list<NodeBinding> myBindings;
134 
136  unsigned int mySearchKey;
137 };
138 
165 
166 template<class T> class DtOctreeNode
167 {
168 protected:
169 
170  typedef std::list<DtOctreeMember<T>*> MemberContainer;
171  typedef typename std::list<DtOctreeMember<T>*>::iterator MemberIterator;
172 
174  static const int NUM_BRANCHES = 8;
175 
176  static const int MAX_BRANCH_DEPTH = 12;
177 
179  static const int MAX_CHILD_MEMBERS = 16;
180 
181  static int sNumNodes;
182  static const int MAX_NUM_NODES = 1000;
183 
185  DtOctreeNode(const DtExtent &region, const unsigned int depth)
186  : myRegion(region)
187  , myDepth(depth)
188  , myCenter(region.center())
189  , myChildren(0)
190  {
191  DEBUG("Create node " EXT_FMT, EXT_ARGS(region));
192 
193  ++sNumNodes;
194  }
195 
198  {
199  DEBUG("Destroy node " EXT_FMT, EXT_ARGS(myRegion));
200  DEBUG_PUSH;
201 
202  if (myChildren)
203  {
204  for(int i=0; i<NUM_BRANCHES; i++)
205  delete myChildren[i];
206  }
207  delete[] myChildren;
208 
209  DEBUG_POP;
210 
211  --sNumNodes;
212  }
213 
222 
223  virtual void visitObjects(const unsigned int key, const DtExtent& extent, DtSpatialSelectionFunctor &callback)
224  {
225  DEBUG(EXT_FMT "::visit(" EXT_FMT ", cb)", EXT_ARGS(myRegion), EXT_ARGS(extent));
226  DEBUG_PUSH;
227 
228  MemberIterator iter, end;
229 
230  for(iter = myMembers.begin(), end = myMembers.end(); iter != end; ++iter)
231  {
232  DEBUG("Member %s " EXT_FMT, OBJ_ARGS((*iter)->myObject), EXT_ARGS((*iter)->myExtent));
233  if ((*iter)->testKey(key))
234  {
235  callback((*iter)->myObject);
236  }
237  }
238 
239  if (myChildren)
240  {
241  int mask = intersectionMask(extent);
242  for(int i = 0; i < NUM_BRANCHES; ++i)
243  {
244  if (myChildren[i] && (mask & (1 << i)))
245  {
246  myChildren[i]->visitObjects(key, extent, callback);
247  }
248  }
249  }
250 
251  DEBUG_POP;
252  }
253 
255  virtual void addMember(DtOctreeMember<T>* member)
256  {
257  DEBUG(EXT_FMT "::addMember(%s)", EXT_ARGS(myRegion), OBJ_ARGS(member->myObject));
258  DEBUG_PUSH;
259 
260 #if OCTREE_DEBUG
261  if (!myRegion.contains(member->myExtent))
262  {
263  DEBUG("FAIL! " EXT_FMT " does not contain " EXT_FMT, EXT_ARGS(myRegion), EXT_ARGS(member->myExtent));
264  }
265 #endif
266 
267  if (myChildren)
268  {
269  int mask = intersectionMask(member->myExtent);
270 
271  if (mask == 0xff)
272  {
274  member->bind(this);
275  }
276  else
277  {
278  for (int childIndex = 0; childIndex < NUM_BRANCHES; ++childIndex)
279  {
280  if (mask & (1 << childIndex))
281  {
282  addMemberToChild(member, childIndex);
283  }
284  }
285  }
286  }
287  else
288  {
289  DEBUG("add as child member (not enough child members yet)");
290 
291  member->bind(this);
292 
293  //if (numChildCandidates() >= MAX_CHILD_MEMBERS && myDepth < MAX_BRANCH_DEPTH)
295  {
296  split();
297  }
298  }
299 
300  DEBUG_POP;
301  }
302 
306  {
307  DEBUG(EXT_FMT "::coalesceEmptyChildren()", EXT_ARGS(myRegion));
308  DEBUG_PUSH;
309 
310  bool retVal = (myMembers.size() == 0);
311 
312  if (myChildren)
313  {
314  for(int i=0; i<NUM_BRANCHES; i++)
315  {
316  if (myChildren[i])
317  {
319  {
320  DEBUG("Deleting child %d\n", i);
321  delete myChildren[i];
322  myChildren[i] = 0;
323  } else {
324  retVal = false;
325  }
326  }
327  }
328  }
329 
330  DEBUG_POP;
331 
332  return retVal;
333  }
334 
337  {
338  int retVal = 0;
339 
340  MemberIterator iter, end;
341  for(iter = myMembers.begin(), end = myMembers.end(); iter != end; ++iter)
342  {
346  if (intersectionMask((*iter)->myExtent) != 0xff)
347  {
348  retVal++;
349  }
350  }
351 
352  return retVal;
353  }
354 
360  int intersectionMask(const DtExtent &extent) const
361  {
362  int result = 0xff;
363 
364  if (extent.minX() >= myCenter.x())
365  result &= 0xf0;
366  if (extent.maxX() <= myCenter.x())
367  result &= 0x0f;
368 
369  if (extent.minY() >= myCenter.y())
370  result &= 0xcc;
371  if (extent.maxY() <= myCenter.y())
372  result &= 0x33;
373 
374  if (extent.minZ() >= myCenter.z())
375  result &= 0xaa;
376  if (extent.maxZ() <= myCenter.z())
377  result &= 0x55;
378 
379  if (result == 0)
380  {
384  return 0xff;
385  }
386 
387  return result;
388  }
389 
393  void addMemberToChild(DtOctreeMember<T>* member, int childIndex)
394  {
395  DEBUG(EXT_FMT "::addMemberToChild(%s, %d)", EXT_ARGS(myRegion), OBJ_ARGS(member->myObject), childIndex);
396  DEBUG_PUSH;
397 
398  if (myChildren[childIndex] == 0)
399  {
400  DtPoint childCorner;
401 
402  if (childIndex & 4)
403  childCorner.setX(myRegion.maxX());
404  else
405  childCorner.setX(myRegion.minX());
406 
407  if (childIndex & 2)
408  childCorner.setY(myRegion.maxY());
409  else
410  childCorner.setY(myRegion.minY());
411 
412  if (childIndex & 1)
413  childCorner.setZ(myRegion.maxZ());
414  else
415  childCorner.setZ(myRegion.minZ());
416 
417  myChildren[childIndex] = new DtOctreeNode(DtExtent(childCorner, myCenter), myDepth + 1);
418  }
419 
420  myChildren[childIndex]->addMember(member);
421 
422  DEBUG_POP;
423  }
424 
427  void split()
428  {
429  DEBUG(EXT_FMT "::split()", EXT_ARGS(myRegion));
430  DEBUG_PUSH;
431 
433 
434  for(int i=0; i<NUM_BRANCHES; i++)
435  {
436  myChildren[i] = 0;
437  }
438 
439  MemberIterator iter, next, end;
440  for(iter = myMembers.begin(), end = myMembers.end(); iter != end; iter = next)
441  {
442  next = iter;
443  ++next;
444 
445  DtOctreeMember<T>* member = *iter;
446 
447  int mask = intersectionMask(member->myExtent);
448 
451  if (mask != 0xff)
452  {
453  member->unbind(this);
454 
455  for(int childIndex = 0; childIndex < NUM_BRANCHES; ++childIndex)
456  {
457  if (mask & (1 << childIndex))
458  {
459  addMemberToChild(member, childIndex);
460  }
461  }
462  }
463  }
464 
465  DEBUG_POP;
466  }
467 
470 
473 
474 
475  unsigned int myDepth;
476 
481 
485 
486  template<class U> friend class DtOctree;
487  template<class U> friend class DtOctreeMember;
488  template<class U> friend class DtOctreeDebugger;
489 };
490 
491 template<class T> int DtOctreeNode<T>::sNumNodes = 0;
492 
504 
505 template<class T> class DtOctree
506 {
507 public:
508 
510  typedef std::map<T*, DtOctreeMember<T>*> MemberContainer;
511  typedef typename std::map<T*, DtOctreeMember<T>*>::iterator MemberIterator;
512 
513  typedef std::list<T*> OutsideAreaContainer;
514  typedef typename std::list<T*>::iterator OutsideAreaIterator;
515 
517  DtOctree(const DtExtent &region) : mySearchKey(0)
518  {
519  myRootNode = new DtOctreeNode<T>(region, 0);
520  }
521 
523  virtual ~DtOctree()
524  {
525  delete myRootNode;
526 
527  MemberIterator iter, end;
528  for(iter = myMemberMap.begin(), end = myMemberMap.end(); iter != end; ++iter)
529  {
530  delete (*iter).second;
531  }
532  }
533 
537  virtual void visitObjects(const DtExtent& extent, DtSpatialSelectionFunctor &callback)
538  {
539  ++mySearchKey;
540 
541 
542 
543 
544  if (myRootNode->myRegion.intersects(extent))
545  {
546  myRootNode->visitObjects(mySearchKey, extent, callback);
547  }
548 
549  OutsideAreaIterator iter, end;
550  for(iter = myObjectsOutsideArea.begin(), end = myObjectsOutsideArea.end(); iter != end; ++iter)
551  {
552  callback(*iter);
553  }
554  }
555 
558 
560  virtual void addObject(T* object, const DtExtent& extent)
561  {
562  DEBUG("DtOctree::addObject(%s, " EXT_FMT ")", OBJ_ARGS(object), EXT_ARGS(extent));
563  DEBUG_PUSH;
564 
565  if (myRootNode->myRegion.contains(extent))
566  {
567  DtOctreeMember<T>* newMember = new DtOctreeMember<T>(object, extent);
568  myRootNode->addMember(newMember);
569  myMemberMap[object] = newMember;
570  }
571  else
572  {
573  DtWarn("Member %s (" EXT_FMT ") added outside octree (" EXT_FMT ")\n",
574  OBJ_ARGS(object), EXT_ARGS(extent), EXT_ARGS(myRootNode->myRegion));
575  myObjectsOutsideArea.push_back(object);
576  }
577 
578  DEBUG_POP;
579  }
580 
582  virtual void removeObject(T* object)
583  {
584  DEBUG("DtOctree::removeObject(%s)", OBJ_ARGS(object));
585  DEBUG_PUSH;
586 
587  MemberIterator iter;
588  iter = myMemberMap.find(object);
589  if (iter != myMemberMap.end())
590  {
591  DtOctreeMember<T>* member = (*iter).second;
592  member->unbind();
593  myMemberMap.erase(iter);
594  delete member;
595  }
596  else if (!removeObjectOutsideArea(object))
597  {
601 
602  //DtWarn("Tried to remove %s from octree, but couldn't find!\n", OBJ_ARGS(object));
603  }
604 
605  DEBUG_POP;
606  }
607 
613  virtual void updatePositions()
614  {
615  MemberIterator cur = myMemberMap.begin();
616  while (cur != myMemberMap.end())
617  {
618  MemberIterator iter = cur++;
619 
620  T* object = (*iter).first;
621  DtOctreeMember<T>* member = (*iter).second;
622 
624  if (member->myExtent != object->roughExtent())
625  {
626  member->myExtent = object->roughExtent();
627 
628  if (!myRootNode->myRegion.contains(member->myExtent))
629  {
631 
632  DtWarn("Object %s (" EXT_FMT ") moving outside octree (" EXT_FMT ")\n",
633  OBJ_ARGS(object), EXT_ARGS(member->myExtent), EXT_ARGS(myRootNode->myRegion));
634  removeObject(object);
635  myObjectsOutsideArea.push_back(object);
636  }
637  else
638  {
640 
641  member->unbind();
642  myRootNode->addMember(member);
643  }
644  }
645  }
646 
647  myRootNode->coalesceEmptyChildren();
648  }
649 
650  bool containsObject(T* object)
651  {
652  if (myMemberMap.find(object) != myMemberMap.end())
653  {
654  return true;
655  }
656  else
657  {
658  OutsideAreaIterator iter, end;
659  for(iter = myObjectsOutsideArea.begin(), end = myObjectsOutsideArea.end(); iter != end; ++iter)
660  {
661  if (*iter == object)
662  {
663  return true;
664  }
665  }
666  }
667  return false;
668  }
669 
671  {
672  return myMemberMap.size() + myObjectsOutsideArea.size();
673  }
674 
676  {
677  return myObjectsOutsideArea.size();
678  }
679 
680 protected:
681  bool removeObjectOutsideArea(T* object)
682  {
683  OutsideAreaIterator iter, end;
684  for(iter = myObjectsOutsideArea.begin(), end = myObjectsOutsideArea.end(); iter != end; ++iter)
685  {
686  if (*iter == object)
687  {
688  myObjectsOutsideArea.erase(iter);
689  return true;
690  }
691  }
692 
693  return false;
694  }
695 
698 
701 
704 
706  unsigned int mySearchKey;
707 };
708 
712 
713 #if OCTREE_DEBUG
714 
715 class DtDebugOctreeFunctor : public DtSpatialSelectionFunctor
716 {
717 public:
718  DtDebugOctreeFunctor(DtSpatialSelectionFunctor& inner)
719  : myInner(inner)
720  {
721  }
722 
724  virtual bool operator()(const DtVrfObject* object)
725  {
726  mySeenObjects.insert(object);
727  return myInner(object);
728  }
729 
730  std::set<const DtVrfObject*> mySeenObjects;
731  DtSpatialSelectionFunctor& myInner;
732 };
733 
734 template<class T> class DtOctreeDebugger : public DtOctree<T>
735 {
736 public:
737  DtOctreeDebugger(const DtExtent& extent)
738  : DtOctree<T>(extent)
739  { }
740 
741  void addObject(T* object, const DtExtent& extent)
742  {
743  allObjects[object] = extent;
744  DtOctree<T>::addObject(object, extent);
745  }
746 
747  void removeObject(T* object)
748  {
749  allObjects.erase(object);
751  }
752 
753  void updatePositions()
754  {
755  std::map<T*, DtExtent>::iterator iter = allObjects.begin();
756  std::map<T*, DtExtent>::iterator end = allObjects.end();
757 
758  for(; iter != end; ++iter)
759  {
760  T* object = (*iter).first;
761  DtExtent& extent = (*iter).second;
762 
763  extent = object->roughExtent();
764  }
765 
767  }
768 
769  void visitObjects(const DtExtent& extent, DtSpatialSelectionFunctor &callback)
770  {
771  DtDebugOctreeFunctor debugFunctor(callback);
772  DtOctree<T>::visitObjects(extent, debugFunctor);
773 
774  std::map<T*, DtExtent>::iterator iter = allObjects.begin();
775  std::map<T*, DtExtent>::iterator end = allObjects.end();
776 
777  for(; iter != end; ++iter)
778  {
779  T* object = (*iter).first;
780  const DtExtent& objectExtent = (*iter).second;
781 
782  if (objectExtent.intersects(extent) && debugFunctor.mySeenObjects.count(object) == 0)
783  {
784  DEBUG("FAILED to visit object %s", OBJ_ARGS(object));
785  DEBUG_PUSH;
786  DEBUG("Old extent is " EXT_FMT, EXT_ARGS(objectExtent));
787  DEBUG("New extent is " EXT_FMT, EXT_ARGS(object->roughExtent()));
788  DEBUG_POP;
789  }
790  }
791  }
792 protected:
793  std::map<T*, DtExtent> allObjects;
794 };
795 
797 
798 static DtOctree<DtVrfObject>* createOctree(const DtExtent& extent)
799 {
800  return new DtOctreeDebugger<DtVrfObject>(extent);
801 }
802 
803 #else
804 
806 {
807  return new DtOctree<DtVrfObject>(extent);
808 }
809 
810 #endif
811 
813 
814 template<class T> void DtOctreeMember<T>::bind(DtOctreeNode<T>* node)
815 {
816  for (typename std::list<NodeBinding>::const_iterator it = myBindings.begin(); it != myBindings.end(); ++it)
817  {
818  if (node == (*it).first)
819  {
820  return;
821  }
822  }
823 
824  myBindings.push_back(NodeBinding(node, node->myMembers.insert(node->myMembers.end(), this)));
825 }
826 
827 template<class T> void DtOctreeMember<T>::unbind(DtOctreeNode<T>* node)
828 {
829  for (typename std::list<NodeBinding>::iterator it = myBindings.begin(); it != myBindings.end(); ++it)
830  {
831  if (node == (*it).first)
832  {
833  node->myMembers.erase((*it).second);
834  myBindings.erase(it);
835  return;
836  }
837  }
838 }
839 
840 template<class T> void DtOctreeMember<T>::unbind()
841 {
842  for (typename std::list<NodeBinding>::const_iterator it = myBindings.begin(); it != myBindings.end(); ++it)
843  {
844  (*it).first->myMembers.erase((*it).second);
845  }
846  myBindings.clear();
847 }
848 
849 #endif

Document ID: Generated on Thu Apr 12 03:15:37 EDT 2018 from SVN revision 187986
Copyright © 2005-2018 VT MÄK. All Rights Reserved (www.mak.com)