diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-01-17 04:34:05 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-01-17 06:17:02 +0300 |
commit | a8e7275627a065e987172101aec5e1ddea3c4e36 (patch) | |
tree | 7943b03b087762d225c0dcb2dcea211afdb34d93 | |
parent | 6fac10dd0d6ad601388c378b75459ee78c468384 (diff) |
BMesh: keep selection history when removing doubles
Auto-merge would loose the active vertex.
-rw-r--r-- | source/blender/bmesh/intern/bmesh_marking.c | 65 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_marking.h | 3 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_removedoubles.c | 43 |
3 files changed, 109 insertions, 2 deletions
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index add4529e18d..5ac5dedb595 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -43,6 +43,9 @@ #include "bmesh.h" #include "bmesh_structure.h" +/* For '_FLAG_OVERLAP'. */ +#include "bmesh_private.h" + static void recount_totsels(BMesh *bm) { const char iter_types[3] = {BM_VERTS_OF_MESH, @@ -1058,6 +1061,68 @@ GHash *BM_select_history_map_create(BMesh *bm) return map; } +/** + * Map arguments may all be the same pointer. + */ +void BM_select_history_merge_from_targetmap( + BMesh *bm, + GHash *vert_map, + GHash *edge_map, + GHash *face_map, + const bool use_chain) +{ + +#ifdef DEBUG + for (BMEditSelection *ese = bm->selected.first; ese; ese = ese->next) { + BLI_assert(BM_ELEM_API_FLAG_TEST(ese->ele, _FLAG_OVERLAP) == 0); + } +#endif + + for (BMEditSelection *ese = bm->selected.first; ese; ese = ese->next) { + BM_ELEM_API_FLAG_ENABLE(ese->ele, _FLAG_OVERLAP); + + /* Only loop when (use_chain == true). */ + GHash *map = NULL; + switch (ese->ele->head.htype) { + case BM_VERT: map = vert_map; break; + case BM_EDGE: map = edge_map; break; + case BM_FACE: map = face_map; break; + default: BMESH_ASSERT(0); break; + } + if (map != NULL) { + BMElem *ele_dst = ese->ele; + while (true) { + BMElem *ele_dst_next = BLI_ghash_lookup(map, ele_dst); + BLI_assert(ele_dst != ele_dst_next); + if (ele_dst_next == NULL) { + break; + } + ele_dst = ele_dst_next; + /* Break loop on circular reference (should never happen). */ + if (UNLIKELY(ele_dst == ese->ele)) { + BLI_assert(0); + break; + } + if (use_chain == false) { + break; + } + } + ese->ele = ele_dst; + } + } + + /* Remove overlapping duplicates. */ + for (BMEditSelection *ese = bm->selected.first, *ese_next; ese; ese = ese_next) { + ese_next = ese->next; + if (BM_ELEM_API_FLAG_TEST(ese->ele, _FLAG_OVERLAP)) { + BM_ELEM_API_FLAG_DISABLE(ese->ele, _FLAG_OVERLAP); + } + else { + BLI_freelinkN(&bm->selected, ese); + } + } +} + void BM_mesh_elem_hflag_disable_test( BMesh *bm, const char htype, const char hflag, const bool respecthide, const bool overwrite, const char hflag_test) diff --git a/source/blender/bmesh/intern/bmesh_marking.h b/source/blender/bmesh/intern/bmesh_marking.h index 4730af66a74..8e6a8f9e991 100644 --- a/source/blender/bmesh/intern/bmesh_marking.h +++ b/source/blender/bmesh/intern/bmesh_marking.h @@ -114,6 +114,9 @@ void BM_select_history_clear(BMesh *bm); bool BM_select_history_active_get(BMesh *bm, struct BMEditSelection *ese); struct GHash *BM_select_history_map_create(BMesh *bm); +void BM_select_history_merge_from_targetmap( + BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain); + #define BM_SELECT_HISTORY_BACKUP(bm) { \ ListBase _bm_prev_selected = (bm)->selected; BLI_listbase_clear(&(bm)->selected) diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index ed06090bb79..d096642a62a 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -31,6 +31,7 @@ #include "BLI_math.h" #include "BLI_alloca.h" #include "BLI_kdtree.h" +#include "BLI_listbase.h" #include "BLI_utildefines_stack.h" #include "BLI_stack.h" @@ -199,6 +200,15 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) BMFace *f; BMOpSlot *slot_targetmap = BMO_slot_get(op->slots_in, "targetmap"); + /* Maintain selection history. */ + const bool has_selected = !BLI_listbase_is_empty(&bm->selected); + const bool use_targetmap_all = has_selected; + GHash *targetmap_all = NULL; + if (use_targetmap_all) { + /* Map deleted to keep elem. */ + targetmap_all = BLI_ghash_ptr_new(__func__); + } + /* mark merge verts for deletion */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { BMVert *v_dst = BMO_slot_map_elem_get(slot_targetmap, v); @@ -207,6 +217,11 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) /* merge the vertex flags, else we get randomly selected/unselected verts */ BM_elem_flag_merge_ex(v, v_dst, BM_ELEM_HIDDEN); + + if (use_targetmap_all) { + BLI_assert(v != v_dst); + BLI_ghash_insert(targetmap_all, v, v_dst); + } } } @@ -237,6 +252,10 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) e_new = BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP); } BM_elem_flag_merge_ex(e_new, e, BM_ELEM_HIDDEN); + if (use_targetmap_all) { + BLI_assert(e != e_new); + BLI_ghash_insert(targetmap_all, e, e_new); + } } BMO_edge_flag_enable(bm, e, ELE_DEL); @@ -259,12 +278,13 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) } if (vert_delete) { + bool use_in_place = false; + BMFace *f_new = NULL; BMO_face_flag_enable(bm, f, ELE_DEL); if (f->len - edge_collapse >= 3) { bool created; - BMFace *f_new = remdoubles_createface(bm, f, slot_targetmap, &created); - + f_new = remdoubles_createface(bm, f, slot_targetmap, &created); /* do this so we don't need to return a list of created faces */ if (f_new) { if (created) { @@ -276,15 +296,34 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) BMO_face_flag_disable(bm, f, ELE_DEL); BM_face_kill(bm, f_new); + use_in_place = true; } else { BM_elem_flag_merge_ex(f_new, f, BM_ELEM_HIDDEN); } } } + + if ((use_in_place == false) && (f_new != NULL)) { + BLI_assert(f != f_new); + if (use_targetmap_all) { + BLI_ghash_insert(targetmap_all, f, f_new); + } + if (bm->act_face && (f == bm->act_face)) { + bm->act_face = f_new; + } + } } } + if (has_selected) { + BM_select_history_merge_from_targetmap(bm, targetmap_all, targetmap_all, targetmap_all, true); + } + + if (use_targetmap_all) { + BLI_ghash_free(targetmap_all, NULL, NULL); + } + BMO_mesh_delete_oflag_context(bm, ELE_DEL, DEL_ONLYTAGGED); } |