Complete Note#1 in the http://wiki.osgeo.org/wiki/GEOS_Provenance_Review to get out...
[geos.git] / src / io / WKTWriter.cpp
blob5431718ee3d720c82c82f25421e56ed35b48b9dc
1 /**********************************************************************
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
6 * Copyright (C) 2011 Sandro Santilli <strk@keybit.net>
7 * Copyright (C) 2005-2006 Refractions Research Inc.
8 * Copyright (C) 2001-2002 Vivid Solutions Inc.
10 * This is free software; you can redistribute and/or modify it under
11 * the terms of the GNU Lesser General Public Licence as published
12 * by the Free Software Foundation.
13 * See the COPYING file for more information.
15 **********************************************************************
17 * Last port: io/WKTWriter.java rev. 1.34 (JTS-1.7)
19 **********************************************************************/
21 #include <geos/io/WKTWriter.h>
22 #include <geos/io/Writer.h>
23 #include <geos/io/CLocalizer.h>
24 #include <geos/geom/Coordinate.h>
25 #include <geos/geom/Point.h>
26 #include <geos/geom/LinearRing.h>
27 #include <geos/geom/LineString.h>
28 #include <geos/geom/Polygon.h>
29 #include <geos/geom/MultiPoint.h>
30 #include <geos/geom/MultiLineString.h>
31 #include <geos/geom/MultiPolygon.h>
32 #include <geos/geom/CoordinateSequence.h>
33 #include <geos/geom/PrecisionModel.h>
34 #include <geos/util/IllegalArgumentException.h>
36 #include <typeinfo>
37 #include <cstdio> // should avoid this
38 #include <string>
39 #include <sstream>
40 #include <cassert>
41 #include <cmath>
42 #include <iomanip>
44 using namespace std;
45 using namespace geos::geom;
47 namespace geos {
48 namespace io { // geos.io
50 WKTWriter::WKTWriter():
51 decimalPlaces(6),
52 isFormatted(false),
53 roundingPrecision(-1),
54 trim(false),
55 level(0),
56 defaultOutputDimension(2),
57 old3D(false)
61 /* public */
62 void
63 WKTWriter::setOutputDimension(int dims)
65 if ( dims < 2 || dims > 3 )
66 throw util::IllegalArgumentException("WKT output dimension must be 2 or 3");
67 defaultOutputDimension = dims;
70 WKTWriter::~WKTWriter() {}
72 /*static*/
73 string
74 WKTWriter::toLineString(const CoordinateSequence& seq)
76 stringstream buf(ios_base::in|ios_base::out);
77 buf << "LINESTRING ";
78 unsigned int npts = seq.getSize();
79 if ( npts == 0 )
81 buf << "EMPTY";
83 else
85 buf << "(";
86 for (unsigned int i=0; i<npts; ++i)
88 if (i) buf << ", ";
89 buf << seq.getX(i) << " " << seq.getY(i);
90 #if PRINT_Z
91 buf << seq.getZ(i);
92 #endif
94 buf << ")";
97 return buf.str();
100 /*static*/
101 string
102 WKTWriter::toLineString(const Coordinate& p0, const Coordinate& p1)
104 stringstream ret(ios_base::in|ios_base::out);
105 ret << "LINESTRING (" << p0.x << " " << p0.y;
106 #if PRINT_Z
107 ret << " " << p0.z;
108 #endif
109 ret << ", " << p1.x << " " << p1.y;
110 #if PRINT_Z
111 ret << " " << p1.z;
112 #endif
113 ret << ")";
115 return ret.str();
118 /*static*/
119 string
120 WKTWriter::toPoint(const Coordinate& p0)
122 stringstream ret(ios_base::in|ios_base::out);
123 ret << "POINT (";
124 #if PRINT_Z
125 ret << p0.x << " " << p0.y << " " << p0.z << " )";
126 #else
127 ret << p0.x << " " << p0.y << " )";
128 #endif
129 return ret.str();
132 void
133 WKTWriter::setRoundingPrecision(int p0)
135 if(p0 < -1) {
136 p0 = -1;
138 roundingPrecision = p0;
141 void
142 WKTWriter::setTrim(bool p0)
144 trim = p0;
147 string WKTWriter::write(const Geometry *geometry) {
148 Writer sw;
149 writeFormatted(geometry,false,&sw);
150 string res=sw.toString();
151 return res;
154 void WKTWriter::write(const Geometry *geometry, Writer *writer) {
155 writeFormatted(geometry, false, writer);
158 string WKTWriter::writeFormatted(const Geometry *geometry) {
159 Writer sw;
160 writeFormatted(geometry, true, &sw);
161 return sw.toString();
164 void WKTWriter::writeFormatted(const Geometry *geometry, Writer *writer) {
165 writeFormatted(geometry, true, writer);
168 void
169 WKTWriter::writeFormatted(const Geometry *geometry, bool isFormatted,
170 Writer *writer)
172 CLocalizer clocale;
173 this->isFormatted=isFormatted;
174 decimalPlaces = roundingPrecision == -1 ? geometry->getPrecisionModel()->getMaximumSignificantDigits() : roundingPrecision;
175 appendGeometryTaggedText(geometry, 0, writer);
178 void
179 WKTWriter::appendGeometryTaggedText(const Geometry *geometry, int level,
180 Writer *writer)
182 outputDimension = min( defaultOutputDimension,
183 geometry->getCoordinateDimension() );
185 indent(level, writer);
186 if ( const Point* point = dynamic_cast<const Point*>(geometry) )
188 appendPointTaggedText(point->getCoordinate(),level,writer);
190 else if ( const LinearRing* lr =
191 dynamic_cast<const LinearRing*>(geometry) )
193 appendLinearRingTaggedText(lr, level, writer);
195 else if ( const LineString* ls =
196 dynamic_cast<const LineString*>(geometry) )
198 appendLineStringTaggedText(ls, level, writer);
200 else if ( const Polygon* x =
201 dynamic_cast<const Polygon*>(geometry) )
203 appendPolygonTaggedText(x, level, writer);
205 else if ( const MultiPoint* x =
206 dynamic_cast<const MultiPoint*>(geometry) )
208 appendMultiPointTaggedText(x, level, writer);
210 else if ( const MultiLineString* x =
211 dynamic_cast<const MultiLineString*>(geometry) )
213 appendMultiLineStringTaggedText(x, level, writer);
215 else if ( const MultiPolygon* x =
216 dynamic_cast<const MultiPolygon*>(geometry) )
218 appendMultiPolygonTaggedText(x, level, writer);
220 else if ( const GeometryCollection* x =
221 dynamic_cast<const GeometryCollection*>(geometry) )
223 appendGeometryCollectionTaggedText(x, level, writer);
225 else
227 assert(0); // Unsupported Geometry implementation
231 /*protected*/
232 void
233 WKTWriter::appendPointTaggedText(const Coordinate* coordinate, int level,
234 Writer *writer)
236 writer->write("POINT ");
237 if( outputDimension == 3 && !old3D && coordinate != NULL )
238 writer->write( "Z " );
240 appendPointText(coordinate, level, writer);
243 void
244 WKTWriter::appendLineStringTaggedText(const LineString *lineString, int level,
245 Writer *writer)
247 writer->write("LINESTRING ");
248 if( outputDimension == 3 && !old3D && !lineString->isEmpty() )
249 writer->write( "Z " );
251 appendLineStringText(lineString, level, false, writer);
255 * Converts a <code>LinearRing</code> to &lt;LinearRing Tagged Text&gt;
256 * format, then appends it to the writer.
258 * @param linearRing the <code>LinearRing</code> to process
259 * @param writer the output writer to append to
261 void WKTWriter::appendLinearRingTaggedText(const LinearRing* linearRing, int level, Writer *writer) {
262 writer->write("LINEARRING ");
263 if( outputDimension == 3 && !old3D && !linearRing->isEmpty() )
264 writer->write( "Z " );
265 appendLineStringText((LineString*)linearRing, level, false, writer);
268 void WKTWriter::appendPolygonTaggedText(const Polygon *polygon, int level, Writer *writer) {
269 writer->write("POLYGON ");
270 if( outputDimension == 3 && !old3D && !polygon->isEmpty())
271 writer->write( "Z " );
272 appendPolygonText(polygon, level, false, writer);
275 void WKTWriter::appendMultiPointTaggedText(const MultiPoint *multipoint, int level, Writer *writer) {
276 writer->write("MULTIPOINT ");
277 if( outputDimension == 3 && !old3D && !multipoint->isEmpty() )
278 writer->write( "Z " );
279 appendMultiPointText(multipoint, level, writer);
282 void WKTWriter::appendMultiLineStringTaggedText(const MultiLineString *multiLineString, int level,Writer *writer) {
283 writer->write("MULTILINESTRING ");
284 if( outputDimension == 3 && !old3D && !multiLineString->isEmpty() )
285 writer->write( "Z " );
286 appendMultiLineStringText(multiLineString, level, false, writer);
289 void WKTWriter::appendMultiPolygonTaggedText(const MultiPolygon *multiPolygon, int level, Writer *writer) {
290 writer->write("MULTIPOLYGON ");
291 if( outputDimension == 3 && !old3D && !multiPolygon->isEmpty() )
292 writer->write( "Z " );
293 appendMultiPolygonText(multiPolygon, level, writer);
296 void WKTWriter::appendGeometryCollectionTaggedText(const GeometryCollection *geometryCollection, int level,Writer *writer) {
297 writer->write("GEOMETRYCOLLECTION ");
298 if( outputDimension == 3 && !old3D && !geometryCollection->isEmpty() )
299 writer->write( "Z " );
300 appendGeometryCollectionText(geometryCollection, level, writer);
303 void
304 WKTWriter::appendPointText(const Coordinate* coordinate, int /*level*/,
305 Writer *writer)
307 if (coordinate==NULL) {
308 writer->write("EMPTY");
309 } else {
310 writer->write("(");
311 appendCoordinate(coordinate, writer);
312 writer->write(")");
316 /* pritected */
317 void
318 WKTWriter::appendCoordinate(const Coordinate* coordinate,
319 Writer *writer)
321 string out="";
322 out+=writeNumber(coordinate->x);
323 out+=" ";
324 out+=writeNumber(coordinate->y);
325 if( outputDimension == 3 )
327 out+=" ";
328 if( ISNAN(coordinate->z) )
329 out+=writeNumber(0.0);
330 else
331 out+=writeNumber(coordinate->z);
333 writer->write(out);
336 /* protected */
337 string
338 WKTWriter::writeNumber(double d) {
340 std::stringstream ss;
342 if ( ! trim ) ss << std::fixed;
343 ss << std::setprecision(decimalPlaces >= 0 ? decimalPlaces : 0) << d;
345 return ss.str();
348 void
349 WKTWriter::appendLineStringText(const LineString *lineString, int level,
350 bool doIndent, Writer *writer)
352 if (lineString->isEmpty()) {
353 writer->write("EMPTY");
354 } else {
355 if (doIndent) indent(level, writer);
356 writer->write("(");
357 for(size_t i=0, n=lineString->getNumPoints(); i<n; ++i)
359 if (i>0) {
360 writer->write(", ");
361 if (i%10==0) indent(level + 2, writer);
363 appendCoordinate(&(lineString->getCoordinateN(i)), writer);
365 writer->write(")");
369 void
370 WKTWriter::appendPolygonText(const Polygon *polygon, int /*level*/,
371 bool indentFirst, Writer *writer)
373 if (polygon->isEmpty()) {
374 writer->write("EMPTY");
375 } else {
376 if (indentFirst) indent(level, writer);
377 writer->write("(");
378 appendLineStringText(polygon->getExteriorRing(), level, false, writer);
379 for (size_t i=0, n=polygon->getNumInteriorRing(); i<n; ++i)
381 writer->write(", ");
382 const LineString *ls=polygon->getInteriorRingN(i);
383 appendLineStringText(ls, level + 1, true, writer);
385 writer->write(")");
389 void
390 WKTWriter::appendMultiPointText(const MultiPoint *multiPoint,
391 int /*level*/, Writer *writer)
393 if (multiPoint->isEmpty()) {
394 writer->write("EMPTY");
395 } else {
396 writer->write("(");
397 for (unsigned int i=0, n=multiPoint->getNumGeometries();
398 i<n; i++)
400 if (i > 0)
402 writer->write(", ");
404 appendCoordinate(
405 dynamic_cast<const Point*>(multiPoint->getGeometryN(i))->getCoordinate(),
406 writer);
408 writer->write(")");
412 void WKTWriter::appendMultiLineStringText(const MultiLineString *multiLineString, int level, bool indentFirst,
413 Writer *writer) {
414 if (multiLineString->isEmpty()) {
415 writer->write("EMPTY");
416 } else {
417 int level2=level;
418 bool doIndent=indentFirst;
419 writer->write("(");
420 for (unsigned int i=0, n=multiLineString->getNumGeometries();
421 i<n; i++)
423 if (i>0) {
424 writer->write(", ");
425 level2=level+1;
426 doIndent=true;
428 const LineString* ls = dynamic_cast<const LineString *>(
429 multiLineString->getGeometryN(i)
431 appendLineStringText(ls, level2, doIndent, writer);
433 writer->write(")");
437 void WKTWriter::appendMultiPolygonText(const MultiPolygon *multiPolygon, int level, Writer *writer) {
438 if (multiPolygon->isEmpty()) {
439 writer->write("EMPTY");
440 } else {
441 int level2=level;
442 bool doIndent=false;
443 writer->write("(");
444 for (unsigned int i=0, n=multiPolygon->getNumGeometries();
445 i < n; i++)
447 if (i>0) {
448 writer->write(", ");
449 level2=level+1;
450 doIndent=true;
452 const Polygon *p = dynamic_cast<const Polygon *>(
453 multiPolygon->getGeometryN(i)
455 appendPolygonText(p, level2, doIndent, writer);
457 writer->write(")");
461 void
462 WKTWriter::appendGeometryCollectionText(
463 const GeometryCollection *geometryCollection,
464 int level,
465 Writer *writer)
467 if (geometryCollection->isEmpty()) {
468 writer->write("EMPTY");
469 } else {
470 int level2=level;
471 writer->write("(");
472 for (unsigned int i=0, n=geometryCollection->getNumGeometries();
473 i < n ; ++i)
475 if (i>0) {
476 writer->write(", ");
477 level2=level+1;
479 appendGeometryTaggedText(geometryCollection->getGeometryN(i),level2,writer);
481 writer->write(")");
485 void WKTWriter::indent(int level, Writer *writer) {
486 if (!isFormatted || level<=0) return;
487 writer->write("\n");
488 writer->write(string(INDENT * level, ' '));
491 } // namespace geos.io
492 } // namespace geos