![]() |
VR-Forces 4.0.4 Class Documentation
|
00001 /******************************************************************************* 00002 ** Copyright (c) 2004 MAK Technologies, Inc. 00003 ** All rights reserved. 00004 *******************************************************************************/ 00005 /******************************************************************************* 00006 ** $RCSfile: spatialSubdivision.h,v $ $Revision: 1.29 $ $State: Exp $ 00007 *******************************************************************************/ 00008 #ifndef spatialSubdivision_H_ 00009 #define spatialSubdivision_H_ 00010 00011 #include "geometry/point.h" 00012 #include "geometry/tdbextent.h" 00013 00014 #include <vlutil/vlConfig.h> 00015 #include <list> 00016 #include <vector> 00017 #include <assert.h> 00018 00019 #include <vlutil/vlPrint.h> 00020 00021 class DtGdbNode; 00022 00023 // class DtSpatialSubdivision: 00024 // 00025 // Instances of DtSpatialSubdivision represent a spatially sorted collection 00026 // of cells, which contain the types specified at creation. Each cell in the 00027 // rectangular area (or rectangular solid if 3D) will contain a container of 00028 // the items referenced in it. 00029 // 00030 // ------------------- 00031 // |\ \ \ 00032 // | \________\________\ 00033 // | |\ \ \ 00034 // | | \ \ \ 00035 // | | \--------\--------\ 00036 // |\| | | | 00037 // | \ | | | 00038 // | |\ | | | 00039 // | | \ | | | 00040 // | | \--------\--------\ 00041 // \| | | | 00042 // \ | | | 00043 // \ | | | 00044 // \ | | | 00045 // \--------\--------\ 00046 // A 2 x 2 x 2 Spatial Subdivision 00047 // 00048 // This class provides a minimal interface to make it easy for users to extend 00049 // the types of elements contained within it by writing examination and modification 00050 // classes outside of this one. Thus no mechanism for examination or 00051 // modification, outside of points, is provided. 00052 // 00053 // This class is *not* threadsafe. 00054 // 00055 // \b Class Invariant: 00056 // A fully constructed spatial subdivision must always respect the following: 00057 // - A positive cell size in any dimension where the number of cells is greater 00058 // than one. 00059 // - The number of cells in each dimension must be greater than or equal to 1 at 00060 // all times. The smallest number of cells in any dimension is 1. If a 00061 // subdivision is created or resized with an extent that is either 00062 // uninitialized or has an empty dimension, the number of cells in that 00063 // dimension is still one, and the cell size will be zero. 00064 // - The same number of cells in the container as equals the dimensions multiplied 00065 // together. 00066 // 00067 template <typename T> 00068 class DtSpatialSubdivision 00069 { 00070 public: 00071 // typedefs for the containers used to hold the contained elements 00072 typedef std::list<T> DtSpatialSubCellType; 00073 typedef typename DtSpatialSubCellType::iterator DtSpatialSubCellIter; 00074 typedef typename DtSpatialSubCellType::const_iterator DtSpatialSubCellConstIter; 00075 00076 // As this is a 3D grid, cells can be addressed by indices as well. 00077 typedef int DtSpatialSubCellIndex; 00078 00079 // Iterators into the spatial subdivision's cells 00080 typedef typename std::vector< DtSpatialSubCellType >::iterator DtSpatialSubIter; 00081 typedef typename std::vector< DtSpatialSubCellType >::const_iterator DtSpatialSubConstIter; 00082 00083 00084 // Intended default constructor 00085 // \throws std::bad_alloc if there is not enough memory to allocate the object 00086 DtSpatialSubdivision(const DtPoint& origin, 00087 unsigned int cellCountX, 00088 unsigned int cellCountY, 00089 unsigned int cellCountZ, 00090 double cellDx, 00091 double cellDy, 00092 double cellDz); 00093 00094 // Cover this extent with the given number of cells. 00095 // \throws std::bad_alloc if there is not enough memory to allocate the object 00096 explicit DtSpatialSubdivision(DtExtent extent, 00097 unsigned int cellCountX, 00098 unsigned int cellCountY, 00099 unsigned int cellCountZ = 1); 00100 00101 // Cover this extent with the given cell sizes (in DB units) 00102 // \throws std::bad_alloc if there is not enough memory to allocate the object 00103 explicit DtSpatialSubdivision(DtExtent extent, 00104 double cellDx, 00105 double cellDy, 00106 double cellDz = -1.0); 00107 00108 // Destructor 00109 virtual ~DtSpatialSubdivision(); 00110 00111 private: 00112 // Copy constructor & Assignment operator - not implemented 00113 DtSpatialSubdivision(const DtSpatialSubdivision& orig); 00114 DtSpatialSubdivision& operator=(const DtSpatialSubdivision& orig); 00115 00116 public: 00117 00118 // Resizes the spatial subdivision to fit the specified extent. This function 00119 // clears the contents of the subdivision, and updates the cell sizes and origin 00120 // with the specified extent. 00121 virtual void setExtent(DtExtent extent); 00122 00123 // Warning: clears all contents! 00124 // Resets the cell counts of the spatial subdivision to the specified values, 00125 // reallocating the memory associated if necessary. 00126 // 00127 // \implementation As an optimization, it will not reallocate if the total 00128 // cell count is the same as before, even if the resolutions are actually 00129 // different. Thus if the previous resolutions were 10,15,1 and the new 00130 // resolutions are 15,10,1, no reallocation will occur. 00131 // 00132 // \note The minimum resolution is 1, which will be used if 0 is specified. 00133 virtual void setResolutions(unsigned int cellCountX, unsigned int cellCountY, 00134 unsigned int cellCountZ = 1); 00135 00136 // Resizes the spatial subdivision to fit the specified extent. This function 00137 // clears the contents of the subdivision, and updates the cell sizes and origin 00138 // with the specified extent. 00139 // This function will \b only reallocate the container of cells when the 00140 // requested cell count total differs from the existing cell count total. 00141 // 00142 // \note Thus if a subdivision is resized from 10,10,1 to 10,1,10, the cells 00143 // will only be cleared, not reallocated. This is meant as a possible 00144 // optimization when it is possible to reuse an existing container. 00145 virtual void resize(DtExtent extent, unsigned int cellCountX, 00146 unsigned int cellCountY, unsigned int cellCountZ); 00147 00148 // Empties the entire spatial subdivision, removing all contents 00149 // \note Does not deallocate the container, just clears the contents 00150 // of the cells. 00151 virtual void clear(); 00152 00153 // Clears the cells referenced by the specified iterators. 00154 // \note The template type must support the clear() function, as 00155 // this function will call clear() on all cells at or between the 00156 // specified iterators. 00157 virtual void clearCell(DtSpatialSubIter& cellIter); 00158 virtual void clearCell(DtSpatialSubIter& startIter, DtSpatialSubIter& endIter); 00159 00160 // \return A boolean indicating whether or not anything is contained 00161 // in the subdivision 00162 virtual bool empty() const; 00163 00164 // \return the total number of cells in the subdivision 00165 virtual unsigned int size() const; 00166 00167 // 00168 // Accessors 00169 // 00170 // \return iterators to the first and last cells respectively. 00172 virtual DtSpatialSubIter begin(); 00173 virtual DtSpatialSubConstIter begin() const; 00174 00175 virtual DtSpatialSubIter end(); 00176 virtual DtSpatialSubConstIter end() const; 00178 00179 // \return an iterator to the spatial subdivision cell at the specified index, 00180 // if the index is valid. 00181 // \note the results are undefined if the index is outside of the range of the 00182 // spatial subdivision's cells. (technically, this just passes the index 00183 // down to the std::vector at() call, so it will throw a range error exception.) 00184 // 00186 virtual DtSpatialSubCellType& at(DtSpatialSubCellIndex index); 00187 virtual const DtSpatialSubCellType& at(DtSpatialSubCellIndex index) const; 00188 00189 virtual DtSpatialSubCellType& at(DtSpatialSubCellIndex xIndex, 00190 DtSpatialSubCellIndex yIndex, DtSpatialSubCellIndex zIndex); 00191 virtual const DtSpatialSubCellType& at(DtSpatialSubCellIndex xIndex, 00192 DtSpatialSubCellIndex yIndex, DtSpatialSubCellIndex zIndex) const; 00194 00195 // \return an iterator to the spatial subdivision cell at the specified index, 00196 // \note Does \b not check if the index is valid or not. 00198 virtual DtSpatialSubCellType& operator[](DtSpatialSubCellIndex index); 00199 virtual const DtSpatialSubCellType& operator[](DtSpatialSubCellIndex index) const; 00201 00202 00203 // \return a reference (const or not) to the first or last spatial subdivision cell 00204 // in the spatial subdivision. 00205 // \note User \b must ensure the spatial subdivision is \b not empty before 00206 // calling these functions. 00208 virtual DtSpatialSubCellType& front(); 00209 virtual const DtSpatialSubCellType& front() const; 00210 00211 virtual DtSpatialSubCellType& back(); 00212 virtual const DtSpatialSubCellType& back() const; 00214 00215 // Get/Set the origin of the spatial index (the point of lowest X, Y, Z) 00217 virtual const DtPoint& origin() const; 00218 virtual void setOrigin(const DtPoint& newOrigin); 00220 00221 // \return the cell count in the specified dimension. 00223 virtual unsigned int cellCountX() const; 00224 virtual unsigned int cellCountY() const; 00225 virtual unsigned int cellCountZ() const; 00227 00228 // \return the size of each cell in the specified dimension. 00230 virtual double cellDx() const; 00231 virtual double cellDy() const; 00232 virtual double cellDz() const; 00234 00235 // Get the cell that contains the given coordinate if the coordinate lies 00236 // within the spatial subdivision. 00237 // 00238 // If the specified point lies within the spatial subdivision, the 00239 // function sets the specified point to point to the cell and returns true. 00240 // 00241 // \return A boolean indicating whether or not the point lies within the 00242 // spatial subdivision. If it does not, the cell pointer is not set. 00244 virtual bool cell(double x, double y, double z, DtSpatialSubCellType*& cell); 00245 virtual bool cell(double x, double y, double z, const DtSpatialSubCellType*& cell) const; 00246 00247 virtual bool cell(const DtPoint& containing, DtSpatialSubCellType*& cell); 00248 virtual bool cell(const DtPoint& containing, const DtSpatialSubCellType*& cell) const; 00250 00251 // Given an offset vector (local coordinate - origin), return the cell 00252 // index values. 00253 // 00254 // \param xIndex The index in X, of the specified point. Set by the function. 00255 // \param yIndex The index in Y, of the specified point. Set by the function. 00256 // \param zIndex The index in Z, of the specified point. Set by the function. 00257 // 00258 // \note There is no guarantee that the resulting indices are inside the spatial 00259 // subdivision. 00260 virtual void offsetToIndices(const DtPoint& offset, DtSpatialSubCellIndex& xIndex, 00261 DtSpatialSubCellIndex& yIndex, DtSpatialSubCellIndex& zIndex) const; 00262 00263 // Check if the given index values are within the spatial subdivision 00264 // \return a boolean signifying whether or not the specified index/indices 00265 // are valid (refer to cells inside the spatial subdivision) 00266 virtual bool indexIsValid(DtSpatialSubCellIndex index) const; 00267 virtual bool indicesAreValid(DtSpatialSubCellIndex xIndex, 00268 DtSpatialSubCellIndex yIndex, DtSpatialSubCellIndex zIndex) const; 00269 00270 virtual int sizeInBytes() const; 00271 00272 protected: 00273 // Tests the class invariant. Called at the beginning of every public 00274 // member function and at the end of all non-const public member functions. 00275 bool testInvariant() const; 00276 00277 protected: 00278 // \return the inverse of the size of each cell in the specified dimension. 00279 // \note If the dimension is 0, then the function returns 0.0 as a default. 00280 // \note These should not be called when the dimension is 0, even though they 00281 // return 0.0 to be safe. 00283 double inverseCellDx() const; 00284 double inverseCellDy() const; 00285 double inverseCellDz() const; 00287 00289 // Calculates the minimum and maximum sizes, in each dimension, of any offset 00290 // that is to be translated into an index. An offset that contains any 00291 // dimension larger or smaller (negative) than these will result in rollover 00292 // problems and the wrong index being calculated. Since this is a function 00293 // of std::limits<>max() and the cell delta in the appropriate dimension 00294 void calculateMinMaxOffsets(); 00295 00296 // Calculates the inverse of the cell deltas in each dimension. Used every time 00297 // an index is calculated from an offset. 00298 void calculateInverseDeltas(); 00299 00300 DtPoint myOrigin; 00301 00302 unsigned int myCellCountX; 00303 unsigned int myCellCountY; 00304 unsigned int myCellCountZ; 00305 00306 double myCellDx; 00307 double myCellDy; 00308 double myCellDz; 00309 00310 // These are used instead of dividing when calculating indexes from an offset 00311 double myInverseCellDx; 00312 double myInverseCellDy; 00313 double myInverseCellDz; 00314 00315 // These are the maximum sizes, in each dimension, of any offset that is to 00316 // be translated into and index. An offset that contains any dimension larger 00317 // than these will result in rollover problems and the wrong index being 00318 // calculated. 00319 double myMaxOffsetX; 00320 double myMaxOffsetY; 00321 double myMaxOffsetZ; 00322 00323 double myMinOffsetX; 00324 double myMinOffsetY; 00325 double myMinOffsetZ; 00326 00327 std::vector< DtSpatialSubCellType > myCells; 00328 }; 00329 00330 00331 //------------------------------------------------------ 00332 // INLINE METHODS 00333 //------------------------------------------------------ 00334 // include the inline code 00335 #define SPATIALSUBDIVISION_HEADER 00336 #include "geometry/spatialSubdivision.inl" 00337 #undef SPATIALSUBDIVISION_HEADER 00338 00339 #endif