diff --git a/Lab/demo/Lab/Plugins/PMP/Isotropic_remeshing_dialog.ui b/Lab/demo/Lab/Plugins/PMP/Isotropic_remeshing_dialog.ui
index fd2e9c6ab6c3..610b9b7f64f0 100644
--- a/Lab/demo/Lab/Plugins/PMP/Isotropic_remeshing_dialog.ui
+++ b/Lab/demo/Lab/Plugins/PMP/Isotropic_remeshing_dialog.ui
@@ -22,7 +22,6 @@
15
- 75
true
@@ -59,121 +58,78 @@
Isotropic remeshing
-
- -
-
-
-
+
+
-
+
+
+
+ 110
+ 0
+
-
-
- -
-
-
- Minimum edge length
+
+ 1
- -
-
+
-
+
+
+ 0.00
+
- -
-
-
- 0
+
-
+
+
+ -1
-
- 100
+
+ false
-
- 1
+
+
+ -
+
+
+ Minimum edge length
- -
+
-
Error tolerance
- -
-
+
-
+
-
+ Target edge length
-
- true
+
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
- -
-
+
-
+
-
+ Ball radius
-
- 0.00
+
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
- -
-
-
- -1
-
-
- QLayout::SetDefaultConstraint
-
-
- 11
-
-
- 14
-
-
-
-
-
- Edge sizing
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 168
- 16777215
-
-
-
-
-
- Uniform
-
-
- -
-
- Adaptive
-
-
-
-
-
-
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -183,53 +139,66 @@
- -
-
-
- Allow 1D smoothing along borders
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
+
-
+
- Protect borders/selected edges
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+ Maximum edge length
-
+
+ true
+
+ -
+
+
+ 0
+
+
+ 100
+
+
+ 1
+
+
+
-
Preserve duplicated edges
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
- -
-
-
+
-
+
+
+ Qt::Orientation::Vertical
+
+
+ QSizePolicy::Policy::Maximum
+
+
- 110
- 0
+ 20
+ 24
-
- 1
+
+
+ -
+
+
+
@@ -239,43 +208,68 @@
Number of Main iterations
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
nbIterations_spinbox
- -
-
-
- Qt::Vertical
+
-
+
+
+ 0.00
-
- QSizePolicy::Maximum
+
+
+ -
+
+
+ 0.00
-
-
- 20
- 24
-
+
+
+ -
+
+
+
-
+
+ true
+
+
- -
-
+
-
+
- Target edge length
+ Curvature smoothing
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ Protect borders/selected edges
+
+
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
-
- Qt::ImhNone
+ Qt::InputMethodHint::ImhNone
@@ -288,26 +282,64 @@
- -
-
+
-
+
- Maximum edge length
+ Allow 1D smoothing along borders
-
-
- -
-
-
- 0.00
+
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
- -
-
-
- 0.00
+
-
+
+
+ 6
-
+
+ QLayout::SizeConstraint::SetDefaultConstraint
+
+
+ 11
+
+
+ 14
+
+ -
+
+
+ Edge sizing
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 168
+ 16777215
+
+
+
-
+
+ Uniform
+
+
+ -
+
+ Adaptive
+
+
+
+
+
-
@@ -315,37 +347,30 @@
Number of Smoothing iterations
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
- -
-
-
- Ball radius
+
-
+
+
+ false
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
- -
-
+
-
+
+
+ Qt::LayoutDirection::LeftToRight
+
- Curvature smoothing
+ Do not triangulate faces after split
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -1
-
-
- false
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
@@ -355,15 +380,12 @@
-
- Qt::Vertical
-
-
- QSizePolicy::MinimumExpanding
+ Qt::Orientation::Vertical
- 0
- 0
+ 20
+ 40
@@ -371,10 +393,10 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+ QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok
@@ -388,7 +410,6 @@
- splitEdgesOnly_checkbox
edgeLength_dspinbox
nbIterations_spinbox
nbSmoothing_spinbox
diff --git a/Lab/demo/Lab/Plugins/PMP/Isotropic_remeshing_plugin.cpp b/Lab/demo/Lab/Plugins/PMP/Isotropic_remeshing_plugin.cpp
index 948c76652473..f12e049c840d 100644
--- a/Lab/demo/Lab/Plugins/PMP/Isotropic_remeshing_plugin.cpp
+++ b/Lab/demo/Lab/Plugins/PMP/Isotropic_remeshing_plugin.cpp
@@ -301,7 +301,8 @@ class CGAL_Lab_isotropic_remeshing_plugin :
const double error_tol,
const double min_length,
const double max_length,
- const double curv_ball_r)
+ const double curv_ball_r,
+ const bool do_not_triangulate)
{
std::vector p_edges;
for(edge_descriptor e : edges(pmesh))
@@ -327,7 +328,8 @@ class CGAL_Lab_isotropic_remeshing_plugin :
, target_length
, *selection_item->polyhedron()
, CGAL::parameters::geom_traits(EPICK())
- .edge_is_constrained_map(selection_item->constrained_edges_pmap()));
+ .edge_is_constrained_map(selection_item->constrained_edges_pmap())
+ .do_not_triangulate_faces(do_not_triangulate));
}
else if (edge_sizing_type == 1)
{
@@ -343,7 +345,8 @@ class CGAL_Lab_isotropic_remeshing_plugin :
, adaptive_sizing
, *selection_item->polyhedron()
, CGAL::parameters::geom_traits(EPICK())
- .edge_is_constrained_map(selection_item->constrained_edges_pmap()));
+ .edge_is_constrained_map(selection_item->constrained_edges_pmap())
+ .do_not_triangulate_faces(do_not_triangulate));
}
}
else
@@ -387,6 +390,7 @@ public Q_SLOTS:
int edge_sizing_type = ui.edgeSizing_type_combo_box->currentIndex();
bool edges_only = ui.splitEdgesOnly_checkbox->isChecked();
+ bool do_not_triangulate = ui.doNotTriangulate_checkbox->isChecked();
bool preserve_duplicates = ui.preserveDuplicates_checkbox->isChecked();
double target_length = ui.edgeLength_dspinbox->value();
double error_tol = ui.errorTol_edit->value();
@@ -429,7 +433,8 @@ public Q_SLOTS:
if (edges_only)
{
do_split_edges(edge_sizing_type, selection_item, pmesh,
- target_length, error_tol, min_length, max_length, curv_ball_r);
+ target_length, error_tol, min_length, max_length, curv_ball_r,
+ do_not_triangulate);
}
else //not edges_only
{
@@ -465,7 +470,8 @@ public Q_SLOTS:
else
{
do_split_edges(edge_sizing_type, selection_item, pmesh,
- target_length, error_tol, min_length, max_length, curv_ball_r);
+ target_length, error_tol, min_length, max_length, curv_ball_r,
+ do_not_triangulate);
}
}
@@ -675,7 +681,8 @@ public Q_SLOTS:
, pmesh
, CGAL::parameters::geom_traits(EPICK())
. edge_is_constrained_map(eif)
- . face_patch_map(fpmap));
+ . face_patch_map(fpmap)
+ . do_not_triangulate_faces(do_not_triangulate));
}
else if (edge_sizing_type == 1)
{
@@ -691,6 +698,7 @@ public Q_SLOTS:
, pmesh
, CGAL::parameters::geom_traits(EPICK())
. edge_is_constrained_map(eif)
+ . do_not_triangulate_faces(do_not_triangulate)
. face_patch_map(fpmap));
}
}
@@ -703,6 +711,7 @@ public Q_SLOTS:
, target_length
, pmesh
, CGAL::parameters::geom_traits(EPICK())
+ . do_not_triangulate_faces(do_not_triangulate)
. edge_is_constrained_map(eif));
}
else if (edge_sizing_type == 1)
@@ -862,6 +871,7 @@ public Q_SLOTS:
{
// Remeshing parameters
bool edges_only = false, preserve_duplicates = false;
+ bool do_not_triangulate = false;
int edge_sizing_type = 0;
double target_length = 0.;
double error_tol = 0.;
@@ -901,6 +911,7 @@ public Q_SLOTS:
}
edges_only = ui.splitEdgesOnly_checkbox->isChecked();
+ do_not_triangulate = ui.doNotTriangulate_checkbox->isChecked();
preserve_duplicates = ui.preserveDuplicates_checkbox->isChecked();
edge_sizing_type = ui.edgeSizing_type_combo_box->currentIndex();
target_length = ui.edgeLength_dspinbox->value();
@@ -963,6 +974,7 @@ public Q_SLOTS:
tbb::blocked_range(0, selection.size()),
Remesh_polyhedron_item_for_parallel_for(
selection, edges_to_protect, edges_only
+ , do_not_triangulate
, edge_sizing_type, target_length, error_tol
, min_length , max_length, nb_iter
, protect, smooth_features)
@@ -1012,6 +1024,7 @@ public Q_SLOTS:
int edge_sizing_type_;
bool edges_only_;
+ bool do_not_triangulate_;
double target_length_;
double error_tol_;
double min_length_;
@@ -1043,7 +1056,8 @@ public Q_SLOTS:
CGAL::Polygon_mesh_processing::split_long_edges(
border_edges
, target_length_
- , *poly_item->polyhedron());
+ , *poly_item->polyhedron()
+ , CGAL::parameters::do_not_triangulate_faces(do_not_triangulate_));
}
else if (edge_sizing_type_ == 1)
{
@@ -1056,7 +1070,8 @@ public Q_SLOTS:
CGAL::Polygon_mesh_processing::split_long_edges(
border_edges
, target_length_
- , *poly_item->polyhedron());
+ , *poly_item->polyhedron()
+ , CGAL::parameters::do_not_triangulate_faces(do_not_triangulate_));
}
}
else
@@ -1102,6 +1117,7 @@ public Q_SLOTS:
public:
Remesh_polyhedron_item(
const bool edges_only,
+ const bool do_not_triangulate,
const int edge_sizing_type,
const double target_length,
const double error_tol,
@@ -1112,6 +1128,7 @@ public Q_SLOTS:
const bool smooth_features)
: edge_sizing_type_(edge_sizing_type)
, edges_only_(edges_only)
+ , do_not_triangulate_(do_not_triangulate)
, target_length_(target_length)
, error_tol_(error_tol)
, min_length_(min_length)
@@ -1124,6 +1141,7 @@ public Q_SLOTS:
Remesh_polyhedron_item(const Remesh_polyhedron_item& remesh)
: edge_sizing_type_(remesh.edge_sizing_type_)
, edges_only_(remesh.edges_only_)
+ , do_not_triangulate_(remesh.do_not_triangulate_)
, target_length_(remesh.target_length_)
, error_tol_(remesh.error_tol_)
, min_length_(remesh.min_length_)
@@ -1154,6 +1172,7 @@ public Q_SLOTS:
const std::vector& selection,
std::map& edges_to_protect,
const bool edges_only,
+ const bool do_not_triangulate,
const int edge_sizing_type,
const double target_length,
const double error_tol,
@@ -1164,7 +1183,8 @@ public Q_SLOTS:
const bool smooth_features)
: RemeshFunctor(edges_only, edge_sizing_type, target_length
, error_tol, min_length, max_length
- , nb_iter, protect, smooth_features)
+ , nb_iter, protect, smooth_features
+ , do_not_triangulate)
, selection_(selection), edges_to_protect_(edges_to_protect)
{}
@@ -1205,6 +1225,8 @@ public Q_SLOTS:
{
if(ui.splitEdgesOnly_checkbox->isChecked())
{
+ ui.doNotTriangulate_checkbox->setEnabled(true);
+
ui.nbIterations_label->setEnabled(false);
ui.nbIterations_spinbox->setEnabled(false);
ui.nbSmoothing_label->setEnabled(false);
@@ -1220,6 +1242,8 @@ public Q_SLOTS:
}
else
{
+ ui.doNotTriangulate_checkbox->setEnabled(false);
+
ui.nbIterations_label->setEnabled(true);
ui.nbIterations_spinbox->setEnabled(true);
ui.nbSmoothing_label->setEnabled(true);
diff --git a/PMP_Remeshing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h b/PMP_Remeshing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h
index ae2c5712bfd9..555321850d98 100644
--- a/PMP_Remeshing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h
+++ b/PMP_Remeshing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#include
@@ -254,6 +255,47 @@ namespace internal {
return true;
}
+ template
+ struct Triangulate_face_visitor
+ : public CGAL::Polygon_mesh_processing::Triangulate_faces::Default_visitor
+ {
+ using face_descriptor = typename boost::graph_traits::face_descriptor;
+ using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor;
+
+ const Mesh& m_mesh;
+ std::unordered_set& m_created_halfedges;
+ std::unordered_set& m_created_faces;
+
+ std::unordered_set m_face_halfedges;
+
+ Triangulate_face_visitor(const Mesh& mesh,
+ std::unordered_set& created_faces,
+ std::unordered_set& created_halfedges)
+ : m_mesh(mesh)
+ , m_created_faces(created_faces)
+ , m_created_halfedges(created_halfedges)
+ {}
+
+ void before_subface_creations(face_descriptor f)
+ {
+ for(halfedge_descriptor h : halfedges_around_face(halfedge(f, m_mesh), m_mesh))
+ m_face_halfedges.insert(h);
+ }
+ void after_subface_creations()
+ {
+ for(face_descriptor f : m_created_faces)
+ {
+ for(halfedge_descriptor h : halfedges_around_face(halfedge(f, m_mesh), m_mesh))
+ if(m_face_halfedges.count(h) == 0)
+ m_created_halfedges.insert(h);
+ }
+ }
+ void after_subface_created(face_descriptor f)
+ {
+ m_created_faces.insert(f);
+ }
+ };
+
template
void split_long_edges(const EdgeRange& edge_range,
- SizingFunction& sizing)
+ SizingFunction& sizing,
+ const bool do_not_triangulate_faces)
{
#ifdef CGAL_PMP_REMESHING_VERBOSE
@@ -417,7 +460,7 @@ namespace internal {
long_edges.erase(eit);
//split edge
- Point refinement_point = this->midpoint(he);
+ const Point refinement_point = sizing.split_placement(he, mesh_);
halfedge_descriptor hnew = CGAL::Euler::split_edge(he, mesh_);
// propagate the constrained status
put(ecmap_, edge(hnew, mesh_), get(ecmap_, edge(he, mesh_)));
@@ -447,26 +490,29 @@ namespace internal {
long_edges.emplace(hnext, sqlen_new.value());
//insert new edges to keep triangular faces, and update long_edges
- if (!is_border(hnew, mesh_))
+ if(!do_not_triangulate_faces)
{
- Patch_id patch_id = get_patch_id(face(hnew, mesh_));
- halfedge_descriptor hnew2 =
- CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_);
- put(ecmap_, edge(hnew2, mesh_), false);
- set_patch_id(face(hnew2, mesh_), patch_id);
- set_patch_id(face(opposite(hnew2, mesh_), mesh_), patch_id);
- }
+ if (!is_border(hnew, mesh_))
+ {
+ Patch_id patch_id = get_patch_id(face(hnew, mesh_));
+ halfedge_descriptor hnew2 =
+ CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_);
+ put(ecmap_, edge(hnew2, mesh_), false);
+ set_patch_id(face(hnew2, mesh_), patch_id);
+ set_patch_id(face(opposite(hnew2, mesh_), mesh_), patch_id);
+ }
- //do it again on the other side if we're not on boundary
- halfedge_descriptor hnew_opp = opposite(hnew, mesh_);
- if (!is_border(hnew_opp, mesh_))
- {
- Patch_id patch_id = get_patch_id(face(hnew_opp, mesh_));
- halfedge_descriptor hnew2 =
- CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_);
- put(ecmap_, edge(hnew2, mesh_), false);
- set_patch_id(face(hnew2, mesh_), patch_id);
- set_patch_id(face(opposite(hnew2, mesh_), mesh_), patch_id);
+ //do it again on the other side if we're not on boundary
+ halfedge_descriptor hnew_opp = opposite(hnew, mesh_);
+ if (!is_border(hnew_opp, mesh_))
+ {
+ Patch_id patch_id = get_patch_id(face(hnew_opp, mesh_));
+ halfedge_descriptor hnew2 =
+ CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_);
+ put(ecmap_, edge(hnew2, mesh_), false);
+ set_patch_id(face(hnew2, mesh_), patch_id);
+ set_patch_id(face(opposite(hnew2, mesh_), mesh_), patch_id);
+ }
}
}
#ifdef CGAL_PMP_REMESHING_VERBOSE
@@ -505,107 +551,107 @@ namespace internal {
long_edges.emplace(halfedge(e, mesh_), sqlen.value());
}
+ auto emplace_if_too_long = [&](halfedge_descriptor h) {
+ std::optional sqlen_new = sizing.is_too_long(source(h, mesh_), target(h, mesh_), mesh_);
+ if(sqlen_new != std::nullopt)
+ long_edges.emplace(h, sqlen_new.value());
+ };
+
//split long edges
#ifdef CGAL_PMP_REMESHING_VERBOSE
unsigned int nb_splits = 0;
#endif
+
while (!long_edges.empty())
{
- //the edge with longest length
- auto eit = long_edges.begin();
- halfedge_descriptor he = eit->first;
- long_edges.erase(eit);
+ // split existing long edges until there is none left,
+ // as splitting an edge can leave remaining "half-length" long edges
+ while(!long_edges.empty())
+ {
+ //the edge with longest length
+ auto eit = long_edges.begin();
+ halfedge_descriptor he = eit->first;
+ long_edges.erase(eit);
#ifdef CGAL_PMP_REMESHING_VERBOSE_PROGRESS
- std::cout << "\r\t(" << long_edges.size() << " long edges, ";
- std::cout << nb_splits << " splits)";
- std::cout.flush();
+ std::cout << "\r\t(" << long_edges.size() << " long edges, ";
+ std::cout << nb_splits << " splits)";
+ std::cout.flush();
#endif
- if (protect_constraints_ && !is_longest_on_faces(edge(he, mesh_)))
- continue;
-
- //collect patch_ids
- Patch_id patch_id = get_patch_id(face(he, mesh_));
- Patch_id patch_id_opp = get_patch_id(face(opposite(he, mesh_), mesh_));
+ if (protect_constraints_ && !is_longest_on_faces(edge(he, mesh_)))
+ continue;
- //split edge
- Point refinement_point = sizing.split_placement(he, mesh_);
- halfedge_descriptor hnew = CGAL::Euler::split_edge(he, mesh_);
- CGAL_assertion(he == next(hnew, mesh_));
- put(ecmap_, edge(hnew, mesh_), get(ecmap_, edge(he, mesh_)) );
+ //split edge
+ Point refinement_point = sizing.split_placement(he, mesh_);
+ halfedge_descriptor hnew = CGAL::Euler::split_edge(he, mesh_);
+ CGAL_assertion(he == next(hnew, mesh_));
+ put(ecmap_, edge(hnew, mesh_), get(ecmap_, edge(he, mesh_)) );
#ifdef CGAL_PMP_REMESHING_VERBOSE
- ++nb_splits;
+ ++nb_splits;
#endif
- //move refinement point
- vertex_descriptor vnew = target(hnew, mesh_);
- put(vpmap_, vnew, refinement_point);
+ //move refinement point
+ vertex_descriptor vnew = target(hnew, mesh_);
+ put(vpmap_, vnew, refinement_point);
#ifdef CGAL_PMP_REMESHING_VERY_VERBOSE
- std::cout << " Refinement point : " << refinement_point << std::endl;
+ std::cout << " Refinement point : " << refinement_point << std::endl;
#endif
- //after splitting
- halfedge_descriptor hnew_opp = opposite(hnew, mesh_);
- halfedge_added(hnew, status(he));
- halfedge_added(hnew_opp, status(opposite(he, mesh_)));
+ //after split
+ halfedge_descriptor hnew_opp = opposite(hnew, mesh_);
+ halfedge_added(hnew, status(he));
+ halfedge_added(hnew_opp, status(opposite(he, mesh_)));
- //update sizing field with the new point
- sizing.register_split_vertex(vnew, mesh_);
+ //update sizing field with the new point
+ sizing.register_split_vertex(vnew, mesh_);
- //check sub-edges
- //if it was more than twice the "long" threshold, insert them
- std::optional sqlen_new = sizing.is_too_long(source(hnew, mesh_), target(hnew, mesh_), mesh_);
- if(sqlen_new != std::nullopt)
- long_edges.emplace(hnew, sqlen_new.value());
+ //check sub-edges
+ const halfedge_descriptor hnext = next(hnew, mesh_);
+ emplace_if_too_long(hnew);
+ emplace_if_too_long(hnext);
- const halfedge_descriptor hnext = next(hnew, mesh_);
- sqlen_new = sizing.is_too_long(source(hnext, mesh_), target(hnext, mesh_), mesh_);
- if (sqlen_new != std::nullopt)
- long_edges.emplace(hnext, sqlen_new.value());
+ } // end while long_edges
- //insert new edges to keep triangular faces, and update long_edges
- if (!is_on_border(hnew))
+ // triangulate faces that have a long edge on their border, and update long_edges
+ std::unordered_set to_triangulate;
+ for(halfedge_descriptor he : halfedges(mesh_))
{
- halfedge_descriptor hnew2 = CGAL::Euler::split_face(hnew,
- next(next(hnew, mesh_), mesh_),
- mesh_);
- put(ecmap_, edge(hnew2, mesh_), false);
- Halfedge_status snew = (is_on_patch(hnew) || is_on_patch_border(hnew))
- ? PATCH
- : MESH;
- halfedge_added(hnew2, snew);
- halfedge_added(opposite(hnew2, mesh_), snew);
- set_patch_id(face(hnew2, mesh_), patch_id);
- set_patch_id(face(opposite(hnew2, mesh_), mesh_), patch_id);
-
- if (snew == PATCH)
- {
- std::optional sql = sizing.is_too_long(source(hnew2, mesh_), target(hnew2, mesh_), mesh_);
- if(sql != std::nullopt)
- long_edges.emplace(hnew2, sql.value());
- }
+ if(is_on_border(he) || is_triangle(he, mesh_))
+ continue;
+ if(is_on_patch(he) || is_on_patch_border(he))
+ to_triangulate.insert(he);
}
- //do it again on the other side if we're not on boundary
- if (!is_on_border(hnew_opp))
+ while(!to_triangulate.empty())
{
- halfedge_descriptor hnew2 = CGAL::Euler::split_face(prev(hnew_opp, mesh_),
- next(hnew_opp, mesh_),
- mesh_);
- put(ecmap_, edge(hnew2, mesh_), false);
- Halfedge_status snew = (is_on_patch(hnew_opp) || is_on_patch_border(hnew_opp))
- ? PATCH
- : MESH;
- halfedge_added(hnew2, snew);
- halfedge_added(opposite(hnew2, mesh_), snew);
- set_patch_id(face(hnew2, mesh_), patch_id_opp);
- set_patch_id(face(opposite(hnew2, mesh_), mesh_), patch_id_opp);
-
- if (snew == PATCH)
+ halfedge_descriptor he = *to_triangulate.begin();
+ to_triangulate.erase(he);
+
+ const Patch_id patch_id = get_patch_id(face(he, mesh_));
+
+ std::unordered_set created_faces;
+ std::unordered_set created_halfedges;
+ Triangulate_face_visitor visitor(mesh_, created_faces, created_halfedges);
+ CGAL::Polygon_mesh_processing::triangulate_face(face(he, mesh_),
+ mesh_,
+ parameters::visitor(visitor)
+ .geom_traits(gt_)
+ .vertex_point_map(vpmap_));
+
+ for(auto f : created_faces)
+ set_patch_id(f, patch_id);
+
+ for(auto hnew2 : created_halfedges)
{
- std::optional sql = sizing.is_too_long(source(hnew2, mesh_), target(hnew2, mesh_), mesh_);
- if (sql != std::nullopt)
- long_edges.emplace(hnew2, sql.value());
+ put(ecmap_, edge(hnew2, mesh_), false);
+
+ // update status : it must be PATCH because we only split faces that have a long edge
+ // on their border, and border edges are PATCH or PATCH_BORDER
+ halfedge_added(hnew2, PATCH);
+ halfedge_added(opposite(hnew2, mesh_), PATCH);
+
+ // put new edges in long_edges if needed
+ emplace_if_too_long(hnew2);
}
}
}
diff --git a/PMP_Remeshing/include/CGAL/Polygon_mesh_processing/remesh.h b/PMP_Remeshing/include/CGAL/Polygon_mesh_processing/remesh.h
index 59f9fd4c4553..ffd2630faee3 100644
--- a/PMP_Remeshing/include/CGAL/Polygon_mesh_processing/remesh.h
+++ b/PMP_Remeshing/include/CGAL/Polygon_mesh_processing/remesh.h
@@ -441,6 +441,12 @@ void isotropic_remeshing(const FaceRange& faces
* \cgalParamDefault{a default property map where no edge is constrained}
* \cgalParamExtra{A constrained edge can be split or collapsed, but not flipped, nor its endpoints moved by smoothing.}
* \cgalParamNEnd
+*
+* \cgalParamNBegin{do_not_triangulate_faces}
+* \cgalParamDescription{If `true`, the faces created by splitting are not triangulated.}
+* \cgalParamType{`bool`}
+* \cgalParamDefault{`false`}
+* \cgalParamNEnd
* \cgalNamedParamsEnd
*
* @sa `isotropic_remeshing()`
@@ -492,6 +498,9 @@ void split_long_edges(const EdgeRange& edges
get_parameter(np, internal_np::face_patch),
internal::Connected_components_pmap(faces(pmesh), pmesh, ecmap, fimap, false));
+ const bool do_not_triangulate
+ = choose_parameter(get_parameter(np, internal_np::do_not_triangulate_faces), false);
+
typename internal::Incremental_remesher, // no constraint pmap
FPMap,FIMap
@@ -502,7 +511,7 @@ void split_long_edges(const EdgeRange& edges
fimap,
false/*need aabb_tree*/);
- remesher.split_long_edges(edges, sizing);
+ remesher.split_long_edges(edges, sizing, do_not_triangulate);
}
// Convenience overload when using max_length for sizing