[Bf-blender-cvs] [a8e7275627a] blender2.7: BMesh: keep selection history when removing doubles

Campbell Barton noreply at git.blender.org
Thu Jan 17 04:17:35 CET 2019


Commit: a8e7275627a065e987172101aec5e1ddea3c4e36
Author: Campbell Barton
Date:   Thu Jan 17 12:34:05 2019 +1100
Branches: blender2.7
https://developer.blender.org/rBa8e7275627a065e987172101aec5e1ddea3c4e36

BMesh: keep selection history when removing doubles

Auto-merge would loose the active vertex.

===================================================================

M	source/blender/bmesh/intern/bmesh_marking.c
M	source/blender/bmesh/intern/bmesh_marking.h
M	source/blender/bmesh/operators/bmo_removedoubles.c

===================================================================

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);
 }



More information about the Bf-blender-cvs mailing list