From 069756ba3c350880c8d8e10bb57952999c528c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 21 Jul 2023 09:55:01 +0200 Subject: [PATCH 01/35] Fix not being able to Rebind multiple time SMDS_3 / Tet Remesh Vb/Cb If you have the following construct: class V : public Vb; class V_base { struct Rebind --> V; } then you cannot rebind twice. More vicious, if Vb can rebind twice multiple times (e.g. it's a T3 Vb), then it'll silently drop V in the stack, and rebind only up to the rebound Vb! Rebinding multiple times happens for example in Triangulation_hierarchy_3 (Delaunay_triangulation_3 with Fast_locate). --- .../CGAL/Simplicial_mesh_cell_base_3.h | 123 +++++++-------- .../CGAL/Simplicial_mesh_vertex_base_3.h | 142 +++++++++--------- .../Remeshing_cell_base_3.h | 61 ++++---- .../Remeshing_vertex_base_3.h | 15 +- 4 files changed, 158 insertions(+), 183 deletions(-) diff --git a/SMDS_3/include/CGAL/Simplicial_mesh_cell_base_3.h b/SMDS_3/include/CGAL/Simplicial_mesh_cell_base_3.h index ad535d2e402..3c882ad9b52 100644 --- a/SMDS_3/include/CGAL/Simplicial_mesh_cell_base_3.h +++ b/SMDS_3/include/CGAL/Simplicial_mesh_cell_base_3.h @@ -32,11 +32,46 @@ namespace CGAL { +/*! +\ingroup PkgSMDS3Classes + +The class `Simplicial_mesh_cell_base_3` +is a model of the concept `SimplicialMeshCellBase_3`. +It is designed to serve as cell base class for 3D simplicial mesh data structures. +It stores and gives access to data about the complex the cell belongs to, such as the +subdomain it belongs to or surface it takes part to. + +\tparam Gt is the geometric traits class. +It must be a model of the concept `TriangulationTraits_3` + +\tparam SubdomainIndex Type of indices for subdomains of the discretized geometric domain. +Must be a model of `CopyConstructible`, `Assignable`, `DefaultConstructible` +and `EqualityComparable`. The default constructed value must match the label +of the exterior of the domain (which contains at least the unbounded component). +It must match `MeshDomain_3::Subdomain_index` when used for mesh generation. + +\tparam SurfacePatchIndex Type of indices for surface patches (boundaries and interfaces) +of the discretized geometric domain. +Must be a model of `CopyConstructible`, `Assignable`, `DefaultConstructible` +and `EqualityComparable`. The default constructed value must be the index value +assigned to a non surface facet. +It must match `MeshDomain_3::Surface_patch_index` when used for mesh generation. + +\tparam Cb is the cell base class from which `Simplicial_mesh_cell_base_3` derives. +It must be a model of the concept `TriangulationCellBase_3`. + +\cgalModels `SimplicialMeshCellBase_3` + +\sa `CGAL::Mesh_complex_3_in_triangulation_3` +\sa \link Mesh_cell_base_3 `CGAL::Mesh_cell_base_3`\endlink +\sa `MeshDomain_3` +\sa `MeshDomainWithFeatures_3` +*/ template -class Simplicial_mesh_cell_3 + typename Cb = Triangulation_cell_base_3 > +class Simplicial_mesh_cell_base_3 : public Cb { public: @@ -50,11 +85,22 @@ public: using Surface_patch_index = SurfacePatchIndex; public: - Simplicial_mesh_cell_3() + template + struct Rebind_TDS + { + using Cb2 = typename Cb::template Rebind_TDS::Other; + using Other = Simplicial_mesh_cell_base_3; + }; + +public: + Simplicial_mesh_cell_base_3() : time_stamp_(std::size_t(-1)) {} - Simplicial_mesh_cell_3(const Simplicial_mesh_cell_3& rhs) + Simplicial_mesh_cell_base_3(const Simplicial_mesh_cell_base_3& rhs) : Cb(static_cast(rhs)), time_stamp_(rhs.time_stamp_), subdomain_index_(rhs.subdomain_index_) @@ -63,15 +109,15 @@ public: surface_index_table_[i] = rhs.surface_index_table_[i]; } - Simplicial_mesh_cell_3(Vertex_handle v0, Vertex_handle v1, - Vertex_handle v2, Vertex_handle v3) + Simplicial_mesh_cell_base_3(Vertex_handle v0, Vertex_handle v1, + Vertex_handle v2, Vertex_handle v3) : Cb(v0, v1, v2, v3) { } - Simplicial_mesh_cell_3(Vertex_handle v0, Vertex_handle v1, - Vertex_handle v2, Vertex_handle v3, - Cell_handle n0, Cell_handle n1, - Cell_handle n2, Cell_handle n3) + Simplicial_mesh_cell_base_3(Vertex_handle v0, Vertex_handle v1, + Vertex_handle v2, Vertex_handle v3, + Cell_handle n0, Cell_handle n1, + Cell_handle n2, Cell_handle n3) : Cb(v0, v1, v2, v3, n0, n1, n2, n3) { } @@ -153,7 +199,7 @@ private: public: friend std::istream& operator>>(std::istream& is, - Simplicial_mesh_cell_3& c) + Simplicial_mesh_cell_base_3& c) { Subdomain_index index; if(IO::is_ascii(is)) @@ -180,7 +226,7 @@ public: friend std::ostream& operator<<(std::ostream& os, - const Simplicial_mesh_cell_3& c) + const Simplicial_mesh_cell_base_3& c) { if(IO::is_ascii(os)) os << c.subdomain_index(); @@ -199,59 +245,6 @@ public: } }; -/*! -\ingroup PkgSMDS3Classes - -The class `Simplicial_mesh_cell_base_3` -is a model of the concept `SimplicialMeshCellBase_3`. -It is designed to serve as cell base class for 3D simplicial mesh data structures. -It stores and gives access to data about the complex the cell belongs to, such as the -subdomain it belongs to or surface it takes part to. - -\tparam Gt is the geometric traits class. -It must be a model of the concept `TriangulationTraits_3` - -\tparam SubdomainIndex Type of indices for subdomains of the discretized geometric domain. -Must be a model of `CopyConstructible`, `Assignable`, `DefaultConstructible` -and `EqualityComparable`. The default constructed value must match the label -of the exterior of the domain (which contains at least the unbounded component). -It must match `MeshDomain_3::Subdomain_index` when used for mesh generation. - -\tparam SurfacePatchIndex Type of indices for surface patches (boundaries and interfaces) -of the discretized geometric domain. -Must be a model of `CopyConstructible`, `Assignable`, `DefaultConstructible` -and `EqualityComparable`. The default constructed value must be the index value -assigned to a non surface facet. -It must match `MeshDomain_3::Surface_patch_index` when used for mesh generation. - -\tparam Cb is the cell base class from which `Simplicial_mesh_cell_base_3` derives. -It must be a model of the concept `TriangulationCellBase_3`. - -\cgalModels `SimplicialMeshCellBase_3` - -\sa `CGAL::Mesh_complex_3_in_triangulation_3` -\sa \link Mesh_cell_base_3 `CGAL::Mesh_cell_base_3`\endlink -\sa `MeshDomain_3` -\sa `MeshDomainWithFeatures_3` -*/ -template > -class Simplicial_mesh_cell_base_3 -{ -public: - template - struct Rebind_TDS - { - using Cb2 = typename Cb::template Rebind_TDS::Other; - using Other = Simplicial_mesh_cell_3; - }; -}; - } // namespace CGAL #endif // CGAL_SIMPLICIAL_MESH_CELL_BASE_3_H diff --git a/SMDS_3/include/CGAL/Simplicial_mesh_vertex_base_3.h b/SMDS_3/include/CGAL/Simplicial_mesh_vertex_base_3.h index a25cf6f4329..1b47ea8de4f 100644 --- a/SMDS_3/include/CGAL/Simplicial_mesh_vertex_base_3.h +++ b/SMDS_3/include/CGAL/Simplicial_mesh_vertex_base_3.h @@ -35,13 +35,62 @@ namespace CGAL { // Adds information to Vb about the localization of the vertex in regards to the 3D input complex. + +/*! +\ingroup PkgSMDS3Classes + +The class `Simplicial_mesh_vertex_base_3` is a model of the concept +`SimplicialMeshVertexBase_3`. +It is designed to serve as vertex base class for 3D simplicial mesh data structures. +It stores and gives access to data about the complex the vertex belongs to, such as the +index of the subcomplex it belongs to. + +\tparam Gt is the geometric traits class. +It must be a model of the concept `TriangulationTraits_3` + +\tparam SubdomainIndex Type of indices for subdomains of the discretized geometric domain. +Must be a model of `CopyConstructible`, `Assignable`, `DefaultConstructible` +and `EqualityComparable`. The default constructed value must match the label +of the exterior of the domain (which contains at least the unbounded component). +It must match `MeshDomain_3::Subdomain_index` when used for mesh generation. + +\tparam SurfacePatchIndex Type of indices for surface patches (boundaries and interfaces) +of the discretized geometric domain. +Must be a model of `CopyConstructible`, `Assignable`, `DefaultConstructible` +and `EqualityComparable`. The default constructed value must be the index value +assigned to a non surface facet. +It must match `MeshDomain_3::Surface_patch_index` when used for mesh generation. + +\tparam CurveIndex Type of indices for curves (i.e. \f$ 1\f$-dimensional features) +of the discretized geometric domain. +Must be a model of `CopyConstructible`, `Assignable`, `DefaultConstructible` and +`LessThanComparable`. The default constructed value must be the value for an edge which +does not approximate a 1-dimensional feature of the geometric domain. +It must match `MeshDomainWithFeatures_3::Curve_index` when used for mesh generation. + +\tparam CornerIndex Type of indices for corners (i.e.\f$ 0\f$--dimensional features) +of the discretized geometric domain. +It must be a model of `CopyConstructible`, `Assignable`, `DefaultConstructible` and +`LessThanComparable`. +It must match `MeshDomainWithFeatures_3::Corner_index` when used for mesh generation. + +\tparam Vb is the vertex base class from which `Simplicial_mesh_vertex_base_3` derives. +It must be a model of the concept `TriangulationVertexBase_3`. + +\cgalModels `SimplicialMeshVertexBase_3` + +\sa `CGAL::Mesh_complex_3_in_triangulation_3` +\sa \link Mesh_vertex_base_3 `CGAL::Mesh_vertex_base_3`\endlink +\sa `MeshDomain_3` +\sa `MeshDomainWithFeatures_3` +*/ template -class Simplicial_mesh_vertex_3 + typename Vb = CGAL::Triangulation_vertex_base_3 > +class Simplicial_mesh_vertex_base_3 : public Vb { private : @@ -61,7 +110,20 @@ public: using FT = typename Gt::FT; public: - Simplicial_mesh_vertex_3() + template + struct Rebind_TDS + { + using Vb2 = typename Vb::template Rebind_TDS::Other; + using Other = Simplicial_mesh_vertex_base_3; + }; + +public: + Simplicial_mesh_vertex_base_3() : Vb() , number_of_incident_facets_(0) , number_of_components_(0) @@ -160,7 +222,7 @@ private: public: friend std::istream& operator>>(std::istream& is, - Simplicial_mesh_vertex_3& v) + Simplicial_mesh_vertex_base_3& v) { is >> static_cast(v); int dimension; @@ -186,7 +248,7 @@ public: } friend std::ostream& operator<<(std::ostream& os, - const Simplicial_mesh_vertex_3& v) + const Simplicial_mesh_vertex_base_3& v) { os << static_cast(v); if(IO::is_ascii(os)) { @@ -207,76 +269,6 @@ public: } }; -/*! -\ingroup PkgSMDS3Classes - -The class `Simplicial_mesh_vertex_base_3` is a model of the concept -`SimplicialMeshVertexBase_3`. -It is designed to serve as vertex base class for 3D simplicial mesh data structures. -It stores and gives access to data about the complex the vertex belongs to, such as the -index of the subcomplex it belongs to. - -\tparam Gt is the geometric traits class. -It must be a model of the concept `TriangulationTraits_3` - -\tparam SubdomainIndex Type of indices for subdomains of the discretized geometric domain. -Must be a model of `CopyConstructible`, `Assignable`, `DefaultConstructible` -and `EqualityComparable`. The default constructed value must match the label -of the exterior of the domain (which contains at least the unbounded component). -It must match `MeshDomain_3::Subdomain_index` when used for mesh generation. - -\tparam SurfacePatchIndex Type of indices for surface patches (boundaries and interfaces) -of the discretized geometric domain. -Must be a model of `CopyConstructible`, `Assignable`, `DefaultConstructible` -and `EqualityComparable`. The default constructed value must be the index value -assigned to a non surface facet. -It must match `MeshDomain_3::Surface_patch_index` when used for mesh generation. - -\tparam CurveIndex Type of indices for curves (i.e. \f$ 1\f$-dimensional features) -of the discretized geometric domain. -Must be a model of `CopyConstructible`, `Assignable`, `DefaultConstructible` and -`LessThanComparable`. The default constructed value must be the value for an edge which -does not approximate a 1-dimensional feature of the geometric domain. -It must match `MeshDomainWithFeatures_3::Curve_index` when used for mesh generation. - -\tparam CornerIndex Type of indices for corners (i.e.\f$ 0\f$--dimensional features) -of the discretized geometric domain. -It must be a model of `CopyConstructible`, `Assignable`, `DefaultConstructible` and -`LessThanComparable`. -It must match `MeshDomainWithFeatures_3::Corner_index` when used for mesh generation. - -\tparam Vb is the vertex base class from which `Simplicial_mesh_vertex_base_3` derives. -It must be a model of the concept `TriangulationVertexBase_3`. - -\cgalModels `SimplicialMeshVertexBase_3` - -\sa `CGAL::Mesh_complex_3_in_triangulation_3` -\sa \link Mesh_vertex_base_3 `CGAL::Mesh_vertex_base_3`\endlink -\sa `MeshDomain_3` -\sa `MeshDomainWithFeatures_3` -*/ -template > -class Simplicial_mesh_vertex_base_3 -{ -public: - template - struct Rebind_TDS - { - using Vb2 = typename Vb::template Rebind_TDS::Other; - using Other = Simplicial_mesh_vertex_3; - }; -}; - } // namespace CGAL #endif // CGAL_SIMPLICIAL_MESH_VERTEX_BASE_3_H diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/Remeshing_cell_base_3.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/Remeshing_cell_base_3.h index 30de338cdf7..162cfa27f21 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/Remeshing_cell_base_3.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/Remeshing_cell_base_3.h @@ -22,9 +22,27 @@ namespace CGAL { namespace Tetrahedral_remeshing { +/*! +\ingroup PkgTetrahedralRemeshingClasses + +The class `Remeshing_cell_base_3` is a model of the concept `RemeshingCellBase_3`. +It is designed to serve as cell base class for the 3D triangulation +used in the tetrahedral remeshing process. + +\tparam Gt is the geometric traits class. +It has to be a model of the concept `RemeshingTriangulationTraits_3`. + +\tparam Cb is a cell base class from which `Remeshing_cell_base_3` derives. +It must be a model of the `SimplicialMeshCellBase_3` concept. + +\cgalModels `RemeshingCellBase_3` + +*/ template -class Remeshing_cell_3 + typename Cb = CGAL::Simplicial_mesh_cell_base_3 > +class Remeshing_cell_base_3 : public Cb { public: @@ -35,6 +53,14 @@ public: using Geom_traits = Gt; +public: + template + struct Rebind_TDS + { + using Cb2 = typename Cb::template Rebind_TDS::Other; + using Other = Remeshing_cell_base_3; + }; + public: using Cb::Cb; // constructors @@ -59,37 +85,6 @@ private: mutable bool sliver_cache_validity_ = false; }; -/*! -\ingroup PkgTetrahedralRemeshingClasses - -The class `Remeshing_cell_base_3` is a model of the concept `RemeshingCellBase_3`. -It is designed to serve as cell base class for the 3D triangulation -used in the tetrahedral remeshing process. - -\tparam Gt is the geometric traits class. -It has to be a model of the concept `RemeshingTriangulationTraits_3`. - -\tparam Cb is a cell base class from which `Remeshing_cell_base_3` derives. -It must be a model of the `SimplicialMeshCellBase_3` concept. - -\cgalModels `RemeshingCellBase_3` - -*/ -template > -class Remeshing_cell_base_3 -{ -public: - template - struct Rebind_TDS - { - using Cb2 = typename Cb::template Rebind_TDS::Other; - using Other = Remeshing_cell_3; - }; -}; - } // namespace Tetrahedral_remeshing } // namespace CGAL diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/Remeshing_vertex_base_3.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/Remeshing_vertex_base_3.h index faab3950f9a..34e5fb0855c 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/Remeshing_vertex_base_3.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/Remeshing_vertex_base_3.h @@ -20,15 +20,6 @@ namespace CGAL { namespace Tetrahedral_remeshing { -template -class Remeshing_vertex_3 - : public Vb -{ -public: - using Vb::Vb; // constructors -}; - /*! \ingroup PkgTetrahedralRemeshingClasses @@ -51,14 +42,18 @@ template > class Remeshing_vertex_base_3 + : public Vb { public: template struct Rebind_TDS { using Vb2 = typename Vb::template Rebind_TDS::Other; - using Other = Remeshing_vertex_3; + using Other = Remeshing_vertex_base_3; }; + +public: + using Vb::Vb; // constructors }; } // namespace Tetrahedral_remeshing From 5e8d59c4dd9deb5f1c35f0675e96c4bf91578bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 21 Jul 2023 16:22:41 +0200 Subject: [PATCH 02/35] Make the triangulation a template parameter of the Alpha Wrap builder Advanced users only for now: you need to know what you're doing as the geom traits need to define the Ball_3 (usually that means wrapping your Gt with AABB_AW_geom_traits) and you need to have Vb/Cb contain the AW Vb/Cb in the stack. --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 271 ++++++++++-------- 1 file changed, 148 insertions(+), 123 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index f12ad06804b..677242e9da1 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -34,11 +34,20 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + #include #include #include #include +#include #include #include #include @@ -50,16 +59,9 @@ #include // only if non-manifoldness is not treated #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include #include #include #include @@ -74,6 +76,34 @@ namespace CGAL { namespace Alpha_wraps_3 { namespace internal { +struct Cell_info +{ + bool is_outside = false; +}; + +enum Vertex_info +{ + DEFAULT = 0, + BBOX_VERTEX, + SEED_VERTEX +}; + +template +using Alpha_wrap_triangulation_vertex_base_3 = + CGAL::Triangulation_vertex_base_with_info_3< + Vertex_info, + GeomTraits, + CGAL::Triangulation_vertex_base_3 >; + +template +using Alpha_wrap_triangulation_cell_base_3 = + CGAL::Triangulation_cell_base_with_info_3< + Cell_info, + GeomTraits, + CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3< + GeomTraits, + CGAL::Delaunay_triangulation_cell_base_3 > >; + template class Cell_base_with_timestamp : public Cb @@ -125,11 +155,34 @@ struct Wrapping_default_visitor void on_alpha_wrapping_end(const AlphaWrapper&) { }; }; -template +template class Alpha_wrap_3 { + using Oracle = Oracle_; + + // Triangulation using Base_GT = typename Oracle::Geom_traits; - using Geom_traits = Robust_circumcenter_filtered_traits_3; + using Default_Gt = Robust_circumcenter_filtered_traits_3; + + using Default_Vb = Alpha_wrap_triangulation_vertex_base_3; + using Default_Cb = Alpha_wrap_triangulation_cell_base_3; + using Default_Cbt = Cell_base_with_timestamp; // determinism + using Default_Tds = CGAL::Triangulation_data_structure_3; + using Default_Triangulation = CGAL::Delaunay_triangulation_3; + + using Triangulation = typename Default::Get::type; + + using Cell_handle = typename Triangulation::Cell_handle; + using Facet = typename Triangulation::Facet; + using Vertex_handle = typename Triangulation::Vertex_handle; + using Locate_type = typename Triangulation::Locate_type; + + using Gate = internal::Gate; + using Alpha_PQ = Modifiable_priority_queue, CGAL_BOOST_PAIRING_HEAP>; + + // Use the geom traits from the triangulation, and trust the (advanced) user that provided it + using Geom_traits = typename Triangulation::Geom_traits; using FT = typename Geom_traits::FT; using Point_3 = typename Geom_traits::Point_3; @@ -143,34 +196,6 @@ class Alpha_wrap_3 using SC_Iso_cuboid_3 = SC::Iso_cuboid_3; using SC2GT = Cartesian_converter; - struct Cell_info - { - bool is_outside = false; - }; - - enum Vertex_info - { - DEFAULT = 0, - BBOX_VERTEX, - SEED_VERTEX - }; - - using Vb = Triangulation_vertex_base_3; - using Vbi = Triangulation_vertex_base_with_info_3; - using Cbb = Delaunay_triangulation_cell_base_3; - using Cb = Delaunay_triangulation_cell_base_with_circumcenter_3; - using Cbi = Triangulation_cell_base_with_info_3; - using Cbt = Cell_base_with_timestamp; - using Tds = Triangulation_data_structure_3; - using Dt = Delaunay_triangulation_3; - - using Cell_handle = typename Dt::Cell_handle; - using Facet = typename Dt::Facet; - using Vertex_handle = typename Dt::Vertex_handle; - using Locate_type = typename Dt::Locate_type; - - using Gate = internal::Gate
; - using Alpha_PQ = Modifiable_priority_queue, CGAL_BOOST_PAIRING_HEAP>; protected: const Oracle m_oracle; @@ -179,7 +204,7 @@ protected: FT m_alpha, m_sq_alpha; FT m_offset, m_sq_offset; - Dt m_dt; + Triangulation m_tr; Alpha_PQ m_queue; public: @@ -187,7 +212,7 @@ public: Alpha_wrap_3(const Oracle& oracle) : m_oracle(oracle), - m_dt(Geom_traits(oracle.geom_traits())), + m_tr(Geom_traits(oracle.geom_traits())), // used to set up the initial MPQ, use some arbitrary not-too-small value m_queue(4096) { @@ -197,9 +222,9 @@ public: } public: - const Geom_traits& geom_traits() const { return m_dt.geom_traits(); } - Dt& triangulation() { return m_dt; } - const Dt& triangulation() const { return m_dt; } + const Geom_traits& geom_traits() const { return m_tr.geom_traits(); } + Triangulation& triangulation() { return m_tr; } + const Triangulation& triangulation() const { return m_tr; } const Alpha_PQ& queue() const { return m_queue; } double default_alpha() const @@ -216,13 +241,13 @@ private: const Point_3& circumcenter(const Cell_handle c) const { // We only cross an infinite facet once, so this isn't going to be recomputed many times - if(m_dt.is_infinite(c)) + if(m_tr.is_infinite(c)) { - const int inf_index = c->index(m_dt.infinite_vertex()); + const int inf_index = c->index(m_tr.infinite_vertex()); c->set_circumcenter( - geom_traits().construct_circumcenter_3_object()(m_dt.point(c, (inf_index+1)&3), - m_dt.point(c, (inf_index+2)&3), - m_dt.point(c, (inf_index+3)&3))); + geom_traits().construct_circumcenter_3_object()(m_tr.point(c, (inf_index+1)&3), + m_tr.point(c, (inf_index+2)&3), + m_tr.point(c, (inf_index+3)&3))); } return c->circumcenter(geom_traits()); @@ -418,7 +443,7 @@ private: for(int i=0; i<8; ++i) { const Point_3 bp = SC2GT()(m_bbox.vertex(i)); - Vertex_handle bv = m_dt.insert(bp); + Vertex_handle bv = m_tr.insert(bp); #ifdef CGAL_AW3_DEBUG_INITIALIZATION std::cout << "\t" << bp << std::endl; #endif @@ -433,7 +458,7 @@ private: // that the refinement point is separated from the existing point set. bool cavity_cell_outside_tag(const Cell_handle ch) { - CGAL_precondition(!m_dt.is_infinite(ch)); + CGAL_precondition(!m_tr.is_infinite(ch)); const Tetrahedron_with_outside_info tet(ch, geom_traits()); if(m_oracle.do_intersect(tet)) @@ -536,7 +561,7 @@ private: // This problem only appears when the seed and icosahedron vertices are close to the offset surface, // which usually happens for large alpha values. - Vertex_handle seed_v = m_dt.insert(seed_p); + Vertex_handle seed_v = m_tr.insert(seed_p); seed_v->info() = SEED_VERTEX; seed_vs.push_back(seed_v); @@ -573,7 +598,7 @@ private: if(bbox.has_on_unbounded_side(seed_neighbor_p)) continue; - Vertex_handle ico_v = m_dt.insert(seed_neighbor_p, seed_v /*hint*/); + Vertex_handle ico_v = m_tr.insert(seed_neighbor_p, seed_v /*hint*/); ico_v->info() = SEED_VERTEX; } } @@ -587,26 +612,26 @@ private: } #ifdef CGAL_AW3_DEBUG_INITIALIZATION - std::cout << m_dt.number_of_vertices() - 8 /*bbox*/ << " vertice(s) due to seeds" << std::endl; + std::cout << m_tr.number_of_vertices() - 8 /*bbox*/ << " vertice(s) due to seeds" << std::endl; #endif for(Vertex_handle seed_v : seed_vs) { std::vector inc_cells; inc_cells.reserve(64); - m_dt.incident_cells(seed_v, std::back_inserter(inc_cells)); + m_tr.incident_cells(seed_v, std::back_inserter(inc_cells)); for(Cell_handle ch : inc_cells) ch->info().is_outside = cavity_cell_outside_tag(ch); } // Might as well go through the full triangulation since only seeds should have been inserted - for(Cell_handle ch : m_dt.all_cell_handles()) + for(Cell_handle ch : m_tr.all_cell_handles()) { if(!ch->info().is_outside) continue; // When the algorithm starts from a manually dug hole, infinite cells are tagged "inside" - CGAL_assertion(!m_dt.is_infinite(ch)); + CGAL_assertion(!m_tr.is_infinite(ch)); for(int i=0; i<4; ++i) push_facet(std::make_pair(ch, i)); @@ -627,12 +652,12 @@ private: // init queue with all convex hull facets bool initialize_from_infinity() { - for(Cell_handle ch : m_dt.all_cell_handles()) + for(Cell_handle ch : m_tr.all_cell_handles()) { - if(m_dt.is_infinite(ch)) + if(m_tr.is_infinite(ch)) { ch->info().is_outside = true; - const int inf_index = ch->index(m_dt.infinite_vertex()); + const int inf_index = ch->index(m_tr.infinite_vertex()); push_facet(std::make_pair(ch, inf_index)); } else @@ -659,10 +684,10 @@ public: clear(output_mesh); - CGAL_assertion_code(for(auto cit=m_dt.finite_cells_begin(), cend=m_dt.finite_cells_end(); cit!=cend; ++cit)) + CGAL_assertion_code(for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit)) CGAL_assertion(cit->tds_data().is_clear()); - for(auto cit=m_dt.finite_cells_begin(), cend=m_dt.finite_cells_end(); cit!=cend; ++cit) + for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit) { Cell_handle seed = cit; if(seed->info().is_outside || seed->tds_data().processed()) @@ -678,7 +703,7 @@ public: while(!to_visit.empty()) { const Cell_handle cell = to_visit.front(); - CGAL_assertion(!cell->info().is_outside && !m_dt.is_infinite(cell)); + CGAL_assertion(!cell->info().is_outside && !m_tr.is_infinite(cell)); to_visit.pop(); @@ -698,9 +723,9 @@ public: // CGAL_assertion(cell->vertex((fid + 2)&3)->info() == DEFAULT); // CGAL_assertion(cell->vertex((fid + 3)&3)->info() == DEFAULT); - points.push_back(m_dt.point(cell, Dt::vertex_triple_index(fid, 0))); - points.push_back(m_dt.point(cell, Dt::vertex_triple_index(fid, 1))); - points.push_back(m_dt.point(cell, Dt::vertex_triple_index(fid, 2))); + points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 0))); + points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 1))); + points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 2))); faces.push_back({idx, idx + 1, idx + 2}); idx += 3; } @@ -722,7 +747,7 @@ public: CGAL_assertion(is_closed(output_mesh)); } - for(auto cit=m_dt.finite_cells_begin(), cend=m_dt.finite_cells_end(); cit!=cend; ++cit) + for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit) cit->tds_data().clear(); CGAL_postcondition(!is_empty(output_mesh)); @@ -742,7 +767,7 @@ public: std::cout << "> Extract wrap... ()" << std::endl; #endif - CGAL_assertion_code(for(Vertex_handle v : m_dt.finite_vertex_handles())) + CGAL_assertion_code(for(Vertex_handle v : m_tr.finite_vertex_handles())) CGAL_assertion(!is_non_manifold(v)); clear(output_mesh); @@ -754,11 +779,11 @@ public: std::unordered_map vertex_to_id; std::size_t nv = 0; - for(auto fit=m_dt.finite_facets_begin(), fend=m_dt.finite_facets_end(); fit!=fend; ++fit) + for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) { Facet f = *fit; if(!f.first->info().is_outside) - f = m_dt.mirror_facet(f); + f = m_tr.mirror_facet(f); const Cell_handle c = f.first; const int s = f.second; @@ -769,11 +794,11 @@ public: std::array ids; for(int pos=0; pos<3; ++pos) { - Vertex_handle vh = c->vertex(Dt::vertex_triple_index(s, pos)); + Vertex_handle vh = c->vertex(Triangulation::vertex_triple_index(s, pos)); auto insertion_res = vertex_to_id.emplace(vh, nv); if(insertion_res.second) // successful insertion, never-seen-before vertex { - points.push_back(m_dt.point(vh)); + points.push_back(m_tr.point(vh)); ++nv; } @@ -817,14 +842,14 @@ public: private: bool is_traversable(const Facet& f) const { - return less_squared_radius_of_min_empty_sphere(m_sq_alpha, f, m_dt); + return less_squared_radius_of_min_empty_sphere(m_sq_alpha, f, m_tr); } bool compute_steiner_point(const Cell_handle ch, const Cell_handle neighbor, Point_3& steiner_point) const { - CGAL_precondition(!m_dt.is_infinite(neighbor)); + CGAL_precondition(!m_tr.is_infinite(neighbor)); typename Geom_traits::Construct_ball_3 ball = geom_traits().construct_ball_3_object(); typename Geom_traits::Construct_vector_3 vector = geom_traits().construct_vector_3_object(); @@ -920,7 +945,7 @@ private: // e.g. from DT3 Facet_queue_status facet_status(const Facet& f) const { - CGAL_precondition(!m_dt.is_infinite(f)); + CGAL_precondition(!m_tr.is_infinite(f)); #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "facet status: " @@ -933,7 +958,7 @@ private: const Cell_handle ch = f.first; const int id = f.second; const Cell_handle nh = ch->neighbor(id); - if(m_dt.is_infinite(nh)) + if(m_tr.is_infinite(nh)) return TRAVERSABLE; if(nh->info().is_outside) @@ -947,7 +972,7 @@ private: // push if facet is connected to artificial vertices for(int i=0; i<3; ++i) { - const Vertex_handle vh = ch->vertex(Dt::vertex_triple_index(id, i)); + const Vertex_handle vh = ch->vertex(Triangulation::vertex_triple_index(id, i)); if(vh->info() == BBOX_VERTEX || vh->info() == SEED_VERTEX) { #ifdef CGAL_AW3_DEBUG_FACET_STATUS @@ -986,9 +1011,9 @@ private: const Cell_handle ch = f.first; const int id = f.second; - const Point_3& p0 = m_dt.point(ch, (id+1)&3); - const Point_3& p1 = m_dt.point(ch, (id+2)&3); - const Point_3& p2 = m_dt.point(ch, (id+3)&3); + const Point_3& p0 = m_tr.point(ch, (id+1)&3); + const Point_3& p1 = m_tr.point(ch, (id+2)&3); + const Point_3& p2 = m_tr.point(ch, (id+3)&3); // @todo should prob be the real value we compare to alpha instead of squared_radius const FT sqr = geom_traits().compute_squared_radius_3_object()(p0, p1, p2); @@ -1022,7 +1047,7 @@ private: m_offset = FT(offset); m_sq_offset = square(m_offset); - m_dt.clear(); + m_tr.clear(); m_queue.clear(); insert_bbox_corners(); @@ -1052,7 +1077,7 @@ private: // const& to something that will be popped, but safe as `ch` && `id` are extracted before the pop const Gate& gate = m_queue.top(); const Facet& f = gate.facet(); - CGAL_precondition(!m_dt.is_infinite(f)); + CGAL_precondition(!m_tr.is_infinite(f)); const Cell_handle ch = f.first; const int id = f.second; @@ -1060,11 +1085,11 @@ private: #ifdef CGAL_AW3_DEBUG_QUEUE static int fid = 0; - std::cout << m_dt.number_of_vertices() << " DT vertices" << std::endl; + std::cout << m_tr.number_of_vertices() << " DT vertices" << std::endl; std::cout << m_queue.size() << " facets in the queue" << std::endl; std::cout << "Face " << fid++ << "\n" - << "c = " << &*ch << " (" << m_dt.is_infinite(ch) << "), n = " << &*neighbor << " (" << m_dt.is_infinite(neighbor) << ")" << "\n" - << m_dt.point(ch, (id+1)&3) << "\n" << m_dt.point(ch, (id+2)&3) << "\n" << m_dt.point(ch, (id+3)&3) << std::endl; + << "c = " << &*ch << " (" << m_tr.is_infinite(ch) << "), n = " << &*neighbor << " (" << m_tr.is_infinite(neighbor) << ")" << "\n" + << m_tr.point(ch, (id+1)&3) << "\n" << m_tr.point(ch, (id+2)&3) << "\n" << m_tr.point(ch, (id+3)&3) << std::endl; std::cout << "Priority: " << gate.priority() << std::endl; #endif @@ -1080,11 +1105,11 @@ private: std::string face_name = "results/steps/face_" + std::to_string(static_cast(i++)) + ".xyz"; std::ofstream face_out(face_name); face_out.precision(17); - face_out << "3\n" << m_dt.point(ch, (id+1)&3) << "\n" << m_dt.point(ch, (id+2)&3) << "\n" << m_dt.point(ch, (id+3)&3) << std::endl; + face_out << "3\n" << m_tr.point(ch, (id+1)&3) << "\n" << m_tr.point(ch, (id+2)&3) << "\n" << m_tr.point(ch, (id+3)&3) << std::endl; face_out.close(); #endif - if(m_dt.is_infinite(neighbor)) + if(m_tr.is_infinite(neighbor)) { neighbor->info().is_outside = true; continue; @@ -1100,14 +1125,14 @@ private: // locate cells that are going to be destroyed and remove their facet from the queue int li, lj = 0; Locate_type lt; - const Cell_handle conflict_cell = m_dt.locate(steiner_point, lt, li, lj, neighbor); - CGAL_assertion(lt != Dt::VERTEX); + const Cell_handle conflict_cell = m_tr.locate(steiner_point, lt, li, lj, neighbor); + CGAL_assertion(lt != Triangulation::VERTEX); std::vector boundary_facets; std::vector conflict_zone; boundary_facets.reserve(32); conflict_zone.reserve(32); - m_dt.find_conflicts(steiner_point, conflict_cell, + m_tr.find_conflicts(steiner_point, conflict_cell, std::back_inserter(boundary_facets), std::back_inserter(conflict_zone)); @@ -1125,7 +1150,7 @@ private: for(const Facet& f : boundary_facets) { - const Facet mf = m_dt.mirror_facet(f); // boundary facets have incident cells in the CZ + const Facet mf = m_tr.mirror_facet(f); // boundary facets have incident cells in the CZ if(m_queue.contains_with_bounds_check(Gate(mf))) m_queue.erase(Gate(mf)); } @@ -1133,18 +1158,18 @@ private: visitor.before_Steiner_point_insertion(*this, steiner_point); // Actual insertion of the Steiner point - Vertex_handle vh = m_dt.insert(steiner_point, lt, conflict_cell, li, lj); + Vertex_handle vh = m_tr.insert(steiner_point, lt, conflict_cell, li, lj); vh->info() = DEFAULT; visitor.after_Steiner_point_insertion(*this, vh); std::vector new_cells; new_cells.reserve(32); - m_dt.incident_cells(vh, std::back_inserter(new_cells)); + m_tr.incident_cells(vh, std::back_inserter(new_cells)); for(const Cell_handle& ch : new_cells) { // std::cout << "new cell has time stamp " << ch->time_stamp() << std::endl; - ch->info().is_outside = m_dt.is_infinite(ch); + ch->info().is_outside = m_tr.is_infinite(ch); } // Push all new boundary facets to the queue. @@ -1156,7 +1181,7 @@ private: { for(int i=0; i<4; ++i) { - if(m_dt.is_infinite(ch, i)) + if(m_tr.is_infinite(ch, i)) continue; const Cell_handle nh = ch->neighbor(i); @@ -1167,7 +1192,7 @@ private: if(ch->info().is_outside) push_facet(boundary_f); else - push_facet(m_dt.mirror_facet(boundary_f)); + push_facet(m_tr.mirror_facet(boundary_f)); } } } @@ -1188,10 +1213,10 @@ private: visitor.on_flood_fill_end(*this); // Check that no useful facet has been ignored - CGAL_postcondition_code(for(auto fit=m_dt.finite_facets_begin(), fend=m_dt.finite_facets_end(); fit!=fend; ++fit) {) + CGAL_postcondition_code(for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) {) CGAL_postcondition_code( if(fit->first->info().is_outside == fit->first->neighbor(fit->second)->info().is_outside) continue;) CGAL_postcondition_code( Facet f = *fit;) - CGAL_postcondition_code( if(!fit->first->info().is_outside) f = m_dt.mirror_facet(f);) + CGAL_postcondition_code( if(!fit->first->info().is_outside) f = m_tr.mirror_facet(f);) CGAL_postcondition( facet_status(f) == IRRELEVANT); CGAL_postcondition_code(}) } @@ -1199,13 +1224,13 @@ private: private: bool is_non_manifold(Vertex_handle v) const { - CGAL_precondition(!m_dt.is_infinite(v)); + CGAL_precondition(!m_tr.is_infinite(v)); bool is_non_manifold = false; std::vector inc_cells; inc_cells.reserve(64); - m_dt.incident_cells(v, std::back_inserter(inc_cells)); + m_tr.incident_cells(v, std::back_inserter(inc_cells)); // Flood one inside and outside CC. // Process both an inside and an outside CC to also detect edge pinching. @@ -1278,7 +1303,7 @@ private: bool is_non_manifold(Cell_handle c) const { - CGAL_precondition(!m_dt.is_infinite(c)); + CGAL_precondition(!m_tr.is_infinite(c)); for(int i=0; i<4; ++i) { @@ -1294,7 +1319,7 @@ private: { // Not the best complexity, but it's not important: this function is purely for information // Better complexity --> see PMP::non_manifold_vertices + throw - for(const Vertex_handle v : m_dt.finite_vertex_handles()) + for(const Vertex_handle v : m_tr.finite_vertex_handles()) if(is_non_manifold(v)) return true; @@ -1307,14 +1332,14 @@ private: bool remove_bbox_vertices() { bool do_remove = true; - auto vit = m_dt.finite_vertices_begin(); + auto vit = m_tr.finite_vertices_begin(); for(std::size_t i=0; i<8; ++i) { Vertex_handle v = vit++; std::vector inc_cells; inc_cells.reserve(64); - m_dt.finite_incident_cells(v, std::back_inserter(inc_cells)); + m_tr.finite_incident_cells(v, std::back_inserter(inc_cells)); for(Cell_handle c : inc_cells) { @@ -1333,11 +1358,11 @@ private: if(!do_remove) return false; - vit = m_dt.finite_vertices_begin(); + vit = m_tr.finite_vertices_begin(); for(std::size_t i=0; i<8; ++i) { Vertex_handle v = vit++; - m_dt.remove(v); + m_tr.remove(v); } return true; @@ -1355,7 +1380,7 @@ public: // remove_bbox_vertices(); std::stack non_manifold_vertices; // @todo sort somehow? - for(Vertex_handle v : m_dt.finite_vertex_handles()) + for(Vertex_handle v : m_tr.finite_vertex_handles()) { if(is_non_manifold(v)) non_manifold_vertices.push(v); @@ -1395,17 +1420,17 @@ public: // auto sq_circumradius = [&](Cell_handle c) -> FT // { // const Point_3& cc = circumcenter(c); -// return geom_traits().compute_squared_distance_3_object()(m_dt.point(c, 0), cc); +// return geom_traits().compute_squared_distance_3_object()(m_tr.point(c, 0), cc); // }; auto sq_longest_edge = [&](Cell_handle c) -> FT { - return (std::max)({ squared_distance(m_dt.point(c, 0), m_dt.point(c, 1)), - squared_distance(m_dt.point(c, 0), m_dt.point(c, 2)), - squared_distance(m_dt.point(c, 0), m_dt.point(c, 3)), - squared_distance(m_dt.point(c, 1), m_dt.point(c, 2)), - squared_distance(m_dt.point(c, 3), m_dt.point(c, 3)), - squared_distance(m_dt.point(c, 2), m_dt.point(c, 3)) }); + return (std::max)({ squared_distance(m_tr.point(c, 0), m_tr.point(c, 1)), + squared_distance(m_tr.point(c, 0), m_tr.point(c, 2)), + squared_distance(m_tr.point(c, 0), m_tr.point(c, 3)), + squared_distance(m_tr.point(c, 1), m_tr.point(c, 2)), + squared_distance(m_tr.point(c, 3), m_tr.point(c, 3)), + squared_distance(m_tr.point(c, 2), m_tr.point(c, 3)) }); }; #ifdef CGAL_AW3_DEBUG_MANIFOLDNESS @@ -1450,7 +1475,7 @@ public: std::vector inc_cells; inc_cells.reserve(64); - m_dt.finite_incident_cells(v, std::back_inserter(inc_cells)); + m_tr.finite_incident_cells(v, std::back_inserter(inc_cells)); #define CGAL_AW3_USE_BRUTE_FORCE_MUTABLE_PRIORITY_QUEUE #ifndef CGAL_AW3_USE_BRUTE_FORCE_MUTABLE_PRIORITY_QUEUE @@ -1464,7 +1489,7 @@ public: std::sort(cit, cend, comparer); #endif Cell_handle ic = *cit; - CGAL_assertion(!m_dt.is_infinite(ic)); + CGAL_assertion(!m_tr.is_infinite(ic)); // This is where new material is added ic->info().is_outside = false; @@ -1484,14 +1509,14 @@ public: std::vector adj_vertices; adj_vertices.reserve(64); - m_dt.finite_adjacent_vertices(v, std::back_inserter(adj_vertices)); + m_tr.finite_adjacent_vertices(v, std::back_inserter(adj_vertices)); for(Vertex_handle nv : adj_vertices) if(is_non_manifold(nv)) non_manifold_vertices.push(nv); } - CGAL_assertion_code(for(Vertex_handle v : m_dt.finite_vertex_handles())) + CGAL_assertion_code(for(Vertex_handle v : m_tr.finite_vertex_handles())) CGAL_assertion(!is_non_manifold(v)); } @@ -1508,12 +1533,12 @@ private: const Facet& current_f = current_gate.facet(); const Cell_handle ch = current_f.first; const int id = current_f.second; - const Point_3& p0 = m_dt.point(ch, (id+1)&3); - const Point_3& p1 = m_dt.point(ch, (id+2)&3); - const Point_3& p2 = m_dt.point(ch, (id+3)&3); + const Point_3& p0 = m_tr.point(ch, (id+1)&3); + const Point_3& p1 = m_tr.point(ch, (id+2)&3); + const Point_3& p2 = m_tr.point(ch, (id+3)&3); const FT sqr = geom_traits().compute_squared_radius_3_object()(p0, p1, p2); - std::cout << "At Facet with VID " << get(Gate_ID_PM
(), current_gate) << std::endl; + std::cout << "At Facet with VID " << get(Gate_ID_PM(), current_gate) << std::endl; if(current_gate.priority() != sqr) std::cerr << "Error: facet in queue has wrong priority" << std::endl; @@ -1546,7 +1571,7 @@ private: std::size_t nv = 0; std::size_t nf = 0; - for(auto fit=m_dt.finite_facets_begin(), fend=m_dt.finite_facets_end(); fit!=fend; ++fit) + for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) { Cell_handle c = fit->first; int s = fit->second; @@ -1562,7 +1587,7 @@ private: auto insertion_res = vertex_to_id.emplace(v, nv); if(insertion_res.second) { - vertices_ss << m_dt.point(v) << "\n"; + vertices_ss << m_tr.point(v) << "\n"; ++nv; } From 924f2df4925ac6f1da1f523654a50ac79a86b9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 21 Jul 2023 16:24:45 +0200 Subject: [PATCH 03/35] Add an example: remeshing the (internal) 3D triangulation of an alpha wrap --- .../examples/Alpha_wrap_3/CMakeLists.txt | 1 + .../examples/Alpha_wrap_3/volumetric_wrap.cpp | 174 ++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt b/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt index 2014b9baa7c..0be54f87eed 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt @@ -12,3 +12,4 @@ create_single_source_cgal_program("triangle_soup_wrap.cpp") create_single_source_cgal_program("point_set_wrap.cpp") create_single_source_cgal_program("wrap_from_cavity.cpp") create_single_source_cgal_program("mixed_inputs_wrap.cpp") +create_single_source_cgal_program("volumetric_wrap.cpp") diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp new file mode 100644 index 00000000000..7fb4d470420 --- /dev/null +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp @@ -0,0 +1,174 @@ +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +namespace PMP = CGAL::Polygon_mesh_processing; +namespace AW3i = CGAL::Alpha_wraps_3::internal; + +using K = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_3 = K::Point_3; + +using Points = std::vector; +using Face = std::array; +using Faces = std::vector; + +using Mesh = CGAL::Surface_mesh; + +// If we provide a triangulation, AW3 uses its Gt, so we have to make the Gt stack explicit +using Gtb = AW3i::Alpha_wrap_AABB_geom_traits; // provides Ball_3 +using Gt = CGAL::Robust_circumcenter_filtered_traits_3; // better inexact constructions (not mandatory) + +// Since we are going to use tetrahedral remeshing on the underlying triangulation, +// we need special vertex and cell base types that meets the requirements of the +// tetrahedral remeshing concepts +using Vbbb = AW3i::Alpha_wrap_triangulation_vertex_base_3; +using Vbb = CGAL::Simplicial_mesh_vertex_base_3; +using Vb = CGAL::Tetrahedral_remeshing::Remeshing_vertex_base_3; + +using Cbbb = AW3i::Alpha_wrap_triangulation_cell_base_3; +using Cbb = CGAL::Simplicial_mesh_cell_base_3; +using Cb = CGAL::Tetrahedral_remeshing::Remeshing_cell_base_3; + +using Tds = CGAL::Triangulation_data_structure_3; + +using Delaunay_triangulation = CGAL::Delaunay_triangulation_3; + +// because the Fast_location does all kinds of rebinding shenanigans + T3_hierarchy is in the stack... +using Triangulation = CGAL::Triangulation_3; + +using Facet = Triangulation::Facet; + +int main(int argc, char** argv) +{ + // Read the input + const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/armadillo.off"); + std::cout << "Reading " << filename << "..." << std::endl; + + Points points; + Faces faces; + if(!CGAL::IO::read_polygon_soup(filename, points, faces) || faces.empty()) + { + std::cerr << "Invalid input." << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Input: " << points.size() << " vertices, " << faces.size() << " faces" << std::endl; + + // Compute the alpha and offset values + const double relative_alpha = (argc > 2) ? std::stod(argv[2]) : 20.; + const double relative_offset = (argc > 3) ? std::stod(argv[3]) : 600.; + + CGAL::Bbox_3 bbox; + for(const Point_3& p : points) + bbox += p.bbox(); + + const double diag_length = std::sqrt(CGAL::square(bbox.xmax() - bbox.xmin()) + + CGAL::square(bbox.ymax() - bbox.ymin()) + + CGAL::square(bbox.zmax() - bbox.zmin())); + + const double alpha = diag_length / relative_alpha; + const double offset = diag_length / relative_offset; + std::cout << "alpha: " << alpha << ", offset: " << offset << std::endl; + + // Construct the wrap + CGAL::Real_timer t; + t.start(); + + using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle; + + Oracle oracle(K{}); + oracle.add_triangle_soup(points, faces, CGAL::parameters::default_values()); + + CGAL::Alpha_wraps_3::internal::Alpha_wrap_3 aw3(oracle); + Mesh wrap; + aw3(alpha, offset, wrap); + + t.stop(); + std::cout << "Result: " << num_vertices(wrap) << " vertices, " << num_faces(wrap) << " faces" << std::endl; + std::cout << "Took " << t.time() << " s." << std::endl; + + // Get the interior tetrahedrization + auto dt = aw3.triangulation(); + + // Save the result + std::string input_name = std::string(filename); + input_name = input_name.substr(input_name.find_last_of("/") + 1, input_name.length() - 1); + input_name = input_name.substr(0, input_name.find_last_of(".")); + std::string output_name = input_name + + "_" + std::to_string(static_cast(relative_alpha)) + + "_" + std::to_string(static_cast(relative_offset)) + ".off"; + std::cout << "Writing to " << output_name << std::endl; + CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); + + // Remesh the interior of the wrap + const Delaunay_triangulation& aw3_dt = aw3.triangulation(); + const Triangulation& aw3_tr = static_cast(aw3_dt); + Triangulation tr = aw3_tr; // intentional copy + + std::cout << "BEFORE: " << tr.number_of_vertices() << " vertices, " << tr.number_of_cells() << " cells" << std::endl; + + // Set up the domain information and grab the boundary faces + std::set boundary_facets; + + for(auto v : tr.finite_vertex_handles()) + v->set_dimension(3); + + for(auto c : tr.finite_cell_handles()) + { + if(c->info().is_outside) + c->set_subdomain_index(0); + else + c->set_subdomain_index(1); + + // if the neighboring cell has a different outside info, put the vertices + // of the common face on the surface boundary + for(int i=0; i<4; ++i) + { + if(c->neighbor(i)->info().is_outside != c->info().is_outside) + { + c->set_surface_patch_index(i, 1); + boundary_facets.emplace(c, i); + for(int j=1; j<4; ++j) + c->vertex((i+j)%4)->set_dimension(2); + } + } + } + + // CGAL::draw(tr); + std::ofstream out_before("before_remeshing.mesh"); + CGAL::IO::write_MEDIT(out_before, tr); + + auto fcm = CGAL::make_boolean_property_map(boundary_facets); + CGAL::tetrahedral_isotropic_remeshing(tr, alpha, + CGAL::parameters::facet_is_constrained_map(fcm)); + + std::cout << "AFTER: " << tr.number_of_vertices() << " vertices, " << tr.number_of_cells() << " cells" << std::endl; + + // CGAL::draw(tr); + std::ofstream out_after("after_remeshing.mesh"); + CGAL::IO::write_MEDIT(out_after, tr); + + return EXIT_SUCCESS; +} From e0bb872d8a8160bf962236a1528ae288b39d6085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 21 Jul 2023 16:26:12 +0200 Subject: [PATCH 04/35] Minor doc typo --- .../doc/Tetrahedral_remeshing/Tetrahedral_remeshing.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tetrahedral_remeshing/doc/Tetrahedral_remeshing/Tetrahedral_remeshing.txt b/Tetrahedral_remeshing/doc/Tetrahedral_remeshing/Tetrahedral_remeshing.txt index 6336998d527..5ae7a827373 100644 --- a/Tetrahedral_remeshing/doc/Tetrahedral_remeshing/Tetrahedral_remeshing.txt +++ b/Tetrahedral_remeshing/doc/Tetrahedral_remeshing/Tetrahedral_remeshing.txt @@ -15,7 +15,7 @@ namespace CGAL { \section secTetRemeshing Multi-Material Isotropic Tetrahedral Remeshing This package implements an algorithm for quality tetrahedral remeshing, -introduced by N.Faraj et al in \cgalCite{faraj2016mvr}. +introduced by Faraj et al in \cgalCite{faraj2016mvr}. This practical iterative remeshing algorithm is designed to remesh multi-material tetrahedral meshes, by iteratively performing a sequence of elementary operations such as edge splits, edge collapses, edge flips, From dab63942159c96692e7b83459e4e53ba59b17592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Thu, 3 Aug 2023 12:05:40 +0200 Subject: [PATCH 05/35] Introduce AW3 Vb/Cb to avoid using T3_Vb/Cb_with_info_3 --- .../examples/Alpha_wrap_3/volumetric_wrap.cpp | 4 +- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 133 ++++++------------ .../internal/Alpha_wrap_AABB_geom_traits.h | 14 +- .../Alpha_wrap_triangulation_cell_base_3.h | 97 +++++++++++++ .../Alpha_wrap_triangulation_vertex_base_3.h | 71 ++++++++++ .../Alpha_wrap_3/Alpha_wrap_3_plugin.cpp | 4 +- 6 files changed, 225 insertions(+), 98 deletions(-) create mode 100644 Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h create mode 100644 Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_vertex_base_3.h diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp index 7fb4d470420..dd63ad66711 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp @@ -137,7 +137,7 @@ int main(int argc, char** argv) for(auto c : tr.finite_cell_handles()) { - if(c->info().is_outside) + if(c->is_outside()) c->set_subdomain_index(0); else c->set_subdomain_index(1); @@ -146,7 +146,7 @@ int main(int argc, char** argv) // of the common face on the surface boundary for(int i=0; i<4; ++i) { - if(c->neighbor(i)->info().is_outside != c->info().is_outside) + if(c->neighbor(i)->is_outside() != c->is_outside()) { c->set_surface_patch_index(i, 1); boundary_facets.emplace(c, i); diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 677242e9da1..ba752a77590 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2022 Google LLC (USA). +// Copyright (c) 2019-2023 Google LLC (USA). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -29,6 +29,8 @@ #include +#include +#include #include #include #include @@ -37,9 +39,7 @@ #include #include #include -#include #include -#include #include #include @@ -76,58 +76,11 @@ namespace CGAL { namespace Alpha_wraps_3 { namespace internal { -struct Cell_info -{ - bool is_outside = false; -}; +namespace { -enum Vertex_info -{ - DEFAULT = 0, - BBOX_VERTEX, - SEED_VERTEX -}; +namespace AW3i = ::CGAL::Alpha_wraps_3::internal; -template -using Alpha_wrap_triangulation_vertex_base_3 = - CGAL::Triangulation_vertex_base_with_info_3< - Vertex_info, - GeomTraits, - CGAL::Triangulation_vertex_base_3 >; - -template -using Alpha_wrap_triangulation_cell_base_3 = - CGAL::Triangulation_cell_base_with_info_3< - Cell_info, - GeomTraits, - CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3< - GeomTraits, - CGAL::Delaunay_triangulation_cell_base_3 > >; - -template -class Cell_base_with_timestamp - : public Cb -{ - std::size_t time_stamp_; - -public: - template - Cell_base_with_timestamp(const Args&... args) : Cb(args...), time_stamp_(-1) { } - - Cell_base_with_timestamp(const Cell_base_with_timestamp& other) : Cb(other), time_stamp_(other.time_stamp_) { } - - typedef CGAL::Tag_true Has_timestamp; - - std::size_t time_stamp() const { return time_stamp_; } - void set_time_stamp(const std::size_t& ts) { time_stamp_ = ts; } - - template - struct Rebind_TDS - { - typedef typename Cb::template Rebind_TDS::Other Cb2; - typedef Cell_base_with_timestamp Other; - }; -}; +} // unnamed namespace struct Wrapping_default_visitor { @@ -163,7 +116,7 @@ class Alpha_wrap_3 // Triangulation using Base_GT = typename Oracle::Geom_traits; - using Default_Gt = Robust_circumcenter_filtered_traits_3; + using Default_Gt = CGAL::Robust_circumcenter_filtered_traits_3; using Default_Vb = Alpha_wrap_triangulation_vertex_base_3; using Default_Cb = Alpha_wrap_triangulation_cell_base_3; @@ -447,7 +400,7 @@ private: #ifdef CGAL_AW3_DEBUG_INITIALIZATION std::cout << "\t" << bp << std::endl; #endif - bv->info() = BBOX_VERTEX; + bv->type() = AW3i::Vertex_type:: BBOX_VERTEX; } } @@ -562,7 +515,7 @@ private: // which usually happens for large alpha values. Vertex_handle seed_v = m_tr.insert(seed_p); - seed_v->info() = SEED_VERTEX; + seed_v->type() = AW3i::Vertex_type:: SEED_VERTEX; seed_vs.push_back(seed_v); // Icosahedron vertices (see also BGL::make_icosahedron()) @@ -599,7 +552,7 @@ private: continue; Vertex_handle ico_v = m_tr.insert(seed_neighbor_p, seed_v /*hint*/); - ico_v->info() = SEED_VERTEX; + ico_v->type() = AW3i::Vertex_type:: SEED_VERTEX; } } @@ -621,13 +574,13 @@ private: inc_cells.reserve(64); m_tr.incident_cells(seed_v, std::back_inserter(inc_cells)); for(Cell_handle ch : inc_cells) - ch->info().is_outside = cavity_cell_outside_tag(ch); + ch->is_outside() = cavity_cell_outside_tag(ch); } // Might as well go through the full triangulation since only seeds should have been inserted for(Cell_handle ch : m_tr.all_cell_handles()) { - if(!ch->info().is_outside) + if(!ch->is_outside()) continue; // When the algorithm starts from a manually dug hole, infinite cells are tagged "inside" @@ -656,13 +609,13 @@ private: { if(m_tr.is_infinite(ch)) { - ch->info().is_outside = true; + ch->is_outside() = true; const int inf_index = ch->index(m_tr.infinite_vertex()); push_facet(std::make_pair(ch, inf_index)); } else { - ch->info().is_outside = false; + ch->is_outside() = false; } } @@ -690,7 +643,7 @@ public: for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit) { Cell_handle seed = cit; - if(seed->info().is_outside || seed->tds_data().processed()) + if(seed->is_outside() || seed->tds_data().processed()) continue; std::queue to_visit; @@ -703,7 +656,7 @@ public: while(!to_visit.empty()) { const Cell_handle cell = to_visit.front(); - CGAL_assertion(!cell->info().is_outside && !m_tr.is_infinite(cell)); + CGAL_assertion(!cell->is_outside() && !m_tr.is_infinite(cell)); to_visit.pop(); @@ -715,13 +668,13 @@ public: for(int fid=0; fid<4; ++fid) { const Cell_handle neighbor = cell->neighbor(fid); - if(neighbor->info().is_outside) + if(neighbor->is_outside()) { // There shouldn't be any artificial vertex on the inside/outside boundary // (past initialization) -// CGAL_assertion(cell->vertex((fid + 1)&3)->info() == DEFAULT); -// CGAL_assertion(cell->vertex((fid + 2)&3)->info() == DEFAULT); -// CGAL_assertion(cell->vertex((fid + 3)&3)->info() == DEFAULT); +// CGAL_assertion(cell->vertex((fid + 1)&3)->type() == AW3i::Vertex_type:: DEFAULT); +// CGAL_assertion(cell->vertex((fid + 2)&3)->type() == AW3i::Vertex_type:: DEFAULT); +// CGAL_assertion(cell->vertex((fid + 3)&3)->type() == AW3i::Vertex_type:: DEFAULT); points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 0))); points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 1))); @@ -782,13 +735,13 @@ public: for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) { Facet f = *fit; - if(!f.first->info().is_outside) + if(!f.first->is_outside()) f = m_tr.mirror_facet(f); const Cell_handle c = f.first; const int s = f.second; const Cell_handle nh = c->neighbor(s); - if(c->info().is_outside == nh->info().is_outside) + if(c->is_outside() == nh->is_outside()) continue; std::array ids; @@ -961,7 +914,7 @@ private: if(m_tr.is_infinite(nh)) return TRAVERSABLE; - if(nh->info().is_outside) + if(nh->is_outside()) { #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "Neighbor already outside" << std::endl; @@ -973,7 +926,8 @@ private: for(int i=0; i<3; ++i) { const Vertex_handle vh = ch->vertex(Triangulation::vertex_triple_index(id, i)); - if(vh->info() == BBOX_VERTEX || vh->info() == SEED_VERTEX) + if(vh->type() == AW3i::Vertex_type:: BBOX_VERTEX || + vh->type() == AW3i::Vertex_type:: SEED_VERTEX) { #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "artificial facet due to artificial vertex #" << i << std::endl; @@ -999,7 +953,7 @@ private: bool push_facet(const Facet& f) { - CGAL_precondition(f.first->info().is_outside); + CGAL_precondition(f.first->is_outside()); // skip if f is already in queue if(m_queue.contains_with_bounds_check(Gate(f))) @@ -1111,7 +1065,7 @@ private: if(m_tr.is_infinite(neighbor)) { - neighbor->info().is_outside = true; + neighbor->is_outside() = true; continue; } @@ -1159,7 +1113,7 @@ private: // Actual insertion of the Steiner point Vertex_handle vh = m_tr.insert(steiner_point, lt, conflict_cell, li, lj); - vh->info() = DEFAULT; + vh->type() = AW3i::Vertex_type:: DEFAULT; visitor.after_Steiner_point_insertion(*this, vh); @@ -1169,7 +1123,7 @@ private: for(const Cell_handle& ch : new_cells) { // std::cout << "new cell has time stamp " << ch->time_stamp() << std::endl; - ch->info().is_outside = m_tr.is_infinite(ch); + ch->is_outside() = m_tr.is_infinite(ch); } // Push all new boundary facets to the queue. @@ -1185,11 +1139,11 @@ private: continue; const Cell_handle nh = ch->neighbor(i); - if(nh->info().is_outside == ch->info().is_outside) // not on the boundary + if(nh->is_outside() == ch->is_outside()) // not on the boundary continue; const Facet boundary_f = std::make_pair(ch, i); - if(ch->info().is_outside) + if(ch->is_outside()) push_facet(boundary_f); else push_facet(m_tr.mirror_facet(boundary_f)); @@ -1199,7 +1153,7 @@ private: else { // tag neighbor as OUTSIDE - neighbor->info().is_outside = true; + neighbor->is_outside() = true; // for each finite facet of neighbor, push it to the queue for(int i=0; i<4; ++i) @@ -1214,9 +1168,9 @@ private: // Check that no useful facet has been ignored CGAL_postcondition_code(for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) {) - CGAL_postcondition_code( if(fit->first->info().is_outside == fit->first->neighbor(fit->second)->info().is_outside) continue;) + CGAL_postcondition_code( if(fit->first->is_outside() == fit->first->neighbor(fit->second)->is_outside()) continue;) CGAL_postcondition_code( Facet f = *fit;) - CGAL_postcondition_code( if(!fit->first->info().is_outside) f = m_tr.mirror_facet(f);) + CGAL_postcondition_code( if(!fit->first->is_outside()) f = m_tr.mirror_facet(f);) CGAL_postcondition( facet_status(f) == IRRELEVANT); CGAL_postcondition_code(}) } @@ -1243,7 +1197,7 @@ private: for(Cell_handle ic : inc_cells) { ic->tds_data().clear(); - if(ic->info().is_outside) + if(ic->is_outside()) outside_start = ic; else if(inside_start == Cell_handle()) inside_start = ic; @@ -1278,7 +1232,7 @@ private: CGAL_assertion(neigh_c->has_vertex(v)); if(neigh_c->tds_data().processed() || - neigh_c->info().is_outside != curr_c->info().is_outside) // do not cross the boundary + neigh_c->is_outside() != curr_c->is_outside()) // do not cross the boundary continue; cells_to_visit.push(neigh_c); @@ -1343,7 +1297,7 @@ private: for(Cell_handle c : inc_cells) { - if(!c->info().is_outside) + if(!c->is_outside()) { do_remove = false; break; @@ -1390,15 +1344,20 @@ public: auto has_artificial_vertex = [](Cell_handle c) -> bool { for(int i=0; i<4; ++i) - if(c->vertex(i)->info() == BBOX_VERTEX || c->vertex(i)->info() == SEED_VERTEX) + { + if(c->vertex(i)->type() == AW3i::Vertex_type:: BBOX_VERTEX || + c->vertex(i)->type() == AW3i::Vertex_type:: SEED_VERTEX) + { return true; + } + } return false; }; auto is_on_boundary = [](Cell_handle c, int i) -> bool { - return (c->info().is_outside != c->neighbor(i)->info().is_outside); + return (c->is_outside() != c->neighbor(i)->is_outside()); }; auto count_boundary_facets = [&](Cell_handle c, Vertex_handle v) -> int @@ -1492,7 +1451,7 @@ public: CGAL_assertion(!m_tr.is_infinite(ic)); // This is where new material is added - ic->info().is_outside = false; + ic->is_outside() = false; #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP static int i = 0; @@ -1577,7 +1536,7 @@ private: int s = fit->second; Cell_handle nc = c->neighbor(s); - if(only_boundary_faces && (c->info().is_outside == nc->info().is_outside)) + if(only_boundary_faces && (c->is_outside() == nc->is_outside())) continue; std::array ids; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_geom_traits.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_geom_traits.h index 22c64e9b5e2..80a403c258e 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_geom_traits.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_geom_traits.h @@ -36,24 +36,24 @@ struct Tetrahedron_with_outside_info using Triangle_3 = typename Kernel::Triangle_3; template - Tetrahedron_with_outside_info(const CellHandle ch, const K& k) + Tetrahedron_with_outside_info(const CellHandle c, const K& k) { typename K::Construct_bbox_3 bbox = k.construct_bbox_3_object(); typename K::Construct_tetrahedron_3 tetrahedron = k.construct_tetrahedron_3_object(); typename K::Construct_triangle_3 triangle = k.construct_triangle_3_object(); - m_tet = tetrahedron(ch->vertex(0)->point(), ch->vertex(1)->point(), - ch->vertex(2)->point(), ch->vertex(3)->point()); + m_tet = tetrahedron(c->vertex(0)->point(), c->vertex(1)->point(), + c->vertex(2)->point(), c->vertex(3)->point()); m_bbox = bbox(m_tet); for(int i=0; i<4; ++i) { - if(ch->neighbor(i)->info().is_outside) + if(c->neighbor(i)->is_outside()) m_b.set(i, true); - m_triangles[i] = triangle(ch->vertex((i+1)& 3)->point(), - ch->vertex((i+2)& 3)->point(), - ch->vertex((i+3)& 3)->point()); + m_triangles[i] = triangle(c->vertex((i+1)& 3)->point(), + c->vertex((i+2)& 3)->point(), + c->vertex((i+3)& 3)->point()); m_tbox[i] = bbox(m_triangles[i]); } } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h new file mode 100644 index 00000000000..ebe337b614c --- /dev/null +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h @@ -0,0 +1,97 @@ +// Copyright (c) 2019-2023 Google LLC (USA). +// 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) : Mael Rouxel-Labbé + +#ifndef CGAL_ALPHA_WRAP_TRIANGULATION_CELL_BASE_3_H +#define CGAL_ALPHA_WRAP_TRIANGULATION_CELL_BASE_3_H + +#include + +#include + +namespace CGAL { +namespace Alpha_wraps_3 { +namespace internal { + +template < typename GT, + typename Cb = CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3 > +class Alpha_wrap_triangulation_cell_base_3 + : public Cb +{ +private: + bool outside; + +public: + typedef typename Cb::Vertex_handle Vertex_handle; + typedef typename Cb::Cell_handle Cell_handle; + + template < typename TDS2 > + struct Rebind_TDS + { + using Cb2 = typename Cb::template Rebind_TDS::Other; + using Other = Alpha_wrap_triangulation_cell_base_3; + }; + + Alpha_wrap_triangulation_cell_base_3() + : Cb() + {} + + Alpha_wrap_triangulation_cell_base_3(Vertex_handle v0, Vertex_handle v1, + Vertex_handle v2, Vertex_handle v3) + : Cb(v0, v1, v2, v3) + {} + + Alpha_wrap_triangulation_cell_base_3(Vertex_handle v0, Vertex_handle v1, + Vertex_handle v2, Vertex_handle v3, + Cell_handle n0, Cell_handle n1, + Cell_handle n2, Cell_handle n3) + : Cb(v0, v1, v2, v3, n0, n1, n2, n3) + {} + + bool is_outside() const { return outside; } + bool& is_outside() { return outside; } +}; + +template +class Cell_base_with_timestamp + : public Cb +{ + std::size_t time_stamp_; + +public: + using Has_timestamp = CGAL::Tag_true; + + template + struct Rebind_TDS + { + using Cb2 = typename Cb::template Rebind_TDS::Other; + using Other = Cell_base_with_timestamp; + }; + +public: + template + Cell_base_with_timestamp(const Args&... args) + : Cb(args...), time_stamp_(-1) + { } + + Cell_base_with_timestamp(const Cell_base_with_timestamp& other) + : Cb(other), time_stamp_(other.time_stamp_) + { } + +public: + std::size_t time_stamp() const { return time_stamp_; } + void set_time_stamp(const std::size_t& ts) { time_stamp_ = ts; } +}; + +} // namespace internal +} // namespace Alpha_wraps_3 +} // namespace CGAL + +#endif // CGAL_ALPHA_WRAP_TRIANGULATION_CELL_BASE_3_H diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_vertex_base_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_vertex_base_3.h new file mode 100644 index 00000000000..75f26741755 --- /dev/null +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_vertex_base_3.h @@ -0,0 +1,71 @@ +// Copyright (c) 2019-2023 Google LLC (USA). +// 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) : Mael Rouxel-Labbé + +#ifndef CGAL_ALPHA_WRAP_TRIANGULATION_VERTEX_BASE_3_H +#define CGAL_ALPHA_WRAP_TRIANGULATION_VERTEX_BASE_3_H + +#include + +#include + +namespace CGAL { +namespace Alpha_wraps_3 { +namespace internal { + +enum class Vertex_type +{ + DEFAULT = 0, + BBOX_VERTEX, + SEED_VERTEX +}; + +template > +class Alpha_wrap_triangulation_vertex_base_3 + : public Vb +{ +private: + Vertex_type vertex_type; + +public: + using Cell_handle = typename Vb::Cell_handle; + using Point = typename Vb::Point; + + template + struct Rebind_TDS + { + using Vb2 = typename Vb::template Rebind_TDS::Other; + using Other = Alpha_wrap_triangulation_vertex_base_3; + }; + +public: + Alpha_wrap_triangulation_vertex_base_3() + : Vb() {} + + Alpha_wrap_triangulation_vertex_base_3(const Point& p) + : Vb(p) {} + + Alpha_wrap_triangulation_vertex_base_3(const Point& p, Cell_handle c) + : Vb(p, c) {} + + Alpha_wrap_triangulation_vertex_base_3(Cell_handle c) + : Vb(c) {} + +public: + const Vertex_type& type() const { return vertex_type; } + Vertex_type& type() { return vertex_type; } +}; + +} // namespace internal +} // namespace Alpha_wraps_3 +} // namespace CGAL + +#endif // CGAL_ALPHA_WRAP_TRIANGULATION_VERTEX_BASE_3_H diff --git a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp index a105d1ba12e..a1b29fd5689 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp @@ -153,13 +153,13 @@ public: for(auto fit=wrapper.triangulation().finite_facets_begin(), fend=wrapper.triangulation().finite_facets_end(); fit!=fend; ++fit) { Facet f = *fit; - if(!f.first->info().is_outside) + if(!f.first->is_outside()) f = wrapper.triangulation().mirror_facet(f); const Cell_handle c = f.first; const int s = f.second; const Cell_handle nh = c->neighbor(s); - if(c->info().is_outside == nh->info().is_outside) + if(c->is_outside() == nh->is_outside()) continue; std::array ids; From 5179c4acb12724fa452591946300fd1b8d25bc28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Thu, 3 Aug 2023 12:06:23 +0200 Subject: [PATCH 06/35] Clean examples --- .../examples/Alpha_wrap_3/mixed_inputs_wrap.cpp | 2 +- .../examples/Alpha_wrap_3/volumetric_wrap.cpp | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp index be64a8febbd..ffcedc7f1cb 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp @@ -16,9 +16,9 @@ using K = CGAL::Exact_predicates_inexact_constructions_kernel; using Point_3 = K::Point_3; using Segment_3 = K::Segment_3; -using Face = std::array; using Segments = std::vector; using Points = std::vector; +using Face = std::array; using Faces = std::vector; using Mesh = CGAL::Surface_mesh; diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp index dd63ad66711..66e9653f1b4 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp @@ -129,9 +129,7 @@ int main(int argc, char** argv) std::cout << "BEFORE: " << tr.number_of_vertices() << " vertices, " << tr.number_of_cells() << " cells" << std::endl; - // Set up the domain information and grab the boundary faces - std::set boundary_facets; - + // Set up the c3t3 information for(auto v : tr.finite_vertex_handles()) v->set_dimension(3); @@ -149,24 +147,25 @@ int main(int argc, char** argv) if(c->neighbor(i)->is_outside() != c->is_outside()) { c->set_surface_patch_index(i, 1); - boundary_facets.emplace(c, i); for(int j=1; j<4; ++j) c->vertex((i+j)%4)->set_dimension(2); } } } - // CGAL::draw(tr); std::ofstream out_before("before_remeshing.mesh"); CGAL::IO::write_MEDIT(out_before, tr); - auto fcm = CGAL::make_boolean_property_map(boundary_facets); - CGAL::tetrahedral_isotropic_remeshing(tr, alpha, - CGAL::parameters::facet_is_constrained_map(fcm)); + // edge length of equilateral triangle with circumradius alpha + // const double l = 2 * alpha * 0.8660254037844386; // sqrt(3)/2 + + // edge length of regular tetrahedron with circumradius alpha + const double l = 1.6329931618554521 * alpha; // sqrt(8/3) + + CGAL::tetrahedral_isotropic_remeshing(tr, l, CGAL::parameters::remesh_boundaries(false)); std::cout << "AFTER: " << tr.number_of_vertices() << " vertices, " << tr.number_of_cells() << " cells" << std::endl; - // CGAL::draw(tr); std::ofstream out_after("after_remeshing.mesh"); CGAL::IO::write_MEDIT(out_after, tr); From 6949cdb40aca7874b2f16fed0256802a58f83891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Thu, 3 Aug 2023 12:15:36 +0200 Subject: [PATCH 07/35] Fix missing default initialization of the AW3 markers in the new Vb/Cb --- .../internal/Alpha_wrap_triangulation_cell_base_3.h | 2 +- .../internal/Alpha_wrap_triangulation_vertex_base_3.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h index ebe337b614c..db1df61c8f6 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h @@ -26,7 +26,7 @@ class Alpha_wrap_triangulation_cell_base_3 : public Cb { private: - bool outside; + bool outside = false; public: typedef typename Cb::Vertex_handle Vertex_handle; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_vertex_base_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_vertex_base_3.h index 75f26741755..3743edffbc7 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_vertex_base_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_vertex_base_3.h @@ -33,7 +33,7 @@ class Alpha_wrap_triangulation_vertex_base_3 : public Vb { private: - Vertex_type vertex_type; + Vertex_type vertex_type = Vertex_type::DEFAULT; public: using Cell_handle = typename Vb::Cell_handle; From 57fe29fe4f3308f9b2fcbfdfb303481581de4705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 4 Aug 2023 11:26:46 +0200 Subject: [PATCH 08/35] Add some comments about failed speedup experiments --- .../include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index ba752a77590..04b30cf7678 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1082,10 +1082,12 @@ private: const Cell_handle conflict_cell = m_tr.locate(steiner_point, lt, li, lj, neighbor); CGAL_assertion(lt != Triangulation::VERTEX); + // Using small vectors like in Triangulation_3 does not bring any runtime improvement std::vector boundary_facets; std::vector conflict_zone; boundary_facets.reserve(32); conflict_zone.reserve(32); + m_tr.find_conflicts(steiner_point, conflict_cell, std::back_inserter(boundary_facets), std::back_inserter(conflict_zone)); @@ -1112,6 +1114,8 @@ private: visitor.before_Steiner_point_insertion(*this, steiner_point); // Actual insertion of the Steiner point + // We could use TDS functions to avoid recomputing the conflict zone, but in practice + // it does not bring any runtime improvements Vertex_handle vh = m_tr.insert(steiner_point, lt, conflict_cell, li, lj); vh->type() = AW3i::Vertex_type:: DEFAULT; From 6b62d1d9b40d765462fa79bbee6baee04b243f00 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 9 Aug 2023 10:48:54 +0300 Subject: [PATCH 09/35] Introduced is_intersection_valid() to check the validity of a new intersection point. Perhaps, a similar fix is required for validity of overlapping intersections --- .../Arrangement_2/Arrangement_zone_2_impl.h | 106 +++++++++--------- .../include/CGAL/Arrangement_zone_2.h | 21 +++- 2 files changed, 72 insertions(+), 55 deletions(-) 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 feb429273ee..dfb8851479f 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 @@ -137,7 +137,7 @@ void Arrangement_zone_2::compute_zone() if (m_found_overlap) { // In this case m_cv overlaps the curve associated with m_intersect_he. // Compute the overlapping subcurve. - bool dummy; + Arr_parameter_space dummy; auto obj = _compute_next_intersection(m_intersect_he, false, dummy); m_overlap_cv = boost::get(*obj); @@ -153,7 +153,7 @@ void Arrangement_zone_2::compute_zone() // overlaps the curve associated with this edge. m_intersect_he = m_arr.non_const_handle(*hh); - bool dummy; + Arr_parameter_space dummy; auto obj = _compute_next_intersection(m_intersect_he, false, dummy); m_overlap_cv = boost::get(*obj); @@ -211,7 +211,7 @@ void Arrangement_zone_2::compute_zone() if (m_found_overlap) { // In this case m_cv overlaps the curve associated with m_intersect_he. // Compute the overlapping subcurve to the right of curr_v. - bool dummy; + Arr_parameter_space dummy; auto obj = _compute_next_intersection(m_intersect_he, false, dummy); m_overlap_cv = boost::get(*obj); @@ -505,6 +505,37 @@ _direct_intersecting_edge_to_left(const X_monotone_curve_2& cv_ins, } } +//----------------------------------------------------------------------------- +template +bool Arrangement_zone_2:: +is_intersection_valid_impl(const Point_2& ip, + Arr_parameter_space& /* intersection_location */, + Arr_all_sides_oblivious_tag) const +{ return (m_geom_traits->compare_xy_2_object()(ip, m_left_pt) == LARGER); } + +template +bool Arrangement_zone_2:: +is_intersection_valid_impl(const Point_2& ip, + Arr_parameter_space& intersection_location, + Arr_not_all_sides_oblivious_tag) const { + auto equal = m_geom_traits->equal_2_object(); + if (m_left_on_boundary) { + // The left-end lies on the left boundary. If the intersection point is not + // equal to the left-end, the intersection is valid, because it must lie to + // its right. + if (m_has_left_pt) return ! equal(ip, m_left_pt); + else return true; + } + if (m_has_right_pt && m_right_on_boundary && equal(ip, m_right_pt)) { + intersection_location = ARR_RIGHT_BOUNDARY; + return true; + } + + // We have a simple intersection point; + // make sure it lies to the right of m_left_pt. + return (m_geom_traits->compare_xy_2_object()(ip, m_left_pt) == LARGER); +} + //----------------------------------------------------------------------------- // Get the next intersection of cv with the given halfedge. // @@ -513,7 +544,7 @@ typename Arrangement_zone_2::Optional_intersection Arrangement_zone_2:: _compute_next_intersection(Halfedge_handle he, bool skip_first_point, - bool& intersection_on_right_boundary) + Arr_parameter_space& intersection_location) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_compute_next_intersection(" << he->curve() << ", " @@ -534,7 +565,7 @@ _compute_next_intersection(Halfedge_handle he, const X_monotone_curve_2* icv; bool valid_intersection; - intersection_on_right_boundary = false; + intersection_location = ARR_INTERIOR; if (iter != m_inter_map.end()) { // The intersections with the curve have already been computed. // Retrieve the intersections list from the map. @@ -548,25 +579,9 @@ _compute_next_intersection(Halfedge_handle he, // Compare that current object with m_left_pt (if exists). ip = boost::get(&(inter_list.front())); if (ip != nullptr) { - // We have an intersection point - if (m_left_on_boundary) { - // The left-end lies on the left boundary. If the intersection point - // is not equal to the left-end, the intersection is valid, because - // it must lie to its right. - if (m_has_left_pt) valid_intersection = ! equal(ip->first, m_left_pt); - else valid_intersection = true; - } - else if (m_has_right_pt && m_right_on_boundary && - equal(ip->first, m_right_pt)) - { - valid_intersection = true; - intersection_on_right_boundary = true; - } - else { - // We have a simple intersection point - make sure it lies to the - // right of m_left_pt. - valid_intersection = (compare_xy(ip->first, m_left_pt) == LARGER); - } + // We have an intersection point - + valid_intersection = + is_intersection_valid(ip->first, intersection_location); } else { // We have an overlapping subcurve. @@ -609,27 +624,11 @@ _compute_next_intersection(Halfedge_handle he, while (! inter_list.empty()) { // Compare that current object with m_left_pt (if exists). ip = boost::get(&(inter_list.front())); - if (ip != nullptr) { // We have an intersection point - // Check whether we need to skip the first intersection - if (is_first && skip_first_point) valid_intersection = false; - else if (m_left_on_boundary) { - // The left-end lies on the left boundary. If the intersection point - // is not equal to the left-end, the intersection is valid, because - // it must lie to its right. - if (m_has_left_pt) valid_intersection = ! equal(ip->first, m_left_pt); - else valid_intersection = true; - } - else if (m_right_on_boundary && m_has_right_pt && - equal(ip->first, m_right_pt)) - { - valid_intersection = true; - intersection_on_right_boundary = true; - } - else { - valid_intersection = (compare_xy(ip->first, m_left_pt) == LARGER); - } + valid_intersection = (is_first && skip_first_point) ? false : + is_intersection_valid(ip->first, intersection_location); } else if (m_left_on_boundary) { // The left end is on the boundary, so all overlapping curves are valid, @@ -768,7 +767,7 @@ _is_to_right_impl(const Point_2& p, Halfedge_handle he, template void Arrangement_zone_2:: _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, - bool& leftmost_on_right_boundary) + Arr_parameter_space& leftmost_location) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_leftmost_intersection(" << he_curr->curve() << ", " @@ -793,7 +792,7 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, // entirely to the right of m_intersect_p, its intersection with m_cv (if any) // cannot lie to the left of this point. We therefore do not need to compute // this intersection. - if (m_found_intersect && ! leftmost_on_right_boundary && + if (m_found_intersect && (leftmost_location != ARR_RIGHT_BOUNDARY) && _is_to_left(m_intersect_p, he_curr)) return; @@ -821,13 +820,14 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, // do not intersect. if (! left_equals_curr_endpoint && ((! m_left_on_boundary && _is_to_right(m_left_pt, he_curr)) || - ! is_in_x_range(m_cv, he_curr->curve()))) + ! is_in_x_range(m_cv, he_curr->curve()))) { return; + } // Compute the next intersection of m_cv and the current halfedge. - bool intersection_on_right_boundary; + Arr_parameter_space intersection_location; auto iobj = _compute_next_intersection(he_curr, left_equals_curr_endpoint, - intersection_on_right_boundary); + intersection_location); if (iobj) { // We have found an intersection (either a simple point or an @@ -839,8 +839,8 @@ _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_on_right_boundary && - (leftmost_on_right_boundary || + ((intersection_location != ARR_RIGHT_BOUNDARY) && + ((leftmost_location == ARR_RIGHT_BOUNDARY) || compare_xy(ip, m_intersect_p) == SMALLER))) { // Store the leftmost intersection point and the halfedge handle. @@ -848,7 +848,7 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, m_ip_multiplicity = int_p->second; m_intersect_he = he_curr; m_found_overlap = false; - leftmost_on_right_boundary = intersection_on_right_boundary; + leftmost_location = intersection_location; } } else { @@ -895,7 +895,7 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) auto compare_xy = m_geom_traits->compare_xy_2_object(); auto is_in_x_range = m_geom_traits->is_in_x_range_2_object(); - bool leftmost_on_right_boundary = false; + Arr_parameter_space leftmost_location = ARR_INTERIOR; // Traverse the face outer-boundaries; iterate through all outer CCBs. for (auto occb_it = face->outer_ccbs_begin(); @@ -903,7 +903,7 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) { Ccb_halfedge_circulator he_first = *occb_it; Ccb_halfedge_circulator he_curr = he_first; - do _leftmost_intersection(he_curr, on_boundary, leftmost_on_right_boundary); + do _leftmost_intersection(he_curr, on_boundary, leftmost_location); while (++he_curr != he_first); } @@ -913,7 +913,7 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) { Ccb_halfedge_circulator he_first = *iccb_it; Ccb_halfedge_circulator he_curr = he_first; - do _leftmost_intersection(he_curr, on_boundary, leftmost_on_right_boundary); + do _leftmost_intersection(he_curr, on_boundary, leftmost_location); while (++he_curr != he_first); } 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 81f1c8bad04..71b5e4a7409 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h @@ -336,7 +336,7 @@ private: Optional_intersection _compute_next_intersection(Halfedge_handle he, bool skip_first_point, - bool& intersect_on_right_boundary); + Arr_parameter_space& intersection_location); /*! Remove the next intersection of m_cv with the given halfedge from the map. * \param he A handle to the halfedge. @@ -394,12 +394,29 @@ private: bool _is_to_right_impl(const Point_2& p, Halfedge_handle he, Arr_not_all_sides_oblivious_tag) const; + /*! Check whether an intersection point is valid. A valid intersection point + * must be to the left of the left end of the curve involved. + */ + bool is_intersection_valid(const Point_2& ip, + Arr_parameter_space& intersection_location) const { + return is_intersection_valid_impl(ip, intersection_location, + Are_all_sides_oblivious_category()); + } + + bool is_intersection_valid_impl(const Point_2& ip, + Arr_parameter_space& intersection_location, + Arr_all_sides_oblivious_tag) const; + + bool is_intersection_valid_impl(const Point_2& ip, + Arr_parameter_space& intersection_location, + Arr_not_all_sides_oblivious_tag) const; + /*! Compute the (lexicographically) leftmost intersection of the query * curve with a given halfedge on the boundary of a face in the arrangement. */ void _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, - bool& leftmost_on_right_boundary); + Arr_parameter_space& leftmost_location); /*! Compute the (lexicographically) leftmost intersection of the query * curve with the boundary of a given face in the arrangement. From a9625eb17cfd5da8f96686ac6cb122645f4caa0f Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 9 Aug 2023 14:03:14 +0300 Subject: [PATCH 10/35] Enhanced drawing---added support for arrangement on spheres indiced by geodesic arcs --- .../include/CGAL/draw_arrangement_2.h | 240 ++++++++++++++---- 1 file changed, 193 insertions(+), 47 deletions(-) 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 c7637f04b91..76e2eaf3283 100644 --- a/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h +++ b/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h @@ -29,7 +29,9 @@ #include #include +#include #include +#include namespace CGAL { @@ -46,32 +48,32 @@ struct Default_color_generator { }; // Viewer class for`< Polygon_2 -template -class Arr_2_basic_viewer_qt : public Basic_viewer_qt { - using Arr = Arrangement_2_; +class Aos_2_basic_viewer_qt : public Basic_viewer_qt { + using Aos = ArrangementOnSurface_2; using Color_generator = ColorGenerator; using Base = Basic_viewer_qt; - using Gt = typename Arr::Geometry_traits_2; - using Point = typename Arr::Point_2; - using X_monotone_curve = typename Arr::X_monotone_curve_2; - using Vertex_const_handle = typename Arr::Vertex_const_handle; - using Halfedge_const_handle = typename Arr::Halfedge_const_handle; - using Face_const_handle = typename Arr::Face_const_handle; + using Gt = typename Aos::Geometry_traits_2; + using Point = typename Aos::Point_2; + using X_monotone_curve = typename Aos::X_monotone_curve_2; + using Vertex_const_handle = typename Aos::Vertex_const_handle; + using Halfedge_const_handle = typename Aos::Halfedge_const_handle; + using Face_const_handle = typename Aos::Face_const_handle; using Ccb_halfedge_const_circulator = - typename Arr::Ccb_halfedge_const_circulator; + typename Aos::Ccb_halfedge_const_circulator; public: /// Construct the viewer. /// @param arr the arrangement to view /// @param title the title of the window - Arr_2_basic_viewer_qt(QWidget* parent, const Arr& arr, + Aos_2_basic_viewer_qt(QWidget* parent, const Aos& aos, Color_generator color_generator, const char* title = "2D Arrangement Basic Viewer", bool draw_vertices = false) : // First draw: vertices; edges, faces; multi-color; no inverse normal Base(parent, title, draw_vertices, true, true, false, false), - m_arr(arr), + m_aos(aos), m_color_generator(color_generator) { // mimic the computation of Camera::pixelGLRatio() @@ -154,32 +156,47 @@ public: */ CGAL::Bbox_2 bounding_box() { CGAL::Bbox_2 bbox; - const auto* traits = this->m_arr.geometry_traits(); + const auto* traits = this->m_aos.geometry_traits(); // At this point we assume that the arrangement is not open, and thus the // bounding box is defined by the vertices. - for (auto it = m_arr.vertices_begin(); it != m_arr.vertices_end(); ++it) + for (auto it = m_aos.vertices_begin(); it != m_aos.vertices_end(); ++it) bounding_box_impl1(bbox, it->point(), *traits, 0); return bbox; } + /*! 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()); } + /*! Add all elements to be drawn. */ void add_elements() { + // std::cout << "add_elements()\n"; // std::cout << "ratio: " << this->pixel_ratio() << std::endl; clear(); m_visited.clear(); - if (m_arr.is_empty()) return; - for (auto it = m_arr.unbounded_faces_begin(); - it != m_arr.unbounded_faces_end(); ++it) - add_face(it); + if (m_aos.is_empty()) return; + add_faces(*(this->m_aos.geometry_traits())); - // Add edges that do not separe faces. - for (auto it = m_arr.edges_begin(); it != m_arr.edges_end(); ++it) + // Add edges that do not separate faces. + for (auto it = m_aos.edges_begin(); it != m_aos.edges_end(); ++it) if (it->face() == it->twin()->face()) draw_curve(it->curve()); // Add all points - for (auto it = m_arr.vertices_begin(); it != m_arr.vertices_end(); ++it) + for (auto it = m_aos.vertices_begin(); it != m_aos.vertices_end(); ++it) draw_point(it->point()); m_visited.clear(); @@ -190,11 +207,20 @@ public: double pixel_ratio() const { return m_pixel_ratio; } protected: + 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. */ - Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ) { - const auto* traits = this->m_arr.geometry_traits(); + 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(); @@ -241,6 +267,7 @@ protected: template void draw_approximate_region(Halfedge_const_handle curr, const Approximate& approx) { + // std::cout << "draw_approximate_region()\n"; std::vector polyline; double error(this->pixel_ratio()); bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT; @@ -258,7 +285,7 @@ protected: */ template void draw_exact_curve(const XMonotoneCurve& curve) { - const auto* traits = this->m_arr.geometry_traits(); + 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(); this->add_segment(ctr_min(curve), ctr_max(curve)); @@ -267,7 +294,7 @@ protected: /*! Draw an exact region. */ void draw_exact_region(Halfedge_const_handle curr) { - this->add_point_in_face(curr->source()->point()); + // this->add_point_in_face(curr->source()->point()); draw_exact_curve(curr->curve()); } @@ -300,9 +327,46 @@ protected: { draw_approximate_region(curr, traits.approximate_2_object()); } #endif + template + void draw_region_impl1 + (Halfedge_const_handle curr, + Arr_geodesic_arc_on_sphere_traits_2 const& traits, + int) { + // 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; + + 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); + this->add_segment(prev, next); + prev = next; + // this->add_point_in_face(*prev); + } + } + /*! Draw 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 * `Approximate_2` has an appropriate operator. @@ -321,8 +385,8 @@ protected: auto color = m_color_generator(circ->face()); this->face_begin(color); - const auto* traits = this->m_arr.geometry_traits(); - auto ext = find_smallest(circ); + const auto* traits = this->m_aos.geometry_traits(); + auto ext = find_smallest(circ, *traits); auto curr = ext; do { @@ -382,6 +446,37 @@ protected: { draw_approximate_curve(xcv, traits.approximate_2_object()); } #endif + template + void draw_curve_impl1 + (const X_monotone_curve& xcv, + Arr_geodesic_arc_on_sphere_traits_2 const& traits, + int) { + 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 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); + this->add_segment(prev, next); + prev = next; + } + } + /*! Draw a curve. */ template @@ -404,14 +499,14 @@ protected: #if 0 if constexpr (std::experimental::is_detected_v) { - const auto* traits = this->m_arr.geometry_traits(); + 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 - const auto* traits = this->m_arr.geometry_traits(); + const auto* traits = this->m_aos.geometry_traits(); draw_curve_impl1(curve, *traits, 0); #endif } @@ -442,16 +537,35 @@ protected: { 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) { + 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); + add_point(p3); + } + /*! Draw a point. */ void draw_point(const Point& p) { - const auto* traits = m_arr.geometry_traits(); + const auto* traits = m_aos.geometry_traits(); draw_point_impl1(p, *traits, 0); } /*! 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(); @@ -464,8 +578,9 @@ protected: /*! Add a face. */ void add_face(Face_const_handle face) { - using Inner_ccb_const_iterator = typename Arr::Inner_ccb_const_iterator; - using Outer_ccb_const_iterator = typename Arr::Outer_ccb_const_iterator; + // std::cout << "add_face()\n"; + using Inner_ccb_const_iterator = typename Aos::Inner_ccb_const_iterator; + using Outer_ccb_const_iterator = typename Aos::Outer_ccb_const_iterator; for (Inner_ccb_const_iterator it = face->inner_ccbs_begin(); it != face->inner_ccbs_end(); ++it) @@ -505,7 +620,7 @@ protected: double m_pixel_ratio = 1; //! The arrangement to draw. - const Arr& m_arr; + const Aos& m_aos; //! The color generator. Color_generator m_color_generator; @@ -514,32 +629,63 @@ protected: }; //! Basic viewer of a 2D arrangement. -template -class Arr_2_viewer_qt : public Arr_2_basic_viewer_qt { public: - using Arr = Arrangement_2_; + using Aos = ArrangementOnSurface_2; using Color_generator = ColorGenerator; - using Base = Arr_2_basic_viewer_qt; - using Point = typename Arr::Point_2; - using X_monotone_curve = typename Arr::X_monotone_curve_2; - using Halfedge_const_handle = typename Arr::Halfedge_const_handle; - using Face_const_handle = typename Arr::Face_const_handle; + using Base = Aos_2_basic_viewer_qt; + using Point = typename Aos::Point_2; + using X_monotone_curve = typename Aos::X_monotone_curve_2; + using Halfedge_const_handle = typename Aos::Halfedge_const_handle; + using Face_const_handle = typename Aos::Face_const_handle; using Ccb_halfedge_const_circulator = - typename Arr::Ccb_halfedge_const_circulator; + typename Aos::Ccb_halfedge_const_circulator; /// Construct the viewer. /// @param arr the arrangement to view /// @param title the title of the window - Arr_2_viewer_qt(QWidget* parent, const Arr& arr, + Aos_2_viewer_qt(QWidget* parent, const Aos& aos, Color_generator color_generator, - const char* title = "2D Arrangement Basic Viewer", + const char* title = "2D Arrangement on Surface Basic Viewer", bool draw_vertices = false) : - Base(parent, arr, color_generator, title, draw_vertices) + Base(parent, aos, color_generator, title, draw_vertices) {} }; +/*! Draw an arrangement on surface. + */ +template +void draw(const Arrangement_on_surface_2& aos, + const char* title = "2D Arrangement on Surface Basic Viewer", + bool draw_vertices = false) { +#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; + using Gt = GeometryTraits_2; + using Tt = TopologyTraits; + using Aos = CGAL::Arrangement_on_surface_2; + using Viewer = Aos_2_viewer_qt; + + CGAL::Qt::init_ogl_context(4,3); + + int argc = 1; + const char* argv[2] = {"t2_viewer", nullptr}; + QApplication app(argc, const_cast(argv)); + Default_color_generator color_generator; + Viewer mainwindow(app.activeWindow(), aos, color_generator, title, + draw_vertices); + mainwindow.add_elements(); + mainwindow.show(); + app.exec(); +} + /*! Draw an arrangement. */ template @@ -555,7 +701,7 @@ void draw(const Arrangement_2& arr, if (cgal_test_suite) return; using Gt = GeometryTraits_2; using Arr = CGAL::Arrangement_2; - using Viewer = Arr_2_viewer_qt; + using Viewer = Aos_2_viewer_qt; CGAL::Qt::init_ogl_context(4,3); @@ -589,7 +735,7 @@ void draw(const Arrangement_2& arr, using Color_generator = ColorGenerator; using Gt = GeometryTraits_2; using Arr = CGAL::Arrangement_2; - using Viewer = Arr_2_viewer_qt; + using Viewer = Aos_2_viewer_qt; CGAL::Qt::init_ogl_context(4,3); From 46c42465706e397c031b5e15d1d70584afc6a913 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 9 Aug 2023 17:37:01 +0300 Subject: [PATCH 11/35] Cleaned up --- .../Arr_geodesic_arc_on_sphere_traits_2.h | 719 +++++++++--------- 1 file changed, 360 insertions(+), 359 deletions(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h index 7a0a2eaa3af..e3a934889bc 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h @@ -39,9 +39,86 @@ namespace CGAL { +/*! Represent an extended 3D direction that is used in turn to represent a + * spherical-arc endpoint. The extended data consists of two flags that + * indicate whether the point is on the x and on a y boundaries, + * respectively. + */ +template +class Arr_extended_direction_3 : public Kernel::Direction_3 { +public: + using FT = typename Kernel::FT; + using Direction_3 = typename Kernel::Direction_3; + + /*! Enumeration of discontinuity type */ + enum Location_type { + NO_BOUNDARY_LOC = 0, + MIN_BOUNDARY_LOC, + MID_BOUNDARY_LOC, + MAX_BOUNDARY_LOC + }; + +private: + using Direction_2 = typename Kernel::Direction_2; + + //! The point discontinuity type + Location_type m_location; + + inline Sign x_sign(Direction_3 d) const { return CGAL::sign(d.dx()); } + + inline Sign y_sign(Direction_3 d) const { return CGAL::sign(d.dy()); } + + inline Sign z_sign(Direction_3 d) const { return CGAL::sign(d.dz()); } + +public: + /*! Default constructor */ + Arr_extended_direction_3() : + Direction_3(0, 0, 1), + m_location(MAX_BOUNDARY_LOC) + {} + + /*! Constructor */ + Arr_extended_direction_3(const Direction_3& dir, Location_type location) : + Direction_3(dir), + m_location(location) + {} + + /*! Copy constructor */ + Arr_extended_direction_3(const Arr_extended_direction_3& other) : + Direction_3(static_cast(other)) + { m_location = other.discontinuity_type(); } + + /*! Assignment operator */ + Arr_extended_direction_3& operator=(const Arr_extended_direction_3& other) { + *(static_cast(this)) = static_cast(other); + m_location = other.discontinuity_type(); + return (*this); + } + + /*! Set the location of the point. + */ + void set_location(Location_type location) { m_location = location; } + + /*! Obtain the location of the point. + */ + Location_type location() const { return m_location; } + + /*! Obtain the discontinuity type of the point. + * \todo deprecate this one; use the above instead. + */ + Location_type discontinuity_type() const { return m_location; } + + bool is_no_boundary() const { return (m_location == NO_BOUNDARY_LOC); } + + bool is_min_boundary() const { return (m_location == MIN_BOUNDARY_LOC); } + + bool is_mid_boundary() const { return (m_location == MID_BOUNDARY_LOC); } + + bool is_max_boundary() const { return (m_location == MAX_BOUNDARY_LOC); } +}; + template class Arr_x_monotone_geodesic_arc_on_sphere_3; template class Arr_geodesic_arc_on_sphere_3; -template class Arr_extended_direction_3; /*! A traits class-template for constructing and maintaining arcs of great * circles embedded on spheres. It is parameterized from a (linear) geometry @@ -54,44 +131,43 @@ class Arr_geodesic_arc_on_sphere_traits_2 : public Kernel_ { friend class Arr_extended_direction_3; public: - typedef Kernel_ Kernel; + using Kernel = Kernel_; // Category tags: - typedef Tag_true Has_left_category; - typedef Tag_true Has_merge_category; - typedef Tag_false Has_do_intersect_category; + using Has_left_category = Tag_true; + using Has_merge_category = Tag_true; + using Has_do_intersect_category = Tag_false; - typedef Arr_identified_side_tag Left_side_category; - typedef Arr_contracted_side_tag Bottom_side_category; - typedef Arr_contracted_side_tag Top_side_category; - typedef Arr_identified_side_tag Right_side_category; + using Left_side_category = Arr_identified_side_tag; + using Bottom_side_category = Arr_contracted_side_tag; + using Top_side_category = Arr_contracted_side_tag; + using Right_side_category = Arr_identified_side_tag; - typedef std::integral_constant Zero_atan_y; + using Zero_atan_y = std::integral_constant; // Traits objects - typedef Arr_extended_direction_3 Point_2; - typedef Arr_x_monotone_geodesic_arc_on_sphere_3 X_monotone_curve_2; - typedef Arr_geodesic_arc_on_sphere_3 Curve_2; - typedef unsigned int Multiplicity; + using Point_2 = Arr_extended_direction_3; + using X_monotone_curve_2 = Arr_x_monotone_geodesic_arc_on_sphere_3; + using Curve_2 = Arr_geodesic_arc_on_sphere_3; + using Multiplicity = std::size_t; /*! Default constructor */ Arr_geodesic_arc_on_sphere_traits_2() {} protected: - typedef typename Kernel::FT FT; + using FT = typename Kernel::FT; - typedef typename Kernel::Direction_3 Direction_3; - typedef typename Kernel::Vector_3 Vector_3; - typedef typename Kernel::Direction_2 Direction_2; - typedef typename Kernel::Vector_2 Vector_2; + using Direction_3 = typename Kernel::Direction_3; + using Vector_3 = typename Kernel::Vector_3; + using Direction_2 = typename Kernel::Direction_2; + using Vector_2 = typename Kernel::Vector_2; /*! Obtain the intersection of the identification arc and the xy plane. * By default, it is the vector directed along the negative x axis * (x = -infinity). * \return the intersection of the identification arc and the xy plane. */ - inline static const Direction_2& identification_xy() - { + inline static const Direction_2& identification_xy() { static const Direction_2 d(atan_x, atan_y); return d; } @@ -101,8 +177,7 @@ protected: * (y = infinity). * \return the normal of the plane that contains the identification arc. */ - inline static const Direction_3& identification_normal() - { + inline static const Direction_3& identification_normal() { static const Direction_3 d(atan_y, -atan_x, 0); return d; } @@ -110,8 +185,7 @@ protected: /*! Obtain the 2D direction directed along the negative x axis * \return the direction directed at x = -infinity */ - inline static const Direction_2& neg_x_2() - { + inline static const Direction_2& neg_x_2() { CGAL_STATIC_THREAD_LOCAL_VARIABLE_2(Direction_2, d, -1, 0); return d; } @@ -119,8 +193,7 @@ protected: /*! Obtain the 2D direction directed along the negative y axis * \return the direction directed at y = -infinity */ - inline static const Direction_2& neg_y_2() - { + inline static const Direction_2& neg_y_2() { CGAL_STATIC_THREAD_LOCAL_VARIABLE_2(Direction_2, d, 0, -1); return d; } @@ -186,8 +259,7 @@ protected: * \param dir the direction. */ inline Oriented_side oriented_side(const Direction_3& normal, - const Direction_3 dir) const - { + const Direction_3 dir) const { FT dot = normal.vector() * dir.vector(); return CGAL::sign(dot); } @@ -197,9 +269,8 @@ protected: * \param d2 the second direction. * \return the relative orientation of d1 and d2. */ - inline Orientation orientation(const Direction_2& d1, const Direction_2& d2) - const - { + inline Orientation orientation(const Direction_2& d1, + const Direction_2& d2) const { const Kernel& kernel(*this); return kernel.orientation_2_object()(d1.vector(), d2.vector()); } @@ -209,8 +280,7 @@ protected: * \param d2 the second direction. */ inline Direction_3 construct_normal_3(const Direction_3& d1, - const Direction_3& d2) const - { + const Direction_3& d2) const { const Kernel& kernel(*this); Vector_3 v = kernel.construct_cross_product_vector_3_object()(d1.vector(), d2.vector()); @@ -224,8 +294,7 @@ protected: * \return true if dir is contained in plane; false otherwise. * \pre the plane contains the origin. */ - inline bool has_on(const Direction_3& normal, const Direction_3& dir) const - { + inline bool has_on(const Direction_3& normal, const Direction_3& dir) const { FT dot = normal.vector() * dir.vector(); return CGAL::sign(dot) == ZERO; } @@ -239,8 +308,7 @@ public: * LARGER - v(d1) > v(d2). */ inline Comparison_result compare_y(const Direction_3& d1, - const Direction_3& d2) const - { + const Direction_3& d2) const { Vector_3 v1 = d1.vector(); Vector_3 v2 = d2.vector(); @@ -274,8 +342,7 @@ public: * LARGER - u(d1) > u(d2). */ inline Comparison_result compare_x(const Direction_2& d1, - const Direction_2& d2) const - { + const Direction_2& d2) const { const Kernel& kernel = *this; if (kernel.equal_2_object()(d1, d2)) return EQUAL; const Direction_2& d = identification_xy(); @@ -293,8 +360,7 @@ public: * \pre d2 does not coincide with any pole. */ inline Comparison_result compare_x(const Direction_3& d1, - const Direction_3& d2) const - { + const Direction_3& d2) const { // Compare the projections onto the xy plane: Direction_2 d1_2 = project_xy(d1); Direction_2 d2_2 = project_xy(d2); @@ -313,8 +379,7 @@ public: * \pre d2 does not lie on the discontinuity arc. */ inline Comparison_result compare_xy(const Direction_3& d1, - const Direction_3& d2) const - { + const Direction_3& d2) const { Comparison_result res = compare_x(d1, d2); if (res == EQUAL) return compare_y(d1, d2); return res; @@ -327,9 +392,9 @@ public: * false otherwise. * \pre point does not coincide with one of the poles */ - bool is_in_x_range(const X_monotone_curve_2& xcv, const Point_2& point) const - { - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + bool is_in_x_range(const X_monotone_curve_2& xcv, + const Point_2& point) const { + using Traits = Arr_geodesic_arc_on_sphere_traits_2; CGAL_precondition(!point.is_min_boundary()); CGAL_precondition(!point.is_max_boundary()); @@ -358,8 +423,7 @@ public: */ void intersection_with_identification(const X_monotone_curve_2& xcv, Direction_3& dp, - std::true_type) const - { + std::true_type) const { const Direction_3& normal = xcv.normal(); dp = (CGAL::sign(normal.dz()) == POSITIVE) ? Direction_3(-(normal.dz()), 0, normal.dx()) : @@ -371,8 +435,7 @@ public: */ void intersection_with_identification(const X_monotone_curve_2& xcv, Direction_3& dp, - std::false_type) const - { + std::false_type) const { const Direction_3& normal = xcv.normal(); FT z((atan_x * normal.dx() + atan_y * normal.dy()) / -(normal.dz())); @@ -383,8 +446,7 @@ public: * \param[in] cv the curve */ bool overlap_with_identification(const X_monotone_curve_2& xcv, - std::true_type) const - { + std::true_type) const { const Direction_3& normal = xcv.normal(); return ((x_sign(normal) == ZERO) && (((y_sign(normal) == NEGATIVE) && !xcv.is_directed_right()) || @@ -395,8 +457,7 @@ public: * \param[in] cv the curve */ bool overlap_with_identification(const X_monotone_curve_2& xcv, - std::false_type) const - { + std::false_type) const { const Direction_3& normal = xcv.normal(); const Direction_3& iden_normal = identification_normal(); const Direction_2 iden_normal_xy = project_xy(iden_normal); @@ -417,9 +478,9 @@ public: /*! A functor that constructs a point on the sphere. */ class Construct_point_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -436,8 +497,7 @@ public: * \param[in] y the y coordinate * \param[in] z the z coordinate */ - Point_2 operator()(const FT& x, const FT& y, const FT& z) - { + Point_2 operator()(const FT& x, const FT& y, const FT& z) { Point_2 p; Direction_3& d(p); d = Direction_3(x, y, z); @@ -449,8 +509,7 @@ public: * direction. * \param other the other direction */ - Point_2 operator()(const Direction_3& other) - { + Point_2 operator()(const Direction_3& other) { Point_2 p; Direction_3& d(p); d = Direction_3(other); @@ -461,8 +520,7 @@ public: /*! Initialize a point on the sphere, * \param[in] p the point to initialize. */ - void init(Point_2& p, std::true_type) const - { + void init(Point_2& p, std::true_type) const { const Direction_3& dir = p; if (y_sign(dir) != ZERO) { p.set_location(Point_2::NO_BOUNDARY_LOC); @@ -480,8 +538,7 @@ public: /*! Initialize a point on the sphere, * \param[in] p the point to initialize. */ - void init(Point_2& p, std::false_type) const - { + void init(Point_2& p, std::false_type) const { const Direction_3& dir = p; if ((x_sign(dir) == ZERO) && (y_sign(dir) == ZERO)) { typename Point_2::Location_type location = (z_sign(dir) == NEGATIVE) ? @@ -508,9 +565,9 @@ public: /*! A functor that constructs an x-monotone geodesic arc on the sphere. */ class Construct_x_monotone_curve_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -536,9 +593,8 @@ public: * \pre the source and target must not coincide. * \pre the source and target cannot be antipodal. */ - X_monotone_curve_2 operator()(const Point_2& source, const Point_2& target) - const - { + X_monotone_curve_2 operator()(const Point_2& source, + const Point_2& target) const { X_monotone_curve_2 xcv; xcv.set_source(source); @@ -561,8 +617,7 @@ public: * \param plane the containing plane. * \pre the plane is not vertical */ - X_monotone_curve_2 operator()(const Direction_3& normal) const - { + X_monotone_curve_2 operator()(const Direction_3& normal) const { X_monotone_curve_2 xcv; xcv.set_normal(normal); @@ -608,12 +663,11 @@ public: * \param target the target point. * \pre the source and target cannot be equal. */ - void init(X_monotone_curve_2& xcv) const - { + void init(X_monotone_curve_2& xcv) const { const Point_2& source = xcv.source(); const Point_2& target = xcv.target(); - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; const Kernel& kernel(m_traits); CGAL_precondition(!kernel.equal_3_object()(Direction_3(source), @@ -701,9 +755,9 @@ public: /*! A functor that constructs a geodesic arc on the sphere. */ class Construct_curve_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -728,8 +782,7 @@ public: * \pre the source and target cannot be equal. * \pre the source and target cannot be the opoosite of each other. */ - Curve_2 operator()(const Point_2& source, const Point_2& target) - { + Curve_2 operator()(const Point_2& source, const Point_2& target) { Curve_2 cv; cv.set_source(source); cv.set_target(target); @@ -794,8 +847,7 @@ public: Orientation orient = m_traits.orientation(s, t); const Kernel& kernel = m_traits; - typename Kernel::Counterclockwise_in_between_2 cc_in_between = - kernel.counterclockwise_in_between_2_object(); + auto cc_in_between = kernel.counterclockwise_in_between_2_object(); const Direction_2& d = Traits::identification_xy(); if (orient == LEFT_TURN) { @@ -819,8 +871,7 @@ public: * \pre Both endpoints lie on the given plane. */ Curve_2 operator()(const Point_2& source, const Point_2& target, - const Direction_3& normal) - { + const Direction_3& normal) { Curve_2 cv; cv.set_source(source); @@ -829,7 +880,7 @@ public: cv.set_is_degenerate(false); cv.set_is_empty(false); - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; CGAL_precondition(m_traits.has_on(normal, source)); CGAL_precondition(m_traits.has_on(normal, target)); @@ -912,8 +963,7 @@ public: Direction_2 s = project(source); Direction_2 t = project(target); const Direction_2& ny = Traits::neg_y_2(); - typename Kernel::Counterclockwise_in_between_2 ccib = - kernel.counterclockwise_in_between_2_object(); + auto ccib = kernel.counterclockwise_in_between_2_object(); cv.set_is_x_monotone((plane_is_positive && !ccib(ny, s, t)) || (!plane_is_positive && !ccib(ny, t, s))); @@ -929,8 +979,7 @@ public: const Direction_2& d = Traits::identification_xy(); Direction_2 s = Traits::project_xy(source); Direction_2 t = Traits::project_xy(target); - typename Kernel::Counterclockwise_in_between_2 ccib = - kernel.counterclockwise_in_between_2_object(); + auto ccib = kernel.counterclockwise_in_between_2_object(); bool plane_is_positive = (z_sign(normal) == POSITIVE); cv.set_is_x_monotone((plane_is_positive && !ccib(d, s, t)) || (!plane_is_positive && !ccib(d, t, s))); @@ -961,9 +1010,9 @@ public: /*! A functor that compares the x-coordinates of two directional points */ class Compare_x_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -983,8 +1032,7 @@ public: * \pre p1 does not lie on the boundary. * \pre p2 does not lie on the boundary. */ - Comparison_result operator()(const Point_2& p1, const Point_2& p2) const - { + Comparison_result operator()(const Point_2& p1, const Point_2& p2) const { CGAL_precondition(p1.is_no_boundary()); CGAL_precondition(p2.is_no_boundary()); @@ -996,8 +1044,7 @@ protected: /*! Obtain the positive (north) pole * \return the positive (north) pole */ - inline static const Point_2& pos_pole() - { + inline static const Point_2& pos_pole() { static const Point_2 p(Direction_3(0, 0, 1), Point_2::MAX_BOUNDARY_LOC); return p; } @@ -1005,8 +1052,7 @@ protected: /*! Obtain the negative (south) pole * \return the negative (south) pole */ - inline static const Point_2& neg_pole() - { + inline static const Point_2& neg_pole() { static const Point_2 p(Direction_3(0, 0, -1), Point_2::MIN_BOUNDARY_LOC); return p; } @@ -1020,9 +1066,9 @@ public: */ class Compare_xy_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1044,8 +1090,7 @@ public: * \pre p1 does not lie on the boundary. * \pre p2 does not lie on the boundary. */ - Comparison_result operator()(const Point_2& p1, const Point_2& p2) const - { + Comparison_result operator()(const Point_2& p1, const Point_2& p2) const { CGAL_precondition(p1.is_no_boundary()); CGAL_precondition(p2.is_no_boundary()); @@ -1094,8 +1139,7 @@ public: * \return true if the curve is a vertical spherical_arc; false otherwise. * \pre the arc is not degenerate (consists of a single point) */ - bool operator()(const X_monotone_curve_2& xc) const - { + bool operator()(const X_monotone_curve_2& xc) const { CGAL_precondition(!xc.is_degenerate()); return xc.is_vertical(); } @@ -1109,9 +1153,9 @@ public: */ class Compare_y_at_x_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1132,8 +1176,7 @@ public: * \pre p is in the x-range of xc. */ Comparison_result operator()(const Point_2& p, - const X_monotone_curve_2& xc) const - { + const X_monotone_curve_2& xc) const { CGAL_precondition(!p.is_min_boundary() && !p.is_max_boundary()); CGAL_precondition(m_traits.is_in_x_range(xc, p)); @@ -1169,9 +1212,9 @@ public: */ class Compare_y_at_x_left_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1195,8 +1238,7 @@ public: */ Comparison_result operator()(const X_monotone_curve_2& xc1, const X_monotone_curve_2& xc2, - const Point_2& p) const - { + const Point_2& p) const { CGAL_precondition(! xc1.is_degenerate()); CGAL_precondition(! xc2.is_degenerate()); CGAL_precondition(p == xc1.right()); @@ -1227,8 +1269,7 @@ public: auto opposite_3 = kernel.construct_opposite_direction_3_object(); Direction_3 opposite_p = opposite_3(p); if (kernel.equal_3_object()(opposite_p, Direction_3(l1)) || - kernel.equal_3_object()(opposite_p, Direction_3(l2))) - { + kernel.equal_3_object()(opposite_p, Direction_3(l2))) { Sign xsign = Traits::x_sign(p); Sign ysign = Traits::y_sign(p); Project project = (xsign == ZERO) ? @@ -1286,9 +1327,9 @@ public: */ class Compare_y_at_x_right_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1312,8 +1353,7 @@ public: */ Comparison_result operator()(const X_monotone_curve_2& xc1, const X_monotone_curve_2& xc2, - const Point_2& p) const - { + const Point_2& p) const { CGAL_precondition(! xc1.is_degenerate()); CGAL_precondition(! xc2.is_degenerate()); @@ -1335,8 +1375,7 @@ public: auto opposite_3 = kernel.construct_opposite_direction_3_object(); Direction_3 opposite_p = opposite_3(p); if (kernel.equal_3_object()(opposite_p, Direction_3(r1)) || - kernel.equal_3_object()(opposite_p, Direction_3(r2))) - { + kernel.equal_3_object()(opposite_p, Direction_3(r2))) { Sign xsign = Traits::x_sign(p); Sign ysign = Traits::y_sign(p); Project project = (xsign == ZERO) ? @@ -1402,9 +1441,9 @@ public: */ class Equal_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1422,8 +1461,7 @@ public: * \return true if the two curves are the same; false otherwise. */ bool operator()(const X_monotone_curve_2& xc1, - const X_monotone_curve_2& xc2) const - { + const X_monotone_curve_2& xc2) const { const Kernel& kernel = m_traits; typename Kernel::Equal_3 equal_3 = kernel.equal_3_object(); if (xc1.is_full() || xc2.is_full()) { @@ -1447,8 +1485,7 @@ public: * \param p2 the second point. * \return true if the two point are the same; false otherwise. */ - bool operator()(const Point_2& p1, const Point_2& p2) const - { + bool operator()(const Point_2& p1, const Point_2& p2) const { const Kernel& kernel = m_traits; return kernel.equal_3_object()(Direction_3(p1), Direction_3(p2)); } @@ -1466,9 +1503,9 @@ public: */ class Parameter_space_in_x_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1498,8 +1535,7 @@ public: * \pre xcv does not coincide with the identification */ Arr_parameter_space operator()(const X_monotone_curve_2& xcv, - Arr_curve_end ce) const - { + Arr_curve_end ce) const { CGAL_precondition(!m_traits.is_on_y_identification_2_object()(xcv)); // vertical, but not on identification! if (xcv.is_vertical()) return ARR_INTERIOR; @@ -1516,8 +1552,7 @@ public: * \param p the point. * \return the parameter space at p. */ - Arr_parameter_space operator()(const Point_2& p) const - { + Arr_parameter_space operator()(const Point_2& p) const { CGAL_precondition(p.is_no_boundary()); CGAL_USE(p); return ARR_INTERIOR; @@ -1551,8 +1586,7 @@ public: * maximal end. */ Arr_parameter_space operator()(const X_monotone_curve_2& xcv, - Arr_curve_end ce) const - { + Arr_curve_end ce) const { return (ce == ARR_MIN_END) ? ((xcv.left().is_min_boundary()) ? ARR_BOTTOM_BOUNDARY: ARR_INTERIOR) : ((xcv.right().is_max_boundary()) ? ARR_TOP_BOUNDARY : ARR_INTERIOR); @@ -1565,8 +1599,7 @@ public: * \param p the point. * \return the parameter space at p. */ - Arr_parameter_space operator()(const Point_2& p) const - { + Arr_parameter_space operator()(const Point_2& p) const { return (p.is_min_boundary()) ? ARR_BOTTOM_BOUNDARY : (p.is_max_boundary()) ? ARR_TOP_BOUNDARY : ARR_INTERIOR; @@ -1583,9 +1616,9 @@ public: */ class Compare_x_on_boundary_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1613,8 +1646,8 @@ public: */ Comparison_result operator()(const Point_2& point, const X_monotone_curve_2& xcv, - Arr_curve_end CGAL_precondition_code(ce)) const - { + Arr_curve_end CGAL_precondition_code(ce)) + const { CGAL_precondition(point.is_no_boundary()); CGAL_precondition_code (const Point_2& p2 = (ce == ARR_MIN_END) ? xcv.left() : xcv.right();); @@ -1659,8 +1692,8 @@ public: Comparison_result operator()(const X_monotone_curve_2& xcv1, Arr_curve_end CGAL_precondition_code(ce1), const X_monotone_curve_2& xcv2, - Arr_curve_end CGAL_precondition_code(ce2)) const - { + Arr_curve_end CGAL_precondition_code(ce2)) + const { CGAL_precondition_code (const Point_2& p1 = (ce1 == ARR_MIN_END) ? xcv1.left() : xcv1.right();); CGAL_precondition(!p1.is_no_boundary()); @@ -1695,9 +1728,7 @@ public: */ Comparison_result operator()(const Point_2& /* p1 */, const Point_2& /* p2 */) const - { - CGAL_error(); return EQUAL; - } + { CGAL_error(); return EQUAL; } }; /*! Obtain a Compare_x_on_boundary_2 function object. @@ -1710,9 +1741,9 @@ public: */ class Compare_x_near_boundary_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1746,8 +1777,8 @@ public: CGAL_precondition_code(xcv1), const X_monotone_curve_2& CGAL_precondition_code(xcv2), - Arr_curve_end CGAL_precondition_code(ce)) const - { + Arr_curve_end CGAL_precondition_code(ce)) + const { CGAL_precondition_code (const Point_2& p1 = (ce == ARR_MIN_END) ? xcv1.left() : xcv1.right();); CGAL_precondition(!p1.is_no_boundary()); @@ -1774,9 +1805,9 @@ public: */ class Compare_y_near_boundary_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1800,8 +1831,7 @@ public: */ Comparison_result operator()(const X_monotone_curve_2& xcv1, const X_monotone_curve_2& xcv2, - Arr_curve_end ce) const - { + Arr_curve_end ce) const { CGAL_precondition(! xcv1.is_degenerate()); CGAL_precondition(! xcv2.is_degenerate()); @@ -1918,9 +1948,9 @@ public: */ class Is_on_y_identification_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1944,8 +1974,7 @@ public: * \return a Boolean indicating whether xcv coincides with the vertical * identification arc. */ - bool operator()(const X_monotone_curve_2& xcv) const - { + bool operator()(const X_monotone_curve_2& xcv) const { /* If the curve is not vertical and non of its endpoints lie on the * boundary, the arc itself cannot lie on the identification arc. */ @@ -1977,9 +2006,9 @@ public: */ class Compare_y_on_boundary_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2000,8 +2029,7 @@ public: * \pre p1 lies on the vertical identification arc including the poles! * \pre p2 lies on the vertical identification arc including the poles! */ - Comparison_result operator()(const Point_2& p1, const Point_2& p2) const - { + Comparison_result operator()(const Point_2& p1, const Point_2& p2) const { // first deal with the 'degenerate' case of poles! if (p1.is_min_boundary()) { if (p2.is_min_boundary()) return EQUAL; @@ -2039,9 +2067,9 @@ public: */ class Make_x_monotone_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2063,8 +2091,8 @@ public: */ template OutputIterator operator()(const Curve_2& c, OutputIterator oi) const { - typedef boost::variant - Make_x_monotone_result; + using Make_x_monotone_result = + boost::variant; // std::cout << "full: " << c.is_full() << std::endl; // std::cout << "vert: " << c.is_vertical() << std::endl; // std::cout << "xmon: " << c.is_x_monotone() << std::endl; @@ -2199,9 +2227,9 @@ public: /*! A functor that splits an x-monotone arc at a directional point. */ class Split_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2223,8 +2251,7 @@ public: * \pre xc is not degenerate */ void operator()(const X_monotone_curve_2& xc, const Point_2& p, - X_monotone_curve_2& xc1, X_monotone_curve_2& xc2) const - { + X_monotone_curve_2& xc1, X_monotone_curve_2& xc2) const { CGAL_precondition(!xc.is_degenerate()); const Point_2& source = xc.source(); const Point_2& target = xc.target(); @@ -2268,9 +2295,9 @@ public: /*! The clockwise-in-between function object */ class Clockwise_in_between_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2282,8 +2309,7 @@ public: public: bool operator()(const Direction_2& d, - const Direction_2& d1, const Direction_2& d2) const - { + const Direction_2& d1, const Direction_2& d2) const { const Kernel& kernel = m_traits; return kernel.counterclockwise_in_between_2_object()(d, d2, d1); } @@ -2318,11 +2344,10 @@ public: bool vertical, const In_between& in_between, Project project, - OutputIterator oi) const - { - typedef std::pair Intersection_point; - typedef boost::variant - Intersection_result; + OutputIterator oi) const { + using Intersection_point = std::pair; + using Intersection_result = + boost::variant; const Kernel& kernel = m_traits; typename Kernel::Equal_2 equal = kernel.equal_2_object(); @@ -2473,8 +2498,7 @@ public: * \pre point lies in the underlying plane of xc. */ bool is_in_between(const Point_2& point, - const X_monotone_curve_2& xc) const - { + const X_monotone_curve_2& xc) const { const Kernel& kernel = m_traits; CGAL_precondition(m_traits.has_on(xc.normal(), point)); @@ -2523,9 +2547,9 @@ public: } protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2548,20 +2572,16 @@ public: template OutputIterator operator()(const X_monotone_curve_2& xc1, const X_monotone_curve_2& xc2, - OutputIterator oi) const - { + OutputIterator oi) const { // std::cout << "xc1: " << xc1 << std::endl // << "xc2: " << xc2 << std::endl; CGAL_precondition(!xc1.is_degenerate()); CGAL_precondition(!xc2.is_degenerate()); - typedef typename Kernel::Counterclockwise_in_between_2 - Counterclockwise_in_between_2; - typedef typename Kernel::Equal_3 Equal_3; - - typedef std::pair Intersection_point; - typedef boost::variant - Intersection_result; + using Equal_3 = typename Kernel::Equal_3; + using Intersection_point = std::pair; + using Intersection_result = + boost::variant; const Kernel& kernel = m_traits; @@ -2574,7 +2594,7 @@ public: if (equal_3(normal1, normal2) || equal_3(opposite_normal1, normal2)) { // The underlying planes are the same - Counterclockwise_in_between_2 ccib = kernel.counterclockwise_in_between_2_object(); + auto ccib = kernel.counterclockwise_in_between_2_object(); auto cib = m_traits.clockwise_in_between_2_object(); if (xc1.is_vertical()) { @@ -2662,9 +2682,9 @@ public: /*! A functor that tests whether two x-monotone arcs can be merged. */ class Are_mergeable_2 { - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2684,8 +2704,7 @@ public: * 2. share a common endpoint that is not on the identification arc */ bool operator()(const X_monotone_curve_2& xc1, - const X_monotone_curve_2& xc2) const - { + const X_monotone_curve_2& xc2) const { if (xc1.is_empty() || xc2.is_empty()) return true; if ((xc1.is_full() || xc1.is_meridian()) && (xc2.is_full() || xc2.is_meridian())) return false; @@ -2734,9 +2753,9 @@ public: /*! A functor that merges two x-monotone arcs into one */ class Merge_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2755,8 +2774,7 @@ public: */ void operator()(const X_monotone_curve_2& xc1, const X_monotone_curve_2& xc2, - X_monotone_curve_2& xc) const - { + X_monotone_curve_2& xc) const { CGAL_precondition (m_traits.are_mergeable_2_object()(xc1, xc2) == true); if (xc1.is_degenerate() || xc1.is_empty()) { @@ -2835,9 +2853,11 @@ public: /// \name Functor definitions for the landmarks point-location strategy. //@{ - typedef double Approximate_number_type; - typedef CGAL::Cartesian Approximate_kernel; - typedef Approximate_kernel::Point_2 Approximate_point_2; + using Approximate_number_type = double; + using Approximate_kernel = CGAL::Cartesian; + using Approximate_point_2 = Arr_extended_direction_3; + using Approximate_kernel_vector_3 = Approximate_kernel::Vector_3; + using Approximate_kernel_direction_3 = Approximate_kernel::Direction_3; class Approximate_2 { public: @@ -2849,21 +2869,103 @@ public: * approximation of p's y-coordinate (if i == 1). */ Approximate_number_type operator()(const Point_2& p, int i) const { - CGAL_precondition((i == 0) || (i == 1)); - return (i == 0) ? CGAL::to_double(p.x()) : CGAL::to_double(p.y()); + CGAL_precondition((i == 0) || (i == 1) || (i == 2)); + return (i == 0) ? CGAL::to_double(p.dx()) : + ((i == 1) ? CGAL::to_double(p.dy()) : CGAL::to_double(p.dz())); } /*! Obtain an approximation of a point. */ - Approximate_point_2 operator()(const Point_2& p) const - { return Approximate_point_2(operator()(p, 0), operator()(p, 1)); } + Approximate_point_2 operator()(const Point_2& p) const { + Approximate_kernel::Direction_3 dir(operator()(p, 0), operator()(p, 1), + operator()(p, 2)); + auto loc = static_cast(p.location()); + return Approximate_point_2(dir, loc); + } /*! Obtain 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 { - CGAL_error_msg("Not implemented yet!"); + OutputIterator operator()(const X_monotone_curve_2& xcv, + Approximate_number_type error, + OutputIterator oi, bool l2r = true) const { + auto s = xcv.source(); + auto t = xcv.target(); + auto n = xcv.normal(); + + // get the approximate points; + auto as = (*this)(s); + auto at = (*this)(t); + + // convert the approximate points to vectors with approximate-kernel + auto vs = approximate_vector_3(as); + auto vt = approximate_vector_3(at); + auto vn = approximate_vector_3(n); + + // normalize the vectors + auto normalize = [](auto& x) { x /= std::sqrt(x.squared_length()); }; + normalize(vs); + normalize(vt); + normalize(vn); + + // Define the spanning vectors of the coordinate system where we are + // going to make the approximation: + auto axis_x = vs; // x-axis will coincide with the vector from the + // origin to the normalized SOURCE-vector + auto axis_z = vn; // this will make sure that the orientation of the + // approximated curve is consistent with the curve + auto axis_y = CGAL::cross_product(axis_z, axis_x); + normalize(axis_y); + + // In this coordinate system the source has local coords (0,0), hence its + // initial angle with the X-axis is 0 degrees (radians) + // Compute the local coordinates and the angle it makes with the X-axis + Approximate_number_type theta; + if (xcv.is_full()) theta = 2.0 * CGAL_PI; + else { + auto ltx = CGAL::scalar_product(axis_x, vt); + auto lty = CGAL::scalar_product(axis_y, vt); + theta = std::atan2(lty, ltx); + if (theta < 0) + theta += 2.0 * CGAL_PI; + } + + // compute the number of divisions given the requested error + const Approximate_number_type R = 1.0; // radius is always 1 + Approximate_number_type dtheta = 2.0 * std::acos(1 - error / R); + int num_segs = std::ceil(theta / dtheta); + dtheta = theta / num_segs; + + // generate the points approximating the curve + const auto loc = Approximate_point_2::NO_BOUNDARY_LOC; + *oi++ = approximate_point_2(vs, loc); // source vector + for (int i = 1; i < num_segs; ++i) { + const Approximate_number_type angle = i * dtheta; + auto p = std::cos(angle) * axis_x + std::sin(angle) * axis_y; + *oi++ = approximate_point_2(p, loc); + } + *oi++ = approximate_point_2(vt, loc); // target vector + + return oi; + } + + private: + Approximate_kernel_vector_3 + approximate_vector_3(const Approximate_point_2& p) const + { return Approximate_kernel_vector_3(p.dx(), p.dy(), p.dz()); }; + + Approximate_kernel_vector_3 + approximate_vector_3(const Direction_3& d) const { + return Approximate_kernel_vector_3(CGAL::to_double(d.dx()), + CGAL::to_double(d.dy()), + CGAL::to_double(d.dz())); + }; + + Approximate_point_2 + approximate_point_2(const Approximate_kernel_vector_3& v, + const Approximate_point_2::Location_type loc) const { + Approximate_kernel_direction_3 d(v.x(), v.y(), v.z()); + return Approximate_point_2(d, loc); } }; @@ -2877,9 +2979,7 @@ public: class Compare_endpoints_xy_2 { public: - - /*! - * Compare the endpoints of an $x$-monotone curve lexicographically. + /*! Compare the endpoints of an $x$-monotone curve lexicographically. * (assuming the curve has a designated source and target points). * \param xc the curve. * \return SMALLER if the curve is directed right; @@ -2911,8 +3011,7 @@ public: #if 0 /*! Inserter for the spherical_arc class used by the traits-class */ template - friend OutputStream& operator<<(OutputStream& os, const Point_2& p) - { + friend OutputStream& operator<<(OutputStream& os, const Point_2& p) { CGAL::To_double todouble; os << static_cast(todouble(p.dx())) << ", " << static_cast(todouble(p.dy())) << ", " @@ -2923,101 +3022,20 @@ public: /*! Inserter for the spherical_arc class used by the traits-class */ template friend OutputStream& operator<<(OutputStream& os, - const X_monotone_curve_2& xc) - { + const X_monotone_curve_2& xc) { os << "(" << xc.left() << "), (" << xc.right() << ")"; return os; } /*! Extractor for the spherical_arc class used by the traits-class */ template - friend InputStream& operator>>(InputStream& is, X_monotone_curve_2& arc) - { + friend InputStream& operator>>(InputStream& is, X_monotone_curve_2& arc) { CGAL_error_msg("Not implemented yet!"); return is; } #endif }; -/*! Represent an extended 3D direction that is used in turn to represent a - * spherical-arc endpoint. The extended data consists of two flags that - * indicate whether the point is on the x and on a y boundaries, - * respectively. - */ -template -class Arr_extended_direction_3 : public Kernel::Direction_3 { -public: - typedef typename Kernel::FT FT; - typedef typename Kernel::Direction_3 Direction_3; - - /*! Enumeration of discontinuity type */ - enum Location_type { - NO_BOUNDARY_LOC = 0, - MIN_BOUNDARY_LOC, - MID_BOUNDARY_LOC, - MAX_BOUNDARY_LOC - }; - -private: - typedef typename Kernel::Direction_2 Direction_2; - - /*! The point discontinuity type */ - Location_type m_location; - - inline Sign x_sign(Direction_3 d) const { return CGAL::sign(d.dx()); } - - inline Sign y_sign(Direction_3 d) const { return CGAL::sign(d.dy()); } - - inline Sign z_sign(Direction_3 d) const { return CGAL::sign(d.dz()); } - -public: - /*! Default constructor */ - Arr_extended_direction_3() : - Direction_3(0, 0, 1), - m_location(MAX_BOUNDARY_LOC) - {} - - /*! Constructor */ - Arr_extended_direction_3(const Direction_3& dir, Location_type location) : - Direction_3(dir), - m_location(location) - {} - - /*! Copy constructor */ - Arr_extended_direction_3(const Arr_extended_direction_3& other) : - Direction_3(static_cast(other)) - { m_location = other.discontinuity_type(); } - - /*! Assignment operator */ - Arr_extended_direction_3& operator=(const Arr_extended_direction_3& other) - { - *(static_cast(this)) = static_cast(other); - m_location = other.discontinuity_type(); - return (*this); - } - - /*! Set the location of the point. - */ - void set_location(Location_type location) { m_location = location; } - - /*! Obtain the location of the point. - */ - Location_type location() const { return m_location; } - - /*! Obtain the discontinuity type of the point. - * \todo deprecate this one; use the above instead. - */ - Location_type discontinuity_type() const { return m_location; } - - bool is_no_boundary() const { return (m_location == NO_BOUNDARY_LOC); } - - bool is_min_boundary() const { return (m_location == MIN_BOUNDARY_LOC); } - - bool is_mid_boundary() const { return (m_location == MID_BOUNDARY_LOC); } - - bool is_max_boundary() const { return (m_location == MAX_BOUNDARY_LOC); } -}; - /*! A Representation of an x-monotone great circular arc embedded on a sphere, * as used by the Arr_geodesic_arc_on_sphere_traits_2 traits-class * An x-monotone great circular arc cannot cross the closed hemi-circle arc of @@ -3029,38 +3047,38 @@ public: template class Arr_x_monotone_geodesic_arc_on_sphere_3 { public: - typedef Kernel_ Kernel; - typedef typename Kernel::Direction_3 Direction_3; - typedef typename Kernel::Plane_3 Plane_3; - typedef typename Kernel::Vector_3 Vector_3; - typedef typename Kernel::Direction_2 Direction_2; + using Kernel = Kernel_; + using Direction_3 = typename Kernel::Direction_3; + using Plane_3 = typename Kernel::Plane_3; + using Vector_3 = typename Kernel::Vector_3; + using Direction_2 = typename Kernel::Direction_2; protected: // For some reason compilation under Windows fails without the qualifier - typedef CGAL::Arr_extended_direction_3 Arr_extended_direction_3; + using Arr_extended_direction_3 = CGAL::Arr_extended_direction_3; - /*! The source point of the arc. */ + //! The source point of the arc. Arr_extended_direction_3 m_source; - /*! The target point of the arc. */ + //! The target point of the arc. Arr_extended_direction_3 m_target; - /*! The direction of the plane that contains the arc. */ + //! The direction of the plane that contains the arc. Direction_3 m_normal; - /*! The arc is vertical. */ + //! The arc is vertical. bool m_is_vertical; - /*! Target (lexicographically) larger than source. */ + //! Target (lexicographically) larger than source. bool m_is_directed_right; - /*! The arc is a full circle. */ + //! The arc is a full circle. bool m_is_full; - /* The arc is degenerate - it consists of a single point. */ + //! The arc is degenerate - it consists of a single point. bool m_is_degenerate; - /*! The arc is empty. */ + //! The arc is empty. bool m_is_empty; inline Sign x_sign(Direction_3 d) const { return CGAL::sign(d.dx()); } @@ -3109,8 +3127,7 @@ public: * \param other the other arc */ Arr_x_monotone_geodesic_arc_on_sphere_3 - (const Arr_x_monotone_geodesic_arc_on_sphere_3& other) - { + (const Arr_x_monotone_geodesic_arc_on_sphere_3& other) { m_source = other.m_source; m_target = other.m_target; m_normal = other.m_normal; @@ -3123,8 +3140,7 @@ public: /*! Assignment operator */ Arr_x_monotone_geodesic_arc_on_sphere_3& operator= - (const Arr_x_monotone_geodesic_arc_on_sphere_3& other) - { + (const Arr_x_monotone_geodesic_arc_on_sphere_3& other) { m_source = other.m_source; m_target = other.m_target; m_normal = other.m_normal; @@ -3150,9 +3166,8 @@ public: * \param target the target point. * \pre the source and target cannot be equal. */ - void init() - { - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + void init() { + using Traits = Arr_geodesic_arc_on_sphere_traits_2; Kernel kernel; CGAL_precondition(!kernel.equal_3_object()(Direction_3(m_source), @@ -3241,8 +3256,7 @@ public: m_is_directed_right(z_sign(normal) == POSITIVE), m_is_full(true), m_is_degenerate(false), - m_is_empty(false) - { + m_is_empty(false) { CGAL_precondition(z_sign(normal) != ZERO); #if (CGAL_IDENTIFICATION_XY == CGAL_X_MINUS_1_Y_0) @@ -3250,8 +3264,8 @@ public: Direction_3(-(normal.dz()), 0, normal.dx()) : Direction_3(normal.dz(), 0, -(normal.dx())); #else - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; - typedef typename Kernel::FT FT; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; + using FT = typename Kernel::FT; const Direction_2& xy = Traits::identification_xy(); FT x = xy.dx(); @@ -3277,8 +3291,7 @@ public: m_is_directed_right(z_sign(normal) == POSITIVE), m_is_full(true), m_is_degenerate(false), - m_is_empty(false) - { + m_is_empty(false) { CGAL_precondition(has_on(point)); CGAL_precondition(z_sign(normal) != ZERO); #if !defined(CGAL_FULL_X_MONOTONE_GEODESIC_ARC_ON_SPHERE_IS_SUPPORTED) @@ -3303,8 +3316,7 @@ public: m_normal(normal), m_is_full(false), m_is_degenerate(false), - m_is_empty(false) - { + m_is_empty(false) { CGAL_precondition(has_on(source)); CGAL_precondition(has_on(target)); @@ -3414,8 +3426,7 @@ public: #if 0 /*! Create a bounding box for the spherical_arc */ - Bbox_2 bbox() const - { + Bbox_2 bbox() const { Kernel kernel; Segment_2 seg = kernel.construct_spherical_arc_2_object()(this->m_source, this->m_target); @@ -3424,8 +3435,7 @@ public: #endif /*! Flip the spherical_arc (swap it source and target) */ - Arr_x_monotone_geodesic_arc_on_sphere_3 opposite() const - { + Arr_x_monotone_geodesic_arc_on_sphere_3 opposite() const { Arr_x_monotone_geodesic_arc_on_sphere_3 opp; opp.m_source = this->m_target; opp.m_target = this->m_source; @@ -3444,8 +3454,7 @@ public: * \return true if dir is contained in plane; false otherwise. * \pre the plane contains the origin. */ - inline bool has_on(const Direction_3& dir) const - { + inline bool has_on(const Direction_3& dir) const { typename Kernel::FT dot = normal().vector() * dir.vector(); return CGAL::sign(dot) == ZERO; } @@ -3463,25 +3472,25 @@ template class Arr_geodesic_arc_on_sphere_3 : public Arr_x_monotone_geodesic_arc_on_sphere_3 { public: - typedef Kernel_ Kernel; + using Kernel = Kernel_; protected: - typedef Arr_x_monotone_geodesic_arc_on_sphere_3 Base; + using Base = Arr_x_monotone_geodesic_arc_on_sphere_3; public: - typedef typename Base::Plane_3 Plane_3; - typedef typename Base::Direction_3 Direction_3; - typedef typename Base::Direction_2 Direction_2; + using Plane_3 = typename Base::Plane_3; + using Direction_3 = typename Base::Direction_3; + using Direction_2 = typename Base::Direction_2; protected: // For some reason compilation under Windows fails without the qualifier - typedef CGAL::Arr_extended_direction_3 Arr_extended_direction_3; + using Arr_extended_direction_3 = CGAL::Arr_extended_direction_3; using Base::x_sign; using Base::y_sign; using Base::z_sign; - /*! Indicates whether the arc is x-monotone */ + //! Indicates whether the arc is x-monotone bool m_is_x_monotone; public: @@ -3537,8 +3546,7 @@ public: */ Arr_geodesic_arc_on_sphere_3(const Arr_extended_direction_3& source, const Arr_extended_direction_3& target, - const Direction_3& normal) - { + const Direction_3& normal) { Kernel kernel; this->set_source(source); @@ -3547,7 +3555,7 @@ public: this->set_is_degenerate(false); this->set_is_empty(false); - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; CGAL_precondition(this->has_on(source)); CGAL_precondition(this->has_on(target)); @@ -3627,8 +3635,7 @@ public: Direction_2 s = project(source); Direction_2 t = project(target); const Direction_2& ny = Traits::neg_y_2(); - typename Kernel::Counterclockwise_in_between_2 ccib = - kernel.counterclockwise_in_between_2_object(); + auto ccib = kernel.counterclockwise_in_between_2_object(); set_is_x_monotone((plane_is_positive && !ccib(ny, s, t)) || (!plane_is_positive && !ccib(ny, t, s))); @@ -3644,8 +3651,7 @@ public: const Direction_2& d = Traits::identification_xy(); Direction_2 s = Traits::project_xy(source); Direction_2 t = Traits::project_xy(target); - typename Kernel::Counterclockwise_in_between_2 ccib = - kernel.counterclockwise_in_between_2_object(); + auto ccib = kernel.counterclockwise_in_between_2_object(); bool plane_is_positive = (z_sign(normal) == POSITIVE); set_is_x_monotone((plane_is_positive && !ccib(d, s, t)) || (!plane_is_positive && !ccib(d, t, s))); @@ -3654,8 +3660,7 @@ public: /*! Construct a full spherical_arc from a normal to a plane. * \param normal the normal to the plane containing the arc. */ - Arr_geodesic_arc_on_sphere_3(const Direction_3& normal) - { + Arr_geodesic_arc_on_sphere_3(const Direction_3& normal) { this->normal(normal); this->set_is_vertical(CGAL::sign(normal.dz()) == ZERO); this->set_is_directed_right(true); @@ -3679,8 +3684,7 @@ public: /*! Inserter for the spherical_arc class used by the traits-class */ template OutputStream& operator<<(OutputStream& os, - const Arr_extended_direction_3& ed) -{ + const Arr_extended_direction_3& ed) { #if defined(CGAL_ARR_GEODESIC_ARC_ON_SPHERE_DETAILS) os << "(" << ed.dx() << ", " << ed.dy() << ", " << ed.dz(); @@ -3703,8 +3707,7 @@ OutputStream& operator<<(OutputStream& os, template OutputStream& operator<<(OutputStream& os, - const Arr_x_monotone_geodesic_arc_on_sphere_3& arc) -{ + const Arr_x_monotone_geodesic_arc_on_sphere_3& arc) { #if defined(CGAL_ARR_GEODESIC_ARC_ON_SPHERE_DETAILS) os << "(" << "(" << arc.source() << "), (" << arc.target() << ")" @@ -3724,10 +3727,9 @@ operator<<(OutputStream& os, /*! Extractor for the spherical-arc point class used by the traits-class */ template InputStream& -operator>>(InputStream& is, Arr_extended_direction_3& point) -{ - typedef Kernel_ Kernel; - typedef Arr_extended_direction_3 Point; +operator>>(InputStream& is, Arr_extended_direction_3& point) { + using Kernel = Kernel_; + using Point = Arr_extended_direction_3; // CGAL_error_msg("Importing a geodesic point is not supported!"); typename Kernel::Direction_3 d; is >> d; @@ -3741,10 +3743,9 @@ operator>>(InputStream& is, Arr_extended_direction_3& point) template InputStream& operator>>(InputStream& is, - Arr_x_monotone_geodesic_arc_on_sphere_3& arc) -{ - typedef Kernel_ Kernel; - typedef Arr_extended_direction_3 Point; + Arr_x_monotone_geodesic_arc_on_sphere_3& arc) { + using Kernel = Kernel_; + using Point = Arr_extended_direction_3; // CGAL_error_msg("Importing a geodesic arc is not supported!\n"); From afa58a942661b42e7c2c432b286dbccb589ca33a Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 9 Aug 2023 17:46:35 +0300 Subject: [PATCH 12/35] Cleaned up --- .../Arrangement_2/Arrangement_zone_2_impl.h | 64 +++++++------------ 1 file changed, 24 insertions(+), 40 deletions(-) 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 dfb8851479f..054724aa6e4 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 @@ -28,8 +28,7 @@ namespace CGAL { // template void Arrangement_zone_2:: -init_with_hint(const X_monotone_curve_2& cv, Pl_result_type obj) -{ +init_with_hint(const X_monotone_curve_2& cv, Pl_result_type obj) { #if defined(ARR_ZONE_VERBOSE) std::cout << "init_with_hint()" << std::endl; #endif @@ -80,8 +79,7 @@ init_with_hint(const X_monotone_curve_2& cv, Pl_result_type obj) // notifications for the visitor. // template -void Arrangement_zone_2::compute_zone() -{ +void Arrangement_zone_2::compute_zone() { #if defined(ARR_ZONE_VERBOSE) std::cout << "compute_zone()" << std::endl; #endif @@ -253,8 +251,7 @@ template 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 -{ + 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(); @@ -307,8 +304,7 @@ do_overlap_impl(const X_monotone_curve_2& cv1, // template bool Arrangement_zone_2:: -_find_prev_around_vertex(Vertex_handle v, Halfedge_handle& he) -{ +_find_prev_around_vertex(Vertex_handle v, Halfedge_handle& he) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_find_prev_around_vertex(" << v->point() << ")" << std::endl; #endif @@ -393,8 +389,7 @@ typename Arrangement_zone_2::Halfedge_handle Arrangement_zone_2:: _direct_intersecting_edge_to_right(const X_monotone_curve_2& cv_ins, const Point_2& cv_left_pt, - Halfedge_handle query_he) -{ + Halfedge_handle query_he) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_direct_intersecting_edge_to_right() " << cv_left_pt << std::endl; @@ -446,8 +441,7 @@ template typename Arrangement_zone_2::Halfedge_handle Arrangement_zone_2:: _direct_intersecting_edge_to_left(const X_monotone_curve_2& cv_ins, - Halfedge_handle query_he) -{ + Halfedge_handle query_he) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_direct_intersecting_edge_to_left()" << std::endl; #endif @@ -544,8 +538,7 @@ typename Arrangement_zone_2::Optional_intersection Arrangement_zone_2:: _compute_next_intersection(Halfedge_handle he, bool skip_first_point, - Arr_parameter_space& intersection_location) -{ + Arr_parameter_space& intersection_location) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_compute_next_intersection(" << he->curve() << ", " << skip_first_point << ")" << std::endl; @@ -591,7 +584,8 @@ _compute_next_intersection(Halfedge_handle he, if (is_closed(*icv, ARR_MIN_END)) { // The curve has a valid left point - make sure it lies to the // right of m_left_pt. - valid_intersection = (compare_xy(ctr_min(*icv), m_left_pt) != SMALLER); + valid_intersection = + (compare_xy(ctr_min(*icv), m_left_pt) != SMALLER); } // In this case the overlap is not valid. else valid_intersection = false; @@ -670,8 +664,7 @@ _compute_next_intersection(Halfedge_handle he, // template void Arrangement_zone_2:: -_remove_next_intersection(Halfedge_handle he) -{ +_remove_next_intersection(Halfedge_handle he) { // Get a pointer to the curve associated with the halfedge. const X_monotone_curve_2* p_curve = &(he->curve()); @@ -691,8 +684,7 @@ _remove_next_intersection(Halfedge_handle he) template bool Arrangement_zone_2:: _is_to_left_impl(const Point_2& p, Halfedge_handle he, - Arr_not_all_sides_oblivious_tag) const -{ + Arr_not_all_sides_oblivious_tag) const { #if defined(ARR_ZONE_VERBOSE) std::cout << "_is_to_left_impl(" << p << "," << he->curve() << ")" << std::endl; @@ -723,13 +715,13 @@ _is_to_left_impl(const Point_2& p, Halfedge_handle he, } //----------------------------------------------------------------------------- -// Determine whether a given point lies completely to the right of a given curve. +// Determine whether a given point lies completely to the right of a given +// curve. // template bool Arrangement_zone_2:: _is_to_right_impl(const Point_2& p, Halfedge_handle he, - Arr_not_all_sides_oblivious_tag) const -{ + Arr_not_all_sides_oblivious_tag) const { #if defined(ARR_ZONE_VERBOSE) std::cout << "_is_to_right_impl(" << p << "," << he->curve() << ")" << std::endl; @@ -767,8 +759,7 @@ _is_to_right_impl(const Point_2& p, Halfedge_handle he, template void Arrangement_zone_2:: _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, - Arr_parameter_space& leftmost_location) -{ + Arr_parameter_space& leftmost_location) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_leftmost_intersection(" << he_curr->curve() << ", " << on_boundary << ")" << std::endl; @@ -880,8 +871,7 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, // template void Arrangement_zone_2:: -_leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) -{ +_leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_leftmost_intersection_with_face_boundary(" << on_boundary << ")" << std::endl; @@ -899,8 +889,7 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) // Traverse the face outer-boundaries; iterate through all outer CCBs. for (auto occb_it = face->outer_ccbs_begin(); - occb_it != face->outer_ccbs_end(); ++occb_it) - { + occb_it != face->outer_ccbs_end(); ++occb_it) { Ccb_halfedge_circulator he_first = *occb_it; Ccb_halfedge_circulator he_curr = he_first; do _leftmost_intersection(he_curr, on_boundary, leftmost_location); @@ -909,8 +898,7 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) // Traverse the face inner-boundaries; iterate through all inner CCBs (holes). for (auto iccb_it = face->inner_ccbs_begin(); - iccb_it != face->inner_ccbs_end(); ++iccb_it) - { + iccb_it != face->inner_ccbs_end(); ++iccb_it) { Ccb_halfedge_circulator he_first = *iccb_it; Ccb_halfedge_circulator he_curr = he_first; do _leftmost_intersection(he_curr, on_boundary, leftmost_location); @@ -921,17 +909,15 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) // Traverse the isolated vertices inside the face (if there exist any), and // check whether an isolated vertex lies on the curve. - typedef typename Arrangement_2::Isolated_vertex_iterator - Isolated_vertex_iterator; - for (Isolated_vertex_iterator iv_it = face->isolated_vertices_begin(); - iv_it != face->isolated_vertices_end(); ++iv_it) - { + for (auto iv_it = face->isolated_vertices_begin(); + iv_it != face->isolated_vertices_end(); ++iv_it) { // If the isolated vertex is not in the x-range of our curve, disregard it. if (! is_in_x_range(m_cv, iv_it->point())) continue; // If we already have an intersection point, compare it to the current // isolated vertex, in order to filter unnecessary computations. - if (m_found_intersect && compare_xy(iv_it->point(), m_intersect_p) == LARGER) + if (m_found_intersect && + (compare_xy(iv_it->point(), m_intersect_p) == LARGER)) continue; // In case the isolated vertex lies on the curve, update the intersection @@ -960,8 +946,7 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) // template bool Arrangement_zone_2:: -_zone_in_face(Face_handle face, bool on_boundary) -{ +_zone_in_face(Face_handle face, bool on_boundary) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_zone_in_face(" << on_boundary << ")" << std::endl; #endif @@ -1190,8 +1175,7 @@ _zone_in_face(Face_handle face, bool on_boundary) // curve currently associated with m_intersect_he. // template -bool Arrangement_zone_2::_zone_in_overlap() -{ +bool Arrangement_zone_2::_zone_in_overlap() { #if defined(ARR_ZONE_VERBOSE) std::cout << "_zone_in_overlap()" << std::endl; #endif From ada39fdfaedc8847ea689b54dbc382c145692abb Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 9 Aug 2023 19:10:16 +0300 Subject: [PATCH 13/35] Cleaned up and dispatched is_intersection_valid_impl() properly --- .../Arrangement_2/Arrangement_zone_2_impl.h | 50 +++++++-- .../include/CGAL/Arrangement_zone_2.h | 104 +++++++++--------- 2 files changed, 96 insertions(+), 58 deletions(-) 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 054724aa6e4..6903b44429a 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 @@ -504,14 +504,46 @@ template bool Arrangement_zone_2:: is_intersection_valid_impl(const Point_2& ip, Arr_parameter_space& /* intersection_location */, - Arr_all_sides_oblivious_tag) const + Arr_boundary_cond_tag) const { return (m_geom_traits->compare_xy_2_object()(ip, m_left_pt) == LARGER); } template bool Arrangement_zone_2:: is_intersection_valid_impl(const Point_2& ip, Arr_parameter_space& intersection_location, - Arr_not_all_sides_oblivious_tag) const { + Arr_has_identified_side_tag) const { + auto equal = m_geom_traits->equal_2_object(); + auto is_on_y_ident = m_geom_traits->is_on_y_identification_2_object(); + // Case 1: the curve lies on the y-identification + if (is_on_y_ident(m_cv)) { + if (equal(ip, m_left_pt)) return false; + // We set the location to be on the left as a convention + intersection_location = ARR_LEFT_BOUNDARY; + return true; + } + + // Case 2: The left-end lies on the left boundary + // (It cannot lie on the right boundary) + // If the intersection point is not equal to the left-end, it must lie to + // its right; thus valid. + if (m_left_on_boundary) return ! equal(ip, m_left_pt); + + // Case 3: The right-end lies on the right boundary + if (m_right_on_boundary && equal(ip, m_right_pt)) { + intersection_location = ARR_RIGHT_BOUNDARY; + return true; + } + + // We have a simple intersection point; + // make sure it lies to the right of m_left_pt. + return (m_geom_traits->compare_xy_2_object()(ip, m_left_pt) == LARGER); +} + +template +bool Arrangement_zone_2:: +is_intersection_valid_impl(const Point_2& ip, + Arr_parameter_space& intersection_location, + Arr_has_open_side_tag) const { auto equal = m_geom_traits->equal_2_object(); if (m_left_on_boundary) { // The left-end lies on the left boundary. If the intersection point is not @@ -699,12 +731,12 @@ _is_to_left_impl(const Point_2& p, Halfedge_handle he, 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 = ps_in_y(he->curve(), ARR_MIN_END); - if (ps_y != ARR_INTERIOR) { + auto ps_y_min = ps_in_y(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(); const auto res = cmp_x(p, he->curve(), ARR_MIN_END); - return ((res == SMALLER) || (res == EQUAL && ps_y == ARR_TOP_BOUNDARY)); + return ((res == SMALLER) || (res == EQUAL && ps_y_min == ARR_TOP_BOUNDARY)); } // In case the minimal curve-end does not have boundary conditions, simply @@ -738,12 +770,12 @@ _is_to_right_impl(const Point_2& p, Halfedge_handle he, 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 = ps_in_y(he->curve(), ARR_MAX_END); - if (ps_y != ARR_INTERIOR) { + auto ps_y_max = ps_in_y(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(); auto res = cmp_x(p, he->curve(), ARR_MAX_END); - return ((res == LARGER) || (res == EQUAL && ps_y == ARR_BOTTOM_BOUNDARY)); + return ((res == LARGER) || (res == EQUAL && ps_y_max == ARR_BOTTOM_BOUNDARY)); } // In case the maximal curve-end does not have boundary conditions, simply @@ -783,7 +815,7 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, // entirely to the right of m_intersect_p, its intersection with m_cv (if any) // cannot lie to the left of this point. We therefore do not need to compute // this intersection. - if (m_found_intersect && (leftmost_location != ARR_RIGHT_BOUNDARY) && + if (m_found_intersect && (leftmost_location == ARR_INTERIOR) && _is_to_left(m_intersect_p, he_curr)) return; 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 71b5e4a7409..5d22e410109 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h @@ -55,65 +55,70 @@ namespace CGAL { template class Arrangement_zone_2 { public: - typedef Arrangement_ Arrangement_2; - typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; - typedef typename Arrangement_2::Topology_traits Topology_traits; + using Arrangement_2 = Arrangement_; + using Geometry_traits_2 = typename Arrangement_2::Geometry_traits_2; + using Topology_traits = typename Arrangement_2::Topology_traits; protected: - typedef Arr_traits_adaptor_2 Traits_adaptor_2; + using Traits_adaptor_2 = Arr_traits_adaptor_2; - typedef typename Traits_adaptor_2::Left_side_category Left_side_category; - typedef typename Traits_adaptor_2::Bottom_side_category Bottom_side_category; - typedef typename Traits_adaptor_2::Top_side_category Top_side_category; - typedef typename Traits_adaptor_2::Right_side_category Right_side_category; + using Left_side_category = typename Traits_adaptor_2::Left_side_category; + using Bottom_side_category = typename Traits_adaptor_2::Bottom_side_category; + using Top_side_category = typename Traits_adaptor_2::Top_side_category; + using Right_side_category = typename Traits_adaptor_2::Right_side_category; static_assert(Arr_sane_identified_tagging::value); + // Categories for dispatching + using Are_all_sides_oblivious_category = + typename Arr_all_sides_oblivious_category::result; + + using Left_or_right_sides_category = + typename Arr_two_sides_category::result; public: - typedef ZoneVisitor_ Visitor; + using Visitor = ZoneVisitor_; - typedef typename Arrangement_2::Vertex_handle Vertex_handle; - typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; - typedef typename Arrangement_2::Face_handle Face_handle; + using Vertex_handle = typename Arrangement_2::Vertex_handle; + using Halfedge_handle = typename Arrangement_2::Halfedge_handle; + using Face_handle = typename Arrangement_2::Face_handle; - typedef std::pair Visitor_result; + using Visitor_result = std::pair; - typedef typename Geometry_traits_2::Point_2 Point_2; - typedef typename Geometry_traits_2::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Geometry_traits_2::Multiplicity Multiplicity; + using Point_2 = typename Geometry_traits_2::Point_2; + using X_monotone_curve_2 = typename Geometry_traits_2::X_monotone_curve_2; + using Multiplicity = typename Geometry_traits_2::Multiplicity; protected: - typedef typename Arr_all_sides_oblivious_category::result - Are_all_sides_oblivious_category; + // General types + using Vertex_const_handle = typename Arrangement_2::Vertex_const_handle; + using Halfedge_const_handle = typename Arrangement_2::Halfedge_const_handle; + using Face_const_handle = typename Arrangement_2::Face_const_handle; - typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; - typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; - typedef typename Arrangement_2::Face_const_handle Face_const_handle; - - typedef typename Arrangement_2::Ccb_halfedge_circulator - Ccb_halfedge_circulator; + using Ccb_halfedge_circulator = + typename Arrangement_2::Ccb_halfedge_circulator; // Types used for caching intersection points: - typedef std::pair Intersection_point; - typedef boost::variant - Intersection_result; - typedef boost::optional Optional_intersection; - typedef std::list Intersect_list; - typedef std::map - Intersect_map; - typedef typename Intersect_map::iterator Intersect_map_iterator; + using Intersection_point = std::pair; + using Intersection_result = + boost::variant; + using Optional_intersection = boost::optional; + using Intersect_list = std::list; + using Intersect_map = + std::map; + using Intersect_map_iterator = typename Intersect_map::iterator; - typedef std::set Curves_set; - typedef typename Curves_set::iterator Curves_set_iterator; + using Curves_set = std::set; + using Curves_set_iterator = typename Curves_set::iterator; - typedef Arr_point_location_result Pl_result; - typedef typename Pl_result::Type Pl_result_type; + using Pl_result = Arr_point_location_result; + using Pl_result_type = typename Pl_result::Type; // Data members: Arrangement_2& m_arr; // The associated arrangement. @@ -193,8 +198,7 @@ public: * \param pl A point-location object associated with the arrangement. */ template - void init(const X_monotone_curve_2& cv, const PointLocation& pl) - { + void init(const X_monotone_curve_2& cv, const PointLocation& pl) { // Set the curve and check whether its left end has boundary conditions. m_cv = cv; @@ -267,8 +271,7 @@ private: */ bool do_overlap_impl(const X_monotone_curve_2& cv1, const X_monotone_curve_2& cv2, - const Point_2& p, Arr_all_sides_oblivious_tag) const - { + const Point_2& p, Arr_all_sides_oblivious_tag) const { return m_geom_traits->compare_y_at_x_right_2_object()(cv1, cv2, p) == EQUAL; } @@ -381,8 +384,7 @@ private: { return (_is_to_right_impl(p, he, Are_all_sides_oblivious_category())); } bool _is_to_right_impl(const Point_2& p, Halfedge_handle he, - Arr_all_sides_oblivious_tag) const - { + Arr_all_sides_oblivious_tag) const { return (((he->direction() == ARR_LEFT_TO_RIGHT) && m_geom_traits->compare_xy_2_object()(p, he->target()->point()) == LARGER) || @@ -400,16 +402,20 @@ private: bool is_intersection_valid(const Point_2& ip, Arr_parameter_space& intersection_location) const { return is_intersection_valid_impl(ip, intersection_location, - Are_all_sides_oblivious_category()); + Left_or_right_sides_category()); } bool is_intersection_valid_impl(const Point_2& ip, Arr_parameter_space& intersection_location, - Arr_all_sides_oblivious_tag) const; + Arr_boundary_cond_tag) const; bool is_intersection_valid_impl(const Point_2& ip, Arr_parameter_space& intersection_location, - Arr_not_all_sides_oblivious_tag) const; + Arr_has_identified_side_tag) const; + + bool is_intersection_valid_impl(const Point_2& ip, + Arr_parameter_space& intersection_location, + Arr_has_open_side_tag) const; /*! Compute the (lexicographically) leftmost intersection of the query * curve with a given halfedge on the boundary of a face in the arrangement. From 0762a3040051bc0eb4fa611e20e1cfd57302321f Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 10 Aug 2023 21:38:52 +0300 Subject: [PATCH 14/35] Fixed is_intersection_valid_impl() and added test case --- .../Arrangement_2/Arrangement_zone_2_impl.h | 11 ++++++++--- .../include/CGAL/Arrangement_zone_2.h | 4 ++-- .../geodesic_arcs_on_sphere/test40.txt | 17 +++++++++++++++++ ...est_construction.geodesic_arcs_on_sphere.cmd | 1 + 4 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/test_construction/geodesic_arcs_on_sphere/test40.txt 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 6903b44429a..222f869444a 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 @@ -499,14 +499,15 @@ _direct_intersecting_edge_to_left(const X_monotone_curve_2& cv_ins, } } -//----------------------------------------------------------------------------- +//! Implementation for no boundary conditions. template bool Arrangement_zone_2:: is_intersection_valid_impl(const Point_2& ip, Arr_parameter_space& /* intersection_location */, - Arr_boundary_cond_tag) const + Arr_all_sides_oblivious_tag) const { return (m_geom_traits->compare_xy_2_object()(ip, m_left_pt) == LARGER); } +//! Implementation for left and right identified boundaries. template bool Arrangement_zone_2:: is_intersection_valid_impl(const Point_2& ip, @@ -539,11 +540,15 @@ is_intersection_valid_impl(const Point_2& ip, return (m_geom_traits->compare_xy_2_object()(ip, m_left_pt) == LARGER); } +/*! Implementation for all the rest. + * It would be better to split into the various cases, which is the cartesian + * product of (contructed, closed, open) X (contructed, closed, open) + */ template bool Arrangement_zone_2:: is_intersection_valid_impl(const Point_2& ip, Arr_parameter_space& intersection_location, - Arr_has_open_side_tag) const { + Arr_boundary_cond_tag) const { auto equal = m_geom_traits->equal_2_object(); if (m_left_on_boundary) { // The left-end lies on the left boundary. If the intersection point is not 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 5d22e410109..2a5db1727c3 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h @@ -407,7 +407,7 @@ private: bool is_intersection_valid_impl(const Point_2& ip, Arr_parameter_space& intersection_location, - Arr_boundary_cond_tag) const; + Arr_all_sides_oblivious_tag) const; bool is_intersection_valid_impl(const Point_2& ip, Arr_parameter_space& intersection_location, @@ -415,7 +415,7 @@ private: bool is_intersection_valid_impl(const Point_2& ip, Arr_parameter_space& intersection_location, - Arr_has_open_side_tag) const; + Arr_boundary_cond_tag) const; /*! Compute 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/test/Arrangement_on_surface_2/data/test_construction/geodesic_arcs_on_sphere/test40.txt b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/test_construction/geodesic_arcs_on_sphere/test40.txt new file mode 100644 index 00000000000..adccf6ecad9 --- /dev/null +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/test_construction/geodesic_arcs_on_sphere/test40.txt @@ -0,0 +1,17 @@ +5 +0 -1 0 0 0 -1 0 +0 0 -1 0 0 0 -1 +0 0 0 -1 0 1 0 +0 0 1 0 -1 0 0 +0 0 0 -1 -1 0 0 +0 +4 5 3 +0 0 -1 +-1 0 0 +0 -1 0 +0 1 0 +0 0 0 -1 -1 0 0 1 +0 -1 0 0 0 -1 0 1 +0 0 -1 0 0 0 -1 1 +0 0 0 -1 0 1 0 1 +0 0 1 0 -1 0 0 1 diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_construction.geodesic_arcs_on_sphere.cmd b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_construction.geodesic_arcs_on_sphere.cmd index 547aa518864..d995644a095 100644 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_construction.geodesic_arcs_on_sphere.cmd +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_construction.geodesic_arcs_on_sphere.cmd @@ -37,3 +37,4 @@ data/test_construction/geodesic_arcs_on_sphere/test36.txt data/test_construction/geodesic_arcs_on_sphere/test37.txt data/test_construction/geodesic_arcs_on_sphere/test38.txt data/test_construction/geodesic_arcs_on_sphere/test39.txt +data/test_construction/geodesic_arcs_on_sphere/test40.txt From 7b00717eabbe10265204ad6261a364064dc0055b Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Fri, 18 Aug 2023 12:49:32 +0300 Subject: [PATCH 15/35] Fixed comment --- .../include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h index e3a934889bc..ddf3688c48d 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h @@ -95,11 +95,11 @@ public: return (*this); } - /*! Set the location of the point. + /*! Set the location type of the point. */ void set_location(Location_type location) { m_location = location; } - /*! Obtain the location of the point. + /*! Obtain the location type of the point. */ Location_type location() const { return m_location; } From de459faa76881bd151204fb1cedb16324f4f94ed Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Fri, 18 Aug 2023 13:35:00 +0300 Subject: [PATCH 16/35] Fixed the Approximate_2::operator() that returns a sequence of points that approximate a curve; in particular, respected the l2r parameter. --- .../Arr_geodesic_arc_on_sphere_traits_2.h | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h index ddf3688c48d..3dde86da5a9 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h @@ -2889,18 +2889,31 @@ public: OutputIterator operator()(const X_monotone_curve_2& xcv, Approximate_number_type error, OutputIterator oi, bool l2r = true) const { - auto s = xcv.source(); - auto t = xcv.target(); - auto n = xcv.normal(); + const auto& s = xcv.source(); + const auto& t = xcv.target(); + const auto& n = xcv.normal(); + const auto dx = CGAL::to_double(n.dx()); + const auto dy = CGAL::to_double(n.dy()); + const auto dz = CGAL::to_double(n.dz()); - // get the approximate points; - auto as = (*this)(s); - auto at = (*this)(t); + Approximate_point_2 as, at; + Approximate_kernel_vector_3 vn; + if (xcv.is_directed_right() == l2r) { + // Get the approximate points + as = (*this)(s); + at = (*this)(t); + vn = Approximate_kernel_vector_3(dx, dy, dz); + } + else { + // Get the approximate points + as = (*this)(t); + at = (*this)(s); + vn = Approximate_kernel_vector_3(-dx, -dy, -dz); + } // convert the approximate points to vectors with approximate-kernel auto vs = approximate_vector_3(as); auto vt = approximate_vector_3(at); - auto vn = approximate_vector_3(n); // normalize the vectors auto normalize = [](auto& x) { x /= std::sqrt(x.squared_length()); }; From 51fc8aa18d314194a8cf0c6b3ee5aff18aed2c09 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Fri, 18 Aug 2023 13:38:34 +0300 Subject: [PATCH 17/35] Removed unused variable --- .../include/CGAL/Arrangement_2/Arrangement_zone_2_impl.h | 1 - 1 file changed, 1 deletion(-) 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 222f869444a..7a824ab974a 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 @@ -581,7 +581,6 @@ _compute_next_intersection(Halfedge_handle he, << skip_first_point << ")" << std::endl; #endif - auto equal = m_geom_traits->equal_2_object(); auto compare_xy = m_geom_traits->compare_xy_2_object(); auto ctr_min = m_geom_traits->construct_min_vertex_2_object(); auto is_closed = m_geom_traits->is_closed_2_object(); From 3b84bd05f86e4003804b3b5b59858f8ba02ceadc Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Fri, 18 Aug 2023 13:45:53 +0300 Subject: [PATCH 18/35] Reported the fix in PR #7644 --- Installation/CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index bedbfc89832..a0e667f0328 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -11,6 +11,9 @@ Release date: October 2023 - **Breaking change**: C++17 is now required - Support for Visual `C++` 14.0 (Visual studio 2015) is dropped. +### [2D Arrangements](https://doc.cgal.org/6.0/Manual/packages.html#PkgArrangementOnSurface2) +- 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. [Release 5.6](https://github.com/CGAL/cgal/releases/tag/v5.6) ----------- From ea46c6f28252ea4010b610cc883cebbe5ea1f6a1 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Mon, 28 Aug 2023 16:24:03 +0300 Subject: [PATCH 19/35] Pacify msvc17: explicitly name the (non-const) iterator type --- .../include/CGAL/Arrangement_2/Arrangement_zone_2_impl.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 5aa184d4d0c..2889f219237 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 @@ -946,7 +946,9 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) { // Traverse the isolated vertices inside the face (if there exist any), and // check whether an isolated vertex lies on the curve. - for (auto iv_it = face->isolated_vertices_begin(); + // MSVC17 requires an explicit (non-const) type for the iterator. + typename Arrangement_2::Isolated_vertex_iterator iv_it; + for (iv_it = face->isolated_vertices_begin(); iv_it != face->isolated_vertices_end(); ++iv_it) { // If the isolated vertex is not in the x-range of our curve, disregard it. if (! is_in_x_range(m_cv, iv_it->point())) continue; From 7beae3e8beb8d400d7e997471467198d14ab8e7c Mon Sep 17 00:00:00 2001 From: ange-clement Date: Wed, 6 Sep 2023 16:19:02 +0200 Subject: [PATCH 20/35] Made images colors adapt to their base color --- .../demo/Polyhedron/Scene_image_item.cpp | 27 ++++++++++++------- Polyhedron/demo/Polyhedron/Scene_image_item.h | 2 ++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_image_item.cpp b/Polyhedron/demo/Polyhedron/Scene_image_item.cpp index e9999831d4e..6969b172e37 100644 --- a/Polyhedron/demo/Polyhedron/Scene_image_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_image_item.cpp @@ -24,7 +24,7 @@ template class Image_accessor { public: - Image_accessor(const Image& im, int dx=1, int dy=1, int dz=1); + Image_accessor(const Image& im, int dx=1, int dy=1, int dz=1, const QColor& default_color = QColor()); bool is_vertex_active(std::size_t i, std::size_t j, std::size_t k) const; const QColor& vertex_color(std::size_t i, std::size_t j, std::size_t k) const; @@ -64,12 +64,12 @@ private: }; template -Image_accessor::Image_accessor(const Image& im, int dx, int dy, int dz) +Image_accessor::Image_accessor(const Image& im, int dx, int dy, int dz, const QColor& default_color) : im_(&im) , dx_(dx) , dy_(dy) , dz_(dz) -, default_color_() +, default_color_(default_color) , colors_() { const std::size_t xdim = im_->xdim(); @@ -88,14 +88,15 @@ Image_accessor::Image_accessor(const Image& im, int dx, int dy, int d } } - double i=0; - const double starting_hue = 45./360.; // magenta + const double nb_Colors = colors_.size()+1; + double i=1; + const double starting_hue = default_color.hueF(); for ( auto it = colors_.begin(), end = colors_.end() ; it != end ; ++it, i += 1.) { - double hue = starting_hue + 1./double(colors_.size()) * i; + double hue = starting_hue + 1./nb_Colors * i; if ( hue > 1. ) { hue -= 1.; } - it->second = QColor::fromHsvF(hue, .75, .75); + it->second = QColor::fromHsvF(hue, default_color.saturationF(), default_color.valueF()); } } @@ -753,6 +754,11 @@ void Scene_image_item::drawEdges(Viewer_interface *viewer) const bool Scene_image_item::isGray() { return d->is_hidden;} +void Scene_image_item::setColor(QColor c) { + color_ = c; + invalidateOpenGLBuffers(); +} + void Scene_image_item::invalidateOpenGLBuffers() { setBuffersFilled(false); @@ -779,9 +785,9 @@ void Scene_image_item::initializeBuffers(Viewer_interface *v) const template internal::Vertex_buffer_helper* -init_helper(const Image &im, int dx, int dy, int dz, bool is_ogl_4_3) +init_helper(const Image &im, int dx, int dy, int dz, bool is_ogl_4_3, const QColor& default_color = QColor()) { - internal::Image_accessor image_data_accessor(im, dx, dy, dz); + internal::Image_accessor image_data_accessor(im, dx, dy, dz, default_color); return new internal::Vertex_buffer_helper_impl(std::move(image_data_accessor), is_ogl_4_3); } @@ -800,7 +806,8 @@ void Scene_image_item::computeElements() const CGAL_IMAGE_IO_CASE(m_image->image(), d->helper = init_helper(*m_image, d->m_voxel_scale, d->m_voxel_scale, d->m_voxel_scale, - d->is_ogl_4_3)); + d->is_ogl_4_3, + color_)); d->helper->fill_buffer_data(); getTriangleContainer(0)->allocate( Tc::Smooth_vertices, diff --git a/Polyhedron/demo/Polyhedron/Scene_image_item.h b/Polyhedron/demo/Polyhedron/Scene_image_item.h index fadffb352c4..d841f4b4f33 100644 --- a/Polyhedron/demo/Polyhedron/Scene_image_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_image_item.h @@ -49,6 +49,8 @@ public: void set_image_weights(const Image& img, const float sigma); float sigma_weights() const; + void setColor(QColor c); + void invalidateOpenGLBuffers(); void initializeBuffers(Viewer_interface *) const; void computeElements() const; From 6f8116c4d55cb4fd691ea4e02e003f468b8afd68 Mon Sep 17 00:00:00 2001 From: ange-clement Date: Wed, 6 Sep 2023 18:24:27 +0200 Subject: [PATCH 21/35] Update mesh coloring. Visible surface patches uses the domains' colors. The mesh generated from an image has now the same color (if their base color is the same). --- .../Polyhedron/Scene_triangulation_3_item.cpp | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp b/Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp index 7dc8c51f1ce..837d859aa97 100644 --- a/Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp @@ -442,6 +442,7 @@ struct Scene_triangulation_3_item_priv { typedef std::set Indices; Indices surface_patch_indices_; Indices subdomain_indices_; + std::unordered_map visible_surface_patch_to_subdomain; std::unordered_map id_to_compact; QSlider* tet_Slider; bool is_filterable; @@ -643,6 +644,7 @@ Scene_triangulation_3_item::triangulation_changed() // Fill indices map and get max subdomain value d->surface_patch_indices_.clear(); d->subdomain_indices_.clear(); + d->visible_surface_patch_to_subdomain.clear(); d->visible_subdomain.clear(); d->id_to_compact.clear(); @@ -664,7 +666,18 @@ Scene_triangulation_3_item::triangulation_changed() end = triangulation().finite_facets_end(); fit != end; ++fit) { max = (std::max)(max, fit->first->surface_patch_index(fit->second)); - d->surface_patch_indices_.insert(fit->first->surface_patch_index(fit->second)); + int index = fit->first->surface_patch_index(fit->second); + d->surface_patch_indices_.insert(index); + int dom0 = fit->first->subdomain_index(); + int dom1 = fit->first->neighbor(fit->second)->subdomain_index(); + if (dom0 == 0) // if cell is not in complex + { + d->visible_surface_patch_to_subdomain[index] = dom1; + } + else if (dom1 == 0) // if opposite cell is not in complex + { + d->visible_surface_patch_to_subdomain[index] = dom0; + } } d->colors.resize(max + 1); @@ -882,12 +895,23 @@ Scene_triangulation_3_item_priv::compute_color_map(const QColor& c) } const size_type nb_patch_indices = surface_patch_indices_.size(); i = 0; + double patch_hsv_value = fmod(c.valueF() + .5, 1.); for (Indices::iterator it = surface_patch_indices_.begin(), end = surface_patch_indices_.end(); it != end; ++it, i += 1.) { double hue = c.hueF() + 1. / double(nb_patch_indices) * i; if (hue > 1) { hue -= 1.; } - colors[*it] = QColor::fromHsvF(hue, c.saturationF(), c.valueF()); + colors[*it] = QColor::fromHsvF(hue, c.saturationF(), patch_hsv_value); + } + + const size_type nb_visible_patch_indices = visible_surface_patch_to_subdomain.size(); + i = 0; + for (std::unordered_map::iterator it = visible_surface_patch_to_subdomain.begin(), + end = visible_surface_patch_to_subdomain.end(); it != end; ++it, i += 1.) + { + double hue = c.hueF() + 1. / double(nb_patch_indices) * i; + if (hue > 1) { hue -= 1.; } + colors[it->first] = colors_subdomains[it->second]; } } From c059ee5be3f9014ca433d9d6437b464909f3f4e4 Mon Sep 17 00:00:00 2001 From: ange-clement Date: Thu, 7 Sep 2023 10:06:25 +0200 Subject: [PATCH 22/35] Updated scene mesh creation The color is initialized to the base item's color. --- Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp index 59c687fb8a4..ca47e02782a 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp @@ -1037,7 +1037,7 @@ treat_result(Scene_item& source_item, float((bbox.ymin() + bbox.ymax())/2.f), float((bbox.zmin() + bbox.zmax())/2.f)); - result_item->setColor(default_mesh_color); + result_item->setColor(source_item.color()); result_item->setRenderingMode(source_item.renderingMode()); result_item->set_data_item(&source_item); From 7d79636f0bec6a5e703f3a9c81c9052d6e5ed0cf Mon Sep 17 00:00:00 2001 From: ange-clement Date: Mon, 11 Sep 2023 17:48:24 +0200 Subject: [PATCH 23/35] Removed unnecessary lines --- Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp b/Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp index 837d859aa97..91e88fb6ae2 100644 --- a/Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp @@ -904,13 +904,9 @@ Scene_triangulation_3_item_priv::compute_color_map(const QColor& c) colors[*it] = QColor::fromHsvF(hue, c.saturationF(), patch_hsv_value); } - const size_type nb_visible_patch_indices = visible_surface_patch_to_subdomain.size(); - i = 0; for (std::unordered_map::iterator it = visible_surface_patch_to_subdomain.begin(), - end = visible_surface_patch_to_subdomain.end(); it != end; ++it, i += 1.) + end = visible_surface_patch_to_subdomain.end(); it != end; ++it) { - double hue = c.hueF() + 1. / double(nb_patch_indices) * i; - if (hue > 1) { hue -= 1.; } colors[it->first] = colors_subdomains[it->second]; } } From 86e28d2c85e868b20a41ac5939673bc324e6c830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 13 Sep 2023 15:45:15 +0200 Subject: [PATCH 24/35] Change default model --- Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp index 66e9653f1b4..113215b631a 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp @@ -63,7 +63,7 @@ using Facet = Triangulation::Facet; int main(int argc, char** argv) { // Read the input - const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/armadillo.off"); + const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/bull.off"); std::cout << "Reading " << filename << "..." << std::endl; Points points; From 3ac8ddf5af12c86bf15ecafe0541b5cac78d910b Mon Sep 17 00:00:00 2001 From: JacksonCampolattaro Date: Sun, 24 Sep 2023 18:38:07 +0200 Subject: [PATCH 25/35] More accounting for non-nullable maps --- .../Polygonal_surface_reconstruction/internal/hypothesis.h | 2 +- .../internal/point_set_with_planes.h | 2 +- .../Surface_reconstruction_advancing_front_impl.cpp | 6 ++---- .../Point_set/Surface_reconstruction_polygonal_impl.cpp | 6 ++---- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/hypothesis.h b/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/hypothesis.h index 19ee7849a78..e4c1f4e004a 100644 --- a/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/hypothesis.h +++ b/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/hypothesis.h @@ -747,7 +747,7 @@ namespace CGAL { if (v == Polygon_mesh::null_vertex()) // failed splitting edge return Polygon_mesh::null_halfedge(); - typename Polygon_mesh::template Property_map& coords = mesh.points(); + auto &coords = mesh.points(); coords[v] = *ep.pos; Edge_descriptor e1 = mesh.edge(h); diff --git a/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/point_set_with_planes.h b/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/point_set_with_planes.h index 09d628e7f4e..2061ed13b25 100644 --- a/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/point_set_with_planes.h +++ b/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/point_set_with_planes.h @@ -142,7 +142,7 @@ namespace CGAL { std::size_t idx = 0; for (typename PointRange::const_iterator it = points.begin(); it != points.end(); ++it) { Base_class::m_points[idx] = get(point_map, *it); - Base_class::m_normals[idx] = get(normal_map, *it); + Base_class::m_normals.value()[idx] = get(normal_map, *it); int plane_index = get(plane_index_map, *it); if (plane_index != -1) { auto it_and_bool = plane_index_remap.emplace(plane_index, planar_segments_.size()); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_advancing_front_impl.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_advancing_front_impl.cpp index a8c93069b29..38dffa910f2 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_advancing_front_impl.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_advancing_front_impl.cpp @@ -19,9 +19,8 @@ struct Construct{ template Construct(SMesh& mesh, const PointRange& points) - : mesh(mesh) + : mesh(mesh), vpmap(get(boost::vertex_point, mesh)) { - vpmap = get(boost::vertex_point, mesh); for (const auto& p : points) { typename boost::graph_traits::vertex_descriptor v; @@ -192,8 +191,7 @@ SMesh* advancing_front (const Point_set& points, if (structuring) // todo { - Point_set::Property_map shape_map - = points.property_map("shape").first; + auto shape_map = points.property_map("shape").value(); typedef CGAL::Point_set_with_structure Structuring; std::vector planes; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_polygonal_impl.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_polygonal_impl.cpp index 3e320160372..8e075d26ce4 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_polygonal_impl.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_polygonal_impl.cpp @@ -26,11 +26,9 @@ SMesh* polygonal_reconstruct (const Point_set& points, CGAL_USE (model_complexity); CGAL_USE (solver_name); - Point_set::Property_map shape_map - = points.property_map("shape").first; + auto shape_map = points.property_map("shape").value(); - Polygonal_surface_reconstruction poly - (points, points.point_map(), points.normal_map(), shape_map); + Polygonal_surface_reconstruction poly(points, points.point_map(), points.normal_map(), shape_map); SMesh* mesh = new SMesh; From bf3bc031c7072056c6adcc422388374ef8068265 Mon Sep 17 00:00:00 2001 From: JacksonCampolattaro Date: Sun, 24 Sep 2023 19:38:25 +0200 Subject: [PATCH 26/35] Eliminate another `boost::tie` --- .../Polyhedron/Plugins/Display/Heat_method_plugin.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Display/Heat_method_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Display/Heat_method_plugin.cpp index fc6d564379b..c5cffdac60b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Display/Heat_method_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Display/Heat_method_plugin.cpp @@ -730,11 +730,9 @@ private: return; // Here we only target the property maps added by this plugin, so 'double' is fine - SMesh::Property_map property; - bool found; - std::tie(property, found) = sm->property_map(property_name); - if(found) - sm->remove_property_map(property); + auto property = sm->get_property_map(property_name); + if(property) + sm->remove_property_map(property.value()); } void removePluginProperties(Scene_item* item) From 9b738cbf4b9821d7326bfa4a069b530ac930f846 Mon Sep 17 00:00:00 2001 From: JacksonCampolattaro Date: Sun, 24 Sep 2023 22:38:27 +0200 Subject: [PATCH 27/35] Eliminate more instances of boost::tie found with a global search The classification plugin should probably be refactored at some point. --- .../CGAL/Classification/Planimetric_grid.h | 6 +- .../Classification/Point_set_neighborhood.h | 6 +- .../CGAL/Classification/property_maps.h | 2 - .../Classification/Cluster_classification.cpp | 120 +++++++++--------- .../Classification/Cluster_classification.h | 30 ++--- .../Point_set_item_classification.cpp | 102 +++++++-------- .../Point_set_item_classification.h | 69 +++++----- .../Surface_mesh_item_classification.cpp | 26 ++-- .../Surface_mesh_item_classification.h | 5 +- .../demo/Polyhedron/include/Point_set_3.h | 12 +- .../include/CGAL/Search_traits_adapter.h | 26 ++-- 11 files changed, 192 insertions(+), 212 deletions(-) diff --git a/Classification/include/CGAL/Classification/Planimetric_grid.h b/Classification/include/CGAL/Classification/Planimetric_grid.h index 2fd1adf5773..673727f2df9 100644 --- a/Classification/include/CGAL/Classification/Planimetric_grid.h +++ b/Classification/include/CGAL/Classification/Planimetric_grid.h @@ -59,7 +59,7 @@ private: using Image_bool = Image; const PointRange* m_points; - PointMap m_point_map; + std::optional m_point_map; Iso_cuboid_3 m_bbox; float m_resolution; @@ -342,7 +342,7 @@ public: { if (m_lower_scale == nullptr) { - const Point_3& p = get(m_point_map, *(m_points->begin()+index)); + const Point_3& p = get(m_point_map.value(), *(m_points->begin()+index)); return (std::size_t)((p.x() - m_bbox.xmin()) / m_resolution); } @@ -356,7 +356,7 @@ public: { if (m_lower_scale == nullptr) { - const Point_3& p = get(m_point_map, *(m_points->begin()+index)); + const Point_3& p = get(m_point_map.value(), *(m_points->begin()+index)); return (std::size_t)((p.y() - m_bbox.ymin()) / m_resolution); } diff --git a/Classification/include/CGAL/Classification/Point_set_neighborhood.h b/Classification/include/CGAL/Classification/Point_set_neighborhood.h index c27c874f0c2..4527ab53f05 100644 --- a/Classification/include/CGAL/Classification/Point_set_neighborhood.h +++ b/Classification/include/CGAL/Classification/Point_set_neighborhood.h @@ -69,7 +69,7 @@ class Point_set_neighborhood using key_type = std::uint32_t; using category = boost::readable_property_map_tag; - My_point_property_map () { } + //My_point_property_map () { } My_point_property_map (const PointRange *input, PointMap point_map) : input (input), point_map (point_map) { } @@ -88,7 +88,7 @@ class Point_set_neighborhood using Knn = Orthogonal_k_neighbor_search; std::shared_ptr m_tree; - Distance m_distance; + std::optional m_distance; public: @@ -300,7 +300,7 @@ private: void k_neighbors (const Point& query, const unsigned int k, OutputIterator output) const { CGAL_assertion (m_tree != nullptr); - Knn search (*m_tree, query, k, 0, true, m_distance); + Knn search (*m_tree, query, k, 0, true, m_distance.value()); for (typename Knn::iterator it = search.begin(); it != search.end(); ++ it) *(output ++) = it->first; } diff --git a/Classification/include/CGAL/Classification/property_maps.h b/Classification/include/CGAL/Classification/property_maps.h index f03e837d806..bad32f9d7ee 100644 --- a/Classification/include/CGAL/Classification/property_maps.h +++ b/Classification/include/CGAL/Classification/property_maps.h @@ -59,8 +59,6 @@ private: public: - Face_descriptor_to_center_of_mass_map () - : m_mesh (nullptr) { } Face_descriptor_to_center_of_mass_map (const FaceGraph* mesh) : m_mesh (mesh), m_vpm (get (vertex_point, *m_mesh)) { } Face_descriptor_to_center_of_mass_map (const FaceGraph* mesh, VertexPointMap vpm) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp index b26135e231a..2c861f7c0c7 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp @@ -30,9 +30,8 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po backup_existing_colors_and_add_new(); - bool cluster_found = false; - boost::tie (m_cluster_id, cluster_found) = m_points->point_set()->property_map("shape"); - if (!cluster_found) + auto m_cluster_id = m_points->point_set()->property_map("shape"); + if (!m_cluster_id) { std::cerr << "Error! Cluster not found!" << std::endl; abort(); @@ -40,7 +39,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po CGAL::Classification::create_clusters_from_indices (*(m_points->point_set()), m_points->point_set()->point_map(), - m_cluster_id, + m_cluster_id.value(), m_clusters); std::cerr << m_clusters.size() << " cluster(s) found" << std::endl; @@ -57,20 +56,20 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po if (!classif_found) { - Point_set::Property_map las_classif; - boost::tie (las_classif, las_found) = m_points->point_set()->property_map("classification"); - if (las_found) + auto las_classif = m_points->point_set()->property_map("classification"); + las_found = las_classif.has_value(); + if (las_classif) { m_input_is_las = true; for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - unsigned char uc = las_classif[*it]; - m_classif[*it] = int(uc); + unsigned char uc = las_classif.value()[*it]; + m_classif.value()[*it] = int(uc); if (!training_found) - m_training[*it] = int(uc); + m_training.value()[*it] = int(uc); } - m_points->point_set()->remove_property_map (las_classif); + m_points->point_set()->remove_property_map (las_classif.value()); classif_found = true; training_found = true; } @@ -85,7 +84,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po { if (training_found) { - int l = m_training[*it]; + int l = m_training.value()[*it]; if (l >= 0) { if (std::size_t(l) >= used_indices.size()) @@ -95,7 +94,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po } if (classif_found) { - int l = m_classif[*it]; + int l = m_classif.value()[*it]; if (l >= 0) { if (std::size_t(l) >= used_indices.size()) @@ -125,31 +124,31 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int c = m_cluster_id[*it]; + int c = m_cluster_id.value()[*it]; if (training_found) { if (std::size_t(current_idx) != used_indices.size()) // Empty indices -> reorder indices in point set { - if (las_found && (m_training[*it] == 0 || m_training[*it] == 1)) // Unclassified class in LAS - m_training[*it] = -1; - else if (m_training[*it] != -1) - m_training[*it] = used_indices[std::size_t(m_training[*it])]; + if (las_found && (m_training.value()[*it] == 0 || m_training.value()[*it] == 1)) // Unclassified class in LAS + m_training.value()[*it] = -1; + else if (m_training.value()[*it] != -1) + m_training.value()[*it] = used_indices[std::size_t(m_training.value()[*it])]; } - if (c != -1 && m_training[*it] != -1) - m_clusters[c].training() = m_training[*it]; + if (c != -1 && m_training.value()[*it] != -1) + m_clusters[c].training() = m_training.value()[*it]; } if (classif_found) { if (std::size_t(current_idx) != used_indices.size()) // Empty indices -> reorder indices in point set { - if (las_found && (m_classif[*it] == 0 || m_classif[*it] == 1)) // Unclassified class in LAS - m_classif[*it] = -1; - else if (m_classif[*it] != -1) - m_classif[*it] = used_indices[std::size_t(m_classif[*it])]; + if (las_found && (m_classif.value()[*it] == 0 || m_classif.value()[*it] == 1)) // Unclassified class in LAS + m_classif.value()[*it] = -1; + else if (m_classif.value()[*it] != -1) + m_classif.value()[*it] = used_indices[std::size_t(m_classif.value()[*it])]; } - if (c != -1 && m_classif[*it] != -1) - m_clusters[c].label() = m_classif[*it]; + if (c != -1 && m_classif.value()[*it] != -1) + m_clusters[c].label() = m_classif.value()[*it]; } } @@ -240,11 +239,11 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po Delaunay dt (boost::make_transform_iterator (m_points->point_set()->begin(), Point_set_with_cluster_info (m_points->point_set(), - m_cluster_id)), + m_cluster_id.value())), boost::make_transform_iterator (m_points->point_set()->end(), Point_set_with_cluster_info (m_points->point_set(), - m_cluster_id))); + m_cluster_id.value()))); std::set > adjacencies; @@ -294,16 +293,16 @@ Cluster_classification::~Cluster_classification() for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int c = m_cluster_id[*it]; + int c = m_cluster_id.value()[*it]; if (c != -1) { - m_training[*it] = m_clusters[c].training(); - m_classif[*it] = m_clusters[c].label(); + m_training.value()[*it] = m_clusters[c].training(); + m_classif.value()[*it] = m_clusters[c].label(); } else { - m_training[*it] = -1; - m_classif[*it] = -1; + m_training.value()[*it] = -1; + m_classif.value()[*it] = -1; } } @@ -359,22 +358,22 @@ Cluster_classification::~Cluster_classification() for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - int c = m_classif[*it]; + int c = m_classif.value()[*it]; unsigned char lc = 1; // unclassified in LAS standard if (c != -1) lc = label_indices[std::size_t(c)]; las_classif[*it] = lc; - int t = m_training[*it]; + int t = m_training.value()[*it]; unsigned char lt = 1; // unclassified in LAS standard if (t != -1) lt = label_indices[std::size_t(t)]; - m_training[*it] = int(lt); + m_training.value()[*it] = int(lt); } - m_points->point_set()->remove_property_map (m_classif); + m_points->point_set()->remove_property_map (m_classif.value()); } @@ -391,7 +390,7 @@ void Cluster_classification::backup_existing_colors_and_add_new() m_color = m_points->point_set()->add_property_map("real_color").first; for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_color[*it] = CGAL::IO::Color ((unsigned char)(255 * m_points->point_set()->red(*it)), + m_color.value()[*it] = CGAL::IO::Color ((unsigned char)(255 * m_points->point_set()->red(*it)), (unsigned char)(255 * m_points->point_set()->green(*it)), (unsigned char)(255 * m_points->point_set()->blue(*it))); @@ -403,15 +402,15 @@ void Cluster_classification::backup_existing_colors_and_add_new() void Cluster_classification::reset_colors() { - if (m_color == Point_set::Property_map()) + if (!m_color) m_points->point_set()->remove_colors(); else { for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_points->point_set()->set_color(*it, m_color[*it]); + m_points->point_set()->set_color(*it, m_color.value()[*it]); - m_points->point_set()->remove_property_map(m_color); + m_points->point_set()->remove_property_map(m_color.value()); } } @@ -438,7 +437,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_points->point_set()->set_color(*it, m_color[*it]); + m_points->point_set()->set_color(*it, m_color.value()[*it]); } else if (index_color == 1) // classif { @@ -446,7 +445,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) it != m_points->point_set()->first_selected(); ++ it) { QColor color (0, 0, 0); - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { std::size_t c = m_clusters[cid].label(); @@ -464,7 +463,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) it != m_points->point_set()->first_selected(); ++ it) { QColor color (0, 0, 0); - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; float div = 1; if (cid != -1) @@ -486,7 +485,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { @@ -516,7 +515,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { float v = (std::max) (0.f, (std::min)(1.f, m_label_probabilities[corrected_index][cid])); @@ -553,7 +552,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { if (feature->value(cid) > max) @@ -567,7 +566,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { float v = (feature->value(cid) - min) / (max - min); @@ -598,15 +597,14 @@ int Cluster_classification::real_index_color() const { int out = m_index_color; - if (out == 0 && m_color == Point_set::Property_map()) + if (out == 0 && !m_color) out = -1; return out; } void Cluster_classification::reset_indices () { - Point_set::Property_map indices - = m_points->point_set()->property_map("index").first; + auto indices = m_points->point_set()->property_map("index").value(); m_points->point_set()->unselect_all(); Point_set::Index idx; @@ -629,18 +627,16 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe m_features.clear(); - Point_set::Vector_map normal_map; + std::optional normal_map; bool normals = m_points->point_set()->has_normal_map(); if (normals) normal_map = m_points->point_set()->normal_map(); - bool colors = (m_color != Point_set::Property_map()); + bool colors = m_color.has_value(); - Point_set::Property_map echo_map; - bool echo; - boost::tie (echo_map, echo) = m_points->point_set()->template property_map("echo"); - if (!echo) - boost::tie (echo_map, echo) = m_points->point_set()->template property_map("number_of_returns"); + auto echo_map = m_points->point_set()->template property_map("echo"); + if (!echo_map) + echo_map = m_points->point_set()->template property_map("number_of_returns").value(); Feature_set pointwise_features; @@ -655,11 +651,11 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe generator.generate_point_based_features(pointwise_features); if (normals) - generator.generate_normal_based_features (pointwise_features, normal_map); + generator.generate_normal_based_features (pointwise_features, normal_map.value()); if (colors) - generator.generate_color_based_features (pointwise_features, m_color); - if (echo) - generator.generate_echo_based_features (pointwise_features, echo_map); + generator.generate_color_based_features (pointwise_features, m_color.value()); + if (echo_map) + generator.generate_echo_based_features (pointwise_features, echo_map.value()); #ifdef CGAL_LINKED_WITH_TBB pointwise_features.end_parallel_additions(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h index ef4d006e2ce..c89e25e747b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h @@ -125,13 +125,12 @@ class Cluster_classification : public Item_classification_base { typedef typename Point_set::template Property_map Pmap; bool okay = false; - Pmap pmap; - boost::tie (pmap, okay) = m_points->point_set()->template property_map(name.c_str()); - if (okay) + auto pmap = m_points->point_set()->template property_map(name.c_str()); + if (pmap) feature_set.template add > - (*(m_points->point_set()), pmap, name.c_str()); + (*(m_points->point_set()), pmap.value(), name.c_str()); - return okay; + return pmap.has_value(); } void add_selection_to_training_set (std::size_t label) @@ -139,7 +138,7 @@ class Cluster_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { m_clusters[cid].training() = int(label); @@ -165,7 +164,7 @@ class Cluster_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { m_clusters[cid].training() = -1; @@ -187,7 +186,7 @@ class Cluster_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) m_clusters[cid].training() = m_clusters[cid].label(); } @@ -212,7 +211,7 @@ class Cluster_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { int c = m_clusters[cid].label(); @@ -238,7 +237,7 @@ class Cluster_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { int c = m_clusters[cid].label(); @@ -376,13 +375,10 @@ class Cluster_classification : public Item_classification_base std::vector m_clusters; - Point_set::Property_map m_red; - Point_set::Property_map m_green; - Point_set::Property_map m_blue; - Point_set::Property_map m_color; - Point_set::Property_map m_cluster_id; - Point_set::Property_map m_training; - Point_set::Property_map m_classif; + std::optional> m_color; + std::optional> m_cluster_id; + std::optional> m_training; + std::optional> m_classif; std::vector > m_label_probabilities; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp index 12bc858fea9..3c827920cb5 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp @@ -16,23 +16,20 @@ #include Point_set_item_classification::Point_set_item_classification(Scene_points_with_normal_item* points) - : m_points (points) - , m_generator (nullptr) - , m_input_is_las (false) -{ + : m_points(points), m_generator(nullptr), m_input_is_las(false), + m_training(), + m_classif(){ m_index_color = 1; reset_indices(); - Point_set::Property_map cluster_id; - bool cluster_found = false; - boost::tie (cluster_id, cluster_found) = m_points->point_set()->property_map("shape"); - if (cluster_found) + auto cluster_id = m_points->point_set()->property_map("shape"); + if (cluster_id) { for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int c = cluster_id[*it]; + int c = cluster_id.value()[*it]; if (c == -1) continue; if (std::size_t(c) >= m_clusters.size()) @@ -54,20 +51,20 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n if (!classif_found) { - Point_set::Property_map las_classif; - boost::tie (las_classif, las_found) = m_points->point_set()->property_map("classification"); - if (las_found) + auto las_classif = m_points->point_set()->property_map("classification"); + las_found = las_classif.has_value(); + if (las_classif) { m_input_is_las = true; for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - unsigned char uc = las_classif[*it]; - m_classif[*it] = int(uc); + unsigned char uc = las_classif.value()[*it]; + m_classif.value()[*it] = int(uc); if (!training_found) - m_training[*it] = int(uc); + m_training.value()[*it] = int(uc); } - m_points->point_set()->remove_property_map (las_classif); + m_points->point_set()->remove_property_map (las_classif.value()); classif_found = true; training_found = true; } @@ -82,7 +79,7 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n { if (training_found) { - int l = m_training[*it]; + int l = m_training.value()[*it]; if (l >= 0) { if (std::size_t(l) >= used_indices.size()) @@ -92,7 +89,7 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n } if (classif_found) { - int l = m_classif[*it]; + int l = m_classif.value()[*it]; if (l >= 0) { if (std::size_t(l) >= used_indices.size()) @@ -125,17 +122,17 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n { if (training_found) { - if (las_found && (m_training[*it] == 0 || m_training[*it] == 1)) // Unclassified class in LAS - m_training[*it] = -1; - else if (m_training[*it] != -1) - m_training[*it] = used_indices[std::size_t(m_training[*it])]; + if (las_found && (m_training.value()[*it] == 0 || m_training.value()[*it] == 1)) // Unclassified class in LAS + m_training.value()[*it] = -1; + else if (m_training.value()[*it] != -1) + m_training.value()[*it] = used_indices[std::size_t(m_training.value()[*it])]; } if (classif_found) { - if (las_found && (m_classif[*it] == 0 || m_classif[*it] == 1)) // Unclassified class in LAS - m_classif[*it] = -1; - else if (m_classif[*it] != -1) - m_classif[*it] = used_indices[std::size_t(m_classif[*it])]; + if (las_found && (m_classif.value()[*it] == 0 || m_classif.value()[*it] == 1)) // Unclassified class in LAS + m_classif.value()[*it] = -1; + else if (m_classif.value()[*it] != -1) + m_classif.value()[*it] = used_indices[std::size_t(m_classif.value()[*it])]; } } } @@ -295,22 +292,22 @@ Point_set_item_classification::~Point_set_item_classification() for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - int c = m_classif[*it]; + int c = m_classif.value()[*it]; unsigned char lc = 1; // unclassified in LAS standard if (c != -1) lc = label_indices[std::size_t(c)]; las_classif[*it] = lc; - int t = m_training[*it]; + int t = m_training.value()[*it]; unsigned char lt = 1; // unclassified in LAS standard if (t != -1) lt = label_indices[std::size_t(t)]; - m_training[*it] = int(lt); + m_training.value()[*it] = int(lt); } - m_points->point_set()->remove_property_map (m_classif); + m_points->point_set()->remove_property_map (m_classif.value()); } reset_colors(); @@ -327,7 +324,7 @@ void Point_set_item_classification::backup_existing_colors_and_add_new() m_color = m_points->point_set()->add_property_map("real_color").first; for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_color[*it] = CGAL::IO::Color((unsigned char)(255 * m_points->point_set()->red(*it)), + m_color.value()[*it] = CGAL::IO::Color((unsigned char)(255 * m_points->point_set()->red(*it)), (unsigned char)(255 * m_points->point_set()->green(*it)), (unsigned char)(255 * m_points->point_set()->blue(*it))); @@ -339,15 +336,15 @@ void Point_set_item_classification::backup_existing_colors_and_add_new() void Point_set_item_classification::reset_colors() { - if (m_color == Point_set::Property_map()) + if (!m_color) m_points->point_set()->remove_colors(); else { for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_points->point_set()->set_color(*it, m_color[*it]); + m_points->point_set()->set_color(*it, m_color.value()[*it]); - m_points->point_set()->remove_property_map(m_color); + m_points->point_set()->remove_property_map(m_color.value()); } } @@ -374,7 +371,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_points->point_set()->set_color(*it, m_color[*it]); + m_points->point_set()->set_color(*it, m_color.value()[*it]); } else if (index_color == 1) // classif { @@ -382,7 +379,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* it != m_points->point_set()->first_selected(); ++ it) { QColor color (0, 0, 0); - std::size_t c = m_classif[*it]; + std::size_t c = m_classif.value()[*it]; if (c != std::size_t(-1)) color = label_qcolor (m_labels[c]); @@ -396,8 +393,8 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* it != m_points->point_set()->first_selected(); ++ it) { QColor color (0, 0, 0); - int c = m_training[*it]; - int c2 = m_classif[*it]; + int c = m_training.value()[*it]; + int c2 = m_classif.value()[*it]; if (c != -1) color = label_qcolor (m_labels[std::size_t(c)]); @@ -490,15 +487,14 @@ int Point_set_item_classification::real_index_color() const { int out = m_index_color; - if (out == 0 && m_color == Point_set::Property_map()) + if (out == 0 && !m_color) out = -1; return out; } void Point_set_item_classification::reset_indices () { - Point_set::Property_map indices - = m_points->point_set()->property_map("index").first; + auto indices = m_points->point_set()->property_map("index").value(); m_points->point_set()->unselect_all(); Point_set::Index idx; @@ -524,18 +520,16 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo m_features.clear(); - Point_set::Vector_map normal_map; + std::optional normal_map; bool normals = m_points->point_set()->has_normal_map(); if (normals) normal_map = m_points->point_set()->normal_map(); - bool colors = (m_color != Point_set::Property_map()); + bool colors = m_color.has_value(); - Point_set::Property_map echo_map; - bool echo; - boost::tie (echo_map, echo) = m_points->point_set()->template property_map("echo"); - if (!echo) - boost::tie (echo_map, echo) = m_points->point_set()->template property_map("number_of_returns"); + auto echo_map = m_points->point_set()->template property_map("echo"); + if (!echo_map) + echo_map = m_points->point_set()->template add_property_map("number_of_returns").first; m_generator = new Generator (*(m_points->point_set()), m_points->point_set()->point_map(), nb_scales, voxel_size); @@ -548,11 +542,11 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo m_generator->generate_point_based_features(m_features); if (normals) - m_generator->generate_normal_based_features (m_features, normal_map); + m_generator->generate_normal_based_features (m_features, normal_map.value()); if (colors) - m_generator->generate_color_based_features (m_features, m_color); - if (echo) - m_generator->generate_echo_based_features (m_features, echo_map); + m_generator->generate_color_based_features (m_features, m_color.value()); + if (echo_map) + m_generator->generate_echo_based_features (m_features, echo_map.value()); #ifdef CGAL_LINKED_WITH_TBB m_features.end_parallel_additions(); @@ -709,7 +703,7 @@ void Point_set_item_classification::train(int classifier, const QMultipleInputDi for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - training[*it] = m_training[*it]; + training[*it] = m_training.value()[*it]; if (training[*it] != -1) { nb_label[std::size_t(training[*it])] ++; @@ -758,7 +752,7 @@ void Point_set_item_classification::train(int classifier, const QMultipleInputDi for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_classif[*it] = indices[*it]; + m_classif.value()[*it] = indices[*it]; if (m_index_color == 1 || m_index_color == 2) change_color (m_index_color); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h index f52e2438aab..0b0f21e96f6 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h @@ -47,13 +47,9 @@ class Point_set_item_classification : public Item_classification_base Point_set::Property_map cluster_id; std::vector* clusters; - Cluster_neighborhood (Point_set* point_set, - std::vector& clusters) - : point_set (point_set) - , clusters (&clusters) - { - cluster_id = point_set->property_map("shape").first; - } + Cluster_neighborhood(Point_set* point_set, + std::vector& clusters) + : point_set(point_set), clusters(&clusters), cluster_id(point_set->add_property_map("shape").first) {} template OutputIterator operator() (const Point_set::Index& idx, @@ -147,18 +143,16 @@ class Point_set_item_classification : public Item_classification_base bool try_adding_simple_feature (const std::string& name) { typedef typename Point_set::template Property_map Pmap; - bool okay = false; - Pmap pmap; - boost::tie (pmap, okay) = m_points->point_set()->template property_map(name.c_str()); - if (okay) + auto pmap = m_points->point_set()->template property_map(name.c_str()); + if (pmap) { std::cerr << "Adding property<" << CGAL::demangle(typeid(Type).name()) << ">(" << name << ") as feature" << std::endl; m_features.template add > - (*(m_points->point_set()), pmap, name.c_str()); + (*(m_points->point_set()), pmap.value(), name.c_str()); } - return okay; + return pmap.has_value(); } void add_selection_to_training_set (std::size_t label) @@ -166,8 +160,8 @@ class Point_set_item_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) { - m_training[*it] = int(label); - m_classif[*it] = int(label); + m_training.value()[*it] = int(label); + m_classif.value()[*it] = int(label); } m_points->resetSelection(); @@ -178,8 +172,8 @@ class Point_set_item_classification : public Item_classification_base { for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) - if (m_training[*it] == int(label)) - m_training[*it] = -1; + if (m_training.value()[*it] == int(label)) + m_training.value()[*it] = -1; if (m_index_color == 1 || m_index_color == 2) change_color (m_index_color); } @@ -188,8 +182,8 @@ class Point_set_item_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) { - m_training[*it] = -1; - m_classif[*it] = -1; + m_training.value()[*it] = -1; + m_classif.value()[*it] = -1; } if (m_index_color == 1 || m_index_color == 2) change_color (m_index_color); @@ -198,7 +192,7 @@ class Point_set_item_classification : public Item_classification_base { for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) - m_training[*it] = -1; + m_training.value()[*it] = -1; if (m_index_color == 1 || m_index_color == 2) change_color (m_index_color); } @@ -206,7 +200,7 @@ class Point_set_item_classification : public Item_classification_base { for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) - m_training[*it] = m_classif[*it]; + m_training.value()[*it] = m_classif.value()[*it]; m_points->resetSelection(); if (m_index_color == 1 || m_index_color == 2) @@ -229,7 +223,7 @@ class Point_set_item_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - int c = m_classif[*it]; + int c = m_classif.value()[*it]; if (c == label) points_item->point_set()->insert (m_points->point_set()->point(*it)); } @@ -251,7 +245,7 @@ class Point_set_item_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - int c = m_classif[*it]; + int c = m_classif.value()[*it]; if (c != -1) points_item[c]->point_set()->insert (m_points->point_set()->point(*it)); } @@ -271,15 +265,15 @@ class Point_set_item_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - if (m_training[*it] == int(position)) - m_training[*it] = -1; - else if (m_training[*it] > int(position)) - m_training[*it] --; + if (m_training.value()[*it] == int(position)) + m_training.value()[*it] = -1; + else if (m_training.value()[*it] > int(position)) + m_training.value()[*it] --; - if (m_classif[*it] == int(position)) - m_classif[*it] = -1; - else if (m_classif[*it] > int(position)) - m_classif[*it] --; + if (m_classif.value()[*it] == int(position)) + m_classif.value()[*it] = -1; + else if (m_classif.value()[*it] > int(position)) + m_classif.value()[*it] --; } update_comments_of_point_set_item(); } @@ -364,8 +358,8 @@ class Point_set_item_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - m_classif[*it] = indices[*it]; - ground_truth[*it] = m_training[*it]; + m_classif.value()[*it] = indices[*it]; + ground_truth[*it] = m_training.value()[*it]; } if (m_index_color == 1 || m_index_color == 2) @@ -396,14 +390,11 @@ class Point_set_item_classification : public Item_classification_base std::vector m_clusters; - Point_set::Property_map m_red; - Point_set::Property_map m_green; - Point_set::Property_map m_blue; - Point_set::Property_map m_color; + std::optional> m_color; std::vector > m_label_probabilities; - Point_set::Property_map m_training; - Point_set::Property_map m_classif; + std::optional> m_training; + std::optional> m_classif; Generator* m_generator; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.cpp b/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.cpp index 4880c0917db..00a9e29a532 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.cpp @@ -15,13 +15,13 @@ Surface_mesh_item_classification::Surface_mesh_item_classification(Scene_surface_mesh_item* mesh) : m_mesh (mesh), m_selection (nullptr), - m_generator (nullptr) + m_generator (nullptr), + m_training(m_mesh->polyhedron()->add_property_map("f:training", std::size_t(-1)).first), + m_classif(m_mesh->polyhedron()->add_property_map("f:label", std::size_t(-1)).first) { m_index_color = 1; backup_existing_colors_and_add_new(); - m_training = m_mesh->polyhedron()->add_property_map("f:training", std::size_t(-1)).first; - m_classif = m_mesh->polyhedron()->add_property_map("f:label", std::size_t(-1)).first; m_labels.add("ground"); m_labels.add("vegetation"); @@ -64,8 +64,8 @@ void Surface_mesh_item_classification::backup_existing_colors_and_add_new() = m_mesh->polyhedron()->add_property_map("f:real_color").first; for(face_descriptor fd : faces(*(m_mesh->polyhedron()))) { - m_real_color[fd] = m_color[fd]; - m_color[fd] = CGAL::IO::Color(128, 128, 128); + m_real_color.value()[fd] = m_color.value()[fd]; + m_color.value()[fd] = CGAL::IO::Color(128, 128, 128); } } else @@ -77,7 +77,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo { m_index_color = index; int index_color = index; - if (index == 0 && m_real_color == Mesh::Property_map()) + if (index == 0 && !m_real_color) index_color = -1; static Color_ramp ramp; @@ -86,12 +86,12 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo if (index_color == -1) // item color { for(face_descriptor fd : faces(*(m_mesh->polyhedron()))) - m_color[fd] = CGAL::IO::Color(128,128,128); + m_color.value()[fd] = CGAL::IO::Color(128,128,128); } else if (index_color == 0) // real colors { for(face_descriptor fd : faces(*(m_mesh->polyhedron()))) - m_color[fd] = m_real_color[fd]; + m_color.value()[fd] = m_real_color.value()[fd]; } else if (index_color == 1) // classif { @@ -103,7 +103,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo if (c != std::size_t(-1)) color = label_qcolor (m_labels[c]); - m_color[fd] = CGAL::IO::Color(color.red(), color.green(), color.blue()); + m_color.value()[fd] = CGAL::IO::Color(color.red(), color.green(), color.blue()); } } else if (index_color == 2) // training @@ -120,7 +120,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo float div = 1; if (c != c2) div = 2; - m_color[fd] = CGAL::IO::Color(color.red() / div, + m_color.value()[fd] = CGAL::IO::Color(color.red() / div, color.green() / div, color.blue() / div); } @@ -135,7 +135,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo { for(face_descriptor fd : faces(*(m_mesh->polyhedron()))) { - m_color[fd] = CGAL::IO::Color((unsigned char)(128), + m_color.value()[fd] = CGAL::IO::Color((unsigned char)(128), (unsigned char)(128), (unsigned char)(128)); } @@ -145,7 +145,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo for(face_descriptor fd : faces(*(m_mesh->polyhedron()))) { float v = (std::max) (0.f, (std::min)(1.f, m_label_probabilities[corrected_index][fd])); - m_color[fd] = CGAL::IO::Color((unsigned char)(ramp.r(v) * 255), + m_color.value()[fd] = CGAL::IO::Color((unsigned char)(ramp.r(v) * 255), (unsigned char)(ramp.g(v) * 255), (unsigned char)(ramp.b(v) * 255)); } @@ -189,7 +189,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo if (v < 0.f) v = 0.f; if (v > 1.f) v = 1.f; - m_color[fd] = CGAL::IO::Color((unsigned char)(ramp.r(v) * 255), + m_color.value()[fd] = CGAL::IO::Color((unsigned char)(ramp.r(v) * 255), (unsigned char)(ramp.g(v) * 255), (unsigned char)(ramp.b(v) * 255)); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.h b/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.h index 797e88de438..df71c098b74 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.h @@ -200,8 +200,9 @@ protected: Scene_polyhedron_selection_item* m_selection; Mesh::Property_map m_training; Mesh::Property_map m_classif; - Mesh::Property_map m_color; - Mesh::Property_map m_real_color; + + std::optional> m_color; + std::optional> m_real_color; std::vector > m_label_probabilities; diff --git a/Polyhedron/demo/Polyhedron/include/Point_set_3.h b/Polyhedron/demo/Polyhedron/include/Point_set_3.h index 64f5a31be31..c3b00ac3258 100644 --- a/Polyhedron/demo/Polyhedron/include/Point_set_3.h +++ b/Polyhedron/demo/Polyhedron/include/Point_set_3.h @@ -295,17 +295,17 @@ public: void set_color (const Index& index, const QColor& color) { - m_red[index] = color.red(); - m_green[index] = color.green(); - m_blue[index] = color.blue(); + m_red.value()[index] = color.red(); + m_green.value()[index] = color.green(); + m_blue.value()[index] = color.blue(); } template void set_color (const Index& index, const ColorRange& color) { - m_red[index] = color[0]; - m_green[index] = color[1]; - m_blue[index] = color[2]; + m_red.value()[index] = color[0]; + m_green.value()[index] = color[1]; + m_blue.value()[index] = color[2]; } diff --git a/Spatial_searching/include/CGAL/Search_traits_adapter.h b/Spatial_searching/include/CGAL/Search_traits_adapter.h index ff640dc639a..a43dca7bd30 100644 --- a/Spatial_searching/include/CGAL/Search_traits_adapter.h +++ b/Spatial_searching/include/CGAL/Search_traits_adapter.h @@ -66,13 +66,15 @@ struct Get_iso_box_d template class Search_traits_adapter : public Base_traits{ - PointPropertyMap ppmap; + std::optional ppmap; public: typedef Base_traits Base; typedef typename internal::Get_iso_box_d::type Iso_box_d; - Search_traits_adapter(const PointPropertyMap& ppmap_=PointPropertyMap(), + Search_traits_adapter() {} + + Search_traits_adapter(const PointPropertyMap& ppmap_, const Base_traits& base=Base_traits() ):Base_traits(base),ppmap(ppmap_){} @@ -246,28 +248,30 @@ public: } Iso_box_d operator() (const Point_with_info& p, const Point_with_info& q) const { - return Base_functor::operator() (get(ppmap,p),get(ppmap,q)); + return Base_functor::operator() (get(ppmap.value(),p),get(ppmap.value(),q)); } }; - const PointPropertyMap& point_property_map() const {return ppmap;} + const PointPropertyMap& point_property_map() const {return ppmap.value();} Construct_cartesian_const_iterator_d construct_cartesian_const_iterator_d_object() const { return Construct_cartesian_const_iterator_d( Base::construct_cartesian_const_iterator_d_object(), - ppmap); + ppmap.value()); } }; template class Distance_adapter : public Base_distance { - PointPropertyMap ppmap; + std::optional ppmap; public: - Distance_adapter( const PointPropertyMap& ppmap_=PointPropertyMap(), - const Base_distance& distance=Base_distance() - ):Base_distance(distance),ppmap(ppmap_){} + Distance_adapter() {} + + Distance_adapter(const PointPropertyMap& ppmap_, + const Base_distance& distance = Base_distance()) + : Base_distance(distance), ppmap(ppmap_) {} using Base_distance::transformed_distance; @@ -275,11 +279,11 @@ public: typedef Point_with_info Point_d; typedef typename Base_distance::Query_item Query_item; - const PointPropertyMap& point_property_map() const {return ppmap;} + const PointPropertyMap& point_property_map() const {return ppmap.value();} FT transformed_distance(const Query_item& p1, const Point_with_info& p2) const { - return Base_distance::transformed_distance(p1,get(ppmap,p2)); + return Base_distance::transformed_distance(p1,get(ppmap.value(),p2)); } template From c575cd29cdb0ec7c6a2bd8726607cc9d1bc3c331 Mon Sep 17 00:00:00 2001 From: JacksonCampolattaro Date: Sun, 24 Sep 2023 23:30:05 +0200 Subject: [PATCH 28/35] Remove a couple of default initializations --- .../Plugins/Surface_mesh/Parameterization_plugin.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp index fffd332a832..596a315eb74 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp @@ -269,10 +269,9 @@ public : pen.setWidth(0); painter->setPen(pen); painter->setBrush(brush); - SMesh::Property_map u,v; - u = graph->add_property_map("h:u", 0.0f).first; - v = graph->add_property_map("h:v", 0.0f).first; + auto u = graph->add_property_map("h:u", 0.0f).first; + auto v = graph->add_property_map("h:v", 0.0f).first; for( Component::iterator fi = components->at(m_current_component).begin(); @@ -926,11 +925,8 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio QApplication::restoreOverrideCursor(); QPointF pmin(FLT_MAX, FLT_MAX), pmax(-FLT_MAX, -FLT_MAX); - SMesh::Property_map umap; - SMesh::Property_map vmap; - - umap = tMesh.add_property_map("h:u", 0.0f).first; - vmap = tMesh.add_property_map("h:v", 0.0f).first; + auto umap = tMesh.add_property_map("h:u", 0.0f).first; + auto vmap = tMesh.add_property_map("h:v", 0.0f).first; tMesh.property_stats(std::cerr); Base_face_graph::Halfedge_iterator it; From 6f86c932c8ab22e8fe32214381ad5ed2e491b4ee Mon Sep 17 00:00:00 2001 From: JacksonCampolattaro Date: Wed, 27 Sep 2023 21:13:46 +0200 Subject: [PATCH 29/35] Update function documentation for consistency --- Orthtree/include/CGAL/Orthtree.h | 288 ++++++++++++++++++++----------- 1 file changed, 185 insertions(+), 103 deletions(-) diff --git a/Orthtree/include/CGAL/Orthtree.h b/Orthtree/include/CGAL/Orthtree.h index e9f29084a54..2c0de4864f8 100644 --- a/Orthtree/include/CGAL/Orthtree.h +++ b/Orthtree/include/CGAL/Orthtree.h @@ -268,8 +268,7 @@ public: while nodes that were not split and for which `split_predicate` returns `true` are split. - \param split_predicate determines whether or not a node needs to - be subdivided. + \param split_predicate determines whether or not a node needs to be subdivided. */ void refine(const Split_predicate& split_predicate) { @@ -303,7 +302,6 @@ public: } /*! - \brief Convenience overload that refines an orthtree using a maximum depth and maximum number of inliers in a node as split predicate. @@ -331,6 +329,8 @@ public: /*! \brief refines the orthtree such that the difference of depth between two immediate neighbor leaves is never more than 1. + + This is done only by adding nodes, nodes are never removed. */ void grade() { @@ -459,6 +459,10 @@ public: \note The object constructed is not the bounding box of the node's contents, but the bounding box of the node itself. For a cubic orthtree, this will always be cubic. + + \param n node to generate a bounding box for + + \return the bounding box of the node n */ Bbox bbox(Node_index n) const { @@ -479,7 +483,15 @@ public: /// @{ /*! - * \brief pass-through to `get_or_add_property` for node properties. + \brief Gets a property for nodes, adding it if it doesn't already exist. + + \tparam T the type of the property to add + + \param name the name of the new property + \param default_value the default value assigned to nodes for this property + + \return pair of a reference to the new node property array + and a boolean which is True if the property needed to be created */ template std::pair>, bool> @@ -488,7 +500,14 @@ public: } /*! - * \brief pass-through to `add_property` for node properties. + \brief Adds a property for nodes. + + \tparam T the type of the property to add + + \param name the name of the new property + \param default_value the default value assigned to nodes for this property + + \return a reference to the new property array */ template Node_property_container::Array & add_node_property(const std::string& name, const T default_value = T()) { @@ -496,7 +515,15 @@ public: } /*! - * \brief pass-through to `get_property` for node properties. + \brief Gets a property of the tree nodes. + + The property to be retrieved must exist in the tree. + + \tparam T the type of the property to retrieve + + \param name the name of the property + + \return a reference to the property array */ template Node_property_container::Array & get_node_property(const std::string& name) { @@ -504,7 +531,13 @@ public: } /*! - * \brief pass-through to `get_property_if_exists` for node properties. + \brief Gets a property of the tree nodes if it exists. + + \tparam T the type of the property to retrieve + + \param name the name of the property + + \return an optional containing a reference to the property array if it exists */ template std::optional>> @@ -512,8 +545,6 @@ public: return m_node_properties.get_property_if_exists(name); } - // todo: is it ever useful to be able to delete/reset properties? - /// @} /// \name Queries @@ -527,6 +558,7 @@ public: the region enclosed by the orthtree (bbox of the root node). \param point query point. + \return the index of the node which contains the point. */ const Node_index locate(const Point& point) const { @@ -563,12 +595,15 @@ public: \note this function requires the function `bool CGAL::do_intersect(QueryType, Traits::Bbox_d)` to be defined. - This function finds all the intersecting nodes and writes their indices to the ouput iterator. + This function finds all the intersecting leaf nodes and writes their indices to the ouput iterator. \tparam Query the primitive class (e.g. sphere, ray) \tparam OutputIterator a model of `OutputIterator` that accepts `Node_index` types + \param query the intersecting primitive. \param output output iterator. + + \return the output iterator after writing */ template OutputIterator intersected_nodes(const Query& query, OutputIterator output) const { @@ -585,6 +620,10 @@ public: Trees may be considered equivalent even if they have different contents. Equivalent trees must have the same root bounding box and the same node structure. + + \param rhs the other orthtree + + \return boolean, True if the trees have the same topology */ bool operator==(const Self& rhs) const { @@ -602,6 +641,10 @@ public: /*! \brief compares the topology of the orthtree with that of `rhs`. + + \param rhs the other orthtree + + \return boolean, False if the trees have the same topology */ bool operator!=(const Self& rhs) const { return !operator==(rhs); @@ -613,63 +656,79 @@ public: /// @{ /*! - * \brief Determines whether the node specified by index `n` is a leaf node. - * - * @param n index of the node to check. - * @return true of the node is a leaf, false otherwise. + \brief Determines whether the node specified by index `n` is a leaf node. + + \param n index of the node to check. + + \return true of the node is a leaf, false otherwise. */ bool is_leaf(Node_index n) const { return !m_node_children[n].has_value(); } /*! - * \brief Determines whether the node specified by index `n` is a root node. - * - * @param n index of the node to check. - * @return true of the node is a root, false otherwise. + \brief Determines whether the node specified by index `n` is a root node. + + \param n index of the node to check. + + \return True of the node is a root, False otherwise. */ bool is_root(Node_index n) const { return n == 0; } /*! - * \brief Determines the depth of the node specified. - * - * The root node has depth 0, its children have depth 1, and so on. - * - * @param n index of the node to check. - * @return the depth of the node within its tree. + \brief Determines the depth of the node specified. + + The root node has depth 0, its children have depth 1, and so on. + + \param n index of the node to check. + + \return the depth of the node n within its tree. */ std::size_t depth(Node_index n) const { return m_node_depths[n]; } /*! - * \brief Retrieves a reference to the Node_data associated with the node specified by `n`. - * - * @param n index of the node to retrieve data for. - * @return the data associated with the node. + \brief Retrieves a reference to the Node_data associated with the node specified by `n`. + + \param n index of the node to retrieve the contents of. + + \return a reference to the data associated with the node. */ Node_data& data(Node_index n) { return m_node_contents[n]; } /*! - * \brief const version of `data()` + \brief const version of `data()` + + \param n index of the node to retrieve the contents of. + + \return a const reference to the data associated with the node. */ const Node_data& data(Node_index n) const { return m_node_contents[n]; } /*! - * \brief Retrieves the global coordinates of the node. + \brief Retrieves the global coordinates of the node. + + \param n index of the node to retrieve the coordinates of. + + \return the global coordinates of the node within the tree */ Global_coordinates global_coordinates(Node_index n) const { return m_node_coordinates[n]; } /*! - * \brief Retrieves the local coordinates of the node. + \brief Retrieves the local coordinates of the node. + + \param n index of the node to retrieve the coordinates of. + + \return the local coordinates of the node within the tree */ Local_coordinates local_coordinates(Node_index n) const { Local_coordinates result; @@ -679,35 +738,46 @@ public: } /*! - \brief returns this node's parent. + \brief returns this n's parent. + \pre `!is_root()` + + \param n index of the node to retrieve the parent of + + \return the index of the parent of node n */ - Node_index parent(Node_index node) const { - CGAL_precondition (!is_root(node)); - return *m_node_parents[node]; + Node_index parent(Node_index n) const { + CGAL_precondition (!is_root(n)); + return *m_node_parents[n]; } /*! - \brief returns this node's `i`th child. + \brief returns a node's `i`th child. + \pre `!is_leaf()` + + \param n index of the node to retrieve the child of + + \return the index of the `i`th child of node n */ - Node_index child(Node_index node, std::size_t i) const { - CGAL_precondition (!is_leaf(node)); - return *m_node_children[node] + i; + Node_index child(Node_index n, std::size_t i) const { + CGAL_precondition (!is_leaf(n)); + return *m_node_children[n] + i; } /*! - * \brief Retrieves an arbitrary descendant of the node specified by `node`. - * - * Convenience function to avoid the need to call `orthtree.child(orthtree.child(node, 0), 1)`. - * - * Each index in `indices` specifies which child to enter as descending the tree from `node` down. - * Indices are evaluated in the order they appear as parameters, so - * `descendant(root, 0, 1)` returns the second child of the first child of the root. - * - * @param node the node to descend - * @param indices the descent to perform - * @return the index of the specified descendant node. + \brief Retrieves an arbitrary descendant of the node specified by `node`. + + Convenience function to avoid the need to call `orthtree.child(orthtree.child(node, 0), 1)`. + + Each index in `indices` specifies which child to enter as descending the tree from `node` down. + Indices are evaluated in the order they appear as parameters, so + `descendant(root, 0, 1)` returns the second child of the first child of the root. + + \param node the node to descend + \param indices the integer indices specifying the descent to perform + + \return the index of the specified descendant node */ template Node_index descendant(Node_index node, Indices... indices) { @@ -715,7 +785,13 @@ public: } /*! - * \brief Convenience function for retrieving arbitrary nodes, equivalent to `tree.descendant(tree.root(), indices...)`. + \brief Convenience function for retrieving arbitrary nodes. + + Equivalent to `tree.descendant(tree.root(), indices...)`. + + \param indices the integer indices specifying the descent to perform, starting from root + + \return the index of the specified node */ template Node_index node(Indices... indices) { @@ -723,12 +799,14 @@ public: } /*! - * \brief Finds the next sibling in the parent of the node specified by the index `n`. - * - * Traverses the tree in increasing order of local index (e.g. 000, 001, 010, etc.) - * - * @param n the node to find the sibling of. - * @return the next sibling of `n` if `n` is not the last node in its parent, otherwise nothing. + \brief Finds the next sibling in the parent of the node specified by the index `n`. + + Traverses the tree in increasing order of local index (e.g. 000, 001, 010, etc.) + + \param n the index of the node to find the sibling of + + \return the index of the next sibling of n + if n is not the last node in its parent, otherwise nothing. */ const Maybe_node_index next_sibling(Node_index n) const { @@ -747,10 +825,12 @@ public: } /*! - * \brief Finds the next sibling of the parent of the node specified by `n` if it exists. - * - * @param n the node to find the sibling up of. - * @return The next sibling of the parent of `n` if `n` is not the root and its parent has a sibling, otherwise nothing. + \brief Finds the next sibling of the parent of the node specified by `n` if it exists. + + \param n the index node to find the sibling up of. + + \return The index of the next sibling of the parent of n + if n is not the root and its parent has a sibling, otherwise nothing. */ const Maybe_node_index next_sibling_up(Node_index n) const { @@ -769,12 +849,13 @@ public: } /*! - * \brief Finds the leaf node reached when descending the tree and always choosing child 0. - * - * This is the starting point of a depth-first traversal. - * - * @param n the node to find the deepest first child of. - * @return the index of the deepest first child. + \brief Finds the leaf node reached when descending the tree and always choosing child 0. + + This is the starting point of a depth-first traversal. + + \param n the index of the node to find the deepest first child of. + + \return the index of the deepest first child of node n. */ Node_index deepest_first_child(Node_index n) const { @@ -786,13 +867,14 @@ public: } /*! - * \brief Finds node reached when descending the tree to a depth `d` and always choosing child 0. - * - * Similar to `deepest_first_child`, but does not go to a fixed depth. - * - * @param n the node to find the `d`th first child of. - * @param d the depth to descend to. - * @return the index of the `d`th first child, nothing if the tree is not deep enough. + \brief Finds node reached when descending the tree to a depth `d` and always choosing child 0. + + Similar to `deepest_first_child`, but does not go to a fixed depth. + + \param n the index of the node to find the `d`th first child of. + \param d the depth to descend to. + + \return the index of the `d`th first child, nothing if the tree is not deep enough. */ Maybe_node_index first_child_at_depth(Node_index n, std::size_t d) const { @@ -815,13 +897,15 @@ public: } /*! - \brief splits the node into subnodes. + \brief splits a node into subnodes. - Only leaf nodes should be split. - When a node is split it is no longer a leaf node. - A number of `Degree::value` children are constructed automatically, and their values are set. - Contents of this node are _not_ propagated automatically, this is responsibility of the - `distribute_node_contents_object` in the Traits class. + Only leaf nodes should be split. + When a node is split it is no longer a leaf node. + A number of `Degree::value` children are constructed automatically, and their values are set. + Contents of this node are _not_ propagated automatically, this is responsibility of the + `distribute_node_contents_object` in the Traits class. + + \param n index of the node to split */ void split(Node_index n) { @@ -863,22 +947,11 @@ public: } /*! - * \brief eliminates this node's children, making it a leaf node. + * \brief Finds the center point of a node. * - * When a node is un-split, its children are automatically deleted. - * After un-splitting a node it will be considered a leaf node. - * Idempotent, un-splitting a leaf node has no effect. - */ - void unsplit(Node_index n) { - // todo: the child nodes should be de-allocated! - // This may need to be done recursively - } - - /*! - * \brief Finds the center point of the node specified by `n`. + * @param n index of the node to find the center point for * - * @param n The node to find the center point for. - * @return the center point of node `n`. + * @return the center point of node n */ Point barycenter(Node_index n) const { @@ -898,13 +971,14 @@ public: } /*! - * \brief Determines whether a pair of subtrees have the same topology. - * - * @param lhsNode a node in lhsTree - * @param lhsTree an Orthtree - * @param rhsNode a node in rhsTree - * @param rhsTree another Orthtree - * @return true if lhsNode and rhsNode have the same topology, false otherwise + \brief Determines whether a pair of subtrees have the same topology. + + \param lhsNode index of a node in lhsTree + \param lhsTree an Orthtree + \param rhsNode index of a node in rhsTree + \param rhsTree another Orthtree + + @return true if lhsNode and rhsNode have the same topology, false otherwise */ static bool is_topology_equal(Node_index lhsNode, const Self& lhsTree, Node_index rhsNode, const Self& rhsTree) { @@ -928,7 +1002,12 @@ public: } /*! - * \brief Helper function for calling `is_topology_equal` on the root nodes of two trees. + \brief Helper function for calling `is_topology_equal` on the root nodes of two trees. + + \param lhsTree an Orthtree + \param rhsTree another Orthtree + + \return True if lhsTree and rhsTree have the same topology */ static bool is_topology_equal(const Self& lhs, const Self& rhs) { return is_topology_equal(lhs.root(), lhs, rhs.root(), rhs); @@ -937,7 +1016,6 @@ public: /*! \brief finds the directly adjacent node in a specific direction - \pre `!is_null()` \pre `direction.to_ulong < 2 * Dimension::value` Adjacent nodes are found according to several properties: @@ -978,6 +1056,7 @@ public: there is no adjacent node in that direction, it returns a null node. + \param n index of the node to find a neighbor of \param direction which way to find the adjacent node relative to this one. Each successive bit selects the direction for the corresponding dimension: for an Octree in 3D, 010 means: negative @@ -1030,6 +1109,9 @@ public: /*! \brief equivalent to `adjacent_node()`, with an adjacency direction rather than a bitset. + + \param n index of the node to find a neighbor of + \param direction which way to find the adjacent node relative to this one */ Maybe_node_index adjacent_node(Node_index n, Adjacency adjacency) const { return adjacent_node(n, std::bitset(static_cast(adjacency))); From 92232c9295ed2f246ff3f20221f231021c3d4aa7 Mon Sep 17 00:00:00 2001 From: CCXXXI Date: Thu, 28 Sep 2023 12:53:05 +0800 Subject: [PATCH 30/35] fix a typo in Tutorial_hello_world.txt --- .../doc/Documentation/Tutorials/Tutorial_hello_world.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/doc/Documentation/Tutorials/Tutorial_hello_world.txt b/Documentation/doc/Documentation/Tutorials/Tutorial_hello_world.txt index da30ca174cc..a006447c79a 100644 --- a/Documentation/doc/Documentation/Tutorials/Tutorial_hello_world.txt +++ b/Documentation/doc/Documentation/Tutorials/Tutorial_hello_world.txt @@ -73,7 +73,7 @@ seems that the points are collinear, or perform a right turn. If you must ensure that your numbers get interpreted at their full precision you can use a \cgal kernel that performs exact predicates and -extract constructions. +exact constructions. \cgalExample{Kernel_23/exact.cpp} From 047a9494bde833678915f3b897ca88c429454d7e Mon Sep 17 00:00:00 2001 From: JacksonCampolattaro Date: Sat, 30 Sep 2023 09:24:20 +0200 Subject: [PATCH 31/35] Fix mismatched parameter names in documentation --- Orthtree/include/CGAL/Orthtree.h | 7 ++++--- Orthtree/include/CGAL/Orthtree/Nearest_neighbors.h | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Orthtree/include/CGAL/Orthtree.h b/Orthtree/include/CGAL/Orthtree.h index 2c0de4864f8..cd59162d91f 100644 --- a/Orthtree/include/CGAL/Orthtree.h +++ b/Orthtree/include/CGAL/Orthtree.h @@ -757,6 +757,7 @@ public: \pre `!is_leaf()` \param n index of the node to retrieve the child of + \param i in [0, 2^D) specifying the child to retrieve \return the index of the `i`th child of node n */ @@ -1004,8 +1005,8 @@ public: /*! \brief Helper function for calling `is_topology_equal` on the root nodes of two trees. - \param lhsTree an Orthtree - \param rhsTree another Orthtree + \param lhs an Orthtree + \param rhs another Orthtree \return True if lhsTree and rhsTree have the same topology */ @@ -1111,7 +1112,7 @@ public: \brief equivalent to `adjacent_node()`, with an adjacency direction rather than a bitset. \param n index of the node to find a neighbor of - \param direction which way to find the adjacent node relative to this one + \param adjacency which way to find the adjacent node relative to this one */ Maybe_node_index adjacent_node(Node_index n, Adjacency adjacency) const { return adjacent_node(n, std::bitset(static_cast(adjacency))); diff --git a/Orthtree/include/CGAL/Orthtree/Nearest_neighbors.h b/Orthtree/include/CGAL/Orthtree/Nearest_neighbors.h index 190a49fd70f..270ac53179c 100644 --- a/Orthtree/include/CGAL/Orthtree/Nearest_neighbors.h +++ b/Orthtree/include/CGAL/Orthtree/Nearest_neighbors.h @@ -129,6 +129,7 @@ namespace Orthtrees { \tparam Tree must be an orthtree with traits which are a model of CollectionPartitioningOrthtreeTraits \tparam OutputIterator must be a model of `OutputIterator` that accepts points + \param orthtree the tree to search within \param query_sphere the region to search within \param k the number of points to find @@ -172,6 +173,7 @@ OutputIterator nearest_k_neighbors_in_radius( \tparam Tree must be an orthtree with traits which are a model of CollectionPartitioningOrthtreeTraits \tparam OutputIterator a model of `OutputIterator` that accept `Point_d` objects. + \param orthtree the tree to search within \param query query point. \param k number of neighbors. @@ -193,6 +195,7 @@ OutputIterator nearest_neighbors(const Tree& orthtree, const typename Tree::Poin \tparam Tree must be an orthtree with traits which are a model of CollectionPartitioningOrthtreeTraits \tparam OutputIterator a model of `OutputIterator` that accept `Point_d` objects. + \param orthtree the tree to search within \param query query sphere. \param output output iterator. From feb87c737ae15e99d9a7f37609516f9a27bf23b3 Mon Sep 17 00:00:00 2001 From: JacksonCampolattaro Date: Thu, 5 Oct 2023 10:24:38 +0200 Subject: [PATCH 32/35] Eliminate most whitespace changes --- .../include/CGAL/Surface_mesh/Surface_mesh.h | 2915 +++++++++-------- 1 file changed, 1506 insertions(+), 1409 deletions(-) diff --git a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h index 9b0acad0868..86713e830d1 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h @@ -59,7 +59,7 @@ namespace CGAL { class SM_Index { public: - typedef std::uint32_t size_type; + typedef std::uint32_t size_type; /// Constructor. %Default construction creates an invalid index. /// We write -1, which is /// (std::numeric_limits::max)() @@ -341,7 +341,6 @@ class Surface_mesh public: #ifndef DOXYGEN_RUNNING - template using Property_container = Properties::Property_container; @@ -353,299 +352,311 @@ public: #endif // DOXYGEN_RUNNING - /// \name Basic Types - /// - ///@{ + /// \name Basic Types + /// + ///@{ - /// The point type. - typedef P Point; + /// The point type. + typedef P Point; - /// The type used to represent an index. - typedef std::uint32_t size_type; + /// The type used to represent an index. + typedef std::uint32_t size_type; - ///@} + ///@} - /// \name Basic Elements - /// - ///@{ + /// \name Basic Elements + /// + ///@{ #ifdef DOXYGEN_RUNNING - /// This class represents a vertex. - /// \cgalModels{Index,LessThanComparable,Hashable} - /// \sa `Halfedge_index`, `Edge_index`, `Face_index` - class Vertex_index - { - public: - /// %Default constructor. - Vertex_index(){} + /// This class represents a vertex. + /// \cgalModels{Index,LessThanComparable,Hashable} + /// \sa `Halfedge_index`, `Edge_index`, `Face_index` + class Vertex_index + { + public: + /// %Default constructor. + Vertex_index(){} - Vertex_index(size_type _idx){} + Vertex_index(size_type _idx){} - /// prints the index and a short identification string to an ostream. - friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Vertex_index const& v) - {} - }; + /// prints the index and a short identification string to an ostream. + friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Vertex_index const& v) + {} + }; #else typedef SM_Vertex_index Vertex_index; #endif #ifdef DOXYGEN_RUNNING - /// This class represents a halfedge. - /// \cgalModels{Index,LessThanComparable,Hashable} - /// \sa `Vertex_index`, `Edge_index`, `Face_index` - class Halfedge_index - { - public: - /// %Default constructor - Halfedge_index(){} + /// This class represents a halfedge. + /// \cgalModels{Index,LessThanComparable,Hashable} + /// \sa `Vertex_index`, `Edge_index`, `Face_index` + class Halfedge_index + { + public: + /// %Default constructor + Halfedge_index(){} - Halfedge_index(size_type _idx){} + Halfedge_index(size_type _idx){} - /// prints the index and a short identification string to an ostream. - friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Halfedge_index const& h) - { - } + /// prints the index and a short identification string to an ostream. + friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Halfedge_index const& h) + { + } - }; + }; #else typedef SM_Halfedge_index Halfedge_index; #endif #ifdef DOXYGEN_RUNNING - /// This class represents a face - /// \cgalModels{Index,LessThanComparable,Hashable} - /// \sa `Vertex_index`, `Halfedge_index`, `Edge_index` - class Face_index - { - public: - /// %Default constructor - Face_index(){} + /// This class represents a face + /// \cgalModels{Index,LessThanComparable,Hashable} + /// \sa `Vertex_index`, `Halfedge_index`, `Edge_index` + class Face_index + { + public: + /// %Default constructor + Face_index(){} - Face_index(size_type _idx){} + Face_index(size_type _idx){} - /// prints the index and a short identification string to an ostream. - friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Face_index const& f) - {} - }; + /// prints the index and a short identification string to an ostream. + friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Face_index const& f) + {} + }; #else typedef SM_Face_index Face_index; #endif #ifdef DOXYGEN_RUNNING - /// This class represents an edge. - /// \cgalModels{Index,LessThanComparable,Hashable} - /// \sa `Vertex_index`, `Halfedge_index`, `Face_index` - class Edge_index - { - public: - /// %Default constructor - Edge_index(){} + /// This class represents an edge. + /// \cgalModels{Index,LessThanComparable,Hashable} + /// \sa `Vertex_index`, `Halfedge_index`, `Face_index` + class Edge_index + { + public: + /// %Default constructor + Edge_index(){} - Edge_index(size_type idx){} + Edge_index(size_type idx){} - /// constructs an `Edge_index` from a halfedge. - Edge_index(Halfedge_index he){} + /// constructs an `Edge_index` from a halfedge. + Edge_index(Halfedge_index he){} - /// prints the index and a short identification string to an ostream. - friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Edge_index const& e) - {} - }; + /// prints the index and a short identification string to an ostream. + friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Edge_index const& e) + {} + }; #else typedef SM_Edge_index Edge_index; #endif - ///@} + ///@} #ifndef CGAL_TEST_SURFACE_MESH private: //-------------------------------------------------- connectivity types #endif - /// This type stores the vertex connectivity - /// \sa `Halfedge_connectivity`, `Face_connectivity` - struct Vertex_connectivity { - /// an incoming halfedge per vertex (it will be a border halfedge for border vertices) - Halfedge_index halfedge_; - }; + /// This type stores the vertex connectivity + /// \sa `Halfedge_connectivity`, `Face_connectivity` + struct Vertex_connectivity + { + /// an incoming halfedge per vertex (it will be a border halfedge for border vertices) + Halfedge_index halfedge_; + }; - /// This type stores the halfedge connectivity - /// \sa `Vertex_connectivity`, `Face_connectivity` - struct Halfedge_connectivity { - /// face incident to halfedge - Face_index face_; - /// vertex the halfedge points to - Vertex_index vertex_; - /// next halfedge within a face (or along a border) - Halfedge_index next_halfedge_; - /// previous halfedge within a face (or along a border) - Halfedge_index prev_halfedge_; - }; + /// This type stores the halfedge connectivity + /// \sa `Vertex_connectivity`, `Face_connectivity` + struct Halfedge_connectivity + { + /// face incident to halfedge + Face_index face_; + /// vertex the halfedge points to + Vertex_index vertex_; + /// next halfedge within a face (or along a border) + Halfedge_index next_halfedge_; + /// previous halfedge within a face (or along a border) + Halfedge_index prev_halfedge_; + }; - /// This type stores the face connectivity - /// \sa `Vertex_connectivity`, `Halfedge_connectivity` - struct Face_connectivity { - /// a halfedge that is part of the face - Halfedge_index halfedge_; - }; + /// This type stores the face connectivity + /// \sa `Vertex_connectivity`, `Halfedge_connectivity` + struct Face_connectivity + { + /// a halfedge that is part of the face + Halfedge_index halfedge_; + }; private: //------------------------------------------------------ iterator types - template - class Index_iterator - : public boost::iterator_facade, - Index_, - std::random_access_iterator_tag, - Index_ - > { - typedef boost::iterator_facade, - Index_, - std::random_access_iterator_tag, - Index_> Facade; - public: - Index_iterator() : hnd_(), mesh_(nullptr) {} - - Index_iterator(const Index_& h, const Surface_mesh* m) - : hnd_(h), mesh_(m) { - if (mesh_ && mesh_->has_garbage()) { - while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_; - } - } - - private: - friend class boost::iterator_core_access; - - void increment() { - ++hnd_; - CGAL_assertion(mesh_ != nullptr); - - if (mesh_->has_garbage()) - while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_; - } - - void decrement() { - --hnd_; - CGAL_assertion(mesh_ != nullptr); - if (mesh_->has_garbage()) - while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) --hnd_; - } - - void advance(std::ptrdiff_t n) { - CGAL_assertion(mesh_ != nullptr); - - if (mesh_->has_garbage()) { - if (n > 0) - for (std::ptrdiff_t i = 0; i < n; ++i) - increment(); - else - for (std::ptrdiff_t i = 0; i < -n; ++i) - decrement(); - } else - hnd_ += n; - } - - std::ptrdiff_t distance_to(const Index_iterator& other) const { - if (mesh_->has_garbage()) { - bool forward = (other.hnd_ > hnd_); - - std::ptrdiff_t out = 0; - Index_iterator it = *this; - while (!it.equal(other)) { - if (forward) { - ++it; - ++out; - } else { - --it; - --out; + template + class Index_iterator + : public boost::iterator_facade< Index_iterator, + Index_, + std::random_access_iterator_tag, + Index_ + > + { + typedef boost::iterator_facade< Index_iterator, + Index_, + std::random_access_iterator_tag, + Index_> Facade; + public: + Index_iterator() : hnd_(), mesh_(nullptr) {} + Index_iterator(const Index_& h, const Surface_mesh* m) + : hnd_(h), mesh_(m) { + if (mesh_ && mesh_->has_garbage()){ + while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_; } } - return out; - } + private: + friend class boost::iterator_core_access; + void increment() + { + ++hnd_; + CGAL_assertion(mesh_ != nullptr); - // else - return std::ptrdiff_t(other.hnd_) - std::ptrdiff_t(this->hnd_); - } + if(mesh_->has_garbage()) + while ( mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_; + } - bool equal(const Index_iterator& other) const { - return this->hnd_ == other.hnd_; - } + void decrement() + { + --hnd_; + CGAL_assertion(mesh_ != nullptr); + if(mesh_->has_garbage()) + while ( mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) --hnd_; + } - Index_ dereference() const { return hnd_; } + void advance(std::ptrdiff_t n) + { + CGAL_assertion(mesh_ != nullptr); - Index_ hnd_; - const Surface_mesh* mesh_; + if (mesh_->has_garbage()) + { + if (n > 0) + for (std::ptrdiff_t i = 0; i < n; ++ i) + increment(); + else + for (std::ptrdiff_t i = 0; i < -n; ++ i) + decrement(); + } + else + hnd_ += n; + } - }; + std::ptrdiff_t distance_to(const Index_iterator& other) const + { + if (mesh_->has_garbage()) + { + bool forward = (other.hnd_ > hnd_); + std::ptrdiff_t out = 0; + Index_iterator it = *this; + while (!it.equal(other)) + { + if (forward) + { + ++ it; + ++ out; + } + else + { + -- it; + -- out; + } + } + return out; + } + + // else + return std::ptrdiff_t(other.hnd_) - std::ptrdiff_t(this->hnd_); + } + + bool equal(const Index_iterator& other) const + { + return this->hnd_ == other.hnd_; + } + + Index_ dereference() const { return hnd_; } + + Index_ hnd_; + const Surface_mesh* mesh_; + + }; public: - /// \name Range Types - /// - /// Each range `R` in this section has a nested type `R::iterator`, - /// is convertible to `std::pair`, so that one can use `boost::tie()`, - /// and can be used with `BOOST_FOREACH()`, as well as with the C++11 range based for-loop. + /// \name Range Types + /// + /// Each range `R` in this section has a nested type `R::iterator`, + /// is convertible to `std::pair`, so that one can use `boost::tie()`, + /// and can be used with `BOOST_FOREACH()`, as well as with the C++11 range based for-loop. - ///@{ + ///@{ #ifndef DOXYGEN_RUNNING - typedef Index_iterator Vertex_iterator; + typedef Index_iterator Vertex_iterator; #endif - /// \brief The range over all vertex indices. - /// - /// A model of BidirectionalRange with value type `Vertex_index`. - /// \sa `vertices()` - /// \sa `Halfedge_range`, `Edge_range`, `Face_range` + /// \brief The range over all vertex indices. + /// + /// A model of BidirectionalRange with value type `Vertex_index`. + /// \sa `vertices()` + /// \sa `Halfedge_range`, `Edge_range`, `Face_range` #ifdef DOXYGEN_RUNNING - typedef unspecified_type Vertex_range; + typedef unspecified_type Vertex_range; #else - typedef Iterator_range Vertex_range; + typedef Iterator_range Vertex_range; #endif #ifndef DOXYGEN_RUNNING - typedef Index_iterator Halfedge_iterator; + typedef Index_iterator Halfedge_iterator; #endif - /// \brief The range over all halfedge indices. - /// - /// A model of BidirectionalRange with value type `Halfedge_index`. - /// \sa `halfedges()` - /// \sa `Vertex_range`, `Edge_range`, `Face_range` + /// \brief The range over all halfedge indices. + /// + /// A model of BidirectionalRange with value type `Halfedge_index`. + /// \sa `halfedges()` + /// \sa `Vertex_range`, `Edge_range`, `Face_range` #ifdef DOXYGEN_RUNNING - typedef unspecified_type Halfedge_range; + typedef unspecified_type Halfedge_range; #else - typedef Iterator_range Halfedge_range; + typedef Iterator_range Halfedge_range; #endif #ifndef DOXYGEN_RUNNING - typedef Index_iterator Edge_iterator; + typedef Index_iterator Edge_iterator; #endif - /// \brief The range over all edge indices. - /// - /// A model of BidirectionalRange with value type `Edge_index`. - /// \sa `edges()` - /// \sa `Halfedge_range`, `Vertex_range`, `Face_range` + /// \brief The range over all edge indices. + /// + /// A model of BidirectionalRange with value type `Edge_index`. + /// \sa `edges()` + /// \sa `Halfedge_range`, `Vertex_range`, `Face_range` #ifdef DOXYGEN_RUNNING - typedef unspecified_type Edge_range; + typedef unspecified_type Edge_range; #else - typedef Iterator_range Edge_range; + typedef Iterator_range Edge_range; #endif #ifndef DOXYGEN_RUNNING - typedef Index_iterator Face_iterator; + typedef Index_iterator Face_iterator; #endif - /// \brief The range over all face indices. - /// - /// A model of BidirectionalRange with value type `Face_index`. - /// \sa `faces()` - /// \sa `Vertex_range`, `Halfedge_range`, `Edge_range` -#ifdef DOXYGEN_RUNNING - typedef unspecified_type Face_range; + /// \brief The range over all face indices. + /// + /// A model of BidirectionalRange with value type `Face_index`. + /// \sa `faces()` + /// \sa `Vertex_range`, `Halfedge_range`, `Edge_range` + #ifdef DOXYGEN_RUNNING + typedef unspecified_type Face_range; #else - typedef Iterator_range Face_range; + typedef Iterator_range Face_range; #endif #ifndef DOXYGEN_RUNNING @@ -653,215 +664,229 @@ public: typedef CGAL::Vertex_around_target_iterator Vertex_around_target_iterator; typedef Iterator_range Vertex_around_target_range; - typedef CGAL::Halfedge_around_target_iterator Halfedge_around_target_iterator; + typedef CGAL::Halfedge_around_target_iterator Halfedge_around_target_iterator; typedef Iterator_range Halfedge_around_target_range; - typedef CGAL::Face_around_target_iterator Face_around_target_iterator; + typedef CGAL::Face_around_target_iterator Face_around_target_iterator; typedef Iterator_range Face_around_target_range; - typedef CGAL::Vertex_around_face_iterator Vertex_around_face_iterator; + typedef CGAL::Vertex_around_face_iterator Vertex_around_face_iterator; typedef Iterator_range Vertex_around_face_range; - typedef CGAL::Halfedge_around_face_iterator Halfedge_around_face_iterator; + typedef CGAL::Halfedge_around_face_iterator Halfedge_around_face_iterator; typedef Iterator_range Halfedge_around_face_range; - typedef CGAL::Face_around_face_iterator Face_around_face_iterator; + typedef CGAL::Face_around_face_iterator Face_around_face_iterator; typedef Iterator_range Face_around_face_range; #endif - /// @cond CGAL_BEGIN_END - /// Start iterator for vertices. - Vertex_iterator vertices_begin() const { - return Vertex_iterator(Vertex_index(0), this); - } + /// @cond CGAL_BEGIN_END + /// Start iterator for vertices. + Vertex_iterator vertices_begin() const + { + return Vertex_iterator(Vertex_index(0), this); + } - /// End iterator for vertices. - Vertex_iterator vertices_end() const { - return Vertex_iterator(Vertex_index(number_of_vertices()), this); - } - /// @endcond + /// End iterator for vertices. + Vertex_iterator vertices_end() const + { + return Vertex_iterator(Vertex_index(number_of_vertices()), this); + } + /// @endcond - /// returns the iterator range of the vertices of the mesh. - Vertex_range vertices() const { - return make_range(vertices_begin(), vertices_end()); - } + /// returns the iterator range of the vertices of the mesh. + Vertex_range vertices() const { + return make_range(vertices_begin(), vertices_end()); + } - /// @cond CGAL_BEGIN_END - /// Start iterator for halfedges. - Halfedge_iterator halfedges_begin() const { - return Halfedge_iterator(Halfedge_index(0), this); - } + /// @cond CGAL_BEGIN_END + /// Start iterator for halfedges. + Halfedge_iterator halfedges_begin() const + { + return Halfedge_iterator(Halfedge_index(0), this); + } - /// End iterator for halfedges. - Halfedge_iterator halfedges_end() const { - return Halfedge_iterator(Halfedge_index(number_of_halfedges()), this); - } - /// @endcond + /// End iterator for halfedges. + Halfedge_iterator halfedges_end() const + { + return Halfedge_iterator(Halfedge_index(number_of_halfedges()), this); + } + /// @endcond - /// returns the iterator range of the halfedges of the mesh. - Halfedge_range halfedges() const { - return make_range(halfedges_begin(), halfedges_end()); - } + /// returns the iterator range of the halfedges of the mesh. + Halfedge_range halfedges() const { + return make_range(halfedges_begin(), halfedges_end()); + } - /// @cond CGAL_BEGIN_END - /// Start iterator for edges. - Edge_iterator edges_begin() const { - return Edge_iterator(Edge_index(0), this); - } + /// @cond CGAL_BEGIN_END + /// Start iterator for edges. + Edge_iterator edges_begin() const + { + return Edge_iterator(Edge_index(0), this); + } - /// End iterator for edges. - Edge_iterator edges_end() const { - return Edge_iterator(Edge_index(number_of_edges()), this); - } - /// @endcond + /// End iterator for edges. + Edge_iterator edges_end() const + { + return Edge_iterator(Edge_index(number_of_edges()), this); + } + /// @endcond - /// returns the iterator range of the edges of the mesh. - Edge_range edges() const { - return make_range(edges_begin(), edges_end()); - } + /// returns the iterator range of the edges of the mesh. + Edge_range edges() const + { + return make_range(edges_begin(), edges_end()); + } - /// @cond CGAL_BEGIN_END - /// Start iterator for faces. - Face_iterator faces_begin() const { - return Face_iterator(Face_index(0), this); - } + /// @cond CGAL_BEGIN_END + /// Start iterator for faces. + Face_iterator faces_begin() const + { + return Face_iterator(Face_index(0), this); + } - /// End iterator for faces. - Face_iterator faces_end() const { - return Face_iterator(Face_index(number_of_faces()), this); - } - /// @endcond + /// End iterator for faces. + Face_iterator faces_end() const + { + return Face_iterator(Face_index(number_of_faces()), this); + } + /// @endcond - /// returns the iterator range of the faces of the mesh. - Face_range faces() const { - return make_range(faces_begin(), faces_end()); - } + /// returns the iterator range of the faces of the mesh. + Face_range faces() const { + return make_range(faces_begin(), faces_end()); + } #ifndef DOXYGEN_RUNNING + /// returns the iterator range for vertices around vertex `target(h)`, starting at `source(h)`. + Vertex_around_target_range vertices_around_target(Halfedge_index h) const + { + return CGAL::vertices_around_target(h,*this); + } - /// returns the iterator range for vertices around vertex `target(h)`, starting at `source(h)`. - Vertex_around_target_range vertices_around_target(Halfedge_index h) const { - return CGAL::vertices_around_target(h, *this); - } + /// returns the iterator range for incoming halfedges around vertex `target(h)`, starting at `h`. + Halfedge_around_target_range halfedges_around_target(Halfedge_index h) const + { + return CGAL::halfedges_around_target(h,*this); + } - /// returns the iterator range for incoming halfedges around vertex `target(h)`, starting at `h`. - Halfedge_around_target_range halfedges_around_target(Halfedge_index h) const { - return CGAL::halfedges_around_target(h, *this); - } + /// returns the iterator range for faces around vertex `target(h)`, starting at `face(h)`. + Face_around_target_range faces_around_target(Halfedge_index h) const + { + return CGAL::faces_around_target(h,*this); + } - /// returns the iterator range for faces around vertex `target(h)`, starting at `face(h)`. - Face_around_target_range faces_around_target(Halfedge_index h) const { - return CGAL::faces_around_target(h, *this); - } + /// returns the iterator range for vertices around face `face(h)`, starting at `target(h)`. + Vertex_around_face_range vertices_around_face(Halfedge_index h) const + { + return CGAL::vertices_around_face(h,*this); + } - /// returns the iterator range for vertices around face `face(h)`, starting at `target(h)`. - Vertex_around_face_range vertices_around_face(Halfedge_index h) const { - return CGAL::vertices_around_face(h, *this); - } + /// returns the iterator range for halfedges around face `face(h)`, starting at `h`. + Halfedge_around_face_range halfedges_around_face(Halfedge_index h) const + { + return CGAL::halfedges_around_face(h,*this); + } - /// returns the iterator range for halfedges around face `face(h)`, starting at `h`. - Halfedge_around_face_range halfedges_around_face(Halfedge_index h) const { - return CGAL::halfedges_around_face(h, *this); - } - - /// returns the iterator range for halfedges around face `face(h)`, starting at `h`. - Face_around_face_range faces_around_face(Halfedge_index h) const { - return CGAL::faces_around_face(h, *this); - } + /// returns the iterator range for halfedges around face `face(h)`, starting at `h`. + Face_around_face_range faces_around_face(Halfedge_index h) const + { + return CGAL::faces_around_face(h,*this); + } #endif - ///@} + ///@} public: #ifndef DOXYGEN_RUNNING - /// \name Circulator Types - /// - /// The following circulators enable to iterate through the elements around a face or vertex. - /// As explained in the \ref SurfaceMeshOrientation "User Manual", we can speak of a - /// *clockwise* or *counterclockwise* - /// traversal, by looking at the surface from the right side. - ///@{ + /// \name Circulator Types + /// + /// The following circulators enable to iterate through the elements around a face or vertex. + /// As explained in the \ref SurfaceMeshOrientation "User Manual", we can speak of a + /// *clockwise* or *counterclockwise* + /// traversal, by looking at the surface from the right side. + ///@{ - /// \brief This class circulates clockwise through all - /// one-ring neighbors of a vertex. - /// A model of `BidirectionalCirculator` with value type `Vertex_index`. - /// \sa `Halfedge_around_target_circulator`, `Face_around_target_circulator` + /// \brief This class circulates clockwise through all + /// one-ring neighbors of a vertex. + /// A model of `BidirectionalCirculator` with value type `Vertex_index`. + /// \sa `Halfedge_around_target_circulator`, `Face_around_target_circulator` typedef CGAL::Vertex_around_target_circulator Vertex_around_target_circulator; - /// \brief This class circulates clockwise through all incident faces of a vertex. - /// A model of `BidirectionalCirculator` with value type `Face_index`. - /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` + /// \brief This class circulates clockwise through all incident faces of a vertex. + /// A model of `BidirectionalCirculator` with value type `Face_index`. + /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` typedef CGAL::Face_around_target_circulator Face_around_target_circulator; - /// \brief This class circulates clockwise through all halfedges around a vertex that have this vertex as target. - /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. - /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` + /// \brief This class circulates clockwise through all halfedges around a vertex that have this vertex as target. + /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. + /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` typedef CGAL::Halfedge_around_target_circulator Halfedge_around_target_circulator; - /// \brief This class circulates clockwise through all halfedges around a vertex that have this vertex as source. - /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. - /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` + /// \brief This class circulates clockwise through all halfedges around a vertex that have this vertex as source. + /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. + /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` typedef CGAL::Halfedge_around_source_circulator Halfedge_around_source_circulator; - /// \brief This class circulates counterclockwise through all vertices around a face. - /// A model of `BidirectionalCirculator` with value type `Vertex_index`. + /// \brief This class circulates counterclockwise through all vertices around a face. + /// A model of `BidirectionalCirculator` with value type `Vertex_index`. - typedef CGAL::Vertex_around_face_circulator Vertex_around_face_circulator; + typedef CGAL::Vertex_around_face_circulator Vertex_around_face_circulator; - /// \brief This class circulates counterclockwise through all halfedges around a face. - /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. + /// \brief This class circulates counterclockwise through all halfedges around a face. + /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. - typedef CGAL::Halfedge_around_face_circulator Halfedge_around_face_circulator; + typedef CGAL::Halfedge_around_face_circulator Halfedge_around_face_circulator; - /// \brief This class circulates counterclockwise through all faces around a face. - /// A model of `BidirectionalCirculator` with value type `Face_index`. - /// Note that the face index is the same after `operator++`, if the neighboring faces share - /// several halfedges. + /// \brief This class circulates counterclockwise through all faces around a face. + /// A model of `BidirectionalCirculator` with value type `Face_index`. + /// Note that the face index is the same after `operator++`, if the neighboring faces share + /// several halfedges. - typedef CGAL::Face_around_face_circulator Face_around_face_circulator; + typedef CGAL::Face_around_face_circulator Face_around_face_circulator; /// @} #endif /// @cond CGAL_DOCUMENT_INTERNALS // typedefs which make it easier to write the partial specialisation of boost::graph_traits - typedef Vertex_index vertex_index; - typedef P vertex_property_type; + typedef Vertex_index vertex_index; + typedef P vertex_property_type; typedef Halfedge_index halfedge_index; - typedef Edge_index edge_index; - typedef Face_index face_index; + typedef Edge_index edge_index; + typedef Face_index face_index; - typedef Vertex_iterator vertex_iterator; - typedef Halfedge_iterator halfedge_iterator; - typedef Edge_iterator edge_iterator; - typedef Face_iterator face_iterator; - typedef CGAL::Out_edge_iterator out_edge_iterator; + typedef Vertex_iterator vertex_iterator; + typedef Halfedge_iterator halfedge_iterator; + typedef Edge_iterator edge_iterator; + typedef Face_iterator face_iterator; + typedef CGAL::Out_edge_iterator out_edge_iterator; - typedef boost::undirected_tag directed_category; + typedef boost::undirected_tag directed_category; typedef boost::disallow_parallel_edge_tag edge_parallel_category; struct traversal_category : public virtual boost::bidirectional_graph_tag, public virtual boost::vertex_list_graph_tag, - public virtual boost::edge_list_graph_tag { - }; + public virtual boost::edge_list_graph_tag + {}; typedef size_type vertices_size_type; typedef size_type halfedges_size_type; @@ -869,288 +894,297 @@ public: typedef size_type faces_size_type; typedef size_type degree_size_type; - /// @endcond + /// @endcond public: - /// \name Construction, Destruction, Assignment - /// - /// Copy constructors as well as assignment do also copy simplices marked as removed. - ///@{ + /// \name Construction, Destruction, Assignment + /// + /// Copy constructors as well as assignment do also copy simplices marked as removed. + ///@{ - /// %Default constructor. - Surface_mesh() : - vconn_(vprops_.add_property("v:connectivity")), - hconn_(hprops_.add_property("h:connectivity")), - fconn_(fprops_.add_property("f:connectivity")), - vpoint_(vprops_.add_property("v:point")), - anonymous_property_(0) {} + /// %Default constructor. + Surface_mesh() : + vconn_(vprops_.add_property("v:connectivity")), + hconn_(hprops_.add_property("h:connectivity")), + fconn_(fprops_.add_property("f:connectivity")), + vpoint_(vprops_.add_property("v:point")), + anonymous_property_(0) {} - /// Copy constructor: copies `rhs` to `*this`. Performs a deep copy of all properties. - Surface_mesh(const Surface_mesh& rhs) : - vprops_(rhs.vprops_), - hprops_(rhs.hprops_), - fprops_(rhs.fprops_), - eprops_(rhs.eprops_), - vconn_(vprops_.get_property("v:connectivity")), - vpoint_(vprops_.get_property("v:point")), - hconn_(hprops_.get_property("h:connectivity")), - fconn_(fprops_.get_property("f:connectivity")), - anonymous_property_(0) {} + /// Copy constructor: copies `rhs` to `*this`. Performs a deep copy of all properties. + Surface_mesh(const Surface_mesh& rhs) : + vprops_(rhs.vprops_), + hprops_(rhs.hprops_), + fprops_(rhs.fprops_), + eprops_(rhs.eprops_), + vconn_(vprops_.get_property("v:connectivity")), + vpoint_(vprops_.get_property("v:point")), + hconn_(hprops_.get_property("h:connectivity")), + fconn_(fprops_.get_property("f:connectivity")), + anonymous_property_(0) {} - /// Move constructor. - Surface_mesh(Surface_mesh&& sm) : - vprops_(std::move(sm.vprops_)), - hprops_(std::move(sm.hprops_)), - eprops_(std::move(sm.eprops_)), - fprops_(std::move(sm.fprops_)), - vconn_(vprops_.get_property("v:connectivity")), - vpoint_(vprops_.get_property("v:point")), - hconn_(hprops_.get_property("h:connectivity")), - fconn_(fprops_.get_property("f:connectivity")), - anonymous_property_(0) {} + /// Move constructor. + Surface_mesh(Surface_mesh&& sm) : + vprops_(std::move(sm.vprops_)), + hprops_(std::move(sm.hprops_)), + eprops_(std::move(sm.eprops_)), + fprops_(std::move(sm.fprops_)), + vconn_(vprops_.get_property("v:connectivity")), + vpoint_(vprops_.get_property("v:point")), + hconn_(hprops_.get_property("h:connectivity")), + fconn_(fprops_.get_property("f:connectivity")), + anonymous_property_(0) {} - /// assigns `rhs` to `*this`. Performs a deep copy of all properties. - Surface_mesh& operator=(const Surface_mesh& rhs); + /// assigns `rhs` to `*this`. Performs a deep copy of all properties. + Surface_mesh& operator=(const Surface_mesh& rhs); - /// move assignment - Surface_mesh& operator=(Surface_mesh&& sm) { - vprops_ = std::move(sm.vprops_); - hprops_ = std::move(sm.hprops_); - eprops_ = std::move(sm.eprops_); - fprops_ = std::move(sm.fprops_); - return *this; - } + /// move assignment + Surface_mesh& operator=(Surface_mesh&& sm) + { + vprops_ = std::move(sm.vprops_); + hprops_ = std::move(sm.hprops_); + eprops_ = std::move(sm.eprops_); + fprops_ = std::move(sm.fprops_); + return *this; + } - /// assigns `rhs` to `*this`. Does not copy custom properties. - //Surface_mesh& assign(const Surface_mesh& rhs); - - ///@} + ///@} public: - /// \name Adding Vertices, Edges, and Faces - ///@{ + /// \name Adding Vertices, Edges, and Faces + ///@{ - /// adds a new vertex, and resizes vertex properties if necessary. - Vertex_index add_vertex() { - if (recycle_) - return vprops_.emplace(); - else - return vprops_.emplace_back(); - } + /// adds a new vertex, and resizes vertex properties if necessary. + Vertex_index add_vertex() + { + if(recycle_) + return vprops_.emplace(); + else + return vprops_.emplace_back(); + } + + /// adds a new vertex, resizes vertex properties if necessary, + /// and sets the \em point property to `p`. + /// \note Several vertices may have the same point property. + Vertex_index add_vertex(const Point& p) + { + Vertex_index v = add_vertex(); + vpoint_[v] = p; + return v; + } - /// adds a new vertex, resizes vertex properties if necessary, - /// and sets the \em point property to `p`. - /// \note Several vertices may have the same point property. - Vertex_index add_vertex(const Point& p) { - Vertex_index v = add_vertex(); - vpoint_[v] = p; - return v; - } public: - /// adds a new edge, and resizes edge and halfedge properties if necessary. - Halfedge_index add_edge() { + /// adds a new edge, and resizes edge and halfedge properties if necessary. + Halfedge_index add_edge() + { - // Add properties for a new edge - if (recycle_) - eprops_.emplace(); - else - eprops_.emplace_back(); + // Add properties for a new edge + if (recycle_) + eprops_.emplace(); + else + eprops_.emplace_back(); - // Add properties for a pair of new half-edges - // The new half-edges are placed adjacently, and we return the index of the first - if (recycle_) - return hprops_.emplace_group(2); - else - return hprops_.emplace_group_back(2); - } + // Add properties for a pair of new half-edges + // The new half-edges are placed adjacently, and we return the index of the first + if (recycle_) + return hprops_.emplace_group(2); + else + return hprops_.emplace_group_back(2); + } - /// adds two opposite halfedges, and resizes edge and halfedge properties if necessary. - /// Sets the targets of the halfedge to the given vertices, but does not modify the halfedge - /// associated to the vertices. - /// \note The function does not check whether there is already an edge between the vertices. - /// \returns the halfedge with `v1` as target + /// adds two opposite halfedges, and resizes edge and halfedge properties if necessary. + /// Sets the targets of the halfedge to the given vertices, but does not modify the halfedge + /// associated to the vertices. + /// \note The function does not check whether there is already an edge between the vertices. + /// \returns the halfedge with `v1` as target - Halfedge_index add_edge(Vertex_index v0, Vertex_index v1) { - CGAL_assertion(v0 != v1); - Halfedge_index h = add_edge(); + Halfedge_index add_edge(Vertex_index v0, Vertex_index v1) + { + CGAL_assertion(v0 != v1); + Halfedge_index h = add_edge(); - set_target(h, v1); - set_target(opposite(h), v0); + set_target(h, v1); + set_target(opposite(h), v0); - return h; - } + return h; + } - /// adds a new face, and resizes face properties if necessary. - Face_index add_face() { - if (recycle_) - return fprops_.emplace(); - else - return fprops_.emplace_back(); - } + /// adds a new face, and resizes face properties if necessary. + Face_index add_face() + { + if(recycle_) + return fprops_.emplace(); + else + return fprops_.emplace_back(); + } - /// if possible, adds a new face with vertices from a range with value type `Vertex_index`. - /// The function adds halfedges between successive vertices if they are not yet indicent to halfedges, - /// or updates the connectivity of halfedges already in place. - /// Resizes halfedge, edge, and face properties if necessary. - /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. - template - Face_index add_face(const Range& vertices); + /// if possible, adds a new face with vertices from a range with value type `Vertex_index`. + /// The function adds halfedges between successive vertices if they are not yet indicent to halfedges, + /// or updates the connectivity of halfedges already in place. + /// Resizes halfedge, edge, and face properties if necessary. + /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. + template + Face_index add_face(const Range& vertices); - /// adds a new triangle connecting vertices `v0`, `v1`, `v2`. - /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. - Face_index add_face(Vertex_index v0, Vertex_index v1, Vertex_index v2) { - std::array - v = {{v0, v1, v2}}; - return add_face(v); - } + /// adds a new triangle connecting vertices `v0`, `v1`, `v2`. + /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. + Face_index add_face(Vertex_index v0, Vertex_index v1, Vertex_index v2) + { + std::array + v = {{v0, v1, v2}}; + return add_face(v); + } - /// adds a new quad connecting vertices `v0`, `v1`, `v2`, `v3`. - /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. - Face_index add_face(Vertex_index v0, Vertex_index v1, Vertex_index v2, Vertex_index v3) { - std::array - v = {{v0, v1, v2, v3}}; - return add_face(v); - } + /// adds a new quad connecting vertices `v0`, `v1`, `v2`, `v3`. + /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. + Face_index add_face(Vertex_index v0, Vertex_index v1, Vertex_index v2, Vertex_index v3) + { + std::array + v = {{v0, v1, v2, v3}}; + return add_face(v); + } - ///@} + ///@} - /// \name Low-Level Removal Functions - /// - /// Although the elements are only marked as removed - /// their connectivity and properties should not be used. - /// - /// \warning Functions in this group do not adjust any of - /// connected elements and usually leave the surface mesh in an - /// invalid state. - /// - /// - /// @{ + /// \name Low-Level Removal Functions + /// + /// Although the elements are only marked as removed + /// their connectivity and properties should not be used. + /// + /// \warning Functions in this group do not adjust any of + /// connected elements and usually leave the surface mesh in an + /// invalid state. + /// + /// + /// @{ - /// removes vertex `v` from the halfedge data structure without - /// adjusting anything. - void remove_vertex(Vertex_index v) { - // todo: confirm this behaves correctly - vprops_.erase(v); - } + /// removes vertex `v` from the halfedge data structure without + /// adjusting anything. + void remove_vertex(Vertex_index v) + { + // todo: confirm this behaves correctly + vprops_.erase(v); + } - /// removes the two halfedges corresponding to `e` from the halfedge data structure without - /// adjusting anything. - void remove_edge(Edge_index e) { - // todo: confirm this behaves correctly - eprops_.erase(e); - } + /// removes the two halfedges corresponding to `e` from the halfedge data structure without + /// adjusting anything. + void remove_edge(Edge_index e) + { + // todo: confirm this behaves correctly + eprops_.erase(e); + } - /// removes face `f` from the halfedge data structure without - /// adjusting anything. + /// removes face `f` from the halfedge data structure without + /// adjusting anything. - void remove_face(Face_index f) { - // todo: confirm this behaves correctly - fprops_.erase(f); - } + void remove_face(Face_index f) + { + // todo: confirm this behaves correctly + fprops_.erase(f); + } - ///@} + ///@} - /// \name Memory Management - /// - /// Functions to check the number of elements, the amount of space - /// allocated for elements, and to clear the structure. - ///@{ + /// \name Memory Management + /// + /// Functions to check the number of elements, the amount of space + /// allocated for elements, and to clear the structure. + ///@{ #ifndef DOXYGEN_RUNNING - /// returns the number of used and removed vertices in the mesh. - size_type num_vertices() const { return (size_type) vprops_.size(); } + /// returns the number of used and removed vertices in the mesh. + size_type num_vertices() const { return (size_type) vprops_.size(); } - /// returns the number of used and removed halfedges in the mesh. - size_type num_halfedges() const { return (size_type) hprops_.size(); } + /// returns the number of used and removed halfedges in the mesh. + size_type num_halfedges() const { return (size_type) hprops_.size(); } - /// returns the number of used and removed edges in the mesh. - size_type num_edges() const { return (size_type) eprops_.size(); } + /// returns the number of used and removed edges in the mesh. + size_type num_edges() const { return (size_type) eprops_.size(); } - /// returns the number of used and removed faces in the mesh. - size_type num_faces() const { return (size_type) fprops_.size(); } + /// returns the number of used and removed faces in the mesh. + size_type num_faces() const { return (size_type) fprops_.size(); } #endif /// returns the number of vertices in the mesh. - size_type number_of_vertices() const { + size_type number_of_vertices() const + { return vprops_.size(); } /// returns the number of halfedges in the mesh. - size_type number_of_halfedges() const { + size_type number_of_halfedges() const + { return hprops_.size(); } /// returns the number of edges in the mesh. - size_type number_of_edges() const { + size_type number_of_edges() const + { return eprops_.size(); } /// returns the number of faces in the mesh. - size_type number_of_faces() const { + size_type number_of_faces() const + { return fprops_.size(); } - /// returns `true` iff the mesh is empty, i.e., has no vertices, halfedges and faces. - bool is_empty() const { + /// returns `true` iff the mesh is empty, i.e., has no vertices, halfedges and faces. + bool is_empty() const + { return (vprops_.size() == 0 && hprops_.size() == 0 && fprops_.size() == 0); } - /// removes all vertices, halfedge, edges and faces. Collects garbage and removes all property maps added by a call to `add_property_map()` for all simplex types. - /// - /// After calling this method, the object is the same as a newly constructed object. The additional property maps are also removed and must thus be re-added if needed. - void clear() { - clear_without_removing_property_maps(); - vprops_.remove_all_properties_except({"v:connectivity", "v:point"}); - hprops_.remove_all_properties_except({"h:connectivity"}); - fprops_.remove_all_properties_except({"f:connectivity"}); - eprops_.remove_all_properties_except({}); - } + /// removes all vertices, halfedge, edges and faces. Collects garbage and removes all property maps added by a call to `add_property_map()` for all simplex types. + /// + /// After calling this method, the object is the same as a newly constructed object. The additional property maps are also removed and must thus be re-added if needed. + void clear() + { + clear_without_removing_property_maps(); + vprops_.remove_all_properties_except({"v:connectivity", "v:point"}); + hprops_.remove_all_properties_except({"h:connectivity"}); + fprops_.remove_all_properties_except({"f:connectivity"}); + eprops_.remove_all_properties_except({}); + } - void clear_without_removing_property_maps() { - vprops_.reserve(0); - hprops_.reserve(0); - eprops_.reserve(0); - fprops_.reserve(0); - } + void clear_without_removing_property_maps() + { + vprops_.reserve(0); + hprops_.reserve(0); + eprops_.reserve(0); + fprops_.reserve(0); + } - /// reserves space for vertices, halfedges, edges, faces, and their currently - /// associated properties. - void reserve(size_type nvertices, - size_type nedges, - size_type nfaces) { - vprops_.reserve(nvertices); - hprops_.reserve(2 * nedges); - eprops_.reserve(nedges); - fprops_.reserve(nfaces); - } - -// void resize(size_type nvertices, -// size_type nedges, -// size_type nfaces) { -// vprops_.resize(nvertices); -// hprops_.resize(2 * nedges); -// eprops_.resize(nedges); -// fprops_.resize(nfaces); -// } + /// reserves space for vertices, halfedges, edges, faces, and their currently + /// associated properties. + void reserve(size_type nvertices, + size_type nedges, + size_type nfaces ) + { + vprops_.reserve(nvertices); + hprops_.reserve(2*nedges); + eprops_.reserve(nedges); + fprops_.reserve(nfaces); + } /// copies the simplices from `other`, and copies values of /// properties that already exist under the same name in `*this`. /// In case `*this` has a property that does not exist in `other` /// the copied simplices get the default value of the property. - bool join(const Surface_mesh& other) { + bool join(const Surface_mesh& other) + { // Record the original sizes of the property maps const size_type nv = number_of_vertices(), nh = number_of_halfedges(), nf = number_of_faces(); @@ -1164,645 +1198,678 @@ public: // todo: the below code assumes no gaps were present in the properties! That might be okay for this situation. // translate halfedge index in vertex -> halfedge - for (size_type i = nv; i < nv + other.number_of_vertices(); i++) { + for(size_type i = nv; i < nv+other.number_of_vertices(); i++){ Vertex_index vi(i); - if (vconn_[vi].halfedge_ != null_halfedge()) { - vconn_[vi].halfedge_ = Halfedge_index(size_type(vconn_[vi].halfedge_) + nh); + if(vconn_[vi].halfedge_ != null_halfedge()){ + vconn_[vi].halfedge_ = Halfedge_index(size_type(vconn_[vi].halfedge_)+nh); } } // translate halfedge index in face -> halfedge - for (size_type i = nf; i < nf + other.number_of_faces(); i++) { + for(size_type i = nf; i < nf+other.number_of_faces(); i++){ Face_index fi(i); - if (fconn_[fi].halfedge_ != null_halfedge()) { - fconn_[fi].halfedge_ = Halfedge_index(size_type(fconn_[fi].halfedge_) + nh); + if(fconn_[fi].halfedge_ != null_halfedge()){ + fconn_[fi].halfedge_ = Halfedge_index(size_type(fconn_[fi].halfedge_)+nh); } } // translate indices in halfedge -> face, halfedge -> target, halfedge -> prev, and halfedge -> next - for (size_type i = nh; i < nh + other.number_of_halfedges(); i++) { + for(size_type i = nh; i < nh+other.number_of_halfedges(); i++){ Halfedge_index hi(i); - if (hconn_[hi].face_ != null_face()) { - hconn_[hi].face_ = Face_index(size_type(hconn_[hi].face_) + nf); + if(hconn_[hi].face_ != null_face()){ + hconn_[hi].face_ = Face_index(size_type(hconn_[hi].face_)+nf); } - if (hconn_[hi].vertex_ != null_vertex()) { - hconn_[hi].vertex_ = Vertex_index(size_type(hconn_[hi].vertex_) + nv); + if( hconn_[hi].vertex_ != null_vertex()){ + hconn_[hi].vertex_ = Vertex_index(size_type(hconn_[hi].vertex_)+nv); } - if (hconn_[hi].next_halfedge_ != null_halfedge()) { - hconn_[hi].next_halfedge_ = Halfedge_index(size_type(hconn_[hi].next_halfedge_) + nh); + if(hconn_[hi].next_halfedge_ != null_halfedge()){ + hconn_[hi].next_halfedge_ = Halfedge_index(size_type(hconn_[hi].next_halfedge_)+nh); } - if (hconn_[hi].prev_halfedge_ != null_halfedge()) { - hconn_[hi].prev_halfedge_ = Halfedge_index(size_type(hconn_[hi].prev_halfedge_) + nh); + if(hconn_[hi].prev_halfedge_ != null_halfedge()){ + hconn_[hi].prev_halfedge_ = Halfedge_index(size_type(hconn_[hi].prev_halfedge_)+nh); } } return true; } - ///@} + ///@} - /// \name Garbage Collection - /// - /// While removing elements only marks them as removed - /// garbage collection really removes them. - /// The API in this section allows to check whether - /// an element is removed, to get the number of - /// removed elements, and to collect garbage. - /// The number of elements together with the number of removed elements is - /// an upperbound on the index, and is needed - /// by algorithms that temporarily store a - /// property in a vector of the appropriate size. - /// Note however that by garbage collecting elements get new indices. - /// In case you store indices in an auxiliary data structure - /// or in a property these indices are potentially no longer - /// referring to the right elements. - /// When adding elements, by default elements that are marked as removed - /// are recycled. + /// \name Garbage Collection + /// + /// While removing elements only marks them as removed + /// garbage collection really removes them. + /// The API in this section allows to check whether + /// an element is removed, to get the number of + /// removed elements, and to collect garbage. + /// The number of elements together with the number of removed elements is + /// an upperbound on the index, and is needed + /// by algorithms that temporarily store a + /// property in a vector of the appropriate size. + /// Note however that by garbage collecting elements get new indices. + /// In case you store indices in an auxiliary data structure + /// or in a property these indices are potentially no longer + /// referring to the right elements. + /// When adding elements, by default elements that are marked as removed + /// are recycled. - ///@{ + ///@{ - /// returns the number of vertices in the mesh which are marked removed. - size_type number_of_removed_vertices() const { return vprops_.capacity() - vprops_.size(); } + /// returns the number of vertices in the mesh which are marked removed. + size_type number_of_removed_vertices() const { return vprops_.capacity() - vprops_.size(); } - /// returns the number of halfedges in the mesh which are marked removed. - size_type number_of_removed_halfedges() const { return hprops_.capacity() - hprops_.size(); } + /// returns the number of halfedges in the mesh which are marked removed. + size_type number_of_removed_halfedges() const { return hprops_.capacity() - hprops_.size(); } - /// returns the number of edges in the mesh which are marked removed. - size_type number_of_removed_edges() const { return eprops_.capacity() - eprops_.size(); } + /// returns the number of edges in the mesh which are marked removed. + size_type number_of_removed_edges() const { return eprops_.capacity() - eprops_.size(); } - /// returns the number offaces in the mesh which are marked removed. - size_type number_of_removed_faces() const { return fprops_.capacity() - fprops_.size(); } + /// returns the number offaces in the mesh which are marked removed. + size_type number_of_removed_faces() const { return fprops_.capacity() - fprops_.size(); } - /// returns whether vertex `v` is marked removed. - bool is_removed(Vertex_index v) const { - return vprops_.is_erased(v); - } - - /// returns whether halfedge `h` is marked removed. - bool is_removed(Halfedge_index h) const { - return hprops_.is_erased(h); - } - - /// returns whether edge `e` is marked removed. - bool is_removed(Edge_index e) const { - return eprops_.is_erased(e); - } - - /// returns whether face `f` is marked removed. - bool is_removed(Face_index f) const { - return fprops_.is_erased(f); - } - - /// checks if any vertices, halfedges, edges, or faces are marked as removed. - /// \sa collect_garbage - // todo: remove - bool has_garbage() const { - return number_of_removed_vertices() != 0 || - number_of_removed_edges() != 0 || - number_of_removed_halfedges() != 0 || - number_of_removed_faces() != 0; - } - - /// really removes vertices, halfedges, edges, and faces which are marked removed. - /// \sa `has_garbage()` - /// \attention By garbage collecting elements get new indices. - /// In case you store indices in an auxiliary data structure - /// or in a property these indices are potentially no longer - /// referring to the right elements. - void collect_garbage() { - // todo: this should compress the array - } - - // undocumented convenience function that allows to get old-index->new-index information - template - void collect_garbage(Visitor& visitor) { - // todo: this should compress the array and remap indices - } - - /// controls the recycling or not of simplices previously marked as removed - /// upon addition of new elements. - /// When set to `true` (default value), new elements are first picked in the garbage (if any) - /// while if set to `false` only new elements are created. - void set_recycle_garbage(bool b) { recycle_ = b; } - - /// Getter - bool does_recycle_garbage() const { return recycle_; } - - /// @cond CGAL_DOCUMENT_INTERNALS - /// removes unused memory from vectors. This shrinks the storage - /// of all properties to the minimal required size. - /// \attention Invalidates all existing references to properties. - -// void shrink_to_fit() { -// vprops_.shrink_to_fit(); -// hprops_.shrink_to_fit(); -// eprops_.shrink_to_fit(); -// fprops_.shrink_to_fit(); -// } - /// @endcond - - ///@} - - /// @cond CGAL_DOCUMENT_INTERNALS - /// - /// \name Simple Validity Checks - /// - /// Functions in this group check if the index is valid, that is between - /// `0` and the currently allocated maximum amount of the - /// elements. They do not check if an element is marked as removed. - ///@{ - - /// returns whether the index of vertex `v` is valid, that is within the current array bounds. - bool has_valid_index(Vertex_index v) const { - return ((size_type) v < number_of_vertices()); - } - - /// returns whether the index of halfedge `h` is valid, that is within the current array bounds. - bool has_valid_index(Halfedge_index h) const { - return ((size_type) h < number_of_halfedges()); - } - - /// returns whether the index of edge `e` is valid, that is within the current array bounds. - bool has_valid_index(Edge_index e) const { - return ((size_type) e < number_of_edges()); - } - - /// returns whether the index of face `f` is valid, that is within the current array bounds. - bool has_valid_index(Face_index f) const { - return ((size_type) f < number_of_faces()); - } - - /// @} - /// @endcond - - /// \name Validity Checks - /// - /// Functions in this group perform checks for structural - /// consistency of a complete surface mesh, or an individual element. - /// They are expensive and should only be used in debug configurations. - - ///@{ - - /// perform an expensive validity check on the data structure and - /// print found errors to `std::cerr` when `verbose == true`. - bool is_valid(bool verbose = false) const { - bool valid = true; - size_type vcount = 0, hcount = 0, fcount = 0; - for (Halfedge_iterator it = halfedges_begin(); it != halfedges_end(); ++it) { - ++hcount; - valid = valid && next(*it).is_valid(); - valid = valid && opposite(*it).is_valid(); - if (!valid) { - if (verbose) - std::cerr << "Integrity of halfedge " << *it << " corrupted." << std::endl; - break; - } - - valid = valid && (opposite(*it) != *it); - valid = valid && (opposite(opposite(*it)) == *it); - if (!valid) { - if (verbose) - std::cerr << "Integrity of opposite halfedge of " << *it << " corrupted." << std::endl; - break; - } - - valid = valid && (next(prev(*it)) == *it); - if (!valid) { - if (verbose) - std::cerr << "Integrity of previous halfedge of " << *it << " corrupted." << std::endl; - break; - } - - valid = valid && (prev(next(*it)) == *it); - if (!valid) { - if (verbose) - std::cerr << "Integrity of next halfedge of " << *it << " corrupted." << std::endl; - break; - } - - valid = valid && target(*it).is_valid(); - if (!valid) { - if (verbose) - std::cerr << "Integrity of vertex of halfedge " << *it << " corrupted." << std::endl; - break; - } - - valid = valid && (target(*it) == target(opposite(next(*it)))); - if (!valid) { - if (verbose) - std::cerr << "Halfedge vertex of next opposite is not the same for " << *it << "." << std::endl; - break; - } + /// returns whether vertex `v` is marked removed. + bool is_removed(Vertex_index v) const + { + return vprops_.is_erased(v); + } + /// returns whether halfedge `h` is marked removed. + bool is_removed(Halfedge_index h) const + { + return hprops_.is_erased(h); + } + /// returns whether edge `e` is marked removed. + bool is_removed(Edge_index e) const + { + return eprops_.is_erased(e); + } + /// returns whether face `f` is marked removed. + bool is_removed(Face_index f) const + { + return fprops_.is_erased(f); } - for (Vertex_iterator it = vertices_begin(); it != vertices_end(); ++it) { - ++vcount; - if (halfedge(*it).is_valid()) { - // not an isolated vertex - valid = valid && (target(halfedge(*it)) == *it); - if (!valid) { - if (verbose) - std::cerr << "Halfedge of " << *it << " is not an incoming halfedge." << std::endl; - break; + /// checks if any vertices, halfedges, edges, or faces are marked as removed. + /// \sa collect_garbage + bool has_garbage() const { + return number_of_removed_vertices() != 0 || + number_of_removed_edges() != 0 || + number_of_removed_halfedges() != 0 || + number_of_removed_faces() != 0; + } + + /// really removes vertices, halfedges, edges, and faces which are marked removed. + /// \sa `has_garbage()` + /// \attention By garbage collecting elements get new indices. + /// In case you store indices in an auxiliary data structure + /// or in a property these indices are potentially no longer + /// referring to the right elements. + void collect_garbage() { + // todo: this should compress the array + } + + //undocumented convenience function that allows to get old-index->new-index information + template + void collect_garbage(Visitor& visitor) { + // todo: this should compress the array and remap indices + } + + /// controls the recycling or not of simplices previously marked as removed + /// upon addition of new elements. + /// When set to `true` (default value), new elements are first picked in the garbage (if any) + /// while if set to `false` only new elements are created. + void set_recycle_garbage(bool b) { recycle_ = b; } + + /// Getter + bool does_recycle_garbage() const { return recycle_; } + + /// @cond CGAL_DOCUMENT_INTERNALS + /// removes unused memory from vectors. This shrinks the storage + /// of all properties to the minimal required size. + /// \attention Invalidates all existing references to properties. + + /// @endcond + + ///@} + + /// @cond CGAL_DOCUMENT_INTERNALS + /// + /// \name Simple Validity Checks + /// + /// Functions in this group check if the index is valid, that is between + /// `0` and the currently allocated maximum amount of the + /// elements. They do not check if an element is marked as removed. + ///@{ + + /// returns whether the index of vertex `v` is valid, that is within the current array bounds. + bool has_valid_index(Vertex_index v) const + { + return ((size_type)v < number_of_vertices()); + } + + /// returns whether the index of halfedge `h` is valid, that is within the current array bounds. + bool has_valid_index(Halfedge_index h) const + { + return ((size_type)h < number_of_halfedges()); + } + /// returns whether the index of edge `e` is valid, that is within the current array bounds. + bool has_valid_index(Edge_index e) const + { + return ((size_type)e < number_of_edges()); + } + /// returns whether the index of face `f` is valid, that is within the current array bounds. + bool has_valid_index(Face_index f) const + { + return ((size_type)f < number_of_faces()); + } + + /// @} + /// @endcond + + /// \name Validity Checks + /// + /// Functions in this group perform checks for structural + /// consistency of a complete surface mesh, or an individual element. + /// They are expensive and should only be used in debug configurations. + + ///@{ + + /// perform an expensive validity check on the data structure and + /// print found errors to `std::cerr` when `verbose == true`. + bool is_valid(bool verbose = false) const + { + bool valid = true; + size_type vcount = 0, hcount = 0, fcount = 0; + for(Halfedge_iterator it = halfedges_begin(); it != halfedges_end(); ++it) { + ++hcount; + valid = valid && next(*it).is_valid(); + valid = valid && opposite(*it).is_valid(); + if(!valid) { + if (verbose) + std::cerr << "Integrity of halfedge " << *it << " corrupted." << std::endl; + break; + } + + valid = valid && (opposite(*it) != *it); + valid = valid && (opposite(opposite(*it)) == *it); + if(!valid) { + if (verbose) + std::cerr << "Integrity of opposite halfedge of " << *it << " corrupted." << std::endl; + break; + } + + valid = valid && (next(prev(*it)) == *it); + if(!valid) { + if (verbose) + std::cerr << "Integrity of previous halfedge of " << *it << " corrupted." << std::endl; + break; + } + + valid = valid && (prev(next(*it)) == *it); + if(!valid) { + if (verbose) + std::cerr << "Integrity of next halfedge of " << *it << " corrupted." << std::endl; + break; + } + + valid = valid && target(*it).is_valid(); + if(!valid) { + if (verbose) + std::cerr << "Integrity of vertex of halfedge " << *it << " corrupted." << std::endl; + break; + } + + valid = valid && (target(*it) == target(opposite(next(*it)))); + if(!valid) { + if (verbose) + std::cerr << "Halfedge vertex of next opposite is not the same for " << *it << "." << std::endl; + break; + } } + + for(Vertex_iterator it = vertices_begin(); it != vertices_end(); ++it) { + ++vcount; + if(halfedge(*it).is_valid()) { + // not an isolated vertex + valid = valid && (target(halfedge(*it)) == *it); + if(!valid) { + if (verbose) + std::cerr << "Halfedge of " << *it << " is not an incoming halfedge." << std::endl; + break; + } + } + } + for(Face_iterator it = faces_begin(); it != faces_end(); ++it) { + ++fcount; + } + + valid = valid && (vcount == number_of_vertices()); + if(!valid && verbose){ + std::cerr << "#vertices: iterated: " << vcount << " vs number_of_vertices(): " << number_of_vertices()<< std::endl; + } + + valid = valid && (hcount == number_of_halfedges()); + if(!valid && verbose){ + std::cerr << "#halfedges: iterated: " << hcount << " vs number_of_halfedges(): " << number_of_halfedges()<< std::endl; + } + + valid = valid && (fcount == number_of_faces()); + if(!valid && verbose){ + std::cerr << "#faces: iterated: " << fcount << " vs number_of_faces(): " << number_of_faces()<< std::endl; + } + + return valid; + } + + /// performs a validity check on a single vertex. + bool is_valid(Vertex_index v, + bool verbose = false) const + { + Verbose_ostream verr(verbose); + + if(!has_valid_index(v)) + { + verr << "Vertex has invalid index: " << (size_type)v << std::endl; + return false; + } + + Halfedge_index h = vconn_[v].halfedge_; + if(h != null_halfedge() && (!has_valid_index(h) || is_removed(h))) { + verr << "Vertex connectivity halfedge error: Vertex " << (size_type)v + << " with " << (size_type)h << std::endl; + return false; + } + return true; + } + + /// performs a validity check on a single halfedge. + bool is_valid(Halfedge_index h, + bool verbose = false) const + { + Verbose_ostream verr(verbose); + + if(!has_valid_index(h)) + { + verr << "Halfedge has invalid index: " << (size_type)h << std::endl; + return false; + } + + Face_index f = hconn_[h].face_; + Vertex_index v = hconn_[h].vertex_; + Halfedge_index hn = hconn_[h].next_halfedge_; + Halfedge_index hp = hconn_[h].prev_halfedge_; + + bool valid = true; + // don't validate the face if this is a border halfedge + if(!is_border(h)) { + if(!has_valid_index(f) || is_removed(f)) { + verr << "Halfedge connectivity error: Face " + << (!has_valid_index(f) ? "invalid" : "removed") + << " in " << (size_type)h << std::endl; + valid = false; + } + } + + if(!has_valid_index(v) || is_removed(v)) { + verr << "Halfedge connectivity error: Vertex " + << (!has_valid_index(v) ? "invalid" : "removed") + << " in " << (size_type)h << std::endl; + valid = false; + } + + if(!has_valid_index(hn) || is_removed(hn)) { + verr << "Halfedge connectivity error: hnext " + << (!has_valid_index(hn) ? "invalid" : "removed") + << " in " << (size_type)h << std::endl; + valid = false; + } + if(!has_valid_index(hp) || is_removed(hp)) { + verr << "Halfedge connectivity error: hprev " + << (!has_valid_index(hp) ? "invalid" : "removed") + << " in " << (size_type)h << std::endl; + valid = false; + } + return valid; + } + + + /// performs a validity check on a single edge. + bool is_valid(Edge_index e, + bool verbose = false) const + { + Verbose_ostream verr(verbose); + + if(!has_valid_index(e)) + { + verr << "Edge has invalid index: " << (size_type)e << std::endl; + return false; + } + + Halfedge_index h = halfedge(e); + return is_valid(h, verbose) && is_valid(opposite(h), verbose); + } + + + /// performs a validity check on a single face. + bool is_valid(Face_index f, + bool verbose = false) const + { + Verbose_ostream verr(verbose); + + if(!has_valid_index(f)) + { + verr << "Face has invalid index: " << (size_type)f << std::endl; + return false; + } + + Halfedge_index h = fconn_[f].halfedge_; + if(!has_valid_index(h) || is_removed(h)) { + verr << "Face connectivity halfedge error: Face " << (size_type)f + << " with " << (size_type)h << std::endl; + return false; + } + return true; + } + + ///@} + + + + /// \name Low-Level Connectivity + ///@{ + + /// returns the vertex the halfedge `h` points to. + Vertex_index target(Halfedge_index h) const + { + return hconn_[h].vertex_; + } + + /// sets the vertex the halfedge `h` points to to `v`. + void set_target(Halfedge_index h, Vertex_index v) + { + hconn_[h].vertex_ = v; + } + + /// returns the face incident to halfedge `h`. + Face_index face(Halfedge_index h) const + { + return hconn_[h].face_; + } + + /// sets the incident face to halfedge `h` to `f`. + void set_face(Halfedge_index h, Face_index f) + { + hconn_[h].face_ = f; + } + + /// returns the next halfedge within the incident face. + Halfedge_index next(Halfedge_index h) const + { + return hconn_[h].next_halfedge_; + } + + /// returns the previous halfedge within the incident face. + Halfedge_index prev(Halfedge_index h) const + { + return hconn_[h].prev_halfedge_; + } + + /// @cond CGAL_DOCUMENT_INTERNALS + // sets the next halfedge of `h` within the face to `nh`. + void set_next_only(Halfedge_index h, Halfedge_index nh) + { + hconn_[h].next_halfedge_ = nh; + } + + // sets previous halfedge of `h` to `nh`. + void set_prev_only(Halfedge_index h, Halfedge_index nh) + { + if(h != null_halfedge()){ + hconn_[h].prev_halfedge_ = nh; } } - for (Face_iterator it = faces_begin(); it != faces_end(); ++it) { - ++fcount; + /// @endcond + + /// sets the next halfedge of `h` within the face to `nh` and + /// the previous halfedge of `nh` to `h`. + void set_next(Halfedge_index h, Halfedge_index nh) + { + set_next_only(h, nh); + set_prev_only(nh, h); } - valid = valid && (vcount == number_of_vertices()); - if (!valid && verbose) { - std::cerr << "#vertices: iterated: " << vcount << " vs number_of_vertices(): " << number_of_vertices() - << std::endl; + /// returns an incoming halfedge of vertex `v`. + /// If `v` is a border vertex this will be a border halfedge. + /// \invariant `target(halfedge(v)) == v` + Halfedge_index halfedge(Vertex_index v) const + { + return vconn_[v].halfedge_; } - valid = valid && (hcount == number_of_halfedges()); - if (!valid && verbose) { - std::cerr << "#halfedges: iterated: " << hcount << " vs number_of_halfedges(): " << number_of_halfedges() - << std::endl; + /// sets the incoming halfedge of vertex `v` to `h`. + void set_halfedge(Vertex_index v, Halfedge_index h) + { + vconn_[v].halfedge_ = h; } - valid = valid && (fcount == number_of_faces()); - if (!valid && verbose) { - std::cerr << "#faces: iterated: " << fcount << " vs number_of_faces(): " << number_of_faces() << std::endl; + + /// returns a halfedge of face `f`. + Halfedge_index halfedge(Face_index f) const + { + return fconn_[f].halfedge_; } - return valid; - } - - /// performs a validity check on a single vertex. - bool is_valid(Vertex_index v, - bool verbose = false) const { - Verbose_ostream verr(verbose); - - if (!has_valid_index(v)) { - verr << "Vertex has invalid index: " << (size_type) v << std::endl; - return false; + /// sets the halfedge of face `f` to `h`. + void set_halfedge(Face_index f, Halfedge_index h) + { + fconn_[f].halfedge_ = h; } - Halfedge_index h = vconn_[v].halfedge_; - if (h != null_halfedge() && (!has_valid_index(h) || is_removed(h))) { - verr << "Vertex connectivity halfedge error: Vertex " << (size_type) v - << " with " << (size_type) h << std::endl; - return false; - } - return true; - } - - /// performs a validity check on a single halfedge. - bool is_valid(Halfedge_index h, - bool verbose = false) const { - Verbose_ostream verr(verbose); - - if (!has_valid_index(h)) { - verr << "Halfedge has invalid index: " << (size_type) h << std::endl; - return false; + /// returns the opposite halfedge of `h`. Note that there is no function `set_opposite()`. + Halfedge_index opposite(Halfedge_index h) const + { + return Halfedge_index(((size_type)h & 1) ? (size_type)h-1 : (size_type)h+1); } - Face_index f = hconn_[h].face_; - Vertex_index v = hconn_[h].vertex_; - Halfedge_index hn = hconn_[h].next_halfedge_; - Halfedge_index hp = hconn_[h].prev_halfedge_; + ///@} - bool valid = true; - // don't validate the face if this is a border halfedge - if (!is_border(h)) { - if (!has_valid_index(f) || is_removed(f)) { - verr << "Halfedge connectivity error: Face " - << (!has_valid_index(f) ? "invalid" : "removed") - << " in " << (size_type) h << std::endl; - valid = false; - } + /// \name Low-Level Connectivity Convenience Functions + ///@{ + + /// returns the vertex the halfedge `h` emanates from. + Vertex_index source(Halfedge_index h) const + { + return target(opposite(h)); } - if (!has_valid_index(v) || is_removed(v)) { - verr << "Halfedge connectivity error: Vertex " - << (!has_valid_index(v) ? "invalid" : "removed") - << " in " << (size_type) h << std::endl; - valid = false; + /// returns `opposite(next(h))`, that is the next halfedge \ref SurfaceMeshOrientation + /// "clockwise" around the target vertex of `h`. + Halfedge_index next_around_target(Halfedge_index h) const + { + return opposite(next(h)); } - if (!has_valid_index(hn) || is_removed(hn)) { - verr << "Halfedge connectivity error: hnext " - << (!has_valid_index(hn) ? "invalid" : "removed") - << " in " << (size_type) h << std::endl; - valid = false; - } - if (!has_valid_index(hp) || is_removed(hp)) { - verr << "Halfedge connectivity error: hprev " - << (!has_valid_index(hp) ? "invalid" : "removed") - << " in " << (size_type) h << std::endl; - valid = false; - } - return valid; - } - - - /// performs a validity check on a single edge. - bool is_valid(Edge_index e, - bool verbose = false) const { - Verbose_ostream verr(verbose); - - if (!has_valid_index(e)) { - verr << "Edge has invalid index: " << (size_type) e << std::endl; - return false; + /// returns `prev(opposite(h))`, that is the previous halfedge \ref SurfaceMeshOrientation + /// "clockwise" around the target vertex of `h`. + Halfedge_index prev_around_target(Halfedge_index h) const + { + return prev(opposite(h)); } - Halfedge_index h = halfedge(e); - return is_valid(h, verbose) && is_valid(opposite(h), verbose); - } - - - /// performs a validity check on a single face. - bool is_valid(Face_index f, - bool verbose = false) const { - Verbose_ostream verr(verbose); - - if (!has_valid_index(f)) { - verr << "Face has invalid index: " << (size_type) f << std::endl; - return false; + /// returns `next(opposite(h))`, that is the next halfedge \ref SurfaceMeshOrientation + /// "clockwise" around the source vertex of `h`. + Halfedge_index next_around_source(Halfedge_index h) const + { + return next(opposite(h)); } - Halfedge_index h = fconn_[f].halfedge_; - if (!has_valid_index(h) || is_removed(h)) { - verr << "Face connectivity halfedge error: Face " << (size_type) f - << " with " << (size_type) h << std::endl; - return false; + /// returns `opposite(prev(h))`, that is the previous halfedge \ref SurfaceMeshOrientation + /// "clockwise" around the source vertex of `h`. + Halfedge_index prev_around_source(Halfedge_index h) const + { + return opposite(prev(h)); } - return true; - } - ///@} - - - - /// \name Low-Level Connectivity - ///@{ - - /// returns the vertex the halfedge `h` points to. - Vertex_index target(Halfedge_index h) const { - return hconn_[h].vertex_; - } - - /// sets the vertex the halfedge `h` points to to `v`. - void set_target(Halfedge_index h, Vertex_index v) { - hconn_[h].vertex_ = v; - } - - /// returns the face incident to halfedge `h`. - Face_index face(Halfedge_index h) const { - return hconn_[h].face_; - } - - /// sets the incident face to halfedge `h` to `f`. - void set_face(Halfedge_index h, Face_index f) { - hconn_[h].face_ = f; - } - - /// returns the next halfedge within the incident face. - Halfedge_index next(Halfedge_index h) const { - return hconn_[h].next_halfedge_; - } - - /// returns the previous halfedge within the incident face. - Halfedge_index prev(Halfedge_index h) const { - return hconn_[h].prev_halfedge_; - } - - /// @cond CGAL_DOCUMENT_INTERNALS - // sets the next halfedge of `h` within the face to `nh`. - void set_next_only(Halfedge_index h, Halfedge_index nh) { - hconn_[h].next_halfedge_ = nh; - } - - // sets previous halfedge of `h` to `nh`. - void set_prev_only(Halfedge_index h, Halfedge_index nh) { - if (h != null_halfedge()) { - hconn_[h].prev_halfedge_ = nh; + /// returns the i'th vertex of edge `e`, for `i=0` or `1`. + Vertex_index vertex(Edge_index e, unsigned int i) const + { + CGAL_assertion(i<=1); + return target(halfedge(e, i)); } - } - /// @endcond - /// sets the next halfedge of `h` within the face to `nh` and - /// the previous halfedge of `nh` to `h`. - void set_next(Halfedge_index h, Halfedge_index nh) { - set_next_only(h, nh); - set_prev_only(nh, h); - } + /// finds a halfedge between two vertices. Returns a default constructed + /// `Halfedge_index`, if `source` and `target` are not connected. + Halfedge_index halfedge(Vertex_index source, Vertex_index target) const; - /// returns an incoming halfedge of vertex `v`. - /// If `v` is a border vertex this will be a border halfedge. - /// \invariant `target(halfedge(v)) == v` - Halfedge_index halfedge(Vertex_index v) const { - return vconn_[v].halfedge_; - } - - /// sets the incoming halfedge of vertex `v` to `h`. - void set_halfedge(Vertex_index v, Halfedge_index h) { - vconn_[v].halfedge_ = h; - } + ///@} - /// returns a halfedge of face `f`. - Halfedge_index halfedge(Face_index f) const { - return fconn_[f].halfedge_; - } + /// \name Switching between Halfedges and Edges + ///@{ - /// sets the halfedge of face `f` to `h`. - void set_halfedge(Face_index f, Halfedge_index h) { - fconn_[f].halfedge_ = h; - } - - /// returns the opposite halfedge of `h`. Note that there is no function `set_opposite()`. - Halfedge_index opposite(Halfedge_index h) const { - return Halfedge_index(((size_type) h & 1) ? (size_type) h - 1 : (size_type) h + 1); - } - - ///@} - - /// \name Low-Level Connectivity Convenience Functions - ///@{ - - /// returns the vertex the halfedge `h` emanates from. - Vertex_index source(Halfedge_index h) const { - return target(opposite(h)); - } - - /// returns `opposite(next(h))`, that is the next halfedge \ref SurfaceMeshOrientation - /// "clockwise" around the target vertex of `h`. - Halfedge_index next_around_target(Halfedge_index h) const { - return opposite(next(h)); - } - - /// returns `prev(opposite(h))`, that is the previous halfedge \ref SurfaceMeshOrientation - /// "clockwise" around the target vertex of `h`. - Halfedge_index prev_around_target(Halfedge_index h) const { - return prev(opposite(h)); - } - - /// returns `next(opposite(h))`, that is the next halfedge \ref SurfaceMeshOrientation - /// "clockwise" around the source vertex of `h`. - Halfedge_index next_around_source(Halfedge_index h) const { - return next(opposite(h)); - } - - /// returns `opposite(prev(h))`, that is the previous halfedge \ref SurfaceMeshOrientation - /// "clockwise" around the source vertex of `h`. - Halfedge_index prev_around_source(Halfedge_index h) const { - return opposite(prev(h)); - } - - /// returns the i'th vertex of edge `e`, for `i=0` or `1`. - Vertex_index vertex(Edge_index e, unsigned int i) const { - CGAL_assertion(i <= 1); - return target(halfedge(e, i)); - } - - /// finds a halfedge between two vertices. Returns a default constructed - /// `Halfedge_index`, if `source` and `target` are not connected. - Halfedge_index halfedge(Vertex_index source, Vertex_index target) const; - - ///@} - - - /// \name Switching between Halfedges and Edges - ///@{ - - /// returns the edge that contains halfedge `h` as one of its two halfedges. - Edge_index edge(Halfedge_index h) const { - return Edge_index(h); - } - - /// returns the halfedge corresponding to the edge `e`. - Halfedge_index halfedge(Edge_index e) const { - return Halfedge_index(e.halfedge()); - } - - /// returns the i'th halfedge of edge `e`, for `i=0` or `1`. - Halfedge_index halfedge(Edge_index e, unsigned int i) const { - CGAL_assertion(i <= 1); - return Halfedge_index(((size_type) e << 1) + i); - } - - ///@} - - - /// \name Degree Functions - ///@{ - - /// returns the number of incident halfedges of vertex `v`. - size_type degree(Vertex_index v) const; - - /// returns the number of incident halfedges of face `f`. - size_type degree(Face_index f) const; - - ///@} - - - - /// \name Borders - /// - /// A halfedge, or edge is on the border of a surface mesh - /// if it is incident to a `null_face()`. A vertex is on a border - /// if it is isolated or incident to a border halfedge. While for a halfedge and - /// edge this is a constant time operation, for a vertex it means - /// to look at all incident halfedges. If algorithms operating on a - /// surface mesh maintain that the halfedge associated to a border vertex is - /// a border halfedge, this is a constant time operation too. - /// This section provides functions to check if an element is on a - /// border and to change the halfedge associated to a border vertex. - ///@{ - - /// returns whether `v` is a border vertex. - /// \cgalAdvancedBegin - /// With the default value for - /// `check_all_incident_halfedges` the function iteratates over the incident halfedges. - /// With `check_all_incident_halfedges == false` the function returns `true`, if the incident - /// halfedge associated to vertex `v` is a border halfedge, or if the vertex is isolated. - /// \cgalAdvancedEnd - /// \attention If the data contained in the `Surface_mesh` is not a 2-manifold, then - /// this operation is not guaranteed to return the right result. - bool is_border(Vertex_index v, bool check_all_incident_halfedges = true) const { - Halfedge_index h(halfedge(v)); - if (h == null_halfedge()) { - return true; + /// returns the edge that contains halfedge `h` as one of its two halfedges. + Edge_index edge(Halfedge_index h) const + { + return Edge_index(h); } - if (check_all_incident_halfedges) { - Halfedge_around_target_circulator hatc(h, *this), done(hatc); - do { - if (is_border(*hatc)) { + + /// returns the halfedge corresponding to the edge `e`. + Halfedge_index halfedge(Edge_index e) const + { + return Halfedge_index(e.halfedge()); + } + + /// returns the i'th halfedge of edge `e`, for `i=0` or `1`. + Halfedge_index halfedge(Edge_index e, unsigned int i) const + { + CGAL_assertion(i<=1); + return Halfedge_index(((size_type)e << 1) + i); + } + + ///@} + + + /// \name Degree Functions + ///@{ + + /// returns the number of incident halfedges of vertex `v`. + size_type degree(Vertex_index v) const; + + /// returns the number of incident halfedges of face `f`. + size_type degree(Face_index f) const; + + ///@} + + + + /// \name Borders + /// + /// A halfedge, or edge is on the border of a surface mesh + /// if it is incident to a `null_face()`. A vertex is on a border + /// if it is isolated or incident to a border halfedge. While for a halfedge and + /// edge this is a constant time operation, for a vertex it means + /// to look at all incident halfedges. If algorithms operating on a + /// surface mesh maintain that the halfedge associated to a border vertex is + /// a border halfedge, this is a constant time operation too. + /// This section provides functions to check if an element is on a + /// border and to change the halfedge associated to a border vertex. + ///@{ + + /// returns whether `v` is a border vertex. + /// \cgalAdvancedBegin + /// With the default value for + /// `check_all_incident_halfedges` the function iteratates over the incident halfedges. + /// With `check_all_incident_halfedges == false` the function returns `true`, if the incident + /// halfedge associated to vertex `v` is a border halfedge, or if the vertex is isolated. + /// \cgalAdvancedEnd + /// \attention If the data contained in the `Surface_mesh` is not a 2-manifold, then + /// this operation is not guaranteed to return the right result. + bool is_border(Vertex_index v, bool check_all_incident_halfedges = true) const + { + Halfedge_index h(halfedge(v)); + if (h == null_halfedge()){ return true; } - } while (++hatc != done); - return false; + if(check_all_incident_halfedges){ + Halfedge_around_target_circulator hatc(h,*this), done(hatc); + do { + if(is_border(*hatc)){ + return true; + } + }while(++hatc != done); + return false; + } + return is_border(h); } - return is_border(h); - } - /// returns whether `h` is a border halfege, that is if its incident face is `sm.null_face()`. - bool is_border(Halfedge_index h) const { - return !face(h).is_valid(); - } + /// returns whether `h` is a border halfege, that is if its incident face is `sm.null_face()`. + bool is_border(Halfedge_index h) const + { + return !face(h).is_valid(); + } - /// returns whether `e` is a border edge, i.e., if any - /// of its two halfedges is a border halfedge. - bool is_border(Edge_index e) const { - return is_border(e.halfedge()) || is_border(opposite(e.halfedge())); - } + /// returns whether `e` is a border edge, i.e., if any + /// of its two halfedges is a border halfedge. + bool is_border(Edge_index e) const + { + return is_border(e.halfedge()) || is_border(opposite(e.halfedge())); + } /// iterates over the incident halfedges and sets the incident halfedge /// associated to vertex `v` to a border halfedge and returns `true` if it exists. - bool set_vertex_halfedge_to_border_halfedge(Vertex_index v) { - if (halfedge(v) == null_halfedge()) { + bool set_vertex_halfedge_to_border_halfedge(Vertex_index v) + { + if(halfedge(v) == null_halfedge()){ return false; } - Halfedge_around_target_circulator hatc(halfedge(v), *this), done(hatc); + Halfedge_around_target_circulator hatc(halfedge(v),*this), done(hatc); do { - if (is_border(*hatc)) { - set_halfedge(v, *hatc); + if(is_border(*hatc)){ + set_halfedge(v,*hatc); return true; } - } while (++hatc != done); + }while(++hatc != done); return false; } /// applies `set_vertex_halfedge_to_border_halfedge(Vertex_index)` on all vertices /// around the face associated to `h`. - void set_vertex_halfedge_to_border_halfedge(Halfedge_index h) { - if (is_border(h)) { - Halfedge_around_face_circulator hafc(h, *this), done(hafc); + void set_vertex_halfedge_to_border_halfedge(Halfedge_index h) + { + if(is_border(h)){ + Halfedge_around_face_circulator hafc(h,*this),done(hafc); do { - set_halfedge(target(*hafc), *hafc); - } while (++hafc != done); + set_halfedge(target(*hafc),*hafc); + }while(++hafc != done); } else { - Vertex_around_face_circulator vafc(h, *this), done(vafc); + Vertex_around_face_circulator vafc(h,*this),done(vafc); do { set_vertex_halfedge_to_border_halfedge(*vafc); - } while (++vafc != done); + }while(++vafc != done); } } /// applies `set_vertex_halfedge_to_border_halfedge(Vertex_index)` on all vertices /// of the surface mesh. - void set_vertex_halfedge_to_border_halfedge() { - for (Halfedge_index h: halfedges()) { - if (is_border(h)) { - set_halfedge(target(h), h); - } + void set_vertex_halfedge_to_border_halfedge() + { + for(Halfedge_index h : halfedges()){ + if(is_border(h)){ + set_halfedge(target(h),h); + } } } - /// returns whether `v` is isolated, i.e., incident to `Surface_mesh::null_halfedge()`. - bool is_isolated(Vertex_index v) const { - return !halfedge(v).is_valid(); - } + /// returns whether `v` is isolated, i.e., incident to `Surface_mesh::null_halfedge()`. + bool is_isolated(Vertex_index v) const + { + return !halfedge(v).is_valid(); + } - ///@} + ///@} -public: //--------------------------------------------------- property handling +private: //--------------------------------------------------- property handling template Property_container& get_property_container() { @@ -1829,17 +1896,17 @@ public: //--------------------------------------------------- property handling } -public: + public: - /*! \name Property Handling + /*! \name Property Handling - A `Properties::Property_map` allows to associate properties of type `T` to a vertex, halfdge, edge, or face index type I. - Properties can be added, and looked up with a string, and they can be removed at runtime. - The \em point property of type `P` is associated to the string "v:point". + A `Properties::Property_map` allows to associate properties of type `T` to a vertex, halfdge, edge, or face index type I. + Properties can be added, and looked up with a string, and they can be removed at runtime. + The \em point property of type `P` is associated to the string "v:point". - */ - ///@{ + */ + ///@{ /// Model of `LvaluePropertyMap` with `I` as key type and `T` as value type, where `I` /// is either a vertex, halfedge, edge, or face index type. @@ -1852,247 +1919,256 @@ public: #endif - // todo: I can't see a good reason for these two functions to exist separately, but do almost the same thing + // todo: I can't see a good reason for these two functions to exist separately, but do almost the same thing - /// adds a property map named `name` with value type `T` and default `t` - /// for index type `I`. Returns the property map together with a Boolean - /// that is `true` if a new map was created. In case it already exists - /// the existing map together with `false` is returned. - template - std::pair, bool> - add_property_map(std::string name = std::string(), const T t = T()) { - if (name.empty()) { - // todo: maybe this should be done by the property container itself? - std::ostringstream oss; - oss << "anonymous-property-" << anonymous_property_++; - name = std::string(oss.str()); + /// adds a property map named `name` with value type `T` and default `t` + /// for index type `I`. Returns the property map together with a Boolean + /// that is `true` if a new map was created. In case it already exists + /// the existing map together with `false` is returned. + template + std::pair, bool> + add_property_map(std::string name=std::string(), const T t=T()) { + if(name.empty()){ + // todo: maybe this should be done by the property container itself? + std::ostringstream oss; + oss << "anonymous-property-" << anonymous_property_++; + name = std::string(oss.str()); + } + // todo: double check this is working + auto [array, created] = + const_cast*>(this)->get_property_container().template get_or_add_property(name, t); + return {{array.get()}, created}; } - // todo: double check this is working - auto [array, created] = - const_cast*>(this)->get_property_container().template get_or_add_property(name, t); - return {{array.get()}, created}; - } - /// returns a property map named `name` with key type `I` and value type `T`, - /// and a Boolean that is `true` if the property was created. - template - std::pair, bool> - property_map(const std::string& name) const { - auto [array, created] = - const_cast*>(this)->get_property_container().template get_or_add_property(name); - return {{array.get()}, created}; - } + /// returns a property map named `name` with key type `I` and value type `T`, + /// and a Boolean that is `true` if the property was created. + template + std::pair, bool> + property_map(const std::string& name) const { + auto [array, created] = + const_cast*>(this)->get_property_container().template get_or_add_property(name); + return {{array.get()}, created}; + } - /// returns a property map named `name` with key type `I` and value type `T`, - /// if such a property map exists - template - std::optional> - get_property_map(const std::string& name) { - auto maybe_property_map = get_property_container().template get_property_if_exists(name); - if (!maybe_property_map) return {}; - else return {{maybe_property_map.value()}}; - } + /// returns a property map named `name` with key type `I` and value type `T`, + /// if such a property map exists + template + std::optional> + get_property_map(const std::string& name) { + auto maybe_property_map = get_property_container().template get_property_if_exists(name); + if (!maybe_property_map) return {}; + else return {{maybe_property_map.value()}}; + } - template - std::optional> - get_property_map(const std::string& name) const { - auto maybe_property_map = const_cast*>(this)->get_property_container().template get_property_if_exists(name); - if (!maybe_property_map) return {}; - else return {{maybe_property_map.value()}}; - } + template + std::optional> + get_property_map(const std::string& name) const { + auto maybe_property_map = const_cast*>(this)->get_property_container().template get_property_if_exists(name); + if (!maybe_property_map) return {}; + else return {{maybe_property_map.value()}}; + } - /// removes property map `p`. The memory allocated for that property map is - /// freed. - template - void remove_property_map(Property_map p) { - // Maybe this could be replaced with removal by name? - const_cast*>(this)->get_property_container().template remove_property(p.array()); - } + /// removes property map `p`. The memory allocated for that property map is + /// freed. + template + void remove_property_map(Property_map p) { + // Maybe this could be replaced with removal by name? + const_cast*>(this)->get_property_container().template remove_property(p.array()); + } - /// @cond CGAL_DOCUMENT_INTERNALS - /// returns the std::type_info of the value type of the - /// property identified by `name`. `typeid(void)` if `name` - /// does not identify any property. - /// - /// @tparam I The key type of the property. + /// @cond CGAL_DOCUMENT_INTERNALS + /// returns the std::type_info of the value type of the + /// property identified by `name`. `typeid(void)` if `name` + /// does not identify any property. + /// + /// @tparam I The key type of the property. - template - const std::type_info& property_type(const std::string& name) { - return get_property_container().property_type(name); - } - /// @endcond + template + const std::type_info& property_type(const std::string& name) + { + return get_property_container().property_type(name); + } + /// @endcond - /// returns a vector with all strings that describe properties with the key type `I`. - /// @tparam I The key type of the properties. - template - std::vector properties() const { - return get_property_container().properties(); - } + /// returns a vector with all strings that describe properties with the key type `I`. + /// @tparam I The key type of the properties. + template + std::vector properties() const + { + return get_property_container().properties(); + } - /// returns the property for the string "v:point". - // todo: shouldn't this return a const pmap? - // In the original version, there was no difference between const & non-const maps - Property_array& - points() const { return vpoint_; } + /// returns the property for the string "v:point". + // todo: shouldn't this return a const pmap? + // In the original version, there was no difference between const & non-const maps + Property_array& + points() const { return vpoint_; } - Property_array& - points() { return vpoint_; } + Property_array& + points() { return vpoint_; } - /// returns the point associated to vertex `v`. - const Point& - point(Vertex_index v) const { return vpoint_[v]; } + /// returns the point associated to vertex `v`. + const Point& + point(Vertex_index v) const { return vpoint_[v]; } - /// returns the point associated to vertex `v`. - Point& - point(Vertex_index v) { return vpoint_[v]; } + /// returns the point associated to vertex `v`. + Point& + point(Vertex_index v) { return vpoint_[v]; } - /// @cond CGAL_DOCUMENT_INTERNALS - /// prints property statistics to the stream `out`. The output is human-readable but - /// not machine-friendly. - /// - void property_stats(std::ostream& out = std::cout) const; - /// @endcond - ///@} + /// @cond CGAL_DOCUMENT_INTERNALS + /// prints property statistics to the stream `out`. The output is human-readable but + /// not machine-friendly. + /// + void property_stats(std::ostream& out = std::cout) const; + /// @endcond + ///@} - /// \name Null Elements - ///@{ + /// \name Null Elements + ///@{ /// returns `Vertex_index(std::numeric_limits::%max())`. - static Vertex_index null_vertex() { + static Vertex_index null_vertex() + { return vertex_index((std::numeric_limits::max)()); } /// returns `Edge_index(std::numeric_limits::%max())`. - static Edge_index null_edge() { + static Edge_index null_edge() + { return edge_index((std::numeric_limits::max)()); } - /// returns `Halfedge_index(std::numeric_limits::%max())`. - static Halfedge_index null_halfedge() { + static Halfedge_index null_halfedge() + { return halfedge_index((std::numeric_limits::max)()); } - /// returns `Face_index(std::numeric_limits::%max())`. - static Face_index null_face() { + static Face_index null_face() + { return face_index((std::numeric_limits::max)()); } /// @} #if defined(CGAL_SURFACE_MESH_TEST_SUITE) - - std::vector vertex_freelist() const { + std::vector vertex_freelist() const + { return vprops_.inactive_list(); } - std::vector face_freelist() const { + std::vector face_freelist() const + { return fprops_.inactive_list(); } - std::vector edge_freelist() const { + std::vector edge_freelist() const + { return eprops_.inactive_list(); } - #endif private: //--------------------------------------------------- helper functions - /// make sure that the incoming halfedge of vertex v is a border halfedge - /// if `v` is a border vertex. - void adjust_incoming_halfedge(Vertex_index v); + /// make sure that the incoming halfedge of vertex v is a border halfedge + /// if `v` is a border vertex. + void adjust_incoming_halfedge(Vertex_index v); private: //------------------------------------------------------- private data - Property_container vprops_; - Property_container hprops_; - Property_container eprops_; - Property_container fprops_; + Property_container vprops_; + Property_container hprops_; + Property_container eprops_; + Property_container fprops_; - Property_array& vconn_; - Property_array& hconn_; - Property_array& fconn_; + Property_array& vconn_; + Property_array& hconn_; + Property_array& fconn_; - Property_array& vpoint_; + Property_array& vpoint_; - size_type vertices_freelist_; - size_type edges_freelist_; - size_type faces_freelist_; - bool recycle_ = true; + size_type vertices_freelist_; + size_type edges_freelist_; + size_type faces_freelist_; + bool recycle_ = true; - size_type anonymous_property_; + size_type anonymous_property_; }; -/*! \addtogroup PkgSurface_mesh - * - * @{ - */ + /*! \addtogroup PkgSurface_mesh + * + * @{ + */ -/// \relates Surface_mesh -/// Inserts `other` into `sm`. -/// Shifts the indices of vertices of `other` by `sm.number_of_vertices() + sm.number_of_removed_vertices()` -/// and analogously for halfedges, edges, and faces. -/// Copies entries of all property maps which have the same name in `sm` and `other`. -/// that is, property maps which are only in `other` are ignored. -/// Also copies elements which are marked as removed, and concatenates the freelists of `sm` and `other`. + /// \relates Surface_mesh + /// Inserts `other` into `sm`. + /// Shifts the indices of vertices of `other` by `sm.number_of_vertices() + sm.number_of_removed_vertices()` + /// and analogously for halfedges, edges, and faces. + /// Copies entries of all property maps which have the same name in `sm` and `other`. + /// that is, property maps which are only in `other` are ignored. + /// Also copies elements which are marked as removed, and concatenates the freelists of `sm` and `other`. -template -Surface_mesh

& operator+=(Surface_mesh

& sm, const Surface_mesh

& other) { - sm.join(other); - return sm; -} + template + Surface_mesh

& operator+=(Surface_mesh

& sm, const Surface_mesh

& other) + { + sm.join(other); + return sm; + } -/// \relates Surface_mesh -/// -/// This operator calls `write_OFF(std::ostream& os, const CGAL::Surface_mesh& sm)`. -template -std::ostream& operator<<(std::ostream& os, const Surface_mesh

& sm) { - IO::write_OFF(os, sm); - return os; -} + /// \relates Surface_mesh + /// + /// This operator calls `write_OFF(std::ostream& os, const CGAL::Surface_mesh& sm)`. + template + std::ostream& operator<<(std::ostream& os, const Surface_mesh

& sm) + { + IO::write_OFF(os, sm); + return os; + } -/// \relates Surface_mesh -/// Extracts the surface mesh from an input stream in OFF -/// and appends it to the surface mesh `sm`. -/// -/// This operator calls `read_OFF(std::istream& is, CGAL::Surface_mesh& sm)`. -template -std::istream& operator>>(std::istream& is, Surface_mesh

& sm) { - IO::read_OFF(is, sm); - return is; -} + /// \relates Surface_mesh + /// Extracts the surface mesh from an input stream in OFF + /// and appends it to the surface mesh `sm`. + /// + /// This operator calls `read_OFF(std::istream& is, CGAL::Surface_mesh& sm)`. + template + std::istream& operator>>(std::istream& is, Surface_mesh

& sm) + { + IO::read_OFF(is, sm); + return is; + } -/*! @} */ + /*! @} */ //----------------------------------------------------------------------------- template Surface_mesh

& Surface_mesh

:: -operator=(const Surface_mesh

& rhs) { - if (this != &rhs) { +operator=(const Surface_mesh

& rhs) +{ + if (this != &rhs) + { + // deep copy of property containers + vprops_ = rhs.vprops_; + hprops_ = rhs.hprops_; + eprops_ = rhs.eprops_; + fprops_ = rhs.fprops_; - // Deep copy of properties - vprops_ = rhs.vprops_; - hprops_ = rhs.hprops_; - eprops_ = rhs.eprops_; - fprops_ = rhs.fprops_; - - // Property array refs don't need to be reassigned, - // because the deep copy updated the values they point to + // Property array refs don't need to be reassigned, + // because the deep copy updated the values they point to - // how many elements are removed? - vertices_freelist_ = rhs.vertices_freelist_; - edges_freelist_ = rhs.edges_freelist_; - faces_freelist_ = rhs.faces_freelist_; - recycle_ = rhs.recycle_; - anonymous_property_ = rhs.anonymous_property_; - } + // how many elements are removed? + vertices_freelist_ = rhs.vertices_freelist_; + edges_freelist_ = rhs.edges_freelist_; + faces_freelist_ = rhs.faces_freelist_; + recycle_ = rhs.recycle_; + anonymous_property_ = rhs.anonymous_property_; + } - return *this; + return *this; } //----------------------------------------------------------------------------- @@ -2100,28 +2176,29 @@ operator=(const Surface_mesh

& rhs) { template void Surface_mesh

:: -property_stats(std::ostream& out) const { - std::vector props; +property_stats(std::ostream& out) const +{ + std::vector props; - out << "vertex properties:\n"; - props = properties(); - for (unsigned int i = 0; i < props.size(); ++i) - out << "\t" << props[i] << std::endl; + out << "vertex properties:\n"; + props = properties(); + for (unsigned int i=0; i(); - for (unsigned int i = 0; i < props.size(); ++i) - out << "\t" << props[i] << std::endl; + out << "halfedge properties:\n"; + props = properties(); + for (unsigned int i=0; i(); - for (unsigned int i = 0; i < props.size(); ++i) - out << "\t" << props[i] << std::endl; + out << "edge properties:\n"; + props = properties(); + for (unsigned int i=0; i(); - for (unsigned int i = 0; i < props.size(); ++i) - out << "\t" << props[i] << std::endl; + out << "face properties:\n"; + props = properties(); + for (unsigned int i=0; i typename Surface_mesh

::Halfedge_index Surface_mesh

:: -halfedge(Vertex_index source, Vertex_index target) const { - CGAL_assertion(has_valid_index(source) && has_valid_index(target)); +halfedge(Vertex_index source, Vertex_index target) const +{ + CGAL_assertion(has_valid_index(source) && has_valid_index(target)); - Halfedge_index h = halfedge(target); - const Halfedge_index hh = h; + Halfedge_index h = halfedge(target); + const Halfedge_index hh = h; - if (h.is_valid()) { - do { - if (this->source(h) == source) - return h; - h = next_around_target(h); - } while (h != hh); - } + if (h.is_valid()) + { + do + { + if (this->source(h) == source) + return h; + h = next_around_target(h); + } + while (h != hh); + } - return Halfedge_index(); + return Halfedge_index(); } @@ -2151,116 +2232,128 @@ halfedge(Vertex_index source, Vertex_index target) const { template void Surface_mesh

:: -adjust_incoming_halfedge(Vertex_index v) { - Halfedge_index h = halfedge(v); - Halfedge_index hh = h; +adjust_incoming_halfedge(Vertex_index v) +{ + Halfedge_index h = halfedge(v); + Halfedge_index hh = h; - if (h.is_valid()) { - if (target(h) != v) { - // wrong target, flip - h = opposite(h); - hh = h; - set_halfedge(v, h); + if (h.is_valid()) + { + if (target(h) != v) + { + // wrong target, flip + h = opposite(h); + hh = h; + set_halfedge(v, h); + } + + do + { + if (is_border(h)) + { + set_halfedge(v, h); + return; + } + h = next_around_target(h); + } + while (h != hh); } - - do { - if (is_border(h)) { - set_halfedge(v, h); - return; - } - h = next_around_target(h); - } while (h != hh); - } } //----------------------------------------------------------------------------- -/// @cond CGAL_DOCUMENT_INTERNALS + /// @cond CGAL_DOCUMENT_INTERNALS template template typename Surface_mesh

::Face_index -Surface_mesh

::add_face(const Range& r) { +Surface_mesh

::add_face(const Range& r) +{ return CGAL::Euler::add_face(r, *this); } -/// @endcond + /// @endcond //----------------------------------------------------------------------------- template typename Surface_mesh

::size_type Surface_mesh

:: -degree(Vertex_index v) const { - Halfedge_index h = halfedge(v); +degree(Vertex_index v) const +{ + Halfedge_index h = halfedge(v); - if (h == null_halfedge()) { - return 0; - } - size_type count(0); - Halfedge_index done = h; - do { - ++count; - h = opposite(next(h)); - } while (h != done); - - return count; -} - - -//----------------------------------------------------------------------------- -template -typename Surface_mesh

::size_type -Surface_mesh

:: -degree(Face_index f) const { - size_type count(0); - if (halfedge(f) == null_halfedge()) { - return 0; - } - Vertex_around_face_circulator fvit(halfedge(f), *this); - Vertex_around_face_circulator fvend = fvit; - if (fvit) + if(h == null_halfedge()){ + return 0; + } + size_type count(0); + Halfedge_index done = h; do { ++count; + h = opposite(next(h)); + }while(h != done); + + return count; +} + + +//----------------------------------------------------------------------------- +template +typename Surface_mesh

::size_type +Surface_mesh

:: +degree(Face_index f) const +{ + size_type count(0); + if(halfedge(f) == null_halfedge()){ + return 0; + } + Vertex_around_face_circulator fvit(halfedge(f),*this); + Vertex_around_face_circulator fvend = fvit; + if(fvit) do { + ++count; } while (++fvit != fvend); - return count; + return count; } -namespace internal { -namespace handle { -template <> -struct Hash_functor { - std::size_t - operator()(const SM_Vertex_index i) { - return i; - } -}; +namespace internal{ + namespace handle { + template <> + struct Hash_functor{ + std::size_t + operator()(const SM_Vertex_index i) + { + return i; + } + }; -template <> -struct Hash_functor { - std::size_t - operator()(const SM_Halfedge_index i) { - return i; - } -}; + template <> + struct Hash_functor{ + std::size_t + operator()(const SM_Halfedge_index i) + { + return i; + } + }; -template <> -struct Hash_functor { - std::size_t - operator()(const SM_Edge_index i) { - return i; - } -}; + template <> + struct Hash_functor{ + std::size_t + operator()(const SM_Edge_index i) + { + return i; + } + }; -template <> -struct Hash_functor { - std::size_t - operator()(const SM_Face_index i) { - return i; + template <> + struct Hash_functor{ + std::size_t + operator()(const SM_Face_index i) + { + return i; + } + }; } -}; -} } } // namespace CGAL @@ -2276,42 +2369,45 @@ namespace std { #ifndef CGAL_CFG_NO_STD_HASH -template <> -struct hash - : public CGAL::cpp98::unary_function { + template <> + struct hash + : public CGAL::cpp98::unary_function { - std::size_t operator()(const CGAL::SM_Halfedge_index& i) const { - return i; - } -}; + std::size_t operator()(const CGAL::SM_Halfedge_index& i) const + { + return i; + } + }; -template <> -struct hash - : public CGAL::cpp98::unary_function { + template <> + struct hash + : public CGAL::cpp98::unary_function { - std::size_t operator()(const CGAL::SM_Vertex_index& i) const { - return i; - } -}; + std::size_t operator()(const CGAL::SM_Vertex_index& i) const + { + return i; + } + }; -template <> -struct hash - : public CGAL::cpp98::unary_function { + template <> + struct hash + : public CGAL::cpp98::unary_function { - std::size_t operator()(const CGAL::SM_Face_index& i) const { - return i; - } -}; + std::size_t operator()(const CGAL::SM_Face_index& i) const + { + return i; + } + }; -template <> -struct hash - : public CGAL::cpp98::unary_function { - - std::size_t operator()(const CGAL::SM_Edge_index& i) const { - return i; - } -}; + template <> + struct hash + : public CGAL::cpp98::unary_function { + std::size_t operator()(const CGAL::SM_Edge_index& i) const + { + return i; + } + }; #endif // CGAL_CFG_NO_STD_HASH #if defined(BOOST_MSVC) @@ -2321,12 +2417,13 @@ struct hash } // namespace std namespace boost { -template <> -struct hash { - std::size_t operator()(const CGAL::SM_Vertex_index& i) const { - return i; - } -}; + template <> + struct hash { + std::size_t operator()(const CGAL::SM_Vertex_index& i) const + { + return i; + } + }; } // namespace boost From 6963e7f973c09e0fcc4dd12e98b0796a7047ec09 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Thu, 5 Oct 2023 13:57:01 +0200 Subject: [PATCH 33/35] fix emplace_group on MSVC --- Property_map/include/CGAL/Property_container.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Property_map/include/CGAL/Property_container.h b/Property_map/include/CGAL/Property_container.h index 35887a1ee43..83d6e81cde2 100644 --- a/Property_map/include/CGAL/Property_container.h +++ b/Property_map/include/CGAL/Property_container.h @@ -106,7 +106,7 @@ public: } virtual void move(Property_array_base&& other_base) override { - auto&& other = dynamic_cast&&>(other_base); + auto&& other = static_cast&&>(other_base); m_data = std::move(other.m_data); CGAL_precondition(m_active_indices.size() == m_data.size()); } @@ -489,10 +489,13 @@ public: [](bool used) { return !used; } ); + auto unused_end = unused_begin; + // Determine if the group fits - auto unused_end = std::find_if( - unused_begin, std::min(unused_begin + n, m_active_indices.end()), - [](bool used) { return used; } + if (std::distance(unused_begin, m_active_indices.end()) >= n) + unused_end = std::find_if( + unused_begin, std::min(unused_begin + n, m_active_indices.end()), + [](bool used) { return used; } ); // If the discovered range was large enough From f797ae714f09d0053c7c6edca89632e1105c1cf1 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Thu, 5 Oct 2023 13:57:18 +0200 Subject: [PATCH 34/35] fix compilation on MSVC --- Orthtree/examples/Orthtree/octree_build_from_point_vector.cpp | 2 +- Orthtree/examples/Orthtree/octree_grade.cpp | 2 +- Orthtree/examples/Orthtree/quadtree_build_from_point_vector.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Orthtree/examples/Orthtree/octree_build_from_point_vector.cpp b/Orthtree/examples/Orthtree/octree_build_from_point_vector.cpp index 754fcaa3553..1081e155df3 100644 --- a/Orthtree/examples/Orthtree/octree_build_from_point_vector.cpp +++ b/Orthtree/examples/Orthtree/octree_build_from_point_vector.cpp @@ -23,7 +23,7 @@ int main() { points.emplace_back(-1, 1, 1); // Create an octree from the points - Octree octree({points}); + Octree octree(points); // Build the octree octree.refine(10, 1); diff --git a/Orthtree/examples/Orthtree/octree_grade.cpp b/Orthtree/examples/Orthtree/octree_grade.cpp index ae41079ea87..5bb410d7e33 100644 --- a/Orthtree/examples/Orthtree/octree_grade.cpp +++ b/Orthtree/examples/Orthtree/octree_grade.cpp @@ -30,7 +30,7 @@ int main() { points.emplace_back(-1.0001, 1, 1); // Create an octree from the points - Octree octree({points}); + Octree octree(points); // Build the octree with a small bucket size, so we get a deep node octree.refine(10, 2); diff --git a/Orthtree/examples/Orthtree/quadtree_build_from_point_vector.cpp b/Orthtree/examples/Orthtree/quadtree_build_from_point_vector.cpp index 45a9b2a80f5..bd40ace0423 100644 --- a/Orthtree/examples/Orthtree/quadtree_build_from_point_vector.cpp +++ b/Orthtree/examples/Orthtree/quadtree_build_from_point_vector.cpp @@ -18,7 +18,7 @@ int main() points_2d.emplace_back(r.get_double(-1., 1.), r.get_double(-1., 1.)); - Quadtree quadtree({points_2d}); + Quadtree quadtree(points_2d); quadtree.refine(10, 5); return EXIT_SUCCESS; From 047a223db0bf6d4ca8e23392d70cd7e041de9682 Mon Sep 17 00:00:00 2001 From: JacksonCampolattaro Date: Sun, 8 Oct 2023 15:05:24 +0200 Subject: [PATCH 35/35] Revert Surface_mesh to the old memory management scheme The new property container system is still used. Beneficial changes to surface mesh and additions to unit tests are preserved. --- Orthtree/doc/Orthtree/Orthtree.txt | 2 +- .../include/CGAL/Surface_mesh/Surface_mesh.h | 542 ++++++++++++++---- .../test/Surface_mesh/sm_circulator_test.cpp | 8 +- .../test/Surface_mesh/sm_join_test.cpp | 31 +- Surface_mesh/test/Surface_mesh/sm_remove.cpp | 43 +- 5 files changed, 474 insertions(+), 152 deletions(-) diff --git a/Orthtree/doc/Orthtree/Orthtree.txt b/Orthtree/doc/Orthtree/Orthtree.txt index 1f40d39d5c5..6abe414ea5f 100644 --- a/Orthtree/doc/Orthtree/Orthtree.txt +++ b/Orthtree/doc/Orthtree/Orthtree.txt @@ -293,4 +293,4 @@ provided kind help and advice all the way through. */ -} +} \ No newline at end of file diff --git a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h index 86713e830d1..7411c8889ee 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h @@ -690,7 +690,7 @@ public: /// End iterator for vertices. Vertex_iterator vertices_end() const { - return Vertex_iterator(Vertex_index(number_of_vertices()), this); + return Vertex_iterator(Vertex_index(num_vertices()), this); } /// @endcond @@ -711,7 +711,7 @@ public: /// End iterator for halfedges. Halfedge_iterator halfedges_end() const { - return Halfedge_iterator(Halfedge_index(number_of_halfedges()), this); + return Halfedge_iterator(Halfedge_index(num_halfedges()), this); } /// @endcond @@ -732,7 +732,7 @@ public: /// End iterator for edges. Edge_iterator edges_end() const { - return Edge_iterator(Edge_index(number_of_edges()), this); + return Edge_iterator(Edge_index(num_edges()), this); } /// @endcond @@ -754,7 +754,7 @@ public: /// End iterator for faces. Face_iterator faces_end() const { - return Face_iterator(Face_index(number_of_faces()), this); + return Face_iterator(Face_index(num_faces()), this); } /// @endcond @@ -908,31 +908,58 @@ public: hconn_(hprops_.add_property("h:connectivity")), fconn_(fprops_.add_property("f:connectivity")), vpoint_(vprops_.add_property("v:point")), + vremoved_(vprops_.add_property("v:removed")), + eremoved_(eprops_.add_property("e:removed")), + fremoved_(fprops_.add_property("f:removed")), anonymous_property_(0) {} /// Copy constructor: copies `rhs` to `*this`. Performs a deep copy of all properties. Surface_mesh(const Surface_mesh& rhs) : - vprops_(rhs.vprops_), - hprops_(rhs.hprops_), - fprops_(rhs.fprops_), - eprops_(rhs.eprops_), - vconn_(vprops_.get_property("v:connectivity")), - vpoint_(vprops_.get_property("v:point")), - hconn_(hprops_.get_property("h:connectivity")), - fconn_(fprops_.get_property("f:connectivity")), - anonymous_property_(0) {} + vprops_(rhs.vprops_) + , hprops_(rhs.hprops_) + , fprops_(rhs.fprops_) + , eprops_(rhs.eprops_) + , vpoint_(vprops_.get_property("v:point")) + , vconn_(vprops_.get_property("v:connectivity")) + , hconn_(hprops_.get_property("h:connectivity")) + , fconn_(fprops_.get_property("f:connectivity")) + , vremoved_(vprops_.get_property("v:removed")) + , eremoved_(eprops_.get_property("e:removed")) + , fremoved_(fprops_.get_property("f:removed")) + , removed_vertices_(rhs.removed_vertices_) + , removed_edges_(rhs.removed_edges_) + , removed_faces_(rhs.removed_faces_) + , vertices_freelist_(rhs.vertices_freelist_) + , edges_freelist_(rhs.edges_freelist_) + , faces_freelist_(rhs.faces_freelist_) + , garbage_(rhs.garbage_) + , recycle_(rhs.recycle_) + , anonymous_property_(rhs.anonymous_property_) + {} /// Move constructor. - Surface_mesh(Surface_mesh&& sm) : - vprops_(std::move(sm.vprops_)), - hprops_(std::move(sm.hprops_)), - eprops_(std::move(sm.eprops_)), - fprops_(std::move(sm.fprops_)), - vconn_(vprops_.get_property("v:connectivity")), - vpoint_(vprops_.get_property("v:point")), - hconn_(hprops_.get_property("h:connectivity")), - fconn_(fprops_.get_property("f:connectivity")), - anonymous_property_(0) {} + Surface_mesh(Surface_mesh&& sm) + : vprops_(std::move(sm.vprops_)) + , hprops_(std::move(sm.hprops_)) + , eprops_(std::move(sm.eprops_)) + , fprops_(std::move(sm.fprops_)) + , vpoint_(vprops_.get_property("v:point")) + , vconn_(vprops_.get_property("v:connectivity")) + , hconn_(hprops_.get_property("h:connectivity")) + , fconn_(fprops_.get_property("f:connectivity")) + , vremoved_(vprops_.get_property("v:removed")) + , eremoved_(eprops_.get_property("e:removed")) + , fremoved_(fprops_.get_property("f:removed")) + , removed_vertices_(std::exchange(sm.removed_vertices_, 0)) + , removed_edges_(std::exchange(sm.removed_edges_, 0)) + , removed_faces_(std::exchange(sm.removed_faces_, 0)) + , vertices_freelist_(std::exchange(sm.vertices_freelist_,(std::numeric_limits::max)())) + , edges_freelist_(std::exchange(sm.edges_freelist_,(std::numeric_limits::max)())) + , faces_freelist_(std::exchange(sm.faces_freelist_,(std::numeric_limits::max)())) + , garbage_(std::exchange(sm.garbage_, false)) + , recycle_(std::exchange(sm.recycle_, true)) + , anonymous_property_(std::exchange(sm.anonymous_property_, 0)) + {} /// assigns `rhs` to `*this`. Performs a deep copy of all properties. Surface_mesh& operator=(const Surface_mesh& rhs); @@ -940,6 +967,7 @@ public: /// move assignment Surface_mesh& operator=(Surface_mesh&& sm) { + // Moving properties also moves their contents without invalidating references vprops_ = std::move(sm.vprops_); hprops_ = std::move(sm.hprops_); eprops_ = std::move(sm.eprops_); @@ -957,10 +985,17 @@ public: /// adds a new vertex, and resizes vertex properties if necessary. Vertex_index add_vertex() { - if(recycle_) - return vprops_.emplace(); - else - return vprops_.emplace_back(); + size_type inf = (std::numeric_limits::max)(); + if(recycle_ && (vertices_freelist_ != inf)){ + size_type idx = vertices_freelist_; + vertices_freelist_ = (size_type)vconn_[Vertex_index(vertices_freelist_)].halfedge_; + --removed_vertices_; + vremoved_[Vertex_index(idx)] = false; + vprops_.reset(Vertex_index(idx)); + return Vertex_index(idx); + } else { + return Vertex_index(vprops_.emplace_back()); + } } /// adds a new vertex, resizes vertex properties if necessary, @@ -980,19 +1015,21 @@ public: /// adds a new edge, and resizes edge and halfedge properties if necessary. Halfedge_index add_edge() { - - // Add properties for a new edge - if (recycle_) - eprops_.emplace(); - else + Halfedge_index h0, h1; + size_type inf = (std::numeric_limits::max)(); + if(recycle_ && (edges_freelist_ != inf)){ + size_type idx = edges_freelist_; + edges_freelist_ = (size_type)hconn_[Halfedge_index(edges_freelist_)].next_halfedge_; + --removed_edges_; + eremoved_[Edge_index(Halfedge_index(idx))] = false; + hprops_.reset(Halfedge_index(idx)); + hprops_.reset(opposite(Halfedge_index(idx))); + eprops_.reset(Edge_index(Halfedge_index(idx))); + return Halfedge_index(idx); + } else { eprops_.emplace_back(); - - // Add properties for a pair of new half-edges - // The new half-edges are placed adjacently, and we return the index of the first - if (recycle_) - return hprops_.emplace_group(2); - else - return hprops_.emplace_group_back(2); + return Halfedge_index(hprops_.emplace_group_back(2)); + } } /// adds two opposite halfedges, and resizes edge and halfedge properties if necessary. @@ -1015,10 +1052,17 @@ public: /// adds a new face, and resizes face properties if necessary. Face_index add_face() { - if(recycle_) - return fprops_.emplace(); - else - return fprops_.emplace_back(); + size_type inf = (std::numeric_limits::max)(); + if(recycle_ && (faces_freelist_ != inf)){ + size_type idx = faces_freelist_; + faces_freelist_ = (size_type)fconn_[Face_index(faces_freelist_)].halfedge_; + --removed_faces_; + fprops_.reset(Face_index(idx)); + fremoved_[Face_index(idx)] = false; + return Face_index(idx); + } else { + return Face_index(fprops_.emplace_back()); + } } /// if possible, adds a new face with vertices from a range with value type `Vertex_index`. @@ -1068,16 +1112,18 @@ public: /// adjusting anything. void remove_vertex(Vertex_index v) { - // todo: confirm this behaves correctly - vprops_.erase(v); + vremoved_[v] = true; ++removed_vertices_; garbage_ = true; + vconn_[v].halfedge_ = Halfedge_index(vertices_freelist_); + vertices_freelist_ = (size_type)v; } /// removes the two halfedges corresponding to `e` from the halfedge data structure without /// adjusting anything. void remove_edge(Edge_index e) { - // todo: confirm this behaves correctly - eprops_.erase(e); + eremoved_[e] = true; ++removed_edges_; garbage_ = true; + hconn_[Halfedge_index((size_type)e << 1)].next_halfedge_ = Halfedge_index(edges_freelist_ ); + edges_freelist_ = ((size_type)e << 1); } /// removes face `f` from the halfedge data structure without @@ -1085,8 +1131,9 @@ public: void remove_face(Face_index f) { - // todo: confirm this behaves correctly - fprops_.erase(f); + fremoved_[f] = true; ++removed_faces_; garbage_ = true; + fconn_[f].halfedge_ = Halfedge_index(faces_freelist_); + faces_freelist_ = (size_type)f; } @@ -1099,51 +1146,45 @@ public: /// allocated for elements, and to clear the structure. ///@{ -#ifndef DOXYGEN_RUNNING - /// returns the number of used and removed vertices in the mesh. - size_type num_vertices() const { return (size_type) vprops_.size(); } - - /// returns the number of used and removed halfedges in the mesh. - size_type num_halfedges() const { return (size_type) hprops_.size(); } - - /// returns the number of used and removed edges in the mesh. - size_type num_edges() const { return (size_type) eprops_.size(); } - - /// returns the number of used and removed faces in the mesh. - size_type num_faces() const { return (size_type) fprops_.size(); } - -#endif - /// returns the number of vertices in the mesh. size_type number_of_vertices() const { - return vprops_.size(); + return num_vertices() - number_of_removed_vertices(); } /// returns the number of halfedges in the mesh. size_type number_of_halfedges() const { - return hprops_.size(); + return num_halfedges() - number_of_removed_halfedges(); } /// returns the number of edges in the mesh. size_type number_of_edges() const { - return eprops_.size(); + return num_edges() - number_of_removed_edges(); } /// returns the number of faces in the mesh. size_type number_of_faces() const { - return fprops_.size(); + return num_faces() - number_of_removed_faces(); } /// returns `true` iff the mesh is empty, i.e., has no vertices, halfedges and faces. bool is_empty() const { - return (vprops_.size() == 0 - && hprops_.size() == 0 - && fprops_.size() == 0); + return ( num_vertices() == number_of_removed_vertices() + && num_halfedges() == number_of_removed_halfedges() + && num_faces() == number_of_removed_faces()); + } + + /// removes all vertices, halfedge, edges and faces. Collects garbage but keeps all property maps. + void clear_without_removing_property_maps() + { + vprops_.reserve(0); + hprops_.reserve(0); + eprops_.reserve(0); + fprops_.reserve(0); } /// removes all vertices, halfedge, edges and faces. Collects garbage and removes all property maps added by a call to `add_property_map()` for all simplex types. @@ -1158,14 +1199,6 @@ public: eprops_.remove_all_properties_except({}); } - void clear_without_removing_property_maps() - { - vprops_.reserve(0); - hprops_.reserve(0); - eprops_.reserve(0); - fprops_.reserve(0); - } - /// reserves space for vertices, halfedges, edges, faces, and their currently /// associated properties. @@ -1179,6 +1212,16 @@ public: fprops_.reserve(nfaces); } + void resize(size_type nvertices, + size_type nedges, + size_type nfaces ) + { + vprops_.resize(nvertices); + hprops_.resize(2*nedges); + eprops_.resize(nedges); + fprops_.resize(nfaces); + } + /// copies the simplices from `other`, and copies values of /// properties that already exist under the same name in `*this`. /// In case `*this` has a property that does not exist in `other` @@ -1195,24 +1238,22 @@ public: fprops_.append(other.fprops_); eprops_.append(other.eprops_); - // todo: the below code assumes no gaps were present in the properties! That might be okay for this situation. - // translate halfedge index in vertex -> halfedge - for(size_type i = nv; i < nv+other.number_of_vertices(); i++){ + for(size_type i = nv; i < nv+other.num_vertices(); i++){ Vertex_index vi(i); if(vconn_[vi].halfedge_ != null_halfedge()){ vconn_[vi].halfedge_ = Halfedge_index(size_type(vconn_[vi].halfedge_)+nh); } } // translate halfedge index in face -> halfedge - for(size_type i = nf; i < nf+other.number_of_faces(); i++){ + for(size_type i = nf; i < nf+other.num_faces(); i++){ Face_index fi(i); if(fconn_[fi].halfedge_ != null_halfedge()){ fconn_[fi].halfedge_ = Halfedge_index(size_type(fconn_[fi].halfedge_)+nh); } } // translate indices in halfedge -> face, halfedge -> target, halfedge -> prev, and halfedge -> next - for(size_type i = nh; i < nh+other.number_of_halfedges(); i++){ + for(size_type i = nh; i < nh+other.num_halfedges(); i++){ Halfedge_index hi(i); if(hconn_[hi].face_ != null_face()){ hconn_[hi].face_ = Face_index(size_type(hconn_[hi].face_)+nf); @@ -1227,6 +1268,55 @@ public: hconn_[hi].prev_halfedge_ = Halfedge_index(size_type(hconn_[hi].prev_halfedge_)+nh); } } + size_type inf_value = (std::numeric_limits::max)(); + + // merge vertex free list + if(other.vertices_freelist_ != inf_value){ + Vertex_index vi(nv+other.vertices_freelist_); + Halfedge_index inf((std::numeric_limits::max)()); + // correct the indices in the linked list of free vertices copied (due to vconn_ translation) + while(vconn_[vi].halfedge_ != inf){ + Vertex_index corrected_vi = Vertex_index(size_type(vconn_[vi].halfedge_)+nv-nh); + vconn_[vi].halfedge_ = Halfedge_index(corrected_vi); + vi = corrected_vi; + } + // append the vertex free linked list of `this` to the copy of `other` + vconn_[vi].halfedge_ = Halfedge_index(vertices_freelist_); + // update the begin of the vertex free linked list + vertices_freelist_ = nv + other.vertices_freelist_; + } + // merge face free list + if(other.faces_freelist_ != inf_value){ + Face_index fi(nf+other.faces_freelist_); + Halfedge_index inf((std::numeric_limits::max)()); + // correct the indices in the linked list of free faces copied (due to fconn_ translation) + while(fconn_[fi].halfedge_ != inf){ + Face_index corrected_fi = Face_index(size_type(fconn_[fi].halfedge_)+nf-nh); + fconn_[fi].halfedge_ = Halfedge_index(corrected_fi); + fi = corrected_fi; + } + // append the face free linked list of `this` to the copy of `other` + fconn_[fi].halfedge_ = Halfedge_index(faces_freelist_); + // update the begin of the face free linked list + faces_freelist_ = nf + other.faces_freelist_; + } + // merge edge free list + if(other.edges_freelist_ != inf_value){ + Halfedge_index hi(nh+other.edges_freelist_); + Halfedge_index inf((std::numeric_limits::max)()); + while(hconn_[hi].next_halfedge_ != inf){ + hi = hconn_[hi].next_halfedge_; + } + // append the halfedge free linked list of `this` to the copy of `other` + hconn_[hi].next_halfedge_ = Halfedge_index(edges_freelist_); + // update the begin of the halfedge free linked list + edges_freelist_ = nh + other.edges_freelist_; + } + // update garbage infos + garbage_ = garbage_ || other.garbage_; + removed_vertices_ += other.removed_vertices_; + removed_edges_ += other.removed_edges_; + removed_faces_ += other.removed_faces_; return true; } @@ -1252,49 +1342,63 @@ public: /// are recycled. ///@{ +#ifndef DOXYGEN_RUNNING + /// returns the number of used and removed vertices in the mesh. + size_type num_vertices() const { return (size_type) vprops_.size(); } + + /// returns the number of used and removed halfedges in the mesh. + size_type num_halfedges() const { return (size_type) hprops_.size(); } + + /// returns the number of used and removed edges in the mesh. + size_type num_edges() const { return (size_type) eprops_.size(); } + + /// returns the number of used and removed faces in the mesh. + size_type num_faces() const { return (size_type) fprops_.size(); } + +#endif /// returns the number of vertices in the mesh which are marked removed. - size_type number_of_removed_vertices() const { return vprops_.capacity() - vprops_.size(); } + size_type number_of_removed_vertices() const { return removed_vertices_; } /// returns the number of halfedges in the mesh which are marked removed. - size_type number_of_removed_halfedges() const { return hprops_.capacity() - hprops_.size(); } + size_type number_of_removed_halfedges() const { return 2*removed_edges_; } /// returns the number of edges in the mesh which are marked removed. - size_type number_of_removed_edges() const { return eprops_.capacity() - eprops_.size(); } + size_type number_of_removed_edges() const { return removed_edges_; } /// returns the number offaces in the mesh which are marked removed. - size_type number_of_removed_faces() const { return fprops_.capacity() - fprops_.size(); } + size_type number_of_removed_faces() const { return removed_faces_; } + /// returns whether vertex `v` is marked removed. + /// \sa `collect_garbage()` bool is_removed(Vertex_index v) const { - return vprops_.is_erased(v); + return vremoved_[v]; } /// returns whether halfedge `h` is marked removed. + /// \sa `collect_garbage()` bool is_removed(Halfedge_index h) const { - return hprops_.is_erased(h); + return eremoved_[edge(h)]; } /// returns whether edge `e` is marked removed. + /// \sa `collect_garbage()` bool is_removed(Edge_index e) const { - return eprops_.is_erased(e); + return eremoved_[e]; } /// returns whether face `f` is marked removed. + /// \sa `collect_garbage()` bool is_removed(Face_index f) const { - return fprops_.is_erased(f); + return fremoved_[f]; } /// checks if any vertices, halfedges, edges, or faces are marked as removed. /// \sa collect_garbage - bool has_garbage() const { - return number_of_removed_vertices() != 0 || - number_of_removed_edges() != 0 || - number_of_removed_halfedges() != 0 || - number_of_removed_faces() != 0; - } + bool has_garbage() const { return garbage_; } /// really removes vertices, halfedges, edges, and faces which are marked removed. /// \sa `has_garbage()` @@ -1302,15 +1406,11 @@ public: /// In case you store indices in an auxiliary data structure /// or in a property these indices are potentially no longer /// referring to the right elements. - void collect_garbage() { - // todo: this should compress the array - } + void collect_garbage(); //undocumented convenience function that allows to get old-index->new-index information template - void collect_garbage(Visitor& visitor) { - // todo: this should compress the array and remap indices - } + void collect_garbage(Visitor& visitor); /// controls the recycling or not of simplices previously marked as removed /// upon addition of new elements. @@ -1326,6 +1426,13 @@ public: /// of all properties to the minimal required size. /// \attention Invalidates all existing references to properties. + void shrink_to_fit() + { + vprops_.shrink_to_fit(); + hprops_.shrink_to_fit(); + eprops_.shrink_to_fit(); + fprops_.shrink_to_fit(); + } /// @endcond ///@} @@ -1342,23 +1449,23 @@ public: /// returns whether the index of vertex `v` is valid, that is within the current array bounds. bool has_valid_index(Vertex_index v) const { - return ((size_type)v < number_of_vertices()); + return ((size_type)v < num_vertices()); } /// returns whether the index of halfedge `h` is valid, that is within the current array bounds. bool has_valid_index(Halfedge_index h) const { - return ((size_type)h < number_of_halfedges()); + return ((size_type)h < num_halfedges()); } /// returns whether the index of edge `e` is valid, that is within the current array bounds. bool has_valid_index(Edge_index e) const { - return ((size_type)e < number_of_edges()); + return ((size_type)e < num_edges()); } /// returns whether the index of face `f` is valid, that is within the current array bounds. bool has_valid_index(Face_index f) const { - return ((size_type)f < number_of_faces()); + return ((size_type)f < num_faces()); } /// @} @@ -1456,6 +1563,32 @@ public: std::cerr << "#faces: iterated: " << fcount << " vs number_of_faces(): " << number_of_faces()<< std::endl; } + size_type inf = (std::numeric_limits::max)(); + size_type vfl = vertices_freelist_; + size_type rv = 0; + while(vfl != inf){ + vfl = (size_type)vconn_[Vertex_index(vfl)].halfedge_; + rv++; + } + valid = valid && ( rv == removed_vertices_ ); + + + size_type efl = edges_freelist_; + size_type re = 0; + while(efl != inf){ + efl = (size_type)hconn_[Halfedge_index(efl)].next_halfedge_; + re++; + } + valid = valid && ( re == removed_edges_ ); + + size_type ffl = faces_freelist_; + size_type rf = 0; + while(ffl != inf){ + ffl = (size_type)fconn_[Face_index(ffl)].halfedge_; + rf++; + } + valid = valid && ( rf == removed_faces_ ); + return valid; } @@ -1919,8 +2052,6 @@ private: //--------------------------------------------------- property handling #endif - // todo: I can't see a good reason for these two functions to exist separately, but do almost the same thing - /// adds a property map named `name` with value type `T` and default `t` /// for index type `I`. Returns the property map together with a Boolean /// that is `true` if a new map was created. In case it already exists @@ -1934,7 +2065,6 @@ private: //--------------------------------------------------- property handling oss << "anonymous-property-" << anonymous_property_++; name = std::string(oss.str()); } - // todo: double check this is working auto [array, created] = const_cast*>(this)->get_property_container().template get_or_add_property(name, t); return {{array.get()}, created}; @@ -2053,19 +2183,19 @@ private: //--------------------------------------------------- property handling /// @} #if defined(CGAL_SURFACE_MESH_TEST_SUITE) - std::vector vertex_freelist() const + Vertex_index vertex_freelist() const { - return vprops_.inactive_list(); + return Vertex_index(vertices_freelist_); } - std::vector face_freelist() const + Face_index face_freelist() const { - return fprops_.inactive_list(); + return Face_index(faces_freelist_); } - std::vector edge_freelist() const + Edge_index edge_freelist() const { - return eprops_.inactive_list(); + return Edge_index(edges_freelist_>>1); } #endif @@ -2087,11 +2217,20 @@ private: //------------------------------------------------------- private data Property_array& hconn_; Property_array& fconn_; + Property_array &vremoved_; + Property_array &eremoved_; + Property_array &fremoved_; + Property_array& vpoint_; - size_type vertices_freelist_; - size_type edges_freelist_; - size_type faces_freelist_; + size_type removed_vertices_ = 0; + size_type removed_edges_ = 0; + size_type removed_faces_ = 0; + + size_type vertices_freelist_ = std::numeric_limits::max(); + size_type edges_freelist_ = std::numeric_limits::max(); + size_type faces_freelist_ = std::numeric_limits::max(); + bool garbage_ = false; bool recycle_ = true; size_type anonymous_property_; @@ -2315,6 +2454,169 @@ degree(Face_index f) const return count; } +template template< typename Visitor> +void +Surface_mesh

:: +collect_garbage(Visitor &visitor) +{ + if (!has_garbage()) + { + return; + } + + std::uint32_t i, i0, i1, + nV(num_vertices()), + nE(num_edges()), + nH(num_halfedges()), + nF(num_faces()); + + Vertex_index v; + Halfedge_index h; + Face_index f; + + + // setup index mapping% + Property_map vmap = add_property_map("v:garbage-collection").first; + Property_map hmap = add_property_map("h:garbage-collection").first; + Property_map fmap = add_property_map("f:garbage-collection").first; + for (i=0; i 0) + { + i0=0; i1=nV-1; + + while (1) + { + // find first removed and last un-removed + while (!vremoved_[Vertex_index(i0)] && i0 < i1) ++i0; + while ( vremoved_[Vertex_index(i1)] && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + vprops_.swap(i0, i1); + }; + + // remember new size + nV = vremoved_[Vertex_index(i0)] ? i0 : i0+1; + } + + // really remove edges + if (nE > 0) + { + i0=0; i1=nE-1; + + while (1) + { + // find first removed and last un-removed + while (!eremoved_[Edge_index(i0)] && i0 < i1) ++i0; + while ( eremoved_[Edge_index(i1)] && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + eprops_.swap(SM_Edge_index{i0}, SM_Edge_index{i1}); + hprops_.swap(SM_Halfedge_index{2*i0}, SM_Halfedge_index{2*i1}); + hprops_.swap(SM_Halfedge_index{2*i0+1}, SM_Halfedge_index{2*i1+1}); + }; + + // remember new size + nE = eremoved_[Edge_index(i0)] ? i0 : i0+1; + nH = 2*nE; + } + + + // really remove faces + if (nF > 0) + { + i0=0; i1=nF-1; + + while (1) + { + // find 1st removed and last un-removed + while (!fremoved_[Face_index(i0)] && i0 < i1) ++i0; + while ( fremoved_[Face_index(i1)] && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + fprops_.swap(SM_Face_index{i0}, SM_Face_index{i1}); + }; + + // remember new size + nF = fremoved_[Face_index(i0)] ? i0 : i0+1; + } + + + // update vertex connectivity + for (i=0; i(vmap); + remove_property_map(hmap); + remove_property_map(fmap); + + // finally resize arrays + vprops_.resize(nV); vprops_.shrink_to_fit(); + hprops_.resize(nH); hprops_.shrink_to_fit(); + eprops_.resize(nE); eprops_.shrink_to_fit(); + fprops_.resize(nF); fprops_.shrink_to_fit(); + + removed_vertices_ = removed_edges_ = removed_faces_ = 0; + vertices_freelist_ = edges_freelist_ = faces_freelist_ = -1; + garbage_ = false; +} + +#ifndef DOXYGEN_RUNNING +namespace collect_garbage_internal { +struct Dummy_visitor{ + template + void operator()(const A&, const B&, const C&) + {} +}; + +} +#endif + +template +void +Surface_mesh

:: +collect_garbage() +{ + collect_garbage_internal::Dummy_visitor visitor; + collect_garbage(visitor); +} namespace internal{ namespace handle { diff --git a/Surface_mesh/test/Surface_mesh/sm_circulator_test.cpp b/Surface_mesh/test/Surface_mesh/sm_circulator_test.cpp index 5e932869a44..bf446b30959 100644 --- a/Surface_mesh/test/Surface_mesh/sm_circulator_test.cpp +++ b/Surface_mesh/test/Surface_mesh/sm_circulator_test.cpp @@ -64,20 +64,20 @@ struct test_emptiness : public Surface_fixture assert(m.is_isolated(iv)); Sm::Vertex_around_target_range vr = m.vertices_around_target(m.halfedge(iv)); - assert(is_empty_range(std::begin(vr), std::end(vr))); + assert(is_empty_range(boost::begin(vr), boost::end(vr))); Sm::Face_around_target_range fr = m.faces_around_target(m.halfedge(iv)); - assert(is_empty_range(std::begin(fr), std::end(fr))); + assert(is_empty_range(boost::begin(fr), boost::end(fr))); Sm::Halfedge_around_target_range hr = m.halfedges_around_target(m.halfedge(iv)); - assert(is_empty_range(std::begin(hr), std::end(hr))); + assert(is_empty_range(boost::begin(hr), boost::end(hr))); // not true for everything else m.remove_vertex(iv); assert(m.is_removed(iv)); Sm::Vertex_iterator vb, ve; for(boost::tie(vb, ve) = m.vertices(); vb != ve; ++vb) { Sm::Vertex_around_target_range vr = m.vertices_around_target(m.halfedge(*vb)); - assert(!is_empty_range(std::begin(vr), std::end(vr))); + assert(!is_empty_range(boost::begin(vr), boost::end(vr))); } } }; diff --git a/Surface_mesh/test/Surface_mesh/sm_join_test.cpp b/Surface_mesh/test/Surface_mesh/sm_join_test.cpp index 65b83c9fef6..4a71243b8e4 100644 --- a/Surface_mesh/test/Surface_mesh/sm_join_test.cpp +++ b/Surface_mesh/test/Surface_mesh/sm_join_test.cpp @@ -19,24 +19,35 @@ typedef boost::graph_traits::face_descriptor face_descriptor; void freelist(const Sm& sm, int vc, int fc, int ec) { - // vc should be the number of in-active vertex indices std::cout << "vertex freelist" << std::endl; - auto unused_vertices = sm.vertex_freelist(); - for (auto vd: unused_vertices) + vertex_descriptor vd = sm.vertex_freelist(); + while(vd != sm.null_vertex()){ + --vc; std::cout << vd << std::endl; - assert(vc == unused_vertices.size()); + halfedge_descriptor hd = halfedge(vd,sm); + vd = vertex_descriptor((Sm::size_type)hd); + } + assert(vc == 0); std::cout << "face freelist" << std::endl; - auto unused_faces = sm.face_freelist(); - for (auto fd: unused_faces) + face_descriptor fd = sm.face_freelist(); + while(fd != sm.null_face()){ + --fc; std::cout << fd << std::endl; - assert(fc == unused_faces.size()); + halfedge_descriptor hd = halfedge(fd,sm); + fd = face_descriptor((Sm::size_type)hd); + } + assert(fc == 0); std::cout << "edge freelist" << std::endl; - auto unused_edges = sm.edge_freelist(); - for (auto ed: unused_edges) + edge_descriptor ed = sm.edge_freelist(); + while(ed != sm.null_edge()){ + --ec; std::cout << ed << std::endl; - assert(ec == unused_edges.size()); + halfedge_descriptor hd = next(halfedge(ed,sm),sm); + ed = edge(hd,sm); + } + assert(ec == 0); } diff --git a/Surface_mesh/test/Surface_mesh/sm_remove.cpp b/Surface_mesh/test/Surface_mesh/sm_remove.cpp index 6744fbf77b2..5aadc4a132e 100644 --- a/Surface_mesh/test/Surface_mesh/sm_remove.cpp +++ b/Surface_mesh/test/Surface_mesh/sm_remove.cpp @@ -19,13 +19,13 @@ int main() Sm m; Sm::vertex_index u; - assert(m.number_of_vertices() == 0); + assert(m.num_vertices() == 0); assert(m.number_of_removed_vertices() == 0); for(int i=0; i < 10; i++){ u = m.add_vertex(Point_3(0,0,0)); m.remove_vertex(u); } - assert(m.number_of_vertices() == 0); + assert(m.num_vertices() == 1); assert(m.number_of_removed_vertices() == 1); @@ -34,23 +34,26 @@ int main() assert(! m.does_recycle_garbage()); m.add_vertex(Point_3(0,0,0)); - assert(m.number_of_vertices() == 1); + assert(m.num_vertices() == 2); assert(m.number_of_removed_vertices() == 1); m.set_recycle_garbage(true); m.add_vertex(Point_3(0,0,0)); - assert(m.number_of_vertices() == 2); + assert(m.num_vertices() == 2); assert(m.number_of_removed_vertices() == 0); - std::cout << m.number_of_vertices() << " " << m.number_of_removed_vertices() << std::endl; + std::cout << m.num_vertices() << " " << m.number_of_removed_vertices() << std::endl; // make sure all is OK when clearing the mesh - auto vconn = m.add_property_map("v:connectivity").first; - auto hconn = m.add_property_map("h:connectivity").first; - auto fconn = m.add_property_map("f:connectivity").first; - auto vpoint = m.add_property_map("v:point").first; + auto vconn = m.property_map("v:connectivity").first; + auto hconn = m.property_map("h:connectivity").first; + auto fconn = m.property_map("f:connectivity").first; + auto vpoint = m.property_map("v:point").first; + auto vremoved = m.property_map("v:removed").first; + auto eremoved = m.property_map("e:removed").first; + auto fremoved = m.property_map("f:removed").first; // first call to squat the first available position m.add_property_map("vprop_dummy"); @@ -71,10 +74,13 @@ int main() auto l_fprop = m.add_property_map("fprop").first; auto l_eprop = m.add_property_map("eprop").first; - auto l_vconn = m.add_property_map("v:connectivity").first; - auto l_hconn = m.add_property_map("h:connectivity").first; - auto l_fconn = m.add_property_map("f:connectivity").first; - auto l_vpoint = m.add_property_map("v:point").first; + auto l_vconn = m.property_map("v:connectivity").first; + auto l_hconn = m.property_map("h:connectivity").first; + auto l_fconn = m.property_map("f:connectivity").first; + auto l_vpoint = m.property_map("v:point").first; + auto l_vremoved = m.property_map("v:removed").first; + auto l_eremoved = m.property_map("e:removed").first; + auto l_fremoved = m.property_map("f:removed").first; assert( vconn == l_vconn ); assert( hconn == l_hconn ); @@ -89,10 +95,13 @@ int main() { m.clear(); - auto l_vconn = m.add_property_map("v:connectivity").first; - auto l_hconn = m.add_property_map("h:connectivity").first; - auto l_fconn = m.add_property_map("f:connectivity").first; - auto l_vpoint = m.add_property_map("v:point").first; + auto l_vconn = m.property_map("v:connectivity").first; + auto l_hconn = m.property_map("h:connectivity").first; + auto l_fconn = m.property_map("f:connectivity").first; + auto l_vpoint = m.property_map("v:point").first; + auto l_vremoved = m.property_map("v:removed").first; + auto l_eremoved = m.property_map("e:removed").first; + auto l_fremoved = m.property_map("f:removed").first; assert( vconn == l_vconn ); assert( hconn == l_hconn );