/*
* Copyright (C) 2014 Alec Dhuse
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package co.foldingmap.mapImportExport;
import co.foldingmap.map.vector.Region;
import co.foldingmap.map.vector.LinearRing;
import co.foldingmap.map.vector.MultiGeometry;
import co.foldingmap.map.vector.LatLonAltBox;
import co.foldingmap.map.vector.VectorLayer;
import co.foldingmap.map.vector.CoordinateList;
import co.foldingmap.map.vector.VectorObject;
import co.foldingmap.map.vector.LevelOfDetail;
import co.foldingmap.map.vector.LineString;
import co.foldingmap.map.vector.MapIcon;
import co.foldingmap.map.vector.Polygon;
import co.foldingmap.map.vector.Coordinate;
import co.foldingmap.map.vector.MapPoint;
import co.foldingmap.map.vector.InnerBoundary;
import co.foldingmap.map.themes.PolygonStyle;
import co.foldingmap.map.themes.ColorHelper;
import co.foldingmap.map.themes.MapTheme;
import co.foldingmap.map.themes.ColorStyle;
import co.foldingmap.map.themes.LabelStyle;
import co.foldingmap.map.themes.IconStyle;
import co.foldingmap.map.themes.LineStyle;
import co.foldingmap.map.themes.StyleMap;
import co.foldingmap.map.DigitalMap;
import co.foldingmap.map.Layer;
import co.foldingmap.map.raster.ImageOverlay;
import co.foldingmap.xml.XmlOutput;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
*
* @author Alec
*/
public class KmlExporter {
public void exportGroundOverlay(XmlOutput kmlWriter, ImageOverlay groundOverlay) {
LatLonAltBox bounds = groundOverlay.getBounds();
kmlWriter.openTag("GroundOverlay id=\"" + groundOverlay.getID() + "\"");
exportIcon(kmlWriter, groundOverlay.getMapIcon());
kmlWriter.openTag("LatLonBox");
kmlWriter.writeTag("north", Float.toString(bounds.getNorth()));
kmlWriter.writeTag("south", Float.toString(bounds.getSouth()));
kmlWriter.writeTag("east", Float.toString(bounds.getEast()));
kmlWriter.writeTag("west", Float.toString(bounds.getWest()));
kmlWriter.writeTag("rotation", "0");
kmlWriter.closeTag("LatLonBox");
kmlWriter.closeTag("GroundOverlay");
}
/**
* Writes out the KML for the MapIcon Object.
*
* @param kmlWriter
* @param mapIcon
*/
public void exportIcon(XmlOutput kmlWriter, MapIcon mapIcon) {
kmlWriter.openTag("Icon id=\"" + mapIcon.getID() + "\"");
kmlWriter.writeTag("href", mapIcon.getFileAddress());
kmlWriter.writeTag("refreshMode", Integer.toString(mapIcon.getRefreshMode()));
kmlWriter.writeTag("refreshInterval", Float.toString(mapIcon.getRefreshInterval()));
kmlWriter.writeTag("viewRefreshMode", Integer.toString(mapIcon.getViewRefreshMode()));
kmlWriter.closeTag("Icon");
}
/**
* Writes an IconStyle to KML.
*
* @param kmlWriter
*/
public static void exportIconStyle(XmlOutput kmlWriter, IconStyle style) {
try {
kmlWriter.openTag ("Style id=\"" + style.getID() + "\"");
kmlWriter.openTag ("IconStyle");
kmlWriter.writeTag("color", ColorHelper.getColorHexAlphabetical(style.getFillColor()));
if (style.getColorMode() == ColorStyle.NORMAL) {
kmlWriter.writeTag("colorMode", "normal");
} else if (style.getColorMode() == ColorStyle.RANDOM) {
kmlWriter.writeTag("colorMode", "random");
}
kmlWriter.writeTag("scale", Float.toString(style.getScale()));
kmlWriter.writeTag("heading", Float.toString(style.getHeading()));
if (style.getImageFile() != null) {
kmlWriter.openTag ("Icon");
kmlWriter.writeTag("href", style.getImageFile().getName());
kmlWriter.closeTag("Icon");
}
kmlWriter.closeTag("IconStyle");
if (style.getLabel() != null)
exportLabelStyle(kmlWriter, style.getLabel());
kmlWriter.closeTag("Style");
} catch (Exception e) {
System.err.println("Error in KmlExporter.exportIconStyle(KmlOutpu, IconStyle) - " + e);
}
}
/**
* Writes out KML for this LabelStyle.
*
* @param kmlWriter
*/
public static void exportLabelStyle(XmlOutput kmlWriter, LabelStyle style) {
kmlWriter.openTag ("LabelStyle");
kmlWriter.writeTag("color", ColorHelper.getColorHexAlphabetical(style.getFillColor()));
kmlWriter.closeTag("LabelStyle");
}
/**
* Writes a LinearRing as KML
*
* @param kmlWriter
* @param ring
*/
public static void exportLinearRing(XmlOutput kmlWriter, LinearRing ring) {
try {
kmlWriter.openTag ("Placemark");
kmlWriter.writeTag("name", ring.getName());
writeCustomDataFieldsAsXML(kmlWriter, ring);
if (ring.hasDisplayableText(ring.getDescription()) && !ring.getDescription().equalsIgnoreCase("null"))
kmlWriter.writeTag("description", "<![CDATA[" + ring.getDescription() + "]]>");
kmlWriter.writeTag("styleUrl", "#" + ring.getObjectClass());
if (ring.getVisibility() != null) {
LatLonAltBox bounds = ring.getBoundingBox();
float max = Region.calculateLodFromTileZoom(ring.getVisibility().getMaxTileZoomLevel(), bounds);
float min = Region.calculateLodFromTileZoom(ring.getVisibility().getMinTileZoomLevel(), bounds);
LevelOfDetail lod = new LevelOfDetail(max, min);
Region r = new Region(ring.getName() + "-region", bounds, lod);
r.toXML(kmlWriter);
}
kmlWriter.openTag ("LinearRing");
if (ring.getAltitudeMode() == VectorObject.ABSOLUTE) {
kmlWriter.writeTag("altitudeMode", "absolute");
} else if (ring.getAltitudeMode() == VectorObject.RELATIVE_TO_GROUND) {
kmlWriter.writeTag("altitudeMode", "relativeToGround");
} else {
kmlWriter.writeTag("altitudeMode", "clampToGround");
}
kmlWriter.writeTag("coordinates", getCoordinateString(ring.getCoordinateList()));
kmlWriter.closeTag("LineString");
kmlWriter.closeTag("LinearRing");
kmlWriter.closeTag("Placemark");
} catch (Exception e) {
System.err.println("Error in KmlExporter.exportLinearRing(KmlWriter) Object: " + ring.getName() + " - " + e);
}
}
/**
* Writes LineString KML to the xmlWriter.
*
* @param kmlWriter
* @param line
*/
public static void exportLineString(XmlOutput kmlWriter, LineString line) {
try {
kmlWriter.openTag ("Placemark");
kmlWriter.writeTag("name", line.getName());
writeCustomDataFieldsAsXML(kmlWriter, line);
if (line.hasDisplayableText(line.getDescription()) && !line.getDescription().equalsIgnoreCase("null"))
kmlWriter.writeTag("description", "<![CDATA[" + line.getDescription() + "]]>");
kmlWriter.writeTag("styleUrl", "#" + line.getObjectClass());
if (line.getVisibility() != null) {
LatLonAltBox bounds = line.getBoundingBox();
float max = Region.calculateLodFromTileZoom(line.getVisibility().getMaxTileZoomLevel(), bounds);
float min = Region.calculateLodFromTileZoom(line.getVisibility().getMinTileZoomLevel(), bounds);
LevelOfDetail lod = new LevelOfDetail(max, min);
Region r = new Region(line.getName() + "-region", bounds, lod);
r.toXML(kmlWriter);
}
kmlWriter.openTag ("LineString");
if (line.getAltitudeMode() == VectorObject.ABSOLUTE) {
kmlWriter.writeTag("altitudeMode", "absolute");
} else if (line.getAltitudeMode() == VectorObject.RELATIVE_TO_GROUND) {
kmlWriter.writeTag("altitudeMode", "relativeToGround");
} else {
kmlWriter.writeTag("altitudeMode", "clampToGround");
}
kmlWriter.writeTag("coordinates", getCoordinateString(line.getCoordinateList()));
kmlWriter.closeTag("LineString");
kmlWriter.closeTag("LineString");
kmlWriter.closeTag("Placemark");
} catch (Exception e) {
System.out.println("Error in KmlExporter.exportLineString(KmlWriter, LineString) Object: " + line.getName() + " - " + e);
}
}
/**
* Writes out a LineStyle to KML.
*
* @param kmlWriter
*/
public static void exportLineStyle(XmlOutput kmlWriter, LineStyle style) {
kmlWriter.openTag ("Style id=\"" + style.getID() + "\"");
kmlWriter.openTag ("LineStyle");
kmlWriter.writeTag("color", ColorHelper.getColorHexAlphabetical(style.getFillColor()));
kmlWriter.writeTag("width", Float.toString(style.getLineWidth()));
if (style.isOutlined()) {
kmlWriter.writeTag("gx:outerColor", ColorHelper.getColorHexAlphabetical(style.getOutlineColor()));
}
kmlWriter.closeTag("LineStyle");
kmlWriter.closeTag("Style");
}
public static void exportMap(XmlOutput kmlWriter, DigitalMap mapData) {
double mapLatitude, mapLongitude, mapZoomLevel;
try {
mapLatitude = mapData.getLastMapView().getMapProjection().getReferenceLatitude() ;
mapLongitude = mapData.getLastMapView().getMapProjection().getReferenceLongitude() ;
mapZoomLevel = mapData.getLastMapView().getZoomLevel();
kmlWriter.writeTextLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
kmlWriter.openTag("kml xmlns=\"http://www.opengis.net/kml/2.2\"");
kmlWriter.openTag("Document");
kmlWriter.writeTag("name", mapData.getName());
kmlWriter.writeTag("open", "1");
kmlWriter.openTag ("LookAt");
kmlWriter.writeTag("longitude", Double.toString(mapLongitude));
kmlWriter.writeTag("latitude", Double.toString(mapLatitude));
kmlWriter.closeTag("LookAt");
//export theme
exportTheme(kmlWriter, mapData.getTheme());
//layer objects
for (Layer currentLayer: mapData.getLayers()) {
if (currentLayer instanceof VectorLayer) {
exportVectorLayer(kmlWriter, (VectorLayer) currentLayer);
} else {
currentLayer.toXML(kmlWriter);
}
}
kmlWriter.closeTag("Document");
kmlWriter.closeTag("kml");
} catch (Exception e) {
System.err.println("Error in KmlExporter.exportMap(KmlWritter, MapData) - " + e);
}
}
/**
* Writes KML for a given VectorObject.
*
* @param kmlWriter
* @param object
*/
public static void exportMapObject(XmlOutput kmlWriter, VectorObject object) {
try {
if (object instanceof LinearRing) {
exportLinearRing(kmlWriter, (LinearRing) object);
} else if (object instanceof LineString) {
exportLineString(kmlWriter, (LineString) object);
} else if (object instanceof MapPoint) {
exportMapPoint(kmlWriter, (MapPoint) object);
} else if (object instanceof MultiGeometry) {
getMultiGeometryXML(kmlWriter, (MultiGeometry) object);
} else if (object instanceof Polygon) {
exportPolygon(kmlWriter, (Polygon) object);
} else {
object.toXML(kmlWriter);
}
} catch (Exception e) {
System.err.println("Error in KmlExport.getMapObjectXML(KmlOutput, MapObject) - " + e);
}
}
/**
* Writes a MapPoint to KML
*
* @param kmlWriter
* @param point
*/
public static void exportMapPoint(XmlOutput kmlWriter, MapPoint point) {
kmlWriter.openTag ("Placemark");
kmlWriter.writeTag("name", point.getName());
writeCustomDataFieldsAsXML(kmlWriter, point);
if (point.hasDisplayableText(point.getDescription()) && !point.getDescription().equalsIgnoreCase("null"))
kmlWriter.writeTag("description", "<![CDATA[" + point.getDescription() + "]]>");
kmlWriter.writeTag("styleUrl", point.getObjectClass());
if (point.getVisibility() != null) {
LatLonAltBox bounds = point.getBoundingBox();
float max = Region.calculateLodFromTileZoom(point.getVisibility().getMaxTileZoomLevel(), bounds);
float min = Region.calculateLodFromTileZoom(point.getVisibility().getMinTileZoomLevel(), bounds);
LevelOfDetail lod = new LevelOfDetail(max, min);
Region r = new Region(point.getName() + "-region", bounds, lod);
r.toXML(kmlWriter);
}
kmlWriter.openTag ("Point");
kmlWriter.writeTag("coordinates", getCoordinateString(point.getCoordinateList()));
kmlWriter.closeTag("Point");
kmlWriter.closeTag("Placemark");
}
/**
* Outputs a PolygonStyle as KML.
*
* @param kmlWriter
*/
public static void exportPolyStyle(XmlOutput kmlWriter, PolygonStyle style) {
kmlWriter.openTag ("Style id=\"" + style.getID() + "\"");
kmlWriter.openTag ("PolyStyle");
kmlWriter.writeTag("color", ColorHelper.getColorHexAlphabetical(style.getFillColor()));
if (style.getColorMode() == ColorStyle.NORMAL) {
kmlWriter.writeTag("colorMode", "normal");
} else if (style.getColorMode() == ColorStyle.RANDOM) {
kmlWriter.writeTag("colorMode", "random");
}
if (style.isFilled()) {
kmlWriter.writeTag("fill", "1");
} else {
kmlWriter.writeTag("fill", "0");
}
if (style.isOutlined()) {
kmlWriter.writeTag("outline", "1");
//No polygon outling color suported in KML
//kmlWriter.writeTag("gx:outlineColor", ColorHelper.getColorHexAlphabetical(style.getOutlineColor()));
} else {
kmlWriter.writeTag("outline", "0");
}
kmlWriter.closeTag("PolyStyle");
kmlWriter.closeTag("Style");
}
public static void exportVectorLayer(XmlOutput kmlWriter, VectorLayer layer) {
try {
kmlWriter.openTag ("Folder");
kmlWriter.writeTag("name", layer.getName());
if (layer.getDescription() != null) {
if (!layer.getDescription() .equals("") && !layer.getDescription() .equalsIgnoreCase("null"))
kmlWriter.writeTag("description", layer.getDescription());
}
if (layer.hasTimeSpan()) {
kmlWriter.openTag ("TimeSpan");
kmlWriter.writeTag("begin", layer.getTimeSpanBeginString());
kmlWriter.writeTag("end", layer.getTimeSpanEndString());
kmlWriter.closeTag("TimeSpan");
}
//get xml for each object
for (int i = 0; i < layer.getObjectList().size(); i++) {
VectorObject object = layer.getObjectList().get(i);
exportMapObject(kmlWriter, object);
}
kmlWriter.closeTag("Folder");
} catch (Exception e) {
System.err.println("Error in KmlExporter.exportVectorLayer(KmlWriter, VectorLayer) - " + e);
}
}
/**
* Returns a Coordinate String in the KML format.
*
* @param coordinateString
* @return
*/
public static String getCoordinateString(CoordinateList<Coordinate> coordinateString) {
String cString;
StringBuilder coord;
coord = new StringBuilder();
try {
for (Coordinate currentCoordinate: coordinateString) {
coord.append(currentCoordinate.getLongitude());
coord.append(",");
coord.append(currentCoordinate.getLatitude());
coord.append(",");
coord.append(currentCoordinate.getAltitude());
coord.append(" ");
}
} catch (Exception e) {
System.err.println("Error in CoordinateList.getCoordinateString() - " + e);
}
cString = coord.toString();
//remove last space
return cString.substring(0, coord.length() - 1);
}
/**
* Writes MultiGeometry as KML
*
* @param kmlWriter
* @param mg
*/
public static void getMultiGeometryXML(XmlOutput kmlWriter, MultiGeometry mg) {
try {
kmlWriter.openTag ("Placemark");
kmlWriter.writeTag("name", mg.getName());
writeCustomDataFieldsAsXML(kmlWriter, mg);
if (MultiGeometry.hasDisplayableText(mg.getDescription()) && !mg.getDescription().equalsIgnoreCase("null"))
kmlWriter.writeTag("description", "<![CDATA[" + mg.getDescription() + "]]>");
kmlWriter.openTag ("MultiGeometry id=\"" + mg.getName() + "\"");
for (int i = 0; i < mg.getComponentObjects().size(); i++) {
VectorObject currentMapObject = mg.getComponentObjects().get(i);
currentMapObject.toXML(kmlWriter);
}
writeCustomDataFieldsAsXML(kmlWriter, mg);
kmlWriter.closeTag("MultiGeometry");
kmlWriter.closeTag("Placemark");
} catch (Exception e) {
System.err.println("Error in MultiGeometry.toXML(KmlWriter) Object: " + mg.getName() + " - " + e);
}
}
/**
* Writes Polygon as KML.
*
* @param kmlWriter
* @param poly
*/
public static void exportPolygon(XmlOutput kmlWriter, Polygon poly) {
try {
kmlWriter.openTag ("Placemark");
kmlWriter.writeTag("name", poly.getName());
if (poly.hasDisplayableText(poly.getDescription()) && !poly.getDescription().equalsIgnoreCase("null"))
kmlWriter.writeTag("description", "<![CDATA[" + poly.getDescription() + "]]>");
kmlWriter.writeTag("styleUrl", "#" + poly.getObjectClass());
if (poly.getVisibility() != null) {
LatLonAltBox bounds = poly.getBoundingBox();
float max = Region.calculateLodFromTileZoom(poly.getVisibility().getMaxTileZoomLevel(), bounds);
float min = Region.calculateLodFromTileZoom(poly.getVisibility().getMinTileZoomLevel(), bounds);
LevelOfDetail lod = new LevelOfDetail(max, min);
Region r = new Region(poly.getName() + "-region", bounds, lod);
r.toXML(kmlWriter);
}
writeCustomDataFieldsAsXML(kmlWriter, poly);
kmlWriter.openTag ("Polygon");
kmlWriter.writeTag("extrude", "0");
kmlWriter.writeTag("tessellate", "0");
kmlWriter.writeTag("altitudeMode", "clampToGround");
kmlWriter.openTag ("outerBoundaryIs");
kmlWriter.openTag ("LinearRing");
kmlWriter.writeTag("coordinates", getCoordinateString(poly.getCoordinateList()));
kmlWriter.closeTag("LinearRing");
kmlWriter.closeTag("outerBoundaryIs");
for (InnerBoundary ib: poly.getInnerBoundaries())
ib.toXML(kmlWriter);
kmlWriter.closeTag("Polygon");
kmlWriter.closeTag("Placemark");
} catch (Exception e) {
System.err.println("Error in KmlExporter.exportPolygon(KmlWriter, Polygon) Object: " + poly.getName() + " - " + e);
}
}
/**
* Writes out KML for a given MapTheme
*
* @param kmlWriter
* @param theme
*/
public static void exportTheme(XmlOutput kmlWriter, MapTheme theme) {
ArrayList<IconStyle> iconStylesVector;
ArrayList<LineStyle> lineStylesVector;
ArrayList<PolygonStyle> polygonStylesVector;
ArrayList<StyleMap> styleMapsVector;
try {
iconStylesVector = new ArrayList<IconStyle> (theme.getAllIconStyles());
lineStylesVector = new ArrayList<LineStyle> (theme.getAllLineStyles());
polygonStylesVector = new ArrayList<PolygonStyle> (theme.getAllPolygonStyles());
styleMapsVector = new ArrayList<StyleMap> (theme.getAllStyleMaps());
for (IconStyle currentIconStyle: iconStylesVector)
exportIconStyle(kmlWriter, currentIconStyle);
for (LineStyle currentStyle: lineStylesVector)
exportLineStyle(kmlWriter, currentStyle);
for (PolygonStyle currentStyle: polygonStylesVector)
exportPolyStyle(kmlWriter, currentStyle);
for (StyleMap currentStyle: styleMapsVector)
currentStyle.toXML(kmlWriter);
} catch (Exception e) {
System.err.println("Error in KmlExporter.exportTheme(KmlOutput, MapTheme) - " + e);
}
}
/**
* Writes all of the custom data fields as XML to the KMLWriter
*
* @param kmlWriter The writer to write CML to.
*/
public static void writeCustomDataFieldsAsXML(XmlOutput kmlBuffer, VectorObject object) {
Set set = object.getCustomDataFields().entrySet();
Iterator it = set.iterator();
if (set.size() > 0) {
kmlBuffer.openTag("ExtendedData");
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
kmlBuffer.openTag ("Data name=\"" + entry.getKey() + "\"");
kmlBuffer.writeTag("value", (String) entry.getValue());
kmlBuffer.closeTag("Data");
}
kmlBuffer.closeTag("ExtendedData");
}
}
}