pcb 4.1.1
An interactive printed circuit board layout editor.

oocs.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 "gts.h"
00022 
00023 static void cluster_destroy (GtsObject * object)
00024 {
00025   GtsCluster * c = GTS_CLUSTER (object);
00026 
00027   if (c->v && gts_vertex_is_unattached (c->v))
00028     gts_object_destroy (GTS_OBJECT (c->v));
00029 
00030   /* do not forget to call destroy method of the parent */
00031   (* GTS_OBJECT_CLASS (gts_cluster_class ())->parent_class->destroy) (object);
00032 }
00033 
00034 static void cluster_add (GtsCluster * c, GtsPoint * p, gpointer data)
00035 {
00036   GtsPoint * cp;
00037 
00038   g_return_if_fail (c != NULL);
00039   g_return_if_fail (c->v != NULL);
00040   g_return_if_fail (p != NULL);
00041 
00042   cp = GTS_POINT (c->v);
00043   
00044   cp->x += p->x;
00045   cp->y += p->y;
00046   cp->z += p->z;
00047   c->n++;
00048 }
00049 
00050 static void cluster_update (GtsCluster * c)
00051 {
00052   GtsPoint * p;
00053 
00054   g_return_if_fail (c != NULL);
00055   g_return_if_fail (c->v != NULL);
00056 
00057   if (c->n > 1) {
00058     p = GTS_POINT (c->v);
00059     p->x /= c->n;
00060     p->y /= c->n;
00061     p->z /= c->n;
00062   }
00063 }
00064 
00065 static void cluster_class_init (GtsClusterClass * klass)
00066 {
00067   klass->add = cluster_add;
00068   klass->update = cluster_update;
00069 
00070   GTS_OBJECT_CLASS (klass)->destroy = cluster_destroy;
00071 }
00072 
00073 static void cluster_init (GtsCluster * c)
00074 {
00075   c->v = NULL;
00076   c->n = 0;
00077 }
00078 
00084 GtsClusterClass * gts_cluster_class (void)
00085 {
00086   static GtsClusterClass * klass = NULL;
00087 
00088   if (klass == NULL) {
00089     GtsObjectClassInfo cluster_info = {
00090       "GtsCluster",
00091       sizeof (GtsCluster),
00092       sizeof (GtsClusterClass),
00093       (GtsObjectClassInitFunc) cluster_class_init,
00094       (GtsObjectInitFunc) cluster_init,
00095       (GtsArgSetFunc) NULL,
00096       (GtsArgGetFunc) NULL
00097     };
00098     klass = gts_object_class_new (gts_object_class (), &cluster_info);
00099   }
00100 
00101   return klass;
00102 }
00103 
00112 GtsCluster * gts_cluster_new (GtsClusterClass * klass,
00113                               GtsClusterId id,
00114                               GtsVertexClass * vklass)
00115 {
00116   GtsCluster * c;
00117 
00118   c = GTS_CLUSTER (gts_object_new (GTS_OBJECT_CLASS (klass)));
00119   c->id = id;
00120   c->v = gts_vertex_new (vklass, 0., 0., 0.);
00121 
00122   return c;
00123 }
00124 
00133 void gts_cluster_add (GtsCluster * c, GtsPoint * p, gpointer data)
00134 {
00135   g_return_if_fail (c != NULL);
00136   g_return_if_fail (p != NULL);
00137 
00138   (* GTS_CLUSTER_CLASS (GTS_OBJECT (c)->klass)->add) (c, p, data);
00139 }
00140 
00148 void gts_cluster_update (GtsCluster * c)
00149 {
00150   g_return_if_fail (c != NULL);
00151 
00152   (* GTS_CLUSTER_CLASS (GTS_OBJECT (c)->klass)->update) (c);
00153 }
00154 
00155 static void destroy_cluster (GtsClusterId * id, GtsObject * cluster)
00156 {
00157   gts_object_destroy (cluster);
00158 }
00159 
00160 static void cluster_grid_destroy (GtsObject * object)
00161 {
00162   GtsClusterGrid * cluster_grid = GTS_CLUSTER_GRID (object);
00163 
00164   g_hash_table_foreach (cluster_grid->clusters, 
00165                         (GHFunc) destroy_cluster, NULL);
00166   g_hash_table_destroy (cluster_grid->clusters);
00167   
00168   (* GTS_OBJECT_CLASS (gts_cluster_grid_class ())->parent_class->destroy) 
00169     (object);
00170 }
00171 
00172 static void cluster_grid_class_init (GtsClusterGridClass * klass)
00173 {
00174   GTS_OBJECT_CLASS (klass)->destroy = cluster_grid_destroy;
00175 }
00176 
00177 static gint cluster_id_equal (gconstpointer v1,
00178                               gconstpointer v2)
00179 {
00180   const GtsClusterId * id1 = (const GtsClusterId *) v1;
00181   const GtsClusterId * id2 = (const GtsClusterId *) v2;
00182   return ((id1->x == id2->x) && (id1->y == id2->y) && (id1->z == id2->z));
00183 }
00184 
00185 static guint cluster_id_hash (gconstpointer key)
00186 {
00187   const GtsClusterId * id = (const GtsClusterId *) key;
00188   return id->x + id->y + id->z;
00189 }
00190 
00191 static void cluster_grid_init (GtsClusterGrid * cluster_grid)
00192 {
00193   cluster_grid->surface = NULL;
00194   cluster_grid->bbox = NULL;
00195   cluster_grid->cluster_class = gts_cluster_class ();
00196   cluster_grid->clusters = g_hash_table_new (cluster_id_hash,
00197                                               cluster_id_equal);
00198 }
00199 
00205 GtsClusterGridClass * gts_cluster_grid_class (void)
00206 {
00207   static GtsClusterGridClass * klass = NULL;
00208 
00209   if (klass == NULL) {
00210     GtsObjectClassInfo cluster_grid_info = {
00211       "GtsClusterGrid",
00212       sizeof (GtsClusterGrid),
00213       sizeof (GtsClusterGridClass),
00214       (GtsObjectClassInitFunc) cluster_grid_class_init,
00215       (GtsObjectInitFunc) cluster_grid_init,
00216       (GtsArgSetFunc) NULL,
00217       (GtsArgGetFunc) NULL
00218     };
00219     klass = gts_object_class_new (gts_object_class (), &cluster_grid_info);
00220   }
00221 
00222   return klass;
00223 }
00224 
00235 GtsClusterGrid * gts_cluster_grid_new (GtsClusterGridClass * klass,
00236                                        GtsClusterClass * cluster_class,
00237                                        GtsSurface * s,
00238                                        GtsBBox * bbox,
00239                                        gdouble delta)
00240 {
00241   GtsClusterGrid * cluster_grid;
00242   GtsVector size;
00243 
00244   g_return_val_if_fail (klass != NULL, NULL);
00245   g_return_val_if_fail (cluster_class != NULL, NULL);
00246   g_return_val_if_fail (s != NULL, NULL);
00247   g_return_val_if_fail (bbox != NULL, NULL);
00248   g_return_val_if_fail (delta > 0., NULL);
00249 
00250   size[0] = ceil ((bbox->x2 - bbox->x1)/delta);
00251   size[1] = ceil ((bbox->y2 - bbox->y1)/delta);
00252   size[2] = ceil ((bbox->z2 - bbox->z1)/delta);
00253   g_return_val_if_fail (size[0] <= 2.*G_MAXINT + 2. &&
00254                         size[1] <= 2.*G_MAXINT + 2. &&
00255                         size[2] <= 2.*G_MAXINT + 2., NULL);
00256   cluster_grid = 
00257     GTS_CLUSTER_GRID (gts_object_new (GTS_OBJECT_CLASS (klass)));
00258   cluster_grid->cluster_class = cluster_class;
00259   cluster_grid->surface = s;
00260   cluster_grid->bbox = bbox;
00261   cluster_grid->size[0] = size[0];
00262   cluster_grid->size[1] = size[1];
00263   cluster_grid->size[2] = size[2];
00264 
00265   return cluster_grid;
00266 }
00267 
00268 static GtsClusterId cluster_index (GtsPoint * p,
00269                                    GtsBBox * bb,
00270                                    GtsVector n)
00271 {
00272   GtsClusterId id = {0, 0, 0};
00273   
00274   g_return_val_if_fail (p->x >= bb->x1 && p->x <= bb->x2, id);
00275   g_return_val_if_fail (p->y >= bb->y1 && p->y <= bb->y2, id);
00276   g_return_val_if_fail (p->z >= bb->z1 && p->z <= bb->z2, id);
00277   
00278   id.x = (guint) (p->x == bb->x2 ? n[0] - 1. : n[0]*(p->x - bb->x1)/(bb->x2 - bb->x1));
00279   id.y = (guint) (p->y == bb->y2 ? n[1] - 1. : n[1]*(p->y - bb->y1)/(bb->y2 - bb->y1));
00280   id.z = (guint) (p->z == bb->z2 ? n[2] - 1. : n[2]*(p->z - bb->z1)/(bb->z2 - bb->z1));
00281 
00282   return id;
00283 }
00284 
00285 static GtsCluster * cluster_grid_add_point (GtsClusterGrid * cluster_grid,
00286                                             GtsPoint * p,
00287                                             gpointer data)
00288 {
00289   GtsClusterId id = cluster_index (p, 
00290                                    cluster_grid->bbox, 
00291                                    cluster_grid->size);
00292   GtsCluster * c = g_hash_table_lookup (cluster_grid->clusters, &id);
00293 
00294   if (c == NULL) {
00295     c = gts_cluster_new (cluster_grid->cluster_class, id, 
00296                          cluster_grid->surface->vertex_class);
00297     g_hash_table_insert (cluster_grid->clusters, &c->id, c);
00298   }
00299   
00300   gts_cluster_add (c, p, data);
00301   
00302   return c;
00303 }
00304 
00316 void gts_cluster_grid_add_triangle (GtsClusterGrid * cluster_grid,
00317                                     GtsPoint * p1,
00318                                     GtsPoint * p2,
00319                                     GtsPoint * p3,
00320                                     gpointer data)
00321 {
00322   GtsCluster * c1, * c2, * c3;
00323 
00324   g_return_if_fail (cluster_grid != NULL);
00325   g_return_if_fail (p1 != NULL);
00326   g_return_if_fail (p2 != NULL);
00327   g_return_if_fail (p3 != NULL);
00328   g_return_if_fail (cluster_grid->surface != NULL);
00329 
00330   c1 = cluster_grid_add_point (cluster_grid, p1, data);
00331   c2 = cluster_grid_add_point (cluster_grid, p2, data);
00332   c3 = cluster_grid_add_point (cluster_grid, p3, data);
00333   
00334   if (c1 != c2 && c2 != c3 && c3 != c1) {
00335     GtsVertex * v1, * v2, * v3;
00336     GtsEdge * e1, * e2, * e3;
00337     gboolean new_edge = FALSE;
00338     
00339     v1 = c1->v; v2 = c2->v; v3 = c3->v;
00340 
00341     if ((e1 = GTS_EDGE (gts_vertices_are_connected (v1, v2))) == NULL) {
00342       e1 = gts_edge_new (cluster_grid->surface->edge_class, v1, v2);
00343       new_edge = TRUE;
00344     }
00345     if ((e2 = GTS_EDGE (gts_vertices_are_connected (v2, v3))) == NULL) {
00346       e2 = gts_edge_new (cluster_grid->surface->edge_class, v2, v3);
00347       new_edge = TRUE;
00348     }
00349     if ((e3 = GTS_EDGE (gts_vertices_are_connected (v3, v1))) == NULL) {
00350       e3 = gts_edge_new (cluster_grid->surface->edge_class, v3, v1);
00351       new_edge = TRUE;
00352     }
00353     if (new_edge || !gts_triangle_use_edges (e1, e2, e3))
00354       gts_surface_add_face (cluster_grid->surface, 
00355                             gts_face_new (cluster_grid->surface->face_class, 
00356                                           e1, e2, e3));
00357   }
00358 }
00359 
00360 static void update_cluster (gint * id, GtsCluster * cluster, GtsRange * stats)
00361 {
00362   gts_cluster_update (cluster);
00363   gts_range_add_value (stats, cluster->n);
00364 }
00365 
00375 GtsRange gts_cluster_grid_update (GtsClusterGrid * cluster_grid)
00376 {
00377   GtsRange stats;
00378 
00379   gts_range_init (&stats);
00380   g_return_val_if_fail (cluster_grid != NULL, stats);
00381 
00382   g_hash_table_foreach (cluster_grid->clusters, 
00383                         (GHFunc) update_cluster, &stats);
00384   gts_range_update (&stats);
00385 
00386   return stats;
00387 }