mirror of https://github.com/CGAL/cgal
Merge pull request #5012 from MaelRL/PMP-Repair_degeneracies_fixes-5.1-GF
PMP: Degeneracy removal fixes
This commit is contained in:
commit
40338b2a23
|
|
@ -256,7 +256,7 @@ std::size_t remove_connected_components_of_negligible_size(TriangleMesh& tmesh,
|
||||||
|
|
||||||
// Volumes make no sense for CCs that are not closed
|
// Volumes make no sense for CCs that are not closed
|
||||||
std::vector<bool> cc_closeness(num, true);
|
std::vector<bool> cc_closeness(num, true);
|
||||||
std::vector<FT> component_volumes(num);
|
std::vector<FT> component_volumes(num, FT(0));
|
||||||
|
|
||||||
if(use_volumes)
|
if(use_volumes)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -183,13 +183,15 @@ bool is_collapse_geometrically_valid(typename boost::graph_traits<TriangleMesh>:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template <class TriangleMesh, typename VPM, typename Traits>
|
template <class TriangleMesh, typename VPM, typename Traits>
|
||||||
boost::optional<double> get_collapse_volume(typename boost::graph_traits<TriangleMesh>::halfedge_descriptor h,
|
boost::optional<typename Traits::FT>
|
||||||
const TriangleMesh& tmesh,
|
get_collapse_volume(typename boost::graph_traits<TriangleMesh>::halfedge_descriptor h,
|
||||||
const VPM& vpm,
|
const TriangleMesh& tmesh,
|
||||||
const Traits& gt)
|
const VPM& vpm,
|
||||||
|
const Traits& gt)
|
||||||
{
|
{
|
||||||
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
|
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
|
||||||
|
|
||||||
|
typedef typename Traits::FT FT;
|
||||||
typedef typename boost::property_traits<VPM>::reference Point_ref;
|
typedef typename boost::property_traits<VPM>::reference Point_ref;
|
||||||
typedef typename Traits::Vector_3 Vector_3;
|
typedef typename Traits::Vector_3 Vector_3;
|
||||||
|
|
||||||
|
|
@ -204,8 +206,8 @@ boost::optional<double> get_collapse_volume(typename boost::graph_traits<Triangl
|
||||||
Point_ref removed= get(vpm, target(h, tmesh));
|
Point_ref removed= get(vpm, target(h, tmesh));
|
||||||
|
|
||||||
// init volume with incident triangles (reversed orientation
|
// init volume with incident triangles (reversed orientation
|
||||||
double delta_vol = volume(removed, kept, get(vpm, target(next(h, tmesh), tmesh)), origin) +
|
FT delta_vol = volume(removed, kept, get(vpm, target(next(h, tmesh), tmesh)), origin) +
|
||||||
volume(kept, removed, get(vpm, target(next(opposite(h, tmesh), tmesh), tmesh)), origin);
|
volume(kept, removed, get(vpm, target(next(opposite(h, tmesh), tmesh), tmesh)), origin);
|
||||||
|
|
||||||
// consider triangles incident to the vertex removed
|
// consider triangles incident to the vertex removed
|
||||||
halfedge_descriptor stop = prev(opposite(h, tmesh), tmesh);
|
halfedge_descriptor stop = prev(opposite(h, tmesh), tmesh);
|
||||||
|
|
@ -248,13 +250,14 @@ get_best_edge_orientation(typename boost::graph_traits<TriangleMesh>::edge_descr
|
||||||
const Traits& gt)
|
const Traits& gt)
|
||||||
{
|
{
|
||||||
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
|
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
|
||||||
|
typedef typename Traits::FT FT;
|
||||||
|
|
||||||
halfedge_descriptor h = halfedge(e, tmesh), ho = opposite(h, tmesh);
|
halfedge_descriptor h = halfedge(e, tmesh), ho = opposite(h, tmesh);
|
||||||
|
|
||||||
CGAL_assertion(!get(vcm, source(h, tmesh)) || !get(vcm, target(h, tmesh)));
|
CGAL_assertion(!get(vcm, source(h, tmesh)) || !get(vcm, target(h, tmesh)));
|
||||||
|
|
||||||
boost::optional<double> dv1 = get_collapse_volume(h, tmesh, vpm, gt);
|
boost::optional<FT> dv1 = get_collapse_volume(h, tmesh, vpm, gt);
|
||||||
boost::optional<double> dv2 = get_collapse_volume(ho, tmesh, vpm, gt);
|
boost::optional<FT> dv2 = get_collapse_volume(ho, tmesh, vpm, gt);
|
||||||
|
|
||||||
// the resulting point of the collapse of a halfedge is the target of the halfedge before collapse
|
// the resulting point of the collapse of a halfedge is the target of the halfedge before collapse
|
||||||
if(get(vcm, source(h, tmesh)))
|
if(get(vcm, source(h, tmesh)))
|
||||||
|
|
@ -288,6 +291,7 @@ bool should_flip(typename boost::graph_traits<TriangleMesh>::edge_descriptor e,
|
||||||
{
|
{
|
||||||
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
|
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
|
||||||
|
|
||||||
|
typedef typename Traits::FT FT;
|
||||||
typedef typename boost::property_traits<VPM>::reference Point_ref;
|
typedef typename boost::property_traits<VPM>::reference Point_ref;
|
||||||
typedef typename Traits::Vector_3 Vector_3;
|
typedef typename Traits::Vector_3 Vector_3;
|
||||||
|
|
||||||
|
|
@ -318,16 +322,16 @@ bool should_flip(typename boost::graph_traits<TriangleMesh>::edge_descriptor e,
|
||||||
const Vector_3 v23 = gt.construct_vector_3_object()(p2, p3);
|
const Vector_3 v23 = gt.construct_vector_3_object()(p2, p3);
|
||||||
const Vector_3 v30 = gt.construct_vector_3_object()(p3, p0);
|
const Vector_3 v30 = gt.construct_vector_3_object()(p3, p0);
|
||||||
|
|
||||||
const double p1p3 = gt.compute_scalar_product_3_object()(
|
const FT p1p3 = gt.compute_scalar_product_3_object()(
|
||||||
gt.construct_cross_product_vector_3_object()(v12, v23),
|
gt.construct_cross_product_vector_3_object()(v12, v23),
|
||||||
gt.construct_cross_product_vector_3_object()(v30, v01));
|
gt.construct_cross_product_vector_3_object()(v30, v01));
|
||||||
|
|
||||||
const Vector_3 v21 = gt.construct_opposite_vector_3_object()(v12);
|
const Vector_3 v21 = gt.construct_opposite_vector_3_object()(v12);
|
||||||
const Vector_3 v03 = gt.construct_opposite_vector_3_object()(v30);
|
const Vector_3 v03 = gt.construct_opposite_vector_3_object()(v30);
|
||||||
|
|
||||||
const double p0p2 = gt.compute_scalar_product_3_object()(
|
const FT p0p2 = gt.compute_scalar_product_3_object()(
|
||||||
gt.construct_cross_product_vector_3_object()(v01, v21),
|
gt.construct_cross_product_vector_3_object()(v01, v21),
|
||||||
gt.construct_cross_product_vector_3_object()(v23, v03));
|
gt.construct_cross_product_vector_3_object()(v23, v03));
|
||||||
|
|
||||||
return p0p2 <= p1p3;
|
return p0p2 <= p1p3;
|
||||||
}
|
}
|
||||||
|
|
@ -1694,37 +1698,23 @@ bool remove_degenerate_faces(const FaceRange& face_range,
|
||||||
// Ignore faces with null edges
|
// Ignore faces with null edges
|
||||||
if(!all_removed)
|
if(!all_removed)
|
||||||
{
|
{
|
||||||
std::map<edge_descriptor, bool> are_degenerate_edges;
|
typename std::set<face_descriptor>::iterator it = degenerate_face_set.begin();
|
||||||
|
while(it != degenerate_face_set.end())
|
||||||
for(face_descriptor fd : degenerate_face_set)
|
|
||||||
{
|
{
|
||||||
for(halfedge_descriptor hd : halfedges_around_face(halfedge(fd, tmesh), tmesh))
|
bool has_degenerate_edge = false;
|
||||||
|
for(halfedge_descriptor hd : halfedges_around_face(halfedge(*it, tmesh), tmesh))
|
||||||
{
|
{
|
||||||
edge_descriptor ed = edge(hd, tmesh);
|
const edge_descriptor ed = edge(hd, tmesh);
|
||||||
std::pair<typename std::map<edge_descriptor, bool>::iterator, bool> is_insert_successful =
|
if(is_degenerate_edge(ed, tmesh, np))
|
||||||
are_degenerate_edges.insert(std::make_pair(ed, false));
|
|
||||||
|
|
||||||
bool is_degenerate = false;
|
|
||||||
if(is_insert_successful.second)
|
|
||||||
{
|
{
|
||||||
// did not previously exist in the map, so actually have to check if it is degenerate
|
has_degenerate_edge = true;
|
||||||
if(traits.equal_3_object()(get(vpmap, target(ed, tmesh)), get(vpmap, source(ed, tmesh))))
|
it = degenerate_face_set.erase(it);
|
||||||
is_degenerate = true;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
is_insert_successful.first->second = is_degenerate;
|
|
||||||
|
|
||||||
if(is_degenerate)
|
|
||||||
{
|
|
||||||
halfedge_descriptor h = halfedge(ed, tmesh);
|
|
||||||
if(!is_border(h, tmesh))
|
|
||||||
degenerate_face_set.erase(face(h, tmesh));
|
|
||||||
|
|
||||||
h = opposite(h, tmesh);
|
|
||||||
if(!is_border(h, tmesh))
|
|
||||||
degenerate_face_set.erase(face(h, tmesh));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!has_degenerate_edge)
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -403,7 +403,7 @@ is_needle_triangle_face(typename boost::graph_traits<TriangleMesh>::face_descrip
|
||||||
if(min_sq_length == 0)
|
if(min_sq_length == 0)
|
||||||
return min_h;
|
return min_h;
|
||||||
|
|
||||||
const FT sq_threshold = threshold * threshold;
|
const FT sq_threshold = square(FT(threshold));
|
||||||
if(max_sq_length / min_sq_length >= sq_threshold)
|
if(max_sq_length / min_sq_length >= sq_threshold)
|
||||||
{
|
{
|
||||||
CGAL_assertion(min_h != boost::graph_traits<TriangleMesh>::null_halfedge());
|
CGAL_assertion(min_h != boost::graph_traits<TriangleMesh>::null_halfedge());
|
||||||
|
|
@ -482,7 +482,7 @@ is_cap_triangle_face(typename boost::graph_traits<TriangleMesh>::face_descriptor
|
||||||
typedef typename Traits::FT FT;
|
typedef typename Traits::FT FT;
|
||||||
typedef typename Traits::Vector_3 Vector_3;
|
typedef typename Traits::Vector_3 Vector_3;
|
||||||
|
|
||||||
const FT sq_threshold = threshold * threshold;
|
const FT sq_threshold = square(FT(threshold));
|
||||||
const halfedge_descriptor h0 = halfedge(f, tm);
|
const halfedge_descriptor h0 = halfedge(f, tm);
|
||||||
|
|
||||||
std::array<FT, 3> sq_lengths;
|
std::array<FT, 3> sq_lengths;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#define CGAL_PMP_DEBUG_SMALL_CC_REMOVAL
|
#define CGAL_PMP_DEBUG_SMALL_CC_REMOVAL
|
||||||
|
|
||||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||||
|
|
||||||
#include <CGAL/Surface_mesh.h>
|
#include <CGAL/Surface_mesh.h>
|
||||||
#include <CGAL/Polyhedron_3.h>
|
#include <CGAL/Polyhedron_3.h>
|
||||||
|
|
@ -21,6 +22,7 @@ namespace PMP = CGAL::Polygon_mesh_processing;
|
||||||
namespace CP = CGAL::parameters;
|
namespace CP = CGAL::parameters;
|
||||||
|
|
||||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK;
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK;
|
||||||
|
typedef CGAL::Exact_predicates_exact_constructions_kernel EPECK;
|
||||||
|
|
||||||
template <typename K, typename EdgeRange, typename FaceRange, typename Mesh>
|
template <typename K, typename EdgeRange, typename FaceRange, typename Mesh>
|
||||||
void detect_degeneracies(const EdgeRange& edge_range,
|
void detect_degeneracies(const EdgeRange& edge_range,
|
||||||
|
|
@ -340,17 +342,21 @@ void test()
|
||||||
typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
|
typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
|
||||||
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Polyhedron_with_ID;
|
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Polyhedron_with_ID;
|
||||||
|
|
||||||
std::cout << "EPICK SM TESTS" << std::endl;
|
std::cout << "SM TESTS" << std::endl;
|
||||||
test<Kernel, Surface_mesh>();
|
test<Kernel, Surface_mesh>();
|
||||||
|
|
||||||
std::cout << "EPICK POLYHEDRON TESTS" << std::endl;
|
std::cout << "POLYHEDRON TESTS" << std::endl;
|
||||||
test<Kernel, Polyhedron_with_ID>();
|
test<Kernel, Polyhedron_with_ID>();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int /*argc*/, char** /*argv*/)
|
int main(int /*argc*/, char** /*argv*/)
|
||||||
{
|
{
|
||||||
|
std::cout << "EPICK TESTS" << std::endl;
|
||||||
test<EPICK>();
|
test<EPICK>();
|
||||||
|
|
||||||
|
std::cout << "EPECK TESTS" << std::endl;
|
||||||
|
test<EPECK>();
|
||||||
|
|
||||||
std::cout << "Done" << std::endl;
|
std::cout << "Done" << std::endl;
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue