grid_of_cubes.h
Go to the documentation of this file.
00001 // Copyright (c) 2009-2010  INRIA Sophia-Antipolis (France).
00002 // All rights reserved.
00003 //
00004 //This file is part of ESBTL.
00005 //
00006 //ESBTL is free software: you can redistribute it and/or modify
00007 //it under the terms of the GNU General Public License as published by
00008 //the Free Software Foundation, either version 3 of the License, or
00009 //(at your option) any later version.
00010 //
00011 //ESBTL is distributed in the hope that it will be useful,
00012 //but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //GNU General Public License for more details.
00015 //
00016 //You should have received a copy of the GNU General Public License
00017 //along with ESBTL.  If not, see <http://www.gnu.org/licenses/>.
00018 //
00019 //
00020 //Additional permission under GNU GPL version 3 section 7
00021 //
00022 //If you modify this Library, or any covered work, by linking or
00023 //combining it with CGAL (or a modified version of that library), the
00024 //licensors of this Library grant you additional permission to convey
00025 //the resulting work. Corresponding Source for a non-source form of
00026 //such a combination shall include the source code for the parts of CGAL
00027 //used as well as that of the covered work. 
00028 //
00029 //
00030 //
00031 // Author(s)     :  Sébastien Loriot
00032 
00033 
00034 
00035 #ifndef ESBTL_GRID_OF_CUBES_H
00036 #define ESBTL_GRID_OF_CUBES_H
00037 
00038 
00039 #include <boost/tuple/tuple.hpp>
00040 #include <boost/tuple/tuple_comparison.hpp>
00041 #include <list>
00042 #include <map>
00043 
00044 
00045 namespace ESBTL{
00046 
00047 using boost::tuple;
00048 using boost::make_tuple;
00049 
00054 template<class Point_,class Iterator_>
00055 struct Traits_for_grid{
00056   typedef double NT;
00057   typedef Iterator_ Iterator;
00058   typedef Point_ Point;
00059   
00069   static void init_grid(const Iterator& begin,const Iterator& end,int& xlim,int& ylim,int& zlim,double& rmax,Point& lower_corner){
00070     Point min,max;
00071     boost::tie(min,max)=ESBTL::bounding_box<Point>(begin,end);
00072     
00073     //#warning should not be hardcoded
00074     rmax = 3.;
00075     xlim=static_cast<int>( ceil( ( max.x()-min.x() + 2*rmax )/rmax) );
00076     ylim=static_cast<int>( ceil( ( max.y()-min.y() + 2*rmax )/rmax) );
00077     zlim=static_cast<int>( ceil( ( max.z()-min.z() + 2*rmax )/rmax) );
00078     lower_corner=min;
00079   };
00080   
00092   template<class Any_iterator>
00093   static boost::tuple<int,int,int> 
00094   locate_cube(Any_iterator it,const int& xlim,const int& ylim,const int& zlim,const double& cubel,const Point& lower_corner){
00095     int x=static_cast<int>( floor( ( it->x()-lower_corner.x() )/cubel ) );
00096     int y=static_cast<int>( floor( ( it->y()-lower_corner.y() )/cubel ) );
00097     int z=static_cast<int>( floor( ( it->z()-lower_corner.z() )/cubel ) );
00098     
00099     //handle limit cases: snapping point at the limit of the bounding box and possibly
00100     //intersecting an element of the cube. This is not the optimal method as we are making more test than needed
00101     //(we know that some cubes are free from intersection) : maybe allow this in the iterator: just modify the is_outside_grid
00102     //criteria and allow iterator for *lim and -1
00103     if (x==xlim) x=xlim-1;
00104     if (y==ylim) y=ylim-1;
00105     if (z==zlim) z=zlim-1;
00106     if (x==-1) x=0;
00107     if (y==-1) y=0;
00108     if (z==-1) z=0;
00109     
00110     assert(!(x<0) && x < xlim);
00111     assert(!(y<0) && y < ylim);
00112     assert(!(z<0) && z < zlim);
00113     return boost::make_tuple(x,y,z);
00114   };
00115   
00126   template<class Any_iterator>
00127   static bool 
00128   is_outside_grid(Any_iterator it,const int& xlim,const int& ylim,const int& zlim,const double& cubel,const Point& lower_corner){
00129     int x=static_cast<int>( floor( ( it->x()-lower_corner.x() )/cubel ) );
00130     int y=static_cast<int>( floor( ( it->y()-lower_corner.y() )/cubel ) );
00131     int z=static_cast<int>( floor( ( it->z()-lower_corner.z() )/cubel ) );
00132     if (x<-1 || x > xlim) return true;
00133     if (y<-1 || y > ylim) return true;
00134     if (z<-1 || z > zlim) return true;
00135     return false;
00136   };
00137 };  
00138   
00145 template<class Traits>
00146 struct Grid_of_cubes
00147 {
00148   typedef tuple<int,int,int> Cube_coordinates;
00149   
00150   typedef typename Traits::Iterator Object_iterator;
00151   
00152   struct Cube_unit{
00153     typedef typename std::list<Object_iterator>::iterator In_cube_iterator;
00154     std::list<Object_iterator> objects;
00155     Cube_unit(Object_iterator V){ objects.push_front(V); }
00156     void insert(Object_iterator V){ objects.push_front(V); }
00157     unsigned size() const { return objects.size(); }
00158     In_cube_iterator begin(){ return objects.begin(); }
00159     In_cube_iterator end(){ return objects.end(); }
00160   };
00161 
00162   //Iterate over objects in a cube
00163   typedef typename Grid_of_cubes<Traits>::Cube_unit::In_cube_iterator In_cube_iterator;
00164   //use pointer to allow to delete a unit cube
00165   typedef std::map<Cube_coordinates,Cube_unit*> Cube_container;
00166 
00167   //Data members
00168   Cube_container cube_container;//contains cubes from 0 to *lim-1 in each direction
00169   int xlim,ylim,zlim;//nb of cubes in each direction
00170   typename Traits::NT cube_edge_length;
00171   typename Traits::Point lower_corner;
00172   
00173   
00174   //functions
00175   void init(const Object_iterator& it_beg,const Object_iterator& it_end){
00176     Traits::init_grid(it_beg,it_end,xlim,ylim,zlim,cube_edge_length,lower_corner);
00177   }
00178   
00179   void fill(Object_iterator it_beg,Object_iterator it_end){
00180     for(Object_iterator it=it_beg;it!=it_end;++it)
00181       insert_in_cube(it);
00182   }
00183   
00184   Grid_of_cubes(){}
00185   
00186   Grid_of_cubes(const Object_iterator& it_beg,const Object_iterator& it_end){
00187     init(it_beg,it_end);
00188     fill(it_beg,it_end);
00189   }
00190 
00191   ~Grid_of_cubes(){
00192      for(typename Cube_container::iterator it=cube_container.begin();it!=cube_container.end();++it)
00193        delete (*it).second;
00194   }
00195   
00196   
00197   unsigned nb_element() const {
00198     unsigned i=0;
00199     for(typename Cube_container::const_iterator it=cube_container.begin();it!=cube_container.end();++it)
00200        i+=it->second->size();
00201     return i;
00202   }
00203   
00204   Cube_unit* 
00205   get_cube(const Cube_coordinates& t) {
00206     typename Cube_container::iterator it=cube_container.find(t);
00207     return (it==cube_container.end())?(NULL):(it->second);
00208   }
00209   
00210   template <class Any_iterator>
00211   Cube_coordinates 
00212   locate_cube(Any_iterator v) const {
00213     return Traits::locate_cube(v,xlim,ylim,zlim,cube_edge_length,lower_corner);
00214   }
00215   
00216   template <class Any_iterator>
00217   Cube_unit* 
00218   get_cube(Any_iterator v) {
00219     return get_cube( locate_cube(v) );
00220   }
00221   
00222   void insert_in_cube(Object_iterator V){
00223     Cube_coordinates T=Traits::locate_cube(V,xlim,ylim,zlim,cube_edge_length,lower_corner);
00224     typename Cube_container::iterator it=cube_container.find(T);
00225     if (it==cube_container.end())
00226       cube_container[T]=new Cube_unit(V);
00227     else
00228       (*it).second->insert(V);
00229   };
00230   
00231   template <class Any_iterator>
00232   bool is_outside_grid(Any_iterator v) const {
00233     return Traits::is_outside_grid(v,xlim,ylim,zlim,cube_edge_length,lower_corner);
00234   }
00235   
00236   bool valid_tuple(const Cube_coordinates& T) const {
00237     return cube_container.find(T)!=cube_container.end();
00238   }
00239   
00240   class object_iterator;
00241   
00242   class iterator{
00243     friend class Grid_of_cubes<Traits>::object_iterator;    
00244     friend void Grid_of_cubes<Traits>::erase(const object_iterator& it);      
00245     protected:
00246     Cube_coordinates current;
00247     Grid_of_cubes* grid_ptr;
00248     Cube_coordinates 
00249     get_next(){
00250       assert(current!=make_tuple(-1,-1,-1));//DEBUG
00251       Cube_coordinates ret=current;
00252       if (current.get<0>() < grid_ptr->xlim-1)
00253         ret.get<0>()++;
00254       else{
00255         if (current.get<1>() < grid_ptr->ylim-1){
00256           ret.get<1>()++;
00257           ret.get<0>()=0;
00258         }
00259         else{
00260           if (current.get<2>() < grid_ptr->zlim-1){
00261           ret.get<2>()++;
00262           ret.get<0>()=0;
00263           ret.get<1>()=0;
00264           }
00265           else{
00266             return Cube_coordinates(-1,-1,-1);
00267           }
00268         }
00269       }
00270       if (grid_ptr->valid_tuple(ret)) return ret;
00271       current=ret;
00272       return get_next();
00273     }
00274     public:
00275     iterator(){};
00276     iterator(const Cube_coordinates& C):current(C),grid_ptr(NULL){};
00277     iterator(Grid_of_cubes* Grd):grid_ptr(Grd){current=make_tuple(-1,-1,-1);};
00278     iterator(Grid_of_cubes* Grd,const Cube_coordinates& C):current(C),grid_ptr(Grd){};
00279     iterator& operator++(){
00280       current=get_next();
00281       assert(grid_ptr->valid_tuple(current) || current==make_tuple(-1,-1,-1));//DEBUG
00282       return *this;
00283     }
00284     Cube_unit& operator*(){
00285       typename Cube_container::iterator it=grid_ptr->cube_container.find(current);
00286       assert(current!=make_tuple(-1,-1,-1));//DEBUG
00287       assert(it!=grid_ptr->cube_container.end());//DEBUG
00288       return *(*it).second;
00289     }
00290     Cube_unit* operator->(){
00291       typename Cube_container::iterator it=grid_ptr->cube_container.find(current);
00292       assert(it!=grid_ptr->cube_container.end());//DEBUG
00293       return (*it).second;
00294     }
00295     bool operator==(const iterator& it){
00296       return this->current==it.current;
00297     }
00298     bool operator!=(const iterator& it){
00299       return this->current!=it.current;
00300     }
00301   };
00302   
00303   class neighbor_iterator : public iterator
00304   {
00305     using iterator::current;
00306     using iterator::grid_ptr;
00307     private:
00308     Cube_coordinates center;
00309     
00310     Cube_coordinates get_next(){
00311       Cube_coordinates ret=current;
00312       assert(current!=make_tuple(-1,-1,-1));//DEBUG
00313       if ( (current.template get<0>() < center.get<0>() + 1) && (current.template get<0>() < grid_ptr->xlim - 1) )
00314         ret.get<0>()++;
00315       else{
00316         if ( (current.template get<1>() < center.get<1>() + 1 ) && (current.template get<1>() < grid_ptr->ylim-1) ){
00317           ret.get<1>()++;
00318           ret.get<0>()=((center.get<0>() == 0)?(center.get<0>()):(center.get<0>()-1));
00319         }
00320         else{
00321           if ( (current.template get<2>() < center.get<2>()+1) && (current.template get<2>() < grid_ptr->zlim-1) ){
00322             ret.get<2>()++;
00323             ret.get<0>()=((center.get<0>() == 0)?(center.get<0>()):(center.get<0>()-1));
00324             ret.get<1>()=((center.get<1>() == 0)?(center.get<1>()):(center.get<1>()-1));
00325           }
00326           else{
00327             return make_tuple(-1,-1,-1);
00328           }
00329         }
00330       }
00331       if (ret==center){
00332         current=ret;
00333         return get_next();
00334       }
00335       if (grid_ptr->valid_tuple(ret)) return ret;
00336       current=ret;
00337       return get_next();  
00338     }
00339     
00340     public:
00341     neighbor_iterator(){}
00342     neighbor_iterator(const Cube_coordinates& C):iterator(C){}
00343     neighbor_iterator(const Cube_coordinates& C,Grid_of_cubes* Grd):iterator(Grd),center(C){
00344       current=grid_ptr->get_first_neighbor(center);
00345       if (!grid_ptr->valid_tuple(current))
00346         current=this->get_next();
00347     } 
00348     
00349     Cube_coordinates& get_current(){
00350       return current;
00351     }
00352     
00353     neighbor_iterator& operator++(){
00354       current=this->get_next();
00355       return *this;
00356     }
00357   };
00358   
00359   iterator begin(){
00360     iterator ret=iterator(this,make_tuple(0,0,0));
00361     return (this->valid_tuple(make_tuple(0,0,0)))?(ret):(++ret);
00362   }
00363   iterator end(){
00364     return iterator(this,make_tuple(-1,-1,-1));
00365   }
00366   neighbor_iterator nend(){
00367     return neighbor_iterator(make_tuple(-1,-1,-1));
00368   }
00369   
00370   class object_iterator{
00371     friend void Grid_of_cubes<Traits>::erase(const object_iterator& it);
00372     protected:
00373     iterator current_cube;
00374     In_cube_iterator current_object;
00375 
00376     public:
00377     object_iterator(){};
00378     object_iterator(iterator it,In_cube_iterator itc):current_cube(it),current_object(itc){};
00379     object_iterator(iterator it):current_cube(it),current_object(NULL){};
00380 
00381     object_iterator& operator++(){
00382       if (++current_object==(*current_cube).end()){
00383         ++current_cube;
00384         if (current_cube!=current_cube.grid_ptr->end())
00385           current_object=(*current_cube).begin();
00386       }
00387       return *this;
00388     }
00389     
00390     //postfix 
00391     object_iterator operator++(int ){
00392       object_iterator tmp=*this;
00393       if (++current_object==(*current_cube).end()){
00394         ++current_cube;
00395         if (current_cube!=current_cube.grid_ptr->end())
00396           current_object=(*current_cube).begin();
00397       }
00398       return tmp;
00399     }    
00400     
00401     Object_iterator& operator*(){ return (*current_object);};
00402     Cube_unit* operator->(){ return *(*current_object);   };
00403     bool operator==(const object_iterator& it){
00404       bool ret=(this->current_cube==it.current_cube);
00405       if (!ret)
00406         return false;
00407       return (this->current_cube==this->current_cube.grid_ptr->end())?(true):(this->current_object==it.current_object);
00408     }
00409     bool operator!=(const object_iterator& it){
00410       bool ret=(this->current_cube!=it.current_cube);
00411       if (ret)
00412         return true;
00413       return (this->current_cube==this->current_cube.grid_ptr->end())?(false):(this->current_object!=it.current_object);      
00414     }
00415   };
00416   
00417   object_iterator last_object(){return object_iterator(this->end());}
00418   object_iterator first_object(){
00419     if (this->begin()!=this->end())
00420       return object_iterator(this->begin(),(*(this->begin())).begin());
00421     else
00422       return object_iterator(this->end());
00423   }
00424   
00425   void erase(const object_iterator& it){
00426                 #ifndef NDEBUG
00427     int k=get_cube(it.current_cube.current)->size();//DEBUG
00428                 #endif
00429     get_cube(it.current_cube.current)->objects.erase(it.current_object);
00430     #ifndef NDEBUG
00431     assert(k==(int) get_cube(it.current_cube.current)->objects.size()+1);//DEBUG
00432     #endif
00433     if (get_cube(it.current_cube.current)->objects.size()==0){
00434       typename Cube_container::iterator Iterator=cube_container.find(it.current_cube.current);
00435       delete (*Iterator).second;
00436       cube_container.erase(Iterator);
00437     }
00438   }
00439   
00440   Cube_coordinates get_first_neighbor(Cube_coordinates& T)
00441   {
00442     int a,b,c;
00443     int pb=0;
00444     if (T.get<0>()>0)
00445       a=T.get<0>()-1;
00446     else{
00447       a=T.get<0>();
00448       ++pb;
00449     }
00450     if (T.get<1>()>0)
00451       b=T.get<1>()-1;
00452     else{
00453       b=T.get<1>();
00454       ++pb;
00455     }
00456     if (T.get<2>()>0)
00457       c=T.get<2>()-1;
00458     else{
00459       c=T.get<2>();
00460       ++pb;
00461     }    
00462     return (pb==3)?(Cube_coordinates(1,0,0)):(Cube_coordinates(a,b,c));
00463   }  
00464   
00465   neighbor_iterator first_neighbor(const Cube_coordinates& C) {
00466     return neighbor_iterator(C,this);
00467   }
00468   
00469   neighbor_iterator first_neighbor(iterator& it){
00470     return neighbor_iterator(it.get_current(),this);
00471   }
00472 };
00473 
00474 } //namespace ESBTL
00475 
00476 #endif //ESBTL_GRID_OF_CUBES_H