/********************************************************************** * * GEOS - Geometry Engine Open Source * http://geos.osgeo.org * * Copyright (C) 2005-2006 Refractions Research Inc. * Copyright (C) 2001-2002 Vivid Solutions Inc. * * This is free software; you can redistribute and/or modify it under * the terms of the GNU Lesser General Public Licence as published * by the Free Software Foundation. * See the COPYING file for more information. * ********************************************************************** * * Last port: io/WKTReader.java rev. 1.1 (JTS-1.7) * **********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef GEOS_DEBUG #define GEOS_DEBUG 0 #endif #ifdef GEOS_DEBUG #include #endif #ifndef GEOS_INLINE #include #endif using namespace std; using namespace geos::geom; namespace geos { namespace io { // geos.io Geometry * WKTReader::read(const string &wellKnownText) { //auto_ptr tokenizer(new StringTokenizer(wellKnownText)); CLocalizer clocale; StringTokenizer tokenizer(wellKnownText); Geometry *g=NULL; g=readGeometryTaggedText(&tokenizer); return g; } CoordinateSequence* WKTReader::getCoordinates(StringTokenizer *tokenizer) { size_t dim; string nextToken=getNextEmptyOrOpener(tokenizer); if (nextToken=="EMPTY") { return geometryFactory->getCoordinateSequenceFactory()->create(); //new CoordinateArraySequence(); } Coordinate coord; getPreciseCoordinate(tokenizer, coord, dim); CoordinateSequence *coordinates = \ geometryFactory->getCoordinateSequenceFactory()->create((size_t)0,dim); coordinates->add(coord); try { nextToken=getNextCloserOrComma(tokenizer); while (nextToken==",") { getPreciseCoordinate(tokenizer, coord, dim ); coordinates->add(coord); nextToken=getNextCloserOrComma(tokenizer); } } catch (...) { delete coordinates; throw; } return coordinates; } void WKTReader::getPreciseCoordinate(StringTokenizer *tokenizer, Coordinate& coord, size_t &dim ) { coord.x=getNextNumber(tokenizer); coord.y=getNextNumber(tokenizer); if (isNumberNext(tokenizer)) { coord.z=getNextNumber(tokenizer); dim = 3; // If there is a fourth value (M) read and discard it. if (isNumberNext(tokenizer)) getNextNumber(tokenizer); } else { coord.z=DoubleNotANumber; dim = 2; } precisionModel->makePrecise(coord); } bool WKTReader::isNumberNext(StringTokenizer *tokenizer) { return tokenizer->peekNextToken()==StringTokenizer::TT_NUMBER; } double WKTReader::getNextNumber(StringTokenizer *tokenizer) { int type=tokenizer->nextToken(); switch(type){ case StringTokenizer::TT_EOF: throw ParseException("Expected number but encountered end of stream"); case StringTokenizer::TT_EOL: throw ParseException("Expected number but encountered end of line"); case StringTokenizer::TT_NUMBER: return tokenizer->getNVal(); case StringTokenizer::TT_WORD: throw ParseException("Expected number but encountered word",tokenizer->getSVal()); case '(': throw ParseException("Expected number but encountered '('"); case ')': throw ParseException("Expected number but encountered ')'"); case ',': throw ParseException("Expected number but encountered ','"); } assert(0); // Encountered unexpected StreamTokenizer type return 0; } string WKTReader::getNextEmptyOrOpener(StringTokenizer *tokenizer) { string nextWord=getNextWord(tokenizer); // Skip the Z, M or ZM of an SF1.2 3/4 dim coordinate. if (nextWord == "Z" || nextWord == "M" || nextWord == "ZM" ) nextWord = getNextWord(tokenizer); if (nextWord=="EMPTY" || nextWord=="(") { return nextWord; } throw ParseException("Expected 'Z', 'M', 'ZM', 'EMPTY' or '(' but encountered ",nextWord); } string WKTReader::getNextCloserOrComma(StringTokenizer *tokenizer) { string nextWord=getNextWord(tokenizer); if (nextWord=="," || nextWord==")") { return nextWord; } throw ParseException("Expected ')' or ',' but encountered",nextWord); } string WKTReader::getNextCloser(StringTokenizer *tokenizer) { string nextWord=getNextWord(tokenizer); if (nextWord==")") { return nextWord; } throw ParseException("Expected ')' but encountered",nextWord); } string WKTReader::getNextWord(StringTokenizer *tokenizer) { int type=tokenizer->nextToken(); switch(type){ case StringTokenizer::TT_EOF: throw ParseException("Expected word but encountered end of stream"); case StringTokenizer::TT_EOL: throw ParseException("Expected word but encountered end of line"); case StringTokenizer::TT_NUMBER: throw ParseException("Expected word but encountered number", tokenizer->getNVal()); case StringTokenizer::TT_WORD: { string word = tokenizer->getSVal(); int i = word.size(); while( --i >= 0 ) { word[i] = static_cast(toupper(word[i])); } return word; } case '(': return "("; case ')': return ")"; case ',': return ","; } assert(0); //throw ParseException("Encountered unexpected StreamTokenizer type"); return ""; } Geometry* WKTReader::readGeometryTaggedText(StringTokenizer *tokenizer) { string type = getNextWord(tokenizer); if (type=="POINT") { return readPointText(tokenizer); } else if (type=="LINESTRING") { return readLineStringText(tokenizer); } else if (type=="LINEARRING") { return readLinearRingText(tokenizer); } else if (type=="POLYGON") { return readPolygonText(tokenizer); } else if (type=="MULTIPOINT") { return readMultiPointText(tokenizer); } else if (type=="MULTILINESTRING") { return readMultiLineStringText(tokenizer); } else if (type=="MULTIPOLYGON") { return readMultiPolygonText(tokenizer); } else if (type=="GEOMETRYCOLLECTION") { return readGeometryCollectionText(tokenizer); } throw ParseException("Unknown type",type); } Point* WKTReader::readPointText(StringTokenizer *tokenizer) { size_t dim; string nextToken=getNextEmptyOrOpener(tokenizer); if (nextToken=="EMPTY") { return geometryFactory->createPoint(Coordinate::getNull()); } Coordinate coord; getPreciseCoordinate(tokenizer, coord, dim); getNextCloser(tokenizer); return geometryFactory->createPoint(coord); } LineString* WKTReader::readLineStringText(StringTokenizer *tokenizer) { CoordinateSequence *coords = getCoordinates(tokenizer); LineString *ret = geometryFactory->createLineString(coords); return ret; } LinearRing* WKTReader::readLinearRingText(StringTokenizer *tokenizer) { CoordinateSequence *coords = getCoordinates(tokenizer); LinearRing *ret; ret = geometryFactory->createLinearRing(coords); return ret; } MultiPoint* WKTReader::readMultiPointText(StringTokenizer *tokenizer) { string nextToken=getNextEmptyOrOpener(tokenizer); if (nextToken=="EMPTY") { return geometryFactory->createMultiPoint(); } int tok = tokenizer->peekNextToken(); if ( tok == StringTokenizer::TT_NUMBER ) { size_t dim; // Try to parse deprecated form "MULTIPOINT(0 0, 1 1)" const CoordinateSequenceFactory* csf = \ geometryFactory->getCoordinateSequenceFactory(); CoordinateSequence *coords = csf->create(); try { do { Coordinate coord; getPreciseCoordinate(tokenizer, coord, dim); coords->add(coord); nextToken=getNextCloserOrComma(tokenizer); } while(nextToken == ","); MultiPoint *ret = geometryFactory->createMultiPoint(*coords); delete coords; return ret; } catch (...) { delete coords; throw; } } else if ( tok == '(' ) { // Try to parse correct form "MULTIPOINT((0 0), (1 1))" vector *points=new vector(); try { do { Point *point=readPointText(tokenizer); points->push_back(point); nextToken=getNextCloserOrComma(tokenizer); } while(nextToken == ","); return geometryFactory->createMultiPoint(points); } catch (...) { // clean up for (size_t i=0; isize(); i++) { delete (*points)[i]; } delete points; throw; } } else { stringstream err; err << "Unexpected token: "; switch (tok) { case StringTokenizer::TT_WORD: err << "WORD " << tokenizer->getSVal(); break; case StringTokenizer::TT_NUMBER: err << "NUMBER " << tokenizer->getNVal(); break; case StringTokenizer::TT_EOF: case StringTokenizer::TT_EOL: err << "EOF or EOL"; break; case '(': err << "("; break; case ')': err << ")"; break; case ',': err << ","; break; default: err << "??"; break; } err << endl; throw ParseException(err.str()); } } Polygon* WKTReader::readPolygonText(StringTokenizer *tokenizer) { Polygon *poly=NULL; LinearRing *shell=NULL; string nextToken=getNextEmptyOrOpener(tokenizer); if (nextToken=="EMPTY") { return geometryFactory->createPolygon(NULL,NULL); } vector *holes=new vector(); try { shell=readLinearRingText(tokenizer); nextToken=getNextCloserOrComma(tokenizer); while(nextToken==",") { LinearRing *hole=readLinearRingText(tokenizer); holes->push_back(hole); nextToken=getNextCloserOrComma(tokenizer); } poly = geometryFactory->createPolygon(shell,holes); } catch (...) { for (unsigned int i=0; isize(); i++) delete (*holes)[i]; delete holes; delete shell; throw; } return poly; } MultiLineString* WKTReader::readMultiLineStringText(StringTokenizer *tokenizer) { string nextToken=getNextEmptyOrOpener(tokenizer); if (nextToken=="EMPTY") { return geometryFactory->createMultiLineString(NULL); } vector *lineStrings=new vector(); LineString *lineString=readLineStringText(tokenizer); lineStrings->push_back(lineString); nextToken=getNextCloserOrComma(tokenizer); while(nextToken==",") { LineString *lineString=readLineStringText(tokenizer); lineStrings->push_back(lineString); nextToken=getNextCloserOrComma(tokenizer); } MultiLineString *ret = geometryFactory->createMultiLineString(lineStrings); //for (int i=0; isize(); i++) delete (*lineStrings)[i]; //delete lineStrings; return ret; } MultiPolygon* WKTReader::readMultiPolygonText(StringTokenizer *tokenizer) { string nextToken=getNextEmptyOrOpener(tokenizer); if (nextToken=="EMPTY") { return geometryFactory->createMultiPolygon(NULL); } vector *polygons=new vector(); Polygon *polygon=readPolygonText(tokenizer); polygons->push_back(polygon); nextToken=getNextCloserOrComma(tokenizer); while(nextToken==",") { Polygon *polygon=readPolygonText(tokenizer); polygons->push_back(polygon); nextToken=getNextCloserOrComma(tokenizer); } MultiPolygon *ret = geometryFactory->createMultiPolygon(polygons); //for (int i=0; isize(); i++) delete (*polygons)[i]; //delete polygons; return ret; } GeometryCollection* WKTReader::readGeometryCollectionText(StringTokenizer *tokenizer) { string nextToken=getNextEmptyOrOpener(tokenizer); if (nextToken=="EMPTY") { return geometryFactory->createGeometryCollection(NULL); } vector *geoms=new vector(); Geometry *geom; geom=readGeometryTaggedText(tokenizer); geoms->push_back(geom); nextToken=getNextCloserOrComma(tokenizer); while(nextToken==",") { geom=readGeometryTaggedText(tokenizer); geoms->push_back(geom); nextToken=getNextCloserOrComma(tokenizer); } GeometryCollection *ret = geometryFactory->createGeometryCollection(geoms); //for (int i=0; isize(); i++) delete (*geoms)[i]; //delete geoms; return ret; } } // namespace geos.io } // namespace geos