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

com.hazelcast.shaded.org.locationtech.jts.io.WKTWriter Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * Copyright (c) 2016 Vivid Solutions.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
 * and the Eclipse Distribution License is available at
 *
 * http://www.eclipse.org/org/documents/edl-v10.php.
 */
package com.hazelcast.shaded.org.locationtech.jts.io;


import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.EnumSet;

import com.hazelcast.shaded.org.locationtech.jts.geom.Coordinate;
import com.hazelcast.shaded.org.locationtech.jts.geom.CoordinateSequence;
import com.hazelcast.shaded.org.locationtech.jts.geom.CoordinateSequenceFilter;
import com.hazelcast.shaded.org.locationtech.jts.geom.Geometry;
import com.hazelcast.shaded.org.locationtech.jts.geom.GeometryCollection;
import com.hazelcast.shaded.org.locationtech.jts.geom.LineString;
import com.hazelcast.shaded.org.locationtech.jts.geom.LinearRing;
import com.hazelcast.shaded.org.locationtech.jts.geom.MultiLineString;
import com.hazelcast.shaded.org.locationtech.jts.geom.MultiPoint;
import com.hazelcast.shaded.org.locationtech.jts.geom.MultiPolygon;
import com.hazelcast.shaded.org.locationtech.jts.geom.Point;
import com.hazelcast.shaded.org.locationtech.jts.geom.Polygon;
import com.hazelcast.shaded.org.locationtech.jts.geom.PrecisionModel;
import com.hazelcast.shaded.org.locationtech.jts.util.Assert;

/**
 * Writes the Well-Known Text representation of a {@link Geometry}.
 * The Well-Known Text format is defined in the
 * OGC 
 * Simple Features Specification for SQL.
 * See {@link WKTReader} for a formal specification of the format syntax.
 * 

* The WKTWriter outputs coordinates rounded to the precision * model. Only the maximum number of decimal places * necessary to represent the ordinates to the required precision will be * output. *

* The SFS WKT spec does not define a special tag for {@link LinearRing}s. * Under the spec, rings are output as LINESTRINGs. * In order to allow precisely specifying constructed geometries, * JTS also supports a non-standard LINEARRING tag which is used * to output LinearRings. * * @version 1.7 * @see WKTReader */ public class WKTWriter { /** * Generates the WKT for a POINT * specified by a {@link Coordinate}. * * @param p0 the point coordinate * * @return the WKT */ public static String toPoint(Coordinate p0) { return WKTConstants.POINT + " ( " + format(p0) + " )"; } /** * Generates the WKT for a LINESTRING * specified by a {@link CoordinateSequence}. * * @param seq the sequence to write * * @return the WKT string */ public static String toLineString(CoordinateSequence seq) { StringBuilder buf = new StringBuilder(); buf.append(WKTConstants.LINESTRING); buf.append(" "); if (seq.size() == 0) buf.append(WKTConstants.EMPTY); else { buf.append("("); for (int i = 0; i < seq.size(); i++) { if (i > 0) buf.append(", "); buf.append(format(seq.getX(i), seq.getY(i))); } buf.append(")"); } return buf.toString(); } /** * Generates the WKT for a LINESTRING * specified by a {@link CoordinateSequence}. * * @param coord the sequence to write * * @return the WKT string */ public static String toLineString(Coordinate[] coord) { StringBuilder buf = new StringBuilder(); buf.append(WKTConstants.LINESTRING); buf.append(" "); if (coord.length == 0) buf.append(WKTConstants.EMPTY); else { buf.append("("); for (int i = 0; i < coord.length; i++) { if (i > 0) buf.append(", "); buf.append(format(coord[i])); } buf.append(")"); } return buf.toString(); } /** * Generates the WKT for a LINESTRING * specified by two {@link Coordinate}s. * * @param p0 the first coordinate * @param p1 the second coordinate * * @return the WKT */ public static String toLineString(Coordinate p0, Coordinate p1) { return WKTConstants.LINESTRING + " ( " + format(p0) + ", " + format(p1) + " )"; } public static String format(Coordinate p) { return format(p.x, p.y); } private static String format(double x, double y) { return OrdinateFormat.DEFAULT.format(x) + " " + OrdinateFormat.DEFAULT.format(y); } private static final int INDENT = 2; private static final int OUTPUT_DIMENSION = 2; /** * 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 OrdinateFormat createFormatter(PrecisionModel precisionModel) { return OrdinateFormat.create(precisionModel.getMaximumSignificantDigits()); } /** * Returns a String of repeated characters. * *@param ch the character to repeat *@param count the number of times to repeat the character *@return a String of characters */ private static String stringOfChar(char ch, int count) { StringBuilder buf = new StringBuilder(count); for (int i = 0; i < count; i++) { buf.append(ch); } return buf.toString(); } /** * A filter implementation to test if a coordinate sequence actually has * meaningful values for an ordinate bit-pattern */ private class CheckOrdinatesFilter implements CoordinateSequenceFilter { private final EnumSet checkOrdinateFlags; private final EnumSet outputOrdinates; /** * Creates an instance of this class * @param checkOrdinateFlags the index for the ordinates to test. */ private CheckOrdinatesFilter(EnumSet checkOrdinateFlags) { this.outputOrdinates = EnumSet.of(Ordinate.X, Ordinate.Y); this.checkOrdinateFlags = checkOrdinateFlags; } /** @see org.locationtech.jts.geom.CoordinateSequenceFilter#isGeometryChanged */ public void filter(CoordinateSequence seq, int i) { if (checkOrdinateFlags.contains(Ordinate.Z) && !outputOrdinates.contains(Ordinate.Z)) { if (!Double.isNaN(seq.getZ(i))) outputOrdinates.add(Ordinate.Z); } if (checkOrdinateFlags.contains(Ordinate.M) && !outputOrdinates.contains(Ordinate.M)) { if (!Double.isNaN(seq.getM(i))) outputOrdinates.add(Ordinate.M); } } /** @see org.locationtech.jts.geom.CoordinateSequenceFilter#isGeometryChanged */ public boolean isGeometryChanged() { return false; } /** @see org.locationtech.jts.geom.CoordinateSequenceFilter#isDone */ public boolean isDone() { return outputOrdinates.equals(checkOrdinateFlags); } /** * Gets the evaluated ordinate bit-pattern * * @return A bit-pattern of ordinates with valid values masked by {@link #checkOrdinateFlags}. */ EnumSet getOutputOrdinates() { return outputOrdinates; } } private EnumSet outputOrdinates; private final int outputDimension; private PrecisionModel precisionModel = null; private OrdinateFormat ordinateFormat = null; private boolean isFormatted = false; private int coordsPerLine = -1; private String indentTabStr ; /** * Creates a new WKTWriter with default settings */ public WKTWriter() { this(OUTPUT_DIMENSION); } /** * Creates a writer that writes {@link Geometry}s with * the given output dimension (2 to 4). * The output follows the following rules: *

    *
  • If the specified output dimension is 3 and the z is measure flag * is set to true, the Z value of coordinates will be written if it is present * (i.e. if it is not Double.NaN)
  • *
  • If the specified output dimension is 3 and the z is measure flag * is set to false, the Measure value of coordinates will be written if it is present * (i.e. if it is not Double.NaN)
  • *
  • If the specified output dimension is 4, the Z value of coordinates will * be written even if it is not present when the Measure value is present.The Measrue * value of coordinates will be written if it is present * (i.e. if it is not Double.NaN)
  • *
* * @param outputDimension the coordinate dimension to output (2 to 4) */ public WKTWriter(int outputDimension) { setTab(INDENT); this.outputDimension = outputDimension; if (outputDimension < 2 || outputDimension > 4) throw new IllegalArgumentException("Invalid output dimension (must be 2 to 4)"); this.outputOrdinates = EnumSet.of(Ordinate.X, Ordinate.Y); if (outputDimension > 2) outputOrdinates.add(Ordinate.Z); if (outputDimension > 3) outputOrdinates.add(Ordinate.M); } /** * Sets whether the output will be formatted. * * @param isFormatted true if the output is to be formatted */ public void setFormatted(boolean isFormatted) { this.isFormatted = isFormatted; } /** * Sets the maximum number of coordinates per line * written in formatted output. * If the provided coordinate number is <= 0, * coordinates will be written all on one line. * * @param coordsPerLine the number of coordinates per line to output. */ public void setMaxCoordinatesPerLine(int coordsPerLine) { this.coordsPerLine = coordsPerLine; } /** * Sets the tab size to use for indenting. * * @param size the number of spaces to use as the tab string * @throws IllegalArgumentException if the size is non-positive */ public void setTab(int size) { if(size <= 0) throw new IllegalArgumentException("Tab count must be positive"); this.indentTabStr = stringOfChar(' ', size); } /** * Sets the {@link Ordinate} that are to be written. Possible members are: *
    *
  • {@link Ordinate#X}
  • *
  • {@link Ordinate#Y}
  • *
  • {@link Ordinate#Z}
  • *
  • {@link Ordinate#M}
  • *
* Values of {@link Ordinate#X} and {@link Ordinate#Y} are always assumed and not * particularly checked for. * * @param outputOrdinates A set of {@link Ordinate} values */ public void setOutputOrdinates(EnumSet outputOrdinates) { this.outputOrdinates.remove(Ordinate.Z); this.outputOrdinates.remove(Ordinate.M); if (this.outputDimension == 3) { if (outputOrdinates.contains(Ordinate.Z)) this.outputOrdinates.add(Ordinate.Z); else if (outputOrdinates.contains(Ordinate.M)) this.outputOrdinates.add(Ordinate.M); } if (this.outputDimension == 4) { if (outputOrdinates.contains(Ordinate.Z)) this.outputOrdinates.add(Ordinate.Z); if (outputOrdinates.contains(Ordinate.M)) this.outputOrdinates.add(Ordinate.M); } } /** * Gets a bit-pattern defining which ordinates should be * @return an ordinate bit-pattern * @see #setOutputOrdinates(EnumSet) */ public EnumSet getOutputOrdinates() { return this.outputOrdinates; } /** * Sets a {@link PrecisionModel} that should be used on the ordinates written. *

If none/{@code null} is assigned, the precision model of the {@link Geometry#getFactory()} * is used.

*

Note: The precision model is applied to all ordinate values, not just x and y.

* @param precisionModel * the flag indicating if {@link Coordinate#z}/{} is actually a measure value. */ public void setPrecisionModel(PrecisionModel precisionModel) { this.precisionModel = precisionModel; this.ordinateFormat = OrdinateFormat.create(precisionModel.getMaximumSignificantDigits()); } /** * Converts a Geometry to its Well-known Text representation. * *@param geometry a Geometry to process *@return a <Geometry Tagged Text> string (see the OpenGIS Simple * Features Specification) */ public String write(Geometry geometry) { Writer sw = new StringWriter(); try { writeFormatted(geometry, false, sw); } catch (IOException ex) { Assert.shouldNeverReachHere(); } return sw.toString(); } /** * Converts a Geometry to its Well-known Text representation. * *@param geometry a Geometry to process */ public void write(Geometry geometry, Writer writer) throws IOException { // write the geometry writeFormatted(geometry, isFormatted, writer); } /** * Same as write, but with newlines and spaces to make the * well-known text more readable. * *@param geometry a Geometry to process *@return a <Geometry Tagged Text> string (see the OpenGIS Simple * Features Specification), with newlines and spaces */ public String writeFormatted(Geometry geometry) { Writer sw = new StringWriter(); try { writeFormatted(geometry, true, sw); } catch (IOException ex) { Assert.shouldNeverReachHere(); } return sw.toString(); } /** * Same as write, but with newlines and spaces to make the * well-known text more readable. * *@param geometry a Geometry to process */ public void writeFormatted(Geometry geometry, Writer writer) throws IOException { writeFormatted(geometry, true, writer); } /** * Converts a Geometry to its Well-known Text representation. * *@param geometry a Geometry to process */ private void writeFormatted(Geometry geometry, boolean useFormatting, Writer writer) throws IOException { OrdinateFormat formatter = getFormatter(geometry); // append the WKT appendGeometryTaggedText(geometry, useFormatting, writer, formatter); } private OrdinateFormat getFormatter(Geometry geometry) { // if present use the cached formatter if (ordinateFormat != null) return ordinateFormat; // no precision model was specified, so use the geometry's PrecisionModel pm = geometry.getPrecisionModel(); OrdinateFormat formatter = createFormatter(pm); return formatter; } /** * Converts a Geometry to <Geometry Tagged Text> format, * then appends it to the writer. * * @param geometry the Geometry to process * @param useFormatting flag indicating that the output should be formatted * @param writer the output writer to append to * @param formatter the DecimalFormatter to use to convert * from a precise coordinate to an external coordinate */ private void appendGeometryTaggedText(Geometry geometry, boolean useFormatting, Writer writer, OrdinateFormat formatter) throws IOException { // evaluate the ordinates actually present in the geometry CheckOrdinatesFilter cof = new CheckOrdinatesFilter(this.outputOrdinates); geometry.apply(cof); // Append the WKT appendGeometryTaggedText(geometry, cof.getOutputOrdinates(), useFormatting, 0, writer, formatter); } /** * Converts a Geometry to <Geometry Tagged Text> format, * then appends it to the writer. * * @param geometry the Geometry to process * @param useFormatting flag indicating that the output should be formatted * @param level the indentation level * @param writer the output writer to append to * @param formatter the DecimalFormatter to use to convert * from a precise coordinate to an external coordinate */ private void appendGeometryTaggedText( Geometry geometry, EnumSet outputOrdinates, boolean useFormatting, int level, Writer writer, OrdinateFormat formatter) throws IOException { indent(useFormatting, level, writer); if (geometry instanceof Point) { appendPointTaggedText((Point) geometry, outputOrdinates, useFormatting, level, writer, formatter); } else if (geometry instanceof LinearRing) { appendLinearRingTaggedText((LinearRing) geometry, outputOrdinates, useFormatting, level, writer, formatter); } else if (geometry instanceof LineString) { appendLineStringTaggedText((LineString) geometry, outputOrdinates, useFormatting, level, writer, formatter); } else if (geometry instanceof Polygon) { appendPolygonTaggedText((Polygon) geometry, outputOrdinates, useFormatting, level, writer, formatter); } else if (geometry instanceof MultiPoint) { appendMultiPointTaggedText((MultiPoint) geometry, outputOrdinates, useFormatting, level, writer, formatter); } else if (geometry instanceof MultiLineString) { appendMultiLineStringTaggedText((MultiLineString) geometry, outputOrdinates, useFormatting, level, writer, formatter); } else if (geometry instanceof MultiPolygon) { appendMultiPolygonTaggedText((MultiPolygon) geometry, outputOrdinates, useFormatting, level, writer, formatter); } else if (geometry instanceof GeometryCollection) { appendGeometryCollectionTaggedText((GeometryCollection) geometry, outputOrdinates, useFormatting, level, writer, formatter); } else { Assert.shouldNeverReachHere("Unsupported Geometry implementation:" + geometry.getClass()); } } /** * Converts a Coordinate to <Point Tagged Text> format, * then appends it to the writer. * * @param point the Point to process * @param useFormatting flag indicating that the output should be formatted * @param level the indentation level * @param writer the output writer to append to * @param formatter the formatter to use when writing numbers */ private void appendPointTaggedText( Point point, EnumSet outputOrdinates, boolean useFormatting, int level, Writer writer, OrdinateFormat formatter) throws IOException { writer.write(WKTConstants.POINT); writer.write(" "); appendOrdinateText(outputOrdinates, writer); appendSequenceText(point.getCoordinateSequence(), outputOrdinates, useFormatting, level, false, writer, formatter); } /** * Converts a LineString to <LineString Tagged Text> * format, then appends it to the writer. * * @param lineString the LineString to process * @param useFormatting flag indicating that the output should be formatted * @param level the indentation level * @param writer the output writer to append to * @param formatter the DecimalFormatter to use to convert * from a precise coordinate to an external coordinate */ private void appendLineStringTaggedText( LineString lineString, EnumSet outputOrdinates, boolean useFormatting, int level, Writer writer, OrdinateFormat formatter) throws IOException { writer.write(WKTConstants.LINESTRING); writer.write(" "); appendOrdinateText(outputOrdinates, writer); appendSequenceText(lineString.getCoordinateSequence(), outputOrdinates, useFormatting, level, false, writer, formatter); } /** * Converts a LinearRing to <LinearRing Tagged Text> * format, then appends it to the writer. * * @param linearRing the LinearRing to process * @param useFormatting flag indicating that the output should be formatted * @param level the indentation level * @param writer the output writer to append to * @param formatter the DecimalFormatter to use to convert * from a precise coordinate to an external coordinate */ private void appendLinearRingTaggedText( LinearRing linearRing, EnumSet outputOrdinates, boolean useFormatting, int level, Writer writer, OrdinateFormat formatter) throws IOException { writer.write(WKTConstants.LINEARRING); writer.write(" "); appendOrdinateText(outputOrdinates, writer); appendSequenceText(linearRing.getCoordinateSequence(), outputOrdinates, useFormatting, level, false, writer, formatter); } /** * Converts a Polygon to <Polygon Tagged Text> format, * then appends it to the writer. * * @param polygon the Polygon to process * @param useFormatting flag indicating that the output should be formatted * @param level the indentation level * @param writer the output writer to append to * @param formatter the DecimalFormatter to use to convert * from a precise coordinate to an external coordinate */ private void appendPolygonTaggedText( Polygon polygon, EnumSet outputOrdinates, boolean useFormatting, int level, Writer writer, OrdinateFormat formatter) throws IOException { writer.write(WKTConstants.POLYGON); writer.write(" "); appendOrdinateText(outputOrdinates, writer); appendPolygonText(polygon, outputOrdinates, useFormatting, level, false, writer, formatter); } /** * Converts a MultiPoint to <MultiPoint Tagged Text> * format, then appends it to the writer. * * @param multipoint the MultiPoint to process * @param useFormatting flag indicating that the output should be formatted * @param level the indentation level * @param writer the output writer to append to * @param formatter the DecimalFormatter to use to convert * from a precise coordinate to an external coordinate */ private void appendMultiPointTaggedText(MultiPoint multipoint, EnumSet outputOrdinates, boolean useFormatting, int level, Writer writer, OrdinateFormat formatter) throws IOException { writer.write(WKTConstants.MULTIPOINT); writer.write(" "); appendOrdinateText(outputOrdinates, writer); appendMultiPointText(multipoint, outputOrdinates, useFormatting, level, writer, formatter); } /** * Converts a MultiLineString to <MultiLineString Tagged * Text> format, then appends it to the writer. * * @param multiLineString the MultiLineString to process * @param useFormatting flag indicating that the output should be formatted * @param level the indentation level * @param writer the output writer to append to * @param formatter the DecimalFormatter to use to convert * from a precise coordinate to an external coordinate */ private void appendMultiLineStringTaggedText( MultiLineString multiLineString, EnumSet outputOrdinates, boolean useFormatting, int level, Writer writer, OrdinateFormat formatter) throws IOException { writer.write(WKTConstants.MULTILINESTRING); writer.write(" "); appendOrdinateText(outputOrdinates, writer); appendMultiLineStringText(multiLineString, outputOrdinates, useFormatting, level, /*false, */writer, formatter); } /** * Converts a MultiPolygon to <MultiPolygon Tagged Text> * format, then appends it to the writer. * * @param multiPolygon the MultiPolygon to process * @param useFormatting flag indicating that the output should be formatted * @param level the indentation level * @param writer the output writer to append to * @param formatter the DecimalFormatter to use to convert * from a precise coordinate to an external coordinate */ private void appendMultiPolygonTaggedText( MultiPolygon multiPolygon, EnumSet outputOrdinates, boolean useFormatting, int level, Writer writer, OrdinateFormat formatter) throws IOException { writer.write(WKTConstants.MULTIPOLYGON); writer.write(" "); appendOrdinateText(outputOrdinates, writer); appendMultiPolygonText(multiPolygon, outputOrdinates, useFormatting, level, writer, formatter); } /** * Converts a GeometryCollection to <GeometryCollection * Tagged Text> format, then appends it to the writer. * * @param geometryCollection the GeometryCollection to process * @param useFormatting flag indicating that the output should be formatted * @param level the indentation level * @param writer the output writer to append to * @param formatter the DecimalFormatter to use to convert * from a precise coordinate to an external coordinate */ private void appendGeometryCollectionTaggedText( GeometryCollection geometryCollection, EnumSet outputOrdinates, boolean useFormatting, int level, Writer writer, OrdinateFormat formatter) throws IOException { writer.write(WKTConstants.GEOMETRYCOLLECTION); writer.write(" "); appendOrdinateText(outputOrdinates, writer); appendGeometryCollectionText(geometryCollection, outputOrdinates, useFormatting, level, writer, formatter); } /** * Appends the i'th coordinate from the sequence to the writer *

If the {@code seq} has coordinates that are {@link double.NAN}, these are not written, even though * {@link #outputDimension} suggests this. * * @param seq the CoordinateSequence to process * @param i the index of the coordinate to write * @param writer the output writer to append to * @param formatter the formatter to use for writing ordinate values */ private void appendCoordinate( CoordinateSequence seq, EnumSet outputOrdinates, int i, Writer writer, OrdinateFormat formatter) throws IOException { writer.write(writeNumber(seq.getX(i), formatter) + " " + writeNumber(seq.getY(i), formatter)); if (outputOrdinates.contains(Ordinate.Z)) { writer.write(" "); writer.write(writeNumber(seq.getZ(i), formatter)); } if (outputOrdinates.contains(Ordinate.M)) { writer.write(" "); writer.write(writeNumber(seq.getM(i), formatter)); } } /** * Converts a double to a String, not in scientific * notation. * *@param d the double to convert *@return the double as a String, not in * scientific notation */ private static String writeNumber(double d, OrdinateFormat formatter) { return formatter.format(d); } /** * Appends additional ordinate information. This function may *

    *
  • append 'Z' if in {@code outputOrdinates} the * {@link Ordinate#Z} value is included *
  • *
  • append 'M' if in {@code outputOrdinates} the * {@link Ordinate#M} value is included *
  • *
  • append 'ZM' if in {@code outputOrdinates} the * {@link Ordinate#Z} and * {@link Ordinate#M} values are included *
  • *
* * @param outputOrdinates a bit-pattern of ordinates to write. * @param writer the output writer to append to. * @throws IOException if an error occurs while using the writer. */ private void appendOrdinateText(EnumSet outputOrdinates, Writer writer) throws IOException { if (outputOrdinates.contains(Ordinate.Z)) writer.append(WKTConstants.Z); if (outputOrdinates.contains(Ordinate.M)) writer.append(WKTConstants.M); } /** * Appends all members of a CoordinateSequence to the stream. Each {@code Coordinate} is separated from * another using a colon, the ordinates of a {@code Coordinate} are separated by a space. * * @param seq the CoordinateSequence to process * @param useFormatting flag indicating that * @param level the indentation level * @param indentFirst flag indicating that the first {@code Coordinate} of the sequence should be indented for * better visibility * @param writer the output writer to append to * @param formatter the formatter to use for writing ordinate values. */ private void appendSequenceText(CoordinateSequence seq, EnumSet outputOrdinates, boolean useFormatting, int level, boolean indentFirst, Writer writer, OrdinateFormat formatter) throws IOException { if (seq.size() == 0) { writer.write(WKTConstants.EMPTY); } else { if (indentFirst) indent(useFormatting, level, writer); writer.write("("); for (int i = 0; i < seq.size(); i++) { if (i > 0) { writer.write(", "); if (coordsPerLine > 0 && i % coordsPerLine == 0) { indent(useFormatting, level + 1, writer); } } appendCoordinate(seq, outputOrdinates, i, writer, formatter); } writer.write(")"); } } /** * Converts a Polygon to <Polygon Text> format, then * appends it to the writer. * * @param polygon the Polygon to process * @param useFormatting flag indicating that * @param level the indentation level * @param indentFirst flag indicating that the first {@code Coordinate} of the sequence should be indented for * better visibility * @param writer the output writer to append to * @param formatter the formatter to use for writing ordinate values. */ private void appendPolygonText( Polygon polygon, EnumSet outputOrdinates, boolean useFormatting, int level, boolean indentFirst, Writer writer, OrdinateFormat formatter) throws IOException { if (polygon.isEmpty()) { writer.write(WKTConstants.EMPTY); } else { if (indentFirst) indent(useFormatting, level, writer); writer.write("("); appendSequenceText(polygon.getExteriorRing().getCoordinateSequence(), outputOrdinates, useFormatting, level, false, writer, formatter); for (int i = 0; i < polygon.getNumInteriorRing(); i++) { writer.write(", "); appendSequenceText(polygon.getInteriorRingN(i).getCoordinateSequence(), outputOrdinates, useFormatting,level + 1,true, writer, formatter); } writer.write(")"); } } /** * Converts a MultiPoint to <MultiPoint Text> format, then * appends it to the writer. * * @param multiPoint the MultiPoint to process * @param useFormatting flag indicating that * @param level the indentation level * @param writer the output writer to append to * @param formatter the formatter to use for writing ordinate values. */ private void appendMultiPointText( MultiPoint multiPoint, EnumSet outputOrdinates, boolean useFormatting, int level, Writer writer, OrdinateFormat formatter) throws IOException { if (multiPoint.getNumGeometries() == 0) { writer.write(WKTConstants.EMPTY); } else { writer.write("("); for (int i = 0; i < multiPoint.getNumGeometries(); i++) { if (i > 0) { writer.write(", "); indentCoords(useFormatting, i, level + 1, writer); } appendSequenceText(((Point) multiPoint.getGeometryN(i)).getCoordinateSequence(), outputOrdinates, useFormatting, level, false, writer, formatter); } writer.write(")"); } } /** * Converts a MultiLineString to <MultiLineString Text> * format, then appends it to the writer. * * @param multiLineString the MultiLineString to process * @param useFormatting flag indicating that * @param level the indentation level * //@param indentFirst flag indicating that the first {@code Coordinate} of the sequence should be indented for * // better visibility * @param writer the output writer to append to * @param formatter the formatter to use for writing ordinate values. */ private void appendMultiLineStringText(MultiLineString multiLineString, EnumSet outputOrdinates, boolean useFormatting, int level, /*boolean indentFirst, */Writer writer, OrdinateFormat formatter) throws IOException { if (multiLineString.getNumGeometries() == 0) { writer.write(WKTConstants.EMPTY); } else { int level2 = level; boolean doIndent = false; writer.write("("); for (int i = 0; i < multiLineString.getNumGeometries(); i++) { if (i > 0) { writer.write(", "); level2 = level + 1; doIndent = true; } appendSequenceText(((LineString) multiLineString.getGeometryN(i)).getCoordinateSequence(), outputOrdinates, useFormatting, level2, doIndent, writer, formatter); } writer.write(")"); } } /** * Converts a MultiPolygon to <MultiPolygon Text> format, * then appends it to the writer. * * @param multiPolygon the MultiPolygon to process * @param useFormatting flag indicating that * @param level the indentation level * @param writer the output writer to append to * @param formatter the formatter to use for writing ordinate values. */ private void appendMultiPolygonText( MultiPolygon multiPolygon, EnumSet outputOrdinates, boolean useFormatting, int level, Writer writer, OrdinateFormat formatter) throws IOException { if (multiPolygon.getNumGeometries() == 0) { writer.write(WKTConstants.EMPTY); } else { int level2 = level; boolean doIndent = false; writer.write("("); for (int i = 0; i < multiPolygon.getNumGeometries(); i++) { if (i > 0) { writer.write(", "); level2 = level + 1; doIndent = true; } appendPolygonText((Polygon) multiPolygon.getGeometryN(i), outputOrdinates, useFormatting, level2, doIndent, writer, formatter); } writer.write(")"); } } /** * Converts a GeometryCollection to <GeometryCollectionText> * format, then appends it to the writer. * * @param geometryCollection the GeometryCollection to process * @param useFormatting flag indicating that * @param level the indentation level * @param writer the output writer to append to * @param formatter the formatter to use for writing ordinate values. */ private void appendGeometryCollectionText( GeometryCollection geometryCollection, EnumSet outputOrdinates, boolean useFormatting, int level, Writer writer, OrdinateFormat formatter) throws IOException { if (geometryCollection.getNumGeometries() == 0) { writer.write(WKTConstants.EMPTY); } else { int level2 = level; writer.write("("); for (int i = 0; i < geometryCollection.getNumGeometries(); i++) { if (i > 0) { writer.write(", "); level2 = level + 1; } appendGeometryTaggedText(geometryCollection.getGeometryN(i), outputOrdinates, useFormatting, level2, writer, formatter); } writer.write(")"); } } private void indentCoords(boolean useFormatting, int coordIndex, int level, Writer writer) throws IOException { if (coordsPerLine <= 0 || coordIndex % coordsPerLine != 0) return; indent(useFormatting, level, writer); } private void indent(boolean useFormatting, int level, Writer writer) throws IOException { if (! useFormatting || level <= 0) return; writer.write("\n"); for (int i = 0; i < level; i++) { writer.write(indentTabStr); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy