diff --git a/vcg/space/index/grid_static_ptr.h b/vcg/space/index/grid_static_ptr.h index 1a1da6f0..39f4e5ed 100644 --- a/vcg/space/index/grid_static_ptr.h +++ b/vcg/space/index/grid_static_ptr.h @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.3 2004/05/12 18:50:58 ganovelli +changed calls to Dist + Revision 1.2 2004/05/11 14:33:46 ganovelli changed to grid_static_obj to grid_static_ptr @@ -44,447 +47,477 @@ Initial commit #include namespace vcg { + + /** Static Uniform Grid + A spatial search structure for a accessing a container of objects. + It is based on a uniform grid overlayed over a protion of space. + The grid partion the space into cells. Cells contains just pointers + to the object that are stored elsewhere. + The set of objects is meant to be static and pointer stable. - /** Static Uniform Grid - A spatial search structure for a accessing a container of objects. It is based on a uniform grid overlayed over a protion of space. - The grid partion the space into cells. Cells contains just pointers to the object that are stored elsewhere. - The set of object is meant to be static and pointer stable. - Useful for situation were many space related query are issued over the same dataset (ray tracing, measuring distances between meshes, re-detailing ecc.). Works well for distribution that ar reasonably uniform. + Useful for situation were many space related query are issued over + the same dataset (ray tracing, measuring distances between meshes, + re-detailing ecc.). + Works well for distribution that ar reasonably uniform. How to use it: + ContainerType must have a 'value_type' typedef inside. + (stl containers already have it) + Objects pointed by cells (of kind 'value_type') must have + a 'ScalarType' typedef (float or double usually) + and 2 member functions: + + bool Dist(const Point3f &point, ScalarType &mindist, Point3f &result); + which return true if the distance from point to the object is < mindist + and set mindist to said distance, and result must be set as the closest + point of the object to point) + + void GetBBox(Box3 &b) + which return the bounding box of the object + */ + template < typename ContainerType > class GridStaticPtr { -public: + public: - /** Internal class for keeping the first pointer of object. - Definizione Link dentro la griglia. Classe di supporto per GridStaticObj. - */ - class Link - { - public: - /// Costruttore di default - inline Link(){}; - /// Costruttore con inizializzatori - inline Link( typename ContainerType::iterator const nt, const int ni ){ - assert(ni>=0); - t = nt; - i = ni; - }; - - - inline bool operator < ( const Link & l ) const{ return i < l.i; } - inline bool operator <= ( const Link & l ) const{ return i <= l.i; } - inline bool operator > ( const Link & l ) const{ return i > l.i; } - inline bool operator >= ( const Link & l ) const{ return i >= l.i; } - inline bool operator == ( const Link & l ) const{ return i == l.i; } - inline bool operator != ( const Link & l ) const{ return i != l.i; } - - inline typename ContainerType::iterator & Elem() { - return t; - } - inline int & Index() { - return i; - } - - private: - /// Puntatore all'elemento T - typename ContainerType::iterator t; - /// Indirizzo del voxel dentro la griglia - int i; - - - };//end class Link - - typedef typename ContainerType::value_type ObjType; - typedef ObjType* ObjPtr; - typedef typename ObjType::ScalarType ScalarType; - typedef Point3 Point3x; - typedef Box3 Box3x; - typedef Line3 Line3x; - typedef Link* Cell; - - Box3x bbox; - Point3x dim; /// Dimensione spaziale (lunghezza lati) del bbox - Point3i siz; /// Dimensioni griglia in celle - Point3x voxel; /// Dimensioni di una cella - - /// Insieme di tutti i links - std::vector links; - /// Griglia vera e propria - std::vector grid; - - /// Dato un punto, ritorna la cella che lo contiene - inline Cell* Grid( const Point3d & p ) - { - int x = int( (p[0]-bbox.min[0])/voxel[0] ); - int y = int( (p[1]-bbox.min[1])/voxel[1] ); - int z = int( (p[2]-bbox.min[2])/voxel[2] ); + /** Internal class for keeping the first pointer of object. + Definizione Link dentro la griglia. Classe di supporto per GridStaticObj. + */ + class Link + { + public: + /// Costruttore di default + inline Link(){}; + /// Costruttore con inizializzatori + inline Link( typename ContainerType::iterator const nt, const int ni ){ + assert(ni>=0); + t = nt; + i = ni; + }; + + + inline bool operator < ( const Link & l ) const{ return i < l.i; } + inline bool operator <= ( const Link & l ) const{ return i <= l.i; } + inline bool operator > ( const Link & l ) const{ return i > l.i; } + inline bool operator >= ( const Link & l ) const{ return i >= l.i; } + inline bool operator == ( const Link & l ) const{ return i == l.i; } + inline bool operator != ( const Link & l ) const{ return i != l.i; } + + inline typename ContainerType::iterator & Elem() { + return t; + } + inline int & Index() { + return i; + } + + private: + /// Puntatore all'elemento T + typename ContainerType::iterator t; + /// Indirizzo del voxel dentro la griglia + int i; + + + };//end class Link + + typedef typename ContainerType::value_type ObjType; + typedef ObjType* ObjPtr; + typedef typename ObjType::ScalarType ScalarType; + typedef Point3 Point3x; + typedef Box3 Box3x; + typedef Line3 Line3x; + typedef Link* Cell; + + Box3x bbox; + Point3x dim; /// Dimensione spaziale (lunghezza lati) del bbox + Point3i siz; /// Dimensioni griglia in celle + Point3x voxel; /// Dimensioni di una cella + + std::vector links; /// Insieme di tutti i links + std::vector grid; /// Griglia vera e propria + + /// Dato un punto, ritorna la cella che lo contiene + inline Cell* Grid( const Point3d & p ) + { + int x = int( (p[0]-bbox.min[0])/voxel[0] ); + int y = int( (p[1]-bbox.min[1])/voxel[1] ); + int z = int( (p[2]-bbox.min[2])/voxel[2] ); + #ifndef NDEBUG - if ( x<0 || x>=siz[0] || y<0 || y>=siz[1] || z<0 || z>=siz[2] ) - return NULL; - else + if ( x<0 || x>=siz[0] || y<0 || y>=siz[1] || z<0 || z>=siz[2] ) + return NULL; + else #endif - - return grid.begin() + ( x+siz[0]*(y+siz[1]*z) ); - } - /// Date le coordinate ritorna la cella - inline Cell* Grid( const int x, const int y, const int z ) - { -#ifndef NDEBUG - if ( x<0 || x>=siz[0] || y<0 || y>=siz[1] || z<0 || z>=siz[2] ) - assert(0); - //return NULL; - else -#endif - assert(((unsigned int)x+siz[0]*y+siz[1]*z) & cl, - std::vector &o) - { -#ifndef NDEBUG - if ( p[0]<0 || p[0]>siz[0] || p[1]<0 || p[1]>siz[1] || p[2]<0 || p[2]>siz[2] ) - assert(0); - //return NULL; - else -#endif - assert(((unsigned int) p[0]+siz[0]*p[1]+siz[1]*p[2])=siz[0] || y<0 || y>=siz[1] || z<0 || z>=siz[2] ) + assert(0); + //return NULL; + else +#endif + assert(((unsigned int)x+siz[0]*y+siz[1]*z) & cl, + std::vector &o) + { +#ifndef NDEBUG + if ( p[0]<0 || p[0]>siz[0] || + p[1]<0 || p[1]>siz[1] || + p[2]<0 || p[2]>siz[2] ) + assert(0); + //return NULL; + else +#endif + assert(((unsigned int) p[0]+siz[0]*p[1]+siz[1]*p[2])0.5) radius=(1.0-radius); radius*=voxel[0]; + + ScalarType tmp=dy-ScalarType(iy); + if (tmp>0.5) tmp=1.0-tmp; + tmp*=voxel[1]; + if (radius>tmp) radius=tmp; + tmp=dz-ScalarType(iz); + if (tmp>0.5) tmp=1.0-tmp; + tmp*=voxel[2]; + if (radius>tmp) radius=tmp; + + Point3x t_res; + //ScalarType min_dist=1e10; + ObjPtr winner=NULL; + Link *first, *last; + Link *l; + if ((ix>=0) && (iy>=0) && (iz>=0) && + (ixElem()->IsD() && l->Elem()->Dist(p,min_dist,t_res)) { + winner=&*(l->Elem()); + res=t_res; + + } + }; + }; + + //return winner; + + Point3i done_min=Point3i(ix,iy,iz), done_max=Point3i(ix,iy,iz); - /** Returns the closest posistion of a point p and its distance - @param p a 3d point - @return The closest element - */ - ObjPtr GetClosest( const Point3x & p, ScalarType & min_dist, Point3x & res) + //printf("."); + + while (min_dist>radius) { + //if (dy-ScalarType(iy)) + done_min[0]--; if (done_min[0]<0) done_min[0]=0; + done_min[1]--; if (done_min[1]<0) done_min[1]=0; + done_min[2]--; if (done_min[2]<0) done_min[2]=0; + done_max[0]++; if (done_max[0]>=siz[0]-1) done_max[0]=siz[0]-1; + done_max[1]++; if (done_max[1]>=siz[1]-1) done_max[1]=siz[1]-1; + done_max[2]++; if (done_max[2]>=siz[2]-1) done_max[2]=siz[2]-1; + radius+=voxel_min; + //printf("+"); + for (ix=done_min[0]; ix<=done_max[0]; ix++) + for (iy=done_min[1]; iy<=done_max[1]; iy++) + for (iz=done_min[2]; iz<=done_max[2]; iz++) + { + Grid( ix, iy, iz, first, last ); + for(l=first;l!=last;++l) + { + if (!l->Elem()->IsD() && l->Elem()->Dist(p,min_dist,t_res)) { + winner=&*(l->Elem()); + res=t_res; + }; + }; + } + }; + return winner; + }; + + /// Inserisce una mesh nella griglia. Nota: prima bisogna + /// chiamare SetBBox che setta dim in maniera corretta + void Set( ContainerType & s ) + { + Set(s,s.size()); + } + + + /// Inserisce una mesh nella griglia. Nota: prima bisogna + /// chiamare SetBBox che setta dim in maniera corretta + void Set( ContainerType & s,int _size ) + { + Point3i _siz; + + BestDim( _size, dim, _siz ); + Set(s,_siz); + } + void Set(ContainerType & s, Point3i _siz) + { + siz=_siz; + // Calcola la dimensione della griglia + voxel[0] = dim[0]/siz[0]; + voxel[1] = dim[1]/siz[1]; + voxel[2] = dim[2]/siz[2]; + + // "Alloca" la griglia: +1 per la sentinella + grid.resize( siz[0]*siz[1]*siz[2]+1 ); + + // Ciclo inserimento dei tetraedri: creazione link + links.clear(); + typename ContainerType::iterator pt; + for(pt=s.begin(); pt!=s.end(); ++pt) { - ScalarType dx = ( (p[0]-bbox.min[0])/voxel[0] ); - ScalarType dy = ( (p[1]-bbox.min[1])/voxel[1] ); - ScalarType dz = ( (p[2]-bbox.min[2])/voxel[2] ); - - int ix = int( dx ); - int iy = int( dy ); - int iz = int( dz ); - - double voxel_min=voxel[0]; - if (voxel_min0.5) radius=(1.0-radius); radius*=voxel[0]; - - ScalarType - tmp=dy-ScalarType(iy); if (tmp>0.5) tmp=1.0-tmp; tmp*=voxel[1]; if (radius>tmp) radius=tmp; - tmp=dz-ScalarType(iz); if (tmp>0.5) tmp=1.0-tmp; tmp*=voxel[2]; if (radius>tmp) radius=tmp; - - Point3x t_res; - //ScalarType min_dist=1e10; - ObjPtr winner=NULL; - - Link *first, *last; - Link *l; - if ((ix>=0) && (iy>=0) && (iz>=0) && (ixElem()->IsD() && l->Elem()->Dist(p,min_dist,t_res)) { - winner=&*(l->Elem()); - res=t_res; - - } - }; - }; - - //return winner; - - Point3i done_min=Point3i(ix,iy,iz), done_max=Point3i(ix,iy,iz); - - //printf("."); - - while (min_dist>radius) { - //if (dy-ScalarType(iy)) - done_min[0]--; if (done_min[0]<0) done_min[0]=0; - done_min[1]--; if (done_min[1]<0) done_min[1]=0; - done_min[2]--; if (done_min[2]<0) done_min[2]=0; - done_max[0]++; if (done_max[0]>=siz[0]-1) done_max[0]=siz[0]-1; - done_max[1]++; if (done_max[1]>=siz[1]-1) done_max[1]=siz[1]-1; - done_max[2]++; if (done_max[2]>=siz[2]-1) done_max[2]=siz[2]-1; - radius+=voxel_min; - //printf("+"); - for (ix=done_min[0]; ix<=done_max[0]; ix++) - for (iy=done_min[1]; iy<=done_max[1]; iy++) - for (iz=done_min[2]; iz<=done_max[2]; iz++) - { - Grid( ix, iy, iz, first, last ); - for(l=first;l!=last;++l) - { - if (!l->Elem()->IsD() && l->Elem()->Dist(p,min_dist,t_res)) { - winner=&*(l->Elem()); - res=t_res; - }; - }; - } - }; - return winner; - }; - - /// Inserisce una mesh nella griglia. Nota: prima bisogna - /// chiamare SetBBox che setta dim in maniera corretta - void Set( ContainerType & s ) - { - Set(s,s.size()); - } - - - /// Inserisce una mesh nella griglia. Nota: prima bisogna - /// chiamare SetBBox che setta dim in maniera corretta - void Set( ContainerType & s,int _size ) - { - Point3i _siz; - - BestDim( _size, dim, _siz ); - Set(s,_siz); - } - void Set(ContainerType & s, Point3i _siz) - { - siz=_siz; - // Calcola la dimensione della griglia - voxel[0] = dim[0]/siz[0]; - voxel[1] = dim[1]/siz[1]; - voxel[2] = dim[2]/siz[2]; - - // "Alloca" la griglia: +1 per la sentinella - grid.resize( siz[0]*siz[1]*siz[2]+1 ); - - // Ciclo inserimento dei tetraedri: creazione link - links.clear(); - typename ContainerType::iterator pt; - for(pt=s.begin(); pt!=s.end(); ++pt) + Box3x bb; // Boundig box del tetraedro corrente + (*pt).GetBBox(bb); + bb.Intersect(bbox); + if(! bb.IsNull() ) + { + Box3i ib; // Boundig box in voxels + BoxToIBox( bb,ib ); + + int x,y,z; + for(z=ib.min[2];z<=ib.max[2];++z) { - Box3x bb; // Boundig box del tetraedro corrente - (*pt).GetBBox(bb); - bb.Intersect(bbox); - if(! bb.IsNull() ) - { - Box3i ib; // Boundig box in voxels - BoxToIBox( bb,ib ); - - int x,y,z; - for(z=ib.min[2];z<=ib.max[2];++z) - { - int bz = z*siz[1]; - for(y=ib.min[1];y<=ib.max[1];++y) - { - int by = (y+bz)*siz[0]; - for(x=ib.min[0];x<=ib.max[0];++x) - // Inserire calcolo cella corrente - // if( pt->Intersect( ... ) - links.push_back( Link(pt,by+x) ); - } - } - } + int bz = z*siz[1]; + for(y=ib.min[1];y<=ib.max[1];++y) + { + int by = (y+bz)*siz[0]; + for(x=ib.min[0];x<=ib.max[0];++x) + // Inserire calcolo cella corrente + // if( pt->Intersect( ... ) + links.push_back( Link(pt,by+x) ); + } } - // Push della sentinella - links.push_back( Link((typename ContainerType::iterator)NULL,(grid.size()-1))); - - // Ordinamento dei links - sort( links.begin(), links.end() ); - - // Creazione puntatori ai links - typename std::vector::iterator pl; - unsigned int pg; - pl = links.begin(); - for(pg=0;pgIndex() ) // Trovato inizio - { - ++pl; // Ricerca prossimo blocco - if(pl==links.end()) - break; - } - } - + } } - - /** Calcolo dimensioni griglia. - Calcola la dimensione della griglia in funzione - della ratio del bounding box e del numero di elementi - */ - static void BestDim( const int elems, const Point3x & size, Point3i & dim ) - { - const int mincells = 1; // Numero minimo di celle - const double GFactor = 1.0; // GridEntry = NumElem*GFactor - double diag = size.Norm(); // Diagonale del box - double eps = diag*1e-4; // Fattore di tolleranza - - assert(elems>0); - assert(size[0]>=0.0); - assert(size[1]>=0.0); - assert(size[2]>=0.0); - - int ncell = int(elems*GFactor); // Calcolo numero di voxel - if(ncelleps) - { - if(size[1]>eps) - { - if(size[2]>eps) - { - double k = pow((double)(ncell/(size[0]*size[1]*size[2])),double(1.0/3.f)); - dim[0] = int(size[0] * k); - dim[1] = int(size[1] * k); - dim[2] = int(size[2] * k); - } - else - { - dim[0] = int(::sqrt(ncell*size[0]/size[1])); - dim[1] = int(::sqrt(ncell*size[1]/size[0])); - } - } - else - { - if(size[2]>eps) - { - dim[0] = int(::sqrt(ncell*size[0]/size[2])); - dim[2] = int(::sqrt(ncell*size[2]/size[0])); - } - else - dim[0] = int(ncell); - } - } - else - { - if(size[1]>eps) - { - if(size[2]>eps) - { - dim[1] = int(::sqrt(ncell*size[1]/size[2])); - dim[2] = int(::sqrt(ncell*size[2]/size[1])); - } - else - dim[1] = int(ncell); - } - else if(size[2]>eps) - dim[2] = int(ncell); - } - dim[0] = math::Max(dim[0],1); - dim[1] = math::Max(dim[1],1); - dim[2] = math::Max(dim[2],1); - } - - - int MemUsed() + // Push della sentinella + links.push_back( Link((typename ContainerType::iterator)NULL, + (grid.size()-1))); + + // Ordinamento dei links + sort( links.begin(), links.end() ); + + // Creazione puntatori ai links + typename std::vector::iterator pl; + unsigned int pg; + pl = links.begin(); + for(pg=0;pgIndex() ) // Trovato inizio + { + ++pl; // Ricerca prossimo blocco + if(pl==links.end()) + break; + } } + + } + + /** Calcolo dimensioni griglia. + Calcola la dimensione della griglia in funzione + della ratio del bounding box e del numero di elementi + */ + static void BestDim( const int elems, const Point3x & size, Point3i & dim ) + { + const int mincells = 1; // Numero minimo di celle + const double GFactor = 1.0; // GridEntry = NumElem*GFactor + double diag = size.Norm(); // Diagonale del box + double eps = diag*1e-4; // Fattore di tolleranza + + assert(elems>0); + assert(size[0]>=0.0); + assert(size[1]>=0.0); + assert(size[2]>=0.0); + + int ncell = int(elems*GFactor); // Calcolo numero di voxel + if(ncelleps) + { + if(size[1]>eps) + { + if(size[2]>eps) + { + double k = pow((double)(ncell/(size[0]*size[1]*size[2])),double(1.0/3.f)); + dim[0] = int(size[0] * k); + dim[1] = int(size[1] * k); + dim[2] = int(size[2] * k); + } + else + { + dim[0] = int(::sqrt(ncell*size[0]/size[1])); + dim[1] = int(::sqrt(ncell*size[1]/size[0])); + } + } + else + { + if(size[2]>eps) + { + dim[0] = int(::sqrt(ncell*size[0]/size[2])); + dim[2] = int(::sqrt(ncell*size[2]/size[0])); + } + else + dim[0] = int(ncell); + } + } + else + { + if(size[1]>eps) + { + if(size[2]>eps) + { + dim[1] = int(::sqrt(ncell*size[1]/size[2])); + dim[2] = int(::sqrt(ncell*size[2]/size[1])); + } + else + dim[1] = int(ncell); + } + else if(size[2]>eps) + dim[2] = int(ncell); + } + dim[0] = math::Max(dim[0],1); + dim[1] = math::Max(dim[1],1); + dim[2] = math::Max(dim[2],1); + } + + + int MemUsed() + { + return sizeof(GridStaticObj)+ sizeof(Link)*links.size() + + sizeof(Cell) * grid.size(); + } }; //end class GridStaticObj - + }; // end namespace #endif