/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved. * This code is licensed under the GPL 2.0 license, availible at the root * application directory. */ package org.geoserver.kml; import org.geoserver.wms.WMSMapContent; import org.geotools.gml.producer.GeometryTransformer; import org.geotools.xml.transform.Translator; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import com.vividsolutions.jts.geom.Geometry; /** * Geometry transformer for KML geometries. * <p> * While KML geometry encoding is quite similar to GML, there are a couple of tweaks: * <ul><li>the GML namespace is not used </li> * <li>there are a couple of extra tags that can be inserted to tell the client * how to treat 3d data (eg, <code><extrude></code> and * <code><altitudeMode></code>) </li> * </ul> * </p> * @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org */ public class KMLGeometryTransformer extends GeometryTransformer { static final String[] validAltitudeModes= new String[]{ "relativeToGround", "absolute", "clampToGround" }; public Translator createTranslator(ContentHandler handler, WMSMapContent context) { return new KMLGeometryTranslator(handler, numDecimals, useDummyZ, context); } /** * Subclass which sets prefix and nsuri to null. */ public static class KMLGeometryTranslator extends GeometryTranslator { private boolean extrude = true; private String altitudeMode = "relativeToGround"; private boolean extrudeEnabled = true; private static final String[] GEOMETRYNAMES = new String[] { "Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon", "GeometryCollection" }; public KMLGeometryTranslator( ContentHandler handler, int numDecimals, boolean useDummyZ, WMSMapContent context ) { //super(handler, "kml", "http://earth.google.com/kml/2.0" ); super(handler, null, null, numDecimals, useDummyZ, 3); coordWriter = new KMLCoordinateWriter(numDecimals, useDummyZ); String extrudeValue = (String)context.getRequest().getFormatOptions().get("extrude"); if (extrudeValue != null){ extrude = Boolean.valueOf(extrudeValue).booleanValue(); } String requestedAltitudeMode = (String)context.getRequest().getFormatOptions().get("altitudeMode"); if (requestedAltitudeMode != null){ for (String mode : validAltitudeModes){ if (mode.equalsIgnoreCase(requestedAltitudeMode.trim())){ altitudeMode = mode; } } } } public void encode(Object o, String srsname){ if (o instanceof Geometry){ extrudeEnabled = inspectGeometry((Geometry)o); } super.encode(o, srsname); } public void encode(Object o){ if (o instanceof Geometry){ extrudeEnabled = inspectGeometry((Geometry)o); } super.encode(o); } public void encode(Geometry g, String srsname){ extrudeEnabled = inspectGeometry(g); super.encode(g, srsname); } public void encode(Geometry g){ extrudeEnabled = inspectGeometry(g); super.encode(g); } protected void start(String element, Attributes atts){ super.start(element,atts); if (isGeometryElement(element)){ insertExtrudeTags(); } } private boolean inspectGeometry(Geometry g){ double d = g.getCoordinate().z; return !(Double.isNaN(d) || d == 0); } public void insertExtrudeTags(){ if (extrudeEnabled){ element("extrude", extrude ? "1" : "0"); element("altitudeMode", altitudeMode); } } public void insertExtrudeTags(Geometry g){ if (inspectGeometry(g)){ element("extrude", extrude ? "1" : "0"); element("altitudeMode", altitudeMode); } } private boolean isGeometryElement(String elementName){ for (String name : GEOMETRYNAMES){ if (name.equals(elementName)) return true; } return false; } } }