pcb 4.1.1
An interactive printed circuit board layout editor.

iso.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 typedef enum { LEFT = 0, RIGHT = 1 } Orientation;
00023 
00024 typedef struct {
00025   GtsVertex * v;
00026   Orientation orientation;
00027 } OrientedVertex;
00028 
00029 struct _GtsIsoSlice {
00030   OrientedVertex *** vertices;
00031   guint nx, ny;
00032 };
00033 
00034 /* coordinates of the edges of the cube (see doc/isocube.fig) */
00035 static guint c[12][4] = {
00036   {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 1}, {0, 0, 1, 0},
00037   {1, 0, 0, 0}, {1, 0, 0, 1}, {1, 1, 0, 1}, {1, 1, 0, 0},
00038   {2, 0, 0, 0}, {2, 1, 0, 0}, {2, 1, 1, 0}, {2, 0, 1, 0}};
00039 
00040 /* first index is the edge number, second index is the edge orientation 
00041    (RIGHT or LEFT), third index are the edges which this edge may connect to
00042    in order */
00043 static guint edge[12][2][3] = {
00044   {{9, 1, 8}, {4, 3, 7}},   /* 0 */
00045   {{6, 2, 5}, {8, 0, 9}},   /* 1 */
00046   {{10, 3, 11}, {5, 1, 6}}, /* 2 */
00047   {{7, 0, 4}, {11, 2, 10}}, /* 3 */
00048   {{3, 7, 0}, {8, 5, 11}},  /* 4 */
00049   {{11, 4, 8}, {1, 6, 2}},  /* 5 */
00050   {{2, 5, 1}, {9, 7, 10}},  /* 6 */
00051   {{10, 6, 9}, {0, 4, 3}},  /* 7 */
00052   {{5, 11, 4}, {0, 9, 1}},  /* 8 */
00053   {{1, 8, 0}, {7, 10, 6}},  /* 9 */
00054   {{6, 9, 7}, {3, 11, 2}},  /* 10 */
00055   {{2, 10, 3}, {4, 8, 5}}   /* 11 */
00056 };
00057 
00058 static void ** malloc2D (guint nx, guint ny, gulong size)
00059 {
00060   void ** m = g_malloc (nx*sizeof (void *));
00061   guint i;
00062 
00063   for (i = 0; i < nx; i++)
00064     m[i] = g_malloc0 (ny*size);
00065 
00066   return m;
00067 }
00068 
00069 static void free2D (void ** m, guint nx)
00070 {
00071   guint i;
00072 
00073   g_return_if_fail (m != NULL);
00074 
00075   for (i = 0; i < nx; i++)
00076     g_free (m[i]);
00077   g_free (m);
00078 }
00079 
00087 GtsGridPlane * gts_grid_plane_new (guint nx, guint ny)
00088 {
00089   GtsGridPlane * g = g_malloc (sizeof (GtsGridPlane));
00090 
00091   g->p = (GtsPoint **) malloc2D (nx, ny, sizeof (GtsPoint));
00092   g->nx = nx;
00093   g->ny = ny;
00094   
00095   return g;
00096 }
00097 
00103 void gts_grid_plane_destroy (GtsGridPlane * g)
00104 {
00105   g_return_if_fail (g != NULL);
00106 
00107   free2D ((void **) g->p, g->nx);
00108   g_free (g);
00109 }
00110 
00118 GtsIsoSlice * gts_iso_slice_new (guint nx, guint ny)
00119 {
00120   GtsIsoSlice * slice;
00121 
00122   g_return_val_if_fail (nx > 1, NULL);
00123   g_return_val_if_fail (ny > 1, NULL);
00124 
00125   slice = g_malloc (sizeof (GtsIsoSlice));
00126 
00127   slice->vertices = g_malloc (3*sizeof (OrientedVertex **));
00128   slice->vertices[0] = 
00129     (OrientedVertex **) malloc2D (nx, ny, sizeof (OrientedVertex));
00130   slice->vertices[1] = 
00131     (OrientedVertex **) malloc2D (nx - 1, ny, sizeof (OrientedVertex));
00132   slice->vertices[2] = 
00133     (OrientedVertex **) malloc2D (nx, ny - 1, sizeof (OrientedVertex));
00134   slice->nx = nx;
00135   slice->ny = ny;
00136 
00137   return slice;
00138 }
00139 
00154 void gts_iso_slice_fill (GtsIsoSlice * slice,
00155                          GtsGridPlane * plane1,
00156                          GtsGridPlane * plane2,
00157                          gdouble ** f1,
00158                          gdouble ** f2,
00159                          gdouble iso,
00160                          GtsVertexClass * klass)
00161 {
00162   OrientedVertex *** vertices;
00163   GtsPoint ** p1, ** p2 = NULL;
00164   guint i, j, nx, ny;
00165 
00166   g_return_if_fail (slice != NULL);
00167   g_return_if_fail (plane1 != NULL);
00168   g_return_if_fail (f1 != NULL);
00169   g_return_if_fail (f2 == NULL || plane2 != NULL);
00170 
00171   p1 = plane1->p;
00172   if (plane2) 
00173     p2 = plane2->p;
00174   vertices = slice->vertices;
00175   nx = slice->nx;
00176   ny = slice->ny;
00177 
00178   if (f2)
00179     for (i = 0; i < nx; i++)
00180       for (j = 0; j < ny; j++) {
00181         gdouble v1 = f1[i][j] - iso;
00182         gdouble v2 = f2[i][j] - iso;
00183         if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
00184           gdouble c2 = v1/(v1 - v2), c1 = 1. - c2;
00185           vertices[0][i][j].v = 
00186             gts_vertex_new (klass,
00187                             c1*p1[i][j].x + c2*p2[i][j].x,
00188                             c1*p1[i][j].y + c2*p2[i][j].y,
00189                             c1*p1[i][j].z + c2*p2[i][j].z);
00190           vertices[0][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
00191         }
00192         else
00193           vertices[0][i][j].v = NULL;
00194       }
00195   for (i = 0; i < nx - 1; i++)
00196     for (j = 0; j < ny; j++) {
00197       gdouble v1 = f1[i][j] - iso;
00198       gdouble v2 = f1[i+1][j] - iso;
00199       if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
00200         gdouble c2 = v1/(v1 - v2), c1 = 1. - c2;
00201         vertices[1][i][j].v = 
00202           gts_vertex_new (klass,
00203                           c1*p1[i][j].x + c2*p1[i+1][j].x,
00204                           c1*p1[i][j].y + c2*p1[i+1][j].y,
00205                           c1*p1[i][j].z + c2*p1[i+1][j].z);
00206         vertices[1][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
00207       }
00208       else
00209         vertices[1][i][j].v = NULL;
00210     }
00211   for (i = 0; i < nx; i++)
00212     for (j = 0; j < ny - 1; j++) {
00213       gdouble v1 = f1[i][j] - iso;
00214       gdouble v2 = f1[i][j+1] - iso;
00215       if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
00216         gdouble c2 = v1/(v1 - v2), c1 = 1. - c2;
00217         vertices[2][i][j].v = 
00218           gts_vertex_new (klass,
00219                           c1*p1[i][j].x + c2*p1[i][j+1].x,
00220                           c1*p1[i][j].y + c2*p1[i][j+1].y,
00221                           c1*p1[i][j].z + c2*p1[i][j+1].z);
00222         vertices[2][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
00223       }
00224       else
00225         vertices[2][i][j].v = NULL;
00226     }
00227 }
00228  
00241 void gts_iso_slice_fill_cartesian (GtsIsoSlice * slice,
00242                                    GtsCartesianGrid g,
00243                                    gdouble ** f1,
00244                                    gdouble ** f2,
00245                                    gdouble iso,
00246                                    GtsVertexClass * klass)
00247 {
00248   OrientedVertex *** vertices;
00249   guint i, j;
00250   gdouble x, y;
00251 
00252   g_return_if_fail (slice != NULL);
00253   g_return_if_fail (f1 != NULL);
00254 
00255   vertices = slice->vertices;
00256 
00257   if (f2)
00258     for (i = 0, x = g.x; i < g.nx; i++, x += g.dx)
00259       for (j = 0, y = g.y; j < g.ny; j++, y += g.dy) {
00260         gdouble v1 = f1[i][j] - iso;
00261         gdouble v2 = f2[i][j] - iso;
00262         if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
00263           vertices[0][i][j].v = 
00264             gts_vertex_new (klass,
00265                             x, y, g.z + g.dz*v1/(v1 - v2));
00266           vertices[0][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
00267         }
00268         else
00269           vertices[0][i][j].v = NULL;
00270       }
00271   for (i = 0, x = g.x; i < g.nx - 1; i++, x += g.dx)
00272     for (j = 0, y = g.y; j < g.ny; j++, y += g.dy) {
00273       gdouble v1 = f1[i][j] - iso;
00274       gdouble v2 = f1[i+1][j] - iso;
00275       if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
00276         vertices[1][i][j].v = 
00277           gts_vertex_new (klass, x + g.dx*v1/(v1 - v2), y, g.z);
00278         vertices[1][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
00279       }
00280       else
00281         vertices[1][i][j].v = NULL;
00282     }
00283   for (i = 0, x = g.x; i < g.nx; i++, x += g.dx)
00284     for (j = 0, y = g.y; j < g.ny - 1; j++, y += g.dy) {
00285       gdouble v1 = f1[i][j] - iso;
00286       gdouble v2 = f1[i][j+1] - iso;
00287       if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
00288         vertices[2][i][j].v = 
00289           gts_vertex_new (klass, x, y + g.dy*v1/(v1 - v2), g.z);
00290         vertices[2][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
00291       }
00292       else
00293         vertices[2][i][j].v = NULL;
00294     }
00295 }
00296 
00303 void gts_iso_slice_destroy (GtsIsoSlice * slice)
00304 {
00305   g_return_if_fail (slice != NULL);
00306 
00307   free2D ((void **) slice->vertices[0], slice->nx);
00308   free2D ((void **) slice->vertices[1], slice->nx - 1);
00309   free2D ((void **) slice->vertices[2], slice->nx);  
00310   g_free (slice->vertices);
00311   g_free (slice);
00312 }
00313 
00323 void gts_isosurface_slice (GtsIsoSlice * slice1,
00324                            GtsIsoSlice * slice2,
00325                            GtsSurface * surface)
00326 {
00327   guint j, k, l, nx, ny;
00328   OrientedVertex *** vertices[2];
00329   GtsVertex * va[12];
00330 
00331   g_return_if_fail (slice1 != NULL);
00332   g_return_if_fail (slice2 != NULL);
00333   g_return_if_fail (surface != NULL);
00334   g_return_if_fail (slice1->nx == slice2->nx && slice1->ny == slice2->ny);
00335 
00336   vertices[0] = slice1->vertices;
00337   vertices[1] = slice2->vertices;
00338   nx = slice1->nx;
00339   ny = slice1->ny;
00340 
00341   /* link vertices with segments and triangles */
00342   for (j = 0; j < nx - 1; j++)
00343     for (k = 0; k < ny - 1; k++) {
00344       gboolean cube_is_cut = FALSE;
00345       for (l = 0; l < 12; l++) {
00346         guint nv = 0, e = l;
00347         OrientedVertex ov = 
00348           vertices[c[e][1]][c[e][0]][j + c[e][2]][k + c[e][3]];
00349         while (ov.v && !GTS_OBJECT (ov.v)->reserved) {
00350           guint m = 0, * ne = edge[e][ov.orientation];
00351           va[nv++] = ov.v;
00352           GTS_OBJECT (ov.v)->reserved = surface;
00353           ov.v = NULL;
00354           while (m < 3 && !ov.v) {
00355             e = ne[m++];
00356             ov = vertices[c[e][1]][c[e][0]][j + c[e][2]][k + c[e][3]];
00357           }
00358         }
00359         /* create edges and faces */
00360         if (nv > 2) {
00361           GtsEdge * e1, * e2, * e3;
00362           guint m;
00363           if (!(e1 = GTS_EDGE (gts_vertices_are_connected (va[0], va[1]))))
00364             e1 = gts_edge_new (surface->edge_class, va[0], va[1]);
00365           for (m = 1; m < nv - 1; m++) {
00366             if (!(e2 = GTS_EDGE (gts_vertices_are_connected (va[m], va[m+1]))))
00367               e2 = gts_edge_new (surface->edge_class, va[m], va[m+1]);
00368             if (!(e3 = GTS_EDGE (gts_vertices_are_connected (va[m+1], va[0]))))
00369               e3 = gts_edge_new (surface->edge_class, va[m+1], va[0]);
00370             gts_surface_add_face (surface, 
00371                                   gts_face_new (surface->face_class,
00372                                                 e1, e2, e3));
00373             e1 = e3;
00374           }
00375         }
00376         if (nv > 0)
00377           cube_is_cut = TRUE;
00378       }
00379       if (cube_is_cut)
00380         for (l = 0; l < 12; l++) {
00381           GtsVertex * v = 
00382             vertices[c[l][1]][c[l][0]][j + c[l][2]][k + c[l][3]].v;
00383           if (v)
00384             GTS_OBJECT (v)->reserved = NULL;
00385         }
00386     }
00387 }
00388 
00389 #define SWAP(s1, s2, tmp) (tmp = s1, s1 = s2, s2 = tmp)
00390 
00407 void gts_isosurface_cartesian (GtsSurface * surface,
00408                                GtsCartesianGrid g,
00409                                GtsIsoCartesianFunc f,
00410                                gpointer data,
00411                                gdouble iso)
00412 {
00413   void * tmp;
00414   gdouble ** f1, ** f2;
00415   GtsIsoSlice * slice1, * slice2;
00416   guint i;
00417 
00418   g_return_if_fail (surface != NULL);
00419   g_return_if_fail (f != NULL);
00420   g_return_if_fail (g.nx > 1);
00421   g_return_if_fail (g.ny > 1);
00422   g_return_if_fail (g.nz > 1);
00423 
00424   slice1 = gts_iso_slice_new (g.nx, g.ny);
00425   slice2 = gts_iso_slice_new (g.nx, g.ny);
00426   f1 = (gdouble **) malloc2D (g.nx, g.ny, sizeof (gdouble));
00427   f2 = (gdouble **) malloc2D (g.nx, g.ny, sizeof (gdouble));
00428 
00429   (*f) (f1, g, 0, data);
00430   g.z += g.dz;
00431   (*f) (f2, g, 1, data);
00432   g.z -= g.dz;
00433   gts_iso_slice_fill_cartesian (slice1, g, f1, f2, iso, 
00434                                 surface->vertex_class);
00435   g.z += g.dz;
00436   for (i = 2; i < g.nz; i++) {
00437     g.z += g.dz;
00438     (*f) (f1, g, i, data);
00439     SWAP (f1, f2, tmp);
00440     g.z -= g.dz;
00441     gts_iso_slice_fill_cartesian (slice2, g, f1, f2, iso, 
00442                                   surface->vertex_class);
00443     g.z += g.dz;
00444     gts_isosurface_slice (slice1, slice2, surface);
00445     SWAP (slice1, slice2, tmp);
00446   }
00447   gts_iso_slice_fill_cartesian (slice2, g, f2, NULL, iso,
00448                                 surface->vertex_class);
00449   gts_isosurface_slice (slice1, slice2, surface);
00450 
00451   gts_iso_slice_destroy (slice1);
00452   gts_iso_slice_destroy (slice2);
00453   free2D ((void **) f1, g.nx);
00454   free2D ((void **) f2, g.nx);
00455 }