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