00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef VCGLIB_SPATIAL_HASHING
00025 #define VCGLIB_SPATIAL_HASHING
00026
00027 #include <vcg/space/index/grid_util.h>
00028 #include <vcg/space/index/grid_closest.h>
00029 #include<unordered_map>
00030
00031 #include <vector>
00032 #include <algorithm>
00033
00034 namespace vcg{
00035
00036
00037
00038
00039 struct HashFunctor : public std::unary_function<Point3i, size_t>
00040 {
00041 enum
00042 {
00043 bucket_size = 4,
00044 min_buckets = 8
00045 };
00046
00047 size_t operator()(const Point3i &p) const
00048 {
00049 const size_t _HASH_P0 = 73856093u;
00050 const size_t _HASH_P1 = 19349663u;
00051 const size_t _HASH_P2 = 83492791u;
00052
00053 return size_t(p.V(0))*_HASH_P0 ^ size_t(p.V(1))*_HASH_P1 ^ size_t(p.V(2))*_HASH_P2;
00054 }
00055
00056 bool operator()(const Point3i &s1, const Point3i &s2) const
00057 {
00058 return (s1 < s2);
00059 }
00060 };
00061
00062
00063
00064
00070 template < typename ObjType,class FLT=double>
00071 class SpatialHashTable:public BasicGrid<FLT>, public SpatialIndex<ObjType,FLT>
00072 {
00073
00074 public:
00075 typedef SpatialHashTable SpatialHashType;
00076 typedef ObjType* ObjPtr;
00077 typedef typename ObjType::ScalarType ScalarType;
00078 typedef Point3<ScalarType> CoordType;
00079 typedef typename BasicGrid<FLT>::Box3x Box3x;
00080
00081
00082
00083
00084
00085 typedef typename std::unordered_multimap<Point3i, ObjType *, HashFunctor> HashType;
00086 typedef typename HashType::iterator HashIterator;
00087 HashType hash_table;
00088
00089
00090
00091 std::vector<Point3i> AllocatedCells;
00092
00093
00094
00095
00096 struct CellIterator
00097 {
00098 CellIterator(){}
00099 HashIterator t;
00100 ObjPtr &operator *(){return (t->second); }
00101 ObjPtr operator *() const {return (t->second); }
00102 bool operator != (const CellIterator & p) const {return t!=p.t;}
00103 void operator ++() {t++;}
00104 };
00105
00106 inline bool Empty() const
00107 {
00108 return hash_table.empty();
00109 }
00110
00111 size_t CellSize(const Point3i &cell)
00112 {
00113 return hash_table.count(cell);
00114 }
00115
00116 inline bool EmptyCell(const Point3i &cell) const
00117 {
00118 return hash_table.find(cell) == hash_table.end();
00119 }
00120
00121 void UpdateAllocatedCells()
00122 {
00123 AllocatedCells.clear();
00124 if(hash_table.empty()) return;
00125 AllocatedCells.push_back(hash_table.begin()->first);
00126 for(HashIterator fi=hash_table.begin();fi!=hash_table.end();++fi)
00127 {
00128 if(AllocatedCells.back()!=fi->first) AllocatedCells.push_back(fi->first);
00129 }
00130 }
00131 protected:
00132
00134 void InsertObject(ObjType* s, const Point3i &cell)
00135 {
00136
00137 hash_table.insert(typename HashType::value_type(cell, s));
00138 }
00139
00141 void RemoveCell(const Point3i &)
00142 {
00143 }
00144
00145
00146 bool RemoveObject(ObjType* s, const Point3i &cell)
00147 {
00148 std::pair<HashIterator,HashIterator> CellRange = hash_table.equal_range(cell);
00149 CellIterator first; first.t=CellRange.first;
00150 CellIterator end; end.t=CellRange.second;
00151 for(CellIterator ci = first; ci!=end;++ci)
00152 {
00153 if (*ci == s)
00154 {
00155 hash_table.erase(ci.t);
00156 return true;
00157 }
00158 }
00159 return false;
00160 }
00161
00162 public:
00163
00164 vcg::Box3i Add( ObjType* s)
00165 {
00166 Box3<ScalarType> b;
00167 s->GetBBox(b);
00168 vcg::Box3i bb;
00169 this->BoxToIBox(b,bb);
00170
00171 for (int i=bb.min.X();i<=bb.max.X();i++)
00172 for (int j=bb.min.Y();j<=bb.max.Y();j++)
00173 for (int k=bb.min.Z();k<=bb.max.Z();k++)
00174 InsertObject(s,vcg::Point3i(i,j,k));
00175
00176 return bb;
00177 }
00178
00180
00181 bool RemoveCell(ObjType* s)
00182 {
00183 Point3i pi;
00184 PToIP(s->cP(),pi);
00185 std::pair<HashIterator,HashIterator> CellRange = hash_table.equal_range(pi);
00186 hash_table.erase(CellRange.first,CellRange.second);
00187 return true;
00188 }
00189
00190 int CountInSphere(const Point3<ScalarType> &p, const ScalarType radius, std::vector<HashIterator> &inSphVec)
00191 {
00192 Box3x b(p-CoordType(radius,radius,radius),p+CoordType(radius,radius,radius));
00193 vcg::Box3i bb;
00194 this->BoxToIBox(b,bb);
00195 ScalarType r2=radius*radius;
00196 inSphVec.clear();
00197
00198 for (int i=bb.min.X();i<=bb.max.X();i++)
00199 for (int j=bb.min.Y();j<=bb.max.Y();j++)
00200 for (int k=bb.min.Z();k<=bb.max.Z();k++)
00201 {
00202 std::pair<HashIterator,HashIterator> CellRange = hash_table.equal_range(Point3i(i,j,k));
00203 for(HashIterator hi = CellRange.first; hi!=CellRange.second;++hi)
00204 {
00205 if(SquaredDistance(p,hi->second->cP()) <= r2)
00206 inSphVec.push_back(hi);
00207 }
00208 }
00209 return inSphVec.size();
00210 }
00211
00212 int RemoveInSphere(const Point3<ScalarType> &p, const ScalarType radius)
00213 {
00214 std::vector<HashIterator> inSphVec;
00215 CountInSphere(p,radius,inSphVec);
00216 for(typename std::vector<HashIterator>::iterator vi=inSphVec.begin(); vi!=inSphVec.end();++vi)
00217 hash_table.erase(*vi);
00218
00219 return inSphVec.size();
00220 }
00221
00222 template<class DistanceFunctor>
00223 int RemoveInSphereNormal(const Point3<ScalarType> &p, const Point3<ScalarType> &n, DistanceFunctor &DF, const ScalarType radius)
00224 {
00225 Box3x b(p-CoordType(radius,radius,radius),p+CoordType(radius,radius,radius));
00226 vcg::Box3i bb;
00227 this->BoxToIBox(b,bb);
00228 int cnt=0;
00229 std::vector<HashIterator> toDel;
00230
00231 for (int i=bb.min.X();i<=bb.max.X();i++)
00232 for (int j=bb.min.Y();j<=bb.max.Y();j++)
00233 for (int k=bb.min.Z();k<=bb.max.Z();k++)
00234 {
00235 std::pair<HashIterator,HashIterator> CellRange = hash_table.equal_range(Point3i(i,j,k));
00236 for(HashIterator hi = CellRange.first; hi!=CellRange.second;++hi)
00237 {
00238 if(DF(p,n,hi->second->cP(),hi->second->cN()) <= radius)
00239 {
00240 cnt++;
00241 toDel.push_back(hi);
00242 }
00243 }
00244 }
00245 for(typename std::vector<HashIterator>::iterator vi=toDel.begin(); vi!=toDel.end();++vi)
00246 hash_table.erase(*vi);
00247
00248 return cnt;
00249 }
00250
00251
00252
00253
00254 void RemovePunctual( ObjType *s)
00255 {
00256 Point3i pi;
00257 PToIP(s->cP(),pi);
00258 std::pair<HashIterator,HashIterator> CellRange = hash_table.equal_range(pi);
00259 for(HashIterator hi = CellRange.first; hi!=CellRange.second;++hi)
00260 {
00261 if (hi->second == s)
00262 {
00263 hash_table.erase(hi);
00264 return;
00265 }
00266 }
00267 }
00268
00269 void Remove( ObjType* s)
00270 {
00271 Box3<ScalarType> b;
00272 s->GetBBox(b);
00273 vcg::Box3i bb;
00274 BoxToIBox(b,bb);
00275
00276 for (int i=bb.min.X();i<=bb.max.X();i++)
00277 for (int j=bb.min.Y();j<=bb.max.Y();j++)
00278 for (int k=bb.min.Z();k<=bb.max.Z();k++)
00279 RemoveObject(s,vcg::Point3i(i,j,k));
00280 }
00281
00283 void InitEmpty(const Box3x &_bbox, vcg::Point3i grid_size)
00284 {
00285 Box3x b;
00286 Box3x &bbox = this->bbox;
00287 CoordType &dim = this->dim;
00288 Point3i &siz = this->siz;
00289 CoordType &voxel = this->voxel;
00290
00291 assert(!_bbox.IsNull());
00292 bbox=_bbox;
00293 dim = bbox.max - bbox.min;
00294 assert((grid_size.V(0)>0)&&(grid_size.V(1)>0)&&(grid_size.V(2)>0));
00295 siz=grid_size;
00296
00297 voxel[0] = dim[0]/siz[0];
00298 voxel[1] = dim[1]/siz[1];
00299 voxel[2] = dim[2]/siz[2];
00300 hash_table.clear();
00301 }
00302
00304 template <class OBJITER>
00305 void Set(const OBJITER & _oBegin, const OBJITER & _oEnd, const Box3x &_bbox=Box3x() )
00306 {
00307 OBJITER i;
00308 Box3x b;
00309 Box3x &bbox = this->bbox;
00310 CoordType &dim = this->dim;
00311 Point3i &siz = this->siz;
00312 CoordType &voxel = this->voxel;
00313
00314 int _size=(int)std::distance<OBJITER>(_oBegin,_oEnd);
00315 if(!_bbox.IsNull()) this->bbox=_bbox;
00316 else
00317 {
00318 for(i = _oBegin; i!= _oEnd; ++i)
00319 {
00320 (*i).GetBBox(b);
00321 this->bbox.Add(b);
00322 }
00324 bbox.Offset(bbox.Diag()/100.0) ;
00325 }
00326
00327 dim = bbox.max - bbox.min;
00328 BestDim( _size, dim, siz );
00329
00330 voxel[0] = dim[0]/siz[0];
00331 voxel[1] = dim[1]/siz[1];
00332 voxel[2] = dim[2]/siz[2];
00333
00334 for(i = _oBegin; i!= _oEnd; ++i)
00335 Add(&(*i));
00336 }
00337
00338
00340 void GridReal( const Point3<ScalarType> & p, CellIterator & first, CellIterator & last )
00341 {
00342 vcg::Point3i _c;
00343 this->PToIP(p,_c);
00344 Grid(_c,first,last);
00345 }
00346
00348 void Grid( int x,int y,int z, CellIterator & first, CellIterator & last )
00349 {
00350 this->Grid(vcg::Point3i(x,y,z),first,last);
00351 }
00352
00354 void Grid( const Point3i & _c, CellIterator & first, CellIterator & end )
00355 {
00356 std::pair<HashIterator,HashIterator> CellRange = hash_table.equal_range(_c);
00357 first.t=CellRange.first;
00358 end.t=CellRange.second;
00359 }
00360
00361 void Clear()
00362 {
00363 hash_table.clear();
00364 AllocatedCells.clear();
00365 }
00366
00367
00368 template <class OBJPOINTDISTFUNCTOR, class OBJMARKER>
00369 ObjPtr GetClosest(OBJPOINTDISTFUNCTOR & _getPointDistance, OBJMARKER & _marker,
00370 const CoordType & _p, const ScalarType & _maxDist,ScalarType & _minDist, CoordType & _closestPt)
00371 {
00372 return (vcg::GridClosest<SpatialHashType,OBJPOINTDISTFUNCTOR,OBJMARKER>(*this,_getPointDistance,_marker, _p,_maxDist,_minDist,_closestPt));
00373 }
00374
00375
00376 template <class OBJPOINTDISTFUNCTOR, class OBJMARKER, class OBJPTRCONTAINER,class DISTCONTAINER, class POINTCONTAINER>
00377 unsigned int GetKClosest(OBJPOINTDISTFUNCTOR & _getPointDistance,OBJMARKER & _marker,
00378 const unsigned int _k, const CoordType & _p, const ScalarType & _maxDist,OBJPTRCONTAINER & _objectPtrs,
00379 DISTCONTAINER & _distances, POINTCONTAINER & _points)
00380 {
00381 return (vcg::GridGetKClosest<SpatialHashType,
00382 OBJPOINTDISTFUNCTOR,OBJMARKER,OBJPTRCONTAINER,DISTCONTAINER,POINTCONTAINER>
00383 (*this,_getPointDistance,_marker,_k,_p,_maxDist,_objectPtrs,_distances,_points));
00384 }
00385
00386 template <class OBJPOINTDISTFUNCTOR, class OBJMARKER, class OBJPTRCONTAINER, class DISTCONTAINER, class POINTCONTAINER>
00387 unsigned int GetInSphere(OBJPOINTDISTFUNCTOR & _getPointDistance,
00388 OBJMARKER & _marker,
00389 const CoordType & _p,
00390 const ScalarType & _r,
00391 OBJPTRCONTAINER & _objectPtrs,
00392 DISTCONTAINER & _distances,
00393 POINTCONTAINER & _points)
00394 {
00395 return(vcg::GridGetInSphere<SpatialHashType,
00396 OBJPOINTDISTFUNCTOR,OBJMARKER,OBJPTRCONTAINER,DISTCONTAINER,POINTCONTAINER>
00397 (*this,_getPointDistance,_marker,_p,_r,_objectPtrs,_distances,_points));
00398 }
00399
00400 template <class OBJMARKER, class OBJPTRCONTAINER>
00401 unsigned int GetInBox(OBJMARKER & _marker,
00402 const Box3x _bbox,
00403 OBJPTRCONTAINER & _objectPtrs)
00404 {
00405 return(vcg::GridGetInBox<SpatialHashType,OBJMARKER,OBJPTRCONTAINER>
00406 (*this,_marker,_bbox,_objectPtrs));
00407 }
00408
00409 template <class OBJRAYISECTFUNCTOR, class OBJMARKER>
00410 ObjPtr DoRay(OBJRAYISECTFUNCTOR & _rayIntersector, OBJMARKER & _marker, const Ray3<ScalarType> & _ray, const ScalarType & _maxDist, ScalarType & _t)
00411 {
00412 return(vcg::GridDoRay<SpatialHashType,OBJRAYISECTFUNCTOR,OBJMARKER>
00413 (*this,_rayIntersector,_marker,_ray,_maxDist,_t));
00414 }
00415
00416
00417 };
00418
00423 template < typename ContainerType,class FLT=double>
00424 class DynamicSpatialHashTable: public SpatialHashTable<ContainerType,FLT>
00425 {
00426 public:
00427 typedef typename SpatialHashTable<ContainerType,FLT>::CoordType CoordType;
00428 typedef typename SpatialHashTable<ContainerType,FLT>::ObjType ObjType;
00429 typedef typename SpatialHashTable<ContainerType,FLT>::ObjPtr ObjPtr;
00430 typedef typename SpatialHashTable<ContainerType,FLT>::Box3x Box3x;
00431 typedef typename SpatialHashTable<ContainerType,FLT>::CellIterator CellIterator;
00432
00433 void _UpdateHMark(ObjType* s){ s->HMark() = this->tempMark;}
00434
00435 void getInCellUpdated(vcg::Point3i cell,std::vector<ObjPtr> &elems)
00436 {
00437 CellIterator first,last,l;
00438 Grid(cell,first,last);
00439 for (l=first;l!=last;l++)
00440 {
00441 if ((l->second)>=(**l).HMark())
00442 elems.push_back(&(**l));
00443 }
00444 }
00445
00446 };
00447
00448
00449
00450
00451
00452 }
00453
00454 #endif