Blender  V2.93
bmesh_edgeloop.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  * The Original Code is Copyright (C) 2013 by Campbell Barton.
17  * All rights reserved.
18  */
19 
26 #include "MEM_guardedalloc.h"
27 
28 #include "BLI_listbase.h"
29 #include "BLI_math_vector.h"
30 #include "BLI_mempool.h"
31 #include "BLI_stack.h"
32 #include "BLI_utildefines_iter.h"
33 
34 #include "bmesh.h"
35 
36 #include "bmesh_edgeloop.h" /* own include */
37 
38 typedef struct BMEdgeLoopStore {
41  int flag;
42  int len;
43  /* optional values to calc */
44  float co[3], no[3];
46 
47 #define BM_EDGELOOP_IS_CLOSED (1 << 0)
48 
49 /* Use a small value since we need normals even for very small loops. */
50 #define EDGELOOP_EPS 1e-10f
51 
52 /* -------------------------------------------------------------------- */
53 /* BM_mesh_edgeloops_find & Util Functions */
54 
55 static int bm_vert_other_tag(BMVert *v, BMVert *v_prev, BMEdge **r_e)
56 {
57  BMIter iter;
58  BMEdge *e, *e_next = NULL;
59  uint count = 0;
60 
61  BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
63  BMVert *v_other = BM_edge_other_vert(e, v);
64  if (v_other != v_prev) {
65  e_next = e;
66  count++;
67  }
68  }
69  }
70 
71  *r_e = e_next;
72  return count;
73 }
74 
78 static bool bm_loop_build(BMEdgeLoopStore *el_store, BMVert *v_prev, BMVert *v, int dir)
79 {
80  void (*add_fn)(ListBase *, void *) = dir == 1 ? BLI_addhead : BLI_addtail;
81  BMEdge *e_next;
82  BMVert *v_next;
83  BMVert *v_first = v;
84 
85  BLI_assert(abs(dir) == 1);
86 
88  return true;
89  }
90 
91  while (v) {
92  LinkData *node = MEM_callocN(sizeof(*node), __func__);
93  int count;
94  node->data = v;
95  add_fn(&el_store->verts, node);
96  el_store->len++;
98 
99  count = bm_vert_other_tag(v, v_prev, &e_next);
100  if (count == 1) {
101  v_next = BM_edge_other_vert(e_next, v);
103  if (UNLIKELY(v_next == v_first)) {
104  el_store->flag |= BM_EDGELOOP_IS_CLOSED;
105  v_next = NULL;
106  }
107  }
108  else if (count == 0) {
109  /* pass */
110  v_next = NULL;
111  }
112  else {
113  v_next = NULL;
114  return false;
115  }
116 
117  v_prev = v;
118  v = v_next;
119  }
120 
121  return true;
122 }
123 
128  ListBase *r_eloops,
129  bool (*test_fn)(BMEdge *, void *user_data),
130  void *user_data)
131 {
132  BMIter iter;
133  BMEdge *e;
134  BMVert *v;
135  int count = 0;
136 
137  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
139  }
140 
141  /* first flush edges to tags, and tag verts */
142  BLI_Stack *edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
143  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
145  if (test_fn(e, user_data)) {
149  BLI_stack_push(edge_stack, (void *)&e);
150  }
151  else {
153  }
154  }
155 
156  const uint edges_len = BLI_stack_count(edge_stack);
157  BMEdge **edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__);
158  BLI_stack_pop_n_reverse(edge_stack, edges, BLI_stack_count(edge_stack));
159  BLI_stack_free(edge_stack);
160 
161  for (uint i = 0; i < edges_len; i += 1) {
162  e = edges[i];
164  BMEdgeLoopStore *el_store = MEM_callocN(sizeof(BMEdgeLoopStore), __func__);
165 
166  /* add both directions */
167  if (bm_loop_build(el_store, e->v1, e->v2, 1) && bm_loop_build(el_store, e->v2, e->v1, -1) &&
168  el_store->len > 1) {
169  BLI_addtail(r_eloops, el_store);
170  count++;
171  }
172  else {
173  BM_edgeloop_free(el_store);
174  }
175  }
176  }
177 
178  for (uint i = 0; i < edges_len; i += 1) {
179  e = edges[i];
183  }
184 
185  MEM_freeN(edges);
186  return count;
187 }
188 
189 /* -------------------------------------------------------------------- */
190 /* BM_mesh_edgeloops_find_path & Util Functions */
191 
196 struct VertStep {
197  struct VertStep *next, *prev;
199 };
200 
201 static void vs_add(
202  BLI_mempool *vs_pool, ListBase *lb, BMVert *v, BMEdge *e_prev, const int iter_tot)
203 {
204  struct VertStep *vs_new = BLI_mempool_alloc(vs_pool);
205  vs_new->v = v;
206 
207  BM_elem_index_set(v, iter_tot); /* set_dirty */
208 
209  /* This edge stores a direct path back to the original vertex so we can
210  * backtrack without having to store an array of previous verts. */
211 
212  /* WARNING - setting the edge is not common practice
213  * but currently harmless, take care. */
214  BLI_assert(BM_vert_in_edge(e_prev, v));
215  v->e = e_prev;
216 
217  BLI_addtail(lb, vs_new);
218 }
219 
221  ListBase *lb,
222  const int dir,
223  BMVert *v_match[2])
224 {
225  ListBase lb_tmp = {NULL, NULL};
226  struct VertStep *vs, *vs_next;
227  BLI_assert(abs(dir) == 1);
228 
229  for (vs = lb->first; vs; vs = vs_next) {
230  BMIter iter;
231  BMEdge *e;
232  /* these values will be the same every iteration */
233  const int vs_iter_tot = BM_elem_index_get(vs->v);
234  const int vs_iter_next = vs_iter_tot + dir;
235 
236  vs_next = vs->next;
237 
238  BM_ITER_ELEM (e, &iter, vs->v, BM_EDGES_OF_VERT) {
240  BMVert *v_next = BM_edge_other_vert(e, vs->v);
241  const int v_next_index = BM_elem_index_get(v_next);
242  /* not essential to clear flag but prevents more checking next time round */
244  if (v_next_index == 0) {
245  vs_add(vs_pool, &lb_tmp, v_next, e, vs_iter_next);
246  }
247  else if ((dir < 0) == (v_next_index < 0)) {
248  /* on the same side - do nothing */
249  }
250  else {
251  /* we have met out match! (vertices from different sides meet) */
252  if (dir == 1) {
253  v_match[0] = vs->v;
254  v_match[1] = v_next;
255  }
256  else {
257  v_match[0] = v_next;
258  v_match[1] = vs->v;
259  }
260  /* normally we would manage memory of remaining items in (lb, lb_tmp),
261  * but search is done, vs_pool will get destroyed immediately */
262  return true;
263  }
264  }
265  }
266 
267  BLI_mempool_free(vs_pool, vs);
268  }
269 
270  /* Commented because used in a loop, and this flag has already been set. */
271  /* bm->elem_index_dirty |= BM_VERT; */
272 
273  /* lb is now full of free'd items, overwrite */
274  *lb = lb_tmp;
275 
276  return (BLI_listbase_is_empty(lb) == false);
277 }
278 
280  ListBase *r_eloops,
281  bool (*test_fn)(BMEdge *, void *user_data),
282  void *user_data,
283  BMVert *v_src,
284  BMVert *v_dst)
285 {
286  BMIter iter;
287  BMEdge *e;
288  bool found = false;
289 
290  BLI_assert(v_src != v_dst);
291 
292  {
293  BMVert *v;
294  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
295  BM_elem_index_set(v, 0);
297  }
298  }
300 
301  /* first flush edges to tags, and tag verts */
302  int edges_len;
303  BMEdge **edges;
304 
305  if (test_fn) {
306  BLI_Stack *edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
307  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
308  if (test_fn(e, user_data)) {
312  BLI_stack_push(edge_stack, (void *)&e);
313  }
314  else {
316  }
317  }
318  edges_len = BLI_stack_count(edge_stack);
319  edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__);
320  BLI_stack_pop_n_reverse(edge_stack, edges, BLI_stack_count(edge_stack));
321  BLI_stack_free(edge_stack);
322  }
323  else {
324  int i = 0;
325  edges_len = bm->totedge;
326  edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__);
327 
328  BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
332  edges[i] = e;
333  }
334  }
335 
336  /* prime the lists and begin search */
337  {
338  BMVert *v_match[2] = {NULL, NULL};
339  ListBase lb_src = {NULL, NULL};
340  ListBase lb_dst = {NULL, NULL};
341  BLI_mempool *vs_pool = BLI_mempool_create(sizeof(struct VertStep), 0, 512, BLI_MEMPOOL_NOP);
342 
343  /* edge args are dummy */
344  vs_add(vs_pool, &lb_src, v_src, v_src->e, 1);
345  vs_add(vs_pool, &lb_dst, v_dst, v_dst->e, -1);
347 
348  do {
349  if ((bm_loop_path_build_step(vs_pool, &lb_src, 1, v_match) == false) || v_match[0]) {
350  break;
351  }
352  if ((bm_loop_path_build_step(vs_pool, &lb_dst, -1, v_match) == false) || v_match[0]) {
353  break;
354  }
355  } while (true);
356 
357  BLI_mempool_destroy(vs_pool);
358 
359  if (v_match[0]) {
360  BMEdgeLoopStore *el_store = MEM_callocN(sizeof(BMEdgeLoopStore), __func__);
361  BMVert *v;
362 
363  /* build loop from edge pointers */
364  v = v_match[0];
365  while (true) {
366  LinkData *node = MEM_callocN(sizeof(*node), __func__);
367  node->data = v;
368  BLI_addhead(&el_store->verts, node);
369  el_store->len++;
370  if (v == v_src) {
371  break;
372  }
373  v = BM_edge_other_vert(v->e, v);
374  }
375 
376  v = v_match[1];
377  while (true) {
378  LinkData *node = MEM_callocN(sizeof(*node), __func__);
379  node->data = v;
380  BLI_addtail(&el_store->verts, node);
381  el_store->len++;
382  if (v == v_dst) {
383  break;
384  }
385  v = BM_edge_other_vert(v->e, v);
386  }
387 
388  BLI_addtail(r_eloops, el_store);
389 
390  found = true;
391  }
392  }
393 
394  for (uint i = 0; i < edges_len; i += 1) {
395  e = edges[i];
399  }
400  MEM_freeN(edges);
401 
402  return found;
403 }
404 
405 /* -------------------------------------------------------------------- */
406 /* BM_mesh_edgeloops_xxx utility function */
407 
409 {
410  BMEdgeLoopStore *el_store;
411  while ((el_store = BLI_pophead(eloops))) {
412  BM_edgeloop_free(el_store);
413  }
414 }
415 
417 {
418  BMEdgeLoopStore *el_store;
419  for (el_store = eloops->first; el_store; el_store = el_store->next) {
420  BM_edgeloop_calc_center(bm, el_store);
421  }
422 }
423 
425 {
426  BMEdgeLoopStore *el_store;
427  for (el_store = eloops->first; el_store; el_store = el_store->next) {
428  BM_edgeloop_calc_normal(bm, el_store);
429  }
430 }
431 
432 void BM_mesh_edgeloops_calc_normal_aligned(BMesh *bm, ListBase *eloops, const float no_align[3])
433 {
434  BMEdgeLoopStore *el_store;
435  for (el_store = eloops->first; el_store; el_store = el_store->next) {
436  BM_edgeloop_calc_normal_aligned(bm, el_store, no_align);
437  }
438 }
439 
440 void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const bool use_normals)
441 {
442  ListBase eloops_ordered = {NULL};
443  BMEdgeLoopStore *el_store;
444  float cent[3];
445  int tot = 0;
446  zero_v3(cent);
447  /* assumes we calculated centers already */
448  for (el_store = eloops->first; el_store; el_store = el_store->next, tot++) {
449  add_v3_v3(cent, el_store->co);
450  }
451  mul_v3_fl(cent, 1.0f / (float)tot);
452 
453  /* Find the furthest out loop. */
454  {
455  BMEdgeLoopStore *el_store_best = NULL;
456  float len_best_sq = -1.0f;
457  for (el_store = eloops->first; el_store; el_store = el_store->next) {
458  const float len_sq = len_squared_v3v3(cent, el_store->co);
459  if (len_sq > len_best_sq) {
460  len_best_sq = len_sq;
461  el_store_best = el_store;
462  }
463  }
464 
465  BLI_remlink(eloops, el_store_best);
466  BLI_addtail(&eloops_ordered, el_store_best);
467  }
468 
469  /* not so efficient re-ordering */
470  while (eloops->first) {
471  BMEdgeLoopStore *el_store_best = NULL;
472  const float *co = ((BMEdgeLoopStore *)eloops_ordered.last)->co;
473  const float *no = ((BMEdgeLoopStore *)eloops_ordered.last)->no;
474  float len_best_sq = FLT_MAX;
475 
476  if (use_normals) {
477  BLI_ASSERT_UNIT_V3(no);
478  }
479 
480  for (el_store = eloops->first; el_store; el_store = el_store->next) {
481  float len_sq;
482  if (use_normals) {
483  /* scale the length by how close the loops are to pointing at eachother */
484  float dir[3];
485  sub_v3_v3v3(dir, co, el_store->co);
486  len_sq = normalize_v3(dir);
487  len_sq = len_sq *
488  ((1.0f - fabsf(dot_v3v3(dir, no))) + (1.0f - fabsf(dot_v3v3(dir, el_store->no))));
489  }
490  else {
491  len_sq = len_squared_v3v3(co, el_store->co);
492  }
493 
494  if (len_sq < len_best_sq) {
495  len_best_sq = len_sq;
496  el_store_best = el_store;
497  }
498  }
499 
500  BLI_remlink(eloops, el_store_best);
501  BLI_addtail(&eloops_ordered, el_store_best);
502  }
503 
504  *eloops = eloops_ordered;
505 }
506 
507 /* -------------------------------------------------------------------- */
508 /* BM_edgeloop_*** functions */
509 
510 /* return new edgeloops */
512 {
513  BMEdgeLoopStore *el_store_copy = MEM_mallocN(sizeof(*el_store), __func__);
514  *el_store_copy = *el_store;
515  BLI_duplicatelist(&el_store_copy->verts, &el_store->verts);
516  return el_store_copy;
517 }
518 
519 BMEdgeLoopStore *BM_edgeloop_from_verts(BMVert **v_arr, const int v_arr_tot, bool is_closed)
520 {
521  BMEdgeLoopStore *el_store = MEM_callocN(sizeof(*el_store), __func__);
522  int i;
523  for (i = 0; i < v_arr_tot; i++) {
524  LinkData *node = MEM_callocN(sizeof(*node), __func__);
525  node->data = v_arr[i];
526  BLI_addtail(&el_store->verts, node);
527  }
528  el_store->len = v_arr_tot;
529  if (is_closed) {
530  el_store->flag |= BM_EDGELOOP_IS_CLOSED;
531  }
532  return el_store;
533 }
534 
536 {
537  BLI_freelistN(&el_store->verts);
538  MEM_freeN(el_store);
539 }
540 
542 {
543  return (el_store->flag & BM_EDGELOOP_IS_CLOSED) != 0;
544 }
545 
547 {
548  return &el_store->verts;
549 }
550 
552 {
553  return el_store->len;
554 }
555 
556 const float *BM_edgeloop_normal_get(struct BMEdgeLoopStore *el_store)
557 {
558  return el_store->no;
559 }
560 
561 const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store)
562 {
563  return el_store->co;
564 }
565 
566 #define NODE_AS_V(n) ((BMVert *)((LinkData *)n)->data)
567 #define NODE_AS_CO(n) ((BMVert *)((LinkData *)n)->data)->co
568 
572 void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr)
573 {
574  LinkData *node;
575  int i = 0;
576  for (node = el_store->verts.first; node && node->next; node = node->next) {
577  e_arr[i++] = BM_edge_exists(NODE_AS_V(node), NODE_AS_V(node->next));
578  BLI_assert(e_arr[i - 1] != NULL);
579  }
580 
581  if (el_store->flag & BM_EDGELOOP_IS_CLOSED) {
582  e_arr[i] = BM_edge_exists(NODE_AS_V(el_store->verts.first), NODE_AS_V(el_store->verts.last));
583  BLI_assert(e_arr[i] != NULL);
584  }
585  BLI_assert(el_store->len == i + 1);
586 }
587 
589 {
590  LinkData *node_curr = el_store->verts.last;
591  LinkData *node_prev = ((LinkData *)el_store->verts.last)->prev;
592  LinkData *node_first = el_store->verts.first;
593  LinkData *node_next = node_first;
594 
595  const float *v_prev = NODE_AS_CO(node_prev);
596  const float *v_curr = NODE_AS_CO(node_curr);
597  const float *v_next = NODE_AS_CO(node_next);
598 
599  float totw = 0.0f;
600  float w_prev;
601 
602  zero_v3(el_store->co);
603 
604  w_prev = len_v3v3(v_prev, v_curr);
605  do {
606  const float w_curr = len_v3v3(v_curr, v_next);
607  const float w = (w_curr + w_prev);
608  madd_v3_v3fl(el_store->co, v_curr, w);
609  totw += w;
610  w_prev = w_curr;
611 
612  node_prev = node_curr;
613  node_curr = node_next;
614  node_next = node_next->next;
615 
616  if (node_next == NULL) {
617  break;
618  }
619  v_prev = v_curr;
620  v_curr = v_next;
621  v_next = NODE_AS_CO(node_next);
622  } while (1);
623 
624  if (totw != 0.0f) {
625  mul_v3_fl(el_store->co, 1.0f / (float)totw);
626  }
627 }
628 
630 {
631  LinkData *node_curr = el_store->verts.first;
632  const float *v_prev = NODE_AS_CO(el_store->verts.last);
633  const float *v_curr = NODE_AS_CO(node_curr);
634 
635  zero_v3(el_store->no);
636 
637  /* Newell's Method */
638  do {
639  add_newell_cross_v3_v3v3(el_store->no, v_prev, v_curr);
640 
641  if ((node_curr = node_curr->next)) {
642  v_prev = v_curr;
643  v_curr = NODE_AS_CO(node_curr);
644  }
645  else {
646  break;
647  }
648  } while (true);
649 
650  if (UNLIKELY(normalize_v3(el_store->no) < EDGELOOP_EPS)) {
651  el_store->no[2] = 1.0f; /* other axis set to 0.0 */
652  return false;
653  }
654  return true;
655 }
656 
664  BMEdgeLoopStore *el_store,
665  const float no_align[3])
666 {
667  LinkData *node_curr = el_store->verts.first;
668  const float *v_prev = NODE_AS_CO(el_store->verts.last);
669  const float *v_curr = NODE_AS_CO(node_curr);
670 
671  zero_v3(el_store->no);
672 
673  /* Own Method */
674  do {
675  float cross[3], no[3], dir[3];
676  sub_v3_v3v3(dir, v_curr, v_prev);
677  cross_v3_v3v3(cross, no_align, dir);
678  cross_v3_v3v3(no, dir, cross);
679  add_v3_v3(el_store->no, no);
680 
681  if ((node_curr = node_curr->next)) {
682  v_prev = v_curr;
683  v_curr = NODE_AS_CO(node_curr);
684  }
685  else {
686  break;
687  }
688  } while (true);
689 
690  if (UNLIKELY(normalize_v3(el_store->no) < EDGELOOP_EPS)) {
691  el_store->no[2] = 1.0f; /* other axis set to 0.0 */
692  return false;
693  }
694  return true;
695 }
696 
698 {
699  negate_v3(el_store->no);
700  BLI_listbase_reverse(&el_store->verts);
701 }
702 
704  BMesh *bm, BMEdgeLoopStore *el_store, int el_store_len, bool split, GSet *split_edges)
705 {
706  bool split_swap = true;
707 
708 #define EDGE_SPLIT(node_copy, node_other) \
709  { \
710  BMVert *v_split, *v_other = (node_other)->data; \
711  BMEdge *e_split, *e_other = BM_edge_exists((node_copy)->data, v_other); \
712  v_split = BM_edge_split( \
713  bm, e_other, split_swap ? (node_copy)->data : v_other, &e_split, 0.0f); \
714  v_split->e = e_split; \
715  BLI_assert(v_split == e_split->v2); \
716  BLI_gset_insert(split_edges, e_split); \
717  (node_copy)->data = v_split; \
718  } \
719  ((void)0)
720 
721  /* first double until we are more than half as big */
722  while ((el_store->len * 2) < el_store_len) {
723  LinkData *node_curr = el_store->verts.first;
724  while (node_curr) {
725  LinkData *node_curr_copy = MEM_dupallocN(node_curr);
726  if (split == false) {
727  BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
728  node_curr = node_curr_copy->next;
729  }
730  else {
731  if (node_curr->next || (el_store->flag & BM_EDGELOOP_IS_CLOSED)) {
732  EDGE_SPLIT(node_curr_copy,
733  node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first);
734  BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
735  node_curr = node_curr_copy->next;
736  }
737  else {
738  EDGE_SPLIT(node_curr_copy, node_curr->prev);
739  BLI_insertlinkbefore(&el_store->verts, node_curr, node_curr_copy);
740  node_curr = node_curr->next;
741  }
742  split_swap = !split_swap;
743  }
744  el_store->len++;
745  }
746  split_swap = !split_swap;
747  }
748 
749  if (el_store->len < el_store_len) {
750  LinkData *node_curr = el_store->verts.first;
751 
752  int iter_prev = 0;
753  BLI_FOREACH_SPARSE_RANGE (el_store->len, (el_store_len - el_store->len), iter) {
754  while (iter_prev < iter) {
755  node_curr = node_curr->next;
756  iter_prev += 1;
757  }
758 
759  LinkData *node_curr_copy;
760  node_curr_copy = MEM_dupallocN(node_curr);
761  if (split == false) {
762  BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
763  node_curr = node_curr_copy->next;
764  }
765  else {
766  if (node_curr->next || (el_store->flag & BM_EDGELOOP_IS_CLOSED)) {
767  EDGE_SPLIT(node_curr_copy,
768  node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first);
769  BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
770  node_curr = node_curr_copy->next;
771  }
772  else {
773  EDGE_SPLIT(node_curr_copy, node_curr->prev);
774  BLI_insertlinkbefore(&el_store->verts, node_curr, node_curr_copy);
775  node_curr = node_curr->next;
776  }
777  split_swap = !split_swap;
778  }
779  el_store->len++;
780  iter_prev += 1;
781  }
782  }
783 
784 #undef BKE_FOREACH_SUBSET_OF_RANGE
785 #undef EDGE_SPLIT
786 
787  BLI_assert(el_store->len == el_store_len);
788 }
789 
791  struct BMEdgeLoopStore *el_store_b)
792 {
793  LinkData *node;
794 
795  /* A little more efficient if 'a' as smaller. */
796  if (el_store_a->len > el_store_b->len) {
797  SWAP(BMEdgeLoopStore *, el_store_a, el_store_b);
798  }
799 
800  /* init */
801  for (node = el_store_a->verts.first; node; node = node->next) {
803  }
804  for (node = el_store_b->verts.first; node; node = node->next) {
806  }
807 
808  /* Check 'a' (clear as we go). */
809  for (node = el_store_a->verts.first; node; node = node->next) {
811  /* Finish clearing 'a', leave tag clean. */
812  while ((node = node->next)) {
814  }
815  return true;
816  }
818  }
819  return false;
820 }
#define BLI_assert(a)
Definition: BLI_assert.h:58
struct GSet GSet
Definition: BLI_ghash.h:189
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:257
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:87
void void void void void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:352
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:395
void void void void void void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1)
Definition: listbase.c:871
#define BLI_ASSERT_UNIT_V3(v)
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
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 add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
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 negate_v3(float r[3])
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
@ BLI_MEMPOOL_NOP
Definition: BLI_mempool.h:77
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int totelem, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_mempool.c:268
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_mempool.c:334
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:757
void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL()
Definition: stack.c:208
size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: stack.c:285
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL()
Definition: stack.c:163
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition: stack.c:114
#define BLI_stack_new(esize, descr)
unsigned int uint
Definition: BLI_sys_types.h:83
#define SWAP(type, a, b)
#define UNUSED(x)
#define UNLIKELY(x)
#define BLI_FOREACH_SPARSE_RANGE(src, dst, i)
Read Guarded memory(de)allocation.
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_ELEM_INTERNAL_TAG
Definition: bmesh_class.h:496
#define BM_EDGELOOP_IS_CLOSED
BMEdgeLoopStore * BM_edgeloop_copy(BMEdgeLoopStore *el_store)
struct BMEdgeLoopStore BMEdgeLoopStore
const float * BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store)
static bool bm_loop_path_build_step(BLI_mempool *vs_pool, ListBase *lb, const int dir, BMVert *v_match[2])
#define NODE_AS_CO(n)
void BM_edgeloop_expand(BMesh *bm, BMEdgeLoopStore *el_store, int el_store_len, bool split, GSet *split_edges)
void BM_mesh_edgeloops_free(ListBase *eloops)
void BM_edgeloop_free(BMEdgeLoopStore *el_store)
BMEdgeLoopStore * BM_edgeloop_from_verts(BMVert **v_arr, const int v_arr_tot, bool is_closed)
int BM_mesh_edgeloops_find(BMesh *bm, ListBase *r_eloops, bool(*test_fn)(BMEdge *, void *user_data), void *user_data)
#define NODE_AS_V(n)
bool BM_mesh_edgeloops_find_path(BMesh *bm, ListBase *r_eloops, bool(*test_fn)(BMEdge *, void *user_data), void *user_data, BMVert *v_src, BMVert *v_dst)
#define EDGELOOP_EPS
int BM_edgeloop_length_get(BMEdgeLoopStore *el_store)
void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const bool use_normals)
static bool bm_loop_build(BMEdgeLoopStore *el_store, BMVert *v_prev, BMVert *v, int dir)
bool BM_edgeloop_is_closed(BMEdgeLoopStore *el_store)
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr)
ListBase * BM_edgeloop_verts_get(BMEdgeLoopStore *el_store)
void BM_mesh_edgeloops_calc_normal_aligned(BMesh *bm, ListBase *eloops, const float no_align[3])
static int bm_vert_other_tag(BMVert *v, BMVert *v_prev, BMEdge **r_e)
bool BM_edgeloop_calc_normal(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
bool BM_edgeloop_overlap_check(struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b)
bool BM_edgeloop_calc_normal_aligned(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store, const float no_align[3])
const float * BM_edgeloop_normal_get(struct BMEdgeLoopStore *el_store)
void BM_edgeloop_flip(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
static void vs_add(BLI_mempool *vs_pool, ListBase *lb, BMVert *v, BMEdge *e_prev, const int iter_tot)
void BM_mesh_edgeloops_calc_normal(BMesh *bm, ListBase *eloops)
#define EDGE_SPLIT(node_copy, node_other)
void BM_edgeloop_calc_center(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
void BM_mesh_edgeloops_calc_center(BMesh *bm, ListBase *eloops)
#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_index_set(ele, index)
Definition: bmesh_inline.h:125
#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)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1995
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) 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 const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
OperationNode * node
void * user_data
int count
#define fabsf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:115
struct BMEdgeLoopStore * next
struct BMEdgeLoopStore * prev
struct BMEdge * e
Definition: bmesh_class.h:109
char elem_index_dirty
Definition: bmesh_class.h:305
int totedge
Definition: bmesh_class.h:297
struct LinkData * next
Definition: DNA_listBase.h:41
struct LinkData * prev
Definition: DNA_listBase.h:41
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
struct VertStep * next
struct VertStep * prev
BMVert * v
__forceinline avxf cross(const avxf &a, const avxf &b)
Definition: util_avxf.h:119
__forceinline const avxi abs(const avxi &a)
Definition: util_avxi.h:186