pcb 4.1.1
An interactive printed circuit board layout editor.

graph.c

Go to the documentation of this file.
00001 /* GTS - Library for the manipulation of triangulated surfaces
00002  * Copyright (C) 1999 Stéphane Popinet
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library 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 GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 #include <math.h>
00021 #include <stdlib.h>
00022 #include "gts.h"
00023 
00024 /* GtsGNode */
00025 
00026 gboolean gts_allow_floating_gnodes = FALSE;
00027 
00028 static void gnode_remove_container (GtsContainee * i, GtsContainer * c)
00029 {
00030   (* GTS_CONTAINEE_CLASS (GTS_OBJECT_CLASS (gts_gnode_class ())->parent_class)->remove_container) (i, c);
00031   if (GTS_SLIST_CONTAINEE (i)->containers == NULL && 
00032       !gts_allow_floating_gnodes &&
00033       !GTS_OBJECT_DESTROYED(GTS_OBJECT (i)))
00034     gts_object_destroy (GTS_OBJECT (i));
00035 }
00036 
00037 static void gnode_class_init (GtsGNodeClass * klass)
00038 {
00039   klass->weight = NULL;
00040 
00041   GTS_CONTAINEE_CLASS (klass)->remove_container = gnode_remove_container;
00042 }
00043 
00044 static void gnode_init (GtsGNode * n)
00045 {
00046   n->level = 0;
00047 }
00048 
00054 GtsGNodeClass * gts_gnode_class (void)
00055 {
00056   static GtsGNodeClass * klass = NULL;
00057 
00058   if (klass == NULL) {
00059     GtsObjectClassInfo gnode_info = {
00060       "GtsGNode",
00061       sizeof (GtsGNode),
00062       sizeof (GtsGNodeClass),
00063       (GtsObjectClassInitFunc) gnode_class_init,
00064       (GtsObjectInitFunc) gnode_init,
00065       (GtsArgSetFunc) NULL,
00066       (GtsArgGetFunc) NULL
00067     };
00068     klass = 
00069       gts_object_class_new (GTS_OBJECT_CLASS (gts_slist_container_class ()),
00070                             &gnode_info);
00071   }
00072 
00073   return klass;
00074 }
00075 
00082 GtsGNode * gts_gnode_new (GtsGNodeClass * klass)
00083 {
00084   GtsGNode * object;
00085 
00086   object = GTS_GNODE (gts_object_new (GTS_OBJECT_CLASS (klass)));
00087 
00088   return object;
00089 }
00090 
00101 void gts_gnode_foreach_neighbor (GtsGNode * n, 
00102                                  GtsGraph * g,
00103                                  GtsFunc func,
00104                                  gpointer data)
00105 {
00106   GSList * i;
00107 
00108   g_return_if_fail (n != NULL);
00109   g_return_if_fail (func != NULL);
00110 
00111   i = GTS_SLIST_CONTAINER (n)->items;
00112   while (i) {
00113     GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
00114     if (g == NULL || gts_containee_is_contained (GTS_CONTAINEE (n1),
00115                                                  GTS_CONTAINER (g)))
00116       (* func) (n1, data);
00117     i = i->next;
00118   }
00119 }
00120 
00131 void gts_gnode_foreach_edge (GtsGNode * n, 
00132                              GtsGraph * g,
00133                              GtsFunc func,
00134                              gpointer data)
00135 {
00136   GSList * i;
00137 
00138   g_return_if_fail (n != NULL);
00139   g_return_if_fail (func != NULL);
00140 
00141   i = GTS_SLIST_CONTAINER (n)->items;
00142   while (i) {
00143     GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
00144     if (g == NULL || gts_containee_is_contained (GTS_CONTAINEE (n1),
00145                                                  GTS_CONTAINER (g)))
00146       (* func) (i->data, data);
00147     i = i->next;
00148   }
00149 }
00150 
00158 guint gts_gnode_degree (GtsGNode * n,
00159                         GtsGraph * g)
00160 {
00161   GSList * i;
00162   guint nn = 0;
00163 
00164   g_return_val_if_fail (n != NULL, 0);
00165 
00166   i = GTS_SLIST_CONTAINER (n)->items;
00167   while (i) {
00168     GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
00169     if (g == NULL || gts_containee_is_contained (GTS_CONTAINEE (n1),
00170                                                  GTS_CONTAINER (g)))
00171       nn++;
00172     i = i->next;
00173   }
00174 
00175   return nn;
00176 }
00177 
00187 gfloat gts_gnode_move_cost (GtsGNode * n,
00188                             GtsGraph * src,
00189                             GtsGraph * dst)
00190 {
00191   GSList * i;
00192   gfloat cost = 0.;
00193   
00194   g_return_val_if_fail (n != NULL, G_MAXFLOAT);
00195   g_return_val_if_fail (src != NULL, G_MAXFLOAT);
00196   g_return_val_if_fail (dst != NULL, G_MAXFLOAT);
00197   g_return_val_if_fail (gts_containee_is_contained (GTS_CONTAINEE (n),
00198                                                     GTS_CONTAINER (src)),
00199                         G_MAXFLOAT);
00200 
00201   i = GTS_SLIST_CONTAINER (n)->items;
00202   while (i) {
00203     GtsGEdge * ge = i->data;
00204     GtsGNode * neighbor = GTS_GNODE_NEIGHBOR (n, ge);
00205 
00206     if (gts_containee_is_contained (GTS_CONTAINEE (neighbor), 
00207                                     GTS_CONTAINER (src)))
00208       cost += gts_gedge_weight (ge);
00209     else if (gts_containee_is_contained (GTS_CONTAINEE (neighbor), 
00210                                          GTS_CONTAINER (dst)))
00211       cost -= gts_gedge_weight (ge);
00212     i = i->next;
00213   }
00214   
00215   return cost;
00216 }
00217 
00225 gfloat gts_gnode_weight (GtsGNode * n)
00226 {
00227   g_return_val_if_fail (n != NULL, 0.);
00228 
00229   if (GTS_GNODE_CLASS (GTS_OBJECT (n)->klass)->weight)
00230     return (* GTS_GNODE_CLASS (GTS_OBJECT (n)->klass)->weight) (n);
00231   return 1.;
00232 }
00233 
00234 /* GtsNGNode */
00235 
00236 static void ngnode_init (GtsNGNode * n)
00237 {
00238   n->id = 0;
00239 }
00240 
00246 GtsNGNodeClass * gts_ngnode_class (void)
00247 {
00248   static GtsNGNodeClass * klass = NULL;
00249 
00250   if (klass == NULL) {
00251     GtsObjectClassInfo ngnode_info = {
00252       "GtsNGNode",
00253       sizeof (GtsNGNode),
00254       sizeof (GtsNGNodeClass),
00255       (GtsObjectClassInitFunc) NULL,
00256       (GtsObjectInitFunc) ngnode_init,
00257       (GtsArgSetFunc) NULL,
00258       (GtsArgGetFunc) NULL
00259     };
00260     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()),
00261                                   &ngnode_info);
00262   }
00263 
00264   return klass;
00265 }
00266 
00273 GtsNGNode * gts_ngnode_new (GtsNGNodeClass * klass,
00274                             guint id)
00275 {
00276   GtsNGNode * n;
00277 
00278   n = GTS_NGNODE (gts_gnode_new (GTS_GNODE_CLASS (klass)));
00279   n->id = id;
00280 
00281   return n;
00282 }
00283 
00284 /* GtsWGNode */
00285 
00286 static gfloat wgnode_weight (GtsGNode * n)
00287 {
00288   return GTS_WGNODE (n)->weight;
00289 }
00290 
00291 static void wgnode_class_init (GtsWGNodeClass * klass)
00292 {
00293   GTS_GNODE_CLASS (klass)->weight = wgnode_weight;
00294 }
00295 
00296 static void wgnode_init (GtsWGNode * n)
00297 {
00298   n->weight = 1.;
00299 }
00300 
00306 GtsWGNodeClass * gts_wgnode_class (void)
00307 {
00308   static GtsWGNodeClass * klass = NULL;
00309 
00310   if (klass == NULL) {
00311     GtsObjectClassInfo wgnode_info = {
00312       "GtsWGNode",
00313       sizeof (GtsWGNode),
00314       sizeof (GtsWGNodeClass),
00315       (GtsObjectClassInitFunc) wgnode_class_init,
00316       (GtsObjectInitFunc) wgnode_init,
00317       (GtsArgSetFunc) NULL,
00318       (GtsArgGetFunc) NULL
00319     };
00320     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()),
00321                                   &wgnode_info);
00322   }
00323 
00324   return klass;
00325 }
00326 
00334 GtsWGNode * gts_wgnode_new (GtsWGNodeClass * klass,
00335                             gfloat weight)
00336 {
00337   GtsWGNode * n;
00338 
00339   n = GTS_WGNODE (gts_gnode_new (GTS_GNODE_CLASS (klass)));
00340   n->weight = weight;
00341 
00342   return n;
00343 }
00344 
00345 /* GtsPNode */
00346 
00347 static void pnode_write (GtsGNode * n, FILE * fp)
00348 {
00349   if (GTS_IS_NVERTEX (GTS_PNODE (n)->data))
00350     fprintf (fp, "label=\"%p:%s\",", 
00351              GTS_PNODE (n)->data,
00352              GTS_NVERTEX (GTS_PNODE (n)->data)->name);
00353   else
00354     fprintf (fp, "label=\"%p\",", GTS_PNODE (n)->data);
00355 }
00356 
00357 static void pnode_class_init (GtsPNodeClass * klass)
00358 {
00359   GTS_GNODE_CLASS (klass)->write = pnode_write;
00360 }
00361 
00362 static void pnode_init (GtsPNode * pn)
00363 {
00364   pn->data = NULL;
00365 }
00366 
00372 GtsPNodeClass * gts_pnode_class (void)
00373 {
00374   static GtsPNodeClass * klass = NULL;
00375 
00376   if (klass == NULL) {
00377     GtsObjectClassInfo pnode_info = {
00378       "GtsPNode",
00379       sizeof (GtsPNode),
00380       sizeof (GtsPNodeClass),
00381       (GtsObjectClassInitFunc) pnode_class_init,
00382       (GtsObjectInitFunc) pnode_init,
00383       (GtsArgSetFunc) NULL,
00384       (GtsArgGetFunc) NULL
00385     };
00386     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()),
00387                                   &pnode_info);
00388   }
00389 
00390   return klass;
00391 }
00392 
00400 GtsPNode * gts_pnode_new (GtsPNodeClass * klass, gpointer data)
00401 {
00402   GtsPNode * pn;
00403 
00404   pn = GTS_PNODE (gts_object_new (GTS_OBJECT_CLASS (klass)));
00405   pn->data = data;
00406 
00407   return pn;
00408 }
00409 
00410 /* GtsFNode */
00411 
00412 static void fnode_write (GtsGNode * n, FILE * fp)
00413 {
00414   fprintf (fp, "label=\"%p\",", GTS_FNODE (n)->f);
00415 }
00416 
00417 static void fnode_class_init (GtsGNodeClass * klass)
00418 {
00419   klass->write = fnode_write;
00420 }
00421 
00422 static void fnode_init (GtsFNode * fn)
00423 {
00424   fn->f = NULL;
00425 }
00426 
00432 GtsFNodeClass * gts_fnode_class (void)
00433 {
00434   static GtsFNodeClass * klass = NULL;
00435 
00436   if (klass == NULL) {
00437     GtsObjectClassInfo fnode_info = {
00438       "GtsFNode",
00439       sizeof (GtsFNode),
00440       sizeof (GtsFNodeClass),
00441       (GtsObjectClassInitFunc) fnode_class_init,
00442       (GtsObjectInitFunc) fnode_init,
00443       (GtsArgSetFunc) NULL,
00444       (GtsArgGetFunc) NULL
00445     };
00446     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()),
00447                                   &fnode_info);
00448   }
00449 
00450   return klass;
00451 }
00452 
00460 GtsFNode * gts_fnode_new (GtsFNodeClass * klass, GtsFace * f)
00461 {
00462   GtsFNode * fn;
00463 
00464   g_return_val_if_fail (f != NULL, NULL);
00465 
00466   fn = GTS_FNODE (gts_object_new (GTS_OBJECT_CLASS (klass)));
00467   fn->f = f;
00468 
00469   return fn;
00470 }
00471 
00472 /* GtsGEdge */
00473 
00474 static void gedge_destroy (GtsObject * object)
00475 {
00476   GtsGEdge * ge = GTS_GEDGE (object);
00477 
00478   if (ge->n1)
00479     gts_container_remove (GTS_CONTAINER (ge->n1), GTS_CONTAINEE (ge));
00480   if (ge->n2)
00481     gts_container_remove (GTS_CONTAINER (ge->n2), GTS_CONTAINEE (ge));
00482 
00483   (* GTS_OBJECT_CLASS (gts_gedge_class ())->parent_class->destroy) (object);
00484 }
00485 
00486 static void gedge_remove_container (GtsContainee * i, GtsContainer * c)
00487 {
00488   GtsGEdge * ge = GTS_GEDGE (i);
00489   GtsGNode * n1 = ge->n1;
00490   GtsGNode * n2 = ge->n2;
00491 
00492   ge->n1 = ge->n2 = NULL;
00493   if (n1 != NULL && n2 != NULL) {
00494     if (GTS_CONTAINER (n1) == c) {
00495       if (n2 && n2 != n1) gts_container_remove (GTS_CONTAINER (n2), i);
00496     }
00497     else if (GTS_CONTAINER (n2) == c) {
00498       if (n1 && n1 != n2) gts_container_remove (GTS_CONTAINER (n1), i);
00499     }
00500     else
00501       g_assert_not_reached ();
00502     (* GTS_OBJECT_CLASS (gts_gedge_class ())->parent_class->destroy)
00503       (GTS_OBJECT (i));
00504   }
00505 }
00506 
00507 static gboolean gedge_is_contained (GtsContainee * i, GtsContainer * c)
00508 {
00509   GtsGEdge * ge = GTS_GEDGE (i);
00510 
00511   if (GTS_CONTAINER (ge->n1) == c || GTS_CONTAINER (ge->n2) == c)
00512     return TRUE;
00513   return FALSE;
00514 }
00515 
00516 static void gedge_class_init (GtsGEdgeClass * klass)
00517 {
00518   klass->link = NULL;
00519   klass->weight = NULL;
00520 
00521   GTS_CONTAINEE_CLASS (klass)->remove_container = gedge_remove_container;
00522   GTS_CONTAINEE_CLASS (klass)->is_contained = gedge_is_contained;
00523 
00524   GTS_OBJECT_CLASS (klass)->destroy = gedge_destroy;
00525 }
00526 
00527 static void gedge_init (GtsGEdge * object)
00528 {
00529   object->n1 = object->n2 = NULL;
00530 }
00531 
00537 GtsGEdgeClass * gts_gedge_class (void)
00538 {
00539   static GtsGEdgeClass * klass = NULL;
00540 
00541   if (klass == NULL) {
00542     GtsObjectClassInfo gedge_info = {
00543       "GtsGEdge",
00544       sizeof (GtsGEdge),
00545       sizeof (GtsGEdgeClass),
00546       (GtsObjectClassInitFunc) gedge_class_init,
00547       (GtsObjectInitFunc) gedge_init,
00548       (GtsArgSetFunc) NULL,
00549       (GtsArgGetFunc) NULL
00550     };
00551     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_containee_class ()),
00552                                   &gedge_info);
00553   }
00554 
00555   return klass;
00556 }
00557 
00566 GtsGEdge * gts_gedge_new (GtsGEdgeClass * klass, GtsGNode * n1, GtsGNode * n2)
00567 {
00568   GtsGEdge * object;
00569 
00570   g_return_val_if_fail (n1 != NULL, NULL);
00571   g_return_val_if_fail (n2 != NULL, NULL);
00572 
00573   object = GTS_GEDGE (gts_object_new (GTS_OBJECT_CLASS (klass)));
00574   object->n1 = n1;
00575   gts_container_add (GTS_CONTAINER (n1), GTS_CONTAINEE (object));
00576   object->n2 = n2;
00577   if (n1 != n2)
00578     gts_container_add (GTS_CONTAINER (n2), GTS_CONTAINEE (object));
00579 
00580   if (klass->link)
00581     object = (* klass->link) (object, n1, n2);
00582 
00583   return object;
00584 }
00585 
00593 gfloat gts_gedge_weight (GtsGEdge * e)
00594 {
00595   g_return_val_if_fail (e != NULL, 0.);
00596 
00597   if (GTS_GEDGE_CLASS (GTS_OBJECT (e)->klass)->weight)
00598     return (* GTS_GEDGE_CLASS (GTS_OBJECT (e)->klass)->weight) (e);
00599   return 1.;
00600 }
00601 
00602 /* GtsPGEdge */
00603 
00604 static void pgedge_write (GtsGEdge * ge, FILE * fp)
00605 {
00606   if (GTS_IS_EDGE (GTS_PGEDGE (ge)->data)) {
00607     GtsEdge * e = GTS_PGEDGE (ge)->data;
00608     guint n = g_slist_length (e->triangles);
00609 
00610     fprintf (fp, "label=\"%p:%s:%d\",color=%s", e,
00611              GTS_IS_NEDGE (e) ? GTS_NEDGE (e)->name : "",
00612              n,
00613              n == 0 ? "black" : 
00614              n == 1 ? "blue" :
00615              n == 2 ? "green" :
00616              n == 3 ? "violet" :
00617              n == 4 ? "red" : 
00618              "pink");
00619   }
00620   else
00621     fprintf (fp, "label=\"%p\",", GTS_PGEDGE (ge)->data);
00622 }
00623 
00624 static void pgedge_class_init (GtsPGEdgeClass * klass)
00625 {
00626   GTS_GEDGE_CLASS (klass)->write = pgedge_write;
00627 }
00628 
00629 static void pgedge_init (GtsPGEdge * e)
00630 {
00631   e->data = NULL;
00632 }
00633 
00639 GtsPGEdgeClass * gts_pgedge_class (void)
00640 {
00641   static GtsPGEdgeClass * klass = NULL;
00642 
00643   if (klass == NULL) {
00644     GtsObjectClassInfo pgedge_info = {
00645       "GtsPGEdge",
00646       sizeof (GtsPGEdge),
00647       sizeof (GtsPGEdgeClass),
00648       (GtsObjectClassInitFunc) pgedge_class_init,
00649       (GtsObjectInitFunc) pgedge_init,
00650       (GtsArgSetFunc) NULL,
00651       (GtsArgGetFunc) NULL
00652     };
00653     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gedge_class ()),
00654                                   &pgedge_info);
00655   }
00656 
00657   return klass;
00658 }
00659 
00669 GtsPGEdge * gts_pgedge_new (GtsPGEdgeClass * klass,
00670                             GtsGNode * g1,
00671                             GtsGNode * g2,
00672                             gpointer data)
00673 {
00674   GtsPGEdge * we;
00675 
00676   we = GTS_PGEDGE (gts_gedge_new (GTS_GEDGE_CLASS (klass), g1, g2));
00677   we->data = data;
00678 
00679   return we;
00680 }
00681 
00682 /* GtsWGEdge */
00683 
00684 static gfloat wgedge_weight (GtsGEdge * e)
00685 {
00686   return GTS_WGEDGE (e)->weight;
00687 }
00688 
00689 static void wgedge_class_init (GtsWGEdgeClass * klass)
00690 {
00691   GTS_GEDGE_CLASS (klass)->weight = wgedge_weight;
00692 }
00693 
00694 static void wgedge_init (GtsWGEdge * e)
00695 {
00696   e->weight = 1.;
00697 }
00698 
00704 GtsWGEdgeClass * gts_wgedge_class (void)
00705 {
00706   static GtsWGEdgeClass * klass = NULL;
00707 
00708   if (klass == NULL) {
00709     GtsObjectClassInfo wgedge_info = {
00710       "GtsWGEdge",
00711       sizeof (GtsWGEdge),
00712       sizeof (GtsWGEdgeClass),
00713       (GtsObjectClassInitFunc) wgedge_class_init,
00714       (GtsObjectInitFunc) wgedge_init,
00715       (GtsArgSetFunc) NULL,
00716       (GtsArgGetFunc) NULL
00717     };
00718     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gedge_class ()),
00719                                   &wgedge_info);
00720   }
00721 
00722   return klass;
00723 }
00724 
00734 GtsWGEdge * gts_wgedge_new (GtsWGEdgeClass * klass,
00735                             GtsGNode * g1,
00736                             GtsGNode * g2,
00737                             gfloat weight)
00738 {
00739   GtsWGEdge * we;
00740 
00741   we = GTS_WGEDGE (gts_gedge_new (GTS_GEDGE_CLASS (klass), g1, g2));
00742   we->weight = weight;
00743 
00744   return we;
00745 }
00746 
00747 /* GtsGraph */
00748 
00749 static void graph_init (GtsGraph * g)
00750 {
00751   g->graph_class = gts_graph_class ();
00752   g->node_class  = gts_gnode_class ();
00753   g->edge_class  = gts_gedge_class ();
00754 }
00755 
00756 static void graph_write (GtsObject * object, FILE * fp)
00757 {
00758   GtsGraph * graph = GTS_GRAPH (object);
00759 
00760   fprintf (fp, " %s %s %s",
00761            object->klass->info.name,
00762            GTS_OBJECT_CLASS (graph->node_class)->info.name,
00763            GTS_OBJECT_CLASS (graph->edge_class)->info.name);
00764 }
00765 
00766 static void graph_read (GtsObject ** object, GtsFile * f)
00767 {
00768   GtsObjectClass * klass;
00769 
00770   if (f->type != GTS_STRING) {
00771     gts_file_error (f, "expecting a string (GtsGNodeClass)");
00772     return;
00773   }
00774   klass = gts_object_class_from_name (f->token->str);
00775   if (klass == NULL) {
00776     gts_file_error (f, "unknown class `%s'", f->token->str);
00777     return;
00778   }
00779   if (!gts_object_class_is_from_class (klass, gts_gnode_class ())) {
00780     gts_file_error (f, "class `%s' is not a GtsGNodeClass", f->token->str);
00781     return;
00782   }
00783   GTS_GRAPH (*object)->node_class = GTS_GNODE_CLASS (klass);
00784   gts_file_next_token (f);
00785 
00786   if (f->type != GTS_STRING) {
00787     gts_file_error (f, "expecting a string (GtsGEdgeClass)");
00788     return;
00789   }
00790   klass = gts_object_class_from_name (f->token->str);
00791   if (klass == NULL) {
00792     gts_file_error (f, "unknown class `%s'", f->token->str);
00793     return;
00794   }
00795   if (!gts_object_class_is_from_class (klass, gts_gedge_class ())) {
00796     gts_file_error (f, "class `%s' is not a GtsGEdgeClass", f->token->str);
00797     return;
00798   }
00799   GTS_GRAPH (*object)->edge_class = GTS_GEDGE_CLASS (klass);
00800   gts_file_next_token (f);
00801 }
00802 
00803 static void graph_class_init (GtsGraphClass * klass)
00804 {
00805   klass->weight = NULL;
00806 
00807   GTS_OBJECT_CLASS (klass)->write = graph_write;
00808   GTS_OBJECT_CLASS (klass)->read = graph_read;
00809 }
00810 
00816 GtsGraphClass * gts_graph_class (void)
00817 {
00818   static GtsGraphClass * klass = NULL;
00819 
00820   if (klass == NULL) {
00821     GtsObjectClassInfo graph_info = {
00822       "GtsGraph",
00823       sizeof (GtsGraph),
00824       sizeof (GtsGraphClass),
00825       (GtsObjectClassInitFunc) graph_class_init,
00826       (GtsObjectInitFunc) graph_init,
00827       (GtsArgSetFunc) NULL,
00828       (GtsArgGetFunc) NULL
00829     };
00830     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_hash_container_class ()),
00831                                   &graph_info);
00832   }
00833 
00834   return klass;
00835 }
00836 
00845 GtsGraph * gts_graph_new (GtsGraphClass * klass,
00846                           GtsGNodeClass * node_class,
00847                           GtsGEdgeClass * edge_class)
00848 {
00849   GtsGraph * g;
00850 
00851   g_return_val_if_fail (klass != NULL, NULL);
00852   g_return_val_if_fail (node_class != NULL, NULL);
00853   g_return_val_if_fail (edge_class != NULL, NULL);
00854 
00855   g = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass)));
00856   g->node_class = node_class;
00857   g->edge_class = edge_class;
00858 
00859   return g;
00860 }
00861 
00862 static void compute_degree (GtsGNode * n, gpointer * data)
00863 {
00864   GtsGraph * g = data[0];
00865   GtsRange * degree = data[1];
00866 
00867   gts_range_add_value (degree, gts_gnode_degree (n, g));
00868 }
00869 
00877 void gts_graph_print_stats (GtsGraph * g, FILE * fp)
00878 {
00879   GtsRange degree;
00880   gpointer data[2];
00881 
00882   g_return_if_fail (g != NULL);
00883   g_return_if_fail (fp != NULL);
00884 
00885   fprintf (fp, "# nodes: %d weight: %g\n", 
00886            gts_container_size (GTS_CONTAINER (g)),
00887            gts_graph_weight (g));
00888   fprintf (fp, "#   degree: ");
00889   gts_range_init (&degree);
00890   data[0] = g;
00891   data[1] = &degree;
00892   gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) compute_degree, data);
00893   gts_range_update (&degree);
00894   gts_range_print (&degree, fp);
00895   fprintf (fp, "\n");
00896   fprintf (fp, "#   edges cut: %d edges cut weight: %g\n", 
00897            gts_graph_edges_cut (g),
00898            gts_graph_edges_cut_weight (g));
00899 }
00900 
00901 struct _GtsGraphTraverse {
00902   GtsFifo * q;
00903   GtsGraph * g;
00904 };
00905 
00906 static void reset_level (GtsGNode * n)
00907 {
00908   n->level = 0;
00909 }
00910 
00921 GtsGraphTraverse * gts_graph_traverse_new (GtsGraph * g, 
00922                                            GtsGNode * n,
00923                                            GtsTraverseType type,
00924                                            gboolean reinit)
00925 {
00926   GtsGraphTraverse * t;
00927 
00928   g_return_val_if_fail (g != NULL, NULL);
00929   g_return_val_if_fail (n != NULL, NULL);
00930   g_return_val_if_fail (gts_containee_is_contained (GTS_CONTAINEE (n), 
00931                                                     GTS_CONTAINER (g)), 
00932                         NULL);
00933 
00934   if (reinit)
00935     gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) reset_level, NULL);
00936 
00937   t = g_malloc (sizeof (GtsGraphTraverse));
00938   t->q = gts_fifo_new ();
00939   t->g = g;
00940   n->level = 1;
00941   gts_fifo_push (t->q, n);
00942 
00943   return t;
00944 }
00945 
00946 static void push_neighbor (GtsGNode * n, gpointer * data)
00947 {
00948   GtsFifo * q = data[0];
00949   GtsGNode * u = data[1];
00950 
00951   if (n->level == 0) {
00952     n->level = u->level + 1;
00953     gts_fifo_push (q, n);
00954   }
00955 }
00956 
00964 GtsGNode * gts_graph_traverse_next (GtsGraphTraverse * t) 
00965 { 
00966   GtsGNode * u;
00967 
00968   g_return_val_if_fail (t != NULL, NULL);
00969 
00970   u = gts_fifo_pop (t->q);
00971   if (u) {
00972     gpointer data[2];
00973 
00974     data[0] = t->q;
00975     data[1] = u;
00976     gts_gnode_foreach_neighbor (u, t->g, (GtsFunc) push_neighbor, data);
00977   }
00978   
00979   return u;
00980 }
00981 
00989 GtsGNode * gts_graph_traverse_what_next (GtsGraphTraverse * t)
00990 {
00991   g_return_val_if_fail (t != NULL, NULL);
00992 
00993   return gts_fifo_top (t->q);
00994 }
00995 
01002 void gts_graph_traverse_destroy (GtsGraphTraverse * t)
01003 {
01004   g_return_if_fail (t != NULL);
01005 
01006   gts_fifo_destroy (t->q);
01007   g_free (t);
01008 }
01009 
01010 static void edge_foreach_node (GtsGNode * n, gpointer * info)
01011 {
01012   GtsFunc func = (GtsFunc) info[0];
01013   gpointer data = info[1];
01014   GHashTable * hash = info[2];
01015   GSList * i = GTS_SLIST_CONTAINER (n)->items;
01016 
01017   while (i) {
01018     GtsGEdge * e = i->data;
01019     if (!g_hash_table_lookup (hash, e)) {
01020       (* func) (e, data);
01021       g_hash_table_insert (hash, e, e);
01022     }
01023     i = i->next;
01024   }  
01025 }
01026 
01035 void gts_graph_foreach_edge (GtsGraph * g, GtsFunc func, gpointer data)
01036 {
01037   gpointer info[3];
01038   GHashTable * hash;
01039 
01040   g_return_if_fail (g != NULL);
01041   g_return_if_fail (func != NULL);
01042 
01043   info[0] = func;
01044   info[1] = data;
01045   info[2] = hash = g_hash_table_new (NULL, NULL);
01046   gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) edge_foreach_node, info);
01047   g_hash_table_destroy (hash);
01048 }
01049 
01057 gfloat gts_graph_weight (GtsGraph * g)
01058 {
01059   g_return_val_if_fail (g != NULL, 0.);
01060 
01061   if (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass)->weight)
01062     return (* GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass)->weight) (g);
01063   return (gfloat) gts_container_size (GTS_CONTAINER (g));
01064 }
01065 
01074 guint gts_graph_distance_sum (GtsGraph * g, GtsGNode * center)
01075 {
01076   GtsGraphTraverse * t;
01077   GtsGNode * n;
01078   guint sum = 0;
01079 
01080   g_return_val_if_fail (g != NULL, 0);
01081   g_return_val_if_fail (center != NULL, 0);
01082 
01083   t = gts_graph_traverse_new (g, center, GTS_BREADTH_FIRST, TRUE);
01084   while ((n = gts_graph_traverse_next (t)))
01085     sum += n->level - 1;
01086   gts_graph_traverse_destroy (t);
01087 
01088   return sum;
01089 }
01090 
01099 GtsGNode * gts_graph_farthest (GtsGraph * g, GSList * gnodes)
01100 {
01101   GtsGNode * farthest = NULL;
01102   GSList * i;
01103   gboolean reinit = TRUE, changed = TRUE;
01104   guint level = 1;
01105 
01106   g_return_val_if_fail (g != NULL, NULL);
01107 
01108   /* initialize traversals */
01109   i = gnodes;
01110   while (i) {
01111     GTS_OBJECT (i->data)->reserved = 
01112       gts_graph_traverse_new (g, i->data, GTS_BREADTH_FIRST, reinit);
01113     reinit = FALSE;
01114     i = i->next;
01115   }
01116 
01117   while (changed) {
01118     changed = FALSE;
01119     i = gnodes;
01120     while (i) {
01121       GtsGraphTraverse * t = GTS_OBJECT (i->data)->reserved;
01122       GtsGNode * n;
01123       while ((n = gts_graph_traverse_what_next (t)) && n->level == level) {
01124         changed = TRUE;
01125         farthest = n;
01126         gts_graph_traverse_next (t);
01127       }
01128       i = i->next;
01129     }
01130     level++;
01131   }
01132 
01133   /* destroy traversals */
01134   i = gnodes;
01135   while (i) {
01136     gts_graph_traverse_destroy (GTS_OBJECT (i->data)->reserved);
01137     GTS_OBJECT (i->data)->reserved = NULL;
01138     i = i->next;
01139   }
01140   return farthest;
01141 }
01142 
01143 static void neighbor_count (GtsGNode * n, gpointer * data)
01144 {
01145   guint * cuts = data[0];
01146   GtsGraph * g = data[1];
01147   
01148   if (!gts_containee_is_contained (GTS_CONTAINEE (n), GTS_CONTAINER (g)))
01149     (*cuts)++;
01150 }
01151 
01152 static void count_edge_cuts (GtsGNode * n, gpointer * data)
01153 {
01154   gts_gnode_foreach_neighbor (n, NULL, (GtsFunc) neighbor_count, data);
01155 }
01156 
01164 guint gts_graph_edges_cut (GtsGraph * g)
01165 {
01166   guint cuts = 0;
01167   gpointer data[2];
01168 
01169   g_return_val_if_fail (g != NULL, 0);
01170 
01171   data[0] = &cuts;
01172   data[1] = g;
01173   gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) count_edge_cuts, data);
01174 
01175   return cuts;
01176 }
01177 
01178 static void sum_edge_cuts_weight (GtsGNode * n, gpointer * data)
01179 {
01180   gfloat * weight = data[0];
01181   GtsGraph * g = data[1];
01182   GSList * i = GTS_SLIST_CONTAINER (n)->items;
01183 
01184   while (i) {
01185     GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
01186     if (!gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g)))
01187       *weight += gts_gedge_weight (i->data);
01188     i = i->next;
01189   }
01190 }
01191 
01199 gfloat gts_graph_edges_cut_weight (GtsGraph * g)
01200 {
01201   gfloat weight = 0.;
01202   gpointer data[2];
01203 
01204   g_return_val_if_fail (g != NULL, 0);
01205 
01206   data[0] = &weight;
01207   data[1] = g;
01208   gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) sum_edge_cuts_weight, 
01209                          data);
01210 
01211   return weight;
01212 }
01213 
01228 guint gts_graph_read_jostle (GtsGraph * g, GtsFile * fp)
01229 {
01230   guint nn, ne, n;
01231   GtsGNode ** nodes;
01232 
01233   g_return_val_if_fail (g != NULL, 1);
01234   g_return_val_if_fail (fp != NULL, 1);
01235 
01236   if (fp->type != GTS_INT) {
01237     gts_file_error (fp, "expecting an integer (number of nodes)");
01238     return fp->line;
01239   }
01240   nn = atoi (fp->token->str);
01241   gts_file_next_token (fp);
01242 
01243   if (fp->type != GTS_INT) {
01244     gts_file_error (fp, "expecting an integer (number of edges)");
01245     return fp->line;
01246   }
01247   ne = atoi (fp->token->str);
01248 
01249   gts_file_first_token_after (fp, '\n');
01250   nodes = g_malloc (sizeof (GtsGNode *)*(nn + 1));
01251 
01252   n = 0;
01253   while (n < nn && fp->type != GTS_ERROR) {
01254     GtsNGNode * node = gts_ngnode_new (gts_ngnode_class (), fp->line);
01255     
01256     nodes[n++] = GTS_GNODE (node);
01257     gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (node));
01258     do {
01259       if (fp->type != GTS_INT)
01260         gts_file_error (fp, "expecting an integer (node index)");
01261       else {
01262         guint in = atoi (fp->token->str);
01263         
01264         if (in == 0 || in > nn)
01265           gts_file_error (fp, "node index `%d' is out of range `[1,%d]'",
01266                           in, nn);
01267         else if (in == n)
01268           gts_file_error (fp, "node index `%d' references itself", in);
01269         else if (in < n) {
01270           gts_gedge_new (g->edge_class, GTS_GNODE (node), nodes[in - 1]);
01271           ne--;
01272           gts_file_next_token (fp);
01273         }
01274       }
01275     } while (fp->type != GTS_ERROR && fp->type != '\n');
01276   }
01277   g_free (nodes);
01278 
01279   if (fp->type != GTS_ERROR) {
01280     if (n != nn)
01281       gts_file_error (fp, "only `%d' nodes read out of `%d'",
01282                       n, nn);
01283     else if (ne > 0)
01284       gts_file_error (fp, "`%d' unallocated edges remaining",
01285                       ne);
01286   }
01287 
01288   if (fp->type == GTS_ERROR)
01289     return fp->line;
01290   return 0;
01291 }
01292 
01293 static void count_edges (GtsGEdge * e, guint * nedge)
01294 {
01295   (*nedge)++;
01296 }
01297 
01298 static void write_node (GtsObject * node, gpointer * data)
01299 {
01300   FILE * fp = data[0];
01301   guint * nnode = data[1];
01302 
01303   node->reserved = GUINT_TO_POINTER ((*nnode)++);
01304   if (node->klass->write)
01305     (* node->klass->write) (node, fp);
01306   fputc ('\n', fp);
01307 }
01308 
01309 static void write_edge (GtsGEdge * edge, FILE * fp)
01310 {
01311   fprintf (fp, "%u %u", 
01312            GPOINTER_TO_UINT (GTS_OBJECT (edge->n1)->reserved),
01313            GPOINTER_TO_UINT (GTS_OBJECT (edge->n2)->reserved));
01314   if (GTS_OBJECT (edge)->klass->write)
01315     (* GTS_OBJECT (edge)->klass->write) (GTS_OBJECT (edge), fp);
01316   fputc ('\n', fp);
01317 }
01318 
01344 void gts_graph_write (GtsGraph * g, FILE * fp)
01345 {
01346   guint nnode = 1, nedge = 0;
01347   gpointer data[2];
01348 
01349   g_return_if_fail (g != NULL);
01350   g_return_if_fail (fp != NULL);
01351 
01352   gts_graph_foreach_edge (g, (GtsFunc) count_edges, &nedge);
01353   fprintf (fp, "%u %u", gts_container_size (GTS_CONTAINER (g)), nedge);
01354   if (GTS_OBJECT (g)->klass->write)
01355     (* GTS_OBJECT (g)->klass->write) (GTS_OBJECT (g), fp);
01356   fputc ('\n', fp);
01357   data[0] = fp;
01358   data[1] = &nnode;
01359   gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) write_node, data);
01360   gts_graph_foreach_edge (g, (GtsFunc) write_edge, fp);
01361   gts_container_foreach (GTS_CONTAINER (g), 
01362                          (GtsFunc) gts_object_reset_reserved, NULL);
01363 }
01364 
01374 GtsGraph * gts_graph_read (GtsFile * fp)
01375 {
01376   GtsGraph * g;
01377   GtsGNode ** nodes;
01378   guint nn, ne, n;
01379 
01380   g_return_val_if_fail (fp != NULL, NULL);
01381 
01382   if (fp->type != GTS_INT) {
01383     gts_file_error (fp, "expecting an integer (number of nodes)");
01384     return NULL;
01385   }
01386   nn = atoi (fp->token->str);
01387   gts_file_next_token (fp);
01388 
01389   if (fp->type != GTS_INT) {
01390     gts_file_error (fp, "expecting an integer (number of edges)");
01391     return NULL;
01392   }
01393   ne = atoi (fp->token->str);
01394 
01395   gts_file_next_token (fp);
01396   if (fp->type != '\n') {
01397     GtsObjectClass * klass;
01398 
01399     gts_graph_class ();
01400     gts_gnode_class ();
01401     gts_gedge_class ();
01402 
01403     if (fp->type != GTS_STRING) {
01404       gts_file_error (fp, "expecting a string (GtsGraphClass)");
01405       return NULL;
01406     }
01407     klass = gts_object_class_from_name (fp->token->str);
01408     if (klass == NULL) {
01409       gts_file_error (fp, "unknown class `%s'", fp->token->str);
01410       return NULL;
01411     }
01412     if (!gts_object_class_is_from_class (klass, gts_graph_class ())) {
01413       gts_file_error (fp, "class `%s' is not a GtsGraphClass", fp->token->str);
01414       return NULL;
01415     }
01416     g = GTS_GRAPH (gts_object_new (klass));
01417     g->graph_class = GTS_GRAPH_CLASS (klass);
01418     gts_file_next_token (fp);
01419     (* klass->read) ((GtsObject **) &g, fp);
01420     if (fp->type == GTS_ERROR) {
01421       gts_object_destroy (GTS_OBJECT (g));
01422       return NULL;
01423     }
01424   }
01425   else
01426     g = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (gts_graph_class ())));
01427   gts_file_first_token_after (fp, '\n');
01428   if (nn <= 0)
01429     return g;
01430 
01431   nodes = g_malloc ((nn + 1)*sizeof (GtsGNode *));
01432 
01433   n = 0;
01434   while (n < nn && fp->type != GTS_ERROR) {
01435     GtsObject * new_node = 
01436       gts_object_new (GTS_OBJECT_CLASS (g->node_class));
01437 
01438     gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (new_node));
01439     if (GTS_OBJECT_CLASS (g->node_class)->read)
01440       (*GTS_OBJECT_CLASS (g->node_class)->read) (&new_node, fp);
01441     gts_file_first_token_after (fp, '\n');
01442     nodes[n++] = GTS_GNODE (new_node);
01443   }
01444   if (fp->type == GTS_ERROR)
01445     nn = n;
01446 
01447   n = 0;
01448   while (n < ne && fp->type != GTS_ERROR) {
01449     guint n1, n2;
01450 
01451     if (fp->type != GTS_INT)
01452       gts_file_error (fp, "expecting an integer (first node index)");
01453     else {
01454       n1 = atoi (fp->token->str);
01455       if (n1 == 0 || n1 > nn)
01456         gts_file_error (fp, "node index `%d' is out of range `[1,%d]'",
01457                         n1, nn);
01458       else {
01459         gts_file_next_token (fp);
01460         if (fp->type != GTS_INT)
01461           gts_file_error (fp, "expecting an integer (second node index)");
01462         else {
01463           n2 = atoi (fp->token->str);
01464           if (n2 == 0 || n2 > nn)
01465             gts_file_error (fp, "node index `%d' is out of range `[1,%d]'",
01466                             n2, nn);
01467           else {
01468             GtsGEdge * new_edge =
01469               gts_gedge_new (g->edge_class, nodes[n1 - 1], nodes [n2 - 1]);
01470 
01471             gts_file_next_token (fp);
01472             if (fp->type != '\n')
01473               if (GTS_OBJECT_CLASS (g->edge_class)->read)
01474                 (*GTS_OBJECT_CLASS (g->edge_class)->read)
01475                   ((GtsObject **) &new_edge, fp);
01476             gts_file_first_token_after (fp, '\n');
01477             n++;
01478           }
01479         }
01480       }
01481     }
01482   }
01483 
01484   if (fp->type == GTS_ERROR) {
01485     gts_allow_floating_gnodes = TRUE;
01486     while (nn)
01487       gts_object_destroy (GTS_OBJECT (nodes[nn-- - 1]));
01488     gts_allow_floating_gnodes = FALSE;
01489   }
01490   g_free (nodes);
01491 
01492   if (fp->type == GTS_ERROR) {
01493     gts_object_destroy (GTS_OBJECT (g));
01494     return NULL;
01495   }
01496   return g;
01497 }
01498 
01499 static void write_dot_node (GtsGNode * node, gpointer * data)
01500 {
01501   FILE * fp = data[0];
01502   guint * nnode = data[1];
01503 
01504   fprintf (fp, "  n%u", *nnode);
01505   if (GTS_GNODE_CLASS (GTS_OBJECT (node)->klass)->write) {
01506     fputs (" [", fp);
01507     (* GTS_GNODE_CLASS (GTS_OBJECT (node)->klass)->write) (node, fp);
01508     fputc (']', fp);
01509   }
01510   fputs (";\n", fp);
01511   GTS_OBJECT (node)->reserved = GUINT_TO_POINTER ((*nnode)++);  
01512 }
01513 
01514 static void write_dot_edge (GtsGEdge * edge, FILE * fp)
01515 {
01516   fprintf (fp, "  n%u -> n%u", 
01517            GPOINTER_TO_UINT (GTS_OBJECT (edge->n1)->reserved),
01518            GPOINTER_TO_UINT (GTS_OBJECT (edge->n2)->reserved));
01519   if (GTS_GEDGE_CLASS (GTS_OBJECT (edge)->klass)->write) {
01520     fputs (" [", fp);
01521     (* GTS_GEDGE_CLASS (GTS_OBJECT (edge)->klass)->write) (edge, fp);
01522     fputc (']', fp);
01523   }
01524   fputs (";\n", fp);
01525 }
01526 
01535 void gts_graph_write_dot (GtsGraph * g, FILE * fp)
01536 {
01537   guint nnode = 1;
01538   gpointer data[2];
01539 
01540   g_return_if_fail (g != NULL);
01541   g_return_if_fail (fp != NULL);
01542 
01543   fprintf (fp, "digraph \"%p\" {\n", g);
01544   data[0] = fp;
01545   data[1] = &nnode;
01546   gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) write_dot_node, data);
01547   gts_graph_foreach_edge (g, (GtsFunc) write_dot_edge, fp);
01548   fputs ("}\n", fp);
01549 
01550   gts_container_foreach (GTS_CONTAINER (g), 
01551                          (GtsFunc) gts_object_reset_reserved, NULL);
01552 }
01553 
01554 /* GtsWGraph */
01555 
01556 static gfloat wgraph_weight (GtsGraph * g)
01557 {
01558   return GTS_WGRAPH (g)->weight;
01559 }
01560 
01561 static void wgraph_add (GtsContainer * g, GtsContainee * n)
01562 {
01563   GtsWGraph * wg = GTS_WGRAPH (g);
01564   gfloat w = gts_gnode_weight (GTS_GNODE (n));
01565 
01566   wg->weight += w;
01567   
01568   (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_wgraph_class ())->parent_class)->add) (g, n);
01569 }
01570 
01571 static void wgraph_remove (GtsContainer * g, GtsContainee * n)
01572 {
01573   GTS_WGRAPH (g)->weight -= gts_gnode_weight (GTS_GNODE (n));
01574   
01575   (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_wgraph_class ())->parent_class)->remove) (g, n);
01576 }
01577 
01578 static void wgraph_class_init (GtsWGraphClass * klass)
01579 {
01580   GTS_GRAPH_CLASS (klass)->weight = wgraph_weight;
01581 
01582   GTS_CONTAINER_CLASS (klass)->add = wgraph_add;
01583   GTS_CONTAINER_CLASS (klass)->remove = wgraph_remove;
01584 }
01585 
01586 static void wgraph_init (GtsWGraph * g)
01587 {
01588   g->weight = 0.;
01589 }
01590 
01596 GtsWGraphClass * gts_wgraph_class (void)
01597 {
01598   static GtsWGraphClass * klass = NULL;
01599 
01600   if (klass == NULL) {
01601     GtsObjectClassInfo wgraph_info = {
01602       "GtsWGraph",
01603       sizeof (GtsWGraph),
01604       sizeof (GtsWGraphClass),
01605       (GtsObjectClassInitFunc) wgraph_class_init,
01606       (GtsObjectInitFunc) wgraph_init,
01607       (GtsArgSetFunc) NULL,
01608       (GtsArgGetFunc) NULL
01609     };
01610     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_graph_class ()),
01611                                   &wgraph_info);
01612   }
01613 
01614   return klass;
01615 }
01616 
01617 static void weight_max (GtsGNode * n, gfloat * wmax)
01618 {
01619   gfloat w = gts_gnode_weight (n);
01620 
01621   if (w > *wmax)
01622     *wmax = w;
01623 }
01624 
01631 gfloat gts_wgraph_weight_max (GtsWGraph * wg)
01632 {
01633   gfloat wmax = - G_MAXFLOAT;
01634 
01635   g_return_val_if_fail (wg != NULL, 0.);
01636 
01637   gts_container_foreach (GTS_CONTAINER (wg), (GtsFunc) weight_max, &wmax);
01638 
01639   return wmax;
01640 }
01641 
01642 /* Surface graph */
01643 
01644 static void create_node (GtsFace * f, GtsGraph * graph)
01645 {
01646   GtsFNode * fn = gts_fnode_new (gts_fnode_class (), f);
01647 
01648   gts_container_add (GTS_CONTAINER (graph), GTS_CONTAINEE (fn));
01649   GTS_OBJECT (f)->reserved = fn;
01650 }
01651 
01652 static void create_edge (GtsEdge * e, GtsSurface * s)
01653 {
01654   GSList * i = e->triangles;
01655   
01656   while (i) {
01657     GtsFace * f = i->data;
01658     if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, s)) {
01659       GSList * j = i->next;
01660       while (j) {
01661         GtsFace * f1 = j->data;
01662         if (GTS_IS_FACE (f1) && gts_face_has_parent_surface (f1, s))
01663           gts_pgedge_new (gts_pgedge_class (), 
01664                           GTS_OBJECT (f)->reserved,
01665                           GTS_OBJECT (f1)->reserved,
01666                           e);
01667         j = j->next;
01668       }
01669     }
01670     i = i->next;
01671   }
01672 }
01673 
01683 GtsGraph * gts_surface_graph_new (GtsGraphClass * klass,
01684                                   GtsSurface * s)
01685 {
01686   GtsGraph * graph;
01687   
01688   g_return_val_if_fail (klass != NULL, NULL);
01689   g_return_val_if_fail (s != NULL, NULL);
01690 
01691   graph = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass)));
01692   gts_surface_foreach_face (s, (GtsFunc) create_node, graph);
01693   gts_surface_foreach_edge (s, (GtsFunc) create_edge, s);
01694   gts_surface_foreach_face (s, (GtsFunc) gts_object_reset_reserved, NULL);
01695 
01696   return graph;
01697 }
01698 
01699 static void create_segment_edge (GtsSegment * s, GtsGraph * graph)
01700 {
01701   GtsGNode * n1 = GTS_OBJECT (s->v1)->reserved, * n2;
01702 
01703   if (n1 == NULL) {
01704     n1 = GTS_GNODE (gts_pnode_new (gts_pnode_class (), s->v1));
01705     gts_container_add (GTS_CONTAINER (graph), GTS_CONTAINEE (n1));
01706     GTS_OBJECT (s->v1)->reserved = n1;
01707   }
01708 
01709   n2 = GTS_OBJECT (s->v2)->reserved;
01710   if (n2 == NULL) {
01711     n2 = GTS_GNODE (gts_pnode_new (gts_pnode_class (), s->v2));
01712     gts_container_add (GTS_CONTAINER (graph), GTS_CONTAINEE (n2));
01713     GTS_OBJECT (s->v2)->reserved = n2;
01714   }
01715   
01716   gts_pgedge_new (gts_pgedge_class (), n1, n2, s);
01717 }
01718 
01719 static void reset_reserved (GtsSegment * s)
01720 {
01721   GTS_OBJECT (s->v1)->reserved = GTS_OBJECT (s->v2)->reserved = NULL;
01722 }
01723 
01732 GtsGraph * gts_segments_graph_new (GtsGraphClass * klass,
01733                                    GSList * segments)
01734 {
01735   GtsGraph * graph;
01736   
01737   g_return_val_if_fail (klass != NULL, NULL);
01738 
01739   graph = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass)));
01740   g_slist_foreach (segments, (GFunc) create_segment_edge, graph);
01741   g_slist_foreach (segments, (GFunc) reset_reserved, NULL);
01742 
01743   return graph;
01744 }
01745 
01746 static void add_to_surface (GtsGNode * n, GtsSurface * s)
01747 {
01748   if (GTS_IS_FNODE (n))
01749     gts_surface_add_face (s, GTS_FNODE (n)->f);
01750 }
01751 
01760 GtsSurface * gts_surface_graph_surface (GtsGraph * surface_graph,
01761                                         GtsSurface * s)
01762 {
01763   GtsSurface * s1;
01764 
01765   g_return_val_if_fail (surface_graph != NULL, NULL);
01766   g_return_val_if_fail (s != NULL, NULL);
01767   
01768   s1 = gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass),
01769                         s->face_class,
01770                         s->edge_class,
01771                         s->vertex_class);
01772   gts_container_foreach (GTS_CONTAINER (surface_graph), 
01773                          (GtsFunc) add_to_surface, s1);
01774   return s1;
01775 }
01776