Blender  V2.59
graph.c
Go to the documentation of this file.
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 }