Blender  V2.93
bmesh_mods.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 
24 #include "MEM_guardedalloc.h"
25 
26 #include "BLI_array.h"
27 #include "BLI_math.h"
28 
29 #include "BKE_customdata.h"
30 
31 #include "bmesh.h"
32 #include "intern/bmesh_private.h"
33 
60 {
61  /* logic for 3 or more is identical */
62  const int len = BM_vert_edge_count_at_most(v, 3);
63 
64  if (len == 1) {
65  BM_vert_kill(bm, v); /* will kill edges too */
66  return true;
67  }
68  if (!BM_vert_is_manifold(v)) {
69  if (!v->e) {
70  BM_vert_kill(bm, v);
71  return true;
72  }
73  if (!v->e->l) {
74  if (len == 2) {
75  return (BM_vert_collapse_edge(bm, v->e, v, true, true, true) != NULL);
76  }
77  /* used to kill the vertex here, but it may be connected to faces.
78  * so better do nothing */
79  return false;
80  }
81  return false;
82  }
83  if (len == 2 && BM_vert_face_count_is_equal(v, 1)) {
84  /* boundary vertex on a face */
85  return (BM_vert_collapse_edge(bm, v->e, v, true, true, true) != NULL);
86  }
87  return BM_disk_dissolve(bm, v);
88 }
89 
94 {
95  BMEdge *e, *keepedge = NULL, *baseedge = NULL;
96  int len = 0;
97 
98  if (!BM_vert_is_manifold(v)) {
99  return false;
100  }
101 
102  if (v->e) {
103  /* v->e we keep, what else */
104  e = v->e;
105  do {
107  if (!(BM_edge_share_face_check(e, v->e))) {
108  keepedge = e;
109  baseedge = v->e;
110  break;
111  }
112  len++;
113  } while (e != v->e);
114  }
115 
116  /* this code for handling 2 and 3-valence verts
117  * may be totally bad */
118  if (keepedge == NULL && len == 3) {
119 #if 0
120  /* handle specific case for three-valence. solve it by
121  * increasing valence to four. this may be hackish. . */
122  BMLoop *l_a = BM_face_vert_share_loop(e->l->f, v);
123  BMLoop *l_b = (e->l->v == v) ? e->l->next : e->l;
124 
125  if (!BM_face_split(bm, e->l->f, l_a, l_b, NULL, NULL, false)) {
126  return false;
127  }
128 
129  if (!BM_disk_dissolve(bm, v)) {
130  return false;
131  }
132 #else
133  if (UNLIKELY(!BM_faces_join_pair(bm, e->l, e->l->radial_next, true))) {
134  return false;
135  }
136  if (UNLIKELY(!BM_vert_collapse_faces(bm, v->e, v, 1.0, true, false, true, true))) {
137  return false;
138  }
139 #endif
140  return true;
141  }
142  if (keepedge == NULL && len == 2) {
143  /* collapse the vertex */
144  e = BM_vert_collapse_faces(bm, v->e, v, 1.0, true, true, true, true);
145 
146  if (!e) {
147  return false;
148  }
149 
150  /* handle two-valence */
151  if (e->l != e->l->radial_next) {
152  if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) {
153  return false;
154  }
155  }
156 
157  return true;
158  }
159 
160  if (keepedge) {
161  bool done = false;
162 
163  while (!done) {
164  done = true;
165  e = v->e;
166  do {
167  BMFace *f = NULL;
168  if (BM_edge_is_manifold(e) && (e != baseedge) && (e != keepedge)) {
169  f = BM_faces_join_pair(bm, e->l, e->l->radial_next, true);
170  /* return if couldn't join faces in manifold
171  * conditions */
172  /* !disabled for testing why bad things happen */
173  if (!f) {
174  return false;
175  }
176  }
177 
178  if (f) {
179  done = false;
180  break;
181  }
182  } while ((e = bmesh_disk_edge_next(e, v)) != v->e);
183  }
184 
185  /* collapse the vertex */
186  /* note, the baseedge can be a boundary of manifold, use this as join_faces arg */
188  bm, baseedge, v, 1.0, true, !BM_edge_is_boundary(baseedge), true, true);
189 
190  if (!e) {
191  return false;
192  }
193 
194  if (e->l) {
195  /* get remaining two faces */
196  if (e->l != e->l->radial_next) {
197  /* join two remaining faces */
198  if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) {
199  return false;
200  }
201  }
202  }
203  }
204 
205  return true;
206 }
207 
221 BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
222 {
223  BLI_assert((l_a != l_b) && (l_a->e == l_b->e));
224 
225  if (l_a->v == l_b->v) {
226  const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
227  bmesh_kernel_loop_reverse(bm, l_b->f, cd_loop_mdisp_offset, true);
228  }
229 
230  BMFace *faces[2] = {l_a->f, l_b->f};
231  return BM_faces_join(bm, faces, 2, do_del);
232 }
233 
253  BMFace *f,
254  BMLoop *l_a,
255  BMLoop *l_b,
256  BMLoop **r_l,
257  BMEdge *example,
258  const bool no_double)
259 {
260  const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
261  BMFace *f_new, *f_tmp;
262 
263  BLI_assert(l_a != l_b);
264  BLI_assert(f == l_a->f && f == l_b->f);
266 
267  /* could be an assert */
268  if (UNLIKELY(BM_loop_is_adjacent(l_a, l_b)) || UNLIKELY((f != l_a->f || f != l_b->f))) {
269  if (r_l) {
270  *r_l = NULL;
271  }
272  return NULL;
273  }
274 
275  /* do we have a multires layer? */
276  if (cd_loop_mdisp_offset != -1) {
277  f_tmp = BM_face_copy(bm, bm, f, false, false);
278  }
279 
280 #ifdef USE_BMESH_HOLES
281  f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, r_l, NULL, example, no_double);
282 #else
283  f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, r_l, example, no_double);
284 #endif
285 
286  if (f_new) {
287  /* handle multires update */
288  if (cd_loop_mdisp_offset != -1) {
289  float f_dst_center[3];
290  float f_src_center[3];
291 
292  BM_face_calc_center_median(f_tmp, f_src_center);
293 
294  BM_face_calc_center_median(f, f_dst_center);
295  BM_face_interp_multires_ex(bm, f, f_tmp, f_dst_center, f_src_center, cd_loop_mdisp_offset);
296 
297  BM_face_calc_center_median(f_new, f_dst_center);
299  bm, f_new, f_tmp, f_dst_center, f_src_center, cd_loop_mdisp_offset);
300 
301 #if 0
302  /* BM_face_multires_bounds_smooth doesn't flip displacement correct */
305 #endif
306  }
307  }
308 
309  if (cd_loop_mdisp_offset != -1) {
310  BM_face_kill(bm, f_tmp);
311  }
312 
313  return f_new;
314 }
315 
335  BMFace *f,
336  BMLoop *l_a,
337  BMLoop *l_b,
338  float cos[][3],
339  int n,
340  BMLoop **r_l,
341  BMEdge *example)
342 {
343  BMFace *f_new, *f_tmp;
344  BMLoop *l_new;
345  BMEdge *e, *e_new;
346  BMVert *v_new;
347  // BMVert *v_a = l_a->v; /* UNUSED */
348  BMVert *v_b = l_b->v;
349  int i, j;
350 
351  BLI_assert(l_a != l_b);
352  BLI_assert(f == l_a->f && f == l_b->f);
353  BLI_assert(!((n == 0) && BM_loop_is_adjacent(l_a, l_b)));
354 
355  /* could be an assert */
356  if (UNLIKELY((n == 0) && BM_loop_is_adjacent(l_a, l_b)) || UNLIKELY(l_a->f != l_b->f)) {
357  if (r_l) {
358  *r_l = NULL;
359  }
360  return NULL;
361  }
362 
363  f_tmp = BM_face_copy(bm, bm, f, true, true);
364 
365 #ifdef USE_BMESH_HOLES
366  f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, &l_new, NULL, example, false);
367 #else
368  f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, &l_new, example, false);
369 #endif
370  /* bmesh_kernel_split_face_make_edge returns in 'l_new'
371  * a Loop for f_new going from 'v_a' to 'v_b'.
372  * The radial_next is for 'f' and goes from 'v_b' to 'v_a' */
373 
374  if (f_new) {
375  e = l_new->e;
376  for (i = 0; i < n; i++) {
377  v_new = bmesh_kernel_split_edge_make_vert(bm, v_b, e, &e_new);
378  BLI_assert(v_new != NULL);
379  /* bmesh_kernel_split_edge_make_vert returns in 'e_new'
380  * the edge going from 'v_new' to 'v_b'. */
381  copy_v3_v3(v_new->co, cos[i]);
382 
383  /* interpolate the loop data for the loops with (v == v_new), using orig face */
384  for (j = 0; j < 2; j++) {
385  BMEdge *e_iter = (j == 0) ? e : e_new;
386  BMLoop *l_iter = e_iter->l;
387  do {
388  if (l_iter->v == v_new) {
389  /* this interpolates both loop and vertex data */
390  BM_loop_interp_from_face(bm, l_iter, f_tmp, true, true);
391  }
392  } while ((l_iter = l_iter->radial_next) != e_iter->l);
393  }
394  e = e_new;
395  }
396  }
397 
398  BM_face_verts_kill(bm, f_tmp);
399 
400  if (r_l) {
401  *r_l = l_new;
402  }
403 
404  return f_new;
405 }
406 
431  BMEdge *e_kill,
432  BMVert *v_kill,
433  float fac,
434  const bool do_del,
435  const bool join_faces,
436  const bool kill_degenerate_faces,
437  const bool kill_duplicate_faces)
438 {
439  BMEdge *e_new = NULL;
440  BMVert *tv = BM_edge_other_vert(e_kill, v_kill);
441 
442  BMEdge *e2;
443  BMVert *tv2;
444 
445  /* Only intended to be called for 2-valence vertices */
446  BLI_assert(bmesh_disk_count(v_kill) <= 2);
447 
448  /* first modify the face loop data */
449 
450  if (e_kill->l) {
451  BMLoop *l_iter;
452  const float w[2] = {1.0f - fac, fac};
453 
454  l_iter = e_kill->l;
455  do {
456  if (l_iter->v == tv && l_iter->next->v == v_kill) {
457  const void *src[2];
458  BMLoop *tvloop = l_iter;
459  BMLoop *kvloop = l_iter->next;
460 
461  src[0] = kvloop->head.data;
462  src[1] = tvloop->head.data;
463  CustomData_bmesh_interp(&bm->ldata, src, w, NULL, 2, kvloop->head.data);
464  }
465  } while ((l_iter = l_iter->radial_next) != e_kill->l);
466  }
467 
468  /* now interpolate the vertex data */
469  BM_data_interp_from_verts(bm, v_kill, tv, v_kill, fac);
470 
471  e2 = bmesh_disk_edge_next(e_kill, v_kill);
472  tv2 = BM_edge_other_vert(e2, v_kill);
473 
474  if (join_faces) {
475  BMIter fiter;
476  BMFace **faces = NULL;
477  BMFace *f;
479 
480  BM_ITER_ELEM (f, &fiter, v_kill, BM_FACES_OF_VERT) {
482  }
483 
484  if (BLI_array_len(faces) >= 2) {
486  if (f2) {
487  BMLoop *l_a, *l_b;
488 
489  if ((l_a = BM_face_vert_share_loop(f2, tv)) && (l_b = BM_face_vert_share_loop(f2, tv2))) {
490  BMLoop *l_new;
491 
492  if (BM_face_split(bm, f2, l_a, l_b, &l_new, NULL, false)) {
493  e_new = l_new->e;
494  }
495  }
496  }
497  }
498 
500 
502  }
503  else {
504  /* single face or no faces */
505  /* same as BM_vert_collapse_edge() however we already
506  * have vars to perform this operation so don't call. */
508  bm, e_kill, v_kill, do_del, true, kill_degenerate_faces, kill_duplicate_faces);
509 
510  /* e_new = BM_edge_exists(tv, tv2); */ /* same as return above */
511  }
512 
513  return e_new;
514 }
515 
524  BMEdge *e_kill,
525  BMVert *v_kill,
526  const bool do_del,
527  const bool kill_degenerate_faces,
528  const bool kill_duplicate_faces)
529 {
530  /* nice example implementation but we want loops to have their customdata
531  * accounted for */
532 #if 0
533  BMEdge *e_new = NULL;
534 
535  /* Collapse between 2 edges */
536 
537  /* in this case we want to keep all faces and not join them,
538  * rather just get rid of the vertex - see bug T28645. */
539  BMVert *tv = BM_edge_other_vert(e_kill, v_kill);
540  if (tv) {
541  BMEdge *e2 = bmesh_disk_edge_next(e_kill, v_kill);
542  if (e2) {
543  BMVert *tv2 = BM_edge_other_vert(e2, v_kill);
544  if (tv2) {
545  /* only action, other calls here only get the edge to return */
547  bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
548  }
549  }
550  }
551 
552  return e_new;
553 #else
554  /* with these args faces are never joined, same as above
555  * but account for loop customdata */
556  return BM_vert_collapse_faces(
557  bm, e_kill, v_kill, 1.0f, do_del, false, kill_degenerate_faces, kill_duplicate_faces);
558 #endif
559 }
560 
561 #undef DO_V_INTERP
562 
567  BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces)
568 {
569  return bmesh_kernel_join_vert_kill_edge(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
570 }
571 
591 BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
592 {
593  BMVert *v_new, *v_other;
594  BMEdge *e_new;
595  BMFace **oldfaces = NULL;
596  BLI_array_staticdeclare(oldfaces, 32);
597  const int cd_loop_mdisp_offset = BM_edge_is_wire(e) ?
598  -1 :
600 
601  BLI_assert(BM_vert_in_edge(e, v) == true);
602 
603  /* do we have a multi-res layer? */
604  if (cd_loop_mdisp_offset != -1) {
605  BMLoop *l;
606  int i;
607 
608  l = e->l;
609  do {
610  BLI_array_append(oldfaces, l->f);
611  l = l->radial_next;
612  } while (l != e->l);
613 
614  /* flag existing faces so we can differentiate oldfaces from new faces */
615  for (i = 0; i < BLI_array_len(oldfaces); i++) {
617  oldfaces[i] = BM_face_copy(bm, bm, oldfaces[i], true, true);
619  }
620  }
621 
622  v_other = BM_edge_other_vert(e, v);
623  v_new = bmesh_kernel_split_edge_make_vert(bm, v, e, &e_new);
624  if (r_e != NULL) {
625  *r_e = e_new;
626  }
627 
628  BLI_assert(v_new != NULL);
629  BLI_assert(BM_vert_in_edge(e_new, v) && BM_vert_in_edge(e_new, v_new));
630  BLI_assert(BM_vert_in_edge(e, v_new) && BM_vert_in_edge(e, v_other));
631 
632  sub_v3_v3v3(v_new->co, v_other->co, v->co);
633  madd_v3_v3v3fl(v_new->co, v->co, v_new->co, fac);
634 
635  e_new->head.hflag = e->head.hflag;
636  BM_elem_attrs_copy(bm, bm, e, e_new);
637 
638  /* v->v_new->v2 */
639  BM_data_interp_face_vert_edge(bm, v_other, v, v_new, e, fac);
640  BM_data_interp_from_verts(bm, v, v_other, v_new, fac);
641 
642  if (cd_loop_mdisp_offset != -1) {
643  int i, j;
644 
645  /* interpolate new/changed loop data from copied old faces */
646  for (i = 0; i < BLI_array_len(oldfaces); i++) {
647  float f_center_old[3];
648 
649  BM_face_calc_center_median(oldfaces[i], f_center_old);
650 
651  for (j = 0; j < 2; j++) {
652  BMEdge *e1 = j ? e_new : e;
653  BMLoop *l;
654 
655  l = e1->l;
656 
657  if (UNLIKELY(!l)) {
658  BMESH_ASSERT(0);
659  break;
660  }
661 
662  do {
663  /* check this is an old face */
665  float f_center[3];
666 
667  BM_face_calc_center_median(l->f, f_center);
669  bm, l->f, oldfaces[i], f_center, f_center_old, cd_loop_mdisp_offset);
670  }
671  l = l->radial_next;
672  } while (l != e1->l);
673  }
674  }
675 
676  /* destroy the old faces */
677  for (i = 0; i < BLI_array_len(oldfaces); i++) {
678  BM_face_verts_kill(bm, oldfaces[i]);
679  }
680 
681  /* fix boundaries a bit, doesn't work too well quite yet */
682 #if 0
683  for (j = 0; j < 2; j++) {
684  BMEdge *e1 = j ? e_new : e;
685  BMLoop *l, *l2;
686 
687  l = e1->l;
688  if (UNLIKELY(!l)) {
689  BMESH_ASSERT(0);
690  break;
691  }
692 
693  do {
695  l = l->radial_next;
696  } while (l != e1->l);
697  }
698 #endif
699 
700  BLI_array_free(oldfaces);
701  }
702 
703  return v_new;
704 }
705 
711 BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
712 {
713  int i;
714  float percent;
715  BMVert *v_new = NULL;
716 
717  for (i = 0; i < numcuts; i++) {
718  percent = 1.0f / (float)(numcuts + 1 - i);
719  v_new = BM_edge_split(bm, e, e->v2, NULL, percent);
720  if (r_varr) {
721  /* fill in reverse order (v1 -> v2) */
722  r_varr[numcuts - i - 1] = v_new;
723  }
724  }
725  return v_new;
726 }
727 
734 {
735  SWAP(BMVert *, e->v1, e->v2);
736  SWAP(BMDiskLink, e->v1_disk_link, e->v2_disk_link);
737 }
738 
739 #if 0
743 bool BM_face_validate(BMFace *face, FILE *err)
744 {
745  BMIter iter;
747  BMVert **verts = NULL;
748  BMLoop *l;
749  int i, j;
750  bool ret = true;
751 
752  if (face->len == 2) {
753  fprintf(err, "warning: found two-edged face. face ptr: %p\n", face);
754  fflush(err);
755  }
756 
758  BM_ITER_ELEM_INDEX (l, &iter, face, BM_LOOPS_OF_FACE, i) {
759  verts[i] = l->v;
760  if (l->e->v1 == l->e->v2) {
761  fprintf(err, "Found bmesh edge with identical verts!\n");
762  fprintf(err, " edge ptr: %p, vert: %p\n", l->e, l->e->v1);
763  fflush(err);
764  ret = false;
765  }
766  }
767 
768  for (i = 0; i < face->len; i++) {
769  for (j = 0; j < face->len; j++) {
770  if (j == i) {
771  continue;
772  }
773 
774  if (verts[i] == verts[j]) {
775  fprintf(err, "Found duplicate verts in bmesh face!\n");
776  fprintf(err, " face ptr: %p, vert: %p\n", face, verts[i]);
777  fflush(err);
778  ret = false;
779  }
780  }
781  }
782 
784  return ret;
785 }
786 #endif
787 
802 void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2)
803 {
804  BMVert *v1, *v2;
805  BMFace *fa, *fb;
806 
807  /* this should have already run */
809 
810  /* we know this will work */
811  BM_edge_face_pair(e, &fa, &fb);
812 
813  /* so we can use `ccw` variable correctly,
814  * otherwise we could use the edges verts direct */
816 
817  /* we could swap the verts _or_ the faces, swapping faces
818  * gives more predictable results since that way the next vert
819  * just stitches from face fa / fb */
820  if (!ccw) {
821  SWAP(BMFace *, fa, fb);
822  }
823 
824  *r_l1 = BM_face_other_vert_loop(fb, v2, v1);
825  *r_l2 = BM_face_other_vert_loop(fa, v1, v2);
826 }
827 
835 {
836  BMFace *fa, *fb;
837  if (BM_edge_face_pair(e, &fa, &fb)) {
838  BMLoop *la, *lb;
839 
840  la = BM_face_other_vert_loop(fa, e->v2, e->v1);
841  lb = BM_face_other_vert_loop(fb, e->v2, e->v1);
842 
843  /* check that the next vert in both faces isn't the same
844  * (ie - the next edge doesn't share the same faces).
845  * since we can't rotate usefully in this case. */
846  if (la->v == lb->v) {
847  return false;
848  }
849 
850  /* mirror of the check above but in the opposite direction */
851  la = BM_face_other_vert_loop(fa, e->v1, e->v2);
852  lb = BM_face_other_vert_loop(fb, e->v1, e->v2);
853 
854  if (la->v == lb->v) {
855  return false;
856  }
857 
858  return true;
859  }
860  return false;
861 }
862 
875 {
876  /* note: for these vars 'old' just means initial edge state. */
877 
878  float ed_dir_old[3]; /* edge vector */
879  float ed_dir_new[3]; /* edge vector */
880  float ed_dir_new_flip[3]; /* edge vector */
881 
882  float ed_dir_v1_old[3];
883  float ed_dir_v2_old[3];
884 
885  float ed_dir_v1_new[3];
886  float ed_dir_v2_new[3];
887 
888  float cross_old[3];
889  float cross_new[3];
890 
891  /* original verts - these will be in the edge 'e' */
892  BMVert *v1_old, *v2_old;
893 
894  /* verts from the loops passed */
895 
896  BMVert *v1, *v2;
897  /* These are the opposite verts - the verts that _would_ be used if `ccw` was inverted. */
898  BMVert *v1_alt, *v2_alt;
899 
900  /* this should have already run */
902 
903  BM_edge_ordered_verts(e, &v1_old, &v2_old);
904 
905  v1 = l1->v;
906  v2 = l2->v;
907 
908  /* get the next vert along */
909  v1_alt = BM_face_other_vert_loop(l1->f, v1_old, v1)->v;
910  v2_alt = BM_face_other_vert_loop(l2->f, v2_old, v2)->v;
911 
912  /* normalize all so comparisons are scale independent */
913 
914  BLI_assert(BM_edge_exists(v1_old, v1));
915  BLI_assert(BM_edge_exists(v1, v1_alt));
916 
917  BLI_assert(BM_edge_exists(v2_old, v2));
918  BLI_assert(BM_edge_exists(v2, v2_alt));
919 
920  /* old and new edge vecs */
921  sub_v3_v3v3(ed_dir_old, v1_old->co, v2_old->co);
922  sub_v3_v3v3(ed_dir_new, v1->co, v2->co);
923  normalize_v3(ed_dir_old);
924  normalize_v3(ed_dir_new);
925 
926  /* old edge corner vecs */
927  sub_v3_v3v3(ed_dir_v1_old, v1_old->co, v1->co);
928  sub_v3_v3v3(ed_dir_v2_old, v2_old->co, v2->co);
929  normalize_v3(ed_dir_v1_old);
930  normalize_v3(ed_dir_v2_old);
931 
932  /* old edge corner vecs */
933  sub_v3_v3v3(ed_dir_v1_new, v1->co, v1_alt->co);
934  sub_v3_v3v3(ed_dir_v2_new, v2->co, v2_alt->co);
935  normalize_v3(ed_dir_v1_new);
936  normalize_v3(ed_dir_v2_new);
937 
938  /* compare */
939  cross_v3_v3v3(cross_old, ed_dir_old, ed_dir_v1_old);
940  cross_v3_v3v3(cross_new, ed_dir_new, ed_dir_v1_new);
941  if (dot_v3v3(cross_old, cross_new) < 0.0f) { /* does this flip? */
942  return false;
943  }
944  cross_v3_v3v3(cross_old, ed_dir_old, ed_dir_v2_old);
945  cross_v3_v3v3(cross_new, ed_dir_new, ed_dir_v2_new);
946  if (dot_v3v3(cross_old, cross_new) < 0.0f) { /* does this flip? */
947  return false;
948  }
949 
950  negate_v3_v3(ed_dir_new_flip, ed_dir_new);
951 
952  /* result is zero area corner */
953  if ((dot_v3v3(ed_dir_new, ed_dir_v1_new) > 0.999f) ||
954  (dot_v3v3(ed_dir_new_flip, ed_dir_v2_new) > 0.999f)) {
955  return false;
956  }
957 
958  return true;
959 }
960 
962 {
963  /* Stupid check for now:
964  * Could compare angles of surrounding edges
965  * before & after, but this is OK.*/
966  return (len_squared_v3v3(e->v1->co, e->v2->co) > len_squared_v3v3(l1->v->co, l2->v->co));
967 }
968 
983 BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag)
984 {
985  BMVert *v1, *v2;
986  BMLoop *l1, *l2;
987  BMFace *f;
988  BMEdge *e_new = NULL;
989  char f_active_prev = 0;
990  char f_hflag_prev_1;
991  char f_hflag_prev_2;
992 
993  if (!BM_edge_rotate_check(e)) {
994  return NULL;
995  }
996 
997  BM_edge_calc_rotate(e, ccw, &l1, &l2);
998 
999  /* the loops will be freed so assign verts */
1000  v1 = l1->v;
1001  v2 = l2->v;
1002 
1003  /* --------------------------------------- */
1004  /* Checking Code - make sure we can rotate */
1005 
1006  if (check_flag & BM_EDGEROT_CHECK_BEAUTY) {
1007  if (!BM_edge_rotate_check_beauty(e, l1, l2)) {
1008  return NULL;
1009  }
1010  }
1011 
1012  /* check before applying */
1013  if (check_flag & BM_EDGEROT_CHECK_EXISTS) {
1014  if (BM_edge_exists(v1, v2)) {
1015  return NULL;
1016  }
1017  }
1018 
1019  /* slowest, check last */
1020  if (check_flag & BM_EDGEROT_CHECK_DEGENERATE) {
1021  if (!BM_edge_rotate_check_degenerate(e, l1, l2)) {
1022  return NULL;
1023  }
1024  }
1025  /* Done Checking */
1026  /* ------------- */
1027 
1028  /* --------------- */
1029  /* Rotate The Edge */
1030 
1031  /* first create the new edge, this is so we can copy the customdata from the old one
1032  * if splice if disabled, always add in a new edge even if there's one there. */
1033  e_new = BM_edge_create(
1035 
1036  f_hflag_prev_1 = l1->f->head.hflag;
1037  f_hflag_prev_2 = l2->f->head.hflag;
1038 
1039  /* maintain active face */
1040  if (bm->act_face == l1->f) {
1041  f_active_prev = 1;
1042  }
1043  else if (bm->act_face == l2->f) {
1044  f_active_prev = 2;
1045  }
1046 
1047  const bool is_flipped = !BM_edge_is_contiguous(e);
1048 
1049  /* don't delete the edge, manually remove the edge after so we can copy its attributes */
1050  f = BM_faces_join_pair(
1051  bm, BM_face_edge_share_loop(l1->f, e), BM_face_edge_share_loop(l2->f, e), true);
1052 
1053  if (f == NULL) {
1054  return NULL;
1055  }
1056 
1057  /* note, this assumes joining the faces _didnt_ also remove the verts.
1058  * the #BM_edge_rotate_check will ensure this, but its possibly corrupt state or future edits
1059  * break this */
1060  if ((l1 = BM_face_vert_share_loop(f, v1)) && (l2 = BM_face_vert_share_loop(f, v2)) &&
1061  BM_face_split(bm, f, l1, l2, NULL, NULL, true)) {
1062  /* we should really be able to know the faces some other way,
1063  * rather than fetching them back from the edge, but this is predictable
1064  * where using the return values from face split isn't. - campbell */
1065  BMFace *fa, *fb;
1066  if (BM_edge_face_pair(e_new, &fa, &fb)) {
1067  fa->head.hflag = f_hflag_prev_1;
1068  fb->head.hflag = f_hflag_prev_2;
1069 
1070  if (f_active_prev == 1) {
1071  bm->act_face = fa;
1072  }
1073  else if (f_active_prev == 2) {
1074  bm->act_face = fb;
1075  }
1076 
1077  if (is_flipped) {
1079 
1080  if (ccw) {
1081  /* Needed otherwise `ccw` toggles direction */
1082  e_new->l = e_new->l->radial_next;
1083  }
1084  }
1085  }
1086  }
1087  else {
1088  return NULL;
1089  }
1090 
1091  return e_new;
1092 }
1093 
1098 {
1100 }
1101 
1103 {
1105 }
1106 
1108 {
1109  return bmesh_kernel_unglue_region_make_vert_multi(bm, larr, larr_len);
1110 }
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.c:4048
A (mainly) macro array library.
#define BLI_array_grow_items(arr, num)
Definition: BLI_array.h:99
#define BLI_array_append(arr, item)
Definition: BLI_array.h:104
#define BLI_array_staticdeclare(arr, maxstatic)
Definition: BLI_array.h:69
#define BLI_array_declare(arr)
Definition: BLI_array.h:62
#define BLI_array_len(arr)
Definition: BLI_array.h:74
#define BLI_array_free(arr)
Definition: BLI_array.h:116
#define BLI_assert(a)
Definition: BLI_assert.h:58
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:576
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:1209
void BM_face_verts_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:861
BMVert * bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep)
Definition: bmesh_core.c:2938
void BM_vert_kill(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:1002
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:1463
void BM_face_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:881
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
BMVert * bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
Un-glue Region Make Vert (URMV)
Definition: bmesh_core.c:2685
BMVert * bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len)
Definition: bmesh_core.c:2754
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:1037
BMFace * BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, const bool copy_verts, const bool copy_edges)
Definition: bmesh_core.c:303
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:1620
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:1988
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:147
@ BM_CREATE_NOP
Definition: bmesh_core.h:27
@ BM_CREATE_NO_DOUBLE
Definition: bmesh_core.h:29
#define BMESH_ASSERT(a)
Definition: bmesh_error.h:76
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:591
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
Definition: bmesh_interp.c:625
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:737
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)
Data Face-Vert Edge Interp.
Definition: bmesh_interp.c:129
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, Interp From Verts.
Definition: bmesh_interp.c:91
#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:221
void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2)
Definition: bmesh_mods.c:802
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
Definition: bmesh_mods.c:591
BMVert * BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep)
Definition: bmesh_mods.c:1102
bool BM_disk_dissolve(BMesh *bm, BMVert *v)
Definition: bmesh_mods.c:93
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:430
bool BM_edge_rotate_check_degenerate(BMEdge *e, BMLoop *l1, BMLoop *l2)
Check if Edge Rotate Gives Degenerate Faces.
Definition: bmesh_mods.c:874
bool BM_vert_dissolve(BMesh *bm, BMVert *v)
Dissolve Vert.
Definition: bmesh_mods.c:59
BMVert * BM_face_loop_separate(BMesh *bm, BMLoop *l_sep)
Rip a single face from a vertex fan.
Definition: bmesh_mods.c:1097
bool BM_edge_rotate_check_beauty(BMEdge *e, BMLoop *l1, BMLoop *l2)
Definition: bmesh_mods.c:961
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:523
BMVert * BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
Split an edge multiple times evenly.
Definition: bmesh_mods.c:711
bool BM_edge_rotate_check(BMEdge *e)
Check if Rotate Edge is OK.
Definition: bmesh_mods.c:834
void BM_edge_verts_swap(BMEdge *e)
Definition: bmesh_mods.c:733
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
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:566
BMEdge * BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag)
Rotate Edge.
Definition: bmesh_mods.c:983
BMVert * BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len)
Definition: bmesh_mods.c:1107
bool BM_face_validate(BMFace *face, FILE *err)
@ BM_EDGEROT_CHECK_EXISTS
Definition: bmesh_mods.h:86
@ BM_EDGEROT_CHECK_BEAUTY
Definition: bmesh_mods.h:92
@ BM_EDGEROT_CHECK_SPLICE
Definition: bmesh_mods.h:88
@ BM_EDGEROT_CHECK_DEGENERATE
Definition: bmesh_mods.h:90
void BM_face_normal_flip(BMesh *bm, BMFace *f)
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
#define BM_ELEM_API_FLAG_DISABLE(element, f)
Definition: bmesh_private.h:76
#define BM_ELEM_API_FLAG_TEST(element, f)
Definition: bmesh_private.h:81
@ _FLAG_OVERLAP
Definition: bmesh_private.h:64
#define BM_ELEM_API_FLAG_ENABLE(element, f)
Definition: bmesh_private.h:71
int bmesh_disk_count(const BMVert *v)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1995
void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2)
Definition: bmesh_query.c:1464
int BM_vert_edge_count_at_most(const BMVert *v, const int count_max)
Definition: bmesh_query.c:827
BMLoop * BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
Other Loop in Face Sharing a Vertex.
Definition: bmesh_query.c:97
bool BM_vert_is_manifold(const BMVert *v)
Definition: bmesh_query.c:943
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
Definition: bmesh_query.c:732
BMLoop * BM_face_edge_share_loop(BMFace *f, BMEdge *e)
Return the Loop Shared by Face and Edge.
Definition: bmesh_query.c:1426
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
Definition: bmesh_query.c:1314
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
Definition: bmesh_query.c:1403
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:101
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
static FT_Error err
Definition: freetypefont.c:52
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:123
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
struct BMLoop * l
Definition: bmesh_class.h:140
int len
Definition: bmesh_class.h:279
BMHeader head
Definition: bmesh_class.h:267
char hflag
Definition: bmesh_class.h:78
void * data
Definition: bmesh_class.h:63
BMHeader head
Definition: bmesh_class.h:157
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109
BMHeader head
Definition: bmesh_class.h:97
BMFace * act_face
Definition: bmesh_class.h:366
CustomData ldata
Definition: bmesh_class.h:337
uint len