Blender  V2.93
bmesh_region_match.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 
34 #include <string.h>
35 
36 #include "BLI_alloca.h"
37 #include "BLI_ghash.h"
38 #include "BLI_linklist.h"
39 #include "BLI_linklist_stack.h"
40 #include "BLI_listbase.h"
41 #include "BLI_mempool.h"
42 #include "MEM_guardedalloc.h"
43 
44 #include "bmesh.h"
45 
46 #include "tools/bmesh_region_match.h" /* own include */
47 
48 /* avoid re-creating ghash and pools for each search */
49 #define USE_WALKER_REUSE
50 
51 /* do a first-pass id of all vertices,
52  * this avoids expensive checks on every item later on
53  * (works fine without, just slower) */
54 #define USE_PIVOT_FASTMATCH
55 
56 /* otherwise use active element as pivot, for quick tests only */
57 #define USE_PIVOT_SEARCH
58 
59 // #define DEBUG_TIME
60 // #define DEBUG_PRINT
61 
62 #ifdef DEBUG_TIME
63 # include "PIL_time.h"
64 # include "PIL_time_utildefines.h"
65 #endif
66 
67 #include "BLI_strict_flags.h"
68 
69 /* -------------------------------------------------------------------- */
73 #define PRIME_VERT_INIT 100003
74 
76 
77 typedef struct UUIDWalk {
78 
79  /* List of faces we can step onto (UUIDFaceStep's) */
81 
82  /* Face & Vert UUID's */
85 
86  /* memory pool for LinkNode's */
88 
89  /* memory pool for LinkBase's */
91 
92  /* memory pool for UUIDFaceStep's */
95 
96  /* Optionally use face-tag to isolate search */
98 
99  /* Increment for each pass added */
101 
102  /* runtime vars, avoid re-creating each pass */
103  struct {
104  GHash *verts_uuid; /* BMVert -> UUID */
105  GSet *faces_step; /* BMFace */
106 
107  GHash *faces_from_uuid; /* UUID -> UUIDFaceStepItem */
108 
111  } cache;
112 
114 
115 /* stores a set of potential faces to step onto */
116 typedef struct UUIDFaceStep {
117  struct UUIDFaceStep *next, *prev;
118 
119  /* unsorted 'BMFace' */
121 
122  /* faces sorted into 'UUIDFaceStepItem' */
125 
126 /* store face-lists with same uuid */
127 typedef struct UUIDFaceStepItem {
130 
134 
136 {
137  if (uuidwalk->use_face_isolate) {
139  }
140  return true;
141 }
142 
144 {
145  void **ret;
146  ret = BLI_ghash_lookup_p(uuidwalk->verts_uuid, v);
147  if (ret) {
148  *r_uuid = (UUID_Int)(*ret);
149  return true;
150  }
151  return false;
152 }
153 
155 {
156  void **ret;
157  ret = BLI_ghash_lookup_p(uuidwalk->faces_uuid, f);
158  if (ret) {
159  *r_uuid = (UUID_Int)(*ret);
160  return true;
161  }
162  return false;
163 }
164 
165 static uint ghashutil_bmelem_indexhash(const void *key)
166 {
167  const BMElem *ele = key;
168  return (uint)BM_elem_index_get(ele);
169 }
170 
171 static bool ghashutil_bmelem_indexcmp(const void *a, const void *b)
172 {
173  BLI_assert((a != b) == (BM_elem_index_get((BMElem *)a) != BM_elem_index_get((BMElem *)b)));
174  return (a != b);
175 }
176 
177 static GHash *ghash_bmelem_new_ex(const char *info, const uint nentries_reserve)
178 {
179  return BLI_ghash_new_ex(
180  ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
181 }
182 
183 static GSet *gset_bmelem_new_ex(const char *info, const uint nentries_reserve)
184 {
185  return BLI_gset_new_ex(
186  ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
187 }
188 
189 static GHash *ghash_bmelem_new(const char *info)
190 {
191  return ghash_bmelem_new_ex(info, 0);
192 }
193 
194 static GSet *gset_bmelem_new(const char *info)
195 {
196  return gset_bmelem_new_ex(info, 0);
197 }
198 
199 static void bm_uuidwalk_init(UUIDWalk *uuidwalk,
200  const uint faces_src_region_len,
201  const uint verts_src_region_len)
202 {
203  BLI_listbase_clear(&uuidwalk->faces_step);
204 
205  uuidwalk->verts_uuid = ghash_bmelem_new_ex(__func__, verts_src_region_len);
206  uuidwalk->faces_uuid = ghash_bmelem_new_ex(__func__, faces_src_region_len);
207 
208  uuidwalk->cache.verts_uuid = ghash_bmelem_new(__func__);
209  uuidwalk->cache.faces_step = gset_bmelem_new(__func__);
210 
211  /* works because 'int' ghash works for intptr_t too */
212  uuidwalk->cache.faces_from_uuid = BLI_ghash_int_new(__func__);
213 
214  uuidwalk->cache.rehash_store = NULL;
215  uuidwalk->cache.rehash_store_len = 0;
216 
217  uuidwalk->use_face_isolate = false;
218 
219  /* smaller pool's for faster clearing */
220  uuidwalk->link_pool = BLI_mempool_create(sizeof(LinkNode), 64, 64, BLI_MEMPOOL_NOP);
221  uuidwalk->step_pool = BLI_mempool_create(sizeof(UUIDFaceStep), 64, 64, BLI_MEMPOOL_NOP);
223  sizeof(UUIDFaceStepItem), 64, 64, BLI_MEMPOOL_NOP);
224 
225  uuidwalk->pass = 1;
226 }
227 
228 static void bm_uuidwalk_clear(UUIDWalk *uuidwalk)
229 {
230  BLI_listbase_clear(&uuidwalk->faces_step);
231 
232  BLI_ghash_clear(uuidwalk->verts_uuid, NULL, NULL);
233  BLI_ghash_clear(uuidwalk->faces_uuid, NULL, NULL);
234 
236  BLI_gset_clear(uuidwalk->cache.faces_step, NULL);
238 
239  /* keep rehash_store as-is, for reuse */
240 
241  uuidwalk->use_face_isolate = false;
242 
243  BLI_mempool_clear(uuidwalk->link_pool);
244  BLI_mempool_clear(uuidwalk->step_pool);
246 
247  uuidwalk->pass = 1;
248 }
249 
250 static void bm_uuidwalk_free(UUIDWalk *uuidwalk)
251 {
258  BLI_ghash_free(uuidwalk->verts_uuid, NULL, NULL);
259  BLI_ghash_free(uuidwalk->faces_uuid, NULL, NULL);
260 
261  /* cache */
262  BLI_ghash_free(uuidwalk->cache.verts_uuid, NULL, NULL);
263  BLI_gset_free(uuidwalk->cache.faces_step, NULL);
265  MEM_SAFE_FREE(uuidwalk->cache.rehash_store);
266 
267  BLI_mempool_destroy(uuidwalk->link_pool);
268  BLI_mempool_destroy(uuidwalk->step_pool);
270 }
271 
273 {
274 #define PRIME_VERT_SMALL 7
275 #define PRIME_VERT_MID 43
276 #define PRIME_VERT_LARGE 1031
277 
278 #define PRIME_FACE_SMALL 13
279 #define PRIME_FACE_MID 53
280 
281  UUID_Int uuid;
282 
283  uuid = uuidwalk->pass * PRIME_VERT_LARGE;
284 
285  /* vert -> other */
286  {
287  uint tot = 0;
288  BMIter eiter;
289  BMEdge *e;
290  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
291  BMVert *v_other = BM_edge_other_vert(e, v);
292  UUID_Int uuid_other;
293  if (bm_uuidwalk_vert_lookup(uuidwalk, v_other, &uuid_other)) {
294  uuid ^= (uuid_other * PRIME_VERT_SMALL);
295  tot += 1;
296  }
297  }
298  uuid ^= (tot * PRIME_VERT_MID);
299  }
300 
301  /* faces */
302  {
303  uint tot = 0;
304  BMIter iter;
305  BMFace *f;
306 
307  BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
308  UUID_Int uuid_other;
309  if (bm_uuidwalk_face_lookup(uuidwalk, f, &uuid_other)) {
310  uuid ^= (uuid_other * PRIME_FACE_SMALL);
311  tot += 1;
312  }
313  }
314  uuid ^= (tot * PRIME_FACE_MID);
315  }
316 
317  return uuid;
318 
319 #undef PRIME_VERT_SMALL
320 #undef PRIME_VERT_MID
321 #undef PRIME_VERT_LARGE
322 
323 #undef PRIME_FACE_SMALL
324 #undef PRIME_FACE_MID
325 }
326 
328 {
329 #define PRIME_VERT_SMALL 11
330 
331 #define PRIME_FACE_SMALL 17
332 #define PRIME_FACE_LARGE 1013
333 
334  UUID_Int uuid;
335 
336  uuid = uuidwalk->pass * (uint)f->len * PRIME_FACE_LARGE;
337 
338  /* face-verts */
339  {
340  BMLoop *l_iter, *l_first;
341 
342  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
343  do {
344  UUID_Int uuid_other;
345  if (bm_uuidwalk_vert_lookup(uuidwalk, l_iter->v, &uuid_other)) {
346  uuid ^= (uuid_other * PRIME_VERT_SMALL);
347  }
348  } while ((l_iter = l_iter->next) != l_first);
349  }
350 
351  /* face-faces (connected by edge) */
352  {
353  BMLoop *l_iter, *l_first;
354 
355  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
356  do {
357  if (l_iter->radial_next != l_iter) {
358  BMLoop *l_iter_radial = l_iter->radial_next;
359  do {
360  UUID_Int uuid_other;
361  if (bm_uuidwalk_face_lookup(uuidwalk, l_iter_radial->f, &uuid_other)) {
362  uuid ^= (uuid_other * PRIME_FACE_SMALL);
363  }
364  } while ((l_iter_radial = l_iter_radial->radial_next) != l_iter);
365  }
366  } while ((l_iter = l_iter->next) != l_first);
367  }
368 
369  return uuid;
370 
371 #undef PRIME_VERT_SMALL
372 
373 #undef PRIME_FACE_SMALL
374 #undef PRIME_FACE_LARGE
375 }
376 
377 static void bm_uuidwalk_rehash_reserve(UUIDWalk *uuidwalk, uint rehash_store_len_new)
378 {
379  if (UNLIKELY(rehash_store_len_new > uuidwalk->cache.rehash_store_len)) {
380  /* avoid re-allocs */
381  rehash_store_len_new *= 2;
382  uuidwalk->cache.rehash_store = MEM_reallocN(uuidwalk->cache.rehash_store,
383  rehash_store_len_new *
384  sizeof(*uuidwalk->cache.rehash_store));
385  uuidwalk->cache.rehash_store_len = rehash_store_len_new;
386  }
387 }
388 
392 static void bm_uuidwalk_rehash(UUIDWalk *uuidwalk)
393 {
394  GHashIterator gh_iter;
395  UUID_Int *uuid_store;
396  uint i;
397 
398  uint rehash_store_len_new = MAX2(BLI_ghash_len(uuidwalk->verts_uuid),
399  BLI_ghash_len(uuidwalk->faces_uuid));
400 
401  bm_uuidwalk_rehash_reserve(uuidwalk, rehash_store_len_new);
402  uuid_store = uuidwalk->cache.rehash_store;
403 
404  /* verts */
405  i = 0;
406  GHASH_ITER (gh_iter, uuidwalk->verts_uuid) {
407  BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
408  uuid_store[i++] = bm_uuidwalk_calc_vert_uuid(uuidwalk, v);
409  }
410  i = 0;
411  GHASH_ITER (gh_iter, uuidwalk->verts_uuid) {
412  void **uuid_p = BLI_ghashIterator_getValue_p(&gh_iter);
413  *((UUID_Int *)uuid_p) = uuid_store[i++];
414  }
415 
416  /* faces */
417  i = 0;
418  GHASH_ITER (gh_iter, uuidwalk->faces_uuid) {
419  BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
420  uuid_store[i++] = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
421  }
422  i = 0;
423  GHASH_ITER (gh_iter, uuidwalk->faces_uuid) {
424  void **uuid_p = BLI_ghashIterator_getValue_p(&gh_iter);
425  *((UUID_Int *)uuid_p) = uuid_store[i++];
426  }
427 }
428 
430  LinkNode *faces,
431  const uint faces_len,
432  const bool is_init)
433 {
434  UUID_Int *uuid_store;
435  LinkNode *f_link;
436  uint i;
437 
438  bm_uuidwalk_rehash_reserve(uuidwalk, faces_len);
439  uuid_store = uuidwalk->cache.rehash_store;
440 
441  i = 0;
442  for (f_link = faces; f_link; f_link = f_link->next) {
443  BMFace *f = f_link->link;
444  uuid_store[i++] = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
445  }
446 
447  i = 0;
448  if (is_init) {
449  for (f_link = faces; f_link; f_link = f_link->next) {
450  BMFace *f = f_link->link;
451  BLI_ghash_insert(uuidwalk->faces_uuid, f, (void *)uuid_store[i++]);
452  }
453  }
454  else {
455  for (f_link = faces; f_link; f_link = f_link->next) {
456  BMFace *f = f_link->link;
457  void **uuid_p = BLI_ghash_lookup_p(uuidwalk->faces_uuid, f);
458  *((UUID_Int *)uuid_p) = uuid_store[i++];
459  }
460  }
461 }
462 
463 static bool bm_vert_is_uuid_connect(UUIDWalk *uuidwalk, BMVert *v)
464 {
465  BMIter eiter;
466  BMEdge *e;
467 
468  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
469  BMVert *v_other = BM_edge_other_vert(e, v);
470  if (BLI_ghash_haskey(uuidwalk->verts_uuid, v_other)) {
471  return true;
472  }
473  }
474  return false;
475 }
476 
477 static void bm_uuidwalk_pass_add(UUIDWalk *uuidwalk,
478  LinkNode *faces_pass,
479  const uint faces_pass_len)
480 {
481  GHashIterator gh_iter;
482  GHash *verts_uuid_pass;
483  GSet *faces_step_next;
484  LinkNode *f_link;
485 
486  UUIDFaceStep *fstep;
487 
488  BLI_assert(faces_pass_len == (uint)BLI_linklist_count(faces_pass));
489 
490  /* rehash faces now all their verts have been added */
491  bm_uuidwalk_rehash_facelinks(uuidwalk, faces_pass, faces_pass_len, true);
492 
493  /* create verts_new */
494  verts_uuid_pass = uuidwalk->cache.verts_uuid;
495  faces_step_next = uuidwalk->cache.faces_step;
496 
497  BLI_assert(BLI_ghash_len(verts_uuid_pass) == 0);
498  BLI_assert(BLI_gset_len(faces_step_next) == 0);
499 
500  /* Add the face_step data from connected faces, creating new passes */
501  fstep = BLI_mempool_alloc(uuidwalk->step_pool);
502  BLI_addhead(&uuidwalk->faces_step, fstep);
503  fstep->faces = NULL;
504  BLI_listbase_clear(&fstep->items);
505 
506  for (f_link = faces_pass; f_link; f_link = f_link->next) {
507  BMFace *f = f_link->link;
508  BMLoop *l_iter, *l_first;
509 
510  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
511  do {
512  /* fill verts_new */
513  void **val_p;
514  if (!BLI_ghash_haskey(uuidwalk->verts_uuid, l_iter->v) &&
515  !BLI_ghash_ensure_p(verts_uuid_pass, l_iter->v, &val_p) &&
516  (bm_vert_is_uuid_connect(uuidwalk, l_iter->v) == true)) {
517  const UUID_Int uuid = bm_uuidwalk_calc_vert_uuid(uuidwalk, l_iter->v);
518  *val_p = (void *)uuid;
519  }
520 
521  /* fill faces_step_next */
522  if (l_iter->radial_next != l_iter) {
523  BMLoop *l_iter_radial = l_iter->radial_next;
524  do {
525  if (!BLI_ghash_haskey(uuidwalk->faces_uuid, l_iter_radial->f) &&
526  !BLI_gset_haskey(faces_step_next, l_iter_radial->f) &&
527  (bm_uuidwalk_face_test(uuidwalk, l_iter_radial->f))) {
528  BLI_gset_insert(faces_step_next, l_iter_radial->f);
529 
530  /* add to fstep */
531  BLI_linklist_prepend_pool(&fstep->faces, l_iter_radial->f, uuidwalk->link_pool);
532  }
533  } while ((l_iter_radial = l_iter_radial->radial_next) != l_iter);
534  }
535  } while ((l_iter = l_iter->next) != l_first);
536  }
537 
538  /* faces_uuid.update(verts_new) */
539  GHASH_ITER (gh_iter, verts_uuid_pass) {
540  BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
541  void *uuid_p = BLI_ghashIterator_getValue(&gh_iter);
542  BLI_ghash_insert(uuidwalk->verts_uuid, v, uuid_p);
543  }
544 
545  /* rehash faces now all their verts have been added */
546  bm_uuidwalk_rehash_facelinks(uuidwalk, faces_pass, faces_pass_len, false);
547 
548  uuidwalk->pass += 1;
549 
551  BLI_gset_clear(uuidwalk->cache.faces_step, NULL);
552 }
553 
554 static int bm_face_len_cmp(const void *v1, const void *v2)
555 {
556  const BMFace *f1 = *((BMFace **)v1);
557  const BMFace *f2 = *((BMFace **)v2);
558 
559  if (f1->len > f2->len) {
560  return 1;
561  }
562  if (f1->len < f2->len) {
563  return -1;
564  }
565  return 0;
566 }
567 
569 {
570  BMLoop *l_iter = e->l;
571  uint f_arr_len = (uint)BM_edge_face_count(e);
572  BMFace **f_arr = BLI_array_alloca(f_arr, f_arr_len);
573  uint fstep_num = 0, i = 0;
574 
575  do {
576  BMFace *f = l_iter->f;
577  if (bm_uuidwalk_face_test(uuidwalk, f)) {
578  f_arr[i++] = f;
579  }
580  } while ((l_iter = l_iter->radial_next) != e->l);
581  BLI_assert(i <= f_arr_len);
582  f_arr_len = i;
583 
584  qsort(f_arr, f_arr_len, sizeof(*f_arr), bm_face_len_cmp);
585 
586  /* start us off! */
587  {
588  const UUID_Int uuid = PRIME_VERT_INIT;
589  BLI_ghash_insert(uuidwalk->verts_uuid, e->v1, (void *)uuid);
590  BLI_ghash_insert(uuidwalk->verts_uuid, e->v2, (void *)uuid);
591  }
592 
593  /* turning an array into LinkNode's seems odd,
594  * but this is just for initialization,
595  * elsewhere using LinkNode's makes more sense */
596  for (i = 0; i < f_arr_len;) {
597  LinkNode *faces_pass = NULL;
598  const uint i_init = i;
599  const int f_len = f_arr[i]->len;
600 
601  do {
602  BLI_linklist_prepend_pool(&faces_pass, f_arr[i++], uuidwalk->link_pool);
603  } while (i < f_arr_len && (f_len == f_arr[i]->len));
604 
605  bm_uuidwalk_pass_add(uuidwalk, faces_pass, i - i_init);
606  BLI_linklist_free_pool(faces_pass, NULL, uuidwalk->link_pool);
607  fstep_num += 1;
608  }
609 
610  return fstep_num;
611 }
612 
613 #undef PRIME_VERT_INIT
614 
617 /* -------------------------------------------------------------------- */
621 static int facestep_sort(const void *a, const void *b)
622 {
623  const UUIDFaceStepItem *fstep_a = a;
624  const UUIDFaceStepItem *fstep_b = b;
625  return (fstep_a->uuid > fstep_b->uuid) ? 1 : 0;
626 }
627 
632 static bool bm_uuidwalk_facestep_begin(UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
633 {
634  LinkNode *f_link, *f_link_next, **f_link_prev_p;
635  bool ok = false;
636 
639 
640  f_link_prev_p = &fstep->faces;
641  for (f_link = fstep->faces; f_link; f_link = f_link_next) {
642  BMFace *f = f_link->link;
643  f_link_next = f_link->next;
644 
645  /* possible another pass added this face already, free in that case */
646  if (!BLI_ghash_haskey(uuidwalk->faces_uuid, f)) {
647  const UUID_Int uuid = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
648  UUIDFaceStepItem *fstep_item;
649  void **val_p;
650 
651  ok = true;
652 
653  if (BLI_ghash_ensure_p(uuidwalk->cache.faces_from_uuid, (void *)uuid, &val_p)) {
654  fstep_item = *val_p;
655  }
656  else {
657  fstep_item = *val_p = BLI_mempool_alloc(uuidwalk->step_pool_items);
658 
659  /* add to start, so its handled on the next round of passes */
660  BLI_addhead(&fstep->items, fstep_item);
661  fstep_item->uuid = uuid;
662  fstep_item->list = NULL;
663  fstep_item->list_len = 0;
664  }
665 
666  BLI_linklist_prepend_pool(&fstep_item->list, f, uuidwalk->link_pool);
667  fstep_item->list_len += 1;
668 
669  f_link_prev_p = &f_link->next;
670  }
671  else {
672  *f_link_prev_p = f_link->next;
673  BLI_mempool_free(uuidwalk->link_pool, f_link);
674  }
675  }
676 
678 
680 
681  return ok;
682 }
683 
687 static void bm_uuidwalk_facestep_end(UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
688 {
689  UUIDFaceStepItem *fstep_item;
690 
691  while ((fstep_item = BLI_pophead(&fstep->items))) {
692  BLI_mempool_free(uuidwalk->step_pool_items, fstep_item);
693  }
694 }
695 
696 static void bm_uuidwalk_facestep_free(UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
697 {
698  LinkNode *f_link, *f_link_next;
699 
701 
702  for (f_link = fstep->faces; f_link; f_link = f_link_next) {
703  f_link_next = f_link->next;
704  BLI_mempool_free(uuidwalk->link_pool, f_link);
705  }
706 
707  BLI_remlink(&uuidwalk->faces_step, fstep);
708  BLI_mempool_free(uuidwalk->step_pool, fstep);
709 }
710 
713 /* -------------------------------------------------------------------- */
714 /* Main Loop to match up regions */
715 
721 #ifdef USE_WALKER_REUSE
722  UUIDWalk *w_src,
723  UUIDWalk *w_dst,
724 #endif
725  BMEdge *e_src,
726  BMEdge *e_dst,
727  const uint faces_src_region_len,
728  const uint verts_src_region_len,
729  uint *r_faces_result_len)
730 {
731 #ifndef USE_WALKER_REUSE
732  UUIDWalk w_src_, w_dst_;
733  UUIDWalk *w_src = &w_src_, *w_dst = &w_dst_;
734 #endif
735  BMFace **faces_result = NULL;
736  bool found = false;
737 
738  BLI_assert(e_src != e_dst);
739 
740 #ifndef USE_WALKER_REUSE
741  bm_uuidwalk_init(w_src, faces_src_region_len, verts_src_region_len);
742  bm_uuidwalk_init(w_dst, faces_src_region_len, verts_src_region_len);
743 #endif
744 
745  w_src->use_face_isolate = true;
746 
747  /* setup the initial state */
748  if (UNLIKELY(bm_uuidwalk_init_from_edge(w_src, e_src) !=
749  bm_uuidwalk_init_from_edge(w_dst, e_dst))) {
750  /* should never happen, if verts passed are compatible, but to be safe... */
751  goto finally;
752  }
753 
754  bm_uuidwalk_rehash_reserve(w_src, MAX2(faces_src_region_len, verts_src_region_len));
755  bm_uuidwalk_rehash_reserve(w_dst, MAX2(faces_src_region_len, verts_src_region_len));
756 
757  while (true) {
758  bool ok = false;
759 
760  UUIDFaceStep *fstep_src = w_src->faces_step.first;
761  UUIDFaceStep *fstep_dst = w_dst->faces_step.first;
762 
763  BLI_assert(BLI_listbase_count(&w_src->faces_step) == BLI_listbase_count(&w_dst->faces_step));
764 
765  while (fstep_src) {
766 
767  /* even if the destination has faces,
768  * it's not important, since the source doesn't, free and move-on. */
769  if (fstep_src->faces == NULL) {
770  UUIDFaceStep *fstep_src_next = fstep_src->next;
771  UUIDFaceStep *fstep_dst_next = fstep_dst->next;
772  bm_uuidwalk_facestep_free(w_src, fstep_src);
773  bm_uuidwalk_facestep_free(w_dst, fstep_dst);
774  fstep_src = fstep_src_next;
775  fstep_dst = fstep_dst_next;
776  continue;
777  }
778 
779  if (bm_uuidwalk_facestep_begin(w_src, fstep_src) &&
780  bm_uuidwalk_facestep_begin(w_dst, fstep_dst)) {
781  /* Step over face-lists with matching UUID's
782  * both lists are sorted, so no need for lookups.
783  * The data is created on 'begin' and cleared on 'end' */
784  UUIDFaceStepItem *fstep_item_src;
785  UUIDFaceStepItem *fstep_item_dst;
786  for (fstep_item_src = fstep_src->items.first, fstep_item_dst = fstep_dst->items.first;
787  fstep_item_src && fstep_item_dst;
788  fstep_item_src = fstep_item_src->next, fstep_item_dst = fstep_item_dst->next) {
789  while ((fstep_item_dst != NULL) && (fstep_item_dst->uuid < fstep_item_src->uuid)) {
790  fstep_item_dst = fstep_item_dst->next;
791  }
792 
793  if ((fstep_item_dst == NULL) || (fstep_item_src->uuid != fstep_item_dst->uuid) ||
794  (fstep_item_src->list_len > fstep_item_dst->list_len)) {
795  /* if the target walker has less than the source
796  * then the islands don't match, bail early */
797  ok = false;
798  break;
799  }
800 
801  if (fstep_item_src->list_len == fstep_item_dst->list_len) {
802  /* found a match */
803  bm_uuidwalk_pass_add(w_src, fstep_item_src->list, fstep_item_src->list_len);
804  bm_uuidwalk_pass_add(w_dst, fstep_item_dst->list, fstep_item_dst->list_len);
805 
806  BLI_linklist_free_pool(fstep_item_src->list, NULL, w_src->link_pool);
807  BLI_linklist_free_pool(fstep_item_dst->list, NULL, w_dst->link_pool);
808 
809  fstep_item_src->list = NULL;
810  fstep_item_src->list_len = 0;
811 
812  fstep_item_dst->list = NULL;
813  fstep_item_dst->list_len = 0;
814 
815  ok = true;
816  }
817  }
818  }
819 
820  bm_uuidwalk_facestep_end(w_src, fstep_src);
821  bm_uuidwalk_facestep_end(w_dst, fstep_dst);
822 
823  /* lock-step */
824  fstep_src = fstep_src->next;
825  fstep_dst = fstep_dst->next;
826  }
827 
828  if (!ok) {
829  break;
830  }
831 
832  found = (BLI_ghash_len(w_dst->faces_uuid) == faces_src_region_len);
833  if (found) {
834  break;
835  }
836 
837  /* Expensive! but some cases fails without.
838  * (also faster in other cases since it can rule-out invalid regions) */
839  bm_uuidwalk_rehash(w_src);
840  bm_uuidwalk_rehash(w_dst);
841  }
842 
843  if (found) {
844  GHashIterator gh_iter;
845  const uint faces_result_len = BLI_ghash_len(w_dst->faces_uuid);
846  uint i;
847 
848  faces_result = MEM_mallocN(sizeof(*faces_result) * (faces_result_len + 1), __func__);
849  GHASH_ITER_INDEX (gh_iter, w_dst->faces_uuid, i) {
850  BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
851  faces_result[i] = f;
852  }
853  faces_result[faces_result_len] = NULL;
854  *r_faces_result_len = faces_result_len;
855  }
856  else {
857  *r_faces_result_len = 0;
858  }
859 
860 finally:
861 
862 #ifdef USE_WALKER_REUSE
863  bm_uuidwalk_clear(w_src);
864  bm_uuidwalk_clear(w_dst);
865 #else
866  bm_uuidwalk_free(w_src);
867  bm_uuidwalk_free(w_dst);
868 #endif
869 
870  return faces_result;
871 }
872 
877  const uint faces_len,
878  uint *r_verts_len,
879  bool visit_faces)
880 {
881  uint verts_len = 0;
882  uint i;
883  for (i = 0; i < faces_len; i++) {
884  BMFace *f = faces[i];
885  BMLoop *l_iter, *l_first;
886  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
887  do {
888  if (r_verts_len) {
889  if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
890  verts_len += 1;
891  }
892  }
893 
896  } while ((l_iter = l_iter->next) != l_first);
897 
898  if (visit_faces) {
900  }
901  }
902 
903  if (r_verts_len) {
904  *r_verts_len = verts_len;
905  }
906 }
907 
908 #ifdef USE_PIVOT_SEARCH
909 
910 /* -------------------------------------------------------------------- */
914 /* signed user id */
916 
918 {
919  return (a < 0) ? -a : a;
920 }
921 
923 {
924  if (e->l->radial_next != e->l) {
925  BMLoop *l_iter = e->l;
926  do {
927  if (!BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
928  return true;
929  }
930  } while ((l_iter = l_iter->radial_next) != e->l);
931  return false;
932  }
933  /* boundary */
934  return true;
935 }
936 
938  BMEdge *e_test,
939  BMEdge **r_e_pivot_best,
940  SUID_Int e_pivot_best_id[2])
941 {
942  SUID_Int e_pivot_test_id[2];
943 
944  e_pivot_test_id[0] = (SUID_Int)BLI_ghash_lookup(gh, e_test->v1);
945  e_pivot_test_id[1] = (SUID_Int)BLI_ghash_lookup(gh, e_test->v2);
946  if (e_pivot_test_id[0] > e_pivot_test_id[1]) {
947  SWAP(SUID_Int, e_pivot_test_id[0], e_pivot_test_id[1]);
948  }
949 
950  if ((*r_e_pivot_best == NULL) ||
951  ((e_pivot_best_id[0] != e_pivot_test_id[0]) ? (e_pivot_best_id[0] < e_pivot_test_id[0]) :
952  (e_pivot_best_id[1] < e_pivot_test_id[1]))) {
953  e_pivot_best_id[0] = e_pivot_test_id[0];
954  e_pivot_best_id[1] = e_pivot_test_id[1];
955 
956  /* both verts are from the same pass, record this! */
957  *r_e_pivot_best = e_test;
958  }
959 }
960 
961 /* quick id from a boundary vertex */
963 {
964 # define PRIME_VERT_SMALL_A 7
965 # define PRIME_VERT_SMALL_B 13
966 # define PRIME_VERT_MID_A 103
967 # define PRIME_VERT_MID_B 131
968 
969  int tot = 0;
970  BMIter iter;
971  BMLoop *l;
973 
974  BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
975  const bool is_boundary_vert = (bm_edge_is_region_boundary(l->e) ||
977  id ^= l->f->len * (is_boundary_vert ? PRIME_VERT_SMALL_A : PRIME_VERT_SMALL_B);
978  tot += 1;
979  }
980 
981  id ^= (tot * PRIME_VERT_MID_B);
982 
983  return id ? abs_intptr(id) : 1;
984 
985 # undef PRIME_VERT_SMALL_A
986 # undef PRIME_VERT_SMALL_B
987 # undef PRIME_VERT_MID_A
988 # undef PRIME_VERT_MID_B
989 }
990 
995 {
996  BMIter eiter;
997  BMEdge *e;
998  SUID_Int tot = 0;
999  SUID_Int v_sum_face_len = 0;
1000  SUID_Int v_sum_id = 0;
1001  SUID_Int id;
1002  SUID_Int id_min = INTPTR_MIN + 1;
1003 
1004 # define PRIME_VERT_MID_A 23
1005 # define PRIME_VERT_MID_B 31
1006 
1007  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
1009  BMVert *v_other = BM_edge_other_vert(e, v);
1010  if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
1011  /* non-zero values aren't allowed... so no need to check haskey */
1012  SUID_Int v_other_id = (SUID_Int)BLI_ghash_lookup(gh, v_other);
1013  if (v_other_id > 0) {
1014  v_sum_id += v_other_id;
1015  tot += 1;
1016 
1017  /* face-count */
1018  {
1019  BMLoop *l_iter = e->l;
1020  do {
1021  if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
1022  v_sum_face_len += l_iter->f->len;
1023  }
1024  } while ((l_iter = l_iter->radial_next) != e->l);
1025  }
1026  }
1027  }
1028  }
1029  }
1030 
1031  id = (tot * PRIME_VERT_MID_A);
1032  id ^= (v_sum_face_len * PRIME_VERT_MID_B);
1033  id ^= v_sum_id;
1034 
1035  /* disallow 0 & min (since it can't be flipped) */
1036  id = (UNLIKELY(id == 0) ? 1 : UNLIKELY(id < id_min) ? id_min : id);
1037 
1038  return abs_intptr(id);
1039 
1040 # undef PRIME_VERT_MID_A
1041 # undef PRIME_VERT_MID_B
1042 }
1043 
1052  uint faces_region_len,
1053  uint verts_region_len,
1054  uint *r_depth)
1055 {
1056  /* note, keep deterministic where possible (geometry order independent)
1057  * this function assumed all visit faces & edges are tagged */
1058 
1059  BLI_LINKSTACK_DECLARE(vert_queue_prev, BMVert *);
1060  BLI_LINKSTACK_DECLARE(vert_queue_next, BMVert *);
1061 
1062  GHash *gh = BLI_ghash_ptr_new(__func__);
1063  uint i;
1064 
1065  BMEdge *e_pivot = NULL;
1066  /* pick any non-boundary edge (not ideal) */
1067  BMEdge *e_pivot_fallback = NULL;
1068 
1069  SUID_Int pass = 0;
1070 
1071  /* total verts in 'gs' we have visited - aka - not v_init_none */
1072  uint vert_queue_used = 0;
1073 
1074  BLI_LINKSTACK_INIT(vert_queue_prev);
1075  BLI_LINKSTACK_INIT(vert_queue_next);
1076 
1077  /* face-verts */
1078  for (i = 0; i < faces_region_len; i++) {
1079  BMFace *f = faces_region[i];
1080 
1081  BMLoop *l_iter, *l_first;
1082  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1083  do {
1084  BMEdge *e = l_iter->e;
1086  uint j;
1087  for (j = 0; j < 2; j++) {
1088  void **val_p;
1089  if (!BLI_ghash_ensure_p(gh, (&e->v1)[j], &val_p)) {
1090  SUID_Int v_id = bm_face_region_vert_boundary_id((&e->v1)[j]);
1091  *val_p = (void *)v_id;
1092  BLI_LINKSTACK_PUSH(vert_queue_prev, (&e->v1)[j]);
1093  vert_queue_used += 1;
1094  }
1095  }
1096  }
1097  else {
1098  /* Use in case (depth == 0), no interior verts. */
1099  e_pivot_fallback = e;
1100  }
1101  } while ((l_iter = l_iter->next) != l_first);
1102  }
1103 
1104  while (BLI_LINKSTACK_SIZE(vert_queue_prev)) {
1105  BMVert *v;
1106  while ((v = BLI_LINKSTACK_POP(vert_queue_prev))) {
1107  BMIter eiter;
1108  BMEdge *e;
1111  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
1113  BMVert *v_other = BM_edge_other_vert(e, v);
1114  if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
1115  void **val_p;
1116  if (!BLI_ghash_ensure_p(gh, v_other, &val_p)) {
1117  /* add as negative, so we know not to read from them this pass */
1118  const SUID_Int v_id_other = -bm_face_region_vert_pass_id(gh, v_other);
1119  *val_p = (void *)v_id_other;
1120  BLI_LINKSTACK_PUSH(vert_queue_next, v_other);
1121  vert_queue_used += 1;
1122  }
1123  }
1124  }
1125  }
1126  }
1127 
1128  /* flip all the newly added hashes to positive */
1129  {
1130  LinkNode *v_link;
1131  for (v_link = vert_queue_next; v_link; v_link = v_link->next) {
1132  SUID_Int *v_id_p = (SUID_Int *)BLI_ghash_lookup_p(gh, v_link->link);
1133  *v_id_p = -(*v_id_p);
1134  BLI_assert(*v_id_p > 0);
1135  }
1136  }
1137 
1138  BLI_LINKSTACK_SWAP(vert_queue_prev, vert_queue_next);
1139  pass += 1;
1140 
1141  if (vert_queue_used == verts_region_len) {
1142  break;
1143  }
1144  }
1145 
1146  if (BLI_LINKSTACK_SIZE(vert_queue_prev) >= 2) {
1147  /* common case - we managed to find some interior verts */
1148  LinkNode *v_link;
1149  BMEdge *e_pivot_best = NULL;
1150  SUID_Int e_pivot_best_id[2] = {0, 0};
1151 
1152  /* temp untag, so we can quickly know what other verts are in this last pass */
1153  for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
1154  BMVert *v = v_link->link;
1156  }
1157 
1158  /* restore correct tagging */
1159  for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
1160  BMIter eiter;
1161  BMEdge *e_test;
1162 
1163  BMVert *v = v_link->link;
1165 
1166  BM_ITER_ELEM (e_test, &eiter, v, BM_EDGES_OF_VERT) {
1167  if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) {
1168  BMVert *v_other = BM_edge_other_vert(e_test, v);
1169  if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == false) {
1170  bm_face_region_pivot_edge_use_best(gh, e_test, &e_pivot_best, e_pivot_best_id);
1171  }
1172  }
1173  }
1174  }
1175 
1176  e_pivot = e_pivot_best;
1177  }
1178 
1179  if ((e_pivot == NULL) && BLI_LINKSTACK_SIZE(vert_queue_prev)) {
1180  /* find the best single edge */
1181  BMEdge *e_pivot_best = NULL;
1182  SUID_Int e_pivot_best_id[2] = {0, 0};
1183 
1184  LinkNode *v_link;
1185 
1186  /* reduce a pass since we're having to step into a previous passes vert,
1187  * and will be closer to the boundary */
1188  BLI_assert(pass != 0);
1189  pass -= 1;
1190 
1191  for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
1192  BMVert *v = v_link->link;
1193 
1194  BMIter eiter;
1195  BMEdge *e_test;
1196  BM_ITER_ELEM (e_test, &eiter, v, BM_EDGES_OF_VERT) {
1197  if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) {
1198  BMVert *v_other = BM_edge_other_vert(e_test, v);
1199  if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
1200  bm_face_region_pivot_edge_use_best(gh, e_test, &e_pivot_best, e_pivot_best_id);
1201  }
1202  }
1203  }
1204  }
1205 
1206  e_pivot = e_pivot_best;
1207  }
1208 
1209  BLI_LINKSTACK_FREE(vert_queue_prev);
1210  BLI_LINKSTACK_FREE(vert_queue_next);
1211 
1212  BLI_ghash_free(gh, NULL, NULL);
1213 
1214  if (e_pivot == NULL) {
1215 # ifdef DEBUG_PRINT
1216  printf("%s: using fallback edge!\n", __func__);
1217 # endif
1218  e_pivot = e_pivot_fallback;
1219  pass = 0;
1220  }
1221 
1222  *r_depth = (uint)pass;
1223 
1224  return e_pivot;
1225 }
1228 #endif /* USE_PIVOT_SEARCH */
1229 
1230 /* Quick UUID pass - identify candidates */
1231 
1232 #ifdef USE_PIVOT_FASTMATCH
1233 
1234 /* -------------------------------------------------------------------- */
1239 
1241 {
1242  BMIter eiter;
1243  BMEdge *e;
1244  UUIDFashMatch e_num = 0, f_num = 0, l_num = 0;
1245 
1246 # define PRIME_EDGE 7
1247 # define PRIME_FACE 31
1248 # define PRIME_LOOP 61
1249 
1250  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
1251  if (!BM_edge_is_wire(e)) {
1252  BMLoop *l_iter = e->l;
1253  e_num += 1;
1254  do {
1255  f_num += 1;
1256  l_num += (uint)l_iter->f->len;
1257  } while ((l_iter = l_iter->radial_next) != e->l);
1258  }
1259  }
1260 
1261  return ((e_num * PRIME_EDGE) ^ (f_num * PRIME_FACE) * (l_num * PRIME_LOOP));
1262 
1263 # undef PRIME_EDGE
1264 # undef PRIME_FACE
1265 # undef PRIME_LOOP
1266 }
1267 
1269 {
1270  UUIDFashMatch *id_prev;
1271  UUIDFashMatch *id_curr;
1272  uint pass, i;
1273  BMVert *v;
1274  BMIter iter;
1275 
1276  id_prev = MEM_mallocN(sizeof(*id_prev) * (uint)bm->totvert, __func__);
1277  id_curr = MEM_mallocN(sizeof(*id_curr) * (uint)bm->totvert, __func__);
1278 
1279  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1280  id_prev[i] = bm_vert_fasthash_single(v);
1281  }
1282 
1283  for (pass = 0; pass < depth; pass++) {
1284  BMEdge *e;
1285 
1286  memcpy(id_curr, id_prev, sizeof(*id_prev) * (uint)bm->totvert);
1287 
1288  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
1289  if (BM_edge_is_wire(e) == false) {
1290  const int i1 = BM_elem_index_get(e->v1);
1291  const int i2 = BM_elem_index_get(e->v2);
1292 
1293  id_curr[i1] += id_prev[i2];
1294  id_curr[i2] += id_prev[i1];
1295  }
1296  }
1297  }
1298  MEM_freeN(id_prev);
1299 
1300  return id_curr;
1301 }
1302 
1304  const BMEdge *e,
1305  UUIDFashMatch e_fm[2])
1306 {
1307  e_fm[0] = fm[BM_elem_index_get(e->v1)];
1308  e_fm[1] = fm[BM_elem_index_get(e->v2)];
1309 
1310  if (e_fm[0] > e_fm[1]) {
1311  SWAP(UUIDFashMatch, e_fm[0], e_fm[1]);
1312  }
1313 }
1314 
1315 static bool bm_vert_fasthash_edge_is_match(UUIDFashMatch *fm, const BMEdge *e_a, const BMEdge *e_b)
1316 {
1317  UUIDFashMatch e_a_fm[2];
1318  UUIDFashMatch e_b_fm[2];
1319 
1320  bm_vert_fasthash_edge_order(fm, e_a, e_a_fm);
1321  bm_vert_fasthash_edge_order(fm, e_b, e_b_fm);
1322 
1323  return ((e_a_fm[0] == e_b_fm[0]) && (e_a_fm[1] == e_b_fm[1]));
1324 }
1325 
1327 {
1328  MEM_freeN(fm);
1329 }
1330 
1333 #endif /* USE_PIVOT_FASTMATCH */
1334 
1342  BMFace **faces_region,
1343  uint faces_region_len,
1344  ListBase *r_face_regions)
1345 {
1346  BMEdge *e_src;
1347  BMEdge *e_dst;
1348  BMIter iter;
1349  uint verts_region_len = 0;
1350  uint faces_result_len = 0;
1351  /* number of steps from e_src to a boundary vert */
1352  uint depth;
1353 
1354 #ifdef USE_WALKER_REUSE
1355  UUIDWalk w_src, w_dst;
1356 #endif
1357 
1358 #ifdef USE_PIVOT_FASTMATCH
1359  UUIDFashMatch *fm;
1360 #endif
1361 
1362 #ifdef DEBUG_PRINT
1363  int search_num = 0;
1364 #endif
1365 
1366 #ifdef DEBUG_TIME
1367  TIMEIT_START(region_match);
1368 #endif
1369 
1370  /* initialize visited verts */
1372  bm_face_array_visit(faces_region, faces_region_len, &verts_region_len, true);
1373 
1374  /* needed for 'ghashutil_bmelem_indexhash' */
1376 
1377 #ifdef USE_PIVOT_SEARCH
1378  e_src = bm_face_region_pivot_edge_find(faces_region, faces_region_len, verts_region_len, &depth);
1379 
1380  /* see which edge is added */
1381 # if 0
1383  if (e_src) {
1384  BM_select_history_store(bm, e_src);
1385  }
1386 # endif
1387 
1388 #else
1389  /* quick test only! */
1390  e_src = BM_mesh_active_edge_get(bm);
1391 #endif
1392 
1393  if (e_src == NULL) {
1394 #ifdef DEBUG_PRINT
1395  printf("Couldn't find 'e_src'");
1396 #endif
1397  return 0;
1398  }
1399 
1400  BLI_listbase_clear(r_face_regions);
1401 
1402 #ifdef USE_PIVOT_FASTMATCH
1403  if (depth > 0) {
1404  fm = bm_vert_fasthash_create(bm, depth);
1405  }
1406  else {
1407  fm = NULL;
1408  }
1409 #endif
1410 
1411 #ifdef USE_WALKER_REUSE
1412  bm_uuidwalk_init(&w_src, faces_region_len, verts_region_len);
1413  bm_uuidwalk_init(&w_dst, faces_region_len, verts_region_len);
1414 #endif
1415 
1416  BM_ITER_MESH (e_dst, &iter, bm, BM_EDGES_OF_MESH) {
1417  BMFace **faces_result;
1418  uint faces_result_len_out;
1419 
1420  if (BM_elem_flag_test(e_dst, BM_ELEM_TAG) || BM_edge_is_wire(e_dst)) {
1421  continue;
1422  }
1423 
1424 #ifdef USE_PIVOT_FASTMATCH
1425  if (fm && !bm_vert_fasthash_edge_is_match(fm, e_src, e_dst)) {
1426  continue;
1427  }
1428 #endif
1429 
1430 #ifdef DEBUG_PRINT
1431  search_num += 1;
1432 #endif
1433 
1434  faces_result = bm_mesh_region_match_pair(
1435 #ifdef USE_WALKER_REUSE
1436  &w_src,
1437  &w_dst,
1438 #endif
1439  e_src,
1440  e_dst,
1441  faces_region_len,
1442  verts_region_len,
1443  &faces_result_len_out);
1444 
1445  /* tag verts as visited */
1446  if (faces_result) {
1447  LinkData *link;
1448 
1449  bm_face_array_visit(faces_result, faces_result_len_out, NULL, false);
1450 
1451  link = BLI_genericNodeN(faces_result);
1452  BLI_addtail(r_face_regions, link);
1453  faces_result_len += 1;
1454  }
1455  }
1456 
1457 #ifdef USE_WALKER_REUSE
1458  bm_uuidwalk_free(&w_src);
1459  bm_uuidwalk_free(&w_dst);
1460 #else
1461  (void)bm_uuidwalk_clear;
1462 #endif
1463 
1464 #ifdef USE_PIVOT_FASTMATCH
1465  if (fm) {
1467  }
1468 #endif
1469 
1470 #ifdef DEBUG_PRINT
1471  printf("%s: search: %d, found %d\n", __func__, search_num, faces_result_len);
1472 #endif
1473 
1474 #ifdef DEBUG_TIME
1475  TIMEIT_END(region_match);
1476 #endif
1477 
1478  return (int)faces_result_len;
1479 }
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:36
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
struct GSet GSet
Definition: BLI_ghash.h:189
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:146
GHash * BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:707
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:996
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:150
BLI_INLINE void ** BLI_ghashIterator_getValue_p(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:154
unsigned int BLI_gset_len(GSet *gs) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1138
#define GHASH_ITER(gh_iter_, ghash_)
Definition: BLI_ghash.h:169
unsigned int BLI_ghash_len(GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:744
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1248
bool BLI_ghash_haskey(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:941
void BLI_gset_insert(GSet *gs, void *key)
Definition: BLI_ghash.c:1147
GHash * BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
GSet * BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1117
bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1216
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void ** BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:830
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:851
#define GHASH_ITER_INDEX(gh_iter_, ghash_, i_)
Definition: BLI_ghash.h:173
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
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
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
struct LinkData * BLI_genericNodeN(void *data)
Definition: listbase.c:923
void void BLI_listbase_sort(struct ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
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
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
@ 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_mempool_clear(BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:749
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
unsigned int uint
Definition: BLI_sys_types.h:83
#define SWAP(type, a, b)
#define MAX2(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 i1
_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 MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
Platform independent time functions.
Utility defines for timing/benchmarks.
#define TIMEIT_START(var)
#define TIMEIT_END(var)
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_test_bool(ele, hflag)
Definition: bmesh_inline.h:27
#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_FACES_OF_VERT
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_select_history_clear(BMesh *bm)
BMEdge * BM_mesh_active_edge_get(BMesh *bm)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
#define BM_select_history_store(bm, ele)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
int BM_edge_face_count(const BMEdge *e)
Definition: bmesh_query.c:847
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) 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 BMVert * v
static void bm_uuidwalk_init(UUIDWalk *uuidwalk, const uint faces_src_region_len, const uint verts_src_region_len)
BLI_INLINE bool bm_uuidwalk_face_test(UUIDWalk *uuidwalk, BMFace *f)
#define PRIME_LOOP
BLI_INLINE bool bm_uuidwalk_vert_lookup(UUIDWalk *uuidwalk, BMVert *v, UUID_Int *r_uuid)
static void bm_face_region_pivot_edge_use_best(GHash *gh, BMEdge *e_test, BMEdge **r_e_pivot_best, SUID_Int e_pivot_best_id[2])
static UUID_Int bm_uuidwalk_calc_face_uuid(UUIDWalk *uuidwalk, BMFace *f)
#define PRIME_VERT_MID_B
struct UUIDFaceStepItem UUIDFaceStepItem
static void bm_uuidwalk_free(UUIDWalk *uuidwalk)
static int bm_face_len_cmp(const void *v1, const void *v2)
static void bm_uuidwalk_rehash_reserve(UUIDWalk *uuidwalk, uint rehash_store_len_new)
static bool ghashutil_bmelem_indexcmp(const void *a, const void *b)
struct UUIDWalk UUIDWalk
#define PRIME_FACE_MID
static bool bm_vert_is_uuid_connect(UUIDWalk *uuidwalk, BMVert *v)
intptr_t SUID_Int
static UUID_Int bm_uuidwalk_calc_vert_uuid(UUIDWalk *uuidwalk, BMVert *v)
static void bm_uuidwalk_pass_add(UUIDWalk *uuidwalk, LinkNode *faces_pass, const uint faces_pass_len)
#define USE_WALKER_REUSE
static UUIDFashMatch bm_vert_fasthash_single(BMVert *v)
static UUIDFashMatch * bm_vert_fasthash_create(BMesh *bm, const uint depth)
static bool bm_uuidwalk_facestep_begin(UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
#define PRIME_VERT_MID
static BMFace ** bm_mesh_region_match_pair(UUIDWalk *w_src, UUIDWalk *w_dst, BMEdge *e_src, BMEdge *e_dst, const uint faces_src_region_len, const uint verts_src_region_len, uint *r_faces_result_len)
#define PRIME_FACE
BLI_INLINE intptr_t abs_intptr(intptr_t a)
#define PRIME_EDGE
BLI_INLINE bool bm_uuidwalk_face_lookup(UUIDWalk *uuidwalk, BMFace *f, UUID_Int *r_uuid)
#define PRIME_FACE_SMALL
uintptr_t UUIDFashMatch
static GSet * gset_bmelem_new_ex(const char *info, const uint nentries_reserve)
static void bm_vert_fasthash_destroy(UUIDFashMatch *fm)
static SUID_Int bm_face_region_vert_pass_id(GHash *gh, BMVert *v)
static uint bm_uuidwalk_init_from_edge(UUIDWalk *uuidwalk, BMEdge *e)
static int facestep_sort(const void *a, const void *b)
static void bm_uuidwalk_facestep_free(UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
#define PRIME_VERT_LARGE
#define PRIME_VERT_SMALL
static uint ghashutil_bmelem_indexhash(const void *key)
static bool bm_vert_fasthash_edge_is_match(UUIDFashMatch *fm, const BMEdge *e_a, const BMEdge *e_b)
static BMEdge * bm_face_region_pivot_edge_find(BMFace **faces_region, uint faces_region_len, uint verts_region_len, uint *r_depth)
#define PRIME_VERT_MID_A
#define PRIME_VERT_INIT
static void bm_uuidwalk_rehash(UUIDWalk *uuidwalk)
static void bm_uuidwalk_facestep_end(UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
#define PRIME_VERT_SMALL_A
static void bm_uuidwalk_clear(UUIDWalk *uuidwalk)
struct UUIDFaceStep UUIDFaceStep
static SUID_Int bm_face_region_vert_boundary_id(BMVert *v)
static bool bm_edge_is_region_boundary(BMEdge *e)
static GHash * ghash_bmelem_new(const char *info)
#define PRIME_FACE_LARGE
uintptr_t UUID_Int
static void bm_vert_fasthash_edge_order(const UUIDFashMatch *fm, const BMEdge *e, UUIDFashMatch e_fm[2])
#define PRIME_VERT_SMALL_B
int BM_mesh_region_match(BMesh *bm, BMFace **faces_region, uint faces_region_len, ListBase *r_face_regions)
static void bm_uuidwalk_rehash_facelinks(UUIDWalk *uuidwalk, LinkNode *faces, const uint faces_len, const bool is_init)
static GHash * ghash_bmelem_new_ex(const char *info, const uint nentries_reserve)
static void bm_face_array_visit(BMFace **faces, const uint faces_len, uint *r_verts_len, bool visit_faces)
static GSet * gset_bmelem_new(const char *info)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static char faces[256]
static unsigned a[3]
Definition: RandGen.cpp:92
return ret
#define INTPTR_MIN
Definition: stdint.h:182
_W64 unsigned int uintptr_t
Definition: stdint.h:122
_W64 int intptr_t
Definition: stdint.h:121
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
int len
Definition: bmesh_class.h:279
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
int totvert
Definition: bmesh_class.h:297
void * link
Definition: BLI_linklist.h:40
struct LinkNode * next
Definition: BLI_linklist.h:39
void * first
Definition: DNA_listBase.h:47
struct UUIDFaceStepItem * prev
struct UUIDFaceStepItem * next
struct UUIDFaceStep * prev
struct UUIDFaceStep * next
BLI_mempool * step_pool
BLI_mempool * lbase_pool
GHash * faces_from_uuid
struct UUIDWalk::@170 cache
bool use_face_isolate
GHash * verts_uuid
BLI_mempool * step_pool_items
UUID_Int * rehash_store
GHash * faces_uuid
BLI_mempool * link_pool
ListBase faces_step
uint len