Code cleanup and bug fixes

This commit is contained in:
Shepard Liu 2025-07-08 09:53:24 +08:00
parent 99aeb5f80a
commit 30b9a29ee9
27 changed files with 1985 additions and 1991 deletions

View File

@ -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(

View File

@ -1,7 +1,9 @@
#include "CGAL/Random.h"
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Arrangement_2.h>
#include <CGAL/Arr_segment_traits_2.h>
#include <CGAL/draw_arrangement_2.h>
#include <iterator>
using Kernel = CGAL::Exact_predicates_exact_constructions_kernel;
using Traits = CGAL::Arr_segment_traits_2<Kernel>;
@ -17,9 +19,8 @@ using Arrangement_2 = CGAL::Arrangement_2<Traits>;
* \param sat Saturation component range: [0, 1]
* \param value Value component range: [0, 1]
* \return tuple<red, green, blue>, where each component is in the range [0, 255]
*/
std::tuple<unsigned char, unsigned char, unsigned char>
hsv_to_rgb(float hue, float sat, float value) {
*/
std::tuple<unsigned char, unsigned char, unsigned char> 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<Arrangement_2, typename Arrangement_2::Vertex_const_handle,
typename Arrangement_2::Halfedge_const_handle, typename Arrangement_2::Face_const_handle>
gso;
gso.colored_face = [](const Arrangement_2&, Arrangement_2::Face_const_handle) -> bool { return true; };
CGAL::Graphics_scene_options<Arrangement_2,
typename Arrangement_2::Vertex_const_handle,
typename Arrangement_2::Halfedge_const_handle,
typename Arrangement_2::Face_const_handle> 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;
}

View File

@ -2,6 +2,7 @@
// Constructing an arrangement of arcs of rational functions.
#include <CGAL/config.h>
#include <CGAL/draw_arrangement_2.h>
#ifndef CGAL_USE_CORE
#include <iostream>
@ -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;
}

View File

@ -4,6 +4,7 @@
#include <cassert>
#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;
}

View File

@ -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 <typename Geom_traits, bool Has_approximate_2>
template <typename GeomTraits, bool Has_approximate_2>
class Arr_approximate_point_2_impl;
template <typename Geom_traits>
class Arr_approximate_point_2_impl<Geom_traits, true>
template <typename GeomTraits>
class Arr_approximate_point_2_impl<GeomTraits, true>
{
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<GeomTraits>;
using Point_2 = typename Traits_adaptor<GeomTraits>::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 <typename Kernel>
class Arr_approximate_point_2_impl<Arr_rational_function_traits_2<Kernel>, true>
{
using Geom_traits = Arr_rational_function_traits_2<Kernel>;
using Approx_traits = Arr_approximation_geometry_traits<Geom_traits>;
using Point_2 = typename Traits_adaptor<Geom_traits>::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 <typename Geom_traits>
class Arr_approximate_point_2_impl<Geom_traits, false>
template <typename GeomTraits>
class Arr_approximate_point_2_impl<GeomTraits, false>
{
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<GeomTraits>;
using Point_2 = typename Traits_adaptor<GeomTraits>::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 <typename Geom_traits>
template <typename GeomTraits>
using Arr_approximate_point_2 =
internal::Arr_approximate_point_2_impl<Geom_traits, has_approximate_2<Geom_traits>::value>;
internal::Arr_approximate_point_2_impl<GeomTraits,
has_approximate_2_object_v<GeomTraits> &&
has_operator_point_v<GeomTraits, typename GeomTraits::Approximate_2>>;
} // namespace draw_aos
} // namespace CGAL
#endif // CGAL_DRAW_AOS_ARR_APPROXIMATE_POINT_2_H

View File

@ -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 <boost/iterator/function_output_iterator.hpp>
#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 <typename GeomTraits>
class Arr_approximate_point_2_at_x
{
using Point_2 = typename Traits_adaptor<GeomTraits>::Point_2;
using X_monotone_curve_2 = typename Traits_adaptor<GeomTraits>::X_monotone_curve_2;
using Intersect_2 = typename Traits_adaptor<GeomTraits>::Intersect_2;
using FT = typename Traits_adaptor<GeomTraits>::FT;
using Approx_traits = Arr_approximation_geometry_traits<GeomTraits>;
using Approx_point = typename Approx_traits::Approx_point;
using Is_vertical_2 = typename Traits_adaptor<GeomTraits>::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<Approx_point> 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<Point_2, Multiplicity>;
using Intersect_curve = X_monotone_curve_2;
using Intersect_type = std::variant<Intersect_point, Intersect_curve>;
auto vertical_line = m_cst_vertical_segment(x, m_ymin, m_ymax);
std::optional<Approx_point> pt;
auto func_out_iter = boost::make_function_output_iterator([&pt, this](const Intersect_type& res) {
CGAL_assertion_msg(std::holds_alternative<Intersect_point>(res),
"Unexpected intersection type, expected Intersect_point");
pt = this->m_approx_pt(std::get<Intersect_point>(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<GeomTraits> m_approx_pt;
const Arr_construct_vertical_segment<GeomTraits> 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<double>::lowest();
// constexpr static double m_ymax = std::numeric_limits<double>::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 <typename Kernel>
class Arr_approximate_point_2_at_x<Arr_rational_function_traits_2<Kernel>>
{
using Geom_traits = CGAL::Arr_rational_function_traits_2<Kernel>;
using Point_2 = typename Traits_adaptor<Geom_traits>::Point_2;
using X_monotone_curve_2 = typename Traits_adaptor<Geom_traits>::X_monotone_curve_2;
using FT = typename Traits_adaptor<Geom_traits>::FT;
using Approx_point = typename Arr_approximation_geometry_traits<Geom_traits>::Approx_point;
using Construct_curve_end = Arr_construct_curve_end<Geom_traits>;
public:
Arr_approximate_point_2_at_x(const Geom_traits& traits)
: m_cst_curve_end(traits) {}
std::optional<Approx_point> operator()(const X_monotone_curve_2& curve, FT x) const {
std::optional<Point_2> min_end = m_cst_curve_end(curve, ARR_MIN_END);
if(min_end.has_value() && x < min_end->x()) {
return std::nullopt;
}
std::optional<Point_2> 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

View File

@ -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 <cstddef>
#include <boost/range/iterator_range.hpp>
#include "CGAL/Arr_enums.h"
#include "CGAL/unordered_flat_map.h"
#include "CGAL/Draw_aos/type_utils.h"
namespace CGAL {
namespace draw_aos {
template <typename Arrangement>
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<Geom_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<Vertex_const_handle, Vertex_cache_obj>;
using Halfedge_cache = unordered_flat_map<Halfedge_const_handle, Halfedge_cache_obj>;
using Face_cache = unordered_flat_map<Face_const_handle, Face_cache_obj>;
@ -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<Vertex_cache_obj&, bool> 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

View File

@ -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<double>;
using Approx_point = Approximation_kernel::Point_2;
using FT = double;
using Point_geom = Approx_point;
using Apporx_point_vec = std::vector<Point_geom>;
using Polyline_geom = Apporx_point_vec;
using Triangle = std::array<std::size_t, 3>;
using Triangle_vec = std::vector<Triangle>;
struct Triangulated_face
{
Apporx_point_vec points;
Triangle_vec triangles;
};
};
} // namespace CGAL
#endif // CGAL_DRAW_AOS_ARR_APPROXIMATION_GEOMETRY_TRAITS_H

View File

@ -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 <algorithm>
#include <cstddef>
#include <functional>
#include <iterator>
#include <optional>
#include <vector>
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 <typename Arrangement, bool Has_approximate_2_on_curve>
class Arr_bounded_approximate_curve_2_impl;
template <typename Arrangement>
class Arr_bounded_approximate_curve_2_impl<Arrangement, false>
{
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<Geom_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<Geom_traits>;
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<Geom_traits>;
using Bounded_render_context = Arr_bounded_render_context<Arrangement>;
using Intersections_vector = std::vector<Point_2>;
struct Execution_context : public Arr_context_delegator<Arr_bounded_render_context>
struct Execution_context : public Arr_context_delegator<Bounded_render_context>
{
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<Bounded_render_context>(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<Geom_traits>(ctx.traits)(curve, ARR_MIN_END))
, max_end(Arr_construct_curve_end<Geom_traits>(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<Geom_traits>(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<Geom_traits>(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_point> 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<Point_2> min_end, max_end;
const FT tight_xmin, tight_xmax, tight_ymin, tight_ymax;
std::optional<Approx_point> min_end, max_end;
double txmin, txmax, tymin, tymax;
std::back_insert_iterator<Polyline_geom> out_it;
const Construct_coordinate<Geom_traits> 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<Geom_traits>& cst_curve_end) {
using Intersect_point = std::pair<Geom_traits::Point_2, Geom_traits::Multiplicity>;
using Intersect_curve = Geom_traits::X_monotone_curve_2;
using Intersect_point = std::pair<Point_2, typename Geom_traits::Multiplicity>;
using Intersect_curve = X_monotone_curve_2;
using Intersect_type = std::variant<Intersect_point, Intersect_curve>;
std::vector<Point_2> intersections;
@ -106,23 +120,24 @@ private:
return intersections;
}
static std::optional<Point_2> first_intersection(Execution_context& ctx) {
static std::optional<Approx_point> 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<Point_2> first_inter = first_intersection(ctx);
double last_x;
std::optional<Approx_point> 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<Geom_traits> 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 <typename Arrangement>
class Arr_bounded_approximate_curve_2_impl<Arrangement, true>
{
using Geom_traits = typename Arrangement::Geometry_traits_2;
using Halfedge_const_handle = typename Arrangement::Halfedge_const_iterator;
using Approx_traits = Arr_approximation_geometry_traits<Geom_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<Geom_traits>;
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<Geom_traits>;
using Bounded_render_context = Arr_bounded_render_context<Arrangement>;
private:
struct Execution_context : public Arr_context_delegator<Bounded_render_context>
{
Execution_context(const Bounded_render_context& ctx,
const X_monotone_curve_2& curve,
const Approximate_2& approx_2,
Polyline_geom& polyline)
: Arr_context_delegator<Bounded_render_context>(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<Polyline_geom> 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<std::function<void(Approx_point)>> 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<std::variant<Approx_point, Approx_line_2>> res =
CGAL::intersection(Approx_line_2(last_pt, pt), boundary_line);
Approx_point inter = ctx->make_on_boundary(std::get<Approx_point>(*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<std::size_t>(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<Approx_point> 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 <typename Arrangement>
using Arr_bounded_approximate_curve_2 = Arr_bounded_approximate_curve_2_impl<
Arrangement,
has_approximate_2_object_v<typename Arrangement::Geometry_traits_2> &&
has_operator_xcv_v<typename Arrangement::Geometry_traits_2,
typename Arrangement::Geometry_traits_2::Approximate_2>>;
} // namespace draw_aos
} // namespace CGAL
#endif // CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_CURVE_2_H

View File

@ -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 <cstddef>
#include <functional>
#include <optional>
#include <type_traits>
#include <variant>
#include <algorithm>
#include <boost/iterator/function_output_iterator.hpp>
#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 <CGAL/Draw_aos/Arr_approximation_geometry_traits.h>
#include <CGAL/Draw_aos/helpers.h>
#include <algorithm>
#include <boost/iterator/function_output_iterator.hpp>
#include <cstddef>
#include <functional>
#include <iostream>
#include <iterator>
#include <optional>
#include <type_traits>
#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 <typename GeomTraits>
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<GeomTraits>::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<Side_of_boundary>((static_cast<int>(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 <typename OutputIterator>
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 <typename OutputIterator>
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 <typename OutputIterator>
class Geom_simplifier
template <typename GeomTraits, typename OutputIterator>
class Colinear_simplifier
{
using Approx_point = Arr_approximation_geometry_traits::Approx_point;
using Geom_traits = GeomTraits;
using Approx_point = typename Arr_approximation_geometry_traits<Geom_traits>::Approx_point;
public:
using Insert_iterator = boost::function_output_iterator<std::function<void(Approx_point)>>;
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<Approx_point> 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 <typename Arrangement>
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<Geom_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<Arrangement>::Feature_portals_map;
using Portal_vector = typename Arr_portals<Arrangement>::Portal_vector;
using Portal = typename Arr_portals<Arrangement>::Portal;
using Point_or_portal = std::variant<Approx_point, Portal>;
using FT = typename Traits_adaptor<Geom_traits>::FT;
template <typename OutputIterator>
using Geom_simplifier = internal::Geom_simplifier<OutputIterator>;
using Bounded_approximate_point_2 = Arr_bounded_approximate_point_2<Arrangement>;
using Bounded_approximate_curve_2 = Arr_bounded_approximate_curve_2<Arrangement>;
using Bounded_render_context = Arr_bounded_render_context<Arrangement>;
using Triangulator = Arr_bounded_face_triangulator<Arrangement>;
using Patch_boundary = Patch_boundary<Geom_traits>;
using Simplifier = Colinear_simplifier<Geom_traits, typename Triangulator::Insert_iterator>;
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<Arr_bounded_render_context>
class Execution_context : public Arr_context_delegator<Bounded_render_context>
{
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<Geom_traits, typename Triangulator::Insert_iterator>::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<std::function<void(Approx_point pt)>>;
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<Bounded_render_context>(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<Approx_point> 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 <typename OutputIterator>
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 <typename DirectionTag>
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<DirectionTag, Left_to_right_tag>;
using Approx_point_it = std::conditional_t<Is_left_to_right, typename Polyline_geom::const_iterator,
typename Polyline_geom::const_reverse_iterator>;
using Portals_it = std::conditional_t<Is_left_to_right, typename Portal_vector::const_iterator,
typename Portal_vector::const_reverse_iterator>;
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<Portal>(&point_or_portal)) {
traverse_portal(ctx, *portal);
return;
}
*ctx.out_it++ = std::get<Approx_point>(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<Inner_ccb_tag>(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 <typename CcbTag, bool Bounded = true>
template <typename CcbTag, bool Unbounded = false>
static void approximate_ccb(Execution_context& ctx, Ccb_halfedge_const_circulator start_circ) {
constexpr bool Is_outer_ccb = std::is_same_v<CcbTag, Outer_ccb_tag>;
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<CcbTag>();
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<Approx_point> last_pt;
// These vars are used only in unbounded ccb.
std::optional<Approx_point> 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<Outer_ccb_tag, false>(ctx, fh->outer_ccb());
} else {
approximate_ccb<Outer_ccb_tag, true>(ctx, fh->outer_ccb());
} else {
approximate_ccb<Outer_ccb_tag, false>(ctx, fh->outer_ccb());
}
for(auto inner_ccb = fh->inner_ccbs_begin(); inner_ccb != fh->inner_ccbs_end(); ++inner_ccb) {
approximate_ccb<Inner_ccb_tag>(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

View File

@ -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 <CGAL/Draw_aos/helpers.h>
#include <CGAL/Draw_aos/Arr_approximate_point_2.h>
#include <CGAL/Draw_aos/Arr_approximation_geometry_traits.h>
#include <utility>
#include <CGAL/Draw_aos/type_utils.h>
#include <CGAL/Draw_aos/Arr_render_context.h>
#include <CGAL/Draw_aos/Arr_approximate_point_2.h>
namespace CGAL {
namespace draw_aos {
template <typename Arrangement>
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<Geom_traits>::Point_2;
using Vertex_const_handle = typename Arrangement::Vertex_const_handle;
using Point_geom = typename Arr_approximation_geometry_traits<Geom_traits>::Point_geom;
using Bounded_render_context = Arr_bounded_render_context<Arrangement>;
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

View File

@ -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 <CGAL/Draw_aos/helpers.h>
#include <CGAL/Draw_aos/Arr_construct_segments.h>
#include <CGAL/Draw_aos/Arr_construct_curve_end.h>
#include <CGAL/Draw_aos/Arr_compute_y_at_x.h>
#include <boost/iterator/function_output_iterator.hpp>
#include <optional>
namespace CGAL {} // namespace CGAL
#endif // CGAL_DRAW_AOS_ARR_BOUNDED_COMPUTE_Y_AT_X_H

View File

@ -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 <algorithm>
#include <cstddef>
#include <CGAL/Draw_aos/helpers.h>
#include <boost/iterator/function_output_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <functional>
#include <utility>
#include <vector>
#include <boost/iterator/function_output_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
#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/unordered_flat_map.h>
#include <CGAL/Constrained_triangulation_2.h>
#include <CGAL/Constrained_triangulation_face_base_2.h>
#include <CGAL/Draw_aos/Arr_render_context.h>
#if defined(CGAL_DRAW_AOS_DEBUG) && defined(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR)
#include <fstream>
#include <filesystem>
template <typename Arrangement>
class Arr_bounded_face_triangulator;
template <typename Arrangement>
void debug_print(const Arr_bounded_face_triangulator<Arrangement>& 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 <typename Arrangement>
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<Geom_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 <typename T>
friend void debug_print(const Arr_bounded_face_triangulator<T>& 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<Point_index, Epick>;
using Fb = CGAL::Constrained_triangulation_face_base_2<Epick>;
using Tds = CGAL::Triangulation_data_structure_2<Vb, Fb>;
using Epick = Exact_predicates_inexact_constructions_kernel;
using Vb = Triangulation_vertex_base_with_info_2<Point_index, Epick>;
using Fb = Constrained_triangulation_face_base_2<Epick>;
using Tds = Triangulation_data_structure_2<Vb, Fb>;
using Ct = Constrained_triangulation_2<Epick, Tds, Exact_predicates_tag>;
using KPoint = Epick::Point_2;
using KPoint_with_info = std::pair<KPoint, Point_index>;
/**
* @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 <typename Ccb_tag>
class Ccb_constraint
{
constexpr static bool Is_outer_ccb = std::is_same_v<Ccb_tag, Outer_ccb_tag>;
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<KPoint_with_info>& points() { return m_triangulator->m_points; }
const std::vector<KPoint_with_info>& 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<std::size_t>(m_ccb_start);
auto indexes_end = boost::make_counting_iterator<std::size_t>(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<KPoint_with_info>(transformed_begin, transformed_end);
} else {
ct.insert_with_info<KPoint_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<std::size_t> m_helper_indices; // The offseted point indices when inserting outer ccb constraint
};
using Bounded_render_context = Arr_bounded_render_context<Arrangement>;
public:
Arr_bounded_face_triangulator(const Arr_bounded_render_context& ctx)
using Insert_iterator = boost::function_output_iterator<std::function<void(Approx_point)>>;
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<std::size_t>(0);
auto indexes_end = boost::make_counting_iterator<std::size_t>(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<KPoint_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<Ct::Face_handle, bool> in_domain_map;
unordered_flat_map<typename Ct::Face_handle, bool> in_domain_map;
boost::associative_property_map<decltype(in_domain_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 <typename Ccb_tag>
Ccb_constraint<Ccb_tag> make_ccb_constraint() {
if constexpr(std::is_same_v<Ccb_tag, Outer_ccb_tag>) {
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<Ccb_tag>(*this);
}
private:
const Arr_bounded_render_context& m_ctx;
const Bounded_render_context& m_ctx;
Ct m_ct;
std::vector<KPoint_with_info> m_points;
std::vector<std::size_t> m_ccb_start_indices;
bool m_has_active_constraint = false;
bool m_outer_ccb_processed = false;
std::vector<Approx_point> m_points;
double m_offset = 0.5; // Doesn't matter how much we offset.
std::vector<std::size_t> 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 <typename Arrangement>
void debug_print(const Arr_bounded_face_triangulator<Arrangement>& 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<int&>(*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

View File

@ -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 <CGAL/Draw_aos/helpers.h>
#include <CGAL/Draw_aos/Arr_portals.h>
#include <CGAL/IO/Color.h>
#include <vector>
#include <CGAL/Arr_trapezoid_ric_point_location.h>
#include <CGAL/Bbox_2.h>
#include <CGAL/IO/Color.h>
#include <CGAL/Draw_aos/Arr_approximation_cache.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 <CGAL/Draw_aos/type_utils.h>
#include <CGAL/Draw_aos/Arr_portals.h>
namespace CGAL {
namespace draw_aos {
/**
* @brief Render arrangement on surface within a bounding box.
*
* @note The class is not thread-safe.
*/
template <typename Arrangement>
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<Geom_traits>::FT;
using Point_2 = typename Traits_adaptor<Geom_traits>::Point_2;
using X_monotone_curve_2 = typename Traits_adaptor<Geom_traits>::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<Arrangement>;
using Feature_const = std::variant<Vertex_const_handle, Halfedge_const_handle, Face_const_handle>;
using Feature_const_vector = std::vector<Feature_const>;
using Feature_const_vector_inserter = std::back_insert_iterator<Feature_const_vector>;
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<Geom_traits>;
using Point_geom = typename Approx_traits::Point_geom;
using Polyline_geom = typename Approx_traits::Polyline_geom;
using Feature_portal_map = typename Arr_portals<Arrangement>::Feature_portals_map;
using Bounded_render_context = Arr_bounded_render_context<Arrangement>;
using Render_context = Arr_render_context<Arrangement>;
using Bounded_approx_point_2 = Arr_bounded_approximate_point_2<Arrangement>;
using Bounded_approx_curve_2 = Arr_bounded_approximate_curve_2<Arrangement>;
using Bounded_approx_face_2 = Arr_bounded_approximate_face_2<Arrangement>;
using Approx_cache = Arr_approximation_cache<Arrangement>;
// QFlags implement this pattern better, but we try not to reply on Qt classes.
template <typename E>
class Arr_flags
@ -65,46 +77,62 @@ class Arr_bounded_renderer
Face = 1 << 2,
};
struct Execution_context : Arr_context_delegator<Arr_bounded_render_context>
struct Execution_context : Arr_context_delegator<Bounded_render_context>
{
Execution_context(const Arr_bounded_render_context& ctx)
: Arr_context_delegator(ctx)
Execution_context(const Bounded_render_context& ctx)
: Arr_context_delegator<Bounded_render_context>(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 <typename OutputIterator>
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<Feature_type> feats) {
CGAL_assertion(side != Side_of_boundary::None);
using Feature = std::variant<Vertex_handle, Halfedge_handle, Face_handle>;
using Feature_vector = std::vector<Feature>;
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<Vertex_handle>(&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<Halfedge_handle>(&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<Face_handle>(&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<Vertex_const_handle>(&feature)) {
ctx.bounded_approx_pt(*vh);
} else if(auto* he = std::get_if<Halfedge_const_handle>(&feature)) {
ctx.bounded_approx_curve(*he);
} else if(auto* fh = std::get_if<Face_const_handle>(&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<Geom_traits> to_ft;
const Bbox_2 m_bbox;
};
} // namespace draw_aos
} // namespace CGAL
#endif // CGAL_DRAW_AOS_ARR_BOUNDED_RENDERER_H

View File

@ -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 <boost/iterator/function_output_iterator.hpp>
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<FT> 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<Point_2, Multiplicity>;
using Intersect_curve = X_monotone_curve_2;
using Intersect_type = std::variant<Intersect_point, Intersect_curve>;
auto vertical_line = m_ctx.cst_vertical_segment(x, m_ymin, m_ymax);
std::optional<FT> y;
auto func_out_iter = boost::make_function_output_iterator(
[&y, this](const Intersect_type& res) { y = std::get<Intersect_point>(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<double>::lowest();
constexpr static double m_ymax = std::numeric_limits<double>::max();
};
} // namespace CGAL
#endif // CGAL_DRAW_AOS_ARR_COMPUTE_Y_AT_X_H

View File

@ -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 <optional>
namespace CGAL {
#include <CGAL/Arr_enums.h>
#include <CGAL/Arr_has.h>
#include <CGAL/Draw_aos/type_utils.h>
namespace CGAL {
namespace draw_aos {
namespace internal {
template <typename Geom_traits>
template <typename GeomTraits>
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 <typename Geom_traits, bool Has_parameter_space_in_x>
template <typename GeomTraits, bool Has_parameter_space_in_x>
class Arr_construct_curve_end_impl;
template <typename Geom_traits>
class Arr_construct_curve_end_impl<Geom_traits, true> : public Arr_construct_curve_end_base<Geom_traits>
template <typename GeomTraits>
class Arr_construct_curve_end_impl<GeomTraits, true> : public Arr_construct_curve_end_base<GeomTraits>
{
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<GeomTraits>;
using Point_2 = typename Traits_adaptor<GeomTraits>::Point_2;
using X_monotone_curve = typename Traits_adaptor<GeomTraits>::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<Geom_traits>(traits)
Arr_construct_curve_end_impl(const GeomTraits& traits)
: Arr_construct_curve_end_base<GeomTraits>(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 <typename Geom_traits>
class Arr_construct_curve_end_impl<Geom_traits, false> : public Arr_construct_curve_end_base<Geom_traits>
template <typename GeomTraits>
class Arr_construct_curve_end_impl<GeomTraits, false> : public Arr_construct_curve_end_base<GeomTraits>
{
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<GeomTraits>;
using Point_2 = typename Traits_adaptor<GeomTraits>::Point_2;
using X_monotone_curve = typename Traits_adaptor<GeomTraits>::X_monotone_curve_2;
public:
Arr_construct_curve_end_impl(const Geom_traits& traits)
: Arr_construct_curve_end_base<Geom_traits>(traits) {}
Arr_construct_curve_end_impl(const GeomTraits& traits)
: Arr_construct_curve_end_base<GeomTraits>(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 <typename Geom_traits>
template <typename GeomTraits>
using Arr_construct_curve_end =
internal::Arr_construct_curve_end_impl<Geom_traits, has_parameter_space_in_x_2<Geom_traits>::value>;
internal::Arr_construct_curve_end_impl<GeomTraits,
Traits_adaptor<GeomTraits>::Has_unbounded_curves &&
has_parameter_space_in_x_2<GeomTraits>::value>;
} // namespace draw_aos
} // namespace CGAL
#endif // CGAL_ARR_CONSTRUCT_CURVE_END_H

View File

@ -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 <CGAL/Arr_circle_segment_traits_2.h>
#include <CGAL/number_utils.h>
#include <CGAL/Polynomial_traits_d.h>
#include <CGAL/Draw_aos/type_utils.h>
namespace CGAL {
namespace draw_aos {
template <typename GeomTraits, bool HasConstructXMonotoneCurve2>
class Arr_construct_segment_impl;
// Default implementation for traits that models Construct_x_monotone_curve_2
template <typename GeomTraits>
class Arr_construct_segment_impl<GeomTraits, true>
{
using Point_2 = typename Traits_adaptor<GeomTraits>::Point_2;
using X_monotone_curve_2 = typename Traits_adaptor<GeomTraits>::X_monotone_curve_2;
using Construct_x_monotone_curve_2 = typename GeomTraits::Construct_x_monotone_curve_2;
using FT = typename Traits_adaptor<GeomTraits>::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 <typename Kernel>
class Arr_construct_segment_impl<Arr_circle_segment_traits_2<Kernel>, false>
{
using Geom_traits = Arr_circle_segment_traits_2<Kernel>;
using Point_2 = typename Traits_adaptor<Geom_traits>::Point_2;
using X_monotone_curve_2 = typename Traits_adaptor<Geom_traits>::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<Geom_traits>::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 <typename GeomTraits>
class Arr_construct_segment_impl<GeomTraits, false>
{
static_assert(false, "Not implemented yet!");
};
template <typename GeomTraits>
using Arr_construct_segment =
Arr_construct_segment_impl<GeomTraits, has_construct_x_monotone_curve_2<GeomTraits>::value>;
template <typename GeomTraits>
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<GeomTraits>::Point_2;
using X_monotone_curve_2 = typename Traits_adaptor<GeomTraits>::X_monotone_curve_2;
using FT = typename Traits_adaptor<GeomTraits>::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<GeomTraits> m_cst_seg;
};
template <typename GeomTraits>
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<GeomTraits>::Point_2;
using X_monotone_curve_2 = typename Traits_adaptor<GeomTraits>::X_monotone_curve_2;
using FT = typename Traits_adaptor<GeomTraits>::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<GeomTraits> m_cst_seg;
};
// Arr_construct_vertical_segment Specialization for Arr_rational_function_traits_2
template <typename Kernel>
class Arr_construct_vertical_segment<Arr_rational_function_traits_2<Kernel>>
{
using Geom_traits = Arr_rational_function_traits_2<Kernel>;
using Point_2 = typename Traits_adaptor<Geom_traits>::Point_2;
using X_monotone_curve_2 = typename Traits_adaptor<Geom_traits>::X_monotone_curve_2;
using Construct_x_monotone_curve_2 = typename Geom_traits::Construct_x_monotone_curve_2;
using FT = typename Traits_adaptor<Geom_traits>::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 <typename Kernel>
class Arr_construct_horizontal_segment<Arr_rational_function_traits_2<Kernel>>
{
using Geom_traits = Arr_rational_function_traits_2<Kernel>;
using Point_2 = typename Traits_adaptor<Geom_traits>::Point_2;
using X_monotone_curve_2 = typename Traits_adaptor<Geom_traits>::X_monotone_curve_2;
using FT = typename Traits_adaptor<Geom_traits>::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

View File

@ -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 <boost/range/iterator_range.hpp>
#include <CGAL/Arr_enums.h>
#include <CGAL/Union_find.h>
#include <CGAL/unordered_flat_map.h>
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()) {

View File

@ -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 <boost/iterator/function_output_iterator.hpp>
#include <CGAL/Draw_aos/helpers.h>
#include <CGAL/Draw_aos/Arr_approximation_geometry_traits.h>
#include <limits>
#include <utility>
#include <boost/iterator/function_output_iterator.hpp>
#include <CGAL/Arr_vertical_decomposition_2.h>
#include <CGAL/Object.h>
#include <CGAL/unordered_flat_map.h>
#include <CGAL/Draw_aos/Arr_approximate_point_2_at_x.h>
#include <CGAL/Draw_aos/Arr_approximate_point_2.h>
#include <CGAL/Draw_aos/Arr_construct_segments.h>
#include <CGAL/Draw_aos/Arr_graph_conn.h>
#include <CGAL/Draw_aos/type_utils.h>
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 <typename Arrangement>
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<Geom_traits>::Point_2;
using Approx_point = typename Arr_approximation_geometry_traits<Geom_traits>::Approx_point;
using X_monotone_curve_2 = typename Traits_adaptor<Geom_traits>::X_monotone_curve_2;
using Feature_const = std::variant<Vertex_const_handle, Halfedge_const_handle, Face_const_handle>;
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<Feature_const, Portal_vector>;
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<double>::max());
bool found_intersection = false;
using Multiplicity = Geom_traits::Multiplicity;
using Intersect_point = std::pair<Point_2, Multiplicity>;
using Intersect_curve = X_monotone_curve_2;
using Intersect_type = std::variant<Intersect_point, Intersect_curve>;
intersect(curve, vertical_line, boost::make_function_output_iterator([&](const Intersect_type& res) {
found_intersection = true;
if(std::holds_alternative<Intersect_point>(res)) {
intersection_point = std::get<Intersect_point>(res).first;
return;
}
CGAL_assertion(false && "Unexpected intersection type");
}));
return found_intersection ? intersection_point : Point_2(pt.x(), std::numeric_limits<double>::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<Vertex_const_handle>();
Feature_portals_map feature_portals;
auto intersect = arr.traits()->intersect_2_object();
auto approx_pt = Arr_approximate_point_2<Geom_traits>(*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<Portal>{});
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<Portal>{});
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<Geom_traits> m_approx_pt_at_x;
const Arr_approximate_point_2<Geom_traits> m_approx_pt;
};
} // namespace draw_aos
} // namespace CGAL
#endif // CGAL_DRAW_AOS_ARR_CREATE_PORTALS_H

View File

@ -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 <cstdlib>
#include <limits>
#include <memory>
#include <algorithm>
#include <atomic>
#include <chrono>
#include <CGAL/Bbox_2.h>
#include <CGAL/Arr_point_location_result.h>
#include <CGAL/Arr_trapezoid_ric_point_location.h>
#include <CGAL/Arrangement_2.h>
#include <CGAL/Draw_aos/helpers.h>
#include <cstdlib>
#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 <CGAL/Draw_aos/Arr_portals.h>
#include <CGAL/Draw_aos/type_utils.h>
#if defined(CGAL_DRAW_AOS_DEBUG)
#include <fstream>
#include <iterator>
#include <limits>
#include <memory>
#endif
namespace CGAL {
namespace draw_aos {
class Arr_cancellable_context_mixin
{
@ -50,23 +55,18 @@ private:
std::shared_ptr<std::atomic<bool>> m_done;
};
template <typename GeomTraits>
class Arr_bounds_context_mixin
{
using Approx_point = Arr_approximation_geometry_traits::Approx_point;
using Approx_point = typename Arr_approximation_geometry_traits<GeomTraits>::Approx_point;
using Point_2 = typename Traits_adaptor<GeomTraits>::Point_2;
using FT = typename Traits_adaptor<GeomTraits>::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 <typename FT>
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 <typename FT>
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 <typename Point>
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 <typename FT>
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 <typename FT>
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 <typename Point>
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 <typename Point>
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 <typename Point>
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<GeomTraits> to_ft;
};
template <typename GeomTraits>
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<Geom_traits> 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<Geom_traits> approx_pt;
const GeomTraits& traits;
const Arr_construct_curve_end<GeomTraits> cst_curve_end;
const Arr_construct_vertical_segment<GeomTraits> cst_vertical_segment;
const Arr_construct_horizontal_segment<GeomTraits> cst_horizontal_segment;
const typename Traits_adaptor<GeomTraits>::Intersect_2 intersect_2;
const typename Traits_adaptor<GeomTraits>::Compare_xy_2 compare_xy_2;
const typename Traits_adaptor<GeomTraits>::Is_vertical_2 is_vertical_2;
const Arr_approximate_point_2<GeomTraits> approx_pt;
};
class Arr_render_context : public Arr_cancellable_context_mixin, public Arr_geom_traits_context_mixin
template <typename Arrangement>
class Arr_render_context : public Arr_cancellable_context_mixin,
public Arr_geom_traits_context_mixin<typename Arrangement::Geometry_traits_2>
{
using Point_location = Arr_trapezoid_ric_point_location<Arrangement>;
using Feature_portals_map = typename Arr_portals<Arrangement>::Feature_portals_map;
using Cancellable_context_mixin = Arr_cancellable_context_mixin;
using Geom_traits_context_mixin = Arr_geom_traits_context_mixin<typename Arrangement::Geometry_traits_2>;
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<std::size_t>(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<std::size_t> 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<int> debug_counter = std::make_shared<int>(0);
#endif
};
class Arr_bounded_render_context : public Arr_render_context, public Arr_bounds_context_mixin
template <typename Arrangement>
class Arr_bounded_render_context : public Arr_render_context<Arrangement>,
public Arr_bounds_context_mixin<typename Arrangement::Geometry_traits_2>
{
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<Geom_traits>::Approx_point;
using Point_2 = typename Traits_adaptor<Geom_traits>::Point_2;
using Render_context = Arr_render_context<Arrangement>;
using Bounds_context_mixin = Arr_bounds_context_mixin<Geom_traits>;
using Approx_cache = Arr_approximation_cache<Arrangement>;
constexpr static double ep_base = std::numeric_limits<double>::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

View File

@ -16,12 +16,10 @@
#ifndef ARR_VIEWER_H
#define ARR_VIEWER_H
#include "CGAL/Draw_aos/type_utils.h"
#include <array>
#include <cstddef>
#include <iterator>
#include <memory>
#include <utility>
#include <vector>
#include <limits>
#include <boost/iterator/function_output_iterator.hpp>
#include <boost/range/iterator_range.hpp>
@ -33,28 +31,30 @@
#include <QtGui/QMouseEvent>
#include <QtGui/QKeyEvent>
#include "CGAL/Arr_trapezoid_ric_point_location.h"
#include "CGAL/Arrangement_on_surface_2.h"
#include <CGAL/Qt/camera.h>
#include <CGAL/Arr_linear_traits_2.h>
#include <CGAL/Arr_segment_traits_2.h>
#include <CGAL/Basic_viewer.h>
#include "CGAL/Bbox_2.h"
#include <CGAL/Draw_aos/helpers.h>
#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 <CGAL/Bbox_2.h>
#include <CGAL/Graphics_scene.h>
#include <CGAL/Graphics_scene_options.h>
#include <CGAL/Draw_aos/Arr_bounded_renderer.h>
#include <CGAL/Draw_aos/Arr_render_context.h>
namespace CGAL {
namespace draw_aos {
class Arr_viewer : public Qt::Basic_viewer {
template <typename Arrangement, typename GSOptions>
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<Arrangement, Vertex_const_handle, Halfedge_const_handle, Face_const_handle>;
using Point_location = CGAL::Arr_trapezoid_ric_point_location<Arrangement>;
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<Arrangement>::Feature_portals_map;
using Graphics_scene_options = GSOptions;
using Point_location = Arr_trapezoid_ric_point_location<Arrangement>;
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<double>::max();
double ymax = std::numeric_limits<double>::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<Geom_traits>::Approximation_sizing_factor == 0.0) {
return std::numeric_limits<double>::max();
}
std::array<GLint, 4> viewport;
camera_->getViewport(viewport.data());
double width = static_cast<double>(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<double>(viewport[2]);
double bbox_xspan = bbox.x_span();
return bbox_xspan / viewport_width * Traits_adaptor<Geom_traits>::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<Arrangement>(*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<Arrangement> ctx(m_arr, m_pl, m_feature_portals, get_approx_error(bbox));
Arr_bounded_renderer<Arrangement> 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<Geom_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<Arrangement, Arrangement::Vertex_const_handle, Arrangement::Halfedge_const_handle,
Arrangement::Face_const_handle>
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

View File

@ -1,20 +0,0 @@
#ifndef CGAL_DRAW_AOS_HELPERS_H
#define CGAL_DRAW_AOS_HELPERS_H
#include "CGAL/Arr_linear_traits_2.h"
#include <CGAL/Arr_segment_traits_2.h>
#include <CGAL/Arrangement_2.h>
namespace CGAL {
using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
// using Geom_traits = Arr_segment_traits_2<Exact_kernel>;
using Geom_traits = CGAL::Arr_linear_traits_2<Exact_kernel>;
using Arrangement = Arrangement_2<Geom_traits>;
struct Inner_ccb_tag
{};
struct Outer_ccb_tag
{};
} // namespace CGAL
#endif // CGAL_DRAW_AOS_HELPERS_H

View File

@ -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 <type_traits>
#include <CGAL/Arr_segment_traits_2.h>
#include <CGAL/Arr_linear_traits_2.h>
#include <CGAL/Arr_circle_segment_traits_2.h>
#include <CGAL/Arr_conic_traits_2.h>
#include <CGAL/Arr_circular_arc_traits_2.h>
#include <CGAL/Arr_Bezier_curve_traits_2.h>
#include <CGAL/Arr_geodesic_arc_on_sphere_traits_2.h>
#include <CGAL/Arr_rational_function_traits_2.h>
#include <CGAL/Arr_algebraic_segment_traits_2.h>
#include <CGAL/Arr_circular_line_arc_traits_2.h>
namespace CGAL {
namespace draw_aos {
enum class Side_of_boundary {
Top = 0,
Left = 1,
Bottom = 2,
Right = 3,
None = -1,
};
template <typename, typename = std::void_t<>>
struct has_construct_x_monotone_curve_2 : std::false_type
{};
template <typename T>
struct has_construct_x_monotone_curve_2<T, std::void_t<typename T::Construct_x_monotone_curve_2>> : std::true_type
{};
template <typename, typename = std::void_t<>>
struct has_approximate_2_object : std::false_type
{};
// Specialization: detection succeeds if decltype(T::approximate_2_object()) is valid
template <typename T>
struct has_approximate_2_object<T, std::void_t<decltype(std::declval<T>().approximate_2_object())>> : std::true_type
{};
// Convenience variable
template <typename T>
inline constexpr bool has_approximate_2_object_v = has_approximate_2_object<T>::value;
// Primary templates: detection fails by default
// Does a class have operator()(const Point&)?
template <typename, typename, typename = std::void_t<>>
struct has_operator_point : std::false_type
{};
// Specialization: detection succeeds if decltype works out
template <typename T, typename A>
struct has_operator_point<T, A, std::void_t<decltype(std::declval<A>()(std::declval<const typename T::Point_2&>()))>>
: std::true_type
{};
// Convenience variable
template <typename T, typename A>
inline constexpr bool has_operator_point_v = has_operator_point<T, A>::value;
// Primary templates: detection fails by default
// Does a class have operator()(const X_monotone_curve&)?
template <typename, typename, typename, typename = std::void_t<>>
struct has_operator_xcv : std::false_type
{};
template <typename T, typename A, typename O>
struct has_operator_xcv<T,
A,
O,
std::void_t<decltype(std::declval<A&>()(std::declval<const typename T::X_monotone_curve_2&>(),
std::declval<double>(),
std::declval<O>(),
std::declval<bool>()))>> : std::true_type
{};
// Convenience variable
template <typename T, typename A>
constexpr bool has_operator_xcv_v = has_operator_xcv<T, A, void*>::value;
template <typename GeomTraits>
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 <typename GeomTraits>
struct Traits_adaptor;
template <typename Kernel>
struct Traits_adaptor<Arr_segment_traits_2<Kernel>> : public Traits_adaptor_base<Arr_segment_traits_2<Kernel>>
{
private:
using Geom_traits = Arr_segment_traits_2<Kernel>;
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 <typename SegmentTraits>
struct Traits_adaptor<Arr_polyline_traits_2<SegmentTraits>>
: public Traits_adaptor_base<Arr_polyline_traits_2<SegmentTraits>>
{
private:
using Geom_traits = Arr_polyline_traits_2<SegmentTraits>;
using Sub_traits = SegmentTraits;
using Adapted_sub_traits = Traits_adaptor<Sub_traits>;
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 <typename SubcurveTraits>
struct Traits_adaptor<Arr_polycurve_traits_2<SubcurveTraits>>
: public Traits_adaptor_base<Arr_polycurve_traits_2<SubcurveTraits>>
{
private:
using Sub_traits = SubcurveTraits;
using Geom_traits = Arr_polycurve_traits_2<Sub_traits>;
using Adapted_sub_traits = Traits_adaptor<Sub_traits>;
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 <typename Kernel>
struct Traits_adaptor<Arr_linear_traits_2<Kernel>> : public Traits_adaptor_base<Arr_linear_traits_2<Kernel>>
{
private:
using Geom_traits = Arr_segment_traits_2<Kernel>;
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 <typename RatKernel, typename AlgKernel, typename NtTraits>
struct Traits_adaptor<Arr_conic_traits_2<RatKernel, AlgKernel, NtTraits>>
: public Traits_adaptor_base<Arr_conic_traits_2<RatKernel, AlgKernel, NtTraits>>
{
private:
using Geom_traits = Arr_conic_traits_2<RatKernel, AlgKernel, NtTraits>;
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 <typename Kernel>
struct Traits_adaptor<Arr_circle_segment_traits_2<Kernel>>
: public Traits_adaptor_base<Arr_circle_segment_traits_2<Kernel>>
{
private:
using Geom_traits = Arr_circle_segment_traits_2<Kernel>;
using Base = Traits_adaptor_base<Geom_traits>;
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 <typename RatKernel, typename AlgKernel, typename NtTraits>
struct Traits_adaptor<Arr_Bezier_curve_traits_2<RatKernel, AlgKernel, NtTraits>>
: public Traits_adaptor_base<Arr_Bezier_curve_traits_2<RatKernel, AlgKernel, NtTraits>>
{
static_assert(false, "Approximate_2 not yet modeled by this geometry traits class.");
};
template <typename Kernel>
struct Traits_adaptor<Arr_circular_line_arc_traits_2<Kernel>>
: public Traits_adaptor_base<Arr_circular_line_arc_traits_2<Kernel>>
{
static_assert(false, "Approximate_2 not yet modeled by this geometry traits class.");
};
template <typename Kernel>
struct Traits_adaptor<Arr_rational_function_traits_2<Kernel>>
: public Traits_adaptor_base<Arr_rational_function_traits_2<Kernel>>
{
private:
using Geom_traits = Arr_rational_function_traits_2<Kernel>;
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<double>;
using Approximate_point_2 = typename Approximate_kernel::Point_2;
};
template <typename GeomTraits>
class Construct_coordinate
{
using FT = typename Traits_adaptor<GeomTraits>::FT;
public:
FT operator()(double val) const { return FT(val); }
};
template <typename Kernel>
class Construct_coordinate<Arr_rational_function_traits_2<Kernel>>
{
using FT = typename Traits_adaptor<Arr_rational_function_traits_2<Kernel>>::FT;
using Bound = typename Kernel::Bound;
public:
FT operator()(double val) const { return FT(Bound(val)); }
};
template <typename GeomTraits>
class Arr_approximation_geometry_traits
{
using Adapted_traits = Traits_adaptor<GeomTraits>;
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<Point_geom>;
using Polyline_geom = Apporx_point_vec;
using Triangle = std::array<std::size_t, 3>;
using Triangle_vec = std::vector<Triangle>;
struct Triangulated_face
{
Apporx_point_vec points;
Triangle_vec triangles;
};
};
} // namespace draw_aos
} // namespace CGAL
#endif // CGAL_DRAW_AOS_TYPE_UTILS_H

View File

@ -16,22 +16,6 @@
#ifndef CGAL_DRAW_ARRANGEMENT_2_H
#define CGAL_DRAW_ARRANGEMENT_2_H
#include <CGAL/license/Arrangement_on_surface_2.h>
#include <CGAL/Draw_aos/helpers.h>
#include <CGAL/Draw_aos/Arr_viewer.h>
#include <CGAL/Draw_aos/Arr_bounded_renderer.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_bounded_approximate_point_2.h>
#include <CGAL/Draw_aos/Arr_approximation_cache.h>
#include <CGAL/Draw_aos/Arr_bounded_compute_y_at_x.h>
#include <CGAL/Draw_aos/Arr_render_context.h>
#include <CGAL/Draw_aos/Arr_bounded_face_triangulator.h>
#include <CGAL/Draw_aos/Arr_approximation_geometry_traits.h>
#include <CGAL/config.h>
#include <cstdlib>
#include <type_traits>
#include <unordered_map>
@ -43,6 +27,9 @@
#include <CGAL/Graphics_scene.h>
#include <CGAL/Graphics_scene_options.h>
#include <CGAL/Random.h>
#include <CGAL/license/Arrangement_on_surface_2.h>
#include <CGAL/config.h>
#include <CGAL/Draw_aos/Arr_viewer.h>
namespace CGAL {
@ -606,47 +593,46 @@ protected:
#define CGAL_ARR_TYPE CGAL::Arrangement_on_surface_2<GeometryTraits_2, TopologyTraits>
///
template <typename GeometryTraits_2, typename TopologyTraits, class GSOptions>
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 <typename GeometryTraits_2, typename TopologyTraits>
void add_to_graphics_scene(const CGAL_ARR_TYPE& aos, CGAL::Graphics_scene& graphics_scene) {
CGAL::Graphics_scene_options<CGAL_ARR_TYPE, typename CGAL_ARR_TYPE::Vertex_const_handle,
typename CGAL_ARR_TYPE::Halfedge_const_handle, typename CGAL_ARR_TYPE::Face_const_handle>
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 <typename GeometryTraits_2, typename TopologyTraits, class GSOptions>
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 <typename GeometryTraits_2, typename TopologyTraits>
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<Arrangement, Vertex_const_handle, Halfedge_const_handle, Face_const_handle> 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

View File

@ -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})

View File

@ -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 <array>
#include <fstream>
#include <iostream>
#include "CGAL/Exact_predicates_exact_constructions_kernel.h"
#include "CGAL/Exact_predicates_inexact_constructions_kernel.h"
#include <CGAL/draw_arrangement_2.h>
#include <vector>
// void draw_segments_arr_1() {
// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
// using Segment_traits = CGAL::Arr_segment_traits_2<Exact_kernel>;
// using Point_2 = Segment_traits::Point_2;
// using Arrangement = CGAL::Arrangement_2<Segment_traits>;
// // 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<Exact_kernel>;
// using Point_2 = Segment_traits::Point_2;
// using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2;
// using Arrangement = CGAL::Arrangement_2<Segment_traits>;
// 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<Point_2, 6> 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<X_monotone_curve_2, 6> 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<Exact_kernel>;
// using Point_2 = Segment_traits::Point_2;
// using Arrangement = CGAL::Arrangement_2<Segment_traits>;
// 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<X_monotone_curve_2> 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<Exact_kernel>;
// using Point_2 = Segment_traits::Point_2;
// using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2;
// using Arrangement = CGAL::Arrangement_2<Segment_traits>;
// Arrangement arr;
// auto traits = arr.traits();
// auto cst_x_curve = traits->construct_x_monotone_curve_2_object();
// std::vector<X_monotone_curve_2> segments;
// std::vector<Point_2> 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<Point_2> 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<Exact_kernel>;
// using Point_2 = Segment_traits::Point_2;
// using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2;
// using Arrangement = CGAL::Arrangement_2<Segment_traits>;
// Arrangement arr;
// auto traits = arr.traits();
// auto cst_x_curve = traits->construct_x_monotone_curve_2_object();
// std::vector<X_monotone_curve_2> segments;
// std::vector<Point_2> 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<Exact_kernel>;
// using Point_2 = Segment_traits::Point_2;
// using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2;
// using Arrangement = CGAL::Arrangement_2<Segment_traits>;
// Arrangement arr;
// auto traits = arr.traits();
// auto cst_x_curve = traits->construct_x_monotone_curve_2_object();
// std::vector<X_monotone_curve_2> segments;
// std::vector<Point_2> 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<Exact_kernel>;
// 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<Traits>;
// 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<Exact_kernel>;
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<Traits>;
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<Exact_kernel>;
// 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<Traits>;
// 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<Point_2> 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<X_monotone_curve_2> 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<Exact_kernel>;
// using Point_2 = Traits::Point_2;
// using Curve_2 = Traits::Curve_2;
// using Arrangement = CGAL::Arrangement_2<Traits>;
// 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<Rational>;
// 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<Algebraic>;
// using Traits = CGAL::Arr_conic_traits_2<Rat_kernel, Alg_kernel, Nt_traits>;
// 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<Traits>;
// 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 <CGAL/Gmpz.h>
// using Integer = CGAL::Gmpz;
// #elif CGAL_USE_CORE
// #include <CGAL/CORE_BigInt.h>
// using Integer = CORE::BigInt;
// #else
// #include <CGAL/leda_integer.h>
// using Integer = LEDA::integer;
// #endif
// using Traits = CGAL::Arr_algebraic_segment_traits_2<Integer>;
// using Arrangement = CGAL::Arrangement_2<Traits>;
// 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<CORE::BigInt>;
// using Traits = CGAL::Arr_rational_function_traits_2<AK1>;
// using Arrangement = CGAL::Arrangement_2<Traits>;
// 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<Exact_kernel>;
// using Spherical_topo_traits = CGAL::Arr_spherical_topology_traits_2<Geodesic_traits>;
// using Arrangement = CGAL::Arrangement_on_surface_2<Geodesic_traits, Spherical_topo_traits>;
// 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<Point>& 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;
}

View File

@ -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 <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <algorithm>
#include <cstddef>
#include <utility>
#include <vector>
#include "CGAL/Random.h"
#include "CGAL/IO/Color.h"
#include "CGAL/draw_triangulation_2.h"
#include "CGAL/mark_domain_in_triangulation.h"
#include <CGAL/Graphics_scene_options.h>
template <class PT>
struct Polygon_triangulation_gs_options : public CGAL::Graphics_scene_options<typename PT::Triangulation,
typename PT::Vertex_handle,
typename PT::Finite_edges_iterator,
typename PT::Finite_faces_iterator>
{
using T2 = typename PT::Triangulation;
template <class IPM>
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<size_t, K>;
using Fb = CGAL::Constrained_triangulation_face_base_2<K>;
using Tds = CGAL::Triangulation_data_structure_2<Vb, Fb>;
using Cdt = CGAL::Constrained_triangulation_2<K, Tds, CGAL::Exact_predicates_tag>;
using Point = K::Point_2;
Cdt cdt;
std::vector<Point> 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<Point> 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<Point> 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<std::pair<Point, size_t>>(boost::make_transform_iterator(outer.begin(), add_info),
boost::make_transform_iterator(outer.end(), add_info));
// cdt.insert_with_info<std::pair<Point, size_t>>(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<typename Cdt::Face_handle, bool>;
In_domain_map in_domain_map;
boost::associative_property_map<In_domain_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<Cdt::Triangulation, Cdt::Vertex_handle, Cdt::Finite_edges_iterator,
Cdt::Finite_faces_iterator>
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<std::size_t, 3> 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");
}