1 |
# Copyright (C) 2002, 2003 Intevation GmbH <[email protected]> |
2 |
# Author: Bernhard Herzog <[email protected]> |
3 |
# |
4 |
# This program is free software under the GPL (>=v2) |
5 |
# Read the file GPL coming with the software for details. |
6 |
|
7 |
"""Convert Well-Known Text format to python objects |
8 |
|
9 |
Main entry point is the convert_well_known_text function which takes a |
10 |
geometry in Well-Known Text format and returns a python object with the |
11 |
geometry. |
12 |
""" |
13 |
|
14 |
__version__ = "$Revision$" |
15 |
# $Source$ |
16 |
# $Id$ |
17 |
|
18 |
import re |
19 |
|
20 |
|
21 |
_open_parens = r"[ \t]*(\([ \t]*)*" |
22 |
_close_parens = r"[ \t]*(\)[ \t]*)+" |
23 |
rx_point_list = re.compile(_open_parens + r"(?P<coords>[^\)]+)" |
24 |
+ _close_parens + ",?") |
25 |
|
26 |
|
27 |
def parse_coordinate_lists(wkt): |
28 |
"""Return the coordinates in wkt as a list of lists of coordinate pairs. |
29 |
|
30 |
The wkt parameter is the coordinate part of a geometry in well-known |
31 |
text format. |
32 |
""" |
33 |
geometry = [] |
34 |
while wkt: |
35 |
match = rx_point_list.match(wkt) |
36 |
if match: |
37 |
poly = [] |
38 |
wktcoords = match.group("coords") |
39 |
for pair in wktcoords.split(","): |
40 |
# a pair may be a triple actually. For now we just |
41 |
# ignore any third value |
42 |
x, y = map(float, pair.split())[:2] |
43 |
poly.append((x, y)) |
44 |
geometry.append(poly) |
45 |
wkt = wkt[match.end(0):].strip() |
46 |
else: |
47 |
raise ValueError("Invalid well-known-text (WKT) syntax") |
48 |
return geometry |
49 |
|
50 |
|
51 |
def parse_multipolygon(wkt): |
52 |
""" |
53 |
Return the MULTIPOLYGON geometry wkt as a list of lists of float pairs |
54 |
""" |
55 |
return parse_coordinate_lists(wkt) |
56 |
|
57 |
def parse_polygon(wkt): |
58 |
"""Return the POLYGON geometry in wkt as a list of float pairs""" |
59 |
return parse_coordinate_lists(wkt) |
60 |
|
61 |
def parse_multilinestring(wkt): |
62 |
""" |
63 |
Return the MULTILINESTRING geometry wkt as a list of lists of float pairs |
64 |
""" |
65 |
return parse_coordinate_lists(wkt) |
66 |
|
67 |
def parse_linestring(wkt): |
68 |
"""Return the LINESTRING geometry in wkt as a list of float pairs""" |
69 |
return parse_coordinate_lists(wkt)[0] |
70 |
|
71 |
def parse_point(wkt): |
72 |
"""Return the POINT geometry in wkt format as pair of floats""" |
73 |
return parse_coordinate_lists(wkt)[0][0] |
74 |
|
75 |
|
76 |
# map geometry types to parser functions |
77 |
_function_map = [ |
78 |
("MULTIPOLYGON", parse_multipolygon), |
79 |
("POLYGON", parse_polygon), |
80 |
("MULTILINESTRING", parse_multilinestring), |
81 |
("LINESTRING", parse_linestring), |
82 |
("POINT", parse_point), |
83 |
] |
84 |
|
85 |
def convert_well_known_text(wkt): |
86 |
"""Return the geometry given in well-known text format as python objects |
87 |
|
88 |
The function accepts only 2D data and supports the POINT, POLYGON, |
89 |
MULTIPOLYGON, LINESTRING and MULTILINESTRING geometries. |
90 |
|
91 |
The structure of the return value depends on the geometry type. For |
92 |
MULTIPOLYGON and MULTILINESTRING return a list of lists of |
93 |
coordinate pairs. For POLYGON and LINESTRING return a list of |
94 |
coordinate pairs. For POINT return a coordinate pair. All |
95 |
coordinates are floats. |
96 |
|
97 |
The string wkt may contain an SRID specification in addition to the |
98 |
actual geometry. This SRID is ignored. |
99 |
""" |
100 |
parts = wkt.split(";") |
101 |
for part in parts: |
102 |
part = part.strip() |
103 |
if part.startswith("SRID"): |
104 |
# ignore SRIDs |
105 |
continue |
106 |
else: |
107 |
for geotype, function in _function_map: |
108 |
if part.startswith(geotype): |
109 |
return function(part[len(geotype):]) |
110 |
else: |
111 |
raise ValueError("Unsupported WKT-part %s" % repr(part[:20])) |
112 |
else: |
113 |
# there were no recognized geometries in the WKT string |
114 |
raise ValueError("No recognized geometry in WKT string") |
115 |
|
116 |
def parse_wkt_thuban(wkt): |
117 |
"""Like convert_well_known_text, but return lists of lists of pairs""" |
118 |
parts = wkt.split(";") |
119 |
for part in parts: |
120 |
part = part.strip() |
121 |
if part.startswith("SRID"): |
122 |
# ignore SRIDs |
123 |
continue |
124 |
else: |
125 |
# split on "(" to separate the geometry type from the |
126 |
# coordinate values |
127 |
components = part.split("(", 1) |
128 |
if len(components) > 1: |
129 |
return parse_coordinate_lists(components[1]) |
130 |
else: |
131 |
raise ValueError("WKT part %r doesn't contain opening" |
132 |
" parenthesis" % part) |
133 |
else: |
134 |
# there were no recognized geometries in the WKT string |
135 |
raise ValueError("No recognized geometry in WKT string") |