BWAPI
SPAR/AIModule/BWTA/vendors/CGAL/CGAL/Polygon_2/Polygon_2_algorithms_impl.h
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines