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.
This commit is contained in:
Campbell Barton 2014-06-14 01:38:57 +10:00
parent cb7915fc60
commit 5861e528d6
5 changed files with 257 additions and 0 deletions

View File

@ -2160,6 +2160,7 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.operator("mesh.merge")
layout.operator("mesh.rip_move")
layout.operator("mesh.rip_move_fill")
layout.operator("mesh.rip_edge_move")
layout.operator("mesh.split")
layout.operator_menu_enum("mesh.separate", "type")
layout.operator("mesh.vert_connect", text="Connect")

View File

@ -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

View File

@ -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);
}

View File

@ -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 *** */

View File

@ -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);