/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, 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. * */ /* * GeometryTransformer.java * * Created on October 24, 2003, 1:08 PM */ package org.geotools.gml.producer; import org.geotools.xml.transform.TransformerBase; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.CoordinateSequence; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.geom.impl.PackedCoordinateSequence; /** * Used to walk through GeometryObjects issuing SAX events * as needed. * <p> * Please note that this GeometryTransformer issues GML2 events, * the Coordinate * * @author Ian Schneider * * @source $URL$ */ public class GeometryTransformer extends TransformerBase { protected boolean useDummyZ = false; protected int numDecimals = 4; public void setUseDummyZ(boolean flag){ useDummyZ = flag; } public void setNumDecimals(int num) { numDecimals = num; } /** * @TODO remove constant from GometryTraslator contructor call */ public org.geotools.xml.transform.Translator createTranslator( ContentHandler handler) { return new GeometryTranslator(handler, numDecimals, useDummyZ); } public static class GeometryTranslator extends TranslatorSupport { protected CoordinateWriter coordWriter = new CoordinateWriter(); public GeometryTranslator(ContentHandler handler) { this(handler,"gml",GMLUtils.GML_URL); } public GeometryTranslator(ContentHandler handler, String prefix, String nsUri ) { super(handler,prefix,nsUri); coordWriter.setPrefix( prefix ); coordWriter.setNamespaceUri( nsUri ); } public GeometryTranslator(ContentHandler handler, int numDecimals) { this(handler,"gml",GMLUtils.GML_URL,numDecimals); } public GeometryTranslator(ContentHandler handler, String prefix, String nsUri, int numDecimals) { this(handler,prefix,nsUri); coordWriter = new CoordinateWriter(numDecimals, false); coordWriter.setPrefix( prefix ); coordWriter.setNamespaceUri( nsUri ); } public GeometryTranslator(ContentHandler handler, int numDecimals, boolean isDummyZEnabled) { this(handler,"gml",GMLUtils.GML_URL,numDecimals,isDummyZEnabled); } public GeometryTranslator(ContentHandler handler, String prefix, String nsUri, int numDecimals, boolean isDummyZEnabled) { this(handler,prefix,nsUri); coordWriter = new CoordinateWriter(numDecimals, isDummyZEnabled); coordWriter.setPrefix( prefix ); coordWriter.setNamespaceUri( nsUri ); } /** * Constructor for GeometryTranslator allowing the specification of the number of * valid dimension represented in the Coordinates. * @param handler * @param prefix * @param nsUri * @param numDecimals * @param isDummyZEnabled * @param dimension If this value is 3; the coordinate.z will be used rather than dummyZ * since 2.4.1 */ public GeometryTranslator(ContentHandler handler, String prefix, String nsUri, int numDecimals, boolean isDummyZEnabled, int dimension) { this(handler,prefix,nsUri); coordWriter = new CoordinateWriter(numDecimals, isDummyZEnabled, dimension ); coordWriter.setPrefix( prefix ); coordWriter.setNamespaceUri( nsUri ); } public boolean isDummyZEnabled(){ return coordWriter.isDummyZEnabled(); } public int getNumDecimals(){ return coordWriter.getNumDecimals(); } public void encode(Object o, String srsName) throws IllegalArgumentException { if (o instanceof Geometry) { encode((Geometry) o, srsName); } else { throw new IllegalArgumentException("Unable to encode " + o); } } public void encode(Object o) throws IllegalArgumentException { encode(o, null); } public void encode(Envelope bounds) { encode(bounds, null); } public void encode(Envelope bounds, String srsName) { // DJB: old behavior for null bounds: // //<gml:Box srsName="http://www.opengis.net/gml/srs/epsg.xml#0"> //<gml:coordinates decimal="." cs="," ts=" ">0,0 -1,-1</gml:coordinates> //</gml:Box> // // new behavior: // <gml:null>unknown</gml:null> if(bounds == null || bounds.isNull()) { encodeNullBounds(); return; // we're done! } String boxName = boxName(); if ((srsName == null) || srsName.equals("")) { start(boxName); } else { AttributesImpl atts = new AttributesImpl(); atts.addAttribute("", "srsName", "srsName", "", srsName); start(boxName, atts); } try { double[] coords = new double[4]; coords[0] = bounds.getMinX(); coords[1] = bounds.getMinY(); coords[2] = bounds.getMaxX(); coords[3] = bounds.getMaxY(); CoordinateSequence coordSeq = new PackedCoordinateSequence.Double(coords, 2); coordWriter.writeCoordinates(coordSeq, contentHandler); } catch (SAXException se) { throw new RuntimeException(se); } end(boxName); } /** * Method to be subclasses in order to allow for gml3 encoding for null enevelope. */ protected void encodeNullBounds() { start("null"); String text = "unknown"; try{ contentHandler.characters(text.toCharArray(), 0, text.length()); } catch(Exception e) //this shouldnt happen!! { System.out.println("got exception while writing null boundedby:"+e.getLocalizedMessage()); e.printStackTrace(); } end("null"); } /** * Method to be subclassed in order to allow for gml3 encoding of envelopes. * @return "Box" */ protected String boxName() { return "Box"; } /** * Encodes the given geometry with no srsName attribute and forcing 2D */ public void encode(Geometry geometry) { encode(geometry, null); } /** * Encodes the geometry in plain 2D using the given srsName attribute value * @see #encode(Geometry, String, int) */ public void encode(Geometry geometry, String srsName) { encode(geometry, srsName, 2); } /** * Encodes the given geometry with the provided srsName attribute and for the specified dimensions * @param geometry non null geometry to encode * @param srsName srsName attribute for the geometry, or <code>null</code> * @param dimensions shall laid between 1, 2, or 3. Number of coordinate dimensions to force. * TODO: dimensions is not being taken into account currently. Jody? */ public void encode(Geometry geometry, String srsName, final int dimensions) { String geomName = GMLUtils.getGeometryName(geometry); if ((srsName == null) || srsName.equals("")) { start(geomName); } else { AttributesImpl atts = new AttributesImpl(); atts.addAttribute("", "srsName", "srsName", "", srsName); start(geomName, atts); } int geometryType = GMLUtils.getGeometryType(geometry); CoordinateSequence coordSeq; switch (geometryType) { case GMLUtils.POINT: coordSeq = ((Point) geometry).getCoordinateSequence(); try { coordWriter.writeCoordinates(coordSeq, contentHandler); } catch (SAXException e) { throw new RuntimeException(e); } break; case GMLUtils.LINESTRING: coordSeq = ((LineString) geometry).getCoordinateSequence(); try { coordWriter.writeCoordinates(coordSeq, contentHandler); } catch (SAXException s) { throw new RuntimeException(s); } break; case GMLUtils.POLYGON: writePolygon((Polygon) geometry); break; case GMLUtils.MULTIPOINT: case GMLUtils.MULTILINESTRING: case GMLUtils.MULTIPOLYGON: case GMLUtils.MULTIGEOMETRY: writeMulti((GeometryCollection) geometry, GMLUtils.getMemberName(geometryType)); break; } end(geomName); } private void writePolygon(Polygon geometry) { String outBound = "outerBoundaryIs"; String lineRing = "LinearRing"; String inBound = "innerBoundaryIs"; start(outBound); start(lineRing); CoordinateSequence coordSeq; try { coordSeq = geometry.getExteriorRing().getCoordinateSequence(); coordWriter.writeCoordinates(coordSeq, contentHandler); } catch (SAXException s) { throw new RuntimeException(s); } end(lineRing); end(outBound); for (int i = 0, ii = geometry.getNumInteriorRing(); i < ii; i++) { start(inBound); start(lineRing); try { coordSeq = geometry.getInteriorRingN(i).getCoordinateSequence(); coordWriter.writeCoordinates(coordSeq, contentHandler); } catch (SAXException s) { throw new RuntimeException(s); } end(lineRing); end(inBound); } } private void writeMulti(GeometryCollection geometry, String member) { for (int i = 0, n = geometry.getNumGeometries(); i < n; i++) { start(member); encode(geometry.getGeometryN(i)); end(member); } } } }