[Bf-blender-cvs] [f283b95] master: BMesh: BM_vert_separate double edge fix

Campbell Barton noreply at git.blender.org
Sat May 2 08:27:54 CEST 2015


Commit: f283b959e7d4ebd3fc2cddc480d2f08cef662caf
Author: Campbell Barton
Date:   Sat May 2 16:04:02 2015 +1000
Branches: master
https://developer.blender.org/rBf283b959e7d4ebd3fc2cddc480d2f08cef662caf

BMesh: BM_vert_separate double edge fix

Splitting edges could give duplicates.

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

M	source/blender/bmesh/intern/bmesh_core.c
M	source/blender/bmesh/intern/bmesh_core.h
M	source/blender/python/bmesh/bmesh_py_utils.c

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

diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index 38849b7..7083642 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -2053,6 +2053,16 @@ bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
 	return true;
 }
 
+
+/** \name BM_vert_separate, bmesh_vert_separate and friends
+ * \{ */
+
+/* BM_edge_face_count(e) >= 1 */
+BLI_INLINE bool bm_edge_supports_separate(const BMEdge *e)
+{
+	return (e->l && e->l->radial_next != e->l);
+}
+
 /**
  * \brief Separate Vert
  *
@@ -2176,24 +2186,125 @@ void bmesh_vert_separate(
 }
 
 /**
+ * Utility function for #BM_vert_separate
+ *
+ * Takes a list of edges, which have been split from their original.
+ *
+ * Any edges which failed to split off in #bmesh_vert_separate will be merged back into the original edge.
+ *
+ * \param edges_seperate
+ * A list-of-lists, each list is from a single original edge (the first edge is the original),
+ * Check for duplicates (not just with the first) but between all.
+ * This is O(n2) but radial edges are very rarely >2 and almost never >~10.
+ *
+ * \note typically its best to avoid createing the data in the first place,
+ * but inspecting all loops connectivity is quite involved.
+ *
+ * \note this function looks like it could become slow,
+ * but in common cases its only going to iterate a few times.
+ */
+static void bmesh_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate)
+{
+	do {
+		LinkNode *n_orig = edges_separate->link;
+		do {
+			BMEdge *e_orig = n_orig->link;
+			LinkNode *n_step = n_orig->next;
+			LinkNode *n_prev = n_orig;
+			do {
+				BMEdge *e = n_step->link;
+				BLI_assert(e != e_orig);
+				if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2)) {
+					BM_edge_splice(bm, e_orig, e);
+					n_prev->next = n_step->next;
+					n_step = n_prev;
+				}
+			} while ((n_prev = n_step),
+			         (n_step = n_step->next));
+
+		} while ((n_orig = n_orig->next) && n_orig->next);
+	} while ((edges_separate = edges_separate->next));
+}
+
+/**
  * High level function which wraps both #bmesh_vert_separate and #bmesh_edge_separate
  */
 void BM_vert_separate(
-        BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
-        BMEdge **e_in, int e_in_len)
+        BMesh *bm, BMVert *v,
+        BMEdge **e_in, int e_in_len,
+        const bool copy_select,
+        BMVert ***r_vout, int *r_vout_len)
 {
+	LinkNode *edges_separate = NULL;
 	int i;
 
 	for (i = 0; i < e_in_len; i++) {
 		BMEdge *e = e_in[i];
-		if (e->l && BM_vert_in_edge(e, v)) {
-			bmesh_edge_separate(bm, e, e->l, false);
+		if (bm_edge_supports_separate(e)) {
+			LinkNode *edges_orig = NULL;
+			do {
+				BMLoop *l_sep = e->l;
+				bmesh_edge_separate(bm, e, l_sep, copy_select);
+				BLI_linklist_prepend_alloca(&edges_orig, l_sep->e);
+				BLI_assert(e != l_sep->e);
+			} while (bm_edge_supports_separate(e));
+			BLI_linklist_prepend_alloca(&edges_orig, e);
+			BLI_linklist_prepend_alloca(&edges_separate, edges_orig);
 		}
 	}
 
-	bmesh_vert_separate(bm, v, r_vout, r_vout_len, false);
+	bmesh_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
+
+	if (edges_separate) {
+		bmesh_vert_separate__cleanup(bm, edges_separate);
+	}
+}
+
+
+/**
+ * A version of #BM_vert_separate which takes a flag.
+ */
+void BM_vert_separate_hflag(
+        BMesh *bm, BMVert *v,
+        const char hflag,
+        const bool copy_select,
+        BMVert ***r_vout, int *r_vout_len)
+{
+	LinkNode *edges_separate = NULL;
+	BMEdge *e_iter, *e_first;
+
+	e_iter = e_first = v->e;
+	do {
+		if (BM_elem_flag_test(e_iter, hflag)) {
+			BMEdge *e = e_iter;
+			if (bm_edge_supports_separate(e)) {
+				LinkNode *edges_orig = NULL;
+				do {
+					BMLoop *l_sep = e->l;
+					bmesh_edge_separate(bm, e, l_sep, copy_select);
+					/* trick to avoid looping over seperated edges */
+					if (edges_separate == NULL && edges_orig == NULL) {
+						e_first = l_sep->e;
+					}
+					BLI_linklist_prepend_alloca(&edges_orig, l_sep->e);
+					BLI_assert(e != l_sep->e);
+				} while (bm_edge_supports_separate(e));
+				BLI_linklist_prepend_alloca(&edges_orig, e);
+				BLI_linklist_prepend_alloca(&edges_separate, edges_orig);
+			}
+		}
+	} while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
+
+	bmesh_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
+
+	if (edges_separate) {
+		bmesh_vert_separate__cleanup(bm, edges_separate);
+	}
 }
 
+/** \} */
+
+
 /**
  * \brief Splice Edge
  *
@@ -2261,7 +2372,7 @@ void bmesh_edge_separate(
 	BLI_assert(e->l);
 	
 	if (BM_edge_is_boundary(e)) {
-		/* no cut required */
+		BLI_assert(0); /* no cut required */
 		return;
 	}
 
diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h
index 452ed07..54656fc 100644
--- a/source/blender/bmesh/intern/bmesh_core.h
+++ b/source/blender/bmesh/intern/bmesh_core.h
@@ -77,8 +77,11 @@ bool    bmesh_loop_reverse(BMesh *bm, BMFace *f);
 
 BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del);
 void    BM_vert_separate(
-        BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
-        BMEdge **e_in, int e_in_len);
+        BMesh *bm, BMVert *v, BMEdge **e_in, int e_in_len, const bool copy_select,
+        BMVert ***r_vout, int *r_vout_len);
+void BM_vert_separate_hflag(
+        BMesh *bm, BMVert *v, const char hflag, const bool copy_select,
+        BMVert ***r_vout, int *r_vout_len);
 
 /* EULER API - For modifying structure */
 BMFace *bmesh_sfme(
diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c
index f810a64..b789092 100644
--- a/source/blender/python/bmesh/bmesh_py_utils.c
+++ b/source/blender/python/bmesh/bmesh_py_utils.c
@@ -307,7 +307,7 @@ static PyObject *bpy_bm_utils_vert_separate(PyObject *UNUSED(self), PyObject *ar
 		return NULL;
 	}
 
-	BM_vert_separate(bm, py_vert->v, &elem, &elem_len, edge_array, edge_array_len);
+	BM_vert_separate(bm, py_vert->v, edge_array, edge_array_len, false, &elem, &elem_len);
 	/* return collected verts */
 	ret = BPy_BMVert_Array_As_Tuple(bm, elem, elem_len);
 	MEM_freeN(elem);




More information about the Bf-blender-cvs mailing list