/* * Copyright (C) 2017-2019 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * SPDX-License-Identifier: Apache-2.0 * License-Filename: LICENSE */ package com.here.xyz.models.geojson.coordinates; import com.here.xyz.models.geojson.implementation.GeometryItem; 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 com.vividsolutions.jts.geom.PrecisionModel; import java.util.ArrayList; import java.util.List; public class JTSHelper { private final static Point[] EMPTY_POINT_ARRAY = new Point[0]; // ############## Methods to convert from GeoJSON to JTS ############## public static GeometryFactory factory = new GeometryFactory(new PrecisionModel(), 4326); /** * Creates a Point. */ public static Point toPoint(PointCoordinates coords) { if (coords == null) { return null; } if (coords.getAltitude() != null) { return factory.createPoint(new Coordinate(coords.getLongitude(), coords.getLatitude(), coords.getAltitude())); } return factory.createPoint(new Coordinate(coords.getLongitude(), coords.getLatitude())); } /** * Creates a MultiPoint. */ public static MultiPoint toMultiPoint(MultiPointCoordinates coords) { if (coords == null) { return null; } ArrayList<Point> pointsList = new ArrayList<>(); for (PointCoordinates pointCoords : coords) { pointsList.add(toPoint(pointCoords)); } return factory.createMultiPoint(pointsList.toArray(EMPTY_POINT_ARRAY)); } /** * Creates a LineString. */ public static LineString toLineString(LineStringCoordinates coords) { if (coords == null) { return null; } Coordinate[] jtsCoords = new Coordinate[coords.size()]; for (int i = 0; i < jtsCoords.length; i++) { jtsCoords[i] = toCoordinate(coords.get(i)); } return JTSHelper.factory.createLineString(jtsCoords); } /** * Creates a MultiLineString. */ public static MultiLineString toMultiLineString(MultiLineStringCoordinates coords) { if (coords == null) { return null; } LineString[] lines = new LineString[coords.size()]; for (int i = 0; i < lines.length; i++) { lines[i] = toLineString(coords.get(i)); } return JTSHelper.factory.createMultiLineString(lines); } /** * Creates a Polygon. */ public static Polygon toPolygon(PolygonCoordinates coords) { if (coords == null) { return null; } LinearRing shell = toLinearRing(coords.get(0)); if (coords.size() == 1) { return JTSHelper.factory.createPolygon(shell); } LinearRing[] holes = new LinearRing[coords.size() - 1]; for (int i = 1; i < coords.size(); i++) { holes[i - 1] = toLinearRing(coords.get(i)); } return JTSHelper.factory.createPolygon(shell, holes); } /** * Creates a MultiPolygon. */ public static MultiPolygon toMultiPolygon(MultiPolygonCoordinates coords) { if (coords == null) { return null; } Polygon[] polygons = new Polygon[coords.size()]; for (int i = 0; i < polygons.length; i++) { polygons[i] = toPolygon(coords.get(i)); } return JTSHelper.factory.createMultiPolygon(polygons); } /** * Creates a linear ring. */ public static LinearRing toLinearRing(LinearRingCoordinates coords) { if (coords == null) { return null; } Coordinate[] jtsCoords = new Coordinate[coords.size()]; for (int i = 0; i < jtsCoords.length; i++) { jtsCoords[i] = toCoordinate(coords.get(i)); } return factory.createLinearRing(jtsCoords); } /** * Creates a JTS Coordinate. */ public static Coordinate toCoordinate(Position pos) { return (pos.getAltitude() == null) ? new Coordinate(pos.getLongitude(), pos.getLatitude()) : new Coordinate(pos.getLongitude(), pos.getLatitude(), pos.getAltitude()); } /** * Creates a JTS Geometry from the provided GeoJSON geometry. */ @SuppressWarnings("unchecked") public static <X extends Geometry> X toGeometry(com.here.xyz.models.geojson.implementation.Geometry geometry) { if (geometry == null) { return null; } if (geometry instanceof com.here.xyz.models.geojson.implementation.Point) { return (X) toPoint(((com.here.xyz.models.geojson.implementation.Point) geometry).getCoordinates()); } if (geometry instanceof com.here.xyz.models.geojson.implementation.MultiPoint) { return (X) toMultiPoint(((com.here.xyz.models.geojson.implementation.MultiPoint) geometry).getCoordinates()); } if (geometry instanceof com.here.xyz.models.geojson.implementation.LineString) { return (X) toLineString(((com.here.xyz.models.geojson.implementation.LineString) geometry).getCoordinates()); } if (geometry instanceof com.here.xyz.models.geojson.implementation.MultiLineString) { return (X) toMultiLineString(((com.here.xyz.models.geojson.implementation.MultiLineString) geometry).getCoordinates()); } if (geometry instanceof com.here.xyz.models.geojson.implementation.Polygon) { return (X) toPolygon(((com.here.xyz.models.geojson.implementation.Polygon) geometry).getCoordinates()); } if (geometry instanceof com.here.xyz.models.geojson.implementation.MultiPolygon) { return (X) toMultiPolygon(((com.here.xyz.models.geojson.implementation.MultiPolygon) geometry).getCoordinates()); } if (geometry instanceof com.here.xyz.models.geojson.implementation.GeometryCollection) { return (X) toGeometryCollection(((com.here.xyz.models.geojson.implementation.GeometryCollection) geometry)); } return null; } public static GeometryCollection toGeometryCollection(com.here.xyz.models.geojson.implementation.GeometryCollection geometryCollection) { if (geometryCollection == null) { return null; } List<GeometryItem> geometries = geometryCollection.getGeometries(); int len = geometries.size(); Geometry[] jtsGeometries = new Geometry[len]; for (int i = 0; i < len; i++) { jtsGeometries[i] = toGeometry(geometries.get(i)); } return new GeometryCollection(jtsGeometries, factory); } // ############## Methods to convert from JTS to GeoJSON ############## /** * Create a GeoJSON position. */ public static Position createPosition(Coordinate coord) { return (Double.isNaN(coord.z)) ? new Position(coord.x, coord.y) : new Position(coord.x, coord.y, coord.z); } /** * Create GeoJSON Point coordinates. */ public static PointCoordinates createPointCoordinates(Point geom) { if (geom == null) { return null; } final Coordinate coordinate = geom.getCoordinate(); return (Double.isNaN(coordinate.z)) ? new PointCoordinates(coordinate.x, coordinate.y) : new PointCoordinates(coordinate.x, coordinate.y, coordinate.z); } /** * Create GeoJSON MultiPoint coordinates. */ public static MultiPointCoordinates createMultiPointCoordinates(MultiPoint geom) { if (geom == null) { return null; } int len = geom.getNumGeometries(); MultiPointCoordinates multiPointCoordinates = new MultiPointCoordinates(len); for (int i = 0; i < len; i++) { multiPointCoordinates.add(createPointCoordinates((Point) geom.getGeometryN(i))); } return multiPointCoordinates; } /** * Create GeoJSON LineString coordinates. */ public static LineStringCoordinates createLineStringCoordinates(LineString geom) { if (geom == null) { return null; } int len = geom.getNumPoints(); LineStringCoordinates lineStringCoordinates = new LineStringCoordinates(len); for (int i = 0; i < len; i++) { lineStringCoordinates.add(createPosition(geom.getCoordinateN(i))); } return lineStringCoordinates; } /** * Create GeoJSON MultiLineString coordinates. */ public static MultiLineStringCoordinates createMultiLineStringCoordinates(MultiLineString geom) { if (geom == null) { return null; } int len = geom.getNumGeometries(); MultiLineStringCoordinates multiLineStringCoordinates = new MultiLineStringCoordinates(len); for (int i = 0; i < len; i++) { multiLineStringCoordinates.add(createLineStringCoordinates((LineString) geom.getGeometryN(i))); } return multiLineStringCoordinates; } /** * Create GeoJSON LinearRing coordinates. */ public static LinearRingCoordinates createLinearRingCoordinates(LinearRing geom) { if (geom == null) { return null; } int len = geom.getNumPoints(); LinearRingCoordinates linearRingCoordinates = new LinearRingCoordinates(len); for (int i = 0; i < len; i++) { linearRingCoordinates.add(createPosition(geom.getCoordinateN(i))); } return linearRingCoordinates; } /** * Create GeoJSON Polygon coordinates. */ public static PolygonCoordinates createPolygonCoordinates(Polygon geom) { if (geom == null) { return null; } LinearRing shell = (LinearRing) geom.getExteriorRing(); int lenInterior = geom.getNumInteriorRing(); PolygonCoordinates polygonCoordinates = new PolygonCoordinates(lenInterior + 1); polygonCoordinates.add(createLinearRingCoordinates(shell)); for (int i = 0; i < lenInterior; i++) { polygonCoordinates.add(createLinearRingCoordinates((LinearRing) geom.getInteriorRingN(i))); } return polygonCoordinates; } /** * Create MultiPolygon coordinates. */ public static MultiPolygonCoordinates createMultiPolygonCoordinates(MultiPolygon geom) { if (geom == null) { return null; } int len = geom.getNumGeometries(); MultiPolygonCoordinates multiPolygonCoordinates = new MultiPolygonCoordinates(len); for (int i = 0; i < len; i++) { multiPolygonCoordinates.add(createPolygonCoordinates((Polygon) geom.getGeometryN(i))); } return multiPolygonCoordinates; } @SuppressWarnings("unchecked") public static <X extends com.here.xyz.models.geojson.implementation.Geometry> X fromGeometry(Geometry jtsGeometry) { if (jtsGeometry == null) { return null; } if (jtsGeometry instanceof Point) { return (X) new com.here.xyz.models.geojson.implementation.Point().withCoordinates(createPointCoordinates((Point) jtsGeometry)); } if (jtsGeometry instanceof MultiPoint) { return (X) new com.here.xyz.models.geojson.implementation.MultiPoint() .withCoordinates(createMultiPointCoordinates((MultiPoint) jtsGeometry)); } if (jtsGeometry instanceof LineString) { return (X) new com.here.xyz.models.geojson.implementation.LineString() .withCoordinates(createLineStringCoordinates((LineString) jtsGeometry)); } if (jtsGeometry instanceof MultiLineString) { return (X) new com.here.xyz.models.geojson.implementation.MultiLineString() .withCoordinates(createMultiLineStringCoordinates((MultiLineString) jtsGeometry)); } if (jtsGeometry instanceof Polygon) { return (X) new com.here.xyz.models.geojson.implementation.Polygon().withCoordinates(createPolygonCoordinates((Polygon) jtsGeometry)); } if (jtsGeometry instanceof MultiPolygon) { return (X) new com.here.xyz.models.geojson.implementation.MultiPolygon() .withCoordinates(createMultiPolygonCoordinates((MultiPolygon) jtsGeometry)); } if (jtsGeometry instanceof GeometryCollection) { return (X) fromGeometryCollection((GeometryCollection) jtsGeometry); } return null; } public static com.here.xyz.models.geojson.implementation.GeometryCollection fromGeometryCollection( GeometryCollection jtsGeometryCollection) { if (jtsGeometryCollection == null) { return null; } com.here.xyz.models.geojson.implementation.GeometryCollection geometryCollection = new com.here.xyz.models.geojson.implementation.GeometryCollection(); int len = jtsGeometryCollection.getNumGeometries(); List<com.here.xyz.models.geojson.implementation.GeometryItem> geometries = new ArrayList<>(); for (int i = 0; i < len; i++) { geometries.add(fromGeometry(jtsGeometryCollection.getGeometryN(i))); } return geometryCollection.withGeometries(geometries); } }