Cleaned up; Pacify MSVC; suppressed warnings.

This commit is contained in:
Efi Fogel 2025-10-23 12:11:31 +03:00
parent 6314299598
commit 5ed29f9173
12 changed files with 334 additions and 423 deletions

View File

@ -15,6 +15,7 @@
#ifndef CGAL_DRAW_AOS_ARR_APPROXIMATION_CACHE_H #ifndef CGAL_DRAW_AOS_ARR_APPROXIMATION_CACHE_H
#define CGAL_DRAW_AOS_ARR_APPROXIMATION_CACHE_H #define CGAL_DRAW_AOS_ARR_APPROXIMATION_CACHE_H
#include <boost/range/iterator_range.hpp> #include <boost/range/iterator_range.hpp>
#include <CGAL/Arr_enums.h> #include <CGAL/Arr_enums.h>
@ -24,16 +25,14 @@
namespace CGAL { namespace CGAL {
namespace draw_aos { namespace draw_aos {
/** /** @brief Cache class for approximating arrangement on surface.
* @brief Cache class for approximating arrangement on surface.
* *
* When iterating over the arrangement dcel, a feature(vertex, halfedge, face) might be visited multiple times. * When iterating over the arrangement dcel, a feature(vertex, halfedge, face) might be visited multiple times.
* This cache stores the approximated geometry for each feature to avoid redundant calculations. * This cache stores the approximated geometry for each feature to avoid redundant calculations.
* @tparam Arrangement * @tparam Arrangement
*/ */
template <typename Arrangement> template <typename Arrangement>
class Arr_approximation_cache class Arr_approximation_cache {
{
using Geom_traits = typename Arrangement::Geometry_traits_2; using Geom_traits = typename Arrangement::Geometry_traits_2;
using Approx_traits = Arr_approximate_traits<Geom_traits>; using Approx_traits = Arr_approximate_traits<Geom_traits>;
@ -67,4 +66,5 @@ private:
} // namespace draw_aos } // namespace draw_aos
} // namespace CGAL } // namespace CGAL
#endif #endif

View File

@ -15,6 +15,7 @@
#ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_FACE_H #ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_FACE_H
#define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_FACE_H #define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_FACE_H
#include <iterator> #include <iterator>
#include <optional> #include <optional>
#include <utility> #include <utility>

View File

@ -15,6 +15,7 @@
#ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_HALFEDGE_H #ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_HALFEDGE_H
#define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_HALFEDGE_H #define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_HALFEDGE_H
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstdlib> #include <cstdlib>
@ -32,16 +33,14 @@
namespace CGAL { namespace CGAL {
namespace draw_aos { namespace draw_aos {
/** /** @brief Functor to approximate an x-monotone curve within an bounding box.
* @brief Functor to approximate an x-monotone curve within an bounding box.
* *
* The Approximation is done from xmin to xmax with a given step. For parts outbound the y limits and precedes or * 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 * succeeds a part within, the approximation may be skipped but there will be at least one point outside the bbox
* for indication. * for indication.
*/ */
template <typename Arrangement> template <typename Arrangement>
class Arr_bounded_approximate_halfedge class Arr_bounded_approximate_halfedge {
{
using Geom_traits = typename Arrangement::Geometry_traits_2; using Geom_traits = typename Arrangement::Geometry_traits_2;
using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle; using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle;
using Gt_point = typename Geom_traits::Point_2; using Gt_point = typename Geom_traits::Point_2;
@ -58,32 +57,31 @@ class Arr_bounded_approximate_halfedge
using Boundary_lines = std::array<Approx_line_2, 4>; using Boundary_lines = std::array<Approx_line_2, 4>;
constexpr static bool Has_approximate_xcv_with_bounds = constexpr static bool Has_approximate_xcv_with_bounds =
has_approximate_xcv_with_bounds_v<Geom_traits, typename Geom_traits::Approximate_2>; has_approximate_xcv_with_bounds_v<Geom_traits, typename Geom_traits::Approximate_2>;
private: private:
struct Context : public Bounded_render_context struct Context : public Bounded_render_context {
{ Context(const Bounded_render_context& ctx, const X_monotone_curve_2& curve, Polyline& polyline) :
Context(const Bounded_render_context& ctx, const X_monotone_curve_2& curve, Polyline& polyline) Bounded_render_context(ctx),
: Bounded_render_context(ctx) m_polyline(polyline), m_curve(curve)
, m_polyline(polyline) {}
, m_curve(curve) {}
// Prevent accidental copying. // Prevent accidental copying.
Context(const Context&) = delete; Context(const Context&) = delete;
Context& operator=(const Context&) = delete; Context& operator=(const Context&) = delete;
public: public:
/*! /*! \brief Insert a point to the polyline if it is within the x-range of the curve
* \brief Insert a point to the polyline if it is within the x-range of the curve
* \note Will be replaced after AosApproximateUnboundedTraits_2 is fully available. * \note Will be replaced after AosApproximateUnboundedTraits_2 is fully available.
* \param pt * \param pt
*/ */
void insert(Point pt) { void insert(Point pt) {
if(pt.x() < this->xmin()) { if (pt.x() < this->xmin()) {
// We need the last point if not yet x-inbound. // We need the last point if not yet x-inbound.
m_last_pt = pt; m_last_pt = pt;
return; return;
} else if(pt.x() > this->xmax()) }
return; else if (pt.x() > this->xmax()) return;
m_polyline.push_back(pt); m_polyline.push_back(pt);
m_last_pt = pt; m_last_pt = pt;
@ -99,12 +97,11 @@ private:
const X_monotone_curve_2& m_curve; const X_monotone_curve_2& m_curve;
}; };
/*! /*! \brief Computes the intersection point between the given boundary side and the line segment from last_pt to pt.
* \brief Computes the intersection point between the given boundary side and the line segment from last_pt to pt.
*/ */
Point boundary_intersection(const Context& ctx, Point pt, Boundary_side side) const { Point boundary_intersection(const Context& ctx, Point pt, Boundary_side side) const {
std::optional<double> x, y; std::optional<double> x, y;
const Approx_line_2* line; const Approx_line_2* line = nullptr;
switch(side) { switch(side) {
case Boundary_side::Left: case Boundary_side::Left:
x = ctx.xmin(); x = ctx.xmin();
@ -126,41 +123,41 @@ private:
CGAL_assertion(false && "Unexpected side of boundary."); CGAL_assertion(false && "Unexpected side of boundary.");
} }
Point inter = std::get<Point>(*CGAL::intersection(Approx_line_2(*ctx.last_pt(), pt), *line)); Point inter = std::get<Point>(*CGAL::intersection(Approx_line_2(*ctx.last_pt(), pt), *line));
if(x.has_value()) return Point(*x, inter.y()); if (x.has_value()) return Point(*x, inter.y());
return Point(inter.x(), *y); return Point(inter.x(), *y);
} }
/*! /*! \brief Trace approximated curve point in ltr ordering, adding boundary intersections if necessary.
* \brief Trace approximated curve point in ltr ordering, adding boundary intersections if necessary.
* *
* \note This method will eventually be replaced by AosApproximateUnboundedTraits_2. * \note This method will eventually be replaced by AosApproximateUnboundedTraits_2.
*/ */
void trace_add(Context& ctx, Point pt) const { void trace_add(Context& ctx, Point pt) const {
if(!ctx.last_pt().has_value()) { if (! ctx.last_pt().has_value()) {
ctx.insert(pt); ctx.insert(pt);
return; return;
} }
if(ctx.last_pt()->x() < ctx.xmin() && pt.x() >= ctx.xmin()) if (ctx.last_pt()->x() < ctx.xmin() && pt.x() >= ctx.xmin())
ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Left)); ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Left));
if(ctx.last_pt()->y() < ctx.ymin()) { if (ctx.last_pt()->y() < ctx.ymin()) {
if(pt.y() > ctx.ymin()) ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Bottom)); if (pt.y() > ctx.ymin()) ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Bottom));
if(pt.y() > ctx.ymax()) ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Top)); if (pt.y() > ctx.ymax()) ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Top));
} else if(ctx.last_pt()->y() > ctx.ymax()) { }
if(pt.y() < ctx.ymax()) ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Top)); else if (ctx.last_pt()->y() > ctx.ymax()) {
if(pt.y() < ctx.ymin()) ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Bottom)); if (pt.y() < ctx.ymax()) ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Top));
} else { if (pt.y() < ctx.ymin()) ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Bottom));
if(pt.y() < ctx.ymin()) }
else {
if (pt.y() < ctx.ymin())
ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Bottom)); ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Bottom));
else if(pt.y() > ctx.ymax()) else if (pt.y() > ctx.ymax())
ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Top)); ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Top));
} }
if(ctx.last_pt()->x() <= ctx.xmax() && pt.x() > ctx.xmax()) if (ctx.last_pt()->x() <= ctx.xmax() && pt.x() > ctx.xmax())
ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Right)); ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Right));
ctx.insert(pt); ctx.insert(pt);
} }
/*! /*! \brief Check if the point is within the x-range of the curve.
* \brief Check if the point is within the x-range of the curve.
*/ */
static bool is_in_x_range(const Context& ctx, const Gt_point& pt) { static bool is_in_x_range(const Context& ctx, const Gt_point& pt) {
const Geom_traits& traits = ctx.m_traits; const Geom_traits& traits = ctx.m_traits;
@ -170,42 +167,40 @@ private:
if constexpr(!has_parameter_space_in_x_2<Geom_traits>::value) { if constexpr(!has_parameter_space_in_x_2<Geom_traits>::value) {
const auto& min_pt = traits.construct_min_vertex_2_object()(curve); const auto& min_pt = traits.construct_min_vertex_2_object()(curve);
const auto& max_pt = traits.construct_max_vertex_2_object()(curve); const auto& max_pt = traits.construct_max_vertex_2_object()(curve);
return traits.compare_x_2_object()(pt, min_pt) != CGAL::SMALLER && return ((traits.compare_x_2_object()(pt, min_pt) != CGAL::SMALLER) &&
traits.compare_x_2_object()(pt, max_pt) != CGAL::LARGER; (traits.compare_x_2_object()(pt, max_pt) != CGAL::LARGER));
} }
Comparison_result left_cmp; Comparison_result left_cmp;
if(auto left_loc = traits.parameter_space_in_x_2_object()(curve, ARR_MIN_END); left_loc == ARR_INTERIOR) if (auto left_loc = traits.parameter_space_in_x_2_object()(curve, ARR_MIN_END); left_loc == ARR_INTERIOR)
left_cmp = traits.compare_x_2_object()(pt, traits.construct_min_vertex_2_object()(curve)); left_cmp = traits.compare_x_2_object()(pt, traits.construct_min_vertex_2_object()(curve));
else if(left_loc == ARR_LEFT_BOUNDARY) else if (left_loc == ARR_LEFT_BOUNDARY)
left_cmp = CGAL::LARGER; left_cmp = CGAL::LARGER;
else else
left_cmp = traits.compare_x_on_boundary_2_object()(pt, curve, ARR_MIN_END); left_cmp = traits.compare_x_on_boundary_2_object()(pt, curve, ARR_MIN_END);
if(left_cmp == CGAL::SMALLER) return false; if (left_cmp == CGAL::SMALLER) return false;
if(left_cmp == CGAL::EQUAL) return true; if (left_cmp == CGAL::EQUAL) return true;
Comparison_result right_cmp; Comparison_result right_cmp;
if(auto right_loc = traits.parameter_space_in_x_2_object()(curve, ARR_MAX_END); right_loc == ARR_INTERIOR) if (auto right_loc = traits.parameter_space_in_x_2_object()(curve, ARR_MAX_END); right_loc == ARR_INTERIOR)
right_cmp = traits.compare_x_2_object()(pt, traits.construct_max_vertex_2_object()(curve)); right_cmp = traits.compare_x_2_object()(pt, traits.construct_max_vertex_2_object()(curve));
else if(right_loc == ARR_RIGHT_BOUNDARY) else if (right_loc == ARR_RIGHT_BOUNDARY)
right_cmp = CGAL::SMALLER; right_cmp = CGAL::SMALLER;
else else
right_cmp = traits.compare_x_on_boundary_2_object()(pt, curve, ARR_MAX_END); right_cmp = traits.compare_x_on_boundary_2_object()(pt, curve, ARR_MAX_END);
return right_cmp != CGAL::LARGER; return right_cmp != CGAL::LARGER;
} }
/*! /*! \brief transform approximated curve points(ltr ordering) in place based on the halfedge, giving correct
* \brief transform approximated curve points(ltr ordering) in place based on the halfedge, giving correct
* ordering, continuity, etc. * ordering, continuity, etc.
*/ */
static void transform_polyline(Context& ctx, Polyline& polyline, const Halfedge_const_handle& he) { static void transform_polyline(Context& ctx, Polyline& polyline, const Halfedge_const_handle& he)
transform_polyline_impl<Geom_traits>(ctx, polyline, he); { transform_polyline_impl<Geom_traits>(ctx, polyline, he); }
}
// For planar arrangements, we only need to reverse the polyline if the halfedge is rtl. // For planar arrangements, we only need to reverse the polyline if the halfedge is rtl.
template <typename Gt, std::enable_if_t<!is_or_derived_from_curved_surf_traits_v<Gt>, int> = 0> template <typename Gt, std::enable_if_t<!is_or_derived_from_curved_surf_traits_v<Gt>, int> = 0>
static void transform_polyline_impl(Context&, Polyline& polyline, const Halfedge_const_handle& he) { static void transform_polyline_impl(Context&, Polyline& polyline, const Halfedge_const_handle& he) {
if(he->direction() == CGAL::ARR_LEFT_TO_RIGHT) return; if (he->direction() == CGAL::ARR_LEFT_TO_RIGHT) return;
std::reverse(polyline.begin(), polyline.end()); std::reverse(polyline.begin(), polyline.end());
} }
@ -214,21 +209,22 @@ private:
using Direction_3 = typename Geom_traits::Direction_3; using Direction_3 = typename Geom_traits::Direction_3;
using Vector_3 = typename Geom_traits::Vector_3; using Vector_3 = typename Geom_traits::Vector_3;
if(polyline.size() < 2) return; if (polyline.size() < 2) return;
const X_monotone_curve_2& curve = he->curve(); const X_monotone_curve_2& curve = he->curve();
const auto& traits = ctx.m_traits; const auto& traits = ctx.m_traits;
if(curve.is_vertical()) { if (curve.is_vertical()) {
Direction_3 normal_dir = curve.is_directed_right() ? curve.normal() : -curve.normal(); Direction_3 normal_dir = curve.is_directed_right() ? curve.normal() : -curve.normal();
Direction_3 azimuth_dir(CGAL::cross_product(Vector_3(0, 0, 1), normal_dir.vector())); Direction_3 azimuth_dir(CGAL::cross_product(Vector_3(0, 0, 1), normal_dir.vector()));
Approx_nt azimuth = ctx.to_uv(traits.approximate_2_object()(traits.construct_point_2_object()(azimuth_dir))).x(); Approx_nt azimuth = ctx.to_uv(traits.approximate_2_object()(traits.construct_point_2_object()(azimuth_dir))).x();
if(azimuth == 0 && he->direction() == ARR_LEFT_TO_RIGHT) azimuth = 2 * CGAL_PI; if (azimuth == 0 && he->direction() == ARR_LEFT_TO_RIGHT) azimuth = 2 * CGAL_PI;
std::transform(polyline.begin(), polyline.end(), polyline.begin(), std::transform(polyline.begin(), polyline.end(), polyline.begin(),
[azimuth](Point pt) { return Point(azimuth, pt.y()); }); [azimuth](Point pt) { return Point(azimuth, pt.y()); });
} else if(polyline.back().x() == 0) { }
else if (polyline.back().x() == 0) {
// For strictly x-monotone arcs whose target point sits on the boundary, the x should be set to 2 * CGAL_PI // For strictly x-monotone arcs whose target point sits on the boundary, the x should be set to 2 * CGAL_PI
polyline.back() = Point(2 * CGAL_PI, polyline.back().y()); polyline.back() = Point(2 * CGAL_PI, polyline.back().y());
} }
if(he->direction() == CGAL::ARR_LEFT_TO_RIGHT) return; if (he->direction() == CGAL::ARR_LEFT_TO_RIGHT) return;
std::reverse(polyline.begin(), polyline.end()); std::reverse(polyline.begin(), polyline.end());
} }
@ -242,22 +238,23 @@ private:
Polyline& polyline = ctx.m_polyline; Polyline& polyline = ctx.m_polyline;
auto compare_y_at_x_2 = traits.compare_y_at_x_2_object(); auto compare_y_at_x_2 = traits.compare_y_at_x_2_object();
if(is_in_x_range(ctx, m_top_left)) { if (is_in_x_range(ctx, m_top_left)) {
if(compare_y_at_x_2(m_top_left, curve) == CGAL::SMALLER) { if (compare_y_at_x_2(m_top_left, curve) == CGAL::SMALLER) {
polyline.insert(polyline.end(), {Approx_traits::Null_point, Point(ctx.xmin(), ctx.ymax())}); polyline.insert(polyline.end(), {Approx_traits::Null_point, Point(ctx.xmin(), ctx.ymax())});
} else if(compare_y_at_x_2(m_bottom_left, curve) == CGAL::LARGER) { }
else if (compare_y_at_x_2(m_bottom_left, curve) == CGAL::LARGER) {
polyline.insert(polyline.end(), {Approx_traits::Null_point, Point(ctx.xmin(), ctx.ymin())}); polyline.insert(polyline.end(), {Approx_traits::Null_point, Point(ctx.xmin(), ctx.ymin())});
} }
} }
traits.approximate_2_object()(curve, ctx.m_approx_error, traits.approximate_2_object()(curve, ctx.m_approx_error,
boost::make_function_output_iterator([&ctx, this](Approx_point approx_pt) { boost::make_function_output_iterator([&ctx, this](Approx_point approx_pt)
ctx.m_polyline.push_back(snap_to_boundary(ctx, ctx.to_uv(approx_pt))); { ctx.m_polyline.push_back(snap_to_boundary(ctx, ctx.to_uv(approx_pt))); }),
}),
ctx.bbox(), true); ctx.bbox(), true);
if(is_in_x_range(ctx, m_top_right)) { if (is_in_x_range(ctx, m_top_right)) {
if(compare_y_at_x_2(m_top_right, curve) == CGAL::SMALLER) { if (compare_y_at_x_2(m_top_right, curve) == CGAL::SMALLER) {
polyline.insert(polyline.end(), {Point(ctx.xmax(), ctx.ymax()), Approx_traits::Null_point}); polyline.insert(polyline.end(), {Point(ctx.xmax(), ctx.ymax()), Approx_traits::Null_point});
} else if(compare_y_at_x_2(m_bottom_right, curve) == CGAL::LARGER) { }
else if (compare_y_at_x_2(m_bottom_right, curve) == CGAL::LARGER) {
polyline.insert(polyline.end(), {Point(ctx.xmax(), ctx.ymin()), Approx_traits::Null_point}); polyline.insert(polyline.end(), {Point(ctx.xmax(), ctx.ymin()), Approx_traits::Null_point});
} }
} }
@ -266,36 +263,31 @@ private:
// If Approximate_2 does not support curve approximation with bounding box // If Approximate_2 does not support curve approximation with bounding box
template <typename Gt, std::enable_if_t<!has_approximate_xcv_with_bounds_v<Gt, typename Gt::Approximate_2>, int> = 0> template <typename Gt, std::enable_if_t<!has_approximate_xcv_with_bounds_v<Gt, typename Gt::Approximate_2>, int> = 0>
void approximate_curve_impl(Context& ctx) const { void approximate_curve_impl(Context& ctx) const {
m_ctx.m_traits.approximate_2_object()( auto approx = m_ctx.m_traits.approximate_2_object();
ctx.m_curve, ctx.m_approx_error, approx(ctx.m_curve, ctx.m_approx_error,
boost::make_function_output_iterator([&ctx, this](Approx_point pt) { trace_add(ctx, ctx.to_uv(pt)); }), true); boost::make_function_output_iterator([&ctx, this](Approx_point pt) { trace_add(ctx, ctx.to_uv(pt)); }), true);
} }
/*! /*! \brief Adjusts a point by snapping it to the nearest boundary to reduce floating-point error.
* \brief Adjusts a point by snapping it to the nearest boundary to reduce floating-point error.
* *
* \return The adjusted (snapped) point if it lies within snapping tolerance, or the original point otherwise. * \return The adjusted (snapped) point if it lies within snapping tolerance, or the original point otherwise.
*/ */
Point snap_to_boundary(const Context& ctx, Point pt) const { Point snap_to_boundary(const Context& ctx, Point pt) const {
Approx_nt x = pt.x(), y = pt.y(); Approx_nt x = pt.x(), y = pt.y();
if(std::abs(x - ctx.xmin()) < m_ep_left) if (std::abs(x - ctx.xmin()) < m_ep_left) x = ctx.xmin();
x = ctx.xmin(); else if (std::abs(x - ctx.xmax()) < m_ep_right) x = ctx.xmax();
else if(std::abs(x - ctx.xmax()) < m_ep_right) if (std::abs(y - ctx.ymin()) < m_ep_bottom) y = ctx.ymin();
x = ctx.xmax(); else if (std::abs(y - ctx.ymax()) < m_ep_top) y = ctx.ymax();
if(std::abs(y - ctx.ymin()) < m_ep_bottom)
y = ctx.ymin();
else if(std::abs(y - ctx.ymax()) < m_ep_top)
y = ctx.ymax();
return Point(x, y); return Point(x, y);
} }
public: public:
Arr_bounded_approximate_halfedge(const Bounded_render_context& ctx) Arr_bounded_approximate_halfedge(const Bounded_render_context& ctx) :
: m_ctx(ctx) m_ctx(ctx),
, m_top(ctx.top_left(), ctx.top_right()) m_left(ctx.bottom_left(), ctx.top_left()),
, m_bottom(ctx.bottom_left(), ctx.bottom_right()) m_right(ctx.bottom_right(), ctx.top_right()),
, m_left(ctx.bottom_left(), ctx.top_left()) m_bottom(ctx.bottom_left(), ctx.bottom_right()),
, m_right(ctx.bottom_right(), ctx.top_right()) { m_top(ctx.top_left(), ctx.top_right()) {
Construct_gt_point_2<Geom_traits> ctr_p; Construct_gt_point_2<Geom_traits> ctr_p;
m_top_left = ctr_p(ctx.to_cartesian(ctx.top_left())); m_top_left = ctr_p(ctx.to_cartesian(ctx.top_left()));
m_top_right = ctr_p(ctx.to_cartesian(ctx.top_right())); m_top_right = ctr_p(ctx.to_cartesian(ctx.top_right()));
@ -314,8 +306,8 @@ public:
auto& cache = m_ctx.m_cache.halfedges(); auto& cache = m_ctx.m_cache.halfedges();
auto [iter, inserted] = cache.try_emplace(he, Polyline()); auto [iter, inserted] = cache.try_emplace(he, Polyline());
Polyline& polyline = iter->second; Polyline& polyline = iter->second;
if(!inserted) return polyline; if (!inserted) return polyline;
if(m_ctx.is_cancelled()) return polyline; if (m_ctx.is_cancelled()) return polyline;
const X_monotone_curve_2& curve = he->curve(); const X_monotone_curve_2& curve = he->curve();
Context ctx(m_ctx, curve, polyline); Context ctx(m_ctx, curve, polyline);
@ -325,18 +317,19 @@ public:
// also approximate the twin halfedge // also approximate the twin halfedge
auto [twin_iter, twin_inserted] = cache.try_emplace(he->twin(), std::move(poly_copy)); auto [twin_iter, twin_inserted] = cache.try_emplace(he->twin(), std::move(poly_copy));
if(twin_inserted) transform_polyline(ctx, twin_iter->second, he->twin()); if (twin_inserted) transform_polyline(ctx, twin_iter->second, he->twin());
// The previous iterator might have been invalidated by the second try_emplace call, so we do an extra lookup. // The previous iterator might have been invalidated by the second try_emplace call, so we do an extra lookup.
return cache.at(he); return cache.at(he);
} }
private: private:
const Bounded_render_context& m_ctx; const Bounded_render_context& m_ctx;
Approx_line_2 m_left, m_right, m_top, m_bottom; Approx_line_2 m_left, m_right, m_bottom, m_top;
Gt_point m_top_left, m_top_right, m_bottom_left, m_bottom_right; Gt_point m_top_left, m_top_right, m_bottom_left, m_bottom_right;
Approx_nt m_ep_left, m_ep_right, m_ep_bottom, m_ep_top; Approx_nt m_ep_left, m_ep_right, m_ep_bottom, m_ep_top;
}; };
} // namespace draw_aos } // namespace draw_aos
} // namespace CGAL } // namespace CGAL
#endif #endif

View File

@ -23,8 +23,7 @@ namespace CGAL {
namespace draw_aos { namespace draw_aos {
template <typename Arrangement> template <typename Arrangement>
class Arr_bounded_approximate_vertex class Arr_bounded_approximate_vertex {
{
using Geom_traits = typename Arrangement::Geometry_traits_2; using Geom_traits = typename Arrangement::Geometry_traits_2;
using Point_2 = typename Geom_traits::Point_2; using Point_2 = typename Geom_traits::Point_2;
using Vertex_const_handle = typename Arrangement::Vertex_const_handle; using Vertex_const_handle = typename Arrangement::Vertex_const_handle;
@ -32,11 +31,9 @@ class Arr_bounded_approximate_vertex
using Bounded_render_context = Arr_bounded_render_context<Arrangement>; using Bounded_render_context = Arr_bounded_render_context<Arrangement>;
public: public:
Arr_bounded_approximate_vertex(const Bounded_render_context& ctx) Arr_bounded_approximate_vertex(const Bounded_render_context& ctx) : m_ctx(ctx) {}
: m_ctx(ctx) {}
/** /** @brief Approximate a vertex within the x-bounded range.
* @brief Approximate a vertex within the x-bounded range.
* *
* The function uses cached values if available. * The function uses cached values if available.
* @precondition: The vertex must have an associated point. * @precondition: The vertex must have an associated point.
@ -47,7 +44,7 @@ public:
const Point_geom& operator()(const Vertex_const_handle& vh) const { const Point_geom& operator()(const Vertex_const_handle& vh) const {
auto [iter, inserted] = m_ctx.m_cache.vertices().try_emplace(vh); auto [iter, inserted] = m_ctx.m_cache.vertices().try_emplace(vh);
Point_geom& point = iter->second; Point_geom& point = iter->second;
if(!inserted) return point; if (! inserted) return point;
return point = m_ctx.to_uv(m_ctx.m_traits.approximate_2_object()(vh->point())); return point = m_ctx.to_uv(m_ctx.m_traits.approximate_2_object()(vh->point()));
} }

View File

@ -54,8 +54,7 @@ namespace draw_aos {
* @brief Triangulator for a face of an arrangement within a bounding box. * @brief Triangulator for a face of an arrangement within a bounding box.
*/ */
template <typename Arrangement> template <typename Arrangement>
class Arr_bounded_face_triangulator class Arr_bounded_face_triangulator {
{
using Geom_traits = typename Arrangement::Geometry_traits_2; using Geom_traits = typename Arrangement::Geometry_traits_2;
constexpr static bool Is_on_curved_surface = is_or_derived_from_curved_surf_traits_v<Geom_traits>; constexpr static bool Is_on_curved_surface = is_or_derived_from_curved_surf_traits_v<Geom_traits>;
@ -74,15 +73,12 @@ class Arr_bounded_face_triangulator
enum Point_type { Vertex_only, Constraint_only, Vertex_and_constraint }; enum Point_type { Vertex_only, Constraint_only, Vertex_and_constraint };
/*! /*! \brief A index wrapper defaulted to invalid.
* \brief A index wrapper defaulted to invalid.
*/ */
class Index class Index {
{
public: public:
Index() = default; Index() = default;
Index(int idx) Index(int idx) : m_index(idx) {}
: m_index(idx) {}
bool is_valid() const { return m_index != Invalid_index; } bool is_valid() const { return m_index != Invalid_index; }
operator int() const { return m_index; } operator int() const { return m_index; }
@ -111,8 +107,7 @@ public:
private: private:
static KPoint to_kpoint(Point pt) { return KPoint(pt.x(), pt.y()); } static KPoint to_kpoint(Point pt) { return KPoint(pt.x(), pt.y()); }
/*! /*! \brief Offset a point on a specific boundary outward by a given offset.
* \brief Offset a point on a specific boundary outward by a given offset.
* *
* \pre side != Boundary_side::None * \pre side != Boundary_side::None
*/ */
@ -120,32 +115,25 @@ private:
CGAL_precondition(side != Boundary_side::None); CGAL_precondition(side != Boundary_side::None);
switch(side) { switch(side) {
case Boundary_side::Left: case Boundary_side::Left: return Point(pt.x() - offset, pt.y());
return Point(pt.x() - offset, pt.y()); case Boundary_side::Right: return Point(pt.x() + offset, pt.y());
case Boundary_side::Right: case Boundary_side::Top: return Point(pt.x(), pt.y() + offset);
return Point(pt.x() + offset, pt.y()); case Boundary_side::Bottom: return Point(pt.x(), pt.y() - offset);
case Boundary_side::Top: default: return pt; // Should not reach here
return Point(pt.x(), pt.y() + offset);
case Boundary_side::Bottom:
return Point(pt.x(), pt.y() - offset);
default:
return pt; // Should not reach here
} }
} }
/*! /*! \brief Find the shared boundary side of two points, or None if they are not on the same boundary.
* \brief Find the shared boundary side of two points, or None if they are not on the same boundary.
*/ */
Boundary_side shared_boundary(const Point& pt1, const Point& pt2) const { Boundary_side shared_boundary(const Point& pt1, const Point& pt2) const {
if(m_ctx.is_on_left(pt1) && m_ctx.is_on_left(pt2)) return Boundary_side::Left; if (m_ctx.is_on_left(pt1) && m_ctx.is_on_left(pt2)) return Boundary_side::Left;
if(m_ctx.is_on_right(pt1) && m_ctx.is_on_right(pt2)) return Boundary_side::Right; if (m_ctx.is_on_right(pt1) && m_ctx.is_on_right(pt2)) return Boundary_side::Right;
if(m_ctx.is_on_bottom(pt1) && m_ctx.is_on_bottom(pt2)) return Boundary_side::Bottom; if (m_ctx.is_on_bottom(pt1) && m_ctx.is_on_bottom(pt2)) return Boundary_side::Bottom;
if(m_ctx.is_on_top(pt1) && m_ctx.is_on_top(pt2)) return Boundary_side::Top; if (m_ctx.is_on_top(pt1) && m_ctx.is_on_top(pt2)) return Boundary_side::Top;
return Boundary_side::None; return Boundary_side::None;
} }
/*! /*! \brief Add a helper point on the shared boundary of two points if they are on the same boundary side.
* \brief Add a helper point on the shared boundary of two points if they are on the same boundary side.
* *
* When triangulating a arrangement face within a bounding box, curves outside the bounding box are projected on the * When triangulating a arrangement face within a bounding box, curves outside the bounding box are projected on the
* four sides of the bbox. Topological errors could be introduced if several segments are lying on the same side. * four sides of the bbox. Topological errors could be introduced if several segments are lying on the same side.
@ -155,9 +143,9 @@ private:
// Arrangements on curved surfaces currently draws the entire parameter space, so there's no need to add // Arrangements on curved surfaces currently draws the entire parameter space, so there's no need to add
// helper points. // helper points.
if constexpr(Is_on_curved_surface) return; if constexpr(Is_on_curved_surface) return;
if(from == to) return; if (from == to) return;
auto shared_side = shared_boundary(from, to); auto shared_side = shared_boundary(from, to);
if(shared_side == Boundary_side::None) return; if (shared_side == Boundary_side::None) return;
Point mid = CGAL::midpoint(from, to); Point mid = CGAL::midpoint(from, to);
m_points.push_back(offset_boundary_point(mid, shared_side, m_offset += 0.1)); m_points.push_back(offset_boundary_point(mid, shared_side, m_offset += 0.1));
m_point_types.push_back(Constraint_only); m_point_types.push_back(Constraint_only);
@ -185,7 +173,7 @@ private:
void insert_all_constraints() { void insert_all_constraints() {
auto constraint_filter = [this](int idx) { return m_point_types[idx] != Vertex_only; }; auto constraint_filter = [this](int idx) { return m_point_types[idx] != Vertex_only; };
auto index_to_point = [this](int idx) -> KPoint { return to_kpoint(m_points[idx]); }; auto index_to_point = [this](int idx) -> KPoint { return to_kpoint(m_points[idx]); };
for(auto [start_idx, end_idx] : m_cst_ranges) { for (auto [start_idx, end_idx] : m_cst_ranges) {
auto indexes_begin = boost::make_counting_iterator<int>(start_idx); auto indexes_begin = boost::make_counting_iterator<int>(start_idx);
auto indexes_end = boost::make_counting_iterator<int>(end_idx); auto indexes_end = boost::make_counting_iterator<int>(end_idx);
auto filtered_begin = boost::make_filter_iterator(constraint_filter, indexes_begin, indexes_end); auto filtered_begin = boost::make_filter_iterator(constraint_filter, indexes_begin, indexes_end);
@ -197,14 +185,15 @@ private:
} }
public: public:
Arr_bounded_face_triangulator(const Bounded_render_context& ctx, Face_const_handle fh) Arr_bounded_face_triangulator(const Bounded_render_context& ctx, Face_const_handle fh) :
: m_ctx(ctx) m_ctx(ctx),
, m_fh(fh) {} m_fh(fh)
{}
void push_back(Point pt) { void push_back(Point pt) {
CGAL_assertion_msg(m_curr_cst_begin.has_value(), "Call start_constraint() before push_back()."); CGAL_assertion_msg(m_curr_cst_begin.has_value(), "Call start_constraint() before push_back().");
if(m_points.size() - *m_curr_cst_begin >= 1) add_boundary_helper_point(m_points.back(), pt); if (m_points.size() - *m_curr_cst_begin >= 1) add_boundary_helper_point(m_points.back(), pt);
m_points.push_back(pt); m_points.push_back(pt);
m_point_types.push_back(Vertex_and_constraint); m_point_types.push_back(Vertex_and_constraint);
} }
@ -216,7 +205,7 @@ public:
int cst_begin = *m_curr_cst_begin; int cst_begin = *m_curr_cst_begin;
m_curr_cst_begin.reset(); m_curr_cst_begin.reset();
if(m_points.size() - cst_begin <= 2) { if (m_points.size() - cst_begin <= 2) {
m_points.erase(m_points.begin() + cst_begin, m_points.end()); m_points.erase(m_points.begin() + cst_begin, m_points.end());
m_point_types.erase(m_point_types.begin() + cst_begin, m_point_types.end()); m_point_types.erase(m_point_types.begin() + cst_begin, m_point_types.end());
return; return;
@ -225,24 +214,23 @@ public:
m_cst_ranges.emplace_back(cst_begin, m_points.size()); m_cst_ranges.emplace_back(cst_begin, m_points.size());
} }
/*! /*! \brief Converts the triangulator to a triangulated face, moving internal data to the result.
* \brief Converts the triangulator to a triangulated face, moving internal data to the result.
* *
* \return Triangulated_face * \return Triangulated_face
*/ */
operator Triangle_soup() && { operator Triangle_soup() && {
CGAL_assertion_msg(!m_curr_cst_begin.has_value(), "Call end_constraint() before conversion"); CGAL_assertion_msg(!m_curr_cst_begin.has_value(), "Call end_constraint() before conversion");
if(m_points.empty()) return Triangle_soup(); if (m_points.empty()) return Triangle_soup();
if constexpr(Is_on_curved_surface) { if constexpr(Is_on_curved_surface) {
if(auto it = m_ctx.m_face_points.find(m_fh); it != m_ctx.m_face_points.end()) { if (auto it = m_ctx.m_face_points.find(m_fh); it != m_ctx.m_face_points.end()) {
m_points.insert(m_points.end(), it->second.begin(), it->second.end()); m_points.insert(m_points.end(), it->second.begin(), it->second.end());
m_point_types.insert(m_point_types.end(), it->second.size(), Vertex_only); m_point_types.insert(m_point_types.end(), it->second.size(), Vertex_only);
} }
} }
insert_all_vertices(); insert_all_vertices();
insert_all_constraints(); insert_all_constraints();
if(m_ct.number_of_faces() == 0) return Triangle_soup(); if (m_ct.number_of_faces() == 0) return Triangle_soup();
#if defined(CGAL_DRAW_AOS_DEBUG) #if defined(CGAL_DRAW_AOS_DEBUG)
debug_print(*this); debug_print(*this);
@ -255,12 +243,12 @@ public:
// Collect triangles within the constrained domain. // Collect triangles within the constrained domain.
Triangle_soup ts; Triangle_soup ts;
ts.triangles.reserve(m_ct.number_of_faces()); ts.triangles.reserve(m_ct.number_of_faces());
for(auto fit = m_ct.finite_faces_begin(); fit != m_ct.finite_faces_end(); ++fit) { for (auto fit = m_ct.finite_faces_begin(); fit != m_ct.finite_faces_end(); ++fit) {
Index v1 = fit->vertex(0)->info(); Index v1 = fit->vertex(0)->info();
Index v2 = fit->vertex(1)->info(); Index v2 = fit->vertex(1)->info();
Index v3 = fit->vertex(2)->info(); Index v3 = fit->vertex(2)->info();
if(!v1.is_valid() || !v2.is_valid() || !v3.is_valid()) continue; if (! v1.is_valid() || !v2.is_valid() || !v3.is_valid()) continue;
if(!get(in_domain, fit)) continue; if (! get(in_domain, fit)) continue;
ts.triangles.push_back(Triangle{v1, v2, v3}); ts.triangles.push_back(Triangle{v1, v2, v3});
} }
ts.points = std::move(m_points); ts.points = std::move(m_points);
@ -300,20 +288,20 @@ void debug_print(const Arr_bounded_face_triangulator<Arrangement>& triangulator)
auto points_path = debug_dir / points_filename; auto points_path = debug_dir / points_filename;
std::ofstream ofs_points(points_path); std::ofstream ofs_points(points_path);
ofs_index << points_filename << std::endl; ofs_index << points_filename << std::endl;
for(int i = 0; i < triangulator.m_points.size(); ++i) { for (int i = 0; i < triangulator.m_points.size(); ++i) {
if(m_point_types[i] == Point_type::Constraint_only) continue; if (m_point_types[i] == Point_type::Constraint_only) continue;
const auto& pt = m_points[i]; const auto& pt = m_points[i];
ofs_points << pt.x() << " " << pt.y() << "\n"; ofs_points << pt.x() << " " << pt.y() << "\n";
} }
int counter = 0; int counter = 0;
for(auto [start_idx, end_idx] : triangulator.m_cst_ranges) { for (auto [start_idx, end_idx] : triangulator.m_cst_ranges) {
auto filename = ccb_constraint_file_name_prefix + "_" + std::to_string(counter++) + ".txt"; auto filename = ccb_constraint_file_name_prefix + "_" + std::to_string(counter++) + ".txt";
auto filepath = debug_dir / filename; auto filepath = debug_dir / filename;
ofs_index << filename << std::endl; ofs_index << filename << std::endl;
std::ofstream ofs_ccb_constraint(filepath); std::ofstream ofs_ccb_constraint(filepath);
for(int i = start_idx; i < end_idx; ++i) { for (int i = start_idx; i < end_idx; ++i) {
if(m_point_types[i] == Point_type::Vertex_only) continue; if (m_point_types[i] == Point_type::Vertex_only) continue;
const auto& pt = m_points[i]; const auto& pt = m_points[i];
ofs_ccb_constraint << pt.x() << " " << pt.y() << "\n"; ofs_ccb_constraint << pt.x() << " " << pt.y() << "\n";
} }

View File

@ -25,21 +25,20 @@
namespace CGAL { namespace CGAL {
namespace draw_aos { namespace draw_aos {
/** /** @brief Render arrangement on surface within a bounding box.
* @brief Render arrangement on surface within a bounding box.
*/ */
template <typename Arrangement> template <typename Arrangement>
class Arr_bounded_renderer class Arr_bounded_renderer {
{
using Geom_traits = typename Arrangement::Geometry_traits_2; using Geom_traits = typename Arrangement::Geometry_traits_2;
using Face_const_handle = typename Arrangement::Face_const_handle; using Face_const_handle = typename Arrangement::Face_const_handle;
using Render_context = Arr_render_context<Arrangement>; using Render_context = Arr_render_context<Arrangement>;
using Approx_cache = Arr_approximation_cache<Arrangement>; using Approx_cache = Arr_approximation_cache<Arrangement>;
public: public:
Arr_bounded_renderer(const Render_context& ctx, Bbox_2 bbox) Arr_bounded_renderer(const Render_context& ctx, Bbox_2 bbox) :
: m_ctx(ctx) m_ctx(ctx),
, m_bbox(bbox) {} m_bbox(bbox)
{}
Approx_cache render() const { Approx_cache render() const {
Approx_cache cache; Approx_cache cache;

View File

@ -15,6 +15,7 @@
#ifndef CGAL_DRAW_AOS_ARR_COORDINATE_CONVERTER_H #ifndef CGAL_DRAW_AOS_ARR_COORDINATE_CONVERTER_H
#define CGAL_DRAW_AOS_ARR_COORDINATE_CONVERTER_H #define CGAL_DRAW_AOS_ARR_COORDINATE_CONVERTER_H
#include <cmath> #include <cmath>
#include <CGAL/number_type_config.h> #include <CGAL/number_type_config.h>
@ -24,33 +25,28 @@
namespace CGAL { namespace CGAL {
namespace draw_aos { namespace draw_aos {
/*! /*! \brief class handling coordinate conversion between 2D parameterized surface coordinates and cartesian coordinates.
* \brief class handling coordinate conversion between 2D parameterized surface coordinates and cartesian coordinates.
* *
* \tparam GeomTraits * \tparam GeomTraits
*/ */
template <typename GeomTraits> template <typename GeomTraits>
class Arr_coordinate_converter class Arr_coordinate_converter {
{
using Geom_traits = GeomTraits; using Geom_traits = GeomTraits;
using Approx_traits = Arr_approximate_traits<Geom_traits>; using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Approx_point = typename Approx_traits::Approx_point; using Approx_point = typename Approx_traits::Approx_point;
using Point = typename Approx_traits::Point; using Point = typename Approx_traits::Point;
public: public:
Arr_coordinate_converter(const GeomTraits& traits) Arr_coordinate_converter(const GeomTraits& traits) : m_traits(traits) {}
: m_traits(traits) {}
/*! /*! \brief converts a point in cartesian coordinates to parameterized surface coordinates.
* \brief Converts a point in cartesian coordinates to parameterized surface coordinates.
* *
* \param pt * \param pt
* \return Point * \return Point
*/ */
Point to_uv(Approx_point pt) const { return pt; } Point to_uv(Approx_point pt) const { return pt; }
/*! /*! \brief Converts a point in parameterized surface coordinates to cartesian coordinates.
* \brief Converts a point in parameterized surface coordinates to cartesian coordinates.
* *
* \param pt * \param pt
* \return Approx_point * \return Approx_point
@ -61,10 +57,9 @@ private:
const GeomTraits& m_traits; const GeomTraits& m_traits;
}; };
/*! /*! \brief Converter specialization for geodesic arc on sphere traits.
* \brief Converter specialization for geodesic arc on sphere traits.
* *
* Provides conversions between spherical coordinates and right-handed Cartesian coordinates. Sphercial coordinates are * provides conversions between spherical coordinates and right-handed Cartesian coordinates. Sphercial coordinates are
* represented as azimuth ( [0, 2 Pi) ) and polar ( [0, Pi] ) angle in radians. Points on the identification curve have * represented as azimuth ( [0, 2 Pi) ) and polar ( [0, Pi] ) angle in radians. Points on the identification curve have
* azimuth == 0. The south pole has polar == 0. * azimuth == 0. The south pole has polar == 0.
* *
@ -73,8 +68,7 @@ private:
* \tparam atanY * \tparam atanY
*/ */
template <typename Kernel, int atanX, int atanY> template <typename Kernel, int atanX, int atanY>
class Arr_coordinate_converter<Arr_geodesic_arc_on_sphere_traits_2<Kernel, atanX, atanY>> class Arr_coordinate_converter<Arr_geodesic_arc_on_sphere_traits_2<Kernel, atanX, atanY>> {
{
using Geom_traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel>; using Geom_traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel>;
using Approx_traits = Arr_approximate_traits<Geom_traits>; using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Approx_point = typename Approx_traits::Approx_point; using Approx_point = typename Approx_traits::Approx_point;
@ -82,14 +76,13 @@ class Arr_coordinate_converter<Arr_geodesic_arc_on_sphere_traits_2<Kernel, atanX
using Point = typename Approx_traits::Point; using Point = typename Approx_traits::Point;
public: public:
Arr_coordinate_converter(const Geom_traits& traits) Arr_coordinate_converter(const Geom_traits& traits) : m_traits(traits) {}
: m_traits(traits) {}
Point to_uv(Approx_point point) const { Point to_uv(Approx_point point) const {
if(point.location() == Approx_point::MAX_BOUNDARY_LOC) return Point(0, CGAL_PI); if(point.location() == Approx_point::MAX_BOUNDARY_LOC) return Point(0, CGAL_PI);
if(point.location() == Approx_point::MIN_BOUNDARY_LOC) return Point(0, 0); if(point.location() == Approx_point::MIN_BOUNDARY_LOC) return Point(0, 0);
Approx_nt azimuth_from_id = Approx_nt azimuth_from_id =
std::fmod(std::atan2(point.dy(), point.dx()) - std::atan2(atanY, atanX) + 2 * CGAL_PI, 2 * CGAL_PI); std::fmod(std::atan2(point.dy(), point.dx()) - std::atan2(atanY, atanX) + 2 * CGAL_PI, 2 * CGAL_PI);
return Point(azimuth_from_id, std::acos(-point.dz())); return Point(azimuth_from_id, std::acos(-point.dz()));
} }

View File

@ -15,6 +15,7 @@
#ifndef CGAL_DRAW_AOS_ARR_FACE_POINT_GENERATOR_H #ifndef CGAL_DRAW_AOS_ARR_FACE_POINT_GENERATOR_H
#define CGAL_DRAW_AOS_ARR_FACE_POINT_GENERATOR_H #define CGAL_DRAW_AOS_ARR_FACE_POINT_GENERATOR_H
#include <utility> #include <utility>
#include <variant> #include <variant>
#include <vector> #include <vector>
@ -30,8 +31,7 @@
namespace CGAL { namespace CGAL {
namespace draw_aos { namespace draw_aos {
/*! /*! \brief Generate face interior points.
* \brief Generate face interior points.
* *
* \tparam Arrangement * \tparam Arrangement
*/ */
@ -39,10 +39,9 @@ template <typename Arrangement, typename = void>
class Arr_face_point_generator; class Arr_face_point_generator;
template <typename Arrangement> template <typename Arrangement>
class Arr_face_point_generator< class Arr_face_point_generator<Arrangement,
Arrangement, std::enable_if_t<!is_or_derived_from_curved_surf_traits_v
std::enable_if_t<!is_or_derived_from_curved_surf_traits_v<typename Arrangement::Geometry_traits_2>>> <typename Arrangement::Geometry_traits_2>>> {
{
using Point_geom = typename Arr_approximate_traits<typename Arrangement::Geometry_traits_2>::Point; using Point_geom = typename Arr_approximate_traits<typename Arrangement::Geometry_traits_2>::Point;
using Face_const_handle = typename Arrangement::Face_const_handle; using Face_const_handle = typename Arrangement::Face_const_handle;
@ -55,8 +54,7 @@ public:
template <typename Arrangement> template <typename Arrangement>
class Arr_face_point_generator<Arrangement, class Arr_face_point_generator<Arrangement,
std::enable_if_t<is_or_derived_from_agas_v<typename Arrangement::Geometry_traits_2>>> std::enable_if_t<is_or_derived_from_agas_v<typename Arrangement::Geometry_traits_2>>> {
{
using Geom_traits = typename Arrangement::Geometry_traits_2; using Geom_traits = typename Arrangement::Geometry_traits_2;
using Approx_traits = Arr_approximate_traits<Geom_traits>; using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Approx_nt = typename Approx_traits::Approx_nt; using Approx_nt = typename Approx_traits::Approx_nt;
@ -76,8 +74,8 @@ public:
std::vector<Gt_point> points; std::vector<Gt_point> points;
Arr_coordinate_converter<Geom_traits> coords(traits); Arr_coordinate_converter<Geom_traits> coords(traits);
points.reserve(2 * CGAL_PI / cell_size * CGAL_PI / cell_size); points.reserve(2 * CGAL_PI / cell_size * CGAL_PI / cell_size);
for(Approx_nt x = 0; x < 2 * CGAL_PI; x += cell_size) { for (Approx_nt x = 0; x < 2 * CGAL_PI; x += cell_size) {
for(Approx_nt y = 0; y < CGAL_PI; y += cell_size) { for (Approx_nt y = 0; y < CGAL_PI; y += cell_size) {
auto pt = coords.to_cartesian(Point(x, y)); auto pt = coords.to_cartesian(Point(x, y));
points.push_back(traits.construct_point_2_object()(pt.dx(), pt.dy(), pt.dz())); points.push_back(traits.construct_point_2_object()(pt.dx(), pt.dy(), pt.dz()));
} }
@ -86,7 +84,7 @@ public:
unordered_flat_map<Face_const_handle, std::vector<Point>> face_points; unordered_flat_map<Face_const_handle, std::vector<Point>> face_points;
CGAL::locate(arr, points.begin(), points.end(), CGAL::locate(arr, points.begin(), points.end(),
boost::make_function_output_iterator([&face_points, &traits, &coords](const Query_result& res) { boost::make_function_output_iterator([&face_points, &traits, &coords](const Query_result& res) {
if(!std::holds_alternative<Face_const_handle>(res.second)) return; if (! std::holds_alternative<Face_const_handle>(res.second)) return;
Face_const_handle fh = std::get<Face_const_handle>(res.second); Face_const_handle fh = std::get<Face_const_handle>(res.second);
auto [it, _] = face_points.try_emplace(fh, std::vector<Point>()); auto [it, _] = face_points.try_emplace(fh, std::vector<Point>());
it->second.push_back(coords.to_uv(traits.approximate_2_object()(res.first))); it->second.push_back(coords.to_uv(traits.approximate_2_object()(res.first)));

View File

@ -15,6 +15,7 @@
#ifndef CGAL_DRAW_AOS_ARR_RENDER_CONTEXT_H #ifndef CGAL_DRAW_AOS_ARR_RENDER_CONTEXT_H
#define CGAL_DRAW_AOS_ARR_RENDER_CONTEXT_H #define CGAL_DRAW_AOS_ARR_RENDER_CONTEXT_H
#include <cstdlib> #include <cstdlib>
#include <memory> #include <memory>
#include <atomic> #include <atomic>
@ -36,23 +37,22 @@
namespace CGAL { namespace CGAL {
namespace draw_aos { namespace draw_aos {
/** /** @brief A cancellable context mixin for asynchronous operations. It also tracks elapsed time for performance
* @brief A cancellable context mixin for asynchronous operations. It also tracks elapsed time for performance
* profiling. * profiling.
* *
* The idea is borrowed from golang with a simple implementation. * The idea is borrowed from golang with a simple implementation.
* @see https://pkg.go.dev/context * @see https://pkg.go.dev/context
*/ */
class Arr_cancellable_context_mixin class Arr_cancellable_context_mixin {
{
using Clock = std::chrono::steady_clock; using Clock = std::chrono::steady_clock;
using Duration = Clock::duration; using Duration = Clock::duration;
using Time_point = std::chrono::time_point<Clock, Duration>; using Time_point = std::chrono::time_point<Clock, Duration>;
protected: protected:
Arr_cancellable_context_mixin() Arr_cancellable_context_mixin() :
: m_start_time(Clock::now()) m_start_time(Clock::now()),
, m_cancelled(std::make_shared<std::atomic<bool>>(false)) {} m_cancelled(std::make_shared<std::atomic<bool>>(false))
{}
public: public:
Time_point start_time() const { return m_start_time; } Time_point start_time() const { return m_start_time; }
@ -70,23 +70,20 @@ private:
std::shared_ptr<std::atomic<bool>> m_cancelled; std::shared_ptr<std::atomic<bool>> m_cancelled;
}; };
/** /** @brief Boundary context mixin for rendering arrangements within a bounding box.
* @brief Boundary context mixin for rendering arrangements within a bounding box.
* Provides extended functionality for checking point-bbox relations. * Provides extended functionality for checking point-bbox relations.
* *
* @tparam GeomTraits the geometry traits class. * @tparam GeomTraits the geometry traits class.
*/ */
template <typename GeomTraits> template <typename GeomTraits>
class Arr_bounds_context_mixin class Arr_bounds_context_mixin {
{
using Geom_traits = GeomTraits; using Geom_traits = GeomTraits;
using Approx_traits = Arr_approximate_traits<Geom_traits>; using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Point = typename Approx_traits::Point; using Point = typename Approx_traits::Point;
using Approx_nt = typename Approx_traits::Approx_nt; using Approx_nt = typename Approx_traits::Approx_nt;
protected: protected:
Arr_bounds_context_mixin(const Bbox_2& bbox) Arr_bounds_context_mixin(const Bbox_2& bbox) : m_bbox(bbox) {}
: m_bbox(bbox) {}
public: public:
double xmin() const { return m_bbox.xmin(); } double xmin() const { return m_bbox.xmin(); }
@ -118,22 +115,22 @@ template <typename GeomTraits>
using Arr_parameterization_context_mixin = Arr_coordinate_converter<GeomTraits>; using Arr_parameterization_context_mixin = Arr_coordinate_converter<GeomTraits>;
template <typename Arrangement> template <typename Arrangement>
class Arr_render_context : public Arr_cancellable_context_mixin, class Arr_render_context :
public Arr_parameterization_context_mixin<typename Arrangement::Geometry_traits_2> public Arr_cancellable_context_mixin,
{ public Arr_parameterization_context_mixin<typename Arrangement::Geometry_traits_2> {
using Cancellable_context_mixin = Arr_cancellable_context_mixin; using Cancellable_context_mixin = Arr_cancellable_context_mixin;
using Param_context_mixin = Arr_parameterization_context_mixin<typename Arrangement::Geometry_traits_2>; using Param_context_mixin = Arr_parameterization_context_mixin<typename Arrangement::Geometry_traits_2>;
using Geom_traits = typename Arrangement::Geometry_traits_2; using Geom_traits = typename Arrangement::Geometry_traits_2;
using Face_points_map = typename Arr_face_point_generator<Arrangement>::Face_points_map; using Face_points_map = typename Arr_face_point_generator<Arrangement>::Face_points_map;
public: public:
Arr_render_context(const Arrangement& arr, double approx_error, Face_points_map& face_points) Arr_render_context(const Arrangement& arr, double approx_error, Face_points_map& face_points) :
: Cancellable_context_mixin() Cancellable_context_mixin(),
, Param_context_mixin(*arr.geometry_traits()) Param_context_mixin(*arr.geometry_traits()),
, m_arr(arr) m_arr(arr),
, m_traits(*arr.geometry_traits()) m_traits(*arr.geometry_traits()),
, m_approx_error(approx_error) m_approx_error(approx_error),
, m_face_points(face_points) { m_face_points(face_points) {
#if defined(CGAL_DRAW_AOS_DEBUG) && defined(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR) #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); std::filesystem::path debug_file_dir(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR);
// clear the index file. // clear the index file.
@ -142,9 +139,9 @@ public:
} }
public: public:
const double m_approx_error;
const Arrangement& m_arr; const Arrangement& m_arr;
const Geom_traits& m_traits; const Geom_traits& m_traits;
const double m_approx_error;
const Face_points_map& m_face_points; const Face_points_map& m_face_points;
#if defined(CGAL_DRAW_AOS_DEBUG) #if defined(CGAL_DRAW_AOS_DEBUG)
@ -153,9 +150,9 @@ public:
}; };
template <typename Arrangement> template <typename Arrangement>
class Arr_bounded_render_context : public Arr_render_context<Arrangement>, class Arr_bounded_render_context :
public Arr_bounds_context_mixin<typename Arrangement::Geometry_traits_2> public Arr_render_context<Arrangement>,
{ public Arr_bounds_context_mixin<typename Arrangement::Geometry_traits_2> {
using Geom_traits = typename Arrangement::Geometry_traits_2; using Geom_traits = typename Arrangement::Geometry_traits_2;
using Approx_point = typename Geom_traits::Approximate_point_2; using Approx_point = typename Geom_traits::Approximate_point_2;
using Render_context = Arr_render_context<Arrangement>; using Render_context = Arr_render_context<Arrangement>;
@ -163,10 +160,11 @@ class Arr_bounded_render_context : public Arr_render_context<Arrangement>,
using Approx_cache = Arr_approximation_cache<Arrangement>; using Approx_cache = Arr_approximation_cache<Arrangement>;
public: public:
Arr_bounded_render_context(const Render_context& ctx, const Bbox_2& bbox, Approx_cache& cache) Arr_bounded_render_context(const Render_context& ctx, const Bbox_2& bbox, Approx_cache& cache) :
: Render_context(ctx) Render_context(ctx),
, Bounds_context_mixin(bbox) Bounds_context_mixin(bbox),
, m_cache(cache) {} m_cache(cache)
{}
public: public:
Approx_cache& m_cache; Approx_cache& m_cache;
@ -174,4 +172,5 @@ public:
} // namespace draw_aos } // namespace draw_aos
} // namespace CGAL } // namespace CGAL
#endif #endif

View File

@ -21,12 +21,7 @@
#include <cstdlib> #include <cstdlib>
#include <type_traits> #include <type_traits>
#include <QtWidgets/QApplication> #include <QWidget>
#include <QtWidgets/QWidget>
#include <QtOpenGLWidgets/QtOpenGLWidgets>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QMouseEvent>
#include <QtGui/QKeyEvent>
#include <CGAL/Qt/Basic_viewer.h> #include <CGAL/Qt/Basic_viewer.h>
#include <CGAL/Qt/camera.h> #include <CGAL/Qt/camera.h>
@ -48,8 +43,7 @@
namespace CGAL { namespace CGAL {
namespace draw_aos { namespace draw_aos {
/*! /*! \brief Viewport helper functions
* \brief Viewport helper functions
* *
* \tparam Arrangement * \tparam Arrangement
*/ */
@ -58,10 +52,9 @@ class Arr_viewport_helpers;
// Specialization for planar arrangements // Specialization for planar arrangements
template <typename Arrangement> template <typename Arrangement>
class Arr_viewport_helpers< class Arr_viewport_helpers<Arrangement,
Arrangement, std::enable_if_t<! is_or_derived_from_curved_surf_traits_v
std::enable_if_t<!is_or_derived_from_curved_surf_traits_v<typename Arrangement::Geometry_traits_2>>> <typename Arrangement::Geometry_traits_2>>> {
{
using Geom_traits = typename Arrangement::Geometry_traits_2; using Geom_traits = typename Arrangement::Geometry_traits_2;
using Approx_traits = Arr_approximate_traits<Geom_traits>; using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Approx_point = typename Approx_traits::Approx_point; using Approx_point = typename Approx_traits::Approx_point;
@ -70,22 +63,18 @@ class Arr_viewport_helpers<
using Local_point = Buffer_for_vao::Local_point; using Local_point = Buffer_for_vao::Local_point;
protected: protected:
Arr_viewport_helpers(const Arrangement& arr) Arr_viewport_helpers(const Arrangement& arr) : m_arr(arr) {}
: m_arr(arr) {}
/*! /*! \brief Computes a subpixel-level approximation error based on the bounding box and viewport width.
* \brief Computes a subpixel-level approximation error based on the bounding box and viewport width.
* *
* \param bbox * \param bbox
* \param viewport_width width of the viewport in pixels * \param viewport_width width of the viewport in pixels
* \return double * \return double
*/ */
double approximation_error(const Bbox_2& bbox, int viewport_width) const { double approximation_error(const Bbox_2& bbox, int viewport_width) const
return bbox.x_span() / viewport_width; { return bbox.x_span() / viewport_width; }
}
/*! /*! \brief Computes a parameter space bounding box that contains everything in the arrangement with some margin.
* \brief Computes a parameter space bounding box that contains everything in the arrangement with some margin.
* *
* \note For arrangement induced by unbounded curves, the bounding box only fits all vertices. * \note For arrangement induced by unbounded curves, the bounding box only fits all vertices.
* \return Bbox_2 * \return Bbox_2
@ -94,28 +83,27 @@ protected:
const auto& traits = *m_arr.geometry_traits(); const auto& traits = *m_arr.geometry_traits();
Bbox_2 bbox; Bbox_2 bbox;
// Computes a rough bounding box from the vertices. // Computes a rough bounding box from the vertices.
for(const auto& vh : m_arr.vertex_handles()) { for (const auto& vh : m_arr.vertex_handles())
bbox += traits.approximate_2_object()(vh->point()).bbox(); bbox += traits.approximate_2_object()(vh->point()).bbox();
}
double approx_error = approximation_error(bbox, 100); double approx_error = approximation_error(bbox, 100);
// Computes a more precise bounding box from the halfedges. // Computes a more precise bounding box from the halfedges.
for(const auto& he : m_arr.halfedge_handles()) { auto approx = traits.approximate_2_object();
traits.approximate_2_object()( for (const auto& he : m_arr.halfedge_handles()) {
he->curve(), approx_error, approx(he->curve(), approx_error,
boost::make_function_output_iterator([this, &bbox](Approx_point pt) { bbox += pt.bbox(); })); boost::make_function_output_iterator([&bbox](Approx_point pt) { bbox += pt.bbox(); }));
} }
// Place margin around the bbox. // Place margin around the bbox.
double dx = bbox.x_span() * 0.1; double dx = bbox.x_span() * 0.1;
double dy = bbox.y_span() * 0.1; double dy = bbox.y_span() * 0.1;
bbox = Bbox_2(bbox.xmin() - dx, bbox.ymin() - dy, bbox.xmax() + dx, bbox.ymax() + dy); bbox = Bbox_2(bbox.xmin() - dx, bbox.ymin() - dy, bbox.xmax() + dx, bbox.ymax() + dy);
// Make sure the bbox is not degenerate. // Make sure the bbox is not degenerate.
if(bbox.x_span() == 0) bbox += Bbox_2(bbox.xmin() - 1, bbox.ymin(), bbox.xmax() + 1, bbox.ymax()); if (bbox.x_span() == 0) bbox += Bbox_2(bbox.xmin() - 1, bbox.ymin(), bbox.xmax() + 1, bbox.ymax());
if(bbox.y_span() == 0) bbox += Bbox_2(bbox.xmin(), bbox.ymin() - 1, bbox.xmax(), bbox.ymax() + 1); if (bbox.y_span() == 0) bbox += Bbox_2(bbox.xmin(), bbox.ymin() - 1, bbox.xmax(), bbox.ymax() + 1);
return bbox; return bbox;
} }
/*! /*! \brief Fits the camera to bbox.
* \brief Fits the camera to bbox.
* *
* \param bbox * \param bbox
* \param camera * \param camera
@ -125,8 +113,7 @@ protected:
cam.fitBoundingBox(Vec(bbox.xmin(), bbox.ymin(), 0.0), Vec(bbox.xmax(), bbox.ymax(), 0.0)); cam.fitBoundingBox(Vec(bbox.xmin(), bbox.ymin(), 0.0), Vec(bbox.xmax(), bbox.ymax(), 0.0));
} }
/*! /*! \brief Computes parameter space axis aligned bounding box from camera parameters.
* \brief Computes parameter space axis aligned bounding box from camera parameters.
* *
* \param cam * \param cam
* \return Bbox_2 * \return Bbox_2
@ -142,9 +129,9 @@ protected:
double xmax = std::numeric_limits<double>::lowest(); double xmax = std::numeric_limits<double>::lowest();
double ymin = std::numeric_limits<double>::max(); double ymin = std::numeric_limits<double>::max();
double ymax = std::numeric_limits<double>::lowest(); 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; 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 x = world.x();
double y = world.y(); double y = world.y();
xmin = std::min(xmin, x); xmin = std::min(xmin, x);
@ -155,8 +142,7 @@ protected:
return Bbox_2(xmin, ymin, xmax, ymax); return Bbox_2(xmin, ymin, xmax, ymax);
} }
/*! /*! \brief Converts a parameter space point to a local point of the buffer object.
* \brief Converts a parameter space point to a local point of the buffer object.
* *
* \param pt * \param pt
* \return Local_point * \return Local_point
@ -170,8 +156,7 @@ private:
// Spherical arrangement specialization // Spherical arrangement specialization
template <typename Arrangement> template <typename Arrangement>
class Arr_viewport_helpers<Arrangement, class Arr_viewport_helpers<Arrangement,
std::enable_if_t<is_or_derived_from_agas_v<typename Arrangement::Geometry_traits_2>>> std::enable_if_t<is_or_derived_from_agas_v<typename Arrangement::Geometry_traits_2>>> {
{
using Geom_traits = typename Arrangement::Geometry_traits_2; using Geom_traits = typename Arrangement::Geometry_traits_2;
using Approx_traits = Arr_approximate_traits<Geom_traits>; using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Approx_point = typename Approx_traits::Approx_point; using Approx_point = typename Approx_traits::Approx_point;
@ -180,8 +165,7 @@ class Arr_viewport_helpers<Arrangement,
using Local_point = Buffer_for_vao::Local_point; using Local_point = Buffer_for_vao::Local_point;
protected: protected:
Arr_viewport_helpers(const Arrangement& arr) Arr_viewport_helpers(const Arrangement& arr) : m_arr(arr) {}
: m_arr(arr) {}
Bbox_2 arr_bbox() const { return Bbox_2(0, 0, 2 * CGAL_PI, CGAL_PI); } Bbox_2 arr_bbox() const { return Bbox_2(0, 0, 2 * CGAL_PI, CGAL_PI); }
@ -195,10 +179,10 @@ protected:
double approximation_error(const Bbox_2& bbox, int viewport_width) const { double approximation_error(const Bbox_2& bbox, int viewport_width) const {
// If crossing hemisphere // If crossing hemisphere
if(bbox.x_span() >= CGAL_PI) return 1.0 / viewport_width; if (bbox.x_span() >= CGAL_PI) return 1.0 / viewport_width;
// Otherwise we evalute the error bound with respect to the longest longitude arc // Otherwise we evalute the error bound with respect to the longest longitude arc
double theta = double theta =
std::abs(bbox.ymin() - CGAL_PI / 2.0) < std::abs(bbox.ymax() - CGAL_PI / 2.0) ? bbox.ymin() : bbox.ymax(); std::abs(bbox.ymin() - CGAL_PI / 2.0) < std::abs(bbox.ymax() - CGAL_PI / 2.0) ? bbox.ymin() : bbox.ymax();
return bbox.x_span() * std::sin(theta) / viewport_width; return bbox.x_span() * std::sin(theta) / viewport_width;
} }
@ -217,8 +201,7 @@ private:
* \tparam GSOptions * \tparam GSOptions
*/ */
template <typename Arrangement, typename GSOptions> template <typename Arrangement, typename GSOptions>
class Arr_viewer : public Qt::Basic_viewer, Arr_viewport_helpers<Arrangement> class Arr_viewer : public Qt::Basic_viewer, Arr_viewport_helpers<Arrangement> {
{
using Basic_viewer = Qt::Basic_viewer; using Basic_viewer = Qt::Basic_viewer;
using Helpers = Arr_viewport_helpers<Arrangement>; using Helpers = Arr_viewport_helpers<Arrangement>;
using Vertex_const_handle = typename Arrangement::Vertex_const_handle; using Vertex_const_handle = typename Arrangement::Vertex_const_handle;
@ -231,11 +214,10 @@ class Arr_viewer : public Qt::Basic_viewer, Arr_viewport_helpers<Arrangement>
using Point_generator = Arr_face_point_generator<Arrangement>; using Point_generator = Arr_face_point_generator<Arrangement>;
using Faces_point_map = typename Point_generator::Face_points_map; using Faces_point_map = typename Point_generator::Face_points_map;
struct Render_params struct Render_params {
{ bool operator==(const Render_params& other) const
bool operator==(const Render_params& other) const { { return bbox == other.bbox && approx_error == other.approx_error; }
return bbox == other.bbox && approx_error == other.approx_error;
}
Bbox_2 bbox; Bbox_2 bbox;
double approx_error{0}; double approx_error{0};
}; };
@ -243,9 +225,8 @@ class Arr_viewer : public Qt::Basic_viewer, Arr_viewport_helpers<Arrangement>
constexpr static bool Is_on_curved_surface = is_or_derived_from_curved_surf_traits_v<Geom_traits>; constexpr static bool Is_on_curved_surface = is_or_derived_from_curved_surf_traits_v<Geom_traits>;
private: private:
static bool contains(const Bbox_2& bbox, const Point& pt) { static bool contains(const Bbox_2& bbox, const Point& pt)
return bbox.xmin() <= pt.x() && pt.x() <= bbox.xmax() && bbox.ymin() <= pt.y() && pt.y() <= bbox.ymax(); { return bbox.xmin() <= pt.x() && pt.x() <= bbox.xmax() && bbox.ymin() <= pt.y() && pt.y() <= bbox.ymax(); }
}
int viewport_width() const { int viewport_width() const {
std::array<GLint, 4> viewport; std::array<GLint, 4> viewport;
@ -268,56 +249,53 @@ private:
auto cache = renderer.render(); auto cache = renderer.render();
// add faces // add faces
for(const auto& [fh, tf] : cache.faces()) { for (const auto& [fh, tf] : cache.faces()) {
if(!m_gso.draw_face(m_arr, fh)) continue; if (! m_gso.draw_face(m_arr, fh)) continue;
bool colored_face = m_gso.colored_face(m_arr, fh); bool colored_face = m_gso.colored_face(m_arr, fh);
auto color = colored_face ? m_gso.face_color(m_arr, fh) : CGAL::IO::Color(); auto color = colored_face ? m_gso.face_color(m_arr, fh) : CGAL::IO::Color();
for(const auto& tri : tf.triangles) { for (const auto& tri : tf.triangles) {
if(colored_face) if (colored_face) m_gs.face_begin(color);
m_gs.face_begin(color); else m_gs.face_begin();
else for (const auto i : tri) m_gs.add_point_in_face(this->to_local_point(tf.points[i]));
m_gs.face_begin();
for(const auto i : tri) m_gs.add_point_in_face(this->to_local_point(tf.points[i]));
m_gs.face_end(); m_gs.face_end();
} }
} }
// add edges // add edges
for(const auto& [he, polyline] : cache.halfedges()) { for (const auto& [he, polyline] : cache.halfedges()) {
if(he->direction() == ARR_RIGHT_TO_LEFT || !m_gso.draw_edge(m_arr, he) || polyline.size() < 2) continue; if (he->direction() == ARR_RIGHT_TO_LEFT || !m_gso.draw_edge(m_arr, he) || polyline.size() < 2) continue;
bool colored_edge = m_gso.colored_edge(m_arr, he); bool colored_edge = m_gso.colored_edge(m_arr, he);
auto color = colored_edge ? m_gso.edge_color(m_arr, he) : CGAL::IO::Color(); auto color = colored_edge ? m_gso.edge_color(m_arr, he) : CGAL::IO::Color();
// skip first two if starts with a sep point. // skip first two if starts with a sep point.
int start_idx = Approx_traits::is_null(polyline.front()) ? 2 : 0; int start_idx = Approx_traits::is_null(polyline.front()) ? 2 : 0;
// skip last two if ends with a sep point. // skip last two if ends with a sep point.
int end_idx = Approx_traits::is_null(polyline.back()) ? polyline.size() - 2 : polyline.size(); int end_idx = Approx_traits::is_null(polyline.back()) ? polyline.size() - 2 : polyline.size();
for(int i = start_idx; i < end_idx - 1; ++i) { for (int i = start_idx; i < end_idx - 1; ++i) {
const auto& src = polyline[i]; const auto& src = polyline[i];
const auto& tgt = polyline[i + 1]; const auto& tgt = polyline[i + 1];
if(Approx_traits::is_null(src) || Approx_traits::is_null(tgt)) continue; if (Approx_traits::is_null(src) || Approx_traits::is_null(tgt)) continue;
if(!contains(bbox, src) || !contains(bbox, tgt)) continue; if (! contains(bbox, src) || !contains(bbox, tgt)) continue;
if(colored_edge) if (colored_edge)
m_gs.add_segment(this->to_local_point(src), this->to_local_point(tgt), color); m_gs.add_segment(this->to_local_point(src), this->to_local_point(tgt), color);
else else
m_gs.add_segment(this->to_local_point(src), this->to_local_point(tgt)); m_gs.add_segment(this->to_local_point(src), this->to_local_point(tgt));
} }
} }
// add vertices // add vertices
for(const auto& [vh, pt] : cache.vertices()) { for (const auto& [vh, pt] : cache.vertices()) {
if(!m_gso.draw_vertex(m_arr, vh) || !contains(bbox, pt)) continue; if (! m_gso.draw_vertex(m_arr, vh) || !contains(bbox, pt)) continue;
if(m_gso.colored_vertex(m_arr, vh)) if (m_gso.colored_vertex(m_arr, vh))
m_gs.add_point(this->to_local_point(pt), m_gso.vertex_color(m_arr, vh)); m_gs.add_point(this->to_local_point(pt), m_gso.vertex_color(m_arr, vh));
else else
m_gs.add_point(this->to_local_point(pt)); m_gs.add_point(this->to_local_point(pt));
} }
} }
/*! /*! \brief Rerender scene within the given bounding box.
* \brief Rerender scene within the given bounding box. *
* \param bbox * \param bbox
*/ */
void rerender(const Render_params& params) { void rerender(const Render_params& params) {
if(params == m_last_params) return; if (params == m_last_params) return;
m_last_params = params; m_last_params = params;
m_gs.clear(); m_gs.clear();
render_arr(params); render_arr(params);
@ -325,13 +303,13 @@ private:
} }
public: public:
Arr_viewer(QWidget* parent, const Arrangement& arr, const GSOptions& gso, const char* title, Bbox_2 initial_bbox) Arr_viewer(QWidget* parent, const Arrangement& arr, const GSOptions& gso, const char* title, Bbox_2 initial_bbox) :
: Basic_viewer(parent, m_gs, title) Basic_viewer(parent, m_gs, title),
, Helpers(arr) Helpers(arr),
, m_gso(gso) m_gso(gso),
, m_arr(arr) m_arr(arr),
, m_coords(*arr.geometry_traits()) { m_coords(*arr.geometry_traits()) {
if(initial_bbox.x_span() == 0 || initial_bbox.y_span() == 0 || Is_on_curved_surface) if ((initial_bbox.x_span() == 0) || (initial_bbox.y_span() == 0) || (Is_on_curved_surface))
m_initial_bbox = this->arr_bbox(); m_initial_bbox = this->arr_bbox();
else else
m_initial_bbox = initial_bbox; m_initial_bbox = initial_bbox;
@ -341,7 +319,7 @@ public:
Render_params params = compute_render_params(); Render_params params = compute_render_params();
#if defined(CGAL_DRAW_AOS_DEBUG) #if defined(CGAL_DRAW_AOS_DEBUG)
if constexpr(!is_or_derived_from_agas_v<Geom_traits>) { if constexpr(! is_or_derived_from_agas_v<Geom_traits>) {
Bbox_2& bbox = params.bbox; Bbox_2& bbox = params.bbox;
double dx = (bbox.xmax() - bbox.xmin()) * 0.1; double dx = (bbox.xmax() - bbox.xmin()) * 0.1;
double dy = (bbox.ymax() - bbox.ymin()) * 0.1; double dy = (bbox.ymax() - bbox.ymin()) * 0.1;
@ -352,7 +330,7 @@ public:
rerender(params); rerender(params);
if(!m_initialized) { if (! m_initialized) {
// The initial render must be done with original camera parameters or the width of edges gets exaggerated. // The initial render must be done with original camera parameters or the width of edges gets exaggerated.
// So we fit the camera after initial render. // So we fit the camera after initial render.
this->fit_camera(m_initial_bbox, *this->camera_); this->fit_camera(m_initial_bbox, *this->camera_);

View File

@ -15,6 +15,7 @@
#ifndef CGAL_DRAW_AOS_TYPE_UTILS_H #ifndef CGAL_DRAW_AOS_TYPE_UTILS_H
#define CGAL_DRAW_AOS_TYPE_UTILS_H #define CGAL_DRAW_AOS_TYPE_UTILS_H
#include <limits> #include <limits>
#include <vector> #include <vector>
#include <type_traits> #include <type_traits>
@ -34,8 +35,7 @@ enum class Boundary_side {
}; };
template <typename, typename = std::void_t<>> template <typename, typename = std::void_t<>>
struct has_approximate_2_object : std::false_type struct has_approximate_2_object : std::false_type {};
{};
template <typename Gt> template <typename Gt>
struct has_approximate_2_object<Gt, std::void_t<decltype(std::declval<Gt>().approximate_2_object())>> : std::true_type struct has_approximate_2_object<Gt, std::void_t<decltype(std::declval<Gt>().approximate_2_object())>> : std::true_type
@ -46,14 +46,13 @@ template <typename Gt>
inline constexpr bool has_approximate_2_object_v = has_approximate_2_object<Gt>::value; inline constexpr bool has_approximate_2_object_v = has_approximate_2_object<Gt>::value;
template <typename, typename, typename = std::void_t<>> template <typename, typename, typename = std::void_t<>>
struct has_approximate_point : std::false_type struct has_approximate_point : std::false_type {};
{};
template <typename Gt, typename A> template <typename Gt, typename A>
struct has_approximate_point<Gt, struct has_approximate_point<Gt,
A, A,
std::void_t<decltype(std::declval<A>()(std::declval<const typename Gt::Point_2&>()))>> std::void_t<decltype(std::declval<A>()(std::declval<const typename Gt::Point_2&>()))>> :
: std::true_type std::true_type
{}; {};
// Detect whether A has operator()(const Gt::Point_2&) // Detect whether A has operator()(const Gt::Point_2&)
@ -61,18 +60,17 @@ template <typename Gt, typename A>
inline constexpr bool has_approximate_point_v = has_approximate_point<Gt, A>::value; inline constexpr bool has_approximate_point_v = has_approximate_point<Gt, A>::value;
template <typename, typename, typename, typename = std::void_t<>> template <typename, typename, typename, typename = std::void_t<>>
struct has_approximate_xcv : std::false_type struct has_approximate_xcv : std::false_type {};
{};
template <typename Gt, typename A, typename O> template <typename Gt, typename A, typename O>
struct has_approximate_xcv< struct has_approximate_xcv
Gt, <Gt,
A, A,
O, O,
std::void_t<decltype(std::declval<A&>()(std::declval<const typename Gt::X_monotone_curve_2&>(), std::void_t<decltype(std::declval<A&>()(std::declval<const typename Gt::X_monotone_curve_2&>(),
std::declval<double>(), std::declval<double>(),
std::declval<O>(), std::declval<O>(),
std::declval<bool>()))>> : std::true_type std::declval<bool>()))>> : std::true_type
{}; {};
// Detect whether A has operator()(const Gt::X_monotone_curve_2&, double, OutputIterator, bool)? // Detect whether A has operator()(const Gt::X_monotone_curve_2&, double, OutputIterator, bool)?
@ -84,15 +82,15 @@ struct has_approximate_xcv_with_bounds : std::false_type
{}; {};
template <typename Gt, typename A, typename O> template <typename Gt, typename A, typename O>
struct has_approximate_xcv_with_bounds< struct has_approximate_xcv_with_bounds
Gt, <Gt,
A, A,
O, O,
std::void_t<decltype(std::declval<A&>()(std::declval<const typename Gt::X_monotone_curve_2&>(), std::void_t<decltype(std::declval<A&>()(std::declval<const typename Gt::X_monotone_curve_2&>(),
std::declval<double>(), std::declval<double>(),
std::declval<O>(), std::declval<O>(),
std::declval<Bbox_2>(), std::declval<Bbox_2>(),
std::declval<bool>()))>> : std::true_type std::declval<bool>()))>> : std::true_type
{}; {};
// Detect whether A has operator()(const X_monotone_curve&, double, OutputIterator, Bbox_2, bool) // Detect whether A has operator()(const X_monotone_curve&, double, OutputIterator, Bbox_2, bool)
@ -102,9 +100,9 @@ inline constexpr bool has_approximate_xcv_with_bounds_v = has_approximate_xcv_wi
// Detect whether a geometry traits has all the necessary types and functions for approximation // Detect whether a geometry traits has all the necessary types and functions for approximation
template <typename Gt> template <typename Gt>
constexpr bool has_approximate_traits_v = constexpr bool has_approximate_traits_v =
has_approximate_2_object_v<Gt> && has_approximate_point_v<Gt, typename Gt::Approximate_2> && has_approximate_2_object_v<Gt> && has_approximate_point_v<Gt, typename Gt::Approximate_2> &&
(has_approximate_xcv_v<Gt, typename Gt::Approximate_2> || (has_approximate_xcv_v<Gt, typename Gt::Approximate_2> ||
has_approximate_xcv_with_bounds_v<Gt, typename Gt::Approximate_2>); has_approximate_xcv_with_bounds_v<Gt, typename Gt::Approximate_2>);
template <typename Gt, typename = std::void_t<>> template <typename Gt, typename = std::void_t<>>
struct has_is_in_x_range : std::false_type struct has_is_in_x_range : std::false_type
@ -112,8 +110,8 @@ struct has_is_in_x_range : std::false_type
template <typename Gt> template <typename Gt>
struct has_is_in_x_range<Gt, struct has_is_in_x_range<Gt,
std::void_t<decltype(std::declval<typename Gt::X_monotone_curve_2>().is_in_x_range( std::void_t<decltype(std::declval<typename Gt::X_monotone_curve_2>().is_in_x_range
std::declval<const typename Gt::Point_2&>()))>> : std::true_type (std::declval<const typename Gt::Point_2&>()))>> : std::true_type
{}; {};
// Detect whether Gt::X_monotone_curve_2 has a member function bool is_in_x_range(const Gt::Point_2&) // Detect whether Gt::X_monotone_curve_2 has a member function bool is_in_x_range(const Gt::Point_2&)
@ -122,8 +120,7 @@ inline constexpr bool has_is_in_x_range_v = has_is_in_x_range<Gt>::value;
// Detect whether Gt is or derives from Arr_geodesic_arc_on_sphere_traits_2<*, *, *> // Detect whether Gt is or derives from Arr_geodesic_arc_on_sphere_traits_2<*, *, *>
template <typename Gt> template <typename Gt>
struct is_or_derived_from_agas struct is_or_derived_from_agas {
{
private: private:
template <typename Kernel_, int AtanX, int AtanY> template <typename Kernel_, int AtanX, int AtanY>
static std::true_type test(const Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY>*); static std::true_type test(const Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY>*);
@ -143,30 +140,25 @@ inline constexpr bool is_or_derived_from_curved_surf_traits_v = is_or_derived_fr
// Static helpers to get template arguments from a geometry traits // Static helpers to get template arguments from a geometry traits
template <typename Gt> template <typename Gt>
struct tmpl_args struct tmpl_args {};
{};
template <typename Kernel_, int AtanX, int AtanY> template <typename Kernel_, int AtanX, int AtanY>
struct tmpl_args<Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY>> struct tmpl_args<Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY>> {
{
using Kernel = Kernel_; using Kernel = Kernel_;
static constexpr int atan_x = AtanX; static constexpr int atan_x = AtanX;
static constexpr int atan_y = AtanY; static constexpr int atan_y = AtanY;
}; };
/*! /*! \brief Approximation data types
* \brief Approximation data types
* *
* \tparam Gt Geometry traits * \tparam Gt Geometry traits
*/ */
template <typename Gt> template <typename Gt>
class Arr_approximate_traits class Arr_approximate_traits {
{
using Geom_traits = Gt; using Geom_traits = Gt;
template <typename P, typename I> template <typename P, typename I>
struct Triangle_soup_ struct Triangle_soup_ {
{
using Index = I; using Index = I;
using Triangle = std::array<Index, 3>; using Triangle = std::array<Index, 3>;
using Point = P; using Point = P;
@ -198,8 +190,7 @@ public:
* \tparam Gt Geometry traits * \tparam Gt Geometry traits
*/ */
template <typename Gt> template <typename Gt>
class Construct_gt_point_2 class Construct_gt_point_2 {
{
using Approx_traits = Arr_approximate_traits<Gt>; using Approx_traits = Arr_approximate_traits<Gt>;
using Approx_point = typename Approx_traits::Approx_point; using Approx_point = typename Approx_traits::Approx_point;
using Gt_point = typename Gt::Point_2; using Gt_point = typename Gt::Point_2;
@ -210,8 +201,7 @@ public:
// Specialization for Arr_geodesic_arc_on_sphere_traits_2 // Specialization for Arr_geodesic_arc_on_sphere_traits_2
template <typename Kernel, int AtanX, int AtanY> template <typename Kernel, int AtanX, int AtanY>
class Construct_gt_point_2<Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>> class Construct_gt_point_2<Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>> {
{
using Geom_traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>; using Geom_traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>;
using Approx_traits = Arr_approximate_traits<Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>>; using Approx_traits = Arr_approximate_traits<Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>>;
using Approx_point = typename Approx_traits::Approx_point; using Approx_point = typename Approx_traits::Approx_point;
@ -220,7 +210,8 @@ class Construct_gt_point_2<Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, At
public: public:
Gt_point operator()(const Approx_point& pt) const { Gt_point operator()(const Approx_point& pt) const {
using Direction_3 = typename Kernel::Direction_3; using Direction_3 = typename Kernel::Direction_3;
return Gt_point(Direction_3(pt.dx(), pt.dy(), pt.dz()), static_cast<typename Gt_point::Location_type>(pt.location())); return Gt_point(Direction_3(pt.dx(), pt.dy(), pt.dz()),
static_cast<typename Gt_point::Location_type>(pt.location()));
} }
}; };

View File

@ -26,6 +26,8 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include <QApplication>
#include <CGAL/Arr_geodesic_arc_on_sphere_traits_2.h> #include <CGAL/Arr_geodesic_arc_on_sphere_traits_2.h>
#include <CGAL/Arrangement_2.h> #include <CGAL/Arrangement_2.h>
#include <CGAL/Arrangement_on_surface_2.h> #include <CGAL/Arrangement_on_surface_2.h>
@ -132,29 +134,24 @@ public:
//! //!
template <typename T, typename A, std::enable_if_t<!has_approximate_point_v<T, A>, int> = 0> template <typename T, typename A, std::enable_if_t<!has_approximate_point_v<T, A>, int> = 0>
void draw_region_impl2(const T& /* traits */, const A& /* approximate */, Halfedge_const_handle curr) { void draw_region_impl2(const T& /* traits */, const A& /* approximate */, Halfedge_const_handle curr)
draw_exact_region(curr); { draw_exact_region(curr); }
}
//! //!
template <typename T, typename A, std::enable_if_t<has_approximate_point_v<T, A>, int> = 0> template <typename T, typename A, std::enable_if_t<has_approximate_point_v<T, A>, int> = 0>
auto draw_region_impl2(const T& /* traits */, const A& approx, Halfedge_const_handle curr) { auto draw_region_impl2(const T& /* traits */, const A& approx, Halfedge_const_handle curr)
draw_approximate_region(curr, approx); { draw_approximate_region(curr, approx); }
}
/*! draws a region, where the traits does not has approximate_2_object. /*! draws a region, where the traits does not has approximate_2_object.
*/ */
template <typename T, std::enable_if_t<!has_approximate_2_object_v<T> && !is_or_derived_from_agas_v<T>, int> = 0> template <typename T, std::enable_if_t<!has_approximate_2_object_v<T> && !is_or_derived_from_agas_v<T>, int> = 0>
void draw_region_impl1(const T& /* traits */, Halfedge_const_handle curr) { void draw_region_impl1(const T& /* traits */, Halfedge_const_handle curr)
draw_exact_region(curr); { draw_exact_region(curr); }
}
/// ///
template <typename T, std::enable_if_t<has_approximate_2_object_v<T> && !is_or_derived_from_agas_v<T>, int> = 0> template <typename T, std::enable_if_t<has_approximate_2_object_v<T> && !is_or_derived_from_agas_v<T>, int> = 0>
auto draw_region_impl1(const T& traits, Halfedge_const_handle curr) { auto draw_region_impl1(const T& traits, Halfedge_const_handle curr)
using Approximate = typename Gt::Approximate_2; { draw_region_impl2(traits, traits.approximate_2_object(), curr); }
draw_region_impl2(traits, traits.approximate_2_object(), curr);
}
/*! draws a geodesic region /*! draws a geodesic region
*/ */
@ -191,10 +188,8 @@ public:
auto ctr_min = traits->construct_min_vertex_2_object(); auto ctr_min = traits->construct_min_vertex_2_object();
auto ctr_max = traits->construct_max_vertex_2_object(); auto ctr_max = traits->construct_max_vertex_2_object();
m_gs.add_segment(ctr_min(curve), ctr_max(curve)); m_gs.add_segment(ctr_min(curve), ctr_max(curve));
if (colored) if (colored) m_gs.add_segment(ctr_min(curve), ctr_max(curve), c);
m_gs.add_segment(ctr_min(curve), ctr_max(curve), c); else m_gs.add_segment(ctr_min(curve), ctr_max(curve));
else
m_gs.add_segment(ctr_min(curve), ctr_max(curve));
} }
/*! draws a region in an exact manner. /*! draws a region in an exact manner.
@ -204,9 +199,8 @@ public:
//! Add all faces. //! Add all faces.
template <typename Traits> template <typename Traits>
void add_faces(const Traits&) { void add_faces(const Traits&)
for (auto it = m_aos.unbounded_faces_begin(); it != m_aos.unbounded_faces_end(); ++it) add_face(it); { for (auto it = m_aos.unbounded_faces_begin(); it != m_aos.unbounded_faces_end(); ++it) add_face(it); }
}
//! Compile time dispatching //! Compile time dispatching
@ -214,47 +208,39 @@ public:
*/ */
template <typename Approximate> template <typename Approximate>
void draw_approximate_point(const Point& p, const Approximate& approx, bool colored, const CGAL::IO::Color& color) { void draw_approximate_point(const Point& p, const Approximate& approx, bool colored, const CGAL::IO::Color& color) {
if (colored) if (colored) m_gs.add_point(approx(p), color);
m_gs.add_point(approx(p), color); else m_gs.add_point(approx(p));
else
m_gs.add_point(approx(p));
} }
//! //!
void draw_exact_point(const Point& p, bool colored, const CGAL::IO::Color& color) { void draw_exact_point(const Point& p, bool colored, const CGAL::IO::Color& color) {
if (colored) if (colored) m_gs.add_point(p, color);
m_gs.add_point(p, color); else m_gs.add_point(p);
else
m_gs.add_point(p);
} }
//! //!
template <typename T, typename A, std::enable_if_t<!has_approximate_point_v<T, A>, int> = 0> template <typename T, typename A, std::enable_if_t<!has_approximate_point_v<T, A>, int> = 0>
void draw_point_impl2( void draw_point_impl2(const T& /* traits */, const A& /* approximate */, const Point& p, bool colored,
const T& /* traits */, const A& /* approximate */, const Point& p, bool colored, const CGAL::IO::Color& c) { const CGAL::IO::Color& c)
draw_exact_point(p, colored, c); { draw_exact_point(p, colored, c); }
}
//! //!
template <typename T, typename A, std::enable_if_t<has_approximate_point_v<T, A>, int> = 0> template <typename T, typename A, std::enable_if_t<has_approximate_point_v<T, A>, int> = 0>
auto auto
draw_point_impl2(const T& /* traits */, const A& approx, const Point& p, bool colored, const CGAL::IO::Color& c) { draw_point_impl2(const T& /* traits */, const A& approx, const Point& p, bool colored, const CGAL::IO::Color& c)
draw_approximate_point(p, approx, colored, c); { draw_approximate_point(p, approx, colored, c); }
}
/*! draws a point, where the traits does not has approximate_2_object. /*! draws a point, where the traits does not has approximate_2_object.
*/ */
template <typename T, std::enable_if_t<!has_approximate_2_object_v<T> && !is_or_derived_from_agas_v<T>, int> = 0> template <typename T, std::enable_if_t<!has_approximate_2_object_v<T> && !is_or_derived_from_agas_v<T>, int> = 0>
void draw_point_impl1(const T& /* traits */, const Point& p, bool colored, const CGAL::IO::Color& c) { void draw_point_impl1(const T& /* traits */, const Point& p, bool colored, const CGAL::IO::Color& c)
draw_exact_point(p, colored, c); { draw_exact_point(p, colored, c); }
}
/*! draws a point, where the traits does have approximate_2_object. /*! draws a point, where the traits does have approximate_2_object.
*/ */
template <typename T, std::enable_if_t<has_approximate_2_object_v<T> && !is_or_derived_from_agas_v<T>, int> = 0> template <typename T, std::enable_if_t<has_approximate_2_object_v<T> && !is_or_derived_from_agas_v<T>, int> = 0>
auto draw_point_impl1(const T& traits, const Point& p, bool colored, const CGAL::IO::Color& c) { auto draw_point_impl1(const T& traits, const Point& p, bool colored, const CGAL::IO::Color& c)
draw_point_impl2(traits, traits.approximate_2_object(), p, colored, c); { draw_point_impl2(traits, traits.approximate_2_object(), p, colored, c); }
}
/*! draws a geodesic point. /*! draws a geodesic point.
*/ */
@ -271,10 +257,8 @@ public:
auto z = ap.dz(); auto z = ap.dz();
auto l = std::sqrt(x * x + y * y + z * z); auto l = std::sqrt(x * x + y * y + z * z);
Approx_point_3 p3(x / l, y / l, z / l); Approx_point_3 p3(x / l, y / l, z / l);
if (colored) if (colored) m_gs.add_point(p3, color);
m_gs.add_point(p3, color); else m_gs.add_point(p3);
else
m_gs.add_point(p3);
} }
//! draws a point. //! draws a point.
@ -386,10 +370,8 @@ public:
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) if (colored) m_gs.add_segment(*prev, *it, c);
m_gs.add_segment(*prev, *it, c); else m_gs.add_segment(*prev, *it);
else
m_gs.add_segment(*prev, *it);
} }
} }
@ -399,23 +381,20 @@ public:
const A& /* approximate */, const A& /* approximate */,
const X_monotone_curve& xcv, const X_monotone_curve& xcv,
bool colored, bool colored,
const CGAL::IO::Color& c) { const CGAL::IO::Color& c)
draw_exact_curve(xcv, colored, c); { draw_exact_curve(xcv, colored, c); }
}
/// ///
template <typename T, typename A, std::enable_if_t<has_approximate_point_v<T, A>, int> = 0> template <typename T, typename A, std::enable_if_t<has_approximate_point_v<T, A>, int> = 0>
auto draw_curve_impl2( auto draw_curve_impl2(const T& /* traits */, const A& approx, const X_monotone_curve& xcv, bool colored,
const T& /* traits */, const A& approx, const X_monotone_curve& xcv, bool colored, const CGAL::IO::Color& c) { const CGAL::IO::Color& c)
draw_approximate_curve(xcv, approx, colored, c); { draw_approximate_curve(xcv, approx, colored, c); }
}
/*! draws a curve, where the traits does not has approximate_2_object. /*! draws a curve, where the traits does not has approximate_2_object.
*/ */
template <typename T, std::enable_if_t<!has_approximate_2_object_v<T> && !is_or_derived_from_agas_v<T>, int> = 0> template <typename T, std::enable_if_t<!has_approximate_2_object_v<T> && !is_or_derived_from_agas_v<T>, int> = 0>
void draw_curve_impl1(const T& /* traits */, const X_monotone_curve& xcv, bool colored, const CGAL::IO::Color& c) { void draw_curve_impl1(const T& /* traits */, const X_monotone_curve& xcv, bool colored, const CGAL::IO::Color& c)
draw_exact_curve(xcv, colored, c); { draw_exact_curve(xcv, colored, c); }
}
/*! draws a curve, where the traits does have approximate_2_object. /*! draws a curve, where the traits does have approximate_2_object.
*/ */
@ -431,7 +410,6 @@ public:
void draw_curve_impl1(const T& traits, const X_monotone_curve& xcv, bool colored, const CGAL::IO::Color& c) { void draw_curve_impl1(const T& traits, const X_monotone_curve& xcv, bool colored, const CGAL::IO::Color& c) {
// std::cout << "draw_curve (geodesic)\n"; // std::cout << "draw_curve (geodesic)\n";
using Traits = T; using Traits = T;
using Kernel = typename Traits::Kernel;
using Ak = typename Traits::Approximate_kernel; using Ak = typename Traits::Approximate_kernel;
using Ap = typename Traits::Approximate_point_2; using Ap = typename Traits::Approximate_point_2;
using Approx_point_3 = typename Ak::Point_3; using Approx_point_3 = typename Ak::Point_3;
@ -452,10 +430,8 @@ public:
auto z = it->dz(); auto z = it->dz();
auto l = std::sqrt(x * x + y * y + z * z); auto l = std::sqrt(x * x + y * y + z * z);
Approx_point_3 next(x / l, y / l, z / l); Approx_point_3 next(x / l, y / l, z / l);
if (colored) if (colored) m_gs.add_segment(prev, next, c);
m_gs.add_segment(prev, next, c); else m_gs.add_segment(prev, next);
else
m_gs.add_segment(prev, next);
prev = next; prev = next;
} }
} }
@ -535,11 +511,10 @@ protected:
m_halfedge_map[e->twin()] = Halfedge_const_handle(); // twin is created as well m_halfedge_map[e->twin()] = Halfedge_const_handle(); // twin is created as well
} }
virtual void before_split_edge(Halfedge_handle e, Vertex_handle v, virtual void before_split_edge(Halfedge_handle /* e */, Vertex_handle v,
const X_monotone_curve_2& c1, const X_monotone_curve_2& /* c1 */,
const X_monotone_curve_2& c2) override { const X_monotone_curve_2& /* c2 */) override
if (m_vertex_map.find(v) == m_vertex_map.end()) m_vertex_map[v] = Vertex_const_handle(); // v is newly created { if (m_vertex_map.find(v) == m_vertex_map.end()) m_vertex_map[v] = Vertex_const_handle(); }
}
virtual void after_split_edge(Halfedge_handle e1, Halfedge_handle e2) override { virtual void after_split_edge(Halfedge_handle e1, Halfedge_handle e2) override {
if (auto it = m_halfedge_map.find(e1); it == m_halfedge_map.end()) if (auto it = m_halfedge_map.find(e1); it == m_halfedge_map.end())
@ -597,8 +572,7 @@ public:
} }
private: private:
/*! /*! maps tracking the changes between the original arrangement and modified arrangement.
* Maps tracking the changes between the original arrangement and modified arrangement.
* The key is the current feature, and the value is the corresponding feature before modification. * The key is the current feature, and the value is the corresponding feature before modification.
* If there is no entry about a feature, the corresponding feature is itself. * If there is no entry about a feature, the corresponding feature is itself.
* If the value is a invalid handle, it means that the feature is newly created and thus has no corresponding * If the value is a invalid handle, it means that the feature is newly created and thus has no corresponding
@ -774,15 +748,15 @@ void draw(const Arrangement& arr,
gso.enable_vertices(); gso.enable_vertices();
gso.draw_vertex = [](const Arrangement&, const Vertex_const_handle&) { return true; }; gso.draw_vertex = [](const Arrangement&, const Vertex_const_handle&) { return true; };
gso.colored_vertex = [](const Arrangement&, const Vertex_const_handle&) { return true; }; gso.colored_vertex = [](const Arrangement&, const Vertex_const_handle&) { return true; };
gso.vertex_color = [](const Arrangement&, const Vertex_const_handle& vh) -> CGAL::IO::Color { gso.vertex_color = [](const Arrangement&, const Vertex_const_handle& /* vh */) -> CGAL::IO::Color
return CGAL::IO::Color(255, 0, 0); { return CGAL::IO::Color(255, 0, 0); };
};
gso.enable_edges(); gso.enable_edges();
gso.draw_edge = [](const Arrangement&, const Halfedge_const_handle&) { return true; }; gso.draw_edge = [](const Arrangement&, const Halfedge_const_handle&) { return true; };
gso.colored_edge = [](const Arrangement&, const Halfedge_const_handle&) { return true; }; gso.colored_edge = [](const Arrangement&, const Halfedge_const_handle&) { return true; };
gso.edge_color = [](const Arrangement&, const Halfedge_const_handle& heh) -> CGAL::IO::Color { gso.edge_color = [](const Arrangement&, const Halfedge_const_handle& /* heh */) -> CGAL::IO::Color
return CGAL::IO::Color(0, 0, 0); { return CGAL::IO::Color(0, 0, 0); };
};
gso.enable_faces(); gso.enable_faces();
gso.draw_face = [](const Arrangement&, const Face_const_handle&) { return true; }; gso.draw_face = [](const Arrangement&, const Face_const_handle&) { return true; };
gso.colored_face = [](const Arrangement&, const Face_const_handle&) { return true; }; gso.colored_face = [](const Arrangement&, const Face_const_handle&) { return true; };
@ -807,8 +781,8 @@ void add_to_graphics_scene(const CGAL_ARR_TYPE& aos, CGAL::Graphics_scene& graph
template <typename GeometryTraits_2, typename TopologyTraits> template <typename GeometryTraits_2, typename TopologyTraits>
void add_to_graphics_scene(const CGAL_ARR_TYPE& aos, CGAL::Graphics_scene& graphics_scene) { 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, 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> typename CGAL_ARR_TYPE::Halfedge_const_handle,
gso; typename CGAL_ARR_TYPE::Face_const_handle> gso;
// colored face? // colored face?
gso.colored_face = [](const CGAL_ARR_TYPE&, typename CGAL_ARR_TYPE::Face_const_handle) -> bool { return true; }; gso.colored_face = [](const CGAL_ARR_TYPE&, typename CGAL_ARR_TYPE::Face_const_handle) -> bool { return true; };