From 4ee8f532b7065e19e10d417591581df8f354c642 Mon Sep 17 00:00:00 2001 From: Simon Giraudot Date: Tue, 21 Jul 2020 09:53:53 +0200 Subject: [PATCH 01/11] Early intersection ending with bbox --- .../include/CGAL/Arr_segment_traits_2.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h index a671a741f80..69ea3c7b6d3 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h @@ -711,6 +711,10 @@ public: typedef boost::variant Intersection_result; + // Early ending with Bbox overlapping test + if (!CGAL::do_overlap(cv1.bbox(), cv2.bbox())) + return oi; + // Intersect the two supporting lines. const Kernel& kernel = m_traits; auto res = kernel.intersect_2_object()(cv1.line(), cv2.line()); @@ -1068,8 +1072,9 @@ public: Bbox_2 bbox() const { Kernel kernel; - Segment_2 seg = kernel.construct_segment_2_object()(this->m_ps, this->m_pt); - return (kernel.construct_bbox_2_object()(seg)); + typename Kernel::Construct_bbox_2 + construct_bbox = kernel.construct_bbox_2_object(); + return construct_bbox(this->m_ps) + construct_bbox(this->m_pt); } /*! Obtain the segment source. From a43b9944251db8a5cf62b270aa7306f1e346947a Mon Sep 17 00:00:00 2001 From: Simon Giraudot Date: Tue, 21 Jul 2020 10:11:05 +0200 Subject: [PATCH 02/11] Use specialized do_intersect + early ending --- .../include/CGAL/Arr_segment_traits_2.h | 66 +++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h index 69ea3c7b6d3..925d4f654a8 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h @@ -715,12 +715,14 @@ public: if (!CGAL::do_overlap(cv1.bbox(), cv2.bbox())) return oi; - // Intersect the two supporting lines. + // Early ending with specialized do_intersect const Kernel& kernel = m_traits; - auto res = kernel.intersect_2_object()(cv1.line(), cv2.line()); + if (!do_intersect (cv1.left(), cv1.right(), cv2.left(), cv2.right(), kernel)) + return oi; - // The supporting line are parallel lines and do not intersect: - if (! res) return oi; + // Intersect the two supporting lines. + auto res = kernel.intersect_2_object()(cv1.line(), cv2.line()); + CGAL_assertion(res); // Check if we have a single intersection point. const Point_2* ip = boost::get(&*res); @@ -787,6 +789,62 @@ public: return oi; } + + // Specialized do_intersect with many tests skipped because at + // this point, we already know which point is left / right for + // both segments + bool do_intersect (const Point_2 &A1, + const Point_2 &A2, + const Point_2 &B1, + const Point_2 &B2, + const Kernel& k) const + { + typename Kernel::Less_xy_2 less_xy; + typename Kernel::Compare_xy_2 compare_xy; + + switch(make_certain(compare_xy(A1,B1))) { + case SMALLER: + switch(make_certain(compare_xy(A2,B1))) { + case SMALLER: + return false; + case EQUAL: + return true; + default: // LARGER + switch(make_certain(compare_xy(A2,B2))) { + case SMALLER: + return CGAL::Intersections::internal + ::seg_seg_do_intersect_crossing(A1,A2,B1,B2, k); + case EQUAL: + return true; + default: // LARGER + return CGAL::Intersections::internal + ::seg_seg_do_intersect_contained(A1,A2,B1,B2, k); + } + } + case EQUAL: + return true; + default: // LARGER + switch(make_certain(compare_xy(B2,A1))) { + case SMALLER: + return false; + case EQUAL: + return true; + default: // LARGER + switch(make_certain(compare_xy(B2,A2))) { + case SMALLER: + return CGAL::Intersections::internal + ::seg_seg_do_intersect_crossing(B1,B2,A1,A2, k); + case EQUAL: + return true; + default: // LARGER + return CGAL::Intersections::internal + ::seg_seg_do_intersect_contained(B1,B2,A1,A2, k); + } + } + } + CGAL_assertion(false); + return false; + } }; /*! Obtain an Intersect_2 functor object. */ From 94155bd89e152f4dcde43e1443f7e02f425e15da Mon Sep 17 00:00:00 2001 From: Simon Giraudot Date: Tue, 21 Jul 2020 11:23:24 +0200 Subject: [PATCH 03/11] Fix assertion with explicit boolean conversion --- Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h index 925d4f654a8..e62c6028a24 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h @@ -722,7 +722,7 @@ public: // Intersect the two supporting lines. auto res = kernel.intersect_2_object()(cv1.line(), cv2.line()); - CGAL_assertion(res); + CGAL_assertion(bool(res)); // Check if we have a single intersection point. const Point_2* ip = boost::get(&*res); From becb663e3936d398713936d22e0a425b2d9fc5f2 Mon Sep 17 00:00:00 2001 From: Simon Giraudot Date: Tue, 21 Jul 2020 11:46:25 +0200 Subject: [PATCH 04/11] Use fast pool allocator --- Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h | 3 ++- .../include/CGAL/Arrangement_on_surface_2.h | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h b/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h index 5a93384baa6..16befc318ee 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h @@ -34,6 +34,7 @@ #include #include +#include namespace CGAL { @@ -876,7 +877,7 @@ public: * The arrangement DCEL class. */ template + class Allocator = boost::fast_pool_allocator > class Arr_dcel_base { public: // Define the vertex, halfedge and face types. diff --git a/Arrangement_on_surface_2/include/CGAL/Arrangement_on_surface_2.h b/Arrangement_on_surface_2/include/CGAL/Arrangement_on_surface_2.h index ddcc1c6229b..5c1c5b36013 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arrangement_on_surface_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arrangement_on_surface_2.h @@ -46,6 +46,8 @@ #include #include +#include + namespace CGAL { /*! \class Arrangement_on_surface_2 @@ -64,7 +66,7 @@ class Arrangement_on_surface_2 { public: typedef GeomTraits_ Geometry_traits_2; typedef TopTraits_ Topology_traits; - typedef CGAL_ALLOCATOR(int) Allocator; + typedef boost::fast_pool_allocator Allocator; // first define adaptor ... typedef Arr_traits_basic_adaptor_2 Traits_adaptor_2; From d309bdf2ca1b2c0135bca73acba9b5676346a0f1 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Tue, 18 Aug 2020 12:16:27 +0300 Subject: [PATCH 05/11] Used ..._object() member function to obtain functor objects and cleaned up formatting. --- .../include/CGAL/Arr_segment_traits_2.h | 85 ++++++++----------- 1 file changed, 36 insertions(+), 49 deletions(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h index e62c6028a24..21c6b43356a 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h @@ -712,12 +712,12 @@ public: Intersection_result; // Early ending with Bbox overlapping test - if (!CGAL::do_overlap(cv1.bbox(), cv2.bbox())) - return oi; + if (! CGAL::do_overlap(cv1.bbox(), cv2.bbox())) return oi; // Early ending with specialized do_intersect const Kernel& kernel = m_traits; - if (!do_intersect (cv1.left(), cv1.right(), cv2.left(), cv2.right(), kernel)) + if (! do_intersect(cv1.left(), cv1.right(), cv2.left(), cv2.right(), + kernel)) return oi; // Intersect the two supporting lines. @@ -793,56 +793,44 @@ public: // Specialized do_intersect with many tests skipped because at // this point, we already know which point is left / right for // both segments - bool do_intersect (const Point_2 &A1, - const Point_2 &A2, - const Point_2 &B1, - const Point_2 &B2, - const Kernel& k) const + bool do_intersect(const Point_2& A1, const Point_2& A2, + const Point_2& B1, const Point_2& B2, + const Kernel& k) const { - typename Kernel::Less_xy_2 less_xy; - typename Kernel::Compare_xy_2 compare_xy; + auto less_xy = k.less_xy_2_object(); + auto compare_xy = k.compare_xy_2_object(); + namespace interx = CGAL::Intersections::internal; switch(make_certain(compare_xy(A1,B1))) { - case SMALLER: - switch(make_certain(compare_xy(A2,B1))) { - case SMALLER: - return false; - case EQUAL: - return true; - default: // LARGER - switch(make_certain(compare_xy(A2,B2))) { - case SMALLER: - return CGAL::Intersections::internal - ::seg_seg_do_intersect_crossing(A1,A2,B1,B2, k); - case EQUAL: - return true; - default: // LARGER - return CGAL::Intersections::internal - ::seg_seg_do_intersect_contained(A1,A2,B1,B2, k); - } + case SMALLER: + switch(make_certain(compare_xy(A2,B1))) { + case SMALLER: return false; + case EQUAL: return true; + default: // LARGER + switch(make_certain(compare_xy(A2,B2))) { + case SMALLER: + return interx::seg_seg_do_intersect_crossing(A1,A2,B1,B2, k); + case EQUAL: return true; + default: // LARGER + return interx::seg_seg_do_intersect_contained(A1,A2,B1,B2, k); } - case EQUAL: - return true; - default: // LARGER - switch(make_certain(compare_xy(B2,A1))) { - case SMALLER: - return false; - case EQUAL: - return true; - default: // LARGER - switch(make_certain(compare_xy(B2,A2))) { - case SMALLER: - return CGAL::Intersections::internal - ::seg_seg_do_intersect_crossing(B1,B2,A1,A2, k); - case EQUAL: - return true; - default: // LARGER - return CGAL::Intersections::internal - ::seg_seg_do_intersect_contained(B1,B2,A1,A2, k); - } + } + case EQUAL: return true; + default: // LARGER + switch(make_certain(compare_xy(B2,A1))) { + case SMALLER: return false; + case EQUAL: return true; + default: // LARGER + switch(make_certain(compare_xy(B2,A2))) { + case SMALLER: + return interx::seg_seg_do_intersect_crossing(B1,B2,A1,A2, k); + case EQUAL: return true; + default: // LARGER + return interx::seg_seg_do_intersect_contained(B1,B2,A1,A2, k); } + } } - CGAL_assertion(false); + CGAL_error(); // never reached return false; } }; @@ -1130,8 +1118,7 @@ public: Bbox_2 bbox() const { Kernel kernel; - typename Kernel::Construct_bbox_2 - construct_bbox = kernel.construct_bbox_2_object(); + auto construct_bbox = kernel.construct_bbox_2_object(); return construct_bbox(this->m_ps) + construct_bbox(this->m_pt); } From ae62039df390d968179a52488d67b325672d6553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 18 Aug 2020 14:08:15 +0200 Subject: [PATCH 06/11] remove used variable --- Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h index 21c6b43356a..da21164610a 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h @@ -797,7 +797,6 @@ public: const Point_2& B1, const Point_2& B2, const Kernel& k) const { - auto less_xy = k.less_xy_2_object(); auto compare_xy = k.compare_xy_2_object(); namespace interx = CGAL::Intersections::internal; From 9d6d9929ec898c7289efabf49ac88d995865eaf2 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 20 Aug 2020 19:53:52 +0300 Subject: [PATCH 07/11] Cleaned up. Moved some operations from the the curve (Arr_segment_2) to the traits and declared the former deprecated. Optimized further the Intersect_2 functor. --- .../include/CGAL/Arr_segment_traits_2.h | 1120 +++++++++++------ 1 file changed, 733 insertions(+), 387 deletions(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h index da21164610a..76a08325fa9 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h @@ -8,8 +8,9 @@ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // Author(s): Ron Wein -// Efi Fogel +// Efi Fogel // Waqar Khan +// Simon Giraudot #ifndef CGAL_ARR_SEGMENT_TRAITS_2_H #define CGAL_ARR_SEGMENT_TRAITS_2_H @@ -26,12 +27,12 @@ #include +#include #include #include #include -#include -#include #include +#include namespace CGAL { @@ -81,211 +82,143 @@ public: typedef typename Kernel::Point_2 Point_2; protected: - Line_2 m_l; // The line that supports the segment. - Point_2 m_ps; // The source point of the segment. - Point_2 m_pt; // The target point of the segment. - bool m_is_pt_max; // Is the target (lexicographically) larger - // than the source. - bool m_is_vert; // Is this a vertical segment. - bool m_is_degen; // Is the segment degenerate (a single point). + Line_2 m_l; // the line that supports the segment. + Point_2 m_ps; // the source point of the segment. + Point_2 m_pt; // the target point of the segment. + bool m_is_directed_right; // is (lexicographically) directed left to right. + bool m_is_vert; // is this a vertical segment. + bool m_is_degen; // is the segment degenerate (a single point). public: - /*! Default constructor. */ - _Segment_cached_2() : m_is_vert(false), m_is_degen(true) {} - /*! Constructor from a segment. - * \param seg The segment. - * \pre The segment is not degenerate. + /// \name Creation + //@{ + + /*! Construct default. */ + _Segment_cached_2(); + + /*! Construct a segment from a Kernel segment. + * \param seg the segment. + * \pre the segment is not degenerate. */ - _Segment_cached_2(const Segment_2& seg) - { - Kernel kernel; - auto construct_vertex = kernel.construct_vertex_2_object(); + _Segment_cached_2(const Segment_2& seg); - m_ps = construct_vertex(seg, 0); - m_pt = construct_vertex(seg, 1); - - Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt); - m_is_degen = (res == EQUAL); - m_is_pt_max = (res == SMALLER); - - CGAL_precondition_msg (! m_is_degen, - "Cannot construct a degenerate segment."); - - m_l = kernel.construct_line_2_object()(seg); - m_is_vert = kernel.is_vertical_2_object()(seg); - } - - /*! Construct a segment from two end-points. - * \param source The source point. - * \param target The target point. - * \param The two points must not be equal. + /*! Construct a segment from two endpoints. + * \param source the source point. + * \param target the target point. + * \param `source` and `target` are not equal. */ - _Segment_cached_2(const Point_2& source, const Point_2& target) : - m_ps(source), - m_pt(target) - { - Kernel kernel; + _Segment_cached_2(const Point_2& source, const Point_2& target); - Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt); - m_is_degen = (res == EQUAL); - m_is_pt_max = (res == SMALLER); - - CGAL_precondition_msg(! m_is_degen, - "Cannot construct a degenerate segment."); - - m_l = kernel.construct_line_2_object()(source, target); - m_is_vert = kernel.is_vertical_2_object()(m_l); - } - - /*! Construct a segment from two end-points on a supporting line. - * \param supp_line The supporting line. - * \param source The source point. - * \param target The target point. - * \pre The two endpoints are not the same and both lie on the given line. + /*! Construct a segment from two endpoints on a supporting line. + * \param line the supporting line. + * \param source the source point. + * \param target the target point. + * \pre `source` and `target` are not equal and both lie on `line`. */ - _Segment_cached_2(const Line_2& supp_line, - const Point_2& source, const Point_2& target) : - m_l(supp_line), - m_ps(source), - m_pt(target) - { - Kernel kernel; + _Segment_cached_2(const Line_2& line, + const Point_2& source, const Point_2& target); - CGAL_precondition - (Segment_assertions::_assert_is_point_on(source, m_l, - Has_exact_division()) && - Segment_assertions::_assert_is_point_on(target, m_l, - Has_exact_division())); + /*! Construct a segment from all fields. + * \param line the supporting line. + * \param source the source point. + * \param target the target point. + * \param is_directed_right is (lexicographically) directed left to right. + * \param is_vert is the segment vertical. + * \param is_degen is the segment degenerate (a single point). + */ + _Segment_cached_2(const Line_2& line, + const Point_2& source, const Point_2& target, + bool is_directed_right, bool is_vert, bool is_degen); - m_is_vert = kernel.is_vertical_2_object()(m_l); - - Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt); - m_is_degen = (res == EQUAL); - m_is_pt_max = (res == SMALLER); - - CGAL_precondition_msg(! m_is_degen, - "Cannot construct a degenerate segment."); - } - - /*! Assignment operator. + /*! Assign. * \param seg the source segment to copy from - * \pre The segment is not degenerate. + * \pre the segment is not degenerate. */ - const _Segment_cached_2& operator=(const Segment_2& seg) - { - Kernel kernel; - auto construct_vertex = kernel.construct_vertex_2_object(); + const _Segment_cached_2& operator=(const Segment_2& seg); - m_ps = construct_vertex(seg, 0); - m_pt = construct_vertex(seg, 1); + //@} - Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt); - m_is_degen = (res == EQUAL); - m_is_pt_max = (res == SMALLER); - - CGAL_precondition_msg(! m_is_degen, - "Cannot construct a degenerate segment."); - - m_l = kernel.construct_line_2_object()(seg); - m_is_vert = kernel.is_vertical_2_object()(seg); - - return (*this); - } - - /*! Obtain the (lexicographically) left endpoint. - */ - const Point_2& left() const { return (m_is_pt_max ? m_ps : m_pt); } - - /*! Set the (lexicographically) left endpoint. - * \param p The point to set. - * \pre p lies on the supporting line to the left of the right endpoint. - */ - void set_left(const Point_2& p) - { - CGAL_precondition(! m_is_degen); - CGAL_precondition_code(Kernel kernel); - CGAL_precondition - (Segment_assertions::_assert_is_point_on(p, m_l, Has_exact_division()) && - (kernel.compare_xy_2_object()(p, right()) == SMALLER)); - - if (m_is_pt_max) m_ps = p; - else m_pt = p; - } - - /*! Obtain the (lexicographically) right endpoint. - */ - const Point_2& right() const { return (m_is_pt_max ? m_pt : m_ps); } - - /*! Set the (lexicographically) right endpoint. - * \param p The point to set. - * \pre p lies on the supporting line to the right of the left endpoint. - */ - void set_right(const Point_2& p) - { - CGAL_precondition(! m_is_degen); - CGAL_precondition_code(Kernel kernel); - CGAL_precondition - (Segment_assertions::_assert_is_point_on(p, m_l, Has_exact_division()) && - (kernel.compare_xy_2_object()(p, left()) == LARGER)); - - if (m_is_pt_max) m_pt = p; - else m_ps = p; - } + /// \name Accessors + //@{ /*! Obtain the supporting line. + * \return the supporting line. */ - const Line_2& line() const - { - CGAL_precondition(! m_is_degen); - return m_l; - } + const Line_2& line() const; + + /*! Obtain the segment source. + * \return the segment source. + */ + const Point_2& source() const; + + /*! Obtain the segment target. + * \return the segment target. + */ + const Point_2& target() const; /*! Determine whether the curve is vertical. + * \return a Boolean flag indicating whether the curve is vertical. */ - bool is_vertical() const - { - CGAL_precondition(! m_is_degen); - return m_is_vert; - } + bool is_vertical() const; - /*! Determine whether the curve is directed lexicographic from left to right + /*! Determine whether the curve is degenerate. + * return a Boolean flag indicating whether the curve is degenerate. */ - bool is_directed_right() const { return (m_is_pt_max); } + bool is_degenerate() const; + + /*! Determine whether the curve is lexicographically directed from left to + * right. + * \return a Boolean flag indicating whether the curve is lexicographically + * directed from left to right. + */ + bool is_directed_right() const; + + /*! Obtain the (lexicographically) left endpoint. + * \return the (lexicographically) left endpoint. + */ + const Point_2& left() const; + + /*! Obtain the (lexicographically) right endpoint. + * \return the (lexicographically) right endpoint. + */ + const Point_2& right() const; + + //@} + + /// \name Modifiers + //@{ + + /*! Set the (lexicographically) left endpoint. + * \param p the point to set. + * \pre p lies on the supporting line to the left of the right endpoint. + */ + void set_left(const Point_2& p); + + /*! Set the (lexicographically) right endpoint. + * \param p the point to set. + * \pre p lies on the supporting line to the right of the left endpoint. + */ + void set_right(const Point_2& p); + + //@} + + /// \name Deprecated + //@{ /*! Determine whether the given point is in the x-range of the segment. - * \param p The query point. + * \param p the query point. * \return (true) is in the x-range of the segment; (false) if it is not. */ - bool is_in_x_range(const Point_2& p) const - { - Kernel kernel; - typename Kernel_::Compare_x_2 compare_x = kernel.compare_x_2_object(); - const Comparison_result res1 = compare_x(p, left()); - - if (res1 == SMALLER) return false; - else if (res1 == EQUAL) return true; - - const Comparison_result res2 = compare_x(p, right()); - return (res2 != LARGER); - } + CGAL_DEPRECATED bool is_in_x_range(const Point_2& p) const; /*! Determine whether the given point is in the y-range of the segment. - * \param p The query point. + * \param p the query point. * \return (true) is in the y-range of the segment; (false) if it is not. */ - bool is_in_y_range(const Point_2& p) const - { - Kernel kernel; - typename Kernel_::Compare_y_2 compare_y = kernel.compare_y_2_object(); - const Comparison_result res1 = compare_y(p, left()); + CGAL_DEPRECATED bool is_in_y_range(const Point_2& p) const; - if (res1 == SMALLER) return false; - else if (res1 == EQUAL) return true; - - const Comparison_result res2 = compare_y(p, right()); - return (res2 != LARGER); - } + //@} }; public: @@ -296,7 +229,7 @@ public: typedef unsigned int Multiplicity; public: - /*! Default constructor. */ + /*! Construct default. */ Arr_segment_traits_2() {} /// \name Basic functor definitions. @@ -306,7 +239,7 @@ public: protected: typedef Arr_segment_traits_2 Traits; - /*! The traits (in case it has state) */ + //! The traits (in case it has state). const Traits& m_traits; /*! Constructor @@ -318,8 +251,8 @@ public: public: /*! Compare the x-coordinates of two points. - * \param p1 The first point. - * \param p2 The second point. + * \param p1 the first point. + * \param p2 the second point. * \return LARGER if x(p1) > x(p2); * SMALLER if x(p1) < x(p2); * EQUAL if x(p1) = x(p2). @@ -350,8 +283,8 @@ public: public: /*! Compare two points lexicographically: by x, then by y. - * \param p1 The first point. - * \param p2 The second point. + * \param p1 the 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); * EQUAL if the two points are equal. @@ -369,8 +302,8 @@ public: class Construct_min_vertex_2 { public: /*! Obtain the left endpoint of the x-monotone curve (segment). - * \param cv The curve. - * \return The left endpoint. + * \param cv the curve. + * \return the left endpoint. */ const Point_2& operator()(const X_monotone_curve_2& cv) const { return (cv.left()); } @@ -383,8 +316,8 @@ public: class Construct_max_vertex_2 { public: /*! Obtain the right endpoint of the x-monotone curve (segment). - * \param cv The curve. - * \return The right endpoint. + * \param cv the curve. + * \return the right endpoint. */ const Point_2& operator()(const X_monotone_curve_2& cv) const { return (cv.right()); } @@ -397,7 +330,7 @@ public: class Is_vertical_2 { public: /*! Check whether the given x-monotone curve is a vertical segment. - * \param cv The curve. + * \param cv the curve. * \return (true) if the curve is a vertical segment; (false) otherwise. */ bool operator()(const X_monotone_curve_2& cv) const @@ -411,7 +344,7 @@ public: protected: typedef Arr_segment_traits_2 Traits; - /*! The traits (in case it has state) */ + /*! the traits (in case it has state) */ const Traits& m_traits; /*! Constructor @@ -423,8 +356,8 @@ public: public: /*! Return the location of the given point with respect to the input curve. - * \param cv The curve. - * \param p The point. + * \param cv the 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; @@ -433,19 +366,19 @@ public: Comparison_result operator()(const Point_2& p, const X_monotone_curve_2& cv) const { - CGAL_precondition(cv.is_in_x_range(p)); + CGAL_precondition(m_traits.is_in_x_range_2_object()(cv, p)); const Kernel& kernel = m_traits; if (! cv.is_vertical()) { - // Compare p with the segment's supporting line. + // Compare p with the segment supporting line. CGAL_assertion_code(auto cmp_x = kernel.compare_x_2_object()); CGAL_assertion(cmp_x(cv.left(), cv.right()) == SMALLER); return kernel.orientation_2_object()(cv.left(), cv.right(), p); } - // Compare with the vertical segment's end-points. - typename Kernel::Compare_y_2 compare_y = kernel.compare_y_2_object(); + // Compare with the vertical segment endpoints. + auto compare_y = kernel.compare_y_2_object(); Comparison_result res1 = compare_y(p, cv.left()); Comparison_result res2 = compare_y(p, cv.right()); return (res1 == res2) ? res1 : EQUAL; @@ -473,12 +406,12 @@ public: public: /*! Compare the y value of two x-monotone curves immediately to the left * 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 + * \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 left. - * \return The relative position of cv1 with respect to cv2 immediately to + * \return the relative position of cv1 with respect to cv2 immediately to * the left of p: SMALLER, LARGER or EQUAL. */ Comparison_result operator()(const X_monotone_curve_2& cv1, @@ -527,12 +460,12 @@ public: public: /*! 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 + * \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 immediately to + * \return the relative position of cv1 with respect to cv2 immediately to * the right of p: SMALLER, LARGER or EQUAL. */ Comparison_result operator()(const X_monotone_curve_2& cv1, @@ -579,8 +512,8 @@ public: public: /*! Check whether the two x-monotone curves are the same (have the same * graph). - * \param cv1 The first curve. - * \param cv2 The second curve. + * \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, @@ -594,8 +527,8 @@ public: } /*! Determine whether the two points are the same. - * \param p1 The first point. - * \param p2 The second point. + * \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 @@ -607,6 +540,7 @@ public: /*! Obtain an Equal_2 functor object. */ Equal_2 equal_2_object() const { return Equal_2(*this); } + //@} /// \name Functor definitions for supporting intersections. @@ -617,9 +551,9 @@ public: /*! 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 variant<.... - * \return The past-the-end iterator. + * \param cv the curve. + * \param oi the output iterator, whose value-type is variant<.... + * \return the past-the-end iterator. */ template OutputIterator operator()(const Curve_2& cv, OutputIterator oi) const @@ -650,11 +584,11 @@ public: 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. + * \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 endpoints. */ void operator()(const X_monotone_curve_2& cv, const Point_2& p, X_monotone_curve_2& c1, X_monotone_curve_2& c2) const @@ -686,21 +620,76 @@ public: /*! The traits (in case it has state) */ const Traits& m_traits; - /*! Constructor + /*! Construct * \param traits the traits (in case it has state) */ Intersect_2(const Traits& traits) : m_traits(traits) {} friend class Arr_segment_traits_2; + // Specialized do_intersect with many tests skipped because at + // this point, we already know which point is left / right for + // both segments + bool do_intersect(const Point_2& A1, const Point_2& A2, + const Point_2& B1, const Point_2& B2) const + { + const Kernel& kernel = m_traits; + auto compare_xy = kernel.compare_xy_2_object(); + namespace interx = CGAL::Intersections::internal; + + switch(make_certain(compare_xy(A1,B1))) { + case SMALLER: + switch(make_certain(compare_xy(A2,B1))) { + case SMALLER: return false; + case EQUAL: return true; + default: // LARGER + switch(make_certain(compare_xy(A2,B2))) { + case SMALLER: + return interx::seg_seg_do_intersect_crossing(A1,A2,B1,B2, kernel); + case EQUAL: return true; + default: // LARGER + return interx::seg_seg_do_intersect_contained(A1,A2,B1,B2, kernel); + } + } + case EQUAL: return true; + default: // LARGER + switch(make_certain(compare_xy(B2,A1))) { + case SMALLER: return false; + case EQUAL: return true; + default: // LARGER + switch(make_certain(compare_xy(B2,A2))) { + case SMALLER: + return interx::seg_seg_do_intersect_crossing(B1,B2,A1,A2, kernel); + case EQUAL: return true; + default: // LARGER + return interx::seg_seg_do_intersect_contained(B1,B2,A1,A2, kernel); + } + } + } + CGAL_error(); // never reached + return false; + } + + /*! Determine whether the bounding boxes of two segments overlap + */ + bool do_overlap(const X_monotone_curve_2& cv1, + const X_monotone_curve_2& cv2) const + { + const Kernel& kernel = m_traits; + auto bbox_ctr = kernel.construct_bbox_2_object(); + auto bbox1 = bbox_ctr(cv1.source()) + bbox_ctr(cv1.target()); + auto bbox2 = bbox_ctr(cv2.source()) + bbox_ctr(cv2.target()); + return CGAL::do_overlap(bbox1, bbox2); + } + public: /*! Find the intersections of the two given curves and insert them into the * given output iterator. As two segments may intersect 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. + * \param cv1 the first curve. + * \param cv2 the second curve. + * \param oi the output iterator. + * \return the past-the-end iterator. */ template OutputIterator operator()(const X_monotone_curve_2& cv1, @@ -712,14 +701,15 @@ public: Intersection_result; // Early ending with Bbox overlapping test - if (! CGAL::do_overlap(cv1.bbox(), cv2.bbox())) return oi; + if (! do_overlap(cv1, cv2)) return oi; // Early ending with specialized do_intersect const Kernel& kernel = m_traits; - if (! do_intersect(cv1.left(), cv1.right(), cv2.left(), cv2.right(), - kernel)) + if (! do_intersect(cv1.left(), cv1.right(), cv2.left(), cv2.right())) return oi; + // An intersection is guaranteed. + // Intersect the two supporting lines. auto res = kernel.intersect_2_object()(cv1.line(), cv2.line()); CGAL_assertion(bool(res)); @@ -727,21 +717,14 @@ public: // Check if we have a single intersection point. const Point_2* ip = boost::get(&*res); if (ip != nullptr) { - // Check if the intersection point ip lies on both segments. - const bool ip_on_cv1 = cv1.is_vertical() ? - cv1.is_in_y_range(*ip) : cv1.is_in_x_range(*ip); - - if (ip_on_cv1) { - const bool ip_on_cv2 = cv2.is_vertical() ? - cv2.is_in_y_range(*ip) : cv2.is_in_x_range(*ip); - - if (ip_on_cv2) { - // Create a pair representing the point with its multiplicity, - // which is always 1 for line segments. - Intersection_point ip_mult(*ip, 1); - *oi++ = Intersection_result(ip_mult); - } - } + CGAL_assertion(cv1.is_vertical() ? + m_traits.is_in_y_range_2_object()(cv1, *ip) : + m_traits.is_in_x_range_2_object()(cv1, *ip)); + CGAL_assertion(cv2.is_vertical() ? + m_traits.is_in_y_range_2_object()(cv2, *ip) : + m_traits.is_in_x_range_2_object()(cv2, *ip)); + Intersection_point ip_mult(*ip, 1); + *oi++ = Intersection_result(ip_mult); return oi; } @@ -750,34 +733,13 @@ public: // rightmost of the two left endpoints and p_r is the leftmost of the // two right endpoints. auto compare_xy = kernel.compare_xy_2_object(); - Point_2 p_l = (compare_xy(cv1.left(), cv2.left()) == SMALLER) ? + const Point_2& p_l = (compare_xy(cv1.left(), cv2.left()) == SMALLER) ? cv2.left() : cv1.left(); - Point_2 p_r = (compare_xy(cv1.right(), cv2.right()) == SMALLER) ? + const Point_2& p_r = (compare_xy(cv1.right(), cv2.right()) == SMALLER) ? cv1.right() : cv2.right(); // Examine the resulting segment. const Comparison_result cmp_res = compare_xy(p_l, p_r); - - if (cmp_res == SMALLER) { - // We have discovered an overlapping segment: - if (cv1.is_directed_right() == cv2.is_directed_right()) { - // cv1 and cv2 have the same directions, maintain this direction - // in the overlap segment - if (cv1.is_directed_right()) { - X_monotone_curve_2 overlap_seg(cv1.line(), p_l, p_r); - *oi++ = Intersection_result(overlap_seg); - return oi; - } - X_monotone_curve_2 overlap_seg(cv1.line(), p_r, p_l); - *oi++ = Intersection_result(overlap_seg); - return oi; - } - // cv1 and cv2 have opposite directions, the overlap segment - // will be directed from left to right - X_monotone_curve_2 overlap_seg(cv1.line(), p_l, p_r); - *oi++ = Intersection_result(overlap_seg); - return oi; - } if (cmp_res == EQUAL) { // The two segment have the same supporting line, but they just share // a common endpoint. Thus we have an intersection point, but we leave @@ -787,50 +749,25 @@ public: return oi; } - return oi; - } - - // Specialized do_intersect with many tests skipped because at - // this point, we already know which point is left / right for - // both segments - bool do_intersect(const Point_2& A1, const Point_2& A2, - const Point_2& B1, const Point_2& B2, - const Kernel& k) const - { - auto compare_xy = k.compare_xy_2_object(); - namespace interx = CGAL::Intersections::internal; - - switch(make_certain(compare_xy(A1,B1))) { - case SMALLER: - switch(make_certain(compare_xy(A2,B1))) { - case SMALLER: return false; - case EQUAL: return true; - default: // LARGER - switch(make_certain(compare_xy(A2,B2))) { - case SMALLER: - return interx::seg_seg_do_intersect_crossing(A1,A2,B1,B2, k); - case EQUAL: return true; - default: // LARGER - return interx::seg_seg_do_intersect_contained(A1,A2,B1,B2, k); - } - } - case EQUAL: return true; - default: // LARGER - switch(make_certain(compare_xy(B2,A1))) { - case SMALLER: return false; - case EQUAL: return true; - default: // LARGER - switch(make_certain(compare_xy(B2,A2))) { - case SMALLER: - return interx::seg_seg_do_intersect_crossing(B1,B2,A1,A2, k); - case EQUAL: return true; - default: // LARGER - return interx::seg_seg_do_intersect_contained(B1,B2,A1,A2, k); - } + CGAL_assertion(cmp_res == SMALLER); + // We have discovered an overlapping segment: + if (cv1.is_directed_right() == cv2.is_directed_right()) { + // cv1 and cv2 have the same directions, maintain this direction + // in the overlap segment + if (cv1.is_directed_right()) { + X_monotone_curve_2 overlap_seg(cv1.line(), p_l, p_r); + *oi++ = Intersection_result(overlap_seg); + return oi; } + X_monotone_curve_2 overlap_seg(cv1.line(), p_r, p_l); + *oi++ = Intersection_result(overlap_seg); + return oi; } - CGAL_error(); // never reached - return false; + // cv1 and cv2 have opposite directions, the overlap segment + // will be directed from left to right + X_monotone_curve_2 overlap_seg(cv1.line(), p_l, p_r); + *oi++ = Intersection_result(overlap_seg); + return oi; } }; @@ -853,8 +790,8 @@ public: public: /*! Check whether it is possible to merge two given x-monotone curves. - * \param cv1 The first curve. - * \param cv2 The second curve. + * \param cv1 the first curve. + * \param cv2 the second curve. * \return (true) if the two curves are mergeable, that is, if they are * supported by the same line; (false) otherwise. * \pre cv1 and cv2 share a common endpoint. @@ -898,10 +835,10 @@ public: 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. + * \param cv1 the first curve. + * \param cv2 the second curve. + * \param c Output: the merged curve. + * \pre the two curves are mergeable. */ void operator()(const X_monotone_curve_2& cv1, const X_monotone_curve_2& cv2, @@ -939,8 +876,8 @@ public: class Approximate_2 { public: /*! Obtain an approximation of a point coordinate. - * \param p The exact point. - * \param i The coordinate index (either 0 or 1). + * \param p the exact point. + * \param i the coordinate index (either 0 or 1). * \pre i is either 0 or 1. * \return An approximation of p's x-coordinate (if i == 0), or an * approximation of p's y-coordinate (if i == 1). @@ -956,20 +893,97 @@ public: Approximate_2 approximate_2_object() const { return Approximate_2(); } class Construct_x_monotone_curve_2 { - public: - /*! Obtain 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. + protected: + typedef Arr_segment_traits_2 Traits; + + //! The traits (in case it has state). + const Traits& m_traits; + + /*! Constructor + * \param traits the traits (in case it has state) */ - X_monotone_curve_2 operator()(const Point_2& p, const Point_2& q) const - { return (X_monotone_curve_2(p, q)); } + Construct_x_monotone_curve_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_segment_traits_2; + + public: + typedef typename Kernel::Segment_2 Segment_2; + + /*! Obtain an x-monotone curve connecting two given endpoints. + * \param source the first point. + * \param target the second point. + * \pre `source` and `target` must not be equal. + * \return a segment connecting `source` and `target`. + */ + X_monotone_curve_2 operator()(const Point_2& source, + const Point_2& target) const + { + const Kernel& kernel = m_traits; + auto line = kernel.construct_line_2_object()(source, target); + Comparison_result res = kernel.compare_xy_2_object()(source, target); + auto is_degen = (res == EQUAL); + auto is_directed_right = (res == SMALLER); + CGAL_precondition_msg(! is_degen, + "Cannot construct a degenerate segment."); + auto is_vert = kernel.is_vertical_2_object()(line); + return X_monotone_curve_2(line, source, target, + is_directed_right, is_vert, is_degen); + } + + /*! Obtain an \f$x\f$-monotone curve given a Kernel segment. + * \param seg the segment. + * \return the \f$x\f$-monotone curve. + * \pre the segment is not degenerate. + * \return a segment that is the same as `seg`.. + */ + X_monotone_curve_2 operator()(const Segment_2& seg) const + { + const Kernel& kernel = m_traits; + auto line = kernel.construct_line_2_object()(seg); + auto vertex_ctr = kernel.construct_vertex_2_object(); + auto source = vertex_ctr(seg, 0); + auto target = vertex_ctr(seg, 1); + Comparison_result res = kernel.compare_xy_2_object()(source, target); + auto is_degen = (res == EQUAL); + auto is_directed_right = (res == SMALLER); + CGAL_precondition_msg(! is_degen, + "Cannot construct a degenerate segment."); + auto is_vert = kernel.is_vertical_2_object()(seg); + return X_monotone_curve_2(line, source, target, + is_directed_right, is_vert, is_degen); + } + + /*! Obtain an \f$x\f$-monotone curve given two endpoints and the supporting + * line. + * \param line the supporting line. + * \param the source point. + * \param the target point. + * \pre `ps` and `pt` are not equal and both lie on `line`. + */ + X_monotone_curve_2 operator()(const Line_2& line, + const Point_2& source, + const Point_2& target) const + { + const Kernel& kernel = m_traits; + CGAL_precondition + (Segment_assertions::_assert_is_point_on(source, line, + Has_exact_division()) && + Segment_assertions::_assert_is_point_on(target, line, + Has_exact_division())); + auto is_vert = kernel.is_vertical_2_object()(line); + Comparison_result res = kernel.compare_xy_2_object()(source, target); + auto is_degen = (res == EQUAL); + auto is_directed_right = (res == SMALLER); + CGAL_precondition_msg(! is_degen, + "Cannot construct a degenerate segment."); + return X_monotone_curve_2(line, source, target, + is_directed_right, is_vert, is_degen); + } }; /*! 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(); } + { return Construct_x_monotone_curve_2(*this); } //@} /// \name Functor definitions for the Boolean set-operation traits. @@ -990,10 +1004,10 @@ public: friend class Arr_segment_traits_2; /*! Obtain a trimmed version of a line. - * \param xseg The x-monotone segment. + * \param xseg the x-monotone segment. * \param src the new start endpoint. * \param tgt the new end endpoint. - * \return The trimmed x-monotone segment. + * \return the trimmed x-monotone segment. * \pre src != tgt * \pre both points must lie on segment */ @@ -1031,7 +1045,7 @@ public: public: /*! Compare the endpoints of an $x$-monotone curve lexicographically. * (assuming the curve has a designated source and target points). - * \param cv The curve. + * \param cv the curve. * \return SMALLER if the curve is directed right; * LARGER if the curve is directed left. */ @@ -1046,8 +1060,8 @@ public: class Construct_opposite_2 { public: /*! Construct an opposite x-monotone (with swapped source and target). - * \param cv The curve. - * \return The opposite curve. + * \param cv the curve. + * \return the opposite curve. */ X_monotone_curve_2 operator()(const X_monotone_curve_2& cv) const { return (cv.flip()); } @@ -1057,94 +1071,426 @@ public: Construct_opposite_2 construct_opposite_2_object() const { return Construct_opposite_2(); } //@} + + /// \name Utilities. + //@{ + + class Is_in_x_range_2 { + protected: + typedef Arr_segment_traits_2 Traits; + + //! The traits (in case it has state). + const Traits& m_traits; + + /*! Construct + * \param traits the traits (in case it has state) + */ + Is_in_x_range_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_segment_traits_2; + + public: + /*! Determine whether a given point is in the \f$x\f$-range of a given + * segment. + * \param cv the segment. + * \param p the point. + * \return true if p is in the \f$x\f$-range of cv; false otherwise. + */ + bool operator()(const X_monotone_curve_2& cv, const Point_2& p) const + { + const Kernel& kernel = m_traits; + auto compare_x = kernel.compare_x_2_object(); + Comparison_result res1 = compare_x(p, cv.left()); + + if (res1 == SMALLER) return false; + else if (res1 == EQUAL) return true; + + Comparison_result res2 = compare_x(p, cv.right()); + return (res2 != LARGER); + } + }; + + /*! Obtain an Is_in_x_range_2 functor object */ + Is_in_x_range_2 is_in_x_range_2_object() const + { return Is_in_x_range_2(*this); } + + class Is_in_y_range_2 { + protected: + typedef Arr_segment_traits_2 Traits; + + //! The traits (in case it has state). + const Traits& m_traits; + + /*! Construct + * \param traits the traits (in case it has state) + */ + Is_in_y_range_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_segment_traits_2; + + public: + /*! Determine whether a given point is in the \f$y\f$-range of a given + * segment. + * \param cv the segment. + * \param p the point. + * \return true if p is in the \f$y\f$-range of cv; false otherwise. + */ + bool operator()(const X_monotone_curve_2& cv, const Point_2& p) const + { + const Kernel& kernel = m_traits; + auto compare_y = kernel.compare_y_2_object(); + Comparison_result res1 = compare_y(p, cv.left()); + + if (res1 == SMALLER) return false; + else if (res1 == EQUAL) return true; + + Comparison_result res2 = compare_y(p, cv.right()); + return (res2 != LARGER); + } + }; + + /*! Obtain an Is_in_y_range_2 functor object */ + Is_in_y_range_2 is_in_y_range_2_object() const + { return Is_in_y_range_2(*this); } + + //@} }; +// Creation + +//! \brief constructs default. +template +Arr_segment_traits_2::_Segment_cached_2::_Segment_cached_2() : + m_is_vert(false), + m_is_degen(true) +{} + +//! \brief constructs a segment from a Kernel segment. +template +Arr_segment_traits_2:: +_Segment_cached_2::_Segment_cached_2(const Segment_2& seg) +{ + Kernel kernel; + auto vertex_ctr = kernel.construct_vertex_2_object(); + + m_ps = vertex_ctr(seg, 0); + m_pt = vertex_ctr(seg, 1); + + Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt); + m_is_degen = (res == EQUAL); + m_is_directed_right = (res == SMALLER); + + CGAL_precondition_msg(! m_is_degen, "Cannot construct a degenerate segment."); + + m_l = kernel.construct_line_2_object()(seg); + m_is_vert = kernel.is_vertical_2_object()(seg); +} + +//! \brief Constructs a segment from two endpoints. +template +Arr_segment_traits_2:: +_Segment_cached_2::_Segment_cached_2(const Point_2& source, + const Point_2& target) : + m_ps(source), + m_pt(target) +{ + Kernel kernel; + + Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt); + m_is_degen = (res == EQUAL); + m_is_directed_right = (res == SMALLER); + + CGAL_precondition_msg(! m_is_degen, "Cannot construct a degenerate segment."); + + m_l = kernel.construct_line_2_object()(source, target); + m_is_vert = kernel.is_vertical_2_object()(m_l); +} + +//! \brief constructs a segment from two endpoints on a supporting line. +template +Arr_segment_traits_2:: +_Segment_cached_2::_Segment_cached_2(const Line_2& line, + const Point_2& source, + const Point_2& target) : + m_l(line), + m_ps(source), + m_pt(target) +{ + Kernel kernel; + + CGAL_precondition + (Segment_assertions::_assert_is_point_on(source, m_l, + Has_exact_division()) && + Segment_assertions::_assert_is_point_on(target, m_l, + Has_exact_division())); + + m_is_vert = kernel.is_vertical_2_object()(m_l); + + Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt); + m_is_degen = (res == EQUAL); + m_is_directed_right = (res == SMALLER); + + CGAL_precondition_msg(! m_is_degen, "Cannot construct a degenerate segment."); +} + +//! \brief constructs a segment from all fields. +template +Arr_segment_traits_2::_Segment_cached_2:: +_Segment_cached_2(const Line_2& line, + const Point_2& source, const Point_2& target, + bool is_directed_right, bool is_vert, bool is_degen) : + m_l(line), + m_ps(source), + m_pt(target), + m_is_directed_right(is_directed_right), + m_is_vert(is_vert), + m_is_degen(is_degen) +{} + +//! \brief assigns. +template +const typename Arr_segment_traits_2::_Segment_cached_2& +Arr_segment_traits_2::_Segment_cached_2::operator=(const Segment_2& seg) +{ + Kernel kernel; + auto vertex_ctr = kernel.construct_vertex_2_object(); + + m_ps = vertex_ctr(seg, 0); + m_pt = vertex_ctr(seg, 1); + + Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt); + m_is_degen = (res == EQUAL); + m_is_directed_right = (res == SMALLER); + + CGAL_precondition_msg(! m_is_degen, "Cannot construct a degenerate segment."); + + m_l = kernel.construct_line_2_object()(seg); + m_is_vert = kernel.is_vertical_2_object()(seg); + + return (*this); +} + +// Accessors + +//! \brief obtains the supporting line. +template +const typename Kernel::Line_2& +Arr_segment_traits_2::_Segment_cached_2::line() const { return m_l; } + +//! \brief determines whether the curve is vertical. +template +bool Arr_segment_traits_2::_Segment_cached_2::is_vertical() const +{ return m_is_vert; } + +//! \brief determines whether the curve is degenerate. +template +bool Arr_segment_traits_2::_Segment_cached_2::is_degenerate() const +{ return m_is_degen; } + +/*! \brief determines whether the curve is lexicographically directed from + * left to right + */ +template +bool Arr_segment_traits_2::_Segment_cached_2::is_directed_right() const +{ return m_is_directed_right; } + +//! \brief obtain the segment source. +template +const typename Kernel::Point_2& +Arr_segment_traits_2::_Segment_cached_2::source() const { return m_ps; } + +//! \brief obtains the segment target. +template +const typename Kernel::Point_2& +Arr_segment_traits_2::_Segment_cached_2::target() const { return m_pt; } + +//! \brief obtains the (lexicographically) left endpoint. +template +const typename Kernel::Point_2& +Arr_segment_traits_2::_Segment_cached_2::left() const +{ return (m_is_directed_right ? m_ps : m_pt); } + +//! \brief obtains the (lexicographically) right endpoint. +template +const typename Kernel::Point_2& +Arr_segment_traits_2::_Segment_cached_2::right() const +{ return (m_is_directed_right ? m_pt : m_ps); } + +// Modifiers + +//! \brief sets the (lexicographically) left endpoint. +template +void Arr_segment_traits_2::_Segment_cached_2::set_left(const Point_2& p) +{ + CGAL_precondition(! m_is_degen); + CGAL_precondition_code(Kernel kernel); + CGAL_precondition + (Segment_assertions::_assert_is_point_on(p, m_l, Has_exact_division()) && + (kernel.compare_xy_2_object()(p, right()) == SMALLER)); + + if (m_is_directed_right) m_ps = p; + else m_pt = p; +} + +//! \brief sets the (lexicographically) right endpoint. +template +void Arr_segment_traits_2::_Segment_cached_2::set_right(const Point_2& p) +{ + CGAL_precondition(! m_is_degen); + CGAL_precondition_code(Kernel kernel); + CGAL_precondition + (Segment_assertions::_assert_is_point_on(p, m_l, Has_exact_division()) && + (kernel.compare_xy_2_object()(p, left()) == LARGER)); + + if (m_is_directed_right) m_pt = p; + else m_ps = p; +} + +//! \brief determines whether the given point is in the x-range of the segment. +template +bool Arr_segment_traits_2::_Segment_cached_2:: +is_in_x_range(const Point_2& p) const +{ + Kernel kernel; + typename Kernel::Compare_x_2 compare_x = kernel.compare_x_2_object(); + const Comparison_result res1 = compare_x(p, left()); + + if (res1 == SMALLER) return false; + else if (res1 == EQUAL) return true; + + const Comparison_result res2 = compare_x(p, right()); + return (res2 != LARGER); +} + +//! \brief determines whether the given point is in the y-range of the segment. +template +bool Arr_segment_traits_2::_Segment_cached_2:: +is_in_y_range(const Point_2& p) const +{ + Kernel kernel; + typename Kernel::Compare_y_2 compare_y = kernel.compare_y_2_object(); + const Comparison_result res1 = compare_y(p, left()); + + if (res1 == SMALLER) return false; + else if (res1 == EQUAL) return true; + + const Comparison_result res2 = compare_y(p, right()); + return (res2 != LARGER); +} + +// IO + /*! \class A representation of a segment, as used by the Arr_segment_traits_2 * traits-class. */ template -class Arr_segment_2 : - public Arr_segment_traits_2::_Segment_cached_2 -{ +class Arr_segment_2 : public Arr_segment_traits_2::_Segment_cached_2 { typedef Kernel_ Kernel; + typedef typename Arr_segment_traits_2::_Segment_cached_2 Base; typedef typename Kernel::Segment_2 Segment_2; typedef typename Kernel::Point_2 Point_2; typedef typename Kernel::Line_2 Line_2; public: - /*! Default constructor. */ - Arr_segment_2() : Base() {} + /*! Construct default. */ + Arr_segment_2(); - /*! Constructor from a "kernel" segment. - * \param seg The segment. - * \pre The segment is not degenerate. + /*! Construct a segment from a "kernel" segment. + * \param seg the segment. + * \pre the segment is not degenerate. */ - Arr_segment_2(const Segment_2& seg) : Base(seg) {} + Arr_segment_2(const Segment_2& seg); - /*! Construct a segment from two end-points. - * \param source The source point. - * \param target The target point. - * \pre The two points are not the same. + /*! Construct a segment from two endpoints. + * \param source the source point. + * \param target the target point. + * \pre `source` and `target` are not equal. */ - Arr_segment_2(const Point_2& source, const Point_2& target) : - Base(source, target) - {} + Arr_segment_2(const Point_2& source, const Point_2& target); - /*! Construct a segment from a line and two end-points. - * \param line The supporting line. - * \param source The source point. - * \param target The target point. - * \pre Both source and target must be on the supporting line. - * \pre The two points are not the same. + /*! Construct a segment from a line and two endpoints. + * \param line the supporting line. + * \param source the source point. + * \param target the target point. + * \pre Both `source` and `target` must be on `line`. + * \pre `source` and `target` are not equal. */ Arr_segment_2(const Line_2& line, - const Point_2& source, const Point_2& target) : - Base(line,source, target) - {} + const Point_2& source, const Point_2& target); + + /*! Construct a segment from all fields. + * \param line the supporting line. + * \param source the source point. + * \param target the target point. + * \param is_directed_right is (lexicographically) directed left to right. + * \param is_vert is the segment vertical. + * \param is_degen is the segment degenerate (a single point). + */ + Arr_segment_2(const Line_2& line, + const Point_2& source, const Point_2& target, + bool is_directed_right, bool is_vert, bool is_degen); /*! Cast to a segment. */ - operator Segment_2() const - { - Kernel kernel; - Segment_2 seg = kernel.construct_segment_2_object()(this->m_ps, this->m_pt); - return seg; - } - - /*! Create a bounding box for the segment. - */ - Bbox_2 bbox() const - { - Kernel kernel; - auto construct_bbox = kernel.construct_bbox_2_object(); - return construct_bbox(this->m_ps) + construct_bbox(this->m_pt); - } - - /*! Obtain the segment source. - */ - const Point_2& source() const { return (this->m_ps); } - - /*! Obtain the segment target. - */ - const Point_2& target() const { return (this->m_pt); } + operator Segment_2() const; /*! Flip the segment (swap its source and target). */ - Arr_segment_2 flip() const - { - Arr_segment_2 opp; - opp.m_l = this->m_l; - opp.m_ps = this->m_pt; - opp.m_pt = this->m_ps; - opp.m_is_pt_max = !(this->m_is_pt_max); - opp.m_is_vert = this->m_is_vert; - opp.m_is_degen = this->m_is_degen; - - return opp; - } + Arr_segment_2 flip() const; }; +//! \brief constructs default. +template +Arr_segment_2::Arr_segment_2() : Base() {} + +//! \brief constructs from a "kernel" segment. +template +Arr_segment_2::Arr_segment_2(const Segment_2& seg) : Base(seg) {} + +//! \brief constructs a segment from two end-points. +template +Arr_segment_2::Arr_segment_2(const Point_2& source, + const Point_2& target) : + Base(source, target) +{} + +//! \brief constructs a segment from a line and two end-points. +template +Arr_segment_2::Arr_segment_2(const Line_2& line, + const Point_2& source, + const Point_2& target) : + Base(line,source, target) +{} + +//! \brief constructs a segment from all fields. +template +Arr_segment_2::Arr_segment_2(const Line_2& line, + const Point_2& source, + const Point_2& target, + bool is_directed_right, + bool is_vert, bool is_degen) : + Base(line, source, target, is_directed_right, is_vert, is_degen) +{} + +//! \brief casts to a segment. +template +Arr_segment_2::operator Segment_2() const +{ + Kernel kernel; + auto seg_ctr = kernel.construct_segment_2_object(); + return seg_ctr(this->source(), this->target()); +} + +//! \brief flips the segment (swap its source and target). +template +Arr_segment_2 Arr_segment_2::flip() const +{ + return Arr_segment_2(this->line(), this->target(), this->source(), + ! (this->is_directed_right()), this->is_vertical(), + this->is_degenerate()); +} + /*! Exporter for the segment class used by the traits-class. */ template From a857651c21fb20b169efd6fb32c229165e04a518 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 20 Aug 2020 20:39:50 +0300 Subject: [PATCH 08/11] Optimized the bbox construction in do_bboxes_overlap() --- .../include/CGAL/Arr_segment_traits_2.h | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h index 76a08325fa9..e7f0de2b586 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h @@ -672,13 +672,25 @@ public: /*! Determine whether the bounding boxes of two segments overlap */ - bool do_overlap(const X_monotone_curve_2& cv1, - const X_monotone_curve_2& cv2) const + bool do_bboxes_overlap(const X_monotone_curve_2& cv1, + const X_monotone_curve_2& cv2) const { - const Kernel& kernel = m_traits; - auto bbox_ctr = kernel.construct_bbox_2_object(); - auto bbox1 = bbox_ctr(cv1.source()) + bbox_ctr(cv1.target()); - auto bbox2 = bbox_ctr(cv2.source()) + bbox_ctr(cv2.target()); + auto x1_min = CGAL::to_double(cv1.left().x()); + auto x1_max = CGAL::to_double(cv1.right().x()); + auto y1_s = CGAL::to_double(cv1.source().y()); + auto y1_t = CGAL::to_double(cv1.target().y()); + auto bbox1 = (y1_s < y1_t) ? + CGAL::Bbox_2(x1_min, y1_s, x1_max, y1_t) : + CGAL::Bbox_2(x1_min, y1_t, x1_max, y1_s); + + auto x2_min = CGAL::to_double(cv2.left().x()); + auto x2_max = CGAL::to_double(cv2.right().x()); + auto y2_s = CGAL::to_double(cv2.source().y()); + auto y2_t = CGAL::to_double(cv2.target().y()); + auto bbox2 = (y2_s < y2_t) ? + CGAL::Bbox_2(x2_min, y2_s, x2_max, y2_t) : + CGAL::Bbox_2(x2_min, y2_t, x2_max, y2_s); + return CGAL::do_overlap(bbox1, bbox2); } @@ -701,7 +713,7 @@ public: Intersection_result; // Early ending with Bbox overlapping test - if (! do_overlap(cv1, cv2)) return oi; + if (! do_bboxes_overlap(cv1, cv2)) return oi; // Early ending with specialized do_intersect const Kernel& kernel = m_traits; From b4e7a4ad0265280c8d4fac8d9bf82a3bc1e01666 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Sat, 22 Aug 2020 21:04:40 +0300 Subject: [PATCH 09/11] Reverted the bbox computation optimization as it turns out it doesn't help --- .../include/CGAL/Arr_segment_traits_2.h | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h index e7f0de2b586..f2e47b41549 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h @@ -675,22 +675,10 @@ public: bool do_bboxes_overlap(const X_monotone_curve_2& cv1, const X_monotone_curve_2& cv2) const { - auto x1_min = CGAL::to_double(cv1.left().x()); - auto x1_max = CGAL::to_double(cv1.right().x()); - auto y1_s = CGAL::to_double(cv1.source().y()); - auto y1_t = CGAL::to_double(cv1.target().y()); - auto bbox1 = (y1_s < y1_t) ? - CGAL::Bbox_2(x1_min, y1_s, x1_max, y1_t) : - CGAL::Bbox_2(x1_min, y1_t, x1_max, y1_s); - - auto x2_min = CGAL::to_double(cv2.left().x()); - auto x2_max = CGAL::to_double(cv2.right().x()); - auto y2_s = CGAL::to_double(cv2.source().y()); - auto y2_t = CGAL::to_double(cv2.target().y()); - auto bbox2 = (y2_s < y2_t) ? - CGAL::Bbox_2(x2_min, y2_s, x2_max, y2_t) : - CGAL::Bbox_2(x2_min, y2_t, x2_max, y2_s); - + const Kernel& kernel = m_traits; + auto construct_bbox = kernel.construct_bbox_2_object(); + auto bbox1 = construct_bbox(cv1.source()) + construct_bbox(cv1.target()); + auto bbox2 = construct_bbox(cv2.source()) + construct_bbox(cv2.target()); return CGAL::do_overlap(bbox1, bbox2); } @@ -1390,8 +1378,6 @@ is_in_y_range(const Point_2& p) const return (res2 != LARGER); } -// IO - /*! \class A representation of a segment, as used by the Arr_segment_traits_2 * traits-class. */ From 58fb204e972bfaf33007d0d9fe61dab159409e4c Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Mon, 24 Aug 2020 11:52:27 +0300 Subject: [PATCH 10/11] Placed back the bbox() function. (Will be deprecated in a separate commit.) --- .../include/CGAL/Arr_segment_traits_2.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h index f2e47b41549..8e48f735158 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h @@ -1436,6 +1436,15 @@ public: /*! Flip the segment (swap its source and target). */ Arr_segment_2 flip() const; + + /*! Create a bounding box for the segment. + */ + Bbox_2 bbox() const + { + Kernel kernel; + auto construct_bbox = kernel.construct_bbox_2_object(); + return construct_bbox(this->m_ps) + construct_bbox(this->m_pt); + } }; //! \brief constructs default. From 23a02ff4412e06cd3c28e1d96fc7ec1ceb00f6a9 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Tue, 25 Aug 2020 11:48:20 +0300 Subject: [PATCH 11/11] Pacify Windows msvc (definition of casting operator). --- Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h index 8e48f735158..44f65d9b056 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h @@ -1482,7 +1482,7 @@ Arr_segment_2::Arr_segment_2(const Line_2& line, //! \brief casts to a segment. template -Arr_segment_2::operator Segment_2() const +Arr_segment_2::operator typename Kernel::Segment_2() const { Kernel kernel; auto seg_ctr = kernel.construct_segment_2_object();