// Copyright (c) 2006,2007,2009,2010,2011 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/Arrangement_zone_2.h $ // $Id: Arrangement_zone_2.h 58276ed 2020-03-31T18:34:28+03:00 Efi Fogel // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // // Author(s): Ron Wein // Efi Fogel // (based on old version by Eyal Flato) #ifndef CGAL_ARRANGEMENT_ZONE_2_H #define CGAL_ARRANGEMENT_ZONE_2_H #include #include /*! \file * Defintion of the Arrangement_zone_2 class. */ #include #include #include #include #include #include #include namespace CGAL { /*! \class * A class for computing the zone of a given $x$-monotone curve in a given * arrangement. * The arrangement parameter corresponds to the underlying arrangement, and * the zone-visitor parameter corresponds to a visitor class which is capable * of receiving notifications on the arrangment features the query curve * traverses. The visitor has to support the following functions: * - init(), for initializing the visitor with a given arrangement. * - found_subcurve(), called when a non-intersecting x-monotone curve is * computed and located in the arrangement. * - found_overlap(), called when an x-monotone curve overlaps an existing * halfedge in the arrangement. * Both the second and the third functions return pair, * where the halfedge handle corresponds to the halfedge created or modified * by the visitor (if valid), and the Boolean value indicates whether we * should halt the zone-computation process. */ template class Arrangement_zone_2 { public: typedef Arrangement_ Arrangement_2; typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; typedef typename Arrangement_2::Topology_traits Topology_traits; protected: typedef Arr_traits_adaptor_2 Traits_adaptor_2; typedef typename Traits_adaptor_2::Left_side_category Left_side_category; typedef typename Traits_adaptor_2::Bottom_side_category Bottom_side_category; typedef typename Traits_adaptor_2::Top_side_category Top_side_category; typedef typename Traits_adaptor_2::Right_side_category Right_side_category; BOOST_MPL_ASSERT ((typename Arr_sane_identified_tagging::result)); public: typedef ZoneVisitor_ Visitor; typedef typename Arrangement_2::Vertex_handle Vertex_handle; typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; typedef typename Arrangement_2::Face_handle Face_handle; typedef std::pair Visitor_result; typedef typename Geometry_traits_2::Point_2 Point_2; typedef typename Geometry_traits_2::X_monotone_curve_2 X_monotone_curve_2; typedef typename Geometry_traits_2::Multiplicity Multiplicity; protected: typedef typename Arr_are_all_sides_oblivious_tag::result Are_all_sides_oblivious_category; typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; typedef typename Arrangement_2::Face_const_handle Face_const_handle; typedef typename Arrangement_2::Ccb_halfedge_circulator Ccb_halfedge_circulator; // Types used for caching intersection points: typedef std::pair Intersection_point; typedef boost::variant Intersection_result; typedef boost::optional Optional_intersection; typedef std::list Intersect_list; typedef std::map Intersect_map; typedef typename Intersect_map::iterator Intersect_map_iterator; typedef std::set Curves_set; typedef typename Curves_set::iterator Curves_set_iterator; // Data members: Arrangement_2& m_arr; // The associated arrangement. const Traits_adaptor_2* m_geom_traits; // Its associated geometry traits. Arr_accessor m_arr_access; // An accessor for the arrangement. Visitor* m_visitor; // The zone visitor. Intersect_map m_inter_map; // Stores all computed intersections. const Vertex_handle m_invalid_v; // An invalid vertex handle. const Halfedge_handle m_invalid_he; // An invalid halfedge handle. X_monotone_curve_2 m_cv; // The current portion of the // inserted curve. CGAL::Object m_obj; // The location of the left endpoint. bool m_has_left_pt; // Is the left end of the curve bounded. bool m_left_on_boundary; // Is the left point on the boundary. Point_2 m_left_pt; // Its current left endpoint. bool m_has_right_pt; // Is the right end of the curve bounded. bool m_right_on_boundary; // Is the right point on the boundary. Point_2 m_right_pt; // Its right endpoint (if bounded). Vertex_handle m_left_v; // The arrangement vertex associated // with the current left_pt (if any). Halfedge_handle m_left_he; // If left_v is valid, left_he is the // predecessor for cv around this // vertex. Otherwise, if it is valid, // it is the halfedge that contains // the left endpoint it its interior. Vertex_handle m_right_v; // The arrangement vertex associated // with the current m_right_pt (if any). Halfedge_handle m_right_he; // If m_right_v is valid, left_he is the // predecessor for cv around this // vertex. Otherwise, if it is valid, // it is the halfedge that contains // the right endpoint it its interior. Point_2 m_intersect_p; // The next intersection point. unsigned int m_ip_multiplicity; // Its multiplicity // (0 in case of an overlap). bool m_found_intersect; // An intersection has been found. // (or an overlap). X_monotone_curve_2 m_overlap_cv; // The currently discovered overlap. bool m_found_overlap; // An overlap has been found. bool m_found_iso_vert; // Check whether an isolated vertex // induces the next intersection. Vertex_handle m_intersect_v; // The vertex that intersects cv. Halfedge_handle m_intersect_he; // The halfedge that intersects cv // (or overlaps it). X_monotone_curve_2 m_sub_cv1; // Auxiliary variable (for curve split). X_monotone_curve_2 m_sub_cv2; // Auxiliary variable (for curve split). public: /*! Constructor. * \param _arr The arrangement for which we compute the zone. * \param _visitor A pointer to a zone-visitor object. */ Arrangement_zone_2(Arrangement_2& arr, Visitor* visitor) : m_arr(arr), m_arr_access(arr), m_visitor(visitor), m_invalid_v(), m_invalid_he() { m_geom_traits = static_cast(arr.geometry_traits()); CGAL_assertion(visitor != nullptr); // Initialize the visitor. visitor->init(&arr); } /*! Initialize the zone-computation process with a given curve. * \param _cv The query curve. * \param pl A point-location object associated with the arrangement. */ template void init(const X_monotone_curve_2& cv, const PointLocation& pl) { // Set the curve and check whether its left end has boundary conditions. m_cv = cv; const Arr_parameter_space bx1 = m_geom_traits->parameter_space_in_x_2_object()(m_cv, ARR_MIN_END); const Arr_parameter_space by1 = m_geom_traits->parameter_space_in_y_2_object()(m_cv, ARR_MIN_END); if (bx1 == ARR_INTERIOR && by1 == ARR_INTERIOR) { // The curve has a finite left endpoint with no boundary conditions: // locate it in the arrangement. m_has_left_pt = true; m_left_on_boundary = (bx1 != ARR_INTERIOR || by1 != ARR_INTERIOR); m_left_pt = m_geom_traits->construct_min_vertex_2_object()(m_cv); m_obj = pl.locate(m_left_pt); } else { // The left end of the curve has boundary conditions: use the topology // traits use the arrangement accessor to locate it. // Note that if the curve-end is unbounded, m_left_pt does not exist. // Note that if the curve-end is unbounded, m_left_pt does not exist. m_has_left_pt = m_geom_traits->is_closed_2_object()(m_cv, ARR_MIN_END); m_left_on_boundary = true; if (m_has_left_pt) m_left_pt = m_geom_traits->construct_min_vertex_2_object()(m_cv); m_obj = m_arr_access.locate_curve_end(m_cv, ARR_MIN_END, bx1, by1); } // Check the boundary conditions of th right curve end. if (m_geom_traits->is_closed_2_object()(m_cv, ARR_MAX_END)) { const Arr_parameter_space bx2 = m_geom_traits->parameter_space_in_x_2_object()(m_cv, ARR_MAX_END); const Arr_parameter_space by2 = m_geom_traits->parameter_space_in_y_2_object()(m_cv, ARR_MAX_END); // The right endpoint is valid. m_has_right_pt = true; m_right_pt = m_geom_traits->construct_max_vertex_2_object()(m_cv); m_right_on_boundary = (bx2 != ARR_INTERIOR) || (by2 != ARR_INTERIOR); } else { // The right end of the curve lies at infinity. m_has_right_pt = false; m_right_on_boundary = true; } } /*! Initialize the zone-computation process with a given curve and an object * that wraps the location of the curve's left end. * \param cv The query curve. * \param obj An object that represents the location of the left end of the * curve. */ void init_with_hint(const X_monotone_curve_2& cv, const Object& obj); /*! Compute the zone of the given curve and issue the apporpriate * notifications for the visitor. */ void compute_zone(); private: /*! Check whether two curves with a common endpoint overlap. * \pre p == min_point(cv1) * \pre p == min_point(cv2) * \todo move this function to a more accessible place so that it can be reused */ bool do_overlap(const X_monotone_curve_2& cv1, const X_monotone_curve_2& cv2, const Point_2& p) const { return do_overlap_impl(cv1, cv2, p, Are_all_sides_oblivious_category()); } /*! Check whether two curves with a common min endpoint overlap. */ bool do_overlap_impl(const X_monotone_curve_2& cv1, const X_monotone_curve_2& cv2, const Point_2& p, Arr_all_sides_oblivious_tag) const { return m_geom_traits->compare_y_at_x_right_2_object()(cv1, cv2, p) == EQUAL; } /*! Check whether two curves with a common min endpoint overlap. */ bool do_overlap_impl(const X_monotone_curve_2& cv1, const X_monotone_curve_2& cv2, const Point_2& p, Arr_not_all_sides_oblivious_tag) const; /* Check whether the given query curve is encountered when rotating the * first curve in a clockwise direction around a given point until reaching * the second curve. * \pre p == min_point(xcv) * \pre p == min_point(xcv1) * \pre p == min_point(cxv2) * \pre xcv_to_right == TRUE * \todo move this function to a more accessible place so that it can be reused */ bool is_between_cw(const X_monotone_curve_2& xcv, bool xcv_to_right, const X_monotone_curve_2& xcv1, bool xcv1_to_right, const X_monotone_curve_2& xcv2, bool xcv2_to_right, const Point_2& p, bool& xcv_equal_xcv1, bool& xcv_equal_xcv2) const { return is_between_cw_impl(xcv, xcv_to_right, xcv1, xcv1_to_right, xcv2, xcv2_to_right, p, xcv_equal_xcv1, xcv_equal_xcv2, Are_all_sides_oblivious_category()); } /* Check whether the given query curve is encountered when rotating the * first curve in a clockwise direction around a given point until reaching * the second curve. */ bool is_between_cw_impl(const X_monotone_curve_2& xcv, bool xcv_to_right, const X_monotone_curve_2& xcv1, bool xcv1_to_right, const X_monotone_curve_2& xcv2, bool xcv2_to_right, const Point_2& p, bool& xcv_equal_xcv1, bool& xcv_equal_xcv2, Arr_all_sides_oblivious_tag) const { return m_geom_traits->is_between_cw_2_object()(xcv, xcv_to_right, xcv1, xcv1_to_right, xcv2, xcv2_to_right, p, xcv_equal_xcv1, xcv_equal_xcv2); } /* Check whether the given query curve is encountered when rotating the * first curve in a clockwise direction around a given point until reaching * the second curve. */ bool is_between_cw_impl(const X_monotone_curve_2& xcv, bool xcv_to_right, const X_monotone_curve_2& xcv1, bool xcv1_to_right, const X_monotone_curve_2& xcv2, bool xcv2_to_right, const Point_2& p, bool& xcv_equal_xcv1, bool& xcv_equal_xcv2, Arr_not_all_sides_oblivious_tag) const; /*! Find a face containing the query curve m_cv around the given vertex. * In case an overlap occurs, sets m_intersect_he to be the overlapping edge. * \param v The query vertex. * \param he Output: The predecessor of m_cv around the vertex. * \return (true) if m_cv overlaps with the curve associated with he; * (false) if there is no overlap. */ bool _find_prev_around_vertex(Vertex_handle v, Halfedge_handle& he); /*! Direct the halfedge for the location of the given subcurve around a split * point that occurs in the interior of a given edge, when the subcurve lies * to the right of the split point. * In case of overlaps, it sets also m_found_overlap and m_intersect_he. * \param cv_ins The curve to be inserted, whose left endpoint coincides * with the edge to be split. * \param cv_left_pt The left endpoint of cv_ins. * \param query_he The edge that intersects cv_ins. * \pre The left endpoint of cv_ins lies in the interior of the curve * associated with query_he. * \return The halfedge whose incident face contains cv_ins * (either query_he or its twin). */ Halfedge_handle _direct_intersecting_edge_to_right(const X_monotone_curve_2& cv_ins, const Point_2& cv_left_pt, Halfedge_handle query_he); /*! Direct the halfedge for the location of the given subcurve around a split * point that occurs in the interior of a given edge, when the subcurve lies * to the left of the split point. * \param cv_ins The curve to be inserted, whose right endpoint coincides * with the edge to be split. * \param query_he The edge that intersects cv_ins. * \pre The right endpoint of cv_ins lies in the interior of the curve * associated with query_he. * \return The halfedge whose incident face contains cv_ins * (either query_he or its twin). */ Halfedge_handle _direct_intersecting_edge_to_left(const X_monotone_curve_2& cv_ins, Halfedge_handle query_he); /*! Get the next intersection of m_cv with the given halfedge. * \param he A handle to the halfedge. * \param skip_first_point Should we skip the first intersection point. * \param intersect_on_right_boundary Output: If an intersetion point is * computed, marks whether this * point coincides with the right * curve-end, which lies on the * surface boundary. * \return An object representing the next intersection: Intersection_point * in case of a simple intersection point, X_monotone_curve_2 in * case of an overlap, and an empty object if there is no * intersection. */ Optional_intersection _compute_next_intersection(Halfedge_handle he, bool skip_first_point, bool& intersect_on_right_boundary); /*! Remove the next intersection of m_cv with the given halfedge from the map. * \param he A handle to the halfedge. * \pre The list of intersections with the curve of he has already been * computed, and it is not empty. */ void _remove_next_intersection (Halfedge_handle he); /*! Check whether the given point lies completely to the left of the given * egde. * \param p The point. * \param he The halfedge. * \pre he is not a fictitious edge. * \return Whether p lies entirely to the left of the edge. */ bool _is_to_left(const Point_2& p, Halfedge_handle he) const { return (_is_to_left_impl(p, he, Are_all_sides_oblivious_category())); } bool _is_to_left_impl(const Point_2& p, Halfedge_handle he, Arr_all_sides_oblivious_tag) const { return (((he->direction() == ARR_LEFT_TO_RIGHT) && m_geom_traits->compare_xy_2_object() (p, he->source()->point()) == SMALLER) || (he->direction() == ARR_RIGHT_TO_LEFT && m_geom_traits->compare_xy_2_object() (p, he->target()->point()) == SMALLER)); } bool _is_to_left_impl(const Point_2& p, Halfedge_handle he, Arr_not_all_sides_oblivious_tag) const; /*! Check whether the given point lies completely to the right of the given * egde. * \param p The point. * \param he The halfedge. * \pre he is not a fictitious edge. * \return Whether p lies entirely to the right of the edge. */ bool _is_to_right(const Point_2& p, Halfedge_handle he) const { return (_is_to_right_impl(p, he, Are_all_sides_oblivious_category())); } bool _is_to_right_impl(const Point_2& p, Halfedge_handle he, Arr_all_sides_oblivious_tag) const { return (((he->direction() == ARR_LEFT_TO_RIGHT) && m_geom_traits->compare_xy_2_object()(p, he->target()->point()) == LARGER) || ((he->direction() == ARR_RIGHT_TO_LEFT) && m_geom_traits->compare_xy_2_object()(p, he->source()->point()) == LARGER)); } bool _is_to_right_impl(const Point_2& p, Halfedge_handle he, Arr_not_all_sides_oblivious_tag) const; /*! Compute the (lexicographically) leftmost intersection of the query * curve with a given halfedge on the boundary of a face in the arrangement. */ void _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, bool& leftmost_on_right_boundary); /*! Compute the (lexicographically) leftmost intersection of the query * curve with the boundary of a given face in the arrangement. * The function computes sets m_intersect_p, m_intersect_he (or alternatively * m_overlap_cv and m_intersect_he) and set the flags m_found_intersect and * m_found_overlap accordingly. * \param face A handle to the face. * \param on_boundary Specifies whether the left endpoint of the curve lies * on the face boundary. */ void _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary); /*! Compute the zone of an x-monotone curve in a given arrangement face. * The left endpoint of the curve either lies in the face interior or on * the boundary of the face. * This function updates m_cv and its left endpoint and also sets m_left_v * and m_left_he for the remaining portion of the curve. * In case of overlaps, it sets also m_overlap_cv and m_intersect_he. * \param face The given face. * \param on_boundary Specifies whether the left endpoint of the curve lies * on the face boundary. * \pre If on_boundary is (true) then m_left_he must be valid; if it is * (false), then both m_left_v anf m_left_he must be invalid. * \return (true) if we are done with the zone-computation process; * (false) if we still have a remaining portion of m_cv to continue * with. */ bool _zone_in_face(Face_handle face, bool on_boundary); /*! Compute the zone of an overlapping subcurve m_overlap_cv of m_cv and the * curve currently associated with m_intersect_he. * This function updates m_cv and its left endpoint and also sets m_left_v * and m_left_he for the remaining portion of the curve. * \return (true) if we are done with the zone-computation process; * (false) if we still have a remaining portion of m_cv to continue * with. */ bool _zone_in_overlap(); }; } //namespace CGAL // The function definitions can be found under: #include #include #endif