Blender  V2.93
uvedit_parametrizer.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include "MEM_guardedalloc.h"
22 
23 #include "BLI_boxpack_2d.h"
24 #include "BLI_convexhull_2d.h"
25 #include "BLI_heap.h"
26 #include "BLI_math.h"
27 #include "BLI_memarena.h"
28 #include "BLI_polyfill_2d.h"
30 #include "BLI_rand.h"
31 #include "BLI_utildefines.h"
32 
33 #include "uvedit_parametrizer.h"
34 
35 #include <math.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include "BLI_sys_types.h" /* for intptr_t support */
41 
42 #include "eigen_capi.h"
43 
44 /* Utils */
45 
46 #define param_assert(condition) \
47  if (!(condition)) { /*printf("Assertion %s:%d\n", __FILE__, __LINE__); abort();*/ \
48  } \
49  (void)0
50 #define param_warning(message) \
51  {/*printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);*/}(void)0
52 
53 typedef enum PBool {
54  P_TRUE = 1,
55  P_FALSE = 0,
57 
58 /* Special Purpose Hash */
59 
61 
62 typedef struct PHashLink {
63  struct PHashLink *next;
66 
67 typedef struct PHash {
72 
73 struct PChart;
74 struct PEdge;
75 struct PFace;
76 struct PHandle;
77 struct PVert;
78 
79 /* Simplices */
80 
81 typedef struct PVert {
82  struct PVert *nextlink;
83 
84  union PVertUnion {
85  PHashKey key; /* construct */
86  int id; /* abf/lscm matrix index */
87  float distortion; /* area smoothing */
88  HeapNode *heaplink; /* edge collapsing */
89  } u;
90 
91  struct PEdge *edge;
92  float co[3];
93  float uv[2];
95 
97 
98 typedef struct PEdge {
99  struct PEdge *nextlink;
100 
101  union PEdgeUnion {
102  PHashKey key; /* construct */
103  int id; /* abf matrix index */
104  HeapNode *heaplink; /* fill holes */
105  struct PEdge *nextcollapse; /* simplification */
106  } u;
107 
108  struct PVert *vert;
109  struct PEdge *pair;
110  struct PEdge *next;
111  struct PFace *face;
112  float *orig_uv, old_uv[2];
114 
116 
117 typedef struct PFace {
118  struct PFace *nextlink;
119 
120  union PFaceUnion {
121  PHashKey key; /* construct */
122  int chart; /* construct splitting*/
123  float area3d; /* stretch */
124  int id; /* abf matrix index */
125  } u;
126 
127  struct PEdge *edge;
130 
131 enum PVertFlag {
137 };
138 
139 enum PEdgeFlag {
149 };
150 
151 /* for flipping faces */
152 #define PEDGE_VERTEX_FLAGS (PEDGE_PIN)
153 
154 enum PFaceFlag {
158 };
159 
160 /* Chart */
161 
162 typedef struct PChart {
167 
171 
172  union PChartUnion {
173  struct PChartLscm {
175  float *abf_alpha;
179  float single_pin_uv[2];
180  } lscm;
181  struct PChartPack {
182  float rescale, area;
183  float size[2] /* , trans[2] */;
184  } pack;
185  } u;
186 
188  struct PHandle *handle;
190 
193 };
194 
200 };
201 
202 typedef struct PHandle {
203  enum PHandleState state;
207 
212 
214  int ncharts;
215 
216  float aspx, aspy;
217 
219  float blend;
220  char do_aspect;
222 
223 /* PHash
224  * - special purpose hash that keeps all its elements in a single linked list.
225  * - after construction, this hash is thrown away, and the list remains.
226  * - removing elements is not possible efficiently.
227  */
228 
229 static int PHashSizes[] = {
230  1, 3, 5, 11, 17, 37, 67, 131, 257, 521,
231  1031, 2053, 4099, 8209, 16411, 32771, 65537, 131101, 262147, 524309,
232  1048583, 2097169, 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459,
233 };
234 
235 #define PHASH_hash(ph, item) (((uintptr_t)(item)) % ((uint)(ph)->cursize))
236 #define PHASH_edge(v1, v2) (((v1) < (v2)) ? ((v1)*39) ^ ((v2)*31) : ((v1)*31) ^ ((v2)*39))
237 
238 static PHash *phash_new(PHashLink **list, int sizehint)
239 {
240  PHash *ph = (PHash *)MEM_callocN(sizeof(PHash), "PHash");
241  ph->size = 0;
242  ph->cursize_id = 0;
243  ph->list = list;
244 
245  while (PHashSizes[ph->cursize_id] < sizehint) {
246  ph->cursize_id++;
247  }
248 
249  ph->cursize = PHashSizes[ph->cursize_id];
250  ph->buckets = (PHashLink **)MEM_callocN(ph->cursize * sizeof(*ph->buckets), "PHashBuckets");
251 
252  return ph;
253 }
254 
255 static void phash_delete(PHash *ph)
256 {
257  MEM_freeN(ph->buckets);
258  MEM_freeN(ph);
259 }
260 
261 static int phash_size(PHash *ph)
262 {
263  return ph->size;
264 }
265 
266 static void phash_insert(PHash *ph, PHashLink *link)
267 {
268  int size = ph->cursize;
269  uintptr_t hash = PHASH_hash(ph, link->key);
270  PHashLink *lookup = ph->buckets[hash];
271 
272  if (lookup == NULL) {
273  /* insert in front of the list */
274  ph->buckets[hash] = link;
275  link->next = *(ph->list);
276  *(ph->list) = link;
277  }
278  else {
279  /* insert after existing element */
280  link->next = lookup->next;
281  lookup->next = link;
282  }
283 
284  ph->size++;
285 
286  if (ph->size > (size * 3)) {
287  PHashLink *next = NULL, *first = *(ph->list);
288 
289  ph->cursize = PHashSizes[++ph->cursize_id];
290  MEM_freeN(ph->buckets);
291  ph->buckets = (PHashLink **)MEM_callocN(ph->cursize * sizeof(*ph->buckets), "PHashBuckets");
292  ph->size = 0;
293  *(ph->list) = NULL;
294 
295  for (link = first; link; link = next) {
296  next = link->next;
297  phash_insert(ph, link);
298  }
299  }
300 }
301 
303 {
304  PHashLink *link;
305  uintptr_t hash = PHASH_hash(ph, key);
306 
307  for (link = ph->buckets[hash]; link; link = link->next) {
308  if (link->key == key) {
309  return link;
310  }
311  if (PHASH_hash(ph, link->key) != hash) {
312  return NULL;
313  }
314  }
315 
316  return link;
317 }
318 
319 static PHashLink *phash_next(PHash *ph, PHashKey key, PHashLink *link)
320 {
321  uintptr_t hash = PHASH_hash(ph, key);
322 
323  for (link = link->next; link; link = link->next) {
324  if (link->key == key) {
325  return link;
326  }
327  if (PHASH_hash(ph, link->key) != hash) {
328  return NULL;
329  }
330  }
331 
332  return link;
333 }
334 
335 /* Geometry */
336 
337 static float p_vec_angle_cos(const float v1[3], const float v2[3], const float v3[3])
338 {
339  float d1[3], d2[3];
340 
341  d1[0] = v1[0] - v2[0];
342  d1[1] = v1[1] - v2[1];
343  d1[2] = v1[2] - v2[2];
344 
345  d2[0] = v3[0] - v2[0];
346  d2[1] = v3[1] - v2[1];
347  d2[2] = v3[2] - v2[2];
348 
349  normalize_v3(d1);
350  normalize_v3(d2);
351 
352  return d1[0] * d2[0] + d1[1] * d2[1] + d1[2] * d2[2];
353 }
354 
355 static float p_vec_angle(const float v1[3], const float v2[3], const float v3[3])
356 {
357  float dot = p_vec_angle_cos(v1, v2, v3);
358 
359  if (dot <= -1.0f) {
360  return (float)M_PI;
361  }
362  if (dot >= 1.0f) {
363  return 0.0f;
364  }
365  return acosf(dot);
366 }
367 
368 static float p_vec2_angle(const float v1[2], const float v2[2], const float v3[2])
369 {
370  float u1[3], u2[3], u3[3];
371 
372  u1[0] = v1[0];
373  u1[1] = v1[1];
374  u1[2] = 0.0f;
375  u2[0] = v2[0];
376  u2[1] = v2[1];
377  u2[2] = 0.0f;
378  u3[0] = v3[0];
379  u3[1] = v3[1];
380  u3[2] = 0.0f;
381 
382  return p_vec_angle(u1, u2, u3);
383 }
384 
385 static void p_triangle_angles(
386  const float v1[3], const float v2[3], const float v3[3], float *r_a1, float *r_a2, float *r_a3)
387 {
388  *r_a1 = p_vec_angle(v3, v1, v2);
389  *r_a2 = p_vec_angle(v1, v2, v3);
390  *r_a3 = (float)M_PI - *r_a2 - *r_a1;
391 }
392 
393 static void p_face_angles(PFace *f, float *r_a1, float *r_a2, float *r_a3)
394 {
395  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
396  PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
397 
398  p_triangle_angles(v1->co, v2->co, v3->co, r_a1, r_a2, r_a3);
399 }
400 
401 static float p_face_area(PFace *f)
402 {
403  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
404  PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
405 
406  return area_tri_v3(v1->co, v2->co, v3->co);
407 }
408 
409 static float p_area_signed(const float v1[2], const float v2[2], const float v3[2])
410 {
411  return 0.5f * (((v2[0] - v1[0]) * (v3[1] - v1[1])) - ((v3[0] - v1[0]) * (v2[1] - v1[1])));
412 }
413 
414 static float p_face_uv_area_signed(PFace *f)
415 {
416  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
417  PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
418 
419  return 0.5f * (((v2->uv[0] - v1->uv[0]) * (v3->uv[1] - v1->uv[1])) -
420  ((v3->uv[0] - v1->uv[0]) * (v2->uv[1] - v1->uv[1])));
421 }
422 
423 static float p_edge_length(PEdge *e)
424 {
425  PVert *v1 = e->vert, *v2 = e->next->vert;
426  float d[3];
427 
428  d[0] = v2->co[0] - v1->co[0];
429  d[1] = v2->co[1] - v1->co[1];
430  d[2] = v2->co[2] - v1->co[2];
431 
432  return sqrtf(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
433 }
434 
435 static float p_edge_uv_length(PEdge *e)
436 {
437  PVert *v1 = e->vert, *v2 = e->next->vert;
438  float d[3];
439 
440  d[0] = v2->uv[0] - v1->uv[0];
441  d[1] = v2->uv[1] - v1->uv[1];
442 
443  return sqrtf(d[0] * d[0] + d[1] * d[1]);
444 }
445 
446 static void p_chart_uv_bbox(PChart *chart, float minv[2], float maxv[2])
447 {
448  PVert *v;
449 
450  INIT_MINMAX2(minv, maxv);
451 
452  for (v = chart->verts; v; v = v->nextlink) {
453  minmax_v2v2_v2(minv, maxv, v->uv);
454  }
455 }
456 
457 static float p_chart_uv_area(PChart *chart)
458 {
459  float area = 0.0f;
460 
461  for (PFace *f = chart->faces; f; f = f->nextlink) {
463  }
464 
465  return area;
466 }
467 
468 static void p_chart_uv_scale(PChart *chart, float scale)
469 {
470  PVert *v;
471 
472  for (v = chart->verts; v; v = v->nextlink) {
473  v->uv[0] *= scale;
474  v->uv[1] *= scale;
475  }
476 }
477 
478 static void p_chart_uv_scale_xy(PChart *chart, float x, float y)
479 {
480  PVert *v;
481 
482  for (v = chart->verts; v; v = v->nextlink) {
483  v->uv[0] *= x;
484  v->uv[1] *= y;
485  }
486 }
487 
488 static void p_chart_uv_translate(PChart *chart, const float trans[2])
489 {
490  PVert *v;
491 
492  for (v = chart->verts; v; v = v->nextlink) {
493  v->uv[0] += trans[0];
494  v->uv[1] += trans[1];
495  }
496 }
497 
498 static void p_chart_uv_transform(PChart *chart, const float mat[2][2])
499 {
500  PVert *v;
501 
502  for (v = chart->verts; v; v = v->nextlink) {
503  mul_m2_v2(mat, v->uv);
504  }
505 }
506 
507 static void p_chart_uv_to_array(PChart *chart, float (*points)[2])
508 {
509  PVert *v;
510  uint i = 0;
511 
512  for (v = chart->verts; v; v = v->nextlink) {
513  copy_v2_v2(points[i++], v->uv);
514  }
515 }
516 
517 static void UNUSED_FUNCTION(p_chart_uv_from_array)(PChart *chart, float (*points)[2])
518 {
519  PVert *v;
520  uint i = 0;
521 
522  for (v = chart->verts; v; v = v->nextlink) {
523  copy_v2_v2(v->uv, points[i++]);
524  }
525 }
526 
527 static PBool p_intersect_line_2d_dir(const float v1[2],
528  const float dir1[2],
529  const float v2[2],
530  const float dir2[2],
531  float r_isect[2])
532 {
533  float lmbda, div;
534 
535  div = dir2[0] * dir1[1] - dir2[1] * dir1[0];
536 
537  if (div == 0.0f) {
538  return P_FALSE;
539  }
540 
541  lmbda = ((v1[1] - v2[1]) * dir1[0] - (v1[0] - v2[0]) * dir1[1]) / div;
542  r_isect[0] = v1[0] + lmbda * dir2[0];
543  r_isect[1] = v1[1] + lmbda * dir2[1];
544 
545  return P_TRUE;
546 }
547 
548 #if 0
549 static PBool p_intersect_line_2d(const float v1[2],
550  const float v2[2],
551  const float v3[2],
552  const float v4[2],
553  const float r_isect[2])
554 {
555  float dir1[2], dir2[2];
556 
557  dir1[0] = v4[0] - v3[0];
558  dir1[1] = v4[1] - v3[1];
559 
560  dir2[0] = v2[0] - v1[0];
561  dir2[1] = v2[1] - v1[1];
562 
563  if (!p_intersect_line_2d_dir(v1, dir1, v2, dir2, isect)) {
564  /* parallel - should never happen in theory for polygon kernel, but
565  * let's give a point nearby in case things go wrong */
566  isect[0] = (v1[0] + v2[0]) * 0.5f;
567  isect[1] = (v1[1] + v2[1]) * 0.5f;
568  return P_FALSE;
569  }
570 
571  return P_TRUE;
572 }
573 #endif
574 
575 /* Topological Utilities */
576 
578 {
579  return e->next->next->pair;
580 }
581 
583 {
584  return (e->pair) ? e->pair->next : NULL;
585 }
586 
588 {
589  return e->next->vert->edge;
590 }
591 
593 {
594  PEdge *we = e, *last;
595 
596  do {
597  last = we;
598  we = p_wheel_edge_next(we);
599  } while (we && (we != e));
600 
601  return last->next->next;
602 }
603 
605 {
606  return (v->edge->pair != NULL);
607 }
608 
609 static void p_face_flip(PFace *f)
610 {
611  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
612  PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
613  int f1 = e1->flag, f2 = e2->flag, f3 = e3->flag;
614  float *orig_uv1 = e1->orig_uv, *orig_uv2 = e2->orig_uv, *orig_uv3 = e3->orig_uv;
615 
616  e1->vert = v2;
617  e1->next = e3;
618  e1->orig_uv = orig_uv2;
619  e1->flag = (f1 & ~PEDGE_VERTEX_FLAGS) | (f2 & PEDGE_VERTEX_FLAGS);
620 
621  e2->vert = v3;
622  e2->next = e1;
623  e2->orig_uv = orig_uv3;
624  e2->flag = (f2 & ~PEDGE_VERTEX_FLAGS) | (f3 & PEDGE_VERTEX_FLAGS);
625 
626  e3->vert = v1;
627  e3->next = e2;
628  e3->orig_uv = orig_uv1;
629  e3->flag = (f3 & ~PEDGE_VERTEX_FLAGS) | (f1 & PEDGE_VERTEX_FLAGS);
630 }
631 
632 #if 0
633 static void p_chart_topological_sanity_check(PChart *chart)
634 {
635  PVert *v;
636  PEdge *e;
637 
638  for (v = chart->verts; v; v = v->nextlink) {
639  param_test_equals_ptr("v->edge->vert", v, v->edge->vert);
640  }
641 
642  for (e = chart->edges; e; e = e->nextlink) {
643  if (e->pair) {
644  param_test_equals_ptr("e->pair->pair", e, e->pair->pair);
645  param_test_equals_ptr("pair->vert", e->vert, e->pair->next->vert);
646  param_test_equals_ptr("pair->next->vert", e->next->vert, e->pair->vert);
647  }
648  }
649 }
650 #endif
651 
652 /* Loading / Flushing */
653 
655 {
656  PEdge *e;
657  int nedges = 0, npins = 0;
658  float pinuv[2];
659 
660  v->uv[0] = v->uv[1] = 0.0f;
661  pinuv[0] = pinuv[1] = 0.0f;
662  e = v->edge;
663  do {
664  if (e->orig_uv) {
665  if (e->flag & PEDGE_SELECT) {
666  v->flag |= PVERT_SELECT;
667  }
668 
669  if (e->flag & PEDGE_PIN) {
670  pinuv[0] += e->orig_uv[0] * handle->aspx;
671  pinuv[1] += e->orig_uv[1] * handle->aspy;
672  npins++;
673  }
674  else {
675  v->uv[0] += e->orig_uv[0] * handle->aspx;
676  v->uv[1] += e->orig_uv[1] * handle->aspy;
677  }
678 
679  nedges++;
680  }
681 
682  e = p_wheel_edge_next(e);
683  } while (e && e != (v->edge));
684 
685  if (npins > 0) {
686  v->uv[0] = pinuv[0] / npins;
687  v->uv[1] = pinuv[1] / npins;
688  v->flag |= PVERT_PIN;
689  }
690  else if (nedges > 0) {
691  v->uv[0] /= nedges;
692  v->uv[1] /= nedges;
693  }
694 }
695 
696 static void p_flush_uvs(PHandle *handle, PChart *chart)
697 {
698  PEdge *e;
699 
700  for (e = chart->edges; e; e = e->nextlink) {
701  if (e->orig_uv) {
702  e->orig_uv[0] = e->vert->uv[0] / handle->aspx;
703  e->orig_uv[1] = e->vert->uv[1] / handle->aspy;
704  }
705  }
706 }
707 
708 static void p_flush_uvs_blend(PHandle *handle, PChart *chart, float blend)
709 {
710  PEdge *e;
711  float invblend = 1.0f - blend;
712 
713  for (e = chart->edges; e; e = e->nextlink) {
714  if (e->orig_uv) {
715  e->orig_uv[0] = blend * e->old_uv[0] + invblend * e->vert->uv[0] / handle->aspx;
716  e->orig_uv[1] = blend * e->old_uv[1] + invblend * e->vert->uv[1] / handle->aspy;
717  }
718  }
719 }
720 
721 static void p_face_backup_uvs(PFace *f)
722 {
723  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
724 
725  if (e1->orig_uv) {
726  e1->old_uv[0] = e1->orig_uv[0];
727  e1->old_uv[1] = e1->orig_uv[1];
728  }
729  if (e2->orig_uv) {
730  e2->old_uv[0] = e2->orig_uv[0];
731  e2->old_uv[1] = e2->orig_uv[1];
732  }
733  if (e3->orig_uv) {
734  e3->old_uv[0] = e3->orig_uv[0];
735  e3->old_uv[1] = e3->orig_uv[1];
736  }
737 }
738 
739 static void p_face_restore_uvs(PFace *f)
740 {
741  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
742 
743  if (e1->orig_uv) {
744  e1->orig_uv[0] = e1->old_uv[0];
745  e1->orig_uv[1] = e1->old_uv[1];
746  }
747  if (e2->orig_uv) {
748  e2->orig_uv[0] = e2->old_uv[0];
749  e2->orig_uv[1] = e2->old_uv[1];
750  }
751  if (e3->orig_uv) {
752  e3->orig_uv[0] = e3->old_uv[0];
753  e3->orig_uv[1] = e3->old_uv[1];
754  }
755 }
756 
757 /* Construction (use only during construction, relies on u.key being set */
758 
759 static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge *e)
760 {
761  PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v));
762  copy_v3_v3(v->co, co);
763 
764  /* Sanity check, a single nan/inf point causes the entire result to be invalid.
765  * Note that values within the calculation may _become_ non-finite,
766  * so the rest of the code still needs to take this possibility into account. */
767  for (int i = 0; i < 3; i++) {
768  if (UNLIKELY(!isfinite(v->co[i]))) {
769  v->co[i] = 0.0f;
770  }
771  }
772 
773  v->u.key = key;
774  v->edge = e;
775  v->flag = 0;
776 
777  phash_insert(handle->hash_verts, (PHashLink *)v);
778 
779  return v;
780 }
781 
782 static PVert *p_vert_lookup(PHandle *handle, PHashKey key, const float co[3], PEdge *e)
783 {
784  PVert *v = (PVert *)phash_lookup(handle->hash_verts, key);
785 
786  if (v) {
787  return v;
788  }
789  return p_vert_add(handle, key, co, e);
790 }
791 
792 static PVert *p_vert_copy(PChart *chart, PVert *v)
793 {
794  PVert *nv = (PVert *)BLI_memarena_alloc(chart->handle->arena, sizeof(*nv));
795 
796  copy_v3_v3(nv->co, v->co);
797  nv->uv[0] = v->uv[0];
798  nv->uv[1] = v->uv[1];
799  nv->u.key = v->u.key;
800  nv->edge = v->edge;
801  nv->flag = v->flag;
802 
803  return nv;
804 }
805 
806 static PEdge *p_edge_lookup(PHandle *handle, const PHashKey *vkeys)
807 {
808  PHashKey key = PHASH_edge(vkeys[0], vkeys[1]);
809  PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
810 
811  while (e) {
812  if ((e->vert->u.key == vkeys[0]) && (e->next->vert->u.key == vkeys[1])) {
813  return e;
814  }
815  if ((e->vert->u.key == vkeys[1]) && (e->next->vert->u.key == vkeys[0])) {
816  return e;
817  }
818 
819  e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e);
820  }
821 
822  return NULL;
823 }
824 
825 static int p_face_exists(ParamHandle *phandle, ParamKey *pvkeys, int i1, int i2, int i3)
826 {
827  PHandle *handle = (PHandle *)phandle;
828  PHashKey *vkeys = (PHashKey *)pvkeys;
829  PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]);
830  PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
831 
832  while (e) {
833  if ((e->vert->u.key == vkeys[i1]) && (e->next->vert->u.key == vkeys[i2])) {
834  if (e->next->next->vert->u.key == vkeys[i3]) {
835  return P_TRUE;
836  }
837  }
838  else if ((e->vert->u.key == vkeys[i2]) && (e->next->vert->u.key == vkeys[i1])) {
839  if (e->next->next->vert->u.key == vkeys[i3]) {
840  return P_TRUE;
841  }
842  }
843 
844  e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e);
845  }
846 
847  return P_FALSE;
848 }
849 
850 static PChart *p_chart_new(PHandle *handle)
851 {
852  PChart *chart = (PChart *)MEM_callocN(sizeof(*chart), "PChart");
853  chart->handle = handle;
854 
855  return chart;
856 }
857 
858 static void p_chart_delete(PChart *chart)
859 {
860  /* the actual links are free by memarena */
861  MEM_freeN(chart);
862 }
863 
865 {
866  float *uv1, *uv2, *uvp1, *uvp2;
867  float limit[2];
868 
869  limit[0] = 0.00001;
870  limit[1] = 0.00001;
871 
872  uv1 = e->orig_uv;
873  uv2 = e->next->orig_uv;
874 
875  if (e->vert->u.key == ep->vert->u.key) {
876  uvp1 = ep->orig_uv;
877  uvp2 = ep->next->orig_uv;
878  }
879  else {
880  uvp1 = ep->next->orig_uv;
881  uvp2 = ep->orig_uv;
882  }
883 
884  if ((fabsf(uv1[0] - uvp1[0]) > limit[0]) || (fabsf(uv1[1] - uvp1[1]) > limit[1])) {
885  e->flag |= PEDGE_SEAM;
886  ep->flag |= PEDGE_SEAM;
887  return P_TRUE;
888  }
889  if ((fabsf(uv2[0] - uvp2[0]) > limit[0]) || (fabsf(uv2[1] - uvp2[1]) > limit[1])) {
890  e->flag |= PEDGE_SEAM;
891  ep->flag |= PEDGE_SEAM;
892  return P_TRUE;
893  }
894 
895  return P_FALSE;
896 }
897 
898 static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool topology_from_uvs, PEdge **r_pair)
899 {
900  PHashKey key;
901  PEdge *pe;
902  PVert *v1, *v2;
903  PHashKey key1 = e->vert->u.key;
904  PHashKey key2 = e->next->vert->u.key;
905 
906  if (e->flag & PEDGE_SEAM) {
907  return P_FALSE;
908  }
909 
910  key = PHASH_edge(key1, key2);
911  pe = (PEdge *)phash_lookup(handle->hash_edges, key);
912  *r_pair = NULL;
913 
914  while (pe) {
915  if (pe != e) {
916  v1 = pe->vert;
917  v2 = pe->next->vert;
918 
919  if (((v1->u.key == key1) && (v2->u.key == key2)) ||
920  ((v1->u.key == key2) && (v2->u.key == key1))) {
921 
922  /* don't connect seams and t-junctions */
923  if ((pe->flag & PEDGE_SEAM) || *r_pair ||
924  (topology_from_uvs && p_edge_implicit_seam(e, pe))) {
925  *r_pair = NULL;
926  return P_FALSE;
927  }
928 
929  *r_pair = pe;
930  }
931  }
932 
933  pe = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)pe);
934  }
935 
936  if (*r_pair && (e->vert == (*r_pair)->vert)) {
937  if ((*r_pair)->next->pair || (*r_pair)->next->next->pair) {
938  /* non unfoldable, maybe mobius ring or klein bottle */
939  *r_pair = NULL;
940  return P_FALSE;
941  }
942  }
943 
944  return (*r_pair != NULL);
945 }
946 
948  PEdge *e,
949  PBool topology_from_uvs,
950  PEdge ***stack)
951 {
952  PEdge *pair = NULL;
953 
954  if (!e->pair && p_edge_has_pair(handle, e, topology_from_uvs, &pair)) {
955  if (e->vert == pair->vert) {
956  p_face_flip(pair->face);
957  }
958 
959  e->pair = pair;
960  pair->pair = e;
961 
962  if (!(pair->face->flag & PFACE_CONNECTED)) {
963  **stack = pair;
964  (*stack)++;
965  }
966  }
967 
968  return (e->pair != NULL);
969 }
970 
971 static int p_connect_pairs(PHandle *handle, PBool topology_from_uvs)
972 {
973  PEdge **stackbase = MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces),
974  "Pstackbase");
975  PEdge **stack = stackbase;
976  PFace *f, *first;
977  PEdge *e, *e1, *e2;
978  PChart *chart = handle->construction_chart;
979  int ncharts = 0;
980 
981  /* Connect pairs, count edges, set vertex-edge pointer to a pair-less edge. */
982  for (first = chart->faces; first; first = first->nextlink) {
983  if (first->flag & PFACE_CONNECTED) {
984  continue;
985  }
986 
987  *stack = first->edge;
988  stack++;
989 
990  while (stack != stackbase) {
991  stack--;
992  e = *stack;
993  e1 = e->next;
994  e2 = e1->next;
995 
996  f = e->face;
997  f->flag |= PFACE_CONNECTED;
998 
999  /* assign verts to charts so we can sort them later */
1000  f->u.chart = ncharts;
1001 
1002  if (!p_edge_connect_pair(handle, e, topology_from_uvs, &stack)) {
1003  e->vert->edge = e;
1004  }
1005  if (!p_edge_connect_pair(handle, e1, topology_from_uvs, &stack)) {
1006  e1->vert->edge = e1;
1007  }
1008  if (!p_edge_connect_pair(handle, e2, topology_from_uvs, &stack)) {
1009  e2->vert->edge = e2;
1010  }
1011  }
1012 
1013  ncharts++;
1014  }
1015 
1016  MEM_freeN(stackbase);
1017 
1018  return ncharts;
1019 }
1020 
1021 static void p_split_vert(PChart *chart, PEdge *e)
1022 {
1023  PEdge *we, *lastwe = NULL;
1024  PVert *v = e->vert;
1025  PBool copy = P_TRUE;
1026 
1027  if (e->flag & PEDGE_PIN) {
1028  chart->flag |= PCHART_HAS_PINS;
1029  }
1030 
1031  if (e->flag & PEDGE_VERTEX_SPLIT) {
1032  return;
1033  }
1034 
1035  /* rewind to start */
1036  lastwe = e;
1037  for (we = p_wheel_edge_prev(e); we && (we != e); we = p_wheel_edge_prev(we)) {
1038  lastwe = we;
1039  }
1040 
1041  /* go over all edges in wheel */
1042  for (we = lastwe; we; we = p_wheel_edge_next(we)) {
1043  if (we->flag & PEDGE_VERTEX_SPLIT) {
1044  break;
1045  }
1046 
1047  we->flag |= PEDGE_VERTEX_SPLIT;
1048 
1049  if (we == v->edge) {
1050  /* found it, no need to copy */
1051  copy = P_FALSE;
1052  v->nextlink = chart->verts;
1053  chart->verts = v;
1054  chart->nverts++;
1055  }
1056  }
1057 
1058  if (copy) {
1059  /* not found, copying */
1060  v->flag |= PVERT_SPLIT;
1061  v = p_vert_copy(chart, v);
1062  v->flag |= PVERT_SPLIT;
1063 
1064  v->nextlink = chart->verts;
1065  chart->verts = v;
1066  chart->nverts++;
1067 
1068  v->edge = lastwe;
1069 
1070  we = lastwe;
1071  do {
1072  we->vert = v;
1073  we = p_wheel_edge_next(we);
1074  } while (we && (we != lastwe));
1075  }
1076 }
1077 
1078 static PChart **p_split_charts(PHandle *handle, PChart *chart, int ncharts)
1079 {
1080  PChart **charts = MEM_mallocN(sizeof(*charts) * ncharts, "PCharts"), *nchart;
1081  PFace *f, *nextf;
1082  int i;
1083 
1084  for (i = 0; i < ncharts; i++) {
1085  charts[i] = p_chart_new(handle);
1086  }
1087 
1088  f = chart->faces;
1089  while (f) {
1090  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
1091  nextf = f->nextlink;
1092 
1093  nchart = charts[f->u.chart];
1094 
1095  f->nextlink = nchart->faces;
1096  nchart->faces = f;
1097  e1->nextlink = nchart->edges;
1098  nchart->edges = e1;
1099  e2->nextlink = nchart->edges;
1100  nchart->edges = e2;
1101  e3->nextlink = nchart->edges;
1102  nchart->edges = e3;
1103 
1104  nchart->nfaces++;
1105  nchart->nedges += 3;
1106 
1107  p_split_vert(nchart, e1);
1108  p_split_vert(nchart, e2);
1109  p_split_vert(nchart, e3);
1110 
1111  f = nextf;
1112  }
1113 
1114  return charts;
1115 }
1116 
1117 static PFace *p_face_add(PHandle *handle)
1118 {
1119  PFace *f;
1120  PEdge *e1, *e2, *e3;
1121 
1122  /* allocate */
1123  f = (PFace *)BLI_memarena_alloc(handle->arena, sizeof(*f));
1124  f->flag = 0; /* init ! */
1125 
1126  e1 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e1));
1127  e2 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e2));
1128  e3 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e3));
1129 
1130  /* set up edges */
1131  f->edge = e1;
1132  e1->face = e2->face = e3->face = f;
1133 
1134  e1->next = e2;
1135  e2->next = e3;
1136  e3->next = e1;
1137 
1138  e1->pair = NULL;
1139  e2->pair = NULL;
1140  e3->pair = NULL;
1141 
1142  e1->flag = 0;
1143  e2->flag = 0;
1144  e3->flag = 0;
1145 
1146  return f;
1147 }
1148 
1150  ParamKey key,
1151  const ParamKey *vkeys,
1152  float *co[4],
1153  float *uv[4],
1154  int i1,
1155  int i2,
1156  int i3,
1157  const ParamBool *pin,
1158  const ParamBool *select)
1159 {
1160  PFace *f = p_face_add(handle);
1161  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
1162 
1163  e1->vert = p_vert_lookup(handle, vkeys[i1], co[i1], e1);
1164  e2->vert = p_vert_lookup(handle, vkeys[i2], co[i2], e2);
1165  e3->vert = p_vert_lookup(handle, vkeys[i3], co[i3], e3);
1166 
1167  e1->orig_uv = uv[i1];
1168  e2->orig_uv = uv[i2];
1169  e3->orig_uv = uv[i3];
1170 
1171  if (pin) {
1172  if (pin[i1]) {
1173  e1->flag |= PEDGE_PIN;
1174  }
1175  if (pin[i2]) {
1176  e2->flag |= PEDGE_PIN;
1177  }
1178  if (pin[i3]) {
1179  e3->flag |= PEDGE_PIN;
1180  }
1181  }
1182 
1183  if (select) {
1184  if (select[i1]) {
1185  e1->flag |= PEDGE_SELECT;
1186  }
1187  if (select[i2]) {
1188  e2->flag |= PEDGE_SELECT;
1189  }
1190  if (select[i3]) {
1191  e3->flag |= PEDGE_SELECT;
1192  }
1193  }
1194 
1195  /* insert into hash */
1196  f->u.key = key;
1197  phash_insert(handle->hash_faces, (PHashLink *)f);
1198 
1199  e1->u.key = PHASH_edge(vkeys[i1], vkeys[i2]);
1200  e2->u.key = PHASH_edge(vkeys[i2], vkeys[i3]);
1201  e3->u.key = PHASH_edge(vkeys[i3], vkeys[i1]);
1202 
1203  phash_insert(handle->hash_edges, (PHashLink *)e1);
1204  phash_insert(handle->hash_edges, (PHashLink *)e2);
1205  phash_insert(handle->hash_edges, (PHashLink *)e3);
1206 
1207  return f;
1208 }
1209 
1210 static PFace *p_face_add_fill(PChart *chart, PVert *v1, PVert *v2, PVert *v3)
1211 {
1212  PFace *f = p_face_add(chart->handle);
1213  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
1214 
1215  e1->vert = v1;
1216  e2->vert = v2;
1217  e3->vert = v3;
1218 
1219  e1->orig_uv = e2->orig_uv = e3->orig_uv = NULL;
1220 
1221  f->nextlink = chart->faces;
1222  chart->faces = f;
1223  e1->nextlink = chart->edges;
1224  chart->edges = e1;
1225  e2->nextlink = chart->edges;
1226  chart->edges = e2;
1227  e3->nextlink = chart->edges;
1228  chart->edges = e3;
1229 
1230  chart->nfaces++;
1231  chart->nedges += 3;
1232 
1233  return f;
1234 }
1235 
1236 static PBool p_quad_split_direction(PHandle *handle, float **co, PHashKey *vkeys)
1237 {
1238  /* Slight bias to prefer one edge over the other in case they are equal, so
1239  * that in symmetric models we choose the same split direction instead of
1240  * depending on floating point errors to decide. */
1241  float bias = 1.0f + 1e-6f;
1242  float fac = len_v3v3(co[0], co[2]) * bias - len_v3v3(co[1], co[3]);
1243  PBool dir = (fac <= 0.0f);
1244 
1245  /* The face exists check is there because of a special case:
1246  * when two quads share three vertices, they can each be split into two triangles,
1247  * resulting in two identical triangles. For example in Suzanne's nose. */
1248  if (dir) {
1249  if (p_face_exists(handle, vkeys, 0, 1, 2) || p_face_exists(handle, vkeys, 0, 2, 3)) {
1250  return !dir;
1251  }
1252  }
1253  else {
1254  if (p_face_exists(handle, vkeys, 0, 1, 3) || p_face_exists(handle, vkeys, 1, 2, 3)) {
1255  return !dir;
1256  }
1257  }
1258 
1259  return dir;
1260 }
1261 
1262 /* Construction: boundary filling */
1263 
1264 static void p_chart_boundaries(PChart *chart, int *r_nboundaries, PEdge **r_outer)
1265 {
1266  PEdge *e, *be;
1267  float len, maxlen = -1.0;
1268 
1269  if (r_nboundaries) {
1270  *r_nboundaries = 0;
1271  }
1272  if (r_outer) {
1273  *r_outer = NULL;
1274  }
1275 
1276  for (e = chart->edges; e; e = e->nextlink) {
1277  if (e->pair || (e->flag & PEDGE_DONE)) {
1278  continue;
1279  }
1280 
1281  if (r_nboundaries) {
1282  (*r_nboundaries)++;
1283  }
1284 
1285  len = 0.0f;
1286 
1287  be = e;
1288  do {
1289  be->flag |= PEDGE_DONE;
1290  len += p_edge_length(be);
1291  be = be->next->vert->edge;
1292  } while (be != e);
1293 
1294  if (r_outer && (len > maxlen)) {
1295  *r_outer = e;
1296  maxlen = len;
1297  }
1298  }
1299 
1300  for (e = chart->edges; e; e = e->nextlink) {
1301  e->flag &= ~PEDGE_DONE;
1302  }
1303 }
1304 
1306 {
1307  PEdge *we;
1308  PVert *v, *v1, *v2;
1309  float angle;
1310  int n = 0;
1311 
1312  v = e->vert;
1313 
1314  /* concave angle check -- could be better */
1315  angle = M_PI;
1316 
1317  we = v->edge;
1318  do {
1319  v1 = we->next->vert;
1320  v2 = we->next->next->vert;
1321  angle -= p_vec_angle(v1->co, v->co, v2->co);
1322 
1323  we = we->next->next->pair;
1324  n++;
1325  } while (we && (we != v->edge));
1326 
1327  return angle;
1328 }
1329 
1330 static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges)
1331 {
1332  PEdge *e, *e1, *e2;
1333 
1334  PFace *f;
1335  struct Heap *heap = BLI_heap_new();
1336  float angle;
1337 
1338  e = be;
1339  do {
1341  e->u.heaplink = BLI_heap_insert(heap, angle, e);
1342 
1344  } while (e != be);
1345 
1346  if (nedges == 2) {
1347  /* no real boundary, but an isolated seam */
1348  e = be->next->vert->edge;
1349  e->pair = be;
1350  be->pair = e;
1351 
1352  BLI_heap_remove(heap, e->u.heaplink);
1353  BLI_heap_remove(heap, be->u.heaplink);
1354  }
1355  else {
1356  while (nedges > 2) {
1357  PEdge *ne, *ne1, *ne2;
1358 
1359  e = (PEdge *)BLI_heap_pop_min(heap);
1360 
1361  e1 = p_boundary_edge_prev(e);
1362  e2 = p_boundary_edge_next(e);
1363 
1364  BLI_heap_remove(heap, e1->u.heaplink);
1365  BLI_heap_remove(heap, e2->u.heaplink);
1366  e->u.heaplink = e1->u.heaplink = e2->u.heaplink = NULL;
1367 
1368  e->flag |= PEDGE_FILLED;
1369  e1->flag |= PEDGE_FILLED;
1370 
1371  f = p_face_add_fill(chart, e->vert, e1->vert, e2->vert);
1372  f->flag |= PFACE_FILLED;
1373 
1374  ne = f->edge->next->next;
1375  ne1 = f->edge;
1376  ne2 = f->edge->next;
1377 
1378  ne->flag = ne1->flag = ne2->flag = PEDGE_FILLED;
1379 
1380  e->pair = ne;
1381  ne->pair = e;
1382  e1->pair = ne1;
1383  ne1->pair = e1;
1384 
1385  ne->vert = e2->vert;
1386  ne1->vert = e->vert;
1387  ne2->vert = e1->vert;
1388 
1389  if (nedges == 3) {
1390  e2->pair = ne2;
1391  ne2->pair = e2;
1392  }
1393  else {
1394  ne2->vert->edge = ne2;
1395 
1396  ne2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(ne2), ne2);
1397  e2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(e2), e2);
1398  }
1399 
1400  nedges--;
1401  }
1402  }
1403 
1404  BLI_heap_free(heap, NULL);
1405 }
1406 
1407 static void p_chart_fill_boundaries(PChart *chart, PEdge *outer)
1408 {
1409  PEdge *e, *be; /* *enext - as yet unused */
1410  int nedges;
1411 
1412  for (e = chart->edges; e; e = e->nextlink) {
1413  /* enext = e->nextlink; - as yet unused */
1414 
1415  if (e->pair || (e->flag & PEDGE_FILLED)) {
1416  continue;
1417  }
1418 
1419  nedges = 0;
1420  be = e;
1421  do {
1422  be->flag |= PEDGE_FILLED;
1423  be = be->next->vert->edge;
1424  nedges++;
1425  } while (be != e);
1426 
1427  if (e != outer) {
1428  p_chart_fill_boundary(chart, e, nedges);
1429  }
1430  }
1431 }
1432 
1433 #if 0
1434 /* Polygon kernel for inserting uv's non overlapping */
1435 
1436 static int p_polygon_point_in(const float cp1[2], const float cp2[2], const float p[2])
1437 {
1438  if ((cp1[0] == p[0]) && (cp1[1] == p[1])) {
1439  return 2;
1440  }
1441  else if ((cp2[0] == p[0]) && (cp2[1] == p[1])) {
1442  return 3;
1443  }
1444  else {
1445  return (p_area_signed(cp1, cp2, p) >= 0.0f);
1446  }
1447 }
1448 
1449 static void p_polygon_kernel_clip(float (*oldpoints)[2],
1450  int noldpoints,
1451  float (*newpoints)[2],
1452  int *r_nnewpoints,
1453  const float cp1[2],
1454  const float cp2[2])
1455 {
1456  float *p2, *p1, isect[2];
1457  int i, p2in, p1in;
1458 
1459  p1 = oldpoints[noldpoints - 1];
1460  p1in = p_polygon_point_in(cp1, cp2, p1);
1461  *r_nnewpoints = 0;
1462 
1463  for (i = 0; i < noldpoints; i++) {
1464  p2 = oldpoints[i];
1465  p2in = p_polygon_point_in(cp1, cp2, p2);
1466 
1467  if ((p2in >= 2) || (p1in && p2in)) {
1468  newpoints[*r_nnewpoints][0] = p2[0];
1469  newpoints[*r_nnewpoints][1] = p2[1];
1470  (*r_nnewpoints)++;
1471  }
1472  else if (p1in && !p2in) {
1473  if (p1in != 3) {
1474  p_intersect_line_2d(p1, p2, cp1, cp2, isect);
1475  newpoints[*r_nnewpoints][0] = isect[0];
1476  newpoints[*r_nnewpoints][1] = isect[1];
1477  (*r_nnewpoints)++;
1478  }
1479  }
1480  else if (!p1in && p2in) {
1481  p_intersect_line_2d(p1, p2, cp1, cp2, isect);
1482  newpoints[*r_nnewpoints][0] = isect[0];
1483  newpoints[*r_nnewpoints][1] = isect[1];
1484  (*r_nnewpoints)++;
1485 
1486  newpoints[*r_nnewpoints][0] = p2[0];
1487  newpoints[*r_nnewpoints][1] = p2[1];
1488  (*r_nnewpoints)++;
1489  }
1490 
1491  p1in = p2in;
1492  p1 = p2;
1493  }
1494 }
1495 
1496 static void p_polygon_kernel_center(float (*points)[2], int npoints, float *center)
1497 {
1498  int i, size, nnewpoints = npoints;
1499  float(*oldpoints)[2], (*newpoints)[2], *p1, *p2;
1500 
1501  size = npoints * 3;
1502  oldpoints = MEM_mallocN(sizeof(float[2]) * size, "PPolygonOldPoints");
1503  newpoints = MEM_mallocN(sizeof(float[2]) * size, "PPolygonNewPoints");
1504 
1505  memcpy(oldpoints, points, sizeof(float[2]) * npoints);
1506 
1507  for (i = 0; i < npoints; i++) {
1508  p1 = points[i];
1509  p2 = points[(i + 1) % npoints];
1510  p_polygon_kernel_clip(oldpoints, nnewpoints, newpoints, &nnewpoints, p1, p2);
1511 
1512  if (nnewpoints == 0) {
1513  /* degenerate case, use center of original polygon */
1514  memcpy(oldpoints, points, sizeof(float[2]) * npoints);
1515  nnewpoints = npoints;
1516  break;
1517  }
1518  else if (nnewpoints == 1) {
1519  /* degenerate case, use remaining point */
1520  center[0] = newpoints[0][0];
1521  center[1] = newpoints[0][1];
1522 
1523  MEM_freeN(oldpoints);
1524  MEM_freeN(newpoints);
1525 
1526  return;
1527  }
1528 
1529  if (nnewpoints * 2 > size) {
1530  size *= 2;
1531  MEM_freeN(oldpoints);
1532  oldpoints = MEM_mallocN(sizeof(float[2]) * size, "oldpoints");
1533  memcpy(oldpoints, newpoints, sizeof(float[2]) * nnewpoints);
1534  MEM_freeN(newpoints);
1535  newpoints = MEM_mallocN(sizeof(float[2]) * size, "newpoints");
1536  }
1537  else {
1538  float(*sw_points)[2] = oldpoints;
1539  oldpoints = newpoints;
1540  newpoints = sw_points;
1541  }
1542  }
1543 
1544  center[0] = center[1] = 0.0f;
1545 
1546  for (i = 0; i < nnewpoints; i++) {
1547  center[0] += oldpoints[i][0];
1548  center[1] += oldpoints[i][1];
1549  }
1550 
1551  center[0] /= nnewpoints;
1552  center[1] /= nnewpoints;
1553 
1554  MEM_freeN(oldpoints);
1555  MEM_freeN(newpoints);
1556 }
1557 #endif
1558 
1559 #if 0
1560 /* Edge Collapser */
1561 
1562 int NCOLLAPSE = 1;
1563 int NCOLLAPSEX = 0;
1564 
1565 static float p_vert_cotan(const float v1[3], const float v2[3], const float v3[3])
1566 {
1567  float a[3], b[3], c[3], clen;
1568 
1569  sub_v3_v3v3(a, v2, v1);
1570  sub_v3_v3v3(b, v3, v1);
1571  cross_v3_v3v3(c, a, b);
1572 
1573  clen = len_v3(c);
1574 
1575  if (clen == 0.0f) {
1576  return 0.0f;
1577  }
1578 
1579  return dot_v3v3(a, b) / clen;
1580 }
1581 
1582 static PBool p_vert_flipped_wheel_triangle(PVert *v)
1583 {
1584  PEdge *e = v->edge;
1585 
1586  do {
1587  if (p_face_uv_area_signed(e->face) < 0.0f) {
1588  return P_TRUE;
1589  }
1590 
1591  e = p_wheel_edge_next(e);
1592  } while (e && (e != v->edge));
1593 
1594  return P_FALSE;
1595 }
1596 
1597 static PBool p_vert_map_harmonic_weights(PVert *v)
1598 {
1599  float weightsum, positionsum[2], olduv[2];
1600 
1601  weightsum = 0.0f;
1602  positionsum[0] = positionsum[1] = 0.0f;
1603 
1604  if (p_vert_interior(v)) {
1605  PEdge *e = v->edge;
1606 
1607  do {
1608  float t1, t2, weight;
1609  PVert *v1, *v2;
1610 
1611  v1 = e->next->vert;
1612  v2 = e->next->next->vert;
1613  t1 = p_vert_cotan(v2->co, e->vert->co, v1->co);
1614 
1615  v1 = e->pair->next->vert;
1616  v2 = e->pair->next->next->vert;
1617  t2 = p_vert_cotan(v2->co, e->pair->vert->co, v1->co);
1618 
1619  weight = 0.5f * (t1 + t2);
1620  weightsum += weight;
1621  positionsum[0] += weight * e->pair->vert->uv[0];
1622  positionsum[1] += weight * e->pair->vert->uv[1];
1623 
1624  e = p_wheel_edge_next(e);
1625  } while (e && (e != v->edge));
1626  }
1627  else {
1628  PEdge *e = v->edge;
1629 
1630  do {
1631  float t1, t2;
1632  PVert *v1, *v2;
1633 
1634  v2 = e->next->vert;
1635  v1 = e->next->next->vert;
1636 
1637  t1 = p_vert_cotan(v1->co, v->co, v2->co);
1638  t2 = p_vert_cotan(v2->co, v->co, v1->co);
1639 
1640  weightsum += t1 + t2;
1641  positionsum[0] += (v2->uv[1] - v1->uv[1]) + (t1 * v2->uv[0] + t2 * v1->uv[0]);
1642  positionsum[1] += (v1->uv[0] - v2->uv[0]) + (t1 * v2->uv[1] + t2 * v1->uv[1]);
1643 
1644  e = p_wheel_edge_next(e);
1645  } while (e && (e != v->edge));
1646  }
1647 
1648  if (weightsum != 0.0f) {
1649  weightsum = 1.0f / weightsum;
1650  positionsum[0] *= weightsum;
1651  positionsum[1] *= weightsum;
1652  }
1653 
1654  olduv[0] = v->uv[0];
1655  olduv[1] = v->uv[1];
1656  v->uv[0] = positionsum[0];
1657  v->uv[1] = positionsum[1];
1658 
1659  if (p_vert_flipped_wheel_triangle(v)) {
1660  v->uv[0] = olduv[0];
1661  v->uv[1] = olduv[1];
1662 
1663  return P_FALSE;
1664  }
1665 
1666  return P_TRUE;
1667 }
1668 
1669 static void p_vert_harmonic_insert(PVert *v)
1670 {
1671  PEdge *e;
1672 
1673  if (!p_vert_map_harmonic_weights(v)) {
1674  /* do polygon kernel center insertion: this is quite slow, but should
1675  * only be needed for 0.01 % of verts or so, when insert with harmonic
1676  * weights fails */
1677 
1678  int npoints = 0, i;
1679  float(*points)[2];
1680 
1681  e = v->edge;
1682  do {
1683  npoints++;
1684  e = p_wheel_edge_next(e);
1685  } while (e && (e != v->edge));
1686 
1687  if (e == NULL) {
1688  npoints++;
1689  }
1690 
1691  points = MEM_mallocN(sizeof(float[2]) * npoints, "PHarmonicPoints");
1692 
1693  e = v->edge;
1694  i = 0;
1695  do {
1696  PEdge *nexte = p_wheel_edge_next(e);
1697 
1698  points[i][0] = e->next->vert->uv[0];
1699  points[i][1] = e->next->vert->uv[1];
1700 
1701  if (nexte == NULL) {
1702  i++;
1703  points[i][0] = e->next->next->vert->uv[0];
1704  points[i][1] = e->next->next->vert->uv[1];
1705  break;
1706  }
1707 
1708  e = nexte;
1709  i++;
1710  } while (e != v->edge);
1711 
1712  p_polygon_kernel_center(points, npoints, v->uv);
1713 
1714  MEM_freeN(points);
1715  }
1716 
1717  e = v->edge;
1718  do {
1719  if (!(e->next->vert->flag & PVERT_PIN)) {
1720  p_vert_map_harmonic_weights(e->next->vert);
1721  }
1722  e = p_wheel_edge_next(e);
1723  } while (e && (e != v->edge));
1724 
1725  p_vert_map_harmonic_weights(v);
1726 }
1727 
1728 static void p_vert_fix_edge_pointer(PVert *v)
1729 {
1730  PEdge *start = v->edge;
1731 
1732  /* set v->edge pointer to the edge with no pair, if there is one */
1733  while (v->edge->pair) {
1734  v->edge = p_wheel_edge_prev(v->edge);
1735 
1736  if (v->edge == start) {
1737  break;
1738  }
1739  }
1740 }
1741 
1742 static void p_collapsing_verts(PEdge *edge, PEdge *pair, PVert **r_newv, PVert **r_keepv)
1743 {
1744  /* the two vertices that are involved in the collapse */
1745  if (edge) {
1746  *r_newv = edge->vert;
1747  *r_keepv = edge->next->vert;
1748  }
1749  else {
1750  *r_newv = pair->next->vert;
1751  *r_keepv = pair->vert;
1752  }
1753 }
1754 
1755 static void p_collapse_edge(PEdge *edge, PEdge *pair)
1756 {
1757  PVert *oldv, *keepv;
1758  PEdge *e;
1759 
1760  p_collapsing_verts(edge, pair, &oldv, &keepv);
1761 
1762  /* change e->vert pointers from old vertex to the target vertex */
1763  e = oldv->edge;
1764  do {
1765  if ((e != edge) && !(pair && pair->next == e)) {
1766  e->vert = keepv;
1767  }
1768 
1769  e = p_wheel_edge_next(e);
1770  } while (e && (e != oldv->edge));
1771 
1772  /* set keepv->edge pointer */
1773  if ((edge && (keepv->edge == edge->next)) || (keepv->edge == pair)) {
1774  if (edge && edge->next->pair) {
1775  keepv->edge = edge->next->pair->next;
1776  }
1777  else if (pair && pair->next->next->pair) {
1778  keepv->edge = pair->next->next->pair;
1779  }
1780  else if (edge && edge->next->next->pair) {
1781  keepv->edge = edge->next->next->pair;
1782  }
1783  else {
1784  keepv->edge = pair->next->pair->next;
1785  }
1786  }
1787 
1788  /* update pairs and v->edge pointers */
1789  if (edge) {
1790  PEdge *e1 = edge->next, *e2 = e1->next;
1791 
1792  if (e1->pair) {
1793  e1->pair->pair = e2->pair;
1794  }
1795 
1796  if (e2->pair) {
1797  e2->pair->pair = e1->pair;
1798  e2->vert->edge = p_wheel_edge_prev(e2);
1799  }
1800  else {
1801  e2->vert->edge = p_wheel_edge_next(e2);
1802  }
1803 
1804  p_vert_fix_edge_pointer(e2->vert);
1805  }
1806 
1807  if (pair) {
1808  PEdge *e1 = pair->next, *e2 = e1->next;
1809 
1810  if (e1->pair) {
1811  e1->pair->pair = e2->pair;
1812  }
1813 
1814  if (e2->pair) {
1815  e2->pair->pair = e1->pair;
1816  e2->vert->edge = p_wheel_edge_prev(e2);
1817  }
1818  else {
1819  e2->vert->edge = p_wheel_edge_next(e2);
1820  }
1821 
1822  p_vert_fix_edge_pointer(e2->vert);
1823  }
1824 
1825  p_vert_fix_edge_pointer(keepv);
1826 
1827  /* mark for move to collapsed list later */
1828  oldv->flag |= PVERT_COLLAPSE;
1829 
1830  if (edge) {
1831  PFace *f = edge->face;
1832  PEdge *e1 = edge->next, *e2 = e1->next;
1833 
1834  f->flag |= PFACE_COLLAPSE;
1835  edge->flag |= PEDGE_COLLAPSE;
1836  e1->flag |= PEDGE_COLLAPSE;
1837  e2->flag |= PEDGE_COLLAPSE;
1838  }
1839 
1840  if (pair) {
1841  PFace *f = pair->face;
1842  PEdge *e1 = pair->next, *e2 = e1->next;
1843 
1844  f->flag |= PFACE_COLLAPSE;
1845  pair->flag |= PEDGE_COLLAPSE;
1846  e1->flag |= PEDGE_COLLAPSE;
1847  e2->flag |= PEDGE_COLLAPSE;
1848  }
1849 }
1850 
1851 static void p_split_vertex(PEdge *edge, PEdge *pair)
1852 {
1853  PVert *newv, *keepv;
1854  PEdge *e;
1855 
1856  p_collapsing_verts(edge, pair, &newv, &keepv);
1857 
1858  /* update edge pairs */
1859  if (edge) {
1860  PEdge *e1 = edge->next, *e2 = e1->next;
1861 
1862  if (e1->pair) {
1863  e1->pair->pair = e1;
1864  }
1865  if (e2->pair) {
1866  e2->pair->pair = e2;
1867  }
1868 
1869  e2->vert->edge = e2;
1870  p_vert_fix_edge_pointer(e2->vert);
1871  keepv->edge = e1;
1872  }
1873 
1874  if (pair) {
1875  PEdge *e1 = pair->next, *e2 = e1->next;
1876 
1877  if (e1->pair) {
1878  e1->pair->pair = e1;
1879  }
1880  if (e2->pair) {
1881  e2->pair->pair = e2;
1882  }
1883 
1884  e2->vert->edge = e2;
1885  p_vert_fix_edge_pointer(e2->vert);
1886  keepv->edge = pair;
1887  }
1888 
1889  p_vert_fix_edge_pointer(keepv);
1890 
1891  /* set e->vert pointers to restored vertex */
1892  e = newv->edge;
1893  do {
1894  e->vert = newv;
1895  e = p_wheel_edge_next(e);
1896  } while (e && (e != newv->edge));
1897 }
1898 
1899 static PBool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair)
1900 {
1901  PVert *oldv, *keepv;
1902 
1903  p_collapsing_verts(edge, pair, &oldv, &keepv);
1904 
1905  /* boundary edges */
1906  if (!edge || !pair) {
1907  /* avoid collapsing chart into an edge */
1908  if (edge && !edge->next->pair && !edge->next->next->pair) {
1909  return P_FALSE;
1910  }
1911  else if (pair && !pair->next->pair && !pair->next->next->pair) {
1912  return P_FALSE;
1913  }
1914  }
1915  /* avoid merging two boundaries (oldv and keepv are on the 'other side' of
1916  * the chart) */
1917  else if (!p_vert_interior(oldv) && !p_vert_interior(keepv)) {
1918  return P_FALSE;
1919  }
1920 
1921  return P_TRUE;
1922 }
1923 
1924 static PBool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float *vnew)
1925 {
1926  float nold[3], nnew[3], sub1[3], sub2[3];
1927 
1928  sub_v3_v3v3(sub1, vold, v1);
1929  sub_v3_v3v3(sub2, vold, v2);
1930  cross_v3_v3v3(nold, sub1, sub2);
1931 
1932  sub_v3_v3v3(sub1, vnew, v1);
1933  sub_v3_v3v3(sub2, vnew, v2);
1934  cross_v3_v3v3(nnew, sub1, sub2);
1935 
1936  return (dot_v3v3(nold, nnew) <= 0.0f);
1937 }
1938 
1939 static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
1940 {
1941  PVert *oldv, *keepv;
1942  PEdge *e;
1943  float angulardefect, angle;
1944 
1945  p_collapsing_verts(edge, pair, &oldv, &keepv);
1946 
1947  angulardefect = 2 * M_PI;
1948 
1949  e = oldv->edge;
1950  do {
1951  float a[3], b[3], minangle, maxangle;
1952  PEdge *e1 = e->next, *e2 = e1->next;
1953  PVert *v1 = e1->vert, *v2 = e2->vert;
1954  int i;
1955 
1956  angle = p_vec_angle(v1->co, oldv->co, v2->co);
1957  angulardefect -= angle;
1958 
1959  /* skip collapsing faces */
1960  if (v1 == keepv || v2 == keepv) {
1961  e = p_wheel_edge_next(e);
1962  continue;
1963  }
1964 
1965  if (p_collapse_normal_flipped(v1->co, v2->co, oldv->co, keepv->co)) {
1966  return P_FALSE;
1967  }
1968 
1969  a[0] = angle;
1970  a[1] = p_vec_angle(v2->co, v1->co, oldv->co);
1971  a[2] = M_PI - a[0] - a[1];
1972 
1973  b[0] = p_vec_angle(v1->co, keepv->co, v2->co);
1974  b[1] = p_vec_angle(v2->co, v1->co, keepv->co);
1975  b[2] = M_PI - b[0] - b[1];
1976 
1977  /* ABF criterion 1: avoid sharp and obtuse angles. */
1978  minangle = 15.0f * M_PI / 180.0f;
1979  maxangle = M_PI - minangle;
1980 
1981  for (i = 0; i < 3; i++) {
1982  if ((b[i] < a[i]) && (b[i] < minangle)) {
1983  return P_FALSE;
1984  }
1985  else if ((b[i] > a[i]) && (b[i] > maxangle)) {
1986  return P_FALSE;
1987  }
1988  }
1989 
1990  e = p_wheel_edge_next(e);
1991  } while (e && (e != oldv->edge));
1992 
1993  if (p_vert_interior(oldv)) {
1994  /* HLSCM criterion: angular defect smaller than threshold. */
1995  if (fabsf(angulardefect) > (float)(M_PI * 30.0 / 180.0)) {
1996  return P_FALSE;
1997  }
1998  }
1999  else {
2000  PVert *v1 = p_boundary_edge_next(oldv->edge)->vert;
2001  PVert *v2 = p_boundary_edge_prev(oldv->edge)->vert;
2002 
2003  /* ABF++ criterion 2: avoid collapsing verts inwards. */
2004  if (p_vert_interior(keepv)) {
2005  return P_FALSE;
2006  }
2007 
2008  /* Don't collapse significant boundary changes. */
2009  angle = p_vec_angle(v1->co, oldv->co, v2->co);
2010  if (angle < (M_PI * 160.0 / 180.0)) {
2011  return P_FALSE;
2012  }
2013  }
2014 
2015  return P_TRUE;
2016 }
2017 
2018 static PBool p_collapse_allowed(PEdge *edge, PEdge *pair)
2019 {
2020  PVert *oldv, *keepv;
2021 
2022  p_collapsing_verts(edge, pair, &oldv, &keepv);
2023 
2024  if (oldv->flag & PVERT_PIN) {
2025  return P_FALSE;
2026  }
2027 
2028  return (p_collapse_allowed_topologic(edge, pair) && p_collapse_allowed_geometric(edge, pair));
2029 }
2030 
2031 static float p_collapse_cost(PEdge *edge, PEdge *pair)
2032 {
2033  /* based on volume and boundary optimization from:
2034  * "Fast and Memory Efficient Polygonal Simplification" P. Lindstrom, G. Turk */
2035 
2036  PVert *oldv, *keepv;
2037  PEdge *e;
2038  PFace *oldf1, *oldf2;
2039  float volumecost = 0.0f, areacost = 0.0f, edgevec[3], cost, weight, elen;
2040  float shapecost = 0.0f;
2041  float shapeold = 0.0f, shapenew = 0.0f;
2042  int nshapeold = 0, nshapenew = 0;
2043 
2044  p_collapsing_verts(edge, pair, &oldv, &keepv);
2045  oldf1 = (edge) ? edge->face : NULL;
2046  oldf2 = (pair) ? pair->face : NULL;
2047 
2048  sub_v3_v3v3(edgevec, keepv->co, oldv->co);
2049 
2050  e = oldv->edge;
2051  do {
2052  float a1, a2, a3;
2053  float *co1 = e->next->vert->co;
2054  float *co2 = e->next->next->vert->co;
2055 
2056  if ((e->face != oldf1) && (e->face != oldf2)) {
2057  float tetrav2[3], tetrav3[3];
2058 
2059  /* tetrahedron volume = (1/3!)*|a.(b x c)| */
2060  sub_v3_v3v3(tetrav2, co1, oldv->co);
2061  sub_v3_v3v3(tetrav3, co2, oldv->co);
2062  volumecost += fabsf(volume_tri_tetrahedron_signed_v3(tetrav2, tetrav3, edgevec));
2063 
2064 # if 0
2065  shapecost += dot_v3v3(co1, keepv->co);
2066 
2067  if (p_wheel_edge_next(e) == NULL) {
2068  shapecost += dot_v3v3(co2, keepv->co);
2069  }
2070 # endif
2071 
2072  p_triangle_angles(oldv->co, co1, co2, &a1, &a2, &a3);
2073  a1 = a1 - M_PI / 3.0;
2074  a2 = a2 - M_PI / 3.0;
2075  a3 = a3 - M_PI / 3.0;
2076  shapeold = (a1 * a1 + a2 * a2 + a3 * a3) / ((M_PI / 2) * (M_PI / 2));
2077 
2078  nshapeold++;
2079  }
2080  else {
2081  p_triangle_angles(keepv->co, co1, co2, &a1, &a2, &a3);
2082  a1 = a1 - M_PI / 3.0;
2083  a2 = a2 - M_PI / 3.0;
2084  a3 = a3 - M_PI / 3.0;
2085  shapenew = (a1 * a1 + a2 * a2 + a3 * a3) / ((M_PI / 2) * (M_PI / 2));
2086 
2087  nshapenew++;
2088  }
2089 
2090  e = p_wheel_edge_next(e);
2091  } while (e && (e != oldv->edge));
2092 
2093  if (!p_vert_interior(oldv)) {
2094  PVert *v1 = p_boundary_edge_prev(oldv->edge)->vert;
2095  PVert *v2 = p_boundary_edge_next(oldv->edge)->vert;
2096 
2097  areacost = area_tri_v3(oldv->co, v1->co, v2->co);
2098  }
2099 
2100  elen = len_v3(edgevec);
2101  weight = 1.0f; /* 0.2f */
2102  cost = weight * volumecost * volumecost + elen * elen * areacost * areacost;
2103 # if 0
2104  cost += shapecost;
2105 # else
2106  shapeold /= nshapeold;
2107  shapenew /= nshapenew;
2108  shapecost = (shapeold + 0.00001) / (shapenew + 0.00001);
2109 
2110  cost *= shapecost;
2111 # endif
2112 
2113  return cost;
2114 }
2115 
2116 static void p_collapse_cost_vertex(PVert *vert, float *r_mincost, PEdge **r_mine)
2117 {
2118  PEdge *e, *enext, *pair;
2119 
2120  *r_mine = NULL;
2121  *r_mincost = 0.0f;
2122  e = vert->edge;
2123  do {
2124  if (p_collapse_allowed(e, e->pair)) {
2125  float cost = p_collapse_cost(e, e->pair);
2126 
2127  if ((*r_mine == NULL) || (cost < *r_mincost)) {
2128  *r_mincost = cost;
2129  *r_mine = e;
2130  }
2131  }
2132 
2133  enext = p_wheel_edge_next(e);
2134 
2135  if (enext == NULL) {
2136  /* the other boundary edge, where we only have the pair halfedge */
2137  pair = e->next->next;
2138 
2139  if (p_collapse_allowed(NULL, pair)) {
2140  float cost = p_collapse_cost(NULL, pair);
2141 
2142  if ((*r_mine == NULL) || (cost < *r_mincost)) {
2143  *r_mincost = cost;
2144  *r_mine = pair;
2145  }
2146  }
2147 
2148  break;
2149  }
2150 
2151  e = enext;
2152  } while (e != vert->edge);
2153 }
2154 
2155 static void p_chart_post_collapse_flush(PChart *chart, PEdge *collapsed)
2156 {
2157  /* move to collapsed_ */
2158 
2159  PVert *v, *nextv = NULL, *verts = chart->verts;
2160  PEdge *e, *nexte = NULL, *edges = chart->edges, *laste = NULL;
2161  PFace *f, *nextf = NULL, *faces = chart->faces;
2162 
2163  chart->verts = chart->collapsed_verts = NULL;
2164  chart->edges = chart->collapsed_edges = NULL;
2165  chart->faces = chart->collapsed_faces = NULL;
2166 
2167  chart->nverts = chart->nedges = chart->nfaces = 0;
2168 
2169  for (v = verts; v; v = nextv) {
2170  nextv = v->nextlink;
2171 
2172  if (v->flag & PVERT_COLLAPSE) {
2173  v->nextlink = chart->collapsed_verts;
2174  chart->collapsed_verts = v;
2175  }
2176  else {
2177  v->nextlink = chart->verts;
2178  chart->verts = v;
2179  chart->nverts++;
2180  }
2181  }
2182 
2183  for (e = edges; e; e = nexte) {
2184  nexte = e->nextlink;
2185 
2186  if (!collapsed || !(e->flag & PEDGE_COLLAPSE_EDGE)) {
2187  if (e->flag & PEDGE_COLLAPSE) {
2188  e->nextlink = chart->collapsed_edges;
2189  chart->collapsed_edges = e;
2190  }
2191  else {
2192  e->nextlink = chart->edges;
2193  chart->edges = e;
2194  chart->nedges++;
2195  }
2196  }
2197  }
2198 
2199  /* these are added last so they can be popped of in the right order
2200  * for splitting */
2201  for (e = collapsed; e; e = e->nextlink) {
2202  e->nextlink = e->u.nextcollapse;
2203  laste = e;
2204  }
2205  if (laste) {
2206  laste->nextlink = chart->collapsed_edges;
2207  chart->collapsed_edges = collapsed;
2208  }
2209 
2210  for (f = faces; f; f = nextf) {
2211  nextf = f->nextlink;
2212 
2213  if (f->flag & PFACE_COLLAPSE) {
2214  f->nextlink = chart->collapsed_faces;
2215  chart->collapsed_faces = f;
2216  }
2217  else {
2218  f->nextlink = chart->faces;
2219  chart->faces = f;
2220  chart->nfaces++;
2221  }
2222  }
2223 }
2224 
2225 static void p_chart_post_split_flush(PChart *chart)
2226 {
2227  /* move from collapsed_ */
2228 
2229  PVert *v, *nextv = NULL;
2230  PEdge *e, *nexte = NULL;
2231  PFace *f, *nextf = NULL;
2232 
2233  for (v = chart->collapsed_verts; v; v = nextv) {
2234  nextv = v->nextlink;
2235  v->nextlink = chart->verts;
2236  chart->verts = v;
2237  chart->nverts++;
2238  }
2239 
2240  for (e = chart->collapsed_edges; e; e = nexte) {
2241  nexte = e->nextlink;
2242  e->nextlink = chart->edges;
2243  chart->edges = e;
2244  chart->nedges++;
2245  }
2246 
2247  for (f = chart->collapsed_faces; f; f = nextf) {
2248  nextf = f->nextlink;
2249  f->nextlink = chart->faces;
2250  chart->faces = f;
2251  chart->nfaces++;
2252  }
2253 
2254  chart->collapsed_verts = NULL;
2255  chart->collapsed_edges = NULL;
2256  chart->collapsed_faces = NULL;
2257 }
2258 
2259 static void p_chart_simplify_compute(PChart *chart)
2260 {
2261  /* Computes a list of edge collapses / vertex splits. The collapsed
2262  * simplices go in the chart->collapsed_* lists, The original and
2263  * collapsed may then be view as stacks, where the next collapse/split
2264  * is at the top of the respective lists. */
2265 
2266  Heap *heap = BLI_heap_new();
2267  PVert *v, **wheelverts;
2268  PEdge *collapsededges = NULL, *e;
2269  int nwheelverts, i, ncollapsed = 0;
2270 
2271  wheelverts = MEM_mallocN(sizeof(PVert *) * chart->nverts, "PChartWheelVerts");
2272 
2273  /* insert all potential collapses into heap */
2274  for (v = chart->verts; v; v = v->nextlink) {
2275  float cost;
2276  PEdge *e = NULL;
2277 
2278  p_collapse_cost_vertex(v, &cost, &e);
2279 
2280  if (e) {
2281  v->u.heaplink = BLI_heap_insert(heap, cost, e);
2282  }
2283  else {
2284  v->u.heaplink = NULL;
2285  }
2286  }
2287 
2288  for (e = chart->edges; e; e = e->nextlink) {
2289  e->u.nextcollapse = NULL;
2290  }
2291 
2292  /* pop edge collapse out of heap one by one */
2293  while (!BLI_heap_is_empty(heap)) {
2294  if (ncollapsed == NCOLLAPSE) {
2295  break;
2296  }
2297 
2298  HeapNode *link = BLI_heap_top(heap);
2299  PEdge *edge = (PEdge *)BLI_heap_pop_min(heap), *pair = edge->pair;
2300  PVert *oldv, *keepv;
2301  PEdge *wheele, *nexte;
2302 
2303  /* remember the edges we collapsed */
2304  edge->u.nextcollapse = collapsededges;
2305  collapsededges = edge;
2306 
2307  if (edge->vert->u.heaplink != link) {
2309  edge->next->vert->u.heaplink = NULL;
2310  SWAP(PEdge *, edge, pair);
2311  }
2312  else {
2313  edge->flag |= PEDGE_COLLAPSE_EDGE;
2314  edge->vert->u.heaplink = NULL;
2315  }
2316 
2317  p_collapsing_verts(edge, pair, &oldv, &keepv);
2318 
2319  /* gather all wheel verts and remember them before collapse */
2320  nwheelverts = 0;
2321  wheele = oldv->edge;
2322 
2323  do {
2324  wheelverts[nwheelverts++] = wheele->next->vert;
2325  nexte = p_wheel_edge_next(wheele);
2326 
2327  if (nexte == NULL) {
2328  wheelverts[nwheelverts++] = wheele->next->next->vert;
2329  }
2330 
2331  wheele = nexte;
2332  } while (wheele && (wheele != oldv->edge));
2333 
2334  /* collapse */
2335  p_collapse_edge(edge, pair);
2336 
2337  for (i = 0; i < nwheelverts; i++) {
2338  float cost;
2339  PEdge *collapse = NULL;
2340 
2341  v = wheelverts[i];
2342 
2343  if (v->u.heaplink) {
2344  BLI_heap_remove(heap, v->u.heaplink);
2345  v->u.heaplink = NULL;
2346  }
2347 
2348  p_collapse_cost_vertex(v, &cost, &collapse);
2349 
2350  if (collapse) {
2351  v->u.heaplink = BLI_heap_insert(heap, cost, collapse);
2352  }
2353  }
2354 
2355  ncollapsed++;
2356  }
2357 
2358  MEM_freeN(wheelverts);
2359  BLI_heap_free(heap, NULL);
2360 
2361  p_chart_post_collapse_flush(chart, collapsededges);
2362 }
2363 
2364 static void p_chart_complexify(PChart *chart)
2365 {
2366  PEdge *e, *pair, *edge;
2367  PVert *newv, *keepv;
2368  int x = 0;
2369 
2370  for (e = chart->collapsed_edges; e; e = e->nextlink) {
2371  if (!(e->flag & PEDGE_COLLAPSE_EDGE)) {
2372  break;
2373  }
2374 
2375  edge = e;
2376  pair = e->pair;
2377 
2378  if (edge->flag & PEDGE_COLLAPSE_PAIR) {
2379  SWAP(PEdge *, edge, pair);
2380  }
2381 
2382  p_split_vertex(edge, pair);
2383  p_collapsing_verts(edge, pair, &newv, &keepv);
2384 
2385  if (x >= NCOLLAPSEX) {
2386  newv->uv[0] = keepv->uv[0];
2387  newv->uv[1] = keepv->uv[1];
2388  }
2389  else {
2390  p_vert_harmonic_insert(newv);
2391  x++;
2392  }
2393  }
2394 
2395  p_chart_post_split_flush(chart);
2396 }
2397 
2398 # if 0
2399 static void p_chart_simplify(PChart *chart)
2400 {
2401  /* Not implemented, needs proper reordering in split_flush. */
2402 }
2403 # endif
2404 #endif
2405 
2406 /* ABF */
2407 
2408 #define ABF_MAX_ITER 20
2409 
2410 typedef struct PAbfSystem {
2412  float *alpha, *beta, *sine, *cosine, *weight;
2415  float (*J2dt)[3], *bstar, *dstar;
2418 
2420 {
2421  int i;
2422 
2423  sys->alpha = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFalpha");
2424  sys->beta = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFbeta");
2425  sys->sine = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFsine");
2426  sys->cosine = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFcosine");
2427  sys->weight = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFweight");
2428 
2429  sys->bAlpha = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFbalpha");
2430  sys->bTriangle = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbtriangle");
2431  sys->bInterior = (float *)MEM_mallocN(sizeof(float[2]) * sys->ninterior, "ABFbinterior");
2432 
2433  sys->lambdaTriangle = (float *)MEM_callocN(sizeof(float) * sys->nfaces, "ABFlambdatri");
2434  sys->lambdaPlanar = (float *)MEM_callocN(sizeof(float) * sys->ninterior, "ABFlamdaplane");
2435  sys->lambdaLength = (float *)MEM_mallocN(sizeof(float) * sys->ninterior, "ABFlambdalen");
2436 
2437  sys->J2dt = MEM_mallocN(sizeof(float) * sys->nangles * 3, "ABFj2dt");
2438  sys->bstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbstar");
2439  sys->dstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFdstar");
2440 
2441  for (i = 0; i < sys->ninterior; i++) {
2442  sys->lambdaLength[i] = 1.0;
2443  }
2444 
2445  sys->minangle = 1.0 * M_PI / 180.0;
2446  sys->maxangle = (float)M_PI - sys->minangle;
2447 }
2448 
2450 {
2451  MEM_freeN(sys->alpha);
2452  MEM_freeN(sys->beta);
2453  MEM_freeN(sys->sine);
2454  MEM_freeN(sys->cosine);
2455  MEM_freeN(sys->weight);
2456  MEM_freeN(sys->bAlpha);
2457  MEM_freeN(sys->bTriangle);
2458  MEM_freeN(sys->bInterior);
2459  MEM_freeN(sys->lambdaTriangle);
2460  MEM_freeN(sys->lambdaPlanar);
2461  MEM_freeN(sys->lambdaLength);
2462  MEM_freeN(sys->J2dt);
2463  MEM_freeN(sys->bstar);
2464  MEM_freeN(sys->dstar);
2465 }
2466 
2468 {
2469  int i;
2470  float *sine = sys->sine, *cosine = sys->cosine, *alpha = sys->alpha;
2471 
2472  for (i = 0; i < sys->nangles; i++, sine++, cosine++, alpha++) {
2473  *sine = sinf(*alpha);
2474  *cosine = cosf(*alpha);
2475  }
2476 }
2477 
2478 static float p_abf_compute_sin_product(PAbfSystem *sys, PVert *v, int aid)
2479 {
2480  PEdge *e, *e1, *e2;
2481  float sin1, sin2;
2482 
2483  sin1 = sin2 = 1.0;
2484 
2485  e = v->edge;
2486  do {
2487  e1 = e->next;
2488  e2 = e->next->next;
2489 
2490  if (aid == e1->u.id) {
2491  /* we are computing a derivative for this angle,
2492  * so we use cos and drop the other part */
2493  sin1 *= sys->cosine[e1->u.id];
2494  sin2 = 0.0;
2495  }
2496  else {
2497  sin1 *= sys->sine[e1->u.id];
2498  }
2499 
2500  if (aid == e2->u.id) {
2501  /* see above */
2502  sin1 = 0.0;
2503  sin2 *= sys->cosine[e2->u.id];
2504  }
2505  else {
2506  sin2 *= sys->sine[e2->u.id];
2507  }
2508 
2509  e = e->next->next->pair;
2510  } while (e && (e != v->edge));
2511 
2512  return (sin1 - sin2);
2513 }
2514 
2516 {
2517  PVert *v = e->vert, *v1 = e->next->vert, *v2 = e->next->next->vert;
2518  float deriv;
2519 
2520  deriv = (sys->alpha[e->u.id] - sys->beta[e->u.id]) * sys->weight[e->u.id];
2521  deriv += sys->lambdaTriangle[f->u.id];
2522 
2523  if (v->flag & PVERT_INTERIOR) {
2524  deriv += sys->lambdaPlanar[v->u.id];
2525  }
2526 
2527  if (v1->flag & PVERT_INTERIOR) {
2528  float product = p_abf_compute_sin_product(sys, v1, e->u.id);
2529  deriv += sys->lambdaLength[v1->u.id] * product;
2530  }
2531 
2532  if (v2->flag & PVERT_INTERIOR) {
2533  float product = p_abf_compute_sin_product(sys, v2, e->u.id);
2534  deriv += sys->lambdaLength[v2->u.id] * product;
2535  }
2536 
2537  return deriv;
2538 }
2539 
2540 static float p_abf_compute_gradient(PAbfSystem *sys, PChart *chart)
2541 {
2542  PFace *f;
2543  PEdge *e;
2544  PVert *v;
2545  float norm = 0.0;
2546 
2547  for (f = chart->faces; f; f = f->nextlink) {
2548  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
2549  float gtriangle, galpha1, galpha2, galpha3;
2550 
2551  galpha1 = p_abf_compute_grad_alpha(sys, f, e1);
2552  galpha2 = p_abf_compute_grad_alpha(sys, f, e2);
2553  galpha3 = p_abf_compute_grad_alpha(sys, f, e3);
2554 
2555  sys->bAlpha[e1->u.id] = -galpha1;
2556  sys->bAlpha[e2->u.id] = -galpha2;
2557  sys->bAlpha[e3->u.id] = -galpha3;
2558 
2559  norm += galpha1 * galpha1 + galpha2 * galpha2 + galpha3 * galpha3;
2560 
2561  gtriangle = sys->alpha[e1->u.id] + sys->alpha[e2->u.id] + sys->alpha[e3->u.id] - (float)M_PI;
2562  sys->bTriangle[f->u.id] = -gtriangle;
2563  norm += gtriangle * gtriangle;
2564  }
2565 
2566  for (v = chart->verts; v; v = v->nextlink) {
2567  if (v->flag & PVERT_INTERIOR) {
2568  float gplanar = -2 * M_PI, glength;
2569 
2570  e = v->edge;
2571  do {
2572  gplanar += sys->alpha[e->u.id];
2573  e = e->next->next->pair;
2574  } while (e && (e != v->edge));
2575 
2576  sys->bInterior[v->u.id] = -gplanar;
2577  norm += gplanar * gplanar;
2578 
2579  glength = p_abf_compute_sin_product(sys, v, -1);
2580  sys->bInterior[sys->ninterior + v->u.id] = -glength;
2581  norm += glength * glength;
2582  }
2583  }
2584 
2585  return norm;
2586 }
2587 
2589 {
2590  PFace *f;
2591  PEdge *e;
2592  int i, j, ninterior = sys->ninterior, nvar = 2 * sys->ninterior;
2593  PBool success;
2595 
2596  context = EIG_linear_solver_new(0, nvar, 1);
2597 
2598  for (i = 0; i < nvar; i++) {
2600  }
2601 
2602  for (f = chart->faces; f; f = f->nextlink) {
2603  float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3];
2604  float row1[6], row2[6], row3[6];
2605  int vid[6];
2606  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
2607  PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
2608 
2609  wi1 = 1.0f / sys->weight[e1->u.id];
2610  wi2 = 1.0f / sys->weight[e2->u.id];
2611  wi3 = 1.0f / sys->weight[e3->u.id];
2612 
2613  /* bstar1 = (J1*dInv*bAlpha - bTriangle) */
2614  b = sys->bAlpha[e1->u.id] * wi1;
2615  b += sys->bAlpha[e2->u.id] * wi2;
2616  b += sys->bAlpha[e3->u.id] * wi3;
2617  b -= sys->bTriangle[f->u.id];
2618 
2619  /* si = J1*d*J1t */
2620  si = 1.0f / (wi1 + wi2 + wi3);
2621 
2622  /* J1t*si*bstar1 - bAlpha */
2623  beta[0] = b * si - sys->bAlpha[e1->u.id];
2624  beta[1] = b * si - sys->bAlpha[e2->u.id];
2625  beta[2] = b * si - sys->bAlpha[e3->u.id];
2626 
2627  /* use this later for computing other lambda's */
2628  sys->bstar[f->u.id] = b;
2629  sys->dstar[f->u.id] = si;
2630 
2631  /* set matrix */
2632  W[0][0] = si - sys->weight[e1->u.id];
2633  W[0][1] = si;
2634  W[0][2] = si;
2635  W[1][0] = si;
2636  W[1][1] = si - sys->weight[e2->u.id];
2637  W[1][2] = si;
2638  W[2][0] = si;
2639  W[2][1] = si;
2640  W[2][2] = si - sys->weight[e3->u.id];
2641 
2642  vid[0] = vid[1] = vid[2] = vid[3] = vid[4] = vid[5] = -1;
2643 
2644  if (v1->flag & PVERT_INTERIOR) {
2645  vid[0] = v1->u.id;
2646  vid[3] = ninterior + v1->u.id;
2647 
2648  sys->J2dt[e1->u.id][0] = j2[0][0] = 1.0f * wi1;
2649  sys->J2dt[e2->u.id][0] = j2[1][0] = p_abf_compute_sin_product(sys, v1, e2->u.id) * wi2;
2650  sys->J2dt[e3->u.id][0] = j2[2][0] = p_abf_compute_sin_product(sys, v1, e3->u.id) * wi3;
2651 
2652  EIG_linear_solver_right_hand_side_add(context, 0, v1->u.id, j2[0][0] * beta[0]);
2654  context, 0, ninterior + v1->u.id, j2[1][0] * beta[1] + j2[2][0] * beta[2]);
2655 
2656  row1[0] = j2[0][0] * W[0][0];
2657  row2[0] = j2[0][0] * W[1][0];
2658  row3[0] = j2[0][0] * W[2][0];
2659 
2660  row1[3] = j2[1][0] * W[0][1] + j2[2][0] * W[0][2];
2661  row2[3] = j2[1][0] * W[1][1] + j2[2][0] * W[1][2];
2662  row3[3] = j2[1][0] * W[2][1] + j2[2][0] * W[2][2];
2663  }
2664 
2665  if (v2->flag & PVERT_INTERIOR) {
2666  vid[1] = v2->u.id;
2667  vid[4] = ninterior + v2->u.id;
2668 
2669  sys->J2dt[e1->u.id][1] = j2[0][1] = p_abf_compute_sin_product(sys, v2, e1->u.id) * wi1;
2670  sys->J2dt[e2->u.id][1] = j2[1][1] = 1.0f * wi2;
2671  sys->J2dt[e3->u.id][1] = j2[2][1] = p_abf_compute_sin_product(sys, v2, e3->u.id) * wi3;
2672 
2673  EIG_linear_solver_right_hand_side_add(context, 0, v2->u.id, j2[1][1] * beta[1]);
2675  context, 0, ninterior + v2->u.id, j2[0][1] * beta[0] + j2[2][1] * beta[2]);
2676 
2677  row1[1] = j2[1][1] * W[0][1];
2678  row2[1] = j2[1][1] * W[1][1];
2679  row3[1] = j2[1][1] * W[2][1];
2680 
2681  row1[4] = j2[0][1] * W[0][0] + j2[2][1] * W[0][2];
2682  row2[4] = j2[0][1] * W[1][0] + j2[2][1] * W[1][2];
2683  row3[4] = j2[0][1] * W[2][0] + j2[2][1] * W[2][2];
2684  }
2685 
2686  if (v3->flag & PVERT_INTERIOR) {
2687  vid[2] = v3->u.id;
2688  vid[5] = ninterior + v3->u.id;
2689 
2690  sys->J2dt[e1->u.id][2] = j2[0][2] = p_abf_compute_sin_product(sys, v3, e1->u.id) * wi1;
2691  sys->J2dt[e2->u.id][2] = j2[1][2] = p_abf_compute_sin_product(sys, v3, e2->u.id) * wi2;
2692  sys->J2dt[e3->u.id][2] = j2[2][2] = 1.0f * wi3;
2693 
2694  EIG_linear_solver_right_hand_side_add(context, 0, v3->u.id, j2[2][2] * beta[2]);
2696  context, 0, ninterior + v3->u.id, j2[0][2] * beta[0] + j2[1][2] * beta[1]);
2697 
2698  row1[2] = j2[2][2] * W[0][2];
2699  row2[2] = j2[2][2] * W[1][2];
2700  row3[2] = j2[2][2] * W[2][2];
2701 
2702  row1[5] = j2[0][2] * W[0][0] + j2[1][2] * W[0][1];
2703  row2[5] = j2[0][2] * W[1][0] + j2[1][2] * W[1][1];
2704  row3[5] = j2[0][2] * W[2][0] + j2[1][2] * W[2][1];
2705  }
2706 
2707  for (i = 0; i < 3; i++) {
2708  int r = vid[i];
2709 
2710  if (r == -1) {
2711  continue;
2712  }
2713 
2714  for (j = 0; j < 6; j++) {
2715  int c = vid[j];
2716 
2717  if (c == -1) {
2718  continue;
2719  }
2720 
2721  if (i == 0) {
2722  EIG_linear_solver_matrix_add(context, r, c, j2[0][i] * row1[j]);
2723  }
2724  else {
2725  EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[0][i] * row1[j]);
2726  }
2727 
2728  if (i == 1) {
2729  EIG_linear_solver_matrix_add(context, r, c, j2[1][i] * row2[j]);
2730  }
2731  else {
2732  EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[1][i] * row2[j]);
2733  }
2734 
2735  if (i == 2) {
2736  EIG_linear_solver_matrix_add(context, r, c, j2[2][i] * row3[j]);
2737  }
2738  else {
2739  EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[2][i] * row3[j]);
2740  }
2741  }
2742  }
2743  }
2744 
2745  success = EIG_linear_solver_solve(context);
2746 
2747  if (success) {
2748  for (f = chart->faces; f; f = f->nextlink) {
2749  float dlambda1, pre[3], dalpha;
2750  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
2751  PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
2752 
2753  pre[0] = pre[1] = pre[2] = 0.0;
2754 
2755  if (v1->flag & PVERT_INTERIOR) {
2756  float x = EIG_linear_solver_variable_get(context, 0, v1->u.id);
2757  float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v1->u.id);
2758  pre[0] += sys->J2dt[e1->u.id][0] * x;
2759  pre[1] += sys->J2dt[e2->u.id][0] * x2;
2760  pre[2] += sys->J2dt[e3->u.id][0] * x2;
2761  }
2762 
2763  if (v2->flag & PVERT_INTERIOR) {
2764  float x = EIG_linear_solver_variable_get(context, 0, v2->u.id);
2765  float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v2->u.id);
2766  pre[0] += sys->J2dt[e1->u.id][1] * x2;
2767  pre[1] += sys->J2dt[e2->u.id][1] * x;
2768  pre[2] += sys->J2dt[e3->u.id][1] * x2;
2769  }
2770 
2771  if (v3->flag & PVERT_INTERIOR) {
2772  float x = EIG_linear_solver_variable_get(context, 0, v3->u.id);
2773  float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v3->u.id);
2774  pre[0] += sys->J2dt[e1->u.id][2] * x2;
2775  pre[1] += sys->J2dt[e2->u.id][2] * x2;
2776  pre[2] += sys->J2dt[e3->u.id][2] * x;
2777  }
2778 
2779  dlambda1 = pre[0] + pre[1] + pre[2];
2780  dlambda1 = sys->dstar[f->u.id] * (sys->bstar[f->u.id] - dlambda1);
2781 
2782  sys->lambdaTriangle[f->u.id] += dlambda1;
2783 
2784  dalpha = (sys->bAlpha[e1->u.id] - dlambda1);
2785  sys->alpha[e1->u.id] += dalpha / sys->weight[e1->u.id] - pre[0];
2786 
2787  dalpha = (sys->bAlpha[e2->u.id] - dlambda1);
2788  sys->alpha[e2->u.id] += dalpha / sys->weight[e2->u.id] - pre[1];
2789 
2790  dalpha = (sys->bAlpha[e3->u.id] - dlambda1);
2791  sys->alpha[e3->u.id] += dalpha / sys->weight[e3->u.id] - pre[2];
2792 
2793  /* clamp */
2794  e = f->edge;
2795  do {
2796  if (sys->alpha[e->u.id] > (float)M_PI) {
2797  sys->alpha[e->u.id] = (float)M_PI;
2798  }
2799  else if (sys->alpha[e->u.id] < 0.0f) {
2800  sys->alpha[e->u.id] = 0.0f;
2801  }
2802  } while (e != f->edge);
2803  }
2804 
2805  for (i = 0; i < ninterior; i++) {
2807  sys->lambdaLength[i] += (float)EIG_linear_solver_variable_get(context, 0, ninterior + i);
2808  }
2809  }
2810 
2812 
2813  return success;
2814 }
2815 
2817 {
2818  PVert *v;
2819  PFace *f;
2820  PEdge *e, *e1, *e2, *e3;
2821  PAbfSystem sys;
2822  int i;
2823  float /* lastnorm, */ /* UNUSED */ limit = (chart->nfaces > 100) ? 1.0f : 0.001f;
2824 
2825  /* setup id's */
2826  sys.ninterior = sys.nfaces = sys.nangles = 0;
2827 
2828  for (v = chart->verts; v; v = v->nextlink) {
2829  if (p_vert_interior(v)) {
2830  v->flag |= PVERT_INTERIOR;
2831  v->u.id = sys.ninterior++;
2832  }
2833  else {
2834  v->flag &= ~PVERT_INTERIOR;
2835  }
2836  }
2837 
2838  for (f = chart->faces; f; f = f->nextlink) {
2839  e1 = f->edge;
2840  e2 = e1->next;
2841  e3 = e2->next;
2842  f->u.id = sys.nfaces++;
2843 
2844  /* angle id's are conveniently stored in half edges */
2845  e1->u.id = sys.nangles++;
2846  e2->u.id = sys.nangles++;
2847  e3->u.id = sys.nangles++;
2848  }
2849 
2850  p_abf_setup_system(&sys);
2851 
2852  /* compute initial angles */
2853  for (f = chart->faces; f; f = f->nextlink) {
2854  float a1, a2, a3;
2855 
2856  e1 = f->edge;
2857  e2 = e1->next;
2858  e3 = e2->next;
2859  p_face_angles(f, &a1, &a2, &a3);
2860 
2861  if (a1 < sys.minangle) {
2862  a1 = sys.minangle;
2863  }
2864  else if (a1 > sys.maxangle) {
2865  a1 = sys.maxangle;
2866  }
2867  if (a2 < sys.minangle) {
2868  a2 = sys.minangle;
2869  }
2870  else if (a2 > sys.maxangle) {
2871  a2 = sys.maxangle;
2872  }
2873  if (a3 < sys.minangle) {
2874  a3 = sys.minangle;
2875  }
2876  else if (a3 > sys.maxangle) {
2877  a3 = sys.maxangle;
2878  }
2879 
2880  sys.alpha[e1->u.id] = sys.beta[e1->u.id] = a1;
2881  sys.alpha[e2->u.id] = sys.beta[e2->u.id] = a2;
2882  sys.alpha[e3->u.id] = sys.beta[e3->u.id] = a3;
2883 
2884  sys.weight[e1->u.id] = 2.0f / (a1 * a1);
2885  sys.weight[e2->u.id] = 2.0f / (a2 * a2);
2886  sys.weight[e3->u.id] = 2.0f / (a3 * a3);
2887  }
2888 
2889  for (v = chart->verts; v; v = v->nextlink) {
2890  if (v->flag & PVERT_INTERIOR) {
2891  float anglesum = 0.0, scale;
2892 
2893  e = v->edge;
2894  do {
2895  anglesum += sys.beta[e->u.id];
2896  e = e->next->next->pair;
2897  } while (e && (e != v->edge));
2898 
2899  scale = (anglesum == 0.0f) ? 0.0f : 2.0f * (float)M_PI / anglesum;
2900 
2901  e = v->edge;
2902  do {
2903  sys.beta[e->u.id] = sys.alpha[e->u.id] = sys.beta[e->u.id] * scale;
2904  e = e->next->next->pair;
2905  } while (e && (e != v->edge));
2906  }
2907  }
2908 
2909  if (sys.ninterior > 0) {
2910  p_abf_compute_sines(&sys);
2911 
2912  /* iteration */
2913  /* lastnorm = 1e10; */ /* UNUSED */
2914 
2915  for (i = 0; i < ABF_MAX_ITER; i++) {
2916  float norm = p_abf_compute_gradient(&sys, chart);
2917 
2918  /* lastnorm = norm; */ /* UNUSED */
2919 
2920  if (norm < limit) {
2921  break;
2922  }
2923 
2924  if (!p_abf_matrix_invert(&sys, chart)) {
2925  param_warning("ABF failed to invert matrix");
2926  p_abf_free_system(&sys);
2927  return P_FALSE;
2928  }
2929 
2930  p_abf_compute_sines(&sys);
2931  }
2932 
2933  if (i == ABF_MAX_ITER) {
2934  param_warning("ABF maximum iterations reached");
2935  p_abf_free_system(&sys);
2936  return P_FALSE;
2937  }
2938  }
2939 
2940  chart->u.lscm.abf_alpha = MEM_dupallocN(sys.alpha);
2941  p_abf_free_system(&sys);
2942 
2943  return P_TRUE;
2944 }
2945 
2946 /* Least Squares Conformal Maps */
2947 
2948 static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2)
2949 {
2950  if (!*pin1 || !*pin2 || *pin1 == *pin2) {
2951  /* degenerate case */
2952  PFace *f = chart->faces;
2953  *pin1 = f->edge->vert;
2954  *pin2 = f->edge->next->vert;
2955 
2956  (*pin1)->uv[0] = 0.0f;
2957  (*pin1)->uv[1] = 0.5f;
2958  (*pin2)->uv[0] = 1.0f;
2959  (*pin2)->uv[1] = 0.5f;
2960  }
2961  else {
2962  int diru, dirv, dirx, diry;
2963  float sub[3];
2964 
2965  sub_v3_v3v3(sub, (*pin1)->co, (*pin2)->co);
2966  sub[0] = fabsf(sub[0]);
2967  sub[1] = fabsf(sub[1]);
2968  sub[2] = fabsf(sub[2]);
2969 
2970  if ((sub[0] > sub[1]) && (sub[0] > sub[2])) {
2971  dirx = 0;
2972  diry = (sub[1] > sub[2]) ? 1 : 2;
2973  }
2974  else if ((sub[1] > sub[0]) && (sub[1] > sub[2])) {
2975  dirx = 1;
2976  diry = (sub[0] > sub[2]) ? 0 : 2;
2977  }
2978  else {
2979  dirx = 2;
2980  diry = (sub[0] > sub[1]) ? 0 : 1;
2981  }
2982 
2983  if (dirx == 2) {
2984  diru = 1;
2985  dirv = 0;
2986  }
2987  else {
2988  diru = 0;
2989  dirv = 1;
2990  }
2991 
2992  (*pin1)->uv[diru] = (*pin1)->co[dirx];
2993  (*pin1)->uv[dirv] = (*pin1)->co[diry];
2994  (*pin2)->uv[diru] = (*pin2)->co[dirx];
2995  (*pin2)->uv[dirv] = (*pin2)->co[diry];
2996  }
2997 }
2998 
2999 static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2)
3000 {
3001  PEdge *be, *lastbe = NULL, *maxe1 = NULL, *maxe2 = NULL, *be1, *be2;
3002  PEdge *cure = NULL, *firste1 = NULL, *firste2 = NULL, *nextbe;
3003  float maxlen = 0.0f, curlen = 0.0f, totlen = 0.0f, firstlen = 0.0f;
3004  float len1, len2;
3005 
3006  /* find longest series of verts split in the chart itself, these are
3007  * marked during construction */
3008  be = outer;
3009  lastbe = p_boundary_edge_prev(be);
3010  do {
3011  float len = p_edge_length(be);
3012  totlen += len;
3013 
3014  nextbe = p_boundary_edge_next(be);
3015 
3016  if ((be->vert->flag & PVERT_SPLIT) ||
3017  (lastbe->vert->flag & nextbe->vert->flag & PVERT_SPLIT)) {
3018  if (!cure) {
3019  if (be == outer) {
3020  firste1 = be;
3021  }
3022  cure = be;
3023  }
3024  else {
3025  curlen += p_edge_length(lastbe);
3026  }
3027  }
3028  else if (cure) {
3029  if (curlen > maxlen) {
3030  maxlen = curlen;
3031  maxe1 = cure;
3032  maxe2 = lastbe;
3033  }
3034 
3035  if (firste1 == cure) {
3036  firstlen = curlen;
3037  firste2 = lastbe;
3038  }
3039 
3040  curlen = 0.0f;
3041  cure = NULL;
3042  }
3043 
3044  lastbe = be;
3045  be = nextbe;
3046  } while (be != outer);
3047 
3048  /* make sure we also count a series of splits over the starting point */
3049  if (cure && (cure != outer)) {
3050  firstlen += curlen + p_edge_length(be);
3051 
3052  if (firstlen > maxlen) {
3053  maxlen = firstlen;
3054  maxe1 = cure;
3055  maxe2 = firste2;
3056  }
3057  }
3058 
3059  if (!maxe1 || !maxe2 || (maxlen < 0.5f * totlen)) {
3060  return P_FALSE;
3061  }
3062 
3063  /* find pin1 in the split vertices */
3064  be1 = maxe1;
3065  be2 = maxe2;
3066  len1 = 0.0f;
3067  len2 = 0.0f;
3068 
3069  do {
3070  if (len1 < len2) {
3071  len1 += p_edge_length(be1);
3072  be1 = p_boundary_edge_next(be1);
3073  }
3074  else {
3075  be2 = p_boundary_edge_prev(be2);
3076  len2 += p_edge_length(be2);
3077  }
3078  } while (be1 != be2);
3079 
3080  *pin1 = be1->vert;
3081 
3082  /* find pin2 outside the split vertices */
3083  be1 = maxe1;
3084  be2 = maxe2;
3085  len1 = 0.0f;
3086  len2 = 0.0f;
3087 
3088  do {
3089  if (len1 < len2) {
3090  be1 = p_boundary_edge_prev(be1);
3091  len1 += p_edge_length(be1);
3092  }
3093  else {
3094  len2 += p_edge_length(be2);
3095  be2 = p_boundary_edge_next(be2);
3096  }
3097  } while (be1 != be2);
3098 
3099  *pin2 = be1->vert;
3100 
3101  p_chart_pin_positions(chart, pin1, pin2);
3102 
3103  return !equals_v3v3((*pin1)->co, (*pin2)->co);
3104 }
3105 
3106 static void p_chart_extrema_verts(PChart *chart, PVert **pin1, PVert **pin2)
3107 {
3108  float minv[3], maxv[3], dirlen;
3109  PVert *v, *minvert[3], *maxvert[3];
3110  int i, dir;
3111 
3112  /* find minimum and maximum verts over x/y/z axes */
3113  minv[0] = minv[1] = minv[2] = 1e20;
3114  maxv[0] = maxv[1] = maxv[2] = -1e20;
3115 
3116  minvert[0] = minvert[1] = minvert[2] = NULL;
3117  maxvert[0] = maxvert[1] = maxvert[2] = NULL;
3118 
3119  for (v = chart->verts; v; v = v->nextlink) {
3120  for (i = 0; i < 3; i++) {
3121  if (v->co[i] < minv[i]) {
3122  minv[i] = v->co[i];
3123  minvert[i] = v;
3124  }
3125  if (v->co[i] > maxv[i]) {
3126  maxv[i] = v->co[i];
3127  maxvert[i] = v;
3128  }
3129  }
3130  }
3131 
3132  /* find axes with longest distance */
3133  dir = 0;
3134  dirlen = -1.0;
3135 
3136  for (i = 0; i < 3; i++) {
3137  if (maxv[i] - minv[i] > dirlen) {
3138  dir = i;
3139  dirlen = maxv[i] - minv[i];
3140  }
3141  }
3142 
3143  *pin1 = minvert[dir];
3144  *pin2 = maxvert[dir];
3145 
3146  p_chart_pin_positions(chart, pin1, pin2);
3147 }
3148 
3150 {
3151  LinearSolver *context = chart->u.lscm.context;
3152  PVert *v;
3153 
3154  for (v = chart->verts; v; v = v->nextlink) {
3155  v->uv[0] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id);
3156  v->uv[1] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id + 1);
3157  }
3158 }
3159 
3160 static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
3161 {
3162  PVert *v, *pin1, *pin2;
3163  PBool select = P_FALSE, deselect = P_FALSE;
3164  int npins = 0, id = 0;
3165 
3166  /* give vertices matrix indices and count pins */
3167  for (v = chart->verts; v; v = v->nextlink) {
3168  if (v->flag & PVERT_PIN) {
3169  npins++;
3170  if (v->flag & PVERT_SELECT) {
3171  select = P_TRUE;
3172  }
3173  }
3174 
3175  if (!(v->flag & PVERT_SELECT)) {
3176  deselect = P_TRUE;
3177  }
3178  }
3179 
3180  if ((live && (!select || !deselect))) {
3181  chart->u.lscm.context = NULL;
3182  }
3183  else {
3184 #if 0
3185  p_chart_simplify_compute(chart);
3186  p_chart_topological_sanity_check(chart);
3187 #endif
3188 
3189  if (npins == 1) {
3190  chart->u.lscm.single_pin_area = p_chart_uv_area(chart);
3191  for (v = chart->verts; v; v = v->nextlink) {
3192  if (v->flag & PVERT_PIN) {
3193  chart->u.lscm.single_pin = v;
3194  break;
3195  }
3196  }
3197  }
3198 
3199  if (abf) {
3200  if (!p_chart_abf_solve(chart)) {
3201  param_warning("ABF solving failed: falling back to LSCM.\n");
3202  }
3203  }
3204 
3205  if (npins <= 1) {
3206  /* No pins, let's find some ourself. */
3207  PEdge *outer;
3208 
3209  p_chart_boundaries(chart, NULL, &outer);
3210 
3211  /* Outer can be NULL with non-finite coords. */
3212  if (!(outer && p_chart_symmetry_pins(chart, outer, &pin1, &pin2))) {
3213  p_chart_extrema_verts(chart, &pin1, &pin2);
3214  }
3215 
3216  chart->u.lscm.pin1 = pin1;
3217  chart->u.lscm.pin2 = pin2;
3218  }
3219 
3220  for (v = chart->verts; v; v = v->nextlink) {
3221  v->u.id = id++;
3222  }
3223 
3225  2 * chart->nfaces, 2 * chart->nverts, 1);
3226  }
3227 }
3228 
3229 static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
3230 {
3231  LinearSolver *context = chart->u.lscm.context;
3232  PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2;
3233  PFace *f;
3234  const float *alpha = chart->u.lscm.abf_alpha;
3235  float area_pinned_up, area_pinned_down;
3236  bool flip_faces;
3237  int row;
3238 
3239 #if 0
3240  /* TODO: make loading pins work for simplify/complexify. */
3241 #endif
3242 
3243  for (v = chart->verts; v; v = v->nextlink) {
3244  if (v->flag & PVERT_PIN) {
3245  p_vert_load_pin_select_uvs(handle, v); /* reload for live */
3246  }
3247  }
3248 
3249  if (chart->u.lscm.single_pin) {
3250  /* If only one pin, save area and pin for transform later. */
3251  copy_v2_v2(chart->u.lscm.single_pin_uv, chart->u.lscm.single_pin->uv);
3252  }
3253 
3254  if (chart->u.lscm.pin1) {
3256  EIG_linear_solver_variable_lock(context, 2 * pin1->u.id + 1);
3257  EIG_linear_solver_variable_lock(context, 2 * pin2->u.id);
3258  EIG_linear_solver_variable_lock(context, 2 * pin2->u.id + 1);
3259 
3260  EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id, pin1->uv[0]);
3261  EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id + 1, pin1->uv[1]);
3262  EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id, pin2->uv[0]);
3263  EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id + 1, pin2->uv[1]);
3264  }
3265  else {
3266  /* set and lock the pins */
3267  for (v = chart->verts; v; v = v->nextlink) {
3268  if (v->flag & PVERT_PIN) {
3270  EIG_linear_solver_variable_lock(context, 2 * v->u.id + 1);
3271 
3272  EIG_linear_solver_variable_set(context, 0, 2 * v->u.id, v->uv[0]);
3273  EIG_linear_solver_variable_set(context, 0, 2 * v->u.id + 1, v->uv[1]);
3274  }
3275  }
3276  }
3277 
3278  /* detect up direction based on pinned vertices */
3279  area_pinned_up = 0.0f;
3280  area_pinned_down = 0.0f;
3281 
3282  for (f = chart->faces; f; f = f->nextlink) {
3283  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
3284  PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
3285 
3286  if ((v1->flag & PVERT_PIN) && (v2->flag & PVERT_PIN) && (v3->flag & PVERT_PIN)) {
3287  float area = p_face_uv_area_signed(f);
3288 
3289  if (area > 0.0f) {
3290  area_pinned_up += area;
3291  }
3292  else {
3293  area_pinned_down -= area;
3294  }
3295  }
3296  }
3297 
3298  flip_faces = (area_pinned_down > area_pinned_up);
3299 
3300  /* construct matrix */
3301 
3302  row = 0;
3303  for (f = chart->faces; f; f = f->nextlink) {
3304  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
3305  PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
3306  float a1, a2, a3, ratio, cosine, sine;
3307  float sina1, sina2, sina3, sinmax;
3308 
3309  if (alpha) {
3310  /* use abf angles if passed on */
3311  a1 = *(alpha++);
3312  a2 = *(alpha++);
3313  a3 = *(alpha++);
3314  }
3315  else {
3316  p_face_angles(f, &a1, &a2, &a3);
3317  }
3318 
3319  if (flip_faces) {
3320  SWAP(float, a2, a3);
3321  SWAP(PEdge *, e2, e3);
3322  SWAP(PVert *, v2, v3);
3323  }
3324 
3325  sina1 = sinf(a1);
3326  sina2 = sinf(a2);
3327  sina3 = sinf(a3);
3328 
3329  sinmax = max_fff(sina1, sina2, sina3);
3330 
3331  /* shift vertices to find most stable order */
3332  if (sina3 != sinmax) {
3333  SHIFT3(PVert *, v1, v2, v3);
3334  SHIFT3(float, a1, a2, a3);
3335  SHIFT3(float, sina1, sina2, sina3);
3336 
3337  if (sina2 == sinmax) {
3338  SHIFT3(PVert *, v1, v2, v3);
3339  SHIFT3(float, a1, a2, a3);
3340  SHIFT3(float, sina1, sina2, sina3);
3341  }
3342  }
3343 
3344  /* angle based lscm formulation */
3345  ratio = (sina3 == 0.0f) ? 1.0f : sina2 / sina3;
3346  cosine = cosf(a1) * ratio;
3347  sine = sina1 * ratio;
3348 
3349  EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, cosine - 1.0f);
3350  EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, -sine);
3351  EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -cosine);
3352  EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, sine);
3353  EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id, 1.0);
3354  row++;
3355 
3356  EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, sine);
3357  EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, cosine - 1.0f);
3358  EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -sine);
3359  EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, -cosine);
3360  EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id + 1, 1.0);
3361  row++;
3362  }
3363 
3366  return P_TRUE;
3367  }
3368 
3369  for (v = chart->verts; v; v = v->nextlink) {
3370  v->uv[0] = 0.0f;
3371  v->uv[1] = 0.0f;
3372  }
3373 
3374  return P_FALSE;
3375 }
3376 
3378 {
3379  PVert *pin = chart->u.lscm.single_pin;
3380 
3381  /* If only one pin, keep UV area the same. */
3382  const float new_area = p_chart_uv_area(chart);
3383  if (new_area > 0.0f) {
3384  const float scale = chart->u.lscm.single_pin_area / new_area;
3385  if (scale > 0.0f) {
3386  p_chart_uv_scale(chart, sqrtf(scale));
3387  }
3388  }
3389 
3390  /* Translate to keep the pinned vertex in place. */
3391  float offset[2];
3392  sub_v2_v2v2(offset, chart->u.lscm.single_pin_uv, pin->uv);
3393  p_chart_uv_translate(chart, offset);
3394 }
3395 
3396 static void p_chart_lscm_end(PChart *chart)
3397 {
3398  if (chart->u.lscm.context) {
3400  }
3401 
3402  if (chart->u.lscm.abf_alpha) {
3403  MEM_freeN(chart->u.lscm.abf_alpha);
3404  chart->u.lscm.abf_alpha = NULL;
3405  }
3406 
3407  chart->u.lscm.context = NULL;
3408  chart->u.lscm.pin1 = NULL;
3409  chart->u.lscm.pin2 = NULL;
3410  chart->u.lscm.single_pin = NULL;
3411  chart->u.lscm.single_pin_area = 0.0f;
3412 }
3413 
3414 /* Stretch */
3415 
3416 #define P_STRETCH_ITER 20
3417 
3418 static void p_stretch_pin_boundary(PChart *chart)
3419 {
3420  PVert *v;
3421 
3422  for (v = chart->verts; v; v = v->nextlink) {
3423  if (v->edge->pair == NULL) {
3424  v->flag |= PVERT_PIN;
3425  }
3426  else {
3427  v->flag &= ~PVERT_PIN;
3428  }
3429  }
3430 }
3431 
3432 static float p_face_stretch(PFace *f)
3433 {
3434  float T, w, tmp[3];
3435  float Ps[3], Pt[3];
3436  float a, c, area;
3437  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
3438  PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
3439 
3441 
3442  if (area <= 0.0f) { /* flipped face -> infinite stretch */
3443  return 1e10f;
3444  }
3445 
3446  w = 1.0f / (2.0f * area);
3447 
3448  /* compute derivatives */
3449  copy_v3_v3(Ps, v1->co);
3450  mul_v3_fl(Ps, (v2->uv[1] - v3->uv[1]));
3451 
3452  copy_v3_v3(tmp, v2->co);
3453  mul_v3_fl(tmp, (v3->uv[1] - v1->uv[1]));
3454  add_v3_v3(Ps, tmp);
3455 
3456  copy_v3_v3(tmp, v3->co);
3457  mul_v3_fl(tmp, (v1->uv[1] - v2->uv[1]));
3458  add_v3_v3(Ps, tmp);
3459 
3460  mul_v3_fl(Ps, w);
3461 
3462  copy_v3_v3(Pt, v1->co);
3463  mul_v3_fl(Pt, (v3->uv[0] - v2->uv[0]));
3464 
3465  copy_v3_v3(tmp, v2->co);
3466  mul_v3_fl(tmp, (v1->uv[0] - v3->uv[0]));
3467  add_v3_v3(Pt, tmp);
3468 
3469  copy_v3_v3(tmp, v3->co);
3470  mul_v3_fl(tmp, (v2->uv[0] - v1->uv[0]));
3471  add_v3_v3(Pt, tmp);
3472 
3473  mul_v3_fl(Pt, w);
3474 
3475  /* Sander Tensor */
3476  a = dot_v3v3(Ps, Ps);
3477  c = dot_v3v3(Pt, Pt);
3478 
3479  T = sqrtf(0.5f * (a + c));
3480  if (f->flag & PFACE_FILLED) {
3481  T *= 0.2f;
3482  }
3483 
3484  return T;
3485 }
3486 
3488 {
3489  PEdge *e = v->edge;
3490  float sum = 0.0f;
3491 
3492  do {
3493  sum += p_face_stretch(e->face);
3494  e = p_wheel_edge_next(e);
3495  } while (e && e != (v->edge));
3496 
3497  return sum;
3498 }
3499 
3500 static void p_chart_stretch_minimize(PChart *chart, RNG *rng)
3501 {
3502  PVert *v;
3503  PEdge *e;
3504  int j, nedges;
3505  float orig_stretch, low, stretch_low, high, stretch_high, mid, stretch;
3506  float orig_uv[2], dir[2], random_angle, trusted_radius;
3507 
3508  for (v = chart->verts; v; v = v->nextlink) {
3509  if ((v->flag & PVERT_PIN) || !(v->flag & PVERT_SELECT)) {
3510  continue;
3511  }
3512 
3513  orig_stretch = p_stretch_compute_vertex(v);
3514  orig_uv[0] = v->uv[0];
3515  orig_uv[1] = v->uv[1];
3516 
3517  /* move vertex in a random direction */
3518  trusted_radius = 0.0f;
3519  nedges = 0;
3520  e = v->edge;
3521 
3522  do {
3523  trusted_radius += p_edge_uv_length(e);
3524  nedges++;
3525 
3526  e = p_wheel_edge_next(e);
3527  } while (e && e != (v->edge));
3528 
3529  trusted_radius /= 2 * nedges;
3530 
3531  random_angle = BLI_rng_get_float(rng) * 2.0f * (float)M_PI;
3532  dir[0] = trusted_radius * cosf(random_angle);
3533  dir[1] = trusted_radius * sinf(random_angle);
3534 
3535  /* calculate old and new stretch */
3536  low = 0;
3537  stretch_low = orig_stretch;
3538 
3539  add_v2_v2v2(v->uv, orig_uv, dir);
3540  high = 1;
3541  stretch = stretch_high = p_stretch_compute_vertex(v);
3542 
3543  /* binary search for lowest stretch position */
3544  for (j = 0; j < P_STRETCH_ITER; j++) {
3545  mid = 0.5f * (low + high);
3546  v->uv[0] = orig_uv[0] + mid * dir[0];
3547  v->uv[1] = orig_uv[1] + mid * dir[1];
3548  stretch = p_stretch_compute_vertex(v);
3549 
3550  if (stretch_low < stretch_high) {
3551  high = mid;
3552  stretch_high = stretch;
3553  }
3554  else {
3555  low = mid;
3556  stretch_low = stretch;
3557  }
3558  }
3559 
3560  /* no luck, stretch has increased, reset to old values */
3561  if (stretch >= orig_stretch) {
3562  copy_v2_v2(v->uv, orig_uv);
3563  }
3564  }
3565 }
3566 
3567 /* Minimum area enclosing rectangle for packing */
3568 
3569 static int p_compare_geometric_uv(const void *a, const void *b)
3570 {
3571  const PVert *v1 = *(const PVert *const *)a;
3572  const PVert *v2 = *(const PVert *const *)b;
3573 
3574  if (v1->uv[0] < v2->uv[0]) {
3575  return -1;
3576  }
3577  if (v1->uv[0] == v2->uv[0]) {
3578  if (v1->uv[1] < v2->uv[1]) {
3579  return -1;
3580  }
3581  if (v1->uv[1] == v2->uv[1]) {
3582  return 0;
3583  }
3584  return 1;
3585  }
3586  return 1;
3587 }
3588 
3589 static PBool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, int *r_right)
3590 {
3591  /* Graham algorithm, taken from:
3592  * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117225 */
3593 
3594  PEdge *be, *e;
3595  int npoints = 0, i, ulen, llen;
3596  PVert **U, **L, **points, **p;
3597 
3598  p_chart_boundaries(chart, NULL, &be);
3599 
3600  if (!be) {
3601  return P_FALSE;
3602  }
3603 
3604  e = be;
3605  do {
3606  npoints++;
3608  } while (e != be);
3609 
3610  p = points = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints * 2, "PCHullpoints");
3611  U = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints, "PCHullU");
3612  L = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints, "PCHullL");
3613 
3614  e = be;
3615  do {
3616  *p = e->vert;
3617  p++;
3619  } while (e != be);
3620 
3621  qsort(points, npoints, sizeof(PVert *), p_compare_geometric_uv);
3622 
3623  ulen = llen = 0;
3624  for (p = points, i = 0; i < npoints; i++, p++) {
3625  while ((ulen > 1) && (p_area_signed(U[ulen - 2]->uv, (*p)->uv, U[ulen - 1]->uv) <= 0)) {
3626  ulen--;
3627  }
3628  while ((llen > 1) && (p_area_signed(L[llen - 2]->uv, (*p)->uv, L[llen - 1]->uv) >= 0)) {
3629  llen--;
3630  }
3631 
3632  U[ulen] = *p;
3633  ulen++;
3634  L[llen] = *p;
3635  llen++;
3636  }
3637 
3638  npoints = 0;
3639  for (p = points, i = 0; i < ulen; i++, p++, npoints++) {
3640  *p = U[i];
3641  }
3642 
3643  /* the first and last point in L are left out, since they are also in U */
3644  for (i = llen - 2; i > 0; i--, p++, npoints++) {
3645  *p = L[i];
3646  }
3647 
3648  *r_verts = points;
3649  *r_nverts = npoints;
3650  *r_right = ulen - 1;
3651 
3652  MEM_freeN(U);
3653  MEM_freeN(L);
3654 
3655  return P_TRUE;
3656 }
3657 
3658 static float p_rectangle_area(float *p1, float *dir, float *p2, float *p3, float *p4)
3659 {
3660  /* given 4 points on the rectangle edges and the direction of on edge,
3661  * compute the area of the rectangle */
3662 
3663  float orthodir[2], corner1[2], corner2[2], corner3[2];
3664 
3665  orthodir[0] = dir[1];
3666  orthodir[1] = -dir[0];
3667 
3668  if (!p_intersect_line_2d_dir(p1, dir, p2, orthodir, corner1)) {
3669  return 1e10;
3670  }
3671 
3672  if (!p_intersect_line_2d_dir(p1, dir, p4, orthodir, corner2)) {
3673  return 1e10;
3674  }
3675 
3676  if (!p_intersect_line_2d_dir(p3, dir, p4, orthodir, corner3)) {
3677  return 1e10;
3678  }
3679 
3680  return len_v2v2(corner1, corner2) * len_v2v2(corner2, corner3);
3681 }
3682 
3684 {
3685  /* minimum area enclosing rectangle with rotating calipers, info:
3686  * http://cgm.cs.mcgill.ca/~orm/maer.html */
3687 
3688  float rotated, minarea, minangle, area, len;
3689  float *angles, miny, maxy, v[2], a[4], mina;
3690  int npoints, right, i_min, i_max, i, idx[4], nextidx;
3691  PVert **points, *p1, *p2, *p3, *p4, *p1n;
3692 
3693  /* compute convex hull */
3694  if (!p_chart_convex_hull(chart, &points, &npoints, &right)) {
3695  return 0.0;
3696  }
3697 
3698  /* find left/top/right/bottom points, and compute angle for each point */
3699  angles = MEM_mallocN(sizeof(float) * npoints, "PMinAreaAngles");
3700 
3701  i_min = i_max = 0;
3702  miny = 1e10;
3703  maxy = -1e10;
3704 
3705  for (i = 0; i < npoints; i++) {
3706  p1 = (i == 0) ? points[npoints - 1] : points[i - 1];
3707  p2 = points[i];
3708  p3 = (i == npoints - 1) ? points[0] : points[i + 1];
3709 
3710  angles[i] = (float)M_PI - p_vec2_angle(p1->uv, p2->uv, p3->uv);
3711 
3712  if (points[i]->uv[1] < miny) {
3713  miny = points[i]->uv[1];
3714  i_min = i;
3715  }
3716  if (points[i]->uv[1] > maxy) {
3717  maxy = points[i]->uv[1];
3718  i_max = i;
3719  }
3720  }
3721 
3722  /* left, top, right, bottom */
3723  idx[0] = 0;
3724  idx[1] = i_max;
3725  idx[2] = right;
3726  idx[3] = i_min;
3727 
3728  v[0] = points[idx[0]]->uv[0];
3729  v[1] = points[idx[0]]->uv[1] + 1.0f;
3730  a[0] = p_vec2_angle(points[(idx[0] + 1) % npoints]->uv, points[idx[0]]->uv, v);
3731 
3732  v[0] = points[idx[1]]->uv[0] + 1.0f;
3733  v[1] = points[idx[1]]->uv[1];
3734  a[1] = p_vec2_angle(points[(idx[1] + 1) % npoints]->uv, points[idx[1]]->uv, v);
3735 
3736  v[0] = points[idx[2]]->uv[0];
3737  v[1] = points[idx[2]]->uv[1] - 1.0f;
3738  a[2] = p_vec2_angle(points[(idx[2] + 1) % npoints]->uv, points[idx[2]]->uv, v);
3739 
3740  v[0] = points[idx[3]]->uv[0] - 1.0f;
3741  v[1] = points[idx[3]]->uv[1];
3742  a[3] = p_vec2_angle(points[(idx[3] + 1) % npoints]->uv, points[idx[3]]->uv, v);
3743 
3744  /* 4 rotating calipers */
3745 
3746  rotated = 0.0;
3747  minarea = 1e10;
3748  minangle = 0.0;
3749 
3750  while (rotated <= (float)(M_PI / 2.0)) { /* INVESTIGATE: how far to rotate? */
3751  /* rotate with the smallest angle */
3752  i_min = 0;
3753  mina = 1e10;
3754 
3755  for (i = 0; i < 4; i++) {
3756  if (a[i] < mina) {
3757  mina = a[i];
3758  i_min = i;
3759  }
3760  }
3761 
3762  rotated += mina;
3763  nextidx = (idx[i_min] + 1) % npoints;
3764 
3765  a[i_min] = angles[nextidx];
3766  a[(i_min + 1) % 4] = a[(i_min + 1) % 4] - mina;
3767  a[(i_min + 2) % 4] = a[(i_min + 2) % 4] - mina;
3768  a[(i_min + 3) % 4] = a[(i_min + 3) % 4] - mina;
3769 
3770  /* compute area */
3771  p1 = points[idx[i_min]];
3772  p1n = points[nextidx];
3773  p2 = points[idx[(i_min + 1) % 4]];
3774  p3 = points[idx[(i_min + 2) % 4]];
3775  p4 = points[idx[(i_min + 3) % 4]];
3776 
3777  len = len_v2v2(p1->uv, p1n->uv);
3778 
3779  if (len > 0.0f) {
3780  len = 1.0f / len;
3781  v[0] = (p1n->uv[0] - p1->uv[0]) * len;
3782  v[1] = (p1n->uv[1] - p1->uv[1]) * len;
3783 
3784  area = p_rectangle_area(p1->uv, v, p2->uv, p3->uv, p4->uv);
3785 
3786  /* remember smallest area */
3787  if (area < minarea) {
3788  minarea = area;
3789  minangle = rotated;
3790  }
3791  }
3792 
3793  idx[i_min] = nextidx;
3794  }
3795 
3796  /* try keeping rotation as small as possible */
3797  if (minangle > (float)(M_PI / 4)) {
3798  minangle -= (float)(M_PI / 2.0);
3799  }
3800 
3801  MEM_freeN(angles);
3802  MEM_freeN(points);
3803 
3804  return minangle;
3805 }
3806 
3808 {
3809  float angle = p_chart_minimum_area_angle(chart);
3810  float sine = sinf(angle);
3811  float cosine = cosf(angle);
3812  PVert *v;
3813 
3814  for (v = chart->verts; v; v = v->nextlink) {
3815  float oldu = v->uv[0], oldv = v->uv[1];
3816  v->uv[0] = cosine * oldu - sine * oldv;
3817  v->uv[1] = sine * oldu + cosine * oldv;
3818  }
3819 }
3820 
3821 static void p_chart_rotate_fit_aabb(PChart *chart)
3822 {
3823  float(*points)[2] = MEM_mallocN(sizeof(*points) * chart->nverts, __func__);
3824 
3825  p_chart_uv_to_array(chart, points);
3826 
3827  float angle = BLI_convexhull_aabb_fit_points_2d(points, chart->nverts);
3828 
3829  MEM_freeN(points);
3830 
3831  if (angle != 0.0f) {
3832  float mat[2][2];
3833  angle_to_mat2(mat, angle);
3834  p_chart_uv_transform(chart, mat);
3835  }
3836 }
3837 
3838 /* Area Smoothing */
3839 
3840 /* 2d BSP tree for inverse mapping - that's a bit silly. */
3841 
3842 typedef struct SmoothTriangle {
3843  float co1[2], co2[2], co3[2];
3844  float oco1[2], oco2[2], oco3[2];
3846 
3847 typedef struct SmoothNode {
3848  struct SmoothNode *c1, *c2;
3850  float split;
3851  int axis, ntri;
3853 
3854 static void p_barycentric_2d(
3855  const float v1[2], const float v2[2], const float v3[2], const float p[2], float b[3])
3856 {
3857  float a[2], c[2], h[2], div;
3858 
3859  a[0] = v2[0] - v1[0];
3860  a[1] = v2[1] - v1[1];
3861  c[0] = v3[0] - v1[0];
3862  c[1] = v3[1] - v1[1];
3863 
3864  div = a[0] * c[1] - a[1] * c[0];
3865 
3866  if (div == 0.0f) {
3867  b[0] = 1.0f / 3.0f;
3868  b[1] = 1.0f / 3.0f;
3869  b[2] = 1.0f / 3.0f;
3870  }
3871  else {
3872  h[0] = p[0] - v1[0];
3873  h[1] = p[1] - v1[1];
3874 
3875  div = 1.0f / div;
3876 
3877  b[1] = (h[0] * c[1] - h[1] * c[0]) * div;
3878  b[2] = (a[0] * h[1] - a[1] * h[0]) * div;
3879  b[0] = 1.0f - b[1] - b[2];
3880  }
3881 }
3882 
3884 {
3885  float b[3];
3886 
3887  p_barycentric_2d(t->co1, t->co2, t->co3, co, b);
3888 
3889  if ((b[0] >= 0.0f) && (b[1] >= 0.0f) && (b[2] >= 0.0f)) {
3890  co[0] = t->oco1[0] * b[0] + t->oco2[0] * b[1] + t->oco3[0] * b[2];
3891  co[1] = t->oco1[1] * b[0] + t->oco2[1] * b[1] + t->oco3[1] * b[2];
3892  return P_TRUE;
3893  }
3894 
3895  return P_FALSE;
3896 }
3897 
3899  MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth)
3900 {
3901  SmoothNode *node = BLI_memarena_alloc(arena, sizeof(*node));
3902  int axis, i, t1size = 0, t2size = 0;
3903  float split, /* mi, */ /* UNUSED */ mx;
3904  SmoothTriangle **t1, **t2, *t;
3905 
3906  node->tri = tri;
3907  node->ntri = ntri;
3908 
3909  if (ntri <= 10 || depth >= 15) {
3910  return node;
3911  }
3912 
3913  t1 = MEM_mallocN(sizeof(*t1) * ntri, "PNodeTri1");
3914  t2 = MEM_mallocN(sizeof(*t2) * ntri, "PNodeTri1");
3915 
3916  axis = (bmax[0] - bmin[0] > bmax[1] - bmin[1]) ? 0 : 1;
3917  split = 0.5f * (bmin[axis] + bmax[axis]);
3918 
3919  for (i = 0; i < ntri; i++) {
3920  t = tri[i];
3921 
3922  if ((t->co1[axis] <= split) || (t->co2[axis] <= split) || (t->co3[axis] <= split)) {
3923  t1[t1size] = t;
3924  t1size++;
3925  }
3926  if ((t->co1[axis] >= split) || (t->co2[axis] >= split) || (t->co3[axis] >= split)) {
3927  t2[t2size] = t;
3928  t2size++;
3929  }
3930  }
3931 
3932  if ((t1size == t2size) && (t1size == ntri)) {
3933  MEM_freeN(t1);
3934  MEM_freeN(t2);
3935  return node;
3936  }
3937 
3938  node->tri = NULL;
3939  node->ntri = 0;
3940  MEM_freeN(tri);
3941 
3942  node->axis = axis;
3943  node->split = split;
3944 
3945  /* mi = bmin[axis]; */ /* UNUSED */
3946  mx = bmax[axis];
3947  bmax[axis] = split;
3948  node->c1 = p_node_new(arena, t1, t1size, bmin, bmax, depth + 1);
3949 
3950  bmin[axis] = bmax[axis];
3951  bmax[axis] = mx;
3952  node->c2 = p_node_new(arena, t2, t2size, bmin, bmax, depth + 1);
3953 
3954  return node;
3955 }
3956 
3958 {
3959  if (node->c1) {
3960  p_node_delete(node->c1);
3961  }
3962  if (node->c2) {
3963  p_node_delete(node->c2);
3964  }
3965  if (node->tri) {
3966  MEM_freeN(node->tri);
3967  }
3968 }
3969 
3970 static PBool p_node_intersect(SmoothNode *node, float co[2])
3971 {
3972  int i;
3973 
3974  if (node->tri) {
3975  for (i = 0; i < node->ntri; i++) {
3976  if (p_triangle_inside(node->tri[i], co)) {
3977  return P_TRUE;
3978  }
3979  }
3980 
3981  return P_FALSE;
3982  }
3983 
3984  if (co[node->axis] < node->split) {
3985  return p_node_intersect(node->c1, co);
3986  }
3987  return p_node_intersect(node->c2, co);
3988 }
3989 
3990 /* smoothing */
3991 
3992 static int p_compare_float(const void *a_, const void *b_)
3993 {
3994  const float a = *(const float *)a_;
3995  const float b = *(const float *)b_;
3996 
3997  if (a < b) {
3998  return -1;
3999  }
4000  if (a == b) {
4001  return 0;
4002  }
4003  return 1;
4004 }
4005 
4007 {
4008  PEdge *e;
4009  float *lengths = MEM_mallocN(sizeof(chart->edges) * chart->nedges, "PMedianLength");
4010  float median;
4011  int i;
4012 
4013  /* ok, so I'm lazy */
4014  for (i = 0, e = chart->edges; e; e = e->nextlink, i++) {
4015  lengths[i] = p_edge_length(e);
4016  }
4017 
4018  qsort(lengths, i, sizeof(float), p_compare_float);
4019 
4020  median = lengths[i / 2];
4021  MEM_freeN(lengths);
4022 
4023  return median;
4024 }
4025 
4026 static float p_smooth_distortion(PEdge *e, float avg2d, float avg3d)
4027 {
4028  float len2d = p_edge_uv_length(e) * avg3d;
4029  float len3d = p_edge_length(e) * avg2d;
4030 
4031  return (len3d == 0.0f) ? 0.0f : len2d / len3d;
4032 }
4033 
4034 static void p_smooth(PChart *chart)
4035 {
4036  PEdge *e;
4037  PVert *v;
4038  PFace *f;
4039  int j, it2, maxiter2, it;
4040  int nedges = chart->nedges, nwheel, gridx, gridy;
4041  int edgesx, edgesy, nsize, esize, i, x, y, maxiter, totiter;
4042  float minv[2], maxv[2], median, invmedian, avglen2d, avglen3d;
4043  float center[2], dx, dy, *nodes, dlimit, d, *oldnodesx, *oldnodesy;
4044  float *nodesx, *nodesy, *hedges, *vedges, climit, moved, padding;
4045  SmoothTriangle *triangles, *t, *t2, **tri, **trip;
4046  SmoothNode *root;
4047  MemArena *arena;
4048 
4049  if (nedges == 0) {
4050  return;
4051  }
4052 
4053  p_chart_uv_bbox(chart, minv, maxv);
4054  median = p_smooth_median_edge_length(chart) * 0.10f;
4055 
4056  if (median == 0.0f) {
4057  return;
4058  }
4059 
4060  invmedian = 1.0f / median;
4061 
4062  /* compute edge distortion */
4063  avglen2d = avglen3d = 0.0;
4064 
4065  for (e = chart->edges; e; e = e->nextlink) {
4066  avglen2d += p_edge_uv_length(e);
4067  avglen3d += p_edge_length(e);
4068  }
4069 
4070  avglen2d /= nedges;
4071  avglen3d /= nedges;
4072 
4073  for (v = chart->verts; v; v = v->nextlink) {
4074  v->u.distortion = 0.0;
4075  nwheel = 0;
4076 
4077  e = v->edge;
4078  do {
4079  v->u.distortion += p_smooth_distortion(e, avglen2d, avglen3d);
4080  nwheel++;
4081 
4082  e = e->next->next->pair;
4083  } while (e && (e != v->edge));
4084 
4085  v->u.distortion /= nwheel;
4086  }
4087 
4088  /* need to do excessive grid size checking still */
4089  center[0] = 0.5f * (minv[0] + maxv[0]);
4090  center[1] = 0.5f * (minv[1] + maxv[1]);
4091 
4092  dx = 0.5f * (maxv[0] - minv[0]);
4093  dy = 0.5f * (maxv[1] - minv[1]);
4094 
4095  padding = 0.15f;
4096  dx += padding * dx + 2.0f * median;
4097  dy += padding * dy + 2.0f * median;
4098 
4099  gridx = (int)(dx * invmedian);
4100  gridy = (int)(dy * invmedian);
4101 
4102  minv[0] = center[0] - median * gridx;
4103  minv[1] = center[1] - median * gridy;
4104  maxv[0] = center[0] + median * gridx;
4105  maxv[1] = center[1] + median * gridy;
4106 
4107  /* create grid */
4108  gridx = gridx * 2 + 1;
4109  gridy = gridy * 2 + 1;
4110 
4111  if ((gridx <= 2) || (gridy <= 2)) {
4112  return;
4113  }
4114 
4115  edgesx = gridx - 1;
4116  edgesy = gridy - 1;
4117  nsize = gridx * gridy;
4118  esize = edgesx * edgesy;
4119 
4120  nodes = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodes");
4121  nodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesX");
4122  nodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesY");
4123  oldnodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesX");
4124  oldnodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesY");
4125  hedges = MEM_mallocN(sizeof(float) * esize, "PSmoothHEdges");
4126  vedges = MEM_mallocN(sizeof(float) * esize, "PSmoothVEdges");
4127 
4128  if (!nodes || !nodesx || !nodesy || !oldnodesx || !oldnodesy || !hedges || !vedges) {
4129  if (nodes) {
4130  MEM_freeN(nodes);
4131  }
4132  if (nodesx) {
4133  MEM_freeN(nodesx);
4134  }
4135  if (nodesy) {
4136  MEM_freeN(nodesy);
4137  }
4138  if (oldnodesx) {
4139  MEM_freeN(oldnodesx);
4140  }
4141  if (oldnodesy) {
4142  MEM_freeN(oldnodesy);
4143  }
4144  if (hedges) {
4145  MEM_freeN(hedges);
4146  }
4147  if (vedges) {
4148  MEM_freeN(vedges);
4149  }
4150 
4151  // printf("Not enough memory for area smoothing grid");
4152  return;
4153  }
4154 
4155  for (x = 0; x < gridx; x++) {
4156  for (y = 0; y < gridy; y++) {
4157  i = x + y * gridx;
4158 
4159  nodesx[i] = minv[0] + median * x;
4160  nodesy[i] = minv[1] + median * y;
4161 
4162  nodes[i] = 1.0f;
4163  }
4164  }
4165 
4166  /* embed in grid */
4167  for (f = chart->faces; f; f = f->nextlink) {
4168  PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
4169  float fmin[2], fmax[2];
4170  int bx1, by1, bx2, by2;
4171 
4172  INIT_MINMAX2(fmin, fmax);
4173 
4174  minmax_v2v2_v2(fmin, fmax, e1->vert->uv);
4175  minmax_v2v2_v2(fmin, fmax, e2->vert->uv);
4176  minmax_v2v2_v2(fmin, fmax, e3->vert->uv);
4177 
4178  bx1 = (int)((fmin[0] - minv[0]) * invmedian);
4179  by1 = (int)((fmin[1] - minv[1]) * invmedian);
4180  bx2 = (int)((fmax[0] - minv[0]) * invmedian + 2);
4181  by2 = (int)((fmax[1] - minv[1]) * invmedian + 2);
4182 
4183  for (x = bx1; x < bx2; x++) {
4184  for (y = by1; y < by2; y++) {
4185  float p[2], b[3];
4186 
4187  i = x + y * gridx;
4188 
4189  p[0] = nodesx[i];
4190  p[1] = nodesy[i];
4191 
4192  p_barycentric_2d(e1->vert->uv, e2->vert->uv, e3->vert->uv, p, b);
4193 
4194  if ((b[0] > 0.0f) && (b[1] > 0.0f) && (b[2] > 0.0f)) {
4195  nodes[i] = e1->vert->u.distortion * b[0];
4196  nodes[i] += e2->vert->u.distortion * b[1];
4197  nodes[i] += e3->vert->u.distortion * b[2];
4198  }
4199  }
4200  }
4201  }
4202 
4203  /* smooth the grid */
4204  maxiter = 10;
4205  totiter = 0;
4206  climit = 0.00001f * nsize;
4207 
4208  for (it = 0; it < maxiter; it++) {
4209  moved = 0.0f;
4210 
4211  for (x = 0; x < edgesx; x++) {
4212  for (y = 0; y < edgesy; y++) {
4213  i = x + y * gridx;
4214  j = x + y * edgesx;
4215 
4216  hedges[j] = (nodes[i] + nodes[i + 1]) * 0.5f;
4217  vedges[j] = (nodes[i] + nodes[i + gridx]) * 0.5f;
4218 
4219  /* we do *inverse* mapping */
4220  hedges[j] = 1.0f / hedges[j];
4221  vedges[j] = 1.0f / vedges[j];
4222  }
4223  }
4224 
4225  maxiter2 = 50;
4226  dlimit = 0.0001f;
4227 
4228  for (it2 = 0; it2 < maxiter2; it2++) {
4229  d = 0.0f;
4230  totiter += 1;
4231 
4232  memcpy(oldnodesx, nodesx, sizeof(float) * nsize);
4233  memcpy(oldnodesy, nodesy, sizeof(float) * nsize);
4234 
4235  for (x = 1; x < gridx - 1; x++) {
4236  for (y = 1; y < gridy - 1; y++) {
4237  float p[2], oldp[2], sum1, sum2, diff[2], length;
4238 
4239  i = x + gridx * y;
4240  j = x + edgesx * y;
4241 
4242  oldp[0] = oldnodesx[i];
4243  oldp[1] = oldnodesy[i];
4244 
4245  sum1 = hedges[j - 1] * oldnodesx[i - 1];
4246  sum1 += hedges[j] * oldnodesx[i + 1];
4247  sum1 += vedges[j - edgesx] * oldnodesx[i - gridx];
4248  sum1 += vedges[j] * oldnodesx[i + gridx];
4249 
4250  sum2 = hedges[j - 1];
4251  sum2 += hedges[j];
4252  sum2 += vedges[j - edgesx];
4253  sum2 += vedges[j];
4254 
4255  nodesx[i] = sum1 / sum2;
4256 
4257  sum1 = hedges[j - 1] * oldnodesy[i - 1];
4258  sum1 += hedges[j] * oldnodesy[i + 1];
4259  sum1 += vedges[j - edgesx] * oldnodesy[i - gridx];
4260  sum1 += vedges[j] * oldnodesy[i + gridx];
4261 
4262  nodesy[i] = sum1 / sum2;
4263 
4264  p[0] = nodesx[i];
4265  p[1] = nodesy[i];
4266 
4267  diff[0] = p[0] - oldp[0];
4268  diff[1] = p[1] - oldp[1];
4269 
4270  length = len_v2(diff);
4271  d = max_ff(d, length);
4272  moved += length;
4273  }
4274  }
4275 
4276  if (d < dlimit) {
4277  break;
4278  }
4279  }
4280 
4281  if (moved < climit) {
4282  break;
4283  }
4284  }
4285 
4286  MEM_freeN(oldnodesx);
4287  MEM_freeN(oldnodesy);
4288  MEM_freeN(hedges);
4289  MEM_freeN(vedges);
4290 
4291  /* Create BSP. */
4292  t = triangles = MEM_mallocN(sizeof(SmoothTriangle) * esize * 2, "PSmoothTris");
4293  trip = tri = MEM_mallocN(sizeof(SmoothTriangle *) * esize * 2, "PSmoothTriP");
4294 
4295  if (!triangles || !tri) {
4296  MEM_freeN(nodes);
4297  MEM_freeN(nodesx);
4298  MEM_freeN(nodesy);
4299 
4300  if (triangles) {
4301  MEM_freeN(triangles);
4302  }
4303  if (tri) {
4304  MEM_freeN(tri);
4305  }
4306 
4307  // printf("Not enough memory for area smoothing grid");
4308  return;
4309  }
4310 
4311  for (x = 0; x < edgesx; x++) {
4312  for (y = 0; y < edgesy; y++) {
4313  i = x + y * gridx;
4314 
4315  t->co1[0] = nodesx[i];
4316  t->co1[1] = nodesy[i];
4317 
4318  t->co2[0] = nodesx[i + 1];
4319  t->co2[1] = nodesy[i + 1];
4320 
4321  t->co3[0] = nodesx[i + gridx];
4322  t->co3[1] = nodesy[i + gridx];
4323 
4324  t->oco1[0] = minv[0] + x * median;
4325  t->oco1[1] = minv[1] + y * median;
4326 
4327  t->oco2[0] = minv[0] + (x + 1) * median;
4328  t->oco2[1] = minv[1] + y * median;
4329 
4330  t->oco3[0] = minv[0] + x * median;
4331  t->oco3[1] = minv[1] + (y + 1) * median;
4332 
4333  t2 = t + 1;
4334 
4335  t2->co1[0] = nodesx[i + gridx + 1];
4336  t2->co1[1] = nodesy[i + gridx + 1];
4337 
4338  t2->oco1[0] = minv[0] + (x + 1) * median;
4339  t2->oco1[1] = minv[1] + (y + 1) * median;
4340 
4341  t2->co2[0] = t->co2[0];
4342  t2->co2[1] = t->co2[1];
4343  t2->oco2[0] = t->oco2[0];
4344  t2->oco2[1] = t->oco2[1];
4345 
4346  t2->co3[0] = t->co3[0];
4347  t2->co3[1] = t->co3[1];
4348  t2->oco3[0] = t->oco3[0];
4349  t2->oco3[1] = t->oco3[1];
4350 
4351  *trip = t;
4352  trip++;
4353  t++;
4354  *trip = t;
4355  trip++;
4356  t++;
4357  }
4358  }
4359 
4360  MEM_freeN(nodes);
4361  MEM_freeN(nodesx);
4362  MEM_freeN(nodesy);
4363 
4364  arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param smooth arena");
4365  root = p_node_new(arena, tri, esize * 2, minv, maxv, 0);
4366 
4367  for (v = chart->verts; v; v = v->nextlink) {
4368  if (!p_node_intersect(root, v->uv)) {
4369  param_warning("area smoothing error: couldn't find mapping triangle\n");
4370  }
4371  }
4372 
4373  p_node_delete(root);
4374  BLI_memarena_free(arena);
4375 
4376  MEM_freeN(triangles);
4377 }
4378 
4379 /* Exported */
4380 
4382 {
4383  PHandle *handle = MEM_callocN(sizeof(*handle), "PHandle");
4384  handle->construction_chart = p_chart_new(handle);
4385  handle->state = PHANDLE_STATE_ALLOCATED;
4386  handle->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param construct arena");
4387  handle->polyfill_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "param polyfill arena");
4389  handle->aspx = 1.0f;
4390  handle->aspy = 1.0f;
4391  handle->do_aspect = false;
4392 
4393  handle->hash_verts = phash_new((PHashLink **)&handle->construction_chart->verts, 1);
4394  handle->hash_edges = phash_new((PHashLink **)&handle->construction_chart->edges, 1);
4395  handle->hash_faces = phash_new((PHashLink **)&handle->construction_chart->faces, 1);
4396 
4397  return (ParamHandle *)handle;
4398 }
4399 
4400 void param_aspect_ratio(ParamHandle *handle, float aspx, float aspy)
4401 {
4402  PHandle *phandle = (PHandle *)handle;
4403 
4404  phandle->aspx = aspx;
4405  phandle->aspy = aspy;
4406  phandle->do_aspect = true;
4407 }
4408 
4410 {
4411  PHandle *phandle = (PHandle *)handle;
4412  int i;
4413 
4415 
4416  for (i = 0; i < phandle->ncharts; i++) {
4417  p_chart_delete(phandle->charts[i]);
4418  }
4419 
4420  if (phandle->charts) {
4421  MEM_freeN(phandle->charts);
4422  }
4423 
4424  if (phandle->construction_chart) {
4426 
4427  phash_delete(phandle->hash_verts);
4428  phash_delete(phandle->hash_edges);
4429  phash_delete(phandle->hash_faces);
4430  }
4431 
4432  BLI_memarena_free(phandle->arena);
4434  BLI_heap_free(phandle->polyfill_heap, NULL);
4435  MEM_freeN(phandle);
4436 }
4437 
4438 static void p_add_ngon(ParamHandle *handle,
4439  ParamKey key,
4440  int nverts,
4441  ParamKey *vkeys,
4442  float **co,
4443  float **uv,
4444  ParamBool *pin,
4445  ParamBool *select)
4446 {
4447  /* Allocate memory for polyfill. */
4448  PHandle *phandle = (PHandle *)handle;
4449  MemArena *arena = phandle->polyfill_arena;
4450  Heap *heap = phandle->polyfill_heap;
4451  uint nfilltri = nverts - 2;
4452  uint(*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri);
4453  float(*projverts)[2] = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts);
4454 
4455  /* Calc normal, flipped: to get a positive 2d cross product. */
4456  float normal[3];
4457  zero_v3(normal);
4458 
4459  const float *co_curr, *co_prev = co[nverts - 1];
4460  for (int j = 0; j < nverts; j++) {
4461  co_curr = co[j];
4462  add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
4463  co_prev = co_curr;
4464  }
4465  if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
4466  normal[2] = 1.0f;
4467  }
4468 
4469  /* Project verts to 2d. */
4470  float axis_mat[3][3];
4472  for (int j = 0; j < nverts; j++) {
4473  mul_v2_m3v3(projverts[j], axis_mat, co[j]);
4474  }
4475 
4476  BLI_polyfill_calc_arena(projverts, nverts, 1, tris, arena);
4477 
4478  /* Beautify helps avoid thin triangles that give numerical problems. */
4479  BLI_polyfill_beautify(projverts, nverts, tris, arena, heap);
4480 
4481  /* Add triangles. */
4482  for (int j = 0; j < nfilltri; j++) {
4483  uint *tri = tris[j];
4484  uint v0 = tri[0];
4485  uint v1 = tri[1];
4486  uint v2 = tri[2];
4487 
4488  ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]};
4489  float *tri_co[3] = {co[v0], co[v1], co[v2]};
4490  float *tri_uv[3] = {uv[v0], uv[v1], uv[v2]};
4491  ParamBool tri_pin[3] = {pin[v0], pin[v1], pin[v2]};
4492  ParamBool tri_select[3] = {select[v0], select[v1], select[v2]};
4493 
4494  param_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select);
4495  }
4496 
4497  BLI_memarena_clear(arena);
4498 }
4499 
4501  ParamKey key,
4502  int nverts,
4503  ParamKey *vkeys,
4504  float *co[4],
4505  float *uv[4],
4506  ParamBool *pin,
4507  ParamBool *select)
4508 {
4509  PHandle *phandle = (PHandle *)handle;
4510 
4511  param_assert(phash_lookup(phandle->hash_faces, key) == NULL);
4513  param_assert(ELEM(nverts, 3, 4));
4514 
4515  if (nverts > 4) {
4516  /* ngon */
4517  p_add_ngon(handle, key, nverts, vkeys, co, uv, pin, select);
4518  }
4519  else if (nverts == 4) {
4520  /* quad */
4521  if (p_quad_split_direction(phandle, co, vkeys)) {
4522  p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select);
4523  p_face_add_construct(phandle, key, vkeys, co, uv, 0, 2, 3, pin, select);
4524  }
4525  else {
4526  p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 3, pin, select);
4527  p_face_add_construct(phandle, key, vkeys, co, uv, 1, 2, 3, pin, select);
4528  }
4529  }
4530  else if (!p_face_exists(phandle, vkeys, 0, 1, 2)) {
4531  /* triangle */
4532  p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select);
4533  }
4534 }
4535 
4537 {
4538  PHandle *phandle = (PHandle *)handle;
4539  PEdge *e;
4540 
4542 
4543  e = p_edge_lookup(phandle, vkeys);
4544  if (e) {
4545  e->flag |= PEDGE_SEAM;
4546  }
4547 }
4548 
4550  ParamBool fill,
4551  ParamBool topology_from_uvs,
4552  int *count_fail)
4553 {
4554  PHandle *phandle = (PHandle *)handle;
4555  PChart *chart = phandle->construction_chart;
4556  int i, j, nboundaries = 0;
4557  PEdge *outer;
4558 
4560 
4561  phandle->ncharts = p_connect_pairs(phandle, (PBool)topology_from_uvs);
4562  phandle->charts = p_split_charts(phandle, chart, phandle->ncharts);
4563 
4565  phandle->construction_chart = NULL;
4566 
4567  phash_delete(phandle->hash_verts);
4568  phash_delete(phandle->hash_edges);
4569  phash_delete(phandle->hash_faces);
4570  phandle->hash_verts = phandle->hash_edges = phandle->hash_faces = NULL;
4571 
4572  for (i = j = 0; i < phandle->ncharts; i++) {
4573  PVert *v;
4574  chart = phandle->charts[i];
4575 
4576  p_chart_boundaries(chart, &nboundaries, &outer);
4577 
4578  if (!topology_from_uvs && nboundaries == 0) {
4579  p_chart_delete(chart);
4580  if (count_fail != NULL) {
4581  *count_fail += 1;
4582  }
4583  continue;
4584  }
4585 
4586  phandle->charts[j] = chart;
4587  j++;
4588 
4589  if (fill && (nboundaries > 1)) {
4590  p_chart_fill_boundaries(chart, outer);
4591  }
4592 
4593  for (v = chart->verts; v; v = v->nextlink) {
4594  p_vert_load_pin_select_uvs(handle, v);
4595  }
4596  }
4597 
4598  phandle->ncharts = j;
4599 
4600  phandle->state = PHANDLE_STATE_CONSTRUCTED;
4601 }
4602 
4604 {
4605  PHandle *phandle = (PHandle *)handle;
4606  PFace *f;
4607  int i;
4608 
4610  phandle->state = PHANDLE_STATE_LSCM;
4611 
4612  for (i = 0; i < phandle->ncharts; i++) {
4613  for (f = phandle->charts[i]->faces; f; f = f->nextlink) {
4614  p_face_backup_uvs(f);
4615  }
4616  p_chart_lscm_begin(phandle->charts[i], (PBool)live, (PBool)abf);
4617  }
4618 }
4619 
4620 void param_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed)
4621 {
4622  PHandle *phandle = (PHandle *)handle;
4623  PChart *chart;
4624  int i;
4625 
4626  param_assert(phandle->state == PHANDLE_STATE_LSCM);
4627 
4628  for (i = 0; i < phandle->ncharts; i++) {
4629  chart = phandle->charts[i];
4630 
4631  if (chart->u.lscm.context) {
4632  const PBool result = p_chart_lscm_solve(phandle, chart);
4633 
4634  if (result && !(chart->flag & PCHART_HAS_PINS)) {
4636  }
4637  else if (result && chart->u.lscm.single_pin) {
4638  p_chart_rotate_fit_aabb(chart);
4640  }
4641 
4642  if (!result || !(chart->flag & PCHART_HAS_PINS)) {
4643  p_chart_lscm_end(chart);
4644  }
4645 
4646  if (result) {
4647  if (count_changed != NULL) {
4648  *count_changed += 1;
4649  }
4650  }
4651  else {
4652  if (count_failed != NULL) {
4653  *count_failed += 1;
4654  }
4655  }
4656  }
4657  }
4658 }
4659 
4661 {
4662  PHandle *phandle = (PHandle *)handle;
4663  int i;
4664 
4665  param_assert(phandle->state == PHANDLE_STATE_LSCM);
4666 
4667  for (i = 0; i < phandle->ncharts; i++) {
4668  p_chart_lscm_end(phandle->charts[i]);
4669 #if 0
4670  p_chart_complexify(phandle->charts[i]);
4671 #endif
4672  }
4673 
4674  phandle->state = PHANDLE_STATE_CONSTRUCTED;
4675 }
4676 
4678 {
4679  PHandle *phandle = (PHandle *)handle;
4680  PChart *chart;
4681  PVert *v;
4682  PFace *f;
4683  int i;
4684 
4686  phandle->state = PHANDLE_STATE_STRETCH;
4687 
4688  phandle->rng = BLI_rng_new(31415926);
4689  phandle->blend = 0.0f;
4690 
4691  for (i = 0; i < phandle->ncharts; i++) {
4692  chart = phandle->charts[i];
4693 
4694  for (v = chart->verts; v; v = v->nextlink) {
4695  v->flag &= ~PVERT_PIN; /* don't use user-defined pins */
4696  }
4697 
4698  p_stretch_pin_boundary(chart);
4699 
4700  for (f = chart->faces; f; f = f->nextlink) {
4701  p_face_backup_uvs(f);
4702  f->u.area3d = p_face_area(f);
4703  }
4704  }
4705 }
4706 
4708 {
4709  PHandle *phandle = (PHandle *)handle;
4710 
4712  phandle->blend = blend;
4713 }
4714 
4716 {
4717  PHandle *phandle = (PHandle *)handle;
4718  PChart *chart;
4719  int i;
4720 
4722 
4723  for (i = 0; i < phandle->ncharts; i++) {
4724  chart = phandle->charts[i];
4725  p_chart_stretch_minimize(chart, phandle->rng);
4726  }
4727 }
4728 
4730 {
4731  PHandle *phandle = (PHandle *)handle;
4732 
4734  phandle->state = PHANDLE_STATE_CONSTRUCTED;
4735 
4736  BLI_rng_free(phandle->rng);
4737  phandle->rng = NULL;
4738 }
4739 
4741 {
4742  PHandle *phandle = (PHandle *)handle;
4743  int i;
4744 
4746 
4747  for (i = 0; i < phandle->ncharts; i++) {
4748  PChart *chart = phandle->charts[i];
4749  PVert *v;
4750 
4751  for (v = chart->verts; v; v = v->nextlink) {
4752  v->flag &= ~PVERT_PIN;
4753  }
4754 
4755  p_smooth(chart);
4756  }
4757 }
4758 
4759 /* don't pack, just rotate (used for better packing) */
4760 static void param_pack_rotate(ParamHandle *handle, bool ignore_pinned)
4761 {
4762  PChart *chart;
4763  int i;
4764 
4765  PHandle *phandle = (PHandle *)handle;
4766 
4767  for (i = 0; i < phandle->ncharts; i++) {
4768  chart = phandle->charts[i];
4769 
4770  if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
4771  continue;
4772  }
4773 
4774  p_chart_rotate_fit_aabb(chart);
4775  }
4776 }
4777 
4778 void param_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned)
4779 {
4780  /* box packing variables */
4781  BoxPack *boxarray, *box;
4782  float tot_width, tot_height, scale;
4783 
4784  PChart *chart;
4785  int i, unpacked = 0;
4786  float trans[2];
4787  double area = 0.0;
4788 
4789  PHandle *phandle = (PHandle *)handle;
4790 
4791  if (phandle->ncharts == 0) {
4792  return;
4793  }
4794 
4795  /* this could be its own function */
4796  if (do_rotate) {
4797  param_pack_rotate(handle, ignore_pinned);
4798  }
4799 
4800  if (phandle->aspx != phandle->aspy) {
4801  param_scale(handle, 1.0f / phandle->aspx, 1.0f / phandle->aspy);
4802  }
4803 
4804  /* we may not use all these boxes */
4805  boxarray = MEM_mallocN(phandle->ncharts * sizeof(BoxPack), "BoxPack box");
4806 
4807  for (i = 0; i < phandle->ncharts; i++) {
4808  chart = phandle->charts[i];
4809 
4810  if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
4811  unpacked++;
4812  continue;
4813  }
4814 
4815  box = boxarray + (i - unpacked);
4816 
4817  p_chart_uv_bbox(chart, trans, chart->u.pack.size);
4818 
4819  trans[0] = -trans[0];
4820  trans[1] = -trans[1];
4821 
4822  p_chart_uv_translate(chart, trans);
4823 
4824  box->w = chart->u.pack.size[0] + trans[0];
4825  box->h = chart->u.pack.size[1] + trans[1];
4826  box->index = i; /* warning this index skips PCHART_HAS_PINS boxes */
4827 
4828  if (margin > 0.0f) {
4829  area += (double)sqrtf(box->w * box->h);
4830  }
4831  }
4832 
4833  if (margin > 0.0f) {
4834  /* multiply the margin by the area to give predictable results not dependent on UV scale,
4835  * ...Without using the area running pack multiple times also gives a bad feedback loop.
4836  * multiply by 0.1 so the margin value from the UI can be from
4837  * 0.0 to 1.0 but not give a massive margin */
4838  margin = (margin * (float)area) * 0.1f;
4839  unpacked = 0;
4840  for (i = 0; i < phandle->ncharts; i++) {
4841  chart = phandle->charts[i];
4842 
4843  if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
4844  unpacked++;
4845  continue;
4846  }
4847 
4848  box = boxarray + (i - unpacked);
4849  trans[0] = margin;
4850  trans[1] = margin;
4851  p_chart_uv_translate(chart, trans);
4852  box->w += margin * 2;
4853  box->h += margin * 2;
4854  }
4855  }
4856 
4857  BLI_box_pack_2d(boxarray, phandle->ncharts - unpacked, &tot_width, &tot_height);
4858 
4859  if (tot_height > tot_width) {
4860  scale = 1.0f / tot_height;
4861  }
4862  else {
4863  scale = 1.0f / tot_width;
4864  }
4865 
4866  for (i = 0; i < phandle->ncharts - unpacked; i++) {
4867  box = boxarray + i;
4868  trans[0] = box->x;
4869  trans[1] = box->y;
4870 
4871  chart = phandle->charts[box->index];
4872  p_chart_uv_translate(chart, trans);
4873  p_chart_uv_scale(chart, scale);
4874  }
4875  MEM_freeN(boxarray);
4876 
4877  if (phandle->aspx != phandle->aspy) {
4878  param_scale(handle, phandle->aspx, phandle->aspy);
4879  }
4880 }
4881 
4882 void param_average(ParamHandle *handle, bool ignore_pinned)
4883 {
4884  PChart *chart;
4885  int i;
4886  float tot_uvarea = 0.0f, tot_facearea = 0.0f;
4887  float tot_fac, fac;
4888  float minv[2], maxv[2], trans[2];
4889  PHandle *phandle = (PHandle *)handle;
4890 
4891  if (phandle->ncharts == 0) {
4892  return;
4893  }
4894 
4895  for (i = 0; i < phandle->ncharts; i++) {
4896  PFace *f;
4897  chart = phandle->charts[i];
4898 
4899  if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
4900  continue;
4901  }
4902 
4903  chart->u.pack.area = 0.0f; /* 3d area */
4904  chart->u.pack.rescale = 0.0f; /* UV area, abusing rescale for tmp storage, oh well :/ */
4905 
4906  for (f = chart->faces; f; f = f->nextlink) {
4907  chart->u.pack.area += p_face_area(f);
4908  chart->u.pack.rescale += fabsf(p_face_uv_area_signed(f));
4909  }
4910 
4911  tot_facearea += chart->u.pack.area;
4912  tot_uvarea += chart->u.pack.rescale;
4913  }
4914 
4915  if (tot_facearea == tot_uvarea || tot_facearea == 0.0f || tot_uvarea == 0.0f) {
4916  /* nothing to do */
4917  return;
4918  }
4919 
4920  tot_fac = tot_facearea / tot_uvarea;
4921 
4922  for (i = 0; i < phandle->ncharts; i++) {
4923  chart = phandle->charts[i];
4924 
4925  if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
4926  continue;
4927  }
4928 
4929  if (chart->u.pack.area != 0.0f && chart->u.pack.rescale != 0.0f) {
4930  fac = chart->u.pack.area / chart->u.pack.rescale;
4931 
4932  /* Get the island center */
4933  p_chart_uv_bbox(chart, minv, maxv);
4934  trans[0] = (minv[0] + maxv[0]) / -2.0f;
4935  trans[1] = (minv[1] + maxv[1]) / -2.0f;
4936 
4937  /* Move center to 0,0 */
4938  p_chart_uv_translate(chart, trans);
4939  p_chart_uv_scale(chart, sqrtf(fac / tot_fac));
4940 
4941  /* Move to original center */
4942  trans[0] = -trans[0];
4943  trans[1] = -trans[1];
4944  p_chart_uv_translate(chart, trans);
4945  }
4946  }
4947 }
4948 
4949 void param_scale(ParamHandle *handle, float x, float y)
4950 {
4951  PHandle *phandle = (PHandle *)handle;
4952  PChart *chart;
4953  int i;
4954 
4955  for (i = 0; i < phandle->ncharts; i++) {
4956  chart = phandle->charts[i];
4957  p_chart_uv_scale_xy(chart, x, y);
4958  }
4959 }
4960 
4962 {
4963  PHandle *phandle = (PHandle *)handle;
4964  PChart *chart;
4965  int i;
4966 
4967  for (i = 0; i < phandle->ncharts; i++) {
4968  chart = phandle->charts[i];
4969 
4970  if ((phandle->state == PHANDLE_STATE_LSCM) && !chart->u.lscm.context) {
4971  continue;
4972  }
4973 
4974  if (phandle->blend == 0.0f) {
4975  p_flush_uvs(phandle, chart);
4976  }
4977  else {
4978  p_flush_uvs_blend(phandle, chart, phandle->blend);
4979  }
4980  }
4981 }
4982 
4984 {
4985  PHandle *phandle = (PHandle *)handle;
4986  PChart *chart;
4987  PFace *f;
4988  int i;
4989 
4990  for (i = 0; i < phandle->ncharts; i++) {
4991  chart = phandle->charts[i];
4992 
4993  for (f = chart->faces; f; f = f->nextlink) {
4994  p_face_restore_uvs(f);
4995  }
4996  }
4997 }
typedef float(TangentPoint)[2]
void BLI_box_pack_2d(BoxPack *boxarray, const unsigned int len, float *r_tot_x, float *r_tot_y)
Definition: boxpack_2d.c:294
float BLI_convexhull_aabb_fit_points_2d(const float(*points)[2], unsigned int n)
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition: BLI_heap.c:221
Heap * BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT
Definition: BLI_heap.c:201
void void bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1)
Definition: BLI_heap.c:305
void * BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1)
Definition: BLI_heap.c:338
HeapNode * BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1)
Definition: BLI_heap.c:268
HeapNode * BLI_heap_top(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:319
Heap * BLI_heap_new(void) ATTR_WARN_UNUSED_RESULT
Definition: BLI_heap.c:216
void void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1
MINLINE float max_fff(float a, float b, float c)
MINLINE float max_ff(float a, float b)
#define M_PI
Definition: BLI_math_base.h:38
float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:315
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
Definition: math_geom.c:3772
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:116
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
Definition: math_matrix.c:921
void mul_m2_v2(const float M[2][2], float v[2])
Definition: math_matrix.c:788
void angle_to_mat2(float R[2][2], const float angle)
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float r[3])
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void 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])
Definition: math_vector.c:1043
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void 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 bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:109
#define BLI_MEMARENA_STD_BUFSIZE
Definition: BLI_memarena.h:36
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:131
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:185
struct MemArena * BLI_memarena_new(const size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:79
void BLI_polyfill_calc_arena(const float(*coords)[2], const unsigned int coords_tot, const int coords_sign, unsigned int(*r_tris)[3], struct MemArena *arena)
Definition: polyfill_2d.c:847
#define BLI_POLYFILL_ALLOC_NGON_RESERVE
void BLI_polyfill_beautify(const float(*coords)[2], const unsigned int coords_tot, unsigned int(*tris)[3], struct MemArena *arena, struct Heap *eheap)
Random number functions.
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition: rand.cc:76
struct RNG * BLI_rng_new(unsigned int seed)
Definition: rand.cc:54
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: rand.cc:120
unsigned char uchar
Definition: BLI_sys_types.h:86
unsigned int uint
Definition: BLI_sys_types.h:83
unsigned short ushort
Definition: BLI_sys_types.h:84
#define INIT_MINMAX2(min, max)
#define UNUSED_FUNCTION(x)
#define SWAP(type, a, b)
#define SHIFT3(type, a, b, c)
#define UNLIKELY(x)
#define ELEM(...)
typedef double(DMatrix)[4][4]
NSNotificationCenter * center
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble u2
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble u1
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble x2
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble right
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint i1
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define MEM_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
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
static T sum(const btAlignedObjectArray< T > &items)
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
Definition: btVector3.h:263
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
OperationNode * node
static CCL_NAMESPACE_BEGIN const double alpha
static float verts[][3]
uint padding(uint offset, uint alignment)
IconTextureDrawCall normal
#define sinf(x)
#define cosf(x)
#define acosf(x)
#define fabsf(x)
#define sqrtf(x)
void EIG_linear_solver_variable_set(LinearSolver *solver, int rhs, int index, double value)
LinearSolver * EIG_linear_solver_new(int num_rows, int num_columns, int num_rhs)
void EIG_linear_solver_right_hand_side_add(LinearSolver *solver, int rhs, int index, double value)
LinearSolver * EIG_linear_least_squares_solver_new(int num_rows, int num_columns, int num_rhs)
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_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static ulong * next
static int corner1[12]
#define T
#define L
static char faces[256]
static int corner2[12]
bool isfinite(uchar)
Definition: image.cpp:44
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt=1)
static void area(int d1, int d2, int e1, int e2, float weights[2])
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:115
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
#define hash
Definition: noise.c:169
struct SELECTID_Context context
Definition: select_engine.c:47
_W64 unsigned int uintptr_t
Definition: stdint.h:122
_W64 int intptr_t
Definition: stdint.h:121
float co[3]
Definition: bmesh_class.h:99
Definition: BLI_heap.c:57
float(* J2dt)[3]
PFace * collapsed_faces
PVert * collapsed_verts
struct PHandle * handle
PEdge * collapsed_edges
union PChart::PChartUnion u
struct PFace * face
float old_uv[2]
struct PEdge * nextlink
struct PEdge * next
float * orig_uv
struct PEdge * pair
struct PVert * vert
union PEdge::PEdgeUnion u
struct PFace * nextlink
struct PEdge * edge
union PFace::PFaceUnion u
PHash * hash_faces
PHash * hash_verts
PChart ** charts
Heap * polyfill_heap
PHash * hash_edges
MemArena * polyfill_arena
MemArena * arena
PChart * construction_chart
enum PHandleState state
PHashLink ** buckets
PHashLink ** list
union PVert::PVertUnion u
struct PVert * nextlink
float uv[2]
struct PEdge * edge
float co[3]
Definition: rand.cc:48
struct SmoothNode * c1
SmoothTriangle ** tri
struct SmoothNode * c2
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
struct PChart::PChartUnion::PChartLscm lscm
struct PChart::PChartUnion::PChartPack pack
struct PEdge * nextcollapse
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
__forceinline ssef low(const avxf &a)
Definition: util_avxf.h:277
__forceinline ssef high(const avxf &a)
Definition: util_avxf.h:281
ccl_device_inline float beta(float x, float y)
Definition: util_math.h:666
static void p_flush_uvs_blend(PHandle *handle, PChart *chart, float blend)
static void phash_insert(PHash *ph, PHashLink *link)
static float p_face_stretch(PFace *f)
void param_stretch_begin(ParamHandle *handle)
struct PChart PChart
static void p_triangle_angles(const float v1[3], const float v2[3], const float v3[3], float *r_a1, float *r_a2, float *r_a3)
@ PCHART_HAS_PINS
struct SmoothTriangle SmoothTriangle
static PFace * p_face_add_construct(PHandle *handle, ParamKey key, const ParamKey *vkeys, float *co[4], float *uv[4], int i1, int i2, int i3, const ParamBool *pin, const ParamBool *select)
static float p_vec_angle_cos(const float v1[3], const float v2[3], const float v3[3])
static float p_abf_compute_grad_alpha(PAbfSystem *sys, PFace *f, PEdge *e)
static PChart ** p_split_charts(PHandle *handle, PChart *chart, int ncharts)
void param_stretch_iter(ParamHandle *handle)
void param_stretch_end(ParamHandle *handle)
struct PHandle PHandle
struct PVert PVert
static void p_split_vert(PChart *chart, PEdge *e)
void param_delete(ParamHandle *handle)
#define PHASH_hash(ph, item)
static void p_smooth(PChart *chart)
static float p_edge_boundary_angle(PEdge *e)
static void p_chart_lscm_load_solution(PChart *chart)
static void p_chart_fill_boundaries(PChart *chart, PEdge *outer)
static void p_chart_uv_to_array(PChart *chart, float(*points)[2])
static void p_abf_setup_system(PAbfSystem *sys)
void param_flush_restore(ParamHandle *handle)
static float p_abf_compute_sin_product(PAbfSystem *sys, PVert *v, int aid)
void param_aspect_ratio(ParamHandle *handle, float aspx, float aspy)
static float p_edge_length(PEdge *e)
static PEdge * p_wheel_edge_next(PEdge *e)
static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool topology_from_uvs, PEdge **r_pair)
struct PHash PHash
static void p_chart_rotate_fit_aabb(PChart *chart)
static void p_node_delete(SmoothNode *node)
void param_flush(ParamHandle *handle)
struct PFace PFace
static PBool p_chart_abf_solve(PChart *chart)
static void p_stretch_pin_boundary(PChart *chart)
static int p_face_exists(ParamHandle *phandle, ParamKey *pvkeys, int i1, int i2, int i3)
ParamHandle * param_construct_begin(void)
static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
static float p_area_signed(const float v1[2], const float v2[2], const float v3[2])
static PHash * phash_new(PHashLink **list, int sizehint)
static PVert * p_vert_lookup(PHandle *handle, PHashKey key, const float co[3], PEdge *e)
static PBool 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])
static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
#define param_assert(condition)
#define PHASH_edge(v1, v2)
static PBool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, int *r_right)
void param_scale(ParamHandle *handle, float x, float y)
struct PAbfSystem PAbfSystem
void param_average(ParamHandle *handle, bool ignore_pinned)
static void p_chart_lscm_end(PChart *chart)
static void p_chart_extrema_verts(PChart *chart, PVert **pin1, PVert **pin2)
static PBool p_triangle_inside(SmoothTriangle *t, float co[2])
static float p_face_uv_area_signed(PFace *f)
void param_face_add(ParamHandle *handle, ParamKey key, int nverts, ParamKey *vkeys, float *co[4], float *uv[4], ParamBool *pin, ParamBool *select)
static PBool p_vert_interior(PVert *v)
static void p_chart_uv_translate(PChart *chart, const float trans[2])
#define PEDGE_VERTEX_FLAGS
static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep)
#define P_STRETCH_ITER
static void p_abf_compute_sines(PAbfSystem *sys)
static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2)
static void phash_delete(PHash *ph)
static float p_chart_uv_area(PChart *chart)
static SmoothNode * p_node_new(MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth)
static PVert * p_vert_copy(PChart *chart, PVert *v)
static float p_vec2_angle(const float v1[2], const float v2[2], const float v3[2])
static int p_compare_float(const void *a_, const void *b_)
static PHashLink * phash_next(PHash *ph, PHashKey key, PHashLink *link)
static void UNUSED_FUNCTION() p_chart_uv_from_array(PChart *chart, float(*points)[2])
static PEdge * p_boundary_edge_prev(PEdge *e)
void param_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf)
static void p_barycentric_2d(const float v1[2], const float v2[2], const float v3[2], const float p[2], float b[3])
static PBool p_node_intersect(SmoothNode *node, float co[2])
void param_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned)
static int PHashSizes[]
static PBool p_quad_split_direction(PHandle *handle, float **co, PHashKey *vkeys)
static float p_smooth_distortion(PEdge *e, float avg2d, float avg3d)
static void p_chart_uv_transform(PChart *chart, const float mat[2][2])
void param_smooth_area(ParamHandle *handle)
void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys)
static PFace * p_face_add_fill(PChart *chart, PVert *v1, PVert *v2, PVert *v3)
static void p_abf_free_system(PAbfSystem *sys)
static int p_connect_pairs(PHandle *handle, PBool topology_from_uvs)
static PFace * p_face_add(PHandle *handle)
static void p_chart_rotate_minimum_area(PChart *chart)
static float p_rectangle_area(float *p1, float *dir, float *p2, float *p3, float *p4)
void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool topology_from_uvs, int *count_fail)
static PEdge * p_boundary_edge_next(PEdge *e)
@ PEDGE_DONE
@ PEDGE_SEAM
@ PEDGE_COLLAPSE_PAIR
@ PEDGE_FILLED
@ PEDGE_COLLAPSE_EDGE
@ PEDGE_COLLAPSE
@ PEDGE_VERTEX_SPLIT
@ PEDGE_SELECT
@ PEDGE_PIN
static void p_chart_stretch_minimize(PChart *chart, RNG *rng)
static void p_chart_uv_scale(PChart *chart, float scale)
static void p_flush_uvs(PHandle *handle, PChart *chart)
@ PFACE_CONNECTED
@ PFACE_COLLAPSE
@ PFACE_FILLED
static void p_chart_delete(PChart *chart)
static void p_face_backup_uvs(PFace *f)
static int p_compare_geometric_uv(const void *a, const void *b)
#define ABF_MAX_ITER
static void p_chart_uv_bbox(PChart *chart, float minv[2], float maxv[2])
@ PVERT_INTERIOR
@ PVERT_COLLAPSE
@ PVERT_PIN
@ PVERT_SPLIT
@ PVERT_SELECT
static void p_face_flip(PFace *f)
struct PHashLink PHashLink
static float p_stretch_compute_vertex(PVert *v)
static float p_chart_minimum_area_angle(PChart *chart)
void param_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed)
static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2)
static PEdge * p_edge_lookup(PHandle *handle, const PHashKey *vkeys)
static PEdge * p_wheel_edge_prev(PEdge *e)
#define param_warning(message)
static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
intptr_t PHashKey
static float p_edge_uv_length(PEdge *e)
static int phash_size(PHash *ph)
static float p_face_area(PFace *f)
static void p_vert_load_pin_select_uvs(PHandle *handle, PVert *v)
void param_lscm_end(ParamHandle *handle)
static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges)
static PHashLink * phash_lookup(PHash *ph, PHashKey key)
static PVert * p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge *e)
static void p_chart_uv_scale_xy(PChart *chart, float x, float y)
static void p_face_restore_uvs(PFace *f)
static PBool p_edge_connect_pair(PHandle *handle, PEdge *e, PBool topology_from_uvs, PEdge ***stack)
static void p_add_ngon(ParamHandle *handle, ParamKey key, int nverts, ParamKey *vkeys, float **co, float **uv, ParamBool *pin, ParamBool *select)
@ PHANDLE_STATE_LSCM
@ PHANDLE_STATE_ALLOCATED
@ PHANDLE_STATE_CONSTRUCTED
@ PHANDLE_STATE_STRETCH
static void param_pack_rotate(ParamHandle *handle, bool ignore_pinned)
static void p_face_angles(PFace *f, float *r_a1, float *r_a2, float *r_a3)
static PChart * p_chart_new(PHandle *handle)
struct PEdge PEdge
@ P_FALSE
@ P_TRUE
static float p_smooth_median_edge_length(PChart *chart)
void param_stretch_blend(ParamHandle *handle, float blend)
static float p_vec_angle(const float v1[3], const float v2[3], const float v3[3])
static void p_chart_boundaries(PChart *chart, int *r_nboundaries, PEdge **r_outer)
struct SmoothNode SmoothNode
static float p_abf_compute_gradient(PAbfSystem *sys, PChart *chart)
static void p_chart_lscm_transform_single_pin(PChart *chart)
void ParamHandle
intptr_t ParamKey
uint len