cgal/Packages/Arrangement/include/CGAL/Arr_polyline_traits.h

932 lines
27 KiB
C++

// ======================================================================
//
// Copyright (c) 1999 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-2.3-I-44 $
// release_date : $CGAL_Date: 2001/03/09 $
//
// file : include/CGAL/Arr_polyline_traits.h
// package : Arrangement (1.77)
// maintainer : Eyal Flato <flato@math.tau.ac.il>
// author(s) : Iddo Hanniel
// coordinator : Tel-Aviv University (Dan Halperin <halperin@math.tau.ac.il>)
//
// ======================================================================
#ifndef CGAL_ARR_POLYLINE_TRAITS_H
#define CGAL_ARR_POLYLINE_TRAITS_H
#include <CGAL/basic.h>
#include <list>
#include <deque>
#include <vector>
#include <algorithm>
#include <CGAL/predicates_on_points_2.h>
#include <CGAL/predicates_on_lines_2.h>
#include <CGAL/Segment_2_Segment_2_intersection.h>
#include <CGAL/Point_2.h>
#include <CGAL/squared_distance_2.h>
#include <CGAL/Pm_segment_traits_2.h>
#include <CGAL/tags.h>
CGAL_BEGIN_NAMESPACE
template <class Kernel_,
class Container = std::vector<CGAL_TYPENAME_MSVC_NULL Kernel_::Point_2 > >
class Arr_polyline_traits : public Kernel_
{
public:
typedef Tag_false Has_left_category;
typedef Kernel_ Kernel;
typedef Arr_polyline_traits<Kernel> Self;
typedef typename Kernel::Point_2 Point_2;
typedef Container Curve_2;
typedef Container X_curve_2;
typedef typename Kernel::Vector_2 Vector_2;
typedef typename Kernel::Line_2 Line_2;
// Obsolete, for backward compatibility
typedef Point_2 Point;
typedef Vector_2 Vector;
typedef X_curve_2 X_curve;
typedef Curve_2 Curve;
protected:
typedef typename Kernel::Segment_2 Segment_2;
protected:
// Functors:
typedef typename Kernel::Is_vertical_2 Is_vertical_2;
typedef typename Kernel::Construct_vertex_2 Construct_vertex_2;
typedef typename Kernel::Less_x_2 Less_x_2;
typedef typename Kernel::Equal_2 Equal_2;
public:
Arr_polyline_traits() { }
/*! compare_x() compares the x-coordinates of two given points
* \param p1 the first point
* \param p2 the second point
* \return LARGER if x(p1) > x(p2), SMALLER if x(p1) < x(p2), or else EQUAL
*
* \todo replace indirect use compare_x() with compare_x_2()
*/
Comparison_result compare_x(const Point_2 & p1, const Point_2 & p2) const
{
return compare_x_2_object()(p1, p2);
}
/*! compare_xy() compares the two given points by x, then by y
* \param p1 the first point
* \param p2 the second point
* \return LARGER if x(p1) > x(p2) or if x(p1) = x(p2) and y(p1) > y(p2);
* SMALLER if x(p1) < x(p2) or if x(p1) = x(p2) and y(p1) < y(p2);
* or else EQUAL
*
* \todo replace indirect use compare_xy() with compare_xy_2()
*/
Comparison_result compare_xy(const Point_2 & p1, const Point_2 & p2) const
{
return compare_xy_2_object()(p1, p2);;
}
/*! curve_is_vertical
* on X_curve only - not Curve!
*/
bool curve_is_vertical(const X_curve_2 & cv) const
{
CGAL_assertion(is_x_monotone(cv));
return compare_x(curve_source(cv), curve_target(cv)) == EQUAL;
}
/*! curve_is_in_x_range
*/
bool curve_is_in_x_range(const X_curve_2 & cv, const Point_2 & p) const
{
CGAL_assertion(is_x_monotone(cv));
Construct_vertex_2 construct_vertex = construct_vertex_2_object();
const Point_2 & source = curve_source(cv);
const Point_2 & target = curve_target(cv);
Less_x_2 less_x = less_x_2_object();
return !((less_x(source, p) && less_x(target, p)) ||
(less_x(p, source) && less_x(p, target)));
}
Comparison_result curve_compare_at_x(const X_curve_2 & cv1,
const X_curve_2 & cv2,
const Point_2 & p) const
{
CGAL_assertion(is_x_monotone(cv1));
CGAL_assertion(is_x_monotone(cv2));
CGAL_precondition(curve_is_in_x_range(cv1,p));
CGAL_precondition(curve_is_in_x_range(cv2,p));
typename X_curve_2::const_iterator pit_1 = cv1.begin(),
pit_2 = cv2.begin();
typename X_curve_2::const_iterator after_1 = pit_1,
after_2 = pit_2;
++after_1; ++after_2;
// read: as long as both *pit and *after are on the same
// side of p
for( ; (compare_x(*pit_1,p) * compare_x(*after_1,p)) /*<=*/ >0 ;
++pit_1,++after_1) {}
for( ; (compare_x(*pit_2,p) * compare_x(*after_2,p)) > 0 ;
++pit_2,++after_2) {}
// the R here is the template parameter (see class def. above)
Pm_segment_traits_2<Kernel> segment_traits;
const typename Pm_segment_traits_2<Kernel>::X_curve_2
seg1(*pit_1, *after_1),
seg2(*pit_2, *after_2);
// bug fix, shai 19/03/2000:
// the polylines may contain vertical segments
return (segment_traits.curve_compare_at_x(seg1, seg2, p));
}
// precondition - x-monotone
Comparison_result curve_compare_at_x_left(const X_curve_2 & cv1,
const X_curve_2 & cv2,
const Point_2 & p) const
{
CGAL_assertion(is_x_monotone(cv1));
CGAL_assertion(is_x_monotone(cv2));
// Check preconditions.
CGAL_precondition(curve_is_in_x_range(cv1,p));
CGAL_precondition(curve_is_in_x_range(cv2,p));
CGAL_precondition(! curve_is_vertical(cv1));
CGAL_precondition(! curve_is_vertical(cv2));
CGAL_precondition_code(
Point_2 leftmost1 =
(compare_x(curve_source(cv1),curve_target(cv1))==LARGER) ?
curve_target(cv1) : curve_source(cv1);
Point_2 leftmost2 =
(compare_x(curve_source(cv2),curve_target(cv2))==LARGER) ?
curve_target(cv2) : curve_source(cv2);
);
CGAL_precondition(compare_x(leftmost1,p) == SMALLER);
CGAL_precondition(compare_x(leftmost2,p) == SMALLER);
// Compare.
typename X_curve_2::const_iterator pit = cv1.begin();
typename X_curve_2::const_iterator after = pit; ++after;
for( ; (compare_x(*pit,p) * compare_x(*after,p)) > 0 ; ++pit,++after) {}
Line_2 l1(*pit,*after);
pit=cv2.begin();
after=pit; ++after;
for( ; (compare_x(*pit,p) * compare_x(*after,p)) > 0 ; ++pit,++after) {}
Line_2 l2(*pit,*after);
CGAL_precondition (CGAL::compare_y_at_x(p,l1,l2) == EQUAL);
// check if they are right endpoints (and compare to the one from
// the left) otherwise -
//
//! \todo This is incorrect! we should probably return EQUAL.
return (CGAL::compare_y_at_x(point_to_left(p),l1,l2));
}
Comparison_result curve_compare_at_x_right(const X_curve_2& cv1,
const X_curve_2& cv2,
const Point_2& p) const
{
CGAL_assertion(is_x_monotone(cv1));
CGAL_assertion(is_x_monotone(cv2));
// Check preconditions.
CGAL_precondition(curve_is_in_x_range(cv1,p));
CGAL_precondition(curve_is_in_x_range(cv2,p));
CGAL_precondition(! curve_is_vertical(cv1));
CGAL_precondition(! curve_is_vertical(cv2));
CGAL_precondition_code(
Point_2 rightmost1 =
(compare_x(curve_source(cv1),curve_target(cv1))==SMALLER) ?
curve_target(cv1) : curve_source(cv1);
Point_2 rightmost2 =
(compare_x(curve_source(cv2),curve_target(cv2))==SMALLER) ?
curve_target(cv2) : curve_source(cv2);
);
CGAL_precondition(compare_x(rightmost1,p) == LARGER);
CGAL_precondition(compare_x(rightmost2,p) == LARGER);
// Compare.
typename X_curve_2::const_iterator pit=cv1.begin();
typename X_curve_2::const_iterator after=pit; ++after;
for( ; (compare_x(*pit,p) * compare_x(*after,p)) > 0 ; ++pit,++after) {}
Line_2 l1(*pit,*after);
pit=cv2.begin();
after=pit; ++after;
for( ; (compare_x(*pit,p) * compare_x(*after,p)) > 0 ; ++pit,++after) {}
Line_2 l2(*pit,*after);
CGAL_precondition (CGAL::compare_y_at_x(p,l1,l2) == EQUAL);
// check if they are left endpoints (and compare to the one from the
// right) otherwise -
//! \todo This is incorrect! we should probably return EQUAL.
return (CGAL::compare_y_at_x(point_to_right(p),l1,l2));
}
Comparison_result curve_get_point_status (const X_curve_2 &cv,
const Point_2& p) const
{
CGAL_assertion(is_x_monotone(cv));
CGAL_precondition(curve_is_in_x_range(cv, p));
if (curve_is_vertical(cv))
{
if (CGAL::compare_y(curve_source(cv),p)*
CGAL::compare_y(curve_target(cv),p)<=0)
return EQUAL;
else
return (CGAL::compare_y(curve_source(cv),p));
}
typename X_curve_2::const_iterator pit = cv.begin(),after=pit; ++after;
while ( (compare_x(*pit,p) * compare_x(*after,p)) > 0 ) {
++pit; ++after;
}
Line_2 l(*pit,*after);
Comparison_result res = CGAL::compare_y_at_x(p, l);
if (res == SMALLER)
return LARGER;
if (res == LARGER)
return SMALLER;
return EQUAL;
}
/*! \todo replace indirect use point_is_same() with equal_2()
*/
bool point_is_same(const Point_2 & p1, const Point_2 & p2) const
{ return equal_2_object()(p1, p2); }
/*! \todo replace indirect use curve_is_same() with equal_2()
*/
bool curve_is_same(const X_curve_2 & cv1, const X_curve_2 & cv2) const
{
CGAL_assertion(is_x_monotone(cv1));
CGAL_assertion(is_x_monotone(cv2));
if (cv1.size() != cv2.size()) return false;
typename X_curve_2::const_iterator it1 = cv1.begin();
typename X_curve_2::const_iterator it2 = cv2.begin();
Equal_2 equal = equal_2_object();
bool is_equal = true;
while (it1 != cv1.end()) {
if (!equal(*it1++, *it2++)) {
is_equal = false;
break;
}
}
if (is_equal) return true;
// Reverse order:
it1 = cv1.begin();
it2 = cv2.end();
while (it1 != cv1.end()) {
if (!equal(*it1++, *--it2)) return false;
}
return true;
}
/*!
*/
Point_2 curve_source(const X_curve_2 & cv) const
{ return *(cv.begin()); }
/*!
*/
Point_2 curve_target(const X_curve_2 & cv) const
{
typename X_curve_2::const_iterator it = cv.end();
return *--it;
}
///////////////////////////////////////////////////////
// ARRANGEMENT FUNCS
X_curve_2 curve_flip(const X_curve_2 & cv) const
{
X_curve_2 cv1(cv);
std::reverse(cv1.begin(),cv1.end());
return cv1;
}
bool is_x_monotone(const Curve_2& cv) const {
CGAL_assertion(cv.size()>=2); //one point is not a curve
if (cv.size()==2) return true; //segment
typename X_curve_2::const_iterator p0=cv.begin();
typename X_curve_2::const_iterator p1=p0; ++p1;
typename X_curve_2::const_iterator p2=p1; ++p2;
for(; p2!=cv.end(); ++p0,++p1,++p2) {
if ( compare_x(*p0,*p1) * compare_x(*p1,*p2) <=0 )
return false;
}
// <= a matter of decision - only one vertical segment is considered
// x-monotone
return true;
}
//cuts into x-monotone curves, each vertical segment is 1 x-monotone curve
//and not part of a bigger x-monotone polyline
void make_x_monotone(const Curve_2& cv, std::list<Curve_2>& l) {
CGAL_assertion(cv.size()>=2); //one point is not a curve
if (cv.size()==2) { //segment
l.push_back(cv);
return;
}
typename X_curve_2::const_iterator p0=cv.begin();
typename X_curve_2::const_iterator p1=p0; ++p1;
typename X_curve_2::const_iterator p2=p1; ++p2;
typename X_curve_2::const_iterator last_cut=p0;
for(; p2!=cv.end(); ++p0,++p1,++p2) {
//in future use constants instead of compare_x
if (compare_x(*p0,*p1)==EQUAL) { //vertical segment - (p0,p1)
if (p0!=last_cut) { //needed for the case:
// | p1
// o p0=lastcut (was p1 before)
// |
l.push_back(X_curve_2(last_cut,p1));
//push_back the curve (last_cut...p0)
}
l.push_back(X_curve_2(p0,p2)); //push_back the segment (p0,p1)
last_cut=p1;
}
else
if ( compare_x(*p0,*p1) * compare_x(*p1,*p2) <= 0 ) {
l.push_back(X_curve_2(last_cut,p2));
last_cut=p1;
}
}
l.push_back(X_curve_2(last_cut,p2)); //push the residue (last cut to end)
CGAL_assertion(p2==cv.end());
}
void curve_split(const X_curve_2& cv, X_curve_2& c1, X_curve_2& c2,
const Point_2& split_pt) {
//split curve at split point into c1 and c2
CGAL_precondition(curve_get_point_status(cv,split_pt)==EQUAL);
CGAL_precondition(CGAL::compare_lexicographically_xy(curve_source(cv),
split_pt) != EQUAL);
CGAL_precondition(CGAL::compare_lexicographically_xy(curve_target(cv),
split_pt) != EQUAL);
typename X_curve_2::const_iterator p0=cv.begin();
typename X_curve_2::const_iterator p1=p0; ++p1;
bool split_at_vertex=false;
for (; p1 != cv.end(); ++p0,++p1) {
if (point_is_same(*p1,split_pt)) {
split_at_vertex=true;
break;
}
if (compare_x(*p0,split_pt) * compare_x(split_pt,*p1) >= 0) {
//in x range
break;
}
}
c1.clear(); c2.clear();
typename X_curve_2::const_iterator ci=cv.begin();
while (ci!=p1) {
c1.push_back(*ci);
++ci;
}
if (!split_at_vertex) {
c1.push_back(split_pt);
c2.push_back(split_pt);
}
else {
c1.push_back(*p1);
}
while (ci!=cv.end()) {
c2.push_back(*ci);
++ci;
}
//moved this up to enable use of vector as container
/*
if (!split_at_vertex) {
c1.push_back(split_pt);
c2.push_front(split_pt);
}
else {
c1.push_back(*p1);
}
*/
}
//NOTE: when there is an overlap we will always return a SEGMENT (i.e.,
// p1 and p2 will be on a segment) even if the overlap is a polyline
// , this is still sufficient for the arrangement. might be
// changed in the future.
bool nearest_intersection_to_right(const X_curve_2& cv1,
const X_curve_2& cv2,
const Point_2& pt,
Point_2& p1,
Point_2& p2) const
{
CGAL_assertion(is_x_monotone(cv1));
CGAL_assertion(is_x_monotone(cv2));
bool found( false);
// curves do not necessarily intersect
if ( ! _do_curves_intersect_to_right(cv1,cv2,pt))
return false;
X_curve_2 c1(cv1),c2(cv2);
if ( ! lexicographically_xy_smaller (curve_source(c1),curve_target(c1)))
c1=curve_flip(cv1);
if ( ! lexicographically_xy_smaller (curve_source(c2),curve_target(c2)))
c2=curve_flip(cv2);
// check if both first points are left of pt, if they are reach the
// points directly left of pt, and check if their segments intersect
//to the right of pt, if not continue with a normal sweep until
//we find an intersection point or we reach the end.
typename X_curve_2::const_iterator i1s=c1.begin(),i1e=c1.end();
typename X_curve_2::const_iterator i1t=i1s; ++i1t;
typename X_curve_2::const_iterator i2s=c2.begin(),i2e=c2.end();
typename X_curve_2::const_iterator i2t=i2s; ++i2t;
int number_to_left=0; //increment this variable if curve starts left of pt
if (!lexicographically_xy_larger (*i1s,pt)) {
//increment to nearest from the left of pt
++number_to_left;
for (; i1t!=i1e; ++i1s,++i1t) {
if (lexicographically_xy_larger (*i1t,pt)) break;
}
if (i1t==i1e) return false;
}
//now i1s holds the source vertex and i1t holds the target
if (!lexicographically_xy_larger (*i2s,pt)) {
//increment
++number_to_left;
for (; i2t!=i2e; ++i2s,++i2t) {
if (lexicographically_xy_larger (*i2t,pt)) break;
}
if (i2t==i2e) return false ; //c2 ends to the left of pt
}
if (number_to_left==2) {
//check if intersection exists and is lex larger
Object result =
intersection(Segment_2(*i1s, *i1t), Segment_2(*i2s, *i2t));
Point_2 i_pt;
Segment_2 i_seg;
if (assign(i_pt,result)) {
//check if intersection point to the right of pt
if (lexicographically_xy_larger (i_pt,pt)) {
//debug
#ifndef ARR_USES_LEDA_RATIONAL //normalize if we are with rational numbers
p1=p2=i_pt;
found = true;
#else
p1=p2=Point_2(i_pt.x().normalize(),i_pt.y().normalize());
found = true;
#endif
}
}
if ( ! found && assign(i_seg,result)) {
//check if intersection seg to the right of pt
if (lexicographically_xy_larger (i_seg.source(),i_seg.target()))
i_seg=i_seg.opposite();
if (lexicographically_xy_larger (i_seg.target(),pt)) {
p2=i_seg.target();
if (lexicographically_xy_larger (i_seg.source(),pt)) {
p1=i_seg.source();}
else {
// p1=pt;
// Modified by Eug
// Performing vertical ray shooting from pt.
// Finding the intersection point. We know by now
// that there is exactly ONE point. Assinging this
// point to p1.
// Bug: What happens if the curves are vertical. The vertical ray
// shoot will return a segment instead of point.
Point_2 ap1( pt.x(), i_seg.source().y() );
Point_2 ap2( pt.x(), i_seg.target().y() );
Segment_2 vertical_pt_x_base( ap1, ap2 );
Object i_obj = intersection( vertical_pt_x_base, i_seg );
//assign( p1, i_obj ); // Causes a bug if the result is a segment.
// Bug fix: Eti.
Point_2 tmp_p1;
Segment_2 i_vertical;
if ( assign( tmp_p1, i_obj ))
p1=tmp_p1;
else if ( assign(i_vertical, i_obj))
// the intersection vertical segment starts at pt.
p1=i_vertical.source();
}
found = true;
}
}
if ( ! found) {
//advance to the nearer point
if (lexicographically_xy_larger (*i2t,*i1t)) {
++i1s; ++i1t;
if (i1t==i1e) return false;
}
else {
++i2s; ++i2t;
if (i2t==i2e) return false;
}
}
}
//NOW we can start sweeping the chains
while ( ! found) {
//check intersection of the segments
Object result;
result = intersection(Segment_2(*i1s, *i1t), Segment_2(*i2s, *i2t));
Point_2 i_pt;
Segment_2 i_seg;
if (assign(i_pt,result)) {
#ifndef ARR_USES_LEDA_RATIONAL //normalize if we are with rational numbers
p1=p2=i_pt;
#else
p1=p2=Point_2(i_pt.x().normalize(),i_pt.y().normalize());
#endif
found = true;
}
if (!found && assign(i_seg,result)) {
//check if intersection seg to the right of pt
if (lexicographically_xy_larger (i_seg.source(),i_seg.target()))
i_seg=i_seg.opposite();
if (lexicographically_xy_larger (i_seg.target(),pt)) {
p2=i_seg.target();
if (lexicographically_xy_larger (i_seg.source(),pt)) {
p1=i_seg.source();}
else {
// p1=pt;
// Modified by Eug
// Performing vertical ray shooting from pt.
// Finding the intersection point. We know by now
// that there is exactly ONE point. Assinging this
// point to p1.
Point_2 ap1( pt.x(), i_seg.source().y() );
Point_2 ap2( pt.x(), i_seg.target().y() );
Segment_2 vertical_pt_x_base( ap1, ap2 );
Object i_obj = intersection( vertical_pt_x_base, i_seg );
//assign( p1, i_obj ); // Causes a bug if the result is a segment.
// Bug fix: Eti.
Point_2 tmp_p1;
Segment_2 i_vertical;
if ( assign( tmp_p1, i_obj ))
p1=tmp_p1;
else if ( assign(i_vertical, i_obj))
// the intersection vertical segment starts at pt.
p1=i_vertical.source();
}
found = true;
}
}
if ( ! found) {
//advance to the nearer point
if (lexicographically_xy_larger (*i2t,*i1t)) {
++i1s; ++i1t;
if (i1t==i1e) return false;
}
else {
++i2s; ++i2t;
if (i2t==i2e) return false;
}
}
} // end while ( ! found)
// if the x point is at the end of a segment, then there might be
// an overlap in the continious of the polyline
if ( found && point_is_same(p1, p2) ) {
typename X_curve_2::const_iterator s1=i1s, t1=i1t, s2=i2s, t2=i2t;
s1++; t1++; s2++; t2++;
if (t1 != i1e && t2 != i2e) {
// check for overlap after x point
Object result;
Segment_2 i_seg;
if ( point_is_same(p1, *i1t) && point_is_same(p1, *i2t)) {
result = intersection(Segment_2(*s1, *t1), Segment_2(*s2, *t2));
}
else if ( point_is_same(p1, *i1t)) {
result = intersection(Segment_2(*s1, *t1), Segment_2(*i2s, *i2t));
}
else if ( point_is_same(p1, *i2t)) {
result = intersection(Segment_2(*i1s, *i1t),
Segment_2(*s2, *t2));
}
if (assign(i_seg,result)) {
// no need to check whether intersection seg to the right of pt,
// because we have already found an x point to the right of pt.
if (lexicographically_xy_larger (i_seg.source(),i_seg.target()))
i_seg=i_seg.opposite();
p1 = i_seg.source();
p2 = i_seg.target();
}
}
}
return found;
}
bool curves_overlap(const X_curve_2& ca, const X_curve_2& cb) const {
CGAL_assertion(is_x_monotone(ca));
CGAL_assertion(is_x_monotone(cb));
//do a flip so they are left to right
X_curve_2 c1(ca),c2(cb);
if (lexicographically_xy_larger(curve_source(ca),curve_target(ca)))
c1=curve_flip(ca);
if (lexicographically_xy_larger(curve_source(cb),curve_target(cb)))
c2=curve_flip(cb);
typename X_curve_2::const_iterator i1s=c1.begin(),i1e=c1.end();
typename X_curve_2::const_iterator i1t=i1s; ++i1t;
typename X_curve_2::const_iterator i2s=c2.begin(),i2e=c2.end();
typename X_curve_2::const_iterator i2t=i2s; ++i2t;
//now i1s holds the source vertex and i1t holds the target
Point_2 i_pt;
Segment_2 i_seg;
Segment_2 s1(*i1s,*i1t),s2(*i2s,*i2t);
Object res=intersection(s1,s2);
if (assign(i_seg,res)) {
if (!point_is_same(i_seg.source(),i_seg.target()))
return true;
}
//advance to the nearer point
if (lexicographically_xy_larger(*i2t,*i1t)) {
++i1s; ++i1t;
if (i1t==i1e) return false;
}
else {
++i2s; ++i2t;
if (i2t==i2e) return false;
}
//NOW we can start sweeping the chains
while (1) {
Segment_2 i_seg;
Segment_2 s1(*i1s,*i1t),s2(*i2s,*i2t);
res=intersection(s1,s2);
if (assign(i_seg,res)) {
if (!point_is_same(i_seg.source(),i_seg.target()))
return true;
}
if (lexicographically_xy_larger(*i2t,*i1t)) {
++i1s; ++i1t;
if (i1t==i1e) return false;
}
else {
++i2s; ++i2t;
if (i2t==i2e) return false;
}
}
}
/*! point_reflect_in_x_and_y() reflects the given point about the origin
*/
Point_2 point_reflect_in_x_and_y(const Point_2 & pt) const
{
Point_2 org = construct_point_2_object()(ORIGIN);
Vector_2 v = construct_vector_2_object()(pt, org);
Point_2 reflected_pt(v);
return reflected_pt;
}
/*!
*/
X_curve_2 curve_reflect_in_x_and_y( const X_curve_2 & cv) const
{
X_curve_2 reflected_cv;
typename Curve_2::const_iterator it = cv.begin();
while (it != cv.end())
reflected_cv.push_back(point_reflect_in_x_and_y(*it++));
return reflected_cv;
}
////////////////////////////////////////////////////////////////////
// PRIVATE
private:
//! \todo Remove the point_to_left() and point_to_right() functions.
Point_2 point_to_left(const Point_2& p) const {
return p+Vector_2(-1,0);;
}
Point_2 point_to_right(const Point_2& p) const {
return p+Vector_2(1,0);;
}
//returns true iff the intersectionis lexicographically strictly right of pt
bool _do_curves_intersect_to_right (const X_curve_2& ca,
const X_curve_2& cb,
const Point_2& pt) const
{
CGAL_assertion(is_x_monotone(ca));
CGAL_assertion(is_x_monotone(cb));
// check if both first points are left of pt, if they are reach the
// points directly left of pt, and check if their segments intersect
//to the right of pt, if not continue with a normal sweep until
//we find an intersection point or we reach the end.
//do a flip or can we assume they are left to right ??
X_curve_2 c1(ca),c2(cb);
if (lexicographically_xy_larger(curve_source(ca), curve_target(ca)) ==
LARGER )
c1=curve_flip(ca);
if (lexicographically_xy_larger(curve_source(cb),curve_target(cb)) ==
LARGER )
c2=curve_flip(cb);
typename X_curve_2::const_iterator i1s=c1.begin(),i1e=c1.end();
typename X_curve_2::const_iterator i1t=i1s; ++i1t;
typename X_curve_2::const_iterator i2s=c2.begin(),i2e=c2.end();
typename X_curve_2::const_iterator i2t=i2s; ++i2t;
int number_to_left=0; //increment this variable if curve starts left of pt
if (!lexicographically_xy_larger (*i1s,pt)) {
//increment to nearest from the left of pt
++number_to_left;
for (; i1t!=i1e; ++i1s,++i1t) {
if (lexicographically_xy_larger (*i1t,pt)) break;
}
if (i1t==i1e) return false; //c1 ends to the left of pt
}
//now i1s holds the source vertex and i1t holds the target
if (!lexicographically_xy_larger (*i2s,pt)) {
//increment
++number_to_left;
for (; i2t!=i2e; ++i2s,++i2t) {
if (lexicographically_xy_larger (*i2t,pt)) break;
}
if (i2t==i2e) return false; //c2 ends to the left of pt
}
if (number_to_left==2) {
//check if intersection exists and is lex larger
Object result;
Point_2 i_pt;
Segment_2 i_seg;
result = intersection(Segment_2(*i1s, *i1t), Segment_2(*i2s, *i2t));
if (assign(i_pt,result)) {
//check if intersection point to the right of pt
if (lexicographically_xy_larger (i_pt,pt))
{
return true;
}
}
else
if (assign(i_seg,result)) {
//check if intersection seg to the right of pt
if (lexicographically_xy_larger (i_seg.source(),pt) ||
lexicographically_xy_larger (i_seg.target(),pt))
{
return true;
}
}
//debug
else {
//cerr << "segments don't intersect ??" << endl;
}
//advance to the nearer point
if (lexicographically_xy_larger (*i2t,*i1t)) {
++i1s; ++i1t;
if (i1t==i1e) return false;
}
else {
++i2s; ++i2t;
if (i2t==i2e) return false;
}
}
//NOW we can start sweeping the chains
while (1) {
//check for intersection of the segments
if (do_intersect(Segment_2(*i1s, *i1t), Segment_2(*i2s, *i2t)))
{
return true;
}
//advance to the nearer point
if (lexicographically_xy_larger (*i2t,*i1t)) {
++i1s; ++i1t;
if (i1t==i1e) return false;
}
else {
++i2s; ++i2t;
if (i2t==i2e) return false;
}
}
}
public:
void display(const X_curve_2& cv) const
{
typename X_curve_2::const_iterator it=cv.begin(),eit=cv.end();
while(it!=eit) { std::cerr << *it++;}
}
//the same for window stream
};
CGAL_END_NAMESPACE
#endif