@afabri :
For the cell with cached circumcenter we use std::optional<Point> instead of a pointer to a 3D point and it should probably be a std::unique_ptr.
@lrineau's proposal is the following:
If the TDS can add property maps, a cell property map of Point_3 is conditionally added. At first, it is the null property map (with nullptr). If the member function t.add_circumcenter_property_map(), then the property map is created, the member function dual(Cell_handle) uses it.
See commit 4b62935:
- I have created a mixing class (base class with CRTP):
|
template <typename Derived_triangulation, typename Geom_traits, typename Tds> |
|
class Cache_cell_circumcenter_with_property_maps |
|
{ |
|
public: |
|
void add_circumcenter_property_map() { |
|
if constexpr(Tds::has_property_maps) { |
|
using Point = typename Geom_traits::Point_3; |
|
this->circumcenter_pmap = static_cast<Derived_triangulation*>(this) |
|
->tds() |
|
.template add_property_map<Cell_index, std::optional<Point>>() |
|
.first; |
|
} |
|
} |
|
protected: |
|
static auto get_property_point_map_type() { |
|
if constexpr(Tds::has_property_maps) { |
|
using Point = typename Geom_traits::Point_3; |
|
using Concurrency_tag = typename Tds::Concurrency_tag; |
|
return Property_map<typename Tds::Cell_index, std::optional<Point>, Concurrency_tag>{}; |
|
} else { |
|
return Null_tag{}; |
|
} |
|
} |
|
using Circumcenter_property_map = decltype(get_property_point_map_type()); |
|
|
|
CGAL_NO_UNIQUE_ADDRESS Circumcenter_property_map circumcenter_pmap; |
|
}; |
|
|
|
} /// namespace CGAL |
- Delaunay_3 and Regular_3 use that mixing:
|
template <class Gt, class Tds_> |
|
using Delaunay_triangulation_3_tds = typename Default::Get< |
|
Tds_, |
|
Triangulation_data_structure_3<Triangulation_vertex_base_3<Gt>, Delaunay_triangulation_cell_base_3<Gt>>>::type; |
|
|
|
// There is a specialization Delaunay_triangulation_3<Gt, Tds, Fast_location> |
|
// defined in <CGAL/Triangulation_3/internal/Delaunay_triangulation_hierarchy_3.h>. |
|
|
|
// Here is the specialization Delaunay_triangulation_3<Gt, Tds>, with three |
|
// arguments, that is if Location_policy being the default value 'Default'. |
|
template <class Gt, class Tds_, class Lock_data_structure_> |
|
class Delaunay_triangulation_3<Gt, Tds_, Default, Lock_data_structure_> |
|
: public Triangulation_3< |
|
Gt, |
|
Delaunay_triangulation_3_tds<Gt, Tds_>, |
|
Lock_data_structure_> |
|
, public Cache_cell_circumcenter_with_property_maps< |
|
Delaunay_triangulation_3<Gt, Tds_, Default, Lock_data_structure_>, |
|
Gt, |
|
Delaunay_triangulation_3_tds<Gt, Tds_>> |
|
{ |
|
typedef Delaunay_triangulation_3_tds<Gt, Tds_> Tds; |
- the
dual(Cell_handle) member function use that property map is it is created:
|
template < class Gt, class Tds, class Lds > |
|
typename Delaunay_triangulation_3<Gt,Tds,Default,Lds>::Point |
|
Delaunay_triangulation_3<Gt,Tds,Default,Lds>:: |
|
dual(Cell_handle c) const |
|
{ |
|
CGAL_precondition(dimension()==3); |
|
CGAL_precondition(! is_infinite(c)); |
|
if constexpr (Tds::has_property_maps) { |
|
if(this->circumcenter_pmap) { |
|
auto& opt_point = this->circumcenter_pmap[c->index()]; |
|
if(opt_point.has_value()) |
|
return *opt_point; |
|
else { |
|
opt_point = construct_circumcenter(point(c, 0), point(c, 1), |
|
point(c, 2), point(c, 3)); |
|
return *opt_point; |
|
} |
|
} |
|
return construct_circumcenter(point(c, 0), point(c, 1), |
|
point(c, 2), point(c, 3)); |
|
|
|
} else { |
|
return c->circumcenter(geom_traits()); |
|
} |
|
} |
TODO: