Statistics
| Revision:

root / trunk / libraries / libTopology / src / org / gvsig / jts / voronoi / chew / DTriangulationForJTS.java @ 21246

History | View | Annotate | Download (15.1 KB)

1
/***********************************************
2
 * created on                 12.06.2006
3
 * last modified:         
4
 * 
5
 * author:                        sstein
6
 * 
7
 * description:
8
 * 
9
 * 
10
 ***********************************************/
11
package org.gvsig.jts.voronoi.chew;
12

    
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.Iterator;
16
import java.util.List;
17
import java.util.Set;
18

    
19
import org.gvsig.jts.JtsUtil;
20
import org.gvsig.topology.Messages;
21

    
22
import com.iver.utiles.swing.threads.CancellableProgressTask;
23
import com.vividsolutions.jts.geom.Coordinate;
24
import com.vividsolutions.jts.geom.Envelope;
25
import com.vividsolutions.jts.geom.Geometry;
26
import com.vividsolutions.jts.geom.GeometryFactory;
27
import com.vividsolutions.jts.geom.LineString;
28
import com.vividsolutions.jts.geom.LinearRing;
29
import com.vividsolutions.jts.geom.Point;
30
import com.vividsolutions.jts.geom.Polygon;
31
import com.vividsolutions.jts.operation.polygonize.Polygonizer;
32

    
33
/**
34
 * OpenJUMP's modified version.
35
 * 
36
 * We have added generics to the input point's list, and passed
37
 * CancellableProgressTask as parameter of those methods we want to monitor its
38
 * progress.
39
 * 
40
 * 
41
 * 
42
 * @author sstein
43
 * @author azabala
44
 * 
45
 * Use the class to access the delauney trinagulation by L. Paul Chew Methods of
46
 * the class are modified versions from DelaunayPanel.java in DelaunayAp.java.
47
 */
48
public class DTriangulationForJTS {
49
        private DelaunayTriangulation dt; // The Delaunay triangulation
50
        private Simplex initialTriangle; // The large initial triangle
51
        private int initialSize = 10000; // Controls size of initial triangle
52
        private boolean isVoronoi; // True iff VoD instead of DT
53
        private double dx = 0;
54
        private double dy = 0;
55
        private Pnt lowerLeftPnt = null;
56
        public boolean debug = false; // True iff printing info for debugging
57

    
58
        public DTriangulationForJTS(List<Point> pointList) {
59
                double argmaxx = 0;
60
                double argmaxy = 0;
61
                double argminx = 0;
62
                double argminy = 0;
63
                int count = 0;
64
                // -- calc coordinates of initial symplex
65
                for (Iterator iter = pointList.iterator(); iter.hasNext();) {
66
                        Point pt = (Point) iter.next();
67
                        if (count == 0) {
68
                                argmaxx = pt.getX();
69
                                argminx = pt.getX();
70
                                argmaxy = pt.getY();
71
                                argminy = pt.getY();
72
                        } else {
73
                                if (pt.getX() < argminx) {
74
                                        argminx = pt.getX();
75
                                }
76
                                if (pt.getX() > argmaxx) {
77
                                        argmaxx = pt.getX();
78
                                }
79
                                if (pt.getY() < argminy) {
80
                                        argminy = pt.getY();
81
                                }
82
                                if (pt.getY() > argmaxy) {
83
                                        argmaxy = pt.getY();
84
                                }
85
                        }
86
                        count++;
87
                }
88
                this.dx = argmaxx - argminx;
89
                this.dy = argmaxy - argminy;
90
                // -- the initial simplex must contain all points
91
                // -- take the bounding box, move the diagonals (sidewards)
92
                // the meeting point will be the mirrored bbox-center on the top edge
93
                this.initialTriangle = new Simplex(new Pnt[] {
94
                                new Pnt(argminx - (1.5 * dx), argminy - dy), // lower left
95
                                new Pnt(argmaxx + (1.5 * dx), argminy - dy), // lower right
96
                                // new Pnt(argminx+(dx/2.0), argmaxy+(dy/2.0))}); //center, top
97
                                new Pnt(argminx + (dx / 2.0), argmaxy + 1.5 * dy) }); // center,
98
                                                                                                                                                // top
99

    
100
                this.lowerLeftPnt = new Pnt(argminx - (1.5 * dx), argminy - dy);
101
                this.dt = new DelaunayTriangulation(initialTriangle);
102
                this.addPoints(pointList);
103
        }
104

    
105
        /**
106
         * 
107
         * @param pointList
108
         * @param envelope
109
         *            the envelope my extend the initial point cloud and result in a
110
         *            larger initial simplex
111
         */
112
        public DTriangulationForJTS(List<Point> pointList, Envelope envelope) {
113
                double argmaxx = 0;
114
                double argmaxy = 0;
115
                double argminx = 0;
116
                double argminy = 0;
117
                int count = 0;
118
                // -- calc coordinates of initial symplex
119
                for (Iterator iter = pointList.iterator(); iter.hasNext();) {
120
                        Point pt = (Point) iter.next();
121
                        if (count == 0) {
122
                                argmaxx = pt.getX();
123
                                argminx = pt.getX();
124
                                argmaxy = pt.getY();
125
                                argminy = pt.getY();
126
                        } else {
127
                                if (pt.getX() < argminx) {
128
                                        argminx = pt.getX();
129
                                }
130
                                if (pt.getX() > argmaxx) {
131
                                        argmaxx = pt.getX();
132
                                }
133
                                if (pt.getY() < argminy) {
134
                                        argminy = pt.getY();
135
                                }
136
                                if (pt.getY() > argmaxy) {
137
                                        argmaxy = pt.getY();
138
                                }
139
                        }
140
                        count++;
141
                }
142
                // -- do check also for the delivered envelope
143
                if (envelope.getMinX() < argminx) {
144
                        argminx = envelope.getMinX();
145
                }
146
                if (envelope.getMaxX() > argmaxx) {
147
                        argmaxx = envelope.getMaxX();
148
                }
149
                if (envelope.getMinY() < argminy) {
150
                        argminy = envelope.getMinY();
151
                }
152
                if (envelope.getMaxY() > argmaxy) {
153
                        argmaxy = envelope.getMaxY();
154
                }
155
                // --
156
                this.dx = argmaxx - argminx;
157
                this.dy = argmaxy - argminy;
158
                // -- the initial simplex must contain all points
159
                // -- take the bounding box, move the diagonals (sidewards)
160
                // the meeting point will be the mirrored bbox-center on the top edge
161
                this.initialTriangle = new Simplex(new Pnt[] {
162
                                new Pnt(argminx - (1.5 * dx), argminy - dy), // lower left
163
                                new Pnt(argmaxx + (1.5 * dx), argminy - dy), // lower right
164
                                // new Pnt(argminx+(dx/2.0), argmaxy+(dy/2.0))}); //center, top
165
                                new Pnt(argminx + (dx / 2.0), argmaxy + 1.5 * dy) }); // center,
166
                                                                                                                                                // top
167

    
168
                this.lowerLeftPnt = new Pnt(argminx - (1.5 * dx), argminy - dy);
169
                this.dt = new DelaunayTriangulation(initialTriangle);
170
                this.addPoints(pointList);
171
        }
172

    
173
        public void addPoints(List<Point> pointList) {
174
                for (Iterator iter = pointList.iterator(); iter.hasNext();) {
175
                        try {
176
                                Geometry element = (Geometry) iter.next();
177
                                if (element instanceof Point) {
178
                                        Point jtsPt = (Point) element;
179
                                        Pnt point = new Pnt(jtsPt.getX(), jtsPt.getY());
180
                                        dt.delaunayPlace(point);
181
                                } else {
182
                                        if (debug)
183
                                                System.out.println("no point geometry");
184
                                }
185
                        } catch (Exception e) {
186
                                if (debug)
187
                                        System.out.println("no geometry");
188
                        }
189
                }
190
        }
191

    
192
        public void addPoint(double x, double y) {
193
                Pnt point = new Pnt(x, y);
194
                if (debug)
195
                        System.out.println("Click " + point);
196
                dt.delaunayPlace(point);
197
        }
198

    
199
        /**
200
         * Draw all the Delaunay edges.
201
         * 
202
         * @return Arraylist with LineString geometries.
203
         */
204
        public List<Geometry> drawAllDelaunay() {
205
                // Loop through all the edges of the DT (each is done twice)
206
                GeometryFactory gf = new GeometryFactory();
207
                ArrayList<Geometry> lines = new ArrayList<Geometry>();
208
                for (Iterator it = dt.iterator(); it.hasNext();) {
209
                        Simplex triangle = (Simplex) it.next();
210
                        for (Iterator otherIt = triangle.facets().iterator(); otherIt
211
                                        .hasNext();) {
212
                                Set facet = (Set) otherIt.next();
213
                                Pnt[] endpoint = (Pnt[]) facet.toArray(new Pnt[2]);
214
                                Coordinate[] coords = new Coordinate[2];
215
                                coords[0] = new Coordinate(endpoint[0].coord(0), endpoint[0]
216
                                                .coord(1));
217
                                coords[1] = new Coordinate(endpoint[1].coord(0), endpoint[1]
218
                                                .coord(1));
219
                                LineString ls = gf.createLineString(coords);
220
                                lines.add(ls);
221
                        }
222
                }
223
                return lines;
224
        }
225

    
226
        public List<Geometry> getTinTriangles(
227
                        CancellableProgressTask progressMonitor) {
228
                ArrayList<Geometry> triangles = new ArrayList<Geometry>();
229

    
230
                if (progressMonitor != null) {
231
                        progressMonitor.setInitialStep(0);
232
                        int numOfSteps = dt.size();
233
                        progressMonitor.setFinalStep(numOfSteps);
234
                        progressMonitor.setDeterminatedProcess(true);
235
                        progressMonitor
236
                                        .setNote(Messages.getText("computing_tin_triangles"));
237
                        progressMonitor.setStatusMessage(Messages
238
                                        .getText("voronoi_diagram_layer_message"));
239
                }
240

    
241
                for (Iterator it = dt.iterator(); it.hasNext();) {
242
                        Simplex triangle = (Simplex) it.next();
243

    
244
                        if (triangle.size() == 3) {
245
                                List<Coordinate> coords = new ArrayList<Coordinate>();
246
                                Iterator itPt = triangle.iterator();
247
                                while (itPt.hasNext()) {
248
                                        Pnt p = (Pnt) itPt.next();
249
                                        coords.add(new Coordinate(p.coord(0), p.coord(1)));
250
                                }
251
                                coords.add(coords.get(0));
252
                                Coordinate[] coordsArray = new Coordinate[coords.size()];
253
                                coords.toArray(coordsArray);
254
                                Polygon polygon = JtsUtil.createPolygon(coordsArray,
255
                                                new int[] { 0 });
256
                                triangles.add(polygon);
257

    
258
                                if (progressMonitor != null)
259
                                        progressMonitor.reportStep();
260
                        }
261
                }
262
                return triangles;
263
        }
264

    
265
        /**
266
         * Draw all the Voronoi edges.
267
         * 
268
         * @return Arraylist with LineString geometries.
269
         */
270
        public List<LineString> drawAllVoronoi() {
271
                GeometryFactory gf = new GeometryFactory();
272
                ArrayList<LineString> lines = new ArrayList<LineString>();
273
                // Loop through all the edges of the DT (each is done twice)
274
                for (Iterator it = dt.iterator(); it.hasNext();) {
275
                        Simplex triangle = (Simplex) it.next();
276
                        for (Iterator otherIt = dt.neighbors(triangle).iterator(); otherIt
277
                                        .hasNext();) {
278
                                Simplex other = (Simplex) otherIt.next();
279
                                Pnt p = Pnt.circumcenter((Pnt[]) triangle.toArray(new Pnt[0]));
280
                                Pnt q = Pnt.circumcenter((Pnt[]) other.toArray(new Pnt[0]));
281
                                Coordinate[] coords = new Coordinate[2];
282
                                coords[0] = new Coordinate(p.coord(0), p.coord(1));
283
                                coords[1] = new Coordinate(q.coord(0), q.coord(1));
284
                                LineString ls = gf.createLineString(coords);
285
                                lines.add(ls);
286
                        }
287
                }
288
                return lines;
289
        }
290

    
291
        /**
292
         * Draw all the sites (i.e., the input points) of the DT.
293
         * 
294
         * @return Arraylist with point geometries.
295
         */
296
        public ArrayList drawAllSites() {
297
                // Loop through all sites of the DT
298
                // Each is done several times, about 6 times each on average; this
299
                // can be proved via Euler's formula.
300
                GeometryFactory gf = new GeometryFactory();
301
                ArrayList points = new ArrayList();
302
                for (Iterator it = dt.iterator(); it.hasNext();) {
303
                        for (Iterator otherIt = ((Simplex) it.next()).iterator(); otherIt
304
                                        .hasNext();) {
305
                                Pnt pt = (Pnt) otherIt.next();
306
                                Coordinate coord = new Coordinate(pt.coord(0), pt.coord(1));
307
                                Point jtsPt = gf.createPoint(coord);
308
                                points.add(jtsPt);
309
                        }
310
                }
311
                return points;
312
        }
313

    
314
        /**
315
         * Draw all the empty circles (one for each triangle) of the DT.
316
         * 
317
         * @return Arraylist with polygon geometries.
318
         */
319
        public ArrayList drawAllCircles() {
320
                // Loop through all triangles of the DT
321
                GeometryFactory gf = new GeometryFactory();
322
                ArrayList circles = new ArrayList();
323
                loop: for (Iterator it = dt.iterator(); it.hasNext();) {
324
                        Simplex triangle = (Simplex) it.next();
325
                        for (Iterator otherIt = initialTriangle.iterator(); otherIt
326
                                        .hasNext();) {
327
                                Pnt p = (Pnt) otherIt.next();
328
                                if (triangle.contains(p))
329
                                        continue loop;
330
                        }
331
                        Pnt c = Pnt.circumcenter((Pnt[]) triangle.toArray(new Pnt[0]));
332
                        double radius = c.subtract((Pnt) triangle.iterator().next())
333
                                        .magnitude();
334
                        Coordinate coord = new Coordinate(c.coord(0), c.coord(1));
335
                        Point jtsPt = gf.createPoint(coord);
336
                        circles.add(jtsPt.buffer(radius));
337
                }
338
                return circles;
339
        }
340

    
341
        public DelaunayTriangulation getDelaunayTriangulation() {
342
                return dt;
343
        }
344

    
345
        /**
346
         * 
347
         * @return the corner points of the initial simplex which is divided into
348
         *         smaller simplexes by the iterative insertion of the point dataset
349
         */
350
        public ArrayList getInitialSimmplexAsJTSPoints() {
351
                GeometryFactory gf = new GeometryFactory();
352
                ArrayList points = new ArrayList();
353

    
354
                for (Iterator otherIt = this.initialTriangle.iterator(); otherIt
355
                                .hasNext();) {
356
                        Pnt pt = (Pnt) otherIt.next();
357
                        Coordinate coord = new Coordinate(pt.coord(0), pt.coord(1));
358
                        Point jtsPt = gf.createPoint(coord);
359
                        points.add(jtsPt);
360
                }
361
                return points;
362
        }
363

    
364
        /**
365
         * the size of the box has been empirically defined to get "undistorted"
366
         * outer thiessen polygons
367
         * 
368
         * @return a bounding box necesseray to create the final thiessenpolygons
369
         */
370
        public Geometry getThiessenBoundingBox() {
371
                GeometryFactory gf = new GeometryFactory();
372
                Coordinate[] coords = new Coordinate[5];
373
                coords[0] = new Coordinate(this.lowerLeftPnt.coord(0) + 1 * this.dx,
374
                                this.lowerLeftPnt.coord(1) + 0.5 * this.dy); // lowerleft
375
                coords[1] = new Coordinate(this.lowerLeftPnt.coord(0) + 3 * this.dx,
376
                                this.lowerLeftPnt.coord(1) + 0.5 * this.dy); // lowerright
377
                coords[2] = new Coordinate(this.lowerLeftPnt.coord(0) + 3 * this.dx,
378
                                this.lowerLeftPnt.coord(1) + 2.5 * this.dy); // topright
379
                coords[3] = new Coordinate(this.lowerLeftPnt.coord(0) + 1 * this.dx,
380
                                this.lowerLeftPnt.coord(1) + 2.5 * this.dy); // topleft
381
                // -- to close linestring
382
                coords[4] = new Coordinate(this.lowerLeftPnt.coord(0) + 1 * this.dx,
383
                                this.lowerLeftPnt.coord(1) + 0.5 * dy); // lowerleft
384
                LinearRing lr = gf.createLinearRing(coords);
385
                Geometry bbox = gf.createPolygon(lr, null);
386
                return bbox;
387
        }
388

    
389
        public List<Geometry> getThiessenPolys() {
390
                return getThiessenPolys(null);
391
        }
392

    
393
        /**
394
         * Method returns thiessen polygons within a empirically enlarged bounding
395
         * box around the point set. Therefore the voronoi edges are polygonized and
396
         * the intersecting voronoi polygons with the bounding box are calculated.
397
         * These intersecting thiessen polygons (in the bounding box) are returned.
398
         * <p>
399
         * Note: "thiesen" and "voronoi" is exchangeable.
400
         * 
401
         * @return
402
         */
403
        public List<Geometry> getThiessenPolys(
404
                        CancellableProgressTask progressMonitor) {
405
                // -- do union of all edges and use the polygonizer to create polygons
406
                // from it
407
                if (debug)
408
                        System.out.println("get voronoi egdes");
409
                List<LineString> edges = this.drawAllVoronoi();
410

    
411
                if (debug)
412
                        System.out.println("merge voronoi egdes to multiLineString");
413

    
414
                Geometry lines = null;
415

    
416
                Geometry mls = (Geometry) edges.get(0);
417

    
418
                if (progressMonitor != null) {
419
                        progressMonitor.setInitialStep(0);
420
                        int numOfSteps = edges.size();
421
                        progressMonitor.setFinalStep(numOfSteps);
422
                        progressMonitor.setDeterminatedProcess(true);
423
                        progressMonitor.setNote(Messages
424
                                        .getText("topology_clean_of_thiessen_edges"));
425
                        progressMonitor.setStatusMessage(Messages
426
                                        .getText("voronoi_diagram_layer_message"));
427
                        progressMonitor.reportStep();
428
                }
429

    
430
                for (int i = 1; i < edges.size(); i++) {
431
                        Geometry line = (Geometry) edges.get(i);
432
                        mls = mls.union(line);
433
                        if (progressMonitor != null)
434
                                progressMonitor.reportStep();
435
                }
436

    
437
                lines = mls;
438

    
439
                // Geometry[] geometries = new Geometry[edges.size()];
440
                // edges.toArray(geometries);
441
                // lines =
442
                // JtsUtil.GEOMETRY_FACTORY.createGeometryCollection(geometries);
443
                // if(lines.getClass().equals(GeometryCollection.class)){
444
                // GeometryCollection gc = (GeometryCollection) lines;
445
                // lines = JtsUtil.convertToMultiLineString(gc);
446
                // }
447

    
448
                if (debug)
449
                        System.out.println("polygonize");
450
                Polygonizer poly = new Polygonizer();
451
                poly.add(lines);
452
                Collection polys = poly.getPolygons();
453
                // -- get final polygons in bounding box (=intersection polygons with
454
                // the bbox)
455
                Geometry bbox = this.getThiessenBoundingBox();
456
                if (debug)
457
                        System.out.println("get intersections and final polys..");
458

    
459
                if (progressMonitor != null) {
460
                        progressMonitor.setInitialStep(0);
461
                        int numOfSteps = polys.size();
462
                        progressMonitor.setFinalStep(numOfSteps);
463
                        progressMonitor.setDeterminatedProcess(true);
464
                        progressMonitor.setNote(Messages
465
                                        .getText("computing_thiessen_polygons"));
466
                        progressMonitor.setStatusMessage(Messages
467
                                        .getText("voronoi_diagram_layer_message"));
468
                }
469

    
470
                ArrayList<Geometry> finalPolys = new ArrayList<Geometry>();
471
                for (Iterator iter = polys.iterator(); iter.hasNext();) {
472
                        Geometry candPoly = (Geometry) iter.next();
473
                        Geometry intersection = bbox.intersection(candPoly);
474
                        if (progressMonitor != null)
475
                                progressMonitor.reportStep();
476
                        if (intersection != null) {
477
                                if (intersection.getArea() > 0) {
478
                                        finalPolys.add(intersection);
479
                                }
480
                        }
481
                }
482
                if (progressMonitor != null)
483
                        progressMonitor.reportStep();
484
                return finalPolys;
485
        }
486

    
487
}