1 /**********************************************************************
4 * GEOS - Geometry Engine Open Source
5 * http://geos.refractions.net
7 * Copyright (C) 2011 Sandro Santilli <strk@keybit.net>
8 * Copyright (C) 2005-2006 Refractions Research Inc.
9 * Copyright (C) 2001-2002 Vivid Solutions Inc.
11 * This is free software; you can redistribute and/or modify it under
12 * the terms of the GNU Lesser General Public Licence as published
13 * by the Free Software Foundation.
14 * See the COPYING file for more information.
16 **********************************************************************
18 * Last port: io/WKTWriter.java rev. 1.34 (JTS-1.7)
20 **********************************************************************/
22 #include <geos/io/WKTWriter.h>
23 #include <geos/io/Writer.h>
24 #include <geos/io/CLocalizer.h>
25 #include <geos/geom/Coordinate.h>
26 #include <geos/geom/Point.h>
27 #include <geos/geom/LinearRing.h>
28 #include <geos/geom/LineString.h>
29 #include <geos/geom/Polygon.h>
30 #include <geos/geom/MultiPoint.h>
31 #include <geos/geom/MultiLineString.h>
32 #include <geos/geom/MultiPolygon.h>
33 #include <geos/geom/CoordinateSequence.h>
34 #include <geos/geom/PrecisionModel.h>
35 #include <geos/util/IllegalArgumentException.h>
38 #include <cstdio> // should avoid this
46 using namespace geos::geom
;
49 namespace io
{ // geos.io
51 WKTWriter::WKTWriter():
54 roundingPrecision(-1),
57 defaultOutputDimension(2),
64 WKTWriter::setOutputDimension(int dims
)
66 if ( dims
< 2 || dims
> 3 )
67 throw util::IllegalArgumentException("WKT output dimension must be 2 or 3");
68 defaultOutputDimension
= dims
;
71 WKTWriter::~WKTWriter() {}
75 WKTWriter::toLineString(const CoordinateSequence
& seq
)
77 stringstream
buf(ios_base::in
|ios_base::out
);
79 unsigned int npts
= seq
.getSize();
87 for (unsigned int i
=0; i
<npts
; ++i
)
90 buf
<< seq
.getX(i
) << " " << seq
.getY(i
);
103 WKTWriter::toLineString(const Coordinate
& p0
, const Coordinate
& p1
)
105 stringstream
ret(ios_base::in
|ios_base::out
);
106 ret
<< "LINESTRING (" << p0
.x
<< " " << p0
.y
;
110 ret
<< ", " << p1
.x
<< " " << p1
.y
;
121 WKTWriter::toPoint(const Coordinate
& p0
)
123 stringstream
ret(ios_base::in
|ios_base::out
);
126 ret
<< p0
.x
<< " " << p0
.y
<< " " << p0
.z
<< " )";
128 ret
<< p0
.x
<< " " << p0
.y
<< " )";
134 WKTWriter::setRoundingPrecision(int p0
)
139 roundingPrecision
= p0
;
143 WKTWriter::setTrim(bool p0
)
148 string
WKTWriter::write(const Geometry
*geometry
) {
150 writeFormatted(geometry
,false,&sw
);
151 string res
=sw
.toString();
155 void WKTWriter::write(const Geometry
*geometry
, Writer
*writer
) {
156 writeFormatted(geometry
, false, writer
);
159 string
WKTWriter::writeFormatted(const Geometry
*geometry
) {
161 writeFormatted(geometry
, true, &sw
);
162 return sw
.toString();
165 void WKTWriter::writeFormatted(const Geometry
*geometry
, Writer
*writer
) {
166 writeFormatted(geometry
, true, writer
);
170 WKTWriter::writeFormatted(const Geometry
*geometry
, bool isFormatted
,
174 this->isFormatted
=isFormatted
;
175 decimalPlaces
= roundingPrecision
== -1 ? geometry
->getPrecisionModel()->getMaximumSignificantDigits() : roundingPrecision
;
176 appendGeometryTaggedText(geometry
, 0, writer
);
180 WKTWriter::appendGeometryTaggedText(const Geometry
*geometry
, int level
,
183 outputDimension
= min( defaultOutputDimension
,
184 geometry
->getCoordinateDimension() );
186 indent(level
, writer
);
187 if ( const Point
* point
= dynamic_cast<const Point
*>(geometry
) )
189 appendPointTaggedText(point
->getCoordinate(),level
,writer
);
191 else if ( const LinearRing
* lr
=
192 dynamic_cast<const LinearRing
*>(geometry
) )
194 appendLinearRingTaggedText(lr
, level
, writer
);
196 else if ( const LineString
* ls
=
197 dynamic_cast<const LineString
*>(geometry
) )
199 appendLineStringTaggedText(ls
, level
, writer
);
201 else if ( const Polygon
* x
=
202 dynamic_cast<const Polygon
*>(geometry
) )
204 appendPolygonTaggedText(x
, level
, writer
);
206 else if ( const MultiPoint
* x
=
207 dynamic_cast<const MultiPoint
*>(geometry
) )
209 appendMultiPointTaggedText(x
, level
, writer
);
211 else if ( const MultiLineString
* x
=
212 dynamic_cast<const MultiLineString
*>(geometry
) )
214 appendMultiLineStringTaggedText(x
, level
, writer
);
216 else if ( const MultiPolygon
* x
=
217 dynamic_cast<const MultiPolygon
*>(geometry
) )
219 appendMultiPolygonTaggedText(x
, level
, writer
);
221 else if ( const GeometryCollection
* x
=
222 dynamic_cast<const GeometryCollection
*>(geometry
) )
224 appendGeometryCollectionTaggedText(x
, level
, writer
);
228 assert(0); // Unsupported Geometry implementation
234 WKTWriter::appendPointTaggedText(const Coordinate
* coordinate
, int level
,
237 writer
->write("POINT ");
238 if( outputDimension
== 3 && !old3D
&& coordinate
!= NULL
)
239 writer
->write( "Z " );
241 appendPointText(coordinate
, level
, writer
);
245 WKTWriter::appendLineStringTaggedText(const LineString
*lineString
, int level
,
248 writer
->write("LINESTRING ");
249 if( outputDimension
== 3 && !old3D
&& !lineString
->isEmpty() )
250 writer
->write( "Z " );
252 appendLineStringText(lineString
, level
, false, writer
);
256 * Converts a <code>LinearRing</code> to <LinearRing Tagged Text>
257 * format, then appends it to the writer.
259 * @param linearRing the <code>LinearRing</code> to process
260 * @param writer the output writer to append to
262 void WKTWriter::appendLinearRingTaggedText(const LinearRing
* linearRing
, int level
, Writer
*writer
) {
263 writer
->write("LINEARRING ");
264 if( outputDimension
== 3 && !old3D
&& !linearRing
->isEmpty() )
265 writer
->write( "Z " );
266 appendLineStringText((LineString
*)linearRing
, level
, false, writer
);
269 void WKTWriter::appendPolygonTaggedText(const Polygon
*polygon
, int level
, Writer
*writer
) {
270 writer
->write("POLYGON ");
271 if( outputDimension
== 3 && !old3D
&& !polygon
->isEmpty())
272 writer
->write( "Z " );
273 appendPolygonText(polygon
, level
, false, writer
);
276 void WKTWriter::appendMultiPointTaggedText(const MultiPoint
*multipoint
, int level
, Writer
*writer
) {
277 writer
->write("MULTIPOINT ");
278 if( outputDimension
== 3 && !old3D
&& !multipoint
->isEmpty() )
279 writer
->write( "Z " );
280 appendMultiPointText(multipoint
, level
, writer
);
283 void WKTWriter::appendMultiLineStringTaggedText(const MultiLineString
*multiLineString
, int level
,Writer
*writer
) {
284 writer
->write("MULTILINESTRING ");
285 if( outputDimension
== 3 && !old3D
&& !multiLineString
->isEmpty() )
286 writer
->write( "Z " );
287 appendMultiLineStringText(multiLineString
, level
, false, writer
);
290 void WKTWriter::appendMultiPolygonTaggedText(const MultiPolygon
*multiPolygon
, int level
, Writer
*writer
) {
291 writer
->write("MULTIPOLYGON ");
292 if( outputDimension
== 3 && !old3D
&& !multiPolygon
->isEmpty() )
293 writer
->write( "Z " );
294 appendMultiPolygonText(multiPolygon
, level
, writer
);
297 void WKTWriter::appendGeometryCollectionTaggedText(const GeometryCollection
*geometryCollection
, int level
,Writer
*writer
) {
298 writer
->write("GEOMETRYCOLLECTION ");
299 if( outputDimension
== 3 && !old3D
&& !geometryCollection
->isEmpty() )
300 writer
->write( "Z " );
301 appendGeometryCollectionText(geometryCollection
, level
, writer
);
305 WKTWriter::appendPointText(const Coordinate
* coordinate
, int /*level*/,
308 if (coordinate
==NULL
) {
309 writer
->write("EMPTY");
312 appendCoordinate(coordinate
, writer
);
319 WKTWriter::appendCoordinate(const Coordinate
* coordinate
,
323 out
+=writeNumber(coordinate
->x
);
325 out
+=writeNumber(coordinate
->y
);
326 if( outputDimension
== 3 )
329 if( ISNAN(coordinate
->z
) )
330 out
+=writeNumber(0.0);
332 out
+=writeNumber(coordinate
->z
);
339 WKTWriter::writeNumber(double d
) {
341 std::stringstream ss
;
343 if ( ! trim
) ss
<< std::fixed
;
344 ss
<< std::setprecision(decimalPlaces
>= 0 ? decimalPlaces
: 0) << d
;
350 WKTWriter::appendLineStringText(const LineString
*lineString
, int level
,
351 bool doIndent
, Writer
*writer
)
353 if (lineString
->isEmpty()) {
354 writer
->write("EMPTY");
356 if (doIndent
) indent(level
, writer
);
358 for(size_t i
=0, n
=lineString
->getNumPoints(); i
<n
; ++i
)
362 if (i
%10==0) indent(level
+ 2, writer
);
364 appendCoordinate(&(lineString
->getCoordinateN(i
)), writer
);
371 WKTWriter::appendPolygonText(const Polygon
*polygon
, int /*level*/,
372 bool indentFirst
, Writer
*writer
)
374 if (polygon
->isEmpty()) {
375 writer
->write("EMPTY");
377 if (indentFirst
) indent(level
, writer
);
379 appendLineStringText(polygon
->getExteriorRing(), level
, false, writer
);
380 for (size_t i
=0, n
=polygon
->getNumInteriorRing(); i
<n
; ++i
)
383 const LineString
*ls
=polygon
->getInteriorRingN(i
);
384 appendLineStringText(ls
, level
+ 1, true, writer
);
391 WKTWriter::appendMultiPointText(const MultiPoint
*multiPoint
,
392 int /*level*/, Writer
*writer
)
394 if (multiPoint
->isEmpty()) {
395 writer
->write("EMPTY");
398 for (unsigned int i
=0, n
=multiPoint
->getNumGeometries();
406 dynamic_cast<const Point
*>(multiPoint
->getGeometryN(i
))->getCoordinate(),
413 void WKTWriter::appendMultiLineStringText(const MultiLineString
*multiLineString
, int level
, bool indentFirst
,
415 if (multiLineString
->isEmpty()) {
416 writer
->write("EMPTY");
419 bool doIndent
=indentFirst
;
421 for (unsigned int i
=0, n
=multiLineString
->getNumGeometries();
429 const LineString
* ls
= dynamic_cast<const LineString
*>(
430 multiLineString
->getGeometryN(i
)
432 appendLineStringText(ls
, level2
, doIndent
, writer
);
438 void WKTWriter::appendMultiPolygonText(const MultiPolygon
*multiPolygon
, int level
, Writer
*writer
) {
439 if (multiPolygon
->isEmpty()) {
440 writer
->write("EMPTY");
445 for (unsigned int i
=0, n
=multiPolygon
->getNumGeometries();
453 const Polygon
*p
= dynamic_cast<const Polygon
*>(
454 multiPolygon
->getGeometryN(i
)
456 appendPolygonText(p
, level2
, doIndent
, writer
);
463 WKTWriter::appendGeometryCollectionText(
464 const GeometryCollection
*geometryCollection
,
468 if (geometryCollection
->isEmpty()) {
469 writer
->write("EMPTY");
473 for (unsigned int i
=0, n
=geometryCollection
->getNumGeometries();
480 appendGeometryTaggedText(geometryCollection
->getGeometryN(i
),level2
,writer
);
486 void WKTWriter::indent(int level
, Writer
*writer
) {
487 if (!isFormatted
|| level
<=0) return;
489 writer
->write(string(INDENT
* level
, ' '));
492 } // namespace geos.io