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