Blender V4.3
uv_parametrizer.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
9#include <functional>
10#include <vector>
11
13
14#include "BLI_array.hh"
15#include "BLI_convexhull_2d.h"
16#include "BLI_ghash.h"
17#include "BLI_math_geom.h"
18#include "BLI_math_matrix.h"
19#include "BLI_math_rotation.h"
20#include "BLI_math_vector.h"
21#include "BLI_polyfill_2d.h"
23#include "BLI_rand.h"
24
25#ifdef WITH_UV_SLIM
26# include "slim_matrix_transfer.h"
27#endif
28
29#include "GEO_uv_pack.hh"
30
31#include "eigen_capi.h"
32
33/* Utils */
34
35namespace blender::geometry {
36
37#define param_warning(message) \
38 {/* `printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);` */}(void)0
39
40/* Prevent unused function warnings when slim is disabled. */
41#ifdef WITH_UV_SLIM
42# define UNUSED_FUNCTION_NO_SLIM(x) x
43#else
44# define UNUSED_FUNCTION_NO_SLIM UNUSED_FUNCTION
45#endif
46
47/* Special Purpose Hash */
48
50
55
61
62/* Simplices */
63
64struct PVert {
66
67 union PVertUnion {
68 PHashKey key; /* Construct. */
69 int id; /* ABF/LSCM matrix index. */
70 HeapNode *heaplink; /* Edge collapsing. */
71 } u;
72
73 struct PEdge *edge;
74 float co[3];
75 float uv[2];
77
78 float weight;
81};
82
83struct PEdge {
85
86 union PEdgeUnion {
87 PHashKey key; /* Construct. */
88 int id; /* ABF matrix index. */
89 HeapNode *heaplink; /* Fill holes. */
90 PEdge *nextcollapse; /* Simplification. */
91 } u;
92
96 struct PFace *face;
97 float *orig_uv, old_uv[2];
99};
100
101struct PFace {
103
105 PHashKey key; /* Construct. */
106 int chart; /* Construct splitting. */
107 float area3d; /* Stretch. */
108 int id; /* ABF matrix index. */
109 } u;
110
113};
114
122
134
135/* for flipping faces */
136#define PEDGE_VERTEX_FLAGS (PEDGE_PIN)
137
144
145/* Chart */
146
172
173/* PHash
174 * - special purpose hash that keeps all its elements in a single linked list.
175 * - after construction, this hash is thrown away, and the list remains.
176 * - removing elements is not possible efficiently.
177 */
178
179static int PHashSizes[] = {
180 1, 3, 5, 11, 17, 37, 67, 131, 257, 521,
181 1031, 2053, 4099, 8209, 16411, 32771, 65537, 131101, 262147, 524309,
182 1048583, 2097169, 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459,
183};
184
185#define PHASH_hash(ph, item) (uintptr_t(item) % uint((ph)->cursize))
186#define PHASH_edge(v1, v2) (((v1) < (v2)) ? ((v1) * 39) ^ ((v2) * 31) : ((v1) * 31) ^ ((v2) * 39))
187
188static PHash *phash_new(PHashLink **list, int sizehint)
189{
190 PHash *ph = (PHash *)MEM_callocN(sizeof(PHash), "PHash");
191 ph->size = 0;
192 ph->cursize_id = 0;
193 ph->list = list;
194
195 while (PHashSizes[ph->cursize_id] < sizehint) {
196 ph->cursize_id++;
197 }
198
199 ph->cursize = PHashSizes[ph->cursize_id];
200 ph->buckets = (PHashLink **)MEM_callocN(ph->cursize * sizeof(*ph->buckets), "PHashBuckets");
201
202 return ph;
203}
204
205static void phash_safe_delete(PHash **pph)
206{
207 if (!*pph) {
208 return;
209 }
210 MEM_SAFE_FREE((*pph)->buckets);
211 MEM_freeN(*pph);
212 *pph = nullptr;
213}
214
215static int phash_size(PHash *ph)
216{
217 return ph->size;
218}
219
220static void phash_insert(PHash *ph, PHashLink *link)
221{
222 int size = ph->cursize;
223 uintptr_t hash = PHASH_hash(ph, link->key);
224 PHashLink *lookup = ph->buckets[hash];
225
226 if (lookup == nullptr) {
227 /* insert in front of the list */
228 ph->buckets[hash] = link;
229 link->next = *(ph->list);
230 *(ph->list) = link;
231 }
232 else {
233 /* insert after existing element */
234 link->next = lookup->next;
235 lookup->next = link;
236 }
237
238 ph->size++;
239
240 if (ph->size > (size * 3)) {
241 PHashLink *next = nullptr, *first = *(ph->list);
242
243 ph->cursize = PHashSizes[++ph->cursize_id];
244 MEM_freeN(ph->buckets);
245 ph->buckets = (PHashLink **)MEM_callocN(ph->cursize * sizeof(*ph->buckets), "PHashBuckets");
246 ph->size = 0;
247 *(ph->list) = nullptr;
248
249 for (link = first; link; link = next) {
250 next = link->next;
251 phash_insert(ph, link);
252 }
253 }
254}
255
257{
258 PHashLink *link;
259 uintptr_t hash = PHASH_hash(ph, key);
260
261 for (link = ph->buckets[hash]; link; link = link->next) {
262 if (link->key == key) {
263 return link;
264 }
265 if (PHASH_hash(ph, link->key) != hash) {
266 return nullptr;
267 }
268 }
269
270 return link;
271}
272
274{
275 uintptr_t hash = PHASH_hash(ph, key);
276
277 for (link = link->next; link; link = link->next) {
278 if (link->key == key) {
279 return link;
280 }
281 if (PHASH_hash(ph, link->key) != hash) {
282 return nullptr;
283 }
284 }
285
286 return link;
287}
288
289/* Angles close to 0 or 180 degrees cause rows filled with zeros in the linear_solver.
290 * The matrix will then be rank deficient and / or have poor conditioning.
291 * => Reduce the maximum angle to 179 degrees, and spread the remainder to the other angles.
292 */
293static void fix_large_angle(const float v_fix[3],
294 const float v1[3],
295 const float v2[3],
296 double *r_fix,
297 double *r_a1,
298 double *r_a2)
299{
300 const double max_angle = DEG2RADF(179.0);
301 const double fix_amount = *r_fix - max_angle;
302 if (fix_amount < 0.0f) {
303 return; /* angle is reasonable, i.e. less than 179 degrees. */
304 }
305
306 /* The triangle is probably degenerate, or close to it.
307 * Without loss of generality, transform the triangle such that
308 * v_fix == { 0, s}, *r_fix = 180 degrees
309 * v1 == {-x1, 0}, *r_a1 = 0
310 * v2 == { x2, 0}, *r_a2 = 0
311 *
312 * With `s = 0`, `x1 > 0`, `x2 > 0`
313 *
314 * Now make `s` a small number and do some math:
315 * tan(*r_a1) = s / x1
316 * tan(*r_a2) = s / x2
317 *
318 * Remember that `tan(angle) ~= angle`
319 *
320 * Rearrange to obtain:
321 * *r_a1 = fix_amount * x2 / (x1 + x2)
322 * *r_a2 = fix_amount * x1 / (x1 + x2)
323 */
324
325 const double dist_v1 = len_v3v3(v_fix, v1);
326 const double dist_v2 = len_v3v3(v_fix, v2);
327 const double sum = dist_v1 + dist_v2;
328 const double weight = (sum > 1e-20f) ? dist_v2 / sum : 0.5f;
329
330 /* Ensure sum of angles in triangle is unchanged. */
331 *r_fix -= fix_amount;
332 *r_a1 += fix_amount * weight;
333 *r_a2 += fix_amount * (1.0f - weight);
334}
335
336static void p_triangle_angles(const float v1[3],
337 const float v2[3],
338 const float v3[3],
339 double *r_a1,
340 double *r_a2,
341 double *r_a3)
342{
343 *r_a1 = angle_v3v3v3(v3, v1, v2);
344 *r_a2 = angle_v3v3v3(v1, v2, v3);
345 *r_a3 = angle_v3v3v3(v2, v3, v1);
346
347 /* Fix for degenerate geometry e.g. v1 = sum(v2 + v3). See #100874 */
348 fix_large_angle(v1, v2, v3, r_a1, r_a2, r_a3);
349 fix_large_angle(v2, v3, v1, r_a2, r_a3, r_a1);
350 fix_large_angle(v3, v1, v2, r_a3, r_a1, r_a2);
351
352 /* Workaround for degenerate geometry, e.g. v1 == v2 == v3. */
353 *r_a1 = max_dd(*r_a1, 0.001f);
354 *r_a2 = max_dd(*r_a2, 0.001f);
355 *r_a3 = max_dd(*r_a3, 0.001f);
356}
357
358static void p_face_angles(PFace *f, double *r_a1, double *r_a2, double *r_a3)
359{
360 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
361 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
362
363 p_triangle_angles(v1->co, v2->co, v3->co, r_a1, r_a2, r_a3);
364}
365
366static float p_vec_cos(const float v1[3], const float v2[3], const float v3[3])
367{
368 return cos_v3v3v3(v1, v2, v3);
369}
370
371static void p_triangle_cos(const float v1[3],
372 const float v2[3],
373 const float v3[3],
374 float *r_cos1,
375 float *r_cos2,
376 float *r_cos3)
377{
378 *r_cos1 = p_vec_cos(v3, v1, v2);
379 *r_cos2 = p_vec_cos(v1, v2, v3);
380 *r_cos3 = p_vec_cos(v2, v3, v1);
381}
382
383static void UNUSED_FUNCTION(p_face_cos)(PFace *f, float *r_cos1, float *r_cos2, float *r_cos3)
384{
385 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
386 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
387
388 p_triangle_cos(v1->co, v2->co, v3->co, r_cos1, r_cos2, r_cos3);
389}
390
391static float p_face_area(PFace *f)
392{
393 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
394 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
395
396 return area_tri_v3(v1->co, v2->co, v3->co);
397}
398
399static float p_area_signed(const float v1[2], const float v2[2], const float v3[2])
400{
401 return 0.5f * (((v2[0] - v1[0]) * (v3[1] - v1[1])) - ((v3[0] - v1[0]) * (v2[1] - v1[1])));
402}
403
405{
406 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
407 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
408
409 return 0.5f * (((v2->uv[0] - v1->uv[0]) * (v3->uv[1] - v1->uv[1])) -
410 ((v3->uv[0] - v1->uv[0]) * (v2->uv[1] - v1->uv[1])));
411}
412
413static float p_edge_length(PEdge *e)
414{
415 return len_v3v3(e->vert->co, e->next->vert->co);
416}
417
419{
420 return len_squared_v3v3(e->vert->co, e->next->vert->co);
421}
422
424{
425 return len_v2v2(e->vert->uv, e->next->vert->uv);
426}
427
428static void p_chart_uv_bbox(PChart *chart, float minv[2], float maxv[2])
429{
430 PVert *v;
431
432 INIT_MINMAX2(minv, maxv);
433
434 for (v = chart->verts; v; v = v->nextlink) {
435 minmax_v2v2_v2(minv, maxv, v->uv);
436 }
437}
438
439static float p_chart_uv_area(PChart *chart)
440{
441 float area = 0.0f;
442
443 for (PFace *f = chart->faces; f; f = f->nextlink) {
444 area += fabsf(p_face_uv_area_signed(f));
445 }
446
447 return area;
448}
449
450static void p_chart_uv_scale(PChart *chart, const float scale)
451{
452 if (scale == 1.0f) {
453 return; /* Identity transform. */
454 }
455
456 for (PVert *v = chart->verts; v; v = v->nextlink) {
457 v->uv[0] *= scale;
458 v->uv[1] *= scale;
459 }
460}
461
462static void uv_parametrizer_scale_x(ParamHandle *phandle, const float scale_x)
463{
464 if (scale_x == 1.0f) {
465 return; /* Identity transform. */
466 }
467
468 /* Scale every chart. */
469 for (int i = 0; i < phandle->ncharts; i++) {
470 PChart *chart = phandle->charts[i];
471 for (PVert *v = chart->verts; v; v = v->nextlink) {
472 v->uv[0] *= scale_x; /* Only scale x axis. */
473 }
474 }
475}
476
477static void p_chart_uv_translate(PChart *chart, const float trans[2])
478{
479 for (PVert *v = chart->verts; v; v = v->nextlink) {
480 v->uv[0] += trans[0];
481 v->uv[1] += trans[1];
482 }
483}
484
485static void p_chart_uv_transform(PChart *chart, const float mat[2][2])
486{
487 for (PVert *v = chart->verts; v; v = v->nextlink) {
488 mul_m2_v2(mat, v->uv);
489 }
490}
491
492static void p_chart_uv_to_array(PChart *chart, float (*points)[2])
493{
494 PVert *v;
495 uint i = 0;
496
497 for (v = chart->verts; v; v = v->nextlink) {
498 copy_v2_v2(points[i++], v->uv);
499 }
500}
501
502static bool p_intersect_line_2d_dir(const float v1[2],
503 const float dir1[2],
504 const float v2[2],
505 const float dir2[2],
506 float r_isect[2])
507{
508 float lmbda, div;
509
510 div = dir2[0] * dir1[1] - dir2[1] * dir1[0];
511
512 if (div == 0.0f) {
513 return false;
514 }
515
516 lmbda = ((v1[1] - v2[1]) * dir1[0] - (v1[0] - v2[0]) * dir1[1]) / div;
517 r_isect[0] = v1[0] + lmbda * dir2[0];
518 r_isect[1] = v1[1] + lmbda * dir2[1];
519
520 return true;
521}
522
523/* Topological Utilities */
524
526{
527 return e->next->next->pair;
528}
529
530static const PEdge *p_wheel_edge_next(const PEdge *e)
531{
532 return e->next->next->pair;
533}
534
536{
537 return (e->pair) ? e->pair->next : nullptr;
538}
539
541{
542 return e->next->vert->edge;
543}
544
546{
547 PEdge *we = e, *last;
548
549 do {
550 last = we;
551 we = p_wheel_edge_next(we);
552 } while (we && (we != e));
553
554 return last->next->next;
555}
556
558{
559 return v->edge->pair;
560}
561
562static void p_face_flip(PFace *f)
563{
564 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
565 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
566 int f1 = e1->flag, f2 = e2->flag, f3 = e3->flag;
567 float *orig_uv1 = e1->orig_uv, *orig_uv2 = e2->orig_uv, *orig_uv3 = e3->orig_uv;
568
569 e1->vert = v2;
570 e1->next = e3;
571 e1->orig_uv = orig_uv2;
572 e1->flag = (f1 & ~PEDGE_VERTEX_FLAGS) | (f2 & PEDGE_VERTEX_FLAGS);
573
574 e2->vert = v3;
575 e2->next = e1;
576 e2->orig_uv = orig_uv3;
577 e2->flag = (f2 & ~PEDGE_VERTEX_FLAGS) | (f3 & PEDGE_VERTEX_FLAGS);
578
579 e3->vert = v1;
580 e3->next = e2;
581 e3->orig_uv = orig_uv1;
582 e3->flag = (f3 & ~PEDGE_VERTEX_FLAGS) | (f1 & PEDGE_VERTEX_FLAGS);
583}
584
585#if 0
586static void p_chart_topological_sanity_check(PChart *chart)
587{
588 PVert *v;
589 PEdge *e;
590
591 for (v = chart->verts; v; v = v->nextlink) {
592 GEO_uv_parametrizer_test_equals_ptr("v->edge->vert", v, v->edge->vert);
593 }
594
595 for (e = chart->edges; e; e = e->nextlink) {
596 if (e->pair) {
597 GEO_uv_parametrizer_test_equals_ptr("e->pair->pair", e, e->pair->pair);
598 GEO_uv_parametrizer_test_equals_ptr("pair->vert", e->vert, e->pair->next->vert);
599 GEO_uv_parametrizer_test_equals_ptr("pair->next->vert", e->next->vert, e->pair->vert);
600 }
601 }
602}
603#endif
604
605/* Loading / Flushing */
606
608{
609 PEdge *e;
610 int nedges = 0, npins = 0;
611 float pinuv[2];
612
613 v->uv[0] = v->uv[1] = 0.0f;
614 pinuv[0] = pinuv[1] = 0.0f;
615 e = v->edge;
616 do {
617 if (e->orig_uv) {
618 if (e->flag & PEDGE_SELECT) {
619 v->flag |= PVERT_SELECT;
620 }
621
622 if (e->flag & PEDGE_PIN) {
623 pinuv[0] += e->orig_uv[0] * handle->aspect_y;
624 pinuv[1] += e->orig_uv[1];
625 npins++;
626 }
627 else {
628 v->uv[0] += e->orig_uv[0] * handle->aspect_y;
629 v->uv[1] += e->orig_uv[1];
630 }
631
632 nedges++;
633 }
634
636 } while (e && e != (v->edge));
637
638 if (npins > 0) {
639 v->uv[0] = pinuv[0] / npins;
640 v->uv[1] = pinuv[1] / npins;
641 v->flag |= PVERT_PIN;
642 }
643 else if (nedges > 0) {
644 v->uv[0] /= nedges;
645 v->uv[1] /= nedges;
646 }
647}
648
649static void p_chart_flush_collapsed_uvs(PChart *chart);
650
651static void p_flush_uvs(ParamHandle *handle, PChart *chart)
652{
653 const float blend = handle->blend;
654 const float invblend = 1.0f - blend;
655 const float invblend_x = invblend / handle->aspect_y;
656 for (PEdge *e = chart->edges; e; e = e->nextlink) {
657 if (e->orig_uv) {
658 e->orig_uv[0] = blend * e->old_uv[0] + invblend_x * e->vert->uv[0];
659 e->orig_uv[1] = blend * e->old_uv[1] + invblend * e->vert->uv[1];
660 }
661 }
662
663 if (chart->collapsed_edges) {
665
666 for (PEdge *e = chart->collapsed_edges; e; e = e->nextlink) {
667 if (e->orig_uv) {
668 e->orig_uv[0] = blend * e->old_uv[0] + invblend_x * e->vert->uv[0];
669 e->orig_uv[1] = blend * e->old_uv[1] + invblend * e->vert->uv[1];
670 }
671 }
672 }
673}
674
676{
677 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
678
679 if (e1->orig_uv) {
680 e1->old_uv[0] = e1->orig_uv[0];
681 e1->old_uv[1] = e1->orig_uv[1];
682 }
683 if (e2->orig_uv) {
684 e2->old_uv[0] = e2->orig_uv[0];
685 e2->old_uv[1] = e2->orig_uv[1];
686 }
687 if (e3->orig_uv) {
688 e3->old_uv[0] = e3->orig_uv[0];
689 e3->old_uv[1] = e3->orig_uv[1];
690 }
691}
692
694{
695 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
696
697 if (e1->orig_uv) {
698 e1->orig_uv[0] = e1->old_uv[0];
699 e1->orig_uv[1] = e1->old_uv[1];
700 }
701 if (e2->orig_uv) {
702 e2->orig_uv[0] = e2->old_uv[0];
703 e2->orig_uv[1] = e2->old_uv[1];
704 }
705 if (e3->orig_uv) {
706 e3->orig_uv[0] = e3->old_uv[0];
707 e3->orig_uv[1] = e3->old_uv[1];
708 }
709}
710
711/* Construction (use only during construction, relies on u.key being set */
712
714 ParamHandle *handle, PHashKey key, const float co[3], const float weight, PEdge *e)
715{
716 PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v));
717 copy_v3_v3(v->co, co);
718 v->weight = weight;
719
720 /* Sanity check, a single nan/inf point causes the entire result to be invalid.
721 * Note that values within the calculation may _become_ non-finite,
722 * so the rest of the code still needs to take this possibility into account. */
723 for (int i = 0; i < 3; i++) {
724 if (UNLIKELY(!isfinite(v->co[i]))) {
725 v->co[i] = 0.0f;
726 }
727 }
728
729 v->u.key = key;
730 v->edge = e;
731 v->flag = 0;
732
733 /* Unused, prevent uninitialized memory access on duplication. */
734 v->on_boundary_flag = false;
735 v->slim_id = 0;
736
737 phash_insert(handle->hash_verts, (PHashLink *)v);
738
739 return v;
740}
741
743 ParamHandle *handle, PHashKey key, const float co[3], const float weight, PEdge *e)
744{
745 PVert *v = (PVert *)phash_lookup(handle->hash_verts, key);
746
747 if (v) {
748 return v;
749 }
750 return p_vert_add(handle, key, co, weight, e);
751}
752
754{
755 PVert *nv = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*nv));
756
757 copy_v3_v3(nv->co, v->co);
758 nv->uv[0] = v->uv[0];
759 nv->uv[1] = v->uv[1];
760 nv->u.key = v->u.key;
761 nv->edge = v->edge;
762 nv->flag = v->flag;
763
764 nv->weight = v->weight;
765 nv->on_boundary_flag = v->on_boundary_flag;
766 nv->slim_id = v->slim_id;
767
768 return nv;
769}
770
771static PEdge *p_edge_lookup(ParamHandle *handle, const PHashKey *vkeys)
772{
773 PHashKey key = PHASH_edge(vkeys[0], vkeys[1]);
774 PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
775
776 while (e) {
777 if ((e->vert->u.key == vkeys[0]) && (e->next->vert->u.key == vkeys[1])) {
778 return e;
779 }
780 if ((e->vert->u.key == vkeys[1]) && (e->next->vert->u.key == vkeys[0])) {
781 return e;
782 }
783
784 e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e);
785 }
786
787 return nullptr;
788}
789
790static int p_face_exists(ParamHandle *handle, const ParamKey *pvkeys, int i1, int i2, int i3)
791{
792 PHashKey *vkeys = (PHashKey *)pvkeys;
793 PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]);
794 PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
795
796 while (e) {
797 if ((e->vert->u.key == vkeys[i1]) && (e->next->vert->u.key == vkeys[i2])) {
798 if (e->next->next->vert->u.key == vkeys[i3]) {
799 return true;
800 }
801 }
802 else if ((e->vert->u.key == vkeys[i2]) && (e->next->vert->u.key == vkeys[i1])) {
803 if (e->next->next->vert->u.key == vkeys[i3]) {
804 return true;
805 }
806 }
807
808 e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e);
809 }
810
811 return false;
812}
813
815{
816 const float *uv1, *uv2, *uvp1, *uvp2;
817 float limit[2];
818
819 limit[0] = 0.00001;
820 limit[1] = 0.00001;
821
822 uv1 = e->orig_uv;
823 uv2 = e->next->orig_uv;
824
825 if (e->vert->u.key == ep->vert->u.key) {
826 uvp1 = ep->orig_uv;
827 uvp2 = ep->next->orig_uv;
828 }
829 else {
830 uvp1 = ep->next->orig_uv;
831 uvp2 = ep->orig_uv;
832 }
833
834 if ((fabsf(uv1[0] - uvp1[0]) > limit[0]) || (fabsf(uv1[1] - uvp1[1]) > limit[1])) {
835 e->flag |= PEDGE_SEAM;
836 ep->flag |= PEDGE_SEAM;
837 return true;
838 }
839 if ((fabsf(uv2[0] - uvp2[0]) > limit[0]) || (fabsf(uv2[1] - uvp2[1]) > limit[1])) {
840 e->flag |= PEDGE_SEAM;
841 ep->flag |= PEDGE_SEAM;
842 return true;
843 }
844
845 return false;
846}
847
848static bool p_edge_has_pair(ParamHandle *handle, PEdge *e, bool topology_from_uvs, PEdge **r_pair)
849{
850 PHashKey key;
851 PEdge *pe;
852 const PVert *v1, *v2;
853 PHashKey key1 = e->vert->u.key;
854 PHashKey key2 = e->next->vert->u.key;
855
856 if (e->flag & PEDGE_SEAM) {
857 return false;
858 }
859
860 key = PHASH_edge(key1, key2);
861 pe = (PEdge *)phash_lookup(handle->hash_edges, key);
862 *r_pair = nullptr;
863
864 while (pe) {
865 if (pe != e) {
866 v1 = pe->vert;
867 v2 = pe->next->vert;
868
869 if (((v1->u.key == key1) && (v2->u.key == key2)) ||
870 ((v1->u.key == key2) && (v2->u.key == key1)))
871 {
872
873 /* don't connect seams and t-junctions */
874 if ((pe->flag & PEDGE_SEAM) || *r_pair ||
875 (topology_from_uvs && p_edge_implicit_seam(e, pe)))
876 {
877 *r_pair = nullptr;
878 return false;
879 }
880
881 *r_pair = pe;
882 }
883 }
884
885 pe = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)pe);
886 }
887
888 if (*r_pair && (e->vert == (*r_pair)->vert)) {
889 if ((*r_pair)->next->pair || (*r_pair)->next->next->pair) {
890 /* non unfoldable, maybe mobius ring or klein bottle */
891 *r_pair = nullptr;
892 return false;
893 }
894 }
895
896 return (*r_pair != nullptr);
897}
898
900 PEdge *e,
901 bool topology_from_uvs,
902 PEdge ***stack)
903{
904 PEdge *pair = nullptr;
905
906 if (!e->pair && p_edge_has_pair(handle, e, topology_from_uvs, &pair)) {
907 if (e->vert == pair->vert) {
908 p_face_flip(pair->face);
909 }
910
911 e->pair = pair;
912 pair->pair = e;
913
914 if (!(pair->face->flag & PFACE_CONNECTED)) {
915 **stack = pair;
916 (*stack)++;
917 }
918 }
919
920 return (e->pair != nullptr);
921}
922
923static int p_connect_pairs(ParamHandle *handle, bool topology_from_uvs)
924{
925 PEdge **stackbase = (PEdge **)MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces),
926 "Pstackbase");
927 PEdge **stack = stackbase;
928 PFace *f, *first;
929 PEdge *e, *e1, *e2;
930 PChart *chart = handle->construction_chart;
931 int ncharts = 0;
932
933 /* Connect pairs, count edges, set vertex-edge pointer to a pair-less edge. */
934 for (first = chart->faces; first; first = first->nextlink) {
935 if (first->flag & PFACE_CONNECTED) {
936 continue;
937 }
938
939 *stack = first->edge;
940 stack++;
941
942 while (stack != stackbase) {
943 stack--;
944 e = *stack;
945 e1 = e->next;
946 e2 = e1->next;
947
948 f = e->face;
949 f->flag |= PFACE_CONNECTED;
950
951 /* assign verts to charts so we can sort them later */
952 f->u.chart = ncharts;
953
954 if (!p_edge_connect_pair(handle, e, topology_from_uvs, &stack)) {
955 e->vert->edge = e;
956 }
957 if (!p_edge_connect_pair(handle, e1, topology_from_uvs, &stack)) {
958 e1->vert->edge = e1;
959 }
960 if (!p_edge_connect_pair(handle, e2, topology_from_uvs, &stack)) {
961 e2->vert->edge = e2;
962 }
963 }
964
965 ncharts++;
966 }
967
968 MEM_freeN(stackbase);
969
970 return ncharts;
971}
972
973static void p_split_vert(ParamHandle *handle, PChart *chart, PEdge *e)
974{
975 PEdge *we, *lastwe = nullptr;
976 PVert *v = e->vert;
977 bool copy = true;
978
979 if (e->flag & PEDGE_PIN) {
980 chart->has_pins = true;
981 }
982
983 if (e->flag & PEDGE_VERTEX_SPLIT) {
984 return;
985 }
986
987 /* rewind to start */
988 lastwe = e;
989 for (we = p_wheel_edge_prev(e); we && (we != e); we = p_wheel_edge_prev(we)) {
990 lastwe = we;
991 }
992
993 /* go over all edges in wheel */
994 for (we = lastwe; we; we = p_wheel_edge_next(we)) {
995 if (we->flag & PEDGE_VERTEX_SPLIT) {
996 break;
997 }
998
1000
1001 if (we == v->edge) {
1002 /* found it, no need to copy */
1003 copy = false;
1004 v->nextlink = chart->verts;
1005 chart->verts = v;
1006 chart->nverts++;
1007 }
1008 }
1009
1010 if (copy) {
1011 /* not found, copying */
1012 v->flag |= PVERT_SPLIT;
1013 v = p_vert_copy(handle, v);
1014 v->flag |= PVERT_SPLIT;
1015
1016 v->nextlink = chart->verts;
1017 chart->verts = v;
1018 chart->nverts++;
1019
1020 v->edge = lastwe;
1021
1022 we = lastwe;
1023 do {
1024 we->vert = v;
1025 we = p_wheel_edge_next(we);
1026 } while (we && (we != lastwe));
1027 }
1028}
1029
1030static PChart **p_split_charts(ParamHandle *handle, PChart *chart, int ncharts)
1031{
1032 PChart **charts = (PChart **)MEM_callocN(sizeof(*charts) * ncharts, "PCharts");
1033
1034 for (int i = 0; i < ncharts; i++) {
1035 charts[i] = (PChart *)MEM_callocN(sizeof(*chart), "PChart");
1036 }
1037
1038 PFace *f = chart->faces;
1039 while (f) {
1040 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
1041 PFace *nextf = f->nextlink;
1042
1043 PChart *nchart = charts[f->u.chart];
1044
1045 f->nextlink = nchart->faces;
1046 nchart->faces = f;
1047 e1->nextlink = nchart->edges;
1048 nchart->edges = e1;
1049 e2->nextlink = nchart->edges;
1050 nchart->edges = e2;
1051 e3->nextlink = nchart->edges;
1052 nchart->edges = e3;
1053
1054 nchart->nfaces++;
1055 nchart->nedges += 3;
1056
1057 p_split_vert(handle, nchart, e1);
1058 p_split_vert(handle, nchart, e2);
1059 p_split_vert(handle, nchart, e3);
1060
1061 f = nextf;
1062 }
1063
1064 return charts;
1065}
1066
1068{
1069 PFace *f;
1070
1071 /* allocate */
1072 f = (PFace *)BLI_memarena_alloc(handle->arena, sizeof(*f));
1073 f->flag = 0;
1074
1075 PEdge *e1 = (PEdge *)BLI_memarena_calloc(handle->arena, sizeof(*e1));
1076 PEdge *e2 = (PEdge *)BLI_memarena_calloc(handle->arena, sizeof(*e2));
1077 PEdge *e3 = (PEdge *)BLI_memarena_calloc(handle->arena, sizeof(*e3));
1078
1079 /* set up edges */
1080 f->edge = e1;
1081 e1->face = e2->face = e3->face = f;
1082
1083 e1->next = e2;
1084 e2->next = e3;
1085 e3->next = e1;
1086
1087 return f;
1088}
1089
1091 ParamKey key,
1092 const ParamKey *vkeys,
1093 const float **co,
1094 float **uv,
1095 const float *weight,
1096 int i1,
1097 int i2,
1098 int i3,
1099 const bool *pin,
1100 const bool *select)
1101{
1102 PFace *f = p_face_add(handle);
1103 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
1104
1105 float weight1, weight2, weight3;
1106 if (weight) {
1107 weight1 = weight[i1];
1108 weight2 = weight[i2];
1109 weight3 = weight[i3];
1110 }
1111 else {
1112 weight1 = 1.0f;
1113 weight2 = 1.0f;
1114 weight3 = 1.0f;
1115 }
1116
1117 e1->vert = p_vert_lookup(handle, vkeys[i1], co[i1], weight1, e1);
1118 e2->vert = p_vert_lookup(handle, vkeys[i2], co[i2], weight2, e2);
1119 e3->vert = p_vert_lookup(handle, vkeys[i3], co[i3], weight3, e3);
1120
1121 e1->orig_uv = uv[i1];
1122 e2->orig_uv = uv[i2];
1123 e3->orig_uv = uv[i3];
1124
1125 if (pin) {
1126 if (pin[i1]) {
1127 e1->flag |= PEDGE_PIN;
1128 }
1129 if (pin[i2]) {
1130 e2->flag |= PEDGE_PIN;
1131 }
1132 if (pin[i3]) {
1133 e3->flag |= PEDGE_PIN;
1134 }
1135 }
1136
1137 if (select) {
1138 if (select[i1]) {
1139 e1->flag |= PEDGE_SELECT;
1140 }
1141 if (select[i2]) {
1142 e2->flag |= PEDGE_SELECT;
1143 }
1144 if (select[i3]) {
1145 e3->flag |= PEDGE_SELECT;
1146 }
1147 }
1148
1149 f->u.key = key;
1150 phash_insert(handle->hash_faces, (PHashLink *)f);
1151
1152 e1->u.key = PHASH_edge(vkeys[i1], vkeys[i2]);
1153 e2->u.key = PHASH_edge(vkeys[i2], vkeys[i3]);
1154 e3->u.key = PHASH_edge(vkeys[i3], vkeys[i1]);
1155
1156 phash_insert(handle->hash_edges, (PHashLink *)e1);
1157 phash_insert(handle->hash_edges, (PHashLink *)e2);
1158 phash_insert(handle->hash_edges, (PHashLink *)e3);
1159
1160 return f;
1161}
1162
1163static PFace *p_face_add_fill(ParamHandle *handle, PChart *chart, PVert *v1, PVert *v2, PVert *v3)
1164{
1165 PFace *f = p_face_add(handle);
1166 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
1167
1168 e1->vert = v1;
1169 e2->vert = v2;
1170 e3->vert = v3;
1171
1172 e1->orig_uv = e2->orig_uv = e3->orig_uv = nullptr;
1173
1174 f->nextlink = chart->faces;
1175 chart->faces = f;
1176 e1->nextlink = chart->edges;
1177 chart->edges = e1;
1178 e2->nextlink = chart->edges;
1179 chart->edges = e2;
1180 e3->nextlink = chart->edges;
1181 chart->edges = e3;
1182
1183 chart->nfaces++;
1184 chart->nedges += 3;
1185
1186 return f;
1187}
1188
1189/* Construction: boundary filling */
1190
1191static void p_chart_boundaries(PChart *chart, PEdge **r_outer)
1192{
1193 PEdge *e, *be;
1194 float len, maxlen = -1.0;
1195
1196 chart->nboundaries = 0;
1197 if (r_outer) {
1198 *r_outer = nullptr;
1199 }
1200
1201 for (e = chart->edges; e; e = e->nextlink) {
1202 if (e->pair || (e->flag & PEDGE_DONE)) {
1203 continue;
1204 }
1205
1206 chart->nboundaries++;
1207
1208 len = 0.0f;
1209
1210 be = e;
1211 do {
1212 be->flag |= PEDGE_DONE;
1213 len += p_edge_length(be);
1214 be = be->next->vert->edge;
1215 } while (be != e);
1216
1217 if (r_outer && (len > maxlen)) {
1218 *r_outer = e;
1219 maxlen = len;
1220 }
1221 }
1222
1223 for (e = chart->edges; e; e = e->nextlink) {
1224 e->flag &= ~PEDGE_DONE;
1225 }
1226}
1227
1229{
1230 PEdge *we;
1231 PVert *v, *v1, *v2;
1232 float angle;
1233
1234 v = e->vert;
1235
1236 /* concave angle check -- could be better */
1237 angle = M_PI;
1238
1239 we = v->edge;
1240 do {
1241 v1 = we->next->vert;
1242 v2 = we->next->next->vert;
1243 angle -= angle_v3v3v3(v1->co, v->co, v2->co);
1244
1245 we = we->next->next->pair;
1246 } while (we && (we != v->edge));
1247
1248 return angle;
1249}
1250
1251static void p_chart_fill_boundary(ParamHandle *handle, PChart *chart, PEdge *be, int nedges)
1252{
1253 PEdge *e, *e1, *e2;
1254
1255 PFace *f;
1256 Heap *heap = BLI_heap_new();
1257 float angle;
1258
1259 e = be;
1260 do {
1261 angle = p_edge_boundary_angle(e);
1262 e->u.heaplink = BLI_heap_insert(heap, angle, e);
1263
1265 } while (e != be);
1266
1267 if (nedges == 2) {
1268 /* no real boundary, but an isolated seam */
1269 e = be->next->vert->edge;
1270 e->pair = be;
1271 be->pair = e;
1272
1273 BLI_heap_remove(heap, e->u.heaplink);
1274 BLI_heap_remove(heap, be->u.heaplink);
1275 }
1276 else {
1277 while (nedges > 2) {
1278 PEdge *ne, *ne1, *ne2;
1279
1280 e = (PEdge *)BLI_heap_pop_min(heap);
1281
1282 e1 = p_boundary_edge_prev(e);
1283 e2 = p_boundary_edge_next(e);
1284
1285 BLI_heap_remove(heap, e1->u.heaplink);
1286 BLI_heap_remove(heap, e2->u.heaplink);
1287 e->u.heaplink = e1->u.heaplink = e2->u.heaplink = nullptr;
1288
1289 e->flag |= PEDGE_FILLED;
1290 e1->flag |= PEDGE_FILLED;
1291
1292 f = p_face_add_fill(handle, chart, e->vert, e1->vert, e2->vert);
1293 f->flag |= PFACE_FILLED;
1294
1295 ne = f->edge->next->next;
1296 ne1 = f->edge;
1297 ne2 = f->edge->next;
1298
1299 ne->flag = ne1->flag = ne2->flag = PEDGE_FILLED;
1300
1301 e->pair = ne;
1302 ne->pair = e;
1303 e1->pair = ne1;
1304 ne1->pair = e1;
1305
1306 ne->vert = e2->vert;
1307 ne1->vert = e->vert;
1308 ne2->vert = e1->vert;
1309
1310 if (nedges == 3) {
1311 e2->pair = ne2;
1312 ne2->pair = e2;
1313 }
1314 else {
1315 ne2->vert->edge = ne2;
1316
1317 ne2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(ne2), ne2);
1318 e2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(e2), e2);
1319 }
1320
1321 nedges--;
1322 }
1323 }
1324
1325 BLI_heap_free(heap, nullptr);
1326}
1327
1328static void p_chart_fill_boundaries(ParamHandle *handle, PChart *chart, const PEdge *outer)
1329{
1330 PEdge *e, *be; /* *enext - as yet unused */
1331 int nedges;
1332
1333 for (e = chart->edges; e; e = e->nextlink) {
1334 /* enext = e->nextlink; - as yet unused */
1335
1336 if (e->pair || (e->flag & PEDGE_FILLED)) {
1337 continue;
1338 }
1339
1340 nedges = 0;
1341 be = e;
1342 do {
1343 be->flag |= PEDGE_FILLED;
1344 be = be->next->vert->edge;
1345 nedges++;
1346 } while (be != e);
1347
1348 if (e != outer) {
1349 p_chart_fill_boundary(handle, chart, e, nedges);
1350 }
1351 }
1352}
1353
1354#if 0
1355/* Polygon kernel for inserting uv's non overlapping */
1356
1357static int p_polygon_point_in(const float cp1[2], const float cp2[2], const float p[2])
1358{
1359 if ((cp1[0] == p[0]) && (cp1[1] == p[1])) {
1360 return 2;
1361 }
1362 else if ((cp2[0] == p[0]) && (cp2[1] == p[1])) {
1363 return 3;
1364 }
1365 else {
1366 return (p_area_signed(cp1, cp2, p) >= 0.0f);
1367 }
1368}
1369
1370static void p_polygon_kernel_clip(float (*oldpoints)[2],
1371 int noldpoints,
1372 float (*newpoints)[2],
1373 int *r_nnewpoints,
1374 const float cp1[2],
1375 const float cp2[2])
1376{
1377 float *p2, *p1, isect[2];
1378 int i, p2in, p1in;
1379
1380 p1 = oldpoints[noldpoints - 1];
1381 p1in = p_polygon_point_in(cp1, cp2, p1);
1382 *r_nnewpoints = 0;
1383
1384 for (i = 0; i < noldpoints; i++) {
1385 p2 = oldpoints[i];
1386 p2in = p_polygon_point_in(cp1, cp2, p2);
1387
1388 if ((p2in >= 2) || (p1in && p2in)) {
1389 newpoints[*r_nnewpoints][0] = p2[0];
1390 newpoints[*r_nnewpoints][1] = p2[1];
1391 (*r_nnewpoints)++;
1392 }
1393 else if (p1in && !p2in) {
1394 if (p1in != 3) {
1395 p_intersect_line_2d(p1, p2, cp1, cp2, isect);
1396 newpoints[*r_nnewpoints][0] = isect[0];
1397 newpoints[*r_nnewpoints][1] = isect[1];
1398 (*r_nnewpoints)++;
1399 }
1400 }
1401 else if (!p1in && p2in) {
1402 p_intersect_line_2d(p1, p2, cp1, cp2, isect);
1403 newpoints[*r_nnewpoints][0] = isect[0];
1404 newpoints[*r_nnewpoints][1] = isect[1];
1405 (*r_nnewpoints)++;
1406
1407 newpoints[*r_nnewpoints][0] = p2[0];
1408 newpoints[*r_nnewpoints][1] = p2[1];
1409 (*r_nnewpoints)++;
1410 }
1411
1412 p1in = p2in;
1413 p1 = p2;
1414 }
1415}
1416
1417static void p_polygon_kernel_center(float (*points)[2], int npoints, float *center)
1418{
1419 int i, size, nnewpoints = npoints;
1420 float(*oldpoints)[2], (*newpoints)[2], *p1, *p2;
1421
1422 size = npoints * 3;
1423 oldpoints = MEM_mallocN(sizeof(float[2]) * size, "PPolygonOldPoints");
1424 newpoints = MEM_mallocN(sizeof(float[2]) * size, "PPolygonNewPoints");
1425
1426 memcpy(oldpoints, points, sizeof(float[2]) * npoints);
1427
1428 for (i = 0; i < npoints; i++) {
1429 p1 = points[i];
1430 p2 = points[(i + 1) % npoints];
1431 p_polygon_kernel_clip(oldpoints, nnewpoints, newpoints, &nnewpoints, p1, p2);
1432
1433 if (nnewpoints == 0) {
1434 /* degenerate case, use center of original face */
1435 memcpy(oldpoints, points, sizeof(float[2]) * npoints);
1436 nnewpoints = npoints;
1437 break;
1438 }
1439 else if (nnewpoints == 1) {
1440 /* degenerate case, use remaining point */
1441 center[0] = newpoints[0][0];
1442 center[1] = newpoints[0][1];
1443
1444 MEM_freeN(oldpoints);
1445 MEM_freeN(newpoints);
1446
1447 return;
1448 }
1449
1450 if (nnewpoints * 2 > size) {
1451 size *= 2;
1452 MEM_freeN(oldpoints);
1453 oldpoints = MEM_mallocN(sizeof(float[2]) * size, "oldpoints");
1454 memcpy(oldpoints, newpoints, sizeof(float[2]) * nnewpoints);
1455 MEM_freeN(newpoints);
1456 newpoints = MEM_mallocN(sizeof(float[2]) * size, "newpoints");
1457 }
1458 else {
1459 float(*sw_points)[2] = oldpoints;
1460 oldpoints = newpoints;
1461 newpoints = sw_points;
1462 }
1463 }
1464
1465 center[0] = center[1] = 0.0f;
1466
1467 for (i = 0; i < nnewpoints; i++) {
1468 center[0] += oldpoints[i][0];
1469 center[1] += oldpoints[i][1];
1470 }
1471
1472 center[0] /= nnewpoints;
1473 center[1] /= nnewpoints;
1474
1475 MEM_freeN(oldpoints);
1476 MEM_freeN(newpoints);
1477}
1478#endif
1479
1480/* Simplify/Complexity
1481 *
1482 * This is currently used for eliminating degenerate vertex coordinates.
1483 * In the future this can be used for efficient unwrapping of high resolution
1484 * charts at lower resolution. */
1485
1486#if 0
1487
1488static float p_vert_cotan(const float v1[3], const float v2[3], const float v3[3])
1489{
1490 float a[3], b[3], c[3], clen;
1491
1492 sub_v3_v3v3(a, v2, v1);
1493 sub_v3_v3v3(b, v3, v1);
1494 cross_v3_v3v3(c, a, b);
1495
1496 clen = len_v3(c);
1497
1498 if (clen == 0.0f) {
1499 return 0.0f;
1500 }
1501
1502 return dot_v3v3(a, b) / clen;
1503}
1504
1505static bool p_vert_flipped_wheel_triangle(PVert *v)
1506{
1507 PEdge *e = v->edge;
1508
1509 do {
1510 if (p_face_uv_area_signed(e->face) < 0.0f) {
1511 return true;
1512 }
1513
1515 } while (e && (e != v->edge));
1516
1517 return false;
1518}
1519
1520static bool p_vert_map_harmonic_weights(PVert *v)
1521{
1522 float weightsum, positionsum[2], olduv[2];
1523
1524 weightsum = 0.0f;
1525 positionsum[0] = positionsum[1] = 0.0f;
1526
1527 if (p_vert_interior(v)) {
1528 PEdge *e = v->edge;
1529
1530 do {
1531 float t1, t2, weight;
1532 PVert *v1, *v2;
1533
1534 v1 = e->next->vert;
1535 v2 = e->next->next->vert;
1536 t1 = p_vert_cotan(v2->co, e->vert->co, v1->co);
1537
1538 v1 = e->pair->next->vert;
1539 v2 = e->pair->next->next->vert;
1540 t2 = p_vert_cotan(v2->co, e->pair->vert->co, v1->co);
1541
1542 weight = 0.5f * (t1 + t2);
1543 weightsum += weight;
1544 positionsum[0] += weight * e->pair->vert->uv[0];
1545 positionsum[1] += weight * e->pair->vert->uv[1];
1546
1548 } while (e && (e != v->edge));
1549 }
1550 else {
1551 PEdge *e = v->edge;
1552
1553 do {
1554 float t1, t2;
1555 PVert *v1, *v2;
1556
1557 v2 = e->next->vert;
1558 v1 = e->next->next->vert;
1559
1560 t1 = p_vert_cotan(v1->co, v->co, v2->co);
1561 t2 = p_vert_cotan(v2->co, v->co, v1->co);
1562
1563 weightsum += t1 + t2;
1564 positionsum[0] += (v2->uv[1] - v1->uv[1]) + (t1 * v2->uv[0] + t2 * v1->uv[0]);
1565 positionsum[1] += (v1->uv[0] - v2->uv[0]) + (t1 * v2->uv[1] + t2 * v1->uv[1]);
1566
1568 } while (e && (e != v->edge));
1569 }
1570
1571 if (weightsum != 0.0f) {
1572 weightsum = 1.0f / weightsum;
1573 positionsum[0] *= weightsum;
1574 positionsum[1] *= weightsum;
1575 }
1576
1577 olduv[0] = v->uv[0];
1578 olduv[1] = v->uv[1];
1579 v->uv[0] = positionsum[0];
1580 v->uv[1] = positionsum[1];
1581
1582 if (p_vert_flipped_wheel_triangle(v)) {
1583 v->uv[0] = olduv[0];
1584 v->uv[1] = olduv[1];
1585
1586 return false;
1587 }
1588
1589 return true;
1590}
1591
1592static void p_vert_harmonic_insert(PVert *v)
1593{
1594 PEdge *e;
1595
1596 if (!p_vert_map_harmonic_weights(v)) {
1597 /* do face kernel center insertion: this is quite slow, but should
1598 * only be needed for 0.01 % of verts or so, when insert with harmonic
1599 * weights fails */
1600
1601 int npoints = 0, i;
1602 float(*points)[2];
1603
1604 e = v->edge;
1605 do {
1606 npoints++;
1608 } while (e && (e != v->edge));
1609
1610 if (e == nullptr) {
1611 npoints++;
1612 }
1613
1614 points = MEM_mallocN(sizeof(float[2]) * npoints, "PHarmonicPoints");
1615
1616 e = v->edge;
1617 i = 0;
1618 do {
1619 PEdge *nexte = p_wheel_edge_next(e);
1620
1621 points[i][0] = e->next->vert->uv[0];
1622 points[i][1] = e->next->vert->uv[1];
1623
1624 if (nexte == nullptr) {
1625 i++;
1626 points[i][0] = e->next->next->vert->uv[0];
1627 points[i][1] = e->next->next->vert->uv[1];
1628 break;
1629 }
1630
1631 e = nexte;
1632 i++;
1633 } while (e != v->edge);
1634
1635 p_polygon_kernel_center(points, npoints, v->uv);
1636
1637 MEM_freeN(points);
1638 }
1639
1640 e = v->edge;
1641 do {
1642 if (!(e->next->vert->flag & PVERT_PIN)) {
1643 p_vert_map_harmonic_weights(e->next->vert);
1644 }
1646 } while (e && (e != v->edge));
1647
1648 p_vert_map_harmonic_weights(v);
1649}
1650#endif
1651
1653{
1654 PEdge *start = v->edge;
1655
1656 /* set v->edge pointer to the edge with no pair, if there is one */
1657 while (v->edge->pair) {
1658 v->edge = p_wheel_edge_prev(v->edge);
1659
1660 if (v->edge == start) {
1661 break;
1662 }
1663 }
1664}
1665
1666static void p_collapsing_verts(PEdge *edge, PEdge *pair, PVert **r_newv, PVert **r_keepv)
1667{
1668 /* the two vertices that are involved in the collapse */
1669 if (edge) {
1670 *r_newv = edge->vert;
1671 *r_keepv = edge->next->vert;
1672 }
1673 else {
1674 *r_newv = pair->next->vert;
1675 *r_keepv = pair->vert;
1676 }
1677}
1678
1679static void p_collapse_edge(PEdge *edge, PEdge *pair)
1680{
1681 PVert *oldv, *keepv;
1682 PEdge *e;
1683
1684 p_collapsing_verts(edge, pair, &oldv, &keepv);
1685
1686 /* change e->vert pointers from old vertex to the target vertex */
1687 e = oldv->edge;
1688 do {
1689 if ((e != edge) && !(pair && pair->next == e)) {
1690 e->vert = keepv;
1691 }
1692
1694 } while (e && (e != oldv->edge));
1695
1696 /* set keepv->edge pointer */
1697 if ((edge && (keepv->edge == edge->next)) || (keepv->edge == pair)) {
1698 if (edge && edge->next->pair) {
1699 keepv->edge = edge->next->pair->next;
1700 }
1701 else if (pair && pair->next->next->pair) {
1702 keepv->edge = pair->next->next->pair;
1703 }
1704 else if (edge && edge->next->next->pair) {
1705 keepv->edge = edge->next->next->pair;
1706 }
1707 else {
1708 keepv->edge = pair->next->pair->next;
1709 }
1710 }
1711
1712 /* update pairs and v->edge pointers */
1713 if (edge) {
1714 PEdge *e1 = edge->next, *e2 = e1->next;
1715
1716 if (e1->pair) {
1717 e1->pair->pair = e2->pair;
1718 }
1719
1720 if (e2->pair) {
1721 e2->pair->pair = e1->pair;
1722 e2->vert->edge = p_wheel_edge_prev(e2);
1723 }
1724 else {
1725 e2->vert->edge = p_wheel_edge_next(e2);
1726 }
1727
1728 p_vert_fix_edge_pointer(e2->vert);
1729 }
1730
1731 if (pair) {
1732 PEdge *e1 = pair->next, *e2 = e1->next;
1733
1734 if (e1->pair) {
1735 e1->pair->pair = e2->pair;
1736 }
1737
1738 if (e2->pair) {
1739 e2->pair->pair = e1->pair;
1740 e2->vert->edge = p_wheel_edge_prev(e2);
1741 }
1742 else {
1743 e2->vert->edge = p_wheel_edge_next(e2);
1744 }
1745
1746 p_vert_fix_edge_pointer(e2->vert);
1747 }
1748
1750
1751 /* mark for move to collapsed list later */
1752 oldv->flag |= PVERT_COLLAPSE;
1753
1754 if (edge) {
1755 PFace *f = edge->face;
1756 PEdge *e1 = edge->next, *e2 = e1->next;
1757
1758 f->flag |= PFACE_COLLAPSE;
1759 edge->flag |= PEDGE_COLLAPSE;
1760 e1->flag |= PEDGE_COLLAPSE;
1761 e2->flag |= PEDGE_COLLAPSE;
1762 }
1763
1764 if (pair) {
1765 PFace *f = pair->face;
1766 PEdge *e1 = pair->next, *e2 = e1->next;
1767
1768 f->flag |= PFACE_COLLAPSE;
1769 pair->flag |= PEDGE_COLLAPSE;
1770 e1->flag |= PEDGE_COLLAPSE;
1771 e2->flag |= PEDGE_COLLAPSE;
1772 }
1773}
1774
1775#if 0
1776static void p_split_vertex(PEdge *edge, PEdge *pair)
1777{
1778 PVert *newv, *keepv;
1779 PEdge *e;
1780
1781 p_collapsing_verts(edge, pair, &newv, &keepv);
1782
1783 /* update edge pairs */
1784 if (edge) {
1785 PEdge *e1 = edge->next, *e2 = e1->next;
1786
1787 if (e1->pair) {
1788 e1->pair->pair = e1;
1789 }
1790 if (e2->pair) {
1791 e2->pair->pair = e2;
1792 }
1793
1794 e2->vert->edge = e2;
1795 p_vert_fix_edge_pointer(e2->vert);
1796 keepv->edge = e1;
1797 }
1798
1799 if (pair) {
1800 PEdge *e1 = pair->next, *e2 = e1->next;
1801
1802 if (e1->pair) {
1803 e1->pair->pair = e1;
1804 }
1805 if (e2->pair) {
1806 e2->pair->pair = e2;
1807 }
1808
1809 e2->vert->edge = e2;
1810 p_vert_fix_edge_pointer(e2->vert);
1811 keepv->edge = pair;
1812 }
1813
1815
1816 /* set e->vert pointers to restored vertex */
1817 e = newv->edge;
1818 do {
1819 e->vert = newv;
1821 } while (e && (e != newv->edge));
1822}
1823#endif
1824
1826{
1827 PVert *oldv, *keepv;
1828
1829 p_collapsing_verts(edge, pair, &oldv, &keepv);
1830
1831 /* boundary edges */
1832 if (!edge || !pair) {
1833 /* avoid collapsing chart into an edge */
1834 if (edge && !edge->next->pair && !edge->next->next->pair) {
1835 return false;
1836 }
1837 else if (pair && !pair->next->pair && !pair->next->next->pair) {
1838 return false;
1839 }
1840 }
1841 /* avoid merging two boundaries (oldv and keepv are on the 'other side' of
1842 * the chart) */
1843 else if (!p_vert_interior(oldv) && !p_vert_interior(keepv)) {
1844 return false;
1845 }
1846
1847 return true;
1848}
1849
1850#if 0
1851static bool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float *vnew)
1852{
1853 float nold[3], nnew[3], sub1[3], sub2[3];
1854
1855 sub_v3_v3v3(sub1, vold, v1);
1856 sub_v3_v3v3(sub2, vold, v2);
1857 cross_v3_v3v3(nold, sub1, sub2);
1858
1859 sub_v3_v3v3(sub1, vnew, v1);
1860 sub_v3_v3v3(sub2, vnew, v2);
1861 cross_v3_v3v3(nnew, sub1, sub2);
1862
1863 return (dot_v3v3(nold, nnew) <= 0.0f);
1864}
1865
1866static bool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
1867{
1868 PVert *oldv, *keepv;
1869 PEdge *e;
1870 float angulardefect, angle;
1871
1872 p_collapsing_verts(edge, pair, &oldv, &keepv);
1873
1874 angulardefect = 2 * M_PI;
1875
1876 e = oldv->edge;
1877 do {
1878 float a[3], b[3], minangle, maxangle;
1879 PEdge *e1 = e->next, *e2 = e1->next;
1880 PVert *v1 = e1->vert, *v2 = e2->vert;
1881 int i;
1882
1883 angle = p_vec_angle(v1->co, oldv->co, v2->co);
1884 angulardefect -= angle;
1885
1886 /* skip collapsing faces */
1887 if (v1 == keepv || v2 == keepv) {
1889 continue;
1890 }
1891
1892 if (p_collapse_normal_flipped(v1->co, v2->co, oldv->co, keepv->co)) {
1893 return false;
1894 }
1895
1896 a[0] = angle;
1897 a[1] = p_vec_angle(v2->co, v1->co, oldv->co);
1898 a[2] = M_PI - a[0] - a[1];
1899
1900 b[0] = p_vec_angle(v1->co, keepv->co, v2->co);
1901 b[1] = p_vec_angle(v2->co, v1->co, keepv->co);
1902 b[2] = M_PI - b[0] - b[1];
1903
1904 /* ABF criterion 1: avoid sharp and obtuse angles. */
1905 minangle = DEG2RADF(15.0);
1906 maxangle = M_PI - minangle;
1907
1908 for (i = 0; i < 3; i++) {
1909 if ((b[i] < a[i]) && (b[i] < minangle)) {
1910 return false;
1911 }
1912 else if ((b[i] > a[i]) && (b[i] > maxangle)) {
1913 return false;
1914 }
1915 }
1916
1918 } while (e && (e != oldv->edge));
1919
1920 if (p_vert_interior(oldv)) {
1921 /* HLSCM criterion: angular defect smaller than threshold. */
1922 if (fabsf(angulardefect) > DEG2RADF(30.0)) {
1923 return false;
1924 }
1925 }
1926 else {
1927 PVert *v1 = p_boundary_edge_next(oldv->edge)->vert;
1928 PVert *v2 = p_boundary_edge_prev(oldv->edge)->vert;
1929
1930 /* ABF++ criterion 2: avoid collapsing verts inwards. */
1931 if (p_vert_interior(keepv)) {
1932 return false;
1933 }
1934
1935 /* Don't collapse significant boundary changes. */
1936 angle = p_vec_angle(v1->co, oldv->co, v2->co);
1937 if (angle < DEG2RADF(160.0)) {
1938 return false;
1939 }
1940 }
1941
1942 return true;
1943}
1944
1945static bool p_collapse_allowed(PEdge *edge, PEdge *pair)
1946{
1947 PVert *oldv, *keepv;
1948
1949 p_collapsing_verts(edge, pair, &oldv, &keepv);
1950
1951 if (oldv->flag & PVERT_PIN) {
1952 return false;
1953 }
1954
1955 return (p_collapse_allowed_topologic(edge, pair) && p_collapse_allowed_geometric(edge, pair));
1956}
1957
1958static float p_collapse_cost(PEdge *edge, PEdge *pair)
1959{
1960 /* based on volume and boundary optimization from:
1961 * "Fast and Memory Efficient Polygonal Simplification" P. Lindstrom, G. Turk */
1962
1963 PVert *oldv, *keepv;
1964 PEdge *e;
1965 PFace *oldf1, *oldf2;
1966 float volumecost = 0.0f, areacost = 0.0f, edgevec[3], cost, weight, elen;
1967 float shapecost = 0.0f;
1968 float shapeold = 0.0f, shapenew = 0.0f;
1969 int nshapeold = 0, nshapenew = 0;
1970
1971 p_collapsing_verts(edge, pair, &oldv, &keepv);
1972 oldf1 = (edge) ? edge->face : nullptr;
1973 oldf2 = (pair) ? pair->face : nullptr;
1974
1975 sub_v3_v3v3(edgevec, keepv->co, oldv->co);
1976
1977 e = oldv->edge;
1978 do {
1979 float a1, a2, a3;
1980 float *co1 = e->next->vert->co;
1981 float *co2 = e->next->next->vert->co;
1982
1983 if (!ELEM(e->face, oldf1, oldf2)) {
1984 float tetrav2[3], tetrav3[3];
1985
1986 /* tetrahedron volume = (1/3!)*|a.(b x c)| */
1987 sub_v3_v3v3(tetrav2, co1, oldv->co);
1988 sub_v3_v3v3(tetrav3, co2, oldv->co);
1989 volumecost += fabsf(volume_tri_tetrahedron_signed_v3(tetrav2, tetrav3, edgevec));
1990
1991# if 0
1992 shapecost += dot_v3v3(co1, keepv->co);
1993
1994 if (p_wheel_edge_next(e) == nullptr) {
1995 shapecost += dot_v3v3(co2, keepv->co);
1996 }
1997# endif
1998
1999 p_triangle_angles(oldv->co, co1, co2, &a1, &a2, &a3);
2000 a1 = a1 - M_PI / 3.0;
2001 a2 = a2 - M_PI / 3.0;
2002 a3 = a3 - M_PI / 3.0;
2003 shapeold = (a1 * a1 + a2 * a2 + a3 * a3) / (M_PI_2 * M_PI_2);
2004
2005 nshapeold++;
2006 }
2007 else {
2008 p_triangle_angles(keepv->co, co1, co2, &a1, &a2, &a3);
2009 a1 = a1 - M_PI / 3.0;
2010 a2 = a2 - M_PI / 3.0;
2011 a3 = a3 - M_PI / 3.0;
2012 shapenew = (a1 * a1 + a2 * a2 + a3 * a3) / (M_PI_2 * M_PI_2);
2013
2014 nshapenew++;
2015 }
2016
2018 } while (e && (e != oldv->edge));
2019
2020 if (!p_vert_interior(oldv)) {
2021 PVert *v1 = p_boundary_edge_prev(oldv->edge)->vert;
2022 PVert *v2 = p_boundary_edge_next(oldv->edge)->vert;
2023
2024 areacost = area_tri_v3(oldv->co, v1->co, v2->co);
2025 }
2026
2027 elen = len_v3(edgevec);
2028 weight = 1.0f; /* 0.2f */
2029 cost = weight * volumecost * volumecost + elen * elen * areacost * areacost;
2030# if 0
2031 cost += shapecost;
2032# else
2033 shapeold /= nshapeold;
2034 shapenew /= nshapenew;
2035 shapecost = (shapeold + 0.00001) / (shapenew + 0.00001);
2036
2037 cost *= shapecost;
2038# endif
2039
2040 return cost;
2041}
2042#endif
2043
2045 PVert *vert,
2046 float *r_mincost,
2047 PEdge **r_mine,
2048 const std::function<float(PEdge *, PEdge *)> &collapse_cost_fn,
2049 const std::function<float(PEdge *, PEdge *)> &collapse_allowed_fn)
2050{
2051 PEdge *e, *enext, *pair;
2052
2053 *r_mine = nullptr;
2054 *r_mincost = 0.0f;
2055 e = vert->edge;
2056 do {
2057 if (collapse_allowed_fn(e, e->pair)) {
2058 float cost = collapse_cost_fn(e, e->pair);
2059
2060 if ((*r_mine == nullptr) || (cost < *r_mincost)) {
2061 *r_mincost = cost;
2062 *r_mine = e;
2063 }
2064 }
2065
2066 enext = p_wheel_edge_next(e);
2067
2068 if (enext == nullptr) {
2069 /* The other boundary edge, where we only have the pair half-edge. */
2070 pair = e->next->next;
2071
2072 if (collapse_allowed_fn(nullptr, pair)) {
2073 float cost = collapse_cost_fn(nullptr, pair);
2074
2075 if ((*r_mine == nullptr) || (cost < *r_mincost)) {
2076 *r_mincost = cost;
2077 *r_mine = pair;
2078 }
2079 }
2080
2081 break;
2082 }
2083
2084 e = enext;
2085 } while (e != vert->edge);
2086}
2087
2088static void p_chart_post_collapse_flush(PChart *chart, PEdge *collapsed)
2089{
2090 /* Move to `collapsed_*`. */
2091
2092 PVert *v, *nextv = nullptr, *verts = chart->verts;
2093 PEdge *e, *nexte = nullptr, *edges = chart->edges, *laste = nullptr;
2094 PFace *f, *nextf = nullptr, *faces = chart->faces;
2095
2096 chart->verts = chart->collapsed_verts = nullptr;
2097 chart->edges = chart->collapsed_edges = nullptr;
2098 chart->faces = chart->collapsed_faces = nullptr;
2099
2100 chart->nverts = chart->nedges = chart->nfaces = 0;
2101
2102 for (v = verts; v; v = nextv) {
2103 nextv = v->nextlink;
2104
2105 if (v->flag & PVERT_COLLAPSE) {
2106 v->nextlink = chart->collapsed_verts;
2107 chart->collapsed_verts = v;
2108 }
2109 else {
2110 v->nextlink = chart->verts;
2111 chart->verts = v;
2112 chart->nverts++;
2113 }
2114 }
2115
2116 for (e = edges; e; e = nexte) {
2117 nexte = e->nextlink;
2118
2119 if (!collapsed || !(e->flag & PEDGE_COLLAPSE_EDGE)) {
2120 if (e->flag & PEDGE_COLLAPSE) {
2121 e->nextlink = chart->collapsed_edges;
2122 chart->collapsed_edges = e;
2123 }
2124 else {
2125 e->nextlink = chart->edges;
2126 chart->edges = e;
2127 chart->nedges++;
2128 }
2129 }
2130 }
2131
2132 /* these are added last so they can be popped of in the right order
2133 * for splitting */
2134 for (e = collapsed; e; e = e->nextlink) {
2135 e->nextlink = e->u.nextcollapse;
2136 laste = e;
2137 }
2138 if (laste) {
2139 laste->nextlink = chart->collapsed_edges;
2140 chart->collapsed_edges = collapsed;
2141 }
2142
2143 for (f = faces; f; f = nextf) {
2144 nextf = f->nextlink;
2145
2146 if (f->flag & PFACE_COLLAPSE) {
2147 f->nextlink = chart->collapsed_faces;
2148 chart->collapsed_faces = f;
2149 }
2150 else {
2151 f->nextlink = chart->faces;
2152 chart->faces = f;
2153 chart->nfaces++;
2154 }
2155 }
2156}
2157
2159 std::function<float(PEdge *, PEdge *)> collapse_cost_fn,
2160 std::function<float(PEdge *, PEdge *)> collapse_allowed_fn)
2161{
2162 /* For debugging. */
2163 static const int MAX_SIMPLIFY = INT_MAX;
2164
2165 /* Computes a list of edge collapses / vertex splits. The collapsed
2166 * simplices go in the `chart->collapsed_*` lists, The original and
2167 * collapsed may then be view as stacks, where the next collapse/split
2168 * is at the top of the respective lists. */
2169
2170 Heap *heap = BLI_heap_new();
2171 PEdge *collapsededges = nullptr;
2172 int ncollapsed = 0;
2173 Vector<PVert *> wheelverts;
2174 wheelverts.reserve(16);
2175
2176 /* insert all potential collapses into heap */
2177 for (PVert *v = chart->verts; v; v = v->nextlink) {
2178 float cost;
2179 PEdge *e = nullptr;
2180
2181 p_collapse_cost_vertex(v, &cost, &e, collapse_cost_fn, collapse_allowed_fn);
2182
2183 if (e) {
2184 v->u.heaplink = BLI_heap_insert(heap, cost, e);
2185 }
2186 else {
2187 v->u.heaplink = nullptr;
2188 }
2189 }
2190
2191 for (PEdge *e = chart->edges; e; e = e->nextlink) {
2192 e->u.nextcollapse = nullptr;
2193 }
2194
2195 /* pop edge collapse out of heap one by one */
2196 while (!BLI_heap_is_empty(heap)) {
2197 if (ncollapsed == MAX_SIMPLIFY) {
2198 break;
2199 }
2200
2201 HeapNode *link = BLI_heap_top(heap);
2202 PEdge *edge = (PEdge *)BLI_heap_pop_min(heap), *pair = edge->pair;
2203 PVert *oldv, *keepv;
2204 PEdge *wheele, *nexte;
2205
2206 /* remember the edges we collapsed */
2207 edge->u.nextcollapse = collapsededges;
2208 collapsededges = edge;
2209
2210 if (edge->vert->u.heaplink != link) {
2212 edge->next->vert->u.heaplink = nullptr;
2213 std::swap(edge, pair);
2214 }
2215 else {
2216 edge->flag |= PEDGE_COLLAPSE_EDGE;
2217 edge->vert->u.heaplink = nullptr;
2218 }
2219
2220 p_collapsing_verts(edge, pair, &oldv, &keepv);
2221
2222 /* gather all wheel verts and remember them before collapse */
2223 wheelverts.clear();
2224 wheele = oldv->edge;
2225
2226 do {
2227 wheelverts.append(wheele->next->vert);
2228 nexte = p_wheel_edge_next(wheele);
2229
2230 if (nexte == nullptr) {
2231 wheelverts.append(wheele->next->next->vert);
2232 }
2233
2234 wheele = nexte;
2235 } while (wheele && (wheele != oldv->edge));
2236
2237 /* collapse */
2238 p_collapse_edge(edge, pair);
2239
2240 for (PVert *v : wheelverts) {
2241 float cost;
2242 PEdge *collapse = nullptr;
2243
2244 if (v->u.heaplink) {
2245 BLI_heap_remove(heap, v->u.heaplink);
2246 v->u.heaplink = nullptr;
2247 }
2248
2249 p_collapse_cost_vertex(v, &cost, &collapse, collapse_cost_fn, collapse_allowed_fn);
2250
2251 if (collapse) {
2252 v->u.heaplink = BLI_heap_insert(heap, cost, collapse);
2253 }
2254 }
2255
2256 ncollapsed++;
2257 }
2258
2259 BLI_heap_free(heap, nullptr);
2260
2261 p_chart_post_collapse_flush(chart, collapsededges);
2262}
2263
2264#if 0
2265static void p_chart_post_split_flush(PChart *chart)
2266{
2267 /* Move from `collapsed_*`. */
2268
2269 PVert *v, *nextv = nullptr;
2270 PEdge *e, *nexte = nullptr;
2271 PFace *f, *nextf = nullptr;
2272
2273 for (v = chart->collapsed_verts; v; v = nextv) {
2274 nextv = v->nextlink;
2275 v->nextlink = chart->verts;
2276 chart->verts = v;
2277 chart->nverts++;
2278 }
2279
2280 for (e = chart->collapsed_edges; e; e = nexte) {
2281 nexte = e->nextlink;
2282 e->nextlink = chart->edges;
2283 chart->edges = e;
2284 chart->nedges++;
2285 }
2286
2287 for (f = chart->collapsed_faces; f; f = nextf) {
2288 nextf = f->nextlink;
2289 f->nextlink = chart->faces;
2290 chart->faces = f;
2291 chart->nfaces++;
2292 }
2293
2294 chart->collapsed_verts = nullptr;
2295 chart->collapsed_edges = nullptr;
2296 chart->collapsed_faces = nullptr;
2297}
2298
2299static void p_chart_complexify(PChart *chart)
2300{
2301 /* For debugging. */
2302 static const int MAX_COMPLEXIFY = INT_MAX;
2303
2304 PEdge *e, *pair, *edge;
2305 PVert *newv, *keepv;
2306 int x = 0;
2307
2308 for (e = chart->collapsed_edges; e; e = e->nextlink) {
2309 if (!(e->flag & PEDGE_COLLAPSE_EDGE)) {
2310 break;
2311 }
2312
2313 edge = e;
2314 pair = e->pair;
2315
2316 if (edge->flag & PEDGE_COLLAPSE_PAIR) {
2317 std::swap(edge, pair);
2318 }
2319
2320 p_split_vertex(edge, pair);
2321 p_collapsing_verts(edge, pair, &newv, &keepv);
2322
2323 if (x >= MAX_COMPLEXIFY) {
2324 newv->uv[0] = keepv->uv[0];
2325 newv->uv[1] = keepv->uv[1];
2326 }
2327 else {
2328 p_vert_harmonic_insert(newv);
2329 x++;
2330 }
2331 }
2332
2333 p_chart_post_split_flush(chart);
2334}
2335
2336static void p_chart_simplify(PChart *chart)
2337{
2338 /* Not implemented, needs proper reordering in split_flush. */
2339}
2340#endif
2341
2342/* ABF */
2343
2344#define ABF_MAX_ITER 20
2345
2353
2355{
2356 int i;
2357
2358 sys->alpha = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFalpha");
2359 sys->beta = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFbeta");
2360 sys->sine = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFsine");
2361 sys->cosine = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFcosine");
2362 sys->weight = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFweight");
2363
2364 sys->bAlpha = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFbalpha");
2365 sys->bTriangle = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbtriangle");
2366 sys->bInterior = (float *)MEM_mallocN(sizeof(float[2]) * sys->ninterior, "ABFbinterior");
2367
2368 sys->lambdaTriangle = (float *)MEM_callocN(sizeof(float) * sys->nfaces, "ABFlambdatri");
2369 sys->lambdaPlanar = (float *)MEM_callocN(sizeof(float) * sys->ninterior, "ABFlamdaplane");
2370 sys->lambdaLength = (float *)MEM_mallocN(sizeof(float) * sys->ninterior, "ABFlambdalen");
2371
2372 sys->J2dt = static_cast<float(*)[3]>(MEM_mallocN(sizeof(float) * sys->nangles * 3, "ABFj2dt"));
2373 sys->bstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbstar");
2374 sys->dstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFdstar");
2375
2376 for (i = 0; i < sys->ninterior; i++) {
2377 sys->lambdaLength[i] = 1.0;
2378 }
2379}
2380
2382{
2383 MEM_freeN(sys->alpha);
2384 MEM_freeN(sys->beta);
2385 MEM_freeN(sys->sine);
2386 MEM_freeN(sys->cosine);
2387 MEM_freeN(sys->weight);
2388 MEM_freeN(sys->bAlpha);
2389 MEM_freeN(sys->bTriangle);
2390 MEM_freeN(sys->bInterior);
2392 MEM_freeN(sys->lambdaPlanar);
2393 MEM_freeN(sys->lambdaLength);
2394 MEM_freeN(sys->J2dt);
2395 MEM_freeN(sys->bstar);
2396 MEM_freeN(sys->dstar);
2397}
2398
2400{
2401 float *sine = sys->sine;
2402 float *cosine = sys->cosine;
2403 const float *alpha = sys->alpha;
2404
2405 for (int i = 0; i < sys->nangles; i++) {
2406 const double angle = alpha[i];
2407 sine[i] = sin(angle);
2408 cosine[i] = cos(angle);
2409 }
2410}
2411
2412static float p_abf_compute_sin_product(PAbfSystem *sys, PVert *v, int aid)
2413{
2414 PEdge *e, *e1, *e2;
2415 float sin1, sin2;
2416
2417 sin1 = sin2 = 1.0;
2418
2419 e = v->edge;
2420 do {
2421 e1 = e->next;
2422 e2 = e->next->next;
2423
2424 if (aid == e1->u.id) {
2425 /* we are computing a derivative for this angle,
2426 * so we use cos and drop the other part */
2427 sin1 *= sys->cosine[e1->u.id];
2428 sin2 = 0.0;
2429 }
2430 else {
2431 sin1 *= sys->sine[e1->u.id];
2432 }
2433
2434 if (aid == e2->u.id) {
2435 /* see above */
2436 sin1 = 0.0;
2437 sin2 *= sys->cosine[e2->u.id];
2438 }
2439 else {
2440 sin2 *= sys->sine[e2->u.id];
2441 }
2442
2443 e = e->next->next->pair;
2444 } while (e && (e != v->edge));
2445
2446 return (sin1 - sin2);
2447}
2448
2450{
2451 PVert *v = e->vert, *v1 = e->next->vert, *v2 = e->next->next->vert;
2452 float deriv;
2453
2454 deriv = (sys->alpha[e->u.id] - sys->beta[e->u.id]) * sys->weight[e->u.id];
2455 deriv += sys->lambdaTriangle[f->u.id];
2456
2457 if (v->flag & PVERT_INTERIOR) {
2458 deriv += sys->lambdaPlanar[v->u.id];
2459 }
2460
2461 if (v1->flag & PVERT_INTERIOR) {
2462 float product = p_abf_compute_sin_product(sys, v1, e->u.id);
2463 deriv += sys->lambdaLength[v1->u.id] * product;
2464 }
2465
2466 if (v2->flag & PVERT_INTERIOR) {
2467 float product = p_abf_compute_sin_product(sys, v2, e->u.id);
2468 deriv += sys->lambdaLength[v2->u.id] * product;
2469 }
2470
2471 return deriv;
2472}
2473
2474static float p_abf_compute_gradient(PAbfSystem *sys, PChart *chart)
2475{
2476 PFace *f;
2477 PEdge *e;
2478 PVert *v;
2479 float norm = 0.0;
2480
2481 for (f = chart->faces; f; f = f->nextlink) {
2482 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
2483 float gtriangle, galpha1, galpha2, galpha3;
2484
2485 galpha1 = p_abf_compute_grad_alpha(sys, f, e1);
2486 galpha2 = p_abf_compute_grad_alpha(sys, f, e2);
2487 galpha3 = p_abf_compute_grad_alpha(sys, f, e3);
2488
2489 sys->bAlpha[e1->u.id] = -galpha1;
2490 sys->bAlpha[e2->u.id] = -galpha2;
2491 sys->bAlpha[e3->u.id] = -galpha3;
2492
2493 norm += galpha1 * galpha1 + galpha2 * galpha2 + galpha3 * galpha3;
2494
2495 gtriangle = sys->alpha[e1->u.id] + sys->alpha[e2->u.id] + sys->alpha[e3->u.id] - float(M_PI);
2496 sys->bTriangle[f->u.id] = -gtriangle;
2497 norm += gtriangle * gtriangle;
2498 }
2499
2500 for (v = chart->verts; v; v = v->nextlink) {
2501 if (v->flag & PVERT_INTERIOR) {
2502 float gplanar = -2 * M_PI, glength;
2503
2504 e = v->edge;
2505 do {
2506 gplanar += sys->alpha[e->u.id];
2507 e = e->next->next->pair;
2508 } while (e && (e != v->edge));
2509
2510 sys->bInterior[v->u.id] = -gplanar;
2511 norm += gplanar * gplanar;
2512
2513 glength = p_abf_compute_sin_product(sys, v, -1);
2514 sys->bInterior[sys->ninterior + v->u.id] = -glength;
2515 norm += glength * glength;
2516 }
2517 }
2518
2519 return norm;
2520}
2521
2523 const int id,
2524 const float dlambda1,
2525 const float pre)
2526{
2527 float alpha = sys->alpha[id];
2528 const float dalpha = (sys->bAlpha[id] - dlambda1);
2529 alpha += dalpha / sys->weight[id] - pre;
2530 sys->alpha[id] = clamp_f(alpha, 0.0f, float(M_PI));
2531}
2532
2533static bool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
2534{
2535 int ninterior = sys->ninterior;
2536 int nvar = 2 * ninterior;
2537 LinearSolver *context = EIG_linear_solver_new(0, nvar, 1);
2538
2539 for (int i = 0; i < nvar; i++) {
2540 EIG_linear_solver_right_hand_side_add(context, 0, i, sys->bInterior[i]);
2541 }
2542
2543 for (PFace *f = chart->faces; f; f = f->nextlink) {
2544 float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3];
2545 float row1[6], row2[6], row3[6];
2546 int vid[6];
2547 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
2548 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
2549
2550 wi1 = 1.0f / sys->weight[e1->u.id];
2551 wi2 = 1.0f / sys->weight[e2->u.id];
2552 wi3 = 1.0f / sys->weight[e3->u.id];
2553
2554 /* bstar1 = (J1*dInv*bAlpha - bTriangle) */
2555 b = sys->bAlpha[e1->u.id] * wi1;
2556 b += sys->bAlpha[e2->u.id] * wi2;
2557 b += sys->bAlpha[e3->u.id] * wi3;
2558 b -= sys->bTriangle[f->u.id];
2559
2560 /* si = J1*d*J1t */
2561 si = 1.0f / (wi1 + wi2 + wi3);
2562
2563 /* J1t*si*bstar1 - bAlpha */
2564 beta[0] = b * si - sys->bAlpha[e1->u.id];
2565 beta[1] = b * si - sys->bAlpha[e2->u.id];
2566 beta[2] = b * si - sys->bAlpha[e3->u.id];
2567
2568 /* use this later for computing other lambda's */
2569 sys->bstar[f->u.id] = b;
2570 sys->dstar[f->u.id] = si;
2571
2572 /* set matrix */
2573 W[0][0] = si - sys->weight[e1->u.id];
2574 W[0][1] = si;
2575 W[0][2] = si;
2576 W[1][0] = si;
2577 W[1][1] = si - sys->weight[e2->u.id];
2578 W[1][2] = si;
2579 W[2][0] = si;
2580 W[2][1] = si;
2581 W[2][2] = si - sys->weight[e3->u.id];
2582
2583 vid[0] = vid[1] = vid[2] = vid[3] = vid[4] = vid[5] = -1;
2584
2585 if (v1->flag & PVERT_INTERIOR) {
2586 vid[0] = v1->u.id;
2587 vid[3] = ninterior + v1->u.id;
2588
2589 sys->J2dt[e1->u.id][0] = j2[0][0] = 1.0f * wi1;
2590 sys->J2dt[e2->u.id][0] = j2[1][0] = p_abf_compute_sin_product(sys, v1, e2->u.id) * wi2;
2591 sys->J2dt[e3->u.id][0] = j2[2][0] = p_abf_compute_sin_product(sys, v1, e3->u.id) * wi3;
2592
2593 EIG_linear_solver_right_hand_side_add(context, 0, v1->u.id, j2[0][0] * beta[0]);
2595 context, 0, ninterior + v1->u.id, j2[1][0] * beta[1] + j2[2][0] * beta[2]);
2596
2597 row1[0] = j2[0][0] * W[0][0];
2598 row2[0] = j2[0][0] * W[1][0];
2599 row3[0] = j2[0][0] * W[2][0];
2600
2601 row1[3] = j2[1][0] * W[0][1] + j2[2][0] * W[0][2];
2602 row2[3] = j2[1][0] * W[1][1] + j2[2][0] * W[1][2];
2603 row3[3] = j2[1][0] * W[2][1] + j2[2][0] * W[2][2];
2604 }
2605
2606 if (v2->flag & PVERT_INTERIOR) {
2607 vid[1] = v2->u.id;
2608 vid[4] = ninterior + v2->u.id;
2609
2610 sys->J2dt[e1->u.id][1] = j2[0][1] = p_abf_compute_sin_product(sys, v2, e1->u.id) * wi1;
2611 sys->J2dt[e2->u.id][1] = j2[1][1] = 1.0f * wi2;
2612 sys->J2dt[e3->u.id][1] = j2[2][1] = p_abf_compute_sin_product(sys, v2, e3->u.id) * wi3;
2613
2614 EIG_linear_solver_right_hand_side_add(context, 0, v2->u.id, j2[1][1] * beta[1]);
2616 context, 0, ninterior + v2->u.id, j2[0][1] * beta[0] + j2[2][1] * beta[2]);
2617
2618 row1[1] = j2[1][1] * W[0][1];
2619 row2[1] = j2[1][1] * W[1][1];
2620 row3[1] = j2[1][1] * W[2][1];
2621
2622 row1[4] = j2[0][1] * W[0][0] + j2[2][1] * W[0][2];
2623 row2[4] = j2[0][1] * W[1][0] + j2[2][1] * W[1][2];
2624 row3[4] = j2[0][1] * W[2][0] + j2[2][1] * W[2][2];
2625 }
2626
2627 if (v3->flag & PVERT_INTERIOR) {
2628 vid[2] = v3->u.id;
2629 vid[5] = ninterior + v3->u.id;
2630
2631 sys->J2dt[e1->u.id][2] = j2[0][2] = p_abf_compute_sin_product(sys, v3, e1->u.id) * wi1;
2632 sys->J2dt[e2->u.id][2] = j2[1][2] = p_abf_compute_sin_product(sys, v3, e2->u.id) * wi2;
2633 sys->J2dt[e3->u.id][2] = j2[2][2] = 1.0f * wi3;
2634
2635 EIG_linear_solver_right_hand_side_add(context, 0, v3->u.id, j2[2][2] * beta[2]);
2637 context, 0, ninterior + v3->u.id, j2[0][2] * beta[0] + j2[1][2] * beta[1]);
2638
2639 row1[2] = j2[2][2] * W[0][2];
2640 row2[2] = j2[2][2] * W[1][2];
2641 row3[2] = j2[2][2] * W[2][2];
2642
2643 row1[5] = j2[0][2] * W[0][0] + j2[1][2] * W[0][1];
2644 row2[5] = j2[0][2] * W[1][0] + j2[1][2] * W[1][1];
2645 row3[5] = j2[0][2] * W[2][0] + j2[1][2] * W[2][1];
2646 }
2647
2648 for (int i = 0; i < 3; i++) {
2649 int r = vid[i];
2650
2651 if (r == -1) {
2652 continue;
2653 }
2654
2655 for (int j = 0; j < 6; j++) {
2656 int c = vid[j];
2657
2658 if (c == -1) {
2659 continue;
2660 }
2661
2662 if (i == 0) {
2663 EIG_linear_solver_matrix_add(context, r, c, j2[0][i] * row1[j]);
2664 }
2665 else {
2666 EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[0][i] * row1[j]);
2667 }
2668
2669 if (i == 1) {
2670 EIG_linear_solver_matrix_add(context, r, c, j2[1][i] * row2[j]);
2671 }
2672 else {
2673 EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[1][i] * row2[j]);
2674 }
2675
2676 if (i == 2) {
2677 EIG_linear_solver_matrix_add(context, r, c, j2[2][i] * row3[j]);
2678 }
2679 else {
2680 EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[2][i] * row3[j]);
2681 }
2682 }
2683 }
2684 }
2685
2686 bool success = EIG_linear_solver_solve(context);
2687
2688 if (success) {
2689 for (PFace *f = chart->faces; f; f = f->nextlink) {
2690 float pre[3];
2691 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
2692 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
2693
2694 pre[0] = pre[1] = pre[2] = 0.0f;
2695
2696 if (v1->flag & PVERT_INTERIOR) {
2697 float x = EIG_linear_solver_variable_get(context, 0, v1->u.id);
2698 float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v1->u.id);
2699 pre[0] += sys->J2dt[e1->u.id][0] * x;
2700 pre[1] += sys->J2dt[e2->u.id][0] * x2;
2701 pre[2] += sys->J2dt[e3->u.id][0] * x2;
2702 }
2703
2704 if (v2->flag & PVERT_INTERIOR) {
2705 float x = EIG_linear_solver_variable_get(context, 0, v2->u.id);
2706 float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v2->u.id);
2707 pre[0] += sys->J2dt[e1->u.id][1] * x2;
2708 pre[1] += sys->J2dt[e2->u.id][1] * x;
2709 pre[2] += sys->J2dt[e3->u.id][1] * x2;
2710 }
2711
2712 if (v3->flag & PVERT_INTERIOR) {
2713 float x = EIG_linear_solver_variable_get(context, 0, v3->u.id);
2714 float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v3->u.id);
2715 pre[0] += sys->J2dt[e1->u.id][2] * x2;
2716 pre[1] += sys->J2dt[e2->u.id][2] * x2;
2717 pre[2] += sys->J2dt[e3->u.id][2] * x;
2718 }
2719
2720 float dlambda1 = pre[0] + pre[1] + pre[2];
2721 dlambda1 = sys->dstar[f->u.id] * (sys->bstar[f->u.id] - dlambda1);
2722
2723 sys->lambdaTriangle[f->u.id] += dlambda1;
2724
2725 p_abf_adjust_alpha(sys, e1->u.id, dlambda1, pre[0]);
2726 p_abf_adjust_alpha(sys, e2->u.id, dlambda1, pre[1]);
2727 p_abf_adjust_alpha(sys, e3->u.id, dlambda1, pre[2]);
2728 }
2729
2730 for (int i = 0; i < ninterior; i++) {
2731 sys->lambdaPlanar[i] += float(EIG_linear_solver_variable_get(context, 0, i));
2732 sys->lambdaLength[i] += float(EIG_linear_solver_variable_get(context, 0, ninterior + i));
2733 }
2734 }
2735
2736 EIG_linear_solver_delete(context);
2737
2738 return success;
2739}
2740
2741static bool p_chart_abf_solve(PChart *chart)
2742{
2743 PVert *v;
2744 PFace *f;
2745 PEdge *e, *e1, *e2, *e3;
2746 PAbfSystem sys;
2747 int i;
2748 float /* lastnorm, */ /* UNUSED */ limit = (chart->nfaces > 100) ? 1.0f : 0.001f;
2749
2750 /* setup id's */
2751 sys.ninterior = sys.nfaces = sys.nangles = 0;
2752
2753 for (v = chart->verts; v; v = v->nextlink) {
2754 if (p_vert_interior(v)) {
2755 v->flag |= PVERT_INTERIOR;
2756 v->u.id = sys.ninterior++;
2757 }
2758 else {
2759 v->flag &= ~PVERT_INTERIOR;
2760 }
2761 }
2762
2763 for (f = chart->faces; f; f = f->nextlink) {
2764 e1 = f->edge;
2765 e2 = e1->next;
2766 e3 = e2->next;
2767 f->u.id = sys.nfaces++;
2768
2769 /* angle id's are conveniently stored in half edges */
2770 e1->u.id = sys.nangles++;
2771 e2->u.id = sys.nangles++;
2772 e3->u.id = sys.nangles++;
2773 }
2774
2775 p_abf_setup_system(&sys);
2776
2777 /* compute initial angles */
2778 for (f = chart->faces; f; f = f->nextlink) {
2779 double a1, a2, a3;
2780
2781 e1 = f->edge;
2782 e2 = e1->next;
2783 e3 = e2->next;
2784 p_face_angles(f, &a1, &a2, &a3);
2785
2786 sys.alpha[e1->u.id] = sys.beta[e1->u.id] = a1;
2787 sys.alpha[e2->u.id] = sys.beta[e2->u.id] = a2;
2788 sys.alpha[e3->u.id] = sys.beta[e3->u.id] = a3;
2789
2790 sys.weight[e1->u.id] = 2.0f / (a1 * a1);
2791 sys.weight[e2->u.id] = 2.0f / (a2 * a2);
2792 sys.weight[e3->u.id] = 2.0f / (a3 * a3);
2793 }
2794
2795 for (v = chart->verts; v; v = v->nextlink) {
2796 if (v->flag & PVERT_INTERIOR) {
2797 float anglesum = 0.0, scale;
2798
2799 e = v->edge;
2800 do {
2801 anglesum += sys.beta[e->u.id];
2802 e = e->next->next->pair;
2803 } while (e && (e != v->edge));
2804
2805 scale = (anglesum == 0.0f) ? 0.0f : 2.0f * float(M_PI) / anglesum;
2806
2807 e = v->edge;
2808 do {
2809 sys.beta[e->u.id] = sys.alpha[e->u.id] = sys.beta[e->u.id] * scale;
2810 e = e->next->next->pair;
2811 } while (e && (e != v->edge));
2812 }
2813 }
2814
2815 if (sys.ninterior > 0) {
2816 p_abf_compute_sines(&sys);
2817
2818 /* iteration */
2819 // lastnorm = 1e10; /* UNUSED. */
2820
2821 for (i = 0; i < ABF_MAX_ITER; i++) {
2822 float norm = p_abf_compute_gradient(&sys, chart);
2823
2824 // lastnorm = norm; /* UNUSED. */
2825
2826 if (norm < limit) {
2827 break;
2828 }
2829
2830 if (!p_abf_matrix_invert(&sys, chart)) {
2831 param_warning("ABF failed to invert matrix");
2832 p_abf_free_system(&sys);
2833 return false;
2834 }
2835
2836 p_abf_compute_sines(&sys);
2837 }
2838
2839 if (i == ABF_MAX_ITER) {
2840 param_warning("ABF maximum iterations reached");
2841 p_abf_free_system(&sys);
2842 return false;
2843 }
2844 }
2845
2846 chart->abf_alpha = (float *)MEM_dupallocN(sys.alpha);
2847 p_abf_free_system(&sys);
2848
2849 return true;
2850}
2851
2852/* Least Squares Conformal Maps */
2853
2854static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2)
2855{
2856 if (!*pin1 || !*pin2 || *pin1 == *pin2) {
2857 /* degenerate case */
2858 PFace *f = chart->faces;
2859 *pin1 = f->edge->vert;
2860 *pin2 = f->edge->next->vert;
2861
2862 (*pin1)->uv[0] = 0.0f;
2863 (*pin1)->uv[1] = 0.5f;
2864 (*pin2)->uv[0] = 1.0f;
2865 (*pin2)->uv[1] = 0.5f;
2866 }
2867 else {
2868 int diru, dirv, dirx, diry;
2869 float sub[3];
2870
2871 sub_v3_v3v3(sub, (*pin1)->co, (*pin2)->co);
2872 sub[0] = fabsf(sub[0]);
2873 sub[1] = fabsf(sub[1]);
2874 sub[2] = fabsf(sub[2]);
2875
2876 if ((sub[0] > sub[1]) && (sub[0] > sub[2])) {
2877 dirx = 0;
2878 diry = (sub[1] > sub[2]) ? 1 : 2;
2879 }
2880 else if ((sub[1] > sub[0]) && (sub[1] > sub[2])) {
2881 dirx = 1;
2882 diry = (sub[0] > sub[2]) ? 0 : 2;
2883 }
2884 else {
2885 dirx = 2;
2886 diry = (sub[0] > sub[1]) ? 0 : 1;
2887 }
2888
2889 if (dirx == 2) {
2890 diru = 1;
2891 dirv = 0;
2892 }
2893 else {
2894 diru = 0;
2895 dirv = 1;
2896 }
2897
2898 (*pin1)->uv[diru] = (*pin1)->co[dirx];
2899 (*pin1)->uv[dirv] = (*pin1)->co[diry];
2900 (*pin2)->uv[diru] = (*pin2)->co[dirx];
2901 (*pin2)->uv[dirv] = (*pin2)->co[diry];
2902 }
2903}
2904
2905static bool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2)
2906{
2907 PEdge *be, *lastbe = nullptr, *maxe1 = nullptr, *maxe2 = nullptr, *be1, *be2;
2908 PEdge *cure = nullptr, *firste1 = nullptr, *firste2 = nullptr, *nextbe;
2909 float maxlen = 0.0f, curlen = 0.0f, totlen = 0.0f, firstlen = 0.0f;
2910 float len1, len2;
2911
2912 /* find longest series of verts split in the chart itself, these are
2913 * marked during construction */
2914 be = outer;
2915 lastbe = p_boundary_edge_prev(be);
2916 do {
2917 float len = p_edge_length(be);
2918 totlen += len;
2919
2920 nextbe = p_boundary_edge_next(be);
2921
2922 if ((be->vert->flag & PVERT_SPLIT) || (lastbe->vert->flag & nextbe->vert->flag & PVERT_SPLIT))
2923 {
2924 if (!cure) {
2925 if (be == outer) {
2926 firste1 = be;
2927 }
2928 cure = be;
2929 }
2930 else {
2931 curlen += p_edge_length(lastbe);
2932 }
2933 }
2934 else if (cure) {
2935 if (curlen > maxlen) {
2936 maxlen = curlen;
2937 maxe1 = cure;
2938 maxe2 = lastbe;
2939 }
2940
2941 if (firste1 == cure) {
2942 firstlen = curlen;
2943 firste2 = lastbe;
2944 }
2945
2946 curlen = 0.0f;
2947 cure = nullptr;
2948 }
2949
2950 lastbe = be;
2951 be = nextbe;
2952 } while (be != outer);
2953
2954 /* make sure we also count a series of splits over the starting point */
2955 if (cure && (cure != outer)) {
2956 firstlen += curlen + p_edge_length(be);
2957
2958 if (firstlen > maxlen) {
2959 maxlen = firstlen;
2960 maxe1 = cure;
2961 maxe2 = firste2;
2962 }
2963 }
2964
2965 if (!maxe1 || !maxe2 || (maxlen < 0.5f * totlen)) {
2966 return false;
2967 }
2968
2969 /* find pin1 in the split vertices */
2970 be1 = maxe1;
2971 be2 = maxe2;
2972 len1 = 0.0f;
2973 len2 = 0.0f;
2974
2975 do {
2976 if (len1 < len2) {
2977 len1 += p_edge_length(be1);
2978 be1 = p_boundary_edge_next(be1);
2979 }
2980 else {
2981 be2 = p_boundary_edge_prev(be2);
2982 len2 += p_edge_length(be2);
2983 }
2984 } while (be1 != be2);
2985
2986 *pin1 = be1->vert;
2987
2988 /* find pin2 outside the split vertices */
2989 be1 = maxe1;
2990 be2 = maxe2;
2991 len1 = 0.0f;
2992 len2 = 0.0f;
2993
2994 do {
2995 if (len1 < len2) {
2996 be1 = p_boundary_edge_prev(be1);
2997 len1 += p_edge_length(be1);
2998 }
2999 else {
3000 len2 += p_edge_length(be2);
3001 be2 = p_boundary_edge_next(be2);
3002 }
3003 } while (be1 != be2);
3004
3005 *pin2 = be1->vert;
3006
3007 p_chart_pin_positions(chart, pin1, pin2);
3008
3009 return !equals_v3v3((*pin1)->co, (*pin2)->co);
3010}
3011
3012static void p_chart_extrema_verts(PChart *chart, PVert **pin1, PVert **pin2)
3013{
3014 float minv[3], maxv[3], dirlen;
3015 PVert *v, *minvert[3], *maxvert[3];
3016 int i, dir;
3017
3018 /* find minimum and maximum verts over x/y/z axes */
3019 minv[0] = minv[1] = minv[2] = 1e20;
3020 maxv[0] = maxv[1] = maxv[2] = -1e20;
3021
3022 minvert[0] = minvert[1] = minvert[2] = nullptr;
3023 maxvert[0] = maxvert[1] = maxvert[2] = nullptr;
3024
3025 for (v = chart->verts; v; v = v->nextlink) {
3026 for (i = 0; i < 3; i++) {
3027 if (v->co[i] < minv[i]) {
3028 minv[i] = v->co[i];
3029 minvert[i] = v;
3030 }
3031 if (v->co[i] > maxv[i]) {
3032 maxv[i] = v->co[i];
3033 maxvert[i] = v;
3034 }
3035 }
3036 }
3037
3038 /* find axes with longest distance */
3039 dir = 0;
3040 dirlen = -1.0;
3041
3042 for (i = 0; i < 3; i++) {
3043 if (maxv[i] - minv[i] > dirlen) {
3044 dir = i;
3045 dirlen = maxv[i] - minv[i];
3046 }
3047 }
3048
3049 *pin1 = minvert[dir];
3050 *pin2 = maxvert[dir];
3051
3052 p_chart_pin_positions(chart, pin1, pin2);
3053}
3054
3055static void p_chart_lscm_begin(PChart *chart, bool live, bool abf)
3056{
3057 BLI_assert(chart->context == nullptr);
3058
3059 bool select = false;
3060 bool deselect = false;
3061 int npins = 0;
3062
3063 /* Give vertices matrix indices, count pins and check selections. */
3064 for (PVert *v = chart->verts; v; v = v->nextlink) {
3065 if (v->flag & PVERT_PIN) {
3066 npins++;
3067 if (v->flag & PVERT_SELECT) {
3068 select = true;
3069 }
3070 }
3071
3072 if (!(v->flag & PVERT_SELECT)) {
3073 deselect = true;
3074 }
3075 }
3076
3077 if (live && (!select || !deselect)) {
3078 chart->skip_flush = true;
3079 return;
3080 }
3081#if 0
3082 p_chart_simplify_compute(chart, p_collapse_cost, p_collapse_allowed);
3083 p_chart_topological_sanity_check(chart);
3084#endif
3085
3086 if (npins == 1) {
3087 chart->area_uv = p_chart_uv_area(chart);
3088 for (PVert *v = chart->verts; v; v = v->nextlink) {
3089 if (v->flag & PVERT_PIN) {
3090 chart->single_pin = v;
3091 break;
3092 }
3093 }
3094 }
3095
3096 if (abf) {
3097 if (!p_chart_abf_solve(chart)) {
3098 param_warning("ABF solving failed: falling back to LSCM.\n");
3099 }
3100 }
3101
3102 /* ABF uses these indices for it's internal references.
3103 * Set the indices afterwards. */
3104 int id = 0;
3105 for (PVert *v = chart->verts; v; v = v->nextlink) {
3106 v->u.id = id++;
3107 }
3108
3109 if (npins <= 1) {
3110 /* No pins, let's find some ourself. */
3111 PEdge *outer;
3112 p_chart_boundaries(chart, &outer);
3113
3114 PVert *pin1, *pin2;
3115 /* Outer can be null with non-finite coordinates. */
3116 if (!(outer && p_chart_symmetry_pins(chart, outer, &pin1, &pin2))) {
3117 p_chart_extrema_verts(chart, &pin1, &pin2);
3118 }
3119
3120 chart->pin1 = pin1;
3121 chart->pin2 = pin2;
3122 }
3123
3124 chart->context = EIG_linear_least_squares_solver_new(2 * chart->nfaces, 2 * chart->nverts, 1);
3125}
3126
3127static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
3128{
3129 LinearSolver *context = chart->context;
3130
3131 for (PVert *v = chart->verts; v; v = v->nextlink) {
3132 if (v->flag & PVERT_PIN) {
3133 p_vert_load_pin_select_uvs(handle, v); /* Reload for Live Unwrap. */
3134 }
3135 }
3136
3137 if (chart->single_pin) {
3138 /* If only one pin, save location as origin. */
3139 copy_v2_v2(chart->origin, chart->single_pin->uv);
3140 }
3141
3142 if (chart->pin1) {
3143 PVert *pin1 = chart->pin1;
3144 PVert *pin2 = chart->pin2;
3145 EIG_linear_solver_variable_lock(context, 2 * pin1->u.id);
3146 EIG_linear_solver_variable_lock(context, 2 * pin1->u.id + 1);
3147 EIG_linear_solver_variable_lock(context, 2 * pin2->u.id);
3148 EIG_linear_solver_variable_lock(context, 2 * pin2->u.id + 1);
3149
3150 EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id, pin1->uv[0]);
3151 EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id + 1, pin1->uv[1]);
3152 EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id, pin2->uv[0]);
3153 EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id + 1, pin2->uv[1]);
3154 }
3155 else {
3156 /* Set and lock the pins. */
3157 for (PVert *v = chart->verts; v; v = v->nextlink) {
3158 if (v->flag & PVERT_PIN) {
3159 EIG_linear_solver_variable_lock(context, 2 * v->u.id);
3160 EIG_linear_solver_variable_lock(context, 2 * v->u.id + 1);
3161
3162 EIG_linear_solver_variable_set(context, 0, 2 * v->u.id, v->uv[0]);
3163 EIG_linear_solver_variable_set(context, 0, 2 * v->u.id + 1, v->uv[1]);
3164 }
3165 }
3166 }
3167
3168 /* Detect "up" direction based on pinned vertices. */
3169 float area_pinned_up = 0.0f;
3170 float area_pinned_down = 0.0f;
3171
3172 for (PFace *f = chart->faces; f; f = f->nextlink) {
3173 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
3174 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
3175
3176 if ((v1->flag & PVERT_PIN) && (v2->flag & PVERT_PIN) && (v3->flag & PVERT_PIN)) {
3177 const float area = p_face_uv_area_signed(f);
3178
3179 if (area > 0.0f) {
3180 area_pinned_up += area;
3181 }
3182 else {
3183 area_pinned_down -= area;
3184 }
3185 }
3186 }
3187
3188 const bool flip_faces = (area_pinned_down > area_pinned_up);
3189
3190 /* Construct matrix. */
3191 const float *alpha = chart->abf_alpha;
3192 int row = 0;
3193 for (PFace *f = chart->faces; f; f = f->nextlink) {
3194 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
3195 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
3196 double a1, a2, a3;
3197
3198 if (alpha) {
3199 /* Use abf angles if present. */
3200 a1 = *(alpha++);
3201 a2 = *(alpha++);
3202 a3 = *(alpha++);
3203 }
3204 else {
3205 p_face_angles(f, &a1, &a2, &a3);
3206 }
3207
3208 if (flip_faces) {
3209 std::swap(a2, a3);
3210 std::swap(e2, e3);
3211 std::swap(v2, v3);
3212 }
3213
3214 double sina1 = sin(a1);
3215 double sina2 = sin(a2);
3216 double sina3 = sin(a3);
3217
3218 const double sinmax = max_ddd(sina1, sina2, sina3);
3219
3220 /* Shift vertices to find most stable order. */
3221 if (sina3 != sinmax) {
3222 SHIFT3(PVert *, v1, v2, v3);
3223 SHIFT3(double, a1, a2, a3);
3224 SHIFT3(double, sina1, sina2, sina3);
3225
3226 if (sina2 == sinmax) {
3227 SHIFT3(PVert *, v1, v2, v3);
3228 SHIFT3(double, a1, a2, a3);
3229 SHIFT3(double, sina1, sina2, sina3);
3230 }
3231 }
3232
3233 /* Angle based lscm formulation. */
3234 const double ratio = (sina3 == 0.0f) ? 1.0f : sina2 / sina3;
3235 const double cosine = cos(a1) * ratio;
3236 const double sine = sina1 * ratio;
3237
3238 EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, cosine - 1.0f);
3239 EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, -sine);
3240 EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -cosine);
3241 EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, sine);
3242 EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id, 1.0);
3243 row++;
3244
3245 EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, sine);
3246 EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, cosine - 1.0f);
3247 EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -sine);
3248 EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, -cosine);
3249 EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id + 1, 1.0);
3250 row++;
3251 }
3252
3253 if (EIG_linear_solver_solve(context)) {
3254 for (PVert *v = chart->verts; v; v = v->nextlink) {
3255 v->uv[0] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id);
3256 v->uv[1] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id + 1);
3257 }
3258 return true;
3259 }
3260
3261 for (PVert *v = chart->verts; v; v = v->nextlink) {
3262 v->uv[0] = 0.0f;
3263 v->uv[1] = 0.0f;
3264 }
3265
3266 return false;
3267}
3268
3270{
3271 PVert *pin = chart->single_pin;
3272
3273 /* If only one pin, keep UV area the same. */
3274 const float new_area = p_chart_uv_area(chart);
3275 if (new_area > 0.0f) {
3276 const float scale = chart->area_uv / new_area;
3277 if (scale > 0.0f) {
3278 p_chart_uv_scale(chart, sqrtf(scale));
3279 }
3280 }
3281
3282 /* Translate to keep the pinned UV in place. */
3283 float offset[2];
3284 sub_v2_v2v2(offset, chart->origin, pin->uv);
3285 p_chart_uv_translate(chart, offset);
3286}
3287
3288static void p_chart_lscm_end(PChart *chart)
3289{
3291 chart->context = nullptr;
3292
3293 MEM_SAFE_FREE(chart->abf_alpha);
3294
3295 chart->pin1 = nullptr;
3296 chart->pin2 = nullptr;
3297 chart->single_pin = nullptr;
3298}
3299
3300/* Stretch */
3301
3302#define P_STRETCH_ITER 20
3303
3305{
3306 PVert *v;
3307
3308 for (v = chart->verts; v; v = v->nextlink) {
3309 if (v->edge->pair == nullptr) {
3310 v->flag |= PVERT_PIN;
3311 }
3312 else {
3313 v->flag &= ~PVERT_PIN;
3314 }
3315 }
3316}
3317
3318static float p_face_stretch(PFace *f)
3319{
3320 float T, w, tmp[3];
3321 float Ps[3], Pt[3];
3322 float a, c, area;
3323 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
3324 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
3325
3326 area = p_face_uv_area_signed(f);
3327
3328 if (area <= 0.0f) {
3329 /* When a face is flipped, provide a large penalty.
3330 * Add on a slight gradient to unflip the face, see also: #99781. */
3331 return 1e8f * (1.0f + p_edge_uv_length(e1) + p_edge_uv_length(e2) + p_edge_uv_length(e3));
3332 }
3333
3334 w = 1.0f / (2.0f * area);
3335
3336 /* compute derivatives */
3337 copy_v3_v3(Ps, v1->co);
3338 mul_v3_fl(Ps, (v2->uv[1] - v3->uv[1]));
3339
3340 copy_v3_v3(tmp, v2->co);
3341 mul_v3_fl(tmp, (v3->uv[1] - v1->uv[1]));
3342 add_v3_v3(Ps, tmp);
3343
3344 copy_v3_v3(tmp, v3->co);
3345 mul_v3_fl(tmp, (v1->uv[1] - v2->uv[1]));
3346 add_v3_v3(Ps, tmp);
3347
3348 mul_v3_fl(Ps, w);
3349
3350 copy_v3_v3(Pt, v1->co);
3351 mul_v3_fl(Pt, (v3->uv[0] - v2->uv[0]));
3352
3353 copy_v3_v3(tmp, v2->co);
3354 mul_v3_fl(tmp, (v1->uv[0] - v3->uv[0]));
3355 add_v3_v3(Pt, tmp);
3356
3357 copy_v3_v3(tmp, v3->co);
3358 mul_v3_fl(tmp, (v2->uv[0] - v1->uv[0]));
3359 add_v3_v3(Pt, tmp);
3360
3361 mul_v3_fl(Pt, w);
3362
3363 /* Sander Tensor */
3364 a = dot_v3v3(Ps, Ps);
3365 c = dot_v3v3(Pt, Pt);
3366
3367 T = sqrtf(0.5f * (a + c));
3368 if (f->flag & PFACE_FILLED) {
3369 T *= 0.2f;
3370 }
3371
3372 return T;
3373}
3374
3376{
3377 PEdge *e = v->edge;
3378 float sum = 0.0f;
3379
3380 do {
3381 sum += p_face_stretch(e->face);
3383 } while (e && e != (v->edge));
3384
3385 return sum;
3386}
3387
3388static void p_chart_stretch_minimize(PChart *chart, RNG *rng)
3389{
3390 PVert *v;
3391 PEdge *e;
3392 int j, nedges;
3393 float orig_stretch, low, stretch_low, high, stretch_high, mid, stretch;
3394 float orig_uv[2], dir[2], random_angle, trusted_radius;
3395
3396 for (v = chart->verts; v; v = v->nextlink) {
3397 if ((v->flag & PVERT_PIN) || !(v->flag & PVERT_SELECT)) {
3398 continue;
3399 }
3400
3401 orig_stretch = p_stretch_compute_vertex(v);
3402 orig_uv[0] = v->uv[0];
3403 orig_uv[1] = v->uv[1];
3404
3405 /* move vertex in a random direction */
3406 trusted_radius = 0.0f;
3407 nedges = 0;
3408 e = v->edge;
3409
3410 do {
3411 trusted_radius += p_edge_uv_length(e);
3412 nedges++;
3413
3415 } while (e && e != (v->edge));
3416
3417 trusted_radius /= 2 * nedges;
3418
3419 random_angle = BLI_rng_get_float(rng) * 2.0f * float(M_PI);
3420 dir[0] = trusted_radius * cosf(random_angle);
3421 dir[1] = trusted_radius * sinf(random_angle);
3422
3423 /* calculate old and new stretch */
3424 low = 0;
3425 stretch_low = orig_stretch;
3426
3427 add_v2_v2v2(v->uv, orig_uv, dir);
3428 high = 1;
3429 stretch = stretch_high = p_stretch_compute_vertex(v);
3430
3431 /* binary search for lowest stretch position */
3432 for (j = 0; j < P_STRETCH_ITER; j++) {
3433 mid = 0.5f * (low + high);
3434 v->uv[0] = orig_uv[0] + mid * dir[0];
3435 v->uv[1] = orig_uv[1] + mid * dir[1];
3436 stretch = p_stretch_compute_vertex(v);
3437
3438 if (stretch_low < stretch_high) {
3439 high = mid;
3440 stretch_high = stretch;
3441 }
3442 else {
3443 low = mid;
3444 stretch_low = stretch;
3445 }
3446 }
3447
3448 /* no luck, stretch has increased, reset to old values */
3449 if (stretch >= orig_stretch) {
3450 copy_v2_v2(v->uv, orig_uv);
3451 }
3452 }
3453}
3454
3455/* Minimum area enclosing rectangle for packing */
3456
3457static int p_compare_geometric_uv(const void *a, const void *b)
3458{
3459 const PVert *v1 = *(const PVert *const *)a;
3460 const PVert *v2 = *(const PVert *const *)b;
3461
3462 if (v1->uv[0] < v2->uv[0]) {
3463 return -1;
3464 }
3465 if (v1->uv[0] == v2->uv[0]) {
3466 if (v1->uv[1] < v2->uv[1]) {
3467 return -1;
3468 }
3469 if (v1->uv[1] == v2->uv[1]) {
3470 return 0;
3471 }
3472 return 1;
3473 }
3474 return 1;
3475}
3476
3477static bool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, int *r_right)
3478{
3479 /* Graham algorithm, taken from:
3480 * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117225 */
3481
3482 PEdge *be, *e;
3483 int npoints = 0, i, ulen, llen;
3484 PVert **U, **L, **points, **p;
3485
3486 p_chart_boundaries(chart, &be);
3487
3488 if (!be) {
3489 return false;
3490 }
3491
3492 e = be;
3493 do {
3494 npoints++;
3496 } while (e != be);
3497
3498 p = points = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints * 2, "PCHullpoints");
3499 U = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints, "PCHullU");
3500 L = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints, "PCHullL");
3501
3502 e = be;
3503 do {
3504 *p = e->vert;
3505 p++;
3507 } while (e != be);
3508
3509 qsort(points, npoints, sizeof(PVert *), p_compare_geometric_uv);
3510
3511 ulen = llen = 0;
3512 for (p = points, i = 0; i < npoints; i++, p++) {
3513 while ((ulen > 1) && (p_area_signed(U[ulen - 2]->uv, (*p)->uv, U[ulen - 1]->uv) <= 0)) {
3514 ulen--;
3515 }
3516 while ((llen > 1) && (p_area_signed(L[llen - 2]->uv, (*p)->uv, L[llen - 1]->uv) >= 0)) {
3517 llen--;
3518 }
3519
3520 U[ulen] = *p;
3521 ulen++;
3522 L[llen] = *p;
3523 llen++;
3524 }
3525
3526 npoints = 0;
3527 for (p = points, i = 0; i < ulen; i++, p++, npoints++) {
3528 *p = U[i];
3529 }
3530
3531 /* the first and last point in L are left out, since they are also in U */
3532 for (i = llen - 2; i > 0; i--, p++, npoints++) {
3533 *p = L[i];
3534 }
3535
3536 *r_verts = points;
3537 *r_nverts = npoints;
3538 *r_right = ulen - 1;
3539
3540 MEM_freeN(U);
3541 MEM_freeN(L);
3542
3543 return true;
3544}
3545
3546static float p_rectangle_area(float *p1, float *dir, float *p2, float *p3, float *p4)
3547{
3548 /* given 4 points on the rectangle edges and the direction of on edge,
3549 * compute the area of the rectangle */
3550
3551 float orthodir[2], corner1[2], corner2[2], corner3[2];
3552
3553 orthodir[0] = dir[1];
3554 orthodir[1] = -dir[0];
3555
3556 if (!p_intersect_line_2d_dir(p1, dir, p2, orthodir, corner1)) {
3557 return 1e10;
3558 }
3559
3560 if (!p_intersect_line_2d_dir(p1, dir, p4, orthodir, corner2)) {
3561 return 1e10;
3562 }
3563
3564 if (!p_intersect_line_2d_dir(p3, dir, p4, orthodir, corner3)) {
3565 return 1e10;
3566 }
3567
3568 return len_v2v2(corner1, corner2) * len_v2v2(corner2, corner3);
3569}
3570
3572{
3573 /* minimum area enclosing rectangle with rotating calipers, info:
3574 * http://cgm.cs.mcgill.ca/~orm/maer.html */
3575
3576 float rotated, minarea, minangle, area, len;
3577 float *angles, miny, maxy, v[2], a[4], mina;
3578 int npoints, right, i_min, i_max, i, idx[4], nextidx;
3579 PVert **points, *p1, *p2, *p3, *p4, *p1n;
3580
3581 /* compute convex hull */
3582 if (!p_chart_convex_hull(chart, &points, &npoints, &right)) {
3583 return 0.0;
3584 }
3585
3586 /* find left/top/right/bottom points, and compute angle for each point */
3587 angles = (float *)MEM_mallocN(sizeof(float) * npoints, "PMinAreaAngles");
3588
3589 i_min = i_max = 0;
3590 miny = 1e10;
3591 maxy = -1e10;
3592
3593 for (i = 0; i < npoints; i++) {
3594 p1 = (i == 0) ? points[npoints - 1] : points[i - 1];
3595 p2 = points[i];
3596 p3 = (i == npoints - 1) ? points[0] : points[i + 1];
3597
3598 angles[i] = float(M_PI) - angle_v2v2v2(p1->uv, p2->uv, p3->uv);
3599
3600 if (points[i]->uv[1] < miny) {
3601 miny = points[i]->uv[1];
3602 i_min = i;
3603 }
3604 if (points[i]->uv[1] > maxy) {
3605 maxy = points[i]->uv[1];
3606 i_max = i;
3607 }
3608 }
3609
3610 /* left, top, right, bottom */
3611 idx[0] = 0;
3612 idx[1] = i_max;
3613 idx[2] = right;
3614 idx[3] = i_min;
3615
3616 v[0] = points[idx[0]]->uv[0];
3617 v[1] = points[idx[0]]->uv[1] + 1.0f;
3618 a[0] = angle_v2v2v2(points[(idx[0] + 1) % npoints]->uv, points[idx[0]]->uv, v);
3619
3620 v[0] = points[idx[1]]->uv[0] + 1.0f;
3621 v[1] = points[idx[1]]->uv[1];
3622 a[1] = angle_v2v2v2(points[(idx[1] + 1) % npoints]->uv, points[idx[1]]->uv, v);
3623
3624 v[0] = points[idx[2]]->uv[0];
3625 v[1] = points[idx[2]]->uv[1] - 1.0f;
3626 a[2] = angle_v2v2v2(points[(idx[2] + 1) % npoints]->uv, points[idx[2]]->uv, v);
3627
3628 v[0] = points[idx[3]]->uv[0] - 1.0f;
3629 v[1] = points[idx[3]]->uv[1];
3630 a[3] = angle_v2v2v2(points[(idx[3] + 1) % npoints]->uv, points[idx[3]]->uv, v);
3631
3632 /* 4 rotating calipers */
3633
3634 rotated = 0.0;
3635 minarea = 1e10;
3636 minangle = 0.0;
3637
3638 while (rotated <= float(M_PI_2)) { /* INVESTIGATE: how far to rotate? */
3639 /* rotate with the smallest angle */
3640 i_min = 0;
3641 mina = 1e10;
3642
3643 for (i = 0; i < 4; i++) {
3644 if (a[i] < mina) {
3645 mina = a[i];
3646 i_min = i;
3647 }
3648 }
3649
3650 rotated += mina;
3651 nextidx = (idx[i_min] + 1) % npoints;
3652
3653 a[i_min] = angles[nextidx];
3654 a[(i_min + 1) % 4] = a[(i_min + 1) % 4] - mina;
3655 a[(i_min + 2) % 4] = a[(i_min + 2) % 4] - mina;
3656 a[(i_min + 3) % 4] = a[(i_min + 3) % 4] - mina;
3657
3658 /* compute area */
3659 p1 = points[idx[i_min]];
3660 p1n = points[nextidx];
3661 p2 = points[idx[(i_min + 1) % 4]];
3662 p3 = points[idx[(i_min + 2) % 4]];
3663 p4 = points[idx[(i_min + 3) % 4]];
3664
3665 len = len_v2v2(p1->uv, p1n->uv);
3666
3667 if (len > 0.0f) {
3668 len = 1.0f / len;
3669 v[0] = (p1n->uv[0] - p1->uv[0]) * len;
3670 v[1] = (p1n->uv[1] - p1->uv[1]) * len;
3671
3672 area = p_rectangle_area(p1->uv, v, p2->uv, p3->uv, p4->uv);
3673
3674 /* remember smallest area */
3675 if (area < minarea) {
3676 minarea = area;
3677 minangle = rotated;
3678 }
3679 }
3680
3681 idx[i_min] = nextidx;
3682 }
3683
3684 /* try keeping rotation as small as possible */
3685 if (minangle > float(M_PI_4)) {
3686 minangle -= float(M_PI_2);
3687 }
3688
3689 MEM_freeN(angles);
3690 MEM_freeN(points);
3691
3692 return minangle;
3693}
3694
3696{
3697 float angle = p_chart_minimum_area_angle(chart);
3698 float sine = sinf(angle);
3699 float cosine = cosf(angle);
3700 PVert *v;
3701
3702 for (v = chart->verts; v; v = v->nextlink) {
3703 float oldu = v->uv[0], oldv = v->uv[1];
3704 v->uv[0] = cosine * oldu - sine * oldv;
3705 v->uv[1] = sine * oldu + cosine * oldv;
3706 }
3707}
3708
3710{
3711 float(*points)[2] = static_cast<float(*)[2]>(
3712 MEM_mallocN(sizeof(*points) * chart->nverts, __func__));
3713
3714 p_chart_uv_to_array(chart, points);
3715
3716 float angle = BLI_convexhull_aabb_fit_points_2d(points, chart->nverts);
3717
3718 MEM_freeN(points);
3719
3720 if (angle != 0.0f) {
3721 float mat[2][2];
3722 angle_to_mat2(mat, angle);
3723 p_chart_uv_transform(chart, mat);
3724 }
3725}
3726
3739
3741{
3743 arena = nullptr;
3745 polyfill_arena = nullptr;
3746 BLI_heap_free(polyfill_heap, nullptr);
3747 polyfill_heap = nullptr;
3748
3750
3754
3755 if (pin_hash) {
3756 BLI_ghash_free(pin_hash, nullptr, nullptr);
3757 pin_hash = nullptr;
3758 }
3759
3760 for (int i = 0; i < ncharts; i++) {
3762 }
3764
3765 if (rng) {
3767 rng = nullptr;
3768 }
3769}
3770
3771void uv_parametrizer_aspect_ratio(ParamHandle *phandle, const float aspect_y)
3772{
3773 BLI_assert(aspect_y > 0.0f);
3774 phandle->aspect_y = aspect_y;
3775}
3776
3782
3783ParamKey uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
3784{
3785 if (!handle->pin_hash) {
3786 return bmvertindex; /* No verts pinned. */
3787 }
3788
3789 const GeoUVPinIndex *pinuvlist = (const GeoUVPinIndex *)BLI_ghash_lookup(
3790 handle->pin_hash, POINTER_FROM_INT(bmvertindex));
3791 if (!pinuvlist) {
3792 return bmvertindex; /* Vert not pinned. */
3793 }
3794
3795 /* At least one of the UVs associated with bmvertindex is pinned. Find the best one. */
3796 float bestdistsquared = len_squared_v2v2(pinuvlist->uv, uv);
3797 ParamKey bestkey = pinuvlist->reindex;
3798 pinuvlist = pinuvlist->next;
3799 while (pinuvlist) {
3800 const float distsquared = len_squared_v2v2(pinuvlist->uv, uv);
3801 if (bestdistsquared > distsquared) {
3802 bestdistsquared = distsquared;
3803 bestkey = pinuvlist->reindex;
3804 }
3805 pinuvlist = pinuvlist->next;
3806 }
3807 return bestkey;
3808}
3809
3810static GeoUVPinIndex *new_geo_uv_pinindex(ParamHandle *handle, const float uv[2])
3811{
3812 GeoUVPinIndex *pinuv = (GeoUVPinIndex *)BLI_memarena_alloc(handle->arena, sizeof(*pinuv));
3813 pinuv->next = nullptr;
3814 copy_v2_v2(pinuv->uv, uv);
3815 pinuv->reindex = PARAM_KEY_MAX - (handle->unique_pin_count++);
3816 return pinuv;
3817}
3818
3819void uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
3820{
3821 if (!handle->pin_hash) {
3822 handle->pin_hash = BLI_ghash_int_new("uv pin reindex");
3823 }
3824
3825 GeoUVPinIndex *pinuvlist = (GeoUVPinIndex *)BLI_ghash_lookup(handle->pin_hash,
3826 POINTER_FROM_INT(bmvertindex));
3827 if (!pinuvlist) {
3829 handle->pin_hash, POINTER_FROM_INT(bmvertindex), new_geo_uv_pinindex(handle, uv));
3830 return;
3831 }
3832
3833 while (true) {
3834 if (equals_v2v2(pinuvlist->uv, uv)) {
3835 return;
3836 }
3837 if (!pinuvlist->next) {
3838 pinuvlist->next = new_geo_uv_pinindex(handle, uv);
3839 return;
3840 }
3841 pinuvlist = pinuvlist->next;
3842 }
3843}
3844
3845static void p_add_ngon(ParamHandle *handle,
3846 const ParamKey key,
3847 const int nverts,
3848 const ParamKey *vkeys,
3849 const float **co,
3850 float **uv, /* Output will eventually be written to `uv`. */
3851 const float *weight,
3852 const bool *pin,
3853 const bool *select)
3854{
3855 /* Allocate memory for polyfill. */
3856 MemArena *arena = handle->polyfill_arena;
3857 Heap *heap = handle->polyfill_heap;
3858 uint nfilltri = nverts - 2;
3859 uint(*tris)[3] = static_cast<uint(*)[3]>(
3860 BLI_memarena_alloc(arena, sizeof(*tris) * size_t(nfilltri)));
3861 float(*projverts)[2] = static_cast<float(*)[2]>(
3862 BLI_memarena_alloc(arena, sizeof(*projverts) * size_t(nverts)));
3863
3864 /* Calc normal, flipped: to get a positive 2d cross product. */
3865 float normal[3];
3866 zero_v3(normal);
3867
3868 const float *co_curr, *co_prev = co[nverts - 1];
3869 for (int j = 0; j < nverts; j++) {
3870 co_curr = co[j];
3871 add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
3872 co_prev = co_curr;
3873 }
3874 if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
3875 normal[2] = 1.0f;
3876 }
3877
3878 /* Project verts to 2d. */
3879 float axis_mat[3][3];
3880 axis_dominant_v3_to_m3_negate(axis_mat, normal);
3881 for (int j = 0; j < nverts; j++) {
3882 mul_v2_m3v3(projverts[j], axis_mat, co[j]);
3883 }
3884
3885 BLI_polyfill_calc_arena(projverts, nverts, 1, tris, arena);
3886
3887 /* Beautify helps avoid thin triangles that give numerical problems. */
3888 BLI_polyfill_beautify(projverts, nverts, tris, arena, heap);
3889
3890 /* Add triangles. */
3891 for (uint j = 0; j < nfilltri; j++) {
3892 uint *tri = tris[j];
3893 uint v0 = tri[0];
3894 uint v1 = tri[1];
3895 uint v2 = tri[2];
3896
3897 const ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]};
3898 const float *tri_co[3] = {co[v0], co[v1], co[v2]};
3899 float *tri_uv[3] = {uv[v0], uv[v1], uv[v2]};
3900
3901 const float *tri_weight = nullptr;
3902 float tri_weight_tmp[3];
3903
3904 if (weight) {
3905 tri_weight_tmp[0] = weight[v0];
3906 tri_weight_tmp[1] = weight[v1];
3907 tri_weight_tmp[2] = weight[v2];
3908 tri_weight = tri_weight_tmp;
3909 };
3910
3911 const bool tri_pin[3] = {pin[v0], pin[v1], pin[v2]};
3912 const bool tri_select[3] = {select[v0], select[v1], select[v2]};
3913
3915 handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_weight, tri_pin, tri_select);
3916 }
3917
3918 BLI_memarena_clear(arena);
3919}
3920
3922 const ParamKey key,
3923 const int nverts,
3924 const ParamKey *vkeys,
3925 const float **co,
3926 float **uv,
3927 const float *weight,
3928 const bool *pin,
3929 const bool *select)
3930{
3931 BLI_assert(nverts >= 3);
3933
3934 if (nverts > 3) {
3935 /* Protect against (manifold) geometry which has a non-manifold triangulation.
3936 * See #102543. */
3937
3938 Vector<int, 32> permute;
3939 permute.reserve(nverts);
3940 for (int i = 0; i < nverts; i++) {
3941 permute.append_unchecked(i);
3942 }
3943
3944 for (int i = nverts - 1; i >= 0;) {
3945 /* Just check the "ears" of the n-gon.
3946 * For quads, this is sufficient.
3947 * For pentagons and higher, we might miss internal duplicate triangles, but note
3948 * that such cases are rare if the source geometry is manifold and non-intersecting. */
3949 const int pm = int(permute.size());
3950 BLI_assert(pm > 3);
3951 int i0 = permute[i];
3952 int i1 = permute[(i + 1) % pm];
3953 int i2 = permute[(i + 2) % pm];
3954 if (!p_face_exists(phandle, vkeys, i0, i1, i2)) {
3955 i--; /* All good. */
3956 continue;
3957 }
3958
3959 /* An existing triangle has already been inserted.
3960 * As a heuristic, attempt to add the *previous* triangle.
3961 * NOTE: Should probably call `uv_parametrizer_face_add`
3962 * instead of `p_face_add_construct`. */
3963 int iprev = permute[(i + pm - 1) % pm];
3964 p_face_add_construct(phandle, key, vkeys, co, uv, weight, iprev, i0, i1, pin, select);
3965
3966 permute.remove(i);
3967 if (permute.size() == 3) {
3968 break;
3969 }
3970 }
3971 if (permute.size() != nverts) {
3972 const int pm = int(permute.size());
3973 /* Add the remaining `pm-gon` data. */
3974 Array<ParamKey> vkeys_sub(pm);
3975 Array<const float *> co_sub(pm);
3976 Array<float *> uv_sub(pm);
3977 Array<float> weight_sub(weight ? pm : 0);
3978 Array<bool> pin_sub(pm);
3979 Array<bool> select_sub(pm);
3980 for (int i = 0; i < pm; i++) {
3981 int j = permute[i];
3982 vkeys_sub[i] = vkeys[j];
3983 co_sub[i] = co[j];
3984 uv_sub[i] = uv[j];
3985 if (weight) {
3986 weight_sub[i] = weight[j];
3987 }
3988 pin_sub[i] = pin && pin[j];
3989 select_sub[i] = select && select[j];
3990 }
3991 p_add_ngon(phandle,
3992 key,
3993 pm,
3994 &vkeys_sub.first(),
3995 &co_sub.first(),
3996 &uv_sub.first(),
3997 weight ? &weight_sub.first() : nullptr,
3998 &pin_sub.first(),
3999 &select_sub.first());
4000 return; /* Nothing more to do. */
4001 }
4002 /* No "ears" have previously been inserted. Continue as normal. */
4003 }
4004 if (nverts > 3) {
4005 /* ngon */
4006 p_add_ngon(phandle, key, nverts, vkeys, co, uv, weight, pin, select);
4007 }
4008 else if (!p_face_exists(phandle, vkeys, 0, 1, 2)) {
4009 /* triangle */
4010 p_face_add_construct(phandle, key, vkeys, co, uv, weight, 0, 1, 2, pin, select);
4011 }
4012}
4013
4015{
4017
4018 PEdge *e = p_edge_lookup(phandle, vkeys);
4019 if (e) {
4020 e->flag |= PEDGE_SEAM;
4021 }
4022}
4023
4025 bool fill_holes,
4026 bool topology_from_uvs,
4027 int *r_count_failed)
4028{
4029 int i, j;
4030
4032
4033 phandle->ncharts = p_connect_pairs(phandle, topology_from_uvs);
4034 phandle->charts = p_split_charts(phandle, phandle->construction_chart, phandle->ncharts);
4035
4036 MEM_freeN(phandle->construction_chart);
4037 phandle->construction_chart = nullptr;
4038
4039 phash_safe_delete(&phandle->hash_verts);
4040 phash_safe_delete(&phandle->hash_edges);
4041 phash_safe_delete(&phandle->hash_faces);
4042
4043 for (i = j = 0; i < phandle->ncharts; i++) {
4044 PChart *chart = phandle->charts[i];
4045
4046 PEdge *outer;
4047 p_chart_boundaries(chart, &outer);
4048
4049 if (!topology_from_uvs && chart->nboundaries == 0) {
4050 MEM_freeN(chart);
4051 if (r_count_failed) {
4052 *r_count_failed += 1;
4053 }
4054 continue;
4055 }
4056
4057 phandle->charts[j++] = chart;
4058
4059 if (fill_holes && chart->nboundaries > 1) {
4060 p_chart_fill_boundaries(phandle, chart, outer);
4061 }
4062
4063 for (PVert *v = chart->verts; v; v = v->nextlink) {
4064 p_vert_load_pin_select_uvs(phandle, v);
4065 }
4066 }
4067
4068 phandle->ncharts = j;
4069
4071}
4072
4073void uv_parametrizer_lscm_begin(ParamHandle *phandle, bool live, bool abf)
4074{
4076 phandle->state = PHANDLE_STATE_LSCM;
4077
4078 for (int i = 0; i < phandle->ncharts; i++) {
4079 for (PFace *f = phandle->charts[i]->faces; f; f = f->nextlink) {
4081 }
4082 p_chart_lscm_begin(phandle->charts[i], live, abf);
4083 }
4084}
4085
4086void uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, int *count_failed)
4087{
4088 BLI_assert(phandle->state == PHANDLE_STATE_LSCM);
4089
4090 for (int i = 0; i < phandle->ncharts; i++) {
4091 PChart *chart = phandle->charts[i];
4092
4093 if (!chart->context) {
4094 continue;
4095 }
4096 const bool result = p_chart_lscm_solve(phandle, chart);
4097
4098 if (result && !chart->has_pins) {
4099 /* Every call to LSCM will eventually call uv_pack, so rotating here might be redundant. */
4101 }
4102 else if (result && chart->single_pin) {
4105 }
4106
4107 if (!result || !chart->has_pins) {
4108 p_chart_lscm_end(chart);
4109 }
4110
4111 if (result) {
4112 if (count_changed != nullptr) {
4113 *count_changed += 1;
4114 }
4115 }
4116 else {
4117 if (count_failed != nullptr) {
4118 *count_failed += 1;
4119 }
4120 }
4121 }
4122}
4123
4125{
4126 BLI_assert(phandle->state == PHANDLE_STATE_LSCM);
4127
4128 for (int i = 0; i < phandle->ncharts; i++) {
4129 p_chart_lscm_end(phandle->charts[i]);
4130#if 0
4131 p_chart_complexify(phandle->charts[i]);
4132#endif
4133 }
4134
4136}
4137
4139{
4141 phandle->state = PHANDLE_STATE_STRETCH;
4142
4143 phandle->rng = BLI_rng_new(31415926);
4144 phandle->blend = 0.0f;
4145
4146 for (int i = 0; i < phandle->ncharts; i++) {
4147 PChart *chart = phandle->charts[i];
4148
4149 for (PVert *v = chart->verts; v; v = v->nextlink) {
4150 v->flag &= ~PVERT_PIN; /* don't use user-defined pins */
4151 }
4152
4154
4155 for (PFace *f = chart->faces; f; f = f->nextlink) {
4157 f->u.area3d = p_face_area(f);
4158 }
4159 }
4160}
4161
4163{
4165 phandle->blend = blend;
4166}
4167
4169{
4171 for (int i = 0; i < phandle->ncharts; i++) {
4172 p_chart_stretch_minimize(phandle->charts[i], phandle->rng);
4173 }
4174}
4175
4181
4182void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned)
4183{
4184 if (handle->ncharts == 0) {
4185 return;
4186 }
4187
4188 uv_parametrizer_scale_x(handle, 1.0f / handle->aspect_y);
4189
4190 Vector<PackIsland *> pack_island_vector;
4191
4193 params.rotate_method = do_rotate ? ED_UVPACK_ROTATION_ANY : ED_UVPACK_ROTATION_NONE;
4194 params.margin = margin;
4195 params.margin_method = ED_UVPACK_MARGIN_SCALED;
4196
4197 for (int i = 0; i < handle->ncharts; i++) {
4198 PChart *chart = handle->charts[i];
4199 if (ignore_pinned && chart->has_pins) {
4200 continue;
4201 }
4202
4203 geometry::PackIsland *pack_island = new geometry::PackIsland();
4204 pack_island->caller_index = i;
4205 pack_island->aspect_y = handle->aspect_y;
4206 pack_island->pinned = chart->has_pins;
4207
4208 for (PFace *f = chart->faces; f; f = f->nextlink) {
4209 PVert *v0 = f->edge->vert;
4210 PVert *v1 = f->edge->next->vert;
4211 PVert *v2 = f->edge->next->next->vert;
4212 pack_island->add_triangle(v0->uv, v1->uv, v2->uv);
4213 }
4214
4215 pack_island_vector.append(pack_island);
4216 }
4217
4218 const float scale = pack_islands(pack_island_vector, params);
4219
4220 for (const int64_t i : pack_island_vector.index_range()) {
4221 PackIsland *pack_island = pack_island_vector[i];
4222 const float island_scale = pack_island->can_scale_(params) ? scale : 1.0f;
4223 PChart *chart = handle->charts[pack_island->caller_index];
4224
4225 float matrix[2][2];
4226 pack_island->build_transformation(island_scale, pack_island->angle, matrix);
4227 for (PVert *v = chart->verts; v; v = v->nextlink) {
4228 geometry::mul_v2_m2_add_v2v2(v->uv, matrix, v->uv, pack_island->pre_translate);
4229 }
4230
4231 pack_island_vector[i] = nullptr;
4232 delete pack_island;
4233 }
4234
4235 uv_parametrizer_scale_x(handle, handle->aspect_y);
4236}
4237
4238void uv_parametrizer_average(ParamHandle *phandle, bool ignore_pinned, bool scale_uv, bool shear)
4239{
4240 int i;
4241 float tot_area_3d = 0.0f;
4242 float tot_area_uv = 0.0f;
4243 float minv[2], maxv[2], trans[2];
4244
4245 if (phandle->ncharts == 0) {
4246 return;
4247 }
4248
4249 for (i = 0; i < phandle->ncharts; i++) {
4250 PChart *chart = phandle->charts[i];
4251
4252 if (ignore_pinned && chart->has_pins) {
4253 continue;
4254 }
4255
4256 /* Store original bounding box midpoint. */
4257 p_chart_uv_bbox(chart, minv, maxv);
4258 mid_v2_v2v2(chart->origin, minv, maxv);
4259
4260 if (scale_uv || shear) {
4261 /* It's possible that for some "bad" inputs, the following iteration will converge slowly or
4262 * perhaps even diverge. Rather than infinite loop, we only iterate a maximum of `max_iter`
4263 * times. (Also useful when making changes to the calculation.) */
4264 int max_iter = 10;
4265 for (int j = 0; j < max_iter; j++) {
4266 /* An island could contain millions of polygons. When summing many small values, we need to
4267 * use double precision in the accumulator to maintain accuracy. Note that the individual
4268 * calculations only need to be at single precision. */
4269 double scale_cou = 0;
4270 double scale_cov = 0;
4271 double scale_cross = 0;
4272 double weight_sum = 0;
4273 for (PFace *f = chart->faces; f; f = f->nextlink) {
4274 float m[2][2], s[2][2];
4275 PVert *va = f->edge->vert;
4276 PVert *vb = f->edge->next->vert;
4277 PVert *vc = f->edge->next->next->vert;
4278 s[0][0] = va->uv[0] - vc->uv[0];
4279 s[0][1] = va->uv[1] - vc->uv[1];
4280 s[1][0] = vb->uv[0] - vc->uv[0];
4281 s[1][1] = vb->uv[1] - vc->uv[1];
4282 /* Find the "U" axis and "V" axis in triangle co-ordinates. Normally this would require
4283 * SVD, but in 2D we can use a cheaper matrix inversion instead. */
4284 if (!invert_m2_m2(m, s)) {
4285 continue;
4286 }
4287 float cou[3], cov[3]; /* i.e. Texture "U" and texture "V" in 3D co-ordinates. */
4288 for (int k = 0; k < 3; k++) {
4289 cou[k] = m[0][0] * (va->co[k] - vc->co[k]) + m[0][1] * (vb->co[k] - vc->co[k]);
4290 cov[k] = m[1][0] * (va->co[k] - vc->co[k]) + m[1][1] * (vb->co[k] - vc->co[k]);
4291 }
4292 const float weight = p_face_area(f);
4293 scale_cou += len_v3(cou) * weight;
4294 scale_cov += len_v3(cov) * weight;
4295 if (shear) {
4296 normalize_v3(cov);
4297 normalize_v3(cou);
4298
4299 /* Why is scale_cross called `cross` when we call `dot`? The next line calculates:
4300 * `scale_cross += length(cross(cross(cou, face_normal), cov))`
4301 * By construction, both `cou` and `cov` are orthogonal to the face normal.
4302 * By definition, the normal vector has unit length. */
4303 scale_cross += dot_v3v3(cou, cov) * weight;
4304 }
4305 weight_sum += weight;
4306 }
4307 if (scale_cou * scale_cov < 1e-10f) {
4308 break;
4309 }
4310 const float scale_factor_u = scale_uv ? sqrtf(scale_cou / scale_cov) : 1.0f;
4311
4312 /* Compute correction transform. */
4313 float t[2][2];
4314 t[0][0] = scale_factor_u;
4315 t[1][0] = clamp_f(float(scale_cross / weight_sum), -0.5f, 0.5f);
4316 t[0][1] = 0;
4317 t[1][1] = 1.0f / scale_factor_u;
4318
4319 /* Apply the correction. */
4320 p_chart_uv_transform(chart, t);
4321
4322 /* How far from the identity transform are we? [[1,0],[0,1]] */
4323 const float err = fabsf(t[0][0] - 1.0f) + fabsf(t[1][0]) + fabsf(t[0][1]) +
4324 fabsf(t[1][1] - 1.0f);
4325
4326 const float tolerance = 1e-6f; /* Trade accuracy for performance. */
4327 if (err < tolerance) {
4328 /* Too slow? Use Richardson Extrapolation to accelerate the convergence. */
4329 break;
4330 }
4331 }
4332 }
4333
4334 chart->area_3d = 0.0f;
4335 chart->area_uv = 0.0f;
4336
4337 for (PFace *f = chart->faces; f; f = f->nextlink) {
4338 chart->area_3d += p_face_area(f);
4339 chart->area_uv += fabsf(p_face_uv_area_signed(f));
4340 }
4341
4342 tot_area_3d += chart->area_3d;
4343 tot_area_uv += chart->area_uv;
4344 }
4345
4346 if (tot_area_3d == 0.0f || tot_area_uv == 0.0f) {
4347 /* Prevent divide by zero. */
4348 return;
4349 }
4350
4351 const float tot_fac = tot_area_3d / tot_area_uv;
4352
4353 for (i = 0; i < phandle->ncharts; i++) {
4354 PChart *chart = phandle->charts[i];
4355
4356 if (ignore_pinned && chart->has_pins) {
4357 continue;
4358 }
4359
4360 if (chart->area_3d != 0.0f && chart->area_uv != 0.0f) {
4361 const float fac = chart->area_3d / chart->area_uv;
4362
4363 /* Average scale. */
4364 p_chart_uv_scale(chart, sqrtf(fac / tot_fac));
4365
4366 /* Get the current island bounding box. */
4367 p_chart_uv_bbox(chart, minv, maxv);
4368
4369 /* Move back to original midpoint. */
4370 mid_v2_v2v2(trans, minv, maxv);
4371 sub_v2_v2v2(trans, chart->origin, trans);
4372
4373 p_chart_uv_translate(chart, trans);
4374 }
4375 }
4376}
4377
4379{
4380 for (int i = 0; i < phandle->ncharts; i++) {
4381 PChart *chart = phandle->charts[i];
4382 if (chart->skip_flush) {
4383 continue;
4384 }
4385
4386 p_flush_uvs(phandle, chart);
4387 }
4388}
4389
4391{
4392 for (int i = 0; i < phandle->ncharts; i++) {
4393 PChart *chart = phandle->charts[i];
4394 for (PFace *f = chart->faces; f; f = f->nextlink) {
4396 }
4397 }
4398}
4399
4400/* -------------------------------------------------------------------- */
4404static bool p_collapse_doubles_allowed(PEdge *edge, PEdge *pair, float threshold_squared)
4405{
4406 PVert *oldv, *keepv;
4407
4408 p_collapsing_verts(edge, pair, &oldv, &keepv);
4409
4410 /* Do not collapse a pinned vertex unless the target vertex
4411 * is also pinned. */
4412 if ((oldv->flag & PVERT_PIN) && !(keepv->flag & PVERT_PIN)) {
4413 return false;
4414 }
4415
4416 if (!p_collapse_allowed_topologic(edge, pair)) {
4417 return false;
4418 }
4419
4420 PEdge *collapse_e = edge ? edge : pair;
4421 return p_edge_length_squared(collapse_e) < threshold_squared;
4422}
4423
4424static float p_collapse_doubles_cost(PEdge *edge, PEdge *pair)
4425{
4426 PEdge *collapse_e = edge ? edge : pair;
4427 return p_edge_length_squared(collapse_e);
4428}
4429
4430static void UNUSED_FUNCTION(p_chart_collapse_doubles)(PChart *chart, const float threshold)
4431{
4432 const float threshold_squared = threshold * threshold;
4433
4435 return p_collapse_doubles_allowed(e, pair, threshold_squared);
4436 });
4437}
4438
4440{
4441 PEdge *e, *pair, *edge;
4442 PVert *newv, *keepv;
4443
4444 for (e = chart->collapsed_edges; e; e = e->nextlink) {
4445 if (!(e->flag & PEDGE_COLLAPSE_EDGE)) {
4446 break;
4447 }
4448 edge = e;
4449 pair = e->pair;
4450 if (edge->flag & PEDGE_COLLAPSE_PAIR) {
4451 std::swap(edge, pair);
4452 }
4453 p_collapsing_verts(edge, pair, &newv, &keepv);
4454
4455 if (!(newv->flag & PVERT_PIN)) {
4456 newv->uv[0] = keepv->uv[0];
4457 newv->uv[1] = keepv->uv[1];
4458 }
4459 }
4460}
4461
4463 const float corr_co1[3],
4464 const float corr_co2[3],
4465 const float min_area,
4466 const float min_angle_cos)
4467{
4468 /* Check whether the given corrected coordinates don't result in any other triangle with area
4469 * lower than min_area. */
4470
4471 const PVert *corr_v = corr_e->vert;
4472 const PEdge *e = corr_v->edge;
4473
4474 do {
4475 float area;
4476
4477 if (e == corr_e) {
4478 continue;
4479 }
4480
4481 if (!(e->face->flag & PFACE_DONE)) {
4482 continue;
4483 }
4484
4485 if (e->next->next == corr_e->pair) {
4486 PVert *other_v = e->next->next->vert;
4487 area = area_tri_v3(corr_co1, corr_co2, other_v->co);
4488 }
4489 else {
4490 const PVert *other_v1 = e->next->vert;
4491 const PVert *other_v2 = e->next->next->vert;
4492 area = area_tri_v3(corr_co1, other_v1->co, other_v2->co);
4493 }
4494
4495 if (area < min_area) {
4496 return false;
4497 }
4498
4499 float f_cos[3];
4500
4501 if (e->next->next == corr_e->pair) {
4502 PVert *other_v = e->next->next->vert;
4503 p_triangle_cos(corr_co1, corr_co2, other_v->co, f_cos, f_cos + 1, f_cos + 2);
4504 }
4505 else {
4506 const PVert *other_v1 = e->next->vert;
4507 const PVert *other_v2 = e->next->next->vert;
4508 p_triangle_cos(corr_co1, other_v1->co, other_v2->co, f_cos, f_cos + 1, f_cos + 2);
4509 }
4510
4511 for (int i = 0; i < 3; i++) {
4512 if (f_cos[i] > min_angle_cos) {
4513 return false;
4514 }
4515 }
4516
4517 } while ((e = p_wheel_edge_next(e)) && (e != corr_v->edge));
4518
4519 return true;
4520}
4521
4522static bool p_validate_corrected_coords(const PEdge *corr_e,
4523 const float corr_co[3],
4524 float min_area,
4525 float min_angle_cos)
4526{
4527 /* Check whether the given corrected coordinates don't result in any other triangle with area
4528 * lower than min_area. */
4529
4530 const PVert *corr_v = corr_e->vert;
4531 const PEdge *e = corr_v->edge;
4532
4533 do {
4534 if (!(e->face->flag & PFACE_DONE) && (e != corr_e)) {
4535 continue;
4536 }
4537
4538 const PVert *other_v1 = e->next->vert;
4539 const PVert *other_v2 = e->next->next->vert;
4540
4541 const float area = area_tri_v3(corr_co, other_v1->co, other_v2->co);
4542
4543 if (area < min_area) {
4544 return false;
4545 }
4546
4547 float f_cos[3];
4548 p_triangle_cos(corr_co, other_v1->co, other_v2->co, f_cos, f_cos + 1, f_cos + 2);
4549
4550 for (int i = 0; i < 3; i++) {
4551 if (f_cos[i] > min_angle_cos) {
4552 return false;
4553 }
4554 }
4555
4556 } while ((e = p_wheel_edge_next(e)) && (e != corr_v->edge));
4557
4558 return true;
4559}
4560
4561static bool p_edge_matrix(float R[3][3], const float edge_dir[3])
4562{
4563 static const constexpr float eps = 1.0e-5;
4564 static const constexpr float n1[3] = {0.0f, 0.0f, 1.0f};
4565 static const constexpr float n2[3] = {0.0f, 1.0f, 0.0f};
4566
4567 float edge_len = len_v3(edge_dir);
4568 if (edge_len < eps) {
4569 return false;
4570 }
4571
4572 float edge_dir_norm[3];
4573 copy_v3_v3(edge_dir_norm, edge_dir);
4574 mul_v3_fl(edge_dir_norm, 1.0f / edge_len);
4575
4576 float normal_dir[3];
4577 cross_v3_v3v3(normal_dir, edge_dir_norm, n1);
4578 float normal_len = len_v3(normal_dir);
4579
4580 if (normal_len < eps) {
4581 cross_v3_v3v3(normal_dir, edge_dir_norm, n2);
4582 normal_len = len_v3(normal_dir);
4583
4584 if (normal_len < eps) {
4585 return false;
4586 }
4587 }
4588
4589 mul_v3_fl(normal_dir, 1.0f / normal_len);
4590
4591 float tangent_dir[3];
4592 cross_v3_v3v3(tangent_dir, edge_dir_norm, normal_dir);
4593
4594 R[0][0] = edge_dir_norm[0];
4595 R[1][0] = edge_dir_norm[1];
4596 R[2][0] = edge_dir_norm[2];
4597
4598 R[0][1] = normal_dir[0];
4599 R[1][1] = normal_dir[1];
4600 R[2][1] = normal_dir[2];
4601
4602 R[0][2] = tangent_dir[0];
4603 R[1][2] = tangent_dir[1];
4604 R[2][2] = tangent_dir[2];
4605
4606 return true;
4607}
4608
4609static bool p_edge_matrix(float R[3][3], const PEdge *e)
4610{
4611 float edge_dir[3];
4612 copy_v3_v3(edge_dir, e->next->vert->co);
4613 sub_v3_v3(edge_dir, e->vert->co);
4614
4615 return p_edge_matrix(R, edge_dir);
4616}
4617
4618static const float CORR_ZERO_AREA_EPS = 1.0e-10f;
4619
4621 float min_area,
4622 float min_angle_cos)
4623{
4624 static const float3 ref_edges[] = {
4625 {1.0f, 0.0f, 0.0f},
4626 {0.0f, 1.0f, 0.0f},
4627 {0.0f, 0.0f, 1.0f},
4628 {0.0f, 1.0f, 1.0f},
4629 {1.0f, 0.0f, 1.0f},
4630 {1.0f, 1.0f, 0.0f},
4631
4632 {0.0f, 0.5f, 1.0f},
4633 {0.5f, 0.0f, 1.0f},
4634 {0.5f, 1.0f, 0.0f},
4635
4636 {0.0f, 1.0f, 0.5f},
4637 {1.0f, 0.0f, 0.5f},
4638 {1.0f, 0.5f, 0.0f},
4639 };
4640 static const int ref_edge_count = ARRAY_SIZE(ref_edges);
4641 static const int LEN_MULTIPLIER_COUNT = 3;
4642 bool corr_co_found = false;
4643
4644 float corr_len = 2.0f * std::sqrt((min_area + CORR_ZERO_AREA_EPS) / 3.0f / std::sqrt(3.0f));
4645
4646 for (int m = 0; m < LEN_MULTIPLIER_COUNT; m++) {
4647 for (int re = 0; re < ref_edge_count; re++) {
4648 float M[3][3];
4649
4650 if (!p_edge_matrix(M, ref_edges[re])) {
4651 continue;
4652 }
4653
4654 float corr_co[3][3];
4655 PEdge *e = f->edge;
4656
4657 for (int i = 0; i < 3; i++) {
4658 const float angle = (float(i) / 3.0f) * float(2.0 * M_PI);
4659 float corr_dir[3] = {0.0f, cos(angle), sin(angle)};
4660
4661 float corr_len_multiplied = corr_len * (m + 1);
4662
4663 mul_m3_v3(M, corr_dir);
4664 mul_v3_fl(corr_dir, corr_len_multiplied);
4665
4666 copy_v3_v3(corr_co[i], e->vert->co);
4667 add_v3_v3(corr_co[i], corr_dir);
4668 e = e->next;
4669 }
4670
4671 e = f->edge;
4672 for (int i = 0; i < 3; i++) {
4674 e, corr_co[i], corr_co[(i + 1) % 3], min_area, min_angle_cos))
4675 {
4676 return false;
4677 }
4678
4679 e = e->next;
4680 }
4681
4682 e = f->edge;
4683 for (int i = 0; i < 3; i++) {
4684 copy_v3_v3(e->vert->co, corr_co[i]);
4685 e = e->next;
4686 }
4687
4688 corr_co_found = true;
4689 break;
4690 }
4691
4692 if (corr_co_found) {
4693 break;
4694 }
4695 }
4696
4697 if (!corr_co_found) {
4698 return false;
4699 }
4700
4701 f->flag |= PFACE_DONE;
4702 return true;
4703}
4704
4705static bool p_chart_correct_degenerate_triangles2(PChart *chart, float min_area, float min_angle)
4706{
4707 static const float eps = 1.0e-6;
4708
4709 float min_angle_cos = std::cos(min_angle);
4710 float min_angle_sin = std::sin(min_angle + CORR_ZERO_AREA_EPS);
4711
4712 for (PFace *f = chart->faces; f; f = f->nextlink) {
4713 if (f->flag & PFACE_DONE) {
4714 continue;
4715 }
4716
4717 float face_area = p_face_area(f);
4718
4719 PEdge *max_edge = nullptr;
4720 float max_edge_len = -std::numeric_limits<float>::infinity();
4721
4722 PEdge *min_edge = nullptr;
4723 float min_edge_len = std::numeric_limits<float>::infinity();
4724
4725 PEdge *middle_edge = nullptr;
4726
4727 PEdge *e = f->edge;
4728 do {
4729 float len = p_edge_length(e);
4730
4731 if (len > max_edge_len) {
4732 max_edge = e;
4733 max_edge_len = len;
4734
4735 middle_edge = max_edge->next == min_edge ? min_edge->next : max_edge->next;
4736 }
4737
4738 if (len < min_edge_len) {
4739 min_edge = e;
4740 min_edge_len = len;
4741
4742 middle_edge = min_edge->next == max_edge ? max_edge->next : min_edge->next;
4743 }
4744
4745 e = e->next;
4746 } while (e != f->edge);
4747
4748 BLI_assert(max_edge);
4749 BLI_assert(min_edge);
4750 BLI_assert(middle_edge);
4751
4752 bool small_uniside_tri = (face_area <= min_area) && (min_edge == max_edge);
4753
4754 if ((max_edge_len < eps) || small_uniside_tri) {
4755 p_chart_correct_degenerate_triangle_point(f, min_area, min_angle_cos);
4756 continue;
4757 }
4758
4759 if (min_edge == max_edge) {
4760 BLI_assert(face_area > min_area);
4761 f->flag |= PFACE_DONE;
4762 continue;
4763 }
4764
4765 BLI_assert(middle_edge != max_edge);
4766 BLI_assert(middle_edge != min_edge);
4767
4768 float M[3][3];
4769 if (!p_edge_matrix(M, max_edge)) {
4770 continue;
4771 }
4772
4773 float max_face_cos =
4774 middle_edge->next == max_edge ?
4775 p_vec_cos(middle_edge->vert->co, max_edge->vert->co, min_edge->vert->co) :
4776 p_vec_cos(max_edge->vert->co, middle_edge->vert->co, min_edge->vert->co);
4777
4778 float angle_corr_len = max_face_cos > min_angle_cos ?
4779 p_edge_length(middle_edge) * min_angle_sin :
4780 0.0f;
4781
4782 if ((face_area > min_area) && (angle_corr_len == 0.0f)) {
4783 f->flag |= PFACE_DONE;
4784 continue;
4785 }
4786
4787 float corr_len = (min_area + CORR_ZERO_AREA_EPS) * 2.0f / max_edge_len;
4788 corr_len = std::max(corr_len, angle_corr_len);
4789
4790 PEdge *corr_e = max_edge->next->next;
4791 PVert *corr_v = corr_e->vert;
4792
4793 /* Check 4 distinct directions. */
4794 static const constexpr int DIR_COUNT = 16;
4795 static const constexpr int LEN_MULTIPLIER_COUNT = 2;
4796 float corr_co[3];
4797 bool corr_co_found = false;
4798
4799 for (int m = 0; m < LEN_MULTIPLIER_COUNT; m++) {
4800 for (int d = 0; d < DIR_COUNT; d++) {
4801 const float angle = (float(d) / DIR_COUNT) * float(2.0 * M_PI);
4802 float corr_dir[3] = {0.0f, cos(angle), sin(angle)};
4803
4804 const float corr_len_multiplied = corr_len * (m + 1);
4805
4806 mul_m3_v3(M, corr_dir);
4807 mul_v3_fl(corr_dir, corr_len_multiplied);
4808
4809 copy_v3_v3(corr_co, corr_v->co);
4810 add_v3_v3(corr_co, corr_dir);
4811
4812 if (p_validate_corrected_coords(corr_e, corr_co, min_area, min_angle_cos)) {
4813 corr_co_found = true;
4814 break;
4815 }
4816 }
4817
4818 if (corr_co_found) {
4819 break;
4820 }
4821 }
4822
4823 if (!corr_co_found) {
4824 continue;
4825 }
4826
4827 f->flag |= PFACE_DONE;
4828 copy_v3_v3(corr_v->co, corr_co);
4829 }
4830
4831 return true;
4832}
4833
4834#ifndef NDEBUG
4835
4836static bool p_validate_triangle_angles(const PVert *vert1,
4837 const PVert *vert2,
4838 const PVert *vert3,
4839 const float min_angle_cos)
4840{
4841 float t_cos[3];
4842 p_triangle_cos(vert1->co, vert2->co, vert3->co, t_cos, t_cos + 1, t_cos + 2);
4843
4844 for (int i = 0; i < 3; i++) {
4845 if (t_cos[i] > min_angle_cos) {
4846 return false;
4847 }
4848 }
4849
4850 return true;
4851}
4852
4853#endif
4854
4856 const float min_area,
4857 const float min_angle)
4858{
4859 /* Look for degenerate triangles: triangles with angles lower than `min_angle` or having area
4860 * lower than `min_area` and try to correct vertex coordinates so that the resulting triangle is
4861 * not degenerate.
4862 *
4863 * The return value indicates whether all triangles could be corrected.
4864 */
4865
4866 bool ret = p_chart_correct_degenerate_triangles2(chart, min_area, min_angle);
4867
4868#ifndef NDEBUG
4869 float min_angle_cos = std::cos(min_angle - CORR_ZERO_AREA_EPS);
4870#endif
4871
4872 for (PFace *f = chart->faces; f; f = f->nextlink) {
4873 if (!(f->flag & PFACE_DONE)) {
4874 ret = false;
4875 }
4876 else {
4877#ifndef NDEBUG
4878 float f_area = p_face_area(f);
4879 BLI_assert(f_area > (min_area - CORR_ZERO_AREA_EPS));
4880
4881 PVert *vert1 = f->edge->vert;
4882 PVert *vert2 = f->edge->next->vert;
4883 PVert *vert3 = f->edge->next->next->vert;
4884
4885 BLI_assert(p_validate_triangle_angles(vert1, vert2, vert3, min_angle_cos));
4886#endif
4887 }
4888
4889 f->flag &= ~PFACE_DONE;
4890 }
4891
4892 return ret;
4893}
4894
4897/* -------------------------------------------------------------------- */
4901#ifdef WITH_UV_SLIM
4902
4906static slim::MatrixTransfer *slim_matrix_transfer(const ParamSlimOptions *slim_options)
4907{
4909
4910 mt->use_weights = slim_options->weight_influence > 0.0f;
4911 mt->weight_influence = slim_options->weight_influence;
4912 mt->n_iterations = slim_options->iterations;
4913 mt->reflection_mode = slim_options->no_flip;
4914 mt->skip_initialization = slim_options->skip_init;
4915
4916 return mt;
4917}
4918
4923static void slim_allocate_matrices(const PChart *chart, slim::MatrixTransferChart *mt_chart)
4924{
4925 mt_chart->verts_num = chart->nverts;
4926 mt_chart->faces_num = chart->nfaces;
4927 mt_chart->edges_num = chart->nedges;
4928
4929 mt_chart->v_matrices.resize(mt_chart->verts_num * 3);
4930 mt_chart->uv_matrices.resize(mt_chart->verts_num * 2);
4931 mt_chart->pp_matrices.resize(mt_chart->verts_num * 2);
4932
4933 mt_chart->f_matrices.resize(mt_chart->faces_num * 3);
4934 mt_chart->p_matrices.resize(mt_chart->verts_num);
4935 mt_chart->b_vectors.resize(mt_chart->verts_num);
4936 /* Also clear memory for weight vectors, hence 'new' followed by `()`. */
4937 mt_chart->w_vectors.resize(mt_chart->verts_num, 0.0);
4938
4939 mt_chart->e_matrices.resize(mt_chart->edges_num * 2 * 2);
4940 mt_chart->el_vectors.resize(mt_chart->edges_num * 2);
4941}
4942
4946static void slim_transfer_edges(PChart *chart, slim::MatrixTransferChart *mt_chart)
4947{
4948 std::vector<int> &E = mt_chart->e_matrices;
4949 std::vector<double> &EL = mt_chart->el_vectors;
4950
4951 PEdge *outer;
4952 p_chart_boundaries(chart, &outer);
4953
4954 PEdge *be = outer;
4955 int eid = 0;
4956
4957 static const float DOUBLED_VERT_THRESHOLD = 1.0e-5;
4958
4959 do {
4960 E[eid] = be->vert->slim_id;
4961 const float edge_len = p_edge_length(be);
4962 EL[eid] = edge_len;
4963
4964 /* Temporary solution : SLIM doesn't support doubled vertices for now. */
4965 if (edge_len < DOUBLED_VERT_THRESHOLD) {
4966 mt_chart->succeeded = false;
4967 }
4968
4969 be = p_boundary_edge_next(be);
4970 E[eid + mt_chart->edges_num + mt_chart->boundary_vertices_num] = be->vert->slim_id;
4971 eid++;
4972
4973 } while (be != outer);
4974
4975 for (PEdge *e = chart->edges; e; e = e->nextlink) {
4976 PEdge *e1 = e->next;
4977
4978 E[eid] = e->vert->slim_id;
4979 const float edge_len = p_edge_length(e);
4980 EL[eid] = edge_len;
4981
4982 /* Temporary solution : SLIM doesn't support doubled vertices for now. */
4983 if (edge_len < DOUBLED_VERT_THRESHOLD) {
4984 mt_chart->succeeded = false;
4985 }
4986
4987 E[eid + mt_chart->edges_num + mt_chart->boundary_vertices_num] = e1->vert->slim_id;
4988 eid++;
4989 }
4990}
4991
4995static void slim_transfer_vertices(const PChart *chart,
4996 slim::MatrixTransferChart *mt_chart,
4998{
4999 int r = mt_chart->verts_num;
5000 std::vector<double> &v_mat = mt_chart->v_matrices;
5001 std::vector<double> &uv_mat = mt_chart->uv_matrices;
5002 std::vector<int> &p_mat = mt_chart->p_matrices;
5003 std::vector<double> &pp_mat = mt_chart->pp_matrices;
5004 std::vector<float> &w_vec = mt_chart->w_vectors;
5005
5006 int p_vid = 0;
5007 int vid = mt_chart->boundary_vertices_num;
5008
5009 /* For every vertex, fill up V matrix and P matrix (pinned vertices) */
5010 for (PVert *v = chart->verts; v; v = v->nextlink) {
5011 if (!v->on_boundary_flag) {
5012 if (mt->use_weights) {
5013 w_vec[vid] = v->weight;
5014 }
5015
5016 v->slim_id = vid;
5017 vid++;
5018 }
5019
5020 v_mat[v->slim_id] = v->co[0];
5021 v_mat[r + v->slim_id] = v->co[1];
5022 v_mat[2 * r + v->slim_id] = v->co[2];
5023
5024 uv_mat[v->slim_id] = v->uv[0];
5025 uv_mat[r + v->slim_id] = v->uv[1];
5026
5027 if (v->flag & PVERT_PIN || (mt->is_minimize_stretch && !(v->flag & PVERT_SELECT))) {
5028 mt_chart->pinned_vertices_num += 1;
5029
5030 p_mat[p_vid] = v->slim_id;
5031 pp_mat[2 * p_vid] = double(v->uv[0]);
5032 pp_mat[2 * p_vid + 1] = double(v->uv[1]);
5033 p_vid += 1;
5034 }
5035 }
5036}
5037
5041static void slim_transfer_boundary_vertices(PChart *chart,
5042 slim::MatrixTransferChart *mt_chart,
5043 const slim::MatrixTransfer *mt)
5044{
5045 std::vector<int> &b_vec = mt_chart->b_vectors;
5046 std::vector<float> &w_vec = mt_chart->w_vectors;
5047
5048 /* For every vertex, set slim_flag to 0 */
5049 for (PVert *v = chart->verts; v; v = v->nextlink) {
5050 v->on_boundary_flag = false;
5051 }
5052
5053 /* Find vertices on boundary and save into vector B */
5054 PEdge *outer;
5055 p_chart_boundaries(chart, &outer);
5056
5057 PEdge *be = outer;
5058 int vid = 0;
5059
5060 do {
5061 if (mt->use_weights) {
5062 w_vec[vid] = be->vert->weight;
5063 }
5064
5065 mt_chart->boundary_vertices_num += 1;
5066 be->vert->slim_id = vid;
5067 be->vert->on_boundary_flag = true;
5068 b_vec[vid] = vid;
5069
5070 vid += 1;
5071 be = p_boundary_edge_next(be);
5072
5073 } while (be != outer);
5074}
5075
5079static void slim_transfer_faces(const PChart *chart, slim::MatrixTransferChart *mt_chart)
5080{
5081 int fid = 0;
5082
5083 for (PFace *f = chart->faces; f; f = f->nextlink) {
5084 PEdge *e = f->edge;
5085 PEdge *e1 = e->next;
5086 PEdge *e2 = e1->next;
5087
5088 int r = mt_chart->faces_num;
5089 std::vector<int> &F = mt_chart->f_matrices;
5090
5091 F[fid] = e->vert->slim_id;
5092 F[r + fid] = e1->vert->slim_id;
5093 F[2 * r + fid] = e2->vert->slim_id;
5094 fid++;
5095 }
5096}
5097
5101static void slim_convert_blender(ParamHandle *phandle, slim::MatrixTransfer *mt)
5102{
5103 static const float SLIM_CORR_MIN_AREA = 1.0e-8;
5104 static const float SLIM_CORR_MIN_ANGLE = DEG2RADF(1.0);
5105
5106 mt->charts.resize(phandle->ncharts);
5107
5108 for (int i = 0; i < phandle->ncharts; i++) {
5109 PChart *chart = phandle->charts[i];
5110 slim::MatrixTransferChart *mt_chart = &mt->charts[i];
5111
5112 p_chart_correct_degenerate_triangles(chart, SLIM_CORR_MIN_AREA, SLIM_CORR_MIN_ANGLE);
5113
5114 mt_chart->succeeded = true;
5115 mt_chart->pinned_vertices_num = 0;
5116 mt_chart->boundary_vertices_num = 0;
5117
5118 /* Allocate memory for matrices of Vertices,Faces etc. for each chart. */
5119 slim_allocate_matrices(chart, mt_chart);
5120
5121 /* For each chart, fill up matrices. */
5122 slim_transfer_boundary_vertices(chart, mt_chart, mt);
5123 slim_transfer_vertices(chart, mt_chart, mt);
5124 slim_transfer_edges(chart, mt_chart);
5125 slim_transfer_faces(chart, mt_chart);
5126
5127 mt_chart->pp_matrices.resize(mt_chart->pinned_vertices_num * 2);
5128 mt_chart->pp_matrices.shrink_to_fit();
5129
5130 mt_chart->p_matrices.resize(mt_chart->pinned_vertices_num);
5131 mt_chart->p_matrices.shrink_to_fit();
5132
5133 mt_chart->b_vectors.resize(mt_chart->boundary_vertices_num);
5134 mt_chart->b_vectors.shrink_to_fit();
5135
5136 mt_chart->e_matrices.resize((mt_chart->edges_num + mt_chart->boundary_vertices_num) * 2);
5137 mt_chart->e_matrices.shrink_to_fit();
5138 }
5139}
5140
5141static void slim_transfer_data_to_slim(ParamHandle *phandle, const ParamSlimOptions *slim_options)
5142{
5143 slim::MatrixTransfer *mt = slim_matrix_transfer(slim_options);
5144
5145 slim_convert_blender(phandle, mt);
5146 phandle->slim_mt = mt;
5147}
5148
5152static void slim_flush_uvs(ParamHandle *phandle,
5154 int *count_changed,
5155 int *count_failed,
5156 bool live = false)
5157{
5158 int vid;
5159 PVert *v;
5160
5161 for (int i = 0; i < phandle->ncharts; i++) {
5162 PChart *chart = phandle->charts[i];
5163 slim::MatrixTransferChart *mt_chart = &mt->charts[i];
5164
5165 if (mt_chart->succeeded) {
5166 if (count_changed) {
5167 (*count_changed)++;
5168 }
5169
5170 const std::vector<double> &UV = mt_chart->uv_matrices;
5171 for (v = chart->verts; v; v = v->nextlink) {
5172 if (v->flag & PVERT_PIN) {
5173 continue;
5174 }
5175
5176 vid = v->slim_id;
5177 v->uv[0] = UV[vid];
5178 v->uv[1] = UV[mt_chart->verts_num + vid];
5179 }
5180 }
5181 else {
5182 if (count_failed) {
5183 (*count_failed)++;
5184 }
5185
5186 if (!live) {
5187 for (v = chart->verts; v; v = v->nextlink) {
5188 v->uv[0] = 0.0f;
5189 v->uv[1] = 0.0f;
5190 }
5191 }
5192 }
5193 }
5194}
5195
5199static void slim_free_matrix_transfer(ParamHandle *phandle)
5200{
5201 delete phandle->slim_mt;
5202 phandle->slim_mt = nullptr;
5203}
5204
5205static void slim_get_pinned_vertex_data(ParamHandle *phandle,
5206 PChart *chart,
5207 slim::MatrixTransferChart &mt_chart,
5208 slim::PinnedVertexData &pinned_vertex_data)
5209{
5210 std::vector<int> &pinned_vertex_indices = pinned_vertex_data.pinned_vertex_indices;
5211 std::vector<double> &pinned_vertex_positions_2D = pinned_vertex_data.pinned_vertex_positions_2D;
5212 std::vector<int> &selected_pins = pinned_vertex_data.selected_pins;
5213
5214 pinned_vertex_indices.clear();
5215 pinned_vertex_positions_2D.clear();
5216 selected_pins.clear();
5217
5218 /* Boundary vertices have lower slim_ids, process them first. */
5219 PEdge *outer;
5220 p_chart_boundaries(chart, &outer);
5221 PEdge *be = outer;
5222 do {
5223 if (be->vert->flag & PVERT_PIN) {
5224 /* Reload vertex position. */
5225 p_vert_load_pin_select_uvs(phandle, be->vert);
5226
5227 if (be->vert->flag & PVERT_SELECT) {
5228 selected_pins.push_back(be->vert->slim_id);
5229 }
5230
5231 pinned_vertex_indices.push_back(be->vert->slim_id);
5232 pinned_vertex_positions_2D.push_back(be->vert->uv[0]);
5233 pinned_vertex_positions_2D.push_back(be->vert->uv[1]);
5234 }
5235 be = p_boundary_edge_next(be);
5236 } while (be != outer);
5237
5238 PVert *v;
5239 for (v = chart->verts; v; v = v->nextlink) {
5240 if (!v->on_boundary_flag && (v->flag & PVERT_PIN)) {
5241 /* Reload `v`. */
5242 p_vert_load_pin_select_uvs(phandle, v);
5243
5244 if (v->flag & PVERT_SELECT) {
5245 selected_pins.push_back(v->slim_id);
5246 }
5247 pinned_vertex_indices.push_back(v->slim_id);
5248 pinned_vertex_positions_2D.push_back(v->uv[0]);
5249 pinned_vertex_positions_2D.push_back(v->uv[1]);
5250 }
5251 }
5252
5253 mt_chart.pinned_vertices_num = pinned_vertex_indices.size();
5254}
5255
5256#endif /* WITH_UV_SLIM */
5257
5260/* -------------------------------------------------------------------- */
5265 const ParamSlimOptions *slim_options,
5266 int *count_changed,
5267 int *count_failed)
5268{
5269#ifdef WITH_UV_SLIM
5270 slim_transfer_data_to_slim(phandle, slim_options);
5271 slim::MatrixTransfer *mt = phandle->slim_mt;
5272
5273 mt->parametrize();
5274
5275 slim_flush_uvs(phandle, mt, count_changed, count_failed);
5276 slim_free_matrix_transfer(phandle);
5277#else
5278 *count_changed = 0;
5279 *count_failed = 0;
5280 UNUSED_VARS(phandle, slim_options, count_changed, count_failed);
5281#endif /* !WITH_UV_SLIM */
5282}
5283
5285{
5286#ifdef WITH_UV_SLIM
5287 slim_transfer_data_to_slim(phandle, slim_options);
5288 slim::MatrixTransfer *mt = phandle->slim_mt;
5289
5290 for (int i = 0; i < phandle->ncharts; i++) {
5291 for (PFace *f = phandle->charts[i]->faces; f; f = f->nextlink) {
5293 }
5294 }
5295
5296 for (int i = 0; i < phandle->ncharts; i++) {
5297 PChart *chart = phandle->charts[i];
5298 slim::MatrixTransferChart &mt_chart = mt->charts[i];
5299
5300 bool select = false, deselect = false;
5301
5302 /* Give vertices matrix indices and count pins. */
5303 for (PVert *v = chart->verts; v; v = v->nextlink) {
5304 if (v->flag & PVERT_PIN) {
5305 if (v->flag & PVERT_SELECT) {
5306 select = true;
5307 }
5308 }
5309
5310 if (!(v->flag & PVERT_SELECT)) {
5311 deselect = true;
5312 }
5313 }
5314
5315 if (!select || !deselect) {
5316 chart->skip_flush = true;
5317 mt_chart.succeeded = false;
5318 continue;
5319 }
5320
5321 mt->setup_slim_data(mt_chart);
5322 }
5323#else
5324 UNUSED_VARS(phandle, slim_options);
5325#endif /* !WITH_UV_SLIM */
5326}
5327
5329{
5330#ifdef WITH_UV_SLIM
5331 slim::MatrixTransfer *mt = phandle->slim_mt;
5332
5333 /* Do one iteration and transfer UVs. */
5334 for (int i = 0; i < phandle->ncharts; i++) {
5335 mt->charts[i].parametrize_single_iteration();
5336 mt->charts[i].transfer_uvs_blended(blend);
5337 }
5338
5339 /* Assign new UVs back to each vertex. */
5340 slim_flush_uvs(phandle, mt, nullptr, nullptr);
5341#else
5342 UNUSED_VARS(phandle, blend);
5343#endif /* !WITH_UV_SLIM */
5344}
5345
5347{
5348#ifdef WITH_UV_SLIM
5349 slim::MatrixTransfer *mt = phandle->slim_mt;
5350
5351 /* Do one iteration and transfer UVs */
5352 for (int i = 0; i < phandle->ncharts; i++) {
5353 PChart *chart = phandle->charts[i];
5354 slim::MatrixTransferChart &mt_chart = mt->charts[i];
5355
5356 if (!mt_chart.data) {
5357 continue;
5358 }
5359
5360 slim_get_pinned_vertex_data(phandle, chart, mt_chart, mt->pinned_vertex_data);
5361
5362 mt->parametrize_live(mt_chart, mt->pinned_vertex_data);
5363 }
5364
5365 /* Assign new UVs back to each vertex. */
5366 const bool live = true;
5367 slim_flush_uvs(phandle, mt, nullptr, nullptr, live);
5368#else
5369 UNUSED_VARS(phandle);
5370#endif /* !WITH_UV_SLIM */
5371}
5372
5374{
5375#ifdef WITH_UV_SLIM
5376 slim::MatrixTransfer *mt = phandle->slim_mt;
5377
5378 for (int i = 0; i < phandle->ncharts; i++) {
5379 slim::MatrixTransferChart *mt_chart = &mt->charts[i];
5380 mt_chart->free_slim_data();
5381 }
5382
5383 slim_free_matrix_transfer(phandle);
5384#else
5385 UNUSED_VARS(phandle);
5386#endif /* WITH_UV_SLIM */
5387}
5388
5390{
5391#ifdef WITH_UV_SLIM
5392 return phandle->slim_mt != nullptr;
5393#else
5394 UNUSED_VARS(phandle);
5395 return false;
5396#endif
5397}
5398
5401} // namespace blender::geometry
#define BLI_assert(a)
Definition BLI_assert.h:50
float BLI_convexhull_aabb_fit_points_2d(const float(*points)[2], int points_num)
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
GHash * BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
HeapNode * BLI_heap_top(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition BLI_heap.c:279
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition BLI_heap.c:192
Heap * BLI_heap_new_ex(unsigned int reserve_num) ATTR_WARN_UNUSED_RESULT
Definition BLI_heap.c:172
void void bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1)
Definition BLI_heap.c:269
void * BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1)
Definition BLI_heap.c:291
HeapNode * BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1)
Definition BLI_heap.c:235
void void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1
Heap * BLI_heap_new(void) ATTR_WARN_UNUSED_RESULT
Definition BLI_heap.c:187
MINLINE double max_ddd(double a, double b, double c)
MINLINE float clamp_f(float value, float min, float max)
#define M_PI_2
MINLINE double max_dd(double a, double b)
#define M_PI
#define M_PI_4
float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:269
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:98
bool invert_m2_m2(float inverse[2][2], const float mat[2][2])
void mul_m3_v3(const float M[3][3], float r[3])
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
void mul_m2_v2(const float mat[2][2], float vec[2])
#define DEG2RADF(_deg)
void angle_to_mat2(float R[2][2], float angle)
float angle_v2v2v2(const float a[2], const float b[2], const float c[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE bool equals_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE 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])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE 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 add_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 void zero_v3(float r[3])
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void * BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
#define BLI_MEMARENA_STD_BUFSIZE
void void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
void BLI_polyfill_calc_arena(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3], struct MemArena *arena)
#define BLI_POLYFILL_ALLOC_NGON_RESERVE
void BLI_polyfill_beautify(const float(*coords)[2], unsigned int coords_num, unsigned int(*tris)[3], struct MemArena *arena, struct Heap *eheap)
Random number functions.
struct RNG * BLI_rng_new(unsigned int seed)
Definition rand.cc:39
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition rand.cc:58
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition rand.cc:93
unsigned int uint
#define INIT_MINMAX2(min, max)
#define UNUSED_FUNCTION(x)
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define POINTER_FROM_INT(i)
#define SHIFT3(type, a, b, c)
#define UNLIKELY(x)
#define ELEM(...)
typedef double(DMatrix)[4][4]
@ ED_UVPACK_MARGIN_SCALED
@ ED_UVPACK_ROTATION_ANY
@ ED_UVPACK_ROTATION_NONE
#define PARAM_KEY_MAX
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
#define MEM_SAFE_FREE(v)
#define MEM_SIZE_OPTIMAL(size)
#define U
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
static T sum(const btAlignedObjectArray< T > &items)
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
Definition btVector3.h:263
const T & first() const
Definition BLI_array.hh:270
int64_t size() const
void append(const T &value)
void remove(const int64_t index)
IndexRange index_range() const
void append_unchecked(const T &value)
void reserve(const int64_t min_capacity)
bool can_scale_(const UVPackIsland_Params &params) const
Definition uv_pack.cc:2428
void build_transformation(float scale, double rotation, float r_matrix[2][2]) const
Definition uv_pack.cc:2351
void add_triangle(float2 uv0, float2 uv1, float2 uv2)
Definition uv_pack.cc:149
local_group_size(16, 16) .push_constant(Type b
#define sinf(x)
#define cosf(x)
#define fabsf(x)
#define sqrtf(x)
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static float verts[][3]
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
LinearSolver * EIG_linear_solver_new(int num_rows, int num_columns, int num_rhs)
LinearSolver * EIG_linear_least_squares_solver_new(int num_rows, int num_columns, int num_rhs)
void EIG_linear_solver_variable_set(LinearSolver *solver, int rhs, int index, double value)
void EIG_linear_solver_right_hand_side_add(LinearSolver *solver, int rhs, int index, double value)
void EIG_linear_solver_delete(LinearSolver *solver)
double EIG_linear_solver_variable_get(LinearSolver *solver, int rhs, int index)
void EIG_linear_solver_matrix_add(LinearSolver *solver, int row, int col, double value)
bool EIG_linear_solver_solve(LinearSolver *solver)
void EIG_linear_solver_variable_lock(LinearSolver *solver, int index)
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
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
ccl_device_inline float3 cos(float3 v)
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
static ulong * next
#define M
static int corner1[12]
#define T
#define R
#define L
static int corner2[12]
static void p_chart_rotate_minimum_area(PChart *chart)
bool uv_parametrizer_is_slim(const ParamHandle *phandle)
static PVert * p_vert_add(ParamHandle *handle, PHashKey key, const float co[3], const float weight, PEdge *e)
static PFace * p_face_add_construct(ParamHandle *handle, ParamKey key, const ParamKey *vkeys, const float **co, float **uv, const float *weight, int i1, int i2, int i3, const bool *pin, const bool *select)
void uv_parametrizer_construct_end(ParamHandle *phandle, bool fill_holes, bool topology_from_uvs, int *r_count_failed=nullptr)
static bool p_validate_corrected_coords(const PEdge *corr_e, const float corr_co[3], float min_area, float min_angle_cos)
static void p_chart_fill_boundaries(ParamHandle *handle, PChart *chart, const PEdge *outer)
static PFace * p_face_add_fill(ParamHandle *handle, PChart *chart, PVert *v1, PVert *v2, PVert *v3)
void uv_parametrizer_edge_set_seam(ParamHandle *phandle, const ParamKey *vkeys)
static void p_vert_load_pin_select_uvs(ParamHandle *handle, PVert *v)
static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
static void p_face_angles(PFace *f, double *r_a1, double *r_a2, double *r_a3)
static bool p_intersect_line_2d_dir(const float v1[2], const float dir1[2], const float v2[2], const float dir2[2], float r_isect[2])
void uv_parametrizer_average(ParamHandle *handle, bool ignore_pinned, bool scale_uv, bool shear)
static float p_chart_uv_area(PChart *chart)
void uv_parametrizer_flush(ParamHandle *handle)
static PHash * phash_new(PHashLink **list, int sizehint)
static bool UNUSED_FUNCTION_NO_SLIM p_chart_correct_degenerate_triangles(PChart *chart, const float min_area, const float min_angle)
static void p_face_backup_uvs(PFace *f)
static void p_abf_adjust_alpha(PAbfSystem *sys, const int id, const float dlambda1, const float pre)
static void p_chart_rotate_fit_aabb(PChart *chart)
static void p_flush_uvs(ParamHandle *handle, PChart *chart)
void uv_parametrizer_slim_live_begin(ParamHandle *phandle, const ParamSlimOptions *slim_options)
static void p_collapse_cost_vertex(PVert *vert, float *r_mincost, PEdge **r_mine, const std::function< float(PEdge *, PEdge *)> &collapse_cost_fn, const std::function< float(PEdge *, PEdge *)> &collapse_allowed_fn)
static float p_rectangle_area(float *p1, float *dir, float *p2, float *p3, float *p4)
void uv_parametrizer_slim_stretch_iteration(ParamHandle *phandle, float blend)
static float p_collapse_doubles_cost(PEdge *edge, PEdge *pair)
static bool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair)
static void phash_safe_delete(PHash **pph)
static bool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2)
static bool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, int *r_right)
static float p_vec_cos(const float v1[3], const float v2[3], const float v3[3])
void uv_parametrizer_slim_live_solve_iteration(ParamHandle *phandle)
static void p_chart_stretch_minimize(PChart *chart, RNG *rng)
static PEdge * p_edge_lookup(ParamHandle *handle, const PHashKey *vkeys)
static float p_face_stretch(PFace *f)
ParamKey uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
static void p_split_vert(ParamHandle *handle, PChart *chart, PEdge *e)
static PEdge * p_wheel_edge_prev(PEdge *e)
static void p_collapsing_verts(PEdge *edge, PEdge *pair, PVert **r_newv, PVert **r_keepv)
static void p_stretch_pin_boundary(PChart *chart)
static float p_chart_minimum_area_angle(PChart *chart)
static bool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
static int phash_size(PHash *ph)
static bool p_chart_correct_degenerate_triangle_point(PFace *f, float min_area, float min_angle_cos)
static float p_edge_length(PEdge *e)
void uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
static void p_face_restore_uvs(PFace *f)
static PEdge * p_wheel_edge_next(PEdge *e)
void uv_parametrizer_slim_live_end(ParamHandle *phandle)
static void p_chart_lscm_end(PChart *chart)
static void UNUSED_FUNCTION p_chart_collapse_doubles(PChart *chart, const float threshold)
static int PHashSizes[]
static void p_abf_setup_system(PAbfSystem *sys)
static const float CORR_ZERO_AREA_EPS
static void p_abf_compute_sines(PAbfSystem *sys)
static int p_compare_geometric_uv(const void *a, const void *b)
static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2)
static float p_edge_length_squared(PEdge *e)
void uv_parametrizer_stretch_blend(ParamHandle *handle, float blend)
static void p_chart_uv_bbox(PChart *chart, float minv[2], float maxv[2])
static bool p_edge_matrix(float R[3][3], const float edge_dir[3])
void uv_parametrizer_slim_solve(ParamHandle *phandle, const ParamSlimOptions *slim_options, int *count_changed, int *count_failed)
static bool p_edge_connect_pair(ParamHandle *handle, PEdge *e, bool topology_from_uvs, PEdge ***stack)
void mul_v2_m2_add_v2v2(float r[2], const float mat[2][2], const float a[2], const float b[2])
Definition uv_pack.cc:55
static void p_chart_post_collapse_flush(PChart *chart, PEdge *collapsed)
static void p_collapse_edge(PEdge *edge, PEdge *pair)
static bool p_vert_interior(PVert *v)
static GeoUVPinIndex * new_geo_uv_pinindex(ParamHandle *handle, const float uv[2])
static float p_abf_compute_grad_alpha(PAbfSystem *sys, PFace *f, PEdge *e)
static float p_face_uv_area_signed(PFace *f)
static bool p_collapse_doubles_allowed(PEdge *edge, PEdge *pair, float threshold_squared)
static void UNUSED_FUNCTION p_face_cos(PFace *f, float *r_cos1, float *r_cos2, float *r_cos3)
static void p_vert_fix_edge_pointer(PVert *v)
static void p_chart_uv_translate(PChart *chart, const float trans[2])
static bool p_edge_implicit_seam(PEdge *e, PEdge *ep)
static void p_chart_uv_scale(PChart *chart, const float scale)
void uv_parametrizer_lscm_end(ParamHandle *handle)
static void p_chart_fill_boundary(ParamHandle *handle, PChart *chart, PEdge *be, int nedges)
static bool p_edge_has_pair(ParamHandle *handle, PEdge *e, bool topology_from_uvs, PEdge **r_pair)
static void p_chart_uv_to_array(PChart *chart, float(*points)[2])
static float p_area_signed(const float v1[2], const float v2[2], const float v3[2])
void uv_parametrizer_aspect_ratio(ParamHandle *handle, float aspect_y)
static void p_chart_uv_transform(PChart *chart, const float mat[2][2])
static float p_abf_compute_gradient(PAbfSystem *sys, PChart *chart)
void uv_parametrizer_stretch_begin(ParamHandle *handle)
static PEdge * p_boundary_edge_next(PEdge *e)
static void p_chart_lscm_begin(PChart *chart, bool live, bool abf)
static PHashLink * phash_lookup(PHash *ph, PHashKey key)
static void p_abf_free_system(PAbfSystem *sys)
static void p_triangle_angles(const float v1[3], const float v2[3], const float v3[3], double *r_a1, double *r_a2, double *r_a3)
void uv_parametrizer_flush_restore(ParamHandle *handle)
static bool p_chart_abf_solve(PChart *chart)
static bool p_chart_correct_degenerate_triangles2(PChart *chart, float min_area, float min_angle)
static PVert * p_vert_copy(ParamHandle *handle, PVert *v)
static bool p_validate_corrected_coords_point(const PEdge *corr_e, const float corr_co1[3], const float corr_co2[3], const float min_area, const float min_angle_cos)
static PFace * p_face_add(ParamHandle *handle)
static void p_triangle_cos(const float v1[3], const float v2[3], const float v3[3], float *r_cos1, float *r_cos2, float *r_cos3)
static float p_stretch_compute_vertex(PVert *v)
static PChart ** p_split_charts(ParamHandle *handle, PChart *chart, int ncharts)
static void p_add_ngon(ParamHandle *handle, const ParamKey key, const int nverts, const ParamKey *vkeys, const float **co, float **uv, const float *weight, const bool *pin, const bool *select)
static float p_abf_compute_sin_product(PAbfSystem *sys, PVert *v, int aid)
void uv_parametrizer_lscm_begin(ParamHandle *handle, bool live, bool abf)
static void p_chart_extrema_verts(PChart *chart, PVert **pin1, PVert **pin2)
float pack_islands(Span< PackIsland * > islands, const UVPackIsland_Params &params)
static float p_edge_boundary_angle(PEdge *e)
void uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed)
static void fix_large_angle(const float v_fix[3], const float v1[3], const float v2[3], double *r_fix, double *r_a1, double *r_a2)
static void p_chart_simplify_compute(PChart *chart, std::function< float(PEdge *, PEdge *)> collapse_cost_fn, std::function< float(PEdge *, PEdge *)> collapse_allowed_fn)
void uv_parametrizer_stretch_iter(ParamHandle *handle)
static void uv_parametrizer_scale_x(ParamHandle *phandle, const float scale_x)
static int p_face_exists(ParamHandle *handle, const ParamKey *pvkeys, int i1, int i2, int i3)
static void p_face_flip(PFace *f)
static void phash_insert(PHash *ph, PHashLink *link)
static float p_face_area(PFace *f)
static PVert * p_vert_lookup(ParamHandle *handle, PHashKey key, const float co[3], const float weight, PEdge *e)
void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned)
static void p_chart_flush_collapsed_uvs(PChart *chart)
void uv_parametrizer_stretch_end(ParamHandle *handle)
static PEdge * p_boundary_edge_prev(PEdge *e)
static PHashLink * phash_next(PHash *ph, PHashKey key, PHashLink *link)
static float p_edge_uv_length(PEdge *e)
static void p_chart_boundaries(PChart *chart, PEdge **r_outer)
static int p_connect_pairs(ParamHandle *handle, bool topology_from_uvs)
static void p_chart_lscm_transform_single_pin(PChart *chart)
static bool p_validate_triangle_angles(const PVert *vert1, const PVert *vert2, const PVert *vert3, const float min_angle_cos)
void uv_parametrizer_face_add(ParamHandle *handle, const ParamKey key, const int nverts, const ParamKey *vkeys, const float **co, float **uv, const float *weight, const bool *pin, const bool *select)
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
#define hash
Definition noise.c:154
const btScalar eps
Definition poly34.cpp:11
return ret
_W64 unsigned int uintptr_t
Definition stdint.h:119
__int64 int64_t
Definition stdint.h:89
float co[3]
Definition rand.cc:33
union blender::geometry::PEdge::PEdgeUnion u
union blender::geometry::PFace::PFaceUnion u
union blender::geometry::PVert::PVertUnion u
std::vector< float > w_vectors
std::vector< double > el_vectors
std::vector< double > v_matrices
std::vector< double > uv_matrices
std::vector< double > pp_matrices
void setup_slim_data(MatrixTransferChart &chart) const
std::vector< MatrixTransferChart > charts
PinnedVertexData pinned_vertex_data
void parametrize_live(MatrixTransferChart &chart, const PinnedVertexData &pinned_vertex_data)
std::vector< int > selected_pins
std::vector< int > pinned_vertex_indices
std::vector< double > pinned_vertex_positions_2D
ccl_device_inline float beta(float x, float y)
Definition util/math.h:833
#define UNUSED_FUNCTION_NO_SLIM
#define PHASH_hash(ph, item)
#define PHASH_edge(v1, v2)
#define PEDGE_VERTEX_FLAGS
#define P_STRETCH_ITER
#define ABF_MAX_ITER
#define param_warning(message)