mirror of https://github.com/CGAL/cgal
959 lines
30 KiB
C
959 lines
30 KiB
C
// ======================================================================
|
|
//
|
|
// 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 <wieger@cs.ruu.nl>
|
|
//
|
|
// coordinator : Utrecht University
|
|
//
|
|
// ======================================================================
|
|
|
|
#include <CGAL/Polygon_2_algorithms.h>
|
|
|
|
#include <cstdlib>
|
|
#include <algorithm>
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
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 ForwardIterator, class Traits>
|
|
class Simplicity_test_2 {
|
|
protected:
|
|
std::vector<ForwardIterator> 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<ForwardIterator, Traits>* s;
|
|
public:
|
|
VertexComp() {}
|
|
VertexComp(
|
|
const Simplicity_test_2<ForwardIterator, Traits>* 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<ForwardIterator, Traits>* s;
|
|
public:
|
|
EdgeComp() {}
|
|
EdgeComp(
|
|
const Simplicity_test_2<ForwardIterator, Traits>* 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<int,VertexComp>::const_iterator const_iterator;
|
|
//-----------------------------------------------------------------//
|
|
|
|
protected:
|
|
std::set<int,VertexComp> queue;
|
|
public:
|
|
EventQueue(Simplicity_test_2<ForwardIterator, Traits>* 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<int,VertexComp>::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<int,EdgeComp>::const_iterator const_iterator;
|
|
//-----------------------------------------------------------------//
|
|
|
|
protected:
|
|
std::set<int,EdgeComp> status;
|
|
// if i is an element of status, it means that
|
|
|
|
std::vector<typename std::set<int,EdgeComp>::iterator> index;
|
|
// the iterators of the edges are stored to enable fast deletion
|
|
|
|
const Simplicity_test_2<ForwardIterator, Traits>* s;
|
|
// store a pointer to the Simplicity_test_2 class, to enable
|
|
// access to the vertices
|
|
|
|
public:
|
|
SweepStatus(
|
|
const Simplicity_test_2<ForwardIterator, Traits>* 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<int,EdgeComp>::const_iterator i;
|
|
for (i = status.begin(); i != status.end(); ++i) {
|
|
int v1 = *i;
|
|
int v2 = (v1<n-1) ? v1+1 : v1+1-n;
|
|
// edge(v1) = (vertex(v1), vertex(v2))
|
|
|
|
Comparison_result c1 =
|
|
s->traits().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<int,EdgeComp>::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<int,EdgeComp>::iterator cur = index[e1];
|
|
status.erase(cur++);
|
|
index[e2] = status.insert(cur, e2);
|
|
return e2;
|
|
}
|
|
|
|
int left(int e) const
|
|
{ typename std::set<int,EdgeComp>::const_iterator i = index[e];
|
|
return (i == status.begin()) ? -1 : *(--i);
|
|
}
|
|
|
|
int right(int e) const
|
|
{ typename std::set<int,EdgeComp>::const_iterator i = index[e]; ++i;
|
|
return (i == status.end()) ? -1 : *i;
|
|
}
|
|
};
|
|
};
|
|
|
|
template <class ForwardIterator, class Traits>
|
|
inline
|
|
bool Simplicity_test_2<ForwardIterator, Traits>::VertexCompare(
|
|
int i, int j) const
|
|
{
|
|
return !d_traits.lexicographically_yx_smaller_or_equal(Vertex(i), Vertex(j));
|
|
}
|
|
|
|
template <class ForwardIterator, class Traits>
|
|
inline
|
|
bool Simplicity_test_2<ForwardIterator, Traits>::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 <class ForwardIterator, class Traits>
|
|
bool Simplicity_test_2<ForwardIterator, Traits>::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<n-1) ? e1+1 : e1+1-n; // edge(e1) = (vertex(e1), vertex(f1))
|
|
int f2 = (e2<n-1) ? e2+1 : e2+1-n; // edge(e2) = (vertex(e2), vertex(f2))
|
|
|
|
if (f1 == e2)
|
|
if (d_traits.compare_y(Vertex(e2), Vertex(f2)) != EQUAL)
|
|
return has_on_left_side(Vertex(e1), Vertex(e2), Vertex(f2));
|
|
else if (d_traits.compare_x(Vertex(e2), Vertex(f2)) == SMALLER)
|
|
// Precondition 1) implies that e1 is on or above line (e2, f2).
|
|
// If above the line, then say segment e1 is smaller. If on the line,
|
|
// vertex e1 is to the right of e2; by convention make the edge
|
|
// with the smaller other endpoint the smaller one.
|
|
return (d_traits.compare_y(Vertex(e1), Vertex(f2)) != EQUAL) ||
|
|
(d_traits.compare_x(Vertex(e1), Vertex(f2)) == SMALLER);
|
|
else // vertex e1 is on or below line (e2, f2); edge e1 is smaller only
|
|
// if vertex e1 is on the line and to the left of f2
|
|
return (d_traits.compare_y(Vertex(e1), Vertex(f2)) == EQUAL) &&
|
|
(d_traits.compare_x(Vertex(e1), Vertex(f2)) == SMALLER);
|
|
else // f2 and e1 are the same
|
|
if (d_traits.compare_y(Vertex(e2), Vertex(f2)) != EQUAL)
|
|
return has_on_left_side(Vertex(f1), Vertex(f2), Vertex(e2));
|
|
else if (d_traits.compare_x(Vertex(e2), Vertex(f2)) == LARGER)
|
|
return (d_traits.compare_y(Vertex(f1), Vertex(e2)) != EQUAL) ||
|
|
(d_traits.compare_x(Vertex(f1), Vertex(e2)) == SMALLER);
|
|
else
|
|
return (d_traits.compare_y(Vertex(f1), Vertex(e2)) == EQUAL) &&
|
|
(d_traits.compare_x(Vertex(f1), Vertex(e2)) == SMALLER);
|
|
}
|
|
|
|
template <class ForwardIterator, class Traits>
|
|
bool
|
|
Simplicity_test_2<ForwardIterator, Traits>::edge_compare_non_consecutive(
|
|
int e1, int e2) const
|
|
{
|
|
int n = NumberOfVertices();
|
|
int f1 = (e1<n-1) ? e1+1 : e1+1-n; // edge(e1) = (vertex(e1), vertex(f1))
|
|
int f2 = (e2<n-1) ? e2+1 : e2+1-n; // edge(e2) = (vertex(e2), vertex(f2))
|
|
|
|
if (has_y_overlap(Vertex(e1), Vertex(e2), Vertex(f2)))
|
|
return has_on_left_side(Vertex(e1), Vertex(e2), Vertex(f2));
|
|
|
|
if (has_y_overlap(Vertex(f1), Vertex(e2), Vertex(f2)))
|
|
return has_on_left_side(Vertex(f1), Vertex(e2), Vertex(f2));
|
|
|
|
// if the vertices from edge e1 do not have y-overlap with edge e2, then
|
|
// the vertices from edge e2 must have y_overlap with edge e1
|
|
return !has_on_left_side(Vertex(e2), Vertex(e1), Vertex(f1));
|
|
}
|
|
|
|
template <class ForwardIterator, class Traits>
|
|
bool
|
|
Simplicity_test_2<ForwardIterator, Traits>::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<ForwardIterator>::size_type Size_type;
|
|
Size_type i;
|
|
for (i=0; i<d_index.size(); i++)
|
|
cout << i << " " << Vertex(i) << endl;
|
|
cout << endl;
|
|
events.Show();
|
|
}
|
|
#endif // CGAL_POLYGON_DEBUG
|
|
|
|
SweepStatus status(this,n);
|
|
|
|
#ifdef CGAL_POLYGON_DEBUG
|
|
{
|
|
cout << endl;
|
|
status.Show();
|
|
}
|
|
#endif // CGAL_POLYGON_DEBUG
|
|
|
|
while (!events.empty()) {
|
|
|
|
#ifdef CGAL_POLYGON_DEBUG
|
|
CGAL_polygon_assertion(status.is_valid());
|
|
#endif // CGAL_POLYGON_DEBUG
|
|
|
|
int i = events.pop();
|
|
d_eventpoint = i;
|
|
|
|
#ifdef CGAL_POLYGON_DEBUG
|
|
{
|
|
cout << endl;
|
|
cout << "--- Event point: " << d_eventpoint << " on sweep line {y = "
|
|
<< Vertex(d_eventpoint).y() << "}" << endl;
|
|
cout << endl;
|
|
status.Show();
|
|
}
|
|
#endif // CGAL_POLYGON_DEBUG
|
|
|
|
int prev = (i>0) ? i-1 : i-1+n;
|
|
int next = (i<n-1) ? i+1 : i+1-n;
|
|
|
|
bool prev_less_than_i = VertexCompare(i,prev);
|
|
bool next_less_than_i = VertexCompare(i,next);
|
|
if (prev_less_than_i != next_less_than_i) {
|
|
int e = prev_less_than_i ? status.replace(i,prev) :
|
|
status.replace(prev,i);
|
|
CGAL_polygon_assertion(status.is_valid());
|
|
|
|
#ifdef CGAL_POLYGON_DEBUG
|
|
{
|
|
cout << endl;
|
|
status.Show();
|
|
}
|
|
#endif // CGAL_POLYGON_DEBUG
|
|
|
|
// check for intersections of newly inserted edge e with neighbors
|
|
int left = status.left(e);
|
|
if ((left >= 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 <class ForwardIterator, class Traits>
|
|
bool Simplicity_test_2<ForwardIterator, Traits>::EdgesDoIntersect(
|
|
int e1, int e2) const
|
|
{
|
|
#ifdef CGAL_POLYGON_DEBUG
|
|
{
|
|
cout << " intersecting edges " << e1 << " and " << e2 << endl;
|
|
}
|
|
#endif
|
|
|
|
int n = NumberOfVertices();
|
|
int f1 = (e1<n-1) ? e1+1 : e1+1-n; // edge(e1) = (vertex(e1), vertex(f1))
|
|
int f2 = (e2<n-1) ? e2+1 : e2+1-n; // edge(e2) = (vertex(e2), vertex(f2))
|
|
|
|
bool Result;
|
|
if (consecutive_edges(e1,e2))
|
|
Result = d_traits.have_equal_direction(Vertex(f1) - Vertex(e1),
|
|
Vertex(e2) - Vertex(f2) );
|
|
else
|
|
Result = d_traits.do_intersect(Vertex(e1),
|
|
Vertex(f1),
|
|
Vertex(e2),
|
|
Vertex(f2));
|
|
|
|
// N.B. traits() instead of d_traits gives an error with g++ 2.7.2
|
|
|
|
return Result;
|
|
}
|
|
|
|
template <class ForwardIterator, class Traits>
|
|
inline
|
|
bool Simplicity_test_2<ForwardIterator, Traits>::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 <class ForwardIterator, class Traits>
|
|
bool is_simple_2(ForwardIterator first,
|
|
ForwardIterator last,
|
|
const Traits& traits)
|
|
{
|
|
Simplicity_test_2<ForwardIterator, Traits> test(traits);
|
|
return test.Test(first, last);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------//
|
|
// left_vertex_2
|
|
//-----------------------------------------------------------------------//
|
|
// uses Traits::Less_xy
|
|
|
|
template <class ForwardIterator, class Traits>
|
|
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 <class ForwardIterator, class Traits>
|
|
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 <class ForwardIterator, class Traits>
|
|
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 <class ForwardIterator, class Traits>
|
|
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 <class InputIterator>
|
|
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 <class ForwardIterator, class FT, class Traits>
|
|
// void area_2(ForwardIterator first,
|
|
// ForwardIterator last,
|
|
// FT& result,
|
|
// const Traits& traits)
|
|
//{
|
|
|
|
//-----------------------------------------------------------------------//
|
|
// is_convex_2
|
|
//-----------------------------------------------------------------------//
|
|
// uses Traits::lexicographically_xy_smaller
|
|
// Traits::orientation
|
|
|
|
template <class ForwardIterator, class Traits>
|
|
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 <class ForwardIterator, class Point, class Traits>
|
|
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 <class ForwardIterator, class Point, class Traits>
|
|
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 <class ForwardIterator, class Traits>
|
|
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
|
|
|