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>
37 #include <cstdio> // should avoid this
45 using namespace geos::geom
;
48 namespace io
{ // geos.io
50 WKTWriter::WKTWriter():
53 roundingPrecision(-1),
56 defaultOutputDimension(2),
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() {}
74 WKTWriter::toLineString(const CoordinateSequence
& seq
)
76 stringstream
buf(ios_base::in
|ios_base::out
);
78 unsigned int npts
= seq
.getSize();
86 for (unsigned int i
=0; i
<npts
; ++i
)
89 buf
<< seq
.getX(i
) << " " << seq
.getY(i
);
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
;
109 ret
<< ", " << p1
.x
<< " " << p1
.y
;
120 WKTWriter::toPoint(const Coordinate
& p0
)
122 stringstream
ret(ios_base::in
|ios_base::out
);
125 ret
<< p0
.x
<< " " << p0
.y
<< " " << p0
.z
<< " )";
127 ret
<< p0
.x
<< " " << p0
.y
<< " )";
133 WKTWriter::setRoundingPrecision(int p0
)
138 roundingPrecision
= p0
;
142 WKTWriter::setTrim(bool p0
)
147 string
WKTWriter::write(const Geometry
*geometry
) {
149 writeFormatted(geometry
,false,&sw
);
150 string res
=sw
.toString();
154 void WKTWriter::write(const Geometry
*geometry
, Writer
*writer
) {
155 writeFormatted(geometry
, false, writer
);
158 string
WKTWriter::writeFormatted(const Geometry
*geometry
) {
160 writeFormatted(geometry
, true, &sw
);
161 return sw
.toString();
164 void WKTWriter::writeFormatted(const Geometry
*geometry
, Writer
*writer
) {
165 writeFormatted(geometry
, true, writer
);
169 WKTWriter::writeFormatted(const Geometry
*geometry
, bool isFormatted
,
173 this->isFormatted
=isFormatted
;
174 decimalPlaces
= roundingPrecision
== -1 ? geometry
->getPrecisionModel()->getMaximumSignificantDigits() : roundingPrecision
;
175 appendGeometryTaggedText(geometry
, 0, writer
);
179 WKTWriter::appendGeometryTaggedText(const Geometry
*geometry
, int level
,
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
);
227 assert(0); // Unsupported Geometry implementation
233 WKTWriter::appendPointTaggedText(const Coordinate
* coordinate
, int level
,
236 writer
->write("POINT ");
237 if( outputDimension
== 3 && !old3D
&& coordinate
!= NULL
)
238 writer
->write( "Z " );
240 appendPointText(coordinate
, level
, writer
);
244 WKTWriter::appendLineStringTaggedText(const LineString
*lineString
, int level
,
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 <LinearRing Tagged Text>
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
);
304 WKTWriter::appendPointText(const Coordinate
* coordinate
, int /*level*/,
307 if (coordinate
==NULL
) {
308 writer
->write("EMPTY");
311 appendCoordinate(coordinate
, writer
);
318 WKTWriter::appendCoordinate(const Coordinate
* coordinate
,
322 out
+=writeNumber(coordinate
->x
);
324 out
+=writeNumber(coordinate
->y
);
325 if( outputDimension
== 3 )
328 if( ISNAN(coordinate
->z
) )
329 out
+=writeNumber(0.0);
331 out
+=writeNumber(coordinate
->z
);
338 WKTWriter::writeNumber(double d
) {
340 std::stringstream ss
;
342 if ( ! trim
) ss
<< std::fixed
;
343 ss
<< std::setprecision(decimalPlaces
>= 0 ? decimalPlaces
: 0) << d
;
349 WKTWriter::appendLineStringText(const LineString
*lineString
, int level
,
350 bool doIndent
, Writer
*writer
)
352 if (lineString
->isEmpty()) {
353 writer
->write("EMPTY");
355 if (doIndent
) indent(level
, writer
);
357 for(size_t i
=0, n
=lineString
->getNumPoints(); i
<n
; ++i
)
361 if (i
%10==0) indent(level
+ 2, writer
);
363 appendCoordinate(&(lineString
->getCoordinateN(i
)), writer
);
370 WKTWriter::appendPolygonText(const Polygon
*polygon
, int /*level*/,
371 bool indentFirst
, Writer
*writer
)
373 if (polygon
->isEmpty()) {
374 writer
->write("EMPTY");
376 if (indentFirst
) indent(level
, writer
);
378 appendLineStringText(polygon
->getExteriorRing(), level
, false, writer
);
379 for (size_t i
=0, n
=polygon
->getNumInteriorRing(); i
<n
; ++i
)
382 const LineString
*ls
=polygon
->getInteriorRingN(i
);
383 appendLineStringText(ls
, level
+ 1, true, writer
);
390 WKTWriter::appendMultiPointText(const MultiPoint
*multiPoint
,
391 int /*level*/, Writer
*writer
)
393 if (multiPoint
->isEmpty()) {
394 writer
->write("EMPTY");
397 for (unsigned int i
=0, n
=multiPoint
->getNumGeometries();
405 dynamic_cast<const Point
*>(multiPoint
->getGeometryN(i
))->getCoordinate(),
412 void WKTWriter::appendMultiLineStringText(const MultiLineString
*multiLineString
, int level
, bool indentFirst
,
414 if (multiLineString
->isEmpty()) {
415 writer
->write("EMPTY");
418 bool doIndent
=indentFirst
;
420 for (unsigned int i
=0, n
=multiLineString
->getNumGeometries();
428 const LineString
* ls
= dynamic_cast<const LineString
*>(
429 multiLineString
->getGeometryN(i
)
431 appendLineStringText(ls
, level2
, doIndent
, writer
);
437 void WKTWriter::appendMultiPolygonText(const MultiPolygon
*multiPolygon
, int level
, Writer
*writer
) {
438 if (multiPolygon
->isEmpty()) {
439 writer
->write("EMPTY");
444 for (unsigned int i
=0, n
=multiPolygon
->getNumGeometries();
452 const Polygon
*p
= dynamic_cast<const Polygon
*>(
453 multiPolygon
->getGeometryN(i
)
455 appendPolygonText(p
, level2
, doIndent
, writer
);
462 WKTWriter::appendGeometryCollectionText(
463 const GeometryCollection
*geometryCollection
,
467 if (geometryCollection
->isEmpty()) {
468 writer
->write("EMPTY");
472 for (unsigned int i
=0, n
=geometryCollection
->getNumGeometries();
479 appendGeometryTaggedText(geometryCollection
->getGeometryN(i
),level2
,writer
);
485 void WKTWriter::indent(int level
, Writer
*writer
) {
486 if (!isFormatted
|| level
<=0) return;
488 writer
->write(string(INDENT
* level
, ' '));
491 } // namespace geos.io