Merge remote-tracking branch 'MaelRL/PMP-Improve_SI_repair-GF' into HEAD

This commit is contained in:
Sébastien Loriot 2022-01-18 09:18:20 +01:00
commit 07e917ca09
10 changed files with 1269 additions and 886 deletions

View File

@ -437,7 +437,7 @@ struct Face_filtered_graph
initialize_halfedge_indices();
}
///change the set of selected faces using a patch id
/// changes the set of selected faces using a patch id
template<class FacePatchIndexMap>
void set_selected_faces(typename boost::property_traits<FacePatchIndexMap>::value_type face_patch_id,
FacePatchIndexMap face_patch_index_map)
@ -466,7 +466,7 @@ struct Face_filtered_graph
reset_indices();
}
/// change the set of selected faces using a range of patch ids
/// changes the set of selected faces using a range of patch ids
template<class FacePatchIndexRange, class FacePatchIndexMap>
void set_selected_faces(const FacePatchIndexRange& selected_face_patch_indices,
FacePatchIndexMap face_patch_index_map
@ -506,7 +506,7 @@ struct Face_filtered_graph
reset_indices();
}
/// change the set of selected faces using a range of face descriptors
/// changes the set of selected faces using a range of face descriptors
template<class FaceRange>
void set_selected_faces(const FaceRange& selection)
{
@ -569,18 +569,21 @@ struct Face_filtered_graph
{
return selected_halfedges[get(himap, halfedge(e,_graph))];
}
///returns the number of selected faces
size_type number_of_faces()const
/// returns the number of selected faces
size_type number_of_faces() const
{
return selected_faces.count();
}
///returns the number of selected vertices.
size_type number_of_vertices()const
/// returns the number of selected vertices.
size_type number_of_vertices() const
{
return selected_vertices.count();
}
///returns the number of selected halfedges.
size_type number_of_halfedges()const
/// returns the number of selected halfedges.
size_type number_of_halfedges() const
{
return selected_halfedges.count();
}
@ -612,18 +615,15 @@ struct Face_filtered_graph
return bind_property_maps(himap, make_property_map(halfedge_indices) );
}
/// returns `true` if around any vertex of a selected face,
/// there is at most one connected set of selected faces.
/// returns `true` if around any vertex of a selected face there is at most a single umbrella
bool is_selection_valid() const
{
typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
// Non-manifoldness can appear either:
// - if 'pm' is pinched at a vertex. While traversing the incoming halfedges at this vertex,
// we will meet strictly more than one border halfedge.
// - if there are multiple umbrellas around a vertex. In that case, we will find a non-visited
// halfedge that has for target a vertex that is already visited.
// Non-manifoldness can appear if there are multiple umbrellas around a vertex.
// In that case, we will find a non-visited halfedge that has for target a vertex
// that is already visited.
boost::unordered_set<vertex_descriptor> vertices_visited;
boost::unordered_set<halfedge_descriptor> halfedges_handled;
@ -643,15 +643,11 @@ struct Face_filtered_graph
if(!vertices_visited.insert(vd).second)
return false;
std::size_t border_halfedge_counter = 0;
// Can't simply call halfedges_around_target(vd, *this) because 'halfedge(vd)' is not necessarily 'hd'
// Can't call halfedges_around_target(vd, *this) because 'halfedge(vd)' is not necessarily 'hd'
halfedge_descriptor ihd = hd;
do
{
halfedges_handled.insert(ihd);
if(is_border(ihd, *this))
++border_halfedge_counter;
do
{
@ -660,9 +656,6 @@ struct Face_filtered_graph
while(!is_in_cc(ihd) && ihd != hd);
}
while(ihd != hd);
if(border_halfedge_counter > 1)
return false;
}
return true;
@ -1050,7 +1043,8 @@ typename boost::graph_traits< Face_filtered_graph<Graph, FIMap, VIMap, HIMap> >:
next(typename boost::graph_traits< Face_filtered_graph<Graph, FIMap, VIMap, HIMap> >::halfedge_descriptor h,
const Face_filtered_graph<Graph, FIMap, VIMap, HIMap> & w)
{
CGAL_assertion(w.is_in_cc(h));
CGAL_precondition(w.is_in_cc(h));
if(w.is_in_cc(next(h, w.graph())))
return next(h, w.graph());
@ -1074,8 +1068,8 @@ typename boost::graph_traits< Face_filtered_graph<Graph, FIMap, VIMap, HIMap> >:
prev(typename boost::graph_traits< Face_filtered_graph<Graph, FIMap, VIMap, HIMap> >::halfedge_descriptor h,
const Face_filtered_graph<Graph, FIMap, VIMap, HIMap> & w)
{
CGAL_precondition(w.is_in_cc(h));
CGAL_assertion(w.is_in_cc(h));
if(w.is_in_cc(prev(h, w.graph())))
return prev(h, w.graph());

View File

@ -484,8 +484,8 @@ void test_invalid_selections()
face_range.push_back(SM::Face_index(2));
face_range.push_back(SM::Face_index(3));
CGAL::Face_filtered_graph<SM> bad_fg(mesh, face_range);
assert(!bad_fg.is_selection_valid());
CGAL::Face_filtered_graph<SM> pinched_fg(mesh, face_range);
assert(pinched_fg.is_selection_valid());
// this creates a non-manifold vertex (multiple umbrellas)
clear(mesh);
@ -495,8 +495,8 @@ void test_invalid_selections()
face_range.clear();
merge_vertices(SM::Vertex_index(1337), SM::Vertex_index(87), face_range, mesh);
CGAL::Face_filtered_graph<SM> bad_fg_2(mesh, face_range);
assert(!bad_fg_2.is_selection_valid());
CGAL::Face_filtered_graph<SM> many_umbrellas_fg(mesh, face_range);
assert(!many_umbrellas_fg.is_selection_valid());
}
int main()

View File

@ -92,7 +92,7 @@ void construct_oriented_bounding_box(const PointRange& points,
obb_points[6] = cp(xmax, ymin, zmax);
obb_points[7] = cp(xmax, ymax, zmax);
// Apply the inverse rotation to the rotated axis aligned bounding box
// Apply the inverse rotation to the rotated axis-aligned bounding box
for(std::size_t i=0; i<8; ++i)
{
obb_points[i] = inverse_transformation.transform(obb_points[i]);
@ -141,13 +141,13 @@ void compute_best_transformation(const PointRange& points,
rot(1, 0), rot(1, 1), rot(1, 2),
rot(2, 0), rot(2, 1), rot(2, 2));
// inverse transformation is simply the transposed since the matrix is unitary
// the inverse transformation is simply the transposed matrix since the matrix is unitary
inverse_transformation = Aff_transformation_3(rot(0, 0), rot(1, 0), rot(2, 0),
rot(0, 1), rot(1, 1), rot(2, 1),
rot(0, 2), rot(1, 2), rot(2, 2));
}
// Following two functions are overloads to dispatch depending on return type
// The following two functions are overloads to dispatch depending on the return type
template <typename PointRange, typename K, typename Traits>
void construct_oriented_bounding_box(const PointRange& points,
CGAL::Aff_transformation_3<K>& transformation,
@ -325,6 +325,7 @@ void oriented_bounding_box(const PointRange& points,
{
using CGAL::parameters::choose_parameter;
using CGAL::parameters::get_parameter;
using CGAL::parameters::is_default_parameter;
typedef typename CGAL::GetPointMap<PointRange, NamedParameters>::type PointMap;
@ -350,7 +351,8 @@ void oriented_bounding_box(const PointRange& points,
const unsigned int seed = choose_parameter(get_parameter(np, internal_np::random_seed), -1); // undocumented
CGAL::Random fixed_seed_rng(seed);
CGAL::Random& rng = (seed == unsigned(-1)) ? CGAL::get_default_random() : fixed_seed_rng;
CGAL::Random& rng = is_default_parameter(get_parameter(np, internal_np::random_seed)) ?
CGAL::get_default_random() : fixed_seed_rng;
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
std::cout << "Random seed: " << rng.get_seed() << std::endl;

View File

@ -46,16 +46,21 @@ struct Tracer_polyhedron
int i, int k,
bool last = true)
{
if(i + 1 == k) { return P[i+1]; }
if(i + 1 == k)
return P[i+1];
halfedge_descriptor h, g;
if(i+2 == k){
if(i+2 == k)
{
if(last)
{
h = P[i+1];
Euler::fill_hole(h,pmesh); }
{
h = P[i + 1];
Euler::fill_hole(h, pmesh);
}
else
{ h = Euler::add_face_to_border(prev(P[i+1],pmesh), P[i+2/*k*/], pmesh); }
{
h = Euler::add_face_to_border(prev(P[i + 1], pmesh), P[i + 2 /*k*/], pmesh);
}
CGAL_assertion(face(h,pmesh) != boost::graph_traits<PolygonMesh>::null_face());
*out++ = face(h,pmesh);
@ -68,12 +73,14 @@ struct Tracer_polyhedron
g = operator()(lambda, la, k, false);
if(last)
{
h = g;
Euler::fill_hole(g,pmesh);
}
{
h = g;
Euler::fill_hole(g, pmesh);
}
else
{ h = Euler::add_face_to_border(prev(h,pmesh), g, pmesh); }
{
h = Euler::add_face_to_border(prev(h, pmesh), g, pmesh);
}
CGAL_assertion(face(h,pmesh) != boost::graph_traits<PolygonMesh>::null_face());
*out++ = face(h,pmesh);
@ -106,28 +113,29 @@ triangulate_hole_polygon_mesh(PolygonMesh& pmesh,
typedef std::map<vertex_descriptor, int> Vertex_map;
typedef typename Vertex_map::iterator Vertex_map_it;
#ifdef CGAL_PMP_HOLE_FILLING_DEBUG
#ifdef CGAL_PMP_HOLE_FILLING_DEBUG
CGAL::Timer timer; timer.start();
#endif
#endif
std::vector<Point_3> P, Q;
std::vector<Point_3> P, Q;
std::vector<halfedge_descriptor> P_edges;
Vertex_map vertex_map;
int id = 0;
Hedge_around_face_circulator circ(border_halfedge,pmesh), done(circ);
do{
do
{
P.push_back(get(vpmap, target(*circ, pmesh)));
Q.push_back(get(vpmap, target(next(opposite(next(*circ,pmesh),pmesh),pmesh),pmesh)));
P_edges.push_back(*circ);
if(!vertex_map.insert(std::make_pair(target(*circ,pmesh), id++)).second) {
#ifndef CGAL_TEST_SUITE
if(!vertex_map.insert(std::make_pair(target(*circ,pmesh), id++)).second)
{
#ifndef CGAL_TEST_SUITE
CGAL_warning_msg(false, "Returning no output. Non-manifold vertex is found on boundary!");
#else
#else
std::cerr << "W: Returning no output. Non-manifold vertex is found on boundary!\n";
#endif
return std::make_pair(out,
CGAL::internal::Weight_min_max_dihedral_and_area::NOT_VALID());
#endif
return std::make_pair(out, CGAL::internal::Weight_min_max_dihedral_and_area::NOT_VALID());
}
} while (++circ != done);
@ -151,52 +159,52 @@ triangulate_hole_polygon_mesh(PolygonMesh& pmesh,
if(v_it_neigh_it != vertex_map.end()) //other endpoint found in the map
{
int v_it_neigh_id = v_it_neigh_it->second;
if( v_it_neigh_id != v_it_prev && v_it_neigh_id != v_it_next )
{ //there is an edge incident to v_it, which is not next or previous
if(v_it_neigh_id != v_it_prev && v_it_neigh_id != v_it_next)
{
//there is an edge incident to v_it, which is not next or previous
//from vertex_map (checked by comparing IDs)
if(v_it_id < v_it_neigh_id) // to include each edge only once
{ existing_edges.push_back(std::make_pair(v_it_id, v_it_neigh_id)); }
existing_edges.push_back(std::make_pair(v_it_id, v_it_neigh_id));
}
}
} while(++circ_vertex != done_vertex);
}
//#define CGAL_USE_WEIGHT_INCOMPLETE
#ifdef CGAL_USE_WEIGHT_INCOMPLETE
//#define CGAL_USE_WEIGHT_INCOMPLETE
#ifdef CGAL_USE_WEIGHT_INCOMPLETE
typedef CGAL::internal::Weight_calculator<Weight_incomplete<CGAL::internal::Weight_min_max_dihedral_and_area>,
CGAL::internal::Is_valid_existing_edges_and_degenerate_triangle> WC;
#else
#else
typedef CGAL::internal::Weight_calculator<CGAL::internal::Weight_min_max_dihedral_and_area,
CGAL::internal::Is_valid_existing_edges_and_degenerate_triangle> WC;
#endif
#endif
CGAL::internal::Is_valid_existing_edges_and_degenerate_triangle is_valid(existing_edges);
// fill hole using polyline function, with custom tracer for PolygonMesh
Tracer_polyhedron<PolygonMesh, OutputIterator>
tracer(out, pmesh, P_edges);
Tracer_polyhedron<PolygonMesh, OutputIterator> tracer(out, pmesh, P_edges);
#ifndef CGAL_HOLE_FILLING_DO_NOT_USE_CDT2
if(use_cdt && triangulate_hole_polyline_with_cdt(P, tracer, is_valid, k, max_squared_distance))
{
return std::make_pair(tracer.out, CGAL::internal::Weight_min_max_dihedral_and_area(0,0));
}
if(use_cdt && triangulate_hole_polyline_with_cdt(P, tracer, is_valid, k, max_squared_distance))
return std::make_pair(tracer.out, CGAL::internal::Weight_min_max_dihedral_and_area(0,0));
#endif
CGAL::internal::Weight_min_max_dihedral_and_area weight =
triangulate_hole_polyline(P, Q, tracer, WC(is_valid),
use_delaunay_triangulation, k)
#ifdef CGAL_USE_WEIGHT_INCOMPLETE
.weight // get actual weight in Weight_incomplete
#ifndef CGAL_USE_WEIGHT_INCOMPLETE
triangulate_hole_polyline(P, Q, tracer, WC(is_valid), use_delaunay_triangulation, k);
#else
// get actual weight in Weight_incomplete
triangulate_hole_polyline(P, Q, tracer, WC(is_valid), use_delaunay_triangulation, k).weight;
#endif
;
#ifdef CGAL_PMP_HOLE_FILLING_DEBUG
#ifdef CGAL_PMP_HOLE_FILLING_DEBUG
std::cerr << "Hole filling: " << timer.time() << " sc." << std::endl; timer.reset();
#endif
#endif
return std::make_pair(tracer.out, weight);
}
}// namespace internal
}// namespace Polygon_mesh_processing
}// namespace CGAL
} // namespace internal
} // namespace Polygon_mesh_processing
} // namespace CGAL
#endif //CGAL_HOLE_FILLING_TRIANGULATE_HOLE_POLYHEDRON_3_H

View File

@ -1492,11 +1492,11 @@ triangulate_hole_polyline(const PointRange1& points,
typedef Kernel K;
typedef typename K::Point_3 Point_3;
#ifndef CGAL_HOLE_FILLING_DO_NOT_USE_DT3
#ifndef CGAL_HOLE_FILLING_DO_NOT_USE_DT3
typedef CGAL::internal::Triangulate_hole_polyline_DT<K, Tracer, WeightCalculator> Fill_DT;
#else
#else
CGAL_USE(use_delaunay_triangulation);
#endif
#endif
typedef CGAL::internal::Triangulate_hole_polyline<K, Tracer, WeightCalculator> Fill;
std::vector<Point_3> P(boost::begin(points), boost::end(points));
@ -1510,20 +1510,19 @@ triangulate_hole_polyline(const PointRange1& points,
}
typename WeightCalculator::Weight w =
#ifndef CGAL_HOLE_FILLING_DO_NOT_USE_DT3
#ifndef CGAL_HOLE_FILLING_DO_NOT_USE_DT3
use_delaunay_triangulation ? Fill_DT().operator()(P,Q,tracer,WC) :
#endif
#endif
Fill().operator()(P,Q,tracer,WC);
#ifndef CGAL_HOLE_FILLING_DO_NOT_USE_DT3
if (use_delaunay_triangulation
&& w == WeightCalculator::Weight::NOT_VALID())
if(use_delaunay_triangulation && w == WeightCalculator::Weight::NOT_VALID())
w = Fill().operator()(P, Q, tracer, WC);
#endif
#ifdef CGAL_PMP_HOLE_FILLING_DEBUG
#ifdef CGAL_PMP_HOLE_FILLING_DEBUG
std::cerr << w << std::endl;
#endif
#endif
return w;
}

View File

@ -27,7 +27,7 @@ namespace Polygon_mesh_processing {
/*!
\ingroup PMP_meshing_grp
@brief refines a region of a triangle mesh
@brief refines a region of a triangle mesh.
@tparam TriangleMesh model of `MutableFaceGraph`
@tparam FaceRange range of face descriptors, model of `Range`.

View File

@ -105,7 +105,7 @@ namespace Polygon_mesh_processing {
*
* \cgalParamNBegin{protect_constraints}
* \cgalParamDescription{If `true`, the edges set as constrained in `edge_is_constrained_map`
* (or by default the boundary edges) are not split nor collapsed during remeshing.}
* (or by default the boundary edges) are neither split nor collapsed during remeshing.}
* \cgalParamType{Boolean}
* \cgalParamDefault{`false`}
* \cgalParamExtra{Note that around constrained edges that have their length higher than

View File

@ -136,7 +136,7 @@ namespace Polygon_mesh_processing {
CGAL_precondition(face(border_halfedge, pmesh) == boost::graph_traits<PolygonMesh>::null_face());
bool use_cdt =
#ifdef CGAL_HOLE_FILLING_DO_NOT_USE_CDT2
#ifdef CGAL_HOLE_FILLING_DO_NOT_USE_CDT2
false;
#else
choose_parameter(get_parameter(np, internal_np::use_2d_constrained_delaunay_triangulation), false);
@ -176,22 +176,6 @@ namespace Polygon_mesh_processing {
max_squared_distance).first;
}
template<typename PM, typename VertexRange>
void test_in_edges(const PM& pmesh, const VertexRange& patch)
{
for(typename boost::graph_traits<PM>::vertex_descriptor v0 : patch)
{
typename boost::graph_traits<PM>::in_edge_iterator e, e_end;
for (boost::tie(e, e_end) = in_edges(v0, pmesh); e != e_end; e++)
{
typename boost::graph_traits<PM>::halfedge_descriptor he = halfedge(*e, pmesh);
if (is_border(he, pmesh)) { continue; }
CGAL_assertion(v0 == target(he, pmesh) || v0 == source(he, pmesh));
}
}
}
/*!
\ingroup hole_filling_grp
@brief triangulates and refines a hole in a polygon mesh.
@ -285,8 +269,6 @@ namespace Polygon_mesh_processing {
triangulate_hole(pmesh, border_halfedge, std::back_inserter(patch), np);
face_out = std::copy(patch.begin(), patch.end(), face_out);
test_in_edges(pmesh, vertices(pmesh));
return refine(pmesh, patch, face_out, vertex_out, np);
}
@ -401,16 +383,13 @@ namespace Polygon_mesh_processing {
VertexOutputIterator vertex_out,
const NamedParameters& np = parameters::default_values())
{
CGAL_precondition(CGAL::is_triangle_mesh(pmesh));
std::vector<typename boost::graph_traits<PolygonMesh>::vertex_descriptor> patch;
CGAL_assertion(CGAL::is_triangle_mesh(pmesh));
face_out = triangulate_and_refine_hole
(pmesh, border_halfedge, face_out, std::back_inserter(patch), np).first;
CGAL_assertion(CGAL::is_triangle_mesh(pmesh));
test_in_edges(pmesh, patch);
CGAL_postcondition(CGAL::is_triangle_mesh(pmesh));
bool fair_success = fair(pmesh, patch, np);
@ -536,9 +515,9 @@ bool use_dt3 =
#ifndef CGAL_HOLE_FILLING_DO_NOT_USE_CDT2
if (use_cdt)
{
struct Always_valid{
bool operator()(const std::vector<Point>&, int,int,int)const
{return true;}
struct Always_valid
{
bool operator()(const std::vector<Point>&, int,int,int) const { return true; }
};
Always_valid is_valid;
@ -549,8 +528,9 @@ bool use_dt3 =
const typename Kernel::FT threshold_distance = choose_parameter(
get_parameter(np, internal_np::threshold_distance), typename Kernel::FT(-1));
typename Kernel::FT max_squared_distance = default_squared_distance;
if (threshold_distance >= typename Kernel::FT(0))
if(threshold_distance >= typename Kernel::FT(0))
max_squared_distance = threshold_distance * threshold_distance;
CGAL_assertion(max_squared_distance >= typename Kernel::FT(0));
if (triangulate_hole_polyline_with_cdt(
points,

View File

@ -1529,6 +1529,9 @@ public:
/// performs a validity check on a single vertex.
bool is_valid(Vertex_index v) const {
if(!has_valid_index(v))
return false;
Halfedge_index h = vconn_[v].halfedge_;
if(h!= null_halfedge() && (!has_valid_index(h) || is_removed(h))) {
std::cerr << "Vertex connectivity halfedge error in " << (size_type)v
@ -1540,6 +1543,9 @@ public:
/// performs a validity check on a single halfedge.
bool is_valid(Halfedge_index h) const {
if(!has_valid_index(h))
return false;
Face_index f = hconn_[h].face_;
Vertex_index v = hconn_[h].vertex_;
Halfedge_index hn = hconn_[h].next_halfedge_;
@ -1581,6 +1587,9 @@ public:
/// performs a validity check on a single edge.
bool is_valid(Edge_index e) const {
if(!has_valid_index(e))
return false;
Halfedge_index h = halfedge(e);
return is_valid(h) && is_valid(opposite(h));
}
@ -1588,6 +1597,9 @@ public:
/// performs a validity check on a single face.
bool is_valid(Face_index f) const {
if(!has_valid_index(f))
return false;
Halfedge_index h = fconn_[f].halfedge_;
if(!has_valid_index(h) || is_removed(h)) {
std::cerr << "Face connectivity halfedge error in " << (size_type)f