Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flip it if you can't collapse it #8609

Merged
merged 12 commits into from
Dec 23, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -871,14 +871,14 @@ namespace internal {
std::array<halfedge_descriptor, 2> r1 = internal::is_badly_shaped(
face(he, mesh_),
mesh_, vpmap_, vcmap_, ecmap_, gt_,
cap_threshold, // bound on the angle: above 160 deg => cap
4, // bound on shortest/longest edge above 4 => needle
cap_threshold, // bound on the angle: above 160 deg => cap
0,// collapse length threshold : not needed here
0); // flip triangle height threshold

std::array<halfedge_descriptor, 2> r2 = internal::is_badly_shaped(
face(opposite(he, mesh_), mesh_),
mesh_, vpmap_, vcmap_, ecmap_, gt_, cap_threshold, 4, 0, 0);
mesh_, vpmap_, vcmap_, ecmap_, gt_, 4, cap_threshold, 0, 0);

const bool badly_shaped = (r1[0] != boost::graph_traits<PolygonMesh>::null_halfedge()//needle
|| r1[1] != boost::graph_traits<PolygonMesh>::null_halfedge()//cap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,18 @@ namespace Polygon_mesh_processing {
namespace internal {

template <typename TriangleMesh, typename VPM, typename VCM, typename ECM, typename Traits>
std::array<typename boost::graph_traits<TriangleMesh>::halfedge_descriptor, 2>
is_badly_shaped(const typename boost::graph_traits<TriangleMesh>::face_descriptor f,
TriangleMesh& tmesh,
const VPM& vpm,
const VCM& vcm,
const ECM& ecm,
const Traits& gt,
const double cap_threshold, // angle over 160° ==> cap
const double needle_threshold, // longest edge / shortest edge over this ratio ==> needle
const double collapse_length_threshold, // max length of edges allowed to be collapsed
const double flip_triangle_height_threshold_squared) // max height of triangles allowed to be flipped
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor
is_it_a_needle(const typename boost::graph_traits<TriangleMesh>::face_descriptor f,
TriangleMesh& tmesh,
const VPM& vpm,
const VCM& vcm,
const ECM& /* ecm */, //not used because vcm is filled with end points of edges in ecm
const Traits& gt,
const double needle_threshold, // longest edge / shortest edge over this ratio ==> needle
const double collapse_length_threshold) // max length of edges allowed to be collapsed
{
namespace PMP = CGAL::Polygon_mesh_processing;

typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;

const halfedge_descriptor null_h = boost::graph_traits<TriangleMesh>::null_halfedge();

halfedge_descriptor res = PMP::is_needle_triangle_face(f, tmesh, needle_threshold,
Expand All @@ -78,21 +74,64 @@ is_badly_shaped(const typename boost::graph_traits<TriangleMesh>::face_descripto
if(collapse_length_threshold == 0 ||
edge_length(res, tmesh, parameters::vertex_point_map(vpm).geom_traits(gt)) <= collapse_length_threshold)
{
return make_array(res, null_h);
return res;
}
}

res = PMP::is_cap_triangle_face(f, tmesh, cap_threshold, parameters::vertex_point_map(vpm).geom_traits(gt));
return null_h;
}

template <typename TriangleMesh, typename VPM, typename VCM, typename ECM, typename Traits>
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor
is_it_a_cap(const typename boost::graph_traits<TriangleMesh>::face_descriptor f,
TriangleMesh& tmesh,
const VPM& vpm,
const VCM& /* vcm */,
const ECM& ecm,
const Traits& gt,
const double cap_threshold, // angle over 160° ==> cap
const double flip_triangle_height_threshold_squared) // max height of triangles allowed to be flipped
{
namespace PMP = CGAL::Polygon_mesh_processing;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
const halfedge_descriptor null_h = boost::graph_traits<TriangleMesh>::null_halfedge();

halfedge_descriptor res =
PMP::is_cap_triangle_face(f, tmesh, cap_threshold, parameters::vertex_point_map(vpm).geom_traits(gt));
if( res != null_h && !get(ecm, edge(res, tmesh) ) &&
(flip_triangle_height_threshold_squared == 0 ||
typename Traits::Compare_squared_distance_3()( get(vpm, target(next(res,tmesh), tmesh)),
typename Traits::Line_3(get(vpm, source(res,tmesh)), get(vpm, target(res,tmesh))),
flip_triangle_height_threshold_squared) != LARGER ))
{
return make_array(null_h, res);
return res;
}

return make_array(null_h, null_h);
return null_h;
}

template <typename TriangleMesh, typename VPM, typename VCM, typename ECM, typename Traits>
std::array<typename boost::graph_traits<TriangleMesh>::halfedge_descriptor, 2>
is_badly_shaped(const typename boost::graph_traits<TriangleMesh>::face_descriptor f,
TriangleMesh& tmesh,
const VPM& vpm,
const VCM& vcm,
const ECM& ecm,
const Traits& gt,
const double needle_threshold, // longest edge / shortest edge over this ratio ==> needle
const double cap_threshold, // angle over 160° ==> cap
const double collapse_length_threshold, // max length of edges allowed to be collapsed
const double flip_triangle_height_threshold_squared) // max height of triangles allowed to be flipped
{

typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
const halfedge_descriptor null_h = boost::graph_traits<TriangleMesh>::null_halfedge();
std::array<halfedge_descriptor,2> retval = make_array(null_h, null_h);

retval[0] = is_it_a_needle(f, tmesh, vpm, vcm, ecm, gt, needle_threshold, collapse_length_threshold);
retval[1] = is_it_a_cap(f, tmesh, vpm, vcm, ecm, gt, cap_threshold, flip_triangle_height_threshold_squared);

return retval;
}

template <typename TriangleMesh, typename HalfedgeContainer,
Expand All @@ -112,14 +151,17 @@ void collect_badly_shaped_triangles(const typename boost::graph_traits<TriangleM
{
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;

std::array<halfedge_descriptor, 2> res = is_badly_shaped(f, tmesh, vpm, vcm, ecm, gt, cap_threshold,
needle_threshold,
std::array<halfedge_descriptor, 2> res = is_badly_shaped(f, tmesh, vpm, vcm, ecm, gt,
needle_threshold, cap_threshold,
collapse_length_threshold, flip_triangle_height_threshold_squared);

if(res[0] != boost::graph_traits<TriangleMesh>::null_halfedge())
{
#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA
std::cout << "add new needle: " << edge(res[0], tmesh) << std::endl;
if (res[1] == boost::graph_traits<TriangleMesh>::null_halfedge())
std::cout << "add new needle: " << edge(res[0], tmesh) << std::endl;
else
std::cout << "add new needle (also a cap): " << edge(res[0], tmesh) << std::endl;
MaelRL marked this conversation as resolved.
Show resolved Hide resolved
#endif
CGAL_assertion(!is_border(res[0], tmesh));
CGAL_assertion(!get(ecm, edge(res[0], tmesh)));
Expand Down Expand Up @@ -738,29 +780,35 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
<< " (" << source(e, tmesh) << " " << tmesh.point(source(h, tmesh))
<< " --- " << source(e, tmesh) << " " << tmesh.point(target(h, tmesh)) << ")" << std::endl;
#endif

if(CGAL::Euler::does_satisfy_link_condition(e, tmesh))
{
// Verify that the element is still badly shaped
const std::array<halfedge_descriptor, 2> nc =
internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt,
cap_threshold, needle_threshold, collapse_length_threshold, flip_triangle_height_threshold_squared);
needle_threshold, cap_threshold, collapse_length_threshold, flip_triangle_height_threshold_squared);

if(nc[0] != h)
{
#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA
std::cout << "\t Needle criteria no longer verified" << std::endl;
#endif
if (nc[1]!=boost::graph_traits<TriangleMesh>::null_halfedge()) edges_to_flip.insert(nc[1]);
continue;
}


// pick the orientation of edge to keep the vertex minimizing the volume variation
const halfedge_descriptor best_h = internal::get_best_edge_orientation(e, tmesh, vpm, vcm, gt);
if(best_h == boost::graph_traits<TriangleMesh>::null_halfedge())
{
#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA
std::cout << "\t Geometrically invalid edge collapse!" << std::endl;
#endif
next_edges_to_collapse.insert(h);
if (nc[1]!=boost::graph_traits<TriangleMesh>::null_halfedge())
edges_to_flip.insert(nc[1]);
else
next_edges_to_collapse.insert(h);
continue;
}

Expand All @@ -769,7 +817,10 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA
std::cout << "\t edge collapse prevented by the user functor" << std::endl;
#endif
next_edges_to_collapse.insert(h);
if (nc[1]!=boost::graph_traits<TriangleMesh>::null_halfedge())
edges_to_flip.insert(nc[1]);
else
next_edges_to_collapse.insert(h);
continue;
}

Expand Down Expand Up @@ -862,7 +913,20 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA
std::cout << "\t Uncollapsable edge!" << std::endl;
#endif
next_edges_to_collapse.insert(h);

halfedge_descriptor nc =
internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt,
cap_threshold, flip_triangle_height_threshold_squared);

if (nc==boost::graph_traits<TriangleMesh>::null_halfedge())
next_edges_to_collapse.insert(h);
else
{
#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA
std::cout << "\t Uncollapsable edge --> register it as cap!" << std::endl;
#endif
edges_to_flip.insert(nc);
}
}
}

Expand All @@ -889,11 +953,11 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
<< " --- " << target(e, tmesh) << " " << tmesh.point(target(h, tmesh)) << ")" << std::endl;
#endif

std::array<halfedge_descriptor,2> nc = internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt,
cap_threshold, needle_threshold,
collapse_length_threshold, flip_triangle_height_threshold_squared);
halfedge_descriptor nc =
internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt,
cap_threshold, flip_triangle_height_threshold_squared);
// Check the triangle is still a cap
if(nc[1] != h)
if(nc != h)
{
#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA
std::cout << "\t Cap criteria no longer verified" << std::endl;
Expand Down Expand Up @@ -965,7 +1029,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
CGAL_assertion(!is_border(h, tmesh));
std::array<halfedge_descriptor, 2> nc =
internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt,
cap_threshold, needle_threshold,
needle_threshold, cap_threshold,
collapse_length_threshold, flip_triangle_height_threshold_squared);

if(nc[1] != boost::graph_traits<TriangleMesh>::null_halfedge() && nc[1] != h)
Expand Down
Loading