From 30b9a29ee9da7ceb5215ba7fe06896cd98147aa6 Mon Sep 17 00:00:00 2001 From: Shepard Liu Date: Tue, 8 Jul 2025 09:53:24 +0800 Subject: [PATCH] Code cleanup and bug fixes --- .../Arrangement_on_surface_2/CMakeLists.txt | 3 + .../Arrangement_on_surface_2/draw_arr.cpp | 83 ++-- .../rational_functions.cpp | 13 +- .../unbounded_non_intersecting.cpp | 27 +- .../CGAL/Draw_aos/Arr_approximate_point_2.h | 62 ++- .../Draw_aos/Arr_approximate_point_2_at_x.h | 124 +++++ .../CGAL/Draw_aos/Arr_approximation_cache.h | 37 +- .../Arr_approximation_geometry_traits.h | 26 - .../Arr_bounded_approximate_curve_2.h | 393 ++++++++++----- .../Draw_aos/Arr_bounded_approximate_face_2.h | 430 ++++++++++------- .../Arr_bounded_approximate_point_2.h | 25 +- .../Draw_aos/Arr_bounded_compute_y_at_x.h | 15 - .../Draw_aos/Arr_bounded_face_triangulator.h | 409 ++++++++-------- .../CGAL/Draw_aos/Arr_bounded_renderer.h | 167 ++++--- .../CGAL/Draw_aos/Arr_compute_y_at_x.h | 77 --- .../CGAL/Draw_aos/Arr_construct_curve_end.h | 58 +-- .../CGAL/Draw_aos/Arr_construct_segments.h | 161 ++++++- .../include/CGAL/Draw_aos/Arr_graph_conn.h | 19 +- .../include/CGAL/Draw_aos/Arr_portals.h | 94 ++-- .../CGAL/Draw_aos/Arr_render_context.h | 198 ++++---- .../include/CGAL/Draw_aos/Arr_viewer.h | 182 ++++--- .../include/CGAL/Draw_aos/helpers.h | 20 - .../include/CGAL/Draw_aos/type_utils.h | 283 +++++++++++ .../include/CGAL/draw_arrangement_2.h | 80 ++- .../Arrangement_on_surface_2/cgal_test.cmake | 418 ++++++---------- .../test_drawing_planar.cpp | 454 ------------------ .../test_drawing_spherical.cpp | 118 ----- 27 files changed, 1985 insertions(+), 1991 deletions(-) create mode 100644 Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximate_point_2_at_x.h delete mode 100644 Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximation_geometry_traits.h delete mode 100644 Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_compute_y_at_x.h delete mode 100644 Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_compute_y_at_x.h delete mode 100644 Arrangement_on_surface_2/include/CGAL/Draw_aos/helpers.h create mode 100644 Arrangement_on_surface_2/include/CGAL/Draw_aos/type_utils.h delete mode 100644 Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_drawing_planar.cpp delete mode 100644 Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_drawing_spherical.cpp diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt index bb5566835ab..90e21c2f1d5 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt @@ -15,8 +15,10 @@ foreach(cppfile ${cppfiles}) create_single_source_cgal_program("${cppfile}") endforeach() + if(CGAL_Qt6_FOUND) target_link_libraries(draw_arr PRIVATE CGAL::CGAL_Basic_viewer) + target_link_libraries(unbounded_non_intersecting PRIVATE CGAL::CGAL_Basic_viewer) target_link_libraries(linear_conics PRIVATE CGAL::CGAL_Basic_viewer) target_link_libraries(parabolas PRIVATE CGAL::CGAL_Basic_viewer) target_link_libraries(ellipses PRIVATE CGAL::CGAL_Basic_viewer) @@ -24,6 +26,7 @@ if(CGAL_Qt6_FOUND) target_link_libraries(polylines PRIVATE CGAL::CGAL_Basic_viewer) target_link_libraries(circles PRIVATE CGAL::CGAL_Basic_viewer) target_link_libraries(circular_arcs PRIVATE CGAL::CGAL_Basic_viewer) + target_link_libraries(rational_functions PRIVATE CGAL::CGAL_Basic_viewer) target_link_libraries(spherical_insert PRIVATE CGAL::CGAL_Basic_viewer) else() message( diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_arr.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_arr.cpp index 1b10d7504fa..4a94d8b849b 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_arr.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_arr.cpp @@ -1,7 +1,9 @@ +#include "CGAL/Random.h" #include #include #include #include +#include using Kernel = CGAL::Exact_predicates_exact_constructions_kernel; using Traits = CGAL::Arr_segment_traits_2; @@ -17,9 +19,8 @@ using Arrangement_2 = CGAL::Arrangement_2; * \param sat Saturation component range: [0, 1] * \param value Value component range: [0, 1] * \return tuple, where each component is in the range [0, 255] -*/ -std::tuple -hsv_to_rgb(float hue, float sat, float value) { + */ +std::tuple hsv_to_rgb(float hue, float sat, float value) { float red, green, blue; float fc = value * sat; // Chroma float hue_prime = fmod(hue / 60.0f, 6.f); @@ -30,33 +31,27 @@ hsv_to_rgb(float hue, float sat, float value) { red = fc; green = fx; blue = 0; - } - else if(1 <= hue_prime && hue_prime < 2) { + } else if(1 <= hue_prime && hue_prime < 2) { red = fx; green = fc; blue = 0; - } - else if(2 <= hue_prime && hue_prime < 3) { + } else if(2 <= hue_prime && hue_prime < 3) { red = 0; green = fc; blue = fx; - } - else if(3 <= hue_prime && hue_prime < 4) { + } else if(3 <= hue_prime && hue_prime < 4) { red = 0; green = fx; blue = fc; - } - else if(4 <= hue_prime && hue_prime < 5) { + } else if(4 <= hue_prime && hue_prime < 5) { red = fx; green = 0; blue = fc; - } - else if(5 <= hue_prime && hue_prime < 6) { + } else if(5 <= hue_prime && hue_prime < 6) { red = fc; green = 0; blue = fx; - } - else { + } else { red = 0; green = 0; blue = 0; @@ -80,44 +75,38 @@ int main() { Arrangement_2 arr(&traits); auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); - CGAL::insert(arr, ctr_xcv(Point(-2,-2), Point(2,-2))); - CGAL::insert(arr, ctr_xcv(Point(2,-2), Point(2,2))); - CGAL::insert(arr, ctr_xcv(Point(2,2), Point(-2,2))); - CGAL::insert(arr, ctr_xcv(Point(-2,2), Point(-2,-2))); + CGAL::insert(arr, ctr_xcv(Point(-2, -2), Point(2, -2))); + CGAL::insert(arr, ctr_xcv(Point(2, -2), Point(2, 2))); + CGAL::insert(arr, ctr_xcv(Point(2, 2), Point(-2, 2))); + CGAL::insert(arr, ctr_xcv(Point(-2, 2), Point(-2, -2))); - CGAL::insert(arr, ctr_xcv(Point(-1,-1), Point(1,-1))); - CGAL::insert(arr, ctr_xcv(Point(1,-1), Point(1,1))); - CGAL::insert(arr, ctr_xcv(Point(1,1), Point(-1,1))); - CGAL::insert(arr, ctr_xcv(Point(-1,1), Point(-1,-1))); + CGAL::insert(arr, ctr_xcv(Point(-1, -1), Point(1, -1))); + CGAL::insert(arr, ctr_xcv(Point(1, -1), Point(1, 1))); + CGAL::insert(arr, ctr_xcv(Point(1, 1), Point(-1, 1))); + CGAL::insert(arr, ctr_xcv(Point(-1, 1), Point(-1, -1))); - CGAL::insert(arr, ctr_xcv(Point(-2,-2), Point(-2,-4))); - CGAL::insert(arr, ctr_xcv(Point(2,-2), Point(4,-2))); + CGAL::insert(arr, ctr_xcv(Point(-2, -2), Point(-2, -4))); + CGAL::insert(arr, ctr_xcv(Point(2, -2), Point(4, -2))); - CGAL::insert(arr, ctr_xcv(Point(0,0), Point(0,-3))); + CGAL::insert(arr, ctr_xcv(Point(0, 0), Point(0, -3))); - std::cout << arr.number_of_vertices() << ", " - << arr.number_of_edges() << ", " - << arr.number_of_faces() << std::endl; + std::cout << arr.number_of_vertices() << ", " << arr.number_of_edges() << ", " << arr.number_of_faces() << std::endl; - std::size_t id(0); + CGAL::Graphics_scene_options + gso; + gso.colored_face = [](const Arrangement_2&, Arrangement_2::Face_const_handle) -> bool { return true; }; - CGAL::Graphics_scene_options gso; - gso.colored_face=[](const Arrangement_2&, Arrangement_2::Face_const_handle) -> bool - { return true; }; + gso.face_color = [](const Arrangement_2& arr, Arrangement_2::Face_const_handle fh) -> CGAL::IO::Color { + CGAL::Random random((size_t(fh.ptr()))); + float h = 360.0f * random.get_double(0, 1); + float s = 0.5; + float v = 0.5; + auto [r, g, b] = hsv_to_rgb(h, s, v); + return CGAL::IO::Color(r, g, b); + }; - gso.face_color=[&id](const Arrangement_2& arr, Arrangement_2::Face_const_handle) -> CGAL::IO::Color - { - float h = 360.0f * id++ / arr.number_of_faces(); - float s = 0.5; - float v = 0.5; - auto [r, g, b] = hsv_to_rgb(h, s, v); - return CGAL::IO::Color(r,g,b); - }; + CGAL::draw(arr, gso, "hsv colors"); - CGAL::draw(arr, gso, "hsv colors"); - - return EXIT_SUCCESS; + return EXIT_SUCCESS; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/rational_functions.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/rational_functions.cpp index 20c542f086b..df0c5f19bab 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/rational_functions.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/rational_functions.cpp @@ -2,6 +2,7 @@ // Constructing an arrangement of arcs of rational functions. #include +#include #ifndef CGAL_USE_CORE #include @@ -17,7 +18,7 @@ int main() { #include "arr_print.h" int main() { - CGAL::IO::set_pretty_mode(std::cout); // for nice printouts. + CGAL::IO::set_pretty_mode(std::cout); // for nice printouts. // Define a traits class object and a constructor for rational functions. Traits traits; @@ -31,24 +32,24 @@ int main() { // Create an arc (C1) supported by the polynomial y = x^4 - 6x^2 + 8, // defined over the (approximate) interval [-2.1, 2.1]. - Polynomial P1 = CGAL::ipower(x,4) - 6*x*x + 8; + Polynomial P1 = CGAL::ipower(x, 4) - 6 * x * x + 8; Alg_real l(Bound(-2.1)), r(Bound(2.1)); arcs.push_back(construct(P1, l, r)); // Create an arc (C2) supported by the function y = x / (1 + x^2), // defined over the interval [-3, 3]. Polynomial P2 = x; - Polynomial Q2 = 1 + x*x; + Polynomial Q2 = 1 + x * x; arcs.push_back(construct(P2, Q2, Alg_real(-3), Alg_real(3))); // Create an arc (C3) supported by the parbola y = 8 - x^2, // defined over the interval [-2, 3]. - Polynomial P3 = 8 - x*x; + Polynomial P3 = 8 - x * x; arcs.push_back(construct(P3, Alg_real(-2), Alg_real(3))); // Create an arc (C4) supported by the line y = -2x, // defined over the interval [-3, 0]. - Polynomial P4 = -2*x; + Polynomial P4 = -2 * x; arcs.push_back(construct(P4, Alg_real(-3), Alg_real(0))); // Construct the arrangement of the four arcs. @@ -56,6 +57,8 @@ int main() { insert(arr, arcs.begin(), arcs.end()); print_arrangement(arr); + CGAL::draw(arr); + return 0; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/unbounded_non_intersecting.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/unbounded_non_intersecting.cpp index 7de9d0981d6..2246f44bb96 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/unbounded_non_intersecting.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/unbounded_non_intersecting.cpp @@ -4,6 +4,7 @@ #include +#include "CGAL/draw_arrangement_2.h" #include "arr_linear.h" #include "arr_print.h" @@ -14,8 +15,8 @@ int main() { // then, insert a point that lies on the line splitting it into two. X_monotone_curve c1 = Line(Point(-1, 0), Point(1, 0)); arr.insert_in_face_interior(c1, arr.unbounded_face()); - Vertex_handle v = insert_point(arr, Point(0,0)); - assert(! v->is_at_open_boundary()); + Vertex_handle v = insert_point(arr, Point(0, 0)); + assert(!v->is_at_open_boundary()); // Add two more rays using the specialized insertion functions. arr.insert_from_right_vertex(Ray(Point(0, 0), Point(-1, 1)), v); // c2 @@ -30,25 +31,27 @@ int main() { // Print the outer CCBs of the unbounded faces. int k = 1; - for (auto it = arr.unbounded_faces_begin(); it != arr.unbounded_faces_end(); - ++it) - { - std::cout << "Face no. " << k++ << "(" << it->is_unbounded() << "," - << it->number_of_holes() << ")" << ": "; + for(auto it = arr.unbounded_faces_begin(); it != arr.unbounded_faces_end(); ++it) { + std::cout << "Face no. " << k++ << "(" << it->is_unbounded() << "," << it->number_of_holes() << ")" << ": "; Arrangement::Ccb_halfedge_const_circulator first = it->outer_ccb(); auto curr = first; - if (! curr->source()->is_at_open_boundary()) + if(!curr->source()->is_at_open_boundary()) std::cout << "(" << curr->source()->point() << ")"; do { Arrangement::Halfedge_const_handle e = curr; - if (! e->is_fictitious()) std::cout << " [" << e->curve() << "] "; - else std::cout << " [ ... ] "; + if(!e->is_fictitious()) + std::cout << " [" << e->curve() << "] "; + else + std::cout << " [ ... ] "; - if (! e->target()->is_at_open_boundary()) + if(!e->target()->is_at_open_boundary()) std::cout << "(" << e->target()->point() << ")"; - } while (++curr != first); + } while(++curr != first); std::cout << std::endl; } + + CGAL::draw(arr); + return 0; } diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximate_point_2.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximate_point_2.h index 1fcbbbe0ba7..04ae489730f 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximate_point_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximate_point_2.h @@ -1,32 +1,31 @@ #ifndef CGAL_DRAW_AOS_ARR_APPROXIMATE_POINT_2_H #define CGAL_DRAW_AOS_ARR_APPROXIMATE_POINT_2_H -#include "CGAL/Arr_has.h" -#include "CGAL/Draw_aos/Arr_approximation_geometry_traits.h" +#include "CGAL/Arr_rational_function_traits_2.h" #include "CGAL/number_utils.h" +#include "CGAL/Draw_aos/type_utils.h" namespace CGAL { - +namespace draw_aos { namespace internal { -template +template class Arr_approximate_point_2_impl; -template -class Arr_approximate_point_2_impl +template +class Arr_approximate_point_2_impl { - using Approx_kernel = Arr_approximation_geometry_traits::Approximation_kernel; - using Point_2 = typename Geom_traits::Point_2; - using Approx_point = Arr_approximation_geometry_traits::Approx_point; + using Approx_traits = Arr_approximation_geometry_traits; + using Point_2 = typename Traits_adaptor::Point_2; + using Approx_point = typename Approx_traits::Approx_point; public: - Arr_approximate_point_2_impl(const Geom_traits& traits) + Arr_approximate_point_2_impl(const GeomTraits& traits) : m_approx(traits.approximate_2_object()) {} /** * @brief Approximate a point. * TODO: make it work for spherical traits. - * * @param pt * @return Point_geom */ @@ -42,20 +41,38 @@ public: double operator()(const Point_2& pt, int dim) const { return m_approx(pt, dim); } private: - typename Geom_traits::Approximate_2 m_approx; + const typename GeomTraits::Approximate_2 m_approx; +}; + +// Specialized for Arr_rational_function_traits_2. +template +class Arr_approximate_point_2_impl, true> +{ + using Geom_traits = Arr_rational_function_traits_2; + using Approx_traits = Arr_approximation_geometry_traits; + using Point_2 = typename Traits_adaptor::Point_2; + using Approx_point = typename Approx_traits::Approx_point; + using Approximate_2 = typename Geom_traits::Approximate_2; + +public: + Arr_approximate_point_2_impl(const Geom_traits& traits) {} + + Approx_point operator()(const Point_2& pt) const { return {pt.x().to_double(), pt.y().to_double()}; } + + double operator()(const Point_2& pt, int dim) const { return (dim == 0) ? pt.x().to_double() : pt.y().to_double(); } }; // Fallback to use CGAL::to_double for traits that do not have an approximate_2_object. -template -class Arr_approximate_point_2_impl +template +class Arr_approximate_point_2_impl { - using Approx_kernel = Arr_approximation_geometry_traits::Approximation_kernel; - using Point_2 = typename Geom_traits::Point_2; - using Approx_point = Arr_approximation_geometry_traits::Approx_point; + using Approx_traits = Arr_approximation_geometry_traits; + using Point_2 = typename Traits_adaptor::Point_2; + using Approx_point = typename Approx_traits::Approx_point; public: - // traits object is not used in the fallback implementation, but we keep it for consistency. - Arr_approximate_point_2_impl(const Geom_traits& traits) {} + // traits object is not used in the fallback implementation, but we keep it for consistency. + Arr_approximate_point_2_impl(const GeomTraits& traits) {} /** * @brief Approximate a point. @@ -88,10 +105,13 @@ public: } // namespace internal -template +template using Arr_approximate_point_2 = - internal::Arr_approximate_point_2_impl::value>; + internal::Arr_approximate_point_2_impl && + has_operator_point_v>; +} // namespace draw_aos } // namespace CGAL #endif // CGAL_DRAW_AOS_ARR_APPROXIMATE_POINT_2_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximate_point_2_at_x.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximate_point_2_at_x.h new file mode 100644 index 00000000000..71fe4de2d56 --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximate_point_2_at_x.h @@ -0,0 +1,124 @@ +#ifndef CGAL_DRAW_AOS_ARR_APPROXIMATE_POINT_2_AT_X_H +#define CGAL_DRAW_AOS_ARR_APPROXIMATE_POINT_2_AT_X_H +#include + +#include "CGAL/number_utils.h" +#include "CGAL/Arr_rational_function_traits_2.h" +#include "CGAL/Draw_aos/Arr_construct_curve_end.h" +#include "CGAL/Draw_aos/Arr_construct_segments.h" +#include "CGAL/Draw_aos/Arr_approximate_point_2.h" +#include "CGAL/Draw_aos/type_utils.h" + +namespace CGAL { +namespace draw_aos { + +/** + * @brief Functor to compute the point at a given x-coordinate on an x-monotone curve within a bounding box. + */ +template +class Arr_approximate_point_2_at_x +{ + using Point_2 = typename Traits_adaptor::Point_2; + using X_monotone_curve_2 = typename Traits_adaptor::X_monotone_curve_2; + using Intersect_2 = typename Traits_adaptor::Intersect_2; + using FT = typename Traits_adaptor::FT; + using Approx_traits = Arr_approximation_geometry_traits; + using Approx_point = typename Approx_traits::Approx_point; + using Is_vertical_2 = typename Traits_adaptor::Is_vertical_2; + +public: + Arr_approximate_point_2_at_x(const GeomTraits& traits) + : m_approx_pt(traits) + , m_cst_vertical_segment(traits) + , m_is_vertical_2(traits.is_vertical_2_object()) + , m_intersect_2(traits.intersect_2_object()) {} + + /** + * @brief Computes the point at a given x-coordinate on an x-monotone curve + * + * @precondition: The curve is not verical + * @param curve + * @param x + * @return true if there is an intersection at given x, + * @return false otherwise. + */ + std::optional operator()(const X_monotone_curve_2& curve, FT x) const { + CGAL_assertion(!m_is_vertical_2(curve)); + + using Multiplicity = typename GeomTraits::Multiplicity; + using Intersect_point = std::pair; + using Intersect_curve = X_monotone_curve_2; + using Intersect_type = std::variant; + + auto vertical_line = m_cst_vertical_segment(x, m_ymin, m_ymax); + std::optional pt; + auto func_out_iter = boost::make_function_output_iterator([&pt, this](const Intersect_type& res) { + CGAL_assertion_msg(std::holds_alternative(res), + "Unexpected intersection type, expected Intersect_point"); + pt = this->m_approx_pt(std::get(res).first); + }); + m_intersect_2(vertical_line, curve, func_out_iter); + + if(pt.has_value()) { + pt = Approx_point(CGAL::to_double(x), pt->y()); + } + return pt; + } + +private: + const Arr_approximate_point_2 m_approx_pt; + const Arr_construct_vertical_segment m_cst_vertical_segment; + const Is_vertical_2 m_is_vertical_2; + const Intersect_2 m_intersect_2; + + // Should be enough for visualization purposes. + // constexpr static double m_ymin = std::numeric_limits::lowest(); + // constexpr static double m_ymax = std::numeric_limits::max(); + // maximum of double is too large for CORE number types, no idea why + constexpr static double m_ymin = -1e8; + constexpr static double m_ymax = 1e8; +}; + +// Specialization for rational function traits, which has no vertical curves but provides +// evaluation at x directly. +template +class Arr_approximate_point_2_at_x> +{ + using Geom_traits = CGAL::Arr_rational_function_traits_2; + using Point_2 = typename Traits_adaptor::Point_2; + using X_monotone_curve_2 = typename Traits_adaptor::X_monotone_curve_2; + using FT = typename Traits_adaptor::FT; + using Approx_point = typename Arr_approximation_geometry_traits::Approx_point; + using Construct_curve_end = Arr_construct_curve_end; + +public: + Arr_approximate_point_2_at_x(const Geom_traits& traits) + : m_cst_curve_end(traits) {} + + std::optional operator()(const X_monotone_curve_2& curve, FT x) const { + std::optional min_end = m_cst_curve_end(curve, ARR_MIN_END); + if(min_end.has_value() && x < min_end->x()) { + return std::nullopt; + } + std::optional max_end = m_cst_curve_end(curve, ARR_MAX_END); + if(max_end.has_value() && x > max_end->x()) { + return std::nullopt; + } + + using Bound = typename Geom_traits::Bound; + const auto& numerator = curve.numerator(); + const auto& denominator = curve.denominator(); + Bound approx_x = (x.lower() + x.upper()) / 2.0; + double enum_at_x = CGAL::to_double(numerator.evaluate(approx_x)); + double denom_at_x = CGAL::to_double(denominator.evaluate(approx_x)); + return std::make_optional(Approx_point(CGAL::to_double(x), enum_at_x / denom_at_x)); + } + +private: + const Construct_curve_end m_cst_curve_end; +}; + +} // namespace draw_aos +} // namespace CGAL + +#endif // CGAL_DRAW_AOS_ARR_COMPUTE_Y_AT_X_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximation_cache.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximation_cache.h index e70edb3023e..5b34edfa724 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximation_cache.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximation_cache.h @@ -1,26 +1,32 @@ #ifndef CGAL_DRAW_AOS_ARR_APPROXIMATION_CACHE_H #define CGAL_DRAW_AOS_ARR_APPROXIMATION_CACHE_H -#include "CGAL/Arr_enums.h" -#include "CGAL/Draw_aos/Arr_approximation_geometry_traits.h" -#include "CGAL/Draw_aos/helpers.h" -#include "CGAL/unordered_flat_map.h" +#include + #include +#include "CGAL/Arr_enums.h" +#include "CGAL/unordered_flat_map.h" +#include "CGAL/Draw_aos/type_utils.h" + namespace CGAL { +namespace draw_aos { + +template class Arr_approximation_cache { - using Approx_geom_traits = Arr_approximation_geometry_traits; + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Approx_traits = Arr_approximation_geometry_traits; public: - using Vertex_cache_obj = Approx_geom_traits::Point_geom; - using Halfedge_cache_obj = Approx_geom_traits::Polyline_geom; - using Face_cache_obj = Approx_geom_traits::Triangulated_face; + using Vertex_cache_obj = typename Approx_traits::Point_geom; + using Halfedge_cache_obj = typename Approx_traits::Polyline_geom; + using Face_cache_obj = typename Approx_traits::Triangulated_face; private: - using Vertex_const_handle = Arrangement::Vertex_const_handle; - using Edge_const_handle = Arrangement::Edge_const_iterator; - using Halfedge_const_handle = Arrangement::Halfedge_const_iterator; - using Face_const_handle = Arrangement::Face_const_handle; + using Vertex_const_handle = typename Arrangement::Vertex_const_handle; + using Edge_const_handle = typename Arrangement::Edge_const_iterator; + using Halfedge_const_handle = typename Arrangement::Halfedge_const_iterator; + using Face_const_handle = typename Arrangement::Face_const_handle; using Vertex_cache = unordered_flat_map; using Halfedge_cache = unordered_flat_map; using Face_cache = unordered_flat_map; @@ -38,6 +44,12 @@ private: } public: + Arr_approximation_cache() = default; + + void reserve_vertex_cache(std::size_t size) { m_vertex_cache.reserve(size); } + void reserve_halfedge_cache(std::size_t size) { m_halfedge_cache.reserve(size); } + void reserve_face_cache(std::size_t size) { m_face_cache.reserve(size); } + std::pair try_emplace(const Vertex_const_handle& vh) { const auto& [it, inserted] = m_vertex_cache.try_emplace(vh, Vertex_cache_obj()); return {it->second, inserted}; @@ -104,5 +116,6 @@ private: Face_cache m_face_cache; }; +} // namespace draw_aos } // namespace CGAL #endif // CGAL_DRAW_AOS_ARR_APPROXIMATION_CACHE_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximation_geometry_traits.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximation_geometry_traits.h deleted file mode 100644 index 24c901f2e90..00000000000 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximation_geometry_traits.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef CGAL_DRAW_AOS_ARR_APPROXIMATION_GEOMETRY_TRAITS_H -#define CGAL_DRAW_AOS_ARR_APPROXIMATION_GEOMETRY_TRAITS_H - -#include "CGAL/Simple_cartesian.h" - -namespace CGAL { -class Arr_approximation_geometry_traits -{ -public: - using Approximation_kernel = Simple_cartesian; - using Approx_point = Approximation_kernel::Point_2; - using FT = double; - using Point_geom = Approx_point; - using Apporx_point_vec = std::vector; - using Polyline_geom = Apporx_point_vec; - using Triangle = std::array; - using Triangle_vec = std::vector; - struct Triangulated_face - { - Apporx_point_vec points; - Triangle_vec triangles; - }; -}; - -} // namespace CGAL -#endif // CGAL_DRAW_AOS_ARR_APPROXIMATION_GEOMETRY_TRAITS_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_curve_2.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_curve_2.h index 3a5169215f8..d6a780ef8be 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_curve_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_curve_2.h @@ -1,83 +1,97 @@ #ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_CURVE_2_H #define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_CURVE_2_H -#include "CGAL/Arr_enums.h" -#include "CGAL/Draw_aos/Arr_bounded_approximate_point_2.h" -#include "CGAL/Draw_aos/Arr_compute_y_at_x.h" -#include "CGAL/Draw_aos/Arr_construct_curve_end.h" -#include "CGAL/Draw_aos/Arr_construct_segments.h" -#include "CGAL/Draw_aos/Arr_render_context.h" -#include "CGAL/Draw_aos/helpers.h" -#include "CGAL/Draw_aos/Arr_approximation_geometry_traits.h" -#include "CGAL/basic.h" #include #include +#include #include #include #include -namespace CGAL { +#include "CGAL/Arr_enums.h" +#include "CGAL/Draw_aos/Arr_approximate_point_2_at_x.h" +#include "CGAL/Draw_aos/Arr_render_context.h" +#include "CGAL/Draw_aos/type_utils.h" +#include "CGAL/basic.h" -/** - * @brief Functor to approximate an x-monotone curve within an bounding box. - * The bbox here has closed boundary. - * - * The Approximation is done from xmin to xmax with a given step. For parts outbound the y limits and precedes or - * succeeds a part within, the approximation may be skipped but there will be at least one point outside the bbox for - * indication. - * - * @note Bounded approximation is meaningful only when the curve has at least two points within the bbox (boundary - * points included). - * - * TODO: Possible optimizations: - * - Specialize for traits that models Approximate_2 on curves. - */ -class Arr_bounded_approximate_curve_2 +namespace CGAL { +namespace draw_aos { + +template +class Arr_bounded_approximate_curve_2_impl; + +template +class Arr_bounded_approximate_curve_2_impl { - using FT = Geom_traits::FT; - using Point_2 = Geom_traits::Point_2; - using X_monotone_curve_2 = Geom_traits::X_monotone_curve_2; - using Halfedge_const_handle = Arrangement::Halfedge_const_iterator; - using Approx_point = Arr_approximation_geometry_traits::Approx_point; - using Point_geom = Arr_approximation_geometry_traits::Point_geom; - using Polyline_geom = Arr_approximation_geometry_traits::Polyline_geom; + using Halfedge_const_handle = typename Arrangement::Halfedge_const_iterator; + using Geom_traits = typename Arrangement::Geometry_traits_2; + + using Approx_traits = Arr_approximation_geometry_traits; + using Approx_nt = typename Approx_traits::Approx_nt; + using Approx_point = typename Approx_traits::Approx_point; + using Polyline_geom = typename Approx_traits::Polyline_geom; + + using Adapted_traits = Traits_adaptor; + using FT = typename Adapted_traits::FT; + using Point_2 = typename Adapted_traits::Point_2; + using X_monotone_curve_2 = typename Adapted_traits::X_monotone_curve_2; + + using Approx_point_2_at_x = Arr_approximate_point_2_at_x; + using Bounded_render_context = Arr_bounded_render_context; + using Intersections_vector = std::vector; - struct Execution_context : public Arr_context_delegator + struct Execution_context : public Arr_context_delegator { - Execution_context(const Arr_bounded_render_context& ctx, + Execution_context(const Bounded_render_context& ctx, const X_monotone_curve_2& curve, - const Arr_bounded_approximate_point_2& approx_pt, - const Arr_compute_y_at_x& compute_y_at_x, + const Approx_point_2_at_x& approx_pt_at_x, const Intersections_vector& top_inters, const Intersections_vector& bottom_inters, Polyline_geom& polyline) - : Arr_context_delegator(ctx) + : Arr_context_delegator(ctx) , curve(curve) - , compute_y_at_x(compute_y_at_x) - , bounded_approx_pt(approx_pt) + , m_approx_pt_at_x(approx_pt_at_x) , top_inters(top_inters) , bottom_inters(bottom_inters) - , min_end(Arr_construct_curve_end(ctx.traits)(curve, ARR_MIN_END)) - , max_end(Arr_construct_curve_end(ctx.traits)(curve, ARR_MAX_END)) - , tight_xmin(is_min_end_bounded() ? std::clamp(min_end->x(), FT(ctx.xmin()), FT(ctx.xmax())) : FT(ctx.xmin())) - , tight_xmax(is_max_end_bounded() ? std::clamp(max_end->x(), FT(ctx.xmin()), FT(ctx.xmax())) : FT(ctx.xmax())) - , tight_ymin(is_min_end_bounded() ? std::clamp(min_end->y(), FT(ctx.ymin()), FT(ctx.ymax())) : FT(ctx.ymin())) - , tight_ymax(is_max_end_bounded() ? std::clamp(max_end->y(), FT(ctx.ymin()), FT(ctx.ymax())) : FT(ctx.ymax())) - , out_it(std::back_inserter(polyline)) {} + , out_it(std::back_inserter(polyline)) { + auto min_end_pt = Arr_construct_curve_end(ctx.traits)(curve, ARR_MIN_END); + if(min_end_pt.has_value()) { + min_end = (*this)->approx_pt(min_end_pt.value()); + } + auto max_end_pt = Arr_construct_curve_end(ctx.traits)(curve, ARR_MAX_END); + if(max_end_pt.has_value()) { + max_end = (*this)->approx_pt(max_end_pt.value()); + } + txmin = is_min_end_bounded() ? std::clamp(min_end->x(), ctx.xmin(), ctx.xmax()) : ctx.xmin(); + txmax = is_max_end_bounded() ? std::clamp(max_end->x(), ctx.xmin(), ctx.xmax()) : ctx.xmax(); + tymin = is_min_end_bounded() ? std::clamp(min_end->y(), ctx.ymin(), ctx.ymax()) : ctx.ymin(); + tymax = is_max_end_bounded() ? std::clamp(max_end->y(), ctx.ymin(), ctx.ymax()) : ctx.ymax(); + } bool has_y_intersections() const { return !top_inters.empty() || !bottom_inters.empty(); } bool is_min_end_bounded() const { return min_end.has_value(); } bool is_max_end_bounded() const { return max_end.has_value(); } bool is_bounded_curve() const { return is_min_end_bounded() && is_max_end_bounded(); } + std::optional approx_pt_at_x(double x) const { + if(x == txmin && is_min_end_bounded() && (*this)->contains_x(min_end->x())) { + return min_end; + } + if(x == txmax && is_max_end_bounded() && (*this)->contains_x(max_end->x())) { + return max_end; + } + return m_approx_pt_at_x(curve, to_ft(x)); + } const X_monotone_curve_2& curve; - const Arr_compute_y_at_x& compute_y_at_x; - const Arr_bounded_approximate_point_2& bounded_approx_pt; const Intersections_vector &top_inters, bottom_inters; - const std::optional min_end, max_end; - const FT tight_xmin, tight_xmax, tight_ymin, tight_ymax; + std::optional min_end, max_end; + double txmin, txmax, tymin, tymax; std::back_insert_iterator out_it; + const Construct_coordinate to_ft; + + private: + const Approx_point_2_at_x& m_approx_pt_at_x; }; private: @@ -85,8 +99,8 @@ private: const X_monotone_curve_2& cv2, const typename Geom_traits::Intersect_2& intersect_2, const Arr_construct_curve_end& cst_curve_end) { - using Intersect_point = std::pair; - using Intersect_curve = Geom_traits::X_monotone_curve_2; + using Intersect_point = std::pair; + using Intersect_curve = X_monotone_curve_2; using Intersect_type = std::variant; std::vector intersections; @@ -106,23 +120,24 @@ private: return intersections; } - static std::optional first_intersection(Execution_context& ctx) { + static std::optional first_intersection(Execution_context& ctx) { if(!ctx.top_inters.empty() && !ctx.bottom_inters.empty()) { - return ctx->compare_xy_2(ctx.top_inters.front(), ctx.bottom_inters.front()) == CGAL::SMALLER - ? ctx.top_inters.front() - : ctx.bottom_inters.front(); + return ctx->approx_pt(ctx->compare_xy_2(ctx.top_inters.front(), ctx.bottom_inters.front()) == CGAL::SMALLER + ? ctx.top_inters.front() + : ctx.bottom_inters.front()); } if(!ctx.top_inters.empty()) { - return ctx.top_inters.front(); + return ctx->approx_pt(ctx.top_inters.front()); } if(!ctx.bottom_inters.empty()) { - return ctx.bottom_inters.front(); + return ctx->approx_pt(ctx.bottom_inters.front()); } return std::nullopt; } /** * @brief approximate strictly x-monotone curve segment that does not cross the y bounds. + * A fallback implementation that approximates curve with Arr_approximate_point_2_at_x, which is inefficient. * * @precondition: The segment is either inbound or outbound the bbox in the given range. * @param start the x-coordinate of the segment start(exclusive) @@ -130,27 +145,27 @@ private: * @param step the step to approximate the curve segment, negative values allowed. * @returns true if this part of the curve is within the closed bbox */ - static void approximate_simple_curve_segment(Execution_context& ctx, const FT& start, const FT& end, double step) { - for(FT x = start + step; x < end; x += step) { - auto y = ctx.compute_y_at_x(ctx.curve, x); - if(!y.has_value()) { + static void approximate_simple_curve_segment(Execution_context& ctx, double start, double end, double step) { + for(double x = start + step; x <= end - step; x += step) { + auto pt = ctx.approx_pt_at_x(x); + if(!pt.has_value()) { // break as soon as there's no more intersections break; } - if(y == ctx->ymin() || y == ctx->ymax()) { + if(pt->y() == ctx->ymin() || pt->y() == ctx->ymax()) { // The segment overlaps with the bbox edge. There's no need to insert a dummy point. break; } - *ctx.out_it++ = ctx->approx_pt(Point_2(x, y.value())); - if(y > ctx->ymax() || y < ctx->ymin()) { + *ctx.out_it++ = pt.value(); + if(!ctx->contains_y(pt->y())) { // We are outside the bbox. The dummy point was already inserted to indicate that. break; } } - }; + } static void approximate_vertical_curve(Execution_context& ctx) { - if(ctx.is_bounded_curve() && (ctx.min_end->x() < ctx->xmin() || ctx.min_end->x() > ctx->xmax())) { + if(ctx.is_bounded_curve() && !ctx->contains_x(ctx.min_end->x())) { // The curve is outside the bbox in x direction, no need to approximate return; } @@ -161,28 +176,25 @@ private: } // The vertical curve is now within the x bounds. - FT tymin = ctx.tight_ymin; - FT tymax = ctx.tight_ymax; - if(tymax == tymin) { + if(ctx.tymax == ctx.tymin) { // But the curve is not degenerate. So, either it has only one point within the bbox or it is // entirely outside the bbox in y direction. return; } // Now we gaurantee that the curve has at least two points within the bbox in y direction. // We have to obtain the x coordinate of this vertical curve. - FT x = ctx.is_bounded_curve() ? ctx.min_end->x() : first_intersection(ctx)->x(); - *ctx.out_it++ = ctx->approx_pt(Point_2(x, tymin)); - *ctx.out_it++ = ctx->approx_pt(Point_2(x, tymax)); + double x = ctx.is_bounded_curve() ? ctx.min_end->x() : first_intersection(ctx).value().x(); + *ctx.out_it++ = Approx_point(x, ctx.tymin); + *ctx.out_it++ = Approx_point(x, ctx.tymax); } public: - Arr_bounded_approximate_curve_2(const Arr_bounded_render_context& ctx, - const Arr_bounded_approximate_point_2& point_approx) - : m_compute_y_at_x(ctx) - , m_approx_pt(point_approx) + Arr_bounded_approximate_curve_2_impl(const Bounded_render_context& ctx) + : to_ft() , m_ctx(ctx) - , m_top(ctx.cst_horizontal_segment(ctx.ymax(), ctx.xmin(), ctx.xmax())) - , m_bottom(ctx.cst_horizontal_segment(ctx.ymin(), ctx.xmin(), ctx.xmax())) {} + , m_approx_pt_at_x(ctx.traits) + , m_top(ctx.cst_horizontal_segment(to_ft(ctx.ymax()), to_ft(ctx.xmin()), to_ft(ctx.xmax()))) + , m_bottom(ctx.cst_horizontal_segment(to_ft(ctx.ymin()), to_ft(ctx.xmin()), to_ft(ctx.xmax()))) {} /** * @brief Approximate an x-monotone curve from left to right within the bounding box. @@ -204,13 +216,9 @@ public: const X_monotone_curve_2& curve = he->curve(); - if(curve.is_degenerate()) { - return polyline; - } - - auto top_inters = compute_intersections(curve, m_top, m_ctx.intersect_2, m_ctx.cst_curve_end); - auto bottom_inters = compute_intersections(curve, m_bottom, m_ctx.intersect_2, m_ctx.cst_curve_end); - Execution_context ctx(m_ctx, curve, m_approx_pt, m_compute_y_at_x, top_inters, bottom_inters, polyline); + auto top_inters = compute_intersections(m_top, curve, m_ctx.intersect_2, m_ctx.cst_curve_end); + auto bottom_inters = compute_intersections(m_bottom, curve, m_ctx.intersect_2, m_ctx.cst_curve_end); + Execution_context ctx(m_ctx, curve, m_approx_pt_at_x, top_inters, bottom_inters, polyline); if(ctx->is_vertical_2(curve)) { approximate_vertical_curve(ctx); @@ -219,20 +227,17 @@ public: polyline.reserve(top_inters.size() + bottom_inters.size()); - FT txmin = ctx.tight_xmin; - FT txmax = ctx.tight_xmax; - FT last_x; - std::optional first_inter = first_intersection(ctx); + double last_x; + std::optional first_inter = first_intersection(ctx); - if(auto y_at_txmin = ctx.compute_y_at_x(curve, txmin); - y_at_txmin.has_value() && y_at_txmin != ctx->ymin() && y_at_txmin != ctx->ymax()) + if(auto pt_at_txmin = ctx.approx_pt_at_x(ctx.txmin); + pt_at_txmin.has_value() && pt_at_txmin->y() != ctx->ymin() && pt_at_txmin->y() != ctx->ymax()) { // The tight starting point of the curve is within the bbox and // it's not on the top or bottom edge. - *ctx.out_it++ = txmin == ctx->xmin() ? ctx->approx_pt_on_boundary(Point_2(txmin, y_at_txmin.value())) - : ctx->approx_pt(Point_2(txmin, y_at_txmin.value())); - FT segment_end = first_inter.has_value() ? first_inter->x() : txmax; - approximate_simple_curve_segment(ctx, txmin, segment_end, ctx->approx_error); + *ctx.out_it++ = ctx.txmin == ctx->xmin() ? ctx->make_on_boundary(pt_at_txmin.value()) : pt_at_txmin.value(); + double segment_end = first_inter.has_value() ? first_inter->x() : ctx.txmax; + approximate_simple_curve_segment(ctx, ctx.txmin, segment_end, ctx->approx_error); last_x = segment_end; } else if(first_inter.has_value()) { last_x = first_inter->x(); @@ -243,29 +248,203 @@ public: // iterate through the intersections and insert segments in-between. std::merge(top_inters.begin(), top_inters.end(), bottom_inters.begin(), bottom_inters.end(), boost::make_function_output_iterator([&last_x, &ctx](const Point_2& inter) { - approximate_simple_curve_segment(ctx, last_x, inter.x(), ctx->approx_error); - *ctx.out_it++ = ctx->approx_pt_on_boundary(inter); - last_x = inter.x(); + auto approx_inter = ctx->approx_pt(inter); + approximate_simple_curve_segment(ctx, last_x, approx_inter.x(), ctx->approx_error); + *ctx.out_it++ = ctx->make_on_boundary(approx_inter); + last_x = approx_inter.x(); }), [&ctx](const Point_2& pt1, const Point_2& pt2) { return ctx->compare_xy_2(pt1, pt2) == CGAL::SMALLER; }); - if(auto y_at_txmax = ctx.compute_y_at_x(curve, txmax); - y_at_txmax.has_value() && y_at_txmax != ctx->ymin() && y_at_txmax != ctx->ymax()) + if(auto pt_at_txmax = ctx.approx_pt_at_x(ctx.txmax); + pt_at_txmax.has_value() && pt_at_txmax->y() != ctx->ymin() && pt_at_txmax->y() != ctx->ymax()) { - approximate_simple_curve_segment(ctx, last_x, txmax, ctx->approx_error); - *ctx.out_it++ = txmax == ctx->xmax() ? ctx->approx_pt_on_boundary(Point_2(txmax, y_at_txmax.value())) - : ctx->approx_pt(Point_2(txmax, y_at_txmax.value())); + approximate_simple_curve_segment(ctx, last_x, ctx.txmax, ctx->approx_error); + *ctx.out_it++ = ctx.txmax == ctx->xmax() ? ctx->make_on_boundary(pt_at_txmax.value()) : pt_at_txmax.value(); } return polyline; } private: - const Arr_bounded_render_context& m_ctx; - const Arr_bounded_approximate_point_2& m_approx_pt; - const Arr_compute_y_at_x m_compute_y_at_x; + const Construct_coordinate to_ft; + const Bounded_render_context& m_ctx; + const Approx_point_2_at_x m_approx_pt_at_x; const X_monotone_curve_2 m_top; const X_monotone_curve_2 m_bottom; }; + +template +class Arr_bounded_approximate_curve_2_impl +{ + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Halfedge_const_handle = typename Arrangement::Halfedge_const_iterator; + + using Approx_traits = Arr_approximation_geometry_traits; + using Approx_nt = typename Approx_traits::Approx_nt; + using Approx_point = typename Approx_traits::Approx_point; + using Approx_kernel = typename Approx_traits::Approx_kernel; + using Approx_line_2 = typename Approx_kernel::Line_2; + using Polyline_geom = typename Approx_traits::Polyline_geom; + + using Adapted_traits = Traits_adaptor; + using Approximate_2 = typename Adapted_traits::Approximate_2; + using X_monotone_curve_2 = typename Adapted_traits::X_monotone_curve_2; + using Construct_curve_end = Arr_construct_curve_end; + + using Bounded_render_context = Arr_bounded_render_context; + +private: + struct Execution_context : public Arr_context_delegator + { + Execution_context(const Bounded_render_context& ctx, + const X_monotone_curve_2& curve, + const Approximate_2& approx_2, + Polyline_geom& polyline) + : Arr_context_delegator(ctx) + , curve(curve) + , approx_2(approx_2) + , top(Approx_line_2(Approx_point(ctx.xmin(), ctx.ymax()), Approx_point(ctx.xmax(), ctx.ymax()))) + , right(Approx_line_2(Approx_point(ctx.xmax(), ctx.ymin()), Approx_point(ctx.xmax(), ctx.ymax()))) + , bottom(Approx_line_2(Approx_point(ctx.xmin(), ctx.ymin()), Approx_point(ctx.xmax(), ctx.ymin()))) + , left(Approx_line_2(Approx_point(ctx.xmin(), ctx.ymin()), Approx_point(ctx.xmin(), ctx.ymax()))) + , m_base_out_it(std::back_inserter(polyline)) + , out_it(boost::make_function_output_iterator(std::function([this](Approx_point pt) { + if(!(*this)->contains_x(pt.x())) { + return; + } + *this->m_base_out_it++ = pt; + }))) {} + + private: + std::back_insert_iterator m_base_out_it; + + public: + const X_monotone_curve_2& curve; + const Approximate_2& approx_2; + const Approx_line_2 top, right, bottom, left; + boost::function_output_iterator> out_it; + }; + + static void update_on_crossing_boundary(Execution_context& ctx, + Approx_point& last_pt, + const Approx_point& pt, + Side_of_boundary side) { + const auto& boundary_line = [&ctx, side]() { + switch(side) { + case Side_of_boundary::Top: + return ctx.top; + case Side_of_boundary::Right: + return ctx.right; + case Side_of_boundary::Bottom: + return ctx.bottom; + case Side_of_boundary::Left: + return ctx.left; + default: + return Approx_line_2(); + } + CGAL_assertion(false && "Unexpected side of boundary"); + }(); + + std::optional> res = + CGAL::intersection(Approx_line_2(last_pt, pt), boundary_line); + Approx_point inter = ctx->make_on_boundary(std::get(*res)); + if(!ctx->contains_x(inter.x())) { + return; + } + last_pt = inter; + *ctx.out_it++ = last_pt; + } + +public: + Arr_bounded_approximate_curve_2_impl(const Bounded_render_context& ctx) + : m_ctx(ctx) + , m_approximate_2(ctx.traits.approximate_2_object()) {} + + const Polyline_geom& operator()(const Halfedge_const_handle& he) const { + CGAL_assertion(!he->is_fictitious()); + + auto [polyline, inserted] = m_ctx.cache.try_emplace(he); + if(!inserted) { + return polyline; + } + + if(m_ctx.is_cancelled()) { + return polyline; + } + + polyline.reserve(static_cast(m_ctx.bbox().x_span() / m_ctx.approx_error)); + const X_monotone_curve_2& curve = he->curve(); + Execution_context ctx(m_ctx, curve, m_approximate_2, polyline); + std::optional last_pt; + + m_approximate_2(curve, m_ctx.approx_error, boost::make_function_output_iterator([&ctx, &last_pt](Approx_point pt) { + if(last_pt.has_value()) { + if(last_pt->x() < ctx->xmin() && pt.x() >= ctx->xmin()) { + update_on_crossing_boundary(ctx, last_pt.value(), pt, Side_of_boundary::Left); + } + if(last_pt->y() < ctx->ymin()) { + if(pt.y() >= ctx->ymin()) { + *ctx.out_it++ = last_pt.value(); + update_on_crossing_boundary(ctx, last_pt.value(), pt, Side_of_boundary::Bottom); + } + if(pt.y() > ctx->ymax()) { + update_on_crossing_boundary(ctx, last_pt.value(), pt, Side_of_boundary::Top); + } + } else if(last_pt->y() > ctx->ymax()) { + if(pt.y() <= ctx->ymax()) { + *ctx.out_it++ = last_pt.value(); + update_on_crossing_boundary(ctx, last_pt.value(), pt, Side_of_boundary::Top); + } + if(pt.y() < ctx->ymin()) { + update_on_crossing_boundary(ctx, last_pt.value(), pt, Side_of_boundary::Bottom); + } + } else { + if(pt.y() < ctx->ymin()) { + update_on_crossing_boundary(ctx, last_pt.value(), pt, Side_of_boundary::Bottom); + } else if(pt.y() > ctx->ymax()) { + update_on_crossing_boundary(ctx, last_pt.value(), pt, Side_of_boundary::Top); + } + } + if(last_pt->x() <= ctx->xmax() && pt.x() > ctx->xmax()) { + update_on_crossing_boundary(ctx, last_pt.value(), pt, Side_of_boundary::Right); + } + + if(!(pt.y() > ctx->ymax() && last_pt->y() > ctx->ymax() || + pt.y() < ctx->ymin() && last_pt->y() < ctx->ymin())) { + *ctx.out_it++ = pt; + } + } else { + *ctx.out_it++ = pt; + } + + last_pt = pt; + }), + true); + + return polyline; + } + +private: + const Bounded_render_context& m_ctx; + const Approximate_2 m_approximate_2; +}; + +/** + * @brief Functor to approximate an x-monotone curve within an bounding box. + * The bbox here has closed boundary. + * + * The Approximation is done from xmin to xmax with a given step. For parts outbound the y limits and precedes or + * succeeds a part within, the approximation may be skipped but there will be at least one point outside the bbox + * for indication. + * + */ +template +using Arr_bounded_approximate_curve_2 = Arr_bounded_approximate_curve_2_impl< + Arrangement, + has_approximate_2_object_v && + has_operator_xcv_v>; + +} // namespace draw_aos } // namespace CGAL #endif // CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_CURVE_2_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_face_2.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_face_2.h index 851ce684c29..9f2d6190b30 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_face_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_face_2.h @@ -1,45 +1,37 @@ #ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_FACE_2_H #define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_FACE_2_H +#include +#include +#include +#include +#include +#include + +#include + #include "CGAL/Arr_enums.h" #include "CGAL/Bbox_2.h" #include "CGAL/Draw_aos/Arr_bounded_approximate_curve_2.h" #include "CGAL/Draw_aos/Arr_bounded_approximate_point_2.h" #include "CGAL/Draw_aos/Arr_bounded_face_triangulator.h" #include "CGAL/Draw_aos/Arr_render_context.h" -#include "CGAL/basic.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "CGAL/Draw_aos/type_utils.h" namespace CGAL { -namespace internal { +namespace draw_aos { /** * @brief Patches corners between two boundary points of the bbox * counter-clockwisely. */ +template class Patch_boundary { - using Approx_point = Arr_approximation_geometry_traits::Approx_point; - - enum class Side_of_boundary { - Top = 0, - Left = 1, - Bottom = 2, - Right = 3, - None = -1, - }; + using Approx_point = typename Arr_approximation_geometry_traits::Approx_point; private: - Side_of_boundary side_of_boundary(const Approx_point& pt) const { + Side_of_boundary side_of_boundary(Approx_point pt) const { if(m_bbox.xmin() <= pt.x() && pt.x() < m_bbox.xmax() && pt.y() == m_bbox.ymax()) { return Side_of_boundary::Top; } else if(pt.x() == m_bbox.xmin() && m_bbox.ymin() <= pt.y() && pt.y() < m_bbox.ymax()) { @@ -83,9 +75,8 @@ private: return static_cast((static_cast(side) + 1) % 4); } - bool is_on_boundary(const Approx_point& pt) const { return side_of_boundary(pt) != Side_of_boundary::None; } - - double distance_on_same_side(const Approx_point& pt1, const Approx_point& pt2) const { + // Computes the distance between two points with the precondition that they are on the same side of the boundary. + double distance_on_same_side(Approx_point pt1, Approx_point pt2) const { return std::abs(pt1.x() - pt2.x()) + std::abs(pt1.y() - pt2.y()); } @@ -93,8 +84,11 @@ public: Patch_boundary(Bbox_2 bbox) : m_bbox(bbox) {} + /** + * @brief Patch the boundary between two points on the boundary of the bbox counter-clockwisely. + */ template - void operator()(const Approx_point& from, const Approx_point& to, OutputIterator out_it) const { + void operator()(Approx_point from, Approx_point to, OutputIterator out_it) const { auto from_side = side_of_boundary(from); auto to_side = side_of_boundary(to); @@ -117,21 +111,39 @@ public: continue; } *out_it++ = corner; - std::cout << "Patching corner: " << corner << std::endl; } return; } + /** + * @brief Patch all four sides. + */ + template + void operator()(OutputIterator out_it) const { + for(auto side : {Side_of_boundary::Top, Side_of_boundary::Left, Side_of_boundary::Bottom, Side_of_boundary::Right}) + { + *out_it++ = corner_of_side(side); + } + } + private: const Bbox_2 m_bbox; }; -template -class Geom_simplifier +template +class Colinear_simplifier { - using Approx_point = Arr_approximation_geometry_traits::Approx_point; + using Geom_traits = GeomTraits; + using Approx_point = typename Arr_approximation_geometry_traits::Approx_point; + +public: + using Insert_iterator = boost::function_output_iterator>; + +public: + Colinear_simplifier(OutputIterator out_it, Bbox_2 bbox) + : m_out_it(out_it) + , m_bbox(bbox) {} -private: void dump() { if(m_start.has_value()) { *m_out_it++ = m_start.value(); @@ -143,17 +155,9 @@ private: } } -public: - Geom_simplifier(OutputIterator& out_it, const Bbox_2& bbox) - : m_out_it(out_it) - , m_bbox(bbox) {} - - decltype(auto) insert_iterator() { - return boost::make_function_output_iterator([this](const Approx_point& p) { + Insert_iterator insert_iterator() { + return boost::make_function_output_iterator(std::function([this](Approx_point p) { if(m_mid.has_value()) { - if(m_mid.value() == p) { - return; - } if(p.y() == m_mid->y() && p.y() == m_start->y() || p.x() == m_mid->x() && p.x() == m_start->x()) { // Three points are collinear horizontally or vertically. m_mid = p; @@ -166,175 +170,270 @@ public: } if(m_start.has_value()) { - if(m_start.value() == p) { - return; - } m_mid = p; } else { m_start = p; } - }); + })); } - ~Geom_simplifier() { dump(); } + ~Colinear_simplifier() { dump(); } private: - OutputIterator& m_out_it; + OutputIterator m_out_it; std::optional m_start, m_mid; - Bbox_2 m_bbox; + const Bbox_2 m_bbox; }; -} // namespace internal - /** * @brief Bounded face approximation for arrangements. * @note Member functions are not thread-safe. */ +template class Arr_bounded_approximate_face_2 { - using Approx_geom_traits = Arr_approximation_geometry_traits; - using Face_const_handle = Arrangement::Face_const_handle; - using Halfedge_const_handle = Arrangement::Halfedge_const_handle; - using Vertex_const_handle = Arrangement::Vertex_const_handle; - using Polyline_geom = Approx_geom_traits::Polyline_geom; - using Ccb_halfedge_const_circulator = Arrangement::Ccb_halfedge_const_circulator; - using Approx_point = Approx_geom_traits::Approx_point; - using Triangulated_face = Approx_geom_traits::Triangulated_face; - using Patch_boundary = internal::Patch_boundary; + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Approx_traits = Arr_approximation_geometry_traits; + using Face_const_handle = typename Arrangement::Face_const_handle; + using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle; + using Vertex_const_handle = typename Arrangement::Vertex_const_handle; + using Polyline_geom = typename Approx_traits::Polyline_geom; + using Ccb_halfedge_const_circulator = typename Arrangement::Ccb_halfedge_const_circulator; + using Approx_point = typename Approx_traits::Approx_point; + using Triangulated_face = typename Approx_traits::Triangulated_face; + using Feature_portal_map = typename Arr_portals::Feature_portals_map; + using Portal_vector = typename Arr_portals::Portal_vector; + using Portal = typename Arr_portals::Portal; + using Point_or_portal = std::variant; + using FT = typename Traits_adaptor::FT; - template - using Geom_simplifier = internal::Geom_simplifier; + using Bounded_approximate_point_2 = Arr_bounded_approximate_point_2; + using Bounded_approximate_curve_2 = Arr_bounded_approximate_curve_2; + using Bounded_render_context = Arr_bounded_render_context; + + using Triangulator = Arr_bounded_face_triangulator; + using Patch_boundary = Patch_boundary; + using Simplifier = Colinear_simplifier; struct Left_to_right_tag {}; struct Right_to_left_tag {}; + struct Inner_ccb_tag + {}; + struct Outer_ccb_tag + {}; + private: - class Execution_context : public Arr_context_delegator + class Execution_context : public Arr_context_delegator { - public: - Execution_context(const Arr_bounded_render_context& ctx, - Arr_bounded_face_triangulator& triangulator, - const Patch_boundary& patch_boundary, - const Arr_bounded_approximate_point_2& bounded_approx_pt, - const Arr_bounded_approximate_curve_2& bounded_approx_curve) - : Arr_context_delegator(ctx) - , triangulator(triangulator) - , patch_boundary(patch_boundary) - , bounded_approx_pt(bounded_approx_pt) - , bounded_approx_curve(bounded_approx_curve) {} + private: + using Output_iterator = + typename Colinear_simplifier::Insert_iterator; public: - const Arr_bounded_approximate_point_2& bounded_approx_pt; - const Arr_bounded_approximate_curve_2& bounded_approx_curve; - Arr_bounded_face_triangulator& triangulator; + using Insert_iterator = boost::function_output_iterator>; + + Execution_context(const Bounded_render_context& ctx, + const Patch_boundary& patch_boundary, + Output_iterator out_it, + const Bounded_approximate_point_2& bounded_approx_pt, + const Bounded_approximate_curve_2& bounded_approx_curve) + : Arr_context_delegator(ctx) + , base_out_it(out_it) + , patch_boundary(patch_boundary) + , bounded_approx_pt(bounded_approx_pt) + , bounded_approx_curve(bounded_approx_curve) { + this->out_it = boost::make_function_output_iterator(std::function([this](Approx_point pt) { + if(!(*this)->contains_x(pt.x())) { + return; + } + + pt = Approx_point(pt.x(), std::clamp(pt.y(), (*this)->ymin(), (*this)->ymax())); + if(pt == last_pt) { + passed_fictitious_edge = false; + return; + } + + if(passed_fictitious_edge && last_pt.has_value()) { + this->patch_boundary(last_pt.value(), pt, base_out_it); + } + passed_fictitious_edge = false; + + *base_out_it++ = pt; + + if(!first_pt.has_value()) { + first_pt = pt; + } + last_pt = pt; + })); + } + // Let's not accidentally copy this object. + Execution_context(const Execution_context&) = delete; + Execution_context& operator=(const Execution_context&) = delete; + + public: + const Bounded_approximate_point_2& bounded_approx_pt; + const Bounded_approximate_curve_2& bounded_approx_curve; + Insert_iterator out_it; + std::optional last_pt, first_pt; + bool passed_fictitious_edge{false}; + Output_iterator base_out_it; const Patch_boundary& patch_boundary; }; private: + /** + * @brief Get the first halfedge on the inner ccb that should be traversed. + * + * @precondition: The vertex must not be isolated. + * @param vh + */ + static Halfedge_const_handle get_inner_ccb_first_halfedge(const Vertex_const_handle& vh) { + auto circ = vh->incident_halfedges(); + if(vh->degree() == 1) { + return circ->twin(); + } + auto curr = circ; + auto next = curr; + ++next; + // Traverse the halfedges incident to the vertex in clockwise direction. + // Note that circulator around a vertex points to a halfedge whose target is the vertex. + do { + if(curr->direction() == ARR_LEFT_TO_RIGHT && next->direction() == ARR_RIGHT_TO_LEFT) { + // This indicates that "curr" crosses 12 o'clock and reaches "next". + break; + } + ++curr; + ++next; + } while(curr != circ); + + return next->twin(); + } + static void approximate_vertex(Execution_context& ctx, const Vertex_const_handle& vh) { if(vh->is_at_open_boundary()) { return; } ctx.bounded_approx_pt(vh); - } - template - static void - approximate_halfedge_of_ccb(Execution_context& ctx, const Halfedge_const_handle& he, OutputIterator& out_it) { - if(he->is_fictitious()) { + auto portals_it = ctx->feature_portals.find(vh); + if(portals_it == ctx->feature_portals.end()) { return; } + const auto& portals = portals_it->second; + if(portals.empty()) { + return; + } + CGAL_assertion_msg(portals.size() == 1, "Vertex should have at most one portal."); + traverse_portal(ctx, portals.front()); + } - const Polyline_geom& polyline = ctx.bounded_approx_curve(he); - if(he->direction() == ARR_LEFT_TO_RIGHT) { - std::copy(polyline.begin(), polyline.end(), out_it); + template + static void approximate_halfedge(Execution_context& ctx, const Halfedge_const_handle& he, DirectionTag dir_tag) { + constexpr bool Is_left_to_right = std::is_same_v; + using Approx_point_it = std::conditional_t; + using Portals_it = std::conditional_t; + + const Polyline_geom& polyline = he->is_fictitious() ? Polyline_geom{} : ctx.bounded_approx_curve(he); + auto portal_map_it = ctx->feature_portals.find(he); + const Portal_vector& portals = + portal_map_it != ctx->feature_portals.end() ? portal_map_it->second : Portal_vector{}; + + Approx_point_it points_iter, points_end; + Portals_it portals_iter, portals_end; + if constexpr(Is_left_to_right) { + points_iter = polyline.begin(); + points_end = polyline.end(); + portals_iter = portals.begin(); + portals_end = portals.end(); } else { - std::copy(polyline.rbegin(), polyline.rend(), out_it); + points_iter = polyline.rbegin(); + points_end = polyline.rend(); + portals_iter = portals.rbegin(); + portals_end = portals.rend(); + } + + std::merge(points_iter, points_end, portals_iter, portals_end, + boost::make_function_output_iterator([&ctx](const Point_or_portal& point_or_portal) { + if(auto* portal = std::get_if(&point_or_portal)) { + traverse_portal(ctx, *portal); + return; + } + *ctx.out_it++ = std::get(point_or_portal); + }), + [](const Portal& portal, const Approx_point& pt) { + return Is_left_to_right ? portal.second->point().x() < FT(pt.x()) + : portal.second->point().x() > FT(pt.x()); + }); + } + + static void approximate_inner_ccb(Execution_context& ctx, const Vertex_const_handle& vh) { + if(vh->is_isolated()) { + approximate_vertex(ctx, vh); + return; + } + approximate_ccb(ctx, get_inner_ccb_first_halfedge(vh)); + } + + static void traverse_portal(Execution_context& ctx, const Portal& portal) { // We have a portal. + const auto& [source, dest] = portal; + Approx_point dest_pt = ctx->approx_pt(dest->point()); + Approx_point source_pt = source.has_value() ? source.value() : Approx_point(dest_pt.x(), ctx->ymax()); + + *ctx.out_it++ = source_pt; + approximate_inner_ccb(ctx, dest); + // We come back here after inner ccb is approximated. + *ctx.out_it++ = source_pt; + + if(!source.has_value()) { + ctx.passed_fictitious_edge = true; } } - template + template static void approximate_ccb(Execution_context& ctx, Ccb_halfedge_const_circulator start_circ) { constexpr bool Is_outer_ccb = std::is_same_v; - static_assert(Is_outer_ccb || Bounded, "Inner CCBs are impossible to be unbounded."); + static_assert(Is_outer_ccb || !Unbounded, "Inner CCBs are impossible to be unbounded."); // For unbound ccb, we start on a fictitious edge - if constexpr(!Bounded) { + if constexpr(Unbounded) { while(!start_circ->is_fictitious()) { ++start_circ; } } - auto ccb_constraint = ctx.triangulator.make_ccb_constraint(); - auto constraint_out_it = ccb_constraint.insert_iterator(); - - auto simplifier = Geom_simplifier(constraint_out_it, ctx->bbox()); - auto simplifier_out_it = simplifier.insert_iterator(); - auto circ = start_circ; - std::optional last_pt; - - // These vars are used only in unbounded ccb. - std::optional first_pt; - bool passed_fictitious_edge = false; - - auto he_process_out_it = boost::make_function_output_iterator([&](const Approx_point& pt) { - Approx_point regulated_pt(pt.x(), std::clamp(pt.y(), ctx->ymin(), ctx->ymax())); - if(last_pt == regulated_pt) { - return; - } - - *simplifier_out_it++ = regulated_pt; - - if constexpr(!Bounded) { - // TODO: nesting too deep and looks ugly - if(passed_fictitious_edge) { - passed_fictitious_edge = false; - if(last_pt.has_value()) { - ctx.patch_boundary(last_pt.value(), regulated_pt, simplifier_out_it); - } - } - if(!first_pt.has_value()) { - first_pt = regulated_pt; - } - } - - last_pt = regulated_pt; - }); - do { - if constexpr(!Bounded) { - if(circ->is_fictitious()) { - passed_fictitious_edge = true; - } + if(circ->is_fictitious()) { + ctx.passed_fictitious_edge = true; } - approximate_halfedge_of_ccb(ctx, circ, he_process_out_it); + + circ->direction() == ARR_LEFT_TO_RIGHT ? approximate_halfedge(ctx, circ, Left_to_right_tag{}) + : approximate_halfedge(ctx, circ, Right_to_left_tag{}); approximate_vertex(ctx, circ->target()); } while(++circ != start_circ); - if constexpr(!Bounded) { - if(!first_pt.has_value()) { - *simplifier_out_it++ = Approx_point(ctx->xmin(), ctx->ymin()); - *simplifier_out_it++ = Approx_point(ctx->xmin(), ctx->ymax()); - *simplifier_out_it++ = Approx_point(ctx->xmax(), ctx->ymax()); - *simplifier_out_it++ = Approx_point(ctx->xmax(), ctx->ymin()); - + if constexpr(Unbounded) { + if(ctx.first_pt.has_value()) { + ctx.patch_boundary(ctx.last_pt.value(), ctx.first_pt.value(), ctx.base_out_it); } else { - ctx.patch_boundary(last_pt.value(), first_pt.value(), simplifier_out_it); + ctx.patch_boundary(ctx.base_out_it); } } } public: - Arr_bounded_approximate_face_2(const Arr_bounded_render_context& ctx, - const Arr_bounded_approximate_point_2& point_approx, - const Arr_bounded_approximate_curve_2& curve_approx) + Arr_bounded_approximate_face_2(const Bounded_render_context& ctx, + const Bounded_approximate_point_2& bounded_approx_pt, + const Bounded_approximate_curve_2& bounded_approx_curve) : m_ctx(ctx) , m_patch_boundary(ctx.bbox()) - , m_point_approx(point_approx) - , m_curve_approx(curve_approx) {} + , m_bounded_approx_pt(bounded_approx_pt) + , m_bounded_approx_curve(bounded_approx_curve) {} const Triangulated_face& operator()(const Face_const_handle& fh) const { auto [triangulated_face, inserted] = m_ctx.cache.try_emplace(fh); @@ -346,47 +445,50 @@ public: return triangulated_face; } - CGAL_assertion_msg(!fh->is_fictitious(), "Cannot approximate a fictitious face."); + CGAL_precondition_msg(!fh->is_fictitious(), "Cannot approximate a fictitious face."); if(!fh->has_outer_ccb()) { // The face is the unbounded face of bounded arrangements, we skip approximating any non degenerate features. for(auto inner_ccb = fh->inner_ccbs_begin(); inner_ccb != fh->inner_ccbs_end(); ++inner_ccb) { - if((*inner_ccb)->twin()->face() != (*inner_ccb)->face()) { - continue; - } - m_curve_approx(*inner_ccb); + auto circ = *inner_ccb; + do { + if(circ->face() != circ->twin()->face()) { + // Found non degenerate edge, skip. + continue; + } + m_bounded_approx_curve(circ); + } while(++circ != *inner_ccb); } - for(auto isolated_vh = fh->isolated_vertices_begin(); isolated_vh != fh->isolated_vertices_end(); ++isolated_vh) { - m_point_approx(isolated_vh); + for(auto vh = fh->isolated_vertices_begin(); vh != fh->isolated_vertices_end(); ++vh) { + m_bounded_approx_pt(vh); } + return triangulated_face; } - Arr_bounded_face_triangulator triangulator(m_ctx); - Execution_context ctx(m_ctx, triangulator, m_patch_boundary, m_point_approx, m_curve_approx); + auto triangulator = Triangulator(m_ctx); + auto simplifier = Simplifier(triangulator.insert_iterator(), m_ctx.bbox()); + auto ctx = Execution_context(m_ctx, m_patch_boundary, simplifier.insert_iterator(), m_bounded_approx_pt, + m_bounded_approx_curve); if(fh->is_unbounded()) { - approximate_ccb(ctx, fh->outer_ccb()); - } else { approximate_ccb(ctx, fh->outer_ccb()); + } else { + approximate_ccb(ctx, fh->outer_ccb()); } - for(auto inner_ccb = fh->inner_ccbs_begin(); inner_ccb != fh->inner_ccbs_end(); ++inner_ccb) { - approximate_ccb(ctx, *inner_ccb); - } + simplifier.dump(); - for(auto isolated_vh = fh->isolated_vertices_begin(); isolated_vh != fh->isolated_vertices_begin(); ++isolated_vh) { - approximate_vertex(ctx, isolated_vh); - } - - return triangulated_face = (std::move(triangulator)); + return triangulated_face = std::move(triangulator); } private: - const Arr_bounded_render_context& m_ctx; - const Arr_bounded_approximate_point_2& m_point_approx; - const Arr_bounded_approximate_curve_2& m_curve_approx; + const Bounded_render_context& m_ctx; + const Bounded_approximate_point_2& m_bounded_approx_pt; + const Bounded_approximate_curve_2& m_bounded_approx_curve; const Patch_boundary m_patch_boundary; }; + +} // namespace draw_aos } // namespace CGAL #endif // CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_FACE_2_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_point_2.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_point_2.h index c768341f017..514b7e62f6e 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_point_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_point_2.h @@ -2,22 +2,26 @@ #ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_POINT_2_H #define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_POINT_2_H -#include "CGAL/Draw_aos/Arr_render_context.h" -#include -#include -#include #include +#include +#include +#include + namespace CGAL { +namespace draw_aos { + +template class Arr_bounded_approximate_point_2 { - using Approx_kernel = Arr_approximation_geometry_traits::Approximation_kernel; - using Point_2 = Geom_traits::Point_2; - using Vertex_const_handle = Arrangement::Vertex_const_handle; - using Point_geom = Arr_approximation_geometry_traits::Point_geom; + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Point_2 = typename Traits_adaptor::Point_2; + using Vertex_const_handle = typename Arrangement::Vertex_const_handle; + using Point_geom = typename Arr_approximation_geometry_traits::Point_geom; + using Bounded_render_context = Arr_bounded_render_context; public: - Arr_bounded_approximate_point_2(const Arr_bounded_render_context& ctx) + Arr_bounded_approximate_point_2(const Bounded_render_context& ctx) : m_ctx(ctx) {} /** @@ -47,9 +51,10 @@ public: } private: - const Arr_bounded_render_context& m_ctx; + const Bounded_render_context& m_ctx; }; +} // namespace draw_aos } // namespace CGAL #endif // CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_POINT_2_H diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_compute_y_at_x.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_compute_y_at_x.h deleted file mode 100644 index 27a593cda2c..00000000000 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_compute_y_at_x.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef CGAL_DRAW_AOS_ARR_BOUNDED_COMPUTE_Y_AT_X_H -#define CGAL_DRAW_AOS_ARR_BOUNDED_COMPUTE_Y_AT_X_H - -#include "CGAL/Arr_enums.h" -#include "CGAL/Draw_aos/Arr_render_context.h" -#include "CGAL/basic.h" -#include -#include -#include -#include -#include -#include - -namespace CGAL {} // namespace CGAL -#endif // CGAL_DRAW_AOS_ARR_BOUNDED_COMPUTE_Y_AT_X_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_face_triangulator.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_face_triangulator.h index 56f3b0ada95..a7c641d255f 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_face_triangulator.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_face_triangulator.h @@ -1,37 +1,55 @@ #ifndef CGAL_DRAW_AOS_ARR_FACE_TRIANGULATOR_H #define CGAL_DRAW_AOS_ARR_FACE_TRIANGULATOR_H -#include "CGAL/Constrained_triangulation_2.h" -#include "CGAL/Constrained_triangulation_face_base_2.h" -#include "CGAL/Draw_aos/Arr_approximation_geometry_traits.h" -#include "CGAL/Draw_aos/Arr_render_context.h" -#include "CGAL/Exact_predicates_inexact_constructions_kernel.h" -#include "CGAL/Triangulation_vertex_base_with_info_2.h" -#include "CGAL/mark_domain_in_triangulation.h" -#include "CGAL/number_utils.h" -#include "CGAL/unordered_flat_map.h" +#include #include -#include -#include -#include +#include #include #include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if defined(CGAL_DRAW_AOS_DEBUG) && defined(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR) +#include +#include + +template +class Arr_bounded_face_triangulator; + +template +void debug_print(const Arr_bounded_face_triangulator& triangulator); +#endif + namespace CGAL { +namespace draw_aos { /** - * @brief Triangulator a bounded face of an arrangement + * @brief Triangulate a face of an arrangement within a bounding box. * * @note The face must have an outer CCB. */ +template class Arr_bounded_face_triangulator { - using Approx_geom_traits = Arr_approximation_geometry_traits; - using Approx_kernel = Approx_geom_traits::Approximation_kernel; - using Approx_point = Approx_geom_traits::Approx_point; - using Point_vec = Approx_geom_traits::Apporx_point_vec; - using Triangle = Approx_geom_traits::Triangle; - using Triangulated_face = Approx_geom_traits::Triangulated_face; + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Approx_traits = Arr_approximation_geometry_traits; + using Approx_point = typename Approx_traits::Approx_point; + using Point_vec = typename Approx_traits::Apporx_point_vec; + using Triangle = typename Approx_traits::Triangle; + using Triangulated_face = typename Approx_traits::Triangulated_face; +#if defined(CGAL_DRAW_AOS_DEBUG) + template + friend void debug_print(const Arr_bounded_face_triangulator& triangulator); +#endif struct Point_index { @@ -43,190 +61,137 @@ class Arr_bounded_face_triangulator bool is_valid() const { return index != Invalid_index; } operator std::size_t() const { return index; } }; - using Epick = CGAL::Exact_predicates_inexact_constructions_kernel; - using Vb = CGAL::Triangulation_vertex_base_with_info_2; - using Fb = CGAL::Constrained_triangulation_face_base_2; - using Tds = CGAL::Triangulation_data_structure_2; + using Epick = Exact_predicates_inexact_constructions_kernel; + using Vb = Triangulation_vertex_base_with_info_2; + using Fb = Constrained_triangulation_face_base_2; + using Tds = Triangulation_data_structure_2; using Ct = Constrained_triangulation_2; using KPoint = Epick::Point_2; using KPoint_with_info = std::pair; - /** - * @brief RAII-style inserter for one CCB in a triangulation. - * Collects points and inserts them as a constraint on destruction. - * Only one instance per Arr_face_triangulator is allowed at a time. - */ - template - class Ccb_constraint - { - constexpr static bool Is_outer_ccb = std::is_same_v; - - friend class Arr_bounded_face_triangulator; - using Side_of_boundary = Arr_bounded_render_context::Side_of_boundary; - - Ccb_constraint(Arr_bounded_face_triangulator& triangulator) - : m_triangulator(&triangulator) - , m_ccb_start(m_triangulator->m_points.size()) { - triangulator.m_has_active_constraint = true; - } - - private: - std::vector& points() { return m_triangulator->m_points; } - const std::vector& points() const { return m_triangulator->m_points; } - auto first_point() const { return points()[m_ccb_start].first; } - auto last_point() const { return points().back().first; } - const Arr_bounded_render_context& ctx() const { return m_triangulator->m_ctx; } - void add_point(const KPoint& pt) { points().emplace_back(pt, points().size()); } - std::size_t ccb_size() const { return m_triangulator->m_points.size() - m_ccb_start - m_helper_indices.size(); } - - KPoint offset_boundary_point(const KPoint& pt, Side_of_boundary side, double offset) const { - CGAL_precondition(side != Side_of_boundary::None); - switch(side) { - case Side_of_boundary::Left: - return KPoint(pt.x() - offset, pt.y()); - case Side_of_boundary::Right: - return KPoint(pt.x() + offset, pt.y()); - case Side_of_boundary::Top: - return KPoint(pt.x(), pt.y() + offset); - case Side_of_boundary::Bottom: - return KPoint(pt.x(), pt.y() - offset); - default: - return pt; // Should not reach here - } - } - - void insert_ccb() { - auto& ct = m_triangulator->m_ct; - auto& points = m_triangulator->m_points; - - auto begin = points.begin() + m_ccb_start; - auto end = points.end(); - - if constexpr(Is_outer_ccb) { - auto helpers_iter = m_helper_indices.begin(); - auto helpers_end = m_helper_indices.end(); - - auto concrete_pt_filter = [&helpers_iter, helpers_end](std::size_t idx) { - if(helpers_iter == helpers_end) { - return true; - } - if(idx == *helpers_iter) { - ++helpers_iter; - return false; - } - return true; - }; - - auto index_to_point_with_info = [&points](std::size_t idx) { return points[idx]; }; - auto indexes_begin = boost::make_counting_iterator(m_ccb_start); - auto indexes_end = boost::make_counting_iterator(points.size()); - auto filtered_begin = boost::make_filter_iterator(concrete_pt_filter, indexes_begin, indexes_end); - auto filtered_end = boost::make_filter_iterator(concrete_pt_filter, indexes_end, indexes_end); - auto transformed_begin = boost::make_transform_iterator(filtered_begin, index_to_point_with_info); - auto transformed_end = boost::make_transform_iterator(filtered_end, index_to_point_with_info); - - ct.insert_with_info(transformed_begin, transformed_end); - } else { - ct.insert_with_info(begin, end); - } - } - - void try_add_offset(const KPoint& from, const KPoint& to) { - if(from == to) { - return; - } - auto shared_side = ctx().shared_boundary_side(from, to); - if(shared_side == Arr_bounded_render_context::Side_of_boundary::None) { - return; - } - // m_helper_indices.push_back(points().size()); - // add_point(offset_boundary_point(from, shared_side, m_offset)); - m_helper_indices.push_back(points().size()); - add_point(offset_boundary_point(KPoint((from.x() + to.x()) / 2, (from.y() + to.y()) / 2), shared_side, m_offset)); - - // TODO: we'll come back to find out if we do need to offset the second point. - // m_helper_indices.push_back(points().size()); - // add_point(offset_boundary_point(to, shared_side, m_offset)); - // Doesn't matter how much we increase the offset. - m_offset += 0.5; - } - - public: - Ccb_constraint(const Ccb_constraint&) = delete; - Ccb_constraint& operator=(const Ccb_constraint&) = delete; - Ccb_constraint(Ccb_constraint&& other) noexcept - : m_triangulator(other.m_triangulator) { - other.m_triangulator = nullptr; - } - Ccb_constraint& operator=(Ccb_constraint&& other) noexcept { - if(this != &other) { - m_triangulator = other.m_triangulator; - other.m_triangulator = nullptr; - } - return *this; - } - - auto insert_iterator() { - return boost::make_function_output_iterator([this](const Approx_point& pt) { - CGAL_assertion_msg(m_triangulator != nullptr, "Use of destructed or moved Ccb_constraint object."); - CGAL_assertion_msg(ctx().contains(pt), "Outbound point in Ccb_constraint."); - KPoint kp(pt.x(), pt.y()); - - if(Is_outer_ccb && ccb_size() != 0) { - try_add_offset(last_point(), kp); - } - - add_point(kp); - }); - } - - ~Ccb_constraint() { - if(m_triangulator == nullptr) { - return; - } - - if(Is_outer_ccb && ccb_size() != 0) { - try_add_offset(last_point(), first_point()); - } - - insert_ccb(); - m_triangulator->m_has_active_constraint = false; - m_triangulator = nullptr; - } - - private: - Arr_bounded_face_triangulator* m_triangulator; - const std::size_t m_ccb_start; - - // These are used only for outer CCBs. - double m_offset = 0.5; // Doesn't matter how much we offset. - std::vector m_helper_indices; // The offseted point indices when inserting outer ccb constraint - }; + using Bounded_render_context = Arr_bounded_render_context; public: - Arr_bounded_face_triangulator(const Arr_bounded_render_context& ctx) + using Insert_iterator = boost::function_output_iterator>; + +private: + static KPoint transform_point(Approx_point pt) { return KPoint(pt.x(), pt.y()); } + + static Approx_point offset_boundary_point(Approx_point pt, Side_of_boundary side, double offset) { + CGAL_precondition(side != Side_of_boundary::None); + switch(side) { + case Side_of_boundary::Left: + return Approx_point(pt.x() - offset, pt.y()); + case Side_of_boundary::Right: + return Approx_point(pt.x() + offset, pt.y()); + case Side_of_boundary::Top: + return Approx_point(pt.x(), pt.y() + offset); + case Side_of_boundary::Bottom: + return Approx_point(pt.x(), pt.y() - offset); + default: + return pt; // Should not reach here + } + } + + void insert_ccb() { + auto begin = m_points.begin(); + auto end = m_points.end(); + + auto helpers_iter = m_helper_indices.begin(); + auto helpers_end = m_helper_indices.end(); + + auto concrete_pt_filter = [&helpers_iter, helpers_end](std::size_t idx) { + if(helpers_iter == helpers_end) { + return true; + } + if(idx == *helpers_iter) { + ++helpers_iter; + return false; + } + return true; + }; + + auto indexes_begin = boost::make_counting_iterator(0); + auto indexes_end = boost::make_counting_iterator(m_points.size()); + auto filtered_begin = boost::make_filter_iterator(concrete_pt_filter, indexes_begin, indexes_end); + auto filtered_end = boost::make_filter_iterator(concrete_pt_filter, indexes_end, indexes_end); + auto index_to_point_with_info = [this](std::size_t idx) -> KPoint_with_info { + return std::make_pair(transform_point(m_points[idx]), idx); + }; + auto transformed_begin = boost::make_transform_iterator(filtered_begin, index_to_point_with_info); + auto transformed_end = boost::make_transform_iterator(filtered_end, index_to_point_with_info); + + m_ct.template insert_with_info(transformed_begin, transformed_end); + } + + Side_of_boundary shared_boundary_side(const Approx_point& pt1, const Approx_point& pt2) const { + if(pt1.x() == m_ctx.xmin() && pt2.x() == m_ctx.xmin() && m_ctx.contains_y(pt1.y()) && m_ctx.contains_y(pt2.y())) { + return Side_of_boundary::Left; + } else if(pt1.x() == m_ctx.xmax() && pt2.x() == m_ctx.xmax() && m_ctx.contains_y(pt1.y()) && + m_ctx.contains_y(pt2.y())) + { + return Side_of_boundary::Right; + } else if(pt1.y() == m_ctx.ymin() && pt2.y() == m_ctx.ymin() && m_ctx.contains_x(pt1.x()) && + m_ctx.contains_x(pt2.x())) + { + return Side_of_boundary::Bottom; + } else if(pt1.y() == m_ctx.ymax() && pt2.y() == m_ctx.ymax() && m_ctx.contains_x(pt1.x()) && + m_ctx.contains_x(pt2.x())) + { + return Side_of_boundary::Top; + } + return Side_of_boundary::None; + } + + void add_boundary_helper_point(Approx_point from, Approx_point to) { + if(from == to) { + return; + } + auto shared_side = shared_boundary_side(from, to); + if(shared_side == Side_of_boundary::None) { + return; + } + m_helper_indices.push_back(m_points.size()); + m_points.emplace_back( + offset_boundary_point(Approx_point((from.x() + to.x()) / 2, (from.y() + to.y()) / 2), shared_side, m_offset)); + m_offset += 0.5; + } + +public: + Arr_bounded_face_triangulator(const Bounded_render_context& ctx) : m_ctx(ctx) {} - Arr_bounded_face_triangulator(const Arr_bounded_face_triangulator& other) = delete; - Arr_bounded_face_triangulator& operator=(const Arr_bounded_face_triangulator& other) = delete; + + Insert_iterator insert_iterator() { + return boost::make_function_output_iterator(std::function([this](Approx_point pt) { + CGAL_assertion_msg(m_ctx.contains(pt), "Outbound point in Ccb_constraint."); + + if(m_points.size() != 0) { + add_boundary_helper_point(m_points.back(), pt); + } + m_points.emplace_back(pt); + })); + } operator Triangulated_face() && { - CGAL_assertion(!m_has_active_constraint && "There is an active constraint in the triangulator."); - CGAL_assertion(m_outer_ccb_processed && "Outer CCB has not been processed yet."); - if(m_points.empty() || m_ct.number_of_faces() == 0) { + if(m_points.empty()) { return Triangulated_face(); } + add_boundary_helper_point(m_points.back(), m_points.front()); + insert_ccb(); // insert_constraint() should be called after insert_with_info(), or info will not be set correctly. - auto first_of_pair = [](const KPoint_with_info& pt_with_info) { return pt_with_info.first; }; - for(std::size_t i = 0; i < m_ccb_start_indices.size(); ++i) { - auto begin = m_points.begin() + m_ccb_start_indices[i]; - auto end = i + 1 < m_ccb_start_indices.size() ? m_points.begin() + m_ccb_start_indices[i + 1] : m_points.end(); + m_ct.insert_constraint(boost::make_transform_iterator(m_points.begin(), transform_point), + boost::make_transform_iterator(m_points.end(), transform_point), true); - m_ct.insert_constraint(boost::make_transform_iterator(begin, first_of_pair), - boost::make_transform_iterator(end, first_of_pair), true); +#if defined(CGAL_DRAW_AOS_DEBUG) + debug_print(*this); +#endif + + if(m_ct.number_of_faces() == 0) { + return Triangulated_face(); } - unordered_flat_map in_domain_map; + unordered_flat_map in_domain_map; boost::associative_property_map in_domain(in_domain_map); CGAL::mark_domain_in_triangulation(m_ct, in_domain); @@ -246,39 +211,57 @@ public: tf.triangles.emplace_back(tri); } - auto transform_first_of_pair = [](const KPoint_with_info& pt_with_info) { - return Approx_point(CGAL::to_double(pt_with_info.first.x()), CGAL::to_double(pt_with_info.first.y())); - }; - tf.points = Point_vec(boost::make_transform_iterator(m_points.begin(), transform_first_of_pair), - boost::make_transform_iterator(m_points.end(), transform_first_of_pair)); + tf.points = std::move(m_points); return tf; } - /** - * @brief Get an constraint object for a certain ccb. - * @note Only one Ccb_constraint can be active per triangulator at a certain time point. When it goes out of scope, - * the points collected will be inserted as a constraint into the triangulation. - */ - template - Ccb_constraint make_ccb_constraint() { - if constexpr(std::is_same_v) { - CGAL_assertion_msg(!m_outer_ccb_processed, "Outer CCB has already been processed."); - m_outer_ccb_processed = true; - } - CGAL_assertion_msg(!m_has_active_constraint, "Only one Ccb_constraint can be active per triangulator at a time."); - m_ccb_start_indices.push_back(m_points.size()); - return Ccb_constraint(*this); - } - private: - const Arr_bounded_render_context& m_ctx; + const Bounded_render_context& m_ctx; Ct m_ct; - std::vector m_points; - std::vector m_ccb_start_indices; - bool m_has_active_constraint = false; - bool m_outer_ccb_processed = false; + std::vector m_points; + double m_offset = 0.5; // Doesn't matter how much we offset. + std::vector m_helper_indices; // The offseted point indices when inserting outer ccb constraint }; +#if defined(CGAL_DRAW_AOS_DEBUG) && defined(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR) +template +void debug_print(const Arr_bounded_face_triangulator& triangulator) { + const auto& ctx = triangulator.m_ctx; + const auto& m_points = triangulator.m_points; + const auto& m_helper_indices = triangulator.m_helper_indices; + + using Path = std::filesystem::path; + Path debug_dir(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR); + std::string index_file_name = "index.txt"; + Path index_file_path = debug_dir / index_file_name; + std::string ccb_file_name = "ccb_" + std::to_string(*ctx.debug_counter) + ".txt"; + std::string ccb_constraint_file_name = "ccb_constraint_" + std::to_string(*ctx.debug_counter) + ".txt"; + Path ccb_file_path = debug_dir / ccb_file_name; + Path ccb_constraint_file_path = debug_dir / ccb_constraint_file_name; + const_cast(*ctx.debug_counter)++; + + std::ofstream ofs_index(index_file_path, std::ios::app); + ofs_index << ccb_file_name << "\n" << ccb_constraint_file_name << std::endl; + + std::ofstream ofs_ccb(ccb_file_path); + std::size_t helper_indices_index = 0; + for(std::size_t i = 0; i < m_points.size(); ++i) { + const auto& pt = m_points[i]; + if(helper_indices_index < m_helper_indices.size() && i == m_helper_indices[helper_indices_index]) { + helper_indices_index++; + continue; + } + ofs_ccb << pt.x() << " " << pt.y() << "\n"; + } + + std::ofstream ofs_ccb_constraint(ccb_constraint_file_path); + for(const auto& pt : m_points) { + ofs_ccb_constraint << pt.x() << " " << pt.y() << "\n"; + } +} +#endif // CGAL_DRAW_AOS_DEBUG && CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR + +} // namespace draw_aos } // namespace CGAL #endif // CGAL_DRAW_AOS_ARR_FACE_TRIANGULATOR_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_renderer.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_renderer.h index 8301a59221e..8ee79ebd442 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_renderer.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_renderer.h @@ -1,44 +1,56 @@ #ifndef CGAL_DRAW_AOS_ARR_BOUNDED_RENDERER_H #define CGAL_DRAW_AOS_ARR_BOUNDED_RENDERER_H -#include "CGAL/Arr_trapezoid_ric_point_location.h" -#include "CGAL/Bbox_2.h" -#include "CGAL/Draw_aos/Arr_approximation_cache.h" -#include "CGAL/Draw_aos/Arr_approximation_geometry_traits.h" -#include "CGAL/Draw_aos/Arr_bounded_approximate_curve_2.h" -#include "CGAL/Draw_aos/Arr_bounded_approximate_face_2.h" -#include "CGAL/Draw_aos/Arr_render_context.h" -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + namespace CGAL { +namespace draw_aos { + /** * @brief Render arrangement on surface within a bounding box. * * @note The class is not thread-safe. */ +template class Arr_bounded_renderer { using Color = IO::Color; - using Point_2 = Geom_traits::Point_2; - using Vertex_const_handle = Arrangement::Vertex_const_handle; - using Edge_const_handle = Arrangement::Edge_const_iterator; - using Halfedge_const_handle = Arrangement::Halfedge_const_handle; - using Face_const_handle = Arrangement::Face_const_handle; - using Vertex_handle = Arrangement::Vertex_handle; - using Halfedge_handle = Arrangement::Halfedge_handle; - using Face_handle = Arrangement::Face_handle; - using X_monotone_curve_2 = Geom_traits::X_monotone_curve_2; + using Geom_traits = typename Arrangement::Geometry_traits_2; + using FT = typename Traits_adaptor::FT; + using Point_2 = typename Traits_adaptor::Point_2; + using X_monotone_curve_2 = typename Traits_adaptor::X_monotone_curve_2; + using Vertex_const_handle = typename Arrangement::Vertex_const_handle; + using Edge_const_handle = typename Arrangement::Edge_const_iterator; + using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle; + using Face_const_handle = typename Arrangement::Face_const_handle; + using Vertex_handle = typename Arrangement::Vertex_handle; + using Halfedge_handle = typename Arrangement::Halfedge_handle; + using Face_handle = typename Arrangement::Face_handle; using Point_Location = Arr_trapezoid_ric_point_location; using Feature_const = std::variant; using Feature_const_vector = std::vector; using Feature_const_vector_inserter = std::back_insert_iterator; - using Arr_approx_geom_traits = Arr_approximation_geometry_traits; - using Point_geom = Arr_approx_geom_traits::Point_geom; - using Polyline_geom = Arr_approx_geom_traits::Polyline_geom; - using Feature_portal_map = Arr_portals::Feature_portals_map; + using Approx_traits = Arr_approximation_geometry_traits; + using Point_geom = typename Approx_traits::Point_geom; + using Polyline_geom = typename Approx_traits::Polyline_geom; + using Feature_portal_map = typename Arr_portals::Feature_portals_map; + using Bounded_render_context = Arr_bounded_render_context; + using Render_context = Arr_render_context; + using Bounded_approx_point_2 = Arr_bounded_approximate_point_2; + using Bounded_approx_curve_2 = Arr_bounded_approximate_curve_2; + using Bounded_approx_face_2 = Arr_bounded_approximate_face_2; + using Approx_cache = Arr_approximation_cache; + // QFlags implement this pattern better, but we try not to reply on Qt classes. template class Arr_flags @@ -65,46 +77,62 @@ class Arr_bounded_renderer Face = 1 << 2, }; - struct Execution_context : Arr_context_delegator + struct Execution_context : Arr_context_delegator { - Execution_context(const Arr_bounded_render_context& ctx) - : Arr_context_delegator(ctx) + Execution_context(const Bounded_render_context& ctx) + : Arr_context_delegator(ctx) , bounded_approx_pt(ctx) - , bounded_approx_curve(ctx, bounded_approx_pt) + , bounded_approx_curve(ctx) , bounded_approx_face(ctx, bounded_approx_pt, bounded_approx_curve) {} - const Arr_bounded_approximate_point_2 bounded_approx_pt; - const Arr_bounded_approximate_curve_2 bounded_approx_curve; - const Arr_bounded_approximate_face_2 bounded_approx_face; + const Bounded_approx_point_2 bounded_approx_pt; + const Bounded_approx_curve_2 bounded_approx_curve; + const Bounded_approx_face_2 bounded_approx_face; }; private: - template - static void locate_intersecting_features(const Execution_context& ctx, + static Face_const_handle inbound_face_of_edge(const Halfedge_const_handle& he, Side_of_boundary side) { + bool is_left_to_right = he->direction() == ARR_LEFT_TO_RIGHT; + switch(side) { + case Side_of_boundary::Top: + case Side_of_boundary::Left: + return is_left_to_right ? he->twin()->face() : he->face(); + case Side_of_boundary::Bottom: + case Side_of_boundary::Right: + return is_left_to_right ? he->face() : he->twin()->face(); + default: + CGAL_assertion(false && "Invalid side of boundary"); + } + return Face_const_handle(); + } + static void approx_intersecting_features(Execution_context& ctx, const X_monotone_curve_2& curve, - OutputIterator out_iter, + Side_of_boundary side, Arr_flags feats) { + CGAL_assertion(side != Side_of_boundary::None); using Feature = std::variant; using Feature_vector = std::vector; - auto func_out_iter = boost::make_function_output_iterator([&out_iter, &feats](const Feature& feature) { + auto func_out_iter = boost::make_function_output_iterator([&ctx, feats, side](const Feature& feature) { if(auto* vh = std::get_if(&feature)) { if(!feats.is_set(Feature_type::Vertex) || (*vh)->is_at_open_boundary()) { return; } - *out_iter++ = Vertex_const_handle(*vh); + ctx.bounded_approx_pt(*vh); } else if(auto* he = std::get_if(&feature)) { if(!feats.is_set(Feature_type::Halfedge) || (*he)->is_fictitious()) { return; } - *out_iter++ = Halfedge_const_handle(*he); + ctx.bounded_approx_curve(*he); + + // There's a rare case that some faces' outer ccb overlaps with the bounding box edges, causing + // no face to be discovered. We need to approximate the inbound face incident to the halfedge + discover_faces(ctx, inbound_face_of_edge(*he, side)); } else if(auto* fh = std::get_if(&feature)) { if(!feats.is_set(Feature_type::Face)) { return; } - *out_iter++ = Face_const_handle(*fh); - } else { - CGAL_assertion(false && "Unexpected feature type"); + discover_faces(ctx, *fh); } }); @@ -126,14 +154,16 @@ private: ctx.bounded_approx_face(fh); for(auto inner_ccb = fh->inner_ccbs_begin(); inner_ccb != fh->inner_ccbs_end(); ++inner_ccb) { - auto he = *inner_ccb; - auto inner_face = he->twin()->face(); + auto circ = *inner_ccb; - if(inner_face == fh || !ctx->strictly_contains(inner_face->outer_ccb()->source()->point())) { - continue; - } - - discover_faces(ctx, inner_face); + // We have to traverse the entire inner ccb instead of using arbitary vertex, + // because the inner ccb may contain degenerate edges. + do { + auto inner_face = circ->twin()->face(); + if(inner_face != fh && ctx->strictly_contains(circ->source()->point())) { + discover_faces(ctx, inner_face); + } + } while(++circ != *inner_ccb); } // We don't need to handle isolated vertices. @@ -153,8 +183,7 @@ private: continue; } - bool within_bounds = ctx->strictly_contains(adj_face->outer_ccb()->source()->point()); - if(!within_bounds) { + if(!ctx->strictly_contains(adj_face->outer_ccb()->source()->point())) { continue; } // For a face that is not one of the seeding faces, @@ -165,12 +194,16 @@ private: } public: - Arr_bounded_renderer(Arr_render_context& ctx, Bbox_2 bbox) + Arr_bounded_renderer(const Render_context& ctx, Bbox_2 bbox) : m_ctx(ctx) + , to_ft() , m_bbox(bbox) {} - Arr_approximation_cache render() const { - Arr_approximation_cache cache; + Approx_cache render() const { + Approx_cache cache; + cache.reserve_face_cache(m_ctx.arr.number_of_faces()); + cache.reserve_halfedge_cache(m_ctx.arr.number_of_halfedges()); + cache.reserve_vertex_cache(m_ctx.arr.number_of_vertices()); if(m_ctx.is_cancelled()) { return cache; @@ -178,38 +211,28 @@ public: Execution_context ctx(Arr_bounded_render_context(m_ctx, m_bbox, cache)); - auto insert_features = boost::make_function_output_iterator([&ctx](const Feature_const& feature) { - if(auto* vh = std::get_if(&feature)) { - ctx.bounded_approx_pt(*vh); - } else if(auto* he = std::get_if(&feature)) { - ctx.bounded_approx_curve(*he); - } else if(auto* fh = std::get_if(&feature)) { - discover_faces(ctx, *fh); - } else { - CGAL_assertion(false && "Unexpected feature type"); - } - }); - - auto top = ctx->cst_horizontal_segment(ctx->ymax(), ctx->xmin(), ctx->xmax()); - auto bottom = ctx->cst_horizontal_segment(ctx->ymin(), ctx->xmin(), ctx->xmax()); - auto left = ctx->cst_vertical_segment(ctx->xmin(), ctx->ymin(), ctx->ymax()); - auto right = ctx->cst_vertical_segment(ctx->xmax(), ctx->ymin(), ctx->ymax()); + auto top = ctx->cst_horizontal_segment(to_ft(ctx->ymax()), to_ft(ctx->xmin()), to_ft(ctx->xmax())); + auto bottom = ctx->cst_horizontal_segment(to_ft(ctx->ymin()), to_ft(ctx->xmin()), to_ft(ctx->xmax())); + auto left = ctx->cst_vertical_segment(to_ft(ctx->xmin()), to_ft(ctx->ymin()), to_ft(ctx->ymax())); + auto right = ctx->cst_vertical_segment(to_ft(ctx->xmax()), to_ft(ctx->ymin()), to_ft(ctx->ymax())); // top, left are open edges while bottom, right are closed. - locate_intersecting_features(ctx, top, insert_features, Feature_type::Face); - locate_intersecting_features(ctx, left, insert_features, Feature_type::Face); - locate_intersecting_features(ctx, bottom, insert_features, {Feature_type::Face, Feature_type::Halfedge}); - locate_intersecting_features(ctx, right, insert_features, + approx_intersecting_features(ctx, top, Side_of_boundary::Top, Feature_type::Face); + approx_intersecting_features(ctx, left, Side_of_boundary::Left, Feature_type::Face); + approx_intersecting_features(ctx, bottom, Side_of_boundary::Bottom, {Feature_type::Face, Feature_type::Halfedge}); + approx_intersecting_features(ctx, right, Side_of_boundary::Right, {Feature_type::Face, Feature_type::Halfedge, Feature_type::Vertex}); return cache; } private: - Arr_render_context m_ctx; + const Render_context& m_ctx; + const Construct_coordinate to_ft; const Bbox_2 m_bbox; }; +} // namespace draw_aos } // namespace CGAL #endif // CGAL_DRAW_AOS_ARR_BOUNDED_RENDERER_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_compute_y_at_x.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_compute_y_at_x.h deleted file mode 100644 index 98610a1dece..00000000000 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_compute_y_at_x.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef CGAL_DRAW_AOS_ARR_COMPUTE_Y_AT_X_H -#define CGAL_DRAW_AOS_ARR_COMPUTE_Y_AT_X_H -#include "CGAL/Bbox_2.h" -#include "CGAL/Draw_aos/Arr_render_context.h" -#include "CGAL/Draw_aos/helpers.h" -#include - -namespace CGAL { - -/** - * @brief Functor to compute the y-coordinate at a given x-coordinate for an x-monotone curve within a bounding box. - */ -class Arr_compute_y_at_x -{ -public: - using Point_2 = Geom_traits::Point_2; - using X_monotone_curve_2 = Geom_traits::X_monotone_curve_2; - using Intersect_2 = Geom_traits::Intersect_2; - using Construct_min_vertex_2 = Geom_traits::Construct_min_vertex_2; - using FT = Geom_traits::FT; - using Approximate_2 = Geom_traits::Approximate_2; - using Is_vertical_2 = Geom_traits::Is_vertical_2; - - Arr_compute_y_at_x(const Arr_render_context& ctx) - : m_ctx(ctx) - // TODO: some traits does not have approximate_2_object. we'll need a specialization for them. - , m_approx(ctx.traits.approximate_2_object()) {} - - /** - * @brief Computes the y-coordinate at a given x-coordinate for an x-monotone curve trimmed - * to the bounding box. - * - * The bounding box here is considered as closed. - * - * @precondition The curve is not verical - * @param curve - * @param x - * @return true if there is an intersection at given x within the bounding box, - * @return false otherwise. - */ - std::optional operator()(const X_monotone_curve_2& curve, const FT& x) const { - CGAL_assertion(!m_ctx.is_vertical_2(curve)); - - auto min_pt = m_ctx.cst_curve_end(curve, ARR_MIN_END); - auto max_pt = m_ctx.cst_curve_end(curve, ARR_MAX_END); - if(min_pt.has_value() && min_pt->x() == x) { - return min_pt->y(); - } - if(max_pt.has_value() && max_pt->x() == x) { - return max_pt->y(); - } - - using Multiplicity = Geom_traits::Multiplicity; - using Intersect_point = std::pair; - using Intersect_curve = X_monotone_curve_2; - using Intersect_type = std::variant; - - auto vertical_line = m_ctx.cst_vertical_segment(x, m_ymin, m_ymax); - std::optional y; - auto func_out_iter = boost::make_function_output_iterator( - [&y, this](const Intersect_type& res) { y = std::get(res).first.y(); }); - m_ctx.intersect_2(curve, vertical_line, func_out_iter); - return y; - } - -private: - Approximate_2 m_approx; - const Arr_render_context& m_ctx; - - // Should be enough for visualization purposes. - constexpr static double m_ymin = std::numeric_limits::lowest(); - constexpr static double m_ymax = std::numeric_limits::max(); -}; - -} // namespace CGAL - -#endif // CGAL_DRAW_AOS_ARR_COMPUTE_Y_AT_X_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_construct_curve_end.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_construct_curve_end.h index c27a5e1afc2..0fa916082ce 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_construct_curve_end.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_construct_curve_end.h @@ -1,23 +1,24 @@ #ifndef CGAL_ARR_CONSTRUCT_CURVE_END_H #define CGAL_ARR_CONSTRUCT_CURVE_END_H -#include "CGAL/Arr_enums.h" -#include "CGAL/Arr_has.h" -#include "CGAL/Draw_aos/Arr_approximation_geometry_traits.h" #include -namespace CGAL { +#include +#include +#include +namespace CGAL { +namespace draw_aos { namespace internal { -template +template class Arr_construct_curve_end_base { - using Construct_min_vertex_2 = typename Geom_traits::Construct_min_vertex_2; - using Construct_max_vertex_2 = typename Geom_traits::Construct_max_vertex_2; + using Construct_min_vertex_2 = typename GeomTraits::Construct_min_vertex_2; + using Construct_max_vertex_2 = typename GeomTraits::Construct_max_vertex_2; protected: - Arr_construct_curve_end_base(const Geom_traits& traits) + Arr_construct_curve_end_base(const GeomTraits& traits) : m_cst_min_vertex(traits.construct_min_vertex_2_object()) , m_cst_max_vertex(traits.construct_max_vertex_2_object()) {} @@ -25,21 +26,21 @@ protected: Construct_min_vertex_2 m_cst_min_vertex; }; -template +template class Arr_construct_curve_end_impl; -template -class Arr_construct_curve_end_impl : public Arr_construct_curve_end_base +template +class Arr_construct_curve_end_impl : public Arr_construct_curve_end_base { - using Approx_geom_traits = Arr_approximation_geometry_traits; - using Point_2 = typename Geom_traits::Point_2; - using X_monotone_curve = typename Geom_traits::X_monotone_curve_2; - using Parameter_space_in_x_2 = typename Geom_traits::Parameter_space_in_x_2; - using Parameter_space_in_y_2 = typename Geom_traits::Parameter_space_in_y_2; + using Approx_geom_traits = Arr_approximation_geometry_traits; + using Point_2 = typename Traits_adaptor::Point_2; + using X_monotone_curve = typename Traits_adaptor::X_monotone_curve_2; + using Parameter_space_in_x_2 = typename GeomTraits::Parameter_space_in_x_2; + using Parameter_space_in_y_2 = typename GeomTraits::Parameter_space_in_y_2; public: - Arr_construct_curve_end_impl(const Geom_traits& traits) - : Arr_construct_curve_end_base(traits) + Arr_construct_curve_end_impl(const GeomTraits& traits) + : Arr_construct_curve_end_base(traits) , m_param_space_in_x(traits.parameter_space_in_x_2_object()) , m_param_space_in_y(traits.parameter_space_in_y_2_object()) {} @@ -67,16 +68,16 @@ private: Parameter_space_in_y_2 m_param_space_in_y; }; -template -class Arr_construct_curve_end_impl : public Arr_construct_curve_end_base +template +class Arr_construct_curve_end_impl : public Arr_construct_curve_end_base { - using Approx_geom_traits = Arr_approximation_geometry_traits; - using Point_2 = typename Geom_traits::Point_2; - using X_monotone_curve = typename Geom_traits::X_monotone_curve_2; + using Approx_geom_traits = Arr_approximation_geometry_traits; + using Point_2 = typename Traits_adaptor::Point_2; + using X_monotone_curve = typename Traits_adaptor::X_monotone_curve_2; public: - Arr_construct_curve_end_impl(const Geom_traits& traits) - : Arr_construct_curve_end_base(traits) {} + Arr_construct_curve_end_impl(const GeomTraits& traits) + : Arr_construct_curve_end_base(traits) {} /** * @brief Construct the min or max vertex of the x-monotone curve based on the curve end enum. @@ -92,10 +93,13 @@ public: } // namespace internal -template +template using Arr_construct_curve_end = - internal::Arr_construct_curve_end_impl::value>; + internal::Arr_construct_curve_end_impl::Has_unbounded_curves && + has_parameter_space_in_x_2::value>; +} // namespace draw_aos } // namespace CGAL #endif // CGAL_ARR_CONSTRUCT_CURVE_END_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_construct_segments.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_construct_segments.h index 346d6989038..80195c95f2d 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_construct_segments.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_construct_segments.h @@ -1,45 +1,164 @@ #ifndef CGAL_DRAW_AOS_ARR_CONSTRUCT_SEGMENTS_H #define CGAL_DRAW_AOS_ARR_CONSTRUCT_SEGMENTS_H -#include "CGAL/Draw_aos/helpers.h" + +#include "CGAL/CORE/BigRat.h" +#include +#include +#include +#include namespace CGAL { +namespace draw_aos { + +template +class Arr_construct_segment_impl; + +// Default implementation for traits that models Construct_x_monotone_curve_2 +template +class Arr_construct_segment_impl +{ + using Point_2 = typename Traits_adaptor::Point_2; + using X_monotone_curve_2 = typename Traits_adaptor::X_monotone_curve_2; + using Construct_x_monotone_curve_2 = typename GeomTraits::Construct_x_monotone_curve_2; + using FT = typename Traits_adaptor::FT; + +public: + Arr_construct_segment_impl(const GeomTraits& traits) + : m_cst_x_curve(traits.construct_x_monotone_curve_2_object()) {} + + X_monotone_curve_2 operator()(FT x1, FT y1, FT x2, FT y2) const { + return m_cst_x_curve(Point_2(x1, y1), Point_2(x2, y2)); + } + +private: + const Construct_x_monotone_curve_2 m_cst_x_curve; +}; + +// Specialization for Arr_circle_segment_traits_2 +template +class Arr_construct_segment_impl, false> +{ + using Geom_traits = Arr_circle_segment_traits_2; + using Point_2 = typename Traits_adaptor::Point_2; + using X_monotone_curve_2 = typename Traits_adaptor::X_monotone_curve_2; + using Line_2 = typename X_monotone_curve_2::Line_2; + using Approximate_2 = typename Geom_traits::Approximate_2; + using NT = typename Traits_adaptor::FT; + using FT = typename Kernel::FT; + +public: + Arr_construct_segment_impl(const Geom_traits& traits) {} + + X_monotone_curve_2 operator()(NT x1, NT y1, NT x2, NT y2) const { + using Kernel_point_2 = typename Kernel::Point_2; + return X_monotone_curve_2(Kernel_point_2(CGAL::to_double(x1), CGAL::to_double(y1)), + Kernel_point_2(CGAL::to_double(x2), CGAL::to_double(y2))); + } +}; + +template +class Arr_construct_segment_impl +{ + static_assert(false, "Not implemented yet!"); +}; + +template +using Arr_construct_segment = + Arr_construct_segment_impl::value>; + +template class Arr_construct_vertical_segment { - using Point_2 = Geom_traits::Point_2; - using X_monotone_curve_2 = Geom_traits::X_monotone_curve_2; - using FT = Geom_traits::FT; + using Point_2 = typename Traits_adaptor::Point_2; + using X_monotone_curve_2 = typename Traits_adaptor::X_monotone_curve_2; + using FT = typename Traits_adaptor::FT; public: - Arr_construct_vertical_segment(const Geom_traits& traits) - : m_traits(traits) {} + Arr_construct_vertical_segment(const GeomTraits& traits) + : m_cst_seg(traits) {} - X_monotone_curve_2 operator()(const FT& x, const FT& ymin, const FT& ymax) const { - auto cst_x_curve = m_traits.construct_x_monotone_curve_2_object(); - return cst_x_curve(Point_2(x, ymin), Point_2(x, ymax)); - } + X_monotone_curve_2 operator()(FT x, FT ymin, FT ymax) const { return m_cst_seg(x, ymin, x, ymax); } private: - const Geom_traits& m_traits; + const Arr_construct_segment m_cst_seg; }; +template class Arr_construct_horizontal_segment { - using Point_2 = Geom_traits::Point_2; - using X_monotone_curve_2 = Geom_traits::X_monotone_curve_2; - using FT = Geom_traits::FT; + using Point_2 = typename Traits_adaptor::Point_2; + using X_monotone_curve_2 = typename Traits_adaptor::X_monotone_curve_2; + using FT = typename Traits_adaptor::FT; public: - Arr_construct_horizontal_segment(const Geom_traits& traits) - : m_traits(traits) {} + Arr_construct_horizontal_segment(const GeomTraits& traits) + : m_cst_seg(traits) {} - X_monotone_curve_2 operator()(FT y, FT xmin, FT xmax) const { - auto cst_x_curve = m_traits.construct_x_monotone_curve_2_object(); - return cst_x_curve(Point_2(xmin, y), Point_2(xmax, y)); - } + X_monotone_curve_2 operator()(FT y, FT xmin, FT xmax) const { return m_cst_seg(xmin, y, xmax, y); } private: - const Geom_traits& m_traits; + const Arr_construct_segment m_cst_seg; }; + +// Arr_construct_vertical_segment Specialization for Arr_rational_function_traits_2 +template +class Arr_construct_vertical_segment> +{ + using Geom_traits = Arr_rational_function_traits_2; + using Point_2 = typename Traits_adaptor::Point_2; + using X_monotone_curve_2 = typename Traits_adaptor::X_monotone_curve_2; + using Construct_x_monotone_curve_2 = typename Geom_traits::Construct_x_monotone_curve_2; + using FT = typename Traits_adaptor::FT; + using Polynomial_1 = typename Geom_traits::Polynomial_1; + +public: + Arr_construct_vertical_segment(const Geom_traits&) {} + + X_monotone_curve_2 operator()(FT x0, FT ymin, FT ymax) const { + Geom_traits traits; + auto cst_x_curve = traits.construct_x_monotone_curve_2_object(); + + // We could only construct a near vertical segment when dealing with rational functions. + Polynomial_1 x = CGAL::shift(Polynomial_1(1), 1); + Polynomial_1 x0_num(CORE::numerator(x0.lower())); + Polynomial_1 x0_denum(CORE::denominator(x0.lower())); + double k = 100; + double xmin = ymin.to_double() / k + x0.to_double(); + double xmax = ymax.to_double() / k + x0.to_double(); + Polynomial_1 p_num = x0_num * k * x - k * x0_denum; + Polynomial_1 p_denum = x0_denum; + return cst_x_curve(p_num, p_denum, xmin, xmax); + } +}; + +// Arr_construct_horizontal_segment Specialization for Arr_rational_function_traits_2 +template +class Arr_construct_horizontal_segment> +{ + using Geom_traits = Arr_rational_function_traits_2; + using Point_2 = typename Traits_adaptor::Point_2; + using X_monotone_curve_2 = typename Traits_adaptor::X_monotone_curve_2; + using FT = typename Traits_adaptor::FT; + using Polynomial_1 = typename Geom_traits::Polynomial_1; + using Construct_x_monotone_curve_2 = typename Geom_traits::Construct_x_monotone_curve_2; + +public: + Arr_construct_horizontal_segment(const Geom_traits&) {} + + X_monotone_curve_2 operator()(FT y, FT xmin, FT xmax) const { + // The traits object is stateful. Currently there's a problem with internal cache that an exception will be + // triggered after constructing a number of segments. + // So we create a new traits object instead of reusing an old one. + Geom_traits traits; + auto cst_x_curve = traits.construct_x_monotone_curve_2_object(); + // TODO: only works for CORE now, support other number types + Polynomial_1 num(CORE::numerator(y.lower())); + Polynomial_1 denum(CORE::denominator(y.lower())); + return cst_x_curve(num, denum, xmin, xmax); + } +}; + +} // namespace draw_aos } // namespace CGAL #endif \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_graph_conn.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_graph_conn.h index eb24d908a0b..05ec4a63417 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_graph_conn.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_graph_conn.h @@ -1,9 +1,12 @@ #ifndef CGAL_DRAW_AOS_ARR_GRAPH_CONN_H #define CGAL_DRAW_AOS_ARR_GRAPH_CONN_H -#include "CGAL/Union_find.h" -#include "CGAL/unordered_flat_map.h" #include + +#include +#include +#include + namespace CGAL { /** * @brief Arr_graph_conn provides fast connectivity queries for arrangement vertices @@ -23,13 +26,14 @@ private: const auto& target = he->target(); auto [source_it, source_inserted] = m_lookup.try_emplace(source, Union_find_handle()); - auto [target_it, target_inserted] = m_lookup.try_emplace(target, Union_find_handle()); if(source_inserted) { source_it->second = m_uf.make_set(source); } + auto [target_it, target_inserted] = m_lookup.try_emplace(target, Union_find_handle()); if(target_inserted) { target_it->second = m_uf.make_set(target); } + m_uf.unify_sets(source_it->second, target_it->second); } @@ -37,8 +41,13 @@ private: public: Arr_graph_conn(const Arr& arr) { - for(const auto& eh : arr.edge_handles()) { - insert_halfedge(eh); + m_lookup.reserve(arr.number_of_vertices()); + + for(const auto& he : arr.halfedge_handles()) { + if(he->direction() != ARR_LEFT_TO_RIGHT) { + continue; + } + insert_halfedge(he); } for(const auto& vh : arr.vertex_handles()) { diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_portals.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_portals.h index b4661de874a..e61b703c7fa 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_portals.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_portals.h @@ -1,21 +1,21 @@ #ifndef CGAL_DRAW_AOS_ARR_CREATE_PORTALS_H #define CGAL_DRAW_AOS_ARR_CREATE_PORTALS_H - -#include "CGAL/Arr_vertical_decomposition_2.h" -#include "CGAL/Draw_aos/Arr_approximate_point_2.h" -#include "CGAL/Draw_aos/Arr_construct_segments.h" -#include "CGAL/Draw_aos/helpers.h" -#include "CGAL/Draw_aos/Arr_graph_conn.h" -#include "CGAL/Object.h" -#include "CGAL/basic.h" -#include "CGAL/unordered_flat_map.h" -#include -#include -#include -#include #include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + namespace CGAL { +namespace draw_aos { + /** * @brief Portals are virtual vertical segments that connect the outer * connected component boundary (ccb) of a face with its inner ccbs. @@ -25,15 +25,16 @@ namespace CGAL { * hits another ccb. Eventually, faces of the arrangement become hole-free and can * be drawn with Graphics_scene. */ +template class Arr_portals { - - using Vertex_const_handle = Arrangement::Vertex_const_handle; - using Halfedge_const_handle = Arrangement::Halfedge_const_handle; - using Face_const_handle = Arrangement::Face_const_handle; - using Point_2 = Geom_traits::Point_2; - using Approx_point = Arr_approximation_geometry_traits::Approx_point; - using X_monotone_curve_2 = Geom_traits::X_monotone_curve_2; + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Vertex_const_handle = typename Arrangement::Vertex_const_handle; + using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle; + using Face_const_handle = typename Arrangement::Face_const_handle; + using Point_2 = typename Traits_adaptor::Point_2; + using Approx_point = typename Arr_approximation_geometry_traits::Approx_point; + using X_monotone_curve_2 = typename Traits_adaptor::X_monotone_curve_2; using Feature_const = std::variant; public: @@ -43,33 +44,10 @@ public: // Map from a feature to its portals sorted by the x coordinate of the virtual vertical segments. using Feature_portals_map = unordered_flat_map; -private: - // Use this function to locate the intersection point of a vertical ray shooted from a point - // to it's upper x-monotone curve(it can't be vertical, or we should've got its min vertex from vertical - // decomposition). - static Point_2 upper_intersection(const Geom_traits& traits, const Point_2& pt, const X_monotone_curve_2& curve) { - Arr_construct_vertical_segment cst_vertical_segment(traits); - Point_2 intersection_point; - auto intersect = traits.intersect_2_object(); - auto vertical_line = cst_vertical_segment(pt.x(), pt.y(), std::numeric_limits::max()); - bool found_intersection = false; - - using Multiplicity = Geom_traits::Multiplicity; - using Intersect_point = std::pair; - using Intersect_curve = X_monotone_curve_2; - using Intersect_type = std::variant; - - intersect(curve, vertical_line, boost::make_function_output_iterator([&](const Intersect_type& res) { - found_intersection = true; - if(std::holds_alternative(res)) { - intersection_point = std::get(res).first; - return; - } - CGAL_assertion(false && "Unexpected intersection type"); - })); - - return found_intersection ? intersection_point : Point_2(pt.x(), std::numeric_limits::max()); - } +public: + Arr_portals(const Geom_traits& traits) + : m_approx_pt_at_x(traits) + , m_approx_pt(traits) {} public: Feature_portals_map create(const Arrangement& arr) const { @@ -79,11 +57,12 @@ public: Arr_graph_conn conn(arr); auto visited_ccbs = std::unordered_set(); Feature_portals_map feature_portals; - auto intersect = arr.traits()->intersect_2_object(); - auto approx_pt = Arr_approximate_point_2(*arr.traits()); + const auto& traits = *arr.geometry_traits(); + auto intersect = traits.intersect_2_object(); auto func_out_iter = boost::make_function_output_iterator([&](const Vert_decomp_entry& entry) { const auto& [vh, obj_pair] = entry; + const auto& above_feat = obj_pair.second; const auto& ccb_main_vertex = conn.ccb_representative_vertex(vh); if(visited_ccbs.find(ccb_main_vertex) != visited_ccbs.end()) { @@ -91,7 +70,6 @@ public: return; } - const auto& above_feat = obj_pair.second; if(Vertex_const_handle above_vh; CGAL::assign(above_vh, above_feat)) { if(conn.is_connected(above_vh, vh)) { // This upper vertex is connected to vh, skip it @@ -99,10 +77,10 @@ public: } const auto& [it, _] = feature_portals.try_emplace(above_vh, std::vector{}); - if((above_vh)->is_at_open_boundary()) { + if(above_vh->is_at_open_boundary()) { it->second.emplace_back(std::nullopt, vh); } else { - it->second.emplace_back(approx_pt((above_vh)->point()), vh); + it->second.emplace_back(m_approx_pt(above_vh->point()), vh); } } else if(Halfedge_const_handle above_he; CGAL::assign(above_he, above_feat)) { if(conn.is_connected((above_he)->source(), vh)) { @@ -110,11 +88,11 @@ public: } const auto& [it, _] = feature_portals.try_emplace(above_he, std::vector{}); - if((above_he)->is_fictitious()) { + if(above_he->is_fictitious()) { it->second.emplace_back(std::nullopt, vh); - return; + } else { + it->second.emplace_back(m_approx_pt_at_x(above_he->curve(), vh->point().x()).value(), vh); } - it->second.emplace_back(approx_pt(upper_intersection(*arr.traits(), vh->point(), (above_he)->curve())), vh); } else if(Face_const_handle above_fh; CGAL::assign(above_fh, above_feat)) { // We don't create portals for the unbounded face in bounded arrangements. CGAL_assertion(above_fh->is_unbounded() && !above_fh->has_outer_ccb()); @@ -128,6 +106,12 @@ public: decompose(arr, func_out_iter); return feature_portals; } + +private: + const Arr_approximate_point_2_at_x m_approx_pt_at_x; + const Arr_approximate_point_2 m_approx_pt; }; + +} // namespace draw_aos } // namespace CGAL #endif // CGAL_DRAW_AOS_ARR_CREATE_PORTALS_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_render_context.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_render_context.h index bb5e1e49388..54ac11a3054 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_render_context.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_render_context.h @@ -1,24 +1,29 @@ #ifndef CGAL_DRAW_AOS_ARR_RENDER_CONTEXT_H #define CGAL_DRAW_AOS_ARR_RENDER_CONTEXT_H -#include "CGAL/Arr_point_location_result.h" -#include "CGAL/Arr_trapezoid_ric_point_location.h" -#include "CGAL/Bbox_2.h" -#include "CGAL/Draw_aos/Arr_approximate_point_2.h" -#include "CGAL/Draw_aos/Arr_approximation_cache.h" -#include "CGAL/Draw_aos/Arr_construct_curve_end.h" -#include "CGAL/Draw_aos/Arr_construct_segments.h" +#include +#include +#include #include #include #include + +#include +#include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include + +#if defined(CGAL_DRAW_AOS_DEBUG) #include -#include -#include -#include +#endif namespace CGAL { +namespace draw_aos { class Arr_cancellable_context_mixin { @@ -50,23 +55,18 @@ private: std::shared_ptr> m_done; }; +template class Arr_bounds_context_mixin { - using Approx_point = Arr_approximation_geometry_traits::Approx_point; + using Approx_point = typename Arr_approximation_geometry_traits::Approx_point; + using Point_2 = typename Traits_adaptor::Point_2; + using FT = typename Traits_adaptor::FT; protected: Arr_bounds_context_mixin(const Bbox_2& bbox) : m_bbox(bbox) {} public: - enum class Side_of_boundary { - Left, - Right, - Bottom, - Top, - None, - }; - double xmin() const { return m_bbox.xmin(); } double xmax() const { return m_bbox.xmax(); } double ymin() const { return m_bbox.ymin(); } @@ -74,64 +74,43 @@ public: const Bbox_2& bbox() const { return m_bbox; } - template - bool strictly_contains_x(FT x) const { - return xmin() < x && x <= xmax(); - } + bool strictly_contains_x(double x) const { return xmin() < x && x <= xmax(); } + bool strictly_contains_x(FT x) const { return to_ft(xmin()) < x && x <= to_ft(xmax()); } - template - bool strictly_contains_y(FT y) const { - return ymin() < y && y <= ymax(); - } + bool strictly_contains_y(double y) const { return ymin() < y && y <= ymax(); } + bool strictly_contains_y(FT y) const { return to_ft(ymin()) < y && y <= to_ft(ymax()); } - template - bool strictly_contains(const Point& pt) const { - return strictly_contains_x(pt.x()) && strictly_contains_y(pt.y()); - } + bool strictly_contains(Point_2 pt) const { return strictly_contains_x(pt.x()) && strictly_contains_y(pt.y()); } + bool strictly_contains(Approx_point pt) const { return strictly_contains_x(pt.x()) && strictly_contains_y(pt.y()); } - template - bool contains_x(FT x) const { - return xmin() <= x && x <= xmax(); - } + bool contains_x(double x) const { return xmin() <= x && x <= xmax(); } + bool contains_x(FT x) const { return to_ft(xmin()) <= x && x <= to_ft(xmax()); } - template - bool contains_y(FT y) const { - return ymin() <= y && y <= ymax(); - } + bool contains_y(double y) const { return ymin() <= y && y <= ymax(); } + bool contains_y(FT y) const { return to_ft(ymin()) <= y && y <= to_ft(ymax()); } - template - bool contains(const Point& pt) const { - return contains_x(pt.x()) && contains_y(pt.y()); - } + bool contains(Approx_point pt) const { return contains_x(pt.x()) && contains_y(pt.y()); } + bool contains(Point_2 pt) const { return contains_x(pt.x()) && contains_y(pt.y()); } - template - bool is_on_boundary(const Point& pt) const { + bool is_on_boundary(Approx_point pt) const { return (pt.x() == xmin() || pt.x() == xmax()) && contains_y(pt.y()) || (pt.y() == ymin() || pt.y() == ymax()) && contains_x(pt.x()); } - - template - Side_of_boundary shared_boundary_side(const Point& pt1, const Point& pt2) const { - if(pt1.x() == xmin() && pt2.x() == xmin() && contains_y(pt1.y()) && contains_y(pt2.y())) { - return Side_of_boundary::Left; - } else if(pt1.x() == xmax() && pt2.x() == xmax() && contains_y(pt1.y()) && contains_y(pt2.y())) { - return Side_of_boundary::Right; - } else if(pt1.y() == ymin() && pt2.y() == ymin() && contains_x(pt1.x()) && contains_x(pt2.x())) { - return Side_of_boundary::Bottom; - } else if(pt1.y() == ymax() && pt2.y() == ymax() && contains_x(pt1.x()) && contains_x(pt2.x())) { - return Side_of_boundary::Top; - } - return Side_of_boundary::None; + bool is_on_boundary(Point_2 pt) const { + return (pt.x() == to_ft(xmin()) || pt.x() == to_ft(xmax())) && contains_y(pt.y()) || + (pt.y() == to_ft(ymin()) || pt.y() == to_ft(ymax())) && contains_x(pt.x()); } private: const Bbox_2 m_bbox; + const Construct_coordinate to_ft; }; +template class Arr_geom_traits_context_mixin { public: - Arr_geom_traits_context_mixin(const Geom_traits& _traits) + Arr_geom_traits_context_mixin(const GeomTraits& _traits) : traits(_traits) , cst_curve_end(_traits) , cst_horizontal_segment(_traits) @@ -141,68 +120,88 @@ public: , is_vertical_2(_traits.is_vertical_2_object()) , approx_pt(_traits) {} - const Geom_traits& traits; - const Arr_construct_curve_end cst_curve_end; - const Arr_construct_vertical_segment cst_vertical_segment; - const Arr_construct_horizontal_segment cst_horizontal_segment; - const Geom_traits::Intersect_2 intersect_2; - const Geom_traits::Compare_xy_2 compare_xy_2; - const Geom_traits::Is_vertical_2 is_vertical_2; - const Arr_approximate_point_2 approx_pt; + const GeomTraits& traits; + const Arr_construct_curve_end cst_curve_end; + const Arr_construct_vertical_segment cst_vertical_segment; + const Arr_construct_horizontal_segment cst_horizontal_segment; + const typename Traits_adaptor::Intersect_2 intersect_2; + const typename Traits_adaptor::Compare_xy_2 compare_xy_2; + const typename Traits_adaptor::Is_vertical_2 is_vertical_2; + const Arr_approximate_point_2 approx_pt; }; -class Arr_render_context : public Arr_cancellable_context_mixin, public Arr_geom_traits_context_mixin +template +class Arr_render_context : public Arr_cancellable_context_mixin, + public Arr_geom_traits_context_mixin { using Point_location = Arr_trapezoid_ric_point_location; + using Feature_portals_map = typename Arr_portals::Feature_portals_map; + using Cancellable_context_mixin = Arr_cancellable_context_mixin; + using Geom_traits_context_mixin = Arr_geom_traits_context_mixin; public: - Arr_render_context(const Arrangement& arr, const Point_location& pl, double approx_error) - : Arr_cancellable_context_mixin() - , Arr_geom_traits_context_mixin(*arr.traits()) + Arr_render_context(const Arrangement& arr, + const Point_location& pl, + const Feature_portals_map& feature_portals, + double approx_error) + : Cancellable_context_mixin() + , Geom_traits_context_mixin(*arr.geometry_traits()) , arr(arr) , point_location(pl) - , counter(std::make_shared(0)) // TODO: remove this after debugging - , approx_error(approx_error) {} + , feature_portals(feature_portals) + , approx_error(approx_error) { +#if defined(CGAL_DRAW_AOS_DEBUG) && defined(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR) + std::filesystem::path debug_file_dir(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR); + // clear the index file. + std::filesystem::remove(debug_file_dir / "index.txt"); +#endif + } public: const double approx_error; const Arrangement& arr; - std::shared_ptr counter; // TODO: remove this after debugging const Point_location& point_location; + const Feature_portals_map& feature_portals; + +#if defined(CGAL_DRAW_AOS_DEBUG) + std::shared_ptr debug_counter = std::make_shared(0); +#endif }; -class Arr_bounded_render_context : public Arr_render_context, public Arr_bounds_context_mixin +template +class Arr_bounded_render_context : public Arr_render_context, + public Arr_bounds_context_mixin { - using Approx_point = Arr_approximation_geometry_traits::Approx_point; - using Point_2 = Geom_traits::Point_2; + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Approx_point = typename Arr_approximation_geometry_traits::Approx_point; + using Point_2 = typename Traits_adaptor::Point_2; + using Render_context = Arr_render_context; + using Bounds_context_mixin = Arr_bounds_context_mixin; + using Approx_cache = Arr_approximation_cache; + constexpr static double ep_base = std::numeric_limits::epsilon(); public: - Arr_bounded_render_context(const Arr_render_context& ctx, const Bbox_2& bbox, Arr_approximation_cache& cache) - : Arr_render_context(ctx) + Arr_bounded_render_context(const Render_context& ctx, const Bbox_2& bbox, Approx_cache& cache) + : Render_context(ctx) + , Bounds_context_mixin(bbox) , ep_xmin(std::max(std::abs(ep_base * bbox.xmin()), ep_base)) , ep_xmax(std::max(std::abs(ep_base * bbox.xmax()), ep_base)) , ep_ymin(std::max(std::abs(ep_base * bbox.ymin()), ep_base)) , ep_ymax(std::max(std::abs(ep_base * bbox.ymax()), ep_base)) - , Arr_bounds_context_mixin(bbox) - , cache(cache) { + , cache(cache) {} - // TODO: remove this after debugging - std::ofstream ofs_index("/Users/shep/codes/aos_2_js_helper/shapes.txt", std::ios::out | std::ios::trunc); - } + Approx_point make_on_boundary(const Approx_point& pt) const { + double x = pt.x(), y = pt.y(); - Approx_point approx_pt_on_boundary(const Point_2& pt) const { - double x = this->approx_pt(pt, 0); - double y = this->approx_pt(pt, 1); - - if(std::abs(x - xmin()) < ep_xmin) { - x = xmin(); - } else if(std::abs(x - xmax()) < ep_xmax) { - x = xmax(); - } else if(std::abs(y - ymin()) < ep_ymin) { - y = ymin(); - } else if(std::abs(y - ymax()) < ep_ymax) { - y = ymax(); + if(std::abs(x - this->xmin()) < ep_xmin) { + x = this->xmin(); + } else if(std::abs(x - this->xmax()) < ep_xmax) { + x = this->xmax(); + } else if(std::abs(y - this->ymin()) < ep_ymin) { + y = this->ymin(); + } else if(std::abs(y - this->ymax()) < ep_ymax) { + y = this->ymax(); } else { // We shall not call this function if not approximated from a boundary point. CGAL_assertion(false && "Failed to match point to the boundary"); @@ -212,7 +211,7 @@ public: } public: - Arr_approximation_cache& cache; + Approx_cache& cache; private: // floating point epsilon at boundary coordinates @@ -236,5 +235,6 @@ private: const Context& m_ctx; }; +} // namespace draw_aos } // namespace CGAL #endif // CGAL_DRAW_AOS_ARR_RENDER_CONTEXT_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_viewer.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_viewer.h index 9c101f05426..4c17790b9ea 100644 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_viewer.h +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_viewer.h @@ -16,12 +16,10 @@ #ifndef ARR_VIEWER_H #define ARR_VIEWER_H +#include "CGAL/Draw_aos/type_utils.h" #include #include -#include -#include -#include -#include +#include #include #include @@ -33,28 +31,30 @@ #include #include -#include "CGAL/Arr_trapezoid_ric_point_location.h" -#include "CGAL/Arrangement_on_surface_2.h" +#include +#include +#include #include -#include "CGAL/Bbox_2.h" -#include -#include "CGAL/Draw_aos/Arr_bounded_renderer.h" -#include "CGAL/Draw_aos/Arr_render_context.h" -#include "CGAL/Graphics_scene.h" -#include "CGAL/Graphics_scene_options.h" -#include "CGAL/Qt/camera.h" -#include "CGAL/unordered_flat_map.h" +#include +#include +#include +#include +#include namespace CGAL { +namespace draw_aos { -class Arr_viewer : public Qt::Basic_viewer { +template +class Arr_viewer : public Qt::Basic_viewer +{ using Basic_viewer = Qt::Basic_viewer; - using Vertex_const_handle = Arrangement::Vertex_const_handle; - using Halfedge_const_handle = Arrangement::Halfedge_const_handle; - using Face_const_handle = Arrangement::Face_const_handle; - using Graphics_scene_options = - CGAL::Graphics_scene_options; - using Point_location = CGAL::Arr_trapezoid_ric_point_location; + using Vertex_const_handle = typename Arrangement::Vertex_const_handle; + using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle; + using Face_const_handle = typename Arrangement::Face_const_handle; + using Feature_portal_map = typename Arr_portals::Feature_portals_map; + using Graphics_scene_options = GSOptions; + using Point_location = Arr_trapezoid_ric_point_location; + using Geom_traits = typename Arrangement::Geometry_traits_2; private: // Function to check if the camera's state has changed @@ -64,7 +64,7 @@ private: this->camera_->computeModelViewMatrix(); this->camera_->getProjectionMatrix(proj_mat.data()); this->camera_->getModelViewMatrix(mv_mat.data()); - if (proj_mat == m_last_proj_matrix && mv_mat == m_last_modelview_matrix) { + if(proj_mat == m_last_proj_matrix && mv_mat == m_last_modelview_matrix) { return false; } m_last_proj_matrix = proj_mat; @@ -72,18 +72,6 @@ private: return true; } - // Bbox_2 initial_bbox() const { - // Bbox_2 bbox; - // for(const auto& vh : m_arr.vertex_handles()) { - // bbox += vh->point().bbox(); - // } - // if(bbox.x_span() == 0 || bbox.y_span() == 0) { - // // make a default bbox around the degenrate rect - // bbox = Bbox_2(bbox.xmin() - 1, bbox.ymin() - 1, bbox.xmax() + 1, bbox.ymax() + 1); - // } - // return bbox; - // } - /** * @brief Computes the bounding box of the view from orthogonal camera. * @@ -105,9 +93,10 @@ private: double ymin = std::numeric_limits::max(); double ymax = std::numeric_limits::lowest(); - for (const QVector4D& corner : clip_space_corners) { + for(const QVector4D& corner : clip_space_corners) { QVector4D world = inverse_mvp * corner; - if (world.w() != 0.0) world /= world.w(); + if(world.w() != 0.0) + world /= world.w(); double x = world.x(); double y = world.y(); @@ -121,40 +110,47 @@ private: } double get_approx_error(const Bbox_2& bbox) const { + if constexpr(Traits_adaptor::Approximation_sizing_factor == 0.0) { + return std::numeric_limits::max(); + } std::array viewport; camera_->getViewport(viewport.data()); - double width = static_cast(viewport[2]); - // return bbox.x_span() / std::min(600.0, width); - // We are testing linear traits, lets set it to inf - return 10000; + double viewport_width = static_cast(viewport[2]); + double bbox_xspan = bbox.x_span(); + return bbox_xspan / viewport_width * Traits_adaptor::Approximation_sizing_factor; } public: Arr_viewer(QWidget* parent, const Arrangement& arr, Graphics_scene_options options, - const char* title = "Arrangement Viewer") : - Basic_viewer(parent, m_scene, title), - m_scene_options(options), - m_arr(arr), - m_pl(arr) - {} + const char* title = "Arrangement Viewer") + : Basic_viewer(parent, m_scene, title) + , m_scene_options(options) + , m_arr(arr) + , m_feature_portals(Arr_portals(*arr.geometry_traits()).create(arr)) + , m_pl(arr) {} - void render_arr(const Arrangement& arr, const Point_location& pl, const Bbox_2& bbox) { - Arr_render_context ctx(arr, pl, get_approx_error(bbox)); - Arr_bounded_renderer renderer(ctx, bbox); + void render_arr(const Bbox_2& bbox) { + Arr_render_context ctx(m_arr, m_pl, m_feature_portals, get_approx_error(bbox)); + Arr_bounded_renderer renderer(ctx, bbox); const auto& cache = renderer.render(); +#if defined(CGAL_DRAW_AOS_DEBUG) + std::cout << "Rendering arrangement with " << cache.face_cache_size() << " visible faces, " + << cache.halfedge_cache_size() << " visible halfedges, " << cache.vertex_cache_size() + << " visible vertices." << std::endl; +#endif + // add faces - for (const auto& [fh, face_tris] : cache.face_cache()) { + for(const auto& [fh, face_tris] : cache.face_cache()) { const auto& points = face_tris.points; const auto& tris = face_tris.triangles; - bool draw_face = m_scene_options.colored_face(arr, fh); - for (const auto& t : tris) { - if (draw_face) { - m_scene.face_begin(m_scene_options.face_color(arr, fh)); - } - else { + bool draw_face = m_scene_options.colored_face(m_arr, fh); + for(const auto& t : tris) { + if(draw_face) { + m_scene.face_begin(m_scene_options.face_color(m_arr, fh)); + } else { m_scene.face_begin(); } for(const auto idx : t) { @@ -165,55 +161,67 @@ public: } // add edges - for (const auto& [he, polyline] : cache.halfedge_cache()) { - if (polyline.size() < 2) { - continue; // skip degenerate edges + for(const auto& [he, polyline] : cache.halfedge_cache()) { + if(polyline.size() < 2) { + continue; } - bool draw_colored_edge = m_scene_options.colored_edge(arr, he); - auto color = draw_colored_edge ? m_scene_options.edge_color(arr, he) : CGAL::IO::Color(); - for (size_t i = 0; i < polyline.size() - 1; ++i) { + bool draw_colored_edge = m_scene_options.colored_edge(m_arr, he); + auto color = draw_colored_edge ? m_scene_options.edge_color(m_arr, he) : CGAL::IO::Color(); + for(size_t i = 0; i < polyline.size() - 1; ++i) { const auto& cur_pt = polyline[i]; const auto& next_pt = polyline[i + 1]; auto mid_pt = CGAL::midpoint(cur_pt, next_pt); - if (mid_pt.x() <= bbox.xmin() || mid_pt.x() > bbox.xmax() || mid_pt.y() <= bbox.ymin() || + if(mid_pt.x() <= bbox.xmin() || mid_pt.x() > bbox.xmax() || mid_pt.y() <= bbox.ymin() || mid_pt.y() > bbox.ymax()) { continue; } - if (draw_colored_edge) { + if(draw_colored_edge) { m_scene.add_segment(cur_pt, next_pt, color); - } - else { + } else { m_scene.add_segment(cur_pt, next_pt); } } } + // add vertices - for (const auto& [vh, pt] : cache.vertex_cache()) { - if (m_scene_options.colored_vertex(arr, vh)) { - m_scene.add_point(pt, m_scene_options.vertex_color(arr, vh)); - } - else { + for(const auto& [vh, pt] : cache.vertex_cache()) { + if(m_scene_options.colored_vertex(m_arr, vh)) { + m_scene.add_point(pt, m_scene_options.vertex_color(m_arr, vh)); + } else { m_scene.add_point(pt); } } + + // If there's nothing to render, we fill the bbox with background color. + // This is to keep the Basic_viewer working in 2D mode. + if(m_scene.empty()) { + m_scene.face_begin(CGAL::IO::Color(255, 255, 255)); // White, by now + using Approx_point = typename Arr_approximation_geometry_traits::Approx_point; + m_scene.add_point_in_face(Approx_point(bbox.xmin(), bbox.ymin())); + m_scene.add_point_in_face(Approx_point(bbox.xmax(), bbox.ymin())); + m_scene.add_point_in_face(Approx_point(bbox.xmax(), bbox.ymax())); + m_scene.add_point_in_face(Approx_point(bbox.xmin(), bbox.ymax())); + m_scene.face_end(); + } } void rerender(Bbox_2 bbox) { m_scene.clear(); - render_arr(m_arr, m_pl, bbox); + render_arr(bbox); Basic_viewer::redraw(); } virtual void draw() override { if(is_camera_changed()) { Bbox_2 bbox = view_bbox_from_camera(); - // shrink the bbox by 10% for testing +#if defined(CGAL_DRAW_AOS_DEBUG) double dx = (bbox.xmax() - bbox.xmin()) * 0.1; double dy = (bbox.ymax() - bbox.ymin()) * 0.1; bbox = Bbox_2(bbox.xmin() + dx, bbox.ymin() + dy, bbox.xmax() - dx, bbox.ymax() - dy); std::cout << "Camera changed, recomputing arrangement bounding box: " << bbox << std::endl; +#endif rerender(bbox); } Basic_viewer::draw(); @@ -226,36 +234,12 @@ private: Graphics_scene_options m_scene_options; Arrangement m_arr; Point_location m_pl; + Feature_portal_map m_feature_portals; QMatrix4x4 m_last_proj_matrix; QMatrix4x4 m_last_modelview_matrix; }; -void draw_viewer(const Arrangement& arr) { - Qt::init_ogl_context(4, 3); - int argc; - QApplication app(argc, nullptr); - Graphics_scene_options - gso; - gso.enable_faces(); - gso.enable_edges(); - gso.enable_vertices(); - gso.face_color = [](const Arrangement&, const Arrangement::Face_const_handle& fh) -> CGAL::IO::Color { - CGAL::Random random((size_t(&*fh))); - return get_random_color(random); - }; - gso.colored_face = [](const Arrangement&, const Arrangement::Face_const_handle&) { return true; }; - gso.vertex_color = [](const Arrangement&, const Arrangement::Vertex_const_handle& vh) -> CGAL::IO::Color { - CGAL::Random random((size_t(&*vh))); - return get_random_color(random); - }; - // Arr_viewer viewer(app.activeWindow(), move_degenerate_features(arr), gso, "Arrangement Viewer"); - Arr_viewer viewer(app.activeWindow(), arr, gso, "Arrangement Viewer"); - std::cout << "Preprocess complete" << std::endl; - viewer.show(); - app.exec(); -} - +} // namespace draw_aos } // namespace CGAL #endif diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/helpers.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/helpers.h deleted file mode 100644 index ebba088d7a5..00000000000 --- a/Arrangement_on_surface_2/include/CGAL/Draw_aos/helpers.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef CGAL_DRAW_AOS_HELPERS_H -#define CGAL_DRAW_AOS_HELPERS_H -#include "CGAL/Arr_linear_traits_2.h" -#include -#include -namespace CGAL { - -using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; -// using Geom_traits = Arr_segment_traits_2; -using Geom_traits = CGAL::Arr_linear_traits_2; -using Arrangement = Arrangement_2; - -struct Inner_ccb_tag -{}; -struct Outer_ccb_tag -{}; - -} // namespace CGAL - -#endif // CGAL_DRAW_AOS_HELPERS_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/type_utils.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/type_utils.h new file mode 100644 index 00000000000..0dd41e29f00 --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/type_utils.h @@ -0,0 +1,283 @@ +#ifndef CGAL_DRAW_AOS_TYPE_UTILS_H +#define CGAL_DRAW_AOS_TYPE_UTILS_H +#include "CGAL/Arr_polycurve_traits_2.h" +#include "CGAL/Arr_polyline_traits_2.h" +#include "CGAL/Cartesian.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { +namespace draw_aos { + +enum class Side_of_boundary { + Top = 0, + Left = 1, + Bottom = 2, + Right = 3, + None = -1, +}; + +template > +struct has_construct_x_monotone_curve_2 : std::false_type +{}; + +template +struct has_construct_x_monotone_curve_2> : std::true_type +{}; + +template > +struct has_approximate_2_object : std::false_type +{}; + +// Specialization: detection succeeds if decltype(T::approximate_2_object()) is valid +template +struct has_approximate_2_object().approximate_2_object())>> : std::true_type +{}; + +// Convenience variable +template +inline constexpr bool has_approximate_2_object_v = has_approximate_2_object::value; + +// Primary templates: detection fails by default +// Does a class have operator()(const Point&)? +template > +struct has_operator_point : std::false_type +{}; + +// Specialization: detection succeeds if decltype works out +template +struct has_operator_point()(std::declval()))>> + : std::true_type +{}; + +// Convenience variable +template +inline constexpr bool has_operator_point_v = has_operator_point::value; + +// Primary templates: detection fails by default +// Does a class have operator()(const X_monotone_curve&)? +template > +struct has_operator_xcv : std::false_type +{}; + +template +struct has_operator_xcv()(std::declval(), + std::declval(), + std::declval(), + std::declval()))>> : std::true_type +{}; + +// Convenience variable +template +constexpr bool has_operator_xcv_v = has_operator_xcv::value; + +template +struct Traits_adaptor_base +{ +public: + using Geom_traits = GeomTraits; + using Point_2 = typename Geom_traits::Point_2; + using X_monotone_curve_2 = typename Geom_traits::X_monotone_curve_2; + using Intersect_2 = typename Geom_traits::Intersect_2; + using Is_vertical_2 = typename Geom_traits::Is_vertical_2; + using Compare_xy_2 = typename Geom_traits::Compare_xy_2; +}; + +template +struct Traits_adaptor; + +template +struct Traits_adaptor> : public Traits_adaptor_base> +{ +private: + using Geom_traits = Arr_segment_traits_2; + +public: + constexpr static bool Has_unbounded_curves = false; + constexpr static double Approximation_sizing_factor = 1.0; + using FT = typename Kernel::FT; + using Approximate_2 = typename Geom_traits::Approximate_2; + using Approximate_number_type = typename Geom_traits::Approximate_number_type; + using Approximate_kernel = typename Geom_traits::Approximate_kernel; + using Approximate_point_2 = typename Geom_traits::Approximate_point_2; +}; + +template +struct Traits_adaptor> + : public Traits_adaptor_base> +{ +private: + using Geom_traits = Arr_polyline_traits_2; + using Sub_traits = SegmentTraits; + using Adapted_sub_traits = Traits_adaptor; + +public: + constexpr static bool Has_unbounded_curves = false; + constexpr static double Approximation_sizing_factor = 1.0; + using FT = typename Adapted_sub_traits::FT; + using Approximate_2 = typename Geom_traits::Approximate_2; + using Approximate_number_type = typename Adapted_sub_traits::Approximate_number_type; + using Approximate_kernel = typename Adapted_sub_traits::Approximate_kernel; + using Approximate_point_2 = typename Adapted_sub_traits::Approximate_point_2; +}; + +template +struct Traits_adaptor> + : public Traits_adaptor_base> +{ +private: + using Sub_traits = SubcurveTraits; + using Geom_traits = Arr_polycurve_traits_2; + using Adapted_sub_traits = Traits_adaptor; + +public: + constexpr static bool Has_unbounded_curves = false; + constexpr static double Approximation_sizing_factor = 1.0; + using FT = typename Adapted_sub_traits::FT; + using Approximate_2 = typename Geom_traits::Approximate_2; + using Approximate_number_type = typename Adapted_sub_traits::Approximate_number_type; + using Approximate_kernel = typename Adapted_sub_traits::Approximate_kernel; + using Approximate_point_2 = typename Adapted_sub_traits::Approximate_point_2; +}; + +template +struct Traits_adaptor> : public Traits_adaptor_base> +{ +private: + using Geom_traits = Arr_segment_traits_2; + +public: + constexpr static bool Has_unbounded_curves = true; + constexpr static double Approximation_sizing_factor = 0.0; + using FT = typename Kernel::FT; + using Approximate_2 = typename Geom_traits::Approximate_2; + using Approximate_number_type = typename Geom_traits::Approximate_number_type; + using Approximate_kernel = typename Geom_traits::Approximate_kernel; + using Approximate_point_2 = typename Geom_traits::Approximate_point_2; +}; + +template +struct Traits_adaptor> + : public Traits_adaptor_base> +{ +private: + using Geom_traits = Arr_conic_traits_2; + +public: + constexpr static bool Has_unbounded_curves = false; + constexpr static double Approximation_sizing_factor = 1.0; + using FT = typename AlgKernel::FT; + using Approximate_2 = typename Geom_traits::Approximate_2; + using Approximate_number_type = typename Geom_traits::Approximate_number_type; + using Approximate_kernel = typename Geom_traits::Approximate_kernel; + using Approximate_point_2 = typename Geom_traits::Approximate_point_2; +}; + +template +struct Traits_adaptor> + : public Traits_adaptor_base> +{ +private: + using Geom_traits = Arr_circle_segment_traits_2; + using Base = Traits_adaptor_base; + +public: + constexpr static bool Has_unbounded_curves = false; + constexpr static double Approximation_sizing_factor = 0.5; + using FT = typename Base::Point_2::CoordNT; + using Approximate_2 = typename Geom_traits::Approximate_2; + using Approximate_number_type = typename Geom_traits::Approximate_number_type; + using Approximate_kernel = typename Geom_traits::Approximate_kernel; + using Approximate_point_2 = typename Geom_traits::Approximate_point_2; +}; + +template +struct Traits_adaptor> + : public Traits_adaptor_base> +{ + static_assert(false, "Approximate_2 not yet modeled by this geometry traits class."); +}; + +template +struct Traits_adaptor> + : public Traits_adaptor_base> +{ + static_assert(false, "Approximate_2 not yet modeled by this geometry traits class."); +}; + +template +struct Traits_adaptor> + : public Traits_adaptor_base> +{ +private: + using Geom_traits = Arr_rational_function_traits_2; + +public: + constexpr static bool Has_unbounded_curves = true; + constexpr static double Approximation_sizing_factor = 5.0; + using FT = typename Geom_traits::Algebraic_real_1; + using Approximate_2 = typename Geom_traits::Approximate_2; + // Currently, Approximate_number_type is defined as Bound in Arr_rational_function_traits_2, + // And there's no Approximate_kernel defined. + using Approximate_number_type = double; + using Approximate_kernel = Cartesian; + using Approximate_point_2 = typename Approximate_kernel::Point_2; +}; + +template +class Construct_coordinate +{ + using FT = typename Traits_adaptor::FT; + +public: + FT operator()(double val) const { return FT(val); } +}; + +template +class Construct_coordinate> +{ + using FT = typename Traits_adaptor>::FT; + using Bound = typename Kernel::Bound; + +public: + FT operator()(double val) const { return FT(Bound(val)); } +}; + +template +class Arr_approximation_geometry_traits +{ + using Adapted_traits = Traits_adaptor; + +public: + using Approx_point = typename Adapted_traits::Approximate_point_2; + using Approx_nt = typename Adapted_traits::Approximate_number_type; + using Approx_kernel = typename Adapted_traits::Approximate_kernel; + using Point_geom = Approx_point; + using Apporx_point_vec = std::vector; + using Polyline_geom = Apporx_point_vec; + using Triangle = std::array; + using Triangle_vec = std::vector; + struct Triangulated_face + { + Apporx_point_vec points; + Triangle_vec triangles; + }; +}; + +} // namespace draw_aos +} // namespace CGAL + +#endif // CGAL_DRAW_AOS_TYPE_UTILS_H \ No newline at end of file diff --git a/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h b/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h index d9c8c414d1a..c87cf6805ed 100644 --- a/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h +++ b/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h @@ -16,22 +16,6 @@ #ifndef CGAL_DRAW_ARRANGEMENT_2_H #define CGAL_DRAW_ARRANGEMENT_2_H -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - #include #include #include @@ -43,6 +27,9 @@ #include #include #include +#include +#include +#include namespace CGAL { @@ -606,47 +593,46 @@ protected: #define CGAL_ARR_TYPE CGAL::Arrangement_on_surface_2 -/// -template -void add_to_graphics_scene(const CGAL_ARR_TYPE& aos, CGAL::Graphics_scene& graphics_scene, const GSOptions& gso) { - draw_function_for_arrangement_2::Draw_arr_tool dar(aos, graphics_scene, gso); - dar.add_elements(); -} - -/// -template -void add_to_graphics_scene(const CGAL_ARR_TYPE& aos, CGAL::Graphics_scene& graphics_scene) { - CGAL::Graphics_scene_options - gso; - // colored face? - gso.colored_face = [](const CGAL_ARR_TYPE&, typename CGAL_ARR_TYPE::Face_const_handle) -> bool { return true; }; - - // face color - gso.face_color = [](const CGAL_ARR_TYPE&, typename CGAL_ARR_TYPE::Face_const_handle fh) -> CGAL::IO::Color { - CGAL::Random random((unsigned int)(std::size_t)(&*fh)); - return get_random_color(random); - }; - - add_to_graphics_scene(aos, graphics_scene, gso); -} - /// Draw an arrangement on surface. template void draw(const CGAL_ARR_TYPE& aos, const GSOptions& gso, const char* title = "2D Arrangement on Surface Basic Viewer") { - CGAL::Graphics_scene graphics_scene; - add_to_graphics_scene(aos, graphics_scene, gso); - draw_graphics_scene(graphics_scene, title); + Qt::init_ogl_context(4, 3); + int argc; + QApplication app(argc, nullptr); + auto viewer = draw_aos::Arr_viewer(app.activeWindow(), aos, gso, title); + viewer.show(); + app.exec(); } /// Draw an arrangement on surface. template void draw(const CGAL_ARR_TYPE& aos, const char* title = "2D Arrangement on Surface Basic Viewer") { - CGAL::Graphics_scene graphics_scene; - add_to_graphics_scene(aos, graphics_scene); - draw_graphics_scene(graphics_scene, title); + using Arrangement = CGAL_ARR_TYPE; + using Face_const_handle = typename Arrangement::Face_const_handle; + using Vertex_const_handle = typename Arrangement::Vertex_const_handle; + using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle; + + Qt::init_ogl_context(4, 3); + int argc; + QApplication app(argc, nullptr); + Graphics_scene_options gso; + gso.enable_faces(); + gso.enable_edges(); + gso.enable_vertices(); + gso.face_color = [](const Arrangement&, const Face_const_handle& fh) -> CGAL::IO::Color { + CGAL::Random random((size_t(fh.ptr()))); + return get_random_color(random); + }; + gso.colored_face = [](const Arrangement&, const Face_const_handle&) { return true; }; + gso.vertex_color = [](const Arrangement&, const Vertex_const_handle& vh) -> CGAL::IO::Color { + CGAL::Random random((size_t(vh.ptr()))); + return get_random_color(random); + }; + auto viewer = draw_aos::Arr_viewer(app.activeWindow(), aos, gso, "Arrangement Viewer"); + viewer.show(); + app.exec(); } #undef CGAL_ARR_TYPE diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test.cmake b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test.cmake index 7fdb4d9a3f7..bc8f8c10c5c 100644 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test.cmake +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test.cmake @@ -118,7 +118,6 @@ set(IS_BETWEEN_CW 26) set(COMPARE_CW_AROUND_POINT 27) set(PUSH_BACK 28) set(PUSH_FRONT 29) -set(APPROXIMATE 30) set(NUMBER_OF_POINTS 32) set(COMPARE_ENDPOINTS_XY 33) set(CONSTRUCT_OPPOSITE 34) @@ -241,30 +240,22 @@ function(execute_commands_old_structure data_dir traits_type_name) # the old structure is default, so this function executes all commands # except the commands that are given as arguments - set(commands_indicator_APPROXIMATE 1) - set(commands_indicator_ARE_MERGEABLE 1) - set(commands_indicator_ASSERTIONS 1) set(commands_indicator_COMPARE 1) + set(commands_indicator_VERTEX 1) + set(commands_indicator_IS_VERTICAL 1) set(commands_indicator_COMPARE_Y_AT_X 1) set(commands_indicator_COMPARE_Y_AT_X_LEFT 1) set(commands_indicator_COMPARE_Y_AT_X_RIGHT 1) - set(commands_indicator_CONSTRUCTOR 1) - set(commands_indicator_INTERSECT 1) - set(commands_indicator_IS_VERTICAL 1) set(commands_indicator_MAKE_X_MONOTONE 1) - set(commands_indicator_MERGE 1) + set(commands_indicator_INTERSECT 1) set(commands_indicator_SPLIT 1) - set(commands_indicator_VERTEX 1) - + set(commands_indicator_ARE_MERGEABLE 1) + set(commands_indicator_MERGE 1) + set(commands_indicator_ASSERTIONS 1) + set(commands_indicator_CONSTRUCTOR 1) foreach(arg ${ARGN}) set(commands_indicator_${arg} 0) endforeach() - - if(commands_indicator_APPROXIMATE) - run_trapped_test(test_traits - data/empty.zero data/${data_dir}/approximate.xcv - data/empty.zero data/${data_dir}/approximate ${traits_type_name}) - endif() if(commands_indicator_COMPARE) run_trapped_test(test_traits data/compare.pt data/empty.zero @@ -287,21 +278,18 @@ function(execute_commands_old_structure data_dir traits_type_name) endif() if(commands_indicator_COMPARE_Y_AT_X_LEFT) run_trapped_test(test_traits - data/${data_dir}/compare_y_at_x_left.pt - data/${data_dir}/compare_y_at_x_left.xcv + data/${data_dir}/compare_y_at_x_left.pt data/${data_dir}/compare_y_at_x_left.xcv data/empty.zero data/${data_dir}/compare_y_at_x_left ${traits_type_name}) endif() if(commands_indicator_COMPARE_Y_AT_X_RIGHT) run_trapped_test(test_traits - data/${data_dir}/compare_y_at_x_right.pt - data/${data_dir}/compare_y_at_x_right.xcv + data/${data_dir}/compare_y_at_x_right.pt data/${data_dir}/compare_y_at_x_right.xcv data/empty.zero data/${data_dir}/compare_y_at_x_right ${traits_type_name}) endif() if(commands_indicator_MAKE_X_MONOTONE) run_trapped_test(test_traits data/empty.zero data/${data_dir}/make_x_monotone.xcv - data/${data_dir}/make_x_monotone.cv - data/${data_dir}/make_x_monotone ${traits_type_name}) + data/${data_dir}/make_x_monotone.cv data/${data_dir}/make_x_monotone ${traits_type_name}) endif() if(commands_indicator_INTERSECT) run_trapped_test(test_traits @@ -331,8 +319,7 @@ function(execute_commands_old_structure data_dir traits_type_name) if(commands_indicator_CONSTRUCTOR) run_trapped_test(test_traits data/empty.zero data/${data_dir}/constructor.xcv - data/${data_dir}/constructor.cv data/${data_dir}/constructor - ${traits_type_name}) + data/${data_dir}/constructor.cv data/${data_dir}/constructor ${traits_type_name}) endif() endfunction() @@ -345,166 +332,133 @@ function(execute_commands_new_structure data_dir traits_type_name) # the new structure is not default, so this function executes only # commands that are given as arguments - set(commands_indicator_APPROXIMATE 0) - set(commands_indicator_ARE_MERGEABLE 0) - set(commands_indicator_ASSERTIONS 0) set(commands_indicator_COMPARE 0) - set(commands_indicator_COMPARE_ENDPOINTS_XY 0) - set(commands_indicator_COMPARE_X_NEAR_BOUNDARY 0) + set(commands_indicator_VERTEX 0) + set(commands_indicator_IS_VERTICAL 0) set(commands_indicator_COMPARE_X_ON_BOUNDARY 0) + set(commands_indicator_COMPARE_X_NEAR_BOUNDARY 0) + set(commands_indicator_COMPARE_Y_NEAR_BOUNDARY 0) + set(commands_indicator_PARAMETER_SPACE_X 0) + set(commands_indicator_PARAMETER_SPACE_Y 0) set(commands_indicator_COMPARE_Y_AT_X 0) set(commands_indicator_COMPARE_Y_AT_X_LEFT 0) set(commands_indicator_COMPARE_Y_AT_X_RIGHT 0) - set(commands_indicator_COMPARE_Y_NEAR_BOUNDARY 0) - set(commands_indicator_CONSTRUCTOR 0) - set(commands_indicator_CONSTRUCT_OPPOSITE 0) - set(commands_indicator_EQUAL 0) - set(commands_indicator_INTERSECT 0) - set(commands_indicator_IS_VERTICAL 0) set(commands_indicator_MAKE_X_MONOTONE 0) + set(commands_indicator_INTERSECT 0) + set(commands_indicator_SPLIT 0) + set(commands_indicator_ARE_MERGEABLE 0) set(commands_indicator_MERGE 0) - set(commands_indicator_NUMBER_OF_POINTS 0) - set(commands_indicator_PARAMETER_SPACE_X 0) - set(commands_indicator_PARAMETER_SPACE_Y 0) + set(commands_indicator_ASSERTIONS 0) + set(commands_indicator_CONSTRUCTOR 0) + set(commands_indicator_EQUAL 0) set(commands_indicator_PUSH_BACK 0) set(commands_indicator_PUSH_FRONT 0) - set(commands_indicator_SPLIT 0) + set(commands_indicator_NUMBER_OF_POINTS 0) + set(commands_indicator_COMPARE_ENDPOINTS_XY 0) + set(commands_indicator_CONSTRUCT_OPPOSITE 0) set(commands_indicator_TRIM 0) - set(commands_indicator_VERTEX 0) - foreach(arg ${ARGN}) set(commands_indicator_${arg} 1) endforeach() - - if(commands_indicator_APPROXIMATE) - run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/approximate ${traits_type_name}) - endif() if(commands_indicator_COMPARE) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/compare ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/compare ${traits_type_name}) endif() if(commands_indicator_VERTEX) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/vertex ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/vertex ${traits_type_name}) endif() if(commands_indicator_IS_VERTICAL) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/is_vertical ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/is_vertical ${traits_type_name}) endif() if(commands_indicator_COMPARE_X_ON_BOUNDARY) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/compare_x_on_boundary ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/compare_x_on_boundary ${traits_type_name}) endif() if(commands_indicator_COMPARE_X_NEAR_BOUNDARY) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/compare_x_near_boundary ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/compare_x_near_boundary ${traits_type_name}) endif() if(commands_indicator_COMPARE_Y_NEAR_BOUNDARY) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/compare_y_near_boundary ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/compare_y_near_boundary ${traits_type_name}) endif() if(commands_indicator_PARAMETER_SPACE_X) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/parameter_space_x ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/parameter_space_x ${traits_type_name}) endif() if(commands_indicator_PARAMETER_SPACE_Y) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/parameter_space_y ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/parameter_space_y ${traits_type_name}) endif() if(commands_indicator_COMPARE_Y_AT_X) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/compare_y_at_x ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/compare_y_at_x ${traits_type_name}) endif() if(commands_indicator_COMPARE_Y_AT_X_LEFT) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/compare_y_at_x_left ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/compare_y_at_x_left ${traits_type_name}) endif() if(commands_indicator_COMPARE_Y_AT_X_RIGHT) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/compare_y_at_x_right ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/compare_y_at_x_right ${traits_type_name}) endif() if(commands_indicator_MAKE_X_MONOTONE) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/make_x_monotone ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/make_x_monotone ${traits_type_name}) endif() if(commands_indicator_INTERSECT) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/intersect ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/intersect ${traits_type_name}) endif() if(commands_indicator_SPLIT) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/split ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/split ${traits_type_name}) endif() if(commands_indicator_ARE_MERGEABLE) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/are_mergeable ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/are_mergeable ${traits_type_name}) endif() if(commands_indicator_MERGE) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/merge ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/merge ${traits_type_name}) endif() if(commands_indicator_ASSERTIONS) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/assertions ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/assertions ${traits_type_name}) endif() if(commands_indicator_CONSTRUCTOR) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/constructor ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/constructor ${traits_type_name}) endif() if(commands_indicator_EQUAL) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/equal ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/equal ${traits_type_name}) endif() if(commands_indicator_PUSH_BACK) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/push_back ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/push_back ${traits_type_name}) endif() if(commands_indicator_PUSH_FRONT) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/push_front ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/push_front ${traits_type_name}) endif() if(commands_indicator_NUMBER_OF_POINTS) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/number_of_points ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/number_of_points ${traits_type_name}) endif() if(commands_indicator_COMPARE_ENDPOINTS_XY) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/compare_endpoints_xy ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/compare_endpoints_xy ${traits_type_name}) endif() if(commands_indicator_CONSTRUCT_OPPOSITE) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/construct_opposite ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/construct_opposite ${traits_type_name}) endif() if(commands_indicator_TRIM) run_trapped_test(test_traits data/${data_dir}/points - data/${data_dir}/xcurves data/${data_dir}/curves - data/${data_dir}/trim ${traits_type_name}) + data/${data_dir}/xcurves data/${data_dir}/curves data/${data_dir}/trim ${traits_type_name}) endif() endfunction() @@ -513,32 +467,26 @@ function(execute_commands_traits_adaptor data_dir traits_type_name) # the new structure is not default, so this function executes only # commands that are given as arguments - set(commands_indicator_ARE_MERGEABLE 0) - set(commands_indicator_COMPARE_CW_AROUND_POINT 0) - set(commands_indicator_COMPARE_XY 0) - set(commands_indicator_COMPARE_Y_AT_X_LEFT 0) - set(commands_indicator_COMPARE_X_NEAR_BOUNDARY 0) - set(commands_indicator_COMPARE_Y_NEAR_BOUNDARY 0) - set(commands_indicator_COMPARE_X_ON_BOUNDARY 0) - set(commands_indicator_COMPARE_Y_POSITION 0) - set(commands_indicator_IS_BETWEEN_CW 0) - set(commands_indicator_IS_BOUNDED 0) - set(commands_indicator_IS_IN_X_RANGE 0) - set(commands_indicator_MERGE 0) set(commands_indicator_PARAMETER_SPACE_X 0) set(commands_indicator_PARAMETER_SPACE_Y 0) + set(commands_indicator_COMPARE_XY 0) + set(commands_indicator_COMPARE_X_ON_BOUNDARY 0) + set(commands_indicator_COMPARE_X_NEAR_BOUNDARY 0) + set(commands_indicator_COMPARE_Y_NEAR_BOUNDARY 0) + set(commands_indicator_COMPARE_Y_AT_X_LEFT 0) + set(commands_indicator_ARE_MERGEABLE 0) + set(commands_indicator_MERGE 0) set(commands_indicator_X_ON_IDENTIFICATION 0) set(commands_indicator_Y_ON_IDENTIFICATION 0) - + set(commands_indicator_IS_BOUNDED 0) + set(commands_indicator_IS_IN_X_RANGE 0) + set(commands_indicator_COMPARE_Y_POSITION 0) + set(commands_indicator_IS_BETWEEN_CW 0) + set(commands_indicator_COMPARE_CW_AROUND_POINT 0) foreach(arg ${ARGN}) set(commands_indicator_${arg} 1) endforeach() - if(commands_indicator_ARE_MERGEABLE) - run_trapped_test(test_traits_adaptor data/test_adaptor/${data_dir}/points - data/test_adaptor/${data_dir}/xcurves data/test_adaptor/${data_dir}/curves - data/test_adaptor/${data_dir}/are_mergeable ${traits_type_name}) - endif() if(commands_indicator_PARAMETER_SPACE_X) run_trapped_test(test_traits_adaptor data/test_adaptor/${data_dir}/points data/test_adaptor/${data_dir}/xcurves data/test_adaptor/${data_dir}/curves @@ -576,6 +524,11 @@ function(execute_commands_traits_adaptor data_dir traits_type_name) data/test_adaptor/${data_dir}/xcurves data/test_adaptor/${data_dir}/curves data/test_adaptor/${data_dir}/compare_y_at_x_left ${traits_type_name}) endif() + if(commands_indicator_ARE_MERGEABLE) + run_trapped_test(test_traits_adaptor data/test_adaptor/${data_dir}/points + data/test_adaptor/${data_dir}/xcurves data/test_adaptor/${data_dir}/curves + data/test_adaptor/${data_dir}/are_mergeable ${traits_type_name}) + endif() if(commands_indicator_MERGE) run_trapped_test(test_traits_adaptor data/test_adaptor/${data_dir}/points data/test_adaptor/${data_dir}/xcurves data/test_adaptor/${data_dir}/curves @@ -629,7 +582,7 @@ function(test_segment_traits_adaptor) compile_test_with_flags(test_traits_adaptor segments "${flags}") # if [ -n "${SUCCESS}" ] ; then - execute_commands_traits_adaptor(segments segments_traits_adaptor + execute_commands_traits_adaptor( segments segments_traits_adaptor COMPARE_XY COMPARE_Y_POSITION COMPARE_CW_AROUND_POINT COMPARE_Y_AT_X_LEFT ARE_MERGEABLE MERGE IS_IN_X_RANGE IS_BETWEEN_CW) endfunction() @@ -645,7 +598,7 @@ function(test_linear_traits_adaptor) compile_test_with_flags( test_traits_adaptor linear "${flags}") - execute_commands_traits_adaptor(linear linear_traits_adaptor + execute_commands_traits_adaptor( linear linear_traits_adaptor COMPARE_XY COMPARE_Y_AT_X_LEFT ARE_MERGEABLE MERGE IS_IN_X_RANGE COMPARE_Y_POSITION IS_BETWEEN_CW COMPARE_CW_AROUND_POINT) endfunction() @@ -662,7 +615,7 @@ function(test_spherical_arcs_traits_adaptor) compile_test_with_flags( test_traits_adaptor geodesic_arcs_on_sphere "${flags}") - execute_commands_traits_adaptor(spherical_arcs spherical_arcs_traits_adaptor + execute_commands_traits_adaptor( spherical_arcs spherical_arcs_traits_adaptor COMPARE_XY COMPARE_Y_AT_X_LEFT ARE_MERGEABLE MERGE IS_IN_X_RANGE COMPARE_Y_POSITION IS_BETWEEN_CW COMPARE_CW_AROUND_POINT) endfunction() @@ -690,7 +643,7 @@ function(test_construction_segments) set(kernel ${CARTESIAN_KERNEL}) set(geom_traits ${SEGMENT_GEOM_TRAITS}) set(flags "-DTEST_NT=${nt} -DTEST_KERNEL=${kernel} -DTEST_GEOM_TRAITS=${geom_traits}") - compile_and_run_with_flags(test_construction segments "${flags}") + compile_and_run_with_flags( test_construction segments "${flags}") endfunction() #---------------------------------------------------------------------# @@ -702,7 +655,7 @@ function(test_construction_linear_curves) set(geom_traits ${LINEAR_GEOM_TRAITS}) set(topol_traits ${PLANAR_UNBOUNDED_TOPOL_TRAITS}) set(flags "-DTEST_NT=${nt} -DTEST_KERNEL=${kernel} -DTEST_GEOM_TRAITS=${geom_traits} -DTEST_TOPOL_TRAITS=${topol_traits}") - compile_and_run_with_flags(test_construction linear "${flags}") + compile_and_run_with_flags( test_construction linear "${flags}") endfunction() #---------------------------------------------------------------------# @@ -714,7 +667,7 @@ function(test_construction_spherical_arcs) set(geom_traits ${GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS}) set(topol_traits ${SPHERICAL_TOPOL_TRAITS}) set(flags "-DTEST_NT=${nt} -DTEST_KERNEL=${kernel} -DTEST_GEOM_TRAITS=${geom_traits} -DTEST_TOPOL_TRAITS=${topol_traits}") - compile_and_run_with_flags(test_construction geodesic_arcs_on_sphere "${flags}") + compile_and_run_with_flags( test_construction geodesic_arcs_on_sphere "${flags}") endfunction() #---------------------------------------------------------------------# @@ -725,7 +678,7 @@ function(test_construction_polylines) set(kernel ${CARTESIAN_KERNEL}) set(geom_traits ${POLYLINE_GEOM_TRAITS}) set(flags "-DTEST_NT=${nt} -DTEST_KERNEL=${kernel} -DTEST_GEOM_TRAITS=${geom_traits}") - compile_and_run_with_flags(test_construction polylines "${flags}") + compile_and_run_with_flags( test_construction polylines "${flags}") endfunction() @@ -884,16 +837,14 @@ function(test_segment_traits) compile_test_with_flags(test_traits segments "${flags}") - execute_commands_old_structure(segments segment_traits - APPROXIMATE ARE_MERGEABLE COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT - COMPARE_Y_AT_X_RIGHT CONSTRUCTOR IS_VERTICAL VERTEX) + execute_commands_old_structure( segments segment_traits + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT CONSTRUCTOR + COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE) execute_commands_new_structure( segments segment_traits - ARE_MERGEABLE - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT - IS_VERTICAL) + IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT ARE_MERGEABLE) - run_trapped_test(test_traits + run_trapped_test( test_traits data/segments/vertex.pt data/segments/xcurves data/empty.zero data/segments/vertex segment_traits) endfunction() @@ -910,13 +861,11 @@ function(test_non_caching_segment_traits) compile_test_with_flags(test_traits non_caching_segments "${flags}") execute_commands_old_structure(segments non_caching_segment_traits - APPROXIMATE ARE_MERGEABLE ASSERTIONS - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT CONSTRUCTOR COMPARE_Y_AT_X_RIGHT - IS_VERTICAL VERTEX) + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT CONSTRUCTOR + COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE ASSERTIONS) execute_commands_new_structure(segments segment_traits - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT - IS_VERTICAL) + IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT) run_trapped_test(test_traits data/segments/vertex.pt data/segments/xcurves @@ -945,20 +894,23 @@ function(test_polycurve_conic_traits) # Execute_command_new_structure will only run the test on functors provided as the third, fourth and so on arguments. # To see how the input data directory should be structured for each functor, check the execute_commands_new_structure function in this file. execute_commands_new_structure(polycurves_conics polycurve_conic_traits - ARE_MERGEABLE - COMPARE_ENDPOINTS_XY COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT - CONSTRUCT_OPPOSITE - EQUAL + COMPARE_Y_AT_X INTERSECT + EQUAL IS_VERTICAL - MAKE_X_MONOTONE - MERGE - NUMBER_OF_POINTS SPLIT + ARE_MERGEABLE + COMPARE_Y_AT_X_LEFT + COMPARE_Y_AT_X_RIGHT + MAKE_X_MONOTONE PUSH_BACK PUSH_FRONT - TRIM - VERTEX) + NUMBER_OF_POINTS + VERTEX + CONSTRUCT_OPPOSITE + MERGE + COMPARE_ENDPOINTS_XY + TRIM) endfunction() @@ -973,21 +925,23 @@ function(test_polycurve_circular_arc_traits) compile_test_with_flags(test_traits circular_arc_polycurve "${flags}") - execute_commands_new_structure(polycurves_circular_arcs - polycurve_circular_arc_traits - ARE_MERGEABLE - COMPARE_ENDPOINTS_XY COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT - CONSTRUCT_OPPOSITE + execute_commands_new_structure(polycurves_circular_arcs polycurve_circular_arc_traits + COMPARE_Y_AT_X EQUAL - INTERSECT IS_VERTICAL + SPLIT + ARE_MERGEABLE + COMPARE_Y_AT_X_LEFT + COMPARE_Y_AT_X_RIGHT MAKE_X_MONOTONE - MERGE - NUMBER_OF_POINTS PUSH_BACK PUSH_FRONT - SPLIT - VERTEX) + NUMBER_OF_POINTS + VERTEX + CONSTRUCT_OPPOSITE + MERGE + COMPARE_ENDPOINTS_XY + INTERSECT) endfunction() #---------------------------------------------------------------------# @@ -1006,15 +960,15 @@ function(test_polycurve_bezier_traits) compile_test_with_flags(test_traits bezier_polycurve "${flags}") execute_commands_new_structure(polycurves_bezier test_polycurve_bezier_traits - ARE_MERGEABLE - COMPARE_ENDPOINTS_XY + MERGE EQUAL IS_VERTICAL NUMBER_OF_POINTS - MERGE PUSH_BACK PUSH_FRONT VERTEX + ARE_MERGEABLE + COMPARE_ENDPOINTS_XY # TODO (add data for these tests) # COMPARE_Y_AT_X # SPLIT @@ -1039,8 +993,8 @@ function(test_polyline_traits) compile_test_with_flags(test_traits test_polylines "${flags}") execute_commands_old_structure(polylines polyline_traits - APPROXIMATE ARE_MERGEABLE - COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT CONSTRUCTOR) + CONSTRUCTOR COMPARE_Y_AT_X_LEFT + COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE) endfunction() #---------------------------------------------------------------------# @@ -1055,8 +1009,8 @@ function(test_non_caching_polyline_traits) compile_test_with_flags(test_traits non_caching_polylines "${flags}") execute_commands_old_structure(polylines non_caching_polyline_traits - APPROXIMATE ARE_MERGEABLE - COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT CONSTRUCTOR) + CONSTRUCTOR COMPARE_Y_AT_X_LEFT + COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE) endfunction() #---------------------------------------------------------------------# @@ -1071,39 +1025,32 @@ function(test_linear_traits) compile_test_with_flags(test_traits linear "${flags}") execute_commands_old_structure(linear/segments linear_traits.segments - APPROXIMATE ARE_MERGEABLE - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT CONSTRUCTOR - IS_VERTICAL VERTEX) + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT + COMPARE_Y_AT_X_RIGHT CONSTRUCTOR ARE_MERGEABLE) execute_commands_new_structure(linear/segments linear_traits.segments - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT - IS_VERTICAL) + IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT) run_trapped_test(test_traits data/linear/segments/vertex.pt data/linear/segments/xcurves data/empty.zero data/linear/segments/vertex linear_traits.segments) execute_commands_old_structure(linear/rays linear_traits.rays - APPROXIMATE ARE_MERGEABLE - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT CONSTRUCTOR - IS_VERTICAL VERTEX) + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT + COMPARE_Y_AT_X_RIGHT CONSTRUCTOR ARE_MERGEABLE) execute_commands_new_structure(linear/rays linear_traits.rays - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT - IS_VERTICAL) + IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT) run_trapped_test(test_traits data/linear/rays/vertex.pt data/linear/rays/xcurves data/empty.zero data/linear/rays/vertex linear_traits.rays) execute_commands_new_structure(linear/lines linear_traits.lines - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT - COMPARE_X_ON_BOUNDARY COMPARE_X_NEAR_BOUNDARY COMPARE_Y_NEAR_BOUNDARY - IS_VERTICAL - INTERSECT - MERGE + IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT INTERSECT + SPLIT MERGE PARAMETER_SPACE_X PARAMETER_SPACE_Y - SPLIT) + COMPARE_X_ON_BOUNDARY COMPARE_X_NEAR_BOUNDARY COMPARE_Y_NEAR_BOUNDARY) endfunction() #---------------------------------------------------------------------# @@ -1122,13 +1069,11 @@ function(test_conic_traits) compile_test_with_flags(test_traits conics "${flags}") execute_commands_old_structure(conics conic_traits - APPROXIMATE ARE_MERGEABLE COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT - INTERSECT SPLIT MERGE) + INTERSECT SPLIT MERGE COMPARE_Y_AT_X_LEFT + COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE) execute_commands_new_structure(conics conic_traits - INTERSECT - MERGE - SPLIT) + INTERSECT SPLIT MERGE) run_trapped_test(test_traits data/conics/compare.pt data/empty.zero @@ -1147,13 +1092,11 @@ function(test_line_arc_traits) compile_test_with_flags(test_traits line_arcs "${flags}") execute_commands_old_structure(circular_lines line_arc_traits - APPROXIMATE ARE_MERGEABLE ASSERTIONS - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT - IS_VERTICAL MERGE VERTEX) + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT + ASSERTIONS COMPARE_Y_AT_X_RIGHT MERGE ARE_MERGEABLE) execute_commands_new_structure(circular_lines line_arc_traits - COMPARE_Y_AT_X - IS_VERTICAL) + IS_VERTICAL COMPARE_Y_AT_X) run_trapped_test(test_traits data/circular_lines/compare.pt data/empty.zero @@ -1176,14 +1119,11 @@ function(test_circular_arc_traits) compile_test_with_flags(test_traits circular_arcs "${flags}") execute_commands_old_structure(circular_arcs circular_arc_traits - APPROXIMATE ARE_MERGEABLE ASSERTIONS - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT - IS_VERTICAL MERGE VERTEX) + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT + ASSERTIONS COMPARE_Y_AT_X_RIGHT MERGE ARE_MERGEABLE) execute_commands_new_structure(circular_arcs circular_arc_traits - COMPARE_Y_AT_X - IS_VERTICAL - VERTEX) + VERTEX IS_VERTICAL COMPARE_Y_AT_X) endfunction() #---------------------------------------------------------------------# @@ -1198,13 +1138,11 @@ function(test_circular_line_arc_traits) compile_test_with_flags(test_traits circular_line_arcs "${flags}") execute_commands_old_structure(circular_line_arcs circular_line_arc_traits - APPROXIMATE ARE_MERGEABLE ASSERTIONS - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT CONSTRUCTOR - IS_VERTICAL MERGE VERTEX) + VERTEX IS_VERTICAL CONSTRUCTOR COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT + ASSERTIONS COMPARE_Y_AT_X_RIGHT MERGE ARE_MERGEABLE) execute_commands_new_structure(circular_line_arcs circular_line_arc_traits - COMPARE_Y_AT_X - IS_VERTICAL) + IS_VERTICAL COMPARE_Y_AT_X) run_trapped_test(test_traits data/circular_line_arcs/vertex.pt data/circular_line_arcs/xcurves @@ -1223,12 +1161,8 @@ function(test_circle_segments_traits) compile_test_with_flags(test_traits circle_segments "${flags}") execute_commands_old_structure(circle_segments circle_segments_traits - APPROXIMATE ARE_MERGEABLE - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT CONSTRUCTOR - IS_VERTICAL VERTEX) - - execute_commands_new_structure(circle_segments circle_segments_traits - APPROXIMATE) + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT + COMPARE_Y_AT_X_RIGHT CONSTRUCTOR ARE_MERGEABLE) run_trapped_test(test_traits data/circle_segments/points data/circle_segments/xcurves.8 @@ -1266,8 +1200,8 @@ function(test_bezier_traits) compile_test_with_flags(test_traits Bezier "${flags}") execute_commands_old_structure(bezier bezier_traits - APPROXIMATE ARE_MERGEABLE ASSERTIONS - COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT CONSTRUCTOR SPLIT) + COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT SPLIT + CONSTRUCTOR ASSERTIONS ARE_MERGEABLE) endfunction() #---------------------------------------------------------------------# @@ -1283,14 +1217,14 @@ function(test_spherical_arc_traits) compile_test_with_flags(test_traits geodesic_arcs_on_sphere "${flags}") execute_commands_old_structure(spherical_arcs spherical_arc_traits - APPROXIMATE ARE_MERGEABLE ASSERTIONS - COMPARE COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT INTERSECT CONSTRUCTOR - MAKE_X_MONOTONE MERGE SPLIT) + COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT INTERSECT + CONSTRUCTOR + COMPARE MAKE_X_MONOTONE SPLIT MERGE ASSERTIONS ARE_MERGEABLE) execute_commands_new_structure(spherical_arcs spherical_arc_traits - APPROXIMATE - COMPARE_X_ON_BOUNDARY COMPARE_X_NEAR_BOUNDARY COMPARE_Y_NEAR_BOUNDARY - INTERSECT) + INTERSECT + COMPARE_X_ON_BOUNDARY COMPARE_X_NEAR_BOUNDARY + COMPARE_Y_NEAR_BOUNDARY) run_trapped_test(test_traits data/spherical_arcs/compare.pt data/spherical_arcs/compare.xcv @@ -1317,12 +1251,8 @@ function(test_rational_arc_traits) data/empty.zero data/compare rational_arc_traits) execute_commands_new_structure(rational_arcs rational_arc_traits - COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT - COMPARE_X_ON_BOUNDARY COMPARE_X_NEAR_BOUNDARY COMPARE_Y_NEAR_BOUNDARY - IS_VERTICAL - MERGE - SPLIT - VERTEX) + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT SPLIT MERGE + COMPARE_X_ON_BOUNDARY COMPARE_X_NEAR_BOUNDARY COMPARE_Y_NEAR_BOUNDARY) endfunction() #---------------------------------------------------------------------# @@ -1343,13 +1273,8 @@ function(test_algebraic_traits_gmp) execute_commands_new_structure(algebraic algebraic_traits_gmp COMPARE COMPARE_Y_AT_X COMPARE_Y_AT_X_RIGHT COMPARE_Y_AT_X_LEFT - IS_VERTICAL - INTERSECT - MAKE_X_MONOTONE - MERGE - PARAMETER_SPACE_X PARAMETER_SPACE_Y - SPLIT - VERTEX) + MAKE_X_MONOTONE IS_VERTICAL VERTEX SPLIT MERGE INTERSECT + PARAMETER_SPACE_X PARAMETER_SPACE_Y) endfunction() #---------------------------------------------------------------------# @@ -1367,13 +1292,8 @@ function(test_algebraic_traits_leda) execute_commands_new_structure(algebraic algebraic_traits_leda COMPARE COMPARE_Y_AT_X COMPARE_Y_AT_X_RIGHT COMPARE_Y_AT_X_LEFT - IS_VERTICAL - INTERSECT - MAKE_X_MONOTONE - MERGE - PARAMETER_SPACE_X PARAMETER_SPACE_Y - SPLIT - VERTEX) + MAKE_X_MONOTONE IS_VERTICAL VERTEX SPLIT MERGE INTERSECT + PARAMETER_SPACE_X PARAMETER_SPACE_Y) endfunction() @@ -1395,38 +1315,10 @@ function(test_algebraic_traits_core) execute_commands_new_structure(algebraic algebraic_traits_core COMPARE COMPARE_Y_AT_X COMPARE_Y_AT_X_RIGHT COMPARE_Y_AT_X_LEFT - IS_VERTICAL - INTERSECT - MAKE_X_MONOTONE - MERGE - PARAMETER_SPACE_X PARAMETER_SPACE_Y - SPLIT - VERTEX) + MAKE_X_MONOTONE IS_VERTICAL VERTEX SPLIT MERGE INTERSECT + PARAMETER_SPACE_X PARAMETER_SPACE_Y) endfunction() -#---------------------------------------------------------------------# -# Draw_aos tests -#---------------------------------------------------------------------# - -function (test_drawing_planar) - set(nt ${CGAL_GMPQ_NT}) - set(kernel ${CARTESIAN_KERNEL}) - set(geom_traits ${POLYLINE_GEOM_TRAITS}) - set(flags "-DCGAL_USE_BASIC_VIEWER") - compile_test_with_flags(test_drawing_planar drawing "${flags}") - # target_link_libraries(test_drawing_planar PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets) - target_link_libraries(test_drawing_planar PRIVATE CGAL::CGAL_Basic_viewer CGAL::CGAL_Qt6) -endfunction() - -function (test_drawing_spherical) - set(nt ${CGAL_GMPQ_NT}) - set(kernel ${CARTESIAN_KERNEL}) - set(geom_traits ${POLYLINE_GEOM_TRAITS}) - set(flags "-DTEST_NT=${nt} -DTEST_KERNEL=${kernel} -DTEST_GEOM_TRAITS=${geom_traits}") - - compile_test_with_flags(test_drawing_spherical drawing "${flags}") - target_link_libraries(test_drawing_spherical PRIVATE CGAL::CGAL_Basic_viewer CGAL::CGAL_Qt6) -endfunction() configure("") compile_and_run(construction_test_suite_generator) @@ -1509,10 +1401,6 @@ compile_and_run(test_io) compile_and_run(test_sgm) compile_and_run(test_polycurve_intersection) - -test_drawing_planar() -test_drawing_spherical() - if(CGAL_DISABLE_GMP) get_directory_property(LIST_OF_TESTS TESTS) foreach(_test ${LIST_OF_TESTS}) diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_drawing_planar.cpp b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_drawing_planar.cpp deleted file mode 100644 index 01532380433..00000000000 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_drawing_planar.cpp +++ /dev/null @@ -1,454 +0,0 @@ - -#include "CGAL/Arr_algebraic_segment_traits_2.h" -#include "CGAL/Arr_circle_segment_traits_2.h" -#include "CGAL/Arr_conic_traits_2.h" -#include "CGAL/Arr_default_dcel.h" -#include "CGAL/Arr_enums.h" -#include "CGAL/Arr_linear_traits_2.h" -#include "CGAL/Arr_rational_function_traits_2.h" -#include "CGAL/Arr_segment_traits_2.h" -#include "CGAL/Arr_spherical_topology_traits_2.h" -#include "CGAL/Arrangement_2.h" -#include "CGAL/Arrangement_on_surface_2.h" -#include "CGAL/CORE_algebraic_number_traits.h" -#include "CGAL/Draw_aos/Arr_viewer.h" -#include -#include -#include -#include "CGAL/Exact_predicates_exact_constructions_kernel.h" -#include "CGAL/Exact_predicates_inexact_constructions_kernel.h" -#include -#include - -// void draw_segments_arr_1() { -// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; -// using Segment_traits = CGAL::Arr_segment_traits_2; -// using Point_2 = Segment_traits::Point_2; -// using Arrangement = CGAL::Arrangement_2; -// // Make a square -// Arrangement arr; -// auto traits = arr.traits(); -// auto cst_x_curve = traits->construct_x_monotone_curve_2_object(); -// auto square = {cst_x_curve({0, 0}, {5, 0}), cst_x_curve({5, 0}, {5, 5}), cst_x_curve({5, 5}, {0, 5}), -// cst_x_curve({0, 5}, {0, 0})}; -// insert(arr, square.begin(), square.end()); -// auto hole_triangle = { -// cst_x_curve({1, 1}, {2, 1}), -// cst_x_curve({2, 1}, {2, 2}), -// cst_x_curve({2, 2}, {1, 1}), -// }; -// insert(arr, hole_triangle.begin(), hole_triangle.end()); -// // CGAL::draw_viewer(arr); -// } - -// void draw_segments_arr_2() { -// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; -// using Segment_traits = CGAL::Arr_segment_traits_2; -// using Point_2 = Segment_traits::Point_2; -// using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2; -// using Arrangement = CGAL::Arrangement_2; -// Arrangement arr; -// auto traits = arr.traits(); -// auto cst_x_curve = traits->construct_x_monotone_curve_2_object(); -// // make a hexagon centered at the origin with radius 10 -// double radius = 10.0; -// std::array hexagon_points = {{ -// {radius * cos(0 * CGAL_PI / 3), radius * sin(0 * CGAL_PI / 3)}, // 0° -// {radius * cos(1 * CGAL_PI / 3), radius * sin(1 * CGAL_PI / 3)}, // 60° -// {radius * cos(2 * CGAL_PI / 3), radius * sin(2 * CGAL_PI / 3)}, // 120° -// {radius * cos(3 * CGAL_PI / 3), radius * sin(3 * CGAL_PI / 3)}, // 180° -// {radius * cos(4 * CGAL_PI / 3), radius * sin(4 * CGAL_PI / 3)}, // 240° -// {radius * cos(5 * CGAL_PI / 3), radius * sin(5 * CGAL_PI / 3)}, // 300° -// }}; -// std::array hexagon; -// for(size_t i = 0; i < hexagon_points.size(); ++i) { -// size_t next_i = (i + 1) % hexagon_points.size(); -// hexagon[i] = cst_x_curve(hexagon_points[i], hexagon_points[next_i]); -// } -// // rect hole -// auto hole_rectangle = {cst_x_curve({-2, -2}, {2, -2}), cst_x_curve({2, -2}, {2, 2}), cst_x_curve({2, 2}, {-2, 2}), -// cst_x_curve({-2, 2}, {-2, -2})}; -// // iso vertex inside rect hole -// auto iso_vertex_inside_hole = Point_2{0.5, 0.5}; -// // degenerate segment below the rect hole -// auto degenerate_segment = cst_x_curve({0, -3}, {1, -3}); - -// CGAL::insert_point(arr, iso_vertex_inside_hole); -// CGAL::insert(arr, hexagon.begin(), hexagon.end()); -// CGAL::insert(arr, hole_rectangle.begin(), hole_rectangle.end()); -// CGAL::insert(arr, degenerate_segment); -// CGAL::draw_viewer(arr); -// } - -// void draw_segments_arr_3() { -// // generate random segments and draw them -// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; -// using Segment_traits = CGAL::Arr_segment_traits_2; -// using Point_2 = Segment_traits::Point_2; -// using Arrangement = CGAL::Arrangement_2; -// using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2; -// using Random = CGAL::Random; - -// Arrangement arr; -// auto traits = arr.traits(); -// auto cst_x_curve = traits->construct_x_monotone_curve_2_object(); -// Random random; -// std::vector segments; -// std::cout << "Generating random segments..." << std::endl; -// for(int i = 0; i < 100; ++i) { -// // generate random points -// Point_2 p1(random.get_double(-100, 100), random.get_double(-100, 100)); -// Point_2 p2(random.get_double(-100, 100), random.get_double(-100, 100)); -// // create a segment -// X_monotone_curve_2 seg = cst_x_curve(p1, p2); -// segments.push_back(seg); -// } - -// std::cout << "Inserting segments into the arrangement..." << std::endl; -// // insert segments into the arrangement -// CGAL::insert(arr, segments.begin(), segments.end()); - -// // draw the arrangement -// // CGAL::draw_viewer(arr); -// } - -// void draw_segments_arr_4() { -// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; -// using Segment_traits = CGAL::Arr_segment_traits_2; -// using Point_2 = Segment_traits::Point_2; -// using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2; -// using Arrangement = CGAL::Arrangement_2; -// Arrangement arr; -// auto traits = arr.traits(); -// auto cst_x_curve = traits->construct_x_monotone_curve_2_object(); - -// std::vector segments; - -// std::vector polyline1{ -// {6, -21}, {6, -3}, {13, -3}, {13, -12}, {18, -12}, {18, -4}, {18, -3}, {25, -3}, {25, -21}, {6, -21}, -// }; -// for(size_t i = 0; i < polyline1.size() - 1; ++i) { -// segments.push_back(cst_x_curve(polyline1[i], polyline1[i + 1])); -// } - -// std::vector polyline2{ -// {-27, -14}, {-24, -14}, {-21, -16}, {-19, -18}, {-18, -21}, {-17, -24}, {-18, -28}, {-19, -30}, {-22, -32}, -// {-24, -33}, {-29, -33}, {-34, -33}, {-38, -32}, {-43, -30}, {-46, -29}, {-50, -25}, {-53, -21}, {-53, -17}, -// {-54, -12}, {-53, -7}, {-52, -2}, {-50, 2}, {-45, 5}, {-40, 6}, {-34, 7}, {-29, 7}, {-23, 7}, -// {-20, 6}, {-18, 5}, {-16, 2}, {-15, 0}, {-16, -3}, {-17, -3}, {-18, -1}, {-19, 1}, {-20, 4}, -// {-22, 4}, {-26, 4}, {-28, 4}, {-31, 4}, {-33, 4}, {-37, 4}, {-41, 3}, {-44, 2}, {-47, 1}, -// {-48, 0}, {-49, -2}, {-50, -5}, {-51, -8}, {-51, -13}, {-51, -16}, {-50, -18}, {-49, -22}, {-46, -24}, -// {-42, -27}, {-40, -29}, {-36, -29}, {-32, -30}, {-28, -31}, {-24, -31}, {-21, -30}, {-19, -28}, {-19, -25}, -// {-20, -23}, {-21, -21}, {-24, -18}, {-26, -16}, {-27, -15}, {-27, -14}, -// }; -// for(size_t i = 0; i < polyline2.size() - 1; ++i) { -// segments.push_back(cst_x_curve(polyline2[i], polyline2[i + 1])); -// } - -// CGAL::insert(arr, segments.begin(), segments.end()); - -// CGAL::draw_viewer(arr); -// } - -// void draw_segments_arr_5() { -// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; -// using Segment_traits = CGAL::Arr_segment_traits_2; -// using Point_2 = Segment_traits::Point_2; -// using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2; -// using Arrangement = CGAL::Arrangement_2; -// Arrangement arr; -// auto traits = arr.traits(); -// auto cst_x_curve = traits->construct_x_monotone_curve_2_object(); - -// std::vector segments; - -// std::vector polyline1{ -// {11, 23}, {12, -13}, {17, -13}, {18, 1}, {18, 16}, {18, 23}, {15, 35}, {15, 44}, {18, 47}, {19, 42}, -// {19, 37}, {20, 28}, {23, 21}, {23, 9}, {24, -7}, {22, -15}, {20, -19}, {15, -19}, {10, -16}, {7, -14}, -// {7, -3}, {5, 11}, {1, 20}, {0, 35}, {1, 45}, {3, 51}, {5, 53}, {11, 53}, {19, 53}, {23, 49}, -// {25, 40}, {28, 31}, {34, 16}, {35, 7}, {38, -11}, {44, -11}, {43, -7}, {43, -5}, {42, 7}, {40, 23}, -// {38, 30}, {35, 49}, {19, 57}, {8, 58}, {-2, 55}, {-2, 30}, {-3, 15}, {-3, -16}, {1, -20}, {12, -22}, -// {20, -22}, {25, -21}, {26, -14}, {28, -3}, {27, 15}, {23, 31}, {22, 44}, {20, 49}, {15, 49}, {10, 46}, -// {8, 39}, {8, 32}, {8, 28}, {11, 23}, -// }; -// for(size_t i = 0; i < polyline1.size() - 1; ++i) { -// segments.push_back(cst_x_curve(polyline1[i], polyline1[i + 1])); -// } - -// CGAL::insert(arr, segments.begin(), segments.end()); - -// CGAL::draw_viewer(arr); -// } - -// void draw_segments_arr_6() { -// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; -// using Segment_traits = CGAL::Arr_segment_traits_2; -// using Point_2 = Segment_traits::Point_2; -// using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2; -// using Arrangement = CGAL::Arrangement_2; -// Arrangement arr; -// auto traits = arr.traits(); -// auto cst_x_curve = traits->construct_x_monotone_curve_2_object(); - -// std::vector segments; - -// std::vector polyline1{ -// {9, -3}, {11, -34}, {26, -34}, {26, -8}, {26, -34}, {36, -34}, {36, -31}, {36, -27}, {37, -23}, {41, -23}, -// {47, -23}, {49, -16}, {49, -2}, {42, 10}, {41, 0}, {41, -19}, {41, 0}, {42, 10}, {30, 10}, {28, 6}, -// {28, 2}, {29, -30}, {28, 2}, {28, 6}, {30, 10}, {42, 10}, {29, 16}, {18, 12}, {9, -3}, -// }; -// for(size_t i = 0; i < polyline1.size() - 1; ++i) { -// segments.push_back(cst_x_curve(polyline1[i], polyline1[i + 1])); -// } - -// CGAL::insert(arr, segments.begin(), segments.end()); - -// CGAL::draw_viewer(arr); -// } - -// void draw_linear_arr_1() { -// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; -// using Traits = CGAL::Arr_linear_traits_2; -// using Point_2 = Traits::Point_2; -// using Line_2 = Traits::Line_2; -// using Ray_2 = Traits::Ray_2; -// using Curve_2 = Traits::Curve_2; -// using Arrangement = CGAL::Arrangement_2; -// using Face_const_handle = Arrangement::Face_const_handle; -// using Halfedge_const_handle = Arrangement::Halfedge_const_iterator; -// using X_monotone_curve_2 = Traits::X_monotone_curve_2; - -// Arrangement arr; -// auto x_axis = X_monotone_curve_2(Ray_2(Point_2(0, 0), Point_2(1, 0))); -// auto y_axis = X_monotone_curve_2(Ray_2(Point_2(0, 0), Point_2(0, 1))); -// CGAL::insert(arr, x_axis); -// CGAL::insert(arr, y_axis); - -// CGAL::draw_viewer(arr); -// } - -void draw_linear_arr_2() { - using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; - using Traits = CGAL::Arr_linear_traits_2; - using Point_2 = Traits::Point_2; - using Line_2 = Traits::Line_2; - using Segment_2 = Traits::Segment_2; - using Ray_2 = Traits::Ray_2; - using Curve_2 = Traits::Curve_2; - using Arrangement = CGAL::Arrangement_2; - using Face_const_handle = Arrangement::Face_const_handle; - using Halfedge_const_handle = Arrangement::Halfedge_const_iterator; - using X_monotone_curve_2 = Traits::X_monotone_curve_2; - - Arrangement arr; - auto& traits = *arr.traits(); - // Insert a n*n grid, each cell is a square of size 5 - int n = 5; - for(int i = 0; i < n; ++i) { - Point_2 p1(i * 5, 0); - Point_2 p2(i * 5, 1); - CGAL::insert(arr, Curve_2(Line_2(p1, p2))); - } - for(int i = 0; i < n; ++i) { - Point_2 p1(0, i * 5); - Point_2 p2(1, i * 5); - CGAL::insert(arr, Curve_2(Line_2(p1, p2))); - } - // Generate a inner square(2*2) for all cells - // And an inner triangle for each square - for(int i = 0; i < n; ++i) { - for(int j = 0; j < n; ++j) { - Point_2 p1(i * 5 + 1, j * 5 + 1); - Point_2 p2(i * 5 + 4, j * 5 + 4); - CGAL::insert(arr, Curve_2(Segment_2(p1, Point_2(p2.x(), p1.y())))); - CGAL::insert(arr, Curve_2(Segment_2(Point_2(p1.x(), p2.y()), p2))); - CGAL::insert(arr, Curve_2(Segment_2(p1, Point_2(p1.x(), p2.y())))); - CGAL::insert(arr, Curve_2(Segment_2(Point_2(p2.x(), p1.y()), p2))); - - // Insert a triangle inside the square - Point_2 tri_p1(i * 5 + 2, j * 5 + 2); - Point_2 tri_p2(i * 5 + 3, j * 5 + 2); - Point_2 tri_p3(i * 5 + 2.5, j * 5 + 3); - CGAL::insert(arr, Curve_2(Segment_2(tri_p1, tri_p2))); - CGAL::insert(arr, Curve_2(Segment_2(tri_p2, tri_p3))); - CGAL::insert(arr, Curve_2(Segment_2(tri_p3, tri_p1))); - - // Connect the triangle to the square - Point_2 top(i * 5 + 2.5, j * 5 + 4); - CGAL::insert(arr, Curve_2(Segment_2(tri_p1, top))); - } - } - std::cout << "Arrangement has " << arr.number_of_faces() << " faces." << std::endl; - CGAL::draw_viewer(arr); -} - -// void draw_linear_arr_3() { -// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; -// using Traits = CGAL::Arr_linear_traits_2; -// using Point_2 = Traits::Point_2; -// using Line_2 = Traits::Line_2; -// using Segment_2 = Traits::Segment_2; -// using Ray_2 = Traits::Ray_2; -// using Curve_2 = Traits::Curve_2; -// using Arrangement = CGAL::Arrangement_2; -// using Face_const_handle = Arrangement::Face_const_handle; -// using Halfedge_const_handle = Arrangement::Halfedge_const_iterator; -// using X_monotone_curve_2 = Traits::X_monotone_curve_2; - -// std::vector points{ -// {11, 23}, {12, -13}, {17, -13}, {18, 1}, {18, 16}, {18, 23}, {15, 35}, {15, 44}, {18, 47}, {19, 42}, -// {19, 37}, {20, 28}, {23, 21}, {23, 9}, {24, -7}, {22, -15}, {20, -19}, {15, -19}, {10, -16}, {7, -14}, -// {7, -3}, {5, 11}, {1, 20}, {0, 35}, {1, 45}, {3, 51}, {5, 53}, {11, 53}, {19, 53}, {23, 49}, -// {25, 40}, {28, 31}, {34, 16}, {35, 7}, {38, -11}, {44, -11}, {43, -7}, {43, -5}, {42, 7}, {40, 23}, -// {38, 30}, {35, 49}, {19, 57}, {8, 58}, {-2, 55}, {-2, 30}, {-3, 15}, {-3, -16}, {1, -20}, {12, -22}, -// {20, -22}, {25, -21}, {26, -14}, {28, -3}, {27, 15}, {23, 31}, {22, 44}, {20, 49}, {15, 49}, {10, 46}, -// {8, 39}, {8, 32}, {8, 28}, {11, 23}, -// }; - -// Arrangement arr; -// auto& traits = *arr.traits(); -// std::vector segments; -// for(size_t i = 0; i < points.size() - 1; ++i) { -// Point_2 p1 = points[i]; -// Point_2 p2 = points[i + 1]; -// // create a segment -// X_monotone_curve_2 seg = traits.construct_x_monotone_curve_2_object()(p1, p2); -// segments.push_back(seg); -// } - -// // insert segments into the arrangement -// CGAL::insert(arr, segments.begin(), segments.end()); - -// CGAL::draw_viewer(arr); -// } -// // supports segments -// void draw_circle_segs_arr() { -// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; -// using Traits = CGAL::Arr_circle_segment_traits_2; -// using Point_2 = Traits::Point_2; -// using Curve_2 = Traits::Curve_2; -// using Arrangement = CGAL::Arrangement_2; - -// auto traits = Traits(); -// Arrangement arr; -// auto cv1 = Curve_2(Exact_kernel::Circle_2({0, 0}, 10)); -// CGAL::insert(arr, cv1); -// CGAL::draw(arr); -// } - -// void draw_conic_arcs_arr() { -// using Nt_traits = CGAL::CORE_algebraic_number_traits; -// using Rational = Nt_traits::Rational; -// using Rat_kernel = CGAL::Cartesian; -// using Rat_point = Rat_kernel::Point_2; -// using Rat_segment = Rat_kernel::Segment_2; -// using Rat_circle = Rat_kernel::Circle_2; -// using Algebraic = Nt_traits::Algebraic; -// using Alg_kernel = CGAL::Cartesian; -// using Traits = CGAL::Arr_conic_traits_2; -// using Point = Traits::Point_2; -// using Conic_arc = Traits::Curve_2; -// using X_monotone_conic_arc = Traits::X_monotone_curve_2; -// using Arrangement = CGAL::Arrangement_2; - -// Arrangement arr; -// auto traits = Traits(); -// auto cst_x_curve = traits.construct_curve_2_object(); - -// auto vert_seg = cst_x_curve(Rat_segment(Rat_point(0, 0), Rat_point(1, 0))); -// auto hor_seg = cst_x_curve(Rat_segment(Rat_point(0, 0), Rat_point(0, 1))); - -// CGAL::insert(arr, vert_seg); -// CGAL::insert(arr, hor_seg); - -// CGAL::draw(arr); -// } - -// void draw_algebraic_arr() { -// #if CGAL_USE_GMP && CGAL_USE_MPFI -// #include -// using Integer = CGAL::Gmpz; -// #elif CGAL_USE_CORE -// #include -// using Integer = CORE::BigInt; -// #else -// #include -// using Integer = LEDA::integer; -// #endif -// using Traits = CGAL::Arr_algebraic_segment_traits_2; -// using Arrangement = CGAL::Arrangement_2; -// using Polynomial = Traits::Polynomial_2; -// using X_monotone_curve_2 = Traits::X_monotone_curve_2; -// using Parameter_space_in_x_2 = Traits::Parameter_space_in_x_2; - -// Arrangement arr; -// auto traits = arr.traits(); -// X_monotone_curve_2 cv; -// auto param_space_in_x = traits->parameter_space_in_x_2_object(); -// auto ctr_cv = traits->construct_curve_2_object(); -// Polynomial x = CGAL::shift(Polynomial(1), 1, 0); -// Polynomial y = CGAL::shift(Polynomial(1), 1, 1); -// auto cst_x_curve = traits->construct_x_monotone_segment_2_object(); -// auto curve = ctr_cv(CGAL::ipower(x, 4) + CGAL::ipower(y, 3) - 1); -// CGAL::insert(arr, curve); -// // CGAL::draw(arr); -// } - -// void draw_rational_arr() { -// using AK1 = CGAL::Algebraic_kernel_d_1; -// using Traits = CGAL::Arr_rational_function_traits_2; -// using Arrangement = CGAL::Arrangement_2; -// using Polynomial = Traits::Polynomial_1; -// using Alg_real = Traits::Algebraic_real_1; -// using Bound = Traits::Bound; - -// auto traits = Traits(); -// auto approx = traits.approximate_2_object(); -// auto cst_x_curve = traits.construct_x_monotone_curve_2_object(); -// Arrangement arr; -// Polynomial x = CGAL::shift(Polynomial(1), 1); -// Polynomial P1 = CGAL::ipower(x, 4) - 6 * x * x + 8; -// Alg_real l(Bound(-2.1)), r(Bound(2.1)); -// auto cv1 = cst_x_curve(P1, l, r); -// CGAL::insert(arr, cv1); -// // CGAL::draw(arr); -// } - -// void draw_spherical_arr() { -// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; -// using Direction_3 = Exact_kernel::Direction_3; -// using Geodesic_traits = CGAL::Arr_geodesic_arc_on_sphere_traits_2; -// using Spherical_topo_traits = CGAL::Arr_spherical_topology_traits_2; -// using Arrangement = CGAL::Arrangement_on_surface_2; -// using Point_2 = Geodesic_traits::Point_2; - -// Arrangement arr; -// auto traits = arr.geometry_traits(); -// auto cst_pt = traits->construct_point_2_object(); -// auto cst_param = traits->parameter_space_in_x_2_object(); - -// Point_2 p1 = cst_pt(Direction_3(1, 0, 0)); -// } - -using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; -using Point = Kernel::Point_2; -// void write_polyline(std::string filename, const std::vector& points) { -// std::ofstream ofs_index("/Users/shep/codes/aos_2_js_helper/shapes.txt"); -// ofs_index << filename << std::endl; -// std::ofstream ofs("/Users/shep/codes/aos_2_js_helper/" + filename); -// for(const auto& pt : points) { -// ofs << pt << "\n"; -// } -// ofs << std::endl; -// } - -int main() { - // draw_segments_arr_6(); - draw_linear_arr_2(); - // test_zone(); - // draw_conic_arcs_arr(); - // draw_algebraic_arr(); - // draw_rational_arr(); - // draw_circle_segs_arr(); - return 0; -} \ No newline at end of file diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_drawing_spherical.cpp b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_drawing_spherical.cpp deleted file mode 100644 index 1664696b293..00000000000 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_drawing_spherical.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "CGAL/Constrained_triangulation_2.h" -#include "CGAL/Graphics_scene.h" -#include "CGAL/Triangulation_data_structure_2.h" -#include "CGAL/Triangulation_vertex_base_with_info_2.h" -#include -#include -#include -#include -#include -#include "CGAL/Random.h" -#include "CGAL/IO/Color.h" -#include "CGAL/draw_triangulation_2.h" -#include "CGAL/mark_domain_in_triangulation.h" -#include - -template -struct Polygon_triangulation_gs_options : public CGAL::Graphics_scene_options -{ - using T2 = typename PT::Triangulation; - template - Polygon_triangulation_gs_options(IPM ipm) { - this->colored_face = [](const T2&, const typename PT::Finite_faces_iterator) -> bool { return true; }; - - this->face_color = [ipm](const T2&, const typename PT::Finite_faces_iterator fh) -> CGAL::IO::Color { - if(!get(ipm, fh)) { - std::cout << "Face not in domain, returning black color." << std::endl; - return CGAL::IO::Color(0, 0, 0); - } - CGAL::Random random((unsigned int)(std::size_t)(&*fh)); - return CGAL::get_random_color(random); - }; - - this->draw_face = [ipm](const T2&, const typename PT::Finite_faces_iterator fh) -> bool { return true; }; - - this->draw_edge = [ipm](const T2& pt, const typename PT::Finite_edges_iterator eh) -> bool { - typename PT::Face_handle fh1 = eh->first; - typename PT::Face_handle fh2 = pt.mirror_edge(*eh).first; - return get(ipm, fh1) || get(ipm, fh2); - }; - } -}; - -int main() { - using K = CGAL::Exact_predicates_inexact_constructions_kernel; - using Vb = CGAL::Triangulation_vertex_base_with_info_2; - using Fb = CGAL::Constrained_triangulation_face_base_2; - using Tds = CGAL::Triangulation_data_structure_2; - using Cdt = CGAL::Constrained_triangulation_2; - using Point = K::Point_2; - - Cdt cdt; - std::vector outer = {{4, 1}, {4, 4}, {2.5, 4}, {2.32026, 3.28104}, {2.32026, 2.64052}, - {2.5, 3}, {3, 2}, {2.32026, 2}, {2.32026, 3.28104}, {2.5, 4}, - {2.32026, 4}, {2.32026, 1}, {4, 1}}; - std::vector inner = {Point(0, 0), Point(0.5, 0), Point(0.5, 0.5), Point(0.5, 0), - Point(1, 0), Point(1, 1), Point(0, 1)}; - std::vector outer_constraint = {{4, 1}, - {4, 4}, - {2.5, 4}, - {2.32026, 3.28104}, - {1.32026, 3.28104}, - {1.32026, 2.64052}, - {2.32026, 2.64052}, - {2.5, 3}, - {3, 2}, - {2.32026, 2}, - {1.32026, 2}, - {1.32026, 3.28104}, - {2.32026, 3.28104}, - {2.5, 4}, - {2.32026, 4}, - {1.32026, 4}, - {1.32026, 1}, - {2.32026, 1}, - {4, 1}}; - - auto add_info = [](const Point& p) { return std::make_pair(p, 1); }; - - cdt.insert_with_info>(boost::make_transform_iterator(outer.begin(), add_info), - boost::make_transform_iterator(outer.end(), add_info)); - // cdt.insert_with_info>(boost::make_transform_iterator(inner.begin(), add_info), - // boost::make_transform_iterator(inner.end(), add_info)); - cdt.insert_constraint(outer_constraint.begin(), outer_constraint.end(), true); - // cdt.insert_constraint(inner.begin(), inner.end(), true); - using In_domain_map = CGAL::unordered_flat_map; - In_domain_map in_domain_map; - boost::associative_property_map in_domain(in_domain_map); - - CGAL::mark_domain_in_triangulation(cdt, in_domain); - - std::cout << "Number of faces in triangulation: " << cdt.number_of_faces() << std::endl; - - CGAL::Graphics_scene_options - gso; - gso.face_color = [&](const Cdt::Triangulation&, const typename Cdt::Finite_faces_iterator fh) -> CGAL::IO::Color { - if(!in_domain_map[fh]) { - return CGAL::IO::Color(255, 255, 255); // black for faces not in domain - } - std::array vertices; - for(int i = 0; i < 3; ++i) { - vertices[i] = fh->vertex(i)->info(); - } - if(std::any_of(vertices.begin(), vertices.end(), [](auto idx) { return idx == 0; })) { - return CGAL::IO::Color(255, 255, 255); - } - CGAL::Random rand((std::size_t)(&*fh)); - return CGAL::get_random_color(rand); - }; - gso.colored_face = [&](const Cdt::Triangulation&, const typename Cdt::Finite_faces_iterator) -> bool { - return true; // always color faces - }; - - CGAL::draw(cdt, gso, "Polygon Triangulation Viewer"); -} \ No newline at end of file