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 |
|