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