diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index b313e4245dc..055f818ace6 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -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 diff --git a/AABB_tree/doc/AABB_tree/Concepts/AABBPrimitiveWithSharedData.h b/AABB_tree/doc/AABB_tree/Concepts/AABBPrimitiveWithSharedData.h index 284c90b6038..b85c3461cb2 100644 --- a/AABB_tree/doc/AABB_tree/Concepts/AABBPrimitiveWithSharedData.h +++ b/AABB_tree/doc/AABB_tree/Concepts/AABBPrimitiveWithSharedData.h @@ -44,12 +44,14 @@ Type of input datum. typedef unspecified_type Datum; /*! -Point reference type returned by the function `point(const Shared_data&)`. It is convertible to the type `Point`. +Point reference type returned by the function \link reference_point `reference_point(const Shared_data&)`\endlink. +It is convertible to the type `Point`. */ typedef unspecified_type Point_reference; /*! -Datum reference type returned by the function `datum(const Shared_data&)`. It is convertible to the type `Datum`. +Datum reference type returned by the function \link datum `datum(const Shared_data&)`\endlink. +It is convertible to the type `Datum`. */ typedef unspecified_type Datum_reference; diff --git a/AABB_tree/include/CGAL/AABB_tree.h b/AABB_tree/include/CGAL/AABB_tree.h index fdc6a71817c..8476d671875 100644 --- a/AABB_tree/include/CGAL/AABB_tree.h +++ b/AABB_tree/include/CGAL/AABB_tree.h @@ -128,7 +128,7 @@ namespace CGAL { * @param first iterator over first primitive to insert * @param beyond past-the-end iterator * - * constructs an empty tree followed by a call to `insert(first,last,t...)`. + * constructs an empty tree followed by a call to \link insert(InputIterator, InputIterator, T&&...) `insert(first,last,t...)`\endlink. * The tree stays empty if the memory allocation is not successful. */ template @@ -140,7 +140,8 @@ namespace CGAL { /// This procedure is called implicitly at the first call to a query member function. /// An explicit call to `build()` must be made to ensure that the next call to /// a query function will not trigger the construction of the data structure. - /// A call to `AABBTraits::set_shared_data(t...)` is made using the internally stored traits. + /// A call to \link AABBTraits::set_shared_data `AABBTraits::set_shared_data(t...)`\endlink + // is made using the internally stored traits. /// This procedure has a complexity of \cgalBigO{n log(n)}, where \f$n\f$ is the number of /// primitives of the tree. template @@ -160,16 +161,17 @@ namespace CGAL { /// \name Operations ///@{ - /// is equivalent to calling `clear()`, `insert(first,last,t...)`, and `build()` + /// is equivalent to calling `clear()`, \link insert(InputIterator, InputIterator, T&&...) `insert(first,last,t...)`\endlink, + // and `build()` template void rebuild(ConstPrimitiveIterator first, ConstPrimitiveIterator beyond,T&& ...); - /// adds a sequence of primitives to the set of primitives of the AABB tree. /// `%InputIterator` is any iterator and the parameter pack `T` contains any types /// such that `Primitive` has a constructor with the following signature: /// `Primitive(%InputIterator, T...)`. If `Primitive` is a model of the concept - /// `AABBPrimitiveWithSharedData`, a call to `AABBTraits::set_shared_data(t...)` + /// `AABBPrimitiveWithSharedData`, a call to + /// \link AABBTraits::set_shared_data `AABBTraits::set_shared_data(t...)`\endlink /// is made using the internally stored traits. template void insert(InputIterator first, InputIterator beyond,T&& ...); diff --git a/Algebraic_foundations/doc/Algebraic_foundations/Concepts/FromDoubleConstructible.h b/Algebraic_foundations/doc/Algebraic_foundations/Concepts/FromDoubleConstructible.h index 6746fedcee2..e130fd73852 100644 --- a/Algebraic_foundations/doc/Algebraic_foundations/Concepts/FromDoubleConstructible.h +++ b/Algebraic_foundations/doc/Algebraic_foundations/Concepts/FromDoubleConstructible.h @@ -7,7 +7,7 @@ A model of the concept `FromDoubleConstructible` is required to be constructible from the type `double`. In case the type is a model of `RealEmbeddable` too, for any double d -the identity: `d == CGAL::to_double(T(d))`, is guaranteed. +the identity: `d == ` \link CGAL::to_double ` CGAL::to_double(T(d))`\endlink, is guaranteed. */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt b/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt index 0b2f6aa2082..a1b3034e3d5 100644 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt @@ -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` 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` class. Since storing hidden sites may not be of interest in some cases (e.g., diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_2.h index 1a8f0f595f2..20f8ecbb12f 100644 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_2.h +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_2.h @@ -112,7 +112,7 @@ typedef Gt::Site_2 Site_2; the edge type. The `Edge(f,i)` is the edge common to faces `f` and `f.neighbor(i)`. It is also the edge joining the vertices -`vertex(cw(i))` and `vertex(ccw(i))` of `f`. +`f->vertex(cw(i))` and `f->vertex(ccw(i))` of `f`. \pre `i` must be `0`, `1` or `2`. */ typedef Data_structure::Edge Edge; diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_2.h index 778dd9160e1..0cf934d8ab1 100644 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_2.h +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_2.h @@ -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()); diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt index f7c3e6ef4ce..93d0489722c 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt @@ -1048,8 +1048,8 @@ not coincide with any existing arrangement vertex and does not lie on any edge. As mentioned in Section \ref arr_ssectraverse, it is possible to obtain the face containing an isolated vertex calling the member function `Arrangement_on_surface_2::Vertex::face()`. The member -function -`Arrangement_on_surface_2::remove_isolated_vertex(Vertex_handle v)` +function \link Arrangement_on_surface_2::remove_isolated_vertex() +`Arrangement_on_surface_2::remove_isolated_vertex(Vertex_handle v)`\endlink accepts a handle to an isolated vertex and removes it from the arrangement. @@ -4890,7 +4890,7 @@ using Arrangement = CGAL::Arrangement_2; \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`, 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() \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 diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_circle_segment_traits_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_circle_segment_traits_2.h index 88b0fc1dc2b..c05c6e2b3a1 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_circle_segment_traits_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_circle_segment_traits_2.h @@ -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 diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_conic_traits_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_conic_traits_2.h index 33a5f127a31..613942f9e75 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_conic_traits_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_conic_traits_2.h @@ -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} */ diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_linear_traits_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_linear_traits_2.h index 8a26dc62256..d46569f0e12 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_linear_traits_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_linear_traits_2.h @@ -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 class Arr_linear_traits_2 { diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_observer.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_observer.h index 7335a661699..3b7001a984a 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_observer.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_observer.h @@ -3,9 +3,8 @@ namespace CGAL { /*! \ingroup PkgArrangementOnSurface2Ref * * `Arr_observer` is an alias for - * `Aos_observer`, - * where `Arrangement_2` derives from `Arrangement_on_surface_2` and the latter - * is an instance of the template + * `Aos_observer`, where `Arrangement_2` derives from + * `Arrangement_on_surface_2` and the latter is an instance of the template * `CGAL::Arrangement_on_surface_2`. */ diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_segment_traits_2.h index 3d2826da6f5..5a4db7d2735 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_segment_traits_2.h @@ -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 class Arr_segment_traits_2 : public Kernel { diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/draw_arrangement_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/draw_arrangement_2.h index e8748ae253c..3660fd211d6 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/draw_arrangement_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/draw_arrangement_2.h @@ -19,6 +19,8 @@ #include +#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 -void draw(const Arrangement_2& arr, - const GSOptions& gso); + +template +void draw(const Arrangement_on_surface_2& 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{})`, where `Aos` is + * `Arrangement_on_surface_2`. */ -template -void draw(const Arrangement_2& arr); + +template +void draw(const Arrangement_on_surface_2& 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 -void add_to_graphics_scene(const Arrangement_2& arr, - CGAL::Graphics_scene& gs, const GSOptions& gso); + +template +void draw(const Arrangement_on_surface_2& 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{})`, where `Aos` is + * `Arrangement_on_surface_2`. */ -template -void add_to_graphics_scene(const Arrangement_2& arr, - CGAL::Graphics_scene& gs); + +template +void draw(const Arrangement_on_surface_2& arr, + const char* title = "2D Arrangement on Surface"); } /* namespace CGAL */ diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosApproximatePointTraits_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosApproximatePointTraits_2.h index 90b53ff56e5..367a8703ce3 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosApproximatePointTraits_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosApproximatePointTraits_2.h @@ -18,8 +18,6 @@ * \cgalHasModels{CGAL::Arr_rational_function_traits_2} * \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; /// @} diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosApproximateTraits_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosApproximateTraits_2.h index 2020e723039..c04fee15fc2 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosApproximateTraits_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosApproximateTraits_2.h @@ -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: diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosApproximateUnboundedTraits_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosApproximateUnboundedTraits_2.h new file mode 100644 index 00000000000..518d5b01889 --- /dev/null +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosApproximateUnboundedTraits_2.h @@ -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} + * \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; + + /// @} +} diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--ApproximatePoint_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--ApproximatePoint_2.h new file mode 100644 index 00000000000..6d311aff303 --- /dev/null +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--ApproximatePoint_2.h @@ -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 */ + +} diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--ApproximateUnbounded_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--ApproximateUnbounded_2.h new file mode 100644 index 00000000000..6431ad05d9f --- /dev/null +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--ApproximateUnbounded_2.h @@ -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 + OutputIterator operator()(const X_monotone_curve_2& xcv, double error, OutputIterator oi, + const Bbox_2& bbox, bool l2r = true) const; + + /// @} +}; /* end AosTraits::Approximate_2 */ + +} diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--Approximate_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--Approximate_2.h index a9712000aa9..f1a3caaf62b 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--Approximate_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--Approximate_2.h @@ -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 OutputIterator operator()(const X_monotone_curve_2& xcv, double error, diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--Merge_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--Merge_2.h index 6c8bbdf153f..117c62aaf9c 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--Merge_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/AosTraits--Merge_2.h @@ -18,7 +18,7 @@ public: /*! accepts two mergeable \f$x\f$-monotone curves `xc1` and `xc2` * and assigns `xc` with the merged curve. * - * \pre `are_mergeable_2`(`xc1`, `xc2`) is true. + * \pre \link AosTraits::AreMergeable_2 `are_mergeable_2`\endlink(`xc1`, `xc2`) is true. */ void merge(AosTraits::X_monotone_curve_2 xc1, AosTraits::X_monotone_curve_2 xc2, diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/OverlayTraits.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/OverlayTraits.h index ec00686e66b..fae8d501a84 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/OverlayTraits.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/OverlayTraits.h @@ -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: /// @{ diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/PackageDescription.txt b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/PackageDescription.txt index ea1b0b666e7..d1f0ab2fa19 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/PackageDescription.txt +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/PackageDescription.txt @@ -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 */ diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/examples.txt b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/examples.txt index f3d19cb4c94..9a03d716697 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/examples.txt +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/examples.txt @@ -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 + */ diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt index bb5566835ab..6fe1641085f 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt @@ -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 diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circles.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circles.cpp index f12cfb5af63..5b5c0e1967d 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circles.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circles.cpp @@ -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; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circular_arcs.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circular_arcs.cpp index 11043fb5555..252983822b0 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circular_arcs.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circular_arcs.cpp @@ -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; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_agas.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_agas.cpp new file mode 100644 index 00000000000..9bae8834bc8 --- /dev/null +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_agas.cpp @@ -0,0 +1,106 @@ +#include + +#include + +#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 arcs; + std::vector> 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 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 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; +} diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_arr.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_arr.cpp index 1b10d7504fa..31830317fdd 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_arr.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_arr.cpp @@ -1,13 +1,13 @@ +#include + +#include +#include #include #include #include +#include #include -using Kernel = CGAL::Exact_predicates_exact_constructions_kernel; -using Traits = CGAL::Arr_segment_traits_2; -using Point = Traits::Point_2; -using Arrangement_2 = CGAL::Arrangement_2; - /*! 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; * \param sat Saturation component range: [0, 1] * \param value Value component range: [0, 1] * \return tuple, where each component is in the range [0, 255] -*/ -std::tuple -hsv_to_rgb(float hue, float sat, float value) { + */ +std::tuple 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; + using Point = Traits::Point_2; + using Arrangement = CGAL::Arrangement_2; + 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 + gso; + gso.colored_face = [](const Arrangement&, Arrangement::Face_const_handle) -> bool { return true; }; - CGAL::Graphics_scene_options 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; + using Point = Traits::Point_2; + using Arrangement = CGAL::Arrangement_2; + 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 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; + 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; + + 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; + using Point = Traits::Point_2; + using Arrangement = CGAL::Arrangement_2; + 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 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; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/ellipses.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/ellipses.cpp index 480b0eefe31..a83c3a69efc 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/ellipses.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/ellipses.cpp @@ -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; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/hyperbolas.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/hyperbolas.cpp index 8c165cac9f6..ecc9961adf2 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/hyperbolas.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/hyperbolas.cpp @@ -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; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/linear_conics.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/linear_conics.cpp index 071c118052e..abec7c1dc8b 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/linear_conics.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/linear_conics.cpp @@ -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; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/parabolas.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/parabolas.cpp index 7213b06f095..8b1faa498a7 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/parabolas.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/parabolas.cpp @@ -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; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/polylines.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/polylines.cpp index 51fa18d82c8..1320b164323 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/polylines.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/polylines.cpp @@ -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; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/rational_functions.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/rational_functions.cpp index 20c542f086b..b9dbc0eb88f 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/rational_functions.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/rational_functions.cpp @@ -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. diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/spherical_insert.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/spherical_insert.cpp index 300cbb2d061..ad54d5890b6 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/spherical_insert.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/spherical_insert.cpp @@ -1,6 +1,5 @@ //! \file examples/Arrangement_on_surface_2/spherical_insert.cpp // Constructing an arrangement of arcs of great circles. - #include #include #include @@ -9,6 +8,7 @@ #include #include #include +#include #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; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/spherical_overlay.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/spherical_overlay.cpp index e43b1df9ab8..3ff03015e93 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/spherical_overlay.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/spherical_overlay.cpp @@ -3,6 +3,7 @@ #include #include +#include #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; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/unbounded_non_intersecting.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/unbounded_non_intersecting.cpp index 7de9d0981d6..132c4948bd3 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/unbounded_non_intersecting.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/unbounded_non_intersecting.cpp @@ -4,6 +4,7 @@ #include +#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; } diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Bezier_x_monotone_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Bezier_x_monotone_2.h index ba17acc09ad..65e3806529d 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Bezier_x_monotone_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Bezier_x_monotone_2.h @@ -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); diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_linear_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_linear_traits_2.h index bf8792fdac5..8cd273a6463 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_linear_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_linear_traits_2.h @@ -28,11 +28,13 @@ #include +#include #include #include #include #include #include +#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_kernel; + typedef Approximate_kernel::Point_2 Approximate_point_2; class Approximate_2 { + protected: + using Traits = Arr_linear_traits_2; + + /*! 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; + 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 + 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 + 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(&*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(&*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(&*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(&*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(&*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(&*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 { diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_polycurve_basic_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_polycurve_basic_traits_2.h index 94173b2e083..b59b5079d89 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_polycurve_basic_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_polycurve_basic_traits_2.h @@ -1115,6 +1115,7 @@ public: using Approximate_number_type = void; using Approximate_point_2 = void; using Approximate_2 = void; + using Approximate_kernel = void; }; template @@ -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::Approximate_2; using Approximate_point_2 = typename has_approximate_2::Approximate_point_2; + using Approximate_kernel = + typename has_approximate_2::Approximate_kernel; /*! obtains an Approximate_2 functor object. */ Approximate_2 approximate_2_object_impl(std::false_type) const diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_polyline_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_polyline_traits_2.h index 90864a7f64e..b84e30259bf 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_polyline_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_polyline_traits_2.h @@ -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: diff --git a/Arrangement_on_surface_2/include/CGAL/Arrangement_2/Arrangement_zone_2_impl.h b/Arrangement_on_surface_2/include/CGAL/Arrangement_2/Arrangement_zone_2_impl.h index 370f0d78043..379a83b321f 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arrangement_2/Arrangement_zone_2_impl.h +++ b/Arrangement_on_surface_2/include/CGAL/Arrangement_2/Arrangement_zone_2_impl.h @@ -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:: 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 +bool Arrangement_zone_2:: +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 +bool Arrangement_zone_2:: +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 +bool Arrangement_zone_2:: +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::_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::_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 diff --git a/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h b/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h index 811fdb931e2..2faebbd50f8 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h @@ -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. */ diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximation_cache.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximation_cache.h new file mode 100644 index 00000000000..9d872f4f78f --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_approximation_cache.h @@ -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 + +#ifndef CGAL_DRAW_AOS_ARR_APPROXIMATION_CACHE_H +#define CGAL_DRAW_AOS_ARR_APPROXIMATION_CACHE_H + +#include + +#include + +#include +#include +#include + +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 +class Arr_approximation_cache { + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Approx_traits = Arr_approximate_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; + using Halfedge_cache = unordered_flat_map; + using Face_cache = unordered_flat_map; + +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 diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_face.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_face.h new file mode 100644 index 00000000000..b5e72418a06 --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_face.h @@ -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 + +#ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_FACE_H +#define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_FACE_H + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { + +namespace draw_aos { + +/*! \brief Functor to approximate arrangement face with triangles within a bounding box. + * + * \tparam Arrangement + */ +template +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; + 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; + using Bounded_approximate_halfedge = Arr_bounded_approximate_halfedge; + using Bounded_render_context = Arr_bounded_render_context; + using Triangulator = Arr_bounded_face_triangulator; + + static constexpr bool Is_on_curved_surface = is_or_derived_from_curved_surf_traits_v; + + 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 + 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 m_start, m_mid; + }; + + class Context : public Bounded_render_context { + using Simplifier = Colinear_simplifier>; + + 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& last_pt() const { return m_last_pt; } + + private: + Triangulator& m_triangulator; + // Colinear simplifier is only used for optimizing planar arrangements. + std::optional m_simplifier; + std::optional 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 diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_halfedge.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_halfedge.h new file mode 100644 index 00000000000..3668dd1953c --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_halfedge.h @@ -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 + +#ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_HALFEDGE_H +#define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_HALFEDGE_H + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +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 +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; + 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; + using Boundary_lines = std::array; + + constexpr static bool Has_approximate_xcv_with_bounds = + has_approximate_xcv_with_bounds_v; + +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& last_pt() const { return m_last_pt; } + + private: + std::optional 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 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(*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) return curve.is_in_x_range(pt); + if constexpr(!has_parameter_space_in_x_2::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(ctx, polyline, he); } + + // For planar arrangements, we only need to reverse the polyline if the halfedge is rtl. + template , 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 , 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(ctx); } + + // If Approximate_2 supports curve approximation with bounding box + template , 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 , 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 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::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 diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_vertex.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_vertex.h new file mode 100644 index 00000000000..44c5867cb18 --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_approximate_vertex.h @@ -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 + +#ifndef CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_VERTEX_H +#define CGAL_DRAW_AOS_ARR_BOUNDED_APPROXIMATE_VERTEX_H + +#include + +#include +#include + +namespace CGAL { +namespace draw_aos { + +template +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::Point; + using Bounded_render_context = Arr_bounded_render_context; + +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 diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_face_triangulator.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_face_triangulator.h new file mode 100644 index 00000000000..01041c66195 --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_face_triangulator.h @@ -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 + +#ifndef CGAL_DRAW_AOS_ARR_FACE_TRIANGULATOR_H +#define CGAL_DRAW_AOS_ARR_FACE_TRIANGULATOR_H + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CGAL_DRAW_AOS_DEBUG) && defined(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR) +#include +#include + +template +class Arr_bounded_face_triangulator; + +template +void debug_print(const Arr_bounded_face_triangulator& triangulator); +#endif + +namespace CGAL { +namespace draw_aos { + +/** + * @brief Triangulator for a face of an arrangement within a bounding box. + */ +template +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; + + using Approx_traits = Arr_approximate_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 + friend void debug_print(const Arr_bounded_face_triangulator& 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; + using Fb = Constrained_triangulation_face_base_2; + using Tds = Triangulation_data_structure_2; + // For planar arrangements, Constrained_triangulation_2 is enough. + using Ct = std::conditional_t, + Constrained_triangulation_2>; + + using KPoint = Epick::Point_2; + using KPoint_with_index = std::pair; + using Bounded_render_context = Arr_bounded_render_context; + +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(0); + auto indexes_end = boost::make_counting_iterator(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(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(start_idx); + auto indexes_end = boost::make_counting_iterator(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 in_domain_map; + in_domain_map.reserve(m_ct.number_of_faces()); + boost::associative_property_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 m_points; + std::vector m_point_types; + std::vector> m_cst_ranges; + std::optional m_curr_cst_begin; + double m_offset{0}; +}; + +#if defined(CGAL_DRAW_AOS_DEBUG) && defined(CGAL_DRAW_AOS_TRIANGULATOR_DEBUG_FILE_DIR) +template +void debug_print(const Arr_bounded_face_triangulator& 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::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(*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 diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_renderer.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_renderer.h new file mode 100644 index 00000000000..964697daf40 --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_bounded_renderer.h @@ -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 + +#ifndef CGAL_DRAW_AOS_ARR_BOUNDED_RENDERER_H +#define CGAL_DRAW_AOS_ARR_BOUNDED_RENDERER_H + +#include + +#include +#include +#include +#include +#include + +namespace CGAL { +namespace draw_aos { + +/** @brief Render arrangement on surface within a bounding box. + */ +template +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; + using Approx_cache = Arr_approximation_cache; + +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 derived_ctx(m_ctx, m_bbox, cache); + Arr_bounded_approximate_face 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 diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_coordinate_converter.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_coordinate_converter.h new file mode 100644 index 00000000000..82b2478f10c --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_coordinate_converter.h @@ -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 + +#ifndef CGAL_DRAW_AOS_ARR_COORDINATE_CONVERTER_H +#define CGAL_DRAW_AOS_ARR_COORDINATE_CONVERTER_H + +#include + +#include + +#include +#include +#include + +namespace CGAL { +namespace draw_aos { + +/*! \brief class handling coordinate conversion between 2D parameterized surface coordinates and cartesian coordinates. + * + * \tparam GeomTraits + */ +template +class Arr_coordinate_converter { + using Geom_traits = GeomTraits; + using Approx_traits = Arr_approximate_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 +class Arr_coordinate_converter> { + using Geom_traits = Arr_geodesic_arc_on_sphere_traits_2; + using Approx_traits = Arr_approximate_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 diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_face_point_generator.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_face_point_generator.h new file mode 100644 index 00000000000..398f8be03e4 --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_face_point_generator.h @@ -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 + +#ifndef CGAL_DRAW_AOS_ARR_FACE_POINT_GENERATOR_H +#define CGAL_DRAW_AOS_ARR_FACE_POINT_GENERATOR_H + +#include + +#include +#include +#include + +#include + +#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 +class Arr_face_point_generator; + +template +class Arr_face_point_generator>> { + using Point_geom = typename Arr_approximate_traits::Point; + using Face_const_handle = typename Arrangement::Face_const_handle; + +public: + using Face_points_map = unordered_flat_map>; + + // No-op implementation for non-curved surface arrangements. + Face_points_map operator()(const Arrangement&, double) { return {}; } +}; + +template +class Arr_face_point_generator>> { + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Approx_traits = Arr_approximate_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::Type>; + +public: + using Face_points_map = unordered_flat_map>; + + 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 points; + Arr_coordinate_converter 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_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(res.second)) return; + Face_const_handle fh = std::get(res.second); + auto [it, _] = face_points.try_emplace(fh, std::vector()); + it->second.push_back(coords.to_uv(traits.approximate_2_object()(res.first))); + })); + return face_points; + } +}; + +} // namespace draw_aos +} // namespace CGAL + +#endif diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_render_context.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_render_context.h new file mode 100644 index 00000000000..54a554535db --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_render_context.h @@ -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 + +#ifndef CGAL_DRAW_AOS_ARR_RENDER_CONTEXT_H +#define CGAL_DRAW_AOS_ARR_RENDER_CONTEXT_H + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CGAL_DRAW_AOS_DEBUG) +#include +#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; + +protected: + Arr_cancellable_context_mixin() : + m_start_time(Clock::now()), + m_cancelled(std::make_shared>(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> 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 +class Arr_bounds_context_mixin { + using Geom_traits = GeomTraits; + using Approx_traits = Arr_approximate_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 +using Arr_parameterization_context_mixin = Arr_coordinate_converter; + +template +class Arr_render_context : + public Arr_cancellable_context_mixin, + public Arr_parameterization_context_mixin { + using Cancellable_context_mixin = Arr_cancellable_context_mixin; + using Param_context_mixin = Arr_parameterization_context_mixin; + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Face_points_map = typename Arr_face_point_generator::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 debug_counter = std::make_shared(0); +#endif +}; + +template +class Arr_bounded_render_context : + public Arr_render_context, + public Arr_bounds_context_mixin { + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Approx_point = typename Geom_traits::Approximate_point_2; + using Render_context = Arr_render_context; + using Bounds_context_mixin = Arr_bounds_context_mixin; + using Approx_cache = Arr_approximation_cache; + +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 diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_viewer.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_viewer.h new file mode 100644 index 00000000000..65765badf56 --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/Arr_viewer.h @@ -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 + +#ifndef ARR_VIEWER_H +#define ARR_VIEWER_H + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { +namespace draw_aos { + +/*! \brief Viewport helper functions + * + * \tparam Arrangement + */ +template +class Arr_viewport_helpers; + +// Specialization for planar arrangements +template +class Arr_viewport_helpers>> { + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Approx_traits = Arr_approximate_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 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::max(); + double xmax = std::numeric_limits::lowest(); + double ymin = std::numeric_limits::max(); + double ymax = std::numeric_limits::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 +class Arr_viewport_helpers>> { + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Approx_traits = Arr_approximate_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(*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 +class Arr_viewer : public Qt::Basic_viewer, Arr_viewport_helpers { + using Basic_viewer = Qt::Basic_viewer; + using Helpers = Arr_viewport_helpers; + 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; + using Approx_point = typename Approx_traits::Approx_point; + using Point = typename Approx_traits::Point; + using Point_generator = Arr_face_point_generator; + 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; + +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 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 ctx(m_arr, params.approx_error, face_points); + Arr_bounded_renderer 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) { + 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 m_coords; + Render_params m_last_params; +}; + +} // namespace draw_aos +} // namespace CGAL + +#endif diff --git a/Arrangement_on_surface_2/include/CGAL/Draw_aos/type_utils.h b/Arrangement_on_surface_2/include/CGAL/Draw_aos/type_utils.h new file mode 100644 index 00000000000..3704bd923d9 --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/Draw_aos/type_utils.h @@ -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 + +#ifndef CGAL_DRAW_AOS_TYPE_UTILS_H +#define CGAL_DRAW_AOS_TYPE_UTILS_H + +#include + +#include +#include +#include +#include + +#include + +namespace CGAL { +namespace draw_aos { + +enum class Boundary_side { + Top = 0, + Left = 1, + Bottom = 2, + Right = 3, + None = -1, +}; + +template > +struct has_approximate_2_object : std::false_type {}; + +template +struct has_approximate_2_object().approximate_2_object())>> : std::true_type +{}; + +// Detect whether Gt has defined a member function approximate_2_object() +template +inline constexpr bool has_approximate_2_object_v = has_approximate_2_object::value; + +template > +struct has_approximate_point : std::false_type {}; + +template +struct has_approximate_point()(std::declval()))>> : + std::true_type +{}; + +// Detect whether A has operator()(const Gt::Point_2&) +template +inline constexpr bool has_approximate_point_v = has_approximate_point::value; + +template > +struct has_approximate_xcv : std::false_type {}; + +template +struct has_approximate_xcv +()(std::declval(), + std::declval(), + std::declval(), + std::declval()))>> : std::true_type +{}; + +// Detect whether A has operator()(const Gt::X_monotone_curve_2&, double, OutputIterator, bool)? +template +constexpr bool has_approximate_xcv_v = has_approximate_xcv::value; + +template > +struct has_approximate_xcv_with_bounds : std::false_type +{}; + +template +struct has_approximate_xcv_with_bounds +()(std::declval(), + std::declval(), + std::declval(), + std::declval(), + std::declval()))>> : std::true_type +{}; + +// Detect whether A has operator()(const X_monotone_curve&, double, OutputIterator, Bbox_2, bool) +template +inline constexpr bool has_approximate_xcv_with_bounds_v = has_approximate_xcv_with_bounds::value; + +// Detect whether a geometry traits has all the necessary types and functions for approximation +template +constexpr bool has_approximate_traits_v = + has_approximate_2_object_v && has_approximate_point_v && + (has_approximate_xcv_v || + has_approximate_xcv_with_bounds_v); + +template > +struct has_is_in_x_range : std::false_type +{}; + +template +struct has_is_in_x_range().is_in_x_range + (std::declval()))>> : std::true_type +{}; + +// Detect whether Gt::X_monotone_curve_2 has a member function bool is_in_x_range(const Gt::Point_2&) +template +inline constexpr bool has_is_in_x_range_v = has_is_in_x_range::value; + +// Detect whether Gt is or derives from Arr_geodesic_arc_on_sphere_traits_2<*, *, *> +template +struct is_or_derived_from_agas { +private: + template + static std::true_type test(const Arr_geodesic_arc_on_sphere_traits_2*); + + static std::false_type test(...); + +public: + static constexpr bool value = decltype(test(static_cast(nullptr)))::value; +}; + +template +inline constexpr bool is_or_derived_from_agas_v = is_or_derived_from_agas::value; + +// Detect whether T is or derives from a geometry traits on curved surfaces +template +inline constexpr bool is_or_derived_from_curved_surf_traits_v = is_or_derived_from_agas_v; + +// Static helpers to get template arguments from a geometry traits +template +struct tmpl_args {}; + +template +struct tmpl_args> { + using Kernel = Kernel_; + static constexpr int atan_x = AtanX; + static constexpr int atan_y = AtanY; +}; + +/*! \brief Approximation data types + * + * \tparam Gt Geometry traits + */ +template +class Arr_approximate_traits { + using Geom_traits = Gt; + + template + struct Triangle_soup_ { + using Index = I; + using Triangle = std::array; + using Point = P; + + std::vector points; + std::vector 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; + + using Triangle_soup = Triangle_soup_; + + // 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::signaling_NaN(), std::numeric_limits::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 +class Construct_gt_point_2 { + using Approx_traits = Arr_approximate_traits; + 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 +class Construct_gt_point_2> { + using Geom_traits = Arr_geodesic_arc_on_sphere_traits_2; + using Approx_traits = Arr_approximate_traits>; + 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(pt.location())); + } +}; + +} // namespace draw_aos +} // namespace CGAL + +#endif // CGAL_DRAW_AOS_TYPE_UTILS_H diff --git a/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h b/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h index 1057e1c0f8a..1317f5d362e 100644 --- a/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h +++ b/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h @@ -11,84 +11,94 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s): Efi Fogel +// Author(s): Efi Fogel +// Shepard Liu #ifndef CGAL_DRAW_ARRANGEMENT_2_H #define CGAL_DRAW_ARRANGEMENT_2_H #include - -#include - -#include +#include #include -#include +#include +#include +#include +#include +#ifdef CGAL_USE_BASIC_VIEWER +#include +#endif + +#include +#include +#include #include #include #include #include +#include +#include +#include +#include +#include -#include -#include -#include -#include +#ifdef CGAL_USE_BASIC_VIEWER +#include +#endif namespace CGAL { -namespace draw_function_for_arrangement_2 -{ - template - class Draw_arr_tool - { - public: - using Halfedge_const_handle=typename Arr::Halfedge_const_handle; - using Vertex_const_handle=typename Arr::Vertex_const_handle; - using Face_const_handle=typename Arr::Face_const_handle; - using Ccb_halfedge_const_circulator=typename Arr::Ccb_halfedge_const_circulator; - using Inner_ccb_const_iterator=typename Arr::Inner_ccb_const_iterator; - using Outer_ccb_const_iterator=typename Arr::Outer_ccb_const_iterator; - using Gt=typename Arr::Geometry_traits_2; - using Point=typename Arr::Point_2; - using X_monotone_curve = typename Arr::X_monotone_curve_2; +namespace draw_aos { - Draw_arr_tool(Arr& a_aos, CGAL::Graphics_scene& a_gs, const GSOptions& a_gso): - m_aos(a_aos), m_gs(a_gs), m_gso(a_gso) - {} +template +class Draw_arr_tool { +public: + using Halfedge_const_handle = typename Arr::Halfedge_const_handle; + using Vertex_const_handle = typename Arr::Vertex_const_handle; + using Face_const_handle = typename Arr::Face_const_handle; + using Ccb_halfedge_const_circulator = typename Arr::Ccb_halfedge_const_circulator; + using Inner_ccb_const_iterator = typename Arr::Inner_ccb_const_iterator; + using Outer_ccb_const_iterator = typename Arr::Outer_ccb_const_iterator; + using Gt = typename Arr::Geometry_traits_2; + using Point = typename Arr::Point_2; + using X_monotone_curve = typename Arr::X_monotone_curve_2; - /// Add a face. - void add_face(Face_const_handle face) - { - // std::cout << "add_face()\n"; - for (Inner_ccb_const_iterator it = face->inner_ccbs_begin(); - it != face->inner_ccbs_end(); ++it) - { add_ccb(*it); } + /*! constructs + */ + Draw_arr_tool(Arr& a_aos, CGAL::Graphics_scene& a_gs, const GSOptions& a_gso) : + m_aos(a_aos), + m_gs(a_gs), + m_gso(a_gso) + {} - for (Outer_ccb_const_iterator it = face->outer_ccbs_begin(); - it != face->outer_ccbs_end(); ++it) - { + //! adds a face. + void add_face(Face_const_handle face) { + // std::cout << "add_face()\n"; + for (Inner_ccb_const_iterator it = face->inner_ccbs_begin(); it != face->inner_ccbs_end(); ++it) add_ccb(*it); + + if (! face->is_unbounded()) { + for (Outer_ccb_const_iterator it = face->outer_ccbs_begin(); it != face->outer_ccbs_end(); ++it) { add_ccb(*it); draw_region(*it); } } + } - /// Add a Connected Component of the Boundary. - void add_ccb(Ccb_halfedge_const_circulator circ) - { - // std::cout << "add_ccb()\n"; - auto curr = circ; - do { - auto new_face = curr->twin()->face(); - if (m_visited.find(new_face) != m_visited.end()) continue; - m_visited[new_face] = true; - add_face(new_face); - } while (++curr != circ); - } + //! adds a Connected Component of the Boundary. + void add_ccb(Ccb_halfedge_const_circulator circ) { + // std::cout << "add_ccb()\n"; + auto curr = circ; + do { + auto new_face = curr->twin()->face(); + if (m_visited.find(new_face) != m_visited.end()) continue; + m_visited[new_face] = true; + add_face(new_face); + } while(++curr != circ); + } - ///! Draw a region. - void draw_region(Ccb_halfedge_const_circulator circ) - { + //! draws a region. + void draw_region(Ccb_halfedge_const_circulator circ) { // std::cout << "draw_region()\n"; /* Check whether the traits has a member function called * approximate_2_object() and if so check whether the return type, namely @@ -105,318 +115,248 @@ namespace draw_function_for_arrangement_2 * * For now we use C++14 features. */ - if(m_gso.colored_face(m_aos, circ->face())) - { m_gs.face_begin(m_gso.face_color(m_aos, circ->face())); } - else - { m_gs.face_begin(); } + if (m_gso.colored_face(m_aos, circ->face())) + m_gs.face_begin(m_gso.face_color(m_aos, circ->face())); + else + m_gs.face_begin(); - const auto* traits = this->m_aos.geometry_traits(); - auto ext = find_smallest(circ, *traits); - auto curr = ext; + const auto* traits = this->m_aos.geometry_traits(); + auto ext = find_smallest(circ, *traits); + auto curr = ext; - do { - // Skip halfedges that are "antenas": - while (curr->face() == curr->twin()->face()) curr = curr->twin()->next(); - draw_region_impl1(curr, *traits, 0); - curr = curr->next(); - } while (curr != ext); + do { + // Skip halfedges that are "antenas": + while(curr->face() == curr->twin()->face()) curr = curr->twin()->next(); + while(curr->face() == curr->twin()->face()) curr = curr->twin()->next(); + draw_region_impl1(*traits, curr); + curr = curr->next(); + } while(curr != ext); - m_gs.face_end(); - } + m_gs.face_end(); + } - /// Compile time dispatching -#if 0 - template - void draw_region_impl2(Halfedge_const_handle curr, T const&, long) - { draw_exact_region(curr); } + //! Compile time dispatching - template - auto draw_region_impl2(Halfedge_const_handle curr, T const& approx, int) -> - decltype(approx.template operator()(X_monotone_curve{}, double{}, I{}, - bool{}), void()) - { draw_approximate_region(curr, approx); } + //! + template , int> = 0> + void draw_region_impl2(const T& /* traits */, const A& /* approximate */, Halfedge_const_handle curr) + { draw_exact_region(curr); } - template - void draw_region_impl1(Halfedge_const_handle curr, T const&, long) - { draw_exact_region(curr); } + //! + template , int> = 0> + auto draw_region_impl2(const T& /* traits */, const A& approx, Halfedge_const_handle curr) + { draw_approximate_region(curr, approx); } - template - auto draw_region_impl1(Halfedge_const_handle curr, T const& traits, int) -> - decltype(traits.approximate_2_object(), void()) { - using Approximate = typename Gt::Approximate_2; - draw_region_impl2(curr, traits.approximate_2_object(), 0); - } -#else - template - void draw_region_impl1(Halfedge_const_handle curr, T const& traits, int) - { draw_approximate_region(curr, traits.approximate_2_object()); } -#endif + /*! draws a region, where the traits does not has approximate_2_object. + */ + template && !is_or_derived_from_agas_v, int> = 0> + void draw_region_impl1(const T& /* traits */, Halfedge_const_handle curr) + { draw_exact_region(curr); } - template - void draw_region_impl1 - (Halfedge_const_handle curr, - Arr_geodesic_arc_on_sphere_traits_2 const& traits, - int) - { - if(!m_gso.draw_edge(m_aos, curr)) - { return; } + /// + template && !is_or_derived_from_agas_v, int> = 0> + auto draw_region_impl1(const T& traits, Halfedge_const_handle curr) + { draw_region_impl2(traits, traits.approximate_2_object(), curr); } - // std::cout << "draw_region_impl1()\n"; - auto approx = traits.approximate_2_object(); - using Kernel = Kernel_; - using Traits = Arr_geodesic_arc_on_sphere_traits_2; - using Ak = typename Traits::Approximate_kernel; - using Ap = typename Traits::Approximate_point_2; - using Approx_point_3 = typename Ak::Point_3; + /*! draws a geodesic region + */ + template , int> = 0> + void draw_region_impl1(const T& traits, Halfedge_const_handle curr) { + //! \todo not implemented yet; for now, we just draw the boundaries using draw_curve_impl1() + draw_curve_impl1(traits, curr->curve(), false, CGAL::IO::Color()); + } - std::vector polyline; - double error(0.01); - bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT; - approx(curr->curve(), error, std::back_inserter(polyline), l2r); - if (polyline.empty()) return; - auto it = polyline.begin(); - auto x = it->dx(); - auto y = it->dy(); - auto z = it->dz(); - auto l = std::sqrt(x*x + y*y + z*z); - Approx_point_3 prev(x/l, y/l, z/l); - for (++it; it != polyline.end(); ++it) { - auto x = it->dx(); - auto y = it->dy(); - auto z = it->dz(); - auto l = std::sqrt(x*x + y*y + z*z); - Approx_point_3 next(x/l, y/l, z/l); + /*! draws a region using approximate coordinates. + * Call this member function only if the geometry traits is equipped with + * the coordinate-approximation functionality of a curve. + * This function must be inlined (e.g., a template) to enable the + * compiled-time dispatching in the function `draw_region()`. + */ + template + void draw_approximate_region(Halfedge_const_handle curr, const Approximate& approx) { + // std::cout << "draw_approximate_region()\n"; + std::vector polyline; + double error(0.01); // TODO? (this->pixel_ratio()); + bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT; + approx(curr->curve(), error, std::back_inserter(polyline), l2r); + if (polyline.empty()) return; + auto it = polyline.begin(); + auto prev = it++; + for (; it != polyline.end(); prev = it++) m_gs.add_point_in_face(*prev); + } - if(m_gso.colored_edge(m_aos, curr)) - { m_gs.add_segment(prev, next, m_gso.edge_color(m_aos, curr)); } - else - { m_gs.add_segment(prev, next); } + /*! draws an exact curve. + */ + template + void draw_exact_curve(const XMonotoneCurve& curve, bool colored, const CGAL::IO::Color& c) { + const auto* traits = this->m_aos.geometry_traits(); + auto ctr_min = traits->construct_min_vertex_2_object(); + auto ctr_max = traits->construct_max_vertex_2_object(); + m_gs.add_segment(ctr_min(curve), ctr_max(curve)); + if (colored) m_gs.add_segment(ctr_min(curve), ctr_max(curve), c); + else m_gs.add_segment(ctr_min(curve), ctr_max(curve)); + } - prev = next; - // m_gs.add_point_in_face(*prev); + /*! draws a region in an exact manner. + * This fallback simply draws the curve in an exact manner (and even this is not guaranteed). + */ + void draw_exact_region(Halfedge_const_handle curr) { draw_exact_curve(curr->curve(), false, CGAL::IO::Color()); } + + //! Add all faces. + template + void add_faces(const Traits&) + { for (auto it = m_aos.unbounded_faces_begin(); it != m_aos.unbounded_faces_end(); ++it) add_face(it); } + + //! Compile time dispatching + + /*! draws a point using approximate coordinates. + */ + template + void draw_approximate_point(const Point& p, const Approximate& approx, bool colored, const CGAL::IO::Color& color) { + if (colored) m_gs.add_point(approx(p), color); + else m_gs.add_point(approx(p)); + } + + //! + void draw_exact_point(const Point& p, bool colored, const CGAL::IO::Color& color) { + if (colored) m_gs.add_point(p, color); + else m_gs.add_point(p); + } + + //! + template , int> = 0> + void draw_point_impl2(const T& /* traits */, const A& /* approximate */, const Point& p, bool colored, + const CGAL::IO::Color& c) + { draw_exact_point(p, colored, c); } + + //! + template , int> = 0> + auto + draw_point_impl2(const T& /* traits */, const A& approx, const Point& p, bool colored, const CGAL::IO::Color& c) + { draw_approximate_point(p, approx, colored, c); } + + /*! draws a point, where the traits does not has approximate_2_object. + */ + template && !is_or_derived_from_agas_v, int> = 0> + void draw_point_impl1(const T& /* traits */, const Point& p, bool colored, const CGAL::IO::Color& c) + { draw_exact_point(p, colored, c); } + + /*! draws a point, where the traits does have approximate_2_object. + */ + template && !is_or_derived_from_agas_v, int> = 0> + auto draw_point_impl1(const T& traits, const Point& p, bool colored, const CGAL::IO::Color& c) + { draw_point_impl2(traits, traits.approximate_2_object(), p, colored, c); } + + /*! draws a geodesic point. + */ + template , int> = 0> + void draw_point_impl1(const T& traits, const Point& p, bool colored, const CGAL::IO::Color& color) { + using Traits = T; + using Ak = typename Traits::Approximate_kernel; + using Approx_point_3 = typename Ak::Point_3; + + auto approx = traits.approximate_2_object(); + auto ap = approx(p); + auto x = ap.dx(); + auto y = ap.dy(); + auto z = ap.dz(); + auto l = std::sqrt(x * x + y * y + z * z); + Approx_point_3 p3(x / l, y / l, z / l); + if (colored) m_gs.add_point(p3, color); + else m_gs.add_point(p3); + } + + //! draws a point. + void draw_point(const Point& p, bool colored, const CGAL::IO::Color& c) { + const auto* traits = m_aos.geometry_traits(); + draw_point_impl1(*traits, p, colored, c); + } + + /// + template + Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ, + Arr_geodesic_arc_on_sphere_traits_2 const&) + { return circ; } + + /*! finds the halfedge incident to the lexicographically smallest vertex + * along the CCB, such that there is no other halfedge underneath. + */ + template + Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ, const Traits&) { + // std::cout << "find_smallest()\n"; + const auto* traits = this->m_aos.geometry_traits(); + auto cmp_xy = traits->compare_xy_2_object(); + auto cmp_y = traits->compare_y_at_x_right_2_object(); + + // Find the first halfedge directed from left to right + auto curr = circ; + do if (curr->direction() == CGAL::ARR_LEFT_TO_RIGHT) break; + while(++curr != circ); + Halfedge_const_handle ext = curr; + + // Find the halfedge incident to the lexicographically smallest vertex, + // such that there is no other halfedge underneath. + do { + // Discard edges not directed from left to right: + if (curr->direction() != CGAL::ARR_LEFT_TO_RIGHT) continue; + + auto res = cmp_xy(curr->source()->point(), ext->source()->point()); + + // Discard the edges inciden to a point strictly larger than the point + // incident to the stored extreme halfedge: + if (res == LARGER) continue; + + // Store the edge inciden to a point strictly smaller: + if (res == SMALLER) { + ext = curr; + continue; } - } - /*! Draw a region using approximate coordinates. - * Call this member function only if the geometry traits is equipped with - * the coordinate-approximation functionality of a curve. - * This function must be inlined (e.g., a template) to enable the - * compiled-time dispatching in the function `draw_region()`. - */ - template - void draw_approximate_region(Halfedge_const_handle curr, - const Approximate& approx) - { - // std::cout << "draw_approximate_region()\n"; - std::vector polyline; - double error(0.01); // TODO? (this->pixel_ratio()); - bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT; - approx(curr->curve(), error, std::back_inserter(polyline), l2r); - if (polyline.empty()) return; - auto it = polyline.begin(); - auto prev = it++; - for (; it != polyline.end(); prev = it++) { - if(m_gso.draw_edge(m_aos, curr)) - { - if(m_gso.colored_edge(m_aos, curr)) - { m_gs.add_segment(*prev, *it, m_gso.edge_color(m_aos, curr)); } - else - { m_gs.add_segment(*prev, *it); } - } - m_gs.add_point_in_face(*prev); - } - } + // The incident points are equal; compare the halfedges themselves: + if (cmp_y(curr->curve(), ext->curve(), curr->source()->point()) == SMALLER) ext = curr; + } while(++curr != circ); - /// Draw an exact curve. - template - void draw_exact_curve(const XMonotoneCurve& curve) - { - const auto* traits = this->m_aos.geometry_traits(); - auto ctr_min = traits->construct_min_vertex_2_object(); - auto ctr_max = traits->construct_max_vertex_2_object(); - m_gs.add_segment(ctr_min(curve), ctr_max(curve)); - } + return ext; + } - /// Draw an exact region. - void draw_exact_region(Halfedge_const_handle curr) - { - // this->add_point_in_face(curr->source()->point()); - draw_exact_curve(curr->curve()); - } - - /// Add all faces. - template - void add_faces(const Traits&) - { - for (auto it=m_aos.unbounded_faces_begin(); it!=m_aos.unbounded_faces_end(); ++it) - { add_face(it); } - } - - /// Add all faces. - template - void add_faces(Arr_geodesic_arc_on_sphere_traits_2 const&) - { add_face(m_aos.faces_begin()); } - - /// Compile time dispatching -#if 0 - template - void draw_point_impl2(const Point& p, T const&, long) { m_gs.add_point(p); } - - template - auto draw_point_impl2(const Point& p, T const& approx, int) -> - decltype(approx.operator()(p), void()) - { m_gs.add_point(approx(p)); } - - template - void draw_point_impl1(const Point& p, T const&, long) { m_gs.add_point(p); } - - template - auto draw_point_impl1(const Point& p, T const& traits, int) -> - decltype(traits.approximate_2_object(), void()) { - using Approximate = typename Gt::Approximate_2; - draw_point_impl2(p, traits.approximate_2_object(), true); - } -#else - template - void draw_point_impl1(const Point& p, T const& traits, int, - bool colored, const CGAL::IO::Color& color) - { - if(colored) - { m_gs.add_point(traits.approximate_2_object()(p), color); } - else - { m_gs.add_point(traits.approximate_2_object()(p)); } - } -#endif - - template - void draw_point_impl1 - (const Point& p, - Arr_geodesic_arc_on_sphere_traits_2 const& traits, - int, - bool colored, - const CGAL::IO::Color& color) - { - auto approx = traits.approximate_2_object(); - using Traits = Arr_geodesic_arc_on_sphere_traits_2; - using Ak = typename Traits::Approximate_kernel; - using Approx_point_3 = typename Ak::Point_3; - auto ap = approx(p); - auto x = ap.dx(); - auto y = ap.dy(); - auto z = ap.dz(); - auto l = std::sqrt(x*x + y*y + z*z); - Approx_point_3 p3(x/l, y/l, z/l); - if(colored) - { m_gs.add_point(p3, color); } - else - { m_gs.add_point(p3); } - } - - /// Draw a point. - void draw_point(Vertex_const_handle vh) - { - const auto* traits = m_aos.geometry_traits(); - if(m_gso.draw_vertex(m_aos, vh)) - { - if(m_gso.colored_vertex(m_aos, vh)) - { draw_point_impl1(vh->point(), *traits, 0, true, - m_gso.vertex_color(m_aos, vh)); } - else - { draw_point_impl1(vh->point(), *traits, 0, false, CGAL::IO::Color()); } // color will be unused - } - } - - template - Halfedge_const_handle - find_smallest(Ccb_halfedge_const_circulator circ, - Arr_geodesic_arc_on_sphere_traits_2 const&) - { return circ; } - - /*! Find the halfedge incident to the lexicographically smallest vertex - * along the CCB, such that there is no other halfedge underneath. - */ - template - Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ, - const Traits&) - { - // std::cout << "find_smallest()\n"; - const auto* traits = this->m_aos.geometry_traits(); - auto cmp_xy = traits->compare_xy_2_object(); - auto cmp_y = traits->compare_y_at_x_right_2_object(); - - // Find the first halfedge directed from left to right - auto curr = circ; - do if (curr->direction() == CGAL::ARR_LEFT_TO_RIGHT) break; - while (++curr != circ); - Halfedge_const_handle ext = curr; - - // Find the halfedge incident to the lexicographically smallest vertex, - // such that there is no other halfedge underneath. - do { - // Discard edges not directed from left to right: - if (curr->direction() != CGAL::ARR_LEFT_TO_RIGHT) continue; - - auto res = cmp_xy(curr->source()->point(), ext->source()->point()); - - // Discard the edges inciden to a point strictly larger than the point - // incident to the stored extreme halfedge: - if (res == LARGER) continue; - - // Store the edge inciden to a point strictly smaller: - if (res == SMALLER) { - ext = curr; - continue; - } - - // The incident points are equal; compare the halfedges themselves: - if (cmp_y(curr->curve(), ext->curve(), curr->source()->point()) == - SMALLER) - ext = curr; - } while (++curr != circ); - - return ext; - } - - /// Add all elements to be drawn. - void add_elements() - { + //! adds all elements to be drawn. + void add_elements() { // std::cout << "add_elements()\n"; // std::cout << "ratio: " << this->pixel_ratio() << std::endl; m_visited.clear(); if (m_aos.is_empty()) return; - if(m_gso.are_faces_enabled()) - { add_faces(*(this->m_aos.geometry_traits())); } + if (m_gso.are_faces_enabled()) add_faces(*(this->m_aos.geometry_traits())); // Add edges that do not separate faces. - if(m_gso.are_edges_enabled()) - { - for (auto it = m_aos.edges_begin(); it != m_aos.edges_end(); ++it) - { if (it->face()==it->twin()->face()) - { - if(m_gso.draw_edge(m_aos, it)) - { - if(m_gso.colored_edge(m_aos, it)) - { draw_curve(it->curve(), true, m_gso.edge_color(m_aos, it)); } + if (m_gso.are_edges_enabled()) { + for (auto it = m_aos.edges_begin(); it != m_aos.edges_end(); ++it) { + if (it->face() != it->twin()->face()) { + if (m_gso.draw_edge(m_aos, it)) { + if (m_gso.colored_edge(m_aos, it)) + draw_curve(it->curve(), true, m_gso.edge_color(m_aos, it)); else - { draw_curve(it->curve(), false, CGAL::IO::Color()); } + draw_curve(it->curve(), false, CGAL::IO::Color()); } } } } // Add all points - if(m_gso.are_vertices_enabled()) - { - for (auto it = m_aos.vertices_begin(); it != m_aos.vertices_end(); ++it) - { draw_point(it); } + if (m_gso.are_vertices_enabled()) { + for (auto it = m_aos.vertices_begin(); it != m_aos.vertices_end(); ++it) { + if (m_gso.colored_vertex(m_aos, it)) + draw_point(it->point(), true, m_gso.vertex_color(m_aos, it)); + else + draw_point(it->point(), false, CGAL::IO::Color()); + } } m_visited.clear(); } - /*! Draw a curve using approximate coordinates. + /*! draws a curve using approximate coordinates. * Call this member function only of the geometry traits is equipped with * the coordinate-aproximation functionality of a curve. * This function must be inlined (e.g., a template) to enable the @@ -425,161 +365,443 @@ namespace draw_function_for_arrangement_2 template void draw_approximate_curve(const XMonotoneCurve& curve, const Approximate& approx, - bool colored, const CGAL::IO::Color& c) - { + bool colored, + const CGAL::IO::Color& c) { + // std::cout << "draw_approximate_curve\n"; std::vector polyline; double error(0.01); // TODO? (this->pixel_ratio()); approx(curve, error, std::back_inserter(polyline)); if (polyline.empty()) return; auto it = polyline.begin(); auto prev = it++; - for (; it != polyline.end(); prev = it++) - { - if(colored) - { m_gs.add_segment(*prev, *it, c); } - else - { m_gs.add_segment(*prev, *it); } + for (; it != polyline.end(); prev = it++) { + if (colored) m_gs.add_segment(*prev, *it, c); + else m_gs.add_segment(*prev, *it); } - } - /*! Compile time dispatching + /// + template , int> = 0> + void draw_curve_impl2(const T& /* traits */, + const A& /* approximate */, + const X_monotone_curve& xcv, + bool colored, + const CGAL::IO::Color& c) + { draw_exact_curve(xcv, colored, c); } + + /// + template , int> = 0> + auto draw_curve_impl2(const T& /* traits */, const A& approx, const X_monotone_curve& xcv, bool colored, + const CGAL::IO::Color& c) + { draw_approximate_curve(xcv, approx, colored, c); } + + /*! draws a curve, where the traits does not has approximate_2_object. */ -#if 0 - template - void draw_curve_impl2(const X_monotone_curve& xcv, T const&, long) - { draw_exact_curve(xcv); } + template && !is_or_derived_from_agas_v, int> = 0> + void draw_curve_impl1(const T& /* traits */, const X_monotone_curve& xcv, bool colored, const CGAL::IO::Color& c) + { draw_exact_curve(xcv, colored, c); } - template - auto draw_curve_impl2(const X_monotone_curve& xcv, T const& approx, int) -> - decltype(approx.template operator()(X_monotone_curve{}, double{}, I{}, - bool{}), void()) - { draw_approximate_curve(xcv, approx); } + /*! draws a curve, where the traits does have approximate_2_object. + */ + template && !is_or_derived_from_agas_v, int> = 0> + auto draw_curve_impl1(const T& traits, const X_monotone_curve& xcv, bool colored, const CGAL::IO::Color& c) + { draw_curve_impl2(traits, traits.approximate_2_object(), xcv, colored, c); } - template - void draw_curve_impl1(const X_monotone_curve& xcv, T const&, long) - { draw_exact_curve(xcv); } + /*! draws a geodesic curve + */ + template , int> = 0> + void draw_curve_impl1(const T& traits, const X_monotone_curve& xcv, bool colored, const CGAL::IO::Color& c) { + // std::cout << "draw_curve (geodesic)\n"; + using Traits = T; + using Ak = typename Traits::Approximate_kernel; + using Ap = typename Traits::Approximate_point_2; + using Approx_point_3 = typename Ak::Point_3; - template - auto draw_curve_impl1(const X_monotone_curve& xcv, T const& traits, int) -> - decltype(traits.approximate_2_object(), void()) { - using Approximate = typename Gt::Approximate_2; - draw_curve_impl2(xcv, traits.approximate_2_object(), 0); - } -#else - template - void draw_curve_impl1(const X_monotone_curve& xcv, T const& traits, int, - bool colored, const CGAL::IO::Color& c) - { draw_approximate_curve(xcv, traits.approximate_2_object(), colored, c); } -#endif - - template - void draw_curve_impl1 - (const X_monotone_curve& xcv, - Arr_geodesic_arc_on_sphere_traits_2 const& traits, - int, - bool colored, const CGAL::IO::Color& c) - { - auto approx = traits.approximate_2_object(); - using Kernel = Kernel_; - using Traits = Arr_geodesic_arc_on_sphere_traits_2; - using Ak = typename Traits::Approximate_kernel; - using Ap = typename Traits::Approximate_point_2; - using Approx_point_3 = typename Ak::Point_3; - std::vector apoints; - double error(0.01); - approx(xcv, error, std::back_inserter(apoints)); - auto it = apoints.begin(); + auto approx = traits.approximate_2_object(); + std::vector apoints; + double error(0.01); + approx(xcv, error, std::back_inserter(apoints)); + auto it = apoints.begin(); + auto x = it->dx(); + auto y = it->dy(); + auto z = it->dz(); + auto l = std::sqrt(x * x + y * y + z * z); + Approx_point_3 prev(x / l, y / l, z / l); + for (++it; it != apoints.end(); ++it) { auto x = it->dx(); auto y = it->dy(); auto z = it->dz(); - auto l = std::sqrt(x*x + y*y + z*z); - Approx_point_3 prev(x/l, y/l, z/l); - for (++it; it != apoints.end(); ++it) { - auto x = it->dx(); - auto y = it->dy(); - auto z = it->dz(); - auto l = std::sqrt(x*x + y*y + z*z); - Approx_point_3 next(x/l, y/l, z/l); - if(colored) - { m_gs.add_segment(prev, next, c); } - else - { m_gs.add_segment(prev, next); } - prev = next; - } + auto l = std::sqrt(x * x + y * y + z * z); + Approx_point_3 next(x / l, y / l, z / l); + if (colored) m_gs.add_segment(prev, next, c); + else m_gs.add_segment(prev, next); + prev = next; } + } - /// Draw a curve. - template - void draw_curve(const XMonotoneCurve& curve, - bool colored, const CGAL::IO::Color& c) - { - /* Check whether the traits has a member function called - * approximate_2_object() and if so check whether the return type, namely - * `Approximate_2` has an appropriate operator. - * - * C++20 supports concepts and `requires` expression; see, e.g., - * https://en.cppreference.com/w/cpp/language/constraints; thus, the first - * condition above can be elegantly verified as follows: - * constexpr bool has_approximate_2_object = - * requires(const Gt& traits) { traits.approximate_2_object(); }; - * - * C++17 has experimental constructs called is_detected and - * is_detected_v that can be used to achieve the same goal. - * - * For now we use C++14 features. - */ + //! draws a curve. + template + void draw_curve(const XMonotoneCurve& curve, bool colored, const CGAL::IO::Color& c) { + /* Check whether the traits has a member function called + * approximate_2_object() and if so check whether the return type, namely + * `Approximate_2` has an appropriate operator. + * + * C++20 supports concepts and `requires` expression; see, e.g., + * https://en.cppreference.com/w/cpp/language/constraints; thus, the first + * condition above can be elegantly verified as follows: + * constexpr bool has_approximate_2_object = + * requires(const Gt& traits) { traits.approximate_2_object(); }; + * + * C++17 has experimental constructs called is_detected and + * is_detected_v that can be used to achieve the same goal. + * + * For now we use C++14 features. + */ #if 0 - if constexpr (std::experimental::is_detected_v) - { - const auto* traits = this->m_aos.geometry_traits(); - auto approx = traits->approximate_2_object(); - draw_approximate_curve(curve, approx); - return; - } - draw_exact_curve(curve); -#else + if constexpr (std::experimental::is_detected_v) { const auto* traits = this->m_aos.geometry_traits(); - draw_curve_impl1(curve, *traits, 0, colored, c); -#endif + auto approx = traits->approximate_2_object(); + draw_approximate_curve(curve, approx); + return; } + draw_exact_curve(curve); +#else + const auto* traits = this->m_aos.geometry_traits(); + draw_curve_impl1(*traits, curve, colored, c); +#endif + } - protected: - Arr& m_aos; - CGAL::Graphics_scene& m_gs; - const GSOptions& m_gso; - std::unordered_map m_visited; +protected: + Arr& m_aos; + CGAL::Graphics_scene& m_gs; + const GSOptions& m_gso; + std::unordered_map m_visited; +}; + +template +static auto map_from_pair_ranges(Range1 range1, Range2 range2) { + CGAL_assertion_msg(range1.size() == range2.size(), "The two ranges must have the same size."); + auto begin = boost::make_zip_iterator(boost::make_tuple(range1.begin(), range2.begin())); + auto end = boost::make_zip_iterator(boost::make_tuple(range1.end(), range2.end())); + auto tuple_to_pair = [](const auto& t) { return std::make_pair(boost::get<0>(t), boost::get<1>(t)); }; + return unordered_flat_map(boost::make_transform_iterator(begin, tuple_to_pair), + boost::make_transform_iterator(end, tuple_to_pair)); +} + +/*! Tracking changes between an arrangement and its copy that will be later inserted to. + * + * \note tracks insertions only. If any other actions made(e.g. deletions, merging, etc), the state of the tracker + * instance may become invalid. + * + * \tparam Arrangement + */ +template +class Arr_insertion_tracker : Arr_observer { + using Base = Arr_observer; + using Halfedge_handle = typename Arrangement::Halfedge_handle; + using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle; + using Face_handle = typename Arrangement::Face_handle; + using Face_const_handle = typename Arrangement::Face_const_handle; + using Vertex_handle = typename Arrangement::Vertex_handle; + using Vertex_const_handle = typename Arrangement::Vertex_const_handle; + using X_monotone_curve_2 = typename Arrangement::X_monotone_curve_2; + +protected: + virtual void after_create_vertex(Vertex_handle v) override { m_vertex_map[v] = Vertex_const_handle(); } + + virtual void after_create_edge(Halfedge_handle e) override { + m_halfedge_map[e] = Halfedge_const_handle(); + m_halfedge_map[e->twin()] = Halfedge_const_handle(); // twin is created as well + } + + virtual void before_split_edge(Halfedge_handle /* e */, Vertex_handle v, + const X_monotone_curve_2& /* c1 */, + const X_monotone_curve_2& /* c2 */) override + { if (m_vertex_map.find(v) == m_vertex_map.end()) m_vertex_map[v] = Vertex_const_handle(); } + + virtual void after_split_edge(Halfedge_handle e1, Halfedge_handle e2) override { + if (auto it = m_halfedge_map.find(e1); it == m_halfedge_map.end()) + m_halfedge_map[e2] = e1; + else if (it->second == Halfedge_const_handle()) + m_halfedge_map[e2] = Halfedge_const_handle(); // e1 has no corresponding edge in the original arrangement + else + m_halfedge_map[e2] = it->second; // e1 is created by splitting an existing edge + } + + virtual void after_split_face(Face_handle f1, Face_handle f2, bool) override { + // Face cannot be created but by splitting an existing face. + if (auto it = m_face_map.find(f1); it == m_face_map.end()) + m_face_map[f2] = f1; + else + m_face_map[f2] = it->second; // f1 is created by splitting an existing face + } + +public: + Arr_insertion_tracker(Arrangement& arr) : Base(arr) {} + + /*! queries the original face of a given face. + * + * \param fh a valid face handle in the modified arrangement. + * \return Face_const_handle + */ + Face_const_handle original_face(Face_const_handle fh) const { + auto it = m_face_map.find(fh); + if (it == m_face_map.end()) return fh; + return it->second; // new face from splitting an existing face + } + + /*! queries the original halfedge of a given halfedge. + * + * \param heh a valid halfedge handle in the modified arrangement. + * \return Halfedge_const_handle + */ + Halfedge_const_handle original_halfedge(Halfedge_const_handle he) const { + auto it = m_halfedge_map.find(he); + if (it == m_halfedge_map.end()) return he; + if (it->second == Halfedge_const_handle()) return Halfedge_const_handle(); // newly created halfedge + return it->second; + } + + /*! queries the original vertex of a given vertex. + * + * \param vh a valid vertex handle in the modified arrangement. + * \return Vertex_const_handle + */ + Vertex_const_handle original_vertex(Vertex_const_handle vh) const { + auto it = m_vertex_map.find(vh); + if (it == m_vertex_map.end()) return vh; + if (it->second == Vertex_const_handle()) return Vertex_const_handle(); // newly created vertex + return it->second; // it will never reach here. + } + +private: + /*! maps tracking the changes between the original arrangement and modified arrangement. + * The key is the current feature, and the value is the corresponding feature before modification. + * If there is no entry about a feature, the corresponding feature is itself. + * If the value is a invalid handle, it means that the feature is newly created and thus has no corresponding + * feature in the original arrangement. + */ + unordered_flat_map m_face_map; + unordered_flat_map m_halfedge_map; + unordered_flat_map m_vertex_map; +}; + +#ifdef CGAL_USE_BASIC_VIEWER +//! +void draw_unimplemented() { + CGAL_error_msg("Geometry traits type of arrangement is required to support approximation of Point_2 and " + "X_monotone_curve_2. Traits on curved surfaces needs additional support for parameterization."); +} + +//! +template +void draw_impl_planar(const Arrangement& arr, const GSOptions& gso, const char* title, Bbox_2 initial_bbox, + QApplication& app) { + Arr_viewer viewer(app.activeWindow(), arr, gso, title, initial_bbox); + viewer.show(); + app.exec(); +} + +//! +template +void draw_impl_agas(const Arrangement& arr, const GSOptions& gso, + const char* title, Bbox_2 initial_bbox, QApplication& app) { + using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle; + using Face_const_handle = typename Arrangement::Face_const_handle; + using Vertex_const_handle = typename Arrangement::Vertex_const_handle; + using Geom_traits = typename Arrangement::Geometry_traits_2; + using Direction_3 = typename Geom_traits::Direction_3; + using Point_2 = typename Geom_traits::Point_2; + using Agas_template_args = tmpl_args; + + Arrangement derived_arr(arr); + auto vertex_map = map_from_pair_ranges(derived_arr.vertex_handles(), + arr.vertex_handles()); + auto halfedge_map = map_from_pair_ranges(derived_arr.halfedge_handles(), + arr.halfedge_handles()); + auto face_map = map_from_pair_ranges(derived_arr.face_handles(), + arr.face_handles()); + // setup tracker and insert the identification curve. + Arr_insertion_tracker tracker(derived_arr); + Point_2 src(Direction_3(0, 0, -1), Point_2::MIN_BOUNDARY_LOC); + Point_2 trg(Direction_3(0, 0, 1), Point_2::MAX_BOUNDARY_LOC); + auto ctr_xcv = arr.geometry_traits()->construct_x_monotone_curve_2_object(); + auto id_curve = ctr_xcv(src, trg, Direction_3(Agas_template_args::atan_y, -Agas_template_args::atan_x, 0)); + insert(derived_arr, id_curve); + + // derived_gso proxies the call to the original gso + GSOptions derived_gso(gso); + derived_gso.draw_vertex = [&](const Arrangement&, const Vertex_const_handle& vh) { + Vertex_const_handle original_vh = tracker.original_vertex(vh); + if (original_vh == Vertex_const_handle() || vertex_map.find(original_vh) == vertex_map.end()) return false; + return gso.draw_vertex(arr, vertex_map.at(original_vh)); + }; + derived_gso.colored_vertex = [&](const Arrangement&, const Vertex_const_handle& vh) { + Vertex_const_handle original_vh = tracker.original_vertex(vh); + if (original_vh == Vertex_const_handle() || vertex_map.find(original_vh) == vertex_map.end()) return false; + return gso.colored_vertex(arr, vertex_map.at(original_vh)); + }; + derived_gso.vertex_color = [&](const Arrangement&, const Vertex_const_handle& vh) -> CGAL::IO::Color { + Vertex_const_handle original_vh = tracker.original_vertex(vh); + if (original_vh == Vertex_const_handle() || vertex_map.find(original_vh) == vertex_map.end()) + return CGAL::IO::Color(); + return gso.vertex_color(arr, vertex_map.at(original_vh)); + }; + derived_gso.draw_edge = [&](const Arrangement&, const Halfedge_const_handle& he) { + Halfedge_const_handle original_he = tracker.original_halfedge(he); + if (original_he == Halfedge_const_handle() || halfedge_map.find(original_he) == halfedge_map.end()) return false; + return gso.draw_edge(arr, halfedge_map.at(original_he)); + }; + derived_gso.colored_edge = [&](const Arrangement&, const Halfedge_const_handle& he) { + Halfedge_const_handle original_he = tracker.original_halfedge(he); + if (original_he == Halfedge_const_handle() || halfedge_map.find(original_he) == halfedge_map.end()) return false; + return gso.colored_edge(arr, halfedge_map.at(original_he)); + }; + derived_gso.edge_color = [&](const Arrangement&, const Halfedge_const_handle& he) -> CGAL::IO::Color { + Halfedge_const_handle original_he = tracker.original_halfedge(he); + if (original_he == Halfedge_const_handle() || halfedge_map.find(original_he) == halfedge_map.end()) + return CGAL::IO::Color(); + return gso.edge_color(arr, halfedge_map.at(original_he)); + }; + derived_gso.draw_face = [&](const Arrangement&, const Face_const_handle& fh) { + Face_const_handle original_fh = tracker.original_face(fh); + if (face_map.find(original_fh) == face_map.end()) return false; + return gso.draw_face(arr, face_map.at(original_fh)); + }; + derived_gso.colored_face = [&](const Arrangement&, const Face_const_handle& fh) { + Face_const_handle original_fh = tracker.original_face(fh); + if (face_map.find(original_fh) == face_map.end()) return false; + return gso.draw_face(arr, face_map.at(original_fh)); + }; + derived_gso.face_color = [&](const Arrangement&, const Face_const_handle& fh) -> CGAL::IO::Color { + Face_const_handle original_fh = tracker.original_face(fh); + if (face_map.find(original_fh) == face_map.end()) return CGAL::IO::Color(); + return gso.face_color(arr, face_map.at(original_fh)); }; -} // namespace draw_function_for_arrangement_2 + Arr_viewer viewer(app.activeWindow(), derived_arr, derived_gso, title, initial_bbox); + viewer.show(); + app.exec(); +} + +//! +template +void draw(const Arrangement& arr, const GSOptions& gso, Args&&... args) { + using Geom_traits = typename Arrangement::Geometry_traits_2; + + if constexpr(!has_approximate_traits_v) + return draw_unimplemented(); + else if constexpr(is_or_derived_from_agas_v) + // Arrangements on curved surfaces require special handling. The identification curve must be present to make the + // curved surface homeomorphic to a bounded plane. + return draw_impl_agas(arr, gso, std::forward(args)...); + else + return draw_impl_planar(arr, gso, std::forward(args)...); +} +#endif + +} // namespace draw_aos + +/*! draws an arrangement on surface. + * + * \tparam Arrangement + * \tparam GSOptions + * \param arr the arrangement to be drawn + * \param gso graphics scene options + * \param title title of the viewer window + * \param initial_bbox parameter space bounding box to be shown initially. If empty, the approximate bounding box of the + * arrangement is used. For arrangements induced by unbounded curves, the default initial bounding box is computed from + * vertex coordinates. + */ +template +void draw(const Arrangement& arr, + const GSOptions& gso, + const char* title = "2D Arrangement on Surface Viewer", + Bbox_2 initial_bbox = Bbox_2(0, 0, 0, 0)) { + CGAL_USE(arr); + CGAL_USE(gso); + CGAL_USE(title); + CGAL_USE(initial_bbox); + +#ifdef CGAL_USE_BASIC_VIEWER +#if defined(CGAL_TEST_SUITE) + bool cgal_test_suite = true; +#else + bool cgal_test_suite = qEnvironmentVariableIsSet("CGAL_TEST_SUITE"); +#endif + + if (cgal_test_suite) return; + + Qt::init_ogl_context(4, 3); + int argc; + QApplication app(argc, nullptr); + draw_aos::draw(arr, gso, title, initial_bbox, app); +#endif +} + +/*! draws an arrangement on surface with default graphics scene options. Faces are colored randomly. + * + * \tparam Arrangement + * \param arr the arrangement to be drawn + * \param title title of the viewer window + * \param initial_bbox parameter space bounding box to be shown initially. If empty, the approximate bounding box of the + * arrangement is used. For arrangements induced by unbounded curves, the default initial bounding box is computed from + * vertex coordinates. + */ +template +void draw(const Arrangement& arr, + const char* title = "2D Arrangement on Surface Viewer", + Bbox_2 initial_bbox = Bbox_2(0, 0, 0, 0)) { + using Face_const_handle = typename Arrangement::Face_const_handle; + using Vertex_const_handle = typename Arrangement::Vertex_const_handle; + using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle; + using GSOptions = + CGAL::Graphics_scene_options; + + GSOptions gso; + gso.enable_vertices(); + gso.draw_vertex = [](const Arrangement&, const Vertex_const_handle&) { return true; }; + gso.colored_vertex = [](const Arrangement&, const Vertex_const_handle&) { return true; }; + gso.vertex_color = [](const Arrangement&, const Vertex_const_handle& /* vh */) -> CGAL::IO::Color + { return CGAL::IO::Color(255, 0, 0); }; + + gso.enable_edges(); + gso.draw_edge = [](const Arrangement&, const Halfedge_const_handle&) { return true; }; + gso.colored_edge = [](const Arrangement&, const Halfedge_const_handle&) { return true; }; + gso.edge_color = [](const Arrangement&, const Halfedge_const_handle& /* heh */) -> CGAL::IO::Color + { return CGAL::IO::Color(0, 0, 0); }; + + gso.enable_faces(); + gso.draw_face = [](const Arrangement&, const Face_const_handle&) { return true; }; + gso.colored_face = [](const Arrangement&, const Face_const_handle&) { return true; }; + gso.face_color = [](const Arrangement&, const Face_const_handle& fh) -> CGAL::IO::Color { + CGAL::Random random(std::size_t(fh.ptr())); + return get_random_color(random); + }; + + draw(arr, gso, title, initial_bbox); +} #define CGAL_ARR_TYPE CGAL::Arrangement_on_surface_2 +/// template -void add_to_graphics_scene(const CGAL_ARR_TYPE& aos, - CGAL::Graphics_scene& graphics_scene, - const GSOptions& gso) -{ - draw_function_for_arrangement_2::Draw_arr_tool dar(aos, graphics_scene, gso); +void add_to_graphics_scene(const CGAL_ARR_TYPE& aos, CGAL::Graphics_scene& graphics_scene, const GSOptions& gso) { + draw_aos::Draw_arr_tool dar(aos, graphics_scene, gso); dar.add_elements(); } +/// template -void add_to_graphics_scene(const CGAL_ARR_TYPE& aos, - CGAL::Graphics_scene& graphics_scene) -{ - CGAL::Graphics_scene_options - gso; - gso.colored_face=[](const CGAL_ARR_TYPE&, - typename CGAL_ARR_TYPE::Face_const_handle) -> bool - { return true; }; + typename CGAL_ARR_TYPE::Face_const_handle> gso; + // colored face? + gso.colored_face = [](const CGAL_ARR_TYPE&, typename CGAL_ARR_TYPE::Face_const_handle) -> bool { return true; }; - gso.face_color=[](const CGAL_ARR_TYPE&, - typename CGAL_ARR_TYPE::Face_const_handle fh) -> CGAL::IO::Color - { + // face color + gso.face_color = [](const CGAL_ARR_TYPE&, typename CGAL_ARR_TYPE::Face_const_handle fh) -> CGAL::IO::Color { CGAL::Random random((unsigned int)(std::size_t)(&*fh)); return get_random_color(random); }; @@ -587,28 +809,24 @@ void add_to_graphics_scene(const CGAL_ARR_TYPE& aos, add_to_graphics_scene(aos, graphics_scene, gso); } -/// Draw an arrangement on surface. +//! draws an arrangement on surface. template -void draw(const CGAL_ARR_TYPE& aos, const GSOptions& gso, - const char* title = "2D Arrangement on Surface Basic Viewer") -{ +void draw_old(const CGAL_ARR_TYPE& aos, + const GSOptions& gso, + const char* title = "2D Arrangement on Surface Basic Viewer") { CGAL::Graphics_scene graphics_scene; add_to_graphics_scene(aos, graphics_scene, gso); draw_graphics_scene(graphics_scene, title); - } +//! draws an arrangement on surface. template -void draw(const CGAL_ARR_TYPE& aos, - const char* title = "2D Arrangement on Surface Basic Viewer") -{ +void draw_old(const CGAL_ARR_TYPE& aos, const char* title = "2D Arrangement on Surface Basic Viewer") { CGAL::Graphics_scene graphics_scene; add_to_graphics_scene(aos, graphics_scene); draw_graphics_scene(graphics_scene, title); } -#undef CGAL_ARR_TYPE - } // namespace CGAL #endif diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test.cmake b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test.cmake index fef22ea95c5..4b7b99f25e7 100644 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test.cmake +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test.cmake @@ -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() \ No newline at end of file diff --git a/BGL/doc/BGL/BGL.txt b/BGL/doc/BGL/BGL.txt index f20f60bf20d..0655164a7ec 100644 --- a/BGL/doc/BGL/BGL.txt +++ b/BGL/doc/BGL/BGL.txt @@ -87,9 +87,9 @@ boost::graph_traits::edge_iterator ei; Algorithms obtain incidence information in graphs with the help of global functions such as: -- `std::pair vertices(const Graph& g);` to obtain an iterator range providing access to all the vertices, or -- `vertices_size_type num_vertices(const Graph&);` to obtain the number of vertices of a graph, or -- `vertex_descriptor source(edge_descriptor, const Graph&);` to obtain the source vertex of an edge. +- \ref VertexListGraph::vertices(const VertexListGraph&) "std::pair vertices(const Graph& g)" to obtain an iterator range providing access to all the vertices, or +- \link VertexListGraph::num_vertices(const VertexListGraph&) `vertices_size_type num_vertices(const Graph&)`\endlink to obtain the number of vertices of a graph, or +- \link IncidenceGraph `vertex_descriptor source(edge_descriptor, const Graph&)` \endlink to obtain the source vertex of an edge. Note, that the way we have written the types is a simplification; in reality, the signature of the first of the above functions is: diff --git a/BGL/doc/BGL/NamedParameters.txt b/BGL/doc/BGL/NamedParameters.txt index 8fad0e16910..d19023924bf 100644 --- a/BGL/doc/BGL/NamedParameters.txt +++ b/BGL/doc/BGL/NamedParameters.txt @@ -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); diff --git a/BGL/include/CGAL/boost/graph/Euler_operations.h b/BGL/include/CGAL/boost/graph/Euler_operations.h index ece862d5dc7..998ba506857 100644 --- a/BGL/include/CGAL/boost/graph/Euler_operations.h +++ b/BGL/include/CGAL/boost/graph/Euler_operations.h @@ -585,8 +585,11 @@ add_edge(typename boost::graph_traits::vertex_descriptor s, * checks whether a new face defined by a range of vertices (identified by their descriptors, * `boost::graph_traits::%vertex_descriptor`) can be added. */ -template -bool can_add_face(const VertexRange& vrange, const PMesh& sm) +template +bool can_add_face(const VertexRange& vrange, + const PMesh& sm, + const bool verbose = false) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; @@ -603,10 +606,16 @@ bool can_add_face(const VertexRange& vrange, const PMesh& sm) typename std::vector::iterator it = std::unique(f2.begin(),f2.end()); if((N > 0) && (it != f2.end())){ + if (verbose){ + std::cerr << "Cannot add face: face contains duplicate vertices." << std::endl; + } return false; } if(N < 3){ + if (verbose){ + std::cerr << "Cannot add face: face must contain at least 3 vertices." << std::endl; + } return false; } @@ -617,6 +626,9 @@ bool can_add_face(const VertexRange& vrange, const PMesh& sm) bool found; std::tie(hd,found) = halfedge(face[i],face[i+1],sm); if(found && (! is_border(hd,sm))){ + if (verbose){ + std::cerr << "Cannot add face: face contains an edge that is not a border halfedge." << std::endl; + } return false; } } @@ -627,6 +639,9 @@ bool can_add_face(const VertexRange& vrange, const PMesh& sm) } if(! is_border(face[i],sm)){ + if (verbose){ + std::cerr << "Cannot add face: face contains a vertex that is not a border vertex." << std::endl; + } return false; } } @@ -648,8 +663,9 @@ bool can_add_face(const VertexRange& vrange, const PMesh& sm) if ( halfedge_around_vertex == boost::graph_traits::null_halfedge() || halfedge(previous_vertex,sm) == boost::graph_traits::null_halfedge()|| - halfedge(next_vertex,sm) == boost::graph_traits::null_halfedge() - ) continue; + halfedge(next_vertex,sm) == boost::graph_traits::null_halfedge() ) { + continue; + } halfedge_descriptor start=halfedge_around_vertex; //halfedges pointing to/running out from vertex indices[i] @@ -694,7 +710,12 @@ bool can_add_face(const VertexRange& vrange, const PMesh& sm) if ( is_border(opposite(halfedge_around_vertex,sm),sm) ) break; } while (halfedge_around_vertex != prev_hd); - if (halfedge_around_vertex == prev_hd) return false; + if (halfedge_around_vertex == prev_hd) { + if (verbose){ + std::cerr << "Cannot add face: halfedge_around_vertex == prev_hd" << std::endl; + } + return false; + } start = halfedge_around_vertex; } } @@ -703,7 +724,6 @@ bool can_add_face(const VertexRange& vrange, const PMesh& sm) } - /** * adds a new face defined by a range of vertices (identified by their descriptors, * `boost::graph_traits::%vertex_descriptor`). @@ -1552,7 +1572,7 @@ does_satisfy_link_condition(typename boost::graph_traits::edge_descriptor * * \returns vertex `v1`. * \pre g must be a triangulated graph - * \pre `does_satisfy_link_condition(e,g) == true`. + * \pre \link CGAL::Euler::does_satisfy_link_condition `does_satisfy_link_condition`\endlink(e,g) == `true`. */ template typename boost::graph_traits::vertex_descriptor @@ -1670,7 +1690,7 @@ collapse_edge(typename boost::graph_traits::edge_descriptor e, * \returns vertex `v1`. * \pre This function requires `g` to be an oriented 2-manifold with or without boundaries. * Furthermore, the edge `v0v1` must satisfy the link condition, which guarantees that the surface mesh is also 2-manifold after the edge collapse. - * \pre `get(edge_is_constrained_map, v0v1)==false`. + * \pre `get(edge_is_constrained_map, v0v1) == false`. * \pre `v0` and `v1` are not both incident to a constrained edge. */ @@ -1876,7 +1896,7 @@ bool satisfies_link_condition(typename boost::graph_traits::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`. * diff --git a/BGL/include/CGAL/boost/graph/IO/Generic_facegraph_builder.h b/BGL/include/CGAL/boost/graph/IO/Generic_facegraph_builder.h index 1dd6235a28c..cd26453f27c 100644 --- a/BGL/include/CGAL/boost/graph/IO/Generic_facegraph_builder.h +++ b/BGL/include/CGAL/boost/graph/IO/Generic_facegraph_builder.h @@ -144,8 +144,16 @@ public: face[j] = vertices[m_faces[i][j]]; face_descriptor f = CGAL::Euler::add_face(face, g); - if(f == boost::graph_traits::null_face()) + if(f == boost::graph_traits::null_face()) { + if (verbose) { + std::cerr << "Error: Failed to add face [" << i << "]\n"; + std::cerr << "Diagnostic:" << std::endl; + CGAL_assertion_code(bool cannot_add = ) + CGAL::Euler::can_add_face(face, g, true /*verbose*/); + CGAL_assertion(!cannot_add); + } return false; + } if(has_face_colors) put(fcm, f, face_colors[i]); diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index 26b358b3561..45b52e8699a 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -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)); diff --git a/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/triangle_coordinates_2.h b/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/triangle_coordinates_2.h index bc681d3bf38..5dd40f19b0b 100644 --- a/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/triangle_coordinates_2.h +++ b/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/triangle_coordinates_2.h @@ -64,7 +64,7 @@ namespace Barycentric_coordinates { \return an output iterator to the element in the destination range, one past the last coordinate stored - \pre area_2(p0, p1, p2) != 0 + \pre \link BarycentricTraits_2::Compute_area_2 `area_2`\endlink(p0, p1, p2) != 0 */ template< typename OutIterator, @@ -133,7 +133,7 @@ namespace Barycentric_coordinates { \return a tuple `std::tuple` with the computed coordinates - \pre area_2(p0, p1, p2) != 0 + \pre \link BarycentricTraits_2::Compute_area_2 `area_2`\endlink(p0, p1, p2) != 0 */ template std::tuple< diff --git a/Basic_viewer/include/CGAL/Qt/Basic_viewer.h b/Basic_viewer/include/CGAL/Qt/Basic_viewer.h index b26ecdd479b..d7e3dcd48cc 100644 --- a/Basic_viewer/include/CGAL/Qt/Basic_viewer.h +++ b/Basic_viewer/include/CGAL/Qt/Basic_viewer.h @@ -1480,10 +1480,15 @@ protected: if(!m_scene.empty()) { auto& bbox=m_scene.bounding_box(); - double d=CGAL::sqrt(CGAL::squared_distance - (Local_point(bbox.xmin(), bbox.ymin(), bbox.zmin()), - Local_point(bbox.xmax(), bbox.ymax(), bbox.zmax()))); + double d=is_two_dimensional() + ?2.5 + : CGAL::sqrt(CGAL::squared_distance + (Local_point(bbox.xmin(), bbox.ymin(), bbox.zmin()), + Local_point(bbox.xmax(), bbox.ymax(), bbox.zmax()))); // std::cout<<"Length of the diagonal: "<width() <height() < 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 Outer_ccb_and_face; diff --git a/Bounding_volumes/include/CGAL/pierce_rectangles_2.h b/Bounding_volumes/include/CGAL/pierce_rectangles_2.h index f33964389da..d122ae70361 100644 --- a/Bounding_volumes/include/CGAL/pierce_rectangles_2.h +++ b/Bounding_volumes/include/CGAL/pierce_rectangles_2.h @@ -892,8 +892,8 @@ four_cover_points(Staircases< Traits >& d, OutputIterator o, bool& ok) sdistx(*(shf - 1), bottom) <= FT(2) * d.r)))) #else if (sdistx(bottom_i.second, bottom) <= FT(2) * d.r && - ((!d.is_x_greater_y() || - (shl == Citerator(share.end()) || + (!d.is_x_greater_y() || + ((shl == Citerator(share.end()) || sdistx(share.back(), bottom) <= FT(2) * d.r) && (shf == Citerator(share.begin()) || sdistx(*(shf - 1), bottom) <= FT(2) * d.r)))) diff --git a/CGAL_ipelets/doc/CGAL_ipelets/CGAL_ipelets.txt b/CGAL_ipelets/doc/CGAL_ipelets/CGAL_ipelets.txt index 3025dc11155..ebf86250765 100644 --- a/CGAL_ipelets/doc/CGAL_ipelets/CGAL_ipelets.txt +++ b/CGAL_ipelets/doc/CGAL_ipelets/CGAL_ipelets.txt @@ -116,13 +116,13 @@ Draws a theta-graph with k cones
  • Yao-k-graph: Draws a Yao-graph with k cones
  • Half-theta-k-graph with even cones: -Draws an half-theta-graph with the even of k cones. +Draws a half-theta-graph with the even of k cones.
  • Half-Yao-k-graph with even cones: -Draws an half-Yao-graph with the even of k cones. +Draws a half-Yao-graph with the even of k cones.
  • Half-theta-k-graph with odd cones: -Draws an half-theta-graph with the odd of k cones. +Draws a half-theta-graph with the odd of k cones.
  • Half-Yao-k-graph with odd cones: -Draws an half-Yao-graph with the odd of k cones. +Draws a half-Yao-graph with the odd of k cones.
  • k cones: For each selected point. Draws the k cones around the point. diff --git a/Circular_kernel_2/include/CGAL/Circular_kernel_intersections.h b/Circular_kernel_2/include/CGAL/Circular_kernel_intersections.h index ae9453be1c0..02cf1d24709 100644 --- a/Circular_kernel_2/include/CGAL/Circular_kernel_intersections.h +++ b/Circular_kernel_2/include/CGAL/Circular_kernel_intersections.h @@ -92,17 +92,17 @@ intersection(const Line_2 &c1, const Line_2 &c2, OutputIterator res) CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circular_arc_2, Circular_arc_2) CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_arc_2, Line_arc_2) -CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_arc_2, Circle_2) -CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circle_2, Line_arc_2) + CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circular_arc_2, Circle_2) CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circle_2, Circular_arc_2) -CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_arc_2, Circular_arc_2) -CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circular_arc_2, Line_arc_2) CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_2, Circular_arc_2) -CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_2, Line_arc_2) CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circular_arc_2, Line_2) +CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circular_arc_2, Line_arc_2) +CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_arc_2, Circular_arc_2) +CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_arc_2, Circle_2) +CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Circle_2, Line_arc_2) CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_arc_2, Line_2) - +CGAL_CIRCULAR_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_(Line_2, Line_arc_2) } //namespace CGAL diff --git a/Circular_kernel_3/include/CGAL/Circular_kernel_3/Intersection_traits.h b/Circular_kernel_3/include/CGAL/Circular_kernel_3/Intersection_traits.h index ed6ac62628f..f932d8b9aa0 100644 --- a/Circular_kernel_3/include/CGAL/Circular_kernel_3/Intersection_traits.h +++ b/Circular_kernel_3/include/CGAL/Circular_kernel_3/Intersection_traits.h @@ -156,6 +156,10 @@ template struct SK3_Intersection_traits : SK3_intersect_ternary {}; +template +struct SK3_Intersection_traits + : SK3_intersect_ternary {}; + template struct SK3_Intersection_traits : SK3_intersect_ternary {}; @@ -164,6 +168,10 @@ template struct SK3_Intersection_traits : SK3_intersect_ternary {}; +template +struct SK3_Intersection_traits + : SK3_intersect_ternary {}; + template struct SK3_Intersection_traits : SK3_intersect_ternary {}; diff --git a/Circular_kernel_3/include/CGAL/Circular_kernel_3/function_objects_polynomial_sphere.h b/Circular_kernel_3/include/CGAL/Circular_kernel_3/function_objects_polynomial_sphere.h index c2940aa42d7..8664f3abe5c 100644 --- a/Circular_kernel_3/include/CGAL/Circular_kernel_3/function_objects_polynomial_sphere.h +++ b/Circular_kernel_3/include/CGAL/Circular_kernel_3/function_objects_polynomial_sphere.h @@ -935,8 +935,10 @@ template < class SK > \ CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_2(Line_3, Sphere_3) CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Sphere_3, Sphere_3, Sphere_3) CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Sphere_3, Sphere_3, Plane_3) + CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Sphere_3, Plane_3, Sphere_3) CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Plane_3, Sphere_3, Sphere_3) CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Plane_3, Plane_3, Sphere_3) + CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Plane_3, Sphere_3, Plane_3) CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_3(Sphere_3, Plane_3, Plane_3) CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_2(Circle_3, Plane_3) CGAL_SPHERICAL_KERNEL_MACRO_DO_INTERSECTION_3_2(Plane_3, Circle_3) @@ -1024,6 +1026,12 @@ template < class SK > \ const Plane_3 & p, OutputIterator res) const { return SphericalFunctors::intersect_3 (p,s1,s2,res); } + template < class OutputIterator > + OutputIterator + operator()(const Sphere_3 & s1, const Plane_3 & p, + const Sphere_3 & s2, OutputIterator res) const + { return SphericalFunctors::intersect_3 (p,s1,s2,res); } + template < class OutputIterator > OutputIterator operator()(const Plane_3 & p, const Sphere_3 & s1, @@ -1036,6 +1044,12 @@ template < class SK > \ const Sphere_3 & s, OutputIterator res) const { return SphericalFunctors::intersect_3 (p1,p2,s,res); } + template < class OutputIterator > + OutputIterator + operator()(const Plane_3 & p1, const Sphere_3 & s, + const Plane_3 & p2, OutputIterator res) const + { return SphericalFunctors::intersect_3 (p1,p2,s,res); } + template < class OutputIterator > OutputIterator operator()(const Sphere_3 & s, const Plane_3 & p1, diff --git a/Circular_kernel_3/include/CGAL/Spherical_kernel_intersections.h b/Circular_kernel_3/include/CGAL/Spherical_kernel_intersections.h index a587d87cea4..7d605d82897 100644 --- a/Circular_kernel_3/include/CGAL/Spherical_kernel_intersections.h +++ b/Circular_kernel_3/include/CGAL/Spherical_kernel_intersections.h @@ -71,8 +71,10 @@ CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_JUST_INTERSECTION_2_(Sphere_3, Line_ CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_JUST_INTERSECTION_2_(Line_3, Sphere_3) CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Sphere_3, Sphere_3, Sphere_3) CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Sphere_3, Sphere_3, Plane_3) +CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Sphere_3, Plane_3, Sphere_3) CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Plane_3, Sphere_3, Sphere_3) CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Plane_3, Plane_3, Sphere_3) +CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Plane_3, Sphere_3, Plane_3) CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_3_(Sphere_3, Plane_3, Plane_3) CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_2_(Circle_3, Plane_3) CGAL_SPHERICAL_KERNEL_MACRO_GLOBAL_FUNCTION_INTERSECTION_2_(Plane_3, Circle_3) diff --git a/Circular_kernel_3/test/Circular_kernel_3/include/CGAL/_test_sphere_constructions.h b/Circular_kernel_3/test/Circular_kernel_3/include/CGAL/_test_sphere_constructions.h index cac9217e371..670800fc5e2 100644 --- a/Circular_kernel_3/test/Circular_kernel_3/include/CGAL/_test_sphere_constructions.h +++ b/Circular_kernel_3/test/Circular_kernel_3/include/CGAL/_test_sphere_constructions.h @@ -928,7 +928,9 @@ void _test_intersection_construct(SK sk) { intersection(s1, s2, pl, std::back_inserter(intersection_1)); intersection(s1, s3, pl, std::back_inserter(intersection_2)); if(intersection_1.size() == 1) { - assert(CGAL::do_intersect(s1, s2, pl)); + assert(CGAL::do_intersect(pl, s1, s2)); + assert(CGAL::do_intersect(s1, pl, s2)); + assert(CGAL::do_intersect(s1, s2, pl)); Circle_3 circle; std::pair cap; if(assign_variant(circle,intersection_1[0])) { @@ -1006,7 +1008,9 @@ void _test_intersection_construct(SK sk) { theIntersect_3(s1, p1, pl, std::back_inserter(intersection_1)); theIntersect_3(s1, p2, pl, std::back_inserter(intersection_2)); if(intersection_1.size() == 1) { - assert(theDo_intersect_3(s1, p1, pl)); + assert(theDo_intersect_3(s1, p1, pl)); + assert(theDo_intersect_3(p1, s1, pl)); + assert(theDo_intersect_3(p1, pl, s1)); Circle_3 circle; std::pair cap; if(assign_variant(circle,intersection_1[0])) { diff --git a/Combinatorial_map/doc/Combinatorial_map/Combinatorial_map.txt b/Combinatorial_map/doc/Combinatorial_map/Combinatorial_map.txt index 1ea01c1d29a..cfdf656d527 100644 --- a/Combinatorial_map/doc/Combinatorial_map/Combinatorial_map.txt +++ b/Combinatorial_map/doc/Combinatorial_map/Combinatorial_map.txt @@ -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". diff --git a/Combinatorial_map/doc/Combinatorial_map/Concepts/CombinatorialMap.h b/Combinatorial_map/doc/Combinatorial_map/Concepts/CombinatorialMap.h index 251d424bc02..efe5fefc244 100644 --- a/Combinatorial_map/doc/Combinatorial_map/Concepts/CombinatorialMap.h +++ b/Combinatorial_map/doc/Combinatorial_map/Concepts/CombinatorialMap.h @@ -149,7 +149,7 @@ template bool is_sewable(Dart_const_descriptor d1, Dart_const_d Links by \f$ \beta_i \f$ two by two all the darts of the orbit D1=\f$ \langle{}\f$\f$ \beta_1\f$,\f$ \ldots\f$,\f$ \beta_{i-2}\f$,\f$ \beta_{i+2}\f$,\f$ \ldots\f$,\f$ \beta_d\f$\f$ \rangle{}\f$(`d1`) and D2=\f$ \langle{}\f$\f$ \beta_0\f$,\f$ \beta_2\f$,\f$ \ldots\f$,\f$ \beta_{i-2}\f$,\f$ \beta_{i+2}\f$,\f$ \ldots\f$,\f$ \beta_d\f$\f$ \rangle{}\f$(`d2`) such that d2=f(d1), where f is the bijection between D1 and D2 satisfying: f(d1)=d2, and for all e \f$ \in \f$ D1, for all j \f$ \in \f$ {1,\f$ \ldots\f$,i-2,i+2,\f$ \ldots\f$,d}, f(\f$ \beta_j\f$(e))=\f$ \beta_j^{-1}\f$(f(e)). If \link GenericMap::are_attributes_automatically_managed `are_attributes_automatically_managed()`\endlink`==true`, when necessary, non void attributes are updated to ensure the validity of the generic map: for each j-cells c1 and c2 which are merged into one j-cell during the sew, the two associated attributes attr1 and attr2 are considered. If one attribute is `null_descriptor` and the other not, the non `null_descriptor` attribute is associated to all the darts of the resulting cell. When the two attributes are non `null_descriptor`, functor \link CellAttribute::On_merge `Attribute_type::type::On_merge`\endlink is called on the two attributes attr1 and attr2. If set, the dynamic onmerge function of i-attributes is also called on attr1 and attr2. Then, the attribute attr1 is associated to all darts of the resulting j-cell. Finally, attribute attr2 is removed from the generic map. -\pre \link CombinatorialMap::is_sewable `is_sewable(d1,d2)`\endlink. +\pre \link CombinatorialMap::is_sewable `is_sewable`\endlink(`d1`,`d2`). \cgalAdvancedBegin If \link GenericMap::are_attributes_automatically_managed `are_attributes_automatically_managed()`\endlink`==false`, non void attributes are not updated; thus the generic map can be no more valid after this operation. diff --git a/Combinatorial_map/doc/Combinatorial_map/Concepts/GenericMap.h b/Combinatorial_map/doc/Combinatorial_map/Concepts/GenericMap.h index b7f985acac0..4c9a672d69b 100644 --- a/Combinatorial_map/doc/Combinatorial_map/Concepts/GenericMap.h +++ b/Combinatorial_map/doc/Combinatorial_map/Concepts/GenericMap.h @@ -467,14 +467,14 @@ const typename Attribute_type::type::Info & info(Dart_const_descriptor adart) /*! A shortcut for \link GenericMap::dart_of_attribute `dart_of_attribute`\endlink`(`\link GenericMap::attribute `attribute`\endlink`(adart))`. -\pre `attribute(adart)!=nullptr`. +\pre \link GenericMap::attribute `attribute`\endlink`(adart)!=nullptr`. */ template Dart_descriptor & dart(Dart_descriptor adart); /*! A shortcut for \link GenericMap::dart_of_attribute(typename Attribute_const_descriptor::type)const `dart_of_attribute`\endlink`(`\link GenericMap::attribute(Dart_const_descriptor)const `attribute`\endlink`(adart))` for const descriptor. -\pre `attribute(adart)!=nullptr`. +\pre \link GenericMap::attribute(Dart_const_descriptor)const `attribute`\endlink`(adart)!=nullptr`. */ template Dart_const_descriptor dart(Dart_const_descriptor adart) const; @@ -771,13 +771,13 @@ bool is_marked(Dart_const_descriptor d, size_type m) const; /*! Marks dart `d` for `m`. -\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink and `d`\f$ \in \f$ `darts()`. +\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`) and `d`\f$ \in \f$ `darts()`. */ void mark(Dart_const_descriptor d, size_type m) const; /*! Unmarks dart `d` for the mark `m`. -\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink and `d`\f$ \in \f$ `darts()`. +\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`) and `d`\f$ \in \f$ `darts()`. */ void unmark(Dart_const_descriptor d, size_type m) const; @@ -785,31 +785,31 @@ void unmark(Dart_const_descriptor d, size_type m) const; Inverse the mark `m` for all the darts of the generic map. All the marked darts become unmarked and all the unmarked darts become marked. -\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink. +\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`). */ void negate_mark(size_type m) const; /*! Unmarks all the darts of the generic map for `m`. -\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink. +\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`). */ void unmark_all(size_type m) const; /*! Returns the number of marked darts for `m`. -\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink. +\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`). */ size_type number_of_marked_darts(size_type m) const; /*! Return the number of unmarked darts for `m`. -\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink. +\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`). */ size_type number_of_unmarked_darts(size_type m) const; /*! Frees mark `m`. -\pre \link GenericMap::is_reserved `is_reserved(m)`\endlink. +\pre \link GenericMap::is_reserved `is_reserved`\endlink(`m`). */ void free_mark(size_type m) const; @@ -820,7 +820,7 @@ void free_mark(size_type m) const; /*! Creates a combinatorial hexahedron (six combinatorial quadrangles 2-sewn together), and adds it in the generic map. Returns a descriptor on one dart of this combinatorial hexahedron. -\pre `dimension` \f$\geq\f$ 2. +\pre \link GenericMap::dimension `dimension`\endlink \f$\geq\f$ 2. \sa `make_edge()` \sa `make_combinatorial_polygon()` @@ -831,7 +831,7 @@ Dart_descriptor make_combinatorial_hexahedron(); /*! Creates a combinatorial polygon of length `lg` (a cycle of `lg` edges), and adds it in the generic map. Returns a descriptor on one dart of this combinatorial polygon. -\pre `dimension`\f$ \geq\f$ 1 and `lg`\f$ >\f$ 0. +\pre \link GenericMap::dimension `dimension`\endlink \f$ \geq\f$ 1 and `lg`\f$ >\f$ 0. \sa `make_edge()` \sa `make_combinatorial_tetrahedron()` @@ -841,7 +841,7 @@ Dart_descriptor make_combinatorial_polygon(unsigned int lg); /*! Creates a combinatorial tetrahedron (four combinatorial triangles 2-sewn together), and adds it in the generic map. Returns a descriptor on one dart of this combinatorial tetrahedron. -\pre `dimension`\f$ \geq\f$ 2. +\pre \link GenericMap::dimension `dimension`\endlink \f$ \geq\f$ 2. \sa `make_edge()` \sa `make_combinatorial_polygon()` @@ -851,7 +851,7 @@ Dart_descriptor make_combinatorial_tetrahedron(); /*! Creates an isolated edge (two darts sewn to represent one edge and two vertices) and adds it in the generic map. Returns a descriptor on one dart of this edge. -\pre `dimension`\f$ \geq\f$ 2. +\pre \link GenericMap::dimension `dimension`\endlink \f$ \geq\f$ 2. \sa `make_combinatorial_polygon()` \sa `make_combinatorial_tetrahedron()` @@ -908,7 +908,7 @@ Dart_descriptor insert_cell_0_in_cell_2(Dart_descriptor d); /*! Inserts a 1-cell in the 2-cell containing `d1` and `d2`. Returns `previous(d1)`, a descriptor on one dart belonging to the new 1-cell. -\pre `is_insertable_cell_1_in_cell_2(d1,d2)`. +\pre \link GenericMap::is_insertable_cell_1_in_cell_2 `is_insertable_cell_1_in_cell_2`\endlink(`d1`,`d2`). See examples for combinatorial map in \cgalFigureRef{fig_cmap_insert_edge} and for generalized map in \cgalFigureRef{fig_gmap_insert_edge}. @@ -930,7 +930,7 @@ Dart_descriptor insert_cell_1_in_cell_2(Dart_descriptor d1, Dart_descriptor d2); /*! Inserts a 1-cell between the 2-cell containing `d1` and the one containing `d2`. Returns `previous(d1)`, a descriptor on one dart belonging to the new 1-cell. -\pre `is_insertable_cell_1_between_two_cells_2(d1,d2)`. +\pre \link GenericMap::is_insertable_cell_1_between_two_cells_2 `is_insertable_cell_1_between_two_cells_2`\endlink(`d1`,`d2`). If \link GenericMap::are_attributes_automatically_managed `are_attributes_automatically_managed()`\endlink`==true`, call \link CellAttribute::On_merge `Attribute_type::type::On_merge`\endlink(a,a') is called for all enabled i-attributes, for i>=2, with a the original 2-attribute associated with `d1` and a' the original 2-attribute associated with `d2`. If set, the dynamic on-merge function of i-attributes is also called on a and a'. @@ -957,7 +957,7 @@ Dart_descriptor insert_cell_1(Dart_descriptor d1, Dart_descriptor d2); /*! Inserts a 2-cell along the path of 1-cells containing darts given by the range `[afirst,alast)`. Returns `opposite<2>(*afirst)`, a descriptor on one dart belonging to the new 2-cell. -\pre `is_insertable_cell_2_in_cell_3(afirst,alast)`. +\pre \link GenericMap::is_insertable_cell_2_in_cell_3 `is_insertable_cell_2_in_cell_3`\endlink(`afirst`,`alast`). See examples for combinatorial map in \cgalFigureRef{fig_cmap_insert_facet} and for generalized map in \cgalFigureRef{fig_gmap_insert_facet}. @@ -1045,7 +1045,7 @@ bool is_removable(Dart_const_descriptor d); /*! Removes the i-cell containing `d`. Returns the number of darts removed from the generic map. -\pre `is_removable(d)`. +\pre \link GenericMap::is_removable `is_removable`\endlink(`d`). See examples in \cgalFigureRef{fig_cmap_insert_vertex}, \cgalFigureRef{fig_cmap_insert_edge} and \cgalFigureRef{fig_cmap_insert_facet}. diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map.h b/Combinatorial_map/include/CGAL/Combinatorial_map.h index 59f88e34970..407b27617fd 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map.h @@ -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 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(); } diff --git a/Combinatorial_map/include/CGAL/Compact_container_with_index.h b/Combinatorial_map/include/CGAL/Compact_container_with_index.h index 7395743edb0..308261a0001 100644 --- a/Combinatorial_map/include/CGAL/Compact_container_with_index.h +++ b/Combinatorial_map/include/CGAL/Compact_container_with_index.h @@ -453,7 +453,7 @@ public: // Constructor allowing to transform an index from one container to another template - Index_for_cc_with_index(const Index2& idx): m_idx(static_cast(idx)) + Index_for_cc_with_index(const Index2& idx): m_idx(static_cast(idx)) {} /// Increment the internal index. This operations does not diff --git a/Constrained_triangulation_3/include/CGAL/Conforming_constrained_Delaunay_triangulation_3.h b/Constrained_triangulation_3/include/CGAL/Conforming_constrained_Delaunay_triangulation_3.h index 59fc31bb7ad..56547d232ee 100644 --- a/Constrained_triangulation_3/include/CGAL/Conforming_constrained_Delaunay_triangulation_3.h +++ b/Constrained_triangulation_3/include/CGAL/Conforming_constrained_Delaunay_triangulation_3.h @@ -1074,7 +1074,7 @@ public: /*! * @brief same as `face_constraint_index(f)` with `f` being `Triangulation::Facet(ch, index)`. - * @pre `is_facet_constrained(f)` + * @pre \link Conforming_constrained_Delaunay_triangulation_3::is_facet_constrained `is_facet_constrained`\endlink(`f`) */ CDT_3_signed_index face_constraint_index(typename Triangulation::Cell_handle ch, int i) const { @@ -1084,7 +1084,7 @@ public: /*! * @brief returns the index of the constraint that constrains the * facet \p f - * @pre `is_facet_constrained(f)` + * @pre \link Conforming_constrained_Delaunay_triangulation_3::is_facet_constrained `is_facet_constrained`\endlink(`f`) */ CDT_3_signed_index face_constraint_index(const typename Triangulation::Facet& f) const { diff --git a/Documentation/doc/CMakeLists.txt b/Documentation/doc/CMakeLists.txt index 789111c5c21..a64be63b944 100644 --- a/Documentation/doc/CMakeLists.txt +++ b/Documentation/doc/CMakeLists.txt @@ -49,9 +49,6 @@ if(TARGET Doxygen::doxygen) PROPERTY IMPORTED_LOCATION) endif() -# Visual Studio users might appreciate this -# set_property(GLOBAL PROPERTY USE_FOLDERS ON) - macro(subdirlist result curdir) file( GLOB children diff --git a/Documentation/doc/Documentation/Developer_manual/Chapter_kernels.txt b/Documentation/doc/Documentation/Developer_manual/Chapter_kernels.txt index c665ec1f890..cd93d21c8ce 100644 --- a/Documentation/doc/Documentation/Developer_manual/Chapter_kernels.txt +++ b/Documentation/doc/Documentation/Developer_manual/Chapter_kernels.txt @@ -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 diff --git a/Documentation/doc/Documentation/Preliminaries.txt b/Documentation/doc/Documentation/Preliminaries.txt index f2006d05154..50d44334d30 100644 --- a/Documentation/doc/Documentation/Preliminaries.txt +++ b/Documentation/doc/Documentation/Preliminaries.txt @@ -43,6 +43,40 @@ also avoid CMake to link with the native threads support library on your system. \cgal is based on the version C++17 of the C++ standard. +\section preliminaries_secconmod Concepts and Models + +One of the core principles of \cgal is algorithmic genericity, enabling users to call +algorithms with custom data types, and to modify their behavior. To achieve this, and following +the examples of the C++ Standard Template Library (STL) and \boost libraries, \cgal makes heavy +use of C++ templates. + +The traditional design pattern used to specify the requirements of these templates is +the concept-model pattern. In this context, a concept is an informal, +abstract set of requirements on a type. A type that satisfies these requirements is said to +model the concept. A concept's requirements are typically syntactic (the set of valid +expressions that a type must support, including member types, member functions, and operators) +and semantic (the expected behavior and invariants of the syntactic requirements) requirements. + +For example, the concept `FaceGraph` describes the requirements for a graph data structure that +explicitly maintains faces defined by halfedges. It requires specific accessors, such as a function +to get an incident halfedge from a face, and a function to get an incident face from a halfedge. +Any class that provides these operations with the expected behavior, such as `CGAL::Surface_mesh` +or `CGAL::Polyhedron_3`, can be said to model the `FaceGraph` concept. This allows these different +data structures to be used interchangeably as arguments to many mesh processing algorithms of \cgal. + +Concepts can also be refined. A refined concept builds upon an existing one by adding +further requirements. For instance, a `MutableFaceGraph` concept would inherit all the requirements +of `FaceGraph` but add new ones for operations that modify the graph structure, such as adding or +removing faces. Any type that models `MutableFaceGraph` also models `FaceGraph`. + +It is important to note that these concepts from the concept-model design pattern should not be +confused with the first-class concepts language feature introduced in C++20. +The requirements described by the concept-model pattern are more akin to the pre-existing +C++ Named Requirements +found in the C++ standard, which serve as a formal description of the interface and behavior +required of template arguments. The concept-model pattern provides the philosophical framework +for designing generic libraries like \cgal. + \section preliminaries_secchecks Checks Much of the \cgal code contains assert statements for preconditions, and postconditions of functions diff --git a/Documentation/doc/biblio/geom.bib b/Documentation/doc/biblio/geom.bib index 07295e7aab1..9144b1d59c5 100644 --- a/Documentation/doc/biblio/geom.bib +++ b/Documentation/doc/biblio/geom.bib @@ -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} +} diff --git a/Documentation/doc/resources/1.14.0/menu_version.js b/Documentation/doc/resources/1.14.0/menu_version.js index 5a33e8c8f23..59a85e3a4b0 100644 --- a/Documentation/doc/resources/1.14.0/menu_version.js +++ b/Documentation/doc/resources/1.14.0/menu_version.js @@ -1,12 +1,12 @@ (function() { 'use strict'; - var url_re = /(cgal\.geometryfactory\.com\/CGAL\/doc\/|doc\.cgal\.org\/)(master|latest|(\d\.\d+|\d\.\d+\.\d+)(-beta\d)?)\//; + var url_re = /(cgal\.geometryfactory\.com\/CGAL\/doc\/|doc\.cgal\.org\/)(main|latest|(\d\.\d+|\d\.\d+\.\d+)(-beta\d)?)\//; var url_local = /.*\/doc_output\//; - var current_version_local = 'master' + var current_version_local = 'main' var all_versions = [ - 'master', - '6.1-beta2', + 'main', + '6.1', '6.0.2', 'latest', '5.6.3', @@ -31,12 +31,12 @@ ]; function build_select(current_version) { - if( current_version == 'master') { + if( current_version == 'main') { let top_elt = document.getElementById("top"); let first_element = top_elt.childNodes[0]; let new_div = document.createElement("p"); - new_div.innerHTML = '⚠️ This documentation corresponds to the master development branch of CGAL. It might diverge from the official releases.'; + new_div.innerHTML = '⚠️ This documentation corresponds to the main development branch of CGAL. It might diverge from the official releases.'; new_div.style.cssText = "background-color: #ff9800; margin: 1ex auto 1ex 1em; padding: 1ex; border-radius: 1ex; display: inline-block;" let OK = top_elt.insertBefore(new_div, first_element); } diff --git a/Documentation/doc/resources/1.8.13/menu_version.js b/Documentation/doc/resources/1.8.13/menu_version.js index 5a33e8c8f23..59a85e3a4b0 100644 --- a/Documentation/doc/resources/1.8.13/menu_version.js +++ b/Documentation/doc/resources/1.8.13/menu_version.js @@ -1,12 +1,12 @@ (function() { 'use strict'; - var url_re = /(cgal\.geometryfactory\.com\/CGAL\/doc\/|doc\.cgal\.org\/)(master|latest|(\d\.\d+|\d\.\d+\.\d+)(-beta\d)?)\//; + var url_re = /(cgal\.geometryfactory\.com\/CGAL\/doc\/|doc\.cgal\.org\/)(main|latest|(\d\.\d+|\d\.\d+\.\d+)(-beta\d)?)\//; var url_local = /.*\/doc_output\//; - var current_version_local = 'master' + var current_version_local = 'main' var all_versions = [ - 'master', - '6.1-beta2', + 'main', + '6.1', '6.0.2', 'latest', '5.6.3', @@ -31,12 +31,12 @@ ]; function build_select(current_version) { - if( current_version == 'master') { + if( current_version == 'main') { let top_elt = document.getElementById("top"); let first_element = top_elt.childNodes[0]; let new_div = document.createElement("p"); - new_div.innerHTML = '⚠️ This documentation corresponds to the master development branch of CGAL. It might diverge from the official releases.'; + new_div.innerHTML = '⚠️ This documentation corresponds to the main development branch of CGAL. It might diverge from the official releases.'; new_div.style.cssText = "background-color: #ff9800; margin: 1ex auto 1ex 1em; padding: 1ex; border-radius: 1ex; display: inline-block;" let OK = top_elt.insertBefore(new_div, first_element); } diff --git a/Documentation/doc/resources/1.9.6/menu_version.js b/Documentation/doc/resources/1.9.6/menu_version.js index 5a33e8c8f23..59a85e3a4b0 100644 --- a/Documentation/doc/resources/1.9.6/menu_version.js +++ b/Documentation/doc/resources/1.9.6/menu_version.js @@ -1,12 +1,12 @@ (function() { 'use strict'; - var url_re = /(cgal\.geometryfactory\.com\/CGAL\/doc\/|doc\.cgal\.org\/)(master|latest|(\d\.\d+|\d\.\d+\.\d+)(-beta\d)?)\//; + var url_re = /(cgal\.geometryfactory\.com\/CGAL\/doc\/|doc\.cgal\.org\/)(main|latest|(\d\.\d+|\d\.\d+\.\d+)(-beta\d)?)\//; var url_local = /.*\/doc_output\//; - var current_version_local = 'master' + var current_version_local = 'main' var all_versions = [ - 'master', - '6.1-beta2', + 'main', + '6.1', '6.0.2', 'latest', '5.6.3', @@ -31,12 +31,12 @@ ]; function build_select(current_version) { - if( current_version == 'master') { + if( current_version == 'main') { let top_elt = document.getElementById("top"); let first_element = top_elt.childNodes[0]; let new_div = document.createElement("p"); - new_div.innerHTML = '⚠️ This documentation corresponds to the master development branch of CGAL. It might diverge from the official releases.'; + new_div.innerHTML = '⚠️ This documentation corresponds to the main development branch of CGAL. It might diverge from the official releases.'; new_div.style.cssText = "background-color: #ff9800; margin: 1ex auto 1ex 1em; padding: 1ex; border-radius: 1ex; display: inline-block;" let OK = top_elt.insertBefore(new_div, first_element); } diff --git a/Frechet_distance/include/CGAL/Frechet_distance/internal/Frechet_light.h b/Frechet_distance/include/CGAL/Frechet_distance/internal/Frechet_light.h index 46e91745821..57bd1305cc5 100644 --- a/Frechet_distance/include/CGAL/Frechet_distance/internal/Frechet_light.h +++ b/Frechet_distance/include/CGAL/Frechet_distance/internal/Frechet_light.h @@ -514,6 +514,7 @@ inline void FrechetLight::continueQSimpleSearch(QSimpleInterval& qsimple, // TODO: uncritical for correctness or speed but unelegant coding style: stripping down information added by getInterval CInterval temp_interval = FrechetLight::getInterval( fixed_curve, fixed, curve, cur); + Interval interval = Interval(temp_interval.begin.getPoint() == cur ? temp_interval.begin.getFraction() : 1, diff --git a/Frechet_distance/include/CGAL/Frechet_distance/internal/geometry_basics.h b/Frechet_distance/include/CGAL/Frechet_distance/internal/geometry_basics.h index f7cf9f72548..8dec6273f8a 100644 --- a/Frechet_distance/include/CGAL/Frechet_distance/internal/geometry_basics.h +++ b/Frechet_distance/include/CGAL/Frechet_distance/internal/geometry_basics.h @@ -113,7 +113,10 @@ struct Lambda> // 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> { 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 res = approx < other.approx; if (CGAL::is_certain(res)) { @@ -206,7 +211,8 @@ struct Lambda> } update_exact(); other.update_exact(); - return exact < other.exact; + bool eres = exact.value() < other.exact.value(); + return eres; } }; diff --git a/Frechet_distance/test/Frechet_distance/CMakeLists.txt b/Frechet_distance/test/Frechet_distance/CMakeLists.txt index 9a489adcc6f..fdf7fc6d1a6 100644 --- a/Frechet_distance/test/Frechet_distance/CMakeLists.txt +++ b/Frechet_distance/test/Frechet_distance/CMakeLists.txt @@ -6,6 +6,9 @@ project( Frechet_distance_Tests ) find_package(CGAL REQUIRED) + +create_single_source_cgal_program( "Frechet-IssueOct25.cpp" ) + find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) include(CGAL_Eigen3_support) if(TARGET CGAL::Eigen3_support) diff --git a/Frechet_distance/test/Frechet_distance/Frechet-IssueOct25.cpp b/Frechet_distance/test/Frechet_distance/Frechet-IssueOct25.cpp new file mode 100644 index 00000000000..ff753671a9f --- /dev/null +++ b/Frechet_distance/test/Frechet_distance/Frechet-IssueOct25.cpp @@ -0,0 +1,40 @@ +#include +#include + +#include + +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 &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 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 res = CGAL::bounded_error_Frechet_distance(poly1, poly2, 0.000001); + std::cout << "Frechet distance: [" << res.first << ", " << res.second << "]" << std::endl; + return 0; +} diff --git a/Frechet_distance/test/Frechet_distance/poly1.txt b/Frechet_distance/test/Frechet_distance/poly1.txt new file mode 100644 index 00000000000..309937888c6 --- /dev/null +++ b/Frechet_distance/test/Frechet_distance/poly1.txt @@ -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 diff --git a/Frechet_distance/test/Frechet_distance/poly2.txt b/Frechet_distance/test/Frechet_distance/poly2.txt new file mode 100644 index 00000000000..5317263ddb9 --- /dev/null +++ b/Frechet_distance/test/Frechet_distance/poly2.txt @@ -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 diff --git a/Generalized_map/doc/Generalized_map/Concepts/GeneralizedMap.h b/Generalized_map/doc/Generalized_map/Concepts/GeneralizedMap.h index 16fa1e40eab..893231d371e 100644 --- a/Generalized_map/doc/Generalized_map/Concepts/GeneralizedMap.h +++ b/Generalized_map/doc/Generalized_map/Concepts/GeneralizedMap.h @@ -113,7 +113,7 @@ template bool is_sewable(Dart_const_descriptor d1, Dart_const_d Links by \f$ \alpha_i\f$ two by two all the darts of the orbit D1=\f$ \langle{}\f$\f$ \alpha_0\f$,\f$ \ldots\f$,\f$ \alpha_{i-2}\f$,\f$ \alpha_{i+2}\f$,\f$ \ldots\f$,\f$ \alpha_d\f$\f$ \rangle{}\f$(`d1`) and D2=\f$ \langle{}\f$\f$ \alpha_0\f$,\f$ \alpha_2\f$,\f$ \ldots\f$,\f$ \alpha_{i-2}\f$,\f$ \alpha_{i+2}\f$,\f$ \ldots\f$,\f$ \alpha_d\f$\f$ \rangle{}\f$(`d2`) such that d2=f(d1), where f is the bijection between D1 and D2 satisfying: f(d1)=d2, and for all e\f$ \in\f$ D1, for all j\f$ \in\f$ {1,\f$ \ldots\f$,i-2,i+2,\f$ \ldots\f$,d}, f(\f$ \alpha_j\f$(e))=\f$ \alpha_j\f$(f(e)). If \link GenericMap::are_attributes_automatically_managed `are_attributes_automatically_managed()`\endlink`==true`, when necessary, non void attributes are updated to ensure the validity of the generic map: for each j-cells c1 and c2 which are merged into one j-cell during the sew, the two associated attributes attr1 and attr2 are considered. If one attribute is `null_descriptor` and the other not, the non `null_descriptor` attribute is associated to all the darts of the resulting cell. When the two attributes are non `null_descriptor`, functor \link CellAttribute::On_merge `Attribute_type::type::On_merge`\endlink is called on the two attributes attr1 and attr2. If set, the dynamic onmerge function of i-attributes is also called on attr1 and attr2. Then, the attribute attr1 is associated to all darts of the resulting j-cell. Finally, attribute attr2 is removed from the generic map. -\pre \link GeneralizedMap::is_sewable `is_sewable(d1,d2)`\endlink. +\pre \link GeneralizedMap::is_sewable `is_sewable`\endlink(`d1`,`d2`). \cgalAdvancedBegin If \link GenericMap::are_attributes_automatically_managed `are_attributes_automatically_managed()`\endlink`==false`, non void attributes are not updated; thus the generic map can be no more valid after this operation. diff --git a/Generalized_map/doc/Generalized_map/Generalized_map.txt b/Generalized_map/doc/Generalized_map/Generalized_map.txt index 44143d90f4e..35010bf0e93 100644 --- a/Generalized_map/doc/Generalized_map/Generalized_map.txt +++ b/Generalized_map/doc/Generalized_map/Generalized_map.txt @@ -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". diff --git a/Generalized_map/include/CGAL/Generalized_map.h b/Generalized_map/include/CGAL/Generalized_map.h index acb4cc583da..fbd0963c94f 100644 --- a/Generalized_map/include/CGAL/Generalized_map.h +++ b/Generalized_map/include/CGAL/Generalized_map.h @@ -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() { diff --git a/Generator/doc/Generator/CGAL/point_generators_d.h b/Generator/doc/Generator/CGAL/point_generators_d.h index f26d9a7034c..fd7d8c5ffbb 100644 --- a/Generator/doc/Generator/CGAL/point_generators_d.h +++ b/Generator/doc/Generator/CGAL/point_generators_d.h @@ -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} diff --git a/GraphicsView/include/CGAL/Qt/manipulatedCameraFrame.h b/GraphicsView/include/CGAL/Qt/manipulatedCameraFrame.h index a838b677761..966c24a4bbe 100644 --- a/GraphicsView/include/CGAL/Qt/manipulatedCameraFrame.h +++ b/GraphicsView/include/CGAL/Qt/manipulatedCameraFrame.h @@ -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_; diff --git a/HalfedgeDS/include/CGAL/HalfedgeDS_decorator.h b/HalfedgeDS/include/CGAL/HalfedgeDS_decorator.h index 525e47c167a..eed5237568c 100644 --- a/HalfedgeDS/include/CGAL/HalfedgeDS_decorator.h +++ b/HalfedgeDS/include/CGAL/HalfedgeDS_decorator.h @@ -743,7 +743,7 @@ public: typedef std::vector 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. diff --git a/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/PackageDescription.txt b/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/PackageDescription.txt index c347636ff34..d6939ca7176 100644 --- a/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/PackageDescription.txt +++ b/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/PackageDescription.txt @@ -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} diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 827bfc8a762..a1caaaa7107 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -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*>` 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) diff --git a/Installation/cmake/modules/CGALHelpers.cmake b/Installation/cmake/modules/CGALHelpers.cmake index f29fd11111b..957371769bd 100644 --- a/Installation/cmake/modules/CGALHelpers.cmake +++ b/Installation/cmake/modules/CGALHelpers.cmake @@ -28,7 +28,14 @@ function(process_CGAL_subdirectory entry subdir type_name) endif() endif() if(source_dir) + set(CGAL_CMAKE_FOLDER_PREFIX) + if(CMAKE_FOLDER) + set(CGAL_CMAKE_FOLDER_PREFIX "${CMAKE_FOLDER}/") + endif() + set(CMAKE_FOLDER "${CGAL_CMAKE_FOLDER_PREFIX}${subdir}/${ENTRY_DIR_NAME}") + list(APPEND CMAKE_MESSAGE_INDENT " ") add_subdirectory( "${source_dir}" "${CMAKE_BINARY_DIR}/${subdir}/${ENTRY_DIR_NAME}" EXCLUDE_FROM_ALL) + list(POP_BACK CMAKE_MESSAGE_INDENT) endif() endfunction() diff --git a/Installation/cmake/modules/FindMPFR.cmake b/Installation/cmake/modules/FindMPFR.cmake index b0507120ce0..891b2a7edbd 100644 --- a/Installation/cmake/modules/FindMPFR.cmake +++ b/Installation/cmake/modules/FindMPFR.cmake @@ -46,6 +46,9 @@ if (NOT MPFR_in_cache) if ( NOT MPFR_INCLUDE_DIR OR NOT MPFR_LIBRARIES_DIR ) include( MPFRConfig OPTIONAL ) endif() + + set(MPFR_DEPENDENCY_INCLUDE_DIR ${GMP_INCLUDE_DIR}) + set(MPFR_DEPENDENCY_LIBRARIES ${GMP_LIBRARIES}) endif() diff --git a/Intersections_2/include/CGAL/Intersections_2/Iso_rectangle_2_Iso_rectangle_2.h b/Intersections_2/include/CGAL/Intersections_2/Iso_rectangle_2_Iso_rectangle_2.h index 0b73db82b88..35013ea0e5e 100644 --- a/Intersections_2/include/CGAL/Intersections_2/Iso_rectangle_2_Iso_rectangle_2.h +++ b/Intersections_2/include/CGAL/Intersections_2/Iso_rectangle_2_Iso_rectangle_2.h @@ -20,6 +20,7 @@ #include #include +#include namespace CGAL { diff --git a/Intersections_2/include/CGAL/intersection_2.h b/Intersections_2/include/CGAL/intersection_2.h index 4b22e327369..d793cd8d133 100644 --- a/Intersections_2/include/CGAL/intersection_2.h +++ b/Intersections_2/include/CGAL/intersection_2.h @@ -19,10 +19,14 @@ #ifndef CGAL_INTERSECTION_2_H #define CGAL_INTERSECTION_2_H +#include #include +#include #include #include #include +#include +#include #include #include diff --git a/Interval_skip_list/doc/Interval_skip_list/Interval_skip_list.txt b/Interval_skip_list/doc/Interval_skip_list/Interval_skip_list.txt index 26bdba5ef1b..db519f23720 100644 --- a/Interval_skip_list/doc/Interval_skip_list/Interval_skip_list.txt +++ b/Interval_skip_list/doc/Interval_skip_list/Interval_skip_list.txt @@ -46,7 +46,7 @@ class. In this example we use the class `Interval_skip_list_interval`. \subsection Interval_skip_listExamplewithFacesofaTriangulated Example with Faces of a Triangulated Terrain The second example creates an interval skip list that allows to find all the faces -of a terrain intersected by an horizontal plane at a given height. +of a terrain intersected by a horizontal plane at a given height. The data points for the terrain are read from a file. As model for the interval concept, we use a class that is a wrapper diff --git a/Kernel_23/doc/Kernel_23/CGAL/intersections.h b/Kernel_23/doc/Kernel_23/CGAL/intersections.h index 3670052bb6d..20d298e1cf1 100644 --- a/Kernel_23/doc/Kernel_23/CGAL/intersections.h +++ b/Kernel_23/doc/Kernel_23/CGAL/intersections.h @@ -32,25 +32,22 @@ bounded region, this region is part of the object. The types `Type1` and `Type2` can be any of the following: -- `Point_2` +- `Bbox_2` +- `Circle_2` +- `Iso_rectangle_2` - `Line_2` +- `Point_2` - `Ray_2` - `Segment_2` - `Triangle_2` -- `Iso_rectangle_2` - -Also, `Type1` and `Type2` can be both of type - -- `Line_2` -- `Circle_2` In three-dimensional space, the types `Type1` and `Type2` can be any of the following: - `Bbox_3`. +- `Line_3` - `Point_3` - `Plane_3` -- `Line_3` - `Ray_3` - `Segment_3` - `Sphere_3` @@ -192,8 +189,8 @@ the template parameter pack. -Additional overloads are provided for the type `Point_2` combined with any other type with the result type being -`std::optional< std::variant< Point_2 > >`. +Additional overloads are provided for the type `Point_2` combined with any other type in the table above, +with the result type being `std::optional< std::variant< Point_2 > >`. Overloads are also provided for the type `Bbox_2`, for all intersections existing with the type `Iso_rectangle_2`. Note that the return type for `Bbox_2` - `Bbox_2` is `Bbox_2` and not `Iso_rectangle_2`. @@ -350,11 +347,11 @@ the template parameter pack. -Additional overloads are provided for the type `Point_3` combined with any other type with the result type being -`std::optional< std::variant< Point_3 > >`. Overloads are also provided for the type `Bbox_3`, for all +Additional overloads are provided for the type `Point_3` combined with any other type in the table above, +with the result type being `std::optional< std::variant< Point_3 > >`. +Overloads are also provided for the type `Bbox_3`, for all intersections existing with the type `Iso_cuboid_3`. Note that the return type for `Bbox_3` - `Bbox_3` - is `Bbox_3` and not `Iso_cuboid_3`. - +is `Bbox_3` and not `Iso_cuboid_3`. \cgalHeading{Examples} diff --git a/Kernel_d/doc/Kernel_d/CGAL/Epeck_d.h b/Kernel_d/doc/Kernel_d/CGAL/Epeck_d.h index af63a8781c6..8d5bae50181 100644 --- a/Kernel_d/doc/Kernel_d/CGAL/Epeck_d.h +++ b/Kernel_d/doc/Kernel_d/CGAL/Epeck_d.h @@ -75,7 +75,7 @@ public: Point_d(double x0, double x1, ...); /*! introduces a point with coordinate set `[first,end)`. - \pre If `DimensionTag` is a fixed dimension, it matches `distance(first,end)`. + \pre If `DimensionTag` is a fixed dimension, it matches `std::distance(first,end)`. \tparam ForwardIterator has its value type that is convertible to `double`. */ template @@ -108,7 +108,7 @@ public: Vector_d(double x0, double x1, ...); /*! introduces a vector with coordinate set `[first,end)`. - \pre If `DimensionTag` is a fixed dimension, it matches `distance(first,end)`. + \pre If `DimensionTag` is a fixed dimension, it matches `std::distance(first,end)`. \tparam ForwardIterator has its value type that is convertible to `double`. */ template diff --git a/Kernel_d/doc/Kernel_d/CGAL/Epick_d.h b/Kernel_d/doc/Kernel_d/CGAL/Epick_d.h index 61cd6153cdf..216ca642860 100644 --- a/Kernel_d/doc/Kernel_d/CGAL/Epick_d.h +++ b/Kernel_d/doc/Kernel_d/CGAL/Epick_d.h @@ -63,7 +63,7 @@ public: Point_d(double x0, double x1, ...); /*! introduces a point with coordinate set `[first,end)`. - \pre If `DimensionTag` is a fixed dimension, it matches `distance(first,end)`. + \pre If `DimensionTag` is a fixed dimension, it matches `std::distance(first,end)`. \tparam InputIterator has its value type that is convertible to `double`. */ template @@ -98,7 +98,7 @@ public: Vector_d(double x0, double x1, ...); /*! introduces a vector with coordinate set `[first,end)`. - \pre If `DimensionTag` is a fixed dimension, it matches `distance(first,end)`. + \pre If `DimensionTag` is a fixed dimension, it matches `std::distance(first,end)`. \tparam InputIterator has its value type that is convertible to `double`. */ template diff --git a/Kernel_d/doc/Kernel_d/CGAL/predicates_d.h b/Kernel_d/doc/Kernel_d/CGAL/predicates_d.h index 5eaddde1125..d0642c2017b 100644 --- a/Kernel_d/doc/Kernel_d/CGAL/predicates_d.h +++ b/Kernel_d/doc/Kernel_d/CGAL/predicates_d.h @@ -164,7 +164,7 @@ returns the relative position of point `p` to the sphere defined by `A = tuple [first,last)`. The order of the points of \f$ A\f$ does not matter. -\pre `orientation(first,last)` is not `ZERO`. +\pre \ref CGAL::orientation(ForwardIterator, ForwardIterator) "orientation(first,last)" is not `ZERO`. \tparam ForwardIterator has `Point_d` as value type. */ template Bounded_side diff --git a/Kernel_d/doc/Kernel_d/Concepts/Kernel--Component_accessor_d.h b/Kernel_d/doc/Kernel_d/Concepts/Kernel--Component_accessor_d.h index ecc427a12b7..32b3c227c9c 100644 --- a/Kernel_d/doc/Kernel_d/Concepts/Kernel--Component_accessor_d.h +++ b/Kernel_d/doc/Kernel_d/Concepts/Kernel--Component_accessor_d.h @@ -19,7 +19,7 @@ the dimension of \f$ p\f$. int dimension(const Kernel_d::Point_d& p); /*! -returns the ith homogeneous coordinate of \f$ p\f$. +returns the i-th homogeneous coordinate of \f$ p\f$. \pre `0 <= i <= dimension(p)`. */ @@ -27,7 +27,7 @@ Kernel_d::RT homogeneous(const Kernel_d::Point_d& p, int i); /*! -returns the ith %Cartesian coordinate of \f$ p\f$. +returns the i-th %Cartesian coordinate of \f$ p\f$. \pre `0 <= i < dimension(p)`. */ diff --git a/Kernel_d/doc/Kernel_d/Concepts/Kernel--Side_of_bounded_sphere_d.h b/Kernel_d/doc/Kernel_d/Concepts/Kernel--Side_of_bounded_sphere_d.h index b436ee1561a..32cfc217fb1 100644 --- a/Kernel_d/doc/Kernel_d/Concepts/Kernel--Side_of_bounded_sphere_d.h +++ b/Kernel_d/doc/Kernel_d/Concepts/Kernel--Side_of_bounded_sphere_d.h @@ -17,7 +17,7 @@ returns the relative position of point `p` to the sphere defined by `A = tuple [first,last)`. The order of the points of \f$ A\f$ does not matter. -\pre `orientation(first,last)` is not `ZERO`. +\pre \ref CGAL::orientation(ForwardIterator, ForwardIterator) "orientation(first,last)" is not `ZERO`. \tparam ForwardIterator has `Kernel_d::Point_d` as value type. */ template Bounded_side diff --git a/Kernel_d/doc/Kernel_d/Concepts/LinearAlgebraTraits_d.h b/Kernel_d/doc/Kernel_d/Concepts/LinearAlgebraTraits_d.h index e0e523e5363..6b55ad30d40 100644 --- a/Kernel_d/doc/Kernel_d/Concepts/LinearAlgebraTraits_d.h +++ b/Kernel_d/doc/Kernel_d/Concepts/LinearAlgebraTraits_d.h @@ -66,7 +66,7 @@ Vector& c); returns the inverse matrix of `M`. More precisely, \f$ 1/D\f$ times the matrix returned is the inverse of `M`. -\pre `determinant(M) != 0`. +\pre \ref determinant(const Matrix&) "determinant(M)"` != 0`. \pre \f$ M\f$ is square. */ diff --git a/Kernel_d/doc/Kernel_d/Concepts/Matrix.h b/Kernel_d/doc/Kernel_d/Concepts/Matrix.h index f2daec7a033..f5d1b315bcc 100644 --- a/Kernel_d/doc/Kernel_d/Concepts/Matrix.h +++ b/Kernel_d/doc/Kernel_d/Concepts/Matrix.h @@ -272,7 +272,7 @@ iterator begin(); an iterator pointing beyond the last entry of \f$ M\f$. */ -terator end(); +iterator end(); /*! an iterator pointing to the first entry diff --git a/Kinetic_space_partition/include/CGAL/KSP_3/Data_structure.h b/Kinetic_space_partition/include/CGAL/KSP_3/Data_structure.h index 8514cff93d8..662b0ff3200 100644 --- a/Kinetic_space_partition/include/CGAL/KSP_3/Data_structure.h +++ b/Kinetic_space_partition/include/CGAL/KSP_3/Data_structure.h @@ -363,11 +363,6 @@ public: if (m_intersection_graph.iedge_is_on_bbox(edge)) return 0; - // Count faces - std::size_t numfaces = 0; - for (std::size_t i = 0; i < m_support_planes.size(); i++) - numfaces += m_support_planes[i].data().mesh.number_of_faces(); - Support_plane& sp = m_support_planes[sp_idx]; To_exact to_exact; @@ -550,11 +545,6 @@ public: template void fill_event_queue(Queue& queue) { - // Count faces - std::size_t faces = 0; - for (std::size_t i = 0; i < m_support_planes.size(); i++) - faces += m_support_planes[i].data().mesh.number_of_faces(); - for (std::size_t sp_idx = 6; sp_idx < m_support_planes.size(); sp_idx++) { std::vector border; m_support_planes[sp_idx].get_border(m_intersection_graph, border); diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/kinetic_3d_test_all.cpp b/Kinetic_space_partition/test/Kinetic_space_partition/kinetic_3d_test_all.cpp index 1fb8898a153..ec20f21d091 100644 --- a/Kinetic_space_partition/test/Kinetic_space_partition/kinetic_3d_test_all.cpp +++ b/Kinetic_space_partition/test/Kinetic_space_partition/kinetic_3d_test_all.cpp @@ -11,6 +11,9 @@ using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; std::size_t different = 0; +std::size_t no_input = 0; +std::size_t failed = 0; +std::size_t passed = 0; template bool run_test( @@ -33,7 +36,7 @@ bool run_test( input_file_ply.close(); else { std::cerr << "ERROR: can't read the OFF/PLY file " << filename << "!" << std::endl; - different++; + no_input++; return false; } @@ -56,7 +59,9 @@ bool run_test( std::cout << ksp.number_of_volumes() << std::endl; - if (results[i][0] != count[0] || results[i][1] != count[2] || results[i][2] != count[3]) { + if (ksp.number_of_volumes() == 0) + failed++; + else if (results[i][0] != count[0] || results[i][1] != count[2] || results[i][2] != count[3]) { std::cout << "TEST differs: Partitioning has not expected number of vertices, faces or volumes for k = " << ks[i] << std::endl; std::cout << "Expectation:" << std::endl; @@ -66,7 +71,10 @@ bool run_test( different++; } - else std::cout << "TEST PASSED k = " << ks[i] << " " << input_filename << std::endl; + else { + passed++; + std::cout << "TEST PASSED k = " << ks[i] << " " << input_filename << std::endl; + } } return true; @@ -277,11 +285,25 @@ void run_all_tests() { results[2] = { 1395, 3115, 882 }; run_test("data/real-data-test/test-40-polygons.ply", { 1, 2, 3 }, results); + std::cout << "\n"; + const auto kernel_name = boost::typeindex::type_id().pretty_name(); - if (different != 0) { - std::cout << std::endl << kernel_name << " " << different << " TESTS differ from typical values!" << std::endl << std::endl; + if (no_input != 0) { + std::cout << kernel_name << " " << no_input << " TESTS failed due to missing input files!\n"; } - std::cout << std::endl << kernel_name << " TESTS SUCCESS!" << std::endl << std::endl; + + if (failed != 0) { + std::cout << kernel_name << " " << failed << " TESTS failed! The space partition was empty!\n"; + } + + if (different != 0) { + std::cout << kernel_name << " " << different << " TESTS differ from typical values!\n"; + } + + if (passed != 0) + std::cout << kernel_name << " " << passed << " TESTS passed!\n"; + + std::cout << "\n" << kernel_name << " TESTS FINISHED!" << std::endl; } int main(const int /* argc */, const char** /* argv */) { diff --git a/Kinetic_surface_reconstruction/include/CGAL/Kinetic_surface_reconstruction_3.h b/Kinetic_surface_reconstruction/include/CGAL/Kinetic_surface_reconstruction_3.h index 221a3fa4683..5873b7df672 100644 --- a/Kinetic_surface_reconstruction/include/CGAL/Kinetic_surface_reconstruction_3.h +++ b/Kinetic_surface_reconstruction/include/CGAL/Kinetic_surface_reconstruction_3.h @@ -1365,8 +1365,8 @@ private: CGAL_assertion_code(auto it =) va2vh.insert(std::make_pair(polygons[i][j], vertices.size() - 1)); CGAL_assertion(it.second || it.first->first == polygons[i][j]); - vertices.back()->info().i = i; - vertices.back()->info().j = j; + vertices.back()->info().i = static_cast(i); + vertices.back()->info().j = static_cast(j); vertices.back()->info().p = pl.to_2d(m_lcc.point(m_lcc.template dart_of_attribute<0>(polygons[i][j]))); vertices.back()->info().dh = polygons[i][j]; diff --git a/Lab/demo/Lab/Plugins/IO/WKT_io_plugin.cpp b/Lab/demo/Lab/Plugins/IO/WKT_io_plugin.cpp index 9315f9a85b4..ec3aaa1b3ad 100644 --- a/Lab/demo/Lab/Plugins/IO/WKT_io_plugin.cpp +++ b/Lab/demo/Lab/Plugins/IO/WKT_io_plugin.cpp @@ -2,6 +2,9 @@ #include #include +#include +#include +#include #include #include #include @@ -45,36 +48,50 @@ canLoad(QFileInfo) const { QList CGAL_Lab_wkt_plugin:: load(QFileInfo fileinfo, bool& ok, bool add_to_scene) { + typedef Scene_polylines_item::Point_3 Point_3; + typedef CGAL::Kernel_traits::Kernel K; + typedef std::vector Polyline; + typedef CGAL::Projection_traits_xy_3 Kernel; + typedef CGAL::Polygon_with_holes_2 Polygon; + std::ifstream in(fileinfo.filePath().toUtf8()); - if(!in) - std::cerr << "Error!\n"; - QApplication::setOverrideCursor(Qt::WaitCursor); - - if(fileinfo.size() == 0) + if(!in || fileinfo.size() == 0) { - CGAL::Three::Three::warning( tr("The file you are trying to load is empty.")); + CGAL::Three::Three::warning( tr("The file you are trying to load does not exist or is empty.")); ok = false; - QApplication::restoreOverrideCursor(); return QList(); } - std::list > polylines; - bool success = CGAL::IO::read_multi_linestring_WKT (in, polylines); - if(! success){ - in.close(); - in.open(fileinfo.filePath().toUtf8()); - std::vector polyline; - std::cout << " read" << std::endl; - success = CGAL::IO::read_linestring_WKT (in, polyline); - std::cout << " done " << std::boolalpha << success << " " << polyline.size() << std::endl; - if(! success){ - ok = false; - QApplication::restoreOverrideCursor(); - return QList(); - } + QApplication::setOverrideCursor(Qt::WaitCursor); + + std::vector points; + std::list polylines; + std::vector polygons; + bool success = CGAL::IO::read_WKT(in, points, polylines, polygons); + for(const Polygon& p : polygons) + { + Polyline polyline(p.outer_boundary().vertices_begin(), p.outer_boundary().vertices_end()); + polyline.push_back(polyline.front()); polylines.push_back(polyline); + for(auto hit = p.holes_begin(); hit != p.holes_end(); ++hit) + { + Polyline hole(hit->vertices_begin(), hit->vertices_end()); + hole.push_back(hole.front()); + polylines.push_back(hole); + } + } + if(! polygons.empty()){ + CGAL::Three::Three::warning( tr("The polygons will be drawn as polylines")); + } + + if(!success || polylines.empty()) + { + CGAL::Three::Three::warning( tr("The file you are trying to load is not a valid WKT file or is empty")); + ok = false; + QApplication::restoreOverrideCursor(); + return QList(); } Scene_polylines_item* item = new Scene_polylines_item; diff --git a/Lab/demo/Lab/Plugins/Mesh_3/CMakeLists.txt b/Lab/demo/Lab/Plugins/Mesh_3/CMakeLists.txt index c950047d0f0..7a0275e552d 100644 --- a/Lab/demo/Lab/Plugins/Mesh_3/CMakeLists.txt +++ b/Lab/demo/Lab/Plugins/Mesh_3/CMakeLists.txt @@ -39,6 +39,7 @@ if(ITK_FOUND) message(STATUS "ITK found") include(${ITK_USE_FILE}) target_link_libraries(mesh_3_plugin PRIVATE CGAL::ITK_support) + target_compile_definitions(mesh_3_plugin PRIVATE ITK_LEGACY_FUTURE_REMOVE) endif(ITK_FOUND) find_package(VTK 9.0 QUIET COMPONENTS ImagingGeneral IOImage IOXML NO_MODULE) diff --git a/Lab/demo/Lab/Plugins/Point_set/Kinetic_surface_reconstruction_plugin.cpp b/Lab/demo/Lab/Plugins/Point_set/Kinetic_surface_reconstruction_plugin.cpp index 9ef3b7a5f0c..4fa74390627 100644 --- a/Lab/demo/Lab/Plugins/Point_set/Kinetic_surface_reconstruction_plugin.cpp +++ b/Lab/demo/Lab/Plugins/Point_set/Kinetic_surface_reconstruction_plugin.cpp @@ -298,7 +298,7 @@ private Q_SLOTS: std::size_t max_depth = m_ksr->estimate_max_subdivision_depth(); dock_widget->partReorientCheck->setChecked(true); dock_widget->partSubdivisionCheck->setChecked(true); - dock_widget->partMaxDepthBox->setValue(max_depth); + dock_widget->partMaxDepthBox->setValue(static_cast(max_depth)); dock_widget->partPolygonsPerNodeBox->setValue(40); dock_widget->partKBox->setValue(2); } @@ -591,7 +591,7 @@ private: m_ksr->estimate_detection_parameters(max_distance, max_angle, min_region_size); dock_widget->sdMaxDistanceBox->setValue(max_distance); dock_widget->sdMaxAngleBox->setValue(max_angle); - dock_widget->sdMinRegionSizeBox->setValue(min_region_size); + dock_widget->sdMinRegionSizeBox->setValue(static_cast(min_region_size)); dock_widget->sdkNeighborsBox->setValue(12); dock_widget->srCoplanarityCheck->setChecked(true); dock_widget->srMaxOffsetBox->setValue(max_distance * 0.5); diff --git a/Lab/demo/Lab/Scene_points_with_normal_item.cpp b/Lab/demo/Lab/Scene_points_with_normal_item.cpp index a75bf57bf79..e0970648dc1 100644 --- a/Lab/demo/Lab/Scene_points_with_normal_item.cpp +++ b/Lab/demo/Lab/Scene_points_with_normal_item.cpp @@ -808,8 +808,7 @@ void Scene_points_with_normal_item::computes_local_spacing(int k) // Compute the radius of each point = (distance max to k nearest neighbors)/2. { - int i=0; - for (Point_set::iterator it=d->m_points->begin(); it!=d->m_points->end(); ++it, ++i) + for (Point_set::iterator it=d->m_points->begin(); it!=d->m_points->end(); ++it) { Neighbor_search search(tree, d->m_points->point(*it), k+1, 0, true, tr_dist); double maxdist2 = (--search.end())->second; // squared distance to furthest neighbor diff --git a/Lab/demo/Lab/Scene_polygon_soup_item.cpp b/Lab/demo/Lab/Scene_polygon_soup_item.cpp index 7bdc0f69a0c..4f82672743c 100644 --- a/Lab/demo/Lab/Scene_polygon_soup_item.cpp +++ b/Lab/demo/Lab/Scene_polygon_soup_item.cpp @@ -39,11 +39,7 @@ #include #include -#include -#include #include -#include -#include #include using namespace CGAL::Three; @@ -565,7 +561,7 @@ Scene_polygon_soup_item::save(std::ostream& out) const } writer.write_footer(); - return (bool) out; + return false == out.fail(); } bool diff --git a/Lab/demo/Lab/triangulate_primitive.h b/Lab/demo/Lab/triangulate_primitive.h index 54fceb64eb3..8093ed4e3bc 100644 --- a/Lab/demo/Lab/triangulate_primitive.h +++ b/Lab/demo/Lab/triangulate_primitive.h @@ -145,14 +145,9 @@ private: Vertex_handle previous, first, last_inserted; // Iterate the points of the facet and decide if they must be inserted in the CDT - typename Kernel::FT x(0), y(0), z(0); - for(std::size_t i = 0;i& idPoint = idPoints[i]; - x += idPoint.first.x(); - y += idPoint.first.y(); - z += idPoint.first.z(); Vertex_handle vh; // Always insert the first point, then only insert if the distance with the previous is reasonable. diff --git a/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt b/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt index 1b19dfc111d..5d7ac3cfd55 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt +++ b/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt @@ -281,7 +281,7 @@ The following example shows the incremental builder. \subsection Linear_cell_complexInsert Insert an Edge Between Two Different Faces -The following example shows the use of \link GenericMap::insert_cell_1_between_two_cells_2 `insert_cell_1_between_two_cells_2`\endlink operation that inserts an edge between two different faces, thus creating an hole in the first face. +The following example shows the use of \link GenericMap::insert_cell_1_between_two_cells_2 `insert_cell_1_between_two_cells_2`\endlink operation that inserts an edge between two different faces, thus creating a hole in the first face. \cgalExample{Linear_cell_complex/linear_cell_complex_3_insert.cpp} diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h index b1943bca3c4..3204c4e3bd1 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h @@ -214,14 +214,14 @@ namespace CGAL { } /** Create a vertex attribute. - * @return an handle on the new attribute. + * @return a handle on the new attribute. */ template Vertex_attribute_descriptor create_vertex_attribute(const Args&... args) { return Base::template create_attribute<0>(args...); } /** - * Create a new dart associated with an handle through an attribute. + * Create a new dart associated with a handle through an attribute. * @param ahandle the point handle to associated with the dart. * @return a Dart_descriptor on the new dart. */ diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_for_combinatorial_map.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_for_combinatorial_map.h index 46e24d100e3..e11e05ce3c8 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_for_combinatorial_map.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_for_combinatorial_map.h @@ -157,7 +157,7 @@ namespace CGAL { return is; } - /** 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 void import_from_halfedge_graph(const HEG& heg , const PointConverter& pointconverter, @@ -198,7 +198,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 void import_from_halfedge_graph(const HEG& heg, std::unordered_map diff --git a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_3_test.h b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_3_test.h index 4222e553c43..2d24bcff74e 100644 --- a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_3_test.h +++ b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_3_test.h @@ -977,7 +977,7 @@ bool test_LCC_3() lcc.template sew<3>(dh3, lcc.make_combinatorial_polygon(4)); create_attributes_3(lcc); - // Create an hole in the face between the two cubes + // Create a hole in the face between the two cubes lcc.insert_cell_1_between_two_cells_2(lcc.template opposite<2>(lcc.next(lcc.next(dh1))), lcc.next(lcc.next(dh3))); diff --git a/Maintenance/test_handling/testsuite_comparison/diff_testsuites.html b/Maintenance/test_handling/testsuite_comparison/diff_testsuites.html index ab4842098e0..a707fb07230 100644 --- a/Maintenance/test_handling/testsuite_comparison/diff_testsuites.html +++ b/Maintenance/test_handling/testsuite_comparison/diff_testsuites.html @@ -24,7 +24,7 @@

    Note that the diff should be done from left to right, as red or yellow squares in the left testsuite that become green in the right testsuite will be ignored.

    - I = Master
    + I = main
    Ic = integration

    diff --git a/Mesh_3/doc/Mesh_3/Concepts/MeshDomain_3.h b/Mesh_3/doc/Mesh_3/Concepts/MeshDomain_3.h index b4ecaab30d8..12fdea95f9b 100644 --- a/Mesh_3/doc/Mesh_3/Concepts/MeshDomain_3.h +++ b/Mesh_3/doc/Mesh_3/Concepts/MeshDomain_3.h @@ -172,7 +172,8 @@ intersection between an object of type `Segment_3`, `Ray_3` or `Intersection operator()(Ray_3 r)` `Intersection operator()(Line_3 l)` -\pre do_intersect_surface(s/r/l) == true + +\pre `do_intersect_surface_object(s/r/l)` == `true` */ typedef unspecified_type Construct_intersection; diff --git a/Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h b/Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h index 2c0539b9be0..8d452ee8036 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h +++ b/Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h @@ -1285,8 +1285,6 @@ perturb_vertex( PVertex pv CGAL_assertion(pv.is_perturbable()); - int num_new_vertices_to_treat = 0; - Cell_vector slivers; slivers.reserve(8); if (!helper_.try_lock_and_get_incident_slivers( @@ -1349,8 +1347,7 @@ perturb_vertex( PVertex pv pv.increment_try_nb(); // update modified vertices - num_new_vertices_to_treat += - update_priority_queue(modified_vertices, sliver_bound, visitor, bad_vertices); + update_priority_queue(modified_vertices, sliver_bound, visitor, bad_vertices); } else { @@ -1372,7 +1369,6 @@ perturb_vertex( PVertex pv if (pv.is_perturbable()) { enqueue_task(pv, sliver_bound, visitor, bad_vertices); - ++num_new_vertices_to_treat; } } else diff --git a/Mesh_3/include/CGAL/refine_mesh_3.h b/Mesh_3/include/CGAL/refine_mesh_3.h index b19dd04a8b8..e970ab1159a 100644 --- a/Mesh_3/include/CGAL/refine_mesh_3.h +++ b/Mesh_3/include/CGAL/refine_mesh_3.h @@ -151,7 +151,7 @@ private: * \tparam MC either a model of the concept `MeshCriteria_3` or a model * of `MeshCriteriaWithFeatures_3` if the domain has exposed features. * - * \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters + * \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * * \param c3t3 the mesh to be refined that is modified by the refinement process. * As the refinement process only adds points to the triangulation, all diff --git a/Miscellany/doc/Miscellany/Miscellany.txt b/Miscellany/doc/Miscellany/Miscellany.txt index eb8ed642c34..40d108a8290 100644 --- a/Miscellany/doc/Miscellany/Miscellany.txt +++ b/Miscellany/doc/Miscellany/Miscellany.txt @@ -78,7 +78,7 @@ halfedge data structure than by using the high-level Euler operators of the polyhedron. \cgalFigureBegin{figureModifierDesign,modifier_small.png} -Class diagram for the modifier. It illustrates the safe access to an internal representation through an high-level interface. +Class diagram for the modifier. It illustrates the safe access to an internal representation through a high-level interface. \cgalFigureEnd The solution provided here is inspired by the strategy diff --git a/Nef_2/doc/Nef_2/CGAL/Nef_polyhedron_2.h b/Nef_2/doc/Nef_2/CGAL/Nef_polyhedron_2.h index 25df26141eb..858e6df5ba7 100644 --- a/Nef_2/doc/Nef_2/CGAL/Nef_polyhedron_2.h +++ b/Nef_2/doc/Nef_2/CGAL/Nef_polyhedron_2.h @@ -432,16 +432,15 @@ bool is_isolated(Vertex_const_handle v) ; returns one halfedge with source `v`. It's the starting point for the circular iteration over the halfedges with source `v`. -\pre `!is_isolated(v)`. - +\pre `!`\ref is_isolated(Vertex_const_handle) "is_isolated" `(v)`. */ Halfedge_const_handle first_out_edge(Vertex_const_handle v) ; /*! returns the halfedge with source `v` that is the last -in the circular iteration before encountering `first_out_edge(v)` -again. \pre `!is_isolated(v)`. +in the circular iteration before encountering `first_out_edge(v)` again. +\pre `!`\ref is_isolated(Vertex_const_handle) "is_isolated" `(v)`. */ Halfedge_const_handle last_out_edge(Vertex_const_handle v) ; @@ -482,7 +481,8 @@ Face_const_handle face(Halfedge_const_handle e) ; /*! -returns the face incident to `v`. \pre `is_isolated(v)`. +returns the face incident to `v`. +\pre `!`\ref is_isolated(Vertex_const_handle) "is_isolated" `(v)`. */ Face_const_handle face(Vertex_const_handle v) ; @@ -733,13 +733,15 @@ bool is_standard(Vertex_const_handle v) ; /*! returns the standard -point that is the embedding of `v`. \pre `E.is_standard(v)`. +point that is the embedding of `v`. +\pre \ref is_standard(Vertex_const_handle v) "is_standard"(`v`). */ Point point(Vertex_const_handle v) ; /*! returns the ray defining -the non-standard point on the frame. \pre `!E.is_standard(v)`. +the non-standard point on the frame. +\pre !\ref is_standard(Vertex_const_handle v) "is_standard"(`v`). */ Ray ray(Vertex_const_handle v) ; diff --git a/Nef_2/doc/Nef_2/Concepts/ExtendedKernelTraits_2.h b/Nef_2/doc/Nef_2/Concepts/ExtendedKernelTraits_2.h index 1311b83a7d5..69914efc037 100644 --- a/Nef_2/doc/Nef_2/Concepts/ExtendedKernelTraits_2.h +++ b/Nef_2/doc/Nef_2/Concepts/ExtendedKernelTraits_2.h @@ -191,21 +191,20 @@ returns `true` iff bool is_standard(const Point_2& p) ; /*! -returns -the standard point represented by `p`. \pre `K.is_standard(p)`. +returns the standard point represented by `p`. +\pre \ref is_standard(const Point_2& p) "is_standard"(`p`). */ Standard_point_2 standard_point(const Point_2& p) ; /*! -returns -the oriented line representing the bundle of rays defining `p`. -\pre `!K.is_standard(p)`. +returns the oriented line representing the bundle of rays defining `p`. +\pre ! \ref is_standard(const Point_2& p) "is_standard"(`p`). */ Standard_line_2 standard_line(const Point_2& p) ; /*! -a ray -defining `p`. \pre `!K.is_standard(p)`. +a ray defining `p`. +\pre ! \ref is_standard(const Point_2& p) "is_standard"(`p`). */ Standard_ray_2 standard_ray(const Point_2& p) ; diff --git a/Optimal_transportation_reconstruction_2/include/CGAL/OTR_2/Reconstruction_face_base_2.h b/Optimal_transportation_reconstruction_2/include/CGAL/OTR_2/Reconstruction_face_base_2.h index 39c994d671d..a1774c87556 100644 --- a/Optimal_transportation_reconstruction_2/include/CGAL/OTR_2/Reconstruction_face_base_2.h +++ b/Optimal_transportation_reconstruction_2/include/CGAL/OTR_2/Reconstruction_face_base_2.h @@ -17,6 +17,8 @@ #include #include +#include +#include #include @@ -62,6 +64,8 @@ private: FT m_relevance[3]; + std::size_t time_stamp_ = std::size_t(-2); + public: Reconstruction_face_base_2() { @@ -190,6 +194,18 @@ public: for (int i = 0; i < 3; ++i) clean_samples(i); } + + /// For the determinism of Compact_container iterators + ///@{ + typedef Tag_true Has_timestamp; + + std::size_t time_stamp() const { + return time_stamp_; + } + void set_time_stamp(const std::size_t& ts) { + time_stamp_ = ts; + } + ///@} }; //---------------STRUCT LESS FACE_HANDLE--------------------- diff --git a/Optimal_transportation_reconstruction_2/include/CGAL/OTR_2/Reconstruction_vertex_base_2.h b/Optimal_transportation_reconstruction_2/include/CGAL/OTR_2/Reconstruction_vertex_base_2.h index 7df7b10b047..4690b2baa33 100644 --- a/Optimal_transportation_reconstruction_2/include/CGAL/OTR_2/Reconstruction_vertex_base_2.h +++ b/Optimal_transportation_reconstruction_2/include/CGAL/OTR_2/Reconstruction_vertex_base_2.h @@ -16,6 +16,8 @@ #include +#include +#include #include namespace CGAL { @@ -53,6 +55,7 @@ private: int m_sample; Point m_relocated; FT m_relevance; + std::size_t time_stamp_ = std::size_t(-2); public: @@ -110,6 +113,18 @@ public: Point& relocated() { return m_relocated; } bool has_sample_assigned() const { return sample() != -1; } + + /// For the determinism of Compact_container iterators + ///@{ + typedef Tag_true Has_timestamp; + + std::size_t time_stamp() const { + return time_stamp_; + } + void set_time_stamp(const std::size_t& ts) { + time_stamp_ = ts; + } + ///@} }; //---------------STRUCT LESS VERTEX_HANDLE--------------------- template diff --git a/Partition_2/include/CGAL/partition_is_valid_2.h b/Partition_2/include/CGAL/partition_is_valid_2.h index f6a5f2bbd7f..ce3f79b92e2 100644 --- a/Partition_2/include/CGAL/partition_is_valid_2.h +++ b/Partition_2/include/CGAL/partition_is_valid_2.h @@ -153,9 +153,14 @@ partition_is_valid_2 (InputIterator point_first, InputIterator point_last, P_Vertex_map output_vertex_set(poly_first, poly_last, traits); if (output_vertex_set.polygons_overlap()) return false; - +#ifdef CGAL_PARTITION_CHECK_DEBUG int poly_num = 0; - for (; poly_first != poly_last; poly_first++, poly_num++) + #endif + for (; poly_first != poly_last; poly_first++ +#ifdef CGAL_PARTITION_CHECK_DEBUG + , poly_num++ +#endif + ) { vtx_begin = (*poly_first).vertices_begin(); vtx_end = (*poly_first).vertices_end(); diff --git a/Periodic_2_triangulation_2/test/Periodic_2_triangulation_2/include/types.h b/Periodic_2_triangulation_2/test/Periodic_2_triangulation_2/include/types.h index 5426a481478..6fb89645bfb 100644 --- a/Periodic_2_triangulation_2/test/Periodic_2_triangulation_2/include/types.h +++ b/Periodic_2_triangulation_2/test/Periodic_2_triangulation_2/include/types.h @@ -4,8 +4,6 @@ #ifndef P2T2_UNIT_TEST_TYPES_H #define P2T2_UNIT_TEST_TYPES_H -#define _USE_MATH_DEFINES -#include #include #include diff --git a/Periodic_2_triangulation_2/test/Periodic_2_triangulation_2/test_p2t2_delaunay_remove.cpp b/Periodic_2_triangulation_2/test/Periodic_2_triangulation_2/test_p2t2_delaunay_remove.cpp index 81728edfc7a..f1a19bd7e26 100644 --- a/Periodic_2_triangulation_2/test/Periodic_2_triangulation_2/test_p2t2_delaunay_remove.cpp +++ b/Periodic_2_triangulation_2/test/Periodic_2_triangulation_2/test_p2t2_delaunay_remove.cpp @@ -30,7 +30,7 @@ int main() vh_midpoint = t.insert(Point(0, 0) + midpoint); for (int i = 0; i < n; ++i) { - t.insert(Point(0.3 * sin(i * 1.0 / n * 2 * M_PI), 0.3 * cos(i * 1.0 / n * 2 * M_PI)) + midpoint); + t.insert(Point(0.3 * sin(i * 1.0 / n * 2 * CGAL_PI), 0.3 * cos(i * 1.0 / n * 2 * CGAL_PI)) + midpoint); } t.remove(vh_midpoint); assert(t.is_valid(true)); diff --git a/Periodic_3_mesh_3/include/CGAL/refine_periodic_3_mesh_3.h b/Periodic_3_mesh_3/include/CGAL/refine_periodic_3_mesh_3.h index 21f05786b57..bbaffe38f2f 100644 --- a/Periodic_3_mesh_3/include/CGAL/refine_periodic_3_mesh_3.h +++ b/Periodic_3_mesh_3/include/CGAL/refine_periodic_3_mesh_3.h @@ -270,7 +270,7 @@ void project_dummy_points_of_surface(C3T3& c3t3, * `criteria` provides a sizing field to guide the discretization * of 1-dimensional exposed features. * - * \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters + * \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * * \param c3t3 the mesh to be refined. * \param domain the domain to be discretized diff --git a/Periodic_3_triangulation_3/doc/Periodic_3_triangulation_3/CGAL/Periodic_3_triangulation_3.h b/Periodic_3_triangulation_3/doc/Periodic_3_triangulation_3/CGAL/Periodic_3_triangulation_3.h index daec23b7c5d..3bda0596ca6 100644 --- a/Periodic_3_triangulation_3/doc/Periodic_3_triangulation_3/CGAL/Periodic_3_triangulation_3.h +++ b/Periodic_3_triangulation_3/doc/Periodic_3_triangulation_3/CGAL/Periodic_3_triangulation_3.h @@ -1276,7 +1276,7 @@ Cell_handle start, int f) const; /*! Copies the `Cell_handle`s of all cells incident to `v` to the output iterator `cells`. Returns the resulting output iterator. -\pre `v` \f$ \neq\f$ `Vertex_handle()`, `t`.`is_vertex(v)`. +\pre `v` \f$ \neq\f$ `Vertex_handle()` and \ref CGAL::Periodic_3_triangulation_3::is_vertex "is_vertex"(`v`) */ template OutputIterator @@ -1286,7 +1286,7 @@ incident_cells(Vertex_handle v, OutputIterator cells) const; Copies the `Facet`s incident to `v` to the output iterator `facets`. Returns the resulting output iterator. -\pre `v` \f$ \neq\f$ `Vertex_handle()`, `t`.`is_vertex(v)`. +\pre `v` \f$ \neq\f$ `Vertex_handle()` and \ref CGAL::Periodic_3_triangulation_3::is_vertex "is_vertex"(`v`) */ template OutputIterator @@ -1296,7 +1296,7 @@ incident_facets(Vertex_handle v, OutputIterator facets) const; Copies the `Edge`s incident to `v` to the output iterator `edges`. Returns the resulting output iterator. -\pre `v` \f$ \neq\f$ `Vertex_handle()`, `t`.`is_vertex(v)`. +\pre `v` \f$ \neq\f$ `Vertex_handle()` and \ref CGAL::Periodic_3_triangulation_3::is_vertex "is_vertex"(`v`) */ template OutputIterator @@ -1305,7 +1305,7 @@ incident_edges(Vertex_handle v, OutputIterator edges) const; /*! Copies the `Vertex_handle`s of all vertices adjacent to `v` to the output iterator `vertices`. Returns the resulting output iterator. -\pre `v` \f$ \neq\f$ `Vertex_handle()`, `t`.`is_vertex(v)`. +\pre `v` \f$ \neq\f$ `Vertex_handle()` and \ref CGAL::Periodic_3_triangulation_3::is_vertex "is_vertex"(`v`) */ template OutputIterator @@ -1313,7 +1313,7 @@ adjacent_vertices(Vertex_handle v, OutputIterator vertices) const; /*! Returns the degree of `v`, that is, the number of adjacent vertices. -\pre `v` \f$ \neq\f$ `Vertex_handle()`, `t`.`is_vertex(v)`. +\pre `v` \f$ \neq\f$ `Vertex_handle()` and \ref CGAL::Periodic_3_triangulation_3::is_vertex "is_vertex"(`v`) */ size_type degree(Vertex_handle v) const; diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_2/internal/Dehn_hyperbolic_octagon_translation_word.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_2/internal/Dehn_hyperbolic_octagon_translation_word.h index 709da137caf..bfdf687f2ec 100644 --- a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_2/internal/Dehn_hyperbolic_octagon_translation_word.h +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_2/internal/Dehn_hyperbolic_octagon_translation_word.h @@ -89,7 +89,6 @@ private: { Word_idx_type start = 0; Word_idx_type mstart = 0; - Word_idx_type end = 1; Word_idx_type max = 1; Word_idx_type len = 1; std::vector tmp, mvec; @@ -98,7 +97,6 @@ private: { if(is_next_relation_index(w[i], w[i-1])) { - end++; len++; tmp.push_back(w[i]); if(len > max) { @@ -112,7 +110,6 @@ private: tmp.clear(); tmp.push_back(w[i]); start = i; - end = i; len = 0; } } diff --git a/Point_set_processing_3/include/CGAL/IO/write_las_points.h b/Point_set_processing_3/include/CGAL/IO/write_las_points.h index 94ff12182ff..1d9408a0b88 100644 --- a/Point_set_processing_3/include/CGAL/IO/write_las_points.h +++ b/Point_set_processing_3/include/CGAL/IO/write_las_points.h @@ -103,7 +103,13 @@ namespace LAS { inline void output_value(LASpoint& r, const unsigned char& v, const LAS_property::Withheld_flag&) { r.set_withheld_flag(v); } inline void output_value(LASpoint& r, const float& v, const LAS_property::Scan_angle&) - { r.set_scan_angle_rank(char(v)); } + { +#if LAS_TOOLS_VERSION < 250517 + r.set_scan_angle_rank(I8_QUANTIZE(v)); +#else + r.set_scan_angle(v); +#endif + } inline void output_value(LASpoint& r, const unsigned char& v, const LAS_property::User_data&) { r.set_user_data(v); } inline void output_value(LASpoint& r, const unsigned short& v, const LAS_property::Point_source_ID&) diff --git a/Polygon/include/CGAL/Polygon_2_algorithms.h b/Polygon/include/CGAL/Polygon_2_algorithms.h index 2a5997f821d..4bd6f9bdbdd 100644 --- a/Polygon/include/CGAL/Polygon_2_algorithms.h +++ b/Polygon/include/CGAL/Polygon_2_algorithms.h @@ -314,7 +314,7 @@ Bounded_side bounded_side_2(ForwardIterator first, const PolygonTraits& traits); /// Computes if a polygon is clockwise or counterclockwise oriented. -/// \pre `is_simple_2(first, last, traits);` +/// \pre \link CGAL::is_simple_2 `is_simple_2`\endlink(`first`, `last`, `traits`) /// /// \tparam Traits is a model of the concept /// `PolygonTraits_2`. diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/approximated_centroidal_Voronoi_diagram_remeshing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/approximated_centroidal_Voronoi_diagram_remeshing.h index 7ac21d5019d..6f68a6e03f1 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/approximated_centroidal_Voronoi_diagram_remeshing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/approximated_centroidal_Voronoi_diagram_remeshing.h @@ -651,7 +651,7 @@ acvd_impl(TriangleMesh& tmesh, int vi; vertex_descriptor vd; do { - vi = rnd.get_int(0, nb_vertices); + vi = rnd.get_int(0, static_cast(nb_vertices)); vd = *std::next(vertices(tmesh).begin(), vi); } while (get(vertex_cluster_pmap, vd) != -1); @@ -1105,7 +1105,7 @@ acvd_impl(TriangleMesh& tmesh, std::size_t cb = points.size() - 1; if (cb_first == -1) - cb_first = cb; + cb_first = static_cast(cb); std::size_t ct_mapped = valid_cluster_map[ct], cs_mapped = valid_cluster_map[cs]; @@ -1276,8 +1276,8 @@ acvd_impl(TriangleMesh& tmesh, if (clusters[c].nb_vertices == 1) continue; - put(vertex_cluster_pmap, v, clusters.size()); - CGAL_assertion(get(vertex_cluster_pmap, v) == (int) clusters.size()); + put(vertex_cluster_pmap, v, static_cast(clusters.size())); + CGAL_assertion(get(vertex_cluster_pmap, v) == static_cast(clusters.size())); clusters.emplace_back(); } @@ -1291,7 +1291,7 @@ acvd_impl(TriangleMesh& tmesh, for (std::size_t nmi : one_ring) frozen_clusters[nmi] = false; - nb_clusters = clusters.size(); + nb_clusters = static_cast(clusters.size()); frozen_clusters.resize(nb_clusters, false); nb_loops = 0; qem_energy_minimization = false; @@ -1402,7 +1402,7 @@ bool approximated_centroidal_Voronoi_diagram_remeshing(TriangleMesh& tmesh, std::size_t nb_vertices, const NamedParameters& np = parameters::default_values()) { - auto ps = internal::acvd_impl(tmesh, nb_vertices, np); + auto ps = internal::acvd_impl(tmesh, static_cast(nb_vertices), np); CGAL_assertion(is_polygon_soup_a_polygon_mesh(ps.second)); auto vpm = parameters::choose_parameter( diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/fair.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/fair.h index 60829f72623..1cd739fed52 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/fair.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/fair.h @@ -118,7 +118,7 @@ bool fair(TriangleMesh& tmesh, @return `true` if fairing is successful, otherwise no vertices are relocated. - @pre `is_triangle_mesh(tmesh)` + @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink @warning This function involves linear algebra, that is computed using non-exact, floating-point arithmetic. diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h index dc23ff6a462..65d71ac16ad 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h @@ -2071,7 +2071,7 @@ public: std::cout << "\n"; #endif - //backup an halfedge per polyline + //backup a halfedge per polyline std::vector tm1_polylines, tm2_polylines; std::vector polyline_lengths; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polyline.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polyline.h index 3a323ce5312..292334886fe 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polyline.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polyline.h @@ -1447,6 +1447,12 @@ triangulate_hole_polyline_with_cdt(const PointRange& points, vertices[v->info()] = v; } + if (vertices.size()!=cdt.number_of_vertices()) + { + visitor.end_planar_phase(false); + return false; + } + try { for (std::size_t i = 0; i < size; ++i) { diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h index e0ab99d02bb..717411b9c2d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h @@ -337,8 +337,8 @@ struct Throw_at_first_output { * reports all the pairs of faces intersecting between two triangulated surface meshes. * This function depends on the package \ref PkgBoxIntersectionD. * - * \pre `CGAL::is_triangle_mesh(tm1)` - * \pre `CGAL::is_triangle_mesh(tm2)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm1)` \endlink + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm2)` \endlink * * \tparam TriangleMesh a model of `FaceListGraph` * \tparam FaceRange range of `boost::graph_traits::%face_descriptor`, @@ -475,7 +475,7 @@ compute_face_face_intersection(const FaceRange& face_range1, * \attention If a polyline vertex intersects a face, the intersection will * be reported twice (or more if it is on a vertex, edge, or point). * - * \pre `CGAL::is_triangle_mesh(tm)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm)` \endlink * * \tparam TriangleMesh a model of `FaceListGraph` * \tparam FaceRange range of `boost::graph_traits::%face_descriptor`, @@ -607,7 +607,7 @@ compute_face_polyline_intersection(const FaceRange& face_range, * \attention If a polyline vertex intersects a face, the intersection will * be reported twice (even more if it is on a vertex, edge, or point). * - * \pre `CGAL::is_triangle_mesh(tm)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm)` \endlink * * \tparam TriangleMesh a model of `FaceListGraph` * \tparam FaceRange range of `boost::graph_traits::%face_descriptor`, @@ -939,8 +939,8 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1, * reports all the pairs of faces intersecting between two triangulated surface meshes. * This function depends on the package \ref PkgBoxIntersectionD. * - * @pre `CGAL::is_triangle_mesh(tm1)` - * @pre `CGAL::is_triangle_mesh(tm2)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm1)` \endlink + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm2)` \endlink * * \tparam TriangleMesh a model of `FaceListGraph` * \tparam OutputIterator a model of `OutputIterator` holding objects of type @@ -998,7 +998,7 @@ compute_face_face_intersection(const TriangleMesh& tm1, * \attention If a polyline vertex intersects a face or another polyline, the intersection will * be reported twice (even more if it is on a vertex, edge, or point). * - * \pre `CGAL::is_triangle_mesh(tm)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm)` \endlink * * \tparam TriangleMesh a model of `FaceListGraph` * \tparam Polyline a `RandomAccessRange` of points. The point type of the range must be the @@ -1223,10 +1223,10 @@ bool do_intersect(const Polyline& polyline1, * In that case, the meshes must be closed. * This function depends on the package \ref PkgBoxIntersectionD. * - * @pre `CGAL::is_triangle_mesh(tm1)` - * @pre `CGAL::is_triangle_mesh(tm2)` - * @pre `!do_overlap_test_of_bounded_sides || CGAL::is_closed(tm1)` - * @pre `!do_overlap_test_of_bounded_sides || CGAL::is_closed(tm2)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm1)` \endlink + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm2)` \endlink + * @pre `!do_overlap_test_of_bounded_sides` || \link CGAL::is_closed `CGAL::is_closed(tm1)` \endlink + * @pre `!do_overlap_test_of_bounded_sides` || \link CGAL::is_closed `CGAL::is_closed(tm2)` \endlink * * @tparam TriangleMesh a model of `FaceListGraph` * @tparam NamedParameters1 a sequence of \ref bgl_namedparameters "Named Parameters" for `tm1` @@ -1323,7 +1323,7 @@ bool do_intersect(const TriangleMesh& tm1, * and `false` otherwise. * This function depends on the package \ref PkgBoxIntersectionD. * - * @pre `CGAL::is_triangle_mesh(tm)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm)` \endlink * * \tparam TriangleMesh a model of `FaceListGraph` * \tparam PolylineRange a `RandomAccessRange` of `RandomAccessRange` of points. The point type of the range must be the @@ -1390,7 +1390,7 @@ bool do_intersect(const TriangleMesh& tm, * returns `true` if there exists a face of `tm` and a segment of `polyline` which intersect, and `false` otherwise. * This function depends on the package \ref PkgBoxIntersectionD. * - * @pre `CGAL::is_triangle_mesh(tm)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm)` \endlink * * \tparam TriangleMesh a model of `FaceListGraph` * \tparam Polyline a `RandomAccessRange` of points. The point type of the range must be the diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h index 0ee5e95fc40..67450783a00 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h @@ -149,8 +149,8 @@ namespace internal{ * The normal vector to each face is chosen pointing on the side of the face * where its sequence of vertices is seen counterclockwise. * - * @pre `CGAL::is_closed(tm)` - * @pre `CGAL::is_triangle_mesh(tm)` + * @pre \link CGAL::is_closed `CGAL::is_closed(tm)` \endlink + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm)` \endlink * @pre If `tm` contains several connected components, they are oriented consistently. * In other words, the answer to this predicate would be the same for each * isolated connected component. @@ -374,7 +374,7 @@ void reverse_face_orientations(const FaceRange& face_range, PolygonMesh& pmesh) * @param tm a closed triangulated surface mesh * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * -* \pre `CGAL::is_closed(tm)` +* @pre \link CGAL::is_closed `CGAL::is_closed(tm)` \endlink * * \cgalNamedParamsBegin * \cgalParamNBegin{vertex_point_map} @@ -700,7 +700,7 @@ void set_cc_intersecting_pairs( * @param volume_id_map the property map filled by this function with indices of volume components associated to the faces of `tm` * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * - * @pre `CGAL::is_closed(tm)` + * @pre \link CGAL::is_closed `CGAL::is_closed(tm)` \endlink * * \cgalNamedParamsBegin * \cgalParamNBegin{vertex_point_map} @@ -1244,7 +1244,7 @@ volume_connected_components(const TriangleMesh& tm, * @param tm a closed triangulated surface mesh * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * - * @pre `CGAL::is_closed(tm)` + * @pre \link CGAL::is_closed `CGAL::is_closed(tm)` \endlink * * @attention if `tm` is self-intersecting the behavior of this function is undefined. * @@ -1307,7 +1307,7 @@ bool does_bound_a_volume(const TriangleMesh& tm, const NamedParameters& np = par * @param tm a closed triangulated surface mesh * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * - * @pre `CGAL::is_closed(tm)` + * @pre \link CGAL::is_closed `CGAL::is_closed(tm)` \endlink * * \cgalNamedParamsBegin * \cgalParamNBegin{outward_orientation} diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine.h index 38fe4ff0608..0a29099ffc7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine.h @@ -65,7 +65,7 @@ namespace Polygon_mesh_processing { @return pair of `faces_out` and `vertices_out` - \pre `is_triangle_mesh(tmesh)` + @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink @todo current algorithm iterates 10 times at most, since (I guess) there is no termination proof. */ diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index 35c3104dd7e..1f31a9eea89 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -562,7 +562,7 @@ struct Filter_wrapper_for_cap_needle_removal::%face_descriptor` as value type @@ -1371,7 +1371,7 @@ remove_a_border_edge(typename boost::graph_traits::edge_descriptor // removes the degenerate edges from a triangulated surface mesh. // An edge is considered degenerate if its two extremities share the same location. // -// @pre `CGAL::is_triangle_mesh(tmesh)` +// @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink // // @tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph` // @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" @@ -1926,7 +1926,7 @@ bool remove_degenerate_edges(TriangleMesh& tmesh, // A face is considered degenerate if two of its vertices share the same location, // or more generally if all its vertices are collinear. // -// @pre `CGAL::is_triangle_mesh(tmesh)` +// @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink // // @tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph` // @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h index 183fc299f70..9b7c12e70f5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h @@ -523,7 +523,7 @@ self_intersections_impl(const FaceRange& face_range, * * This function depends on the package \ref PkgBoxIntersectionD. * - * @pre `CGAL::is_triangle_mesh(tmesh)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink * * @tparam ConcurrencyTag enables sequential versus parallel algorithm. * Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`. @@ -591,7 +591,7 @@ self_intersections(const FaceRange& face_range, * * This function depends on the package \ref PkgBoxIntersectionD. * - * @pre `CGAL::is_triangle_mesh(tmesh)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink * * @tparam ConcurrencyTag enables sequential versus parallel algorithm. * Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`. @@ -656,7 +656,7 @@ self_intersections(const TriangleMesh& tmesh, * * This function depends on the package \ref PkgBoxIntersectionD. * - * @pre `CGAL::is_triangle_mesh(tmesh)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tm)` \endlink * * @tparam ConcurrencyTag enables sequential versus parallel algorithm. * Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`. @@ -727,7 +727,7 @@ bool does_self_intersect(const FaceRange& face_range, * * This function depends on the package \ref PkgBoxIntersectionD. * - * @pre `CGAL::is_triangle_mesh(tmesh)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink * * @tparam ConcurrencyTag enables sequential versus parallel algorithm. * Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`. diff --git a/Polygon_mesh_processing/include/CGAL/Side_of_triangle_mesh.h b/Polygon_mesh_processing/include/CGAL/Side_of_triangle_mesh.h index 7514f945bae..2963b6b995e 100644 --- a/Polygon_mesh_processing/include/CGAL/Side_of_triangle_mesh.h +++ b/Polygon_mesh_processing/include/CGAL/Side_of_triangle_mesh.h @@ -124,7 +124,8 @@ public: * @param vpmap the property map with the points associated to the vertices of `tmesh` * @param gt an instance of the geometric traits class * - * @pre `CGAL::is_closed(tmesh) && CGAL::is_triangle_mesh(tmesh)` + * @pre \link CGAL::is_closed `CGAL::is_closed(tmesh)` \endlink + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink */ Side_of_triangle_mesh(const TriangleMesh& tmesh, VertexPointMap vpmap, @@ -150,7 +151,8 @@ public: * @param tmesh the triangulated surface mesh bounding the domain to be tested * @param gt an instance of the geometric traits class * - * @pre `CGAL::is_closed(tmesh) && CGAL::is_triangle_mesh(tmesh)` + * @pre \link CGAL::is_closed `CGAL::is_closed(tmesh)` \endlink + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink */ Side_of_triangle_mesh(const TriangleMesh& tmesh, const GeomTraits& gt=GeomTraits()) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 34e7145d474..1203ab95c6e 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -98,11 +98,11 @@ Input (left), non-zero (middle) even-odd (right). \section SectionPolygonRepair_UnionIntersection Union and Intersection Rule -Given several valid polygons these rules apply a %Boolean operation: +Given several valid polygons these rules apply a Boolean operation: In the arrangement of two valid multipolygons with holes, the faces that are in any and both multipolygons with holes are in the resulting multipolygon with holes for a union and intersection, respectively. -While this %Boolean operation works for any two valid multipolygons, in the scope of repairing +While this Boolean operation works for any two valid multipolygons, in the scope of repairing it serves to obtain an approximation from outside and inside when applying union and intersection, respectively, when the input is similar. diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Boolean.h b/Polygon_repair/include/CGAL/Polygon_repair/Boolean.h index a726139d70d..4b9c865bd1d 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Boolean.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Boolean.h @@ -28,13 +28,14 @@ #include +#ifndef DOXYGEN_RUNNING namespace CGAL { namespace Polygon_repair { /*! \ingroup PkgTriangulation2Miscellaneous -\tparam Kernel must be +\tparam Kernel must be model of `ConstrainedDelaunayTriangulationTraits_2` */ template @@ -322,7 +323,7 @@ public: // @todo taken from Polygon_repair and adapted; might be factorized /*! -performs the Boolean operation applying `fct` and returns the result as a multipolygon with holes. +performs the %Boolean operation applying `fct` and returns the result as a multipolygon with holes. \tparam Fct must have the operator `bool operator()(bool, bool)`. */ @@ -378,7 +379,7 @@ performs the Boolean operation applying `fct` and returns the result as a multip /*! -access to the underlying constrained triangulation. +gives access to the underlying constrained triangulation. */ const CDTplus& triangulation() const @@ -393,4 +394,5 @@ access to the underlying constrained triangulation. } // namespace Polygon_repair } //namespace CGAL +#endif // DOXYGEN_RUNNING #endif // CGAL_POLYGON_REPAIR_BOOLEAN_H diff --git a/Polyhedron/include/CGAL/Polyhedron_3.h b/Polyhedron/include/CGAL/Polyhedron_3.h index b732d305895..cb9a6f36021 100644 --- a/Polyhedron/include/CGAL/Polyhedron_3.h +++ b/Polyhedron/include/CGAL/Polyhedron_3.h @@ -1309,7 +1309,7 @@ public: // cut the polyhedron into two parts along the cycle (h,i,j). // Three copies of the vertices and two new triangles will be // created. h,i,j will be incident to the first new triangle. The - // returnvalue will be an halfedge iterator denoting the new + // returnvalue will be a halfedge iterator denoting the new // halfedges of the second new triangle which was h beforehand. // Precondition: h,i,j are distinct, consecutive vertices of the // polyhedron and form a cycle: i.e. `h->vertex() == i->opposite() @@ -1360,7 +1360,7 @@ public: Halfedge_handle join_loop( Halfedge_handle h, Halfedge_handle g) { // glues the boundary of two facets together. Both facets and the - // vertices of g gets removed. Returns an halfedge iterator for h. + // vertices of g gets removed. Returns a halfedge iterator for h. // The invariant `join_loop( h, split_loop( h, i, j))' returns h // and keeps the polyhedron unchanged. Precondition: `HDS' // supports removal of vertices and facets. The facets denoted by @@ -1591,7 +1591,7 @@ public: << std::endl; break; } - // Distinct facets on each side of an halfedge. + // Distinct facets on each side of a halfedge. valid = valid && ( ! check_tag( Supports_halfedge_face()) || D.get_face(i) != D.get_face(i->opposite())); if ( ! valid) { diff --git a/Polyhedron/include/CGAL/Polyhedron_incremental_builder_3.h b/Polyhedron/include/CGAL/Polyhedron_incremental_builder_3.h index bbb2977db06..ac1158fa237 100644 --- a/Polyhedron/include/CGAL/Polyhedron_incremental_builder_3.h +++ b/Polyhedron/include/CGAL/Polyhedron_incremental_builder_3.h @@ -384,7 +384,7 @@ protected: Halfedge_handle lookup_halfedge( size_type w, size_type v) { // Pre: 0 <= w,v < new_vertices - // Case a: It exists an halfedge g from w to v: + // Case a: It exists a halfedge g from w to v: // g must be a border halfedge and the facet of g->opposite() // must be set and different from the current facet. // Set the facet of g to the current facet. Return the diff --git a/Polyline_simplification_2/include/CGAL/Polyline_simplification_2/simplify.h b/Polyline_simplification_2/include/CGAL/Polyline_simplification_2/simplify.h index 9e7fe636d01..cbed7f5b484 100644 --- a/Polyline_simplification_2/include/CGAL/Polyline_simplification_2/simplify.h +++ b/Polyline_simplification_2/include/CGAL/Polyline_simplification_2/simplify.h @@ -229,14 +229,15 @@ public: return n; } - void + int initialize_costs() { int n=0; Constraint_iterator cit = pct.constraints_begin(), e = pct.constraints_end(); for(; cit!=e; ++cit){ - n+= initialize_costs(*cit); + n+=initialize_costs(*cit); } + return n; } bool diff --git a/README.md b/README.md index 2d51a910d8a..2415111daa0 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ or `Triangulation_3`); however some packages serve special needs: More Information ================ * [The CGAL web site](https://www.cgal.org/) -* [Latest CGAL release documentation pages](https://doc.cgal.org/) -* [Latest CGAL master documentation pages, updated once a week](https://cgal.geometryfactory.com/CGAL/doc/master/) +* [Documentation of the latest CGAL release](https://doc.cgal.org/) +* [Documentation of the CGAL `main` branch (updated weekly)](https://cgal.geometryfactory.com/CGAL/doc/master/) * [CGAL daily testsuite results](https://cgal.geometryfactory.com/CGAL/testsuite/) * [Guidelines for CGAL developers](https://github.com/CGAL/cgal/wiki/Guidelines) and [Information for new developers](https://github.com/CGAL/cgal/wiki/Information-for-New-Developers) diff --git a/SMDS_3/include/CGAL/IO/File_maya.h b/SMDS_3/include/CGAL/IO/File_maya.h index 682f9540642..4ef9ccf1c9d 100644 --- a/SMDS_3/include/CGAL/IO/File_maya.h +++ b/SMDS_3/include/CGAL/IO/File_maya.h @@ -150,10 +150,10 @@ output_to_maya(std::ostream& os, { facets_sstr << " setAttr -s " << number_of_triangles << " \".fc[0:" << number_of_triangles-1 << "]\" -type \"polyFaces\" \n"; - int c = 0; + for( Facet_iterator fit = c3t3.facets_in_complex_begin(); fit != c3t3.facets_in_complex_end(); - ++fit, ++c) + ++fit) { int indices[3]; //Weighted_point points[3]; @@ -207,10 +207,10 @@ output_to_maya(std::ostream& os, { facets_sstr << " setAttr -s " << 4*c3t3.number_of_cells_in_complex() << " \".fc[0:" << 4*c3t3.number_of_cells_in_complex()-1 << "]\" -type \"polyFaces\" \n"; - int c = 0; + for( Cell_iterator cit = c3t3.cells_in_complex_begin(); cit != c3t3.cells_in_complex_end(); - ++cit, ++c) + ++cit) { for (int facet_i = 0 ; facet_i < 4 ; ++facet_i) { diff --git a/SMDS_3/include/CGAL/SMDS_3/tet_soup_to_c3t3.h b/SMDS_3/include/CGAL/SMDS_3/tet_soup_to_c3t3.h index da33e68756b..a627a80c7f8 100644 --- a/SMDS_3/include/CGAL/SMDS_3/tet_soup_to_c3t3.h +++ b/SMDS_3/include/CGAL/SMDS_3/tet_soup_to_c3t3.h @@ -566,6 +566,7 @@ bool build_triangulation_from_file(std::istream& is, { using Point_3 = typename Tr::Point; using Subdomain_index = typename Tr::Cell::Subdomain_index; + using Surface_patch_index = typename Tr::Cell::Surface_patch_index; using Facet = std::array; // 3 = id using Tet_with_ref = std::array; // 4 = id @@ -576,7 +577,7 @@ bool build_triangulation_from_file(std::istream& is, std::vector finite_cells; std::vector subdomains; std::vector points; - boost::unordered_map border_facets; + boost::unordered_map border_facets; int dim; int nv, nf, ntet, ref; @@ -632,7 +633,7 @@ bool build_triangulation_from_file(std::istream& is, if(line.find("Triangles") != std::string::npos) { bool has_negative_surface_patch_ids = false; - typename Tr::Cell::Surface_patch_index max_surface_patch_id = 0; + Surface_patch_index max_surface_patch_id{0}; is >> nf; if(verbose) @@ -641,7 +642,7 @@ bool build_triangulation_from_file(std::istream& is, for(int i=0; i> n[0] >> n[1] >> n[2] >> surface_patch_id)) { if(verbose) diff --git a/STL_Extension/doc/STL_Extension/CGAL/Compact_container.h b/STL_Extension/doc/STL_Extension/CGAL/Compact_container.h index 0015f923df9..6579411b243 100644 --- a/STL_Extension/doc/STL_Extension/CGAL/Compact_container.h +++ b/STL_Extension/doc/STL_Extension/CGAL/Compact_container.h @@ -532,7 +532,7 @@ bool is_used(size_type i) const; /*! returns the element at pos `i` in the container. -\pre `is_used(i) == true` and \f$ 0 \leq \f$ `i` \f$ < \f$ `capacity()` +\pre \link is_used(size_type)const `is_used(i)`\endlink`== true` and \f$ 0 \leq \f$ `i` \f$ < \f$ `capacity()` */ const T& operator[] (size_type i) const; @@ -545,7 +545,7 @@ const T& operator[] (size_type i) const; /*! returns the element at pos `i` in the container. -\pre `is_used(i) == true` and \f$ 0 \leq \f$ `i` \f$ < \f$ `capacity()` +\pre \link is_used(size_type)const `is_used(i)`\endlink`== true` and \f$ 0 \leq \f$ `i` \f$ < \f$ `capacity()` */ T& operator[] (size_type i); diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h index ffe386d086c..73c54858bf2 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -185,6 +185,8 @@ CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost) CGAL_add_named_parameter(get_placement_policy_t, get_placement_policy, get_placement) CGAL_add_named_parameter(filter_t, filter, filter) CGAL_add_named_parameter(use_relaxed_order_t, use_relaxed_order, use_relaxed_order) +CGAL_add_named_parameter(line_policies_weight_t, line_policies_weight, line_policies_weight) +CGAL_add_named_parameter(discontinuity_multiplier_t, discontinuity_multiplier, discontinuity_multiplier) //to be documented CGAL_add_named_parameter(face_normal_t, face_normal, face_normal_map) diff --git a/Scripts/developer_scripts/cgal-show-testsuites b/Scripts/developer_scripts/cgal-show-testsuites index 4c813e6c1d3..f01f52e924f 100755 --- a/Scripts/developer_scripts/cgal-show-testsuites +++ b/Scripts/developer_scripts/cgal-show-testsuites @@ -11,10 +11,10 @@ for d in $(seq 0 6); do echo echo -n "## $(date +'%A' -d "now+$d day") night" git "--git-dir=$CGAL_GIT_DIR" log --format='%Cblue%d%Creset %h' --color=always -n1 cgal-dev/testsuite-$(date +'%A' -d "now+$d day") - git "--git-dir=$CGAL_GIT_DIR" log --format='%Cred%h%Creset %C(bold blue)<%an>%Creset %Cgreen(%cr)%Creset (parents: %C(yellow)%p%Creset)%n %s' --first-parent --decorate cgal/master..cgal-dev/testsuite-$(date +'%A' -d "now+$d day") + git "--git-dir=$CGAL_GIT_DIR" log --format='%Cred%h%Creset %C(bold blue)<%an>%Creset %Cgreen(%cr)%Creset (parents: %C(yellow)%p%Creset)%n %s' --first-parent --decorate cgal/main..cgal-dev/testsuite-$(date +'%A' -d "now+$d day") done echo echo '## cgal-dev/integration' -git "--git-dir=$CGAL_GIT_DIR" log --format='%Cred%h%Creset %C(bold blue)<%an>%Creset %Cgreen(%cr)%Creset (parents: %C(yellow)%p%Creset)%n %s' --first-parent --decorate cgal/master..cgal-dev/integration +git "--git-dir=$CGAL_GIT_DIR" log --format='%Cred%h%Creset %C(bold blue)<%an>%Creset %Cgreen(%cr)%Creset (parents: %C(yellow)%p%Creset)%n %s' --first-parent --decorate cgal/main..cgal-dev/integration } |& less -S --raw +G -X diff --git a/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake b/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake index 1d8a21b403e..f8b901b9124 100644 --- a/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake +++ b/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake @@ -210,7 +210,7 @@ endforeach() # make an extra copy of examples and demos for the testsuite if (TESTSUITE) - SET(FMT_ARG "format:SCM branch:%n%H %d%n%nShort log from master:%n") + SET(FMT_ARG "format:SCM branch:%n%H %d%n%nShort log from main:%n") execute_process( COMMAND git --git-dir=${GIT_REPO}/.git --work-tree=${GIT_REPO} log -n1 --format=${FMT_ARG} WORKING_DIRECTORY "${release_dir}" @@ -220,7 +220,7 @@ if (TESTSUITE) file(WRITE ${release_dir}/.scm-branch "${OUT_VAR}") SET(FMT_ARG "%h %s%n parents: %p%n") execute_process( - COMMAND git --git-dir=${GIT_REPO}/.git --work-tree=${GIT_REPO} log --first-parent --format=${FMT_ARG} cgal/master.. + COMMAND git --git-dir=${GIT_REPO}/.git --work-tree=${GIT_REPO} log --first-parent --format=${FMT_ARG} cgal/main.. WORKING_DIRECTORY "${release_dir}" OUTPUT_VARIABLE OUT_VAR ) diff --git a/Scripts/developer_scripts/cgal_git_update_hooks_for_client b/Scripts/developer_scripts/cgal_git_update_hooks_for_client index caac1420362..b214eb2237b 100755 --- a/Scripts/developer_scripts/cgal_git_update_hooks_for_client +++ b/Scripts/developer_scripts/cgal_git_update_hooks_for_client @@ -15,9 +15,9 @@ then exit fi -if [ "$branch" != "master" ]; +if [ "$branch" != "main" ]; then - echo "Call $0 from branch 'master'" + echo "Call $0 from branch 'main'" exit fi diff --git a/Scripts/developer_scripts/create_new_release b/Scripts/developer_scripts/create_new_release index c8ab40d3929..8a058d66f2d 100755 --- a/Scripts/developer_scripts/create_new_release +++ b/Scripts/developer_scripts/create_new_release @@ -28,7 +28,7 @@ usage() { printerr ' --help : prints this usage help' printerr ' --public : also build the corresponding public versions' printerr ' --do-it : the real thing (NOT for local tests! Only for the release' - printerr ' master! Does write operations (updating the version_number,' + printerr ' main! Does write operations (updating the version_number,' printerr ' tag, copying on the web server...)' printerr ' --do-not-tag : when used with --do-it, the tag is not created.' printerr ' --tag : when used without --do-it, the tag is created, but files' diff --git a/Scripts/developer_scripts/git-show-content b/Scripts/developer_scripts/git-show-content index 3d34694a5f7..cfdbb53fa2e 100755 --- a/Scripts/developer_scripts/git-show-content +++ b/Scripts/developer_scripts/git-show-content @@ -14,13 +14,13 @@ and show for each the weight of the commit. [HEAD] is the head of the branch you want to display. Its default value is 'HEAD'. -[BASE] is the base of the range. Its default value is 'cgal/master'. +[BASE] is the base of the range. Its default value is 'cgal/main'. EOF exit 0 fi commit=${1:-HEAD} -base=${2:-cgal/master} +base=${2:-cgal/main} function reset() { git update-ref -d refs/cgal/git-show-content diff --git a/Scripts/developer_scripts/run_doxygen_testsuite b/Scripts/developer_scripts/run_doxygen_testsuite index 5aaab01d981..d76ecc9c1de 100755 --- a/Scripts/developer_scripts/run_doxygen_testsuite +++ b/Scripts/developer_scripts/run_doxygen_testsuite @@ -70,11 +70,11 @@ PATH=/home/cgal-testsuite/local/bin:$PATH export PATH cd "${PWD}/doc/scripts" bash -$- ./process_doc.sh /home/cgal-testsuite/bin/doxygen_1_8_13 /home/cgal-testsuite/bin/doxygen_1_9_6 /srv/CGAL/www/Members/Manual_doxygen_test -if head -2 ../../.scm-branch | grep -q cgal/master; then - rsync -a --delete "/srv/CGAL/www/Members/Manual_doxygen_test/${CGAL_RELEASE_ID}/output2/" /srv/CGAL/www/doc/master/ +if head -2 ../../.scm-branch | grep -q cgal/main; then + rsync -a --delete "/srv/CGAL/www/Members/Manual_doxygen_test/${CGAL_RELEASE_ID}/output2/" /srv/CGAL/www/doc/main/ fi -if sestatus &>/dev/null && [ -d "/srv/CGAL/www/doc/master/" ] && [ -d "/srv/CGAL/www/Members/Manual_doxygen_test/${CGAL_RELEASE_ID}" ]; then - restorecon -R /srv/CGAL/www/doc/master/ /srv/CGAL/www/Members/Manual_doxygen_test/${CGAL_RELEASE_ID} || error "restorecon command failed" +if sestatus &>/dev/null && [ -d "/srv/CGAL/www/doc/main/" ] && [ -d "/srv/CGAL/www/Members/Manual_doxygen_test/${CGAL_RELEASE_ID}" ]; then + restorecon -R /srv/CGAL/www/doc/main/ /srv/CGAL/www/Members/Manual_doxygen_test/${CGAL_RELEASE_ID} || error "restorecon command failed" else error "SELinux is not enabled or the paths do not exist" fi diff --git a/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/Concepts/SegmentDelaunayGraphSite_2.h b/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/Concepts/SegmentDelaunayGraphSite_2.h index 879c81bdcc0..e5d5f1fd47a 100644 --- a/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/Concepts/SegmentDelaunayGraphSite_2.h +++ b/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/Concepts/SegmentDelaunayGraphSite_2.h @@ -239,14 +239,14 @@ Point_2 target_of_supporting_site(unsigned int i); /*! Returns the source point of the `i`-th crossing site of the this site. -\pre `is_segment()` must be `true`, `is_input(i)` must be `false` and `i` must either be `0` or `1`. +\pre `is_segment()` must be `true`, \link is_input(unsigned int) `is_input(i)`\endlink must be `false` and `i` must either be `0` or `1`. */ Point_2 source_of_crossing_site(unsigned int i); /*! Returns the target point of the `i`-th supporting site of the this site. -\pre `is_segment()` must be `true`, `is_input(i)` must be `false` and `i` must either be `0` or `1`. +\pre `is_segment()` must be `true`, \link is_input(unsigned int) `is_input(i)`\endlink must be `false` and `i` must either be `0` or `1`. */ Point_2 target_of_crossing_site(unsigned int i); diff --git a/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/Concepts/SegmentDelaunayGraphStorageSite_2.h b/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/Concepts/SegmentDelaunayGraphStorageSite_2.h index e6605fbcdac..19db7d0c6da 100644 --- a/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/Concepts/SegmentDelaunayGraphStorageSite_2.h +++ b/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/Concepts/SegmentDelaunayGraphStorageSite_2.h @@ -234,14 +234,14 @@ Point_handle target_of_supporting_site(unsigned int i); /*! Returns a handle to the source point of the `i`-th crossing site of the this site. -\pre `is_segment()` must be `true`, `is_input(i)` must be `false` and `i` must either be `0` or `1`. +\pre `is_segment()` must be `true`, \link is_input(unsigned int) `is_input(i)`\endlink must be `false` and `i` must either be `0` or `1`. */ Point_handle source_of_crossing_site(unsigned int i); /*! Returns a handle to the target point of the `i`-th supporting site of the this site. -\pre `is_segment()` must be `true`, `is_input(i)` must be `false` and `i` must either be `0` or `1`. +\pre `is_segment()` must be `true`, \link is_input(unsigned int) `is_input(i)`\endlink must be `false` and `i` must either be `0` or `1`. */ Point_handle target_of_crossing_site(unsigned int i); diff --git a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/internal/Circle_arrangment.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/internal/Circle_arrangment.h index d07c2c7f2a7..74410e611d8 100644 --- a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/internal/Circle_arrangment.h +++ b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/internal/Circle_arrangment.h @@ -38,7 +38,7 @@ * depth 0,1,2+ where depth is the number of inserted open half-circles inserted * that covers this cell in addition this class contains some static functions * that are in this class inorder of sharing its typedefs all the circle is - * always covered by some cell. there can't be an hole + * always covered by some cell. there can't be a hole */ namespace CGAL { diff --git a/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_2_impl.h b/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_2_impl.h index 0c0a87466ca..49577ac7ef5 100644 --- a/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_2_impl.h +++ b/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_2_impl.h @@ -2104,7 +2104,7 @@ void Straight_skeleton_builder_2::EnforceSimpleConnectedness() // For each face with hole(s), create the extra halfedges to bridge the gap between // the skeleton face's border and the holes by shooting a ray from a vertex hole to a halfedge // .first is the source of the ray - // .second is th event creating the intersection of the ray with an halfedge + // .second is th event creating the intersection of the ray with a halfedge // Collect first for all faces, apply later because one might split std::vector > artifical_events; diff --git a/Stream_lines_2/doc/Stream_lines_2/Concepts/VectorField_2.h b/Stream_lines_2/doc/Stream_lines_2/Concepts/VectorField_2.h index 0cdfedfcb1c..8f716bb6f0e 100644 --- a/Stream_lines_2/doc/Stream_lines_2/Concepts/VectorField_2.h +++ b/Stream_lines_2/doc/Stream_lines_2/Concepts/VectorField_2.h @@ -64,7 +64,7 @@ Geom_traits::Iso_rectangle_2 bbox(); /*! returns the vector field value and the local density. -\pre `is_in_domain(p)` must be `true`. +\pre \link is_in_domain `is_in_domain(p)`\endlink must be `true`. */ std::pair get_field(Point_2 p); @@ -76,7 +76,7 @@ bool is_in_domain(Point_2 p); /*! returns the integration step at the point `p`, i.e., the distance between `p` and the next point in the polyline. -\pre `is_in_domain(p)` must be `true`. +\pre \link is_in_domain `is_in_domain(p)`\endlink must be `true`. */ FT get_integration_step(Point_2 p); diff --git a/Stream_lines_2/include/CGAL/Regular_grid_2.h b/Stream_lines_2/include/CGAL/Regular_grid_2.h index 2ef9c992a01..2e9eb33bc58 100644 --- a/Stream_lines_2/include/CGAL/Regular_grid_2.h +++ b/Stream_lines_2/include/CGAL/Regular_grid_2.h @@ -93,7 +93,7 @@ public: template inline -typename Regular_grid_2::Geom_traits::Iso_rectangle_2 +typename StreamLinesTraits_2::Iso_rectangle_2 Regular_grid_2::bbox() const { return typename Geom_traits::Iso_rectangle_2(0.0, 0.0, diff --git a/Stream_lines_2/include/CGAL/Triangular_field_2.h b/Stream_lines_2/include/CGAL/Triangular_field_2.h index 1dd733409c7..df6eb6807f4 100644 --- a/Stream_lines_2/include/CGAL/Triangular_field_2.h +++ b/Stream_lines_2/include/CGAL/Triangular_field_2.h @@ -134,7 +134,7 @@ protected: template inline -typename Triangular_field_2::Geom_traits::Iso_rectangle_2 +typename StreamLinesTraits_2::Iso_rectangle_2 Triangular_field_2::bbox() const { return typename Geom_traits::Iso_rectangle_2(minx, miny, maxx, diff --git a/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt b/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt index 53a1a22b2cf..fa8d6fd5249 100644 --- a/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt +++ b/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt @@ -522,14 +522,14 @@ The Medit format, using file extension `.mesh`, is a format used by the Medit so In \cgal, it is used to represent 3D meshes. A precise specification of the format is available in this report, -in the appendices (section 7.2.1, page 36). +in the appendices (Section 7.2.1, Page 36). The following \cgal data structures can be exported into the `.mesh` file format: - `CGAL::Mesh_complex_3_in_triangulation_3`, using the function - \link CGAL::IO::write_MEDIT(std::ostream &, const CGAL::Mesh_complex_3_in_triangulation_3< T3, CornerIndex, CurveIndex >&, const NamedParameters &) `CGAL::IO::write_MEDIT(` \endlink, and + \link CGAL::IO::write_MEDIT(std::ostream &, const CGAL::Mesh_complex_3_in_triangulation_3< T3, CornerIndex, CurveIndex >&, const NamedParameters &) `CGAL::IO::write_MEDIT()` \endlink, and - `CGAL::Conforming_constrained_Delaunay_triangulation_3`, using the function - \link CGAL::IO::write_MEDIT(std::ostream &os, const CGAL::Conforming_constrained_Delaunay_triangulation_3< Traits, Tr > &ccdt, const NamedParameters& np) `CGAL::IO::write_MEDIT(` \endlink. + \link CGAL::IO::write_MEDIT(std::ostream &os, const CGAL::Conforming_constrained_Delaunay_triangulation_3< Traits, Tr > &ccdt, const NamedParameters& np) `CGAL::IO::write_MEDIT()` \endlink. \section IOStreamTetgen Tetgen File Format diff --git a/Stream_support/examples/Stream_support/read_WKT.cpp b/Stream_support/examples/Stream_support/read_WKT.cpp index 9c7ed82d578..0ebd9f27bf9 100644 --- a/Stream_support/examples/Stream_support/read_WKT.cpp +++ b/Stream_support/examples/Stream_support/read_WKT.cpp @@ -1,15 +1,17 @@ #include +#include #include #include #include #include -typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Projection_traits_xy_3 Kernel; int main(int argc, char* argv[]) { - typedef CGAL::Point_2 Point; + typedef Kernel::Point_2 Point; typedef std::vector MultiPoint; typedef std::vector LineString; @@ -23,6 +25,7 @@ int main(int argc, char* argv[]) MultiPoint points; MultiLineString polylines; MultiPolygon polygons; + CGAL::IO::read_WKT(is, points,polylines,polygons); for(Point p : points) @@ -30,8 +33,9 @@ int main(int argc, char* argv[]) for(LineString ls : polylines) for(Point p : ls) std::cout< gc(mp); - internal::read_wkt_or_fail_stream(in, line, gc); + found = internal::read_wkt_or_fail_stream(in, line, gc); break; } } - + if(! found){ + return false; + } return !in.fail(); } @@ -168,16 +171,20 @@ bool read_linestring_WKT(std::istream& in, LineString& polyline) { std::string line; + bool found = false; while(internal::get_a_new_line(in, line)) { if(line.substr(0, 10).compare("LINESTRING") == 0) { CGAL::internal::Geometry_container gc(polyline); - internal::read_wkt_or_fail_stream(in, line, gc); + found = internal::read_wkt_or_fail_stream(in, line, gc); break; } } + if(! found){ + return false; + } return !in.fail(); } @@ -199,6 +206,7 @@ bool read_multi_linestring_WKT(std::istream& in, MultiLineString& mls) { std::string line; + bool found = false; while(internal::get_a_new_line(in, line)) { if(line.substr(0, 15).compare("MULTILINESTRING") == 0) @@ -209,7 +217,7 @@ bool read_multi_linestring_WKT(std::istream& in, std::vector pr_range; CGAL::internal::Geometry_container, boost::geometry::multi_linestring_tag> gc(pr_range); - internal::read_wkt_or_fail_stream(in, line, gc); + found = internal::read_wkt_or_fail_stream(in, line, gc); for(LineString& ls : gc) { mls.push_back(*ls.range); } @@ -217,7 +225,9 @@ bool read_multi_linestring_WKT(std::istream& in, break; } } - + if(! found){ + return false; + } return !in.fail(); } @@ -237,15 +247,19 @@ bool read_polygon_WKT(std::istream& in, Polygon& polygon) { std::string line; + bool found = false; while(internal::get_a_new_line(in, line)) { if(line.substr(0, 7).compare("POLYGON") == 0) { - internal::read_wkt_or_fail_stream(in, line, polygon); + found = internal::read_wkt_or_fail_stream(in, line, polygon); internal::pop_back_if_equal_to_front(polygon); break; } } + if(! found){ + return false; + } return !in.fail(); } @@ -268,12 +282,13 @@ bool read_multi_polygon_WKT(std::istream& in, MultiPolygon& polygons) { std::string line; + bool found = false; while(internal::get_a_new_line(in, line)) { if(line.substr(0, 12).compare("MULTIPOLYGON") == 0) { CGAL::internal::Geometry_container gc(polygons); - internal::read_wkt_or_fail_stream(in, line, gc); + found = internal::read_wkt_or_fail_stream(in, line, gc); for(auto& p : gc) internal::pop_back_if_equal_to_front(p); @@ -281,7 +296,9 @@ bool read_multi_polygon_WKT(std::istream& in, break; } } - + if(! found){ + return false; + } return !in.fail(); } @@ -461,6 +478,7 @@ bool read_WKT(std::istream& is, { auto fail = [&is]() { is.clear(is.rdstate() | std::ios::failbit); return false; }; + bool found = false; std::string line; while(is >> std::ws && is.good() && std::getline(is, line)) { @@ -490,44 +508,57 @@ bool read_WKT(std::istream& is, { Point p; if(!IO::read_point_WKT(iss, p) ) return fail(); + found = true; points.push_back(p); } else if(type == "LINESTRING") { LineString l; if(!IO::read_linestring_WKT(iss, l)) return fail(); + found = true; polylines.push_back(std::move(l)); } else if(type == "POLYGON") { Polygon p; if(!IO::read_polygon_WKT(iss, p)) return fail(); - if(!p.outer_boundary().is_empty()) + if(!p.outer_boundary().is_empty()){ + found = true; polygons.push_back(std::move(p)); + } } else if(type == "MULTIPOINT") { MultiPoint mp; if(!IO::read_multi_point_WKT(iss, mp)) return fail(); - for(const Point& point : mp) + for(const Point& point : mp){ points.push_back(point); + found = true; + } } else if(type == "MULTILINESTRING") { MultiLineString mls; if(!IO::read_multi_linestring_WKT(iss, mls)) return fail(); - for(LineString& ls : mls) + for(LineString& ls : mls){ polylines.push_back(std::move(ls)); + found = true; + } } else if(type == "MULTIPOLYGON") { MultiPolygon mp; if(!IO::read_multi_polygon_WKT(iss, mp)) return fail(); - for(Polygon& poly : mp) + for(Polygon& poly : mp){ polygons.push_back(std::move(poly)); + found = true; + } } } + if(!found){ + return false; + } return !is.fail(); } diff --git a/Stream_support/test/Stream_support/test_WKT.cpp b/Stream_support/test/Stream_support/test_WKT.cpp index 7af1e011668..5a2ff5492c9 100644 --- a/Stream_support/test/Stream_support/test_WKT.cpp +++ b/Stream_support/test/Stream_support/test_WKT.cpp @@ -24,6 +24,42 @@ typedef std::vector MultiPoint typedef std::vector MultiLinestring3; //////////////////////////////////////////////////////////////////////////////////////////////////// +bool test_mismatch() +{ + Point3 p(1,2,3); + MultiPoint3 mq; + std::stringstream ss; + CGAL::IO::write_point_WKT(ss, p); + bool b = CGAL::IO::read_multi_point_WKT(ss, mq); + assert(!b); + return !b; +} + +bool test_read2Dinto3D() +{ + Point p(10,11); + Point3 p3(1,2,3); + std::stringstream ss; + CGAL::IO::write_point_WKT(ss, p); + bool b = CGAL::IO::read_point_WKT(ss, p3); + assert(p.x() == p3.x()); + assert(p.y() == p3.y()); + assert(p3.z() == 0); + + Point q(12,13); + Linestring ls; + Linestring3 ls3; + ls.push_back(p); + ls.push_back(q); + CGAL::IO::write_linestring_WKT(ss, ls); + b = CGAL::IO::read_linestring_WKT(ss, ls3); + assert(ls3[0]==p3); + assert(ls3[1] == Point3(12,13,0)); + assert(b); + return b; +} + + bool test_WKT_3D() { { @@ -337,6 +373,10 @@ int main() assert(ok); ok = test_WKT_3D(); assert(ok); + ok = test_mismatch(); + assert(ok); + ok = test_read2Dinto3D(); + assert(ok); return EXIT_SUCCESS; } diff --git a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h index d38d7ffeabd..ad339ef5ca7 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h @@ -2680,8 +2680,12 @@ collect_garbage(Visitor &visitor) for (i=0; i +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick; + +int main() +{ +CGAL::Surface_mesh mesh; + auto f0 = mesh.add_face(); + mesh.add_face(); + mesh.remove_face(f0); + + auto v0 = mesh.add_vertex(); + mesh.add_vertex(); + mesh.remove_vertex(v0); + + auto e0 = mesh.add_edge(); + mesh.add_edge(); + mesh.remove_edge(edge(e0,mesh)); + + + mesh.collect_garbage(); + + return 0; +} diff --git a/Surface_mesh_deformation/include/CGAL/Surface_mesh_deformation.h b/Surface_mesh_deformation/include/CGAL/Surface_mesh_deformation.h index 7b36a1ce486..e3682606748 100644 --- a/Surface_mesh_deformation/include/CGAL/Surface_mesh_deformation.h +++ b/Surface_mesh_deformation/include/CGAL/Surface_mesh_deformation.h @@ -617,7 +617,7 @@ public: * * @param vd a control vertex * @param t translation vector - * \pre `is_control_vertex(vd)` + * \pre \link is_control_vertex `is_control_vertex(vd)`\endlink */ template void translate(vertex_descriptor vd, const Vect& t) @@ -662,7 +662,7 @@ public: * @param vd a control vertex * @param to_rotation_center the vector to translate the origin to the center of the rotation * @param quat quaternion of the rotation - * \pre `is_control_vertex(vd)` + * \pre \link is_control_vertex `is_control_vertex(vd)`\endlink * \pre `quad` represents a rotation */ template @@ -709,7 +709,7 @@ public: /** * Returns the target position of a control vertex. * \param vd a control vertex - * \pre `is_control_vertex(vd)` + * \pre \link is_control_vertex `is_control_vertex(vd)`\endlink */ const Point& target_position(vertex_descriptor vd) { diff --git a/Surface_mesh_segmentation/include/CGAL/mesh_segmentation.h b/Surface_mesh_segmentation/include/CGAL/mesh_segmentation.h index 98af65ee5b2..f056eb09250 100644 --- a/Surface_mesh_segmentation/include/CGAL/mesh_segmentation.h +++ b/Surface_mesh_segmentation/include/CGAL/mesh_segmentation.h @@ -66,7 +66,7 @@ sdf_values( const TriangleMesh& triangle_mesh, * It is possible to compute raw SDF values (without postprocessing). In such a case, * -1 is used to indicate when no SDF value could be computed for a facet. * - * @pre `is_triangle_mesh(triangle_mesh)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink * * @tparam TriangleMesh a model of `FaceListGraph` * @tparam SDFPropertyMap a `ReadWritePropertyMap` with `boost::graph_traits::%face_descriptor` as key and `double` as value type @@ -119,7 +119,7 @@ sdf_values( const TriangleMesh& triangle_mesh, * * See the section \ref Surface_mesh_segmentationPostprocessing for more details. * - * @pre `is_triangle_mesh(triangle_mesh)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink * @pre Raw values should be greater or equal to 0. -1 indicates when no value could be computed * * @tparam TriangleMesh a model of `FaceListGraph` @@ -157,7 +157,7 @@ sdf_values_postprocessing(const TriangleMesh& triangle_mesh, * \note There is no direct relation between the parameter `number_of_clusters` * and the final number of segments after segmentation. However, setting a large number of clusters will result in a detailed segmentation of the mesh with a large number of segments. * - * @pre `is_triangle_mesh(triangle_mesh)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink * @pre `number_of_clusters > 0` * * @tparam TriangleMesh a model of `FaceListGraph` @@ -253,7 +253,7 @@ segmentation_via_sdf_values(const TriangleMesh& triangle_mesh, * it is more efficient to first compute the SDF values using `CGAL::sdf_values()` and use them in different calls to * `CGAL::segmentation_from_sdf_values()`. * - * @pre `is_triangle_mesh(triangle_mesh)` + * @pre \link CGAL::is_triangle_mesh `CGAL::is_triangle_mesh(tmesh)` \endlink * @pre `number_of_clusters > 0` * * @tparam TriangleMesh a model of `FaceListGraph` diff --git a/Surface_mesh_simplification/benchmark/Surface_mesh_simplification/CMakeLists.txt b/Surface_mesh_simplification/benchmark/Surface_mesh_simplification/CMakeLists.txt new file mode 100644 index 00000000000..cf960bece45 --- /dev/null +++ b/Surface_mesh_simplification/benchmark/Surface_mesh_simplification/CMakeLists.txt @@ -0,0 +1,17 @@ +# Created by the script cgal_create_cmake_script_with_options +# This is the CMake script for compiling a set of CGAL applications. + +cmake_minimum_required(VERSION 3.12...3.31) +project(Surface_mesh_simplification_Examples) + +# CGAL and its components +find_package(CGAL REQUIRED) + +find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) +include(CGAL_Eigen3_support) +if(TARGET CGAL::Eigen3_support) + create_single_source_cgal_program("bench_garland_heckbert.cpp") + target_link_libraries(bench_garland_heckbert PRIVATE CGAL::Eigen3_support) +else() + message(STATUS "NOTICE: Garland-Heckbert polices require the Eigen library, which has not been found; related examples will not be compiled.") +endif() diff --git a/Surface_mesh_simplification/benchmark/Surface_mesh_simplification/bench_garland_heckbert.cpp b/Surface_mesh_simplification/benchmark/Surface_mesh_simplification/bench_garland_heckbert.cpp new file mode 100644 index 00000000000..08b2cf3aeb2 --- /dev/null +++ b/Surface_mesh_simplification/benchmark/Surface_mesh_simplification/bench_garland_heckbert.cpp @@ -0,0 +1,156 @@ +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#define TAG CGAL::Parallel_if_available_tag + +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::FT FT; +typedef Kernel::Point_3 Point_3; +typedef CGAL::Surface_mesh Surface_mesh; + +namespace SMS = CGAL::Surface_mesh_simplification; +namespace PMP = CGAL::Polygon_mesh_processing; + +typedef SMS::GarlandHeckbert_plane_policies Classic_plane; +typedef SMS::GarlandHeckbert_probabilistic_plane_policies Prob_plane; +typedef SMS::GarlandHeckbert_triangle_policies Classic_tri; +typedef SMS::GarlandHeckbert_probabilistic_triangle_policies Prob_tri; +typedef SMS::GarlandHeckbert_policies Classic_plane_and_line; + +// Old policies composed with line policies +typedef SMS::internal::GarlandHeckbert_line_policies Line_quadric; +typedef SMS::internal::GarlandHeckbert_composed_policies Proba_plane_and_line; +typedef SMS::internal::GarlandHeckbert_composed_policies Classic_tri_plus_line; +typedef SMS::internal::GarlandHeckbert_composed_policies Proba_tri_plus_line; + +double mean_aspect_ratio(Surface_mesh& mesh) +{ + double total_aspect_ratio = 0; + double total_area = 0; + for(auto f: faces(mesh)){ + // double a = PMP::face_area(f, mesh); + double a = 1.; + total_aspect_ratio += a*CGAL::to_double(PMP::face_aspect_ratio(f, mesh)); + total_area += a; + } + return total_aspect_ratio/total_area; +} + +template +double collapse_gh(Surface_mesh& mesh, + const double ratio, + GHPolicies gh_policies) +{ + std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); + + SMS::Edge_count_ratio_stop_predicate stop(ratio); + + // Garland&Heckbert simplification policies + + typedef typename GHPolicies::Get_cost GH_cost; + typedef typename GHPolicies::Get_placement GH_placement; + typedef SMS::Bounded_normal_change_filter<> Filter; + + const GH_cost& gh_cost = gh_policies.get_cost(); + const GH_placement& gh_placement = gh_policies.get_placement(); + + SMS::edge_collapse(mesh, stop, CGAL::parameters::get_cost(gh_cost).filter(Filter()).get_placement(gh_placement)); + + std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); + + return (std::chrono::duration_cast(end_time - start_time).count()) / 1000.; +} + +std::string getFileNameWithoutExtension(const std::string& filePath) +{ + std::filesystem::path path(filePath); + return path.stem().string(); // 'stem' gets the filename without extension +} + +int main(int argc, char** argv) +{ + Surface_mesh mesh; + const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/cube-meshed.off"); + PMP::duplicate_non_manifold_vertices(mesh); + PMP::autorefine(mesh); + + if(!CGAL::IO::read_polygon_mesh(filename, mesh)) + { + std::cerr << "Failed to read input mesh: " << filename << std::endl; + return EXIT_FAILURE; + } + + if(!CGAL::is_triangle_mesh(mesh)) + { + std::cerr << "Input geometry is not triangulated." << std::endl; + return EXIT_FAILURE; + } + + const double ratio = (argc > 2) ? std::stod(argv[2]) : 0.2; + std::cout << ratio << std::endl; + std::cout << "\n\nPolicy Approx_Hausdorff Dist_points_to_input mean_aspect_ratio running_time" << std::endl; + auto collapse=[&](std::string policy){ + using CGAL::Surface_mesh_simplification::make_GarlandHeckbert_plane_and_line_policies; + Surface_mesh tmesh(mesh); + double time; + if(policy == "Classic_plane") + time=collapse_gh(tmesh, ratio, Classic_plane(tmesh)); + else if(policy == "Classic_triangle") + time=collapse_gh(tmesh, ratio, Classic_tri(tmesh)); + else if(policy == "Prob_plane") + time=collapse_gh(tmesh, ratio, Prob_plane(tmesh)); + else if(policy == "Prob_triangle") + time=collapse_gh(tmesh, ratio, Prob_tri(tmesh)); + // else if(policy == "Plane_plus_line_0.1") + // time=collapse_gh(tmesh, ratio, make_GarlandHeckbert_plane_and_line_policies(tmesh, CGAL::parameters::line_policies_weight(0.1))); + else if(policy == "Plane_plus_line_0.01") + time=collapse_gh(tmesh, ratio, make_GarlandHeckbert_plane_and_line_policies(tmesh, CGAL::parameters::line_policies_weight(0.01))); + else if(policy == "Plane_plus_line_0.001") + time=collapse_gh(tmesh, ratio, make_GarlandHeckbert_plane_and_line_policies(tmesh, CGAL::parameters::line_policies_weight(0.001))); + // else if(policy == "Classic_tri_line") + // time=collapse_gh(tmesh, ratio, Classic_tri_plus_line(tmesh, 100)); + // else if(policy == "Proba_plane_line") + // time=collapse_gh(tmesh, ratio, Proba_plane_and_line(tmesh, Prob_plane(tmesh), Line_quadric(tmesh), 100)); + // else if(policy == "Proba_tri_line") + // time=collapse_gh(tmesh, ratio, Proba_tri_plus_line(tmesh, Prob_tri(tmesh), Line_quadric(tmesh), 100)); + + std::cout << policy << " " << PMP::approximate_symmetric_Hausdorff_distance(tmesh, mesh) + << " " << PMP::max_distance_to_triangle_mesh(tmesh.points(),mesh) + << " " << mean_aspect_ratio(tmesh) + << " " << time << std::endl; + CGAL::IO::write_polygon_mesh("out_"+policy+"_"+std::to_string(ratio)+".off", tmesh, CGAL::parameters::stream_precision(17)); + }; + + collapse("Classic_plane"); + collapse("Classic_triangle"); + collapse("Prob_plane"); + collapse("Prob_triangle"); + // collapse("Plane_plus_line_0.1"); + collapse("Plane_plus_line_0.01"); + collapse("Plane_plus_line_0.001"); + // collapse("Classic_tri_line"); + // collapse("Proba_plane_line"); + // collapse("Proba_tri_line"); + // collapse("Plane_plus_line_0.001"); + + return EXIT_SUCCESS; +} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_and_line_policies.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_and_line_policies.h new file mode 100644 index 00000000000..0325f5093ff --- /dev/null +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_and_line_policies.h @@ -0,0 +1,96 @@ +namespace CGAL { +namespace Surface_mesh_simplification { + +/*! +\ingroup PkgSurfaceMeshSimplificationRef + +The class `GarlandHeckbert_plane_and_line_policies` regroups the cost and placement policies +based on the Garland-Heckbert "Plane and line" strategy of Liu and colleagues \cgalCite{liu2025linequadrics}. + +This policy enhances the original Garland-Heckbert quadric error metrics +by adding to the cost the distance to the line passing through the input vertices and aligned with their normals. +Compared to the "classic" plane strategy, this strategy improves the speed and the quality of the result +(see Section \ref SurfaceMeshSimplificationGarlandHeckbertStrategy). + +\note Both the cost and the placement policies must be used together as they internally use +and share information associating quadrics to vertices. +Note however, that they may still be wrapped with behavior-modifying classes +such as `Constrained_placement` or `Bounded_normal_change_placement`. + +\tparam TriangleMesh is the type of surface mesh being simplified, and must be a model + of the `MutableFaceGraph` and `HalfedgeListGraph` concepts. +\tparam GeomTraits must be a model of `Kernel`. If you have passed a traits class in the optional + named parameters in the call to `edge_collapse()`, the types must be identical. + +These policies depend on the third party \ref thirdpartyEigen library. + +\sa `GarlandHeckbert_policies` +\sa `GarlandHeckbert_plane_policies` +\sa `GarlandHeckbert_probabilistic_plane_policies` +\sa `GarlandHeckbert_triangle_policies` +\sa `GarlandHeckbert_probabilistic_triangle_policies` +*/ +template +class GarlandHeckbert_plane_and_line_policies +{ +public: + /// The type of the Garland-Heckbert cost functor, a model of the concept `GetCost` + typedef unspecified_type Get_cost; + + /// The type of the Garland-Heckbert placement functor, a model of the concept `GetPlacement` + typedef unspecified_type Get_placement; + + /// \name Creation + /// @{ + + /*! + initializes the Garland-Heckbert plane and line policies. + + \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" + + \param tmesh the triangle mesh + \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below + + \cgalNamedParamsBegin + \cgalParamNBegin{vertex_normal_map} + \cgalParamDescription{a property map associating to each vertex of `tmesh` a normal direction for that vertex} + \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` + as key type and `Vector_3` as value type} + \cgalParamDefault{an internal map filled using `CGAL::Polygon_mesh_processing::compute_vertex_normals`} + \cgalParamNEnd + \cgalParamNBegin{discontinuity_multiplier} + \cgalParamDescription{a multiplier of the error value for boundary edges to preserve the boundaries} + \cgalParamType{double} + \cgalParamDefault{100} + \cgalParamNEnd + \cgalParamNBegin{line_policies_weight} + \cgalParamDescription{a value that defines the weight of the line policies compared to the plane policies} + \cgalParamType{double} + \cgalParamDefault{0.01} + \cgalParamNEnd + \cgalNamedParamsEnd + */ + template + GarlandHeckbert_plane_and_line_policies(TriangleMesh& tmesh, const NamedParameters &np = parameters::default_values()); + + /// @} + + /// \name Accessors + /// @{ + + const Get_cost& get_cost() const; + const Get_placement& get_placement() const; + + /// @} + +}; + +/*! +creates a Garland-Heckbert plane and line policies object. +*/ +template +GarlandHeckbert_plane_and_line_policies make_GarlandHeckbert_plane_and_line_policies(TriangleMesh& tmesh, + const NamedParameters& np = parameters::default_values()); + +} // namespace Surface_mesh_simplification +} // namespace CGAL diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_policies.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_policies.h index 033c589de71..271502c26ca 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_policies.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_policies.h @@ -25,6 +25,7 @@ These policies depend on the third party \ref thirdpartyEigen library. \sa `GarlandHeckbert_probabilistic_plane_policies` \sa `GarlandHeckbert_triangle_policies` \sa `GarlandHeckbert_probabilistic_triangle_policies` +\sa `GarlandHeckbert_plane_and_line_policies` */ template class GarlandHeckbert_plane_policies diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_policies.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_policies.h index 5a5bc1edd4d..f5c464d524f 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_policies.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_policies.h @@ -4,55 +4,19 @@ namespace Surface_mesh_simplification { /*! \ingroup PkgSurfaceMeshSimplificationRef -\deprecated This class is deprecated since \cgal 5.5 and the introduction of variations -of Garland-Heckbert policies (Section \ref SurfaceMeshSimplificationGarlandHeckbertStrategy). -The class `GarlandHeckbert_plane_policies` is the modern equivalent to this class. +This class is an alias for the current state-of-the-art Garland-Heckbert policies +(see Section \ref SurfaceMeshSimplificationGarlandHeckbertStrategy). +It is currently an alias of `GarlandHeckbert_plane_and_line_policies`. -The class `GarlandHeckbert_policies` regroups the cost and placement policies -based on the Garland-Heckbert strategy (Section \ref SurfaceMeshSimplificationGarlandHeckbertStrategy), -both oracles must indeed be used together as they internally use and share information -associating quadrics to vertices. - -Note however, that they may still be wrapped with behavior modifying classes -such as `Constrained_placement` or `Bounded_normal_change_placement`. - -\tparam TriangleMesh is the type of surface mesh being simplified, and must be a model - of the `MutableFaceGraph` and `HalfedgeListGraph` concepts. -\tparam GeomTraits must be a model of `Kernel`. If you have passed a traits class in the optional - named parameters in the call to `edge_collapse()`, the types must be identical. - -These policies depend on the third party \ref thirdpartyEigen library. +\sa `GarlandHeckbert_plane_policies` +\sa `GarlandHeckbert_probabilistic_plane_policies` +\sa `GarlandHeckbert_triangle_policies` +\sa `GarlandHeckbert_probabilistic_triangle_policies` +\sa `GarlandHeckbert_plane_and_line_policies` */ -template -class GarlandHeckbert_policies -{ -public: - /// The type of the Garland Heckbert cost functor, a model of the concept `GetCost` - typedef unspecified_type Get_cost; - - /// The type of the Garland Heckbert placement functor, a model of the concept `GetPlacement` - typedef unspecified_type Get_placement; - - /// \name Creation - /// @{ - - /*! - Initializes the Garland-Heckbert policies. - */ - GarlandHeckbert_policies(TriangleMesh& tmesh); - - /// @} - - /// \name Accessors - /// @{ - - const Get_cost& get_cost() const; - const Get_placement& get_placement() const; - - /// @} - -}; +template +using GarlandHeckbert_policies = GarlandHeckbert_plane_and_line_policies; } // namespace Surface_mesh_simplification } // namespace CGAL diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_plane_policies.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_plane_policies.h index bb214bab663..63601750de0 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_plane_policies.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_plane_policies.h @@ -26,6 +26,7 @@ These policies depend on the third party \ref thirdpartyEigen library. \sa `GarlandHeckbert_plane_policies` \sa `GarlandHeckbert_triangle_policies` \sa `GarlandHeckbert_probabilistic_triangle_policies` +\sa `GarlandHeckbert_plane_and_line_policies` */ template class GarlandHeckbert_probabilistic_plane_policies diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_triangle_policies.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_triangle_policies.h index 7e3692cb275..5d0870d0c52 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_triangle_policies.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_triangle_policies.h @@ -26,6 +26,7 @@ These policies depend on the third party \ref thirdpartyEigen library. \sa `GarlandHeckbert_plane_policies` \sa `GarlandHeckbert_probabilistic_plane_policies` \sa `GarlandHeckbert_triangle_policies` +\sa `GarlandHeckbert_plane_and_line_policies` */ template class GarlandHeckbert_probabilistic_triangle_policies diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Doxyfile.in b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Doxyfile.in index 377bdfd7c1a..64e5fa4ddf3 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Doxyfile.in +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Doxyfile.in @@ -2,4 +2,5 @@ PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - Triangulated Surface Mesh Simplification" -HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/sappho.jpg +HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/sappho.png \ + ${CGAL_PACKAGE_DOC_DIR}/fig/octocat.png diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/PackageDescription.txt b/Surface_mesh_simplification/doc/Surface_mesh_simplification/PackageDescription.txt index a597bb02a77..548234de826 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/PackageDescription.txt +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/PackageDescription.txt @@ -49,7 +49,8 @@ - `CGAL::Surface_mesh_simplification::GarlandHeckbert_probabilistic_plane_policies` - `CGAL::Surface_mesh_simplification::GarlandHeckbert_triangle_policies` - `CGAL::Surface_mesh_simplification::GarlandHeckbert_probabilistic_triangle_policies` -- `CGAL::Surface_mesh_simplification::GarlandHeckbert_policies` (deprecated) +- `CGAL::Surface_mesh_simplification::GarlandHeckbert_plane_and_line_policies` +- `CGAL::Surface_mesh_simplification::GarlandHeckbert_policies` \cgalCRPSection{Policy Enhancements} - `CGAL::Surface_mesh_simplification::Constrained_placement` diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Surface_mesh_simplification.txt b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Surface_mesh_simplification.txt index 8ef4268e07f..9991fcfcdc7 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Surface_mesh_simplification.txt +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Surface_mesh_simplification.txt @@ -188,21 +188,38 @@ face normals). This variance naturally deteriorates the tightness of the result, hand it enables creating more uniform triangulations and the approach is more tolerant to noise, while still maintaining feature sensitivity. +Another extension of the Garland–Heckbert approach was introduced by Liu et al. \cgalCite{liu2025linequadrics}, +who enhance the classic plane-based quadric error metrics with line quadrics. +More precisely, line quadrics, which encode the distance to a line, are defined at all input vertices using the supporting lines of the normals. +These quadrics are then combined with the classic plane quadrics, but with a small weight (0.01 by default). +This results in more uniform triangulations, while preserving the tightness of the approximation. + \cgalFigureAnchor{SurfaceMeshSimplification_GH}
    - +
    \cgalFigureCaptionBegin{SurfaceMeshSimplification_GH} Sappho's Head model (leftmost, 34882 vertices). From left to right, simplified output (1745 vertices) and symmetric Hausdorff distance -for the four Garland-Heckbert variations: plane (0.217912), probabilistic -plane (0.256801), triangle (0.268872), and probabilistic triangle (0.490846). +for the five Garland-Heckbert variations: plane (0.217912), probabilistic +plane (0.256801), triangle (0.268872), probabilistic triangle (0.490846) and plane and line (0.173344). +\cgalFigureCaptionEnd + +\cgalFigureAnchor{SurfaceMeshSimplification_GH_octocat} +
    + +
    +\cgalFigureCaptionBegin{SurfaceMeshSimplification_GH_octocat} +Octocat model (top-left, 18944 vertices). +From top-left to bottom-right, simplified output (1895 vertices) and symmetric Hausdorff distance +for the five Garland-Heckbert variations: plane (0.19631), probabilistic +plane (0.59446), triangle (0.377533), probabilistic triangle (0.891286) and plane and line (0.304001). \cgalFigureCaptionEnd \subsection Surface_mesh_simplificationCostStrategyPolicies Cost Strategy Policies The cost strategy used by the algorithm is selected by means of three policies: -`GetPlacement`, `GetCost`, and `Filter`. +`GetPlacement`, `GetCost`, and `PlacementFilter`. The `GetPlacement` policy is called to compute the new position for the remaining vertex after the halfedge-collapse. It returns @@ -400,8 +417,8 @@ steps of the simplification algorithm. Each Garland-Heckbert simplification strategy is implemented with a single class that regroups both the cost and the placement policies, which must be used together as they share vertex quadric data. -The classic strategy of using plane-based quadric error metrics is implemented with the class -`Surface_mesh_simplification::GarlandHeckbert_plane_policies`. +The state-of-the-art strategy of combining plane and line-based quadric error metrics is implemented with the class +`Surface_mesh_simplification::GarlandHeckbert_policies`. Although both policies must be used together, it is still possible to wrap either policy using behavior modifiers such as `Surface_mesh_simplification::Bounded_normal_change_placement`. @@ -420,5 +437,7 @@ The implementation of the Garland-Heckbert simplification policies is the result of Baskın Şenbaşlar (Google Summer of Code 2019), and Julian Komaromy (Google Summer of Code 2021) They both were mentored by Mael Rouxel-Labbé, who also contributed to the code and to the documentation. +Léo Valque added the `Surface_mesh_simplification::GarlandHeckbert_plane_and_line_policies` functionality in \cgal 6.2. + */ } /* namespace CGAL */ diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/octocat.png b/Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/octocat.png new file mode 100644 index 00000000000..413b2eaa0e6 Binary files /dev/null and b/Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/octocat.png differ diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/sappho.png b/Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/sappho.png new file mode 100644 index 00000000000..f8ba8ef513b Binary files /dev/null and b/Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/sappho.png differ diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/sappho.jpg b/Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/sappho_old.jpg similarity index 100% rename from Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/sappho.jpg rename to Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/sappho_old.jpg diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_garland_heckbert.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_garland_heckbert.cpp index 7d2f9500b5d..3e0b632d0f8 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_garland_heckbert.cpp +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_garland_heckbert.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -24,6 +24,7 @@ typedef SMS::GarlandHeckbert_plane_policies typedef SMS::GarlandHeckbert_probabilistic_plane_policies Prob_plane; typedef SMS::GarlandHeckbert_triangle_policies Classic_tri; typedef SMS::GarlandHeckbert_probabilistic_triangle_policies Prob_tri; +typedef SMS::GarlandHeckbert_plane_and_line_policies Plane_and_line; template void collapse_gh(Surface_mesh& mesh, @@ -37,16 +38,17 @@ void collapse_gh(Surface_mesh& mesh, typedef typename GHPolicies::Get_cost GH_cost; typedef typename GHPolicies::Get_placement GH_placement; - typedef SMS::Bounded_normal_change_placement Bounded_GH_placement; + typedef SMS::Bounded_normal_change_filter<> Filter; GHPolicies gh_policies(mesh); const GH_cost& gh_cost = gh_policies.get_cost(); const GH_placement& gh_placement = gh_policies.get_placement(); - Bounded_GH_placement placement(gh_placement); + Filter filter; int r = SMS::edge_collapse(mesh, stop, CGAL::parameters::get_cost(gh_cost) - .get_placement(placement)); + .filter(filter) + .get_placement(gh_placement)); std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); @@ -59,7 +61,7 @@ void collapse_gh(Surface_mesh& mesh, // Usage: // ./command [input] [ratio] [policy] [output] -// policy can be "cp" (classic plane), "ct" (classic triangle), "pp" (probabilistic plane), "pt" (probabilistic triangle) +// policy can be "cp" (classic plane), "ct" (classic triangle), "pp" (probabilistic plane), "pt" (probabilistic triangle), "pl" (plane and line) int main(int argc, char** argv) { Surface_mesh mesh; @@ -91,8 +93,10 @@ int main(int argc, char** argv) collapse_gh(mesh, ratio); else if(policy == "pp") collapse_gh(mesh, ratio); - else + else if(policy == "pt") collapse_gh(mesh, ratio); + else + collapse_gh(mesh, ratio); CGAL::IO::write_polygon_mesh((argc > 4) ? argv[4] : "out.off", mesh, CGAL::parameters::stream_precision(17)); diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_and_line_policies.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_and_line_policies.h new file mode 100644 index 00000000000..ae415434165 --- /dev/null +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_and_line_policies.h @@ -0,0 +1,126 @@ +// Copyright (c) 2025 GeometryFactory (France). 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) : Leo Valque + +#ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_GARLANDHECKBERT_PLANE_AND_LINE_POLICIES_H +#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_GARLANDHECKBERT_PLANE_AND_LINE_POLICIES_H + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace CGAL { +namespace Surface_mesh_simplification { + +namespace internal { + +// Helpers to perform computation in the constructor GH_plane_and_line_policies before calling the constructor of Base +template< typename TriangleMesh = void, typename NamedParameters = void> +struct GH_helper{ + typedef typename GetGeomTraits::type GT; + typedef typename GT::Vector_3 Vector_3; + typedef typename GT::FT FT; + + typedef dynamic_vertex_property_t Vertex_normal_tag; + typedef typename boost::property_map::type Vertex_normal_dmap; + typedef typename internal_np::Lookup_named_param_def::type Vertex_normal_map; + + NamedParameters np; + GH_helper(const NamedParameters &np_):np(np_){ } + + Vertex_normal_map vnm(TriangleMesh& tmesh) const{ + using parameters::choose_parameter; + using parameters::is_default_parameter; + using parameters::get_parameter; + constexpr bool must_compute_vertex_normals = is_default_parameter::value; + + Vertex_normal_map vertex_normals = choose_parameter(get_parameter(np, internal_np::vertex_normal_map), + get(Vertex_normal_tag(), tmesh)); + if constexpr(must_compute_vertex_normals){ + Polygon_mesh_processing::compute_vertex_normals(tmesh, vertex_normals, np); + } + return vertex_normals; + } + + double lw() const{ + using parameters::choose_parameter; + using parameters::get_parameter; + return choose_parameter(get_parameter(np, internal_np::line_policies_weight), 0.01); + } + + double dm() const{ + using parameters::choose_parameter; + using parameters::get_parameter; + + return choose_parameter(get_parameter(np, internal_np::discontinuity_multiplier), 100); + } +}; + +} // namespace internal + +template +class GarlandHeckbert_plane_and_line_policies + : public internal::GarlandHeckbert_composed_policies, + internal::GarlandHeckbert_line_policies, + true> +{ + typedef GarlandHeckbert_plane_policies GH_plane_polices; + typedef internal::GarlandHeckbert_line_policies GH_line_polices; + typedef internal::GarlandHeckbert_composed_policies Base; + +public: + typedef typename Base::Quadric_calculator Quadric_calculator; + + typedef typename GeomTraits::FT FT; + +public: + template + GarlandHeckbert_plane_and_line_policies(TriangleMesh& tmesh, const NP& np = parameters::default_values()): + Base(tmesh, + GH_plane_polices(tmesh), + GH_line_polices(tmesh, internal::GH_helper(np).vnm(tmesh)), + FT(1.)/internal::GH_helper(np).lw(), + FT(1.), + internal::GH_helper(np).dm()) + { } + +public: + using Base::operator(); + using Base::get_cost; + using Base::get_placement; +}; + +template +GarlandHeckbert_plane_and_line_policies::type> + make_GarlandHeckbert_plane_and_line_policies(TriangleMesh& tmesh, + const NamedParameters& np = parameters::default_values()){ + typedef typename GetGeomTraits::type GT; + return GarlandHeckbert_plane_and_line_policies(tmesh, np); +} + +} // namespace Surface_mesh_simplification +} // namespace CGAL + +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_GARLANDHECKBERT_PLANE_AND_LINE_POLICIES_H \ No newline at end of file diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_policies.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_policies.h index 8fbc2cba3fc..3f99ca2c751 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_policies.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_plane_policies.h @@ -32,6 +32,15 @@ class Plane_quadric_calculator public: Plane_quadric_calculator() { } + template + Mat_4 construct_quadric_from_vertex(typename boost::graph_traits::vertex_descriptor /*v*/, + const TriangleMesh& /*tmesh*/, + const VertexPointMap /*point_map*/, + const GeomTraits& /*gt*/) const + { + return Mat_4::Zero(); + } + template Mat_4 construct_quadric_from_edge(typename boost::graph_traits::halfedge_descriptor he, const TriangleMesh& tmesh, diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_policies.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_policies.h index c45bfe2a65f..1be69571481 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_policies.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_policies.h @@ -21,12 +21,13 @@ #include #include #include +#include namespace CGAL { namespace Surface_mesh_simplification { template -using GarlandHeckbert_policies CGAL_DEPRECATED = GarlandHeckbert_plane_policies; +using GarlandHeckbert_policies = GarlandHeckbert_plane_and_line_policies; } // namespace Surface_mesh_simplification } // namespace CGAL diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_plane_policies.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_plane_policies.h index e533b381ded..f7c439c845a 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_plane_policies.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_plane_policies.h @@ -74,6 +74,15 @@ public: } public: + template + Mat_4 construct_quadric_from_vertex(typename boost::graph_traits::vertex_descriptor /*v*/, + const TriangleMesh& /*tmesh*/, + const VertexPointMap /*point_map*/, + const GeomTraits& /*gt*/) const + { + return Mat_4::Zero(); + } + template Mat_4 construct_quadric_from_edge(const halfedge_descriptor he, const TriangleMesh& tmesh, diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_triangle_policies.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_triangle_policies.h index d8ef45f13f0..8d13f92ae63 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_triangle_policies.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_probabilistic_triangle_policies.h @@ -48,7 +48,7 @@ private: // this is only used when we fall back to probabilistic planes for the discontinuous edges, // the actual triangle quadric calculation only uses the normal variance - static constexpr FT position_variance_factor = 1; + static constexpr FT position_variance_factor = 0.1; Face_variance_map m_face_variance_map; @@ -74,6 +74,15 @@ public: } public: + template + Mat_4 construct_quadric_from_vertex(typename boost::graph_traits::vertex_descriptor /*v*/, + const TriangleMesh& /*tmesh*/, + const VertexPointMap /*point_map*/, + const GeomTraits& /*gt*/) const + { + return Mat_4::Zero(); + } + // we don't have a sensible way to construct a triangle quadric // from an edge, so we fall back to probabilistic plane quadrics here template diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_triangle_policies.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_triangle_policies.h index 1e8b2eaee10..5318623cf5d 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_triangle_policies.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_triangle_policies.h @@ -32,6 +32,15 @@ class Triangle_quadric_calculator public: Triangle_quadric_calculator() { } + template + Mat_4 construct_quadric_from_vertex(typename boost::graph_traits::vertex_descriptor /*v*/, + const TriangleMesh& /*tmesh*/, + const VertexPointMap /*point_map*/, + const GeomTraits& /*gt*/) const + { + return Mat_4::Zero(); + } + template Mat_4 construct_quadric_from_edge(typename boost::graph_traits::halfedge_descriptor he, const TriangleMesh& tmesh, diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_composed_policies.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_composed_policies.h new file mode 100644 index 00000000000..dba5e665f87 --- /dev/null +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_composed_policies.h @@ -0,0 +1,144 @@ +// Copyright (c) 2025 GeometryFactory (France). 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) : Leo Valque + +#ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_GARLANDHECKBERT_COMPOSED_POLICIES_H +#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_GARLANDHECKBERT_COMPOSED_POLICIES_H + +#include + +#include +#include +#include + +namespace CGAL { +namespace Surface_mesh_simplification { +namespace internal { + +/* +This policy was created to combine the line policy with the existing ones. +The composition of some quadrics is always invertible, but this is not necessarily true for all composed quadrics. +`invertible` boolean parameter reflects this distinction. +*/ +template +class Composed_quadric_calculator +{ + typedef typename GarlandHeckbert_matrix_types::Mat_4 Mat_4; + typedef typename GarlandHeckbert_matrix_types::Col_4 Col_4; + typedef typename GarlandHeckbert_matrix_types::Row_4 Row_4; + + Quadric_calculator_1 quadric_calculator_1; + Quadric_calculator_2 quadric_calculator_2; + double weight_1; + double weight_2; + +public: + Composed_quadric_calculator(const Quadric_calculator_1& qc1, const Quadric_calculator_2& qc2, double w1 = 1., double w2 = 1.) + : quadric_calculator_1(qc1) + , quadric_calculator_2(qc2) + , weight_1(w1) + , weight_2(w2) {} + Composed_quadric_calculator(double w1 = 1., double w2 = 1.) + : weight_1(w1) + , weight_2(w2) {} + + template + Mat_4 construct_quadric_from_vertex(typename boost::graph_traits::vertex_descriptor v, + const TriangleMesh& tmesh, + const VertexPointMap point_map, + const GeomTraits& gt) const + { + return weight_1 * quadric_calculator_1.construct_quadric_from_vertex(v, tmesh, point_map, gt) + + weight_2 * quadric_calculator_2.construct_quadric_from_vertex(v, tmesh, point_map, gt); + } + + template + Mat_4 construct_quadric_from_edge(typename boost::graph_traits::halfedge_descriptor he, + const TriangleMesh& tmesh, + const VertexPointMap point_map, + const GeomTraits& gt) const + { + return weight_1 * quadric_calculator_1.construct_quadric_from_edge(he, tmesh, point_map, gt) + + weight_2 * quadric_calculator_2.construct_quadric_from_edge(he, tmesh, point_map, gt); + } + + template + Mat_4 construct_quadric_from_face(typename boost::graph_traits::face_descriptor f, + const TriangleMesh& tmesh, + const VertexPointMap point_map, + const GeomTraits& gt) const + { + return weight_1 * quadric_calculator_1.construct_quadric_from_face(f, tmesh, point_map, gt) + + weight_2 * quadric_calculator_2.construct_quadric_from_face(f, tmesh, point_map, gt); + } + + + Col_4 construct_optimal_point(const Mat_4& quadric, + const Col_4& p0, + const Col_4& p1) const + { + if constexpr(invertible) + return construct_optimal_point_invertible(quadric); + else + return construct_optimal_point_singular(quadric, p0, p1); + } +}; + +template +class GarlandHeckbert_composed_policies + : public internal::GarlandHeckbert_cost_and_placement< + internal::Composed_quadric_calculator, + TriangleMesh, GeomTraits> +{ +public: + typedef internal::Composed_quadric_calculator + Quadric_calculator; + +private: + typedef internal::GarlandHeckbert_cost_and_placement< + Quadric_calculator, TriangleMesh, GeomTraits> Base; + typedef GarlandHeckbert_composed_policies Self; + +public: + typedef Self Get_cost; + typedef Self Get_placement; + + typedef typename GeomTraits::FT FT; + +public: + GarlandHeckbert_composed_policies(TriangleMesh& tmesh, + double w1=1., double w2=1.,const double dm = 100) + : Base(tmesh, Quadric_calculator(w1, w2), FT(dm)) + { } + + GarlandHeckbert_composed_policies(TriangleMesh& tmesh, + GH_policies_1 ghp1, + GH_policies_2 ghp2, + double w1=1., double w2=1.,const double dm = 100) + : Base(tmesh, Quadric_calculator(ghp1.quadric_calculator(), ghp2.quadric_calculator(), w1, w2), FT(dm)) + { } + +public: + const Get_cost& get_cost() const { return *this; } + const Get_placement& get_placement() const { return *this; } + + using Base::operator(); +}; + +} // namespace internal +} // namespace Surface_mesh_simplification +} // namespace CGAL + +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_GARLANDHECKBERT_COMPOSED_POLICIES_H \ No newline at end of file diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_functions.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_functions.h index 6d954dd8b65..444053c2893 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_functions.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_functions.h @@ -17,8 +17,13 @@ #include #include +#include + #include +#include +#include + #include namespace CGAL { @@ -236,8 +241,8 @@ construct_optimal_point_singular(const typename GarlandHeckbert_matrix_types svd pseudo-inverse + Eigen::JacobiSVD svd_decomp(mat, Eigen::ComputeThinU | Eigen::ComputeThinV); + svd_decomp.setThreshold(1e-5); + + opt_pt(0) = mean.x(); + opt_pt(1) = mean.y(); + opt_pt(2) = mean.z(); + opt_pt(3) = 1.; + + opt_pt += svd_decomp.solve(Col_4(0,0,0,1) - mat * opt_pt); +#endif + return opt_pt; } } @@ -508,6 +533,45 @@ construct_prob_triangle_quadric_from_face(typename boost::graph_traits +typename GarlandHeckbert_matrix_types::Mat_4 +construct_line_quadric_from_normal(const typename GeomTraits::Vector_3& normal, + const typename GeomTraits::Point_3& point, + const GeomTraits& gt) +{ + typedef typename GeomTraits::Vector_3 Vector_3; + + auto cp = gt.construct_cross_product_vector_3_object(); + auto plane = gt.construct_plane_3_object(); + auto c_point = gt.construct_point_3_object(); + auto base= gt.construct_base_vector_3_object(); + + Vector_3 x = base(plane(c_point(0,0,0),normal), 1); + CGAL::Polygon_mesh_processing::internal::normalize(x, gt); + Vector_3 y = cp(x,normal); + + return construct_classic_plane_quadric_from_normal(x, point, gt)+construct_classic_plane_quadric_from_normal(y, point, gt); +} + +/* +template +typename GarlandHeckbert_matrix_types::Mat_4 +construct_line_quadric_from_vertex(const typename boost::graph_traits::vertex_descriptor v, + const TriangleMesh& mesh, + const VertexPointMap vpm, + const GeomTraits& gt) +{ + typedef typename GeomTraits::Vector_3 Vector_3; + + const Vector_3 normal = Polygon_mesh_processing::compute_vertex_normal(v, mesh, parameters::geom_traits(gt).vertex_point_map(vpm)); + return construct_line_quadric_from_normal(normal, get(vpm, v), gt); +} +*/ + //////////////////////////////////////////////////////////////////////////////////////////////////// /// PROB VARIANCE //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_line_policies.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_line_policies.h new file mode 100644 index 00000000000..03eed8a4235 --- /dev/null +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_line_policies.h @@ -0,0 +1,132 @@ +// Copyright (c) 2025 GeometryFactory (France). 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) : Leo Valque + +#ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_GARLANDHECKBERT_LINE_POLICIES_H +#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_GARLANDHECKBERT_LINE_POLICIES_H + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +namespace CGAL { +namespace Surface_mesh_simplification { +namespace internal { + +/* +This policy is not useful on its own; it is designed to be combined with another policy using a small weight. +Therefore, it is kept internal. +*/ +template +class Line_quadric_calculator +{ + typedef typename GarlandHeckbert_matrix_types::Mat_4 Mat_4; + typedef typename GarlandHeckbert_matrix_types::Col_4 Col_4; + typedef typename GarlandHeckbert_matrix_types::Row_4 Row_4; + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename GeomTraits::Vector_3 Vector_3; + +private: + std::function m_vertex_normal_map; + +public: + Line_quadric_calculator() = delete; + + template + Line_quadric_calculator(const VNM vnm) + : m_vertex_normal_map([vnm](vertex_descriptor v) -> Vector_3{ return get(vnm, v); }) + { } + + template + Mat_4 construct_quadric_from_vertex(typename boost::graph_traits::vertex_descriptor v, + const TriangleMesh& /*tmesh*/, + const VertexPointMap point_map, + const GeomTraits& gt) const + { + return construct_line_quadric_from_normal(m_vertex_normal_map(v), get(point_map, v), gt); + } + + template + Mat_4 construct_quadric_from_edge(typename boost::graph_traits::halfedge_descriptor /*he*/, + const TriangleMesh& /*tmesh*/, + const VertexPointMap /*point_map*/, + const GeomTraits& /*gt*/) const + { + return Mat_4::Zero(); + } + + template + Mat_4 construct_quadric_from_face(typename boost::graph_traits::face_descriptor /*f*/, + const TriangleMesh& /*tmesh*/, + const VertexPointMap /*point_map*/, + const GeomTraits& /*gt*/) const + { + return Mat_4::Zero(); + } + + /* + // Since these policies are never used alone but always composed with another one, this code is not used + Col_4 construct_optimal_point(const Mat_4& quadric, + const Col_4& p0, + const Col_4& p1) const + { + return construct_optimal_point_singular(quadric, p0, p1); + } + */ +}; + +template >::type > +class GarlandHeckbert_line_policies + : public internal::GarlandHeckbert_cost_and_placement< + internal::Line_quadric_calculator, TriangleMesh, GeomTraits> +{ +public: + typedef internal::Line_quadric_calculator Quadric_calculator; + +private: + typedef internal::GarlandHeckbert_cost_and_placement< + Quadric_calculator, TriangleMesh, GeomTraits> Base; + typedef GarlandHeckbert_line_policies Self; + +public: + typedef Self Get_cost; + typedef Self Get_placement; + + typedef typename GeomTraits::FT FT; + +public: + template + GarlandHeckbert_line_policies(TriangleMesh& tmesh, const VNM vnm) + : Base(tmesh, Quadric_calculator(vnm), 0) + { } + +public: + const Get_cost& get_cost() const { return *this; } + const Get_placement& get_placement() const { return *this; } + + using Base::operator(); +}; + +} // namespace internal +} // namespace Surface_mesh_simplification +} // namespace CGAL + +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_GARLANDHECKBERT_LINE_POLICIES_H \ No newline at end of file diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_policy_base.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_policy_base.h index 590747a252b..289a1e4125b 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_policy_base.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_policy_base.h @@ -72,6 +72,10 @@ public: { m_cost_matrices = get(Cost_property(), tmesh); } + + Quadric_calculator quadric_calculator() const{ + return m_quadric_calculator; + } }; template @@ -129,6 +133,15 @@ public: } public: + template + Mat_4 construct_quadric(const vertex_descriptor v, + const TriangleMesh& tmesh, + const VertexPointMap vpm, + const GeomTraits& gt) const + { + return quadric_calculator().construct_quadric_from_vertex(v, tmesh, vpm, gt); + } + template Mat_4 construct_quadric(const halfedge_descriptor he, const TriangleMesh& tmesh, @@ -154,10 +167,8 @@ public: const VertexPointMap vpm, const GeomTraits& gt) const { - Mat_4 zero_mat = Mat_4::Zero(); - for(vertex_descriptor v : vertices(tmesh)) - put(vcm(), v, zero_mat); + put(vcm(), v, construct_quadric(v, tmesh, vpm, gt)); for(face_descriptor f : faces(tmesh)) { diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/internal/Edge_collapse.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/internal/Edge_collapse.h index 2335bb5a843..e895fd9edc4 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/internal/Edge_collapse.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/internal/Edge_collapse.h @@ -590,8 +590,6 @@ loop() { CGAL_SMS_TRACE(0, "Collapsing edges..."); - CGAL_assertion_code(size_type non_collapsable_count = 0); - // Pops and processes each edge from the PQ std::optional opt_h; @@ -658,8 +656,6 @@ loop() } else { - CGAL_assertion_code(++non_collapsable_count); - m_visitor.OnNonCollapsable(profile); CGAL_SMS_TRACE(1, edge_to_string(*opt_h) << " NOT Collapsible (filter)" ); @@ -679,8 +675,6 @@ loop() } else { - CGAL_assertion_code(++non_collapsable_count); - m_visitor.OnNonCollapsable(profile); CGAL_SMS_TRACE(1, edge_to_string(*opt_h) << " NOT Collapsible (topology)" ); diff --git a/Surface_mesh_simplification/package_info/Surface_mesh_simplification/dependencies b/Surface_mesh_simplification/package_info/Surface_mesh_simplification/dependencies index e6a49c552eb..4237bce9f6f 100644 --- a/Surface_mesh_simplification/package_info/Surface_mesh_simplification/dependencies +++ b/Surface_mesh_simplification/package_info/Surface_mesh_simplification/dependencies @@ -18,3 +18,4 @@ STL_Extension Spatial_searching Stream_support Surface_mesh_simplification +Polygon_mesh_processing diff --git a/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_garland_heckbert_variations.cpp b/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_garland_heckbert_variations.cpp index 32505153d06..2384787c044 100644 --- a/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_garland_heckbert_variations.cpp +++ b/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_garland_heckbert_variations.cpp @@ -32,6 +32,7 @@ typedef SMS::GarlandHeckbert_plane_policies typedef SMS::GarlandHeckbert_probabilistic_plane_policies Prob_plane; typedef SMS::GarlandHeckbert_triangle_policies Classic_tri; typedef SMS::GarlandHeckbert_probabilistic_triangle_policies Prob_tri; +typedef SMS::GarlandHeckbert_plane_and_line_policies Classic_plane_and_line; // settings for benchmarking - throw away the first n_burns results and keep the n_samples samples constexpr int n_burns = 1; @@ -41,6 +42,7 @@ constexpr std::size_t classic_plane_index = 0; constexpr std::size_t prob_plane_index = 1; constexpr std::size_t classic_tri_index = 2; constexpr std::size_t prob_tri_index = 3; +constexpr std::size_t plane_and_line_index = 4; // ================================================================================================= // ================================================================================================= @@ -89,7 +91,8 @@ get_all_meshes(const std::vector& filenames) template Surface_mesh edge_collapse(Surface_mesh& mesh, - const double ratio = 0.2) + const double ratio, + const Policy p) { typedef typename Policy::Get_cost Cost; typedef typename Policy::Get_placement Placement; @@ -97,8 +100,6 @@ Surface_mesh edge_collapse(Surface_mesh& mesh, std::cout << "Edge collapse mesh of " << num_edges(mesh) << " edges. Policy: " << typeid(Policy).name() << std::endl; - const Policy p { mesh, 100 }; - const Cost& cost = p.get_cost(); const Placement& unbounded_placement = p.get_placement(); Bounded_placement bounded_placement(unbounded_placement); @@ -117,6 +118,12 @@ Surface_mesh edge_collapse(Surface_mesh& mesh, return mesh; } +template +Surface_mesh edge_collapse(Surface_mesh& mesh, + const double ratio = 0.2){ + return edge_collapse(mesh, ratio, Policy(mesh)); +} + // ================================================================================================= // ================================================================================================= // ================================================================================================= @@ -145,21 +152,6 @@ void time_mesh(const TriangleMesh mesh, << "Average: " << elapsed_ns / n_samples << " (ms)" << std::endl; } -template -void time_policy(const TriangleMesh& mesh, - std::ostream& out, - const std::string& policy) -{ - if(policy == "classic_plane") - time_mesh(mesh, out); - else if(policy == "classic_tri") - time_mesh(mesh, out); - else if(policy == "prob_plane") - time_mesh(mesh, out); - else if(policy == "prob_tri") - time_mesh(mesh, out); -} - template void time_all_policies(const TriangleMesh& mesh, std::ostream& out) @@ -170,6 +162,7 @@ void time_all_policies(const TriangleMesh& mesh, time_mesh(mesh, out); time_mesh(mesh, out); time_mesh(mesh, out); + time_mesh(mesh, out); } // ================================================================================================= @@ -196,15 +189,16 @@ double hausdorff_error(const TriangleMesh& mesh, // calculate approximate Hausdorff errors for all different policies at the same decimation ratio template -std::array hausdorff_errors(const TriangleMesh& mesh, +std::array hausdorff_errors(const TriangleMesh& mesh, double ratio) { - std::array ret { {0, 0, 0, 0} }; + std::array ret { {0, 0, 0, 0, 0} }; ret[classic_plane_index] = hausdorff_error(mesh, ratio); ret[prob_plane_index] = hausdorff_error(mesh, ratio); ret[classic_tri_index] = hausdorff_error(mesh, ratio); ret[prob_tri_index] = hausdorff_error(mesh, ratio); + ret[plane_and_line_index] = hausdorff_error(mesh, ratio); return ret; } @@ -218,13 +212,14 @@ void hausdorff_errors(const TriangleMesh& mesh, for(InputIt it=begin; it!=end; ++it) { - std::array errs = hausdorff_errors(mesh, *it); + std::array errs = hausdorff_errors(mesh, *it); out << " -- Hausdorff error for collapse with ratio: " << *it << '\n'; out << "classic plane: " << errs[classic_plane_index] << std::endl; out << "prob plane : " << errs[prob_plane_index] << std::endl; out << "classic tri : " << errs[classic_tri_index] << std::endl; out << "prob tri : " << errs[prob_tri_index] << std::endl; + out << "plane + line : " << errs[plane_and_line_index] << std::endl; } } @@ -252,11 +247,13 @@ void gather_face_aspect_ratio(const TriangleMesh& mesh, Surface_mesh pp = mesh; Surface_mesh ct = mesh; Surface_mesh pt = mesh; + Surface_mesh pl = mesh; edge_collapse(cp); edge_collapse(pp); edge_collapse(ct); edge_collapse(pt); + edge_collapse(pl); out << "Face aspect-ratio: classic plane\n"; write_aspect_ratios(cp, out); @@ -266,6 +263,8 @@ void gather_face_aspect_ratio(const TriangleMesh& mesh, write_aspect_ratios(ct, out); out << "Face aspect-ratio: prob triangle\n"; write_aspect_ratios(pt, out); + out << "Face aspect-ratio: classic plane and line\n"; + write_aspect_ratios(pl, out); } template @@ -287,6 +286,21 @@ void run(const std::pair& input) gather_face_aspect_ratio(input.first, out); } +template +void test_parameters_plane_and_line(const TriangleMesh& mesh){ + using CGAL::Surface_mesh_simplification::make_GarlandHeckbert_plane_and_line_policies; + using PMap = boost::associative_property_map::vertex_descriptor, typename Kernel::Vector_3>>; + std::map::vertex_descriptor, typename Kernel::Vector_3> map; + PMap pmap(map); + CGAL::Polygon_mesh_processing::compute_vertex_normals(mesh, pmap); + TriangleMesh cp = mesh; + edge_collapse(cp, 0.2, make_GarlandHeckbert_plane_and_line_policies(cp, + CGAL::parameters::line_policies_weight(0.001) + .discontinuity_multiplier(50) + .geom_traits(Kernel()) + .vertex_normal_map(pmap))); +} + int main(int argc, char** argv) { std::vector default_data = { "data/helmet.off", @@ -301,8 +315,10 @@ int main(int argc, char** argv) data = default_data; std::vector > named_meshes = get_all_meshes(data); - for(const auto& e : named_meshes) + for(const auto& e : named_meshes){ run(e); + test_parameters_plane_and_line(e.first); + } std::cout << "Done!" << std::endl; diff --git a/Surface_mesh_topology/doc/Surface_mesh_topology/CGAL/Curves_on_surface_topology.h b/Surface_mesh_topology/doc/Surface_mesh_topology/CGAL/Curves_on_surface_topology.h index 21a7c20ee0e..5c1264976bc 100644 --- a/Surface_mesh_topology/doc/Surface_mesh_topology/CGAL/Curves_on_surface_topology.h +++ b/Surface_mesh_topology/doc/Surface_mesh_topology/CGAL/Curves_on_surface_topology.h @@ -4,7 +4,7 @@ namespace Surface_mesh_topology { /*! \ingroup PkgSurfaceMeshTopologyClasses - The class `Curves_on_surface_topology` provides methods to compute shortest non contractible cycles and to test homotopy on paths. Each object of this class is constructed from an external mesh, either a \ref CombinatorialMap "2D combinatorial map" or a model of a FaceGraph. It maintains a correspondence between this mesh and an internal representation, computed the first time an homotopy test is called. The user must not modify the input surface as long as homotopy tests are performed with this `Curves_on_surface_topology`. + The class `Curves_on_surface_topology` provides methods to compute shortest non contractible cycles and to test homotopy on paths. Each object of this class is constructed from an external mesh, either a \ref CombinatorialMap "2D combinatorial map" or a model of a FaceGraph. It maintains a correspondence between this mesh and an internal representation, computed the first time a homotopy test is called. The user must not modify the input surface as long as homotopy tests are performed with this `Curves_on_surface_topology`. \tparam Mesh a model of `CombinatorialMap` or of `FaceGraph` */ diff --git a/Surface_mesh_topology/doc/Surface_mesh_topology/CGAL/Path_on_surface.h b/Surface_mesh_topology/doc/Surface_mesh_topology/CGAL/Path_on_surface.h index bd7ead4deda..c49cb979888 100644 --- a/Surface_mesh_topology/doc/Surface_mesh_topology/CGAL/Path_on_surface.h +++ b/Surface_mesh_topology/doc/Surface_mesh_topology/CGAL/Path_on_surface.h @@ -43,7 +43,7 @@ namespace Surface_mesh_topology { bool can_be_pushed(halfedge_descriptor hd, bool flip=false) const; /// adds `hd` at the end of this path. If `flip` is true, the opposite of `hd` is considered. - /// @pre `can_be_pushed(hd)` + /// @pre \link can_be_pushed `can_be_pushed(hd)`\endlink void push_back(halfedge_descriptor hd, bool flip=false); /// returns `true` iff the dart/halfedge with index `i` can be added at the end of this path. @@ -52,7 +52,7 @@ namespace Surface_mesh_topology { /// adds the dart/halfedge with index `i` at the end of this path. /// If Mesh is a `Polyhedron_3`, takes time proportional to the number of halfedges. - /// @pre `can_be_pushed_by_index(i)` + /// @pre \link can_be_pushed_by_index `can_be_pushed_by_index(i)`\endlink void push_back_by_index(std::size_t i); /// adds successively all dart/halfedges in `l` (a sequence of indices), at the end of the path. diff --git a/Surface_mesh_topology/doc/Surface_mesh_topology/Surface_mesh_topology.txt b/Surface_mesh_topology/doc/Surface_mesh_topology/Surface_mesh_topology.txt index ad624ea4586..74cc0ac91db 100644 --- a/Surface_mesh_topology/doc/Surface_mesh_topology/Surface_mesh_topology.txt +++ b/Surface_mesh_topology/doc/Surface_mesh_topology/Surface_mesh_topology.txt @@ -59,7 +59,7 @@ The algorithm used is based on a paper by Despré and Lazarus \cgalCite{cgal:dl- \subsection SMTopology_Input Specifying the Input Surface and Curves -The main class for this package is `Surface_mesh_topology::Curves_on_surface_topology`. Its constructor takes the input surface. An internal representation of the surface (described below) is computed the first time an homotopy test is called. +The main class for this package is `Surface_mesh_topology::Curves_on_surface_topology`. Its constructor takes the input surface. An internal representation of the surface (described below) is computed the first time a homotopy test is called. Each combinatorial curve on this surface is contained in an instance of the class `Surface_mesh_topology::Path_on_surface`. An object in this class behaves as a list. This list is initially empty and the halfedges corresponding to the sequence of consecutive oriented edges of an input curve should be pushed back in this list. The class provides four ways for extending a nonempty path. - Simply push the next halfedge using the \ref Surface_mesh_topology::Path_on_surface::push_back "push_back()" member function. One can also specify if this halfedge should have its direction flipped so as to satisfy the condition of a `Path_on_surface` (see the description of \ref Surface_mesh_topology::Path_on_surface::can_be_pushed "can_be_pushed()" below) This can be done even when the path is empty, @@ -121,7 +121,7 @@ Given two `Surface_mesh_topology::Path_on_surface` \f$p_1\f$ and \f$p_2\f$, the - \ref Surface_mesh_topology::Curves_on_surface_topology::are_homotopic_with_fixed_endpoints "are_homotopic_with_fixed_endpoints"(\f$p_1\f$, \f$p_2\f$) returns `true` if the paths \f$p_1\f$ and \f$p_2\f$ are homotopic with fixed endpoints. This call is equivalent to \ref Surface_mesh_topology::Curves_on_surface_topology::is_contractible "is_contractible"(\f$p_1\cdot \overline{p_2}\f$), where \f$p_1\cdot \overline{p_2}\f$ is the concatenation of \f$p_1\f$ and the reverse of \f$p_2\f$. -A common first step in the homotopy test algorithms is to simplify the input combinatorial surface. This preprocessing step is done once and for all for a given mesh, the first time an homotopy test is called. The simplified surface is a quadrangulation, every face of which is a quadrilateral, stored in a `Surface_mesh_topology::Curves_on_surface_topology`. It has 2 vertices and \f$2g\f$ quadrilaterals where \f$g\f$ is the genus of +A common first step in the homotopy test algorithms is to simplify the input combinatorial surface. This preprocessing step is done once and for all for a given mesh, the first time a homotopy test is called. The simplified surface is a quadrangulation, every face of which is a quadrilateral, stored in a `Surface_mesh_topology::Curves_on_surface_topology`. It has 2 vertices and \f$2g\f$ quadrilaterals where \f$g\f$ is the genus of the input surface. This is otherwise independent of the size of input surface, \note The user must not modify the input surface as long as homotopy tests are performed with this `Surface_mesh_topology::Curves_on_surface_topology`. @@ -188,7 +188,7 @@ The machine used is a PC running Ubuntu 18.04 with an Intel CPU Core i7-4790 CPU \subsection SMTopology_bench1 Combinatorial Surface Topology Computation Time -The first time an homotopy test is called, we build a special quadrangulation of the surface as internal representation (as explained in Section \ref SMTopology_Theory "Implementation Details"). The complexity of this operation is linear in the number of darts of the input surface, as we can see in \cgalFigureRef{fig_sm_topology_bench1}. +The first time a homotopy test is called, we build a special quadrangulation of the surface as internal representation (as explained in Section \ref SMTopology_Theory "Implementation Details"). The complexity of this operation is linear in the number of darts of the input surface, as we can see in \cgalFigureRef{fig_sm_topology_bench1}. For this benchmark, we computed 38 `Surface_mesh_topology::Curves_on_surface_topology` objects for different input surfaces with different number of darts (between 8,000 and 30,000,000). We show in the figure the computation time of the quadrangulation according to the number of darts of the input surface. We remind that this computation needs be done only once if you want to perform several path homotopy tests on the same surface. diff --git a/Surface_mesh_topology/include/CGAL/Path_on_surface.h b/Surface_mesh_topology/include/CGAL/Path_on_surface.h index a02e19063d8..66d9186c990 100644 --- a/Surface_mesh_topology/include/CGAL/Path_on_surface.h +++ b/Surface_mesh_topology/include/CGAL/Path_on_surface.h @@ -292,7 +292,7 @@ public: } /// Add the given dart at the end of this path. - /// @pre can_be_pushed(dh) + /// @pre \link can_be_pushed `can_be_pushed(dh)`\endlink void push_back(Dart_const_descriptor dh, bool flip=false, bool update_isclosed=true) { diff --git a/Surface_mesh_topology/include/CGAL/Surface_mesh_topology/internal/Minimal_quadrangulation.h b/Surface_mesh_topology/include/CGAL/Surface_mesh_topology/internal/Minimal_quadrangulation.h index 4af6c45dd35..b61564b6488 100644 --- a/Surface_mesh_topology/include/CGAL/Surface_mesh_topology/internal/Minimal_quadrangulation.h +++ b/Surface_mesh_topology/include/CGAL/Surface_mesh_topology/internal/Minimal_quadrangulation.h @@ -15,7 +15,7 @@ // Should be defined before to include Path_on_surface_with_rle.h // If nothing is defined, use V1 // #define CGAL_PWRLE_TURN_V1 // Compute turns by turning (method of CMap) -// #define CGAL_PWRLE_TURN_V2 // Compute turns by using an id of darts, given by an hash-table (built and given by Minimal_quadrangulation) +// #define CGAL_PWRLE_TURN_V2 // Compute turns by using an id of darts, given by an hash table (built and given by Minimal_quadrangulation) #define CGAL_PWRLE_TURN_V3 // Compute turns by using an id of darts, associated in Info of Darts (build by Minimal_quadrangulation) #include diff --git a/Surface_mesh_topology/include/CGAL/Surface_mesh_topology/internal/Path_on_surface_with_rle.h b/Surface_mesh_topology/include/CGAL/Surface_mesh_topology/internal/Path_on_surface_with_rle.h index f56db8e5cb9..4405c055908 100644 --- a/Surface_mesh_topology/include/CGAL/Surface_mesh_topology/internal/Path_on_surface_with_rle.h +++ b/Surface_mesh_topology/include/CGAL/Surface_mesh_topology/internal/Path_on_surface_with_rle.h @@ -447,7 +447,7 @@ public: } /// Add the given dart at the end of this path. - /// @pre can_be_pushed(dh) + /// @pre \link can_be_pushed `can_be_pushed(dh)`\endlink void push_back(Dart_const_descriptor dh, bool update_isclosed=true) { CGAL_assertion(dh!=Map::null_descriptor); diff --git a/Surface_mesher/doc/Surface_mesher/Concepts/SurfaceMeshTriangulation_3.h b/Surface_mesher/doc/Surface_mesher/Concepts/SurfaceMeshTriangulation_3.h index eb277fce941..8ec09112946 100644 --- a/Surface_mesher/doc/Surface_mesher/Concepts/SurfaceMeshTriangulation_3.h +++ b/Surface_mesher/doc/Surface_mesher/Concepts/SurfaceMeshTriangulation_3.h @@ -234,7 +234,7 @@ Finite_facets_iterator finite_facets_end() const; Copies the `Cell_handle`s of all cells incident to `v` to the output iterator `cells`. If `t.dimension() < 3`, then do nothing. Returns the resulting output iterator. -\pre `v != Vertex_handle()`, `t.is_vertex(v)`. +\pre `v != Vertex_handle()` and \link is_vertex `is_vertex(v->point())`\endlink. */ template OutputIterator @@ -346,7 +346,7 @@ all the cells (resp. facets) describing the hole, creates a new vertex a new cell (resp. facet) with `v` as vertex. Then `v->set_point(p)` is called and `v` is returned. -\pre `t.dimension() >= 2`, the set of cells (resp. facets in dimension 2) is connected, its boundary is connected, and `p` lies inside the hole, which is star-shaped wrt `p`. +\pre `dimension() >= 2`, the set of cells (resp. facets in dimension 2) is connected, its boundary is connected, and `p` lies inside the hole, which is star-shaped wrt `p`. */ template Vertex_handle insert_in_hole(Point p, CellIt cell_begin, CellIt cell_end, diff --git a/TDS_3/doc/TDS_3/Concepts/TriangulationDataStructure_3.h b/TDS_3/doc/TDS_3/Concepts/TriangulationDataStructure_3.h index 752093512af..3d8a5dda8a6 100644 --- a/TDS_3/doc/TDS_3/Concepts/TriangulationDataStructure_3.h +++ b/TDS_3/doc/TDS_3/Concepts/TriangulationDataStructure_3.h @@ -116,9 +116,9 @@ typedef unspecified_type Vertex_handle; typedef unspecified_type Cell_handle; /*! -Can be `CGAL::Sequential_tag`, `CGAL::Parallel_tag`, or `Parallel_if_available_tag`. If it is +Can be `CGAL::Sequential_tag`, `CGAL::Parallel_tag`, or `CGAL::Parallel_if_available_tag`. If it is `CGAL::Parallel_tag`, the following functions can be called concurrently: -`create_vertex`, `create_cell`, `delete_vertex`, `delete_cell`. +`create_vertex()`, `create_cell()`, `delete_vertex()`, `delete_cell()`. */ typedef unspecified_type Concurrency_tag; @@ -232,13 +232,13 @@ TriangulationDataStructure_3(const TriangulationDataStructure_3 & tds1); /*! Assignment operator. All vertices and cells are duplicated, and the former -data structure of `tds` is deleted. +data structure is deleted. */ TriangulationDataStructure_3& operator= (const TriangulationDataStructure_3 & tds1); /*! -`tds1` is copied into `tds`. If `v != Vertex_handle()`, -the vertex of `tds` corresponding to `v` is returned, +`tds1` is copied into `this`. If `v != Vertex_handle()`, +the vertex corresponding to `v` is returned, otherwise `Vertex_handle()` is returned. \pre The optional argument `v` is a vertex of `tds1`. */ @@ -266,19 +266,19 @@ otherwise `Vertex_handle()` is returned. \pre The optional argument `v` is a vertex of `tds_src` or is `Vertex_handle()`. */ template -Vertex_handle tds.copy_tds(const TDS_src& tds_src, typename TDS_src::Vertex_handle v, const ConvertVertex& convert_vertex, const ConvertCell& convert_cell); +Vertex_handle copy_tds(const TDS_src& tds_src, typename TDS_src::Vertex_handle v, const ConvertVertex& convert_vertex, const ConvertCell& convert_cell); /*! -Swaps `tds` and `tds1`. There is no copy of cells and vertices, +Swaps `this` and `tds1`. There is no copy of cells and vertices, thus this method runs in constant time. This method should be preferred to -`tds`=`tds1` or `tds`(`tds1`) when `tds1` is deleted after -that. +copy assignment (`*this = tds1`) or copy construction (`*this(tds1)`) +if `tds1` is deleted after the copy. */ void swap(TriangulationDataStructure_3 & tds1); /*! -Deletes all cells and vertices. `tds` is reset as a triangulation -data structure constructed by the default constructor. +Deletes all cells and vertices. The triangulation data structure is reset as if +constructed by the default constructor. */ void clear(); @@ -301,7 +301,7 @@ counted. size_type number_of_vertices() const; /*! -The number of cells. Returns 0 if `tds`.`dimension()`\f$ <3\f$. +The number of cells. Returns 0 if `dimension()`\f$ <3\f$. */ size_type number_of_cells() const; @@ -311,12 +311,12 @@ size_type number_of_cells() const; /// @{ /*! -The number of facets. Returns 0 if `tds`.`dimension()`\f$ <2\f$. +The number of facets. Returns 0 if `dimension()`\f$ <2\f$. */ size_type number_of_facets() const; /*! -The number of edges. Returns 0 if `tds`.`dimension()`\f$ <1\f$. +The number of edges. Returns 0 if `dimension()`\f$ <1\f$. */ size_type number_of_edges() const; @@ -339,19 +339,19 @@ void set_dimension(int n); /// @{ /*! -Tests whether `v` is a vertex of `tds`. +Tests whether `v` is a vertex of the triangulation data structure. */ bool is_vertex(Vertex_handle v) const; /*! -Tests whether `(c,i,j)` is an edge of `tds`. Answers `false` when -`dimension()` \f$ <1\f$ . +Tests whether `(c,i,j)` is an edge of the triangulation data structure. +Answers `false` when `dimension()` \f$ <1\f$ . \pre \f$ i,j \in\{0,1,2,3\}\f$ */ bool is_edge(Cell_handle c, int i, int j) const; /*! -Tests whether `(u,v)` is an edge of `tds`. If the edge is found, +Tests whether `(u,v)` is an edge of the triangulation data structure. If the edge is found, it computes a cell `c` having this edge and the indices `i` and `j` of the vertices `u` and `v`, in this order. */ @@ -359,19 +359,19 @@ bool is_edge(Vertex_handle u, Vertex_handle v, Cell_handle & c, int & i, int & j) const; /*! -Tests whether `(u,v)` is an edge of `tds`. +Tests whether `(u,v)` is an edge of the triangulation data structure. */ bool is_edge(Vertex_handle u, Vertex_handle v) const; /*! -Tests whether `(c,i)` is a facet of `tds`. Answers `false` when -`dimension()` \f$ <2\f$ . +Tests whether `(c,i)` is a facet of of the triangulation data structure. +Answers `false` when `dimension()` \f$ <2\f$ . \pre \f$ i \in\{0,1,2,3\}\f$ */ bool is_facet(Cell_handle c, int i) const; /*! -Tests whether `(u,v,w)` is a facet of `tds`. If the facet is found, +Tests whether `(u,v,w)` is a facet of the triangulation data structure. If the facet is found, it computes a cell `c` having this facet and the indices `i`, `j` and `k` of the vertices `u`, `v` and `w`, in this order. @@ -380,13 +380,13 @@ bool is_facet(Vertex_handle u, Vertex_handle v, Vertex_handle w, Cell_handle & c, int & i, int & j, int & k) const; /*! -Tests whether `c` is a cell of `tds`. Answers `false` when -`dimension()` \f$ <3\f$ . +Tests whether `c` is a cell of the triangulation data structure. +Answers `false` when `dimension()` \f$ <3\f$ . */ bool is_cell(Cell_handle c) const; /*! -Tests whether `(u,v,w,t)` is a cell of `tds`. If the cell +Tests whether `(u,v,w,t)` is a cell of the triangulation data structure. If the cell `c` is found, it computes the indices `i`, `j`, `k` and `l` of the vertices `u`, `v`, `w` and `t` in `c`, in this order. @@ -401,7 +401,7 @@ Cell_handle & c, int & i, int & j, int & k, int & l) const; /*! If `v` is a vertex of `f`, then `j` is the index of `v` in the cell `f.first`, and the method returns `true`. -\pre `tds`.dimension()=3 +\pre `dimension() == 3` */ bool has_vertex(const Facet & f, Vertex_handle v, int & j) const; @@ -429,17 +429,17 @@ bool has_vertex(Cell_handle c, int i, Vertex_handle v) const; /// @{ /*! - +\pre `dimension() == 3` */ bool are_equal(const Facet & f, const Facet & g) const; /*! - +\pre `dimension() == 3` */ bool are_equal(Cell_handle c, int i, Cell_handle n, int j) const; /*! -For these three methods: \pre `tds`.dimension()=3. +\pre `dimension() == 3` */ bool are_equal(const Facet & f, Cell_handle n, int j) const; @@ -528,7 +528,7 @@ void flip_flippable(Cell_handle c, int i); Creates a new vertex, inserts it in cell `c` and returns its handle. The cell `c` is split into four new cells, each of these cells being formed by the new vertex and a facet of `c`. -\pre `tds`.`dimension()` \f$ = 3\f$ and `c` is a cell of `tds`. +\pre `dimension()` \f$ = 3\f$ and \link is_cell `is_cell(c)`\endlink. */ Vertex_handle insert_in_cell(Cell_handle c); @@ -536,14 +536,14 @@ Vertex_handle insert_in_cell(Cell_handle c); Creates a new vertex, inserts it in facet `f` and returns its handle. In dimension 3, the two incident cells are split into 3 new cells; in dimension 2, the facet is split into 3 facets. -\pre `tds`.`dimension()` \f$ \geq2\f$ and `f` is a facet of `tds`. +\pre `dimension()` \f$ \geq2\f$ and \link is_facet(Cell_handle, int)const `is_facet(f.first, f.second)`\endlink. */ Vertex_handle insert_in_facet(const Facet & f); /*! Creates a new vertex, inserts it in facet `i` of `c` and returns its handle. -\pre `tds`.`dimension()` \f$ \geq2\f$, \f$ i \in\{0,1,2,3\}\f$ in dimension 3, \f$ i=3\f$ in dimension 2 and `(c,i)` is a facet of `tds`. +\pre `dimension()` \f$ \geq2\f$, \f$ i \in\{0,1,2,3\}\f$ in dimension 3, \f$ i=3\f$ in dimension 2 and \link is_facet(Cell_handle, int)const `is_facet(c, i)`\endlink. */ Vertex_handle insert_in_facet(Cell_handle c, int i); @@ -553,14 +553,14 @@ In dimension 3, all the incident cells are split into 2 new cells; in dimension 2, the 2 incident facets are split into 2 new facets; in dimension 1, the edge is split into 2 new edges. -\pre `tds`.`dimension()` \f$ \geq1\f$ and `e` is an edge of `tds`. +\pre `dimension()` \f$ \geq1\f$ and \link is_edge(Cell_handle, int,int)const `is_edge(e.first, e.second, e.third)`\endlink. */ Vertex_handle insert_in_edge(Edge e); /*! Creates a new vertex, inserts it in edge \f$ (i,j)\f$ of `c` and returns its handle. -\pre `tds`.`dimension()` \f$ \geq1\f$. \f$ i\neq j\f$, \f$ i,j \in\{0,1,2,3\}\f$ in dimension 3, \f$ i,j \in\{0,1,2\}\f$ in dimension 2, \f$ i,j \in\{0,1\}\f$ in dimension 1 and `(c,i,j)` is an edge of `tds`. +\pre `dimension()` \f$ \geq1\f$. \f$ i\neq j\f$, \f$ i,j \in\{0,1,2,3\}\f$ in dimension 3, \f$ i,j \in\{0,1,2\}\f$ in dimension 2, \f$ i,j \in\{0,1\}\f$ in dimension 1 and \link is_edge(Cell_handle, int,int)const `is_edge(c,i,j)`\endlink. */ Vertex_handle insert_in_edge(Cell_handle c, int i, int j); @@ -582,8 +582,7 @@ This method can be used to insert the first two vertices in an empty triangulation. A handle to `v` is returned. -\pre `tds`.`dimension()` \f$ = d < 3\f$. When `tds`.`number_of_vertices()` \f$ >0\f$, \f$ star \neq\f$ `Vertex_handle()` and `star` is a vertex of `tds`. - +\pre `dimension()` \f$ = d < 3\f$. When `number_of_vertices()` \f$ >0\f$, \f$ star \neq\f$ `Vertex_handle()` and \link is_vertex `is_vertex(star)`\endlink. \anchor TDS3figtopoinsert_outside_affine_hull \image html topo-insert_outside_affine_hull.png "insert_increase_dimension (1-dimensional case)." @@ -603,15 +602,14 @@ described, and `begin->neighbor(i)` does not. Then this function deletes all the cells (resp. facets) describing the hole, creates a new vertex `v`, and for each facet (resp. edge) on the boundary of the hole, creates a new cell (resp. facet) with `v` as vertex. `v` is returned. -\pre `tds`.`dimension()` \f$ \geq2\f$, the set of cells (resp. facets) is connected, and its boundary is connected. +\pre `dimension()` \f$ \geq2\f$, the set of cells (resp. facets) is connected, and its boundary is connected. */ template Vertex_handle insert_in_hole(CellIt cell_begin, CellIt cell_end, Cell_handle begin, int i); /*! -Same as above, except that `newv` will be used as the new vertex, which -must have been allocated previously with e.g. `create_vertex`. +Same as above, except that `newv` will be used as the new vertex, which must have been allocated previously with, e.g., `create_vertex()`. */ template Vertex_handle insert_in_hole(CellIt cell_begin, CellIt cell_end, @@ -627,7 +625,8 @@ This operation is the reciprocal of `insert_increase_dimension()`. It transforms a triangulation of the sphere \f$ S^d\f$ of \f$ \mathbb{R}^{d+1}\f$ into the triangulation of the sphere \f$ S^{d-1}\f$ of \f$ \mathbb{R}^{d}\f$ by removing the vertex `v`. Delete the cells incident to `w`, keep the others. -\pre `tds`.`dimension()` \f$ = d \geq-1\f$. `tds`.`degree(v)` \f$ =\f$ `degree(w)` \f$ =\f$ `tds`.`number_of_vertices()` \f$ -1\f$. +\pre `dimension()` \f$ = d \geq-1\f$. +\pre \link degree `degree(v)`\endlink \f$ =\f$ \link degree `degree(w)`\endlink \f$ =\f$ `number_of_vertices()` \f$ -1\f$. */ void remove_decrease_dimension(Vertex_handle v, Vertex_handle w = v); @@ -635,10 +634,10 @@ void remove_decrease_dimension(Vertex_handle v, Vertex_handle w = v); /*! Removes `v`. The incident simplices of maximal dimension incident to `v` are replaced by a single simplex of the same dimension. This -operation is exactly the reciprocal to `tds`.`insert_in_cell(v)` in -dimension 3, `tds`.`insert_in_facet(v)` in dimension 2, and -`tds`.`insert_in_edge(v)` in dimension 1. -\pre `tds`.`degree(v)` \f$ =\f$ `tds`.`dimension()+1`. +operation is exactly the reciprocal to `insert_in_cell(v)` in +dimension 3, `insert_in_facet(v)` in dimension 2, and +`insert_in_edge(v)` in dimension 1. +\pre \link degree `degree(v)`\endlink \f$ =\f$ `dimension()+1`. */ Cell_handle remove_from_maximal_dimension_simplex(Vertex_handle v); @@ -656,7 +655,8 @@ triangulation of the sphere \f$ S^d\f$ of \f$ \mathbb{R}^{d+1}\f$ onto the triangulation of the sphere \f$ S^{d-1}\f$ of \f$ \mathbb{R}^{d}\f$ formed by the link of `v` augmented with the vertex `v` itself, for \f$ d\f$==2,3; this one is placed on the facet `(c, i)` (see Fig. \ref TDS3dim_down). -\pre The dimension must be 2 or 3. The degree of `v` must be equal to the total number of vertices of the triangulation data structure minus 1. +\pre The dimension must be 2 or 3. +\pre The degree of `v` must be equal to the total number of vertices of the triangulation data structure minus 1. \anchor TDS3dim_down \image html tds-dim_down.png @@ -680,7 +680,7 @@ void decrease_dimension(Cell_handle c, int i); \cgalAdvancedBegin Changes the orientation of all cells of the triangulation data structure. \cgalAdvancedEnd -\pre `tds`.`dimension()` \f$ \geq1\f$. +\pre `dimension()` \f$ \geq1\f$. */ void reorient(); @@ -746,7 +746,7 @@ Cell_handle n2, Cell_handle n3); \cgalAdvancedBegin Removes the vertex from the triangulation data structure. \cgalAdvancedEnd -\pre The vertex is a vertex of `tds`. +\pre \link is_vertex `is_vertex(v)`\endlink. */ void delete_vertex( Vertex_handle v ); @@ -755,7 +755,7 @@ void delete_vertex( Vertex_handle v ); \cgalAdvancedBegin Removes the cell from the triangulation data structure. \cgalAdvancedEnd -\pre The cell is a cell of `tds`. +\pre \link is_cell(Cell_handle)const `is_cell(c)`\endlink. */ void delete_cell( Cell_handle c ); @@ -783,7 +783,7 @@ void delete_cells(CellIt first, CellIt last); /// @{ /*! -Returns `cells_end()` when `tds.dimension()` \f$ <3\f$. +Returns `cells_end()` when `dimension()` \f$ <3\f$. */ Cell_iterator cells_begin() const; @@ -794,7 +794,7 @@ Cell_iterator cells_end() const; /*! Low-level access to the cells, does not return `cells_end()` -when `tds.dimension()` \f$ <3\f$. +when `dimension()` \f$ <3\f$. */ Cell_iterator raw_cells_begin() const; @@ -804,7 +804,7 @@ Cell_iterator raw_cells_begin() const; Cell_iterator raw_cells_end() const; /*! -Returns `facets_end()` when `tds.dimension()` \f$ <2\f$. +Returns `facets_end()` when `dimension()` \f$ <2\f$. */ Facet_iterator facets_begin() const; @@ -814,7 +814,7 @@ Facet_iterator facets_begin() const; Facet_iterator facets_end() const; /*! -Returns `edges_end()` when `tds.dimension()` \f$ <1\f$. +Returns `edges_end()` when `dimension()` \f$ <1\f$. */ Edge_iterator edges_begin() const; @@ -840,7 +840,7 @@ Vertex_iterator vertices_end() const; /*! Starts at an arbitrary cell incident to `e`. -\pre `tds.dimension()` \f$ =3\f$ +\pre `dimension()` \f$ =3\f$ */ Cell_circulator incident_cells(const Edge & e) const; @@ -851,7 +851,7 @@ Cell_circulator incident_cells(Cell_handle c, int i, int j) const; /*! Starts at cell `start`. -\pre `tds.dimension()` \f$ =3\f$ and `start` is incident to `e`. +\pre `dimension()` \f$ =3\f$ and `start` is incident to `e`. */ Cell_circulator incident_cells(const Edge & e, Cell_handle start) const; @@ -865,9 +865,9 @@ const; Starts at an arbitrary facet incident to `e`. Only defined in dimension 3, though are defined also in dimension 2: -there are only two facets sahring an edge in dimension 2. +there are only two facets sharing an edge in dimension 2. -\pre `tds.dimension()` \f$ =3\f$ +\pre `dimension()` \f$ =3\f$ */ Facet_circulator incident_facets(Edge e) const; @@ -875,7 +875,7 @@ Facet_circulator incident_facets(Edge e) const; As above for edge `(i,j)` of `c`. Only defined in dimension 3, though are defined also in dimension 2: -there are only two facets sahring an edge in dimension 2. +there are only two facets sharing an edge in dimension 2. */ Facet_circulator incident_facets(Cell_handle c, int i, int j) const; @@ -883,7 +883,7 @@ Facet_circulator incident_facets(Cell_handle c, int i, int j) const; Starts at facet `start`. Only defined in dimension 3, though are defined also in dimension 2: -there are only two facets sahring an edge in dimension 2. +there are only two facets sharing an edge in dimension 2. \pre `start` is incident to `e`. */ @@ -893,7 +893,7 @@ Facet_circulator incident_facets(Edge e, Facet start) const; Starts at facet of index `f` in `start`. Only defined in dimension 3, though are defined also in dimension 2: -there are only two facets sahring an edge in dimension 2. +there are only two facets sharing an edge in dimension 2. */ Facet_circulator incident_facets(Edge e, Cell_handle start, int f) const; @@ -901,7 +901,7 @@ Facet_circulator incident_facets(Edge e, Cell_handle start, int f) const; As above for edge `(i,j)` of `c`. Only defined in dimension 3, though are defined also in dimension 2: -there are only two facets sahring an edge in dimension 2. +there are only two facets sharing an edge in dimension 2. */ Facet_circulator incident_facets(Cell_handle c, int i, int j, Facet start) const; @@ -910,7 +910,7 @@ Facet start) const; As above for edge `(i,j)` of `c` and facet `(start,f)`. Only defined in dimension 3, though are defined also in dimension 2: -there are only two facets sahring an edge in dimension 2. +there are only two facets sharing an edge in dimension 2. */ Facet_circulator incident_facets(Cell_handle c, int i, int j, Cell_handle start, int f) const; @@ -924,7 +924,8 @@ Cell_handle start, int f) const; Copies the `Cell_handle`s of all cells incident to `v` to the output iterator `cells`. Returns the resulting output iterator. -\pre `tds.dimension()` \f$ =3\f$, `v` \f$ \neq\f$ `Vertex_handle()`, `tds.is_vertex(v)`. +\pre `dimension()` \f$ =3\f$ +\pre `v` \f$ \neq\f$ `Vertex_handle()` and \link is_vertex `is_vertex(v)`\endlink */ template OutputIterator @@ -934,7 +935,8 @@ incident_cells(Vertex_handle v, OutputIterator cells) const; Copies the `Facet`s incident to `v` to the output iterator `facets`. Returns the resulting output iterator. -\pre `tds.dimension()` \f$ >1\f$, `v` \f$ \neq\f$ `Vertex_handle()`, `tds.is_vertex(v)`. +\pre `dimension()` \f$ >1\f$ +\pre `v` \f$ \neq\f$ `Vertex_handle()` and \link is_vertex `is_vertex(v)`\endlink */ template OutputIterator @@ -943,7 +945,8 @@ incident_facets(Vertex_handle v, OutputIterator facets) const; /*! Copies all `Edge`s incident to `v` to the output iterator `edges`. Returns the resulting output iterator. -\pre `tds.dimension()` \f$ >0\f$, `v` \f$ \neq\f$ `Vertex_handle()`, `tds.is_vertex(v)`. +\pre `dimension()` \f$ >0\f$ +\pre `v` \f$ \neq\f$ `Vertex_handle()` and \link is_vertex `is_vertex(v)`\endlink */ template OutputIterator @@ -951,9 +954,9 @@ incident_edges(Vertex_handle v, OutputIterator edges) const; /*! Copies the `Vertex_handle`s of all vertices adjacent to `v` to the -output iterator `vertices`. If `tds.dimension()` \f$ <0\f$, then do +output iterator `vertices`. If `dimension()` \f$ <0\f$, then do nothing. Returns the resulting output iterator. -\pre `v` \f$ \neq\f$ `Vertex_handle()`, `tds.is_vertex(v)`. +\pre `v` \f$ \neq\f$ `Vertex_handle()` and \link is_vertex `is_vertex(v)`\endlink */ template OutputIterator @@ -961,7 +964,8 @@ adjacent_vertices(Vertex_handle v, OutputIterator vertices) const; /*! Returns the degree of `v`, that is, the number of incident vertices. -\pre `v` \f$ \neq\f$ `Vertex_handle()`, `tds.is_vertex(v)`. +\pre `v` \f$ \neq\f$ `Vertex_handle()` +\pre \link is_vertex `is_vertex(v)`\endlink */ size_type degree(Vertex_handle v) const; @@ -1045,7 +1049,7 @@ Writes `tds` into the stream `os` ostream& operator<< (ostream& os, const TriangulationDataStructure_3 & tds); /*! \ingroup PkgIOTDS3 -The tds streamed in `is`, of original type `TDS_src`, is written into the triangulation data structure. As the vertex and cell +The triangulation data structure streamed in `is`, of original type `TDS_src`, is written into the triangulation data structure. As the vertex and cell types might be different and incompatible, the creation of new cells and vertices is made thanks to the functors `convert_vertex` and `convert_cell`, that convert vertex and cell types. For each vertex `v_src` in `is`, the corresponding diff --git a/Tetrahedral_remeshing/test/Tetrahedral_remeshing/CMakeLists.txt b/Tetrahedral_remeshing/test/Tetrahedral_remeshing/CMakeLists.txt index 3747ae19125..bd96756d058 100644 --- a/Tetrahedral_remeshing/test/Tetrahedral_remeshing/CMakeLists.txt +++ b/Tetrahedral_remeshing/test/Tetrahedral_remeshing/CMakeLists.txt @@ -40,6 +40,9 @@ if(TARGET CGAL::Eigen3_support) create_single_source_cgal_program("features_and_adaptive_sizing.cpp") target_link_libraries(features_and_adaptive_sizing PRIVATE CGAL::Eigen3_support) + create_single_source_cgal_program("test_mesh_and_remesh_with_io.cpp") + target_link_libraries(test_mesh_and_remesh_with_io PRIVATE CGAL::Eigen3_support) + # with MLS projection add_executable(test_mesh_and_remesh_polyhedron_with_features_mls "test_mesh_and_remesh_polyhedron_with_features.cpp") diff --git a/Tetrahedral_remeshing/test/Tetrahedral_remeshing/test_mesh_and_remesh_with_io.cpp b/Tetrahedral_remeshing/test/Tetrahedral_remeshing/test_mesh_and_remesh_with_io.cpp new file mode 100644 index 00000000000..ae25746ac5b --- /dev/null +++ b/Tetrahedral_remeshing/test/Tetrahedral_remeshing/test_mesh_and_remesh_with_io.cpp @@ -0,0 +1,77 @@ +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +// Domain +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; + +typedef CGAL::Image_3 Image; +typedef CGAL::Labeled_mesh_domain_3 Mesh_domain; + +// Triangulation +typedef CGAL::Mesh_triangulation_3::type Tr; +typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; + +// Mesh Criteria +typedef CGAL::Mesh_criteria_3 Mesh_criteria; +typedef Mesh_criteria::Facet_criteria Facet_criteria; +typedef Mesh_criteria::Cell_criteria Cell_criteria; + +typedef Tr::Geom_traits Gt; +typedef CGAL::Triangulation_3 T3; +typedef CGAL::Tetrahedral_remeshing::Remeshing_triangulation_3 Remeshing_triangulation; + +using namespace CGAL::parameters; + +int main() +{ + const std::string filename = CGAL::data_file_path("images/liver.inr.gz"); + + CGAL::Image_3 image; + if(!image.read(filename)) { + std::cerr << "Error: Cannot read file " << filename << std::endl; + return EXIT_FAILURE; + } + Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain(image, relative_error_bound = 1e-9); + + // Mesh criteria + Facet_criteria facet_criteria(25, 20, 2); // angle, size, approximation + Cell_criteria cell_criteria(3, 20); // radius-edge ratio, size + Mesh_criteria criteria(facet_criteria, cell_criteria); + + // Mesh + C3t3 c3t3 = CGAL::make_mesh_3(domain, criteria, no_exude(), no_perturb()); + + std::cout << "Meshing done." << std::endl; + + // Write + std::ofstream os("after_meshing_io.mesh"); + CGAL::IO::write_MEDIT(os, c3t3); + os.close(); + + // Read + Remeshing_triangulation tr; + std::ifstream is("after_meshing_io.mesh"); + CGAL::IO::read_MEDIT(is, tr); + + // Remesh + double target_edge_length = 10.; + CGAL::tetrahedral_isotropic_remeshing(tr, target_edge_length); + + std::cout << "Remeshing done." << std::endl; + + return 0; +} diff --git a/Triangulation_2/benchmark/Triangulation_2/Delaunay_remove.cpp b/Triangulation_2/benchmark/Triangulation_2/Delaunay_remove.cpp index 08e8016e13c..9b7b6994757 100644 --- a/Triangulation_2/benchmark/Triangulation_2/Delaunay_remove.cpp +++ b/Triangulation_2/benchmark/Triangulation_2/Delaunay_remove.cpp @@ -1,11 +1,10 @@ +#include #include #include #include #include #include -#include -#include #include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; @@ -26,28 +25,31 @@ int main(int argc, char **argv) rep=atoi(argv[2]); std::vector points; points.reserve(n); + CGAL::get_default_random() = CGAL::Random(42); CGAL::Random_points_in_disc_2 g(1); - CGAL::copy_n( g, n, std::back_inserter(points)); + std::copy_n( g, n, std::back_inserter(points)); Delaunay original; original.insert(points.begin(),points.end()); double res=0; for (int r=0;r vertices; - for(FVI fvi = delaunay.finite_vertices_begin(); fvi != delaunay.finite_vertices_end();++fvi){ - vertices.push_back(fvi); - } + std::vector vertices(delaunay.number_of_vertices()); + std::copy(delaunay.finite_vertex_handles().begin(), + delaunay.finite_vertex_handles().end(), + vertices.begin()); CGAL::Timer t; t.start(); - for (int k=0; k