|
Space-efficient geometric algorithms and data structuresBy Ilya Katz and Hervé Brönnimann |
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.