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 |
} |