From 5861e528d64906325632a490b1682f696abd3ebc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 14 Jun 2014 01:38:57 +1000 Subject: New Editmesh Tool: Extend Vertex, (Alt+D) D512 Helps to easily add details to existing edges. Similar to the rip tool it depends on cursor location to choose the edge to extend along. --- source/blender/editors/mesh/CMakeLists.txt | 1 + source/blender/editors/mesh/editmesh_rip_edge.c | 244 ++++++++++++++++++++++++ source/blender/editors/mesh/mesh_intern.h | 1 + source/blender/editors/mesh/mesh_ops.c | 10 + 4 files changed, 256 insertions(+) create mode 100644 source/blender/editors/mesh/editmesh_rip_edge.c (limited to 'source') diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 8d91b300ff3..6bf9d5a3b6a 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -50,6 +50,7 @@ set(SRC editmesh_loopcut.c editmesh_path.c editmesh_rip.c + editmesh_rip_edge.c editmesh_select.c editmesh_tools.c editmesh_utils.c diff --git a/source/blender/editors/mesh/editmesh_rip_edge.c b/source/blender/editors/mesh/editmesh_rip_edge.c new file mode 100644 index 00000000000..8b784f8a3f8 --- /dev/null +++ b/source/blender/editors/mesh/editmesh_rip_edge.c @@ -0,0 +1,244 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_rip_edge.c + * \ingroup edmesh + * + * based on mouse cursor position, split of vertices along the closest edge. + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_object_types.h" + +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_editmesh.h" + +#include "RNA_define.h" +#include "RNA_access.h" + +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_transform.h" +#include "ED_view3d.h" + +#include "bmesh.h" + +#include "mesh_intern.h" /* own include */ + +/* uses total number of selected edges around a vertex to choose how to extend */ +#define USE_TRICKY_EXTEND + +static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMIter viter; + BMVert *v; + const float mval_fl[2] = {UNPACK2(event->mval)}; + float cent_sco[2]; + int cent_tot; + + /* mouse direction to view center */ + float mval_dir[2]; + + float projectMat[4][4]; + + if (bm->totvertsel == 0) + return OPERATOR_CANCELLED; + + ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); + + zero_v2(cent_sco); + cent_tot = 0; + + /* clear tags and calc screen center */ + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_disable(v, BM_ELEM_TAG); + + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + float v_sco[2]; + ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat); + + add_v2_v2(cent_sco, v_sco); + cent_tot += 1; + } + } + mul_v2_fl(cent_sco, 1.0f / (float)cent_tot); + + /* not essential, but gives more expected results with edge selection */ + if (bm->totedgesel) { + /* angle against center can give odd result, + * try re-position the center to the closest edge */ + BMIter eiter; + BMEdge *e; + float dist_sq_best = len_squared_v2v2(cent_sco, mval_fl); + + BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + float e_sco[2][2]; + float cent_sco_test[2]; + float dist_sq_test; + + ED_view3d_project_float_v2_m4(ar, e->v1->co, e_sco[0], projectMat); + ED_view3d_project_float_v2_m4(ar, e->v2->co, e_sco[1], projectMat); + + closest_to_line_segment_v2(cent_sco_test, mval_fl, e_sco[0], e_sco[1]); + dist_sq_test = len_squared_v2v2(cent_sco_test, mval_fl); + if (dist_sq_test < dist_sq_best) { + dist_sq_best = dist_sq_test; + + /* we have a new screen center */ + copy_v2_v2(cent_sco, cent_sco_test); + } + } + } + } + + sub_v2_v2v2(mval_dir, mval_fl, cent_sco); + normalize_v2(mval_dir); + + /* operate on selected verts */ + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + BMIter eiter; + BMEdge *e; + float v_sco[2]; + + if (BM_elem_flag_test(v, BM_ELEM_SELECT) && + BM_elem_flag_test(v, BM_ELEM_TAG) == false) + { + /* Rules for */ + float angle_best = FLT_MAX; + BMEdge *e_best = NULL; + +#ifdef USE_TRICKY_EXTEND + /* first check if we can select the edge to split based on selection-only */ + int tot_sel = 0, tot = 0; + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + e_best = e; + tot_sel += 1; + } + tot += 1; + } + } + if (tot_sel != 1) { + e_best = NULL; + } + + /* only one edge selected, operate on that */ + if (e_best) { + goto found_edge; + } + /* none selected, fall through and find one */ + else if (tot_sel == 0) { + /* pass */ + } + /* selection not 0 or 1, do nothing */ + else { + goto found_edge; + } +#endif + ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat); + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + BMVert *v_other = BM_edge_other_vert(e, v); + float v_other_sco[2]; + float angle_test; + + ED_view3d_project_float_v2_m4(ar, v_other->co, v_other_sco, projectMat); + + /* avoid comparing with view-axis aligned edges (less then a pixel) */ + if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) { + float v_dir[2]; + + sub_v2_v2v2(v_dir, v_other_sco, v_sco); + normalize_v2(v_dir); + + angle_test = angle_normalized_v2v2(mval_dir, v_dir); + + if (angle_test < angle_best) { + angle_best = angle_test; + e_best = e; + } + } + } + } + +#ifdef USE_TRICKY_EXTEND +found_edge: +#endif + if (e_best) { + const bool e_select = BM_elem_flag_test_bool(e_best, BM_ELEM_SELECT); + BMVert *v_new; + BMEdge *e_new; + + v_new = BM_edge_split(bm, e_best, v, &e_new, 0.0f); + + BM_vert_select_set(bm, v, false); + BM_edge_select_set(bm, e_new, false); + + BM_vert_select_set(bm, v_new, true); + if (e_select) { + BM_edge_select_set(bm, e_best, true); + } + BM_elem_flag_enable(v_new, BM_ELEM_TAG); /* prevent further splitting */ + } + } + } + + BM_select_history_clear(bm); + + BM_mesh_select_mode_flush(bm); + + EDBM_update_generic(em, true, true); + + return OPERATOR_FINISHED; +} + + +void MESH_OT_rip_edge(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Extend Vertex"; + ot->idname = "MESH_OT_rip_edge"; + ot->description = "Extend vertices along the edge closest to the cursor"; + + /* api callbacks */ + ot->invoke = edbm_rip_edge_invoke; + ot->poll = EDBM_view3d_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* to give to transform */ + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY); +} diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 8aea932e93a..655d96ae6e5 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -128,6 +128,7 @@ void MESH_OT_loopcut(struct wmOperatorType *ot); /* *** editmesh_rip.c *** */ void MESH_OT_rip(struct wmOperatorType *ot); +void MESH_OT_rip_edge(struct wmOperatorType *ot); /* *** editmesh_select.c *** */ diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 7c38ef21791..8cc25f01879 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -142,6 +142,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_noise); WM_operatortype_append(MESH_OT_flip_normals); WM_operatortype_append(MESH_OT_rip); + WM_operatortype_append(MESH_OT_rip_edge); WM_operatortype_append(MESH_OT_blend_from_shape); WM_operatortype_append(MESH_OT_shape_propagate_to_all); @@ -239,6 +240,13 @@ void ED_operatormacros_mesh(void) RNA_enum_set(otmacro->ptr, "proportional", 0); RNA_boolean_set(otmacro->ptr, "mirror", false); + ot = WM_operatortype_append_macro("MESH_OT_rip_edge_move", "Rip Edge", "Rip polygons and move the result", + OPTYPE_UNDO | OPTYPE_REGISTER); + WM_operatortype_macro_define(ot, "MESH_OT_rip_edge"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", false); + ot = WM_operatortype_append_macro("MESH_OT_extrude_region_move", "Extrude Region and Move", "Extrude region and move result", OPTYPE_UNDO | OPTYPE_REGISTER); otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region"); @@ -372,6 +380,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MESH_OT_rip_move", VKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "MESH_OT_rip_move_fill", VKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_add_item(keymap, "MESH_OT_rip_edge_move", DKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_add_item(keymap, "MESH_OT_merge", MKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "TRANSFORM_OT_shrink_fatten", SKEY, KM_PRESS, KM_ALT, 0); -- cgit v1.2.3