org.envirocar.server.rest.util.GeoJSON.java Source code

Java tutorial

Introduction

Here is the source code for org.envirocar.server.rest.util.GeoJSON.java

Source

/*
 * Copyright (C) 2013 The enviroCar project
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.envirocar.server.rest.util;

import static org.envirocar.server.core.util.GeoJSONConstants.*;

import org.envirocar.server.core.exception.GeometryConverterException;
import org.envirocar.server.core.util.GeometryConverter;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
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;

/**
 * TODO JavaDoc
 *
 * @author Christian Autermann <autermann@uni-muenster.de>
 */
public class GeoJSON implements GeometryConverter<JsonNode> {
    protected final GeometryFactory geometryFactory;
    private final JsonNodeFactory jsonFactory;

    @Inject
    public GeoJSON(GeometryFactory geometryFactory, JsonNodeFactory jsonFactory) {
        this.geometryFactory = geometryFactory;
        this.jsonFactory = jsonFactory;
    }

    public JsonNodeFactory getJsonFactory() {
        return jsonFactory;
    }

    public GeometryFactory getGeometryFactory() {
        return geometryFactory;
    }

    @Override
    public ObjectNode encode(Geometry value) throws GeometryConverterException {
        if (value == null) {
            return null;
        } else {
            return encodeGeometry(value);
        }
    }

    @Override
    public Geometry decode(JsonNode json) throws GeometryConverterException {
        if (json == null) {
            return null;
        } else {
            return decodeGeometry(json);
        }
    }

    protected ObjectNode encodeGeometry(Geometry geometry) throws GeometryConverterException {
        Preconditions.checkNotNull(geometry);
        if (geometry.isEmpty()) {
            return null;
        } else if (geometry instanceof Point) {
            return encode((Point) geometry);
        } else if (geometry instanceof LineString) {
            return encode((LineString) geometry);
        } else if (geometry instanceof Polygon) {
            return encode((Polygon) geometry);
        } else if (geometry instanceof MultiPoint) {
            return encode((MultiPoint) geometry);
        } else if (geometry instanceof MultiLineString) {
            return encode((MultiLineString) geometry);
        } else if (geometry instanceof MultiPolygon) {
            return encode((MultiPolygon) geometry);
        } else if (geometry instanceof GeometryCollection) {
            return encode((GeometryCollection) geometry);
        } else {
            throw new GeometryConverterException("unknown geometry type " + geometry.getGeometryType());
        }
    }

    @Override
    public ObjectNode encode(Point geometry) throws GeometryConverterException {
        Preconditions.checkNotNull(geometry);
        ObjectNode json = getJsonFactory().objectNode();
        json.put(TYPE_KEY, POINT_TYPE);
        json.put(COORDINATES_KEY, encodeCoordinates(geometry));
        return json;
    }

    @Override
    public ObjectNode encode(LineString geometry) throws GeometryConverterException {
        Preconditions.checkNotNull(geometry);
        ObjectNode json = getJsonFactory().objectNode();
        json.put(TYPE_KEY, LINE_STRING_TYPE);
        json.put(COORDINATES_KEY, encodeCoordinates(geometry));
        return json;
    }

    @Override
    public ObjectNode encode(Polygon geometry) throws GeometryConverterException {
        Preconditions.checkNotNull(geometry);
        ObjectNode json = getJsonFactory().objectNode();
        json.put(TYPE_KEY, POLYGON_TYPE);
        json.put(COORDINATES_KEY, encodeCoordinates(geometry));
        return json;
    }

    @Override
    public ObjectNode encode(MultiPoint geometry) throws GeometryConverterException {
        Preconditions.checkNotNull(geometry);
        ObjectNode json = getJsonFactory().objectNode();
        json.put(TYPE_KEY, MULTI_POINT_TYPE);
        ArrayNode list = getJsonFactory().arrayNode();
        for (int i = 0; i < geometry.getNumGeometries(); ++i) {
            list.add(encodeCoordinates((Point) geometry.getGeometryN(i)));
        }
        json.put(COORDINATES_KEY, list);
        return json;
    }

    @Override
    public ObjectNode encode(MultiLineString geometry) throws GeometryConverterException {
        Preconditions.checkNotNull(geometry);
        ObjectNode json = getJsonFactory().objectNode();
        json.put(TYPE_KEY, MULTI_LINE_STRING_TYPE);
        ArrayNode list = getJsonFactory().arrayNode();
        for (int i = 0; i < geometry.getNumGeometries(); ++i) {
            list.add(encodeCoordinates((LineString) geometry.getGeometryN(i)));
        }
        json.put(COORDINATES_KEY, list);
        return json;
    }

    @Override
    public ObjectNode encode(MultiPolygon geometry) throws GeometryConverterException {
        Preconditions.checkNotNull(geometry);
        ObjectNode json = getJsonFactory().objectNode();
        json.put(TYPE_KEY, MULTI_POLYGON_TYPE);
        ArrayNode list = getJsonFactory().arrayNode();
        for (int i = 0; i < geometry.getNumGeometries(); ++i) {
            list.add(encodeCoordinates((Polygon) geometry.getGeometryN(i)));
        }
        json.put(COORDINATES_KEY, list);
        return json;
    }

    @Override
    public ObjectNode encode(GeometryCollection geometry) throws GeometryConverterException {
        Preconditions.checkNotNull(geometry);
        ObjectNode json = getJsonFactory().objectNode();
        json.put(TYPE_KEY, GEOMETRY_COLLECTION_TYPE);
        ArrayNode geometries = getJsonFactory().arrayNode();
        for (int i = 0; i < geometry.getNumGeometries(); ++i) {
            geometries.add(encodeGeometry(geometry.getGeometryN(i)));
        }
        json.put(GEOMETRIES_KEY, geometries);
        return json;
    }

    protected ArrayNode encodeCoordinate(Coordinate coordinate) throws GeometryConverterException {
        ArrayNode list = getJsonFactory().arrayNode();
        list.add(coordinate.x);
        list.add(coordinate.y);
        return list;
    }

    protected ArrayNode encodeCoordinates(CoordinateSequence coordinates) throws GeometryConverterException {
        ArrayNode list = getJsonFactory().arrayNode();
        for (int i = 0; i < coordinates.size(); ++i) {
            ArrayNode coordinate = getJsonFactory().arrayNode();
            coordinate.add(coordinates.getX(i));
            coordinate.add(coordinates.getY(i));
            list.add(coordinate);
        }
        return list;
    }

    protected ArrayNode encodeCoordinates(Point geometry) throws GeometryConverterException {
        return encodeCoordinate(geometry.getCoordinate());
    }

    protected ArrayNode encodeCoordinates(LineString geometry) throws GeometryConverterException {
        return encodeCoordinates(geometry.getCoordinateSequence());
    }

    protected ArrayNode encodeCoordinates(Polygon geometry) throws GeometryConverterException {
        ArrayNode list = getJsonFactory().arrayNode();
        list.add(encodeCoordinates(geometry.getExteriorRing()));
        for (int i = 0; i < geometry.getNumInteriorRing(); ++i) {
            list.add(encodeCoordinates(geometry.getInteriorRingN(i)));
        }
        return list;
    }

    protected ArrayNode requireCoordinates(JsonNode json) throws GeometryConverterException {
        if (!json.has(COORDINATES_KEY)) {
            throw new GeometryConverterException("missing 'coordinates' field");
        }
        return toList(json.get(COORDINATES_KEY));
    }

    protected Coordinate decodeCoordinate(ArrayNode list) throws GeometryConverterException {
        if (list.size() != 2) {
            throw new GeometryConverterException("coordinates may only have 2 dimensions");
        }
        Number x = list.get(0).numberValue();
        Number y = list.get(1).numberValue();
        if (x == null || y == null) {
            throw new GeometryConverterException("x and y have to be numbers");
        }
        return new Coordinate(x.doubleValue(), y.doubleValue());
    }

    protected ArrayNode toList(Object o) throws GeometryConverterException {
        if (!(o instanceof ArrayNode)) {
            throw new GeometryConverterException("expected list");
        }
        return (ArrayNode) o;
    }

    protected Coordinate[] decodeCoordinates(ArrayNode list) throws GeometryConverterException {
        Coordinate[] coordinates = new Coordinate[list.size()];
        for (int i = 0; i < list.size(); ++i) {
            coordinates[i] = decodeCoordinate(toList(list.get(i)));
        }
        return coordinates;
    }

    protected Polygon decodePolygonCoordinates(ArrayNode coordinates) throws GeometryConverterException {
        if (coordinates.size() < 1) {
            throw new GeometryConverterException("missing polygon shell");
        }
        LinearRing shell = getGeometryFactory().createLinearRing(decodeCoordinates(toList(coordinates.get(0))));
        LinearRing[] holes = new LinearRing[coordinates.size() - 1];
        for (int i = 1; i < coordinates.size(); ++i) {
            holes[i - 1] = getGeometryFactory().createLinearRing(decodeCoordinates(toList(coordinates.get(i))));
        }
        return getGeometryFactory().createPolygon(shell, holes);
    }

    protected Geometry decodeGeometry(Object o) throws GeometryConverterException {
        if (!(o instanceof ObjectNode)) {
            throw new GeometryConverterException("Cannot decode " + o);
        }
        ObjectNode json = (ObjectNode) o;
        if (!json.has(TYPE_KEY)) {
            throw new GeometryConverterException("Can not determine geometry type (missing 'type' field)");
        }
        Object to = json.path(TYPE_KEY).textValue();
        if (!(to instanceof String)) {
            throw new GeometryConverterException("'type' field has to be a string");
        }
        String type = (String) to;
        if (type.equals(POINT_TYPE)) {
            return decodePoint(json);
        } else if (type.equals(MULTI_POINT_TYPE)) {
            return decodeMultiPoint(json);
        } else if (type.equals(LINE_STRING_TYPE)) {
            return decodeLineString(json);
        } else if (type.equals(MULTI_LINE_STRING_TYPE)) {
            return decodeMultiLineString(json);
        } else if (type.equals(POLYGON_TYPE)) {
            return decodePolygon(json);
        } else if (type.equals(MULTI_POLYGON_TYPE)) {
            return decodeMultiPolygon(json);
        } else if (type.equals(GEOMETRY_COLLECTION_TYPE)) {
            return decodeGeometryCollection(json);
        } else {
            throw new GeometryConverterException("Unkown geometry type: " + type);
        }
    }

    @Override
    public MultiLineString decodeMultiLineString(JsonNode json) throws GeometryConverterException {
        ArrayNode coordinates = requireCoordinates(json);
        LineString[] lineStrings = new LineString[coordinates.size()];
        for (int i = 0; i < coordinates.size(); ++i) {
            Object coords = coordinates.get(i);
            lineStrings[i] = getGeometryFactory().createLineString(decodeCoordinates(toList(coords)));
        }
        return getGeometryFactory().createMultiLineString(lineStrings);
    }

    @Override
    public LineString decodeLineString(JsonNode json) throws GeometryConverterException {
        Coordinate[] coordinates = decodeCoordinates(requireCoordinates(json));
        return getGeometryFactory().createLineString(coordinates);
    }

    @Override
    public MultiPoint decodeMultiPoint(JsonNode json) throws GeometryConverterException {
        Coordinate[] coordinates = decodeCoordinates(requireCoordinates(json));
        return getGeometryFactory().createMultiPoint(coordinates);
    }

    @Override
    public Point decodePoint(JsonNode json) throws GeometryConverterException {
        Coordinate parsed = decodeCoordinate(requireCoordinates(json));
        return getGeometryFactory().createPoint(parsed);
    }

    @Override
    public Polygon decodePolygon(JsonNode json) throws GeometryConverterException {
        ArrayNode coordinates = requireCoordinates(json);
        return decodePolygonCoordinates(coordinates);
    }

    @Override
    public MultiPolygon decodeMultiPolygon(JsonNode json) throws GeometryConverterException {
        ArrayNode coordinates = requireCoordinates(json);
        Polygon[] polygons = new Polygon[coordinates.size()];
        for (int i = 0; i < coordinates.size(); ++i) {
            polygons[i] = decodePolygonCoordinates(toList(coordinates.get(i)));
        }
        return getGeometryFactory().createMultiPolygon(polygons);
    }

    @Override
    public GeometryCollection decodeGeometryCollection(JsonNode json) throws GeometryConverterException {
        if (!json.has(GEOMETRIES_KEY)) {
            throw new GeometryConverterException("missing 'geometries' field");
        }
        ArrayNode geometries = toList(json.get(GEOMETRIES_KEY));
        Geometry[] geoms = new Geometry[geometries.size()];
        for (int i = 0; i < geometries.size(); ++i) {
            geoms[i] = decodeGeometry(geometries.get(i));
        }
        return getGeometryFactory().createGeometryCollection(geoms);
    }
}