Space-efficient geometric algorithms and data structures

By Ilya Katz and Hervé Brönnimann    

cgl.hpp

Go to the documentation of this file.
00001 
00012 #ifndef CGL_HPP
00013 #define CGL_HPP
00014 
00015 //add multi-dpoint, less_nth_object, trienble, point_in_triangle
00016 
00017 #include <boost/array.hpp>
00018 
00019 
00020 
00021 template <class NT, std::size_t N=2>
00022 class cgl
00023 {
00024 
00025 public:
00026 
00028    typedef NT                                                   coord_type;
00030   typedef boost::array<coord_type,2>    point_type;
00032   typedef boost::array<point_type,2>    line_type;
00034   typedef boost::array<coord_type, N> multiD_point_type;
00036   typedef boost::array<point_type,4>    box_type;
00038   typedef boost::array<point_type,3> triangle_type;
00046     enum side {TOP, BOTTOM};
00047    typedef std::pair<boost::array<point_type,2>,side> halfplane_type;
00048 
00049 
00051    struct less_x_object_type
00052   {
00053     bool operator()(cgl::point_type p1, cgl::point_type p2){
00054       return p1[0]<p2[0];
00055     }
00056   };
00058   struct less_y_object_type
00059   {
00060     bool operator()(const cgl::point_type& p1, const cgl::point_type& p2){
00061       return p1[1]<p2[1];
00062     }
00063 
00064   };
00065 
00067   struct equals_xy_object_type
00068   {
00069     bool operator()(const cgl::point_type& p1, const cgl::point_type& p2){
00070       return p1[1]==p2[1] && p1[0]==p2[0];
00071     }
00072 
00073   };
00074 
00075   struct equals_lines_object_type
00076   {
00077     bool operator()(const line_type& l1, const line_type& l2){
00078       return    l1[1][1]==l2[1][1] && l1[0][0]==l2[0][0] &&
00079           l1[0][1]==l2[0][1] && l1[1][0]==l2[1][0];
00080     }
00081 
00082   };
00083 
00085   struct less_xy_object_type
00086   {
00087     bool operator()(cgl::point_type p1, cgl::point_type p2){
00088       return p1[0]<p2[0] ||      (!(p2[0]<p1[0]) && p1[1]<p2[1]);
00089     }
00090 
00091   };
00093   struct less_nth_object_type
00094   {
00095     private:
00096       std::size_t dimension;
00097     public:
00098       less_nth_object_type(std::size_t d):dimension(d){}
00099       bool operator()(multiD_point_type p1, multiD_point_type p2)
00100       {
00101         return p1[dimension-1]<p2[dimension-2];
00102       }
00103   };
00104 
00106   less_nth_object_type less_nth_object(std::size_t n)
00107   {
00108     return less_nth_object_type(n);
00109   }
00111   less_x_object_type less_x_object()
00112   {
00113     return less_x_object_type();
00114   }
00116   less_y_object_type less_y_object()
00117   {
00118     return less_y_object_type();
00119   }
00121   less_xy_object_type less_xy_object()
00122   {
00123     return less_xy_object_type();
00124   }
00126   equals_xy_object_type equals_xy_object()
00127   {
00128     return equals_xy_object_type();
00129   }
00130 
00131   equals_lines_object_type equals_lines_object()
00132   {
00133     return equals_lines_object_type();
00134   }
00135 
00136 
00137   //point related predicates and functions
00138 
00139 
00141   point_type make_point(coord_type x, coord_type y)
00142   {
00143     point_type p = {x,y};
00144     return p;
00145   }
00146 
00148   coord_type get_x_coordinate(point_type p)
00149   {
00150     return p[0];
00151   }
00152 
00154   coord_type get_y_coordinate(point_type p)
00155   {
00156     return p[1];
00157   }
00158 
00159 
00160   // box-related predicate and functions
00161 
00162 
00164   box_type make_empty_box()
00165   {
00166     box_type new_box;
00167     point_type p = {0,0};
00168     new_box[3] = new_box[2] = new_box[1] = new_box[0] = p;
00169   }
00170 
00172 
00177   box_type make_box(point_type ll, point_type ur)
00178   {
00179     if( ur[0]<ll[0] || ur[1]<ll[1] ||
00180      (!(ll[0] < ur[0]) && !(ur[0] < ll[0])) || //ll[0]==ur[0]
00181      (!(ll[0] < ur[0]) && !(ur[0] < ll[0])) )  //ll[1]==ur[1]
00182     {
00183       return make_empty_box();
00184     }
00185 
00186     return make_box (ll[0],ur[0],ur[1],ll[1]);
00187   }
00188 
00189   //returns a box given x coordinates of the top and bottom sides and y coordinates of the left and right sides
00190   box_type make_box(coord_type left, coord_type right,
00191         coord_type top, coord_type bottom)
00192   {
00193 
00194     box_type new_box;
00195 
00196     point_type ll = {left, bottom};
00197     point_type ul = {left, top};
00198     point_type ur = {right, top};
00199     point_type lr = {right, bottom};
00200 
00201     new_box[0] = ll;            //lower left
00202     new_box[1] = lr;            //lower right
00203     new_box[2] = ul;            //upper left
00204     new_box[3] = ur;            //upper right
00205 
00206     return new_box;
00207 
00208   }
00209 
00211   bool is_empty_box(box_type box)
00212   {
00213     return get_x_coordinate(box[0])== get_x_coordinate(box[1]) &&
00214          get_y_coordinate(box[0])== get_x_coordinate(box[1]) &&
00215          get_x_coordinate(box[2])== get_x_coordinate(box[3]) &&
00216          get_y_coordinate(box[2])== get_x_coordinate(box[3]) ;
00217   }
00218 
00220   coord_type get_left(box_type Q)
00221   {
00222     return lower_left(Q)[0];
00223   }
00224 
00226   coord_type get_right(box_type Q)
00227   {
00228     return upper_right(Q)[0];
00229   }
00230 
00232   coord_type get_top(box_type Q)
00233   {
00234     return upper_right(Q)[1];
00235   }
00236 
00238   coord_type get_bottom(box_type Q)
00239   {
00240     return lower_left(Q)[1];
00241   }
00242 
00244   point_type lower_left(box_type box)
00245   {
00246     return box[0];
00247   }
00248 
00250   point_type lower_right(box_type box)
00251   {
00252     return box[1];
00253   }
00254 
00256   point_type upper_left(box_type box)
00257   {
00258     return box[2];
00259   }
00260 
00262   point_type upper_right(box_type box)
00263   {
00264     return box[3];
00265   }
00266 
00268   bool disjoint(box_type b1, box_type b2)
00269   {
00270     return
00271     b2.upper_right()[0] < b1.upper_left() [0]  ||       //to the left
00272     b1.upper_right()[0] < b2.upper_left() [0]  ||       //to the right
00273     b2.upper_left() [1] < b1.lower_left() [1]  ||       //below
00274     b1.upper_left() [1] < b2.lower_left() [1]  ;        //above
00275   }
00276 
00277 
00279   //false otherwise
00280   //if box is empty, false is returned
00281   bool point_in_box(point_type p, box_type box)
00282   {
00283     if(is_empty_box(box))
00284     {
00285       return false;
00286     }
00287 
00288     return !(get_y_coordinate(p) < get_bottom(box)) && //get_bottom(box)<=get_y_coordinate(p)
00289          get_top(box)>get_y_coordinate(p) &&
00290          !(get_x_coordinate(p)< get_left(box)) &&   //get_left(box)<=get_x_coordinate(p)
00291          get_right(box)>get_x_coordinate(p);
00292 
00293   }
00294 
00296   //false otherwise
00297   //if box is empty, false is returned
00298   bool point_in_closed_box(point_type p, box_type box)
00299   {
00300     if(is_empty_box(box))
00301     {
00302       return false;
00303     }
00304     return !(get_y_coordinate(p) < get_bottom(box)) &&     //get_bottom(box)<=get_y_coordinate(p)
00305          !(get_top(box)<get_y_coordinate(p)) &&            //get_top(box)>=get_y_coordinate(p)
00306          !(get_x_coordinate(p)< get_left(box)) &&        //get_left(box)<=get_x_coordinate(p)
00307          !(get_right(box)<get_x_coordinate(p));            //get_right(box)>=get_x_coordinate(p)
00308 
00309 
00310   }
00311 
00313   //if both boxes are empty, false is returned
00314   //if either box is empty, but not both, true is returned
00315   bool contains(box_type inner, box_type outer)
00316   {
00317     if(is_empty_box(inner) && is_empty_box(outer))
00318     {
00319       return false;
00320     }
00321     else if(is_empty_box(inner))
00322     {
00323       return true;
00324     }
00325     else if(is_empty_box(outer))
00326     {
00327       return true;
00328     }
00329 
00330     return
00331     point_in_box(lower_left(inner),outer) &&
00332     point_in_box(upper_left(inner),outer) &&
00333     point_in_box(lower_right(inner),outer) &&
00334     point_in_box(upper_right(inner),outer);
00335   }
00336 
00338 
00342   box_type box_hull(box_type b1, box_type b2)
00343   {
00344     box_type new_box;
00345     point_type ll ={std::min (lower_left(b1)[0], lower_left(b2)[0]),
00346         std::min (lower_left(b1)[1], lower_left(b2)[1])
00347         };
00348     point_type ur ={std::max (upper_right(b1)[0], upper_right(b2)[0]),
00349         std::max (upper_right(b1)[0], upper_right(b2)[0])
00350         };
00351 
00352     return make_box(ll,ur);
00353   }
00354 
00356 
00358   box_type intersection(box_type b1, box_type b2)
00359   {
00360     if(disjoint(b1,b2))
00361     {
00362       return make_empty_box();
00363     }
00364 
00365     //else do the work
00366     point_type ll ={std::max(lower_left(b1)[0],lower_left(b2)[0]),
00367         std::max(lower_left(b1)[1],lower_left(b2)[1])
00368         };
00369     point_type ur ={std::min(upper_right(b1)[0],upper_right(b2)[0]),
00370         std::min(upper_right(b1)[1],upper_right(b1)[1])
00371         };
00372     return make_box(ll,ur);
00373 
00374   }
00375 
00376   /*
00377    * halfplane predicates and functions
00378    */
00379 
00381     halfplane_type make_halfplane(point_type a, point_type b, side which_one)
00382     {
00383       // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00384       //\TODO what if they have the same x-value
00385       // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00386 
00387 
00388       //point with the smaller x-coordinate will always be in position 0
00389        boost::array<point_type,2> pp;
00390        pp[0]=std::min(a,b, less_x_object());
00391        pp[1]=std::max(a,b, less_x_object());
00392 
00393        halfplane_type halfplane(pp,which_one);
00394 
00395        return halfplane;
00396     }
00397 
00399     halfplane_type make_halfplane(point_type a, point_type b)
00400     {
00401       less_xy_object_type comparator;
00402       if(comparator(a,b))
00403       {
00404         return make_halfplane(a,b,TOP);
00405       }
00406       else
00407       {
00408         return make_halfplane(a,b,BOTTOM);
00409       }
00410 
00411     }
00412 
00414     //halfplane is considered to be empty if it is defined by two points
00415     //having the same coordinates
00416     halfplane_type empty_halfplane()
00417     {
00418       return make_plane(make_point(0,0),make_point(0,0),TOP);
00419     }
00420 
00422     bool
00423     is_empty_halfplane(halfplane_type halfplane)
00424     {
00425       return (halfplane.first)[0][0]==(halfplane.first)[0][1] &&
00426            (halfplane.first)[1][0]==(halfplane.first)[1][1] ;
00427     }
00428 
00430     boost::array<point_type,2> get_halfplane_points(halfplane_type halfplane)
00431     {
00432       return halfplane.first;
00433     }
00434 
00436     bool is_TOP(halfplane_type halfplane)
00437     {
00438       return halfplane.second == TOP;
00439     }
00440 
00442     bool is_BOTTOM(halfplane_type halfplane)
00443     {
00444       return halfplane.second == BOTTOM;
00445     }
00446 
00447 
00448 
00453     bool point_in_halfplane(point_type point, halfplane_type halfplane)
00454     {
00455       //if the plane spans the bottom portion,
00456       //all that needs to be done is to check if the points
00457       //the define the plane and the point that is beeing checked
00458       //make a left turn
00459       if(is_empty_halfplane(halfplane))
00460       {
00461         return false;
00462       }
00463       if( is_TOP(halfplane))
00464       {
00465         return
00466         _point_position( (halfplane.first)[0],(halfplane.first)[1],point) == LEFT_TURN;
00467       }
00468 
00469       //otherwise, check if it makes a right turn
00470       else
00471       {
00472       return
00473         _point_position( (halfplane.first)[0],(halfplane.first)[1],point) == RIGHT_TURN;
00474       }
00475     }
00476 
00477 
00479   side top()
00480   {
00481     return TOP;
00482   }
00483 
00485   side bottom()
00486   {
00487     return BOTTOM;
00488   }
00489 
00490 
00491   /*
00492    * lines
00493    */
00494 
00495   line_type make_line(const point_type& a, const point_type& b)
00496   {
00497     line_type l = {std::min(a,b, less_x_object_type()),
00498             std::max(a,b, less_x_object_type())};
00499     return l;
00500   }
00501 
00502 
00503 
00504   /*
00505    * triangles
00506    */
00507 
00508 
00510   triangle_type make_trianlge(point_type a, point_type b, point_type c)
00511   {
00512     triangle_type new_t= {a,b,c};
00513     std::sort(new_t.begin(), new_t.end(), less_x_object());
00514 
00515   }
00516 
00518   //point is inside a convex polygon if all  p1,p2, p
00519   //make the same turn (left or right)
00520   bool point_in_open_triangle(point_type p, triangle_type t)
00521   {
00522     return _point_position(t[0], t[1], p)==
00523               _point_position(t[1], t[2], p) &&
00524               _point_position(t[1], t[2], p)==
00525               _point_position(t[2], t[0], p);
00526   }
00527 
00529   bool point_in_closed_triangle(point_type p, triangle_type t)
00530   {
00531     return      point_in_open_triangle(p, t) ||
00532         _point_position(t[0], t[1], p) == COLLINEAR ||
00533         _point_position(t[1], t[2], p) == COLLINEAR ||
00534         _point_position(t[2], t[0], p) == COLLINEAR;
00535 
00536   }
00537 
00538 private:
00539   enum type {LEFT_TURN, COLLINEAR, RIGHT_TURN};
00540 
00541   /*
00542      * Given three points
00543      * 2 points that define a plane
00544      * 1 argument point
00545      *
00546      * the determinant of the matrix is
00547      *
00548      *        |a0 a1 1 |
00549      *    D = |b0 b1 1 | = (b0 - a0)(c1 - a1) - (b1 - a1)(c0 - a0)
00550      *        |c0 c1 1 |
00551      *
00552      * if D>0, than the points make a left turn
00553      * if D==0, then the points are collinear
00554      * else, points make a right turn
00555      */
00556     type
00557     _point_position(point_type plane_point1, point_type plane_point2, point_type point)
00558     {
00559       coord_type D =   (plane_point2[0] - plane_point1[0])
00560               *(point[1] - plane_point1[1])
00561               -(plane_point2[1] - plane_point1[1])
00562               *(point[0] - plane_point1[0]);
00563 
00564       if(0<D)
00565       {
00566         return LEFT_TURN;
00567       }
00568       else if (D<0)
00569       {
00570         return RIGHT_TURN;
00571       }
00572       else
00573       {
00574         return COLLINEAR;
00575 
00576       }
00577     }
00578 
00579 }; //end cgl
00580 
00581 
00582 #include <iostream>
00583 
00584 
00585 std::ostream& operator<<(std::ostream& os, cgl<double>::line_type l)
00586 {
00587   os<<"("<<l[0][0]<<","<<l[0][1]<<")-("
00588     <<l[1][0]<<","<<l[1][1]<<")";
00589   return os;
00590 }
00591 
00592 std::ostream& operator<<(std::ostream& os, cgl<int>::line_type l)
00593 {
00594   os<<"("<<l[0][0]<<","<<l[0][1]<<")-("
00595     <<l[1][0]<<","<<l[1][1]<<")";
00596 //os<<l[0][1];
00597   return os;
00598 }
00599 
00600 
00601 std::ostream& operator<<(std::ostream& os, cgl<double>::point_type l)
00602 {
00603   os<<"("<<l[0]<<","<<l[1]<<")";
00604   return os;
00605 }
00606 
00607 
00608 
00609 std::ostream& operator<<(std::ostream& os, cgl<int>::point_type l)
00610 {
00611   os<<"("<<l[0]<<","<<l[1]<<")";
00612   return os;
00613 }
00614 std::ostream& operator<<(std::ostream& os, cgl<float>::line_type l)
00615 {
00616   os<<"("<<l[0][0]<<","<<l[0][1]<<")-("
00617     <<l[1][0]<<","<<l[1][1]<<")";
00618   return os;
00619 }
00620 
00621 std::ostream& operator<<(std::ostream& os, cgl<float>::line_type& l)
00622 {
00623   os<<"("<<l[0][0]<<","<<l[0][1]<<")-("
00624     <<l[1][0]<<","<<l[1][1]<<")";
00625   return os;
00626 }
00627 
00628 std::ostream& operator<<(std::ostream& os, cgl<float>::point_type l)
00629 {
00630   os<<"("<<l[0]<<","<<l[1]<<")";
00631   return os;
00632 }
00633 
00634 
00635 bool operator==(cgl<int>::line_type& a, cgl<int>::line_type& b)
00636 {
00637         return (a[0][0]==b[0][0] &&
00638                 a[0][1]==b[0][1] &&
00639                 a[1][0]==b[1][0] &&
00640                 a[1][1]==b[1][1]);
00641 }
00642 
00643 #endif

Code Documentation generated Using Doxygen

Copyright © Ilya Katz and Hervé Brönnimann, 2005, 2006.