[Bf-blender-cvs] [008c1db] master: BMesh: split-py-edge now splices verts into edges

Campbell Barton noreply at git.blender.org
Tue Dec 15 06:32:04 CET 2015


Commit: 008c1dbb944ead58967343f2ed8fe4f145a7bdc0
Author: Campbell Barton
Date:   Tue Dec 15 16:08:33 2015 +1100
Branches: master
https://developer.blender.org/rB008c1dbb944ead58967343f2ed8fe4f145a7bdc0

BMesh: split-py-edge now splices verts into edges

Edge chains spanning faces or ending without a connecting edge
are now supported by splicing verts into the face boundaries.

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

M	source/blender/editors/mesh/editmesh_intersect.c

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

diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index ed35e46..b60df2e 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -436,6 +436,123 @@ static void bm_face_split_by_edges_island_connect(
 	        NULL, NULL);
 }
 
+/**
+ * Check if \a v_pivot should be spliced into an existing edge.
+ *
+ * Detect one of 3 cases:
+ *
+ * - \a v_pivot is shared by 2+ edges from different faces.
+ *   in this case return the closest edge shared by all faces.
+ *
+ * - \a v_pivot is an end-point of an edge which has no other edges connected.
+ *   in this case return the closest edge in \a f_a to the \a v_pivot.
+ *
+ * - \a v_pivot has only edges from the same face connected,
+ *   in this case return NULL. This is the most common case - no action is needed.
+ *
+ * \return the edge to be split.
+ *
+ * \note Currently we don't snap to verts or split chains by verts on-edges.
+ */
+static BMEdge *bm_face_split_edge_find(
+        BMEdge *e_a, BMFace *f_a, BMVert *v_pivot, BMFace **ftable, const int ftable_len,
+        float r_v_pivot_co[3], float *r_v_pivot_fac)
+{
+	const int f_a_index = BM_elem_index_get(e_a);
+	bool found_other_self = false;
+	int  found_other_face = 0;
+	BLI_SMALLSTACK_DECLARE(face_stack, BMFace *);
+
+	/* loop over surrounding edges to check if we're part of a chain or a delimiter vertex */
+	BMEdge *e_b = v_pivot->e;
+	do {
+		if (e_b != e_a) {
+			const int f_b_index = BM_elem_index_get(e_b);
+			if (f_b_index == f_a_index) {
+				/* not an endpoint */
+				found_other_self = true;
+			}
+			else if (f_b_index != -1) {
+				BLI_assert(f_b_index < ftable_len);
+				UNUSED_VARS_NDEBUG(ftable_len);
+
+				/* 'v_pivot' spans 2+ faces,
+				 * tag to ensure we pick an edge that includes this face */
+				BMFace *f_b = ftable[f_b_index];
+				if (!BM_elem_flag_test(f_b, BM_ELEM_INTERNAL_TAG)) {
+					BM_elem_flag_enable(f_b, BM_ELEM_INTERNAL_TAG);
+					BLI_SMALLSTACK_PUSH(face_stack, f_b);
+					found_other_face++;
+				}
+			}
+		}
+	} while ((e_b = BM_DISK_EDGE_NEXT(e_b, v_pivot)) != v_pivot->e);
+
+	BMEdge *e_split = NULL;
+
+	/* if we have no others or the other edge is outside this face,
+	 * we're an endpoint to connect to a boundary */
+	if ((found_other_self == false) || found_other_face) {
+
+		BMLoop *l_iter, *l_first;
+		l_iter = l_first = BM_FACE_FIRST_LOOP(f_a);
+		float dist_best_sq = FLT_MAX;
+
+		do {
+			float v_pivot_co_test[3];
+			float v_pivot_fac = line_point_factor_v3(v_pivot->co, l_iter->e->v1->co, l_iter->e->v2->co);
+			CLAMP(v_pivot_fac, 0.0f, 1.0f);
+			interp_v3_v3v3(v_pivot_co_test, l_iter->e->v1->co, l_iter->e->v2->co, v_pivot_fac);
+
+			float dist_test_sq = len_squared_v3v3(v_pivot_co_test, v_pivot->co);
+			if ((dist_test_sq < dist_best_sq) || (e_split == NULL)) {
+				bool ok = true;
+
+				if (UNLIKELY(BM_edge_exists(v_pivot, l_iter->e->v1) ||
+				             BM_edge_exists(v_pivot, l_iter->e->v2)))
+				{
+					/* very unlikley but will cause complications splicing the verts together,
+					 * so just skip this case */
+					ok = false;
+				}
+				else if (found_other_face) {
+					/* double check that _all_ the faces used by v_pivot's edges are attached to this edge
+					 * otherwise don't attempt the split since it will give non-deterministic results */
+					BMLoop *l_radial_iter = l_iter->radial_next;
+					int other_face_shared = 0;
+					if (l_radial_iter != l_iter) {
+						do {
+							if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_INTERNAL_TAG)) {
+								other_face_shared++;
+							}
+						} while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
+					}
+					if (other_face_shared != found_other_face) {
+						ok = false;
+					}
+				}
+
+				if (ok) {
+					e_split = l_iter->e;
+					dist_best_sq = dist_test_sq;
+					copy_v3_v3(r_v_pivot_co, v_pivot_co_test);
+					*r_v_pivot_fac = v_pivot_fac;
+				}
+			}
+		} while ((l_iter = l_iter->next) != l_first);
+	}
+
+	{
+		/* reset the flag, for future use */
+		BMFace *f;
+		while ((f = BLI_SMALLSTACK_POP(face_stack))) {
+			BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG);
+		}
+	}
+
+	return e_split;
+}
+
 #endif  /* USE_NET_ISLAND_CONNECT */
 
 
@@ -484,6 +601,7 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
 			else {
 				BM_elem_flag_disable(f, hflag);
 			}
+			BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG);
 			BM_elem_index_set(f, i);  /* set_ok */
 		}
 	}
@@ -570,7 +688,7 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
 	/* before overwriting edge index values, collect edges left untouched */
 	BLI_Stack *edges_loose = BLI_stack_new(sizeof(BMEdge * ), __func__);
 	BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
-		if (BM_elem_index_get(e) == -1 && BM_edge_is_wire(e)) {
+		if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) {
 			BLI_stack_push(edges_loose, &e);
 		}
 	}
@@ -588,9 +706,15 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
 
 		MemArena *mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
 
+		BM_mesh_elem_index_ensure(bm, BM_FACE);
+
 		{
 			BMBVHTree *bmbvh = BKE_bmbvh_new(bm, em->looptris, em->tottri, BMBVH_RESPECT_SELECT, NULL, NULL);
 
+			BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+				BM_elem_index_set(e, -1);  /* set_dirty */
+			}
+
 			while (!BLI_stack_is_empty(edges_loose)) {
 				BLI_stack_pop(edges_loose, &e);
 				float e_center[3];
@@ -599,12 +723,58 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
 				BMFace *f = BKE_bmbvh_find_face_closest(bmbvh, e_center, FLT_MAX);
 				if (f) {
 					ghash_insert_face_edge_link(face_edge_map, f, e, mem_arena);
+					BM_elem_index_set(e, BM_elem_index_get(f));  /* set_dirty */
 				}
 			}
 
 			BKE_bmbvh_free(bmbvh);
 		}
 
+		bm->elem_index_dirty |= BM_EDGE;
+
+		BM_mesh_elem_table_ensure(bm, BM_FACE);
+
+		/* detect edges chains that span faces
+		 * and splice vertices into the closest edges */
+		{
+			GHashIterator gh_iter;
+
+			GHASH_ITER(gh_iter, face_edge_map) {
+				BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+				struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
+				LinkNode *e_link = e_ls_base->list;
+
+				do {
+					e = e_link->link;
+
+					for (int j = 0; j < 2; j++) {
+						BMVert *v_pivot = (&e->v1)[j];
+						/* checking that \a v_pivot isn't in the face
+						 * prevents attempting to splice the same vertex into an edge from multiple faces */
+						if (!BM_vert_in_face(v_pivot, f)) {
+							float v_pivot_co[3];
+							float v_pivot_fac;
+							BMEdge *e_split = bm_face_split_edge_find(
+							        e, f, v_pivot, bm->ftable, bm->totface,
+							        v_pivot_co, &v_pivot_fac);
+
+							if (e_split) {
+								BMEdge *e_new;
+								BMVert *v_new = BM_edge_split(bm, e_split, e_split->v1, &e_new, v_pivot_fac);
+								if (v_new) {
+									/* we _know_ these don't share an edge */
+									BM_vert_splice(bm, v_pivot, v_new);
+									BM_elem_index_set(e_new, BM_elem_index_get(e_split));
+								}
+							}
+						}
+					}
+
+				} while ((e_link = e_link->next));
+			}
+		}
+
+
 		{
 			MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);




More information about the Bf-blender-cvs mailing list