/*
* 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.*;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* GeobufFeature encodes and decodes SimpleFeatures
* @author Jared Erickson
*/
public class GeobufFeature {
private GeobufGeometry geobufGeometry;
public GeobufFeature() {
this(new GeobufGeometry());
}
public GeobufFeature(GeobufGeometry geobufGeometry) {
this.geobufGeometry = geobufGeometry;
}
public GeobufGeometry getGeobufGeometry() {
return this.geobufGeometry;
}
public void encode(SimpleFeature feature, OutputStream out) throws IOException {
Geobuf.Data.Builder dataBuilder = Geobuf.Data.newBuilder();
for (AttributeDescriptor descriptor : feature.getFeatureType().getAttributeDescriptors()) {
if (!(descriptor instanceof GeometryDescriptor)) {
dataBuilder.addKeys(descriptor.getLocalName());
}
}
dataBuilder.setDimensions(geobufGeometry.getDimension());
dataBuilder.setPrecision(geobufGeometry.getPrecision());
dataBuilder.setFeature(encode(feature));
dataBuilder.build().writeTo(out);
}
public SimpleFeature decode(InputStream in) throws IOException {
Geobuf.Data data = Geobuf.Data.parseFrom(in);
GeobufFeatureType geobufFeatureType = new GeobufFeatureType();
return decode(data, new SimpleFeatureBuilder(geobufFeatureType.getFeatureType("features", data)));
}
protected Geobuf.Data.Feature encode(SimpleFeature feature) {
Geobuf.Data.Feature.Builder featureBuilder = Geobuf.Data.Feature.newBuilder();
int i = 0;
for (AttributeDescriptor attributeDescriptor : feature.getFeatureType().getAttributeDescriptors()) {
Object value = feature.getAttribute(attributeDescriptor.getName());
if (attributeDescriptor instanceof GeometryDescriptor) {
featureBuilder.setGeometry(geobufGeometry.encode((Geometry)feature.getDefaultGeometry()));
} else {
featureBuilder.addValues(i, encodeValue(attributeDescriptor, value));
i++;
}
}
return featureBuilder.build();
}
protected Geobuf.Data.Value encodeValue(AttributeDescriptor attributeDescriptor, Object value) {
Geobuf.Data.Value.Builder builder = Geobuf.Data.Value.newBuilder();
if (value instanceof String) {
builder.setStringValue((String)value);
} else if (value instanceof Integer) {
builder.setPosIntValue((Integer) value);
} else if (value instanceof Double) {
builder.setDoubleValue((Double) value);
} else if (value instanceof Boolean) {
builder.setBoolValue((Boolean)value);
} else {
builder.setStringValue(value != null ? value.toString() : null);
}
return builder.build();
}
protected SimpleFeature decode(Geobuf.Data data) throws IOException {
GeobufFeatureType geobufFeatureType = new GeobufFeatureType();
return decode(data, 0, new SimpleFeatureBuilder(geobufFeatureType.getFeatureType("features", data)));
}
protected SimpleFeature decode(Geobuf.Data data, SimpleFeatureBuilder featureBuilder) {
return decode(data, 0, featureBuilder);
}
protected SimpleFeature decode(Geobuf.Data data, int index, SimpleFeatureBuilder featureBuilder) {
if (data.getDataTypeCase() == Geobuf.Data.DataTypeCase.GEOMETRY) {
if (index > 0) {
return null;
}
featureBuilder.set(featureBuilder.getFeatureType().getGeometryDescriptor().getLocalName(),
geobufGeometry.decode(data.getGeometry()));
} else if (data.getDataTypeCase() == Geobuf.Data.DataTypeCase.FEATURE) {
if (index > 0) {
return null;
}
featureBuilder.set(featureBuilder.getFeatureType().getGeometryDescriptor().getLocalName(),
geobufGeometry.decode(data.getFeature().getGeometry()));
int keyCount = data.getKeysCount();
for (int j = 0; j < keyCount; j++) {
String key = data.getKeys(j);
Object value = getValue(data.getFeature().getValues(j));
featureBuilder.set(key, value);
}
} else if (data.getDataTypeCase() == Geobuf.Data.DataTypeCase.FEATURE_COLLECTION) {
if (index >= data.getFeatureCollection().getFeaturesCount()) {
return null;
}
Geobuf.Data.Feature feature = data.getFeatureCollection().getFeatures(index);
featureBuilder.set(featureBuilder.getFeatureType().getGeometryDescriptor().getLocalName(),
geobufGeometry.decode(feature.getGeometry()));
int keyCount = data.getKeysCount();
for (int j = 0; j < keyCount; j++) {
String key = data.getKeys(j);
Object value = feature.getValuesCount() > j ? getValue(feature.getValues(j)) : null;
featureBuilder.set(key, value);
}
}
return featureBuilder.buildFeature(String.valueOf(index));
}
protected Object getValue(Geobuf.Data.Value value) {
if (value.getValueTypeCase() == Geobuf.Data.Value.ValueTypeCase.STRING_VALUE) {
return value.getStringValue();
} else if (value.getValueTypeCase() == Geobuf.Data.Value.ValueTypeCase.POS_INT_VALUE) {
return value.getPosIntValue();
} else if (value.getValueTypeCase() == Geobuf.Data.Value.ValueTypeCase.NEG_INT_VALUE) {
return value.getNegIntValue();
} else if (value.getValueTypeCase() == Geobuf.Data.Value.ValueTypeCase.DOUBLE_VALUE) {
return value.getDoubleValue();
} else if (value.getValueTypeCase() == Geobuf.Data.Value.ValueTypeCase.BOOL_VALUE) {
return value.getBoolValue();
} else if (value.getValueTypeCase() == Geobuf.Data.Value.ValueTypeCase.JSON_VALUE) {
return value.getJsonValue();
} else {
return null;
}
}
}