Blender  V2.93
bmo_offset_edgeloops.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 
26 #include "MEM_guardedalloc.h"
27 
28 #include "BLI_alloca.h"
29 #include "BLI_math.h"
30 #include "BLI_utildefines_stack.h"
31 
32 #include "BKE_customdata.h"
33 
34 #include "bmesh.h"
35 
36 #include "intern/bmesh_operators_private.h" /* own include */
37 
38 #define USE_CAP_OPTION
39 
40 #define ELE_NEW (1 << 0)
41 
42 #ifdef USE_CAP_OPTION
43 # define ELE_VERT_ENDPOINT (1 << 1)
44 #endif
45 
46 /* set for debugging */
47 #define OFFSET 0.0f
48 
50 {
51  float(*cos)[3];
52  BMLoop *l_dst;
53  BMFace *f;
54  int num, i;
55 
56  for (l_dst = l_src->prev, num = 0; BM_elem_index_get(l_dst->prev->v) != -1;
57  l_dst = l_dst->prev, num++) {
58  /* pass */
59  }
60 
61  BLI_assert(num != 0);
62 
63  cos = BLI_array_alloca(cos, num);
64 
65  for (l_dst = l_src->prev, i = 0; BM_elem_index_get(l_dst->prev->v) != -1;
66  l_dst = l_dst->prev, i++) {
67  copy_v3_v3(cos[num - (i + 1)], l_dst->v->co);
68  }
69 
70  f = BM_face_split_n(bm, l_src->f, l_dst->prev, l_src->next, cos, num, r_l, NULL);
71 
72  return f;
73 }
74 
76 {
77  const int edges_num = BMO_slot_buffer_count(op->slots_in, "edges");
78  BMVert **verts;
80  int i;
81 
82 #ifdef USE_CAP_OPTION
83  bool use_cap_endpoint = BMO_slot_bool_get(op->slots_in, "use_cap_endpoint");
84  int v_edges_max = 0;
85 #endif
86 
87  BMOIter oiter;
88 
89  /* only so we can detect new verts (index == -1) */
91 
93 
94  /* over alloc */
95  verts = MEM_mallocN(sizeof(*verts) * (edges_num * 2), __func__);
96 
97  STACK_INIT(verts, (edges_num * 2));
98 
99  {
100  BMEdge *e;
101  BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) {
102  int j;
103 
105 
106  for (j = 0; j < 2; j++) {
107  BMVert *v_edge = *(&(e->v1) + j);
108  if (!BM_elem_flag_test(v_edge, BM_ELEM_TAG)) {
110  STACK_PUSH(verts, v_edge);
111  }
112  }
113  }
114  }
115 
116  /* -------------------------------------------------------------------- */
117  /* Remove verts only used by tagged edges */
118 
119  for (i = 0; i < STACK_SIZE(verts); i++) {
120  BMIter iter;
121  int flag = 0;
122  BMEdge *e;
123 
124  BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) {
125  flag |= BM_elem_flag_test(e, BM_ELEM_TAG) ? 1 : 2;
126  if (flag == (1 | 2)) {
127  break;
128  }
129  }
130 
131  /* only boundary verts are interesting */
132  if (flag != (1 | 2)) {
133  STACK_REMOVE(verts, i);
134  }
135  }
136 
137  /* possible but unlikely we have no mixed vertices */
138  if (UNLIKELY(STACK_SIZE(verts) == 0)) {
139  MEM_freeN(verts);
140  return;
141  }
142 
143  /* main loop */
144  for (i = 0; i < STACK_SIZE(verts); i++) {
145  int v_edges_num = 0;
146  int v_edges_num_untag = 0;
147  BMVert *v = verts[i];
148  BMIter iter;
149  BMEdge *e;
150 
151  BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) {
153  BMVert *v_other;
154  BMIter liter;
155  BMLoop *l;
156 
157  BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
159  }
160 
161  v_other = BM_edge_other_vert(e, v);
162  BM_edge_split(bm, e, v_other, NULL, 1.0f - OFFSET);
163  }
164  else {
165  v_edges_num_untag += 1;
166  }
167 
168  v_edges_num += 1;
169  }
170 
171 #ifdef USE_CAP_OPTION
172  if (v_edges_num_untag == 1) {
174  }
175 
176  CLAMP_MIN(v_edges_max, v_edges_num);
177 #endif
178  }
179 
180  for (i = 0; i < STACK_SIZE(verts); i++) {
181  BMVert *v = verts[i];
182  BMIter liter;
183  BMLoop *l;
184 
185  BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
186  if (BM_elem_flag_test(l->f, BM_ELEM_TAG) && (l->f->len != 3)) {
187  BMFace *f_cmp = l->f;
188  if ((BM_elem_index_get(l->next->v) == -1) && (BM_elem_index_get(l->prev->v) == -1)) {
189 #ifdef USE_CAP_OPTION
190  if (use_cap_endpoint || (BMO_vert_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0))
191 #endif
192  {
193  BMLoop *l_new;
194  BM_face_split(bm, l->f, l->prev, l->next, &l_new, NULL, true);
195  BLI_assert(f_cmp == l->f);
196  BLI_assert(f_cmp != l_new->f);
197  UNUSED_VARS_NDEBUG(f_cmp);
198  BMO_edge_flag_enable(bm, l_new->e, ELE_NEW);
199  }
200  }
201  else if (l->f->len > 4) {
203  if (BM_elem_index_get(l->next->v) == -1) {
204  if (BM_elem_index_get(l->prev->prev->v) == -1) {
205  BMLoop *l_new;
206  BM_face_split(bm, l->f, l->prev->prev, l->next, &l_new, NULL, true);
207  BLI_assert(f_cmp == l->f);
208  BLI_assert(f_cmp != l_new->f);
209  BMO_edge_flag_enable(bm, l_new->e, ELE_NEW);
211  }
212  else {
213  /* walk backwards */
214  BMLoop *l_new;
215  bm_face_split_walk_back(bm, l, &l_new);
216  do {
217  BMO_edge_flag_enable(bm, l_new->e, ELE_NEW);
218  l_new = l_new->next;
219  } while (BM_vert_is_edge_pair(l_new->v));
221  }
222  }
223 
224  /* Note: instead of duplicate code in alternate direction,
225  * we can be sure to hit the other vertex, so the code above runs. */
226 #if 0
227  else if (BM_elem_index_get(l->prev->v) == -1) {
228  if (BM_elem_index_get(l->next->next->v) == -1) {
229  /* pass */
230  }
231  }
232 #endif
233  }
234  }
235  }
236  }
237  }
238 
239 #ifdef USE_CAP_OPTION
240  if (use_cap_endpoint == false) {
241  BMVert **varr = BLI_array_alloca(varr, v_edges_max);
242  STACK_DECLARE(varr);
243  BMVert *v;
244 
245  for (i = 0; i < STACK_SIZE(verts); i++) {
246  BMIter iter;
247  BMEdge *e;
248 
249  v = verts[i];
250 
251  STACK_INIT(varr, v_edges_max);
252 
253  BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
254  BMVert *v_other;
255  v_other = BM_edge_other_vert(e, v);
256  if (BM_elem_index_get(v_other) == -1) {
257  if (BM_vert_is_edge_pair(v_other)) {
258  /* defer bmesh_kernel_join_edge_kill_vert to avoid looping over data we're removing */
259  v_other->e = e;
260  STACK_PUSH(varr, v_other);
261  }
262  }
263  }
264 
265  while ((v = STACK_POP(varr))) {
266  bmesh_kernel_join_edge_kill_vert(bm, v->e, v, true, false, false, true);
267  }
268  }
269  }
270 #endif
271 
272  MEM_freeN(verts);
273 
275 }
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:36
#define BLI_assert(a)
Definition: BLI_assert.h:58
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_INIT(stack, tot)
#define STACK_SIZE(stack)
#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:1803
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#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_enable(ele, hflag)
Definition: bmesh_inline.h:28
#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.c:2152
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
Definition: bmesh_mods.c:591
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:252
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:334
#define BMO_edge_flag_enable(bm, e, oflag)
#define BMO_vert_flag_enable(bm, e, oflag)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
int BMO_slot_buffer_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_vert_flag_test(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, const char htype, const short oflag)
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:771
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:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
int len
Definition: bmesh_class.h:279
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109