Statistics
| Revision:

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

History | View | Annotate | Download (14.4 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 19632 2008-03-16 12:42:28Z 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.List;
59

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

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

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

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

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

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

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

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

    
242
        public static boolean isClosed(Geometry geom) {
243
                return isClosed(geom, 0d);
244
        }
245

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

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

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

    
299
                return null;
300
        }
301

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

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

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

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

    
363
                return false;
364
        }
365

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

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

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

    
410
                } else if (fmapGeometry instanceof FMultiPoint2D) {
411
                        solution = ((FMultiPoint2D) fmapGeometry).toJTSGeometry();
412
                }
413
                return solution;
414
        }
415
        
416
        public static Envelope toSnapRectangle(Coordinate coord, double snapTolerance){
417
                Envelope solution = null;
418
                
419
                double xmin = coord.x - snapTolerance;
420
                double xmax = coord.x + snapTolerance;
421
                double ymin = coord.y - snapTolerance;
422
                double ymax = coord.y + snapTolerance;
423
                solution = new Envelope(xmin, xmax, ymin, ymax);
424
                return solution;
425
        }
426
}