svn-gvsig-desktop / trunk / extensions / extGraph / src / org / gvsig / fmap / algorithm / triangulation / visad / DelaunayWatson.java @ 39203
History | View | Annotate | Download (11.1 KB)
1 |
//
|
---|---|
2 |
// DelaunayWatson.java
|
3 |
//
|
4 |
|
5 |
/*
|
6 |
VisAD system for interactive analysis and visualization of numerical
|
7 |
data. Copyright (C) 1996 - 2002 Bill Hibbard, Curtis Rueden, Tom
|
8 |
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
|
9 |
Tommy Jasmin.
|
10 |
|
11 |
This library is free software; you can redistribute it and/or
|
12 |
modify it under the terms of the GNU Library General Public
|
13 |
License as published by the Free Software Foundation; either
|
14 |
version 2 of the License, or (at your option) any later version.
|
15 |
|
16 |
This library is distributed in the hope that it will be useful,
|
17 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
18 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
19 |
Library General Public License for more details.
|
20 |
|
21 |
You should have received a copy of the GNU Library General Public
|
22 |
License along with this library; if not, write to the Free
|
23 |
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
24 |
MA 02111-1307, USA
|
25 |
*/
|
26 |
|
27 |
package org.gvsig.fmap.algorithm.triangulation.visad; |
28 |
|
29 |
import java.util.Random; |
30 |
|
31 |
/*
|
32 |
* The Delaunay triangulation/tetrahedralization algorithm in this class is
|
33 |
* originally from nnsort.c by David F. Watson:
|
34 |
*
|
35 |
* nnsort() finds the Delaunay triangulation of the two- or three-component
|
36 |
* vectors in 'data_list' and returns a list of simplex vertices in 'vertices'
|
37 |
* with the corresponding circumcentre and squared radius in the rows of
|
38 |
* 'circentres'. nnsort() also can be used to find the ordered convex hull of
|
39 |
* the two- or three-component vectors in 'data_list' and returns a list of
|
40 |
* (d-1)-facet vertices in 'vertices' (dummy filename for 'circentres' must be
|
41 |
* used). nnsort() was written by Dave Watson and uses the algorithm described
|
42 |
* in - Watson, D.F., 1981, Computing the n-dimensional Delaunay tessellation
|
43 |
* with application to Voronoi polytopes: The Computer J., 24(2), p. 167-172.
|
44 |
*
|
45 |
* additional information about this algorithm can be found in - CONTOURING: A
|
46 |
* guide to the analysis and display of spatial data, by David F. Watson,
|
47 |
* Pergamon Press, 1992, ISBN 0 08 040286 0
|
48 |
*/
|
49 |
|
50 |
/**
|
51 |
* DelaunayWatson represents an O(N^2) method with low overhead to find the
|
52 |
* Delaunay triangulation or tetrahedralization of a set of samples of R^2 or
|
53 |
* R^3.
|
54 |
* <P>
|
55 |
*/
|
56 |
public class DelaunayWatson extends Delaunay { |
57 |
|
58 |
private static final float BIGNUM = (float) 1E37; |
59 |
private static final float EPSILON = 0.00001f; |
60 |
// temporary storage size factor
|
61 |
private static final int TSIZE = 75; |
62 |
// factor (>=1) for radius of control points
|
63 |
private static final float RANGE = 10.0f; |
64 |
|
65 |
public DelaunayWatson(double[][] samples) throws VisADException { |
66 |
int dim = samples.length;
|
67 |
int nrs = samples[0].length; |
68 |
|
69 |
double xx, yy, bgs;
|
70 |
int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i11;
|
71 |
int[] ii = new int[3]; |
72 |
int dm, dim1, nts, tsz;
|
73 |
|
74 |
double[][] mxy = new double[2][dim]; |
75 |
for (i0 = 0; i0 < dim; i0++) |
76 |
mxy[0][i0] = -(mxy[1][i0] = BIGNUM); |
77 |
dim1 = dim + 1;
|
78 |
double[][] wrk = new double[dim][dim1]; |
79 |
for (i0 = 0; i0 < dim; i0++) |
80 |
for (i1 = 0; i1 < dim1; i1++) |
81 |
wrk[i0][i1] = -RANGE; |
82 |
for (i0 = 0; i0 < dim; i0++) |
83 |
wrk[i0][i0] = RANGE * (3 * dim - 1); |
84 |
|
85 |
double[][] pts = new double[nrs + dim1][dim]; |
86 |
for (i0 = 0; i0 < nrs; i0++) { |
87 |
if (dim < 3) { |
88 |
pts[i0][0] = samples[0][i0]; |
89 |
pts[i0][1] = samples[1][i0]; |
90 |
} else {
|
91 |
pts[i0][0] = samples[0][i0]; |
92 |
pts[i0][1] = samples[1][i0]; |
93 |
pts[i0][2] = samples[2][i0]; |
94 |
} |
95 |
// compute bounding box
|
96 |
for (i1 = 0; i1 < dim; i1++) { |
97 |
if (mxy[0][i1] < pts[i0][i1]) |
98 |
mxy[0][i1] = pts[i0][i1]; // max |
99 |
if (mxy[1][i1] > pts[i0][i1]) |
100 |
mxy[1][i1] = pts[i0][i1]; // min |
101 |
} |
102 |
} |
103 |
|
104 |
for (bgs = 0, i0 = 0; i0 < dim; i0++) { |
105 |
mxy[0][i0] -= mxy[1][i0]; |
106 |
if (bgs < mxy[0][i0]) |
107 |
bgs = mxy[0][i0];
|
108 |
} |
109 |
// now bgs = largest range
|
110 |
// add random perturbations to points
|
111 |
bgs *= EPSILON; |
112 |
|
113 |
Random rand = new Random(367); |
114 |
for (i0 = 0; i0 < nrs; i0++) |
115 |
for (i1 = 0; i1 < dim; i1++) { |
116 |
// random numbers [0, 1]
|
117 |
pts[i0][i1] += bgs * (0.5 - rand.nextDouble() / 0x7fffffff); |
118 |
} |
119 |
for (i0 = 0; i0 < dim1; i0++) |
120 |
for (i1 = 0; i1 < dim; i1++) { |
121 |
pts[nrs + i0][i1] = mxy[1][i1] + wrk[i1][i0] * mxy[0][i1]; |
122 |
} |
123 |
for (i1 = 1, i0 = 2; i0 < dim1; i0++) |
124 |
i1 *= i0; |
125 |
tsz = TSIZE * i1; |
126 |
int[][] tmp = new int[tsz + 1][dim]; |
127 |
// storage allocation - increase value of `i1' for 3D if necessary
|
128 |
i1 *= (nrs + 50 * i1);
|
129 |
/* WLH 4 Nov 97 */
|
130 |
if (dim == 3) |
131 |
i1 *= 10;
|
132 |
/* end WLH 4 Nov 97 */
|
133 |
int[] id = new int[i1]; |
134 |
for (i0 = 0; i0 < i1; i0++) |
135 |
id[i0] = i0; |
136 |
int[][] a3s = new int[i1][dim1]; |
137 |
double[][] ccr = new double[i1][dim1]; |
138 |
for (a3s[0][0] = nrs, i0 = 1; i0 < dim1; i0++) |
139 |
a3s[0][i0] = a3s[0][i0 - 1] + 1; |
140 |
for (ccr[0][dim] = BIGNUM, i0 = 0; i0 < dim; i0++) |
141 |
ccr[0][i0] = 0; |
142 |
nts = i4 = 1;
|
143 |
dm = dim - 1;
|
144 |
for (i0 = 0; i0 < nrs; i0++) { |
145 |
i1 = i7 = -1;
|
146 |
i9 = 0;
|
147 |
Loop3: for (i11 = 0; i11 < nts; i11++) { |
148 |
i1++; |
149 |
while (a3s[i1][0] < 0) |
150 |
i1++; |
151 |
xx = ccr[i1][dim]; |
152 |
for (i2 = 0; i2 < dim; i2++) { |
153 |
xx -= (pts[i0][i2] - ccr[i1][i2]) |
154 |
* (pts[i0][i2] - ccr[i1][i2]); |
155 |
if (xx < 0) |
156 |
continue Loop3;
|
157 |
} |
158 |
i9--; |
159 |
i4--; |
160 |
id[i4] = i1; |
161 |
Loop2: for (i2 = 0; i2 < dim1; i2++) { |
162 |
ii[0] = 0; |
163 |
if (ii[0] == i2) |
164 |
ii[0]++;
|
165 |
for (i3 = 1; i3 < dim; i3++) { |
166 |
ii[i3] = ii[i3 - 1] + 1; |
167 |
if (ii[i3] == i2)
|
168 |
ii[i3]++; |
169 |
} |
170 |
if (i7 > dm) {
|
171 |
i8 = i7; |
172 |
Loop1: for (i3 = 0; i3 <= i8; i3++) { |
173 |
for (i5 = 0; i5 < dim; i5++) { |
174 |
if (a3s[i1][ii[i5]] != tmp[i3][i5])
|
175 |
continue Loop1;
|
176 |
} |
177 |
for (i6 = 0; i6 < dim; i6++) |
178 |
tmp[i3][i6] = tmp[i8][i6]; |
179 |
i7--; |
180 |
continue Loop2;
|
181 |
} |
182 |
} |
183 |
if (++i7 > tsz) {
|
184 |
int newtsz = 2 * tsz; |
185 |
int[][] newtmp = new int[newtsz + 1][dim]; |
186 |
System.arraycopy(tmp, 0, newtmp, 0, tsz); |
187 |
tsz = newtsz; |
188 |
tmp = newtmp; |
189 |
// WLH 23 july 97
|
190 |
// throw new VisADException(
|
191 |
// "DelaunayWatson: Temporary storage exceeded");
|
192 |
} |
193 |
for (i3 = 0; i3 < dim; i3++) |
194 |
tmp[i7][i3] = a3s[i1][ii[i3]]; |
195 |
} |
196 |
a3s[i1][0] = -1; |
197 |
} |
198 |
for (i1 = 0; i1 <= i7; i1++) { |
199 |
for (i2 = 0; i2 < dim; i2++) { |
200 |
for (wrk[i2][dim] = 0, i3 = 0; i3 < dim; i3++) { |
201 |
wrk[i2][i3] = pts[tmp[i1][i2]][i3] - pts[i0][i3]; |
202 |
wrk[i2][dim] += wrk[i2][i3] |
203 |
* (pts[tmp[i1][i2]][i3] + pts[i0][i3]) / 2;
|
204 |
} |
205 |
} |
206 |
if (dim < 3) { |
207 |
xx = wrk[0][0] * wrk[1][1] - wrk[1][0] * wrk[0][1]; |
208 |
ccr[id[i4]][0] = (wrk[0][2] * wrk[1][1] - wrk[1][2] |
209 |
* wrk[0][1]) |
210 |
/ xx; |
211 |
ccr[id[i4]][1] = (wrk[0][0] * wrk[1][2] - wrk[1][0] |
212 |
* wrk[0][2]) |
213 |
/ xx; |
214 |
} else {
|
215 |
xx = (wrk[0][0] * (wrk[1][1] * wrk[2][2] - wrk[2][1] |
216 |
* wrk[1][2])) |
217 |
- (wrk[0][1] * (wrk[1][0] * wrk[2][2] - wrk[2][0] |
218 |
* wrk[1][2])) |
219 |
+ (wrk[0][2] * (wrk[1][0] * wrk[2][1] - wrk[2][0] |
220 |
* wrk[1][1])); |
221 |
ccr[id[i4]][0] = ((wrk[0][3] * (wrk[1][1] * wrk[2][2] - wrk[2][1] |
222 |
* wrk[1][2])) |
223 |
- (wrk[0][1] * (wrk[1][3] * wrk[2][2] - wrk[2][3] |
224 |
* wrk[1][2])) + (wrk[0][2] * (wrk[1][3] |
225 |
* wrk[2][1] - wrk[2][3] * wrk[1][1]))) |
226 |
/ xx; |
227 |
ccr[id[i4]][1] = ((wrk[0][0] * (wrk[1][3] * wrk[2][2] - wrk[2][3] |
228 |
* wrk[1][2])) |
229 |
- (wrk[0][3] * (wrk[1][0] * wrk[2][2] - wrk[2][0] |
230 |
* wrk[1][2])) + (wrk[0][2] * (wrk[1][0] |
231 |
* wrk[2][3] - wrk[2][0] * wrk[1][3]))) |
232 |
/ xx; |
233 |
ccr[id[i4]][2] = ((wrk[0][0] * (wrk[1][1] * wrk[2][3] - wrk[2][1] |
234 |
* wrk[1][3])) |
235 |
- (wrk[0][1] * (wrk[1][0] * wrk[2][3] - wrk[2][0] |
236 |
* wrk[1][3])) + (wrk[0][3] * (wrk[1][0] |
237 |
* wrk[2][1] - wrk[2][0] * wrk[1][1]))) |
238 |
/ xx; |
239 |
} |
240 |
for (ccr[id[i4]][dim] = 0, i2 = 0; i2 < dim; i2++) { |
241 |
ccr[id[i4]][dim] += (pts[i0][i2] - ccr[id[i4]][i2]) |
242 |
* (pts[i0][i2] - ccr[id[i4]][i2]); |
243 |
a3s[id[i4]][i2] = tmp[i1][i2]; |
244 |
} |
245 |
a3s[id[i4]][dim] = i0; |
246 |
i4++; |
247 |
i9++; |
248 |
} |
249 |
nts += i9; |
250 |
} |
251 |
|
252 |
/*
|
253 |
* OUTPUT is in a3s ARRAY needed output is: Tri - array of pointers from
|
254 |
* triangles or tetrahedra to their corresponding vertices Vertices -
|
255 |
* array of pointers from vertices to their corresponding triangles or
|
256 |
* tetrahedra Walk - array of pointers from triangles or tetrahedra to
|
257 |
* neighboring triangles or tetrahedra Edges - array of pointers from
|
258 |
* each triangle or tetrahedron's edges to their corresponding triangles
|
259 |
* or tetrahedra
|
260 |
*
|
261 |
* helpers: nverts - number of triangles or tetrahedra per vertex
|
262 |
*/
|
263 |
|
264 |
// compute number of triangles or tetrahedra
|
265 |
int[] nverts = new int[nrs]; |
266 |
for (int i = 0; i < nrs; i++) |
267 |
nverts[i] = 0;
|
268 |
int ntris = 0; |
269 |
i0 = -1;
|
270 |
for (i11 = 0; i11 < nts; i11++) { |
271 |
i0++; |
272 |
while (a3s[i0][0] < 0) |
273 |
i0++; |
274 |
if (a3s[i0][0] < nrs) { |
275 |
ntris++; |
276 |
if (dim < 3) { |
277 |
nverts[a3s[i0][0]]++;
|
278 |
nverts[a3s[i0][1]]++;
|
279 |
nverts[a3s[i0][2]]++;
|
280 |
} else {
|
281 |
nverts[a3s[i0][0]]++;
|
282 |
nverts[a3s[i0][1]]++;
|
283 |
nverts[a3s[i0][2]]++;
|
284 |
nverts[a3s[i0][3]]++;
|
285 |
} |
286 |
} |
287 |
} |
288 |
Vertices = new int[nrs][]; |
289 |
for (int i = 0; i < nrs; i++) |
290 |
Vertices[i] = new int[nverts[i]]; |
291 |
for (int i = 0; i < nrs; i++) |
292 |
nverts[i] = 0;
|
293 |
|
294 |
// build Tri & Vertices components
|
295 |
Tri = new int[ntris][dim1]; |
296 |
int a, b, c, d;
|
297 |
int itri = 0; |
298 |
i0 = -1;
|
299 |
for (i11 = 0; i11 < nts; i11++) { |
300 |
i0++; |
301 |
while (a3s[i0][0] < 0) |
302 |
i0++; |
303 |
if (a3s[i0][0] < nrs) { |
304 |
if (dim < 3) { |
305 |
a = a3s[i0][0];
|
306 |
b = a3s[i0][1];
|
307 |
c = a3s[i0][2];
|
308 |
Vertices[a][nverts[a]] = itri; |
309 |
nverts[a]++; |
310 |
Vertices[b][nverts[b]] = itri; |
311 |
nverts[b]++; |
312 |
Vertices[c][nverts[c]] = itri; |
313 |
nverts[c]++; |
314 |
Tri[itri][0] = a;
|
315 |
Tri[itri][1] = b;
|
316 |
Tri[itri][2] = c;
|
317 |
} else {
|
318 |
a = a3s[i0][0];
|
319 |
b = a3s[i0][1];
|
320 |
c = a3s[i0][2];
|
321 |
d = a3s[i0][3];
|
322 |
Vertices[a][nverts[a]] = itri; |
323 |
nverts[a]++; |
324 |
Vertices[b][nverts[b]] = itri; |
325 |
nverts[b]++; |
326 |
Vertices[c][nverts[c]] = itri; |
327 |
nverts[c]++; |
328 |
Vertices[d][nverts[d]] = itri; |
329 |
nverts[d]++; |
330 |
Tri[itri][0] = a;
|
331 |
Tri[itri][1] = b;
|
332 |
Tri[itri][2] = c;
|
333 |
Tri[itri][3] = d;
|
334 |
} |
335 |
itri++; |
336 |
} |
337 |
} |
338 |
|
339 |
// call more generic method for constructing Walk and Edges arrays
|
340 |
finish_triang(samples); |
341 |
} |
342 |
|
343 |
/*
|
344 |
* DO NOT DELETE THIS COMMENTED CODE IT CONTAINS ALGORITHM DETAILS NOT CAST
|
345 |
* INTO JAVA (YET?) i0 = -1; for (i11=0; i11<nts; i11++) { i0++; while
|
346 |
* (a3s[i0][0] < 0) i0++; if (a3s[i0][0] < nrs) { for (i1=0; i1<dim; i1++)
|
347 |
* for (i2=0; i2<dim; i2++) { wrk[i1][i2] = pts[a3s[i0][i1]][i2] -
|
348 |
* pts[a3s[i0][dim]][i2]; } if (dim < 3) { xx = wrk[0][0] * wrk[1][1] -
|
349 |
* wrk[0][1] * wrk[1][0]; if (fabs(xx) > EPSILON) { if (xx < 0)
|
350 |
* fprintf(afile,"%d %d %d\n",a3s[i0][0],a3s[i0][2],a3s[i0][1]); else
|
351 |
* fprintf(afile,"%d %d %d\n",a3s[i0][0],a3s[i0][1],a3s[i0][2]);
|
352 |
* fprintf(bfile,"%e %e %e\n",ccr[i0][0],ccr[i0][1],ccr[i0][2]); } } else {
|
353 |
* xx = ((wrk[0][0] * (wrk[1][1] * wrk[2][2] - wrk[2][1] * wrk[1][2])) -
|
354 |
* (wrk[0][1] * (wrk[1][0] * wrk[2][2] - wrk[2][0] * wrk[1][2])) +
|
355 |
* (wrk[0][2] * (wrk[1][0] * wrk[2][1] - wrk[2][0] * wrk[1][1]))); if
|
356 |
* (fabs(xx) > EPSILON) { if (xx < 0) fprintf(afile,"%d %d %d %d\n",
|
357 |
* a3s[i0][0],a3s[i0][1],a3s[i0][3],a3s[i0][2]); else fprintf(afile,"%d %d
|
358 |
* %d %d\n", a3s[i0][0],a3s[i0][1],a3s[i0][2],a3s[i0][3]); fprintf(bfile,"%e
|
359 |
* %e %e %e\n", ccr[i0][0],ccr[i0][1],ccr[i0][2],ccr[i0][3]); } } } }
|
360 |
*/
|
361 |
|
362 |
} |