Not so fast! This is too cool to exist only as an operator. What about a modifier? ^_^
awesomesauce Daniel Salazar patazstudio.com On Mon, Oct 15, 2012 at 5:50 PM, Nicholas Bishop <[email protected]> wrote: > 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. @@ > _______________________________________________ > Bf-blender-cvs mailing list > [email protected] > http://lists.blender.org/mailman/listinfo/bf-blender-cvs _______________________________________________ Bf-committers mailing list [email protected] http://lists.blender.org/mailman/listinfo/bf-committers
