svn-gvsig-desktop / trunk / extensions / extGraph / src / org / gvsig / fmap / algorithm / triangulation / visad / Delaunay.java @ 39203
History | View | Annotate | Download (26.5 KB)
1 |
//
|
---|---|
2 |
// Delaunay.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 |
|
30 |
/**
|
31 |
Delaunay represents an abstract class for calculating an
|
32 |
N-dimensional Delaunay triangulation, that can be extended
|
33 |
to allow for various triangulation methods.<P>
|
34 |
*/
|
35 |
public abstract class Delaunay implements java.io.Serializable { |
36 |
|
37 |
// Delaunay core components
|
38 |
public int[][] Tri; // triangles/tetrahedra --> vertices |
39 |
// Tri = new int[ntris][dim + 1]
|
40 |
public int[][] Vertices; // vertices --> triangles/tetrahedra |
41 |
// Vertices = new int[nrs][nverts[i]]
|
42 |
public int[][] Walk; // triangles/tetrahedra --> triangles/tetrahedra |
43 |
// Walk = new int[ntris][dim + 1]
|
44 |
public int[][] Edges; // tri/tetra edges --> global edge number |
45 |
// Edges = new int[ntris][3 * (dim - 1)];
|
46 |
public int NumEdges; // number of unique global edge numbers |
47 |
|
48 |
private boolean nonConvex = false; |
49 |
|
50 |
/** The abstract constructor initializes the class's data arrays. */
|
51 |
public Delaunay() throws VisADException { |
52 |
Tri = null;
|
53 |
Vertices = null;
|
54 |
Walk = null;
|
55 |
Edges = null;
|
56 |
NumEdges = 0;
|
57 |
} |
58 |
|
59 |
public void setNonConvex() { |
60 |
nonConvex = true;
|
61 |
} |
62 |
|
63 |
public boolean getNonConvex() { |
64 |
return nonConvex;
|
65 |
} |
66 |
|
67 |
|
68 |
/** The factory class method heuristically decides which extension
|
69 |
to the Delaunay abstract class to use in order to construct the
|
70 |
fastest triangulation, and calls that extension, returning the
|
71 |
finished triangulation. The exact parameter is an indication of
|
72 |
whether the exact Delaunay triangulation is required. The
|
73 |
method chooses from among the Fast, Clarkson, and Watson methods. */
|
74 |
public static Delaunay factory(double[][] samples, boolean exact) |
75 |
throws VisADException {
|
76 |
|
77 |
/* Note: Clarkson doesn't work well for very closely clumped site values,
|
78 |
since the algorithm rounds each value to the nearest integer
|
79 |
before computing the triangulation. This fact should probably
|
80 |
be taken into account in this factory algorithm, but as of yet
|
81 |
is not. In other words, if you need an exact triangulation
|
82 |
and have more than 3000 data sites, and they have closely
|
83 |
clumped values, be sure to scale them up before calling the
|
84 |
factory method. */
|
85 |
|
86 |
/* Note: The factory method will not take new Delaunay extensions into
|
87 |
account unless it is extended as well. */
|
88 |
|
89 |
int choice;
|
90 |
int FAST = 0; |
91 |
int CLARKSON = 1; |
92 |
int WATSON = 2; |
93 |
|
94 |
int dim = samples.length;
|
95 |
if (dim < 2) throw new VisADException("Delaunay.factory: " |
96 |
+"dimension must be 2 or higher");
|
97 |
|
98 |
// only Clarkson can handle triangulations in high dimensions
|
99 |
if (dim > 3) { |
100 |
choice = CLARKSON; |
101 |
} |
102 |
else {
|
103 |
int nrs = samples[0].length; |
104 |
for (int i=1; i<dim; i++) { |
105 |
nrs = Math.min(nrs, samples[i].length);
|
106 |
} |
107 |
if (dim == 2 && !exact && nrs > 10000) { |
108 |
// use fast in 2-D with a very large set and exact not required
|
109 |
choice = FAST; |
110 |
} |
111 |
else if (nrs > 3000) { |
112 |
// use Clarkson for large sets
|
113 |
choice = CLARKSON; |
114 |
} |
115 |
else {
|
116 |
choice = WATSON; |
117 |
} |
118 |
} |
119 |
|
120 |
try {
|
121 |
if (choice == FAST) {
|
122 |
// triangulate with the Fast method and one improvement pass
|
123 |
DelaunayFast delan = new DelaunayFast(samples);
|
124 |
delan.improve(samples, 1);
|
125 |
return (Delaunay) delan;
|
126 |
} |
127 |
if (choice == CLARKSON) {
|
128 |
// triangulate with the Clarkson method
|
129 |
DelaunayClarkson delan = new DelaunayClarkson(samples);
|
130 |
return (Delaunay) delan;
|
131 |
} |
132 |
if (choice == WATSON) {
|
133 |
// triangulate with the Watson method
|
134 |
DelaunayWatson delan = new DelaunayWatson(samples);
|
135 |
return (Delaunay) delan;
|
136 |
} |
137 |
} |
138 |
catch (Exception e) { |
139 |
if (choice != CLARKSON) {
|
140 |
try {
|
141 |
// triangulate with the Clarkson method
|
142 |
DelaunayClarkson delan = new DelaunayClarkson(samples);
|
143 |
return (Delaunay) delan;
|
144 |
} |
145 |
catch (Exception ee) { |
146 |
} |
147 |
} |
148 |
} |
149 |
|
150 |
return null; |
151 |
} |
152 |
|
153 |
/** test checks a triangulation in various ways to make sure it
|
154 |
is constructed correctly; test returns false if there are
|
155 |
any problems with the triangulation. This method is expensive,
|
156 |
provided mainly for debugging purposes. */
|
157 |
public boolean test(double[][] samples) { |
158 |
|
159 |
int dim = samples.length;
|
160 |
int dim1 = dim+1; |
161 |
int ntris = Tri.length;
|
162 |
int nrs = samples[0].length; |
163 |
for (int i=1; i<dim; i++) { |
164 |
nrs = Math.min(nrs, samples[i].length);
|
165 |
} |
166 |
|
167 |
// verify triangulation dimension
|
168 |
for (int i=0; i<ntris; i++) { |
169 |
if (Tri[i].length < dim1) return false; |
170 |
} |
171 |
|
172 |
// verify no illegal triangle vertices
|
173 |
for (int i=0; i<ntris; i++) { |
174 |
for (int j=0; j<dim1; j++) { |
175 |
if (Tri[i][j] < 0 || Tri[i][j] >= nrs) return false; |
176 |
} |
177 |
} |
178 |
|
179 |
// verify that all points are in at least one triangle
|
180 |
int[] nverts = new int[nrs]; |
181 |
for (int i=0; i<nrs; i++) nverts[i] = 0; |
182 |
for (int i=0; i<ntris; i++) { |
183 |
for (int j=0; j<dim1; j++) nverts[Tri[i][j]]++; |
184 |
} |
185 |
for (int i=0; i<nrs; i++) { |
186 |
if (nverts[i] == 0) return false; |
187 |
} |
188 |
|
189 |
// test for duplicate triangles
|
190 |
for (int i=0; i<ntris; i++) { |
191 |
for (int j=i+1; j<ntris; j++) { |
192 |
boolean[] m = new boolean[dim1]; |
193 |
for (int mi=0; mi<dim1; mi++) m[mi] = false; |
194 |
for (int k=0; k<dim1; k++) { |
195 |
for (int l=0; l<dim1; l++) { |
196 |
if (Tri[i][k] == Tri[j][l] && !m[l]) {
|
197 |
m[l] = true;
|
198 |
} |
199 |
} |
200 |
} |
201 |
boolean mtot = true; |
202 |
for (int k=0; k<dim1; k++) { |
203 |
if (!m[k]) mtot = false; |
204 |
} |
205 |
if (mtot) return false; |
206 |
} |
207 |
} |
208 |
|
209 |
// test for errors in Walk array
|
210 |
for (int i=0; i<ntris; i++) { |
211 |
for (int j=0; j<dim1; j++) { |
212 |
if (Walk[i][j] != -1) { |
213 |
boolean found = false; |
214 |
for (int k=0; k<dim1; k++) { |
215 |
if (Walk[Walk[i][j]][k] == i) found = true; |
216 |
} |
217 |
if (!found) return false; |
218 |
|
219 |
// make sure two walk'ed triangles share dim vertices
|
220 |
int sb = 0; |
221 |
for (int k=0; k<dim1; k++) { |
222 |
for (int l=0; l<dim1; l++) { |
223 |
if (Tri[i][k] == Tri[Walk[i][j]][l]) sb++;
|
224 |
} |
225 |
} |
226 |
if (sb != dim) return false; |
227 |
} |
228 |
} |
229 |
} |
230 |
|
231 |
// Note: Another test that could be performed is one that
|
232 |
// makes sure, given a triangle T, all points in the
|
233 |
// triangulation that are not part of T are located
|
234 |
// outside the bounds of T. This test would verify
|
235 |
// that there are no overlapping triangles.
|
236 |
|
237 |
// all tests passed
|
238 |
return true; |
239 |
} |
240 |
|
241 |
/** improve uses edge-flipping to bring the current triangulation
|
242 |
closer to the true Delaunay triangulation. pass is the number
|
243 |
of passes the algorithm should take over all edges (however,
|
244 |
the algorithm terminates if no edges are flipped for an
|
245 |
entire pass). */
|
246 |
public void improve(double[][] samples, int pass) throws VisADException { |
247 |
int dim = samples.length;
|
248 |
int dim1 = dim+1; |
249 |
if (Tri[0].length != dim1) { |
250 |
throw new SetException("Delaunay.improve: samples dimension " + |
251 |
"does not match");
|
252 |
} |
253 |
// only 2-D triangulations supported for now
|
254 |
if (dim > 2) { |
255 |
throw new UnimplementedException("Delaunay.improve: dimension " + |
256 |
"must be 2!");
|
257 |
} |
258 |
int ntris = Tri.length;
|
259 |
int nrs = samples[0].length; |
260 |
for (int i=1; i<dim; i++) { |
261 |
nrs = Math.min(nrs, samples[i].length);
|
262 |
} |
263 |
double[] samp0 = samples[0]; |
264 |
double[] samp1 = samples[1]; |
265 |
|
266 |
// go through entire triangulation pass times
|
267 |
boolean eflipped = false; |
268 |
for (int p=0; p<pass; p++) { |
269 |
eflipped = false;
|
270 |
|
271 |
// edge keeps track of which edges have been checked
|
272 |
boolean[] edge = new boolean[NumEdges]; |
273 |
for (int i=0; i<NumEdges; i++) edge[i] = true; |
274 |
|
275 |
// check every edge of every triangle
|
276 |
for (int t=0; t<ntris; t++) { |
277 |
int[] trit = Tri[t]; |
278 |
int[] walkt = Walk[t]; |
279 |
int[] edgest = Edges[t]; |
280 |
for (int e=0; e<2; e++) { |
281 |
int curedge = edgest[e];
|
282 |
// only check the edge if it hasn't been checked yet
|
283 |
if (edge[curedge]) {
|
284 |
int t2 = walkt[e];
|
285 |
|
286 |
// only check edge if it is not part of the outer hull
|
287 |
if (t2 >= 0) { |
288 |
int[] trit2 = Tri[t2]; |
289 |
int[] walkt2 = Walk[t2]; |
290 |
int[] edgest2 = Edges[t2]; |
291 |
|
292 |
// check if the diagonal needs to be flipped
|
293 |
int f = (walkt2[0] == t) ? 0 : |
294 |
(walkt2[1] == t) ? 1 : 2; |
295 |
int A = (e + 2) % 3; |
296 |
int B = (A + 1) % 3; |
297 |
int C = (B + 1) % 3; |
298 |
int D = (f + 2) % 3; |
299 |
double ax = samp0[trit[A]];
|
300 |
double ay = samp1[trit[A]];
|
301 |
double bx = samp0[trit[B]];
|
302 |
double by = samp1[trit[B]];
|
303 |
double cx = samp0[trit[C]];
|
304 |
double cy = samp1[trit[C]];
|
305 |
double dx = samp0[trit2[D]];
|
306 |
double dy = samp1[trit2[D]];
|
307 |
double abx = ax - bx;
|
308 |
double aby = ay - by;
|
309 |
double acx = ax - cx;
|
310 |
double acy = ay - cy;
|
311 |
double dbx = dx - bx;
|
312 |
double dby = dy - by;
|
313 |
double dcx = dx - cx;
|
314 |
double dcy = dy - cy;
|
315 |
double Q = abx*acx + aby*acy;
|
316 |
double R = dbx*abx + dby*aby;
|
317 |
double S = acx*dcx + acy*dcy;
|
318 |
double T = dbx*dcx + dby*dcy;
|
319 |
boolean QD = abx*acy - aby*acx >= 0; |
320 |
boolean RD = dbx*aby - dby*abx >= 0; |
321 |
boolean SD = acx*dcy - acy*dcx >= 0; |
322 |
boolean TD = dcx*dby - dcy*dbx >= 0; |
323 |
boolean sig = (QD ? 1 : 0) + (RD ? 1 : 0) |
324 |
+ (SD ? 1 : 0) + (TD ? 1 : 0) < 2; |
325 |
boolean d;
|
326 |
if (QD == sig) d = true; |
327 |
else if (RD == sig) d = false; |
328 |
else if (SD == sig) d = false; |
329 |
else if (TD == sig) d = true; |
330 |
else if (Q < 0 && T < 0 || R > 0 && S > 0) d = true; |
331 |
else if (R < 0 && S < 0 || Q > 0 && T > 0) d = false; |
332 |
else if ((Q < 0 ? Q : T) < (R < 0 ? R : S)) d = true; |
333 |
else d = false; |
334 |
if (d) {
|
335 |
// diagonal needs to be swapped
|
336 |
eflipped = true;
|
337 |
int n1 = trit[A];
|
338 |
int n2 = trit[B];
|
339 |
int n3 = trit[C];
|
340 |
int n4 = trit2[D];
|
341 |
int w1 = walkt[A];
|
342 |
int w2 = walkt[C];
|
343 |
int e1 = edgest[A];
|
344 |
int e2 = edgest[C];
|
345 |
int w3, w4, e3, e4;
|
346 |
if (trit2[(D+1)%3] == trit[C]) { |
347 |
w3 = walkt2[D]; |
348 |
w4 = walkt2[(D+2)%3]; |
349 |
e3 = edgest2[D]; |
350 |
e4 = edgest2[(D+2)%3]; |
351 |
} |
352 |
else {
|
353 |
w3 = walkt2[(D+2)%3]; |
354 |
w4 = walkt2[D]; |
355 |
e3 = edgest2[(D+2)%3]; |
356 |
e4 = edgest2[D]; |
357 |
} |
358 |
|
359 |
// update Tri array
|
360 |
trit[0] = n1;
|
361 |
trit[1] = n2;
|
362 |
trit[2] = n4;
|
363 |
trit2[0] = n1;
|
364 |
trit2[1] = n4;
|
365 |
trit2[2] = n3;
|
366 |
|
367 |
// update Walk array
|
368 |
walkt[0] = w1;
|
369 |
walkt[1] = w4;
|
370 |
walkt[2] = t2;
|
371 |
walkt2[0] = t;
|
372 |
walkt2[1] = w3;
|
373 |
walkt2[2] = w2;
|
374 |
if (w2 >= 0) { |
375 |
int val = (Walk[w2][0] == t) ? 0 |
376 |
: (Walk[w2][1] == t) ? 1 : 2; |
377 |
Walk[w2][val] = t2; |
378 |
} |
379 |
if (w4 >= 0) { |
380 |
int val = (Walk[w4][0] == t2) ? 0 |
381 |
: (Walk[w4][1] == t2) ? 1 : 2; |
382 |
Walk[w4][val] = t; |
383 |
} |
384 |
|
385 |
// update Edges array
|
386 |
edgest[0] = e1;
|
387 |
edgest[1] = e4;
|
388 |
// Edges[t][2] and Edges[t2][0] stay the same
|
389 |
edgest2[1] = e3;
|
390 |
edgest2[2] = e2;
|
391 |
|
392 |
// update Vertices array
|
393 |
int[] vertn1 = Vertices[n1]; |
394 |
int[] vertn2 = Vertices[n2]; |
395 |
int[] vertn3 = Vertices[n3]; |
396 |
int[] vertn4 = Vertices[n4]; |
397 |
int ln1 = vertn1.length;
|
398 |
int ln2 = vertn2.length;
|
399 |
int ln3 = vertn3.length;
|
400 |
int ln4 = vertn4.length;
|
401 |
int[] tn1 = new int[ln1 + 1]; // Vertices[n1] adds t2 |
402 |
int[] tn2 = new int[ln2 - 1]; // Vertices[n2] loses t2 |
403 |
int[] tn3 = new int[ln3 - 1]; // Vertices[n3] loses t |
404 |
int[] tn4 = new int[ln4 + 1]; // Vertices[n4] adds t |
405 |
System.arraycopy(vertn1, 0, tn1, 0, ln1); |
406 |
tn1[ln1] = t2; |
407 |
int c = 0; |
408 |
for (int i=0; i<ln2; i++) { |
409 |
if (vertn2[i] != t2) tn2[c++] = vertn2[i];
|
410 |
} |
411 |
c = 0;
|
412 |
for (int i=0; i<ln3; i++) { |
413 |
if (vertn3[i] != t) tn3[c++] = vertn3[i];
|
414 |
} |
415 |
System.arraycopy(vertn4, 0, tn4, 0, ln4); |
416 |
tn4[ln4] = t; |
417 |
Vertices[n1] = tn1; |
418 |
Vertices[n2] = tn2; |
419 |
Vertices[n3] = tn3; |
420 |
Vertices[n4] = tn4; |
421 |
} |
422 |
} |
423 |
|
424 |
// the edge has now been checked
|
425 |
edge[curedge] = false;
|
426 |
} |
427 |
} |
428 |
} |
429 |
|
430 |
// if no edges have been flipped this pass, then stop
|
431 |
if (!eflipped) break; |
432 |
} |
433 |
} |
434 |
|
435 |
/** finish_triang calculates a triangulation's helper arrays, Walk and Edges,
|
436 |
if the triangulation algorithm hasn't calculated them already. Any
|
437 |
extension to the Delaunay class should call finish_triang at the end
|
438 |
of its triangulation constructor. */
|
439 |
public void finish_triang(double[][] samples) throws VisADException { |
440 |
int mdim = Tri[0].length - 1; |
441 |
int mdim1 = mdim + 1; |
442 |
int dim = samples.length;
|
443 |
int dim1 = dim+1; |
444 |
int ntris = Tri.length;
|
445 |
int nrs = samples[0].length; |
446 |
for (int i=1; i<dim; i++) { |
447 |
nrs = Math.min(nrs, samples[i].length);
|
448 |
} |
449 |
|
450 |
if (Vertices == null) { |
451 |
// build Vertices component
|
452 |
Vertices = new int[nrs][]; |
453 |
int[] nverts = new int[nrs]; |
454 |
for (int i=0; i<ntris; i++) { |
455 |
for (int j=0; j<mdim1; j++) nverts[Tri[i][j]]++; |
456 |
} |
457 |
for (int i=0; i<nrs; i++) { |
458 |
Vertices[i] = new int[nverts[i]]; |
459 |
nverts[i] = 0;
|
460 |
} |
461 |
for (int i=0; i<ntris; i++) { |
462 |
for (int j=0; j<mdim1; j++) { |
463 |
Vertices[Tri[i][j]][nverts[Tri[i][j]]++] = i; |
464 |
} |
465 |
} |
466 |
} |
467 |
|
468 |
if (Walk == null && mdim <= 3) { |
469 |
// build Walk component
|
470 |
Walk = new int[ntris][mdim1]; |
471 |
for (int i=0; i<ntris; i++) { |
472 |
WalkDim: |
473 |
for (int j=0; j<mdim1; j++) { |
474 |
int v1 = j;
|
475 |
int v2 = (v1+1)%mdim1; |
476 |
Walk[i][j] = -1;
|
477 |
for (int k=0; k<Vertices[Tri[i][v1]].length; k++) { |
478 |
int temp = Vertices[Tri[i][v1]][k];
|
479 |
if (temp != i) {
|
480 |
for (int l=0; l<Vertices[Tri[i][v2]].length; l++) { |
481 |
if (mdim == 2) { |
482 |
if (temp == Vertices[Tri[i][v2]][l]) {
|
483 |
Walk[i][j] = temp; |
484 |
continue WalkDim;
|
485 |
} |
486 |
} |
487 |
else { // mdim == 3 |
488 |
int temp2 = Vertices[Tri[i][v2]][l];
|
489 |
int v3 = (v2+1)%mdim1; |
490 |
if (temp == temp2) {
|
491 |
for (int m=0; m<Vertices[Tri[i][v3]].length; m++) { |
492 |
if (temp == Vertices[Tri[i][v3]][m]) {
|
493 |
Walk[i][j] = temp; |
494 |
continue WalkDim;
|
495 |
} |
496 |
} |
497 |
} |
498 |
} // end if (mdim == 3)
|
499 |
} // end for (int l=0; l<Vertices[Tri[i][v2]].length; l++)
|
500 |
} // end if (temp != i)
|
501 |
} // end for (int k=0; k<Vertices[Tri[i][v1]].length; k++)
|
502 |
} // end for (int j=0; j<mdim1; j++)
|
503 |
} // end for (int i=0; i<Tri.length; i++)
|
504 |
} // end if (Walk == null && mdim <= 3)
|
505 |
|
506 |
if (Edges == null && mdim <= 3) { |
507 |
// build Edges component
|
508 |
|
509 |
// initialize all edges to "not yet found"
|
510 |
int edim = 3*(mdim-1); |
511 |
Edges = new int[ntris][edim]; |
512 |
for (int i=0; i<ntris; i++) { |
513 |
for (int j=0; j<edim; j++) Edges[i][j] = -1; |
514 |
} |
515 |
|
516 |
// calculate global edge values
|
517 |
NumEdges = 0;
|
518 |
if (mdim == 2) { |
519 |
for (int i=0; i<ntris; i++) { |
520 |
for (int j=0; j<3; j++) { |
521 |
if (Edges[i][j] < 0) { |
522 |
// this edge doesn't have a "global edge number" yet
|
523 |
int othtri = Walk[i][j];
|
524 |
if (othtri >= 0) { |
525 |
int cside = -1; |
526 |
for (int k=0; k<3; k++) { |
527 |
if (Walk[othtri][k] == i) cside = k;
|
528 |
} |
529 |
if (cside != -1) { |
530 |
Edges[othtri][cside] = NumEdges; |
531 |
} |
532 |
else {
|
533 |
throw new SetException("Delaunay.finish_triang: " + |
534 |
"error in triangulation!");
|
535 |
} |
536 |
} |
537 |
Edges[i][j] = NumEdges++; |
538 |
} |
539 |
} |
540 |
} |
541 |
} |
542 |
else { // mdim == 3 |
543 |
int[] ptlook1 = {0, 0, 0, 1, 1, 2}; |
544 |
int[] ptlook2 = {1, 2, 3, 2, 3, 3}; |
545 |
for (int i=0; i<ntris; i++) { |
546 |
for (int j=0; j<6; j++) { |
547 |
if (Edges[i][j] < 0) { |
548 |
// this edge doesn't have a "global edge number" yet
|
549 |
|
550 |
// search through the edge's two end points
|
551 |
int endpt1 = Tri[i][ptlook1[j]];
|
552 |
int endpt2 = Tri[i][ptlook2[j]];
|
553 |
|
554 |
// create an intersection of two sets
|
555 |
int[] set = new int[Vertices[endpt1].length]; |
556 |
int setlen = 0; |
557 |
for (int p1=0; p1<Vertices[endpt1].length; p1++) { |
558 |
int temp = Vertices[endpt1][p1];
|
559 |
for (int p2=0; p2<Vertices[endpt2].length; p2++) { |
560 |
if (temp == Vertices[endpt2][p2]) {
|
561 |
set[setlen++] = temp; |
562 |
break;
|
563 |
} |
564 |
} |
565 |
} |
566 |
|
567 |
// assign global edge number to all members of set
|
568 |
for (int kk=0; kk<setlen; kk++) { |
569 |
int k = set[kk];
|
570 |
for (int l=0; l<edim; l++) { |
571 |
if ((Tri[k][ptlook1[l]] == endpt1
|
572 |
&& Tri[k][ptlook2[l]] == endpt2) |
573 |
|| (Tri[k][ptlook1[l]] == endpt2 |
574 |
&& Tri[k][ptlook2[l]] == endpt1)) { |
575 |
Edges[k][l] = NumEdges; |
576 |
} |
577 |
} |
578 |
} |
579 |
Edges[i][j] = NumEdges++; |
580 |
} // end if (Edges[i][j] < 0)
|
581 |
} // end for (int j=0; j<6; j++)
|
582 |
} // end for (int i=0; i<ntris; i++)
|
583 |
} // end if (mdim == 3)
|
584 |
} // end if (Edges == null && mdim <= 3)
|
585 |
} |
586 |
/*
|
587 |
public void finish_triang(double[][] samples) throws VisADException {
|
588 |
int dim = samples.length;
|
589 |
int dim1 = dim+1;
|
590 |
int ntris = Tri.length;
|
591 |
int nrs = samples[0].length;
|
592 |
for (int i=1; i<dim; i++) {
|
593 |
nrs = Math.min(nrs, samples[i].length);
|
594 |
}
|
595 |
|
596 |
if (Vertices == null) {
|
597 |
// build Vertices component
|
598 |
Vertices = new int[nrs][];
|
599 |
int[] nverts = new int[nrs];
|
600 |
for (int i=0; i<ntris; i++) {
|
601 |
for (int j=0; j<dim1; j++) nverts[Tri[i][j]]++;
|
602 |
}
|
603 |
for (int i=0; i<nrs; i++) {
|
604 |
Vertices[i] = new int[nverts[i]];
|
605 |
nverts[i] = 0;
|
606 |
}
|
607 |
for (int i=0; i<ntris; i++) {
|
608 |
for (int j=0; j<dim1; j++) {
|
609 |
Vertices[Tri[i][j]][nverts[Tri[i][j]]++] = i;
|
610 |
}
|
611 |
}
|
612 |
}
|
613 |
|
614 |
if (Walk == null && dim <= 3) {
|
615 |
// build Walk component
|
616 |
Walk = new int[ntris][dim1];
|
617 |
for (int i=0; i<Tri.length; i++) {
|
618 |
WalkDim:
|
619 |
for (int j=0; j<dim1; j++) {
|
620 |
int v1 = j;
|
621 |
int v2 = (v1+1)%dim1;
|
622 |
Walk[i][j] = -1;
|
623 |
for (int k=0; k<Vertices[Tri[i][v1]].length; k++) {
|
624 |
int temp = Vertices[Tri[i][v1]][k];
|
625 |
if (temp != i) {
|
626 |
for (int l=0; l<Vertices[Tri[i][v2]].length; l++) {
|
627 |
if (dim == 2) {
|
628 |
if (temp == Vertices[Tri[i][v2]][l]) {
|
629 |
Walk[i][j] = temp;
|
630 |
continue WalkDim;
|
631 |
}
|
632 |
}
|
633 |
else { // dim == 3
|
634 |
int temp2 = Vertices[Tri[i][v2]][l];
|
635 |
int v3 = (v2+1)%dim1;
|
636 |
if (temp == temp2) {
|
637 |
for (int m=0; m<Vertices[Tri[i][v3]].length; m++) {
|
638 |
if (temp == Vertices[Tri[i][v3]][m]) {
|
639 |
Walk[i][j] = temp;
|
640 |
continue WalkDim;
|
641 |
}
|
642 |
}
|
643 |
}
|
644 |
} // end if (dim == 3)
|
645 |
} // end for (int l=0; l<Vertices[Tri[i][v2]].length; l++)
|
646 |
} // end if (temp != i)
|
647 |
} // end for (int k=0; k<Vertices[Tri[i][v1]].length; k++)
|
648 |
} // end for (int j=0; j<dim1; j++)
|
649 |
} // end for (int i=0; i<Tri.length; i++)
|
650 |
} // end if (Walk == null && dim <= 3)
|
651 |
|
652 |
if (Edges == null && dim <= 3) {
|
653 |
// build Edges component
|
654 |
|
655 |
// initialize all edges to "not yet found"
|
656 |
int edim = 3*(dim-1);
|
657 |
Edges = new int[ntris][edim];
|
658 |
for (int i=0; i<ntris; i++) {
|
659 |
for (int j=0; j<edim; j++) Edges[i][j] = -1;
|
660 |
}
|
661 |
|
662 |
// calculate global edge values
|
663 |
NumEdges = 0;
|
664 |
if (dim == 2) {
|
665 |
for (int i=0; i<ntris; i++) {
|
666 |
for (int j=0; j<3; j++) {
|
667 |
if (Edges[i][j] < 0) {
|
668 |
// this edge doesn't have a "global edge number" yet
|
669 |
int othtri = Walk[i][j];
|
670 |
if (othtri >= 0) {
|
671 |
int cside = -1;
|
672 |
for (int k=0; k<3; k++) {
|
673 |
if (Walk[othtri][k] == i) cside = k;
|
674 |
}
|
675 |
if (cside != -1) {
|
676 |
Edges[othtri][cside] = NumEdges;
|
677 |
}
|
678 |
else {
|
679 |
throw new SetException("Delaunay.finish_triang: " +
|
680 |
"error in triangulation!");
|
681 |
}
|
682 |
}
|
683 |
Edges[i][j] = NumEdges++;
|
684 |
}
|
685 |
}
|
686 |
}
|
687 |
}
|
688 |
else { // dim == 3
|
689 |
int[] ptlook1 = {0, 0, 0, 1, 1, 2};
|
690 |
int[] ptlook2 = {1, 2, 3, 2, 3, 3};
|
691 |
for (int i=0; i<ntris; i++) {
|
692 |
for (int j=0; j<6; j++) {
|
693 |
if (Edges[i][j] < 0) {
|
694 |
// this edge doesn't have a "global edge number" yet
|
695 |
|
696 |
// search through the edge's two end points
|
697 |
int endpt1 = Tri[i][ptlook1[j]];
|
698 |
int endpt2 = Tri[i][ptlook2[j]];
|
699 |
|
700 |
// create an intersection of two sets
|
701 |
int[] set = new int[Vertices[endpt1].length];
|
702 |
int setlen = 0;
|
703 |
for (int p1=0; p1<Vertices[endpt1].length; p1++) {
|
704 |
int temp = Vertices[endpt1][p1];
|
705 |
for (int p2=0; p2<Vertices[endpt2].length; p2++) {
|
706 |
if (temp == Vertices[endpt2][p2]) {
|
707 |
set[setlen++] = temp;
|
708 |
break;
|
709 |
}
|
710 |
}
|
711 |
}
|
712 |
|
713 |
// assign global edge number to all members of set
|
714 |
for (int kk=0; kk<setlen; kk++) {
|
715 |
int k = set[kk];
|
716 |
for (int l=0; l<edim; l++) {
|
717 |
if ((Tri[k][ptlook1[l]] == endpt1
|
718 |
&& Tri[k][ptlook2[l]] == endpt2)
|
719 |
|| (Tri[k][ptlook1[l]] == endpt2
|
720 |
&& Tri[k][ptlook2[l]] == endpt1)) {
|
721 |
Edges[k][l] = NumEdges;
|
722 |
}
|
723 |
}
|
724 |
}
|
725 |
Edges[i][j] = NumEdges++;
|
726 |
} // end if (Edges[i][j] < 0)
|
727 |
} // end for (int j=0; j<6; j++)
|
728 |
} // end for (int i=0; i<ntris; i++)
|
729 |
} // end if (dim == 3)
|
730 |
} // end if (Edges == null && dim <= 3)
|
731 |
}
|
732 |
*/
|
733 |
|
734 |
public String toString() { |
735 |
return sampleString(null); |
736 |
} |
737 |
|
738 |
public String sampleString(double[][] samples) { |
739 |
StringBuffer s = new StringBuffer(""); |
740 |
if (samples != null) { |
741 |
s.append("\nsamples " + samples[0].length + "\n"); |
742 |
for (int i=0; i<samples[0].length; i++) { |
743 |
s.append(" " + i + " -> " + samples[0][i] + " " + |
744 |
samples[1][i] + "\n"); // + " " + samples[2][i] + "\n"); |
745 |
} |
746 |
s.append("\n");
|
747 |
} |
748 |
|
749 |
s.append("\nTri (triangles -> vertices) " + Tri.length + "\n"); |
750 |
for (int i=0; i<Tri.length; i++) { |
751 |
s.append(" " + i + " -> "); |
752 |
for (int j=0; j<Tri[i].length; j++) { |
753 |
s.append(" " + Tri[i][j]);
|
754 |
} |
755 |
s.append("\n");
|
756 |
} |
757 |
|
758 |
s.append("\nVertices (vertices -> triangles) " + Vertices.length + "\n"); |
759 |
for (int i=0; i<Vertices.length; i++) { |
760 |
s.append(" " + i + " -> "); |
761 |
for (int j=0; j<Vertices[i].length; j++) { |
762 |
s.append(" " + Vertices[i][j]);
|
763 |
} |
764 |
s.append("\n");
|
765 |
} |
766 |
|
767 |
s.append("\nWalk (triangles -> triangles) " + Walk.length + "\n"); |
768 |
for (int i=0; i<Walk.length; i++) { |
769 |
s.append(" " + i + " -> "); |
770 |
for (int j=0; j<Walk[i].length; j++) { |
771 |
s.append(" " + Walk[i][j]);
|
772 |
} |
773 |
s.append("\n");
|
774 |
} |
775 |
|
776 |
s.append("\nEdges (triangles -> global edges) " + Edges.length + "\n"); |
777 |
for (int i=0; i<Edges.length; i++) { |
778 |
s.append(" " + i + " -> "); |
779 |
for (int j=0; j<Edges[i].length; j++) { |
780 |
s.append(" " + Edges[i][j]);
|
781 |
} |
782 |
s.append("\n");
|
783 |
} |
784 |
return s.toString();
|
785 |
} |
786 |
|
787 |
} |
788 |
|