/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2015, Open Source Geospatial Foundation (OSGeo)
*
* 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.geotools.data.geobuf;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import org.geotools.data.memory.MemoryDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* GeobufFeatureCollection encodes and decodes SimpleFeatureCollections.
* @author Jared Erickson
*/
public class GeobufFeatureCollection {
private GeobufFeature geobufFeature;
public GeobufFeatureCollection() {
this(new GeobufFeature());
}
public GeobufFeatureCollection(GeobufFeature geobufFeature) {
this.geobufFeature = geobufFeature;
}
public SimpleFeatureCollection decode(InputStream in) throws IOException {
Geobuf.Data data = Geobuf.Data.parseFrom(in);
return decode(data);
}
public void encode(SimpleFeatureCollection featureCollection, OutputStream out) throws IOException {
encode(featureCollection).writeTo(out);
}
protected SimpleFeatureCollection decode(Geobuf.Data data) throws IOException {
GeobufFeatureType geobufFeatureType = new GeobufFeatureType(
geobufFeature.getGeobufGeometry().getPrecision(), geobufFeature.getGeobufGeometry().getDimension());
SimpleFeatureType featureType = geobufFeatureType.getFeatureType("features", data);
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
MemoryDataStore memoryDataStore = new MemoryDataStore(featureType);
for (int i = 0; i < data.getFeatureCollection().getFeaturesCount(); i++) {
memoryDataStore.addFeature(geobufFeature.decode(data, i, featureBuilder));
}
return memoryDataStore.getFeatureSource("features").getFeatures();
}
protected Geobuf.Data.FeatureCollection encodeAsFeatureCollection(SimpleFeatureCollection featureCollection) {
Geobuf.Data.FeatureCollection.Builder featureCollectionBuilder = Geobuf.Data.FeatureCollection.newBuilder();
SimpleFeatureIterator it = featureCollection.features();
try {
while(it.hasNext()) {
featureCollectionBuilder.addFeatures(geobufFeature.encode(it.next()));
}
} finally {
it.close();
}
return featureCollectionBuilder.build();
}
protected Geobuf.Data encode(SimpleFeatureCollection featureCollection) {
Geobuf.Data.Builder dataBuilder = Geobuf.Data.newBuilder();
for (AttributeDescriptor descriptor : featureCollection.getSchema().getAttributeDescriptors()) {
if (!(descriptor instanceof GeometryDescriptor)) {
dataBuilder.addKeys(descriptor.getLocalName());
}
}
dataBuilder.setDimensions(geobufFeature.getGeobufGeometry().getDimension());
dataBuilder.setPrecision(geobufFeature.getGeobufGeometry().getPrecision());
dataBuilder.setFeatureCollection(encodeAsFeatureCollection(featureCollection));
Geobuf.Data data = dataBuilder.build();
return data;
}
protected int countFeatures(InputStream in) throws IOException {
Geobuf.Data data = Geobuf.Data.parseFrom(in);
if (data.getDataTypeCase() == Geobuf.Data.DataTypeCase.GEOMETRY) {
return 1;
} else if (data.getDataTypeCase() == Geobuf.Data.DataTypeCase.FEATURE) {
return 1;
} else if (data.getDataTypeCase() == Geobuf.Data.DataTypeCase.FEATURE_COLLECTION) {
return data.getFeatureCollection().getFeaturesCount();
} else {
return -1;
}
}
protected ReferencedEnvelope getBounds(InputStream in) throws IOException {
Geobuf.Data data = Geobuf.Data.parseFrom(in);
if (data.getDataTypeCase() == Geobuf.Data.DataTypeCase.GEOMETRY) {
Geometry g = geobufFeature.getGeobufGeometry().decode(data.getGeometry());
Envelope env = g.getEnvelopeInternal();
return new ReferencedEnvelope(env.getMinX(), env.getMaxX(), env.getMinY(), env.getMaxY(), null);
} else if (data.getDataTypeCase() == Geobuf.Data.DataTypeCase.FEATURE) {
Geometry g = (Geometry) geobufFeature.decode(data).getDefaultGeometry();
Envelope env = g.getEnvelopeInternal();
return new ReferencedEnvelope(env.getMinX(), env.getMaxX(), env.getMinY(), env.getMaxY(), null);
} else if (data.getDataTypeCase() == Geobuf.Data.DataTypeCase.FEATURE_COLLECTION) {
SimpleFeatureCollection fc = decode(data);
return fc.getBounds();
} else {
return null;
}
}
}