Statistics
| Revision:

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

History | View | Annotate | Download (30.7 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 25601 2008-11-27 22:14:32Z 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.awt.geom.Rectangle2D;
57
import java.lang.reflect.Array;
58
import java.util.ArrayList;
59
import java.util.Arrays;
60
import java.util.Iterator;
61
import java.util.List;
62
import java.util.Stack;
63

    
64
import com.vividsolutions.jts.algorithm.CGAlgorithms;
65
import com.vividsolutions.jts.algorithms.SnapCGAlgorithms;
66
import com.vividsolutions.jts.geom.Coordinate;
67
import com.vividsolutions.jts.geom.Envelope;
68
import com.vividsolutions.jts.geom.Geometry;
69
import com.vividsolutions.jts.geom.GeometryCollection;
70
import com.vividsolutions.jts.geom.GeometryFactory;
71
import com.vividsolutions.jts.geom.LineSegment;
72
import com.vividsolutions.jts.geom.LineString;
73
import com.vividsolutions.jts.geom.LinearRing;
74
import com.vividsolutions.jts.geom.MultiLineString;
75
import com.vividsolutions.jts.geom.MultiPoint;
76
import com.vividsolutions.jts.geom.MultiPolygon;
77
import com.vividsolutions.jts.geom.Point;
78
import com.vividsolutions.jts.geom.Polygon;
79
import com.vividsolutions.jts.geom.PrecisionModel;
80
import com.vividsolutions.jts.geom.Triangle;
81
import com.vividsolutions.jts.geom.util.GeometryEditor;
82
import com.vividsolutions.jts.geom.util.LinearComponentExtracter;
83
import com.vividsolutions.jts.geom.util.PointExtracter;
84
import com.vividsolutions.jts.geom.util.PolygonExtracter;
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.jts.precision.EnhancedPrecisionOp;
89
import com.vividsolutions.jts.simplify.DouglasPeuckerSimplifier;
90
import com.vividsolutions.jts.simplify.TopologyPreservingSimplifier;
91
import com.vividsolutions.jump.util2.CoordinateArrays;
92

    
93
import es.axios.udig.ui.editingtools.internal.geometryoperations.split.SplitStrategy;
94

    
95
/**
96
 * Utility methods for JTS library use.
97
 * 
98
 * @author azabala
99
 * 
100
 */
101
public class JtsUtil {
102
        
103
        /**
104
         * Generalization factor to compute line generalization
105
         */
106
        public static Double GENERALIZATION_FACTOR = new Double(10d);
107
        
108
        public static  PrecisionModel GVSIG_PRECISION_MODEL = new PrecisionModel(10000);
109

    
110
        public static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory(
111
                        GVSIG_PRECISION_MODEL);
112

    
113
        public static final GeometryEditor GEOMETRY_EDITOR = new GeometryEditor(
114
                        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
170
                                        .createLinearRing(holeCoords);
171
                }
172
                return GEOMETRY_FACTORY.createPolygon(shell, holes);
173
        }
174

    
175
        /**
176
         * Returns an array of lenght equals to the number of parts of a polygon.
177
         * Each member of the array has a 'pointer' to the first point of each part
178
         * in the coordinates array of the polygon.
179
         * 
180
         * 
181
         * @param polygon
182
         * @see createPolygon(Coordinate[] coords, int[] indexOfParts)
183
         * @return
184
         */
185
        public static int[] getIndexOfParts(Polygon polygon) {
186
                int numParts = polygon.getNumInteriorRing() + 1;
187
                int[] indexOfParts = new int[numParts];
188
                indexOfParts[0] = 0;
189
                if (numParts > 1) {
190
                        indexOfParts[1] = polygon.getExteriorRing().getNumPoints();
191
                }
192
                if (numParts > 2) {
193
                        for (int i = 1; i < polygon.getNumInteriorRing(); i++) {
194
                                indexOfParts[i + 1] = indexOfParts[i]
195
                                                + polygon.getInteriorRingN(i).getNumPoints() + 1;
196
                        }
197
                }
198
                return indexOfParts;
199
        }
200

    
201
        public static MultiLineString convertToMultiLineString(
202
                        GeometryCollection geomCol) {
203
                List<LineString> lines = new ArrayList<LineString>();
204
                int numGeometries = geomCol.getNumGeometries();
205
                for (int i = 0; i < numGeometries; i++) {
206
                        Geometry geom = geomCol.getGeometryN(i);
207
                        if (geom instanceof LineString)
208
                                lines.add((LineString) geom);
209
                        else if (geom instanceof MultiLineString) {
210
                                MultiLineString multiLine = (MultiLineString) geom;
211
                                int numLines = multiLine.getNumGeometries();
212
                                for (int j = 0; j < numLines; j++) {
213
                                        lines.add((LineString) multiLine.getGeometryN(j));
214
                                }// j
215
                        }// else
216
                        else if (geom instanceof GeometryCollection) {
217
                                MultiLineString multiLine = convertToMultiLineString((GeometryCollection) geom);
218
                                int numLines = multiLine.getNumGeometries();
219
                                for (int j = 0; j < numLines; j++) {
220
                                        lines.add((LineString) multiLine.getGeometryN(j));
221
                                }// j
222
                        }// else
223
                }// for i
224
                LineString[] lineArray = new LineString[lines.size()];
225
                lines.toArray(lineArray);
226
                return GEOMETRY_FACTORY.createMultiLineString(lineArray);
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
310
                                                .createGeometryCollection(solutionArray);
311
                        return solution;
312
                }// else
313

    
314
                return null;
315
        }
316

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

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

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

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

    
378
                return false;
379
        }
380

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

    
397
        /**
398
         * This method is needed because call to LinearRing.reverse returns a
399
         * LineString,
400
         * 
401
         * @param ring
402
         * @return
403
         */
404
//        public static LinearRing reverse(LinearRing ring) {
405
//                CoordinateSequence seq = ring.getCoordinateSequence();
406
//                CoordinateSequences.reverse(seq);
407
//                LinearRing solution = GEOMETRY_FACTORY.createLinearRing(seq);
408
//                return solution;
409
//        }
410
//        
411
//        
412
        public static LineString reverse(LineString lineString){
413
                LineString solution = lineString.reverse();
414
                if(lineString instanceof LinearRing)
415
                        solution = toLinearRing(lineString);
416
                return solution;
417
                
418
        }
419
        
420
        public static Geometry douglasPeuckerSimplify(Geometry geometry, double distTolerance){
421
                return DouglasPeuckerSimplifier.simplify(geometry, distTolerance);
422
        }
423
        
424
        public static Geometry topologyPreservingSimplify(Geometry geometry, double distTolerance){
425
                return TopologyPreservingSimplifier.simplify(geometry, distTolerance);
426
        }
427

    
428
        public static Envelope toSnapRectangle(Coordinate coord,
429
                        double snapTolerance) {
430
                Envelope solution = null;
431

    
432
                double xmin = coord.x - snapTolerance;
433
                double xmax = coord.x + snapTolerance;
434
                double ymin = coord.y - snapTolerance;
435
                double ymax = coord.y + snapTolerance;
436
                solution = new Envelope(xmin, xmax, ymin, ymax);
437
                return solution;
438
        }
439
        
440
        public static Envelope rectangle2dToEnvelope(Rectangle2D rect){
441
                return new Envelope(rect.getMinX(),
442
                                                        rect.getMaxX(),
443
                                                        rect.getMinY(),
444
                                                        rect.getMaxY());
445
        }
446

    
447
        public static Geometry[] extractGeometries(GeometryCollection geomCol) {
448
                Geometry[] solution;
449
                ArrayList<Geometry> geometries = new ArrayList<Geometry>();
450
                Stack<Geometry> stack = new Stack<Geometry>();
451
                stack.add(geomCol);
452
                while (stack.size() > 0) {
453
                        Geometry geometry = (Geometry) stack.pop();
454
                        if (geometry instanceof GeometryCollection) {
455
                                GeometryCollection collection = (GeometryCollection) geometry;
456
                                for (int i = 0; i < collection.getNumGeometries(); i++) {
457
                                        stack.add(collection.getGeometryN(i));
458
                                }// for
459
                        } else {
460
                                geometries.add(geometry);
461
                        }
462
                }// while
463
                solution = new Geometry[geometries.size()];
464
                return geometries.toArray(solution);
465
        }
466

    
467
        // TODO REESCRIBIR ESTO CON GENERICS
468
        // /**
469
        // * Adapts a Geometry <code>geom</code> to another type of geometry given
470
        // the desired geometry
471
        // * class.
472
        // * <p>
473
        // * Currently implemented adaptations:
474
        // * <ul>
475
        // * <li>Point -> MultiPoint. Wraps the Point on a single part MultiPoint.
476
        // * <li>Polygon -> MultiPolygon. Wraps the Polygon on a single part
477
        // MultiPolygon.
478
        // * <li>LineString -> MultiLineString. Wraps the LineString on a single
479
        // part MultiLineString.
480
        // * <li>MultiLineString -> String. Succeeds if merging the parts result in
481
        // a single LineString,
482
        // * fails otherwise.
483
        // * <li>MultiPolygon -> Polygon. Succeeds if merging the parts result in a
484
        // single Polygon, fails
485
        // * otherwise.
486
        // * <li>* -> GeometryCollection
487
        // * </ul>
488
        // * </p>
489
        // * TODO: add more adaptations on an as needed basis
490
        // *
491
        // * @param inputGeom
492
        // * @param adaptTo
493
        // * @return a new Geometry adapted
494
        // * @throws IllegalArgumentException if <code>geom</code> cannot be adapted
495
        // as
496
        // * <code>adapTo</code>
497
        // */
498
        // public static Geometry adapt( final Geometry inputGeom, final Class< ?
499
        // extends Geometry> adaptTo ) {
500
        //
501
        // assert inputGeom != null : "inputGeom can't be null";
502
        // assert adaptTo != null : "adaptTo can't be null";;
503
        //
504
        // final Class<?> geomClass = inputGeom.getClass();
505
        //
506
        // if (Geometry.class.equals(adaptTo)) {
507
        // return inputGeom;
508
        // }
509
        //
510
        // final GeometryFactory gf = inputGeom.getFactory();
511
        //       
512
        // if (MultiPoint.class.equals(adaptTo) && Point.class.equals(geomClass)) {
513
        // return gf.createMultiPoint(new Point[]{(Point) inputGeom});
514
        // }
515
        //
516
        // if (Polygon.class.equals(adaptTo)) {
517
        // if (adaptTo.equals(geomClass)) {
518
        // return inputGeom;
519
        // }
520
        // Polygonizer polygonnizer = new Polygonizer();
521
        // polygonnizer.add(inputGeom);
522
        // Collection polys = polygonnizer.getPolygons();
523
        // Polygon[] polygons = new ArrayList<Polygon>(polys).toArray(new
524
        // Polygon[polys.size()]);
525
        //
526
        // if (polygons.length == 1) {
527
        // return polygons[0];
528
        // }
529
        // }
530
        //
531
        // if (MultiPolygon.class.equals(adaptTo)) {
532
        // if (adaptTo.equals(geomClass)) {
533
        // return inputGeom;
534
        // }
535
        // if (Polygon.class.equals(geomClass)) {
536
        // return gf.createMultiPolygon(new Polygon[]{(Polygon) inputGeom});
537
        // }
538
        // /*
539
        // * Polygonizer polygonnizer = new Polygonizer();
540
        // polygonnizer.add(inputGeom); Collection
541
        // * polys = polygonnizer.getPolygons(); Polygon[] polygons = new
542
        // ArrayList<Polygon>(polys).toArray(new
543
        // * Polygon[polys.size()]); if (MultiPolygon.class.equals(adaptTo)) {
544
        // return
545
        // * gf.createMultiPolygon(polygons); } if (polygons.length == 1) { return
546
        // polygons[0]; }
547
        // */
548
        // }
549
        //
550
        // if (GeometryCollection.class.equals(adaptTo)) {
551
        // return gf.createGeometryCollection(new Geometry[]{inputGeom});
552
        // }
553
        //
554
        // if (MultiLineString.class.equals(adaptTo) ||
555
        // LineString.class.equals(adaptTo)) {
556
        // LineMerger merger = new LineMerger();
557
        // merger.add(inputGeom);
558
        // Collection mergedLineStrings = merger.getMergedLineStrings();
559
        // ArrayList<LineString> lineList = new
560
        // ArrayList<LineString>(mergedLineStrings);
561
        // LineString[] lineStrings = lineList.toArray(new
562
        // LineString[mergedLineStrings.size()]);
563
        //
564
        // if (MultiLineString.class.equals(adaptTo)) {
565
        // MultiLineString line = gf.createMultiLineString(lineStrings);
566
        // return line;
567
        // }
568
        // if (lineStrings.length == 1) {
569
        // Geometry mergedResult = (Geometry) lineStrings[0];
570
        // return mergedResult;
571
        // }
572
        // }
573
        // if(Polygon.class.equals(adaptTo) &&
574
        // (MultiPolygon.class.equals(geomClass))){
575
        // // adapts multipolygon to polygon
576
        //            
577
        // assert inputGeom.getNumGeometries() == 1 : "the collection must have 1
578
        // element to adapt to Polygon";
579
        // return inputGeom.getGeometryN(1);
580
        //        
581
        // } else if(LineString.class.equals(adaptTo) &&
582
        // (MultiLineString.class.equals(geomClass))){
583
        // // adapts MultiLinestring to Linestring
584
        //            
585
        // assert inputGeom.getNumGeometries() == 1 : "the collection must have 1
586
        // element to adapt to Polygon";
587
        // return inputGeom.getGeometryN(1);
588
        // }
589
        //
590
        // final String msg =
591
        // MessageFormat.format(Messages.GeometryUtil_DonotKnowHowAdapt,
592
        // geomClass.getSimpleName(), adaptTo.getSimpleName());
593
        //
594
        // throw new IllegalArgumentException(msg);
595
        // }
596
        public static LineString[] extractLineStrings(Geometry g) {
597
                LineString[] solution = null;
598
                List<LineString> solutionList = new ArrayList<LineString>();
599
                if (g instanceof LineString)
600
                        solutionList.add((LineString) g);
601
                else if (g instanceof GeometryCollection) {
602
                        GeometryCollection geomCol = (GeometryCollection) g;
603
                        List lines = LinearComponentExtracter.getLines(geomCol);
604
                        solutionList.addAll(lines);
605
                }
606
                solution = new LineString[solutionList.size()];
607
                solutionList.toArray(solution);
608
                return solution;
609
        }
610

    
611
        public static Polygon[] extractPolygons(Geometry g) {
612
                Polygon[] solution = null;
613
                List<Polygon> solutionList = new ArrayList<Polygon>();
614
                if (g instanceof Polygon)
615
                        solutionList.add((Polygon) g);
616
                else if (g instanceof GeometryCollection) {
617
                        GeometryCollection geomCol = (GeometryCollection) g;
618
                        List polygons = PolygonExtracter.getPolygons(geomCol);
619
                        solutionList.addAll(polygons);
620
                }
621
                solution = new Polygon[solutionList.size()];
622
                solutionList.toArray(solution);
623
                return solution;
624
        }
625
        
626
        
627
        public static LineString[] extractRings(Polygon polygon){
628
                int numHoles = polygon.getNumInteriorRing();
629
                LineString[] solution = new LineString[numHoles + 1];
630
                solution[0] = polygon.getExteriorRing();
631
                for(int i = 0; i < numHoles; i++){
632
                        solution[i+1] = polygon.getInteriorRingN(i);
633
                }
634
                return solution;
635
        }
636

    
637
        public static Point[] extractPoints(Geometry g) {
638
                Point[] solution = null;
639
                List<Point> solutionList = new ArrayList<Point>();
640
                if (g instanceof Point)
641
                        solutionList.add((Point) g);
642
                else if (g instanceof GeometryCollection) {
643
                        GeometryCollection geomCol = (GeometryCollection) g;
644
                        List points = PointExtracter.getPoints(geomCol);
645
                        solutionList.addAll(points);
646
                }
647
                solution = new Point[solutionList.size()];
648
                solutionList.toArray(solution);
649
                return solution;
650
        }
651

    
652
        /**
653
         * Returns the segment of the specified geometry closest to the specified
654
         * coordinate.
655
         * 
656
         * This code is extracted from JTS.
657
         * 
658
         * @param geometry
659
         * @param target
660
         * @return
661
         */
662
        public static LineSegment segmentInRange(Geometry geometry,
663
                        Coordinate target, double tolerance) {
664
                LineSegment closest = null;
665
                List coordArrays = CoordinateArrays.toCoordinateArrays(geometry, false);
666
                for (Iterator i = coordArrays.iterator(); i.hasNext();) {
667
                        Coordinate[] coordinates = (Coordinate[]) i.next();
668
                        for (int j = 1; j < coordinates.length; j++) {
669
                                LineSegment candidate = new LineSegment(coordinates[j - 1],
670
                                                coordinates[j]);
671
                                if (candidate.distance(target) > tolerance) {
672
                                        continue;
673
                                }
674
                                if ((closest == null)
675
                                                || (candidate.distance(target) < closest
676
                                                                .distance(target))) {
677
                                        closest = candidate;
678
                                }
679
                        }
680
                }
681
                return closest;
682
        }
683

    
684
        public static LinearRing toLinearRing(LineString lineString) {
685
                Coordinate[] coords = lineString.getCoordinates();
686
                return GEOMETRY_FACTORY.createLinearRing(coords);
687
        }
688

    
689
        private static Geometry removeOverShootFromLine(LineString line,
690
                        double clusterTolerance) {
691
                SnapLineStringSelfIntersectionChecker checker = new SnapLineStringSelfIntersectionChecker(
692
                                line, clusterTolerance);
693
                if (checker.hasSelfIntersections()) {
694
                        // Over shoot
695
                        Geometry[] geoms = checker.clean();
696
                        List<Geometry> linesWithoutOvershoot = new ArrayList<Geometry>();
697
                        for (int i = 0; i < geoms.length; i++) {
698
                                LineString brokenLine = (LineString) geoms[i];
699
                                if(JtsUtil.isClosed(brokenLine, clusterTolerance)){
700
//                                if (brokenLine.isClosed()) {
701
                                        linesWithoutOvershoot.add(brokenLine);
702
                                }// if
703
                        }// for
704
                        if (linesWithoutOvershoot.size() == 1)
705
                                return linesWithoutOvershoot.get(0);
706
                        else {
707
                                Geometry[] solutionGeoms = new Geometry[linesWithoutOvershoot
708
                                                .size()];
709
                                linesWithoutOvershoot.toArray(solutionGeoms);
710
                                return GEOMETRY_FACTORY.createGeometryCollection(solutionGeoms);
711
                        }
712
                } else {// this line doesnt have overshoots
713
                        return line;
714
                }
715
        }
716

    
717
        public static Geometry removeOverShoot(Geometry jtsGeom,
718
                        double clusterTolerance) {
719
                List<Geometry> jtsProcessed = new ArrayList<Geometry>();
720

    
721
                List<Geometry> geom2process = new ArrayList<Geometry>();
722

    
723
                if (jtsGeom instanceof GeometryCollection) {
724
                        GeometryCollection collection = (GeometryCollection) jtsGeom;
725
                        Geometry[] geometries = JtsUtil.extractGeometries(collection);
726
                        geom2process.addAll(Arrays.asList(geometries));
727
                } else if ((jtsGeom instanceof Point)) {
728
                        return jtsGeom;// this fix doesnt apply to point geometries. maybe
729
                                                        // launch an exception?
730
                } else {
731
                        geom2process.add(jtsGeom);
732
                }
733

    
734
                boolean allGeometriesPoint = true;
735
                for (int i = 0; i < geom2process.size(); i++) {
736
                        Geometry geometry = geom2process.get(i);
737
                        if (!(geometry instanceof Point)) {
738
                                allGeometriesPoint = false;
739
                                if (geometry instanceof LineString) {
740
                                        LineString line = (LineString) geometry;
741
                                        Geometry correctedLine = removeOverShootFromLine(line,
742
                                                        clusterTolerance);
743
                                        jtsProcessed.add(correctedLine);
744
                                } else if (geometry instanceof Polygon) {
745
                                        Polygon polygon = (Polygon) geometry;
746

    
747
                                        Geometry correctedShell = removeOverShoot(polygon
748
                                                        .getExteriorRing(), clusterTolerance);
749
                                        if (!(correctedShell instanceof LinearRing)) {
750
                                                correctedShell = JtsUtil
751
                                                                .toLinearRing((LineString) correctedShell);
752
                                        }
753
                                        LinearRing[] correctedHoles = new LinearRing[polygon
754
                                                        .getNumInteriorRing()];
755
                                        for (int j = 0; j < polygon.getNumInteriorRing(); j++) {
756
                                                LineString correctedHole = (LineString) removeOverShootFromLine(
757
                                                                polygon.getInteriorRingN(j), clusterTolerance);
758
                                                if (!(correctedHole instanceof LinearRing)) {
759
                                                        correctedHoles[j] = JtsUtil
760
                                                                        .toLinearRing((LineString) correctedHoles[j]);
761
                                                } else {
762
                                                        correctedHoles[j] = (LinearRing) correctedHole;
763
                                                }
764
                                        }// for j
765

    
766
                                        Polygon newPolygon = GEOMETRY_FACTORY.createPolygon(
767
                                                        (LinearRing) correctedShell, correctedHoles);
768
                                        jtsProcessed.add(newPolygon);
769
                                }// else
770
                        }
771
                }// for i
772

    
773
                if (allGeometriesPoint)
774
                        return jtsGeom;
775
                if (jtsProcessed.size() == 1)
776
                        return jtsProcessed.get(0);
777
                else {
778
                        Geometry[] geoms = new Geometry[jtsProcessed.size()];
779
                        jtsProcessed.toArray(geoms);
780
                        return GEOMETRY_FACTORY.createGeometryCollection(geoms);
781
                }
782
        }
783

    
784
        /**
785
         * Returns the coordinate resulting of extend segment the specified
786
         * distance.
787
         * 
788
         * @param segment
789
         * @param distance
790
         * @return
791
         */
792
        public static Coordinate extentLineSegment(LineSegment segment,
793
                        double distance) {
794
                Coordinate solution = null;
795

    
796
                double segmentLenght = segment.getLength();
797
                Coordinate c0 = segment.getCoordinate(0);
798
                Coordinate c1 = segment.getCoordinate(1);
799
                double dx = c1.x - c0.x;
800
                double dy = c1.y - c0.y;
801

    
802
                double dx2 = dx * (segmentLenght + distance) / segmentLenght;
803
                double dy2 = dy * (segmentLenght + distance) / segmentLenght;
804

    
805
                solution = new Coordinate(c0.x + dx2, c0.y + dy2);
806
                return solution;
807
        }
808

    
809
        /**
810
         * Checks if the given 'a' linestring is connected to the given 'b'
811
         * linestring.
812
         * 
813
         * Two linestrings are connected if they share and end point.
814
         * 
815
         * @param a
816
         * @param b
817
         * @return
818
         */
819
        public static boolean isConnected(LineString a, LineString b,
820
                        double clusterTolerance) {
821
                Coordinate start = a.getCoordinateN(0);
822
                Coordinate end = a.getCoordinateN(a.getNumPoints());
823

    
824
                if (isEndPoint(b, start, clusterTolerance)
825
                                || isEndPoint(b, end, clusterTolerance))
826
                        return true;
827
                else
828
                        return false;
829
        }
830

    
831
        public static boolean isEndPoint(LineString a, Coordinate coord,
832
                        double clusterTolerance) {
833

    
834
                Coordinate start = a.getCoordinateN(0);
835
                Coordinate end = a.getCoordinateN(a.getNumPoints() - 1);
836

    
837
                if (SnapCGAlgorithms.snapEquals2D(start, coord, clusterTolerance)
838
                                || SnapCGAlgorithms.snapEquals2D(end, coord, clusterTolerance))
839
                        return true;
840
                else
841
                        return false;
842
        }
843

    
844
        public static Geometry split(Geometry geom, LineString line) {
845
                return SplitStrategy.splitOp(geom, line);
846
        }
847

    
848
        /**
849
         * Receives a collection of linear rings to form shells and a collection of
850
         * linear rings to form holes and returns derived polygons.
851
         * 
852
         * @param shells
853
         * @param holes
854
         * @return
855
         */
856
        public static Geometry buildPolygons(List<LinearRing> shells,
857
                        List<LinearRing> holes) {
858

    
859
                ArrayList<List<LinearRing>> holesForShells = new ArrayList<List<LinearRing>>(
860
                                shells.size());
861

    
862
                for (int i = 0; i < shells.size(); i++) {
863
                        holesForShells.add(new ArrayList<LinearRing>());
864
                }
865

    
866
                for (int i = 0; i < holes.size(); i++) {// foreach hole
867
                        LinearRing testRing = (LinearRing) holes.get(i);
868
                        LinearRing minShell = null;
869
                        Envelope minEnv = null;
870
                        Envelope testEnv = testRing.getEnvelopeInternal();
871
                        Coordinate testPt = testRing.getCoordinateN(0);
872
                        LinearRing tryRing = null;
873

    
874
                        // we look for the smallest ring that contains the hole
875
                        for (int j = 0; j < shells.size(); j++) {
876
                                tryRing = (LinearRing) shells.get(j);
877

    
878
                                Envelope tryEnv = tryRing.getEnvelopeInternal();
879

    
880
                                if (minShell != null) {
881
                                        minEnv = minShell.getEnvelopeInternal();
882
                                }
883

    
884
                                boolean isContained = false;
885
                                Coordinate[] coordList = tryRing.getCoordinates();
886

    
887
                                if (tryEnv.contains(testEnv)
888
                                                && (CGAlgorithms.isPointInRing(testPt, coordList) || (pointInList(
889
                                                                testPt, coordList)))) {
890
                                        isContained = true;
891
                                }
892

    
893
                                // check if this new containing ring is smaller than the current
894
                                // minimum ring
895
                                if (isContained) {
896
                                        if ((minShell == null) || minEnv.contains(tryEnv)) {
897
                                                minShell = tryRing;
898
                                        }
899
                                }
900
                        }
901

    
902
                        if (minShell == null) {//this hole is not contained by any shell
903

    
904
                                //we do the assumption that this hole is really a
905
                                // shell (polygon)
906
                                // whose point werent digitized in the right order
907
                                LinearRing newRing = (LinearRing) JtsUtil.reverse(testRing);
908
                                shells.add(newRing);
909
                                holesForShells.add(new ArrayList<LinearRing>());
910
                        } else {
911
                                holesForShells.get(shells.indexOf(minShell)).add(testRing);
912
                        }
913
                }// i
914

    
915
                Polygon[] polygons = new Polygon[shells.size()];
916

    
917
                for (int i = 0; i < shells.size(); i++) {
918
                        polygons[i] = GEOMETRY_FACTORY.createPolygon(shells.get(i),
919
                                        (LinearRing[]) (holesForShells.get(i)).toArray(new LinearRing[0]));
920
                }
921
                
922
                if(polygons.length == 1)
923
                        return polygons[0];
924
                else
925
                        return GEOMETRY_FACTORY.createMultiPolygon(polygons);
926
        }
927
        
928
        public static Envelope getBoundingBox(List<Geometry> geometries){
929
                Envelope  envelope = new Envelope();
930
            for (int i = 0; i < geometries.size(); i++) {
931
                Geometry geometry = geometries.get(i);
932
                envelope.expandToInclude(geometry.getEnvelopeInternal());
933
            }
934
            return envelope;
935
        }
936
        
937
        public static Coordinate getCircumCenter(Coordinate a, Coordinate b, Coordinate c){
938
                return Triangle.circumcentre(a, b, c);
939
        }
940

    
941
        public static Geometry difference(Geometry poly, List<Geometry> lineNeighbours){
942
                Geometry solution = null;
943
                List<Geometry> differences = new ArrayList<Geometry>();
944
                for(int i = 0; i < lineNeighbours.size(); i++){
945
                        Geometry neighbour = lineNeighbours.get(i);
946
                        if(poly.overlaps(neighbour))
947
                                differences.add(EnhancedPrecisionOp.difference(poly, neighbour ));
948
                }
949
                solution = GEOMETRY_FACTORY.createGeometryCollection(differences.toArray(new Geometry[0]));
950
                return solution;
951
        }
952
}