From a54e024a32c7008a5af4f22ee6c618f5a0b95615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 13 Sep 2023 17:59:52 +0200 Subject: [PATCH 1/5] start adding dynamic property maps with default WIP: need updates in all models of face graph --- .../boost/graph/properties_HalfedgeDS_base.h | 8 ++--- .../Non_manifold_feature_map.h | 1 + .../include/CGAL/Dynamic_property_map.h | 20 ++++++------ .../boost/graph/properties_Surface_mesh.h | 32 +++++++++---------- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/HalfedgeDS/include/CGAL/boost/graph/properties_HalfedgeDS_base.h b/HalfedgeDS/include/CGAL/boost/graph/properties_HalfedgeDS_base.h index d2a1f11653b..489caf5e3c7 100644 --- a/HalfedgeDS/include/CGAL/boost/graph/properties_HalfedgeDS_base.h +++ b/HalfedgeDS/include/CGAL/boost/graph/properties_HalfedgeDS_base.h @@ -139,13 +139,13 @@ get(PropertyTag p,CGAL_HDS_CLASS const& g, const Key& key) -#define DECLARE_HDS_DYNAMIC_PM(TAG, DESCRIPTOR) \ +#define DECLARE_HDS_DYNAMIC_PM(TAG, DESCRIPTOR) \ template \ typename boost::property_map::const_type \ -get(const TAG&, const CGAL_HDS_CLASS&) \ -{ \ +get(const TAG&, const CGAL_HDS_CLASS&, const T& dv = T()) \ +{ \ typedef typename boost::graph_traits< CGAL_HDS_CLASS >::DESCRIPTOR descriptor; \ - return internal::Dynamic_property_map(); \ + return internal::Dynamic_property_map(dv); \ } DECLARE_HDS_DYNAMIC_PM(dynamic_vertex_property_t, vertex_descriptor) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Non_manifold_feature_map.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Non_manifold_feature_map.h index 8177a02d178..51ca7e6587c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Non_manifold_feature_map.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Non_manifold_feature_map.h @@ -75,6 +75,7 @@ struct Non_manifold_feature_map halfedge_descriptor hd = halfedge(ed, pm); // an edge can be non-manifold only if both its vertices are non-manifold + // THIS IS NOT TRUE! if ( get(v_nm_id, source(hd, pm))==std::size_t(-1) || get(v_nm_id, target(hd, pm))==std::size_t(-1) ) continue; diff --git a/Property_map/include/CGAL/Dynamic_property_map.h b/Property_map/include/CGAL/Dynamic_property_map.h index a7dc48b5354..818d5e274fe 100644 --- a/Property_map/include/CGAL/Dynamic_property_map.h +++ b/Property_map/include/CGAL/Dynamic_property_map.h @@ -136,8 +136,8 @@ struct Dynamic_with_index : m_values() {} - Dynamic_with_index(std::size_t num_features) - : m_values( new std::vector(num_features) ) + Dynamic_with_index(std::size_t num_features, Value default_value = Value()) + : m_values( new std::vector(num_features, default_value) ) {} friend reference get(const Dynamic_with_index& m, const key_type& k) @@ -229,34 +229,34 @@ namespace CGAL { template typename boost::property_map >::const_type -get(const CGAL::dynamic_vertex_property_t&, const G&) +get(const CGAL::dynamic_vertex_property_t&, const G&, const T& default_value = T()) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - return internal::Dynamic_property_map(); + return internal::Dynamic_property_map(default_value); } template typename boost::property_map >::const_type -get(const CGAL::dynamic_halfedge_property_t&, const G&) +get(const CGAL::dynamic_halfedge_property_t&, const G&, const T& default_value = T()) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - return internal::Dynamic_property_map(); + return internal::Dynamic_property_map(default_value); } template typename boost::property_map >::const_type -get(const CGAL::dynamic_edge_property_t&, const G&) +get(const CGAL::dynamic_edge_property_t&, const G&, const T& default_value = T()) { typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - return internal::Dynamic_property_map(); + return internal::Dynamic_property_map(default_value); } template typename boost::property_map >::const_type -get(const CGAL::dynamic_face_property_t&, const G&) +get(const CGAL::dynamic_face_property_t&, const G&, const T& default_value = T()) { typedef typename boost::graph_traits::face_descriptor face_descriptor; - return internal::Dynamic_property_map(); + return internal::Dynamic_property_map(default_value); } template diff --git a/Surface_mesh/include/CGAL/boost/graph/properties_Surface_mesh.h b/Surface_mesh/include/CGAL/boost/graph/properties_Surface_mesh.h index 281c2b37093..43fc21f10b3 100644 --- a/Surface_mesh/include/CGAL/boost/graph/properties_Surface_mesh.h +++ b/Surface_mesh/include/CGAL/boost/graph/properties_Surface_mesh.h @@ -353,67 +353,67 @@ namespace CGAL { // get functions for dynamic properties of mutable Surface_mesh template typename boost::property_map, dynamic_vertex_property_t >::type -get(dynamic_vertex_property_t, Surface_mesh& sm) +get(dynamic_vertex_property_t, Surface_mesh& sm, const T& default_value = T()) { typedef typename boost::property_map, dynamic_vertex_property_t >::SMPM SMPM; typedef typename boost::property_map, dynamic_vertex_property_t >::type DPM; - return DPM(sm, new SMPM(sm.template add_property_map::Vertex_index, T>(std::string()).first)); + return DPM(sm, new SMPM(sm.template add_property_map::Vertex_index, T>(std::string(), default_value).first)); } template typename boost::property_map, dynamic_face_property_t >::type -get(dynamic_face_property_t, Surface_mesh& sm) +get(dynamic_face_property_t, Surface_mesh& sm, const T& default_value = T()) { typedef typename boost::property_map, dynamic_face_property_t >::SMPM SMPM; typedef typename boost::property_map, dynamic_face_property_t >::type DPM; - return DPM(sm, new SMPM(sm.template add_property_map::Face_index, T>(std::string()).first)); + return DPM(sm, new SMPM(sm.template add_property_map::Face_index, T>(std::string(), default_value).first)); } template typename boost::property_map, dynamic_edge_property_t >::type -get(dynamic_edge_property_t, Surface_mesh& sm) +get(dynamic_edge_property_t, Surface_mesh& sm, const T& default_value = T()) { typedef typename boost::property_map, dynamic_edge_property_t >::SMPM SMPM; typedef typename boost::property_map, dynamic_edge_property_t >::type DPM; - return DPM(sm, new SMPM(sm.template add_property_map::Edge_index, T>(std::string()).first)); + return DPM(sm, new SMPM(sm.template add_property_map::Edge_index, T>(std::string(), default_value).first)); } template typename boost::property_map, dynamic_halfedge_property_t >::type -get(dynamic_halfedge_property_t, Surface_mesh& sm) +get(dynamic_halfedge_property_t, Surface_mesh& sm, const T& default_value = T()) { typedef typename boost::property_map, dynamic_halfedge_property_t >::SMPM SMPM; typedef typename boost::property_map, dynamic_halfedge_property_t >::type DPM; - return DPM(sm, new SMPM(sm.template add_property_map::Halfedge_index, T>(std::string()).first)); + return DPM(sm, new SMPM(sm.template add_property_map::Halfedge_index, T>(std::string(), default_value).first)); } // get functions for dynamic properties of const Surface_mesh template typename boost::property_map, dynamic_vertex_property_t >::const_type -get(dynamic_vertex_property_t, const Surface_mesh& sm) +get(dynamic_vertex_property_t, const Surface_mesh& sm, const T& default_value = T()) { - return CGAL::internal::Dynamic_with_index::Vertex_index, T>(num_vertices(sm)); + return CGAL::internal::Dynamic_with_index::Vertex_index, T>(num_vertices(sm), default_value); } template typename boost::property_map, dynamic_face_property_t >::const_type -get(dynamic_face_property_t, const Surface_mesh& sm) +get(dynamic_face_property_t, const Surface_mesh& sm, const T& default_value = T()) { - return CGAL::internal::Dynamic_with_index::Face_index, T>(num_faces(sm)); + return CGAL::internal::Dynamic_with_index::Face_index, T>(num_faces(sm), default_value); } template typename boost::property_map, dynamic_halfedge_property_t >::const_type -get(dynamic_halfedge_property_t, const Surface_mesh& sm) +get(dynamic_halfedge_property_t, const Surface_mesh& sm, const T& default_value = T()) { - return CGAL::internal::Dynamic_with_index::Halfedge_index, T>(num_halfedges(sm)); + return CGAL::internal::Dynamic_with_index::Halfedge_index, T>(num_halfedges(sm), default_value); } template typename boost::property_map, dynamic_edge_property_t >::const_type -get(dynamic_edge_property_t, const Surface_mesh& sm) +get(dynamic_edge_property_t, const Surface_mesh& sm, const T& default_value = T()) { - return CGAL::internal::Dynamic_with_index::Edge_index, T>(num_edges(sm)); + return CGAL::internal::Dynamic_with_index::Edge_index, T>(num_edges(sm), default_value); } // implementation detail: required by Dynamic_property_map_deleter From f3c918171892f20dc52237cb9c7fdea320236c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 25 Mar 2024 10:18:34 +0100 Subject: [PATCH 2/5] add documentation --- BGL/doc/BGL/BGL.txt | 5 +++-- .../examples/Property_map/dynamic_properties.cpp | 12 ++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/BGL/doc/BGL/BGL.txt b/BGL/doc/BGL/BGL.txt index cf7e8a73903..96be1186c66 100644 --- a/BGL/doc/BGL/BGL.txt +++ b/BGL/doc/BGL/BGL.txt @@ -510,11 +510,12 @@ Dynamic property tags, such as `dynamic_vertex_property_t`, are a generalization value type of the dynamic property map, and a default value. `boost::property_map::%type` is used to obtain the type of the dynamic property map for a graph of type `G`, for a -dynamic property tag `T`. This type must be default constructible and assignable. +dynamic property tag `T`. This type must be assignable, and if no +default is provided it must be default constructible. As for ordinary properties, the function `%get()` is overloaded and serves for retrieving a property map for a given graph and dynamic property tag, as well as for retrieving a value for a given key and -property map. +property map. The default value is provided as third parameter. The following example shows how to attach a `string` property to vertices and a `double` value to the halfedges of a graph. diff --git a/Property_map/examples/Property_map/dynamic_properties.cpp b/Property_map/examples/Property_map/dynamic_properties.cpp index 6edbd4cfb9a..cb838c6096f 100644 --- a/Property_map/examples/Property_map/dynamic_properties.cpp +++ b/Property_map/examples/Property_map/dynamic_properties.cpp @@ -14,16 +14,24 @@ int main() CGAL::make_triangle(Point_3(0,0,0),Point_3(1,0,0),Point_3(1,1,0), mesh); typedef boost::property_map >::type VertexNameMap; - VertexNameMap vnm = get(CGAL::dynamic_vertex_property_t(), mesh); + VertexNameMap vnm = get(CGAL::dynamic_vertex_property_t(), mesh, std::string("default")); put(vnm, *(vertices(mesh).first), "Paris"); + assert(get(vnm, *(vertices(mesh).first))=="Paris"); + assert(get(vnm, *(std::next(vertices(mesh).first)))=="default"); + std::cout << get(vnm, *(vertices(mesh).first)) << std::endl; + std::cout << get(vnm, *(std::next(vertices(mesh).first))) << std::endl; typedef boost::property_map >::type TrafficDensityMap; - TrafficDensityMap tdm = get(CGAL::dynamic_halfedge_property_t(), mesh); + TrafficDensityMap tdm = get(CGAL::dynamic_halfedge_property_t(), mesh, -1.); put(tdm, *(halfedges(mesh).first), 0.7); + assert(get(tdm, *(halfedges(mesh).first))==0.7); + assert(get(tdm, *(std::next(halfedges(mesh).first)))==-1.); + std::cout << get(tdm, *(halfedges(mesh).first)) << std::endl; + std::cout << get(tdm, *(std::next(halfedges(mesh).first))) << std::endl; return 0; } From baf084950b927e2b1dec3c4c19ce564286152a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 25 Mar 2024 10:45:37 +0100 Subject: [PATCH 3/5] use default value for dynamic maps --- .../angle_and_area_smoothing.h | 9 +-------- .../internal/Smoothing/mesh_smoothing_impl.h | 5 +---- .../internal/Snapping/snap.h | 12 +++++------- .../Polygon_mesh_processing/manifoldness.h | 19 ++++--------------- .../repair_degeneracies.h | 2 +- .../Polygon_mesh_processing/stitch_borders.h | 2 +- 6 files changed, 13 insertions(+), 36 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_and_area_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_and_area_smoothing.h index e51999b9c54..5db4a1e29fc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_and_area_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_and_area_smoothing.h @@ -209,14 +209,7 @@ void angle_and_area_smoothing(const FaceRange& faces, const bool use_Delaunay_flips = choose_parameter(get_parameter(np, internal_np::use_Delaunay_flips), true); VCMap vcmap = choose_parameter(get_parameter(np, internal_np::vertex_is_constrained), - get(Vertex_property_tag(), tmesh)); - - // If it's the default vcmap, manually set everything to false because the dynamic pmap has no default initialization - if((std::is_same::value)) - { - for(vertex_descriptor v : vertices(tmesh)) - put(vcmap, v, false); - } + get(Vertex_property_tag(), tmesh, false)); ECMap ecmap = choose_parameter(get_parameter(np, internal_np::edge_is_constrained), Static_boolean_property_map()); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/mesh_smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/mesh_smoothing_impl.h index e15ae718823..54b15c7777a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/mesh_smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/mesh_smoothing_impl.h @@ -154,11 +154,8 @@ public: typedef typename boost::property_map::type Marked_edges_map; - Marked_edges_map marks = get(Edge_property_tag(), mesh_); + Marked_edges_map marks = get(Edge_property_tag(), mesh_, false); - // dynamic pmaps do not have default values... - for(edge_descriptor e : edges(mesh_)) - put(marks, e, false); for(edge_descriptor e : edge_range) put(marks, e, true); #ifdef CGAL_PMP_SMOOTHING_DEBUG diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h index b7c0d086c5c..6edbc0f1c3c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h @@ -104,9 +104,7 @@ void simplify_range(HalfedgeRange& halfedge_range, typedef CGAL::dynamic_halfedge_property_t Halfedge_bool_tag; typedef typename boost::property_map::type Range_halfedges; - Range_halfedges range_halfedges = get(Halfedge_bool_tag(), tm); - for(halfedge_descriptor h : halfedge_range) - put(range_halfedges, h, true); + Range_halfedges range_halfedges = get(Halfedge_bool_tag(), tm, false); CGAL_postcondition_code(const std::size_t initial_n = halfedge_range.size();) @@ -1233,10 +1231,10 @@ std::size_t snap_non_conformal(HalfedgeRange& halfedge_range_A, // We keep in memory pairs of source/target edges that are stitchable after vertex-vertex snapping // --> these halfedges should not be considered as targets in non-conformal snapping // Similarly, matching vertices whose incident edges have matching directions are also locked - Locked_vertices locked_vertices_A = get(Vertex_bool_tag(), tm_A); - Locked_vertices locked_vertices_B = get(Vertex_bool_tag(), tm_B); - Locked_halfedges locked_halfedges_A = get(Halfedge_bool_tag(), tm_A); - Locked_halfedges locked_halfedges_B = get(Halfedge_bool_tag(), tm_B); + Locked_vertices locked_vertices_A = get(Vertex_bool_tag(), tm_A, false); + Locked_vertices locked_vertices_B = get(Vertex_bool_tag(), tm_B, false); + Locked_halfedges locked_halfedges_A = get(Halfedge_bool_tag(), tm_A, false); + Locked_halfedges locked_halfedges_B = get(Halfedge_bool_tag(), tm_B, false); std::vector > locked_vertices; std::vector locked_halfedges_A_vector, locked_halfedges_B_vector; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/manifoldness.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/manifoldness.h index de45ca3150e..46ac4ed6cb6 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/manifoldness.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/manifoldness.h @@ -58,9 +58,7 @@ bool is_non_manifold_vertex(typename boost::graph_traits::vertex_de typedef typename boost::property_map::const_type Visited_halfedge_map; // Dynamic pmaps do not have default initialization values (yet) - Visited_halfedge_map visited_halfedges = get(Halfedge_property_tag(), pm); - for(halfedge_descriptor h : halfedges(pm)) - put(visited_halfedges, h, false); + Visited_halfedge_map visited_halfedges = get(Halfedge_property_tag(), pm, false); std::size_t incident_null_faces_counter = 0; for(halfedge_descriptor h : halfedges_around_target(v, pm)) @@ -324,20 +322,11 @@ OutputIterator non_manifold_vertices(const PolygonMesh& pm, typedef CGAL::dynamic_halfedge_property_t Halfedge_property_tag; typedef typename boost::property_map::const_type Visited_halfedge_map; - Known_manifold_vertex_map known_nm_vertices = get(Vertex_bool_tag(), pm); - Visited_vertex_map visited_vertices = get(Vertex_halfedge_tag(), pm); - Visited_halfedge_map visited_halfedges = get(Halfedge_property_tag(), pm); - halfedge_descriptor null_h = boost::graph_traits::null_halfedge(); - // Dynamic pmaps do not have default initialization values (yet) - for(vertex_descriptor v : vertices(pm)) - { - put(known_nm_vertices, v, false); - put(visited_vertices, v, null_h); - } - for(halfedge_descriptor h : halfedges(pm)) - put(visited_halfedges, h, false); + Known_manifold_vertex_map known_nm_vertices = get(Vertex_bool_tag(), pm, false); + Visited_vertex_map visited_vertices = get(Vertex_halfedge_tag(), pm, null_h); + Visited_halfedge_map visited_halfedges = get(Halfedge_property_tag(), pm, false); for(halfedge_descriptor h : halfedges(pm)) { diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index c71a5d4c806..1dde0a5b20d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -639,7 +639,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, // Vertex property map that combines the VCM and the fact that extremities of a constrained edge should be constrained typedef CGAL::dynamic_vertex_property_t Vertex_property_tag; typedef typename boost::property_map::type DVCM; - DVCM vcm = get(Vertex_property_tag(), tmesh); + DVCM vcm = get(Vertex_property_tag(), tmesh, false); // parameters const double cap_threshold = diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h index e30f95fd289..343007a83b2 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h @@ -190,7 +190,7 @@ struct Boundary_cycle_rep_maintainer Boundary_cycle_rep_maintainer(PolygonMesh& pmesh) : m_pmesh(pmesh) { - m_candidate_halfedges = get(Candidate_tag(), pmesh); + m_candidate_halfedges = get(Candidate_tag(), pmesh, false); } public: From a34120d817e062c8b1023ffde3ab144002dff5e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 27 Mar 2024 08:21:34 +0100 Subject: [PATCH 4/5] fix warning --- .../CGAL/Polygon_mesh_processing/angle_and_area_smoothing.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_and_area_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_and_area_smoothing.h index 5db4a1e29fc..0166c85e58f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_and_area_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_and_area_smoothing.h @@ -134,7 +134,6 @@ void angle_and_area_smoothing(const FaceRange& faces, TriangleMesh& tmesh, const NamedParameters& np = parameters::default_values()) { - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::edge_descriptor edge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; From e9fefbbacade9e4b15194e33038421e4e0b6b691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 27 Mar 2024 10:12:02 +0100 Subject: [PATCH 5/5] disable generic overload --- .../CGAL/boost/graph/properties_HalfedgeDS_base.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/HalfedgeDS/include/CGAL/boost/graph/properties_HalfedgeDS_base.h b/HalfedgeDS/include/CGAL/boost/graph/properties_HalfedgeDS_base.h index 489caf5e3c7..a39cfd90715 100644 --- a/HalfedgeDS/include/CGAL/boost/graph/properties_HalfedgeDS_base.h +++ b/HalfedgeDS/include/CGAL/boost/graph/properties_HalfedgeDS_base.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace CGAL { @@ -126,11 +127,20 @@ typename boost::property_map::type get(PropertyTag,CGAL_HDS_CLASS&) { return typename boost::property_map::type(); } + // generalized 3-ary get functions -template +template> && + !std::is_same_v> && + !std::is_same_v> && + !std::is_same_v> + > +> typename boost::property_traits< typename boost::property_map::type >::reference get(PropertyTag p,CGAL_HDS_CLASS& g, const Key& key) -{ return get(get(p, g), key); } +{ + return get(get(p, g), key); +} template typename boost::property_traits< typename boost::property_map::const_type >::reference