[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [51356] trunk/blender: Add BMesh and WM symmetrize operators

Nicholas Bishop nicholasbishop at gmail.com
Tue Oct 16 01:50:11 CEST 2012


Revision: 51356
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=51356
Author:   nicholasbishop
Date:     2012-10-15 23:50:09 +0000 (Mon, 15 Oct 2012)
Log Message:
-----------
Add BMesh and WM symmetrize operators

* The symmetrize operation makes the input mesh elements symmetrical,
  but unlike mirroring it only copies in one direction. The edges and
  faces that cross the plane of symmetry are split as needed to
  enforce symmetry.

* The symmetrize operator can be controlled with the "direction"
  property, which combines the choices of symmetry plane and
  positive-negative/negative-positive. The enum for this is
  BMO_SymmDirection.

* Added menu items in the top-level Mesh menu and the WKEY specials
  menu.

* Documentation:
  http://wiki.blender.org/index.php/User:Nicholasbishop/Symmetrize

* Reviewed by Brecht:
  https://codereview.appspot.com/6618059

Modified Paths:
--------------
    trunk/blender/release/scripts/startup/bl_ui/space_view3d.py
    trunk/blender/source/blender/bmesh/CMakeLists.txt
    trunk/blender/source/blender/bmesh/intern/bmesh_opdefines.c
    trunk/blender/source/blender/bmesh/intern/bmesh_operator_api.h
    trunk/blender/source/blender/bmesh/intern/bmesh_operators_private.h
    trunk/blender/source/blender/editors/mesh/editmesh_tools.c
    trunk/blender/source/blender/editors/mesh/mesh_intern.h
    trunk/blender/source/blender/editors/mesh/mesh_ops.c

Added Paths:
-----------
    trunk/blender/source/blender/bmesh/operators/bmo_symmetrize.c

Modified: trunk/blender/release/scripts/startup/bl_ui/space_view3d.py
===================================================================
--- trunk/blender/release/scripts/startup/bl_ui/space_view3d.py	2012-10-15 23:17:24 UTC (rev 51355)
+++ trunk/blender/release/scripts/startup/bl_ui/space_view3d.py	2012-10-15 23:50:09 UTC (rev 51356)
@@ -1668,7 +1668,7 @@
         layout.menu("VIEW3D_MT_uv_map", text="UV Unwrap...")
 
         layout.separator()
-
+        layout.operator("mesh.symmetrize")
         layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Region")
         layout.operator("view3d.edit_mesh_extrude_individual_move", text="Extrude Individual")
         layout.operator("mesh.duplicate_move")
@@ -1719,6 +1719,7 @@
         layout.operator("mesh.shape_propagate_to_all")
         layout.operator("mesh.select_vertex_path")
         layout.operator("mesh.sort_elements")
+        layout.operator("mesh.symmetrize")
 
 
 class VIEW3D_MT_edit_mesh_select_mode(Menu):

Modified: trunk/blender/source/blender/bmesh/CMakeLists.txt
===================================================================
--- trunk/blender/source/blender/bmesh/CMakeLists.txt	2012-10-15 23:17:24 UTC (rev 51355)
+++ trunk/blender/source/blender/bmesh/CMakeLists.txt	2012-10-15 23:50:09 UTC (rev 51356)
@@ -52,6 +52,7 @@
 	operators/bmo_mirror.c
 	operators/bmo_primitive.c
 	operators/bmo_removedoubles.c
+	operators/bmo_symmetrize.c
 	operators/bmo_subdivide.c
 	operators/bmo_subdivide.h
 	operators/bmo_triangulate.c

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_opdefines.c
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_opdefines.c	2012-10-15 23:17:24 UTC (rev 51355)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_opdefines.c	2012-10-15 23:50:09 UTC (rev 51356)
@@ -1182,6 +1182,29 @@
 	0
 };
 
+/*
+ * Symmetrize
+ *
+ * Mekes the mesh elements in the "input" slot symmetrical. Unlike
+ * normal mirroring, it only copies in one direction, as specified by
+ * the "direction" slot. The edges and faces that cross the plane of
+ * symmetry are split as needed to enforce symmetry.
+ *
+ * All new vertices, edges, and faces are added to the "geomout" slot.
+ */
+static BMOpDefine bmo_symmetrize_def = {
+	"symmetrize",
+	{{BMO_OP_SLOT_ELEMENT_BUF, "input"},
+	 {BMO_OP_SLOT_INT, "direction"},
+
+	 /* Outputs */
+	 {BMO_OP_SLOT_ELEMENT_BUF, "geomout"},
+
+	 {0} /* null-terminating sentinel */},
+	bmo_symmetrize_exec,
+	0
+};
+
 BMOpDefine *opdefines[] = {
 	&bmo_automerge_def,
 	&bmo_average_vert_facedata_def,
@@ -1246,6 +1269,7 @@
 	&bmo_split_def,
 	&bmo_split_edges_def,
 	&bmo_subdivide_edges_def,
+	&bmo_symmetrize_def,
 	&bmo_transform_def,
 	&bmo_translate_def,
 	&bmo_triangle_fill_def,

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_operator_api.h
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_operator_api.h	2012-10-15 23:17:24 UTC (rev 51355)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_operator_api.h	2012-10-15 23:50:09 UTC (rev 51356)
@@ -266,6 +266,16 @@
 	DEL_ONLYTAGGED
 };
 
+typedef enum {
+	BMO_SYMMETRIZE_NEGATIVE_X,
+	BMO_SYMMETRIZE_NEGATIVE_Y,
+	BMO_SYMMETRIZE_NEGATIVE_Z,
+
+	BMO_SYMMETRIZE_POSITIVE_X,
+	BMO_SYMMETRIZE_POSITIVE_Y,
+	BMO_SYMMETRIZE_POSITIVE_Z,
+} BMO_SymmDirection;
+
 void BMO_op_flag_enable(BMesh *bm, BMOperator *op, const int op_flag);
 void BMO_op_flag_disable(BMesh *bm, BMOperator *op, const int op_flag);
 

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_operators_private.h
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_operators_private.h	2012-10-15 23:17:24 UTC (rev 51355)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_operators_private.h	2012-10-15 23:50:09 UTC (rev 51356)
@@ -96,6 +96,7 @@
 void bmo_split_edges_exec(BMesh *bm, BMOperator *op);
 void bmo_split_exec(BMesh *bm, BMOperator *op);
 void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op);
+void bmo_symmetrize_exec(BMesh *bm, BMOperator *op);
 void bmo_transform_exec(BMesh *bm, BMOperator *op);
 void bmo_translate_exec(BMesh *bm, BMOperator *op);
 void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op);

Added: trunk/blender/source/blender/bmesh/operators/bmo_symmetrize.c
===================================================================
--- trunk/blender/source/blender/bmesh/operators/bmo_symmetrize.c	                        (rev 0)
+++ trunk/blender/source/blender/bmesh/operators/bmo_symmetrize.c	2012-10-15 23:50:09 UTC (rev 51356)
@@ -0,0 +1,663 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Nicholas Bishop
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_array.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "bmesh.h"
+#include "intern/bmesh_operators_private.h"
+
+enum {
+	SYMM_OUTPUT_GEOM = (1 << 0)
+};
+
+/* Note: don't think there's much need to make these user-adjustable? */
+#define SYMM_AXIS_THRESHOLD 0.00002f
+#define SYMM_VERT_THRESHOLD 0.00002f
+
+typedef enum {
+	/* Coordinate lies on the side being copied from */
+	SYMM_SIDE_KEEP,
+	/* Coordinate lies on the side being copied from and within the
+	 * axis threshold */
+	SYMM_SIDE_AXIS,
+	/* Coordinate lies on the side being copied to */
+	SYMM_SIDE_KILL
+} SymmSide;
+
+typedef struct {
+	BMesh *bm;
+	BMOperator *op;
+
+	int axis;
+	BMO_SymmDirection direction;
+
+	/* Maps from input vertices to their mirrors. If the vertex
+	 * doesn't have a mirror, it's not in this map. If the vertex is
+	 * within the axis threshold, it's mapped to itself. */
+	GHash *vert_symm_map;
+
+	/* Edges that cross the symmetry plane and are asymmetric get
+	 * split. This map goes from input edges to output vertices. If an
+	 * edge is not split, it's not in this map. */
+	GHash *edge_split_map;
+} Symm;
+
+/* Return which side the coordinate lies on */
+static SymmSide symm_co_side(const Symm *symm,
+							 const float *co)
+{
+	float comp = co[symm->axis];
+	if (ELEM3(symm->direction,
+			  BMO_SYMMETRIZE_NEGATIVE_X,
+			  BMO_SYMMETRIZE_NEGATIVE_Y,
+			  BMO_SYMMETRIZE_NEGATIVE_Z))
+	{
+		comp = -comp;
+	}
+
+	if (comp >= 0) {
+		if (comp < SYMM_AXIS_THRESHOLD)
+			return SYMM_SIDE_AXIS;
+		else
+			return SYMM_SIDE_KEEP;
+	}
+	else
+		return SYMM_SIDE_KILL;
+}
+
+/* Output vertices and the vert_map array */
+static void symm_verts_mirror(Symm *symm)
+{
+	BMOIter oiter;
+	BMVert *src_v, *dst_v;
+
+	symm->vert_symm_map = BLI_ghash_ptr_new(AT);
+
+	BMO_ITER (src_v, &oiter, symm->bm, symm->op, "input", BM_VERT) {
+		SymmSide side = symm_co_side(symm, src_v->co);
+		float co[3];
+
+		switch (side) {
+			case SYMM_SIDE_KEEP:
+				/* The vertex is outside the axis area; output its mirror */
+				copy_v3_v3(co, src_v->co);
+				co[symm->axis] = -co[symm->axis];
+
+				dst_v = BM_vert_create(symm->bm, co, src_v);
+				BMO_elem_flag_enable(symm->bm, dst_v, SYMM_OUTPUT_GEOM);
+				BLI_ghash_insert(symm->vert_symm_map, src_v, dst_v);
+				break;
+
+			case SYMM_SIDE_AXIS:
+				/* The vertex is within the axis area, snap to center */
+				src_v->co[symm->axis] = 0;
+				/* Vertex isn't copied, map to itself */
+				BLI_ghash_insert(symm->vert_symm_map, src_v, src_v);
+				break;
+
+			case SYMM_SIDE_KILL:
+				/* The vertex does not lie in the half-space being
+				 * copied from, nothing to do */
+				break;
+		}
+	}
+}
+
+static int symm_edge_crosses_axis(const Symm *symm, const BMEdge *e)
+{
+	const int sides[2] = {symm_co_side(symm, e->v1->co),
+						  symm_co_side(symm, e->v2->co)};
+
+	return ((sides[0] != SYMM_SIDE_AXIS) &&
+			(sides[1] != SYMM_SIDE_AXIS) &&
+			(sides[0] != sides[1]));
+}
+
+/* Output edge split vertices for asymmetric edges and the edge_splits
+ * mapping array */
+static void symm_split_asymmetric_edges(Symm *symm)
+{
+	BMOIter oiter;
+	BMEdge *e;
+
+	symm->edge_split_map = BLI_ghash_ptr_new(AT);
+
+	BMO_ITER (e, &oiter, symm->bm, symm->op, "input", BM_EDGE) {
+		float flipped[3];
+
+		copy_v3_v3(flipped, e->v1->co);
+		flipped[symm->axis] = -flipped[symm->axis];
+
+		if (symm_edge_crosses_axis(symm, e) &&
+			(!compare_v3v3(e->v2->co, flipped, SYMM_VERT_THRESHOLD)))
+		{
+			/* Endpoints lie on opposite sides and are asymmetric */
+
+			BMVert *v;
+			float lambda = 0, edge_dir[3], co[3];
+			float plane_co[3][3][3] = {
+				/* axis == 0 */
+				{{0, 0, 0}, {0, 1, 0}, {0, 0, 1}},
+				/* axis == 1 */
+				{{0, 0, 0}, {1, 0, 0}, {0, 0, 1}},
+				/* axis == 2 */
+				{{0, 0, 0}, {1, 0, 0}, {0, 1, 0}},
+			};
+			int r;
+
+			/* Find intersection of edge with symmetry plane */
+			sub_v3_v3v3(edge_dir, e->v2->co, e->v1->co);
+			normalize_v3(edge_dir);
+			r = isect_ray_plane_v3(e->v1->co,
+								   edge_dir,
+								   plane_co[symm->axis][0],
+								   plane_co[symm->axis][1],
+								   plane_co[symm->axis][2],
+								   &lambda, TRUE);
+			BLI_assert(r);
+
+			madd_v3_v3v3fl(co, e->v1->co, edge_dir, lambda);
+			co[symm->axis] = 0;
+
+			/* Edge is asymmetric, split it with a new vertex */
+			v = BM_vert_create(symm->bm, co, e->v1);
+			BMO_elem_flag_enable(symm->bm, v, SYMM_OUTPUT_GEOM);
+			BLI_ghash_insert(symm->edge_split_map, e, v);
+		}
+	}
+}
+
+static void symm_mirror_edges(Symm *symm)
+{
+	BMOIter oiter;
+	BMEdge *e;
+
+	BMO_ITER (e, &oiter, symm->bm, symm->op, "input", BM_EDGE) {
+		BMVert *v1 = NULL, *v2 = NULL;
+		BMEdge *e_new;
+
+		v1 = BLI_ghash_lookup(symm->vert_symm_map, e->v1);
+		v2 = BLI_ghash_lookup(symm->vert_symm_map, e->v2);
+
+		if (v1 && v2) {
+			e_new = BM_edge_create(symm->bm, v1, v2, e, TRUE);
+			BMO_elem_flag_enable(symm->bm, e_new, SYMM_OUTPUT_GEOM);
+		}
+		else if (v1 || v2) {

@@ Diff output truncated at 10240 characters. @@


More information about the Bf-blender-cvs mailing list