1 /*   EXTRAITS DE LA LICENCE
2 	Copyright CEA, contributeurs : Luc BILLARD, Damien
3 	CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005)
4 
5 	Adresse mèl :
6 	BILLARD, non joignable par mèl ;
7 	CALISTE, damien P caliste AT cea P fr.
8 	D'ASTIER, dastier AT iie P cnam P fr.
9 
10 	Ce logiciel est un programme informatique servant à visualiser des
11 	structures atomiques dans un rendu pseudo-3D.
12 
13 	Ce logiciel est régi par la licence CeCILL soumise au droit français et
14 	respectant les principes de diffusion des logiciels libres. Vous pouvez
15 	utiliser, modifier et/ou redistribuer ce programme sous les conditions
16 	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
17 	sur le site "http://www.cecill.info".
18 
19 	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
20 	pris connaissance de la licence CeCILL, et que vous en avez accepté les
21 	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
22 */
23 
24 /*   LICENCE SUM UP
25 	Copyright CEA, contributors : Luc BILLARD and Damien
26 	CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005)
27 
28 	E-mail addresses :
29 	BILLARD, not reachable any more ;
30 	CALISTE, damien P caliste AT cea P fr.
31 	D'ASTIER, dastier AT iie P cnam P fr.
32 
33 	This software is a computer program whose purpose is to visualize atomic
34 	configurations in 3D.
35 
36 	This software is governed by the CeCILL  license under French law and
37 	abiding by the rules of distribution of free software.  You can  use,
38 	modify and/ or redistribute the software under the terms of the CeCILL
39 	license as circulated by CEA, CNRS and INRIA at the following URL
40 	"http://www.cecill.info".
41 
42 	The fact that you are presently reading this means that you have had
43 	knowledge of the CeCILL license and that you accept its terms. You can
44 	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
45 */
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 
51 #include <math.h>
52 
53 #include <visu_tools.h>
54 #include "surfaces.h"
55 #include "pot2surf.h"
56 
57 /**
58  * SECTION:pot2surf
59  * @short_description: Creates surfaces from scalar fields.
60  *
61  * <para>Originally written by Luc Billard for his program
62  * VISUALISE. It has been since transformed to a single function and
63  * integrated in V_Sim. .pot file are text files which specification
64  * are the following :
65  * <itemizedlist>
66  * <listitem><para>1st line: full pathname of the potential file to
67  * read</para></listitem>
68  * <listitem><para>2nd line: full pathname of the surface file to
69  * build</para></listitem>
70  * <listitem><para>3rd line: an integer giving the nbr n of
71  * isosurfaces to build </para></listitem>
72  * <listitem><para>Each of the n following lines must match the
73  * pattern [value name] where value is a real number for the isovalue
74  * and name is the name given for the corresponding isosurface to
75  * build. Each surface should be named surface_*.</para></listitem>
76  * </itemizedlist>
77  * The function will fail if it finds no isosurface corresponding to
78  * some of the given isovalues. The <link
79  * linkend="v-sim-panelSurfacesTools">panelSurfacesTools</link>
80  * contains a frontend to build valid .instruc files. This panel is
81  * originally integrated in V_Sim. You can access it through the
82  * Convert tab in the Isosurfaces panel.</para>
83  */
84 
85 #define ISOSURFACES_FLAG_POTENTIAL "# potentialValue"
86 
87 
88 static int nx, ny, nz;
89 static double dxx, dyx, dyy, dzx, dzy, dzz;
90 static double exx, eyx, eyy, ezx, ezy, ezz;
91 static int nxm1, nym1, nzm1;
92 static int nz3, nyz3, nxyz3;
93 static double dxx1, dyx1, dyy1, dzx1, dzy1, dzz1;
94 static double ***f = NULL;
95 static double isovalue;
96 static FILE *in = NULL;
97 
98 static int *itab = NULL;
99 static double *xs = NULL, *ys = NULL, *zs = NULL, *xns = NULL, *yns = NULL, *zns = NULL;
100 static gboolean create_fromSF_uniform(VisuSurface **surf, const VisuScalarField *field,
101                                       double isoValue, const gchar *name);
102 static gboolean create_fromSF_nonuniform(VisuSurface **surf, const VisuScalarField *field,
103                                          double isoValue, const gchar *name);
104 static gboolean Create_surf(int nelez3, int neleyz3, int nelexyz3,
105                             guint sizem1[3], int *iTab, GArray *points,
106                             double isoValue, const VisuScalarField *field, double scalarBox[6],
107                             const gchar *name, VisuSurface **surf);
108 
109 /* Tables from :
110    http://www.swin.edu.au/astronomy/pbourke/modelling/polygonise/index.html
111    (valid link on February 25, 2002)
112 
113    YOU WILL FIND MANY VERY INTERESTING PAGES at Paul Bourke's site:
114    http://astronomy.swin.edu.au/pbourke/
115 
116    Other routines by Luc Billard, on March 1, 2002
117 */
118 
119 static int edgeTable[256]={
120 0x0  , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
121 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
122 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
123 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
124 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
125 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
126 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
127 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
128 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
129 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
130 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
131 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
132 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
133 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
134 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
135 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
136 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
137 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
138 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
139 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
140 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
141 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
142 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
143 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
144 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
145 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
146 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
147 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
148 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
149 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
150 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
151 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0   };
152 
153 static int triTable[256][16] =
154 {{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
155 {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
156 {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
157 {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
158 {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
159 {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
160 {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
161 {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
162 {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
163 {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
164 {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
165 {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
166 {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
167 {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
168 {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
169 {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
170 {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
171 {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
172 {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
173 {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
174 {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
175 {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
176 {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
177 {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
178 {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
179 {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
180 {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
181 {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
182 {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
183 {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
184 {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
185 {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
186 {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
187 {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
188 {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
189 {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
190 {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
191 {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
192 {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
193 {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
194 {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
195 {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
196 {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
197 {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
198 {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
199 {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
200 {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
201 {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
202 {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
203 {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
204 {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
205 {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
206 {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
207 {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
208 {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
209 {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
210 {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
211 {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
212 {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
213 {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
214 {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
215 {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
216 {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
217 {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
218 {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
219 {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
220 {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
221 {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
222 {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
223 {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
224 {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
225 {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
226 {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
227 {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
228 {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
229 {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
230 {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
231 {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
232 {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
233 {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
234 {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
235 {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
236 {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
237 {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
238 {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
239 {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
240 {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
241 {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
242 {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
243 {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
244 {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
245 {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
246 {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
247 {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
248 {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
249 {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
250 {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
251 {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
252 {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
253 {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
254 {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
255 {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
256 {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
257 {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
258 {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
259 {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
260 {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
261 {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
262 {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
263 {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
264 {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
265 {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
266 {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
267 {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
268 {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
269 {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
270 {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
271 {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
272 {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
273 {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
274 {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
275 {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
276 {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
277 {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
278 {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
279 {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
280 {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
281 {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
282 {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
283 {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
284 {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
285 {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
286 {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
287 {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
288 {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
289 {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
290 {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
291 {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
292 {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
293 {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
294 {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
295 {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
296 {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
297 {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
298 {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
299 {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
300 {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
301 {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
302 {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
303 {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
304 {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
305 {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
306 {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
307 {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
308 {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
309 {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
310 {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
311 {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
312 {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
313 {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
314 {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
315 {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
316 {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
317 {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
318 {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
319 {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
320 {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
321 {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
322 {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
323 {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
324 {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
325 {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
326 {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
327 {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
328 {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
329 {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
330 {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
331 {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
332 {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
333 {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
334 {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
335 {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
336 {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
337 {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
338 {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
339 {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
340 {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
341 {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
342 {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
343 {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
344 {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
345 {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
346 {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
347 {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
348 {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
349 {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
350 {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
351 {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
352 {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
353 {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
354 {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
355 {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
356 {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
357 {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
358 {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
359 {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
360 {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
361 {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
362 {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
363 {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
364 {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
365 {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
366 {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
367 {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
368 {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
369 {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
370 {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
371 {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
372 {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
373 {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
374 {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
375 {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
376 {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
377 {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
378 {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
379 {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
380 {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
381 {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
382 {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
383 {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
384 {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
385 {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
386 {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
387 {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
388 {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
389 {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
390 {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
391 {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
392 {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
393 {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
394 {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
395 {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
396 {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
397 {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
398 {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
399 {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
400 {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
401 {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
402 {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
403 {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
404 {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
405 {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
406 {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
407 {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
408 {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
409 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}};
410 
411 /******************************************************************************/
412 
gx(int i,int j,int k)413 static double gx(int i, int j, int k) {
414    if(i > 0 && i < nxm1) {
415       return (f[i+1][j][k]-f[i-1][j][k]) / 2.0;
416    }
417    else if(i == 0) {
418       return (f[i+1][j][k]-f[i][j][k]);
419    }
420    else {
421       return (f[i][j][k]-f[i-1][j][k]);
422    }
423 }
424 
425 /******************************************************************************/
426 
gy(int i,int j,int k)427 static double gy(int i, int j, int k) {
428    if(j > 0 && j < nym1) {
429       return (f[i][j+1][k]-f[i][j-1][k]) / 2.0;
430    }
431    else if(j == 0) {
432       return (f[i][j+1][k]-f[i][j][k]);
433    }
434    else {
435       return (f[i][j][k]-f[i][j-1][k]);
436    }
437 }
438 
439 /******************************************************************************/
440 
gz(int i,int j,int k)441 static double gz(int i, int j, int k) {
442    if(k > 0 && k < nzm1) {
443       return (f[i][j][k+1]-f[i][j][k-1]) / 2.0;
444    }
445    else if(k == 0) {
446       return (f[i][j][k+1]-f[i][j][k]);
447    }
448    else {
449       return (f[i][j][k]-f[i][j][k-1]);
450    }
451 }
452 
453 /******************************************************************************/
454 
calc(guint * n1,guint * n2)455 static GString* calc(guint *n1, guint *n2) {
456 
457 /*  I label local cell vertices as in ref. above
458     and assigns x y z names like this :
459 
460                  y
461                  |
462 
463                  4----------5
464                 /.         /|
465                7----------6 |
466                | .        | |
467                | .        | |
468                | 0........|.1  --x
469                |/         |/
470                3----------2
471 
472              /
473             z
474 
475 */
476    register int i, j, k;
477    guint n;
478    double fac;
479    double xu, yu, zu, xui, xuij, yuj;
480    int cubeindex;
481    int e;
482    int vertlist[12];
483    int m1, m2, m3;
484    double ux, uy, uz, vx, vy, vz, wx, wy, wz, s;
485    double xnu, ynu, znu;
486    GString *out;
487 
488    /* edges are labelled from each corner:
489       x+ then z+ then y+
490       for k varying fastest
491       then j varying fastest
492       then i varying fastest
493    */
494    n = 0;
495    for(i=0; i<nx; i++) {
496       xui = i*dxx1;
497       for(j=0; j<ny; j++) {
498          xuij = xui+j*dyx1;
499          yuj = j*dyy1;
500          for(k=0; k<nz; k++) {
501             xu = xuij+k*dzx1;
502             yu = yuj+k*dzy1;
503             zu = k*dzz1;
504             xnu = gx(i, j, k);
505             ynu = gy(i, j, k);
506             znu = gz(i, j, k);
507             if(i<nxm1) {
508                if((isovalue-f[i][j][k] < 0.0 && isovalue-f[i+1][j][k] >= 0) ||
509                   (isovalue-f[i][j][k] >= 0.0 && isovalue-f[i+1][j][k] < 0)) {
510                   fac = (isovalue-f[i][j][k])/(f[i+1][j][k]-f[i][j][k]);
511                   itab[n] = *n2;
512                   xs[*n2] = xu + fac*dxx1;
513                   ys[*n2] = yu;
514                   zs[*n2] = zu;
515                   ux = xnu + fac*(gx(i+1, j, k) - xnu);
516                   uy = ynu + fac*(gy(i+1, j, k) - ynu);
517                   uz = znu + fac*(gz(i+1, j, k) - znu);
518                   ux = ux*exx+uy*eyx+uz*ezx;
519                   uy =        uy*eyy+uz*ezy;
520                   uz =               uz*ezz;
521                   s = sqrt(ux*ux+uy*uy+uz*uz);
522                   if(s <= 0.0) {
523                     g_warning("normal direction assumed");
524                      xns[*n2] = 1.0;
525                      yns[*n2] = 0.0;
526                      zns[*n2] = 0.0;
527                   }
528                   else {
529                      xns[*n2] = ux/s;
530                      yns[*n2] = uy/s;
531                      zns[*n2] = uz/s;
532                   }
533                   *n2 += 1;
534                }
535                else {
536                   itab[n] = -1;
537                }
538             }
539             else {
540                itab[n] = -1;
541             }
542             n++;
543             if(k<nzm1) {
544                if((isovalue-f[i][j][k] < 0.0 && isovalue-f[i][j][k+1] >= 0) ||
545                   (isovalue-f[i][j][k] >= 0.0 && isovalue-f[i][j][k+1] < 0)) {
546                   fac = (isovalue-f[i][j][k])/(f[i][j][k+1]-f[i][j][k]);
547                   itab[n] = *n2;
548                   xs[*n2] = xu + fac*dzx1;
549                   ys[*n2] = yu + fac*dzy1;
550                   zs[*n2] = zu + fac*dzz1;
551                   ux = xnu + fac*(gx(i, j, k+1) - xnu);
552                   uy = ynu + fac*(gy(i, j, k+1) - ynu);
553                   uz = znu + fac*(gz(i, j, k+1) - znu);
554                   ux = ux*exx+uy*eyx+uz*ezx;
555                   uy =        uy*eyy+uz*ezy;
556                   uz =               uz*ezz;
557                   s = sqrt(ux*ux+uy*uy+uz*uz);
558                   if(s <= 0.0) {
559                     g_warning("normal direction assumed");
560                      xns[*n2] = 1.0;
561                      yns[*n2] = 0.0;
562                      zns[*n2] = 0.0;
563                   }
564                   else {
565                      xns[*n2] = ux/s;
566                      yns[*n2] = uy/s;
567                      zns[*n2] = uz/s;
568                   }
569                   *n2 += 1;
570                }
571                else {
572                   itab[n] = -1;
573                }
574             }
575             else {
576                itab[n] = -1;
577             }
578             n++;
579             if(j<nym1) {
580                if((isovalue-f[i][j][k] < 0.0 && isovalue-f[i][j+1][k] >= 0) ||
581                   (isovalue-f[i][j][k] >= 0.0 && isovalue-f[i][j+1][k] < 0)) {
582                   fac = (isovalue-f[i][j][k])/(f[i][j+1][k]-f[i][j][k]);
583                   itab[n] = *n2;
584                   xs[*n2] = xu + fac*dyx1;
585                   ys[*n2] = yu + fac*dyy1;
586                   zs[*n2] = zu;
587                   ux = xnu + fac*(gx(i, j+1, k) - xnu);
588                   uy = ynu + fac*(gy(i, j+1, k) - ynu);
589                   uz = znu + fac*(gz(i, j+1, k) - znu);
590                   ux = ux*exx+uy*eyx+uz*ezx;
591                   uy =        uy*eyy+uz*ezy;
592                   uz =               uz*ezz;
593                   s = sqrt(ux*ux+uy*uy+uz*uz);
594                   if(s <= 0.0) {
595                     g_warning("normal direction assumed");
596                      xns[*n2] = 1.0;
597                      yns[*n2] = 0.0;
598                      zns[*n2] = 0.0;
599                   }
600                   else {
601                      xns[*n2] = ux/s;
602                      yns[*n2] = uy/s;
603                      zns[*n2] = uz/s;
604                   }
605                   *n2 += 1;
606                }
607                else {
608                   itab[n] = -1;
609                }
610             }
611             else {
612                itab[n] = -1;
613             }
614             n++;
615          }
616       }
617    }
618 
619    if(*n2 == 0) {
620      g_warning("no isosurfaces found.");
621      return (GString*)0;
622    }
623 
624    out = g_string_new("");
625    for(i=0; i<nxm1; i++) {
626       for(j=0; j<nym1; j++) {
627          for(k=0; k<nzm1; k++) {
628             cubeindex = 0;
629             if (f[i  ][j  ][k  ] < isovalue) cubeindex |=   1;
630             if (f[i+1][j  ][k  ] < isovalue) cubeindex |=   2;
631             if (f[i+1][j  ][k+1] < isovalue) cubeindex |=   4;
632             if (f[i  ][j  ][k+1] < isovalue) cubeindex |=   8;
633             if (f[i  ][j+1][k  ] < isovalue) cubeindex |=  16;
634             if (f[i+1][j+1][k  ] < isovalue) cubeindex |=  32;
635             if (f[i+1][j+1][k+1] < isovalue) cubeindex |=  64;
636             if (f[i  ][j+1][k+1] < isovalue) cubeindex |= 128;
637 
638             e = edgeTable[cubeindex];
639 
640             if (e == 0) continue;
641 
642             n = i*nyz3+j*nz3+k*3;
643 
644             if (e & 1   ) vertlist[0 ] = itab[n];
645             if (e & 2   ) vertlist[1 ] = itab[n + nyz3 + 1];
646             if (e & 4   ) vertlist[2 ] = itab[n + 3];
647             if (e & 8   ) vertlist[3 ] = itab[n + 1];
648             if (e & 16  ) vertlist[4 ] = itab[n + nz3];
649             if (e & 32  ) vertlist[5 ] = itab[n + nyz3 + 1 + nz3];
650             if (e & 64  ) vertlist[6 ] = itab[n + 3 + nz3];
651             if (e & 128 ) vertlist[7 ] = itab[n + 1 + nz3];
652             if (e & 256 ) vertlist[8 ] = itab[n + 2];
653             if (e & 512 ) vertlist[9 ] = itab[n + nyz3 + 2];
654             if (e & 1024) vertlist[10] = itab[n + nyz3 + 3 + 2];
655             if (e & 2048) vertlist[11] = itab[n + 3 + 2];
656 
657             for (n = 0; triTable[cubeindex][n]!= -1; n += 3) {
658                m1 = vertlist[triTable[cubeindex][n  ]];
659                if(m1 == -1)
660                  {
661                    g_warning("m1 %d %d %d", i, j, k);
662                    g_string_free(out, TRUE);
663                    return (GString*)0;
664                  }
665                m2 = vertlist[triTable[cubeindex][n+1]];
666                if(m2 == -1)
667                  {
668                    g_warning("m2 %d %d %d", i, j, k);
669                    g_string_free(out, TRUE);
670                    return (GString*)0;
671                  }
672                m3 = vertlist[triTable[cubeindex][n+2]];
673                if(m3 == -1)
674                  {
675                    g_warning("m3 %d %d %d", i, j, k);
676                    g_string_free(out, TRUE);
677                    return (GString*)0;
678                  }
679                ux = xs[m2] - xs[m1];
680                uy = ys[m2] - ys[m1];
681                uz = zs[m2] - zs[m1];
682                vx = xs[m3] - xs[m1];
683                vy = ys[m3] - ys[m1];
684                vz = zs[m3] - zs[m1];
685                wx = uy*vz-uz*vy;
686                wy = uz*vx-ux*vz;
687                wz = ux*vy-uy*vx;
688                s = sqrt(wx*wx+wy*wy+wz*wz);
689                if(s <= 0.0) continue;
690                g_string_append_printf(out, "3 %d %d %d\n", m1+1, m2+1, m3+1);
691                *n1 += 1;
692             }
693          }
694       }
695    }
696 
697    if(*n1 == 0) {
698      g_warning("no isosurfaces found.");
699      return (GString*)0;
700    }
701 
702 
703    for(n=0; n<*n2; n++)
704      g_string_append_printf(out, "%g %g %g  %g %g %g\n",
705                             xs[n], ys[n], zs[n], xns[n], yns[n], zns[n]);
706 
707    return out;
708 }
709 
710 /**
711  * visu_surface_createFromPotentialFile:
712  * @surf_file_to_write: target surf file
713  * @pot_file_to_read: source pot file
714  * @nsurfs_to_build: number of surfaces to build
715  * @surf_value: an array with iso-values
716  * @surf_name: an array with iso-surface names.
717  *
718  * Read the given pot file and produce an associated surf
719  * file. WARNING, it may be removed later.
720  *
721  * Deprecated: 3.7
722  *
723  * Returns: 0 in case of success, n!=0 otherwise.
724  */
725 #ifndef V_SIM_DISABLE_DEPRECATED
visu_surface_createFromPotentialFile(const gchar * surf_file_to_write,const gchar * pot_file_to_read,int nsurfs_to_build,const float * surf_value,const gchar ** surf_name)726 int visu_surface_createFromPotentialFile(const gchar *surf_file_to_write, const gchar *pot_file_to_read, int nsurfs_to_build,
727 		    const float *surf_value, const gchar **surf_name)
728 {
729    register int i, j, k;
730    char rep[TOOL_MAX_LINE_LENGTH], info[TOOL_MAX_LINE_LENGTH];
731    double v;
732    GString *out, *local;
733    guint n1, n2;
734    int n1_tot, n2_tot;
735    gchar *comment;
736    GError *error;
737 
738    n1_tot = 0;
739    n2_tot = 0;
740 
741    in = fopen(pot_file_to_read,"r");
742    if (!in) {
743       (void)fprintf(stderr, "\aERROR: cannot read potential file %s\n", pot_file_to_read);
744       return 1;
745    }
746    DBG_fprintf(stderr, "pot2surf : Reading potential file %s\n", pot_file_to_read);
747 
748    out = g_string_new("");
749    DBG_fprintf(stderr, "pot2surf : Writing surface file %s ...\n", surf_file_to_write);
750 
751    /* 1st line (comment) */
752    g_return_val_if_fail(fgets(rep, TOOL_MAX_LINE_LENGTH, in), 1);
753    rep[strlen(rep)-1] = 0; /* skipping \n */
754    DBG_fprintf(stderr, "Pot2surf : read comment line '%s'\n", rep);
755    comment = g_strdup(rep);
756 
757    g_return_val_if_fail(fgets(rep, TOOL_MAX_LINE_LENGTH, in), 1);
758    g_return_val_if_fail(sscanf(rep, "%d %d %d", &nx, &ny, &nz) != 3, 1);
759 
760    f = g_malloc(nx*sizeof(double **));
761    for(i=0; i<nx; i++) {
762       f[i] = g_malloc(ny*sizeof(double *));
763       for(j=0; j<ny; j++) {
764          f[i][j] = g_malloc(nz*sizeof(double));
765       }
766    }
767 
768    nxm1 = nx - 1;
769    nym1 = ny - 1;
770    nzm1 = nz - 1;
771 
772    nz3 = 3*nz;
773    nyz3 = ny*nz3;
774    nxyz3 = nx*nyz3;
775 
776    itab = g_malloc(nxyz3*sizeof(int));
777 
778    xs = g_malloc(nxyz3*sizeof(double));
779    ys = g_malloc(nxyz3*sizeof(double));
780    zs = g_malloc(nxyz3*sizeof(double));
781    xns = g_malloc(nxyz3*sizeof(double));
782    yns = g_malloc(nxyz3*sizeof(double));
783    zns = g_malloc(nxyz3*sizeof(double));
784 
785    g_return_val_if_fail(fgets(rep, TOOL_MAX_LINE_LENGTH, in), 1);
786    g_return_val_if_fail(sscanf(rep, "%lf %lf %lf", &dxx, &dyx, &dyy) != 3, 1);
787    g_return_val_if_fail(fgets(rep, TOOL_MAX_LINE_LENGTH, in), 1);
788    g_return_val_if_fail(sscanf(rep, "%lf %lf %lf", &dzx, &dzy, &dzz) != 3, 1);;
789 
790    v = dxx*dyy*dzz;
791    exx = dyy*dzz/v;
792    eyx = -dyx*dzz/v;
793    ezx = (dyx*dzy-dyy*dzx)/v;
794    eyy = dxx*dzz/v;
795    ezy = -dxx*dzy/v;
796    ezz = dxx*dyy/v;
797 
798    dxx1 = dxx/nx;
799    dyx1 = dyx/ny;
800    dyy1 = dyy/ny;
801    dzx1 = dzx/nz;
802    dzy1 = dzy/nz;
803    dzz1 = dzz/nz;
804 
805    g_return_val_if_fail(fgets(rep, TOOL_MAX_LINE_LENGTH, in), 1);
806    if(sscanf(rep, "%s", info) != 1) {
807      (void)fprintf(stderr, "\aERROR: missing chain xyz OR zyx\n");
808      return 1;
809    }
810    if(!strcmp(info, "xyz")) {
811      for ( k = 0; k < nz; k++ )
812        for ( j = 0; j < ny; j++ )
813          for ( i = 0; i < nx; i++ )
814            g_return_val_if_fail(fscanf(in, "%lf", &f[i][j][k]) != 1, 1);
815    }
816    else if(!strcmp(info, "zyx")) {
817      for ( i = 0; i < nx; i++ )
818        for ( j = 0; j < ny; j++ )
819          for ( k = 0; k < nz; k++ )
820            g_return_val_if_fail(fscanf(in, "%lf", &f[i][j][k]) != 1, 1);
821    }
822    else {
823       (void)fprintf(stderr,
824          "\aERROR: 5th line should contain chain xyz OR zyx\n");
825       return 1;
826    }
827 
828    for(k=0; k<nsurfs_to_build; k++) {
829 
830      isovalue = surf_value[k];
831 
832      DBG_fprintf(stderr, "Building isosurface for isovalue = %f (%s)\n",
833                  isovalue, surf_name[k]);
834      g_string_append_printf(out, "%s %f\n", ISOSURFACES_FLAG_POTENTIAL, isovalue);
835      if (surf_name[k])
836        g_string_append(out, surf_name[k]);
837      g_string_append(out, "\n");
838 
839      n1 = 0;
840      n2 = 0;
841      local = calc(&n1, &n2);
842      if(!local)
843        return 1;
844      DBG_fprintf(stderr, "  Found %d facets and %d points\n", n1, n2);
845      g_string_append_printf(out, "%12d%12d", n1, n2);
846      g_string_append(out, local->str);
847      g_string_free(local, TRUE);
848 
849      n1_tot += n1;
850      n2_tot += n2;
851    }
852 
853    local = g_string_new(comment);
854    g_free(comment);
855    g_string_append_printf(local, "%f %f %f\n", dxx, dyx, dyy);
856    g_string_append_printf(local, "%f %f %f\n", dzx, dzy, dzz);
857    g_string_append_printf(local, "%12d%12d%12d", nsurfs_to_build, n1_tot, n2_tot);
858    g_string_prepend(out, local->str);
859    g_string_free(local, TRUE);
860 
861    DBG_fprintf(stderr,
862       "Found a total of %d facets and %d points\n", n1_tot, n2_tot);
863    DBG_fprintf(stderr, "Done.\n");
864 
865    for(i=0; i<nx; i++)
866      {
867        for(j=0; j<ny; j++)
868 	 g_free(f[i][j]);
869        g_free(f[i]);
870      }
871    g_free(f);
872 
873    g_free(itab);
874 
875    g_free(xs);
876    g_free(ys);
877    g_free(zs);
878    g_free(xns);
879    g_free(yns);
880    g_free(zns);
881 
882    error = (GError*)0;
883    if (!g_file_set_contents(surf_file_to_write, out->str, -1, &error))
884      {
885        g_warning("%s", error->message);
886        g_error_free(error);
887        return 1;
888      }
889    g_string_free(out, TRUE);
890 
891    return 0;
892 }
893 #endif
894 
895 /******************************************************************************/
896 /******************************************************************************/
897 
898 
899 /* DEVELOPMENT AREA
900    Methods are copied to be callable without all static stuff everywhere. */
901 
getDeltaMesh(int i,double * mesh,int size,gboolean periodic)902 static double getDeltaMesh(int i, double *mesh, int size, gboolean periodic)
903 {
904   if (i >= size - 1)
905     {
906       if (periodic)
907 	return 1. + mesh[(i + 1)%size] - mesh[i%size];
908       else
909 	return (mesh[size] - mesh[size - 1]);
910     }
911   return (mesh[i + 1] - mesh[i]);
912 }
913 
914 /**
915  * visu_surface_new_fromScalarField:
916  * @field: the scalar field to create the surface from ;
917  * @isoValue: the value of the isosurface ;
918  * @name: (allow-none): the name of the surface to use (can be NULL).
919  *
920  * Create on the fly a surface from the scalar field @field. If
921  * @name is given, the surface is created with it, if not, "Isosurface
922  * @id + 1" is used. @surf can already contains several surfaces, in
923  * that case, the new surface is added. If @surf is NULL, then a new
924  * #VisuSurface object is created and returned.
925  *
926  * Returns: (transfer full): the newly created surface, if any.
927  */
visu_surface_new_fromScalarField(const VisuScalarField * field,double isoValue,const gchar * name)928 VisuSurface* visu_surface_new_fromScalarField(const VisuScalarField *field,
929                                                 double isoValue,
930                                                 const gchar *name)
931 {
932   VisuSurface *surf;
933 
934   surf = (VisuSurface*)0;
935   switch (visu_scalar_field_getMeshtype(field))
936     {
937     case VISU_SCALAR_FIELD_MESH_UNIFORM:
938       create_fromSF_uniform   (&surf, field, isoValue, name);
939       break;
940     case VISU_SCALAR_FIELD_MESH_NON_UNIFORM:
941       create_fromSF_nonuniform(&surf, field, isoValue, name);
942       break;
943     default:
944       g_warning("Wrong value for 'meshtype'.");
945       return FALSE;
946     }
947   if (surf)
948     g_object_set_data(G_OBJECT(surf), "origin", (gpointer)field);
949   return surf;
950 }
951 
952 /**
953  * visu_surface_new_defaultFromScalarField:
954  * @field: a #VisuScalarField object.
955  * @neg: (transfer full) (out): a #VisuSurface location.
956  * @pos: (transfer full) (out): a #VisuSurface location.
957  *
958  * Creates one or two surface from @field. If @field is mostly
959  * positive, one surface is generated at the mean value. If @field has
960  * equivalent negative and positive values, two surfaces are
961  * generated, one for th mean negative value and one for the mean
962  * positive value.
963  *
964  * Since: 3.8
965  **/
visu_surface_new_defaultFromScalarField(const VisuScalarField * field,VisuSurface ** neg,VisuSurface ** pos)966 void visu_surface_new_defaultFromScalarField(const VisuScalarField *field,
967                                              VisuSurface **neg,
968                                              VisuSurface **pos)
969 {
970   double mimax[2];
971   VisuSurface *surf;
972   VisuSurfaceResource *res;
973   gchar *label;
974   static guint id = 0;
975   int blue[4] = {0, 24, 185, 196}, red[4] = {185, 24, 0, 196};
976   gboolean new;
977 
978   if (neg)
979     *neg = (VisuSurface*)0;
980   if (pos)
981     *pos = (VisuSurface*)0;
982   id += 1;
983   visu_scalar_field_getMinMax(field, mimax);
984   /* For densities, this create only one surface. For
985      wavefunctions, it create two and set their style
986      accordingly. */
987   if (mimax[0] <= mimax[1] && mimax[0] * mimax[1] < 0.f &&
988       MIN(ABS(mimax[0]), ABS(mimax[1])) / MAX(ABS(mimax[0]), ABS(mimax[1])) > 0.2)
989     {
990       label = g_strdup_printf(_("Negative (%d)"), id);
991       res = visu_surface_resource_new_fromName(label, &new);
992       if (new)
993         g_object_set(res, "color", tool_color_addIntRGBA(blue),
994                      "rendered", TRUE, NULL);
995       g_object_unref(res);
996       surf = visu_surface_new_fromScalarField(field, mimax[0] / 2., label);
997       g_free(label);
998       if (surf && neg)
999         *neg = surf;
1000       else if (surf)
1001         g_object_unref(surf);
1002 
1003       label = g_strdup_printf(_("Positive (%d)"), id);
1004       res = visu_surface_resource_new_fromName(label, &new);
1005       if (new)
1006         g_object_set(res, "color", tool_color_addIntRGBA(red),
1007                      "rendered", TRUE, NULL);
1008       g_object_unref(res);
1009       surf = visu_surface_new_fromScalarField(field, mimax[1] / 2., label);
1010       g_free(label);
1011       if (surf && pos)
1012         *pos = surf;
1013       else if (surf)
1014         g_object_unref(surf);
1015     }
1016   else if (mimax[0] <= mimax[1])
1017     {
1018       surf = visu_surface_new_fromScalarField(field, (mimax[0] + mimax[1]) / 2.,
1019                                               (const gchar*)0);
1020       if (surf && pos)
1021         *pos = surf;
1022       else if (surf)
1023         g_object_unref(surf);
1024     }
1025   else
1026     {
1027       surf = visu_surface_new_fromScalarField(field, 0., (gchar*)0);
1028       if (surf && pos)
1029         *pos = surf;
1030       else if (surf)
1031         g_object_unref(surf);
1032     }
1033 }
1034 
_setNormal(double nrm[3],double s,double vux,double vuy,double vuz)1035 static void _setNormal(double nrm[3], double s, double vux, double vuy, double vuz)
1036 {
1037   if (s <= 0.0)
1038     {
1039       g_warning("normal direction assumed");
1040       nrm[0] = 1.;
1041       nrm[1] = 0.;
1042       nrm[2] = 0.;
1043     }
1044   else
1045     {
1046       nrm[0] = vux/s;
1047       nrm[1] = vuy/s;
1048       nrm[2] = vuz/s;
1049     }
1050 }
1051 
1052 /**
1053  * create_fromSF_uniform:
1054  * @surf: a location on a #VisuSurface pointer ;
1055  * @field: the scalar field to create the surface from ;
1056  * @isoValue: the value of the isosurface ;
1057  * @id: an integer identifying the surface ;
1058  * @name: the name of the surface to use (can be NULL).
1059  *
1060  * Create on the fly a surface from the scalar field @field. If @name is given, the surface
1061  * is created with it, if not, "Isosurface @id + 1" is used. @surf can already
1062  * contains several surfaces, in that case, the new surface is added. If @surf is
1063  * NULL, then a new #VisuSurface object is created and returned.
1064  *
1065  * Returns: TRUE if the surface is created.
1066  */
1067 
create_fromSF_uniform(VisuSurface ** surf,const VisuScalarField * field,double isoValue,const gchar * name)1068 static gboolean create_fromSF_uniform(VisuSurface **surf, const VisuScalarField *field,
1069                                       double isoValue, const gchar *name)
1070 {
1071 
1072 /*  I label local cell vertices as in ref. above
1073     and assigns x y z names like this :
1074 
1075                  y
1076                  |
1077 
1078                  4----------5
1079                 /.         /|
1080                7----------6 |
1081                | .        | |
1082                | .        | |
1083                | 0........|.1  --x
1084                |/         |/
1085                3----------2
1086 
1087              /
1088             z
1089 
1090 */
1091 
1092 /* Local variables */
1093 
1094   register guint i, j, k;
1095   int n;
1096   int nelez3, neleyz3, nelexyz3;
1097   guint sizem1[3]; /*nx-1, ny-1 ,nz-1 : number of mesh intervals in the x,y and z direction*/
1098   guint scalarGrid[3]; /*nx, ny ,nz : number of mesh nodes in the x,y and z direction*/
1099   int *iTab;
1100   double fac;
1101   double xu, yu, zu, xui, xuij, yuj;
1102   double vux, vuy, vuz, s;
1103   double vxnu, vynu, vznu, v;
1104   double orthoBox[6];  /* inverse length of the box*/
1105   double dBox[6];   /*step of the mesh*/
1106   GArray *points;
1107   VisuSurfacePoint at;
1108   double val1, val2;
1109   VisuBox *box;
1110   double scalarBox[VISU_BOX_N_VECTORS]; /*define the box edges and topology*/
1111   gboolean per[3], status;
1112   float scalarShift[3];
1113 
1114 /* Routine code*/
1115 
1116 /* Ensure that the pointer is not zero */
1117   g_return_val_if_fail(surf, FALSE);
1118 
1119   /* edges are labelled from each corner:
1120      x+ then z+ then y+
1121      for k varying fastest
1122      then j varying fastest
1123      then i varying fastest
1124   */
1125 
1126   /* Get data from the field. */
1127   box = visu_boxed_getBox(VISU_BOXED(field));
1128   for (i = 0; i < VISU_BOX_N_VECTORS; i++)
1129     scalarBox[i] = visu_box_getGeometry(box, i);
1130   visu_box_getPeriodicity(box, per);
1131   visu_scalar_field_getGridSize(field, scalarGrid);
1132   visu_pointset_getTranslation(VISU_POINTSET(field), scalarShift);
1133 
1134   DBG_fprintf(stderr, "Pot2surf : compute isosurface at value %g from"
1135 	      " field %p.\n", isoValue, (gpointer)field);
1136   DBG_fprintf(stderr, " | periodic %d, %d, %d.\n", per[0], per[1], per[2]);
1137   DBG_fprintf(stderr, " | value %g.\n", isoValue);
1138   DBG_fprintf(stderr, " | size %d %d %d.\n", scalarGrid[0],
1139 	      scalarGrid[1], scalarGrid[2]);
1140   DBG_fprintf(stderr, " | box %g %g %g\n", scalarBox[0],
1141 	      scalarBox[1], scalarBox[2]);
1142   DBG_fprintf(stderr, " |     %g %g %g.\n", scalarBox[3],
1143 	      scalarBox[4], scalarBox[5]);
1144   DBG_fprintf(stderr, " | shift %g %g %g\n", scalarShift[0],
1145 	      scalarShift[1], scalarShift[2]);
1146 
1147   /* Compute some local values. */
1148   if (per[0])
1149     scalarGrid[0] += 1;
1150   if (per[1])
1151     scalarGrid[1] += 1;
1152   if (per[2])
1153     scalarGrid[2] += 1;
1154   for (i = 0; i < 3; i++)
1155     sizem1[i] = scalarGrid[i] - 1;
1156   v   = scalarBox[0] * scalarBox[2] * scalarBox[5];  /* volume of the box = Lx*Ly*Lz */
1157   orthoBox[0] = scalarBox[2] * scalarBox[5] / v;     /*  1/Lx */
1158   orthoBox[1] = -scalarBox[1] * scalarBox[5] / v;
1159   orthoBox[2] = scalarBox[0] * scalarBox[5] / v;     /*  1/Ly */
1160   orthoBox[3] = (scalarBox[1] * scalarBox[4] - scalarBox[2] * scalarBox[3]) / v;
1161   orthoBox[4] = -scalarBox[0] * scalarBox[4] / v;
1162   orthoBox[5] = scalarBox[0] * scalarBox[2] / v;     /*  1/Lz */
1163   dBox[0] = scalarBox[0] / sizem1[0];
1164   dBox[1] = scalarBox[1] / sizem1[1];
1165   dBox[2] = scalarBox[2] / sizem1[1];
1166   dBox[3] = scalarBox[3] / sizem1[2];
1167   dBox[4] = scalarBox[4] / sizem1[2];
1168   dBox[5] = scalarBox[5] / sizem1[2];
1169   nelez3 = 3 * scalarGrid[2];
1170   neleyz3 = scalarGrid[1] * nelez3;
1171   nelexyz3 = scalarGrid[0] * neleyz3; /* 3*nx*ny*nz */
1172 
1173   /* Allocate buffers. */
1174   points = g_array_sized_new(FALSE, FALSE, sizeof(VisuSurfacePoint), nelexyz3 / 10);
1175   /* Indexes. */
1176   iTab = g_malloc(nelexyz3 * sizeof(int));
1177 
1178   n = 0;
1179   for(i=0; i<scalarGrid[0]; i++) {
1180     xui = i*dBox[0];
1181     for(j=0; j<scalarGrid[1]; j++) {
1182       xuij = xui+j*dBox[1];
1183       yuj = j*dBox[2];
1184       for(k=0; k<scalarGrid[2]; k++) {
1185 	xu = xuij+k*dBox[3] - scalarShift[0];
1186 	yu = yuj+k*dBox[4] - scalarShift[1];
1187 	zu = k*dBox[5] - scalarShift[2];               /* xu,yu,zu coordinate in the mesh corresponding to index i,j,k */
1188 	vxnu = visu_scalar_field_getGradAt(field, i, j, k, TOOL_XYZ_X);
1189 	vynu = visu_scalar_field_getGradAt(field, i, j, k, TOOL_XYZ_Y);
1190 	vznu = visu_scalar_field_getGradAt(field, i, j, k, TOOL_XYZ_Z);
1191 	val1 = visu_scalar_field_getAt(field, i, j, k); /* v(i,j,k) */
1192 	if(i<sizem1[0]) {
1193 	  val2 = visu_scalar_field_getAt(field, i + 1, j, k); /* v(i+1,j,k)*/
1194 	  if((isoValue - val1 < 0.0 && isoValue - val2 >= 0.0) ||
1195 	     (isoValue - val1 >= 0.0 && isoValue - val2 < 0.0)) {
1196 	    fac = (isoValue - val1) / (val2 - val1);
1197 	    iTab[n] = points->len;
1198             at.at[0] = xu + fac*dBox[0];  /* surface intersection
1199                                           coordinates*/
1200             at.at[1] = yu;
1201             at.at[2] = zu;
1202 	    vux = vxnu + fac*(visu_scalar_field_getGradAt(field, i+1, j, k, TOOL_XYZ_X) - vxnu);
1203 	    vuy = vynu + fac*(visu_scalar_field_getGradAt(field, i+1, j, k, TOOL_XYZ_Y) - vynu);
1204 	    vuz = vznu + fac*(visu_scalar_field_getGradAt(field, i+1, j, k, TOOL_XYZ_Z) - vznu);
1205 	    vux = vux*orthoBox[0]+vuy*orthoBox[1]+vuz*orthoBox[3];
1206 	    vuy =                 vuy*orthoBox[2]+vuz*orthoBox[4];
1207 	    vuz =                                 vuz*orthoBox[5];
1208 	    s = sqrt(vux*vux+vuy*vuy+vuz*vuz);
1209             _setNormal(at.normal, s, vux, vuy, vuz);
1210             g_array_append_val(points, at);
1211 	  }
1212 	  else {
1213 	    iTab[n] = -1;
1214 	  }
1215 	}
1216 	else {
1217 	  iTab[n] = -1;
1218 	}
1219 	n++;
1220 	if(k<sizem1[2]) {
1221 	  val2 = visu_scalar_field_getAt(field, i, j, k + 1);
1222 	  if((isoValue - val1 < 0.0 && isoValue - val2 >= 0.0) ||
1223 	     (isoValue - val1 >= 0.0 && isoValue - val2 < 0.0)) {
1224 	    fac = (isoValue - val1) / (val2 - val1);
1225 	    iTab[n] = points->len;
1226             at.at[0] = xu + fac*dBox[3];
1227             at.at[1] = yu + fac*dBox[4];
1228             at.at[2] = zu + fac*dBox[5];
1229 	    vux = vxnu + fac*(visu_scalar_field_getGradAt(field, i, j, k+1, TOOL_XYZ_X) - vxnu);
1230 	    vuy = vynu + fac*(visu_scalar_field_getGradAt(field, i, j, k+1, TOOL_XYZ_Y) - vynu);
1231 	    vuz = vznu + fac*(visu_scalar_field_getGradAt(field, i, j, k+1, TOOL_XYZ_Z) - vznu);
1232 	    vux = vux*orthoBox[0]+vuy*orthoBox[1]+vuz*orthoBox[3];
1233 	    vuy =                 vuy*orthoBox[2]+vuz*orthoBox[4];
1234 	    vuz =                                 vuz*orthoBox[5];
1235 	    s = sqrt(vux*vux+vuy*vuy+vuz*vuz);
1236             _setNormal(at.normal, s, vux, vuy, vuz);
1237             g_array_append_val(points, at);
1238 	  }
1239 	  else {
1240 	    iTab[n] = -1;
1241 	  }
1242 	}
1243 	else {
1244 	  iTab[n] = -1;
1245 	}
1246 	n++;
1247 	if(j<sizem1[1]) {
1248 	  val2 = visu_scalar_field_getAt(field, i, j + 1, k);
1249 	  if((isoValue - val1 < 0.0 && isoValue - val2 >= 0.0) ||
1250 	     (isoValue - val1 >= 0.0 && isoValue - val2 < 0.0)) {
1251 	    fac = (isoValue - val1) / (val2 - val1);
1252 	    iTab[n] = points->len;
1253             at.at[0] = xu + fac*dBox[1];
1254             at.at[1] = yu + fac*dBox[2];
1255             at.at[2] = zu;
1256 	    vux = vxnu + fac*(visu_scalar_field_getGradAt(field, i, j+1, k, TOOL_XYZ_X) - vxnu);
1257 	    vuy = vynu + fac*(visu_scalar_field_getGradAt(field, i, j+1, k, TOOL_XYZ_Y) - vynu);
1258 	    vuz = vznu + fac*(visu_scalar_field_getGradAt(field, i, j+1, k, TOOL_XYZ_Z) - vznu);
1259 	    vux = vux*orthoBox[0]+vuy*orthoBox[1]+vuz*orthoBox[3];
1260 	    vuy =                 vuy*orthoBox[2]+vuz*orthoBox[4];
1261 	    vuz =                                 vuz*orthoBox[5];
1262 	    s = sqrt(vux*vux+vuy*vuy+vuz*vuz);
1263             _setNormal(at.normal, s, vux, vuy, vuz);
1264             g_array_append_val(points, at);
1265 	  }
1266 	  else {
1267 	    iTab[n] = -1;
1268 	  }
1269 	}
1270 	else {
1271 	  iTab[n] = -1;
1272 	}
1273 	n++;
1274       }
1275     }
1276   }
1277   DBG_fprintf(stderr, " | found %d points.\n", points->len);
1278 
1279   if (points->len == 0)
1280     {
1281       g_warning("no isosurface found.");
1282       g_array_unref(points);
1283       g_free(iTab);
1284       return FALSE;
1285     }
1286   status = Create_surf(nelez3, neleyz3, nelexyz3, sizem1, iTab,
1287                        points, isoValue, field, scalarBox, name, surf);
1288 
1289   DBG_fprintf(stderr, " | Surface successfully created.\n");
1290 
1291   return status;
1292 }
1293 
1294 
1295 /**
1296  * create_fromSF_nonuniform:
1297  * @surf: a location on a #VisuSurface pointer ;
1298  * @field: the scalar field to create the surface from ;
1299  * @isoValue: the value of the isosurface ;
1300  * @id: an integer identifying the surface ;
1301  * @name: the name of the surface to use (can be NULL).
1302  *
1303  * Create on the fly a surface from the scalar field @field. If @name is given, the surface
1304  * is created with it, if not, "Isosurface @id + 1" is used. @surf can already
1305  * contains several surfaces, in that case, the new surface is added. If @surf is
1306  * NULL, then a new #VisuSurface object is created and returned.
1307  *
1308  * Returns: TRUE if the surface is created.
1309  */
1310 
create_fromSF_nonuniform(VisuSurface ** surf,const VisuScalarField * field,double isoValue,const gchar * name)1311 static gboolean create_fromSF_nonuniform(VisuSurface **surf, const VisuScalarField *field,
1312                                        double isoValue, const gchar *name)
1313 {
1314 
1315 /*  I label local cell vertices as in ref. above
1316     and assigns x y z names like this :
1317 
1318                  y
1319                  |
1320 
1321                  4---------------5
1322                 /.              /|
1323                7---------------6 |
1324                | .             | |
1325                | .             | |
1326                | 0.............|.1  --x
1327                |/              |/
1328                3---------------2
1329 
1330              /
1331             z
1332 
1333 */
1334 
1335 /* Local variables */
1336 
1337   register guint i, j, k;
1338   int n;
1339   int nelez3, neleyz3, nelexyz3;
1340   guint sizem1[3]; /*nx-1, ny-1 ,nz-1 : number of mesh intervals in the x,y and z direction*/
1341   guint scalarGrid[3]; /*nx, ny ,nz : number of mesh nodes in the x,y and z direction*/
1342   int *iTab;
1343   double fac;
1344   double xu, yu, zu, xui, xuij, yuj, dmesh;
1345   double vux, vuy, vuz, s;
1346   double vxnu, vynu, vznu, v;
1347   double orthoBox[6];  /* inverse length of the box*/
1348   GArray *points;
1349   VisuSurfacePoint at;
1350   double *meshx, *meshy, *meshz;
1351   double val1, val2;
1352   VisuBox *box;
1353   double scalarBox[6]; /*define the box edges and topology*/
1354   gboolean per[3], status;
1355 
1356 /* Routine code*/
1357 
1358 /* Ensure that the pointer is not zero */
1359   g_return_val_if_fail(surf, FALSE);
1360 
1361   /* edges are labelled from each corner:
1362      x+ then z+ then y+
1363      for k varying fastest
1364      then j varying fastest
1365      then i varying fastest
1366   */
1367 
1368   /* Get data from the field. */
1369   box = visu_boxed_getBox(VISU_BOXED(field));
1370   for (i = 0; i < VISU_BOX_N_VECTORS; i++)
1371     scalarBox[i] = visu_box_getGeometry(box, i);
1372   visu_box_getPeriodicity(box, per);
1373   meshx = visu_scalar_field_getMesh(field, TOOL_XYZ_X);
1374   meshy = visu_scalar_field_getMesh(field, TOOL_XYZ_Y);
1375   meshz = visu_scalar_field_getMesh(field, TOOL_XYZ_Z);
1376   visu_scalar_field_getGridSize(field, scalarGrid);
1377 
1378   DBG_fprintf(stderr, "Pot2surf : compute isosurface at value %g from"
1379 	      " field %p.\n", isoValue, (gpointer)field);
1380   DBG_fprintf(stderr, " | periodic %d, %d, %d.\n", per[0], per[1], per[2]);
1381   DBG_fprintf(stderr, " | value %g.\n", isoValue);
1382   DBG_fprintf(stderr, " | size %d %d %d.\n", scalarGrid[0],
1383 	      scalarGrid[1], scalarGrid[2]);
1384   DBG_fprintf(stderr, " | box %g %g %g\n", scalarBox[0],
1385 	      scalarBox[1], scalarBox[2]);
1386   DBG_fprintf(stderr, " |     %g %g %g.\n", scalarBox[3],
1387 	      scalarBox[4], scalarBox[5]);
1388 
1389   /* Compute some local values. */
1390   if (per[0])
1391     scalarGrid[0] += 1;
1392   if (per[1])
1393     scalarGrid[1] += 1;
1394   if (per[2])
1395     scalarGrid[2] += 1;
1396   for (i = 0; i < 3; i++)
1397     sizem1[i] = scalarGrid[i] - 1;
1398   v   = scalarBox[0] * scalarBox[2] * scalarBox[5];  /* volume of the box = Lx*Ly*Lz */
1399   orthoBox[0] = scalarBox[2] * scalarBox[5] / v;     /*  1/Lx */
1400   orthoBox[1] = -scalarBox[1] * scalarBox[5] / v;
1401   orthoBox[2] = scalarBox[0] * scalarBox[5] / v;     /*  1/Ly */
1402   orthoBox[3] = (scalarBox[1] * scalarBox[4] - scalarBox[2] * scalarBox[3]) / v;
1403   orthoBox[4] = -scalarBox[0] * scalarBox[4] / v;
1404   orthoBox[5] = scalarBox[0] * scalarBox[2] / v;     /*  1/Lz */
1405   nelez3 = 3 * scalarGrid[2];
1406   neleyz3 = scalarGrid[1] * nelez3;
1407   nelexyz3 = scalarGrid[0] * neleyz3; /* 3*nx*ny*nz */
1408 
1409   /* Allocate buffers. */
1410   points = g_array_sized_new(FALSE, FALSE, sizeof(VisuSurfacePoint), nelexyz3 / 10);
1411   /* Indexes. */
1412   iTab = g_malloc(nelexyz3 * sizeof(int));
1413 
1414   n = 0;
1415   for(i=0; i<scalarGrid[0]; i++) {
1416     xui   = ((per[0] && i == sizem1[0])?1.:meshx[i]) * scalarBox[0];
1417     for(j=0; j<scalarGrid[1]; j++) {
1418       xuij   = xui  + ((per[1] && j == sizem1[1])?1.:meshy[j]) * scalarBox[1];
1419       yuj    = ((per[1] && j == sizem1[1])?1.:meshy[j]) * scalarBox[2];
1420       for(k=0; k<scalarGrid[2]; k++) {
1421         xu   = xuij  + ((per[2] && k == sizem1[2])?1.:meshz[k]) * scalarBox[3];
1422 	yu   = yuj   + ((per[2] && k == sizem1[2])?1.:meshz[k]) * scalarBox[4];
1423 	zu   = ((per[2] && k == sizem1[2])?1.:meshz[k]) * scalarBox[5];
1424 	/* xu  ,yu  ,zu coordinate in the mesh corresponding to index i ,j ,k */
1425         vxnu = visu_scalar_field_getGradAt(field, i, j, k, TOOL_XYZ_X);
1426         vynu = visu_scalar_field_getGradAt(field, i, j, k, TOOL_XYZ_Y);
1427         vznu = visu_scalar_field_getGradAt(field, i, j, k, TOOL_XYZ_Z);
1428         val1 = visu_scalar_field_getAt(field, i, j, k);       /*  v(i,j,k) */
1429         if(i<sizem1[0]) {
1430           val2 = visu_scalar_field_getAt(field, i + 1, j, k); /* v(i+1,j,k)*/
1431           if((isoValue - val1 < 0.0 && isoValue - val2 >= 0.0) ||
1432              (isoValue - val1 >= 0.0 && isoValue - val2 < 0.0)) {
1433             fac = (isoValue - val1) / (val2 - val1);
1434             iTab[n] = points->len;
1435 	    dmesh = getDeltaMesh(i, meshx, sizem1[0], per[0]);
1436             at.at[0] = xu + fac * dmesh * scalarBox[0];
1437             at.at[1] = yu;
1438             at.at[2] = zu;
1439             vux = vxnu + fac*(visu_scalar_field_getGradAt(field, i+1, j, k, TOOL_XYZ_X) - vxnu);
1440             vuy = vynu + fac*(visu_scalar_field_getGradAt(field, i+1, j, k, TOOL_XYZ_Y) - vynu);
1441             vuz = vznu + fac*(visu_scalar_field_getGradAt(field, i+1, j, k, TOOL_XYZ_Z) - vznu);
1442             vux = vux*orthoBox[0]+vuy*orthoBox[1]+vuz*orthoBox[3];
1443             vuy =                 vuy*orthoBox[2]+vuz*orthoBox[4];
1444             vuz =                                 vuz*orthoBox[5];
1445             s = sqrt(vux*vux+vuy*vuy+vuz*vuz);
1446             _setNormal(at.normal, s, vux, vuy, vuz);
1447             g_array_append_val(points, at);
1448 	  }
1449 	  else {
1450 	    iTab[n] = -1;
1451 	  }
1452 	}
1453 	else {
1454 	  iTab[n] = -1;
1455 	}
1456 	n++;
1457 	if(k<sizem1[2]) {
1458 	  val2 = visu_scalar_field_getAt(field, i, j, k + 1);
1459 	  if((isoValue - val1 < 0.0 && isoValue - val2 >= 0.0) ||
1460 	     (isoValue - val1 >= 0.0 && isoValue - val2 < 0.0)) {
1461 	    fac = (isoValue - val1) / (val2 - val1);
1462 	    iTab[n] = points->len;
1463 	    dmesh = getDeltaMesh(k, meshz, sizem1[2], per[2]);
1464             at.at[0] = xu + fac * dmesh * scalarBox[3];
1465             at.at[1] = yu + fac * dmesh * scalarBox[4];
1466             at.at[2] = zu + fac * dmesh * scalarBox[5];
1467 	    vux = vxnu + fac*(visu_scalar_field_getGradAt(field, i, j, k+1, TOOL_XYZ_X) - vxnu);
1468 	    vuy = vynu + fac*(visu_scalar_field_getGradAt(field, i, j, k+1, TOOL_XYZ_Y) - vynu);
1469 	    vuz = vznu + fac*(visu_scalar_field_getGradAt(field, i, j, k+1, TOOL_XYZ_Z) - vznu);
1470 	    vux = vux*orthoBox[0]+vuy*orthoBox[1]+vuz*orthoBox[3];
1471 	    vuy =                 vuy*orthoBox[2]+vuz*orthoBox[4];
1472 	    vuz =                                 vuz*orthoBox[5];
1473 	    s = sqrt(vux*vux+vuy*vuy+vuz*vuz);
1474             _setNormal(at.normal, s, vux, vuy, vuz);
1475             g_array_append_val(points, at);
1476 	  }
1477 	  else {
1478 	    iTab[n] = -1;
1479 	  }
1480 	}
1481 	else {
1482 	  iTab[n] = -1;
1483 	}
1484 	n++;
1485 	if(j<sizem1[1]) {
1486 	  val2 = visu_scalar_field_getAt(field, i, j + 1, k);
1487 	  if((isoValue - val1 < 0.0 && isoValue - val2 >= 0.0) ||
1488 	     (isoValue - val1 >= 0.0 && isoValue - val2 < 0.0)) {
1489 	    fac = (isoValue - val1) / (val2 - val1);
1490 	    iTab[n] = points->len;
1491 	    dmesh = getDeltaMesh(j, meshy, sizem1[1], per[1]);
1492             at.at[0] = xu + fac * dmesh * scalarBox[1];
1493             at.at[1] = yu + fac * dmesh * scalarBox[2];
1494             at.at[2] = zu;
1495 	    vux = vxnu + fac*(visu_scalar_field_getGradAt(field, i, j+1, k, TOOL_XYZ_X) - vxnu);
1496 	    vuy = vynu + fac*(visu_scalar_field_getGradAt(field, i, j+1, k, TOOL_XYZ_Y) - vynu);
1497 	    vuz = vznu + fac*(visu_scalar_field_getGradAt(field, i, j+1, k, TOOL_XYZ_Z) - vznu);
1498 	    vux = vux*orthoBox[0]+vuy*orthoBox[1]+vuz*orthoBox[3];
1499 	    vuy =                 vuy*orthoBox[2]+vuz*orthoBox[4];
1500 	    vuz =                                 vuz*orthoBox[5];
1501 	    s = sqrt(vux*vux+vuy*vuy+vuz*vuz);
1502             _setNormal(at.normal, s, vux, vuy, vuz);
1503             g_array_append_val(points, at);
1504 	  }
1505 	  else {
1506 	    iTab[n] = -1;
1507 	  }
1508 	}
1509 	else {
1510 	  iTab[n] = -1;
1511 	}
1512 	n++;
1513       }
1514     }
1515   }
1516   DBG_fprintf(stderr, " | found %d points.\n", points->len);
1517 
1518   if (points->len == 0)
1519     {
1520       g_warning("no isosurface found.");
1521       g_array_unref(points);
1522       g_free(iTab);
1523       return FALSE;
1524     }
1525   status = Create_surf(nelez3, neleyz3, nelexyz3, sizem1, iTab,
1526                        points, isoValue, field, scalarBox, name, surf);
1527 
1528   DBG_fprintf(stderr, " | Surface successfully created.\n");
1529 
1530   return status;
1531 }
1532 
1533 /**
1534  * Create_surf:
1535  * @id: an integer identifying the surface ;
1536  * @nelez3: an integer giving the number of element times 3 along z;
1537  * @neleyz3: an integer giving the number of element times 3 in plane y by z;
1538  * @nelexyz3: an integer giving the number of element times 3 in volume x by y by z;
1539  * @nPoints: an integer giving the number points of the surface;
1540  * @sizem1: the number of intervals in each direction;
1541  * @iTab: table containing the number of surface points if surface exists at this place otherwise -1;
1542  * @xsurf: x coordinate of the surface points;
1543  * @ysurf: y coordinate of the surface points;
1544  * @zsurf: z coordinate of the surface points;
1545  * @xnsurf: normal value of the surface points;
1546  * @ynsurf: normal of the surface points;
1547  * @znsurf: normal of the surface points;
1548  * @isoValue: the value of the isosurface;
1549  * @scalarData: the potential values;
1550  * @scalarBox: the box parameters;
1551  * @name: the name of the surface to use (can be NULL).
1552  * @per: boolean for periodicity;
1553  * @surf: a location on a #VisuSurface pointer ;
1554  *
1555  * Create on the fly a surface from the scalar field @field. If @name is given, the surface
1556  * is created with it, if not, "Isosurface @id + 1" is used. @surf can already
1557  * contains several surfaces, in that case, the new surface is added. If @surf is
1558  * NULL, then a new #VisuSurface object is created and returned.
1559  *
1560  * Returns: TRUE if the surface is created.
1561  */
1562 
Create_surf(int nelez3,int neleyz3,int nelexyz3 _U_,guint sizem1[3],int * iTab,GArray * points,double isoValue,const VisuScalarField * field,double scalarBox[6],const gchar * name,VisuSurface ** surf)1563 static gboolean Create_surf(int nelez3, int neleyz3, int nelexyz3 _U_,
1564                             guint sizem1[3], int *iTab, GArray *points,
1565                             double isoValue, const VisuScalarField *field, double scalarBox[6],
1566                             const gchar *name, VisuSurface **surf)
1567 {
1568 
1569 /* Local variables */
1570 
1571   register guint i, j, k;
1572   int cubeindex;
1573   int e, n;
1574   int m1, m2, m3;
1575   int vertlist[12];
1576   GArray *vTab;
1577   VisuSurfacePoly poly;
1578   VisuSurfacePoint *at1, *at2, *at3;
1579   double vx, vy, vz, wx, wy, wz;
1580   double ux, uy, uz, s;
1581   float* densityData;
1582   VisuBox *box;
1583 
1584   /* Routine code */
1585 
1586   /* Ensure that the pointer is not zero */
1587   g_return_val_if_fail(surf, FALSE);
1588 
1589   /* Allocate buffers. The 16 coefficient is for the maximum number of
1590      polygons per grid points. */
1591   vTab = g_array_sized_new(FALSE, FALSE, sizeof(VisuSurfacePoly), points->len / 3);
1592   poly.nvertices = 3;
1593 
1594   /* Main loop */
1595   for(i=0; i<sizem1[0]; i++) {
1596     for(j=0; j<sizem1[1]; j++) {
1597       for(k=0; k<sizem1[2]; k++) {
1598 	cubeindex = 0;
1599 	if (visu_scalar_field_getAt(field, i  , j  , k  ) <= isoValue) cubeindex |=   1;
1600 	if (visu_scalar_field_getAt(field, i+1, j  , k  ) <= isoValue) cubeindex |=   2;
1601 	if (visu_scalar_field_getAt(field, i+1, j  , k+1) <= isoValue) cubeindex |=   4;
1602 	if (visu_scalar_field_getAt(field, i  , j  , k+1) <= isoValue) cubeindex |=   8;
1603 	if (visu_scalar_field_getAt(field, i  , j+1, k  ) <= isoValue) cubeindex |=  16;
1604 	if (visu_scalar_field_getAt(field, i+1, j+1, k  ) <= isoValue) cubeindex |=  32;
1605 	if (visu_scalar_field_getAt(field, i+1, j+1, k+1) <= isoValue) cubeindex |=  64;
1606 	if (visu_scalar_field_getAt(field, i  , j+1, k+1) <= isoValue) cubeindex |= 128;
1607 
1608 	e = edgeTable[cubeindex];
1609 
1610 	if (e == 0) continue;
1611 
1612 	n = i*neleyz3+j*nelez3+k*3;
1613 
1614 	if (e & 1   ) vertlist[0 ] = iTab[n];
1615 	if (e & 2   ) vertlist[1 ] = iTab[n + neleyz3 + 1];
1616 	if (e & 4   ) vertlist[2 ] = iTab[n + 3];
1617 	if (e & 8   ) vertlist[3 ] = iTab[n + 1];
1618 	if (e & 16  ) vertlist[4 ] = iTab[n + nelez3];
1619 	if (e & 32  ) vertlist[5 ] = iTab[n + neleyz3 + 1 + nelez3];
1620 	if (e & 64  ) vertlist[6 ] = iTab[n + 3 + nelez3];
1621 	if (e & 128 ) vertlist[7 ] = iTab[n + 1 + nelez3];
1622 	if (e & 256 ) vertlist[8 ] = iTab[n + 2];
1623 	if (e & 512 ) vertlist[9 ] = iTab[n + neleyz3 + 2];
1624 	if (e & 1024) vertlist[10] = iTab[n + neleyz3 + 3 + 2];
1625 	if (e & 2048) vertlist[11] = iTab[n + 3 + 2];
1626 
1627 	for (n = 0; triTable[cubeindex][n]!= -1; n += 3) {
1628 	  m1 = vertlist[triTable[cubeindex][n  ]];
1629 	  if(m1 == -1)
1630 	    {
1631 	      g_warning("m1 %d %d %d.", i, j, k);
1632               g_array_unref(points);
1633               g_free(iTab);
1634               g_array_unref(vTab);
1635 	      return FALSE;
1636 	    }
1637 	  m2 = vertlist[triTable[cubeindex][n+1]];
1638 	  if(m2 == -1)
1639 	    {
1640 	      g_warning("m2 %d %d %d.", i, j, k);
1641               g_array_unref(points);
1642               g_free(iTab);
1643               g_array_unref(vTab);
1644 	      return FALSE;
1645 	    }
1646 	  m3 = vertlist[triTable[cubeindex][n+2]];
1647 	  if(m3 == -1)
1648 	    {
1649 	      g_warning("m3 %d %d %d.", i, j, k);
1650               g_array_unref(points);
1651               g_free(iTab);
1652               g_array_unref(vTab);
1653 	      return FALSE;
1654 	    }
1655           at1 = &g_array_index(points, VisuSurfacePoint, m1);
1656           at2 = &g_array_index(points, VisuSurfacePoint, m2);
1657           at3 = &g_array_index(points, VisuSurfacePoint, m3);
1658 	  ux = at2->at[0] - at1->at[0];
1659 	  uy = at2->at[1] - at1->at[1];
1660 	  uz = at2->at[2] - at1->at[2];
1661           vx = at3->at[0] - at1->at[0];
1662 	  vy = at3->at[1] - at1->at[1];
1663 	  vz = at3->at[2] - at1->at[2];
1664 	  wx = uy*vz-uz*vy;
1665 	  wy = uz*vx-ux*vz;
1666 	  wz = ux*vy-uy*vx;
1667 	  s = sqrt(wx*wx+wy*wy+wz*wz);
1668 	  if(s <= 0.0) continue;
1669           poly.indices[0] = m1;
1670           poly.indices[1] = m2;
1671           poly.indices[2] = m3;
1672           g_array_append_val(vTab, poly);
1673 	}
1674       }
1675     }
1676   }
1677   DBG_fprintf(stderr, " | found %d polygons.\n", vTab->len);
1678 
1679   if (vTab->len == 0)
1680     {
1681       g_warning("no isosurface found.");
1682       g_array_unref(points);
1683       g_free(iTab);
1684       g_array_unref(vTab);
1685       return FALSE;
1686     }
1687 
1688   /* Ok, try to create a VisuSurface object from here. */
1689   g_return_val_if_fail(*surf == (VisuSurface*)0, FALSE);
1690 
1691   DBG_fprintf(stderr, " | create new VisuSurface.\n");
1692   *surf = visu_surface_new(name, points, vTab);
1693   box = visu_box_new(scalarBox, VISU_BOX_PERIODIC);
1694   visu_boxed_setBox(VISU_BOXED(*surf), VISU_BOXED(box));
1695   g_object_unref(box);
1696   densityData = visu_surface_addPropertyFloat(*surf, VISU_SURFACE_PROPERTY_POTENTIAL);
1697   densityData[0] = isoValue;
1698 
1699 #if DEBUG == 1
1700   visu_surface_checkConsistency(*surf);
1701 #endif
1702 
1703   g_array_unref(points);
1704   g_array_unref(vTab);
1705   g_free(iTab);
1706   return TRUE;
1707 }
1708 
1709 
1710 /*****************************/
1711 /* XML files for iso-values. */
1712 /*****************************/
1713 
1714 /*
1715    <surfaces>
1716      <surface rendered="yes" iso-value="0.45" name="foo">
1717        <hidden-by-planes status="yes" />
1718        <color rgba="0.5 0.5 0.5 1." material="0.2 1. 0.5 0.5 0." />
1719      </surface>
1720    </surfaces>
1721 */
1722 
1723 /* Known elements. */
1724 #define SURF_PARSER_ELEMENT_SURFACES  "surfaces"
1725 #define SURF_PARSER_ELEMENT_SURFACE   "surface"
1726 #define SURF_PARSER_ELEMENT_HIDE      "hidden-by-planes"
1727 #define SURF_PARSER_ELEMENT_COLOR     "color"
1728 /* Known attributes. */
1729 #define SURF_PARSER_ATTRIBUTES_RENDERED "rendered"
1730 #define SURF_PARSER_ATTRIBUTES_VALUE    "iso-value"
1731 #define SURF_PARSER_ATTRIBUTES_NAME     "name"
1732 #define SURF_PARSER_ATTRIBUTES_STATUS   "status"
1733 #define SURF_PARSER_ATTRIBUTES_RGBA     "rgba"
1734 #define SURF_PARSER_ATTRIBUTES_MATERIAL "material"
1735 
1736 struct _surfaces_xml
1737 {
1738   gchar *name;
1739   float iso;
1740   gboolean rendered, masked;
1741   gboolean colorSet, materialSet;
1742   float color[4], material[5];
1743 };
1744 
1745 static gboolean startVisuSurface;
1746 
1747 /* This method is called for every element that is parsed.
1748    The user_data must be a GList of _surfaces_xml. When a 'surface'
1749    element, a new struct instance is created and prepend in the list.
1750    When 'hidden-by-planes' or other qualificative elements are
1751    found, the first surface of the list is modified accordingly. */
surfacesXML_element(GMarkupParseContext * context _U_,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,gpointer user_data,GError ** error)1752 static void surfacesXML_element(GMarkupParseContext *context _U_,
1753                           const gchar         *element_name,
1754                           const gchar        **attribute_names,
1755                           const gchar        **attribute_values,
1756                           gpointer             user_data,
1757                           GError             **error)
1758 {
1759   GList **surfacesList;
1760   struct _surfaces_xml *surf;
1761   int i;
1762 
1763   g_return_if_fail(user_data);
1764   surfacesList = (GList **)user_data;
1765 
1766   DBG_fprintf(stderr, "Surf parser: found '%s' element.\n", element_name);
1767   if (!strcmp(element_name, SURF_PARSER_ELEMENT_SURFACES))
1768     {
1769       /* Should have no attributes. */
1770       if (attribute_names[0])
1771 	{
1772 	  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
1773 		      _("Unexpected attribute '%s' for element '%s'."),
1774 		      attribute_names[0], SURF_PARSER_ELEMENT_SURFACES);
1775 	  return;
1776 	}
1777       /* Initialise the surfacesList. */
1778       if (*surfacesList)
1779 	{
1780 	  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1781 		      _("DTD error: element '%s' should appear only once."),
1782 		      SURF_PARSER_ELEMENT_SURFACES);
1783 	  return;
1784 	}
1785       *surfacesList = (GList*)0;
1786       startVisuSurface = TRUE;
1787     }
1788   else if (!strcmp(element_name, SURF_PARSER_ELEMENT_SURFACE))
1789     {
1790       surf = g_malloc(sizeof(struct _surfaces_xml));
1791       surf->name        = (gchar*)0;
1792       surf->rendered    = TRUE;
1793       surf->masked      = TRUE;
1794       surf->iso         = 12345.6789f;
1795       surf->colorSet    = FALSE;
1796       surf->materialSet = FALSE;
1797 
1798       /* We parse the attributes. */
1799       for (i = 0; attribute_names[i]; i++)
1800 	{
1801 	  if (!strcmp(attribute_names[i], SURF_PARSER_ATTRIBUTES_NAME))
1802 	    surf->name = g_strdup(attribute_values[i]);
1803 	  else if (!strcmp(attribute_names[i], SURF_PARSER_ATTRIBUTES_RENDERED))
1804 	    {
1805 	      if (!strcmp(attribute_values[i], "yes"))
1806 		surf->rendered = TRUE;
1807 	      else if (!strcmp(attribute_values[i], "no"))
1808 		surf->rendered = FALSE;
1809 	      else
1810 		g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1811 			    _("Invalid value '%s' for attribute '%s'."),
1812 			    attribute_values[i], SURF_PARSER_ATTRIBUTES_RENDERED);
1813 	    }
1814 	  else if (!strcmp(attribute_names[i], SURF_PARSER_ATTRIBUTES_VALUE))
1815 	    {
1816 	      if (!(sscanf(attribute_values[i], "%f", &surf->iso) == 1))
1817 		g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1818 			    _("Invalid value '%s' for attribute '%s'."),
1819 			    attribute_values[i], SURF_PARSER_ATTRIBUTES_VALUE);
1820 	    }
1821 	  else
1822 	    g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
1823 			_("Unexpected attribute '%s' for element '%s'."),
1824 			attribute_names[i], SURF_PARSER_ELEMENT_SURFACE);
1825 	  if (*error)
1826 	    {
1827 	      g_free(surf->name);
1828 	      g_free(surf);
1829 	      return;
1830 	    }
1831 	}
1832       /* We check the mandatory attribute. */
1833       if (surf->iso == 12345.6789f)
1834 	{
1835 	  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1836 		      _("Missing attribute '%s' for element '%s'."),
1837 		      SURF_PARSER_ATTRIBUTES_VALUE, SURF_PARSER_ELEMENT_SURFACE);
1838 	  g_free(surf->name);
1839 	  g_free(surf);
1840 	  return;
1841 	}
1842       DBG_fprintf(stderr, "Surf parser: add a new surface '%s' %f %d.\n",
1843 		  (surf->name)?surf->name:"None", surf->iso, surf->rendered);
1844       *surfacesList = g_list_prepend(*surfacesList, (gpointer)surf);
1845     }
1846   else if (startVisuSurface && !strcmp(element_name, SURF_PARSER_ELEMENT_HIDE))
1847     {
1848       if (!*surfacesList)
1849 	{
1850 	  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1851 		      _("DTD error: parent element '%s' of element '%s' is missing."),
1852 		      SURF_PARSER_ELEMENT_SURFACE, SURF_PARSER_ELEMENT_HIDE);
1853 	  return;
1854 	}
1855       surf = (struct _surfaces_xml*)((*surfacesList)->data);
1856 
1857       /* We read the mandatory attribute. */
1858       if (attribute_names[0])
1859 	{
1860 	  if (!strcmp(attribute_names[0], SURF_PARSER_ATTRIBUTES_STATUS))
1861 	    {
1862 	      if (!strcmp(attribute_values[0], "yes"))
1863 		surf->masked = TRUE;
1864 	      else if (!strcmp(attribute_values[0], "no"))
1865 		surf->masked = FALSE;
1866 	      else
1867 		g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1868 			    _("Invalid value '%s' for attribute '%s'."),
1869 			    attribute_values[0], SURF_PARSER_ATTRIBUTES_STATUS);
1870 	    }
1871 	  else
1872 	    g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
1873 			_("Unexpected attribute '%s' for element '%s'."),
1874 			attribute_names[0], SURF_PARSER_ELEMENT_HIDE);
1875 	}
1876       else
1877 	g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1878 		    _("Missing attribute '%s' for element '%s'."),
1879 		    SURF_PARSER_ATTRIBUTES_VALUE, SURF_PARSER_ELEMENT_SURFACE);
1880       if (*error)
1881 	return;
1882 
1883     }
1884   else if (startVisuSurface && !strcmp(element_name, SURF_PARSER_ELEMENT_COLOR))
1885     {
1886       if (!*surfacesList)
1887 	{
1888 	  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1889 		      _("DTD error: parent element '%s' of element '%s' is missing."),
1890 		      SURF_PARSER_ELEMENT_SURFACE, SURF_PARSER_ELEMENT_COLOR);
1891 	  return;
1892 	}
1893       surf = (struct _surfaces_xml*)((*surfacesList)->data);
1894 
1895       for(i = 0; attribute_names[i]; i++)
1896 	{
1897 	  if (!strcmp(attribute_names[i], SURF_PARSER_ATTRIBUTES_RGBA))
1898 	    {
1899 	      if (sscanf(attribute_values[i], "%g %g %g %g",
1900 			 surf->color, surf->color + 1,
1901 			 surf->color + 2, surf->color + 3) != 4)
1902 		g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1903 			    _("Invalid value '%s' for attribute '%s'."),
1904 			    attribute_values[i], SURF_PARSER_ATTRIBUTES_RGBA);
1905 	      else
1906 		surf->colorSet = TRUE;
1907 	    }
1908 	  else if (!strcmp(attribute_names[i], SURF_PARSER_ATTRIBUTES_MATERIAL))
1909 	    {
1910 	      if (sscanf(attribute_values[i], "%g %g %g %g %g",
1911 			 surf->material, surf->material + 1, surf->material + 2,
1912 			 surf->material + 3, surf->material + 4) != 5)
1913 		g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1914 			    _("Invalid value '%s' for attribute '%s'."),
1915 			    attribute_values[i], SURF_PARSER_ATTRIBUTES_MATERIAL);
1916 	      else
1917 		surf->materialSet = TRUE;
1918 	    }
1919 	  else
1920 	    g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
1921 			_("Unexpected attribute '%s' for element '%s'."),
1922 			attribute_names[i], SURF_PARSER_ELEMENT_COLOR);
1923 	  if (*error)
1924 	    return;
1925 	}
1926     }
1927   else if (startVisuSurface)
1928     {
1929       /* We silently ignore the element if surfacesList is unset, but
1930 	 raise an error if surfacesList has been set. */
1931       g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1932 		  _("Unexpected element '%s'."), element_name);
1933     }
1934 }
1935 
1936 /* Check when a element is closed that everything required has been set. */
surfacesXML_end(GMarkupParseContext * context _U_,const gchar * element_name,gpointer user_data _U_,GError ** error _U_)1937 void surfacesXML_end(GMarkupParseContext *context _U_,
1938 		      const gchar         *element_name,
1939 		      gpointer             user_data _U_,
1940 		      GError             **error _U_)
1941 {
1942   if (!strcmp(element_name, SURF_PARSER_ELEMENT_SURFACES))
1943     startVisuSurface = FALSE;
1944 }
1945 
1946 /* What to do when an error is raised. */
surfacesXML_error(GMarkupParseContext * context _U_,GError * error,gpointer user_data)1947 static void surfacesXML_error(GMarkupParseContext *context _U_,
1948 			GError              *error,
1949 			gpointer             user_data)
1950 {
1951   GList *tmpLst;
1952 
1953   DBG_fprintf(stderr, "Surf parser: error raised '%s'.\n", error->message);
1954   g_return_if_fail(user_data);
1955 
1956   /* We free the current list of surfaces. */
1957   tmpLst = *(GList**)user_data;
1958   while (tmpLst)
1959     {
1960       g_free(((struct _surfaces_xml*)tmpLst->data)->name);
1961       g_free(tmpLst->data);
1962       tmpLst = g_list_next(tmpLst);
1963     }
1964   g_list_free(*(GList**)user_data);
1965 }
1966 
1967 /**
1968  * visu_surface_parseXMLFile:
1969  * @filename: a path to a file.
1970  * @surfaces: (inout) (element-type VisuSurface*): a location on a
1971  * #VisuSurface pointer.
1972  * @field: the scalar field to create the surface from.
1973  * @error: a location to store a possible error.
1974  *
1975  * Parse the given XML file, looking for the &lt;surfaces&gt; tag and create
1976  * the given surfaces.
1977  *
1978  * Returns: FALSE if a error occured.
1979  */
visu_surface_parseXMLFile(const gchar * filename,GList ** surfaces,VisuScalarField * field,GError ** error)1980 gboolean visu_surface_parseXMLFile(const gchar* filename, GList **surfaces,
1981 			       VisuScalarField *field, GError **error)
1982 {
1983   GMarkupParseContext* xmlContext;
1984   GMarkupParser parser;
1985   gboolean status;
1986   gsize size;
1987   gchar *buffer;
1988   GList *list, *tmpLst;
1989   VisuSurface *surface;
1990   struct _surfaces_xml *surf;
1991   VisuSurfaceResource *res;
1992 
1993   g_return_val_if_fail(filename && surfaces && field, FALSE);
1994 
1995   buffer = (gchar*)0;
1996   if (!g_file_get_contents(filename, &buffer, &size, error))
1997     return FALSE;
1998 
1999   /* Create context. */
2000   list = (GList*)0;
2001   parser.start_element = surfacesXML_element;
2002   parser.end_element   = surfacesXML_end;
2003   parser.text          = NULL;
2004   parser.passthrough   = NULL;
2005   parser.error         = surfacesXML_error;
2006   xmlContext = g_markup_parse_context_new(&parser, 0, &list, NULL);
2007 
2008   /* Parse data. */
2009   startVisuSurface = FALSE;
2010   status = g_markup_parse_context_parse(xmlContext, buffer, size, error);
2011 
2012   /* Free buffers. */
2013   g_markup_parse_context_free(xmlContext);
2014   g_free(buffer);
2015 
2016   if (!status)
2017     return FALSE;
2018 
2019   if (!list)
2020     {
2021       *error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY,
2022 			  _("No iso-value found."));
2023       return FALSE;
2024     }
2025 
2026   /* Need to reverse the list since elements have been prepended. */
2027   list = g_list_reverse(list);
2028 
2029   /* Convert the list to new isosurfaces. */
2030   DBG_fprintf(stderr, "Surf parser: create %d new surfaces for %p.\n",
2031 	      g_list_length(list), (gpointer)(*surfaces));
2032   tmpLst = list;
2033   while(tmpLst)
2034     {
2035       surf = (struct _surfaces_xml*)tmpLst->data;
2036       surface = visu_surface_new_fromScalarField(field, surf->iso, surf->name);
2037       if (surface)
2038 	{
2039 	  res = visu_surface_getResource(surface);
2040           g_object_set(G_OBJECT(res), "rendered", surf->rendered,
2041                        "maskable", surf->masked, NULL);
2042 	  if (surf->colorSet)
2043             g_object_set(G_OBJECT(res), "color", tool_color_addFloatRGBA(surf->color, NULL), NULL);
2044 	  if (surf->materialSet)
2045             g_object_set(G_OBJECT(res), "material", surf->material, NULL);
2046           *surfaces = g_list_append(*surfaces, surface);
2047 	}
2048       g_free(surf->name);
2049       g_free(surf);
2050       tmpLst = g_list_next(tmpLst);
2051     }
2052   g_list_free(list);
2053 
2054   return TRUE;
2055 }
2056 
2057 /**
2058  * visu_surface_exportXMLFile:
2059  * @filename: a path to a file.
2060  * @values: an array of @n values.
2061  * @res: an array of @n #VisuSurfaceResource.
2062  * @n: number of surface resources to export.
2063  * @error: a location to store a possible error.
2064  *
2065  * Export the surface resources into an XML file.
2066  *
2067  * Returns: FALSE if a error occured.
2068  */
visu_surface_exportXMLFile(const gchar * filename,float * values,VisuSurfaceResource ** res,int n,GError ** error)2069 gboolean visu_surface_exportXMLFile(const gchar* filename, float *values,
2070                                      VisuSurfaceResource **res, int n, GError **error)
2071 {
2072   gboolean valid;
2073   GString *output;
2074   int i;
2075   gchar *lbl;
2076   gboolean rendered, maskable;
2077   ToolColor *color;
2078   float *mat;
2079 
2080   /* We actually output the values. */
2081   output = g_string_new("  <surfaces>\n");
2082   for (i = 0; i < n; i++)
2083     {
2084       g_object_get(G_OBJECT(res[i]), "label", &lbl, "color", &color,
2085                    "material", &mat, "rendered", &rendered,
2086                    "maskable", &maskable, NULL);
2087       g_string_append_printf(output, "    <surface rendered=\"%s\" iso-value=\"%g\"",
2088 			     (rendered)?"yes":"no", values[i]);
2089       if (lbl && lbl[0])
2090 	g_string_append_printf(output, " name=\"%s\"", lbl);
2091       g_string_append(output, ">\n");
2092       g_string_append_printf(output, "      <hidden-by-planes status=\"%s\" />\n",
2093 			     (maskable)?"yes":"no");
2094       g_string_append_printf(output, "      <color rgba=\"%g %g %g %g\""
2095 			     " material=\"%g %g %g %g %g\" />\n",
2096 			     color->rgba[0], color->rgba[1],
2097 			     color->rgba[2], color->rgba[3],
2098 			     mat[0], mat[1], mat[2], mat[3], mat[4]);
2099       g_string_append(output, "    </surface>\n");
2100     }
2101   g_string_append(output, "  </surfaces>");
2102 
2103   valid = tool_XML_substitute(output, filename, "surfaces", error);
2104   if (!valid)
2105     {
2106       g_string_free(output, TRUE);
2107       return FALSE;
2108     }
2109 
2110   valid = g_file_set_contents(filename, output->str, -1, error);
2111   g_string_free(output, TRUE);
2112   return valid;
2113 }
2114