Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libTopology / src / org / gvsig / jts / JtsUtil.java @ 19995

History | View | Annotate | Download (15.5 KB)

1
/*
2
 * Created on 18-sep-2007
3
 *
4
 * gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
5
 *
6
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License
10
 * as published by the Free Software Foundation; either version 2
11
 * of the License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
21
 *
22
 * For more information, contact:
23
 *
24
 *  Generalitat Valenciana
25
 *   Conselleria d'Infraestructures i Transport
26
 *   Av. Blasco Ib??ez, 50
27
 *   46010 VALENCIA
28
 *   SPAIN
29
 *
30
 *      +34 963862235
31
 *   gvsig@gva.es
32
 *      www.gvsig.gva.es
33
 *
34
 *    or
35
 *
36
 *   IVER T.I. S.A
37
 *   Salamanca 50
38
 *   46005 Valencia
39
 *   Spain
40
 *
41
 *   +34 963163400
42
 *   dac@iver.es
43
 */
44
/* CVS MESSAGES:
45
 *
46
 * $Id: JtsUtil.java 19995 2008-04-05 10:28:42Z azabala $
47
 * $Log: JtsUtil.java,v $
48
 * Revision 1.1  2007/09/19 09:01:20  azabala
49
 * first version in cvs
50
 *
51
 *
52
 */
53
package org.gvsig.jts;
54

    
55
import java.awt.geom.Point2D;
56
import java.lang.reflect.Array;
57
import java.util.ArrayList;
58
import java.util.Iterator;
59
import java.util.List;
60

    
61
import org.gvsig.fmap.core.NewFConverter;
62

    
63
import com.iver.cit.gvsig.fmap.core.FGeometry;
64
import com.iver.cit.gvsig.fmap.core.FGeometryCollection;
65
import com.iver.cit.gvsig.fmap.core.FMultiPoint2D;
66
import com.iver.cit.gvsig.fmap.core.FShape;
67
import com.iver.cit.gvsig.fmap.core.IGeometry;
68
import com.vividsolutions.jts.algorithms.SnapCGAlgorithms;
69
import com.vividsolutions.jts.geom.Coordinate;
70
import com.vividsolutions.jts.geom.CoordinateSequence;
71
import com.vividsolutions.jts.geom.CoordinateSequences;
72
import com.vividsolutions.jts.geom.Envelope;
73
import com.vividsolutions.jts.geom.Geometry;
74
import com.vividsolutions.jts.geom.GeometryCollection;
75
import com.vividsolutions.jts.geom.GeometryFactory;
76
import com.vividsolutions.jts.geom.LineSegment;
77
import com.vividsolutions.jts.geom.LineString;
78
import com.vividsolutions.jts.geom.LinearRing;
79
import com.vividsolutions.jts.geom.MultiLineString;
80
import com.vividsolutions.jts.geom.MultiPoint;
81
import com.vividsolutions.jts.geom.MultiPolygon;
82
import com.vividsolutions.jts.geom.Point;
83
import com.vividsolutions.jts.geom.Polygon;
84
import com.vividsolutions.jts.geom.PrecisionModel;
85
import com.vividsolutions.jts.geomgraph.Edge;
86
import com.vividsolutions.jts.geomgraph.EdgeIntersectionList;
87
import com.vividsolutions.jts.geomgraph.GeometryGraph;
88
import com.vividsolutions.jump.util2.CoordinateArrays;
89

    
90
/**
91
 * Utility methods for JTS library use.
92
 * 
93
 * @author azabala
94
 * 
95
 */
96
public class JtsUtil {
97
        //FIXME PrecionModel's scale should be configurable by a JTS preferences
98
        //dialog
99
        public static final PrecisionModel GVSIG_PRECISION_MODEL = 
100
                new PrecisionModel(10000);
101
        
102
        public static final GeometryFactory GEOMETRY_FACTORY = 
103
                new GeometryFactory(GVSIG_PRECISION_MODEL);
104

    
105
        public static Geometry createGeometry(Coordinate[] coords,
106
                        String geometryType) {
107
                if (geometryType.equalsIgnoreCase("POINT")) {
108
                        return GEOMETRY_FACTORY.createPoint(coords[0]);
109
                } else if (geometryType.equalsIgnoreCase("LINESTRING")) {
110
                        return GEOMETRY_FACTORY.createLineString(coords);
111
                } else if (geometryType.equalsIgnoreCase("LINEARRING")) {
112
                        return GEOMETRY_FACTORY.createLinearRing(coords);
113
                }
114
                // else if (geometryType.equalsIgnoreCase("POLYGON")) {
115
                // // LinearRing exterior = geomFactory.createLinearRing(coords);
116
                // // return geomFactory.createPolygon(exterior, null);
117
                // }
118
                else if (geometryType.equalsIgnoreCase("MULTIPOINT")) {
119
                        return GEOMETRY_FACTORY.createMultiPoint(coords);
120
                }
121
                return null;
122
        }
123

    
124
        public static Polygon createPolygon(Coordinate[] coords, int[] indexOfParts) {
125
                int numberOfHoles = indexOfParts.length - 1;
126
                int firstPointOfShell = 0;
127
                int lastPointOfShell;
128
                if (numberOfHoles == 0) {
129
                        lastPointOfShell = coords.length - 1;
130
                } else {
131
                        lastPointOfShell = indexOfParts[1] - 1;
132
                }
133
                Coordinate[] shellCoords = new Coordinate[lastPointOfShell
134
                                - firstPointOfShell + 1];
135
                System.arraycopy(coords, firstPointOfShell, shellCoords, 0,
136
                                shellCoords.length);
137
                LinearRing shell = GEOMETRY_FACTORY.createLinearRing(shellCoords);
138

    
139
                LinearRing[] holes = null;
140
                if (numberOfHoles > 0) {
141
                        holes = new LinearRing[numberOfHoles];
142
                        int firstPointOfHole, lastPointOfHole;
143
                        Coordinate[] holeCoords;
144
                        for (int i = 1; i < indexOfParts.length - 1; i++) {
145
                                firstPointOfHole = indexOfParts[i];
146
                                lastPointOfHole = indexOfParts[i + 1] - 1;
147
                                holeCoords = new Coordinate[lastPointOfHole - firstPointOfHole
148
                                                + 1];
149
                                System.arraycopy(coords, firstPointOfHole, holeCoords, 0,
150
                                                holeCoords.length);
151
                                holes[i - 1] = GEOMETRY_FACTORY.createLinearRing(holeCoords);
152
                        }
153
                        firstPointOfHole = indexOfParts[indexOfParts.length - 1];
154
                        lastPointOfHole = coords.length - 1;
155
                        holeCoords = new Coordinate[lastPointOfHole - firstPointOfHole + 1];
156
                        System.arraycopy(coords, firstPointOfHole, holeCoords, 0,
157
                                        holeCoords.length);
158
                        holes[holes.length - 1] = GEOMETRY_FACTORY.createLinearRing(holeCoords);
159
                }
160
                return GEOMETRY_FACTORY.createPolygon(shell, holes);
161
        }
162

    
163
        /**
164
         * Returns an array of lenght equals to the number of parts of a polygon.
165
         * Each member of the array has a 'pointer' to the first point of each part
166
         * in the coordinates array of the polygon.
167
         * 
168
         * 
169
         * @param polygon
170
         * @see createPolygon(Coordinate[] coords, int[] indexOfParts)
171
         * @return
172
         */
173
        public static int[] getIndexOfParts(Polygon polygon) {
174
                int numParts = polygon.getNumInteriorRing() + 1;
175
                int[] indexOfParts = new int[numParts];
176
                indexOfParts[0] = 0;
177
                if (numParts > 1) {
178
                        indexOfParts[1] = polygon.getExteriorRing().getNumPoints();
179
                }
180
                if (numParts > 2) {
181
                        for (int i = 1; i < polygon.getNumInteriorRing(); i++) {
182
                                indexOfParts[i + 1] = indexOfParts[i]
183
                                                + polygon.getInteriorRingN(i).getNumPoints() + 1;
184
                        }
185
                }
186
                return indexOfParts;
187
        }
188
        
189
        public static MultiLineString convertToMultiLineString(GeometryCollection geomCol){
190
                List<LineString> lines = new ArrayList<LineString>();
191
                int numGeometries = geomCol.getNumGeometries();
192
                for (int i = 0; i < numGeometries; i++) {
193
                        Geometry geom = geomCol.getGeometryN(i);
194
                        if (geom instanceof LineString)
195
                                lines.add((LineString) geom);
196
                        else if (geom instanceof MultiLineString) {
197
                                MultiLineString multiLine = (MultiLineString) geom;
198
                                int numLines = multiLine.getNumGeometries();
199
                                for (int j = 0; j < numLines; j++) {
200
                                        lines.add((LineString) multiLine.getGeometryN(j));
201
                                }// j
202
                        }// else
203
                        else if (geom instanceof GeometryCollection) {
204
                                MultiLineString multiLine = convertToMultiLineString((GeometryCollection) geom);
205
                                int numLines = multiLine.getNumGeometries();
206
                                for (int j = 0; j < numLines; j++) {
207
                                        lines.add((LineString) multiLine.getGeometryN(j));
208
                                }// j
209
                        }// else
210
                }// for i
211
                LineString[] lineArray = new LineString[lines.size()];
212
                lines.toArray(lineArray);
213
                return GEOMETRY_FACTORY.createMultiLineString(lineArray);
214
        }
215
        
216
        
217

    
218
        public static MultiPolygon convertToMultiPolygon(GeometryCollection geomCol) {
219
                List<Polygon> polygons = new ArrayList<Polygon>();
220
                int numGeometries = geomCol.getNumGeometries();
221
                for (int i = 0; i < numGeometries; i++) {
222
                        Geometry geom = geomCol.getGeometryN(i);
223
                        if (geom instanceof Polygon)
224
                                polygons.add((Polygon) geom);
225
                        else if (geom instanceof MultiPolygon) {
226
                                MultiPolygon multiPol = (MultiPolygon) geom;
227
                                int numPols = multiPol.getNumGeometries();
228
                                for (int j = 0; j < numPols; j++) {
229
                                        polygons.add((Polygon) multiPol.getGeometryN(j));
230
                                }// j
231
                        }// else
232
                        else if (geom instanceof GeometryCollection) {
233
                                MultiPolygon multiPol = convertToMultiPolygon((GeometryCollection) geom);
234
                                int numPols = multiPol.getNumGeometries();
235
                                for (int j = 0; j < numPols; j++) {
236
                                        polygons.add((Polygon) multiPol.getGeometryN(j));
237
                                }// j
238
                        }// else
239
                }// for i
240
                Polygon[] polyArray = new Polygon[polygons.size()];
241
                polygons.toArray(polyArray);
242
                return GEOMETRY_FACTORY.createMultiPolygon(polyArray);
243
        }
244

    
245
        public static boolean isClosed(Geometry geom) {
246
                return isClosed(geom, 0d);
247
        }
248

    
249
        public static Geometry getGeometryToClose(Geometry geom,
250
                        double snapTolerance) {
251
                if ((geom instanceof Point) || (geom instanceof MultiPoint))
252
                        return null;
253
                else if (geom instanceof GeometryCollection) {
254
                        GeometryCollection solution = null;
255
                        List<Geometry> solutionGeoms = new ArrayList<Geometry>();
256
                        GeometryCollection geomCol = (GeometryCollection) geom;
257
                        for (int i = 0; i < geomCol.getNumGeometries(); i++) {
258
                                Geometry tempGeom = geomCol.getGeometryN(i);
259
                                Geometry geo2close = getGeometryToClose(tempGeom, snapTolerance);
260
                                solutionGeoms.add(geo2close);
261
                        }
262

    
263
                        Geometry[] solutionG = GeometryFactory
264
                                        .toGeometryArray(solutionGeoms);
265
                        solution = GEOMETRY_FACTORY.createGeometryCollection(solutionG);
266
                        return solution;
267
                } else if (geom instanceof LineString) {
268
                        LineString solution = null;
269
                        LineString tempGeom = (LineString) geom;
270
                        Coordinate start = tempGeom.getCoordinateN(0);
271
                        Coordinate end = tempGeom
272
                                        .getCoordinateN(tempGeom.getNumPoints() - 1);
273
                        if (!SnapCGAlgorithms.snapEquals2D(start, end, snapTolerance)) {
274
                                Coordinate[] coordinates = { start, end };
275
                                solution = GEOMETRY_FACTORY.createLineString(coordinates);
276
                        }
277
                        return solution;
278

    
279
                } else if (geom instanceof Polygon) {
280
                        GeometryCollection solution = null;
281
                        List<Geometry> solutionGeoms = new ArrayList<Geometry>();
282
                        Polygon polygon = (Polygon) geom;
283
                        LineString ring = polygon.getExteriorRing();
284
                        Geometry ring2close = getGeometryToClose(ring, snapTolerance);
285
                        if (ring2close != null)
286
                                solutionGeoms.add(ring2close);
287
                        // TODO Must we check all polygon rings, or only exterior ring?
288
                        int numHoles = polygon.getNumInteriorRing();
289
                        for (int i = 0; i < numHoles; i++) {
290
                                LineString hole = polygon.getInteriorRingN(i);
291
                                Geometry hole2close = getGeometryToClose(hole, snapTolerance);
292
                                if (hole != null)
293
                                        solutionGeoms.add(hole2close);
294
                        }
295
                        Geometry[] solutionArray = GeometryFactory
296
                                        .toGeometryArray(solutionGeoms);
297
                        if (solutionArray.length > 0)
298
                                solution = GEOMETRY_FACTORY.createGeometryCollection(solutionArray);
299
                        return solution;
300
                }// else
301

    
302
                return null;
303
        }
304

    
305
        public static boolean isClosed(Geometry geom, double snapTolerance) {
306
                if ((geom instanceof Point) || (geom instanceof MultiPoint))
307
                        return false;
308
                else if (geom instanceof GeometryCollection) {
309
                        GeometryCollection geomCol = (GeometryCollection) geom;
310
                        for (int i = 0; i < geomCol.getNumGeometries(); i++) {
311
                                Geometry tempGeom = geomCol.getGeometryN(i);
312
                                if (!isClosed(tempGeom, snapTolerance))
313
                                        return false;
314
                        }
315
                        return true;
316
                } else if (geom instanceof LineString) {
317
                        LineString tempGeom = (LineString) geom;
318
                        return SnapCGAlgorithms.snapEquals2D(tempGeom.getCoordinateN(0),
319
                                        tempGeom.getCoordinateN(tempGeom.getNumPoints() - 1),
320
                                        snapTolerance);
321
                } else if (geom instanceof Polygon) {
322
                        Polygon polygon = (Polygon) geom;
323
                        LineString ring = polygon.getExteriorRing();
324
                        if (!isClosed(ring, snapTolerance))
325
                                return false;
326
                        // TODO Must we check all polygon rings, or only exterior ring?
327
                        int numHoles = polygon.getNumInteriorRing();
328
                        for (int i = 0; i < numHoles; i++) {
329
                                LineString hole = polygon.getInteriorRingN(i);
330
                                if (!isClosed(hole, snapTolerance))
331
                                        return false;
332
                        }
333
                        return true;
334
                }// else
335
                return false;
336
        }
337

    
338
        public static Coordinate[] getPoint2DAsCoordinates(Point2D[] point2d) {
339
                Coordinate[] solution = new Coordinate[point2d.length];
340
                for (int i = 0; i < point2d.length; i++) {
341
                        solution[i] = new Coordinate(point2d[i].getX(), point2d[i].getY());
342
                }
343
                return solution;
344
        }
345

    
346
        // TODO Quitar esto de FConverter, llevarlo a JtsUtil, y PROPONER LA
347
        // CREACION DE UN
348
        // PAQUETE JTS EN FMAP
349
        public static boolean pointInList(Coordinate testPoint,
350
                        Coordinate[] pointList) {
351
                return pointInList(testPoint, pointList, 0d);
352
        }
353

    
354
        public static boolean pointInList(Coordinate testPoint,
355
                        Coordinate[] pointList, double snapTolerance) {
356
                int t;
357
                int numpoints;
358
                Coordinate p;
359
                numpoints = Array.getLength(pointList);
360
                for (t = 0; t < numpoints; t++) {
361
                        p = pointList[t];
362
                        if (SnapCGAlgorithms.snapEquals2D(p, testPoint, snapTolerance))
363
                                return true;
364
                }
365

    
366
                return false;
367
        }
368

    
369
        public static Coordinate findPtNotNode(Coordinate[] testCoords,
370
                        LinearRing searchRing, GeometryGraph graph) {
371
                // find edge corresponding to searchRing.
372
                Edge searchEdge = graph.findEdge(searchRing);
373
                // find a point in the testCoords which is not a node of the searchRing
374
                EdgeIntersectionList eiList = searchEdge.getEdgeIntersectionList();
375
                // somewhat inefficient - is there a better way? (Use a node map, for
376
                // instance?)
377
                for (int i = 0; i < testCoords.length; i++) {
378
                        Coordinate pt = testCoords[i];
379
                        if (!eiList.isIntersection(pt))
380
                                return pt;
381
                }
382
                return null;
383
        }
384

    
385
        /**
386
         * This method is needed because call to LinearRing.reverse returns a
387
         * LineString,
388
         * 
389
         * @param ring
390
         * @return
391
         */
392
        public static LinearRing reverse(LinearRing ring) {
393
                CoordinateSequence seq = ring.getCoordinateSequence();
394
                CoordinateSequences.reverse(seq);
395
                LinearRing solution = GEOMETRY_FACTORY.createLinearRing(seq);
396
                return solution;
397
        }
398

    
399
        public static Geometry toJtsGeometry(IGeometry fmapGeometry) {
400
                Geometry solution = null;
401
                if (fmapGeometry instanceof FGeometry) {
402
                        FShape shp = (FShape) ((FGeometry) fmapGeometry).getInternalShape();
403
                        solution = NewFConverter.java2d_to_jts(shp);
404
                } else if (fmapGeometry instanceof FGeometryCollection) {
405
                        IGeometry[] geometries = ((FGeometryCollection) fmapGeometry)
406
                                        .getGeometries();
407
                        Geometry[] theGeoms = new Geometry[geometries.length];
408
                        for (int i = 0; i < geometries.length; i++) {
409
                                theGeoms[i] = ((IGeometry) geometries[i]).toJTSGeometry();
410
                        }
411
                        solution = GEOMETRY_FACTORY.createGeometryCollection(theGeoms);
412

    
413
                } else if (fmapGeometry instanceof FMultiPoint2D) {
414
                        solution = ((FMultiPoint2D) fmapGeometry).toJTSGeometry();
415
                }
416
                return solution;
417
        }
418
        
419
        public static Envelope toSnapRectangle(Coordinate coord, double snapTolerance){
420
                Envelope solution = null;
421
                
422
                double xmin = coord.x - snapTolerance;
423
                double xmax = coord.x + snapTolerance;
424
                double ymin = coord.y - snapTolerance;
425
                double ymax = coord.y + snapTolerance;
426
                solution = new Envelope(xmin, xmax, ymin, ymax);
427
                return solution;
428
        }
429
        
430
        /**
431
         * Returns the segment of the specified geometry closest to
432
         * the specified coordinate.
433
         * 
434
         * This code is extracted from JTS.
435
         * 
436
         * @param geometry
437
         * @param target
438
         * @return
439
         */
440
        public static LineSegment segmentInRange( Geometry geometry, Coordinate target, double tolerance ) {
441
        LineSegment closest = null;
442
        List coordArrays = CoordinateArrays.toCoordinateArrays(geometry, false);
443
        for( Iterator i = coordArrays.iterator(); i.hasNext(); ) {
444
            Coordinate[] coordinates = (Coordinate[]) i.next();
445
            for( int j = 1; j < coordinates.length; j++ ) { 
446
                LineSegment candidate = new LineSegment(coordinates[j - 1], coordinates[j]);
447
                if (candidate.distance(target) > tolerance) {
448
                    continue;
449
                }
450
                if ((closest == null) || (candidate.distance(target) < closest.distance(target))) {
451
                    closest = candidate;
452
                }
453
            }
454
        }
455
        return closest;
456
    }
457
}