/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2010-2011, Geomatys
*
* 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* 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.gml;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import java.util.ArrayList;
import java.util.List;
import org.apache.sis.geometry.DirectPosition2D;
import org.geotoolkit.geometry.jts.JTS;
import org.geotoolkit.gml.xml.AbstractGeometricAggregate;
import org.geotoolkit.gml.xml.AbstractGeometry;
import org.geotoolkit.gml.xml.AbstractRing;
import org.geotoolkit.metadata.Citations;
import org.apache.sis.referencing.IdentifiedObjects;
import static org.geotoolkit.gml.xml.GMLXmlFactory.*;
import org.opengis.geometry.DirectPosition;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.util.FactoryException;
/**
* Set of converters from JTS Geometry to GML Geometry.
*
* @author Quentin Boileau (Geomatys).
* @module
*/
public final class JTStoGeometry {
/**
* Private constructor.
*/
private JTStoGeometry(){}
/**
* Transform A JTS geometry into GML geometry
*
* @param gmlVersion The output gml version. (actually 3.1.1 or 3.2.1 are avalable)
* @param jts The JTS geometry to convert.
*
* @return AbstractGeometry gml geometry.
*
* @throws org.opengis.referencing.NoSuchAuthorityCodeException - if {@link CoordinateReferenceSystem crs}
* can't be extracted from JTS geometry or can't be injected into the {@link AbstractGeometry}.
* @throws org.opengis.util.FactoryException - if {@link CoordinateReferenceSystem crs} can't be extracted from JTS
* geometry or can't be injected into the {@link AbstractGeometry}.
*/
public static AbstractGeometry toGML(final String gmlVersion, final Geometry jts) throws NoSuchAuthorityCodeException, FactoryException {
final CoordinateReferenceSystem crs = JTS.findCoordinateReferenceSystem(jts);
return toGML(gmlVersion, jts, crs);
}
/**
* Transform A JTS geometry into GML geometry
*
* @param gmlVersion The output gml version. (actually 3.1.1 or 3.2.1 are avalable)
* @param jts The JTS geometry to convert.
* @param crs
*
* @return AbstractGeometry gml geometry.
*
* @throws org.opengis.referencing.NoSuchAuthorityCodeException - if {@link CoordinateReferenceSystem crs}
* can't be extracted from JTS geometry or can't be injected into the {@link AbstractGeometry}.
* @throws org.opengis.util.FactoryException - if {@link CoordinateReferenceSystem crs} can't be extracted from JTS
* geometry or can't be injected into the {@link AbstractGeometry}.
*/
public static AbstractGeometry toGML(final String gmlVersion, final Geometry jts, CoordinateReferenceSystem crs) throws NoSuchAuthorityCodeException, FactoryException {
if (crs == null) {
crs = JTS.findCoordinateReferenceSystem(jts);
}
if (jts instanceof Point) {
return toGML(gmlVersion, (Point) jts, crs);
} else if (jts instanceof LineString) {
return toGML(gmlVersion,(LineString) jts, crs);
} else if (jts instanceof Polygon) {
return toGML(gmlVersion,(Polygon) jts, crs);
} else if (jts instanceof LinearRing) {
return toGML(gmlVersion,(LinearRing) jts, crs);
} else if (jts instanceof GeometryCollection) {
return toGML(gmlVersion,(GeometryCollection) jts, crs);
} else if (jts instanceof MultiPoint) {
return toGML(gmlVersion,(MultiPoint) jts, crs);
} else if (jts instanceof MultiLineString) {
return toGML(gmlVersion,(MultiLineString) jts, crs);
} else if (jts instanceof MultiPolygon) {
return toGML(gmlVersion,(MultiPolygon) jts, crs);
} else {
throw new IllegalArgumentException("Unsupported geometry type : " + jts);
}
}
/**
* Try to convert a JTS GeometryCollection to a GML AbstractGeometricAggregateType
*
* @param jtsGeom {@link GeometryCollection collection}
* @param crs Coordinate Reference System
* @return AbstractGeometricAggregateType
*
* @throws org.opengis.referencing.NoSuchAuthorityCodeException - if {@link CoordinateReferenceSystem crs} can't be
* injected into the {@link AbstractGeometry}.
* @throws org.opengis.util.FactoryException - if {@link CoordinateReferenceSystem crs} can't be injected into the
* {@link AbstractGeometry}.
*/
public static AbstractGeometricAggregate toGML(final String gmlVersion, final GeometryCollection jtsGeom, final CoordinateReferenceSystem crs)
throws NoSuchAuthorityCodeException, FactoryException {
//Test if it's a 2D Geometry from CRS
isValideGeometry(crs);
//Get th e class of the first geometry in the GeometryCollection
Class buffer = null;
if (jtsGeom.getNumGeometries() > 0) {
final Geometry geom = jtsGeom.getGeometryN(0);
if (geom.getClass().isAssignableFrom(Polygon.class) || geom.getClass().isAssignableFrom(Point.class)
|| geom.getClass().isAssignableFrom(LineString.class)) {
buffer = geom.getClass();
}
}
//Verify if all other geometries contained by the GeometryCollection is from the same class
boolean isSupported = true;
for (int i = 0; i < jtsGeom.getNumGeometries(); i++) {
if (!(jtsGeom.getGeometryN(i).getClass().isAssignableFrom(buffer))) {
isSupported = false;
break;
}
}
if (isSupported) {
final GeometryFactory gf = new GeometryFactory();
//Convert to a MultiPoint
if (buffer.equals(Point.class)) {
List<Point> ptList = new ArrayList<>();
for (int i = 0; i < jtsGeom.getNumGeometries(); i++) {
ptList.add((Point) jtsGeom.getGeometryN(i));
}
final MultiPoint mutlPt = gf.createMultiPoint(ptList.toArray(new Point[ptList.size()]));
JTS.setCRS(mutlPt, crs);
return toGML(gmlVersion, mutlPt, crs);
//Convert to a MultiLineString
} else if (buffer.equals(LineString.class)) {
List<LineString> lsList = new ArrayList<>();
for (int i = 0; i < jtsGeom.getNumGeometries(); i++) {
lsList.add((LineString) jtsGeom.getGeometryN(i));
}
final MultiLineString multLineString = gf.createMultiLineString(lsList.toArray(new LineString[lsList.size()]));
JTS.setCRS(multLineString, crs);
return toGML(gmlVersion, multLineString, crs);
} else if (buffer.equals(Polygon.class)) {
List<Polygon> polyList = new ArrayList<>();
for (int i = 0; i < jtsGeom.getNumGeometries(); i++) {
polyList.add((Polygon) jtsGeom.getGeometryN(i));
}
final MultiPolygon multPoly = gf.createMultiPolygon(polyList.toArray(new Polygon[polyList.size()]));
JTS.setCRS(multPoly, crs);
return toGML(gmlVersion, multPoly, crs);
} else {
throw new IllegalArgumentException("Unssupported geometry type : " + jtsGeom);
}
} else {
throw new IllegalArgumentException("Unssupported geometry type : " + jtsGeom);
}
}
/**
* Convert JTS MultiPoint to GML MultiPointType
* @param jtsGeom
* @param crs Coordinate Reference System
* @return MultiPointType
*
* @throws org.opengis.referencing.NoSuchAuthorityCodeException - if {@link CoordinateReferenceSystem crs}
* can't be injected into the {@link AbstractGeometry}.
* @throws org.opengis.util.FactoryException - if {@link CoordinateReferenceSystem crs} can't be injected into the
* {@link AbstractGeometry}.
*/
public static org.geotoolkit.gml.xml.MultiPoint toGML(final String gmlVersion, final MultiPoint jtsGeom, final CoordinateReferenceSystem crs)
throws NoSuchAuthorityCodeException, FactoryException {
//Test if it's a 2D Geometry from CRS
isValideGeometry(crs);
final List<org.geotoolkit.gml.xml.Point> pointList = new ArrayList<>();
for (int i = 0; i < jtsGeom.getNumGeometries(); i++) {
pointList.add(toGML(gmlVersion, (Point) jtsGeom.getGeometryN(i), crs));
}
final String srs = getSRS(crs);
return buildMultiPoint(gmlVersion, pointList, srs);
}
/**
* Convert JTS MultiLineString to GML MultiLineStringType
* @param jtsGeom
* @param crs Coordinate Reference System
* @return MultiLineStringType
*
* @throws org.opengis.referencing.NoSuchAuthorityCodeException - if {@link CoordinateReferenceSystem crs}
* can't be injected into the {@link AbstractGeometry}.
* @throws org.opengis.util.FactoryException - if {@link CoordinateReferenceSystem crs} can't be injected into the
* {@link AbstractGeometry}.
*/
public static org.geotoolkit.gml.xml.AbstractGeometricAggregate toGML(final String gmlVersion, final MultiLineString jtsGeom, final CoordinateReferenceSystem crs)
throws NoSuchAuthorityCodeException, FactoryException {
//Test if it's a 2D Geometry from CRS
isValideGeometry(crs);
final List<org.geotoolkit.gml.xml.LineString> lineList = new ArrayList<>();
for (int i = 0; i < jtsGeom.getNumGeometries(); i++) {
lineList.add(toGML(gmlVersion, (LineString) jtsGeom.getGeometryN(i), crs));
}
final String srs = getSRS(crs);
return buildMultiLineString(gmlVersion, lineList, srs);
}
/**
* Convert JTS MultiPolygon to GML MultiPolygonType
* @param jtsGeom
* @param crs Coordinate Reference System
* @return MultiPolygonType
*
* @throws org.opengis.referencing.NoSuchAuthorityCodeException - if {@link CoordinateReferenceSystem crs}
* can't be injected into the {@link AbstractGeometry}.
* @throws org.opengis.util.FactoryException - if {@link CoordinateReferenceSystem crs} can't be injected into the
* {@link AbstractGeometry}.
*/
public static org.geotoolkit.gml.xml.AbstractGeometricAggregate toGML(final String gmlVersion, final MultiPolygon jtsGeom, final CoordinateReferenceSystem crs)
throws NoSuchAuthorityCodeException, FactoryException {
//Test if it's a 2D Geometry from CRS
isValideGeometry(crs);
final List<org.geotoolkit.gml.xml.Polygon> polyList = new ArrayList<>();
for (int i = 0; i < jtsGeom.getNumGeometries(); i++) {
polyList.add(toGML(gmlVersion, (Polygon) jtsGeom.getGeometryN(i), crs));
}
final String srs = getSRS(crs);
return buildMultiPolygon(gmlVersion, polyList, srs);
}
/**
* Convert JTS Polygon to GML PolygonType
* @param jtsGeom
* @param crs Coordinate Reference System
* @return PolygonType
*
* @throws org.opengis.referencing.NoSuchAuthorityCodeException - if {@link CoordinateReferenceSystem crs}
* can't be injected into the {@link AbstractGeometry}.
* @throws org.opengis.util.FactoryException - if {@link CoordinateReferenceSystem crs} can't be injected into the
* {@link AbstractGeometry}.
*/
public static org.geotoolkit.gml.xml.Polygon toGML(final String gmlVersion, final Polygon jtsGeom, final CoordinateReferenceSystem crs)
throws NoSuchAuthorityCodeException, FactoryException {
//Test if it's a 2D Geometry from CRS
isValideGeometry(crs);
//get exterior ring
final AbstractRing gmlExterior = toGML(gmlVersion, (LinearRing) jtsGeom.getExteriorRing(), crs);
//get interiors ring
final List<AbstractRing> gmlInterior = new ArrayList<>();
for (int i = 0; i < jtsGeom.getNumInteriorRing(); i++) {
gmlInterior.add(toGML(gmlVersion, (LinearRing) jtsGeom.getInteriorRingN(i), crs));
}
return buildPolygon(gmlVersion, gmlExterior, gmlInterior, getSRS(crs));
}
/**
* Convert JTS LineString to GML LineStringType
* @param jtsGeom
* @param crs Coordinate Reference System
* @return LineStringType
*
* @throws org.opengis.referencing.NoSuchAuthorityCodeException - if {@link CoordinateReferenceSystem crs}
* can't be injected into the {@link AbstractGeometry}.
* @throws org.opengis.util.FactoryException - if {@link CoordinateReferenceSystem crs} can't be injected into the
* {@link AbstractGeometry}.
*/
public static org.geotoolkit.gml.xml.LineString toGML(final String gmlVersion, final LineString jtsGeom, final CoordinateReferenceSystem crs)
throws NoSuchAuthorityCodeException, FactoryException {
//Test if it's a 2D Geometry from CRS
isValideGeometry(crs);
final Coordinate[] jtsCoord = jtsGeom.getCoordinates();
final List<DirectPosition> dpList = new ArrayList<>();
for (Coordinate c : jtsCoord) {
dpList.add(coordinateToDirectPosition(c, crs));
}
final String srsName = getSRS(crs);
final org.geotoolkit.gml.xml.LineString gmlString = buildLineString(gmlVersion, null, srsName, dpList);
gmlString.setSrsName(getSRS(crs));
return gmlString;
}
/**
* Convert JTS LinearRing to GML LinearRingType
* @param jtsGeom
* @param crs Coordinate Reference System
* @return LinearRingType
*
* @throws org.opengis.referencing.NoSuchAuthorityCodeException - if {@link CoordinateReferenceSystem crs}
* can't be injected into the {@link AbstractGeometry}.
* @throws org.opengis.util.FactoryException - if {@link CoordinateReferenceSystem crs} can't be injected into the
* {@link AbstractGeometry}.
*/
public static org.geotoolkit.gml.xml.LinearRing toGML(final String gmlVersion, final LinearRing jtsGeom, final CoordinateReferenceSystem crs)
throws NoSuchAuthorityCodeException, FactoryException {
//Test if it's a 2D Geometry from CRS
isValideGeometry(crs);
final Coordinate[] jtsCoord = jtsGeom.getCoordinates();
final List<Double> coordList = new ArrayList<>();
for (Coordinate c : jtsCoord) {
coordList.add(c.x);
coordList.add(c.y);
}
return buildLinearRing(gmlVersion, coordList, getSRS(crs));
}
/**
* Convert JTS Point to GML PointType
* @param jtsPoint
* @param crs Coordinate Reference System
* @return PointType
*
* @throws org.opengis.referencing.NoSuchAuthorityCodeException - if {@link CoordinateReferenceSystem crs}
* can't be injected into the {@link AbstractGeometry}.
* @throws org.opengis.util.FactoryException - if {@link CoordinateReferenceSystem crs} can't be injected into the
* {@link AbstractGeometry}.
*/
public static org.geotoolkit.gml.xml.Point toGML(final String gmlVersion, final Point jtsPoint, final CoordinateReferenceSystem crs)
throws NoSuchAuthorityCodeException, FactoryException {
//Test if it's a 2D Geometry from CRS
isValideGeometry(crs);
final org.geotoolkit.gml.xml.Point gmlPoint = buildPoint(gmlVersion, null, coordinateToDirectPosition(jtsPoint.getCoordinate(), crs));
gmlPoint.setSrsName(getSRS(crs));
return gmlPoint;
}
/**
* Convert Coordinate to DirectPosition only in 2D
* @param coord
* @param crs
* @return DirectPostion with x and y
* @throws IllegalArgumentException if isn't a 2D Geometry
*/
private static DirectPosition coordinateToDirectPosition(final Coordinate coord, final CoordinateReferenceSystem crs) {
if (coord.z != Double.NaN) {
//throw new IllegalArgumentException("This service support only 2D coordinate.");
}
return new DirectPosition2D(crs, coord.x, coord.y);
}
/**
* Return the Coordinate Reference System of the Geometry.
* If the geometry CRS isn't define use <code>JTS.setCrs(geometry,CRS)</code> before call a GML conversion.
* @param jtsGeom
* @return the crs if valid geometry
* @throws NoSuchAuthorityCodeException in case of unknow authority
* @throws FactoryException in case of unknow factory
* @throws IllegalArgumentException in case of null CRS
*/
private static CoordinateReferenceSystem getCRS(final Geometry jtsGeom) throws NoSuchAuthorityCodeException, FactoryException {
//get JTS CRS
final CoordinateReferenceSystem crs = JTS.findCoordinateReferenceSystem(jtsGeom);
if (crs == null) {
throw new IllegalArgumentException("JTS geometry must specify a Coordinate Reference System.");
}
return crs;
}
/**
* Check if a geometry is only a 2D geometry
* @param crs
* @return <code>true</code> for valid Geometry, <code>false</code> else.
*/
private static void isValideGeometry(final CoordinateReferenceSystem crs) {
if (crs == null || crs.getCoordinateSystem() == null) {
throw new IllegalArgumentException("This service support only 2D JTS Geometry (CRS null, or coordinate system null).");
} else if (crs.getCoordinateSystem().getDimension() != 2) {
throw new IllegalArgumentException("This service support only 2D JTS Geometry. (CRS dimension != 2) => " + crs.getCoordinateSystem().getDimension());
}
}
/**
* Extract Identifier form a Coordinate Reference System
* @param crs
* @return CRS identifier
* @throws FactoryException
*/
private static String getSRS(final CoordinateReferenceSystem crs) throws FactoryException {
String srs = null;
final String method1 = org.geotoolkit.referencing.IdentifiedObjects.lookupIdentifier(Citations.URN_OGC, crs, false);
if (method1 != null) {
srs = method1;
} else {
//Try to use the deprecated methode
final String method2 = IdentifiedObjects.getIdentifierOrName(crs);
if (method2 != null) {
srs = method2;
} else {
throw new IllegalArgumentException("Can't get Coordinate Reference System identifier.");
}
}
return srs;
}
}