1 |
bh |
1605 |
# 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") |