source: TI02-CSML/trunk/services/3rdParty/GeoTypes-0.6.0/GeoTypes/_WKTParser.py @ 2194

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI02-CSML/trunk/services/3rdParty/GeoTypes-0.6.0/GeoTypes/_WKTParser.py@2194
Revision 2194, 12.6 KB checked in by lawrence, 13 years ago (diff)

Adding various specs and 3rd party code of interest for the CSML
services development.

Line 
1
2################################################################################
3# Copyright (c) QinetiQ Plc 2003
4#
5# Licensed under the LGPL. For full license details see the LICENSE file.
6################################################################################
7
8"""
9A parser for the Well Known Text Format of OpenGIS types.
10
11Changelog:
12    06 jan 06: made SRID optional in WKTParser.parseGeometry (fredericback@gmail.com)
13   
14"""
15
16import shlex, StringIO, sys, traceback
17
18class ExceptionWKTParser(Exception):
19    '''This is the WKT Parser Exception class.'''
20    def __init__(self, value):
21        self.value = value
22    def __str__(self):
23        return `self.value`
24   
25class WKTParser:
26
27    def __init__(self,factory):
28        self._factory = factory
29
30        self._typemap = {'MULTIPOLYGON': self.parseMultiPolygon,
31                         'POINT': self.parsePoint,
32                         'LINESTRING': self.parseLineString,
33                         'POLYGON': self.parsePolygon,
34                         'MULTIPOINT': self.parseMultiPoint,
35                         'MULTILINESTRING': self.parseMultiLineString,
36                         'GEOMETRYCOLLECTION': self.parseGeometryCollection,
37                        }
38       
39   
40    def parseGeometry(self, geometry):
41        """
42        A factory method for creating objects of the correct OpenGIS type.
43        """
44
45        # Used for exception strings
46        self._current_string = geometry
47
48        self._factory.beginWork()
49       
50        # tokenize the string
51        tok_stream = shlex.shlex(StringIO.StringIO(geometry))
52        tok_stream.wordchars = tok_stream.wordchars + '.-'
53
54        # Avoid some extra lookups
55        next_tok = tok_stream.get_token
56
57        # Check if first token contains an SRID. If it does not, assume an SRID of -1.
58        token = next_tok()
59        if token == 'SRID':
60            try:
61                if next_tok() != '=': raise
62                srid = int(next_tok())
63                if next_tok() != ';': raise
64            except: raise ExceptionWKTParser('Invalid SRID in WKT string: %s' % (str(self._current_string),))
65            token = next_tok()
66        else: 
67            srid = -1
68
69        self._factory.beginUnit(srid)
70
71        # Start the parsing proper.
72        if self._typemap.has_key(token):
73            self._typemap[token](next_tok)
74        else:
75            raise ExceptionWKTParser('Invalid geometry in WKT string: %s' % (str(self._current_string),))
76
77        self._factory.endUnit()
78        self._factory.endWork()
79       
80    def parseGeometryCollection(self, next_tok):
81        self._factory.beginGeometryCollection()
82
83        if next_tok() != "(":
84            self._factory.abortGeometryCollection()
85            raise ExceptionWKTParser('Invalid GeometryCollection in WKT string: %s' % (str(self._current_string),))
86
87        last_geom = None
88       
89        while not last_geom:
90            geotype = next_tok()
91            if self._typemap.has_key(geotype):
92                self._typemap[geotype](next_tok)
93            else:
94                self._factory.abortGeometryCollection()
95                raise ExceptionWKTParser('Invalid geometry in WKT string: %s' % (str(self._current_string),))
96           
97            terminal_tok = next_tok()
98
99            # If we have reached the closing ')' then there are no more geoms in this collection.
100            if terminal_tok == ')':
101                last_geom = 1
102            else:
103                if terminal_tok != ',': 
104                    self._factory.abortGeometryCollection()
105                    raise ExceptionWKTParser('Invalid terminal on GeometryCollection in WKT string: %s' % (str(self._current_string),))
106       
107           
108        self._factory.endGeometryCollection()
109       
110##    def parseLinearRing(self, next_tok):
111##        self._factory.begin()
112##        self._factory.end()
113   
114    def parseLineString(self, next_tok):
115        # Linestring is broken in the same way as MultiPoint
116       
117        self._factory.beginLineString()
118
119        try:
120            if next_tok() != "(":
121                self._factory.abortLineString()
122                raise ExceptionWKTParser('Invalid Linestring in WKT string: %s' % (str(self._current_string),))
123
124            broken_form = None
125            last_point = None
126            while not last_point:
127
128                self._factory.beginPoint()
129
130                x = next_tok()
131                if x != '(':
132                    broken_form = 1
133                else:
134                    x = next_tok()
135                   
136                y = next_tok()
137                z = next_tok()
138
139                if z == ',' or z == ')':
140                    terminal_tok = z
141                    z = None
142                else:
143                    terminal_tok = next_tok()
144
145                if z:
146                    self._factory.addPoints3D(float(x),float(y),float(z))
147                else:
148                    self._factory.addPoints(float(x),float(y))
149
150                self._factory.endPoint()
151
152                # If we have reached the closing ')' then there are no more linestring in this collection.
153                if terminal_tok == ')' and broken_form:
154                    last_point = 1
155                elif terminal_tok == ')' and not broken_form:
156                    terminal_tok = next_tok()
157                    if terminal_tok ==')':
158                        last_point = 1                   
159                    else:
160                        if terminal_tok != ',': 
161                            self._factory.abortLineString()
162                            raise ExceptionWKTParser('Invalid terminal on LineString in WKT string: %s' % (str(self._current_string),))
163                else:
164                    if terminal_tok != ',': 
165                        self._factory.abortLineString()
166                        raise ExceptionWKTParser('Invalid terminal on LineString in WKT string: %s' % (str(self._current_string),))                       
167        except:
168            type, value, tb = sys.exc_info()[:3]
169            error = ("%s , %s \n" % (type, value))
170            for bits in traceback.format_exception(type,value,tb):
171                error = error + bits + '\n'
172            del tb
173            self._factory.abortLineString()
174            raise ExceptionWKTParser("Caught unhandled exception parsing Linestring: %s \n"\
175                                     "Traceback: %s\n" % (str(self._current_string),error))
176               
177        self._factory.endLineString()
178   
179    def parseMultiLineString(self, next_tok):
180        self._factory.beginMultiLineString()
181               
182        if next_tok() != "(":
183            self._factory.abortMultiLineString()
184            raise ExceptionWKTParser('Invalid MultiLinestring in WKT string: %s' % (str(self._current_string),))
185
186        last_linestring = None
187        while not last_linestring:
188
189            try:
190                self.parseLineString(next_tok)
191            except ExceptionWKTParser, x:
192                self._factory.abortMultiLineString()
193                raise ExceptionWKTParser(x.value)
194
195            terminal_tok = next_tok()
196
197            # If we have reached the closing ')' then there are no more linestring in this collection.
198            if terminal_tok == ')':
199                last_linestring = 1
200            else:
201                if terminal_tok != ',': 
202                    self._factory.abortMultiLineString()
203                    raise ExceptionWKTParser('Invalid terminal on MultiLineString in WKT string: %s' % (str(self._current_string),))
204       
205
206        self._factory.endMultiLineString()
207   
208    def parseMultiPoint(self, next_tok):
209
210        # Multipoint syntax if broken, the spec says it should be.
211        # MULTIPOINT(<Point Text> { , <Point Text> }* )
212        # <Point Text> = ( <Point> )
213        #
214        # But PG does not include the brackets e.g.
215        # correct = MULTIPOINT((0 0 0),(1 2 1))
216        # pg      = MULTIPOINT(0 0 0,1 2 1)
217        # So we have to special handling for both forms, bummer!
218        self._factory.beginMultiPoint()
219       
220        if next_tok() != "(":
221            self._factory.abortMultiPoint()
222            raise ExceptionWKTParser('Invalid MultiPoint in WKT string: %s' % (str(self._current_string),))
223
224        broken_form = None
225        last_point = None
226        while not last_point:
227
228            self._factory.beginPoint()
229           
230            x = next_tok()
231            if x != '(':
232                broken_form = 1
233            else:
234                x = next_tok()
235
236            y = next_tok()
237            z = next_tok()
238                   
239            if z == ')' or z == ',':
240                terminal_tok = z
241                z = None
242            else:
243                terminal_tok = next_tok()
244
245            if z:
246                self._factory.addPoints3D(float(x),float(y),float(z))
247            else:
248                self._factory.addPoints(float(x),float(y))
249           
250            self._factory.endPoint()
251
252            # If we have reached the closing ')' then there are no more linestring in this collection.
253            if terminal_tok == ')' and broken_form:
254                last_point = 1
255            elif terminal_tok == ')' and not broken_form:
256                terminal_tok = next_tok()
257                if terminal_tok ==')':
258                    last_point = 1                   
259                else:
260                    if terminal_tok != ',': 
261                        self._factory.abortMultiPoint()
262                        raise ExceptionWKTParser('Invalid terminal on MultiPoint in WKT string: %s' % (str(self._current_string),))
263            else:
264                if terminal_tok != ',': 
265                    self._factory.abortMultiPoint()
266                    raise ExceptionWKTParser('Invalid terminal on MultiPoint in WKT string: %s' % (str(self._current_string),))                       
267       
268        self._factory.endMultiPoint()
269   
270    def parseMultiPolygon(self, next_tok):
271        self._factory.beginMultiPolygon()
272       
273        if next_tok() != "(":
274            self._factory.abortMultiPolygon()
275            raise ExceptionWKTParser('Invalid MultiPolygon in WKT string: %s' % (str(self._current_string),))
276
277        last_polygon = None
278        while not last_polygon:
279
280            try:
281                self.parsePolygon(next_tok)
282            except ExceptionWKTParser, x:
283                self._factory.abortMultiPolygon()
284                raise ExceptionWKTParser(x.value)
285
286            terminal_tok = next_tok()
287
288            # If we have reached the closing ')' then there are no more polygons in this collection.
289            if terminal_tok == ')':
290                last_polygon = 1
291            else:
292                if terminal_tok != ',': 
293                    self._factory.abortMultiPolygon()
294                    raise ExceptionWKTParser('Invalid terminal on MultiPolygon in WKT string: %s' % (str(self._current_string),))
295       
296        self._factory.endMultiPolygon()
297
298    def parsePoint(self, next_tok):
299        self._factory.beginPoint()
300               
301        if next_tok() != "(":
302            self._factory.abortPoint()
303            raise ExceptionWKTParser('Invalid Linestring in WKT string: %s' % (str(self._current_string),))
304
305
306        x = next_tok()
307        y = next_tok()
308        z = next_tok()
309
310        if z == ')':
311            terminal_tok = z
312            z = None
313        else:
314            terminal_tok = next_tok()
315
316        if z:
317            self._factory.addPoints3D(float(x),float(y),float(z))
318        else:
319            self._factory.addPoints(float(x),float(y))
320
321        if terminal_tok != ')':
322            self._factory.abortPoint()
323            raise ExceptionWKTParser('Invalid terminal on Linestring in WKT string: %s' % (str(self._current_string),))
324               
325        self._factory.endPoint()
326   
327    def parsePolygon(self, next_tok):
328        self._factory.beginPolygon()
329                       
330        if next_tok() != "(":
331            self._factory.abortPolygon()
332            raise ExceptionWKTParser('Invalid Polygon in WKT string: %s' % (str(self._current_string),))
333
334        last_linestring = None
335        while not last_linestring:
336
337            try:
338                self.parseLineString(next_tok)
339            except ExceptionWKTParser, x:
340                self._factory.abortPolygon()
341                raise ExceptionWKTParser(x.value)
342
343            terminal_tok = next_tok()
344
345            # If we have reached the closing ')' then there are no more linestring in this collection.
346            if terminal_tok == ')':
347                last_linestring = 1
348            else:
349                if terminal_tok != ',': 
350                    self._factory.abortPolygon()
351                    raise ExceptionWKTParser('Invalid terminal on Polygon in WKT string: %s' % (str(self._current_string),))
352       
353
354        self._factory.endPolygon()
Note: See TracBrowser for help on using the repository browser.