Blender  V3.3
bmesh_mods.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
10 #include "MEM_guardedalloc.h"
11 
12 #include "BLI_array.h"
13 #include "BLI_math.h"
14 
15 #include "BKE_customdata.h"
16 
17 #include "bmesh.h"
18 #include "intern/bmesh_private.h"
19 
21 {
22  /* logic for 3 or more is identical */
23  const int len = BM_vert_edge_count_at_most(v, 3);
24 
25  if (len == 1) {
26  BM_vert_kill(bm, v); /* will kill edges too */
27  return true;
28  }
29  if (!BM_vert_is_manifold(v)) {
30  if (!v->e) {
31  BM_vert_kill(bm, v);
32  return true;
33  }
34  if (!v->e->l) {
35  if (len == 2) {
36  return (BM_vert_collapse_edge(bm, v->e, v, true, true, true) != NULL);
37  }
38  /* used to kill the vertex here, but it may be connected to faces.
39  * so better do nothing */
40  return false;
41  }
42  return false;
43  }
44  if (len == 2 && BM_vert_face_count_is_equal(v, 1)) {
45  /* boundary vertex on a face */
46  return (BM_vert_collapse_edge(bm, v->e, v, true, true, true) != NULL);
47  }
48  return BM_disk_dissolve(bm, v);
49 }
50 
52 {
53  BMEdge *e, *keepedge = NULL, *baseedge = NULL;
54  int len = 0;
55 
56  if (!BM_vert_is_manifold(v)) {
57  return false;
58  }
59 
60  if (v->e) {
61  /* v->e we keep, what else */
62  e = v->e;
63  do {
65  if (!(BM_edge_share_face_check(e, v->e))) {
66  keepedge = e;
67  baseedge = v->e;
68  break;
69  }
70  len++;
71  } while (e != v->e);
72  }
73 
74  /* this code for handling 2 and 3-valence verts
75  * may be totally bad */
76  if (keepedge == NULL && len == 3) {
77 #if 0
78  /* handle specific case for three-valence. solve it by
79  * increasing valence to four. this may be hackish. */
80  BMLoop *l_a = BM_face_vert_share_loop(e->l->f, v);
81  BMLoop *l_b = (e->l->v == v) ? e->l->next : e->l;
82 
83  if (!BM_face_split(bm, e->l->f, l_a, l_b, NULL, NULL, false)) {
84  return false;
85  }
86 
87  if (!BM_disk_dissolve(bm, v)) {
88  return false;
89  }
90 #else
91  if (UNLIKELY(!BM_faces_join_pair(bm, e->l, e->l->radial_next, true))) {
92  return false;
93  }
94  if (UNLIKELY(!BM_vert_collapse_faces(bm, v->e, v, 1.0, true, false, true, true))) {
95  return false;
96  }
97 #endif
98  return true;
99  }
100  if (keepedge == NULL && len == 2) {
101  /* collapse the vertex */
102  e = BM_vert_collapse_faces(bm, v->e, v, 1.0, true, true, true, true);
103 
104  if (!e) {
105  return false;
106  }
107 
108  /* handle two-valence */
109  if (e->l != e->l->radial_next) {
110  if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) {
111  return false;
112  }
113  }
114 
115  return true;
116  }
117 
118  if (keepedge) {
119  bool done = false;
120 
121  while (!done) {
122  done = true;
123  e = v->e;
124  do {
125  BMFace *f = NULL;
126  if (BM_edge_is_manifold(e) && (e != baseedge) && (e != keepedge)) {
127  f = BM_faces_join_pair(bm, e->l, e->l->radial_next, true);
128  /* return if couldn't join faces in manifold
129  * conditions */
130  /* !disabled for testing why bad things happen */
131  if (!f) {
132  return false;
133  }
134  }
135 
136  if (f) {
137  done = false;
138  break;
139  }
140  } while ((e = bmesh_disk_edge_next(e, v)) != v->e);
141  }
142 
143  /* collapse the vertex */
144  /* NOTE: the baseedge can be a boundary of manifold, use this as join_faces arg. */
146  bm, baseedge, v, 1.0, true, !BM_edge_is_boundary(baseedge), true, true);
147 
148  if (!e) {
149  return false;
150  }
151 
152  if (e->l) {
153  /* get remaining two faces */
154  if (e->l != e->l->radial_next) {
155  /* join two remaining faces */
156  if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) {
157  return false;
158  }
159  }
160  }
161  }
162 
163  return true;
164 }
165 
166 BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
167 {
168  BLI_assert((l_a != l_b) && (l_a->e == l_b->e));
169 
170  if (l_a->v == l_b->v) {
171  const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
172  bmesh_kernel_loop_reverse(bm, l_b->f, cd_loop_mdisp_offset, true);
173  }
174 
175  BMFace *faces[2] = {l_a->f, l_b->f};
176  return BM_faces_join(bm, faces, 2, do_del);
177 }
178 
180  BMFace *f,
181  BMLoop *l_a,
182  BMLoop *l_b,
183  BMLoop **r_l,
184  BMEdge *example,
185  const bool no_double)
186 {
187  const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
188  BMFace *f_new, *f_tmp;
189 
190  BLI_assert(l_a != l_b);
191  BLI_assert(f == l_a->f && f == l_b->f);
193 
194  /* could be an assert */
195  if (UNLIKELY(BM_loop_is_adjacent(l_a, l_b)) || UNLIKELY((f != l_a->f || f != l_b->f))) {
196  if (r_l) {
197  *r_l = NULL;
198  }
199  return NULL;
200  }
201 
202  /* do we have a multires layer? */
203  if (cd_loop_mdisp_offset != -1) {
204  f_tmp = BM_face_copy(bm, bm, f, false, false);
205  }
206 
207 #ifdef USE_BMESH_HOLES
208  f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, r_l, NULL, example, no_double);
209 #else
210  f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, r_l, example, no_double);
211 #endif
212 
213  if (f_new) {
214  /* handle multires update */
215  if (cd_loop_mdisp_offset != -1) {
216  float f_dst_center[3];
217  float f_src_center[3];
218 
219  BM_face_calc_center_median(f_tmp, f_src_center);
220 
221  BM_face_calc_center_median(f, f_dst_center);
222  BM_face_interp_multires_ex(bm, f, f_tmp, f_dst_center, f_src_center, cd_loop_mdisp_offset);
223 
224  BM_face_calc_center_median(f_new, f_dst_center);
226  bm, f_new, f_tmp, f_dst_center, f_src_center, cd_loop_mdisp_offset);
227 
228 #if 0
229  /* BM_face_multires_bounds_smooth doesn't flip displacement correct */
232 #endif
233  }
234  }
235 
236  if (cd_loop_mdisp_offset != -1) {
237  BM_face_kill(bm, f_tmp);
238  }
239 
240  return f_new;
241 }
242 
244  BMFace *f,
245  BMLoop *l_a,
246  BMLoop *l_b,
247  float cos[][3],
248  int n,
249  BMLoop **r_l,
250  BMEdge *example)
251 {
252  BMFace *f_new, *f_tmp;
253  BMLoop *l_new;
254  BMEdge *e, *e_new;
255  BMVert *v_new;
256  // BMVert *v_a = l_a->v; /* UNUSED */
257  BMVert *v_b = l_b->v;
258  int i, j;
259 
260  BLI_assert(l_a != l_b);
261  BLI_assert(f == l_a->f && f == l_b->f);
262  BLI_assert(!((n == 0) && BM_loop_is_adjacent(l_a, l_b)));
263 
264  /* could be an assert */
265  if (UNLIKELY((n == 0) && BM_loop_is_adjacent(l_a, l_b)) || UNLIKELY(l_a->f != l_b->f)) {
266  if (r_l) {
267  *r_l = NULL;
268  }
269  return NULL;
270  }
271 
272  f_tmp = BM_face_copy(bm, bm, f, true, true);
273 
274 #ifdef USE_BMESH_HOLES
275  f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, &l_new, NULL, example, false);
276 #else
277  f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, &l_new, example, false);
278 #endif
279  /* bmesh_kernel_split_face_make_edge returns in 'l_new'
280  * a Loop for f_new going from 'v_a' to 'v_b'.
281  * The radial_next is for 'f' and goes from 'v_b' to 'v_a'. */
282 
283  if (f_new) {
284  e = l_new->e;
285  for (i = 0; i < n; i++) {
286  v_new = bmesh_kernel_split_edge_make_vert(bm, v_b, e, &e_new);
287  BLI_assert(v_new != NULL);
288  /* bmesh_kernel_split_edge_make_vert returns in 'e_new'
289  * the edge going from 'v_new' to 'v_b'. */
290  copy_v3_v3(v_new->co, cos[i]);
291 
292  /* interpolate the loop data for the loops with (v == v_new), using orig face */
293  for (j = 0; j < 2; j++) {
294  BMEdge *e_iter = (j == 0) ? e : e_new;
295  BMLoop *l_iter = e_iter->l;
296  do {
297  if (l_iter->v == v_new) {
298  /* this interpolates both loop and vertex data */
299  BM_loop_interp_from_face(bm, l_iter, f_tmp, true, true);
300  }
301  } while ((l_iter = l_iter->radial_next) != e_iter->l);
302  }
303  e = e_new;
304  }
305  }
306 
307  BM_face_verts_kill(bm, f_tmp);
308 
309  if (r_l) {
310  *r_l = l_new;
311  }
312 
313  return f_new;
314 }
315 
317  BMEdge *e_kill,
318  BMVert *v_kill,
319  float fac,
320  const bool do_del,
321  const bool join_faces,
322  const bool kill_degenerate_faces,
323  const bool kill_duplicate_faces)
324 {
325  BMEdge *e_new = NULL;
326  BMVert *tv = BM_edge_other_vert(e_kill, v_kill);
327 
328  BMEdge *e2;
329  BMVert *tv2;
330 
331  /* Only intended to be called for 2-valence vertices */
332  BLI_assert(bmesh_disk_count(v_kill) <= 2);
333 
334  /* first modify the face loop data */
335 
336  if (e_kill->l) {
337  BMLoop *l_iter;
338  const float w[2] = {1.0f - fac, fac};
339 
340  l_iter = e_kill->l;
341  do {
342  if (l_iter->v == tv && l_iter->next->v == v_kill) {
343  const void *src[2];
344  BMLoop *tvloop = l_iter;
345  BMLoop *kvloop = l_iter->next;
346 
347  src[0] = kvloop->head.data;
348  src[1] = tvloop->head.data;
349  CustomData_bmesh_interp(&bm->ldata, src, w, NULL, 2, kvloop->head.data);
350  }
351  } while ((l_iter = l_iter->radial_next) != e_kill->l);
352  }
353 
354  /* now interpolate the vertex data */
355  BM_data_interp_from_verts(bm, v_kill, tv, v_kill, fac);
356 
357  e2 = bmesh_disk_edge_next(e_kill, v_kill);
358  tv2 = BM_edge_other_vert(e2, v_kill);
359 
360  if (join_faces) {
361  BMIter fiter;
362  BMFace **faces = NULL;
363  BMFace *f;
365 
366  BM_ITER_ELEM (f, &fiter, v_kill, BM_FACES_OF_VERT) {
368  }
369 
370  if (BLI_array_len(faces) >= 2) {
372  if (f2) {
373  BMLoop *l_a, *l_b;
374 
375  if ((l_a = BM_face_vert_share_loop(f2, tv)) && (l_b = BM_face_vert_share_loop(f2, tv2))) {
376  BMLoop *l_new;
377 
378  if (BM_face_split(bm, f2, l_a, l_b, &l_new, NULL, false)) {
379  e_new = l_new->e;
380  }
381  }
382  }
383  }
384 
386 
388  }
389  else {
390  /* single face or no faces */
391  /* same as BM_vert_collapse_edge() however we already
392  * have vars to perform this operation so don't call. */
394  bm, e_kill, v_kill, do_del, true, kill_degenerate_faces, kill_duplicate_faces);
395 
396  /* e_new = BM_edge_exists(tv, tv2); */ /* same as return above */
397  }
398 
399  return e_new;
400 }
401 
403  BMEdge *e_kill,
404  BMVert *v_kill,
405  const bool do_del,
406  const bool kill_degenerate_faces,
407  const bool kill_duplicate_faces)
408 {
409  /* nice example implementation but we want loops to have their customdata
410  * accounted for */
411 #if 0
412  BMEdge *e_new = NULL;
413 
414  /* Collapse between 2 edges */
415 
416  /* in this case we want to keep all faces and not join them,
417  * rather just get rid of the vertex - see bug T28645. */
418  BMVert *tv = BM_edge_other_vert(e_kill, v_kill);
419  if (tv) {
420  BMEdge *e2 = bmesh_disk_edge_next(e_kill, v_kill);
421  if (e2) {
422  BMVert *tv2 = BM_edge_other_vert(e2, v_kill);
423  if (tv2) {
424  /* only action, other calls here only get the edge to return */
426  bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
427  }
428  }
429  }
430 
431  return e_new;
432 #else
433  /* with these args faces are never joined, same as above
434  * but account for loop customdata */
435  return BM_vert_collapse_faces(
436  bm, e_kill, v_kill, 1.0f, do_del, false, kill_degenerate_faces, kill_duplicate_faces);
437 #endif
438 }
439 
440 #undef DO_V_INTERP
441 
443  BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces)
444 {
445  return bmesh_kernel_join_vert_kill_edge(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
446 }
447 
448 BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
449 {
450  BMVert *v_new, *v_other;
451  BMEdge *e_new;
452  BMFace **oldfaces = NULL;
453  BLI_array_staticdeclare(oldfaces, 32);
454  const int cd_loop_mdisp_offset = BM_edge_is_wire(e) ?
455  -1 :
457 
458  BLI_assert(BM_vert_in_edge(e, v) == true);
459 
460  /* do we have a multi-res layer? */
461  if (cd_loop_mdisp_offset != -1) {
462  BMLoop *l;
463  int i;
464 
465  l = e->l;
466  do {
467  BLI_array_append(oldfaces, l->f);
468  l = l->radial_next;
469  } while (l != e->l);
470 
471  /* flag existing faces so we can differentiate oldfaces from new faces */
472  for (i = 0; i < BLI_array_len(oldfaces); i++) {
474  oldfaces[i] = BM_face_copy(bm, bm, oldfaces[i], true, true);
476  }
477  }
478 
479  v_other = BM_edge_other_vert(e, v);
480  v_new = bmesh_kernel_split_edge_make_vert(bm, v, e, &e_new);
481  if (r_e != NULL) {
482  *r_e = e_new;
483  }
484 
485  BLI_assert(v_new != NULL);
486  BLI_assert(BM_vert_in_edge(e_new, v) && BM_vert_in_edge(e_new, v_new));
487  BLI_assert(BM_vert_in_edge(e, v_new) && BM_vert_in_edge(e, v_other));
488 
489  sub_v3_v3v3(v_new->co, v_other->co, v->co);
490  madd_v3_v3v3fl(v_new->co, v->co, v_new->co, fac);
491 
492  e_new->head.hflag = e->head.hflag;
493  BM_elem_attrs_copy(bm, bm, e, e_new);
494 
495  /* v->v_new->v2 */
496  BM_data_interp_face_vert_edge(bm, v_other, v, v_new, e, fac);
497  BM_data_interp_from_verts(bm, v, v_other, v_new, fac);
498 
499  if (cd_loop_mdisp_offset != -1) {
500  int i, j;
501 
502  /* interpolate new/changed loop data from copied old faces */
503  for (i = 0; i < BLI_array_len(oldfaces); i++) {
504  float f_center_old[3];
505 
506  BM_face_calc_center_median(oldfaces[i], f_center_old);
507 
508  for (j = 0; j < 2; j++) {
509  BMEdge *e1 = j ? e_new : e;
510  BMLoop *l;
511 
512  l = e1->l;
513 
514  if (UNLIKELY(!l)) {
515  BMESH_ASSERT(0);
516  break;
517  }
518 
519  do {
520  /* check this is an old face */
522  float f_center[3];
523 
524  BM_face_calc_center_median(l->f, f_center);
526  bm, l->f, oldfaces[i], f_center, f_center_old, cd_loop_mdisp_offset);
527  }
528  l = l->radial_next;
529  } while (l != e1->l);
530  }
531  }
532 
533  /* destroy the old faces */
534  for (i = 0; i < BLI_array_len(oldfaces); i++) {
535  BM_face_verts_kill(bm, oldfaces[i]);
536  }
537 
538  /* fix boundaries a bit, doesn't work too well quite yet */
539 #if 0
540  for (j = 0; j < 2; j++) {
541  BMEdge *e1 = j ? e_new : e;
542  BMLoop *l, *l2;
543 
544  l = e1->l;
545  if (UNLIKELY(!l)) {
546  BMESH_ASSERT(0);
547  break;
548  }
549 
550  do {
552  l = l->radial_next;
553  } while (l != e1->l);
554  }
555 #endif
556 
557  BLI_array_free(oldfaces);
558  }
559 
560  return v_new;
561 }
562 
563 BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
564 {
565  int i;
566  float percent;
567  BMVert *v_new = NULL;
568 
569  for (i = 0; i < numcuts; i++) {
570  percent = 1.0f / (float)(numcuts + 1 - i);
571  v_new = BM_edge_split(bm, e, e->v2, NULL, percent);
572  if (r_varr) {
573  /* fill in reverse order (v1 -> v2) */
574  r_varr[numcuts - i - 1] = v_new;
575  }
576  }
577  return v_new;
578 }
579 
581 {
582  SWAP(BMVert *, e->v1, e->v2);
583  SWAP(BMDiskLink, e->v1_disk_link, e->v2_disk_link);
584 }
585 
586 #if 0
590 bool BM_face_validate(BMFace *face, FILE *err)
591 {
592  BMIter iter;
594  BMVert **verts = NULL;
595  BMLoop *l;
596  int i, j;
597  bool ret = true;
598 
599  if (face->len == 2) {
600  fprintf(err, "WARNING: found two-edged face. face ptr: %p\n", face);
601  fflush(err);
602  }
603 
605  BM_ITER_ELEM_INDEX (l, &iter, face, BM_LOOPS_OF_FACE, i) {
606  verts[i] = l->v;
607  if (l->e->v1 == l->e->v2) {
608  fprintf(err, "Found bmesh edge with identical verts!\n");
609  fprintf(err, " edge ptr: %p, vert: %p\n", l->e, l->e->v1);
610  fflush(err);
611  ret = false;
612  }
613  }
614 
615  for (i = 0; i < face->len; i++) {
616  for (j = 0; j < face->len; j++) {
617  if (j == i) {
618  continue;
619  }
620 
621  if (verts[i] == verts[j]) {
622  fprintf(err, "Found duplicate verts in bmesh face!\n");
623  fprintf(err, " face ptr: %p, vert: %p\n", face, verts[i]);
624  fflush(err);
625  ret = false;
626  }
627  }
628  }
629 
631  return ret;
632 }
633 #endif
634 
635 void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2)
636 {
637  BMVert *v1, *v2;
638  BMFace *fa, *fb;
639 
640  /* this should have already run */
642 
643  /* we know this will work */
644  BM_edge_face_pair(e, &fa, &fb);
645 
646  /* so we can use `ccw` variable correctly,
647  * otherwise we could use the edges verts direct */
649 
650  /* we could swap the verts _or_ the faces, swapping faces
651  * gives more predictable results since that way the next vert
652  * just stitches from face fa / fb */
653  if (!ccw) {
654  SWAP(BMFace *, fa, fb);
655  }
656 
657  *r_l1 = BM_face_other_vert_loop(fb, v2, v1);
658  *r_l2 = BM_face_other_vert_loop(fa, v1, v2);
659 }
660 
662 {
663  BMFace *fa, *fb;
664  if (BM_edge_face_pair(e, &fa, &fb)) {
665  BMLoop *la, *lb;
666 
667  la = BM_face_other_vert_loop(fa, e->v2, e->v1);
668  lb = BM_face_other_vert_loop(fb, e->v2, e->v1);
669 
670  /* check that the next vert in both faces isn't the same
671  * (ie - the next edge doesn't share the same faces).
672  * since we can't rotate usefully in this case. */
673  if (la->v == lb->v) {
674  return false;
675  }
676 
677  /* mirror of the check above but in the opposite direction */
678  la = BM_face_other_vert_loop(fa, e->v1, e->v2);
679  lb = BM_face_other_vert_loop(fb, e->v1, e->v2);
680 
681  if (la->v == lb->v) {
682  return false;
683  }
684 
685  return true;
686  }
687  return false;
688 }
689 
691 {
692  /* NOTE: for these vars 'old' just means initial edge state. */
693 
694  float ed_dir_old[3]; /* edge vector */
695  float ed_dir_new[3]; /* edge vector */
696  float ed_dir_new_flip[3]; /* edge vector */
697 
698  float ed_dir_v1_old[3];
699  float ed_dir_v2_old[3];
700 
701  float ed_dir_v1_new[3];
702  float ed_dir_v2_new[3];
703 
704  float cross_old[3];
705  float cross_new[3];
706 
707  /* original verts - these will be in the edge 'e' */
708  BMVert *v1_old, *v2_old;
709 
710  /* verts from the loops passed */
711 
712  BMVert *v1, *v2;
713  /* These are the opposite verts - the verts that _would_ be used if `ccw` was inverted. */
714  BMVert *v1_alt, *v2_alt;
715 
716  /* this should have already run */
718 
719  BM_edge_ordered_verts(e, &v1_old, &v2_old);
720 
721  v1 = l1->v;
722  v2 = l2->v;
723 
724  /* get the next vert along */
725  v1_alt = BM_face_other_vert_loop(l1->f, v1_old, v1)->v;
726  v2_alt = BM_face_other_vert_loop(l2->f, v2_old, v2)->v;
727 
728  /* normalize all so comparisons are scale independent */
729 
730  BLI_assert(BM_edge_exists(v1_old, v1));
731  BLI_assert(BM_edge_exists(v1, v1_alt));
732 
733  BLI_assert(BM_edge_exists(v2_old, v2));
734  BLI_assert(BM_edge_exists(v2, v2_alt));
735 
736  /* old and new edge vecs */
737  sub_v3_v3v3(ed_dir_old, v1_old->co, v2_old->co);
738  sub_v3_v3v3(ed_dir_new, v1->co, v2->co);
739  normalize_v3(ed_dir_old);
740  normalize_v3(ed_dir_new);
741 
742  /* old edge corner vecs */
743  sub_v3_v3v3(ed_dir_v1_old, v1_old->co, v1->co);
744  sub_v3_v3v3(ed_dir_v2_old, v2_old->co, v2->co);
745  normalize_v3(ed_dir_v1_old);
746  normalize_v3(ed_dir_v2_old);
747 
748  /* old edge corner vecs */
749  sub_v3_v3v3(ed_dir_v1_new, v1->co, v1_alt->co);
750  sub_v3_v3v3(ed_dir_v2_new, v2->co, v2_alt->co);
751  normalize_v3(ed_dir_v1_new);
752  normalize_v3(ed_dir_v2_new);
753 
754  /* compare */
755  cross_v3_v3v3(cross_old, ed_dir_old, ed_dir_v1_old);
756  cross_v3_v3v3(cross_new, ed_dir_new, ed_dir_v1_new);
757  if (dot_v3v3(cross_old, cross_new) < 0.0f) { /* does this flip? */
758  return false;
759  }
760  cross_v3_v3v3(cross_old, ed_dir_old, ed_dir_v2_old);
761  cross_v3_v3v3(cross_new, ed_dir_new, ed_dir_v2_new);
762  if (dot_v3v3(cross_old, cross_new) < 0.0f) { /* does this flip? */
763  return false;
764  }
765 
766  negate_v3_v3(ed_dir_new_flip, ed_dir_new);
767 
768  /* result is zero area corner */
769  if ((dot_v3v3(ed_dir_new, ed_dir_v1_new) > 0.999f) ||
770  (dot_v3v3(ed_dir_new_flip, ed_dir_v2_new) > 0.999f)) {
771  return false;
772  }
773 
774  return true;
775 }
776 
778 {
779  /* Stupid check for now:
780  * Could compare angles of surrounding edges
781  * before & after, but this is OK. */
782  return (len_squared_v3v3(e->v1->co, e->v2->co) > len_squared_v3v3(l1->v->co, l2->v->co));
783 }
784 
785 BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag)
786 {
787  BMVert *v1, *v2;
788  BMLoop *l1, *l2;
789  BMFace *f;
790  BMEdge *e_new = NULL;
791  char f_active_prev = 0;
792  char f_hflag_prev_1;
793  char f_hflag_prev_2;
794 
795  if (!BM_edge_rotate_check(e)) {
796  return NULL;
797  }
798 
799  BM_edge_calc_rotate(e, ccw, &l1, &l2);
800 
801  /* the loops will be freed so assign verts */
802  v1 = l1->v;
803  v2 = l2->v;
804 
805  /* --------------------------------------- */
806  /* Checking Code - make sure we can rotate */
807 
808  if (check_flag & BM_EDGEROT_CHECK_BEAUTY) {
809  if (!BM_edge_rotate_check_beauty(e, l1, l2)) {
810  return NULL;
811  }
812  }
813 
814  /* check before applying */
815  if (check_flag & BM_EDGEROT_CHECK_EXISTS) {
816  if (BM_edge_exists(v1, v2)) {
817  return NULL;
818  }
819  }
820 
821  /* slowest, check last */
822  if (check_flag & BM_EDGEROT_CHECK_DEGENERATE) {
823  if (!BM_edge_rotate_check_degenerate(e, l1, l2)) {
824  return NULL;
825  }
826  }
827  /* Done Checking */
828  /* ------------- */
829 
830  /* --------------- */
831  /* Rotate The Edge */
832 
833  /* first create the new edge, this is so we can copy the customdata from the old one
834  * if splice if disabled, always add in a new edge even if there's one there. */
835  e_new = BM_edge_create(
837 
838  f_hflag_prev_1 = l1->f->head.hflag;
839  f_hflag_prev_2 = l2->f->head.hflag;
840 
841  /* maintain active face */
842  if (bm->act_face == l1->f) {
843  f_active_prev = 1;
844  }
845  else if (bm->act_face == l2->f) {
846  f_active_prev = 2;
847  }
848 
849  const bool is_flipped = !BM_edge_is_contiguous(e);
850 
851  /* don't delete the edge, manually remove the edge after so we can copy its attributes */
852  f = BM_faces_join_pair(
853  bm, BM_face_edge_share_loop(l1->f, e), BM_face_edge_share_loop(l2->f, e), true);
854 
855  if (f == NULL) {
856  return NULL;
857  }
858 
859  /* NOTE: this assumes joining the faces _didnt_ also remove the verts.
860  * the #BM_edge_rotate_check will ensure this, but its possibly corrupt state or future edits
861  * break this */
862  if ((l1 = BM_face_vert_share_loop(f, v1)) && (l2 = BM_face_vert_share_loop(f, v2)) &&
863  BM_face_split(bm, f, l1, l2, NULL, NULL, true)) {
864  /* we should really be able to know the faces some other way,
865  * rather than fetching them back from the edge, but this is predictable
866  * where using the return values from face split isn't. - campbell */
867  BMFace *fa, *fb;
868  if (BM_edge_face_pair(e_new, &fa, &fb)) {
869  fa->head.hflag = f_hflag_prev_1;
870  fb->head.hflag = f_hflag_prev_2;
871 
872  if (f_active_prev == 1) {
873  bm->act_face = fa;
874  }
875  else if (f_active_prev == 2) {
876  bm->act_face = fb;
877  }
878 
879  if (is_flipped) {
881 
882  if (ccw) {
883  /* Needed otherwise `ccw` toggles direction */
884  e_new->l = e_new->l->radial_next;
885  }
886  }
887  }
888  }
889  else {
890  return NULL;
891  }
892 
893  return e_new;
894 }
895 
897 {
899 }
900 
902 {
904 }
905 
907 {
908  return bmesh_kernel_unglue_region_make_vert_multi(bm, larr, larr_len);
909 }
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const struct CustomData *data, int type)
void CustomData_bmesh_interp(struct CustomData *data, const void **src_blocks, const float *weights, const float *sub_weights, int count, void *dst_block)
Definition: customdata.cc:4088
A (mainly) macro array library.
#define BLI_array_grow_items(arr, num)
Definition: BLI_array.h:91
#define BLI_array_append(arr, item)
Definition: BLI_array.h:98
#define BLI_array_staticdeclare(arr, maxstatic)
Definition: BLI_array.h:58
#define BLI_array_declare(arr)
Definition: BLI_array.h:50
#define BLI_array_len(arr)
Definition: BLI_array.h:63
#define BLI_array_free(arr)
Definition: BLI_array.h:113
#define BLI_assert(a)
Definition: BLI_assert.h:46
MINLINE float normalize_v3(float r[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
#define SWAP(type, a, b)
#define UNLIKELY(x)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define BM_DEFAULT_ITER_STACK_SIZE
Definition: bmesh_class.h:645
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void *ele_dst)
BMFace * BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
Join Connected Faces.
Definition: bmesh_core.c:1123
void BM_face_verts_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:811
BMVert * bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep)
Definition: bmesh_core.c:2642
void BM_vert_kill(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:939
BMFace * bmesh_kernel_split_face_make_edge(BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2, BMLoop **r_l, BMEdge *e_example, const bool no_double)
Split Face Make Edge (SFME)
Definition: bmesh_core.c:1339
void BM_face_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:828
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
BMVert * bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
Un-glue Region Make Vert (URMV)
Definition: bmesh_core.c:2400
BMVert * bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len)
Definition: bmesh_core.c:2462
void bmesh_kernel_loop_reverse(BMesh *bm, BMFace *f, const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
Loop Reverse.
Definition: bmesh_core.c:965
BMFace * BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, const bool copy_verts, const bool copy_edges)
Definition: bmesh_core.c:279
BMVert * bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
Split Edge Make Vert (SEMV)
Definition: bmesh_core.c:1478
BMVert * bmesh_kernel_join_vert_kill_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool check_edge_exists, const bool kill_degenerate_faces)
Join Vert Kill Edge (JVKE)
Definition: bmesh_core.c:1798
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
Definition: bmesh_core.c:123
@ BM_CREATE_NOP
Definition: bmesh_core.h:12
@ BM_CREATE_NO_DOUBLE
Definition: bmesh_core.h:14
#define BMESH_ASSERT(a)
Definition: bmesh_error.h:80
void BM_face_interp_multires_ex(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const float f_dst_center[3], const float f_src_center[3], const int cd_loop_mdisp_offset)
Definition: bmesh_interp.c:544
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
Definition: bmesh_interp.c:574
void BM_loop_interp_from_face(BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires)
Definition: bmesh_interp.c:682
void BM_data_interp_face_vert_edge(BMesh *bm, const BMVert *v_src_1, const BMVert *UNUSED(v_src_2), BMVert *v, BMEdge *e, const float fac)
Definition: bmesh_interp.c:93
void BM_data_interp_from_verts(BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac)
Data, Interpolate From Verts.
Definition: bmesh_interp.c:68
#define BM_ITER_ELEM(ele, iter, data, itype)
@ BM_FACES_OF_VERT
@ BM_LOOPS_OF_FACE
#define BM_ITER_ELEM_INDEX(ele, iter, data, itype, indexvar)
ATTR_WARN_UNUSED_RESULT BMesh * bm
BMFace * BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
Faces Join Pair.
Definition: bmesh_mods.c:166
void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2)
Definition: bmesh_mods.c:635
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
Definition: bmesh_mods.c:448
BMVert * BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep)
Definition: bmesh_mods.c:901
bool BM_disk_dissolve(BMesh *bm, BMVert *v)
Definition: bmesh_mods.c:51
BMEdge * BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac, const bool do_del, const bool join_faces, const bool kill_degenerate_faces, const bool kill_duplicate_faces)
Vert Collapse Faces.
Definition: bmesh_mods.c:316
bool BM_edge_rotate_check_degenerate(BMEdge *e, BMLoop *l1, BMLoop *l2)
Check if Edge Rotate Gives Degenerate Faces.
Definition: bmesh_mods.c:690
bool BM_vert_dissolve(BMesh *bm, BMVert *v)
Dissolve Vert.
Definition: bmesh_mods.c:20
BMVert * BM_face_loop_separate(BMesh *bm, BMLoop *l_sep)
Rip a single face from a vertex fan.
Definition: bmesh_mods.c:896
bool BM_edge_rotate_check_beauty(BMEdge *e, BMLoop *l1, BMLoop *l2)
Definition: bmesh_mods.c:777
BMEdge * BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces, const bool kill_duplicate_faces)
Vert Collapse Faces.
Definition: bmesh_mods.c:402
BMVert * BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
Split an edge multiple times evenly.
Definition: bmesh_mods.c:563
bool BM_edge_rotate_check(BMEdge *e)
Check if Rotate Edge is OK.
Definition: bmesh_mods.c:661
void BM_edge_verts_swap(BMEdge *e)
Definition: bmesh_mods.c:580
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
BMVert * BM_edge_collapse(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces)
Definition: bmesh_mods.c:442
BMEdge * BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag)
Rotate Edge.
Definition: bmesh_mods.c:785
BMVert * BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len)
Definition: bmesh_mods.c:906
@ BM_EDGEROT_CHECK_EXISTS
Definition: bmesh_mods.h:248
@ BM_EDGEROT_CHECK_BEAUTY
Definition: bmesh_mods.h:254
@ BM_EDGEROT_CHECK_SPLICE
Definition: bmesh_mods.h:250
@ BM_EDGEROT_CHECK_DEGENERATE
Definition: bmesh_mods.h:252
bool BM_face_validate(BMFace *face, FILE *err)
void BM_face_normal_flip(BMesh *bm, BMFace *f)
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
@ _FLAG_OVERLAP
Definition: bmesh_private.h:59
#define BM_ELEM_API_FLAG_DISABLE(element, f)
Definition: bmesh_private.h:71
#define BM_ELEM_API_FLAG_TEST(element, f)
Definition: bmesh_private.h:76
#define BM_ELEM_API_FLAG_ENABLE(element, f)
Definition: bmesh_private.h:66
int bmesh_disk_count(const BMVert *v)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1553
void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2)
Definition: bmesh_query.c:1141
int BM_vert_edge_count_at_most(const BMVert *v, const int count_max)
Definition: bmesh_query.c:612
BMLoop * BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
Other Loop in Face Sharing a Vertex.
Definition: bmesh_query.c:39
bool BM_vert_is_manifold(const BMVert *v)
Definition: bmesh_query.c:705
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
Definition: bmesh_query.c:538
BMLoop * BM_face_edge_share_loop(BMFace *f, BMEdge *e)
Return the Loop Shared by Face and Edge.
Definition: bmesh_query.c:1115
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
Definition: bmesh_query.c:1036
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
Definition: bmesh_query.c:1100
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define BM_vert_face_count_is_equal(v, n)
Definition: bmesh_query.h:255
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
ATTR_WARN_UNUSED_RESULT const BMVert * v
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
SyclQueue void void * src
int len
Definition: draw_manager.c:108
static float verts[][3]
BLI_INLINE float fb(float length, float L)
static char faces[256]
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
return ret
BMHeader head
Definition: bmesh_class.h:111
BMVert * v1
Definition: bmesh_class.h:122
BMVert * v2
Definition: bmesh_class.h:122
struct BMLoop * l
Definition: bmesh_class.h:128
int len
Definition: bmesh_class.h:267
BMHeader head
Definition: bmesh_class.h:255
char hflag
Definition: bmesh_class.h:66
void * data
Definition: bmesh_class.h:51
BMHeader head
Definition: bmesh_class.h:145
struct BMVert * v
Definition: bmesh_class.h:153
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMLoop * radial_next
Definition: bmesh_class.h:204
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
float co[3]
Definition: bmesh_class.h:87
struct BMEdge * e
Definition: bmesh_class.h:97
BMHeader head
Definition: bmesh_class.h:85
BMFace * act_face
Definition: bmesh_class.h:366
CustomData ldata
Definition: bmesh_class.h:337
static FT_Error err