Blender  V3.3
bmo_offset_edgeloops.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
12 #include "MEM_guardedalloc.h"
13 
14 #include "BLI_alloca.h"
15 #include "BLI_math.h"
16 #include "BLI_utildefines_stack.h"
17 
18 #include "BKE_customdata.h"
19 
20 #include "bmesh.h"
21 
22 #include "intern/bmesh_operators_private.h" /* own include */
23 
24 #define USE_CAP_OPTION
25 
26 #define ELE_NEW (1 << 0)
27 
28 #ifdef USE_CAP_OPTION
29 # define ELE_VERT_ENDPOINT (1 << 1)
30 #endif
31 
32 /* set for debugging */
33 #define OFFSET 0.0f
34 
36 {
37  float(*cos)[3];
38  BMLoop *l_dst;
39  BMFace *f;
40  int num, i;
41 
42  for (l_dst = l_src->prev, num = 0; BM_elem_index_get(l_dst->prev->v) != -1;
43  l_dst = l_dst->prev, num++) {
44  /* pass */
45  }
46 
47  BLI_assert(num != 0);
48 
49  cos = BLI_array_alloca(cos, num);
50 
51  for (l_dst = l_src->prev, i = 0; BM_elem_index_get(l_dst->prev->v) != -1;
52  l_dst = l_dst->prev, i++) {
53  copy_v3_v3(cos[num - (i + 1)], l_dst->v->co);
54  }
55 
56  f = BM_face_split_n(bm, l_src->f, l_dst->prev, l_src->next, cos, num, r_l, NULL);
57 
58  return f;
59 }
60 
62 {
63  const int edges_num = BMO_slot_buffer_len(op->slots_in, "edges");
64  BMVert **verts;
66  int i;
67 
68 #ifdef USE_CAP_OPTION
69  bool use_cap_endpoint = BMO_slot_bool_get(op->slots_in, "use_cap_endpoint");
70  int v_edges_max = 0;
71 #endif
72 
73  BMOIter oiter;
74 
75  /* only so we can detect new verts (index == -1) */
77 
79 
80  /* over alloc */
81  verts = MEM_mallocN(sizeof(*verts) * (edges_num * 2), __func__);
82 
83  STACK_INIT(verts, (edges_num * 2));
84 
85  {
86  BMEdge *e;
87  BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) {
88  int j;
89 
91 
92  for (j = 0; j < 2; j++) {
93  BMVert *v_edge = *(&(e->v1) + j);
94  if (!BM_elem_flag_test(v_edge, BM_ELEM_TAG)) {
96  STACK_PUSH(verts, v_edge);
97  }
98  }
99  }
100  }
101 
102  /* -------------------------------------------------------------------- */
103  /* Remove verts only used by tagged edges */
104 
105  for (i = 0; i < STACK_SIZE(verts); i++) {
106  BMIter iter;
107  int flag = 0;
108  BMEdge *e;
109 
110  BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) {
111  flag |= BM_elem_flag_test(e, BM_ELEM_TAG) ? 1 : 2;
112  if (flag == (1 | 2)) {
113  break;
114  }
115  }
116 
117  /* only boundary verts are interesting */
118  if (flag != (1 | 2)) {
119  STACK_REMOVE(verts, i);
120  }
121  }
122 
123  /* possible but unlikely we have no mixed vertices */
124  if (UNLIKELY(STACK_SIZE(verts) == 0)) {
125  MEM_freeN(verts);
126  return;
127  }
128 
129  /* main loop */
130  for (i = 0; i < STACK_SIZE(verts); i++) {
131  int v_edges_num = 0;
132  int v_edges_num_untag = 0;
133  BMVert *v = verts[i];
134  BMIter iter;
135  BMEdge *e;
136 
137  BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) {
139  BMVert *v_other;
140  BMIter liter;
141  BMLoop *l;
142 
143  BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
145  }
146 
147  v_other = BM_edge_other_vert(e, v);
148  BM_edge_split(bm, e, v_other, NULL, 1.0f - OFFSET);
149  }
150  else {
151  v_edges_num_untag += 1;
152  }
153 
154  v_edges_num += 1;
155  }
156 
157 #ifdef USE_CAP_OPTION
158  if (v_edges_num_untag == 1) {
160  }
161 
162  CLAMP_MIN(v_edges_max, v_edges_num);
163 #endif
164  }
165 
166  for (i = 0; i < STACK_SIZE(verts); i++) {
167  BMVert *v = verts[i];
168  BMIter liter;
169  BMLoop *l;
170 
171  BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
172  if (BM_elem_flag_test(l->f, BM_ELEM_TAG) && (l->f->len != 3)) {
173  BMFace *f_cmp = l->f;
174  if ((BM_elem_index_get(l->next->v) == -1) && (BM_elem_index_get(l->prev->v) == -1)) {
175 #ifdef USE_CAP_OPTION
176  if (use_cap_endpoint || (BMO_vert_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0))
177 #endif
178  {
179  BMLoop *l_new;
180  BM_face_split(bm, l->f, l->prev, l->next, &l_new, NULL, true);
181  BLI_assert(f_cmp == l->f);
182  BLI_assert(f_cmp != l_new->f);
183  UNUSED_VARS_NDEBUG(f_cmp);
184  BMO_edge_flag_enable(bm, l_new->e, ELE_NEW);
185  }
186  }
187  else if (l->f->len > 4) {
189  if (BM_elem_index_get(l->next->v) == -1) {
190  if (BM_elem_index_get(l->prev->prev->v) == -1) {
191  BMLoop *l_new;
192  BM_face_split(bm, l->f, l->prev->prev, l->next, &l_new, NULL, true);
193  BLI_assert(f_cmp == l->f);
194  BLI_assert(f_cmp != l_new->f);
195  BMO_edge_flag_enable(bm, l_new->e, ELE_NEW);
197  }
198  else {
199  /* walk backwards */
200  BMLoop *l_new;
201  bm_face_split_walk_back(bm, l, &l_new);
202  do {
203  BMO_edge_flag_enable(bm, l_new->e, ELE_NEW);
204  l_new = l_new->next;
205  } while (BM_vert_is_edge_pair(l_new->v));
207  }
208  }
209 
210  /* NOTE: instead of duplicate code in alternate direction,
211  * we can be sure to hit the other vertex, so the code above runs. */
212 #if 0
213  else if (BM_elem_index_get(l->prev->v) == -1) {
214  if (BM_elem_index_get(l->next->next->v) == -1) {
215  /* pass */
216  }
217  }
218 #endif
219  }
220  }
221  }
222  }
223  }
224 
225 #ifdef USE_CAP_OPTION
226  if (use_cap_endpoint == false) {
227  BMVert **varr = BLI_array_alloca(varr, v_edges_max);
228  STACK_DECLARE(varr);
229  BMVert *v;
230 
231  for (i = 0; i < STACK_SIZE(verts); i++) {
232  BMIter iter;
233  BMEdge *e;
234 
235  v = verts[i];
236 
237  STACK_INIT(varr, v_edges_max);
238 
239  BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
240  BMVert *v_other;
241  v_other = BM_edge_other_vert(e, v);
242  if (BM_elem_index_get(v_other) == -1) {
243  if (BM_vert_is_edge_pair(v_other)) {
244  /* defer bmesh_kernel_join_edge_kill_vert to avoid looping over data we're removing */
245  v_other->e = e;
246  STACK_PUSH(varr, v_other);
247  }
248  }
249  }
250 
251  while ((v = STACK_POP(varr))) {
252  bmesh_kernel_join_edge_kill_vert(bm, v->e, v, true, false, false, true);
253  }
254  }
255  }
256 #endif
257 
258  MEM_freeN(verts);
259 
261 }
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:22
#define BLI_assert(a)
Definition: BLI_assert.h:46
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define CLAMP_MIN(a, b)
#define STACK_POP(stack)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
#define STACK_REMOVE(stack, i)
Read Guarded memory(de)allocation.
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
BMEdge * bmesh_kernel_join_edge_kill_vert(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool check_edge_exists, const bool kill_degenerate_faces, const bool kill_duplicate_faces)
Join Edge Kill Vert (JEKV)
Definition: bmesh_core.c:1631
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#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_enable(ele, hflag)
Definition: bmesh_inline.h:14
#define BM_ITER_ELEM(ele, iter, data, itype)
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_EDGE
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:446
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
Definition: bmesh_mods.c:448
BMFace * BM_face_split(BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, BMLoop **r_l, BMEdge *example, const bool no_double)
Face Split.
Definition: bmesh_mods.c:179
BMFace * BM_face_split_n(BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, float cos[][3], int n, BMLoop **r_l, BMEdge *example)
Face Split with intermediate points.
Definition: bmesh_mods.c:243
#define BMO_edge_flag_enable(bm, e, oflag)
#define BMO_vert_flag_enable(bm, e, oflag)
void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
#define BMO_vert_flag_test(bm, e, oflag)
int BMO_slot_buffer_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
bool BM_vert_is_edge_pair(const BMVert *v)
Definition: bmesh_query.c:568
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
#define OFFSET
#define ELE_NEW
static BMFace * bm_face_split_walk_back(BMesh *bm, BMLoop *l_src, BMLoop **r_l)
#define ELE_VERT_ENDPOINT
static float verts[][3]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
int len
Definition: bmesh_class.h:267
struct BMVert * v
Definition: bmesh_class.h:153
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMLoop * prev
Definition: bmesh_class.h:233
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
Definition: bmesh_class.h:87
struct BMEdge * e
Definition: bmesh_class.h:97