BWAPI
|
00001 // Copyright (c) 1997 Utrecht University (The Netherlands), 00002 // ETH Zurich (Switzerland), Freie Universitaet Berlin (Germany), 00003 // INRIA Sophia-Antipolis (France), Martin-Luther-University Halle-Wittenberg 00004 // (Germany), Max-Planck-Institute Saarbruecken (Germany), RISC Linz (Austria), 00005 // and Tel-Aviv University (Israel). All rights reserved. 00006 // 00007 // This file is part of CGAL (www.cgal.org); you can redistribute it and/or 00008 // modify it under the terms of the GNU Lesser General Public License as 00009 // published by the Free Software Foundation; version 2.1 of the License. 00010 // See the file LICENSE.LGPL distributed with CGAL. 00011 // 00012 // Licensees holding a valid commercial license may use this file in 00013 // accordance with the commercial license agreement provided with the software. 00014 // 00015 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00016 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00017 // 00018 // $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/Polygon/include/CGAL/Polygon_2/Polygon_2_algorithms_impl.h $ 00019 // $Id: Polygon_2_algorithms_impl.h 39249 2007-06-27 13:52:53Z cwormser $ 00020 // 00021 // 00022 // Author(s) : Wieger Wesselink <wieger@cs.ruu.nl> 00023 00024 #include <CGAL/Polygon_2/Polygon_2_simplicity.h> 00025 #include <cstdlib> 00026 #include <algorithm> 00027 #include <iterator> 00028 #include <set> 00029 #include <vector> 00030 00031 CGAL_BEGIN_NAMESPACE 00032 00033 00034 //-----------------------------------------------------------------------// 00035 // is_simple_2 00036 //-----------------------------------------------------------------------// 00037 // uses PolygonTraits::Less_xy_2 00038 // PolygonTraits::less_xy_2 00039 // PolygonTraits::Orientation_2 00040 // PolygonTraits::orientation_2 00041 // PolygonTraits::Point_2 00042 00043 00044 template <class ForwardIterator, class PolygonTraits> 00045 bool is_simple_2(ForwardIterator first, 00046 ForwardIterator last, 00047 const PolygonTraits& traits) 00048 { 00049 return is_simple_polygon(first, last, traits); 00050 } 00051 00052 00053 //-----------------------------------------------------------------------// 00054 // left_vertex_2 00055 //-----------------------------------------------------------------------// 00056 // uses PolygonTraits::Less_xy_2 and less_xy_2_object() 00057 00058 template <class ForwardIterator, class PolygonTraits> 00059 ForwardIterator left_vertex_2(ForwardIterator first, 00060 ForwardIterator last, 00061 const PolygonTraits&traits) 00062 { 00063 CGAL_polygon_precondition(first != last); 00064 return std::min_element(first, last, traits.less_xy_2_object()); 00065 } 00066 00067 //-----------------------------------------------------------------------// 00068 // right_vertex_2 00069 //-----------------------------------------------------------------------// 00070 // uses PolygonTraits::Less_xy_2 and less_xy_2_object() 00071 00072 template <class ForwardIterator, class PolygonTraits> 00073 ForwardIterator right_vertex_2(ForwardIterator first, 00074 ForwardIterator last, 00075 const PolygonTraits &traits) 00076 { 00077 CGAL_polygon_precondition(first != last); 00078 return std::max_element(first, last, traits.less_xy_2_object()); 00079 } 00080 00081 //-----------------------------------------------------------------------// 00082 // top_vertex_2 00083 //-----------------------------------------------------------------------// 00084 // uses PolygonTraits::Less_yx_2 and less_yx_2_object() 00085 00086 template <class ForwardIterator, class PolygonTraits> 00087 ForwardIterator top_vertex_2(ForwardIterator first, 00088 ForwardIterator last, 00089 const PolygonTraits&traits) 00090 { 00091 CGAL_polygon_precondition(first != last); 00092 return std::max_element(first, last, traits.less_yx_2_object()); 00093 } 00094 00095 //-----------------------------------------------------------------------// 00096 // bottom_vertex_2 00097 //-----------------------------------------------------------------------// 00098 // uses PolygonTraits::Less_yx_2 and less_yx_2_object() 00099 00100 template <class ForwardIterator, class PolygonTraits> 00101 ForwardIterator bottom_vertex_2(ForwardIterator first, 00102 ForwardIterator last, 00103 const PolygonTraits&traits) 00104 { 00105 CGAL_polygon_precondition(first != last); 00106 return std::min_element(first, last, traits.less_yx_2_object()); 00107 } 00108 00109 //-----------------------------------------------------------------------// 00110 // bbox_2 00111 //-----------------------------------------------------------------------// 00112 00113 template <class InputIterator, class PolygonTraits> 00114 Bbox_2 bbox_2(InputIterator first, 00115 InputIterator last, 00116 const PolygonTraits& traits) 00117 { 00118 typename PolygonTraits::Construct_bbox_2 00119 construct_bbox = traits.construct_bbox_2_object(); 00120 00121 CGAL_polygon_precondition(first != last); 00122 Bbox_2 result = construct_bbox(*first); 00123 00124 while (++first != last) 00125 result = result + construct_bbox(*first); 00126 00127 return result; 00128 } 00129 00130 //-----------------------------------------------------------------------// 00131 // area_2 00132 //-----------------------------------------------------------------------// 00133 // uses Traits:: 00134 // implemented in header file 00135 00136 00137 //-----------------------------------------------------------------------// 00138 // is_convex_2 00139 //-----------------------------------------------------------------------// 00140 // uses Traits::Less_xy_2 and less_xy_2_object() 00141 // Traits::Orientation_2 and orientation_2_object() 00142 // Traits::Equal_2 for filtering repeated points 00143 00144 template <class ForwardIterator, class Traits> 00145 bool is_convex_2(ForwardIterator first, 00146 ForwardIterator last, 00147 const Traits& traits) 00148 { 00149 ForwardIterator previous = first; 00150 if (previous == last) return true; 00151 00152 ForwardIterator current = previous; ++current; 00153 if (current == last) return true; 00154 00155 ForwardIterator next = current; ++next; 00156 if (next == last) return true; 00157 00158 typename Traits::Equal_2 equal = traits.equal_2_object(); 00159 00160 while(equal(*previous, *current)) { 00161 current = next; 00162 ++next; 00163 if (next == last) return true; 00164 } 00165 00166 typename Traits::Less_xy_2 less_xy_2 = traits.less_xy_2_object(); 00167 typename Traits::Orientation_2 orientation = traits.orientation_2_object(); 00168 // initialization 00169 bool HasClockwiseTriples = false; 00170 bool HasCounterClockwiseTriples = false; 00171 bool Order = less_xy_2(*previous, *current); 00172 int NumOrderChanges = 0; 00173 00174 do { 00175 switch_orient: 00176 switch (orientation(*previous, *current, *next)) { 00177 case CLOCKWISE: 00178 HasClockwiseTriples = true; 00179 break; 00180 case COUNTERCLOCKWISE: 00181 HasCounterClockwiseTriples = true; 00182 break; 00183 case ZERO: 00184 if(equal(*current, *next)) { 00185 if(next == first) { 00186 first = current; 00187 } 00188 ++next; 00189 if (next == last) 00190 next = first; 00191 goto switch_orient; 00192 } 00193 break; 00194 } 00195 00196 bool NewOrder = less_xy_2(*current, *next); 00197 if (Order != NewOrder) NumOrderChanges++; 00198 00199 if (NumOrderChanges > 2) { 00200 #ifdef CGAL_POLYGON_DEBUG 00201 std::cout << "too many order changes: not convex!" << std::endl; 00202 #endif 00203 return false; 00204 } 00205 00206 if (HasClockwiseTriples && HasCounterClockwiseTriples) { 00207 #ifdef CGAL_POLYGON_DEBUG 00208 std::cout << "polygon not locally convex!" << std::endl; 00209 #endif 00210 return false; 00211 } 00212 00213 previous = current; 00214 current = next; 00215 ++next; 00216 if (next == last) next = first; 00217 Order = NewOrder; 00218 } 00219 while (previous != first); 00220 00221 return true; 00222 } 00223 00224 //-----------------------------------------------------------------------// 00225 // oriented_side_2 00226 //-----------------------------------------------------------------------// 00227 // uses Traits::Less_xy_2 00228 // Traits::Compare_x_2 compare_x_2_object() 00229 // Traits::Compare_y_2 compare_y_2_object() 00230 // Traits::Orientation_2 and orientation_2_object() 00231 00232 template <class ForwardIterator, class Point, class Traits> 00233 Oriented_side oriented_side_2(ForwardIterator first, 00234 ForwardIterator last, 00235 const Point& point, 00236 const Traits& traits) 00237 { 00238 Orientation o = orientation_2(first, last, traits); 00239 CGAL_polygon_assertion(o != COLLINEAR); 00240 00241 Bounded_side b = bounded_side_2(first, last, point, traits); 00242 switch (b) { 00243 case ON_BOUNDARY: 00244 return ON_ORIENTED_BOUNDARY; 00245 00246 case ON_BOUNDED_SIDE: 00247 return (o == CLOCKWISE) ? ON_NEGATIVE_SIDE : ON_POSITIVE_SIDE; 00248 00249 default: 00250 //case ON_UNBOUNDED_SIDE: 00251 return (o == CLOCKWISE) ? ON_POSITIVE_SIDE : ON_NEGATIVE_SIDE; 00252 } 00253 } 00254 00255 //-----------------------------------------------------------------------// 00256 // bounded_side_2 00257 //-----------------------------------------------------------------------// 00258 // uses Traits::Compare_x_2 compare_x_2_object() 00259 // Traits::Compare_y_2 compare_y_2_object() 00260 // Traits::Orientation_2 and orientation_2_object() 00261 // 00262 // returns ON_BOUNDED_SIDE, ON_BOUNDARY or ON_UNBOUNDED_SIDE 00263 00264 /* 00265 Implementation: we shoot a horizontal ray from the point to the right 00266 and count the number of intersections with polygon segments. 00267 If the number of intersections is odd, the point is inside. 00268 We don't count intersections with horizontal segments. 00269 With non-horizontal segments, the top vertex is considered to be part of 00270 the segment, but the bottom vertex is not. (Segments are half-closed). 00271 */ 00272 00273 namespace i_polygon { 00274 00275 template <class Point, class Orientation_2, class CompareX_2> 00276 int which_side_in_slab(Point const &point, Point const &low, Point const &high, 00277 Orientation_2 &orientation_2, CompareX_2 &compare_x_2) 00278 // returns -1 if point is left of segment <low, high>, 0 if its on the segment 00279 // and 1 if it is to the right 00280 // precondition: low.y < point.y < high.y 00281 { 00282 // first we try to decide on x coordinate values alone 00283 // This is an optimisation (whether this is really faster for 00284 // a homogeneous kernel is not clear, as comparisons can be expensive. 00285 Comparison_result low_x_comp_res = compare_x_2(point, low); 00286 Comparison_result high_x_comp_res = compare_x_2(point, high); 00287 if (low_x_comp_res == SMALLER) { 00288 if (high_x_comp_res == SMALLER) 00289 return -1; 00290 } else { 00291 switch (high_x_comp_res) { 00292 case LARGER: return 1; 00293 case SMALLER: break; 00294 case EQUAL: return (low_x_comp_res == EQUAL) ? 0 : 1; 00295 } 00296 } 00297 switch (orientation_2(low, point, high)) { 00298 case LEFT_TURN: return 1; 00299 case RIGHT_TURN: return -1; 00300 default: return 0; 00301 } 00302 } 00303 00304 } // end namespace i_polygon 00305 00306 template <class ForwardIterator, class Point, class Traits> 00307 Bounded_side bounded_side_2(ForwardIterator first, 00308 ForwardIterator last, 00309 const Point& point, 00310 const Traits& traits) 00311 { 00312 ForwardIterator current = first; 00313 if (current == last) return ON_UNBOUNDED_SIDE; 00314 00315 ForwardIterator next = current; ++next; 00316 if (next == last) return ON_UNBOUNDED_SIDE; 00317 00318 typename Traits::Compare_x_2 compare_x_2 = traits.compare_x_2_object(); 00319 typename Traits::Compare_y_2 compare_y_2 = traits.compare_y_2_object(); 00320 typename Traits::Orientation_2 orientation_2 = traits.orientation_2_object(); 00321 bool IsInside = false; 00322 Comparison_result cur_y_comp_res = compare_y_2(*current, point); 00323 00324 do // check if the segment (current,next) intersects 00325 // the ray { (t,point.y()) | t >= point.x() } 00326 { 00327 Comparison_result next_y_comp_res = compare_y_2(*next, point); 00328 00329 switch (cur_y_comp_res) { 00330 case SMALLER: 00331 switch (next_y_comp_res) { 00332 case SMALLER: 00333 break; 00334 case EQUAL: 00335 switch (compare_x_2(point, *next)) { 00336 case SMALLER: IsInside = !IsInside; break; 00337 case EQUAL: return ON_BOUNDARY; 00338 case LARGER: break; 00339 } 00340 break; 00341 case LARGER: 00342 switch (i_polygon::which_side_in_slab(point, *current, *next, 00343 orientation_2, compare_x_2)) { 00344 case -1: IsInside = !IsInside; break; 00345 case 0: return ON_BOUNDARY; 00346 } 00347 break; 00348 } 00349 break; 00350 case EQUAL: 00351 switch (next_y_comp_res) { 00352 case SMALLER: 00353 switch (compare_x_2(point, *current)) { 00354 case SMALLER: IsInside = !IsInside; break; 00355 case EQUAL: return ON_BOUNDARY; 00356 case LARGER: break; 00357 } 00358 break; 00359 case EQUAL: 00360 switch (compare_x_2(point, *current)) { 00361 case SMALLER: 00362 if (compare_x_2(point, *next) != SMALLER) 00363 return ON_BOUNDARY; 00364 break; 00365 case EQUAL: return ON_BOUNDARY; 00366 case LARGER: 00367 if (compare_x_2(point, *next) != LARGER) 00368 return ON_BOUNDARY; 00369 break; 00370 } 00371 break; 00372 case LARGER: 00373 if (compare_x_2(point, *current) == EQUAL) { 00374 return ON_BOUNDARY; 00375 } 00376 break; 00377 } 00378 break; 00379 case LARGER: 00380 switch (next_y_comp_res) { 00381 case SMALLER: 00382 switch (i_polygon::which_side_in_slab(point, *next, *current, 00383 orientation_2, compare_x_2)) { 00384 case -1: IsInside = !IsInside; break; 00385 case 0: return ON_BOUNDARY; 00386 } 00387 break; 00388 case EQUAL: 00389 if (compare_x_2(point, *next) == EQUAL) { 00390 return ON_BOUNDARY; 00391 } 00392 break; 00393 case LARGER: 00394 break; 00395 } 00396 break; 00397 } 00398 00399 current = next; 00400 cur_y_comp_res = next_y_comp_res; 00401 ++next; 00402 if (next == last) next = first; 00403 } 00404 while (current != first); 00405 00406 return IsInside ? ON_BOUNDED_SIDE : ON_UNBOUNDED_SIDE; 00407 } 00408 00409 //-----------------------------------------------------------------------// 00410 // orientation_2 00411 //-----------------------------------------------------------------------// 00412 // uses Traits::Less_xy_2 (used by left_vertex_2) 00413 // Traits::orientation_2_object() 00414 00415 template <class ForwardIterator, class Traits> 00416 Orientation orientation_2(ForwardIterator first, 00417 ForwardIterator last, 00418 const Traits& traits) 00419 { 00420 CGAL_polygon_precondition(is_simple_2(first, last, traits)); 00421 00422 ForwardIterator i = left_vertex_2(first, last, traits); 00423 00424 ForwardIterator prev = (i == first) ? last : i; 00425 --prev; 00426 00427 ForwardIterator next = i; 00428 ++next; 00429 if (next == last) 00430 next = first; 00431 00432 // if the range [first,last) contains less than three points, then some 00433 // of the points (prev,i,next) will coincide 00434 00435 // return the orientation of the triple (prev,i,next) 00436 return traits.orientation_2_object()(*prev, *i, *next); 00437 } 00438 00439 CGAL_END_NAMESPACE 00440