/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.geometry.isoonjts;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryCollection;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.apache.sis.geometry.GeneralDirectPosition;
import org.geotoolkit.geometry.isoonjts.spatialschema.JTSPositionFactory;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.aggregate.AbstractJTSAggregate;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.aggregate.JTSMultiCurve;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.aggregate.JTSMultiPoint;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.aggregate.JTSMultiPrimitive;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.aggregate.JTSMultiSurface;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.geometry.JTSGeometryFactory;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.geometry.JTSLineString;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.geometry.JTSPolygon;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.primitive.JTSCurve;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.primitive.JTSPrimitiveFactory;
import org.geotoolkit.geometry.jts.SRIDGenerator;
import org.apache.sis.referencing.CRS;
import org.opengis.util.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.geometry.DirectPosition;
import org.opengis.geometry.Envelope;
import org.opengis.geometry.Geometry;
import org.opengis.geometry.PositionFactory;
import org.opengis.geometry.coordinate.GeometryFactory;
import org.opengis.geometry.coordinate.LineString;
import org.opengis.geometry.coordinate.Polygon;
import org.opengis.geometry.primitive.Curve;
import org.opengis.geometry.primitive.PrimitiveFactory;
import org.opengis.geometry.primitive.Ring;
import org.opengis.geometry.primitive.SurfaceBoundary;
import org.opengis.geometry.coordinate.PointArray;
import org.opengis.geometry.coordinate.Position;
import org.apache.sis.util.logging.Logging;
/**
* Class with static methods to help the conversion process between JTS
* geometries and ISO geometries.
* @module
*/
public final class JTSUtils {
/**
* Common instance of GEOMETRY_FACTORY with the default JTS precision model
* that can be used to make new geometries.
*/
public static final com.vividsolutions.jts.geom.GeometryFactory GEOMETRY_FACTORY = new com.vividsolutions.jts.geom.GeometryFactory();
/**
* This class has only static methods, so we make the constructor private
* to prevent instantiation.
*/
private JTSUtils() {
}
/**
* Creates a 19107 primitive geometry from the given JTS geometry.
*/
public static Geometry toISO(final com.vividsolutions.jts.geom.Geometry jtsGeom,
CoordinateReferenceSystem crs) {
if (jtsGeom == null) {
return null;
}
if(crs == null){
//try to extract the crs from the srid
final int srid = jtsGeom.getSRID();
if(srid != 0){
final String strCRS = SRIDGenerator.toSRS(srid, SRIDGenerator.Version.V1);
try {
crs = CRS.forCode(strCRS);
} catch (FactoryException ex) {
Logging.getLogger("org.geotoolkit.geometry.isoonjts").log(Level.SEVERE, null, ex);
}
}
}
//TODO use factory finder when primitive factory and geometry factory are ready.
final PrimitiveFactory pf = new JTSPrimitiveFactory(crs);//FactoryFinder.getPrimitiveFactory(hints);
final GeometryFactory gf = new JTSGeometryFactory(crs); //FactoryFinder.getGeometryFactory(hints);
if (jtsGeom instanceof com.vividsolutions.jts.geom.Point) {
com.vividsolutions.jts.geom.Point candidate = (com.vividsolutions.jts.geom.Point) jtsGeom;
DirectPosition dp = pointToDirectPosition(candidate, crs);
return pf.createPoint(dp);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.LineString) {
com.vividsolutions.jts.geom.LineString candidate = (com.vividsolutions.jts.geom.LineString) jtsGeom;
LineString ls = gf.createLineString(new ArrayList<Position>());
PointArray pointList = ls.getControlPoints();
for (int i = 0, n = candidate.getNumPoints(); i < n; i++) {
pointList.add(coordinateToDirectPosition(candidate.getCoordinateN(i), crs));
}
return (JTSLineString)ls;
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.LinearRing) {
return linearRingToRing((com.vividsolutions.jts.geom.LinearRing) jtsGeom, crs);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.Polygon) {
com.vividsolutions.jts.geom.Polygon jtsPolygon = (com.vividsolutions.jts.geom.Polygon) jtsGeom;
Ring externalRing = linearRingToRing(
(com.vividsolutions.jts.geom.LinearRing) jtsPolygon.getExteriorRing(),
crs);
ArrayList internalRings = new ArrayList();
for (int i = 0, n = jtsPolygon.getNumInteriorRing(); i < n; i++) {
internalRings.add(linearRingToRing(
(com.vividsolutions.jts.geom.LinearRing) jtsPolygon.getInteriorRingN(i),
crs));
}
SurfaceBoundary boundary = pf.createSurfaceBoundary(externalRing, internalRings);
Polygon polygon = gf.createPolygon(boundary);
return (JTSPolygon) polygon;
/*ArrayList<Polygon> patches = new ArrayList<Polygon>();
patches.add(polygon);
PolyhedralSurface result = gf.createPolyhedralSurface(patches);
return result;*/
} else if (jtsGeom instanceof GeometryCollection) {
com.vividsolutions.jts.geom.GeometryCollection jtsCollection = (com.vividsolutions.jts.geom.GeometryCollection) jtsGeom;
boolean multiPoint = true;
boolean multiCurve = true;
boolean multiSurface = true;
for (int i = 0, n = jtsCollection.getNumGeometries(); i < n; i++) {
if (!(jtsCollection.getGeometryN(i) instanceof com.vividsolutions.jts.geom.Point)) {
multiPoint = false;
}
if (!(jtsCollection.getGeometryN(i) instanceof com.vividsolutions.jts.geom.LineString)) {
multiCurve = false;
}
if (!(jtsCollection.getGeometryN(i) instanceof com.vividsolutions.jts.geom.Polygon)) {
multiSurface = false;
}
}
AbstractJTSAggregate result;
if (multiPoint) {
result = new JTSMultiPoint(crs);
Set elements = result.getElements();
for (int i = 0, n = jtsCollection.getNumGeometries(); i < n; i++) {
//result.getElements().add(jtsToGo1(jtsCollection.getGeometryN(i), crs));
elements.add(toISO(jtsCollection.getGeometryN(i), crs));
}
} else if (multiCurve) {
result = new JTSMultiCurve(crs);
Set elements = result.getElements();
for (int i = 0, n = jtsCollection.getNumGeometries(); i < n; i++) {
//result.getElements().add(jtsToGo1(jtsCollection.getGeometryN(i), crs));
Geometry element = toISO(jtsCollection.getGeometryN(i), crs);
if (element instanceof JTSLineString) {
JTSCurve curve = new JTSCurve(crs);
curve.getSegments().add((JTSLineString) element);
element = curve;
}
elements.add(element);
}
} else if (multiSurface) {
result = new JTSMultiSurface(crs);
Set elements = result.getElements();
for (int i = 0, n = jtsCollection.getNumGeometries(); i < n; i++) {
//result.getElements().add(jtsToGo1(jtsCollection.getGeometryN(i), crs));
elements.add(toISO(jtsCollection.getGeometryN(i), crs));
}
} else {
result = new JTSMultiPrimitive();
Set elements = result.getElements();
for (int i = 0, n = jtsCollection.getNumGeometries(); i < n; i++) {
//result.getElements().add(jtsToGo1(jtsCollection.getGeometryN(i), crs));
elements.add(toISO(jtsCollection.getGeometryN(i), crs));
}
}
return result;
} else {
throw new IllegalArgumentException("Unsupported geometry type: " + jtsGeom.getGeometryType());
}
}
/**
* Converts a DirectPosition to a JTS Coordinate. Returns a newly
* instantiated Coordinate object.
*/
public static com.vividsolutions.jts.geom.Coordinate directPositionToCoordinate(final DirectPosition dp) {
double x = Double.NaN, y = Double.NaN, z = Double.NaN;
final int d = dp.getDimension();
if (d >= 1) {
x = dp.getOrdinate(0);
if (d >= 2) {
y = dp.getOrdinate(1);
if (d >= 3) {
z = dp.getOrdinate(2);
}
}
}
return new com.vividsolutions.jts.geom.Coordinate(x, y, z);
}
/**
* Sets the coordinate values of an existing JTS Coordinate by extracting
* values from a DirectPosition. If the dimension of the DirectPosition is
* less than three, then the unused ordinates of the Coordinate are set to
* Double.NaN.
*/
public static void directPositionToCoordinate(final DirectPosition dp, final com.vividsolutions.jts.geom.Coordinate result) {
final int d = dp.getDimension();
if (d >= 1) {
result.x = dp.getOrdinate(0);
if (d >= 2) {
result.y = dp.getOrdinate(1);
if (d >= 3) {
result.z = dp.getOrdinate(3);
} else {
result.z = Double.NaN;
}
} else {
result.y = result.z = Double.NaN;
}
} else {
// I can't imagine a DirectPosition with dimension zero, but it
// can't hurt to have code to handle that case...
result.x = result.y = result.z = Double.NaN;
}
}
/**
* Converts a DirectPosition to a JTS Point primitive. Returns a newly
* instantiated Point object that was created using the default
* GeometryFactory instance.
*/
public static com.vividsolutions.jts.geom.Point directPositionToPoint(final DirectPosition dp) {
return GEOMETRY_FACTORY.createPoint(directPositionToCoordinate(dp));
}
/**
* Converts a JTS Coordinate to a DirectPosition with the given CRS.
*/
public static DirectPosition coordinateToDirectPosition(final com.vividsolutions.jts.geom.Coordinate c,
final CoordinateReferenceSystem crs) {
PositionFactory pf = new JTSPositionFactory(crs);
double[] vertices;
if (crs == null) {
vertices = new double[3];
vertices[0] = c.x;
vertices[1] = c.y;
vertices[2] = c.z;
} else {
vertices = new double[crs.getCoordinateSystem().getDimension()];
if(vertices.length > 0){
vertices[0] = c.x;
if(vertices.length > 1){
vertices[1] = c.y;
if(vertices.length > 2){
vertices[2] = c.z;
}
}
}
}
return pf.createDirectPosition(vertices);
}
/**
* Extracts the values of a JTS coordinate into an existing DirectPosition
* object.
*/
public static void coordinateToDirectPosition(final com.vividsolutions.jts.geom.Coordinate c,
final DirectPosition result) {
// Get the CRS so we can figure out the dimension of the result.
CoordinateReferenceSystem crs = result.getCoordinateReferenceSystem();
int d;
if (crs != null) {
d = crs.getCoordinateSystem().getDimension();
} else {
// If the result DP has no CRS, then we just assume 2 dimensions.
// This could result in IndexOutOfBounds exceptions if the DP has
// fewer than 2 coordinates.
d = 2;
}
final CoordinateSystem cs = crs.getCoordinateSystem();
if (d >= 1) {
int xIndex = GeometryUtils.getDirectedAxisIndex(cs, AxisDirection.EAST);
result.setOrdinate(xIndex, c.x);//0
if (d >= 2) {
int yIndex = GeometryUtils.getDirectedAxisIndex(cs, AxisDirection.NORTH);
result.setOrdinate(yIndex, c.y);//1
if (d >= 3) {
int zIndex = GeometryUtils.getDirectedAxisIndex(cs, AxisDirection.UP);
result.setOrdinate(zIndex, c.z);//2
// If d > 3, then the remaining ordinates of the DP are
// (so far) left with their original values. So we init
// them to zero here.
if (d > 3) {
for (int i = 3; i < d; i++) {
result.setOrdinate(i, 0.0);
}
}
}
}
}
}
/**
* Converts a JTS Point to a DirectPosition with the given CRS.
*/
public static DirectPosition pointToDirectPosition(final com.vividsolutions.jts.geom.Point p,
final CoordinateReferenceSystem crs) {
return coordinateToDirectPosition(p.getCoordinate(), crs);
}
public static Ring linearRingToRing(final com.vividsolutions.jts.geom.LineString jtsLinearRing,
final CoordinateReferenceSystem crs) {
int numPoints = jtsLinearRing.getNumPoints();
if (numPoints != 0 && !jtsLinearRing.getCoordinateN(0).equals(jtsLinearRing.getCoordinateN(numPoints - 1))) {
throw new IllegalArgumentException("LineString must be a ring");
}
PrimitiveFactory pf = new JTSPrimitiveFactory(crs); //FactoryFinder.getPrimitiveFactory(hints);
GeometryFactory gf = new JTSGeometryFactory(crs); //FactoryFinder.getGeometryFactory(hints);
LineString ls = gf.createLineString(new ArrayList());
List pointList = ls.getControlPoints().positions();
for (int i = 0; i < numPoints; i++) {
pointList.add(coordinateToDirectPosition(jtsLinearRing.getCoordinateN(i), crs));
}
Curve curve = pf.createCurve(new ArrayList());
// Cast below can be removed when Types will be allowed to abandon Java 1.4 support.
((List) curve.getSegments()).add(ls);
Ring result = pf.createRing(new ArrayList());
// Cast below can be removed when Types will be allowed to abandon Java 1.4 support.
((List) result.getGenerators()).add(curve);
return result;
}
/**
* Computes the distance between two JTS geometries. Unfortunately, JTS's
* methods do not allow for either parameter to be a collection. So we have
* to implement the logic of dealing with collection geometries separately.
*/
public static double distance(final com.vividsolutions.jts.geom.Geometry g1,
final com.vividsolutions.jts.geom.Geometry g2) {
if (g1 instanceof com.vividsolutions.jts.geom.GeometryCollection) {
double minDistance = Double.POSITIVE_INFINITY;
com.vividsolutions.jts.geom.GeometryCollection gc1 =
(com.vividsolutions.jts.geom.GeometryCollection) g1;
int n = gc1.getNumGeometries();
for (int i = 0; i < n; i++) {
double d = distance(gc1.getGeometryN(i), g2);
if (d < minDistance) {
minDistance = d;
}
}
return minDistance;
} else if (g2 instanceof com.vividsolutions.jts.geom.GeometryCollection) {
double minDistance = Double.POSITIVE_INFINITY;
com.vividsolutions.jts.geom.GeometryCollection gc2 =
(com.vividsolutions.jts.geom.GeometryCollection) g2;
int n = gc2.getNumGeometries();
for (int i = 0; i < n; i++) {
// This call will result in a redundant check of
// g1 instanceof GeometryCollection. Maybe we oughta fix that
// somehow.
double d = distance(g1, gc2.getGeometryN(i));
if (d < minDistance) {
minDistance = d;
}
}
return minDistance;
} else {
return g1.distance(g2);
}
}
/**
* Returns the union of the two geometries. In the case of primitive
* geometries, this simply delegates to the JTS method. In the case of
* aggregates, creates an aggregate containing all the parts of both.
*/
public static com.vividsolutions.jts.geom.Geometry union(
final com.vividsolutions.jts.geom.Geometry g1,
final com.vividsolutions.jts.geom.Geometry g2) {
return null;
}
public static com.vividsolutions.jts.geom.Geometry intersection(
final com.vividsolutions.jts.geom.Geometry g1,
final com.vividsolutions.jts.geom.Geometry g2) {
return null;
}
public static com.vividsolutions.jts.geom.Geometry difference(
final com.vividsolutions.jts.geom.Geometry g1,
final com.vividsolutions.jts.geom.Geometry g2) {
return null;
}
public static com.vividsolutions.jts.geom.Geometry symmetricDifference(
final com.vividsolutions.jts.geom.Geometry g1,
final com.vividsolutions.jts.geom.Geometry g2) {
return null;
}
public static boolean contains(
final com.vividsolutions.jts.geom.Geometry g1,
final com.vividsolutions.jts.geom.Geometry g2) {
return false;
}
public static boolean equals(
final com.vividsolutions.jts.geom.Geometry g1,
final com.vividsolutions.jts.geom.Geometry g2) {
return false;
}
/**
* Returns true if the two given geometries intersect. In the case of
* primitive geometries, this simply delegates to the JTS method. In the
* case of Aggregates, loops over pairs of children looking for
* intersections.
*/
public static boolean intersects(
final com.vividsolutions.jts.geom.Geometry g1,
final com.vividsolutions.jts.geom.Geometry g2) {
if (g1 instanceof com.vividsolutions.jts.geom.GeometryCollection) {
com.vividsolutions.jts.geom.GeometryCollection gc1 =
(com.vividsolutions.jts.geom.GeometryCollection) g1;
int n = gc1.getNumGeometries();
for (int i = 0; i < n; i++) {
com.vividsolutions.jts.geom.Geometry g = gc1.getGeometryN(i);
if (intersects(g, g2)) {
return true;
}
}
return false;
} else if (g2 instanceof com.vividsolutions.jts.geom.GeometryCollection) {
com.vividsolutions.jts.geom.GeometryCollection gc2 =
(com.vividsolutions.jts.geom.GeometryCollection) g2;
int n = gc2.getNumGeometries();
for (int i = 0; i < n; i++) {
com.vividsolutions.jts.geom.Geometry g = gc2.getGeometryN(i);
if (intersects(g1, g)) {
return true;
}
}
return false;
} else {
return g1.intersects(g2);
}
}
/**
* Creates a JTS LineString from the four corners of the specified Envelope.
* @param envelope The Envelope to be converted
* @return A JTS Geometry
*/
public static com.vividsolutions.jts.geom.Geometry getEnvelopeGeometry(
final Envelope envelope) {
// PENDING(NL): Add code to check for CRS compatibility
// Must consider possibility that this is a pixel envelope
// rather than geo coordinate; only way to be sure is to check Units
DirectPosition topCorner = envelope.getUpperCorner();
DirectPosition botCorner = envelope.getLowerCorner();
DirectPosition topLeft = new GeneralDirectPosition(topCorner);
DirectPosition botRight = new GeneralDirectPosition(botCorner);
//Again, making assumption we can ignore this LatLonAlt stuff - colin
/*
// If the Envelope coordinates are LatLonAlts,
// calling setOrdinate causes Error-level logging messages,
// including a stack trace,
// though it still works. But in principal we should
// call get/setLat and get/setLon instead if we have LatLonAlts
if (topLeft instanceof LatLonAlt && botRight instanceof LatLonAlt) {
((LatLonAlt) topLeft).setLon(((LatLonAlt)
botCorner).getLon(Units.DEGREE), Units.DEGREE);
((LatLonAlt) botRight).setLon(((LatLonAlt)
topCorner).getLon(Units.DEGREE), Units.DEGREE);
} else {*/
topLeft.setOrdinate(1, botCorner.getOrdinate(1));
botRight.setOrdinate(1, topCorner.getOrdinate(1));
//}//end of else statment associated with above LatLongAlt stuff
// Create a JTS Envelope
Coordinate jtsTopRight =
JTSUtils.directPositionToCoordinate(topCorner);
Coordinate jtsTopLeft =
JTSUtils.directPositionToCoordinate(topLeft);
Coordinate jtsBotLeft =
JTSUtils.directPositionToCoordinate(botCorner);
Coordinate jtsBotRight =
JTSUtils.directPositionToCoordinate(botRight);
com.vividsolutions.jts.geom.Geometry jtsEnv = GEOMETRY_FACTORY.createLineString(
new Coordinate[]{jtsTopLeft, jtsTopRight, jtsBotRight, jtsBotLeft,
jtsTopLeft}).getEnvelope();
return jtsEnv;
}
}