Merge pull request #9036 from efifogel/Aos_2-approximate_unbounded-efif

Aos 2 approximate unbounded efif
This commit is contained in:
Sébastien Loriot 2025-11-03 09:43:25 +01:00
commit 837939c8ee
16 changed files with 692 additions and 473 deletions

View File

@ -6841,9 +6841,9 @@ arrangement-with-history from a file:
\cgalExample{Arrangement_on_surface_2/io_curve_history.cpp}
\cgalAdvancedBegin
The arrangement package also includes the free functions `write(arr,
os, formatter)` and `read(arr, os, formatter)` that operate on a given
arrangement-with-history instance `arr`. Both functions are
The arrangement package also includes the free functions
`write(arr, os, formatter)` and `read(arr, os, formatter)` that operate
on a given arrangement-with-history instance `arr`. Both functions are
parameterized by a `formatter` object, which defines the I/O
format. The package contains a template called,
`Arr_with_hist_text_formatter<ArranagmentFormatter>`, which extends an
@ -6855,12 +6855,24 @@ and defines a simple textual input/output format.
\subsection arr_ssecarr_io_vis Drawing an Arrangement
<!-- ----------------------------------------------------------------------- -->
An arrangement data structure can be visualized by calling the \link PkgArrangementOnSurface2Draw CGAL::draw<arr>() \endlink function as shown in the following example. This function opens a new window showing the given arrangement. A call to this function is blocking; that is, the program continues execution only after the user closes the window.
An arrangement data structure can be visualized by calling one of the
\link PkgArrangementOnSurface2Draw `CGAL::draw()` \endlink
overloaded template functions. Every variant opens a new window
showing the given arrangement. A call to any \link
PkgArrangementOnSurface2Draw `CGAL::draw()` \endlink function is
blocking; that is, the program continues execution only after the user
closes the window. The most simple variant accepts the arrangement to
draw and an optional string used as the title of the window. In the
following example we exploit a variant that also accepts an object the
type of which is an instance of the class template
`Graphics_scene_options`. It allows us to tune the drawings.
\cgalExample{Arrangement_on_surface_2/draw_arr.cpp}
This function requires `CGAL_Qt6`, and is only available if the macro `CGAL_USE_BASIC_VIEWER` is defined.
Linking with the cmake target `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt6` and add the definition `CGAL_USE_BASIC_VIEWER`.
This function requires `CGAL_Qt6`, and is only available if the macro
`CGAL_USE_BASIC_VIEWER` is defined. Linking with the cmake target
`CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt6` and add the
definition `CGAL_USE_BASIC_VIEWER`.
\cgalFigureBegin{aos_fig-draw_arr,draw_arr.png}
A snapshot of the window created by the program
@ -6868,6 +6880,10 @@ A snapshot of the window created by the program
of 14 vertices, 15 edges, and 3 faces. Notice that the colors are generated at random.
\cgalFigureEnd
Another pair of overloaded \link PkgArrangementOnSurface2Draw
`CGAL::draw()` \endlink functions also accept a bounding box. Each
of these two variants can be ised to draw arrangements induced by
unbounded curves.
<!-- ======================================================================= -->
\section aos_sec-bgl Adapting to Boost Graphs

View File

@ -32,7 +32,7 @@ namespace CGAL {
* same direction as a precondition. Moreover, `Arr_circle_segment_traits_2`
* supports the merging of curves of opposite directions.
*
* \cgalModels{AosTraits_2,AosApproximateTraits_2,AosDirectionalXMonotoneTraits_2}
* \cgalModels{AosTraits_2,AosApproximateTraits_2,AosApproximatePointTraits_2,AosDirectionalXMonotoneTraits_2}
*
*/
template <typename Kernel>

View File

@ -80,7 +80,7 @@ namespace CGAL {
* to have the same direction as a precondition. Moreover, `Arr_conic_traits_2`
* supports the merging of curves of opposite directions.
*
* \cgalModels{AosTraits_2,AosLandmarkTraits_2,AosApproximateTraits_2,AosDirectionalXMonotoneTraits_2}
* \cgalModels{AosTraits_2,AosLandmarkTraits_2,AosApproximateTraits_2,AosApproximatePointTraits_2,AosDirectionalXMonotoneTraits_2}
*
* \cgalHeading{Types}
*/

View File

@ -21,7 +21,7 @@ namespace CGAL {
* we can find out its actual type and convert it to the respective kernel
* object (say, to a `Kernel::Ray_2`).
*
* \cgalModels{AosTraits_2,AosLandmarkTraits_2,AosOpenBoundaryTraits_2}
* \cgalModels{AosTraits_2,AosLandmarkTraits_2,AosOpenBoundaryTraits_2,AosApproximatePointTraits_2,AosApproximateTraits_2,AosApproximateUnboundedTraits_2}
*/
template <typename Kernel>
class Arr_linear_traits_2 {

View File

@ -52,7 +52,7 @@ namespace CGAL {
* same direction as a precondition. Moreover, `Arr_segment_traits_2` supports
* the merging of curves of opposite directions.
*
* \cgalModels{AosTraits_2,AosLandmarkTraits_2,AosApproximateTraits_2,AosDirectionalXMonotoneTraits_2}
* \cgalModels{AosTraits_2,AosLandmarkTraits_2,AosApproximateTraits_2,AosApproximatePointTraits_2,AosDirectionalXMonotoneTraits_2}
*/
template <typename Kernel>
class Arr_segment_traits_2 : public Kernel {

View File

@ -19,6 +19,8 @@
#include <CGAL/Qt/Basic_viewer.h>
#include "CGAL/Bbox_2.h"
#ifdef DOXYGEN_RUNNING
namespace CGAL {
@ -26,8 +28,8 @@ namespace CGAL {
/*! \ingroup PkgArrangementOnSurface2Draw
* The function opens a new window and draws `arr`, an instance of the
* `CGAL::Arrangement_2` class template. Parameters of the drawing are taken
* from the optional graphics scene options parameter.
* `CGAL::Arrangement_on_surface_2` class template. Parameters of the drawing
* are taken from the optional graphics scene options parameter.
*
* A call to this function blocks the execution of the program until the drawing
* window is closed. This function requires `CGAL_Qt6`, and is only available if
@ -35,57 +37,64 @@ namespace CGAL {
* `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt6` and add the definition
* `CGAL_USE_BASIC_VIEWER`.
*
* \tparam GeometryTraits_2 a geometry traits type, a model of a 2D arrangement
* traits concept. At this point it must be an instance of either
* `CGAL::Arr_segment_traits_2` or `CGAL::Arr_conic_traits_2`.
* \tparam Dcel the \dcel type, a model of the `AosDcel` concept.
* \tparam GeometryTraits a geometry traits type, a model of a 2D arrangement
* geometry traits concept. Observe that not all geometery-traits models are
* supported.
*
* \tparam TopologyTraits a topology traits type, a model of the
* `AosTopologyTraits` concept.
*
* \tparam GSOptions a model of `GraphicsSceneOptions` concept.
*
* \param arr the 2D arrangement to draw.
* \param gso the graphics scene options parameter.
* \param bbox a bounding box in parameter space.
* \param gso the graphics scene options.
* \param title the optional title of the window.
*
* \sa `AosDcel`
* \sa `AosTraits_2`
* \sa `AosTopologyTraits`
* \sa `GraphicsSceneOptions`
*/
template <typename GeometryTraits_2, typename Dcel, typename GSOptions>
void draw(const Arrangement_2<GeometryTraits_2, Dcel>& arr,
const GSOptions& gso);
template <typename GeometryTraits, typename TopologyTraits>
void draw(const Arrangement_on_surface_2<GeometryTraits, TopologyTraits>& arr,
const Bbox_2& bbox, const GSOptions& gso,
const char* title = "2D Arrangement on Surface");
/*! \ingroup PkgArrangementOnSurface2Draw
*
* A shortcut to `CGAL::draw(arr, Graphics_scene_options{})`.
* A shortcut to `CGAL::draw(arr, bbox, Graphics_scene_options<Aos,
* Aos::Vertex_const_handle, Aos::Halfedge_const_handle,
* Aos::Face_const_handle>{})`, where `Aos` is
* `Arrangement_on_surface_2<GeometryTraits, TopologyTraits>`.
*/
template <typename GeometryTraits_2, typename Dcel>
void draw(const Arrangement_2<GeometryTraits_2, Dcel>& arr);
template <typename GeometryTraits, typename TopologyTraits>
void draw(const Arrangement_on_surface_2<GeometryTraits, TopologyTraits>& arr,
const Bbox_2& bbox, const char* title = "2D Arrangement on Surface");
/*! \ingroup PkgArrangementOnSurface2Draw
*
* adds the vertices, edges and faces of `arr` into the given graphic scene
* `gs`. Parameters of the cells are taken from the optional graphics scene
* options parameter `gso`. Note that `gs` is not cleared before being filled
* (to enable to draw several data structures in the same basic viewer).
*
* \tparam GeometryTraits_2 a geometry traits type, a model of a 2D arrangement
* traits concept. At this point it must be an instance of either
* `CGAL::Arr_segment_traits_2` or `CGAL::Arr_conic_traits_2`.
* \tparam Dcel the \dcel type, a model of the `AosDcel` concept.
* \tparam GSOptions a model of `GraphicsSceneOptions` concept.
*
* \param arr the 2D arrangement to draw.
* \param gs the graphic scene to fill.
* \param gso the graphics scene options parameter.
* Similar to `CGAL::draw(arr, bbox, gso)`, where the bounding box `bbox` is
* computed to bound all points and curves of the arrangement in parameter
* space.
*/
template <typename GeometryTraits_2, typename Dcel, typename GSOptions>
void add_to_graphics_scene(const Arrangement_2<GeometryTraits_2, Dcel>& arr,
CGAL::Graphics_scene& gs, const GSOptions& gso);
template <typename GeometryTraits, typename TopologyTraits>
void draw(const Arrangement_on_surface_2<GeometryTraits, TopologyTraits>& arr,
const GSOptions& gso, const char* title = "2D Arrangement on Surface");
/*! \ingroup PkgArrangementOnSurface2Draw
* A shortcut to `CGAL::add_to_graphics_scene(arr, gs,
* Graphics_scene_options{})`.
*
* A shortcut to `CGAL::draw(arr, Graphics_scene_options<Aos,
* Aos::Vertex_const_handle, Aos::Halfedge_const_handle,
* Aos::Face_const_handle>{})`, where `Aos` is
* `Arrangement_on_surface_2<GeometryTraits, TopologyTraits>`.
*/
template <typename GeometryTraits_2, typename Dcel>
void add_to_graphics_scene(const Arrangement_2<GeometryTraits_2, Dcel>& arr,
CGAL::Graphics_scene& gs);
template <typename GeometryTraits, typename TopologyTraits>
void draw(const Arrangement_on_surface_2<GeometryTraits, TopologyTraits>& arr,
const char* title = "2D Arrangement on Surface");
} /* namespace CGAL */

View File

@ -18,8 +18,6 @@
* \cgalHasModels{CGAL::Arr_rational_function_traits_2<AlgebraicKernel_d_1>}
* \cgalHasModelsEnd
*
* \sa `AosConstructXMonotoneCurveTraits_2`
* \sa `AosXMonotoneTraits_2`
* \sa `AosTraits_2`
*/
class AosApproximatePointTraits_2 {
@ -35,7 +33,7 @@ public:
/// \name Functor Types
/// @{
/// models the concept `AosTraits::Approximate_2`.
/// models the concept `AosTraits::ApproximatePoint_2`.
typedef unspecified_type Approximate_2;
/// @}

View File

@ -17,7 +17,9 @@
* \cgalHasModelsEnd
*
* \sa `AosApproximatePointTraits_2`
* \sa `draw()`
* \sa `AosConstructXMonotoneCurveTraits_2`
* \sa `AosXMonotoneTraits_2`
* \sa \link PkgArrangementOnSurface2Draw `CGAL::draw()`\endlink
*/
class AosApproximateTraits_2 {
public:

View File

@ -0,0 +1,40 @@
/*! \ingroup PkgArrangementOnSurface2ConceptsTraits
* \cgalConcept
*
* The concept `AosApproximateUnboundedTraits_2` refines the concept
* `AosApproximateTraits_2`. A model of this concept is able to approximate a
* curve constrained to a given bounding box (in addition to the ability to
* approximate a point and a curve without constraints).
*
* \cgalRefines{AosApproximateTraits_2}
*
* \cgalHasModelsBegin
* \cgalHasModels{CGAL::Arr_linear_traits_2<Kernel>}
* \cgalHasModelsEnd
*
* \sa `AosApproximateTraits_2`
* \sa \link PkgArrangementOnSurface2Draw `CGAL::draw()`\endlink
*/
class AosApproximateUnboundedTraits_2 {
public:
/// \name Types
/// @{
/// @}
/// \name Functor Types
/// @{
/// models the concept `AosTraits::ApproximateUnbounded_2`.
typedef unspecified_type Approximate_2;
/// @}
/// \name Accessing Functor Objects
/// @{
///
Approximate_2 approximate_2_object() const;
/// @}
}

View File

@ -0,0 +1,28 @@
namespace AosTraits {
/*! \ingroup PkgArrangementOnSurface2ConceptsFunctionObjects
* \cgalConcept
*
* \cgalRefines{Functor}
*
* \cgalHasModelsBegin
* \cgalHasModels{AosApproximatePointTraits_2::Approximate_2}
* \cgalHasModels{AosApproximateTraits_2::Approximate_2}
* \cgalHasModelsEnd
*/
class ApproximatePoint_2 {
public:
/// \name Operations
/// A model of this concept must provide:
/// @{
/*! obtains an approximation of `p`'s \f$x\f$-coordinate (if `i == 0`), or of
* `p`'s \f$y\f$-coordinate (if `i == 1`).
* \pre `i` is either 0 or 1.
*/
Approximate_number_type operator()(AosTraits::Point_2 p, int i);
/// @}
}; /* end AosTraits::Approximate_2 */
}

View File

@ -0,0 +1,49 @@
namespace AosTraits {
/*! \ingroup PkgArrangementOnSurface2ConceptsFunctionObjects
* \cgalConcept
*
* \cgalRefines{Approximate_2}
*
* \cgalHasModelsBegin
* \cgalHasModels{AosApproximatePointTraits_2::Approximate_2}
* \cgalHasModels{AosApproximateTraits_2::Approximate_2}
* \cgalHasModels{AosApproximateUnboundedTraits_2::Approximate_2}
* \cgalHasModelsEnd
*/
class ApproximateUnbounded_2 {
public:
/// \name Operations
/// A model of this concept must provide:
/// @{
/*! approximates a given \f$x\f$-monotone curve constrained to a bounding
* box. It computes one or more sequences of approximate points that represent
* the disconnected portions of a polyline that approximates `xcv` within the
* bounding box `bbox`, and inserts them into output containers given through
* the output iterator `oi`. The first point of the first sequence and the
* last point of the last sequence are always approximations of the endpoints
* of the given curve.
*
* \param xcv The exact \f$x\f$-monotone curve.
* \param error The error bound of the polyline approximation. This is the
* Hausdorff distance between the curve and the polyline that
* approximates the curve.
* \param oi An output iterator for the output containers.
* \param bbox the bounding box.
* \param l2r A Boolean flag that indicates whether the curve direction is
* left to right.
* \return The past-the-end iterator of the output container.
*
* \pre Dereferencing `oi` must yield an object the type of which is a
* container, where the value type of this container is
* `AosApproximateTraits_2::Approximate_point_2`.
*/
template <typename OutputIterator>
OutputIterator operator()(const X_monotone_curve_2& xcv, double error, OutputIterator oi,
const Bbox_2& bbox, bool l2r = true) const;
/// @}
}; /* end AosTraits::Approximate_2 */
}

View File

@ -3,7 +3,7 @@ namespace AosTraits {
/*! \ingroup PkgArrangementOnSurface2ConceptsFunctionObjects
* \cgalConcept
*
* \cgalRefines{Functor}
* \cgalRefines{ApproximatePoint_2}
*
* \cgalHasModelsBegin
* \cgalHasModels{AosApproximatePointTraits_2::Approximate_2}
@ -16,15 +16,9 @@ public:
/// A model of this concept must provide:
/// @{
/*! obtains an approximation of `p`'s \f$x\f$-coordinate (if `i == 0`), or of
* `p`'s \f$y\f$-coordinate (if `i == 1`).
* \pre `i` is either 0 or 1.
*/
CGAL::Approximate_number_type operator()(AosTraits::Point_2 p, int i);
/*! obtains an approximation of `p`.
*/
CGAL::Approximate_point_2 operator()(AosTraits::Point_2 p);
Approximate_point_2 operator()(AosTraits::Point_2 p);
/*! approximates a given \f$x\f$-monotone curve. It computes a sequence of
* approximate points that represent an approximate polyline, and inserts
@ -42,7 +36,7 @@ public:
* \return The past-the-end iterator of the output container.
*
* \pre Dereferencing `oi` must yield an object of type
* `Arr_conic_traits_2::Approximate_point_2`.
* `AosApproximateTraits_2::Approximate_point_2`.
*/
template <typename OutputIterator>
OutputIterator operator()(const X_monotone_curve_2& xcv, double error,

View File

@ -113,6 +113,7 @@ implemented as peripheral classes or as free (global) functions.
- `AosApproximateTraits_2`
- `AosApproximatePointTraits_2`
- `AosApproximateUnboundedTraits_2`
- `AosBasicTopologyTraits`
- `AosBasicTraits_2`
- `AosBottomSideTraits_2`
@ -167,6 +168,8 @@ implemented as peripheral classes or as free (global) functions.
\cgalCRPSection{Function Object Concepts}
- `AosTraits::Approximate_2`
- `AosTraits::ApproximatePoint_2`
- `AosTraits::ApproximateUnbounded_2`
- `AosTraits::AreMergeable_2`
- `AosTraits::CompareX_2`
- `AosTraits::CompareXy_2`
@ -262,6 +265,6 @@ implemented as peripheral classes or as free (global) functions.
- \link PkgArrangementOnSurface2op_right_shift `CGAL::operator<<` \endlink
\cgalCRPSection{Draw an `Arrangemen_2` object}
- \link PkgArrangementOnSurface2Draw CGAL::draw<>() \endlink
- \link PkgArrangementOnSurface2Draw CGAL::draw<>() \endlink
*/

View File

@ -28,6 +28,7 @@
#include <variant>
#include <CGAL/Cartesian.h>
#include <CGAL/tags.h>
#include <CGAL/intersections.h>
#include <CGAL/Arr_tags.h>
@ -1517,9 +1518,24 @@ public:
/// \name Functor definitions for the landmarks point-location strategy.
//@{
typedef double Approximate_number_type;
typedef double Approximate_number_type;
typedef CGAL::Cartesian<Approximate_number_type> Approximate_kernel;
typedef Approximate_kernel::Point_2 Approximate_point_2;
class Approximate_2 {
protected:
using Traits = Arr_linear_traits_2<Kernel>;
/*! The traits (in case it has state) */
const Traits& m_traits;
/*! constructs
* \param traits the traits.
*/
Approximate_2(const Traits& traits) : m_traits(traits) {}
friend class Arr_linear_traits_2<Kernel>;
public:
/*! obtains an approximation of a point coordinate.
* \param p The exact point.
@ -1533,10 +1549,102 @@ public:
CGAL_precondition((i == 0) || (i == 1));
return (i == 0) ? CGAL::to_double(p.x()) : CGAL::to_double(p.y());
}
/*! obtains an approximation of a point.
*/
Approximate_point_2 operator()(const Point_2& p) const
{ return Approximate_point_2(operator()(p, 0), operator()(p, 1)); }
/*! obtains an approximation of an \f$x\f$-monotone curve.
*/
template <typename OutputIterator>
OutputIterator operator()(const X_monotone_curve_2& xcv, double /* error */,
OutputIterator oi, bool l2r = true) const {
auto min_vertex = m_traits.construct_min_vertex_2_object();
auto max_vertex = m_traits.construct_max_vertex_2_object();
const auto& src = (l2r) ? min_vertex(xcv) : max_vertex(xcv);
const auto& trg = (l2r) ? max_vertex(xcv) : min_vertex(xcv);
auto xs = CGAL::to_double(src.x());
auto ys = CGAL::to_double(src.y());
auto xt = CGAL::to_double(trg.x());
auto yt = CGAL::to_double(trg.y());
*oi++ = Approximate_point_2(xs, ys);
*oi++ = Approximate_point_2(xt, yt);
return oi;
}
/*! obtains an approximation of an \f$x\f$-monotone curve.
*/
template <typename OutputIterator>
OutputIterator operator()(const X_monotone_curve_2& xcv, double /* error */,
OutputIterator oi, const Bbox_2& bbox,
bool l2r = true) const
{
using Approx_pnt = Approximate_point_2;
using Approx_seg = Approximate_kernel::Segment_2;
using Approx_ray = Approximate_kernel::Ray_2;
using Approx_lin = Approximate_kernel::Line_2;
auto xmin = bbox.xmin();
auto ymin = bbox.ymin();
auto xmax = bbox.xmax();
auto ymax = bbox.ymax();
Approximate_kernel::Iso_rectangle_2 rect(xmin, ymin, xmax, ymax);
if (xcv.is_ray()) {
auto ray = xcv.ray();
Kernel kernel;
auto construct_vertex = kernel.construct_point_on_2_object();
Approx_pnt s = this->operator()(construct_vertex(ray, 0));
Approx_pnt t = this->operator()(construct_vertex(ray, 1));
const auto result = CGAL::intersection(rect, Approx_ray(s, t));
if (! result) return oi;
if (const auto* res_seg = std::get_if<Approx_seg>(&*result)) {
*oi++ = l2r ? (res_seg->min)() : (res_seg->max)();
*oi++ = l2r ? (res_seg->max)() : (res_seg->min)();
return oi;
}
const auto* res_pnt = std::get_if<Approx_pnt>(&*result);
CGAL_assertion(res_pnt != nullptr);
*oi++ = *res_pnt;
return oi;
}
if (xcv.is_line()) {
const Line_2 & supp_line = xcv.supp_line();
Approx_lin approx_supp_line(
CGAL::to_double(supp_line.a()),
CGAL::to_double(supp_line.b()),
CGAL::to_double(supp_line.c()));
const auto result = CGAL::intersection(rect, approx_supp_line);
if (! result) return oi;
if (const auto* res_seg = std::get_if<Approx_seg>(&*result)) {
*oi++ = l2r ? (res_seg->min)() : (res_seg->max)();
*oi++ = l2r ? (res_seg->max)() : (res_seg->min)();
return oi;
}
const auto* res_pnt = std::get_if<Approx_pnt>(&*result);
CGAL_assertion(res_pnt != nullptr);
*oi++ = *res_pnt;
return oi;
}
Approx_seg seg(this->operator()(xcv.source()), this->operator()(xcv.target()));
const auto result = CGAL::intersection(rect, seg);
if (! result) return oi;
if (const auto* res_seg = std::get_if<Approx_seg>(&*result)) {
*oi++ = l2r ? (res_seg->min)() : (res_seg->max)();
*oi++ = l2r ? (res_seg->max)() : (res_seg->min)();
return oi;
}
const auto* res_pnt = std::get_if<Approx_pnt>(&*result);
CGAL_assertion(res_pnt != nullptr);
*oi++ = *res_pnt;
return oi;
}
};
/*! obtains an `Approximate_2` functor object. */
Approximate_2 approximate_2_object() const { return Approximate_2(); }
Approximate_2 approximate_2_object() const { return Approximate_2(*this); }
//! Functor
class Construct_x_monotone_curve_2 {

View File

@ -37,58 +37,55 @@
namespace CGAL {
namespace draw_function_for_arrangement_2
{
template<typename Arr, typename GSOptions>
class Draw_arr_tool
{
public:
using Halfedge_const_handle=typename Arr::Halfedge_const_handle;
using Vertex_const_handle=typename Arr::Vertex_const_handle;
using Face_const_handle=typename Arr::Face_const_handle;
using Ccb_halfedge_const_circulator=typename Arr::Ccb_halfedge_const_circulator;
using Inner_ccb_const_iterator=typename Arr::Inner_ccb_const_iterator;
using Outer_ccb_const_iterator=typename Arr::Outer_ccb_const_iterator;
using Gt=typename Arr::Geometry_traits_2;
using Point=typename Arr::Point_2;
using X_monotone_curve = typename Arr::X_monotone_curve_2;
namespace draw_aos {
Draw_arr_tool(Arr& a_aos, CGAL::Graphics_scene& a_gs, const GSOptions& a_gso):
m_aos(a_aos), m_gs(a_gs), m_gso(a_gso)
{}
template<typename Arr, typename GSOptions>
class Draw_arr_tool {
public:
using Halfedge_const_handle=typename Arr::Halfedge_const_handle;
using Vertex_const_handle=typename Arr::Vertex_const_handle;
using Face_const_handle=typename Arr::Face_const_handle;
using Ccb_halfedge_const_circulator=typename Arr::Ccb_halfedge_const_circulator;
using Inner_ccb_const_iterator=typename Arr::Inner_ccb_const_iterator;
using Outer_ccb_const_iterator=typename Arr::Outer_ccb_const_iterator;
using Gt=typename Arr::Geometry_traits_2;
using Point=typename Arr::Point_2;
using X_monotone_curve = typename Arr::X_monotone_curve_2;
/// Add a face.
void add_face(Face_const_handle face)
{
// std::cout << "add_face()\n";
for (Inner_ccb_const_iterator it = face->inner_ccbs_begin();
it != face->inner_ccbs_end(); ++it)
{ add_ccb(*it); }
Draw_arr_tool(Arr& a_aos, CGAL::Graphics_scene& a_gs, const GSOptions& a_gso):
m_aos(a_aos), m_gs(a_gs), m_gso(a_gso)
{}
//! adds a face.
void add_face(Face_const_handle face) {
// std::cout << "add_face()\n";
for (Inner_ccb_const_iterator it = face->inner_ccbs_begin();
it != face->inner_ccbs_end(); ++it)
add_ccb(*it);
if (! face->is_unbounded()) {
for (Outer_ccb_const_iterator it = face->outer_ccbs_begin();
it != face->outer_ccbs_end(); ++it)
{
it != face->outer_ccbs_end(); ++it) {
add_ccb(*it);
draw_region(*it);
}
}
}
/// Add a Connected Component of the Boundary.
void add_ccb(Ccb_halfedge_const_circulator circ)
{
// std::cout << "add_ccb()\n";
auto curr = circ;
do {
auto new_face = curr->twin()->face();
if (m_visited.find(new_face) != m_visited.end()) continue;
m_visited[new_face] = true;
add_face(new_face);
} while (++curr != circ);
}
//! adds a Connected Component of the Boundary.
void add_ccb(Ccb_halfedge_const_circulator circ) {
// std::cout << "add_ccb()\n";
auto curr = circ;
do {
auto new_face = curr->twin()->face();
if (m_visited.find(new_face) != m_visited.end()) continue;
m_visited[new_face] = true;
add_face(new_face);
} while (++curr != circ);
}
///! Draw a region.
void draw_region(Ccb_halfedge_const_circulator circ)
{
//! draws a region.
void draw_region(Ccb_halfedge_const_circulator circ) {
// std::cout << "draw_region()\n";
/* Check whether the traits has a member function called
* approximate_2_object() and if so check whether the return type, namely
@ -105,318 +102,300 @@ namespace draw_function_for_arrangement_2
*
* For now we use C++14 features.
*/
if(m_gso.colored_face(m_aos, circ->face()))
{ m_gs.face_begin(m_gso.face_color(m_aos, circ->face())); }
else
{ m_gs.face_begin(); }
if (m_gso.colored_face(m_aos, circ->face()))
m_gs.face_begin(m_gso.face_color(m_aos, circ->face()));
else
m_gs.face_begin();
const auto* traits = this->m_aos.geometry_traits();
auto ext = find_smallest(circ, *traits);
auto curr = ext;
const auto* traits = this->m_aos.geometry_traits();
auto ext = find_smallest(circ, *traits);
auto curr = ext;
do {
// Skip halfedges that are "antenas":
while (curr->face() == curr->twin()->face()) curr = curr->twin()->next();
draw_region_impl1(curr, *traits, 0);
curr = curr->next();
} while (curr != ext);
do {
// Skip halfedges that are "antenas":
while (curr->face() == curr->twin()->face()) curr = curr->twin()->next();
draw_region_impl1(curr, *traits, 0);
curr = curr->next();
} while (curr != ext);
m_gs.face_end();
}
m_gs.face_end();
}
/// Compile time dispatching
//! Compile time dispatching
#if 0
template <typename T, typename I = void>
void draw_region_impl2(Halfedge_const_handle curr, T const&, long)
{ draw_exact_region(curr); }
template <typename T, typename I = void>
void draw_region_impl2(Halfedge_const_handle curr, T const&, long)
{ draw_exact_region(curr); }
template <typename T, typename I>
auto draw_region_impl2(Halfedge_const_handle curr, T const& approx, int) ->
decltype(approx.template operator()<I>(X_monotone_curve{}, double{}, I{},
bool{}), void())
{ draw_approximate_region(curr, approx); }
template <typename T, typename I>
auto draw_region_impl2(Halfedge_const_handle curr, T const& approx, int) ->
decltype(approx.template operator()<I>(X_monotone_curve{}, double{}, I{},
bool{}), void())
{ draw_approximate_region(curr, approx); }
template <typename T>
void draw_region_impl1(Halfedge_const_handle curr, T const&, long)
{ draw_exact_region(curr); }
template <typename T>
void draw_region_impl1(Halfedge_const_handle curr, T const&, long)
{ draw_exact_region(curr); }
template <typename T>
auto draw_region_impl1(Halfedge_const_handle curr, T const& traits, int) ->
decltype(traits.approximate_2_object(), void()) {
using Approximate = typename Gt::Approximate_2;
draw_region_impl2<Approximate, int>(curr, traits.approximate_2_object(), 0);
}
template <typename T>
auto draw_region_impl1(Halfedge_const_handle curr, T const& traits, int) ->
decltype(traits.approximate_2_object(), void()) {
using Approximate = typename Gt::Approximate_2;
draw_region_impl2<Approximate, int>(curr, traits.approximate_2_object(), 0);
}
#else
template <typename T>
void draw_region_impl1(Halfedge_const_handle curr, T const& traits, int)
{ draw_approximate_region(curr, traits.approximate_2_object()); }
template <typename T>
void draw_region_impl1(Halfedge_const_handle curr, T const& traits, int)
{ draw_approximate_region(curr, traits.approximate_2_object()); }
#endif
template <typename Kernel_, int AtanX, int AtanY>
void draw_region_impl1
(Halfedge_const_handle curr,
Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits,
int)
{
if(!m_gso.draw_edge(m_aos, curr))
{ return; }
template <typename Kernel_, int AtanX, int AtanY>
void draw_region_impl1
(Halfedge_const_handle curr,
Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits,
int)
{
if (! m_gso.draw_edge(m_aos, curr)) return;
// std::cout << "draw_region_impl1()\n";
auto approx = traits.approximate_2_object();
using Kernel = Kernel_;
using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>;
using Ak = typename Traits::Approximate_kernel;
using Ap = typename Traits::Approximate_point_2;
using Approx_point_3 = typename Ak::Point_3;
// std::cout << "draw_region_impl1()\n";
auto approx = traits.approximate_2_object();
using Kernel = Kernel_;
using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>;
using Ak = typename Traits::Approximate_kernel;
using Ap = typename Traits::Approximate_point_2;
using Approx_point_3 = typename Ak::Point_3;
std::vector<Ap> polyline;
double error(0.01);
bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT;
approx(curr->curve(), error, std::back_inserter(polyline), l2r);
if (polyline.empty()) return;
auto it = polyline.begin();
std::vector<Ap> polyline;
double error(0.01);
bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT;
approx(curr->curve(), error, std::back_inserter(polyline), l2r);
if (polyline.empty()) return;
auto it = polyline.begin();
auto x = it->dx();
auto y = it->dy();
auto z = it->dz();
auto l = std::sqrt(x*x + y*y + z*z);
Approx_point_3 prev(x/l, y/l, z/l);
for (++it; it != polyline.end(); ++it) {
auto x = it->dx();
auto y = it->dy();
auto z = it->dz();
auto l = std::sqrt(x*x + y*y + z*z);
Approx_point_3 prev(x/l, y/l, z/l);
for (++it; it != polyline.end(); ++it) {
auto x = it->dx();
auto y = it->dy();
auto z = it->dz();
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(m_gso.colored_edge(m_aos, curr))
{ m_gs.add_segment(prev, next, m_gso.edge_color(m_aos, curr)); }
else
{ m_gs.add_segment(prev, next); }
prev = next;
// m_gs.add_point_in_face(*prev);
}
}
/*! Draw a region using approximate coordinates.
* Call this member function only if the geometry traits is equipped with
* the coordinate-approximation functionality of a curve.
* This function must be inlined (e.g., a template) to enable the
* compiled-time dispatching in the function `draw_region()`.
*/
template <typename Approximate>
void draw_approximate_region(Halfedge_const_handle curr,
const Approximate& approx)
{
// std::cout << "draw_approximate_region()\n";
std::vector<typename Gt::Approximate_point_2> polyline;
double error(0.01); // TODO? (this->pixel_ratio());
bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT;
approx(curr->curve(), error, std::back_inserter(polyline), l2r);
if (polyline.empty()) return;
auto it = polyline.begin();
auto prev = it++;
for (; it != polyline.end(); prev = it++) {
if(m_gso.draw_edge(m_aos, curr))
{
if(m_gso.colored_edge(m_aos, curr))
{ m_gs.add_segment(*prev, *it, m_gso.edge_color(m_aos, curr)); }
else
{ m_gs.add_segment(*prev, *it); }
}
m_gs.add_point_in_face(*prev);
}
}
/// Draw an exact curve.
template <typename XMonotoneCurve>
void draw_exact_curve(const XMonotoneCurve& curve)
{
const auto* traits = this->m_aos.geometry_traits();
auto ctr_min = traits->construct_min_vertex_2_object();
auto ctr_max = traits->construct_max_vertex_2_object();
m_gs.add_segment(ctr_min(curve), ctr_max(curve));
}
/// Draw an exact region.
void draw_exact_region(Halfedge_const_handle curr)
{
// this->add_point_in_face(curr->source()->point());
draw_exact_curve(curr->curve());
}
/// Add all faces.
template <typename Traits>
void add_faces(const Traits&)
{
for (auto it=m_aos.unbounded_faces_begin(); it!=m_aos.unbounded_faces_end(); ++it)
{ add_face(it); }
}
/// Add all faces.
template <typename Kernel_, int AtanX, int AtanY>
void add_faces(Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const&)
{ add_face(m_aos.faces_begin()); }
/// Compile time dispatching
#if 0
template <typename T>
void draw_point_impl2(const Point& p, T const&, long) { m_gs.add_point(p); }
template <typename T>
auto draw_point_impl2(const Point& p, T const& approx, int) ->
decltype(approx.operator()(p), void())
{ m_gs.add_point(approx(p)); }
template <typename T>
void draw_point_impl1(const Point& p, T const&, long) { m_gs.add_point(p); }
template <typename T>
auto draw_point_impl1(const Point& p, T const& traits, int) ->
decltype(traits.approximate_2_object(), void()) {
using Approximate = typename Gt::Approximate_2;
draw_point_impl2<Approximate>(p, traits.approximate_2_object(), true);
}
#else
template <typename T>
void draw_point_impl1(const Point& p, T const& traits, int,
bool colored, const CGAL::IO::Color& color)
{
if(colored)
{ m_gs.add_point(traits.approximate_2_object()(p), color); }
if (m_gso.colored_edge(m_aos, curr))
m_gs.add_segment(prev, next, m_gso.edge_color(m_aos, curr));
else
{ m_gs.add_point(traits.approximate_2_object()(p)); }
m_gs.add_segment(prev, next);
prev = next;
// m_gs.add_point_in_face(*prev);
}
}
/*! draws a region using approximate coordinates.
* Call this member function only if the geometry traits is equipped with
* the coordinate-approximation functionality of a curve.
* This function must be inlined (e.g., a template) to enable the
* compiled-time dispatching in the function `draw_region()`.
*/
template <typename Approximate>
void draw_approximate_region(Halfedge_const_handle curr,
const Approximate& approx) {
// std::cout << "draw_approximate_region()\n";
std::vector<typename Gt::Approximate_point_2> polyline;
double error(0.01); // TODO? (this->pixel_ratio());
bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT;
approx(curr->curve(), error, std::back_inserter(polyline), l2r);
if (polyline.empty()) return;
auto it = polyline.begin();
auto prev = it++;
for (; it != polyline.end(); prev = it++) {
if (m_gso.draw_edge(m_aos, curr)) {
if (m_gso.colored_edge(m_aos, curr))
m_gs.add_segment(*prev, *it, m_gso.edge_color(m_aos, curr));
else
m_gs.add_segment(*prev, *it);
}
m_gs.add_point_in_face(*prev);
}
}
//! draws an exact curve.
template <typename XMonotoneCurve>
void draw_exact_curve(const XMonotoneCurve& curve) {
const auto* traits = this->m_aos.geometry_traits();
auto ctr_min = traits->construct_min_vertex_2_object();
auto ctr_max = traits->construct_max_vertex_2_object();
m_gs.add_segment(ctr_min(curve), ctr_max(curve));
}
//! draws an exact region.
void draw_exact_region(Halfedge_const_handle curr) {
// this->add_point_in_face(curr->source()->point());
draw_exact_curve(curr->curve());
}
//! adds all faces.
template <typename Traits>
void add_faces(const Traits&) {
for (auto it = m_aos.unbounded_faces_begin(); it != m_aos.unbounded_faces_end(); ++it)
add_face(it);
}
//! adds all faces.
template <typename Kernel_, int AtanX, int AtanY>
void add_faces(Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const&)
{ add_face(m_aos.faces_begin()); }
//! Compile time dispatching
#if 0
template <typename T>
void draw_point_impl2(const Point& p, T const&, long) { m_gs.add_point(p); }
template <typename T>
auto draw_point_impl2(const Point& p, T const& approx, int) ->
decltype(approx.operator()(p), void())
{ m_gs.add_point(approx(p)); }
template <typename T>
void draw_point_impl1(const Point& p, T const&, long) { m_gs.add_point(p); }
template <typename T>
auto draw_point_impl1(const Point& p, T const& traits, int) ->
decltype(traits.approximate_2_object(), void()) {
using Approximate = typename Gt::Approximate_2;
draw_point_impl2<Approximate>(p, traits.approximate_2_object(), true);
}
#else
template <typename T>
void draw_point_impl1(const Point& p, T const& traits, int,
bool colored, const CGAL::IO::Color& color) {
if (colored)
{ m_gs.add_point(traits.approximate_2_object()(p), color); }
else
{ m_gs.add_point(traits.approximate_2_object()(p)); }
}
#endif
template <typename Kernel_, int AtanX, int AtanY>
void draw_point_impl1
(const Point& p,
Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits,
int,
bool colored,
const CGAL::IO::Color& color)
{
auto approx = traits.approximate_2_object();
using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY>;
using Ak = typename Traits::Approximate_kernel;
using Approx_point_3 = typename Ak::Point_3;
auto ap = approx(p);
auto x = ap.dx();
auto y = ap.dy();
auto z = ap.dz();
auto l = std::sqrt(x*x + y*y + z*z);
Approx_point_3 p3(x/l, y/l, z/l);
if(colored)
{ m_gs.add_point(p3, color); }
template <typename Kernel_, int AtanX, int AtanY>
void draw_point_impl1
(const Point& p,
Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits,
int,
bool colored,
const CGAL::IO::Color& color) {
auto approx = traits.approximate_2_object();
using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY>;
using Ak = typename Traits::Approximate_kernel;
using Approx_point_3 = typename Ak::Point_3;
auto ap = approx(p);
auto x = ap.dx();
auto y = ap.dy();
auto z = ap.dz();
auto l = std::sqrt(x*x + y*y + z*z);
Approx_point_3 p3(x/l, y/l, z/l);
if (colored) m_gs.add_point(p3, color);
else m_gs.add_point(p3);
}
//! draws a point.
void draw_point(Vertex_const_handle vh) {
const auto* traits = m_aos.geometry_traits();
if (m_gso.draw_vertex(m_aos, vh)) {
if (m_gso.colored_vertex(m_aos, vh))
draw_point_impl1(vh->point(), *traits, 0, true,
m_gso.vertex_color(m_aos, vh));
else
{ m_gs.add_point(p3); }
draw_point_impl1(vh->point(), *traits, 0, false, CGAL::IO::Color()); // color will be unused
}
}
/// Draw a point.
void draw_point(Vertex_const_handle vh)
{
const auto* traits = m_aos.geometry_traits();
if(m_gso.draw_vertex(m_aos, vh))
{
if(m_gso.colored_vertex(m_aos, vh))
{ draw_point_impl1(vh->point(), *traits, 0, true,
m_gso.vertex_color(m_aos, vh)); }
else
{ draw_point_impl1(vh->point(), *traits, 0, false, CGAL::IO::Color()); } // color will be unused
template <typename Kernel, int AtanX, int AtanY>
Halfedge_const_handle
find_smallest(Ccb_halfedge_const_circulator circ,
Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY> const&)
{ return circ; }
/*! finds the halfedge incident to the lexicographically smallest vertex
* along the CCB, such that there is no other halfedge underneath.
*/
template <typename Traits>
Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ,
const Traits&) {
// std::cout << "find_smallest()\n";
const auto* traits = this->m_aos.geometry_traits();
auto cmp_xy = traits->compare_xy_2_object();
auto cmp_y = traits->compare_y_at_x_right_2_object();
// Find the first halfedge directed from left to right
auto curr = circ;
do if (curr->direction() == CGAL::ARR_LEFT_TO_RIGHT) break;
while (++curr != circ);
Halfedge_const_handle ext = curr;
// Find the halfedge incident to the lexicographically smallest vertex,
// such that there is no other halfedge underneath.
do {
// Discard edges not directed from left to right:
if (curr->direction() != CGAL::ARR_LEFT_TO_RIGHT) continue;
auto res = cmp_xy(curr->source()->point(), ext->source()->point());
// Discard the edges inciden to a point strictly larger than the point
// incident to the stored extreme halfedge:
if (res == LARGER) continue;
// Store the edge inciden to a point strictly smaller:
if (res == SMALLER) {
ext = curr;
continue;
}
}
template <typename Kernel, int AtanX, int AtanY>
Halfedge_const_handle
find_smallest(Ccb_halfedge_const_circulator circ,
Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY> const&)
{ return circ; }
// The incident points are equal; compare the halfedges themselves:
if (cmp_y(curr->curve(), ext->curve(), curr->source()->point()) ==
SMALLER)
ext = curr;
} while (++curr != circ);
/*! Find the halfedge incident to the lexicographically smallest vertex
* along the CCB, such that there is no other halfedge underneath.
*/
template <typename Traits>
Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ,
const Traits&)
{
// std::cout << "find_smallest()\n";
const auto* traits = this->m_aos.geometry_traits();
auto cmp_xy = traits->compare_xy_2_object();
auto cmp_y = traits->compare_y_at_x_right_2_object();
return ext;
}
// Find the first halfedge directed from left to right
auto curr = circ;
do if (curr->direction() == CGAL::ARR_LEFT_TO_RIGHT) break;
while (++curr != circ);
Halfedge_const_handle ext = curr;
// Find the halfedge incident to the lexicographically smallest vertex,
// such that there is no other halfedge underneath.
do {
// Discard edges not directed from left to right:
if (curr->direction() != CGAL::ARR_LEFT_TO_RIGHT) continue;
auto res = cmp_xy(curr->source()->point(), ext->source()->point());
// Discard the edges inciden to a point strictly larger than the point
// incident to the stored extreme halfedge:
if (res == LARGER) continue;
// Store the edge inciden to a point strictly smaller:
if (res == SMALLER) {
ext = curr;
continue;
}
// The incident points are equal; compare the halfedges themselves:
if (cmp_y(curr->curve(), ext->curve(), curr->source()->point()) ==
SMALLER)
ext = curr;
} while (++curr != circ);
return ext;
}
/// Add all elements to be drawn.
void add_elements()
{
//! adds all elements to be drawn.
void add_elements() {
// std::cout << "add_elements()\n";
// std::cout << "ratio: " << this->pixel_ratio() << std::endl;
m_visited.clear();
if (m_aos.is_empty()) return;
if(m_gso.are_faces_enabled())
if (m_gso.are_faces_enabled())
{ add_faces(*(this->m_aos.geometry_traits())); }
// Add edges that do not separate faces.
if(m_gso.are_edges_enabled())
{
for (auto it = m_aos.edges_begin(); it != m_aos.edges_end(); ++it)
{ if (it->face()==it->twin()->face())
{
if(m_gso.draw_edge(m_aos, it))
{
if(m_gso.colored_edge(m_aos, it))
{ draw_curve(it->curve(), true, m_gso.edge_color(m_aos, it)); }
if (m_gso.are_edges_enabled()) {
for (auto it = m_aos.edges_begin(); it != m_aos.edges_end(); ++it) {
if (it->face()==it->twin()->face()) {
if (m_gso.draw_edge(m_aos, it)) {
if (m_gso.colored_edge(m_aos, it))
draw_curve(it->curve(), true, m_gso.edge_color(m_aos, it));
else
{ draw_curve(it->curve(), false, CGAL::IO::Color()); }
draw_curve(it->curve(), false, CGAL::IO::Color());
}
}
}
}
// Add all points
if(m_gso.are_vertices_enabled())
{
if (m_gso.are_vertices_enabled()) {
for (auto it = m_aos.vertices_begin(); it != m_aos.vertices_end(); ++it)
{ draw_point(it); }
draw_point(it);
}
m_visited.clear();
}
/*! Draw a curve using approximate coordinates.
/*! draws a curve using approximate coordinates.
* Call this member function only of the geometry traits is equipped with
* the coordinate-aproximation functionality of a curve.
* This function must be inlined (e.g., a template) to enable the
@ -425,149 +404,138 @@ namespace draw_function_for_arrangement_2
template <typename XMonotoneCurve, typename Approximate>
void draw_approximate_curve(const XMonotoneCurve& curve,
const Approximate& approx,
bool colored, const CGAL::IO::Color& c)
{
bool colored, const CGAL::IO::Color& c) {
std::vector<typename Gt::Approximate_point_2> polyline;
double error(0.01); // TODO? (this->pixel_ratio());
approx(curve, error, std::back_inserter(polyline));
if (polyline.empty()) return;
auto it = polyline.begin();
auto prev = it++;
for (; it != polyline.end(); prev = it++)
{
if(colored)
{ m_gs.add_segment(*prev, *it, c); }
else
{ m_gs.add_segment(*prev, *it); }
for (; it != polyline.end(); prev = it++) {
if (colored) m_gs.add_segment(*prev, *it, c);
else m_gs.add_segment(*prev, *it);
}
}
/*! Compile time dispatching
*/
#if 0
template <typename T, typename I = void>
void draw_curve_impl2(const X_monotone_curve& xcv, T const&, long)
{ draw_exact_curve(xcv); }
template <typename T, typename I = void>
void draw_curve_impl2(const X_monotone_curve& xcv, T const&, long)
{ draw_exact_curve(xcv); }
template <typename T, typename I>
auto draw_curve_impl2(const X_monotone_curve& xcv, T const& approx, int) ->
decltype(approx.template operator()<I>(X_monotone_curve{}, double{}, I{},
bool{}), void())
{ draw_approximate_curve(xcv, approx); }
template <typename T, typename I>
auto draw_curve_impl2(const X_monotone_curve& xcv, T const& approx, int) ->
decltype(approx.template operator()<I>(X_monotone_curve{}, double{}, I{},
bool{}), void())
{ draw_approximate_curve(xcv, approx); }
template <typename T>
void draw_curve_impl1(const X_monotone_curve& xcv, T const&, long)
{ draw_exact_curve(xcv); }
template <typename T>
void draw_curve_impl1(const X_monotone_curve& xcv, T const&, long)
{ draw_exact_curve(xcv); }
template <typename T>
auto draw_curve_impl1(const X_monotone_curve& xcv, T const& traits, int) ->
decltype(traits.approximate_2_object(), void()) {
using Approximate = typename Gt::Approximate_2;
draw_curve_impl2<Approximate, int>(xcv, traits.approximate_2_object(), 0);
}
template <typename T>
auto draw_curve_impl1(const X_monotone_curve& xcv, T const& traits, int) ->
decltype(traits.approximate_2_object(), void()) {
using Approximate = typename Gt::Approximate_2;
draw_curve_impl2<Approximate, int>(xcv, traits.approximate_2_object(), 0);
}
#else
template <typename T>
void draw_curve_impl1(const X_monotone_curve& xcv, T const& traits, int,
bool colored, const CGAL::IO::Color& c)
{ draw_approximate_curve(xcv, traits.approximate_2_object(), colored, c); }
template <typename T>
void draw_curve_impl1(const X_monotone_curve& xcv, T const& traits, int,
bool colored, const CGAL::IO::Color& c)
{ draw_approximate_curve(xcv, traits.approximate_2_object(), colored, c); }
#endif
template <typename Kernel_, int AtanX, int AtanY>
void draw_curve_impl1
(const X_monotone_curve& xcv,
Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits,
int,
bool colored, const CGAL::IO::Color& c)
{
auto approx = traits.approximate_2_object();
using Kernel = Kernel_;
using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>;
using Ak = typename Traits::Approximate_kernel;
using Ap = typename Traits::Approximate_point_2;
using Approx_point_3 = typename Ak::Point_3;
std::vector<Ap> apoints;
double error(0.01);
approx(xcv, error, std::back_inserter(apoints));
auto it = apoints.begin();
template <typename Kernel_, int AtanX, int AtanY>
void draw_curve_impl1
(const X_monotone_curve& xcv,
Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits,
int,
bool colored, const CGAL::IO::Color& c)
{
auto approx = traits.approximate_2_object();
using Kernel = Kernel_;
using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>;
using Ak = typename Traits::Approximate_kernel;
using Ap = typename Traits::Approximate_point_2;
using Approx_point_3 = typename Ak::Point_3;
std::vector<Ap> apoints;
double error(0.01);
approx(xcv, error, std::back_inserter(apoints));
auto it = apoints.begin();
auto x = it->dx();
auto y = it->dy();
auto z = it->dz();
auto l = std::sqrt(x*x + y*y + z*z);
Approx_point_3 prev(x/l, y/l, z/l);
for (++it; it != apoints.end(); ++it) {
auto x = it->dx();
auto y = it->dy();
auto z = it->dz();
auto l = std::sqrt(x*x + y*y + z*z);
Approx_point_3 prev(x/l, y/l, z/l);
for (++it; it != apoints.end(); ++it) {
auto x = it->dx();
auto y = it->dy();
auto z = it->dz();
auto l = std::sqrt(x*x + y*y + z*z);
Approx_point_3 next(x/l, y/l, z/l);
if(colored)
{ m_gs.add_segment(prev, next, c); }
else
{ m_gs.add_segment(prev, next); }
prev = next;
}
Approx_point_3 next(x/l, y/l, z/l);
if (colored) m_gs.add_segment(prev, next, c);
else m_gs.add_segment(prev, next);
prev = next;
}
}
/// Draw a curve.
template <typename XMonotoneCurve>
void draw_curve(const XMonotoneCurve& curve,
bool colored, const CGAL::IO::Color& c)
{
/* Check whether the traits has a member function called
* approximate_2_object() and if so check whether the return type, namely
* `Approximate_2` has an appropriate operator.
*
* C++20 supports concepts and `requires` expression; see, e.g.,
* https://en.cppreference.com/w/cpp/language/constraints; thus, the first
* condition above can be elegantly verified as follows:
* constexpr bool has_approximate_2_object =
* requires(const Gt& traits) { traits.approximate_2_object(); };
*
* C++17 has experimental constructs called is_detected and
* is_detected_v that can be used to achieve the same goal.
*
* For now we use C++14 features.
*/
//! draws a curve.
template <typename XMonotoneCurve>
void draw_curve(const XMonotoneCurve& curve,
bool colored, const CGAL::IO::Color& c) {
/* Check whether the traits has a member function called
* approximate_2_object() and if so check whether the return type, namely
* `Approximate_2` has an appropriate operator.
*
* C++20 supports concepts and `requires` expression; see, e.g.,
* https://en.cppreference.com/w/cpp/language/constraints; thus, the first
* condition above can be elegantly verified as follows:
* constexpr bool has_approximate_2_object =
* requires(const Gt& traits) { traits.approximate_2_object(); };
*
* C++17 has experimental constructs called is_detected and
* is_detected_v that can be used to achieve the same goal.
*
* For now we use C++14 features.
*/
#if 0
if constexpr (std::experimental::is_detected_v<approximate_2_object_t, Gt>)
{
const auto* traits = this->m_aos.geometry_traits();
auto approx = traits->approximate_2_object();
draw_approximate_curve(curve, approx);
return;
}
draw_exact_curve(curve);
#else
if constexpr (std::experimental::is_detected_v<approximate_2_object_t, Gt>) {
const auto* traits = this->m_aos.geometry_traits();
draw_curve_impl1(curve, *traits, 0, colored, c);
#endif
auto approx = traits->approximate_2_object();
draw_approximate_curve(curve, approx);
return;
}
draw_exact_curve(curve);
#else
const auto* traits = this->m_aos.geometry_traits();
draw_curve_impl1(curve, *traits, 0, colored, c);
#endif
}
protected:
Arr& m_aos;
CGAL::Graphics_scene& m_gs;
const GSOptions& m_gso;
std::unordered_map<Face_const_handle, bool> m_visited;
};
protected:
Arr& m_aos;
CGAL::Graphics_scene& m_gs;
const GSOptions& m_gso;
std::unordered_map<Face_const_handle, bool> m_visited;
};
} // namespace draw_function_for_arrangement_2
} // namespace draw_aos
#define CGAL_ARR_TYPE CGAL::Arrangement_on_surface_2<GeometryTraits_2, TopologyTraits>
template <typename GeometryTraits_2, typename TopologyTraits, class GSOptions>
void add_to_graphics_scene(const CGAL_ARR_TYPE& aos,
CGAL::Graphics_scene& graphics_scene,
const GSOptions& gso)
{
draw_function_for_arrangement_2::Draw_arr_tool dar(aos, graphics_scene, gso);
const GSOptions& gso) {
draw_aos::Draw_arr_tool dar(aos, graphics_scene, gso);
dar.add_elements();
}
template <typename GeometryTraits_2, typename TopologyTraits>
void add_to_graphics_scene(const CGAL_ARR_TYPE& aos,
CGAL::Graphics_scene& graphics_scene)
{
CGAL::Graphics_scene& graphics_scene) {
CGAL::Graphics_scene_options<CGAL_ARR_TYPE,
typename CGAL_ARR_TYPE::Vertex_const_handle,
typename CGAL_ARR_TYPE::Halfedge_const_handle,
@ -587,11 +555,10 @@ void add_to_graphics_scene(const CGAL_ARR_TYPE& aos,
add_to_graphics_scene(aos, graphics_scene, gso);
}
/// Draw an arrangement on surface.
//! draws an arrangement on surface.
template <typename GeometryTraits_2, typename TopologyTraits, class GSOptions>
void draw(const CGAL_ARR_TYPE& aos, const GSOptions& gso,
const char* title = "2D Arrangement on Surface Basic Viewer")
{
const char* title = "2D Arrangement on Surface Basic Viewer") {
CGAL::Graphics_scene graphics_scene;
add_to_graphics_scene(aos, graphics_scene, gso);
draw_graphics_scene(graphics_scene, title);
@ -600,8 +567,7 @@ void draw(const CGAL_ARR_TYPE& aos, const GSOptions& gso,
template <typename GeometryTraits_2, typename TopologyTraits>
void draw(const CGAL_ARR_TYPE& aos,
const char* title = "2D Arrangement on Surface Basic Viewer")
{
const char* title = "2D Arrangement on Surface Basic Viewer") {
CGAL::Graphics_scene graphics_scene;
add_to_graphics_scene(aos, graphics_scene);
draw_graphics_scene(graphics_scene, title);

View File

@ -4,6 +4,12 @@
Release date: July 2026
### [2D Arrangements](https://doc.cgal.org/6.1/Manual/packages.html#PkgArrangementOnSurface2)
- Introduced a Geometry Traits concept for arrangement on surfaces that enables the provision of the disconnected portions of an approximation of a curve within a given bounding box.
- Made the `Arr_linear_traits_2` a model of the new concept.
### [Linear Cell Complex](https://doc.cgal.org/6.2/Manual/packages.html#PkgLinearCellComplex)
- **API Changes**: The following import functions have been deprecated and renamed for better naming clarity and consistency: