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