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 "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