/**
* H2GIS is a library that brings spatial support to the H2 Database Engine
* <http://www.h2database.com>. H2GIS is developed by CNRS
* <http://www.cnrs.fr/>.
*
* This code is part of the H2GIS project. H2GIS 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 3.0 of the License.
*
* H2GIS 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 <http://www.gnu.org/licenses/>.
*
*
* For more information, please consult: <http://www.h2gis.org/>
* or contact directly: info_at_h2gis.org
*/
package org.h2gis.functions.io.geojson;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.LineString;
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 org.h2gis.api.DeterministicScalarFunction;
/**
* Transform a JTS geometry to a GeoJSON geometry representation.
*
* @author Erwan Bocher
*/
public class ST_AsGeoJSON extends DeterministicScalarFunction {
public ST_AsGeoJSON() {
addProperty(PROP_REMARKS, "Return the geometry as a Geometry Javascript Object Notation (GeoJSON 1.0) element.\n"
+ "2D and 3D Geometries are both supported.\n"
+ "GeoJSON only supports SFS 1.1 geometry types (POINT, LINESTRING, POLYGON and COLLECTION).");
}
@Override
public String getJavaStaticMethod() {
return "toGeojson";
}
/**
* Convert the geometry to a GeoJSON representation.
*
* @param geom
* @return
*/
public static String toGeojson(Geometry geom) {
StringBuilder sb = new StringBuilder();
toGeojsonGeometry(geom, sb);
return sb.toString();
}
/**
* Transform a JTS geometry to a GeoJSON representation.
*
* @param geom
* @param sb
*/
public static void toGeojsonGeometry(Geometry geom, StringBuilder sb) {
if (geom instanceof Point) {
toGeojsonPoint((Point) geom, sb);
} else if (geom instanceof LineString) {
toGeojsonLineString((LineString) geom, sb);
} else if (geom instanceof Polygon) {
toGeojsonPolygon((Polygon) geom, sb);
} else if (geom instanceof MultiPoint) {
toGeojsonMultiPoint((MultiPoint) geom, sb);
} else if (geom instanceof MultiLineString) {
toGeojsonMultiLineString((MultiLineString) geom, sb);
} else if (geom instanceof MultiPolygon) {
toGeojsonMultiPolygon((MultiPolygon) geom, sb);
} else {
toGeojsonGeometryCollection((GeometryCollection) geom, sb);
}
}
/**
* For type "Point", the "coordinates" member must be a single position.
*
* A position is the fundamental geometry construct. The "coordinates"
* member of a geometry object is composed of one position (in the case of a
* Point geometry), an array of positions (LineString or MultiPoint
* geometries), an array of arrays of positions (Polygons,
* MultiLineStrings), or a multidimensional array of positions
* (MultiPolygon).
*
* A position is represented by an array of numbers. There must be at least
* two elements, and may be more. The order of elements must follow x, y, z
* order (easting, northing, altitude for coordinates in a projected
* coordinate reference system, or longitude, latitude, altitude for
* coordinates in a geographic coordinate reference system). Any number of
* additional elements are allowed -- interpretation and meaning of
* additional elements is beyond the scope of this specification.
*
* Syntax:
*
* { "type": "Point", "coordinates": [100.0, 0.0] }
*
* @param point
* @param sb
*/
public static void toGeojsonPoint(Point point, StringBuilder sb) {
Coordinate coord = point.getCoordinate();
sb.append("{\"type\":\"Point\",\"coordinates\":[");
sb.append(coord.x).append(",").append(coord.y);
if (!Double.isNaN(coord.z)) {
sb.append(",").append(coord.z);
}
sb.append("]}");
}
/**
* Coordinates of a MultiPoint are an array of positions.
*
* Syntax:
*
* { "type": "MultiPoint", "coordinates": [ [100.0, 0.0], [101.0, 1.0] ] }
*
* @param multiPoint
* @param sb
*/
public static void toGeojsonMultiPoint(MultiPoint multiPoint, StringBuilder sb) {
sb.append("{\"type\":\"MultiPoint\",\"coordinates\":");
toGeojsonCoordinates(multiPoint.getCoordinates(), sb);
sb.append("}");
}
/**
* Coordinates of LineString are an array of positions.
*
* Syntax:
*
* { "type": "LineString", "coordinates": [ [100.0, 0.0], [101.0, 1.0] ] }
*
* @param lineString
* @param sb
*/
public static void toGeojsonLineString(LineString lineString, StringBuilder sb) {
sb.append("{\"type\":\"LineString\",\"coordinates\":");
toGeojsonCoordinates(lineString.getCoordinates(), sb);
sb.append("}");
}
/**
* Coordinates of a MultiLineString are an array of LineString coordinate
* arrays.
*
* Syntax:
*
* { "type": "MultiLineString", "coordinates": [ [ [100.0, 0.0], [101.0,
* 1.0] ], [ [102.0, 2.0], [103.0, 3.0] ] ] }
*
* @param multiLineString
* @param sb
*/
public static void toGeojsonMultiLineString(MultiLineString multiLineString, StringBuilder sb) {
sb.append("{\"type\":\"MultiLineString\",\"coordinates\":[");
for (int i = 0; i < multiLineString.getNumGeometries(); i++) {
toGeojsonCoordinates(multiLineString.getGeometryN(i).getCoordinates(), sb);
if (i < multiLineString.getNumGeometries() - 1) {
sb.append(",");
}
}
sb.append("]}");
}
/**
* Coordinates of a Polygon are an array of LinearRing coordinate arrays.
* The first element in the array represents the exterior ring. Any
* subsequent elements represent interior rings (or holes).
*
* Syntax:
*
* No holes:
*
* { "type": "Polygon", "coordinates": [ [ [100.0, 0.0], [101.0, 0.0],
* [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ] ] }
*
* With holes:
*
* { "type": "Polygon", "coordinates": [ [ [100.0, 0.0], [101.0, 0.0],
* [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ], [ [100.2, 0.2], [100.8, 0.2],
* [100.8, 0.8], [100.2, 0.8], [100.2, 0.2] ] ] }
*
*
* @param polygon
* @param sb
*/
public static void toGeojsonPolygon(Polygon polygon, StringBuilder sb) {
sb.append("{\"type\":\"Polygon\",\"coordinates\":[");
//Process exterior ring
toGeojsonCoordinates(polygon.getExteriorRing().getCoordinates(), sb);
//Process interior rings
for (int i = 0; i < polygon.getNumInteriorRing(); i++) {
sb.append(",");
toGeojsonCoordinates(polygon.getInteriorRingN(i).getCoordinates(), sb);
}
sb.append("]}");
}
/**
* Coordinates of a MultiPolygon are an array of Polygon coordinate arrays.
*
* Syntax:
*
* { "type": "MultiPolygon", "coordinates": [ [[[102.0, 2.0], [103.0, 2.0],
* [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]], [[[100.0, 0.0], [101.0, 0.0],
* [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]], [[100.2, 0.2], [100.8, 0.2],
* [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]] ] }
*
* @param multiPolygon
* @param sb
*/
public static void toGeojsonMultiPolygon(MultiPolygon multiPolygon, StringBuilder sb) {
sb.append("{\"type\":\"MultiPolygon\",\"coordinates\":[");
for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
Polygon p = (Polygon) multiPolygon.getGeometryN(i);
sb.append("[");
//Process exterior ring
toGeojsonCoordinates(p.getExteriorRing().getCoordinates(), sb);
//Process interior rings
for (int j = 0; j < p.getNumInteriorRing(); j++) {
sb.append(",");
toGeojsonCoordinates(p.getInteriorRingN(j).getCoordinates(), sb);
}
sb.append("]");
if (i < multiPolygon.getNumGeometries() - 1) {
sb.append(",");
}
}
sb.append("]}");
}
/**
* A GeoJSON object with type "GeometryCollection" is a geometry object
* which represents a collection of geometry objects.
*
* A geometry collection must have a member with the name "geometries". The
* value corresponding to "geometries"is an array. Each element in this
* array is a GeoJSON geometry object.
*
* Syntax:
*
* { "type": "GeometryCollection", "geometries": [ { "type": "Point",
* "coordinates": [100.0, 0.0] }, { "type": "LineString", "coordinates": [
* [101.0, 0.0], [102.0, 1.0] ] } ] }
*
* @param geometryCollection
* @param sb
*/
public static void toGeojsonGeometryCollection(GeometryCollection geometryCollection, StringBuilder sb) {
sb.append("{\"type\":\"GeometryCollection\",\"geometries\":[");
for (int i = 0; i < geometryCollection.getNumGeometries(); i++) {
Geometry geom = geometryCollection.getGeometryN(i);
if (geom instanceof Point) {
toGeojsonPoint((Point) geom, sb);
} else if (geom instanceof LineString) {
toGeojsonLineString((LineString) geom, sb);
} else if (geom instanceof Polygon) {
toGeojsonPolygon((Polygon) geom, sb);
}
if (i < geometryCollection.getNumGeometries() - 1) {
sb.append(",");
}
}
sb.append("]}");
}
/**
* Convert a jts array of coordinates to a GeoJSON coordinates
* representation.
*
* Syntax:
*
* [[X1,Y1],[X2,Y2]]
*
* @param coords
* @param sb
*/
public static void toGeojsonCoordinates(Coordinate[] coords, StringBuilder sb) {
sb.append("[");
for (int i = 0; i < coords.length; i++) {
toGeojsonCoordinate(coords[i], sb);
if (i < coords.length - 1) {
sb.append(",");
}
}
sb.append("]");
}
/**
* Convert a JTS coordinate to a GeoJSON representation.
*
* Only x, y and z values are supported.
*
* Syntax:
*
* [X,Y] or [X,Y,Z]
*
* @param coord
* @param sb
*/
public static void toGeojsonCoordinate(Coordinate coord, StringBuilder sb) {
sb.append("[");
sb.append(coord.x).append(",").append(coord.y);
if (!Double.isNaN(coord.z)) {
sb.append(",").append(coord.z);
}
sb.append("]");
}
/**
* Convert a JTS Envelope to a GeoJSON representation.
*
* @param e The envelope
*
* @return The envelope encoded as GeoJSON
*/
public String toGeoJsonEnvelope(Envelope e) {
return new StringBuffer().append("[").append(e.getMinX()).append(",")
.append(e.getMinY()).append(",").append(e.getMaxX()).append(",")
.append(e.getMaxY()).append("]").toString();
}
}