/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wps.ppio;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.geoserver.config.GeoServer;
import org.geoserver.platform.GeoServerExtensions;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.store.ReprojectingFeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.referencing.CRS;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.type.Name;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CRSAuthorityFactory;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.Point;
/**
* Encoder class to encode SimpleFeatureCollection to GPX The encoder uses only a XMLStreamWriter for simplicity and performance sake.
*
*/
public class GpxEncoder {
boolean writeExtendedData = false;
Map<String, Class> trkAttributes = new HashMap<String, Class>();
Map<String, Class> wptAttributes = new HashMap<String, Class>();
Map<String, Class> rteAttributes = new HashMap<String, Class>();
String creator = "GeoServer";
String link = "http://www.geoserver.org";
DecimalFormat format;
public GpxEncoder(boolean writeExtendedData) {
this.writeExtendedData = writeExtendedData;
this.format = new DecimalFormat("#.######");
this.format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.ENGLISH));
trkAttributes.put("name", String.class);
trkAttributes.put("desc", String.class);
trkAttributes.put("name", String.class);
trkAttributes.put("desc", String.class);
}
public void setCreator(String creator) {
this.creator = creator;
}
public void setLink(String link) {
this.link = link;
}
private Map<String, String> types = new HashMap<String, String>();
public void encode(OutputStream lFileOutputStream, SimpleFeatureCollection collection)
throws XMLStreamException, NoSuchAuthorityCodeException, FactoryException {
CRSAuthorityFactory crsFactory = CRS.getAuthorityFactory(true);
CoordinateReferenceSystem targetCRS = crsFactory
.createCoordinateReferenceSystem("EPSG:4326");
collection = new ReprojectingFeatureCollection(collection, targetCRS);
XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance();
XMLStreamWriter writer = xmlFactory.createXMLStreamWriter(lFileOutputStream);
writer.writeStartDocument();
writer.writeStartElement("gpx");
writer.writeAttribute("xmlns", "http://www.topografix.com/GPX/1/1");
if (link != null) {
writer.writeAttribute("xmlns:att", link);
}
writer.writeAttribute("version", "1.1");
if (creator != null) {
writer.writeAttribute("creator", creator);
}
writer.writeStartElement("metadata");
if (link != null && creator != null) {
writer.writeStartElement("link");
writer.writeAttribute("href", link);
writer.writeStartElement("text");
writer.writeCharacters(creator);
writer.writeEndElement();
writer.writeEndElement();
}
writer.writeStartElement("time");
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
writer.writeCharacters(sdf.format(calendar.getTime()));
writer.writeEndElement();
writer.writeEndElement(); // metadata
String schemaName = "";
FeatureIterator<SimpleFeature> iter = collection.features();
try {
while (iter.hasNext()) {
SimpleFeature f = iter.next();
Geometry g = (Geometry) f.getDefaultGeometry();
if (g instanceof MultiLineString) {
MultiLineString mls = (MultiLineString) g;
int numGeometries = mls.getNumGeometries();
writer.writeStartElement("trk");
if (writeExtendedData) {
writeData(writer, f);
}
for (int i = 0; i < numGeometries; i++) {
LineString ls = (LineString) mls.getGeometryN(i);
writeTrkSeg(writer, ls);
}
writer.writeEndElement();
} else if (g instanceof LineString) {
writeRte(writer, (LineString) g, f);
} else if (g instanceof MultiPoint) {
MultiPoint mpt = (MultiPoint) g;
int numGeometries = mpt.getNumGeometries();
for (int i = 0; i < numGeometries; i++) {
Point pt = (Point) mpt.getGeometryN(i);
writeWpt(writer, pt, f);
}
} else if (g instanceof Point) {
writeWpt(writer, (Point) g, f);
} else {
throw new IllegalArgumentException("Unsupported geometry type: "
+ g.getClass().getSimpleName());
}
}
} finally {
iter.close();
}
writer.writeEndDocument();
writer.flush();
writer.close();
return;
/*
*/
}
private void writeCoordinates(XMLStreamWriter writer, String ptElementName, LineString ls)
throws XMLStreamException {
Coordinate[] coordinates = ls.getCoordinates();
for (int ic = 0; ic < coordinates.length; ic++) {
writeWpt(writer, ptElementName, coordinates[ic].x, coordinates[ic].y, coordinates[ic].z);
}
}
private void writeWpt(XMLStreamWriter writer, String ptElementName, double x, double y, double z)
throws XMLStreamException {
writer.writeStartElement(ptElementName);
writer.writeAttribute("lat", format.format(y));
writer.writeAttribute("lon", format.format(x));
if (!Double.isNaN(z)) {
writer.writeAttribute("ele", format.format(z));
}
writer.writeEndElement();
}
private void writeTrkSeg(XMLStreamWriter writer, LineString ls) throws XMLStreamException {
writer.writeStartElement("trkseg");
writeCoordinates(writer, "trkpt", ls);
writer.writeEndElement();
}
private void writeRte(XMLStreamWriter writer, LineString ls, SimpleFeature f)
throws XMLStreamException {
writer.writeStartElement("rte");
if (writeExtendedData) {
writeData(writer, f);
}
writeCoordinates(writer, "rtept", ls);
writer.writeEndElement();
}
private void writeWpt(XMLStreamWriter writer, Point pt, SimpleFeature f)
throws XMLStreamException {
writer.writeStartElement("wpt");
Coordinate c = pt.getCoordinate();
writer.writeAttribute("lon", format.format(c.x));
writer.writeAttribute("lat", format.format(c.y));
if (!Double.isNaN(c.z)) {
writer.writeAttribute("ele", format.format(c.z));
}
if (writeExtendedData) {
writeData(writer, f);
}
writer.writeEndElement();
}
private void writeData(XMLStreamWriter writer, SimpleFeature f) throws XMLStreamException {
writer.writeStartElement("extensions");
for (Property p : f.getProperties()) {
Name name = p.getName();
if (!(p.getValue() instanceof Geometry) && p.getValue() != null) {
writer.writeStartElement("att:" + name.getLocalPart());
writer.writeCharacters(p.getValue().toString());
writer.writeEndElement();
}
}
writer.writeEndElement();
}
}