-
Notifications
You must be signed in to change notification settings - Fork 79
/
wkt.py
143 lines (107 loc) · 3.98 KB
/
wkt.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
from ... import cg
import re
__author__ = "Charles R Schmidt <schmidtc@gmail.com>"
__all__ = ["WKTParser"]
class WKTParser:
"""Class to represent `OGC WKT`, supports reading and writing.
Modified from...
# URL: http://dev.openlayers.org/releases/OpenLayers-2.7/lib/OpenLayers/Format/WKT.js
# Reg Ex Strings copied from OpenLayers.Format.WKT
Examples
--------
>>> import libpysal
Create some Well-Known Text objects.
>>> p = 'POLYGON((1 1, 5 1, 5 5, 1 5, 1 1), (2 2, 3 2, 3 3, 2 3, 2 2))'
>>> pt = 'POINT(6 10)'
>>> l = 'LINESTRING(3 4, 10 50, 20 25)'
Instantiate the parser.
>>> parser = libpysal.io.wkt.WKTParser()
Inspect our WKT polygon.
>>> parser(p).parts
[[(1.0, 1.0), (1.0, 5.0), (5.0, 5.0), (5.0, 1.0), (1.0, 1.0)],
[(2.0, 2.0), (2.0, 3.0), (3.0, 3.0), (3.0, 2.0), (2.0, 2.0)]]
>>> parser(p).centroid
(2.9705882352941178, 2.9705882352941178)
>>> parser(p).area
17.0
Inspect ``pt``, our WKT point object.
>>> parser(pt)
(6.0, 10.0)
Inspect our WKT linestring.
>>> parser(l).len
73.45538453219989
>>> parser(l).parts
[[(3.0, 4.0), (10.0, 50.0), (20.0, 25.0)]]
Read in WKT from a file.
>>> f = libpysal.io.open(libpysal.examples.get_path('stl_hom.wkt'))
>>> f.mode
'r'
>>> f.header
[]
See local doctest output for the items not tested.
"""
regExes = {
"typeStr": re.compile(r"^\s*([\w\s]+)\s*\(\s*(.*)\s*\)\s*$"),
"spaces": re.compile(r"\s+"),
"parenComma": re.compile(r"\)\s*,\s*\("),
"doubleParenComma": re.compile(r"\)\s*\)\s*,\s*\(\s*\("), # can't use {2} here
"trimParens": re.compile(r"^\s*\(?(.*?)\)?\s*$"),
}
def __init__(self):
self.parsers = p = {}
p["point"] = self.Point
p["linestring"] = self.LineString
p["polygon"] = self.Polygon
def Point(self, geoStr):
"""Returns a ``libpysal.cg.Point`` object."""
coords = self.regExes["spaces"].split(geoStr.strip())
return cg.Point((coords[0], coords[1]))
def LineString(self, geoStr):
"""Returns a ``libpysal.cg.Chain`` object."""
points = geoStr.strip().split(",")
points = list(map(self.Point, points))
return cg.Chain(points)
def Polygon(self, geoStr):
"""Returns a ``libpysal.cg.Polygon`` object."""
rings = self.regExes["parenComma"].split(geoStr.strip())
for i, ring in enumerate(rings):
ring = self.regExes["trimParens"].match(ring).groups()[0]
ring = self.LineString(ring).vertices
rings[i] = ring
return cg.Polygon(rings)
def fromWKT(self, wkt):
"""Returns geometric representation from WKT or ``None``.
Raises
------
NotImplementedError
Raised when a unknown/unsupported format is passed in.
"""
matches = self.regExes["typeStr"].match(wkt)
if matches:
geoType, geoStr = matches.groups()
geoType = geoType.lower().strip()
try:
return self.parsers[geoType](geoStr)
except KeyError:
raise NotImplementedError("Unsupported WKT Type: %s." % geoType)
else:
return None
__call__ = fromWKT
if __name__ == "__main__":
p = "POLYGON((1 1,5 1,5 5,1 5,1 1),(2 2, 3 2, 3 3, 2 3,2 2))"
pt = "POINT(6 10)"
l = "LINESTRING(3 4,10 50,20 25)"
wktExamples = [
"POINT(6 10)",
"LINESTRING(3 4,10 50,20 25)",
"POLYGON((1 1,5 1,5 5,1 5,1 1),(2 2, 3 2, 3 3, 2 3,2 2))",
"MULTIPOINT(3.5 5.6,4.8 10.5)",
"MULTILINESTRING((3 4,10 50,20 25),(-5 -8,-10 -8,-15 -4))",
"MULTIPOLYGON(((1 1,5 1,5 5,1 5,1 1),(2 2, 3 2, 3 3, 2 3,2 2)),((3 3,6 2,6 4,3 3)))",
"GEOMETRYCOLLECTION(POINT(4 6),LINESTRING(4 6,7 10))",
"POINT ZM (1 1 5 60)",
"POINT M (1 1 80)",
"POINT EMPTY",
"MULTIPOLYGON EMPTY",
]
wkt = WKTParser()