I agree a modifier version would be nice. I've been thinking though that as new BMesh tools are added, there might be room for a lot of new modifiers. (For example, the convex hull operator I added in the last release would also work well as a modifier.) Perhaps it would be better to create a generic BMesh modifier that applies a BMesh operator to the input?
-Nicholas On Mon, Oct 15, 2012 at 9:26 PM, Daniel Salazar - 3Developer.com <[email protected]> wrote: > 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 _______________________________________________ Bf-committers mailing list [email protected] http://lists.blender.org/mailman/listinfo/bf-committers
