615 lines
24 KiB
C++
Executable File
615 lines
24 KiB
C++
Executable File
// Copyright (c) 2000-2014
|
|
// Utrecht University (The Netherlands),
|
|
// ETH Zurich (Switzerland),
|
|
// INRIA Sophia-Antipolis (France),
|
|
// Max-Planck-Institute Saarbruecken (Germany),
|
|
// and Tel-Aviv University (Israel). All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org).
|
|
// You can redistribute it and/or modify it under the terms of the GNU
|
|
// General Public License as published by the Free Software Foundation,
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// 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$
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
//
|
|
// Author(s) : Waqar Khan <wkhan@mpi-inf.mpg.de>
|
|
|
|
#ifndef CGAL_ARR_POLYLINE_TRAITS_2_H
|
|
#define CGAL_ARR_POLYLINE_TRAITS_2_H
|
|
|
|
#include <CGAL/license/Arrangement_on_surface_2.h>
|
|
|
|
#include <CGAL/disable_warnings.h>
|
|
|
|
/*! \file
|
|
* The traits-class for the linear piece-wiese(polyline) type of curves of the
|
|
* arrangement package.
|
|
*/
|
|
|
|
#include <list>
|
|
#include <iterator>
|
|
#include <boost/type_traits/is_same.hpp>
|
|
#include <boost/utility/enable_if.hpp>
|
|
|
|
#include <CGAL/basic.h>
|
|
#include <CGAL/tags.h>
|
|
#include <CGAL/Arr_segment_traits_2.h>
|
|
#include <CGAL/Arr_polycurve_traits_2.h>
|
|
#include <CGAL/Arr_tags.h>
|
|
#include <CGAL/Arr_enums.h>
|
|
|
|
namespace CGAL {
|
|
|
|
// If no template instantiation is provided, it will be instantiated
|
|
// with Arr_segment_traits.
|
|
template <typename SegmentTraits_2 = Arr_segment_traits_2<> >
|
|
class Arr_polyline_traits_2 : public Arr_polycurve_traits_2<SegmentTraits_2> {
|
|
public:
|
|
typedef SegmentTraits_2 Segment_traits_2;
|
|
|
|
// For completeness
|
|
typedef typename Segment_traits_2::Curve_2 Segment_2;
|
|
typedef typename Segment_traits_2::X_monotone_curve_2 X_monotone_segment_2;
|
|
|
|
private:
|
|
typedef Arr_polyline_traits_2<Segment_traits_2> Self;
|
|
typedef Arr_polycurve_traits_2<Segment_traits_2> Base;
|
|
|
|
public:
|
|
/// \name Types inherited from the polycurve traits class.
|
|
//@{
|
|
|
|
// Tag definitions:
|
|
typedef typename Base::Has_left_category Has_left_category;
|
|
typedef typename Base::Has_merge_category Has_merge_category;
|
|
typedef typename Base::Has_do_intersect_category
|
|
Has_do_intersect_category;
|
|
|
|
typedef typename Base::Left_side_category Left_side_category;
|
|
typedef typename Base::Bottom_side_category Bottom_side_category;
|
|
typedef typename Base::Top_side_category Top_side_category;
|
|
typedef typename Base::Right_side_category Right_side_category;
|
|
|
|
typedef typename Base::Are_all_sides_oblivious_tag
|
|
Are_all_sides_oblivious_tag;
|
|
|
|
typedef typename Base::X_monotone_subcurve_2 X_monotone_subcurve_2;
|
|
typedef typename Base::Subcurve_2 Subcurve_2;
|
|
|
|
typedef typename Base::Point_2 Point_2;
|
|
typedef typename Base::Curve_2 Curve_2;
|
|
typedef typename Base::X_monotone_curve_2 X_monotone_curve_2;
|
|
|
|
typedef typename Base::Multiplicity Multiplicity;
|
|
|
|
typedef typename Base::Compare_x_2 Compare_x_2;
|
|
typedef typename Base::Compare_xy_2 Compare_xy_2;
|
|
typedef typename Base::Construct_min_vertex_2 Construct_min_vertex_2;
|
|
typedef typename Base::Construct_max_vertex_2 Construct_max_vertex_2;
|
|
typedef typename Base::Is_vertical_2 Is_vertical_2;
|
|
typedef typename Base::Compare_y_at_x_2 Compare_y_at_x_2;
|
|
typedef typename Base::Compare_y_at_x_left_2 Compare_y_at_x_left_2;
|
|
typedef typename Base::Compare_y_at_x_right_2 Compare_y_at_x_right_2;
|
|
typedef typename Base::Equal_2 Equal_2;
|
|
typedef typename Base::Compare_endpoints_xy_2 Compare_endpoints_xy_2;
|
|
typedef typename Base::Construct_opposite_2 Construct_opposite_2;
|
|
typedef typename Base::Approximate_2 Approximate_2;
|
|
typedef typename Base::Parameter_space_in_x_2 Parameter_space_in_x_2;
|
|
typedef typename Base::Parameter_space_in_y_2 Parameter_space_in_y_2;
|
|
typedef typename Base::Compare_x_on_boundary_2 Compare_x_on_boundary_2;
|
|
typedef typename Base::Compare_x_at_limit_2 Compare_x_at_limit_2;
|
|
typedef typename Base::Compare_x_near_limit_2 Compare_x_near_limit_2;
|
|
typedef typename Base::Compare_y_on_boundary_2 Compare_y_on_boundary_2;
|
|
typedef typename Base::Compare_y_near_boundary_2 Compare_y_near_boundary_2;
|
|
typedef typename Base::Is_on_y_identification_2 Is_on_y_identification_2;
|
|
typedef typename Base::Is_on_x_identification_2 Is_on_x_identification_2;
|
|
|
|
typedef typename Base::Split_2 Split_2;
|
|
typedef typename Base::Intersect_2 Intersect_2;
|
|
typedef typename Base::Are_mergeable_2 Are_mergeable_2;
|
|
typedef typename Base::Merge_2 Merge_2;
|
|
|
|
typedef typename Base::Number_of_points_2 Number_of_points_2;
|
|
typedef typename Base::Trim_2 Trim_2;
|
|
|
|
//@}
|
|
|
|
public:
|
|
/*! Construct default. */
|
|
Arr_polyline_traits_2() : Base() {}
|
|
|
|
/*! Construct from a segment traits
|
|
* \param geom_traits an already existing segment tarits which is passed will
|
|
* be used by the class.
|
|
*/
|
|
Arr_polyline_traits_2(const Segment_traits_2* geom_traits) :
|
|
Base(geom_traits)
|
|
{}
|
|
|
|
/// \name Types and functors defined here.
|
|
//@{
|
|
|
|
/* Functor to augment a polyline by either adding a vertex or a segment
|
|
* at the back.
|
|
*/
|
|
class Push_back_2 : public Base::Push_back_2 {
|
|
protected:
|
|
typedef Arr_polyline_traits_2<Segment_traits_2> Polyline_traits_2;
|
|
|
|
public:
|
|
/*! Constructor. */
|
|
Push_back_2(const Polyline_traits_2& traits) :
|
|
Base::Push_back_2(traits)
|
|
{}
|
|
|
|
// Normally, the moment the compiler finds a name, it stops looking. In
|
|
// other words, the compiler first finds the operator() in the current
|
|
// class and stops looking, never finding the one in the base class.
|
|
// Explicitly bring the base operator() into scope, unnecesitating the
|
|
// code below.
|
|
using Base::Push_back_2::operator();
|
|
|
|
// /*! Append a segment `seg` to an existing polyline `cv` at the back. */
|
|
// void operator()(Curve_2& cv, const Segment_2& seg) const
|
|
// { Base::Push_back_2::operator() (cv, seg); }
|
|
|
|
// /* Append a segment `seg` to an existing polyline `xcv` at the back. */
|
|
// void operator()(X_monotone_curve_2& xcv,
|
|
// const X_monotone_subcurve_2& seg) const
|
|
// { Base::Push_back_2::operator()(xcv, seg); }
|
|
|
|
/* Append a point `p` to an existing polyline `cv` at the back. */
|
|
void operator()(Curve_2& cv, const Point_2& p) const
|
|
{
|
|
typedef typename Curve_2::size_type size_type;
|
|
size_type num_seg = cv.number_of_subcurves();
|
|
CGAL_precondition(num_seg > 0);
|
|
int last_seg = num_seg-1;
|
|
|
|
const Segment_traits_2* seg_traits =
|
|
this->m_poly_traits.subcurve_traits_2();
|
|
typename Segment_traits_2::Compare_endpoints_xy_2 cmp_seg_endpts =
|
|
seg_traits->compare_endpoints_xy_2_object();
|
|
|
|
/* Since it is desired to maintain `cv` well-oriented, we have
|
|
* to append the segment [cv[last_seg].target(),p]. The
|
|
* following test determines which end of the last segment is
|
|
* the target, i.e. the actual end of `cv`.
|
|
*/
|
|
if (cmp_seg_endpts(cv[last_seg]) == SMALLER) {
|
|
typename Segment_traits_2::Construct_max_vertex_2 get_max_v =
|
|
seg_traits->construct_max_vertex_2_object();
|
|
cv.push_back(Subcurve_2(get_max_v(cv[last_seg]), p));
|
|
}
|
|
else {
|
|
typename Segment_traits_2::Construct_min_vertex_2 get_min_v =
|
|
seg_traits->construct_min_vertex_2_object();
|
|
cv.push_back(Subcurve_2(get_min_v(cv[last_seg]), p));
|
|
}
|
|
}
|
|
|
|
/* Append a point `p` to an existing polyline `xcv` at the back. */
|
|
void operator()(X_monotone_curve_2& xcv, const Point_2& p) const
|
|
{
|
|
typedef typename X_monotone_curve_2::size_type size_type;
|
|
size_type num_seg = xcv.number_of_subcurves();
|
|
CGAL_precondition(num_seg > 0);
|
|
|
|
const Segment_traits_2* seg_traits =
|
|
this->m_poly_traits.subcurves_traits_2();
|
|
CGAL_precondition_code
|
|
(
|
|
typename Segment_traits_2::Compare_x_2 comp_x =
|
|
seg_traits->compare_x_2_object();
|
|
typename Segment_traits_2::Compare_xy_2 comp_xy =
|
|
seg_traits->compare_xy_2_object();
|
|
typename Base::Is_vertical_2 is_vertical =
|
|
this->m_poly_traits.is_vertical_2_object();
|
|
);
|
|
|
|
if (seg_traits->compare_endpoints_xy_2_object()(xcv[0]) == SMALLER) {
|
|
// xcv is oriented left-to-right
|
|
typename Segment_traits_2::Construct_max_vertex_2 get_max_v =
|
|
seg_traits->construct_max_vertex_2_object();
|
|
CGAL_precondition
|
|
(
|
|
(!is_vertical(xcv) &&
|
|
(comp_x(get_max_v(xcv[num_seg-1]), p) == SMALLER)) ||
|
|
(is_vertical(xcv) &&
|
|
(comp_x(get_max_v(xcv[num_seg-1]), p) == EQUAL) &&
|
|
(comp_xy(get_max_v(xcv[num_seg-1]), p) == SMALLER))
|
|
);
|
|
xcv.push_back(X_monotone_subcurve_2(get_max_v(xcv[num_seg-1]), p));
|
|
}
|
|
else {
|
|
// xcv is oriented right-to-left
|
|
typename Segment_traits_2::Construct_min_vertex_2 get_min_v =
|
|
seg_traits->construct_min_vertex_2_object();
|
|
CGAL_precondition
|
|
(
|
|
(!is_vertical(xcv) &&
|
|
(comp_x(get_min_v(xcv[num_seg-1]), p) == LARGER)) ||
|
|
(is_vertical(xcv) &&
|
|
(comp_x(get_min_v(xcv[num_seg-1]), p) == EQUAL) &&
|
|
(comp_xy(get_min_v(xcv[num_seg-1]), p) == LARGER))
|
|
);
|
|
xcv.push_back(X_monotone_subcurve_2(get_min_v(xcv[num_seg-1]), p));
|
|
}
|
|
}
|
|
};
|
|
|
|
/*! Obtain a Push_back_2 functor object. */
|
|
Push_back_2 push_back_2_object() const { return Push_back_2(*this); }
|
|
|
|
/* Functor to augment a polyline by either adding a vertex or a segment
|
|
* at the front.
|
|
* TODO: Test all the operator()'s. (Don't forget vertical cases!)
|
|
*/
|
|
class Push_front_2 : public Base::Push_front_2 {
|
|
protected:
|
|
typedef Arr_polyline_traits_2<Segment_traits_2> Polyline_traits_2;
|
|
|
|
public:
|
|
/*! Constructor. */
|
|
Push_front_2(const Polyline_traits_2& traits) :
|
|
Base::Push_front_2(traits)
|
|
{}
|
|
|
|
// Normally, the moment the compiler finds a name, it stops looking. In
|
|
// other words, the compiler first finds the operator() in the current
|
|
// class and stops looking, never finding the one in the base class.
|
|
// Explicitly bring the base operator() into scope, unnecesitating the
|
|
// code below.
|
|
using Base::Push_front_2::operator();
|
|
|
|
// /*! Append a segment `seg` to an existing polyline `cv` at the front. */
|
|
// void operator()(Curve_2& cv, const Subcurve_2& seg) const
|
|
// { Base::Push_front_2::operator()(cv, seg); }
|
|
|
|
// /*! Append a segment `seg` to an existing polyline `xcv` at the front. */
|
|
// void operator()(X_monotone_curve_2& xcv,
|
|
// const X_monotone_subcurve_2& seg) const
|
|
// { Base::Push_front_2::operator()(xcv, seg); }
|
|
|
|
/* Append a point `p` to an existing polyline `cv` at the front. */
|
|
void operator()(Curve_2& cv, const Point_2& p) const
|
|
{
|
|
CGAL_precondition_code
|
|
(
|
|
typedef typename Curve_2::size_type size_type;
|
|
size_type num_seg = cv.number_of_subcurves();
|
|
);
|
|
CGAL_precondition(num_seg > 0);
|
|
|
|
const Segment_traits_2* geom_traits =
|
|
this->m_poly_traits.subcurve_traits_2();
|
|
typename Segment_traits_2::Compare_endpoints_xy_2 cmp_seg_endpts =
|
|
geom_traits->compare_endpoints_xy_2_object();
|
|
|
|
if (cmp_seg_endpts(cv[0]) == SMALLER) {
|
|
typename Segment_traits_2::Construct_min_vertex_2 get_min_v =
|
|
geom_traits->construct_min_vertex_2_object();
|
|
cv.push_front(Subcurve_2(p, get_min_v(cv[0])));
|
|
}
|
|
else {
|
|
typename Segment_traits_2::Construct_max_vertex_2 get_max_v =
|
|
geom_traits->construct_max_vertex_2_object();
|
|
cv.push_front(Subcurve_2(p, get_max_v(cv[0])));
|
|
}
|
|
}
|
|
|
|
/*! Append a point `p` to an existing polyline `xcv` at the front. */
|
|
void operator()(const X_monotone_curve_2& xcv, Point_2& p) const
|
|
{
|
|
const Segment_traits_2* geom_traits =
|
|
this->m_poly_traits.subcurve_traits_2();
|
|
CGAL_precondition_code
|
|
(
|
|
typedef typename X_monotone_curve_2::size_type size_type;
|
|
size_type num_seg = xcv.number_of_subcurves();
|
|
typename Segment_traits_2::Compare_x_2 comp_x =
|
|
geom_traits->compare_x_2_object();
|
|
typename Segment_traits_2::Compare_xy_2 comp_xy =
|
|
geom_traits->compare_xy_2_object();
|
|
typename Base::Is_vertical_2 is_vertical =
|
|
this->m_poly_traits.is_vertical_2_object();
|
|
);
|
|
CGAL_precondition(num_seg > 0);
|
|
|
|
if (geom_traits->compare_endpoints_xy_2_object()(xcv[0]) == SMALLER) {
|
|
// xcv is oriented left-to-right
|
|
typename Segment_traits_2::Construct_max_vertex_2 get_max_v =
|
|
geom_traits->construct_max_vertex_2_object();
|
|
CGAL_precondition
|
|
(
|
|
(!is_vertical(xcv) &&
|
|
(comp_x(get_max_v(xcv[0]), p) == LARGER)) ||
|
|
(is_vertical(xcv) &&
|
|
(comp_x(get_max_v(xcv[0]), p) == EQUAL) &&
|
|
(comp_xy(get_max_v(xcv[0]), p) == LARGER))
|
|
);
|
|
xcv.push_front(X_monotone_subcurve_2(p, get_max_v(xcv[0])));
|
|
}
|
|
else {
|
|
// xcv is oriented right-to-left
|
|
typename Segment_traits_2::Construct_min_vertex_2 get_min_v =
|
|
geom_traits->construct_min_vertex_2_object();
|
|
CGAL_precondition
|
|
(
|
|
(!is_vertical(xcv) &&
|
|
(comp_x(get_min_v(xcv[0]), p) == SMALLER)) ||
|
|
(is_vertical(xcv) &&
|
|
(comp_x(get_min_v(xcv[0]), p) == EQUAL) &&
|
|
(comp_xy(get_min_v(xcv[0]), p) == SMALLER))
|
|
);
|
|
xcv.push_front(X_monotone_subcurve_2(p, get_min_v(xcv[0])));
|
|
}
|
|
}
|
|
};
|
|
|
|
/*! Obtain a Push_front_2 functor object. */
|
|
Push_front_2 push_front_2_object() const { return Push_front_2(*this); }
|
|
|
|
/*! Construct a general curve. */
|
|
class Construct_curve_2 : public Base::Construct_curve_2 {
|
|
protected:
|
|
typedef Arr_polyline_traits_2<Segment_traits_2> Polyline_traits_2;
|
|
|
|
public:
|
|
/*! Constructor.
|
|
*/
|
|
Construct_curve_2(const Polyline_traits_2& traits) :
|
|
Base::Construct_curve_2(traits)
|
|
{}
|
|
|
|
/* Obtain an polyline connecting two given endpoints.
|
|
*/
|
|
Curve_2 operator()(const Point_2& p, const Point_2& q) const
|
|
{ return Curve_2(Subcurve_2(p, q)); }
|
|
|
|
/* Obtain a polyline consists of one given segment.
|
|
*/
|
|
Curve_2 operator()(const Subcurve_2& seg) const
|
|
{ return Base::Construct_curve_2::operator()(seg); }
|
|
|
|
/* Construct a well-oriented polyline from a range of either
|
|
* `Segment_traits::Point_2` or `Segment_traits::Subcurve_2`.
|
|
*/
|
|
template <typename ForwardIterator>
|
|
Curve_2 operator()(ForwardIterator begin, ForwardIterator end) const
|
|
{
|
|
typedef typename std::iterator_traits<ForwardIterator>::value_type VT;
|
|
typedef typename boost::is_same<VT, Point_2>::type Is_point;
|
|
// Dispatch the range to the appropriate implementation.
|
|
return constructor_impl(begin, end, Is_point());
|
|
}
|
|
|
|
/*! Construction implementation from a range of segments.
|
|
* Note that the segments in the range are NOT necessarily x-monotone,
|
|
* thus it is impossible to test (even in precondition) whether the input
|
|
* forms a continuous and well oriented polyline.
|
|
* \pre Range should contain at least one segment.
|
|
*/
|
|
template <typename ForwardIterator>
|
|
Curve_2 constructor_impl(ForwardIterator begin, ForwardIterator end,
|
|
boost::false_type) const
|
|
{ return Base::Construct_curve_2::operator()(begin, end); }
|
|
|
|
/*! Construction of a polyline from a range of points.
|
|
* \pre The range contains at least two points
|
|
* \pre Consecutive points are disjoint.
|
|
* \return Well-oriented polyline connecting the given points. The order
|
|
* of the vertices is determined by their order in the range.
|
|
* Furthermore, the orientation of the polyline is induced by
|
|
* their order.
|
|
*/
|
|
template <typename ForwardIterator>
|
|
Curve_2 constructor_impl(ForwardIterator begin, ForwardIterator end,
|
|
boost::true_type) const
|
|
{
|
|
// The range must contain at least two points.
|
|
CGAL_precondition_msg(std::distance(begin, end) > 1,
|
|
"Range of points must contain at least 2 points");
|
|
|
|
// Container of the segments to be constructed from the range of points
|
|
std::list<Subcurve_2> segs;
|
|
|
|
CGAL_precondition_code
|
|
(
|
|
typename Segment_traits_2::Equal_2 equal =
|
|
this->m_poly_traits.subcurve_traits_2()->equal_2_object();
|
|
);
|
|
|
|
// Check whether there are no points in the range:
|
|
ForwardIterator next = begin;
|
|
ForwardIterator curr = next++;
|
|
|
|
// Construct a segment from each two adjacent points.
|
|
Curve_2 cv;
|
|
while (next != end) {
|
|
CGAL_precondition_msg(!equal(*curr,*next),
|
|
"Cannot construct a degenerated segment");
|
|
segs.push_back(Subcurve_2(*curr, *next));
|
|
curr = next++;
|
|
}
|
|
|
|
return operator()(segs.begin(), segs.end());
|
|
}
|
|
};
|
|
|
|
/*! Obtain a Construct_curve_2 functor object. */
|
|
Construct_curve_2 construct_curve_2_object() const
|
|
{ return Construct_curve_2(*this); }
|
|
|
|
/*! Construct an x-monotone curve. */
|
|
class Construct_x_monotone_curve_2 :
|
|
public Base::Construct_x_monotone_curve_2
|
|
{
|
|
protected:
|
|
typedef Arr_polyline_traits_2<Segment_traits_2> Polyline_traits_2;
|
|
|
|
public:
|
|
/*! Constructor.
|
|
*/
|
|
Construct_x_monotone_curve_2(const Polyline_traits_2& traits) :
|
|
Base::Construct_x_monotone_curve_2(traits)
|
|
{}
|
|
|
|
/*! Obtain an x-monotone polyline connecting 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
|
|
{
|
|
CGAL_precondition_msg
|
|
(!this->m_poly_traits.subcurve_traits_2()->equal_2_object()(p,q),
|
|
"Cannot construct a degenerated segment as a polyline");
|
|
X_monotone_subcurve_2 seg = this->m_poly_traits.subcurve_traits_2()->
|
|
construct_x_monotone_curve_2_object()(p, q);
|
|
|
|
#ifdef CGAL_ALWAYS_LEFT_TO_RIGHT
|
|
if (this->m_poly_traits.subcurve_traits_2()->compare_xy_2_object()(p,q) ==
|
|
LARGER)
|
|
seg = this->m_poly_traits.subcurve_traits_2()->
|
|
construct_opposite_2_object()(seg);
|
|
#endif
|
|
|
|
return X_monotone_curve_2(seg);
|
|
}
|
|
|
|
/*! Obtain an x-monotone polyline that consists of one given segment.
|
|
* \param seg input segment.
|
|
* \pre seg is not degenerated.
|
|
* \return An x-monotone polyline with one segment.
|
|
*/
|
|
X_monotone_curve_2 operator()(const X_monotone_subcurve_2& seg) const
|
|
{ return Base::Construct_x_monotone_curve_2::operator()(seg); }
|
|
|
|
/*! Construct an x-monotone polyline from a range of elements.
|
|
* \pre Range should from a continuous well-oriented x-monotone polyline.
|
|
*/
|
|
template <typename ForwardIterator>
|
|
X_monotone_curve_2 operator()(ForwardIterator begin, ForwardIterator end)
|
|
const
|
|
{
|
|
typedef typename std::iterator_traits<ForwardIterator>::value_type VT;
|
|
typedef typename boost::is_same<VT, Point_2>::type Is_point;
|
|
// Dispatch the range to the appropriate implementation.
|
|
return constructor_impl(begin, end, Is_point());
|
|
}
|
|
|
|
/*! Construction implementation from a range of segments.
|
|
* \param begin An iterator pointing to the first segment in the range.
|
|
* \param end An iterator pointing to the past-the-end segment
|
|
* in the range.
|
|
* \pre The range contains at least one segment.
|
|
* \pre Segments correspond to a well-oriented polyline. That
|
|
* is, the target of the i-th segment is an source of the
|
|
* (i+1)th segment.
|
|
* \pre The sequence of segments in the range forms a weak x-monotone
|
|
* polyline.
|
|
* \pre The container should support bidirectional iteration.
|
|
* \return A continuous, well-oriented x-monotone polyline which
|
|
* is directed either left-to-right or right-to-left
|
|
* depending on the segments in the input.
|
|
*/
|
|
template <typename ForwardIterator>
|
|
X_monotone_curve_2 constructor_impl(ForwardIterator begin,
|
|
ForwardIterator end,
|
|
boost::false_type) const
|
|
{ return Base::Construct_x_monotone_curve_2::operator()(begin, end); }
|
|
|
|
/*! Construction of an x-monotone polyline from a range of points.
|
|
* The polyline may be oriented left-to-right or right-to-left
|
|
* depending on the lexicographical order of the points in the
|
|
* input.
|
|
* \pre Range contains at least two points.
|
|
* \pre No two consecutive points are the same.
|
|
* \pre The points form an continuous well-oriented x-monotone polyline.
|
|
* \post By the construction the returned polyline is well-oriented.
|
|
*/
|
|
template <typename ForwardIterator>
|
|
X_monotone_curve_2 constructor_impl(ForwardIterator begin,
|
|
ForwardIterator end,
|
|
boost::true_type) const
|
|
{
|
|
// The range must contain at least two points.
|
|
CGAL_precondition_msg(std::distance(begin, end) > 1,
|
|
"Range of points must contain at least 2 points");
|
|
|
|
// Container of the segments to be constructed from the range of points
|
|
std::list<X_monotone_subcurve_2> segs;
|
|
// Make sure the range of points contains at least two points.
|
|
ForwardIterator next = begin;
|
|
ForwardIterator curr = next++;
|
|
|
|
CGAL_precondition_code
|
|
(
|
|
const Segment_traits_2* geom_traits =
|
|
this->m_poly_traits.subcurve_traits_2();
|
|
// Initialize two comparison functors
|
|
typename Segment_traits_2::Compare_x_2 compare_x =
|
|
geom_traits->compare_x_2_object();
|
|
typename Segment_traits_2::Compare_xy_2 compare_xy =
|
|
geom_traits->compare_xy_2_object();
|
|
// Make sure there is no changed of directions.
|
|
// Saves the comp_x between the first two points
|
|
const Comparison_result cmp_x_res = compare_x(*curr, *next);
|
|
// Save the comp_xy between the first two points
|
|
const Comparison_result cmp_xy_res = compare_xy(*curr, *next);
|
|
);
|
|
|
|
// Assure that the first two points are not the same.
|
|
// Note that this also assures that non of the consecutive
|
|
// points are equal in the whole range.
|
|
CGAL_precondition(cmp_xy_res != EQUAL);
|
|
|
|
while (next != end) {
|
|
CGAL_precondition(compare_xy(*curr, *next) == cmp_xy_res);
|
|
CGAL_precondition(compare_x(*curr, *next) == cmp_x_res);
|
|
|
|
segs.push_back(X_monotone_subcurve_2(*curr, *next));
|
|
curr = next++;
|
|
}
|
|
|
|
#ifdef CGAL_ALWAYS_LEFT_TO_RIGHT
|
|
if (this->m_poly_traits.subcurve_traits_2()->
|
|
compare_endpoints_xy_2_object()(*segs.begin()) == LARGER)
|
|
{
|
|
X_monotone_curve_2 xcv(segs.begin(), segs.end());
|
|
return this->m_poly_traits.construct_opposite_2_object()(xcv);
|
|
}
|
|
#endif
|
|
|
|
return operator()(segs.begin(), segs.end());
|
|
}
|
|
};
|
|
|
|
/*! Obtain 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(*this); }
|
|
|
|
/*! Deprecated!
|
|
* Obtain the segment traits.
|
|
* \return the segment traits.
|
|
*/
|
|
CGAL_DEPRECATED const Segment_traits_2* segment_traits_2() const
|
|
{ return this->subcurve_traits_2(); }
|
|
};
|
|
|
|
} // namespace CGAL
|
|
|
|
#include <CGAL/enable_warnings.h>
|
|
|
|
#endif
|