cgal/Arrangement_2/include/CGAL/Arr_polyline_traits_2.h

1048 lines
34 KiB
C++
Executable File

// Copyright(c) 2003 Tel-Aviv University(Israel).
// All rights reserved.
//
// This file is part of CGAL(www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL distributed with CGAL.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
//
// Author(s) : Efi Fogel <efif@post.tau.ac.il>
// Ron Wein <wein@post.tau.ac.il>
#ifndef CGAL_ARR_POLYLINE_TRAITS_2_H
#define CGAL_ARR_POLYLINE_TRAITS_2_H
/*! \file
* The traits-class for the linear piece-wiese(polyline) type of curves of the
* arrangement package.
*/
#include <CGAL/basic.h>
#include <CGAL/tags.h>
#include <CGAL/Arr_traits_2/Polyline_2.h>
CGAL_BEGIN_NAMESPACE
template <class T_SegmentTraits_2>
class Arr_polyline_traits_2 {
public:
typedef T_SegmentTraits_2 Segment_traits_2;
// Tag defintion:
typedef Tag_true Has_left_category;
typedef Tag_true Has_merge_category;
private:
typedef Arr_polyline_traits_2<Segment_traits_2> Self;
// Data members:
Segment_traits_2 seg_traits; // The base segment-traits class.
private:
enum { INVALID_INDEX = 0xffffffff };
public:
/*! Default constructor */
Arr_polyline_traits_2() : seg_traits() {}
/// \name Types and functors inherited from the base segment traits.
//@{
// Traits types:
typedef typename Segment_traits_2::Point_2 Point_2;
typedef typename Segment_traits_2::Curve_2 Segment_2;
typedef _Polyline_2<Segment_traits_2> Curve_2;
typedef _X_monotone_polyline_2<Segment_traits_2> X_monotone_curve_2;
/*! Compare the x-coordinates of two points. */
typedef typename Segment_traits_2::Compare_x_2 Compare_x_2;
/*! Get a Compare_x_2 functor object. */
Compare_x_2 compare_x_2_object() const
{
return seg_traits.compare_x_2_object();
}
/*! Compare two points lexigoraphically: by x, then by y. */
typedef typename Segment_traits_2::Compare_xy_2 Compare_xy_2;
/*! Get a Compare_xy_2 functor object. */
Compare_xy_2 compare_xy_2_object() const
{
return seg_traits.compare_xy_2_object();
}
///@}
/// \name Basic predicate functors(based on the segment traits).
//@{
class Construct_min_vertex_2 {
private:
const Segment_traits_2 * seg_traits;
public:
/*! Constructor. */
Construct_min_vertex_2(const Segment_traits_2 * traits) : seg_traits(traits)
{}
/*!
* Get the left endpoint of the x-monotone curve(segment).
* \param cv The polyline curve.
* \return The left endpoint.
*/
const Point_2 operator()(const X_monotone_curve_2 & cv) const
{
CGAL_assertion(cv.size() > 0);
return seg_traits->construct_min_vertex_2_object()(cv[0]);
}
};
/*! Get a Construct_min_vertex_2 functor object. */
Construct_min_vertex_2 construct_min_vertex_2_object() const
{
return Construct_min_vertex_2(&seg_traits);
}
class Construct_max_vertex_2 {
private:
const Segment_traits_2 * seg_traits;
public:
/*! Constructor. */
Construct_max_vertex_2(const Segment_traits_2 * traits) : seg_traits(traits)
{}
/*!
* Get the right endpoint of the x-monotone curve(segment).
* \param cv The polylinecurve.
* \return The right endpoint.
*/
const Point_2 operator()(const X_monotone_curve_2 & cv) const
{
CGAL_assertion(cv.size() > 0);
return seg_traits->construct_max_vertex_2_object()(cv[cv.size() - 1]);
}
};
/*! Get a Construct_max_vertex_2 functor object. */
Construct_max_vertex_2 construct_max_vertex_2_object() const
{
return Construct_max_vertex_2(&seg_traits);
}
class Is_vertical_2 {
private:
const Segment_traits_2 * seg_traits;
public:
/*! Constructor. */
Is_vertical_2(const Segment_traits_2 * traits) : seg_traits(traits) {}
/*!
* Check whether the given x-monotone curve is a vertical segment.
* \param cv The curve.
* \return (true) if the curve is a vertical segment;(false) otherwise.
*/
bool operator()(const X_monotone_curve_2 & cv) const
{
// An x-monotone polyline can represent a vertical segment only if it
// is comprised of vertical segments. If the first segment is vertical,
// all segments are vertical in an x-monotone polyline
return (seg_traits->is_vertical_2_object()(cv[0]));
}
};
/*! Get an Is_vertical_2 functor object. */
Is_vertical_2 is_vertical_2_object() const
{
return Is_vertical_2(&seg_traits);
}
class Compare_y_at_x_2 {
private:
typedef Arr_polyline_traits_2<Segment_traits_2> Self;
const Segment_traits_2 * seg_traits;
public:
/*! Constructor. */
Compare_y_at_x_2(const Segment_traits_2 * traits) : seg_traits(traits) {}
/*!
* Return the location of the given point with respect to the input curve.
* \param cv The polyline curve.
* \param p The point.
* \pre p is in the x-range of cv.
* \return SMALLER if y(p) < cv(x(p)), i.e. the point is below the curve;
* LARGER if y(p) > cv(x(p)), i.e. the point is above the curve;
* EQUAL if p lies on the curve.
*/
Comparison_result operator()(const Point_2 & p,
const X_monotone_curve_2 & cv) const
{
// Get the index of the segment in cv containing p.
unsigned int i = Self::_locate(seg_traits, cv, p);
CGAL_precondition(i != INVALID_INDEX);
// Compare the segment cv[i] and p.
return seg_traits->compare_y_at_x_2_object()(p, cv[i]);
}
};
friend class Compare_y_at_x_2;
/*! Get a Compare_y_at_x_2 functor object. */
Compare_y_at_x_2 compare_y_at_x_2_object() const
{
return Compare_y_at_x_2(&seg_traits);
}
class Compare_y_at_x_left_2 {
private:
typedef Arr_polyline_traits_2<Segment_traits_2> Self;
const Segment_traits_2 * seg_traits;
public:
/*! Constructor. */
Compare_y_at_x_left_2(const Segment_traits_2 * traits) : seg_traits(traits)
{}
/*!
* Compare the y value of two x-monotone curves immediately to the left
* of their intersection point.
* \param cv1 The first polyline curve.
* \param cv2 The second polyline curve.
* \param p The intersection point.
* \pre The point p lies on both curves, and both of them must be also be
* defined(lexicographically) to its left.
* \return The relative position of cv1 with respect to cv2 immdiately to
* the left of p: SMALLER, LARGER or EQUAL.
*/
Comparison_result operator()(const X_monotone_curve_2 & cv1,
const X_monotone_curve_2 & cv2,
const Point_2 & p) const
{
// Get the indices of the segments in cv1 and cv2 containing p and
// defined to its left.
unsigned int i1 = Self::_locate_side(seg_traits, cv1, p, false);
unsigned int i2 = Self::_locate_side(seg_traits, cv2, p, false);
CGAL_precondition(i1 != INVALID_INDEX);
CGAL_precondition(i2 != INVALID_INDEX);
// Compare cv1[i1] and cv2[i2] at p's left.
return seg_traits->compare_y_at_x_left_2_object()(cv1[i1], cv2[i2], p);
}
};
friend class Compare_y_at_x_left_2;
/*! Get a Compare_y_at_x_left_2 functor object. */
Compare_y_at_x_left_2 compare_y_at_x_left_2_object() const
{
return Compare_y_at_x_left_2(&seg_traits);
}
class Compare_y_at_x_right_2 {
private:
typedef Arr_polyline_traits_2<Segment_traits_2> Self;
const Segment_traits_2 * seg_traits;
public:
/*! Constructor. */
Compare_y_at_x_right_2(const Segment_traits_2 * traits) : seg_traits(traits)
{}
/*!
* Compare the y value of two x-monotone curves immediately to the right
* of their intersection point.
* \param cv1 The first curve.
* \param cv2 The second curve.
* \param p The intersection point.
* \pre The point p lies on both curves, and both of them must be also be
* defined(lexicographically) to its right.
* \return The relative position of cv1 with respect to cv2 immdiately to
* the right of p: SMALLER, LARGER or EQUAL.
*/
Comparison_result operator()(const X_monotone_curve_2 & cv1,
const X_monotone_curve_2 & cv2,
const Point_2 & p) const
{
// Get the indices of the segments in cv1 and cv2 containing p and
// defined to its right.
unsigned int i1 = Self::_locate_side(seg_traits, cv1, p, true);
unsigned int i2 = Self::_locate_side(seg_traits, cv2, p, true);
CGAL_precondition(i1 != INVALID_INDEX);
CGAL_precondition(i2 != INVALID_INDEX);
// Compare cv1[i1] and cv2[i2] at p's right.
return seg_traits->compare_y_at_x_right_2_object()(cv1[i1],cv2[i2], p);
}
};
friend class Compare_y_at_x_right_2;
/*! Get a Compare_y_at_x_right_2 functor object. */
Compare_y_at_x_right_2 compare_y_at_x_right_2_object() const
{
return Compare_y_at_x_right_2(&seg_traits);
}
class Equal_2 {
private:
const Segment_traits_2 * seg_traits;
public:
/*! Constructor. */
Equal_2(const Segment_traits_2 * traits) : seg_traits(traits) {}
/*!
* Check if the two points are the same.
* \param p1 The first point.
* \param p2 The second point.
* \return (true) if the two point are the same;(false) otherwise.
*/
bool operator()(const Point_2 & p1, const Point_2 & p2) const
{
return seg_traits->equal_2_object()(p1, p2);
}
/*!
* Check if the two x-monotone 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;(false) otherwise.
*/
bool operator()(const X_monotone_curve_2 & cv1,
const X_monotone_curve_2 & cv2) const
{
// The two curves must contain the same number of segments.
unsigned int n1 = cv1.size();
unsigned int n2 = cv2.size();
if (n1 != n2)
return false;
// Check the pairwise equality of the contained segments.
typename Segment_traits_2::Equal_2 equal = seg_traits->equal_2_object();
unsigned int i;
for (i = 0; i < n1; ++i) {
if (!equal(cv1[i], cv2[i]))
return false;
}
return true;
}
};
/*! Get an Equal_2 functor object. */
Equal_2 equal_2_object() const
{
return Equal_2(&seg_traits);
}
///@}
/// \name Construction functors(based on the segment traits).
//@{
class Make_x_monotone_2 {
private:
const Segment_traits_2 * seg_traits;
public:
/*! Constructor. */
Make_x_monotone_2(const Segment_traits_2 * traits) : seg_traits(traits) {}
/*!
* Cut the given curve into x-monotone subcurves and insert them into the
* given output iterator. As segments are always x_monotone, only one
* object will be contained in the iterator.
* \param cv The curve.
* \param oi The output iterator, whose value-type is Object. The output
* object is a wrapper of either an X_monotone_curve_2, or - in
* case the input segment is degenerate - a Point_2 object.
* \return The past-the-end iterator.
*/
template<class OutputIterator>
OutputIterator operator()(const Curve_2 & cv, OutputIterator oi) const
{
// Go over all points in the input curve.
typename Curve_2::const_iterator ps = cv.begin();
typename Curve_2::const_iterator end = cv.end();
// Empty polyline:
if (ps == end)
return oi;
typename Curve_2::const_iterator pt = ps;
++pt;
if (pt == end) {
// The polyline contains a single isolated point:
*oi++ = make_object(*ps);
return oi;
}
// Locate points where the x-order changes:
typename Segment_traits_2::Compare_x_2 compare_x =
seg_traits->compare_x_2_object();
typename Segment_traits_2::Compare_xy_2 compare_xy =
seg_traits->compare_xy_2_object();
Comparison_result x_res;
Comparison_result xy_res;
typename Curve_2::const_iterator x_begin = ps;
Comparison_result curr_x_res;
Comparison_result curr_xy_res;
x_res = compare_x(*ps, *pt);
if (x_res != EQUAL)
xy_res = x_res;
else
xy_res = compare_xy(*ps, *pt);
++ps; ++pt;
while (pt != end) {
curr_x_res = compare_x(*ps, *pt);
if (curr_x_res != EQUAL)
curr_xy_res = curr_x_res;
else
curr_xy_res = compare_xy(*ps, *pt);
if (curr_x_res != x_res || curr_xy_res != xy_res) {
// Create a new x-monotone polyline from the range of points
// [x_begin, pt):
*oi++ = make_object(X_monotone_curve_2(x_begin, pt));
x_begin = ps;
x_res = curr_x_res;
xy_res = curr_xy_res;
}
++ps; ++pt;
}
// Create an x-monotone polyline from the remaining points.
CGAL_assertion(x_begin != end);
*oi++ = make_object(X_monotone_curve_2(x_begin, end));
return oi;
}
};
/*! Get a Make_x_monotone_2 functor object. */
Make_x_monotone_2 make_x_monotone_2_object() const
{
return Make_x_monotone_2(&seg_traits);
}
class Split_2
{
private:
typedef Arr_polyline_traits_2<Segment_traits_2> Self;
Segment_traits_2 * seg_traits;
public:
/*! Constructor. */
Split_2(Segment_traits_2 * traits) : seg_traits(traits) {}
public:
/*!
* Split a given x-monotone curve at a given point into two sub-curves.
* \param cv The curve to split
* \param p The split point.
* \param c1 Output: The left resulting subcurve(p is its right endpoint).
* \param c2 Output: The right resulting subcurve(p is its left endpoint).
* \pre p lies on cv but is not one of its end-points.
*/
void operator()(const X_monotone_curve_2 & cv, const Point_2 & p,
X_monotone_curve_2 & c1, X_monotone_curve_2 & c2) const
{
typename Segment_traits_2::Construct_min_vertex_2 min_vertex =
seg_traits->construct_min_vertex_2_object();
typename Segment_traits_2::Construct_max_vertex_2 max_vertex =
seg_traits->construct_max_vertex_2_object();
typename Segment_traits_2::Equal_2 equal = seg_traits->equal_2_object();
// Make sure the split point is not one of the curve endpoints.
CGAL_precondition(!equal(min_vertex(cv[0]), p));
CGAL_precondition(!equal(max_vertex(cv[cv.size() - 1]), p));
// Locate the segment on the polyline cv that contains p.
unsigned int i = Self::_locate(seg_traits, cv, p);
CGAL_precondition(i != INVALID_INDEX);
// Clear the output curves.
c1.clear();
c2.clear();
// Push all segments labeled(0, 1, ... , i-1) into c1.
unsigned int j;
for (j = 0; j < i; ++j)
c1.push_back(cv[j]);
// Check whether the split point is cv[i]'s source of target.
if (equal(max_vertex(cv[i]), p)) {
// The entire i'th segment belongs to c1:
c1.push_back(cv[i]);
} else if (equal(min_vertex(cv[i]), p)) {
// The entire i'th segments belongs to c2:
c2.push_back(cv[i]);
} else {
// The i'th segment should be split: The left part(seg1) goes to cv1,
// and the right part(seg2) goes to cv2.
Segment_2 seg1, seg2;
seg_traits->split_2_object()(cv[i], p, seg1, seg2);
c1.push_back(seg1);
c2.push_back(seg2);
}
// Push all segments labeled(i+1, i+2, ... , n-1) into cv1.
unsigned int n = cv.size();
for (j = i+1; j < n; ++j)
c2.push_back(cv[j]);
}
};
friend class Split_2;
/*! Get a Split_2 functor object. */
Split_2 split_2_object()
{
return Split_2(&seg_traits);
}
class Intersect_2 {
private:
typedef Arr_polyline_traits_2<Segment_traits_2> Self;
Segment_traits_2 * seg_traits;
public:
/*! Constructor. */
Intersect_2(Segment_traits_2 * traits) : seg_traits(traits) {}
/*!
* Find the intersections of the two given curves and insert them into the
* given output iterator. As two segments may itersect only once, only a
* single intersection will be contained in the iterator.
* \param cv1 The first curve.
* \param cv2 The second curve.
* \param oi The output iterator.
* \return The past-the-end iterator.
*/
template<class OutputIterator>
OutputIterator operator()(const X_monotone_curve_2 & cv1,
const X_monotone_curve_2 & cv2,
OutputIterator oi)
{
typename Segment_traits_2::Construct_min_vertex_2 min_vertex =
seg_traits->construct_min_vertex_2_object();
typename Segment_traits_2::Construct_max_vertex_2 max_vertex =
seg_traits->construct_max_vertex_2_object();
typename Segment_traits_2::Equal_2 equal =
seg_traits->equal_2_object();
typename Segment_traits_2::Compare_xy_2 compare_xy =
seg_traits->compare_xy_2_object();
typename Segment_traits_2::Intersect_2 intersect =
seg_traits->intersect_2_object();
typename Segment_traits_2::Compare_y_at_x_2 compare_y_at_x =
seg_traits->compare_y_at_x_2_object();
const unsigned int n1 = cv1.size();
const unsigned int n2 = cv2.size();
unsigned int i1 = 0;
unsigned int i2 = 0;
X_monotone_curve_2 ocv; // Used to represent overlaps.
Comparison_result left_res = compare_xy(min_vertex(cv1[i1]),
min_vertex(cv2[i2]));
if (left_res == SMALLER) {
// cv1's left endpoint is to the left of cv2's left endpoint:
// Locate the index i1 of the segment in cv1 which contains cv2's
// left endpoint.
i1 = Self::_locate(seg_traits, cv1, min_vertex(cv2[i2]));
if (i1 == INVALID_INDEX)
return oi;
if (equal(max_vertex(cv1[i1]), min_vertex(cv2[i2]))) {
++i1;
left_res = EQUAL;
}
} else if (left_res == LARGER) {
// cv1's left endpoint is to the right of cv2's left endpoint:
// Locate the index i2 of the segment in cv2 which contains cv1's
// left endpoint.
i2 = Self::_locate(seg_traits, cv2, min_vertex(cv1[i1]));
if (i2 == INVALID_INDEX)
return oi;
if (equal(max_vertex(cv2[i2]), min_vertex(cv1[i1]))) {
++i2;
left_res = EQUAL;
}
}
// Check if the the left endpoint lies on the other polyline.
bool left_coincides = (left_res == EQUAL);
bool left_overlap = false;
if (left_res == SMALLER)
left_coincides =(compare_y_at_x(min_vertex(cv2[i2]), cv1[i1]) == EQUAL);
else if (left_res == LARGER)
left_coincides =(compare_y_at_x(min_vertex(cv1[i1]), cv2[i2]) == EQUAL);
// The main loop: Go simultaneously over both polylines.
Comparison_result right_res = left_res;
bool right_coincides = left_coincides;
bool right_overlap = false;
while (i1 < n1 && i2 < n2) {
right_res = compare_xy(max_vertex(cv1[i1]), max_vertex(cv2[i2]));
right_coincides = (right_res == EQUAL);
if (right_res == SMALLER)
right_coincides = (compare_y_at_x(max_vertex(cv1[i1]),
cv2[i2]) == EQUAL);
else if (right_res == LARGER)
right_coincides = (compare_y_at_x(max_vertex(cv2[i2]),
cv1[i1]) == EQUAL);
right_overlap = false;
if (!right_coincides && !left_coincides) {
// Non of the endpoints of the current segment of one polyline
// coincides with the curent segment of the other polyline:
// Output the intersection if exists.
oi = intersect(cv1[i1], cv2[i2], oi);
} else if (right_coincides && left_coincides) {
// An overlap exists between the current segments of the polylines:
// Output the overlapping segment.
right_overlap = true;
if (left_res == SMALLER) {
if (right_res == SMALLER) {
Segment_2 seg(min_vertex(cv2[i2]), max_vertex(cv1[i1]));
ocv.push_back(seg);
} else {
Segment_2 seg(min_vertex(cv2[i2]), max_vertex(cv2[i2]));
ocv.push_back(seg);
}
} else {
if (right_res == SMALLER) {
Segment_2 seg(min_vertex(cv1[i1]), max_vertex(cv1[i1]));
ocv.push_back(seg);
} else {
Segment_2 seg(min_vertex(cv1[i1]), max_vertex(cv2[i2]));
ocv.push_back(seg);
}
}
} else if (left_coincides && !right_coincides) {
// The left point of the current segment of one polyline
// coincides with the current segment of the other polyline.
if (left_overlap) {
// An overlap occured at the previous iteration:
// Output the overlapping polyline.
CGAL_assertion(ocv.size() > 0);
*oi++ = make_object(ocv);
ocv.clear();
} else {
// The left point of the current segment of one polyline
// coincides with the current segment of the other polyline, and
// no overlap occured at the previous iteration:
// Output the intersection point. The derivative of at least one of
// the polylines is not defined at this point, so we give it
// multiplicity 0.
if (left_res == SMALLER) {
std::pair<Point_2, unsigned int> p(min_vertex(cv2[i2]), 0);
*oi++ = make_object(p);
} else {
std::pair<Point_2, unsigned int> p(min_vertex(cv1[i1]), 0);
*oi++ = make_object(p);
}
}
}
// Proceed forward.
if (right_res != SMALLER)
++i2;
if (right_res != LARGER)
++i1;
left_res = (right_res == SMALLER) ? LARGER :
(right_res == LARGER) ? SMALLER : EQUAL;
left_coincides = right_coincides;
left_overlap = right_overlap;
}
#if 0
std::cout << "left coincides: " << left_coincides << std::endl;
std::cout << "right coincides: " << right_coincides << std::endl;
std::cout << "right res: " << right_res << std::endl;
std::cout << "left res: " << left_res << std::endl;
#endif
// Output the remaining overlapping polyline, if necessary.
if (ocv.size() > 0) {
*oi++ = make_object(ocv);
} else if (right_coincides) {
if (right_res == SMALLER) {
std::pair<Point_2, unsigned int> ip(max_vertex(cv1[i1 - 1]), 0);
*oi++ = make_object(ip);
} else if (right_res == LARGER) {
std::pair<Point_2, unsigned int> ip(max_vertex(cv2[i2 - 1]), 0);
*oi++ = make_object(ip);
} else if (i1 > 0) {
std::pair<Point_2, unsigned int> ip(max_vertex(cv1[i1 - 1]), 0);
*oi++ = make_object(ip);
} else {
CGAL_assertion(i2 > 0);
std::pair<Point_2, unsigned int> ip(max_vertex(cv2[i2 - 1]), 0);
*oi++ = make_object(ip);
}
}
return oi;
}
};
friend class Intersect_2;
/*! Get an Intersect_2 functor object. */
Intersect_2 intersect_2_object()
{
return Intersect_2(&seg_traits);
}
class Are_mergeable_2 {
private:
const Segment_traits_2 * seg_traits;
public:
/*! Constructor. */
Are_mergeable_2(const Segment_traits_2 * traits) : seg_traits(traits) {}
/*!
* Check whether it is possible to merge two given x-monotone curves.
* \param cv1 The first curve.
* \param cv2 The second curve.
* \return(true) if the two curves are mergeable, that is, they share a
* common endpoint;(false) otherwise.
*/
bool operator()(const X_monotone_curve_2 & cv1,
const X_monotone_curve_2 & cv2) const
{
typename Segment_traits_2::Construct_min_vertex_2 min_vertex =
seg_traits->construct_min_vertex_2_object();
typename Segment_traits_2::Construct_max_vertex_2 max_vertex =
seg_traits->construct_max_vertex_2_object();
typename Segment_traits_2::Equal_2 equal = seg_traits->equal_2_object();
typename Segment_traits_2::Is_vertical_2 is_vertical =
seg_traits->is_vertical_2_object();
const unsigned int n1 = cv1.size();
const unsigned int n2 = cv2.size();
bool ver1 = is_vertical(cv1[0]);
bool ver2 = is_vertical(cv2[0]);
return ((equal(max_vertex(cv1[n1 - 1]), min_vertex(cv2[0])) ||
equal(max_vertex(cv2[n2 - 1]), min_vertex(cv1[0]))) &&
((ver1 && ver2) || (!ver1 && !ver2)));
}
};
/*! Get an Are_mergeable_2 functor object. */
Are_mergeable_2 are_mergeable_2_object() const {
return Are_mergeable_2(&seg_traits);
}
class Merge_2 {
private:
Segment_traits_2 * seg_traits;
public:
/*! Constructor. */
Merge_2(Segment_traits_2 * traits) : seg_traits(traits) {}
public:
/*!
* Merge two given x-monotone curves into a single curve(segment).
* \param cv1 The first curve.
* \param cv2 The second curve.
* \param c Output: The merged curve.
* \pre The two curves are mergeable. That is, they share a common
* endpoint.
*/
void operator()(const X_monotone_curve_2 & cv1,
const X_monotone_curve_2 & cv2,
X_monotone_curve_2 & c) const
{
typename Segment_traits_2::Construct_min_vertex_2 min_vertex =
seg_traits->construct_min_vertex_2_object();
typename Segment_traits_2::Construct_max_vertex_2 max_vertex =
seg_traits->construct_max_vertex_2_object();
typename Segment_traits_2::Equal_2 equal = seg_traits->equal_2_object();
const unsigned int n1 = cv1.size();
const unsigned int n2 = cv2.size();
unsigned int i;
c.clear();
if (equal(max_vertex(cv1[n1 - 1]), min_vertex(cv2[0]))) {
// cv2 extends cv1 to the right:
for (i = 0; i < n1 - 1; ++i)
c.push_back(cv1[i]);
// Try to merge tthe to contiguous line segments:
if (seg_traits->are_mergeable_2_object()(cv1[n1 - 1], cv2[0])) {
Segment_2 seg;
seg_traits->merge_2_object()(cv1[n1 - 1], cv2[0], seg);
c.push_back(seg);
} else {
c.push_back(cv1[n1 - 1]);
c.push_back(cv2[0]);
}
for (i = 1; i < n2; ++i)
c.push_back(cv2[i]);
} else if (equal(max_vertex(cv2[n2 - 1]), min_vertex(cv1[0]))) {
// cv1 extends cv2 to the right:
for (i = 0; i < n2 - 1; ++i)
c.push_back(cv2[i]);
// Try to merge tthe to contiguous line segments:
if (seg_traits->are_mergeable_2_object()(cv2[n2 - 1], cv1[0])) {
Segment_2 seg;
seg_traits->merge_2_object()(cv2[n2 - 1], cv1[0], seg);
c.push_back(seg);
} else {
c.push_back(cv2[n2 - 1]);
c.push_back(cv1[0]);
}
for (i = 1; i < n1; ++i)
c.push_back(cv1[i]);
} else {
CGAL_precondition_msg(false, "The curves are not mergeable.");
}
}
};
/*! Get a Merge_2 functor object. */
Merge_2 merge_2_object()
{
return Merge_2(&seg_traits);
}
///@}
/// \name Functor definitions for the landmarks point-location strategy.
//@{
typedef typename Segment_traits_2::Approximate_number_type
Approximate_number_type;
typedef typename Segment_traits_2::Approximate_2 Approximate_2;
/*! Get an Approximate_2 functor object. */
Approximate_2 approximate_2_object () const
{
return seg_traits.approximate_2_object();
}
class Construct_x_monotone_curve_2
{
public:
/*!
* Return an x-monotone curve connecting the two given endpoints.
* \param p The first point.
* \param q The second point.
* \pre p and q must not be the same.
* \return A segment connecting p and q.
*/
X_monotone_curve_2 operator() (const Point_2& p,
const Point_2& q) const
{
// Construct a polyline containing just two points:
Point_2 pts[2];
pts[0] = p; pts[1] = q;
return (X_monotone_curve_2 (pts + 0, pts + 2));
}
};
/*! Get a Construct_x_monotone_curve_2 functor object. */
Construct_x_monotone_curve_2 construct_x_monotone_curve_2_object () const
{
return Construct_x_monotone_curve_2();
}
//@}
private:
/*!
* Return the index of the segment in the polyline that contains the
* point q in its x-range. The function performs a binary search, so if the
* point q is in the x-range of the polyline with n segments, the segment
* containing it can be located in O(log n) operations.
* \param cv The polyline curve.
* \param q The point.
* \return An index i such that q is in the x-range of cv[i].
* If q is not in the x-range of cv, returns INVALID_INDEX.
*/
static unsigned int _locate(const Segment_traits_2 * seg_traits,
const X_monotone_curve_2 & cv,
const Point_2 & q)
{
typename Segment_traits_2::Construct_min_vertex_2 min_vertex =
seg_traits->construct_min_vertex_2_object();
typename Segment_traits_2::Construct_max_vertex_2 max_vertex =
seg_traits->construct_max_vertex_2_object();
unsigned int from = 0;
unsigned int to = cv.size() - 1;
if (seg_traits->is_vertical_2_object()(cv[0])) {
typename Segment_traits_2::Compare_xy_2 compare_xy =
seg_traits->compare_xy_2_object();
// First check whether the polyline curve really contains q in its
// xy-range:
Comparison_result res_from = compare_xy(min_vertex(cv[from]), q);
if (res_from == EQUAL) return from;
Comparison_result res_to = compare_xy(max_vertex(cv[to]), q);
if (res_to == EQUAL) return to;
typename Segment_traits_2::Compare_x_2 compare_x =
seg_traits->compare_x_2_object();
Comparison_result res = compare_x(max_vertex(cv[to]), q);
if (res != EQUAL) return INVALID_INDEX;
//// q is not in the x-range of cv:
//if (res_from == res_to) return INVALID_INDEX;
// Perform a binary search to locate the segment that contains q in its
// xy-range:
while (to > from) {
unsigned int mid = (from + to) / 2;
if (mid > from) {
Comparison_result res_mid = compare_xy(min_vertex(cv[mid]), q);
if (res_mid == EQUAL) return mid;
if (res_mid == res_from) from = mid;
else to = mid - 1;
} else {
CGAL_assertion(mid < to);
Comparison_result res_mid = compare_xy(max_vertex(cv[mid]), q);
if (res_mid == EQUAL) return mid;
if (res_mid == res_to) to = mid;
else from = mid + 1;
}
}
// In case (from == to), and we know that the polyline contains the q:
CGAL_assertion(from == to);
return from;
}
typename Segment_traits_2::Compare_x_2 compare_x =
seg_traits->compare_x_2_object();
// First check whether the polyline curve really contains q in its x-range.
Comparison_result res_from = compare_x(min_vertex(cv[from]), q);
if (res_from == EQUAL) return from;
Comparison_result res_to = compare_x(max_vertex(cv[to]), q);
if (res_to == EQUAL) return to;
// q is not in the x-range of cv:
if (res_from == res_to) return INVALID_INDEX;
// Perform a binary search and locate the segment that contains q in its
// x-range:
while (to > from) {
unsigned int mid = (from + to) / 2;
if (mid > from) {
Comparison_result res_mid = compare_x(min_vertex(cv[mid]), q);
if (res_mid == EQUAL) return mid;
if (res_mid == res_from) from = mid;
else to = mid - 1;
} else {
CGAL_assertion(mid < to);
Comparison_result res_mid = compare_x(max_vertex(cv[mid]), q);
if (res_mid == EQUAL) return mid;
if (res_mid == res_to) to = mid;
else from = mid + 1;
}
}
// In case(from == to), and we know that the polyline contains the q:
CGAL_assertion(from == to);
return from;
}
/*!
* Find the index of the segment in the polyline that is defined to the
* left(or to the right) of the point q.
* \param cv The polyline curve.
* \param q The point.
* \param to_right(true) if we wish to locate a segment to the right of q,
* (false) if we wish to locate a segment to its right.
* \return An index i such that segments[i] is defined to the left(or to the
* right) of q, or INVALID_INDEX if no such segment exists.
*/
static unsigned int _locate_side(const Segment_traits_2 * seg_traits,
const X_monotone_curve_2 & cv,
const Point_2 & q, const bool & to_right)
{
// First locate a segment segments[i] that contains q in its x-range.
unsigned int i = _locate(seg_traits, cv, q);
if (i == INVALID_INDEX)
return INVALID_INDEX;
typename Segment_traits_2::Equal_2 equal = seg_traits->equal_2_object();
if (equal(seg_traits->construct_min_vertex_2_object()(cv[i]), q)) {
// q is the left endpoint of the i'th segment:
if (to_right)
return i;
else if (i == 0)
return INVALID_INDEX;
else
return i - 1;
}
if (equal(seg_traits->construct_max_vertex_2_object()(cv[i]), q)) {
// q is the right endpoint of the i'th segment:
if (!to_right)
return i;
else if (i == (cv.size() - 1))
return INVALID_INDEX;
else
return i + 1;
}
// In case q is in cv[i]'s interior:
return i;
}
};
CGAL_END_NAMESPACE
#endif