Statistics
| Revision:

root / trunk / libraries / libTopology / src / org / gvsig / jts / JtsUtil.java @ 20259

History | View | Annotate | Download (27.8 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 20259 2008-04-21 15:55:58Z 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.Arrays;
59
import java.util.Iterator;
60
import java.util.List;
61
import java.util.Stack;
62

    
63
import org.gvsig.fmap.core.NewFConverter;
64

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

    
96
import es.axios.udig.ui.editingtools.internal.geometryoperations.split.SplitStrategy;
97

    
98
/**
99
 * Utility methods for JTS library use.
100
 * 
101
 * @author azabala
102
 * 
103
 */
104
public class JtsUtil {
105
        //FIXME PrecionModel's scale should be configurable by a JTS preferences
106
        //dialog
107
        public static final PrecisionModel GVSIG_PRECISION_MODEL = 
108
                new PrecisionModel(10000);
109
        
110
        public static final GeometryFactory GEOMETRY_FACTORY = 
111
                new GeometryFactory(GVSIG_PRECISION_MODEL);
112
        
113
        public static final GeometryEditor GEOMETRY_EDITOR =
114
                        new GeometryEditor(GEOMETRY_FACTORY);
115

    
116
        public static Geometry createGeometry(Coordinate[] coords,
117
                        String geometryType) {
118
                if (geometryType.equalsIgnoreCase("POINT")) {
119
                        return GEOMETRY_FACTORY.createPoint(coords[0]);
120
                } else if (geometryType.equalsIgnoreCase("LINESTRING")) {
121
                        return GEOMETRY_FACTORY.createLineString(coords);
122
                } else if (geometryType.equalsIgnoreCase("LINEARRING")) {
123
                        return GEOMETRY_FACTORY.createLinearRing(coords);
124
                }
125
                // else if (geometryType.equalsIgnoreCase("POLYGON")) {
126
                // // LinearRing exterior = geomFactory.createLinearRing(coords);
127
                // // return geomFactory.createPolygon(exterior, null);
128
                // }
129
                else if (geometryType.equalsIgnoreCase("MULTIPOINT")) {
130
                        return GEOMETRY_FACTORY.createMultiPoint(coords);
131
                }
132
                return null;
133
        }
134

    
135
        public static Polygon createPolygon(Coordinate[] coords, int[] indexOfParts) {
136
                int numberOfHoles = indexOfParts.length - 1;
137
                int firstPointOfShell = 0;
138
                int lastPointOfShell;
139
                if (numberOfHoles == 0) {
140
                        lastPointOfShell = coords.length - 1;
141
                } else {
142
                        lastPointOfShell = indexOfParts[1] - 1;
143
                }
144
                Coordinate[] shellCoords = new Coordinate[lastPointOfShell
145
                                - firstPointOfShell + 1];
146
                System.arraycopy(coords, firstPointOfShell, shellCoords, 0,
147
                                shellCoords.length);
148
                LinearRing shell = GEOMETRY_FACTORY.createLinearRing(shellCoords);
149

    
150
                LinearRing[] holes = null;
151
                if (numberOfHoles > 0) {
152
                        holes = new LinearRing[numberOfHoles];
153
                        int firstPointOfHole, lastPointOfHole;
154
                        Coordinate[] holeCoords;
155
                        for (int i = 1; i < indexOfParts.length - 1; i++) {
156
                                firstPointOfHole = indexOfParts[i];
157
                                lastPointOfHole = indexOfParts[i + 1] - 1;
158
                                holeCoords = new Coordinate[lastPointOfHole - firstPointOfHole
159
                                                + 1];
160
                                System.arraycopy(coords, firstPointOfHole, holeCoords, 0,
161
                                                holeCoords.length);
162
                                holes[i - 1] = GEOMETRY_FACTORY.createLinearRing(holeCoords);
163
                        }
164
                        firstPointOfHole = indexOfParts[indexOfParts.length - 1];
165
                        lastPointOfHole = coords.length - 1;
166
                        holeCoords = new Coordinate[lastPointOfHole - firstPointOfHole + 1];
167
                        System.arraycopy(coords, firstPointOfHole, holeCoords, 0,
168
                                        holeCoords.length);
169
                        holes[holes.length - 1] = GEOMETRY_FACTORY.createLinearRing(holeCoords);
170
                }
171
                return GEOMETRY_FACTORY.createPolygon(shell, holes);
172
        }
173

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

    
229
        public static MultiPolygon convertToMultiPolygon(GeometryCollection geomCol) {
230
                List<Polygon> polygons = new ArrayList<Polygon>();
231
                int numGeometries = geomCol.getNumGeometries();
232
                for (int i = 0; i < numGeometries; i++) {
233
                        Geometry geom = geomCol.getGeometryN(i);
234
                        if (geom instanceof Polygon)
235
                                polygons.add((Polygon) geom);
236
                        else if (geom instanceof MultiPolygon) {
237
                                MultiPolygon multiPol = (MultiPolygon) geom;
238
                                int numPols = multiPol.getNumGeometries();
239
                                for (int j = 0; j < numPols; j++) {
240
                                        polygons.add((Polygon) multiPol.getGeometryN(j));
241
                                }// j
242
                        }// else
243
                        else if (geom instanceof GeometryCollection) {
244
                                MultiPolygon multiPol = convertToMultiPolygon((GeometryCollection) geom);
245
                                int numPols = multiPol.getNumGeometries();
246
                                for (int j = 0; j < numPols; j++) {
247
                                        polygons.add((Polygon) multiPol.getGeometryN(j));
248
                                }// j
249
                        }// else
250
                }// for i
251
                Polygon[] polyArray = new Polygon[polygons.size()];
252
                polygons.toArray(polyArray);
253
                return GEOMETRY_FACTORY.createMultiPolygon(polyArray);
254
        }
255

    
256
        public static boolean isClosed(Geometry geom) {
257
                return isClosed(geom, 0d);
258
        }
259

    
260
        public static Geometry getGeometryToClose(Geometry geom,
261
                        double snapTolerance) {
262
                if ((geom instanceof Point) || (geom instanceof MultiPoint))
263
                        return null;
264
                else if (geom instanceof GeometryCollection) {
265
                        GeometryCollection solution = null;
266
                        List<Geometry> solutionGeoms = new ArrayList<Geometry>();
267
                        GeometryCollection geomCol = (GeometryCollection) geom;
268
                        for (int i = 0; i < geomCol.getNumGeometries(); i++) {
269
                                Geometry tempGeom = geomCol.getGeometryN(i);
270
                                Geometry geo2close = getGeometryToClose(tempGeom, snapTolerance);
271
                                solutionGeoms.add(geo2close);
272
                        }
273

    
274
                        Geometry[] solutionG = GeometryFactory
275
                                        .toGeometryArray(solutionGeoms);
276
                        solution = GEOMETRY_FACTORY.createGeometryCollection(solutionG);
277
                        return solution;
278
                } else if (geom instanceof LineString) {
279
                        LineString solution = null;
280
                        LineString tempGeom = (LineString) geom;
281
                        Coordinate start = tempGeom.getCoordinateN(0);
282
                        Coordinate end = tempGeom
283
                                        .getCoordinateN(tempGeom.getNumPoints() - 1);
284
                        if (!SnapCGAlgorithms.snapEquals2D(start, end, snapTolerance)) {
285
                                Coordinate[] coordinates = { start, end };
286
                                solution = GEOMETRY_FACTORY.createLineString(coordinates);
287
                        }
288
                        return solution;
289

    
290
                } else if (geom instanceof Polygon) {
291
                        GeometryCollection solution = null;
292
                        List<Geometry> solutionGeoms = new ArrayList<Geometry>();
293
                        Polygon polygon = (Polygon) geom;
294
                        LineString ring = polygon.getExteriorRing();
295
                        Geometry ring2close = getGeometryToClose(ring, snapTolerance);
296
                        if (ring2close != null)
297
                                solutionGeoms.add(ring2close);
298
                        // TODO Must we check all polygon rings, or only exterior ring?
299
                        int numHoles = polygon.getNumInteriorRing();
300
                        for (int i = 0; i < numHoles; i++) {
301
                                LineString hole = polygon.getInteriorRingN(i);
302
                                Geometry hole2close = getGeometryToClose(hole, snapTolerance);
303
                                if (hole != null)
304
                                        solutionGeoms.add(hole2close);
305
                        }
306
                        Geometry[] solutionArray = GeometryFactory
307
                                        .toGeometryArray(solutionGeoms);
308
                        if (solutionArray.length > 0)
309
                                solution = GEOMETRY_FACTORY.createGeometryCollection(solutionArray);
310
                        return solution;
311
                }// else
312

    
313
                return null;
314
        }
315

    
316
        public static boolean isClosed(Geometry geom, double snapTolerance) {
317
                if ((geom instanceof Point) || (geom instanceof MultiPoint))
318
                        return false;
319
                else if (geom instanceof GeometryCollection) {
320
                        GeometryCollection geomCol = (GeometryCollection) geom;
321
                        for (int i = 0; i < geomCol.getNumGeometries(); i++) {
322
                                Geometry tempGeom = geomCol.getGeometryN(i);
323
                                if (!isClosed(tempGeom, snapTolerance))
324
                                        return false;
325
                        }
326
                        return true;
327
                } else if (geom instanceof LineString) {
328
                        LineString tempGeom = (LineString) geom;
329
                        return SnapCGAlgorithms.snapEquals2D(tempGeom.getCoordinateN(0),
330
                                        tempGeom.getCoordinateN(tempGeom.getNumPoints() - 1),
331
                                        snapTolerance);
332
                } else if (geom instanceof Polygon) {
333
                        Polygon polygon = (Polygon) geom;
334
                        LineString ring = polygon.getExteriorRing();
335
                        if (!isClosed(ring, snapTolerance))
336
                                return false;
337
                        // TODO Must we check all polygon rings, or only exterior ring?
338
                        int numHoles = polygon.getNumInteriorRing();
339
                        for (int i = 0; i < numHoles; i++) {
340
                                LineString hole = polygon.getInteriorRingN(i);
341
                                if (!isClosed(hole, snapTolerance))
342
                                        return false;
343
                        }
344
                        return true;
345
                }// else
346
                return false;
347
        }
348

    
349
        public static Coordinate[] getPoint2DAsCoordinates(Point2D[] point2d) {
350
                Coordinate[] solution = new Coordinate[point2d.length];
351
                for (int i = 0; i < point2d.length; i++) {
352
                        solution[i] = new Coordinate(point2d[i].getX(), point2d[i].getY());
353
                }
354
                return solution;
355
        }
356

    
357
        // TODO Quitar esto de FConverter, llevarlo a JtsUtil, y PROPONER LA
358
        // CREACION DE UN
359
        // PAQUETE JTS EN FMAP
360
        public static boolean pointInList(Coordinate testPoint,
361
                        Coordinate[] pointList) {
362
                return pointInList(testPoint, pointList, 0d);
363
        }
364

    
365
        public static boolean pointInList(Coordinate testPoint,
366
                        Coordinate[] pointList, double snapTolerance) {
367
                int t;
368
                int numpoints;
369
                Coordinate p;
370
                numpoints = Array.getLength(pointList);
371
                for (t = 0; t < numpoints; t++) {
372
                        p = pointList[t];
373
                        if (SnapCGAlgorithms.snapEquals2D(p, testPoint, snapTolerance))
374
                                return true;
375
                }
376

    
377
                return false;
378
        }
379

    
380
        public static Coordinate findPtNotNode(Coordinate[] testCoords,
381
                        LinearRing searchRing, GeometryGraph graph) {
382
                // find edge corresponding to searchRing.
383
                Edge searchEdge = graph.findEdge(searchRing);
384
                // find a point in the testCoords which is not a node of the searchRing
385
                EdgeIntersectionList eiList = searchEdge.getEdgeIntersectionList();
386
                // somewhat inefficient - is there a better way? (Use a node map, for
387
                // instance?)
388
                for (int i = 0; i < testCoords.length; i++) {
389
                        Coordinate pt = testCoords[i];
390
                        if (!eiList.isIntersection(pt))
391
                                return pt;
392
                }
393
                return null;
394
        }
395

    
396
        /**
397
         * This method is needed because call to LinearRing.reverse returns a
398
         * LineString,
399
         * 
400
         * @param ring
401
         * @return
402
         */
403
        public static LinearRing reverse(LinearRing ring) {
404
                CoordinateSequence seq = ring.getCoordinateSequence();
405
                CoordinateSequences.reverse(seq);
406
                LinearRing solution = GEOMETRY_FACTORY.createLinearRing(seq);
407
                return solution;
408
        }
409

    
410
        public static Geometry toJtsGeometry(IGeometry fmapGeometry) {
411
                Geometry solution = null;
412
                if (fmapGeometry instanceof FGeometry) {
413
                        FShape shp = (FShape) ((FGeometry) fmapGeometry).getInternalShape();
414
                        solution = NewFConverter.java2d_to_jts(shp);
415
                } else if (fmapGeometry instanceof FGeometryCollection) {
416
                        IGeometry[] geometries = ((FGeometryCollection) fmapGeometry)
417
                                        .getGeometries();
418
                        Geometry[] theGeoms = new Geometry[geometries.length];
419
                        for (int i = 0; i < geometries.length; i++) {
420
                                theGeoms[i] = ((IGeometry) geometries[i]).toJTSGeometry();
421
                        }
422
                        solution = GEOMETRY_FACTORY.createGeometryCollection(theGeoms);
423

    
424
                } else if (fmapGeometry instanceof FMultiPoint2D) {
425
                        solution = ((FMultiPoint2D) fmapGeometry).toJTSGeometry();
426
                }
427
                return solution;
428
        }
429
        
430
        public static Envelope toSnapRectangle(Coordinate coord, double snapTolerance){
431
                Envelope solution = null;
432
                
433
                double xmin = coord.x - snapTolerance;
434
                double xmax = coord.x + snapTolerance;
435
                double ymin = coord.y - snapTolerance;
436
                double ymax = coord.y + snapTolerance;
437
                solution = new Envelope(xmin, xmax, ymin, ymax);
438
                return solution;
439
        }
440
        
441
        
442
        public static Geometry[] extractGeometries(GeometryCollection geomCol){
443
                Geometry[] solution;
444
                ArrayList<Geometry> geometries = new ArrayList<Geometry>();
445
                Stack<Geometry> stack = new Stack<Geometry>();
446
                stack.add(geomCol);
447
                while(stack.size() > 0){
448
                        Geometry geometry = (Geometry) stack.pop();
449
                        if(geometry instanceof GeometryCollection){
450
                                GeometryCollection collection = (GeometryCollection) geometry;
451
                                for(int i = 0; i < collection.getNumGeometries(); i++){
452
                                        stack.add(collection.getGeometryN(i));
453
                                }//for
454
                        }else{
455
                                geometries.add(geometry);
456
                        }
457
                }//while
458
                solution = new Geometry[geometries.size()];
459
                return geometries.toArray(solution);
460
        }
461
        
462
        //TODO REESCRIBIR ESTO CON GENERICS
463
//        /**
464
//     * Adapts a Geometry <code>geom</code> to another type of geometry given the desired geometry
465
//     * class.
466
//     * <p>
467
//     * Currently implemented adaptations:
468
//     * <ul>
469
//     * <li>Point -> MultiPoint. Wraps the Point on a single part MultiPoint.
470
//     * <li>Polygon -> MultiPolygon. Wraps the Polygon on a single part MultiPolygon.
471
//     * <li>LineString -> MultiLineString. Wraps the LineString on a single part MultiLineString.
472
//     * <li>MultiLineString -> String. Succeeds if merging the parts result in a single LineString,
473
//     * fails otherwise.
474
//     * <li>MultiPolygon -> Polygon. Succeeds if merging the parts result in a single Polygon, fails
475
//     * otherwise.
476
//     * <li>* -> GeometryCollection
477
//     * </ul>
478
//     * </p>
479
//     * TODO: add more adaptations on an as needed basis
480
//     * 
481
//     * @param inputGeom
482
//     * @param adaptTo
483
//     * @return a new Geometry adapted
484
//     * @throws IllegalArgumentException if <code>geom</code> cannot be adapted as
485
//     *         <code>adapTo</code>
486
//     */
487
//    public static Geometry adapt( final Geometry inputGeom, final Class< ? extends Geometry> adaptTo ) {
488
//
489
//        assert inputGeom != null : "inputGeom can't be null";
490
//        assert adaptTo != null : "adaptTo can't be null";;
491
//
492
//        final Class<?> geomClass = inputGeom.getClass();
493
//
494
//        if (Geometry.class.equals(adaptTo)) {
495
//            return inputGeom;
496
//        }
497
//
498
//        final GeometryFactory gf = inputGeom.getFactory();
499
//       
500
//        if (MultiPoint.class.equals(adaptTo) && Point.class.equals(geomClass)) {
501
//            return gf.createMultiPoint(new Point[]{(Point) inputGeom});
502
//        }
503
//
504
//        if (Polygon.class.equals(adaptTo)) {
505
//            if (adaptTo.equals(geomClass)) {
506
//                return inputGeom;
507
//            }
508
//            Polygonizer polygonnizer = new Polygonizer();
509
//            polygonnizer.add(inputGeom);
510
//            Collection polys = polygonnizer.getPolygons();
511
//            Polygon[] polygons = new ArrayList<Polygon>(polys).toArray(new Polygon[polys.size()]);
512
//
513
//            if (polygons.length == 1) {
514
//                return polygons[0];
515
//            }
516
//        }
517
//
518
//        if (MultiPolygon.class.equals(adaptTo)) {
519
//            if (adaptTo.equals(geomClass)) {
520
//                return inputGeom;
521
//            }
522
//            if (Polygon.class.equals(geomClass)) {
523
//                return gf.createMultiPolygon(new Polygon[]{(Polygon) inputGeom});
524
//            }
525
//            /*
526
//             * Polygonizer polygonnizer = new Polygonizer(); polygonnizer.add(inputGeom); Collection
527
//             * polys = polygonnizer.getPolygons(); Polygon[] polygons = new ArrayList<Polygon>(polys).toArray(new
528
//             * Polygon[polys.size()]); if (MultiPolygon.class.equals(adaptTo)) { return
529
//             * gf.createMultiPolygon(polygons); } if (polygons.length == 1) { return polygons[0]; }
530
//             */
531
//        }
532
//
533
//        if (GeometryCollection.class.equals(adaptTo)) {
534
//            return gf.createGeometryCollection(new Geometry[]{inputGeom});
535
//        }
536
//
537
//        if (MultiLineString.class.equals(adaptTo) || LineString.class.equals(adaptTo)) {
538
//            LineMerger merger = new LineMerger();
539
//            merger.add(inputGeom);
540
//            Collection mergedLineStrings = merger.getMergedLineStrings();
541
//            ArrayList<LineString> lineList = new ArrayList<LineString>(mergedLineStrings);
542
//            LineString[] lineStrings = lineList.toArray(new LineString[mergedLineStrings.size()]);
543
//
544
//            if (MultiLineString.class.equals(adaptTo)) {
545
//                MultiLineString line = gf.createMultiLineString(lineStrings);
546
//                return line;
547
//            }
548
//            if (lineStrings.length == 1) {
549
//                Geometry mergedResult = (Geometry) lineStrings[0];
550
//                return mergedResult;
551
//            }
552
//        }
553
//        if(Polygon.class.equals(adaptTo) && (MultiPolygon.class.equals(geomClass))){
554
//            // adapts multipolygon to polygon
555
//            
556
//            assert inputGeom.getNumGeometries() == 1 : "the collection must have 1 element to adapt to Polygon";
557
//            return inputGeom.getGeometryN(1);
558
//        
559
//        } else if(LineString.class.equals(adaptTo) && (MultiLineString.class.equals(geomClass))){
560
//            // adapts MultiLinestring to Linestring
561
//            
562
//            assert inputGeom.getNumGeometries() == 1 : "the collection must have 1 element to adapt to Polygon";
563
//            return inputGeom.getGeometryN(1);
564
//        }
565
//
566
//        final String msg = MessageFormat.format(Messages.GeometryUtil_DonotKnowHowAdapt,
567
//                                                geomClass.getSimpleName(), adaptTo.getSimpleName());
568
//
569
//        throw new IllegalArgumentException(msg);
570
//    }
571
        public static LineString[] extractLineStrings(Geometry g){
572
                LineString[] solution = null;
573
                List<LineString> solutionList = new ArrayList<LineString>();
574
                if (g instanceof LineString)
575
                        solutionList.add((LineString) g);
576
                else if (g instanceof GeometryCollection) {
577
                        GeometryCollection geomCol = (GeometryCollection) g;
578
                        List lines = LinearComponentExtracter.getLines(geomCol);
579
                        solutionList.addAll(lines);
580
                }
581
                solution = new LineString[solutionList.size()];
582
                solutionList.toArray(solution);
583
                return solution;
584
        }
585
        
586
        public static Polygon[] extractPolygons(Geometry g){
587
                Polygon[] solution = null;
588
                List<Polygon> solutionList = new ArrayList<Polygon>();
589
                if (g instanceof Polygon)
590
                        solutionList.add((Polygon) g);
591
                else if (g instanceof GeometryCollection) {
592
                        GeometryCollection geomCol = (GeometryCollection) g;
593
                        List polygons = PolygonExtracter.getPolygons(geomCol);
594
                        solutionList.addAll(polygons);
595
                }
596
                solution = new Polygon[solutionList.size()];
597
                solutionList.toArray(solution);
598
                return solution;
599
        }
600
        
601
        public static Point[] extractPoints(Geometry g){
602
                Point[] solution = null;
603
                List<Point> solutionList = new ArrayList<Point>();
604
                if (g instanceof Point)
605
                        solutionList.add((Point) g);
606
                else if (g instanceof GeometryCollection) {
607
                        GeometryCollection geomCol = (GeometryCollection) g;
608
                        List points = PointExtracter.getPoints(geomCol);
609
                        solutionList.addAll(points);
610
                }
611
                solution = new Point[solutionList.size()];
612
                solutionList.toArray(solution);
613
                return solution;
614
        }
615
        
616
        /**
617
         * Returns the segment of the specified geometry closest to
618
         * the specified coordinate.
619
         * 
620
         * This code is extracted from JTS.
621
         * 
622
         * @param geometry
623
         * @param target
624
         * @return
625
         */
626
        public static LineSegment segmentInRange( Geometry geometry, Coordinate target, double tolerance ) {
627
        LineSegment closest = null;
628
        List coordArrays = CoordinateArrays.toCoordinateArrays(geometry, false);
629
        for( Iterator i = coordArrays.iterator(); i.hasNext(); ) {
630
            Coordinate[] coordinates = (Coordinate[]) i.next();
631
            for( int j = 1; j < coordinates.length; j++ ) { 
632
                LineSegment candidate = new LineSegment(coordinates[j - 1], coordinates[j]);
633
                if (candidate.distance(target) > tolerance) {
634
                    continue;
635
                }
636
                if ((closest == null) || (candidate.distance(target) < closest.distance(target))) {
637
                    closest = candidate;
638
                }
639
            }
640
        }
641
        return closest;
642
    }
643
        
644
        public static LinearRing toLinearRing(LineString lineString){
645
                Coordinate[] coords = lineString.getCoordinates();
646
                return GEOMETRY_FACTORY.createLinearRing(coords);
647
        }
648
        
649
        
650
        private static Geometry removeOverShootFromLine(LineString line, double clusterTolerance){
651
                SnapLineStringSelfIntersectionChecker checker = 
652
                        new SnapLineStringSelfIntersectionChecker(line, clusterTolerance);
653
                if(checker.hasSelfIntersections()){
654
                        //Over shoot
655
                        Geometry[] geoms = checker.clean();
656
                        List<Geometry> linesWithoutOvershoot = new ArrayList<Geometry>();
657
                        for(int i = 0; i < geoms.length; i++){
658
                                LineString brokenLine = (LineString) geoms[i];
659
                                if(brokenLine.isClosed()){
660
                                        linesWithoutOvershoot.add(brokenLine);
661
                                }//if
662
                        }//for
663
                        if(linesWithoutOvershoot.size() == 1)
664
                                return linesWithoutOvershoot.get(0);
665
                        else{
666
                                Geometry[] solutionGeoms = new Geometry[linesWithoutOvershoot.size()];
667
                                linesWithoutOvershoot.toArray(solutionGeoms);
668
                                return GEOMETRY_FACTORY.createGeometryCollection(solutionGeoms);
669
                        }
670
                }else{//this line doesnt have overshoots
671
                        return line;
672
                }
673
        }
674
        
675
        public static Geometry removeOverShoot(Geometry jtsGeom, double clusterTolerance){
676
                List<Geometry> jtsProcessed = new ArrayList<Geometry>();
677
                
678
                List<Geometry> geom2process = new ArrayList<Geometry>();
679
                
680
                if(jtsGeom instanceof GeometryCollection){
681
                        GeometryCollection collection = (GeometryCollection) jtsGeom;
682
                        Geometry[] geometries = JtsUtil.extractGeometries(collection);
683
                        geom2process.addAll(Arrays.asList(geometries));
684
                }else if((jtsGeom instanceof Point)){
685
                        return jtsGeom;//this fix doesnt apply to point geometries. maybe launch an exception?
686
                }else{
687
                        geom2process.add(jtsGeom);
688
                }
689
                
690
                boolean allGeometriesPoint = true;
691
                for(int i = 0; i < geom2process.size(); i++){
692
                        Geometry geometry = geom2process.get(i);
693
                        if(!(geometry instanceof Point)){
694
                                allGeometriesPoint = false;
695
                                if(geometry instanceof LineString){
696
                                        LineString line = (LineString) geometry;
697
                                        Geometry correctedLine = removeOverShootFromLine(line, clusterTolerance);
698
                                        jtsProcessed.add(correctedLine);
699
                                }else if(geometry instanceof Polygon){
700
                                        Polygon polygon = (Polygon) geometry;
701
                                        
702
                                        Geometry correctedShell = removeOverShoot(polygon.getExteriorRing(), clusterTolerance);
703
                                        if(! (correctedShell instanceof LinearRing)){
704
                                                correctedShell = JtsUtil.toLinearRing((LineString) correctedShell);
705
                                        }
706
                                        LinearRing[] correctedHoles = new LinearRing[polygon.getNumInteriorRing()];
707
                                        for(int j = 0; j < polygon.getNumInteriorRing(); j++){
708
                                                LineString correctedHole = (LineString) removeOverShootFromLine(polygon.getInteriorRingN(j), clusterTolerance);
709
                                                if(! (correctedHole instanceof LinearRing)){
710
                                                        correctedHoles[j] = JtsUtil.toLinearRing((LineString) correctedHoles[j]);
711
                                                }else{
712
                                                        correctedHoles[j] = (LinearRing) correctedHole;
713
                                                }
714
                                        }//for j
715
                                        
716
                                        Polygon newPolygon = GEOMETRY_FACTORY.createPolygon((LinearRing) correctedShell, correctedHoles);
717
                                        jtsProcessed.add(newPolygon);
718
                                }//else
719
                        }
720
                }//for i
721
                
722
                if(allGeometriesPoint)
723
                        return jtsGeom;
724
                if(jtsProcessed.size() == 1)
725
                        return jtsProcessed.get(0);
726
                else{
727
                        Geometry[] geoms = new Geometry[jtsProcessed.size()];
728
                        jtsProcessed.toArray(geoms);
729
                        return GEOMETRY_FACTORY.createGeometryCollection(geoms);
730
                }
731
        }
732
        
733
        /**
734
         * Returns the coordinate resulting of extend segment the specified distance.
735
         * 
736
         * @param segment
737
         * @param distance
738
         * @return
739
         */
740
        public static Coordinate extentLineSegment(LineSegment segment, double distance){
741
                Coordinate solution = null;
742
                
743
                double segmentLenght = segment.getLength();
744
                Coordinate c0 = segment.getCoordinate(0);
745
                Coordinate c1 = segment.getCoordinate(1);
746
                double dx = c1.x - c0.x;
747
                double dy = c1.y - c0.y;
748
                
749
                double dx2 = dx * (segmentLenght + distance) / segmentLenght;
750
                double dy2 = dy * (segmentLenght + distance) / segmentLenght;
751
                
752
                solution = new Coordinate(c0.x + dx2, c0.y + dy2);
753
                return solution;
754
        }
755
        
756
        /**
757
         * Checks if the given 'a' linestring is connected to the given 'b' linestring.
758
         * 
759
         * Two linestrings are connected if they share and end point.
760
         * @param a
761
         * @param b
762
         * @return
763
         */
764
        public static boolean isConnected(LineString a, LineString b, double clusterTolerance){
765
                Coordinate start = a.getCoordinateN(0);
766
                Coordinate end = a.getCoordinateN(a.getNumPoints());
767
                
768
                if(isEndPoint(b, start, clusterTolerance) || isEndPoint(b, end, clusterTolerance))
769
                        return true;
770
                else
771
                        return false;
772
        }
773
        
774
        
775
        public static boolean isEndPoint(LineString a, Coordinate coord, double clusterTolerance){
776
                
777
                Coordinate start = a.getCoordinateN(0);
778
                Coordinate end = a.getCoordinateN(a.getNumPoints() - 1);
779
                
780
                if(SnapCGAlgorithms.snapEquals2D(start, coord, clusterTolerance) || SnapCGAlgorithms.snapEquals2D(end, coord, clusterTolerance) )
781
                        return true;
782
                else
783
                        return false;
784
        }
785
        
786
        
787
        public static Geometry split(Geometry geom, LineString line){
788
                return SplitStrategy.splitOp(geom, line);
789
        }
790
}