Merge branch 'main' into Small_feature/read_write_vtk_for_LCC

This commit is contained in:
Guillaume Damiand 2025-11-06 09:38:10 +01:00 committed by GitHub
commit 6f2c3d819e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
436 changed files with 14019 additions and 4820 deletions

View File

@ -164,7 +164,7 @@ jobs:
wget --no-verbose cgal.github.io -O index.html
if ! egrep -qF "/$PR_NUMBER/$ROUND" index.html || [ "$force" = "yes" ]; then
#list impacted packages
LIST_OF_PKGS=$(git diff --name-only origin/master...HEAD |cut -s -d/ -f1 |sort -u | xargs -I {} echo {} && ls -d {}/package_info 2>/dev/null |cut -d/ -f1 |egrep -v Installation||true)
LIST_OF_PKGS=$(git diff --name-only origin/main...HEAD |cut -s -d/ -f1 |sort -u | xargs -I {} echo {} && ls -d {}/package_info 2>/dev/null |cut -d/ -f1 |egrep -v Installation||true)
if [ "$LIST_OF_PKGS" = "" ]; then
echo "DoxygenError=No package affected." >> $GITHUB_OUTPUT
exit 1

View File

@ -44,12 +44,14 @@ Type of input datum.
typedef unspecified_type Datum;
/*!
Point reference type returned by the function `point(const Shared_data&)`. It is convertible to the type `Point`.
Point reference type returned by the function \link reference_point `reference_point(const Shared_data&)`\endlink.
It is convertible to the type `Point`.
*/
typedef unspecified_type Point_reference;
/*!
Datum reference type returned by the function `datum(const Shared_data&)`. It is convertible to the type `Datum`.
Datum reference type returned by the function \link datum `datum(const Shared_data&)`\endlink.
It is convertible to the type `Datum`.
*/
typedef unspecified_type Datum_reference;

View File

@ -27,7 +27,7 @@ void triangle_mesh(std::string fname)
typedef CGAL::AABB_tree<Traits> Tree;
TriangleMesh tmesh;
if(!CGAL::IO::read_polygon_mesh(fname, tmesh) || CGAL::is_triangle_mesh(tmesh))
if(!CGAL::IO::read_polygon_mesh(fname, tmesh) || !CGAL::is_triangle_mesh(tmesh))
{
std::cerr << "Invalid input." << std::endl;
return;

View File

@ -128,7 +128,7 @@ namespace CGAL {
* @param first iterator over first primitive to insert
* @param beyond past-the-end iterator
*
* constructs an empty tree followed by a call to `insert(first,last,t...)`.
* constructs an empty tree followed by a call to \link insert(InputIterator, InputIterator, T&&...) `insert(first,last,t...)`\endlink.
* The tree stays empty if the memory allocation is not successful.
*/
template<typename InputIterator,typename ... T>
@ -140,7 +140,8 @@ namespace CGAL {
/// This procedure is called implicitly at the first call to a query member function.
/// An explicit call to `build()` must be made to ensure that the next call to
/// a query function will not trigger the construction of the data structure.
/// A call to `AABBTraits::set_shared_data(t...)` is made using the internally stored traits.
/// A call to \link AABBTraits::set_shared_data `AABBTraits::set_shared_data(t...)`\endlink
// is made using the internally stored traits.
/// This procedure has a complexity of \cgalBigO{n log(n)}, where \f$n\f$ is the number of
/// primitives of the tree.
template<typename ... T>
@ -160,16 +161,17 @@ namespace CGAL {
/// \name Operations
///@{
/// is equivalent to calling `clear()`, `insert(first,last,t...)`, and `build()`
/// is equivalent to calling `clear()`, \link insert(InputIterator, InputIterator, T&&...) `insert(first,last,t...)`\endlink,
// and `build()`
template<typename ConstPrimitiveIterator,typename ... T>
void rebuild(ConstPrimitiveIterator first, ConstPrimitiveIterator beyond,T&& ...);
/// adds a sequence of primitives to the set of primitives of the AABB tree.
/// `%InputIterator` is any iterator and the parameter pack `T` contains any types
/// such that `Primitive` has a constructor with the following signature:
/// `Primitive(%InputIterator, T...)`. If `Primitive` is a model of the concept
/// `AABBPrimitiveWithSharedData`, a call to `AABBTraits::set_shared_data(t...)`
/// `AABBPrimitiveWithSharedData`, a call to
/// \link AABBTraits::set_shared_data `AABBTraits::set_shared_data(t...)`\endlink
/// is made using the internally stored traits.
template<typename InputIterator,typename ... T>
void insert(InputIterator first, InputIterator beyond,T&& ...);

View File

@ -7,7 +7,7 @@ A model of the concept `FromDoubleConstructible` is required
to be constructible from the type `double`.
In case the type is a model of `RealEmbeddable` too, for any double d
the identity: `d == CGAL::to_double(T(d))`, is guaranteed.
the identity: `d == ` \link CGAL::to_double ` CGAL::to_double(T(d))`\endlink, is guaranteed.
*/

View File

@ -221,7 +221,7 @@ a visible circle through an iterator called
`ApolloniusGraphVertexBase_2` concept and is implemented by its
model, the `Apollonius_graph_vertex_base_2<Gt,StoreHidden>`
class. It is also possible to iterate through the entire set of hidden
sites using an homonymous iterator defined by the
sites using a homonymous iterator defined by the
`Apollonius_graph_2<Gt,Agds>` class.
Since storing hidden sites may not be of interest in some cases (e.g.,

View File

@ -112,7 +112,7 @@ typedef Gt::Site_2 Site_2;
the edge type.
The `Edge(f,i)` is the edge common to faces `f` and
`f.neighbor(i)`. It is also the edge joining the vertices
`vertex(cw(i))` and `vertex(ccw(i))` of `f`.
`f->vertex(cw(i))` and `f->vertex(ccw(i))` of `f`.
\pre `i` must be `0`, `1` or `2`.
*/
typedef Data_structure::Edge Edge;

View File

@ -56,7 +56,7 @@ public:
/// @{
/*!
Creates an hierarchy of Apollonius graphs using `gt` as
Creates a hierarchy of Apollonius graphs using `gt` as
geometric traits.
*/
Apollonius_graph_hierarchy_2(Gt gt=Gt());

View File

@ -17,12 +17,11 @@ concept `ApolloniusSite_2`.
\cgalHeading{I/O}
The I/O operators are defined for `iostream`.
The I/O operators are defined for `std::iostream`.
The information output in the `iostream` is: the point of the
The information output in the `std::iostream` is: the point of the
Apollonius site and its weight.
\sa `CGAL::Qt_widget`
\sa `CGAL::Apollonius_graph_traits_2<K,Method_tag>`
\sa `CGAL::Apollonius_graph_filtered_traits_2<CK,CM,EK,EM,FK,FM>`
*/
@ -50,7 +49,6 @@ Apollonius_site_2(const Apollonius_site_2<K>& other);
/*!
Inserts the
Apollonius site `s` into the stream `os`.
\note Included through `CGAL/IO/Qt_widget_Apollonius_site_2.h`.
\pre The insert operator must be defined for `Point_2` and `Weight`.
\relates Apollonius_site_2
*/
@ -59,18 +57,9 @@ std::ostream& operator<<(std::ostream& os, const Apollonius_site_2<K>& s) const;
/*!
Reads an Apollonius site from the stream `is` and assigns it
to `s`.
\note Included through `CGAL/IO/Qt_widget_Apollonius_site_2.h`.
\pre The extract operator must be defined for `Point_2` and `Weight`.
\relates Apollonius_site_2
*/
std::istream& operator>>(std::istream& is, const Apollonius_site_2<K>& s);
/*!
Inserts the Apollonius site `s` into the `Qt_widget` stream `w`.
\note Included through `CGAL/IO/Qt_widget_Apollonius_site_2.h`.
\pre The insert operator must be defined for `K::Circle_2`.
\relates Apollonius_site_2
*/
Qt_widget& operator<<(Qt_widget& w, const Apollonius_site_2<K>& s) const;
} /* end namespace CGAL */

View File

@ -63,7 +63,7 @@ struct Parabola_segment_2 : public Parabola_2< Gt >
}
int compute_k(const FT tt, const FT STEP) const {
return int(CGAL::to_double(CGAL::sqrt(tt / STEP)));
return int(CGAL::to_double(CGAL::approximate_sqrt(tt / STEP)));
}
// s0 and s1 define a desired drawing "range"

View File

@ -1048,8 +1048,8 @@ not coincide with any existing arrangement vertex and does not lie on
any edge. As mentioned in Section \ref arr_ssectraverse, it is
possible to obtain the face containing an isolated vertex calling the
member function `Arrangement_on_surface_2::Vertex::face()`. The member
function
`Arrangement_on_surface_2::remove_isolated_vertex(Vertex_handle v)`
function \link Arrangement_on_surface_2::remove_isolated_vertex()
`Arrangement_on_surface_2::remove_isolated_vertex(Vertex_handle v)`\endlink
accepts a handle to an isolated vertex and removes it from the
arrangement.
@ -4890,7 +4890,7 @@ using Arrangement = CGAL::Arrangement_2<Traits>;
<!-- ----------------------------------------------------------------------- -->
\cgalFigureBegin{aos_fig-conic_multiplicities,conic_multiplicities.png}
An arrangement of a circular arc and an hyperbolic arc, as constructed
An arrangement of a circular arc and a hyperbolic arc, as constructed
in \ref Arrangement_on_surface_2/conic_multiplicities.cpp.
\cgalFigureEnd
<!-- ----------------------------------------------------------------------- -->
@ -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

@ -3,9 +3,8 @@ namespace CGAL {
/*! \ingroup PkgArrangementOnSurface2Ref
*
* `Arr_observer<Arrangement_2>` is an alias for
* `Aos_observer<Arrangement_on_surface_2>`,
* where `Arrangement_2` derives from `Arrangement_on_surface_2` and the latter
* is an instance of the template
* `Aos_observer<Arrangement_on_surface_2>`, where `Arrangement_2` derives from
* `Arrangement_on_surface_2` and the latter is an instance of the template
* `CGAL::Arrangement_on_surface_2<GeometryTraits, TopologyTraits>`.
*/

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

@ -18,7 +18,7 @@ public:
/*! accepts two <I>mergeable</I> \f$x\f$-monotone curves `xc1` and `xc2`
* and assigns `xc` with the merged curve.
*
* \pre `are_mergeable_2`(`xc1`, `xc2`) is true.
* \pre \link AosTraits::AreMergeable_2 `are_mergeable_2`\endlink(`xc1`, `xc2`) is true.
*/
void merge(AosTraits::X_monotone_curve_2 xc1,
AosTraits::X_monotone_curve_2 xc2,

View File

@ -136,7 +136,7 @@ public:
/// \name Face Creation
/// The following function is invoked whenever a new face is
/// created. It is guaranteed that all halfedges along the face
/// boundary have already been created an have their auxiliary data
/// boundary have already been created and have their auxiliary data
/// fields attached to them:
/// @{

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

@ -1,52 +1,59 @@
/*!
\example Arrangement_on_surface_2/aggregated_insertion.cpp
\example Arrangement_on_surface_2/algebraic_curves.cpp
\example Arrangement_on_surface_2/algebraic_segments.cpp
\example Arrangement_on_surface_2/batched_point_location.cpp
\example Arrangement_on_surface_2/Bezier_curves.cpp
\example Arrangement_on_surface_2/bgl_dual_adapter.cpp
\example Arrangement_on_surface_2/bgl_primal_adapter.cpp
\example Arrangement_on_surface_2/bounded_vertical_decomposition.cpp
\example Arrangement_on_surface_2/circles.cpp
\example Arrangement_on_surface_2/circular_arcs.cpp
\example Arrangement_on_surface_2/conics.cpp
\example Arrangement_on_surface_2/conic_multiplicities.cpp
\example Arrangement_on_surface_2/consolidated_curve_data.cpp
\example Arrangement_on_surface_2/count_and_trace.cpp
\example Arrangement_on_surface_2/curve_history.cpp
\example Arrangement_on_surface_2/dcel_extension.cpp
\example Arrangement_on_surface_2/dcel_extension_io.cpp
\example Arrangement_on_surface_2/dual_lines.cpp
\example Arrangement_on_surface_2/dual_with_data.cpp
\example Arrangement_on_surface_2/edge_insertion.cpp
\example Arrangement_on_surface_2/edge_manipulation.cpp
\example Arrangement_on_surface_2/edge_manipulation_curve_history.cpp
\example Arrangement_on_surface_2/face_extension.cpp
\example Arrangement_on_surface_2/face_extension_overlay.cpp
\example Arrangement_on_surface_2/generic_curve_data.cpp
\example Arrangement_on_surface_2/global_insertion.cpp
\example Arrangement_on_surface_2/global_removal.cpp
\example Arrangement_on_surface_2/incremental_insertion.cpp
\example Arrangement_on_surface_2/io.cpp
\example Arrangement_on_surface_2/io_curve_history.cpp
\example Arrangement_on_surface_2/isolated_vertices.cpp
\example Arrangement_on_surface_2/observer.cpp
\example Arrangement_on_surface_2/overlay.cpp
\example Arrangement_on_surface_2/overlay_color.cpp
\example Arrangement_on_surface_2/overlay_unbounded.cpp
\example Arrangement_on_surface_2/point_location.cpp
\example Arrangement_on_surface_2/polylines.cpp
\example Arrangement_on_surface_2/predefined_kernel.cpp
\example Arrangement_on_surface_2/predefined_kernel_non_intersecting.cpp
\example Arrangement_on_surface_2/rational_functions.cpp
\example Arrangement_on_surface_2/special_edge_insertion.cpp
\example Arrangement_on_surface_2/spherical_insert.cpp
\example Arrangement_on_surface_2/unbounded_non_intersecting.cpp
\example Arrangement_on_surface_2/unbounded_rational_functions.cpp
\example Arrangement_on_surface_2/vertical_ray_shooting.cpp
\example Arrangement_on_surface_2/draw_arr.cpp
\example Arrangement_on_surface_2/linear_conics.cpp
\example Arrangement_on_surface_2/parabolas.cpp
\example Arrangement_on_surface_2/ellipses.cpp
\example Arrangement_on_surface_2/hyperbolas.cpp
*/
* \example Arrangement_on_surface_2/aggregated_insertion.cpp
* \example Arrangement_on_surface_2/algebraic_curves.cpp
* \example Arrangement_on_surface_2/algebraic_segments.cpp
* \example Arrangement_on_surface_2/batched_point_location.cpp
* \example Arrangement_on_surface_2/Bezier_curves.cpp
* \example Arrangement_on_surface_2/bgl_dual_adapter.cpp
* \example Arrangement_on_surface_2/bgl_primal_adapter.cpp
* \example Arrangement_on_surface_2/bounded_vertical_decomposition.cpp
* \example Arrangement_on_surface_2/circles.cpp
* \example Arrangement_on_surface_2/circular_arcs.cpp
* \example Arrangement_on_surface_2/conics.cpp
* \example Arrangement_on_surface_2/conic_multiplicities.cpp
* \example Arrangement_on_surface_2/consolidated_curve_data.cpp
* \example Arrangement_on_surface_2/count_and_trace.cpp
* \example Arrangement_on_surface_2/curve_history.cpp
* \example Arrangement_on_surface_2/dcel_extension.cpp
* \example Arrangement_on_surface_2/dcel_extension_io.cpp
* \example Arrangement_on_surface_2/draw_agas.cpp
* \example Arrangement_on_surface_2/draw_arr.cpp
* \example Arrangement_on_surface_2/dual_lines.cpp
* \example Arrangement_on_surface_2/dual_with_data.cpp
* \example Arrangement_on_surface_2/edge_insertion.cpp
* \example Arrangement_on_surface_2/edge_manipulation.cpp
* \example Arrangement_on_surface_2/edge_manipulation_curve_history.cpp
* \example Arrangement_on_surface_2/ellipses.cpp
* \example Arrangement_on_surface_2/face_extension.cpp
* \example Arrangement_on_surface_2/face_extension_overlay.cpp
* \example Arrangement_on_surface_2/generic_curve_data.cpp
* \example Arrangement_on_surface_2/global_insertion.cpp
* \example Arrangement_on_surface_2/global_removal.cpp
* \example Arrangement_on_surface_2/hyperbolas.cpp
* \example Arrangement_on_surface_2/incremental_insertion.cpp
* \example Arrangement_on_surface_2/io.cpp
* \example Arrangement_on_surface_2/io_curve_history.cpp
* \example Arrangement_on_surface_2/io_unbounded.cpp
* \example Arrangement_on_surface_2/isolated_vertices.cpp
* \example Arrangement_on_surface_2/linear_conics.cpp
* \example Arrangement_on_surface_2/observer.cpp
* \example Arrangement_on_surface_2/overlay.cpp
* \example Arrangement_on_surface_2/overlay_color.cpp
* \example Arrangement_on_surface_2/overlay_unbounded.cpp
* \example Arrangement_on_surface_2/parabolas.cpp
* \example Arrangement_on_surface_2/point_location.cpp
* \example Arrangement_on_surface_2/polycurve_bezier.cpp
* \example Arrangement_on_surface_2/polycurve_circular_arc.cpp
* \example Arrangement_on_surface_2/polycurve_conic.cpp
* \example Arrangement_on_surface_2/polycurve_geodesic.cpp
* \example Arrangement_on_surface_2/polylines.cpp
* \example Arrangement_on_surface_2/predefined_kernel.cpp
* \example Arrangement_on_surface_2/predefined_kernel_non_intersecting.cpp
* \example Arrangement_on_surface_2/rational_functions.cpp
* \example Arrangement_on_surface_2/special_edge_insertion.cpp
* \example Arrangement_on_surface_2/spherical_insert.cpp
* \example Arrangement_on_surface_2/unbounded_non_intersecting.cpp
* \example Arrangement_on_surface_2/unbounded_rational_functions.cpp
* \example Arrangement_on_surface_2/unb_planar_vertical_decomposition.cpp
* \example Arrangement_on_surface_2/vertical_ray_shooting.cpp
*/

View File

@ -15,16 +15,21 @@ foreach(cppfile ${cppfiles})
create_single_source_cgal_program("${cppfile}")
endforeach()
if(CGAL_Qt6_FOUND)
target_link_libraries(draw_arr PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(linear_conics PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(parabolas PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(ellipses PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(hyperbolas PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(polylines PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(circles PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(circular_arcs PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(draw_arr PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(draw_agas PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(ellipses PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(hyperbolas PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(linear_conics PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(parabolas PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(polylines PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(rational_functions PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(spherical_insert PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(spherical_overlay PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(unbounded_non_intersecting PRIVATE CGAL::CGAL_Basic_viewer)
else()
message(
STATUS

View File

@ -21,14 +21,15 @@ int main() {
// Locate the vertex with maximal degree.
auto vit = arr.vertices_begin();
Arrangement::Vertex_const_handle v_max = vit;
for (++vit; vit != arr.vertices_end(); ++vit)
if (vit->degree() > v_max->degree()) v_max = vit;
for(++vit; vit != arr.vertices_end(); ++vit)
if(vit->degree() > v_max->degree()) v_max = vit;
// Locate the vertex with maximum degree.
std::cout << "The vertex with maximal degree in the arrangement is: "
<< "v_max = (" << v_max->point() << ") "
<< "with degree " << v_max->degree() << "." << std::endl;
CGAL::draw(arr);
CGAL::draw(arr, "circles");
return 0;
}

View File

@ -24,8 +24,7 @@ int main() {
// Create a line segment (C4) with the same supporting line (y = x), but
// having one endpoint with irrational coordinates.
CoordNT sqrt_15 = CoordNT(0, 1, 15); // = sqrt(15)
curves.push_back(Curve(s3.supporting_line(),
Point(3, 3), Point(sqrt_15, sqrt_15)));
curves.push_back(Curve(s3.supporting_line(), Point(3, 3), Point(sqrt_15, sqrt_15)));
// Create a circular arc (C5) that is the upper half of the circle centered at
// (1, 1) with squared radius 3. Create the circle with clockwise orientation,
@ -51,13 +50,12 @@ int main() {
// Create a circular arc (C7) defined by two endpoints and a midpoint,
// all having rational coordinates. This arc is the upper right
// quarter of a circle centered at the origin with radius 5.
curves.push_back(Curve(Rational_point(0, 5), Rational_point(3, 4),
Rational_point(5, 0)));
curves.push_back(Curve(Rational_point(0, 5), Rational_point(3, 4), Rational_point(5, 0)));
// Construct the arrangement of the curves and print its size.
Arrangement arr;
Arrangement arr;
insert(arr, curves.begin(), curves.end());
print_arrangement_size(arr);
CGAL::draw(arr);
CGAL::draw(arr, "circular_arcs");
return 0;
}

View File

@ -0,0 +1,106 @@
#include <vector>
#include <CGAL/draw_arrangement_2.h>
#include "arr_geodesic.h"
#include "arr_print.h"
void draw_face_crossing_boundary() {
Arrangement arr;
const auto& traits = *arr.geometry_traits();
auto ctr_p = traits.construct_point_2_object();
auto ctr_cv = traits.construct_curve_2_object();
auto p1 = ctr_p(-0.95, 0.32, 0), p2 = ctr_p(-0.87, 0.02, 0.49), p3 = ctr_p(-0.93, -0.36, 0),
p4 = ctr_p(-0.81, -0.03, -0.59);
auto arcs = {ctr_cv(p1, p2), ctr_cv(p2, p3), ctr_cv(p3, p4), ctr_cv(p4, p1)};
CGAL::insert(arr, arcs.begin(), arcs.end());
print_arrangement_size(arr);
CGAL::draw(arr, "face crossing boundary");
}
void draw_lakes() {
Arrangement arr;
const auto& traits = *arr.geometry_traits();
auto ctr_p = traits.construct_point_2_object();
auto ctr_cv = traits.construct_curve_2_object();
auto poly1 = {
ctr_p(-0.27, -0.053, -0.96), ctr_p(-0.76, -0.15, -0.63), ctr_p(-0.98, -0.19, -0.063), ctr_p(-0.98, -0.098, 0.2),
ctr_p(-0.44, -0.18, 0.88), ctr_p(0.39, -0.0049, 0.92), ctr_p(-0.01, 0.39, 0.92), ctr_p(-0.54, 0.66, 0.53),
ctr_p(-0.83, 0.56, 0.025), ctr_p(-0.57, 0.32, -0.75), ctr_p(-0.087, 0.048, -1), ctr_p(-0.048, 0.088, -1),
ctr_p(0.12, -0.14, -0.98), ctr_p(-0.12, -0.14, -0.98),
};
auto poly2 = {ctr_p(-0.24, -0.53, -0.81), ctr_p(-0.47, -0.54, -0.69), ctr_p(-0.68, -0.65, -0.32),
ctr_p(-0.71, -0.68, 0.2), ctr_p(-0.54, -0.52, 0.67), ctr_p(-0.18, -0.72, 0.67),
ctr_p(0.31, -0.68, 0.67), ctr_p(0.71, -0.69, 0.11), ctr_p(0.6, -0.58, -0.56),
ctr_p(0.21, -0.62, -0.75)};
auto poly3 = {ctr_p(0.44, 0.27, -0.86), ctr_p(0.58, -0.063, -0.81), ctr_p(0.87, -0.094, -0.48),
ctr_p(0.97, -0.1, 0.2), ctr_p(0.46, 0.77, 0.45), ctr_p(-0.023, 0.89, 0.45),
ctr_p(-0.3, 0.95, 0.11), ctr_p(-0.22, 0.69, -0.69), ctr_p(-0.076, 0.35, -0.93)};
auto poly4 = {
ctr_p(0.4, 0.67, -0.63), ctr_p(0.78, 0.39, -0.48), ctr_p(0.92, 0.35, -0.15),
ctr_p(0.52, 0.86, 0.025), ctr_p(0.068, 0.99, -0.15), ctr_p(0.22, 0.85, -0.48),
};
std::vector<Curve> arcs;
std::vector<std::vector<Point>> polygons{poly1, poly2, poly3, poly4};
for(const auto& poly : polygons) {
for(size_t i = 0; i < poly.size(); ++i) {
size_t next = (i + 1) % poly.size();
arcs.push_back(ctr_cv(poly[i], poly[next]));
}
}
CGAL::insert(arr, arcs.begin(), arcs.end());
print_arrangement_size(arr);
CGAL::draw(arr, "lakes");
}
void draw_gaussian_map() {
Arrangement arr;
const auto& traits = *arr.geometry_traits();
auto ctr_p = traits.construct_point_2_object();
auto ctr_cv = traits.construct_curve_2_object();
auto p1 = ctr_p(1, 1, 1), p2 = ctr_p(-1, -1, 1), p3 = ctr_p(-1, 1, -1), p4 = ctr_p(1, -1, -1);
auto arcs = {ctr_cv(p1, p2), ctr_cv(p2, p3), ctr_cv(p3, p1), ctr_cv(p1, p4), ctr_cv(p2, p4), ctr_cv(p3, p4)};
CGAL::insert(arr, arcs.begin(), arcs.end());
print_arrangement_size(arr);
CGAL::draw(arr, "gaussian map of a tetrahedron");
}
void draw_random_arcs(int n) {
Arrangement arr;
const auto& traits = *arr.geometry_traits();
auto ctr_p = traits.construct_point_2_object();
auto ctr_cv = traits.construct_curve_2_object();
CGAL::Random random;
std::vector<Point> points;
for(int i = 0; i < n; ++i) {
double x = random.get_double(-1.0, 1.0);
double y = random.get_double(-1.0, 1.0);
double z = random.get_double(-1.0, 1.0);
points.push_back(ctr_p(x, y, z));
}
std::vector<Curve> curves;
for(int i = 0; i < n; ++i) {
int j = random.get_int(0, n - 1);
if(i == j)
j = (j + 1) % n;
curves.push_back(ctr_cv(points[i], points[j]));
}
CGAL::insert(arr, curves.begin(), curves.end());
print_arrangement_size(arr);
CGAL::draw(arr, (std::to_string(n) + " random arcs").c_str());
}
int main() {
draw_face_crossing_boundary();
draw_lakes();
draw_gaussian_map();
draw_random_arcs(100);
return 0;
}

View File

@ -1,13 +1,13 @@
#include <string>
#include <CGAL/Random.h>
#include <CGAL/Arr_linear_traits_2.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Arrangement_2.h>
#include <CGAL/Arr_segment_traits_2.h>
#include <CGAL/Arr_non_caching_segment_traits_2.h>
#include <CGAL/draw_arrangement_2.h>
using Kernel = CGAL::Exact_predicates_exact_constructions_kernel;
using Traits = CGAL::Arr_segment_traits_2<Kernel>;
using Point = Traits::Point_2;
using Arrangement_2 = CGAL::Arrangement_2<Traits>;
/*! Convert HSV to RGB color space
* Converts a given set of HSV values `h', `s', `v' into RGB coordinates.
* The output RGB values are in the range [0, 255], and the input HSV values
@ -17,9 +17,8 @@ using Arrangement_2 = CGAL::Arrangement_2<Traits>;
* \param sat Saturation component range: [0, 1]
* \param value Value component range: [0, 1]
* \return tuple<red, green, blue>, where each component is in the range [0, 255]
*/
std::tuple<unsigned char, unsigned char, unsigned char>
hsv_to_rgb(float hue, float sat, float value) {
*/
std::tuple<unsigned char, unsigned char, unsigned char> hsv_to_rgb(float hue, float sat, float value) {
float red, green, blue;
float fc = value * sat; // Chroma
float hue_prime = fmod(hue / 60.0f, 6.f);
@ -75,49 +74,175 @@ hsv_to_rgb(float hue, float sat, float value) {
return std::make_tuple(redc, greenc, bluec);
}
int main() {
void draw_rect() {
using Kernel = CGAL::Exact_predicates_exact_constructions_kernel;
using Traits = CGAL::Arr_non_caching_segment_traits_2<Kernel>;
using Point = Traits::Point_2;
using Arrangement = CGAL::Arrangement_2<Traits>;
Traits traits;
Arrangement_2 arr(&traits);
Arrangement arr(&traits);
auto ctr_xcv = traits.construct_x_monotone_curve_2_object();
CGAL::insert(arr, ctr_xcv(Point(-2,-2), Point(2,-2)));
CGAL::insert(arr, ctr_xcv(Point(2,-2), Point(2,2)));
CGAL::insert(arr, ctr_xcv(Point(2,2), Point(-2,2)));
CGAL::insert(arr, ctr_xcv(Point(-2,2), Point(-2,-2)));
CGAL::insert(arr, ctr_xcv(Point(-2, -2), Point(2, -2)));
CGAL::insert(arr, ctr_xcv(Point(2, -2), Point(2, 2)));
CGAL::insert(arr, ctr_xcv(Point(2, 2), Point(-2, 2)));
CGAL::insert(arr, ctr_xcv(Point(-2, 2), Point(-2, -2)));
CGAL::insert(arr, ctr_xcv(Point(-1,-1), Point(1,-1)));
CGAL::insert(arr, ctr_xcv(Point(1,-1), Point(1,1)));
CGAL::insert(arr, ctr_xcv(Point(1,1), Point(-1,1)));
CGAL::insert(arr, ctr_xcv(Point(-1,1), Point(-1,-1)));
CGAL::insert(arr, ctr_xcv(Point(-1, -1), Point(1, -1)));
CGAL::insert(arr, ctr_xcv(Point(1, -1), Point(1, 1)));
CGAL::insert(arr, ctr_xcv(Point(1, 1), Point(-1, 1)));
CGAL::insert(arr, ctr_xcv(Point(-1, 1), Point(-1, -1)));
CGAL::insert(arr, ctr_xcv(Point(-2,-2), Point(-2,-4)));
CGAL::insert(arr, ctr_xcv(Point(2,-2), Point(4,-2)));
CGAL::insert(arr, ctr_xcv(Point(-2, -2), Point(-2, -4)));
CGAL::insert(arr, ctr_xcv(Point(2, -2), Point(4, -2)));
CGAL::insert(arr, ctr_xcv(Point(0,0), Point(0,-3)));
CGAL::insert(arr, ctr_xcv(Point(0, 0), Point(0, -3)));
std::cout << arr.number_of_vertices() << ", "
<< arr.number_of_edges() << ", "
<< arr.number_of_faces() << std::endl;
std::cout << arr.number_of_vertices() << ", " << arr.number_of_edges() << ", " << arr.number_of_faces() << std::endl;
std::size_t id(0);
CGAL::Graphics_scene_options<Arrangement, typename Arrangement::Vertex_const_handle,
typename Arrangement::Halfedge_const_handle, typename Arrangement::Face_const_handle>
gso;
gso.colored_face = [](const Arrangement&, Arrangement::Face_const_handle) -> bool { return true; };
CGAL::Graphics_scene_options<Arrangement_2,
typename Arrangement_2::Vertex_const_handle,
typename Arrangement_2::Halfedge_const_handle,
typename Arrangement_2::Face_const_handle> gso;
gso.colored_face=[](const Arrangement_2&, Arrangement_2::Face_const_handle) -> bool
{ return true; };
gso.face_color = [](const Arrangement&, Arrangement::Face_const_handle fh) -> CGAL::IO::Color {
CGAL::Random random((size_t(fh.ptr())));
float h = 360.0f * random.get_double(0, 1);
float s = 0.5;
float v = 0.5;
auto [r, g, b] = hsv_to_rgb(h, s, v);
return CGAL::IO::Color(r, g, b);
};
gso.face_color=[&id](const Arrangement_2& arr, Arrangement_2::Face_const_handle) -> CGAL::IO::Color
{
float h = 360.0f * id++ / arr.number_of_faces();
float s = 0.5;
float v = 0.5;
auto [r, g, b] = hsv_to_rgb(h, s, v);
return CGAL::IO::Color(r,g,b);
};
CGAL::draw(arr, gso, "hsv colors");
return EXIT_SUCCESS;
CGAL::draw(arr, gso, "rect with hsv colors");
}
void draw_nested() {
using Kernel = CGAL::Exact_predicates_exact_constructions_kernel;
using Traits = CGAL::Arr_segment_traits_2<Kernel>;
using Point = Traits::Point_2;
using Arrangement = CGAL::Arrangement_2<Traits>;
using X_monotone_curve = Traits::X_monotone_curve_2;
Arrangement arr;
auto traits = arr.traits();
auto ctr_xcv = traits->construct_x_monotone_curve_2_object();
std::vector<X_monotone_curve> curves;
{
// a hexagon centered at the origin
const double r = 10.0;
for (int i = 0; i < 6; ++i) {
int next = (i + 1) % 6;
Point source(r * cos(i * CGAL_PI / 3), r * sin(i * CGAL_PI / 3));
Point target(r * cos(next * CGAL_PI / 3), r * sin(next * CGAL_PI / 3));
curves.push_back(ctr_xcv(source, target));
}
}
{
// a square inside the hexagon
const double size = 4.0;
Point p1(-size, size), p2(size, size), p3(size, -size), p4(-size, -size);
auto rect = {ctr_xcv(p1, p2), ctr_xcv(p2, p3), ctr_xcv(p3, p4), ctr_xcv(p4, p1)};
curves.insert(curves.end(), rect.begin(), rect.end());
}
{
// two adjacent triangle inside the square
Point p1(-1, 0), p2(1, 0), p3(0, sqrt(3)), p4(0, -sqrt(3));
auto tri1 = {ctr_xcv(p1, p2), ctr_xcv(p2, p3), ctr_xcv(p3, p1)};
auto tri2 = {ctr_xcv(p1, p2), ctr_xcv(p2, p4), ctr_xcv(p4, p1)};
curves.insert(curves.end(), tri1.begin(), tri1.end());
curves.insert(curves.end(), tri2.begin(), tri2.end());
}
// a degenerate hole inside the square
auto degen_seg = ctr_xcv({-1, -3}, {1, -3});
curves.push_back(degen_seg);
// an isolated vertex inside the square
auto iso_point = Point{1, -1};
CGAL::insert(arr, curves.begin(), curves.end());
CGAL::insert_point(arr, iso_point);
CGAL::draw(arr, "nested polygons");
}
void draw_unbounded_linear_grid() {
using Kernel = CGAL::Exact_predicates_exact_constructions_kernel;
using Traits = CGAL::Arr_linear_traits_2<Kernel>;
using Point = Traits::Point_2;
using Segment = Traits::Segment_2;
using Line = Traits::Line_2;
using X_monotone_curve = Traits::X_monotone_curve_2;
using Arrangement = CGAL::Arrangement_2<Traits>;
Arrangement arr;
// Insert a n*n grid
int n = 5;
for (int i = 0; i < n; ++i) {
Point p1(i * 5, 0);
Point p2(i * 5, 1);
CGAL::insert(arr, X_monotone_curve(Line(p1, p2)));
}
for (int i = 0; i < n; ++i) {
Point p1(0, i * 5);
Point p2(1, i * 5);
CGAL::insert(arr, X_monotone_curve(Line(p1, p2)));
}
// Generate a inner square(2*2) for all cells
// And an inner triangle for each square
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
Point p1(i * 5 + 1, j * 5 + 1);
Point p2(i * 5 + 4, j * 5 + 4);
CGAL::insert(arr, X_monotone_curve(Segment(p1, Point(p2.x(), p1.y()))));
CGAL::insert(arr, X_monotone_curve(Segment(Point(p1.x(), p2.y()), p2)));
CGAL::insert(arr, X_monotone_curve(Segment(p1, Point(p1.x(), p2.y()))));
CGAL::insert(arr, X_monotone_curve(Segment(Point(p2.x(), p1.y()), p2)));
// Insert a triangle inside the square
Point tri_p1(i * 5 + 2, j * 5 + 2);
Point tri_p2(i * 5 + 3, j * 5 + 2);
Point tri_p3(i * 5 + 2.5, j * 5 + 3);
CGAL::insert(arr, X_monotone_curve(Segment(tri_p1, tri_p2)));
CGAL::insert(arr, X_monotone_curve(Segment(tri_p2, tri_p3)));
CGAL::insert(arr, X_monotone_curve(Segment(tri_p3, tri_p1)));
// Connect the triangle to the square
Point top(i * 5 + 2.5, j * 5 + 4);
CGAL::insert(arr, X_monotone_curve(Segment(tri_p1, top)));
}
}
CGAL::draw(arr, "unbounded linear grid");
}
void draw_random_segments(int n) {
using Kernel = CGAL::Exact_predicates_exact_constructions_kernel;
using Traits = CGAL::Arr_segment_traits_2<Kernel>;
using Point = Traits::Point_2;
using Arrangement = CGAL::Arrangement_2<Traits>;
using X_monotone_curve = Traits::X_monotone_curve_2;
Arrangement arr;
auto traits = arr.traits();
auto ctr_xcv = traits->construct_x_monotone_curve_2_object();
CGAL::Random random;
std::vector<X_monotone_curve> curves;
for (int i = 0; i < n; ++i) {
double x1 = random.get_double(-100, 100);
double y1 = random.get_double(-100, 100);
double x2 = random.get_double(-100, 100);
double y2 = random.get_double(-100, 100);
curves.push_back(ctr_xcv(Point(x1, y1), Point(x2, y2)));
}
CGAL::insert(arr, curves.begin(), curves.end());
CGAL::draw(arr, (std::to_string(n) + " random segments").c_str());
}
int main() {
draw_rect();
draw_nested();
draw_unbounded_linear_grid();
draw_random_segments(100);
return EXIT_SUCCESS;
}

View File

@ -17,14 +17,10 @@ int main() {
auto ctr_cv = traits.construct_curve_2_object();
// Insert a full x-major ellipse
CGAL::insert(arr, ctr_cv(1, 4, 0, 0, 0, -16, CGAL::COUNTERCLOCKWISE,
Point(4,0), Point(0,2)));
CGAL::insert(arr, ctr_cv(1, 4, 0, 0, 0, -16, CGAL::COUNTERCLOCKWISE,
Point(0,2), Point(-4,0)));
CGAL::insert(arr, ctr_cv(1, 4, 0, 0, 0, -16, CGAL::COUNTERCLOCKWISE,
Point(-4,0), Point(0,-2)));
CGAL::insert(arr, ctr_cv(1, 4, 0, 0, 0, -16, CGAL::COUNTERCLOCKWISE,
Point(0,-2), Point(4,0)));
CGAL::insert(arr, ctr_cv(1, 4, 0, 0, 0, -16, CGAL::COUNTERCLOCKWISE, Point(4, 0), Point(0, 2)));
CGAL::insert(arr, ctr_cv(1, 4, 0, 0, 0, -16, CGAL::COUNTERCLOCKWISE, Point(0, 2), Point(-4, 0)));
CGAL::insert(arr, ctr_cv(1, 4, 0, 0, 0, -16, CGAL::COUNTERCLOCKWISE, Point(-4, 0), Point(0, -2)));
CGAL::insert(arr, ctr_cv(1, 4, 0, 0, 0, -16, CGAL::COUNTERCLOCKWISE, Point(0, -2), Point(4, 0)));
// Insert a full y-major ellipse
CGAL::insert(arr, ctr_cv(4, 1, 0, 0, 0, -16));
@ -39,7 +35,7 @@ int main() {
print_arrangement_size(arr);
CGAL::draw(arr);
CGAL::draw(arr, "ellipses");
return 0;
}

View File

@ -19,63 +19,46 @@ int main() {
// Insert a hyperbolic arc (C1), supported by the hyperbola y = 1/x
// (or: xy - 1 = 0) with the endpoints (1/4, 4) and (2, 1/2).
// The arc is counterclockwise oriented.
CGAL::insert(arr, ctr_cv(0, 0, 1, 0, 0, -1, CGAL::COUNTERCLOCKWISE,
Point(Rational(1,4), 4), Point(2, Rational(1,2))));
CGAL::insert(arr, ctr_cv(0, 0, -1, 0, 0, -1, CGAL::CLOCKWISE,
Point(Rational(-1,4), 4), Point(-2, Rational(1,2))));
CGAL::insert(arr,
ctr_cv(0, 0, 1, 0, 0, -1, CGAL::COUNTERCLOCKWISE, Point(Rational(1, 4), 4), Point(2, Rational(1, 2))));
CGAL::insert(arr, ctr_cv(0, 0, -1, 0, 0, -1, CGAL::CLOCKWISE, Point(Rational(-1, 4), 4), Point(-2, Rational(1, 2))));
CGAL::insert(arr, ctr_cv(2, -1, 0, 0, 0, -2, CGAL::COUNTERCLOCKWISE,
Point(3, 4), Point(1, 0)));
CGAL::insert(arr, ctr_cv(2, -1, 0, 0, 0, -2, CGAL::COUNTERCLOCKWISE,
Point(1, 0), Point(3, -4)));
CGAL::insert(arr, ctr_cv(2, -1, 0, 0, 0, -2, CGAL::CLOCKWISE,
Point(-3, 4), Point(-1, 0)));
CGAL::insert(arr, ctr_cv(2, -1, 0, 0, 0, -2, CGAL::CLOCKWISE,
Point(-1, 0), Point(-3, -4)));
CGAL::insert(arr, ctr_cv(2, -1, 0, 0, 0, -2, CGAL::COUNTERCLOCKWISE, Point(3, 4), Point(1, 0)));
CGAL::insert(arr, ctr_cv(2, -1, 0, 0, 0, -2, CGAL::COUNTERCLOCKWISE, Point(1, 0), Point(3, -4)));
CGAL::insert(arr, ctr_cv(2, -1, 0, 0, 0, -2, CGAL::CLOCKWISE, Point(-3, 4), Point(-1, 0)));
CGAL::insert(arr, ctr_cv(2, -1, 0, 0, 0, -2, CGAL::CLOCKWISE, Point(-1, 0), Point(-3, -4)));
CGAL::insert(arr, ctr_cv(-1, 2, 0, 0, 0, -2, CGAL::CLOCKWISE,
Point(4, 3), Point(0, 1)));
CGAL::insert(arr, ctr_cv(-1, 2, 0, 0, 0, -2, CGAL::CLOCKWISE,
Point(0, 1), Point(-4, 3)));
CGAL::insert(arr, ctr_cv(-1, 2, 0, 0, 0, -2, CGAL::COUNTERCLOCKWISE,
Point(4, -3), Point(0, -1)));
CGAL::insert(arr, ctr_cv(-1, 2, 0, 0, 0, -2, CGAL::COUNTERCLOCKWISE,
Point(0, -1), Point(-4, -3)));
CGAL::insert(arr, ctr_cv(-1, 2, 0, 0, 0, -2, CGAL::CLOCKWISE, Point(4, 3), Point(0, 1)));
CGAL::insert(arr, ctr_cv(-1, 2, 0, 0, 0, -2, CGAL::CLOCKWISE, Point(0, 1), Point(-4, 3)));
CGAL::insert(arr, ctr_cv(-1, 2, 0, 0, 0, -2, CGAL::COUNTERCLOCKWISE, Point(4, -3), Point(0, -1)));
CGAL::insert(arr, ctr_cv(-1, 2, 0, 0, 0, -2, CGAL::COUNTERCLOCKWISE, Point(0, -1), Point(-4, -3)));
CGAL::insert(arr, ctr_cv(4, 46, -144, 0, 0, -100, CGAL::COUNTERCLOCKWISE,
Point(-5, 0),
CGAL::insert(arr, ctr_cv(4, 46, -144, 0, 0, -100, CGAL::COUNTERCLOCKWISE, Point(-5, 0),
Point(Rational(14, 10), Rational(48, 10))));
CGAL::insert(arr, ctr_cv(4, 46, -144, 0, 0, -100, CGAL::COUNTERCLOCKWISE,
Point(5, 0),
CGAL::insert(arr, ctr_cv(4, 46, -144, 0, 0, -100, CGAL::COUNTERCLOCKWISE, Point(5, 0),
Point(Rational(-14, 10), Rational(-48, 10))));
// 4*x*x + 46*y*y - 144*x*y - 100
CGAL::insert(arr, ctr_cv(46, 4, -144, 0, 0, -100, CGAL::CLOCKWISE,
Point(0, -5),
Point(Rational(48, 10), Rational(14, 10))));
CGAL::insert(arr, ctr_cv(46, 4, -144, 0, 0, -100, CGAL::CLOCKWISE,
Point(0, 5),
Point(Rational(-48, 10), Rational(-14, 10))));
CGAL::insert(
arr, ctr_cv(46, 4, -144, 0, 0, -100, CGAL::CLOCKWISE, Point(0, -5), Point(Rational(48, 10), Rational(14, 10))));
CGAL::insert(
arr, ctr_cv(46, 4, -144, 0, 0, -100, CGAL::CLOCKWISE, Point(0, 5), Point(Rational(-48, 10), Rational(-14, 10))));
// 46*x*x + 4*y*y - 144*x*y - 100
CGAL::insert(arr, ctr_cv(4, 46, 144, 0, 0, -100, CGAL::CLOCKWISE,
Point(-5, 0),
Point(Rational(14,10), Rational(-48,10))));
CGAL::insert(arr, ctr_cv(4, 46, 144, 0, 0, -100, CGAL::CLOCKWISE,
Point(5, 0),
Point(Rational(-14,10), Rational(48,10))));
CGAL::insert(
arr, ctr_cv(4, 46, 144, 0, 0, -100, CGAL::CLOCKWISE, Point(-5, 0), Point(Rational(14, 10), Rational(-48, 10))));
CGAL::insert(
arr, ctr_cv(4, 46, 144, 0, 0, -100, CGAL::CLOCKWISE, Point(5, 0), Point(Rational(-14, 10), Rational(48, 10))));
// 4*x*x + 46*y*y + 144*x*y - 100
CGAL::insert(arr, ctr_cv(46, 4, 144, 0, 0, -100, CGAL::COUNTERCLOCKWISE,
Point(0, -5),
Point(Rational(-48,10), Rational(14,10))));
CGAL::insert(arr, ctr_cv(46, 4, 144, 0, 0, -100, CGAL::COUNTERCLOCKWISE,
Point(0, 5),
Point(Rational(48,10), Rational(-14,10))));
CGAL::insert(arr, ctr_cv(46, 4, 144, 0, 0, -100, CGAL::COUNTERCLOCKWISE, Point(0, -5),
Point(Rational(-48, 10), Rational(14, 10))));
CGAL::insert(arr, ctr_cv(46, 4, 144, 0, 0, -100, CGAL::COUNTERCLOCKWISE, Point(0, 5),
Point(Rational(48, 10), Rational(-14, 10))));
print_arrangement_size(arr);
CGAL::draw(arr);
CGAL::draw(arr, "hyperbolas");
return 0;
}

View File

@ -20,8 +20,8 @@ int main() {
Point p2(0, -1);
Point p3(0, 1);
Point p4(1, 0);
Point p5(Rational(1,2),Rational(1,2));
Point p6(Rational(-1,2),Rational(1,2));
Point p5(Rational(1, 2), Rational(1, 2));
Point p6(Rational(-1, 2), Rational(1, 2));
Rat_point rp0(0, 0);
Rat_point rp1(1, 0);
Rat_point rp2(0, 1);
@ -56,7 +56,7 @@ int main() {
print_arrangement_size(arr);
CGAL::draw(arr);
CGAL::draw(arr, "linear_conics");
return 0;
}

View File

@ -18,62 +18,49 @@ int main() {
// x-major
// insert the parabola y = x^2; (-1,1)--(1,1)
CGAL::insert(arr, ctr_cv(1, 0, 0, 0, -1, 0, CGAL::COUNTERCLOCKWISE,
Point(-1, 1), Point(1, 1)));
CGAL::insert(arr, ctr_cv(1, 0, 0, 0, -1, 0, CGAL::COUNTERCLOCKWISE, Point(-1, 1), Point(1, 1)));
// translated
// Insert the parabola y = x^2 - 2x + 2; (1,1)--(2,2)
CGAL::insert(arr, ctr_cv(1, 0, 0, -2, -1, 2, CGAL::COUNTERCLOCKWISE,
Point(1, 1), Point(2, 2)));
CGAL::insert(arr, ctr_cv(1, 0, 0, 2, -1, 2, CGAL::COUNTERCLOCKWISE,
Point(-2, 2), Point(-1, 1)));
CGAL::insert(arr, ctr_cv(1, 0, 0, -2, -1, 2, CGAL::COUNTERCLOCKWISE, Point(1, 1), Point(2, 2)));
CGAL::insert(arr, ctr_cv(1, 0, 0, 2, -1, 2, CGAL::COUNTERCLOCKWISE, Point(-2, 2), Point(-1, 1)));
// rotated
// Insert the parabola y = x^2 rotated clockwise about theta, such that
// sin(theta) = 0.6, cos(theta) = 0.8
CGAL::insert(arr, ctr_cv(16, 9, -24, -15, -20, 0, CGAL::COUNTERCLOCKWISE,
Point(Rational(-2,10), Rational(14,10)),
Point(Rational(14,10), Rational(2,10))));
CGAL::insert(arr, ctr_cv(16, 9, 24, 15, -20, 0, CGAL::CLOCKWISE,
Point(Rational(2,10), Rational(14,10)),
Point(Rational(-14,10), Rational(2,10))));
CGAL::insert(arr, ctr_cv(16, 9, 24, -15, 20, 0, CGAL::COUNTERCLOCKWISE,
Point(Rational(14,10), Rational(-2,10)),
Point(Rational(-2,10), Rational(-14,10))));
CGAL::insert(arr, ctr_cv(16, 9, -24, 15, 20, 0, CGAL::COUNTERCLOCKWISE,
Point(Rational(2,10), Rational(-14,10)),
Point(Rational(-14,10), Rational(-2,10))));
CGAL::insert(arr, ctr_cv(16, 9, -24, -15, -20, 0, CGAL::COUNTERCLOCKWISE, Point(Rational(-2, 10), Rational(14, 10)),
Point(Rational(14, 10), Rational(2, 10))));
CGAL::insert(arr, ctr_cv(16, 9, 24, 15, -20, 0, CGAL::CLOCKWISE, Point(Rational(2, 10), Rational(14, 10)),
Point(Rational(-14, 10), Rational(2, 10))));
CGAL::insert(arr, ctr_cv(16, 9, 24, -15, 20, 0, CGAL::COUNTERCLOCKWISE, Point(Rational(14, 10), Rational(-2, 10)),
Point(Rational(-2, 10), Rational(-14, 10))));
CGAL::insert(arr, ctr_cv(16, 9, -24, 15, 20, 0, CGAL::COUNTERCLOCKWISE, Point(Rational(2, 10), Rational(-14, 10)),
Point(Rational(-14, 10), Rational(-2, 10))));
// 16*x*x+9*y*y-24*x*y-15*x-20*y
CGAL::insert(arr, ctr_cv(9, 16, -24, -20, -15, 0, CGAL::COUNTERCLOCKWISE,
Point(Rational(2,10), Rational(14,10)),
Point(Rational(14,10), Rational(-2,10))));
CGAL::insert(arr, ctr_cv(9, 16, 24, -20, 15, 0, CGAL::CLOCKWISE,
Point(Rational(2,10), Rational(-14,10)),
Point(Rational(14,10), Rational(2,10))));
CGAL::insert(arr, ctr_cv(9, 16, 24, 20, -15, 0, CGAL::COUNTERCLOCKWISE,
Point(Rational(-14,10), Rational(-2,10)),
Point(Rational(-2,10), Rational(14,10))));
CGAL::insert(arr, ctr_cv(9, 16, -24, 20, 15, 0, CGAL::COUNTERCLOCKWISE,
Point(Rational(-2,10), Rational(-14,10)),
Point(Rational(-14,10), Rational(2,10))));
CGAL::insert(arr, ctr_cv(9, 16, -24, -20, -15, 0, CGAL::COUNTERCLOCKWISE, Point(Rational(2, 10), Rational(14, 10)),
Point(Rational(14, 10), Rational(-2, 10))));
CGAL::insert(arr, ctr_cv(9, 16, 24, -20, 15, 0, CGAL::CLOCKWISE, Point(Rational(2, 10), Rational(-14, 10)),
Point(Rational(14, 10), Rational(2, 10))));
CGAL::insert(arr, ctr_cv(9, 16, 24, 20, -15, 0, CGAL::COUNTERCLOCKWISE, Point(Rational(-14, 10), Rational(-2, 10)),
Point(Rational(-2, 10), Rational(14, 10))));
CGAL::insert(arr, ctr_cv(9, 16, -24, 20, 15, 0, CGAL::COUNTERCLOCKWISE, Point(Rational(-2, 10), Rational(-14, 10)),
Point(Rational(-14, 10), Rational(2, 10))));
// 9*x*x+16*y*y-24*x*y+20*x+15*y
// rotated & translated
CGAL::insert(arr, ctr_cv(16, 9, -24, -23, -14, 36, CGAL::COUNTERCLOCKWISE,
Point(Rational(8,10), Rational(24,10)),
Point(Rational(24,10), Rational(12,10))));
CGAL::insert(arr, ctr_cv(16, 9, 24, 23, -14, 36, CGAL::CLOCKWISE,
Point(Rational(-8,10), Rational(24,10)),
Point(Rational(-24,10), Rational(12,10))));
CGAL::insert(arr, ctr_cv(16, 9, -24, -23, -14, 36, CGAL::COUNTERCLOCKWISE, Point(Rational(8, 10), Rational(24, 10)),
Point(Rational(24, 10), Rational(12, 10))));
CGAL::insert(arr, ctr_cv(16, 9, 24, 23, -14, 36, CGAL::CLOCKWISE, Point(Rational(-8, 10), Rational(24, 10)),
Point(Rational(-24, 10), Rational(12, 10))));
// 16*x*x+9*y*y-24*x*y-23*x-14*y+36
print_arrangement_size(arr);
CGAL::draw(arr);
CGAL::draw(arr, "parabolas");
return 0;
}

View File

@ -45,7 +45,7 @@ int main() {
insert(arr, pi1);
insert(arr, pi2);
insert(arr, pi3);
print_arrangement_size(arr); // print the arrangement size
CGAL::draw(arr);
print_arrangement_size(arr); // print the arrangement size
CGAL::draw(arr, "polylines");
return 0;
}

View File

@ -17,7 +17,7 @@ int main() {
#include "arr_print.h"
int main() {
CGAL::IO::set_pretty_mode(std::cout); // for nice printouts.
CGAL::IO::set_pretty_mode(std::cout); // for nice printouts.
// Define a traits class object and a constructor for rational functions.
Traits traits;
@ -31,24 +31,24 @@ int main() {
// Create an arc (C1) supported by the polynomial y = x^4 - 6x^2 + 8,
// defined over the (approximate) interval [-2.1, 2.1].
Polynomial P1 = CGAL::ipower(x,4) - 6*x*x + 8;
Polynomial P1 = CGAL::ipower(x, 4) - 6 * x * x + 8;
Alg_real l(Bound(-2.1)), r(Bound(2.1));
arcs.push_back(construct(P1, l, r));
// Create an arc (C2) supported by the function y = x / (1 + x^2),
// defined over the interval [-3, 3].
Polynomial P2 = x;
Polynomial Q2 = 1 + x*x;
Polynomial Q2 = 1 + x * x;
arcs.push_back(construct(P2, Q2, Alg_real(-3), Alg_real(3)));
// Create an arc (C3) supported by the parbola y = 8 - x^2,
// defined over the interval [-2, 3].
Polynomial P3 = 8 - x*x;
Polynomial P3 = 8 - x * x;
arcs.push_back(construct(P3, Alg_real(-2), Alg_real(3)));
// Create an arc (C4) supported by the line y = -2x,
// defined over the interval [-3, 0].
Polynomial P4 = -2*x;
Polynomial P4 = -2 * x;
arcs.push_back(construct(P4, Alg_real(-3), Alg_real(0)));
// Construct the arrangement of the four arcs.

View File

@ -1,6 +1,5 @@
//! \file examples/Arrangement_on_surface_2/spherical_insert.cpp
// Constructing an arrangement of arcs of great circles.
#include <list>
#include <cmath>
#include <cstdio>
@ -9,6 +8,7 @@
#include <CGAL/Arrangement_on_surface_2.h>
#include <CGAL/Arr_geodesic_arc_on_sphere_traits_2.h>
#include <CGAL/Arr_spherical_topology_traits_2.h>
#include <CGAL/draw_arrangement_2.h>
#include "arr_geodesic.h"
#include "arr_print.h"
@ -20,12 +20,11 @@ int main() {
Arrangement arr(&traits);
Point p1 = ctr_p(0, 0, -1), p3 = ctr_p(0, -1, 0), p5 = ctr_p(-1, 0, 0);
Point p2 = ctr_p(0, 0, 1), p4 = ctr_p(0, 1, 0), p6 = ctr_p( 1, 0, 0);
Curve arcs[] = {
ctr_cv(p6, p1), ctr_cv(p6, p2), ctr_cv(p4, p1), ctr_cv(p4, p2),
ctr_cv(p5, p1), ctr_cv(p5, p2), ctr_cv(p3, p1), ctr_cv(p3, p2),
ctr_cv(p6, p4), ctr_cv(p6, p3), ctr_cv(p5, p4), ctr_cv(p5, p3) };
CGAL::insert(arr, arcs, arcs + sizeof(arcs)/sizeof(Curve));
Point p2 = ctr_p(0, 0, 1), p4 = ctr_p(0, 1, 0), p6 = ctr_p(1, 0, 0);
Curve arcs[] = {ctr_cv(p6, p1), ctr_cv(p6, p2), ctr_cv(p4, p1), ctr_cv(p4, p2), ctr_cv(p5, p1), ctr_cv(p5, p2),
ctr_cv(p3, p1), ctr_cv(p3, p2), ctr_cv(p6, p4), ctr_cv(p6, p3), ctr_cv(p5, p4), ctr_cv(p5, p3)};
CGAL::insert(arr, arcs, arcs + sizeof(arcs) / sizeof(Curve));
print_arrangement_size(arr);
CGAL::draw(arr, "spherical insert");
return 0;
}

View File

@ -3,6 +3,7 @@
#include <CGAL/Arr_overlay_2.h>
#include <CGAL/Arr_default_overlay_traits.h>
#include <CGAL/draw_arrangement_2.h>
#include "arr_geodesic_on_sphere.h"
@ -34,8 +35,8 @@ int main() {
Arrangement overlay_arr;
Overlay_traits overlay_traits;
overlay(arr1, arr2, overlay_arr, overlay_traits);
std::cout << "No. of vertices: " << overlay_arr.number_of_vertices()
<< std::endl;
std::cout << "No. of vertices: " << overlay_arr.number_of_vertices() << std::endl;
CGAL::draw(overlay_arr, "spherical overlay");
return 0;
}

View File

@ -4,6 +4,7 @@
#include <cassert>
#include "CGAL/draw_arrangement_2.h"
#include "arr_linear.h"
#include "arr_print.h"
@ -14,8 +15,8 @@ int main() {
// then, insert a point that lies on the line splitting it into two.
X_monotone_curve c1 = Line(Point(-1, 0), Point(1, 0));
arr.insert_in_face_interior(c1, arr.unbounded_face());
Vertex_handle v = insert_point(arr, Point(0,0));
assert(! v->is_at_open_boundary());
Vertex_handle v = insert_point(arr, Point(0, 0));
assert(!v->is_at_open_boundary());
// Add two more rays using the specialized insertion functions.
arr.insert_from_right_vertex(Ray(Point(0, 0), Point(-1, 1)), v); // c2
@ -30,25 +31,27 @@ int main() {
// Print the outer CCBs of the unbounded faces.
int k = 1;
for (auto it = arr.unbounded_faces_begin(); it != arr.unbounded_faces_end();
++it)
{
std::cout << "Face no. " << k++ << "(" << it->is_unbounded() << ","
<< it->number_of_holes() << ")" << ": ";
for(auto it = arr.unbounded_faces_begin(); it != arr.unbounded_faces_end(); ++it) {
std::cout << "Face no. " << k++ << "(" << it->is_unbounded() << "," << it->number_of_holes() << ")" << ": ";
Arrangement::Ccb_halfedge_const_circulator first = it->outer_ccb();
auto curr = first;
if (! curr->source()->is_at_open_boundary())
if(!curr->source()->is_at_open_boundary())
std::cout << "(" << curr->source()->point() << ")";
do {
Arrangement::Halfedge_const_handle e = curr;
if (! e->is_fictitious()) std::cout << " [" << e->curve() << "] ";
else std::cout << " [ ... ] ";
if(!e->is_fictitious())
std::cout << " [" << e->curve() << "] ";
else
std::cout << " [ ... ] ";
if (! e->target()->is_at_open_boundary())
if(!e->target()->is_at_open_boundary())
std::cout << "(" << e->target()->point() << ")";
} while (++curr != first);
} while(++curr != first);
std::cout << std::endl;
}
CGAL::draw(arr, "unbounded_non_intersecting");
return 0;
}

View File

@ -685,7 +685,7 @@ point_position(const Point_2& p, Bezier_cache& cache) const
return EQUAL;
}
// Then check whether the bezier is an horizontal segment or
// Then check whether the bezier is a horizontal segment or
// if p has the same x-coordinate as one of the endpoint
const Comparison_result res1 = p.compare_x(_ps, cache);

View File

@ -28,11 +28,13 @@
#include <variant>
#include <CGAL/Cartesian.h>
#include <CGAL/tags.h>
#include <CGAL/intersections.h>
#include <CGAL/Arr_tags.h>
#include <CGAL/Arr_enums.h>
#include <CGAL/Arr_geometry_traits/Segment_assertions.h>
#include "CGAL/number_utils.h"
namespace CGAL {
@ -1517,9 +1519,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 +1550,103 @@ 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 {
if(xcv.is_ray() || xcv.is_line()) return oi;
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

@ -1115,6 +1115,7 @@ public:
using Approximate_number_type = void;
using Approximate_point_2 = void;
using Approximate_2 = void;
using Approximate_kernel = void;
};
template <typename T>
@ -1123,6 +1124,7 @@ public:
using Approximate_number_type = typename T::Approximate_number_type;
using Approximate_2 = typename T::Approximate_2;
using Approximate_point_2 = typename T::Approximate_point_2;
using Approximate_kernel = typename T::Approximate_kernel;
};
using Approximate_number_type =
@ -1131,6 +1133,8 @@ public:
typename has_approximate_2<Subcurve_traits_2>::Approximate_2;
using Approximate_point_2 =
typename has_approximate_2<Subcurve_traits_2>::Approximate_point_2;
using Approximate_kernel =
typename has_approximate_2<Subcurve_traits_2>::Approximate_kernel;
/*! obtains an Approximate_2 functor object. */
Approximate_2 approximate_2_object_impl(std::false_type) const

View File

@ -597,6 +597,7 @@ public:
//
using Approximate_number_type = typename Base::Approximate_number_type;
using Approximate_point_2 = typename Base::Approximate_point_2;
using Approximate_kernel = typename Base::Approximate_kernel;
class Approximate_2 : public Base::Approximate_2 {
protected:

View File

@ -37,12 +37,12 @@ init_with_hint(const X_monotone_curve_2& cv, Pl_result_type obj) {
// associated with valid endpoints.
m_cv = cv;
auto psx = m_geom_traits->parameter_space_in_x_2_object();
auto psy = m_geom_traits->parameter_space_in_y_2_object();
if (m_geom_traits->is_closed_2_object()(m_cv, ARR_MIN_END)) {
// The left endpoint is valid.
const Arr_parameter_space ps_x1 =
m_geom_traits->parameter_space_in_x_2_object()(m_cv, ARR_MIN_END);
const Arr_parameter_space ps_y1 =
m_geom_traits->parameter_space_in_y_2_object()(m_cv, ARR_MIN_END);
const Arr_parameter_space ps_x1 = psx(m_cv, ARR_MIN_END);
const Arr_parameter_space ps_y1 = psy(m_cv, ARR_MIN_END);
m_has_left_pt = true;
m_left_on_boundary = (ps_x1 != ARR_INTERIOR || ps_y1 != ARR_INTERIOR);
m_left_pt = m_geom_traits->construct_min_vertex_2_object()(m_cv);
@ -55,10 +55,8 @@ init_with_hint(const X_monotone_curve_2& cv, Pl_result_type obj) {
if (m_geom_traits->is_closed_2_object()(m_cv, ARR_MAX_END)) {
// The right endpoint is valid.
const Arr_parameter_space ps_x2 =
m_geom_traits->parameter_space_in_x_2_object()(m_cv, ARR_MAX_END);
const Arr_parameter_space ps_y2 =
m_geom_traits->parameter_space_in_y_2_object()(m_cv, ARR_MAX_END);
const Arr_parameter_space ps_x2 = psx(m_cv, ARR_MAX_END);
const Arr_parameter_space ps_y2 = psy(m_cv, ARR_MAX_END);
m_has_right_pt = true;
m_right_on_boundary = (ps_x2 != ARR_INTERIOR || ps_y2 != ARR_INTERIOR);
m_right_pt = m_geom_traits->construct_max_vertex_2_object()(m_cv);
@ -252,11 +250,12 @@ bool Arrangement_zone_2<Arrangement, ZoneVisitor>::
do_overlap_impl(const X_monotone_curve_2& cv1,
const X_monotone_curve_2& cv2,
const Point_2& p, Arr_not_all_sides_oblivious_tag) const {
typename Traits_adaptor_2::Compare_y_at_x_right_2 cmp_right =
m_geom_traits->compare_y_at_x_right_2_object();
auto cmp_right = m_geom_traits->compare_y_at_x_right_2_object();
auto psx = m_geom_traits->parameter_space_in_x_2_object();
auto psy = m_geom_traits->parameter_space_in_y_2_object();
auto psx1 = m_geom_traits->parameter_space_in_x_2_object()(cv1, ARR_MIN_END);
auto psy1 = m_geom_traits->parameter_space_in_y_2_object()(cv1, ARR_MIN_END);
auto psx1 = psx(cv1, ARR_MIN_END);
auto psy1 = psy(cv1, ARR_MIN_END);
if ((psx1 == ARR_INTERIOR) && (psy1 == ARR_INTERIOR))
return (cmp_right(cv1, cv2, p) == EQUAL);
@ -265,8 +264,8 @@ do_overlap_impl(const X_monotone_curve_2& cv1,
bool vertical2 = m_geom_traits->is_vertical_2_object()(cv2);
if (vertical1 != vertical2) return false;
auto psx2 = m_geom_traits->parameter_space_in_x_2_object()(cv2, ARR_MIN_END);
auto psy2 = m_geom_traits->parameter_space_in_y_2_object()(cv2, ARR_MIN_END);
auto psx2 = psx(cv2, ARR_MIN_END);
auto psy2 = psy(cv2, ARR_MIN_END);
// If, for example, both curves are vertical and the bottom boundary is
// contracted, they may have different parameter space in x values.
@ -277,8 +276,7 @@ do_overlap_impl(const X_monotone_curve_2& cv1,
// left boundary, they completely lie on the left boundary and they overlap.
if (vertical1) return true;
typename Traits_adaptor_2::Compare_y_near_boundary_2 cmp_near =
m_geom_traits->compare_y_near_boundary_2_object();
auto cmp_near = m_geom_traits->compare_y_near_boundary_2_object();
return (cmp_near(cv1, cv2, ARR_MIN_END) == EQUAL);
}
@ -407,7 +405,7 @@ _direct_intersecting_edge_to_right(const X_monotone_curve_2& cv_ins,
// Check whether the curve lies above of below the edge immediately to
// the right of its left endpoint.
const Comparison_result pos_res =
const Comparison_result pos_res =
m_geom_traits->compare_y_at_x_right_2_object()(cv_ins, query_he->curve(),
cv_left_pt);
@ -459,7 +457,7 @@ _direct_intersecting_edge_to_left(const X_monotone_curve_2& cv_ins,
// Check whether the curve lies above of below the edge (we use the curve
// position predicate, as we know they cruves do not overlap and intersect
// only at the split point).
Comparison_result pos_res =
Comparison_result pos_res =
m_geom_traits->compare_y_position_2_object()(cv_ins, query_he->curve());
if (pos_res == EQUAL) {
@ -729,14 +727,14 @@ _is_to_left_impl(const Point_2& p, Halfedge_handle he,
// Check the boundary conditions of the minimal end of the curve associated
// with the given halfedge.
auto ps_in_x = m_geom_traits->parameter_space_in_x_2_object();
auto ps_x_min = ps_in_x(he->curve(), ARR_MIN_END);
auto psx = m_geom_traits->parameter_space_in_x_2_object();
auto ps_x_min = psx(he->curve(), ARR_MIN_END);
// Any point is not to the left of the left boundary.
if (ps_x_min == ARR_LEFT_BOUNDARY) return false;
auto ps_in_y = m_geom_traits->parameter_space_in_y_2_object();
auto ps_y_min = ps_in_y(he->curve(), ARR_MIN_END);
auto psy = m_geom_traits->parameter_space_in_y_2_object();
auto ps_y_min = psy(he->curve(), ARR_MIN_END);
if (ps_y_min != ARR_INTERIOR) {
// Check if p is to the left of the minimal curve-end:
auto cmp_x = m_geom_traits->compare_x_point_curve_end_2_object();
@ -766,16 +764,16 @@ _is_to_right_impl(const Point_2& p, Halfedge_handle he,
// Check the boundary conditions of the maximal end of the curve associated
// with the given halfedge.
auto ps_in_x = m_geom_traits->parameter_space_in_x_2_object();
auto ps_x_max = ps_in_x(he->curve(), ARR_MAX_END);
auto psx = m_geom_traits->parameter_space_in_x_2_object();
auto ps_x_max = psx(he->curve(), ARR_MAX_END);
// Any point is not to the right of the right boundary.
if (ps_x_max == ARR_RIGHT_BOUNDARY) return false;
// Any interior point is to the right of the left boundary.
if (ps_x_max == ARR_LEFT_BOUNDARY) return true;
auto ps_in_y = m_geom_traits->parameter_space_in_y_2_object();
auto ps_y_max = ps_in_y(he->curve(), ARR_MAX_END);
auto psy = m_geom_traits->parameter_space_in_y_2_object();
auto ps_y_max = psy(he->curve(), ARR_MAX_END);
if (ps_y_max != ARR_INTERIOR) {
// Check if p is to the right of the maximal curve-end:
auto cmp_x = m_geom_traits->compare_x_point_curve_end_2_object();
@ -790,6 +788,59 @@ _is_to_right_impl(const Point_2& p, Halfedge_handle he,
return (m_geom_traits->compare_xy_2_object()(p, v_right->point()) == LARGER);
}
//! checks whether a point lies to the left of another point.
template <typename Arrangement, typename ZoneVisitor>
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::
is_to_left_impl(const Point_2& p1, Arr_parameter_space /* ps1 */,
const Point_2& p2, Arr_parameter_space /* ps2 */,
Arr_all_sides_oblivious_tag) const {
auto cmp_xy = m_geom_traits->compare_xy_2_object();
return (cmp_xy(p2, p1) == SMALLER);
}
//! checks whether a point lies to the left of another point.
template <typename Arrangement, typename ZoneVisitor>
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::
is_to_left_impl(const Point_2& p1, Arr_parameter_space /* ps1 */,
const Point_2& p2, Arr_parameter_space /* ps2 */,
Arr_has_identified_side_tag) const {
auto is_on_y_ident = m_geom_traits->is_on_y_identification_2_object();
if (is_on_y_ident(p1)) {
if (is_on_y_ident(p2)) {
auto cmp_y_on_boundary = m_geom_traits->compare_y_on_boundary_2_object();
return (cmp_y_on_boundary(p2, p1) == SMALLER);
}
return false;
}
if (is_on_y_ident(p2)) return true;
auto cmp_xy = m_geom_traits->compare_xy_2_object();
return (cmp_xy(p2, p1) == SMALLER);
}
//! checks whether a point lies to the left of another point.
template <typename Arrangement, typename ZoneVisitor>
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::
is_to_left_impl(const Point_2& p1, Arr_parameter_space ps1,
const Point_2& p2, Arr_parameter_space ps2,
Arr_boundary_cond_tag) const {
if (ps1 == ARR_LEFT_BOUNDARY) {
if (ps2 == ARR_LEFT_BOUNDARY) {
auto cmp_y_on_boundary = m_geom_traits->compare_y_on_boundary_2_object();
return (cmp_y_on_boundary(p2, p1) == SMALLER);
}
return false;
}
if (ps1 == ARR_RIGHT_BOUNDARY) {
if (ps2 == ARR_RIGHT_BOUNDARY) {
auto cmp_y_on_boundary = m_geom_traits->compare_y_on_boundary_2_object();
return (cmp_y_on_boundary(p2, p1) == SMALLER);
}
return true;
}
auto cmp_xy = m_geom_traits->compare_xy_2_object();
return (cmp_xy(p2, p1) == SMALLER);
}
//-----------------------------------------------------------------------------
// Compute the (lexicographically) leftmost intersection of the query
// curve with a given halfedge on the boundary of a face in the arrangement.
@ -866,11 +917,7 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary,
// Found a simple intersection point. Check if it is the leftmost
// intersection point so far.
if (! m_found_intersect ||
((intersection_location != ARR_RIGHT_BOUNDARY) &&
((leftmost_location == ARR_RIGHT_BOUNDARY) ||
compare_xy(ip, m_intersect_p) == SMALLER)))
{
if (! m_found_intersect || is_to_left(m_intersect_p, leftmost_location, ip, intersection_location)) {
// Store the leftmost intersection point and the halfedge handle.
m_intersect_p = ip;
m_ip_multiplicity = int_p->second;
@ -1034,9 +1081,14 @@ _zone_in_face(Face_handle face, bool on_boundary) {
// Set m_cv to be the remaining portion.
m_has_left_pt = true;
m_left_on_boundary = false;
m_left_pt = m_intersect_p;
m_cv = m_sub_cv2;
auto psx = m_geom_traits->parameter_space_in_x_2_object();
auto psy = m_geom_traits->parameter_space_in_y_2_object();
auto ps_x = psx(m_left_pt);
auto ps_y = psy(m_left_pt);
m_left_on_boundary = (ps_x != ARR_INTERIOR || ps_y != ARR_INTERIOR);
}
const X_monotone_curve_2* p_orig_curve = nullptr;
@ -1220,11 +1272,9 @@ bool Arrangement_zone_2<Arrangement, ZoneVisitor>::_zone_in_overlap() {
#endif
// Obtain some geometry-traits functors.
typename Traits_adaptor_2::Equal_2 equal = m_geom_traits->equal_2_object();
typename Traits_adaptor_2::Is_closed_2 is_closed =
m_geom_traits->is_closed_2_object();
typename Traits_adaptor_2::Construct_max_vertex_2 ctr_max_vertex =
m_geom_traits->construct_max_vertex_2_object();
auto equal = m_geom_traits->equal_2_object();
auto is_closed = m_geom_traits->is_closed_2_object();
auto ctr_max_vertex = m_geom_traits->construct_max_vertex_2_object();
// Check if the right end of m_overlap_cv is bounded. If so, compute its
// right endpoint.
@ -1310,8 +1360,13 @@ bool Arrangement_zone_2<Arrangement, ZoneVisitor>::_zone_in_overlap() {
// Set m_cv to be the remaining portion.
m_has_left_pt = true;
m_left_on_boundary = false;
m_left_pt = cv_right_pt;
auto psx = m_geom_traits->parameter_space_in_x_2_object();
auto psy = m_geom_traits->parameter_space_in_y_2_object();
auto ps_x = psx(m_left_pt);
auto ps_y = psy(m_left_pt);
m_left_on_boundary = (ps_x != ARR_INTERIOR || ps_y != ARR_INTERIOR);
m_cv = m_sub_cv2;
// Move to the remaining portion of the curve, whose left endpoint is the

View File

@ -415,6 +415,24 @@ private:
Arr_parameter_space& intersection_location,
Arr_boundary_cond_tag) const;
/*! checks whether an point lies to the left of another point.
*/
bool is_to_left(const Point_2& p1, Arr_parameter_space ps1,
const Point_2& p2, Arr_parameter_space ps2) const
{ return is_to_left_impl(p1, ps1, p2, ps2, Left_or_right_sides_category()); }
bool is_to_left_impl(const Point_2& p1, Arr_parameter_space ps1,
const Point_2& p2, Arr_parameter_space ps2,
Arr_all_sides_oblivious_tag) const;
bool is_to_left_impl(const Point_2& p1, Arr_parameter_space ps1,
const Point_2& p2, Arr_parameter_space ps2,
Arr_has_identified_side_tag) const;
bool is_to_left_impl(const Point_2& p1, Arr_parameter_space ps1,
const Point_2& p2, Arr_parameter_space ps2,
Arr_boundary_cond_tag) const;
/*! computes the (lexicographically) leftmost intersection of the query
* curve with a given halfedge on the boundary of a face in the arrangement.
*/

View File

@ -0,0 +1,72 @@
// Copyright (c) 2025
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s): Shepard Liu <shepard0liu@gmail.com>
#ifndef CGAL_DRAW_AOS_ARR_APPROXIMATION_CACHE_H
#define CGAL_DRAW_AOS_ARR_APPROXIMATION_CACHE_H
#include <CGAL/license/Arrangement_on_surface_2.h>
#include <boost/range/iterator_range.hpp>
#include <CGAL/Arr_enums.h>
#include <CGAL/unordered_flat_map.h>
#include <CGAL/Draw_aos/type_utils.h>
namespace CGAL {
namespace draw_aos {
/** @brief Cache class for approximating arrangement on surface.
*
* 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.
* @tparam Arrangement
*/
template <typename Arrangement>
class Arr_approximation_cache {
using Geom_traits = typename Arrangement::Geometry_traits_2;
using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Vertex_cache_obj = typename Approx_traits::Point;
using Halfedge_cache_obj = typename Approx_traits::Polyline;
using Face_cache_obj = typename Approx_traits::Triangle_soup;
using Vertex_const_handle = typename Arrangement::Vertex_const_handle;
using Halfedge_const_handle = typename Arrangement::Halfedge_const_iterator;
using Face_const_handle = typename Arrangement::Face_const_handle;
using Vertex_cache = unordered_flat_map<Vertex_const_handle, Vertex_cache_obj>;
using Halfedge_cache = unordered_flat_map<Halfedge_const_handle, Halfedge_cache_obj>;
using Face_cache = unordered_flat_map<Face_const_handle, Face_cache_obj>;
public:
Arr_approximation_cache() = default;
const Vertex_cache& vertices() const { return m_vertices; }
const Halfedge_cache& halfedges() const { return m_halfedges; }
const Face_cache& faces() const { return m_faces; }
Vertex_cache& vertices() { return m_vertices; }
Halfedge_cache& halfedges() { return m_halfedges; }
Face_cache& faces() { return m_faces; }
private:
Vertex_cache m_vertices;
Halfedge_cache m_halfedges;
Face_cache m_faces;
};
} // namespace draw_aos
} // namespace CGAL
#endif

View File

@ -0,0 +1,258 @@
// Copyright (c) 2025
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s): Shepard Liu <shepard0liu@gmail.com>
#ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_FACE_H
#define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_FACE_H
#include <CGAL/license/Arrangement_on_surface_2.h>
#include <iterator>
#include <optional>
#include <utility>
#include <algorithm>
#include <boost/iterator/function_output_iterator.hpp>
#include <CGAL/Arr_enums.h>
#include <CGAL/Bbox_2.h>
#include <CGAL/Draw_aos/Arr_bounded_approximate_halfedge.h>
#include <CGAL/Draw_aos/Arr_bounded_approximate_vertex.h>
#include <CGAL/Draw_aos/Arr_bounded_face_triangulator.h>
#include <CGAL/Draw_aos/Arr_render_context.h>
#include <CGAL/Draw_aos/type_utils.h>
namespace CGAL {
namespace draw_aos {
/*! \brief Functor to approximate arrangement face with triangles within a bounding box.
*
* \tparam Arrangement
*/
template <typename Arrangement>
class Arr_bounded_approximate_face {
using Face_const_handle = typename Arrangement::Face_const_handle;
using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle;
using Vertex_const_handle = typename Arrangement::Vertex_const_handle;
using Ccb_halfedge_const_circulator = typename Arrangement::Ccb_halfedge_const_circulator;
using Geom_traits = typename Arrangement::Geometry_traits_2;
using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Point = typename Approx_traits::Point;
using Polyline = typename Approx_traits::Polyline;
using Triangle_soup = typename Approx_traits::Triangle_soup;
using Bounded_approximate_vertex = Arr_bounded_approximate_vertex<Arrangement>;
using Bounded_approximate_halfedge = Arr_bounded_approximate_halfedge<Arrangement>;
using Bounded_render_context = Arr_bounded_render_context<Arrangement>;
using Triangulator = Arr_bounded_face_triangulator<Arrangement>;
static constexpr bool Is_on_curved_surface = is_or_derived_from_curved_surf_traits_v<Geom_traits>;
struct Left_to_right_tag {};
struct Right_to_left_tag {};
private:
/*! \brief A stateful geometry simplifier that simplifies horizontal and vertical segments
*
* \tparam OutputIterator
*/
template <typename OutputIterator>
class Colinear_simplifier {
public:
Colinear_simplifier(OutputIterator out_it) : m_out_it(out_it) {}
void dump() {
if (m_start.has_value()) {
*m_out_it++ = m_start.value();
m_start.reset();
}
if (m_mid.has_value()) {
*m_out_it++ = m_mid.value();
m_mid.reset();
}
}
void push_back(Point p) {
if (m_mid.has_value()) {
if (((p.y() == m_mid->y()) && (p.y() == m_start->y())) || ((p.x() == m_mid->x()) && (p.x() == m_start->x())))
// Three points are collinear horizontally or vertically.
m_mid = p;
else {
*m_out_it++ = m_start.value();
m_start = m_mid;
m_mid = p;
}
return;
}
if (m_start.has_value())
m_mid = p;
else
m_start = p;
}
~Colinear_simplifier() { dump(); }
private:
OutputIterator m_out_it;
std::optional<Point> m_start, m_mid;
};
class Context : public Bounded_render_context {
using Simplifier = Colinear_simplifier<std::back_insert_iterator<Triangulator>>;
public:
Context(const Bounded_render_context& ctx, Triangulator& triangulator) :
Bounded_render_context(ctx),
m_triangulator(triangulator) {
if constexpr(!Is_on_curved_surface) m_simplifier.emplace(std::back_inserter(m_triangulator));
}
// Let's not accidentally copy this object.
Context(const Context&) = delete;
Context& operator=(const Context&) = delete;
void insert(Point pt) {
if (Approx_traits::is_null(pt) || pt == m_last_pt) return;
pt = Point(pt.x(), std::clamp(pt.y(), this->ymin(), this->ymax()));
if constexpr(!Is_on_curved_surface) {
m_simplifier->push_back(pt);
return;
}
m_triangulator.push_back(pt);
m_last_pt = pt;
}
void start_ccb() { m_triangulator.start_constraint(); }
void end_ccb() {
if constexpr(!Is_on_curved_surface) m_simplifier->dump();
m_triangulator.end_constraint();
}
const std::optional<Point>& last_pt() const { return m_last_pt; }
private:
Triangulator& m_triangulator;
// Colinear simplifier is only used for optimizing planar arrangements.
std::optional<Simplifier> m_simplifier;
std::optional<Point> m_last_pt;
};
private:
static Arr_parameter_space side_of_fict_edge(const Halfedge_const_handle& he) {
const auto& source = he->source();
const auto& target = he->target();
auto sx = source->parameter_space_in_x();
auto sy = source->parameter_space_in_y();
auto tx = target->parameter_space_in_x();
auto ty = target->parameter_space_in_y();
if (sx == tx && sx != ARR_INTERIOR) return sx;
if (sy == ty && sy != ARR_INTERIOR) return sy;
CGAL_assertion(false && "Unexpected parameter space for fictitious edge ends.");
return ARR_INTERIOR;
}
// Generate dummy segment for fictitious edge he at its corresponding boundary.
static Polyline approximate_fict_edge(const Context& ctx, const Halfedge_const_handle& he) {
auto side = side_of_fict_edge(he);
// There's no need to handle fictitious edges on left or right boundaries.
if (side == ARR_LEFT_BOUNDARY || side == ARR_RIGHT_BOUNDARY) return Polyline{};
if (side == ARR_BOTTOM_BOUNDARY) return Polyline{ctx.bottom_left(), ctx.bottom_right()};
if (side == ARR_TOP_BOUNDARY) return Polyline{ctx.top_right(), ctx.top_left()};
CGAL_assertion(false && "Unexpected side for a fictitious edge.");
return Polyline{};
}
void approximate_vertex(Context& /* ctx */, const Vertex_const_handle& vh) const {
if (vh->is_at_open_boundary()) return;
m_bounded_approx_vertex(vh);
}
void approximate_halfedge(Context& ctx, const Halfedge_const_handle& he) const {
const Polyline& polyline = he->is_fictitious() ? approximate_fict_edge(ctx, he) : m_bounded_approx_halfedge(he);
for (const auto& curr_pt : polyline) ctx.insert(curr_pt);
}
void approximate_ccb(Context& ctx, Ccb_halfedge_const_circulator start) const {
// Try to start on a concrete halfedge.
// For any unbounded face, there can't be more than 4 adjacent fictitious edges.
for (int i = 0; i < 4 && start->is_fictitious(); ++i) ++start;
ctx.start_ccb();
auto circ = start;
do {
approximate_halfedge(ctx, circ);
approximate_vertex(ctx, circ->target());
} while(++circ != start);
ctx.end_ccb();
}
public:
Arr_bounded_approximate_face(const Bounded_render_context& ctx) :
m_ctx(ctx),
m_bounded_approx_halfedge(ctx),
m_bounded_approx_vertex(ctx)
{}
/*! \brief Approximate an arrangement face with a bunch of triangles.
*
* \param fh
* \return const Triangulated_face&
*/
const Triangle_soup& operator()(const Face_const_handle& fh) const {
CGAL_precondition_msg(!fh->is_fictitious(), "Cannot approximate a fictitious face.");
auto [iter, inserted] = m_ctx.m_cache.faces().try_emplace(fh);
Triangle_soup& ts = iter->second;
if (! inserted || m_ctx.is_cancelled()) return ts;
auto triangulator = Triangulator(m_ctx, fh);
auto ctx = Context(m_ctx, triangulator);
if (! Is_on_curved_surface && !fh->has_outer_ccb()) {
// Skip approximation of the unbounded face in planar arrangements.
// However, degenerate holes still need to be approximated.
for (auto inner_ccb = fh->inner_ccbs_begin(); inner_ccb != fh->inner_ccbs_end(); ++inner_ccb) {
auto circ = *inner_ccb;
do {
if (circ->face() != circ->twin()->face()) continue;
m_bounded_approx_halfedge(circ);
} while(++circ != *inner_ccb);
}
for (auto vh = fh->isolated_vertices_begin(); vh != fh->isolated_vertices_end(); ++vh) m_bounded_approx_vertex(vh);
return ts;
}
for (auto outer_ccb = fh->outer_ccbs_begin(); outer_ccb != fh->outer_ccbs_end(); ++outer_ccb)
approximate_ccb(ctx, *outer_ccb);
for (auto inner_ccb = fh->inner_ccbs_begin(); inner_ccb != fh->inner_ccbs_end(); ++inner_ccb)
approximate_ccb(ctx, *inner_ccb);
for (auto iso_vertex = fh->isolated_vertices_begin(); iso_vertex != fh->isolated_vertices_end(); ++iso_vertex)
approximate_vertex(ctx, iso_vertex);
return ts = std::move(triangulator);
}
private:
const Bounded_render_context& m_ctx;
const Bounded_approximate_halfedge m_bounded_approx_halfedge;
const Bounded_approximate_vertex m_bounded_approx_vertex;
};
} // namespace draw_aos
} // namespace CGAL
#endif

View File

@ -0,0 +1,337 @@
// Copyright (c) 2025
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s): Shepard Liu <shepard0liu@gmail.com>
#ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_HALFEDGE_H
#define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_HALFEDGE_H
#include <CGAL/license/Arrangement_on_surface_2.h>
#include <algorithm>
#include <array>
#include <cstdlib>
#include <optional>
#include <type_traits>
#include <boost/iterator/function_output_iterator.hpp>
#include <CGAL/enum.h>
#include <CGAL/Arr_enums.h>
#include <CGAL/Arr_has.h>
#include <CGAL/Draw_aos/Arr_render_context.h>
#include <CGAL/Draw_aos/type_utils.h>
namespace CGAL {
namespace draw_aos {
/** @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
* succeeds a part within, the approximation may be skipped but there will be at least one point outside the bbox
* for indication.
*/
template <typename Arrangement>
class Arr_bounded_approximate_halfedge {
using Geom_traits = typename Arrangement::Geometry_traits_2;
using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle;
using Gt_point = typename Geom_traits::Point_2;
using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Approx_nt = typename Approx_traits::Approx_nt;
using Approx_point = typename Approx_traits::Approx_point;
using Point = typename Approx_traits::Point;
using Polyline = typename Approx_traits::Polyline;
using Approx_kernel = typename Approx_traits::Approx_kernel;
using Approx_line_2 = typename Approx_kernel::Line_2;
using X_monotone_curve_2 = typename Geom_traits::X_monotone_curve_2;
using Bounded_render_context = Arr_bounded_render_context<Arrangement>;
using Boundary_lines = std::array<Approx_line_2, 4>;
constexpr static bool Has_approximate_xcv_with_bounds =
has_approximate_xcv_with_bounds_v<Geom_traits, typename Geom_traits::Approximate_2>;
private:
struct Context : public Bounded_render_context {
Context(const Bounded_render_context& ctx, const X_monotone_curve_2& curve, Polyline& polyline) :
Bounded_render_context(ctx),
m_polyline(polyline), m_curve(curve)
{}
// Prevent accidental copying.
Context(const Context&) = delete;
Context& operator=(const Context&) = delete;
public:
/*! \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.
* \param pt
*/
void insert(Point pt) {
if (pt.x() < this->xmin()) {
// We need the last point if not yet x-inbound.
m_last_pt = pt;
return;
}
else if (pt.x() > this->xmax()) return;
m_polyline.push_back(pt);
m_last_pt = pt;
}
const std::optional<Point>& last_pt() const { return m_last_pt; }
private:
std::optional<Point> m_last_pt;
public:
Polyline& m_polyline;
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.
*/
Point boundary_intersection(const Context& ctx, Point pt, Boundary_side side) const {
std::optional<double> x, y;
const Approx_line_2* line = nullptr;
switch(side) {
case Boundary_side::Left:
x = ctx.xmin();
line = &m_left;
break;
case Boundary_side::Right:
x = ctx.xmax();
line = &m_right;
break;
case Boundary_side::Top:
y = ctx.ymax();
line = &m_top;
break;
case Boundary_side::Bottom:
y = ctx.ymin();
line = &m_bottom;
break;
default:
CGAL_assertion(false && "Unexpected side of boundary.");
}
Point inter = std::get<Point>(*CGAL::intersection(Approx_line_2(*ctx.last_pt(), pt), *line));
if (x.has_value()) return Point(*x, inter.y());
return Point(inter.x(), *y);
}
/*! \brief Trace approximated curve point in ltr ordering, adding boundary intersections if necessary.
*
* \note This method will eventually be replaced by AosApproximateUnboundedTraits_2.
*/
void trace_add(Context& ctx, Point pt) const {
if (! ctx.last_pt().has_value()) {
ctx.insert(pt);
return;
}
if (ctx.last_pt()->x() < ctx.xmin() && pt.x() >= ctx.xmin())
ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Left));
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.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));
if (pt.y() < ctx.ymin()) ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Bottom));
}
else {
if (pt.y() < ctx.ymin())
ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Bottom));
else if (pt.y() > ctx.ymax())
ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Top));
}
if (ctx.last_pt()->x() <= ctx.xmax() && pt.x() > ctx.xmax())
ctx.insert(boundary_intersection(ctx, pt, Boundary_side::Right));
ctx.insert(pt);
}
/*! \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) {
const Geom_traits& traits = ctx.m_traits;
const X_monotone_curve_2& curve = ctx.m_curve;
if constexpr(has_is_in_x_range_v<Geom_traits>) return curve.is_in_x_range(pt);
if constexpr(!has_parameter_space_in_x_2<Geom_traits>::value) {
const auto& min_pt = traits.construct_min_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) &&
(traits.compare_x_2_object()(pt, max_pt) != CGAL::LARGER));
}
Comparison_result left_cmp;
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));
else if (left_loc == ARR_LEFT_BOUNDARY)
left_cmp = CGAL::LARGER;
else
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::EQUAL) return true;
Comparison_result right_cmp;
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));
else if (right_loc == ARR_RIGHT_BOUNDARY)
right_cmp = CGAL::SMALLER;
else
right_cmp = traits.compare_x_on_boundary_2_object()(pt, curve, ARR_MAX_END);
return right_cmp != CGAL::LARGER;
}
/*! \brief transform approximated curve points(ltr ordering) in place based on the halfedge, giving correct
* ordering, continuity, etc.
*/
static void transform_polyline(Context& ctx, Polyline& polyline, const Halfedge_const_handle& he)
{ transform_polyline_impl<Geom_traits>(ctx, polyline, he); }
// 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>
static void transform_polyline_impl(Context&, Polyline& polyline, const Halfedge_const_handle& he) {
if (he->direction() == CGAL::ARR_LEFT_TO_RIGHT) return;
std::reverse(polyline.begin(), polyline.end());
}
template <typename Gt, std::enable_if_t<is_or_derived_from_agas_v<Gt>, int> = 0>
static void transform_polyline_impl(Context& ctx, Polyline& polyline, const Halfedge_const_handle& he) {
using Direction_3 = typename Geom_traits::Direction_3;
using Vector_3 = typename Geom_traits::Vector_3;
if (polyline.size() < 2) return;
const X_monotone_curve_2& curve = he->curve();
const auto& traits = ctx.m_traits;
if (curve.is_vertical()) {
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()));
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;
std::transform(polyline.begin(), polyline.end(), polyline.begin(),
[azimuth](Point pt) { return Point(azimuth, pt.y()); });
}
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
polyline.back() = Point(2 * CGAL_PI, polyline.back().y());
}
if (he->direction() == CGAL::ARR_LEFT_TO_RIGHT) return;
std::reverse(polyline.begin(), polyline.end());
}
void approximate_curve(Context& ctx) const { approximate_curve_impl<Geom_traits>(ctx); }
// If Approximate_2 supports 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>
void approximate_curve_impl(Context& ctx) const {
const Geom_traits& traits = ctx.m_traits;
const X_monotone_curve_2& curve = ctx.m_curve;
Polyline& polyline = ctx.m_polyline;
auto compare_y_at_x_2 = traits.compare_y_at_x_2_object();
if (is_in_x_range(ctx, m_top_left)) {
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())});
}
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())});
}
}
traits.approximate_2_object()(curve, ctx.m_approx_error,
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.bbox(), true);
if (is_in_x_range(ctx, m_top_right)) {
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});
}
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});
}
}
}
// 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>
void approximate_curve_impl(Context& ctx) const {
auto approx = m_ctx.m_traits.approximate_2_object();
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);
}
/*! \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.
*/
Point snap_to_boundary(const Context& ctx, Point pt) const {
Approx_nt x = pt.x(), y = pt.y();
if (std::abs(x - ctx.xmin()) < m_ep_left) x = ctx.xmin();
else if (std::abs(x - ctx.xmax()) < m_ep_right) x = ctx.xmax();
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);
}
public:
Arr_bounded_approximate_halfedge(const Bounded_render_context& ctx) :
m_ctx(ctx),
m_left(ctx.bottom_left(), ctx.top_left()),
m_right(ctx.bottom_right(), ctx.top_right()),
m_bottom(ctx.bottom_left(), ctx.bottom_right()),
m_top(ctx.top_left(), ctx.top_right()) {
Construct_gt_point_2<Geom_traits> ctr_p;
m_top_left = ctr_p(ctx.to_cartesian(ctx.top_left()));
m_top_right = ctr_p(ctx.to_cartesian(ctx.top_right()));
m_bottom_left = ctr_p(ctx.to_cartesian(ctx.bottom_left()));
m_bottom_right = ctr_p(ctx.to_cartesian(ctx.bottom_right()));
Approx_nt ep_base = std::numeric_limits<Approx_nt>::epsilon();
m_ep_left = std::max(std::abs(ep_base * ctx.xmin()), ep_base);
m_ep_right = std::max(std::abs(ep_base * ctx.xmax()), ep_base);
m_ep_bottom = std::max(std::abs(ep_base * ctx.ymin()), ep_base);
m_ep_top = std::max(std::abs(ep_base * ctx.ymax()), ep_base);
}
const Polyline& operator()(const Halfedge_const_handle& he) const {
CGAL_assertion(!he->is_fictitious());
auto& cache = m_ctx.m_cache.halfedges();
auto [iter, inserted] = cache.try_emplace(he, Polyline());
Polyline& polyline = iter->second;
if (!inserted) return polyline;
if (m_ctx.is_cancelled()) return polyline;
const X_monotone_curve_2& curve = he->curve();
Context ctx(m_ctx, curve, polyline);
approximate_curve(ctx);
Polyline poly_copy(polyline);
transform_polyline(ctx, polyline, he);
// also approximate the twin halfedge
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());
// The previous iterator might have been invalidated by the second try_emplace call, so we do an extra lookup.
return cache.at(he);
}
private:
const Bounded_render_context& m_ctx;
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;
Approx_nt m_ep_left, m_ep_right, m_ep_bottom, m_ep_top;
};
} // namespace draw_aos
} // namespace CGAL
#endif

View File

@ -0,0 +1,60 @@
// Copyright (c) 2025
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s): Shepard Liu <shepard0liu@gmail.com>
#ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_VERTEX_H
#define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_VERTEX_H
#include <CGAL/license/Arrangement_on_surface_2.h>
#include <CGAL/Draw_aos/type_utils.h>
#include <CGAL/Draw_aos/Arr_render_context.h>
namespace CGAL {
namespace draw_aos {
template <typename Arrangement>
class Arr_bounded_approximate_vertex {
using Geom_traits = typename Arrangement::Geometry_traits_2;
using Point_2 = typename Geom_traits::Point_2;
using Vertex_const_handle = typename Arrangement::Vertex_const_handle;
using Point_geom = typename Arr_approximate_traits<Geom_traits>::Point;
using Bounded_render_context = Arr_bounded_render_context<Arrangement>;
public:
Arr_bounded_approximate_vertex(const Bounded_render_context& ctx) : m_ctx(ctx) {}
/** @brief Approximate a vertex within the x-bounded range.
*
* The function uses cached values if available.
* @precondition: The vertex must have an associated point.
*
* @param vh the vertex handle
* @return const Point_geom&
*/
const Point_geom& operator()(const Vertex_const_handle& vh) const {
auto [iter, inserted] = m_ctx.m_cache.vertices().try_emplace(vh);
Point_geom& point = iter->second;
if (! inserted) return point;
return point = m_ctx.to_uv(m_ctx.m_traits.approximate_2_object()(vh->point()));
}
private:
const Bounded_render_context& m_ctx;
};
} // namespace draw_aos
} // namespace CGAL
#endif

View File

@ -0,0 +1,317 @@
// Copyright (c) 2025
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s): Shepard Liu <shepard0liu@gmail.com>
#ifndef CGAL_DRAW_AOS_ARR_FACE_TRIANGULATOR_H
#define CGAL_DRAW_AOS_ARR_FACE_TRIANGULATOR_H
#include <CGAL/license/Arrangement_on_surface_2.h>
#include <algorithm>
#include <optional>
#include <type_traits>
#include <utility>
#include <vector>
#include <boost/iterator/function_output_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
#include <CGAL/mark_domain_in_triangulation.h>
#include <CGAL/unordered_flat_map.h>
#include <CGAL/Constrained_triangulation_2.h>
#include <CGAL/Constrained_triangulation_face_base_2.h>
#include <CGAL/Bbox_2.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Draw_aos/Arr_render_context.h>
#include <CGAL/Draw_aos/type_utils.h>
#if defined(CGAL_DRAW_AOS_DEBUG) && defined(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR)
#include <fstream>
#include <filesystem>
template <typename Arrangement>
class Arr_bounded_face_triangulator;
template <typename Arrangement>
void debug_print(const Arr_bounded_face_triangulator<Arrangement>& triangulator);
#endif
namespace CGAL {
namespace draw_aos {
/**
* @brief Triangulator for a face of an arrangement within a bounding box.
*/
template <typename Arrangement>
class Arr_bounded_face_triangulator {
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>;
using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Point = typename Approx_traits::Point;
using Approx_point = typename Approx_traits::Approx_point;
using Approx_kernel = typename Approx_traits::Approx_kernel;
using Triangle_soup = typename Approx_traits::Triangle_soup;
using Triangle = typename Triangle_soup::Triangle;
using Face_const_handle = typename Arrangement::Face_const_handle;
#if defined(CGAL_DRAW_AOS_DEBUG)
template <typename T>
friend void debug_print(const Arr_bounded_face_triangulator<T>& triangulator);
#endif
enum Point_type { Vertex_only, Constraint_only, Vertex_and_constraint };
/*! \brief A index wrapper defaulted to invalid.
*/
class Index {
public:
Index() = default;
Index(int idx) : m_index(idx) {}
bool is_valid() const { return m_index != Invalid_index; }
operator int() const { return m_index; }
private:
constexpr static int Invalid_index = -1;
int m_index{Invalid_index};
};
using Epick = Exact_predicates_inexact_constructions_kernel;
using Vb = Triangulation_vertex_base_with_info_2<Index, Epick>;
using Fb = Constrained_triangulation_face_base_2<Epick>;
using Tds = Triangulation_data_structure_2<Vb, Fb>;
// For planar arrangements, Constrained_triangulation_2 is enough.
using Ct = std::conditional_t<Is_on_curved_surface,
Constrained_Delaunay_triangulation_2<Epick, Tds, Exact_predicates_tag>,
Constrained_triangulation_2<Epick, Tds, Exact_predicates_tag>>;
using KPoint = Epick::Point_2;
using KPoint_with_index = std::pair<KPoint, Index>;
using Bounded_render_context = Arr_bounded_render_context<Arrangement>;
public:
using value_type = Point;
private:
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.
*
* \pre side != Boundary_side::None
*/
static Point offset_boundary_point(Point pt, Boundary_side side, double offset) {
CGAL_precondition(side != Boundary_side::None);
switch(side) {
case Boundary_side::Left: return Point(pt.x() - offset, pt.y());
case Boundary_side::Right: return Point(pt.x() + offset, pt.y());
case Boundary_side::Top: 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.
*/
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_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_top(pt1) && m_ctx.is_on_top(pt2)) return Boundary_side::Top;
return Boundary_side::None;
}
/*! \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
* four sides of the bbox. Topological errors could be introduced if several segments are lying on the same side.
* Thus we add the midpoint in between the two points on boundary and move it outward with an increasing offset.
*/
void add_boundary_helper_point(Point from, Point to) {
// Arrangements on curved surfaces currently draws the entire parameter space, so there's no need to add
// helper points.
if constexpr(Is_on_curved_surface) return;
if (from == to) return;
auto shared_side = shared_boundary(from, to);
if (shared_side == Boundary_side::None) return;
Point mid = CGAL::midpoint(from, to);
m_points.push_back(offset_boundary_point(mid, shared_side, m_offset += 0.1));
m_point_types.push_back(Constraint_only);
}
void insert_all_vertices() {
auto vertex_filter = [this](int idx) { return m_point_types[idx] != Constraint_only; };
auto index_to_point_with_info = [this](int idx) -> KPoint_with_index {
return std::make_pair(to_kpoint(m_points[idx]), idx);
};
auto indexes_begin = boost::make_counting_iterator<int>(0);
auto indexes_end = boost::make_counting_iterator<int>(m_points.size());
auto filtered_begin = boost::make_filter_iterator(vertex_filter, indexes_begin, indexes_end);
auto filtered_end = boost::make_filter_iterator(vertex_filter, indexes_end, indexes_end);
auto transformed_begin = boost::make_transform_iterator(filtered_begin, index_to_point_with_info);
auto transformed_end = boost::make_transform_iterator(filtered_end, index_to_point_with_info);
// Constrained_triangulation_2 and Constrained_Delaunay_triangulation_2 have slightly different interfaces.
if constexpr(Is_on_curved_surface)
m_ct.insert(transformed_begin, transformed_end);
else
m_ct.template insert_with_info<KPoint_with_index>(transformed_begin, transformed_end);
}
void insert_all_constraints() {
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]); };
for (auto [start_idx, end_idx] : m_cst_ranges) {
auto indexes_begin = boost::make_counting_iterator<int>(start_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_end = boost::make_filter_iterator(constraint_filter, indexes_end, indexes_end);
auto transformed_begin = boost::make_transform_iterator(filtered_begin, index_to_point);
auto transformed_end = boost::make_transform_iterator(filtered_end, index_to_point);
m_ct.insert_constraint(transformed_begin, transformed_end, true);
}
}
public:
Arr_bounded_face_triangulator(const Bounded_render_context& ctx, Face_const_handle fh) :
m_ctx(ctx),
m_fh(fh)
{}
void push_back(Point pt) {
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);
m_points.push_back(pt);
m_point_types.push_back(Vertex_and_constraint);
}
void start_constraint() { m_curr_cst_begin = m_points.size(); }
void end_constraint() {
CGAL_assertion_msg(m_curr_cst_begin.has_value(), "Call start_constraint() before end_constraint().");
int cst_begin = *m_curr_cst_begin;
m_curr_cst_begin.reset();
if (m_points.size() - cst_begin <= 2) {
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());
return;
}
add_boundary_helper_point(m_points.back(), m_points[cst_begin]);
m_cst_ranges.emplace_back(cst_begin, m_points.size());
}
/*! \brief Converts the triangulator to a triangulated face, moving internal data to the result.
*
* \return Triangulated_face
*/
operator Triangle_soup() && {
CGAL_assertion_msg(!m_curr_cst_begin.has_value(), "Call end_constraint() before conversion");
if (m_points.empty()) return Triangle_soup();
if constexpr(Is_on_curved_surface) {
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_point_types.insert(m_point_types.end(), it->second.size(), Vertex_only);
}
}
insert_all_vertices();
insert_all_constraints();
if (m_ct.number_of_faces() == 0) return Triangle_soup();
#if defined(CGAL_DRAW_AOS_DEBUG)
debug_print(*this);
#endif
unordered_flat_map<typename Ct::Face_handle, bool> in_domain_map;
in_domain_map.reserve(m_ct.number_of_faces());
boost::associative_property_map<decltype(in_domain_map)> in_domain(in_domain_map);
CGAL::mark_domain_in_triangulation(m_ct, in_domain);
// Collect triangles within the constrained domain.
Triangle_soup ts;
ts.triangles.reserve(m_ct.number_of_faces());
for (auto fit = m_ct.finite_faces_begin(); fit != m_ct.finite_faces_end(); ++fit) {
Index v1 = fit->vertex(0)->info();
Index v2 = fit->vertex(1)->info();
Index v3 = fit->vertex(2)->info();
if (! v1.is_valid() || !v2.is_valid() || !v3.is_valid()) continue;
if (! get(in_domain, fit)) continue;
ts.triangles.push_back(Triangle{v1, v2, v3});
}
ts.points = std::move(m_points);
return ts;
}
private:
const Bounded_render_context& m_ctx;
Face_const_handle m_fh;
Ct m_ct;
std::vector<Point> m_points;
std::vector<Point_type> m_point_types;
std::vector<std::pair<int, int>> m_cst_ranges;
std::optional<int> m_curr_cst_begin;
double m_offset{0};
};
#if defined(CGAL_DRAW_AOS_DEBUG) && defined(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR)
template <typename Arrangement>
void debug_print(const Arr_bounded_face_triangulator<Arrangement>& triangulator) {
const auto& ctx = triangulator.m_ctx;
const auto& m_points = triangulator.m_points;
const auto& m_point_types = triangulator.m_point_types;
using Point_type = typename Arr_bounded_face_triangulator<Arrangement>::Point_type;
using Path = std::filesystem::path;
Path debug_dir(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR);
std::string index_file_name = "index.txt";
Path index_file_path = debug_dir / index_file_name;
std::string points_file_name_prefix = "face_" + std::to_string(*ctx.debug_counter) + "_points";
std::string ccb_constraint_file_name_prefix = "face_" + std::to_string(*ctx.debug_counter) + "_constraint";
const_cast<int&>(*ctx.debug_counter)++;
std::ofstream ofs_index(index_file_path, std::ios::app);
auto points_filename = points_file_name_prefix + ".txt";
auto points_path = debug_dir / points_filename;
std::ofstream ofs_points(points_path);
ofs_index << points_filename << std::endl;
for (int i = 0; i < triangulator.m_points.size(); ++i) {
if (m_point_types[i] == Point_type::Constraint_only) continue;
const auto& pt = m_points[i];
ofs_points << pt.x() << " " << pt.y() << "\n";
}
int counter = 0;
for (auto [start_idx, end_idx] : triangulator.m_cst_ranges) {
auto filename = ccb_constraint_file_name_prefix + "_" + std::to_string(counter++) + ".txt";
auto filepath = debug_dir / filename;
ofs_index << filename << std::endl;
std::ofstream ofs_ccb_constraint(filepath);
for (int i = start_idx; i < end_idx; ++i) {
if (m_point_types[i] == Point_type::Vertex_only) continue;
const auto& pt = m_points[i];
ofs_ccb_constraint << pt.x() << " " << pt.y() << "\n";
}
}
}
#endif
} // namespace draw_aos
} // namespace CGAL
#endif

View File

@ -0,0 +1,67 @@
// Copyright (c) 2025
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s): Shepard Liu <shepard0liu@gmail.com>
#ifndef CGAL_DRAW_AOS_ARR_BOUNDED_RENDERER_H
#define CGAL_DRAW_AOS_ARR_BOUNDED_RENDERER_H
#include <CGAL/license/Arrangement_on_surface_2.h>
#include <CGAL/Bbox_2.h>
#include <CGAL/Draw_aos/Arr_approximation_cache.h>
#include <CGAL/Draw_aos/Arr_bounded_approximate_face.h>
#include <CGAL/Draw_aos/Arr_render_context.h>
#include <CGAL/Draw_aos/type_utils.h>
namespace CGAL {
namespace draw_aos {
/** @brief Render arrangement on surface within a bounding box.
*/
template <typename Arrangement>
class Arr_bounded_renderer {
using Geom_traits = typename Arrangement::Geometry_traits_2;
using Face_const_handle = typename Arrangement::Face_const_handle;
using Render_context = Arr_render_context<Arrangement>;
using Approx_cache = Arr_approximation_cache<Arrangement>;
public:
Arr_bounded_renderer(const Render_context& ctx, Bbox_2 bbox) :
m_ctx(ctx),
m_bbox(bbox)
{}
Approx_cache render() const {
Approx_cache cache;
if(m_ctx.is_cancelled()) return cache;
cache.vertices().reserve(m_ctx.m_arr.number_of_vertices());
cache.halfedges().reserve(m_ctx.m_arr.number_of_halfedges());
cache.faces().reserve(m_ctx.m_arr.number_of_faces());
Arr_bounded_render_context<Arrangement> derived_ctx(m_ctx, m_bbox, cache);
Arr_bounded_approximate_face<Arrangement> bounded_approx_face(derived_ctx);
for(Face_const_handle fh = m_ctx.m_arr.faces_begin(); fh != m_ctx.m_arr.faces_end(); ++fh) bounded_approx_face(fh);
return cache;
}
private:
const Render_context& m_ctx;
const Bbox_2 m_bbox;
};
} // namespace draw_aos
} // namespace CGAL
#endif

View File

@ -0,0 +1,112 @@
// Copyright (c) 2025
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s): Shepard Liu <shepard0liu@gmail.com>
#ifndef CGAL_DRAW_AOS_ARR_COORDINATE_CONVERTER_H
#define CGAL_DRAW_AOS_ARR_COORDINATE_CONVERTER_H
#include <CGAL/license/Arrangement_on_surface_2.h>
#include <cmath>
#include <CGAL/number_type_config.h>
#include <CGAL/Arr_geodesic_arc_on_sphere_traits_2.h>
#include <CGAL/Draw_aos/type_utils.h>
namespace CGAL {
namespace draw_aos {
/*! \brief class handling coordinate conversion between 2D parameterized surface coordinates and cartesian coordinates.
*
* \tparam GeomTraits
*/
template <typename GeomTraits>
class Arr_coordinate_converter {
using Geom_traits = GeomTraits;
using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Approx_point = typename Approx_traits::Approx_point;
using Point = typename Approx_traits::Point;
public:
Arr_coordinate_converter(const GeomTraits& traits) : m_traits(traits) {}
/*! \brief converts a point in cartesian coordinates to parameterized surface coordinates.
*
* \param pt
* \return Point
*/
Point to_uv(Approx_point pt) const { return pt; }
/*! \brief Converts a point in parameterized surface coordinates to cartesian coordinates.
*
* \param pt
* \return Approx_point
*/
Approx_point to_cartesian(Point pt) const { return pt; }
private:
const GeomTraits& m_traits;
};
/*! \brief Converter specialization for geodesic arc on sphere traits.
*
* 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
* azimuth == 0. The south pole has polar == 0.
*
* \tparam Kernel
* \tparam atanX
* \tparam atanY
*/
template <typename Kernel, int atanX, int 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 Approx_traits = Arr_approximate_traits<Geom_traits>;
using Approx_point = typename Approx_traits::Approx_point;
using Approx_nt = typename Approx_traits::Approx_nt;
using Point = typename Approx_traits::Point;
public:
Arr_coordinate_converter(const Geom_traits& traits) : m_traits(traits) {}
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::MIN_BOUNDARY_LOC) return Point(0, 0);
Approx_nt azimuth_from_id =
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()));
}
Approx_point to_cartesian(Point point) const {
using Direction_3 = typename Geom_traits::Approximate_kernel::Direction_3;
Approx_nt polar = point.y();
if(point.y() == CGAL_PI) return Approx_point(Direction_3(0, 0, 1), Approx_point::MAX_BOUNDARY_LOC);
if(point.y() == 0) return Approx_point(Direction_3(0, 0, -1), Approx_point::MIN_BOUNDARY_LOC);
Approx_nt azimuth = point.x() + std::atan2(atanY, atanX);
Approx_nt x = std::sin(polar) * std::cos(azimuth);
Approx_nt y = std::sin(polar) * std::sin(azimuth);
Approx_nt z = -std::cos(polar);
Direction_3 dir(x, y, z);
return Approx_point(dir, azimuth == 0 ? Approx_point::MID_BOUNDARY_LOC : Approx_point::NO_BOUNDARY_LOC);
}
private:
const Geom_traits& m_traits;
};
} // namespace draw_aos
} // namespace CGAL
#endif

View File

@ -0,0 +1,101 @@
// Copyright (c) 2025
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s): Shepard Liu <shepard0liu@gmail.com>
#ifndef CGAL_DRAW_AOS_ARR_FACE_POINT_GENERATOR_H
#define CGAL_DRAW_AOS_ARR_FACE_POINT_GENERATOR_H
#include <CGAL/license/Arrangement_on_surface_2.h>
#include <utility>
#include <variant>
#include <vector>
#include <boost/iterator/function_output_iterator.hpp>
#include "CGAL/unordered_flat_map.h"
#include "CGAL/Arr_batched_point_location.h"
#include "CGAL/Arr_point_location_result.h"
#include "CGAL/Draw_aos/Arr_coordinate_converter.h"
#include "CGAL/Draw_aos/type_utils.h"
namespace CGAL {
namespace draw_aos {
/*! \brief Generate face interior points.
*
* \tparam Arrangement
*/
template <typename Arrangement, typename = void>
class Arr_face_point_generator;
template <typename Arrangement>
class Arr_face_point_generator<Arrangement,
std::enable_if_t<!is_or_derived_from_curved_surf_traits_v
<typename Arrangement::Geometry_traits_2>>> {
using Point_geom = typename Arr_approximate_traits<typename Arrangement::Geometry_traits_2>::Point;
using Face_const_handle = typename Arrangement::Face_const_handle;
public:
using Face_points_map = unordered_flat_map<Face_const_handle, std::vector<Point_geom>>;
// No-op implementation for non-curved surface arrangements.
Face_points_map operator()(const Arrangement&, double) { return {}; }
};
template <typename Arrangement>
class Arr_face_point_generator<Arrangement,
std::enable_if_t<is_or_derived_from_agas_v<typename Arrangement::Geometry_traits_2>>> {
using Geom_traits = typename Arrangement::Geometry_traits_2;
using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Approx_nt = typename Approx_traits::Approx_nt;
using Point = typename Approx_traits::Point;
using Face_const_handle = typename Arrangement::Face_const_handle;
using Gt_point = typename Geom_traits::Point_2;
using Query_result = std::pair<Gt_point, typename Arr_point_location_result<Arrangement>::Type>;
public:
using Face_points_map = unordered_flat_map<Face_const_handle, std::vector<Point>>;
Face_points_map operator()(const Arrangement& arr, double error) {
const Geom_traits& traits = *arr.geometry_traits();
// Grid sampling in parameter space.
Approx_nt cell_size = 2.0 * std::acos(1 - error);
std::vector<Gt_point> points;
Arr_coordinate_converter<Geom_traits> coords(traits);
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 y = 0; y < CGAL_PI; y += cell_size) {
auto pt = coords.to_cartesian(Point(x, y));
points.push_back(traits.construct_point_2_object()(pt.dx(), pt.dy(), pt.dz()));
}
}
unordered_flat_map<Face_const_handle, std::vector<Point>> face_points;
CGAL::locate(arr, points.begin(), points.end(),
boost::make_function_output_iterator([&face_points, &traits, &coords](const Query_result& res) {
if (! std::holds_alternative<Face_const_handle>(res.second)) return;
Face_const_handle fh = std::get<Face_const_handle>(res.second);
auto [it, _] = face_points.try_emplace(fh, std::vector<Point>());
it->second.push_back(coords.to_uv(traits.approximate_2_object()(res.first)));
}));
return face_points;
}
};
} // namespace draw_aos
} // namespace CGAL
#endif

View File

@ -0,0 +1,178 @@
// Copyright (c) 2025
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s): Shepard Li <shepard0liu@gmail.com>
#ifndef CGAL_DRAW_AOS_ARR_RENDER_CONTEXT_H
#define CGAL_DRAW_AOS_ARR_RENDER_CONTEXT_H
#include <CGAL/license/Arrangement_on_surface_2.h>
#include <cstdlib>
#include <memory>
#include <atomic>
#include <chrono>
#include <CGAL/Bbox_2.h>
#include <CGAL/Arr_point_location_result.h>
#include <CGAL/Arr_trapezoid_ric_point_location.h>
#include <CGAL/Arrangement_2.h>
#include <CGAL/Draw_aos/Arr_approximation_cache.h>
#include <CGAL/Draw_aos/type_utils.h>
#include <CGAL/Draw_aos/Arr_face_point_generator.h>
#include <CGAL/Draw_aos/Arr_coordinate_converter.h>
#if defined(CGAL_DRAW_AOS_DEBUG)
#include <fstream>
#endif
namespace CGAL {
namespace draw_aos {
/** @brief A cancellable context mixin for asynchronous operations. It also tracks elapsed time for performance
* profiling.
*
* The idea is borrowed from golang with a simple implementation.
* @see https://pkg.go.dev/context
*/
class Arr_cancellable_context_mixin {
using Clock = std::chrono::steady_clock;
using Duration = Clock::duration;
using Time_point = std::chrono::time_point<Clock, Duration>;
protected:
Arr_cancellable_context_mixin() :
m_start_time(Clock::now()),
m_cancelled(std::make_shared<std::atomic<bool>>(false))
{}
public:
Time_point start_time() const { return m_start_time; }
Time_point end_time() const { return m_end_time; }
Duration elapsed_time() const { return Clock::now() - m_start_time; }
bool is_cancelled() const { return m_cancelled->load(); }
void cancel() {
m_cancelled->store(true, std::memory_order_relaxed);
m_end_time = Clock::now();
}
private:
Time_point m_start_time, m_end_time;
std::shared_ptr<std::atomic<bool>> m_cancelled;
};
/** @brief Boundary context mixin for rendering arrangements within a bounding box.
* Provides extended functionality for checking point-bbox relations.
*
* @tparam GeomTraits the geometry traits class.
*/
template <typename GeomTraits>
class Arr_bounds_context_mixin {
using Geom_traits = GeomTraits;
using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Point = typename Approx_traits::Point;
using Approx_nt = typename Approx_traits::Approx_nt;
protected:
Arr_bounds_context_mixin(const Bbox_2& bbox) : m_bbox(bbox) {}
public:
double xmin() const { return m_bbox.xmin(); }
double xmax() const { return m_bbox.xmax(); }
double ymin() const { return m_bbox.ymin(); }
double ymax() const { return m_bbox.ymax(); }
const Bbox_2& bbox() const { return m_bbox; }
bool contains_x(Approx_nt x) const { return xmin() <= x && x <= xmax(); }
bool contains_y(Approx_nt y) const { return ymin() <= y && y <= ymax(); }
bool contains(Point pt) const { return contains_x(pt.x()) && contains_y(pt.y()); }
Point top_left() const { return Point(xmin(), ymax()); }
Point top_right() const { return Point(xmax(), ymax()); }
Point bottom_left() const { return Point(xmin(), ymin()); }
Point bottom_right() const { return Point(xmax(), ymin()); }
bool is_on_left(Point pt) const { return pt.x() == xmin() && contains_y(pt.y()); }
bool is_on_right(Point pt) const { return pt.x() == xmax() && contains_y(pt.y()); }
bool is_on_bottom(Point pt) const { return pt.y() == ymin() && contains_x(pt.x()); }
bool is_on_top(Point pt) const { return pt.y() == ymax() && contains_x(pt.x()); }
bool is_on_boundary(Point pt) const { return is_on_left(pt) || is_on_right(pt) || is_on_bottom(pt) || is_on_top(pt); }
private:
const Bbox_2 m_bbox;
};
template <typename GeomTraits>
using Arr_parameterization_context_mixin = Arr_coordinate_converter<GeomTraits>;
template <typename Arrangement>
class Arr_render_context :
public Arr_cancellable_context_mixin,
public Arr_parameterization_context_mixin<typename Arrangement::Geometry_traits_2> {
using Cancellable_context_mixin = Arr_cancellable_context_mixin;
using Param_context_mixin = Arr_parameterization_context_mixin<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;
public:
Arr_render_context(const Arrangement& arr, double approx_error, Face_points_map& face_points) :
Cancellable_context_mixin(),
Param_context_mixin(*arr.geometry_traits()),
m_arr(arr),
m_traits(*arr.geometry_traits()),
m_approx_error(approx_error),
m_face_points(face_points) {
#if defined(CGAL_DRAW_AOS_DEBUG) && defined(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR)
std::filesystem::path debug_file_dir(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR);
// clear the index file.
std::filesystem::remove(debug_file_dir / "index.txt");
#endif
}
public:
const Arrangement& m_arr;
const Geom_traits& m_traits;
const double m_approx_error;
const Face_points_map& m_face_points;
#if defined(CGAL_DRAW_AOS_DEBUG)
std::shared_ptr<int> debug_counter = std::make_shared<int>(0);
#endif
};
template <typename Arrangement>
class Arr_bounded_render_context :
public Arr_render_context<Arrangement>,
public Arr_bounds_context_mixin<typename Arrangement::Geometry_traits_2> {
using Geom_traits = typename Arrangement::Geometry_traits_2;
using Approx_point = typename Geom_traits::Approximate_point_2;
using Render_context = Arr_render_context<Arrangement>;
using Bounds_context_mixin = Arr_bounds_context_mixin<Geom_traits>;
using Approx_cache = Arr_approximation_cache<Arrangement>;
public:
Arr_bounded_render_context(const Render_context& ctx, const Bbox_2& bbox, Approx_cache& cache) :
Render_context(ctx),
Bounds_context_mixin(bbox),
m_cache(cache)
{}
public:
Approx_cache& m_cache;
};
} // namespace draw_aos
} // namespace CGAL
#endif

View File

@ -0,0 +1,358 @@
// Copyright (c) 2025
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s): Shepard Liu <shepard0liu@gmail.com>
#ifndef ARR_VIEWER_H
#define ARR_VIEWER_H
#include <algorithm>
#include <array>
#include <cstdlib>
#include <type_traits>
#include <QWidget>
#include <CGAL/Qt/Basic_viewer.h>
#include <CGAL/Qt/camera.h>
#include <CGAL/IO/Color.h>
#include <CGAL/Basic_viewer.h>
#include <CGAL/Bbox_2.h>
#include <CGAL/Graphics_scene.h>
#include <CGAL/Qt/camera.h>
#include <CGAL/Graphics_scene.h>
#include <CGAL/Graphics_scene_options.h>
#include <CGAL/Buffer_for_vao.h>
#include <CGAL/Arr_enums.h>
#include <CGAL/Draw_aos/type_utils.h>
#include <CGAL/Draw_aos/Arr_render_context.h>
#include <CGAL/Draw_aos/Arr_bounded_renderer.h>
#include <CGAL/Draw_aos/Arr_coordinate_converter.h>
#include <CGAL/Draw_aos/Arr_face_point_generator.h>
namespace CGAL {
namespace draw_aos {
/*! \brief Viewport helper functions
*
* \tparam Arrangement
*/
template <typename Arrangement, typename = void>
class Arr_viewport_helpers;
// Specialization for planar arrangements
template <typename Arrangement>
class Arr_viewport_helpers<Arrangement,
std::enable_if_t<! is_or_derived_from_curved_surf_traits_v
<typename Arrangement::Geometry_traits_2>>> {
using Geom_traits = typename Arrangement::Geometry_traits_2;
using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Approx_point = typename Approx_traits::Approx_point;
using Camera = qglviewer::Camera;
using Point = typename Approx_traits::Point;
using Local_point = Buffer_for_vao::Local_point;
protected:
Arr_viewport_helpers(const Arrangement& arr) : m_arr(arr) {}
/*! \brief Computes a subpixel-level approximation error based on the bounding box and viewport width.
*
* \param bbox
* \param viewport_width width of the viewport in pixels
* \return double
*/
double approximation_error(const Bbox_2& bbox, int viewport_width) const
{ return bbox.x_span() / viewport_width; }
/*! \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.
* \return Bbox_2
*/
Bbox_2 arr_bbox() const {
const auto& traits = *m_arr.geometry_traits();
Bbox_2 bbox;
// Computes a rough bounding box from the vertices.
for (const auto& vh : m_arr.vertex_handles())
bbox += traits.approximate_2_object()(vh->point()).bbox();
double approx_error = approximation_error(bbox, 100);
// Computes a more precise bounding box from the halfedges.
auto approx = traits.approximate_2_object();
for (const auto& he : m_arr.halfedge_handles()) {
approx(he->curve(), approx_error,
boost::make_function_output_iterator([&bbox](Approx_point pt) { bbox += pt.bbox(); }));
}
// Place margin around the bbox.
double dx = bbox.x_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);
// 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.y_span() == 0) bbox += Bbox_2(bbox.xmin(), bbox.ymin() - 1, bbox.xmax(), bbox.ymax() + 1);
return bbox;
}
/*! \brief Fits the camera to bbox.
*
* \param bbox
* \param camera
*/
void fit_camera(const Bbox_2& bbox, Camera& cam) const {
using Vec = qglviewer::Vec;
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.
*
* \param cam
* \return Bbox_2
*/
Bbox_2 screen_to_world(const Camera& cam) const {
QMatrix4x4 mvp;
cam.getModelViewProjectionMatrix(mvp.data());
QMatrix4x4 inverse_mvp = mvp.inverted();
// Define 4 corners of the near plane in NDC (-1 to 1 in x and y)
std::array<QVector4D, 4> clip_space_corners{QVector4D(-1.0, -1.0, 0.0, 1.0), QVector4D(-1.0, 1.0, 0.0, 1.0),
QVector4D(1.0, -1.0, 0.0, 1.0), QVector4D(1.0, 1.0, 0.0, 1.0)};
double xmin = std::numeric_limits<double>::max();
double xmax = std::numeric_limits<double>::lowest();
double ymin = std::numeric_limits<double>::max();
double ymax = std::numeric_limits<double>::lowest();
for (const QVector4D& corner : clip_space_corners) {
QVector4D world = inverse_mvp * corner;
if (world.w() != 0.0) world /= world.w();
double x = world.x();
double y = world.y();
xmin = std::min(xmin, x);
xmax = std::max(xmax, x);
ymin = std::min(ymin, y);
ymax = std::max(ymax, y);
}
return Bbox_2(xmin, ymin, xmax, ymax);
}
/*! \brief Converts a parameter space point to a local point of the buffer object.
*
* \param pt
* \return Local_point
*/
Local_point to_local_point(Point pt) const { return Local_point(pt.x(), pt.y(), 0.0); }
private:
const Arrangement& m_arr;
};
// Spherical arrangement specialization
template <typename Arrangement>
class Arr_viewport_helpers<Arrangement,
std::enable_if_t<is_or_derived_from_agas_v<typename Arrangement::Geometry_traits_2>>> {
using Geom_traits = typename Arrangement::Geometry_traits_2;
using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Approx_point = typename Approx_traits::Approx_point;
using Camera = qglviewer::Camera;
using Point = typename Approx_traits::Point;
using Local_point = Buffer_for_vao::Local_point;
protected:
Arr_viewport_helpers(const Arrangement& arr) : m_arr(arr) {}
Bbox_2 arr_bbox() const { return Bbox_2(0, 0, 2 * CGAL_PI, CGAL_PI); }
Bbox_2 screen_to_world(const Camera& /* cam */) const { return Bbox_2(0, 0, 2 * CGAL_PI, CGAL_PI); }
void fit_camera(const Bbox_2&, Camera& cam) {
using Vec = qglviewer::Vec;
cam.setSceneCenter(Vec(0, 0, 0));
cam.fitSphere(Vec(0, 0, 0), 1.1); // slightly larger than the unit sphere
}
double approximation_error(const Bbox_2& bbox, int viewport_width) const {
// If crossing hemisphere
if (bbox.x_span() >= CGAL_PI) return 1.0 / viewport_width;
// Otherwise we evaluate the error bound with respect to the longest longitude arc
double theta =
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;
}
Buffer_for_vao::Local_point to_local_point(Point pt) const {
auto approx_pt = Arr_coordinate_converter<Geom_traits>(*m_arr.geometry_traits()).to_cartesian(pt);
return Buffer_for_vao::Local_point(approx_pt.dx(), approx_pt.dy(), approx_pt.dz());
}
private:
const Arrangement& m_arr;
};
/*! Viewer for visualizing arrangements on surface.
*
* \tparam Arrangement
* \tparam GSOptions
*/
template <typename Arrangement, typename GSOptions>
class Arr_viewer : public Qt::Basic_viewer, Arr_viewport_helpers<Arrangement> {
using Basic_viewer = Qt::Basic_viewer;
using Helpers = Arr_viewport_helpers<Arrangement>;
using Vertex_const_handle = typename Arrangement::Vertex_const_handle;
using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle;
using Face_const_handle = typename Arrangement::Face_const_handle;
using Geom_traits = typename Arrangement::Geometry_traits_2;
using Approx_traits = Arr_approximate_traits<Geom_traits>;
using Approx_point = typename Approx_traits::Approx_point;
using Point = typename Approx_traits::Point;
using Point_generator = Arr_face_point_generator<Arrangement>;
using Faces_point_map = typename Point_generator::Face_points_map;
struct Render_params {
bool operator==(const Render_params& other) const
{ return bbox == other.bbox && approx_error == other.approx_error; }
Bbox_2 bbox;
double approx_error{0};
};
constexpr static bool Is_on_curved_surface = is_or_derived_from_curved_surf_traits_v<Geom_traits>;
private:
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(); }
int viewport_width() const {
std::array<GLint, 4> viewport;
this->camera_->getViewport(viewport.data());
return viewport[2];
}
Render_params compute_render_params() {
Render_params params;
params.bbox = this->screen_to_world(*this->camera_);
params.approx_error = this->approximation_error(params.bbox, viewport_width());
return params;
}
void render_arr(const Render_params& params) {
const Bbox_2& bbox = params.bbox;
auto face_points = Point_generator()(m_arr, params.approx_error);
Arr_render_context<Arrangement> ctx(m_arr, params.approx_error, face_points);
Arr_bounded_renderer<Arrangement> renderer(ctx, bbox);
auto cache = renderer.render();
// add faces
for (const auto& [fh, tf] : cache.faces()) {
if (! m_gso.draw_face(m_arr, fh)) continue;
bool colored_face = m_gso.colored_face(m_arr, fh);
auto color = colored_face ? m_gso.face_color(m_arr, fh) : CGAL::IO::Color();
for (const auto& tri : tf.triangles) {
if (colored_face) m_gs.face_begin(color);
else 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();
}
}
// add edges
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;
bool colored_edge = m_gso.colored_edge(m_arr, he);
auto color = colored_edge ? m_gso.edge_color(m_arr, he) : CGAL::IO::Color();
// skip first two if starts with a sep point.
int start_idx = Approx_traits::is_null(polyline.front()) ? 2 : 0;
// skip last two if ends with a sep point.
int end_idx = Approx_traits::is_null(polyline.back()) ? polyline.size() - 2 : polyline.size();
for (int i = start_idx; i < end_idx - 1; ++i) {
const auto& src = polyline[i];
const auto& tgt = polyline[i + 1];
if (Approx_traits::is_null(src) || Approx_traits::is_null(tgt)) continue;
if (! contains(bbox, src) || !contains(bbox, tgt)) continue;
if (colored_edge)
m_gs.add_segment(this->to_local_point(src), this->to_local_point(tgt), color);
else
m_gs.add_segment(this->to_local_point(src), this->to_local_point(tgt));
}
}
// add vertices
for (const auto& [vh, pt] : cache.vertices()) {
if (! m_gso.draw_vertex(m_arr, vh) || !contains(bbox, pt)) continue;
if (m_gso.colored_vertex(m_arr, vh))
m_gs.add_point(this->to_local_point(pt), m_gso.vertex_color(m_arr, vh));
else
m_gs.add_point(this->to_local_point(pt));
}
}
/*! \brief Rerender scene within the given bounding box.
*
* \param bbox
*/
void rerender(const Render_params& params) {
if (params == m_last_params) return;
m_last_params = params;
m_gs.clear();
render_arr(params);
Basic_viewer::redraw();
}
public:
Arr_viewer(QWidget* parent, const Arrangement& arr, const GSOptions& gso, const char* title, Bbox_2 initial_bbox) :
Basic_viewer(parent, m_gs, title),
Helpers(arr),
m_gso(gso),
m_arr(arr),
m_coords(*arr.geometry_traits()) {
if ((initial_bbox.x_span() == 0) || (initial_bbox.y_span() == 0) || (Is_on_curved_surface))
m_initial_bbox = this->arr_bbox();
else
m_initial_bbox = initial_bbox;
}
virtual void draw() override {
Render_params params = compute_render_params();
#if defined(CGAL_DRAW_AOS_DEBUG)
if constexpr(! is_or_derived_from_agas_v<Geom_traits>) {
Bbox_2& bbox = params.bbox;
double dx = (bbox.xmax() - bbox.xmin()) * 0.1;
double dy = (bbox.ymax() - bbox.ymin()) * 0.1;
bbox = Bbox_2(bbox.xmin() + dx, bbox.ymin() + dy, bbox.xmax() - dx, bbox.ymax() - dy);
std::cout << "Camera changed, recomputing arrangement bounding box: " << bbox << std::endl;
}
#endif
rerender(params);
if (! m_initialized) {
// 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.
this->fit_camera(m_initial_bbox, *this->camera_);
m_initialized = true;
}
Basic_viewer::draw();
}
virtual ~Arr_viewer() {}
private:
Graphics_scene m_gs;
GSOptions m_gso;
const Arrangement& m_arr;
bool m_initialized{false};
Bbox_2 m_initial_bbox;
const Arr_coordinate_converter<Geom_traits> m_coords;
Render_params m_last_params;
};
} // namespace draw_aos
} // namespace CGAL
#endif

View File

@ -0,0 +1,223 @@
// Copyright (c) 2025
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s): Shepard Liu <shepard0liu@gmail.com>
#ifndef CGAL_DRAW_AOS_TYPE_UTILS_H
#define CGAL_DRAW_AOS_TYPE_UTILS_H
#include <CGAL/license/Arrangement_on_surface_2.h>
#include <limits>
#include <vector>
#include <type_traits>
#include <cmath>
#include <CGAL/Arr_geodesic_arc_on_sphere_traits_2.h>
namespace CGAL {
namespace draw_aos {
enum class Boundary_side {
Top = 0,
Left = 1,
Bottom = 2,
Right = 3,
None = -1,
};
template <typename, typename = std::void_t<>>
struct has_approximate_2_object : std::false_type {};
template <typename Gt>
struct has_approximate_2_object<Gt, std::void_t<decltype(std::declval<Gt>().approximate_2_object())>> : std::true_type
{};
// Detect whether Gt has defined a member function approximate_2_object()
template <typename Gt>
inline constexpr bool has_approximate_2_object_v = has_approximate_2_object<Gt>::value;
template <typename, typename, typename = std::void_t<>>
struct has_approximate_point : std::false_type {};
template <typename Gt, typename A>
struct has_approximate_point<Gt,
A,
std::void_t<decltype(std::declval<A>()(std::declval<const typename Gt::Point_2&>()))>> :
std::true_type
{};
// Detect whether A has operator()(const Gt::Point_2&)
template <typename Gt, typename A>
inline constexpr bool has_approximate_point_v = has_approximate_point<Gt, A>::value;
template <typename, typename, typename, typename = std::void_t<>>
struct has_approximate_xcv : std::false_type {};
template <typename Gt, typename A, typename O>
struct has_approximate_xcv
<Gt,
A,
O,
std::void_t<decltype(std::declval<A&>()(std::declval<const typename Gt::X_monotone_curve_2&>(),
std::declval<double>(),
std::declval<O>(),
std::declval<bool>()))>> : std::true_type
{};
// Detect whether A has operator()(const Gt::X_monotone_curve_2&, double, OutputIterator, bool)?
template <typename Gt, typename A>
constexpr bool has_approximate_xcv_v = has_approximate_xcv<Gt, A, void*>::value;
template <typename, typename, typename, typename = std::void_t<>>
struct has_approximate_xcv_with_bounds : std::false_type
{};
template <typename Gt, typename A, typename O>
struct has_approximate_xcv_with_bounds
<Gt,
A,
O,
std::void_t<decltype(std::declval<A&>()(std::declval<const typename Gt::X_monotone_curve_2&>(),
std::declval<double>(),
std::declval<O>(),
std::declval<Bbox_2>(),
std::declval<bool>()))>> : std::true_type
{};
// Detect whether A has operator()(const X_monotone_curve&, double, OutputIterator, Bbox_2, bool)
template <typename Gt, typename A>
inline constexpr bool has_approximate_xcv_with_bounds_v = has_approximate_xcv_with_bounds<Gt, A, void*>::value;
// Detect whether a geometry traits has all the necessary types and functions for approximation
template <typename Gt>
constexpr bool has_approximate_traits_v =
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_with_bounds_v<Gt, typename Gt::Approximate_2>);
template <typename Gt, typename = std::void_t<>>
struct has_is_in_x_range : std::false_type
{};
template <typename 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::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&)
template <typename Gt>
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<*, *, *>
template <typename Gt>
struct is_or_derived_from_agas {
private:
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::false_type test(...);
public:
static constexpr bool value = decltype(test(static_cast<const Gt*>(nullptr)))::value;
};
template <typename Gt>
inline constexpr bool is_or_derived_from_agas_v = is_or_derived_from_agas<Gt>::value;
// Detect whether T is or derives from a geometry traits on curved surfaces
template <typename Gt>
inline constexpr bool is_or_derived_from_curved_surf_traits_v = is_or_derived_from_agas_v<Gt>;
// Static helpers to get template arguments from a geometry traits
template <typename Gt>
struct tmpl_args {};
template <typename Kernel_, int AtanX, int AtanY>
struct tmpl_args<Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY>> {
using Kernel = Kernel_;
static constexpr int atan_x = AtanX;
static constexpr int atan_y = AtanY;
};
/*! \brief Approximation data types
*
* \tparam Gt Geometry traits
*/
template <typename Gt>
class Arr_approximate_traits {
using Geom_traits = Gt;
template <typename P, typename I>
struct Triangle_soup_ {
using Index = I;
using Triangle = std::array<Index, 3>;
using Point = P;
std::vector<Point> points;
std::vector<Triangle> triangles;
};
public:
using Approx_point = typename Geom_traits::Approximate_point_2;
using Approx_nt = typename Geom_traits::Approximate_number_type;
using Approx_kernel = typename Geom_traits::Approximate_kernel;
// 2D parameter space point
using Point = typename Approx_kernel::Point_2;
using Polyline = std::vector<Point>;
using Triangle_soup = Triangle_soup_<Point, int>;
// A null point with NaN coordinates. Use ::is_null(pt) to check if a point is null.
inline static const Point Null_point =
Point(std::numeric_limits<Approx_nt>::signaling_NaN(), std::numeric_limits<Approx_nt>::signaling_NaN());
static bool is_null(Point pt) { return std::isnan(pt.x()) || std::isnan(pt.y()); }
};
/*!
* \brief Functor to construct a Point_2 from an Approximate_point_2.
*
* \tparam Gt Geometry traits
*/
template <typename Gt>
class Construct_gt_point_2 {
using Approx_traits = Arr_approximate_traits<Gt>;
using Approx_point = typename Approx_traits::Approx_point;
using Gt_point = typename Gt::Point_2;
public:
Gt_point operator()(const Approx_point& pt) const { return Gt_point(pt.x(), pt.y()); }
};
// Specialization for Arr_geodesic_arc_on_sphere_traits_2
template <typename Kernel, int AtanX, int 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 Approx_traits = Arr_approximate_traits<Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>>;
using Approx_point = typename Approx_traits::Approx_point;
using Gt_point = typename Geom_traits::Point_2;
public:
Gt_point operator()(const Approx_point& pt) const {
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()));
}
};
} // namespace draw_aos
} // namespace CGAL
#endif // CGAL_DRAW_AOS_TYPE_UTILS_H

File diff suppressed because it is too large Load Diff

View File

@ -87,9 +87,9 @@ boost::graph_traits<Graph>::edge_iterator ei;
Algorithms obtain incidence information in graphs with the help of global
functions such as:
- `std::pair<vertex_iterator,vertex_iterator> vertices(const Graph& g);` to obtain an iterator range providing access to all the vertices, or
- `vertices_size_type num_vertices(const Graph&);` to obtain the number of vertices of a graph, or
- `vertex_descriptor source(edge_descriptor, const Graph&);` to obtain the source vertex of an edge.
- \ref VertexListGraph::vertices(const VertexListGraph&) "std::pair<vertex_iterator,vertex_iterator> vertices(const Graph& g)" to obtain an iterator range providing access to all the vertices, or
- \link VertexListGraph::num_vertices(const VertexListGraph&) `vertices_size_type num_vertices(const Graph&)`\endlink to obtain the number of vertices of a graph, or
- \link IncidenceGraph `vertex_descriptor source(edge_descriptor, const Graph&)` \endlink to obtain the source vertex of an edge.
Note, that the way we have written the types is a simplification; in reality,
the signature of the first of the above functions is:

View File

@ -31,7 +31,7 @@ the dot operator, and a typical usage is thus:
\code {.cpp}
Graph g1, g2;
Vertex_point_map_2 vpm_2; // an hypothetical custom property map assigning a Point to the vertices of g2
Vertex_point_map_2 vpm_2; // a hypothetical custom property map assigning a Point to the vertices of g2
// without any named parameter (default values are used)
CGAL::copy_face_graph(g1, g2);

View File

@ -509,8 +509,7 @@ the requirement for traversal of all faces in a graph.
/// I/O Functions for the \ref IOStream3MF
/// \ingroup PkgBGLIOFct
/// \defgroup PkgBGLIOFctDeprecated I/O Functions (Deprecated)
/// \ingroup PkgBGLIOFct
/*!
\addtogroup PkgBGLPropertiesDynamic

View File

@ -585,8 +585,11 @@ add_edge(typename boost::graph_traits<Graph>::vertex_descriptor s,
* checks whether a new face defined by a range of vertices (identified by their descriptors,
* `boost::graph_traits<Graph>::%vertex_descriptor`) can be added.
*/
template <typename VertexRange,typename PMesh>
bool can_add_face(const VertexRange& vrange, const PMesh& sm)
template <typename VertexRange,
typename PMesh>
bool can_add_face(const VertexRange& vrange,
const PMesh& sm,
const bool verbose = false)
{
typedef typename boost::graph_traits<PMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<PMesh>::halfedge_descriptor halfedge_descriptor;
@ -603,10 +606,16 @@ bool can_add_face(const VertexRange& vrange, const PMesh& sm)
typename std::vector<vertex_descriptor>::iterator it = std::unique(f2.begin(),f2.end());
if((N > 0) && (it != f2.end())){
if (verbose){
std::cerr << "Cannot add face: face contains duplicate vertices." << std::endl;
}
return false;
}
if(N < 3){
if (verbose){
std::cerr << "Cannot add face: face must contain at least 3 vertices." << std::endl;
}
return false;
}
@ -617,6 +626,9 @@ bool can_add_face(const VertexRange& vrange, const PMesh& sm)
bool found;
std::tie(hd,found) = halfedge(face[i],face[i+1],sm);
if(found && (! is_border(hd,sm))){
if (verbose){
std::cerr << "Cannot add face: face contains an edge that is not a border halfedge." << std::endl;
}
return false;
}
}
@ -627,6 +639,9 @@ bool can_add_face(const VertexRange& vrange, const PMesh& sm)
}
if(! is_border(face[i],sm)){
if (verbose){
std::cerr << "Cannot add face: face contains a vertex that is not a border vertex." << std::endl;
}
return false;
}
}
@ -648,8 +663,9 @@ bool can_add_face(const VertexRange& vrange, const PMesh& sm)
if ( halfedge_around_vertex == boost::graph_traits<PMesh>::null_halfedge() ||
halfedge(previous_vertex,sm) == boost::graph_traits<PMesh>::null_halfedge()||
halfedge(next_vertex,sm) == boost::graph_traits<PMesh>::null_halfedge()
) continue;
halfedge(next_vertex,sm) == boost::graph_traits<PMesh>::null_halfedge() ) {
continue;
}
halfedge_descriptor start=halfedge_around_vertex;
//halfedges pointing to/running out from vertex indices[i]
@ -694,7 +710,12 @@ bool can_add_face(const VertexRange& vrange, const PMesh& sm)
if ( is_border(opposite(halfedge_around_vertex,sm),sm) ) break;
}
while (halfedge_around_vertex != prev_hd);
if (halfedge_around_vertex == prev_hd) return false;
if (halfedge_around_vertex == prev_hd) {
if (verbose){
std::cerr << "Cannot add face: halfedge_around_vertex == prev_hd" << std::endl;
}
return false;
}
start = halfedge_around_vertex;
}
}
@ -703,7 +724,6 @@ bool can_add_face(const VertexRange& vrange, const PMesh& sm)
}
/**
* adds a new face defined by a range of vertices (identified by their descriptors,
* `boost::graph_traits<Graph>::%vertex_descriptor`).
@ -1552,7 +1572,7 @@ does_satisfy_link_condition(typename boost::graph_traits<Graph>::edge_descriptor
*
* \returns vertex `v1`.
* \pre g must be a triangulated graph
* \pre `does_satisfy_link_condition(e,g) == true`.
* \pre \link CGAL::Euler::does_satisfy_link_condition `does_satisfy_link_condition`\endlink(e,g) == `true`.
*/
template<typename Graph>
typename boost::graph_traits<Graph>::vertex_descriptor
@ -1670,7 +1690,7 @@ collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor e,
* \returns vertex `v1`.
* \pre This function requires `g` to be an oriented 2-manifold with or without boundaries.
* Furthermore, the edge `v0v1` must satisfy the link condition, which guarantees that the surface mesh is also 2-manifold after the edge collapse.
* \pre `get(edge_is_constrained_map, v0v1)==false`.
* \pre `get(edge_is_constrained_map, v0v1) == false`.
* \pre `v0` and `v1` are not both incident to a constrained edge.
*/
@ -1876,7 +1896,7 @@ bool satisfies_link_condition(typename boost::graph_traits<Graph>::edge_descript
* \param h halfedge descriptor
* \param g the graph
*
* \returns an halfedge linking the two vertices adjacent to the vertex being removed.
* \returns a halfedge linking the two vertices adjacent to the vertex being removed.
*
* \pre `degree(target(h, g), g) == 2`.
*

View File

@ -144,8 +144,16 @@ public:
face[j] = vertices[m_faces[i][j]];
face_descriptor f = CGAL::Euler::add_face(face, g);
if(f == boost::graph_traits<Graph>::null_face())
if(f == boost::graph_traits<Graph>::null_face()) {
if (verbose) {
std::cerr << "Error: Failed to add face [" << i << "]\n";
std::cerr << "Diagnostic:" << std::endl;
CGAL_assertion_code(bool cannot_add = )
CGAL::Euler::can_add_face(face, g, true /*verbose*/);
CGAL_assertion(!cannot_add);
}
return false;
}
if(has_face_colors)
put(fcm, f, face_colors[i]);

View File

@ -247,36 +247,7 @@ bool read_OFF(const std::string& fname,
} // namespace IO
#ifndef CGAL_NO_DEPRECATED_CODE
/*!
\ingroup PkgBGLIOFctDeprecated
\deprecated This function is deprecated since \cgal 5.3, `CGAL::IO::read_OFF()` should be used instead.
*/
template <typename Graph, typename CGAL_NP_TEMPLATE_PARAMETERS>
CGAL_DEPRECATED bool read_off(std::istream& is, Graph& g, const CGAL_NP_CLASS& np = parameters::default_values())
{
return IO::read_OFF(is, g, np);
}
/*!
\ingroup PkgBGLIOFctDeprecated
\deprecated This function is deprecated since \cgal 5.3, `CGAL::IO::read_OFF()` should be used instead.
*/
template <typename Graph, typename CGAL_NP_TEMPLATE_PARAMETERS>
CGAL_DEPRECATED bool read_off(const char* fname, Graph& g, const CGAL_NP_CLASS& np = parameters::default_values())
{
return IO::read_OFF(fname, g, np);
}
template <typename Graph>
CGAL_DEPRECATED bool read_off(const std::string& fname, Graph& g)
{
return read_off(fname.c_str(), g, parameters::default_values());
}
#endif // CGAL_NO_DEPRECATED_CODE
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
@ -453,31 +424,6 @@ bool write_OFF(const std::string& fname,
} // namespace IO
#ifndef CGAL_NO_DEPRECATED_CODE
/*!
\ingroup PkgBGLIOFctDeprecated
\deprecated This function is deprecated since \cgal 5.3, `CGAL::IO::write_OFF()` should be used instead.
*/
template <typename Graph, typename CGAL_NP_TEMPLATE_PARAMETERS>
CGAL_DEPRECATED bool write_off(std::ostream& os, const Graph& g, const CGAL_NP_CLASS& np = parameters::default_values())
{
return IO::write_OFF(os, g, np);
}
/*!
\ingroup PkgBGLIOFctDeprecated
\deprecated This function is deprecated since \cgal 5.3, `CGAL::IO::write_OFF()` should be used instead.
*/
template <typename Graph, typename CGAL_NP_TEMPLATE_PARAMETERS>
CGAL_DEPRECATED bool write_off(const char* fname, const Graph& g, const CGAL_NP_CLASS& np = parameters::default_values())
{
return IO::write_OFF(fname, g, np);
}
#endif // CGAL_NO_DEPRECATED_CODE
} // namespace CGAL

View File

@ -529,20 +529,7 @@ bool write_VTP(const std::string& fname, const Graph& g, const CGAL_NP_CLASS& np
} // namespace IO
#ifndef CGAL_NO_DEPRECATED_CODE
/*!
\ingroup PkgBGLIOFctDeprecated
\deprecated This function is deprecated since \cgal 5.3, `CGAL::IO::write_VTP()` should be used instead.
*/
template <typename Graph, typename CGAL_NP_TEMPLATE_PARAMETERS>
CGAL_DEPRECATED bool write_vtp(std::ostream& os, const Graph& g, const CGAL_NP_CLASS& np = parameters::default_values())
{
return IO::write_VTP(os, g, np);
}
#endif // CGAL_NO_DEPRECATED_CODE
} // namespace CGAL

View File

@ -111,20 +111,7 @@ bool write_WRL(const std::string& fname, const Graph& g, const CGAL_NP_CLASS& np
} // namespace IO
#ifndef CGAL_NO_DEPRECATED_CODE
/*!
\ingroup PkgBGLIOFctDeprecated
\deprecated This function is deprecated since \cgal 5.3, `CGAL::IO::write_WRL()` should be used instead.
*/
template <typename Graph, typename CGAL_NP_TEMPLATE_PARAMETERS>
CGAL_DEPRECATED bool write_wrl(std::ostream& os, const Graph& g, const CGAL_NP_CLASS& np = parameters::default_values())
{
return IO::write_WRL(os, g, np);
}
#endif // CGAL_NO_DEPRECATED_CODE
} // namespace CGAL

View File

@ -67,23 +67,8 @@ template <CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS, typename CGAL_XX_YATP>
struct property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, DTAG<CGAL_XX_YATP> > \
: property_map<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME, DTAG<CGAL_XX_YATP> > \
{};\
} /* boost namespace */\
\
namespace CGAL { \
template <CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS, typename CGAL_XX_YATP>\
typename boost::property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, DTAG<CGAL_XX_YATP> >::type \
get(DTAG<CGAL_XX_YATP> t, CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, const CGAL_XX_YATP& default_value = CGAL_XX_YATP()) \
{ \
return get(t, static_cast<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME&>(g), default_value); \
} \
\
template <CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS, typename CGAL_XX_YATP>\
typename boost::property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, DTAG<CGAL_XX_YATP> >::const_type \
get(DTAG<CGAL_XX_YATP> t, const CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, const CGAL_XX_YATP& default_value = CGAL_XX_YATP()) \
{ \
return get(t, static_cast<const CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME&>(g), default_value); \
}\
} //CGAL namespace
} /* boost namespace */
CGAL_PM_DT_SPEC(CGAL::dynamic_vertex_property_t)
CGAL_PM_DT_SPEC(CGAL::dynamic_halfedge_property_t)
@ -94,12 +79,31 @@ CGAL_PM_DT_SPEC(CGAL::dynamic_edge_property_t)
namespace CGAL {
template <CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS,
typename Dynamic_property_tag,
typename = std::enable_if_t<is_dynamic_property_tag<Dynamic_property_tag>()>,
typename ...Default_value_args>
auto
get(Dynamic_property_tag t, CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, Default_value_args&&... default_value_args)
{
return get(t, static_cast<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME&>(g), default_value_args...);
}
template <CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS,
typename Dynamic_property_tag,
typename = std::enable_if_t<is_dynamic_property_tag<Dynamic_property_tag>()>,
typename ...Default_value_args>
auto
get(Dynamic_property_tag t, const CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, Default_value_args&&... default_value_args)
{
return get(t, static_cast<const CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME&>(g), default_value_args...);
}
template <CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS, typename CGAL_XX_YATP>
struct graph_has_property<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, CGAL_XX_YATP> :
public CGAL::graph_has_property<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME, CGAL_XX_YATP>
{};
} // CGAL namespace
#undef CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS
@ -126,23 +130,8 @@ template <typename CGAL_XX_YATP> \
struct property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, DTAG<CGAL_XX_YATP> > \
: property_map<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME, DTAG<CGAL_XX_YATP> > \
{};\
} /* boost namespace */\
\
namespace CGAL { \
template <typename CGAL_XX_YATP>\
typename boost::property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, DTAG<CGAL_XX_YATP> >::type \
get(DTAG<CGAL_XX_YATP> t, CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, const CGAL_XX_YATP& default_value = CGAL_XX_YATP()) \
{ \
return get(t, static_cast<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME&>(g), default_value); \
} \
\
template <typename CGAL_XX_YATP>\
typename boost::property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, DTAG<CGAL_XX_YATP> >::const_type \
get(DTAG<CGAL_XX_YATP> t, const CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, const CGAL_XX_YATP& default_value = CGAL_XX_YATP()) \
{ \
return get(t, static_cast<const CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME&>(g), default_value); \
}\
} //CGAL namespace
} /* boost namespace */
CGAL_PM_DT_SPEC(CGAL::dynamic_vertex_property_t)
CGAL_PM_DT_SPEC(CGAL::dynamic_halfedge_property_t)
@ -153,14 +142,32 @@ CGAL_PM_DT_SPEC(CGAL::dynamic_edge_property_t)
namespace CGAL {
template <typename Dynamic_property_tag,
typename = std::enable_if_t<is_dynamic_property_tag<Dynamic_property_tag>()>,
typename ...Default_value_args>
auto
get(Dynamic_property_tag t, CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, Default_value_args&&... default_value_args)
{
return get(t, static_cast<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME&>(g), default_value_args...);
}
template <typename Dynamic_property_tag,
typename = std::enable_if_t<is_dynamic_property_tag<Dynamic_property_tag>()>,
typename ...Default_value_args>
auto
get(Dynamic_property_tag t, const CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, Default_value_args&&... default_value_args)
{
return get(t, static_cast<const CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME&>(g), default_value_args...);
}
template <typename CGAL_XX_YATP>
struct graph_has_property<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, CGAL_XX_YATP> :
public CGAL::graph_has_property<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME, CGAL_XX_YATP>
{};
} // CGAL namespace
#endif

View File

@ -537,7 +537,7 @@ bool is_valid_polygon_mesh(const Mesh& g, bool verb = false)
return false;
// test for 2-manifoldness
// Distinct facets on each side of an halfedge.
// Distinct facets on each side of a halfedge.
for(halfedge_descriptor i : halfedges(g))
{
valid = (face(i, g) != face(opposite(i, g), g));

View File

@ -871,7 +871,54 @@ private:
*/
template <typename Graph>
class Face_around_face_circulator
{};
#ifndef DOXYGEN_RUNNING
: public boost::iterator_adaptor<
Face_around_face_circulator<Graph> // Derived
, Halfedge_around_face_circulator<Graph> // Base
, typename boost::graph_traits<Graph>::face_descriptor // Value
, Bidirectional_circulator_tag // CategoryOrTraversal
, typename boost::graph_traits<Graph>::face_descriptor // Reference
>
#endif
{
internal::Opposite_face<Graph> fct;
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
public:
#ifndef DOXYGEN_RUNNING
typedef std::size_t size_type;
#endif
Face_around_face_circulator()
{}
Face_around_face_circulator(halfedge_descriptor h, const Graph& g)
: Face_around_face_circulator::iterator_adaptor_(Halfedge_around_face_circulator<Graph>(h,g)), fct(g)
{}
#ifndef DOXYGEN_RUNNING
explicit operator bool() const
{
return (! (this->base_reference() == nullptr));
}
bool operator== (void*) const
{
return this->base_reference()== nullptr;
}
bool operator!= (void*) const
{
return this->base_reference()!= nullptr;
}
private:
friend class boost::iterator_core_access;
typename boost::graph_traits<Graph>::face_descriptor dereference() const { return fct(*this->base_reference()); }
#endif
};
/**
* \ingroup PkgBGLIterators

View File

@ -38,7 +38,6 @@ create_single_source_cgal_program("test_graph_traits.cpp")
create_single_source_cgal_program("test_Properties.cpp")
create_single_source_cgal_program("bench_read_from_stream_vs_add_face_and_add_faces.cpp")
create_single_source_cgal_program("graph_traits_inheritance.cpp" )
create_single_source_cgal_program("test_deprecated_io.cpp")
find_package(OpenMesh QUIET)
if(OpenMesh_FOUND)
@ -69,8 +68,6 @@ if (VTK_FOUND AND VTK_LIBRARIES)
message(STATUS "VTK ${VTK_VERSION} found ${VTK_LIBRARIES}")
target_link_libraries(test_bgl_read_write PRIVATE ${VTK_LIBRARIES})
target_compile_definitions(test_bgl_read_write PRIVATE -DCGAL_USE_VTK -DNOMINMAX)
target_link_libraries(test_deprecated_io PRIVATE ${VTK_LIBRARIES})
target_compile_definitions(test_deprecated_io PRIVATE -DCGAL_USE_VTK -DNOMINMAX)
else()
message(STATUS "Tests that use VTK will not be compiled.")
endif() #VTK_FOUND

View File

@ -4,6 +4,7 @@
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/graph_traits_Linear_cell_complex_for_combinatorial_map.h>
#include <CGAL/convex_hull_3.h>
#include <CGAL/Polygon_mesh_processing/manifoldness.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
@ -75,5 +76,12 @@ int main()
My_mesh_5 poly5;
CGAL::convex_hull_3(points.begin(), points.end(), poly5);
CGAL::Polygon_mesh_processing::non_manifold_vertices(poly1, CGAL::Emptyset_iterator());
CGAL::Polygon_mesh_processing::non_manifold_vertices(poly2, CGAL::Emptyset_iterator());
CGAL::Polygon_mesh_processing::non_manifold_vertices(poly3, CGAL::Emptyset_iterator());
CGAL::Polygon_mesh_processing::non_manifold_vertices(poly4, CGAL::Emptyset_iterator());
CGAL::Polygon_mesh_processing::non_manifold_vertices(poly5, CGAL::Emptyset_iterator());
return 0;
}

View File

@ -18,6 +18,7 @@ typedef GraphTraits::edge_descriptor edge_descriptor;
typedef GraphTraits::out_edge_iterator out_edge_iterator;
typedef GraphTraits::in_edge_iterator in_edge_iterator;
typedef CGAL::Face_around_face_circulator<Polyhedron> face_around_face_circulator;
typedef CGAL::Halfedge_around_face_circulator<Polyhedron> halfedge_around_face_circulator;
typedef CGAL::Halfedge_around_target_circulator<Polyhedron> halfedge_around_target_circulator;
typedef CGAL::Vertex_around_target_circulator<Polyhedron> vertex_around_target_circulator;
@ -32,6 +33,7 @@ typedef CGAL::Vertex_around_target_iterator<Polyhedron> vertex_around_target_ite
int main(int argc, char* argv[])
{
BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<face_around_face_circulator>));
BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<halfedge_around_face_circulator>));
BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<halfedge_around_target_circulator>));
BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<vertex_around_target_circulator>));
@ -62,6 +64,14 @@ int main(int argc, char* argv[])
}while(hafc != done);
}
{
face_around_face_circulator fafc(hd,P), done(fafc);
do {
++fafc;
}while(fafc != done);
}
{
halfedge_around_target_circulator havc(hd,P), done(havc);
vertex_descriptor vd = target(hd,P);

View File

@ -1,59 +0,0 @@
#include <CGAL/Installation/internal/disable_deprecation_warnings_and_errors.h>
#include <fstream>
#include <iostream>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/boost/graph/generators.h>
#include <CGAL/boost/graph/IO/OFF.h>
#include <CGAL/boost/graph/IO/VTK.h>
#include <CGAL/boost/graph/IO/WRL.h>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Point_3> SM;
int main()
{
// OFF
SM sm_in, sm_out;
Point_3 p0(0,0,0), p1(1,0,0), p2(0,1,0);
CGAL::make_triangle(p0, p1, p2, sm_out);
bool ok = CGAL::write_off("tmp_deprecated.off", sm_out);
assert(ok);
ok = CGAL::read_off("tmp_deprecated.off", sm_in);
assert(ok);
assert(num_vertices(sm_in) == 3 && num_faces(sm_in) == 1);
sm_in.clear();
std::ofstream os("tmp_deprecated.off");
ok = CGAL::write_off(os, sm_out);
assert(ok);
os.close();
std::ifstream is("tmp_deprecated.off");
ok = CGAL::read_off(is, sm_in);
assert(ok);
assert(num_vertices(sm_in) == 3 && num_faces(sm_in) == 1);
is.close();
sm_in.clear();
#ifdef CGAL_USE_VTK
//vtk
os.open("tmp_deprecated.vtp");
ok = CGAL::write_vtp(os, sm_out);
assert(ok);
os.close();
ok = CGAL::IO::read_VTP("tmp_deprecated.vtp", sm_in);
assert(ok);
assert(num_vertices(sm_in) == 3 && num_faces(sm_in) == 1);
sm_in.clear();
#endif
//wrl
os.open("tmp_deprecated.wrl");
ok = CGAL::write_wrl(os, sm_out);
assert(ok);
os.close();
return EXIT_SUCCESS;
}

View File

@ -64,7 +64,7 @@ namespace Barycentric_coordinates {
\return an output iterator to the element in the destination range,
one past the last coordinate stored
\pre area_2(p0, p1, p2) != 0
\pre \link BarycentricTraits_2::Compute_area_2 `area_2`\endlink(p0, p1, p2) != 0
*/
template<
typename OutIterator,
@ -133,7 +133,7 @@ namespace Barycentric_coordinates {
\return a tuple `std::tuple<GeomTraits::FT, GeomTraits::FT, GeomTraits::FT>`
with the computed coordinates
\pre area_2(p0, p1, p2) != 0
\pre \link BarycentricTraits_2::Compute_area_2 `area_2`\endlink(p0, p1, p2) != 0
*/
template<typename GeomTraits>
std::tuple<

View File

@ -15,8 +15,6 @@ find_package(Eigen3 3.1.0)
include(CGAL_Eigen3_support)
create_single_source_cgal_program("draw_lcc.cpp")
create_single_source_cgal_program("draw_mesh_and_points.cpp")
create_single_source_cgal_program("draw_several_windows.cpp")
create_single_source_cgal_program("draw_surface_mesh_height.cpp")
create_single_source_cgal_program("draw_surface_mesh_small_faces.cpp")
create_single_source_cgal_program("draw_surface_mesh_vcolor.cpp")
@ -24,18 +22,19 @@ create_single_source_cgal_program("draw_surface_mesh_vcolor.cpp")
if(CGAL_Qt6_FOUND)
#link it with the required CGAL libraries
target_link_libraries(draw_lcc PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(draw_mesh_and_points PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(draw_several_windows PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(draw_surface_mesh_height PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(draw_surface_mesh_small_faces PRIVATE CGAL::CGAL_Basic_viewer)
target_link_libraries(draw_surface_mesh_vcolor PRIVATE CGAL::CGAL_Basic_viewer)
if(TARGET CGAL::Eigen3_support)
create_single_source_cgal_program("draw_mesh_and_points.cpp")
create_single_source_cgal_program("draw_several_windows.cpp")
target_link_libraries(draw_mesh_and_points PRIVATE CGAL::Eigen3_support CGAL::CGAL_Basic_viewer)
target_link_libraries(draw_several_windows PRIVATE CGAL::Eigen3_support CGAL::CGAL_Basic_viewer)
else()
message("Eigen3 is not found, examples that require Eigen3 will not be compiled.")
endif()
else()
message("CGAL_Qt6 not configured: examples that require Qt will not be compiled.")
endif()
if(TARGET CGAL::Eigen3_support)
target_link_libraries(draw_mesh_and_points PRIVATE CGAL::Eigen3_support)
target_link_libraries(draw_several_windows PRIVATE CGAL::Eigen3_support)
endif()
#end of the file

View File

@ -1480,10 +1480,15 @@ protected:
if(!m_scene.empty())
{
auto& bbox=m_scene.bounding_box();
double d=CGAL::sqrt(CGAL::squared_distance
(Local_point(bbox.xmin(), bbox.ymin(), bbox.zmin()),
Local_point(bbox.xmax(), bbox.ymax(), bbox.zmax())));
double d=is_two_dimensional()
?2.5
: CGAL::sqrt(CGAL::squared_distance
(Local_point(bbox.xmin(), bbox.ymin(), bbox.zmin()),
Local_point(bbox.xmax(), bbox.ymax(), bbox.zmax())));
// std::cout<<"Length of the diagonal: "<<d<<std::endl;
// std::cout<<"width: "<< this->width() <<std::endl;
// std::cout<<"height: "<< this->height() <<std::endl;
m_size_vertices=1.5*d;
m_size_edges=d;
m_size_rays=m_size_edges;

View File

@ -27,7 +27,7 @@ the source and target points of `xc`, respectively. If the target
point of `xc2` and the source point of `xc1` coincide; then
the source point of `xc2` and the target point of `xc1` become
the source and target points of `xc`, respectively.
\pre `are_mergeable_2`(`xc1`, `xc2`) is true.
\pre \link ArrDirectionalTraits::AreMergeable_2 `are_mergeable_2`\endlink(`xc1`, `xc2`) is `true`.
*/
void operator()(ArrDirectionalTraits::X_monotone_curve_2 xc1,
ArrDirectionalTraits::X_monotone_curve_2 xc2,

View File

@ -1193,7 +1193,7 @@ protected:
// accessor for low-level arrangement functionalities
CGAL::Arr_accessor<Aos_2> accessor(*arr);
// the face field of outer and inner ccb are used in the loop to access the old face an halfedge
// the face field of outer and inner ccb are used in the loop to access the old face a halfedge
// used to contribute to. These two vectors are used to delay the association to the new face to
// avoid overwriting a field that is still needed
typedef std::pair<typename Aos_2::Dcel::Outer_ccb*, typename Aos_2::Dcel::Face*> Outer_ccb_and_face;

View File

@ -622,7 +622,7 @@ bool are_holes_and_boundary_pairwise_disjoint
Topology_traits;
typedef CGAL::Gps_on_surface_base_2<Traits_2, Topology_traits>
Polygon_set_2;
typedef typename Polygon_set_2::Size Size;
// typedef typename Polygon_set_2::Size Size;
typedef typename Traits_2::Polygon_2 Polygon_2;
typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2;
typedef typename Polygon_with_holes_2::Hole_const_iterator
@ -676,7 +676,7 @@ bool are_holes_and_boundary_pairwise_disjoint
Polygon_set_2 gps(traits);
// check for 2D intersections of holes (holes must be disjoint except for
// vertices)
Size num_of_holes = 0;
// Size num_of_holes = 0;
// functors for creating a pwh needed for inserting pgns into the arrangement
// quickly
Construct_polygon_with_holes_2 construct_pwh_functor =
@ -700,7 +700,7 @@ bool are_holes_and_boundary_pairwise_disjoint
// traits.Construct_polygon_with_holes_2 (hole);
// Polygon_with_holes_2 empty_pwh(hole);
gps.insert(empty_pwh);
num_of_holes++;
// num_of_holes++;
}
}
/* not good - doesn't work if intersection at vertices is legal.

View File

@ -5,7 +5,7 @@ namespace CGAL {
\ingroup PkgBoundingVolumesRef
An object of the class `Min_ellipse_2` is the unique ellipse of smallest area
enclosing a finite (multi)set of points in two-dimensional euclidean
enclosing a finite (multi)set of points in two-dimensional Euclidean
space \f$ \E^2\f$. For a point set \f$ P\f$ we denote by \f$ me(P)\f$ the smallest
ellipse that contains all points of \f$ P\f$. Note that \f$ me(P)\f$ can be
degenerate,

View File

@ -892,8 +892,8 @@ four_cover_points(Staircases< Traits >& d, OutputIterator o, bool& ok)
sdistx(*(shf - 1), bottom) <= FT(2) * d.r))))
#else
if (sdistx(bottom_i.second, bottom) <= FT(2) * d.r &&
((!d.is_x_greater_y() ||
(shl == Citerator(share.end()) ||
(!d.is_x_greater_y() ||
((shl == Citerator(share.end()) ||
sdistx(share.back(), bottom) <= FT(2) * d.r) &&
(shf == Citerator(share.begin()) ||
sdistx(*(shf - 1), bottom) <= FT(2) * d.r))))

View File

@ -29,12 +29,10 @@
#include <CGAL/export/CORE.h>
#ifdef CGAL_TEST_SUITE
// disabled for the testsuite to avoid `w`
#define CGAL_CORE_warning_msg(X ,Y)
// if (!(X)) CGAL_error_msg(Y)
#else
#ifdef CGAL_CORE_DEBUG
#define CGAL_CORE_warning_msg(X ,Y) CGAL_warning_msg(X ,Y)
#else
#define CGAL_CORE_warning_msg(X ,Y)
#endif

View File

@ -20,13 +20,7 @@
#include <algorithm>
#include <string>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#ifndef BOOST_FILESYSTEM_VERSION
// That macro was not defined in previous releases of Boost.
# define BOOST_FILESYSTEM_VERSION 2
#endif
#include <filesystem>
#include <CGAL/IO/binary_file_io.h>
@ -60,15 +54,9 @@ public:
}
display_information(fileName, std::cout);
boost::filesystem::path headerFile(fileName);
boost::filesystem::path dataFile(string_field("in"));
#if BOOST_FILESYSTEM_VERSION == 2
dataFile = boost::filesystem::complete(dataFile,
boost::filesystem::complete(headerFile.parent_path()));
#else
dataFile = boost::filesystem::absolute(dataFile,
boost::filesystem::absolute(headerFile.parent_path()));
#endif
std::filesystem::path headerFile(fileName);
std::filesystem::path dataFile = std::filesystem::absolute(fileName).parent_path() / std::filesystem::path(string_field("in"));
if(!load_data(dataFile.string())) {
return;
err_msg = "Invalid data file \"";

View File

@ -116,13 +116,13 @@ Draws a theta-graph with k cones
<li><b>Yao-k-graph:</b>
Draws a Yao-graph with k cones
<li><b>Half-theta-k-graph with even cones:</b>
Draws an half-theta-graph with the even of k cones.
Draws a half-theta-graph with the even of k cones.
<li><b>Half-Yao-k-graph with even cones:</b>
Draws an half-Yao-graph with the even of k cones.
Draws a half-Yao-graph with the even of k cones.
<li><b>Half-theta-k-graph with odd cones:</b>
Draws an half-theta-graph with the odd of k cones.
Draws a half-theta-graph with the odd of k cones.
<li><b>Half-Yao-k-graph with odd cones:</b>
Draws an half-Yao-graph with the odd of k cones.
Draws a half-Yao-graph with the odd of k cones.
<li><b>k cones:</b> For each selected point.
Draws the k cones around the point.
</ul>

View File

@ -29,7 +29,7 @@ A model of `RingNumberType`.
typedef unspecified_type RT;
/*!
A model of `FieldNumberType``<RT>`.
A model of `FieldNumberType<RT>`.
*/
typedef unspecified_type FT;

View File

@ -92,17 +92,17 @@ intersection(const Line_2 <K> &c1, const Line_2 <K> &c2, OutputIterator res)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circular_arc_2, Circular_arc_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_arc_2, Line_arc_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_arc_2, Circle_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circle_2, Line_arc_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circular_arc_2, Circle_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circle_2, Circular_arc_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_arc_2, Circular_arc_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circular_arc_2, Line_arc_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_2, Circular_arc_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_2, Line_arc_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circular_arc_2, Line_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circular_arc_2, Line_arc_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_arc_2, Circular_arc_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_arc_2, Circle_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circle_2, Line_arc_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_arc_2, Line_2)
CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_2, Line_arc_2)
} //namespace CGAL

View File

@ -29,7 +29,7 @@ A model of `RingNumberType`.
typedef unspecified_type RT;
/*!
A model of `FieldNumberType``<RT>`.
A model of `FieldNumberType<RT>`.
*/
typedef unspecified_type FT;

View File

@ -156,6 +156,10 @@ template <typename SK>
struct SK3_Intersection_traits<SK, typename SK::Sphere_3, typename SK::Sphere_3, typename SK::Plane_3>
: SK3_intersect_ternary<SK> {};
template <typename SK>
struct SK3_Intersection_traits<SK, typename SK::Sphere_3, typename SK::Plane_3, typename SK::Sphere_3>
: SK3_intersect_ternary<SK> {};
template <typename SK>
struct SK3_Intersection_traits<SK, typename SK::Plane_3, typename SK::Sphere_3, typename SK::Sphere_3>
: SK3_intersect_ternary<SK> {};
@ -164,6 +168,10 @@ template <typename SK>
struct SK3_Intersection_traits<SK, typename SK::Plane_3, typename SK::Plane_3, typename SK::Sphere_3>
: SK3_intersect_ternary<SK> {};
template <typename SK>
struct SK3_Intersection_traits<SK, typename SK::Plane_3, typename SK::Sphere_3, typename SK::Plane_3>
: SK3_intersect_ternary<SK> {};
template <typename SK>
struct SK3_Intersection_traits<SK, typename SK::Sphere_3, typename SK::Plane_3, typename SK::Plane_3>
: SK3_intersect_ternary<SK> {};

View File

@ -935,8 +935,10 @@ template < class SK > \
CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_2(Line_3, Sphere_3)
CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Sphere_3, Sphere_3, Sphere_3)
CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Sphere_3, Sphere_3, Plane_3)
CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Sphere_3, Plane_3, Sphere_3)
CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Plane_3, Sphere_3, Sphere_3)
CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Plane_3, Plane_3, Sphere_3)
CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Plane_3, Sphere_3, Plane_3)
CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Sphere_3, Plane_3, Plane_3)
CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_2(Circle_3, Plane_3)
CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_2(Plane_3, Circle_3)
@ -1024,6 +1026,12 @@ template < class SK > \
const Plane_3 & p, OutputIterator res) const
{ return SphericalFunctors::intersect_3<SK> (p,s1,s2,res); }
template < class OutputIterator >
OutputIterator
operator()(const Sphere_3 & s1, const Plane_3 & p,
const Sphere_3 & s2, OutputIterator res) const
{ return SphericalFunctors::intersect_3<SK> (p,s1,s2,res); }
template < class OutputIterator >
OutputIterator
operator()(const Plane_3 & p, const Sphere_3 & s1,
@ -1036,6 +1044,12 @@ template < class SK > \
const Sphere_3 & s, OutputIterator res) const
{ return SphericalFunctors::intersect_3<SK> (p1,p2,s,res); }
template < class OutputIterator >
OutputIterator
operator()(const Plane_3 & p1, const Sphere_3 & s,
const Plane_3 & p2, OutputIterator res) const
{ return SphericalFunctors::intersect_3<SK> (p1,p2,s,res); }
template < class OutputIterator >
OutputIterator
operator()(const Sphere_3 & s, const Plane_3 & p1,

View File

@ -71,8 +71,10 @@ CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_JUST_INTERSECTION_2_(Sphere_3, Line_
CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_JUST_INTERSECTION_2_(Line_3, Sphere_3)
CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Sphere_3, Sphere_3, Sphere_3)
CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Sphere_3, Sphere_3, Plane_3)
CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Sphere_3, Plane_3, Sphere_3)
CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Plane_3, Sphere_3, Sphere_3)
CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Plane_3, Plane_3, Sphere_3)
CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Plane_3, Sphere_3, Plane_3)
CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Sphere_3, Plane_3, Plane_3)
CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_2_(Circle_3, Plane_3)
CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_2_(Plane_3, Circle_3)

View File

@ -928,7 +928,9 @@ void _test_intersection_construct(SK sk) {
intersection(s1, s2, pl, std::back_inserter(intersection_1));
intersection(s1, s3, pl, std::back_inserter(intersection_2));
if(intersection_1.size() == 1) {
assert(CGAL::do_intersect(s1, s2, pl));
assert(CGAL::do_intersect(pl, s1, s2));
assert(CGAL::do_intersect(s1, pl, s2));
assert(CGAL::do_intersect(s1, s2, pl));
Circle_3 circle;
std::pair<Circular_arc_point_3, unsigned> cap;
if(assign_variant(circle,intersection_1[0])) {
@ -1006,7 +1008,9 @@ void _test_intersection_construct(SK sk) {
theIntersect_3(s1, p1, pl, std::back_inserter(intersection_1));
theIntersect_3(s1, p2, pl, std::back_inserter(intersection_2));
if(intersection_1.size() == 1) {
assert(theDo_intersect_3(s1, p1, pl));
assert(theDo_intersect_3(s1, p1, pl));
assert(theDo_intersect_3(p1, s1, pl));
assert(theDo_intersect_3(p1, pl, s1));
Circle_3 circle;
std::pair<Circular_arc_point_3, unsigned> cap;
if(assign_variant(circle,intersection_1[0])) {

View File

@ -472,7 +472,7 @@ The output is:
Number of 2-free darts: 4
\endverbatim
We can verify that there are 6 2-cells after the insertion since the squared face was inserted as a hole in one face of the hexahedron. We can also see that there are 4 2-free darts, which are the darts of the squared face. Since they bound an hole, there is no face filling the hole and thus 4 darts are 2-free.
We can verify that there are 6 2-cells after the insertion since the squared face was inserted as a hole in one face of the hexahedron. We can also see that there are 4 2-free darts, which are the darts of the squared face. Since they bound a hole, there is no face filling the hole and thus 4 darts are 2-free.
See also a similar example for Linear cell complex \ref Linear_cell_complexInsert "Insert an Edge Between Two Different Faces".

View File

@ -149,7 +149,7 @@ template <unsigned int i> bool is_sewable(Dart_const_descriptor d1, Dart_const_d
Links by \f$ \beta_i \f$ two by two all the darts of the orbit <I>D1</I>=\f$ \langle{}\f$\f$ \beta_1\f$,\f$ \ldots\f$,\f$ \beta_{i-2}\f$,\f$ \beta_{i+2}\f$,\f$ \ldots\f$,\f$ \beta_d\f$\f$ \rangle{}\f$(`d1`) and <I>D2</I>=\f$ \langle{}\f$\f$ \beta_0\f$,\f$ \beta_2\f$,\f$ \ldots\f$,\f$ \beta_{i-2}\f$,\f$ \beta_{i+2}\f$,\f$ \ldots\f$,\f$ \beta_d\f$\f$ \rangle{}\f$(`d2`) such that <I>d2</I>=<I>f</I>(<I>d1</I>), where <I>f</I> is the bijection between <I>D1</I> and <I>D2</I> satisfying: <I>f</I>(<I>d1</I>)=<I>d2</I>, and for all <I>e</I> \f$ \in \f$ <I>D1</I>, for all <I>j</I> \f$ \in \f$ {1,\f$ \ldots\f$,<I>i</I>-2,<I>i</I>+2,\f$ \ldots\f$,<I>d</I>}, <I>f</I>(\f$ \beta_j\f$(<I>e</I>))=\f$ \beta_j^{-1}\f$(<I>f</I>(<I>e</I>)).
If \link GenericMap::are_attributes_automatically_managed `are_attributes_automatically_managed()`\endlink`==true`, when necessary, non void attributes are updated to ensure the validity of the generic map: for each <I>j</I>-cells <I>c1</I> and <I>c2</I> which are merged into one <I>j</I>-cell during the sew, the two associated attributes <I>attr1</I> and <I>attr2</I> are considered. If one attribute is `null_descriptor` and the other not, the non `null_descriptor` attribute is associated to all the darts of the resulting cell. When the two attributes are non `null_descriptor`, functor \link CellAttribute::On_merge `Attribute_type<i>::type::On_merge`\endlink is called on the two attributes <I>attr1</I> and <I>attr2</I>. If set, the dynamic onmerge function of <i>i</i>-attributes is also called on <I>attr1</I> and <I>attr2</I>. Then, the attribute <I>attr1</I> is associated to all darts of the resulting <I>j</I>-cell. Finally, attribute <I>attr2</I> is removed from the generic map.
\pre \link CombinatorialMap::is_sewable `is_sewable<i>(d1,d2)`\endlink.
\pre \link CombinatorialMap::is_sewable `is_sewable<i>`\endlink(`d1`,`d2`).
\cgalAdvancedBegin
If \link GenericMap::are_attributes_automatically_managed `are_attributes_automatically_managed()`\endlink`==false`, non void attributes are not updated; thus the generic map can be no more valid after this operation.

View File

@ -467,14 +467,14 @@ const typename Attribute_type<i>::type::Info & info(Dart_const_descriptor adart)
/*!
A shortcut for \link GenericMap::dart_of_attribute `dart_of_attribute<i>`\endlink`(`\link GenericMap::attribute `attribute<i>`\endlink`(adart))`.
\pre `attribute<i>(adart)!=nullptr`.
\pre \link GenericMap::attribute `attribute<i>`\endlink`(adart)!=nullptr`.
*/
template<unsigned int i>
Dart_descriptor & dart(Dart_descriptor adart);
/*!
A shortcut for \link GenericMap::dart_of_attribute(typename Attribute_const_descriptor<i>::type)const `dart_of_attribute<i>`\endlink`(`\link GenericMap::attribute(Dart_const_descriptor)const `attribute<i>`\endlink`(adart))` for const descriptor.
\pre `attribute<i>(adart)!=nullptr`.
\pre \link GenericMap::attribute(Dart_const_descriptor)const `attribute<i>`\endlink`(adart)!=nullptr`.
*/
template<unsigned int i>
Dart_const_descriptor dart(Dart_const_descriptor adart) const;
@ -771,13 +771,13 @@ bool is_marked(Dart_const_descriptor d, size_type m) const;
/*!
Marks dart `d` for `m`.
\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink and `d`\f$ \in \f$ `darts()`.
\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`) and `d`\f$ \in \f$ `darts()`.
*/
void mark(Dart_const_descriptor d, size_type m) const;
/*!
Unmarks dart `d` for the mark `m`.
\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink and `d`\f$ \in \f$ `darts()`.
\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`) and `d`\f$ \in \f$ `darts()`.
*/
void unmark(Dart_const_descriptor d, size_type m) const;
@ -785,31 +785,31 @@ void unmark(Dart_const_descriptor d, size_type m) const;
Inverse the mark `m` for all the darts of the generic map.
All the marked darts become unmarked and all the unmarked darts
become marked.
\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink.
\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`).
*/
void negate_mark(size_type m) const;
/*!
Unmarks all the darts of the generic map for `m`.
\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink.
\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`).
*/
void unmark_all(size_type m) const;
/*!
Returns the number of marked darts for `m`.
\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink.
\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`).
*/
size_type number_of_marked_darts(size_type m) const;
/*!
Return the number of unmarked darts for `m`.
\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink.
\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`).
*/
size_type number_of_unmarked_darts(size_type m) const;
/*!
Frees mark `m`.
\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink.
\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`).
*/
void free_mark(size_type m) const;
@ -820,7 +820,7 @@ void free_mark(size_type m) const;
/*!
Creates a combinatorial hexahedron (six combinatorial quadrangles 2-sewn together), and adds it in the generic map. Returns a descriptor on one dart of this combinatorial hexahedron.
\pre `dimension` \f$\geq\f$ 2.
\pre \link GenericMap::dimension `dimension`\endlink \f$\geq\f$ 2.
\sa `make_edge()`
\sa `make_combinatorial_polygon()`
@ -831,7 +831,7 @@ Dart_descriptor make_combinatorial_hexahedron();
/*!
Creates a combinatorial polygon of length `lg` (a cycle of `lg` edges), and adds it in the generic map. Returns a descriptor on one dart of this combinatorial polygon.
\pre `dimension`\f$ \geq\f$ 1 and `lg`\f$ >\f$ 0.
\pre \link GenericMap::dimension `dimension`\endlink \f$ \geq\f$ 1 and `lg`\f$ >\f$ 0.
\sa `make_edge()`
\sa `make_combinatorial_tetrahedron()`
@ -841,7 +841,7 @@ Dart_descriptor make_combinatorial_polygon(unsigned int lg);
/*!
Creates a combinatorial tetrahedron (four combinatorial triangles 2-sewn together), and adds it in the generic map. Returns a descriptor on one dart of this combinatorial tetrahedron.
\pre `dimension`\f$ \geq\f$ 2.
\pre \link GenericMap::dimension `dimension`\endlink \f$ \geq\f$ 2.
\sa `make_edge()`
\sa `make_combinatorial_polygon()`
@ -851,7 +851,7 @@ Dart_descriptor make_combinatorial_tetrahedron();
/*!
Creates an isolated edge (two darts sewn to represent one edge and two vertices) and adds it in the generic map. Returns a descriptor on one dart of this edge.
\pre `dimension`\f$ \geq\f$ 2.
\pre \link GenericMap::dimension `dimension`\endlink \f$ \geq\f$ 2.
\sa `make_combinatorial_polygon()`
\sa `make_combinatorial_tetrahedron()`
@ -908,7 +908,7 @@ Dart_descriptor insert_cell_0_in_cell_2(Dart_descriptor d);
/*!
Inserts a 1-cell in the 2-cell containing `d1` and `d2`. Returns `previous(d1)`, a descriptor on one dart belonging to the new 1-cell.
\pre `is_insertable_cell_1_in_cell_2(d1,d2)`.
\pre \link GenericMap::is_insertable_cell_1_in_cell_2 `is_insertable_cell_1_in_cell_2`\endlink(`d1`,`d2`).
See examples for combinatorial map in \cgalFigureRef{fig_cmap_insert_edge} and for generalized map in \cgalFigureRef{fig_gmap_insert_edge}.
@ -930,7 +930,7 @@ Dart_descriptor insert_cell_1_in_cell_2(Dart_descriptor d1, Dart_descriptor d2);
/*!
Inserts a 1-cell between the 2-cell containing `d1` and the one containing `d2`. Returns `previous(d1)`, a descriptor on one dart belonging to the new 1-cell.
\pre `is_insertable_cell_1_between_two_cells_2(d1,d2)`.
\pre \link GenericMap::is_insertable_cell_1_between_two_cells_2 `is_insertable_cell_1_between_two_cells_2`\endlink(`d1`,`d2`).
If \link GenericMap::are_attributes_automatically_managed `are_attributes_automatically_managed()`\endlink`==true`, call \link CellAttribute::On_merge `Attribute_type<i>::type::On_merge`\endlink(<I>a</I>,<I>a'</I>) is called for all enabled i-attributes, for i>=2, with <I>a</I> the original 2-attribute associated with `d1` and <I>a'</I> the original 2-attribute associated with `d2`. If set, the dynamic on-merge function of i-attributes is also called on <I>a</I> and <I>a'</I>.
@ -957,7 +957,7 @@ Dart_descriptor insert_cell_1(Dart_descriptor d1, Dart_descriptor d2);
/*!
Inserts a 2-cell along the path of 1-cells containing darts given by the range `[afirst,alast)`. Returns `opposite<2>(*afirst)`, a descriptor on one dart belonging to the new 2-cell.
\pre `is_insertable_cell_2_in_cell_3(afirst,alast)`.
\pre \link GenericMap::is_insertable_cell_2_in_cell_3 `is_insertable_cell_2_in_cell_3`\endlink(`afirst`,`alast`).
See examples for combinatorial map in \cgalFigureRef{fig_cmap_insert_facet} and for generalized map in \cgalFigureRef{fig_gmap_insert_facet}.
@ -1045,7 +1045,7 @@ bool is_removable(Dart_const_descriptor d);
/*!
Removes the <I>i</I>-cell containing `d`. Returns the number of darts removed from the generic map.
\pre `is_removable<i>(d)`.
\pre \link GenericMap::is_removable `is_removable<i>`\endlink(`d`).
See examples in \cgalFigureRef{fig_cmap_insert_vertex}, \cgalFigureRef{fig_cmap_insert_edge} and \cgalFigureRef{fig_cmap_insert_facet}.

View File

@ -572,7 +572,7 @@ namespace CGAL {
}
}
/** Import the given hds which should be a model of an halfedge graph. */
/** Import the given hds which should be a model of a halfedge graph. */
template<class HEG>
void import_from_halfedge_graph(const HEG& heg,
std::unordered_map
@ -3710,7 +3710,7 @@ namespace CGAL {
void set_automatic_attributes_management_without_correction(bool newval)
{ this->automatic_attributes_management = newval; }
/** Creates an half-edge.
/** Creates a half-edge.
* @return a dart of the new half-edge.
*/
Dart_descriptor make_half_edge()

View File

@ -176,7 +176,7 @@ namespace CGAL {
{
if (amap.template attribute<i>(it)!=amap.null_descriptor)
{
// make composant, dart and property node
// make component, dart and property node
boost::property_tree::ptree & nattr = ndim.add("a", "");
/* boost::property_tree::ptree & ndarts = */
nattr.add("d", myDarts[it]);
@ -209,7 +209,7 @@ namespace CGAL {
{
if (amap.template attribute<i>(it)!=amap.null_descriptor)
{
// make composant, dart and property node
// make component, dart and property node
boost::property_tree::ptree & nattr = ndim.add("a", "");
/* boost::property_tree::ptree & ndarts = */
nattr.add("d", myDarts[it]);
@ -242,7 +242,7 @@ namespace CGAL {
{
if (amap.template attribute<i>(it)!=amap.null_descriptor)
{
// make composant, dart and property node
// make component, dart and property node
boost::property_tree::ptree & nattr = ndim.add("a", "");
/* boost::property_tree::ptree & ndarts = */
nattr.add("d", myDarts[it]);
@ -274,7 +274,7 @@ namespace CGAL {
{
if (amap.template attribute<i>(it)!=amap.null_descriptor)
{
// make composant, dart and property node
// make component, dart and property node
boost::property_tree::ptree & nattr = ndim.add("a", "");
/* boost::property_tree::ptree & ndarts = */
nattr.add("d", myDarts[it]);

View File

@ -453,7 +453,7 @@ public:
// Constructor allowing to transform an index from one container to another
template<typename Index2>
Index_for_cc_with_index(const Index2& idx): m_idx(static_cast<size_t>(idx))
Index_for_cc_with_index(const Index2& idx): m_idx(static_cast<size_type>(idx))
{}
/// Increment the internal index. This operations does not

View File

@ -49,12 +49,13 @@ that satisfy the following properties:
- Each polygonal face must be a simple polygon, i.e., its edges don't intersect,
except consecutive edges, which intersect at their common vertex.
- Each polygonal face must be planar, meaning all its vertices lie on the same plane.
- Each polygonal face may be non-convex.
- Each polygonal face may have one or more holes, each of them also represented by an ordered list of vertices
from the PLC, forming a closed loop.
- If two polygons in the PLC intersect, their intersection is a union of edges and vertices from the
PLC. In particular, the interiors of two polygons cannot overlap.
- Polygonal holes may be non-convex.
- If two polygonal faces in the PLC intersect, their intersection is a union of edges and vertices from the
PLC. In particular, the interiors of two polygonal faces cannot overlap.
Polygons in a PLC may be non-convex and may have holes.
\cgalFigureAnchor{CT_3_plc_fig}
<center>
@ -79,7 +80,7 @@ possible to being Delaunay, given that some faces are marked as _constrained_. M
triangulation is _constrained Delaunay_ if, for any simplex \f$s\f$ of the triangulation, the
interior of its circumscribing sphere contains no vertex of the triangulation that is _visible_ from
any point in the interior of the simplex \f$s\f$. Two points are _visible_ if the open line segment
joining them does not intersect any polygonal face of the PLC, except for polygons that are coplanar with
joining them does not intersect any polygonal face of the PLC, except for polygonal faces that are coplanar with
the segment.
In 3D, constrained triangulations do not always exist. This can be demonstrated using the example of
@ -87,7 +88,7 @@ Sch&ouml;nhardt polyhedra \cgalCite{s-udzvd-28} (see \cgalFigureRef{CT_3_schonha
\cgalCite{b-ip-48a}. Shewchuk \cgalCite{cgal:shewchuk1998condition} demonstrated that for any PLC,
there exists a refined
version of the original PLC that admits a constrained Delaunay triangulation. This refinement is
achieved by adding Steiner vertices to the input edges and polygons. The constrained triangulation
achieved by adding Steiner vertices to the input edges and polygonal faces. The constrained triangulation
built on this refined PLC is known as a _conforming constrained Delaunay triangulation_ (CCDT for
short). \cgalFigureRef{CT_3_plc2cdt_fig} illustrates an example of a conforming constrained
Delaunay triangulation constructed from a PLC.
@ -113,7 +114,8 @@ Right: CCDT (2452 vertices).
The algorithm implemented in this package is based on the work of Hang Si et al., who developed particular
algorithms for constructing conforming constrained Delaunay triangulations from PLCs.
The corresponding implementation takes with floating point numbers as coordinates
The corresponding implementation is designed to handle points whose coordinates
are floating-point numbers.
\cgalCite{si2005meshing}, \cgalCite{cgal:si2008cdt3}, \cgalCite{si2015tetgen}.
@ -136,14 +138,15 @@ manifold (that is, each edge belongs to exactly two faces), and their faces cann
A PLC can also be represented as a polygon soup: a collection of vertices and a set of polygons, where
each polygon is defined by an ordered list of vertices, without explicit connectivity information between
polygons. For a polygon soup to represent a valid PLC, its polygons must satisfy the properties described
polygons. For a polygon soup to represent a valid PLC, its polygons must satisfy the
polygonal faces properties described
in the previous section. This approach allows for the representation of non-manifold geometries; however,
polygons in a polygon soup cannot have holes.
This package also provides a way to group polygons into distinct surface patches using a property map,
This package also provides a way to group polygonal faces into distinct surface patches using a property map,
named `plc_face_id`.
Each polygon can be assigned a _patch_ identifier, allowing multiple polygons to form a continuous surface patch,
which may include holes. Some necessary geometric conditions must be satisfied for these patches to be
Each polygon can be assigned a _patch_ identifier, allowing multiple polygonal faces to form a continuous surface patch,
which may include holes. Some necessary conditions must be satisfied for these patches to be
used in the conforming constrained Delaunay triangulation construction:
- Each patch must be planar, meaning all polygonal faces in the patch lie on the same plane;
- The polygonal faces of the patch must not intersect except at their shared edges.
@ -181,7 +184,8 @@ However, because this package builds upon the 3D Triangulation package, it inher
that the traits class must provide exact predicates.
A key aspect of this algorithm is the creation of new points, known as Steiner points, which are
inserted on the segments and polygons of the input PLC. If a traits class with inexact constructions
inserted on the segments and polygons forming the input PLC polygonal faces.
If a traits class with inexact constructions
is used, it cannot be guaranteed that these points will lie exactly on the intended segments or polygons.
As a result, the output will only approximate the input, with the accuracy limited by the rounding
of the computed Steiner points.

View File

@ -42,6 +42,8 @@ using Constraints_pmap = CGAL::Boolean_property_map<Constraints_set>;
int main(int argc, char* argv[])
{
std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/mpi.off");
double target_edge_length = (argc > 2) ? std::stod(argv[2]) : 1.0;
unsigned int iterations = (argc > 3) ? std::stoi(argv[3]) : 3;
CGAL::Surface_mesh<K::Point_3> mesh;
if(!CGAL::IO::read_polygon_mesh(filename, mesh))
@ -62,17 +64,16 @@ int main(int argc, char* argv[])
namespace Tet_remesh = CGAL::Tetrahedral_remeshing;
Tr tr = Tet_remesh::get_remeshing_triangulation(std::move(ccdt),
np::edge_is_constrained_map(constraints_pmap));
std::cout << "Number of vertices in tr: " << tr.number_of_vertices() << std::endl;
std::cout << "There are " << tr.number_of_vertices() << " vertices in the constrained triangulation" << std::endl;
CGAL::tetrahedral_isotropic_remeshing(tr,
1., // target edge length
np::number_of_iterations(3)
.edge_is_constrained_map(constraints_pmap));
target_edge_length,
np::number_of_iterations(iterations)
.edge_is_constrained_map(constraints_pmap));
std::cout << "Number of vertices in tr: "
<< tr.number_of_vertices() << std::endl;
std::cout << "There are " << tr.number_of_vertices() << " vertices after remeshing" << std::endl;
std::ofstream ofs("tr.mesh");
std::ofstream ofs("remeshed.mesh");
CGAL::IO::write_MEDIT(ofs, tr);
return EXIT_SUCCESS;

Some files were not shown because too many files have changed in this diff Show More