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/examples/AABB_tree/AABB_cached_bbox_example.cpp b/AABB_tree/examples/AABB_tree/AABB_cached_bbox_example.cpp index 129d3e65c1d..cf57b4512a7 100644 --- a/AABB_tree/examples/AABB_tree/AABB_cached_bbox_example.cpp +++ b/AABB_tree/examples/AABB_tree/AABB_cached_bbox_example.cpp @@ -27,7 +27,7 @@ void triangle_mesh(std::string fname) typedef CGAL::AABB_tree Tree; TriangleMesh tmesh; - if(!CGAL::IO::read_polygon_mesh(fname, tmesh) || CGAL::is_triangle_mesh(tmesh)) + if(!CGAL::IO::read_polygon_mesh(fname, tmesh) || !CGAL::is_triangle_mesh(tmesh)) { std::cerr << "Invalid input." << std::endl; return; 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/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_site_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_site_2.h index 8d55878c7e8..077c79f27ac 100644 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_site_2.h +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_site_2.h @@ -17,12 +17,11 @@ concept `ApolloniusSite_2`. \cgalHeading{I/O} -The I/O operators are defined for `iostream`. +The I/O operators are defined for `std::iostream`. -The information output in the `iostream` is: the point of the +The information output in the `std::iostream` is: the point of the Apollonius site and its weight. -\sa `CGAL::Qt_widget` \sa `CGAL::Apollonius_graph_traits_2` \sa `CGAL::Apollonius_graph_filtered_traits_2` */ @@ -50,7 +49,6 @@ Apollonius_site_2(const Apollonius_site_2& other); /*! Inserts the Apollonius site `s` into the stream `os`. -\note Included through `CGAL/IO/Qt_widget_Apollonius_site_2.h`. \pre The insert operator must be defined for `Point_2` and `Weight`. \relates Apollonius_site_2 */ @@ -59,18 +57,9 @@ std::ostream& operator<<(std::ostream& os, const Apollonius_site_2& s) const; /*! Reads an Apollonius site from the stream `is` and assigns it to `s`. -\note Included through `CGAL/IO/Qt_widget_Apollonius_site_2.h`. \pre The extract operator must be defined for `Point_2` and `Weight`. \relates Apollonius_site_2 */ std::istream& operator>>(std::istream& is, const Apollonius_site_2& s); -/*! -Inserts the Apollonius site `s` into the `Qt_widget` stream `w`. -\note Included through `CGAL/IO/Qt_widget_Apollonius_site_2.h`. -\pre The insert operator must be defined for `K::Circle_2`. -\relates Apollonius_site_2 -*/ -Qt_widget& operator<<(Qt_widget& w, const Apollonius_site_2& s) const; - } /* end namespace CGAL */ diff --git a/Apollonius_graph_2/include/CGAL/Parabola_segment_2.h b/Apollonius_graph_2/include/CGAL/Parabola_segment_2.h index 20883169ba7..63faa2d9c92 100644 --- a/Apollonius_graph_2/include/CGAL/Parabola_segment_2.h +++ b/Apollonius_graph_2/include/CGAL/Parabola_segment_2.h @@ -63,7 +63,7 @@ struct Parabola_segment_2 : public Parabola_2< Gt > } int compute_k(const FT tt, const FT STEP) const { - return int(CGAL::to_double(CGAL::sqrt(tt / STEP))); + return int(CGAL::to_double(CGAL::approximate_sqrt(tt / STEP))); } // s0 and s1 define a desired drawing "range" 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/doc/BGL/PackageDescription.txt b/BGL/doc/BGL/PackageDescription.txt index 68a57a60d14..395584b1b30 100644 --- a/BGL/doc/BGL/PackageDescription.txt +++ b/BGL/doc/BGL/PackageDescription.txt @@ -509,8 +509,7 @@ the requirement for traversal of all faces in a graph. /// I/O Functions for the \ref IOStream3MF /// \ingroup PkgBGLIOFct -/// \defgroup PkgBGLIOFctDeprecated I/O Functions (Deprecated) -/// \ingroup PkgBGLIOFct + /*! \addtogroup PkgBGLPropertiesDynamic 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/IO/OFF.h b/BGL/include/CGAL/boost/graph/IO/OFF.h index 25f76b2b1d6..441b088597a 100644 --- a/BGL/include/CGAL/boost/graph/IO/OFF.h +++ b/BGL/include/CGAL/boost/graph/IO/OFF.h @@ -247,36 +247,7 @@ bool read_OFF(const std::string& fname, } // namespace IO -#ifndef CGAL_NO_DEPRECATED_CODE -/*! - \ingroup PkgBGLIOFctDeprecated - - \deprecated This function is deprecated since \cgal 5.3, `CGAL::IO::read_OFF()` should be used instead. -*/ -template -CGAL_DEPRECATED bool read_off(std::istream& is, Graph& g, const CGAL_NP_CLASS& np = parameters::default_values()) -{ - return IO::read_OFF(is, g, np); -} - -/*! -\ingroup PkgBGLIOFctDeprecated - -\deprecated This function is deprecated since \cgal 5.3, `CGAL::IO::read_OFF()` should be used instead. -*/ -template -CGAL_DEPRECATED bool read_off(const char* fname, Graph& g, const CGAL_NP_CLASS& np = parameters::default_values()) -{ - return IO::read_OFF(fname, g, np); -} -template -CGAL_DEPRECATED bool read_off(const std::string& fname, Graph& g) -{ - return read_off(fname.c_str(), g, parameters::default_values()); -} - -#endif // CGAL_NO_DEPRECATED_CODE //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -453,31 +424,6 @@ bool write_OFF(const std::string& fname, } // namespace IO -#ifndef CGAL_NO_DEPRECATED_CODE - -/*! - \ingroup PkgBGLIOFctDeprecated - - \deprecated This function is deprecated since \cgal 5.3, `CGAL::IO::write_OFF()` should be used instead. -*/ -template -CGAL_DEPRECATED bool write_off(std::ostream& os, const Graph& g, const CGAL_NP_CLASS& np = parameters::default_values()) -{ - return IO::write_OFF(os, g, np); -} - -/*! -\ingroup PkgBGLIOFctDeprecated - -\deprecated This function is deprecated since \cgal 5.3, `CGAL::IO::write_OFF()` should be used instead. -*/ -template -CGAL_DEPRECATED bool write_off(const char* fname, const Graph& g, const CGAL_NP_CLASS& np = parameters::default_values()) -{ - return IO::write_OFF(fname, g, np); -} - -#endif // CGAL_NO_DEPRECATED_CODE } // namespace CGAL diff --git a/BGL/include/CGAL/boost/graph/IO/VTK.h b/BGL/include/CGAL/boost/graph/IO/VTK.h index 931c744765e..cfc33c2b867 100644 --- a/BGL/include/CGAL/boost/graph/IO/VTK.h +++ b/BGL/include/CGAL/boost/graph/IO/VTK.h @@ -529,20 +529,7 @@ bool write_VTP(const std::string& fname, const Graph& g, const CGAL_NP_CLASS& np } // namespace IO -#ifndef CGAL_NO_DEPRECATED_CODE -/*! - \ingroup PkgBGLIOFctDeprecated - - \deprecated This function is deprecated since \cgal 5.3, `CGAL::IO::write_VTP()` should be used instead. -*/ -template -CGAL_DEPRECATED bool write_vtp(std::ostream& os, const Graph& g, const CGAL_NP_CLASS& np = parameters::default_values()) -{ - return IO::write_VTP(os, g, np); -} - -#endif // CGAL_NO_DEPRECATED_CODE } // namespace CGAL diff --git a/BGL/include/CGAL/boost/graph/IO/WRL.h b/BGL/include/CGAL/boost/graph/IO/WRL.h index b92429a193b..b2179a8907c 100644 --- a/BGL/include/CGAL/boost/graph/IO/WRL.h +++ b/BGL/include/CGAL/boost/graph/IO/WRL.h @@ -111,20 +111,7 @@ bool write_WRL(const std::string& fname, const Graph& g, const CGAL_NP_CLASS& np } // namespace IO -#ifndef CGAL_NO_DEPRECATED_CODE -/*! - \ingroup PkgBGLIOFctDeprecated - - \deprecated This function is deprecated since \cgal 5.3, `CGAL::IO::write_WRL()` should be used instead. -*/ -template -CGAL_DEPRECATED bool write_wrl(std::ostream& os, const Graph& g, const CGAL_NP_CLASS& np = parameters::default_values()) -{ - return IO::write_WRL(os, g, np); -} - -#endif // CGAL_NO_DEPRECATED_CODE } // namespace CGAL diff --git a/BGL/include/CGAL/boost/graph/graph_traits_inheritance_macros.h b/BGL/include/CGAL/boost/graph/graph_traits_inheritance_macros.h index 9a88014752d..9035d607764 100644 --- a/BGL/include/CGAL/boost/graph/graph_traits_inheritance_macros.h +++ b/BGL/include/CGAL/boost/graph/graph_traits_inheritance_macros.h @@ -67,23 +67,8 @@ template struct property_map > \ : property_map > \ {};\ -} /* boost namespace */\ -\ -namespace CGAL { \ -template \ -typename boost::property_map >::type \ -get(DTAG t, CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, const CGAL_XX_YATP& default_value = CGAL_XX_YATP()) \ -{ \ - return get(t, static_cast(g), default_value); \ -} \ -\ -template \ -typename boost::property_map >::const_type \ -get(DTAG t, const CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, const CGAL_XX_YATP& default_value = CGAL_XX_YATP()) \ -{ \ - return get(t, static_cast(g), default_value); \ -}\ -} //CGAL namespace +} /* boost namespace */ + CGAL_PM_DT_SPEC(CGAL::dynamic_vertex_property_t) CGAL_PM_DT_SPEC(CGAL::dynamic_halfedge_property_t) @@ -94,12 +79,31 @@ CGAL_PM_DT_SPEC(CGAL::dynamic_edge_property_t) namespace CGAL { +template ()>, + typename ...Default_value_args> +auto +get(Dynamic_property_tag t, CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, Default_value_args&&... default_value_args) +{ + return get(t, static_cast(g), default_value_args...); +} + +template ()>, + typename ...Default_value_args> +auto +get(Dynamic_property_tag t, const CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, Default_value_args&&... default_value_args) +{ + return get(t, static_cast(g), default_value_args...); +} + template struct graph_has_property : public CGAL::graph_has_property {}; - } // CGAL namespace #undef CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS @@ -126,23 +130,8 @@ template \ struct property_map > \ : property_map > \ {};\ -} /* boost namespace */\ -\ -namespace CGAL { \ -template \ -typename boost::property_map >::type \ -get(DTAG t, CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, const CGAL_XX_YATP& default_value = CGAL_XX_YATP()) \ -{ \ - return get(t, static_cast(g), default_value); \ -} \ -\ -template \ -typename boost::property_map >::const_type \ -get(DTAG t, const CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, const CGAL_XX_YATP& default_value = CGAL_XX_YATP()) \ -{ \ - return get(t, static_cast(g), default_value); \ -}\ -} //CGAL namespace +} /* boost namespace */ + CGAL_PM_DT_SPEC(CGAL::dynamic_vertex_property_t) CGAL_PM_DT_SPEC(CGAL::dynamic_halfedge_property_t) @@ -153,14 +142,32 @@ CGAL_PM_DT_SPEC(CGAL::dynamic_edge_property_t) namespace CGAL { +template ()>, + typename ...Default_value_args> +auto +get(Dynamic_property_tag t, CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, Default_value_args&&... default_value_args) +{ + return get(t, static_cast(g), default_value_args...); +} + +template ()>, + typename ...Default_value_args> +auto +get(Dynamic_property_tag t, const CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g, Default_value_args&&... default_value_args) +{ + return get(t, static_cast(g), default_value_args...); +} + template struct graph_has_property : public CGAL::graph_has_property {}; - } // CGAL namespace + #endif 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/BGL/include/CGAL/boost/graph/iterator.h b/BGL/include/CGAL/boost/graph/iterator.h index cef4a913cad..e26d7892cbd 100644 --- a/BGL/include/CGAL/boost/graph/iterator.h +++ b/BGL/include/CGAL/boost/graph/iterator.h @@ -871,7 +871,54 @@ private: */ template class Face_around_face_circulator -{}; +#ifndef DOXYGEN_RUNNING + : public boost::iterator_adaptor< + Face_around_face_circulator // Derived + , Halfedge_around_face_circulator // Base + , typename boost::graph_traits::face_descriptor // Value + , Bidirectional_circulator_tag // CategoryOrTraversal + , typename boost::graph_traits::face_descriptor // Reference + > +#endif +{ + internal::Opposite_face fct; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + +public: +#ifndef DOXYGEN_RUNNING + typedef std::size_t size_type; +#endif + + Face_around_face_circulator() + {} + + Face_around_face_circulator(halfedge_descriptor h, const Graph& g) + : Face_around_face_circulator::iterator_adaptor_(Halfedge_around_face_circulator(h,g)), fct(g) + {} + +#ifndef DOXYGEN_RUNNING + + explicit operator bool() const + { + return (! (this->base_reference() == nullptr)); + } + + bool operator== (void*) const + { + return this->base_reference()== nullptr; + } + + bool operator!= (void*) const + { + return this->base_reference()!= nullptr; + } + +private: + friend class boost::iterator_core_access; + typename boost::graph_traits::face_descriptor dereference() const { return fct(*this->base_reference()); } +#endif + +}; /** * \ingroup PkgBGLIterators diff --git a/BGL/test/BGL/CMakeLists.txt b/BGL/test/BGL/CMakeLists.txt index 016e0009d4f..6affc9511d8 100644 --- a/BGL/test/BGL/CMakeLists.txt +++ b/BGL/test/BGL/CMakeLists.txt @@ -38,7 +38,6 @@ create_single_source_cgal_program("test_graph_traits.cpp") create_single_source_cgal_program("test_Properties.cpp") create_single_source_cgal_program("bench_read_from_stream_vs_add_face_and_add_faces.cpp") create_single_source_cgal_program("graph_traits_inheritance.cpp" ) -create_single_source_cgal_program("test_deprecated_io.cpp") find_package(OpenMesh QUIET) if(OpenMesh_FOUND) @@ -69,8 +68,6 @@ if (VTK_FOUND AND VTK_LIBRARIES) message(STATUS "VTK ${VTK_VERSION} found ${VTK_LIBRARIES}") target_link_libraries(test_bgl_read_write PRIVATE ${VTK_LIBRARIES}) target_compile_definitions(test_bgl_read_write PRIVATE -DCGAL_USE_VTK -DNOMINMAX) - target_link_libraries(test_deprecated_io PRIVATE ${VTK_LIBRARIES}) - target_compile_definitions(test_deprecated_io PRIVATE -DCGAL_USE_VTK -DNOMINMAX) else() message(STATUS "Tests that use VTK will not be compiled.") endif() #VTK_FOUND diff --git a/BGL/test/BGL/graph_traits_inheritance.cpp b/BGL/test/BGL/graph_traits_inheritance.cpp index fd4540af69e..80ecbd69820 100644 --- a/BGL/test/BGL/graph_traits_inheritance.cpp +++ b/BGL/test/BGL/graph_traits_inheritance.cpp @@ -4,6 +4,7 @@ #include #include #include +#include typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; @@ -75,5 +76,12 @@ int main() My_mesh_5 poly5; CGAL::convex_hull_3(points.begin(), points.end(), poly5); + + CGAL::Polygon_mesh_processing::non_manifold_vertices(poly1, CGAL::Emptyset_iterator()); + CGAL::Polygon_mesh_processing::non_manifold_vertices(poly2, CGAL::Emptyset_iterator()); + CGAL::Polygon_mesh_processing::non_manifold_vertices(poly3, CGAL::Emptyset_iterator()); + CGAL::Polygon_mesh_processing::non_manifold_vertices(poly4, CGAL::Emptyset_iterator()); + CGAL::Polygon_mesh_processing::non_manifold_vertices(poly5, CGAL::Emptyset_iterator()); + return 0; } diff --git a/BGL/test/BGL/test_circulator.cpp b/BGL/test/BGL/test_circulator.cpp index cd0a18cbbe4..58c56bbd6df 100644 --- a/BGL/test/BGL/test_circulator.cpp +++ b/BGL/test/BGL/test_circulator.cpp @@ -18,6 +18,7 @@ typedef GraphTraits::edge_descriptor edge_descriptor; typedef GraphTraits::out_edge_iterator out_edge_iterator; typedef GraphTraits::in_edge_iterator in_edge_iterator; +typedef CGAL::Face_around_face_circulator face_around_face_circulator; typedef CGAL::Halfedge_around_face_circulator halfedge_around_face_circulator; typedef CGAL::Halfedge_around_target_circulator halfedge_around_target_circulator; typedef CGAL::Vertex_around_target_circulator vertex_around_target_circulator; @@ -32,6 +33,7 @@ typedef CGAL::Vertex_around_target_iterator vertex_around_target_ite int main(int argc, char* argv[]) { + BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator)); BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator)); BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator)); BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator)); @@ -62,6 +64,14 @@ int main(int argc, char* argv[]) }while(hafc != done); } + { + face_around_face_circulator fafc(hd,P), done(fafc); + + do { + ++fafc; + }while(fafc != done); + } + { halfedge_around_target_circulator havc(hd,P), done(havc); vertex_descriptor vd = target(hd,P); diff --git a/BGL/test/BGL/test_deprecated_io.cpp b/BGL/test/BGL/test_deprecated_io.cpp deleted file mode 100644 index 8c22b9f17df..00000000000 --- a/BGL/test/BGL/test_deprecated_io.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - - -typedef CGAL::Simple_cartesian Kernel; -typedef Kernel::Point_3 Point_3; -typedef CGAL::Surface_mesh SM; - -int main() -{ - // OFF - SM sm_in, sm_out; - Point_3 p0(0,0,0), p1(1,0,0), p2(0,1,0); - CGAL::make_triangle(p0, p1, p2, sm_out); - bool ok = CGAL::write_off("tmp_deprecated.off", sm_out); - assert(ok); - ok = CGAL::read_off("tmp_deprecated.off", sm_in); - assert(ok); - assert(num_vertices(sm_in) == 3 && num_faces(sm_in) == 1); - sm_in.clear(); - - std::ofstream os("tmp_deprecated.off"); - ok = CGAL::write_off(os, sm_out); - assert(ok); - os.close(); - std::ifstream is("tmp_deprecated.off"); - ok = CGAL::read_off(is, sm_in); - assert(ok); - assert(num_vertices(sm_in) == 3 && num_faces(sm_in) == 1); - is.close(); - sm_in.clear(); -#ifdef CGAL_USE_VTK - //vtk - os.open("tmp_deprecated.vtp"); - ok = CGAL::write_vtp(os, sm_out); - assert(ok); - os.close(); - - ok = CGAL::IO::read_VTP("tmp_deprecated.vtp", sm_in); - assert(ok); - assert(num_vertices(sm_in) == 3 && num_faces(sm_in) == 1); - sm_in.clear(); -#endif - //wrl - os.open("tmp_deprecated.wrl"); - ok = CGAL::write_wrl(os, sm_out); - assert(ok); - os.close(); - return EXIT_SUCCESS; -} 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/examples/Basic_viewer/CMakeLists.txt b/Basic_viewer/examples/Basic_viewer/CMakeLists.txt index 4106c9defb4..e6aa5faba8a 100644 --- a/Basic_viewer/examples/Basic_viewer/CMakeLists.txt +++ b/Basic_viewer/examples/Basic_viewer/CMakeLists.txt @@ -15,8 +15,6 @@ find_package(Eigen3 3.1.0) include(CGAL_Eigen3_support) create_single_source_cgal_program("draw_lcc.cpp") -create_single_source_cgal_program("draw_mesh_and_points.cpp") -create_single_source_cgal_program("draw_several_windows.cpp") create_single_source_cgal_program("draw_surface_mesh_height.cpp") create_single_source_cgal_program("draw_surface_mesh_small_faces.cpp") create_single_source_cgal_program("draw_surface_mesh_vcolor.cpp") @@ -24,18 +22,19 @@ create_single_source_cgal_program("draw_surface_mesh_vcolor.cpp") if(CGAL_Qt6_FOUND) #link it with the required CGAL libraries target_link_libraries(draw_lcc PRIVATE CGAL::CGAL_Basic_viewer) - target_link_libraries(draw_mesh_and_points PRIVATE CGAL::CGAL_Basic_viewer) - target_link_libraries(draw_several_windows PRIVATE CGAL::CGAL_Basic_viewer) target_link_libraries(draw_surface_mesh_height PRIVATE CGAL::CGAL_Basic_viewer) target_link_libraries(draw_surface_mesh_small_faces PRIVATE CGAL::CGAL_Basic_viewer) target_link_libraries(draw_surface_mesh_vcolor PRIVATE CGAL::CGAL_Basic_viewer) + if(TARGET CGAL::Eigen3_support) + create_single_source_cgal_program("draw_mesh_and_points.cpp") + create_single_source_cgal_program("draw_several_windows.cpp") + target_link_libraries(draw_mesh_and_points PRIVATE CGAL::Eigen3_support CGAL::CGAL_Basic_viewer) + target_link_libraries(draw_several_windows PRIVATE CGAL::Eigen3_support CGAL::CGAL_Basic_viewer) + else() + message("Eigen3 is not found, examples that require Eigen3 will not be compiled.") + endif() else() message("CGAL_Qt6 not configured: examples that require Qt will not be compiled.") endif() -if(TARGET CGAL::Eigen3_support) - target_link_libraries(draw_mesh_and_points PRIVATE CGAL::Eigen3_support) - target_link_libraries(draw_several_windows PRIVATE CGAL::Eigen3_support) -endif() - #end of the file 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/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h index a709bddd4b1..baf8908269c 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h @@ -622,7 +622,7 @@ bool are_holes_and_boundary_pairwise_disjoint Topology_traits; typedef CGAL::Gps_on_surface_base_2 Polygon_set_2; - typedef typename Polygon_set_2::Size Size; + // typedef typename Polygon_set_2::Size Size; typedef typename Traits_2::Polygon_2 Polygon_2; typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; typedef typename Polygon_with_holes_2::Hole_const_iterator @@ -676,7 +676,7 @@ bool are_holes_and_boundary_pairwise_disjoint Polygon_set_2 gps(traits); // check for 2D intersections of holes (holes must be disjoint except for // vertices) - Size num_of_holes = 0; + // Size num_of_holes = 0; // functors for creating a pwh needed for inserting pgns into the arrangement // quickly Construct_polygon_with_holes_2 construct_pwh_functor = @@ -700,7 +700,7 @@ bool are_holes_and_boundary_pairwise_disjoint // traits.Construct_polygon_with_holes_2 (hole); // Polygon_with_holes_2 empty_pwh(hole); gps.insert(empty_pwh); - num_of_holes++; + // num_of_holes++; } } /* not good - doesn't work if intersection at vertices is legal. diff --git a/Bounding_volumes/doc/Bounding_volumes/CGAL/Min_ellipse_2.h b/Bounding_volumes/doc/Bounding_volumes/CGAL/Min_ellipse_2.h index 35a903babec..c77b7c8f2f3 100644 --- a/Bounding_volumes/doc/Bounding_volumes/CGAL/Min_ellipse_2.h +++ b/Bounding_volumes/doc/Bounding_volumes/CGAL/Min_ellipse_2.h @@ -5,7 +5,7 @@ namespace CGAL { \ingroup PkgBoundingVolumesRef An object of the class `Min_ellipse_2` is the unique ellipse of smallest area -enclosing a finite (multi)set of points in two-dimensional euclidean +enclosing a finite (multi)set of points in two-dimensional Euclidean space \f$ \E^2\f$. For a point set \f$ P\f$ we denote by \f$ me(P)\f$ the smallest ellipse that contains all points of \f$ P\f$. Note that \f$ me(P)\f$ can be degenerate, 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_Core/include/CGAL/CORE/Config.h b/CGAL_Core/include/CGAL/CORE/Config.h index 9f49a7f5986..36a342a5f73 100644 --- a/CGAL_Core/include/CGAL/CORE/Config.h +++ b/CGAL_Core/include/CGAL/CORE/Config.h @@ -29,12 +29,10 @@ #include -#ifdef CGAL_TEST_SUITE -// disabled for the testsuite to avoid `w` -#define CGAL_CORE_warning_msg(X ,Y) -// if (!(X)) CGAL_error_msg(Y) -#else +#ifdef CGAL_CORE_DEBUG #define CGAL_CORE_warning_msg(X ,Y) CGAL_warning_msg(X ,Y) +#else +#define CGAL_CORE_warning_msg(X ,Y) #endif diff --git a/CGAL_ImageIO/include/CGAL/SEP_to_ImageIO.h b/CGAL_ImageIO/include/CGAL/SEP_to_ImageIO.h index 97bd4502006..54ed43b9814 100644 --- a/CGAL_ImageIO/include/CGAL/SEP_to_ImageIO.h +++ b/CGAL_ImageIO/include/CGAL/SEP_to_ImageIO.h @@ -20,13 +20,7 @@ #include #include -#include -#include - -#ifndef BOOST_FILESYSTEM_VERSION -// That macro was not defined in previous releases of Boost. -# define BOOST_FILESYSTEM_VERSION 2 -#endif +#include #include @@ -60,15 +54,9 @@ public: } display_information(fileName, std::cout); - boost::filesystem::path headerFile(fileName); - boost::filesystem::path dataFile(string_field("in")); -#if BOOST_FILESYSTEM_VERSION == 2 - dataFile = boost::filesystem::complete(dataFile, - boost::filesystem::complete(headerFile.parent_path())); -#else - dataFile = boost::filesystem::absolute(dataFile, - boost::filesystem::absolute(headerFile.parent_path())); -#endif + std::filesystem::path headerFile(fileName); + std::filesystem::path dataFile = std::filesystem::absolute(fileName).parent_path() / std::filesystem::path(string_field("in")); + if(!load_data(dataFile.string())) { return; err_msg = "Invalid data file \""; 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/doc/Circular_kernel_2/Concepts/AlgebraicKernelForCircles.h b/Circular_kernel_2/doc/Circular_kernel_2/Concepts/AlgebraicKernelForCircles.h index 6241ca39f35..0428ed952ae 100644 --- a/Circular_kernel_2/doc/Circular_kernel_2/Concepts/AlgebraicKernelForCircles.h +++ b/Circular_kernel_2/doc/Circular_kernel_2/Concepts/AlgebraicKernelForCircles.h @@ -29,7 +29,7 @@ A model of `RingNumberType`. typedef unspecified_type RT; /*! -A model of `FieldNumberType```. +A model of `FieldNumberType`. */ typedef unspecified_type FT; 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/doc/Circular_kernel_3/Concepts/AlgebraicKernelForSpheres.h b/Circular_kernel_3/doc/Circular_kernel_3/Concepts/AlgebraicKernelForSpheres.h index c258b5020a9..a3bfabdf0e2 100644 --- a/Circular_kernel_3/doc/Circular_kernel_3/Concepts/AlgebraicKernelForSpheres.h +++ b/Circular_kernel_3/doc/Circular_kernel_3/Concepts/AlgebraicKernelForSpheres.h @@ -29,7 +29,7 @@ A model of `RingNumberType`. typedef unspecified_type RT; /*! -A model of `FieldNumberType```. +A model of `FieldNumberType`. */ typedef unspecified_type FT; 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 fbe5315f6d3..abeeb7bde3b 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 44d653e2c83..fe661377baa 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,7 +3710,7 @@ namespace CGAL { void set_automatic_attributes_management_without_correction(bool newval) { this->automatic_attributes_management = newval; } - /** Creates an half-edge. + /** Creates a half-edge. * @return a dart of the new half-edge. */ Dart_descriptor make_half_edge() diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map_save_load.h b/Combinatorial_map/include/CGAL/Combinatorial_map_save_load.h index e691fce122c..b238637ee3f 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map_save_load.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map_save_load.h @@ -176,7 +176,7 @@ namespace CGAL { { if (amap.template attribute(it)!=amap.null_descriptor) { - // make composant, dart and property node + // make component, dart and property node boost::property_tree::ptree & nattr = ndim.add("a", ""); /* boost::property_tree::ptree & ndarts = */ nattr.add("d", myDarts[it]); @@ -209,7 +209,7 @@ namespace CGAL { { if (amap.template attribute(it)!=amap.null_descriptor) { - // make composant, dart and property node + // make component, dart and property node boost::property_tree::ptree & nattr = ndim.add("a", ""); /* boost::property_tree::ptree & ndarts = */ nattr.add("d", myDarts[it]); @@ -242,7 +242,7 @@ namespace CGAL { { if (amap.template attribute(it)!=amap.null_descriptor) { - // make composant, dart and property node + // make component, dart and property node boost::property_tree::ptree & nattr = ndim.add("a", ""); /* boost::property_tree::ptree & ndarts = */ nattr.add("d", myDarts[it]); @@ -274,7 +274,7 @@ namespace CGAL { { if (amap.template attribute(it)!=amap.null_descriptor) { - // make composant, dart and property node + // make component, dart and property node boost::property_tree::ptree & nattr = ndim.add("a", ""); /* boost::property_tree::ptree & ndarts = */ nattr.add("d", myDarts[it]); 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/doc/Constrained_triangulation_3/Constrained_triangulation_3.txt b/Constrained_triangulation_3/doc/Constrained_triangulation_3/Constrained_triangulation_3.txt index cde3fcb844c..d0c50bc5c78 100644 --- a/Constrained_triangulation_3/doc/Constrained_triangulation_3/Constrained_triangulation_3.txt +++ b/Constrained_triangulation_3/doc/Constrained_triangulation_3/Constrained_triangulation_3.txt @@ -49,12 +49,13 @@ that satisfy the following properties: - Each polygonal face must be a simple polygon, i.e., its edges don't intersect, except consecutive edges, which intersect at their common vertex. - Each polygonal face must be planar, meaning all its vertices lie on the same plane. +- Each polygonal face may be non-convex. - Each polygonal face may have one or more holes, each of them also represented by an ordered list of vertices from the PLC, forming a closed loop. -- If two polygons in the PLC intersect, their intersection is a union of edges and vertices from the - PLC. In particular, the interiors of two polygons cannot overlap. +- Polygonal holes may be non-convex. +- If two polygonal faces in the PLC intersect, their intersection is a union of edges and vertices from the + PLC. In particular, the interiors of two polygonal faces cannot overlap. -Polygons in a PLC may be non-convex and may have holes. \cgalFigureAnchor{CT_3_plc_fig}
    @@ -79,7 +80,7 @@ possible to being Delaunay, given that some faces are marked as _constrained_. M triangulation is _constrained Delaunay_ if, for any simplex \f$s\f$ of the triangulation, the interior of its circumscribing sphere contains no vertex of the triangulation that is _visible_ from any point in the interior of the simplex \f$s\f$. Two points are _visible_ if the open line segment -joining them does not intersect any polygonal face of the PLC, except for polygons that are coplanar with +joining them does not intersect any polygonal face of the PLC, except for polygonal faces that are coplanar with the segment. In 3D, constrained triangulations do not always exist. This can be demonstrated using the example of @@ -87,7 +88,7 @@ Schönhardt polyhedra \cgalCite{s-udzvd-28} (see \cgalFigureRef{CT_3_schonha \cgalCite{b-ip-48a}. Shewchuk \cgalCite{cgal:shewchuk1998condition} demonstrated that for any PLC, there exists a refined version of the original PLC that admits a constrained Delaunay triangulation. This refinement is -achieved by adding Steiner vertices to the input edges and polygons. The constrained triangulation +achieved by adding Steiner vertices to the input edges and polygonal faces. The constrained triangulation built on this refined PLC is known as a _conforming constrained Delaunay triangulation_ (CCDT for short). \cgalFigureRef{CT_3_plc2cdt_fig} illustrates an example of a conforming constrained Delaunay triangulation constructed from a PLC. @@ -113,7 +114,8 @@ Right: CCDT (2452 vertices). The algorithm implemented in this package is based on the work of Hang Si et al., who developed particular algorithms for constructing conforming constrained Delaunay triangulations from PLCs. -The corresponding implementation takes with floating point numbers as coordinates +The corresponding implementation is designed to handle points whose coordinates +are floating-point numbers. \cgalCite{si2005meshing}, \cgalCite{cgal:si2008cdt3}, \cgalCite{si2015tetgen}. @@ -136,14 +138,15 @@ manifold (that is, each edge belongs to exactly two faces), and their faces cann A PLC can also be represented as a polygon soup: a collection of vertices and a set of polygons, where each polygon is defined by an ordered list of vertices, without explicit connectivity information between -polygons. For a polygon soup to represent a valid PLC, its polygons must satisfy the properties described +polygons. For a polygon soup to represent a valid PLC, its polygons must satisfy the +polygonal faces properties described in the previous section. This approach allows for the representation of non-manifold geometries; however, polygons in a polygon soup cannot have holes. -This package also provides a way to group polygons into distinct surface patches using a property map, +This package also provides a way to group polygonal faces into distinct surface patches using a property map, named `plc_face_id`. -Each polygon can be assigned a _patch_ identifier, allowing multiple polygons to form a continuous surface patch, -which may include holes. Some necessary geometric conditions must be satisfied for these patches to be +Each polygon can be assigned a _patch_ identifier, allowing multiple polygonal faces to form a continuous surface patch, +which may include holes. Some necessary conditions must be satisfied for these patches to be used in the conforming constrained Delaunay triangulation construction: - Each patch must be planar, meaning all polygonal faces in the patch lie on the same plane; - The polygonal faces of the patch must not intersect except at their shared edges. @@ -181,7 +184,8 @@ However, because this package builds upon the 3D Triangulation package, it inher that the traits class must provide exact predicates. A key aspect of this algorithm is the creation of new points, known as Steiner points, which are -inserted on the segments and polygons of the input PLC. If a traits class with inexact constructions +inserted on the segments and polygons forming the input PLC polygonal faces. +If a traits class with inexact constructions is used, it cannot be guaranteed that these points will lie exactly on the intended segments or polygons. As a result, the output will only approximate the input, with the accuracy limited by the rounding of the computed Steiner points. diff --git a/Constrained_triangulation_3/examples/Constrained_triangulation_3/remesh_constrained_Delaunay_triangulation_3.cpp b/Constrained_triangulation_3/examples/Constrained_triangulation_3/remesh_constrained_Delaunay_triangulation_3.cpp index e87918ee70b..48ce6b2a194 100644 --- a/Constrained_triangulation_3/examples/Constrained_triangulation_3/remesh_constrained_Delaunay_triangulation_3.cpp +++ b/Constrained_triangulation_3/examples/Constrained_triangulation_3/remesh_constrained_Delaunay_triangulation_3.cpp @@ -42,6 +42,8 @@ using Constraints_pmap = CGAL::Boolean_property_map; int main(int argc, char* argv[]) { std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/mpi.off"); + double target_edge_length = (argc > 2) ? std::stod(argv[2]) : 1.0; + unsigned int iterations = (argc > 3) ? std::stoi(argv[3]) : 3; CGAL::Surface_mesh mesh; if(!CGAL::IO::read_polygon_mesh(filename, mesh)) @@ -62,17 +64,16 @@ int main(int argc, char* argv[]) namespace Tet_remesh = CGAL::Tetrahedral_remeshing; Tr tr = Tet_remesh::get_remeshing_triangulation(std::move(ccdt), np::edge_is_constrained_map(constraints_pmap)); - std::cout << "Number of vertices in tr: " << tr.number_of_vertices() << std::endl; + std::cout << "There are " << tr.number_of_vertices() << " vertices in the constrained triangulation" << std::endl; CGAL::tetrahedral_isotropic_remeshing(tr, - 1., // target edge length - np::number_of_iterations(3) - .edge_is_constrained_map(constraints_pmap)); + target_edge_length, + np::number_of_iterations(iterations) + .edge_is_constrained_map(constraints_pmap)); - std::cout << "Number of vertices in tr: " - << tr.number_of_vertices() << std::endl; + std::cout << "There are " << tr.number_of_vertices() << " vertices after remeshing" << std::endl; - std::ofstream ofs("tr.mesh"); + std::ofstream ofs("remeshed.mesh"); CGAL::IO::write_MEDIT(ofs, tr); return EXIT_SUCCESS; diff --git a/Constrained_triangulation_3/include/CGAL/Conforming_Delaunay_triangulation_3.h b/Constrained_triangulation_3/include/CGAL/Conforming_Delaunay_triangulation_3.h index e1e6ae46326..b98eccbb60e 100644 --- a/Constrained_triangulation_3/include/CGAL/Conforming_Delaunay_triangulation_3.h +++ b/Constrained_triangulation_3/include/CGAL/Conforming_Delaunay_triangulation_3.h @@ -369,6 +369,10 @@ public: return debug_flags[static_cast(Debug_flags::use_older_cavity_algorithm)]; } + bool use_newer_cavity_algorithm() const { + return !debug_flags[static_cast(Debug_flags::use_older_cavity_algorithm)]; + } + void use_older_cavity_algorithm(bool b) { debug_flags.set(static_cast(Debug_flags::use_older_cavity_algorithm), b); } @@ -772,7 +776,9 @@ protected: std::cerr << "!! The constraint passes through a vertex!\n"; std::cerr << " -> constraint " << display_vert(va) << " " << display_vert(vb) << '\n'; std::cerr << " -> vertex " << display_vert(v) << '\n'; +#if CGAL_DEBUG_CDT_3 debug_dump("bug-through-vertex"); +#endif CGAL_error(); } } break; 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 60029fab9ce..2c63b765f4b 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 @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include @@ -71,8 +73,10 @@ #include #include #include +#include #include #include +#include #include #if CGAL_CXX20 && __has_include() # include @@ -186,8 +190,10 @@ does_first_triangle_intersect_second_triangle_interior(const typename K::Triangl auto comp = k.compare_xyz_3_object(); auto sort_ptrs = [&comp](const Point_3* p1, const Point_3* p2) { return comp(*p1, *p2) == SMALLER; }; auto intersection_is_a_vertex_or_a_common_edge = [&]() { + CGAL_assume(nb_of_t1_vertices_in_the_line >= 0 && nb_of_t1_vertices_in_the_line <= 3); std::sort(t1_vertices_in_the_line.data(), t1_vertices_in_the_line.data() + nb_of_t1_vertices_in_the_line, sort_ptrs); + CGAL_assume(nb_of_t2_vertices_in_the_line >= 0 && nb_of_t2_vertices_in_the_line <= 3); std::sort(t2_vertices_in_the_line.data(), t2_vertices_in_the_line.data() + nb_of_t2_vertices_in_the_line, sort_ptrs); std::size_t nb_of_common_vertices = 0; @@ -924,7 +930,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 { @@ -934,7 +940,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 { @@ -1570,6 +1576,36 @@ public: private: + void set_mark(Vertex_handle v, Vertex_marker m) { + v->ccdt_3_data().set_mark(m); + } + + template + void set_marks(Range_of_vertices&& vertices, Vertex_marker m) { + for(auto v : vertices) { + set_mark(v, m); + } + } + + void clear_mark(Vertex_handle v, Vertex_marker m) { + v->ccdt_3_data().clear_mark(m); + } + + template + void clear_marks(Range_of_vertices&& vertices, Vertex_marker m) { + for(auto v : vertices) { + clear_mark(v, m); + } + } + + bool is_marked(Vertex_handle v, Vertex_marker m) const { + return v->ccdt_3_data().is_marked(m); + } + + bool is_marked(Vertex_handle v) const { + return v->ccdt_3_data().is_marked(); + } + class Non_planar_plc_facet_exception : public std::exception { const char* what() const throw() @@ -1937,8 +1973,8 @@ private: const auto index_vd = this->next_around_edge(index_vb, index_va); //write_segment(dump_edges_around, cell_circ->vertex(index_vc), cell_circ->vertex(index_vd)); - if(cell_circ->vertex(index_vc)->ccdt_3_data().is_marked(Vertex_marker::REGION_BORDER)) continue; - if(cell_circ->vertex(index_vd)->ccdt_3_data().is_marked(Vertex_marker::REGION_BORDER)) continue; + if(is_marked(cell_circ->vertex(index_vc), Vertex_marker::REGION_BORDER)) continue; + if(is_marked(cell_circ->vertex(index_vd), Vertex_marker::REGION_BORDER)) continue; int cd_intersects_region = does_edge_intersect_region(cell_circ, index_vc, index_vd, cdt_2, fh_region); if(cd_intersects_region == 1) { return Search_first_intersection_result_type{ Edge{cell_circ, index_vc, index_vd}, border_edge }; @@ -1989,401 +2025,76 @@ private: facets_of_upper_cavity, facets_of_lower_cavity] = outputs; // to avoid "warning: captured structured bindings are a C++20 extension [-Wc++20-extensions]"" - auto& intersecting_edges_ = intersecting_edges; auto& vertices_of_upper_cavity_ = vertices_of_upper_cavity; auto& vertices_of_lower_cavity_ = vertices_of_lower_cavity; + const auto& cr_intersecting_cells = intersecting_cells; std::set> non_intersecting_edges_set; - // marker for already visited elements - std::set visited_vertices; - std::map, bool> visited_edges; - std::set visited_cells; - - auto make__new_element_functor = [](auto& visited_set) { - return [&visited_set](auto... e) { - const auto [_, not_already_visited] = visited_set.emplace(e...); - return not_already_visited; - }; - }; - - auto new_vertex = make__new_element_functor(visited_vertices); - auto new_cell = make__new_element_functor(visited_cells); - auto new_edge = [&](Vertex_handle v0, Vertex_handle v1, bool does_intersect) { - CGAL_assertion(v0 != Vertex_handle{}); - return visited_edges.emplace(CGAL::make_sorted_pair(v0, v1), does_intersect); - }; - -#if CGAL_CDT_3_CAN_USE_CXX20_FORMAT - using Mesh = Surface_mesh; - using Face_index = typename Mesh::Face_index; - using EK = CGAL::Exact_predicates_exact_constructions_kernel; - const auto to_exact = CGAL::Cartesian_converter(); - const auto from_exact = CGAL::Cartesian_converter(); - if(this->debug_regions()) { - - Mesh tets_intersect_region_mesh; - auto [color_vpmap, _] = tets_intersect_region_mesh.template add_property_map("f:patch_id"); - - for(auto ch : tr().finite_cell_handles()) { - auto tetrahedron = typename Geom_traits::Tetrahedron_3{tr().point(ch->vertex(0)), tr().point(ch->vertex(1)), - tr().point(ch->vertex(2)), tr().point(ch->vertex(3))}; - if(!std::any_of(fh_region.begin(), fh_region.end(), [&](auto fh) { - const auto v0 = fh->vertex(0)->info().vertex_handle_3d; - const auto v1 = fh->vertex(1)->info().vertex_handle_3d; - const auto v2 = fh->vertex(2)->info().vertex_handle_3d; - const auto triangle = typename Geom_traits::Triangle_3{tr().point(v0), tr().point(v1), tr().point(v2)}; - return does_tetrahedron_intersect_triangle_interior(tetrahedron, triangle, tr().geom_traits()); - })) - { - continue; - } - bool intersects = false; - for(int i = 0; i < 4; ++i) { - for(int j = i + 1; j < 4; ++j) { - int intersects_region = does_edge_intersect_region(ch, i, j, cdt_2, fh_region); - if(intersects_region != 0) { - intersects = true; - } - } - } - if(!intersects) { - std::cerr << "ERROR: tetrahedron #" << ch->time_stamp() << " has no edge intersecting the region\n"; - } - std::ofstream dump_tetrahedron( - cdt_3_format("dump_intersecting_{}_{}_tetrahedron_{}.off", face_index, region_index, ch->time_stamp())); - dump_tetrahedron.precision(17); - Mesh mesh; - CGAL::make_tetrahedron(tr().point(ch->vertex(0)), tr().point(ch->vertex(1)), tr().point(ch->vertex(2)), - tr().point(ch->vertex(3)), mesh); - dump_tetrahedron << mesh; - dump_tetrahedron.close(); - - auto exact_tetrahedron = to_exact(tetrahedron); - for(auto fh : fh_region) { - auto v0 = fh->vertex(0)->info().vertex_handle_3d; - auto v1 = fh->vertex(1)->info().vertex_handle_3d; - auto v2 = fh->vertex(2)->info().vertex_handle_3d; - auto triangle = typename Geom_traits::Triangle_3{tr().point(v0), tr().point(v1), tr().point(v2)}; - - auto exact_triangle = to_exact(triangle); - auto tetrahedron_triangle_intersection_opt = CGAL::intersection(exact_tetrahedron, exact_triangle); - if(!tetrahedron_triangle_intersection_opt) { - continue; - } - if(const auto* tri = std::get_if(&tetrahedron_triangle_intersection_opt.value())) { - exact(*tri); - auto v0 = tets_intersect_region_mesh.add_vertex(from_exact((*tri)[0])); - auto v1 = tets_intersect_region_mesh.add_vertex(from_exact((*tri)[1])); - auto v2 = tets_intersect_region_mesh.add_vertex(from_exact((*tri)[2])); - std::array arr{v0, v1, v2}; - auto f = CGAL::Euler::add_face(arr, tets_intersect_region_mesh); - put(color_vpmap, f, static_cast(ch->time_stamp())); - } - if(const auto* vec = std::get_if>(&tetrahedron_triangle_intersection_opt.value())) - { - std::vector vec_of_indices; - for(const auto& p : *vec) { - exact(p); - vec_of_indices.push_back(tets_intersect_region_mesh.add_vertex(from_exact(p))); - } - CGAL::Euler::add_face(vec_of_indices, tets_intersect_region_mesh); - } - } - } - std::ofstream tets_intersect_region_out( - cdt_3_format("dump_tets_intersect_region_{}_{}.ply", face_index, region_index)); - tets_intersect_region_out.precision(17); - CGAL::IO::write_PLY(tets_intersect_region_out, tets_intersect_region_mesh); - tets_intersect_region_out.close(); + if constexpr (cdt_3_can_use_cxx20_format()) if(this->debug_regions()) { + debug_dump_tetrahedra_intersect_region(face_index, region_index, cdt_2, fh_region); } -#endif // CGAL_CDT_3_CAN_USE_CXX20_FORMAT - intersecting_edges.push_back(first_intersecting_edge); - const auto [v0, v1] = tr().vertices(first_intersecting_edge); - (void)new_edge(v0, v1, true); - for(std::size_t i = 0; i < intersecting_edges.size(); ++i) { - const auto intersecting_edge = intersecting_edges[i]; - const auto [v_above, v_below] = tr().vertices(intersecting_edge); -#if CGAL_CDT_3_CAN_USE_CXX20_FORMAT - if(this->debug_regions()) { - std::cerr << cdt_3_format("restore_subface_region face index: {}, region #{}, intersecting edge #{}: ({} {})\n", - face_index, region_index, i, - IO::oformat(v_above, with_point_and_info), - IO::oformat(v_below, with_point_and_info)); - dump_region(face_index, region_index, cdt_2); - } -#endif // CGAL_CDT_3_CAN_USE_CXX20_FORMAT - -#if CGAL_CDT_3_CAN_USE_CXX20_FORMAT - if(this->debug_regions()) { - const auto p_above = this->point(v_above); - const auto p_below = this->point(v_below); - const auto edge_segment = typename Geom_traits::Segment_3{p_above, p_below}; - const auto exact_edge_segment = to_exact(edge_segment); - - std::ofstream intersect_out("dump_edge_region_intersection.xyz"); - intersect_out.precision(17); - for(auto fh: fh_region) { - auto v0 = fh->vertex(0)->info().vertex_handle_3d; - auto v1 = fh->vertex(1)->info().vertex_handle_3d; - auto v2 = fh->vertex(2)->info().vertex_handle_3d; - auto triangle = typename Geom_traits::Triangle_3{tr().point(v0), tr().point(v1), tr().point(v2)}; - auto exact_triangle = to_exact(triangle); - if(auto edge_intersection_opt = CGAL::intersection(exact_edge_segment, exact_triangle)) { - const auto& edge_intersection = *edge_intersection_opt; - if(const auto* p = std::get_if(&edge_intersection)) { - exact(*p); - intersect_out << *p << '\n'; - } - } - } - intersect_out.close(); - - auto cells_around_intersecting_edge = Container_from_circulator{this->incident_cells(intersecting_edge)}; - for(const auto& cell: cells_around_intersecting_edge) { - CGAL_assertion(!cell.has_vertex(tr().infinite_vertex())); - auto tetrahedron = - typename Geom_traits::Tetrahedron_3{tr().point(cell.vertex(0)), tr().point(cell.vertex(1)), - tr().point(cell.vertex(2)), tr().point(cell.vertex(3))}; - for(auto fh: fh_region) { - auto v0 = fh->vertex(0)->info().vertex_handle_3d; - auto v1 = fh->vertex(1)->info().vertex_handle_3d; - auto v2 = fh->vertex(2)->info().vertex_handle_3d; - auto triangle = typename Geom_traits::Triangle_3{tr().point(v0), tr().point(v1), tr().point(v2)}; - auto exact_triangle = to_exact(triangle); - } - - std::cerr << cdt_3_format("Test tetrahedron (#{}):\n {}\n {}\n {}\n {}\n", - cell.time_stamp(), - IO::oformat(cell.vertex(0), with_point_and_info), - IO::oformat(cell.vertex(1), with_point_and_info), - IO::oformat(cell.vertex(2), with_point_and_info), - IO::oformat(cell.vertex(3), with_point_and_info)); - if(!std::any_of(fh_region.begin(), fh_region.end(), [&](const auto fh) { - auto v0 = fh->vertex(0)->info().vertex_handle_3d; - auto v1 = fh->vertex(1)->info().vertex_handle_3d; - auto v2 = fh->vertex(2)->info().vertex_handle_3d; - auto triangle = typename Geom_traits::Triangle_3{tr().point(v0), tr().point(v1), tr().point(v2)}; - bool b = does_tetrahedron_intersect_triangle_interior(tetrahedron, triangle, tr().geom_traits()); - if(b) { - std::cerr << " intersects the region\n"; - } - return b; - })) - { - std::cerr << cdt_3_format( - "ERROR: The following tetrahedron (#{}) does not intersect the region:\n {}\n {}\n {}\n {}\n", - cell.time_stamp(), - IO::oformat(cell.vertex(0), with_point_and_info), IO::oformat(cell.vertex(1), with_point_and_info), - IO::oformat(cell.vertex(2), with_point_and_info), IO::oformat(cell.vertex(3), with_point_and_info)); - } - } - } -#endif // CGAL_CDT_3_CAN_USE_CXX20_FORMAT - - auto test_edge = [&](Cell_handle cell, Vertex_handle v0, int index_v0, Vertex_handle v1, int index_v1, - [[maybe_unused]] int expected) { - auto value_returned = [this](bool b) { - CGAL_USE(this); -#if CGAL_CDT_3_CAN_USE_CXX20_FORMAT - if(this->debug_regions()) { - std::cerr << cdt_3_format(" return {}\n", b); - } -#endif // CGAL_CDT_3_CAN_USE_CXX20_FORMAT - return b; - }; -#if CGAL_CDT_3_CAN_USE_CXX20_FORMAT - if(this->debug_regions()) { - std::cerr << cdt_3_format(" test_edge {} {} ", IO::oformat(v0, with_point_and_info), - IO::oformat(v1, with_point_and_info)); - } -#endif // CGAL_CDT_3_CAN_USE_CXX20_FORMAT - auto [cached_value_it, not_visited] = new_edge(v0, v1, false); - if(!not_visited) return value_returned(cached_value_it->second); - int v0v1_intersects_region = (v0->ccdt_3_data().is_marked(Vertex_marker::REGION_INSIDE) || - v1->ccdt_3_data().is_marked(Vertex_marker::REGION_INSIDE)) - ? expected - : does_edge_intersect_region(cell, index_v0, index_v1, cdt_2, fh_region); - if(v0v1_intersects_region != 0) { - if(this->use_older_cavity_algorithm()) { - if(v0v1_intersects_region != expected) { - throw PLC_error{"PLC error: v0v1_intersects_region != expected" , - __FILE__, __LINE__, face_index, region_index}; - } - } - // report the edge with first vertex above the region - if(v0v1_intersects_region < 0) { - std::swap(index_v0, index_v1); - } - intersecting_edges_.emplace_back(cell, index_v0, index_v1); - cached_value_it->second = true; - return value_returned(true); - } else { - non_intersecting_edges_set.insert(make_sorted_pair(v0, v1)); - cached_value_it->second = false; - return value_returned(false); - } - }; - - if(this->use_older_cavity_algorithm()) { - CGAL_assertion(0 == region_border_vertices.count(v_above)); - CGAL_assertion(0 == region_border_vertices.count(v_below)); - if(new_vertex(v_above)) { - vertices_of_upper_cavity.push_back(v_above); - } - if(new_vertex(v_below)) { - vertices_of_lower_cavity.push_back(v_below); - } - } - auto facet_circ = this->incident_facets(intersecting_edge); - const auto facet_circ_end = facet_circ; - do { // loop facets around [v_above, v_below] - CGAL_assertion(false == this->is_infinite(*facet_circ)); - const auto cell = facet_circ->first; - const auto facet_index = facet_circ->second; - CGAL_assertion_msg(!cell->ccdt_3_data().is_facet_constrained(facet_index), - std::invoke([&]() { - this->dump_triangulation_to_off(); - return std::string("intersecting polygons!"); - }).c_str()); - if(new_cell(cell)) { - intersecting_cells.insert(cell); - } - const auto index_v_above = cell->index(v_above); - const auto index_v_below = cell->index(v_below); - const auto index_vc = 6 - index_v_above - index_v_below - facet_index; - const auto vc = cell->vertex(index_vc); - if(region_border_vertices.count(vc) > 0) continue; // intersecting edges cannot touch the border - - if(!test_edge(cell, v_above, index_v_above, vc, index_vc, 1) && - !test_edge(cell, v_below, index_v_below, vc, index_vc, -1) && - this->use_older_cavity_algorithm()) - { - dump_triangulation(); - dump_region(face_index, region_index, cdt_2); - { - std::ofstream out(std::string("dump_two_edges_") + std::to_string(face_index) + ".polylines.txt"); - out.precision(17); - write_segment(out, Edge{cell, index_v_above, index_vc}); - write_segment(out, Edge{cell, index_v_below, index_vc}); - } - throw PLC_error{"PLC error: !test_edge(v_above..) && !test_edge(v_below..)" , - __FILE__, __LINE__, face_index, region_index}; - } - } while(++facet_circ != facet_circ_end); - if(!this->use_older_cavity_algorithm() && i + 1 == intersecting_edges.size()) { - for(auto ch: intersecting_cells) { - if(this->debug_regions()) { - std::cerr << "tetrahedron #" << ch->time_stamp() << " intersects the region\n"; - } - for(int i = 0; i < 4; ++i) { - for(int j = i + 1; j < 4; ++j) { - test_edge(ch, ch->vertex(i), i, ch->vertex(j), j, 1); - } - } - for(int i = 0; i < 4; ++i) { - auto n_ch = ch->neighbor(i); - if(tr().is_infinite(n_ch)) - continue; - if(new_cell(n_ch)) { - auto tetrahedron = - typename Geom_traits::Tetrahedron_3{tr().point(n_ch->vertex(0)), tr().point(n_ch->vertex(1)), - tr().point(n_ch->vertex(2)), tr().point(n_ch->vertex(3))}; - auto tet_bbox = tetrahedron.bbox(); - if(std::any_of(fh_region.begin(), fh_region.end(), [&](auto fh) { - const auto v0 = fh->vertex(0)->info().vertex_handle_3d; - const auto v1 = fh->vertex(1)->info().vertex_handle_3d; - const auto v2 = fh->vertex(2)->info().vertex_handle_3d; - const auto triangle = - typename Geom_traits::Triangle_3{tr().point(v0), tr().point(v1), tr().point(v2)}; - const auto tri_bbox = triangle.bbox(); - if(CGAL::do_overlap(tet_bbox, tri_bbox)) { - return does_tetrahedron_intersect_triangle_interior(tetrahedron, triangle, tr().geom_traits()); - } else { - return false; - } - })) - { - intersecting_cells.insert(n_ch); - if(this->debug_regions()) { - std::cerr << "tetrahedron #" << n_ch->time_stamp() << " intersects the region\n"; - } - } else if(this->debug_regions()) { - std::cerr << "NO, tetrahedron #" << n_ch->time_stamp() << " does not intersect the region\n"; - } - for(int i = 0; i < 4; ++i) { - for(int j = i + 1; j < 4; ++j) { - test_edge(n_ch, n_ch->vertex(i), i, n_ch->vertex(j), j, 1); - } - } - } - } - } - } // last intersecting edge, and new algorithm - } // end loop on intersecting_edges + detect_edges_and_cells_intersecting_region(face_index, region_index, cdt_2, fh_region, region_border_vertices, + first_intersecting_edge, intersecting_edges, intersecting_cells, + non_intersecting_edges_set); if(this->use_older_cavity_algorithm()) { - for(auto intersecting_edge: intersecting_edges) { - const auto [v_above, v_below] = tr().vertices(intersecting_edge); - - auto cell_circ = this->incident_cells(intersecting_edge), end = cell_circ; - CGAL_assume(cell_circ != nullptr); - do { - const Cell_handle cell = cell_circ; - const auto index_v_above = cell->index(v_above); - const auto index_v_below = cell->index(v_below); - const auto cell_above = cell->neighbor(index_v_below); - const auto cell_below = cell->neighbor(index_v_above); - if(0 == intersecting_cells.count(cell_above)) { - facets_of_upper_cavity.emplace_back(cell_above, cell_above->index(cell)); - } - if(0 == intersecting_cells.count(cell_below)) { - facets_of_lower_cavity.emplace_back(cell_below, cell_below->index(cell)); - } - } while(++cell_circ != end); - } + process_older_cavity_algorithm(intersecting_edges, cr_intersecting_cells, vertices_of_upper_cavity, + vertices_of_lower_cavity, facets_of_upper_cavity, facets_of_lower_cavity); } // older algorithm - std::set facets_of_border; - Union_find vertices_of_cavity_union_find; - if(!this->use_older_cavity_algorithm()) { - for(auto c: intersecting_cells) { - for(int i = 0; i < 4; ++i) { - auto n = c->neighbor(i); - if(intersecting_cells.count(n) == 0) { - facets_of_border.emplace(n, n->index(c)); + // those facets are viewed from the outside of the cavity + const std::set facets_of_border = std::invoke([&] { + std::set facets_of_border; + if(this->use_newer_cavity_algorithm()) { + for(auto c : cr_intersecting_cells) { + for(int i = 0; i < 4; ++i) { + auto n = c->neighbor(i); + if(cr_intersecting_cells.count(n) == 0) { + facets_of_border.emplace(n, n->index(c)); + } } } } - Unique_hash_map::handle> vertices_of_cavity_handles; - for(auto c: intersecting_cells) { + return facets_of_border; + }); + if(this->use_newer_cavity_algorithm()) { + + // create a union-find of the vertices of the cavity (but those on the region border) + Union_find vertices_of_cavity_union_find; + using Union_find_handle = typename Union_find::handle; + Unique_hash_map vertices_of_cavity_handles; + for(auto c: cr_intersecting_cells) { for(auto v : tr().vertices(c)) { - if(!v->ccdt_3_data().is_marked()) { - v->ccdt_3_data().set_mark(Vertex_marker::CAVITY); + if(!is_marked(v)) { + set_mark(v, Vertex_marker::CAVITY); vertices_of_cavity_handles[v] = vertices_of_cavity_union_find.make_set(v); } } } + + // use edges of the border facets to unify sets for(auto facet: facets_of_border) { auto vertices = tr().vertices(facet); for(int i = 0; i < 3; ++i) { auto v1 = vertices[i]; auto v2 = vertices[(i + 1) % 3]; - if(v1->ccdt_3_data().is_marked(Vertex_marker::CAVITY) && v2->ccdt_3_data().is_marked(Vertex_marker::CAVITY)) { + if(is_marked(v1, Vertex_marker::CAVITY) && is_marked(v2, Vertex_marker::CAVITY)) { vertices_of_cavity_union_find.unify_sets(vertices_of_cavity_handles[v1], vertices_of_cavity_handles[v2]); } } } + + // use non-intersecting edges to unify sets, until we have at most 2 sets if(vertices_of_cavity_union_find.number_of_sets() > 2) { - for(auto c : intersecting_cells) { + for(auto c : cr_intersecting_cells) { for(int i = 0; i < 4; ++i) { for(int j = i + 1; j < 4; ++j) { const auto v1 = c->vertex(i); const auto v2 = c->vertex(j); - if(v1->ccdt_3_data().is_marked(Vertex_marker::CAVITY) && - v2->ccdt_3_data().is_marked(Vertex_marker::CAVITY) && + if(is_marked(v1, Vertex_marker::CAVITY) && is_marked(v2, Vertex_marker::CAVITY) && non_intersecting_edges_set.count(make_sorted_pair(v1, v2)) > 0) { vertices_of_cavity_union_find.unify_sets(vertices_of_cavity_handles[v1], @@ -2395,62 +2106,160 @@ private: break; } } - Vertex_handle vertex_above{}; - Edges_container all_border_edges{border_edges.begin(), border_edges.end()}; - std::for_each(border_edges.begin(), border_edges.end(), [&](auto edge) { - all_border_edges.emplace_back(edge.first, edge.third, edge.second); - }); - for(const auto& border_edge: all_border_edges) { - const auto [border_edge_va, border_edge_vb] = tr().vertices(border_edge); - auto circ = tr().incident_cells(border_edge); - CGAL_assertion(circ != nullptr); - const auto end = circ; - do { - const auto index_va = circ->index(border_edge_va); - const auto index_vb = circ->index(border_edge_vb); - const auto face_index = tr().next_around_edge(index_va, index_vb); - if(facets_of_border.count(Facet{circ, face_index}) > 0) { - const auto other_vertex_index = 6 - index_va - index_vb - face_index; - const auto other_vertex = circ->vertex(other_vertex_index); - if(other_vertex->ccdt_3_data().is_marked(Vertex_marker::CAVITY)) { - vertex_above = circ->vertex(other_vertex_index); - break; + + // find a vertex and a border-facet above the region + const auto [vertex_above, border_facet_above] = std::invoke([&] { + Edges_container all_border_edges{border_edges.begin(), border_edges.end()}; + std::for_each(border_edges.begin(), border_edges.end(), [&](auto edge) { + all_border_edges.emplace_back(edge.first, edge.third, edge.second); + }); + for(const auto& border_edge: all_border_edges) { + const auto [border_edge_va, border_edge_vb] = tr().vertices(border_edge); + auto circ = tr().incident_cells(border_edge); + CGAL_assertion(circ != nullptr); + const auto end = circ; + do { + const auto index_va = circ->index(border_edge_va); + const auto index_vb = circ->index(border_edge_vb); + const auto face_index = tr().next_around_edge(index_va, index_vb); + Facet facet{circ, face_index}; + if(facets_of_border.count(facet) > 0) { + const auto other_vertex_index = 6 - index_va - index_vb - face_index; + const auto other_vertex = circ->vertex(other_vertex_index); + if(is_marked(other_vertex, Vertex_marker::CAVITY)) { + return std::make_pair(circ->vertex(other_vertex_index), facet); + } } - } - } while(++circ != end); - if(vertex_above != Vertex_handle{}) break; - } + } while(++circ != end); + } + return std::make_pair(Vertex_handle{}, Facet{}); + }); CGAL_assume(vertex_above != Vertex_handle{}); - const auto vertex_above_handle = vertices_of_cavity_handles[vertex_above]; - auto it = vertices_of_cavity_union_find.begin(); - while(it != vertices_of_cavity_union_find.end() && - vertices_of_cavity_union_find.same_set(it, vertex_above_handle)) - { - ++it; + // if there are still more than 2 sets, we need to propagate the information + // using a DFS on the border facets + if(vertices_of_cavity_union_find.number_of_sets() > 2) { + const auto border_edges_set = std::invoke([&] { + using Ordered_pair = std::pair; + using Hash = boost::hash; + CGAL::unordered_flat_set border_edges_set; + for(auto edge : border_edges) { + auto [va, vb] = tr().vertices(edge); + border_edges_set.insert(make_sorted_pair(va, vb)); + } + return border_edges_set; + }); + CGAL::unordered_flat_set> remaining_facets_of_border(facets_of_border.begin(), + facets_of_border.end()); + + std::stack stack; + std::optional reference_handle_of_the_connected_component; + stack.push(border_facet_above); + remaining_facets_of_border.erase(border_facet_above); + while(!stack.empty()) { + const auto facet = stack.top(); + stack.pop(); + const auto [cell, facet_index] = facet; // border facet seen from the outside of the cavity + CGAL_assertion(cr_intersecting_cells.count(cell) == 0); //REMOVE + CGAL_assertion(cr_intersecting_cells.count(cell->neighbor(facet_index)) > 0); //REMOVE + const auto vertices = tr().vertices(facet); + for(auto v : vertices) { + if(is_marked(v, Vertex_marker::CAVITY)) { + if(!reference_handle_of_the_connected_component) { + reference_handle_of_the_connected_component = vertices_of_cavity_handles[v]; + } else { + vertices_of_cavity_union_find.unify_sets(*reference_handle_of_the_connected_component, + vertices_of_cavity_handles[v]); + } + } + } + for(int i = 0; i < 3; ++i) { + const auto va = vertices[i]; + const auto vb = vertices[tr().ccw(i)]; + + if((is_marked(va, Vertex_marker::CAVITY) || is_marked(vb, Vertex_marker::CAVITY)) && + border_edges_set.count(make_sorted_pair(va, vb)) == 0) + { + // loop around the edge [va, vb] to get another facet on the border of the cavity + auto previous_cell = cell; + auto other_cell = cell->neighbor(facet_index); + do { + CGAL_assertion(cr_intersecting_cells.count(other_cell) >= 0); // REMOVE + auto index_va = other_cell->index(va); + auto index_vb = other_cell->index(vb); + auto other_facet_index = tr().next_around_edge(index_vb, index_va); + previous_cell = other_cell; + other_cell = previous_cell->neighbor(other_facet_index); + + } while(cr_intersecting_cells.count(other_cell) > 0); + const Facet neighbor_facet{other_cell, other_cell->index(previous_cell)}; + CGAL_assertion(facets_of_border.count(neighbor_facet) > 0); + if(remaining_facets_of_border.erase(neighbor_facet) > 0) { + stack.push(neighbor_facet); + } + } + } + + // if the stack is empty but there are still facets to process, we start again to recover + // another connected component of the cavity border + if(stack.empty() && !remaining_facets_of_border.empty()) { + stack.push(*remaining_facets_of_border.begin()); + remaining_facets_of_border.erase(remaining_facets_of_border.begin()); + reference_handle_of_the_connected_component.reset(); + } + } } - CGAL_assertion((it == vertices_of_cavity_union_find.end()) == + + CGAL_assertion_msg(vertices_of_cavity_union_find.number_of_sets() <= 2, + std::invoke([&] { + std::stringstream ss; + ss << "Error: cavity has " << vertices_of_cavity_union_find.number_of_sets() + << " sub-cavities (should be <=2)\n"; + return ss.str(); + }).c_str()); + const auto vertex_above_handle = vertices_of_cavity_handles[vertex_above]; + + // find a vertex below the region (if any) + const auto vertex_below_handle = std::invoke([&] { + auto [b, e] = make_prevent_deref_range(vertices_of_cavity_union_find); + auto it = std::find_if_not( + b, e, [&](auto handle) { return vertices_of_cavity_union_find.same_set(handle, vertex_above_handle); }); + if(it != e) { + return *it; + } else { + return vertices_of_cavity_union_find.end(); + } + }); + CGAL_assertion(vertex_below_handle == vertices_of_cavity_union_find.end() || + !vertices_of_cavity_union_find.same_set(vertex_below_handle, vertex_above_handle)); + CGAL_assertion((vertex_below_handle == vertices_of_cavity_union_find.end()) == (vertices_of_cavity_union_find.number_of_sets() == 1)); - const auto vertex_below_handle = it; - for(auto handle = vertices_of_cavity_union_find.begin(), end = vertices_of_cavity_union_find.end(); - handle != end; ++handle) + + // use the union-find sets to mark vertices as above or below the region + for(auto handle : make_prevent_deref_range(vertices_of_cavity_union_find)) { auto v = *handle; - v->ccdt_3_data().clear_mark(Vertex_marker::CAVITY); + clear_mark(v, Vertex_marker::CAVITY); if(vertices_of_cavity_union_find.same_set(handle, vertex_above_handle)) { vertices_of_upper_cavity.push_back(v); - v->ccdt_3_data().set_mark(Vertex_marker::CAVITY_ABOVE); - } else if(vertices_of_cavity_union_find.same_set(handle, vertex_below_handle)) { + set_mark(v, Vertex_marker::CAVITY_ABOVE); + } else if(vertex_below_handle != vertices_of_cavity_union_find.end() && + vertices_of_cavity_union_find.same_set(handle, vertex_below_handle)) + { vertices_of_lower_cavity.push_back(v); - v->ccdt_3_data().set_mark(Vertex_marker::CAVITY_BELOW); + set_mark(v, Vertex_marker::CAVITY_BELOW); } else { CGAL_error(); } } - while(std::any_of(intersecting_cells.begin(), intersecting_cells.end(), [&](Cell_handle c) { + + // if any vertex is still unmarked, it means that the union-find did not + // connect all the vertices of the cavity. Then propagate the information + // using the intersecting cells. + while(std::any_of(cr_intersecting_cells.begin(), cr_intersecting_cells.end(), [&](Cell_handle c) { const auto vs = tr().vertices(c); return std::any_of(vs.begin(), vs.end(), [&](auto v) { - if(!v->ccdt_3_data().is_marked()) { + if(!is_marked(v)) { std::cerr << "INFO: Vertex " << IO::oformat(v, with_point_and_info) << " is not marked\n"; return true; } @@ -2458,88 +2267,56 @@ private: }); })) { - std::for_each(intersecting_cells.begin(), intersecting_cells.end(), [&](Cell_handle c) { + std::for_each(cr_intersecting_cells.begin(), cr_intersecting_cells.end(), [&](Cell_handle c) { for(int i = 0; i < 4; ++i) { for(int j = i + 1; j < 4; ++j) { auto v1 = c->vertex(i); auto v2 = c->vertex(j); - if(v1->ccdt_3_data().is_marked() != v2->ccdt_3_data().is_marked()) { - if(v2->ccdt_3_data().is_marked()) { + if(is_marked(v1) != is_marked(v2)) { + if(is_marked(v2)) { std::swap(v1, v2); } // here v1 is marked and v2 is not - if(v1->ccdt_3_data().is_marked(Vertex_marker::CAVITY_ABOVE)) { + if(is_marked(v1, Vertex_marker::CAVITY_ABOVE)) { vertices_of_upper_cavity_.push_back(v2); - v2->ccdt_3_data().set_mark(Vertex_marker::CAVITY_ABOVE); - } else if(v1->ccdt_3_data().is_marked(Vertex_marker::CAVITY_BELOW)) { + set_mark(v2, Vertex_marker::CAVITY_ABOVE); + } else if(is_marked(v1, Vertex_marker::CAVITY_BELOW)) { vertices_of_lower_cavity_.push_back(v2); - v2->ccdt_3_data().set_mark(Vertex_marker::CAVITY_BELOW); + set_mark(v2, Vertex_marker::CAVITY_BELOW); } } } } }); } + + // classify the facets of the border of the cavity + for(auto facet: facets_of_border) { + if(this->debug_regions()) { + debug_output_facet_vertices({facet}); + } + for(auto v: tr().vertices(facet)) { + if(is_marked(v, Vertex_marker::CAVITY_ABOVE)) { + facets_of_upper_cavity.push_back(facet); + break; + } + if(is_marked(v, Vertex_marker::CAVITY_BELOW)) { + facets_of_lower_cavity.push_back(facet); + break; + } + } + } + clear_marks(vertices_of_upper_cavity, Vertex_marker::CAVITY_ABOVE); + clear_marks(vertices_of_lower_cavity, Vertex_marker::CAVITY_BELOW); } // new algorithm - if(this->debug_regions()) { - std::stringstream ss_filename; - ss_filename << "dump_facets_of_cavity_region_" << face_index << "_" << region_index << "_border.off"; - std::ofstream out(ss_filename.str()); - out.precision(17); - write_facets(out, tr(), facets_of_border); - } if(this->debug_regions()) { + debug_dump_cavity_outputs(face_index, region_index, intersecting_edges, facets_of_border, facets_of_upper_cavity, facets_of_lower_cavity); for(auto edge : intersecting_edges) { auto [v1, v2] = tr().vertices(edge); std::cerr << cdt_3_format(" edge: {} {}\n", IO::oformat(v1, with_point_and_info), IO::oformat(v2, with_point_and_info)); } } - if(!this->use_older_cavity_algorithm()) { - for(auto facet: facets_of_border) { - if(this->debug_regions()) { - std::cerr << " facet: "; - const auto facet_vertices = tr().vertices(facet); - for(auto v: facet_vertices) { - std::cerr << IO::oformat(v, with_point_and_info) << " "; - } - // This assertion is wrong, because there might be only one half-cavity and not a full cavity. - // CGAL_assertion(!std::all_of(facet_vertices.begin(), facet_vertices.end(), - // [](auto v) { return v->is_marked(Vertex_marker::REGION_BORDER); })); - std::cerr << "\n"; - } - for(auto v: tr().vertices(facet)) { - if(v->ccdt_3_data().is_marked(Vertex_marker::CAVITY_ABOVE)) { - facets_of_upper_cavity.push_back(facet); - break; - } - if(v->ccdt_3_data().is_marked(Vertex_marker::CAVITY_BELOW)) { - facets_of_lower_cavity.push_back(facet); - break; - } - } - } - for(auto v: vertices_of_upper_cavity) { - v->ccdt_3_data().clear_mark(Vertex_marker::CAVITY_ABOVE); - } - for(auto v: vertices_of_lower_cavity) { - v->ccdt_3_data().clear_mark(Vertex_marker::CAVITY_BELOW); - } - } - if(this->debug_regions()) { - std::stringstream ss_filename; - ss_filename << "dump_facets_of_upper_cavity_region_" << face_index << "_" << region_index << "_border.off"; - std::ofstream out(ss_filename.str()); - out.precision(17); - write_facets(out, tr(), facets_of_upper_cavity); - out.close(); - ss_filename.str(""); - ss_filename << "dump_facets_of_lower_cavity_region_" << face_index << "_" << region_index << "_border.off"; - out.open(ss_filename.str()); - write_facets(out, tr(), facets_of_lower_cavity); - out.close(); - } - return outputs; } @@ -2593,21 +2370,20 @@ private: } return vertices; }); -#if CGAL_CDT_3_CAN_USE_CXX20_FORMAT - if(this->debug_regions()) { + if constexpr (cdt_3_can_use_cxx20_format()) if(this->debug_regions()) { std::cerr << "region_border_vertices.size() = " << region_border_vertices.size() << "\n"; for(auto v : region_border_vertices) { std::cerr << cdt_3_format(" {}\n", IO::oformat(v, with_point)); } + std::ofstream out(cdt_3_format("dump_border_edges_region_{}_{}.polylines.txt", face_index, region_index)); + out.precision(17); + for(auto edge : border_edges) { + write_segment(out, edge); + } } -#endif // CGAL_CDT_3_CAN_USE_CXX20_FORMAT - for(auto v: region_border_vertices) { - v->ccdt_3_data().set_mark(Vertex_marker::REGION_BORDER); - } + set_marks(region_border_vertices, Vertex_marker::REGION_BORDER); const auto found_edge_opt = search_first_intersection(face_index, cdt_2, fh_region, border_edges); - for(auto v: region_border_vertices) { - v->ccdt_3_data().clear_mark(Vertex_marker::REGION_BORDER); - } + clear_marks(region_border_vertices, Vertex_marker::REGION_BORDER); [[maybe_unused]] auto try_flip_region_size_4 = [&] { if(region_border_vertices.size() == 4) { @@ -2669,7 +2445,6 @@ private: } } -#if CGAL_CAN_USE_CXX20_FORMAT if constexpr (cdt_3_can_use_cxx20_format()) if(this->debug_regions()) { std::cerr << cdt_3_format ("NOTE: diagonal: {:.6} {:.6} {} in tr\n", @@ -2710,7 +2485,6 @@ private: } } } -#endif // CGAL_CAN_USE_CXX20_FORMAT } return false; }; @@ -2747,20 +2521,16 @@ private: } CGAL_assertion(found_edge_opt != std::nullopt); - for(auto v : region_border_vertices) { - v->ccdt_3_data().set_mark(Vertex_marker::REGION_BORDER); - } + set_marks(region_border_vertices, Vertex_marker::REGION_BORDER); for(auto v : region_vertices) { - if(v->ccdt_3_data().is_marked(Vertex_marker::REGION_BORDER)) + if(is_marked(v, Vertex_marker::REGION_BORDER)) continue; - v->ccdt_3_data().set_mark(Vertex_marker::REGION_INSIDE); + set_mark(v, Vertex_marker::REGION_INSIDE); } Scope_exit guard{[&] { - for(auto v : region_vertices) { - v->ccdt_3_data().clear_mark(Vertex_marker::REGION_BORDER); - v->ccdt_3_data().clear_mark(Vertex_marker::REGION_INSIDE); - } + clear_marks(region_vertices, Vertex_marker::REGION_BORDER); + clear_marks(region_vertices, Vertex_marker::REGION_INSIDE); }}; const auto [first_intersecting_edge, _] = *found_edge_opt; @@ -2788,8 +2558,7 @@ private: return true; }; -#if CGAL_CDT_3_CAN_USE_CXX20_FORMAT - if(this->debug_regions()) { + if constexpr (cdt_3_can_use_cxx20_format()) if(this->debug_regions()) { std::cerr << cdt_3_format("Cavity has {} cells and {} edges, " "{} vertices in upper cavity and {} in lower, " "{} facets in upper cavity and {} in lower\n", @@ -2814,7 +2583,6 @@ private: // dump_facets_of_cavity(face_index, region_index, "upper", original_facets_of_upper_cavity); } } -#endif // CGAL_CDT_3_CAN_USE_CXX20_FORMAT auto register_internal_constrained_facet = [this](Facet f) { this->register_facet_to_be_constrained(f); }; if(this->debug_copy_triangulation_into_hole()) { @@ -3003,8 +2771,7 @@ private: const auto upper_inner_map = tr().create_triangulation_inner_map( upper_cavity_triangulation, map_upper_cavity_vertices_to_ambient_vertices, false); -#if CGAL_CDT_3_CAN_USE_CXX20_FORMAT - if(this->debug_copy_triangulation_into_hole()) { + if constexpr (cdt_3_can_use_cxx20_format()) if(this->debug_copy_triangulation_into_hole()) { std::cerr << "upper_inner_map:\n"; for(auto [vt, _] : upper_inner_map) { std::cerr << cdt_3_format(" {:.6}, {:.6}, {:.6})\n", @@ -3013,7 +2780,6 @@ private: IO::oformat(vt[2], with_point)); } } -#endif // CGAL_CDT_3_CAN_USE_CXX20_FORMAT if(this->debug_copy_triangulation_into_hole()) { std::cerr << "# glu the lower triangulation of the cavity\n"; } @@ -3043,7 +2809,7 @@ private: const auto lower_inner_map = tr().create_triangulation_inner_map( lower_cavity_triangulation, map_lower_cavity_vertices_to_ambient_vertices, false); #if CGAL_CDT_3_CAN_USE_CXX20_FORMAT - if(this->debug_copy_triangulation_into_hole()) { + if(this->debug_copy_triangulation_into_hole()) { std::cerr << "outer_map:\n"; for(auto [vt, _] : outer_map) { std::cerr << cdt_3_format(" {:.6}, {:.6}, {:.6})\n", @@ -3217,14 +2983,12 @@ private: tr().is_infinite(v) ? cavity_triangulation.infinite_vertex() : cavity_triangulation.insert(this->point(v)); map_ambient_vertices_to_cavity_vertices[v] = cavity_v; map_cavity_vertices_to_ambient_vertices[cavity_v] = v; -#if CGAL_CDT_3_CAN_USE_CXX20_FORMAT - if(this->debug_regions()) { + if constexpr (cdt_3_can_use_cxx20_format()) if(this->debug_regions()) { std::cerr << cdt_3_format("inserted {}cavity vertex {:.6} -> {:.6}\n", extra, IO::oformat(cavity_v, with_point_and_info), IO::oformat(v, with_point_and_info)); } -#endif // CGAL_CDT_3_CAN_USE_CXX20_FORMAT return cavity_v; }; @@ -3464,25 +3228,21 @@ private: bool restore_face(CDT_3_signed_index face_index) { CDT_2& non_const_cdt_2 = face_cdt_2[face_index]; const CDT_2& cdt_2 = non_const_cdt_2; -#if CGAL_CDT_3_CAN_USE_CXX20_FORMAT - if(this->debug_copy_triangulation_into_hole()) { + if constexpr (cdt_3_can_use_cxx20_format()) if(this->debug_copy_triangulation_into_hole()) { std::cerr << cdt_3_format("restore_face({}): CDT_2 has {} vertices\n", face_index, cdt_2.number_of_vertices()); } -#endif // CGAL_CDT_3_CAN_USE_CXX20_FORMAT for(const auto& edge : cdt_2.finite_edges()) { const auto fh = edge.first; const auto i = edge.second; const auto va_3d = fh->vertex(cdt_2.cw(i))->info().vertex_handle_3d; const auto vb_3d = fh->vertex(cdt_2.ccw(i))->info().vertex_handle_3d; const bool is_3d = this->is_edge(va_3d, vb_3d); -#if CGAL_CDT_3_CAN_USE_CXX20_FORMAT - if(this->debug_copy_triangulation_into_hole()) { + if constexpr (cdt_3_can_use_cxx20_format()) if(this->debug_copy_triangulation_into_hole()) { std::cerr << cdt_3_format("Edge is 3D: {:6} ({} , {})\n", is_3d, IO::oformat(va_3d, with_point_and_info), IO::oformat(vb_3d, with_point_and_info)); } -#endif // CGAL_CDT_3_CAN_USE_CXX20_FORMAT CGAL_assertion(is_3d || !cdt_2.is_constrained(edge)); fh->info().is_edge_also_in_3d_triangulation[unsigned(i)] = is_3d; const auto reverse_edge = cdt_2.mirror_edge(edge); @@ -3794,6 +3554,425 @@ public: write_facets(out, tr, tr.finite_facets()); } + void process_older_cavity_algorithm(const std::vector& intersecting_edges, + const std::set& intersecting_cells, + std::vector& vertices_of_upper_cavity, + std::vector& vertices_of_lower_cavity, + std::vector& facets_of_upper_cavity, + std::vector& facets_of_lower_cavity) + { + auto new_vertex = make__new_element_functor(); + + for(auto intersecting_edge: intersecting_edges) { + const auto [v_above, v_below] = tr().vertices(intersecting_edge); + + if(new_vertex(v_above)) { + vertices_of_upper_cavity.push_back(v_above); + } + if(new_vertex(v_below)) { + vertices_of_lower_cavity.push_back(v_below); + } + + auto cell_circ = this->incident_cells(intersecting_edge), end = cell_circ; + CGAL_assume(cell_circ != nullptr); + do { + const Cell_handle cell = cell_circ; + const auto index_v_above = cell->index(v_above); + const auto index_v_below = cell->index(v_below); + const auto cell_above = cell->neighbor(index_v_below); + const auto cell_below = cell->neighbor(index_v_above); + if(0 == intersecting_cells.count(cell_above)) { + facets_of_upper_cavity.emplace_back(cell_above, cell_above->index(cell)); + } + if(0 == intersecting_cells.count(cell_below)) { + facets_of_lower_cavity.emplace_back(cell_below, cell_below->index(cell)); + } + } while(++cell_circ != end); + } + } + + template + static auto make__new_element_functor() { + return [visited_set = std::set()](auto... e) mutable { + const auto [_, not_already_visited] = visited_set.emplace(e...); + return not_already_visited; + }; + }; + + template + void detect_edges_and_cells_intersecting_region( + CDT_3_signed_index face_index, + int region_index, + const CDT_2& cdt_2, + const Fh_region& fh_region, + const Vertices_container& region_border_vertices, + Edge first_intersecting_edge, + std::vector& intersecting_edges, + std::set& intersecting_cells, + std::set>& non_intersecting_edges_set) + { + // Create visitor functors + auto new_cell = make__new_element_functor(); + std::map, bool> visited_edges; + auto new_edge = [&](Vertex_handle v0, Vertex_handle v1, bool does_intersect) { + CGAL_assertion(v0 != Vertex_handle{}); + return visited_edges.emplace(CGAL::make_sorted_pair(v0, v1), does_intersect); + }; + + // Alias for C++20 extension warning workaround + auto& intersecting_edges_ = intersecting_edges; + + intersecting_edges.push_back(first_intersecting_edge); + const auto [v0, v1] = tr().vertices(first_intersecting_edge); + (void)new_edge(v0, v1, true); + + for(std::size_t i = 0; i < intersecting_edges.size(); ++i) { + const auto intersecting_edge = intersecting_edges[i]; + const auto [v_above, v_below] = tr().vertices(intersecting_edge); + if constexpr (cdt_3_can_use_cxx20_format()) if(this->debug_regions()) { + debug_dump_edge_region_intersection(face_index, region_index, fh_region, i, v_above, v_below, intersecting_edge); + } + + auto test_edge = [&](Cell_handle cell, Vertex_handle v0, int index_v0, Vertex_handle v1, int index_v1, + int expected) { + auto value_returned = [this](bool b) { + CGAL_USE(this); + if constexpr (cdt_3_can_use_cxx20_format()) if(this->debug_regions()) { + std::cerr << cdt_3_format(" return {}\n", b); + } + return b; + }; + if constexpr (cdt_3_can_use_cxx20_format()) if(this->debug_regions()) { + std::cerr << cdt_3_format(" test_edge {} {} ", IO::oformat(v0, with_point_and_info), + IO::oformat(v1, with_point_and_info)); + } + auto [cached_value_it, not_visited] = new_edge(v0, v1, false); + if(!not_visited) return value_returned(cached_value_it->second); + int v0v1_intersects_region = (is_marked(v0, Vertex_marker::REGION_INSIDE) || + is_marked(v1, Vertex_marker::REGION_INSIDE)) + ? expected + : does_edge_intersect_region(cell, index_v0, index_v1, cdt_2, fh_region); + if(v0v1_intersects_region != 0) { + if(this->use_older_cavity_algorithm()) { + if(v0v1_intersects_region != expected) { + throw PLC_error{"PLC error: v0v1_intersects_region != expected" , + __FILE__, __LINE__, face_index, region_index}; + } + } + // report the edge with first vertex above the region + if(v0v1_intersects_region < 0) { + std::swap(index_v0, index_v1); + } + intersecting_edges_.emplace_back(cell, index_v0, index_v1); + cached_value_it->second = true; + return value_returned(true); + } else { + non_intersecting_edges_set.insert(make_sorted_pair(v0, v1)); + cached_value_it->second = false; + return value_returned(false); + } + }; + + auto facet_circ = this->incident_facets(intersecting_edge); + const auto facet_circ_end = facet_circ; + do { // loop facets around [v_above, v_below] + CGAL_assertion(false == this->is_infinite(*facet_circ)); + const auto cell = facet_circ->first; + const auto facet_index = facet_circ->second; + CGAL_assertion_msg(!cell->ccdt_3_data().is_facet_constrained(facet_index), + std::invoke([&]() { + this->dump_triangulation_to_off(); + return std::string("intersecting polygons!"); + }).c_str()); + if(new_cell(cell)) { + intersecting_cells.insert(cell); + } + const auto index_v_above = cell->index(v_above); + const auto index_v_below = cell->index(v_below); + const auto index_vc = 6 - index_v_above - index_v_below - facet_index; + const auto vc = cell->vertex(index_vc); + if(region_border_vertices.count(vc) > 0) continue; // intersecting edges cannot touch the border + + if(!test_edge(cell, v_above, index_v_above, vc, index_vc, 1) && + !test_edge(cell, v_below, index_v_below, vc, index_vc, -1) && + this->use_older_cavity_algorithm()) + { + if(this->debug_regions()) { + dump_triangulation(); + dump_region(face_index, region_index, cdt_2); + std::ofstream out(std::string("dump_two_edges_") + std::to_string(face_index) + ".polylines.txt"); + out.precision(17); + write_segment(out, Edge{cell, index_v_above, index_vc}); + write_segment(out, Edge{cell, index_v_below, index_vc}); + } + throw PLC_error{"PLC error: !test_edge(v_above..) && !test_edge(v_below..)" , + __FILE__, __LINE__, face_index, region_index}; + } + } while(++facet_circ != facet_circ_end); + if(this->use_newer_cavity_algorithm() && i + 1 == intersecting_edges.size()) { + for(auto ch: intersecting_cells) { + if(this->debug_regions()) { + std::cerr << "tetrahedron #" << ch->time_stamp() << " intersects the region\n"; + } + for(int i = 0; i < 4; ++i) { + for(int j = i + 1; j < 4; ++j) { + test_edge(ch, ch->vertex(i), i, ch->vertex(j), j, 1); + } + } + for(int i = 0; i < 4; ++i) { + auto n_ch = ch->neighbor(i); + if(tr().is_infinite(n_ch)) + continue; + if(new_cell(n_ch)) { + const auto tetrahedron = tr().tetrahedron(n_ch); + const auto tet_bbox = tetrahedron.bbox(); + if(std::any_of(fh_region.begin(), fh_region.end(), [&](auto fh) { + const auto triangle = cdt_2.triangle(fh); + const auto tri_bbox = triangle.bbox(); + return CGAL::do_overlap(tet_bbox, tri_bbox) && + does_tetrahedron_intersect_triangle_interior(tetrahedron, triangle, tr().geom_traits()); + })) + { + intersecting_cells.insert(n_ch); + if(this->debug_regions()) { + std::cerr << "tetrahedron #" << n_ch->time_stamp() << " intersects the region\n"; + } + } else if(this->debug_regions()) { + std::cerr << "NO, tetrahedron #" << n_ch->time_stamp() << " does not intersect the region\n"; + } + for(int i = 0; i < 4; ++i) { + for(int j = i + 1; j < 4; ++j) { + test_edge(n_ch, n_ch->vertex(i), i, n_ch->vertex(j), j, 1); + } + } + } + } + } + } // last intersecting edge, and new algorithm + } // end loop on intersecting_edges + } + + void debug_dump_cavity_outputs(CDT_3_signed_index face_index, + int region_index, + const std::vector& intersecting_edges, + const std::set& facets_of_border, + const std::vector& facets_of_upper_cavity, + const std::vector& facets_of_lower_cavity) + { + // Dump facets of cavity border + std::stringstream ss_filename; + ss_filename << "dump_facets_of_cavity_region_" << face_index << "_" << region_index << "_border.off"; + std::ofstream out(ss_filename.str()); + out.precision(17); + write_facets(out, tr(), facets_of_border); + out.close(); + + // Dump intersecting edges information + for(auto edge : intersecting_edges) { + auto [v1, v2] = tr().vertices(edge); + std::cerr << cdt_3_format(" edge: {} {}\n", IO::oformat(v1, with_point_and_info), + IO::oformat(v2, with_point_and_info)); + } + + // Dump upper and lower cavity facets + ss_filename.str(""); + ss_filename << "dump_facets_of_upper_cavity_region_" << face_index << "_" << region_index << "_border.off"; + out.open(ss_filename.str()); + out.precision(17); + write_facets(out, tr(), facets_of_upper_cavity); + out.close(); + ss_filename.str(""); + ss_filename << "dump_facets_of_lower_cavity_region_" << face_index << "_" << region_index << "_border.off"; + out.open(ss_filename.str()); + write_facets(out, tr(), facets_of_lower_cavity); + out.close(); + } + + void debug_output_facet_vertices(const std::set& facets_of_border) + { + for(auto facet: facets_of_border) { + std::cerr << " facet: "; + const auto facet_vertices = tr().vertices(facet); + for(auto v: facet_vertices) { + std::cerr << IO::oformat(v, with_point_and_info) << " "; + } + // This assertion is wrong, because there might be only one half-cavity and not a full cavity. + // CGAL_assertion(!std::all_of(facet_vertices.begin(), facet_vertices.end(), + // [](auto v) { return v->is_marked(Vertex_marker::REGION_BORDER); })); + std::cerr << "\n"; + } + } + + template + void debug_dump_edge_region_intersection(CDT_3_signed_index face_index, + int region_index, + const Fh_region& fh_region, + std::size_t edge_index, + Vertex_handle v_above, + Vertex_handle v_below, + Edge intersecting_edge) + { + using EK = CGAL::Exact_predicates_exact_constructions_kernel; + const auto to_exact = CGAL::Cartesian_converter(); + + std::cerr << cdt_3_format("restore_subface_region face index: {}, region #{}, intersecting edge #{}: ({} {})\n", + face_index, region_index, edge_index, + IO::oformat(v_above, with_point_and_info), + IO::oformat(v_below, with_point_and_info)); + dump_region(face_index, region_index, this->face_cdt_2[face_index]); + + const auto p_above = this->point(v_above); + const auto p_below = this->point(v_below); + const auto edge_segment = typename Geom_traits::Segment_3{p_above, p_below}; + const auto exact_edge_segment = to_exact(edge_segment); + + std::ofstream intersect_out("dump_edge_region_intersection.xyz"); + intersect_out.precision(17); + for(auto fh: fh_region) { + auto v0 = fh->vertex(0)->info().vertex_handle_3d; + auto v1 = fh->vertex(1)->info().vertex_handle_3d; + auto v2 = fh->vertex(2)->info().vertex_handle_3d; + auto triangle = typename Geom_traits::Triangle_3{tr().point(v0), tr().point(v1), tr().point(v2)}; + auto exact_triangle = to_exact(triangle); + if(auto edge_intersection_opt = CGAL::intersection(exact_edge_segment, exact_triangle)) { + const auto& edge_intersection = *edge_intersection_opt; + if(const auto* p = std::get_if(&edge_intersection)) { + exact(*p); + intersect_out << *p << '\n'; + } + } + } + intersect_out.close(); + + auto cells_around_intersecting_edge = Container_from_circulator{this->incident_cells(intersecting_edge)}; + for(const auto& cell: cells_around_intersecting_edge) { + CGAL_assertion(!cell.has_vertex(tr().infinite_vertex())); + auto tetrahedron = + typename Geom_traits::Tetrahedron_3{tr().point(cell.vertex(0)), tr().point(cell.vertex(1)), + tr().point(cell.vertex(2)), tr().point(cell.vertex(3))}; + for(auto fh: fh_region) { + auto v0 = fh->vertex(0)->info().vertex_handle_3d; + auto v1 = fh->vertex(1)->info().vertex_handle_3d; + auto v2 = fh->vertex(2)->info().vertex_handle_3d; + auto triangle = typename Geom_traits::Triangle_3{tr().point(v0), tr().point(v1), tr().point(v2)}; + auto exact_triangle = to_exact(triangle); + } + + std::cerr << cdt_3_format("Test tetrahedron (#{}):\n {}\n {}\n {}\n {}\n", + cell.time_stamp(), + IO::oformat(cell.vertex(0), with_point_and_info), + IO::oformat(cell.vertex(1), with_point_and_info), + IO::oformat(cell.vertex(2), with_point_and_info), + IO::oformat(cell.vertex(3), with_point_and_info)); + if(!std::any_of(fh_region.begin(), fh_region.end(), [&](const auto fh) { + auto v0 = fh->vertex(0)->info().vertex_handle_3d; + auto v1 = fh->vertex(1)->info().vertex_handle_3d; + auto v2 = fh->vertex(2)->info().vertex_handle_3d; + auto triangle = typename Geom_traits::Triangle_3{tr().point(v0), tr().point(v1), tr().point(v2)}; + bool b = does_tetrahedron_intersect_triangle_interior(tetrahedron, triangle, tr().geom_traits()); + if(b) { + std::cerr << " intersects the region\n"; + } + return b; + })) + { + std::cerr << cdt_3_format( + "ERROR: The following tetrahedron (#{}) does not intersect the region:\n {}\n {}\n {}\n {}\n", + cell.time_stamp(), + IO::oformat(cell.vertex(0), with_point_and_info), IO::oformat(cell.vertex(1), with_point_and_info), + IO::oformat(cell.vertex(2), with_point_and_info), IO::oformat(cell.vertex(3), with_point_and_info)); + } + } + } + + template + void debug_dump_tetrahedra_intersect_region(CDT_3_signed_index face_index, + int region_index, + const CDT_2& cdt_2, + const Fh_region& fh_region) + { + using Mesh = Surface_mesh; + using Face_index = typename Mesh::Face_index; + using EK = CGAL::Exact_predicates_exact_constructions_kernel; + const auto to_exact = CGAL::Cartesian_converter(); + const auto from_exact = CGAL::Cartesian_converter(); + + Mesh tets_intersect_region_mesh; + auto [color_vpmap, _] = tets_intersect_region_mesh.template add_property_map("f:patch_id"); + + for(auto ch : tr().finite_cell_handles()) { + auto tetrahedron = typename Geom_traits::Tetrahedron_3{tr().point(ch->vertex(0)), tr().point(ch->vertex(1)), + tr().point(ch->vertex(2)), tr().point(ch->vertex(3))}; + if(!std::any_of(fh_region.begin(), fh_region.end(), [&](auto fh) { + const auto v0 = fh->vertex(0)->info().vertex_handle_3d; + const auto v1 = fh->vertex(1)->info().vertex_handle_3d; + const auto v2 = fh->vertex(2)->info().vertex_handle_3d; + const auto triangle = typename Geom_traits::Triangle_3{tr().point(v0), tr().point(v1), tr().point(v2)}; + return does_tetrahedron_intersect_triangle_interior(tetrahedron, triangle, tr().geom_traits()); + })) + { + continue; + } + bool intersects = false; + for(int i = 0; i < 4; ++i) { + for(int j = i + 1; j < 4; ++j) { + int intersects_region = does_edge_intersect_region(ch, i, j, cdt_2, fh_region); + if(intersects_region != 0) { + intersects = true; + } + } + } + if(!intersects) { + std::cerr << "ERROR: tetrahedron #" << ch->time_stamp() << " has no edge intersecting the region\n"; + } + std::ofstream dump_tetrahedron( + cdt_3_format("dump_intersecting_{}_{}_tetrahedron_{}.off", face_index, region_index, ch->time_stamp())); + dump_tetrahedron.precision(17); + Mesh mesh; + CGAL::make_tetrahedron(tr().point(ch->vertex(0)), tr().point(ch->vertex(1)), tr().point(ch->vertex(2)), + tr().point(ch->vertex(3)), mesh); + dump_tetrahedron << mesh; + dump_tetrahedron.close(); + + auto exact_tetrahedron = to_exact(tetrahedron); + for(auto fh : fh_region) { + auto v0 = fh->vertex(0)->info().vertex_handle_3d; + auto v1 = fh->vertex(1)->info().vertex_handle_3d; + auto v2 = fh->vertex(2)->info().vertex_handle_3d; + auto triangle = typename Geom_traits::Triangle_3{tr().point(v0), tr().point(v1), tr().point(v2)}; + + auto exact_triangle = to_exact(triangle); + auto tetrahedron_triangle_intersection_opt = CGAL::intersection(exact_tetrahedron, exact_triangle); + if(!tetrahedron_triangle_intersection_opt) { + continue; + } + if(const auto* tri = std::get_if(&tetrahedron_triangle_intersection_opt.value())) { + exact(*tri); + auto v0 = tets_intersect_region_mesh.add_vertex(from_exact((*tri)[0])); + auto v1 = tets_intersect_region_mesh.add_vertex(from_exact((*tri)[1])); + auto v2 = tets_intersect_region_mesh.add_vertex(from_exact((*tri)[2])); + std::array arr{v0, v1, v2}; + auto f = CGAL::Euler::add_face(arr, tets_intersect_region_mesh); + put(color_vpmap, f, static_cast(ch->time_stamp())); + } + if(const auto* vec = std::get_if>(&tetrahedron_triangle_intersection_opt.value())) + { + std::vector vec_of_indices; + for(const auto& p : *vec) { + exact(p); + vec_of_indices.push_back(tets_intersect_region_mesh.add_vertex(from_exact(p))); + } + CGAL::Euler::add_face(vec_of_indices, tets_intersect_region_mesh); + } + } + } + std::ofstream tets_intersect_region_out( + cdt_3_format("dump_tets_intersect_region_{}_{}.ply", face_index, region_index)); + tets_intersect_region_out.precision(17); + CGAL::IO::write_PLY(tets_intersect_region_out, tets_intersect_region_mesh); + tets_intersect_region_out.close(); + } + void dump_3d_triangulation(CDT_3_signed_index face_index, int region_index, std::string type, diff --git a/Constrained_triangulation_3/include/CGAL/Constrained_triangulation_3/internal/config.h b/Constrained_triangulation_3/include/CGAL/Constrained_triangulation_3/internal/config.h index 99c39f2555b..47f53d42ac5 100644 --- a/Constrained_triangulation_3/include/CGAL/Constrained_triangulation_3/internal/config.h +++ b/Constrained_triangulation_3/include/CGAL/Constrained_triangulation_3/internal/config.h @@ -48,7 +48,7 @@ decltype(auto) cdt_3_format(std::string_view fmt, const Args&... args) { template constexpr decltype(auto) cdt_3_format(Args&&...) { - return ""; + return std::string{}; } constexpr bool cdt_3_can_use_cxx20_format() { diff --git a/Constrained_triangulation_3/include/CGAL/IO/write_MEDIT.h b/Constrained_triangulation_3/include/CGAL/IO/write_MEDIT.h index 7db93a991b7..70d64ea7f4f 100644 --- a/Constrained_triangulation_3/include/CGAL/IO/write_MEDIT.h +++ b/Constrained_triangulation_3/include/CGAL/IO/write_MEDIT.h @@ -9,7 +9,6 @@ // // Author(s) : Jane Tournois -#include "CGAL/type_traits.h" #include "CGAL/unordered_flat_map.h" #include @@ -17,6 +16,8 @@ #include #include + +#include #include namespace CGAL diff --git a/Convex_hull_3/include/CGAL/convex_hull_3.h b/Convex_hull_3/include/CGAL/convex_hull_3.h index 239d83f9134..38053786f0e 100644 --- a/Convex_hull_3/include/CGAL/convex_hull_3.h +++ b/Convex_hull_3/include/CGAL/convex_hull_3.h @@ -1092,7 +1092,7 @@ void convex_hull_3(InputIterator first, InputIterator beyond, std::enable_if_t::value>* = 0) { typedef typename std::iterator_traits::value_type Point_3; - typedef typename Kernel_traits::type Traits; + typedef typename Convex_hull_3::internal::Default_traits_for_Chull_3::type Traits; Convex_hull_3::internal::Indexed_triangle_set its(vertices,faces); convex_hull_3(first, beyond, its, Traits()); diff --git a/Convex_hull_3/test/Convex_hull_3/issue_8954.cpp b/Convex_hull_3/test/Convex_hull_3/issue_8954.cpp new file mode 100644 index 00000000000..7b68f3f2dad --- /dev/null +++ b/Convex_hull_3/test/Convex_hull_3/issue_8954.cpp @@ -0,0 +1,41 @@ +#include +#include + +#include +#include +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::Point_3 Point_3; + + +int main() { + std::vector points = { +{-7.71169150943396353 ,-19.809308490566039, 10.0950745283018861}, +{-7.90879905660377602, -19.809308490566039, 9.8979669811320754}, +{-7.71169150943396353, -19.6122009433962283, 9.8979669811320754}, +{-7.90879905660377602, -19.6122009433962283, 9.8979669811320754}, +{-7.71169150943396353, -19.4150933962264141, 10.0950745283018861}, +{-7.90879905660377602, -19.809308490566039, 10.0950745283018861}, +{-7.71169150943396353, -19.6122009433962283, 10.2921820754716968}, +{-7.90879905660377602, -19.6122009433962283, 10.0950745283018861}, +{-7.71169150943396353, -19.6122009433962283, 10.0950745283018861}, +{-7.71169150943396353, -19.809308490566039, 9.8979669811320754}, +{-7.90879905660377602, -19.4150933962264141, 9.8979669811320754}, +{-7.90879905660377602, -19.4150933962264141, 10.0950745283018861}, +{-7.71169150943396353, -19.4150933962264141, 9.8979669811320754}, +{-7.90879905660377602, -19.6122009433962283, 10.2921820754716968}, +{-7.90879905660377602, -19.4150933962264141, 10.2921820754716968}, +{-7.71169150943396353, -19.4150933962264141, 10.2921820754716968} }; + + std::vector vertices; + std::vector > faces; + + CGAL::convex_hull_3(points.begin(), points.end(), vertices, faces); + + assert(vertices.size() == 10); + assert(faces.size() == 16); + + return 0; +} diff --git a/Data/data/meshes/cubes.off b/Data/data/meshes/cubes.off new file mode 100644 index 00000000000..c62101f6c12 --- /dev/null +++ b/Data/data/meshes/cubes.off @@ -0,0 +1,44 @@ +OFF +14 24 0 + +0 0 1 +1 0 1 +1 0 0 +0 0 0 +0 1 0 +0 1 1 +1 1 1 +1 1 0 +2 1 0 +2 1 1 +2 2 1 +1 2 1 +1 2 0 +2 2 0 +3 4 5 6 +3 0 3 2 +3 1 2 7 +3 0 1 6 +3 3 0 5 +3 2 3 4 +3 6 7 4 +3 2 1 0 +3 7 6 1 +3 6 5 0 +3 5 4 3 +3 4 7 2 +3 10 12 11 +3 8 6 7 +3 13 9 8 +3 10 6 9 +3 11 7 6 +3 12 8 7 +3 12 10 13 +3 6 8 9 +3 9 13 10 +3 6 10 11 +3 7 11 12 +3 8 12 13 + + + diff --git a/Documentation/doc/CMakeLists.txt b/Documentation/doc/CMakeLists.txt index 323c3dc22d6..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 @@ -288,7 +285,7 @@ list(GET DOXYGEN_VERSION 0 DOXYGEN_VERSION) message(VERBOSE "Doxygen version ${DOXYGEN_VERSION}: ${DOXYGEN_EXECUTABLE}") # The Doxygen version is search in that sorted list (to find the index for which the version is less or equal) -set(CGAL_DOXYGEN_RESOURCES_VERSIONS 1.8.13 1.9.6 1.10.0) +set(CGAL_DOXYGEN_RESOURCES_VERSIONS 1.8.13 1.9.6 1.14.0) list(SORT CGAL_DOXYGEN_RESOURCES_VERSIONS COMPARE NATURAL) # The GLOB is here to check that the list in CGAL_DOXYGEN_RESOURCES_VERSIONS is correct. 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/Documentation/Third_party.txt b/Documentation/doc/Documentation/Third_party.txt index b00992f96c5..10378d5fec0 100644 --- a/Documentation/doc/Documentation/Third_party.txt +++ b/Documentation/doc/Documentation/Third_party.txt @@ -11,12 +11,12 @@ supporting C++17 or later. | Operating System | Compiler | | :---------- | :--------------- | -| Linux | \gnu `g++` 11.4.0 or later\cgalFootnote{\cgalFootnoteCode{https://gcc.gnu.org/}} | -| | `Clang` \cgalFootnote{\cgalFootnoteCode{https://clang.llvm.org/}} compiler version 15.0.7 | -| \ms Windows | \gnu `g++` 11.4.0 or later\cgalFootnote{\cgalFootnoteCode{https://gcc.gnu.org/}} | -| | \ms Visual `C++` 15.9, 16.10, 17.0 (\visualstudio 2017, 2019, and 2022)\cgalFootnote{\cgalFootnoteCode{https://visualstudio.microsoft.com/}} | -| macOS | \gnu `g++` 11.4.0 or later\cgalFootnote{\cgalFootnoteCode{https://gcc.gnu.org/}} | -| | Apple `Clang` compiler versions 10.0.1, 12.0.5, and 15.0.0 | +| Linux | \gnu `g++` 12.2.0 or later\cgalFootnote{\cgalFootnoteCode{https://gcc.gnu.org/}} | +| | `Clang` \cgalFootnote{\cgalFootnoteCode{https://clang.llvm.org/}} compiler version 20.1.6 or later | +| \ms Windows | \gnu `g++` 12.2.0 or later\cgalFootnote{\cgalFootnoteCode{https://gcc.gnu.org/}} | +| | \ms Visual `C++` 15.9, 16.10, 17.14 (\visualstudio 2017, 2019, and 2022)\cgalFootnote{\cgalFootnoteCode{https://visualstudio.microsoft.com/}} | +| macOS | \gnu `g++` 12.2.0 or later\cgalFootnote{\cgalFootnoteCode{https://gcc.gnu.org/}} | +| | Apple `Clang` compiler versions 12.0.5, 14.0.0, and 15.0.0 | diff --git a/Documentation/doc/Documentation/Usage.txt b/Documentation/doc/Documentation/Usage.txt index cf30cb9bcbf..4cbd9aaa410 100644 --- a/Documentation/doc/Documentation/Usage.txt +++ b/Documentation/doc/Documentation/Usage.txt @@ -72,7 +72,7 @@ For other distributions or package manager, please consult your respective docum You can also obtain the \cgal library sources directly from https://www.cgal.org/download.html. -Once you have downloaded the file `CGAL-\cgalReleaseNumber``.tar.xz` containing the +Once you have downloaded the file `CGAL-\cgalReleaseNumber.tar.xz` containing the \cgal sources, you have to unpack it. Under a Unix-like shell, use the command: diff --git a/Documentation/doc/Documentation/advanced/Installation.txt b/Documentation/doc/Documentation/advanced/Installation.txt index 7bf4f0f9874..5f6ecf0e696 100644 --- a/Documentation/doc/Documentation/advanced/Installation.txt +++ b/Documentation/doc/Documentation/advanced/Installation.txt @@ -188,8 +188,8 @@ The binary and source directories do not need to be the same. Thus, you can conf distinct directory for each configuration and by running CMake from there. This is known in CMake terminology as out-of-source configuration, as opposite to an in-source configuration, as showed in the previous sections. -You can, for example, generate subdirectories `CGAL-\cgalReleaseNumber``/build/debug` and -`CGAL-\cgalReleaseNumber``/build/release` for two configurations, respectively: +You can, for example, generate subdirectories `CGAL-\cgalReleaseNumber/build/debug` and +`CGAL-\cgalReleaseNumber/build/release` for two configurations, respectively: mkdir CGAL-\cgalReleaseNumber/build/debug cd CGAL-\cgalReleaseNumber/build/debug diff --git a/Documentation/doc/biblio/geom.bib b/Documentation/doc/biblio/geom.bib index bfb054de162..7cfe999a4c6 100644 --- a/Documentation/doc/biblio/geom.bib +++ b/Documentation/doc/biblio/geom.bib @@ -4493,7 +4493,7 @@ cell neighborhood in $O(m)$ time." , month = nov , year = 1988 , pages = "75--80" -, keywords = "weighted euclidean metric, Voronoi partitions, Voronoi diagrams, geometrical problems, point set" +, keywords = "weighted Euclidean metric, Voronoi partitions, Voronoi diagrams, geometrical problems, point set" , update = "93.05 schwarzkopf" , annote = "Multiplicative weights in $n$ dimensions. Incremental algorithm" @@ -20463,7 +20463,7 @@ $O(n^2)$ in the plane." } @article{bg-sfche-89 -, title = "On the space-filling curve heuristic for the euclidean traveling salesman problem" +, title = "On the space-filling curve heuristic for the Euclidean traveling salesman problem" , author = "D. Bertsimas and M. Grigni" , journal = "Operations Research Letters" , year = 1989 @@ -21005,7 +21005,7 @@ $O(n^2)$ in the plane." , update = "98.11 bibrelex, 98.03 mitchell" , abstract = "Let $\cal P$ be a finite arrangement of non-overlapping open cubes with side-lengths not exceeding 1 in the $3$-dimensional -euclidean space. Let $S$ and $T$ be two points lying outside +Euclidean space. Let $S$ and $T$ be two points lying outside the open cubes. Assume one needs to find a short path emanating from $S$ and terminating at $T$ avoiding the cubes of $\cal P$ under the restriction that the cubes are not known prior to the search. @@ -31216,7 +31216,7 @@ determinants." , volume = 5 , year = 1995 , pages = "125--144" -, keywords = "spanners, geometric graphs, greedy algorithm, transformational method, sparse spanners, euclidean graphs" +, keywords = "spanners, geometric graphs, greedy algorithm, transformational method, sparse spanners, Euclidean graphs" , succeeds = "cdns-nsrgs-92" , update = "96.09 devillers" } @@ -44361,7 +44361,7 @@ information is available. In some cases, it is possible to improve the expected randomized complexity of algorithms from $O(n\log n)$ to $O(n\log^{\star} n)$. This technique applies in the following applications~: triangulation of a simple polygon, skeleton of a simple -polygon, Delaunay triangulation of points knowing the EMST (euclidean +polygon, Delaunay triangulation of points knowing the EMST (Euclidean minimum spanning tree)." } @@ -137480,7 +137480,7 @@ depth." , number = 3 , year = 1991 , pages = "221--230" -, keywords = "constrained relative neighborhood graphs (crng), constrained gabriel graphs (cgg), euclidean plane, Delaunay triangulation" +, keywords = "constrained relative neighborhood graphs (crng), constrained gabriel graphs (cgg), Euclidean plane, Delaunay triangulation" , update = "93.09 rote" , annote = "CRNG and CGG are subgraphs of CDT." , abstract = "The original relative neighborhood graph (RNG) and @@ -149747,7 +149747,7 @@ code." @book{y-snegi-79 , author = "I. M. Yaglom" -, title = "A simple non-euclidean geometry and its physical basis" +, title = "A simple non-Euclidean geometry and its physical basis" , publisher = "Springer-Verlag" , year = 1979 , update = "98.03 bibrelex" @@ -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.10.0/BaseDoxyfile.in b/Documentation/doc/resources/1.14.0/BaseDoxyfile.in similarity index 88% rename from Documentation/doc/resources/1.10.0/BaseDoxyfile.in rename to Documentation/doc/resources/1.14.0/BaseDoxyfile.in index 675ab05ff5f..cc68eac2bc3 100644 --- a/Documentation/doc/resources/1.10.0/BaseDoxyfile.in +++ b/Documentation/doc/resources/1.14.0/BaseDoxyfile.in @@ -1,7 +1,7 @@ -# Doxyfile 1.10.0 +# Doxyfile 1.14.0 # This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. +# Doxygen (www.doxygen.org) for a project. # # Only the settings that are not the default ones are kept in this file @@ -220,19 +220,19 @@ ALIASES = "cgal=%CGAL" \ # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# language is one of the parsers supported by Doxygen: IDL, Java, JavaScript, # Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, # VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: -# FortranFree, unknown formatted Fortran: Fortran. In the latter case the parser +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the -# default for Fortran type files). For instance to make doxygen treat .inc files +# default for Fortran type files). For instance to make Doxygen treat .inc files # as Fortran files (default is PHP), and .f files as C (default is Fortran), # use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. When specifying no_extension you should add +# the files are not read by Doxygen. When specifying no_extension you should add # * to the FILE_PATTERNS. # # Note see also the list of default file extension mappings. @@ -243,24 +243,24 @@ EXTENSION_MAPPING = txt=C++ # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 5. +# Minimum value: 0, maximum value: 99, default value: 6. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and +# tag to YES in order to let Doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. +# versus func(std::string) {}). This also makes the inheritance and +# collaboration diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = YES # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. +# Doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. @@ -281,7 +281,7 @@ SUBGROUPING = NO # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# If the EXTRACT_ALL tag is set to YES, Doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. @@ -335,15 +335,15 @@ SHOW_USED_FILES = NO SHOW_FILES = NO # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated +# by Doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can +# that represents Doxygen's defaults, run Doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. See also section "Changing the # layout of pages" for information. # -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# Note that if you run Doxygen from a directory containing a file called +# DoxygenLayout.xml, Doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = ${CGAL_DOC_RESOURCE_DIR}/DoxygenLayoutPackage.xml @@ -364,7 +364,7 @@ CITE_BIB_FILES = ${CGAL_DOC_BIBLIO_DIR}/cgal_manual.bib \ #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the +# standard output by Doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. @@ -380,7 +380,7 @@ QUIET = YES # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not -# read by doxygen. +# read by Doxygen. # # Note the list of default checked file patterns might differ from the list of # default file extension mappings. @@ -437,7 +437,7 @@ EXAMPLE_RECURSIVE = YES # Configuration options related to source browsing #--------------------------------------------------------------------------- -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# If the VERBATIM_HEADERS tag is set the YES then Doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. @@ -462,34 +462,34 @@ ALPHABETICAL_INDEX = NO # # To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. +# that Doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally +# for information on how to generate the default header that Doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description +# default header when upgrading to a newer version of Doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = ${CGAL_DOC_HEADER_PACKAGE} # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard +# generated HTML page. If the tag is left blank Doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. +# that Doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = ${CGAL_DOC_RESOURCE_DIR}/footer.html # Doxygen stores a couple of settings persistently in the browser (via e.g. # cookies). By default these settings apply to all HTML pages generated by -# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# Doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store # the settings under a project specific key, such that the user preferences will # be stored separately. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -507,36 +507,17 @@ HTML_PROJECT_COOKIE = CGAL DISABLE_INDEX = YES -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. If the tag -# value is set to YES, a side panel will be generated containing a tree-like -# index structure (just like the one that is generated for HTML Help). For this -# to work a browser that supports JavaScript, DHTML, CSS and frames is required -# (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine tune the look of the index (see "Fine-tuning the output"). As an -# example, the default style sheet generated by doxygen has an example that -# shows how to put an image at the root of the tree instead of the PROJECT_NAME. -# Since the tree basically has the same information as the tab index, you could -# consider setting DISABLE_INDEX to YES when enabling this option. -# The default value is: NO. +# When GENERATE_TREEVIEW is set to YES, the PAGE_OUTLINE_PANEL option determines +# if an additional navigation panel is shown at the right hand side of the +# screen, displaying an outline of the contents of the main page, similar to +# e.g. https://developer.android.com/reference If GENERATE_TREEVIEW is set to +# NO, this option has no effect. +# The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = YES +PAGE_OUTLINE_PANEL = NO -# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the -# FULL_SIDEBAR option determines if the side bar is limited to only the treeview -# area (value NO) or if it should extend to the full height of the window (value -# YES). Setting this to YES gives a layout similar to -# https://docs.readthedocs.io with more room for contents, but less room for the -# project logo, title, and description. If either GENERATE_TREEVIEW or -# DISABLE_INDEX is set to NO, this option has no effect. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FULL_SIDEBAR = NO - -# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# If the HTML_FORMULA_FORMAT option is set to svg, Doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for # the HTML output. These images will generally look nicer at scaled resolutions. @@ -585,7 +566,7 @@ ${CGAL_DOC_MATHJAX_LOCATION_FULL_OPTION_LINE} MATHJAX_EXTENSIONS = TeX/AMSmath \ TeX/AMSsymbols -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# The MATHJAX_CODEFILE tag can be used to specify a file with JavaScript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: # http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an @@ -594,12 +575,12 @@ MATHJAX_EXTENSIONS = TeX/AMSmath \ MATHJAX_CODEFILE = ${CGAL_DOC_RESOURCE_DIR}/CGAL_mathjax.js -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and +# When the SEARCHENGINE tag is enabled Doxygen will generate a search box for +# the HTML output. The underlying search engine uses JavaScript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then +# For large projects the JavaScript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically @@ -619,7 +600,7 @@ SEARCHENGINE = NO # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# If the GENERATE_LATEX tag is set to YES, Doxygen will generate LaTeX output. # The default value is: YES. GENERATE_LATEX = NO @@ -636,7 +617,7 @@ GENERATE_LATEX = NO # Configuration options related to the XML output #--------------------------------------------------------------------------- -# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# If the XML_PROGRAMLISTING tag is set to YES, Doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size # of the XML output. @@ -649,7 +630,7 @@ XML_PROGRAMLISTING = NO # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# If the MACRO_EXPANSION tag is set to YES, Doxygen will expand all macro names # in the source code. If set to NO, only conditional compilation will be # performed. Macro expansion can be done in a controlled way by setting # EXPAND_ONLY_PREDEF to YES. @@ -690,7 +671,7 @@ PREDEFINED = DOXYGEN_RUNNING \ #--------------------------------------------------------------------------- # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will be +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. @@ -707,7 +688,7 @@ EXTERNAL_PAGES = NO # Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# If you set the HAVE_DOT tag to YES then Doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: # https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is @@ -716,31 +697,41 @@ EXTERNAL_PAGES = NO HAVE_DOT = YES -# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then Doxygen will # generate a graph for each documented class showing the direct and indirect # inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and # HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case # the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the # CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. # If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance -# relations will be shown as texts / links. +# relations will be shown as texts / links. Explicit enabling an inheritance +# graph or choosing a different representation for an inheritance graph of a +# specific class, can be accomplished by means of the command \inheritancegraph. +# Disabling an inheritance graph can be accomplished by means of the command +# \hideinheritancegraph. # Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. CLASS_GRAPH = TEXT -# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# If the COLLABORATION_GRAPH tag is set to YES then Doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = NO -# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. See also the chapter Grouping -# in the manual. +# If the GROUP_GRAPHS tag is set to YES then Doxygen will generate a graph for +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -755,34 +746,42 @@ GROUP_GRAPHS = NO TEMPLATE_RELATIONS = YES # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to -# YES then doxygen will generate a graph for each documented file showing the +# YES then Doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. INCLUDE_GRAPH = NO # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are -# set to YES then doxygen will generate a graph for each documented file showing +# set to YES then Doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. INCLUDED_BY_GRAPH = NO -# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# If the GRAPHICAL_HIERARCHY tag is set to YES then Doxygen will graphical # hierarchy of all classes instead of a textual one. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GRAPHICAL_HIERARCHY = NO -# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# If the DIRECTORY_GRAPH tag is set to YES then Doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -792,12 +791,15 @@ DIRECTORY_GRAPH = NO # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: # https://www.graphviz.org/)). -# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order -# to make the SVG files visible in IE 9+ (other browsers do not have this -# requirement). +# +# Note the formats svg:cairo and svg:cairo:cairo cannot be used in combination +# with INTERACTIVE_SVG (the INTERACTIVE_SVG will be set to NO). # Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, -# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and -# png:gdiplus:gdiplus. +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus, +# png:gdiplus:gdiplus, svg:cairo, svg:cairo:cairo, svg:svg, svg:svg:core, +# gif:cairo, gif:cairo:gd, gif:cairo:gdiplus, gif:gdiplus, gif:gdiplus:gdiplus, +# gif:gd, gif:gd:gd, jpg:cairo, jpg:cairo:gd, jpg:cairo:gdiplus, jpg:gd, +# jpg:gd:gd, jpg:gdiplus and jpg:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -808,17 +810,18 @@ DOT_IMAGE_FORMAT = svg # # Note that this requires a modern browser other than Internet Explorer. Tested # and working are Firefox, Chrome, Safari, and Opera. -# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make -# the SVG files visible. Older versions of IE do not have SVG support. +# +# Note This option will be automatically disabled when DOT_IMAGE_FORMAT is set +# to svg:cairo or svg:cairo:cairo. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. INTERACTIVE_SVG = YES -# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# If the GENERATE_LEGEND tag is set to YES Doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. -# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# Note: This tag requires that UML_LOOK isn't set, i.e. the Doxygen internal # graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. diff --git a/Documentation/doc/resources/1.10.0/CGAL_mathjax.js b/Documentation/doc/resources/1.14.0/CGAL_mathjax.js similarity index 100% rename from Documentation/doc/resources/1.10.0/CGAL_mathjax.js rename to Documentation/doc/resources/1.14.0/CGAL_mathjax.js diff --git a/Documentation/doc/resources/1.10.0/DoxygenLayout.xml b/Documentation/doc/resources/1.14.0/DoxygenLayout.xml similarity index 100% rename from Documentation/doc/resources/1.10.0/DoxygenLayout.xml rename to Documentation/doc/resources/1.14.0/DoxygenLayout.xml diff --git a/Documentation/doc/resources/1.10.0/DoxygenLayoutPackage.xml b/Documentation/doc/resources/1.14.0/DoxygenLayoutPackage.xml similarity index 100% rename from Documentation/doc/resources/1.10.0/DoxygenLayoutPackage.xml rename to Documentation/doc/resources/1.14.0/DoxygenLayoutPackage.xml diff --git a/Documentation/doc/resources/1.10.0/cgal_stylesheet.css b/Documentation/doc/resources/1.14.0/cgal_stylesheet.css similarity index 100% rename from Documentation/doc/resources/1.10.0/cgal_stylesheet.css rename to Documentation/doc/resources/1.14.0/cgal_stylesheet.css diff --git a/Documentation/doc/resources/1.10.0/footer.html b/Documentation/doc/resources/1.14.0/footer.html similarity index 95% rename from Documentation/doc/resources/1.10.0/footer.html rename to Documentation/doc/resources/1.14.0/footer.html index 2ccc7cf39b8..f1e07d613b3 100644 --- a/Documentation/doc/resources/1.10.0/footer.html +++ b/Documentation/doc/resources/1.14.0/footer.html @@ -1,4 +1,4 @@ - + diff --git a/Documentation/doc/resources/1.10.0/hacks.js b/Documentation/doc/resources/1.14.0/hacks.js similarity index 100% rename from Documentation/doc/resources/1.10.0/hacks.js rename to Documentation/doc/resources/1.14.0/hacks.js diff --git a/Documentation/doc/resources/1.10.0/header.html b/Documentation/doc/resources/1.14.0/header.html similarity index 98% rename from Documentation/doc/resources/1.10.0/header.html rename to Documentation/doc/resources/1.14.0/header.html index 0b1efb0d3c4..850ce64fcdc 100644 --- a/Documentation/doc/resources/1.10.0/header.html +++ b/Documentation/doc/resources/1.14.0/header.html @@ -1,4 +1,4 @@ - + diff --git a/Documentation/doc/resources/1.10.0/header_package.html b/Documentation/doc/resources/1.14.0/header_package.html similarity index 99% rename from Documentation/doc/resources/1.10.0/header_package.html rename to Documentation/doc/resources/1.14.0/header_package.html index d39b6ab93dc..d2643842ca9 100644 --- a/Documentation/doc/resources/1.10.0/header_package.html +++ b/Documentation/doc/resources/1.14.0/header_package.html @@ -1,4 +1,4 @@ - + diff --git a/Documentation/doc/resources/1.10.0/menu_version.js b/Documentation/doc/resources/1.14.0/menu_version.js similarity index 91% rename from Documentation/doc/resources/1.10.0/menu_version.js rename to Documentation/doc/resources/1.14.0/menu_version.js index 79c0a8d5d9f..59a85e3a4b0 100644 --- a/Documentation/doc/resources/1.10.0/menu_version.js +++ b/Documentation/doc/resources/1.14.0/menu_version.js @@ -1,14 +1,15 @@ (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.0.1', + 'main', + '6.1', + '6.0.2', 'latest', - '5.6.2', + '5.6.3', '5.5.5', '5.4.5', '5.3.2', @@ -30,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.10.0/test.html b/Documentation/doc/resources/1.14.0/test.html similarity index 100% rename from Documentation/doc/resources/1.10.0/test.html rename to Documentation/doc/resources/1.14.0/test.html diff --git a/Documentation/doc/resources/1.8.13/menu_version.js b/Documentation/doc/resources/1.8.13/menu_version.js index 79c0a8d5d9f..59a85e3a4b0 100644 --- a/Documentation/doc/resources/1.8.13/menu_version.js +++ b/Documentation/doc/resources/1.8.13/menu_version.js @@ -1,14 +1,15 @@ (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.0.1', + 'main', + '6.1', + '6.0.2', 'latest', - '5.6.2', + '5.6.3', '5.5.5', '5.4.5', '5.3.2', @@ -30,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 79c0a8d5d9f..59a85e3a4b0 100644 --- a/Documentation/doc/resources/1.9.6/menu_version.js +++ b/Documentation/doc/resources/1.9.6/menu_version.js @@ -1,14 +1,15 @@ (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.0.1', + 'main', + '6.1', + '6.0.2', 'latest', - '5.6.2', + '5.6.3', '5.5.5', '5.4.5', '5.3.2', @@ -30,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/Filtered_kernel/include/CGAL/Epic_converter.h b/Filtered_kernel/include/CGAL/Epic_converter.h index b8dd072176d..b7d88e77564 100644 --- a/Filtered_kernel/include/CGAL/Epic_converter.h +++ b/Filtered_kernel/include/CGAL/Epic_converter.h @@ -66,7 +66,7 @@ public: if(fit_in_double(n,d)){ return std::make_pair(d,true); } - return std::make_pair(0,false); + return {}; } std::pair operator()(const Bbox_2 b) const @@ -86,7 +86,7 @@ public: if(fit_in_double(p.x(),x) && fit_in_double(p.y(),y)){ return std::make_pair(Point_2(x,y),true); } - return std::make_pair(ORIGIN,false); + return {}; } std::pair operator()(const typename IK::Vector_2& v) const @@ -96,7 +96,7 @@ public: if(fit_in_double(v.x(),x) && fit_in_double(v.y(),y)){ return std::make_pair(Vector_2(x,y),true); } - return std::make_pair(Vector_2(),false); + return {}; } std::pair operator()(const typename IK::Direction_2& d) const @@ -106,7 +106,7 @@ public: if(fit_in_double(d.dx(),x) && fit_in_double(d.dy(),y)){ return std::make_pair(Direction_2(x,y),true); } - return std::make_pair(Direction_2(),false); + return {}; } std::pair operator()(const typename IK::Weighted_point_2& wp) const @@ -116,18 +116,18 @@ public: if(sp.second && w.second){ return std::make_pair(Weighted_point_2(sp.first,w.first),true); } - return std::make_pair(Weighted_point_2(),false); + return {}; } std::pair operator()(const typename IK::Segment_2& s) const { std::pair sp = operator()(s.source()); if(! sp.second){ - return std::make_pair(Segment_2(),false); + return {}; } std::pair tp = operator()(s.target()); if(! tp.second){ - return std::make_pair(Segment_2(),false); + return {}; } return std::make_pair(Segment_2(sp.first,tp.first), true); } @@ -138,18 +138,18 @@ public: if(a.second && b.second && c.second){ return std::make_pair(Line_2(a.first, b.first, c.first),true); } - return std::make_pair(Line_2(), false); + return {}; } std::pair operator()(const typename IK::Ray_2& r) const { std::pair sp = operator()(r.source()); if(! sp.second){ - return std::make_pair(Ray_2(),false); + return {}; } std::pair tp = operator()(r.second_point()); if(! tp.second){ - return std::make_pair(Ray_2(),false); + return {}; } return std::make_pair(Ray_2(sp.first,tp.first), true); } @@ -158,15 +158,15 @@ public: { std::pair v0 = operator()(t.vertex(0)); if(! v0.second){ - return std::make_pair(Triangle_2(),false); + return {}; } std::pair v1 = operator()(t.vertex(1)); if(! v1.second){ - return std::make_pair(Triangle_2(),false); + return {}; } std::pair v2 = operator()(t.vertex(2)); if(! v2.second){ - return std::make_pair(Triangle_2(),false); + return {}; } return std::make_pair(Triangle_2(v0.first,v1.first, v2.first), true); } @@ -178,18 +178,18 @@ public: if(c.second && sr.second){ return std::make_pair(Circle_2(c.first, sr.first, ci.orientation()),true); } - return std::make_pair(Circle_2(), false); + return {}; } std::pair operator()(const typename IK::Iso_rectangle_2& ir) const { std::pair sp = operator()((ir.min)()); if(! sp.second){ - return std::make_pair(Iso_rectangle_2(),false); + return {}; } std::pair tp = operator()((ir.max)()); if(! tp.second){ - return std::make_pair(Iso_rectangle_2(),false); + return {}; } return std::make_pair(Iso_rectangle_2(sp.first,tp.first), true); } @@ -199,11 +199,11 @@ public: { std::pair sp = operator()(li.point()); if(! sp.second){ - return std::make_pair(Line_3(),false); + return {}; } std::pair tp = operator()(li.to_vector()); if(! tp.second){ - return std::make_pair(Line_3(),false); + return {}; } return std::make_pair(Line_3(sp.first,tp.first), true); } @@ -214,22 +214,22 @@ public: if(a.second && b.second && c.second && d.second){ return std::make_pair(Plane_3(a.first, b.first, c.first, d.first),true); } - return std::make_pair(Plane_3(), false); + return {}; } std::pair operator()(const typename IK::Triangle_3& t) const { std::pair v0 = operator()(t.vertex(0)); if(! v0.second){ - return std::make_pair(Triangle_3(),false); + return {}; } std::pair v1 = operator()(t.vertex(1)); if(! v1.second){ - return std::make_pair(Triangle_3(),false); + return {}; } std::pair v2 = operator()(t.vertex(2)); if(! v2.second){ - return std::make_pair(Triangle_3(),false); + return {}; } return std::make_pair(Triangle_3(v0.first,v1.first, v2.first), true); } @@ -238,19 +238,19 @@ public: { std::pair v0 = operator()(t.vertex(0)); if(! v0.second){ - return std::make_pair(Tetrahedron_3(),false); + return {}; } std::pair v1 = operator()(t.vertex(1)); if(! v1.second){ - return std::make_pair(Tetrahedron_3(),false); + return {}; } std::pair v2 = operator()(t.vertex(2)); if(! v2.second){ - return std::make_pair(Tetrahedron_3(),false); + return {}; } std::pair v3 = operator()(t.vertex(3)); if(! v3.second){ - return std::make_pair(Tetrahedron_3(),false); + return {}; } return std::make_pair(Tetrahedron_3(v0.first,v1.first, v2.first, v3.first), true); } @@ -259,11 +259,11 @@ public: { std::pair sp = operator()(r.source()); if(! sp.second){ - return std::make_pair(Ray_3(),false); + return {}; } std::pair tp = operator()(r.second_point()); if(! tp.second){ - return std::make_pair(Ray_3(),false); + return {}; } return std::make_pair(Ray_3(sp.first,tp.first), true); } @@ -275,7 +275,7 @@ public: if(fit_in_double(p.x(),x) && fit_in_double(p.y(),y) && fit_in_double(p.z(),z)){ return std::make_pair(Point_3(x,y,z),true); } - return std::make_pair(ORIGIN,false); + return {}; } std::pair operator()(const typename IK::Vector_3& v) const @@ -285,7 +285,7 @@ public: if(fit_in_double(v.x(),x) && fit_in_double(v.y(),y) && fit_in_double(v.z(),z)){ return std::make_pair(Vector_3(x,y,z),true); } - return std::make_pair(Vector_3(),false); + return {}; } std::pair operator()(const typename IK::Direction_3& d) const @@ -295,18 +295,18 @@ public: if(fit_in_double(d.dx(),x) && fit_in_double(d.dy(),y) && fit_in_double(d.dz(),z)){ return std::make_pair(Direction_3(x,y,z),true); } - return std::make_pair(Direction_3(),false); + return {}; } std::pair operator()(const typename IK::Segment_3& s) const { std::pair sp = operator()(s.source()); if(! sp.second){ - return std::make_pair(Segment_3(),false); + return {}; } std::pair tp = operator()(s.target()); if(! tp.second){ - return std::make_pair(Segment_3(),false); + return {}; } return std::make_pair(Segment_3(sp.first,tp.first), true); } @@ -318,7 +318,7 @@ public: if(sp.second && w.second){ return std::make_pair(Weighted_point_3(sp.first,w.first),true); } - return std::make_pair(Weighted_point_3(),false); + return {}; } std::pair operator()(const typename IK::Sphere_3& s) const @@ -328,7 +328,7 @@ public: if(c.second && sr.second){ return std::make_pair(Sphere_3(c.first, sr.first, s.orientation()),true); } - return std::make_pair(Sphere_3(), false); + return {}; } std::pair operator()(const typename IK::Circle_3& ci) const @@ -338,18 +338,18 @@ public: if(c.second && sr.second){ return std::make_pair(Circle_3(sr.first, c.first),true); } - return std::make_pair(Circle_3(), false); + return {}; } std::pair operator()(const typename IK::Iso_cuboid_3& ic) const { std::pair sp = operator()((ic.min)()); if(! sp.second){ - return std::make_pair(Iso_cuboid_3(),false); + return {}; } std::pair tp = operator()((ic.max)()); if(! tp.second){ - return std::make_pair(Iso_cuboid_3(),false); + return {}; } return std::make_pair(Iso_cuboid_3(sp.first,tp.first), true); } diff --git a/Filtered_kernel/include/CGAL/Filtered_kernel/internal/Static_filters/Orientation_4.h b/Filtered_kernel/include/CGAL/Filtered_kernel/internal/Static_filters/Orientation_4.h new file mode 100644 index 00000000000..ebd9f99e7f4 --- /dev/null +++ b/Filtered_kernel/include/CGAL/Filtered_kernel/internal/Static_filters/Orientation_4.h @@ -0,0 +1,221 @@ +// Copyright (c) 2025 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Andreas Fabri + +#ifndef CGAL_INTERNAL_STATIC_FILTERS_ORIENTATION_4_H +#define CGAL_INTERNAL_STATIC_FILTERS_ORIENTATION_4_H + +#include +#include +#include +#include + +namespace CGAL { namespace internal { namespace Static_filters_predicates { + + + +template < typename K_base > +class Orientation_4 + : public K_base::Orientation_4 +{ + typedef typename K_base::Orientation Orientation; + typedef typename K_base::Point_4 Point_4; + typedef typename K_base::Orientation_4 Base; + +public: + using Base::operator(); + + Orientation + operator()(const Point_4 &p, const Point_4 &q, + const Point_4 &r, const Point_4 &s, + const Point_4 &t) const + { + CGAL_BRANCH_PROFILER_3("semi-static failures/attempts/calls to : Orientation_4", tmp); + + double p0, p1, p2, p3, q0, q1, q2, q3, r0, r1, r2, r3, s0, s1, s2, s3, t0, t1, t2, t3; + + if (fit_in_double(p.c0(), p0) && fit_in_double(p.c1(), p1) && + fit_in_double(p.c2(), p2) && fit_in_double(p.c3(), p3) && + fit_in_double(q.c0(), q0) && fit_in_double(q.c1(), q1) && + fit_in_double(q.c2(), q2) && fit_in_double(q.c3(), q3) && + fit_in_double(r.c0(), r0) && fit_in_double(r.c1(), r1) && + fit_in_double(r.c2(), r2) && fit_in_double(r.c3(), r3) && + fit_in_double(s.c0(), s0) && fit_in_double(s.c1(), s1) && + fit_in_double(s.c2(), s2) && fit_in_double(s.c3(), s3) && + fit_in_double(t.c0(), t0) && fit_in_double(t.c1(), t1) && + fit_in_double(t.c2(), t2) && fit_in_double(t.c3(), t3) ) + { + CGAL_assertion_code(Orientation should_be = Base::operator()(p, q, r, s, t)); +double m01; + m01 = (q0 - p0); + double m02; + m02 = (r0 - p0); + double m03; + m03 = (s0 - p0); + double m04; + m04 = (t0 - p0); + double m11; + m11 = (q1 - p1); + double m12; + m12 = (r1 - p1); + double m13; + m13 = (s1 - p1); + double m14; + m14 = (t1 - p1); + double m21; + m21 = (q2 - p2); + double m22; + m22 = (r2 - p2); + double m23; + m23 = (s2 - p2); + double m24; + m24 = (t2 - p2); + double m31; + m31 = (q3 - p3); + double m32; + m32 = (r3 - p3); + double m33; + m33 = (s3 - p3); + double m34; + m34 = (t3 - p3); + double det; + det = ::CGAL::determinant( m01, m02, m03, m04, m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34 ); + double eps; + double max1 = CGAL::abs(m01); + double am = CGAL::abs(m02); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m03); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m11); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m12); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m13); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m23); + if( (max1 < am) ) { max1 = am; } + + + double max2 = CGAL::abs(m01); + am = CGAL::abs(m02); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m11); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m12); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m21); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m22); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m23); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m33); + if( (max2 < am) ) { max2 = am; } + + + double max3 = CGAL::abs(m04); + am = CGAL::abs(m14); + if( (max3 < am) ) { max3 = am; } + am = CGAL::abs(m24); + if( (max3 < am) ) { max3 = am; } + am = CGAL::abs(m34); + if( (max3 < am) ) { max3 = am; } + + + double max4 = CGAL::abs(m11); + am = CGAL::abs(m12); + if( (max4 < am) ) { max4 = am; } + am = CGAL::abs(m21); + if( (max4 < am) ) { max4 = am; } + am = CGAL::abs(m22); + if( (max4 < am) ) { max4 = am; } + am = CGAL::abs(m31); + if( (max4 < am) ) { max4 = am; } + am = CGAL::abs(m32); + if( (max4 < am) ) { max4 = am; } + + + double lower_bound_1; + double upper_bound_1; + lower_bound_1 = max1; + upper_bound_1 = max1; + if( (max2 < lower_bound_1) ) + { + lower_bound_1 = max2; + } + else + { + if( (max2 > upper_bound_1) ) + { + upper_bound_1 = max2; + } + } + if( (max3 < lower_bound_1) ) + { + lower_bound_1 = max3; + } + else + { + if( (max3 > upper_bound_1) ) + { + upper_bound_1 = max3; + } + } + if( (max4 < lower_bound_1) ) + { + lower_bound_1 = max4; + } + else + { + if( (max4 > upper_bound_1) ) + { + upper_bound_1 = max4; + } + } + if( (lower_bound_1 < 2.89273249588395272840e-74) ) + { + return Base::operator()(p, q, r, s, t); + } + else + { + if( (upper_bound_1 > 7.23700557733225900010e+75) ) + { + return Base::operator()(p, q, r, s, t); + } + eps = (3.17768858673611327578e-14 * (((max4 * max2) * max1) * max3)); + if( (det > eps) ) + { + CGAL_assertion(should_be == POSITIVE); + return POSITIVE; + } + else + { + if( (det < -eps) ) + { + CGAL_assertion(should_be == NEGATIVE); + return NEGATIVE; + } + else + { + return Base::operator()(p, q, r, s, t); + } + } + } +} + return Base::operator()(p, q, r, s, t); + + } + +}; + +} } } // namespace CGAL::internal::Static_filters_predicates + +#endif // CGAL_INTERNAL_STATIC_FILTERS_ORIENTATION_4_H diff --git a/Filtered_kernel/include/CGAL/Filtered_kernel/internal/Static_filters/Orientation_5.h b/Filtered_kernel/include/CGAL/Filtered_kernel/internal/Static_filters/Orientation_5.h new file mode 100644 index 00000000000..a57f445e885 --- /dev/null +++ b/Filtered_kernel/include/CGAL/Filtered_kernel/internal/Static_filters/Orientation_5.h @@ -0,0 +1,289 @@ +// Copyright (c) 2025 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Andreas Fabri + +#ifndef CGAL_INTERNAL_STATIC_FILTERS_ORIENTATION_5_H +#define CGAL_INTERNAL_STATIC_FILTERS_ORIENTATION_5_H + +#include +#include +#include +#include + +namespace CGAL { namespace internal { namespace Static_filters_predicates { + + + +template < typename K_base > +class Orientation_5 + : public K_base::Orientation_5 +{ + typedef typename K_base::Orientation Orientation; + typedef typename K_base::Point_5 Point_5; + typedef typename K_base::Orientation_5 Base; + +public: + using Base::operator(); + + Orientation + operator()(const Point_5 &p, const Point_5 &q, + const Point_5 &r, const Point_5 &s, + const Point_5 &t, const Point_5 &u) const + { + CGAL_BRANCH_PROFILER_3("semi-static failures/attempts/calls to : Orientation_5", tmp); + + double p0, p1, p2, p3, p4, q0, q1, q2, q3, q4, r0, r1, r2, r3, r4, s0, s1, s2, s3, s4, t0, t1, t2, t3, t4, u0, u1, u2, u3, u4; + + if (fit_in_double(p.c0(), p0) && fit_in_double(p.c1(), p1) && + fit_in_double(p.c2(), p2) && fit_in_double(p.c3(), p3) && + fit_in_double(p.c4(), p4) && + fit_in_double(q.c0(), q0) && fit_in_double(q.c1(), q1) && + fit_in_double(q.c2(), q2) && fit_in_double(q.c3(), q3) && + fit_in_double(q.c4(), q4) && + fit_in_double(r.c0(), r0) && fit_in_double(r.c1(), r1) && + fit_in_double(r.c2(), r2) && fit_in_double(r.c3(), r3) && + fit_in_double(r.c4(), r4) && + fit_in_double(s.c0(), s0) && fit_in_double(s.c1(), s1) && + fit_in_double(s.c2(), s2) && fit_in_double(s.c3(), s3) && + fit_in_double(s.c4(), s4) && + fit_in_double(t.c0(), t0) && fit_in_double(t.c1(), t1) && + fit_in_double(t.c2(), t2) && fit_in_double(t.c3(), t3) && + fit_in_double(t.c4(), t4) && + fit_in_double(u.c0(), u0) && fit_in_double(u.c1(), u1) && + fit_in_double(u.c2(), u2) && fit_in_double(u.c3(), u3) && + fit_in_double(u.c4(), u4)) + + { + CGAL_assertion_code(Orientation should_be = Base::operator()(p, q, r, s, t, u)); + double m01; + m01 = (q0 - p0); + double m02; + m02 = (r0 - p0); + double m03; + m03 = (s0 - p0); + double m04; + m04 = (t0 - p0); + double m05; + m05 = (u0 - p0); + double m11; + m11 = (q1 - p1); + double m12; + m12 = (r1 - p1); + double m13; + m13 = (s1 - p1); + double m14; + m14 = (t1 - p1); + double m15; + m15 = (u1 - p1); + double m21; + m21 = (q2 - p2); + double m22; + m22 = (r2 - p2); + double m23; + m23 = (s2 - p2); + double m24; + m24 = (t2 - p2); + double m25; + m25 = (u2 - p2); + double m31; + m31 = (q3 - p3); + double m32; + m32 = (r3 - p3); + double m33; + m33 = (s3 - p3); + double m34; + m34 = (t3 - p3); + double m35; + m35 = (u3 - p3); + double m41; + m41 = (q4 - p4); + double m42; + m42 = (r4 - p4); + double m43; + m43 = (s4 - p4); + double m44; + m44 = (t4 - p4); + double m45; + m45 = (u4 - p4); + double det; + det = ::CGAL::determinant( m01, m02, m03, m04, m05, m11, m12, m13, m14, m15, m21, m22, m23, m24, m25, m31, m32, m33, m34, m35, m41, m42, m43, m44, m45 ); + double eps; + double max1 = CGAL::abs(m01); + double am = CGAL::abs(m02); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m03); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m11); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m12); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m13); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m21); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m22); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m23); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m33); + if( (max1 < am) ) { max1 = am; } + + + double max2 = CGAL::abs(m01); + am = CGAL::abs(m02); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m11); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m12); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m21); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m22); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m23); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m31); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m32); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m33); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m43); + if( (max2 < am) ) { max2 = am; } + + + double max3 = CGAL::abs(m04); + am = CGAL::abs(m14); + if( (max3 < am) ) { max3 = am; } + am = CGAL::abs(m24); + if( (max3 < am) ) { max3 = am; } + am = CGAL::abs(m34); + if( (max3 < am) ) { max3 = am; } + am = CGAL::abs(m44); + if( (max3 < am) ) { max3 = am; } + + + double max4 = CGAL::abs(m05); + am = CGAL::abs(m15); + if( (max4 < am) ) { max4 = am; } + am = CGAL::abs(m25); + if( (max4 < am) ) { max4 = am; } + am = CGAL::abs(m35); + if( (max4 < am) ) { max4 = am; } + am = CGAL::abs(m45); + if( (max4 < am) ) { max4 = am; } + + + double max5 = CGAL::abs(m11); + am = CGAL::abs(m12); + if( (max5 < am) ) { max5 = am; } + am = CGAL::abs(m21); + if( (max5 < am) ) { max5 = am; } + am = CGAL::abs(m22); + if( (max5 < am) ) { max5 = am; } + am = CGAL::abs(m31); + if( (max5 < am) ) { max5 = am; } + am = CGAL::abs(m32); + if( (max5 < am) ) { max5 = am; } + am = CGAL::abs(m41); + if( (max5 < am) ) { max5 = am; } + am = CGAL::abs(m42); + if( (max5 < am) ) { max5 = am; } + + double lower_bound_1; + double upper_bound_1; + lower_bound_1 = max5; + upper_bound_1 = max5; + if( (max1 < lower_bound_1) ) + { + lower_bound_1 = max1; + } + else + { + if( (max1 > upper_bound_1) ) + { + upper_bound_1 = max1; + } + } + if( (max2 < lower_bound_1) ) + { + lower_bound_1 = max2; + } + else + { + if( (max2 > upper_bound_1) ) + { + upper_bound_1 = max2; + } + } + if( (max3 < lower_bound_1) ) + { + lower_bound_1 = max3; + } + else + { + if( (max3 > upper_bound_1) ) + { + upper_bound_1 = max3; + } + } + if( (max4 < lower_bound_1) ) + { + lower_bound_1 = max4; + } + else + { + if( (max4 > upper_bound_1) ) + { + upper_bound_1 = max4; + } + } + if( (lower_bound_1 < 9.99657131447050328602e-60) ) + { + return Base::operator()(p, q, r, s, t, u); + } + else + { + if( (upper_bound_1 > 3.21387608851797912384e+60) ) + { + return Base::operator()(p, q, r, s, t, u); + } + eps = (2.22889232457534740153e-13 * ((((max5 * max2) * max1) * max3) * max4)); + if( (det > eps) ) + { + CGAL_assertion(should_be == POSITIVE); + return POSITIVE; + } + else + { + if( (det < -eps) ) + { + CGAL_assertion(should_be == NEGATIVE); + return NEGATIVE; + } + else + { + return Base::operator()(p, q, r, s, t, u); + } + } + } + + } + + return Base::operator()(p, q, r, s, t, u); + } + + +}; + +} } } // namespace CGAL::internal::Static_filters_predicates + +#endif // CGAL_INTERNAL_STATIC_FILTERS_ORIENTATION_5_H diff --git a/Filtered_kernel/include/CGAL/Filtered_kernel/internal/Static_filters/Orientation_6.h b/Filtered_kernel/include/CGAL/Filtered_kernel/internal/Static_filters/Orientation_6.h new file mode 100644 index 00000000000..f5f7fae103d --- /dev/null +++ b/Filtered_kernel/include/CGAL/Filtered_kernel/internal/Static_filters/Orientation_6.h @@ -0,0 +1,358 @@ +// Copyright (c) 2025 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Andreas Fabri + +#ifndef CGAL_INTERNAL_STATIC_FILTERS_ORIENTATION_6_H +#define CGAL_INTERNAL_STATIC_FILTERS_ORIENTATION_6_H + +#include +#include +#include +#include + +namespace CGAL { namespace internal { namespace Static_filters_predicates { + + + +template < typename K_base > +class Orientation_6 + : public K_base::Orientation_6 +{ + typedef typename K_base::Orientation Orientation; + typedef typename K_base::Point_6 Point_6; + typedef typename K_base::Orientation_6 Base; + +public: + using Base::operator(); + + Orientation + operator()(const Point_6 &p, const Point_6 &q, + const Point_6 &r, const Point_6 &s, + const Point_6 &t, const Point_6 &u, const Point_6 &v) const + { + CGAL_BRANCH_PROFILER_3("semi-static failures/attempts/calls to : Orientation_6", tmp); + + double p0, p1, p2, p3, p4, p5, q0, q1, q2, q3, q4, q5, r0, r1, r2, r3, r4, r5, s0, s1, s2, s3, s4, s5, t0, t1, t2, t3, t4, t5, u0, u1, u2, u3, u4, u5, v0, v1, v2, v3, v4, v5; + if (fit_in_double(p.c0(), p0) && fit_in_double(p.c1(), p1) && + fit_in_double(p.c2(), p2) && fit_in_double(p.c3(), p3) && + fit_in_double(p.c4(), p4) && fit_in_double(p.c5(), p5) && + + fit_in_double(q.c0(), q0) && fit_in_double(q.c1(), q1) && + fit_in_double(q.c2(), q2) && fit_in_double(q.c3(), q3) && + fit_in_double(q.c4(), q4) && fit_in_double(q.c5(), q5) && + + fit_in_double(r.c0(), r0) && fit_in_double(r.c1(), r1) && + fit_in_double(r.c2(), r2) && fit_in_double(r.c3(), r3) && + fit_in_double(r.c4(), r4) && fit_in_double(r.c5(), r5) && + + fit_in_double(s.c0(), s0) && fit_in_double(s.c1(), s1) && + fit_in_double(s.c2(), s2) && fit_in_double(s.c3(), s3) && + fit_in_double(s.c4(), s4) && fit_in_double(s.c5(), s5) && + + fit_in_double(t.c0(), t0) && fit_in_double(t.c1(), t1) && + fit_in_double(t.c2(), t2) && fit_in_double(t.c3(), t3) && + fit_in_double(t.c4(), t4) && fit_in_double(t.c5(), t5) && + + fit_in_double(u.c0(), u0) && fit_in_double(u.c1(), u1) && + fit_in_double(u.c2(), u2) && fit_in_double(u.c3(), u3) && + fit_in_double(u.c4(), u4) && fit_in_double(u.c5(), u5) && + + fit_in_double(v.c0(), v0) && fit_in_double(v.c1(), v1) && + fit_in_double(v.c2(), v2) && fit_in_double(v.c3(), v3) && + fit_in_double(v.c4(), v4) && fit_in_double(v.c5(), v5)) + { + CGAL_assertion_code(Orientation should_be = Base::operator()(p, q, r, s, t, u, v)); + double m01; + m01 = (q0 - p0); + double m02; + m02 = (r0 - p0); + double m03; + m03 = (s0 - p0); + double m04; + m04 = (t0 - p0); + double m05; + m05 = (u0 - p0); + double m06; + m06 = (v0 - p0); + double m11; + m11 = (q1 - p1); + double m12; + m12 = (r1 - p1); + double m13; + m13 = (s1 - p1); + double m14; + m14 = (t1 - p1); + double m15; + m15 = (u1 - p1); + double m16; + m16 = (v1 - p1); + double m21; + m21 = (q2 - p2); + double m22; + m22 = (r2 - p2); + double m23; + m23 = (s2 - p2); + double m24; + m24 = (t2 - p2); + double m25; + m25 = (u2 - p2); + double m26; + m26 = (v2 - p2); + double m31; + m31 = (q3 - p3); + double m32; + m32 = (r3 - p3); + double m33; + m33 = (s3 - p3); + double m34; + m34 = (t3 - p3); + double m35; + m35 = (u3 - p3); + double m36; + m36 = (v3 - p3); + double m41; + m41 = (q4 - p4); + double m42; + m42 = (r4 - p4); + double m43; + m43 = (s4 - p4); + double m44; + m44 = (t4 - p4); + double m45; + m45 = (u4 - p4); + double m46; + m46 = (v4 - p4); + double m51; + m51 = (q5 - p5); + double m52; + m52 = (r5 - p5); + double m53; + m53 = (s5 - p5); + double m54; + m54 = (t5 - p5); + double m55; + m55 = (u5 - p5); + double m56; + m56 = (v5 - p5); + double det; + det = ::CGAL::determinant( m01, m02, m03, m04, m05, m06, m11, m12, m13, m14, m15, m16, m21, m22, m23, m24, m25, m26, m31, m32, m33, m34, m35, m36, m41, m42, m43, m44, m45, m46, m51, m52, m53, m54, m55, m56 ); + double eps; + double max1 = CGAL::abs(m01); + double am = CGAL::abs(m02); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m11); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m12); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m21); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m22); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m31); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m32); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m41); + if( (max1 < am) ) { max1 = am; } + am = CGAL::abs(m42); + if( (max1 < am) ) { max1 = am; } + + + double max2 = CGAL::abs(m03); + am = CGAL::abs(m11); + + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m12); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m13); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m21); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m22); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m23); + + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m31); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m32); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m33); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m41); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m42); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m43); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m51); + if( (max2 < am) ) { max2 = am; } + am = CGAL::abs(m52); + if( (max2 < am) ) { max2 = am; } + + + double max3 = CGAL::abs(m04); + am = CGAL::abs(m14); + if( (max3 < am) ) { max3 = am; } + am = CGAL::abs(m24); + if( (max3 < am) ) { max3 = am; } + am = CGAL::abs(m34); + if( (max3 < am) ) { max3 = am; } + am = CGAL::abs(m44); + if( (max3 < am) ) { max3 = am; } + am = CGAL::abs(m54); + if( (max3 < am) ) { max3 = am; } + + double max4 = CGAL::abs(m05); + am = CGAL::abs(m15); + if( (max4 < am) ) { max4 = am; } + am = CGAL::abs(m25); + if( (max4 < am) ) { max3 = am; } + am = CGAL::abs(m35); + if( (max4 < am) ) { max4= am; } + am = CGAL::abs(m45); + if( (max4 < am) ) { max4 = am; } + am = CGAL::abs(m55); + if( (max4 < am) ) { max4 = am; } + + double max5 = CGAL::abs(m06); + am = CGAL::abs(m16); + if( (max5 < am) ) { max5 = am; } + am = CGAL::abs(m26); + if( (max5 < am) ) { max5 = am; } + am = CGAL::abs(m36); + if( (max5 < am) ) { max5 = am; } + am = CGAL::abs(m46); + if( (max5 < am) ) { max5 = am; } + am = CGAL::abs(m56); + if( (max5 < am) ) { max5 = am; } + + + double max6 = CGAL::abs(m13); + am = CGAL::abs(m21); + if( (max6 < am) ) { max6 = am; } + am = CGAL::abs(m22); + if( (max6 < am) ) { max6 = am; } + am = CGAL::abs(m23); + if( (max6 < am) ) { max6 = am; } + am = CGAL::abs(m31); + if( (max6 < am) ) { max6 = am; } + am = CGAL::abs(m32); + if( (max6 < am) ) { max6 = am; } + am = CGAL::abs(m33); + if( (max6 < am) ) { max6 = am; } + am = CGAL::abs(m41); + if( (max6 < am) ) { max6 = am; } + am = CGAL::abs(m42); + if( (max6 < am) ) { max6 = am; } + am = CGAL::abs(m43); + if( (max6 < am) ) { max6 = am; } + am = CGAL::abs(m51); + if( (max6 < am) ) { max6 = am; } + am = CGAL::abs(m52); + if( (max6 < am) ) { max6 = am; } + am = CGAL::abs(m53); + am = CGAL::abs(m53); + if( (max6 < am) ) { max6 = am; } + + + double lower_bound_1; + double upper_bound_1; + lower_bound_1 = max6; + upper_bound_1 = max6; + if( (max5 < lower_bound_1) ) + { + lower_bound_1 = max5; + } + else + { + if( (max5 > upper_bound_1) ) + { + upper_bound_1 = max5; + } + } + if( (max1 < lower_bound_1) ) + { + lower_bound_1 = max1; + } + else + { + if( (max1 > upper_bound_1) ) + { + upper_bound_1 = max1; + } + } + if( (max2 < lower_bound_1) ) + { + lower_bound_1 = max2; + } + else + { + if( (max2 > upper_bound_1) ) + { + upper_bound_1 = max2; + } + } + if( (max3 < lower_bound_1) ) + { + lower_bound_1 = max3; + } + else + { + if( (max3 > upper_bound_1) ) + { + upper_bound_1 = max3; + } + } + if( (max4 < lower_bound_1) ) + { + lower_bound_1 = max4; + } + else + { + if( (max4 > upper_bound_1) ) + { + upper_bound_1 = max4; + } + } + if( (lower_bound_1 < 4.82472686053427214432e-50) ) + { + return Base::operator()(p, q, r, s, t, u, v); + } + else + { + if( (upper_bound_1 > 1.87072209578355511223e+50) ) + { + return Base::operator()(p, q, r, s, t, u, v); + } + eps = (1.76403842114300859158e-12 * (((((max1 * max2) * max6) * max3) * max4) * max5)); + if( (det > eps) ) + { + CGAL_assertion(should_be == POSITIVE); + return POSITIVE; + } + else + { + if( (det < -eps) ) + { + CGAL_assertion(should_be == NEGATIVE); + return NEGATIVE; + } + } + } +} + return Base::operator()(p, q, r, s, t, u, v); + } +}; + +} } } // namespace CGAL::internal::Static_filters_predicates + +#endif // CGAL_INTERNAL_STATIC_FILTERS_ORIENTATION_6_H diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index f62e70e6dc0..c578852a331 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -119,23 +119,19 @@ templateinline std::enable_if_t::value, int> depth(T){ namespace internal{ - template - struct Evaluate> +template +struct Evaluate> +{ + template + void operator()(const Lazy& l) { - void operator()(const Lazy& l) - { - exact(l); - } + exact(l); + } + void operator()(const Lazy_exact_nt& l) + { + exact(l); + } }; - - template - struct Evaluate> - { - void operator()(const Lazy_exact_nt& l) - { - exact(l); - } - }; } // internal namespace // For an iterator, exact/approx applies to the objects it points to @@ -233,14 +229,14 @@ print_dag(const Return_base_tag&, std::ostream& os, int level) struct Depth_base { #ifdef CGAL_PROFILE - int depth_; + mutable int depth_; Depth_base() : depth_(0) {} int depth() const { return depth_; } - void set_depth(int i) + void set_depth(int i) const { depth_ = i; CGAL_HISTOGRAM_PROFILER(std::string("[Lazy_kernel DAG depths]"), i); @@ -248,7 +244,7 @@ struct Depth_base { } #else int depth() const { return 0; } - void set_depth(int) {} + void set_depth(int) const {} #endif }; @@ -660,6 +656,7 @@ class Lazy_rep_n final : auto* p = new typename Base::Indirect(ec()( CGAL::exact( std::get(l) ) ... ) ); this->set_at(p); this->set_ptr(p); + this->set_depth(0); if(!noprune || is_currently_single_threaded()) lazy_reset_member(l); } diff --git a/Frechet_distance/include/CGAL/Frechet_distance/internal/Frechet_classical.h b/Frechet_distance/include/CGAL/Frechet_distance/internal/Frechet_classical.h index d7b8ad175a1..fe37d5385c5 100644 --- a/Frechet_distance/include/CGAL/Frechet_distance/internal/Frechet_classical.h +++ b/Frechet_distance/include/CGAL/Frechet_distance/internal/Frechet_classical.h @@ -78,7 +78,7 @@ bool FrechetClassical::lessThan(distance_t const& distance, Curve const& curv reachable1[i][j] = free_int.begin; } else if (reachable1[i][j-1] && reachable1[i][j-1] <= free_int.end) { - reachable1[i][j] = CGAL::max(free_int.begin, reachable1[i][j-1].value()); + reachable1[i][j] = (CGAL::max)(free_int.begin, reachable1[i][j-1].value())); } } } @@ -89,7 +89,7 @@ bool FrechetClassical::lessThan(distance_t const& distance, Curve const& curv reachable2[i][j] = free_int.begin; } else if (reachable2[i-1][j] && reachable2[i-1][j] <= free_int.end) { - reachable2[i][j] = CGAL::max(free_int.begin, reachable2[i-1][j].value()); + reachable2[i][j] = (CGAL::max)(free_int.begin, reachable2[i-1][j].value()); } } } 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/doc/GraphicsView/GraphicsView.txt b/GraphicsView/doc/GraphicsView/GraphicsView.txt index 17dd8bfa0d0..5a8f45d7d51 100644 --- a/GraphicsView/doc/GraphicsView/GraphicsView.txt +++ b/GraphicsView/doc/GraphicsView/GraphicsView.txt @@ -8,17 +8,17 @@ namespace CGAL { \cgalAutoToc \authors Andreas Fabri and Laurent Rineau -Qt is a Gui toolkit for +Qt is a Gui toolkit for cross-platform application development. \section GraphicsViewIntroduction Introduction This chapter describes classes that help to visualize two dimensional \cgal objects -with the Qt Graphics View Framework. +with the Qt Graphics View Framework. -This framework uses the model view paradigm. `QGraphicsItem`s are stored in a -`QGraphicsScene` -and are displayed in a `QGraphicsView`. The items +This framework uses the model view paradigm. `QGraphicsItem`s are stored in a +`QGraphicsScene` +and are displayed in a `QGraphicsView`. The items have a paint method which is called when an item is in the visible area of a view. The framework is also responsible for dispatching events from the view via the scene to the items. The framework is extensible in the sense @@ -50,14 +50,14 @@ classes that have to override member functions adhering to this naming scheme. \section GraphicsViewOverall Overall Design In \cgalFigureRef{graphicsviewuml} you see four classes depicted in grey, -that come from the %Qt Graphics View Framework. The `QGraphicsScene` -contains `QGraphicsItem`s, which get displayed in any number -of `QGraphicsView`s. The views are widgets, that is they take screen space +that come from the %Qt Graphics View Framework. The `QGraphicsScene` +contains `QGraphicsItem`s, which get displayed in any number +of `QGraphicsView`s. The views are widgets, that is they take screen space in an application. -The fourth class is the `QObject`. It plays an important role in %Qt for -event handling and memory management. First, it allows to add signals and -slots, and to connect them. Second, it allows to install event filters. +The fourth class is the `QObject`. It plays an important role in %Qt for +event handling and memory management. First, it allows to add signals and +slots, and to connect them. Second, it allows to install event filters. \cgalFigureBegin{graphicsviewuml,uml-design.png} UML Class Diagram with the %Qt classes (blue), \cgal classes for using the framework (yellow), \cgal data structures (red), and application classes (green). @@ -68,8 +68,8 @@ UML Class Diagram with the %Qt classes (blue), \cgal classes for using the frame In order to visualize for example a `CGAL::Delaunay_triangulation_2`, we provide the graphics item class `CGAL::Qt::TriangulationGraphicsItem`. It provides a `paint` method that draws the edges and vertices of a triangulation -using the drawing primitives of the `QPainter`. The color of vertices and edges, -can be chosen by setting a user defined `QPen`. +using the drawing primitives of the `QPainter`. The color of vertices and edges, +can be chosen by setting a user defined `QPen`. As this graphics item only stores a pointer to a triangulation, it must be notified about changes like the insertion of points coming from diff --git a/GraphicsView/doc/GraphicsView/PackageDescription.txt b/GraphicsView/doc/GraphicsView/PackageDescription.txt index b95109777fc..dfbd2086c33 100644 --- a/GraphicsView/doc/GraphicsView/PackageDescription.txt +++ b/GraphicsView/doc/GraphicsView/PackageDescription.txt @@ -13,7 +13,7 @@ \cgalPkgPicture{detail.png} \cgalPkgSummaryBegin \cgalPkgAuthors{Andreas Fabri and Laurent Rineau} -\cgalPkgDesc{This package provides classes for displaying \cgal objects and data structures in the Qt 5 Graphics View Framework.} +\cgalPkgDesc{This package provides classes for displaying \cgal objects and data structures in the Qt 5 Graphics View Framework.} \cgalPkgManuals{Chapter_CGAL_and_the_Qt_Graphics_View_Framework,PkgGraphicsViewRef} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin @@ -26,7 +26,7 @@ This package provides some classes which allow to use \cgal classes in Qt applications which make use of the Qt Graphics +HREF="https://doc.qt.io/qt-6/graphicsview.html">Qt Graphics View Framework. \cgalClassifedRefPages 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/GraphicsView/include/CGAL/Qt/manipulatedFrame_impl.h b/GraphicsView/include/CGAL/Qt/manipulatedFrame_impl.h index c1cd449d001..7b807fc5e29 100644 --- a/GraphicsView/include/CGAL/Qt/manipulatedFrame_impl.h +++ b/GraphicsView/include/CGAL/Qt/manipulatedFrame_impl.h @@ -475,7 +475,7 @@ void ManipulatedFrame::wheelEvent(QWheelEvent *const event, //////////////////////////////////////////////////////////////////////////////// /*! Returns "pseudo-distance" from (x,y) to ball of radius size. -\arg for a point inside the ball, it is proportional to the euclidean distance +\arg for a point inside the ball, it is proportional to the Euclidean distance to the ball \arg for a point outside the ball, it is proportional to the inverse of this distance (tends to zero) on the ball, the function is continuous. */ static qreal projectOnBall(qreal x, qreal y) { diff --git a/GraphicsView/include/CGAL/Qt/qglviewer.h b/GraphicsView/include/CGAL/Qt/qglviewer.h index e24a5fcd6d7..673e9450980 100644 --- a/GraphicsView/include/CGAL/Qt/qglviewer.h +++ b/GraphicsView/include/CGAL/Qt/qglviewer.h @@ -34,6 +34,13 @@ #include #include +#ifndef APIENTRY +#define APIENTRY QT_APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + class QTabWidget; class QImage; class QOpenGLFramebufferObject; 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/TODO b/Hyperbolic_triangulation_2/TODO index f38377d2492..ad766691294 100644 --- a/Hyperbolic_triangulation_2/TODO +++ b/Hyperbolic_triangulation_2/TODO @@ -19,7 +19,7 @@ remove variant for supporting circle or line of bisector call it only when we know that it is a circle it will simplify the code of Construct_hyperbolic_bisector_2 at least in some cases -test bisectors dual functions in special cases of euclidean line segments +test bisectors dual functions in special cases of Euclidean line segments ** Hyperbolic_random_points_in_disc 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 ed6e884697b..a1caaaa7107 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -1,29 +1,83 @@ # Release History +## [Release 6.2](https://github.com/CGAL/cgal/releases/tag/v6.2) + +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: + - `import_from_plane_graph()` → `read_plane_graph_in_lcc()` + - `import_from_polyhedron_3()` → `polyhedron_3_to_lcc()` + - `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 + ### General Changes + +- The new list of supported compilers is: + - Visual C++ 15.9, 16.10, 17.0 (from Visual Studio 2017, 2019 and 2022) or later + - Gnu g++ 12.2.0 or later (on Linux) + - LLVM Clang version 20.1.6 or later (on Linux) + - Apple Clang compiler versions 12.0.5 and 12.0.5 (on macOS) - The minimal supported version of Boost is now 1.74.0. -### [dD Fréchet Distance](https://doc.cgal.org/6.1/Manual/packages.html#FrechetDistance) (new package) -- This package provides functions for computing the Fréchet distance of polylines in any dimension under the Euclidean metric. - ### [3D Constrained Triangulations](https://doc.cgal.org/6.1/Manual/packages.html#PkgConstrainedTriangulation3) (new package) -- This package adds the function `CGAL::make_conforming_constrained_Delaunay_triangulation_3()` - to create a conforming constrained Delaunay triangulation in 3D, which can be represented by the new - class template `CGAL::Conforming_constrained_Delaunay_triangulation_3`. -### 2D Triangulations on Hyperbolic Surfaces (new package) +- This package implements the construction of a 3D Constrained Delaunay triangulation. + This triangulation is a generalization of a 3D Delaunay Triangulation which conforms to + the set of faces of a 3D piecewise linear complex (PLC), ensuring that these faces are + part of the triangulation. As not all PLCs are tetrahedralizable, the algorithm may + insert Steiner points to construct the constrained triangulation. + The main entry point is the function + [`CGAL::make_conforming_constrained_Delaunay_triangulation_3()`](https://doc.cgal.org/6.1/Constrained_triangulation_3/group__PkgConstrainedTriangulation3FunctionsPolygonSoupOrMesh.html). + +### [3D Isosurfacing](https://doc.cgal.org/6.1/Manual/packages.html#PkgIsosurfacing3) (new package) + +- This package provides algorithms to extract isosurfaces from scalar fields. + The algorithms provided in this first version include Marching Cubes, Topologically Correct + Marching Cubes, and Dual Contouring. The algorithm is generic with respect to the scalar field + representation (implicit function, discrete values, ...) and the discretization data structure + (Cartesian grid, octree, ...). The output is an indexed face set that stores an isosurface in the + form of a surface mesh. + +### [dD Fréchet Distance](https://doc.cgal.org/6.1/Manual/packages.html#PkgFrechetDistance) (new package) + +- This package provides functions for computing the Fréchet distance of polylines + in any dimension under the Euclidean metric. + +### [2D Triangulations on Hyperbolic Surfaces](https://doc.cgal.org/6.1/Manual/packages.html#PkgHyperbolicSurfaceTriangulation2) (new package) + - This package enables building and handling triangulations of closed orientable hyperbolic surfaces. It offers functions for the generation of the triangulation from a convex fundamental domain, - the Delaunay flip algorithm and the construction of a portion of the lift of the triangulation + the Delaunay flip algorithm, and the construction of a portion of the lift of the triangulation in the Poincaré disk. A method is offered that generates such domains in genus two. + 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 + 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. @@ -39,7 +93,6 @@ - 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. -- Added the parameter `apply_iterative_snap_rounding` to the function `CGAL::Polygon_mesh_processing::autorefine_triangle_soup()`. When set to `true`, the coordinates are rounded to fit in double and may perform additional subdivisions to ensure the output is free of self-intersections. ### [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. @@ -60,6 +113,9 @@ - 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) @@ -85,21 +141,123 @@ ### [Polygon Repair](https://doc.cgal.org/6.1/Manual/packages.html#PkgPolygonRepair) -- Add a the non-zero rule, as well as functions to compute the conservative inner and outer hull of similar polygons. +- Added the [non-zero rule](https://doc.cgal.org/6.1/Polygon_repair/structCGAL_1_1Polygon__repair_1_1Non__zero__rule.html) + (areas with non-zero winding number are kept), as well as two functions to compute the + conservative inner and outer hull of similar polygons: + - [`CGAL::Polygon_repair::join()`](https://doc.cgal.org/6.1/Polygon_repair/group__PkgPolygonRepairFunctions.html#gad5b959666d952392c0e3b8d4b1b1847a) + - [`CGAL::Polygon_repair::intersect()`](https://doc.cgal.org/6.1/Polygon_repair/group__PkgPolygonRepairFunctions.html#ga780e31115643e3d0b406349b56c9f3d5) -### Triangulations -- All triangulations now offer the functions `point(Vertex_handle)` and `point(Simplex, int)`, which enables users to access the geometric position of a vertex and of the i-th vertex of a simplex of a triangulation. + See also the associated [news entry](https://www.cgal.org/2025/05/22/Polygon_repair/). +### [Polygon Mesh Processing](https://doc.cgal.org/6.1/Manual/packages.html#PkgPolygonMeshProcessing) +- Added the parameter `apply_iterative_snap_rounding` to the function + [`CGAL::Polygon_mesh_processing::autorefine_triangle_soup()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__corefinement__grp.html#gaf7747d676c459d9e5da9b13be7d12bb5). + When set to `true`, the coordinates are rounded to fit in double and may perform additional + subdivisions to ensure the output is free of self-intersections. + See also the associated [news entry](https://www.cgal.org/2025/06/13/autorefine-and-snap/). +- Added the function [`CGAL::Polygon_mesh_processing::approximated_centroidal_Voronoi_diagram_remeshing()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PkgPolygonMeshProcessingRef.html#gaed23e63b12c7fe8268927d17b4d379f1) + 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. + See also the associated [news entry](https://www.cgal.org/2025/05/22/Surface_remeshing/). +- New implementation of [`CGAL::Polygon_mesh_processing::clip()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__corefinement__grp.html#ga2c73d3460872e601f84a03f58dd069ae) + and [`CGAL::Polygon_mesh_processing::split()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__corefinement__grp.html#ga6738052411a4d548a5b375f11b913924) + with a plane as clipper that is much faster and is now able to handle non-triangulated surface meshes. + See also the associated [news entry](https://www.cgal.org/2025/06/06/new_clip/). +- Added the function [`CGAL::Polygon_mesh_processing::refine_with_plane()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__corefinement__grp.html#gacb9d68fa4dea8fd03ec53b56a16d6fc6), + which enables users to refine a mesh with its intersection with a plane. +- Added a function in the [visitor of the corefinement based methods](https://doc.cgal.org/6.1/Polygon_mesh_processing/classPMPCorefinementVisitor.html) + to trace faces in the output meshes which correspond to coplanar faces of the input. +- Added the function [`CGAL::Polygon_mesh_processing::discrete_mean_curvature()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__measure__grp.html#ga1a31fa9412b4643dc7202a54246db78b) + and [`CGAL::Polygon_mesh_processing::discrete_Gaussian_curvature()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__measure__grp.html#ga11a2d646d4636605d185653bff5bbbbb) + to evaluate the discrete curvature at a vertex of a mesh. +- Added the function [`CGAL::Polygon_mesh_processing::angle_sum()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__measure__grp.html#ga25d3836c21931610cf76b6716a06254c) + to compute the sum of the angles around a vertex. + +### [Point Set Processing](https://doc.cgal.org/6.1/Manual/packages.html#PkgPointSetProcessing3) + +- Added [`CGAL::poisson_eliminate()`](https://doc.cgal.org/6.1/Point_set_processing_3/group__PkgPointSetProcessing3Algorithms.html#ga2d73d46ca766656a219bf5e6045b837a), + which can be used to downsample a point cloud to a target size while providing Poisson disk property, + i.e., a larger minimal distance between points. ### [CGAL and the Boost Graph Library (BGL)](https://doc.cgal.org/6.1/Manual/packages.html#PkgBGL) -- Added the function `dijkstra_shortest_path()` which computes the geometrically shortest sequence of halfedges between two vertices. +- Added the function [`dijkstra_shortest_path()`](https://doc.cgal.org/6.1/BGL/group__PkgBGLTraversal.html#gaa4058482db0089886b84a8c6a341e528), + which can be used to compute the geometrically shortest sequence of halfedges between two vertices. +- Added the function [`CGAL::Euler::remove_degree_2_vertex()`](https://doc.cgal.org/6.1/BGL/group__PkgBGLEulerOperations.html#gab3455663b7db4624529e54ae3ce2387c), + which enables users to remove vertices which have exactly two incident edges. + +### [2D Arrangements](https://doc.cgal.org/6.1/Manual/packages.html#PkgArrangementOnSurface2) + +- **Breaking change**: Renamed the concept `AosApproximateTraits_2` to [`AosApproximatePointTraits_2`](https://doc.cgal.org/6.1/Arrangement_on_surface_2/classAosApproximatePointTraits__2.html) + to make room for the new concept [`AosApproximateTraits_2`](https://doc.cgal.org/6.1/Arrangement_on_surface_2/classAosApproximateTraits__2.html). + This concept requires the provision of a functor called `Approximate_2` that has an operator + that approximates the coordinates of a point. +- **Breaking change**: The concept [`AosApproximateTraits_2`](https://doc.cgal.org/6.1/Arrangement_on_surface_2/classAosApproximateTraits__2.html) + now refines the concept [`AosApproximatePointTraits_2`](https://doc.cgal.org/6.1/Arrangement_on_surface_2/classAosApproximatePointTraits__2.html) + and 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. +- Renamed the prefix of the names of all concepts in the Arrangement_on_surface_2 package from "Arrangement" to "Aos". +- Introduced two traits decorators, namely [`CGAL::Arr_tracing_traits_2`](https://doc.cgal.org/6.1/Arrangement_on_surface_2/classCGAL_1_1Arr__tracing__traits__2.html) + and [`CGAL::Arr_counting_traits_2`](https://doc.cgal.org/6.1/Arrangement_on_surface_2/classCGAL_1_1Arr__counting__traits__2.html), + 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. +- Fixed `do_intersect()` of a 2D Arrangement with a curve. + +### Triangulations +- All triangulations now offer the functions `point(Vertex_handle)` and `point(Simplex, int)`, + which enables users to access the geometric position of a vertex and of the i-th vertex + of a simplex of a triangulation. + +### [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. + +### [2D Triangulations](https://doc.cgal.org/6.1/Manual/packages.html#PkgTriangulation2) + +- **Breaking change**: In the class template [`Constrained_triangulation_plus_2`](https://doc.cgal.org/6.1/Triangulation_2/classCGAL_1_1Constrained__triangulation__plus__2.html), + the value type of the range returned by [`subconstraints()`](https://doc.cgal.org/6.1/Triangulation_2/classCGAL_1_1Constrained__triangulation__plus__2.html#af25114a7e1675194367f8f9de9de90d2) + has changed from `const std::pair*>` to `Subconstraint`. + The old range type is now returned by a new function named `subconstraints_and_contexts()`. + +### [3D Mesh Generation](https://doc.cgal.org/6.1/Manual/packages.html#PkgMesh3) + +- Added two new meshing parameters that enable custom mesh initialization: + - [`initial_points_generator`](https://doc.cgal.org/6.1/Mesh_3/group__PkgMesh3Parameters.html#gaf53777b83f1b2f3e7d49275dbab6e46b): + enables the user to specify a functor that generates initial points, + - [`initial_points`](https://doc.cgal.org/6.1/Mesh_3/group__PkgMesh3Parameters.html#gaf26d164d1845dcd66dc4861b6920b5ec): + enables the user to specify a `Range` of initial points. +- Added a new meshing parameter [`surface_only`](https://doc.cgal.org/6.1/Mesh_3/group__PkgMesh3Parameters.html#gaa2618c09b6117d7caab12dccca16ee58), + which can be used to improve performance when only surface mesh generation is sought. +- Added a new mesh domain [`Poisson_mesh_domain_3`](https://doc.cgal.org/6.1/Poisson_surface_reconstruction_3/classCGAL_1_1Poisson__mesh__domain__3.html), + which should be used when generating a mesh from a Poisson surface + obtained with the package [Poisson Surface Reconstruction](https://doc.cgal.org/6.1/Manual/packages.html#PkgPoissonSurfaceReconstruction3). + This mesh domain re-integrates some optimizations for Poisson surface mesh generation that were lost + when the package [3D Mesh Generation](https://doc.cgal.org/6.1/Manual/packages.html#PkgMesh3) had to be replaced instead of the deprecated package [3D Surface Mesh Generation](https://doc.cgal.org/latest/Manual/packages.html#PkgSurfaceMesher3). + +### [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()`](https://doc.cgal.org/6.1/Subdivision_method_3/group__PkgSurfaceSubdivisionMethod3Functions.html#gafa1e441c4e07eb06e1f6efecef7ff268) + and [`CGAL::Subdivision_method_3::CatmullClark_subdivision()`](https://doc.cgal.org/6.1/Subdivision_method_3/group__PkgSurfaceSubdivisionMethod3Functions.html#ga8e6c8dd3c26d7a27c070b3a091684679), + which enables users to subdivide a mesh without modifying its geometry. + +### [Algebraic Kernel](https://doc.cgal.org/6.1/Manual/packages.html#PkgAlgebraicKernelD) + +- **Breaking change**: Classes based on the RS Library are no longer provided. + ## [Release 6.0.1](https://github.com/CGAL/cgal/releases/tag/v6.0.1) +Release date: October 2024 + ### [Poisson Surface Reconstruction](https://doc.cgal.org/6.0.1/Manual/packages.html#PkgPoissonSurfaceReconstruction3) -- Made the implicit function thread-safe so that the parallel version of `make_mesh_3()` can be used. + +- Made the implicit function thread-safe so that the parallel version of [`CGAL::make_mesh_3()`](https://doc.cgal.org/6.0.1/Mesh_3/group__PkgMesh3Functions.html#gac8599a0c967075f740bf8e2e92c4770e) + can be used. + ## [Release 6.0](https://github.com/CGAL/cgal/releases/tag/v6.0) diff --git a/Installation/CMakeLists.txt b/Installation/CMakeLists.txt index 2aba88233d3..5eb6bc64231 100644 --- a/Installation/CMakeLists.txt +++ b/Installation/CMakeLists.txt @@ -970,19 +970,6 @@ ${CGAL_3RD_PARTY_DEFINITIONS} ${CGAL_Qt6_3RD_PARTY_DEFINITIONS} \ ${CGAL_DEFINITIONS}" -std=c++17) message("COMPILATION OPTIONS ARE : ${compile_options}") - if(NOT RS_FOUND AND NOT RS3_FOUND) - set(compile_options - "${compile_options} \ --DCGAL_ALGEBRAIC_KERNEL_RS_GMPZ_D_1=1 \ --DCGAL_ALGEBRAIC_KERNEL_RS_GMPQ_D_1=1") - message(STATUS "Skip RS headers \"CGAL/Algebraic_kernel_rs_gmpq_d_1.h\" \ -and \"CGAL/Algebraic_kernel_rs_gmpz_d_1.h\" because RS_FOUND is false.") - else() - set(compile_options - "${compile_options} \ --DCGAL_USE_MPFI=1 \ --DCGAL_USE_RS=1") - endif() if(NOT OpenMesh_FOUND) set(compile_options "${compile_options} \ @@ -1163,16 +1150,12 @@ LEDA_FOUND is false.") CMD UNIX_COMMAND "${CMAKE_CXX_COMPILER} ${compile_options_str} ${include_options_str} -x c++ ${flag} -H \ ${CMAKE_CURRENT_SOURCE_DIR}/../${package}/include/${header}" - # The header Algebraic_kernel_rs_gmpz_d_1.h is skipped on purpose: it - # depends on RS. ) # CMD2 is CMD without the -H option separate_arguments( CMD2 UNIX_COMMAND "${CMAKE_CXX_COMPILER} ${compile_options_str} ${include_options_str} -x c++ ${flag} \ ${CMAKE_CURRENT_SOURCE_DIR}/../${package}/include/${header}" - # The header Algebraic_kernel_rs_gmpz_d_1.h is skipped on purpose: it - # depends on RS. ) set(chk_header_name ${CGAL_BINARY_DIR}/package_info/${package}/check_headers/check_${header2} diff --git a/Installation/cmake/modules/CGALHelpers.cmake b/Installation/cmake/modules/CGALHelpers.cmake index de42f8cf269..957371769bd 100644 --- a/Installation/cmake/modules/CGALHelpers.cmake +++ b/Installation/cmake/modules/CGALHelpers.cmake @@ -9,7 +9,7 @@ function(process_CGAL_subdirectory entry subdir type_name) make_directory("${CMAKE_BINARY_DIR}/${subdir}/${ENTRY_DIR_NAME}") endif() - message("\n-- Configuring ${subdir} in ${subdir}/${ENTRY_DIR_NAME}") + message("-- Configuring ${subdir} in ${subdir}/${ENTRY_DIR_NAME}") set(source_dir "") if(EXISTS ${entry}/CMakeLists.txt) @@ -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/CGAL_pointmatcher_support.cmake b/Installation/cmake/modules/CGAL_pointmatcher_support.cmake index 16650ba6d9c..a4f823cdddc 100644 --- a/Installation/cmake/modules/CGAL_pointmatcher_support.cmake +++ b/Installation/cmake/modules/CGAL_pointmatcher_support.cmake @@ -1,16 +1,15 @@ if(libpointmatcher_FOUND AND NOT TARGET CGAL::pointmatcher_support) if (libpointmatcher_VERSION VERSION_GREATER_EQUAL "1.4.4") - find_package(Boost COMPONENTS thread system program_options date_time chrono) + find_package(Boost COMPONENTS thread program_options date_time chrono) else() find_package(Boost COMPONENTS thread filesystem system program_options date_time chrono) endif() if(Boost_chrono_FOUND AND Boost_thread_FOUND - AND Boost_system_FOUND AND Boost_program_options_FOUND AND Boost_date_time_FOUND - AND (libpointmatcher_VERSION VERSION_GREATER_EQUAL "1.4.4" OR Boost_filesystem_FOUND)) + AND (libpointmatcher_VERSION VERSION_GREATER_EQUAL "1.4.4" OR (Boost_filesystem_FOUND AND Boost_system_FOUND))) add_library(CGAL::pointmatcher_support INTERFACE IMPORTED) target_compile_options(CGAL::pointmatcher_support INTERFACE "-D_USE_MATH_DEFINES") target_compile_definitions(CGAL::pointmatcher_support INTERFACE "CGAL_LINKED_WITH_POINTMATCHER") @@ -18,7 +17,7 @@ if(libpointmatcher_FOUND AND NOT TARGET CGAL::pointmatcher_support) target_link_libraries(CGAL::pointmatcher_support INTERFACE ${libpointmatcher_LIBRARIES} libnabo::nabo) else() if (libpointmatcher_VERSION VERSION_GREATER_EQUAL "1.4.4") - message(STATUS "NOTICE: the libpointmatcher library requires the following boost components: thread system program_options date_time chrono.") + message(STATUS "NOTICE: the libpointmatcher library requires the following boost components: thread program_options date_time chrono.") else() message(STATUS "NOTICE: the libpointmatcher library requires the following boost components: thread filesystem system program_options date_time chrono.") endif() 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/Installation/demo/CMakeLists.txt b/Installation/demo/CMakeLists.txt index 92606a5b9d2..9bf4e2e9e0e 100644 --- a/Installation/demo/CMakeLists.txt +++ b/Installation/demo/CMakeLists.txt @@ -1,7 +1,15 @@ cmake_minimum_required(VERSION 3.12...3.31) +project(CGAL_Demos) -if(NOT CGAL_MODULES_DIR) - find_package(CGAL REQUIRED) -endif() -include(${CGAL_MODULES_DIR}/CGALHelpers.cmake) -CGAL_handle_subdirectories(demo demos) +file(GLOB pkgs RELATIVE ${CMAKE_SOURCE_DIR} "*") +list(SORT pkgs) + +message("== Generating build files for demos ==") +foreach(pkg ${pkgs}) + set(pkg_dir ${CMAKE_SOURCE_DIR}/${pkg}) + if(IS_DIRECTORY "${pkg_dir}" AND EXISTS "${pkg_dir}/CMakeLists.txt") + message("\n-- Configuring ${pkg}") + add_subdirectory(${pkg_dir} "${CMAKE_BINARY_DIR}/${pkg}") + endif() +endforeach() +message("== Generating build files for done (DONE) ==") diff --git a/Installation/examples/CMakeLists.txt b/Installation/examples/CMakeLists.txt index e0034b4727f..f96a030628d 100644 --- a/Installation/examples/CMakeLists.txt +++ b/Installation/examples/CMakeLists.txt @@ -1,6 +1,15 @@ cmake_minimum_required(VERSION 3.12...3.31) -if(NOT CGAL_MODULES_DIR) - find_package(CGAL REQUIRED) -endif() -include(${CGAL_MODULES_DIR}/CGALHelpers.cmake) -CGAL_handle_subdirectories(examples examples) +project(CGAL_Examples) + +file(GLOB pkgs RELATIVE ${CMAKE_SOURCE_DIR} "*") +list(SORT pkgs) + +message("== Generating build files for examples ==") +foreach(pkg ${pkgs}) + set(pkg_dir ${CMAKE_SOURCE_DIR}/${pkg}) + if(IS_DIRECTORY "${pkg_dir}" AND EXISTS "${pkg_dir}/CMakeLists.txt") + message("\n-- Configuring ${pkg}") + add_subdirectory(${pkg_dir} "${CMAKE_BINARY_DIR}/${pkg}") + endif() +endforeach() +message("== Generating build files for done (DONE) ==") diff --git a/Installation/include/CGAL/license/Frechet_distance.h b/Installation/include/CGAL/license/Frechet_distance.h index 80af43ef22c..0ad83f173bf 100644 --- a/Installation/include/CGAL/license/Frechet_distance.h +++ b/Installation/include/CGAL/license/Frechet_distance.h @@ -24,12 +24,12 @@ # if defined(CGAL_LICENSE_WARNING) CGAL_pragma_warning("Your commercial license for CGAL does not cover " - "this release of the Frechet Distances package.") + "this release of the dD Frechet Distance package.") # endif # ifdef CGAL_LICENSE_ERROR # error "Your commercial license for CGAL does not cover this release \ - of the dD Frechet Distances package. \ + of the dD Frechet Distance package. \ You get this error, as you defined CGAL_LICENSE_ERROR." # endif // CGAL_LICENSE_ERROR @@ -39,13 +39,13 @@ # if defined(CGAL_LICENSE_WARNING) CGAL_pragma_warning("\nThe macro CGAL_FRECHET_DISTANCE_COMMERCIAL_LICENSE is not defined." - "\nYou use the CGAL Polyline Distances package under " + "\nYou use the CGAL dD Frechet Distance package under " "the terms of the GPLv3+.") # endif // CGAL_LICENSE_WARNING # ifdef CGAL_LICENSE_ERROR # error "The macro CGAL_FRECHET_DISTANCE_COMMERCIAL_LICENSE is not defined.\ - You use the CGAL Polyline Distances package under the terms of \ + You use the CGAL dD Frechet Distance package under the terms of \ the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR." # endif // CGAL_LICENSE_ERROR diff --git a/Installation/include/CGAL/license/Heat_method_3.h b/Installation/include/CGAL/license/Heat_method_3.h index 8e02b59f24a..579d5bca179 100644 --- a/Installation/include/CGAL/license/Heat_method_3.h +++ b/Installation/include/CGAL/license/Heat_method_3.h @@ -11,16 +11,12 @@ // // Warning: this file is generated, see include/CGAL/license/README.md - #ifndef CGAL_LICENSE_HEAT_METHOD_3_H #define CGAL_LICENSE_HEAT_METHOD_3_H #include #include - - - #ifdef CGAL_HEAT_METHOD_3_COMMERCIAL_LICENSE # if CGAL_HEAT_METHOD_3_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE @@ -33,8 +29,8 @@ # ifdef CGAL_LICENSE_ERROR # error "Your commercial license for CGAL does not cover this release \ -of the 3D Heat Method package. \ -You get this error, as you defined CGAL_LICENSE_ERROR." + of the 3D Heat Method package. \ + You get this error, as you defined CGAL_LICENSE_ERROR." # endif // CGAL_LICENSE_ERROR # endif // CGAL_HEAT_METHOD_3_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE @@ -49,10 +45,10 @@ You get this error, as you defined CGAL_LICENSE_ERROR." # ifdef CGAL_LICENSE_ERROR # error "The macro CGAL_HEAT_METHOD_3_COMMERCIAL_LICENSE is not defined.\ - You use the CGAL 3D Heat Method package under the terms of \ -the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR." + You use the CGAL 3D Heat Method package under the terms of \ + the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR." # endif // CGAL_LICENSE_ERROR #endif // no CGAL_HEAT_METHOD_3_COMMERCIAL_LICENSE -#endif // CGAL_LICENSE_CHECK_HEAT_METHOD_3_H +#endif // CGAL_LICENSE_HEAT_METHOD_3_H diff --git a/Installation/include/CGAL/license/Isosurfacing_3.h b/Installation/include/CGAL/license/Isosurfacing_3.h index 345fae13a82..dcf0ef11aa4 100644 --- a/Installation/include/CGAL/license/Isosurfacing_3.h +++ b/Installation/include/CGAL/license/Isosurfacing_3.h @@ -9,7 +9,7 @@ // // Author(s) : Andreas Fabri // -// Warning: this file is generated, see include/CGAL/licence/README.md +// Warning: this file is generated, see include/CGAL/license/README.md #ifndef CGAL_LICENSE_ISOSURFACING_3_H #define CGAL_LICENSE_ISOSURFACING_3_H diff --git a/Installation/include/CGAL/license/Polygon_mesh_processing/Polyhedral_envelope.h b/Installation/include/CGAL/license/Polygon_mesh_processing/Polyhedral_envelope.h index a03dc32b4fc..13a34245bbf 100644 --- a/Installation/include/CGAL/license/Polygon_mesh_processing/Polyhedral_envelope.h +++ b/Installation/include/CGAL/license/Polygon_mesh_processing/Polyhedral_envelope.h @@ -24,12 +24,12 @@ # if defined(CGAL_LICENSE_WARNING) CGAL_pragma_warning("Your commercial license for CGAL does not cover " - "this release of the Polygon Mesh Processing - Polyhedral envelope package.") + "this release of the Polygon Mesh Processing - Polyhedral Envelope package.") # endif # ifdef CGAL_LICENSE_ERROR # error "Your commercial license for CGAL does not cover this release \ - of the Polygon Mesh Processing - Polyhedral envelope package. \ + of the Polygon Mesh Processing - Polyhedral Envelope package. \ You get this error, as you defined CGAL_LICENSE_ERROR." # endif // CGAL_LICENSE_ERROR @@ -39,16 +39,16 @@ # if defined(CGAL_LICENSE_WARNING) CGAL_pragma_warning("\nThe macro CGAL_POLYGON_MESH_PROCESSING_POLYHEDRAL_ENVELOPE_COMMERCIAL_LICENSE is not defined." - "\nYou use the CGAL Polygon Mesh Processing - Polyhedral envelope package under " + "\nYou use the CGAL Polygon Mesh Processing - Polyhedral Envelope package under " "the terms of the GPLv3+.") # endif // CGAL_LICENSE_WARNING # ifdef CGAL_LICENSE_ERROR # error "The macro CGAL_POLYGON_MESH_PROCESSING_POLYHEDRAL_ENVELOPE_COMMERCIAL_LICENSE is not defined.\ - You use the CGAL Polygon Mesh Processing - Polyhedral envelope package under the terms of \ + You use the CGAL Polygon Mesh Processing - Polyhedral Envelope package under the terms of \ the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR." # endif // CGAL_LICENSE_ERROR -#endif // no CGAL_POLYGON_MESH_PROCESSING_ENVELOPE_COMMERCIAL_LICENSE +#endif // no CGAL_POLYGON_MESH_PROCESSING_POLYHEDRAL_ENVELOPE_COMMERCIAL_LICENSE #endif // CGAL_LICENSE_POLYGON_MESH_PROCESSING_POLYHEDRAL_ENVELOPE_H diff --git a/Installation/include/CGAL/license/Polygon_mesh_processing/locate.h b/Installation/include/CGAL/license/Polygon_mesh_processing/locate.h index 854b366ba54..ebd2bf82ac4 100644 --- a/Installation/include/CGAL/license/Polygon_mesh_processing/locate.h +++ b/Installation/include/CGAL/license/Polygon_mesh_processing/locate.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 GeometryFactory SARL (France). +// Copyright (c) 2016 GeometryFactory SARL (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org) @@ -38,9 +38,9 @@ #else // no CGAL_POLYGON_MESH_PROCESSING_LOCATE_COMMERCIAL_LICENSE # if defined(CGAL_LICENSE_WARNING) - CGAL_pragma_warning("\nThe macro CGAL_POLYGON_MESH_PROCESSING_LOCATE_COMMERCIAL_LICENSE is not defined." - "\nYou use the CGAL Polygon Mesh Processing - Locate package under " - "the terms of the GPLv3+.") + CGAL_pragma_warning("\nThe macro CGAL_POLYGON_MESH_PROCESSING_LOCATE_COMMERCIAL_LICENSE is not defined." + "\nYou use the CGAL Polygon Mesh Processing - Locate package under " + "the terms of the GPLv3+.") # endif // CGAL_LICENSE_WARNING # ifdef CGAL_LICENSE_ERROR @@ -51,4 +51,4 @@ #endif // no CGAL_POLYGON_MESH_PROCESSING_LOCATE_COMMERCIAL_LICENSE -#endif // CGAL_LICENSE_CHECK_POLYGON_MESH_PROCESSING_LOCATE_H +#endif // CGAL_LICENSE_POLYGON_MESH_PROCESSING_LOCATE_H diff --git a/Installation/include/CGAL/license/Polygonal_surface_reconstruction.h b/Installation/include/CGAL/license/Polygonal_surface_reconstruction.h index 73f59580778..04e1917e060 100644 --- a/Installation/include/CGAL/license/Polygonal_surface_reconstruction.h +++ b/Installation/include/CGAL/license/Polygonal_surface_reconstruction.h @@ -11,16 +11,12 @@ // // Warning: this file is generated, see include/CGAL/license/README.md - #ifndef CGAL_LICENSE_POLYGONAL_SURFACE_RECONSTRUCTION_H #define CGAL_LICENSE_POLYGONAL_SURFACE_RECONSTRUCTION_H #include #include - - - #ifdef CGAL_POLYGONAL_SURFACE_RECONSTRUCTION_COMMERCIAL_LICENSE # if CGAL_POLYGONAL_SURFACE_RECONSTRUCTION_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE @@ -33,8 +29,8 @@ # ifdef CGAL_LICENSE_ERROR # error "Your commercial license for CGAL does not cover this release \ -of the Polygonal Surface Reconstruction package. \ -You get this error, as you defined CGAL_LICENSE_ERROR." + of the Polygonal Surface Reconstruction package. \ + You get this error, as you defined CGAL_LICENSE_ERROR." # endif // CGAL_LICENSE_ERROR # endif // CGAL_POLYGONAL_SURFACE_RECONSTRUCTION_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE @@ -49,10 +45,10 @@ You get this error, as you defined CGAL_LICENSE_ERROR." # ifdef CGAL_LICENSE_ERROR # error "The macro CGAL_POLYGONAL_SURFACE_RECONSTRUCTION_COMMERCIAL_LICENSE is not defined.\ - You use the CGAL Polygonal Surface Reconstruction package under the terms of \ -the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR." + You use the CGAL Polygonal Surface Reconstruction package under the terms of \ + the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR." # endif // CGAL_LICENSE_ERROR #endif // no CGAL_POLYGONAL_SURFACE_RECONSTRUCTION_COMMERCIAL_LICENSE -#endif // CGAL_LICENSE_CHECK_POLYGONAL_SURFACE_RECONSTRUCTION_H +#endif // CGAL_LICENSE_POLYGONAL_SURFACE_RECONSTRUCTION_H diff --git a/Installation/include/CGAL/license/gpl_package_list.txt b/Installation/include/CGAL/license/gpl_package_list.txt index 6fd1d5b9b42..791271f4ac9 100644 --- a/Installation/include/CGAL/license/gpl_package_list.txt +++ b/Installation/include/CGAL/license/gpl_package_list.txt @@ -20,7 +20,7 @@ Convex_hull_3 3D Convex Hulls Convex_hull_d dD Convex Hulls and Delaunay Triangulations Envelope_2 2D Envelopes Envelope_3 3D Envelopes -Frechet_distance dD Fréchet Distance +Frechet_distance dD Frechet Distance GraphicsView CGAL and the Qt Graphics View Framework Heat_method_3 3D Heat Method Hyperbolic_triangulation_2 2D Hyperbolic Delaunay Triangulations diff --git a/Installation/include/CGAL/version.h b/Installation/include/CGAL/version.h index 57c2faa11bc..02e637c7fad 100644 --- a/Installation/include/CGAL/version.h +++ b/Installation/include/CGAL/version.h @@ -17,12 +17,12 @@ #define CGAL_VERSION_H #ifndef SWIG -#define CGAL_VERSION 6.1-dev +#define CGAL_VERSION 6.2-dev #define CGAL_GIT_HASH abcdef #endif -#define CGAL_VERSION_NR 1060100900 +#define CGAL_VERSION_NR 1060200900 #define CGAL_SVN_REVISION 99999 -#define CGAL_RELEASE_DATE 20241130 +#define CGAL_RELEASE_DATE 20260401 #include diff --git a/Installation/lib/cmake/CGAL/CGALConfigVersion.cmake b/Installation/lib/cmake/CGAL/CGALConfigVersion.cmake index d634917b94b..bcc4c96fb78 100644 --- a/Installation/lib/cmake/CGAL/CGALConfigVersion.cmake +++ b/Installation/lib/cmake/CGAL/CGALConfigVersion.cmake @@ -1,8 +1,8 @@ set(CGAL_MAJOR_VERSION 6) -set(CGAL_MINOR_VERSION 1) +set(CGAL_MINOR_VERSION 2) set(CGAL_BUGFIX_VERSION 0) include(${CMAKE_CURRENT_LIST_DIR}/CGALConfigBuildVersion.cmake) -set(CGAL_VERSION_PUBLIC_RELEASE_VERSION "6.1-dev") +set(CGAL_VERSION_PUBLIC_RELEASE_VERSION "6.2-dev") set(CGAL_VERSION_PUBLIC_RELEASE_NAME "CGAL-${CGAL_VERSION_PUBLIC_RELEASE_VERSION}") if (CGAL_BUGFIX_VERSION AND CGAL_BUGFIX_VERSION GREATER 0) diff --git a/Installation/test/CMakeLists.txt b/Installation/test/CMakeLists.txt index 64d616edd57..183796527e1 100644 --- a/Installation/test/CMakeLists.txt +++ b/Installation/test/CMakeLists.txt @@ -1,8 +1,15 @@ cmake_minimum_required(VERSION 3.12...3.31) +project(CGAL_Tests) +file(GLOB pkgs RELATIVE ${CMAKE_SOURCE_DIR} "*") +list(SORT pkgs) -if(NOT CGAL_MODULES_DIR) - find_package(CGAL REQUIRED) -endif() -include(${CGAL_MODULES_DIR}/CGALHelpers.cmake) -CGAL_handle_subdirectories(test tests) +message("== Generating build files for tests ==") +foreach(pkg ${pkgs}) + set(pkg_dir ${CMAKE_SOURCE_DIR}/${pkg}) + if(IS_DIRECTORY "${pkg_dir}" AND EXISTS "${pkg_dir}/CMakeLists.txt") + message("\n-- Configuring ${pkg}") + add_subdirectory(${pkg_dir} "${CMAKE_BINARY_DIR}/${pkg}") + endif() +endforeach() +message("== Generating build files for done (DONE) ==") 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/Direction_2.h b/Kernel_23/doc/Kernel_23/CGAL/Direction_2.h index d3b7554e272..89c3d787b3b 100644 --- a/Kernel_23/doc/Kernel_23/CGAL/Direction_2.h +++ b/Kernel_23/doc/Kernel_23/CGAL/Direction_2.h @@ -61,7 +61,7 @@ Direction_2(const Kernel::RT &x, const Kernel::RT &y); /// @{ /*! -returns values, such that `d``== Direction_2(delta(0),delta(1))`. +returns values, such that `d == Direction_2(delta(0),delta(1))`. \pre `0 <= i <= 1`. \cgalEpicExact diff --git a/Kernel_23/doc/Kernel_23/CGAL/Direction_3.h b/Kernel_23/doc/Kernel_23/CGAL/Direction_3.h index bf623b6a900..b68dd5d0d7e 100644 --- a/Kernel_23/doc/Kernel_23/CGAL/Direction_3.h +++ b/Kernel_23/doc/Kernel_23/CGAL/Direction_3.h @@ -58,7 +58,7 @@ Direction_3(const Kernel::RT &x, const Kernel::RT &y, const Kernel::RT &z); /// @{ /*! -returns values, such that `d``== Direction_3(delta(0),delta(1),delta(2))`. +returns values, such that `d == Direction_3(delta(0),delta(1),delta(2))`. \pre `0 <= i <= 2`. \cgalEpicExact 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 b59b2f8560d..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 @@ -89,6 +89,44 @@ double operator[](int i)const; Cartesian_const_iterator_d cartesian_begin()const; /*! returns an iterator pointing beyond the last %Cartesian coordinate. */ Cartesian_const_iterator_d cartesian_end()const; + +/*! returns whether the points coincide. */ +friend bool operator==(Point_d,Point_d); +/*! returns whether the points are distinct. */ +friend bool operator!=(Point_d,Point_d); +}; + +/*! +represents a vector in the Euclidean space +\cgalModels{DefaultConstructible,Assignable} +*/ +class Vector_d { +public: +/*! introduces a vector with coordinates (x0, x1, ...) where the number of + coordinates matches the dimension. + \pre `DimensionTag` is a fixed dimension, not `Dynamic_dimension_tag`. */ +Vector_d(double x0, double x1, ...); + +/*! introduces a vector with coordinate set `[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 +Vector_d(ForwardIterator first, ForwardIterator end); + +/*! returns the i-th coordinate of a vector. + \pre `i` is non-negative and less than the dimension. */ +double operator[](int i)const; + +/*! returns an iterator pointing to the zeroth %Cartesian coordinate. */ +Cartesian_const_iterator_d cartesian_begin()const; +/*! returns an iterator pointing beyond the last %Cartesian coordinate. */ +Cartesian_const_iterator_d cartesian_end()const; + +/*! returns whether the vectors coincide. */ +friend bool operator==(Vector_d,Vector_d); +/*! returns whether the vectors are distinct. */ +friend bool operator!=(Vector_d,Vector_d); }; /*! diff --git a/Kernel_d/doc/Kernel_d/CGAL/Epick_d.h b/Kernel_d/doc/Kernel_d/CGAL/Epick_d.h index deb7043c4fc..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 @@ -77,6 +77,48 @@ double operator[](int i)const; Cartesian_const_iterator_d cartesian_begin()const; /*! returns an iterator pointing beyond the last Cartesian coordinate. */ Cartesian_const_iterator_d cartesian_end()const; + +/*! returns whether the points coincide. This may not be safe + if the points are the result of inexact constructions. */ +friend bool operator==(Point_d,Point_d); +/*! returns whether the points are distinct. This may not be safe + if the points are the result of inexact constructions. */ +friend bool operator!=(Point_d,Point_d); +}; + +/*! +represents a vector in the Euclidean space +\cgalModels{DefaultConstructible,Assignable} +*/ +class Vector_d { +public: +/*! introduces a vector with coordinates (x0, x1, ...) where the number of + coordinates matches the dimension. + \pre `DimensionTag` is a fixed dimension, not `Dynamic_dimension_tag`. */ +Vector_d(double x0, double x1, ...); + +/*! introduces a vector with coordinate set `[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 +Vector_d(InputIterator first, InputIterator end); + +/*! returns the i-th coordinate of a vector. + \pre `i` is non-negative and less than the dimension. */ +double operator[](int i)const; + +/*! returns an iterator pointing to the zeroth Cartesian coordinate. */ +Cartesian_const_iterator_d cartesian_begin()const; +/*! returns an iterator pointing beyond the last Cartesian coordinate. */ +Cartesian_const_iterator_d cartesian_end()const; + +/*! returns whether the vectors coincide. This may not be safe + if the vectors are the result of inexact constructions. */ +friend bool operator==(Vector_d,Vector_d); +/*! returns whether the vectors are distinct. This may not be safe + if the vectors are the result of inexact constructions. */ +friend bool operator!=(Vector_d,Vector_d); }; /*! 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 b2325f285d9..5873b7df672 100644 --- a/Kinetic_surface_reconstruction/include/CGAL/Kinetic_surface_reconstruction_3.h +++ b/Kinetic_surface_reconstruction/include/CGAL/Kinetic_surface_reconstruction_3.h @@ -946,7 +946,7 @@ private: KSP_3::internal::dump_polygons(polygon_regions, "faces_by_region-" + std::to_string(lambda) + ".ply"); std::vector > borders; - std::vector > borders_per_region; + std::vector > borders_per_region(region); collect_connected_border(borders, region_index, borders_per_region); for (std::size_t i = 0; i < region; i++) { @@ -1363,10 +1363,10 @@ private: for (std::size_t j = 0; j < polygons[i].size(); j++) { vertices.push_back(cdt.insert(pl.to_2d(m_lcc.point(m_lcc.template dart_of_attribute<0>(polygons[i][j]))))); CGAL_assertion_code(auto it =) va2vh.insert(std::make_pair(polygons[i][j], vertices.size() - 1)); - CGAL_assertion(it.second); + 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]; @@ -1573,8 +1573,6 @@ private: //borders contains Attribute<0> handles casted to std::size_t std::vector processed(m_lcc.upper_bound_on_dart_ids(), false); - borders_per_region.resize(region_index.size()); - for (std::size_t i = 0;i #include #include -//#include -#include +#include +#include #include @@ -60,7 +60,7 @@ typedef Edge_container Ec; typedef Triangle_container Tc; typedef Viewer_interface Vi; -typedef CGAL::Simple_cartesian Simple_kernel; +typedef CGAL::Exact_predicates_inexact_constructions_kernel Simple_kernel; typedef Simple_kernel::FT FT; typedef Simple_kernel::Point_3 Point; typedef std::pair Point_distance; @@ -81,24 +81,25 @@ Simple_kernel::Vector_3 random_vector() return Simple_kernel::Vector_3(x,y,z); } +template< typename Mesh> +struct PPMAP; //functor for tbb parallelization -template +template class FillGridSize { std::size_t grid_size; Point_distance (&distance_function)[100][100]; FT diag; FT& max_distance_function; std::vector&sm_trees; - bool is_signed; CGAL::qglviewer::ManipulatedFrame* frame; public: FillGridSize(std::size_t grid_size, FT diag, Point_distance (&distance_function)[100][100], FT& max_distance_function, std::vector& sm_trees, - bool is_signed, CGAL::qglviewer::ManipulatedFrame* frame) + CGAL::qglviewer::ManipulatedFrame* frame) : grid_size(grid_size), distance_function (distance_function), diag(diag), max_distance_function(max_distance_function), - sm_trees(sm_trees), is_signed(is_signed), frame(frame) + sm_trees(sm_trees), frame(frame) { } template @@ -137,7 +138,7 @@ public: max_distance_function = (std::max)(min, max_distance_function); - if(is_signed) + if constexpr (is_signed) { if(!min_sm_tree) { @@ -145,17 +146,12 @@ public: max_distance_function = DBL_MAX;//(std::max)(min, max_distance_function); continue; } - typedef typename SM_Tree::size_type size_type; - Simple_kernel::Vector_3 random_vec = random_vector(); + CGAL::Side_of_triangle_mesh, SM_Tree> side_of(*min_sm_tree); const Simple_kernel::Point_3& p = distance_function[i][j].first; const FT unsigned_distance = distance_function[i][j].second; - // get sign through ray casting (random vector) - Simple_kernel::Ray_3 ray(p, random_vec); - size_type nbi = min_sm_tree->number_of_intersected_primitives(ray); - - FT sign ( (nbi&1) == 0 ? 1 : -1); + FT sign ( side_of(p)==CGAL::ON_UNBOUNDED_SIDE ? 1 : -1); distance_function[i][j].second = sign * unsigned_distance; } } @@ -191,9 +187,7 @@ public: GLubyte* getData(){return data; } }; -typedef CGAL::Simple_cartesian Simple_kernel; -//typedef CGAL::Exact_predicates_inexact_constructions_kernel Simple_kernel; template< typename Mesh> struct PPMAP { @@ -390,8 +384,8 @@ private: mutable Simple_kernel::FT m_max_distance_function; mutable std::vector tex_map; mutable Cut_planes_types m_cut_plane; - template - void compute_distance_function(QMap *sm_trees, bool is_signed = false)const + template + void compute_distance_function(QMap *sm_trees)const { m_max_distance_function = FT(0); @@ -402,11 +396,11 @@ private: if(!(is_signed && !CGAL::is_closed(*qobject_cast(sm_trees->key(sm_tree))->polyhedron()))) closed_sm_trees.push_back(sm_tree); #ifndef CGAL_LINKED_WITH_TBB - FillGridSize f(m_grid_size, diag, m_distance_function, m_max_distance_function, closed_sm_trees, is_signed, frame); + FillGridSize f(m_grid_size, diag, m_distance_function, m_max_distance_function, closed_sm_trees, frame); HackRange range(0, static_cast(m_grid_size*m_grid_size)); f(range); #else - FillGridSize f(m_grid_size, diag, m_distance_function, m_max_distance_function, closed_sm_trees, is_signed, frame); + FillGridSize f(m_grid_size, diag, m_distance_function, m_max_distance_function, closed_sm_trees, frame); tbb::parallel_for(tbb::blocked_range(0, m_grid_size*m_grid_size), f); #endif } @@ -459,7 +453,7 @@ private: break; case SIGNED_FACETS: if (!facet_sm_trees || facet_sm_trees->empty() ) { return; } - compute_distance_function( facet_sm_trees, true); + compute_distance_function( facet_sm_trees); break; case UNSIGNED_EDGES: diff --git a/Lab/demo/Lab/Plugins/IO/CMakeLists.txt b/Lab/demo/Lab/Plugins/IO/CMakeLists.txt index dbdad76da22..1bb9cf3338b 100644 --- a/Lab/demo/Lab/Plugins/IO/CMakeLists.txt +++ b/Lab/demo/Lab/Plugins/IO/CMakeLists.txt @@ -35,6 +35,9 @@ target_link_libraries(off_to_nef_plugin PRIVATE scene_nef_polyhedron_item) cgal_lab_plugin(polylines_io_plugin Polylines_io_plugin KEYWORDS Viewer Mesh_3) target_link_libraries(polylines_io_plugin PRIVATE scene_polylines_item) +cgal_lab_plugin(spheres_io_plugin Spheres_io_plugin KEYWORDS Viewer Mesh_3) +target_link_libraries(spheres_io_plugin PRIVATE scene_basic_objects) + cgal_lab_plugin(wkt_plugin WKT_io_plugin KEYWORDS Viewer PointSetProcessing Mesh_3) target_link_libraries(wkt_plugin PRIVATE scene_polylines_item) diff --git a/Lab/demo/Lab/Plugins/IO/Spheres_io_plugin.cpp b/Lab/demo/Lab/Plugins/IO/Spheres_io_plugin.cpp new file mode 100644 index 00000000000..976e436d38e --- /dev/null +++ b/Lab/demo/Lab/Plugins/IO/Spheres_io_plugin.cpp @@ -0,0 +1,162 @@ +#include "Scene_spheres_item.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace CGAL::Three; + +class CGAL_Lab_spheres_io_plugin : + public QObject, + public CGAL_Lab_io_plugin_interface, + public CGAL_Lab_plugin_helper +{ + Q_OBJECT + Q_INTERFACES(CGAL::Three::CGAL_Lab_plugin_interface CGAL::Three::CGAL_Lab_io_plugin_interface) + Q_PLUGIN_METADATA(IID "com.geometryfactory.CGALLab.PluginInterface/1.0" FILE "spheres_io_plugin.json") + Q_PLUGIN_METADATA(IID "com.geometryfactory.CGALLab.IOPluginInterface/1.90") + +public: + // To silent a warning -Woverloaded-virtual + // See https://stackoverflow.com/questions/9995421/gcc-woverloaded-virtual-warnings + + using CGAL_Lab_io_plugin_interface::init; + //! Configures the widget + void init(QMainWindow* mainWindow, + CGAL::Three::Scene_interface* scene_interface, + Messages_interface*) override{ + //get the references + this->scene = scene_interface; + this->mw = mainWindow; + + } + QString name() const override{ return "spheres_io_plugin"; } + QString nameFilters() const override{ return "Spheres files (*.spheres.txt)"; } + bool canLoad(QFileInfo fileinfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override; + + bool canSave(const CGAL::Three::Scene_item*) override; + bool save(QFileInfo fileinfo,QList&) override; + bool applicable(QAction* ) const override { + return false; + } + QList actions() const override{ + + return QList(); + } + + bool isDefaultLoader(const Scene_item* item) const override{ + if(qobject_cast(item)) + return true; + return false; + } +}; + +bool CGAL_Lab_spheres_io_plugin::canLoad(QFileInfo fileinfo) const{ + if(!fileinfo.suffix().contains("cgal")) + return true; + std::ifstream in(fileinfo.filePath().toUtf8()); + if(!in) { + return false; + } + int first; + if(!(in >> first) + || first <= 0) + return false; + return true; +} + + +QList +CGAL_Lab_spheres_io_plugin:: +load(QFileInfo fileinfo, bool& ok, bool add_to_scene){ + + // Open file + std::ifstream ifs(fileinfo.filePath().toUtf8()); + if(!ifs) { + std::cerr << "Error! Cannot open file " << (const char*)fileinfo.filePath().toUtf8() << std::endl; + ok = false; + return QList(); + } + + if(fileinfo.size() == 0) + { + CGAL::Three::Three::warning( tr("The file you are trying to load is empty.")); + Scene_spheres_item* item = new Scene_spheres_item(nullptr, 0, false, false); + item->setName(fileinfo.completeBaseName()); + ok = true; + if(add_to_scene) + CGAL::Three::Three::scene()->addItem(item); + return QList()< > spheres; + while (ifs >> x && ifs >> y && ifs >> z && ifs >> r) + spheres.push_back({x, y, z, r}); + + std::vector colors; + if (true) { + colors.resize(spheres.size()); + for (QColor &c : colors) + c = generate_random_color(); + } + else { + colors.reserve(spheres.size()); + compute_deterministic_color_map(QColor(180, 120, 130, 255), spheres.size(), std::back_inserter(colors)); + } + + Scene_spheres_item* item = new Scene_spheres_item(nullptr, spheres.size(), false, true); + item->setName(fileinfo.completeBaseName()); + + for (std::size_t i = 0;i& s = spheres[i]; + item->add_sphere(CGAL::Epick::Sphere_3(CGAL::Epick::Point_3(s[0], s[1], s[2]), s[3] * s[3]), i, CGAL::IO::Color(colors[i].red(), colors[i].green(), colors[i].blue())); + } + + std::cerr << "Number of spheres loaded: " << spheres.size() << std::endl; + + item->invalidateOpenGLBuffers(); + + item->setRenderingMode(Gouraud); + CGAL::Three::Three::scene()->addItem(item); + item->computeElements(); + + return QList()<(item) != 0; +} + +bool CGAL_Lab_spheres_io_plugin:: +save(QFileInfo fileinfo,QList& items) +{ + Scene_item* item = items.front(); + const Scene_spheres_item* sphere_item = + qobject_cast(item); + + if(!sphere_item) + return false; + + std::ofstream out(fileinfo.filePath().toUtf8()); + + out.precision (std::numeric_limits::digits10 + 2); + + if(!out) { + std::cerr << "Error! Cannot open file " << (const char*)fileinfo.filePath().toUtf8() << std::endl; + return false; + } + + return false; +} + +#include "Spheres_io_plugin.moc" 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/IO/lcc_io_plugin.cpp b/Lab/demo/Lab/Plugins/IO/lcc_io_plugin.cpp index 027b52fd69e..690f0f79de8 100644 --- a/Lab/demo/Lab/Plugins/IO/lcc_io_plugin.cpp +++ b/Lab/demo/Lab/Plugins/IO/lcc_io_plugin.cpp @@ -47,7 +47,7 @@ public: QString ext = fileinfo.suffix(); bool res = true; if(ext == "off") - CGAL::import_from_polyhedron_3_flux < Scene_lcc_item::LCC > (lcc, ifs); + CGAL::polyhedron_3_flux_to_lcc < Scene_lcc_item::LCC > (lcc, ifs); else { res = CGAL::load_combinatorial_map(ifs, lcc); diff --git a/Lab/demo/Lab/Plugins/Mesh_3/CMakeLists.txt b/Lab/demo/Lab/Plugins/Mesh_3/CMakeLists.txt index 3c344555147..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) @@ -48,8 +49,7 @@ else() message(STATUS "NOTICE: DICOM files (.dcm) require the VTK libraries, and will not be readable.") endif() -find_package(Boost QUIET OPTIONAL_COMPONENTS filesystem system) -if(Boost_FILESYSTEM_FOUND) + qt6_wrap_ui( imgUI_FILES Image_res_dialog.ui raw_image.ui) cgal_lab_plugin(io_image_plugin Io_image_plugin Volume_plane_intersection.cpp @@ -62,11 +62,7 @@ if(Boost_FILESYSTEM_FOUND) target_compile_definitions(io_image_plugin PRIVATE -DCGAL_USE_VTK -DNOMINMAX) endif() - target_link_libraries(io_image_plugin PRIVATE Boost::filesystem Boost::system) -else() - message(STATUS "NOTICE: the Io_image_plugin requires boost-filesystem, and will not be compiled") -endif() cgal_lab_plugin( mesh_3_optimization_plugin Optimization_plugin diff --git a/Lab/demo/Lab/Plugins/Mesh_3/Io_image_plugin.cpp b/Lab/demo/Lab/Plugins/Mesh_3/Io_image_plugin.cpp index 780511846aa..a4302b32708 100644 --- a/Lab/demo/Lab/Plugins/Mesh_3/Io_image_plugin.cpp +++ b/Lab/demo/Lab/Plugins/Mesh_3/Io_image_plugin.cpp @@ -72,7 +72,7 @@ #include #include -#include +#include #include #include @@ -1520,10 +1520,10 @@ Image* Io_image_plugin::createDirectoryImage(const QString& dirname, CGAL_assertion(ext == Directory_extension_type::BMP); // vtkBMPReader does not provide SetDirectoryName()... - std::vector paths; + std::vector paths; vtkStringArray* files = vtkStringArray::New(); - boost::filesystem::path p(dirname.toUtf8().data()); - for(boost::filesystem::directory_entry& x : boost::filesystem::directory_iterator(p)) + std::filesystem::path p(dirname.toUtf8().data()); + for(const std::filesystem::directory_entry& x : std::filesystem::directory_iterator(p)) { std::string s = x.path().string(); if(CGAL::IO::internal::get_file_extension(s) != "bmp") @@ -1532,10 +1532,10 @@ Image* Io_image_plugin::createDirectoryImage(const QString& dirname, paths.push_back(x.path()); } - // boost::filesystem::directory_iterator does not guarantee a sorted order + // std::filesystem::directory_iterator does not guarantee a sorted order std::sort(std::begin(paths), std::end(paths)); - for(const boost::filesystem::path& p : paths) + for(const std::filesystem::path& p : paths) files->InsertNextValue(p.string()); if(files->GetSize() == 0) 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/Plugins/Point_set/Point_set_shape_detection_plugin.cpp b/Lab/demo/Lab/Plugins/Point_set/Point_set_shape_detection_plugin.cpp index 5a0c76720ea..3d3652eed09 100644 --- a/Lab/demo/Lab/Plugins/Point_set/Point_set_shape_detection_plugin.cpp +++ b/Lab/demo/Lab/Plugins/Point_set/Point_set_shape_detection_plugin.cpp @@ -532,8 +532,8 @@ private: Ransac::Parameters op; op.probability = dialog.search_probability(); // probability to miss the largest primitive on each iteration. op.min_points = dialog.min_points(); // Only extract shapes with a minimum number of points. - op.epsilon = dialog.epsilon(); // maximum euclidean distance between point and shape. - op.cluster_epsilon = dialog.cluster_epsilon(); // maximum euclidean distance between points to be clustered. + op.epsilon = dialog.epsilon(); // maximum Euclidean distance between point and shape. + op.cluster_epsilon = dialog.cluster_epsilon(); // maximum Euclidean distance between points to be clustered. op.normal_threshold = std::cos(CGAL_PI * dialog.normal_tolerance() / 180.); // normal_threshold < dot(surface_normal, point_normal); CGAL::Random rand(static_cast(time(nullptr))); 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/Scene_spheres_item.cpp b/Lab/demo/Lab/Scene_spheres_item.cpp index fac56fbda9b..d65da606030 100644 --- a/Lab/demo/Lab/Scene_spheres_item.cpp +++ b/Lab/demo/Lab/Scene_spheres_item.cpp @@ -2,7 +2,9 @@ #include #include #include +#include #include +#include using namespace CGAL::Three; @@ -43,9 +45,7 @@ struct Scene_spheres_item_priv model_sphere_is_up = false; } - ~Scene_spheres_item_priv() - { - } + ~Scene_spheres_item_priv() {} void pick(int &id)const; @@ -85,6 +85,15 @@ void Scene_spheres_item_priv::pick(int& id) const id = -1; } + if (id != -1 && spheres[id].size() == 1) { + const Sphere& sphere = spheres[id][0].first; + Three::information(QString("Selected sphere: center (%1, %2, %3) radius %4"). + arg(sphere.center().x(), 0, 'g', 10). + arg(sphere.center().y(), 0, 'g', 10). + arg(sphere.center().z(), 0, 'g', 10). + arg(CGAL::approximate_sqrt(sphere.squared_radius()), 0, 'g', 10)); + } + int offset = 0; float color[4]; for(std::size_t i=0; isetAlpha(alpha()); getTriangleContainer(0)->draw(viewer, false); } if(d->pickable && (d->spheres.size() > 1 && viewer->inDrawWithNames())) @@ -218,6 +233,9 @@ void Scene_spheres_item::draw(Viewer_interface *viewer) const void Scene_spheres_item::drawEdges(Viewer_interface *viewer) const { + if (renderingMode() != Wireframe || !visible()) + return; + if(!isInit(viewer)) initGL(viewer); if ( getBuffersFilled() && @@ -295,6 +313,18 @@ void Scene_spheres_item::invalidateOpenGLBuffers() getTriangleContainer(1)->reset_vbos(COLORS); } getEdgeContainer(0)->reset_vbos(NOT_INSTANCED); + compute_bbox(); +} + +QMenu* Scene_spheres_item::contextMenu() { + QMenu* menu = Scene_item_rendering_helper::contextMenu(); + + if (!connected_alpha_slider && alphaSlider() != nullptr) { + connect(alphaSlider(), &QSlider::valueChanged, [this]() {redraw(); }); + connected_alpha_slider = true; + } + + return menu; } QString diff --git a/Lab/demo/Lab/Scene_spheres_item.h b/Lab/demo/Lab/Scene_spheres_item.h index dd365a16ac2..23ae7fe541f 100644 --- a/Lab/demo/Lab/Scene_spheres_item.h +++ b/Lab/demo/Lab/Scene_spheres_item.h @@ -2,6 +2,7 @@ #define SCENE_SPHERES_ITEM_H #include "Scene_basic_objects_config.h" #include "create_sphere.h" +#include "Color_map.h" #include #include @@ -24,7 +25,7 @@ struct Scene_spheres_item_priv; * have a Scene_spheres_item child). */ class SCENE_BASIC_OBJECTS_EXPORT Scene_spheres_item - : public CGAL::Three::Scene_item_rendering_helper + : public CGAL::Three::Scene_group_item { Q_OBJECT public: @@ -37,6 +38,7 @@ public: ~Scene_spheres_item(); + Bbox bbox() const override { return _bbox; } bool isFinite() const override{ return true; } bool isEmpty() const override{ return false; } Scene_item* clone() const override{return nullptr;} @@ -57,10 +59,12 @@ public: void setColor(QColor c) override; bool save(const std::string &file_name) const; + QMenu *contextMenu() override; void initializeBuffers(Viewer_interface *) const override; void computeElements() const override; bool eventFilter(QObject *watched, QEvent *event)override; + Q_SIGNALS: void on_color_changed(); void picked(std::size_t id) const; @@ -68,6 +72,7 @@ Q_SIGNALS: protected: friend struct Scene_spheres_item_priv; Scene_spheres_item_priv* d; + bool connected_alpha_slider; }; #endif // SCENE_SPHERES_ITEM_H 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/demo/Linear_cell_complex/MainWindow.cpp b/Linear_cell_complex/demo/Linear_cell_complex/MainWindow.cpp index 04d95629494..ea72b31a057 100644 --- a/Linear_cell_complex/demo/Linear_cell_complex/MainWindow.cpp +++ b/Linear_cell_complex/demo/Linear_cell_complex/MainWindow.cpp @@ -375,7 +375,7 @@ void MainWindow::load_off (const QString & fileName, bool clear) std::ifstream ifs (qPrintable (fileName)); - CGAL::import_from_polyhedron_3_flux < LCC > (*scene.lcc, ifs); + CGAL::polyhedron_3_flux_to_lcc < LCC > (*scene.lcc, ifs); #ifdef CGAL_PROFILE_LCC_DEMO timer.stop(); @@ -415,7 +415,7 @@ void MainWindow::load_3DTDS (const QString & fileName, bool clear) T.insert (std::istream_iterator < Point_3 >(ifs), std::istream_iterator < Point_3 >() ); - CGAL::import_from_triangulation_3 < LCC, Triangulation >(*scene.lcc, T); + CGAL::triangulation_3_to_lcc < LCC, Triangulation >(*scene.lcc, T); #ifdef CGAL_PROFILE_LCC_DEMO timer.stop(); @@ -673,7 +673,7 @@ void MainWindow::on_actionCompute_Voronoi_3D_triggered () std::map vol_to_dart; - dh = CGAL::import_from_triangulation_3 < LCC, Triangulation > + dh = CGAL::triangulation_3_to_lcc < LCC, Triangulation > (delaunay_lcc, T, &vol_to_dart); Dart_descriptor ddh=delaunay_lcc.dual(*scene.lcc, dh); diff --git a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex_constructors.h b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex_constructors.h index 71796bd842b..0fefb1240b1 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex_constructors.h +++ b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex_constructors.h @@ -24,13 +24,20 @@ Here a small example: Middle: the 2D linear cell complex reconstructed if combinatorial maps are the combinatorial data-structure. Right: the 2D linear cell complex reconstructed if generalized maps are the combinatorial data-structure. -\sa `CGAL::import_from_triangulation_3` -\sa `CGAL::import_from_polyhedron_3` - +\sa `CGAL::triangulation_3_to_lcc` +\sa `CGAL::polyhedron_3_to_lcc` */ template -typename LCC::Dart_descriptor import_from_plane_graph(LCC& lcc, +typename LCC::Dart_descriptor read_plane_graph_in_lcc(LCC& lcc, std::istream& ais); +/*! +\ingroup PkgLinearCellComplexConstructions +\deprecated Use `read_plane_graph_in_lcc()` instead. +*/ +template +[[deprecated("Use read_plane_graph_in_lcc instead")]] +typename LCC::Dart_descriptor import_from_plane_graph(LCC& lcc, std::istream& ais); + } /* namespace CGAL */ diff --git a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Polyhedron_3_to_lcc.h b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Polyhedron_3_to_lcc.h index b6fbef4d30d..5983ebfc73e 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Polyhedron_3_to_lcc.h +++ b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Polyhedron_3_to_lcc.h @@ -5,10 +5,10 @@ namespace CGAL{ Imports `apoly` (a `Polyhedron_3`) into `lcc`, a model of the `LinearCellComplex` concept. Objects are added in `lcc`, existing darts are not modified. Returns a dart created during the import. \pre \link GenericMap::dimension `LCC::dimension`\endlink \f$ \geq\f$ 2 and \link LinearCellComplex::ambient_dimension `LCC::ambient_dimension`\endlink==3. -\sa `CGAL::import_from_plane_graph` -\sa `CGAL::import_from_triangulation_3` +\sa `CGAL::read_plane_graph_in_lcc` +\sa `CGAL::triangulation_3_to_lcc` */ template -typename LCC::Dart_descriptor import_from_polyhedron_3(LCC& lcc, +typename LCC::Dart_descriptor polyhedron_3_to_lcc(LCC& lcc, const Polyhedron &apoly); } diff --git a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Triangulation_3_to_lcc.h b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Triangulation_3_to_lcc.h index 1532b70469b..c1ab3172a09 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Triangulation_3_to_lcc.h +++ b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Triangulation_3_to_lcc.h @@ -3,13 +3,23 @@ namespace CGAL{ /*! \ingroup PkgLinearCellComplexConstructions -Imports `atr` (a `Triangulation_3`) into `lcc`, a model of the `LinearCellComplex` concept. Objects are added in `lcc`, existing darts are not modified. Returns a dart created during the import. -\pre \link GenericMap::dimension `LCC::dimension`\endlink \f$ \geq\f$ 3 and \link LinearCellComplex::ambient_dimension `LCC::ambient_dimension`\endlink==3. +Imports `atr` (a `Triangulation_3`) into `lcc`, a model of the `LinearCellComplex` concept. +Objects are added in `lcc`, existing darts are not modified. Returns a dart created during the import. +\pre \link GenericMap::dimension `LCC::dimension`\endlink \f$ \geq\f$ 3 and + \link LinearCellComplex::ambient_dimension `LCC::ambient_dimension`\endlink==3. -\sa `CGAL::import_from_plane_graph` -\sa `CGAL::import_from_polyhedron_3` +\sa `CGAL::read_plane_graph_in_lcc` +\sa `CGAL::polyhedron_3_to_lcc` */ + template -typename LCC::Dart_descriptor import_from_triangulation_3(LCC& lcc, -const Triangulation_&atr); +typename LCC::Dart_descriptor triangulation_3_to_lcc(LCC& lcc, const Triangulation_&atr); + +template +[[deprecated("Use triangulation_3_to_lcc instead")]] +typename LCC::Dart_descriptor import_from_triangulation_3(LCC& lcc, const Triangulation_& atr) +{ + return triangulation_3_to_lcc(lcc, atr); } + +} \ No newline at end of file diff --git a/Linear_cell_complex/doc/Linear_cell_complex/Concepts/LinearCellComplexTraits.h b/Linear_cell_complex/doc/Linear_cell_complex/Concepts/LinearCellComplexTraits.h index e701f011493..50aac41da1e 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/Concepts/LinearCellComplexTraits.h +++ b/Linear_cell_complex/doc/Linear_cell_complex/Concepts/LinearCellComplexTraits.h @@ -64,8 +64,8 @@ which constructs a vector as the difference of points `p2-p1`, and \link LinearCellComplexTraits::Vector ` Vector `\endlink `operator() (const CGAL::Origin&, const ` \link Point ` Point`\endlink`& p)` which constructs a vector as the difference of point `p` and a point at the origin (used in \link CGAL::barycenter `barycenter`\endlink -and `CGAL::import_from_plane_graph`). -*/ +and `CGAL::read_plane_graph_in_lcc`).*/ + typedef unspecified_type Construct_vector; /*! @@ -104,7 +104,7 @@ a model of \link Kernel::Direction_2 `Direction_2`\endlink. typedef unspecified_type Direction_2; /*! -a model of \link Kernel::ConstructDirection_2 `ConstructDirection_2`\endlink (used in `CGAL::import_from_plane_graph`). +a model of \link Kernel::ConstructDirection_2 `ConstructDirection_2`\endlink (used in `CGAL::read_plane_graph_in_lcc`). */ typedef unspecified_type Construct_direction_2; 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 d0dc1a2b351..0a04ceb347d 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 @@ -105,11 +105,12 @@ There are several member functions allowing to insert specific configurations of There are two functions allowing to build a linear cell complex from two other \cgal data types:
      -
    • \link ::import_from_triangulation_3 `import_from_triangulation_3(lcc,atr)`\endlink: adds in `lcc` all the tetrahedra present in `atr`, a \link CGAL::Triangulation_3 `Triangulation_3`\endlink; -
    • \link ::import_from_polyhedron_3 `import_from_polyhedron_3(lcc,ap)`\endlink: adds in `lcc` all the cells present in `ap`, a `Polyhedron_3`. + +
    • \link CGAL::triangulation_3_to_lcc `triangulation_3_to_lcc(lcc,atr)`\endlink: adds in `lcc` all the tetrahedra present in `atr`, a \link CGAL::Triangulation_3 `Triangulation_3`\endlink; +
    • \link CGAL::polyhedron_3_to_lcc `polyhedron_3_to_lcc(lcc,ap)`\endlink: adds in `lcc` all the cells present in `ap`, a `Polyhedron_3`.
    -Lastly, the function \link ::import_from_plane_graph `import_from_plane_graph(lcc,ais)`\endlink adds in `lcc` all the cells reconstructed from the planar graph read in `ais`, a `std::istream` (see the \link ::import_from_plane_graph `reference manual`\endlink for the file format). +Lastly, the function \link CGAL::read_plane_graph_in_lcc `read_plane_graph_in_lcc(lcc,ais)`\endlink adds in `lcc` all the cells reconstructed from the planar graph read in `ais`, a `std::istream` (see the \link CGAL::read_plane_graph_in_lcc `reference manual`\endlink for the file format). \subsection Linear_cell_complexModificationOperations Modification Operations \anchor ssecmodifop @@ -280,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/doc/Linear_cell_complex/PackageDescription.txt b/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt index 03983e5a810..00619008616 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt +++ b/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt @@ -70,9 +70,9 @@ \cgalCRPSection{Global Functions} \cgalCRPSubsection{Constructions for Linear Cell Complex} -- `CGAL::import_from_plane_graph` -- `CGAL::import_from_triangulation_3` -- `CGAL::import_from_polyhedron_3` +- `CGAL::read_plane_graph_in_lcc` (formerly `import_from_plane_graph`) +- `CGAL::triangulation_3_to_lcc` (formerly `import_from_triangulation_3`) +- `CGAL::polyhedron_3_to_lcc` (formerly `import_from_polyhedron_3`) \cgalCRPSubsection{Operations for Linear Cell Complex} - `CGAL::compute_normal_of_cell_0` diff --git a/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt b/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt index b458bbd6e83..234ae9e83da 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt +++ b/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt @@ -24,7 +24,7 @@ create_single_source_cgal_program( "linear_cell_complex_3_with_colored_vertices.cpp") create_single_source_cgal_program("linear_cell_complex_3_with_mypoint.cpp") create_single_source_cgal_program("linear_cell_complex_4.cpp") -create_single_source_cgal_program("plane_graph_to_lcc_2.cpp") +create_single_source_cgal_program("read_plane_graph_in_lcc_2.cpp") create_single_source_cgal_program("voronoi_2.cpp") create_single_source_cgal_program("voronoi_3.cpp") create_single_source_cgal_program("linear_cell_complex_3_vtk_io.cpp") diff --git a/Linear_cell_complex/examples/Linear_cell_complex/README.txt b/Linear_cell_complex/examples/Linear_cell_complex/README.txt index e461312f2dd..9184123bfeb 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/README.txt +++ b/Linear_cell_complex/examples/Linear_cell_complex/README.txt @@ -8,7 +8,7 @@ Examples for Linear_cell_complex package: Three "basic" examples, detailed in the user manual. -* plane_graph_to_lcc_2.cpp +* read_plane_graph_in_lcc_2.cpp Program allowing to transform a planar graph into a 2D linear cell complex. diff --git a/Linear_cell_complex/examples/Linear_cell_complex/plane_graph_to_lcc_2.cpp b/Linear_cell_complex/examples/Linear_cell_complex/read_plane_graph_in_lcc_2.cpp similarity index 97% rename from Linear_cell_complex/examples/Linear_cell_complex/plane_graph_to_lcc_2.cpp rename to Linear_cell_complex/examples/Linear_cell_complex/read_plane_graph_in_lcc_2.cpp index 58fd07d2bf9..c6ef3bac676 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/plane_graph_to_lcc_2.cpp +++ b/Linear_cell_complex/examples/Linear_cell_complex/read_plane_graph_in_lcc_2.cpp @@ -42,7 +42,7 @@ int main(int narg, char** argv) std::ifstream is(filename.c_str()); std::cout<<"Import plane graph from "< vol_to_dart; - Dart_descriptor d=CGAL::import_from_triangulation_3 + Dart_descriptor d=CGAL::triangulation_3_to_lcc (lcc, T, &vol_to_dart); std::cout<<"Delaunay triangulation :"< Vertex_attribute_descriptor create_vertex_attribute(const Args&... args) { return Base::template create_attribute<0>(args...); } /** - * Creates a new dart associated with an handle through an attribute. + * Creates 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_constructors.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_constructors.h index e770c67e86c..20e83a6ce05 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_constructors.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_constructors.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace CGAL { @@ -36,7 +37,7 @@ namespace CGAL { * Imports a plane-embedded graph from a list of points and edges represented as pairs of vertex indices */ template< class LCC > - typename LCC::Dart_descriptor import_from_plane_graph(LCC& alcc, + typename LCC::Dart_descriptor read_plane_graph_in_lcc(LCC& alcc, const std::vector& vertices, const std::vector& edge_indices) { @@ -130,6 +131,21 @@ namespace CGAL { return first; } +#ifndef CGAL_NO_DEPRECATED_CODE +/*! + \deprecated This function is deprecated since CGAL 6.2. Use `read_plane_graph_in_lcc()` instead. +*/ +template< class LCC > +CGAL_DEPRECATED +typename LCC::Dart_descriptor +import_from_plane_graph(LCC& alcc, + const std::vector& vertices, + const std::vector& edge_indices) +{ + return read_plane_graph_in_lcc(alcc, vertices, edge_indices); +} +#endif + /** * Imports a plane-embedded graph from a file into a LinearCellComplex. * @@ -138,7 +154,7 @@ namespace CGAL { * @return A dart created during the conversion. */ template< class LCC > - typename LCC::Dart_descriptor import_from_plane_graph(LCC& alcc, + typename LCC::Dart_descriptor read_plane_graph_in_lcc(LCC& alcc, std::istream& ais) { using FT = typename LCC::FT; @@ -185,18 +201,44 @@ namespace CGAL { edge_indices.push_back(v2); } - return import_from_plane_graph(alcc, vertices, edge_indices); + return read_plane_graph_in_lcc(alcc, vertices, edge_indices); } +#ifndef CGAL_NO_DEPRECATED_CODE +/*! + \deprecated This function is deprecated since CGAL 6.2. Use `read_plane_graph_in_lcc()` instead. +*/ +template< class LCC > +CGAL_DEPRECATED +typename LCC::Dart_descriptor +import_from_plane_graph(LCC& alcc, std::istream& ais) +{ + return read_plane_graph_in_lcc(alcc, ais); +} +#endif + template < class LCC > typename LCC::Dart_descriptor - import_from_plane_graph(LCC& alcc, const char* filename) + read_plane_graph_in_lcc(LCC& alcc, const char* filename) { std::ifstream input(filename); if (!input.is_open()) return alcc.null_descriptor; - return import_from_plane_graph(alcc, input); + return read_plane_graph_in_lcc(alcc, input); } +#ifndef CGAL_NO_DEPRECATED_CODE +/*! + \deprecated This function is deprecated since CGAL 6.2. Use `read_plane_graph_in_lcc()` instead. +*/ +template< class LCC > +CGAL_DEPRECATED +typename LCC::Dart_descriptor +import_from_plane_graph(LCC& alcc, const char* filename) +{ + return read_plane_graph_in_lcc(alcc, filename); +} +#endif + template < class LCC > bool load_off(LCC& alcc, std::istream& in) { 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/CMakeLists.txt b/Linear_cell_complex/test/Linear_cell_complex/CMakeLists.txt index 9c710c4e061..dc246cecc3b 100644 --- a/Linear_cell_complex/test/Linear_cell_complex/CMakeLists.txt +++ b/Linear_cell_complex/test/Linear_cell_complex/CMakeLists.txt @@ -37,3 +37,13 @@ add_executable(Linear_cell_complex_copy_test_index Linear_cell_complex_copy_test target_compile_definitions(Linear_cell_complex_copy_test_index PRIVATE USE_COMPACT_CONTAINER_WITH_INDEX) target_link_libraries(Linear_cell_complex_copy_test_index PRIVATE CGAL CGAL::Data) cgal_add_compilation_test(Linear_cell_complex_copy_test_index) + +# Alias tests (test old function names, with deprecated warnings disabled) +create_single_source_cgal_program(test_triangulation_alias.cpp ${hfiles}) +target_compile_definitions(test_triangulation_alias PRIVATE CGAL_NO_DEPRECATION_WARNINGS) + +create_single_source_cgal_program(test_polyhedron_3_alias.cpp ${hfiles}) +target_compile_definitions(test_polyhedron_3_alias PRIVATE CGAL_NO_DEPRECATION_WARNINGS) + +create_single_source_cgal_program(test_plane_graph_alias.cpp ${hfiles}) +target_compile_definitions(test_plane_graph_alias PRIVATE CGAL_NO_DEPRECATION_WARNINGS) diff --git a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_2_test.h b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_2_test.h index f22bd0a480a..c1a80876d35 100644 --- a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_2_test.h +++ b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_2_test.h @@ -382,7 +382,7 @@ bool test_LCC_2() std::cout<<"Error: impossible to open 'data/graph.txt'"<(lcc,in); + CGAL::read_plane_graph_in_lcc(lcc,in); if ( !check_number_of_cells_2(lcc, 66, 166, 104, 2) ) return false; lcc.clear(); @@ -431,7 +431,7 @@ struct Test_change_orientation_LCC_2 std::cout<<"Error: impossible to open 'data/graph.txt'"<(lcc,in); + CGAL::read_plane_graph_in_lcc(lcc,in); trace_test_begin(); 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 1f696a41811..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))); @@ -997,7 +997,7 @@ bool test_LCC_3() } in >> P; - CGAL::import_from_polyhedron_3(lcc,P); + CGAL::polyhedron_3_to_lcc(lcc,P); if ( !check_number_of_cells_3(lcc, 1539, 4434, 2894, 2, 2) ) return false; @@ -1029,7 +1029,7 @@ bool test_LCC_3() } T.insert ( std::istream_iterator < Point >(in), std::istream_iterator < Point >() ); - CGAL::import_from_triangulation_3(lcc,T); + CGAL::triangulation_3_to_lcc(lcc,T); if ( !lcc.is_valid() ) return false; diff --git a/Linear_cell_complex/test/Linear_cell_complex/test_plane_graph_alias.cpp b/Linear_cell_complex/test/Linear_cell_complex/test_plane_graph_alias.cpp new file mode 100644 index 00000000000..cafb22ad4b4 --- /dev/null +++ b/Linear_cell_complex/test/Linear_cell_complex/test_plane_graph_alias.cpp @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include + +typedef CGAL::Linear_cell_complex_for_combinatorial_map<2> LCC; + + + +int main() +{ +#ifndef CGAL_NO_DEPRECATED_CODE + LCC lcc1, lcc2; + + // Planar graph with 3 vertices and 3 edges (triangle) + std::stringstream input; + input << "3 3\n0.0 0.0\n1.0 0.0\n0.0 1.0\n0 1\n1 2\n2 0\n"; + + // Test new function + auto d1 = CGAL::read_plane_graph_in_lcc(lcc1, input); + assert(d1 != LCC::null_descriptor); + + // Rewind input stream for second test + input.clear(); + input.seekg(0, std::ios::beg); + + // Test deprecated function + auto d2 = CGAL::import_from_plane_graph(lcc2, input); + assert(d2 != LCC::null_descriptor); +#endif // CGAL_NO_DEPRECATED_CODE + return EXIT_SUCCESS; +} + diff --git a/Linear_cell_complex/test/Linear_cell_complex/test_polyhedron_3_alias.cpp b/Linear_cell_complex/test/Linear_cell_complex/test_polyhedron_3_alias.cpp new file mode 100644 index 00000000000..183aac6e0be --- /dev/null +++ b/Linear_cell_complex/test/Linear_cell_complex/test_polyhedron_3_alias.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include +#include +#include + +typedef CGAL::Linear_cell_complex_for_combinatorial_map<3> LCC; +typedef CGAL::Polyhedron_3 Polyhedron; + + +int main() +{ +#ifndef CGAL_NO_DEPRECATED_CODE + std::stringstream ss("OFF\n0 0 0\n"); + + Polyhedron P; + ss >> P; + + LCC lcc1, lcc2; + + auto d1 = CGAL::polyhedron_3_to_lcc(lcc1, P); + assert(d1 == LCC::null_descriptor); + + auto d2 = CGAL::import_from_polyhedron_3(lcc2, P); + assert(d2 == LCC::null_descriptor); +#endif // CGAL_NO_DEPRECATED_CODE + return EXIT_SUCCESS; +} + diff --git a/Linear_cell_complex/test/Linear_cell_complex/test_triangulation_alias.cpp b/Linear_cell_complex/test/Linear_cell_complex/test_triangulation_alias.cpp new file mode 100644 index 00000000000..43b9e0ebf82 --- /dev/null +++ b/Linear_cell_complex/test/Linear_cell_complex/test_triangulation_alias.cpp @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include +#include + +typedef CGAL::Linear_cell_complex_for_combinatorial_map<3> LCC_3; +typedef CGAL::Delaunay_triangulation_3 Triangulation; + + + +int main() +{ +#ifndef CGAL_NO_DEPRECATED_CODE + LCC_3 lcc1, lcc2; + Triangulation T; + + assert(T.dimension() == -1); + + auto d1 = CGAL::triangulation_3_to_lcc(lcc1, T); + assert(d1 == LCC_3::null_descriptor); + + auto d2 = CGAL::import_from_triangulation_3(lcc2, T); + assert(d2 == LCC_3::null_descriptor); +#endif // CGAL_NO_DEPRECATED_CODE + return EXIT_SUCCESS; +} + diff --git a/Maintenance/public_release/announcement/announcement-beta.md b/Maintenance/public_release/announcement/announcement-beta.md index d847b9b1386..14aeda560b5 100644 --- a/Maintenance/public_release/announcement/announcement-beta.md +++ b/Maintenance/public_release/announcement/announcement-beta.md @@ -1,153 +1,97 @@ -The CGAL Open Source Project is pleased to announce the release 6.0 Beta 1 of CGAL, the Computational Geometry Algorithms Library. +The CGAL Open Source Project is pleased to announce the release 6.1 Beta 1 of CGAL, the Computational Geometry Algorithms Library. -CGAL version 6.0 Beta 1 is a public testing release. It should provide a solid ground to report bugs that need to be tackled before the release of the final version of CGAL 6.0 in July 2024. +CGAL version 6.1 Beta 1 is a public testing release. It should provide a solid ground to report bugs that need to be tackled before the release of the final version of CGAL 6.1 in Sept 2025. -Besides fixes and general enhancement to existing packages, the following has changed since CGAL 5.6: +Besides fixes and general enhancement to existing packages, the following has changed since CGAL 6.0: ### General Changes -- CGAL 6.0 is the first release of CGAL that requires a C++ compiler with the support of C++17 or later. The new list of supported compilers is: +- The new list of supported compilers is: - Visual C++ 15.9, 16.10, 17.0 (from Visual Studio 2017, 2019 and 2022) or later - - Gnu g++ 11.4.0 or later (on Linux or macOS) - - LLVM Clang version 15.0.7 or later (on Linux) - - Apple Clang compiler versions 10.0.1, 12.0.5, and 15.0.0 (on macOS) -- The minimal supported version of Boost is now 1.72.0. -- The CGAL `Core` library is no longer based on GMP, but on [Boost.Multiprecision](https://www.boost.org/doc/libs/1_72_0/libs/multiprecision/doc/html/index.html). Either GMP backend or Boost backend can be used. -- All demos are now based on Qt6. -- **Breaking change**: The CMake file `UseCGAL.cmake` has been removed from CGAL. Usages of the CMake variables `${CGAL_USE_FILE}` and `${CGAL_LIBRARIES}` must be replaced by a link to the imported target `CGAL::CGAL`, for example: `target_link_library(your_target PRIVATE CGAL::CGAL)`. + - Gnu g++ 12.2.0 or later (on Linux) + - LLVM Clang version 20.1.6 or later (on Linux) + - Apple Clang compiler versions 12.0.5 and 12.0.5 (on macOS) +- The minimal supported version of Boost is now 1.74.0. -### [Kinetic Space Partition](https://doc.cgal.org/6.0/Manual/packages.html#PkgKineticSpacePartition) (new package) +### [3D Constrained Triangulations](https://doc.cgal.org/6.1/Manual/packages.html#PkgConstrainedTriangulation3) (new package) -- This package implements kinetic space partition: based on a set of planar input shapes, the bounding box of the input data is split into convex volumes. The complexity of the partition can be adjusted with a single parameter. +- This package implements the construction of a 3D Constrained Delaunay triangulation. This triangulation is a generalization of a 3D Delaunay Triangulation which conforms to the set of faces of a 3D piecewise linear complex (PLC), ensuring that these faces are part of the triangulation. As not all PLCs are tetrahedralizable, the algorithm may insert Steiner points to construct the constrained triangulation. The main entry point is the function [`CGAL::make_conforming_constrained_Delaunay_triangulation_3()`](https://doc.cgal.org/6.1/Constrained_triangulation_3/group__PkgConstrainedTriangulation3FunctionsPolygonSoupOrMesh.html). -### [Kinetic Surface Reconstruction](https://doc.cgal.org/6.0/Manual/packages.html#PkgKineticSurfaceReconstruction) (new package) +### [3D Isosurfacing](https://doc.cgal.org/6.1/Manual/packages.html#PkgIsosurfacing3) (new package) -- The package implements a piece-wise planar surface reconstruction pipeline from point clouds combining methods from the [Shape Detection](https://doc.cgal.org/6.0/Manual/packages.html#PkgShapeDetection), [Shape Regularization](https://doc.cgal.org/6.0/Manual/packages.html#PkgShapeRegularization) and [Kinetic Shape Partition](https://doc.cgal.org/6.0/Manual/packages.html#PkgKineticSpacePartition) packages and graph-cut to reconstruct surfaces from point clouds. +- This package provides algorithms to extract isosurfaces from scalar fields. The algorithms provided in this first version include Marching Cubes, Topologically Correct Marching Cubes, and Dual Contouring. The algorithm is generic with respect to the scalar field representation (implicit function, discrete values, …) and the discretization data structure (Cartesian grid, octree, …). The output is an indexed face set that stores an isosurface in the form of a surface mesh. -### [Basic Viewer](https://doc.cgal.org/6.0/Basic_viewer/index.html#Chapter_Basic_viewer) (new package) +### [dD Fréchet Distance](https://doc.cgal.org/6.1/Manual/packages.html#PkgFrechetDistance) (new package) -- The basic viewer package provides interactive visualization for most CGAL packages, such as [2D Arrangements](https://doc.cgal.org/6.0/Manual/packages.html#PkgArrangementOnSurface2), [2D Regularized Boolean Set-Operations](https://doc.cgal.org/6.0/Manual/packages.html#PkgBooleanSetOperations2), [Linear Cell Complex](https://doc.cgal.org/6.0/Manual/packages.html#PkgLinearCellComplex), [3D Boolean Operations on Nef Polyhedra](https://doc.cgal.org/6.0/Manual/packages.html#PkgNef3), [2D Periodic Triangulations](https://doc.cgal.org/6.0/Manual/packages.html#PkgPeriodic2Triangulation2), [3D Point Set](https://doc.cgal.org/6.0/Manual/packages.html#PkgPointSet3), [2D Polygons](https://doc.cgal.org/6.0/Manual/packages.html#PkgPolygon2), [3D Polyhedral Surface](https://doc.cgal.org/6.0/Manual/packages.html#PkgPolyhedron), [2D Straight Skeleton and Polygon Offsetting](https://doc.cgal.org/6.0/Manual/packages.html#PkgStraightSkeleton2), [Surface Mesh](https://doc.cgal.org/6.0/Manual/packages.html#PkgSurfaceMesh), [2D Triangulations](https://doc.cgal.org/6.0/Manual/packages.html#PkgTriangulation2), [3D Triangulations](https://doc.cgal.org/6.0/Manual/packages.html#PkgTriangulation3), [2D Voronoi Diagrams](https://doc.cgal.org/6.0/Manual/packages.html#PkgVoronoiDiagram2), and more. The most simple use case of the basic viewer is the call of the global `CGAL::draw()` function. There is one such `draw()` function for each CGAL package that has a basic viewer. Such a call opens an interactive window showing the given model and allowing to navigate in the scene, show or hide some specific cells, show the interior of the model if any, etc. The `Basic_viewer` is based on Qt6. +- This package provides functions for computing the Fréchet distance of polylines in any dimension under the Euclidean metric. -### [Polygon Repair](https://doc.cgal.org/6.0/Manual/packages.html#PkgPolygonRepair) (new package) +### [2D Triangulations on Hyperbolic Surfaces](https://doc.cgal.org/6.1/Manual/packages.html#PkgHyperbolicSurfaceTriangulation2) (new package) -- This package provides algorithms to repair 2D polygons, polygons with holes, and multipolygons with holes, by selecting faces of the arrangement of the input using the odd-even heuristic. +- This package enables building and handling triangulations of closed orientable hyperbolic surfaces. It offers functions for the generation of the triangulation from a convex fundamental domain, the Delaunay flip algorithm, and the construction of a portion of the lift of the triangulation in the Poincaré disk. A method is offered that generates such domains in genus two. -### [2D and 3D Linear Geometry Kernel](https://doc.cgal.org/6.0/Manual/packages.html#PkgKernel23) + See also the associated [news entry](https://www.cgal.org/2025/06/24/triangulations-on-hyperbolic-surfaces/). -- **Breaking change**: Replaced all instances of `boost::variant` with `std::variant` in the intersection functions. -- **Breaking change**: Replaced all instances of `boost::optional` with `std::optional` in the intersection functions. +### [Polygon Repair](https://doc.cgal.org/6.1/Manual/packages.html#PkgPolygonRepair) -### [3D Polyhedral Surface](https://doc.cgal.org/6.0/Manual/packages.html#PkgPolyhedron) +- Added the [non-zero rule](https://doc.cgal.org/6.1/Polygon_repair/structCGAL_1_1Polygon__repair_1_1Non__zero__rule.html) (areas with non-zero winding number are kept), as well as two functions to compute the conservative inner and outer hull of similar polygons: + - [`CGAL::Polygon_repair::join()`](https://doc.cgal.org/6.1/Polygon_repair/group__PkgPolygonRepairFunctions.html#gad5b959666d952392c0e3b8d4b1b1847a) + - [`CGAL::Polygon_repair::intersect()`](https://doc.cgal.org/6.1/Polygon_repair/group__PkgPolygonRepairFunctions.html#ga780e31115643e3d0b406349b56c9f3d5) -- The demo of this package, also known as “Polyhedron Demo” has been renamed “CGAL Lab” and moved to its own package (“Lab”). + See also the associated [news entry](https://www.cgal.org/2025/05/22/Polygon_repair/). -### [2D and 3D Fast Intersection and Distance Computation (AABB Tree)](https://doc.cgal.org/6.0/Manual/packages.html#PkgAABBTree) +### [Polygon Mesh Processing](https://doc.cgal.org/6.1/Manual/packages.html#PkgPolygonMeshProcessing) -- The AABB tree can now be used with 2D or 3D primitives: - - The concepts `AABBGeomTraits` and `AABBRayIntersectionGeomTraits` have been replaced by [`AABBGeomTraits_3`](https://doc.cgal.org/6.0/AABB_tree/classAABBGeomTraits__3.html) and by [`AABBRayIntersectionGeomTraits_3`](https://doc.cgal.org/6.0/AABB_tree/classAABBRayIntersectionGeomTraits__3.html), respectively. - - The concepts [`AABBGeomTraits_2`](https://doc.cgal.org/6.0/AABB_tree/classAABBGeomTraits__2.html) and [`AABBRayIntersectionGeomTraits_2`](https://doc.cgal.org/6.0/AABB_tree/classAABBRayIntersectionGeomTraits__2.html) have been introduced, as the 2D counterparts. - - The class [`CGAL::AABB_traits`](https://doc.cgal.org/6.0/AABB_tree/group__PkgAABBTreeRef.html#ga764f0fc59c96355877536810aa1aca5b) is deprecated and replaced by [`CGAL::AABB_traits_3`](https://doc.cgal.org/6.0/AABB_tree/classCGAL_1_1AABB__traits__3.html). - - The class [`CGAL::AABB_traits_2`](https://doc.cgal.org/6.0/AABB_tree/classCGAL_1_1AABB__traits__2.html) is introduced as the 2D counterpart. - - The class [`CGAL::AABB_segment_primitive`](https://doc.cgal.org/6.0/AABB_tree/group__PkgAABBTreeRef.html#gad0acfd5c4a3c081b7570cc6bd4594c8d) has been deprecated and replaced by the class [`CGAL::AABB_segment_primitive_3`](https://doc.cgal.org/6.0/AABB_tree/classCGAL_1_1AABB__segment__primitive__3.html). - - The class [`CGAL::AABB_triangle_primitive`](https://doc.cgal.org/6.0/AABB_tree/group__PkgAABBTreeRef.html#ga54a56f01dc8024624f7d83ee0a01add0) has been deprecated and replaced by the class [`CGAL::AABB_triangle_primitive_3`](https://doc.cgal.org/6.0/AABB_tree/classCGAL_1_1AABB__triangle__primitive__3.html). - - The following 2D primitive classes have been added: [`CGAL::AABB_segment_primitive_2`](https://doc.cgal.org/6.0/AABB_tree/classCGAL_1_1AABB__segment__primitive__2.html), [`CGAL::AABB_polyline_segment_primitive_2`](https://doc.cgal.org/6.0/AABB_tree/classCGAL_1_1AABB__polyline__segment__primitive__2.html), [`CGAL::AABB_triangle_primitive_2`](https://doc.cgal.org/6.0/AABB_tree/classCGAL_1_1AABB__triangle__primitive__2.html), [`CGAL::AABB_indexed_triangle_primitive_2`](https://doc.cgal.org/6.0/AABB_tree/classCGAL_1_1AABB__indexed__triangle__primitive__2.html). -- **Breaking change**: The concept [`AABBTraits`](https://doc.cgal.org/6.0/AABB_tree/classAABBTraits.html) now refines the concept [`SearchTraits`](https://doc.cgal.org/6.0/Spatial_searching/classSearchTraits.html). -- **Breaking change**: Replaced all instances of `boost::optional` with `std::optional`. +- Added the parameter `apply_iterative_snap_rounding` to the function [`CGAL::Polygon_mesh_processing::autorefine_triangle_soup()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__corefinement__grp.html#gaf7747d676c459d9e5da9b13be7d12bb5). When set to `true`, the coordinates are rounded to fit in double and may perform additional subdivisions to ensure the output is free of self-intersections. See also the associated [news entry](https://www.cgal.org/2025/06/13/autorefine-and-snap/). +- Added the function [`CGAL::Polygon_mesh_processing::approximated_centroidal_Voronoi_diagram_remeshing()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PkgPolygonMeshProcessingRef.html#gaed23e63b12c7fe8268927d17b4d379f1) 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. See also the associated [news entry](https://www.cgal.org/2025/05/22/Surface_remeshing/). +- New implementation of [`CGAL::Polygon_mesh_processing::clip()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__corefinement__grp.html#ga2c73d3460872e601f84a03f58dd069ae) and [`CGAL::Polygon_mesh_processing::split()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__corefinement__grp.html#ga6738052411a4d548a5b375f11b913924) with a plane as clipper that is much faster and is now able to handle non-triangulated surface meshes. See also the associated [news entry](https://www.cgal.org/2025/06/06/new_clip/). +- Added the function [`CGAL::Polygon_mesh_processing::refine_with_plane()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__corefinement__grp.html#gacb9d68fa4dea8fd03ec53b56a16d6fc6), which enables users to refine a mesh with its intersection with a plane. +- Added a function in the [visitor of the corefinement based methods](https://doc.cgal.org/6.1/Polygon_mesh_processing/classPMPCorefinementVisitor.html) to trace faces in the output meshes which correspond to coplanar faces of the input. +- Added the function [`CGAL::Polygon_mesh_processing::discrete_mean_curvature()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__measure__grp.html#ga1a31fa9412b4643dc7202a54246db78b) and [`CGAL::Polygon_mesh_processing::discrete_Gaussian_curvature()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__measure__grp.html#ga11a2d646d4636605d185653bff5bbbbb) to evaluate the discrete curvature at a vertex of a mesh. +- Added the function [`CGAL::Polygon_mesh_processing::angle_sum()`](https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__measure__grp.html#ga25d3836c21931610cf76b6716a06254c) to compute the sum of the angles around a vertex. -### [2D Arrangements](https://doc.cgal.org/6.0/Manual/packages.html#PkgArrangementOnSurface2) +### [Point Set Processing](https://doc.cgal.org/6.1/Manual/packages.html#PkgPointSetProcessing3) -- **Breaking change**: Replaced all instances of `boost::variant` with `std::variant`. -- **Breaking change**: The type of the result of point location queries has been changed to `std::variant`. Support for the old macro `CGAL_ARR_POINT_LOCATION_VERSION` has been removed. -- **Breaking change**: Eliminated the error-prone C-type casting that was used to define observers. In general, backward compatibility was maintained; however, the class template [`CGAL::Arr_observer`](https://doc.cgal.org/6.0/Arrangement_on_surface_2/group__PkgArrangementOnSurface2Ref.html#ga8019f986f5469920136c4b92290b7b1b) has been replaced by an alias template. (The class `CGAL::Arr_observer` was renamed to [`CGAL::Aos_observer`](https://doc.cgal.org/6.0/Arrangement_on_surface_2/classCGAL_1_1Aos__observer.html)). -- Introduced [`Arr_dcel`](https://doc.cgal.org/6.0/Arrangement_on_surface_2/classCGAL_1_1Arr__dcel.html), which essentially replaces the former `CGAL::Arr_default_dcel`. Backward compatibility was maintained by the introduction of the alias template [`CGAL::Arr_default_dcel`](https://doc.cgal.org/6.0/Arrangement_on_surface_2/group__PkgArrangementOnSurface2DCEL.html#gaf9635869a3794a46d7dcfce63d7de2a6). `CGAL::Arr_dcel`, as opposed to the former `CGAL::Arr_default_dcel` is templated (in addition to the geometry traits) by `Vertex`, `Halfedge`, and `Face` template parameters, and they have default type values. All this enables the layered extension of DCEL records. -- Fixed a bug in the zone construction code applied to arrangements of geodesic arcs on a sphere, when inserting an arc that lies on the identification curve. -- Introduced a new interactive program that demonstrates 2D arrangements embedded on the sphere called `earth`. The program (i) reads a database of all administrative boundaries of the countries in the world, (ii) displays the globe with all countries and land covered by water (which is land not covered by countries) on a window, and (ii) enables interaction with the user. +- Added [`CGAL::poisson_eliminate()`](https://doc.cgal.org/6.1/Point_set_processing_3/group__PkgPointSetProcessing3Algorithms.html#ga2d73d46ca766656a219bf5e6045b837a), which can be used to downsample a point cloud to a target size while providing Poisson disk property, i.e., a larger minimal distance between points. -### [3D Envelopes](https://doc.cgal.org/6.0/Manual/packages.html#PkgEnvelope3) +### [CGAL and the Boost Graph Library (BGL)](https://doc.cgal.org/6.1/Manual/packages.html#PkgBGL) -- **Breaking change**: [`Construct_projected_boundary_2`](https://doc.cgal.org/6.0/Envelope_3/classEnvelopeTraits__3.html#ac7b8f72870f0572834a0a3de62c67bc1) in [`EnvelopeTraits_3`](https://doc.cgal.org/6.0/Envelope_3/classEnvelopeTraits__3.html) now uses `std::variant` instead of [`CGAL::Object`](https://doc.cgal.org/6.0/STL_Extension/classCGAL_1_1Object.html). -- Passed the base class of [`CGAL::Env_plane_traits_3`](https://doc.cgal.org/6.0/Envelope_3/classCGAL_1_1Env__plane__traits__3.html) as a template parameter with a default value (being the 2D arrangement linear traits). Similarly, passed the base class of `CGAL::Env_triangle_traits_3` as a template parameter with a default value (being the 2D arrangement segment traits). +- Added the function [`dijkstra_shortest_path()`](https://doc.cgal.org/6.1/BGL/group__PkgBGLTraversal.html#gaa4058482db0089886b84a8c6a341e528), which can be used to compute the geometrically shortest sequence of halfedges between two vertices. +- Added the function [`CGAL::Euler::remove_degree_2_vertex()`](https://doc.cgal.org/6.1/BGL/group__PkgBGLEulerOperations.html#gab3455663b7db4624529e54ae3ce2387c), which enables users to remove vertices which have exactly two incident edges. -### [Combinatorial Maps](https://doc.cgal.org/6.0/Manual/packages.html#PkgCombinatorialMaps) and [Generalized Maps](https://doc.cgal.org/6.0/Manual/packages.html#PkgGeneralizedMaps) +### [2D Arrangements](https://doc.cgal.org/6.1/Manual/packages.html#PkgArrangementOnSurface2) -- Added the function [`insert_cell_1_between_two_cells_2()`](https://doc.cgal.org/6.0/Combinatorial_map/classGenericMap.html#aa29570a0812094c7876e24a228373f12) to the [`GenericMap`](https://doc.cgal.org/6.0/Combinatorial_map/classGenericMap.html) concept, which enables users to insert an edge between two different faces in order to create faces with holes. +- **Breaking change**: Renamed the concept `AosApproximateTraits_2` to [`AosApproximatePointTraits_2`](https://doc.cgal.org/6.1/Arrangement_on_surface_2/classAosApproximatePointTraits__2.html) to make room for the new concept [`AosApproximateTraits_2`](https://doc.cgal.org/6.1/Arrangement_on_surface_2/classAosApproximateTraits__2.html). This concept requires the provision of a functor called `Approximate_2` that has an operator that approximates the coordinates of a point. +- **Breaking change**: The concept [`AosApproximateTraits_2`](https://doc.cgal.org/6.1/Arrangement_on_surface_2/classAosApproximateTraits__2.html) now refines the concept [`AosApproximatePointTraits_2`](https://doc.cgal.org/6.1/Arrangement_on_surface_2/classAosApproximatePointTraits__2.html) and 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. +- Renamed the prefix of the names of all concepts in the Arrangement_on_surface_2 package from “Arrangement” to “Aos”. +- Introduced two traits decorators, namely [`CGAL::Arr_tracing_traits_2`](https://doc.cgal.org/6.1/Arrangement_on_surface_2/classCGAL_1_1Arr__tracing__traits__2.html) and [`CGAL::Arr_counting_traits_2`](https://doc.cgal.org/6.1/Arrangement_on_surface_2/classCGAL_1_1Arr__counting__traits__2.html), 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. +- Fixed `do_intersect()` of a 2D Arrangement with a curve. -- Added new meshing criterion `edge_distance`, an upper bound for the distance from the edge to the 1D feature. +### Triangulations -- **Breaking change**: the concept `MeshEdgeCriteria_3` was modified to include the new meshing criterion `edge_distance`. +- All triangulations now offer the functions `point(Vertex_handle)` and `point(Simplex, int)`, which enables users to access the geometric position of a vertex and of the i-th vertex of a simplex of a triangulation. -### [Quadtrees, Octrees, and Orthtrees](https://doc.cgal.org/6.0/Manual/packages.html#PkgOrthtree) +### [Poisson Surface Reconstruction](https://doc.cgal.org/6.1/Manual/packages.html#PkgPoissonSurfaceReconstruction3) -- **Breaking change**: - - Node splitting behavior and per-node data are now customizable via the Traits class. - - Nodes are now stored as a property map, with properties of each node accessed by index. - - Nearest neighbors functions only work for Orthtrees which provide the necessary functionality. +- Added a new mesh domain `Poisson_mesh_domain_3` that integrates some optimizations from the deprecated 3D Surface Mesh Generation package. -### [CGAL and the Boost Graph Library (BGL)](https://doc.cgal.org/6.0/Manual/packages.html#PkgBGL) +### [2D Triangulations](https://doc.cgal.org/6.1/Manual/packages.html#PkgTriangulation2) -- Added the function [`CGAL::remove_all_elements()`](https://doc.cgal.org/6.0/BGL/group__PkgBGLHelperFct.html#gac7e199820c95ed1fc6ab536750749358), which removes vertices, halfedges, and faces without collecting garbage and without removing properties. -- [Dynamic property maps](https://doc.cgal.org/6.0/BGL/group__PkgBGLPropertiesDynamic.html) can now have a default value. -- The class [`CGAL::Face_filtered_graph`](https://doc.cgal.org/6.0/BGL/structCGAL_1_1Face__filtered__graph.html) now supports patch IDs of any type and not just `faces_size_type`. The only requirement is that the type is hashable. +- **Breaking change**: In the class template [`Constrained_triangulation_plus_2`](https://doc.cgal.org/6.1/Triangulation_2/classCGAL_1_1Constrained__triangulation__plus__2.html), the value type of the range returned by [`subconstraints()`](https://doc.cgal.org/6.1/Triangulation_2/classCGAL_1_1Constrained__triangulation__plus__2.html#af25114a7e1675194367f8f9de9de90d2) has changed from `const std::pair*>` to `Subconstraint`. The old range type is now returned by a new function named `subconstraints_and_contexts()`. -### [Polygon Mesh Processing](https://doc.cgal.org/6.0/Manual/packages.html#PkgPolygonMeshProcessing) +### [3D Mesh Generation](https://doc.cgal.org/6.1/Manual/packages.html#PkgMesh3) -- Added the function [`CGAL::Polygon_mesh_processing::autorefine_triangle_soup()`](https://doc.cgal.org/6.0/Polygon_mesh_processing/group__PMP__corefinement__grp.html#gaec85370aa0b2acc0919e5f8406cfb74c), which can be used to refine a soup of triangles such that no pair of triangles intersects in their interiors. Also added, the function [`CGAL::Polygon_mesh_processing::autorefine()`](https://doc.cgal.org/6.0/Polygon_mesh_processing/group__PMP__corefinement__grp.html#ga3e3a0a82b6c04bdc3a6c070e8da4aed5) operating directly on a triangle mesh and updating it using the aforementioned function on a triangle soup. -- Added the class [`CGAL::Corefinement::Non_manifold_output_visitor`](https://doc.cgal.org/6.0/Polygon_mesh_processing/structCGAL_1_1Polygon__mesh__processing_1_1Corefinement_1_1Non__manifold__output__visitor.html), which can be used in corefinement based functions to deal with non-manifold outputs. -- Added the option to use a variable sizing field for [`CGAL::Polygon_mesh_processing::isotropic_remeshing()`](https://doc.cgal.org/6.0/Polygon_mesh_processing/group__PMP__meshing__grp.html#ga66cb01cf228ed22f0a2a474cfa2aeb3f), and a sizing function based on a measure of local curvature for adaptive remeshing. -- Added the function [`CGAL::Polygon_mesh_processing::interpolated_corrected_curvatures()`](https://doc.cgal.org/6.0/Polygon_mesh_processing/group__PMP__corrected__curvatures__grp.html#ga22665c9ce92aaedab07df1b05f20bdb2) which can be used to compute the mean and Gaussian curvatures, as well as the principal curvature and directions. -- Added the function [`CGAL::Polygon_mesh_processing::refine_mesh_at_isolevel()`](https://doc.cgal.org/6.0/Polygon_mesh_processing/group__PkgPolygonMeshProcessingRef.html#ga396505d5a60b5f6d29792b214fa59352) which can be used to refine a polygon mesh along an isocurve. -- Added the function [`CGAL::Polygon_mesh_processing::add_bbox()`](https://doc.cgal.org/6.0/Polygon_mesh_processing/group__PkgPolygonMeshProcessingRef.html#gabaf98d2fd9ae599ff1f3a5a6cde79cf3), which enables adding a tight or extended, triangulated or not, bounding box to a face graph. +- Added two new meshing parameters that enable custom mesh initialization: +- [`initial_points_generator`](https://doc.cgal.org/6.1/Mesh_3/group__PkgMesh3Parameters.html#gaf53777b83f1b2f3e7d49275dbab6e46b): enables the user to specify a functor that generates initial points, +- [`initial_points`](https://doc.cgal.org/6.1/Mesh_3/group__PkgMesh3Parameters.html#gaf26d164d1845dcd66dc4861b6920b5ec): enables the user to specify a `Range` of initial points. +- Added a new meshing parameter [`surface_only`](https://doc.cgal.org/6.1/Mesh_3/group__PkgMesh3Parameters.html#gaa2618c09b6117d7caab12dccca16ee58), which can be used to improve performance when only surface mesh generation is sought. +- Added a new mesh domain [`Poisson_mesh_domain_3`](https://doc.cgal.org/6.1/Poisson_surface_reconstruction_3/classCGAL_1_1Poisson__mesh__domain__3.html), which should be used when generating a mesh from a Poisson surface obtained with the package [Poisson Surface Reconstruction](https://doc.cgal.org/6.1/Manual/packages.html#PkgPoissonSurfaceReconstruction3). This mesh domain re-integrates some optimizations for Poisson surface mesh generation that were lost when the package [3D Mesh Generation](https://doc.cgal.org/6.1/Manual/packages.html#PkgMesh3) had to be replaced instead of the deprecated package [3D Surface Mesh Generation](https://doc.cgal.org/latest/Manual/packages.html#PkgSurfaceMesher3). -### [2D Triangulations](https://doc.cgal.org/6.0/Manual/packages.html#PkgTriangulation2) +### [3D Subdivision Methods](https://doc.cgal.org/6.1/Manual/packages.html#PkgSurfaceSubdivisionMethod3) -- **Breaking change**: the concept [`TriangulationTraits_2`](https://doc.cgal.org/6.0/Triangulation_2/classTriangulationTraits__2.html) now requires an additional functor `Compare_xy_2`. +- Added a new named parameter for [`CGAL::Subdivision_method_3::Loop_subdivision()`](https://doc.cgal.org/6.1/Subdivision_method_3/group__PkgSurfaceSubdivisionMethod3Functions.html#gafa1e441c4e07eb06e1f6efecef7ff268) and [`CGAL::Subdivision_method_3::CatmullClark_subdivision()`](https://doc.cgal.org/6.1/Subdivision_method_3/group__PkgSurfaceSubdivisionMethod3Functions.html#ga8e6c8dd3c26d7a27c070b3a091684679), which enables users to subdivide a mesh without modifying its geometry. -### [3D Triangulations](https://doc.cgal.org/6.0/Manual/packages.html#PkgTriangulation3) +### [Algebraic Kernel](https://doc.cgal.org/6.1/Manual/packages.html#PkgAlgebraicKernelD) -- Added three member functions [`vertices()`](https://doc.cgal.org/6.0/Triangulation_3/classCGAL_1_1Triangulation__3.html#a02faf334255e1ca8caa1a6f412533759) to the class [`CGAL::Triangulation_3`](https://doc.cgal.org/6.0/Triangulation_3/classCGAL_1_1Triangulation__3.html). Each of them returns an array containing the vertices of the given triangulation simplex. - -### [dD Triangulations](https://doc.cgal.org/6.0/Manual/packages.html#PkgTriangulations) - -- **Breaking change**: `CGAL::TDS_full_cell_mirror_storage_policy` is now unsupported in dimension larger than 127. -- **Breaking change**: Inserting multiple unweighted points in the same position now keeps the first one, instead of switching to the latest. This only affects custom point types where not all points in the same position are equivalent. - -### [Tetrahedral Remeshing](https://doc.cgal.org/6.0/Manual/packages.html#PkgTetrahedralRemeshing) - -- Added a sizing field as new parameter of [`CGAL::tetrahedral_isotropic_remeshing()`](https://doc.cgal.org/6.0/Tetrahedral_remeshing/group__PkgTetrahedralRemeshingRef.html#ga263775c52eeb483a86a16aeb9eb31af0), which can be used to perform non-uniform and adaptive remeshing. -- **Breaking change**: The template parameters of [`CGAL::Tetrahedral_remeshing::Remeshing_cell_base_3`](https://doc.cgal.org/6.0/Tetrahedral_remeshing/classCGAL_1_1Tetrahedral__remeshing_1_1Remeshing__cell__base__3.html) have been modified, reverting changes introduced in CGAL 5.6. -- **Breaking change**: The vertex base of [`CGAL::Tetrahedral_remeshing::Remeshing_vertex_base_3`](https://doc.cgal.org/6.0/Tetrahedral_remeshing/classCGAL_1_1Tetrahedral__remeshing_1_1Remeshing__vertex__base__3.html) must now be a model of the concept [`SimplicialMeshVertexBase_3`](https://doc.cgal.org/6.0/SMDS_3/classSimplicialMeshVertexBase__3.html) (and not only [`TriangulationVertexBase_3`](https://doc.cgal.org/6.0/Triangulation_3/classTriangulationVertexBase__3.html)). - -### [3D Simplicial Mesh Data Structure](https://doc.cgal.org/6.0/Manual/packages.html#PkgSMDS3) - -- **Breaking change**: The template parameters of [`CGAL::Simplicial_mesh_cell_base_3`](https://doc.cgal.org/6.0/SMDS_3/classCGAL_1_1Simplicial__mesh__cell__base__3.html) have been modified to enable passing a geometric traits and a custom cell base class. - -### [3D Mesh Generation](https://doc.cgal.org/6.0/Manual/packages.html#PkgMesh3) - -- **Breaking change**: Removed the concept `TriangleAccessor`, the template parameter `TriangleAccessor`, as well as the class `Triangle_accessor`. These were no longer used for several releases. -- **Breaking change**: Removed the class templates `CGAL::Gray_image_mesh_domain_3`, `CGAL::Implicit_mesh_domain_3`, and `CGAL::Labeled_image_mesh_domain_3`, which were deprecated since CGAL-4.13. - -### [3D Surface Mesh Generation](https://doc.cgal.org/6.0/Manual/packages.html#PkgSurfaceMesher3) - -- This package is deprecated and the package [3D Mesh Generation](https://doc.cgal.org/6.0/Manual/packages.html#PkgMesh3) should be used instead. - -### [Surface Mesh Parameterization](https://doc.cgal.org/6.0/Manual/packages.html#PkgSurfaceMeshParameterization) - -- **Breaking change**: The method [`CGAL::Surface_mesh_parameterization::LSCM_parameterizer_3`](https://doc.cgal.org/6.0/Surface_mesh_parameterization/classCGAL_1_1Surface__mesh__parameterization_1_1LSCM__parameterizer__3.html) now requires the Eigen library. -- **Breaking change**: CGAL no longer ships its own version of OpenNL. - -### [Surface Mesh](https://doc.cgal.org/6.0/Manual/packages.html#PkgSurfaceMesh) - -- **Breaking change**: The return type of [`CGAL::Surface_mesh::property_map()`](https://doc.cgal.org/6.0/Surface_mesh/classCGAL_1_1Surface__mesh.html#afc99c7ea179dc1c21a2ab59ed183184a) has been changed to `std::optional`. - -### [3D Point Set](https://doc.cgal.org/6.0/Manual/packages.html#PkgPointSet3) - -- **Breaking change**: The return type of [`CGAL::Point_set_3::property_map()`](https://doc.cgal.org/6.0/Point_set_3/classCGAL_1_1Point__set__3.html#a571ecc603cd32d78c7effaf86fe120ad) has been changed to `std::optional`. - -### [Shape Detection](https://doc.cgal.org/6.0/Manual/packages.html#PkgShapeDetection) - -- **Breaking change**: Replaced all instances of `boost::shared_ptr` with `std::shared_ptr`. - -### [2D Straight Skeleton and Polygon Offsetting](https://doc.cgal.org/6.0/Manual/packages.html#PkgStraightSkeleton2) - -- **Breaking change**: Replaced all instances of `boost::shared_ptr` with `std::shared_ptr`. -- **Breaking change**: Replaced all instances of `boost::optional` with `std::optional`. +- **Breaking change**: Classes based on the RS Library are no longer provided. diff --git a/Maintenance/public_release/announcement/mailing-beta.eml b/Maintenance/public_release/announcement/mailing-beta.eml index fba33a225f0..449487be3bb 100644 --- a/Maintenance/public_release/announcement/mailing-beta.eml +++ b/Maintenance/public_release/announcement/mailing-beta.eml @@ -1,298 +1,205 @@ -Subject: CGAL 6.0 Beta 1 Released, Computational Geometry Algorithms Library +Subject: CGAL 6.1 Beta 1 Released, Computational Geometry Algorithms Library Content-Type: text/plain; charset="utf-8" Body: The CGAL Open Source Project is pleased to announce the release -6.0 Beta 1 of CGAL, the Computational Geometry Algorithms Library. +of CGAL 6.1 Beta 1, the Computational Geometry Algorithms Library. -CGAL version 6.0 Beta 1 is a public testing release. It should provide a -solid ground to report bugs that need to be tackled before the release -of the final version of CGAL 6.0 in July 2024. +CGAL version 6.1 Beta 1 is a public testing release. We encourage you to +use it and report any bugs that should be addressed before the final +release of CGAL 6.1 in September 2025. -Besides fixes and general enhancement to existing packages, the -following has changed since CGAL 5.6: +This CGAL version was actually published two days ago on GitHub, at + https://github.com/CGAL/cgal/releases +However, the CGAL website has been unavailable for a few days due to an +unusual incident at our hosting provider. + +Besides fixes and general enhancements to existing packages, the +following has changed since CGAL 6.0: General Changes -- CGAL 6.0 is the first release of CGAL that requires a C++ compiler - with the support of C++17 or later. The new list of supported - compilers is: +- The new list of supported compilers is: - Visual C++ 15.9, 16.10, 17.0 (from Visual Studio 2017, 2019 and 2022) or later - - Gnu g++ 11.4.0 or later (on Linux or macOS) - - LLVM Clang version 15.0.7 or later (on Linux) - - Apple Clang compiler versions 10.0.1, 12.0.5, and 15.0.0 (on - macOS) -- The minimal supported version of Boost is now 1.72.0. -- The CGAL Core library is no longer based on GMP, but on - Boost.Multiprecision. Either GMP backend or Boost backend can be - used. -- All demos are now based on Qt6. -- Breaking change: The CMake file UseCGAL.cmake has been removed from - CGAL. Usages of the CMake variables ${CGAL_USE_FILE} and - ${CGAL_LIBRARIES} must be replaced by a link to the imported target - CGAL::CGAL, for example: - target_link_library(your_target PRIVATE CGAL::CGAL). + - Gnu g++ 12.2.0 or later (on Linux) + - LLVM Clang version 20.1.6 or later (on Linux) + - Apple Clang compiler versions 12.0.5 and 12.0.5 (on macOS) +- The minimal supported version of Boost is now 1.74.0. -Kinetic Space Partition (new package) +3D Constrained Triangulations (new package) -- This package implements kinetic space partition: based on a set of - planar input shapes, the bounding box of the input data is split - into convex volumes. The complexity of the partition can be adjusted - with a single parameter. +- This package implements the construction of a 3D Constrained + Delaunay triangulation. This triangulation is a generalization of a + 3D Delaunay Triangulation which conforms to the set of faces of a 3D + piecewise linear complex (PLC), ensuring that these faces are part + of the triangulation. As not all PLCs are tetrahedralizable, the + algorithm may insert Steiner points to construct the constrained + triangulation. The main entry point is the function + CGAL::make_conforming_constrained_Delaunay_triangulation_3(). -Kinetic Surface Reconstruction (new package) +3D Isosurfacing (new package) -- The package implements a piece-wise planar surface reconstruction - pipeline from point clouds combining methods from the Shape - Detection, Shape Regularization and Kinetic Shape Partition packages - and graph-cut to reconstruct surfaces from point clouds. +- This package provides algorithms to extract isosurfaces from scalar + fields. The algorithms provided in this first version include + Marching Cubes, Topologically Correct Marching Cubes, and Dual + Contouring. The algorithm is generic with respect to the scalar + field representation (implicit function, discrete values, …) and the + discretization data structure (Cartesian grid, octree, …). The + output is an indexed face set that stores an isosurface in the form + of a surface mesh. -Basic Viewer (new package) +dD Fréchet Distance (new package) -- The basic viewer package provides interactive visualization for most - CGAL packages, such as 2D Arrangements, 2D Regularized Boolean - Set-Operations, Linear Cell Complex, 3D Boolean Operations on Nef - Polyhedra, 2D Periodic Triangulations, 3D Point Set, 2D Polygons, 3D - Polyhedral Surface, 2D Straight Skeleton and Polygon Offsetting, - Surface Mesh, 2D Triangulations, 3D Triangulations, 2D Voronoi - Diagrams, and more. The most simple use case of the basic viewer is - the call of the global CGAL::draw() function. There is one such - draw() function for each CGAL package that has a basic viewer. Such - a call opens an interactive window showing the given model and - allowing to navigate in the scene, show or hide some specific cells, - show the interior of the model if any, etc. The Basic_viewer is - based on Qt6. +- This package provides functions for computing the Fréchet distance + of polylines in any dimension under the Euclidean metric. -Polygon Repair (new package) +2D Triangulations on Hyperbolic Surfaces (new package) -- This package provides algorithms to repair 2D polygons, polygons - with holes, and multipolygons with holes, by selecting faces of the - arrangement of the input using the odd-even heuristic. +- This package enables building and handling triangulations of closed + orientable hyperbolic surfaces. It offers functions for the + generation of the triangulation from a convex fundamental domain, + the Delaunay flip algorithm, and the construction of a portion of + the lift of the triangulation in the Poincaré disk. A method is + offered that generates such domains in genus two. -2D and 3D Linear Geometry Kernel + See also the associated news entry. -- Breaking change: Replaced all instances of boost::variant with - std::variant in the intersection functions. -- Breaking change: Replaced all instances of boost::optional with - std::optional in the intersection functions. +Polygon Repair -3D Polyhedral Surface +- Added the non-zero rule (areas with non-zero winding number are + kept), as well as two functions to compute the conservative inner + and outer hull of similar polygons: + - CGAL::Polygon_repair::join() + - CGAL::Polygon_repair::intersect() -- The demo of this package, also known as “Polyhedron Demo” has been - renamed “CGAL Lab” and moved to its own package (“Lab”). - -2D and 3D Fast Intersection and Distance Computation (AABB Tree) - -- The AABB tree can now be used with 2D or 3D primitives: - - The concepts AABBGeomTraits and AABBRayIntersectionGeomTraits - have been replaced by AABBGeomTraits_3 and by - AABBRayIntersectionGeomTraits_3, respectively. - - The concepts AABBGeomTraits_2 and - AABBRayIntersectionGeomTraits_2 have been introduced, as the 2D - counterparts. - - The class CGAL::AABB_traits is deprecated and replaced by - CGAL::AABB_traits_3. - - The class CGAL::AABB_traits_2 is introduced as the 2D - counterpart. - - The class CGAL::AABB_segment_primitive has been deprecated and - replaced by the class CGAL::AABB_segment_primitive_3. - - The class CGAL::AABB_triangle_primitive has been deprecated and - replaced by the class CGAL::AABB_triangle_primitive_3. - - The following 2D primitive classes have been added: - CGAL::AABB_segment_primitive_2, - CGAL::AABB_polyline_segment_primitive_2, - CGAL::AABB_triangle_primitive_2, - CGAL::AABB_indexed_triangle_primitive_2. -- Breaking change: The concept AABBTraits now refines the concept - SearchTraits. -- Breaking change: Replaced all instances of boost::optional with - std::optional. - -2D Arrangements - -- Breaking change: Replaced all instances of boost::variant with - std::variant. -- Breaking change: The type of the result of point location queries - has been changed to std::variant. Support for the old macro - CGAL_ARR_POINT_LOCATION_VERSION has been removed. -- Breaking change: Eliminated the error-prone C-type casting that was - used to define observers. In general, backward compatibility was - maintained; however, the class template CGAL::Arr_observer has been - replaced by an alias template. (The class CGAL::Arr_observer was - renamed to CGAL::Aos_observer). -- Introduced Arr_dcel, which essentially replaces the former - CGAL::Arr_default_dcel. Backward compatibility was maintained by the - introduction of the alias template CGAL::Arr_default_dcel. - CGAL::Arr_dcel, as opposed to the former CGAL::Arr_default_dcel is - templated (in addition to the geometry traits) by Vertex, Halfedge, - and Face template parameters, and they have default type values. All - this enables the layered extension of DCEL records. -- Fixed a bug in the zone construction code applied to arrangements of - geodesic arcs on a sphere, when inserting an arc that lies on the - identification curve. -- Introduced a new interactive program that demonstrates 2D - arrangements embedded on the sphere called earth. The program (i) - reads a database of all administrative boundaries of the countries - in the world, (ii) displays the globe with all countries and land - covered by water (which is land not covered by countries) on a - window, and (ii) enables interaction with the user. - -3D Envelopes - -- Breaking change: Construct_projected_boundary_2 in EnvelopeTraits_3 - now uses std::variant instead of CGAL::Object. -- Passed the base class of CGAL::Env_plane_traits_3 as a template - parameter with a default value (being the 2D arrangement linear - traits). Similarly, passed the base class of - CGAL::Env_triangle_traits_3 as a template parameter with a default - value (being the 2D arrangement segment traits). - -Combinatorial Maps and Generalized Maps - -- Added the function insert_cell_1_between_two_cells_2() to the - GenericMap concept, which enables users to insert an edge between - two different faces in order to create faces with holes. - -- Added new meshing criterion edge_distance, an upper bound for the - distance from the edge to the 1D feature. - -- Breaking change: the concept MeshEdgeCriteria_3 was modified to - include the new meshing criterion edge_distance. - -Quadtrees, Octrees, and Orthtrees - -- Breaking change: - - Node splitting behavior and per-node data are now customizable - via the Traits class. - - Nodes are now stored as a property map, with properties of each - node accessed by index. - - Nearest neighbors functions only work for Orthtrees which - provide the necessary functionality. - -CGAL and the Boost Graph Library (BGL) - -- Added the function CGAL::remove_all_elements(), which removes - vertices, halfedges, and faces without collecting garbage and - without removing properties. -- Dynamic property maps can now have a default value. -- The class CGAL::Face_filtered_graph now supports patch IDs of any - type and not just faces_size_type. The only requirement is that the - type is hashable. + See also the associated news entry. Polygon Mesh Processing +- Added the parameter apply_iterative_snap_rounding to the function + CGAL::Polygon_mesh_processing::autorefine_triangle_soup(). When set + to true, the coordinates are rounded to fit in double and may + perform additional subdivisions to ensure the output is free of + self-intersections. See also the associated news entry. - Added the function - CGAL::Polygon_mesh_processing::autorefine_triangle_soup(), which can - be used to refine a soup of triangles such that no pair of triangles - intersects in their interiors. Also added, the function - CGAL::Polygon_mesh_processing::autorefine() operating directly on a - triangle mesh and updating it using the aforementioned function on a - triangle soup. -- Added the class CGAL::Corefinement::Non_manifold_output_visitor, - which can be used in corefinement based functions to deal with - non-manifold outputs. -- Added the option to use a variable sizing field for - CGAL::Polygon_mesh_processing::isotropic_remeshing(), and a sizing - function based on a measure of local curvature for adaptive - remeshing. + 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. See also the associated news entry. +- New implementation of CGAL::Polygon_mesh_processing::clip() and + CGAL::Polygon_mesh_processing::split() with a plane as clipper that + is much faster and is now able to handle non-triangulated surface + meshes. See also the associated news entry. - Added the function - CGAL::Polygon_mesh_processing::interpolated_corrected_curvatures() - which can be used to compute the mean and Gaussian curvatures, as - well as the principal curvature and directions. + CGAL::Polygon_mesh_processing::refine_with_plane(), which enables + users to refine a mesh with its intersection with a plane. +- Added a function in the visitor of the corefinement based methods to + trace faces in the output meshes which correspond to coplanar faces + of the input. - Added the function - CGAL::Polygon_mesh_processing::refine_mesh_at_isolevel() which can - be used to refine a polygon mesh along an isocurve. -- Added the function CGAL::Polygon_mesh_processing::add_bbox(), which - enables adding a tight or extended, triangulated or not, bounding - box to a face graph. + CGAL::Polygon_mesh_processing::discrete_mean_curvature() and + CGAL::Polygon_mesh_processing::discrete_Gaussian_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. + +Point Set Processing + +- Added CGAL::poisson_eliminate(), which can be used to downsample a + point cloud to a target size while providing Poisson disk property, + i.e., a larger minimal distance between points. + +CGAL and the Boost Graph Library (BGL) + +- Added the function dijkstra_shortest_path(), which can be used to + compute the geometrically shortest sequence of halfedges between two + vertices. +- Added the function CGAL::Euler::remove_degree_2_vertex(), which + enables users to remove vertices which have exactly two incident + edges. + +2D Arrangements + +- Breaking change: Renamed the 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. +- Breaking change: The concept AosApproximateTraits_2 now refines the + concept AosApproximatePointTraits_2 and 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. +- Renamed the prefix of the names of all concepts in the + Arrangement_on_surface_2 package from “Arrangement” to “Aos”. +- Introduced two traits decorators, namely CGAL::Arr_tracing_traits_2 + and CGAL::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. +- Fixed do_intersect() of a 2D Arrangement with a curve. + +Triangulations + +- All triangulations now offer the functions point(Vertex_handle) and + point(Simplex, int), which enables users to access the geometric + position of a vertex and of the i-th vertex of a simplex of a + triangulation. + +Poisson Surface Reconstruction + +- Added a new mesh domain Poisson_mesh_domain_3 that integrates some + optimizations from the deprecated 3D Surface Mesh Generation + package. 2D Triangulations -- Breaking change: the concept TriangulationTraits_2 now requires an - additional functor Compare_xy_2. - -3D Triangulations - -- Added three member functions vertices() to the class - CGAL::Triangulation_3. Each of them returns an array containing the - vertices of the given triangulation simplex. - -dD Triangulations - -- Breaking change: CGAL::TDS_full_cell_mirror_storage_policy is now - unsupported in dimension larger than 127. -- Breaking change: Inserting multiple unweighted points in the same - position now keeps the first one, instead of switching to the - latest. This only affects custom point types where not all points in - the same position are equivalent. - -Tetrahedral Remeshing - -- Added a sizing field as new parameter of - CGAL::tetrahedral_isotropic_remeshing(), which can be used to - perform non-uniform and adaptive remeshing. -- Breaking change: The template parameters of - CGAL::Tetrahedral_remeshing::Remeshing_cell_base_3 have been - modified, reverting changes introduced in CGAL 5.6. -- Breaking change: The vertex base of - CGAL::Tetrahedral_remeshing::Remeshing_vertex_base_3 must now be a - model of the concept SimplicialMeshVertexBase_3 (and not only - TriangulationVertexBase_3). - -3D Simplicial Mesh Data Structure - -- Breaking change: The template parameters of - CGAL::Simplicial_mesh_cell_base_3 have been modified to enable - passing a geometric traits and a custom cell base class. +- 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(). 3D Mesh Generation -- Breaking change: Removed the concept TriangleAccessor, the template - parameter TriangleAccessor, as well as the class Triangle_accessor. - These were no longer used for several releases. -- Breaking change: Removed the class templates - CGAL::Gray_image_mesh_domain_3, CGAL::Implicit_mesh_domain_3, and - CGAL::Labeled_image_mesh_domain_3, which were deprecated since - CGAL-4.13. +- Added two new meshing parameters that enable custom mesh + initialization: +- 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, which can be used to + improve performance when only surface mesh generation is sought. +- Added a new mesh domain Poisson_mesh_domain_3, which should be used + when generating a mesh from a Poisson surface obtained with the + package Poisson Surface Reconstruction. This mesh domain + re-integrates some optimizations for Poisson surface mesh generation + that were lost when the package 3D Mesh Generation had to be + replaced instead of the deprecated package 3D Surface Mesh + Generation. -3D Surface Mesh Generation +3D Subdivision Methods -- This package is deprecated and the package 3D Mesh Generation should - be used instead. +- 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. -Surface Mesh Parameterization +Algebraic Kernel -- Breaking change: The method - CGAL::Surface_mesh_parameterization::LSCM_parameterizer_3 now - requires the Eigen library. -- Breaking change: CGAL no longer ships its own version of OpenNL. - -Surface Mesh - -- Breaking change: The return type of - CGAL::Surface_mesh::property_map() has been changed to - std::optional. - -3D Point Set - -- Breaking change: The return type of - CGAL::Point_set_3::property_map() has been changed to std::optional. - -Shape Detection - -- Breaking change: Replaced all instances of boost::shared_ptr with - std::shared_ptr. - -2D Straight Skeleton and Polygon Offsetting - -- Breaking change: Replaced all instances of boost::shared_ptr with - std::shared_ptr. -- Breaking change: Replaced all instances of boost::optional with - std::optional. +- Breaking change: Classes based on the RS Library are no longer + provided. -See https://www.cgal.org/2024/06/21/cgal60-beta1/ for a +See https://www.cgal.org/2025/07/07/cgal61-beta1/ for a complete list of changes. diff --git a/Maintenance/public_release/scripts/github-release-upload b/Maintenance/public_release/scripts/github-release-upload index 8a253f112bd..02d0311ee5e 100755 --- a/Maintenance/public_release/scripts/github-release-upload +++ b/Maintenance/public_release/scripts/github-release-upload @@ -6,5 +6,5 @@ release=${${PWD:t}/CGAL-/} tag=v${release} -gh release upload "$tag" *.(zip|xz|txt|exe) -R CGAL/cgal -gh release upload "$tag" CGAL-${release}-win64-auxiliary-libraries-gmp-mpfr.zip'#GMP and MPFR libraries, for Windows 64bits' -R CGAL/cgal --clobber +gh release upload --clobber "$tag" *.(zip|xz|txt|exe) -R CGAL/cgal +gh release upload --clobber "$tag" CGAL-${release}-win64-auxiliary-libraries-gmp-mpfr.zip'#GMP and MPFR libraries, for Windows 64bits' -R CGAL/cgal --clobber diff --git a/Maintenance/test_handling/Summary_Script.js b/Maintenance/test_handling/Summary_Script.js index bde8e5d2adb..19090bfd7c0 100644 --- a/Maintenance/test_handling/Summary_Script.js +++ b/Maintenance/test_handling/Summary_Script.js @@ -5,7 +5,18 @@ let release = ""; let packages = []; function getAllTestDirectories(data) { - return data.platforms.flatMap(platform => platform.test_directories.map(directory => directory.test_directory)); + if (!data || !data.platforms) return []; + return data.platforms + .filter(platform => platform && platform.test_directories) + .flatMap(platform => { + try { + return platform.test_directories.map(directory => directory?.test_directory || '') + .filter(dir => dir); + } catch (e) { + console.warn(`Error processing test directories for platform: `, platform); + return []; + } + }); } function clearPackagesOptions() { @@ -171,7 +182,7 @@ function platformContainer(platforms) { platforms.forEach(platform => { const $container = $('
    ', { class: 'platform ' + platform.name }).appendTo($platformContainer); $container.html(`

    Results of ${platform.name}

    `); - const tplArray = platform.third_party_libs; + const tplArray = platform.third_party_libs || []; const $toggleButton = $('