Improved dispatching

This commit is contained in:
Efi Fogel 2025-05-28 16:15:58 +03:00
parent 2caff8f2d8
commit 35f66f80b6
1 changed files with 121 additions and 97 deletions

View File

@ -38,6 +38,25 @@ namespace CGAL {
namespace draw_function_for_arrangement_2 { namespace draw_function_for_arrangement_2 {
// ============================
// Detection idiom using void_t
// ============================
// Primary template: detection fails by default
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 (C++17)
template <typename T>
inline constexpr bool has_approximate_2_object_v = has_approximate_2_object<T>::value;
///
template<typename Arr, typename GSOptions> template<typename Arr, typename GSOptions>
class Draw_arr_tool { class Draw_arr_tool {
public: public:
@ -113,7 +132,7 @@ public:
do { do {
// Skip halfedges that are "antenas": // Skip halfedges that are "antenas":
while (curr->face() == curr->twin()->face()) curr = curr->twin()->next(); while (curr->face() == curr->twin()->face()) curr = curr->twin()->next();
draw_region_impl1(curr, *traits, 0); draw_region_impl1(*traits, curr);
curr = curr->next(); curr = curr->next();
} while (curr != ext); } while (curr != ext);
@ -131,32 +150,31 @@ public:
decltype(approx.template operator()<I>(X_monotone_curve{}, double{}, I{}, decltype(approx.template operator()<I>(X_monotone_curve{}, double{}, I{},
bool{}), void()) bool{}), void())
{ draw_approximate_region(curr, approx); } { draw_approximate_region(curr, approx); }
template <typename T>
void draw_region_impl1(Halfedge_const_handle curr, T const&, long)
{ draw_exact_region(curr); }
template <typename T>
auto draw_region_impl1(Halfedge_const_handle curr, T const& traits, int) ->
decltype(traits.approximate_2_object(), void()) {
using Approximate = typename Gt::Approximate_2;
draw_region_impl2<Approximate, int>(curr, traits.approximate_2_object(), 0);
}
#else
template <typename T>
void draw_region_impl1(Halfedge_const_handle curr, T const& traits, int)
{ draw_approximate_region(curr, traits.approximate_2_object()); }
#endif #endif
/*! Draw a region, where the traits does not has approximate_2_object.
*/
template <typename T, std::enable_if_t<! has_approximate_2_object_v<T>, int> = 0>
void draw_region_impl1(T const& /* traits */, Halfedge_const_handle curr)
{ draw_exact_region(curr); }
///
template <typename T, std::enable_if_t<has_approximate_2_object_v<T>, int> = 0>
auto draw_region_impl1(T const& traits, Halfedge_const_handle curr) {
using Approximate = typename Gt::Approximate_2;
// draw_region_impl2<Approximate, int>(xcv, traits.approximate_2_object(), 0);
draw_approximate_region(curr, traits.approximate_2_object());
}
/*! Draw a geodesic region
*/
template <typename Kernel_, int AtanX, int AtanY> template <typename Kernel_, int AtanX, int AtanY>
void draw_region_impl1 void draw_region_impl1
(Halfedge_const_handle curr, (Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits,
Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits, Halfedge_const_handle curr)
int)
{ {
if (! m_gso.draw_edge(m_aos, curr)) return; if (! m_gso.draw_edge(m_aos, curr)) return;
// std::cout << "draw_region_impl1()\n";
auto approx = traits.approximate_2_object(); auto approx = traits.approximate_2_object();
using Kernel = Kernel_; using Kernel = Kernel_;
using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>; using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>;
@ -207,14 +225,7 @@ public:
if (polyline.empty()) return; if (polyline.empty()) return;
auto it = polyline.begin(); auto it = polyline.begin();
auto prev = it++; auto prev = it++;
for (; it != polyline.end(); prev = it++) { for (; it != polyline.end(); prev = it++) m_gs.add_point_in_face(*prev);
if (m_gso.draw_edge(m_aos, curr)) {
if (m_gso.colored_edge(m_aos, curr))
m_gs.add_segment(*prev, *it, m_gso.edge_color(m_aos, curr));
else m_gs.add_segment(*prev, *it);
}
m_gs.add_point_in_face(*prev);
}
} }
/*! Draw an exact curve. /*! Draw an exact curve.
@ -230,7 +241,9 @@ public:
else m_gs.add_segment(ctr_min(curve), ctr_max(curve)); else m_gs.add_segment(ctr_min(curve), ctr_max(curve));
} }
/// Draw an exact region. /*! Draw a region in an exact manner.
* This fallback simply draws the curve in an exact manner (and even this is not guaranteed).
*/
void draw_exact_region(Halfedge_const_handle curr) void draw_exact_region(Halfedge_const_handle curr)
{ draw_exact_curve(curr->curve(), false, CGAL::IO::Color()); } { draw_exact_curve(curr->curve(), false, CGAL::IO::Color()); }
@ -257,28 +270,47 @@ public:
{ m_gs.add_point(approx(p)); } { m_gs.add_point(approx(p)); }
template <typename T> template <typename T>
void draw_point_impl1(const Point& p, T const&, long) { m_gs.add_point(p); } void draw_point_impl1(T const&, const Point& p, long) { m_gs.add_point(p); }
template <typename T>
auto draw_point_impl1(const Point& p, T const& traits, int) ->
decltype(traits.approximate_2_object(), void()) {
using Approximate = typename Gt::Approximate_2;
draw_point_impl2<Approximate>(p, traits.approximate_2_object(), true);
}
#else
template <typename T>
void draw_point_impl1(const Point& p, T const& traits, int,
bool colored, const CGAL::IO::Color& color) {
if (colored) m_gs.add_point(traits.approximate_2_object()(p), color);
else m_gs.add_point(traits.approximate_2_object()(p));
}
#endif #endif
/*! Draw a point using approximate coordinates.
*/
template <typename Approximate>
void draw_approximate_point(const Point& p, const Approximate& approx,
bool colored, const CGAL::IO::Color& color) {
if (colored) m_gs.add_point(approx(p), color);
else m_gs.add_point(approx(p));
}
///
void draw_exact_point(const Point& p, bool colored, const CGAL::IO::Color& color) {
if (colored) m_gs.add_point(p, color);
else m_gs.add_point(p);
}
/*! Draw a point, where the traits does not has approximate_2_object.
*/
template <typename T, std::enable_if_t<! has_approximate_2_object_v<T>, int> = 0>
void draw_point_impl1(T const& /* traits */, const Point& p,
bool colored, const CGAL::IO::Color& c)
{ draw_exact_point(p, colored, c); }
/*! Draw a point, where the traits does have approximate_2_object.
*/
template <typename T, std::enable_if_t<has_approximate_2_object_v<T>, int> = 0>
auto draw_point_impl1(T const& traits, const Point& p,
bool colored, const CGAL::IO::Color& c) {
using Approximate = typename Gt::Approximate_2;
// draw_curve_impl2<Approximate, int>(p, traits.approximate_2_object(), 0);
draw_approximate_point(p, traits.approximate_2_object(), colored, c);
}
/*! Draw a geodesic point.
*/
template <typename Kernel_, int AtanX, int AtanY> template <typename Kernel_, int AtanX, int AtanY>
void draw_point_impl1 void draw_point_impl1
(const Point& p, (Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits,
Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits, const Point& p,
int,
bool colored, bool colored,
const CGAL::IO::Color& color) const CGAL::IO::Color& color)
{ {
@ -297,16 +329,9 @@ public:
} }
/// Draw a point. /// Draw a point.
void draw_point(Vertex_const_handle vh) { void draw_point(const Point& p, bool colored, const CGAL::IO::Color& c) {
const auto* traits = m_aos.geometry_traits(); const auto* traits = m_aos.geometry_traits();
if (m_gso.draw_vertex(m_aos, vh)) { draw_point_impl1(*traits, p, colored, c);
if (m_gso.colored_vertex(m_aos, vh)) {
draw_point_impl1(vh->point(), *traits, 0, true, m_gso.vertex_color(m_aos, vh));
}
else
// color unused
draw_point_impl1(vh->point(), *traits, 0, false, CGAL::IO::Color());
}
} }
/// ///
@ -320,8 +345,7 @@ public:
* along the CCB, such that there is no other halfedge underneath. * along the CCB, such that there is no other halfedge underneath.
*/ */
template <typename Traits> template <typename Traits>
Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ, Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ, const Traits&) {
const Traits&) {
// std::cout << "find_smallest()\n"; // std::cout << "find_smallest()\n";
const auto* traits = this->m_aos.geometry_traits(); const auto* traits = this->m_aos.geometry_traits();
auto cmp_xy = traits->compare_xy_2_object(); auto cmp_xy = traits->compare_xy_2_object();
@ -371,13 +395,13 @@ public:
// Add edges that do not separate faces. // Add edges that do not separate faces.
if (m_gso.are_edges_enabled()) { if (m_gso.are_edges_enabled()) {
std::cout << "Edges not enabled\n";
for (auto it = m_aos.edges_begin(); it != m_aos.edges_end(); ++it) { for (auto it = m_aos.edges_begin(); it != m_aos.edges_end(); ++it) {
if (it->face() == it->twin()->face()) { if (it->face() == it->twin()->face()) {
if (m_gso.draw_edge(m_aos, it)) { if (m_gso.draw_edge(m_aos, it)) {
if (m_gso.colored_edge(m_aos, it)) if (m_gso.colored_edge(m_aos, it))
draw_curve(it->curve(), true, m_gso.edge_color(m_aos, it)); draw_curve(it->curve(), true, m_gso.edge_color(m_aos, it));
else else draw_curve(it->curve(), false, CGAL::IO::Color());
draw_curve(it->curve(), false, CGAL::IO::Color());
} }
} }
} }
@ -385,8 +409,11 @@ public:
// Add all points // Add all points
if (m_gso.are_vertices_enabled()) { if (m_gso.are_vertices_enabled()) {
for (auto it = m_aos.vertices_begin(); it != m_aos.vertices_end(); ++it) for (auto it = m_aos.vertices_begin(); it != m_aos.vertices_end(); ++it) {
draw_point(it); if (m_gso.colored_vertex(m_aos, it))
draw_point(it->point(), true, m_gso.vertex_color(m_aos, it));
else draw_point(it->point(), false, CGAL::IO::Color());
}
} }
m_visited.clear(); m_visited.clear();
@ -402,13 +429,14 @@ public:
void draw_approximate_curve(const XMonotoneCurve& curve, void draw_approximate_curve(const XMonotoneCurve& curve,
const Approximate& approx, const Approximate& approx,
bool colored, const CGAL::IO::Color& c) { bool colored, const CGAL::IO::Color& c) {
// std::cout << "draw_approximate_curve\n";
std::vector<typename Gt::Approximate_point_2> polyline; std::vector<typename Gt::Approximate_point_2> polyline;
double error(0.01); // TODO? (this->pixel_ratio()); double error(0.01); // TODO? (this->pixel_ratio());
approx(curve, error, std::back_inserter(polyline)); approx(curve, error, std::back_inserter(polyline));
if (polyline.empty()) return; if (polyline.empty()) return;
auto it = polyline.begin(); auto it = polyline.begin();
auto prev = it++; auto prev = it++;
for (; it != polyline.end(); prev = ++it) { for (; it != polyline.end(); prev = it++) {
if (colored) m_gs.add_segment(*prev, *it, c); if (colored) m_gs.add_segment(*prev, *it, c);
else m_gs.add_segment(*prev, *it); else m_gs.add_segment(*prev, *it);
} }
@ -416,46 +444,42 @@ public:
/*! Compile time dispatching /*! Compile time dispatching
*/ */
#if 0 // template <typename T, typename I = void>
template <typename T, typename I = void> // void draw_curve_impl2(const X_monotone_curve& xcv, T const&, long)
void draw_curve_impl2(const X_monotone_curve& xcv, T const&, long) // { draw_exact_curve(xcv); }
{ draw_exact_curve(xcv); }
template <typename T, typename I> // template <typename T, typename I>
auto draw_curve_impl2(const X_monotone_curve& xcv, T const& approx, int) -> // auto draw_curve_impl2(const X_monotone_curve& xcv, T const& approx, int) ->
decltype(approx.template operator()<I>(X_monotone_curve{}, double{}, I{}, // decltype(approx.template operator()<I>(X_monotone_curve{}, double{}, I{},
bool{}), void()) // bool{}), void())
{ draw_approximate_curve(xcv, approx); } // { draw_approximate_curve(xcv, approx); }
/*! Draw a curve, where the traits has approximate_2_object. /*! Draw a curve, where the traits does not has approximate_2_object.
*/ */
template <typename T> template <typename T, std::enable_if_t<! has_approximate_2_object_v<T>, int> = 0>
void draw_curve_impl1(const X_monotone_curve& xcv, T const&, long) void draw_curve_impl1(T const& /* traits */, const X_monotone_curve& xcv,
{ draw_exact_curve(xcv); }
///
template <typename T>
auto draw_curve_impl1(const X_monotone_curve& xcv, T const& traits, int) ->
decltype(traits.approximate_2_object(), void()) {
using Approximate = typename Gt::Approximate_2;
draw_curve_impl2<Approximate, int>(xcv, traits.approximate_2_object(), 0);
}
#else
template <typename T>
void draw_curve_impl1(const X_monotone_curve& xcv, T const& traits, int,
bool colored, const CGAL::IO::Color& c) bool colored, const CGAL::IO::Color& c)
{ draw_approximate_curve(xcv, traits.approximate_2_object(), colored, c); } { draw_exact_curve(xcv, colored, c); }
#endif
/*! Draw a curve, where the traits does have approximate_2_object.
*/
template <typename T, std::enable_if_t<has_approximate_2_object_v<T>, int> = 0>
auto draw_curve_impl1(T const& traits, const X_monotone_curve& xcv,
bool colored, const CGAL::IO::Color& c) {
using Approximate = typename Gt::Approximate_2;
// draw_curve_impl2<Approximate, int>(xcv, traits.approximate_2_object(), 0);
draw_approximate_curve(xcv, traits.approximate_2_object(), colored, c);
}
/*! Draw a geodesic curve /*! Draw a geodesic curve
*/ */
template <typename Kernel_, int AtanX, int AtanY> template <typename Kernel_, int AtanX, int AtanY>
void draw_curve_impl1 void draw_curve_impl1
(const X_monotone_curve& xcv, (Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits,
Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits, const X_monotone_curve& xcv,
int,
bool colored, const CGAL::IO::Color& c) bool colored, const CGAL::IO::Color& c)
{ {
// std::cout << "draw_curve (geodesic)\n";
auto approx = traits.approximate_2_object(); auto approx = traits.approximate_2_object();
using Kernel = Kernel_; using Kernel = Kernel_;
using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>; using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>;
@ -511,7 +535,7 @@ public:
draw_exact_curve(curve); draw_exact_curve(curve);
#else #else
const auto* traits = this->m_aos.geometry_traits(); const auto* traits = this->m_aos.geometry_traits();
draw_curve_impl1(curve, *traits, 0, colored, c); draw_curve_impl1(*traits, curve, colored, c);
#endif #endif
} }
@ -568,7 +592,7 @@ void draw(const CGAL_ARR_TYPE& aos, const GSOptions& gso,
} }
/// /// Draw an arrangement on surface.
template <typename GeometryTraits_2, typename TopologyTraits> template <typename GeometryTraits_2, typename TopologyTraits>
void draw(const CGAL_ARR_TYPE& aos, void draw(const CGAL_ARR_TYPE& aos,
const char* title = "2D Arrangement on Surface Basic Viewer") { const char* title = "2D Arrangement on Surface Basic Viewer") {