mirror of https://github.com/CGAL/cgal
891 lines
27 KiB
C++
891 lines
27 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 : $$
|
|
// release_date : $$
|
|
//
|
|
// file : include/CGAL/Arr_segment_cached_traits_2.h
|
|
// package : Planar_map (5.87)
|
|
// maintainer : Efi Fogel <efif@math.tau.ac.il>
|
|
// source :
|
|
// revision :
|
|
// revision_date :
|
|
// author(s) : Ron Wein <wein@post.tau.ac.il>
|
|
// Efi Fogel <efif@post.tau.ac.il>
|
|
//
|
|
// coordinator : Tel-Aviv University (Dan Halperin <halperin@math.tau.ac.il>)
|
|
//
|
|
// Chapter :
|
|
// ======================================================================
|
|
#ifndef CGAL_ARR_SEGMENT_CACHED_TRAITS_2_H
|
|
#define CGAL_ARR_SEGMENT_CACHED_TRAITS_2_H
|
|
|
|
#include <CGAL/tags.h>
|
|
#include <CGAL/intersections.h>
|
|
|
|
#include <list>
|
|
#include <fstream>
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
template <class Kernel_> class Segment_cached_2;
|
|
|
|
/*!
|
|
* A traits class for maintaining an arrangement of segments, aoviding
|
|
* cascading of computations as much as possible.
|
|
*/
|
|
template <class Kernel_>
|
|
class Arr_segment_cached_traits_2 : public Kernel_
|
|
{
|
|
public:
|
|
typedef Kernel_ Kernel;
|
|
|
|
typedef Tag_true Has_left_category;
|
|
|
|
/*!
|
|
* Representation of a segement with cached data.
|
|
*/
|
|
class My_segment_cached_2
|
|
{
|
|
typedef typename Kernel_::Line_2 Line_2;
|
|
typedef typename Kernel_::Segment_2 Segment_2;
|
|
typedef typename Kernel_::Point_2 Point_2;
|
|
|
|
protected:
|
|
|
|
Line_2 line; // The line that supports the segment.
|
|
Point_2 ps, pt; // The source a target points.
|
|
bool is_vert; // Is this a vertical segment.
|
|
|
|
/*!
|
|
* Default constructor.
|
|
*/
|
|
My_segment_cached_2 () :
|
|
is_vert(false)
|
|
{}
|
|
|
|
/*!
|
|
* Constructor from a segment.
|
|
* \param seg The segment.
|
|
*/
|
|
My_segment_cached_2 (const Segment_2& seg)
|
|
{
|
|
Kernel_ kernel;
|
|
|
|
line = kernel.construct_line_2_object()(seg);
|
|
is_vert = kernel.is_vertical_2_object()(seg);
|
|
|
|
typename Kernel_::Construct_vertex_2
|
|
construct_vertex = kernel.construct_vertex_2_object();
|
|
|
|
ps = construct_vertex(seg, 0);
|
|
pt = construct_vertex(seg, 1);
|
|
}
|
|
|
|
/*!
|
|
* Construct a segment from two end-points.
|
|
* \param source The source point.
|
|
* \param target The target point.
|
|
*/
|
|
My_segment_cached_2 (const Point_2& source, const Point_2& target)
|
|
{
|
|
Kernel_ kernel;
|
|
|
|
line = kernel.construct_line_2_object()(source, target);
|
|
is_vert = kernel.is_vertical_2_object()(line);
|
|
|
|
ps = source;
|
|
pt = target;
|
|
}
|
|
|
|
friend class Arr_segment_cached_traits_2;
|
|
};
|
|
|
|
// Traits objects
|
|
typedef typename Kernel::Point_2 Point_2;
|
|
typedef Segment_cached_2<Kernel> X_curve_2;
|
|
typedef Segment_cached_2<Kernel> Curve_2;
|
|
|
|
// Backward compatability
|
|
typedef Point_2 Point;
|
|
typedef X_curve_2 X_curve;
|
|
typedef X_curve_2 Curve;
|
|
|
|
protected:
|
|
|
|
// Functors:
|
|
typedef typename Kernel::Less_x_2 Less_x_2;
|
|
typedef typename Kernel::Equal_2 Equal_2;
|
|
typedef typename Kernel::Compare_x_2 Compare_x_2;
|
|
typedef typename Kernel::Compare_y_2 Compare_y_2;
|
|
typedef typename Kernel::Compare_xy_2 Compare_xy_2;
|
|
typedef typename Kernel::Equal_2 Equal_2;
|
|
typedef typename Kernel::Compare_slope_2 Compare_slope_2;
|
|
typedef typename Kernel::Has_on_2 Has_on_2;
|
|
|
|
public:
|
|
|
|
/*!
|
|
* Default constructor.
|
|
*/
|
|
Arr_segment_cached_traits_2() {}
|
|
|
|
// Operations
|
|
// ----------
|
|
|
|
/*!
|
|
* Compare 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.
|
|
*/
|
|
Comparison_result compare_x(const Point_2 & p1, const Point_2 & p2) const
|
|
{
|
|
return (compare_x_2_object()(p1, p2));
|
|
}
|
|
|
|
/*!
|
|
* Compares lexigoraphically the two points: by x, then by y.
|
|
* \param p1 Te 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.
|
|
*/
|
|
Comparison_result compare_xy(const Point_2 & p1, const Point_2 & p2) const
|
|
{
|
|
return (compare_xy_2_object()(p1, p2));
|
|
}
|
|
|
|
/*!
|
|
* Check whether the given curve is a vertical segment.
|
|
* \param cv The curve.
|
|
* \return (true) if the curve is vertical.
|
|
*/
|
|
bool curve_is_vertical(const X_curve_2 & cv) const
|
|
{
|
|
return (cv.is_vert);
|
|
}
|
|
|
|
/*!
|
|
* Check whether the given point is in the x-range of the given curve.
|
|
* In out case, the curve is a segment [s, t], check whether x(s)<=x(q)<=x(t)
|
|
* or whether x(t)<=x(q)<=x(s).
|
|
* \param cv The curve.
|
|
* \param q The point.
|
|
* \return (true) if q is in the x-range of cv.
|
|
*/
|
|
bool curve_is_in_x_range(const X_curve_2 & cv, const Point_2 & q) const
|
|
{
|
|
Compare_x_2 compare_x = compare_x_2_object();
|
|
Comparison_result res1 = compare_x (q, cv.ps);
|
|
|
|
if (cv.is_vert) // Special check for vertical segments.
|
|
return (res1 == EQUAL);
|
|
|
|
Comparison_result res2 = compare_x (q, cv.pt);
|
|
|
|
// We check if x(p) equals the x value of one of the end-points.
|
|
// If not, we check whether one end-point is to p's left and the other is
|
|
// to its right.
|
|
return ((res1 == EQUAL) || (res2 == EQUAL) ||
|
|
(res1 != res2));
|
|
}
|
|
|
|
/*!
|
|
* Get the relative status of two curves at the x-coordinate of a given
|
|
* point.
|
|
* \param cv1 The first curve.
|
|
* \param cv2 The second curve.
|
|
* \param q The point.
|
|
* \pre The point q is in the x-range of the two curves.
|
|
* \return LARGER if cv1(x(q)) > cv2(x(q)); SMALLER if cv1(x(q)) < cv2(x(q));
|
|
* or else EQUAL.
|
|
*/
|
|
Comparison_result curve_compare_at_x(const X_curve_2 & cv1,
|
|
const X_curve_2 & cv2,
|
|
const Point_2 & q) const
|
|
{
|
|
CGAL_precondition(curve_is_in_x_range(cv1, q));
|
|
CGAL_precondition(curve_is_in_x_range(cv2, q));
|
|
|
|
// Special treatment for vertical segments:
|
|
// In case one curve is a vertical segment, return EQUAL if it intersects
|
|
// with the other segment, otherwise return LARGER or SMALLER.
|
|
if (cv1.is_vert)
|
|
{
|
|
if (cv2.is_vert)
|
|
{
|
|
// Compare two vertical segments.
|
|
Compare_y_2 compare_y = compare_y_2_object();
|
|
Comparison_result res1 = compare_y (cv1.ps, cv1.pt);
|
|
const Point_2& lower1 = (res1 == SMALLER) ? cv1.ps : cv1.pt;
|
|
const Point_2& upper1 = (res1 == SMALLER) ? cv1.pt : cv1.ps;
|
|
Comparison_result res2 = compare_y (cv2.ps, cv2.pt);
|
|
const Point_2& lower2 = (res2 == SMALLER) ? cv2.ps : cv2.pt;
|
|
const Point_2& upper2 = (res2 == SMALLER) ? cv2.pt : cv2.ps;
|
|
|
|
if (compare_y(upper1, lower2) == SMALLER)
|
|
// cv1 is entirely below cv2:
|
|
return (SMALLER);
|
|
else if (compare_y(lower1, upper2) == LARGER)
|
|
// cv1 is entirely above cv2:
|
|
return (LARGER);
|
|
else
|
|
// cv1 intersects cv2:
|
|
return (EQUAL);
|
|
}
|
|
|
|
// Only cv1 is vertical:
|
|
Comparison_result res1 = compare_y_at_x_2_object()(cv1.ps,cv2.line);
|
|
Comparison_result res2 = compare_y_at_x_2_object()(cv1.pt,cv2.line);
|
|
|
|
if (res1 == res2)
|
|
{
|
|
CGAL_assertion(res1 != EQUAL);
|
|
return (res1);
|
|
}
|
|
else
|
|
return (EQUAL);
|
|
}
|
|
else if (cv2.is_vert)
|
|
{
|
|
// Only cv2 is vertical:
|
|
Comparison_result res1 = compare_y_at_x_2_object()(cv2.ps,cv1.line);
|
|
Comparison_result res2 = compare_y_at_x_2_object()(cv2.pt,cv1.line);
|
|
|
|
if (res1 == res2)
|
|
{
|
|
CGAL_assertion(res1 != EQUAL);
|
|
return ((res1 == LARGER) ? SMALLER : LARGER);
|
|
}
|
|
else
|
|
return (EQUAL);
|
|
}
|
|
|
|
// Compare using the supporting lines.
|
|
return (compare_y_at_x_2_object()(q, cv1.line, cv2.line));
|
|
}
|
|
|
|
/*!
|
|
* Compares the y value of two curves in an epsilon environment to the left
|
|
* of the x-value of their intersection point.
|
|
* \param cv1 The first curve.
|
|
* \param cv2 The second curve.
|
|
* \param q The point.
|
|
* \pre The point q is in the x range of the two curves, and both of them
|
|
* must be also be defined to its left. Furthermore, cv1(x(q) == cv2(x(q)).
|
|
* \return The relative position of cv1 with respect to cv2 to the left of
|
|
* x(q): LARGER, SMALLER or EQUAL.
|
|
*/
|
|
Comparison_result curve_compare_at_x_left(const X_curve_2 & cv1,
|
|
const X_curve_2 & cv2,
|
|
const Point_2 & q) const
|
|
{
|
|
// The two curves must not be vertical.
|
|
CGAL_precondition(! cv1.is_vert);
|
|
CGAL_precondition(! cv2.is_vert);
|
|
|
|
// The two curve must be defined at q and also to its left.
|
|
CGAL_precondition_code(
|
|
Less_x_2 less_x = less_x_2_object();
|
|
);
|
|
|
|
CGAL_precondition (less_x(cv1.ps, q) || less_x(cv1.pt, q));
|
|
CGAL_precondition (!(less_x(cv1.ps, q) && less_x(cv1.pt, q)));
|
|
|
|
CGAL_precondition (less_x(cv2.ps, q) || less_x(cv2.pt, q));
|
|
CGAL_precondition (!(less_x(cv2.ps, q) && less_x(cv2.pt, q)));
|
|
|
|
// Notice q is a placeholder for the x coordinate of the two segments.
|
|
// That is, if we compare them at x(q) the result should be EQUAL.
|
|
CGAL_precondition(compare_y_at_x_2_object()(q,cv1.line,cv2.line) == EQUAL);
|
|
|
|
// Compare the slopes of the two segments to determine thir relative
|
|
// position immediately to the left of q.
|
|
// Notice we use the supporting lines in order to compare the slopes.
|
|
return (compare_slope_2_object()(cv2.line, cv1.line));
|
|
}
|
|
|
|
/*!
|
|
* Compares the y value of two curves in an epsilon environment to the right
|
|
* of the x-value of their intersection point.
|
|
* \param cv1 The first curve.
|
|
* \param cv2 The second curve.
|
|
* \param q The point.
|
|
* \pre The point q is in the x range of the two curves, and both of them
|
|
* must be also be defined to its right. Furthermore, cv1(x(q) == cv2(x(q)).
|
|
* \return The relative position of cv1 with respect to cv2 to the right of
|
|
* x(q): LARGER, SMALLER or EQUAL.
|
|
*/
|
|
Comparison_result curve_compare_at_x_right(const X_curve_2 & cv1,
|
|
const X_curve_2 & cv2,
|
|
const Point_2 & q) const
|
|
{
|
|
// The two curves must not be vertical.
|
|
CGAL_precondition(! cv1.is_vert);
|
|
CGAL_precondition(! cv2.is_vert);
|
|
|
|
// The two curve must be defined at q and also to its right.
|
|
CGAL_precondition_code(Less_x_2 less_x = less_x_2_object(););
|
|
|
|
CGAL_precondition (less_x(q, cv1.ps) || less_x(q, cv1.pt));
|
|
CGAL_precondition (!(less_x(q, cv1.ps) && less_x(q, cv1.pt)));
|
|
|
|
CGAL_precondition (less_x(q, cv2.ps) || less_x(q, cv2.pt));
|
|
CGAL_precondition (!(less_x(q, cv2.ps) && less_x(q, cv2.pt)));
|
|
|
|
// Notice q is a placeholder for the x coordinate of the two segments.
|
|
// That is, if we compare them at x(q) the result should be EQUAL.
|
|
CGAL_precondition(compare_y_at_x_2_object()(q,cv1.line,cv2.line) == EQUAL);
|
|
|
|
// Compare the slopes of the two segments to determine thir relative
|
|
// position immediately to the right of q.
|
|
// Notice we use the supporting lines in order to compare the slopes.
|
|
return (compare_slope_2_object()(cv1.line, cv2.line));
|
|
}
|
|
|
|
/*!
|
|
* Return the location of the given point with respect to the input curve.
|
|
* \param cv The curve.
|
|
* \param p The point.
|
|
* \pre p is in the x-range of cv.
|
|
* \return SMALLER if cv(x(p)) < y(p);
|
|
* LARGER if cv(x(p)) > y(p);
|
|
* or else (if p is on the curve) EQUAL.
|
|
*/
|
|
Comparison_result curve_get_point_status (const X_curve_2 & cv,
|
|
const Point_2 & p) const
|
|
{
|
|
CGAL_precondition(curve_is_in_x_range(cv, p));
|
|
|
|
if (! cv.is_vert)
|
|
{
|
|
// Compare with the supporting line.
|
|
Comparison_result res = compare_y_at_x_2_object()(p, cv.line);
|
|
|
|
if (res == LARGER)
|
|
return (SMALLER);
|
|
else if (res == SMALLER)
|
|
return (LARGER);
|
|
return (EQUAL);
|
|
}
|
|
else
|
|
{
|
|
// Compare with the vertical segment's end-points.
|
|
Compare_y_2 compare_y = compare_y_2_object();
|
|
Comparison_result res1 = compare_y (cv.ps, p);
|
|
Comparison_result res2 = compare_y (cv.pt, p);
|
|
|
|
if (res1 == res2)
|
|
return (res1);
|
|
else
|
|
return (EQUAL);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Check if the two curves are the same (have the same graph).
|
|
* \param cv1 The first curve.
|
|
* \param cv2 The second curve.
|
|
* \return (true) if the two curves are the same.
|
|
*/
|
|
bool curve_is_same(const X_curve_2 & cv1,const X_curve_2 & cv2) const
|
|
{
|
|
Equal_2 equal = equal_2_object();
|
|
return ((equal(cv1.ps, cv2.ps) && equal(cv1.pt, cv2.pt)) ||
|
|
(equal(cv1.ps, cv2.pt) && equal(cv1.pt, cv2.ps)));
|
|
}
|
|
|
|
/*!
|
|
* Check if the two points are the same.
|
|
* \param p1 The first point.
|
|
* \param p2 The second point.
|
|
* \return (true) if p1 == p2.
|
|
*/
|
|
bool point_is_same(const Point_2 & p1, const Point_2 & p2) const
|
|
{
|
|
return (equal_2_object()(p1, p2));
|
|
}
|
|
|
|
/*!
|
|
* Get the curve source.
|
|
* \param cv The curve.
|
|
* \return The source point.
|
|
*/
|
|
const Point_2& curve_source(const X_curve_2 & cv) const
|
|
{
|
|
return (cv.ps);
|
|
}
|
|
|
|
/*!
|
|
* Get the curve target.
|
|
* \param cv The curve.
|
|
* \return The target point.
|
|
*/
|
|
const Point_2& curve_target(const X_curve_2 & cv) const
|
|
{
|
|
return (cv.pt);
|
|
}
|
|
|
|
/*!
|
|
* Check whether the curve is x-monotone.
|
|
* \param cv The curves.
|
|
* \return (true) if the curve is x-monotone. In case of segments, the
|
|
* function always returns (true), since all segments are x-monotone.
|
|
* Vertical segments are also considered as 'weakly' x-monotone.
|
|
*/
|
|
bool is_x_monotone(const Curve_2 &) const
|
|
{
|
|
// Return true, since a sgement is always x-monotone.
|
|
return (true);
|
|
}
|
|
|
|
/*! Cut the given curve into x-monotone subcurves and stores them in the
|
|
* given list. While segments are x_monotone, still need to cast their type.
|
|
* \param cv The curve.
|
|
* \param x_curves A list of the output x-monotone sub-curves.
|
|
*/
|
|
void make_x_monotone(const Curve_2& cv, std::list<Curve_2>& l) const
|
|
{
|
|
l.clear();
|
|
l.push_back(cv);
|
|
}
|
|
|
|
/*!
|
|
* Flip a given curve.
|
|
* \param cv The input curve.
|
|
* \return The flipped curve. In case of segments, if the input is [s,t],
|
|
* then the flipped curve is simply [t,s].
|
|
*/
|
|
X_curve_2 curve_flip(const X_curve_2 & cv) const
|
|
{
|
|
X_curve_2 flip_cv(cv);
|
|
|
|
flip_cv.ps = cv.pt;
|
|
flip_cv.pt = cv.ps;
|
|
return (flip_cv);
|
|
}
|
|
|
|
/*!
|
|
* Split a given curve at a given split point into two sub-curves.
|
|
* \param cv the curve to split
|
|
* \param c1 the output first part of the split curve. Its source is the
|
|
* source of the original curve.
|
|
* \param c2 the output second part of the split curve. Its target is the
|
|
* target of the original curve.
|
|
* \param p the split point.
|
|
* \pre p lies on cv but is not one of its end-points.
|
|
*/
|
|
void curve_split(const X_curve_2& cv,
|
|
X_curve_2& c1, X_curve_2& c2,
|
|
const Point_2& p) const
|
|
{
|
|
// Check preconditions.
|
|
CGAL_precondition(curve_get_point_status(cv, p) == EQUAL);
|
|
CGAL_precondition_code(Equal_2 is_equal = equal_2_object());
|
|
CGAL_precondition(!is_equal(cv.ps, p));
|
|
CGAL_precondition(!is_equal(cv.pt, p));
|
|
|
|
// Do the split.
|
|
c1.line = cv.line;
|
|
c1.ps = cv.ps;
|
|
c1.pt = p;
|
|
c1.is_vert = cv.is_vert;
|
|
|
|
c2.line = cv.line;
|
|
c2.ps = p;
|
|
c2.pt = cv.pt;
|
|
c2.is_vert = cv.is_vert;
|
|
|
|
return;
|
|
}
|
|
|
|
/*!
|
|
* Find the nearest intersection point (or points) of two given curves to
|
|
* the right lexicographically of a given point not includin the point
|
|
* itself, (with one exception explained below).
|
|
* If the intersection of the two curves is an X_curve_2, that is, they
|
|
* overlap at infinitely many points, then if the right endpoint and the
|
|
* left endpoint of the overlapping subcurve are strickly to the right of
|
|
* the given point, they are returned through the two other point
|
|
* references respectively. If the given point is between the
|
|
* overlapping-subcurve endpoints, or the point is its left endpoint,
|
|
* the point and the right endpoint of the subcurve are returned through
|
|
* the point references respectively. If the intersection of the two curves
|
|
* is a point to the right of the given point, it is returned through the
|
|
* point references.
|
|
* \param cv1 The first curve.
|
|
* \param cv2 The second curve.
|
|
* \param p The refernece point.
|
|
* \param p1 The first output point.
|
|
* \param p2 The second output point.
|
|
* \return (true) if c1 and c2 do intersect to the right of p, or (false)
|
|
* if no such intersection exists.
|
|
*/
|
|
bool nearest_intersection_to_right(const X_curve_2 & cv1,
|
|
const X_curve_2 & cv2,
|
|
const Point_2 & p,
|
|
Point_2 & p1, Point_2 & p2) const
|
|
{
|
|
bool is_overlap;
|
|
|
|
if (! _find_intersection (cv1, cv2, is_overlap, p1, p2))
|
|
return (false);
|
|
|
|
if (! is_overlap)
|
|
{
|
|
if (compare_xy_2_object()(p1, p) == LARGER)
|
|
{
|
|
p2 = p1;
|
|
return (true);
|
|
}
|
|
return (false);
|
|
}
|
|
else
|
|
{
|
|
// Notice that p1 < p2.
|
|
if (compare_xy_2_object()(p1, p) == LARGER)
|
|
{
|
|
return (true);
|
|
}
|
|
else if (compare_xy_2_object()(p2, p) == LARGER)
|
|
{
|
|
p1 = p;
|
|
return (true);
|
|
}
|
|
return (false);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Find the nearest intersection point of two given curves to the left of
|
|
* a given point. Nearest is defined as the lexicographically nearest not
|
|
* including the point itself (with one exception explained below).
|
|
* If the intersection of the two curves is an X_curve_2, that is,
|
|
* there is an overlapping subcurve, then if the the source and target of the
|
|
* subcurve are strickly to the left, they are returned through two
|
|
* other point references p1 and p2. If p is between the source and target
|
|
* of the overlapping subcurve, or p is its right endpoint, p and the source
|
|
* of the left endpoint of the subcurve are returned through p1 and p2
|
|
* respectively.
|
|
* If the intersection of the two curves is a point to the left of p, it is
|
|
* returned through the p1 and p2.
|
|
* \param cv1 The first curve.
|
|
* \param cv2 The second curve.
|
|
* \param p The refernece point.
|
|
* \param p1 The first output point.
|
|
* \param p2 The second output point.
|
|
* \return (true) if c1 and c2 do intersect to the left of p, or (false)
|
|
* if no such intersection exists.
|
|
*/
|
|
bool nearest_intersection_to_left(const X_curve_2 & cv1,
|
|
const X_curve_2 & cv2,
|
|
const Point_2 & p,
|
|
Point_2 & p1, Point_2 & p2) const
|
|
{
|
|
bool is_overlap;
|
|
|
|
if (! _find_intersection (cv1, cv2, is_overlap, p1, p2))
|
|
return (false);
|
|
|
|
if (! is_overlap)
|
|
{
|
|
if (compare_xy_2_object()(p1, p) == SMALLER)
|
|
{
|
|
p2 = p1;
|
|
return (true);
|
|
}
|
|
return (false);
|
|
}
|
|
else
|
|
{
|
|
// Notice that ip1 < ip2.
|
|
if (compare_xy_2_object()(p2, p) == SMALLER)
|
|
{
|
|
return (true);
|
|
}
|
|
else if (compare_xy_2_object()(p1, p) == SMALLER)
|
|
{
|
|
p2 = p;
|
|
return (true);
|
|
}
|
|
return (false);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Check whether the two given curves overlap.
|
|
* \patam cv1 The first curve.
|
|
* \patam cv2 The second curve.
|
|
* \return (true) if the two curves overlap in a one-dimensional subcurve
|
|
* (i.e., not in a finite number of points). Otherwise, if they have a finite
|
|
* number of intersection points, or none at all, return (false).
|
|
*/
|
|
bool curves_overlap(const X_curve_2 & cv1, const X_curve_2 & cv2) const
|
|
{
|
|
// Comparing lines
|
|
// if (!equal_2_object()(cv1.line, cv2.line)) return false;
|
|
// doesn't work, as coincident lines with opposite direction are
|
|
// considered different!
|
|
Has_on_2 has_on = has_on_2_object();
|
|
if (!has_on(cv1.line, cv2.ps) || !has_on(cv1.line, cv2.pt)) return false;
|
|
|
|
if (cv1.is_vert) {
|
|
if (cv2.is_vert) {
|
|
Compare_y_2 compare_y = compare_y_2_object();
|
|
Comparison_result res_ss = compare_y (cv1.ps, cv2.ps);
|
|
Comparison_result res_st = compare_y (cv1.ps, cv2.pt);
|
|
if (res_ss == SMALLER) {
|
|
if (res_st == LARGER) return true;
|
|
if (compare_y (cv1.pt, cv2.ps) == LARGER) return true;
|
|
return (compare_y (cv1.pt, cv2.pt) == LARGER);
|
|
}
|
|
|
|
if (res_ss == LARGER) {
|
|
if (res_st == SMALLER) return true;
|
|
if (compare_y (cv1.pt, cv2.ps) == SMALLER) return true;
|
|
return (compare_y (cv1.pt, cv2.pt) == SMALLER);
|
|
}
|
|
|
|
// res_ss == EQUAL
|
|
if (res_st == SMALLER)
|
|
return (compare_y (cv1.pt, cv2.ps) == LARGER);
|
|
return (compare_y (cv1.pt, cv2.ps) == SMALLER);
|
|
}
|
|
return false;
|
|
}
|
|
if (cv2.is_vert) return false;
|
|
|
|
Compare_x_2 compare_x = compare_x_2_object();
|
|
Comparison_result res_ss = compare_x (cv1.ps, cv2.ps);
|
|
Comparison_result res_st = compare_x (cv1.ps, cv2.pt);
|
|
if (res_ss == SMALLER) {
|
|
if (res_st == LARGER) return true;
|
|
if (compare_x (cv1.pt, cv2.ps) == LARGER) return true;
|
|
return (compare_x (cv1.pt, cv2.pt) == LARGER);
|
|
}
|
|
|
|
if (res_ss == LARGER) {
|
|
if (res_st == SMALLER) return true;
|
|
if (compare_x (cv1.pt, cv2.ps) == SMALLER) return true;
|
|
return (compare_x (cv1.pt, cv2.pt) == SMALLER);
|
|
}
|
|
|
|
// res_ss == EQUAL
|
|
if (res_st == SMALLER)
|
|
return (compare_x (cv1.pt, cv2.ps) == LARGER);
|
|
return (compare_x (cv1.pt, cv2.ps) == SMALLER);
|
|
}
|
|
|
|
private:
|
|
|
|
/*!
|
|
* Find the intersection between teo segements.
|
|
* \param cv1 The first segment.
|
|
* \param cv2 The second segment.
|
|
* \param is_ovelap Are the two segment overlapping.
|
|
* \param p1 The intersection point (if there is no overlap),
|
|
* otherwise the leftmost end-point of the intersection segment.
|
|
* \param p2 If there is an overlap, the rightmost end-point of the
|
|
* intersection segment.
|
|
* \return (true) if an intersectio has been found.
|
|
*/
|
|
bool _find_intersection (const X_curve_2& cv1,
|
|
const X_curve_2& cv2,
|
|
bool& is_overlap,
|
|
Point_2& p1, Point_2& p2) const
|
|
{
|
|
// Computing the orientation ahead and checking whether the end points of
|
|
// one curve are in opposite orientations with respect to the other seems
|
|
// slow down the process!
|
|
|
|
// Intersect the two supporting lines.
|
|
Object res = intersect_2_object()(cv1.line, cv2.line);
|
|
|
|
// Parallel lines do not intersect
|
|
if (res.is_empty())
|
|
return (false);
|
|
|
|
Point_2 ip;
|
|
if (assign(ip, res))
|
|
{
|
|
is_overlap = false;
|
|
|
|
// Simple case of intersection at a single point.
|
|
if (_is_on_segment(cv1, ip) && _is_on_segment(cv2, ip))
|
|
{
|
|
p1 = ip;
|
|
return (true);
|
|
}
|
|
return (false);
|
|
}
|
|
else // The two supporting lines overlap.
|
|
{
|
|
// Assign the end-points such that p1 < p2.
|
|
Compare_xy_2 comp_xy = compare_xy_2_object();
|
|
|
|
if (comp_xy(cv1.ps, cv1.pt) == SMALLER)
|
|
{
|
|
p1 = cv1.ps;
|
|
p2 = cv1.pt;
|
|
}
|
|
else
|
|
{
|
|
p1 = cv1.pt;
|
|
p2 = cv1.ps;
|
|
}
|
|
|
|
// Clip the first segment with respect to cv2.
|
|
Comparison_result res = comp_xy(cv2.ps, cv2.pt);
|
|
const Point_2& left2 = (res == SMALLER) ? cv2.ps : cv2.pt;
|
|
const Point_2& right2 = (res == LARGER) ? cv2.ps : cv2.pt;
|
|
|
|
if (comp_xy(p2, left2) == SMALLER)
|
|
return (false);
|
|
else if (comp_xy(p1, left2) == SMALLER)
|
|
p1 = left2;
|
|
|
|
if (comp_xy(p1, right2) == LARGER)
|
|
return (false);
|
|
else if (comp_xy(p2, right2) == LARGER)
|
|
p2 = right2;
|
|
|
|
// Check if the intersection segment has not become a point.
|
|
is_overlap = (comp_xy(p1,p2) != EQUAL);
|
|
CGAL_assertion(comp_xy(p1,p2) != LARGER);
|
|
return (true);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Check whether the given point lies on the given segment.
|
|
* \param cv The curve.
|
|
* \param q The point.
|
|
* \pre The function assumes q lies on the supporting line of the segment.
|
|
* \return (true) if q lies of cv.
|
|
*/
|
|
bool _is_on_segment (const X_curve_2 & cv, const Point_2 & q) const
|
|
{
|
|
if (! cv.is_vert)
|
|
{
|
|
Compare_x_2 comp_x = compare_x_2_object();
|
|
Comparison_result res1 = comp_x (q, cv.ps);
|
|
Comparison_result res2 = comp_x (q, cv.pt);
|
|
|
|
// We check if x(q) equals the x value of one of the end-points.
|
|
// If not, we check whether one end-point is to q's left and the other is
|
|
// to its right.
|
|
return ((res1 == EQUAL) || (res2 == EQUAL) ||
|
|
(res1 != res2));
|
|
}
|
|
else
|
|
{
|
|
Compare_y_2 comp_y = compare_y_2_object();
|
|
Comparison_result res1 = comp_y (q, cv.ps);
|
|
Comparison_result res2 = comp_y (q, cv.pt);
|
|
|
|
// We check if x(q) equals the y value of one of the end-points.
|
|
// If not, we check whether one end-point is above q and the other is
|
|
// below it.
|
|
return ((res1 == EQUAL) || (res2 == EQUAL) ||
|
|
(res1 != res2));
|
|
}
|
|
}
|
|
};
|
|
|
|
/*!
|
|
* A representation of a segment, as used by the Arr_segment_cached_traits_2
|
|
* traits class.
|
|
*/
|
|
template <class Kernel_>
|
|
class Segment_cached_2 :
|
|
public Arr_segment_cached_traits_2<Kernel_>::My_segment_cached_2
|
|
{
|
|
typedef typename Arr_segment_cached_traits_2<Kernel_>::My_segment_cached_2
|
|
Base;
|
|
typedef typename Kernel_::Segment_2 Segment_2;
|
|
typedef typename Kernel_::Point_2 Point_2;
|
|
|
|
public:
|
|
|
|
/*!
|
|
* Default constructor.
|
|
*/
|
|
Segment_cached_2 () :
|
|
Base()
|
|
{}
|
|
|
|
/*!
|
|
* Constructor from a segment.
|
|
* \param seg The segment.
|
|
*/
|
|
Segment_cached_2 (const Segment_2& seg) :
|
|
Base(seg)
|
|
{}
|
|
|
|
/*!
|
|
* Construct a segment from two end-points.
|
|
* \param source The source point.
|
|
* \param target The target point.
|
|
*/
|
|
Segment_cached_2 (const Point_2& source, const Point_2& target) :
|
|
Base(source,target)
|
|
{}
|
|
|
|
/*!
|
|
* Cast to a segment.
|
|
*/
|
|
operator Segment_2 () const
|
|
{
|
|
return (Segment_2(ps, pt));
|
|
}
|
|
|
|
/*!
|
|
* Create a bounding box for the segment.
|
|
*/
|
|
Bbox_2 bbox()
|
|
{
|
|
Segment_2 seg(ps, pt);
|
|
return (seg.bbox());
|
|
}
|
|
|
|
/*!
|
|
* Get the segment source.
|
|
*/
|
|
const Point_2& source() const
|
|
{
|
|
return ps;
|
|
}
|
|
|
|
/*!
|
|
* Get the segment target.
|
|
*/
|
|
const Point_2& target() const
|
|
{
|
|
return pt;
|
|
}
|
|
};
|
|
|
|
/*!
|
|
* Output operator for a cached segment.
|
|
*/
|
|
template <class Kernel_>
|
|
::std::ostream& operator<< (::std::ostream& os,
|
|
const Segment_cached_2<Kernel_>& seg)
|
|
{
|
|
os << static_cast<typename Kernel_::Segment_2>(seg);
|
|
return (os);
|
|
}
|
|
|
|
CGAL_END_NAMESPACE
|
|
|
|
#endif
|