From c00b4080526c2442cf56484d47aaa1f02b13cd44 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 19 Jun 2013 21:35:06 +0000 Subject: Snap to Symmetry (editmesh tool) Update from a script I had in 2.4x, useful if you have mesh data which is _almost_ symmetrical, there was no good way to automatically make the minor adjustments to make the mesh fully symmetrical. Options for... - symmetry-axis. - blending between the +/- side. - center mid verts. Access from Mesh menu. --- source/blender/editors/mesh/editmesh_tools.c | 126 +++++++++++++++++++++++++++ source/blender/editors/mesh/mesh_intern.h | 1 + source/blender/editors/mesh/mesh_ops.c | 1 + 3 files changed, 128 insertions(+) (limited to 'source') diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 56f70b73a16..bab9a2d8f5a 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -4258,6 +4258,132 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot) "Direction", "Which sides to copy from and to"); } +static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op) +{ + const float eps = 0.00001f; + const float eps_sq = eps * eps; + + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + int *index = MEM_mallocN(bm->totvert * sizeof(*index), __func__); + const bool is_topo = false; + + const float thresh = RNA_float_get(op->ptr, "threshold"); + const float fac = RNA_float_get(op->ptr, "factor"); + const bool use_center = RNA_boolean_get(op->ptr, "use_center"); + + /* stats */ + int totmirr = 0, totfail = 0, totfound = 0; + + /* axix */ + const int axis_dir = RNA_enum_get(op->ptr, "direction"); + int axis = axis_dir % 3; + bool axis_sign = axis != axis_dir; + + /* vertex iter */ + BMIter iter; + BMVert *v; + int i; + + EDBM_verts_mirror_cache_begin_ex(em, axis, true, true, is_topo, thresh, index); + + EDBM_index_arrays_ensure(em, BM_VERT); + + BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false); + + + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + if ((BM_elem_flag_test(v, BM_ELEM_SELECT) != false) && + (BM_elem_flag_test(v, BM_ELEM_TAG) == false)) + { + int i_mirr = index[i]; + if (i_mirr != -1) { + + BMVert *v_mirr = EDBM_vert_at_index(em, index[i]); + + if (v != v_mirr) { + float co[3], co_mirr[3]; + + if ((v->co[axis] > v->co[axis]) == axis_sign) { + SWAP(BMVert *, v, v_mirr); + } + + copy_v3_v3(co_mirr, v_mirr->co); + co_mirr[axis] *= -1.0f; + + if (len_squared_v3v3(v->co, co_mirr) > eps_sq) { + totmirr++; + } + + interp_v3_v3v3(co, v->co, co_mirr, fac); + + copy_v3_v3(v->co, co); + + co[axis] *= -1.0f; + copy_v3_v3(v_mirr->co, co); + + BM_elem_flag_enable(v, BM_ELEM_TAG); + BM_elem_flag_enable(v_mirr, BM_ELEM_TAG); + totfound++; + } + else { + if (use_center) { + + if (fabsf(v->co[axis]) > eps) { + totmirr++; + } + + v->co[axis] = 0.0f; + } + BM_elem_flag_enable(v, BM_ELEM_TAG); + totfound++; + } + } + else { + totfail++; + } + } + } + + + if (totfail) { + BKE_reportf(op->reports, RPT_WARNING, "%d already symmetrical, %d pairs mirrored, %d failed", + totfound - totmirr, totmirr, totfail); + } + else { + BKE_reportf(op->reports, RPT_INFO, "%d already symmetrical, %d pairs mirrored", + totfound - totmirr, totmirr); + } + + /* no need to end cache, just free the array */ + MEM_freeN(index); + + return OPERATOR_FINISHED; +} + +void MESH_OT_symmetry_snap(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Snap to Symmetry"; + ot->description = "Snap vertex pairs to their mirrored locations"; + ot->idname = "MESH_OT_symmetry_snap"; + + /* api callbacks */ + ot->exec = mesh_symmetry_snap_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items, + BMO_SYMMETRIZE_NEGATIVE_X, + "Direction", "Which sides to copy from and to"); + RNA_def_float(ot->srna, "threshold", 0.05, 0.0, 10.0, "Threshold", "", 0.0001, 1.0); + RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0); + RNA_def_boolean(ot->srna, "use_center", true, "Center", "Snap mid verts to the axis center"); +} + #ifdef WITH_FREESTYLE static int edbm_mark_freestyle_edge(bContext *C, wmOperator *op) diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index bc74f4a8bf5..e086e11e3bf 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -170,6 +170,7 @@ void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot); void MESH_OT_wireframe(struct wmOperatorType *ot); void MESH_OT_convex_hull(struct wmOperatorType *ot); void MESH_OT_symmetrize(struct wmOperatorType *ot); +void MESH_OT_symmetry_snap(struct wmOperatorType *ot); void MESH_OT_shape_propagate_to_all(struct wmOperatorType *ot); void MESH_OT_blend_from_shape(struct wmOperatorType *ot); void MESH_OT_sort_elements(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 966d5ecb00e..7fe0c3b0344 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -172,6 +172,7 @@ void ED_operatortypes_mesh(void) #endif WM_operatortype_append(MESH_OT_symmetrize); + WM_operatortype_append(MESH_OT_symmetry_snap); #ifdef WITH_GAMEENGINE WM_operatortype_append(MESH_OT_navmesh_make); -- cgit v1.2.3