pcb 4.1.1
An interactive printed circuit board layout editor.

hsurface.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 <stdlib.h>
00021 #include <string.h>
00022 #include "gts.h"
00023 
00024 #define HEAP_INSERT_HSPLIT(h, e) ((e)->index = gts_eheap_insert (h, e))
00025 #define HEAP_REMOVE_HSPLIT(h, e) (gts_eheap_remove (h, (e)->index),\
00026                                   (e)->index = NULL)
00027 
00028 static void hsplit_init (GtsHSplit * hsplit)
00029 {
00030   hsplit->index = NULL;
00031   hsplit->parent = NULL;
00032   hsplit->nchild = 0;
00033 }
00034 
00040 GtsHSplitClass * gts_hsplit_class (void)
00041 {
00042   static GtsHSplitClass * klass = NULL;
00043 
00044   if (klass == NULL) {
00045     GtsObjectClassInfo hsplit_info = {
00046       "GtsHSplit",
00047       sizeof (GtsHSplit),
00048       sizeof (GtsHSplitClass),
00049       (GtsObjectClassInitFunc) NULL,
00050       (GtsObjectInitFunc) hsplit_init,
00051       (GtsArgSetFunc) NULL,
00052       (GtsArgGetFunc) NULL
00053     };
00054     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_split_class ()), 
00055                                   &hsplit_info);
00056   }
00057 
00058   return klass;
00059 }
00060 
00068 GtsHSplit * gts_hsplit_new (GtsHSplitClass * klass, GtsSplit * vs)
00069 {
00070   GtsHSplit * hs;
00071 
00072   g_return_val_if_fail (vs != NULL, NULL);
00073 
00074   hs = GTS_HSPLIT (gts_object_new (GTS_OBJECT_CLASS (klass)));
00075   memcpy (hs, vs, sizeof (GtsSplit));
00076   GTS_OBJECT (hs)->reserved = NULL;
00077 
00078   return hs;
00079 }
00080 
00089 void gts_hsplit_collapse (GtsHSplit * hs,
00090                           GtsHSurface * hsurface)
00091 {
00092   GtsHSplit * parent;
00093   GtsSplit * vs;
00094 
00095   g_return_if_fail (hs != NULL);
00096   g_return_if_fail (hs->nchild == 2);
00097   g_return_if_fail (hsurface != NULL);
00098 
00099   gts_split_collapse (GTS_SPLIT (hs), hsurface->s->edge_class, NULL);
00100 
00101   hsurface->nvertex--;
00102   hs->nchild = 0;
00103   HEAP_REMOVE_HSPLIT (hsurface->collapsable, hs);
00104   HEAP_INSERT_HSPLIT (hsurface->expandable, hs);
00105 
00106   vs = GTS_SPLIT (hs);
00107   if (GTS_IS_HSPLIT (vs->v1))
00108     HEAP_REMOVE_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v1));
00109   if (GTS_IS_HSPLIT (vs->v2))
00110     HEAP_REMOVE_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v2));
00111 
00112   parent = hs->parent;
00113   if (parent && ++parent->nchild == 2)
00114     HEAP_INSERT_HSPLIT (hsurface->collapsable, parent);
00115 }
00116 
00125 void gts_hsplit_expand (GtsHSplit * hs,
00126                         GtsHSurface * hsurface)
00127 {
00128   GtsHSplit * parent;
00129   GtsSplit * vs;
00130 
00131   g_return_if_fail (hs != NULL);
00132   g_return_if_fail (hsurface != NULL);
00133   g_return_if_fail (hs->nchild == 0);
00134 
00135   gts_split_expand (GTS_SPLIT (hs), hsurface->s, hsurface->s->edge_class);
00136   hsurface->nvertex++;
00137   hs->nchild = 2;
00138   HEAP_REMOVE_HSPLIT (hsurface->expandable, hs);
00139   HEAP_INSERT_HSPLIT (hsurface->collapsable, hs);
00140 
00141   vs = GTS_SPLIT (hs);
00142   if (GTS_IS_HSPLIT (vs->v1))
00143     HEAP_INSERT_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v1));
00144   if (GTS_IS_HSPLIT (vs->v2))
00145     HEAP_INSERT_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v2));
00146 
00147   parent = hs->parent;
00148   if (parent && parent->nchild-- == 2)
00149     HEAP_REMOVE_HSPLIT (hsurface->collapsable, parent);
00150 }
00151 
00152 static void hsurface_destroy (GtsObject * object)
00153 {
00154   GtsHSurface * hs = GTS_HSURFACE (object);
00155 
00156   gts_hsurface_traverse (hs, G_POST_ORDER, -1,
00157                          (GtsSplitTraverseFunc) gts_object_destroy, 
00158                          NULL);
00159   g_slist_free (hs->roots);
00160   if (hs->expandable)
00161     gts_eheap_destroy (hs->expandable);
00162   if (hs->collapsable)
00163     gts_eheap_destroy (hs->collapsable);
00164   g_ptr_array_free (hs->split, TRUE);
00165 
00166   (* GTS_OBJECT_CLASS (gts_hsurface_class ())->parent_class->destroy) (object);
00167 }
00168 
00169 static void hsurface_class_init (GtsObjectClass * klass)
00170 {
00171   klass->destroy = hsurface_destroy;
00172 }
00173 
00174 static void hsurface_init (GtsHSurface * hsurface)
00175 {
00176   hsurface->s = NULL;
00177   hsurface->roots = NULL;
00178   hsurface->expandable = hsurface->collapsable = NULL;
00179   hsurface->split = g_ptr_array_new ();
00180   hsurface->nvertex = 0;
00181 }
00182 
00188 GtsHSurfaceClass * gts_hsurface_class (void)
00189 {
00190   static GtsHSurfaceClass * klass = NULL;
00191 
00192   if (klass == NULL) {
00193     GtsObjectClassInfo hsurface_info = {
00194       "GtsHSurface",
00195       sizeof (GtsHSurface),
00196       sizeof (GtsHSurfaceClass),
00197       (GtsObjectClassInitFunc) hsurface_class_init,
00198       (GtsObjectInitFunc) hsurface_init,
00199       (GtsArgSetFunc) NULL,
00200       (GtsArgGetFunc) NULL
00201     };
00202     klass = gts_object_class_new (gts_object_class (), 
00203                                   &hsurface_info);
00204   }
00205 
00206   return klass;
00207 }
00208 
00225 GtsHSurface * gts_hsurface_new (GtsHSurfaceClass * klass,
00226                                 GtsHSplitClass * hsplit_class,
00227                                 GtsPSurface * psurface,
00228                                 GtsKeyFunc expand_key,
00229                                 gpointer expand_data,
00230                                 GtsKeyFunc collapse_key,
00231                                 gpointer collapse_data)
00232 {
00233   GtsHSurface * hsurface;
00234 
00235   g_return_val_if_fail (klass != NULL, NULL);
00236   g_return_val_if_fail (hsplit_class != NULL, NULL);
00237   g_return_val_if_fail (psurface != NULL, NULL);
00238   g_return_val_if_fail (expand_key != NULL, NULL);
00239   g_return_val_if_fail (collapse_key != NULL, NULL);
00240 
00241   hsurface = GTS_HSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass)));
00242   hsurface->s = psurface->s;
00243   hsurface->expandable = gts_eheap_new (expand_key, expand_data);
00244   hsurface->collapsable = gts_eheap_new (collapse_key, collapse_data);
00245   g_ptr_array_set_size (hsurface->split, psurface->split->len);
00246 
00247   while (gts_psurface_remove_vertex (psurface))
00248     ;
00249   while (psurface->pos) {
00250     GtsSplit * vs = g_ptr_array_index (psurface->split, psurface->pos - 1);
00251     GtsHSplit * hs = gts_hsplit_new (hsplit_class, vs);
00252 
00253     g_ptr_array_index (hsurface->split, psurface->pos - 1) = hs;
00254     psurface->pos--;
00255 
00256     hs->parent = GTS_OBJECT (vs)->reserved;
00257     if (hs->parent) {
00258       GtsSplit * vsp = GTS_SPLIT (hs->parent);
00259 
00260       if (vsp->v1 == GTS_OBJECT (vs)) {
00261         g_assert (vsp->v2 != GTS_OBJECT (vs));
00262         vsp->v1 = GTS_OBJECT (hs);
00263       }
00264       else {
00265         g_assert (vsp->v2 == GTS_OBJECT (vs));
00266         vsp->v2 = GTS_OBJECT (hs);
00267       }
00268     }
00269     else
00270       hsurface->roots = g_slist_prepend (hsurface->roots, hs);
00271 
00272     hs->nchild = 0;
00273     if (GTS_IS_SPLIT (vs->v1))
00274       GTS_OBJECT (vs->v1)->reserved = hs;
00275     else
00276       hs->nchild++;
00277     if (GTS_IS_SPLIT (vs->v2))
00278       GTS_OBJECT (vs->v2)->reserved = hs;
00279     else
00280       hs->nchild++;
00281     
00282     gts_split_expand (vs, psurface->s, psurface->s->edge_class);
00283 
00284     if (hs->nchild == 2)
00285       HEAP_INSERT_HSPLIT (hsurface->collapsable, hs);
00286   }
00287 
00288   hsurface->nvertex = gts_surface_vertex_number (hsurface->s);
00289   gts_object_destroy (GTS_OBJECT (psurface));
00290 
00291   return hsurface;
00292 }
00293 
00309 void gts_hsurface_traverse (GtsHSurface *    hsurface,
00310                             GTraverseType    order,
00311                             gint             depth,
00312                             GtsSplitTraverseFunc func,
00313                             gpointer         data)
00314 {
00315   GSList * i;
00316 
00317   g_return_if_fail (hsurface != NULL);
00318   g_return_if_fail (func != NULL);
00319   g_return_if_fail (order < G_LEVEL_ORDER);
00320   g_return_if_fail (depth == -1 || depth > 0);
00321 
00322   i = hsurface->roots;
00323   while (i) {
00324     gts_split_traverse (i->data, order, depth, func, data);
00325     i = i->next;
00326   }
00327 }
00328 
00343 void gts_hsurface_foreach (GtsHSurface * hsurface,
00344                            GTraverseType order,
00345                            GtsFunc       func,
00346                            gpointer      data)
00347 {
00348   GtsHSplit * hs;
00349   guint i = 0, len;
00350   gboolean stop = FALSE;
00351 
00352   g_return_if_fail (hsurface != NULL);
00353   g_return_if_fail (func != NULL);
00354   g_return_if_fail (order == G_PRE_ORDER || order == G_POST_ORDER);
00355 
00356   while ((hs = gts_eheap_top (hsurface->expandable, NULL))) 
00357     gts_hsplit_expand (hs, hsurface);
00358 
00359   len = hsurface->split->len;
00360   switch (order) {
00361   case G_PRE_ORDER:
00362     while (i < len && !stop) {
00363       GtsHSplit * hs = g_ptr_array_index (hsurface->split, i);
00364       stop = (*func) (hs, data);
00365       if (!stop)
00366         gts_hsplit_collapse (hs, hsurface);
00367       i++;
00368     }
00369     break;
00370   case G_POST_ORDER:
00371     while (i < len && !stop) {
00372       GtsHSplit * hs = g_ptr_array_index (hsurface->split, i);
00373       gts_hsplit_collapse (hs, hsurface);
00374       stop = (*func) (hs, data);
00375       i++;
00376     }
00377     break;
00378   default:
00379     g_assert_not_reached ();
00380   }
00381 }
00382 
00389 guint gts_hsurface_height (GtsHSurface * hsurface)
00390 {
00391   GSList * i;
00392   guint height = 0;
00393 
00394   g_return_val_if_fail (hsurface != NULL, 0);
00395 
00396   i = hsurface->roots;
00397   while (i) {
00398     guint tmp_height = gts_split_height (i->data);
00399     if (tmp_height > height)
00400       height = tmp_height;
00401     i = i->next;
00402   }
00403 
00404   return height;
00405 }