// 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). // // $URL: https://github.com/CGAL/cgal/blob/v5.1/Arrangement_on_surface_2/include/CGAL/Arr_polyline_traits_2.h $ // $Id: Arr_polyline_traits_2.h 254d60f 2019-10-19T15:23:19+02:00 Sébastien Loriot // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // Author(s) : Waqar Khan #ifndef CGAL_ARR_POLYLINE_TRAITS_2_H #define CGAL_ARR_POLYLINE_TRAITS_2_H #include #include /*! \file * The traits-class for the linear piece-wiese(polyline) type of curves of the * arrangement package. */ #include #include #include #include #include #include #include #include #include #include namespace CGAL { // If no template instantiation is provided, it will be instantiated // with Arr_segment_traits. template > class Arr_polyline_traits_2 : public Arr_polycurve_traits_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 Self; typedef Arr_polycurve_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_boundary_2 Compare_x_near_boundary_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 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 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 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 Curve_2 operator()(ForwardIterator begin, ForwardIterator end) const { typedef typename std::iterator_traits::value_type VT; typedef typename boost::is_same::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 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 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 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 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 X_monotone_curve_2 operator()(ForwardIterator begin, ForwardIterator end) const { typedef typename std::iterator_traits::value_type VT; typedef typename boost::is_same::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 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 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 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 #endif