Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * Contributor(s): Martin Poirier 00019 * 00020 * ***** END GPL LICENSE BLOCK ***** 00021 * graph.c: Common graph interface and methods 00022 */ 00023 00029 #include <float.h> 00030 #include <math.h> 00031 00032 #include "MEM_guardedalloc.h" 00033 00034 #include "BLI_graph.h" 00035 #include "BLI_blenlib.h" 00036 #include "BLI_math.h" 00037 #include "BLI_utildefines.h" 00038 00039 00040 00041 static void testRadialSymmetry(BGraph *graph, BNode* root_node, RadialArc* ring, int total, float axis[3], float limit, int group); 00042 00043 static void handleAxialSymmetry(BGraph *graph, BNode *root_node, int depth, float axis[3], float limit); 00044 static void testAxialSymmetry(BGraph *graph, BNode* root_node, BNode* node1, BNode* node2, BArc* arc1, BArc* arc2, float axis[3], float limit, int group); 00045 static void flagAxialSymmetry(BNode *root_node, BNode *end_node, BArc *arc, int group); 00046 00047 void BLI_freeNode(BGraph *graph, BNode *node) 00048 { 00049 if (node->arcs) 00050 { 00051 MEM_freeN(node->arcs); 00052 } 00053 00054 if (graph->free_node) 00055 { 00056 graph->free_node(node); 00057 } 00058 } 00059 00060 void BLI_removeNode(BGraph *graph, BNode *node) 00061 { 00062 BLI_freeNode(graph, node); 00063 BLI_freelinkN(&graph->nodes, node); 00064 } 00065 00066 BNode *BLI_otherNode(BArc *arc, BNode *node) 00067 { 00068 return (arc->head == node) ? arc->tail : arc->head; 00069 } 00070 00071 void BLI_removeArc(BGraph *graph, BArc *arc) 00072 { 00073 if (graph->free_arc) 00074 { 00075 graph->free_arc(arc); 00076 } 00077 00078 BLI_freelinkN(&graph->arcs, arc); 00079 } 00080 00081 void BLI_flagNodes(BGraph *graph, int flag) 00082 { 00083 BNode *node; 00084 00085 for(node = graph->nodes.first; node; node = node->next) 00086 { 00087 node->flag = flag; 00088 } 00089 } 00090 00091 void BLI_flagArcs(BGraph *graph, int flag) 00092 { 00093 BArc *arc; 00094 00095 for(arc = graph->arcs.first; arc; arc = arc->next) 00096 { 00097 arc->flag = flag; 00098 } 00099 } 00100 00101 static void addArcToNodeAdjacencyList(BNode *node, BArc *arc) 00102 { 00103 node->arcs[node->flag] = arc; 00104 node->flag++; 00105 } 00106 00107 void BLI_buildAdjacencyList(BGraph *graph) 00108 { 00109 BNode *node; 00110 BArc *arc; 00111 00112 for(node = graph->nodes.first; node; node = node->next) 00113 { 00114 if (node->arcs != NULL) 00115 { 00116 MEM_freeN(node->arcs); 00117 } 00118 00119 node->arcs = MEM_callocN((node->degree) * sizeof(BArc*), "adjacency list"); 00120 00121 /* temporary use to indicate the first index available in the lists */ 00122 node->flag = 0; 00123 } 00124 00125 for(arc = graph->arcs.first; arc; arc= arc->next) 00126 { 00127 addArcToNodeAdjacencyList(arc->head, arc); 00128 addArcToNodeAdjacencyList(arc->tail, arc); 00129 } 00130 00131 for(node = graph->nodes.first; node; node = node->next) 00132 { 00133 if (node->degree != node->flag) 00134 { 00135 printf("error in node [%p]. Added only %i arcs out of %i\n", (void *)node, node->flag, node->degree); 00136 } 00137 } 00138 } 00139 00140 void BLI_rebuildAdjacencyListForNode(BGraph* graph, BNode *node) 00141 { 00142 BArc *arc; 00143 00144 if (node->arcs != NULL) 00145 { 00146 MEM_freeN(node->arcs); 00147 } 00148 00149 node->arcs = MEM_callocN((node->degree) * sizeof(BArc*), "adjacency list"); 00150 00151 /* temporary use to indicate the first index available in the lists */ 00152 node->flag = 0; 00153 00154 for(arc = graph->arcs.first; arc; arc= arc->next) 00155 { 00156 if (arc->head == node) 00157 { 00158 addArcToNodeAdjacencyList(arc->head, arc); 00159 } 00160 else if (arc->tail == node) 00161 { 00162 addArcToNodeAdjacencyList(arc->tail, arc); 00163 } 00164 } 00165 00166 if (node->degree != node->flag) 00167 { 00168 printf("error in node [%p]. Added only %i arcs out of %i\n", (void *)node, node->flag, node->degree); 00169 } 00170 } 00171 00172 void BLI_freeAdjacencyList(BGraph *graph) 00173 { 00174 BNode *node; 00175 00176 for(node = graph->nodes.first; node; node = node->next) 00177 { 00178 if (node->arcs != NULL) 00179 { 00180 MEM_freeN(node->arcs); 00181 node->arcs = NULL; 00182 } 00183 } 00184 } 00185 00186 int BLI_hasAdjacencyList(BGraph *graph) 00187 { 00188 BNode *node; 00189 00190 for(node = graph->nodes.first; node; node = node->next) 00191 { 00192 if (node->arcs == NULL) 00193 { 00194 return 0; 00195 } 00196 } 00197 00198 return 1; 00199 } 00200 00201 void BLI_replaceNodeInArc(BGraph *graph, BArc *arc, BNode *node_src, BNode *node_replaced) 00202 { 00203 if (arc->head == node_replaced) 00204 { 00205 arc->head = node_src; 00206 node_src->degree++; 00207 } 00208 00209 if (arc->tail == node_replaced) 00210 { 00211 arc->tail = node_src; 00212 node_src->degree++; 00213 } 00214 00215 if (arc->head == arc->tail) 00216 { 00217 node_src->degree -= 2; 00218 00219 graph->free_arc(arc); 00220 BLI_freelinkN(&graph->arcs, arc); 00221 } 00222 00223 if (node_replaced->degree == 0) 00224 { 00225 BLI_removeNode(graph, node_replaced); 00226 } 00227 } 00228 00229 void BLI_replaceNode(BGraph *graph, BNode *node_src, BNode *node_replaced) 00230 { 00231 BArc *arc, *next_arc; 00232 00233 for (arc = graph->arcs.first; arc; arc = next_arc) 00234 { 00235 next_arc = arc->next; 00236 00237 if (arc->head == node_replaced) 00238 { 00239 arc->head = node_src; 00240 node_replaced->degree--; 00241 node_src->degree++; 00242 } 00243 00244 if (arc->tail == node_replaced) 00245 { 00246 arc->tail = node_src; 00247 node_replaced->degree--; 00248 node_src->degree++; 00249 } 00250 00251 if (arc->head == arc->tail) 00252 { 00253 node_src->degree -= 2; 00254 00255 graph->free_arc(arc); 00256 BLI_freelinkN(&graph->arcs, arc); 00257 } 00258 } 00259 00260 if (node_replaced->degree == 0) 00261 { 00262 BLI_removeNode(graph, node_replaced); 00263 } 00264 } 00265 00266 void BLI_removeDoubleNodes(BGraph *graph, float limit) 00267 { 00268 BNode *node_src, *node_replaced; 00269 00270 for(node_src = graph->nodes.first; node_src; node_src = node_src->next) 00271 { 00272 for(node_replaced = graph->nodes.first; node_replaced; node_replaced = node_replaced->next) 00273 { 00274 if (node_replaced != node_src && len_v3v3(node_replaced->p, node_src->p) <= limit) 00275 { 00276 BLI_replaceNode(graph, node_src, node_replaced); 00277 } 00278 } 00279 } 00280 00281 } 00282 00283 BNode * BLI_FindNodeByPosition(BGraph *graph, float *p, float limit) 00284 { 00285 BNode *closest_node = NULL, *node; 00286 float min_distance = 0.0f; 00287 00288 for(node = graph->nodes.first; node; node = node->next) 00289 { 00290 float distance = len_v3v3(p, node->p); 00291 if (distance <= limit && (closest_node == NULL || distance < min_distance)) 00292 { 00293 closest_node = node; 00294 min_distance = distance; 00295 } 00296 } 00297 00298 return closest_node; 00299 } 00300 /************************************* SUBGRAPH DETECTION **********************************************/ 00301 00302 static void flagSubgraph(BNode *node, int subgraph) 00303 { 00304 if (node->subgraph_index == 0) 00305 { 00306 BArc *arc; 00307 int i; 00308 00309 node->subgraph_index = subgraph; 00310 00311 for(i = 0; i < node->degree; i++) 00312 { 00313 arc = node->arcs[i]; 00314 flagSubgraph(BLI_otherNode(arc, node), subgraph); 00315 } 00316 } 00317 } 00318 00319 int BLI_FlagSubgraphs(BGraph *graph) 00320 { 00321 BNode *node; 00322 int subgraph = 0; 00323 00324 if (BLI_hasAdjacencyList(graph) == 0) 00325 { 00326 BLI_buildAdjacencyList(graph); 00327 } 00328 00329 for(node = graph->nodes.first; node; node = node->next) 00330 { 00331 node->subgraph_index = 0; 00332 } 00333 00334 for (node = graph->nodes.first; node; node = node->next) 00335 { 00336 if (node->subgraph_index == 0) 00337 { 00338 subgraph++; 00339 flagSubgraph(node, subgraph); 00340 } 00341 } 00342 00343 return subgraph; 00344 } 00345 00346 void BLI_ReflagSubgraph(BGraph *graph, int old_subgraph, int new_subgraph) 00347 { 00348 BNode *node; 00349 00350 for (node = graph->nodes.first; node; node = node->next) 00351 { 00352 if (node->flag == old_subgraph) 00353 { 00354 node->flag = new_subgraph; 00355 } 00356 } 00357 } 00358 00359 /*************************************** CYCLE DETECTION ***********************************************/ 00360 00361 static int detectCycle(BNode *node, BArc *src_arc) 00362 { 00363 int value = 0; 00364 00365 if (node->flag == 0) 00366 { 00367 int i; 00368 00369 /* mark node as visited */ 00370 node->flag = 1; 00371 00372 for(i = 0; i < node->degree && value == 0; i++) 00373 { 00374 BArc *arc = node->arcs[i]; 00375 00376 /* don't go back on the source arc */ 00377 if (arc != src_arc) 00378 { 00379 value = detectCycle(BLI_otherNode(arc, node), arc); 00380 } 00381 } 00382 } 00383 else 00384 { 00385 value = 1; 00386 } 00387 00388 return value; 00389 } 00390 00391 int BLI_isGraphCyclic(BGraph *graph) 00392 { 00393 BNode *node; 00394 int value = 0; 00395 00396 /* NEED TO CHECK IF ADJACENCY LIST EXIST */ 00397 00398 /* Mark all nodes as not visited */ 00399 BLI_flagNodes(graph, 0); 00400 00401 /* detectCycles in subgraphs */ 00402 for(node = graph->nodes.first; node && value == 0; node = node->next) 00403 { 00404 /* only for nodes in subgraphs that haven't been visited yet */ 00405 if (node->flag == 0) 00406 { 00407 value = value || detectCycle(node, NULL); 00408 } 00409 } 00410 00411 return value; 00412 } 00413 00414 BArc * BLI_findConnectedArc(BGraph *graph, BArc *arc, BNode *v) 00415 { 00416 BArc *nextArc; 00417 00418 for(nextArc = graph->arcs.first; nextArc; nextArc = nextArc->next) 00419 { 00420 if (arc != nextArc && (nextArc->head == v || nextArc->tail == v)) 00421 { 00422 break; 00423 } 00424 } 00425 00426 return nextArc; 00427 } 00428 00429 /*********************************** GRAPH AS TREE FUNCTIONS *******************************************/ 00430 00431 static int subtreeShape(BNode *node, BArc *rootArc, int include_root) 00432 { 00433 int depth = 0; 00434 00435 node->flag = 1; 00436 00437 if (include_root) 00438 { 00439 BNode *newNode = BLI_otherNode(rootArc, node); 00440 return subtreeShape(newNode, rootArc, 0); 00441 } 00442 else 00443 { 00444 /* Base case, no arcs leading away */ 00445 if (node->arcs == NULL || *(node->arcs) == NULL) 00446 { 00447 return 0; 00448 } 00449 else 00450 { 00451 int i; 00452 00453 for(i = 0; i < node->degree; i++) 00454 { 00455 BArc *arc = node->arcs[i]; 00456 BNode *newNode = BLI_otherNode(arc, node); 00457 00458 /* stop immediate and cyclic backtracking */ 00459 if (arc != rootArc && newNode->flag == 0) 00460 { 00461 depth += subtreeShape(newNode, arc, 0); 00462 } 00463 } 00464 } 00465 00466 return SHAPE_RADIX * depth + 1; 00467 } 00468 } 00469 00470 int BLI_subtreeShape(BGraph *graph, BNode *node, BArc *rootArc, int include_root) 00471 { 00472 BLI_flagNodes(graph, 0); 00473 return subtreeShape(node, rootArc, include_root); 00474 } 00475 00476 float BLI_subtreeLength(BNode *node) 00477 { 00478 float length = 0; 00479 int i; 00480 00481 node->flag = 0; /* flag node as visited */ 00482 00483 for(i = 0; i < node->degree; i++) 00484 { 00485 BArc *arc = node->arcs[i]; 00486 BNode *other_node = BLI_otherNode(arc, node); 00487 00488 if (other_node->flag != 0) 00489 { 00490 float subgraph_length = arc->length + BLI_subtreeLength(other_node); 00491 length = MAX2(length, subgraph_length); 00492 } 00493 } 00494 00495 return length; 00496 } 00497 00498 void BLI_calcGraphLength(BGraph *graph) 00499 { 00500 float length = 0; 00501 int nb_subgraphs; 00502 int i; 00503 00504 nb_subgraphs = BLI_FlagSubgraphs(graph); 00505 00506 for (i = 1; i <= nb_subgraphs; i++) 00507 { 00508 BNode *node; 00509 00510 for (node = graph->nodes.first; node; node = node->next) 00511 { 00512 /* start on an external node of the subgraph */ 00513 if (node->subgraph_index == i && node->degree == 1) 00514 { 00515 float subgraph_length = BLI_subtreeLength(node); 00516 length = MAX2(length, subgraph_length); 00517 break; 00518 } 00519 } 00520 } 00521 00522 graph->length = length; 00523 } 00524 00525 /********************************* SYMMETRY DETECTION **************************************************/ 00526 00527 static void markdownSymmetryArc(BGraph *graph, BArc *arc, BNode *node, int level, float limit); 00528 00529 void BLI_mirrorAlongAxis(float v[3], float center[3], float axis[3]) 00530 { 00531 float dv[3], pv[3]; 00532 00533 sub_v3_v3v3(dv, v, center); 00534 project_v3_v3v3(pv, dv, axis); 00535 mul_v3_fl(pv, -2); 00536 add_v3_v3(v, pv); 00537 } 00538 00539 static void testRadialSymmetry(BGraph *graph, BNode* root_node, RadialArc* ring, int total, float axis[3], float limit, int group) 00540 { 00541 int symmetric = 1; 00542 int i; 00543 00544 /* sort ring by angle */ 00545 for (i = 0; i < total - 1; i++) 00546 { 00547 float minAngle = FLT_MAX; 00548 int minIndex = -1; 00549 int j; 00550 00551 for (j = i + 1; j < total; j++) 00552 { 00553 float angle = dot_v3v3(ring[i].n, ring[j].n); 00554 00555 /* map negative values to 1..2 */ 00556 if (angle < 0) 00557 { 00558 angle = 1 - angle; 00559 } 00560 00561 if (angle < minAngle) 00562 { 00563 minIndex = j; 00564 minAngle = angle; 00565 } 00566 } 00567 00568 /* swap if needed */ 00569 if (minIndex != i + 1) 00570 { 00571 RadialArc tmp; 00572 tmp = ring[i + 1]; 00573 ring[i + 1] = ring[minIndex]; 00574 ring[minIndex] = tmp; 00575 } 00576 } 00577 00578 for (i = 0; i < total && symmetric; i++) 00579 { 00580 BNode *node1, *node2; 00581 float tangent[3]; 00582 float normal[3]; 00583 float p[3]; 00584 int j = (i + 1) % total; /* next arc in the circular list */ 00585 00586 add_v3_v3v3(tangent, ring[i].n, ring[j].n); 00587 cross_v3_v3v3(normal, tangent, axis); 00588 00589 node1 = BLI_otherNode(ring[i].arc, root_node); 00590 node2 = BLI_otherNode(ring[j].arc, root_node); 00591 00592 copy_v3_v3(p, node2->p); 00593 BLI_mirrorAlongAxis(p, root_node->p, normal); 00594 00595 /* check if it's within limit before continuing */ 00596 if (len_v3v3(node1->p, p) > limit) 00597 { 00598 symmetric = 0; 00599 } 00600 00601 } 00602 00603 if (symmetric) 00604 { 00605 /* mark node as symmetric physically */ 00606 copy_v3_v3(root_node->symmetry_axis, axis); 00607 root_node->symmetry_flag |= SYM_PHYSICAL; 00608 root_node->symmetry_flag |= SYM_RADIAL; 00609 00610 /* FLAG SYMMETRY GROUP */ 00611 for (i = 0; i < total; i++) 00612 { 00613 ring[i].arc->symmetry_group = group; 00614 ring[i].arc->symmetry_flag = SYM_SIDE_RADIAL + i; 00615 } 00616 00617 if (graph->radial_symmetry) 00618 { 00619 graph->radial_symmetry(root_node, ring, total); 00620 } 00621 } 00622 } 00623 00624 static void handleRadialSymmetry(BGraph *graph, BNode *root_node, int depth, float axis[3], float limit) 00625 { 00626 RadialArc *ring = NULL; 00627 RadialArc *unit; 00628 int total = 0; 00629 int group; 00630 int first; 00631 int i; 00632 00633 /* mark topological symmetry */ 00634 root_node->symmetry_flag |= SYM_TOPOLOGICAL; 00635 00636 /* total the number of arcs in the symmetry ring */ 00637 for (i = 0; i < root_node->degree; i++) 00638 { 00639 BArc *connectedArc = root_node->arcs[i]; 00640 00641 /* depth is store as a negative in flag. symmetry level is positive */ 00642 if (connectedArc->symmetry_level == -depth) 00643 { 00644 total++; 00645 } 00646 } 00647 00648 ring = MEM_callocN(sizeof(RadialArc) * total, "radial symmetry ring"); 00649 unit = ring; 00650 00651 /* fill in the ring */ 00652 for (unit = ring, i = 0; i < root_node->degree; i++) 00653 { 00654 BArc *connectedArc = root_node->arcs[i]; 00655 00656 /* depth is store as a negative in flag. symmetry level is positive */ 00657 if (connectedArc->symmetry_level == -depth) 00658 { 00659 BNode *otherNode = BLI_otherNode(connectedArc, root_node); 00660 float vec[3]; 00661 00662 unit->arc = connectedArc; 00663 00664 /* project the node to node vector on the symmetry plane */ 00665 sub_v3_v3v3(unit->n, otherNode->p, root_node->p); 00666 project_v3_v3v3(vec, unit->n, axis); 00667 sub_v3_v3v3(unit->n, unit->n, vec); 00668 00669 normalize_v3(unit->n); 00670 00671 unit++; 00672 } 00673 } 00674 00675 /* sort ring by arc length 00676 * using a rather bogus insertion sort 00677 * butrings will never get too big to matter 00678 * */ 00679 for (i = 0; i < total; i++) 00680 { 00681 int j; 00682 00683 for (j = i - 1; j >= 0; j--) 00684 { 00685 BArc *arc1, *arc2; 00686 00687 arc1 = ring[j].arc; 00688 arc2 = ring[j + 1].arc; 00689 00690 if (arc1->length > arc2->length) 00691 { 00692 /* swap with smaller */ 00693 RadialArc tmp; 00694 00695 tmp = ring[j + 1]; 00696 ring[j + 1] = ring[j]; 00697 ring[j] = tmp; 00698 } 00699 else 00700 { 00701 break; 00702 } 00703 } 00704 } 00705 00706 /* Dispatch to specific symmetry tests */ 00707 first = 0; 00708 group = 0; 00709 00710 for (i = 1; i < total; i++) 00711 { 00712 int dispatch = 0; 00713 int last = i - 1; 00714 00715 if (fabsf(ring[first].arc->length - ring[i].arc->length) > limit) 00716 { 00717 dispatch = 1; 00718 } 00719 00720 /* if not dispatching already and on last arc 00721 * Dispatch using current arc as last 00722 * */ 00723 if (dispatch == 0 && i == total - 1) 00724 { 00725 last = i; 00726 dispatch = 1; 00727 } 00728 00729 if (dispatch) 00730 { 00731 int sub_total = last - first + 1; 00732 00733 group += 1; 00734 00735 if (sub_total == 1) 00736 { 00737 group -= 1; /* not really a group so decrement */ 00738 /* NOTHING TO DO */ 00739 } 00740 else if (sub_total == 2) 00741 { 00742 BArc *arc1, *arc2; 00743 BNode *node1, *node2; 00744 00745 arc1 = ring[first].arc; 00746 arc2 = ring[last].arc; 00747 00748 node1 = BLI_otherNode(arc1, root_node); 00749 node2 = BLI_otherNode(arc2, root_node); 00750 00751 testAxialSymmetry(graph, root_node, node1, node2, arc1, arc2, axis, limit, group); 00752 } 00753 else if (sub_total != total) /* allocate a new sub ring if needed */ 00754 { 00755 RadialArc *sub_ring = MEM_callocN(sizeof(RadialArc) * sub_total, "radial symmetry ring"); 00756 int sub_i; 00757 00758 /* fill in the sub ring */ 00759 for (sub_i = 0; sub_i < sub_total; sub_i++) 00760 { 00761 sub_ring[sub_i] = ring[first + sub_i]; 00762 } 00763 00764 testRadialSymmetry(graph, root_node, sub_ring, sub_total, axis, limit, group); 00765 00766 MEM_freeN(sub_ring); 00767 } 00768 else if (sub_total == total) 00769 { 00770 testRadialSymmetry(graph, root_node, ring, total, axis, limit, group); 00771 } 00772 00773 first = i; 00774 } 00775 } 00776 00777 00778 MEM_freeN(ring); 00779 } 00780 00781 static void flagAxialSymmetry(BNode *root_node, BNode *end_node, BArc *arc, int group) 00782 { 00783 float vec[3]; 00784 00785 arc->symmetry_group = group; 00786 00787 sub_v3_v3v3(vec, end_node->p, root_node->p); 00788 00789 if (dot_v3v3(vec, root_node->symmetry_axis) < 0) 00790 { 00791 arc->symmetry_flag |= SYM_SIDE_NEGATIVE; 00792 } 00793 else 00794 { 00795 arc->symmetry_flag |= SYM_SIDE_POSITIVE; 00796 } 00797 } 00798 00799 static void testAxialSymmetry(BGraph *graph, BNode* root_node, BNode* node1, BNode* node2, BArc* arc1, BArc* arc2, float axis[3], float limit, int group) 00800 { 00801 float nor[3], vec[3], p[3]; 00802 00803 sub_v3_v3v3(p, node1->p, root_node->p); 00804 cross_v3_v3v3(nor, p, axis); 00805 00806 sub_v3_v3v3(p, root_node->p, node2->p); 00807 cross_v3_v3v3(vec, p, axis); 00808 add_v3_v3(vec, nor); 00809 00810 cross_v3_v3v3(nor, vec, axis); 00811 00812 if (abs(nor[0]) > abs(nor[1]) && abs(nor[0]) > abs(nor[2]) && nor[0] < 0) 00813 { 00814 negate_v3(nor); 00815 } 00816 else if (abs(nor[1]) > abs(nor[0]) && abs(nor[1]) > abs(nor[2]) && nor[1] < 0) 00817 { 00818 negate_v3(nor); 00819 } 00820 else if (abs(nor[2]) > abs(nor[1]) && abs(nor[2]) > abs(nor[0]) && nor[2] < 0) 00821 { 00822 negate_v3(nor); 00823 } 00824 00825 /* mirror node2 along axis */ 00826 copy_v3_v3(p, node2->p); 00827 BLI_mirrorAlongAxis(p, root_node->p, nor); 00828 00829 /* check if it's within limit before continuing */ 00830 if (len_v3v3(node1->p, p) <= limit) 00831 { 00832 /* mark node as symmetric physically */ 00833 copy_v3_v3(root_node->symmetry_axis, nor); 00834 root_node->symmetry_flag |= SYM_PHYSICAL; 00835 root_node->symmetry_flag |= SYM_AXIAL; 00836 00837 /* flag side on arcs */ 00838 flagAxialSymmetry(root_node, node1, arc1, group); 00839 flagAxialSymmetry(root_node, node2, arc2, group); 00840 00841 if (graph->axial_symmetry) 00842 { 00843 graph->axial_symmetry(root_node, node1, node2, arc1, arc2); 00844 } 00845 } 00846 else 00847 { 00848 /* NOT SYMMETRIC */ 00849 } 00850 } 00851 00852 static void handleAxialSymmetry(BGraph *graph, BNode *root_node, int depth, float axis[3], float limit) 00853 { 00854 BArc *arc1 = NULL, *arc2 = NULL; 00855 BNode *node1 = NULL, *node2 = NULL; 00856 int i; 00857 00858 /* mark topological symmetry */ 00859 root_node->symmetry_flag |= SYM_TOPOLOGICAL; 00860 00861 for (i = 0; i < root_node->degree; i++) 00862 { 00863 BArc *connectedArc = root_node->arcs[i]; 00864 00865 /* depth is store as a negative in flag. symmetry level is positive */ 00866 if (connectedArc->symmetry_level == -depth) 00867 { 00868 if (arc1 == NULL) 00869 { 00870 arc1 = connectedArc; 00871 node1 = BLI_otherNode(arc1, root_node); 00872 } 00873 else 00874 { 00875 arc2 = connectedArc; 00876 node2 = BLI_otherNode(arc2, root_node); 00877 break; /* Can stop now, the two arcs have been found */ 00878 } 00879 } 00880 } 00881 00882 /* shouldn't happen, but just to be sure */ 00883 if (node1 == NULL || node2 == NULL) 00884 { 00885 return; 00886 } 00887 00888 testAxialSymmetry(graph, root_node, node1, node2, arc1, arc2, axis, limit, 1); 00889 } 00890 00891 static void markdownSecondarySymmetry(BGraph *graph, BNode *node, int depth, int level, float limit) 00892 { 00893 float axis[3] = {0, 0, 0}; 00894 int count = 0; 00895 int i; 00896 00897 /* count the number of branches in this symmetry group 00898 * and determinte the axis of symmetry 00899 * */ 00900 for (i = 0; i < node->degree; i++) 00901 { 00902 BArc *connectedArc = node->arcs[i]; 00903 00904 /* depth is store as a negative in flag. symmetry level is positive */ 00905 if (connectedArc->symmetry_level == -depth) 00906 { 00907 count++; 00908 } 00909 /* If arc is on the axis */ 00910 else if (connectedArc->symmetry_level == level) 00911 { 00912 add_v3_v3(axis, connectedArc->head->p); 00913 sub_v3_v3v3(axis, axis, connectedArc->tail->p); 00914 } 00915 } 00916 00917 normalize_v3(axis); 00918 00919 /* Split between axial and radial symmetry */ 00920 if (count == 2) 00921 { 00922 handleAxialSymmetry(graph, node, depth, axis, limit); 00923 } 00924 else 00925 { 00926 handleRadialSymmetry(graph, node, depth, axis, limit); 00927 } 00928 00929 /* markdown secondary symetries */ 00930 for (i = 0; i < node->degree; i++) 00931 { 00932 BArc *connectedArc = node->arcs[i]; 00933 00934 if (connectedArc->symmetry_level == -depth) 00935 { 00936 /* markdown symmetry for branches corresponding to the depth */ 00937 markdownSymmetryArc(graph, connectedArc, node, level + 1, limit); 00938 } 00939 } 00940 } 00941 00942 static void markdownSymmetryArc(BGraph *graph, BArc *arc, BNode *node, int level, float limit) 00943 { 00944 int i; 00945 00946 /* if arc is null, we start straight from a node */ 00947 if (arc) 00948 { 00949 arc->symmetry_level = level; 00950 00951 node = BLI_otherNode(arc, node); 00952 } 00953 00954 for (i = 0; i < node->degree; i++) 00955 { 00956 BArc *connectedArc = node->arcs[i]; 00957 00958 if (connectedArc != arc) 00959 { 00960 BNode *connectedNode = BLI_otherNode(connectedArc, node); 00961 00962 /* symmetry level is positive value, negative values is subtree depth */ 00963 connectedArc->symmetry_level = -BLI_subtreeShape(graph, connectedNode, connectedArc, 0); 00964 } 00965 } 00966 00967 arc = NULL; 00968 00969 for (i = 0; i < node->degree; i++) 00970 { 00971 int issymmetryAxis = 0; 00972 BArc *connectedArc = node->arcs[i]; 00973 00974 /* only arcs not already marked as symetric */ 00975 if (connectedArc->symmetry_level < 0) 00976 { 00977 int j; 00978 00979 /* true by default */ 00980 issymmetryAxis = 1; 00981 00982 for (j = 0; j < node->degree; j++) 00983 { 00984 BArc *otherArc = node->arcs[j]; 00985 00986 /* different arc, same depth */ 00987 if (otherArc != connectedArc && otherArc->symmetry_level == connectedArc->symmetry_level) 00988 { 00989 /* not on the symmetry axis */ 00990 issymmetryAxis = 0; 00991 break; 00992 } 00993 } 00994 } 00995 00996 /* arc could be on the symmetry axis */ 00997 if (issymmetryAxis == 1) 00998 { 00999 /* no arc as been marked previously, keep this one */ 01000 if (arc == NULL) 01001 { 01002 arc = connectedArc; 01003 } 01004 else if (connectedArc->symmetry_level < arc->symmetry_level) 01005 { 01006 /* go with more complex subtree as symmetry arc */ 01007 arc = connectedArc; 01008 } 01009 } 01010 } 01011 01012 /* go down the arc continuing the symmetry axis */ 01013 if (arc) 01014 { 01015 markdownSymmetryArc(graph, arc, node, level, limit); 01016 } 01017 01018 01019 /* secondary symmetry */ 01020 for (i = 0; i < node->degree; i++) 01021 { 01022 BArc *connectedArc = node->arcs[i]; 01023 01024 /* only arcs not already marked as symetric and is not the next arc on the symmetry axis */ 01025 if (connectedArc->symmetry_level < 0) 01026 { 01027 /* subtree depth is store as a negative value in the symmetry */ 01028 markdownSecondarySymmetry(graph, node, -connectedArc->symmetry_level, level, limit); 01029 } 01030 } 01031 } 01032 01033 void BLI_markdownSymmetry(BGraph *graph, BNode *root_node, float limit) 01034 { 01035 BNode *node; 01036 BArc *arc; 01037 01038 if (root_node == NULL) 01039 { 01040 return; 01041 } 01042 01043 if (BLI_isGraphCyclic(graph)) 01044 { 01045 return; 01046 } 01047 01048 /* mark down all arcs as non-symetric */ 01049 BLI_flagArcs(graph, 0); 01050 01051 /* mark down all nodes as not on the symmetry axis */ 01052 BLI_flagNodes(graph, 0); 01053 01054 node = root_node; 01055 01056 /* sanity check REMOVE ME */ 01057 if (node->degree > 0) 01058 { 01059 arc = node->arcs[0]; 01060 01061 if (node->degree == 1) 01062 { 01063 markdownSymmetryArc(graph, arc, node, 1, limit); 01064 } 01065 else 01066 { 01067 markdownSymmetryArc(graph, NULL, node, 1, limit); 01068 } 01069 01070 01071 01072 /* mark down non-symetric arcs */ 01073 for (arc = graph->arcs.first; arc; arc = arc->next) 01074 { 01075 if (arc->symmetry_level < 0) 01076 { 01077 arc->symmetry_level = 0; 01078 } 01079 else 01080 { 01081 /* mark down nodes with the lowest level symmetry axis */ 01082 if (arc->head->symmetry_level == 0 || arc->head->symmetry_level > arc->symmetry_level) 01083 { 01084 arc->head->symmetry_level = arc->symmetry_level; 01085 } 01086 if (arc->tail->symmetry_level == 0 || arc->tail->symmetry_level > arc->symmetry_level) 01087 { 01088 arc->tail->symmetry_level = arc->symmetry_level; 01089 } 01090 } 01091 } 01092 } 01093 } 01094 01095 void* IT_head(void* arg) 01096 { 01097 BArcIterator *iter = (BArcIterator*)arg; 01098 return iter->head(iter); 01099 } 01100 01101 void* IT_tail(void* arg) 01102 { 01103 BArcIterator *iter = (BArcIterator*)arg; 01104 return iter->tail(iter); 01105 } 01106 01107 void* IT_peek(void* arg, int n) 01108 { 01109 BArcIterator *iter = (BArcIterator*)arg; 01110 01111 if (iter->index + n < 0) 01112 { 01113 return iter->head(iter); 01114 } 01115 else if (iter->index + n >= iter->length) 01116 { 01117 return iter->tail(iter); 01118 } 01119 else 01120 { 01121 return iter->peek(iter, n); 01122 } 01123 } 01124 01125 void* IT_next(void* arg) 01126 { 01127 BArcIterator *iter = (BArcIterator*)arg; 01128 return iter->next(iter); 01129 } 01130 01131 void* IT_nextN(void* arg, int n) 01132 { 01133 BArcIterator *iter = (BArcIterator*)arg; 01134 return iter->nextN(iter, n); 01135 } 01136 01137 void* IT_previous(void* arg) 01138 { 01139 BArcIterator *iter = (BArcIterator*)arg; 01140 return iter->previous(iter); 01141 } 01142 01143 int IT_stopped(void* arg) 01144 { 01145 BArcIterator *iter = (BArcIterator*)arg; 01146 return iter->stopped(iter); 01147 }