1 /**********************************************************************
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
6 * Copyright (C) 2005-2006 Refractions Research Inc.
7 * Copyright (C) 2001-2002 Vivid Solutions Inc.
9 * This is free software; you can redistribute and/or modify it under
10 * the terms of the GNU Lesser General Public Licence as published
11 * by the Free Software Foundation.
12 * See the COPYING file for more information.
14 **********************************************************************
16 * Last port: io/WKTReader.java rev. 1.1 (JTS-1.7)
18 **********************************************************************/
20 #include <geos/io/WKTReader.h>
21 #include <geos/io/StringTokenizer.h>
22 #include <geos/io/ParseException.h>
23 #include <geos/io/CLocalizer.h>
24 #include <geos/geom/GeometryFactory.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/CoordinateSequenceFactory.h>
34 #include <geos/geom/CoordinateSequence.h>
35 #include <geos/geom/PrecisionModel.h>
36 #include <geos/inline.h>
51 #include <geos/io/WKTReader.inl>
55 using namespace geos::geom
;
58 namespace io
{ // geos.io
61 WKTReader::read(const string
&wellKnownText
)
63 //auto_ptr<StringTokenizer> tokenizer(new StringTokenizer(wellKnownText));
65 StringTokenizer
tokenizer(wellKnownText
);
67 g
=readGeometryTaggedText(&tokenizer
);
72 WKTReader::getCoordinates(StringTokenizer
*tokenizer
)
75 string nextToken
=getNextEmptyOrOpener(tokenizer
);
76 if (nextToken
=="EMPTY") {
77 return geometryFactory
->getCoordinateSequenceFactory()->create(NULL
);
78 //new CoordinateArraySequence();
82 getPreciseCoordinate(tokenizer
, coord
, dim
);
84 CoordinateSequence
*coordinates
= \
85 geometryFactory
->getCoordinateSequenceFactory()->create((size_t)0,dim
);
86 coordinates
->add(coord
);
88 nextToken
=getNextCloserOrComma(tokenizer
);
89 while (nextToken
==",") {
90 getPreciseCoordinate(tokenizer
, coord
, dim
);
91 coordinates
->add(coord
);
92 nextToken
=getNextCloserOrComma(tokenizer
);
103 WKTReader::getPreciseCoordinate(StringTokenizer
*tokenizer
,
107 coord
.x
=getNextNumber(tokenizer
);
108 coord
.y
=getNextNumber(tokenizer
);
109 if (isNumberNext(tokenizer
)) {
110 coord
.z
=getNextNumber(tokenizer
);
113 // If there is a fourth value (M) read and discard it.
114 if (isNumberNext(tokenizer
))
115 getNextNumber(tokenizer
);
118 coord
.z
=DoubleNotANumber
;
121 precisionModel
->makePrecise(coord
);
125 WKTReader::isNumberNext(StringTokenizer
*tokenizer
)
127 return tokenizer
->peekNextToken()==StringTokenizer::TT_NUMBER
;
131 WKTReader::getNextNumber(StringTokenizer
*tokenizer
)
133 int type
=tokenizer
->nextToken();
135 case StringTokenizer::TT_EOF
:
136 throw ParseException("Expected number but encountered end of stream");
137 case StringTokenizer::TT_EOL
:
138 throw ParseException("Expected number but encountered end of line");
139 case StringTokenizer::TT_NUMBER
:
140 return tokenizer
->getNVal();
141 case StringTokenizer::TT_WORD
:
142 throw ParseException("Expected number but encountered word",tokenizer
->getSVal());
144 throw ParseException("Expected number but encountered '('");
146 throw ParseException("Expected number but encountered ')'");
148 throw ParseException("Expected number but encountered ','");
150 assert(0); // Encountered unexpected StreamTokenizer type
155 WKTReader::getNextEmptyOrOpener(StringTokenizer
*tokenizer
)
157 string nextWord
=getNextWord(tokenizer
);
159 // Skip the Z, M or ZM of an SF1.2 3/4 dim coordinate.
160 if (nextWord
== "Z" || nextWord
== "M" || nextWord
== "ZM" )
161 nextWord
= getNextWord(tokenizer
);
163 if (nextWord
=="EMPTY" || nextWord
=="(") {
166 throw ParseException("Expected 'Z', 'M', 'ZM', 'EMPTY' or '(' but encountered ",nextWord
);
170 WKTReader::getNextCloserOrComma(StringTokenizer
*tokenizer
)
172 string nextWord
=getNextWord(tokenizer
);
173 if (nextWord
=="," || nextWord
==")") {
176 throw ParseException("Expected ')' or ',' but encountered",nextWord
);
180 WKTReader::getNextCloser(StringTokenizer
*tokenizer
)
182 string nextWord
=getNextWord(tokenizer
);
186 throw ParseException("Expected ')' but encountered",nextWord
);
190 WKTReader::getNextWord(StringTokenizer
*tokenizer
)
192 int type
=tokenizer
->nextToken();
194 case StringTokenizer::TT_EOF
:
195 throw ParseException("Expected word but encountered end of stream");
196 case StringTokenizer::TT_EOL
:
197 throw ParseException("Expected word but encountered end of line");
198 case StringTokenizer::TT_NUMBER
:
199 throw ParseException("Expected word but encountered number", tokenizer
->getNVal());
200 case StringTokenizer::TT_WORD
:
202 string word
= tokenizer
->getSVal();
207 word
[i
] = static_cast<char>(toupper(word
[i
]));
219 //throw ParseException("Encountered unexpected StreamTokenizer type");
224 WKTReader::readGeometryTaggedText(StringTokenizer
*tokenizer
)
226 string type
= getNextWord(tokenizer
);
228 return readPointText(tokenizer
);
229 } else if (type
=="LINESTRING") {
230 return readLineStringText(tokenizer
);
231 } else if (type
=="LINEARRING") {
232 return readLinearRingText(tokenizer
);
233 } else if (type
=="POLYGON") {
234 return readPolygonText(tokenizer
);
235 } else if (type
=="MULTIPOINT") {
236 return readMultiPointText(tokenizer
);
237 } else if (type
=="MULTILINESTRING") {
238 return readMultiLineStringText(tokenizer
);
239 } else if (type
=="MULTIPOLYGON") {
240 return readMultiPolygonText(tokenizer
);
241 } else if (type
=="GEOMETRYCOLLECTION") {
242 return readGeometryCollectionText(tokenizer
);
244 throw ParseException("Unknown type",type
);
248 WKTReader::readPointText(StringTokenizer
*tokenizer
)
251 string nextToken
=getNextEmptyOrOpener(tokenizer
);
252 if (nextToken
=="EMPTY") {
253 return geometryFactory
->createPoint(Coordinate::getNull());
257 getPreciseCoordinate(tokenizer
, coord
, dim
);
258 getNextCloser(tokenizer
);
260 return geometryFactory
->createPoint(coord
);
263 LineString
* WKTReader::readLineStringText(StringTokenizer
*tokenizer
) {
264 CoordinateSequence
*coords
= getCoordinates(tokenizer
);
265 LineString
*ret
= geometryFactory
->createLineString(coords
);
269 LinearRing
* WKTReader::readLinearRingText(StringTokenizer
*tokenizer
) {
270 CoordinateSequence
*coords
= getCoordinates(tokenizer
);
272 ret
= geometryFactory
->createLinearRing(coords
);
277 WKTReader::readMultiPointText(StringTokenizer
*tokenizer
)
279 string nextToken
=getNextEmptyOrOpener(tokenizer
);
280 if (nextToken
=="EMPTY") {
281 return geometryFactory
->createMultiPoint();
284 int tok
= tokenizer
->peekNextToken();
286 if ( tok
== StringTokenizer::TT_NUMBER
)
290 // Try to parse deprecated form "MULTIPOINT(0 0, 1 1)"
291 const CoordinateSequenceFactory
* csf
= \
292 geometryFactory
->getCoordinateSequenceFactory();
293 CoordinateSequence
*coords
= csf
->create(NULL
);
297 getPreciseCoordinate(tokenizer
, coord
, dim
);
299 nextToken
=getNextCloserOrComma(tokenizer
);
300 } while(nextToken
== ",");
302 MultiPoint
*ret
= geometryFactory
->createMultiPoint(*coords
);
311 else if ( tok
== '(' )
313 // Try to parse correct form "MULTIPOINT((0 0), (1 1))"
314 vector
<Geometry
*> *points
=new vector
<Geometry
*>();
317 Point
*point
=readPointText(tokenizer
);
318 points
->push_back(point
);
319 nextToken
=getNextCloserOrComma(tokenizer
);
320 } while(nextToken
== ",");
321 return geometryFactory
->createMultiPoint(points
);
324 for (size_t i
=0; i
<points
->size(); i
++)
336 err
<< "Unexpected token: ";
339 case StringTokenizer::TT_WORD
:
340 err
<< "WORD " << tokenizer
->getSVal();
342 case StringTokenizer::TT_NUMBER
:
343 err
<< "NUMBER " << tokenizer
->getNVal();
345 case StringTokenizer::TT_EOF
:
346 case StringTokenizer::TT_EOL
:
363 throw ParseException(err
.str());
368 WKTReader::readPolygonText(StringTokenizer
*tokenizer
)
371 LinearRing
*shell
=NULL
;
372 string nextToken
=getNextEmptyOrOpener(tokenizer
);
373 if (nextToken
=="EMPTY") {
374 return geometryFactory
->createPolygon(NULL
,NULL
);
377 vector
<Geometry
*> *holes
=new vector
<Geometry
*>();
379 shell
=readLinearRingText(tokenizer
);
380 nextToken
=getNextCloserOrComma(tokenizer
);
381 while(nextToken
==",") {
382 LinearRing
*hole
=readLinearRingText(tokenizer
);
383 holes
->push_back(hole
);
384 nextToken
=getNextCloserOrComma(tokenizer
);
386 poly
= geometryFactory
->createPolygon(shell
,holes
);
388 for (unsigned int i
=0; i
<holes
->size(); i
++)
397 MultiLineString
* WKTReader::readMultiLineStringText(StringTokenizer
*tokenizer
) {
398 string nextToken
=getNextEmptyOrOpener(tokenizer
);
399 if (nextToken
=="EMPTY") {
400 return geometryFactory
->createMultiLineString(NULL
);
402 vector
<Geometry
*> *lineStrings
=new vector
<Geometry
*>();
403 LineString
*lineString
=readLineStringText(tokenizer
);
404 lineStrings
->push_back(lineString
);
405 nextToken
=getNextCloserOrComma(tokenizer
);
406 while(nextToken
==",") {
407 LineString
*lineString
=readLineStringText(tokenizer
);
408 lineStrings
->push_back(lineString
);
409 nextToken
=getNextCloserOrComma(tokenizer
);
411 MultiLineString
*ret
= geometryFactory
->createMultiLineString(lineStrings
);
412 //for (int i=0; i<lineStrings->size(); i++) delete (*lineStrings)[i];
413 //delete lineStrings;
417 MultiPolygon
* WKTReader::readMultiPolygonText(StringTokenizer
*tokenizer
) {
418 string nextToken
=getNextEmptyOrOpener(tokenizer
);
419 if (nextToken
=="EMPTY") {
420 return geometryFactory
->createMultiPolygon(NULL
);
422 vector
<Geometry
*> *polygons
=new vector
<Geometry
*>();
423 Polygon
*polygon
=readPolygonText(tokenizer
);
424 polygons
->push_back(polygon
);
425 nextToken
=getNextCloserOrComma(tokenizer
);
426 while(nextToken
==",") {
427 Polygon
*polygon
=readPolygonText(tokenizer
);
428 polygons
->push_back(polygon
);
429 nextToken
=getNextCloserOrComma(tokenizer
);
431 MultiPolygon
*ret
= geometryFactory
->createMultiPolygon(polygons
);
432 //for (int i=0; i<polygons->size(); i++) delete (*polygons)[i];
437 GeometryCollection
* WKTReader::readGeometryCollectionText(StringTokenizer
*tokenizer
) {
438 string nextToken
=getNextEmptyOrOpener(tokenizer
);
439 if (nextToken
=="EMPTY") {
440 return geometryFactory
->createGeometryCollection(NULL
);
442 vector
<Geometry
*> *geoms
=new vector
<Geometry
*>();
444 geom
=readGeometryTaggedText(tokenizer
);
445 geoms
->push_back(geom
);
446 nextToken
=getNextCloserOrComma(tokenizer
);
447 while(nextToken
==",") {
448 geom
=readGeometryTaggedText(tokenizer
);
449 geoms
->push_back(geom
);
450 nextToken
=getNextCloserOrComma(tokenizer
);
452 GeometryCollection
*ret
= geometryFactory
->createGeometryCollection(geoms
);
453 //for (int i=0; i<geoms->size(); i++) delete (*geoms)[i];
458 } // namespace geos.io
461 /**********************************************************************
463 * Revision 1.42 2006/04/26 16:35:40 strk
464 * Had WKTReader accept correct form for MultiPoint
466 * Revision 1.41 2006/04/10 12:05:35 strk
467 * Added inline-replicator implementation files to make sure
468 * functions in .inl files are still available out-of-line.
469 * A side effect is this should fix MingW build.
471 * Revision 1.40 2006/03/24 09:52:41 strk
472 * USE_INLINE => GEOS_INLINE
474 * Revision 1.39 2006/03/22 16:58:35 strk
475 * Removed (almost) all inclusions of geom.h.
476 * Removed obsoleted .cpp files.
477 * Fixed a bug in WKTReader not using the provided CoordinateSequence
478 * implementation, optimized out some memory allocations.
480 **********************************************************************/