Blender V4.3
bmesh_path_uv.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
11#include "MEM_guardedalloc.h"
12
13#include "BLI_heap_simple.h"
14#include "BLI_linklist.h"
15#include "BLI_math_geom.h"
16#include "BLI_math_vector.h"
17
18#include "bmesh.hh"
19#include "bmesh_path_uv.hh" /* own include */
20#include "intern/bmesh_query.hh"
22
23#define COST_INIT_MAX FLT_MAX
24
25/* -------------------------------------------------------------------- */
34static float step_cost_3_v2_ex(
35 const float v1[2], const float v2[2], const float v3[2], bool skip_12, bool skip_23)
36{
37 float d1[2], d2[2];
38
39 /* The cost is based on the simple sum of the length of the two edges. */
40 sub_v2_v2v2(d1, v2, v1);
41 sub_v2_v2v2(d2, v3, v2);
42 const float cost_12 = normalize_v2(d1);
43 const float cost_23 = normalize_v2(d2);
44 const float cost = ((skip_12 ? 0.0f : cost_12) + (skip_23 ? 0.0f : cost_23));
45
46 /* But is biased to give higher values to sharp turns, so that it will take paths with
47 * fewer "turns" when selecting between equal-weighted paths between the two edges. */
48 return cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v2v2(d1, d2)))));
49}
50
51static float step_cost_3_v2(const float v1[2], const float v2[2], const float v3[2])
52{
53 return step_cost_3_v2_ex(v1, v2, v3, false, false);
54}
55
58/* -------------------------------------------------------------------- */
63 BMLoop *l_a,
64 BMLoop **loops_prev,
65 float *cost,
67{
68 BLI_assert(params->aspect_y != 0.0f);
69 const int cd_loop_uv_offset = params->cd_loop_uv_offset;
70 const int l_a_index = BM_elem_index_get(l_a);
71 const float *luv_a = BM_ELEM_CD_GET_FLOAT_P(l_a, cd_loop_uv_offset);
72 const float uv_a[2] = {luv_a[0], luv_a[1] / params->aspect_y};
73
74 {
75 BMIter liter;
76 BMLoop *l;
77 /* Loop over faces of face, but do so by first looping over loops. */
78 BM_ITER_ELEM (l, &liter, l_a->v, BM_LOOPS_OF_VERT) {
79 const float *luv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset);
80 if (equals_v2v2(luv_a, luv)) {
81 /* 'l_a' is already tagged, tag all adjacent. */
83 BMLoop *l_b = l->next;
84 do {
86 const float *luv_b = BM_ELEM_CD_GET_FLOAT_P(l_b, cd_loop_uv_offset);
87 const float uv_b[2] = {luv_b[0], luv_b[1] / params->aspect_y};
88 /* We know 'l_b' is not visited, check it out! */
89 const int l_b_index = BM_elem_index_get(l_b);
90 const float cost_cut = params->use_topology_distance ? 1.0f : len_v2v2(uv_a, uv_b);
91 const float cost_new = cost[l_a_index] + cost_cut;
92
93 if (cost[l_b_index] > cost_new) {
94 cost[l_b_index] = cost_new;
95 loops_prev[l_b_index] = l_a;
96 BLI_heapsimple_insert(heap, cost_new, l_b);
97 }
98 }
99 /* This means we only step onto `l->prev` & `l->next`. */
100 if (params->use_step_face == false) {
101 if (l_b == l->next) {
102 l_b = l->prev->prev;
103 }
104 }
105 } while ((l_b = l_b->next) != l);
106 }
107 }
108 }
109}
110
112 BMLoop *l_src,
113 BMLoop *l_dst,
115 bool (*filter_fn)(BMLoop *, void *),
116 void *user_data)
117{
118 LinkNode *path = nullptr;
119 /* BM_ELEM_TAG flag is used to store visited edges */
120 BMIter viter;
121 HeapSimple *heap;
122 float *cost;
123 BMLoop **loops_prev;
124 int i = 0, totloop;
125 BMFace *f;
126
127 /* NOTE: would pass BM_EDGE except we are looping over all faces anyway. */
128 // BM_mesh_elem_index_ensure(bm, BM_LOOP); /* NOTE: not needed for facetag. */
129
130 BM_ITER_MESH (f, &viter, bm, BM_FACES_OF_MESH) {
131 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
132 BMLoop *l_iter = l_first;
133 do {
134 BM_elem_flag_set(l_iter, BM_ELEM_TAG, !filter_fn(l_iter, user_data));
135 BM_elem_index_set(l_iter, i); /* set_inline */
136 i += 1;
137 } while ((l_iter = l_iter->next) != l_first);
138 }
139 bm->elem_index_dirty &= ~BM_LOOP;
140
141 /* Allocate. */
142 totloop = bm->totloop;
143 loops_prev = static_cast<BMLoop **>(MEM_callocN(sizeof(*loops_prev) * totloop, __func__));
144 cost = static_cast<float *>(MEM_mallocN(sizeof(*cost) * totloop, __func__));
145
146 copy_vn_fl(cost, totloop, COST_INIT_MAX);
147
148 /* Regular dijkstra shortest path, but over UV loops instead of vertices. */
149 heap = BLI_heapsimple_new();
150 BLI_heapsimple_insert(heap, 0.0f, l_src);
151 cost[BM_elem_index_get(l_src)] = 0.0f;
152
153 BMLoop *l = nullptr;
154 while (!BLI_heapsimple_is_empty(heap)) {
155 l = static_cast<BMLoop *>(BLI_heapsimple_pop_min(heap));
156
157 if ((l->v == l_dst->v) && BM_loop_uv_share_vert_check(l, l_dst, params->cd_loop_uv_offset)) {
158 break;
159 }
160
162 /* Adjacent loops are tagged while stepping to avoid 2x loops. */
164 verttag_add_adjacent_uv(heap, l, loops_prev, cost, params);
165 }
166 }
167
168 if ((l->v == l_dst->v) && BM_loop_uv_share_vert_check(l, l_dst, params->cd_loop_uv_offset)) {
169 do {
170 BLI_linklist_prepend(&path, l);
171 } while ((l = loops_prev[BM_elem_index_get(l)]));
172 }
173
174 MEM_freeN(loops_prev);
175 MEM_freeN(cost);
176 BLI_heapsimple_free(heap, nullptr);
177
178 return path;
179}
180
183/* -------------------------------------------------------------------- */
188 BMLoop *l_e_a, BMLoop *l_e_b, BMLoop *l_v, const float aspect_y, const int cd_loop_uv_offset)
189{
190 BMLoop *l_v1 = (l_v->v == l_e_a->v) ? l_e_a->next : l_e_a;
191 BMLoop *l_v2 = (l_v->v == l_e_b->v) ? l_e_b->next : l_e_b;
192
193 float *luv_v1 = BM_ELEM_CD_GET_FLOAT_P(l_v1, cd_loop_uv_offset);
194 float *luv_v2 = BM_ELEM_CD_GET_FLOAT_P(l_v2, cd_loop_uv_offset);
195 float *luv_v = BM_ELEM_CD_GET_FLOAT_P(l_v, cd_loop_uv_offset);
196
197 float uv_v1[2] = {luv_v1[0], luv_v1[1] / aspect_y};
198 float uv_v2[2] = {luv_v2[0], luv_v2[1] / aspect_y};
199 float uv_v[2] = {luv_v[0], luv_v[1] / aspect_y};
200
201 return step_cost_3_v2(uv_v1, uv_v, uv_v2);
202}
203
205 BMLoop *l_e_a, BMLoop *l_e_b, BMFace *f, const float aspect_v2[2], const int cd_loop_uv_offset)
206{
207 float l_e_a_cent[2], l_e_b_cent[2], f_cent[2];
208 float *luv_e_a = BM_ELEM_CD_GET_FLOAT_P(l_e_a, cd_loop_uv_offset);
209 float *luv_e_b = BM_ELEM_CD_GET_FLOAT_P(l_e_b, cd_loop_uv_offset);
210
211 mid_v2_v2v2(l_e_a_cent, luv_e_a, luv_e_a);
212 mid_v2_v2v2(l_e_b_cent, luv_e_b, luv_e_b);
213
214 mul_v2_v2(l_e_a_cent, aspect_v2);
215 mul_v2_v2(l_e_b_cent, aspect_v2);
216
217 BM_face_uv_calc_center_median_weighted(f, aspect_v2, cd_loop_uv_offset, f_cent);
218
219 return step_cost_3_v2(l_e_a_cent, l_e_b_cent, f_cent);
220}
221
223 BMLoop *l_a,
224 BMLoop **loops_prev,
225 float *cost,
227{
228 BLI_assert(params->aspect_y != 0.0f);
229 const int cd_loop_uv_offset = params->cd_loop_uv_offset;
230 BMLoop *l_a_verts[2] = {l_a, l_a->next};
231 const int l_a_index = BM_elem_index_get(l_a);
232
233 if (params->use_step_face == false) {
234 for (int i = 0; i < ARRAY_SIZE(l_a_verts); i++) {
235
236 /* Skip current UV vert if it is part of the previous UV edge in the path. */
237 if (loops_prev[l_a_index]) {
238 BMLoop *l_prev = loops_prev[l_a_index];
239 if (l_a_verts[i]->v != l_prev->v) {
240 l_prev = (l_a_verts[i]->v == l_prev->next->v) ? l_prev->next : nullptr;
241 }
242 if (l_prev && BM_loop_uv_share_vert_check(l_a_verts[i], l_prev, cd_loop_uv_offset)) {
243 continue;
244 }
245 }
246
247 BMEdge *e_b;
248 BMIter eiter;
249 BM_ITER_ELEM (e_b, &eiter, l_a_verts[i]->v, BM_EDGES_OF_VERT) {
250 BMLoop *l_first, *l_b;
251 l_first = l_b = e_b->l;
252 do {
254 BMLoop *l_b_vert = (l_a_verts[i]->v == l_b->v) ? l_b : l_b->next;
255 if (BM_loop_uv_share_vert_check(l_a_verts[i], l_b_vert, cd_loop_uv_offset)) {
256 /* We know 'l_b' is not visited, check it out! */
257 const int l_b_index = BM_elem_index_get(l_b);
258 const float cost_cut = params->use_topology_distance ?
259 1.0f :
261 l_b,
262 l_a_verts[i],
263 params->aspect_y,
264 cd_loop_uv_offset);
265 const float cost_new = cost[l_a_index] + cost_cut;
266
267 if (cost[l_b_index] > cost_new) {
268 cost[l_b_index] = cost_new;
269 loops_prev[l_b_index] = l_a;
270 BLI_heapsimple_insert(heap, cost_new, l_b);
271 }
272 }
273 }
274 } while ((l_b = l_b->radial_next) != l_first);
275 }
276 }
277 }
278 else {
279 const float aspect_v2[2] = {1.0f, 1.0f / params->aspect_y};
280 BMLoop *l_first, *l_iter;
281 l_iter = l_first = l_a;
282 do {
283 /* Ensures connected UVs and that they lie on the same island. */
284 if (!BM_loop_uv_share_edge_check(l_a, l_iter, cd_loop_uv_offset)) {
285 continue;
286 }
287
288 BMLoop *l_cycle_iter, *l_cycle_end;
289 l_cycle_iter = l_iter->next;
290 l_cycle_end = l_iter;
291 do {
292 BMLoop *l_b = l_cycle_iter;
294 /* We know 'l_b' is not visited, check it out! */
295 const int l_b_index = BM_elem_index_get(l_b);
296 const float cost_cut = params->use_topology_distance ?
297 1.0f :
299 l_b,
300 l_iter->f,
301 aspect_v2,
302 params->cd_loop_uv_offset);
303 const float cost_new = cost[l_a_index] + cost_cut;
304
305 if (cost[l_b_index] > cost_new) {
306 cost[l_b_index] = cost_new;
307 loops_prev[l_b_index] = l_a;
308 BLI_heapsimple_insert(heap, cost_new, l_b);
309 }
310 }
311 } while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_end);
312 } while ((l_iter = l_iter->radial_next) != l_first);
313 }
314}
315
317 BMLoop *l_src,
318 BMLoop *l_dst,
320 bool (*filter_fn)(BMLoop *, void *),
321 void *user_data)
322{
323 LinkNode *path = nullptr;
324
325 BMFace *f;
326 BMIter iter;
327 HeapSimple *heap;
328 float *cost;
329 BMLoop **loops_prev;
330 int i = 0, totloop;
331
332 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
333 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
334 BMLoop *l_iter = l_first;
335 do {
336 BM_elem_flag_set(l_iter, BM_ELEM_TAG, !filter_fn(l_iter, user_data));
337 BM_elem_index_set(l_iter, i);
338 i += 1;
339 } while ((l_iter = l_iter->next) != l_first);
340 }
341 bm->elem_index_dirty &= ~BM_LOOP;
342
343 totloop = bm->totloop;
344 loops_prev = static_cast<BMLoop **>(MEM_callocN(sizeof(*loops_prev) * totloop, __func__));
345 cost = static_cast<float *>(MEM_mallocN(sizeof(*cost) * totloop, __func__));
346
347 copy_vn_fl(cost, totloop, COST_INIT_MAX);
348
349 /* Regular dijkstra shortest path, but over UV loops/edges instead of vertices. */
350 heap = BLI_heapsimple_new();
351 BLI_heapsimple_insert(heap, 0.0f, l_src);
352 cost[BM_elem_index_get(l_src)] = 0.0f;
353
354 BMLoop *l = nullptr;
355 while (!BLI_heapsimple_is_empty(heap)) {
356 l = static_cast<BMLoop *>(BLI_heapsimple_pop_min(heap));
357
358 if ((l->e == l_dst->e) && BM_loop_uv_share_edge_check(l, l_dst, params->cd_loop_uv_offset)) {
359 break;
360 }
361
364 edgetag_add_adjacent_uv(heap, l, loops_prev, cost, params);
365 }
366 }
367
368 if ((l->e == l_dst->e) && BM_loop_uv_share_edge_check(l, l_dst, params->cd_loop_uv_offset)) {
369 do {
370 BLI_linklist_prepend(&path, l);
371 } while ((l = loops_prev[BM_elem_index_get(l)]));
372 }
373
374 MEM_freeN(loops_prev);
375 MEM_freeN(cost);
376 BLI_heapsimple_free(heap, nullptr);
377
378 return path;
379}
380
383/* -------------------------------------------------------------------- */
388 BMFace *f_b,
389 BMLoop *l_edge,
390 const void *const f_endpoints[2],
391 const float aspect_v2[2],
392 const int cd_loop_uv_offset)
393{
394 float f_a_cent[2];
395 float f_b_cent[2];
396 float e_cent[2];
397
398 BM_face_uv_calc_center_median_weighted(f_a, aspect_v2, cd_loop_uv_offset, f_a_cent);
399 BM_face_uv_calc_center_median_weighted(f_b, aspect_v2, cd_loop_uv_offset, f_b_cent);
400
401 const float *co_v1 = BM_ELEM_CD_GET_FLOAT_P(l_edge, cd_loop_uv_offset);
402 const float *co_v2 = BM_ELEM_CD_GET_FLOAT_P(l_edge->next, cd_loop_uv_offset);
403
404#if 0
405 mid_v2_v2v2(e_cent, co_v1, co_v2);
406#else
407 /* For triangle fans it gives better results to pick a point on the edge. */
408 {
409 float ix_e[2];
410 isect_line_line_v2_point(co_v1, co_v2, f_a_cent, f_b_cent, ix_e);
411 const float factor = line_point_factor_v2(ix_e, co_v1, co_v2);
412 if (factor < 0.0f) {
413 copy_v2_v2(e_cent, co_v1);
414 }
415 else if (factor > 1.0f) {
416 copy_v2_v2(e_cent, co_v2);
417 }
418 else {
419 copy_v2_v2(e_cent, ix_e);
420 }
421 }
422#endif
423
424 /* Apply aspect before calculating cost. */
425 mul_v2_v2(f_a_cent, aspect_v2);
426 mul_v2_v2(f_b_cent, aspect_v2);
427 mul_v2_v2(e_cent, aspect_v2);
428
429 return step_cost_3_v2_ex(
430 f_a_cent, e_cent, f_b_cent, (f_a == f_endpoints[0]), (f_b == f_endpoints[1]));
431}
432
434 BMFace *f_b,
435 BMLoop *l_vert,
436 const void *const f_endpoints[2],
437 const float aspect_v2[2],
438 const int cd_loop_uv_offset)
439{
440 float f_a_cent[2];
441 float f_b_cent[2];
442 float v_cent[2];
443
444 BM_face_uv_calc_center_median_weighted(f_a, aspect_v2, cd_loop_uv_offset, f_a_cent);
445 BM_face_uv_calc_center_median_weighted(f_b, aspect_v2, cd_loop_uv_offset, f_b_cent);
446
447 copy_v2_v2(v_cent, BM_ELEM_CD_GET_FLOAT_P(l_vert, cd_loop_uv_offset));
448
449 mul_v2_v2(f_a_cent, aspect_v2);
450 mul_v2_v2(f_b_cent, aspect_v2);
451 mul_v2_v2(v_cent, aspect_v2);
452
453 return step_cost_3_v2_ex(
454 f_a_cent, v_cent, f_b_cent, (f_a == f_endpoints[0]), (f_b == f_endpoints[1]));
455}
456
458 BMFace *f_a,
459 BMFace **faces_prev,
460 float *cost,
461 const void *const f_endpoints[2],
462 const float aspect_v2[2],
464{
465 const int cd_loop_uv_offset = params->cd_loop_uv_offset;
466 const int f_a_index = BM_elem_index_get(f_a);
467
468 /* Loop over faces of face, but do so by first looping over loops. */
469 {
470 BMIter liter;
471 BMLoop *l_a;
472
473 BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
474 BMLoop *l_first, *l_iter;
475
476 /* Check there is an adjacent face to loop over. */
477 if (l_a != l_a->radial_next) {
478 l_iter = l_first = l_a->radial_next;
479 do {
480 BMFace *f_b = l_iter->f;
481 if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
482 if (BM_loop_uv_share_edge_check(l_a, l_iter, cd_loop_uv_offset)) {
483 /* We know 'f_b' is not visited, check it out! */
484 const int f_b_index = BM_elem_index_get(f_b);
485 const float cost_cut =
486 params->use_topology_distance ?
487 1.0f :
489 f_a, f_b, l_iter, f_endpoints, aspect_v2, cd_loop_uv_offset);
490 const float cost_new = cost[f_a_index] + cost_cut;
491
492 if (cost[f_b_index] > cost_new) {
493 cost[f_b_index] = cost_new;
494 faces_prev[f_b_index] = f_a;
495 BLI_heapsimple_insert(heap, cost_new, f_b);
496 }
497 }
498 }
499 } while ((l_iter = l_iter->radial_next) != l_first);
500 }
501 }
502 }
503
504 if (params->use_step_face) {
505 BMIter liter;
506 BMLoop *l_a;
507
508 BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
509 BMIter litersub;
510 BMLoop *l_b;
511 BM_ITER_ELEM (l_b, &litersub, l_a->v, BM_LOOPS_OF_VERT) {
512 if ((l_a != l_b) && !BM_loop_share_edge_check(l_a, l_b)) {
513 BMFace *f_b = l_b->f;
514 if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
515 if (BM_loop_uv_share_vert_check(l_a, l_b, cd_loop_uv_offset)) {
516 /* We know 'f_b' is not visited, check it out! */
517 const int f_b_index = BM_elem_index_get(f_b);
518 const float cost_cut =
519 params->use_topology_distance ?
520 1.0f :
522 f_a, f_b, l_a, f_endpoints, aspect_v2, cd_loop_uv_offset);
523 const float cost_new = cost[f_a_index] + cost_cut;
524
525 if (cost[f_b_index] > cost_new) {
526 cost[f_b_index] = cost_new;
527 faces_prev[f_b_index] = f_a;
528 BLI_heapsimple_insert(heap, cost_new, f_b);
529 }
530 }
531 }
532 }
533 }
534 }
535 }
536}
537
539 BMFace *f_src,
540 BMFace *f_dst,
542 bool (*filter_fn)(BMFace *, void *),
543 void *user_data)
544{
545 const float aspect_v2[2] = {1.0f, 1.0f / params->aspect_y};
546 LinkNode *path = nullptr;
547 /* BM_ELEM_TAG flag is used to store visited edges */
548 BMIter fiter;
549 HeapSimple *heap;
550 float *cost;
551 BMFace **faces_prev;
552 int i = 0, totface;
553
554 /* Start measuring face path at the face edges, ignoring their centers. */
555 const void *const f_endpoints[2] = {f_src, f_dst};
556
557 /* NOTE: would pass BM_EDGE except we are looping over all faces anyway. */
558 // BM_mesh_elem_index_ensure(bm, BM_LOOP); /* NOTE: not needed for facetag. */
559
560 {
561 BMFace *f;
562 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
563 BM_elem_flag_set(f, BM_ELEM_TAG, !filter_fn(f, user_data));
564 BM_elem_index_set(f, i); /* set_inline */
565 i += 1;
566 }
567 bm->elem_index_dirty &= ~BM_FACE;
568 }
569
570 /* Allocate. */
571 totface = bm->totface;
572 faces_prev = static_cast<BMFace **>(MEM_callocN(sizeof(*faces_prev) * totface, __func__));
573 cost = static_cast<float *>(MEM_mallocN(sizeof(*cost) * totface, __func__));
574
575 copy_vn_fl(cost, totface, COST_INIT_MAX);
576
577 /* Regular dijkstra shortest path, but over UV faces instead of vertices. */
578 heap = BLI_heapsimple_new();
579 BLI_heapsimple_insert(heap, 0.0f, f_src);
580 cost[BM_elem_index_get(f_src)] = 0.0f;
581
582 BMFace *f = nullptr;
583 while (!BLI_heapsimple_is_empty(heap)) {
584 f = static_cast<BMFace *>(BLI_heapsimple_pop_min(heap));
585
586 if (f == f_dst) {
587 break;
588 }
589
591 /* Adjacent loops are tagged while stepping to avoid 2x loops. */
593 facetag_add_adjacent_uv(heap, f, faces_prev, cost, f_endpoints, aspect_v2, params);
594 }
595 }
596
597 if (f == f_dst) {
598 do {
599 BLI_linklist_prepend(&path, f);
600 } while ((f = faces_prev[BM_elem_index_get(f)]));
601 }
602
603 MEM_freeN(faces_prev);
604 MEM_freeN(cost);
605 BLI_heapsimple_free(heap, nullptr);
606
607 return path;
608}
609
#define BLI_assert(a)
Definition BLI_assert.h:50
A min-heap / priority queue ADT.
HeapSimple * BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1)
void * BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1)
bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1)
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1)
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2])
int isect_line_line_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
MINLINE void mul_v2_v2(float r[2], const float a[2])
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
void copy_vn_fl(float *array_tar, int size, float val)
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
void mid_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v2(float n[2])
#define ARRAY_SIZE(arr)
Read Guarded memory(de)allocation.
@ BM_ELEM_TAG
#define BM_FACE_FIRST_LOOP(p)
#define BM_ELEM_CD_GET_FLOAT_P(ele, offset)
#define BM_elem_index_get(ele)
#define BM_elem_flag_set(ele, hflag, val)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(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)
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_EDGES_OF_VERT
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
static float edgetag_cut_cost_face_uv(BMLoop *l_e_a, BMLoop *l_e_b, BMFace *f, const float aspect_v2[2], const int cd_loop_uv_offset)
LinkNode * BM_mesh_calc_path_uv_edge(BMesh *bm, BMLoop *l_src, BMLoop *l_dst, const BMCalcPathUVParams *params, bool(*filter_fn)(BMLoop *, void *), void *user_data)
#define COST_INIT_MAX
static float edgetag_cut_cost_vert_uv(BMLoop *l_e_a, BMLoop *l_e_b, BMLoop *l_v, const float aspect_y, const int cd_loop_uv_offset)
static void facetag_add_adjacent_uv(HeapSimple *heap, BMFace *f_a, BMFace **faces_prev, float *cost, const void *const f_endpoints[2], const float aspect_v2[2], const BMCalcPathUVParams *params)
static void edgetag_add_adjacent_uv(HeapSimple *heap, BMLoop *l_a, BMLoop **loops_prev, float *cost, const BMCalcPathUVParams *params)
static float step_cost_3_v2(const float v1[2], const float v2[2], const float v3[2])
static void verttag_add_adjacent_uv(HeapSimple *heap, BMLoop *l_a, BMLoop **loops_prev, float *cost, const BMCalcPathUVParams *params)
LinkNode * BM_mesh_calc_path_uv_vert(BMesh *bm, BMLoop *l_src, BMLoop *l_dst, const BMCalcPathUVParams *params, bool(*filter_fn)(BMLoop *, void *), void *user_data)
LinkNode * BM_mesh_calc_path_uv_face(BMesh *bm, BMFace *f_src, BMFace *f_dst, const BMCalcPathUVParams *params, bool(*filter_fn)(BMFace *, void *), void *user_data)
static float step_cost_3_v2_ex(const float v1[2], const float v2[2], const float v3[2], bool skip_12, bool skip_23)
static float facetag_cut_cost_edge_uv(BMFace *f_a, BMFace *f_b, BMLoop *l_edge, const void *const f_endpoints[2], const float aspect_v2[2], const int cd_loop_uv_offset)
static float facetag_cut_cost_vert_uv(BMFace *f_a, BMFace *f_b, BMLoop *l_vert, const void *const f_endpoints[2], const float aspect_v2[2], const int cd_loop_uv_offset)
bool BM_loop_share_edge_check(BMLoop *l_a, BMLoop *l_b)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
ATTR_WARN_UNUSED_RESULT const BMVert * v
bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
void BM_face_uv_calc_center_median_weighted(const BMFace *f, const float aspect[2], const int cd_loop_uv_offset, float r_cent[2])
#define fabsf(x)
#define sqrtf(x)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
struct BMLoop * l
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
char elem_index_dirty
int totloop
int totface