|
Blender
V2.59
|
00001 /* 00002 * $Id: reeb.c 36276 2011-04-21 15:53:30Z campbellbarton $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. The Blender 00010 * Foundation also sells licenses for use in proprietary software under 00011 * the Blender License. See http://www.blender.org/BL/ for information 00012 * about this. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with this program; if not, write to the Free Software Foundation, 00021 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00022 * 00023 * Contributor(s): Martin Poirier 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <math.h> 00034 #include <string.h> // for memcpy 00035 #include <stdio.h> 00036 #include <stdlib.h> // for qsort 00037 #include <float.h> 00038 00039 #include "DNA_scene_types.h" 00040 #include "DNA_object_types.h" 00041 00042 #include "MEM_guardedalloc.h" 00043 00044 #include "BKE_context.h" 00045 00046 #include "BLI_blenlib.h" 00047 #include "BLI_math.h" 00048 #include "BLI_utildefines.h" 00049 #include "BLI_editVert.h" 00050 #include "BLI_edgehash.h" 00051 #include "BLI_ghash.h" 00052 #include "BLI_heap.h" 00053 00054 //#include "BDR_editobject.h" 00055 00056 //#include "BIF_interface.h" 00057 //#include "BIF_toolbox.h" 00058 //#include "BIF_graphics.h" 00059 00060 00061 //#include "blendef.h" 00062 00063 #include "ONL_opennl.h" 00064 00065 #include "reeb.h" 00066 00067 #if 0 /* UNUSED 2.5 */ 00068 static ReebGraph *GLOBAL_RG = NULL; 00069 static ReebGraph *FILTERED_RG = NULL; 00070 #endif 00071 00072 /* 00073 * Skeleton generation algorithm based on: 00074 * "Harmonic Skeleton for Realistic Character Animation" 00075 * Gregoire Aujay, Franck Hetroy, Francis Lazarus and Christine Depraz 00076 * SIGGRAPH 2007 00077 * 00078 * Reeb graph generation algorithm based on: 00079 * "Robust On-line Computation of Reeb Graphs: Simplicity and Speed" 00080 * Valerio Pascucci, Giorgio Scorzelli, Peer-Timo Bremer and Ajith Mascarenhas 00081 * SIGGRAPH 2007 00082 * 00083 * */ 00084 00085 #define DEBUG_REEB 00086 #define DEBUG_REEB_NODE 00087 00088 typedef struct VertexData 00089 { 00090 float w; /* weight */ 00091 int i; /* index */ 00092 ReebNode *n; 00093 } VertexData; 00094 00095 typedef struct EdgeIndex 00096 { 00097 EditEdge **edges; 00098 int *offset; 00099 } EdgeIndex; 00100 00101 typedef enum { 00102 MERGE_LOWER, 00103 MERGE_HIGHER, 00104 MERGE_APPEND 00105 } MergeDirection; 00106 00107 int mergeArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1); 00108 void mergeArcEdges(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc, MergeDirection direction); 00109 int mergeConnectedArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1); 00110 EditEdge * NextEdgeForVert(EdgeIndex *indexed_edges, int index); 00111 void mergeArcFaces(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc); 00112 void addFacetoArc(ReebArc *arc, EditFace *efa); 00113 00114 void REEB_RadialSymmetry(BNode* root_node, RadialArc* ring, int count); 00115 void REEB_AxialSymmetry(BNode* root_node, BNode* node1, BNode* node2, struct BArc* barc1, BArc* barc2); 00116 00117 void flipArcBuckets(ReebArc *arc); 00118 00119 00120 /***************************************** UTILS **********************************************/ 00121 00122 static VertexData *allocVertexData(EditMesh *em) 00123 { 00124 VertexData *data; 00125 EditVert *eve; 00126 int totvert, index; 00127 00128 totvert = BLI_countlist(&em->verts); 00129 00130 data = MEM_callocN(sizeof(VertexData) * totvert, "VertexData"); 00131 00132 for(index = 0, eve = em->verts.first; eve; index++, eve = eve->next) 00133 { 00134 data[index].i = index; 00135 data[index].w = 0; 00136 eve->tmp.p = data + index; 00137 } 00138 00139 return data; 00140 } 00141 00142 static int indexData(EditVert *eve) 00143 { 00144 return ((VertexData*)eve->tmp.p)->i; 00145 } 00146 00147 static float weightData(EditVert *eve) 00148 { 00149 return ((VertexData*)eve->tmp.p)->w; 00150 } 00151 00152 static void weightSetData(EditVert *eve, float w) 00153 { 00154 ((VertexData*)eve->tmp.p)->w = w; 00155 } 00156 00157 static ReebNode* nodeData(EditVert *eve) 00158 { 00159 return ((VertexData*)eve->tmp.p)->n; 00160 } 00161 00162 static void nodeSetData(EditVert *eve, ReebNode *n) 00163 { 00164 ((VertexData*)eve->tmp.p)->n = n; 00165 } 00166 00167 void REEB_freeArc(BArc *barc) 00168 { 00169 ReebArc *arc = (ReebArc*)barc; 00170 BLI_freelistN(&arc->edges); 00171 00172 if (arc->buckets) 00173 MEM_freeN(arc->buckets); 00174 00175 if (arc->faces) 00176 BLI_ghash_free(arc->faces, NULL, NULL); 00177 00178 MEM_freeN(arc); 00179 } 00180 00181 void REEB_freeGraph(ReebGraph *rg) 00182 { 00183 ReebArc *arc; 00184 ReebNode *node; 00185 00186 // free nodes 00187 for( node = rg->nodes.first; node; node = node->next ) 00188 { 00189 BLI_freeNode((BGraph*)rg, (BNode*)node); 00190 } 00191 BLI_freelistN(&rg->nodes); 00192 00193 // free arcs 00194 arc = rg->arcs.first; 00195 while( arc ) 00196 { 00197 ReebArc *next = arc->next; 00198 REEB_freeArc((BArc*)arc); 00199 arc = next; 00200 } 00201 00202 // free edge map 00203 BLI_edgehash_free(rg->emap, NULL); 00204 00205 /* free linked graph */ 00206 if (rg->link_up) 00207 { 00208 REEB_freeGraph(rg->link_up); 00209 } 00210 00211 MEM_freeN(rg); 00212 } 00213 00214 ReebGraph * newReebGraph(void) 00215 { 00216 ReebGraph *rg; 00217 rg = MEM_callocN(sizeof(ReebGraph), "reeb graph"); 00218 00219 rg->totnodes = 0; 00220 rg->emap = BLI_edgehash_new(); 00221 00222 00223 rg->free_arc = REEB_freeArc; 00224 rg->free_node = NULL; 00225 rg->radial_symmetry = REEB_RadialSymmetry; 00226 rg->axial_symmetry = REEB_AxialSymmetry; 00227 00228 return rg; 00229 } 00230 00231 void BIF_flagMultiArcs(ReebGraph *rg, int flag) 00232 { 00233 for ( ; rg; rg = rg->link_up) 00234 { 00235 BLI_flagArcs((BGraph*)rg, flag); 00236 } 00237 } 00238 00239 static ReebNode * addNode(ReebGraph *rg, EditVert *eve) 00240 { 00241 float weight; 00242 ReebNode *node = NULL; 00243 00244 weight = weightData(eve); 00245 00246 node = MEM_callocN(sizeof(ReebNode), "reeb node"); 00247 00248 node->flag = 0; // clear flag on init 00249 node->symmetry_level = 0; 00250 node->arcs = NULL; 00251 node->degree = 0; 00252 node->weight = weight; 00253 node->index = rg->totnodes; 00254 VECCOPY(node->p, eve->co); 00255 00256 BLI_addtail(&rg->nodes, node); 00257 rg->totnodes++; 00258 00259 nodeSetData(eve, node); 00260 00261 return node; 00262 } 00263 00264 static ReebNode * copyNode(ReebGraph *rg, ReebNode *node) 00265 { 00266 ReebNode *cp_node = NULL; 00267 00268 cp_node = MEM_callocN(sizeof(ReebNode), "reeb node copy"); 00269 00270 memcpy(cp_node, node, sizeof(ReebNode)); 00271 00272 cp_node->prev = NULL; 00273 cp_node->next = NULL; 00274 cp_node->arcs = NULL; 00275 00276 cp_node->link_up = NULL; 00277 cp_node->link_down = NULL; 00278 00279 BLI_addtail(&rg->nodes, cp_node); 00280 rg->totnodes++; 00281 00282 return cp_node; 00283 } 00284 00285 static void relinkNodes(ReebGraph *low_rg, ReebGraph *high_rg) 00286 { 00287 ReebNode *low_node, *high_node; 00288 00289 if (low_rg == NULL || high_rg == NULL) 00290 { 00291 return; 00292 } 00293 00294 for (low_node = low_rg->nodes.first; low_node; low_node = low_node->next) 00295 { 00296 for (high_node = high_rg->nodes.first; high_node; high_node = high_node->next) 00297 { 00298 if (low_node->index == high_node->index) 00299 { 00300 high_node->link_down = low_node; 00301 low_node->link_up = high_node; 00302 break; 00303 } 00304 } 00305 } 00306 } 00307 00308 ReebNode *BIF_otherNodeFromIndex(ReebArc *arc, ReebNode *node) 00309 { 00310 return (arc->head->index == node->index) ? arc->tail : arc->head; 00311 } 00312 00313 ReebNode *BIF_NodeFromIndex(ReebArc *arc, ReebNode *node) 00314 { 00315 return (arc->head->index == node->index) ? arc->head : arc->tail; 00316 } 00317 00318 ReebNode *BIF_lowestLevelNode(ReebNode *node) 00319 { 00320 while (node->link_down) 00321 { 00322 node = node->link_down; 00323 } 00324 00325 return node; 00326 } 00327 00328 static ReebArc * copyArc(ReebGraph *rg, ReebArc *arc) 00329 { 00330 ReebArc *cp_arc; 00331 ReebNode *node; 00332 00333 cp_arc = MEM_callocN(sizeof(ReebArc), "reeb arc copy"); 00334 00335 memcpy(cp_arc, arc, sizeof(ReebArc)); 00336 00337 cp_arc->link_up = arc; 00338 00339 cp_arc->head = NULL; 00340 cp_arc->tail = NULL; 00341 00342 cp_arc->prev = NULL; 00343 cp_arc->next = NULL; 00344 00345 cp_arc->edges.first = NULL; 00346 cp_arc->edges.last = NULL; 00347 00348 /* copy buckets */ 00349 cp_arc->buckets = MEM_callocN(sizeof(EmbedBucket) * cp_arc->bcount, "embed bucket"); 00350 memcpy(cp_arc->buckets, arc->buckets, sizeof(EmbedBucket) * cp_arc->bcount); 00351 00352 /* copy faces map */ 00353 cp_arc->faces = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "copyArc gh"); 00354 mergeArcFaces(rg, cp_arc, arc); 00355 00356 /* find corresponding head and tail */ 00357 for (node = rg->nodes.first; node && (cp_arc->head == NULL || cp_arc->tail == NULL); node = node->next) 00358 { 00359 if (node->index == arc->head->index) 00360 { 00361 cp_arc->head = node; 00362 } 00363 else if (node->index == arc->tail->index) 00364 { 00365 cp_arc->tail = node; 00366 } 00367 } 00368 00369 BLI_addtail(&rg->arcs, cp_arc); 00370 00371 return cp_arc; 00372 } 00373 00374 static ReebGraph * copyReebGraph(ReebGraph *rg, int level) 00375 { 00376 ReebNode *node; 00377 ReebArc *arc; 00378 ReebGraph *cp_rg = newReebGraph(); 00379 00380 cp_rg->resolution = rg->resolution; 00381 cp_rg->length = rg->length; 00382 cp_rg->link_up = rg; 00383 cp_rg->multi_level = level; 00384 00385 /* Copy nodes */ 00386 for (node = rg->nodes.first; node; node = node->next) 00387 { 00388 ReebNode *cp_node = copyNode(cp_rg, node); 00389 cp_node->multi_level = level; 00390 } 00391 00392 /* Copy arcs */ 00393 for (arc = rg->arcs.first; arc; arc = arc->next) 00394 { 00395 copyArc(cp_rg, arc); 00396 } 00397 00398 BLI_buildAdjacencyList((BGraph*)cp_rg); 00399 00400 return cp_rg; 00401 } 00402 00403 ReebGraph *BIF_graphForMultiNode(ReebGraph *rg, ReebNode *node) 00404 { 00405 ReebGraph *multi_rg = rg; 00406 00407 while(multi_rg && multi_rg->multi_level != node->multi_level) 00408 { 00409 multi_rg = multi_rg->link_up; 00410 } 00411 00412 return multi_rg; 00413 } 00414 00415 static ReebEdge * copyEdge(ReebEdge *edge) 00416 { 00417 ReebEdge *newEdge = NULL; 00418 00419 newEdge = MEM_callocN(sizeof(ReebEdge), "reeb edge"); 00420 memcpy(newEdge, edge, sizeof(ReebEdge)); 00421 00422 newEdge->next = NULL; 00423 newEdge->prev = NULL; 00424 00425 return newEdge; 00426 } 00427 00428 static void printArc(ReebArc *arc) 00429 { 00430 ReebEdge *edge; 00431 ReebNode *head = (ReebNode*)arc->head; 00432 ReebNode *tail = (ReebNode*)arc->tail; 00433 printf("arc: (%i) %f -> (%i) %f\n", head->index, head->weight, tail->index, tail->weight); 00434 00435 for(edge = arc->edges.first; edge ; edge = edge->next) 00436 { 00437 printf("\tedge (%i, %i)\n", edge->v1->index, edge->v2->index); 00438 } 00439 } 00440 00441 static void flipArc(ReebArc *arc) 00442 { 00443 ReebNode *tmp; 00444 tmp = arc->head; 00445 arc->head = arc->tail; 00446 arc->tail = tmp; 00447 00448 flipArcBuckets(arc); 00449 } 00450 00451 #ifdef DEBUG_REEB_NODE 00452 static void NodeDegreeDecrement(ReebGraph *UNUSED(rg), ReebNode *node) 00453 { 00454 node->degree--; 00455 00456 // if (node->degree == 0) 00457 // { 00458 // printf("would remove node %i\n", node->index); 00459 // } 00460 } 00461 00462 static void NodeDegreeIncrement(ReebGraph *UNUSED(rg), ReebNode *node) 00463 { 00464 // if (node->degree == 0) 00465 // { 00466 // printf("first connect node %i\n", node->index); 00467 // } 00468 00469 node->degree++; 00470 } 00471 00472 #else 00473 #define NodeDegreeDecrement(rg, node) {node->degree--;} 00474 #define NodeDegreeIncrement(rg, node) {node->degree++;} 00475 #endif 00476 00477 void repositionNodes(ReebGraph *rg) 00478 { 00479 BArc *arc = NULL; 00480 BNode *node = NULL; 00481 00482 // Reset node positions 00483 for(node = rg->nodes.first; node; node = node->next) 00484 { 00485 node->p[0] = node->p[1] = node->p[2] = 0; 00486 } 00487 00488 for(arc = rg->arcs.first; arc; arc = arc->next) 00489 { 00490 if (((ReebArc*)arc)->bcount > 0) 00491 { 00492 float p[3]; 00493 00494 VECCOPY(p, ((ReebArc*)arc)->buckets[0].p); 00495 mul_v3_fl(p, 1.0f / arc->head->degree); 00496 add_v3_v3(arc->head->p, p); 00497 00498 VECCOPY(p, ((ReebArc*)arc)->buckets[((ReebArc*)arc)->bcount - 1].p); 00499 mul_v3_fl(p, 1.0f / arc->tail->degree); 00500 add_v3_v3(arc->tail->p, p); 00501 } 00502 } 00503 } 00504 00505 void verifyNodeDegree(ReebGraph *rg) 00506 { 00507 #ifdef DEBUG_REEB 00508 ReebNode *node = NULL; 00509 ReebArc *arc = NULL; 00510 00511 for(node = rg->nodes.first; node; node = node->next) 00512 { 00513 int count = 0; 00514 for(arc = rg->arcs.first; arc; arc = arc->next) 00515 { 00516 if (arc->head == node || arc->tail == node) 00517 { 00518 count++; 00519 } 00520 } 00521 if (count != node->degree) 00522 { 00523 printf("degree error in node %i: expected %i got %i\n", node->index, count, node->degree); 00524 } 00525 if (node->degree == 0) 00526 { 00527 printf("zero degree node %i with weight %f\n", node->index, node->weight); 00528 } 00529 } 00530 #endif 00531 } 00532 00533 static void verifyBucketsArc(ReebGraph *UNUSED(rg), ReebArc *arc) 00534 { 00535 ReebNode *head = (ReebNode*)arc->head; 00536 ReebNode *tail = (ReebNode*)arc->tail; 00537 00538 if (arc->bcount > 0) 00539 { 00540 int i; 00541 for(i = 0; i < arc->bcount; i++) 00542 { 00543 if (arc->buckets[i].nv == 0) 00544 { 00545 printArc(arc); 00546 printf("count error in bucket %i/%i\n", i+1, arc->bcount); 00547 } 00548 } 00549 00550 if (ceil(head->weight) != arc->buckets[0].val) 00551 { 00552 printArc(arc); 00553 printf("alloc error in first bucket: %f should be %f \n", arc->buckets[0].val, ceil(head->weight)); 00554 } 00555 if (floor(tail->weight) != arc->buckets[arc->bcount - 1].val) 00556 { 00557 printArc(arc); 00558 printf("alloc error in last bucket: %f should be %f \n", arc->buckets[arc->bcount - 1].val, floor(tail->weight)); 00559 } 00560 } 00561 } 00562 00563 void verifyBuckets(ReebGraph *rg) 00564 { 00565 #ifdef DEBUG_REEB 00566 ReebArc *arc = NULL; 00567 for(arc = rg->arcs.first; arc; arc = arc->next) 00568 { 00569 verifyBucketsArc(rg, arc); 00570 } 00571 #endif 00572 } 00573 00574 void verifyFaces(ReebGraph *rg) 00575 { 00576 #ifdef DEBUG_REEB 00577 int total = 0; 00578 ReebArc *arc = NULL; 00579 for(arc = rg->arcs.first; arc; arc = arc->next) 00580 { 00581 total += BLI_ghash_size(arc->faces); 00582 } 00583 00584 #endif 00585 } 00586 00587 void verifyArcs(ReebGraph *rg) 00588 { 00589 ReebArc *arc; 00590 00591 for (arc = rg->arcs.first; arc; arc = arc->next) 00592 { 00593 if (arc->head->weight > arc->tail->weight) 00594 { 00595 printf("FLIPPED ARC!\n"); 00596 } 00597 } 00598 } 00599 00600 static void verifyMultiResolutionLinks(ReebGraph *rg, int level) 00601 { 00602 #ifdef DEBUG_REEB 00603 ReebGraph *lower_rg = rg->link_up; 00604 00605 if (lower_rg) 00606 { 00607 ReebArc *arc; 00608 00609 for (arc = rg->arcs.first; arc; arc = arc->next) 00610 { 00611 if (BLI_findindex(&lower_rg->arcs, arc->link_up) == -1) 00612 { 00613 printf("missing arc %p for level %i\n", (void *)arc->link_up, level); 00614 printf("Source arc was ---\n"); 00615 printArc(arc); 00616 00617 arc->link_up = NULL; 00618 } 00619 } 00620 00621 00622 verifyMultiResolutionLinks(lower_rg, level + 1); 00623 } 00624 #endif 00625 } 00626 /***************************************** BUCKET UTILS **********************************************/ 00627 00628 static void addVertToBucket(EmbedBucket *b, float co[3]) 00629 { 00630 b->nv++; 00631 interp_v3_v3v3(b->p, b->p, co, 1.0f / b->nv); 00632 } 00633 00634 #if 0 /* UNUSED 2.5 */ 00635 static void removeVertFromBucket(EmbedBucket *b, float co[3]) 00636 { 00637 mul_v3_fl(b->p, (float)b->nv); 00638 sub_v3_v3(b->p, co); 00639 b->nv--; 00640 mul_v3_fl(b->p, 1.0f / (float)b->nv); 00641 } 00642 #endif 00643 00644 static void mergeBuckets(EmbedBucket *bDst, EmbedBucket *bSrc) 00645 { 00646 if (bDst->nv > 0 && bSrc->nv > 0) 00647 { 00648 bDst->nv += bSrc->nv; 00649 interp_v3_v3v3(bDst->p, bDst->p, bSrc->p, (float)bSrc->nv / (float)(bDst->nv)); 00650 } 00651 else if (bSrc->nv > 0) 00652 { 00653 bDst->nv = bSrc->nv; 00654 VECCOPY(bDst->p, bSrc->p); 00655 } 00656 } 00657 00658 static void mergeArcBuckets(ReebArc *aDst, ReebArc *aSrc, float start, float end) 00659 { 00660 if (aDst->bcount > 0 && aSrc->bcount > 0) 00661 { 00662 int indexDst = 0, indexSrc = 0; 00663 00664 start = MAX3(start, aDst->buckets[0].val, aSrc->buckets[0].val); 00665 00666 while(indexDst < aDst->bcount && aDst->buckets[indexDst].val < start) 00667 { 00668 indexDst++; 00669 } 00670 00671 while(indexSrc < aSrc->bcount && aSrc->buckets[indexSrc].val < start) 00672 { 00673 indexSrc++; 00674 } 00675 00676 for( ; indexDst < aDst->bcount && 00677 indexSrc < aSrc->bcount && 00678 aDst->buckets[indexDst].val <= end && 00679 aSrc->buckets[indexSrc].val <= end 00680 00681 ; indexDst++, indexSrc++) 00682 { 00683 mergeBuckets(aDst->buckets + indexDst, aSrc->buckets + indexSrc); 00684 } 00685 } 00686 } 00687 00688 void flipArcBuckets(ReebArc *arc) 00689 { 00690 int i, j; 00691 00692 for (i = 0, j = arc->bcount - 1; i < j; i++, j--) 00693 { 00694 EmbedBucket tmp; 00695 00696 tmp = arc->buckets[i]; 00697 arc->buckets[i] = arc->buckets[j]; 00698 arc->buckets[j] = tmp; 00699 } 00700 } 00701 00702 static int countArcBuckets(ReebArc *arc) 00703 { 00704 return (int)(floor(arc->tail->weight) - ceil(arc->head->weight)) + 1; 00705 } 00706 00707 static void allocArcBuckets(ReebArc *arc) 00708 { 00709 int i; 00710 float start = ceil(arc->head->weight); 00711 arc->bcount = countArcBuckets(arc); 00712 00713 if (arc->bcount > 0) 00714 { 00715 arc->buckets = MEM_callocN(sizeof(EmbedBucket) * arc->bcount, "embed bucket"); 00716 00717 for(i = 0; i < arc->bcount; i++) 00718 { 00719 arc->buckets[i].val = start + i; 00720 } 00721 } 00722 else 00723 { 00724 arc->buckets = NULL; 00725 } 00726 00727 } 00728 00729 static void resizeArcBuckets(ReebArc *arc) 00730 { 00731 EmbedBucket *oldBuckets = arc->buckets; 00732 int oldBCount = arc->bcount; 00733 00734 if (countArcBuckets(arc) == oldBCount) 00735 { 00736 return; 00737 } 00738 00739 allocArcBuckets(arc); 00740 00741 if (oldBCount != 0 && arc->bcount != 0) 00742 { 00743 int oldStart = (int)oldBuckets[0].val; 00744 int oldEnd = (int)oldBuckets[oldBCount - 1].val; 00745 int newStart = (int)arc->buckets[0].val; 00746 int newEnd = (int)arc->buckets[arc->bcount - 1].val; 00747 int oldOffset = 0; 00748 int newOffset = 0; 00749 int len; 00750 00751 if (oldStart < newStart) 00752 { 00753 oldOffset = newStart - oldStart; 00754 } 00755 else 00756 { 00757 newOffset = oldStart - newStart; 00758 } 00759 00760 len = MIN2(oldEnd - (oldStart + oldOffset) + 1, newEnd - (newStart - newOffset) + 1); 00761 00762 memcpy(arc->buckets + newOffset, oldBuckets + oldOffset, len * sizeof(EmbedBucket)); 00763 } 00764 00765 if (oldBuckets != NULL) 00766 { 00767 MEM_freeN(oldBuckets); 00768 } 00769 } 00770 00771 static void reweightBuckets(ReebArc *arc) 00772 { 00773 int i; 00774 float start = ceil((arc->head)->weight); 00775 00776 if (arc->bcount > 0) 00777 { 00778 for(i = 0; i < arc->bcount; i++) 00779 { 00780 arc->buckets[i].val = start + i; 00781 } 00782 } 00783 } 00784 00785 static void interpolateBuckets(ReebArc *arc, float *start_p, float *end_p, int start_index, int end_index) 00786 { 00787 int total; 00788 int j; 00789 00790 total = end_index - start_index + 2; 00791 00792 for (j = start_index; j <= end_index; j++) 00793 { 00794 EmbedBucket *empty = arc->buckets + j; 00795 empty->nv = 1; 00796 interp_v3_v3v3(empty->p, start_p, end_p, (float)(j - start_index + 1) / total); 00797 } 00798 } 00799 00800 static void fillArcEmptyBuckets(ReebArc *arc) 00801 { 00802 float *start_p, *end_p; 00803 int start_index = 0, end_index = 0; 00804 int missing = 0; 00805 int i; 00806 00807 start_p = arc->head->p; 00808 00809 for(i = 0; i < arc->bcount; i++) 00810 { 00811 EmbedBucket *bucket = arc->buckets + i; 00812 00813 if (missing) 00814 { 00815 if (bucket->nv > 0) 00816 { 00817 missing = 0; 00818 00819 end_p = bucket->p; 00820 end_index = i - 1; 00821 00822 interpolateBuckets(arc, start_p, end_p, start_index, end_index); 00823 } 00824 } 00825 else 00826 { 00827 if (bucket->nv == 0) 00828 { 00829 missing = 1; 00830 00831 if (i > 0) 00832 { 00833 start_p = arc->buckets[i - 1].p; 00834 } 00835 start_index = i; 00836 } 00837 } 00838 } 00839 00840 if (missing) 00841 { 00842 end_p = arc->tail->p; 00843 end_index = arc->bcount - 1; 00844 00845 interpolateBuckets(arc, start_p, end_p, start_index, end_index); 00846 } 00847 } 00848 00849 static void ExtendArcBuckets(ReebArc *arc) 00850 { 00851 ReebArcIterator arc_iter; 00852 BArcIterator *iter = (BArcIterator*)&arc_iter; 00853 EmbedBucket *last_bucket, *first_bucket; 00854 float *previous = NULL; 00855 float average_length = 0, length; 00856 int padding_head = 0, padding_tail = 0; 00857 00858 if (arc->bcount == 0) 00859 { 00860 return; /* failsafe, shouldn't happen */ 00861 } 00862 00863 initArcIterator(iter, arc, arc->head); 00864 IT_next(iter); 00865 previous = iter->p; 00866 00867 for ( IT_next(iter); 00868 IT_stopped(iter) == 0; 00869 previous = iter->p, IT_next(iter) 00870 ) 00871 { 00872 average_length += len_v3v3(previous, iter->p); 00873 } 00874 average_length /= (arc->bcount - 1); 00875 00876 first_bucket = arc->buckets; 00877 last_bucket = arc->buckets + (arc->bcount - 1); 00878 00879 length = len_v3v3(first_bucket->p, arc->head->p); 00880 if (length > 2 * average_length) 00881 { 00882 padding_head = (int)floor(length / average_length); 00883 } 00884 00885 length = len_v3v3(last_bucket->p, arc->tail->p); 00886 if (length > 2 * average_length) 00887 { 00888 padding_tail = (int)floor(length / average_length); 00889 } 00890 00891 if (padding_head + padding_tail > 0) 00892 { 00893 EmbedBucket *old_buckets = arc->buckets; 00894 00895 arc->buckets = MEM_callocN(sizeof(EmbedBucket) * (padding_head + arc->bcount + padding_tail), "embed bucket"); 00896 memcpy(arc->buckets + padding_head, old_buckets, arc->bcount * sizeof(EmbedBucket)); 00897 00898 arc->bcount = padding_head + arc->bcount + padding_tail; 00899 00900 MEM_freeN(old_buckets); 00901 } 00902 00903 if (padding_head > 0) 00904 { 00905 interpolateBuckets(arc, arc->head->p, first_bucket->p, 0, padding_head); 00906 } 00907 00908 if (padding_tail > 0) 00909 { 00910 interpolateBuckets(arc, last_bucket->p, arc->tail->p, arc->bcount - padding_tail, arc->bcount - 1); 00911 } 00912 } 00913 00914 /* CALL THIS ONLY AFTER FILTERING, SINCE IT MESSES UP WEIGHT DISTRIBUTION */ 00915 static void extendGraphBuckets(ReebGraph *rg) 00916 { 00917 ReebArc *arc; 00918 00919 for (arc = rg->arcs.first; arc; arc = arc->next) 00920 { 00921 ExtendArcBuckets(arc); 00922 } 00923 } 00924 00925 /**************************************** LENGTH CALCULATIONS ****************************************/ 00926 00927 static void calculateArcLength(ReebArc *arc) 00928 { 00929 ReebArcIterator arc_iter; 00930 BArcIterator *iter = (BArcIterator*)&arc_iter; 00931 float *vec0, *vec1; 00932 00933 arc->length = 0; 00934 00935 initArcIterator(iter, arc, arc->head); 00936 00937 vec0 = arc->head->p; 00938 vec1 = arc->head->p; /* in case there's no embedding */ 00939 00940 while (IT_next(iter)) 00941 { 00942 vec1 = iter->p; 00943 00944 arc->length += len_v3v3(vec0, vec1); 00945 00946 vec0 = vec1; 00947 } 00948 00949 arc->length += len_v3v3(arc->tail->p, vec1); 00950 } 00951 00952 static void calculateGraphLength(ReebGraph *rg) 00953 { 00954 ReebArc *arc; 00955 00956 for (arc = rg->arcs.first; arc; arc = arc->next) 00957 { 00958 calculateArcLength(arc); 00959 } 00960 } 00961 00962 /**************************************** SYMMETRY HANDLING ******************************************/ 00963 00964 void REEB_RadialSymmetry(BNode* root_node, RadialArc* ring, int count) 00965 { 00966 ReebNode *node = (ReebNode*)root_node; 00967 float axis[3]; 00968 int i; 00969 00970 VECCOPY(axis, root_node->symmetry_axis); 00971 00972 /* first pass, merge incrementally */ 00973 for (i = 0; i < count - 1; i++) 00974 { 00975 ReebNode *node1, *node2; 00976 ReebArc *arc1, *arc2; 00977 float tangent[3]; 00978 float normal[3]; 00979 int j = i + 1; 00980 00981 add_v3_v3v3(tangent, ring[i].n, ring[j].n); 00982 cross_v3_v3v3(normal, tangent, axis); 00983 00984 node1 = (ReebNode*)BLI_otherNode(ring[i].arc, root_node); 00985 node2 = (ReebNode*)BLI_otherNode(ring[j].arc, root_node); 00986 00987 arc1 = (ReebArc*)ring[i].arc; 00988 arc2 = (ReebArc*)ring[j].arc; 00989 00990 /* mirror first node and mix with the second */ 00991 BLI_mirrorAlongAxis(node1->p, root_node->p, normal); 00992 interp_v3_v3v3(node2->p, node2->p, node1->p, 1.0f / (j + 1)); 00993 00994 /* Merge buckets 00995 * there shouldn't be any null arcs here, but just to be safe 00996 * */ 00997 if (arc1->bcount > 0 && arc2->bcount > 0) 00998 { 00999 ReebArcIterator arc_iter1, arc_iter2; 01000 BArcIterator *iter1 = (BArcIterator*)&arc_iter1; 01001 BArcIterator *iter2 = (BArcIterator*)&arc_iter2; 01002 EmbedBucket *bucket1 = NULL, *bucket2 = NULL; 01003 01004 initArcIterator(iter1, arc1, (ReebNode*)root_node); 01005 initArcIterator(iter2, arc2, (ReebNode*)root_node); 01006 01007 bucket1 = IT_next(iter1); 01008 bucket2 = IT_next(iter2); 01009 01010 /* Make sure they both start at the same value */ 01011 while(bucket1 && bucket2 && bucket1->val < bucket2->val) 01012 { 01013 bucket1 = IT_next(iter1); 01014 } 01015 01016 while(bucket1 && bucket2 && bucket2->val < bucket1->val) 01017 { 01018 bucket2 = IT_next(iter2); 01019 } 01020 01021 01022 for ( ;bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2)) 01023 { 01024 bucket2->nv += bucket1->nv; /* add counts */ 01025 01026 /* mirror on axis */ 01027 BLI_mirrorAlongAxis(bucket1->p, root_node->p, normal); 01028 /* add bucket2 in bucket1 */ 01029 interp_v3_v3v3(bucket2->p, bucket2->p, bucket1->p, (float)bucket1->nv / (float)(bucket2->nv)); 01030 } 01031 } 01032 } 01033 01034 /* second pass, mirror back on previous arcs */ 01035 for (i = count - 1; i > 0; i--) 01036 { 01037 ReebNode *node1, *node2; 01038 ReebArc *arc1, *arc2; 01039 float tangent[3]; 01040 float normal[3]; 01041 int j = i - 1; 01042 01043 add_v3_v3v3(tangent, ring[i].n, ring[j].n); 01044 cross_v3_v3v3(normal, tangent, axis); 01045 01046 node1 = (ReebNode*)BLI_otherNode(ring[i].arc, root_node); 01047 node2 = (ReebNode*)BLI_otherNode(ring[j].arc, root_node); 01048 01049 arc1 = (ReebArc*)ring[i].arc; 01050 arc2 = (ReebArc*)ring[j].arc; 01051 01052 /* copy first node than mirror */ 01053 VECCOPY(node2->p, node1->p); 01054 BLI_mirrorAlongAxis(node2->p, root_node->p, normal); 01055 01056 /* Copy buckets 01057 * there shouldn't be any null arcs here, but just to be safe 01058 * */ 01059 if (arc1->bcount > 0 && arc2->bcount > 0) 01060 { 01061 ReebArcIterator arc_iter1, arc_iter2; 01062 BArcIterator *iter1 = (BArcIterator*)&arc_iter1; 01063 BArcIterator *iter2 = (BArcIterator*)&arc_iter2; 01064 EmbedBucket *bucket1 = NULL, *bucket2 = NULL; 01065 01066 initArcIterator(iter1, arc1, node); 01067 initArcIterator(iter2, arc2, node); 01068 01069 bucket1 = IT_next(iter1); 01070 bucket2 = IT_next(iter2); 01071 01072 /* Make sure they both start at the same value */ 01073 while(bucket1 && bucket1->val < bucket2->val) 01074 { 01075 bucket1 = IT_next(iter1); 01076 } 01077 01078 while(bucket2 && bucket2->val < bucket1->val) 01079 { 01080 bucket2 = IT_next(iter2); 01081 } 01082 01083 01084 for ( ;bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2)) 01085 { 01086 /* copy and mirror back to bucket2 */ 01087 bucket2->nv = bucket1->nv; 01088 VECCOPY(bucket2->p, bucket1->p); 01089 BLI_mirrorAlongAxis(bucket2->p, node->p, normal); 01090 } 01091 } 01092 } 01093 } 01094 01095 void REEB_AxialSymmetry(BNode* root_node, BNode* node1, BNode* node2, struct BArc* barc1, BArc* barc2) 01096 { 01097 ReebArc *arc1, *arc2; 01098 float nor[3], p[3]; 01099 01100 arc1 = (ReebArc*)barc1; 01101 arc2 = (ReebArc*)barc2; 01102 01103 VECCOPY(nor, root_node->symmetry_axis); 01104 01105 /* mirror node2 along axis */ 01106 VECCOPY(p, node2->p); 01107 BLI_mirrorAlongAxis(p, root_node->p, nor); 01108 01109 /* average with node1 */ 01110 add_v3_v3(node1->p, p); 01111 mul_v3_fl(node1->p, 0.5f); 01112 01113 /* mirror back on node2 */ 01114 VECCOPY(node2->p, node1->p); 01115 BLI_mirrorAlongAxis(node2->p, root_node->p, nor); 01116 01117 /* Merge buckets 01118 * there shouldn't be any null arcs here, but just to be safe 01119 * */ 01120 if (arc1->bcount > 0 && arc2->bcount > 0) 01121 { 01122 ReebArcIterator arc_iter1, arc_iter2; 01123 BArcIterator *iter1 = (BArcIterator*)&arc_iter1; 01124 BArcIterator *iter2 = (BArcIterator*)&arc_iter2; 01125 EmbedBucket *bucket1 = NULL, *bucket2 = NULL; 01126 01127 initArcIterator(iter1, arc1, (ReebNode*)root_node); 01128 initArcIterator(iter2, arc2, (ReebNode*)root_node); 01129 01130 bucket1 = IT_next(iter1); 01131 bucket2 = IT_next(iter2); 01132 01133 /* Make sure they both start at the same value */ 01134 while(bucket1 && bucket1->val < bucket2->val) 01135 { 01136 bucket1 = IT_next(iter1); 01137 } 01138 01139 while(bucket2 && bucket2->val < bucket1->val) 01140 { 01141 bucket2 = IT_next(iter2); 01142 } 01143 01144 01145 for ( ;bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2)) 01146 { 01147 bucket1->nv += bucket2->nv; /* add counts */ 01148 01149 /* mirror on axis */ 01150 BLI_mirrorAlongAxis(bucket2->p, root_node->p, nor); 01151 /* add bucket2 in bucket1 */ 01152 interp_v3_v3v3(bucket1->p, bucket1->p, bucket2->p, (float)bucket2->nv / (float)(bucket1->nv)); 01153 01154 /* copy and mirror back to bucket2 */ 01155 bucket2->nv = bucket1->nv; 01156 VECCOPY(bucket2->p, bucket1->p); 01157 BLI_mirrorAlongAxis(bucket2->p, root_node->p, nor); 01158 } 01159 } 01160 } 01161 01162 /************************************** ADJACENCY LIST *************************************************/ 01163 01164 01165 /****************************************** SMOOTHING **************************************************/ 01166 01167 void postprocessGraph(ReebGraph *rg, char mode) 01168 { 01169 ReebArc *arc; 01170 float fac1 = 0, fac2 = 1, fac3 = 0; 01171 01172 switch(mode) 01173 { 01174 case SKGEN_AVERAGE: 01175 fac1 = fac2 = fac3 = 1.0f / 3.0f; 01176 break; 01177 case SKGEN_SMOOTH: 01178 fac1 = fac3 = 0.25f; 01179 fac2 = 0.5f; 01180 break; 01181 case SKGEN_SHARPEN: 01182 fac1 = fac2 = -0.25f; 01183 fac2 = 1.5f; 01184 break; 01185 default: 01186 // XXX 01187 // error("Unknown post processing mode"); 01188 return; 01189 } 01190 01191 for(arc = rg->arcs.first; arc; arc = arc->next) 01192 { 01193 EmbedBucket *buckets = arc->buckets; 01194 int bcount = arc->bcount; 01195 int index; 01196 01197 for(index = 1; index < bcount - 1; index++) 01198 { 01199 interp_v3_v3v3(buckets[index].p, buckets[index].p, buckets[index - 1].p, fac1 / (fac1 + fac2)); 01200 interp_v3_v3v3(buckets[index].p, buckets[index].p, buckets[index + 1].p, fac3 / (fac1 + fac2 + fac3)); 01201 } 01202 } 01203 } 01204 01205 /********************************************SORTING****************************************************/ 01206 01207 static int compareNodesWeight(void *vnode1, void *vnode2) 01208 { 01209 ReebNode *node1 = (ReebNode*)vnode1; 01210 ReebNode *node2 = (ReebNode*)vnode2; 01211 01212 if (node1->weight < node2->weight) 01213 { 01214 return -1; 01215 } 01216 if (node1->weight > node2->weight) 01217 { 01218 return 1; 01219 } 01220 else 01221 { 01222 return 0; 01223 } 01224 } 01225 01226 void sortNodes(ReebGraph *rg) 01227 { 01228 BLI_sortlist(&rg->nodes, compareNodesWeight); 01229 } 01230 01231 static int compareArcsWeight(void *varc1, void *varc2) 01232 { 01233 ReebArc *arc1 = (ReebArc*)varc1; 01234 ReebArc *arc2 = (ReebArc*)varc2; 01235 ReebNode *node1 = (ReebNode*)arc1->head; 01236 ReebNode *node2 = (ReebNode*)arc2->head; 01237 01238 if (node1->weight < node2->weight) 01239 { 01240 return -1; 01241 } 01242 if (node1->weight > node2->weight) 01243 { 01244 return 1; 01245 } 01246 else 01247 { 01248 return 0; 01249 } 01250 } 01251 01252 void sortArcs(ReebGraph *rg) 01253 { 01254 BLI_sortlist(&rg->arcs, compareArcsWeight); 01255 } 01256 /******************************************* JOINING ***************************************************/ 01257 01258 static void reweightArc(ReebGraph *rg, ReebArc *arc, ReebNode *start_node, float start_weight) 01259 { 01260 ReebNode *node; 01261 float old_weight; 01262 float end_weight = start_weight + ABS(arc->tail->weight - arc->head->weight); 01263 int i; 01264 01265 node = (ReebNode*)BLI_otherNode((BArc*)arc, (BNode*)start_node); 01266 01267 /* prevent backtracking */ 01268 if (node->flag == 1) 01269 { 01270 return; 01271 } 01272 01273 if (arc->tail == start_node) 01274 { 01275 flipArc(arc); 01276 } 01277 01278 start_node->flag = 1; 01279 01280 for (i = 0; i < node->degree; i++) 01281 { 01282 ReebArc *next_arc = node->arcs[i]; 01283 01284 reweightArc(rg, next_arc, node, end_weight); 01285 } 01286 01287 /* update only if needed */ 01288 if (arc->head->weight != start_weight || arc->tail->weight != end_weight) 01289 { 01290 old_weight = arc->head->weight; /* backup head weight, other arcs need it intact, it will be fixed by the source arc */ 01291 01292 arc->head->weight = start_weight; 01293 arc->tail->weight = end_weight; 01294 01295 reweightBuckets(arc); 01296 resizeArcBuckets(arc); 01297 fillArcEmptyBuckets(arc); 01298 01299 arc->head->weight = old_weight; 01300 } 01301 } 01302 01303 static void reweightSubgraph(ReebGraph *rg, ReebNode *start_node, float start_weight) 01304 { 01305 int i; 01306 01307 BLI_flagNodes((BGraph*)rg, 0); 01308 01309 for (i = 0; i < start_node->degree; i++) 01310 { 01311 ReebArc *next_arc = start_node->arcs[i]; 01312 01313 reweightArc(rg, next_arc, start_node, start_weight); 01314 } 01315 start_node->weight = start_weight; 01316 } 01317 01318 static int joinSubgraphsEnds(ReebGraph *rg, float threshold, int nb_subgraphs) 01319 { 01320 int joined = 0; 01321 int subgraph; 01322 01323 for (subgraph = 1; subgraph <= nb_subgraphs; subgraph++) 01324 { 01325 ReebNode *start_node, *end_node; 01326 ReebNode *min_node_start = NULL, *min_node_end = NULL; 01327 float min_distance = FLT_MAX; 01328 01329 for (start_node = rg->nodes.first; start_node; start_node = start_node->next) 01330 { 01331 if (start_node->subgraph_index == subgraph && start_node->degree == 1) 01332 { 01333 01334 for (end_node = rg->nodes.first; end_node; end_node = end_node->next) 01335 { 01336 if (end_node->subgraph_index != subgraph) 01337 { 01338 float distance = len_v3v3(start_node->p, end_node->p); 01339 01340 if (distance < threshold && distance < min_distance) 01341 { 01342 min_distance = distance; 01343 min_node_end = end_node; 01344 min_node_start = start_node; 01345 } 01346 } 01347 } 01348 } 01349 } 01350 01351 end_node = min_node_end; 01352 start_node = min_node_start; 01353 01354 if (end_node && start_node) 01355 { 01356 ReebArc *start_arc, *end_arc; 01357 int merging = 0; 01358 01359 start_arc = start_node->arcs[0]; 01360 end_arc = end_node->arcs[0]; 01361 01362 if (start_arc->tail == start_node) 01363 { 01364 reweightSubgraph(rg, end_node, start_node->weight); 01365 01366 start_arc->tail = end_node; 01367 01368 merging = 1; 01369 } 01370 else if (start_arc->head == start_node) 01371 { 01372 reweightSubgraph(rg, start_node, end_node->weight); 01373 01374 start_arc->head = end_node; 01375 01376 merging = 2; 01377 } 01378 01379 if (merging) 01380 { 01381 BLI_ReflagSubgraph((BGraph*)rg, end_node->flag, subgraph); 01382 01383 resizeArcBuckets(start_arc); 01384 fillArcEmptyBuckets(start_arc); 01385 01386 NodeDegreeIncrement(rg, end_node); 01387 BLI_rebuildAdjacencyListForNode((BGraph*)rg, (BNode*)end_node); 01388 01389 BLI_removeNode((BGraph*)rg, (BNode*)start_node); 01390 } 01391 01392 joined = 1; 01393 } 01394 } 01395 01396 return joined; 01397 } 01398 01399 /* Reweight graph from smallest node, fix fliped arcs */ 01400 static void fixSubgraphsOrientation(ReebGraph *rg, int nb_subgraphs) 01401 { 01402 int subgraph; 01403 01404 for (subgraph = 1; subgraph <= nb_subgraphs; subgraph++) 01405 { 01406 ReebNode *node; 01407 ReebNode *start_node = NULL; 01408 01409 for (node = rg->nodes.first; node; node = node->next) 01410 { 01411 if (node->subgraph_index == subgraph) 01412 { 01413 if (start_node == NULL || node->weight < start_node->weight) 01414 { 01415 start_node = node; 01416 } 01417 } 01418 } 01419 01420 if (start_node) 01421 { 01422 reweightSubgraph(rg, start_node, start_node->weight); 01423 } 01424 } 01425 } 01426 01427 static int joinSubgraphs(ReebGraph *rg, float threshold) 01428 { 01429 int nb_subgraphs; 01430 int joined = 0; 01431 01432 BLI_buildAdjacencyList((BGraph*)rg); 01433 01434 if (BLI_isGraphCyclic((BGraph*)rg)) 01435 { 01436 /* don't deal with cyclic graphs YET */ 01437 return 0; 01438 } 01439 01440 /* sort nodes before flagging subgraphs to make sure root node is subgraph 0 */ 01441 sortNodes(rg); 01442 01443 nb_subgraphs = BLI_FlagSubgraphs((BGraph*)rg); 01444 01445 /* Harmonic function can create flipped arcs, take the occasion to fix them */ 01446 // XXX 01447 // if (G.scene->toolsettings->skgen_options & SKGEN_HARMONIC) 01448 // { 01449 fixSubgraphsOrientation(rg, nb_subgraphs); 01450 // } 01451 01452 if (nb_subgraphs > 1) 01453 { 01454 joined |= joinSubgraphsEnds(rg, threshold, nb_subgraphs); 01455 01456 if (joined) 01457 { 01458 removeNormalNodes(rg); 01459 BLI_buildAdjacencyList((BGraph*)rg); 01460 } 01461 } 01462 01463 return joined; 01464 } 01465 01466 /****************************************** FILTERING **************************************************/ 01467 01468 static float lengthArc(ReebArc *arc) 01469 { 01470 #if 0 01471 ReebNode *head = (ReebNode*)arc->head; 01472 ReebNode *tail = (ReebNode*)arc->tail; 01473 01474 return tail->weight - head->weight; 01475 #else 01476 return arc->length; 01477 #endif 01478 } 01479 01480 static int compareArcs(void *varc1, void *varc2) 01481 { 01482 ReebArc *arc1 = (ReebArc*)varc1; 01483 ReebArc *arc2 = (ReebArc*)varc2; 01484 float len1 = lengthArc(arc1); 01485 float len2 = lengthArc(arc2); 01486 01487 if (len1 < len2) 01488 { 01489 return -1; 01490 } 01491 if (len1 > len2) 01492 { 01493 return 1; 01494 } 01495 else 01496 { 01497 return 0; 01498 } 01499 } 01500 01501 static void filterArc(ReebGraph *rg, ReebNode *newNode, ReebNode *removedNode, ReebArc * srcArc, int merging) 01502 { 01503 ReebArc *arc = NULL, *nextArc = NULL; 01504 01505 if (merging) 01506 { 01507 /* first pass, merge buckets for arcs that spawned the two nodes into the source arc*/ 01508 for(arc = rg->arcs.first; arc; arc = arc->next) 01509 { 01510 if (arc->head == srcArc->head && arc->tail == srcArc->tail && arc != srcArc) 01511 { 01512 ReebNode *head = srcArc->head; 01513 ReebNode *tail = srcArc->tail; 01514 mergeArcBuckets(srcArc, arc, head->weight, tail->weight); 01515 } 01516 } 01517 } 01518 01519 /* second pass, replace removedNode by newNode, remove arcs that are collapsed in a loop */ 01520 arc = rg->arcs.first; 01521 while(arc) 01522 { 01523 nextArc = arc->next; 01524 01525 if (arc->head == removedNode || arc->tail == removedNode) 01526 { 01527 if (arc->head == removedNode) 01528 { 01529 arc->head = newNode; 01530 } 01531 else 01532 { 01533 arc->tail = newNode; 01534 } 01535 01536 // Remove looped arcs 01537 if (arc->head == arc->tail) 01538 { 01539 // v1 or v2 was already newNode, since we're removing an arc, decrement degree 01540 NodeDegreeDecrement(rg, newNode); 01541 01542 // If it's srcArc, it'll be removed later, so keep it for now 01543 if (arc != srcArc) 01544 { 01545 BLI_remlink(&rg->arcs, arc); 01546 REEB_freeArc((BArc*)arc); 01547 } 01548 } 01549 else 01550 { 01551 /* flip arcs that flipped, can happen on diamond shapes, mostly on null arcs */ 01552 if (arc->head->weight > arc->tail->weight) 01553 { 01554 flipArc(arc); 01555 } 01556 //newNode->degree++; // incrementing degree since we're adding an arc 01557 NodeDegreeIncrement(rg, newNode); 01558 mergeArcFaces(rg, arc, srcArc); 01559 01560 if (merging) 01561 { 01562 ReebNode *head = arc->head; 01563 ReebNode *tail = arc->tail; 01564 01565 // resize bucket list 01566 resizeArcBuckets(arc); 01567 mergeArcBuckets(arc, srcArc, head->weight, tail->weight); 01568 01569 /* update length */ 01570 arc->length += srcArc->length; 01571 } 01572 } 01573 } 01574 01575 arc = nextArc; 01576 } 01577 } 01578 01579 void filterNullReebGraph(ReebGraph *rg) 01580 { 01581 ReebArc *arc = NULL, *nextArc = NULL; 01582 01583 arc = rg->arcs.first; 01584 while(arc) 01585 { 01586 nextArc = arc->next; 01587 // Only collapse arcs too short to have any embed bucket 01588 if (arc->bcount == 0) 01589 { 01590 ReebNode *newNode = (ReebNode*)arc->head; 01591 ReebNode *removedNode = (ReebNode*)arc->tail; 01592 float blend; 01593 01594 blend = (float)newNode->degree / (float)(newNode->degree + removedNode->degree); // blending factors 01595 01596 interp_v3_v3v3(newNode->p, removedNode->p, newNode->p, blend); 01597 01598 filterArc(rg, newNode, removedNode, arc, 0); 01599 01600 // Reset nextArc, it might have changed 01601 nextArc = arc->next; 01602 01603 BLI_remlink(&rg->arcs, arc); 01604 REEB_freeArc((BArc*)arc); 01605 01606 BLI_removeNode((BGraph*)rg, (BNode*)removedNode); 01607 } 01608 01609 arc = nextArc; 01610 } 01611 } 01612 01613 static int filterInternalExternalReebGraph(ReebGraph *rg, float threshold_internal, float threshold_external) 01614 { 01615 ReebArc *arc = NULL, *nextArc = NULL; 01616 int value = 0; 01617 01618 BLI_sortlist(&rg->arcs, compareArcs); 01619 01620 for (arc = rg->arcs.first; arc; arc = nextArc) 01621 { 01622 nextArc = arc->next; 01623 01624 // Only collapse non-terminal arcs that are shorter than threshold 01625 if (threshold_internal > 0 && arc->head->degree > 1 && arc->tail->degree > 1 && (lengthArc(arc) < threshold_internal)) 01626 { 01627 ReebNode *newNode = NULL; 01628 ReebNode *removedNode = NULL; 01629 01630 /* Always remove lower node, so arcs don't flip */ 01631 newNode = arc->head; 01632 removedNode = arc->tail; 01633 01634 filterArc(rg, newNode, removedNode, arc, 1); 01635 01636 // Reset nextArc, it might have changed 01637 nextArc = arc->next; 01638 01639 BLI_remlink(&rg->arcs, arc); 01640 REEB_freeArc((BArc*)arc); 01641 01642 BLI_removeNode((BGraph*)rg, (BNode*)removedNode); 01643 value = 1; 01644 } 01645 01646 // Only collapse terminal arcs that are shorter than threshold 01647 else if (threshold_external > 0 && (arc->head->degree == 1 || arc->tail->degree == 1) && (lengthArc(arc) < threshold_external)) 01648 { 01649 ReebNode *terminalNode = NULL; 01650 ReebNode *middleNode = NULL; 01651 ReebNode *removedNode = NULL; 01652 01653 // Assign terminal and middle nodes 01654 if (arc->head->degree == 1) 01655 { 01656 terminalNode = arc->head; 01657 middleNode = arc->tail; 01658 } 01659 else 01660 { 01661 terminalNode = arc->tail; 01662 middleNode = arc->head; 01663 } 01664 01665 if (middleNode->degree == 2 && middleNode != rg->nodes.first) 01666 { 01667 #if 1 01668 // If middle node is a normal node, it will be removed later 01669 // Only if middle node is not the root node 01670 /* USE THIS IF YOU WANT TO PROLONG ARCS TO THEIR TERMINAL NODES 01671 * FOR HANDS, THIS IS NOT THE BEST RESULT 01672 * */ 01673 continue; 01674 #else 01675 removedNode = terminalNode; 01676 01677 // removing arc, so we need to decrease the degree of the remaining node 01678 NodeDegreeDecrement(rg, middleNode); 01679 #endif 01680 } 01681 // Otherwise, just plain remove of the arc 01682 else 01683 { 01684 removedNode = terminalNode; 01685 01686 // removing arc, so we need to decrease the degree of the remaining node 01687 NodeDegreeDecrement(rg, middleNode); 01688 } 01689 01690 // Reset nextArc, it might have changed 01691 nextArc = arc->next; 01692 01693 BLI_remlink(&rg->arcs, arc); 01694 REEB_freeArc((BArc*)arc); 01695 01696 BLI_removeNode((BGraph*)rg, (BNode*)removedNode); 01697 value = 1; 01698 } 01699 } 01700 01701 return value; 01702 } 01703 01704 static int filterCyclesReebGraph(ReebGraph *rg, float UNUSED(distance_threshold)) 01705 { 01706 ReebArc *arc1, *arc2; 01707 ReebArc *next2; 01708 int filtered = 0; 01709 01710 for (arc1 = rg->arcs.first; arc1; arc1 = arc1->next) 01711 { 01712 for (arc2 = arc1->next; arc2; arc2 = next2) 01713 { 01714 next2 = arc2->next; 01715 if (arc1 != arc2 && arc1->head == arc2->head && arc1->tail == arc2->tail) 01716 { 01717 mergeArcEdges(rg, arc1, arc2, MERGE_APPEND); 01718 mergeArcFaces(rg, arc1, arc2); 01719 mergeArcBuckets(arc1, arc2, arc1->head->weight, arc1->tail->weight); 01720 01721 NodeDegreeDecrement(rg, arc1->head); 01722 NodeDegreeDecrement(rg, arc1->tail); 01723 01724 BLI_remlink(&rg->arcs, arc2); 01725 REEB_freeArc((BArc*)arc2); 01726 01727 filtered = 1; 01728 } 01729 } 01730 } 01731 01732 return filtered; 01733 } 01734 01735 int filterSmartReebGraph(ReebGraph *UNUSED(rg), float UNUSED(threshold)) 01736 { 01737 int value = 0; 01738 #if 0 //XXX 01739 ReebArc *arc = NULL, *nextArc = NULL; 01740 01741 BLI_sortlist(&rg->arcs, compareArcs); 01742 01743 #ifdef DEBUG_REEB 01744 { 01745 EditFace *efa; 01746 for(efa=G.editMesh->faces.first; efa; efa=efa->next) { 01747 efa->tmp.fp = -1; 01748 } 01749 } 01750 #endif 01751 01752 arc = rg->arcs.first; 01753 while(arc) 01754 { 01755 nextArc = arc->next; 01756 01757 /* need correct normals and center */ 01758 recalc_editnormals(); 01759 01760 // Only test terminal arcs 01761 if (arc->head->degree == 1 || arc->tail->degree == 1) 01762 { 01763 GHashIterator ghi; 01764 int merging = 0; 01765 int total = BLI_ghash_size(arc->faces); 01766 float avg_angle = 0; 01767 float avg_vec[3] = {0,0,0}; 01768 01769 for(BLI_ghashIterator_init(&ghi, arc->faces); 01770 !BLI_ghashIterator_isDone(&ghi); 01771 BLI_ghashIterator_step(&ghi)) 01772 { 01773 EditFace *efa = BLI_ghashIterator_getValue(&ghi); 01774 01775 #if 0 01776 ReebArcIterator arc_iter; 01777 BArcIterator *iter = (BArcIterator*)&arc_iter; 01778 EmbedBucket *bucket = NULL; 01779 EmbedBucket *previous = NULL; 01780 float min_distance = -1; 01781 float angle = 0; 01782 01783 initArcIterator(iter, arc, arc->head); 01784 01785 bucket = nextBucket(iter); 01786 01787 while (bucket != NULL) 01788 { 01789 float *vec0 = NULL; 01790 float *vec1 = bucket->p; 01791 float midpoint[3], tangent[3]; 01792 float distance; 01793 01794 /* first bucket. Previous is head */ 01795 if (previous == NULL) 01796 { 01797 vec0 = arc->head->p; 01798 } 01799 /* Previous is a valid bucket */ 01800 else 01801 { 01802 vec0 = previous->p; 01803 } 01804 01805 VECCOPY(midpoint, vec1); 01806 01807 distance = len_v3v3(midpoint, efa->cent); 01808 01809 if (min_distance == -1 || distance < min_distance) 01810 { 01811 min_distance = distance; 01812 01813 sub_v3_v3v3(tangent, vec1, vec0); 01814 normalize_v3(tangent); 01815 01816 angle = dot_v3v3(tangent, efa->n); 01817 } 01818 01819 previous = bucket; 01820 bucket = nextBucket(iter); 01821 } 01822 01823 avg_angle += saacos(fabs(angle)); 01824 #ifdef DEBUG_REEB 01825 efa->tmp.fp = saacos(fabs(angle)); 01826 #endif 01827 #else 01828 add_v3_v3(avg_vec, efa->n); 01829 #endif 01830 } 01831 01832 01833 #if 0 01834 avg_angle /= total; 01835 #else 01836 mul_v3_fl(avg_vec, 1.0 / total); 01837 avg_angle = dot_v3v3(avg_vec, avg_vec); 01838 #endif 01839 01840 arc->angle = avg_angle; 01841 01842 if (avg_angle > threshold) 01843 merging = 1; 01844 01845 if (merging) 01846 { 01847 ReebNode *terminalNode = NULL; 01848 ReebNode *middleNode = NULL; 01849 ReebNode *newNode = NULL; 01850 ReebNode *removedNode = NULL; 01851 int merging = 0; 01852 01853 // Assign terminal and middle nodes 01854 if (arc->head->degree == 1) 01855 { 01856 terminalNode = arc->head; 01857 middleNode = arc->tail; 01858 } 01859 else 01860 { 01861 terminalNode = arc->tail; 01862 middleNode = arc->head; 01863 } 01864 01865 // If middle node is a normal node, merge to terminal node 01866 if (middleNode->degree == 2) 01867 { 01868 merging = 1; 01869 newNode = terminalNode; 01870 removedNode = middleNode; 01871 } 01872 // Otherwise, just plain remove of the arc 01873 else 01874 { 01875 merging = 0; 01876 newNode = middleNode; 01877 removedNode = terminalNode; 01878 } 01879 01880 // Merging arc 01881 if (merging) 01882 { 01883 filterArc(rg, newNode, removedNode, arc, 1); 01884 } 01885 else 01886 { 01887 // removing arc, so we need to decrease the degree of the remaining node 01888 //newNode->degree--; 01889 NodeDegreeDecrement(rg, newNode); 01890 } 01891 01892 // Reset nextArc, it might have changed 01893 nextArc = arc->next; 01894 01895 BLI_remlink(&rg->arcs, arc); 01896 REEB_freeArc((BArc*)arc); 01897 01898 BLI_freelinkN(&rg->nodes, removedNode); 01899 value = 1; 01900 } 01901 } 01902 01903 arc = nextArc; 01904 } 01905 01906 #endif 01907 01908 return value; 01909 } 01910 01911 static void filterGraph(ReebGraph *rg, short options, float threshold_internal, float threshold_external) 01912 { 01913 int done = 1; 01914 01915 calculateGraphLength(rg); 01916 01917 if ((options & SKGEN_FILTER_EXTERNAL) == 0) 01918 { 01919 threshold_external = 0; 01920 } 01921 01922 if ((options & SKGEN_FILTER_INTERNAL) == 0) 01923 { 01924 threshold_internal = 0; 01925 } 01926 01927 if (threshold_internal > 0 || threshold_external > 0) 01928 { 01929 /* filter until there's nothing more to do */ 01930 while (done == 1) 01931 { 01932 done = 0; /* no work done yet */ 01933 01934 done = filterInternalExternalReebGraph(rg, threshold_internal, threshold_external); 01935 } 01936 } 01937 01938 if (options & SKGEN_FILTER_SMART) 01939 { 01940 filterSmartReebGraph(rg, 0.5); 01941 filterCyclesReebGraph(rg, 0.5); 01942 } 01943 01944 repositionNodes(rg); 01945 01946 /* Filtering might have created degree 2 nodes, so remove them */ 01947 removeNormalNodes(rg); 01948 } 01949 01950 static void finalizeGraph(ReebGraph *rg, char passes, char method) 01951 { 01952 int i; 01953 01954 BLI_buildAdjacencyList((BGraph*)rg); 01955 01956 sortNodes(rg); 01957 01958 sortArcs(rg); 01959 01960 for(i = 0; i < passes; i++) 01961 { 01962 postprocessGraph(rg, method); 01963 } 01964 01965 extendGraphBuckets(rg); 01966 } 01967 01968 /************************************** WEIGHT SPREADING ***********************************************/ 01969 01970 static int compareVerts( const void* a, const void* b ) 01971 { 01972 EditVert *va = *(EditVert**)a; 01973 EditVert *vb = *(EditVert**)b; 01974 int value = 0; 01975 01976 if (weightData(va) < weightData(vb)) 01977 { 01978 value = -1; 01979 } 01980 else if (weightData(va) > weightData(vb)) 01981 { 01982 value = 1; 01983 } 01984 01985 return value; 01986 } 01987 01988 static void spreadWeight(EditMesh *em) 01989 { 01990 EditVert **verts, *eve; 01991 float lastWeight = 0.0f; 01992 int totvert = BLI_countlist(&em->verts); 01993 int i; 01994 int work_needed = 1; 01995 01996 verts = MEM_callocN(sizeof(EditVert*) * totvert, "verts array"); 01997 01998 for(eve = em->verts.first, i = 0; eve; eve = eve->next, i++) 01999 { 02000 verts[i] = eve; 02001 } 02002 02003 while(work_needed == 1) 02004 { 02005 work_needed = 0; 02006 qsort(verts, totvert, sizeof(EditVert*), compareVerts); 02007 02008 for(i = 0; i < totvert; i++) 02009 { 02010 eve = verts[i]; 02011 02012 if (i == 0 || (weightData(eve) - lastWeight) > FLT_EPSILON) 02013 { 02014 lastWeight = weightData(eve); 02015 } 02016 else 02017 { 02018 work_needed = 1; 02019 weightSetData(eve, lastWeight + FLT_EPSILON * 2); 02020 lastWeight = weightData(eve); 02021 } 02022 } 02023 } 02024 02025 MEM_freeN(verts); 02026 } 02027 02028 /******************************************** EXPORT ***************************************************/ 02029 02030 static void exportNode(FILE *f, const char *text, ReebNode *node) 02031 { 02032 fprintf(f, "%s i:%i w:%f d:%i %f %f %f\n", text, node->index, node->weight, node->degree, node->p[0], node->p[1], node->p[2]); 02033 } 02034 02035 void REEB_exportGraph(ReebGraph *rg, int count) 02036 { 02037 ReebArc *arc; 02038 char filename[128]; 02039 FILE *f; 02040 02041 if (count == -1) 02042 { 02043 sprintf(filename, "test.txt"); 02044 } 02045 else 02046 { 02047 sprintf(filename, "test%05i.txt", count); 02048 } 02049 f = fopen(filename, "w"); 02050 02051 for(arc = rg->arcs.first; arc; arc = arc->next) 02052 { 02053 int i; 02054 float p[3]; 02055 02056 exportNode(f, "v1", arc->head); 02057 02058 for(i = 0; i < arc->bcount; i++) 02059 { 02060 fprintf(f, "b nv:%i %f %f %f\n", arc->buckets[i].nv, arc->buckets[i].p[0], arc->buckets[i].p[1], arc->buckets[i].p[2]); 02061 } 02062 02063 add_v3_v3v3(p, arc->tail->p, arc->head->p); 02064 mul_v3_fl(p, 0.5f); 02065 02066 fprintf(f, "angle %0.3f %0.3f %0.3f %0.3f %i\n", p[0], p[1], p[2], arc->angle, BLI_ghash_size(arc->faces)); 02067 exportNode(f, "v2", arc->tail); 02068 } 02069 02070 fclose(f); 02071 } 02072 02073 /***************************************** MAIN ALGORITHM **********************************************/ 02074 02075 /* edges alone will create zero degree nodes, use this function to remove them */ 02076 static void removeZeroNodes(ReebGraph *rg) 02077 { 02078 ReebNode *node, *next_node; 02079 02080 for (node = rg->nodes.first; node; node = next_node) 02081 { 02082 next_node = node->next; 02083 02084 if (node->degree == 0) 02085 { 02086 BLI_removeNode((BGraph*)rg, (BNode*)node); 02087 } 02088 } 02089 } 02090 02091 void removeNormalNodes(ReebGraph *rg) 02092 { 02093 ReebArc *arc, *nextArc; 02094 02095 // Merge degree 2 nodes 02096 for(arc = rg->arcs.first; arc; arc = nextArc) 02097 { 02098 nextArc = arc->next; 02099 02100 while (arc->head->degree == 2 || arc->tail->degree == 2) 02101 { 02102 // merge at v1 02103 if (arc->head->degree == 2) 02104 { 02105 ReebArc *connectedArc = (ReebArc*)BLI_findConnectedArc((BGraph*)rg, (BArc*)arc, (BNode*)arc->head); 02106 02107 /* If arcs are one after the other */ 02108 if (arc->head == connectedArc->tail) 02109 { 02110 /* remove furthest arc */ 02111 if (arc->tail->weight < connectedArc->head->weight) 02112 { 02113 mergeConnectedArcs(rg, arc, connectedArc); 02114 nextArc = arc->next; 02115 } 02116 else 02117 { 02118 mergeConnectedArcs(rg, connectedArc, arc); 02119 break; /* arc was removed, move to next */ 02120 } 02121 } 02122 /* Otherwise, arcs are side by side */ 02123 else 02124 { 02125 /* Don't do anything, we need to keep the lowest node, even if degree 2 */ 02126 break; 02127 } 02128 } 02129 02130 // merge at v2 02131 if (arc->tail->degree == 2) 02132 { 02133 ReebArc *connectedArc = (ReebArc*)BLI_findConnectedArc((BGraph*)rg, (BArc*)arc, (BNode*)arc->tail); 02134 02135 /* If arcs are one after the other */ 02136 if (arc->tail == connectedArc->head) 02137 { 02138 /* remove furthest arc */ 02139 if (arc->head->weight < connectedArc->tail->weight) 02140 { 02141 mergeConnectedArcs(rg, arc, connectedArc); 02142 nextArc = arc->next; 02143 } 02144 else 02145 { 02146 mergeConnectedArcs(rg, connectedArc, arc); 02147 break; /* arc was removed, move to next */ 02148 } 02149 } 02150 /* Otherwise, arcs are side by side */ 02151 else 02152 { 02153 /* Don't do anything, we need to keep the lowest node, even if degree 2 */ 02154 break; 02155 } 02156 } 02157 } 02158 } 02159 02160 } 02161 02162 static int edgeEquals(ReebEdge *e1, ReebEdge *e2) 02163 { 02164 return (e1->v1 == e2->v1 && e1->v2 == e2->v2); 02165 } 02166 02167 static ReebArc *nextArcMappedToEdge(ReebArc *arc, ReebEdge *e) 02168 { 02169 ReebEdge *nextEdge = NULL; 02170 ReebEdge *edge = NULL; 02171 ReebArc *result = NULL; 02172 02173 /* Find the ReebEdge in the edge list */ 02174 for(edge = arc->edges.first; edge && !edgeEquals(edge, e); edge = edge->next) 02175 { } 02176 02177 nextEdge = edge->nextEdge; 02178 02179 if (nextEdge != NULL) 02180 { 02181 result = nextEdge->arc; 02182 } 02183 02184 return result; 02185 } 02186 02187 void addFacetoArc(ReebArc *arc, EditFace *efa) 02188 { 02189 BLI_ghash_insert(arc->faces, efa, efa); 02190 } 02191 02192 void mergeArcFaces(ReebGraph *UNUSED(rg), ReebArc *aDst, ReebArc *aSrc) 02193 { 02194 GHashIterator ghi; 02195 02196 for(BLI_ghashIterator_init(&ghi, aSrc->faces); 02197 !BLI_ghashIterator_isDone(&ghi); 02198 BLI_ghashIterator_step(&ghi)) 02199 { 02200 EditFace *efa = BLI_ghashIterator_getValue(&ghi); 02201 BLI_ghash_insert(aDst->faces, efa, efa); 02202 } 02203 } 02204 02205 void mergeArcEdges(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc, MergeDirection direction) 02206 { 02207 ReebEdge *e = NULL; 02208 02209 if (direction == MERGE_APPEND) 02210 { 02211 for(e = aSrc->edges.first; e; e = e->next) 02212 { 02213 e->arc = aDst; // Edge is stolen by new arc 02214 } 02215 02216 BLI_movelisttolist(&aDst->edges , &aSrc->edges); 02217 } 02218 else 02219 { 02220 for(e = aSrc->edges.first; e; e = e->next) 02221 { 02222 ReebEdge *newEdge = copyEdge(e); 02223 02224 newEdge->arc = aDst; 02225 02226 BLI_addtail(&aDst->edges, newEdge); 02227 02228 if (direction == MERGE_LOWER) 02229 { 02230 void **p = BLI_edgehash_lookup_p(rg->emap, e->v1->index, e->v2->index); 02231 02232 newEdge->nextEdge = e; 02233 02234 // if edge was the first in the list, point the edit edge to the new reeb edge instead. 02235 if (*p == e) 02236 { 02237 *p = (void*)newEdge; 02238 } 02239 // otherwise, advance in the list until the predecessor is found then insert it there 02240 else 02241 { 02242 ReebEdge *previous = (ReebEdge*)*p; 02243 02244 while(previous->nextEdge != e) 02245 { 02246 previous = previous->nextEdge; 02247 } 02248 02249 previous->nextEdge = newEdge; 02250 } 02251 } 02252 else 02253 { 02254 newEdge->nextEdge = e->nextEdge; 02255 e->nextEdge = newEdge; 02256 } 02257 } 02258 } 02259 } 02260 02261 // return 1 on full merge 02262 int mergeConnectedArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1) 02263 { 02264 int result = 0; 02265 ReebNode *removedNode = NULL; 02266 02267 a0->length += a1->length; 02268 02269 mergeArcEdges(rg, a0, a1, MERGE_APPEND); 02270 mergeArcFaces(rg, a0, a1); 02271 02272 // Bring a0 to the combine length of both arcs 02273 if (a0->tail == a1->head) 02274 { 02275 removedNode = a0->tail; 02276 a0->tail = a1->tail; 02277 } 02278 else if (a0->head == a1->tail) 02279 { 02280 removedNode = a0->head; 02281 a0->head = a1->head; 02282 } 02283 02284 resizeArcBuckets(a0); 02285 // Merge a1 in a0 02286 mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight); 02287 02288 // remove a1 from graph 02289 BLI_remlink(&rg->arcs, a1); 02290 REEB_freeArc((BArc*)a1); 02291 02292 BLI_removeNode((BGraph*)rg, (BNode*)removedNode); 02293 result = 1; 02294 02295 return result; 02296 } 02297 // return 1 on full merge 02298 int mergeArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1) 02299 { 02300 int result = 0; 02301 // TRIANGLE POINTS DOWN 02302 if (a0->head->weight == a1->head->weight) // heads are the same 02303 { 02304 if (a0->tail->weight == a1->tail->weight) // tails also the same, arcs can be totally merge together 02305 { 02306 mergeArcEdges(rg, a0, a1, MERGE_APPEND); 02307 mergeArcFaces(rg, a0, a1); 02308 02309 mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight); 02310 02311 // Adjust node degree 02312 //a1->head->degree--; 02313 NodeDegreeDecrement(rg, a1->head); 02314 //a1->tail->degree--; 02315 NodeDegreeDecrement(rg, a1->tail); 02316 02317 // remove a1 from graph 02318 BLI_remlink(&rg->arcs, a1); 02319 02320 REEB_freeArc((BArc*)a1); 02321 result = 1; 02322 } 02323 else if (a0->tail->weight > a1->tail->weight) // a1->tail->weight is in the middle 02324 { 02325 mergeArcEdges(rg, a1, a0, MERGE_LOWER); 02326 mergeArcFaces(rg, a1, a0); 02327 02328 // Adjust node degree 02329 //a0->head->degree--; 02330 NodeDegreeDecrement(rg, a0->head); 02331 //a1->tail->degree++; 02332 NodeDegreeIncrement(rg, a1->tail); 02333 02334 mergeArcBuckets(a1, a0, a1->head->weight, a1->tail->weight); 02335 a0->head = a1->tail; 02336 resizeArcBuckets(a0); 02337 } 02338 else // a0>n2 is in the middle 02339 { 02340 mergeArcEdges(rg, a0, a1, MERGE_LOWER); 02341 mergeArcFaces(rg, a0, a1); 02342 02343 // Adjust node degree 02344 //a1->head->degree--; 02345 NodeDegreeDecrement(rg, a1->head); 02346 //a0->tail->degree++; 02347 NodeDegreeIncrement(rg, a0->tail); 02348 02349 mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight); 02350 a1->head = a0->tail; 02351 resizeArcBuckets(a1); 02352 } 02353 } 02354 // TRIANGLE POINTS UP 02355 else if (a0->tail->weight == a1->tail->weight) // tails are the same 02356 { 02357 if (a0->head->weight > a1->head->weight) // a0->head->weight is in the middle 02358 { 02359 mergeArcEdges(rg, a0, a1, MERGE_HIGHER); 02360 mergeArcFaces(rg, a0, a1); 02361 02362 // Adjust node degree 02363 //a1->tail->degree--; 02364 NodeDegreeDecrement(rg, a1->tail); 02365 //a0->head->degree++; 02366 NodeDegreeIncrement(rg, a0->head); 02367 02368 mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight); 02369 a1->tail = a0->head; 02370 resizeArcBuckets(a1); 02371 } 02372 else // a1->head->weight is in the middle 02373 { 02374 mergeArcEdges(rg, a1, a0, MERGE_HIGHER); 02375 mergeArcFaces(rg, a1, a0); 02376 02377 // Adjust node degree 02378 //a0->tail->degree--; 02379 NodeDegreeDecrement(rg, a0->tail); 02380 //a1->head->degree++; 02381 NodeDegreeIncrement(rg, a1->head); 02382 02383 mergeArcBuckets(a1, a0, a1->head->weight, a1->tail->weight); 02384 a0->tail = a1->head; 02385 resizeArcBuckets(a0); 02386 } 02387 } 02388 else 02389 { 02390 // Need something here (OR NOT) 02391 } 02392 02393 return result; 02394 } 02395 02396 static void glueByMergeSort(ReebGraph *rg, ReebArc *a0, ReebArc *a1, ReebEdge *e0, ReebEdge *e1) 02397 { 02398 int total = 0; 02399 while (total == 0 && a0 != a1 && a0 != NULL && a1 != NULL) 02400 { 02401 total = mergeArcs(rg, a0, a1); 02402 02403 if (total == 0) // if it wasn't a total merge, go forward 02404 { 02405 if (a0->tail->weight < a1->tail->weight) 02406 { 02407 a0 = nextArcMappedToEdge(a0, e0); 02408 } 02409 else 02410 { 02411 a1 = nextArcMappedToEdge(a1, e1); 02412 } 02413 } 02414 } 02415 } 02416 02417 static void mergePaths(ReebGraph *rg, ReebEdge *e0, ReebEdge *e1, ReebEdge *e2) 02418 { 02419 ReebArc *a0, *a1, *a2; 02420 a0 = e0->arc; 02421 a1 = e1->arc; 02422 a2 = e2->arc; 02423 02424 glueByMergeSort(rg, a0, a1, e0, e1); 02425 glueByMergeSort(rg, a0, a2, e0, e2); 02426 } 02427 02428 static ReebEdge * createArc(ReebGraph *rg, ReebNode *node1, ReebNode *node2) 02429 { 02430 ReebEdge *edge; 02431 02432 edge = BLI_edgehash_lookup(rg->emap, node1->index, node2->index); 02433 02434 // Only add existing edges that haven't been added yet 02435 if (edge == NULL) 02436 { 02437 ReebArc *arc; 02438 ReebNode *v1, *v2; 02439 float len, offset; 02440 int i; 02441 02442 arc = MEM_callocN(sizeof(ReebArc), "reeb arc"); 02443 edge = MEM_callocN(sizeof(ReebEdge), "reeb edge"); 02444 02445 arc->flag = 0; // clear flag on init 02446 arc->symmetry_level = 0; 02447 arc->faces = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "createArc gh"); 02448 02449 if (node1->weight <= node2->weight) 02450 { 02451 v1 = node1; 02452 v2 = node2; 02453 } 02454 else 02455 { 02456 v1 = node2; 02457 v2 = node1; 02458 } 02459 02460 arc->head = v1; 02461 arc->tail = v2; 02462 02463 // increase node degree 02464 //v1->degree++; 02465 NodeDegreeIncrement(rg, v1); 02466 //v2->degree++; 02467 NodeDegreeIncrement(rg, v2); 02468 02469 BLI_edgehash_insert(rg->emap, node1->index, node2->index, edge); 02470 02471 edge->arc = arc; 02472 edge->nextEdge = NULL; 02473 edge->v1 = v1; 02474 edge->v2 = v2; 02475 02476 BLI_addtail(&rg->arcs, arc); 02477 BLI_addtail(&arc->edges, edge); 02478 02479 /* adding buckets for embedding */ 02480 allocArcBuckets(arc); 02481 02482 offset = arc->head->weight; 02483 len = arc->tail->weight - arc->head->weight; 02484 02485 #if 0 02486 /* This is the actual embedding filling described in the paper 02487 * the problem is that it only works with really dense meshes 02488 */ 02489 if (arc->bcount > 0) 02490 { 02491 addVertToBucket(&(arc->buckets[0]), arc->head->co); 02492 addVertToBucket(&(arc->buckets[arc->bcount - 1]), arc->tail->co); 02493 } 02494 #else 02495 for(i = 0; i < arc->bcount; i++) 02496 { 02497 float co[3]; 02498 float f = (arc->buckets[i].val - offset) / len; 02499 02500 interp_v3_v3v3(co, v1->p, v2->p, f); 02501 addVertToBucket(&(arc->buckets[i]), co); 02502 } 02503 #endif 02504 02505 } 02506 02507 return edge; 02508 } 02509 02510 static void addTriangleToGraph(ReebGraph *rg, ReebNode * n1, ReebNode * n2, ReebNode * n3, EditFace *efa) 02511 { 02512 ReebEdge *re1, *re2, *re3; 02513 ReebEdge *e1, *e2, *e3; 02514 float len1, len2, len3; 02515 02516 re1 = createArc(rg, n1, n2); 02517 re2 = createArc(rg, n2, n3); 02518 re3 = createArc(rg, n3, n1); 02519 02520 addFacetoArc(re1->arc, efa); 02521 addFacetoArc(re2->arc, efa); 02522 addFacetoArc(re3->arc, efa); 02523 02524 len1 = (float)fabs(n1->weight - n2->weight); 02525 len2 = (float)fabs(n2->weight - n3->weight); 02526 len3 = (float)fabs(n3->weight - n1->weight); 02527 02528 /* The rest of the algorithm assumes that e1 is the longest edge */ 02529 02530 if (len1 >= len2 && len1 >= len3) 02531 { 02532 e1 = re1; 02533 e2 = re2; 02534 e3 = re3; 02535 } 02536 else if (len2 >= len1 && len2 >= len3) 02537 { 02538 e1 = re2; 02539 e2 = re1; 02540 e3 = re3; 02541 } 02542 else 02543 { 02544 e1 = re3; 02545 e2 = re2; 02546 e3 = re1; 02547 } 02548 02549 /* And e2 is the lowest edge 02550 * If e3 is lower than e2, swap them 02551 */ 02552 if (e3->v1->weight < e2->v1->weight) 02553 { 02554 ReebEdge *etmp = e2; 02555 e2 = e3; 02556 e3 = etmp; 02557 } 02558 02559 02560 mergePaths(rg, e1, e2, e3); 02561 } 02562 02563 ReebGraph * generateReebGraph(EditMesh *em, int subdivisions) 02564 { 02565 ReebGraph *rg; 02566 EditVert *eve; 02567 EditFace *efa; 02568 int index; 02569 /*int totvert;*/ 02570 02571 #ifdef DEBUG_REEB 02572 int totfaces; 02573 int countfaces = 0; 02574 #endif 02575 02576 rg = newReebGraph(); 02577 02578 rg->resolution = subdivisions; 02579 02580 /*totvert = BLI_countlist(&em->verts);*/ /*UNUSED*/ 02581 #ifdef DEBUG_REEB 02582 totfaces = BLI_countlist(&em->faces); 02583 #endif 02584 02585 renormalizeWeight(em, 1.0f); 02586 02587 /* Spread weight to minimize errors */ 02588 spreadWeight(em); 02589 02590 renormalizeWeight(em, (float)rg->resolution); 02591 02592 /* Adding vertice */ 02593 for(index = 0, eve = em->verts.first; eve; eve = eve->next) 02594 { 02595 if (eve->h == 0) 02596 { 02597 addNode(rg, eve); 02598 eve->f2 = 0; 02599 index++; 02600 } 02601 } 02602 02603 /* Adding face, edge per edge */ 02604 for(efa = em->faces.first; efa; efa = efa->next) 02605 { 02606 if (efa->h == 0) 02607 { 02608 ReebNode *n1, *n2, *n3; 02609 02610 n1 = nodeData(efa->v1); 02611 n2 = nodeData(efa->v2); 02612 n3 = nodeData(efa->v3); 02613 02614 addTriangleToGraph(rg, n1, n2, n3, efa); 02615 02616 if (efa->v4) 02617 { 02618 ReebNode *n4 = nodeData(efa->v4); 02619 addTriangleToGraph(rg, n1, n3, n4, efa); 02620 } 02621 #ifdef DEBUG_REEB 02622 countfaces++; 02623 if (countfaces % 100 == 0) 02624 { 02625 printf("\rface %i of %i", countfaces, totfaces); 02626 } 02627 #endif 02628 } 02629 } 02630 02631 printf("\n"); 02632 02633 removeZeroNodes(rg); 02634 02635 removeNormalNodes(rg); 02636 02637 return rg; 02638 } 02639 02640 /***************************************** WEIGHT UTILS **********************************************/ 02641 02642 void renormalizeWeight(EditMesh *em, float newmax) 02643 { 02644 EditVert *eve; 02645 float minimum, maximum, range; 02646 02647 if (em == NULL || BLI_countlist(&em->verts) == 0) 02648 return; 02649 02650 /* First pass, determine maximum and minimum */ 02651 eve = em->verts.first; 02652 minimum = weightData(eve); 02653 maximum = minimum; 02654 for(; eve; eve = eve->next) 02655 { 02656 maximum = MAX2(maximum, weightData(eve)); 02657 minimum = MIN2(minimum, weightData(eve)); 02658 } 02659 02660 range = maximum - minimum; 02661 02662 /* Normalize weights */ 02663 for(eve = em->verts.first; eve; eve = eve->next) 02664 { 02665 float weight = (weightData(eve) - minimum) / range * newmax; 02666 weightSetData(eve, weight); 02667 } 02668 } 02669 02670 02671 int weightFromLoc(EditMesh *em, int axis) 02672 { 02673 EditVert *eve; 02674 02675 if (em == NULL || BLI_countlist(&em->verts) == 0 || axis < 0 || axis > 2) 02676 return 0; 02677 02678 /* Copy coordinate in weight */ 02679 for(eve = em->verts.first; eve; eve = eve->next) 02680 { 02681 weightSetData(eve, eve->co[axis]); 02682 } 02683 02684 return 1; 02685 } 02686 02687 static float cotan_weight(float *v1, float *v2, float *v3) 02688 { 02689 float a[3], b[3], c[3], clen; 02690 02691 sub_v3_v3v3(a, v2, v1); 02692 sub_v3_v3v3(b, v3, v1); 02693 cross_v3_v3v3(c, a, b); 02694 02695 clen = len_v3(c); 02696 02697 if (clen == 0.0f) 02698 return 0.0f; 02699 02700 return dot_v3v3(a, b)/clen; 02701 } 02702 02703 static void addTriangle(EditVert *v1, EditVert *v2, EditVert *v3, int e1, int e2, int e3) 02704 { 02705 /* Angle opposite e1 */ 02706 float t1= cotan_weight(v1->co, v2->co, v3->co) / e2; 02707 02708 /* Angle opposite e2 */ 02709 float t2 = cotan_weight(v2->co, v3->co, v1->co) / e3; 02710 02711 /* Angle opposite e3 */ 02712 float t3 = cotan_weight(v3->co, v1->co, v2->co) / e1; 02713 02714 int i1 = indexData(v1); 02715 int i2 = indexData(v2); 02716 int i3 = indexData(v3); 02717 02718 nlMatrixAdd(i1, i1, t2+t3); 02719 nlMatrixAdd(i2, i2, t1+t3); 02720 nlMatrixAdd(i3, i3, t1+t2); 02721 02722 nlMatrixAdd(i1, i2, -t3); 02723 nlMatrixAdd(i2, i1, -t3); 02724 02725 nlMatrixAdd(i2, i3, -t1); 02726 nlMatrixAdd(i3, i2, -t1); 02727 02728 nlMatrixAdd(i3, i1, -t2); 02729 nlMatrixAdd(i1, i3, -t2); 02730 } 02731 02732 int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges) 02733 { 02734 NLboolean success; 02735 EditVert *eve; 02736 EditEdge *eed; 02737 EditFace *efa; 02738 int totvert = 0; 02739 int index; 02740 int rval; 02741 02742 /* Find local extrema */ 02743 for(eve = em->verts.first; eve; eve = eve->next) 02744 { 02745 totvert++; 02746 } 02747 02748 /* Solve with openNL */ 02749 02750 nlNewContext(); 02751 02752 nlSolverParameteri(NL_NB_VARIABLES, totvert); 02753 02754 nlBegin(NL_SYSTEM); 02755 02756 /* Find local extrema */ 02757 for(index = 0, eve = em->verts.first; eve; index++, eve = eve->next) 02758 { 02759 if (eve->h == 0) 02760 { 02761 EditEdge *eed; 02762 int maximum = 1; 02763 int minimum = 1; 02764 02765 NextEdgeForVert(indexed_edges, -1); /* Reset next edge */ 02766 for(eed = NextEdgeForVert(indexed_edges, index); eed && (maximum || minimum); eed = NextEdgeForVert(indexed_edges, index)) 02767 { 02768 EditVert *eve2; 02769 02770 if (eed->v1 == eve) 02771 { 02772 eve2 = eed->v2; 02773 } 02774 else 02775 { 02776 eve2 = eed->v1; 02777 } 02778 02779 if (eve2->h == 0) 02780 { 02781 /* Adjacent vertex is bigger, not a local maximum */ 02782 if (weightData(eve2) > weightData(eve)) 02783 { 02784 maximum = 0; 02785 } 02786 /* Adjacent vertex is smaller, not a local minimum */ 02787 else if (weightData(eve2) < weightData(eve)) 02788 { 02789 minimum = 0; 02790 } 02791 } 02792 } 02793 02794 if (maximum || minimum) 02795 { 02796 float w = weightData(eve); 02797 eve->f1 = 0; 02798 nlSetVariable(0, index, w); 02799 nlLockVariable(index); 02800 } 02801 else 02802 { 02803 eve->f1 = 1; 02804 } 02805 } 02806 } 02807 02808 nlBegin(NL_MATRIX); 02809 02810 /* Zero edge weight */ 02811 for(eed = em->edges.first; eed; eed = eed->next) 02812 { 02813 eed->tmp.l = 0; 02814 } 02815 02816 /* Add faces count to the edge weight */ 02817 for(efa = em->faces.first; efa; efa = efa->next) 02818 { 02819 if (efa->h == 0) 02820 { 02821 efa->e1->tmp.l++; 02822 efa->e2->tmp.l++; 02823 efa->e3->tmp.l++; 02824 02825 if (efa->e4) 02826 { 02827 efa->e4->tmp.l++; 02828 } 02829 } 02830 } 02831 02832 /* Add faces angle to the edge weight */ 02833 for(efa = em->faces.first; efa; efa = efa->next) 02834 { 02835 if (efa->h == 0) 02836 { 02837 if (efa->v4 == NULL) 02838 { 02839 addTriangle(efa->v1, efa->v2, efa->v3, efa->e1->tmp.l, efa->e2->tmp.l, efa->e3->tmp.l); 02840 } 02841 else 02842 { 02843 addTriangle(efa->v1, efa->v2, efa->v3, efa->e1->tmp.l, efa->e2->tmp.l, 2); 02844 addTriangle(efa->v3, efa->v4, efa->v1, efa->e3->tmp.l, efa->e4->tmp.l, 2); 02845 } 02846 } 02847 } 02848 02849 nlEnd(NL_MATRIX); 02850 02851 nlEnd(NL_SYSTEM); 02852 02853 success = nlSolveAdvanced(NULL, NL_TRUE); 02854 02855 if (success) 02856 { 02857 rval = 1; 02858 for(index = 0, eve = em->verts.first; eve; index++, eve = eve->next) 02859 { 02860 weightSetData(eve, nlGetVariable(0, index)); 02861 } 02862 } 02863 else 02864 { 02865 rval = 0; 02866 } 02867 02868 nlDeleteContext(nlGetCurrent()); 02869 02870 return rval; 02871 } 02872 02873 02874 EditEdge * NextEdgeForVert(EdgeIndex *indexed_edges, int index) 02875 { 02876 static int offset = -1; 02877 02878 /* Reset method, call with NULL mesh pointer */ 02879 if (index == -1) 02880 { 02881 offset = -1; 02882 return NULL; 02883 } 02884 02885 /* first pass, start at the head of the list */ 02886 if (offset == -1) 02887 { 02888 offset = indexed_edges->offset[index]; 02889 } 02890 /* subsequent passes, start on the next edge */ 02891 else 02892 { 02893 offset++; 02894 } 02895 02896 return indexed_edges->edges[offset]; 02897 } 02898 02899 static void shortestPathsFromVert(EditMesh *em, EditVert *starting_vert, EdgeIndex *indexed_edges) 02900 { 02901 Heap *edge_heap; 02902 EditVert *current_eve = NULL; 02903 EditEdge *eed = NULL; 02904 EditEdge *select_eed = NULL; 02905 02906 edge_heap = BLI_heap_new(); 02907 02908 current_eve = starting_vert; 02909 02910 /* insert guard in heap, when that is returned, no more edges */ 02911 BLI_heap_insert(edge_heap, FLT_MAX, NULL); 02912 02913 /* Initialize edge flag */ 02914 for(eed= em->edges.first; eed; eed= eed->next) 02915 { 02916 eed->f1 = 0; 02917 } 02918 02919 while (BLI_heap_size(edge_heap) > 0) 02920 { 02921 float current_weight; 02922 02923 current_eve->f1 = 1; /* mark vertex as selected */ 02924 02925 /* Add all new edges connected to current_eve to the list */ 02926 NextEdgeForVert(indexed_edges, -1); // Reset next edge 02927 for(eed = NextEdgeForVert(indexed_edges, indexData(current_eve)); eed; eed = NextEdgeForVert(indexed_edges, indexData(current_eve))) 02928 { 02929 if (eed->f1 == 0) 02930 { 02931 BLI_heap_insert(edge_heap, weightData(current_eve) + eed->tmp.fp, eed); 02932 eed->f1 = 1; 02933 } 02934 } 02935 02936 /* Find next shortest edge with unselected verts */ 02937 do 02938 { 02939 current_weight = BLI_heap_node_value(BLI_heap_top(edge_heap)); 02940 select_eed = BLI_heap_popmin(edge_heap); 02941 } while (select_eed != NULL && select_eed->v1->f1 != 0 && select_eed->v2->f1); 02942 02943 if (select_eed != NULL) 02944 { 02945 select_eed->f1 = 2; 02946 02947 if (select_eed->v1->f1 == 0) /* v1 is the new vertex */ 02948 { 02949 current_eve = select_eed->v1; 02950 } 02951 else /* otherwise, it's v2 */ 02952 { 02953 current_eve = select_eed->v2; 02954 } 02955 02956 weightSetData(current_eve, current_weight); 02957 } 02958 } 02959 02960 BLI_heap_free(edge_heap, NULL); 02961 } 02962 02963 static void freeEdgeIndex(EdgeIndex *indexed_edges) 02964 { 02965 MEM_freeN(indexed_edges->offset); 02966 MEM_freeN(indexed_edges->edges); 02967 } 02968 02969 static void buildIndexedEdges(EditMesh *em, EdgeIndex *indexed_edges) 02970 { 02971 EditVert *eve; 02972 EditEdge *eed; 02973 int totvert = 0; 02974 int tot_indexed = 0; 02975 int offset = 0; 02976 02977 totvert = BLI_countlist(&em->verts); 02978 02979 indexed_edges->offset = MEM_callocN(totvert * sizeof(int), "EdgeIndex offset"); 02980 02981 for(eed = em->edges.first; eed; eed = eed->next) 02982 { 02983 if (eed->v1->h == 0 && eed->v2->h == 0) 02984 { 02985 tot_indexed += 2; 02986 indexed_edges->offset[indexData(eed->v1)]++; 02987 indexed_edges->offset[indexData(eed->v2)]++; 02988 } 02989 } 02990 02991 tot_indexed += totvert; 02992 02993 indexed_edges->edges = MEM_callocN(tot_indexed * sizeof(EditEdge*), "EdgeIndex edges"); 02994 02995 /* setting vert offsets */ 02996 for(eve = em->verts.first; eve; eve = eve->next) 02997 { 02998 if (eve->h == 0) 02999 { 03000 int d = indexed_edges->offset[indexData(eve)]; 03001 indexed_edges->offset[indexData(eve)] = offset; 03002 offset += d + 1; 03003 } 03004 } 03005 03006 /* adding edges in array */ 03007 for(eed = em->edges.first; eed; eed= eed->next) 03008 { 03009 if (eed->v1->h == 0 && eed->v2->h == 0) 03010 { 03011 int i; 03012 for (i = indexed_edges->offset[indexData(eed->v1)]; i < tot_indexed; i++) 03013 { 03014 if (indexed_edges->edges[i] == NULL) 03015 { 03016 indexed_edges->edges[i] = eed; 03017 break; 03018 } 03019 } 03020 03021 for (i = indexed_edges->offset[indexData(eed->v2)]; i < tot_indexed; i++) 03022 { 03023 if (indexed_edges->edges[i] == NULL) 03024 { 03025 indexed_edges->edges[i] = eed; 03026 break; 03027 } 03028 } 03029 } 03030 } 03031 } 03032 03033 int weightFromDistance(EditMesh *em, EdgeIndex *indexed_edges) 03034 { 03035 EditVert *eve; 03036 int totedge = 0; 03037 int totvert = 0; 03038 int vCount = 0; 03039 03040 totvert = BLI_countlist(&em->verts); 03041 03042 if (em == NULL || totvert == 0) 03043 { 03044 return 0; 03045 } 03046 03047 totedge = BLI_countlist(&em->edges); 03048 03049 if (totedge == 0) 03050 { 03051 return 0; 03052 } 03053 03054 /* Initialize vertice flag and find at least one selected vertex */ 03055 for(eve = em->verts.first; eve; eve = eve->next) 03056 { 03057 eve->f1 = 0; 03058 if (eve->f & SELECT) 03059 { 03060 vCount = 1; 03061 } 03062 } 03063 03064 if (vCount == 0) 03065 { 03066 return 0; /* no selected vert, failure */ 03067 } 03068 else 03069 { 03070 EditEdge *eed; 03071 int allDone = 0; 03072 03073 /* Calculate edge weight */ 03074 for(eed = em->edges.first; eed; eed= eed->next) 03075 { 03076 if (eed->v1->h == 0 && eed->v2->h == 0) 03077 { 03078 eed->tmp.fp = len_v3v3(eed->v1->co, eed->v2->co); 03079 } 03080 } 03081 03082 /* Apply dijkstra spf for each selected vert */ 03083 for(eve = em->verts.first; eve; eve = eve->next) 03084 { 03085 if (eve->f & SELECT) 03086 { 03087 shortestPathsFromVert(em, eve, indexed_edges); 03088 } 03089 } 03090 03091 /* connect unselected islands */ 03092 while (allDone == 0) 03093 { 03094 EditVert *selected_eve = NULL; 03095 float selected_weight = 0; 03096 float min_distance = FLT_MAX; 03097 03098 allDone = 1; 03099 03100 for (eve = em->verts.first; eve; eve = eve->next) 03101 { 03102 /* for every vertex visible that hasn't been processed yet */ 03103 if (eve->h == 0 && eve->f1 != 1) 03104 { 03105 EditVert *closest_eve; 03106 03107 /* find the closest processed vertex */ 03108 for (closest_eve = em->verts.first; closest_eve; closest_eve = closest_eve->next) 03109 { 03110 /* vertex is already processed and distance is smaller than current minimum */ 03111 if (closest_eve->f1 == 1) 03112 { 03113 float distance = len_v3v3(closest_eve->co, eve->co); 03114 if (distance < min_distance) 03115 { 03116 min_distance = distance; 03117 selected_eve = eve; 03118 selected_weight = weightData(closest_eve); 03119 } 03120 } 03121 } 03122 } 03123 } 03124 03125 if (selected_eve) 03126 { 03127 allDone = 0; 03128 03129 weightSetData(selected_eve, selected_weight + min_distance); 03130 shortestPathsFromVert(em, selected_eve, indexed_edges); 03131 } 03132 } 03133 } 03134 03135 for(eve = em->verts.first; eve && vCount == 0; eve = eve->next) 03136 { 03137 if (eve->f1 == 0) 03138 { 03139 printf("vertex not reached\n"); 03140 break; 03141 } 03142 } 03143 03144 return 1; 03145 } 03146 03147 /****************************************** BUCKET ITERATOR **************************************************/ 03148 03149 static void* headNode(void *arg); 03150 static void* tailNode(void *arg); 03151 static void* nextBucket(void *arg); 03152 static void* nextNBucket(void *arg, int n); 03153 static void* peekBucket(void *arg, int n); 03154 static void* previousBucket(void *arg); 03155 static int iteratorStopped(void *arg); 03156 03157 static void initIteratorFct(ReebArcIterator *iter) 03158 { 03159 iter->head = headNode; 03160 iter->tail = tailNode; 03161 iter->peek = peekBucket; 03162 iter->next = nextBucket; 03163 iter->nextN = nextNBucket; 03164 iter->previous = previousBucket; 03165 iter->stopped = iteratorStopped; 03166 } 03167 03168 static void setIteratorValues(ReebArcIterator *iter, EmbedBucket *bucket) 03169 { 03170 if (bucket) 03171 { 03172 iter->p = bucket->p; 03173 iter->no = bucket->no; 03174 } 03175 else 03176 { 03177 iter->p = NULL; 03178 iter->no = NULL; 03179 } 03180 iter->size = 0; 03181 } 03182 03183 void initArcIterator(BArcIterator *arg, ReebArc *arc, ReebNode *head) 03184 { 03185 ReebArcIterator *iter = (ReebArcIterator*)arg; 03186 03187 initIteratorFct(iter); 03188 iter->arc = arc; 03189 03190 if (head == arc->head) 03191 { 03192 iter->start = 0; 03193 iter->end = arc->bcount - 1; 03194 iter->stride = 1; 03195 } 03196 else 03197 { 03198 iter->start = arc->bcount - 1; 03199 iter->end = 0; 03200 iter->stride = -1; 03201 } 03202 03203 iter->length = arc->bcount; 03204 03205 iter->index = -1; 03206 } 03207 03208 void initArcIteratorStart(BArcIterator *arg, struct ReebArc *arc, struct ReebNode *head, int start) 03209 { 03210 ReebArcIterator *iter = (ReebArcIterator*)arg; 03211 03212 initIteratorFct(iter); 03213 iter->arc = arc; 03214 03215 if (head == arc->head) 03216 { 03217 iter->start = start; 03218 iter->end = arc->bcount - 1; 03219 iter->stride = 1; 03220 } 03221 else 03222 { 03223 iter->start = arc->bcount - 1 - start; 03224 iter->end = 0; 03225 iter->stride = -1; 03226 } 03227 03228 iter->index = -1; 03229 03230 iter->length = arc->bcount - start; 03231 03232 if (start >= arc->bcount) 03233 { 03234 iter->start = iter->end; /* stop iterator since it's past its end */ 03235 } 03236 } 03237 03238 void initArcIterator2(BArcIterator *arg, ReebArc *arc, int start, int end) 03239 { 03240 ReebArcIterator *iter = (ReebArcIterator*)arg; 03241 03242 initIteratorFct(iter); 03243 iter->arc = arc; 03244 03245 iter->start = start; 03246 iter->end = end; 03247 03248 if (end > start) 03249 { 03250 iter->stride = 1; 03251 } 03252 else 03253 { 03254 iter->stride = -1; 03255 } 03256 03257 iter->index = -1; 03258 03259 iter->length = abs(iter->end - iter->start) + 1; 03260 } 03261 03262 static void* headNode(void *arg) 03263 { 03264 ReebArcIterator *iter = (ReebArcIterator*)arg; 03265 ReebNode *node; 03266 03267 if (iter->start < iter->end) 03268 { 03269 node = iter->arc->head; 03270 } 03271 else 03272 { 03273 node = iter->arc->tail; 03274 } 03275 03276 iter->p = node->p; 03277 iter->no = node->no; 03278 iter->size = 0; 03279 03280 return node; 03281 } 03282 03283 static void* tailNode(void *arg) 03284 { 03285 ReebArcIterator *iter = (ReebArcIterator*)arg; 03286 ReebNode *node; 03287 03288 if (iter->start < iter->end) 03289 { 03290 node = iter->arc->tail; 03291 } 03292 else 03293 { 03294 node = iter->arc->head; 03295 } 03296 03297 iter->p = node->p; 03298 iter->no = node->no; 03299 iter->size = 0; 03300 03301 return node; 03302 } 03303 03304 static void* nextBucket(void *arg) 03305 { 03306 ReebArcIterator *iter = (ReebArcIterator*)arg; 03307 EmbedBucket *result = NULL; 03308 03309 iter->index++; 03310 03311 if (iter->index < iter->length) 03312 { 03313 result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]); 03314 } 03315 03316 setIteratorValues(iter, result); 03317 return result; 03318 } 03319 03320 static void* nextNBucket(void *arg, int n) 03321 { 03322 ReebArcIterator *iter = (ReebArcIterator*)arg; 03323 EmbedBucket *result = NULL; 03324 03325 iter->index += n; 03326 03327 /* check if passed end */ 03328 if (iter->index < iter->length) 03329 { 03330 result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]); 03331 } 03332 03333 setIteratorValues(iter, result); 03334 return result; 03335 } 03336 03337 static void* peekBucket(void *arg, int n) 03338 { 03339 ReebArcIterator *iter = (ReebArcIterator*)arg; 03340 EmbedBucket *result = NULL; 03341 int index = iter->index + n; 03342 03343 /* check if passed end */ 03344 if (index < iter->length) 03345 { 03346 result = &(iter->arc->buckets[iter->start + (iter->stride * index)]); 03347 } 03348 03349 setIteratorValues(iter, result); 03350 return result; 03351 } 03352 03353 static void* previousBucket(void *arg) 03354 { 03355 ReebArcIterator *iter = (ReebArcIterator*)arg; 03356 EmbedBucket *result = NULL; 03357 03358 if (iter->index > 0) 03359 { 03360 iter->index--; 03361 result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]); 03362 } 03363 03364 setIteratorValues(iter, result); 03365 return result; 03366 } 03367 03368 static int iteratorStopped(void *arg) 03369 { 03370 ReebArcIterator *iter = (ReebArcIterator*)arg; 03371 03372 if (iter->index >= iter->length) 03373 { 03374 return 1; 03375 } 03376 else 03377 { 03378 return 0; 03379 } 03380 } 03381 03382 /************************ PUBLIC FUNCTIONS *********************************************/ 03383 03384 ReebGraph *BIF_ReebGraphMultiFromEditMesh(bContext *C) 03385 { 03386 Scene *scene = CTX_data_scene(C); 03387 Object *obedit = CTX_data_edit_object(C); 03388 EditMesh *em =( (Mesh*)obedit->data)->edit_mesh; 03389 EdgeIndex indexed_edges; 03390 VertexData *data; 03391 ReebGraph *rg = NULL; 03392 ReebGraph *rgi, *previous; 03393 int i, nb_levels = REEB_MAX_MULTI_LEVEL; 03394 03395 if (em == NULL) 03396 return NULL; 03397 03398 data = allocVertexData(em); 03399 03400 buildIndexedEdges(em, &indexed_edges); 03401 03402 if (weightFromDistance(em, &indexed_edges) == 0) 03403 { 03404 // XXX error("No selected vertex\n"); 03405 freeEdgeIndex(&indexed_edges); 03406 return NULL; 03407 } 03408 03409 renormalizeWeight(em, 1.0f); 03410 03411 if (scene->toolsettings->skgen_options & SKGEN_HARMONIC) 03412 { 03413 weightToHarmonic(em, &indexed_edges); 03414 } 03415 03416 freeEdgeIndex(&indexed_edges); 03417 03418 rg = generateReebGraph(em, scene->toolsettings->skgen_resolution); 03419 03420 /* Remove arcs without embedding */ 03421 filterNullReebGraph(rg); 03422 03423 /* smart filter and loop filter on basic level */ 03424 filterGraph(rg, SKGEN_FILTER_SMART, 0, 0); 03425 03426 repositionNodes(rg); 03427 03428 /* Filtering might have created degree 2 nodes, so remove them */ 03429 removeNormalNodes(rg); 03430 03431 joinSubgraphs(rg, 1.0); 03432 03433 BLI_buildAdjacencyList((BGraph*)rg); 03434 03435 /* calc length before copy, so we have same length on all levels */ 03436 BLI_calcGraphLength((BGraph*)rg); 03437 03438 previous = NULL; 03439 for (i = 0; i <= nb_levels; i++) 03440 { 03441 rgi = rg; 03442 03443 /* don't filter last level */ 03444 if (i > 0) 03445 { 03446 float internal_threshold; 03447 float external_threshold; 03448 03449 /* filter internal progressively in second half only*/ 03450 if (i > nb_levels / 2) 03451 { 03452 internal_threshold = rg->length * scene->toolsettings->skgen_threshold_internal; 03453 } 03454 else 03455 { 03456 internal_threshold = rg->length * scene->toolsettings->skgen_threshold_internal * (2 * i / (float)nb_levels); 03457 } 03458 03459 external_threshold = rg->length * scene->toolsettings->skgen_threshold_external * (i / (float)nb_levels); 03460 03461 filterGraph(rgi, scene->toolsettings->skgen_options, internal_threshold, external_threshold); 03462 } 03463 03464 if (i < nb_levels) 03465 { 03466 rg = copyReebGraph(rgi, i + 1); 03467 } 03468 03469 finalizeGraph(rgi, scene->toolsettings->skgen_postpro_passes, scene->toolsettings->skgen_postpro); 03470 03471 BLI_markdownSymmetry((BGraph*)rgi, rgi->nodes.first, scene->toolsettings->skgen_symmetry_limit); 03472 03473 if (previous != NULL) 03474 { 03475 relinkNodes(rgi, previous); 03476 } 03477 previous = rgi; 03478 } 03479 03480 verifyMultiResolutionLinks(rg, 0); 03481 03482 MEM_freeN(data); 03483 03484 return rg; 03485 } 03486 03487 #if 0 03488 03489 ReebGraph *BIF_ReebGraphFromEditMesh(void) 03490 { 03491 EditMesh *em = G.editMesh; 03492 EdgeIndex indexed_edges; 03493 VertexData *data; 03494 ReebGraph *rg = NULL; 03495 03496 if (em == NULL) 03497 return NULL; 03498 03499 data = allocVertexData(em); 03500 03501 buildIndexedEdges(em, &indexed_edges); 03502 03503 if (weightFromDistance(em, &indexed_edges) == 0) 03504 { 03505 error("No selected vertex\n"); 03506 freeEdgeIndex(&indexed_edges); 03507 freeEdgeIndex(&indexed_edges); 03508 return NULL; 03509 } 03510 03511 renormalizeWeight(em, 1.0f); 03512 03513 if (G.scene->toolsettings->skgen_options & SKGEN_HARMONIC) 03514 { 03515 weightToHarmonic(em, &indexed_edges); 03516 } 03517 03518 freeEdgeIndex(&indexed_edges); 03519 03520 #ifdef DEBUG_REEB 03521 weightToVCol(em, 1); 03522 #endif 03523 03524 rg = generateReebGraph(em, G.scene->toolsettings->skgen_resolution); 03525 03526 03527 /* Remove arcs without embedding */ 03528 filterNullReebGraph(rg); 03529 03530 /* smart filter and loop filter on basic level */ 03531 filterGraph(rg, SKGEN_FILTER_SMART, 0, 0); 03532 03533 repositionNodes(rg); 03534 03535 /* Filtering might have created degree 2 nodes, so remove them */ 03536 removeNormalNodes(rg); 03537 03538 joinSubgraphs(rg, 1.0); 03539 03540 BLI_buildAdjacencyList((BGraph*)rg); 03541 03542 /* calc length before copy, so we have same length on all levels */ 03543 BLI_calcGraphLength((BGraph*)rg); 03544 03545 filterGraph(rg, G.scene->toolsettings->skgen_options, G.scene->toolsettings->skgen_threshold_internal, G.scene->toolsettings->skgen_threshold_external); 03546 03547 finalizeGraph(rg, G.scene->toolsettings->skgen_postpro_passes, G.scene->toolsettings->skgen_postpro); 03548 03549 #ifdef DEBUG_REEB 03550 REEB_exportGraph(rg, -1); 03551 03552 arcToVCol(rg, em, 0); 03553 //angleToVCol(em, 1); 03554 #endif 03555 03556 printf("DONE\n"); 03557 printf("%i subgraphs\n", BLI_FlagSubgraphs((BGraph*)rg)); 03558 03559 MEM_freeN(data); 03560 03561 return rg; 03562 } 03563 03564 void BIF_GlobalReebFree() 03565 { 03566 if (GLOBAL_RG != NULL) 03567 { 03568 REEB_freeGraph(GLOBAL_RG); 03569 GLOBAL_RG = NULL; 03570 } 03571 } 03572 03573 void BIF_GlobalReebGraphFromEditMesh(void) 03574 { 03575 ReebGraph *rg; 03576 03577 BIF_GlobalReebFree(); 03578 03579 rg = BIF_ReebGraphMultiFromEditMesh(); 03580 03581 GLOBAL_RG = rg; 03582 } 03583 03584 void REEB_draw() 03585 { 03586 ReebGraph *rg; 03587 ReebArc *arc; 03588 int i = 0; 03589 03590 if (GLOBAL_RG == NULL) 03591 { 03592 return; 03593 } 03594 03595 if (GLOBAL_RG->link_up && G.scene->toolsettings->skgen_options & SKGEN_DISP_ORIG) 03596 { 03597 for (rg = GLOBAL_RG; rg->link_up; rg = rg->link_up) ; 03598 } 03599 else 03600 { 03601 i = G.scene->toolsettings->skgen_multi_level; 03602 03603 for (rg = GLOBAL_RG; rg->multi_level != i && rg->link_up; rg = rg->link_up) ; 03604 } 03605 03606 glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE)); 03607 03608 glDisable(GL_DEPTH_TEST); 03609 for (arc = rg->arcs.first; arc; arc = arc->next, i++) 03610 { 03611 ReebArcIterator arc_iter; 03612 BArcIterator *iter = (BArcIterator*)&arc_iter; 03613 float vec[3]; 03614 char text[128]; 03615 char *s = text; 03616 03617 glLineWidth(BIF_GetThemeValuef(TH_VERTEX_SIZE) + 2); 03618 glColor3f(0, 0, 0); 03619 glBegin(GL_LINE_STRIP); 03620 glVertex3fv(arc->head->p); 03621 03622 if (arc->bcount) 03623 { 03624 initArcIterator(iter, arc, arc->head); 03625 for (IT_next(iter); IT_stopped(iter) == 0; IT_next(iter)) 03626 { 03627 glVertex3fv(iter->p); 03628 } 03629 } 03630 03631 glVertex3fv(arc->tail->p); 03632 glEnd(); 03633 03634 glLineWidth(BIF_GetThemeValuef(TH_VERTEX_SIZE)); 03635 03636 if (arc->symmetry_level == 1) 03637 { 03638 glColor3f(1, 0, 0); 03639 } 03640 else if (arc->symmetry_flag == SYM_SIDE_POSITIVE || arc->symmetry_flag == SYM_SIDE_NEGATIVE) 03641 { 03642 glColor3f(1, 0.5f, 0); 03643 } 03644 else if (arc->symmetry_flag >= SYM_SIDE_RADIAL) 03645 { 03646 glColor3f(0.5f, 1, 0); 03647 } 03648 else 03649 { 03650 glColor3f(1, 1, 0); 03651 } 03652 glBegin(GL_LINE_STRIP); 03653 glVertex3fv(arc->head->p); 03654 03655 if (arc->bcount) 03656 { 03657 initArcIterator(iter, arc, arc->head); 03658 for (iter->next(iter); IT_stopped(iter) == 0; iter->next(iter)) 03659 { 03660 glVertex3fv(iter->p); 03661 } 03662 } 03663 03664 glVertex3fv(arc->tail->p); 03665 glEnd(); 03666 03667 03668 if (G.scene->toolsettings->skgen_options & SKGEN_DISP_EMBED) 03669 { 03670 glColor3f(1, 1, 1); 03671 glBegin(GL_POINTS); 03672 glVertex3fv(arc->head->p); 03673 glVertex3fv(arc->tail->p); 03674 03675 glColor3f(0.5f, 0.5f, 1); 03676 if (arc->bcount) 03677 { 03678 initArcIterator(iter, arc, arc->head); 03679 for (iter->next(iter); IT_stopped(iter) == 0; iter->next(iter)) 03680 { 03681 glVertex3fv(iter->p); 03682 } 03683 } 03684 glEnd(); 03685 } 03686 03687 if (G.scene->toolsettings->skgen_options & SKGEN_DISP_INDEX) 03688 { 03689 interp_v3_v3v3(vec, arc->head->p, arc->tail->p, 0.5f); 03690 s += sprintf(s, "%i (%i-%i-%i) ", i, arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group); 03691 03692 if (G.scene->toolsettings->skgen_options & SKGEN_DISP_WEIGHT) 03693 { 03694 s += sprintf(s, "w:%0.3f ", arc->tail->weight - arc->head->weight); 03695 } 03696 03697 if (G.scene->toolsettings->skgen_options & SKGEN_DISP_LENGTH) 03698 { 03699 s += sprintf(s, "l:%0.3f", arc->length); 03700 } 03701 03702 glColor3f(0, 1, 0); 03703 glRasterPos3fv(vec); 03704 BMF_DrawString( G.fonts, text); 03705 } 03706 03707 if (G.scene->toolsettings->skgen_options & SKGEN_DISP_INDEX) 03708 { 03709 sprintf(text, " %i", arc->head->index); 03710 glRasterPos3fv(arc->head->p); 03711 BMF_DrawString( G.fonts, text); 03712 03713 sprintf(text, " %i", arc->tail->index); 03714 glRasterPos3fv(arc->tail->p); 03715 BMF_DrawString( G.fonts, text); 03716 } 03717 } 03718 glEnable(GL_DEPTH_TEST); 03719 03720 glLineWidth(1.0); 03721 glPointSize(1.0); 03722 } 03723 03724 #endif