package it.geosolutions.android.map.wfs.geojson;
import static it.geosolutions.android.map.wfs.geojson.GeoJsonConstants.COORDINATES;
import static it.geosolutions.android.map.wfs.geojson.GeoJsonConstants.TYPE;
import static it.geosolutions.android.map.wfs.geojson.GeoJsonConstants.TYPE_GEOMETRYCOLLECTION;
import static it.geosolutions.android.map.wfs.geojson.GeoJsonConstants.TYPE_LINESTRING;
import static it.geosolutions.android.map.wfs.geojson.GeoJsonConstants.TYPE_MULTILINESTRING;
import static it.geosolutions.android.map.wfs.geojson.GeoJsonConstants.TYPE_MULTIPOINT;
import static it.geosolutions.android.map.wfs.geojson.GeoJsonConstants.TYPE_MULTIPOLYGON;
import static it.geosolutions.android.map.wfs.geojson.GeoJsonConstants.TYPE_POINT;
import static it.geosolutions.android.map.wfs.geojson.GeoJsonConstants.TYPE_POLYGON;
import java.lang.reflect.Type;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
/**
* <JsonDeserializer> for GeoJson Geometry part
* @author Lorenzo Natali (lorenzo.natali at geo-solutions.it)
* Supports :
* * POINT
* * MULTIPOINT
* * LINESTRING
* * POLYGON
* Does **not** support yet:
* * MultiLineString
*
*/
public class GeometryJsonDeserializer implements JsonDeserializer<Geometry> {
@Override
public Geometry deserialize(JsonElement json, Type type,
JsonDeserializationContext context) throws JsonParseException {
JsonObject obj = json.getAsJsonObject();
String geometryType = obj.get(TYPE) != null ? obj.get(TYPE).getAsString() :null ;
if(geometryType == null){
return null;
}
GeometryFactory fact = new GeometryFactory();
//case Point
if (geometryType.equals(TYPE_POINT)) {
JsonElement jc = obj.get(COORDINATES);
if(jc != null){
return fact.createPoint(getCoordinates(jc.getAsJsonArray()));
}
} else if (geometryType.equals(TYPE_MULTIPOINT)) {
JsonElement jc = obj.get(COORDINATES);
if(jc != null){
return fact.createMultiPoint(getCoordinatesArray(jc.getAsJsonArray()));
}
} else if (geometryType.equals(TYPE_LINESTRING)) {
JsonElement jc = obj.get(COORDINATES);
if(jc != null){
return fact.createLineString(getCoordinatesArray(jc.getAsJsonArray()));
}
} else if (geometryType.equals(TYPE_MULTILINESTRING)) {
JsonElement jc = obj.get(COORDINATES);
if(jc != null){
JsonArray ja = jc.getAsJsonArray();
if(ja != null){
int ja_size = ja.size();
LineString[] lineStringArray = new LineString[ja_size];
for(int i = 0; i < ja_size ; i++){
lineStringArray[i] = fact.createLineString(getCoordinatesArray(ja.get(i).getAsJsonArray()));
}
return fact.createMultiLineString(lineStringArray);
}
}
} else if (geometryType.equals(TYPE_POLYGON)) {
JsonElement jc = obj.get(COORDINATES);
if(jc != null){
//check if this polygon contains inner polygons
if(jc.getAsJsonArray().size() > 1){
final int holesCount = jc.getAsJsonArray().size() - 1;
LinearRing[] holes = new LinearRing[holesCount];
for(int i = 0; i < holesCount;i++){
holes[i] = getLinearRingFromCoordinates(jc.getAsJsonArray().get(i + 1).getAsJsonArray(), fact);
}
return fact.createPolygon(getLinearRingFromCoordinates(jc.getAsJsonArray().get(0).getAsJsonArray(), fact), holes);
}else if(jc.getAsJsonArray().size() == 1){//there is one outer polygon
return fact.createPolygon(getCoordinatesArray(jc.getAsJsonArray().get(0).getAsJsonArray()));
}
}
} else if (geometryType.equals(TYPE_MULTIPOLYGON)) {
// NOT SUPPORTED YET
} else if (geometryType.equals(TYPE_GEOMETRYCOLLECTION)) {
// NOT SUPPORTED YET
}
return null;
}
/**
* convert a <JsonArray> into a <LinearRing>
* @param coordinatesArray (array of arrays)
* @param fact the GeometryFactory
* @return
*/
private LinearRing getLinearRingFromCoordinates(JsonArray coordinatesArray, GeometryFactory fact){
return new LinearRing(fact.getCoordinateSequenceFactory().create(getCoordinatesArray(coordinatesArray)), fact);
}
/**
* convert a <JsonArray> into a <Coordinate> array (case <LineString> ...)
* @param coordinatesArray (array of arrays)
* @return
*/
private Coordinate[] getCoordinatesArray(JsonArray coordinatesArray) {
final Coordinate[] result = new Coordinate[coordinatesArray.size()];
//iteration on coordinates elements
for (int i = 0; i < result.length; i++) {
final JsonArray jca = coordinatesArray.get(i).getAsJsonArray();
//create the single coordinates
result[i] = getCoordinates(jca);
}
return result;
}
/**
* convert a <JsonArray> into a <Coordinate> object (case <Point>)
* @param coordinatesArray (array of latitude - longitude)
* @return
*/
private Coordinate getCoordinates(JsonArray jca) {
if (jca!=null){
if(jca.size() == 2 ){
Coordinate cc = new Coordinate(jca.get(0).getAsDouble(),jca.get(1).getAsDouble());
return cc;
}else if(jca.size() == 3){
Coordinate cc = new Coordinate(jca.get(0).getAsDouble(),jca.get(1).getAsDouble(),jca.get(2).getAsDouble());
return cc;
}
}
return null;
}
}