org.envirocar.server.mongo.util.GeoBSON.java Source code

Java tutorial

Introduction

Here is the source code for org.envirocar.server.mongo.util.GeoBSON.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.mongo.util;

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

import org.bson.BSONObject;
import org.bson.types.BasicBSONList;
import org.envirocar.server.core.exception.GeometryConverterException;
import org.envirocar.server.core.util.GeometryConverter;

import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
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 GeoBSON implements GeometryConverter<BSONObject> {
    private final GeometryFactory factory;

    @Inject
    public GeoBSON(GeometryFactory factory) {
        this.factory = factory;
    }

    protected BSONObject 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 BSONObject encode(Point geometry) {
        Preconditions.checkNotNull(geometry);
        BSONObject db;
        db = new BasicDBObject();
        db.put(TYPE_KEY, POINT_TYPE);
        db.put(COORDINATES_KEY, encodeCoordinates(geometry));
        return db;
    }

    @Override
    public BSONObject encode(LineString geometry) {
        Preconditions.checkNotNull(geometry);
        BSONObject db = new BasicDBObject();
        db.put(TYPE_KEY, LINE_STRING_TYPE);
        db.put(COORDINATES_KEY, encodeCoordinates(geometry));
        return db;
    }

    @Override
    public BSONObject encode(Polygon geometry) {
        Preconditions.checkNotNull(geometry);
        BSONObject db = new BasicDBObject();
        db.put(TYPE_KEY, POLYGON_TYPE);
        db.put(COORDINATES_KEY, encodeCoordinates(geometry));
        return db;
    }

    @Override
    public BSONObject encode(MultiPoint geometry) {
        Preconditions.checkNotNull(geometry);
        BSONObject db = new BasicDBObject();
        db.put(TYPE_KEY, MULTI_POINT_TYPE);
        BasicDBList list = new BasicDBList();
        for (int i = 0; i < geometry.getNumGeometries(); ++i) {
            list.add(encodeCoordinates((Point) geometry.getGeometryN(i)));
        }
        db.put(COORDINATES_KEY, list);
        return db;
    }

    @Override
    public BSONObject encode(MultiLineString geometry) {
        Preconditions.checkNotNull(geometry);
        BSONObject db = new BasicDBObject();
        db.put(TYPE_KEY, MULTI_LINE_STRING_TYPE);
        BasicDBList list = new BasicDBList();
        for (int i = 0; i < geometry.getNumGeometries(); ++i) {
            list.add(encodeCoordinates((LineString) geometry.getGeometryN(i)));
        }
        db.put(COORDINATES_KEY, list);
        return db;
    }

    @Override
    public BSONObject encode(MultiPolygon geometry) {
        Preconditions.checkNotNull(geometry);
        BSONObject db = new BasicDBObject();
        db.put(TYPE_KEY, MULTI_POLYGON_TYPE);
        BasicDBList list = new BasicDBList();
        for (int i = 0; i < geometry.getNumGeometries(); ++i) {
            list.add(encodeCoordinates((Polygon) geometry.getGeometryN(i)));
        }
        db.put(COORDINATES_KEY, list);
        return db;
    }

    @Override
    public BSONObject encode(GeometryCollection geometry) throws GeometryConverterException {
        Preconditions.checkNotNull(geometry);
        BSONObject bson = new BasicDBObject();
        bson.put(TYPE_KEY, GEOMETRY_COLLECTION_TYPE);
        BasicDBList geometries = new BasicDBList();
        for (int i = 0; i < geometry.getNumGeometries(); ++i) {
            geometries.add(encodeGeometry(geometry.getGeometryN(i)));
        }
        bson.put(GEOMETRIES_KEY, geometries);
        return bson;
    }

    protected BSONObject encodeCoordinate(Coordinate coordinate) {
        BasicBSONList list = new BasicBSONList();
        list.add(coordinate.x);
        list.add(coordinate.y);
        return list;
    }

    protected BSONObject encodeCoordinates(CoordinateSequence coordinates) {
        BasicBSONList list = new BasicBSONList();
        for (int i = 0; i < coordinates.size(); ++i) {
            BasicBSONList coordinate = new BasicBSONList();
            coordinate.add(coordinates.getX(i));
            coordinate.add(coordinates.getY(i));
            list.add(coordinate);
        }
        return list;
    }

    protected BSONObject encodeCoordinates(Point geometry) {
        return encodeCoordinate(geometry.getCoordinate());
    }

    protected BSONObject encodeCoordinates(LineString geometry) {
        return encodeCoordinates(geometry.getCoordinateSequence());
    }

    protected BSONObject encodeCoordinates(Polygon geometry) {
        BasicBSONList list = new BasicBSONList();
        list.add(encodeCoordinates(geometry.getExteriorRing()));
        for (int i = 0; i < geometry.getNumInteriorRing(); ++i) {
            list.add(encodeCoordinates(geometry.getInteriorRingN(i)));
        }
        return list;
    }

    protected BasicDBList requireCoordinates(BSONObject bson) throws GeometryConverterException {
        if (!bson.containsField(COORDINATES_KEY)) {
            throw new GeometryConverterException("missing 'coordinates' field");
        }
        return toList(bson.get(COORDINATES_KEY));
    }

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

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

    protected Coordinate[] decodeCoordinates(BasicDBList 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(BasicDBList coordinates) throws GeometryConverterException {
        if (coordinates.size() < 1) {
            throw new GeometryConverterException("missing polygon shell");
        }
        LinearRing shell = factory.createLinearRing(decodeCoordinates(toList(coordinates.get(0))));
        LinearRing[] holes = new LinearRing[coordinates.size() - 1];
        for (int i = 1; i < coordinates.size(); ++i) {
            holes[i - 1] = factory.createLinearRing(decodeCoordinates(toList(coordinates.get(i))));
        }
        return factory.createPolygon(shell, holes);
    }

    protected Geometry decodeGeometry(Object db) throws GeometryConverterException {
        BSONObject bson = (BSONObject) db;
        if (!bson.containsField(TYPE_KEY)) {
            throw new GeometryConverterException("Can not determine geometry type (missing 'type' field)");
        }
        Object to = bson.get(TYPE_KEY);
        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(bson);
        } else if (type.equals(MULTI_POINT_TYPE)) {
            return decodeMultiPoint(bson);
        } else if (type.equals(LINE_STRING_TYPE)) {
            return decodeLineString(bson);
        } else if (type.equals(MULTI_LINE_STRING_TYPE)) {
            return decodeMultiLineString(bson);
        } else if (type.equals(POLYGON_TYPE)) {
            return decodePolygon(bson);
        } else if (type.equals(MULTI_POLYGON_TYPE)) {
            return decodeMultiPolygon(bson);
        } else if (type.equals(GEOMETRY_COLLECTION_TYPE)) {
            return decodeGeometryCollection(bson);
        } else {
            throw new GeometryConverterException("Unkown geometry type: " + type);
        }
    }

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

    @Override
    public LineString decodeLineString(BSONObject bson) throws GeometryConverterException {
        Coordinate[] coordinates = decodeCoordinates(requireCoordinates(bson));
        return factory.createLineString(coordinates);
    }

    @Override
    public MultiPoint decodeMultiPoint(BSONObject bson) throws GeometryConverterException {
        Coordinate[] coordinates = decodeCoordinates(requireCoordinates(bson));
        return factory.createMultiPoint(coordinates);
    }

    @Override
    public Point decodePoint(BSONObject bson) throws GeometryConverterException {
        Coordinate parsed = decodeCoordinate(requireCoordinates(bson));
        return factory.createPoint(parsed);
    }

    @Override
    public Polygon decodePolygon(BSONObject bson) throws GeometryConverterException {
        BasicDBList coordinates = requireCoordinates(bson);
        return decodePolygonCoordinates(coordinates);
    }

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

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

    @Override
    public Geometry decode(BSONObject json) throws GeometryConverterException {
        return json == null ? null : decodeGeometry(json);
    }

    @Override
    public BSONObject encode(Geometry value) throws GeometryConverterException {
        return value == null ? null : encodeGeometry(value);
    }
}