All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vividsolutions.jts.io.kml.KMLWriter Maven / Gradle / Ivy

The newest version!
package com.vividsolutions.jts.io.kml;

import java.io.IOException;
import java.io.Writer;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.util.StringUtil;

/**
 * Writes a formatted string containing the KML representation of a JTS
 * {@link Geometry}. 
 * The output is KML fragments which 
 * can be substituted wherever the KML Geometry abstract element can be used.
 * 

* Output elements are indented to provide a * nicely-formatted representation. * An output line prefix and maximum * number of coordinates per line can be specified. *

* The Z ordinate value output can be forced to be a specific value. * The extrude and altitudeMode modes can be set. * If set, the corresponding sub-elements will be output. */ public class KMLWriter { /** * The KML standard value clampToGround for use in {@link #setAltitudeMode(String)}. */ public static String ALTITUDE_MODE_CLAMPTOGROUND = "clampToGround "; /** * The KML standard value relativeToGround for use in {@link #setAltitudeMode(String)}. */ public static String ALTITUDE_MODE_RELATIVETOGROUND = "relativeToGround "; /** * The KML standard value absolute for use in {@link #setAltitudeMode(String)}. */ public static String ALTITUDE_MODE_ABSOLUTE = "absolute"; /** * Writes a Geometry as KML to a string, using * a specified Z value. * * @param geometry the geometry to write * @param z the Z value to use * @return a string containing the KML geometry representation */ public static String writeGeometry(Geometry geometry, double z) { KMLWriter writer = new KMLWriter(); writer.setZ(z); return writer.write(geometry); } /** * Writes a Geometry as KML to a string, using * a specified Z value, precision, extrude flag, * and altitude mode code. * * @param geometry the geometry to write * @param z the Z value to use * @param precision the maximum number of decimal places to write * @param extrude the extrude flag to write * @param altitudeMode the altitude model code to write * @return a string containing the KML geometry representation */ public static String writeGeometry(Geometry geometry, double z, int precision, boolean extrude, String altitudeMode) { KMLWriter writer = new KMLWriter(); writer.setZ(z); writer.setPrecision(precision); writer.setExtrude(extrude); writer.setAltitudeMode(altitudeMode); return writer.write(geometry); } private final int INDENT_SIZE = 2; private static final String COORDINATE_SEPARATOR = ","; private static final String TUPLE_SEPARATOR = " "; private String linePrefix = null; private int maxCoordinatesPerLine = 5; private double zVal = Double.NaN; private boolean extrude = false; private boolean tesselate; private String altitudeMode = null; private DecimalFormat numberFormatter = null; /** * Creates a new writer. */ public KMLWriter() { } /** * Sets a tag string which is prefixed to every emitted text line. * This can be used to indent the geometry text in a containing document. * * @param linePrefix the tag string */ public void setLinePrefix(String linePrefix) { this.linePrefix = linePrefix; } /** * Sets the maximum number of coordinates to output per line. * * @param maxCoordinatesPerLine the maximum number of coordinates to output */ public void setMaximumCoordinatesPerLine(int maxCoordinatesPerLine) { if (maxCoordinatesPerLine <= 0) { maxCoordinatesPerLine = 1; return; } this.maxCoordinatesPerLine = maxCoordinatesPerLine; } /** * Sets the Z value to be output for all coordinates. * This overrides any Z value present in the Geometry coordinates. * * @param zVal the Z value to output */ public void setZ(double zVal) { this.zVal = zVal; } /** * Sets the flag to be output in the extrude element. * * @param extrude the extrude flag to output */ public void setExtrude(boolean extrude) { this.extrude = extrude; } /** * Sets the flag to be output in the tesselate element. * * @param tesselate the tesselate flag to output */ public void setTesselate(boolean tesselate) { this.tesselate = tesselate; } /** * Sets the value output in the altitudeMode element. * * @param altitudeMode string representing the altitude mode */ public void setAltitudeMode(String altitudeMode) { this.altitudeMode = altitudeMode; } /** * Sets the maximum nummber of decimal places to output in ordinate values. * Useful for limiting output size. * * @param precision the number of decimal places to output */ public void setPrecision(int precision) { //this.precision = precision; if (precision >= 0) numberFormatter = createFormatter(precision); } /** * Writes a {@link Geometry} in KML format as a string. * * @param geom the geometry to write * @return a string containing the KML geometry representation */ public String write(Geometry geom) { StringBuffer buf = new StringBuffer(); write(geom, buf); return buf.toString(); } /** * Writes the KML representation of a {@link Geometry} to a {@link Writer}. * * @param geometry the geometry to write * @param writer the Writer to write to * @throws IOException if an I/O error occurred */ public void write(Geometry geometry, Writer writer) throws IOException { writer.write(write(geometry)); } /** * Appends the KML representation of a {@link Geometry} to a {@link StringBuffer}. * * @param geometry the geometry to write * @param buf the buffer to write into */ public void write(Geometry geometry, StringBuffer buf) { writeGeometry(geometry, 0, buf); } private void writeGeometry(Geometry g, int level, StringBuffer buf) { String attributes = ""; if (g instanceof Point) { writePoint((Point) g, attributes, level, buf); } else if (g instanceof LinearRing) { writeLinearRing((LinearRing) g, attributes, true, level, buf); } else if (g instanceof LineString) { writeLineString((LineString) g, attributes, level, buf); } else if (g instanceof Polygon) { writePolygon((Polygon) g, attributes, level, buf); } else if (g instanceof GeometryCollection) { writeGeometryCollection((GeometryCollection) g, attributes, level, buf); } else throw new IllegalArgumentException("Geometry type not supported: " + g.getGeometryType()); } private void startLine(String text, int level, StringBuffer buf) { if (linePrefix != null) buf.append(linePrefix); buf.append(StringUtil.spaces(INDENT_SIZE * level)); buf.append(text); } private String geometryTag(String geometryName, String attributes) { StringBuffer buf = new StringBuffer(); buf.append("<"); buf.append(geometryName); if (attributes != null && attributes.length() > 0) { buf.append(" "); buf.append(attributes); } buf.append(">"); return buf.toString(); } private void writeModifiers(int level, StringBuffer buf) { if (extrude) { startLine("1\n", level, buf); } if (tesselate) { startLine("1\n", level, buf); } if (altitudeMode != null) { startLine("" + altitudeMode + "\n", level, buf); } } private void writePoint(Point p, String attributes, int level, StringBuffer buf) { // ... startLine(geometryTag("Point", attributes) + "\n", level, buf); writeModifiers(level, buf); write(new Coordinate[] { p.getCoordinate() }, level + 1, buf); startLine("\n", level, buf); } private void writeLineString(LineString ls, String attributes, int level, StringBuffer buf) { // ... startLine(geometryTag("LineString", attributes) + "\n", level, buf); writeModifiers(level, buf); write(ls.getCoordinates(), level + 1, buf); startLine("\n", level, buf); } private void writeLinearRing(LinearRing lr, String attributes, boolean writeModifiers, int level, StringBuffer buf) { // ... startLine(geometryTag("LinearRing", attributes) + "\n", level, buf); if (writeModifiers) writeModifiers(level, buf); write(lr.getCoordinates(), level + 1, buf); startLine("\n", level, buf); } private void writePolygon(Polygon p, String attributes, int level, StringBuffer buf) { startLine(geometryTag("Polygon", attributes) + "\n", level, buf); writeModifiers(level, buf); startLine(" \n", level, buf); writeLinearRing((LinearRing) p.getExteriorRing(), null, false, level + 1, buf); startLine(" \n", level, buf); for (int t = 0; t < p.getNumInteriorRing(); t++) { startLine(" \n", level, buf); writeLinearRing((LinearRing) p.getInteriorRingN(t), null, false, level + 1, buf); startLine(" \n", level, buf); } startLine("\n", level, buf); } private void writeGeometryCollection(GeometryCollection gc, String attributes, int level, StringBuffer buf) { startLine("\n", level, buf); for (int t = 0; t < gc.getNumGeometries(); t++) { writeGeometry(gc.getGeometryN(t), level + 1, buf); } startLine("\n", level, buf); } /** * Takes a list of coordinates and converts it to KML.
* 2d and 3d aware. Terminates the coordinate output with a newline. * * @param cs array of coordinates */ private void write(Coordinate[] coords, int level, StringBuffer buf) { startLine("", level, buf); boolean isNewLine = false; for (int i = 0; i < coords.length; i++) { if (i > 0) { buf.append(TUPLE_SEPARATOR); } if (isNewLine) { startLine(" ", level, buf); isNewLine = false; } write(coords[i], buf); // break output lines to prevent them from getting too long if ((i + 1) % maxCoordinatesPerLine == 0 && i < coords.length - 1) { buf.append("\n"); isNewLine = true; } } buf.append("\n"); } private void write(Coordinate p, StringBuffer buf) { write(p.x, buf); buf.append(COORDINATE_SEPARATOR); write(p.y, buf); double z = p.z; // if altitude was specified directly, use it if (!Double.isNaN(zVal)) z = zVal; // only write if Z present // MD - is this right? Or should it always be written? if (!Double.isNaN(z)) { buf.append(COORDINATE_SEPARATOR); write(z, buf); } } private void write(double num, StringBuffer buf) { if (numberFormatter != null) buf.append(numberFormatter.format(num)); else buf.append(num); } /** * Creates the DecimalFormat used to write doubles * with a sufficient number of decimal places. * * @param precisionModel * the PrecisionModel used to determine the number of * decimal places to write. * @return a DecimalFormat that write double s * without scientific notation. */ private static DecimalFormat createFormatter(int precision) { // specify decimal separator explicitly to avoid problems in other locales DecimalFormatSymbols symbols = new DecimalFormatSymbols(); symbols.setDecimalSeparator('.'); DecimalFormat format = new DecimalFormat("0." + StringUtil.chars('#', precision), symbols); format.setDecimalSeparatorAlwaysShown(false); return format; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy