From b27653493a12e0668cf0d86630909e51fce82f49 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 25 Nov 2022 13:45:23 +0100 Subject: [PATCH] Measurement: prevent ending up in an infinite loop with broken models --- src/libslic3r/Measure.cpp | 16 ++++++++++++++-- src/libslic3r/SurfaceMesh.hpp | 9 +++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index a9cea06bd..37bf68e83 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -189,10 +189,16 @@ void MeasuringImpl::update_planes() he = sm.next_around_target(he); if (he.is_invalid()) goto PLANE_FAILURE; + + // For broken meshes, the iteration might never get back to he_orig. + // Remember all halfedges we saw to break out of such infinite loops. + boost::container::small_vector he_seen; + while ( (int)m_face_to_plane[sm.face(he)] == plane_id && he != he_orig) { + he_seen.emplace_back(he); he = sm.next_around_target(he); - if (he.is_invalid()) - goto PLANE_FAILURE; + if (he.is_invalid() || std::find(he_seen.begin(), he_seen.end(), he) != he_seen.end()) + goto PLANE_FAILURE; } he = sm.opposite(he); if (he.is_invalid()) @@ -210,6 +216,12 @@ void MeasuringImpl::update_planes() visited[face_it - facets.begin()][he.side()] = true; last_border.emplace_back(sm.point(sm.source(he)).cast()); + + // In case of broken meshes, this loop might be infinite. Break + // out in case it is clearly going bad. + if (last_border.size() > 3*facets.size()) + goto PLANE_FAILURE; + } while (he != he_start); if (last_border.size() == 1) diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp index 9e547eec4..93eb9fdaa 100644 --- a/src/libslic3r/SurfaceMesh.hpp +++ b/src/libslic3r/SurfaceMesh.hpp @@ -4,6 +4,8 @@ #include #include +#include "boost/container/small_vector.hpp" + namespace Slic3r { class TriangleMesh; @@ -115,11 +117,18 @@ public: size_t degree(Vertex_index v) const { + // In case the mesh is broken badly, the loop might end up to be infinite, + // never getting back to the first halfedge. Remember list of all half-edges + // and trip if any is encountered for the second time. Halfedge_index h_first = halfedge(v); + boost::container::small_vector he_visited; Halfedge_index h = next_around_target(h_first); size_t degree = 2; while (! h.is_invalid() && h != h_first) { + he_visited.emplace_back(h); h = next_around_target(h); + if (std::find(he_visited.begin(), he_visited.end(), h) == he_visited.end()) + return 0; ++degree; } return h.is_invalid() ? 0 : degree - 1;