Gizmo3D

gzSpatial.h

Go to the documentation of this file.
00001 // *****************************************************************************
00002 // File         : gzSpatial.h
00003 // Module       : gzSpatial
00004 // Description  : Class definition of spatial data storage templates
00005 // Author       : Anders Modén      
00006 // Product      : GizmoBase 2.1.1
00007 //      
00008 // Copyright © 2003- Saab Training Systems AB, Sweden
00009 //          
00010 // NOTE:    GizmoBase is a platform abstraction utility layer for C++. It contains 
00011 //          design patterns and C++ solutions for the advanced programmer.
00012 //
00013 //
00014 // Revision History...                          
00015 //                                  
00016 // Who  Date    Description                     
00017 //                                  
00018 // AMO  050222  Created file 
00019 //
00020 // ******************************************************************************
00021 
00022 #ifndef __GZ_SPATIAL_H__
00023 #define __GZ_SPATIAL_H__
00024 
00030 #include "gzBasicTypes.h"
00031 #include "gzXYZ.h"
00032 
00033 // Forward decl
00034 template <class T> class gzSpatialDataIterator;
00035 
00036 //******************************************************************************
00037 // Class    : gzSpatialData
00038 //                                  
00039 // Purpose  : Template for spatial located data
00040 //                                  
00041 // Notes    : - 
00042 //                                  
00043 // Revision History...                          
00044 //                                  
00045 // Who  Date    Description                     
00046 //                                  
00047 // AMO  050222  Created 
00048 //                                  
00049 //******************************************************************************
00050 template <class T> class gzSpatialData
00051 {
00052 public:
00053 
00054     gzSpatialData(const gzDoubleXYZ& position_1=gzDoubleXYZ(0,0,0) , const gzDoubleXYZ& position_2=gzDoubleXYZ(1,1,1),gzULong divisions=3,gzULong splitItems=0);
00055 
00056     ~gzSpatialData();
00057 
00058     gzVoid      insert(const gzDoubleXYZ &position,const T &data,const gzDoubleXYZ &delta=gzDoubleXYZ(0,0,0));
00059 
00060     gzULong     entries();
00061 
00062     gzVoid      clear();
00063 
00064 private:
00065 
00066     friend class gzSpatialDataIterator<T>;
00067 
00068     class _item;
00069 
00070     class _holder
00071     {
00072     public:
00073 
00074         _holder(const gzDoubleXYZ &min , const gzDoubleXYZ &max,_holder *parent,gzULong index):m_min(min),m_max(max),m_parent(parent),m_subspace(NULL),m_index(index)
00075         {
00076             m_itemList.reuseLinks(TRUE);
00077         }
00078 
00079         ~_holder()
00080         {
00081             if(m_subspace)
00082             {
00083                 for(gzULong i=0;i<m_size;i++)
00084                     if(m_subspace[i])
00085                         delete m_subspace[i];
00086 
00087                 delete [] m_subspace;
00088             }
00089 
00090             m_itemList.clearAndDestroy();
00091         }
00092 
00093         gzVoid createSubspace(gzULong divisions)
00094         {
00095             if(!m_subspace)
00096             {
00097                 m_size=divisions*divisions*divisions;
00098                 m_firstIndex=m_size;
00099 
00100                 m_subspace=new _holder *[m_size];
00101                 memset(m_subspace,0,m_size*sizeof(_holder *));
00102             }
00103         }
00104 
00105         gzList<_item>       m_itemList;
00106         _holder **          m_subspace;
00107         _holder *           m_parent;
00108         gzULong             m_index;
00109         gzDoubleXYZ         m_max;
00110         gzDoubleXYZ         m_min;
00111         gzULong             m_size;
00112         gzULong             m_firstIndex;
00113     };
00114 
00115     class _item
00116     {
00117     public:
00118 
00119         T                   m_data;
00120         gzDoubleXYZ         m_position;
00121         gzDoubleXYZ         m_delta;
00122     };
00123 
00124     _holder *       m_space;
00125 
00126     gzDoubleXYZ         m_minPosition;
00127 
00128     gzDoubleXYZ         m_stepping;
00129 
00130     gzULong         m_divisions;
00131 
00132     gzULong         m_splitItems;
00133 
00134     gzULong         m_entries;
00135 };
00136 
00137 template <class T> inline gzSpatialData<T>::gzSpatialData(const gzDoubleXYZ& position_1 , const gzDoubleXYZ& position_2,gzULong divisions,gzULong splitItems)
00138 {
00139     m_minPosition=gzDoubleXYZ(gzMin(position_1.x,position_2.x),gzMin(position_1.y,position_2.y),gzMin(position_1.z,position_2.z));
00140 
00141     m_stepping=(gzDoubleXYZ(gzMax(position_1.x,position_2.x),gzMax(position_1.y,position_2.y),gzMax(position_1.z,position_2.z))-m_minPosition)/divisions;
00142 
00143     if(!m_stepping.x)
00144         m_stepping.x=1;
00145 
00146     if(!m_stepping.y)
00147         m_stepping.y=1;
00148 
00149     if(!m_stepping.z)
00150         m_stepping.z=1;
00151 
00152     m_divisions=divisions;
00153 
00154     m_splitItems=splitItems;
00155 
00156     m_space=NULL;
00157 
00158     m_entries=0;
00159 }
00160 
00161 template <class T> inline gzSpatialData<T>::~gzSpatialData()
00162 {
00163     if(m_space)
00164         delete m_space;
00165 }
00166 
00167 template <class T> inline gzVoid gzSpatialData<T>::clear()
00168 {
00169     if(m_space)
00170         delete m_space;
00171 
00172     m_space=NULL;
00173     m_entries=0;
00174 }
00175 
00176 template <class T> inline gzULong gzSpatialData<T>::entries()
00177 {
00178     return m_entries;
00179 }
00180 
00181 template <class T> inline gzVoid gzSpatialData<T>::insert(const gzDoubleXYZ &position,const T &data,const gzDoubleXYZ &delta)
00182 {
00183     if(     ((position.x+delta.x)>=(m_minPosition.x+m_divisions*m_stepping.x))  // We are located outside max extent. Need to rebuild tree
00184         ||  ((position.y+delta.y)>=(m_minPosition.y+m_divisions*m_stepping.y))
00185         ||  ((position.z+delta.z)>=(m_minPosition.z+m_divisions*m_stepping.z)) )
00186     {
00187         _holder *old=m_space;
00188         gzULong index=(m_divisions-1)/2;
00189 
00190         gzULong mixIndex=index*(m_divisions*m_divisions)+index*m_divisions+index;
00191         
00192 
00193         m_stepping=m_stepping*m_divisions;
00194         m_minPosition=m_minPosition-m_stepping*index;
00195 
00196         m_space=new _holder(m_minPosition,m_minPosition+m_stepping*m_divisions,NULL,0);
00197         
00198         if(old)
00199         {
00200             m_space->createSubspace(m_divisions);
00201             m_space->m_subspace[mixIndex]=old;
00202             m_space->m_firstIndex=mixIndex;
00203             old->m_parent=m_space;
00204             old->m_index=mixIndex;
00205         }
00206 
00207         insert(position,data,delta);
00208         return;
00209     }
00210 
00211     if(     ((position.x-delta.x)<m_minPosition.x)
00212         ||  ((position.y-delta.y)<m_minPosition.y)
00213         ||  ((position.z-delta.z)<m_minPosition.z)  )
00214     {
00215         _holder *old=m_space;
00216         gzULong index=m_divisions/2;
00217         gzULong mixIndex=index*(m_divisions*m_divisions)+index*m_divisions+index;
00218         
00219         m_stepping=m_stepping*m_divisions;
00220         m_minPosition=m_minPosition-m_stepping*index;
00221 
00222         m_space=new _holder(m_minPosition,m_minPosition+m_stepping*m_divisions,NULL,0);
00223 
00224         if(old)
00225         {
00226             m_space->createSubspace(m_divisions);
00227             m_space->m_subspace[mixIndex]=old;
00228             m_space->m_firstIndex=mixIndex;
00229             old->m_parent=m_space;
00230             old->m_index=mixIndex;
00231         }
00232     
00233         insert(position,data,delta);
00234         return;
00235     }
00236 
00237     gzULong index_x=0,index_y=0,index_z=0;
00238 
00239     _holder *holder=m_space,*parent=NULL;
00240 
00241     gzDoubleXYZ stepping=m_stepping;
00242     gzDoubleXYZ minPosition=m_minPosition;
00243 
00244     while(holder)
00245     {
00246         index_x=(gzULong)((position.x-delta.x-minPosition.x)/stepping.x);
00247         index_y=(gzULong)((position.y-delta.y-minPosition.y)/stepping.y);
00248         index_z=(gzULong)((position.z-delta.z-minPosition.z)/stepping.z);
00249 
00250         if( ((gzULong)((position.x+delta.x-minPosition.x)/stepping.x))!=index_x)
00251             break;
00252 
00253         if( ((gzULong)((position.y+delta.y-minPosition.y)/stepping.y))!=index_y)
00254             break;
00255 
00256         if( ((gzULong)((position.z+delta.z-minPosition.z)/stepping.z))!=index_z)
00257             break;
00258 
00259         if(holder->m_itemList.entries()>=m_splitItems)  // go to subchild
00260         {
00261             minPosition.x=minPosition.x+index_x*stepping.x;
00262             minPosition.y=minPosition.y+index_y*stepping.y;
00263             minPosition.z=minPosition.z+index_z*stepping.z;
00264 
00265             stepping=stepping/m_divisions;
00266 
00267             if(!holder->m_subspace)
00268                 holder->createSubspace(m_divisions);
00269 
00270 
00271             parent=holder;
00272             holder=holder->m_subspace[index_x*(m_divisions*m_divisions)+index_y*m_divisions+index_z];
00273 
00274             continue;
00275         }
00276         else
00277             break;
00278     }
00279 
00280     if(!holder)
00281     {
00282         gzULong mixIndex=index_x*(m_divisions*m_divisions)+index_y*m_divisions+index_z;
00283 
00284         holder=new _holder(minPosition,minPosition+stepping*m_divisions,parent,mixIndex);
00285 
00286         if(!parent)
00287             m_space=holder;
00288         else
00289         {
00290             if(parent->m_firstIndex>mixIndex)
00291                 parent->m_firstIndex=mixIndex;
00292             parent->m_subspace[mixIndex]=holder;
00293         }
00294     }
00295 
00296     // Insert item
00297 
00298     _item *item=new _item;
00299 
00300     holder->m_itemList.insert(item);
00301 
00302     item->m_data=data;
00303     item->m_position=position;
00304     item->m_delta=delta;
00305 
00306     ++m_entries;
00307 }
00308 
00309 
00310 //******************************************************************************
00311 // Class    : gzSpatialDataIterator
00312 //                                  
00313 // Purpose  : Box iterator for spatial located data
00314 //                                  
00315 // Notes    : - 
00316 //                                  
00317 // Revision History...                          
00318 //                                  
00319 // Who  Date    Description                     
00320 //                                  
00321 // AMO  050222  Created 
00322 //                                  
00323 //******************************************************************************
00324 template <class T> class gzSpatialDataIterator
00325 {
00326 public:
00327 
00328     gzSpatialDataIterator(gzSpatialData<T> &owner,const gzDoubleXYZ& position=gzDoubleXYZ(0,0,0) , const gzDoubleXYZ& delta=gzDoubleXYZ(DBL_MAX,DBL_MAX,DBL_MAX));
00329 
00330     ~gzSpatialDataIterator();
00331 
00332     gzBool operator()(T &data,gzDoubleXYZ *pos=NULL,gzDoubleXYZ *delta=NULL);
00333 
00334     gzVoid remove();
00335 
00336 private:
00337 
00338     gzSpatialData<T> &          m_owner;
00339 
00340     const gzDoubleXYZ           m_position;
00341     const gzDoubleXYZ           m_delta;
00342     const gzDouble              dx_p,dy_p,dz_p,dx_m,dy_m,dz_m;
00343     
00344     typename gzSpatialData<T>::_holder *                m_currentHolder;
00345     gzULong                                             m_maxIndex;
00346     gzListIterator<typename gzSpatialData<T>::_item>    m_iterator;
00347     gzBool                                              m_validIterator;
00348 };
00349 
00350 template <class T> inline gzSpatialDataIterator<T>::gzSpatialDataIterator(gzSpatialData<T> &owner,const gzDoubleXYZ& position , const gzDoubleXYZ& delta)
00351         :m_owner(owner),
00352         m_position(position),
00353         m_delta(delta),
00354         m_iterator(NULL),
00355         dx_m(position.x-delta.x),
00356         dy_m(position.y-delta.y),
00357         dz_m(position.z-delta.z),
00358         dx_p(position.x+delta.x),
00359         dy_p(position.y+delta.y),
00360         dz_p(position.z+delta.z)
00361 {
00362     m_maxIndex=m_owner.m_divisions*m_owner.m_divisions*m_owner.m_divisions;
00363     m_currentHolder=m_owner.m_space;
00364     m_validIterator=FALSE;
00365 }
00366 
00367 template <class T> inline gzSpatialDataIterator<T>::~gzSpatialDataIterator()
00368 {
00369 }
00370 
00371 template <class T> inline gzVoid gzSpatialDataIterator<T>::remove()
00372 {
00373     if(m_validIterator)
00374     {
00375         delete m_iterator.remove();
00376         --m_owner.m_entries;
00377     }
00378 }
00379 
00380 template <class T> inline gzBool gzSpatialDataIterator<T>::operator()(T &data,gzDoubleXYZ *pos,gzDoubleXYZ *delta)
00381 {
00382     if(!m_currentHolder)        // Assume a valid holder
00383         return FALSE;
00384 
00385     gzBool isValid;
00386 
00387     typename gzSpatialData<T>::_holder *parent;
00388     typename gzSpatialData<T>::_item *item;
00389 
00390     gzULong offset;
00391 
00392     while(TRUE)
00393     {
00394         // Check to see if holder is valid first time
00395 
00396         if(!m_validIterator)
00397         {
00398             isValid=TRUE;
00399 
00400             if( m_currentHolder->m_max.x < dx_m ) // left of us
00401                 isValid=FALSE;
00402             else if( m_currentHolder->m_min.x > dx_p ) // right of us
00403                 isValid=FALSE;
00404             else if( m_currentHolder->m_max.y < dy_m) // under us
00405                 isValid=FALSE;
00406             else if( m_currentHolder->m_min.y > dy_p) // top of us
00407                 isValid=FALSE;
00408             else if( m_currentHolder->m_max.z < dz_m) 
00409                 isValid=FALSE;
00410             else if( m_currentHolder->m_min.z > dz_p) 
00411                 isValid=FALSE;
00412 
00413             if(!isValid)
00414             {
00415                 // Go to next neighbour
00416 
00417                 while(TRUE)
00418                 {
00419                     if(!m_currentHolder->m_parent)  // check if we hit top
00420                     {
00421                         return FALSE;
00422                     }
00423 
00424                     offset=m_currentHolder->m_index+1;
00425 
00426                     parent=NULL;
00427 
00428                     while(offset<m_maxIndex)
00429                     {
00430                         parent=m_currentHolder->m_parent->m_subspace[offset];
00431 
00432                         if(parent)
00433                         {
00434                             m_currentHolder=parent;
00435                             break;
00436                         }
00437 
00438                         ++offset;
00439                     }
00440 
00441                     if(parent)
00442                         break;
00443 
00444                     // We have no neighbour; check parent neighbour
00445                     m_currentHolder=m_currentHolder->m_parent;
00446                 }
00447 
00448                 // we have a new holder
00449 
00450                 continue;
00451             }
00452 
00453             // Set up valid iterator for holder
00454 
00455             m_validIterator=TRUE;
00456             m_iterator.setList(m_currentHolder->m_itemList);
00457         }
00458 
00459         // Iterate over list for a valid holder
00460 
00461         item=m_iterator();
00462 
00463         if(!item)       // End of list
00464         {
00465             // Clean up
00466             m_validIterator=FALSE;
00467 
00468             // go to first sibling
00469 
00470             if(m_currentHolder->m_subspace)
00471             {
00472                 // Select first child
00473                 m_currentHolder=m_currentHolder->m_subspace[m_currentHolder->m_firstIndex];
00474             }
00475             else
00476             {
00477                 // go to next neighour
00478 
00479                 while(TRUE)
00480                 {
00481                     if(!m_currentHolder->m_parent)  // check if we hit top
00482                     {
00483                         return FALSE;
00484                     }
00485 
00486                     offset=m_currentHolder->m_index+1;
00487 
00488                     parent=NULL;
00489 
00490                     while(offset<m_maxIndex)
00491                     {
00492                         parent=m_currentHolder->m_parent->m_subspace[offset];
00493 
00494                         if(parent)
00495                         {
00496                             m_currentHolder=parent;
00497                             break;
00498                         }
00499 
00500                         ++offset;
00501                     }
00502 
00503                     if(parent)
00504                         break;
00505 
00506                     // We have no neighbour; check parent neighbour
00507                     m_currentHolder=m_currentHolder->m_parent;
00508                 }
00509 
00510                 // we have a new holder
00511 
00512                 continue;
00513             }
00514         }
00515         else    // Check to se if valid
00516         {
00517             if( (item->m_position.x+item->m_delta.x) < dx_m ) // left of us
00518                 continue;
00519 
00520             if( (item->m_position.x-item->m_delta.x) > dx_p ) // right of us
00521                 continue;
00522 
00523             if( (item->m_position.y+item->m_delta.y) < dy_m ) // bottom of us
00524                 continue;
00525 
00526             if( (item->m_position.y-item->m_delta.y) > dy_p ) // top of us
00527                 continue;
00528 
00529             if( (item->m_position.z+item->m_delta.z) < dz_m ) // left of us
00530                 continue;
00531 
00532             if( (item->m_position.z-item->m_delta.z) > dz_p ) // right of us
00533                 continue;
00534 
00535             // We have an intersection
00536 
00537             if(pos)
00538                 *pos=item->m_position;
00539 
00540             if(delta)
00541                 *delta=item->m_delta;
00542 
00543             data=item->m_data;
00544 
00545             return TRUE;
00546         }
00547     } 
00548 }
00549 
00550 #endif // __GZ_SPATIAL_H__

Documentation for Gizmo3D generated at Wed Feb 20 11:54:10 2008 by   Saab Training Systems AB, ¸ (c) 2003-and beyond