|
Blender
V2.59
|
00001 00005 #include "MEM_guardedalloc.h" 00006 00007 #include "BLI_memarena.h" 00008 #include "BLI_math.h" 00009 #include "BLI_rand.h" 00010 #include "BLI_heap.h" 00011 #include "BLI_boxpack2d.h" 00012 #include "BLI_utildefines.h" 00013 00014 00015 00016 #include "ONL_opennl.h" 00017 00018 #include "uvedit_intern.h" 00019 #include "uvedit_parametrizer.h" 00020 00021 #include <math.h> 00022 #include <stdlib.h> 00023 #include <stdio.h> 00024 #include <string.h> 00025 00026 #include "BLO_sys_types.h" // for intptr_t support 00027 00028 #if defined(_WIN32) 00029 #define M_PI 3.14159265358979323846 00030 #endif 00031 00032 /* Utils */ 00033 00034 #if 0 00035 #define param_assert(condition); 00036 #define param_warning(message); 00037 #define param_test_equals_ptr(condition); 00038 #define param_test_equals_int(condition); 00039 #else 00040 #define param_assert(condition) \ 00041 if (!(condition)) \ 00042 { /*printf("Assertion %s:%d\n", __FILE__, __LINE__); abort();*/ } 00043 #define param_warning(message) \ 00044 { /*printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);*/ } 00045 #define param_test_equals_ptr(str, a, b) \ 00046 if (a != b) \ 00047 { /*printf("Equals %s => %p != %p\n", str, a, b);*/ }; 00048 #define param_test_equals_int(str, a, b) \ 00049 if (a != b) \ 00050 { /*printf("Equals %s => %d != %d\n", str, a, b);*/ }; 00051 #endif 00052 00053 typedef enum PBool { 00054 P_TRUE = 1, 00055 P_FALSE = 0 00056 } PBool; 00057 00058 /* Special Purpose Hash */ 00059 00060 typedef intptr_t PHashKey; 00061 00062 typedef struct PHashLink { 00063 struct PHashLink *next; 00064 PHashKey key; 00065 } PHashLink; 00066 00067 typedef struct PHash { 00068 PHashLink **list; 00069 PHashLink **buckets; 00070 int size, cursize, cursize_id; 00071 } PHash; 00072 00073 00074 00075 struct PVert; 00076 struct PEdge; 00077 struct PFace; 00078 struct PChart; 00079 struct PHandle; 00080 00081 /* Simplices */ 00082 00083 typedef struct PVert { 00084 struct PVert *nextlink; 00085 00086 union PVertUnion { 00087 PHashKey key; /* construct */ 00088 int id; /* abf/lscm matrix index */ 00089 float distortion; /* area smoothing */ 00090 HeapNode *heaplink; /* edge collapsing */ 00091 } u; 00092 00093 struct PEdge *edge; 00094 float *co; 00095 float uv[2]; 00096 unsigned char flag; 00097 00098 } PVert; 00099 00100 typedef struct PEdge { 00101 struct PEdge *nextlink; 00102 00103 union PEdgeUnion { 00104 PHashKey key; /* construct */ 00105 int id; /* abf matrix index */ 00106 HeapNode *heaplink; /* fill holes */ 00107 struct PEdge *nextcollapse; /* simplification */ 00108 } u; 00109 00110 struct PVert *vert; 00111 struct PEdge *pair; 00112 struct PEdge *next; 00113 struct PFace *face; 00114 float *orig_uv, old_uv[2]; 00115 unsigned short flag; 00116 00117 } PEdge; 00118 00119 typedef struct PFace { 00120 struct PFace *nextlink; 00121 00122 union PFaceUnion { 00123 PHashKey key; /* construct */ 00124 int chart; /* construct splitting*/ 00125 float area3d; /* stretch */ 00126 int id; /* abf matrix index */ 00127 } u; 00128 00129 struct PEdge *edge; 00130 unsigned char flag; 00131 00132 } PFace; 00133 00134 enum PVertFlag { 00135 PVERT_PIN = 1, 00136 PVERT_SELECT = 2, 00137 PVERT_INTERIOR = 4, 00138 PVERT_COLLAPSE = 8, 00139 PVERT_SPLIT = 16 00140 }; 00141 00142 enum PEdgeFlag { 00143 PEDGE_SEAM = 1, 00144 PEDGE_VERTEX_SPLIT = 2, 00145 PEDGE_PIN = 4, 00146 PEDGE_SELECT = 8, 00147 PEDGE_DONE = 16, 00148 PEDGE_FILLED = 32, 00149 PEDGE_COLLAPSE = 64, 00150 PEDGE_COLLAPSE_EDGE = 128, 00151 PEDGE_COLLAPSE_PAIR = 256 00152 }; 00153 00154 /* for flipping faces */ 00155 #define PEDGE_VERTEX_FLAGS (PEDGE_PIN) 00156 00157 enum PFaceFlag { 00158 PFACE_CONNECTED = 1, 00159 PFACE_FILLED = 2, 00160 PFACE_COLLAPSE = 4 00161 }; 00162 00163 /* Chart */ 00164 00165 typedef struct PChart { 00166 PVert *verts; 00167 PEdge *edges; 00168 PFace *faces; 00169 int nverts, nedges, nfaces; 00170 00171 PVert *collapsed_verts; 00172 PEdge *collapsed_edges; 00173 PFace *collapsed_faces; 00174 00175 union PChartUnion { 00176 struct PChartLscm { 00177 NLContext context; 00178 float *abf_alpha; 00179 PVert *pin1, *pin2; 00180 } lscm; 00181 struct PChartPack { 00182 float rescale, area; 00183 float size[2], trans[2]; 00184 } pack; 00185 } u; 00186 00187 unsigned char flag; 00188 struct PHandle *handle; 00189 } PChart; 00190 00191 enum PChartFlag { 00192 PCHART_NOPACK = 1 00193 }; 00194 00195 enum PHandleState { 00196 PHANDLE_STATE_ALLOCATED, 00197 PHANDLE_STATE_CONSTRUCTED, 00198 PHANDLE_STATE_LSCM, 00199 PHANDLE_STATE_STRETCH 00200 }; 00201 00202 typedef struct PHandle { 00203 enum PHandleState state; 00204 MemArena *arena; 00205 00206 PChart *construction_chart; 00207 PHash *hash_verts; 00208 PHash *hash_edges; 00209 PHash *hash_faces; 00210 00211 PChart **charts; 00212 int ncharts; 00213 00214 float aspx, aspy; 00215 00216 RNG *rng; 00217 float blend; 00218 } PHandle; 00219 00220 00221 /* PHash 00222 - special purpose hash that keeps all its elements in a single linked list. 00223 - after construction, this hash is thrown away, and the list remains. 00224 - removing elements is not possible efficiently. 00225 */ 00226 00227 static int PHashSizes[] = { 00228 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, 00229 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, 00230 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459 00231 }; 00232 00233 #define PHASH_hash(ph, item) (((uintptr_t) (item))%((unsigned int) (ph)->cursize)) 00234 #define PHASH_edge(v1, v2) ((v1)^(v2)) 00235 00236 static PHash *phash_new(PHashLink **list, int sizehint) 00237 { 00238 PHash *ph = (PHash*)MEM_callocN(sizeof(PHash), "PHash"); 00239 ph->size = 0; 00240 ph->cursize_id = 0; 00241 ph->list = list; 00242 00243 while (PHashSizes[ph->cursize_id] < sizehint) 00244 ph->cursize_id++; 00245 00246 ph->cursize = PHashSizes[ph->cursize_id]; 00247 ph->buckets = (PHashLink**)MEM_callocN(ph->cursize*sizeof(*ph->buckets), "PHashBuckets"); 00248 00249 return ph; 00250 } 00251 00252 static void phash_delete(PHash *ph) 00253 { 00254 MEM_freeN(ph->buckets); 00255 MEM_freeN(ph); 00256 } 00257 00258 static int phash_size(PHash *ph) 00259 { 00260 return ph->size; 00261 } 00262 00263 static void phash_insert(PHash *ph, PHashLink *link) 00264 { 00265 int size = ph->cursize; 00266 uintptr_t hash = PHASH_hash(ph, link->key); 00267 PHashLink *lookup = ph->buckets[hash]; 00268 00269 if (lookup == NULL) { 00270 /* insert in front of the list */ 00271 ph->buckets[hash] = link; 00272 link->next = *(ph->list); 00273 *(ph->list) = link; 00274 } 00275 else { 00276 /* insert after existing element */ 00277 link->next = lookup->next; 00278 lookup->next = link; 00279 } 00280 00281 ph->size++; 00282 00283 if (ph->size > (size*3)) { 00284 PHashLink *next = NULL, *first = *(ph->list); 00285 00286 ph->cursize = PHashSizes[++ph->cursize_id]; 00287 MEM_freeN(ph->buckets); 00288 ph->buckets = (PHashLink**)MEM_callocN(ph->cursize*sizeof(*ph->buckets), "PHashBuckets"); 00289 ph->size = 0; 00290 *(ph->list) = NULL; 00291 00292 for (link = first; link; link = next) { 00293 next = link->next; 00294 phash_insert(ph, link); 00295 } 00296 } 00297 } 00298 00299 static PHashLink *phash_lookup(PHash *ph, PHashKey key) 00300 { 00301 PHashLink *link; 00302 uintptr_t hash = PHASH_hash(ph, key); 00303 00304 for (link = ph->buckets[hash]; link; link = link->next) 00305 if (link->key == key) 00306 return link; 00307 else if (PHASH_hash(ph, link->key) != hash) 00308 return NULL; 00309 00310 return link; 00311 } 00312 00313 static PHashLink *phash_next(PHash *ph, PHashKey key, PHashLink *link) 00314 { 00315 uintptr_t hash = PHASH_hash(ph, key); 00316 00317 for (link = link->next; link; link = link->next) 00318 if (link->key == key) 00319 return link; 00320 else if (PHASH_hash(ph, link->key) != hash) 00321 return NULL; 00322 00323 return link; 00324 } 00325 00326 /* Geometry */ 00327 00328 static float p_vec_angle_cos(float *v1, float *v2, float *v3) 00329 { 00330 float d1[3], d2[3]; 00331 00332 d1[0] = v1[0] - v2[0]; 00333 d1[1] = v1[1] - v2[1]; 00334 d1[2] = v1[2] - v2[2]; 00335 00336 d2[0] = v3[0] - v2[0]; 00337 d2[1] = v3[1] - v2[1]; 00338 d2[2] = v3[2] - v2[2]; 00339 00340 normalize_v3(d1); 00341 normalize_v3(d2); 00342 00343 return d1[0]*d2[0] + d1[1]*d2[1] + d1[2]*d2[2]; 00344 } 00345 00346 static float p_vec_angle(float *v1, float *v2, float *v3) 00347 { 00348 float dot = p_vec_angle_cos(v1, v2, v3); 00349 00350 if (dot <= -1.0f) 00351 return (float)M_PI; 00352 else if (dot >= 1.0f) 00353 return 0.0f; 00354 else 00355 return (float)acos(dot); 00356 } 00357 00358 static float p_vec2_angle(float *v1, float *v2, float *v3) 00359 { 00360 float u1[3], u2[3], u3[3]; 00361 00362 u1[0] = v1[0]; u1[1] = v1[1]; u1[2] = 0.0f; 00363 u2[0] = v2[0]; u2[1] = v2[1]; u2[2] = 0.0f; 00364 u3[0] = v3[0]; u3[1] = v3[1]; u3[2] = 0.0f; 00365 00366 return p_vec_angle(u1, u2, u3); 00367 } 00368 00369 static void p_triangle_angles(float *v1, float *v2, float *v3, float *a1, float *a2, float *a3) 00370 { 00371 *a1 = p_vec_angle(v3, v1, v2); 00372 *a2 = p_vec_angle(v1, v2, v3); 00373 *a3 = (float)M_PI - *a2 - *a1; 00374 } 00375 00376 static void p_face_angles(PFace *f, float *a1, float *a2, float *a3) 00377 { 00378 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 00379 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; 00380 00381 p_triangle_angles(v1->co, v2->co, v3->co, a1, a2, a3); 00382 } 00383 00384 static float p_face_area(PFace *f) 00385 { 00386 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 00387 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; 00388 00389 return area_tri_v3(v1->co, v2->co, v3->co); 00390 } 00391 00392 static float p_area_signed(float *v1, float *v2, float *v3) 00393 { 00394 return 0.5f*(((v2[0] - v1[0])*(v3[1] - v1[1])) - 00395 ((v3[0] - v1[0])*(v2[1] - v1[1]))); 00396 } 00397 00398 static float p_face_uv_area_signed(PFace *f) 00399 { 00400 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 00401 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; 00402 00403 return 0.5f*(((v2->uv[0] - v1->uv[0])*(v3->uv[1] - v1->uv[1])) - 00404 ((v3->uv[0] - v1->uv[0])*(v2->uv[1] - v1->uv[1]))); 00405 } 00406 00407 static float p_edge_length(PEdge *e) 00408 { 00409 PVert *v1 = e->vert, *v2 = e->next->vert; 00410 float d[3]; 00411 00412 d[0] = v2->co[0] - v1->co[0]; 00413 d[1] = v2->co[1] - v1->co[1]; 00414 d[2] = v2->co[2] - v1->co[2]; 00415 00416 return sqrt(d[0]*d[0] + d[1]*d[1] + d[2]*d[2]); 00417 } 00418 00419 static float p_edge_uv_length(PEdge *e) 00420 { 00421 PVert *v1 = e->vert, *v2 = e->next->vert; 00422 float d[3]; 00423 00424 d[0] = v2->uv[0] - v1->uv[0]; 00425 d[1] = v2->uv[1] - v1->uv[1]; 00426 00427 return sqrt(d[0]*d[0] + d[1]*d[1]); 00428 } 00429 00430 static void p_chart_uv_bbox(PChart *chart, float *minv, float *maxv) 00431 { 00432 PVert *v; 00433 00434 INIT_MINMAX2(minv, maxv); 00435 00436 for (v=chart->verts; v; v=v->nextlink) { 00437 DO_MINMAX2(v->uv, minv, maxv); 00438 } 00439 } 00440 00441 static void p_chart_uv_scale(PChart *chart, float scale) 00442 { 00443 PVert *v; 00444 00445 for (v=chart->verts; v; v=v->nextlink) { 00446 v->uv[0] *= scale; 00447 v->uv[1] *= scale; 00448 } 00449 } 00450 00451 static void p_chart_uv_scale_xy(PChart *chart, float x, float y) 00452 { 00453 PVert *v; 00454 00455 for (v=chart->verts; v; v=v->nextlink) { 00456 v->uv[0] *= x; 00457 v->uv[1] *= y; 00458 } 00459 } 00460 00461 static void p_chart_uv_translate(PChart *chart, float trans[2]) 00462 { 00463 PVert *v; 00464 00465 for (v=chart->verts; v; v=v->nextlink) { 00466 v->uv[0] += trans[0]; 00467 v->uv[1] += trans[1]; 00468 } 00469 } 00470 00471 static PBool p_intersect_line_2d_dir(float *v1, float *dir1, float *v2, float *dir2, float *isect) 00472 { 00473 float lmbda, div; 00474 00475 div= dir2[0]*dir1[1] - dir2[1]*dir1[0]; 00476 00477 if (div == 0.0f) 00478 return P_FALSE; 00479 00480 lmbda= ((v1[1]-v2[1])*dir1[0]-(v1[0]-v2[0])*dir1[1])/div; 00481 isect[0] = v1[0] + lmbda*dir2[0]; 00482 isect[1] = v1[1] + lmbda*dir2[1]; 00483 00484 return P_TRUE; 00485 } 00486 00487 #if 0 00488 static PBool p_intersect_line_2d(float *v1, float *v2, float *v3, float *v4, float *isect) 00489 { 00490 float dir1[2], dir2[2]; 00491 00492 dir1[0] = v4[0] - v3[0]; 00493 dir1[1] = v4[1] - v3[1]; 00494 00495 dir2[0] = v2[0] - v1[0]; 00496 dir2[1] = v2[1] - v1[1]; 00497 00498 if (!p_intersect_line_2d_dir(v1, dir1, v2, dir2, isect)) { 00499 /* parallel - should never happen in theory for polygon kernel, but 00500 let's give a point nearby in case things go wrong */ 00501 isect[0] = (v1[0] + v2[0])*0.5f; 00502 isect[1] = (v1[1] + v2[1])*0.5f; 00503 return P_FALSE; 00504 } 00505 00506 return P_TRUE; 00507 } 00508 #endif 00509 00510 /* Topological Utilities */ 00511 00512 static PEdge *p_wheel_edge_next(PEdge *e) 00513 { 00514 return e->next->next->pair; 00515 } 00516 00517 static PEdge *p_wheel_edge_prev(PEdge *e) 00518 { 00519 return (e->pair)? e->pair->next: NULL; 00520 } 00521 00522 static PEdge *p_boundary_edge_next(PEdge *e) 00523 { 00524 return e->next->vert->edge; 00525 } 00526 00527 static PEdge *p_boundary_edge_prev(PEdge *e) 00528 { 00529 PEdge *we = e, *last; 00530 00531 do { 00532 last = we; 00533 we = p_wheel_edge_next(we); 00534 } while (we && (we != e)); 00535 00536 return last->next->next; 00537 } 00538 00539 static PBool p_vert_interior(PVert *v) 00540 { 00541 return (v->edge->pair != NULL); 00542 } 00543 00544 static void p_face_flip(PFace *f) 00545 { 00546 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 00547 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; 00548 int f1 = e1->flag, f2 = e2->flag, f3 = e3->flag; 00549 00550 e1->vert = v2; 00551 e1->next = e3; 00552 e1->flag = (f1 & ~PEDGE_VERTEX_FLAGS) | (f2 & PEDGE_VERTEX_FLAGS); 00553 00554 e2->vert = v3; 00555 e2->next = e1; 00556 e2->flag = (f2 & ~PEDGE_VERTEX_FLAGS) | (f3 & PEDGE_VERTEX_FLAGS); 00557 00558 e3->vert = v1; 00559 e3->next = e2; 00560 e3->flag = (f3 & ~PEDGE_VERTEX_FLAGS) | (f1 & PEDGE_VERTEX_FLAGS); 00561 } 00562 00563 #if 0 00564 static void p_chart_topological_sanity_check(PChart *chart) 00565 { 00566 PVert *v; 00567 PEdge *e; 00568 00569 for (v=chart->verts; v; v=v->nextlink) 00570 param_test_equals_ptr("v->edge->vert", v, v->edge->vert); 00571 00572 for (e=chart->edges; e; e=e->nextlink) { 00573 if (e->pair) { 00574 param_test_equals_ptr("e->pair->pair", e, e->pair->pair); 00575 param_test_equals_ptr("pair->vert", e->vert, e->pair->next->vert); 00576 param_test_equals_ptr("pair->next->vert", e->next->vert, e->pair->vert); 00577 } 00578 } 00579 } 00580 #endif 00581 00582 /* Loading / Flushing */ 00583 00584 static void p_vert_load_pin_select_uvs(PHandle *handle, PVert *v) 00585 { 00586 PEdge *e; 00587 int nedges = 0, npins = 0; 00588 float pinuv[2]; 00589 00590 v->uv[0] = v->uv[1] = 0.0f; 00591 pinuv[0] = pinuv[1] = 0.0f; 00592 e = v->edge; 00593 do { 00594 if (e->orig_uv) { 00595 if (e->flag & PEDGE_SELECT) 00596 v->flag |= PVERT_SELECT; 00597 00598 if (e->flag & PEDGE_PIN) { 00599 pinuv[0] += e->orig_uv[0]*handle->aspx; 00600 pinuv[1] += e->orig_uv[1]*handle->aspy; 00601 npins++; 00602 } 00603 else { 00604 v->uv[0] += e->orig_uv[0]*handle->aspx; 00605 v->uv[1] += e->orig_uv[1]*handle->aspy; 00606 } 00607 00608 nedges++; 00609 } 00610 00611 e = p_wheel_edge_next(e); 00612 } while (e && e != (v->edge)); 00613 00614 if (npins > 0) { 00615 v->uv[0] = pinuv[0]/npins; 00616 v->uv[1] = pinuv[1]/npins; 00617 v->flag |= PVERT_PIN; 00618 } 00619 else if (nedges > 0) { 00620 v->uv[0] /= nedges; 00621 v->uv[1] /= nedges; 00622 } 00623 } 00624 00625 static void p_flush_uvs(PHandle *handle, PChart *chart) 00626 { 00627 PEdge *e; 00628 00629 for (e=chart->edges; e; e=e->nextlink) { 00630 if (e->orig_uv) { 00631 e->orig_uv[0] = e->vert->uv[0]/handle->aspx; 00632 e->orig_uv[1] = e->vert->uv[1]/handle->aspy; 00633 } 00634 } 00635 } 00636 00637 static void p_flush_uvs_blend(PHandle *handle, PChart *chart, float blend) 00638 { 00639 PEdge *e; 00640 float invblend = 1.0f - blend; 00641 00642 for (e=chart->edges; e; e=e->nextlink) { 00643 if (e->orig_uv) { 00644 e->orig_uv[0] = blend*e->old_uv[0] + invblend*e->vert->uv[0]/handle->aspx; 00645 e->orig_uv[1] = blend*e->old_uv[1] + invblend*e->vert->uv[1]/handle->aspy; 00646 } 00647 } 00648 } 00649 00650 static void p_face_backup_uvs(PFace *f) 00651 { 00652 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 00653 00654 if (e1->orig_uv && e2->orig_uv && e3->orig_uv) { 00655 e1->old_uv[0] = e1->orig_uv[0]; 00656 e1->old_uv[1] = e1->orig_uv[1]; 00657 e2->old_uv[0] = e2->orig_uv[0]; 00658 e2->old_uv[1] = e2->orig_uv[1]; 00659 e3->old_uv[0] = e3->orig_uv[0]; 00660 e3->old_uv[1] = e3->orig_uv[1]; 00661 } 00662 } 00663 00664 static void p_face_restore_uvs(PFace *f) 00665 { 00666 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 00667 00668 if (e1->orig_uv && e2->orig_uv && e3->orig_uv) { 00669 e1->orig_uv[0] = e1->old_uv[0]; 00670 e1->orig_uv[1] = e1->old_uv[1]; 00671 e2->orig_uv[0] = e2->old_uv[0]; 00672 e2->orig_uv[1] = e2->old_uv[1]; 00673 e3->orig_uv[0] = e3->old_uv[0]; 00674 e3->orig_uv[1] = e3->old_uv[1]; 00675 } 00676 } 00677 00678 /* Construction (use only during construction, relies on u.key being set */ 00679 00680 static PVert *p_vert_add(PHandle *handle, PHashKey key, float *co, PEdge *e) 00681 { 00682 PVert *v = (PVert*)BLI_memarena_alloc(handle->arena, sizeof *v); 00683 v->co = co; 00684 v->u.key = key; 00685 v->edge = e; 00686 v->flag = 0; 00687 00688 phash_insert(handle->hash_verts, (PHashLink*)v); 00689 00690 return v; 00691 } 00692 00693 static PVert *p_vert_lookup(PHandle *handle, PHashKey key, float *co, PEdge *e) 00694 { 00695 PVert *v = (PVert*)phash_lookup(handle->hash_verts, key); 00696 00697 if (v) 00698 return v; 00699 else 00700 return p_vert_add(handle, key, co, e); 00701 } 00702 00703 static PVert *p_vert_copy(PChart *chart, PVert *v) 00704 { 00705 PVert *nv = (PVert*)BLI_memarena_alloc(chart->handle->arena, sizeof *nv); 00706 00707 nv->co = v->co; 00708 nv->uv[0] = v->uv[0]; 00709 nv->uv[1] = v->uv[1]; 00710 nv->u.key = v->u.key; 00711 nv->edge = v->edge; 00712 nv->flag = v->flag; 00713 00714 return nv; 00715 } 00716 00717 static PEdge *p_edge_lookup(PHandle *handle, PHashKey *vkeys) 00718 { 00719 PHashKey key = PHASH_edge(vkeys[0], vkeys[1]); 00720 PEdge *e = (PEdge*)phash_lookup(handle->hash_edges, key); 00721 00722 while (e) { 00723 if ((e->vert->u.key == vkeys[0]) && (e->next->vert->u.key == vkeys[1])) 00724 return e; 00725 else if ((e->vert->u.key == vkeys[1]) && (e->next->vert->u.key == vkeys[0])) 00726 return e; 00727 00728 e = (PEdge*)phash_next(handle->hash_edges, key, (PHashLink*)e); 00729 } 00730 00731 return NULL; 00732 } 00733 00734 static PBool p_face_exists(PHandle *handle, PHashKey *vkeys, int i1, int i2, int i3) 00735 { 00736 PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]); 00737 PEdge *e = (PEdge*)phash_lookup(handle->hash_edges, key); 00738 00739 while (e) { 00740 if ((e->vert->u.key == vkeys[i1]) && (e->next->vert->u.key == vkeys[i2])) { 00741 if (e->next->next->vert->u.key == vkeys[i3]) 00742 return P_TRUE; 00743 } 00744 else if ((e->vert->u.key == vkeys[i2]) && (e->next->vert->u.key == vkeys[i1])) { 00745 if (e->next->next->vert->u.key == vkeys[i3]) 00746 return P_TRUE; 00747 } 00748 00749 e = (PEdge*)phash_next(handle->hash_edges, key, (PHashLink*)e); 00750 } 00751 00752 return P_FALSE; 00753 } 00754 00755 static PChart *p_chart_new(PHandle *handle) 00756 { 00757 PChart *chart = (PChart*)MEM_callocN(sizeof*chart, "PChart"); 00758 chart->handle = handle; 00759 00760 return chart; 00761 } 00762 00763 static void p_chart_delete(PChart *chart) 00764 { 00765 /* the actual links are free by memarena */ 00766 MEM_freeN(chart); 00767 } 00768 00769 static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep) 00770 { 00771 float *uv1, *uv2, *uvp1, *uvp2; 00772 float limit[2]; 00773 00774 limit[0] = 0.00001; 00775 limit[1] = 0.00001; 00776 00777 uv1 = e->orig_uv; 00778 uv2 = e->next->orig_uv; 00779 00780 if (e->vert->u.key == ep->vert->u.key) { 00781 uvp1 = ep->orig_uv; 00782 uvp2 = ep->next->orig_uv; 00783 } 00784 else { 00785 uvp1 = ep->next->orig_uv; 00786 uvp2 = ep->orig_uv; 00787 } 00788 00789 if((fabsf(uv1[0]-uvp1[0]) > limit[0]) || (fabsf(uv1[1]-uvp1[1]) > limit[1])) { 00790 e->flag |= PEDGE_SEAM; 00791 ep->flag |= PEDGE_SEAM; 00792 return P_TRUE; 00793 } 00794 if((fabsf(uv2[0]-uvp2[0]) > limit[0]) || (fabsf(uv2[1]-uvp2[1]) > limit[1])) { 00795 e->flag |= PEDGE_SEAM; 00796 ep->flag |= PEDGE_SEAM; 00797 return P_TRUE; 00798 } 00799 00800 return P_FALSE; 00801 } 00802 00803 static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PEdge **pair, PBool impl) 00804 { 00805 PHashKey key; 00806 PEdge *pe; 00807 PVert *v1, *v2; 00808 PHashKey key1 = e->vert->u.key; 00809 PHashKey key2 = e->next->vert->u.key; 00810 00811 if (e->flag & PEDGE_SEAM) 00812 return P_FALSE; 00813 00814 key = PHASH_edge(key1, key2); 00815 pe = (PEdge*)phash_lookup(handle->hash_edges, key); 00816 *pair = NULL; 00817 00818 while (pe) { 00819 if (pe != e) { 00820 v1 = pe->vert; 00821 v2 = pe->next->vert; 00822 00823 if (((v1->u.key == key1) && (v2->u.key == key2)) || 00824 ((v1->u.key == key2) && (v2->u.key == key1))) { 00825 00826 /* don't connect seams and t-junctions */ 00827 if ((pe->flag & PEDGE_SEAM) || *pair || 00828 (impl && p_edge_implicit_seam(e, pe))) { 00829 *pair = NULL; 00830 return P_FALSE; 00831 } 00832 00833 *pair = pe; 00834 } 00835 } 00836 00837 pe = (PEdge*)phash_next(handle->hash_edges, key, (PHashLink*)pe); 00838 } 00839 00840 if (*pair && (e->vert == (*pair)->vert)) { 00841 if ((*pair)->next->pair || (*pair)->next->next->pair) { 00842 /* non unfoldable, maybe mobius ring or klein bottle */ 00843 *pair = NULL; 00844 return P_FALSE; 00845 } 00846 } 00847 00848 return (*pair != NULL); 00849 } 00850 00851 static PBool p_edge_connect_pair(PHandle *handle, PEdge *e, PEdge ***stack, PBool impl) 00852 { 00853 PEdge *pair = NULL; 00854 00855 if(!e->pair && p_edge_has_pair(handle, e, &pair, impl)) { 00856 if (e->vert == pair->vert) 00857 p_face_flip(pair->face); 00858 00859 e->pair = pair; 00860 pair->pair = e; 00861 00862 if (!(pair->face->flag & PFACE_CONNECTED)) { 00863 **stack = pair; 00864 (*stack)++; 00865 } 00866 } 00867 00868 return (e->pair != NULL); 00869 } 00870 00871 static int p_connect_pairs(PHandle *handle, PBool impl) 00872 { 00873 PEdge **stackbase = MEM_mallocN(sizeof*stackbase*phash_size(handle->hash_faces), "Pstackbase"); 00874 PEdge **stack = stackbase; 00875 PFace *f, *first; 00876 PEdge *e, *e1, *e2; 00877 PChart *chart = handle->construction_chart; 00878 int ncharts = 0; 00879 00880 /* connect pairs, count edges, set vertex-edge pointer to a pairless edge */ 00881 for (first=chart->faces; first; first=first->nextlink) { 00882 if (first->flag & PFACE_CONNECTED) 00883 continue; 00884 00885 *stack = first->edge; 00886 stack++; 00887 00888 while (stack != stackbase) { 00889 stack--; 00890 e = *stack; 00891 e1 = e->next; 00892 e2 = e1->next; 00893 00894 f = e->face; 00895 f->flag |= PFACE_CONNECTED; 00896 00897 /* assign verts to charts so we can sort them later */ 00898 f->u.chart = ncharts; 00899 00900 if (!p_edge_connect_pair(handle, e, &stack, impl)) 00901 e->vert->edge = e; 00902 if (!p_edge_connect_pair(handle, e1, &stack, impl)) 00903 e1->vert->edge = e1; 00904 if (!p_edge_connect_pair(handle, e2, &stack, impl)) 00905 e2->vert->edge = e2; 00906 } 00907 00908 ncharts++; 00909 } 00910 00911 MEM_freeN(stackbase); 00912 00913 return ncharts; 00914 } 00915 00916 static void p_split_vert(PChart *chart, PEdge *e) 00917 { 00918 PEdge *we, *lastwe = NULL; 00919 PVert *v = e->vert; 00920 PBool copy = P_TRUE; 00921 00922 if (e->flag & PEDGE_VERTEX_SPLIT) 00923 return; 00924 00925 /* rewind to start */ 00926 lastwe = e; 00927 for (we = p_wheel_edge_prev(e); we && (we != e); we = p_wheel_edge_prev(we)) 00928 lastwe = we; 00929 00930 /* go over all edges in wheel */ 00931 for (we = lastwe; we; we = p_wheel_edge_next(we)) { 00932 if (we->flag & PEDGE_VERTEX_SPLIT) 00933 break; 00934 00935 we->flag |= PEDGE_VERTEX_SPLIT; 00936 00937 if (we == v->edge) { 00938 /* found it, no need to copy */ 00939 copy = P_FALSE; 00940 v->nextlink = chart->verts; 00941 chart->verts = v; 00942 chart->nverts++; 00943 } 00944 } 00945 00946 if (copy) { 00947 /* not found, copying */ 00948 v->flag |= PVERT_SPLIT; 00949 v = p_vert_copy(chart, v); 00950 v->flag |= PVERT_SPLIT; 00951 00952 v->nextlink = chart->verts; 00953 chart->verts = v; 00954 chart->nverts++; 00955 00956 v->edge = lastwe; 00957 00958 we = lastwe; 00959 do { 00960 we->vert = v; 00961 we = p_wheel_edge_next(we); 00962 } while (we && (we != lastwe)); 00963 } 00964 } 00965 00966 static PChart **p_split_charts(PHandle *handle, PChart *chart, int ncharts) 00967 { 00968 PChart **charts = MEM_mallocN(sizeof*charts * ncharts, "PCharts"), *nchart; 00969 PFace *f, *nextf; 00970 int i; 00971 00972 for (i = 0; i < ncharts; i++) 00973 charts[i] = p_chart_new(handle); 00974 00975 f = chart->faces; 00976 while (f) { 00977 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 00978 nextf = f->nextlink; 00979 00980 nchart = charts[f->u.chart]; 00981 00982 f->nextlink = nchart->faces; 00983 nchart->faces = f; 00984 e1->nextlink = nchart->edges; 00985 nchart->edges = e1; 00986 e2->nextlink = nchart->edges; 00987 nchart->edges = e2; 00988 e3->nextlink = nchart->edges; 00989 nchart->edges = e3; 00990 00991 nchart->nfaces++; 00992 nchart->nedges += 3; 00993 00994 p_split_vert(nchart, e1); 00995 p_split_vert(nchart, e2); 00996 p_split_vert(nchart, e3); 00997 00998 f = nextf; 00999 } 01000 01001 return charts; 01002 } 01003 01004 static PFace *p_face_add(PHandle *handle) 01005 { 01006 PFace *f; 01007 PEdge *e1, *e2, *e3; 01008 01009 /* allocate */ 01010 f = (PFace*)BLI_memarena_alloc(handle->arena, sizeof *f); 01011 f->flag=0; // init ! 01012 01013 e1 = (PEdge*)BLI_memarena_alloc(handle->arena, sizeof *e1); 01014 e2 = (PEdge*)BLI_memarena_alloc(handle->arena, sizeof *e2); 01015 e3 = (PEdge*)BLI_memarena_alloc(handle->arena, sizeof *e3); 01016 01017 /* set up edges */ 01018 f->edge = e1; 01019 e1->face = e2->face = e3->face = f; 01020 01021 e1->next = e2; 01022 e2->next = e3; 01023 e3->next = e1; 01024 01025 e1->pair = NULL; 01026 e2->pair = NULL; 01027 e3->pair = NULL; 01028 01029 e1->flag =0; 01030 e2->flag =0; 01031 e3->flag =0; 01032 01033 return f; 01034 } 01035 01036 static PFace *p_face_add_construct(PHandle *handle, ParamKey key, ParamKey *vkeys, 01037 float *co[3], float *uv[3], int i1, int i2, int i3, 01038 ParamBool *pin, ParamBool *select) 01039 { 01040 PFace *f = p_face_add(handle); 01041 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 01042 01043 e1->vert = p_vert_lookup(handle, vkeys[i1], co[i1], e1); 01044 e2->vert = p_vert_lookup(handle, vkeys[i2], co[i2], e2); 01045 e3->vert = p_vert_lookup(handle, vkeys[i3], co[i3], e3); 01046 01047 e1->orig_uv = uv[i1]; 01048 e2->orig_uv = uv[i2]; 01049 e3->orig_uv = uv[i3]; 01050 01051 if (pin) { 01052 if (pin[i1]) e1->flag |= PEDGE_PIN; 01053 if (pin[i2]) e2->flag |= PEDGE_PIN; 01054 if (pin[i3]) e3->flag |= PEDGE_PIN; 01055 } 01056 01057 if (select) { 01058 if (select[i1]) e1->flag |= PEDGE_SELECT; 01059 if (select[i2]) e2->flag |= PEDGE_SELECT; 01060 if (select[i3]) e3->flag |= PEDGE_SELECT; 01061 } 01062 01063 /* insert into hash */ 01064 f->u.key = key; 01065 phash_insert(handle->hash_faces, (PHashLink*)f); 01066 01067 e1->u.key = PHASH_edge(vkeys[i1], vkeys[i2]); 01068 e2->u.key = PHASH_edge(vkeys[i2], vkeys[i3]); 01069 e3->u.key = PHASH_edge(vkeys[i3], vkeys[i1]); 01070 01071 phash_insert(handle->hash_edges, (PHashLink*)e1); 01072 phash_insert(handle->hash_edges, (PHashLink*)e2); 01073 phash_insert(handle->hash_edges, (PHashLink*)e3); 01074 01075 return f; 01076 } 01077 01078 static PFace *p_face_add_fill(PChart *chart, PVert *v1, PVert *v2, PVert *v3) 01079 { 01080 PFace *f = p_face_add(chart->handle); 01081 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 01082 01083 e1->vert = v1; 01084 e2->vert = v2; 01085 e3->vert = v3; 01086 01087 e1->orig_uv = e2->orig_uv = e3->orig_uv = NULL; 01088 01089 f->nextlink = chart->faces; 01090 chart->faces = f; 01091 e1->nextlink = chart->edges; 01092 chart->edges = e1; 01093 e2->nextlink = chart->edges; 01094 chart->edges = e2; 01095 e3->nextlink = chart->edges; 01096 chart->edges = e3; 01097 01098 chart->nfaces++; 01099 chart->nedges += 3; 01100 01101 return f; 01102 } 01103 01104 static PBool p_quad_split_direction(PHandle *handle, float **co, PHashKey *vkeys) 01105 { 01106 float fac= len_v3v3(co[0], co[2]) - len_v3v3(co[1], co[3]); 01107 PBool dir = (fac <= 0.0f); 01108 01109 /* the face exists check is there because of a special case: when 01110 two quads share three vertices, they can each be split into two 01111 triangles, resulting in two identical triangles. for example in 01112 suzanne's nose. */ 01113 if (dir) { 01114 if (p_face_exists(handle,vkeys,0,1,2) || p_face_exists(handle,vkeys,0,2,3)) 01115 return !dir; 01116 } 01117 else { 01118 if (p_face_exists(handle,vkeys,0,1,3) || p_face_exists(handle,vkeys,1,2,3)) 01119 return !dir; 01120 } 01121 01122 return dir; 01123 } 01124 01125 /* Construction: boundary filling */ 01126 01127 static void p_chart_boundaries(PChart *chart, int *nboundaries, PEdge **outer) 01128 { 01129 PEdge *e, *be; 01130 float len, maxlen = -1.0; 01131 01132 if (nboundaries) 01133 *nboundaries = 0; 01134 if (outer) 01135 *outer = NULL; 01136 01137 for (e=chart->edges; e; e=e->nextlink) { 01138 if (e->pair || (e->flag & PEDGE_DONE)) 01139 continue; 01140 01141 if (nboundaries) 01142 (*nboundaries)++; 01143 01144 len = 0.0f; 01145 01146 be = e; 01147 do { 01148 be->flag |= PEDGE_DONE; 01149 len += p_edge_length(be); 01150 be = be->next->vert->edge; 01151 } while(be != e); 01152 01153 if (outer && (len > maxlen)) { 01154 *outer = e; 01155 maxlen = len; 01156 } 01157 } 01158 01159 for (e=chart->edges; e; e=e->nextlink) 01160 e->flag &= ~PEDGE_DONE; 01161 } 01162 01163 static float p_edge_boundary_angle(PEdge *e) 01164 { 01165 PEdge *we; 01166 PVert *v, *v1, *v2; 01167 float angle; 01168 int n = 0; 01169 01170 v = e->vert; 01171 01172 /* concave angle check -- could be better */ 01173 angle = M_PI; 01174 01175 we = v->edge; 01176 do { 01177 v1 = we->next->vert; 01178 v2 = we->next->next->vert; 01179 angle -= p_vec_angle(v1->co, v->co, v2->co); 01180 01181 we = we->next->next->pair; 01182 n++; 01183 } while (we && (we != v->edge)); 01184 01185 return angle; 01186 } 01187 01188 static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges) 01189 { 01190 PEdge *e, *e1, *e2; 01191 01192 PFace *f; 01193 struct Heap *heap = BLI_heap_new(); 01194 float angle; 01195 01196 e = be; 01197 do { 01198 angle = p_edge_boundary_angle(e); 01199 e->u.heaplink = BLI_heap_insert(heap, angle, e); 01200 01201 e = p_boundary_edge_next(e); 01202 } while(e != be); 01203 01204 if (nedges == 2) { 01205 /* no real boundary, but an isolated seam */ 01206 e = be->next->vert->edge; 01207 e->pair = be; 01208 be->pair = e; 01209 01210 BLI_heap_remove(heap, e->u.heaplink); 01211 BLI_heap_remove(heap, be->u.heaplink); 01212 } 01213 else { 01214 while (nedges > 2) { 01215 PEdge *ne, *ne1, *ne2; 01216 01217 e = (PEdge*)BLI_heap_popmin(heap); 01218 01219 e1 = p_boundary_edge_prev(e); 01220 e2 = p_boundary_edge_next(e); 01221 01222 BLI_heap_remove(heap, e1->u.heaplink); 01223 BLI_heap_remove(heap, e2->u.heaplink); 01224 e->u.heaplink = e1->u.heaplink = e2->u.heaplink = NULL; 01225 01226 e->flag |= PEDGE_FILLED; 01227 e1->flag |= PEDGE_FILLED; 01228 01229 01230 01231 01232 01233 f = p_face_add_fill(chart, e->vert, e1->vert, e2->vert); 01234 f->flag |= PFACE_FILLED; 01235 01236 ne = f->edge->next->next; 01237 ne1 = f->edge; 01238 ne2 = f->edge->next; 01239 01240 ne->flag = ne1->flag = ne2->flag = PEDGE_FILLED; 01241 01242 e->pair = ne; 01243 ne->pair = e; 01244 e1->pair = ne1; 01245 ne1->pair = e1; 01246 01247 ne->vert = e2->vert; 01248 ne1->vert = e->vert; 01249 ne2->vert = e1->vert; 01250 01251 if (nedges == 3) { 01252 e2->pair = ne2; 01253 ne2->pair = e2; 01254 } 01255 else { 01256 ne2->vert->edge = ne2; 01257 01258 ne2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(ne2), ne2); 01259 e2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(e2), e2); 01260 } 01261 01262 nedges--; 01263 } 01264 } 01265 01266 BLI_heap_free(heap, NULL); 01267 } 01268 01269 static void p_chart_fill_boundaries(PChart *chart, PEdge *outer) 01270 { 01271 PEdge *e, *be; /* *enext - as yet unused */ 01272 int nedges; 01273 01274 for (e=chart->edges; e; e=e->nextlink) { 01275 /* enext = e->nextlink; - as yet unused */ 01276 01277 if (e->pair || (e->flag & PEDGE_FILLED)) 01278 continue; 01279 01280 nedges = 0; 01281 be = e; 01282 do { 01283 be->flag |= PEDGE_FILLED; 01284 be = be->next->vert->edge; 01285 nedges++; 01286 } while(be != e); 01287 01288 if (e != outer) 01289 p_chart_fill_boundary(chart, e, nedges); 01290 } 01291 } 01292 01293 #if 0 01294 /* Polygon kernel for inserting uv's non overlapping */ 01295 01296 static int p_polygon_point_in(float *cp1, float *cp2, float *p) 01297 { 01298 if ((cp1[0] == p[0]) && (cp1[1] == p[1])) 01299 return 2; 01300 else if ((cp2[0] == p[0]) && (cp2[1] == p[1])) 01301 return 3; 01302 else 01303 return (p_area_signed(cp1, cp2, p) >= 0.0f); 01304 } 01305 01306 static void p_polygon_kernel_clip(float (*oldpoints)[2], int noldpoints, float (*newpoints)[2], int *nnewpoints, float *cp1, float *cp2) 01307 { 01308 float *p2, *p1, isect[2]; 01309 int i, p2in, p1in; 01310 01311 p1 = oldpoints[noldpoints-1]; 01312 p1in = p_polygon_point_in(cp1, cp2, p1); 01313 *nnewpoints = 0; 01314 01315 for (i = 0; i < noldpoints; i++) { 01316 p2 = oldpoints[i]; 01317 p2in = p_polygon_point_in(cp1, cp2, p2); 01318 01319 if ((p2in >= 2) || (p1in && p2in)) { 01320 newpoints[*nnewpoints][0] = p2[0]; 01321 newpoints[*nnewpoints][1] = p2[1]; 01322 (*nnewpoints)++; 01323 } 01324 else if (p1in && !p2in) { 01325 if (p1in != 3) { 01326 p_intersect_line_2d(p1, p2, cp1, cp2, isect); 01327 newpoints[*nnewpoints][0] = isect[0]; 01328 newpoints[*nnewpoints][1] = isect[1]; 01329 (*nnewpoints)++; 01330 } 01331 } 01332 else if (!p1in && p2in) { 01333 p_intersect_line_2d(p1, p2, cp1, cp2, isect); 01334 newpoints[*nnewpoints][0] = isect[0]; 01335 newpoints[*nnewpoints][1] = isect[1]; 01336 (*nnewpoints)++; 01337 01338 newpoints[*nnewpoints][0] = p2[0]; 01339 newpoints[*nnewpoints][1] = p2[1]; 01340 (*nnewpoints)++; 01341 } 01342 01343 p1in = p2in; 01344 p1 = p2; 01345 } 01346 } 01347 01348 static void p_polygon_kernel_center(float (*points)[2], int npoints, float *center) 01349 { 01350 int i, size, nnewpoints = npoints; 01351 float (*oldpoints)[2], (*newpoints)[2], *p1, *p2; 01352 01353 size = npoints*3; 01354 oldpoints = MEM_mallocN(sizeof(float)*2*size, "PPolygonOldPoints"); 01355 newpoints = MEM_mallocN(sizeof(float)*2*size, "PPolygonNewPoints"); 01356 01357 memcpy(oldpoints, points, sizeof(float)*2*npoints); 01358 01359 for (i = 0; i < npoints; i++) { 01360 p1 = points[i]; 01361 p2 = points[(i+1)%npoints]; 01362 p_polygon_kernel_clip(oldpoints, nnewpoints, newpoints, &nnewpoints, p1, p2); 01363 01364 if (nnewpoints == 0) { 01365 /* degenerate case, use center of original polygon */ 01366 memcpy(oldpoints, points, sizeof(float)*2*npoints); 01367 nnewpoints = npoints; 01368 break; 01369 } 01370 else if (nnewpoints == 1) { 01371 /* degenerate case, use remaining point */ 01372 center[0] = newpoints[0][0]; 01373 center[1] = newpoints[0][1]; 01374 01375 MEM_freeN(oldpoints); 01376 MEM_freeN(newpoints); 01377 01378 return; 01379 } 01380 01381 if (nnewpoints*2 > size) { 01382 size *= 2; 01383 MEM_freeN(oldpoints); 01384 oldpoints = MEM_mallocN(sizeof(float)*2*size, "oldpoints"); 01385 memcpy(oldpoints, newpoints, sizeof(float)*2*nnewpoints); 01386 MEM_freeN(newpoints); 01387 newpoints = MEM_mallocN(sizeof(float)*2*size, "newpoints"); 01388 } 01389 else { 01390 float (*sw_points)[2] = oldpoints; 01391 oldpoints = newpoints; 01392 newpoints = sw_points; 01393 } 01394 } 01395 01396 center[0] = center[1] = 0.0f; 01397 01398 for (i = 0; i < nnewpoints; i++) { 01399 center[0] += oldpoints[i][0]; 01400 center[1] += oldpoints[i][1]; 01401 } 01402 01403 center[0] /= nnewpoints; 01404 center[1] /= nnewpoints; 01405 01406 MEM_freeN(oldpoints); 01407 MEM_freeN(newpoints); 01408 } 01409 #endif 01410 01411 #if 0 01412 /* Edge Collapser */ 01413 01414 int NCOLLAPSE = 1; 01415 int NCOLLAPSEX = 0; 01416 01417 static float p_vert_cotan(float *v1, float *v2, float *v3) 01418 { 01419 float a[3], b[3], c[3], clen; 01420 01421 sub_v3_v3v3(a, v2, v1); 01422 sub_v3_v3v3(b, v3, v1); 01423 cross_v3_v3v3(c, a, b); 01424 01425 clen = len_v3(c); 01426 01427 if (clen == 0.0f) 01428 return 0.0f; 01429 01430 return dot_v3v3(a, b)/clen; 01431 } 01432 01433 static PBool p_vert_flipped_wheel_triangle(PVert *v) 01434 { 01435 PEdge *e = v->edge; 01436 01437 do { 01438 if (p_face_uv_area_signed(e->face) < 0.0f) 01439 return P_TRUE; 01440 01441 e = p_wheel_edge_next(e); 01442 } while (e && (e != v->edge)); 01443 01444 return P_FALSE; 01445 } 01446 01447 static PBool p_vert_map_harmonic_weights(PVert *v) 01448 { 01449 float weightsum, positionsum[2], olduv[2]; 01450 01451 weightsum = 0.0f; 01452 positionsum[0] = positionsum[1] = 0.0f; 01453 01454 if (p_vert_interior(v)) { 01455 PEdge *e = v->edge; 01456 01457 do { 01458 float t1, t2, weight; 01459 PVert *v1, *v2; 01460 01461 v1 = e->next->vert; 01462 v2 = e->next->next->vert; 01463 t1 = p_vert_cotan(v2->co, e->vert->co, v1->co); 01464 01465 v1 = e->pair->next->vert; 01466 v2 = e->pair->next->next->vert; 01467 t2 = p_vert_cotan(v2->co, e->pair->vert->co, v1->co); 01468 01469 weight = 0.5f*(t1 + t2); 01470 weightsum += weight; 01471 positionsum[0] += weight*e->pair->vert->uv[0]; 01472 positionsum[1] += weight*e->pair->vert->uv[1]; 01473 01474 e = p_wheel_edge_next(e); 01475 } while (e && (e != v->edge)); 01476 } 01477 else { 01478 PEdge *e = v->edge; 01479 01480 do { 01481 float t1, t2; 01482 PVert *v1, *v2; 01483 01484 v2 = e->next->vert; 01485 v1 = e->next->next->vert; 01486 01487 t1 = p_vert_cotan(v1->co, v->co, v2->co); 01488 t2 = p_vert_cotan(v2->co, v->co, v1->co); 01489 01490 weightsum += t1 + t2; 01491 positionsum[0] += (v2->uv[1] - v1->uv[1]) + (t1*v2->uv[0] + t2*v1->uv[0]); 01492 positionsum[1] += (v1->uv[0] - v2->uv[0]) + (t1*v2->uv[1] + t2*v1->uv[1]); 01493 01494 e = p_wheel_edge_next(e); 01495 } while (e && (e != v->edge)); 01496 } 01497 01498 if (weightsum != 0.0f) { 01499 weightsum = 1.0f/weightsum; 01500 positionsum[0] *= weightsum; 01501 positionsum[1] *= weightsum; 01502 } 01503 01504 olduv[0] = v->uv[0]; 01505 olduv[1] = v->uv[1]; 01506 v->uv[0] = positionsum[0]; 01507 v->uv[1] = positionsum[1]; 01508 01509 if (p_vert_flipped_wheel_triangle(v)) { 01510 v->uv[0] = olduv[0]; 01511 v->uv[1] = olduv[1]; 01512 01513 return P_FALSE; 01514 } 01515 01516 return P_TRUE; 01517 } 01518 01519 static void p_vert_harmonic_insert(PVert *v) 01520 { 01521 PEdge *e; 01522 01523 if (!p_vert_map_harmonic_weights(v)) { 01524 /* do polygon kernel center insertion: this is quite slow, but should 01525 only be needed for 0.01 % of verts or so, when insert with harmonic 01526 weights fails */ 01527 01528 int npoints = 0, i; 01529 float (*points)[2]; 01530 01531 e = v->edge; 01532 do { 01533 npoints++; 01534 e = p_wheel_edge_next(e); 01535 } while (e && (e != v->edge)); 01536 01537 if (e == NULL) 01538 npoints++; 01539 01540 points = MEM_mallocN(sizeof(float)*2*npoints, "PHarmonicPoints"); 01541 01542 e = v->edge; 01543 i = 0; 01544 do { 01545 PEdge *nexte = p_wheel_edge_next(e); 01546 01547 points[i][0] = e->next->vert->uv[0]; 01548 points[i][1] = e->next->vert->uv[1]; 01549 01550 if (nexte == NULL) { 01551 i++; 01552 points[i][0] = e->next->next->vert->uv[0]; 01553 points[i][1] = e->next->next->vert->uv[1]; 01554 break; 01555 } 01556 01557 e = nexte; 01558 i++; 01559 } while (e != v->edge); 01560 01561 p_polygon_kernel_center(points, npoints, v->uv); 01562 01563 MEM_freeN(points); 01564 } 01565 01566 e = v->edge; 01567 do { 01568 if (!(e->next->vert->flag & PVERT_PIN)) 01569 p_vert_map_harmonic_weights(e->next->vert); 01570 e = p_wheel_edge_next(e); 01571 } while (e && (e != v->edge)); 01572 01573 p_vert_map_harmonic_weights(v); 01574 } 01575 01576 static void p_vert_fix_edge_pointer(PVert *v) 01577 { 01578 PEdge *start = v->edge; 01579 01580 /* set v->edge pointer to the edge with no pair, if there is one */ 01581 while (v->edge->pair) { 01582 v->edge = p_wheel_edge_prev(v->edge); 01583 01584 if (v->edge == start) 01585 break; 01586 } 01587 } 01588 01589 static void p_collapsing_verts(PEdge *edge, PEdge *pair, PVert **newv, PVert **keepv) 01590 { 01591 /* the two vertices that are involved in the collapse */ 01592 if (edge) { 01593 *newv = edge->vert; 01594 *keepv = edge->next->vert; 01595 } 01596 else { 01597 *newv = pair->next->vert; 01598 *keepv = pair->vert; 01599 } 01600 } 01601 01602 static void p_collapse_edge(PEdge *edge, PEdge *pair) 01603 { 01604 PVert *oldv, *keepv; 01605 PEdge *e; 01606 01607 p_collapsing_verts(edge, pair, &oldv, &keepv); 01608 01609 /* change e->vert pointers from old vertex to the target vertex */ 01610 e = oldv->edge; 01611 do { 01612 if ((e != edge) && !(pair && pair->next == e)) 01613 e->vert = keepv; 01614 01615 e = p_wheel_edge_next(e); 01616 } while (e && (e != oldv->edge)); 01617 01618 /* set keepv->edge pointer */ 01619 if ((edge && (keepv->edge == edge->next)) || (keepv->edge == pair)) { 01620 if (edge && edge->next->pair) 01621 keepv->edge = edge->next->pair->next; 01622 else if (pair && pair->next->next->pair) 01623 keepv->edge = pair->next->next->pair; 01624 else if (edge && edge->next->next->pair) 01625 keepv->edge = edge->next->next->pair; 01626 else 01627 keepv->edge = pair->next->pair->next; 01628 } 01629 01630 /* update pairs and v->edge pointers */ 01631 if (edge) { 01632 PEdge *e1 = edge->next, *e2 = e1->next; 01633 01634 if (e1->pair) 01635 e1->pair->pair = e2->pair; 01636 01637 if (e2->pair) { 01638 e2->pair->pair = e1->pair; 01639 e2->vert->edge = p_wheel_edge_prev(e2); 01640 } 01641 else 01642 e2->vert->edge = p_wheel_edge_next(e2); 01643 01644 p_vert_fix_edge_pointer(e2->vert); 01645 } 01646 01647 if (pair) { 01648 PEdge *e1 = pair->next, *e2 = e1->next; 01649 01650 if (e1->pair) 01651 e1->pair->pair = e2->pair; 01652 01653 if (e2->pair) { 01654 e2->pair->pair = e1->pair; 01655 e2->vert->edge = p_wheel_edge_prev(e2); 01656 } 01657 else 01658 e2->vert->edge = p_wheel_edge_next(e2); 01659 01660 p_vert_fix_edge_pointer(e2->vert); 01661 } 01662 01663 p_vert_fix_edge_pointer(keepv); 01664 01665 /* mark for move to collapsed list later */ 01666 oldv->flag |= PVERT_COLLAPSE; 01667 01668 if (edge) { 01669 PFace *f = edge->face; 01670 PEdge *e1 = edge->next, *e2 = e1->next; 01671 01672 f->flag |= PFACE_COLLAPSE; 01673 edge->flag |= PEDGE_COLLAPSE; 01674 e1->flag |= PEDGE_COLLAPSE; 01675 e2->flag |= PEDGE_COLLAPSE; 01676 } 01677 01678 if (pair) { 01679 PFace *f = pair->face; 01680 PEdge *e1 = pair->next, *e2 = e1->next; 01681 01682 f->flag |= PFACE_COLLAPSE; 01683 pair->flag |= PEDGE_COLLAPSE; 01684 e1->flag |= PEDGE_COLLAPSE; 01685 e2->flag |= PEDGE_COLLAPSE; 01686 } 01687 } 01688 01689 static void p_split_vertex(PEdge *edge, PEdge *pair) 01690 { 01691 PVert *newv, *keepv; 01692 PEdge *e; 01693 01694 p_collapsing_verts(edge, pair, &newv, &keepv); 01695 01696 /* update edge pairs */ 01697 if (edge) { 01698 PEdge *e1 = edge->next, *e2 = e1->next; 01699 01700 if (e1->pair) 01701 e1->pair->pair = e1; 01702 if (e2->pair) 01703 e2->pair->pair = e2; 01704 01705 e2->vert->edge = e2; 01706 p_vert_fix_edge_pointer(e2->vert); 01707 keepv->edge = e1; 01708 } 01709 01710 if (pair) { 01711 PEdge *e1 = pair->next, *e2 = e1->next; 01712 01713 if (e1->pair) 01714 e1->pair->pair = e1; 01715 if (e2->pair) 01716 e2->pair->pair = e2; 01717 01718 e2->vert->edge = e2; 01719 p_vert_fix_edge_pointer(e2->vert); 01720 keepv->edge = pair; 01721 } 01722 01723 p_vert_fix_edge_pointer(keepv); 01724 01725 /* set e->vert pointers to restored vertex */ 01726 e = newv->edge; 01727 do { 01728 e->vert = newv; 01729 e = p_wheel_edge_next(e); 01730 } while (e && (e != newv->edge)); 01731 } 01732 01733 static PBool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair) 01734 { 01735 PVert *oldv, *keepv; 01736 01737 p_collapsing_verts(edge, pair, &oldv, &keepv); 01738 01739 /* boundary edges */ 01740 if (!edge || !pair) { 01741 /* avoid collapsing chart into an edge */ 01742 if (edge && !edge->next->pair && !edge->next->next->pair) 01743 return P_FALSE; 01744 else if (pair && !pair->next->pair && !pair->next->next->pair) 01745 return P_FALSE; 01746 } 01747 /* avoid merging two boundaries (oldv and keepv are on the 'other side' of 01748 the chart) */ 01749 else if (!p_vert_interior(oldv) && !p_vert_interior(keepv)) 01750 return P_FALSE; 01751 01752 return P_TRUE; 01753 } 01754 01755 static PBool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float *vnew) 01756 { 01757 float nold[3], nnew[3], sub1[3], sub2[3]; 01758 01759 sub_v3_v3v3(sub1, vold, v1); 01760 sub_v3_v3v3(sub2, vold, v2); 01761 cross_v3_v3v3(nold, sub1, sub2); 01762 01763 sub_v3_v3v3(sub1, vnew, v1); 01764 sub_v3_v3v3(sub2, vnew, v2); 01765 cross_v3_v3v3(nnew, sub1, sub2); 01766 01767 return (dot_v3v3(nold, nnew) <= 0.0f); 01768 } 01769 01770 static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair) 01771 { 01772 PVert *oldv, *keepv; 01773 PEdge *e; 01774 float angulardefect, angle; 01775 01776 p_collapsing_verts(edge, pair, &oldv, &keepv); 01777 01778 angulardefect = 2*M_PI; 01779 01780 e = oldv->edge; 01781 do { 01782 float a[3], b[3], minangle, maxangle; 01783 PEdge *e1 = e->next, *e2 = e1->next; 01784 PVert *v1 = e1->vert, *v2 = e2->vert; 01785 int i; 01786 01787 angle = p_vec_angle(v1->co, oldv->co, v2->co); 01788 angulardefect -= angle; 01789 01790 /* skip collapsing faces */ 01791 if (v1 == keepv || v2 == keepv) { 01792 e = p_wheel_edge_next(e); 01793 continue; 01794 } 01795 01796 if (p_collapse_normal_flipped(v1->co, v2->co, oldv->co, keepv->co)) 01797 return P_FALSE; 01798 01799 a[0] = angle; 01800 a[1] = p_vec_angle(v2->co, v1->co, oldv->co); 01801 a[2] = M_PI - a[0] - a[1]; 01802 01803 b[0] = p_vec_angle(v1->co, keepv->co, v2->co); 01804 b[1] = p_vec_angle(v2->co, v1->co, keepv->co); 01805 b[2] = M_PI - b[0] - b[1]; 01806 01807 /* abf criterion 1: avoid sharp and obtuse angles */ 01808 minangle = 15.0f*M_PI/180.0f; 01809 maxangle = M_PI - minangle; 01810 01811 for (i = 0; i < 3; i++) { 01812 if ((b[i] < a[i]) && (b[i] < minangle)) 01813 return P_FALSE; 01814 else if ((b[i] > a[i]) && (b[i] > maxangle)) 01815 return P_FALSE; 01816 } 01817 01818 e = p_wheel_edge_next(e); 01819 } while (e && (e != oldv->edge)); 01820 01821 if (p_vert_interior(oldv)) { 01822 /* hlscm criterion: angular defect smaller than threshold */ 01823 if (fabs(angulardefect) > (M_PI*30.0/180.0)) 01824 return P_FALSE; 01825 } 01826 else { 01827 PVert *v1 = p_boundary_edge_next(oldv->edge)->vert; 01828 PVert *v2 = p_boundary_edge_prev(oldv->edge)->vert; 01829 01830 /* abf++ criterion 2: avoid collapsing verts inwards */ 01831 if (p_vert_interior(keepv)) 01832 return P_FALSE; 01833 01834 /* don't collapse significant boundary changes */ 01835 angle = p_vec_angle(v1->co, oldv->co, v2->co); 01836 if (angle < (M_PI*160.0/180.0)) 01837 return P_FALSE; 01838 } 01839 01840 return P_TRUE; 01841 } 01842 01843 static PBool p_collapse_allowed(PEdge *edge, PEdge *pair) 01844 { 01845 PVert *oldv, *keepv; 01846 01847 p_collapsing_verts(edge, pair, &oldv, &keepv); 01848 01849 if (oldv->flag & PVERT_PIN) 01850 return P_FALSE; 01851 01852 return (p_collapse_allowed_topologic(edge, pair) && 01853 p_collapse_allowed_geometric(edge, pair)); 01854 } 01855 01856 static float p_collapse_cost(PEdge *edge, PEdge *pair) 01857 { 01858 /* based on volume and boundary optimization from: 01859 "Fast and Memory Efficient Polygonal Simplification" P. Lindstrom, G. Turk */ 01860 01861 PVert *oldv, *keepv; 01862 PEdge *e; 01863 PFace *oldf1, *oldf2; 01864 float volumecost = 0.0f, areacost = 0.0f, edgevec[3], cost, weight, elen; 01865 float shapecost = 0.0f; 01866 float shapeold = 0.0f, shapenew = 0.0f; 01867 int nshapeold = 0, nshapenew = 0; 01868 01869 p_collapsing_verts(edge, pair, &oldv, &keepv); 01870 oldf1 = (edge)? edge->face: NULL; 01871 oldf2 = (pair)? pair->face: NULL; 01872 01873 sub_v3_v3v3(edgevec, keepv->co, oldv->co); 01874 01875 e = oldv->edge; 01876 do { 01877 float a1, a2, a3; 01878 float *co1 = e->next->vert->co; 01879 float *co2 = e->next->next->vert->co; 01880 01881 if ((e->face != oldf1) && (e->face != oldf2)) { 01882 float tetrav2[3], tetrav3[3], c[3]; 01883 01884 /* tetrahedron volume = (1/3!)*|a.(b x c)| */ 01885 sub_v3_v3v3(tetrav2, co1, oldv->co); 01886 sub_v3_v3v3(tetrav3, co2, oldv->co); 01887 cross_v3_v3v3(c, tetrav2, tetrav3); 01888 01889 volumecost += fabs(dot_v3v3(edgevec, c)/6.0f); 01890 #if 0 01891 shapecost += dot_v3v3(co1, keepv->co); 01892 01893 if (p_wheel_edge_next(e) == NULL) 01894 shapecost += dot_v3v3(co2, keepv->co); 01895 #endif 01896 01897 p_triangle_angles(oldv->co, co1, co2, &a1, &a2, &a3); 01898 a1 = a1 - M_PI/3.0; 01899 a2 = a2 - M_PI/3.0; 01900 a3 = a3 - M_PI/3.0; 01901 shapeold = (a1*a1 + a2*a2 + a3*a3)/((M_PI/2)*(M_PI/2)); 01902 01903 nshapeold++; 01904 } 01905 else { 01906 p_triangle_angles(keepv->co, co1, co2, &a1, &a2, &a3); 01907 a1 = a1 - M_PI/3.0; 01908 a2 = a2 - M_PI/3.0; 01909 a3 = a3 - M_PI/3.0; 01910 shapenew = (a1*a1 + a2*a2 + a3*a3)/((M_PI/2)*(M_PI/2)); 01911 01912 nshapenew++; 01913 } 01914 01915 e = p_wheel_edge_next(e); 01916 } while (e && (e != oldv->edge)); 01917 01918 if (!p_vert_interior(oldv)) { 01919 PVert *v1 = p_boundary_edge_prev(oldv->edge)->vert; 01920 PVert *v2 = p_boundary_edge_next(oldv->edge)->vert; 01921 01922 areacost = area_tri_v3(oldv->co, v1->co, v2->co); 01923 } 01924 01925 elen = len_v3(edgevec); 01926 weight = 1.0f; /* 0.2f */ 01927 cost = weight*volumecost*volumecost + elen*elen*areacost*areacost; 01928 #if 0 01929 cost += shapecost; 01930 #else 01931 shapeold /= nshapeold; 01932 shapenew /= nshapenew; 01933 shapecost = (shapeold + 0.00001)/(shapenew + 0.00001); 01934 01935 cost *= shapecost; 01936 #endif 01937 01938 return cost; 01939 } 01940 01941 static void p_collapse_cost_vertex(PVert *vert, float *mincost, PEdge **mine) 01942 { 01943 PEdge *e, *enext, *pair; 01944 01945 *mine = NULL; 01946 *mincost = 0.0f; 01947 e = vert->edge; 01948 do { 01949 if (p_collapse_allowed(e, e->pair)) { 01950 float cost = p_collapse_cost(e, e->pair); 01951 01952 if ((*mine == NULL) || (cost < *mincost)) { 01953 *mincost = cost; 01954 *mine = e; 01955 } 01956 } 01957 01958 enext = p_wheel_edge_next(e); 01959 01960 if (enext == NULL) { 01961 /* the other boundary edge, where we only have the pair halfedge */ 01962 pair = e->next->next; 01963 01964 if (p_collapse_allowed(NULL, pair)) { 01965 float cost = p_collapse_cost(NULL, pair); 01966 01967 if ((*mine == NULL) || (cost < *mincost)) { 01968 *mincost = cost; 01969 *mine = pair; 01970 } 01971 } 01972 01973 break; 01974 } 01975 01976 e = enext; 01977 } while (e != vert->edge); 01978 } 01979 01980 static void p_chart_post_collapse_flush(PChart *chart, PEdge *collapsed) 01981 { 01982 /* move to collapsed_ */ 01983 01984 PVert *v, *nextv = NULL, *verts = chart->verts; 01985 PEdge *e, *nexte = NULL, *edges = chart->edges, *laste = NULL; 01986 PFace *f, *nextf = NULL, *faces = chart->faces; 01987 01988 chart->verts = chart->collapsed_verts = NULL; 01989 chart->edges = chart->collapsed_edges = NULL; 01990 chart->faces = chart->collapsed_faces = NULL; 01991 01992 chart->nverts = chart->nedges = chart->nfaces = 0; 01993 01994 for (v=verts; v; v=nextv) { 01995 nextv = v->nextlink; 01996 01997 if (v->flag & PVERT_COLLAPSE) { 01998 v->nextlink = chart->collapsed_verts; 01999 chart->collapsed_verts = v; 02000 } 02001 else { 02002 v->nextlink = chart->verts; 02003 chart->verts = v; 02004 chart->nverts++; 02005 } 02006 } 02007 02008 for (e=edges; e; e=nexte) { 02009 nexte = e->nextlink; 02010 02011 if (!collapsed || !(e->flag & PEDGE_COLLAPSE_EDGE)) { 02012 if (e->flag & PEDGE_COLLAPSE) { 02013 e->nextlink = chart->collapsed_edges; 02014 chart->collapsed_edges = e; 02015 } 02016 else { 02017 e->nextlink = chart->edges; 02018 chart->edges = e; 02019 chart->nedges++; 02020 } 02021 } 02022 } 02023 02024 /* these are added last so they can be popped of in the right order 02025 for splitting */ 02026 for (e=collapsed; e; e=e->nextlink) { 02027 e->nextlink = e->u.nextcollapse; 02028 laste = e; 02029 } 02030 if (laste) { 02031 laste->nextlink = chart->collapsed_edges; 02032 chart->collapsed_edges = collapsed; 02033 } 02034 02035 for (f=faces; f; f=nextf) { 02036 nextf = f->nextlink; 02037 02038 if (f->flag & PFACE_COLLAPSE) { 02039 f->nextlink = chart->collapsed_faces; 02040 chart->collapsed_faces = f; 02041 } 02042 else { 02043 f->nextlink = chart->faces; 02044 chart->faces = f; 02045 chart->nfaces++; 02046 } 02047 } 02048 } 02049 02050 static void p_chart_post_split_flush(PChart *chart) 02051 { 02052 /* move from collapsed_ */ 02053 02054 PVert *v, *nextv = NULL; 02055 PEdge *e, *nexte = NULL; 02056 PFace *f, *nextf = NULL; 02057 02058 for (v=chart->collapsed_verts; v; v=nextv) { 02059 nextv = v->nextlink; 02060 v->nextlink = chart->verts; 02061 chart->verts = v; 02062 chart->nverts++; 02063 } 02064 02065 for (e=chart->collapsed_edges; e; e=nexte) { 02066 nexte = e->nextlink; 02067 e->nextlink = chart->edges; 02068 chart->edges = e; 02069 chart->nedges++; 02070 } 02071 02072 for (f=chart->collapsed_faces; f; f=nextf) { 02073 nextf = f->nextlink; 02074 f->nextlink = chart->faces; 02075 chart->faces = f; 02076 chart->nfaces++; 02077 } 02078 02079 chart->collapsed_verts = NULL; 02080 chart->collapsed_edges = NULL; 02081 chart->collapsed_faces = NULL; 02082 } 02083 02084 static void p_chart_simplify_compute(PChart *chart) 02085 { 02086 /* Computes a list of edge collapses / vertex splits. The collapsed 02087 simplices go in the chart->collapsed_* lists, The original and 02088 collapsed may then be view as stacks, where the next collapse/split 02089 is at the top of the respective lists. */ 02090 02091 Heap *heap = BLI_heap_new(); 02092 PVert *v, **wheelverts; 02093 PEdge *collapsededges = NULL, *e; 02094 int nwheelverts, i, ncollapsed = 0; 02095 02096 wheelverts = MEM_mallocN(sizeof(PVert*)*chart->nverts, "PChartWheelVerts"); 02097 02098 /* insert all potential collapses into heap */ 02099 for (v=chart->verts; v; v=v->nextlink) { 02100 float cost; 02101 PEdge *e = NULL; 02102 02103 p_collapse_cost_vertex(v, &cost, &e); 02104 02105 if (e) 02106 v->u.heaplink = BLI_heap_insert(heap, cost, e); 02107 else 02108 v->u.heaplink = NULL; 02109 } 02110 02111 for (e=chart->edges; e; e=e->nextlink) 02112 e->u.nextcollapse = NULL; 02113 02114 /* pop edge collapse out of heap one by one */ 02115 while (!BLI_heap_empty(heap)) { 02116 if (ncollapsed == NCOLLAPSE) 02117 break; 02118 02119 HeapNode *link = BLI_heap_top(heap); 02120 PEdge *edge = (PEdge*)BLI_heap_popmin(heap), *pair = edge->pair; 02121 PVert *oldv, *keepv; 02122 PEdge *wheele, *nexte; 02123 02124 /* remember the edges we collapsed */ 02125 edge->u.nextcollapse = collapsededges; 02126 collapsededges = edge; 02127 02128 if (edge->vert->u.heaplink != link) { 02129 edge->flag |= (PEDGE_COLLAPSE_EDGE|PEDGE_COLLAPSE_PAIR); 02130 edge->next->vert->u.heaplink = NULL; 02131 SWAP(PEdge*, edge, pair); 02132 } 02133 else { 02134 edge->flag |= PEDGE_COLLAPSE_EDGE; 02135 edge->vert->u.heaplink = NULL; 02136 } 02137 02138 p_collapsing_verts(edge, pair, &oldv, &keepv); 02139 02140 /* gather all wheel verts and remember them before collapse */ 02141 nwheelverts = 0; 02142 wheele = oldv->edge; 02143 02144 do { 02145 wheelverts[nwheelverts++] = wheele->next->vert; 02146 nexte = p_wheel_edge_next(wheele); 02147 02148 if (nexte == NULL) 02149 wheelverts[nwheelverts++] = wheele->next->next->vert; 02150 02151 wheele = nexte; 02152 } while (wheele && (wheele != oldv->edge)); 02153 02154 /* collapse */ 02155 p_collapse_edge(edge, pair); 02156 02157 for (i = 0; i < nwheelverts; i++) { 02158 float cost; 02159 PEdge *collapse = NULL; 02160 02161 v = wheelverts[i]; 02162 02163 if (v->u.heaplink) { 02164 BLI_heap_remove(heap, v->u.heaplink); 02165 v->u.heaplink = NULL; 02166 } 02167 02168 p_collapse_cost_vertex(v, &cost, &collapse); 02169 02170 if (collapse) 02171 v->u.heaplink = BLI_heap_insert(heap, cost, collapse); 02172 } 02173 02174 ncollapsed++; 02175 } 02176 02177 MEM_freeN(wheelverts); 02178 BLI_heap_free(heap, NULL); 02179 02180 p_chart_post_collapse_flush(chart, collapsededges); 02181 } 02182 02183 static void p_chart_complexify(PChart *chart) 02184 { 02185 PEdge *e, *pair, *edge; 02186 PVert *newv, *keepv; 02187 int x = 0; 02188 02189 for (e=chart->collapsed_edges; e; e=e->nextlink) { 02190 if (!(e->flag & PEDGE_COLLAPSE_EDGE)) 02191 break; 02192 02193 edge = e; 02194 pair = e->pair; 02195 02196 if (edge->flag & PEDGE_COLLAPSE_PAIR) { 02197 SWAP(PEdge*, edge, pair); 02198 } 02199 02200 p_split_vertex(edge, pair); 02201 p_collapsing_verts(edge, pair, &newv, &keepv); 02202 02203 if (x >= NCOLLAPSEX) { 02204 newv->uv[0] = keepv->uv[0]; 02205 newv->uv[1] = keepv->uv[1]; 02206 } 02207 else { 02208 p_vert_harmonic_insert(newv); 02209 x++; 02210 } 02211 } 02212 02213 p_chart_post_split_flush(chart); 02214 } 02215 02216 #if 0 02217 static void p_chart_simplify(PChart *chart) 02218 { 02219 /* Not implemented, needs proper reordering in split_flush. */ 02220 } 02221 #endif 02222 #endif 02223 02224 /* ABF */ 02225 02226 #define ABF_MAX_ITER 20 02227 02228 typedef struct PAbfSystem { 02229 int ninterior, nfaces, nangles; 02230 float *alpha, *beta, *sine, *cosine, *weight; 02231 float *bAlpha, *bTriangle, *bInterior; 02232 float *lambdaTriangle, *lambdaPlanar, *lambdaLength; 02233 float (*J2dt)[3], *bstar, *dstar; 02234 float minangle, maxangle; 02235 } PAbfSystem; 02236 02237 static void p_abf_setup_system(PAbfSystem *sys) 02238 { 02239 int i; 02240 02241 sys->alpha = (float*)MEM_mallocN(sizeof(float)*sys->nangles, "ABFalpha"); 02242 sys->beta = (float*)MEM_mallocN(sizeof(float)*sys->nangles, "ABFbeta"); 02243 sys->sine = (float*)MEM_mallocN(sizeof(float)*sys->nangles, "ABFsine"); 02244 sys->cosine = (float*)MEM_mallocN(sizeof(float)*sys->nangles, "ABFcosine"); 02245 sys->weight = (float*)MEM_mallocN(sizeof(float)*sys->nangles, "ABFweight"); 02246 02247 sys->bAlpha = (float*)MEM_mallocN(sizeof(float)*sys->nangles, "ABFbalpha"); 02248 sys->bTriangle = (float*)MEM_mallocN(sizeof(float)*sys->nfaces, "ABFbtriangle"); 02249 sys->bInterior = (float*)MEM_mallocN(sizeof(float)*2*sys->ninterior, "ABFbinterior"); 02250 02251 sys->lambdaTriangle = (float*)MEM_callocN(sizeof(float)*sys->nfaces, "ABFlambdatri"); 02252 sys->lambdaPlanar = (float*)MEM_callocN(sizeof(float)*sys->ninterior, "ABFlamdaplane"); 02253 sys->lambdaLength = (float*)MEM_mallocN(sizeof(float)*sys->ninterior, "ABFlambdalen"); 02254 02255 sys->J2dt = MEM_mallocN(sizeof(float)*sys->nangles*3, "ABFj2dt"); 02256 sys->bstar = (float*)MEM_mallocN(sizeof(float)*sys->nfaces, "ABFbstar"); 02257 sys->dstar = (float*)MEM_mallocN(sizeof(float)*sys->nfaces, "ABFdstar"); 02258 02259 for (i = 0; i < sys->ninterior; i++) 02260 sys->lambdaLength[i] = 1.0; 02261 02262 sys->minangle = 7.5*M_PI/180.0; 02263 sys->maxangle = (float)M_PI - sys->minangle; 02264 } 02265 02266 static void p_abf_free_system(PAbfSystem *sys) 02267 { 02268 MEM_freeN(sys->alpha); 02269 MEM_freeN(sys->beta); 02270 MEM_freeN(sys->sine); 02271 MEM_freeN(sys->cosine); 02272 MEM_freeN(sys->weight); 02273 MEM_freeN(sys->bAlpha); 02274 MEM_freeN(sys->bTriangle); 02275 MEM_freeN(sys->bInterior); 02276 MEM_freeN(sys->lambdaTriangle); 02277 MEM_freeN(sys->lambdaPlanar); 02278 MEM_freeN(sys->lambdaLength); 02279 MEM_freeN(sys->J2dt); 02280 MEM_freeN(sys->bstar); 02281 MEM_freeN(sys->dstar); 02282 } 02283 02284 static void p_abf_compute_sines(PAbfSystem *sys) 02285 { 02286 int i; 02287 float *sine = sys->sine, *cosine = sys->cosine, *alpha = sys->alpha; 02288 02289 for (i = 0; i < sys->nangles; i++, sine++, cosine++, alpha++) { 02290 *sine = sin(*alpha); 02291 *cosine = cos(*alpha); 02292 } 02293 } 02294 02295 static float p_abf_compute_sin_product(PAbfSystem *sys, PVert *v, int aid) 02296 { 02297 PEdge *e, *e1, *e2; 02298 float sin1, sin2; 02299 02300 sin1 = sin2 = 1.0; 02301 02302 e = v->edge; 02303 do { 02304 e1 = e->next; 02305 e2 = e->next->next; 02306 02307 if (aid == e1->u.id) { 02308 /* we are computing a derivative for this angle, 02309 so we use cos and drop the other part */ 02310 sin1 *= sys->cosine[e1->u.id]; 02311 sin2 = 0.0; 02312 } 02313 else 02314 sin1 *= sys->sine[e1->u.id]; 02315 02316 if (aid == e2->u.id) { 02317 /* see above */ 02318 sin1 = 0.0; 02319 sin2 *= sys->cosine[e2->u.id]; 02320 } 02321 else 02322 sin2 *= sys->sine[e2->u.id]; 02323 02324 e = e->next->next->pair; 02325 } while (e && (e != v->edge)); 02326 02327 return (sin1 - sin2); 02328 } 02329 02330 static float p_abf_compute_grad_alpha(PAbfSystem *sys, PFace *f, PEdge *e) 02331 { 02332 PVert *v = e->vert, *v1 = e->next->vert, *v2 = e->next->next->vert; 02333 float deriv; 02334 02335 deriv = (sys->alpha[e->u.id] - sys->beta[e->u.id])*sys->weight[e->u.id]; 02336 deriv += sys->lambdaTriangle[f->u.id]; 02337 02338 if (v->flag & PVERT_INTERIOR) { 02339 deriv += sys->lambdaPlanar[v->u.id]; 02340 } 02341 02342 if (v1->flag & PVERT_INTERIOR) { 02343 float product = p_abf_compute_sin_product(sys, v1, e->u.id); 02344 deriv += sys->lambdaLength[v1->u.id]*product; 02345 } 02346 02347 if (v2->flag & PVERT_INTERIOR) { 02348 float product = p_abf_compute_sin_product(sys, v2, e->u.id); 02349 deriv += sys->lambdaLength[v2->u.id]*product; 02350 } 02351 02352 return deriv; 02353 } 02354 02355 static float p_abf_compute_gradient(PAbfSystem *sys, PChart *chart) 02356 { 02357 PFace *f; 02358 PEdge *e; 02359 PVert *v; 02360 float norm = 0.0; 02361 02362 for (f=chart->faces; f; f=f->nextlink) { 02363 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 02364 float gtriangle, galpha1, galpha2, galpha3; 02365 02366 galpha1 = p_abf_compute_grad_alpha(sys, f, e1); 02367 galpha2 = p_abf_compute_grad_alpha(sys, f, e2); 02368 galpha3 = p_abf_compute_grad_alpha(sys, f, e3); 02369 02370 sys->bAlpha[e1->u.id] = -galpha1; 02371 sys->bAlpha[e2->u.id] = -galpha2; 02372 sys->bAlpha[e3->u.id] = -galpha3; 02373 02374 norm += galpha1*galpha1 + galpha2*galpha2 + galpha3*galpha3; 02375 02376 gtriangle = sys->alpha[e1->u.id] + sys->alpha[e2->u.id] + sys->alpha[e3->u.id] - (float)M_PI; 02377 sys->bTriangle[f->u.id] = -gtriangle; 02378 norm += gtriangle*gtriangle; 02379 } 02380 02381 for (v=chart->verts; v; v=v->nextlink) { 02382 if (v->flag & PVERT_INTERIOR) { 02383 float gplanar = -2*M_PI, glength; 02384 02385 e = v->edge; 02386 do { 02387 gplanar += sys->alpha[e->u.id]; 02388 e = e->next->next->pair; 02389 } while (e && (e != v->edge)); 02390 02391 sys->bInterior[v->u.id] = -gplanar; 02392 norm += gplanar*gplanar; 02393 02394 glength = p_abf_compute_sin_product(sys, v, -1); 02395 sys->bInterior[sys->ninterior + v->u.id] = -glength; 02396 norm += glength*glength; 02397 } 02398 } 02399 02400 return norm; 02401 } 02402 02403 static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) 02404 { 02405 PFace *f; 02406 PEdge *e; 02407 int i, j, ninterior = sys->ninterior, nvar = 2*sys->ninterior; 02408 PBool success; 02409 02410 nlNewContext(); 02411 nlSolverParameteri(NL_NB_VARIABLES, nvar); 02412 02413 nlBegin(NL_SYSTEM); 02414 02415 nlBegin(NL_MATRIX); 02416 02417 for (i = 0; i < nvar; i++) 02418 nlRightHandSideAdd(0, i, sys->bInterior[i]); 02419 02420 for (f=chart->faces; f; f=f->nextlink) { 02421 float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3]; 02422 float row1[6], row2[6], row3[6]; 02423 int vid[6]; 02424 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 02425 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; 02426 02427 wi1 = 1.0f/sys->weight[e1->u.id]; 02428 wi2 = 1.0f/sys->weight[e2->u.id]; 02429 wi3 = 1.0f/sys->weight[e3->u.id]; 02430 02431 /* bstar1 = (J1*dInv*bAlpha - bTriangle) */ 02432 b = sys->bAlpha[e1->u.id]*wi1; 02433 b += sys->bAlpha[e2->u.id]*wi2; 02434 b += sys->bAlpha[e3->u.id]*wi3; 02435 b -= sys->bTriangle[f->u.id]; 02436 02437 /* si = J1*d*J1t */ 02438 si = 1.0f/(wi1 + wi2 + wi3); 02439 02440 /* J1t*si*bstar1 - bAlpha */ 02441 beta[0] = b*si - sys->bAlpha[e1->u.id]; 02442 beta[1] = b*si - sys->bAlpha[e2->u.id]; 02443 beta[2] = b*si - sys->bAlpha[e3->u.id]; 02444 02445 /* use this later for computing other lambda's */ 02446 sys->bstar[f->u.id] = b; 02447 sys->dstar[f->u.id] = si; 02448 02449 /* set matrix */ 02450 W[0][0] = si - sys->weight[e1->u.id]; W[0][1] = si; W[0][2] = si; 02451 W[1][0] = si; W[1][1] = si - sys->weight[e2->u.id]; W[1][2] = si; 02452 W[2][0] = si; W[2][1] = si; W[2][2] = si - sys->weight[e3->u.id]; 02453 02454 vid[0] = vid[1] = vid[2] = vid[3] = vid[4] = vid[5] = -1; 02455 02456 if (v1->flag & PVERT_INTERIOR) { 02457 vid[0] = v1->u.id; 02458 vid[3] = ninterior + v1->u.id; 02459 02460 sys->J2dt[e1->u.id][0] = j2[0][0] = 1.0f * wi1; 02461 sys->J2dt[e2->u.id][0] = j2[1][0] = p_abf_compute_sin_product(sys, v1, e2->u.id)*wi2; 02462 sys->J2dt[e3->u.id][0] = j2[2][0] = p_abf_compute_sin_product(sys, v1, e3->u.id)*wi3; 02463 02464 nlRightHandSideAdd(0, v1->u.id, j2[0][0]*beta[0]); 02465 nlRightHandSideAdd(0, ninterior + v1->u.id, j2[1][0]*beta[1] + j2[2][0]*beta[2]); 02466 02467 row1[0] = j2[0][0]*W[0][0]; 02468 row2[0] = j2[0][0]*W[1][0]; 02469 row3[0] = j2[0][0]*W[2][0]; 02470 02471 row1[3] = j2[1][0]*W[0][1] + j2[2][0]*W[0][2]; 02472 row2[3] = j2[1][0]*W[1][1] + j2[2][0]*W[1][2]; 02473 row3[3] = j2[1][0]*W[2][1] + j2[2][0]*W[2][2]; 02474 } 02475 02476 if (v2->flag & PVERT_INTERIOR) { 02477 vid[1] = v2->u.id; 02478 vid[4] = ninterior + v2->u.id; 02479 02480 sys->J2dt[e1->u.id][1] = j2[0][1] = p_abf_compute_sin_product(sys, v2, e1->u.id)*wi1; 02481 sys->J2dt[e2->u.id][1] = j2[1][1] = 1.0f*wi2; 02482 sys->J2dt[e3->u.id][1] = j2[2][1] = p_abf_compute_sin_product(sys, v2, e3->u.id)*wi3; 02483 02484 nlRightHandSideAdd(0, v2->u.id, j2[1][1]*beta[1]); 02485 nlRightHandSideAdd(0, ninterior + v2->u.id, j2[0][1]*beta[0] + j2[2][1]*beta[2]); 02486 02487 row1[1] = j2[1][1]*W[0][1]; 02488 row2[1] = j2[1][1]*W[1][1]; 02489 row3[1] = j2[1][1]*W[2][1]; 02490 02491 row1[4] = j2[0][1]*W[0][0] + j2[2][1]*W[0][2]; 02492 row2[4] = j2[0][1]*W[1][0] + j2[2][1]*W[1][2]; 02493 row3[4] = j2[0][1]*W[2][0] + j2[2][1]*W[2][2]; 02494 } 02495 02496 if (v3->flag & PVERT_INTERIOR) { 02497 vid[2] = v3->u.id; 02498 vid[5] = ninterior + v3->u.id; 02499 02500 sys->J2dt[e1->u.id][2] = j2[0][2] = p_abf_compute_sin_product(sys, v3, e1->u.id)*wi1; 02501 sys->J2dt[e2->u.id][2] = j2[1][2] = p_abf_compute_sin_product(sys, v3, e2->u.id)*wi2; 02502 sys->J2dt[e3->u.id][2] = j2[2][2] = 1.0f * wi3; 02503 02504 nlRightHandSideAdd(0, v3->u.id, j2[2][2]*beta[2]); 02505 nlRightHandSideAdd(0, ninterior + v3->u.id, j2[0][2]*beta[0] + j2[1][2]*beta[1]); 02506 02507 row1[2] = j2[2][2]*W[0][2]; 02508 row2[2] = j2[2][2]*W[1][2]; 02509 row3[2] = j2[2][2]*W[2][2]; 02510 02511 row1[5] = j2[0][2]*W[0][0] + j2[1][2]*W[0][1]; 02512 row2[5] = j2[0][2]*W[1][0] + j2[1][2]*W[1][1]; 02513 row3[5] = j2[0][2]*W[2][0] + j2[1][2]*W[2][1]; 02514 } 02515 02516 for (i = 0; i < 3; i++) { 02517 int r = vid[i]; 02518 02519 if (r == -1) 02520 continue; 02521 02522 for (j = 0; j < 6; j++) { 02523 int c = vid[j]; 02524 02525 if (c == -1) 02526 continue; 02527 02528 if (i == 0) 02529 nlMatrixAdd(r, c, j2[0][i]*row1[j]); 02530 else 02531 nlMatrixAdd(r + ninterior, c, j2[0][i]*row1[j]); 02532 02533 if (i == 1) 02534 nlMatrixAdd(r, c, j2[1][i]*row2[j]); 02535 else 02536 nlMatrixAdd(r + ninterior, c, j2[1][i]*row2[j]); 02537 02538 02539 if (i == 2) 02540 nlMatrixAdd(r, c, j2[2][i]*row3[j]); 02541 else 02542 nlMatrixAdd(r + ninterior, c, j2[2][i]*row3[j]); 02543 } 02544 } 02545 } 02546 02547 nlEnd(NL_MATRIX); 02548 02549 nlEnd(NL_SYSTEM); 02550 02551 success = nlSolve(); 02552 02553 if (success) { 02554 for (f=chart->faces; f; f=f->nextlink) { 02555 float dlambda1, pre[3], dalpha; 02556 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 02557 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; 02558 02559 pre[0] = pre[1] = pre[2] = 0.0; 02560 02561 if (v1->flag & PVERT_INTERIOR) { 02562 float x = nlGetVariable(0, v1->u.id); 02563 float x2 = nlGetVariable(0, ninterior + v1->u.id); 02564 pre[0] += sys->J2dt[e1->u.id][0]*x; 02565 pre[1] += sys->J2dt[e2->u.id][0]*x2; 02566 pre[2] += sys->J2dt[e3->u.id][0]*x2; 02567 } 02568 02569 if (v2->flag & PVERT_INTERIOR) { 02570 float x = nlGetVariable(0, v2->u.id); 02571 float x2 = nlGetVariable(0, ninterior + v2->u.id); 02572 pre[0] += sys->J2dt[e1->u.id][1]*x2; 02573 pre[1] += sys->J2dt[e2->u.id][1]*x; 02574 pre[2] += sys->J2dt[e3->u.id][1]*x2; 02575 } 02576 02577 if (v3->flag & PVERT_INTERIOR) { 02578 float x = nlGetVariable(0, v3->u.id); 02579 float x2 = nlGetVariable(0, ninterior + v3->u.id); 02580 pre[0] += sys->J2dt[e1->u.id][2]*x2; 02581 pre[1] += sys->J2dt[e2->u.id][2]*x2; 02582 pre[2] += sys->J2dt[e3->u.id][2]*x; 02583 } 02584 02585 dlambda1 = pre[0] + pre[1] + pre[2]; 02586 dlambda1 = sys->dstar[f->u.id]*(sys->bstar[f->u.id] - dlambda1); 02587 02588 sys->lambdaTriangle[f->u.id] += dlambda1; 02589 02590 dalpha = (sys->bAlpha[e1->u.id] - dlambda1); 02591 sys->alpha[e1->u.id] += dalpha/sys->weight[e1->u.id] - pre[0]; 02592 02593 dalpha = (sys->bAlpha[e2->u.id] - dlambda1); 02594 sys->alpha[e2->u.id] += dalpha/sys->weight[e2->u.id] - pre[1]; 02595 02596 dalpha = (sys->bAlpha[e3->u.id] - dlambda1); 02597 sys->alpha[e3->u.id] += dalpha/sys->weight[e3->u.id] - pre[2]; 02598 02599 /* clamp */ 02600 e = f->edge; 02601 do { 02602 if (sys->alpha[e->u.id] > (float)M_PI) 02603 sys->alpha[e->u.id] = (float)M_PI; 02604 else if (sys->alpha[e->u.id] < 0.0f) 02605 sys->alpha[e->u.id] = 0.0f; 02606 } while (e != f->edge); 02607 } 02608 02609 for (i = 0; i < ninterior; i++) { 02610 sys->lambdaPlanar[i] += nlGetVariable(0, i); 02611 sys->lambdaLength[i] += nlGetVariable(0, ninterior + i); 02612 } 02613 } 02614 02615 nlDeleteContext(nlGetCurrent()); 02616 02617 return success; 02618 } 02619 02620 static PBool p_chart_abf_solve(PChart *chart) 02621 { 02622 PVert *v; 02623 PFace *f; 02624 PEdge *e, *e1, *e2, *e3; 02625 PAbfSystem sys; 02626 int i; 02627 float lastnorm, limit = (chart->nfaces > 100)? 1.0f: 0.001f; 02628 02629 /* setup id's */ 02630 sys.ninterior = sys.nfaces = sys.nangles = 0; 02631 02632 for (v=chart->verts; v; v=v->nextlink) { 02633 if (p_vert_interior(v)) { 02634 v->flag |= PVERT_INTERIOR; 02635 v->u.id = sys.ninterior++; 02636 } 02637 else 02638 v->flag &= ~PVERT_INTERIOR; 02639 } 02640 02641 for (f=chart->faces; f; f=f->nextlink) { 02642 e1 = f->edge; e2 = e1->next; e3 = e2->next; 02643 f->u.id = sys.nfaces++; 02644 02645 /* angle id's are conveniently stored in half edges */ 02646 e1->u.id = sys.nangles++; 02647 e2->u.id = sys.nangles++; 02648 e3->u.id = sys.nangles++; 02649 } 02650 02651 p_abf_setup_system(&sys); 02652 02653 /* compute initial angles */ 02654 for (f=chart->faces; f; f=f->nextlink) { 02655 float a1, a2, a3; 02656 02657 e1 = f->edge; e2 = e1->next; e3 = e2->next; 02658 p_face_angles(f, &a1, &a2, &a3); 02659 02660 if (a1 < sys.minangle) 02661 a1 = sys.minangle; 02662 else if (a1 > sys.maxangle) 02663 a1 = sys.maxangle; 02664 if (a2 < sys.minangle) 02665 a2 = sys.minangle; 02666 else if (a2 > sys.maxangle) 02667 a2 = sys.maxangle; 02668 if (a3 < sys.minangle) 02669 a3 = sys.minangle; 02670 else if (a3 > sys.maxangle) 02671 a3 = sys.maxangle; 02672 02673 sys.alpha[e1->u.id] = sys.beta[e1->u.id] = a1; 02674 sys.alpha[e2->u.id] = sys.beta[e2->u.id] = a2; 02675 sys.alpha[e3->u.id] = sys.beta[e3->u.id] = a3; 02676 02677 sys.weight[e1->u.id] = 2.0f/(a1*a1); 02678 sys.weight[e2->u.id] = 2.0f/(a2*a2); 02679 sys.weight[e3->u.id] = 2.0f/(a3*a3); 02680 } 02681 02682 for (v=chart->verts; v; v=v->nextlink) { 02683 if (v->flag & PVERT_INTERIOR) { 02684 float anglesum = 0.0, scale; 02685 02686 e = v->edge; 02687 do { 02688 anglesum += sys.beta[e->u.id]; 02689 e = e->next->next->pair; 02690 } while (e && (e != v->edge)); 02691 02692 scale = (anglesum == 0.0f)? 0.0f: 2.0f*(float)M_PI/anglesum; 02693 02694 e = v->edge; 02695 do { 02696 sys.beta[e->u.id] = sys.alpha[e->u.id] = sys.beta[e->u.id]*scale; 02697 e = e->next->next->pair; 02698 } while (e && (e != v->edge)); 02699 } 02700 } 02701 02702 if (sys.ninterior > 0) { 02703 p_abf_compute_sines(&sys); 02704 02705 /* iteration */ 02706 lastnorm = 1e10; 02707 02708 for (i = 0; i < ABF_MAX_ITER; i++) { 02709 float norm = p_abf_compute_gradient(&sys, chart); 02710 02711 lastnorm = norm; 02712 02713 if (norm < limit) 02714 break; 02715 02716 if (!p_abf_matrix_invert(&sys, chart)) { 02717 param_warning("ABF failed to invert matrix."); 02718 p_abf_free_system(&sys); 02719 return P_FALSE; 02720 } 02721 02722 p_abf_compute_sines(&sys); 02723 } 02724 02725 if (i == ABF_MAX_ITER) { 02726 param_warning("ABF maximum iterations reached."); 02727 p_abf_free_system(&sys); 02728 return P_FALSE; 02729 } 02730 } 02731 02732 chart->u.lscm.abf_alpha = MEM_dupallocN(sys.alpha); 02733 p_abf_free_system(&sys); 02734 02735 return P_TRUE; 02736 } 02737 02738 /* Least Squares Conformal Maps */ 02739 02740 static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2) 02741 { 02742 if (pin1 == pin2) { 02743 /* degenerate case */ 02744 PFace *f = chart->faces; 02745 *pin1 = f->edge->vert; 02746 *pin2 = f->edge->next->vert; 02747 02748 (*pin1)->uv[0] = 0.0f; 02749 (*pin1)->uv[1] = 0.5f; 02750 (*pin2)->uv[0] = 1.0f; 02751 (*pin2)->uv[1] = 0.5f; 02752 } 02753 else { 02754 int diru, dirv, dirx, diry; 02755 float sub[3]; 02756 02757 sub_v3_v3v3(sub, (*pin1)->co, (*pin2)->co); 02758 sub[0] = fabs(sub[0]); 02759 sub[1] = fabs(sub[1]); 02760 sub[2] = fabs(sub[2]); 02761 02762 if ((sub[0] > sub[1]) && (sub[0] > sub[2])) { 02763 dirx = 0; 02764 diry = (sub[1] > sub[2])? 1: 2; 02765 } 02766 else if ((sub[1] > sub[0]) && (sub[1] > sub[2])) { 02767 dirx = 1; 02768 diry = (sub[0] > sub[2])? 0: 2; 02769 } 02770 else { 02771 dirx = 2; 02772 diry = (sub[0] > sub[1])? 0: 1; 02773 } 02774 02775 if (dirx == 2) { 02776 diru = 1; 02777 dirv = 0; 02778 } 02779 else { 02780 diru = 0; 02781 dirv = 1; 02782 } 02783 02784 (*pin1)->uv[diru] = (*pin1)->co[dirx]; 02785 (*pin1)->uv[dirv] = (*pin1)->co[diry]; 02786 (*pin2)->uv[diru] = (*pin2)->co[dirx]; 02787 (*pin2)->uv[dirv] = (*pin2)->co[diry]; 02788 } 02789 } 02790 02791 static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2) 02792 { 02793 PEdge *be, *lastbe = NULL, *maxe1 = NULL, *maxe2 = NULL, *be1, *be2; 02794 PEdge *cure = NULL, *firste1 = NULL, *firste2 = NULL, *nextbe; 02795 float maxlen = 0.0f, curlen = 0.0f, totlen = 0.0f, firstlen = 0.0f; 02796 float len1, len2; 02797 02798 /* find longest series of verts split in the chart itself, these are 02799 marked during construction */ 02800 be = outer; 02801 lastbe = p_boundary_edge_prev(be); 02802 do { 02803 float len = p_edge_length(be); 02804 totlen += len; 02805 02806 nextbe = p_boundary_edge_next(be); 02807 02808 if ((be->vert->flag & PVERT_SPLIT) || 02809 (lastbe->vert->flag & nextbe->vert->flag & PVERT_SPLIT)) { 02810 if (!cure) { 02811 if (be == outer) 02812 firste1 = be; 02813 cure = be; 02814 } 02815 else 02816 curlen += p_edge_length(lastbe); 02817 } 02818 else if (cure) { 02819 if (curlen > maxlen) { 02820 maxlen = curlen; 02821 maxe1 = cure; 02822 maxe2 = lastbe; 02823 } 02824 02825 if (firste1 == cure) { 02826 firstlen = curlen; 02827 firste2 = lastbe; 02828 } 02829 02830 curlen = 0.0f; 02831 cure = NULL; 02832 } 02833 02834 lastbe = be; 02835 be = nextbe; 02836 } while(be != outer); 02837 02838 /* make sure we also count a series of splits over the starting point */ 02839 if (cure && (cure != outer)) { 02840 firstlen += curlen + p_edge_length(be); 02841 02842 if (firstlen > maxlen) { 02843 maxlen = firstlen; 02844 maxe1 = cure; 02845 maxe2 = firste2; 02846 } 02847 } 02848 02849 if (!maxe1 || !maxe2 || (maxlen < 0.5f*totlen)) 02850 return P_FALSE; 02851 02852 /* find pin1 in the split vertices */ 02853 be1 = maxe1; 02854 be2 = maxe2; 02855 len1 = 0.0f; 02856 len2 = 0.0f; 02857 02858 do { 02859 if (len1 < len2) { 02860 len1 += p_edge_length(be1); 02861 be1 = p_boundary_edge_next(be1); 02862 } 02863 else { 02864 be2 = p_boundary_edge_prev(be2); 02865 len2 += p_edge_length(be2); 02866 } 02867 } while (be1 != be2); 02868 02869 *pin1 = be1->vert; 02870 02871 /* find pin2 outside the split vertices */ 02872 be1 = maxe1; 02873 be2 = maxe2; 02874 len1 = 0.0f; 02875 len2 = 0.0f; 02876 02877 do { 02878 if (len1 < len2) { 02879 be1 = p_boundary_edge_prev(be1); 02880 len1 += p_edge_length(be1); 02881 } 02882 else { 02883 len2 += p_edge_length(be2); 02884 be2 = p_boundary_edge_next(be2); 02885 } 02886 } while (be1 != be2); 02887 02888 *pin2 = be1->vert; 02889 02890 p_chart_pin_positions(chart, pin1, pin2); 02891 02892 return P_TRUE; 02893 } 02894 02895 static void p_chart_extrema_verts(PChart *chart, PVert **pin1, PVert **pin2) 02896 { 02897 float minv[3], maxv[3], dirlen; 02898 PVert *v, *minvert[3], *maxvert[3]; 02899 int i, dir; 02900 02901 /* find minimum and maximum verts over x/y/z axes */ 02902 minv[0] = minv[1] = minv[2] = 1e20; 02903 maxv[0] = maxv[1] = maxv[2] = -1e20; 02904 02905 minvert[0] = minvert[1] = minvert[2] = NULL; 02906 maxvert[0] = maxvert[1] = maxvert[2] = NULL; 02907 02908 for (v = chart->verts; v; v=v->nextlink) { 02909 for (i = 0; i < 3; i++) { 02910 if (v->co[i] < minv[i]) { 02911 minv[i] = v->co[i]; 02912 minvert[i] = v; 02913 } 02914 if (v->co[i] > maxv[i]) { 02915 maxv[i] = v->co[i]; 02916 maxvert[i] = v; 02917 } 02918 } 02919 } 02920 02921 /* find axes with longest distance */ 02922 dir = 0; 02923 dirlen = -1.0; 02924 02925 for (i = 0; i < 3; i++) { 02926 if (maxv[i] - minv[i] > dirlen) { 02927 dir = i; 02928 dirlen = maxv[i] - minv[i]; 02929 } 02930 } 02931 02932 *pin1 = minvert[dir]; 02933 *pin2 = maxvert[dir]; 02934 02935 p_chart_pin_positions(chart, pin1, pin2); 02936 } 02937 02938 static void p_chart_lscm_load_solution(PChart *chart) 02939 { 02940 PVert *v; 02941 02942 for (v=chart->verts; v; v=v->nextlink) { 02943 v->uv[0] = nlGetVariable(0, 2*v->u.id); 02944 v->uv[1] = nlGetVariable(0, 2*v->u.id + 1); 02945 } 02946 } 02947 02948 static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) 02949 { 02950 PVert *v, *pin1, *pin2; 02951 PBool select = P_FALSE, deselect = P_FALSE; 02952 int npins = 0, id = 0; 02953 02954 /* give vertices matrix indices and count pins */ 02955 for (v=chart->verts; v; v=v->nextlink) { 02956 if (v->flag & PVERT_PIN) { 02957 npins++; 02958 if (v->flag & PVERT_SELECT) 02959 select = P_TRUE; 02960 } 02961 02962 if (!(v->flag & PVERT_SELECT)) 02963 deselect = P_TRUE; 02964 } 02965 02966 if ((live && (!select || !deselect)) || (npins == 1)) { 02967 chart->u.lscm.context = NULL; 02968 } 02969 else { 02970 #if 0 02971 p_chart_simplify_compute(chart); 02972 p_chart_topological_sanity_check(chart); 02973 #endif 02974 02975 if (abf) { 02976 if (!p_chart_abf_solve(chart)) 02977 param_warning("ABF solving failed: falling back to LSCM.\n"); 02978 } 02979 02980 if (npins <= 1) { 02981 /* not enough pins, lets find some ourself */ 02982 PEdge *outer; 02983 02984 p_chart_boundaries(chart, NULL, &outer); 02985 02986 if (!p_chart_symmetry_pins(chart, outer, &pin1, &pin2)) 02987 p_chart_extrema_verts(chart, &pin1, &pin2); 02988 02989 chart->u.lscm.pin1 = pin1; 02990 chart->u.lscm.pin2 = pin2; 02991 } 02992 else { 02993 chart->flag |= PCHART_NOPACK; 02994 } 02995 02996 for (v=chart->verts; v; v=v->nextlink) 02997 v->u.id = id++; 02998 02999 nlNewContext(); 03000 nlSolverParameteri(NL_NB_VARIABLES, 2*chart->nverts); 03001 nlSolverParameteri(NL_NB_ROWS, 2*chart->nfaces); 03002 nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE); 03003 03004 chart->u.lscm.context = nlGetCurrent(); 03005 } 03006 } 03007 03008 static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart) 03009 { 03010 PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2; 03011 PFace *f; 03012 float *alpha = chart->u.lscm.abf_alpha; 03013 int row; 03014 03015 nlMakeCurrent(chart->u.lscm.context); 03016 03017 nlBegin(NL_SYSTEM); 03018 03019 #if 0 03020 /* TODO: make loading pins work for simplify/complexify. */ 03021 #endif 03022 03023 for (v=chart->verts; v; v=v->nextlink) 03024 if (v->flag & PVERT_PIN) 03025 p_vert_load_pin_select_uvs(handle, v); /* reload for live */ 03026 03027 if (chart->u.lscm.pin1) { 03028 nlLockVariable(2*pin1->u.id); 03029 nlLockVariable(2*pin1->u.id + 1); 03030 nlLockVariable(2*pin2->u.id); 03031 nlLockVariable(2*pin2->u.id + 1); 03032 03033 nlSetVariable(0, 2*pin1->u.id, pin1->uv[0]); 03034 nlSetVariable(0, 2*pin1->u.id + 1, pin1->uv[1]); 03035 nlSetVariable(0, 2*pin2->u.id, pin2->uv[0]); 03036 nlSetVariable(0, 2*pin2->u.id + 1, pin2->uv[1]); 03037 } 03038 else { 03039 /* set and lock the pins */ 03040 for (v=chart->verts; v; v=v->nextlink) { 03041 if (v->flag & PVERT_PIN) { 03042 nlLockVariable(2*v->u.id); 03043 nlLockVariable(2*v->u.id + 1); 03044 03045 nlSetVariable(0, 2*v->u.id, v->uv[0]); 03046 nlSetVariable(0, 2*v->u.id + 1, v->uv[1]); 03047 } 03048 } 03049 } 03050 03051 /* construct matrix */ 03052 03053 nlBegin(NL_MATRIX); 03054 03055 row = 0; 03056 for (f=chart->faces; f; f=f->nextlink) { 03057 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 03058 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; 03059 float a1, a2, a3, ratio, cosine, sine; 03060 float sina1, sina2, sina3, sinmax; 03061 03062 if (alpha) { 03063 /* use abf angles if passed on */ 03064 a1 = *(alpha++); 03065 a2 = *(alpha++); 03066 a3 = *(alpha++); 03067 } 03068 else 03069 p_face_angles(f, &a1, &a2, &a3); 03070 03071 sina1 = sin(a1); 03072 sina2 = sin(a2); 03073 sina3 = sin(a3); 03074 03075 sinmax = MAX3(sina1, sina2, sina3); 03076 03077 /* shift vertices to find most stable order */ 03078 if (sina3 != sinmax) { 03079 SHIFT3(PVert*, v1, v2, v3); 03080 SHIFT3(float, a1, a2, a3); 03081 SHIFT3(float, sina1, sina2, sina3); 03082 03083 if (sina2 == sinmax) { 03084 SHIFT3(PVert*, v1, v2, v3); 03085 SHIFT3(float, a1, a2, a3); 03086 SHIFT3(float, sina1, sina2, sina3); 03087 } 03088 } 03089 03090 /* angle based lscm formulation */ 03091 ratio = (sina3 == 0.0f)? 1.0f: sina2/sina3; 03092 cosine = cosf(a1)*ratio; 03093 sine = sina1*ratio; 03094 03095 #if 0 03096 nlBegin(NL_ROW); 03097 nlCoefficient(2*v1->u.id, cosine - 1.0); 03098 nlCoefficient(2*v1->u.id+1, -sine); 03099 nlCoefficient(2*v2->u.id, -cosine); 03100 nlCoefficient(2*v2->u.id+1, sine); 03101 nlCoefficient(2*v3->u.id, 1.0); 03102 nlEnd(NL_ROW); 03103 03104 nlBegin(NL_ROW); 03105 nlCoefficient(2*v1->u.id, sine); 03106 nlCoefficient(2*v1->u.id+1, cosine - 1.0); 03107 nlCoefficient(2*v2->u.id, -sine); 03108 nlCoefficient(2*v2->u.id+1, -cosine); 03109 nlCoefficient(2*v3->u.id+1, 1.0); 03110 nlEnd(NL_ROW); 03111 #else 03112 nlMatrixAdd(row, 2*v1->u.id, cosine - 1.0f); 03113 nlMatrixAdd(row, 2*v1->u.id+1, -sine); 03114 nlMatrixAdd(row, 2*v2->u.id, -cosine); 03115 nlMatrixAdd(row, 2*v2->u.id+1, sine); 03116 nlMatrixAdd(row, 2*v3->u.id, 1.0); 03117 row++; 03118 03119 nlMatrixAdd(row, 2*v1->u.id, sine); 03120 nlMatrixAdd(row, 2*v1->u.id+1, cosine - 1.0f); 03121 nlMatrixAdd(row, 2*v2->u.id, -sine); 03122 nlMatrixAdd(row, 2*v2->u.id+1, -cosine); 03123 nlMatrixAdd(row, 2*v3->u.id+1, 1.0); 03124 row++; 03125 #endif 03126 } 03127 03128 nlEnd(NL_MATRIX); 03129 03130 nlEnd(NL_SYSTEM); 03131 03132 if (nlSolveAdvanced(NULL, NL_TRUE)) { 03133 p_chart_lscm_load_solution(chart); 03134 return P_TRUE; 03135 } 03136 else { 03137 for (v=chart->verts; v; v=v->nextlink) { 03138 v->uv[0] = 0.0f; 03139 v->uv[1] = 0.0f; 03140 } 03141 } 03142 03143 return P_FALSE; 03144 } 03145 03146 static void p_chart_lscm_end(PChart *chart) 03147 { 03148 if (chart->u.lscm.context) 03149 nlDeleteContext(chart->u.lscm.context); 03150 03151 if (chart->u.lscm.abf_alpha) { 03152 MEM_freeN(chart->u.lscm.abf_alpha); 03153 chart->u.lscm.abf_alpha = NULL; 03154 } 03155 03156 chart->u.lscm.context = NULL; 03157 chart->u.lscm.pin1 = NULL; 03158 chart->u.lscm.pin2 = NULL; 03159 } 03160 03161 /* Stretch */ 03162 03163 #define P_STRETCH_ITER 20 03164 03165 static void p_stretch_pin_boundary(PChart *chart) 03166 { 03167 PVert *v; 03168 03169 for(v=chart->verts; v; v=v->nextlink) 03170 if (v->edge->pair == NULL) 03171 v->flag |= PVERT_PIN; 03172 else 03173 v->flag &= ~PVERT_PIN; 03174 } 03175 03176 static float p_face_stretch(PFace *f) 03177 { 03178 float T, w, tmp[3]; 03179 float Ps[3], Pt[3]; 03180 float a, c, area; 03181 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 03182 PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; 03183 03184 area = p_face_uv_area_signed(f); 03185 03186 if (area <= 0.0f) /* flipped face -> infinite stretch */ 03187 return 1e10f; 03188 03189 w= 1.0f/(2.0f*area); 03190 03191 /* compute derivatives */ 03192 copy_v3_v3(Ps, v1->co); 03193 mul_v3_fl(Ps, (v2->uv[1] - v3->uv[1])); 03194 03195 copy_v3_v3(tmp, v2->co); 03196 mul_v3_fl(tmp, (v3->uv[1] - v1->uv[1])); 03197 add_v3_v3(Ps, tmp); 03198 03199 copy_v3_v3(tmp, v3->co); 03200 mul_v3_fl(tmp, (v1->uv[1] - v2->uv[1])); 03201 add_v3_v3(Ps, tmp); 03202 03203 mul_v3_fl(Ps, w); 03204 03205 copy_v3_v3(Pt, v1->co); 03206 mul_v3_fl(Pt, (v3->uv[0] - v2->uv[0])); 03207 03208 copy_v3_v3(tmp, v2->co); 03209 mul_v3_fl(tmp, (v1->uv[0] - v3->uv[0])); 03210 add_v3_v3(Pt, tmp); 03211 03212 copy_v3_v3(tmp, v3->co); 03213 mul_v3_fl(tmp, (v2->uv[0] - v1->uv[0])); 03214 add_v3_v3(Pt, tmp); 03215 03216 mul_v3_fl(Pt, w); 03217 03218 /* Sander Tensor */ 03219 a= dot_v3v3(Ps, Ps); 03220 c= dot_v3v3(Pt, Pt); 03221 03222 T = sqrt(0.5f*(a + c)); 03223 if (f->flag & PFACE_FILLED) 03224 T *= 0.2f; 03225 03226 return T; 03227 } 03228 03229 static float p_stretch_compute_vertex(PVert *v) 03230 { 03231 PEdge *e = v->edge; 03232 float sum = 0.0f; 03233 03234 do { 03235 sum += p_face_stretch(e->face); 03236 e = p_wheel_edge_next(e); 03237 } while (e && e != (v->edge)); 03238 03239 return sum; 03240 } 03241 03242 static void p_chart_stretch_minimize(PChart *chart, RNG *rng) 03243 { 03244 PVert *v; 03245 PEdge *e; 03246 int j, nedges; 03247 float orig_stretch, low, stretch_low, high, stretch_high, mid, stretch; 03248 float orig_uv[2], dir[2], random_angle, trusted_radius; 03249 03250 for(v=chart->verts; v; v=v->nextlink) { 03251 if((v->flag & PVERT_PIN) || !(v->flag & PVERT_SELECT)) 03252 continue; 03253 03254 orig_stretch = p_stretch_compute_vertex(v); 03255 orig_uv[0] = v->uv[0]; 03256 orig_uv[1] = v->uv[1]; 03257 03258 /* move vertex in a random direction */ 03259 trusted_radius = 0.0f; 03260 nedges = 0; 03261 e = v->edge; 03262 03263 do { 03264 trusted_radius += p_edge_uv_length(e); 03265 nedges++; 03266 03267 e = p_wheel_edge_next(e); 03268 } while (e && e != (v->edge)); 03269 03270 trusted_radius /= 2 * nedges; 03271 03272 random_angle = rng_getFloat(rng) * 2.0f * (float)M_PI; 03273 dir[0] = trusted_radius * cosf(random_angle); 03274 dir[1] = trusted_radius * sinf(random_angle); 03275 03276 /* calculate old and new stretch */ 03277 low = 0; 03278 stretch_low = orig_stretch; 03279 03280 add_v2_v2v2(v->uv, orig_uv, dir); 03281 high = 1; 03282 stretch = stretch_high = p_stretch_compute_vertex(v); 03283 03284 /* binary search for lowest stretch position */ 03285 for (j = 0; j < P_STRETCH_ITER; j++) { 03286 mid = 0.5f * (low + high); 03287 v->uv[0]= orig_uv[0] + mid*dir[0]; 03288 v->uv[1]= orig_uv[1] + mid*dir[1]; 03289 stretch = p_stretch_compute_vertex(v); 03290 03291 if (stretch_low < stretch_high) { 03292 high = mid; 03293 stretch_high = stretch; 03294 } 03295 else { 03296 low = mid; 03297 stretch_low = stretch; 03298 } 03299 } 03300 03301 /* no luck, stretch has increased, reset to old values */ 03302 if(stretch >= orig_stretch) 03303 copy_v2_v2(v->uv, orig_uv); 03304 } 03305 } 03306 03307 /* Minimum area enclosing rectangle for packing */ 03308 03309 static int p_compare_geometric_uv(const void *a, const void *b) 03310 { 03311 PVert *v1 = *(PVert**)a; 03312 PVert *v2 = *(PVert**)b; 03313 03314 if (v1->uv[0] < v2->uv[0]) 03315 return -1; 03316 else if (v1->uv[0] == v2->uv[0]) { 03317 if (v1->uv[1] < v2->uv[1]) 03318 return -1; 03319 else if (v1->uv[1] == v2->uv[1]) 03320 return 0; 03321 else 03322 return 1; 03323 } 03324 else 03325 return 1; 03326 } 03327 03328 static PBool p_chart_convex_hull(PChart *chart, PVert ***verts, int *nverts, int *right) 03329 { 03330 /* Graham algorithm, taken from: 03331 * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117225 */ 03332 03333 PEdge *be, *e; 03334 int npoints = 0, i, ulen, llen; 03335 PVert **U, **L, **points, **p; 03336 03337 p_chart_boundaries(chart, NULL, &be); 03338 03339 if (!be) 03340 return P_FALSE; 03341 03342 e = be; 03343 do { 03344 npoints++; 03345 e = p_boundary_edge_next(e); 03346 } while(e != be); 03347 03348 p = points = (PVert**)MEM_mallocN(sizeof(PVert*)*npoints*2, "PCHullpoints"); 03349 U = (PVert**)MEM_mallocN(sizeof(PVert*)*npoints, "PCHullU"); 03350 L = (PVert**)MEM_mallocN(sizeof(PVert*)*npoints, "PCHullL"); 03351 03352 e = be; 03353 do { 03354 *p = e->vert; 03355 p++; 03356 e = p_boundary_edge_next(e); 03357 } while(e != be); 03358 03359 qsort(points, npoints, sizeof(PVert*), p_compare_geometric_uv); 03360 03361 ulen = llen = 0; 03362 for (p=points, i = 0; i < npoints; i++, p++) { 03363 while ((ulen > 1) && (p_area_signed(U[ulen-2]->uv, (*p)->uv, U[ulen-1]->uv) <= 0)) 03364 ulen--; 03365 while ((llen > 1) && (p_area_signed(L[llen-2]->uv, (*p)->uv, L[llen-1]->uv) >= 0)) 03366 llen--; 03367 03368 U[ulen] = *p; 03369 ulen++; 03370 L[llen] = *p; 03371 llen++; 03372 } 03373 03374 npoints = 0; 03375 for (p=points, i = 0; i < ulen; i++, p++, npoints++) 03376 *p = U[i]; 03377 03378 /* the first and last point in L are left out, since they are also in U */ 03379 for (i = llen-2; i > 0; i--, p++, npoints++) 03380 *p = L[i]; 03381 03382 *verts = points; 03383 *nverts = npoints; 03384 *right = ulen - 1; 03385 03386 MEM_freeN(U); 03387 MEM_freeN(L); 03388 03389 return P_TRUE; 03390 } 03391 03392 static float p_rectangle_area(float *p1, float *dir, float *p2, float *p3, float *p4) 03393 { 03394 /* given 4 points on the rectangle edges and the direction of on edge, 03395 compute the area of the rectangle */ 03396 03397 float orthodir[2], corner1[2], corner2[2], corner3[2]; 03398 03399 orthodir[0] = dir[1]; 03400 orthodir[1] = -dir[0]; 03401 03402 if (!p_intersect_line_2d_dir(p1, dir, p2, orthodir, corner1)) 03403 return 1e10; 03404 03405 if (!p_intersect_line_2d_dir(p1, dir, p4, orthodir, corner2)) 03406 return 1e10; 03407 03408 if (!p_intersect_line_2d_dir(p3, dir, p4, orthodir, corner3)) 03409 return 1e10; 03410 03411 return len_v2v2(corner1, corner2)*len_v2v2(corner2, corner3); 03412 } 03413 03414 static float p_chart_minimum_area_angle(PChart *chart) 03415 { 03416 /* minimum area enclosing rectangle with rotating calipers, info: 03417 * http://cgm.cs.mcgill.ca/~orm/maer.html */ 03418 03419 float rotated, minarea, minangle, area, len; 03420 float *angles, miny, maxy, v[2], a[4], mina; 03421 int npoints, right, mini, maxi, i, idx[4], nextidx; 03422 PVert **points, *p1, *p2, *p3, *p4, *p1n; 03423 03424 /* compute convex hull */ 03425 if (!p_chart_convex_hull(chart, &points, &npoints, &right)) 03426 return 0.0; 03427 03428 /* find left/top/right/bottom points, and compute angle for each point */ 03429 angles = MEM_mallocN(sizeof(float)*npoints, "PMinAreaAngles"); 03430 03431 mini = maxi = 0; 03432 miny = 1e10; 03433 maxy = -1e10; 03434 03435 for (i = 0; i < npoints; i++) { 03436 p1 = (i == 0)? points[npoints-1]: points[i-1]; 03437 p2 = points[i]; 03438 p3 = (i == npoints-1)? points[0]: points[i+1]; 03439 03440 angles[i] = (float)M_PI - p_vec2_angle(p1->uv, p2->uv, p3->uv); 03441 03442 if (points[i]->uv[1] < miny) { 03443 miny = points[i]->uv[1]; 03444 mini = i; 03445 } 03446 if (points[i]->uv[1] > maxy) { 03447 maxy = points[i]->uv[1]; 03448 maxi = i; 03449 } 03450 } 03451 03452 /* left, top, right, bottom */ 03453 idx[0] = 0; 03454 idx[1] = maxi; 03455 idx[2] = right; 03456 idx[3] = mini; 03457 03458 v[0] = points[idx[0]]->uv[0]; 03459 v[1] = points[idx[0]]->uv[1] + 1.0f; 03460 a[0] = p_vec2_angle(points[(idx[0]+1)%npoints]->uv, points[idx[0]]->uv, v); 03461 03462 v[0] = points[idx[1]]->uv[0] + 1.0f; 03463 v[1] = points[idx[1]]->uv[1]; 03464 a[1] = p_vec2_angle(points[(idx[1]+1)%npoints]->uv, points[idx[1]]->uv, v); 03465 03466 v[0] = points[idx[2]]->uv[0]; 03467 v[1] = points[idx[2]]->uv[1] - 1.0f; 03468 a[2] = p_vec2_angle(points[(idx[2]+1)%npoints]->uv, points[idx[2]]->uv, v); 03469 03470 v[0] = points[idx[3]]->uv[0] - 1.0f; 03471 v[1] = points[idx[3]]->uv[1]; 03472 a[3] = p_vec2_angle(points[(idx[3]+1)%npoints]->uv, points[idx[3]]->uv, v); 03473 03474 /* 4 rotating calipers */ 03475 03476 rotated = 0.0; 03477 minarea = 1e10; 03478 minangle = 0.0; 03479 03480 while (rotated <= (float)(M_PI/2.0)) { /* INVESTIGATE: how far to rotate? */ 03481 /* rotate with the smallest angle */ 03482 mini = 0; 03483 mina = 1e10; 03484 03485 for (i = 0; i < 4; i++) 03486 if (a[i] < mina) { 03487 mina = a[i]; 03488 mini = i; 03489 } 03490 03491 rotated += mina; 03492 nextidx = (idx[mini]+1)%npoints; 03493 03494 a[mini] = angles[nextidx]; 03495 a[(mini+1)%4] = a[(mini+1)%4] - mina; 03496 a[(mini+2)%4] = a[(mini+2)%4] - mina; 03497 a[(mini+3)%4] = a[(mini+3)%4] - mina; 03498 03499 /* compute area */ 03500 p1 = points[idx[mini]]; 03501 p1n = points[nextidx]; 03502 p2 = points[idx[(mini+1)%4]]; 03503 p3 = points[idx[(mini+2)%4]]; 03504 p4 = points[idx[(mini+3)%4]]; 03505 03506 len = len_v2v2(p1->uv, p1n->uv); 03507 03508 if (len > 0.0f) { 03509 len = 1.0f/len; 03510 v[0] = (p1n->uv[0] - p1->uv[0])*len; 03511 v[1] = (p1n->uv[1] - p1->uv[1])*len; 03512 03513 area = p_rectangle_area(p1->uv, v, p2->uv, p3->uv, p4->uv); 03514 03515 /* remember smallest area */ 03516 if (area < minarea) { 03517 minarea = area; 03518 minangle = rotated; 03519 } 03520 } 03521 03522 idx[mini] = nextidx; 03523 } 03524 03525 /* try keeping rotation as small as possible */ 03526 if (minangle > (float)(M_PI/4)) 03527 minangle -= (float)(M_PI/2.0); 03528 03529 MEM_freeN(angles); 03530 MEM_freeN(points); 03531 03532 return minangle; 03533 } 03534 03535 static void p_chart_rotate_minimum_area(PChart *chart) 03536 { 03537 float angle = p_chart_minimum_area_angle(chart); 03538 float sine = sin(angle); 03539 float cosine = cos(angle); 03540 PVert *v; 03541 03542 for (v = chart->verts; v; v=v->nextlink) { 03543 float oldu = v->uv[0], oldv = v->uv[1]; 03544 v->uv[0] = cosine*oldu - sine*oldv; 03545 v->uv[1] = sine*oldu + cosine*oldv; 03546 } 03547 } 03548 03549 /* Area Smoothing */ 03550 03551 /* 2d bsp tree for inverse mapping - that's a bit silly */ 03552 03553 typedef struct SmoothTriangle { 03554 float co1[2], co2[2], co3[2]; 03555 float oco1[2], oco2[2], oco3[2]; 03556 } SmoothTriangle; 03557 03558 typedef struct SmoothNode { 03559 struct SmoothNode *c1, *c2; 03560 SmoothTriangle **tri; 03561 float split; 03562 int axis, ntri; 03563 } SmoothNode; 03564 03565 static void p_barycentric_2d(float *v1, float *v2, float *v3, float *p, float *b) 03566 { 03567 float a[2], c[2], h[2], div; 03568 03569 a[0] = v2[0] - v1[0]; 03570 a[1] = v2[1] - v1[1]; 03571 c[0] = v3[0] - v1[0]; 03572 c[1] = v3[1] - v1[1]; 03573 03574 div = a[0]*c[1] - a[1]*c[0]; 03575 03576 if (div == 0.0f) { 03577 b[0] = 1.0f/3.0f; 03578 b[1] = 1.0f/3.0f; 03579 b[2] = 1.0f/3.0f; 03580 } 03581 else { 03582 h[0] = p[0] - v1[0]; 03583 h[1] = p[1] - v1[1]; 03584 03585 div = 1.0f/div; 03586 03587 b[1] = (h[0]*c[1] - h[1]*c[0])*div; 03588 b[2] = (a[0]*h[1] - a[1]*h[0])*div; 03589 b[0] = 1.0f - b[1] - b[2]; 03590 } 03591 } 03592 03593 static PBool p_triangle_inside(SmoothTriangle *t, float *co) 03594 { 03595 float b[3]; 03596 03597 p_barycentric_2d(t->co1, t->co2, t->co3, co, b); 03598 03599 if ((b[0] >= 0.0f) && (b[1] >= 0.0f) && (b[2] >= 0.0f)) { 03600 co[0] = t->oco1[0]*b[0] + t->oco2[0]*b[1] + t->oco3[0]*b[2]; 03601 co[1] = t->oco1[1]*b[0] + t->oco2[1]*b[1] + t->oco3[1]*b[2]; 03602 return P_TRUE; 03603 } 03604 03605 return P_FALSE; 03606 } 03607 03608 static SmoothNode *p_node_new(MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth) 03609 { 03610 SmoothNode *node = BLI_memarena_alloc(arena, sizeof *node); 03611 int axis, i, t1size = 0, t2size = 0; 03612 float split, mi, mx; 03613 SmoothTriangle **t1, **t2, *t; 03614 03615 node->tri = tri; 03616 node->ntri = ntri; 03617 03618 if (ntri <= 10 || depth >= 15) 03619 return node; 03620 03621 t1 = MEM_mallocN(sizeof(SmoothTriangle)*ntri, "PNodeTri1"); 03622 t2 = MEM_mallocN(sizeof(SmoothTriangle)*ntri, "PNodeTri1"); 03623 03624 axis = (bmax[0] - bmin[0] > bmax[1] - bmin[1])? 0: 1; 03625 split = 0.5f*(bmin[axis] + bmax[axis]); 03626 03627 for (i = 0; i < ntri; i++) { 03628 t = tri[i]; 03629 03630 if ((t->co1[axis] <= split) || (t->co2[axis] <= split) || (t->co3[axis] <= split)) { 03631 t1[t1size] = t; 03632 t1size++; 03633 } 03634 if ((t->co1[axis] >= split) || (t->co2[axis] >= split) || (t->co3[axis] >= split)) { 03635 t2[t2size] = t; 03636 t2size++; 03637 } 03638 } 03639 03640 if ((t1size == t2size) && (t1size == ntri)) { 03641 MEM_freeN(t1); 03642 MEM_freeN(t2); 03643 return node; 03644 } 03645 03646 node->tri = NULL; 03647 node->ntri = 0; 03648 MEM_freeN(tri); 03649 03650 node->axis = axis; 03651 node->split = split; 03652 03653 mi = bmin[axis]; 03654 mx = bmax[axis]; 03655 bmax[axis] = split; 03656 node->c1 = p_node_new(arena, t1, t1size, bmin, bmax, depth+1); 03657 03658 bmin[axis] = bmax[axis]; 03659 bmax[axis] = mx; 03660 node->c2 = p_node_new(arena, t2, t2size, bmin, bmax, depth+1); 03661 03662 return node; 03663 } 03664 03665 static void p_node_delete(SmoothNode *node) 03666 { 03667 if (node->c1) 03668 p_node_delete(node->c1); 03669 if (node->c2) 03670 p_node_delete(node->c2); 03671 if (node->tri) 03672 MEM_freeN(node->tri); 03673 } 03674 03675 static PBool p_node_intersect(SmoothNode *node, float *co) 03676 { 03677 int i; 03678 03679 if (node->tri) { 03680 for (i = 0; i < node->ntri; i++) 03681 if (p_triangle_inside(node->tri[i], co)) 03682 return P_TRUE; 03683 03684 return P_FALSE; 03685 } 03686 else { 03687 if (co[node->axis] < node->split) 03688 return p_node_intersect(node->c1, co); 03689 else 03690 return p_node_intersect(node->c2, co); 03691 } 03692 03693 } 03694 03695 /* smooothing */ 03696 03697 static int p_compare_float(const void *a, const void *b) 03698 { 03699 if (*((float*)a) < *((float*)b)) 03700 return -1; 03701 else if (*((float*)a) == *((float*)b)) 03702 return 0; 03703 else 03704 return 1; 03705 } 03706 03707 static float p_smooth_median_edge_length(PChart *chart) 03708 { 03709 PEdge *e; 03710 float *lengths = MEM_mallocN(sizeof(chart->edges)*chart->nedges, "PMedianLength"); 03711 float median; 03712 int i; 03713 03714 /* ok, so i'm lazy */ 03715 for (i=0, e=chart->edges; e; e=e->nextlink, i++) 03716 lengths[i] = p_edge_length(e); 03717 03718 qsort(lengths, i, sizeof(float), p_compare_float); 03719 03720 median = lengths[i/2]; 03721 MEM_freeN(lengths); 03722 03723 return median; 03724 } 03725 03726 static float p_smooth_distortion(PEdge *e, float avg2d, float avg3d) 03727 { 03728 float len2d = p_edge_uv_length(e)*avg3d; 03729 float len3d = p_edge_length(e)*avg2d; 03730 03731 return (len3d == 0.0f)? 0.0f: len2d/len3d; 03732 } 03733 03734 static void p_smooth(PChart *chart) 03735 { 03736 PEdge *e; 03737 PVert *v; 03738 PFace *f; 03739 int j, it2, maxiter2, it; 03740 int nedges = chart->nedges, nwheel, gridx, gridy; 03741 int edgesx, edgesy, nsize, esize, i, x, y, maxiter, totiter; 03742 float minv[2], maxv[2], median, invmedian, avglen2d, avglen3d; 03743 float center[2], dx, dy, *nodes, dlimit, d, *oldnodesx, *oldnodesy; 03744 float *nodesx, *nodesy, *hedges, *vedges, climit, moved, padding; 03745 SmoothTriangle *triangles, *t, *t2, **tri, **trip; 03746 SmoothNode *root; 03747 MemArena *arena; 03748 03749 if (nedges == 0) 03750 return; 03751 03752 p_chart_uv_bbox(chart, minv, maxv); 03753 median = p_smooth_median_edge_length(chart)*0.10f; 03754 03755 if (median == 0.0f) 03756 return; 03757 03758 invmedian = 1.0f/median; 03759 03760 /* compute edge distortion */ 03761 avglen2d = avglen3d = 0.0; 03762 03763 for (e=chart->edges; e; e=e->nextlink) { 03764 avglen2d += p_edge_uv_length(e); 03765 avglen3d += p_edge_length(e); 03766 } 03767 03768 avglen2d /= nedges; 03769 avglen3d /= nedges; 03770 03771 for (v=chart->verts; v; v=v->nextlink) { 03772 v->u.distortion = 0.0; 03773 nwheel = 0; 03774 03775 e = v->edge; 03776 do { 03777 v->u.distortion += p_smooth_distortion(e, avglen2d, avglen3d); 03778 nwheel++; 03779 03780 e = e->next->next->pair; 03781 } while(e && (e != v->edge)); 03782 03783 v->u.distortion /= nwheel; 03784 } 03785 03786 /* need to do excessive grid size checking still */ 03787 center[0] = 0.5f*(minv[0] + maxv[0]); 03788 center[1] = 0.5f*(minv[1] + maxv[1]); 03789 03790 dx = 0.5f*(maxv[0] - minv[0]); 03791 dy = 0.5f*(maxv[1] - minv[1]); 03792 03793 padding = 0.15f; 03794 dx += padding*dx + 2.0f*median; 03795 dy += padding*dy + 2.0f*median; 03796 03797 gridx = (int)(dx*invmedian); 03798 gridy = (int)(dy*invmedian); 03799 03800 minv[0] = center[0] - median*gridx; 03801 minv[1] = center[1] - median*gridy; 03802 maxv[0] = center[0] + median*gridx; 03803 maxv[1] = center[1] + median*gridy; 03804 03805 /* create grid */ 03806 gridx = gridx*2 + 1; 03807 gridy = gridy*2 + 1; 03808 03809 if ((gridx <= 2) || (gridy <= 2)) 03810 return; 03811 03812 edgesx = gridx-1; 03813 edgesy = gridy-1; 03814 nsize = gridx*gridy; 03815 esize = edgesx*edgesy; 03816 03817 nodes = MEM_mallocN(sizeof(float)*nsize, "PSmoothNodes"); 03818 nodesx = MEM_mallocN(sizeof(float)*nsize, "PSmoothNodesX"); 03819 nodesy = MEM_mallocN(sizeof(float)*nsize, "PSmoothNodesY"); 03820 oldnodesx = MEM_mallocN(sizeof(float)*nsize, "PSmoothOldNodesX"); 03821 oldnodesy = MEM_mallocN(sizeof(float)*nsize, "PSmoothOldNodesY"); 03822 hedges = MEM_mallocN(sizeof(float)*esize, "PSmoothHEdges"); 03823 vedges = MEM_mallocN(sizeof(float)*esize, "PSmoothVEdges"); 03824 03825 if (!nodes || !nodesx || !nodesy || !oldnodesx || !oldnodesy || !hedges || !vedges) { 03826 if (nodes) MEM_freeN(nodes); 03827 if (nodesx) MEM_freeN(nodesx); 03828 if (nodesy) MEM_freeN(nodesy); 03829 if (oldnodesx) MEM_freeN(oldnodesx); 03830 if (oldnodesy) MEM_freeN(oldnodesy); 03831 if (hedges) MEM_freeN(hedges); 03832 if (vedges) MEM_freeN(vedges); 03833 03834 // printf("Not enough memory for area smoothing grid."); 03835 return; 03836 } 03837 03838 for (x = 0; x < gridx; x++) { 03839 for (y = 0; y < gridy; y++) { 03840 i = x + y*gridx; 03841 03842 nodesx[i] = minv[0] + median*x; 03843 nodesy[i] = minv[1] + median*y; 03844 03845 nodes[i] = 1.0f; 03846 } 03847 } 03848 03849 /* embed in grid */ 03850 for (f=chart->faces; f; f=f->nextlink) { 03851 PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; 03852 float fmin[2], fmax[2]; 03853 int bx1, by1, bx2, by2; 03854 03855 INIT_MINMAX2(fmin, fmax); 03856 03857 DO_MINMAX2(e1->vert->uv, fmin, fmax); 03858 DO_MINMAX2(e2->vert->uv, fmin, fmax); 03859 DO_MINMAX2(e3->vert->uv, fmin, fmax); 03860 03861 bx1 = (int)((fmin[0] - minv[0])*invmedian); 03862 by1 = (int)((fmin[1] - minv[1])*invmedian); 03863 bx2 = (int)((fmax[0] - minv[0])*invmedian + 2); 03864 by2 = (int)((fmax[1] - minv[1])*invmedian + 2); 03865 03866 for (x = bx1; x < bx2; x++) { 03867 for (y = by1; y < by2; y++) { 03868 float p[2], b[3]; 03869 03870 i = x + y*gridx; 03871 03872 p[0] = nodesx[i]; 03873 p[1] = nodesy[i]; 03874 03875 p_barycentric_2d(e1->vert->uv, e2->vert->uv, e3->vert->uv, p, b); 03876 03877 if ((b[0] > 0.0f) && (b[1] > 0.0f) && (b[2] > 0.0f)) { 03878 nodes[i] = e1->vert->u.distortion*b[0]; 03879 nodes[i] += e2->vert->u.distortion*b[1]; 03880 nodes[i] += e3->vert->u.distortion*b[2]; 03881 } 03882 } 03883 } 03884 } 03885 03886 /* smooth the grid */ 03887 maxiter = 10; 03888 totiter = 0; 03889 climit = 0.00001f*nsize; 03890 03891 for (it = 0; it < maxiter; it++) { 03892 moved = 0.0f; 03893 03894 for (x = 0; x < edgesx; x++) { 03895 for (y = 0; y < edgesy; y++) { 03896 i = x + y*gridx; 03897 j = x + y*edgesx; 03898 03899 hedges[j] = (nodes[i] + nodes[i+1])*0.5f; 03900 vedges[j] = (nodes[i] + nodes[i+gridx])*0.5f; 03901 03902 /* we do *inverse* mapping */ 03903 hedges[j] = 1.0f/hedges[j]; 03904 vedges[j] = 1.0f/vedges[j]; 03905 } 03906 } 03907 03908 maxiter2 = 50; 03909 dlimit = 0.0001f; 03910 03911 for (it2 = 0; it2 < maxiter2; it2++) { 03912 d = 0.0f; 03913 totiter += 1; 03914 03915 memcpy(oldnodesx, nodesx, sizeof(float)*nsize); 03916 memcpy(oldnodesy, nodesy, sizeof(float)*nsize); 03917 03918 for (x=1; x < gridx-1; x++) { 03919 for (y=1; y < gridy-1; y++) { 03920 float p[2], oldp[2], sum1, sum2, diff[2], length; 03921 03922 i = x + gridx*y; 03923 j = x + edgesx*y; 03924 03925 oldp[0] = oldnodesx[i]; 03926 oldp[1] = oldnodesy[i]; 03927 03928 sum1 = hedges[j-1]*oldnodesx[i-1]; 03929 sum1 += hedges[j]*oldnodesx[i+1]; 03930 sum1 += vedges[j-edgesx]*oldnodesx[i-gridx]; 03931 sum1 += vedges[j]*oldnodesx[i+gridx]; 03932 03933 sum2 = hedges[j-1]; 03934 sum2 += hedges[j]; 03935 sum2 += vedges[j-edgesx]; 03936 sum2 += vedges[j]; 03937 03938 nodesx[i] = sum1/sum2; 03939 03940 sum1 = hedges[j-1]*oldnodesy[i-1]; 03941 sum1 += hedges[j]*oldnodesy[i+1]; 03942 sum1 += vedges[j-edgesx]*oldnodesy[i-gridx]; 03943 sum1 += vedges[j]*oldnodesy[i+gridx]; 03944 03945 nodesy[i] = sum1/sum2; 03946 03947 p[0] = nodesx[i]; 03948 p[1] = nodesy[i]; 03949 03950 diff[0] = p[0] - oldp[0]; 03951 diff[1] = p[1] - oldp[1]; 03952 03953 length = sqrt(diff[0]*diff[0] + diff[1]*diff[1]); 03954 d = MAX2(d, length); 03955 moved += length; 03956 } 03957 } 03958 03959 if (d < dlimit) 03960 break; 03961 } 03962 03963 if (moved < climit) 03964 break; 03965 } 03966 03967 MEM_freeN(oldnodesx); 03968 MEM_freeN(oldnodesy); 03969 MEM_freeN(hedges); 03970 MEM_freeN(vedges); 03971 03972 /* create bsp */ 03973 t = triangles = MEM_mallocN(sizeof(SmoothTriangle)*esize*2, "PSmoothTris"); 03974 trip = tri = MEM_mallocN(sizeof(SmoothTriangle*)*esize*2, "PSmoothTriP"); 03975 03976 if (!triangles || !tri) { 03977 MEM_freeN(nodes); 03978 MEM_freeN(nodesx); 03979 MEM_freeN(nodesy); 03980 03981 if (triangles) MEM_freeN(triangles); 03982 if (tri) MEM_freeN(tri); 03983 03984 // printf("Not enough memory for area smoothing grid."); 03985 return; 03986 } 03987 03988 for (x = 0; x < edgesx; x++) { 03989 for (y = 0; y < edgesy; y++) { 03990 i = x + y*gridx; 03991 03992 t->co1[0] = nodesx[i]; 03993 t->co1[1] = nodesy[i]; 03994 03995 t->co2[0] = nodesx[i+1]; 03996 t->co2[1] = nodesy[i+1]; 03997 03998 t->co3[0] = nodesx[i+gridx]; 03999 t->co3[1] = nodesy[i+gridx]; 04000 04001 t->oco1[0] = minv[0] + x*median; 04002 t->oco1[1] = minv[1] + y*median; 04003 04004 t->oco2[0] = minv[0] + (x+1)*median; 04005 t->oco2[1] = minv[1] + y*median; 04006 04007 t->oco3[0] = minv[0] + x*median; 04008 t->oco3[1] = minv[1] + (y+1)*median; 04009 04010 t2 = t+1; 04011 04012 t2->co1[0] = nodesx[i+gridx+1]; 04013 t2->co1[1] = nodesy[i+gridx+1]; 04014 04015 t2->oco1[0] = minv[0] + (x+1)*median; 04016 t2->oco1[1] = minv[1] + (y+1)*median; 04017 04018 t2->co2[0] = t->co2[0]; t2->co2[1] = t->co2[1]; 04019 t2->oco2[0] = t->oco2[0]; t2->oco2[1] = t->oco2[1]; 04020 04021 t2->co3[0] = t->co3[0]; t2->co3[1] = t->co3[1]; 04022 t2->oco3[0] = t->oco3[0]; t2->oco3[1] = t->oco3[1]; 04023 04024 *trip = t; trip++; t++; 04025 *trip = t; trip++; t++; 04026 } 04027 } 04028 04029 MEM_freeN(nodes); 04030 MEM_freeN(nodesx); 04031 MEM_freeN(nodesy); 04032 04033 arena = BLI_memarena_new(1<<16, "param smooth arena"); 04034 root = p_node_new(arena, tri, esize*2, minv, maxv, 0); 04035 04036 for (v=chart->verts; v; v=v->nextlink) 04037 if (!p_node_intersect(root, v->uv)) 04038 param_warning("area smoothing error: couldn't find mapping triangle\n"); 04039 04040 p_node_delete(root); 04041 BLI_memarena_free(arena); 04042 04043 MEM_freeN(triangles); 04044 } 04045 04046 /* Exported */ 04047 04048 ParamHandle *param_construct_begin(void) 04049 { 04050 PHandle *handle = MEM_callocN(sizeof*handle, "PHandle"); 04051 handle->construction_chart = p_chart_new(handle); 04052 handle->state = PHANDLE_STATE_ALLOCATED; 04053 handle->arena = BLI_memarena_new((1<<16), "param construct arena"); 04054 handle->aspx = 1.0f; 04055 handle->aspy = 1.0f; 04056 04057 handle->hash_verts = phash_new((PHashLink**)&handle->construction_chart->verts, 1); 04058 handle->hash_edges = phash_new((PHashLink**)&handle->construction_chart->edges, 1); 04059 handle->hash_faces = phash_new((PHashLink**)&handle->construction_chart->faces, 1); 04060 04061 return (ParamHandle*)handle; 04062 } 04063 04064 void param_aspect_ratio(ParamHandle *handle, float aspx, float aspy) 04065 { 04066 PHandle *phandle = (PHandle*)handle; 04067 04068 phandle->aspx = aspx; 04069 phandle->aspy = aspy; 04070 } 04071 04072 void param_delete(ParamHandle *handle) 04073 { 04074 PHandle *phandle = (PHandle*)handle; 04075 int i; 04076 04077 param_assert((phandle->state == PHANDLE_STATE_ALLOCATED) || 04078 (phandle->state == PHANDLE_STATE_CONSTRUCTED)); 04079 04080 for (i = 0; i < phandle->ncharts; i++) 04081 p_chart_delete(phandle->charts[i]); 04082 04083 if (phandle->charts) 04084 MEM_freeN(phandle->charts); 04085 04086 if (phandle->construction_chart) { 04087 p_chart_delete(phandle->construction_chart); 04088 04089 phash_delete(phandle->hash_verts); 04090 phash_delete(phandle->hash_edges); 04091 phash_delete(phandle->hash_faces); 04092 } 04093 04094 BLI_memarena_free(phandle->arena); 04095 MEM_freeN(phandle); 04096 } 04097 04098 void param_face_add(ParamHandle *handle, ParamKey key, int nverts, 04099 ParamKey *vkeys, float **co, float **uv, 04100 ParamBool *pin, ParamBool *select) 04101 { 04102 PHandle *phandle = (PHandle*)handle; 04103 04104 param_assert(phash_lookup(phandle->hash_faces, key) == NULL); 04105 param_assert(phandle->state == PHANDLE_STATE_ALLOCATED); 04106 param_assert((nverts == 3) || (nverts == 4)); 04107 04108 if (nverts == 4) { 04109 if (p_quad_split_direction(phandle, co, vkeys)) { 04110 p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select); 04111 p_face_add_construct(phandle, key, vkeys, co, uv, 0, 2, 3, pin, select); 04112 } 04113 else { 04114 p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 3, pin, select); 04115 p_face_add_construct(phandle, key, vkeys, co, uv, 1, 2, 3, pin, select); 04116 } 04117 } 04118 else 04119 p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select); 04120 } 04121 04122 void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys) 04123 { 04124 PHandle *phandle = (PHandle*)handle; 04125 PEdge *e; 04126 04127 param_assert(phandle->state == PHANDLE_STATE_ALLOCATED); 04128 04129 e = p_edge_lookup(phandle, vkeys); 04130 if (e) 04131 e->flag |= PEDGE_SEAM; 04132 } 04133 04134 void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl) 04135 { 04136 PHandle *phandle = (PHandle*)handle; 04137 PChart *chart = phandle->construction_chart; 04138 int i, j, nboundaries = 0; 04139 PEdge *outer; 04140 04141 param_assert(phandle->state == PHANDLE_STATE_ALLOCATED); 04142 04143 phandle->ncharts = p_connect_pairs(phandle, (PBool)impl); 04144 phandle->charts = p_split_charts(phandle, chart, phandle->ncharts); 04145 04146 p_chart_delete(phandle->construction_chart); 04147 phandle->construction_chart = NULL; 04148 04149 phash_delete(phandle->hash_verts); 04150 phash_delete(phandle->hash_edges); 04151 phash_delete(phandle->hash_faces); 04152 phandle->hash_verts = phandle->hash_edges = phandle->hash_faces = NULL; 04153 04154 for (i = j = 0; i < phandle->ncharts; i++) { 04155 PVert *v; 04156 chart = phandle->charts[i]; 04157 04158 p_chart_boundaries(chart, &nboundaries, &outer); 04159 04160 if (!impl && nboundaries == 0) { 04161 p_chart_delete(chart); 04162 continue; 04163 } 04164 04165 phandle->charts[j] = chart; 04166 j++; 04167 04168 if (fill && (nboundaries > 1)) 04169 p_chart_fill_boundaries(chart, outer); 04170 04171 for (v=chart->verts; v; v=v->nextlink) 04172 p_vert_load_pin_select_uvs(handle, v); 04173 } 04174 04175 phandle->ncharts = j; 04176 04177 phandle->state = PHANDLE_STATE_CONSTRUCTED; 04178 } 04179 04180 void param_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf) 04181 { 04182 PHandle *phandle = (PHandle*)handle; 04183 PFace *f; 04184 int i; 04185 04186 param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED); 04187 phandle->state = PHANDLE_STATE_LSCM; 04188 04189 for (i = 0; i < phandle->ncharts; i++) { 04190 for (f=phandle->charts[i]->faces; f; f=f->nextlink) 04191 p_face_backup_uvs(f); 04192 p_chart_lscm_begin(phandle->charts[i], (PBool)live, (PBool)abf); 04193 } 04194 } 04195 04196 void param_lscm_solve(ParamHandle *handle) 04197 { 04198 PHandle *phandle = (PHandle*)handle; 04199 PChart *chart; 04200 int i; 04201 PBool result; 04202 04203 param_assert(phandle->state == PHANDLE_STATE_LSCM); 04204 04205 for (i = 0; i < phandle->ncharts; i++) { 04206 chart = phandle->charts[i]; 04207 04208 if (chart->u.lscm.context) { 04209 result = p_chart_lscm_solve(phandle, chart); 04210 04211 if (result && !(chart->flag & PCHART_NOPACK)) 04212 p_chart_rotate_minimum_area(chart); 04213 04214 if (!result || (chart->u.lscm.pin1)) 04215 p_chart_lscm_end(chart); 04216 } 04217 } 04218 } 04219 04220 void param_lscm_end(ParamHandle *handle) 04221 { 04222 PHandle *phandle = (PHandle*)handle; 04223 int i; 04224 04225 param_assert(phandle->state == PHANDLE_STATE_LSCM); 04226 04227 for (i = 0; i < phandle->ncharts; i++) { 04228 p_chart_lscm_end(phandle->charts[i]); 04229 #if 0 04230 p_chart_complexify(phandle->charts[i]); 04231 #endif 04232 } 04233 04234 phandle->state = PHANDLE_STATE_CONSTRUCTED; 04235 } 04236 04237 void param_stretch_begin(ParamHandle *handle) 04238 { 04239 PHandle *phandle = (PHandle*)handle; 04240 PChart *chart; 04241 PVert *v; 04242 PFace *f; 04243 int i; 04244 04245 param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED); 04246 phandle->state = PHANDLE_STATE_STRETCH; 04247 04248 phandle->rng = rng_new(31415926); 04249 phandle->blend = 0.0f; 04250 04251 for (i = 0; i < phandle->ncharts; i++) { 04252 chart = phandle->charts[i]; 04253 04254 for (v=chart->verts; v; v=v->nextlink) 04255 v->flag &= ~PVERT_PIN; /* don't use user-defined pins */ 04256 04257 p_stretch_pin_boundary(chart); 04258 04259 for (f=chart->faces; f; f=f->nextlink) { 04260 p_face_backup_uvs(f); 04261 f->u.area3d = p_face_area(f); 04262 } 04263 } 04264 } 04265 04266 void param_stretch_blend(ParamHandle *handle, float blend) 04267 { 04268 PHandle *phandle = (PHandle*)handle; 04269 04270 param_assert(phandle->state == PHANDLE_STATE_STRETCH); 04271 phandle->blend = blend; 04272 } 04273 04274 void param_stretch_iter(ParamHandle *handle) 04275 { 04276 PHandle *phandle = (PHandle*)handle; 04277 PChart *chart; 04278 int i; 04279 04280 param_assert(phandle->state == PHANDLE_STATE_STRETCH); 04281 04282 for (i = 0; i < phandle->ncharts; i++) { 04283 chart = phandle->charts[i]; 04284 p_chart_stretch_minimize(chart, phandle->rng); 04285 } 04286 } 04287 04288 void param_stretch_end(ParamHandle *handle) 04289 { 04290 PHandle *phandle = (PHandle*)handle; 04291 04292 param_assert(phandle->state == PHANDLE_STATE_STRETCH); 04293 phandle->state = PHANDLE_STATE_CONSTRUCTED; 04294 04295 rng_free(phandle->rng); 04296 phandle->rng = NULL; 04297 } 04298 04299 void param_smooth_area(ParamHandle *handle) 04300 { 04301 PHandle *phandle = (PHandle*)handle; 04302 int i; 04303 04304 param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED); 04305 04306 for (i = 0; i < phandle->ncharts; i++) { 04307 PChart *chart = phandle->charts[i]; 04308 PVert *v; 04309 04310 for (v=chart->verts; v; v=v->nextlink) 04311 v->flag &= ~PVERT_PIN; 04312 04313 p_smooth(chart); 04314 } 04315 } 04316 04317 void param_pack(ParamHandle *handle, float margin) 04318 { 04319 /* box packing variables */ 04320 boxPack *boxarray, *box; 04321 float tot_width, tot_height, scale; 04322 04323 PChart *chart; 04324 int i, unpacked=0; 04325 float trans[2]; 04326 double area= 0.0; 04327 04328 PHandle *phandle = (PHandle*)handle; 04329 04330 if (phandle->ncharts == 0) 04331 return; 04332 04333 if(phandle->aspx != phandle->aspy) 04334 param_scale(handle, 1.0f/phandle->aspx, 1.0f/phandle->aspy); 04335 04336 /* we may not use all these boxes */ 04337 boxarray = MEM_mallocN( phandle->ncharts*sizeof(boxPack), "boxPack box"); 04338 04339 04340 for (i = 0; i < phandle->ncharts; i++) { 04341 chart = phandle->charts[i]; 04342 04343 if (chart->flag & PCHART_NOPACK) { 04344 unpacked++; 04345 continue; 04346 } 04347 04348 box = boxarray+(i-unpacked); 04349 04350 p_chart_uv_bbox(chart, trans, chart->u.pack.size); 04351 04352 trans[0] = -trans[0]; 04353 trans[1] = -trans[1]; 04354 04355 p_chart_uv_translate(chart, trans); 04356 04357 box->w = chart->u.pack.size[0] + trans[0]; 04358 box->h = chart->u.pack.size[1] + trans[1]; 04359 box->index = i; /* warning this index skips PCHART_NOPACK boxes */ 04360 04361 if(margin>0.0f) 04362 area += sqrt(box->w*box->h); 04363 } 04364 04365 if(margin>0.0f) { 04366 /* multiply the margin by the area to give predictable results not dependant on UV scale, 04367 * ...Without using the area running pack multiple times also gives a bad feedback loop. 04368 * multiply by 0.1 so the margin value from the UI can be from 0.0 to 1.0 but not give a massive margin */ 04369 margin = (margin*(float)area) * 0.1f; 04370 unpacked= 0; 04371 for (i = 0; i < phandle->ncharts; i++) { 04372 chart = phandle->charts[i]; 04373 04374 if (chart->flag & PCHART_NOPACK) { 04375 unpacked++; 04376 continue; 04377 } 04378 04379 box = boxarray+(i-unpacked); 04380 trans[0] = margin; 04381 trans[1] = margin; 04382 p_chart_uv_translate(chart, trans); 04383 box->w += margin*2; 04384 box->h += margin*2; 04385 } 04386 } 04387 04388 boxPack2D(boxarray, phandle->ncharts-unpacked, &tot_width, &tot_height); 04389 04390 if (tot_height>tot_width) 04391 scale = 1.0f/tot_height; 04392 else 04393 scale = 1.0f/tot_width; 04394 04395 for (i = 0; i < phandle->ncharts-unpacked; i++) { 04396 box = boxarray+i; 04397 trans[0] = box->x; 04398 trans[1] = box->y; 04399 04400 chart = phandle->charts[box->index]; 04401 p_chart_uv_translate(chart, trans); 04402 p_chart_uv_scale(chart, scale); 04403 } 04404 MEM_freeN(boxarray); 04405 04406 if(phandle->aspx != phandle->aspy) 04407 param_scale(handle, phandle->aspx, phandle->aspy); 04408 } 04409 04410 void param_average(ParamHandle *handle) 04411 { 04412 PChart *chart; 04413 int i; 04414 float tot_uvarea = 0.0f, tot_facearea = 0.0f; 04415 float tot_fac, fac; 04416 float minv[2], maxv[2], trans[2]; 04417 PHandle *phandle = (PHandle*)handle; 04418 04419 if (phandle->ncharts == 0) 04420 return; 04421 04422 for (i = 0; i < phandle->ncharts; i++) { 04423 PFace *f; 04424 chart = phandle->charts[i]; 04425 04426 chart->u.pack.area = 0.0f; /* 3d area */ 04427 chart->u.pack.rescale = 0.0f; /* UV area, abusing rescale for tmp storage, oh well :/ */ 04428 04429 for (f=chart->faces; f; f=f->nextlink) { 04430 chart->u.pack.area += p_face_area(f); 04431 chart->u.pack.rescale += fabsf(p_face_uv_area_signed(f)); 04432 } 04433 04434 tot_facearea += chart->u.pack.area; 04435 tot_uvarea += chart->u.pack.rescale; 04436 } 04437 04438 if (tot_facearea == tot_uvarea || tot_facearea==0.0f || tot_uvarea==0.0f) { 04439 /* nothing to do */ 04440 return; 04441 } 04442 04443 tot_fac = tot_facearea/tot_uvarea; 04444 04445 for (i = 0; i < phandle->ncharts; i++) { 04446 chart = phandle->charts[i]; 04447 if (chart->u.pack.area != 0.0f && chart->u.pack.rescale != 0.0f) { 04448 fac = chart->u.pack.area / chart->u.pack.rescale; 04449 04450 /* Get the island center */ 04451 p_chart_uv_bbox(chart, minv, maxv); 04452 trans[0] = (minv[0] + maxv[0]) /-2.0f; 04453 trans[1] = (minv[1] + maxv[1]) /-2.0f; 04454 04455 /* Move center to 0,0 */ 04456 p_chart_uv_translate(chart, trans); 04457 p_chart_uv_scale(chart, sqrt(fac / tot_fac)); 04458 04459 /* Move to original center */ 04460 trans[0] = -trans[0]; 04461 trans[1] = -trans[1]; 04462 p_chart_uv_translate(chart, trans); 04463 } 04464 } 04465 } 04466 04467 void param_scale(ParamHandle *handle, float x, float y) 04468 { 04469 PHandle *phandle = (PHandle*)handle; 04470 PChart *chart; 04471 int i; 04472 04473 for (i = 0; i < phandle->ncharts; i++) { 04474 chart = phandle->charts[i]; 04475 p_chart_uv_scale_xy(chart, x, y); 04476 } 04477 } 04478 04479 void param_flush(ParamHandle *handle) 04480 { 04481 PHandle *phandle = (PHandle*)handle; 04482 PChart *chart; 04483 int i; 04484 04485 for (i = 0; i < phandle->ncharts; i++) { 04486 chart = phandle->charts[i]; 04487 04488 if ((phandle->state == PHANDLE_STATE_LSCM) && !chart->u.lscm.context) 04489 continue; 04490 04491 if (phandle->blend == 0.0f) 04492 p_flush_uvs(phandle, chart); 04493 else 04494 p_flush_uvs_blend(phandle, chart, phandle->blend); 04495 } 04496 } 04497 04498 void param_flush_restore(ParamHandle *handle) 04499 { 04500 PHandle *phandle = (PHandle*)handle; 04501 PChart *chart; 04502 PFace *f; 04503 int i; 04504 04505 for (i = 0; i < phandle->ncharts; i++) { 04506 chart = phandle->charts[i]; 04507 04508 for (f=chart->faces; f; f=f->nextlink) 04509 p_face_restore_uvs(f); 04510 } 04511 } 04512