Statistics
| Revision:

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