pcb 4.1.1
An interactive printed circuit board layout editor.

pgraph.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 "gts.h"
00021 
00022 /* GtsGNodeSplit */
00023 
00024 static void gnode_split_destroy (GtsObject * object)
00025 {
00026   GtsGNodeSplit * ns = GTS_GNODE_SPLIT (object);
00027 
00028   if (gts_container_size (GTS_CONTAINER (ns->n)) == 0) {
00029     g_assert (GTS_SLIST_CONTAINEE (ns->n)->containers == NULL);
00030     gts_object_destroy (GTS_OBJECT (ns->n));
00031   }
00032   else {
00033     /* GtsGNode * n1 = GTS_GNODE_SPLIT_N1 (ns); */
00034     /* GtsGNode * n2 = GTS_GNODE_SPLIT_N2 (ns); */
00035 
00036     g_warning ("Memory deallocation for GtsGNodeSplit not fully implemented yet: memory leak!");
00037   }
00038 
00039   (* GTS_OBJECT_CLASS (gts_gnode_split_class ())->parent_class->destroy) 
00040     (object);
00041 }
00042 
00043 static void gnode_split_class_init (GtsGNodeSplitClass * klass)
00044 {
00045   GTS_OBJECT_CLASS (klass)->destroy = gnode_split_destroy;
00046 }
00047 
00048 static void gnode_split_init (GtsGNodeSplit * ns)
00049 {
00050   ns->n = NULL;
00051   ns->n1 = ns->n2 = NULL;
00052 }
00053 
00059 GtsGNodeSplitClass * gts_gnode_split_class (void)
00060 {
00061   static GtsGNodeSplitClass * klass = NULL;
00062 
00063   if (klass == NULL) {
00064     GtsObjectClassInfo gnode_split_info = {
00065       "GtsGNodeSplit",
00066       sizeof (GtsGNodeSplit),
00067       sizeof (GtsGNodeSplitClass),
00068       (GtsObjectClassInitFunc) gnode_split_class_init,
00069       (GtsObjectInitFunc) gnode_split_init,
00070       (GtsArgSetFunc) NULL,
00071       (GtsArgGetFunc) NULL
00072     };
00073     klass = gts_object_class_new (gts_object_class (), &gnode_split_info);
00074   }
00075 
00076   return klass;
00077 }
00078 
00091 GtsGNodeSplit * gts_gnode_split_new (GtsGNodeSplitClass * klass,
00092                                      GtsGNode * n, 
00093                                      GtsObject * n1,
00094                                      GtsObject * n2)
00095 {
00096   GtsGNodeSplit * ns;
00097 
00098   g_return_val_if_fail (klass != NULL, NULL);
00099   g_return_val_if_fail (n != NULL, NULL);
00100   g_return_val_if_fail (GTS_IS_GNODE_SPLIT (n1) || GTS_IS_GNODE (n1), NULL);
00101   g_return_val_if_fail (GTS_IS_GNODE_SPLIT (n2) || GTS_IS_GNODE (n2), NULL);
00102 
00103   ns = GTS_GNODE_SPLIT (gts_object_new (GTS_OBJECT_CLASS (klass)));
00104   ns->n = n;
00105   ns->n1 = n1;
00106   ns->n2 = n2;
00107 
00108   return ns;
00109 }
00110 
00111 static void connect_edge (GtsGEdge * e, gpointer * data)
00112 {
00113   GtsGNode * n = data[0];
00114   GtsGNode * n1 = data[1];
00115   GtsGNode * n2 = data[2];
00116 
00117   if (GTS_OBJECT (e)->reserved || /* edge is disconnected */
00118       gts_gedge_connects (e, n1, n2))
00119     return;
00120   if (e->n1 == n1 || e->n1 == n2)
00121     e->n1 = n;
00122   else if (e->n2 == n1 || e->n2 == n2)
00123     e->n2 = n;
00124   else
00125     g_assert_not_reached ();
00126   gts_container_add (GTS_CONTAINER (n), GTS_CONTAINEE (e));
00127 }
00128 
00138 void gts_gnode_split_collapse (GtsGNodeSplit * ns,
00139                                GtsGraph * g,
00140                                GtsWGEdgeClass * klass)
00141 {
00142   GtsGNode * n1, * n2;
00143   GSList * i;
00144   gpointer data[3];
00145 
00146   g_return_if_fail (ns != NULL);
00147   g_return_if_fail (g != NULL);
00148   g_return_if_fail (gts_container_size (GTS_CONTAINER (ns->n)) == 0);
00149 
00150   n1 = GTS_GNODE_SPLIT_N1 (ns);
00151   n2 = GTS_GNODE_SPLIT_N2 (ns);
00152 
00153   /* look for triangles */
00154   i = GTS_SLIST_CONTAINER (n1)->items;
00155   while (i) {
00156     GtsGEdge * e13 = i->data;
00157     GtsGNode * n3 = GTS_GNODE_NEIGHBOR (n1, e13);
00158     if (n3 != n2) {
00159       GSList * j = GTS_SLIST_CONTAINER (n3)->items;
00160       while (j) {
00161         GtsGEdge * e32 = j->data;
00162         GSList * next = j->next;
00163         GtsGNode * n4 = GTS_GNODE_NEIGHBOR (n3, e32);
00164         if (n4 == n2) { /* found triangle n1 (e13) n3 (e32) n2 */
00165           gts_wgedge_new (klass, ns->n, n3,
00166                           gts_gedge_weight (e13) + gts_gedge_weight (e32));
00167           GTS_OBJECT (e13)->reserved = n3;
00168           GTS_OBJECT (e32)->reserved = n3;
00169           GTS_SLIST_CONTAINER (n3)->items = 
00170             g_slist_remove (GTS_SLIST_CONTAINER (n3)->items, e32);
00171         }
00172         j = next;
00173       }
00174       if (GTS_OBJECT (e13)->reserved == n3)
00175         GTS_SLIST_CONTAINER (n3)->items = 
00176           g_slist_remove (GTS_SLIST_CONTAINER (n3)->items, e13);
00177     }
00178     i = i->next;
00179   }
00180 
00181   /* connect edges to new node */
00182   data[0] = ns->n;
00183   data[1] = n1;
00184   data[2] = n2;
00185   gts_container_foreach (GTS_CONTAINER (n1), (GtsFunc) connect_edge, data);
00186   gts_container_foreach (GTS_CONTAINER (n2), (GtsFunc) connect_edge, data);
00187 
00188   gts_allow_floating_gnodes = TRUE;
00189   gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (n1));
00190   gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (n2));
00191   gts_allow_floating_gnodes = FALSE;
00192   gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (ns->n));
00193 }
00194 
00195 static void restore_edge (GtsGEdge * e, gpointer * data)
00196 {
00197   GtsGNode * n = data[0];
00198   GtsGNode * n1 = data[1];
00199   GtsGNode * n2 = data[2];
00200   GtsGNode * n3 = GTS_OBJECT (e)->reserved;
00201 
00202   if (n3) { /* e is a disconnected edge */
00203     GTS_OBJECT (e)->reserved = NULL;
00204     gts_container_add (GTS_CONTAINER (n3), GTS_CONTAINEE (e));
00205     return;
00206   }
00207 
00208   if (gts_gedge_connects (e, n1, n2))
00209     return;
00210 
00211   if (e->n1 == n)
00212     e->n1 = n1;
00213   else if (e->n2 == n)
00214     e->n2 = n1;
00215   else
00216     g_assert_not_reached ();
00217   GTS_SLIST_CONTAINER (n)->items = 
00218     g_slist_remove (GTS_SLIST_CONTAINER (n)->items, e);
00219 }
00220 
00228 void gts_gnode_split_expand (GtsGNodeSplit * ns,
00229                              GtsGraph * g)
00230 {
00231   GtsGNode * n1, * n2;
00232   gpointer data[3];
00233   GSList * i;
00234 
00235   g_return_if_fail (ns != NULL);
00236   g_return_if_fail (g != NULL);
00237   g_return_if_fail (gts_containee_is_contained (GTS_CONTAINEE (ns->n), 
00238                                                 GTS_CONTAINER (g)));
00239 
00240   n1 = GTS_GNODE_SPLIT_N1 (ns);
00241   n2 = GTS_GNODE_SPLIT_N2 (ns);
00242 
00243   data[0] = ns->n;
00244   data[1] = n1;
00245   data[2] = n2;
00246   gts_container_foreach (GTS_CONTAINER (n1), (GtsFunc) restore_edge, data);
00247   data[1] = n2;
00248   data[2] = n1;
00249   gts_container_foreach (GTS_CONTAINER (n2), (GtsFunc) restore_edge, data);
00250 
00251   i = GTS_SLIST_CONTAINER (ns->n)->items;
00252   while (i) {
00253     GSList * next = i->next;
00254     gts_container_remove (GTS_CONTAINER (ns->n), GTS_CONTAINEE (i->data));
00255     i = next;
00256   }
00257   g_assert (gts_container_size (GTS_CONTAINER (ns->n)) == 0);
00258   
00259   gts_allow_floating_gnodes = TRUE;
00260   gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (ns->n));
00261   gts_allow_floating_gnodes = FALSE;
00262 
00263   gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n1));
00264   gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n2));
00265 }
00266 
00267 /* GtsPGraph */
00268 
00269 static void pgraph_destroy (GtsObject * object)
00270 {
00271   GtsPGraph * pg = GTS_PGRAPH (object);
00272   guint i;
00273 
00274   for (i = 0; i < pg->split->len; i++)
00275     gts_object_destroy (GTS_OBJECT (g_ptr_array_index (pg->split, i)));
00276   g_ptr_array_free (pg->split, TRUE);
00277   g_array_free (pg->levels, TRUE);
00278 
00279   (* GTS_OBJECT_CLASS (gts_pgraph_class ())->parent_class->destroy) (object);
00280 }
00281 
00282 static void pgraph_class_init (GtsPGraphClass * klass)
00283 {
00284   GTS_OBJECT_CLASS (klass)->destroy = pgraph_destroy;
00285 }
00286 
00287 static void pgraph_init (GtsPGraph * pg)
00288 {
00289   pg->g = NULL;
00290   pg->split = g_ptr_array_new ();
00291   pg->levels = g_array_new (FALSE, FALSE, sizeof (guint));
00292   pg->level = 0;
00293   pg->split_class = gts_gnode_split_class ();
00294   pg->edge_class = gts_wgedge_class ();
00295   pg->pos = pg->min = 0;
00296 }
00297 
00303 GtsPGraphClass * gts_pgraph_class (void)
00304 {
00305   static GtsPGraphClass * klass = NULL;
00306 
00307   if (klass == NULL) {
00308     GtsObjectClassInfo pgraph_info = {
00309       "GtsPGraph",
00310       sizeof (GtsPGraph),
00311       sizeof (GtsPGraphClass),
00312       (GtsObjectClassInitFunc) pgraph_class_init,
00313       (GtsObjectInitFunc) pgraph_init,
00314       (GtsArgSetFunc) NULL,
00315       (GtsArgGetFunc) NULL
00316     };
00317     klass = gts_object_class_new (gts_object_class (), &pgraph_info);
00318   }
00319 
00320   return klass;
00321 }
00322 
00323 static void match_neighbor (GtsGNode * n, gpointer * data)
00324 {
00325   if (!GTS_OBJECT (n)->reserved) {
00326     GtsGraph * g = data[0];
00327     GSList ** list = data[1];
00328     GSList * i = GTS_SLIST_CONTAINER (n)->items;
00329     gfloat wmax = - G_MAXFLOAT;
00330     GtsGEdge * emax = NULL;
00331     
00332     while (i) {
00333       GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
00334       if (!GTS_OBJECT (n1)->reserved &&
00335           gts_gedge_weight (i->data) > wmax &&
00336           gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g))) {
00337         emax = i->data;
00338         wmax = gts_gedge_weight (emax);
00339       }
00340       i = i->next;
00341     }
00342     if (emax) {
00343       GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, emax);
00344 
00345       GTS_OBJECT (n1)->reserved = n;
00346       GTS_OBJECT (n)->reserved = n1;
00347       *list = g_slist_prepend (*list, emax);
00348     }
00349   }
00350 }
00351 
00352 static GSList * maximal_matching (GtsGraph * g)
00353 {
00354   GSList * list = NULL;
00355   gpointer data[2];
00356 
00357   data[0] = g;
00358   data[1] = &list;
00359   gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) match_neighbor, data);
00360   gts_container_foreach (GTS_CONTAINER (g), 
00361                          (GtsFunc) gts_object_reset_reserved,
00362                          NULL);
00363 
00364   return list;
00365 }
00366 
00388 GtsPGraph * gts_pgraph_new (GtsPGraphClass * klass,
00389                             GtsGraph * g,
00390                             GtsGNodeSplitClass * split_class,
00391                             GtsWGNodeClass * node_class,
00392                             GtsWGEdgeClass * edge_class,
00393                             guint min)
00394 {
00395   GtsPGraph * pg;
00396   GSList * matching;
00397 
00398   g_return_val_if_fail (klass != NULL, NULL);
00399   g_return_val_if_fail (g != NULL, NULL);
00400   g_return_val_if_fail (split_class != NULL, NULL);
00401   g_return_val_if_fail (node_class != NULL, NULL);
00402   g_return_val_if_fail (edge_class != NULL, NULL);
00403 
00404   pg = GTS_PGRAPH (gts_object_new (GTS_OBJECT_CLASS (klass)));
00405   pg->g = g;
00406   pg->split_class = split_class;
00407   pg->edge_class = edge_class;
00408 
00409   while (gts_container_size (GTS_CONTAINER (g)) > min &&
00410          (matching = maximal_matching (g))) {
00411     GSList * i = matching;
00412     guint size = gts_container_size (GTS_CONTAINER (g));
00413 
00414     g_array_append_val (pg->levels, size);
00415 
00416     while (i && gts_container_size (GTS_CONTAINER (g)) > min) {
00417       GtsGEdge * e = i->data;
00418       GtsGNode * n = GTS_GNODE (gts_wgnode_new (node_class,
00419                                                 gts_gnode_weight (e->n1) +
00420                                                 gts_gnode_weight (e->n2)));
00421       GtsGNodeSplit * ns = gts_gnode_split_new (split_class, n,
00422                                                 GTS_OBJECT (e->n1),
00423                                                 GTS_OBJECT (e->n2));
00424       gts_gnode_split_collapse (ns, g, edge_class);
00425       g_ptr_array_add (pg->split, ns);
00426       i = i->next;
00427     }
00428     g_slist_free (matching);
00429   }
00430 
00431   pg->pos = pg->split->len;
00432   pg->min = gts_container_size (GTS_CONTAINER (g));
00433   pg->level = pg->levels->len;
00434   
00435   return pg;
00436 }
00437 
00448 GtsGNodeSplit * gts_pgraph_add_node (GtsPGraph * pg)
00449 { 
00450   GtsGNodeSplit * ns;
00451 
00452   g_return_val_if_fail (pg != NULL, NULL);
00453 
00454   if (pg->pos == 0)
00455     return NULL;
00456 
00457   ns = g_ptr_array_index (pg->split, --pg->pos);
00458   gts_gnode_split_expand (ns, pg->g);
00459 
00460   return ns;
00461 }
00462 
00473 GtsGNodeSplit * gts_pgraph_remove_node (GtsPGraph * pg)
00474 {
00475   GtsGNodeSplit * ns;
00476 
00477   g_return_val_if_fail (pg != NULL, NULL);
00478 
00479   if (pg->pos == pg->split->len)
00480     return NULL;
00481 
00482   ns = g_ptr_array_index (pg->split, pg->pos++);
00483   gts_gnode_split_collapse (ns, pg->g, pg->edge_class);
00484 
00485   return ns;
00486 }
00487 
00495 guint gts_pgraph_max_node_number (GtsPGraph * pg)
00496 {
00497   g_return_val_if_fail (pg != NULL, 0);
00498 
00499   return pg->min + pg->split->len;
00500 }
00501 
00509 guint gts_pgraph_min_node_number (GtsPGraph * pg)
00510 {
00511   g_return_val_if_fail (pg != NULL, 0);
00512 
00513   return pg->min;
00514 }
00515 
00524 void gts_pgraph_set_node_number (GtsPGraph * pg, guint n)
00525 {
00526   g_return_if_fail (pg != NULL);
00527 
00528   n = pg->min + pg->split->len - n;
00529   while (pg->pos > n && gts_pgraph_add_node (pg))
00530     ;
00531   while (pg->pos < n && gts_pgraph_remove_node (pg))
00532     ;
00533 }
00534 
00541 guint gts_pgraph_get_node_number (GtsPGraph * pg)
00542 {
00543   g_return_val_if_fail (pg != NULL, 0);
00544   
00545   return pg->min + pg->split->len - pg->pos;
00546 }
00547 
00563 gboolean gts_pgraph_down (GtsPGraph * pg,
00564                           GtsFunc func,
00565                           gpointer data)
00566 {
00567   guint size;
00568 
00569   g_return_val_if_fail (pg != NULL, FALSE);
00570 
00571   if (pg->level == 0)
00572     return FALSE;
00573 
00574   size = g_array_index (pg->levels, guint, --(pg->level));
00575   while (gts_container_size (GTS_CONTAINER (pg->g)) < size) {
00576     GtsGNodeSplit * ns = gts_pgraph_add_node (pg);
00577 
00578     g_assert (ns);
00579     if (func)
00580       (* func) (ns, data);
00581   }
00582   return TRUE;
00583 }
00584