Blender V2.61 - r43446

graph.c

Go to the documentation of this file.
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 }