001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions
024: * Suite #1A
025: * 2328 Government Street
026: * Victoria BC V8T 5G5
027: * Canada
028: *
029: * (250)385-6040
030: * www.vividsolutions.com
031: */
032: package com.vividsolutions.jump.io;
033:
034: import com.vividsolutions.jts.geom.*;
035: import java.io.*;
036:
037: /**
038: * Writes or creates a formatted string containing the GML
039: * representation of a JTS Geometry.
040: * Supports a user-defined line prefix and a user-defined maximum number of coordinates per line.
041: * Indents components of Geometries to provide a nicely-formatted representation.
042: */
043: public class GMLGeometryWriter {
044:
045: /**
046: * Returns a <code>String</code> of repeated characters.
047: *
048: *@param ch the character to repeat
049: *@param count the number of times to repeat the character
050: *@return a <code>String</code> of characters
051: */
052: private static String stringOfChar(char ch, int count) {
053: StringBuffer buf = new StringBuffer();
054: for (int i = 0; i < count; i++) {
055: buf.append(ch);
056: }
057: return buf.toString();
058: }
059:
060: private final int INDENT_SIZE = 2;
061: // these could be make settable
062: private static final String coordinateSeparator = ",";
063: private static final String tupleSeparator = " ";
064:
065: private String linePrefix = null;
066: private int maxCoordinatesPerLine = 10;
067: private String srsName = null;
068: private String gid = null;
069:
070: public GMLGeometryWriter() {
071: }
072:
073: public void setLinePrefix(String linePrefix) {
074: this .linePrefix = linePrefix;
075: }
076:
077: /**
078: * Sets the <code>srsName</code> attribute to be output on the Geometry element.
079: * If <code>null</code> no attribute will be output.
080: * @param srsName
081: */
082: public void setSRSName(String srsName) {
083: this .srsName = srsName;
084: }
085:
086: /**
087: * Sets the <code>gid</code> attribute to be output on the Geometry element.
088: * If <code>null</code> no attribute will be output.
089: * @param srsName
090: */
091: public void setGID(String gid) {
092: this .gid = gid;
093: }
094:
095: public void setMaximumCoordinatesPerLine(int maxCoordinatesPerLine) {
096: if (maxCoordinatesPerLine <= 0) {
097: maxCoordinatesPerLine = 1;
098: return;
099: }
100: this .maxCoordinatesPerLine = maxCoordinatesPerLine;
101: }
102:
103: public String write(Geometry geom) {
104: StringBuffer buf = new StringBuffer();
105: write(geom, buf);
106: return buf.toString();
107: }
108:
109: public void write(Geometry geometry, Writer writer)
110: throws IOException {
111: writer.write(write(geometry));
112: }
113:
114: /**
115: * Generates the GML representation of a JTS Geometry.
116: * @param g Geometry to output
117: */
118: public void write(Geometry g, StringBuffer buf) {
119: writeGeometry(g, attributeString(), 0, buf);
120: }
121:
122: /**
123: * Generates the GML representation of a JTS Geometry.
124: * @param g Geometry to output
125: */
126: private void writeGeometry(Geometry g, String attributes,
127: int level, StringBuffer buf) {
128: /*
129: * order is important in this if-else list.
130: * E.g. homogeneous collections need to come before GeometryCollection
131: */
132: if (g instanceof Point) {
133: writePoint((Point) g, attributes, level, buf);
134: } else if (g instanceof LinearRing) {
135: writeLinearRing((LinearRing) g, attributes, level, buf);
136: } else if (g instanceof LineString) {
137: writeLineString((LineString) g, attributes, level, buf);
138: } else if (g instanceof Polygon) {
139: writePolygon((Polygon) g, attributes, level, buf);
140: } else if (g instanceof MultiPoint) {
141: writeMultiPoint((MultiPoint) g, attributes, level, buf);
142: } else if (g instanceof MultiLineString) {
143: writeMultiLineString((MultiLineString) g, attributes,
144: level, buf);
145: } else if (g instanceof MultiPolygon) {
146: writeMultiPolygon((MultiPolygon) g, attributes, level, buf);
147: } else if (g instanceof GeometryCollection) {
148: writeGeometryCollection((GeometryCollection) g, attributes,
149: level, buf);
150: }
151: // throw an error for an unknown type?
152: }
153:
154: private void startLine(StringBuffer buf, int level, String text) {
155: if (linePrefix != null)
156: buf.append(linePrefix);
157: buf.append(stringOfChar(' ', INDENT_SIZE * level));
158: buf.append(text);
159: }
160:
161: private String geometryTag(String geometryName, String attributes) {
162: StringBuffer buf = new StringBuffer();
163: buf.append("<gml:");
164: buf.append(geometryName);
165: if (attributes != null && attributes.length() > 0) {
166: buf.append(" ");
167: buf.append(attributes);
168: }
169: buf.append(">");
170: return buf.toString();
171: }
172:
173: private String attributeString() {
174: StringBuffer buf = new StringBuffer();
175: if (gid != null) {
176: buf.append(" gid='");
177: buf.append(gid);
178: buf.append("'");
179: }
180: if (srsName != null) {
181: buf.append(" srsName='");
182: buf.append(srsName);
183: buf.append("'");
184: }
185: return buf.toString();
186: }
187:
188: //<gml:Point><gml:coordinates>1195156.78946687,382069.533723461</gml:coordinates></gml:Point>
189: private void writePoint(Point p, String attributes, int level,
190: StringBuffer buf) {
191: startLine(buf, level, geometryTag("Point", attributes) + "\n");
192: write(new Coordinate[] { p.getCoordinate() }, level + 1, buf);
193: startLine(buf, level, "</gml:Point>\n");
194: }
195:
196: //<gml:LineString><gml:coordinates>1195123.37289257,381985.763974674 1195120.22369473,381964.660533343 1195118.14929823,381942.597718511</gml:coordinates></gml:LineString>
197: private void writeLineString(LineString ls, String attributes,
198: int level, StringBuffer buf) {
199: startLine(buf, level, geometryTag("LineString", attributes)
200: + "\n");
201: write(ls.getCoordinates(), level + 1, buf);
202: startLine(buf, level, "</gml:LineString>\n");
203: }
204:
205: //<gml:LinearRing><gml:coordinates>1226890.26761027,1466433.47430292 1226880.59239079,1466427.03208053...></coordinates></gml:LinearRing>
206: private void writeLinearRing(LinearRing lr, String attributes,
207: int level, StringBuffer buf) {
208: startLine(buf, level, geometryTag("LinearRing", attributes)
209: + "\n");
210: write(lr.getCoordinates(), level + 1, buf);
211: startLine(buf, level, "</gml:LinearRing>\n");
212: }
213:
214: private void writePolygon(Polygon p, String attributes, int level,
215: StringBuffer buf) {
216: startLine(buf, level, geometryTag("Polygon", attributes) + "\n");
217:
218: startLine(buf, level, " <gml:outerBoundaryIs>\n");
219: writeLinearRing((LinearRing) p.getExteriorRing(), null,
220: level + 1, buf);
221: startLine(buf, level, " </gml:outerBoundaryIs>\n");
222:
223: for (int t = 0; t < p.getNumInteriorRing(); t++) {
224: startLine(buf, level, " <gml:innerBoundaryIs>\n");
225: writeLinearRing((LinearRing) p.getInteriorRingN(t), null,
226: level + 1, buf);
227: startLine(buf, level, " </gml:innerBoundaryIs>\n");
228: }
229:
230: startLine(buf, level, "</gml:Polygon>\n");
231: }
232:
233: private void writeMultiPoint(MultiPoint mp, String attributes,
234: int level, StringBuffer buf) {
235: startLine(buf, level, geometryTag("MultiPoint", attributes)
236: + "\n");
237: for (int t = 0; t < mp.getNumGeometries(); t++) {
238: startLine(buf, level, " <gml:pointMember>\n");
239: writePoint((Point) mp.getGeometryN(t), null, level + 1, buf);
240: startLine(buf, level, " </gml:pointMember>\n");
241: }
242: startLine(buf, level, "</gml:MultiPoint>\n");
243: }
244:
245: private void writeMultiLineString(MultiLineString mls,
246: String attributes, int level, StringBuffer buf) {
247: startLine(buf, level,
248: geometryTag("MultiLineString", attributes) + "\n");
249: for (int t = 0; t < mls.getNumGeometries(); t++) {
250: startLine(buf, level, " <gml:lineStringMember>\n");
251: writeLineString((LineString) mls.getGeometryN(t), null,
252: level + 1, buf);
253: startLine(buf, level, " </gml:lineStringMember>\n");
254: }
255: startLine(buf, level, "</gml:MultiLineString>\n");
256: }
257:
258: private void writeMultiPolygon(MultiPolygon mp, String attributes,
259: int level, StringBuffer buf) {
260: startLine(buf, level, geometryTag("MultiPolygon", attributes)
261: + "\n");
262: for (int t = 0; t < mp.getNumGeometries(); t++) {
263: startLine(buf, level, " <gml:polygonMember>\n");
264: writePolygon((Polygon) mp.getGeometryN(t), null, level + 1,
265: buf);
266: startLine(buf, level, " </gml:polygonMember>\n");
267: }
268: startLine(buf, level, "</gml:MultiPolygon>\n");
269: }
270:
271: private void writeGeometryCollection(GeometryCollection gc,
272: String attributes, int level, StringBuffer buf) {
273: startLine(buf, level, geometryTag("MultiGeometry", attributes)
274: + "\n");
275: for (int t = 0; t < gc.getNumGeometries(); t++) {
276: startLine(buf, level, " <gml:geometryMember>\n");
277: writeGeometry(gc.getGeometryN(t), null, level + 1, buf);
278: startLine(buf, level, " </gml:geometryMember>\n");
279: }
280: startLine(buf, level, "</gml:MultiGeometry>\n");
281: }
282:
283: /**
284: * Takes a list of coordinates and converts it to GML.<br>
285: * 2d and 3d aware.
286: * Terminates the coordinate output with a newline.
287: *@param cs array of coordinates
288: */
289: private void write(Coordinate[] coords, int level, StringBuffer buf) {
290: startLine(buf, level, "<gml:coordinates>");
291: int dim = 2;
292:
293: if (coords.length > 0) {
294: if (!(Double.isNaN(coords[0].z)))
295: dim = 3;
296: }
297:
298: boolean isNewLine = false;
299: for (int i = 0; i < coords.length; i++) {
300: if (isNewLine) {
301: startLine(buf, level, " ");
302: isNewLine = false;
303: }
304: if (dim == 2) {
305: buf.append(coords[i].x);
306: buf.append(coordinateSeparator);
307: buf.append(coords[i].y);
308: } else if (dim == 3) {
309: buf.append(coords[i].x);
310: buf.append(coordinateSeparator);
311: buf.append(coords[i].y);
312: buf.append(coordinateSeparator);
313: buf.append(coords[i].z);
314: }
315: buf.append(tupleSeparator);
316:
317: // break output lines to prevent them from getting too long
318: if ((i + 1) % maxCoordinatesPerLine == 0
319: && i < coords.length - 1) {
320: buf.append("\n");
321: isNewLine = true;
322: }
323: }
324:
325: buf.append("</gml:coordinates>\n");
326: }
327: }
|