Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / topology / triangulation / DelaunayTriangulation.java @ 10627

History | View | Annotate | Download (6.76 KB)

1
/*
2
 * Copyright (c) 2005 by L. Paul Chew.
3
 * 
4
 * Permission is hereby granted, without written agreement and without
5
 * license or royalty fees, to use, copy, modify, and distribute this
6
 * software and its documentation for any purpose, subject to the following 
7
 * conditions:
8
 *
9
 * The above copyright notice and this permission notice shall be included 
10
 * in all copies or substantial portions of the Software.
11
 * 
12
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
13
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
14
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
15
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
16
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
17
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
18
 * DEALINGS IN THE SOFTWARE.
19
 */
20
package com.iver.cit.gvsig.topology.triangulation;
21

    
22
import java.awt.geom.Point2D;
23
import java.util.HashSet;
24
import java.util.Iterator;
25
import java.util.LinkedList;
26
import java.util.Set;
27

    
28
import com.vividsolutions.jts.geom.Coordinate;
29

    
30
/**
31
 * A 2D Delaunay Triangulation (DT) with incremental site insertion.
32
 * This is not the fastest way to build a DT, but it's a reasonable way
33
 * to build the DT incrementally and it makes a nice interactive display.
34
 * There are several O(n log n) methods, but they require that either (1) 
35
 * the sites are all known initially or (2) the sites are inserted in random
36
 * order.
37
 * 
38
 * @author Paul Chew
39
 * 
40
 * Created July 2005.  Derived from an earlier, messier version.
41
 */
42
public class DelaunayTriangulation extends Triangulation {
43
    
44
    private Simplex mostRecent = null;       // Most recently inserted triangle
45
    public boolean debug = false;            // Used for debugging
46
    private static double initialSize = Double.MAX_VALUE / 2.0;
47
//    private static Simplex initialTriangle = new Simplex(new Pnt[] {new Pnt(-10,10), new Pnt(10,10), new Pnt(0,-10)});
48
    private static Simplex initialTriangle = new Simplex(new Pnt[] {
49
            new Pnt(-initialSize, initialSize),
50
            new Pnt( initialSize, initialSize),
51
            new Pnt(           0,  -initialSize)});
52
    
53
    
54
    
55
    /**
56
     * Constructor.
57
     * All sites must fall within the initial triangle.
58
     * @param triangle the initial triangle
59
     */
60
    public DelaunayTriangulation (Simplex triangle) {
61
        super(triangle);
62
        mostRecent = triangle;
63
    }
64

    
65
    public DelaunayTriangulation()
66
    {
67
            super(initialTriangle);
68
            mostRecent = initialTriangle;
69
    }
70

    
71
    /**
72
     * Locate the triangle with point (a Pnt) inside (or on) it.
73
     * @param point the Pnt to locate
74
     * @return triangle (Simplex<Pnt>) that holds the point; null if no such triangle
75
     */
76
    public Simplex locate (Pnt point) {
77
        Simplex triangle = mostRecent;
78
        if (!this.contains(triangle)) triangle = null;
79
        
80
        // Try a directed walk (this works fine in 2D, but can fail in 3D)
81
        Set visited = new HashSet();
82
        while (triangle != null) {
83
            if (visited.contains(triangle)) { // This should never happen
84
                System.out.println("Warning: Caught in a locate loop");
85
                break;
86
            }
87
            visited.add(triangle);
88
            // Corner opposite point
89
            Pnt corner = point.isOutside((Pnt[]) triangle.toArray(new Pnt[0]));
90
            if (corner == null) return triangle;
91
            triangle = this.neighborOpposite(corner, triangle);
92
        }
93
        // No luck; try brute force
94
        System.out.println("Warning: Checking all triangles for " + point);
95
        for (Iterator it = this.iterator(); it.hasNext();) {
96
            Simplex tri = (Simplex) it.next();
97
            if (point.isOutside((Pnt[])tri.toArray(new Pnt[0])) == null) return tri;
98
        }
99
        // No such triangle
100
        System.out.println("Warning: No triangle holds " + point);
101
        return null;
102
    }
103
    
104
    /**
105
     * Place a new point site into the DT.
106
     * @param site the new Pnt
107
     * @return set of all new triangles created
108
     */
109
    public Set delaunayPlace (Pnt site) {
110
        Set newTriangles = new HashSet();
111
        Set oldTriangles = new HashSet();
112
        Set doneSet = new HashSet();
113
        LinkedList waitingQ = new LinkedList();
114
        
115
        // Locate containing triangle
116
        if (debug) System.out.println("Locate");
117
        Simplex triangle = locate(site);
118
        
119
        // Give up if no containing triangle or if site is already in DT
120
        if (triangle == null || triangle.contains(site)) return newTriangles;
121
        
122
        // Find Delaunay cavity (those triangles with site in their circumcircles)
123
        if (debug) System.out.println("Cavity");
124
        waitingQ.add(triangle);
125
        while (!waitingQ.isEmpty()) {
126
            triangle = (Simplex) waitingQ.removeFirst();      
127
            if (site.vsCircumcircle((Pnt[]) triangle.toArray(new Pnt[0])) == 1) continue;
128
            oldTriangles.add(triangle);
129
            Iterator it = this.neighbors(triangle).iterator();
130
            for (; it.hasNext();) {
131
                Simplex tri = (Simplex) it.next();
132
                if (doneSet.contains(tri)) continue;
133
                doneSet.add(tri);
134
                waitingQ.add(tri);
135
            }
136
        }
137
        // Create the new triangles
138
        if (debug) System.out.println("Create");
139
        for (Iterator it = Simplex.boundary(oldTriangles).iterator(); it.hasNext();) {
140
            Set facet = (Set) it.next();
141
            facet.add(site);
142
            newTriangles.add(new Simplex(facet));
143
        }
144
        // Replace old triangles with new triangles
145
        if (debug) System.out.println("Update");
146
        this.update(oldTriangles, newTriangles);
147
        
148
        // Update mostRecent triangle
149
        if (!newTriangles.isEmpty()) mostRecent = (Simplex) newTriangles.iterator().next();
150
        return newTriangles;
151
    }
152
    
153
    /**
154
     * Main program; used for testing.
155
     */
156
    public static void main (String[] args) {
157
//        Simplex tri = new Simplex(new Pnt[] {new Pnt(-10,10), new Pnt(10,10), new Pnt(0,-10)});
158
//        System.out.println("Triangle created: " + tri);
159
//        DelaunayTriangulation dt = new DelaunayTriangulation(tri);
160
            DelaunayTriangulation dt = new DelaunayTriangulation();
161
        System.out.println("DelaunayTriangulation created: " + dt);
162
        dt.delaunayPlace(new Pnt(0,0));
163
        dt.delaunayPlace(new Pnt(1,0));
164
        dt.delaunayPlace(new Pnt(0,1));
165
        System.out.println("After adding 3 points, the DelaunayTriangulation is a " + dt);
166
        dt.printStuff();
167
    }
168
    
169
    public void delaunayPlace(Point2D p)
170
    {
171
            Pnt aux = new Pnt(p.getX(), p.getY());
172
            delaunayPlace(aux);
173
    }
174

    
175
        public void delaunayPlace(Coordinate c) {
176
            Pnt aux = new Pnt(c.x, c.y);
177
            delaunayPlace(aux);                
178
        }
179
}
180

    
181