/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2014, 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;
* 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.data.geojson.utils;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
import org.geotoolkit.data.geojson.binding.*;
import org.geotoolkit.geometry.jts.JTS;
import org.geotoolkit.lang.Static;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import static org.geotoolkit.data.geojson.binding.GeoJSONGeometry.*;
import java.util.Arrays;
import java.util.Collections;
/**
* @author Quentin Boileau (Geomatys)
*/
public final class GeometryUtils extends Static {
private static final GeometryFactory GF = new GeometryFactory();
/**
* Convert GeoJSONGeometry into JTS Geometry with included CRS
* @param jsonGeometry
* @param crs
* @return JTS Geometry
*/
public static Geometry toJTS(GeoJSONGeometry jsonGeometry, CoordinateReferenceSystem crs) {
if (jsonGeometry != null) {
if (crs == null) {
throw new IllegalArgumentException("Null Coordinate Reference System.");
}
if (jsonGeometry instanceof GeoJSONPoint) {
return toJTS((GeoJSONPoint) jsonGeometry, crs);
} else if (jsonGeometry instanceof GeoJSONLineString) {
return toJTS((GeoJSONLineString) jsonGeometry, crs);
} else if (jsonGeometry instanceof GeoJSONPolygon) {
return toJTS((GeoJSONPolygon) jsonGeometry, crs);
} else if (jsonGeometry instanceof GeoJSONMultiPoint) {
return toJTS((GeoJSONMultiPoint) jsonGeometry, crs);
} else if (jsonGeometry instanceof GeoJSONMultiLineString) {
return toJTS((GeoJSONMultiLineString) jsonGeometry, crs);
} else if (jsonGeometry instanceof GeoJSONMultiPolygon) {
return toJTS((GeoJSONMultiPolygon) jsonGeometry, crs);
} else if (jsonGeometry instanceof GeoJSONGeometryCollection) {
return toJTS((GeoJSONGeometryCollection) jsonGeometry, crs);
} else {
throw new IllegalArgumentException("Unsupported geometry type : " + jsonGeometry);
}
}
return null;
}
private static Coordinate toCoordinate(double[] coord) {
if (coord.length == 2) {
return new Coordinate(coord[0], coord[1]);
} else if (coord.length == 3) {
return new Coordinate(coord[0], coord[1], coord[2]);
} else {
throw new IllegalArgumentException("Coordinates not valid : " + Arrays.toString(coord));
}
}
private static CoordinateSequence toCoordinateSequence(double[][] coords) {
Coordinate[] coordinates = new Coordinate[coords.length];
if (coords.length > 0) {
for (int i = 0; i < coords.length; i++) {
coordinates[i] = toCoordinate(coords[i]);
}
}
return new CoordinateArraySequence(coordinates);
}
private static LinearRing toLinearRing(double[][] coords) {
return GF.createLinearRing(toCoordinateSequence(coords));
}
private static Polygon toPolygon(double[][][] coords, CoordinateReferenceSystem crs) {
LinearRing exterior = toLinearRing(coords[0]);
LinearRing[] holes = new LinearRing[coords.length-1];
if (coords.length > 1) {
for (int i = 0; i < holes.length; i++) {
holes[i] = toLinearRing(coords[i+1]);
}
}
Polygon polygon = GF.createPolygon(exterior, holes);
JTS.setCRS(polygon, crs);
return polygon;
}
private static Point toJTS(GeoJSONPoint jsonPoint, CoordinateReferenceSystem crs) {
double[] coord = jsonPoint.getCoordinates();
final Point pt = GF.createPoint(toCoordinate(coord));
JTS.setCRS(pt, crs);
return pt;
}
private static LineString toJTS(GeoJSONLineString jsonLS, CoordinateReferenceSystem crs) {
double[][] coord = jsonLS.getCoordinates();
LineString line = GF.createLineString(toCoordinateSequence(coord));
JTS.setCRS(line, crs);
return line;
}
private static Geometry toJTS(GeoJSONPolygon jsonPolygon, CoordinateReferenceSystem crs) {
double[][][] coord = jsonPolygon.getCoordinates();
if (coord.length <= 0) {
return GF.buildGeometry(Collections.EMPTY_LIST);
}
return toPolygon(coord, crs);
}
private static MultiPoint toJTS(GeoJSONMultiPoint jsonMP, CoordinateReferenceSystem crs) {
double[][] coords = jsonMP.getCoordinates();
Coordinate[] coordinates = new Coordinate[coords.length];
if (coords.length > 0) {
for (int i = 0; i < coords.length; i++) {
coordinates[i] = toCoordinate(coords[i]);
}
}
MultiPoint mpt = GF.createMultiPoint(coordinates);
JTS.setCRS(mpt, crs);
return mpt;
}
private static MultiLineString toJTS(GeoJSONMultiLineString jsonMLS, CoordinateReferenceSystem crs) {
double[][][] coords = jsonMLS.getCoordinates();
LineString[] lines = new LineString[coords.length];
if (coords.length > 0) {
for (int i = 0; i < coords.length; i++) {
lines[i] = GF.createLineString(toCoordinateSequence(coords[i]));
}
}
MultiLineString mls = GF.createMultiLineString(lines);
JTS.setCRS(mls, crs);
return mls;
}
private static MultiPolygon toJTS(GeoJSONMultiPolygon jsonMP, CoordinateReferenceSystem crs) {
double[][][][] coords = jsonMP.getCoordinates();
Polygon[] polygons = new Polygon[coords.length];
if (coords.length > 0) {
for (int i = 0; i < coords.length; i++) {
polygons[i] = toPolygon(coords[i], crs);
}
}
MultiPolygon mp = GF.createMultiPolygon(polygons);
JTS.setCRS(mp, crs);
return mp;
}
private static GeometryCollection toJTS(GeoJSONGeometryCollection jsonGC, CoordinateReferenceSystem crs) {
if (jsonGC.getGeometries() != null) {
int size = jsonGC.getGeometries().size();
Geometry[] geometries = new Geometry[size];
for (int i = 0; i < size; i++) {
geometries[i] = toJTS(jsonGC.getGeometries().get(i), crs);
}
GeometryCollection gc = GF.createGeometryCollection(geometries);
JTS.setCRS(gc, crs);
return gc;
}
return null;
}
/**
* Convert JTS geometry into a GeoJSONGeometry.
* @param geom JTS Geometry
* @return GeoJSONGeometry
*/
public static GeoJSONGeometry toGeoJSONGeometry(Geometry geom) {
if (geom == null) {
throw new IllegalArgumentException("Null Geometry.");
}
if (geom instanceof Point) {
return toGeoJSONGeometry((Point) geom);
} else if (geom instanceof LineString) {
return toGeoJSONGeometry((LineString) geom);
} else if (geom instanceof Polygon) {
return toGeoJSONGeometry((Polygon) geom);
} else if (geom instanceof MultiPoint) {
return toGeoJSONGeometry((MultiPoint) geom);
} else if (geom instanceof MultiLineString) {
return toGeoJSONGeometry((MultiLineString) geom);
} else if (geom instanceof MultiPolygon) {
return toGeoJSONGeometry((MultiPolygon) geom);
} else if (geom instanceof GeometryCollection) {
return toGeoJSONGeometry((GeometryCollection) geom);
} else {
throw new IllegalArgumentException("Unsupported geometry type : " + geom);
}
}
private static double[] toArray(Coordinate coord) {
double x = coord.getOrdinate(0);
double y = coord.getOrdinate(1);
double z = coord.getOrdinate(2);
if (Double.isNaN(z)) {
return new double[] {x, y};
} else {
return new double[] {x, y, z};
}
}
private static double[][] toArray(Coordinate[] coords) {
double[][] result = new double[coords.length][];
for (int i = 0; i < coords.length; i++) {
result[i] = toArray(coords[i]);
}
return result;
}
private static double[][] toArray(CoordinateSequence coords) {
return toArray(coords.toCoordinateArray());
}
private static double[][][] toArray(CoordinateSequence[] coords) {
double[][][] result = new double[coords.length][][];
for (int i = 0; i < coords.length; i++) {
result[i] = toArray(coords[i]);
}
return result;
}
private static double[][][][] toArray(CoordinateSequence[][] coords) {
double[][][][] result = new double[coords.length][][][];
for (int i = 0; i < coords.length; i++) {
result[i] = toArray(coords[i]);
}
return result;
}
private static GeoJSONPoint toGeoJSONGeometry(Point pt) {
GeoJSONPoint jsonPt = new GeoJSONPoint();
jsonPt.setCoordinates(toArray(pt.getCoordinate()));
return jsonPt;
}
private static GeoJSONLineString toGeoJSONGeometry(LineString line) {
GeoJSONLineString jsonln = new GeoJSONLineString();
jsonln.setCoordinates(toArray(line.getCoordinateSequence()));
return jsonln;
}
private static GeoJSONPolygon toGeoJSONGeometry(Polygon polygon) {
GeoJSONPolygon jsonpoly = new GeoJSONPolygon();
CoordinateSequence[] coords = getCoordinateSequencesFromPolygon(polygon);
jsonpoly.setCoordinates(toArray(coords));
return jsonpoly;
}
private static CoordinateSequence[] getCoordinateSequencesFromPolygon(Polygon polygon) {
int totalRings = polygon.getNumInteriorRing() + 1;
CoordinateSequence[] coords = new CoordinateSequence[totalRings];
coords[0] = polygon.getExteriorRing().getCoordinateSequence();
if (totalRings > 1) {
for (int i = 0; i < totalRings - 1; i++) {
coords[i+1] = polygon.getInteriorRingN(i).getCoordinateSequence();
}
}
return coords;
}
private static GeoJSONMultiPoint toGeoJSONGeometry(MultiPoint mpt) {
GeoJSONMultiPoint jsonMpt = new GeoJSONMultiPoint();
jsonMpt.setCoordinates(toArray(mpt.getCoordinates()));
return jsonMpt;
}
private static GeoJSONMultiLineString toGeoJSONGeometry(MultiLineString mln) {
GeoJSONMultiLineString jsonMln = new GeoJSONMultiLineString();
int totalRings = mln.getNumGeometries();
CoordinateSequence[] coords = new CoordinateSequence[totalRings];
for (int i = 0; i < totalRings; i++) {
coords[i] = ((LineString)mln.getGeometryN(i)).getCoordinateSequence();
}
jsonMln.setCoordinates(toArray(coords));
return jsonMln;
}
private static GeoJSONMultiPolygon toGeoJSONGeometry(MultiPolygon multiPolygon) {
GeoJSONMultiPolygon jsonMPoly = new GeoJSONMultiPolygon();
int totalPoly = multiPolygon.getNumGeometries();
CoordinateSequence[][] coords = new CoordinateSequence[totalPoly][];
for (int i = 0; i < totalPoly; i++) {
coords[i] = getCoordinateSequencesFromPolygon((Polygon) multiPolygon.getGeometryN(i));
}
jsonMPoly.setCoordinates(toArray(coords));
return jsonMPoly;
}
private static GeoJSONGeometryCollection toGeoJSONGeometry(GeometryCollection geometryCollection) {
GeoJSONGeometryCollection coll = new GeoJSONGeometryCollection();
int numGeometries = geometryCollection.getNumGeometries();
for (int i = 0; i < numGeometries; i++) {
coll.getGeometries().add(toGeoJSONGeometry(geometryCollection.getGeometryN(i)));
}
return coll;
}
}