new version, after review

This commit is contained in:
Laurent Rineau 2024-06-28 02:09:09 +02:00
parent 49fe0400ac
commit e20cee0fcb
19 changed files with 560 additions and 291 deletions

View File

@ -6,7 +6,7 @@ The concept `ConstrainedDelaunayTriangulationCellBase_3` refines the concept
`TriangulationCellBase_3` and is the base cell class for
the `CGAL::make_constrained_Delaunay_triangulation_3()` function template.
\cgalRefines{TriangulationCellBase_3}
\cgalRefines{TriangulationCellBase_3, BaseWithTimeStamp}
\cgalHasModelsBegin
\cgalHasModels{CGAL::Constrained_Delaunay_triangulation_cell_base_3}

View File

@ -6,14 +6,12 @@ The concept `ConstrainedDelaunayTriangulationVertexBase_3` refines the concept
`TriangulationVertexBase_3` and is the base vertex class for
the `CGAL::make_constrained_Delaunay_triangulation_3()` function template.
\cgalRefines{TriangulationVertexBase_3}
\cgalRefines{TriangulationVertexBase_3, BaseWithTimeStamp}
\cgalHasModelsBegin
\cgalHasModels{CGAL::Constrained_Delaunay_triangulation_vertex_base_3}
\cgalHasModelsEnd
\todo CDT_3 also requires `time_stamp()` but it is not documented in the concept.
\sa `ConstrainedDelaunayTriangulationCellBase_3`
*/

View File

@ -8,6 +8,10 @@ namespace CGAL {
This chapter describes the ...
* \todo Explain what is a CDT. Why a given input, like a polyhedron, might not admit a constrained Delaunay triangulation.
* Explain "conforming to the faces of a polygon mesh".
*
\section CT_3_definitions Definitions
Section on definitions here ...

View File

@ -35,8 +35,9 @@
\cgalClassifedRefPages
`CGAL::make_constrained_Delaunay_triangulation_3()` is the main function to create
a constrained Delaunay triangulation in 3D.
The type alias `CGAL::default_constrained_triangulation_3_t<Kernel>` is the default
a constrained Delaunay triangulation in 3D, an instance of the class template
`CGAL::Constrained_Delaunay_triangulation_3`.
The type alias `CGAL::default_constrained_Delaunay_triangulation_3_t<Kernel>` is the default
constrained triangulation class.
\cgalCRPSection{Functions Templates}
@ -51,7 +52,8 @@ constrained triangulation class.
\cgalCRPSubsection{Class Templates}
- `CGAL::Default_constrained_triangulation_3`
- `CGAL::Constrained_Delaunay_triangulation_3<Traits, Triangulation>`
- `CGAL::Default_constrained_Delaunay_triangulation_3`
- `CGAL::Constrained_Delaunay_triangulation_vertex_base_3`
- `CGAL::Constrained_Delaunay_triangulation_cell_base_3`
*/

View File

@ -6,7 +6,6 @@
#include <algorithm>
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
using Tr = CGAL::default_constrained_triangulation_3_t<K>;
int main(int argc, char* argv[])
{
@ -20,17 +19,12 @@ int main(int argc, char* argv[])
std::cout << "Read " << mesh.number_of_vertices() << " vertices and "
<< mesh.number_of_faces() << " faces" << std::endl;
Tr triangulation = CGAL::make_constrained_Delaunay_triangulation_3<Tr>(mesh);
auto cdt = CGAL::make_constrained_Delaunay_triangulation_3(mesh);
std::cout << "Number of vertices in the CDT: "
<< triangulation.number_of_vertices() << '\n'
<< cdt.triangulation().number_of_vertices() << '\n'
<< "Number of constrained facets in the CDT: "
<< std::count_if(triangulation.finite_facets_begin(),
triangulation.finite_facets_end(),
[](const auto& f) {
auto [cell_handle, facet_index] = f;
return cell_handle->cdt_3_data().is_facet_constrained(facet_index);
}) << std::endl;
<< cdt.number_of_constrained_facets() << '\n';
// CGAL::draw(cdt.triangulation());
}

View File

@ -26,7 +26,8 @@ int main(int argc, char* argv[])
std::cerr << "Error: cannot read file " << filename << std::endl;
return EXIT_FAILURE;
}
Tr tr = CGAL::make_constrained_Delaunay_triangulation_3<Tr>(mesh);
auto cdt = CGAL::make_constrained_Delaunay_triangulation_3(mesh);
auto tr = std::move(cdt).triangulation();
std::cout << "Number of vertices in tr: "
<< tr.number_of_vertices() << std::endl;
CGAL::tetrahedral_isotropic_remeshing(tr, 0.1,

View File

@ -100,52 +100,52 @@ protected:
class Insert_in_conflict_visitor
{
Conforming_Delaunay_triangulation_3<T_3>& self;
Conforming_Delaunay_triangulation_3<T_3>* self;
public:
Insert_in_conflict_visitor(Conforming_Delaunay_triangulation_3& self) : self(self) {}
Insert_in_conflict_visitor(Conforming_Delaunay_triangulation_3* self) : self(self) {}
template <class InputIterator>
void process_cells_in_conflict(InputIterator cell_it, InputIterator end) {
auto d = self.tr.dimension();
auto d = self->tr().dimension();
for( ; cell_it != end; ++cell_it )
for( int i = 0; i < d; ++i )
for( int j = i+1; j <= d; ++j ) {
auto v1 = (*cell_it)->vertex(i);
auto v2 = (*cell_it)->vertex(j);
if(self.tr.is_infinite(v1) || self.tr.is_infinite(v2)) continue;
if(self.use_finite_edges_map()) {
if(self->tr().is_infinite(v1) || self->tr().is_infinite(v2)) continue;
if(self->use_finite_edges_map()) {
if(v1 > v2) std::swap(v1, v2);
auto v1_index = v1->time_stamp();
[[maybe_unused]] auto nb_erased = self.all_finite_edges[v1_index].erase(v2);
if constexpr (cdt_3_can_use_cxx20_format()) if(self.debug_finite_edges_map() && nb_erased > 0) {
std::cerr << cdt_3_format("erasing edge {} {}\n", self.display_vert((std::min)(v1, v2)),
self.display_vert((std::max)(v1, v2)));
[[maybe_unused]] auto nb_erased = self->all_finite_edges[v1_index].erase(v2);
if constexpr (cdt_3_can_use_cxx20_format()) if(self->debug_finite_edges_map() && nb_erased > 0) {
std::cerr << cdt_3_format("erasing edge {} {}\n", self->display_vert((std::min)(v1, v2)),
self->display_vert((std::max)(v1, v2)));
}
}
auto [contexts_begin, contexts_end] =
self.constraint_hierarchy.contexts_range(v1, v2);
self->constraint_hierarchy.contexts_range(v1, v2);
if(contexts_begin != contexts_end) {
self.add_to_subconstraints_to_conform(v1, v2,
self->add_to_subconstraints_to_conform(v1, v2,
contexts_begin->id());
}
}
}
void after_insertion(Vertex_handle v) const {
if(!self.use_finite_edges_map()) return;
CGAL_assertion(self.dimension() > 1);
self.incident_edges(v, boost::make_function_output_iterator([this](Edge e) { self.new_edge(e); }));
self.incident_cells(v, boost::make_function_output_iterator([this, v](Cell_handle c) {
if(!self->use_finite_edges_map()) return;
CGAL_assertion(self->dimension() > 1);
self->incident_edges(v, boost::make_function_output_iterator([this](Edge e) { self->new_edge(e); }));
self->incident_cells(v, boost::make_function_output_iterator([this, v](Cell_handle c) {
auto v_index = c->index(v);
if(self.dimension() == 2) {
auto j = self.cw(v_index);
auto k = self.ccw(v_index);
self.new_edge(Edge(c, j, k));
if(self->dimension() == 2) {
auto j = self->cw(v_index);
auto k = self->ccw(v_index);
self->new_edge(Edge(c, j, k));
} else {
for(int i = 0; i < 3; ++i) {
auto j = self.vertex_triple_index(v_index, i);
auto k = self.vertex_triple_index(v_index, self.cw(i));
self.new_edge(Edge(c, j, k));
auto j = self->vertex_triple_index(v_index, i);
auto k = self->vertex_triple_index(v_index, self->cw(i));
self->new_edge(Edge(c, j, k));
}
}
}));
@ -166,7 +166,7 @@ protected:
}
Vertex_handle insert_in_triangulation(const Point& p, Locate_type lt, Cell_handle c, int li, int lj) {
return self.insert_impl_do_not_split(p, lt, c, li, lj, *this);
return self->insert_impl_do_not_split(p, lt, c, li, lj, *this);
}
};
@ -178,7 +178,7 @@ protected:
Constraint_id id) {
const auto pair = make_subconstraint(va, vb);
#if CGAL_DEBUG_CDT_3 & 32
std::cerr << "tr.subconstraints_to_conform.push("
std::cerr << "tr().subconstraints_to_conform.push("
<< display_subcstr(pair) << ")\n";
#endif // CGAL_DEBUG_CDT_3
subconstraints_to_conform.push({pair, id});
@ -197,7 +197,7 @@ protected:
pair_of_vertices_to_cid.emplace(make_sorted_pair(va, vb), c_id);
// traverse all the vertices along [va, vb] and add pairs of consecutive
// vertices as sub-constraints.
std::for_each(tr.segment_traverser_simplices_begin(va, vb), tr.segment_traverser_simplices_end(),
std::for_each(tr().segment_traverser_simplices_begin(va, vb), tr().segment_traverser_simplices_end(),
[&, prev = Vertex_handle{}](auto simplex) mutable {
// std::cerr << "- " << oformat(simplex, With_point_tag{}) << '\n';
if(simplex.dimension() == 0) {
@ -221,8 +221,8 @@ protected:
void new_edge(Edge e)
{
if(!update_all_finite_edges_) return;
auto [v1, v2] = make_sorted_pair(tr.vertices(e));
if(tr.is_infinite(v1) || tr.is_infinite(v2))
auto [v1, v2] = make_sorted_pair(tr().vertices(e));
if(tr().is_infinite(v1) || tr().is_infinite(v2))
return;
[[maybe_unused]] auto [_, inserted] = all_finite_edges[v1->time_stamp()].insert(v2);
if constexpr (cdt_3_can_use_cxx20_format()) if (debug_finite_edges_map() && inserted) {
@ -232,7 +232,7 @@ protected:
}
void new_cell(Cell_handle c) {
auto d = tr.dimension();
auto d = tr().dimension();
for(int i = 0; i < d; ++i) {
for(int j = i+1; j <= d; ++j) {
new_edge(Edge(c, i, j));
@ -252,32 +252,32 @@ protected:
Vertex_handle insert_impl_do_not_split(const Point &p, Locate_type lt, Cell_handle c,
int li, int lj, Visitor& visitor)
{
switch (tr.dimension()) {
switch (tr().dimension()) {
case 3: {
typename T_3::Conflict_tester_3 tester(p, this);
auto v = tr.insert_in_conflict(p, lt, c, li, lj, tester,
auto v = tr().insert_in_conflict(p, lt, c, li, lj, tester,
visitor);
new_vertex(v);
return v;
} // dim 3
case 2: {
typename T_3::Conflict_tester_2 tester(p, this);
auto v = tr.insert_in_conflict(p, lt, c, li, lj, tester, visitor);
auto v = tr().insert_in_conflict(p, lt, c, li, lj, tester, visitor);
if(use_finite_edges_map()) {
new_vertex(v);
tr.incident_edges(v, boost::make_function_output_iterator([&](Edge e) { this->new_edge(e); }));
tr().incident_edges(v, boost::make_function_output_iterator([&](Edge e) { this->new_edge(e); }));
}
return v;
} // dim 2
default:
// dimension <= 1
// Do not use the generic insert.
auto v = tr.insert(p, c);
auto v = tr().insert(p, c);
if(use_finite_edges_map()) {
new_vertex(v);
all_finite_edges.clear();
if (debug_finite_edges_map()) std::cerr << "all_finite_edges.clear()\n";
for(auto e: tr.all_edges()) {
for(auto e: tr().all_edges()) {
new_edge(e);
}
}
@ -402,7 +402,7 @@ public:
Locate_type lt;
int li, lj;
Cell_handle c = tr.locate(p, lt, li, lj, start);
Cell_handle c = tr().locate(p, lt, li, lj, start);
return insert(p, lt, c, li, lj);
}
@ -415,7 +415,7 @@ public:
bool is_edge(Vertex_handle va, Vertex_handle vb) const {
const bool is_edge_v1 =
((debug_finite_edges_map() && use_finite_edges_map()) || !use_finite_edges_map()) && tr.tds().is_edge(va, vb);
((debug_finite_edges_map() && use_finite_edges_map()) || !use_finite_edges_map()) && tr().tds().is_edge(va, vb);
if(use_finite_edges_map() && va > vb) std::swap(va, vb);
const auto va_index = va->time_stamp();
@ -518,7 +518,7 @@ public:
} result;
const auto vector_of_encroaching_vertices = encroaching_vertices(va, vb);
for(auto v: vector_of_encroaching_vertices) {
const auto dist = CGAL::approximate_sqrt(squared_distance(tr.point(v), Line{tr.point(va), tr.point(vb)}));
const auto dist = CGAL::approximate_sqrt(squared_distance(tr().point(v), Line{tr().point(va), tr().point(vb)}));
if(dist < result.min_dist) {
result = Result{dist, v};
}
@ -534,7 +534,7 @@ public:
if (!this->is_edge(sc.first.first, sc.first.second)) {
const auto v0 = sc.first.first;
const auto v1 = sc.first.second;
out << "2 " << this->tr.point(v0) << " " << this->tr.point(v1)
out << "2 " << this->tr().point(v0) << " " << this->tr().point(v1)
<< '\n';
any_missing_segment = true;
}
@ -548,7 +548,7 @@ public:
[this, &out](const auto &sc) {
const auto v0 = sc.first.first;
const auto v1 = sc.first.second;
out << "2 " << this->tr.point(v0) << " " << this->tr.point(v1) << '\n';
out << "2 " << this->tr().point(v0) << " " << this->tr().point(v1) << '\n';
});
}
@ -587,7 +587,7 @@ protected:
continue;
}
#if CGAL_DEBUG_CDT_3 & 32
std::cerr << "tr.subconstraints_to_conform.pop()="
std::cerr << "tr().subconstraints_to_conform.pop()="
<< display_subcstr(subconstraint) << "\n";
#endif // CGAL_DEBUG_CDT_3
conform_subconstraint(subconstraint, constraint_id, visitor);
@ -603,7 +603,7 @@ protected:
const Vertex_handle vb = subconstraint.second;
Locate_type lt;
int li, lj;
const Cell_handle c = tr.locate(steiner_pt, lt, li, lj, hint);
const Cell_handle c = tr().locate(steiner_pt, lt, li, lj, hint);
const Vertex_handle v = visitor.insert_in_triangulation(steiner_pt, lt, c, li, lj);
v->cdt_3_data().set_vertex_type(CDT_3_vertex_type::STEINER_ON_EDGE);
if(lt != T_3::VERTEX) {
@ -713,18 +713,18 @@ protected:
};
auto encroaching_vertices(Vertex_handle va, Vertex_handle vb) const {
auto& gt = tr.geom_traits();
auto& gt = tr().geom_traits();
auto angle_functor = gt.angle_3_object();
const auto& pa = tr.point(va);
const auto& pb = tr.point(vb);
const auto& pa = tr().point(va);
const auto& pb = tr().point(vb);
namespace bc = boost::container;
bc::flat_set<Vertex_handle, std::less<Vertex_handle>,
bc::small_vector<Vertex_handle, 256>>
encroaching_vertices;
auto register_vertex = [this,&encroaching_vertices](Vertex_handle v) {
if(tr.is_infinite(v)) return;
if(tr().is_infinite(v)) return;
// std::cerr << "register_vertex " << display_vert(v) << '\n';
encroaching_vertices.insert(v);
};
@ -733,7 +733,7 @@ protected:
std::cerr << " - " << IO::oformat(simplex, With_point_tag{}) << '\n';
#endif // CGAL_DEBUG_CDT_3
auto visit_cell = [&](Cell_handle cell) {
for(int i = 0, end = this->tr.dimension() + 1; i < end; ++i) {
for(int i = 0, end = this->tr().dimension() + 1; i < end; ++i) {
const auto v = cell->vertex(i);
register_vertex(v);
}
@ -746,23 +746,23 @@ protected:
case 2: {
const auto [cell, facet_index] = static_cast<Facet>(simplex);
visit_cell(cell);
if(tr.dimension() > 2) {
const auto [other_cell, other_index] = tr.mirror_facet({cell, facet_index});
if(tr().dimension() > 2) {
const auto [other_cell, other_index] = tr().mirror_facet({cell, facet_index});
register_vertex(other_cell->vertex(other_index));
}
break;
}
case 1: {
auto edge = static_cast<Edge>(simplex);
if(tr.dimension() < 3) {
if(tr().dimension() < 3) {
auto [cell, i, j] = edge;
visit_cell(cell);
if(tr.dimension() < 2) break;
if(tr().dimension() < 2) break;
auto neighbor_cell = cell->neighbor(3 - i - j);
visit_cell(neighbor_cell);
break;
}
auto circ = tr.incident_cells(edge);
auto circ = tr().incident_cells(edge);
CGAL_assertion(circ != nullptr);
const auto end = circ;
do {
@ -782,7 +782,7 @@ protected:
default: CGAL_unreachable();
} // end switch
};
std::for_each(tr.segment_traverser_simplices_begin(va, vb), tr.segment_traverser_simplices_end(),
std::for_each(tr().segment_traverser_simplices_begin(va, vb), tr().segment_traverser_simplices_end(),
fill_encroaching_vertices);
auto vector_of_encroaching_vertices = encroaching_vertices.extract_sequence();
#if CGAL_DEBUG_CDT_3 & 0x10
@ -798,13 +798,13 @@ protected:
[va, vb, pa, pb, &angle_functor, this](Vertex_handle v) {
if(va == v || vb == v) return true;
return angle_functor(pa,
this->tr.point(v),
this->tr().point(v),
pb) == ACUTE;
});
#if CGAL_DEBUG_CDT_3 & 0x10
std::cerr << " -> vector_of_encroaching_vertices (after filter):\n";
std::for_each(vector_of_encroaching_vertices.begin(), end, [&](Vertex_handle v) {
std::cerr << " " << this->display_vert(v) << " angle " << approximate_angle(pa, this->tr.point(v), pb)
std::cerr << " " << this->display_vert(v) << " angle " << approximate_angle(pa, this->tr().point(v), pb)
<< '\n';
});
#endif // CGAL_DEBUG_CDT_3
@ -815,7 +815,7 @@ protected:
Construct_Steiner_point_return_type
construct_Steiner_point(Constraint_id constraint_id, Subconstraint subconstraint)
{
auto& gt = tr.geom_traits();
auto& gt = tr().geom_traits();
auto compare_angle_functor = gt.compare_angle_3_object();
auto vector_functor = gt.construct_vector_3_object();
auto midpoint_functor = gt.construct_midpoint_3_object();
@ -826,11 +826,11 @@ protected:
const Vertex_handle va = subconstraint.first;
const Vertex_handle vb = subconstraint.second;
const auto& pa = tr.point(va);
const auto& pb = tr.point(vb);
const auto& pa = tr().point(va);
const auto& pb = tr().point(vb);
const auto [orig_va, orig_vb] = constraint_extremities(constraint_id);
const auto& orig_pa = tr.point(orig_va);
const auto& orig_pb = tr.point(orig_vb);
const auto& orig_pa = tr().point(orig_va);
const auto& orig_pb = tr().point(orig_vb);
if(this->dimension() < 2) {
std::cerr << "dim < 2: midpoint\n";
@ -849,8 +849,8 @@ protected:
vector_of_encroaching_vertices.begin(), vector_of_encroaching_vertices.end(),
[pa, pb, &compare_angle_functor, this](Vertex_handle v1,
Vertex_handle v2) {
return compare_angle_functor(pa, this->tr.point(v1), pb,
pa, this->tr.point(v2), pb) == SMALLER;
return compare_angle_functor(pa, this->tr().point(v1), pb,
pa, this->tr().point(v2), pb) == SMALLER;
});
CGAL_assertion(reference_vertex_it != vector_of_encroaching_vertices.end());
#if CGAL_CDT_3_DEBUG_CONFORMING
@ -858,7 +858,7 @@ protected:
<< '\n';
#endif // CGAL_CDT_3_DEBUG_CONFORMING
const auto reference_vertex = *reference_vertex_it;
const auto& reference_point = tr.point(reference_vertex);
const auto& reference_point = tr().point(reference_vertex);
const auto vector_ab = vector_functor(pa, pb);
@ -930,7 +930,9 @@ protected:
}
protected:
T_3& tr = *this;
T_3& tr() { return *this; };
const T_3& tr() const { return *this; };
Compare_vertex_handle comp = {this};
Constraint_hierarchy constraint_hierarchy = {comp};
Bbox_3 bbox{};
@ -938,10 +940,11 @@ protected:
std::optional<double> max_bbox_edge_length;
using Pair_of_vertex_handles = std::pair<Vertex_handle, Vertex_handle>;
std::map<Pair_of_vertex_handles, Constraint_id> pair_of_vertices_to_cid;
Insert_in_conflict_visitor insert_in_conflict_visitor = {*this};
Insert_in_conflict_visitor insert_in_conflict_visitor = {this};
std::stack<std::pair<Subconstraint, Constraint_id> >
subconstraints_to_conform;
using Stack_info = std::pair<Subconstraint, Constraint_id>;
using Subconstraints_to_conform = std::stack<Stack_info, std::vector<Stack_info>>;
Subconstraints_to_conform subconstraints_to_conform;
std::vector<std::unordered_set<Vertex_handle>> all_finite_edges;
bool update_all_finite_edges_ = false;
@ -951,8 +954,8 @@ protected:
update_all_finite_edges_ = true;
if(use_finite_edges_map()) {
all_finite_edges.clear();
all_finite_edges.resize(tr.number_of_vertices()+1);
for(auto e: tr.all_edges()) {
all_finite_edges.resize(tr().number_of_vertices()+1);
for(auto e: tr().all_edges()) {
new_edge(e);
}
}

View File

@ -40,7 +40,7 @@ namespace CGAL {
* @cgalModels{ConstrainedDelaunayTriangulationCellBase_3, SimplicialMeshCellBase_3, RemeshingCellBase_3}
*
* \note This cell base class also models the `SimplicialMeshCellBase_3` and `RemeshingCellBase_3` concepts, allowing the use of functionality from \ref Chapter_Tetrahedral_Remeshing "Tetrahedral Remeshing" and \ref Chapter_3D_Simplicial_Mesh_Data_Structure "3D Simplicial Mesh Data Structures", if the corresponding vertex base also models the right concepts.
* \todo After discussion with Jane. The note above is wrong. There should be a second pair of Vb/Cb, designed to model the concepts of simplicial mesh and remeshing.
* \todo After discussion with Jane. Maybe there should be a second pair of Vb/Cb, designed to model the concepts of simplicial mesh and remeshing.
*
* \sa `CGAL::Constrained_Delaunay_triangulation_vertex_base_3`
*/

View File

@ -35,7 +35,7 @@ namespace CGAL {
* \ingroup PkgCT_3Classes
* \brief The default 3D constrained Delaunay triangulation type.
*
* `Default_constrained_triangulation_3` is a metafunction that returns the
* `Default_constrained_Delaunay_triangulation_3` is a metafunction that returns the
* default 3D constrained Delaunay triangulation type for a given geometric
* traits class.
*
@ -43,14 +43,16 @@ namespace CGAL {
*
* \return `type` is the default 3D constrained Delaunay triangulation type.
*
* \sa default_constrained_triangulation_3_t
* \sa default_constrained_Delaunay_triangulation_3_t
*/
template <typename Geom_traits>
struct Default_constrained_triangulation_3 {
using Vb = Constrained_Delaunay_triangulation_vertex_base_3<Geom_traits>;
using Cb = Constrained_Delaunay_triangulation_cell_base_3<Geom_traits>;
template <typename Geom_traits,
typename Vb = Constrained_Delaunay_triangulation_vertex_base_3<Geom_traits>,
typename Cb = Constrained_Delaunay_triangulation_cell_base_3<Geom_traits>>
struct Default_constrained_Delaunay_triangulation_3
{
using Tds = Triangulation_data_structure_3<Vb, Cb>;
using type = Triangulation_3<Geom_traits, Tds>;
using Tr = Triangulation_3<Geom_traits, Tds>;
using type = Constrained_Delaunay_triangulation_3<Geom_traits, Tr>;
};
/*!
@ -61,11 +63,10 @@ struct Default_constrained_triangulation_3 {
* This alias template names the default 3D constrained Delaunay triangulation
* type for a given geometric traits class.
*
* \sa Default_constrained_triangulation_3
* \sa Default_constrained_Delaunay_triangulation_3
*/
template <typename Geom_traits>
using default_constrained_triangulation_3_t =
typename Default_constrained_triangulation_3<Geom_traits>::type;
using default_constrained_Delaunay_triangulation_3_t = typename Default_constrained_Delaunay_triangulation_3<Geom_traits>::type;
/*!
* \ingroup PkgCT_3Functions
@ -83,14 +84,18 @@ using default_constrained_triangulation_3_t =
* The generated triangulation will be constrained to conform to the faces of the polygon mesh, or to the surface patches
* described by the `face_patch_map` property map if provided.
*
* \tparam Triangulation_3 An instance of the `Triangulation_3` class template.
* - Its `Geom_traits` type must be a model of `ConstrainedDelaunayTriangulationTraits_3`,
* - Its point type must be constructible from the point type of the polygon mesh,
* - its `Vertex` type must be a model of `ConstrainedDelaunayTriangulationVertexBase_3`, and
* - its `Cell` type must be a model of `ConstrainedDelaunayTriangulationCellBase_3`.
* \tparam Triangulation An instance of the `CGAL::Triangulation_3` class template (or `CGAL::Default`).
* - Its `Geom_traits` type must be a model of `ConstrainedDelaunayTriangulationTraits_3`,
* - Its point type must be constructible from the point type of the polygon mesh,
* - its `Vertex` type must be a model of `ConstrainedDelaunayTriangulationVertexBase_3`, and
* - its `Cell` type must be a model of `ConstrainedDelaunayTriangulationCellBase_3`.
* \tparam PolygonMesh a model of `FaceListGraph`
* \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
*
* If `Triangulation` is `CGAL::Default`, the geometric traits `Geom_traits` is deduced from the polygon mesh type
* `PolygonMesh` and the named parameters `NamedParameters`. And then the default constrained Delaunay triangulation is
* `Default_constrained_Delaunay_triangulation_3<Geom_traits>::type`.
*
* \param mesh The polygon mesh representing the constraints.
* \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
*
@ -111,7 +116,7 @@ using default_constrained_triangulation_3_t =
* \cgalParamNBegin{face_patch_map}
* \cgalParamDescription{a property map associating a patch identifier to each face of `mesh`}
* \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<PolygonMesh>::%face_descriptor`
* as key type and with any value type that is a *regular* type}
* as key type and with any value type that is a *regular* type (model of `Regular`)}
* \cgalParamExtra{If this parameter is omitted, each face of the mesh is considered as a separate patch.}
* \cgalParamExtra{Faces with the same patch identifier are considered as part of the same surface patch.}
* \cgalParamNEnd
@ -121,40 +126,19 @@ using default_constrained_triangulation_3_t =
* \link CGAL::Polygon_mesh_processing::does_self_intersect
* `CGAL::Polygon_mesh_processing::does_self_intersect(mesh, np) == false`
* \endlink
*
* \todo Create a documentation page to describe the concept *regular*, and link it to https://en.cppreference.com/w/cpp/concepts/regular
*/
template <typename Triangulation_3, typename PolygonMesh, typename NamedParams = parameters::Default_named_parameters>
Triangulation_3
make_constrained_Delaunay_triangulation_3(const PolygonMesh& mesh, const NamedParams& np = parameters::default_values())
template <typename Triangulation = CGAL::Default,
typename PolygonMesh,
typename NamedParams = parameters::Default_named_parameters>
auto make_constrained_Delaunay_triangulation_3(const PolygonMesh& mesh,
const NamedParams& np = parameters::default_values())
{
Constrained_Delaunay_triangulation_3<typename Triangulation_3::Geom_traits, Triangulation_3> cdt(mesh, np);
Triangulation_3 tr = std::move(cdt).triangulation();
for(auto vh : tr.all_vertex_handles()) {
vh->sync();
}
for(auto ch : tr.all_cell_handles()) {
ch->set_subdomain_index(1);
}
std::stack<typename Triangulation_3::Cell_handle> stack;
stack.push(tr.infinite_cell());
while(!stack.empty()) {
auto ch = stack.top();
stack.pop();
ch->set_subdomain_index(0);
for(int i = 0; i < 4; ++i) {
if(ch->is_facet_on_surface(i)) continue;
auto n = ch->neighbor(i);
if(n->subdomain_index() == 1) {
stack.push(n);
}
}
}
return tr;
using Mesh_geom_traits = typename GetGeomTraits<PolygonMesh, NamedParams>::type;
using CDT = typename CGAL::Default::Get<Triangulation, default_constrained_Delaunay_triangulation_3_t<Mesh_geom_traits>>::type;
CDT cdt(mesh, np);
auto remeshing_cdt{std::move(cdt).convert_for_remeshing()};
static_assert(std::is_same_v<decltype(remeshing_cdt), CDT>);
return remeshing_cdt;
}
} // end namespace CGAL

View File

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.1...3.23)
project(Constrained_triangulation_3_Tests)
find_package(CGAL REQUIRED)
create_single_source_cgal_program(test_constrained_Delaunay_triangulation_3.cpp)
target_compile_features(test_constrained_Delaunay_triangulation_3 PRIVATE cxx_std_20)

View File

@ -0,0 +1,42 @@
#include <CGAL/make_constrained_Delaunay_triangulation_3.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <algorithm>
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
using CDT = CGAL::Default_constrained_Delaunay_triangulation_3<K>::type;
int main(int argc, char* argv[])
{
CGAL::Surface_mesh<K::Point_3> mesh;
auto filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/mpi.off");
std::ifstream in(filename);
if(!in || !CGAL::IO::read_OFF(in, mesh)) {
std::cerr << "Error: cannot read file " << filename << std::endl;
return EXIT_FAILURE;
}
std::cout << "Read " << mesh.number_of_vertices() << " vertices and "
<< mesh.number_of_faces() << " faces" << std::endl;
auto cdt = CGAL::make_constrained_Delaunay_triangulation_3<CDT>(mesh);
static_assert(std::is_same_v<decltype(cdt), CDT>);
CDT cdt2(mesh);
const auto nb_cstr_facets = cdt2.number_of_constrained_facets();
assert(cdt.triangulation().number_of_vertices() == cdt2.triangulation().number_of_vertices());
assert(cdt.number_of_constrained_facets() == cdt2.number_of_constrained_facets());
assert(cdt.number_of_constrained_facets() > mesh.num_faces());
auto tr = std::move(cdt).triangulation();
assert(0 == cdt.triangulation().number_of_vertices());
assert(tr.number_of_vertices() == cdt2.triangulation().number_of_vertices());
auto nb = 0u;
for(auto _ : cdt2.constrained_facets()) {
++nb;
}
assert(nb == nb_cstr_facets);
assert(nb == std::distance(cdt2.constrained_facets_begin(), cdt2.constrained_facets_end()));
}

View File

@ -157,6 +157,12 @@ class RandomAccessIterator {};
/// See https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator
class BidirectionalIterator {};
/// \cgalConcept
/// A regular type is a type similar to `int`: it is copyable, assignable, and equality comparable.
/// \cgalRefines{DefaultConstructible, CopyConstructible, CopyAssignable, EqualityComparable}
/// See also the C++ concept `std::regular` at https://en.cppreference.com/w/cpp/concepts/regular
class Regular {};
/// \cgalConcept
/// Concept from the \cpp standard.
/// See https://en.cppreference.com/w/cpp/named_req/Swappable

View File

@ -131,6 +131,10 @@ a.el {
vertical-align:middle;
}
.PkgImage > .image > img {
border-radius: 10%;
}
.PkgAuthors {
font-style: italic;
}

View File

@ -0,0 +1,32 @@
/*!
\ingroup PkgSTLExtensionConcepts
\cgalConcept
The concept `BaseWithTimeStamp` describes the functionalities
an object must provide so that its timestamp is updated by
a `CGAL::Compact_container` or a `CGAL::Concurrent_compact_container`.
\cgalHasModelsBegin
\cgalHasModels{CGAL::Base_with_time_stamp}
\cgalHasModelsEnd
\sa `CGAL::Compact_container`
\sa `CGAL::Concurrent_compact_container`
*/
class BaseWithTimeStamp {
public:
/// Tag type to indicate that the class has a time stamp.
/// Must be `CGAL::Tag_true`.
using Has_timestamp = CGAL::Tag_true;
/// @name Access Functions
///
/// Member functions to read and set the time stamp.
/// @{
std::size_t time_stamp() const{
}
void set_time_stamp(const std::size_t&) {
}
///@}
};

View File

@ -4,3 +4,4 @@ PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - STL Extensions for CGAL"
INPUT += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/value_type_traits.h
INPUT += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/functional.h
INPUT += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Base_with_time_stamp.h

View File

@ -16,6 +16,10 @@
namespace CGAL {
/// @brief A base class with a time stamp.
///
/// This class is a base class that can be used to add a time stamp to any class.
/// \cgalModels{BaseWithTimeStamp}
template <typename Base>
class Base_with_time_stamp : public Base {
std::size_t time_stamp_ = 0;

View File

@ -27,6 +27,17 @@ struct is_same_or_derived :
>
{};
template<typename T>
struct is_nothrow_movable :
public std::bool_constant<
std::is_nothrow_move_constructible_v<T> &&
std::is_nothrow_move_assignable_v<T>
>
{};
template<typename T>
inline constexpr bool is_nothrow_movable_v = is_nothrow_movable<T>::value;
namespace cpp20 {
template< class T >

View File

@ -564,7 +564,7 @@ int go(Mesh mesh, CDT_options options) {
std::ofstream dump(options.output_filename);
dump.precision(17);
cdt.write_facets(dump, cdt, std::views::filter(cdt.finite_facets(), [&](auto f) {
return cdt.is_constrained(f);
return cdt.is_facet_constrained(f);
}));
}
CGAL_CDT_3_TASK_END(output_task_handle);