[Bf-blender-cvs] [34d98cfe61b] master: BMesh: spin option to merge first/last

Campbell Barton noreply at git.blender.org
Wed Sep 26 01:41:10 CEST 2018


Commit: 34d98cfe61bd34aa742879a31ba0da01d32d7e3a
Author: Campbell Barton
Date:   Wed Sep 26 09:45:14 2018 +1000
Branches: master
https://developer.blender.org/rB34d98cfe61bd34aa742879a31ba0da01d32d7e3a

BMesh: spin option to merge first/last

For 360d revolutions this is almost always whats intended,
enable by default.

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

M	source/blender/bmesh/intern/bmesh_opdefines.c
M	source/blender/bmesh/operators/bmo_dupe.c
M	source/blender/editors/mesh/editmesh_extrude_spin.c

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

diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 891a15d4184..7abf05044dd 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1389,6 +1389,7 @@ static BMOpDefine bmo_spin_def = {
 	 {"angle", BMO_OP_SLOT_FLT},            /* total rotation angle (radians) */
 	 {"space", BMO_OP_SLOT_MAT},            /* matrix to define the space (typically object matrix) */
 	 {"steps", BMO_OP_SLOT_INT},            /* number of steps */
+	 {"use_merge", BMO_OP_SLOT_BOOL},       /* Merge first/last when the angle is a full revolution. */
 	 {"use_normal_flip", BMO_OP_SLOT_BOOL}, /* Create faces with reversed direction. */
 	 {"use_duplicate", BMO_OP_SLOT_BOOL},   /* duplicate or extrude? */
 	 {{'\0'}},
diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c
index af1cd22ac8d..c50c7657deb 100644
--- a/source/blender/bmesh/operators/bmo_dupe.c
+++ b/source/blender/bmesh/operators/bmo_dupe.c
@@ -26,6 +26,8 @@
  * Duplicate, Split, Split operators.
  */
 
+#include "MEM_guardedalloc.h"
+
 #include "BLI_math.h"
 #include "BLI_alloca.h"
 
@@ -486,10 +488,29 @@ void bmo_spin_exec(BMesh *bm, BMOperator *op)
 	steps    = BMO_slot_int_get(op->slots_in,   "steps");
 	phi      = BMO_slot_float_get(op->slots_in, "angle") / steps;
 	do_dupli = BMO_slot_bool_get(op->slots_in,  "use_duplicate");
-	const bool use_normal_flip = BMO_slot_bool_get(op->slots_in,  "use_normal_flip");
+	const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip");
+	/* Caller needs to perform other sanity checks (such as the spin being 360d). */
+	const bool use_merge = BMO_slot_bool_get(op->slots_in, "use_merge") && steps >= 3;
 
 	axis_angle_normalized_to_mat3(rmat, axis, phi);
 
+	BMVert **vtable = NULL;
+	if (use_merge) {
+		vtable = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__);
+		int i = 0;
+		BMIter iter;
+		BMVert *v;
+		BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+			vtable[i] = v;
+			/* Evil! store original index in normal,
+			 * this is duplicated into every other vertex.
+			 * So we can read the original from the final.
+			 *
+			 * The normals must be recalculated anyway. */
+			*((int *)&v->no[0]) = i;
+		}
+	}
+
 	BMO_slot_copy(op, slots_in,  "geom",
 	              op, slots_out, "geom_last.out");
 	for (a = 0; a < steps; a++) {
@@ -507,11 +528,44 @@ void bmo_spin_exec(BMesh *bm, BMOperator *op)
 			BMO_op_initf(bm, &extop, op->flag, "extrude_face_region geom=%S use_normal_flip=%b",
 			             op, "geom_last.out", use_normal_flip && (a == 0));
 			BMO_op_exec(bm, &extop);
-			BMO_op_callf(bm, op->flag,
-			             "rotate cent=%v matrix=%m3 space=%s verts=%S",
-			             cent, rmat, op, "space", &extop, "geom.out");
-			BMO_slot_copy(&extop, slots_out, "geom.out",
-			              op,     slots_out, "geom_last.out");
+			if ((use_merge && (a == steps - 1)) == false) {
+				BMO_op_callf(bm, op->flag,
+				             "rotate cent=%v matrix=%m3 space=%s verts=%S",
+				             cent, rmat, op, "space", &extop, "geom.out");
+				BMO_slot_copy(&extop, slots_out, "geom.out",
+				              op,     slots_out, "geom_last.out");
+			}
+			else {
+				/* Merge first/last vertices and edges (maintaining 'geom.out' state). */
+				BMOpSlot *slot_geom_out = BMO_slot_get(extop.slots_out, "geom.out");
+				BMElem  **elem_array = (BMElem **)slot_geom_out->data.buf;
+				int elem_array_len = slot_geom_out->len;
+				for (int i = 0; i < elem_array_len; ) {
+					if (elem_array[i]->head.htype == BM_VERT) {
+						BMVert *v_src = (BMVert *)elem_array[i];
+						BMVert *v_dst = vtable[*((const int *)&v_src->no[0])];
+						BM_vert_splice(bm, v_dst, v_src);
+						elem_array_len--;
+						elem_array[i] = elem_array[elem_array_len];
+					}
+					else {
+						i++;
+					}
+				}
+				for (int i = 0; i < elem_array_len; ) {
+					if (elem_array[i]->head.htype == BM_EDGE) {
+						BMEdge *e_src = (BMEdge *)elem_array[i];
+						BMEdge *e_dst = BM_edge_find_double(e_src);
+						BM_edge_splice(bm, e_dst, e_src);
+						elem_array_len--;
+						elem_array[i] = elem_array[elem_array_len];
+					}
+					else {
+						i++;
+					}
+				}
+				slot_geom_out->len = elem_array_len;
+			}
 			BMO_op_finish(bm, &extop);
 		}
 
@@ -522,4 +576,8 @@ void bmo_spin_exec(BMesh *bm, BMOperator *op)
 			             dvec, op, "space", op, "geom_last.out");
 		}
 	}
+
+	if (vtable) {
+		MEM_freeN(vtable);
+	}
 }
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c
index 03176bae2f6..88407576ec0 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin.c
@@ -65,9 +65,14 @@ static int edbm_spin_exec(bContext *C, wmOperator *op)
 	RNA_float_get_array(op->ptr, "center", cent);
 	RNA_float_get_array(op->ptr, "axis", axis);
 	const int steps = RNA_int_get(op->ptr, "steps");
-	const float angle = -RNA_float_get(op->ptr, "angle");
-	const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip");
+	const float angle = RNA_float_get(op->ptr, "angle");
+	const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip") ^ (angle < 0.0f);
 	const bool dupli = RNA_boolean_get(op->ptr, "dupli");
+	const bool use_auto_merge = (
+	        RNA_boolean_get(op->ptr, "use_auto_merge") &&
+	        (dupli == false) &&
+	        (steps >= 3) &&
+	        fabsf((fabsf(angle) - (M_PI * 2))) <= 1e-6f);
 
 	if (is_zero_v3(axis)) {
 		BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis");
@@ -78,14 +83,17 @@ static int edbm_spin_exec(bContext *C, wmOperator *op)
 	if (!EDBM_op_init(
 	            em, &spinop, op,
 	            "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i angle=%f space=%m4 "
-	            "use_normal_flip=%b use_duplicate=%b",
-	            BM_ELEM_SELECT, cent, axis, d, steps, angle, obedit->obmat, use_normal_flip, dupli))
+	            "use_normal_flip=%b use_duplicate=%b use_merge=%b",
+	            BM_ELEM_SELECT, cent, axis, d, steps, -angle, obedit->obmat,
+	            use_normal_flip, dupli, use_auto_merge))
 	{
 		return OPERATOR_CANCELLED;
 	}
 	BMO_op_exec(bm, &spinop);
-	EDBM_flag_disable_all(em, BM_ELEM_SELECT);
-	BMO_slot_buffer_hflag_enable(bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
+	if (use_auto_merge == false) {
+		EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+		BMO_slot_buffer_hflag_enable(bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
+	}
 	if (!EDBM_op_finish(em, &spinop, op, true)) {
 		return OPERATOR_CANCELLED;
 	}
@@ -140,6 +148,7 @@ void MESH_OT_spin(wmOperatorType *ot)
 	prop = RNA_def_float(ot->srna, "angle", DEG2RADF(90.0f), -1e12f, 1e12f, "Angle", "Rotation for each step",
 	                     DEG2RADF(-360.0f), DEG2RADF(360.0f));
 	RNA_def_property_subtype(prop, PROP_ANGLE);
+	RNA_def_boolean(ot->srna, "use_auto_merge", true, "Auto Merge", "Merge first/last when the angle is a full revolution");
 	RNA_def_boolean(ot->srna, "use_normal_flip", 0, "Flip Normals", "");
 
 	RNA_def_float_vector(ot->srna, "center", 3, NULL, -1e12f, 1e12f,



More information about the Bf-blender-cvs mailing list