mirror of https://github.com/CGAL/cgal
Merge remote-tracking branch 'cgal/main' into Point_set-reduce_dependencies-GF
This commit is contained in:
commit
970f16913b
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.,
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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>`.
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/// @}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/// @}
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
/// @{
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -1491,4 +1491,4 @@ if(CGAL_DISABLE_GMP)
|
|||
foreach(_test ${LIST_OF_TESTS})
|
||||
set_property(TEST ${_test} APPEND PROPERTY ENVIRONMENT CGAL_DISABLE_GMP=1)
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1563,10 +1563,10 @@ does_satisfy_link_condition(typename boost::graph_traits<Graph>::edge_descriptor
|
|||
*
|
||||
* After the collapse of edge `e` the following holds:
|
||||
* - The edge `e` is no longer in `g`.
|
||||
* - The faces incident to edge `e` are no longer in `g`.
|
||||
* - The triangle faces incident to edge `e` are no longer in `g`.
|
||||
* - `v0` is no longer in `g`.
|
||||
* - If `h` is not a border halfedge, `p_h` is no longer in `g` and is replaced by `o_n_h`.
|
||||
* - If the opposite of `h` is not a border halfedge, `p_o_h` is no longer in `g` and is replaced by `o_n_o_h`.
|
||||
* - If `h` is part of a triangle face, `p_h` is no longer in `g` and is replaced by `o_n_h`.
|
||||
* - If the opposite of `h` is part of a triangle face, `p_o_h` is no longer in `g` and is replaced by `o_n_o_h`.
|
||||
* - The halfedges kept in `g` that had `v0` as target and source now have `v1` as target and source, respectively.
|
||||
* - No other incidence information is changed in `g`.
|
||||
*
|
||||
|
|
@ -1595,9 +1595,8 @@ collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor e,
|
|||
bool lBottomFaceExists = ! is_border(qp,g);
|
||||
bool lTopLeftFaceExists = lTopFaceExists && ! is_border(pt,g);
|
||||
bool lBottomRightFaceExists = lBottomFaceExists && ! is_border(qb,g);
|
||||
|
||||
CGAL_precondition( !lTopFaceExists || (lTopFaceExists && ( degree(target(pt, g), g) > 2 ) ) ) ;
|
||||
CGAL_precondition( !lBottomFaceExists || (lBottomFaceExists && ( degree(target(qb, g), g) > 2 ) ) ) ;
|
||||
bool lBottomIsTriangle = lBottomFaceExists && is_triangle(qp,g);
|
||||
bool lTopIsTriangle = lTopFaceExists && is_triangle(pq,g);
|
||||
|
||||
vertex_descriptor q = target(pq, g);
|
||||
vertex_descriptor p = source(pq, g);
|
||||
|
|
@ -1605,7 +1604,7 @@ collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor e,
|
|||
|
||||
bool lP_Erased = false;
|
||||
|
||||
if ( lTopFaceExists )
|
||||
if ( lTopIsTriangle)
|
||||
{
|
||||
CGAL_precondition( ! is_border(opposite(pt, g),g) ) ; // p-q-t is a face of the mesh
|
||||
if ( lTopLeftFaceExists )
|
||||
|
|
@ -1632,7 +1631,7 @@ collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor e,
|
|||
}
|
||||
}
|
||||
|
||||
if ( lBottomFaceExists )
|
||||
if ( lBottomIsTriangle)
|
||||
{
|
||||
CGAL_precondition( ! is_border(opposite(qb, g),g) ) ; // p-q-b is a face of the mesh
|
||||
if ( lBottomRightFaceExists )
|
||||
|
|
@ -1679,7 +1678,7 @@ collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor e,
|
|||
* collapses an edge in a graph having non-collapsable edges.
|
||||
*
|
||||
* Let `h` be the halfedge of `e`, and let `v0` and `v1` be the source and target vertices of `h`.
|
||||
* Collapses the edge `e` replacing it with `v1`, as described in the paragraph above
|
||||
* Collapses the edge `e` replacing it with `v1`, as described in the other overload
|
||||
* and guarantees that an edge `e2`, for which `get(edge_is_constrained_map, e2)==true`,
|
||||
* is not removed after the collapse.
|
||||
*
|
||||
|
|
@ -1689,14 +1688,14 @@ 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`.
|
||||
* Furthermore, the edge `e` 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, e) == false`.
|
||||
* \pre `v0` and `v1` are not both incident to a constrained edge.
|
||||
*/
|
||||
|
||||
template<typename Graph, typename EdgeIsConstrainedMap>
|
||||
typename boost::graph_traits<Graph>::vertex_descriptor
|
||||
collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor v0v1,
|
||||
collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor e,
|
||||
Graph& g,
|
||||
EdgeIsConstrainedMap Edge_is_constrained_map)
|
||||
{
|
||||
|
|
@ -1704,11 +1703,11 @@ collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor v0v1,
|
|||
typedef typename Traits::vertex_descriptor vertex_descriptor;
|
||||
typedef typename Traits::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
CGAL_precondition(is_valid_edge_descriptor(v0v1, g));
|
||||
CGAL_precondition(does_satisfy_link_condition(v0v1,g));
|
||||
CGAL_precondition(!get(Edge_is_constrained_map, v0v1));
|
||||
CGAL_precondition(is_valid_edge_descriptor(e, g));
|
||||
CGAL_precondition(does_satisfy_link_condition(e,g));
|
||||
CGAL_precondition(!get(Edge_is_constrained_map, e));
|
||||
|
||||
halfedge_descriptor pq = halfedge(v0v1,g);
|
||||
halfedge_descriptor pq = halfedge(e,g);
|
||||
|
||||
halfedge_descriptor qp = opposite(pq,g);
|
||||
halfedge_descriptor pt = opposite(prev(pq,g),g);
|
||||
|
|
@ -1718,6 +1717,8 @@ collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor v0v1,
|
|||
|
||||
bool lTopFaceExists = ! is_border(pq,g) ;
|
||||
bool lBottomFaceExists = ! is_border(qp,g) ;
|
||||
bool lTopIsTriangle = lTopFaceExists && is_triangle(pq,g);
|
||||
bool lBottomIsTriangle = lBottomFaceExists && is_triangle(qp,g);
|
||||
|
||||
vertex_descriptor q = target(pq,g);
|
||||
vertex_descriptor p = source(pq,g);
|
||||
|
|
@ -1728,7 +1729,7 @@ collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor v0v1,
|
|||
|
||||
// If the top facet exists, we need to choose one out of the two edges which one disappears:
|
||||
// p-t if it is not constrained and t-q otherwise
|
||||
if ( lTopFaceExists )
|
||||
if ( lTopIsTriangle )
|
||||
{
|
||||
if ( !get(Edge_is_constrained_map,edge(pt,g)) )
|
||||
{
|
||||
|
|
@ -1742,7 +1743,7 @@ collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor v0v1,
|
|||
|
||||
// If the bottom facet exists, we need to choose one out of the two edges which one disappears:
|
||||
// q-b if it is not constrained and b-p otherwise
|
||||
if ( lBottomFaceExists )
|
||||
if ( lBottomIsTriangle )
|
||||
{
|
||||
if ( !get(Edge_is_constrained_map,edge(qb,g)) )
|
||||
{
|
||||
|
|
@ -1753,7 +1754,7 @@ collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor v0v1,
|
|||
}
|
||||
}
|
||||
|
||||
if (lTopFaceExists && lBottomFaceExists)
|
||||
if (lTopIsTriangle && lBottomIsTriangle)
|
||||
{
|
||||
if ( face(edges_to_erase[0],g) == face(edges_to_erase[1],g)
|
||||
&& (! is_border(edges_to_erase[0],g)) )
|
||||
|
|
@ -1800,7 +1801,7 @@ collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor v0v1,
|
|||
}
|
||||
else
|
||||
{
|
||||
if (lTopFaceExists)
|
||||
if (lTopIsTriangle)
|
||||
{
|
||||
if (!(is_border(edges_to_erase[0],g))){
|
||||
join_face(edges_to_erase[0],g);
|
||||
|
|
@ -1815,21 +1816,32 @@ collapse_edge(typename boost::graph_traits<Graph>::edge_descriptor v0v1,
|
|||
remove_face(opposite(edges_to_erase[0],g),g);
|
||||
return q;
|
||||
}
|
||||
|
||||
if (! (is_border(edges_to_erase[0],g))){
|
||||
// q will be removed, swap it with p
|
||||
internal::swap_vertices(p, q, g);
|
||||
join_face(edges_to_erase[0],g);
|
||||
join_vertex(qp,g);
|
||||
return q;
|
||||
}
|
||||
if(!is_border(opposite(next(qp,g),g),g))
|
||||
else
|
||||
{
|
||||
// q will be removed, swap it with p
|
||||
internal::swap_vertices(p, q, g);
|
||||
if (lBottomIsTriangle)
|
||||
{
|
||||
if (! (is_border(edges_to_erase[0],g))){
|
||||
// q will be removed, swap it with p
|
||||
internal::swap_vertices(p, q, g);
|
||||
join_face(edges_to_erase[0],g);
|
||||
CGAL_assertion(source(qp,g)==p);
|
||||
join_vertex(qp,g);
|
||||
return q;
|
||||
}
|
||||
if(!is_border(opposite(next(qp,g),g),g))
|
||||
{
|
||||
// q will be removed, swap it with p
|
||||
internal::swap_vertices(p, q, g);
|
||||
}
|
||||
remove_face(opposite(edges_to_erase[0],g),g);
|
||||
return q;
|
||||
}
|
||||
else
|
||||
{
|
||||
join_vertex(pq,g);
|
||||
return q;
|
||||
}
|
||||
}
|
||||
remove_face(opposite(edges_to_erase[0],g),g);
|
||||
return q;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1896,7 +1908,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`.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <CGAL/boost/graph/IO/Generic_facegraph_builder.h>
|
||||
#include <CGAL/Named_function_parameters.h>
|
||||
#include <CGAL/boost/graph/named_params_helper.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
|
@ -44,7 +45,7 @@ class PLY_builder
|
|||
typedef typename Base::Face_container Face_container;
|
||||
|
||||
public:
|
||||
PLY_builder(std::istream& is) : Base(is) { }
|
||||
PLY_builder(std::istream& is, std::string& comments) : Base(is), comments(comments) { }
|
||||
|
||||
template <typename NamedParameters>
|
||||
bool read(std::istream& is,
|
||||
|
|
@ -52,19 +53,22 @@ public:
|
|||
Face_container& faces,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
return read_PLY(is, points, faces, np);
|
||||
return read_PLY(is, points, faces, comments, np);
|
||||
}
|
||||
|
||||
std::string& comments;
|
||||
};
|
||||
|
||||
template <typename Graph, typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_PLY_BGL(std::istream& is,
|
||||
Graph& g,
|
||||
std::string& comments,
|
||||
const CGAL_NP_CLASS& np = parameters::default_values())
|
||||
{
|
||||
typedef typename CGAL::GetVertexPointMap<Graph, CGAL_NP_CLASS>::type VPM;
|
||||
typedef typename boost::property_traits<VPM>::value_type Point;
|
||||
|
||||
internal::PLY_builder<Graph, Point> builder(is);
|
||||
internal::PLY_builder<Graph, Point> builder(is, comments);
|
||||
return builder(g, np);
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +88,7 @@ bool read_PLY_BGL(std::istream& is,
|
|||
|
||||
\param is the input stream
|
||||
\param g the graph to be built from the input data
|
||||
\param comments a string included line by line in the header of the PLY stream (each line will be precedeed by "comment ")
|
||||
\param np optional \ref bgl_namedparameters "Named Parameters" described below
|
||||
|
||||
\cgalNamedParamsBegin
|
||||
|
|
@ -132,15 +137,31 @@ template <typename Graph,
|
|||
typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_PLY(std::istream& is,
|
||||
Graph& g,
|
||||
std::string& comments,
|
||||
const CGAL_NP_CLASS& np = parameters::default_values()
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
, std::enable_if_t<!internal::is_Point_set_or_Range_or_Iterator<Graph>::value>* = nullptr
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return internal::read_PLY_BGL(is, g, np);
|
||||
return internal::read_PLY_BGL(is, g, comments, np);
|
||||
}
|
||||
|
||||
template <typename Graph,
|
||||
typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_PLY(std::istream& is,
|
||||
Graph& g,
|
||||
const CGAL_NP_CLASS& np = parameters::default_values()
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
, std::enable_if_t<!internal::is_Point_set_or_Range_or_Iterator<Graph>::value>* = nullptr
|
||||
#endif
|
||||
)
|
||||
{
|
||||
std::string unused_comments;
|
||||
return internal::read_PLY_BGL(is, g, unused_comments, np);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\ingroup PkgBGLIoFuncsPLY
|
||||
|
||||
|
|
@ -153,6 +174,7 @@ bool read_PLY(std::istream& is,
|
|||
|
||||
\param fname the name of the input file
|
||||
\param g the graph to be built from the input data
|
||||
\param comments a string included line by line in the header of the PLY stream (each line will be precedeed by "comment" )
|
||||
\param np optional \ref bgl_namedparameters "Named Parameters" described below
|
||||
|
||||
\cgalNamedParamsBegin
|
||||
|
|
@ -207,6 +229,7 @@ template <typename Graph,
|
|||
typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_PLY(const std::string& fname,
|
||||
Graph& g,
|
||||
std::string& comments,
|
||||
const CGAL_NP_CLASS& np = parameters::default_values()
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
, std::enable_if_t<!internal::is_Point_set_or_Range_or_Iterator<Graph>::value>* = nullptr
|
||||
|
|
@ -218,16 +241,29 @@ bool read_PLY(const std::string& fname,
|
|||
{
|
||||
std::ifstream is(fname, std::ios::binary);
|
||||
CGAL::IO::set_mode(is, CGAL::IO::BINARY);
|
||||
return internal::read_PLY_BGL(is, g, np);
|
||||
return read_PLY(is, g, comments, np);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ifstream is(fname);
|
||||
CGAL::IO::set_mode(is, CGAL::IO::ASCII);
|
||||
return internal::read_PLY_BGL(is, g, np);
|
||||
return read_PLY(is, g, comments, np);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Graph,
|
||||
typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_PLY(const std::string& fname,
|
||||
Graph& g,
|
||||
const CGAL_NP_CLASS& np = parameters::default_values()
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
, std::enable_if_t<!internal::is_Point_set_or_Range_or_Iterator<Graph>::value>* = nullptr
|
||||
#endif
|
||||
)
|
||||
{
|
||||
std::string unused_comment;
|
||||
return read_PLY(fname, g, unused_comment, np);
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Write
|
||||
|
|
@ -259,6 +295,15 @@ bool read_PLY(const std::string& fname,
|
|||
must be available in `Graph`.}
|
||||
\cgalParamNEnd
|
||||
|
||||
\cgalParamNBegin{vertex_normal_map}
|
||||
\cgalParamDescription{a property map associating normals to the vertices of `g`}
|
||||
\cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%vertex_descriptor`
|
||||
as key type and `%Vector_3` as value type}
|
||||
\cgalParamDefault{`boost::get(CGAL::vertex_point, g)`}
|
||||
\cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
|
||||
must be available in `Graph`.}
|
||||
\cgalParamNEnd
|
||||
|
||||
\cgalParamNBegin{vertex_index_map}
|
||||
\cgalParamDescription{a property map associating to each vertex of `graph` a unique index}
|
||||
\cgalParamType{a class model of `WritablePropertyMap` with `boost::graph_traits<Graph>::%vertex_descriptor`
|
||||
|
|
@ -326,6 +371,8 @@ bool write_PLY(std::ostream& os,
|
|||
|
||||
bool has_vcolor = !is_default_parameter<CGAL_NP_CLASS, internal_np::vertex_color_map_t>::value;
|
||||
bool has_fcolor = !is_default_parameter<CGAL_NP_CLASS, internal_np::face_color_map_t>::value;
|
||||
constexpr bool has_vnormal = !is_default_parameter<CGAL_NP_CLASS, internal_np::vertex_normal_map_t>::value;
|
||||
|
||||
VIMap vim = CGAL::get_initialized_vertex_index_map(g, np);
|
||||
Vpm vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
|
||||
get_const_property_map(boost::vertex_point, g));
|
||||
|
|
@ -351,8 +398,20 @@ bool write_PLY(std::ostream& os,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
os << "element vertex " << vertices(g).size() << std::endl;
|
||||
internal::output_property_header(os, make_ply_point_writer (CGAL::Identity_property_map<Point_3>()));
|
||||
if constexpr (std::is_same<typename Kernel_traits<Point_3>::Kernel::FT, float>::value)
|
||||
{
|
||||
internal::output_property_header(os, make_ply_point_writer (CGAL::Identity_property_map<Point_3>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
typedef typename Kernel_traits<Point_3>::Kernel K;
|
||||
typedef decltype(std::declval<CGAL::Cartesian_converter<K, Epick> >().operator()(std::declval<Point_3>())) Target_point;
|
||||
auto fvpm = CGAL::make_cartesian_converter_property_map<Target_point>(vpm);
|
||||
internal::output_property_header(os, make_ply_point_writer (fvpm));
|
||||
}
|
||||
|
||||
//if vcm is not default add v:color property
|
||||
if(has_vcolor)
|
||||
{
|
||||
|
|
@ -362,10 +421,30 @@ bool write_PLY(std::ostream& os,
|
|||
<< "property uchar alpha" << std::endl;
|
||||
}
|
||||
|
||||
if constexpr (has_vnormal)
|
||||
{
|
||||
auto vnm = get_parameter(np, internal_np::vertex_normal_map);
|
||||
typedef decltype(vnm) Normal_map;
|
||||
typedef typename Normal_map::value_type Vector_3;
|
||||
typedef typename Kernel_traits<Vector_3>::Kernel K;
|
||||
typedef typename K::FT FT;
|
||||
if constexpr (std::is_same<FT, float>::value)
|
||||
{
|
||||
internal::output_property_header(os, make_ply_normal_writer (CGAL::Identity_property_map<Vector_3>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
typedef decltype(std::declval<CGAL::Cartesian_converter<K, Epick> >().operator()(std::declval<Vector_3>())) Target_vector;
|
||||
auto fvnm = CGAL::make_cartesian_converter_property_map<Target_vector>(vnm);
|
||||
internal::output_property_header(os, make_ply_normal_writer (fvnm));
|
||||
}
|
||||
}
|
||||
|
||||
os << "element face " << faces(g).size() << std::endl;
|
||||
internal::output_property_header(
|
||||
os, std::make_pair(CGAL::Identity_property_map<std::vector<std::size_t> >(),
|
||||
PLY_property<std::vector<int> >("vertex_indices")));
|
||||
|
||||
//if fcm is not default add f:color property
|
||||
if(has_fcolor)
|
||||
{
|
||||
|
|
@ -378,8 +457,42 @@ bool write_PLY(std::ostream& os,
|
|||
|
||||
for(vertex_descriptor vd : vertices(g))
|
||||
{
|
||||
const Point_3& p = get(vpm, vd);
|
||||
internal::output_properties(os, &p, make_ply_point_writer (CGAL::Identity_property_map<Point_3>()));
|
||||
if constexpr (std::is_same<typename Kernel_traits<Point_3>::Kernel::FT, float>::value)
|
||||
{
|
||||
decltype(auto) p = get(vpm, vd);
|
||||
internal::output_properties(os, &p, make_ply_point_writer (CGAL::Identity_property_map<Point_3>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
typedef typename Kernel_traits<Point_3>::Kernel K;
|
||||
typedef CGAL::cpp20::remove_cvref_t<decltype(std::declval<CGAL::Cartesian_converter<K, Epick> >().operator()(std::declval<Point_3>()))> Target_point;
|
||||
CGAL::Cartesian_converter_property_map<Target_point, Vpm> fvpm = CGAL::make_cartesian_converter_property_map<Target_point>(vpm);
|
||||
decltype(auto) fp = get(fvpm, vd);
|
||||
internal::output_properties(os, &fp, make_ply_point_writer (CGAL::Identity_property_map<Target_point>()));
|
||||
}
|
||||
|
||||
std::cout << "using generic writer" << std::endl;
|
||||
|
||||
if constexpr (!parameters::is_default_parameter<CGAL_NP_CLASS, internal_np::vertex_normal_map_t>::value)
|
||||
{
|
||||
auto vnm = get_parameter(np, internal_np::vertex_normal_map);
|
||||
typedef decltype(vnm) Normal_map;
|
||||
typedef typename Normal_map::value_type Vector_3;
|
||||
|
||||
if constexpr (std::is_same<typename Kernel_traits<Vector_3>::Kernel::FT, float>::value)
|
||||
{
|
||||
decltype(auto) vec = get(vnm,vd);
|
||||
internal::output_properties(os, &vec, make_ply_normal_writer (CGAL::Identity_property_map<Vector_3>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
typedef typename Kernel_traits<Vector_3>::Kernel K;
|
||||
typedef CGAL::cpp20::remove_cvref_t<decltype(std::declval<CGAL::Cartesian_converter<K, Epick> >().operator()(std::declval<Vector_3>()))> Target_vector;
|
||||
auto fvnm = CGAL::make_cartesian_converter_property_map<Target_vector>(vnm);
|
||||
decltype(auto) fvec = get(fvnm, vd);
|
||||
internal::output_properties(os, &fvec, make_ply_normal_writer (CGAL::Identity_property_map<Target_vector>()));
|
||||
}
|
||||
}
|
||||
if(has_vcolor)
|
||||
{
|
||||
const CGAL::IO::Color& c = get(vcm, vd);
|
||||
|
|
@ -455,6 +568,15 @@ bool write_PLY(std::ostream& os, const Graph& g, const CGAL_NP_CLASS& np = param
|
|||
must be available in `Graph`.}
|
||||
\cgalParamNEnd
|
||||
|
||||
\cgalParamNBegin{vertex_normal_map}
|
||||
\cgalParamDescription{a property map associating normals to the vertices of `g`}
|
||||
\cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%vertex_descriptor`
|
||||
as key type and `%Vector_3` as value type}
|
||||
\cgalParamDefault{`boost::get(CGAL::vertex_point, g)`}
|
||||
\cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
|
||||
must be available in `Graph`.}
|
||||
\cgalParamNEnd
|
||||
|
||||
\cgalParamNBegin{vertex_index_map}
|
||||
\cgalParamDescription{a property map associating to each vertex of `graph` a unique index between `0` and `num_vertices(graph) - 1`}
|
||||
\cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%vertex_descriptor`
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
Algebraic_foundations
|
||||
Arithmetic_kernel
|
||||
BGL
|
||||
Cartesian_kernel
|
||||
Circulator
|
||||
Distance_2
|
||||
Distance_3
|
||||
Filtered_kernel
|
||||
Homogeneous_kernel
|
||||
Hash_map
|
||||
Installation
|
||||
Intersections_2
|
||||
Intersections_3
|
||||
Interval_support
|
||||
Kernel_23
|
||||
Kernel_d
|
||||
Modular_arithmetic
|
||||
Number_types
|
||||
Profiling_tools
|
||||
|
|
@ -15,3 +21,4 @@ Property_map
|
|||
Random_numbers
|
||||
STL_Extension
|
||||
Stream_support
|
||||
CGAL_Core
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
OFF
|
||||
25 13 0
|
||||
|
||||
0.39160239696502686 1.3864846229553223 4.8046874923102223e-08
|
||||
0.053782559931278229 1.3864846229553223 4.8046874923102223e-08
|
||||
-0.94644606113433838 1.6651756763458252 4.8046874923102223e-08
|
||||
-1.3082554340362549 1.7385153770446777 4.8046874923102223e-08
|
||||
-1.3033660650253296 1.1860226392745972 4.8046874923102223e-08
|
||||
1.61628258228302 -0.17601536214351654 4.8046874923102223e-08
|
||||
0.55834579467773438 -0.19216139614582062 4.8046874923102223e-08
|
||||
0.053782559931278229 -0.17601536214351654 4.8046874923102223e-08
|
||||
-0.24240998923778534 -0.22679123282432556 4.8046874923102223e-08
|
||||
-0.58168435096740723 -0.25845989584922791 4.8046874923102223e-08
|
||||
-1.2915089130401611 -0.17601536214351654 4.8046874923102223e-08
|
||||
-1.50871741771698 -0.17601536214351654 4.8046874923102223e-08
|
||||
1.61628258228302 -1.7385153770446777 4.8046874923102223e-08
|
||||
1.1978726387023926 -1.7385153770446777 4.8046874923102223e-08
|
||||
0.71942150592803955 -1.7385153770446777 4.8046874923102223e-08
|
||||
0.053782559931278229 -1.7385153770446777 4.8046874923102223e-08
|
||||
-0.73973840475082397 -1.7385153770446777 4.8046874923102223e-08
|
||||
1.61628258228302 0.36264327168464661 4.8046874923102223e-08
|
||||
-0.26156377792358398 0.45463424921035767 4.8046874923102223e-08
|
||||
-0.028661971911787987 -0.78840988874435425 4.8046874923102223e-08
|
||||
0.053782559931278229 -1.2213115692138672 4.8046874923102223e-08
|
||||
-1.5918357372283936 1.5331641435623169 4.8046874923102223e-08
|
||||
-1.6162823438644409 0.87338578701019287 4.8046874923102223e-08
|
||||
-1.50871741771698 -0.0072435899637639523 4.8046874923102223e-08
|
||||
-1.50871741771698 -1.3000825643539429 4.8046874923102223e-08
|
||||
7 18 2 3 4 22 9 8
|
||||
3 2 18 1
|
||||
7 18 7 6 5 17 0 1
|
||||
7 12 5 6 7 8 19 13
|
||||
6 11 24 16 15 20 10
|
||||
3 9 19 8
|
||||
4 10 20 19 9
|
||||
3 7 18 8
|
||||
3 14 20 15
|
||||
4 13 19 20 14
|
||||
3 3 21 4
|
||||
4 9 22 23 10
|
||||
3 10 23 11
|
||||
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include <CGAL/boost/graph/Euler_operations.h>
|
||||
#include <CGAL/boost/graph/IO/OFF.h>
|
||||
|
||||
#include <boost/range/distance.hpp>
|
||||
|
||||
#include <string>
|
||||
|
|
@ -213,12 +212,30 @@ collapse_edge_test()
|
|||
assert(found == 2);
|
||||
CGAL::clear(test_mesh);
|
||||
}
|
||||
// Case 6 non pure triangle mesh
|
||||
{
|
||||
Mesh ref;
|
||||
if(!CGAL::IO::read_OFF("data/polygon_mesh_to_collapse.off", ref))
|
||||
{
|
||||
std::cout << "Error reading file: data/polygon_mesh_to_collapse.off" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
std::size_t nbe=halfedges(ref).size();
|
||||
for (std::size_t i=0; i< nbe; ++i)
|
||||
{
|
||||
Mesh m = ref;
|
||||
auto h = *std::next(halfedges(m).begin(), i);
|
||||
|
||||
if (CGAL::Euler::does_satisfy_link_condition(edge(h,m),m))
|
||||
CGAL::Euler::collapse_edge(edge(h,m), m);
|
||||
assert(CGAL::is_valid_polygon_mesh(m));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
collapse_edge_test<Polyhedron>();
|
||||
collapse_edge_test<SM>();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
# Created by the script cgal_create_cmake_script.
|
||||
# This is the CMake script for compiling a CGAL application.
|
||||
|
||||
project(Barycentric_coordinates_2_Benchmarks)
|
||||
|
||||
cmake_minimum_required(VERSION 3.12...3.31)
|
||||
project(Barycentric_coordinates_2_Benchmarks)
|
||||
|
||||
find_package(CGAL REQUIRED COMPONENTS Core)
|
||||
|
||||
|
|
@ -14,8 +12,9 @@ create_single_source_cgal_program("benchmark_polygon_16_vertices.cpp")
|
|||
create_single_source_cgal_program("benchmark_polygon_100_vertices.cpp")
|
||||
create_single_source_cgal_program("benchmark_mv_34_vertices.cpp")
|
||||
|
||||
find_package(Eigen3 3.1.0 QUIET) # (3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
if(TARGET CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program("benchmark_hm_4_vertices.cpp")
|
||||
target_link_libraries(benchmark_hm_4_vertices PRIVATE CGAL::Eigen3_support)
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@ create_single_source_cgal_program("terrain_height_modeling.cpp")
|
|||
# this code is deprecated:
|
||||
create_single_source_cgal_program("deprecated_coordinates.cpp")
|
||||
|
||||
find_package(Eigen3 3.1.0 QUIET) # (3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
if(TARGET CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program("affine_coordinates.cpp")
|
||||
target_link_libraries(affine_coordinates PRIVATE CGAL::Eigen3_support)
|
||||
|
|
|
|||
|
|
@ -42,8 +42,9 @@ create_single_source_cgal_program("test_wp_deprecated_api.cpp")
|
|||
create_single_source_cgal_program("test_mv_deprecated_api.cpp")
|
||||
create_single_source_cgal_program("test_dh_deprecated_api.cpp")
|
||||
|
||||
find_package(Eigen3 3.1.0 QUIET) # (3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
if(TARGET CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program("test_hm_unit_square.cpp")
|
||||
target_link_libraries(test_hm_unit_square PRIVATE CGAL::Eigen3_support)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ project(Basic_viewer_Examples)
|
|||
|
||||
#CGAL_Qt6 is needed for the drawing.
|
||||
find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt6)
|
||||
find_package(Eigen3 3.1.0)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
create_single_source_cgal_program("draw_lcc.cpp")
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ project(Approximate_min_ellipsoid_d_Examples)
|
|||
find_package(CGAL REQUIRED)
|
||||
|
||||
# Use Eigen
|
||||
find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
# create a target per cppfile
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ project(Bounding_volumes_Tests)
|
|||
find_package(CGAL REQUIRED COMPONENTS Core)
|
||||
|
||||
# Use Eigen
|
||||
find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
# create a target per cppfile
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
|||
|
||||
find_package(CGAL REQUIRED COMPONENTS Core)
|
||||
|
||||
find_package(Eigen3 3.1.0 QUIET) #(requires 3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
if(NOT TARGET CGAL::Eigen3_support)
|
||||
message("NOTICE: This project requires the Eigen library, and will not be compiled.")
|
||||
return()
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@ if(NOT TARGET CGAL::Boost_iostreams_support)
|
|||
set(Classification_dependencies_met FALSE)
|
||||
endif()
|
||||
|
||||
find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
if(NOT TARGET CGAL::Eigen3_support)
|
||||
message("NOTICE: This project requires the Eigen library, and will not be compiled.")
|
||||
set(Classification_dependencies_met FALSE)
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@ if(NOT TARGET CGAL::Boost_iostreams_support)
|
|||
set(Classification_dependencies_met FALSE)
|
||||
endif()
|
||||
|
||||
find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
if(NOT TARGET CGAL::Eigen3_support)
|
||||
message("NOTICE: This project requires the Eigen library, and will not be compiled.")
|
||||
set(Classification_dependencies_met FALSE)
|
||||
|
|
|
|||
|
|
@ -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".
|
||||
|
||||
|
|
|
|||
|
|
@ -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,8 +3710,8 @@ namespace CGAL {
|
|||
void set_automatic_attributes_management_without_correction(bool newval)
|
||||
{ this->automatic_attributes_management = newval; }
|
||||
|
||||
/** Create an half-edge.
|
||||
* @return a dart of the new half-edge.
|
||||
/** Create a halfedge.
|
||||
* @return a dart of the new halfedge.
|
||||
*/
|
||||
Dart_descriptor make_half_edge()
|
||||
{ return create_dart(); }
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ In any way, a package has to work with both representations.
|
|||
Since \cgal uses homogeneous representation for affine geometry and not
|
||||
for projective geometry, the homogenizing coordinate is non zero.
|
||||
The cartesian
|
||||
representation corresponding to an homogeneous point
|
||||
representation corresponding to a homogeneous point
|
||||
\f$ (x_0,x_1,...,x_d,w)\f$ is
|
||||
\f$ (x_0/w,x_1/w,...,x_d/w)\f$. Hence, homogeneous representation is not unique;
|
||||
\f$ (\alpha x,\alpha y,\alpha z,\alpha w)\f$ is an alternative
|
||||
|
|
|
|||
|
|
@ -117,14 +117,14 @@ Qt is a cross-platform application and UI framework.
|
|||
The component `CGAL_Qt6` is essential to run the \cgal demos and basic viewers.
|
||||
It requires \qt6 installed on your system.
|
||||
In case \qt is not yet installed on your system, you can download
|
||||
it from <A HREF="https://www.qt-project.org/">`https://www.qt-project.org/`</A>.
|
||||
it from <A HREF="https://contribute.qt-project.org/">`https://contribute.qt-project.org/`</A>.
|
||||
|
||||
The exhaustive list of \qt6 components used in demos is:
|
||||
`Core`, `Gui`, `Help`, `OpenGL`, `OpenGLWidgets`, `Qml`, `Svg`, `Widgets`,
|
||||
`WebSockets`, `Network`, and `qcollectiongenerator` (with `sqlite` driver plugin).
|
||||
|
||||
\subsection thirdpartyEigen Eigen
|
||||
<b>Version 3.3.7 or later</b>
|
||||
<b>Version 3.3.7 or later (including Eigen3 5.0.0)</b>
|
||||
|
||||
\eigen is a `C++` template library for linear algebra. \eigen supports all
|
||||
matrix sizes, various matrix decomposition methods and sparse linear solvers.
|
||||
|
|
@ -138,7 +138,7 @@ Overview</a> page. In order to use Eigen in \cgal programs, the
|
|||
executables should be linked with the CMake imported target
|
||||
`CGAL::Eigen3_support` provided in `CGAL_Eigen3_support.cmake`.
|
||||
|
||||
The \eigen web site is <A HREF="https://eigen.tuxfamily.org/index.php?title=Main_Page">`https://eigen.tuxfamily.org`</A>.
|
||||
The \eigen web site is <A HREF="https://libeigen.gitlab.io/">`https://libeigen.gitlab.io/`</A>.
|
||||
|
||||
\subsection thirdpartyOpenGR OpenGR
|
||||
|
||||
|
|
@ -167,17 +167,6 @@ Alternatively, version 1.3.1 of \libpointmatcher is supported with version 3.3.7
|
|||
`https://github.com/ethz-asl/libpointmatcher/blob/master/doc/Compilation.md`:`NABO_INCLUDE_DIR` becomes `libnabo_INCLUDE_DIRS`
|
||||
and `NABO_LIBRARY` becomes `libnabo_LIBRARIES` in the "Build libpointmatcher" section.
|
||||
|
||||
\subsection thirdpartyLeda LEDA
|
||||
<b>Version 6.2 or later</b>
|
||||
|
||||
\leda is a library of efficient data structures and
|
||||
algorithms. Like \core, \leda offers a real number data type.
|
||||
|
||||
In \cgal this library is optional, and its number types can
|
||||
be used as an alternative to \gmp, \mpfr, and \core.
|
||||
|
||||
Free and commercial editions of \leda are available from <A HREF="https://www.algorithmic-solutions.com">`https://www.algorithmic-solutions.com`</A>.
|
||||
|
||||
\subsection thirdpartyMPFI Multiple Precision Floating-point Interval (MPFI)
|
||||
<b>Version 1.4 or later</b>
|
||||
|
||||
|
|
@ -265,7 +254,7 @@ vcpkg install suitesparse
|
|||
\subsection thirdpartyMETIS METIS
|
||||
<b>Version 5.1 or later</b>
|
||||
|
||||
\metis is a library developed by the <A HREF="http://glaros.dtc.umn.edu/gkhome/">Karypis Lab</A>
|
||||
\metis is a library developed by the <A HREF="https://github.com/KarypisLab/">Karypis Lab</A>
|
||||
and designed to partition graphs and produce fill-reducing matrix orderings.
|
||||
|
||||
\cgal offers wrappers around some of the methods of the \metis library
|
||||
|
|
@ -274,7 +263,7 @@ to allow the partitioning of graphs that are models of the concepts of the
|
|||
and, by extension, of surface meshes (see Section \ref BGLPartitioning of the package \ref PkgBGL).
|
||||
|
||||
More information is available on the METIS library
|
||||
at <A HREF="http://glaros.dtc.umn.edu/gkhome/metis/metis/overview">`http://glaros.dtc.umn.edu/gkhome/metis/metis/overview`</A>.
|
||||
at <A HREF="https://github.com/KarypisLab/METIS">`https://github.com/KarypisLab/METIS`</A>.
|
||||
|
||||
\subsection thirdpartyzlib zlib
|
||||
|
||||
|
|
|
|||
|
|
@ -83,12 +83,12 @@ a newline character and each coordinate separated by a white
|
|||
space. Other formats available are 'OFF', 'PLY' and 'LAS'. \cgal
|
||||
provides functions to read such formats:
|
||||
|
||||
- `read_XYZ()`
|
||||
- `read_OFF()`
|
||||
- `read_PLY()`
|
||||
- `read_PLY_with_properties()` to read additional PLY properties
|
||||
- `read_LAS()`
|
||||
- `read_LAS_with_properties()` to read additional LAS properties
|
||||
- `CGAL::IO::read_XYZ()`
|
||||
- `CGAL::IO::read_OFF()`
|
||||
- `CGAL::IO::read_PLY()`
|
||||
- `CGAL::IO::read_PLY_with_properties()` to read additional PLY properties
|
||||
- `CGAL::IO::read_LAS()`
|
||||
- `CGAL::IO::read_LAS_with_properties()` to read additional LAS properties
|
||||
|
||||
\cgal also provides a dedicated container `CGAL::Point_set_3` to
|
||||
handle point sets with additional properties such as normal
|
||||
|
|
|
|||
|
|
@ -152118,3 +152118,15 @@ keywords = {polygonal surface mesh, Surface reconstruction, kinetic framework, s
|
|||
pages={11},
|
||||
year={2015}
|
||||
}
|
||||
|
||||
@article{liu2025linequadrics,
|
||||
journal = {Computer Graphics Forum},
|
||||
title = {{Controlling Quadric Error Simplification with Line Quadrics}},
|
||||
author = {Liu, Hsueh-Ti Derek and Rahimzadeh, Mehdi and Zordan, Victor},
|
||||
year = {2025},
|
||||
publisher = {The Eurographics Association and John Wiley & Sons Ltd.},
|
||||
ISSN = {1467-8659},
|
||||
DOI = {10.1111/cgf.70184},
|
||||
url = {https://doi.org/10.1111/cgf.70184},
|
||||
year={2025}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ project( Frechet_distance_Examples )
|
|||
find_package(CGAL REQUIRED QUIET OPTIONAL_COMPONENTS Core )
|
||||
|
||||
|
||||
find_package(Eigen3 3.1.0 QUIET) #(requires 3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
create_single_source_cgal_program( "Frechet_distance_2.cpp" )
|
||||
|
|
|
|||
|
|
@ -514,6 +514,7 @@ inline void FrechetLight<C>::continueQSimpleSearch(QSimpleInterval& qsimple,
|
|||
// TODO: uncritical for correctness or speed but unelegant coding style: stripping down information added by getInterval
|
||||
CInterval temp_interval = FrechetLight::getInterval<IndexType>(
|
||||
fixed_curve, fixed, curve, cur);
|
||||
|
||||
Interval interval = Interval(temp_interval.begin.getPoint() == cur
|
||||
? temp_interval.begin.getFraction()
|
||||
: 1,
|
||||
|
|
|
|||
|
|
@ -113,7 +113,10 @@ struct Lambda<Curve<FilteredTraits,true>>
|
|||
// fill_lambda returns a pair and we are only interested in a bound
|
||||
bool update_exact() const
|
||||
{
|
||||
if (is_exact) {
|
||||
if (is_exact){
|
||||
if (!exact.has_value()){
|
||||
exact = (is_one) ? std::make_optional(Exact(1)) : std::make_optional(Exact(0));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -198,7 +201,9 @@ struct Lambda<Curve<FilteredTraits,true>>
|
|||
{
|
||||
if ((is_zero && other.is_zero) || (is_one && other.is_one))
|
||||
return false;
|
||||
if ((is_zero && (!other.is_zero)) || (!is_one && other.is_one))
|
||||
// AF this may be wrong if approx is [0.9,1.1] and other.is_one:
|
||||
// if ((is_zero && (!other.is_zero)) || (!is_one && other.is_one))
|
||||
if(is_zero && other.is_one)
|
||||
return true;
|
||||
CGAL::Uncertain<bool> res = approx < other.approx;
|
||||
if (CGAL::is_certain(res)) {
|
||||
|
|
@ -206,7 +211,8 @@ struct Lambda<Curve<FilteredTraits,true>>
|
|||
}
|
||||
update_exact();
|
||||
other.update_exact();
|
||||
return exact < other.exact;
|
||||
bool eres = exact.value() < other.exact.value();
|
||||
return eres;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,12 @@ project( Frechet_distance_Tests )
|
|||
|
||||
find_package(CGAL REQUIRED)
|
||||
|
||||
find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
create_single_source_cgal_program( "Frechet-IssueOct25.cpp" )
|
||||
|
||||
if(TARGET CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program( "Frechet_distance_test.cpp" )
|
||||
target_link_libraries(Frechet_distance_test PRIVATE CGAL::Eigen3_support)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Frechet_distance.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using Point = Kernel::Point_2;
|
||||
using Segment = Kernel::Segment_2;
|
||||
|
||||
bool load_polyline(const std::string &filename, std::vector<Point> &polyline) {
|
||||
polyline.clear();
|
||||
std::ifstream ifs(filename);
|
||||
|
||||
if (!ifs)
|
||||
return false;
|
||||
|
||||
while (ifs.good()) {
|
||||
Point p;
|
||||
ifs >> p;
|
||||
if (ifs.good())
|
||||
polyline.push_back(p);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
std::vector<Point> poly1, poly2;
|
||||
|
||||
if (!load_polyline("poly1.txt", poly1) || !load_polyline("poly2.txt", poly2)) {
|
||||
std::cout << "input files could not be loaded" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
std::pair<double, double> res = CGAL::bounded_error_Frechet_distance(poly1, poly2, 0.000001);
|
||||
std::cout << "Frechet distance: [" << res.first << ", " << res.second << "]" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -6,8 +6,7 @@ project( classical_Frechet_distance )
|
|||
|
||||
find_package(CGAL REQUIRED)
|
||||
|
||||
|
||||
find_package(Eigen3 3.1.0 QUIET) #(requires 3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
create_single_source_cgal_program("Compute_classical_Frechet_distance_3.cpp")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,185 @@
|
|||
-126 70
|
||||
-138 58
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-39 -18
|
||||
-42.6 -14
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
|
|
@ -0,0 +1,625 @@
|
|||
-126 70
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
70 -138
|
||||
61.4 -118.4
|
||||
61.4 -118
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
-126 70
|
||||
|
|
@ -494,7 +494,7 @@ The output is:
|
|||
Number of 2-free darts: 8
|
||||
\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 8 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 8 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 8 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 8 darts are 2-free.
|
||||
|
||||
See also a similar example for Linear cell complex \ref Linear_cell_complexInsert "Insert an Edge Between Two Different Faces".
|
||||
|
||||
|
|
|
|||
|
|
@ -2949,8 +2949,8 @@ namespace CGAL {
|
|||
void set_automatic_attributes_management_without_correction(bool newval)
|
||||
{ this->automatic_attributes_management = newval; }
|
||||
|
||||
/** Create an half-edge.
|
||||
* @return a dart of the new half-edge.
|
||||
/** Create a halfedge.
|
||||
* @return a dart of the new halfedge.
|
||||
*/
|
||||
Dart_descriptor make_half_edge()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ namespace CGAL {
|
|||
/*!
|
||||
|
||||
The class `Random_points_in_cube_d` is an input iterator creating points uniformly
|
||||
distributed in an half-open cube.
|
||||
distributed in a half-open cube.
|
||||
|
||||
\cgalModels{InputIterator,PointGenerator}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ create_single_source_cgal_program("random_segments1.cpp")
|
|||
create_single_source_cgal_program("random_segments2.cpp")
|
||||
create_single_source_cgal_program("sphere_d.cpp")
|
||||
|
||||
find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
if(TARGET CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program("random_points_in_tetrahedral_mesh_3.cpp")
|
||||
target_link_libraries(random_points_in_tetrahedral_mesh_3 PRIVATE CGAL::Eigen3_support)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@ create_single_source_cgal_program("test_tetrahedron_3.cpp")
|
|||
create_single_source_cgal_program("test_triangle_2.cpp")
|
||||
create_single_source_cgal_program("test_triangle_3.cpp")
|
||||
|
||||
find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
if(TARGET CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program("generic_random_test.cpp")
|
||||
target_link_libraries(generic_random_test PRIVATE CGAL::Eigen3_support)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt6)
|
|||
|
||||
find_package(Qt6 QUIET COMPONENTS Widgets)
|
||||
|
||||
find_package(Eigen3 3.1.91 QUIET) #(requires 3.1.91 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
if(NOT TARGET CGAL::Eigen3_support)
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ project(Polygon_Demo)
|
|||
|
||||
find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt6 Core)
|
||||
|
||||
find_package(Eigen3 3.1.0 QUIET) #(requires 3.1.0 or greater)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
if(NOT TARGET CGAL::Eigen3_support)
|
||||
message("NOTICE: This demo requires the Eigen library, and will not be compiled.")
|
||||
return()
|
||||
|
|
|
|||
|
|
@ -221,7 +221,10 @@ void
|
|||
DemosMainWindow::popupAboutBox(QString title, QString html_resource_name)
|
||||
{
|
||||
QFile about_CGAL(html_resource_name);
|
||||
about_CGAL.open(QIODevice::ReadOnly);
|
||||
if (!about_CGAL.open(QIODevice::ReadOnly)) {
|
||||
QMessageBox::warning(this, tr("Error"), tr("Could not open resource file: %1").arg(html_resource_name));
|
||||
return;
|
||||
}
|
||||
QString about_CGAL_txt = QTextStream(&about_CGAL).readAll();
|
||||
#ifdef CGAL_VERSION_STR
|
||||
QString cgal_version(CGAL_VERSION_STR);
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ private:
|
|||
QTimer flyTimer_;
|
||||
|
||||
bool rotatesAroundUpVector_;
|
||||
// Inverse the direction of an horizontal mouse motion. Depends on the
|
||||
// Inverse the direction of a horizontal mouse motion. Depends on the
|
||||
// projected screen orientation of the vertical axis when the mouse button is
|
||||
// pressed.
|
||||
bool constrainedRotationIsReversed_;
|
||||
|
|
|
|||
|
|
@ -743,7 +743,7 @@ public:
|
|||
typedef std::vector<Halfedge_handle> HVector;
|
||||
HVector stack;
|
||||
// Algorithm: The next() pointer is used as visited tag
|
||||
// for a graph search. If the next pointer of an halfedge
|
||||
// for a graph search. If the next pointer of a halfedge
|
||||
// or its opposite halfedge is set to Halfedge_handle(),
|
||||
// this edge has already been visited and must not be put
|
||||
// on the stack again.
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ project(Heat_method_3_Examples)
|
|||
# CGAL and its components
|
||||
find_package(CGAL REQUIRED)
|
||||
|
||||
find_package(Eigen3 3.3.0 QUIET)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
if(NOT TARGET CGAL::Eigen3_support)
|
||||
message("NOTICE: These examples require the Eigen library (3.3 or greater), and will not be compiled.")
|
||||
return()
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ project(Heat_method_3_Tests)
|
|||
# CGAL and its components
|
||||
find_package(CGAL REQUIRED)
|
||||
|
||||
find_package(Eigen3 3.3.0 QUIET)
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
if(NOT TARGET CGAL::Eigen3_support)
|
||||
message("NOTICE: These tests require the Eigen library (3.3 or greater), and will not be compiled.")
|
||||
return()
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ The Delaunay triangulation of a set of points \f$P\f$ in the hyperbolic plane \f
|
|||
|
||||
- `HyperbolicDelaunayTriangulationTraits_2` describes the requirements for an interface for geometric objects, constructions, and predicates in the hyperbolic plane.
|
||||
- `HyperbolicTriangulationFaceBase_2` describes the requirements for faces of the hyperbolic Delaunay triangulation.
|
||||
- `HyperbolicFaceData` describes the requirements for an hyperbolic marker of faces of the hyperbolic Delaunay triangulation, used to filter faces of the Euclidean Delaunay triangulation.
|
||||
- `HyperbolicFaceData` describes the requirements for a hyperbolic marker of faces of the hyperbolic Delaunay triangulation, used to filter faces of the Euclidean Delaunay triangulation.
|
||||
|
||||
\cgalCRPSection{Classes}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,13 @@
|
|||
|
||||
Release date: July 2026
|
||||
|
||||
### [2D Arrangements](https://doc.cgal.org/6.1/Manual/packages.html#PkgArrangementOnSurface2)
|
||||
|
||||
- Introduced a Geometry Traits concept for arrangement on surfaces that enables the provision of the disconnected portions of an approximation of a curve within a given bounding box.
|
||||
- Made the `Arr_linear_traits_2` a model of the new concept.
|
||||
- Added overloads of `draw(Arrangement_on_surface_2& arr, Bbox& bbox, ...)` that enable the drawing of arrangements induced by unbounded curves.
|
||||
|
||||
|
||||
### [Linear Cell Complex](https://doc.cgal.org/6.2/Manual/packages.html#PkgLinearCellComplex)
|
||||
|
||||
- **API Changes**: The following import functions have been deprecated and renamed for better naming clarity and consistency:
|
||||
|
|
@ -12,6 +19,15 @@ Release date: July 2026
|
|||
- `import_from_triangulation_3()` → `triangulation_3_to_lcc()`
|
||||
- The old function names are still available but marked as deprecated for backward compatibility.
|
||||
|
||||
|
||||
### [Surface Mesh Simplification](https://doc.cgal.org/6.2/Manual/packages.html#PkgSurfaceMeshSimplification)
|
||||
|
||||
- Added the class `CGAL::Surface_mesh_simplification::GarlandHeckbert_plane_and_line_policies`, which provides improved output for `CGAL::Surface_mesh_simplification::edge_collapse()`.
|
||||
That class works the same as previous `GarlandHeckbert_policies`.
|
||||
Its constructor accepts a `Mesh` and optional named parameters to set the weight of the line policy relative to the plane policy, set the boundary cost multiplier or provide vertex normals.
|
||||
- **Breaking change**: `CGAL::Surface_mesh_simplification::GarlandHeckbert_policies.h` is now an alias of `CGAL::Surface_mesh_simplification::GarlandHeckbert_plane_and_line_policies.h` and is no longer deprecated.
|
||||
|
||||
|
||||
## [Release 6.1](https://github.com/CGAL/cgal/releases/tag/v6.1)
|
||||
|
||||
Release date: Sept 2025
|
||||
|
|
@ -58,6 +74,71 @@ Release date: Sept 2025
|
|||
|
||||
See also the associated [news entry](https://www.cgal.org/2025/06/24/triangulations-on-hyperbolic-surfaces/).
|
||||
|
||||
### 3D Isosurfacing (new package)
|
||||
|
||||
- This package provides algorithms to extract isosurfaces from different inputs. The input is represented
|
||||
as a 3D domain and can be an implicit function or a Cartesian grid. The output is an indexed face
|
||||
set that stores an isosurface in the form of a surface mesh. The provided algorithms include Marching Cubes,
|
||||
topologically correct Marching Cubes, and Dual Contouring.
|
||||
|
||||
### [Polygon Mesh Processing](https://doc.cgal.org/6.1/Manual/packages.html#PkgPolygonMeshProcessing)
|
||||
- Added the function `CGAL::Polygon_mesh_processing::discrete_mean_curvature` and `CGAL::Polygon_mesh_processing::discrete_Guassian_curvature` to evaluate the discrete curvature at a vertex of a mesh.
|
||||
- Added the function `CGAL::Polygon_mesh_processing::angle_sum` to compute the sum of the angles around a vertex.
|
||||
- Added a function in the [visitor of the corefinement based methods](https://doc.cgal.org/6.1/Polygon_mesh_processing/classPMPCorefinementVisitor.html)
|
||||
to know faces in the output meshes that are corresponding to input coplanar faces.
|
||||
- Added the function `CGAL::Polygon_mesh_processing::approximated_centroidal_Voronoi_diagram_remeshing()`
|
||||
to remesh triangle meshes. This remeshing algorithm uses clustering on polygonal meshes as to
|
||||
approximate a Centroidal Voronoi Diagram construction, and can move vertices as to recover
|
||||
sharp features and corners.
|
||||
- New implementation of `CGAL::Polygon_mesh_processing::clip()` with a plane as clipper that is much faster and is now able to handle non-triangulated surface meshes.
|
||||
- New implementation of `CGAL::Polygon_mesh_processing::split()` with a plane as clipper that is much faster and is now able to handle non-triangulated surface meshes.
|
||||
- Added the function `CGAL::Polygon_mesh_processing::refine_with_plane()`, which enables users to refine a mesh with their intersection with a plane.
|
||||
|
||||
### [Point Set Processing](https://doc.cgal.org/6.1/Manual/packages.html#PkgPointSetProcessing3)
|
||||
- Added `poisson_eliminate()` to downsample a point cloud to a target size while providing Poisson disk property, i.e., a larger minimal distance between points.
|
||||
|
||||
### [Algebraic Kernel](https://doc.cgal.org/6.1/Manual/packages.html#PkgAlgebraicKernelD)
|
||||
- **Breaking change**: Classes based on the RS Library are no longer provided.
|
||||
|
||||
### [BGL](https://doc.cgal.org/6.1/Manual/packages.html#PkgBGL)
|
||||
- Added the function `CGAL::Euler::remove_degree_2_vertex()`, which enables users to remove vertices which have exactly two incident edges.
|
||||
|
||||
### [2D Arrangements](https://doc.cgal.org/6.1/Manual/packages.html#PkgArrangementOnSurface2)
|
||||
|
||||
- Introduces two traits decorators, namely `Arr_tracing_traits_2` and `Arr_counting_traits_2`, which can be used to extract debugging and informative metadata about the traits in use while a program is being executed.
|
||||
- Fixed the Landmark point-location strategy so that it can be applied to arrangements on a sphere.
|
||||
- Fixed a bug in the extensions of vertex and halfedge types of the DCEL when used to instantiate Arrangement_with_history_2 or similar arrangement classes that derive from Arrangement_2.
|
||||
- Renamed the prefix of the names of all concepts in the Arrangement_on_surface_2 package from "Arrangement" to "Aos".
|
||||
- Renamed the old concept `AosApproximateTraits_2` to `AosApproximatePointTraits_2` to make room for the new concept `AosApproximateTraits_2`. This concept requires the provision of a functor called `Approximate_2` that has an operator that approximates the coordinates of a point.
|
||||
- Introduced a new concept called `AosApproximateTraits_2`. It refines the concept `AosApproximatePointTraits_2`. This concept requires the provision of a functor called `Approximate_2`. In addition to an operator that approximates the coordinates of a point, it also requires the provision of (i) an operator that approximates a points, and (ii) an operator that approximates a curve.
|
||||
- Changed all "typedef" style statements in the user manual to "using" style. (Observe that a similar update to the examples has already been made in a previous release.)
|
||||
- Fixed do_intersect() of a 2D Arrangement and a curve.
|
||||
- Added overloads of `draw(Arrangement_on_surface_2& arr, Bbox& bbox, ...)` that enable the drawing of arrangements induced by unbounded curves.
|
||||
- Introduced a Geometry Traits concept for arrangement on surfaces that enables the provision of the disconnected portions of an approximation of a curve within a given bounding box.
|
||||
- Made the `Arr_linear_traits_2` a model of the new concept.
|
||||
|
||||
### [3D Mesh Generation](https://doc.cgal.org/6.1/Manual/packages.html#PkgMesh3)
|
||||
|
||||
- Added two new meshing parameters that enable mesh initialization customization :
|
||||
- `initial_points_generator` : enables the user to specify a functor that generates initial points,
|
||||
- `initial_points` : enables the user to specify a `Range` of initial points.
|
||||
- Added a new meshing parameter `surface_only`, to improve performances when the user is only interested in surface mesh generation.
|
||||
|
||||
### [Poisson Surface Reconstruction](https://doc.cgal.org/6.1/Manual/packages.html#PkgPoissonSurfaceReconstruction3)
|
||||
- Added a new mesh domain `Poisson_mesh_domain_3` that integrates some optimizations from the deprecated 3D Surface Mesh Generation package.
|
||||
|
||||
### [3D Subdivision Methods](https://doc.cgal.org/6.1/Manual/packages.html#PkgSurfaceSubdivisionMethod3)
|
||||
|
||||
- Added a new named parameter for `CGAL::Subdivision_method_3::Loop_subdivision()` and
|
||||
`CGAL::Subdivision_method_3::CatmullClark_subdivision()`, which enables users to subdivide
|
||||
a mesh without modifying its geometry.
|
||||
|
||||
### [2D Triangulations](https://doc.cgal.org/6.1/Manual/packages.html#PkgTriangulation2)
|
||||
|
||||
- **Breaking change**: In the class template `Constrained_triangulation_plus_2`, the value type of the range returned
|
||||
by `subconstraints()` has changed from `const std::pair<const Subconstraint, std::list<Context>*>` to `Subconstraint`.
|
||||
The old range type is now returned by a new function named `subconstraints_and_contexts()`.
|
||||
|
||||
### [Polygon Repair](https://doc.cgal.org/6.1/Manual/packages.html#PkgPolygonRepair)
|
||||
|
||||
- Added the [non-zero rule](https://doc.cgal.org/6.1/Polygon_repair/structCGAL_1_1Polygon__repair_1_1Non__zero__rule.html)
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ if(CERES_FOUND AND NOT TARGET CGAL::Ceres_support)
|
|||
set_target_properties(CGAL::Ceres_support PROPERTIES
|
||||
INTERFACE_COMPILE_DEFINITIONS "CGAL_PMP_USE_CERES_SOLVER"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${CERES_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES "ceres")
|
||||
INTERFACE_LINK_LIBRARIES "Ceres::ceres")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
if((EIGEN3_FOUND OR Eigen3_FOUND) AND NOT TARGET CGAL::Eigen3_support)
|
||||
if ("${Eigen3_VERSION}" VERSION_LESS "3.3.7")
|
||||
set (EIGEN3_FOUND 0)
|
||||
find_package(Eigen3 3.3.7 QUIET) # (3.3.7 or greater)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if((EIGEN3_FOUND OR Eigen3_FOUND) AND NOT TARGET CGAL::Eigen3_support)
|
||||
if(NOT TARGET Threads::Threads)
|
||||
find_package(Threads REQUIRED)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue