Blender  V3.3
editmesh_rip_edge.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
9 #include "MEM_guardedalloc.h"
10 
11 #include "DNA_object_types.h"
12 
13 #include "BLI_math.h"
14 
15 #include "BKE_context.h"
16 #include "BKE_editmesh.h"
17 #include "BKE_layer.h"
18 #include "BKE_report.h"
19 
20 #include "WM_types.h"
21 
22 #include "ED_mesh.h"
23 #include "ED_screen.h"
24 #include "ED_transform.h"
25 #include "ED_view3d.h"
26 
27 #include "bmesh.h"
28 
29 #include "mesh_intern.h" /* own include */
30 
31 /* uses total number of selected edges around a vertex to choose how to extend */
32 #define USE_TRICKY_EXTEND
33 
34 static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
35 {
36  ARegion *region = CTX_wm_region(C);
38  ViewLayer *view_layer = CTX_data_view_layer(C);
39  uint objects_len = 0;
41  view_layer, CTX_wm_view3d(C), &objects_len);
42 
43  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
44  Object *obedit = objects[ob_index];
46  BMesh *bm = em->bm;
47 
48  BMIter viter;
49  BMVert *v;
50  const float mval_fl[2] = {UNPACK2(event->mval)};
51  float cent_sco[2];
52  int cent_tot;
53  bool changed = false;
54 
55  /* mouse direction to view center */
56  float mval_dir[2];
57 
58  float projectMat[4][4];
59 
60  if (bm->totvertsel == 0) {
61  continue;
62  }
63 
64  ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
65 
66  zero_v2(cent_sco);
67  cent_tot = 0;
68 
69  /* clear tags and calc screen center */
70  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
72 
74  float v_sco[2];
75  ED_view3d_project_float_v2_m4(region, v->co, v_sco, projectMat);
76 
77  add_v2_v2(cent_sco, v_sco);
78  cent_tot += 1;
79  }
80  }
81  mul_v2_fl(cent_sco, 1.0f / (float)cent_tot);
82 
83  /* not essential, but gives more expected results with edge selection */
84  if (bm->totedgesel) {
85  /* angle against center can give odd result,
86  * try re-position the center to the closest edge */
87  BMIter eiter;
88  BMEdge *e;
89  float dist_sq_best = len_squared_v2v2(cent_sco, mval_fl);
90 
91  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
93  float e_sco[2][2];
94  float cent_sco_test[2];
95  float dist_sq_test;
96 
97  ED_view3d_project_float_v2_m4(region, e->v1->co, e_sco[0], projectMat);
98  ED_view3d_project_float_v2_m4(region, e->v2->co, e_sco[1], projectMat);
99 
100  closest_to_line_segment_v2(cent_sco_test, mval_fl, e_sco[0], e_sco[1]);
101  dist_sq_test = len_squared_v2v2(cent_sco_test, mval_fl);
102  if (dist_sq_test < dist_sq_best) {
103  dist_sq_best = dist_sq_test;
104 
105  /* we have a new screen center */
106  copy_v2_v2(cent_sco, cent_sco_test);
107  }
108  }
109  }
110  }
111 
112  sub_v2_v2v2(mval_dir, mval_fl, cent_sco);
113  normalize_v2(mval_dir);
114 
115  /* operate on selected verts */
116  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
117  BMIter eiter;
118  BMEdge *e;
119  float v_sco[2];
120 
122  /* Rules for */
123  float angle_best = FLT_MAX;
124  BMEdge *e_best = NULL;
125 
126 #ifdef USE_TRICKY_EXTEND
127  /* first check if we can select the edge to split based on selection-only */
128  int tot_sel = 0;
129 
130  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
133  e_best = e;
134  tot_sel += 1;
135  }
136  }
137  }
138  if (tot_sel != 1) {
139  e_best = NULL;
140  }
141 
142  /* only one edge selected, operate on that */
143  if (e_best) {
144  goto found_edge;
145  }
146  /* none selected, fall through and find one */
147  else if (tot_sel == 0) {
148  /* pass */
149  }
150  /* selection not 0 or 1, do nothing */
151  else {
152  goto found_edge;
153  }
154 #endif
155  ED_view3d_project_float_v2_m4(region, v->co, v_sco, projectMat);
156 
157  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
159  BMVert *v_other = BM_edge_other_vert(e, v);
160  float v_other_sco[2];
161  float angle_test;
162 
163  ED_view3d_project_float_v2_m4(region, v_other->co, v_other_sco, projectMat);
164 
165  /* avoid comparing with view-axis aligned edges (less than a pixel) */
166  if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) {
167  float v_dir[2];
168 
169  sub_v2_v2v2(v_dir, v_other_sco, v_sco);
170  normalize_v2(v_dir);
171 
172  angle_test = angle_normalized_v2v2(mval_dir, v_dir);
173 
174  if (angle_test < angle_best) {
175  angle_best = angle_test;
176  e_best = e;
177  }
178  }
179  }
180  }
181 
182 #ifdef USE_TRICKY_EXTEND
183  found_edge:
184 #endif
185  if (e_best) {
186  const bool e_select = BM_elem_flag_test_bool(e_best, BM_ELEM_SELECT);
187  BMVert *v_new;
188  BMEdge *e_new;
189 
190  v_new = BM_edge_split(bm, e_best, v, &e_new, 0.0f);
191 
192  BM_vert_select_set(bm, v, false);
193  BM_edge_select_set(bm, e_new, false);
194 
195  BM_vert_select_set(bm, v_new, true);
196  if (e_select) {
197  BM_edge_select_set(bm, e_best, true);
198  }
199  BM_elem_flag_enable(v_new, BM_ELEM_TAG); /* prevent further splitting */
200 
201  changed = true;
202  }
203  }
204  }
205 
206  if (changed) {
208 
210 
211  EDBM_update(obedit->data,
212  &(const struct EDBMUpdate_Params){
213  .calc_looptri = true,
214  .calc_normals = false,
215  .is_destructive = true,
216  });
217  }
218  }
219 
220  MEM_freeN(objects);
221 
222  return OPERATOR_FINISHED;
223 }
224 
226 {
227  /* identifiers */
228  ot->name = "Extend Vertices";
229  ot->idname = "MESH_OT_rip_edge";
230  ot->description = "Extend vertices along the edge closest to the cursor";
231 
232  /* api callbacks */
235 
236  /* flags */
238 
239  /* to give to transform */
241 }
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:793
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:542
float 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:357
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:461
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:67
#define UNPACK2(a)
#define UNUSED(x)
Object is a sort of wrapper for general info.
@ OPERATOR_FINISHED
void EDBM_update(struct Mesh *me, const struct EDBMUpdate_Params *params)
#define P_PROPORTIONAL
Definition: ED_transform.h:110
void Transform_Properties(struct wmOperatorType *ot, int flags)
#define P_MIRROR_DUMMY
Definition: ED_transform.h:109
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, const 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], const float mat[4][4])
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
@ OPTYPE_DEPENDS_ON_CURSOR
Definition: WM_types.h:184
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
@ 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:15
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_elem_flag_test_bool(ele, hflag)
Definition: bmesh_inline.h:13
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
#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:448
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:27
struct BMesh * bm
Definition: BKE_editmesh.h:40
float co[3]
Definition: bmesh_class.h:87
int totvertsel
Definition: bmesh_class.h:298
int totedgesel
Definition: bmesh_class.h:298
void * data
int mval[2]
Definition: WM_types.h:684
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
const char * description
Definition: WM_types.h:893
wmOperatorType * ot
Definition: wm_files.c:3479