pcb 4.1.1
An interactive printed circuit board layout editor.
|
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 (°ree); 00890 data[0] = g; 00891 data[1] = °ree; 00892 gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) compute_degree, data); 00893 gts_range_update (°ree); 00894 gts_range_print (°ree, 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