Browse Source

Fix: prevent degeneration of model during simplification

Filip Sykala 3 years ago
parent
commit
ef5c94f90a

+ 26 - 1
src/libslic3r/QuadricEdgeCollapse.cpp

@@ -77,7 +77,8 @@ namespace QuadricEdgeCollapse {
         uint32_t ti, const EdgeInfos& e_infos, const Indices& indices);
     bool is_flipped(const Vec3f &new_vertex, uint32_t ti0, uint32_t ti1, const VertexInfo& v_info, 
         const TriangleInfos &t_infos, const EdgeInfos &e_infos, const indexed_triangle_set &its);
-
+    bool degenerate(uint32_t vi, uint32_t ti0, uint32_t ti1, const VertexInfo &v_info, 
+        const EdgeInfos &e_infos, const Indices &indices);
     // find edge with smallest error in triangle
     Vec3d calculate_3errors(const Triangle &t, const Vertices &vertices, const VertexInfos &v_infos);
     Error calculate_error(uint32_t ti, const Triangle& t,const Vertices &vertices, const VertexInfos& v_infos, unsigned char& min_index);
@@ -179,6 +180,8 @@ void Slic3r::its_quadric_edge_collapse(
             find_triangle_index1(vi1, v_info0, ti0, e_infos, its.indices) :
             find_triangle_index1(vi0, v_info1, ti0, e_infos, its.indices) ;
         if (!ti1_opt.has_value() || // edge has only one triangle
+            degenerate(vi0, ti0, *ti1_opt, v_info1, e_infos, its.indices) ||
+            degenerate(vi1, ti0, *ti1_opt, v_info0, e_infos, its.indices) ||
             is_flipped(new_vertex0, ti0, *ti1_opt, v_info0, t_infos, e_infos, its) ||
             is_flipped(new_vertex0, ti0, *ti1_opt, v_info1, t_infos, e_infos, its)) {
             // try other triangle's edge
@@ -487,6 +490,28 @@ bool QuadricEdgeCollapse::is_flipped(const Vec3f &               new_vertex,
     return false;
 }
 
+bool QuadricEdgeCollapse::degenerate(uint32_t          vi,
+                                     uint32_t          ti0,
+                                     uint32_t          ti1,
+                                     const VertexInfo &v_info,
+                                     const EdgeInfos & e_infos,
+                                     const Indices &   indices)
+{
+    // check surround triangle do not contain vertex index
+    // protect from creation of triangle with two same vertices inside
+    size_t v_info_end = v_info.start + v_info.count;
+    for (size_t ei = v_info.start; ei < v_info_end; ++ei) {
+        assert(ei < e_infos.size());
+        const EdgeInfo &e_info = e_infos[ei];
+        if (e_info.t_index == ti0) continue; // ti0 will be deleted
+        if (e_info.t_index == ti1) continue; // ti1 will be deleted
+        const Triangle &t = indices[e_info.t_index];
+        for (size_t i = 0; i < 3; ++i)
+            if (t[i] == vi) return true;
+    }
+    return false;
+}
+
 Vec3d QuadricEdgeCollapse::calculate_3errors(const Triangle &   t,
                                              const Vertices &   vertices,
                                              const VertexInfos &v_infos)

+ 46 - 0
tests/data/simplification.obj

@@ -0,0 +1,46 @@
+v 39.349007 -54.069000 -199.819000
+v 39.489006 -54.029007 -199.815002
+v 39.419006 -53.993011 -199.769012
+v 39.629005 -53.975006 -199.815002
+v 39.639008 -53.947006 -199.805023
+v 39.651001 -53.919006 -199.795013
+v 39.807007 -53.863007 -199.796997
+v 39.729004 -53.891006 -199.796997
+v 39.727005 -53.935013 -199.813019
+v 39.767006 -53.899002 -199.805023
+v 39.871002 -53.835007 -199.801025
+v 39.443001 -53.829010 -199.878998
+v 39.523003 -53.965012 -199.827026
+v 39.807007 -53.863007 -199.796997
+v 39.833008 -53.723007 -199.723022
+v 39.759003 -53.822998 -199.822998
+v 39.867004 -53.845001 -199.805023
+v 39.937004 -53.805008 -199.805023
+f 1 2 3
+f 4 5 2
+f 2 6 3
+f 7 8 4
+f 9 10 4
+f 10 9 11
+f 12 2 1
+f 13 6 4
+f 13 4 2
+f 8 7 9
+f 6 9 4
+f 6 14 15
+f 16 14 6
+f 17 18 9
+f 3 6 15
+f 12 16 6
+f 12 6 13
+f 12 13 2
+f 5 4 8
+f 6 8 9
+f 5 6 2
+f 6 5 8
+f 17 9 7
+f 7 11 17
+f 18 11 9
+f 11 18 17
+f 10 7 4
+f 7 10 11

+ 11 - 1
tests/libslic3r/test_indexed_triangle_set.cpp

@@ -246,4 +246,14 @@ TEST_CASE("Simplify mesh by Quadric edge collapse to 5%", "[its]")
     CHECK(fabs(original_volume - volume) < 33.);
     float avg_distance = compare(mesh.its, its, 10);
     CHECK(avg_distance < 0.022f); // 0.02022 | 0.0199614074
-}
+}
+
+TEST_CASE("Simplify trouble case", "[its]")
+{
+    TriangleMesh tm = load_model("simplification.obj");
+    REQUIRE_FALSE(tm.empty());
+    float max_error = std::numeric_limits<float>::max();
+    uint32_t wanted_count = 8;
+    its_quadric_edge_collapse(tm.its, wanted_count, &max_error);
+    CHECK(tm.its.indices.size() <= 8);
+}