action.c: UpdatePackage() reloads from disk
[geda-pcb/whiteaudio.git] / gts / iso.c
blob5995a199ccc8f769e0d8bb575411a7a27c05b14b
1 /* GTS - Library for the manipulation of triangulated surfaces
2 * Copyright (C) 1999 Stéphane Popinet
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 #include "gts.h"
22 typedef enum { LEFT = 0, RIGHT = 1 } Orientation;
24 typedef struct {
25 GtsVertex * v;
26 Orientation orientation;
27 } OrientedVertex;
29 struct _GtsIsoSlice {
30 OrientedVertex *** vertices;
31 guint nx, ny;
34 /* coordinates of the edges of the cube (see doc/isocube.fig) */
35 static guint c[12][4] = {
36 {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 1}, {0, 0, 1, 0},
37 {1, 0, 0, 0}, {1, 0, 0, 1}, {1, 1, 0, 1}, {1, 1, 0, 0},
38 {2, 0, 0, 0}, {2, 1, 0, 0}, {2, 1, 1, 0}, {2, 0, 1, 0}};
40 /* first index is the edge number, second index is the edge orientation
41 (RIGHT or LEFT), third index are the edges which this edge may connect to
42 in order */
43 static guint edge[12][2][3] = {
44 {{9, 1, 8}, {4, 3, 7}}, /* 0 */
45 {{6, 2, 5}, {8, 0, 9}}, /* 1 */
46 {{10, 3, 11}, {5, 1, 6}}, /* 2 */
47 {{7, 0, 4}, {11, 2, 10}}, /* 3 */
48 {{3, 7, 0}, {8, 5, 11}}, /* 4 */
49 {{11, 4, 8}, {1, 6, 2}}, /* 5 */
50 {{2, 5, 1}, {9, 7, 10}}, /* 6 */
51 {{10, 6, 9}, {0, 4, 3}}, /* 7 */
52 {{5, 11, 4}, {0, 9, 1}}, /* 8 */
53 {{1, 8, 0}, {7, 10, 6}}, /* 9 */
54 {{6, 9, 7}, {3, 11, 2}}, /* 10 */
55 {{2, 10, 3}, {4, 8, 5}} /* 11 */
58 static void ** malloc2D (guint nx, guint ny, gulong size)
60 void ** m = g_malloc (nx*sizeof (void *));
61 guint i;
63 for (i = 0; i < nx; i++)
64 m[i] = g_malloc0 (ny*size);
66 return m;
69 static void free2D (void ** m, guint nx)
71 guint i;
73 g_return_if_fail (m != NULL);
75 for (i = 0; i < nx; i++)
76 g_free (m[i]);
77 g_free (m);
80 /**
81 * gts_grid_plane_new:
82 * @nx:
83 * @ny:
85 * Returns:
87 GtsGridPlane * gts_grid_plane_new (guint nx, guint ny)
89 GtsGridPlane * g = g_malloc (sizeof (GtsGridPlane));
91 g->p = (GtsPoint **) malloc2D (nx, ny, sizeof (GtsPoint));
92 g->nx = nx;
93 g->ny = ny;
95 return g;
98 /**
99 * gts_grid_plane_destroy:
100 * @g:
103 void gts_grid_plane_destroy (GtsGridPlane * g)
105 g_return_if_fail (g != NULL);
107 free2D ((void **) g->p, g->nx);
108 g_free (g);
112 * gts_iso_slice_new:
113 * @nx: number of vertices in the x direction.
114 * @ny: number of vertices in the y direction.
116 * Returns: a new #GtsIsoSlice.
118 GtsIsoSlice * gts_iso_slice_new (guint nx, guint ny)
120 GtsIsoSlice * slice;
122 g_return_val_if_fail (nx > 1, NULL);
123 g_return_val_if_fail (ny > 1, NULL);
125 slice = g_malloc (sizeof (GtsIsoSlice));
127 slice->vertices = g_malloc (3*sizeof (OrientedVertex **));
128 slice->vertices[0] =
129 (OrientedVertex **) malloc2D (nx, ny, sizeof (OrientedVertex));
130 slice->vertices[1] =
131 (OrientedVertex **) malloc2D (nx - 1, ny, sizeof (OrientedVertex));
132 slice->vertices[2] =
133 (OrientedVertex **) malloc2D (nx, ny - 1, sizeof (OrientedVertex));
134 slice->nx = nx;
135 slice->ny = ny;
137 return slice;
141 * gts_iso_slice_fill:
142 * @slice: a #GtsIsoSlice.
143 * @plane1: a #GtsGridPlane.
144 * @plane2: another #GtsGridPlane.
145 * @f1: values of the function corresponding to @plane1.
146 * @f2: values of the function corresponding to @plane2.
147 * @iso: isosurface value.
148 * @klass: a #GtsVertexClass or one of its descendant to be used for the
149 * new vertices.
151 * Fill @slice with the coordinates of the vertices defined by
152 * f1 (x,y,z) = @iso and f2 (x, y, z) = @iso.
154 void gts_iso_slice_fill (GtsIsoSlice * slice,
155 GtsGridPlane * plane1,
156 GtsGridPlane * plane2,
157 gdouble ** f1,
158 gdouble ** f2,
159 gdouble iso,
160 GtsVertexClass * klass)
162 OrientedVertex *** vertices;
163 GtsPoint ** p1, ** p2 = NULL;
164 guint i, j, nx, ny;
166 g_return_if_fail (slice != NULL);
167 g_return_if_fail (plane1 != NULL);
168 g_return_if_fail (f1 != NULL);
169 g_return_if_fail (f2 == NULL || plane2 != NULL);
171 p1 = plane1->p;
172 if (plane2)
173 p2 = plane2->p;
174 vertices = slice->vertices;
175 nx = slice->nx;
176 ny = slice->ny;
178 if (f2)
179 for (i = 0; i < nx; i++)
180 for (j = 0; j < ny; j++) {
181 gdouble v1 = f1[i][j] - iso;
182 gdouble v2 = f2[i][j] - iso;
183 if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
184 gdouble c2 = v1/(v1 - v2), c1 = 1. - c2;
185 vertices[0][i][j].v =
186 gts_vertex_new (klass,
187 c1*p1[i][j].x + c2*p2[i][j].x,
188 c1*p1[i][j].y + c2*p2[i][j].y,
189 c1*p1[i][j].z + c2*p2[i][j].z);
190 vertices[0][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
192 else
193 vertices[0][i][j].v = NULL;
195 for (i = 0; i < nx - 1; i++)
196 for (j = 0; j < ny; j++) {
197 gdouble v1 = f1[i][j] - iso;
198 gdouble v2 = f1[i+1][j] - iso;
199 if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
200 gdouble c2 = v1/(v1 - v2), c1 = 1. - c2;
201 vertices[1][i][j].v =
202 gts_vertex_new (klass,
203 c1*p1[i][j].x + c2*p1[i+1][j].x,
204 c1*p1[i][j].y + c2*p1[i+1][j].y,
205 c1*p1[i][j].z + c2*p1[i+1][j].z);
206 vertices[1][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
208 else
209 vertices[1][i][j].v = NULL;
211 for (i = 0; i < nx; i++)
212 for (j = 0; j < ny - 1; j++) {
213 gdouble v1 = f1[i][j] - iso;
214 gdouble v2 = f1[i][j+1] - iso;
215 if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
216 gdouble c2 = v1/(v1 - v2), c1 = 1. - c2;
217 vertices[2][i][j].v =
218 gts_vertex_new (klass,
219 c1*p1[i][j].x + c2*p1[i][j+1].x,
220 c1*p1[i][j].y + c2*p1[i][j+1].y,
221 c1*p1[i][j].z + c2*p1[i][j+1].z);
222 vertices[2][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
224 else
225 vertices[2][i][j].v = NULL;
230 * gts_iso_slice_fill_cartesian:
231 * @slice: a #GtsIsoSlice.
232 * @g: a #GtsCartesianGrid.
233 * @f1: values of the function for plane z = @g.z.
234 * @f2: values of the function for plane z = @g.z + @g.dz.
235 * @iso: isosurface value.
236 * @klass: a #GtsVertexClass.
238 * Fill @slice with the coordinates of the vertices defined by
239 * f1 (x,y,z) = @iso and f2 (x, y, z) = @iso.
241 void gts_iso_slice_fill_cartesian (GtsIsoSlice * slice,
242 GtsCartesianGrid g,
243 gdouble ** f1,
244 gdouble ** f2,
245 gdouble iso,
246 GtsVertexClass * klass)
248 OrientedVertex *** vertices;
249 guint i, j;
250 gdouble x, y;
252 g_return_if_fail (slice != NULL);
253 g_return_if_fail (f1 != NULL);
255 vertices = slice->vertices;
257 if (f2)
258 for (i = 0, x = g.x; i < g.nx; i++, x += g.dx)
259 for (j = 0, y = g.y; j < g.ny; j++, y += g.dy) {
260 gdouble v1 = f1[i][j] - iso;
261 gdouble v2 = f2[i][j] - iso;
262 if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
263 vertices[0][i][j].v =
264 gts_vertex_new (klass,
265 x, y, g.z + g.dz*v1/(v1 - v2));
266 vertices[0][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
268 else
269 vertices[0][i][j].v = NULL;
271 for (i = 0, x = g.x; i < g.nx - 1; i++, x += g.dx)
272 for (j = 0, y = g.y; j < g.ny; j++, y += g.dy) {
273 gdouble v1 = f1[i][j] - iso;
274 gdouble v2 = f1[i+1][j] - iso;
275 if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
276 vertices[1][i][j].v =
277 gts_vertex_new (klass, x + g.dx*v1/(v1 - v2), y, g.z);
278 vertices[1][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
280 else
281 vertices[1][i][j].v = NULL;
283 for (i = 0, x = g.x; i < g.nx; i++, x += g.dx)
284 for (j = 0, y = g.y; j < g.ny - 1; j++, y += g.dy) {
285 gdouble v1 = f1[i][j] - iso;
286 gdouble v2 = f1[i][j+1] - iso;
287 if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) {
288 vertices[2][i][j].v =
289 gts_vertex_new (klass, x, y + g.dy*v1/(v1 - v2), g.z);
290 vertices[2][i][j].orientation = v2 >= 0. ? RIGHT : LEFT;
292 else
293 vertices[2][i][j].v = NULL;
298 * gts_iso_slice_destroy:
299 * @slice: a #GtsIsoSlice.
301 * Free all memory allocated for @slice.
303 void gts_iso_slice_destroy (GtsIsoSlice * slice)
305 g_return_if_fail (slice != NULL);
307 free2D ((void **) slice->vertices[0], slice->nx);
308 free2D ((void **) slice->vertices[1], slice->nx - 1);
309 free2D ((void **) slice->vertices[2], slice->nx);
310 g_free (slice->vertices);
311 g_free (slice);
315 * gts_isosurface_slice:
316 * @slice1: a #GtsIsoSlice.
317 * @slice2: another #GtsIsoSlice.
318 * @surface: a #GtsSurface.
320 * Given two successive slices @slice1 and @slice2 link their vertices with
321 * segments and triangles which are added to @surface.
323 void gts_isosurface_slice (GtsIsoSlice * slice1,
324 GtsIsoSlice * slice2,
325 GtsSurface * surface)
327 guint j, k, l, nx, ny;
328 OrientedVertex *** vertices[2];
329 GtsVertex * va[12];
331 g_return_if_fail (slice1 != NULL);
332 g_return_if_fail (slice2 != NULL);
333 g_return_if_fail (surface != NULL);
334 g_return_if_fail (slice1->nx == slice2->nx && slice1->ny == slice2->ny);
336 vertices[0] = slice1->vertices;
337 vertices[1] = slice2->vertices;
338 nx = slice1->nx;
339 ny = slice1->ny;
341 /* link vertices with segments and triangles */
342 for (j = 0; j < nx - 1; j++)
343 for (k = 0; k < ny - 1; k++) {
344 gboolean cube_is_cut = FALSE;
345 for (l = 0; l < 12; l++) {
346 guint nv = 0, e = l;
347 OrientedVertex ov =
348 vertices[c[e][1]][c[e][0]][j + c[e][2]][k + c[e][3]];
349 while (ov.v && !GTS_OBJECT (ov.v)->reserved) {
350 guint m = 0, * ne = edge[e][ov.orientation];
351 va[nv++] = ov.v;
352 GTS_OBJECT (ov.v)->reserved = surface;
353 ov.v = NULL;
354 while (m < 3 && !ov.v) {
355 e = ne[m++];
356 ov = vertices[c[e][1]][c[e][0]][j + c[e][2]][k + c[e][3]];
359 /* create edges and faces */
360 if (nv > 2) {
361 GtsEdge * e1, * e2, * e3;
362 guint m;
363 if (!(e1 = GTS_EDGE (gts_vertices_are_connected (va[0], va[1]))))
364 e1 = gts_edge_new (surface->edge_class, va[0], va[1]);
365 for (m = 1; m < nv - 1; m++) {
366 if (!(e2 = GTS_EDGE (gts_vertices_are_connected (va[m], va[m+1]))))
367 e2 = gts_edge_new (surface->edge_class, va[m], va[m+1]);
368 if (!(e3 = GTS_EDGE (gts_vertices_are_connected (va[m+1], va[0]))))
369 e3 = gts_edge_new (surface->edge_class, va[m+1], va[0]);
370 gts_surface_add_face (surface,
371 gts_face_new (surface->face_class,
372 e1, e2, e3));
373 e1 = e3;
376 if (nv > 0)
377 cube_is_cut = TRUE;
379 if (cube_is_cut)
380 for (l = 0; l < 12; l++) {
381 GtsVertex * v =
382 vertices[c[l][1]][c[l][0]][j + c[l][2]][k + c[l][3]].v;
383 if (v)
384 GTS_OBJECT (v)->reserved = NULL;
389 #define SWAP(s1, s2, tmp) (tmp = s1, s1 = s2, s2 = tmp)
392 * gts_isosurface_cartesian:
393 * @surface: a #GtsSurface.
394 * @g: a #GtsCartesianGrid.
395 * @f: a #GtsIsoCartesianFunc.
396 * @data: user data to be passed to @f.
397 * @iso: isosurface value.
399 * Adds to @surface new faces defining the isosurface f(x,y,z) = @iso. By
400 * convention, the normals to the surface are pointing toward the positive
401 * values of f(x,y,z) - @iso.
403 * The user function @f is called successively for each value of the z
404 * coordinate defined by @g. It must fill the corresponding (x,y) plane with
405 * the values of the function for which the isosurface is to be computed.
407 void gts_isosurface_cartesian (GtsSurface * surface,
408 GtsCartesianGrid g,
409 GtsIsoCartesianFunc f,
410 gpointer data,
411 gdouble iso)
413 void * tmp;
414 gdouble ** f1, ** f2;
415 GtsIsoSlice * slice1, * slice2;
416 guint i;
418 g_return_if_fail (surface != NULL);
419 g_return_if_fail (f != NULL);
420 g_return_if_fail (g.nx > 1);
421 g_return_if_fail (g.ny > 1);
422 g_return_if_fail (g.nz > 1);
424 slice1 = gts_iso_slice_new (g.nx, g.ny);
425 slice2 = gts_iso_slice_new (g.nx, g.ny);
426 f1 = (gdouble **) malloc2D (g.nx, g.ny, sizeof (gdouble));
427 f2 = (gdouble **) malloc2D (g.nx, g.ny, sizeof (gdouble));
429 (*f) (f1, g, 0, data);
430 g.z += g.dz;
431 (*f) (f2, g, 1, data);
432 g.z -= g.dz;
433 gts_iso_slice_fill_cartesian (slice1, g, f1, f2, iso,
434 surface->vertex_class);
435 g.z += g.dz;
436 for (i = 2; i < g.nz; i++) {
437 g.z += g.dz;
438 (*f) (f1, g, i, data);
439 SWAP (f1, f2, tmp);
440 g.z -= g.dz;
441 gts_iso_slice_fill_cartesian (slice2, g, f1, f2, iso,
442 surface->vertex_class);
443 g.z += g.dz;
444 gts_isosurface_slice (slice1, slice2, surface);
445 SWAP (slice1, slice2, tmp);
447 gts_iso_slice_fill_cartesian (slice2, g, f2, NULL, iso,
448 surface->vertex_class);
449 gts_isosurface_slice (slice1, slice2, surface);
451 gts_iso_slice_destroy (slice1);
452 gts_iso_slice_destroy (slice2);
453 free2D ((void **) f1, g.nx);
454 free2D ((void **) f2, g.nx);