From f9649e2bf1848d44ddf8739dd3ef6e087f291f28 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Wed, 22 Apr 2020 12:47:53 -0300 Subject: Fix T75994: Crash with 'Split Edges and Faces' | Auto-Merge It occurred when an edge was collapsed into a vert that was not part of it. This is common when the distance for merging is relatively large. --- source/blender/bmesh/tools/bmesh_intersect_edges.c | 62 +++++++++++++++++----- 1 file changed, 50 insertions(+), 12 deletions(-) (limited to 'source/blender/bmesh') diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c index 2df7c85871d..e2d03a65d46 100644 --- a/source/blender/bmesh/tools/bmesh_intersect_edges.c +++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c @@ -152,6 +152,7 @@ static BMFace *bm_vert_pair_best_face_get( sub_v3_v3v3(data[1], v_a->co, data[0]); r_best_face = BM_vert_pair_shared_face_cb( v_a, v_b, false, bm_vert_pair_share_splittable_face_cb, &data, &dummy, &dummy); + BLI_assert(!r_best_face || BM_edge_in_face(edgenet[0], r_best_face) == false); } else { struct EDBMSplitBestFaceData data = { @@ -846,6 +847,7 @@ bool BM_mesh_intersect_edges( v_val = (*pair_iter)[1].vert; BLI_ghash_insert(r_targetmap, v_key, v_val); if (split_faces) { + /* The vertex index indicates its position in the pair_array flat. */ BM_elem_index_set(v_key, i * 2); BM_elem_index_set(v_val, i * 2 + 1); } @@ -858,6 +860,7 @@ bool BM_mesh_intersect_edges( struct EDBMSplitElem *pair_flat = (struct EDBMSplitElem *)&pair_array[0]; BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + /* Edge out of context or already tested. */ continue; } @@ -869,7 +872,7 @@ bool BM_mesh_intersect_edges( int v_cut_other = BM_elem_index_get(vb); if (v_cut == -1 && v_cut_other == -1) { if (!BM_elem_flag_test(va, BM_ELEM_TAG) && !BM_elem_flag_test(vb, BM_ELEM_TAG)) { - /* Ignore edges out of context. */ + /* Edge out of context. */ BM_elem_flag_enable(e, BM_ELEM_TAG); } continue; @@ -884,38 +887,65 @@ bool BM_mesh_intersect_edges( v_cut_other = -1; } + /* `v_cut` indicates the other vertex within the `pair_array`. */ v_cut += v_cut % 2 ? -1 : 1; va_dest = pair_flat[v_cut].vert; + if (BM_vert_pair_share_face_check(va, va_dest)) { + /* Vert par acts on the same face. + * Although there are cases like this where the face can be splitted, + * for efficiency it is better to ignore then. */ + continue; + } + BMFace *best_face = NULL; - int edgenet_len = 0; BMVert *v_other_dest, *v_other = vb; BMEdge *e_net = e; + int edgenet_len = 0; while (true) { - if (edgenet_alloc_len == edgenet_len) { - edgenet_alloc_len = (edgenet_alloc_len + 1) * 2; - edgenet = MEM_reallocN(edgenet, (edgenet_alloc_len) * sizeof(*edgenet)); - } - edgenet[edgenet_len++] = e_net; - if (v_cut_other != -1) { v_cut_other += v_cut_other % 2 ? -1 : 1; v_other_dest = pair_flat[v_cut_other].vert; + + if (BM_vert_pair_share_face_check(v_other, v_other_dest)) { + /* Vert par acts on the same face. + * Although there are cases like this where the face can be splitted, + * for efficiency and to avoid complications, it is better to ignore these cases. + */ + break; + } } else { v_other_dest = v_other; } - if (BM_edge_exists(va_dest, v_other_dest)) { - /* No need to detect face. (Optimization). */ + if (va_dest == v_other_dest) { + /* Edge/Edgenet to vertex - we can't split the face. */ break; } + if (edgenet_len == 0 && BM_edge_exists(va_dest, v_other_dest)) { + /* Edge to edge - no need to detect face. */ + break; + } + + if (edgenet_alloc_len == edgenet_len) { + edgenet_alloc_len = (edgenet_alloc_len + 1) * 2; + edgenet = MEM_reallocN(edgenet, (edgenet_alloc_len) * sizeof(*edgenet)); + } + edgenet[edgenet_len++] = e_net; best_face = bm_vert_pair_best_face_get( va_dest, v_other_dest, edgenet, edgenet_len, dist); if (best_face) { - if (va_dest != va) { + if ((va_dest != va) && !BM_edge_exists(va_dest, va)) { + /** + *
+                 *  va---vb---
+                 *      /
+                 *  va_dest
+                 * 
+ */ e_net = edgenet[0]; if (edgenet_len > 1) { vb = BM_edge_other_vert(e_net, va); @@ -925,7 +955,15 @@ bool BM_mesh_intersect_edges( } edgenet[0] = BM_edge_create(bm, va_dest, vb, e_net, BM_CREATE_NOP); } - if ((edgenet_len > 1) && (v_other_dest != v_other)) { + if ((edgenet_len > 1) && (v_other_dest != v_other) && + !BM_edge_exists(v_other_dest, v_other)) { + /** + *
+                 *  ---v---v_other
+                 *      \
+                 *       v_other_dest
+                 * 
+ */ e_net = edgenet[edgenet_len - 1]; edgenet[edgenet_len - 1] = BM_edge_create( bm, v_other_dest, BM_edge_other_vert(e_net, v_other), e_net, BM_CREATE_NOP); -- cgit v1.2.3