// ====================================================================== // // Copyright (c) 1997 The CGAL Consortium // // This software and related documentation is part of an INTERNAL release // of the Computational Geometry Algorithms Library (CGAL). It is not // intended for general use. // // ---------------------------------------------------------------------- // // release : $CGAL_Revision: CGAL-0.9-I-06 $ // release_date : $CGAL_Date: 1998/03/11 $ // // file : include/CGAL/Polygon_2_algorithms.C // source : // revision : 1.8a // revision_date : 13 Mar 1998 // author(s) : Wieger Wesselink // // coordinator : Utrecht University // // ====================================================================== #include #include #include #include #include CGAL_BEGIN_NAMESPACE //-----------------------------------------------------------------------// // Simplicity_test_2 //-----------------------------------------------------------------------// // The simplicity test is implemented as a class. // The algorithm used is a sweep line algorithm. The sweep line is a // horizontal line that sweeps from top (big y) to bottom. // In the sweep status the edges are ordered from left (small) to right // (big). template class Simplicity_test_2 { protected: std::vector d_index; // the attribute d_index is just a mapping between the integers and the // sequence of points int d_eventpoint; // the index of the current event point // the current sweepline is the horizontal line through this point const Traits& d_traits; // the traits class for polygons public: typedef typename Traits::Point_2 Point_2; Simplicity_test_2(const Traits& tr): d_traits(tr) {} ~Simplicity_test_2() {} const Traits& traits() const { return d_traits; } const Point_2& Vertex(int i) const { return *d_index[i]; } int NumberOfVertices() const { return d_index.size(); } const Point_2& EventPoint() const { return Vertex(d_eventpoint); } // return the current event point bool Test(ForwardIterator first, ForwardIterator last); // tests if the polygon with points in the range [first,last) is simple bool EdgesDoIntersect(int e1, int e2) const; // tests if the edges e1 and e2 have an intersection // N.B. the common vertex of two consecutive edges is not counted // as an intersection! bool VertexCompare(int i, int j) const; // compares the (lexicographical) order of vertex(i) and vertex(j) class VertexComp { protected: const Simplicity_test_2* s; public: VertexComp() {} VertexComp( const Simplicity_test_2* s0): s(s0) {} bool operator() (int i, int j) const { return s->VertexCompare(i,j); } }; bool has_on_left_side(const Point_2& p, const Point_2& q, const Point_2& r ) const // returns true if point p is left of the point w, where w is the leftmost // intersection point of the horizontal line through p and the line // segment qr // N.B. if p lies on the segment qr, the result is indeterminate. { Comparison_result qr = d_traits.compare_y(q,r); if (qr == EQUAL) return (d_traits.compare_x(p,q) == SMALLER); else return ( d_traits.is_negative(d_traits.cross_product_2(p-q,r-q)) == (qr == SMALLER) ); } bool has_y_overlap(const Point_2& p, const Point_2& q, const Point_2& r ) const // returns true if the horizontal line through p intersects the segments qr { Comparison_result pq = d_traits.compare_y(p,q); Comparison_result pr = d_traits.compare_y(p,r); return (pq != pr) || (pq == EQUAL); } bool EdgeCompare(int e1, int e2) const; // computes the order of two edges e1 and e2 on the current sweepline bool edge_compare_consecutive(int e1, int e2) const; // computes the order of two edges e1 and e2 that share a vertex bool edge_compare_non_consecutive(int e1, int e2) const; // computes the order of two edges e1 and e2 that do not share a vertex bool consecutive_edges(int e1, int e2) const; // true if the edges e1 and e2 are not equal but share a vertex class EdgeComp { protected: const Simplicity_test_2* s; public: EdgeComp() {} EdgeComp( const Simplicity_test_2* s0): s(s0) {} bool operator() (int i, int j) const { return s->EdgeCompare(i,j); } }; class EventQueue { //-----------------------------------------------------------------// // g++ 2.7.2 seems to have problems with the following typedef // // typedef set::const_iterator const_iterator; //-----------------------------------------------------------------// protected: std::set queue; public: EventQueue(Simplicity_test_2* s) : queue(VertexComp(s)) {} bool insert(int i) { return queue.insert(i).second; } bool empty() const { return queue.empty(); } int pop() { int Result = *(queue.begin()); queue.erase(queue.begin()); return Result; } #ifdef CGAL_POLYGON_DEBUG void Show() const { cout << " event queue: "; typename std::set::const_iterator i; for (i = queue.begin(); i != queue.end(); ++i) cout << *i << " "; cout << endl; } #endif }; class SweepStatus { //-----------------------------------------------------------------// // g++ 2.7.2 seems to have problems with the following typedef // // typedef std::set::const_iterator const_iterator; //-----------------------------------------------------------------// protected: std::set status; // if i is an element of status, it means that std::vector::iterator> index; // the iterators of the edges are stored to enable fast deletion const Simplicity_test_2* s; // store a pointer to the Simplicity_test_2 class, to enable // access to the vertices public: SweepStatus( const Simplicity_test_2* s0, int n) : status(EdgeComp(s0)), s(s0) { index.insert(index.end(),n,status.end()); } bool is_valid() // A necessary condition for the sweep status to be valid is that // // 1) every edge in the status intersects the current sweepline // 2) the edges are ordered along the current sweepline { int n = s->NumberOfVertices(); typename std::set::const_iterator i; for (i = status.begin(); i != status.end(); ++i) { int v1 = *i; int v2 = (v1traits().compare_y(s->Vertex(v1), s->EventPoint()); Comparison_result c2 = s->traits().compare_y(s->Vertex(v2), s->EventPoint()); if (c1 == SMALLER && c2 == SMALLER) return false; if (c1 == LARGER && c2 == LARGER) return false; } return true; } #ifdef CGAL_POLYGON_DEBUG void Show() { cout << " sweep status: "; typename std::set::const_iterator i; for (i = status.begin(); i != status.end(); ++i) cout << *i << " "; cout << endl; } #endif // CGAL_POLYGON_DEBUG void insert(int e) { #ifdef CGAL_POLYGON_DEBUG { cout << endl << " inserting edge " << e << " into sweep status" << endl; } #endif // CGAL_POLYGON_DEBUG index[e] = status.insert(e).first; } void erase(int e) { #ifdef CGAL_POLYGON_DEBUG { cout << endl << " removing edge " << e << " from sweep status" << endl; } #endif // CGAL_POLYGON_DEBUG status.erase(index[e]); } int replace(int e1, int e2) { #ifdef CGAL_POLYGON_DEBUG { cout << endl << " replacing edge " << e1 << " by edge "<< e2 << " in sweep status" << endl; } #endif // CGAL_POLYGON_DEBUG typename std::set::iterator cur = index[e1]; status.erase(cur++); index[e2] = status.insert(cur, e2); return e2; } int left(int e) const { typename std::set::const_iterator i = index[e]; return (i == status.begin()) ? -1 : *(--i); } int right(int e) const { typename std::set::const_iterator i = index[e]; ++i; return (i == status.end()) ? -1 : *i; } }; }; template inline bool Simplicity_test_2::VertexCompare( int i, int j) const { return !d_traits.lexicographically_yx_smaller_or_equal(Vertex(i), Vertex(j)); } template inline bool Simplicity_test_2::EdgeCompare( int e1, int e2) const { // Edges must always be compared in the same order! This is to avoid problems // with overlapping edges: // // + v0 // / // -----------------+-v2----------------- sweepline // / // / // / // / // + v1 // // In this case the order of the edges e0 = (v0,v1) and e1 = (v1,v2) on the // sweepline is indeterminate. However, it will only be detected that these // edges overlap after they have been inserted in the sweep state. To make // sure that this insertion is done correctly, the choice for the order // between e0 and e1 needs to be made consistently. bool Result; if (consecutive_edges(e1,e2)) { if (e1 < e2) Result = edge_compare_consecutive(e1,e2); else Result = !edge_compare_consecutive(e2,e1); } else { if (e1 < e2) Result = edge_compare_non_consecutive(e1,e2); else Result = !edge_compare_non_consecutive(e2,e1); } return Result; } template bool Simplicity_test_2::edge_compare_consecutive( int e1, int e2) const // This function is used to compare two edges that share a vertex: // // + | // / \ | // e1 / \ e2 | // / \ | // / \ | // -------------+---------+------------- sweepline | // / \ | // + + | // // Preconditions: 1) the shared vertex is lexicographically smaller or // lexicographically bigger than both endpoints of the two // edges (this condition is always satisfied in the // sweepline algorithm) // // 2) both edges intersect the current sweepline { int n = NumberOfVertices(); int f1 = (e1 bool Simplicity_test_2::edge_compare_non_consecutive( int e1, int e2) const { int n = NumberOfVertices(); int f1 = (e1 bool Simplicity_test_2::Test(ForwardIterator first, ForwardIterator last) { int n = 0; EventQueue events(this); while (first != last) { d_index.push_back(first); if (!events.insert(n++)) // if two vertices coincide... return false; ++first; } if (d_index.size() < 3) return true; #ifdef CGAL_POLYGON_DEBUG { cout << endl; cout << "--- Simplicity test ----------------------------" << endl; cout << endl; cout << "Vertices:" << endl; typedef typename std::vector::size_type Size_type; Size_type i; for (i=0; i0) ? i-1 : i-1+n; int next = (i= 0) && (EdgesDoIntersect(left,e))) return false; int right = status.right(e); if ((right >= 0) && (EdgesDoIntersect(e,right))) return false; } else if (prev_less_than_i) { int e1 = prev; int e2 = i; status.insert(e1); status.insert(e2); CGAL_polygon_assertion(status.is_valid()); #ifdef CGAL_POLYGON_DEBUG { cout << endl; status.Show(); } #endif // CGAL_POLYGON_DEBUG // check for intersections of newly inserted edges e1 and e2 with // neighbors int left, right; left = status.left(e1); if ((left >= 0) && (EdgesDoIntersect(left,e1))) return false; right = status.right(e1); if ((right >= 0) && (EdgesDoIntersect(e1,right))) return false; left = status.left(e2); if ((left >= 0) && (left != e1) && (EdgesDoIntersect(left,e2))) return false; right = status.right(e2); if ((right >= 0) && (right != e1) &&(EdgesDoIntersect(e2,right))) return false; } else { // check for intersections between edges that become new neighbors // in the sweep status due to the deletion int left, right; if (status.left(prev) == i) { left = status.left(i); right = status.right(prev); } else { left = status.left(prev); right = status.right(i); } status.erase(prev); status.erase(i); if (left >=0 && right >=0 && EdgesDoIntersect(left, right)) return false; CGAL_polygon_assertion(status.is_valid()); #ifdef CGAL_POLYGON_DEBUG { cout << endl; status.Show(); } #endif // CGAL_POLYGON_DEBUG } } return true; } template bool Simplicity_test_2::EdgesDoIntersect( int e1, int e2) const { #ifdef CGAL_POLYGON_DEBUG { cout << " intersecting edges " << e1 << " and " << e2 << endl; } #endif int n = NumberOfVertices(); int f1 = (e1 inline bool Simplicity_test_2::consecutive_edges( int e1, int e2) const { int n = NumberOfVertices(); return ( CGAL_NTS abs(e2-e1) == 1 || CGAL_NTS abs(e2-e1) == n-1 ); } //-----------------------------------------------------------------------// // is_simple_2 //-----------------------------------------------------------------------// // uses Traits::compare_x // Traits::compare_y // Traits::cross_product_2 // Traits::do_intersect // Traits::have_equal_direction // Traits::is_negative // Traits::lexicographically_yx_smaller_or_equal template bool is_simple_2(ForwardIterator first, ForwardIterator last, const Traits& traits) { Simplicity_test_2 test(traits); return test.Test(first, last); } //-----------------------------------------------------------------------// // left_vertex_2 //-----------------------------------------------------------------------// // uses Traits::Less_xy template ForwardIterator left_vertex_2(ForwardIterator first, ForwardIterator last, const Traits&) { CGAL_polygon_precondition(first != last); typedef typename Traits::Less_xy Less_xy; return std::min_element(first, last, Less_xy()); } //-----------------------------------------------------------------------// // right_vertex_2 //-----------------------------------------------------------------------// // uses Traits::Less_xy template ForwardIterator right_vertex_2(ForwardIterator first, ForwardIterator last, const Traits&) { CGAL_polygon_precondition(first != last); typedef typename Traits::Less_xy Less_xy; return std::max_element(first, last, Less_xy()); } //-----------------------------------------------------------------------// // top_vertex_2 //-----------------------------------------------------------------------// // uses Traits::Less_yx template ForwardIterator top_vertex_2(ForwardIterator first, ForwardIterator last, const Traits&) { CGAL_polygon_precondition(first != last); typedef typename Traits::Less_yx Less_yx; return std::max_element(first, last, Less_yx()); } //-----------------------------------------------------------------------// // bottom_vertex_2 //-----------------------------------------------------------------------// // uses Traits::Less_yx template ForwardIterator bottom_vertex_2(ForwardIterator first, ForwardIterator last, const Traits&) { CGAL_polygon_precondition(first != last); typedef typename Traits::Less_yx Less_yx; return std::min_element(first, last, Less_yx()); } //-----------------------------------------------------------------------// // bbox_2 //-----------------------------------------------------------------------// template Bbox_2 bbox_2(InputIterator first, InputIterator last) { CGAL_polygon_precondition(first != last); Bbox_2 result = (*first).bbox(); while (++first != last) result = result + (*first).bbox(); return result; } //-----------------------------------------------------------------------// // area_2 //-----------------------------------------------------------------------// // uses Traits::determinant_2 // template // void area_2(ForwardIterator first, // ForwardIterator last, // FT& result, // const Traits& traits) //{ //-----------------------------------------------------------------------// // is_convex_2 //-----------------------------------------------------------------------// // uses Traits::lexicographically_xy_smaller // Traits::orientation template bool is_convex_2(ForwardIterator first, ForwardIterator last, const Traits& traits) { ForwardIterator previous = first; if (previous == last) return true; ForwardIterator current = previous; ++current; if (current == last) return true; ForwardIterator next = current; ++next; if (next == last) return true; // initialization bool HasClockwiseTriples = false; bool HasCounterClockwiseTriples = false; bool Order = traits.lexicographically_xy_smaller(*previous, *current); int NumOrderChanges = 0; do { switch (traits.orientation(*previous, *current, *next)) { case CLOCKWISE: HasClockwiseTriples = true; break; case COUNTERCLOCKWISE: HasCounterClockwiseTriples = true; break; default: ; } bool NewOrder = traits.lexicographically_xy_smaller(*current, *next); if (Order != NewOrder) NumOrderChanges++; if (NumOrderChanges > 2) { #ifdef CGAL_POLYGON_DEBUG cout << "too many order changes: not convex!" << endl; #endif return false; } if (HasClockwiseTriples && HasCounterClockwiseTriples) { #ifdef CGAL_POLYGON_DEBUG cout << "polygon not locally convex!" << endl; #endif return false; } previous = current; current = next; ++next; if (next == last) next = first; Order = NewOrder; } while (previous != first); return true; } //-----------------------------------------------------------------------// // oriented_side_2 //-----------------------------------------------------------------------// // uses Traits::Less_xy // Traits::compare_x // Traits::compare_y // Traits::determinant_2 // Traits::orientation // Traits::sign template Oriented_side oriented_side_2(ForwardIterator first, ForwardIterator last, const Point& point, const Traits& traits) { Oriented_side result; Orientation o = orientation_2(first, last, traits); CGAL_polygon_assertion(o != COLLINEAR); Bounded_side b = bounded_side_2(first, last, point, traits); switch (b) { case ON_BOUNDARY: result = ON_ORIENTED_BOUNDARY; break; case ON_BOUNDED_SIDE: result = (o == CLOCKWISE) ? ON_NEGATIVE_SIDE : ON_POSITIVE_SIDE; break; case ON_UNBOUNDED_SIDE: result = (o == CLOCKWISE) ? ON_POSITIVE_SIDE : ON_NEGATIVE_SIDE; break; } return result; } //-----------------------------------------------------------------------// // bounded_side_2 //-----------------------------------------------------------------------// // uses Traits::compare_x // Traits::compare_y // Traits::determinant_2 // Traits::sign // // returns ON_BOUNDED_SIDE, ON_BOUNDARY or ON_UNBOUNDED_SIDE template Bounded_side bounded_side_2(ForwardIterator first, ForwardIterator last, const Point& point, const Traits& traits) { ForwardIterator current = first; if (current == last) return ON_UNBOUNDED_SIDE; ForwardIterator next = current; ++next; if (next == last) return ON_UNBOUNDED_SIDE; bool IsInside = false; Comparison_result CompareCurrent = traits.compare_y(*current, point); do // check if the segment (current,next) intersects // the ray { (t,y) | t >= point.x() } { Comparison_result CompareNext = traits.compare_y(*next, point); switch (CompareCurrent) { case SMALLER: switch (CompareNext) { case SMALLER: break; case EQUAL: switch (traits.compare_x(point, *next)) { case SMALLER: IsInside = !IsInside; break; case EQUAL: return ON_BOUNDARY; case LARGER: break; } break; case LARGER: if (point.x() < std::min((*current).x(), (*next).x())) { IsInside = !IsInside; } else if (point.x() <= std::max((*current).x(),(*next).x())) { switch (traits.sign(traits.determinant_2(point, *current, *next))) { case 0: return ON_BOUNDARY; case 1: IsInside = !IsInside; break; } } break; } break; case EQUAL: switch (CompareNext) { case SMALLER: switch (traits.compare_x(point, *current)) { case SMALLER: IsInside = !IsInside; break; case EQUAL: return ON_BOUNDARY; case LARGER: break; } break; case EQUAL: if ( (std::min((*current).x(), (*next).x()) <= point.x()) && (point.x() <= std::max((*current).x(), (*next).x())) ) { return ON_BOUNDARY; } break; case LARGER: if (point.x() == (*current).x()) { return ON_BOUNDARY; } break; } break; case LARGER: switch (CompareNext) { case SMALLER: if (point.x() < std::min((*current).x(), (*next).x())) { IsInside = !IsInside; } else if (point.x() <= std::max((*current).x(),(*next).x())) { switch (traits.sign(traits.determinant_2(point, *current, *next))) { case -1: IsInside = !IsInside; break; case 0: return ON_BOUNDARY; } } break; case EQUAL: if (point.x() == (*next).x()) { return ON_BOUNDARY; } break; case LARGER: break; } break; } current = next; CompareCurrent = CompareNext; ++next; if (next == last) next = first; } while (current != first); return IsInside ? ON_BOUNDED_SIDE : ON_UNBOUNDED_SIDE; } //-----------------------------------------------------------------------// // orientation_2 //-----------------------------------------------------------------------// // uses Traits::Less_xy // Traits::orientation template Orientation orientation_2(ForwardIterator first, ForwardIterator last, const Traits& traits) { CGAL_polygon_precondition(is_simple_2(first, last, traits)); ForwardIterator i = left_vertex_2(first, last, traits); ForwardIterator prev = (i == first) ? last : i; --prev; ForwardIterator next = i; ++next; if (next == last) next = first; // if the range [first,last) contains less than three points, then some // of the points (prev,i,next) will coincide // return the orientation of the triple (prev,i,next) return traits.orientation(*prev, *i, *next); } CGAL_END_NAMESPACE