Blender  V2.93
editmesh_rip_edge.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
23 #include "MEM_guardedalloc.h"
24 
25 #include "DNA_object_types.h"
26 
27 #include "BLI_math.h"
28 
29 #include "BKE_context.h"
30 #include "BKE_editmesh.h"
31 #include "BKE_layer.h"
32 #include "BKE_report.h"
33 
34 #include "WM_types.h"
35 
36 #include "ED_mesh.h"
37 #include "ED_screen.h"
38 #include "ED_transform.h"
39 #include "ED_view3d.h"
40 
41 #include "bmesh.h"
42 
43 #include "mesh_intern.h" /* own include */
44 
45 /* uses total number of selected edges around a vertex to choose how to extend */
46 #define USE_TRICKY_EXTEND
47 
48 static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
49 {
50  ARegion *region = CTX_wm_region(C);
52  ViewLayer *view_layer = CTX_data_view_layer(C);
53  uint objects_len = 0;
55  view_layer, CTX_wm_view3d(C), &objects_len);
56 
57  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
58  Object *obedit = objects[ob_index];
60  BMesh *bm = em->bm;
61 
62  BMIter viter;
63  BMVert *v;
64  const float mval_fl[2] = {UNPACK2(event->mval)};
65  float cent_sco[2];
66  int cent_tot;
67  bool changed = false;
68 
69  /* mouse direction to view center */
70  float mval_dir[2];
71 
72  float projectMat[4][4];
73 
74  if (bm->totvertsel == 0) {
75  continue;
76  }
77 
78  ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
79 
80  zero_v2(cent_sco);
81  cent_tot = 0;
82 
83  /* clear tags and calc screen center */
84  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
86 
88  float v_sco[2];
89  ED_view3d_project_float_v2_m4(region, v->co, v_sco, projectMat);
90 
91  add_v2_v2(cent_sco, v_sco);
92  cent_tot += 1;
93  }
94  }
95  mul_v2_fl(cent_sco, 1.0f / (float)cent_tot);
96 
97  /* not essential, but gives more expected results with edge selection */
98  if (bm->totedgesel) {
99  /* angle against center can give odd result,
100  * try re-position the center to the closest edge */
101  BMIter eiter;
102  BMEdge *e;
103  float dist_sq_best = len_squared_v2v2(cent_sco, mval_fl);
104 
105  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
107  float e_sco[2][2];
108  float cent_sco_test[2];
109  float dist_sq_test;
110 
111  ED_view3d_project_float_v2_m4(region, e->v1->co, e_sco[0], projectMat);
112  ED_view3d_project_float_v2_m4(region, e->v2->co, e_sco[1], projectMat);
113 
114  closest_to_line_segment_v2(cent_sco_test, mval_fl, e_sco[0], e_sco[1]);
115  dist_sq_test = len_squared_v2v2(cent_sco_test, mval_fl);
116  if (dist_sq_test < dist_sq_best) {
117  dist_sq_best = dist_sq_test;
118 
119  /* we have a new screen center */
120  copy_v2_v2(cent_sco, cent_sco_test);
121  }
122  }
123  }
124  }
125 
126  sub_v2_v2v2(mval_dir, mval_fl, cent_sco);
127  normalize_v2(mval_dir);
128 
129  /* operate on selected verts */
130  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
131  BMIter eiter;
132  BMEdge *e;
133  float v_sco[2];
134 
136  /* Rules for */
137  float angle_best = FLT_MAX;
138  BMEdge *e_best = NULL;
139 
140 #ifdef USE_TRICKY_EXTEND
141  /* first check if we can select the edge to split based on selection-only */
142  int tot_sel = 0, tot = 0;
143 
144  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
147  e_best = e;
148  tot_sel += 1;
149  }
150  tot += 1;
151  }
152  }
153  if (tot_sel != 1) {
154  e_best = NULL;
155  }
156 
157  /* only one edge selected, operate on that */
158  if (e_best) {
159  goto found_edge;
160  }
161  /* none selected, fall through and find one */
162  else if (tot_sel == 0) {
163  /* pass */
164  }
165  /* selection not 0 or 1, do nothing */
166  else {
167  goto found_edge;
168  }
169 #endif
170  ED_view3d_project_float_v2_m4(region, v->co, v_sco, projectMat);
171 
172  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
174  BMVert *v_other = BM_edge_other_vert(e, v);
175  float v_other_sco[2];
176  float angle_test;
177 
178  ED_view3d_project_float_v2_m4(region, v_other->co, v_other_sco, projectMat);
179 
180  /* avoid comparing with view-axis aligned edges (less than a pixel) */
181  if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) {
182  float v_dir[2];
183 
184  sub_v2_v2v2(v_dir, v_other_sco, v_sco);
185  normalize_v2(v_dir);
186 
187  angle_test = angle_normalized_v2v2(mval_dir, v_dir);
188 
189  if (angle_test < angle_best) {
190  angle_best = angle_test;
191  e_best = e;
192  }
193  }
194  }
195  }
196 
197 #ifdef USE_TRICKY_EXTEND
198  found_edge:
199 #endif
200  if (e_best) {
201  const bool e_select = BM_elem_flag_test_bool(e_best, BM_ELEM_SELECT);
202  BMVert *v_new;
203  BMEdge *e_new;
204 
205  v_new = BM_edge_split(bm, e_best, v, &e_new, 0.0f);
206 
207  BM_vert_select_set(bm, v, false);
208  BM_edge_select_set(bm, e_new, false);
209 
210  BM_vert_select_set(bm, v_new, true);
211  if (e_select) {
212  BM_edge_select_set(bm, e_best, true);
213  }
214  BM_elem_flag_enable(v_new, BM_ELEM_TAG); /* prevent further splitting */
215 
216  changed = true;
217  }
218  }
219  }
220 
221  if (changed) {
223 
225 
226  EDBM_update_generic(obedit->data, true, true);
227  }
228  }
229 
230  MEM_freeN(objects);
231 
232  return OPERATOR_FINISHED;
233 }
234 
236 {
237  /* identifiers */
238  ot->name = "Extend Vertices";
239  ot->idname = "MESH_OT_rip_edge";
240  ot->description = "Extend vertices along the edge closest to the cursor";
241 
242  /* api callbacks */
245 
246  /* flags */
248 
249  /* to give to transform */
251 }
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:769
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:85
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:426
void closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:353
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:521
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
MINLINE float normalize_v2(float r[2])
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNPACK2(a)
#define UNUSED(x)
Object is a sort of wrapper for general info.
@ OPERATOR_FINISHED
void EDBM_update_generic(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
#define P_PROPORTIONAL
Definition: ED_transform.h:124
void Transform_Properties(struct wmOperatorType *ot, int flags)
#define P_MIRROR_DUMMY
Definition: ED_transform.h:123
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float r_pmat[4][4])
void ED_view3d_project_float_v2_m4(const struct ARegion *region, const float co[3], float r_co[2], float mat[4][4])
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_test_bool(ele, hflag)
Definition: bmesh_inline.h:27
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_select_history_clear(BMesh *bm)
void BM_mesh_select_mode_flush(BMesh *bm)
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
Definition: bmesh_mods.c:591
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
void MESH_OT_rip_edge(wmOperatorType *ot)
bool EDBM_view3d_poll(bContext *C)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
struct BMesh * bm
Definition: BKE_editmesh.h:52
float co[3]
Definition: bmesh_class.h:99
int totvertsel
Definition: bmesh_class.h:298
int totedgesel
Definition: bmesh_class.h:298
void * data
int mval[2]
Definition: WM_types.h:583
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
const char * description
Definition: WM_types.h:726
wmOperatorType * ot
Definition: wm_files.c:3156