shapely 1.0b1__py2.4.egg → 1.0b3__py2.4.egg
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- EGG-INFO/PKG-INFO +3 -3
- EGG-INFO/SOURCES.txt +2 -0
- shapely/geometry/__init__.py +9 -0
- shapely/geometry/__init__.pyc +0 -0
- shapely/geometry/base.py +358 -0
- shapely/geometry/base.pyc +0 -0
- shapely/geometry/collection.py +24 -0
- shapely/geometry/collection.pyc +0 -0
- shapely/geometry/geo.py +35 -0
- shapely/geometry/geo.pyc +0 -0
- shapely/geometry/linestring.py +228 -0
- shapely/geometry/linestring.pyc +0 -0
- shapely/geometry/multilinestring.py +155 -0
- shapely/geometry/multilinestring.pyc +0 -0
- shapely/geometry/multipoint.py +182 -0
- shapely/geometry/multipoint.pyc +0 -0
- shapely/geometry/multipolygon.py +141 -0
- shapely/geometry/multipolygon.pyc +0 -0
- shapely/geometry/point.py +242 -0
- shapely/geometry/point.pyc +0 -0
- shapely/geometry/polygon.py +414 -0
- shapely/geometry/polygon.pyc +0 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Points.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from ctypes import string_at, create_string_buffer, \
|
|
6
|
+
c_char_p, c_double, c_float, c_int, c_uint, c_size_t, c_ubyte, \
|
|
7
|
+
c_void_p, byref
|
|
8
|
+
from ctypes import cast, POINTER
|
|
9
|
+
|
|
10
|
+
from shapely.geos import lgeos, DimensionError
|
|
11
|
+
from shapely.geometry.base import BaseGeometry, CoordinateSequence
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def geos_point_from_py(ob, update_geom=None, update_ndim=0):
|
|
15
|
+
"""Create a GEOS geom from an object that is a coordinate sequence
|
|
16
|
+
or that provides the array interface.
|
|
17
|
+
|
|
18
|
+
Returns the GEOS geometry and the number of its dimensions.
|
|
19
|
+
"""
|
|
20
|
+
try:
|
|
21
|
+
# From array protocol
|
|
22
|
+
array = ob.__array_interface__
|
|
23
|
+
assert len(array['shape']) == 1
|
|
24
|
+
n = array['shape'][0]
|
|
25
|
+
assert n == 2 or n == 3
|
|
26
|
+
|
|
27
|
+
cdata = array['data'][0]
|
|
28
|
+
cp = cast(cdata, POINTER(c_double))
|
|
29
|
+
dx = c_double(cp[0])
|
|
30
|
+
dy = c_double(cp[1])
|
|
31
|
+
dz = None
|
|
32
|
+
if n == 3:
|
|
33
|
+
dz = c_double(cp[2])
|
|
34
|
+
ndim = 3
|
|
35
|
+
except AttributeError:
|
|
36
|
+
# Fall back on list
|
|
37
|
+
coords = ob
|
|
38
|
+
n = len(coords)
|
|
39
|
+
dx = c_double(coords[0])
|
|
40
|
+
dy = c_double(coords[1])
|
|
41
|
+
dz = None
|
|
42
|
+
if n == 3:
|
|
43
|
+
dz = c_double(coords[2])
|
|
44
|
+
|
|
45
|
+
if update_geom:
|
|
46
|
+
cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
|
|
47
|
+
if n != update_ndim:
|
|
48
|
+
raise ValueError, \
|
|
49
|
+
"Wrong coordinate dimensions; this geometry has dimensions: %d" \
|
|
50
|
+
% update_ndim
|
|
51
|
+
else:
|
|
52
|
+
cs = lgeos.GEOSCoordSeq_create(1, n)
|
|
53
|
+
|
|
54
|
+
# Because of a bug in the GEOS C API, always set X before Y
|
|
55
|
+
lgeos.GEOSCoordSeq_setX(cs, 0, dx)
|
|
56
|
+
lgeos.GEOSCoordSeq_setY(cs, 0, dy)
|
|
57
|
+
if n == 3:
|
|
58
|
+
lgeos.GEOSCoordSeq_setZ(cs, 0, dz)
|
|
59
|
+
|
|
60
|
+
if update_geom:
|
|
61
|
+
return None
|
|
62
|
+
else:
|
|
63
|
+
return (lgeos.GEOSGeom_createPoint(cs), n)
|
|
64
|
+
|
|
65
|
+
def update_point_from_py(geom, ob):
|
|
66
|
+
geos_point_from_py(ob, geom._geom, geom._ndim)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Point(BaseGeometry):
|
|
70
|
+
|
|
71
|
+
"""A point geometry.
|
|
72
|
+
|
|
73
|
+
Attributes
|
|
74
|
+
----------
|
|
75
|
+
x, y, z : float
|
|
76
|
+
Coordinate values
|
|
77
|
+
|
|
78
|
+
Example
|
|
79
|
+
-------
|
|
80
|
+
>>> p = Point(1.0, -1.0)
|
|
81
|
+
>>> str(p)
|
|
82
|
+
'POINT (1.0000000000000000 -1.0000000000000000)'
|
|
83
|
+
>>> p.y = 0.0
|
|
84
|
+
>>> p.y
|
|
85
|
+
0.0
|
|
86
|
+
>>> p.x
|
|
87
|
+
1.0
|
|
88
|
+
>>> p.array
|
|
89
|
+
[[1.0, 0.0]]
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
def __init__(self, *args):
|
|
93
|
+
"""This *copies* the given data to a new GEOS geometry.
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
|
|
98
|
+
There are 2 cases:
|
|
99
|
+
|
|
100
|
+
1) 1 parameter: this must satisfy the numpy array protocol.
|
|
101
|
+
2) 2 or more parameters: x, y, z : float
|
|
102
|
+
Easting, northing, and elevation.
|
|
103
|
+
"""
|
|
104
|
+
BaseGeometry.__init__(self)
|
|
105
|
+
|
|
106
|
+
if len(args) == 0:
|
|
107
|
+
# allow creation of null points, to support unpickling
|
|
108
|
+
pass
|
|
109
|
+
else:
|
|
110
|
+
if len(args) == 1:
|
|
111
|
+
self._geom, self._ndim = geos_point_from_py(args[0])
|
|
112
|
+
else:
|
|
113
|
+
self._geom, self._ndim = geos_point_from_py(tuple(args))
|
|
114
|
+
|
|
115
|
+
# Coordinate getters and setters
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def x(self):
|
|
119
|
+
"""Return x coordinate."""
|
|
120
|
+
cs = lgeos.GEOSGeom_getCoordSeq(self._geom)
|
|
121
|
+
d = c_double()
|
|
122
|
+
lgeos.GEOSCoordSeq_getX(cs, 0, byref(d))
|
|
123
|
+
return d.value
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def y(self):
|
|
127
|
+
"""Return y coordinate."""
|
|
128
|
+
cs = lgeos.GEOSGeom_getCoordSeq(self._geom)
|
|
129
|
+
d = c_double()
|
|
130
|
+
lgeos.GEOSCoordSeq_getY(cs, 0, byref(d))
|
|
131
|
+
return d.value
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def z(self):
|
|
135
|
+
"""Return z coordinate."""
|
|
136
|
+
if self._ndim != 3:
|
|
137
|
+
raise DimensionError, "This point has no z coordinate."
|
|
138
|
+
cs = lgeos.GEOSGeom_getCoordSeq(self._geom)
|
|
139
|
+
d = c_double()
|
|
140
|
+
lgeos.GEOSCoordSeq_getZ(cs, 0, byref(d))
|
|
141
|
+
return d.value
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def __geo_interface__(self):
|
|
145
|
+
return {
|
|
146
|
+
'type': 'Point',
|
|
147
|
+
'coordinates': self.coords[0]
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def ctypes(self):
|
|
152
|
+
if not self._ctypes_data:
|
|
153
|
+
array_type = c_double * self._ndim
|
|
154
|
+
array = array_type()
|
|
155
|
+
array[0] = self.x
|
|
156
|
+
array[1] = self.y
|
|
157
|
+
if self._ndim == 3:
|
|
158
|
+
array[2] = self.z
|
|
159
|
+
self._ctypes_data = array
|
|
160
|
+
return self._ctypes_data
|
|
161
|
+
|
|
162
|
+
def array_interface(self):
|
|
163
|
+
"""Provide the Numpy array protocol."""
|
|
164
|
+
ai = self.array_interface_base
|
|
165
|
+
ai.update({'shape': (self._ndim,)})
|
|
166
|
+
return ai
|
|
167
|
+
__array_interface__ = property(array_interface)
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def bounds(self):
|
|
171
|
+
cs = lgeos.GEOSGeom_getCoordSeq(self._geom)
|
|
172
|
+
x = c_double()
|
|
173
|
+
y = c_double()
|
|
174
|
+
lgeos.GEOSCoordSeq_getX(cs, 0, byref(x))
|
|
175
|
+
lgeos.GEOSCoordSeq_getY(cs, 0, byref(y))
|
|
176
|
+
return (x.value, y.value, x.value, y.value)
|
|
177
|
+
|
|
178
|
+
# Coordinate access
|
|
179
|
+
|
|
180
|
+
def set_coords(self, coordinates):
|
|
181
|
+
update_point_from_py(self, coordinates)
|
|
182
|
+
|
|
183
|
+
coords = property(BaseGeometry.get_coords, set_coords)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class PointAdapter(Point):
|
|
187
|
+
|
|
188
|
+
"""Adapts a Python coordinate pair or a numpy array to the point interface.
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
context = None
|
|
192
|
+
|
|
193
|
+
def __init__(self, context):
|
|
194
|
+
self.context = context
|
|
195
|
+
|
|
196
|
+
# Override base class __del__
|
|
197
|
+
def __del__(self):
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def _ndim(self):
|
|
202
|
+
try:
|
|
203
|
+
# From array protocol
|
|
204
|
+
array = self.context.__array_interface__
|
|
205
|
+
n = array['shape'][0]
|
|
206
|
+
assert n == 2 or n == 3
|
|
207
|
+
return n
|
|
208
|
+
except AttributeError:
|
|
209
|
+
# Fall back on list
|
|
210
|
+
return len(self.context)
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def _geom(self):
|
|
214
|
+
"""Keeps the GEOS geometry in synch with the context."""
|
|
215
|
+
return geos_point_from_py(self.context)[0]
|
|
216
|
+
|
|
217
|
+
# TODO: reimplement x, y, z properties without calling invoking _geom
|
|
218
|
+
|
|
219
|
+
@property
|
|
220
|
+
def __array_interface__(self):
|
|
221
|
+
"""Provide the Numpy array protocol."""
|
|
222
|
+
try:
|
|
223
|
+
return self.context.__array_interface__
|
|
224
|
+
except AttributeError:
|
|
225
|
+
return self.array_interface()
|
|
226
|
+
|
|
227
|
+
coords = property(BaseGeometry.get_coords)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def asPoint(context):
|
|
231
|
+
"""Factory for PointAdapter instances."""
|
|
232
|
+
return PointAdapter(context)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# Test runner
|
|
236
|
+
def _test():
|
|
237
|
+
import doctest
|
|
238
|
+
doctest.testmod()
|
|
239
|
+
|
|
240
|
+
if __name__ == "__main__":
|
|
241
|
+
_test()
|
|
242
|
+
|
|
Binary file
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Polygons and their linear ring components.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from ctypes import byref, c_double, c_int, c_void_p, cast, POINTER, pointer
|
|
6
|
+
|
|
7
|
+
from shapely.geos import lgeos
|
|
8
|
+
from shapely.geometry.base import BaseGeometry
|
|
9
|
+
from shapely.geometry.linestring import LineString, LineStringAdapter
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def geos_linearring_from_py(ob, update_geom=None, update_ndim=0):
|
|
13
|
+
try:
|
|
14
|
+
# From array protocol
|
|
15
|
+
array = ob.__array_interface__
|
|
16
|
+
assert len(array['shape']) == 2
|
|
17
|
+
m = array['shape'][0]
|
|
18
|
+
n = array['shape'][1]
|
|
19
|
+
assert m >= 2
|
|
20
|
+
assert n == 2 or n == 3
|
|
21
|
+
|
|
22
|
+
# Make pointer to the coordinate array
|
|
23
|
+
try:
|
|
24
|
+
cp = cast(array['data'][0], POINTER(c_double))
|
|
25
|
+
except ArgumentError:
|
|
26
|
+
cp = array['data']
|
|
27
|
+
|
|
28
|
+
# Add closing coordinates to sequence?
|
|
29
|
+
if cp[0] != cp[m*n-n] or cp[1] != cp[m*n-n+1]:
|
|
30
|
+
M = m + 1
|
|
31
|
+
else:
|
|
32
|
+
M = m
|
|
33
|
+
|
|
34
|
+
# Create a coordinate sequence
|
|
35
|
+
if update_geom is not None:
|
|
36
|
+
cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
|
|
37
|
+
if n != update_ndim:
|
|
38
|
+
raise ValueError, \
|
|
39
|
+
"Wrong coordinate dimensions; this geometry has dimensions: %d" \
|
|
40
|
+
% update_ndim
|
|
41
|
+
else:
|
|
42
|
+
cs = lgeos.GEOSCoordSeq_create(M, n)
|
|
43
|
+
|
|
44
|
+
# add to coordinate sequence
|
|
45
|
+
for i in xrange(m):
|
|
46
|
+
dx = c_double(cp[n*i])
|
|
47
|
+
dy = c_double(cp[n*i+1])
|
|
48
|
+
dz = None
|
|
49
|
+
if n == 3:
|
|
50
|
+
dz = c_double(cp[n*i+2])
|
|
51
|
+
|
|
52
|
+
# Because of a bug in the GEOS C API,
|
|
53
|
+
# always set X before Y
|
|
54
|
+
lgeos.GEOSCoordSeq_setX(cs, i, dx)
|
|
55
|
+
lgeos.GEOSCoordSeq_setY(cs, i, dy)
|
|
56
|
+
if n == 3:
|
|
57
|
+
lgeos.GEOSCoordSeq_setZ(cs, i, dz)
|
|
58
|
+
|
|
59
|
+
# Add closing coordinates to sequence?
|
|
60
|
+
if M > m:
|
|
61
|
+
dx = c_double(cp[0])
|
|
62
|
+
dy = c_double(cp[1])
|
|
63
|
+
dz = None
|
|
64
|
+
if n == 3:
|
|
65
|
+
dz = c_double(cp[2])
|
|
66
|
+
|
|
67
|
+
# Because of a bug in the GEOS C API,
|
|
68
|
+
# always set X before Y
|
|
69
|
+
lgeos.GEOSCoordSeq_setX(cs, M-1, dx)
|
|
70
|
+
lgeos.GEOSCoordSeq_setY(cs, M-1, dy)
|
|
71
|
+
if n == 3:
|
|
72
|
+
lgeos.GEOSCoordSeq_setZ(cs, M-1, dz)
|
|
73
|
+
|
|
74
|
+
except AttributeError:
|
|
75
|
+
# Fall back on list
|
|
76
|
+
m = len(ob)
|
|
77
|
+
n = len(ob[0])
|
|
78
|
+
assert m >= 2
|
|
79
|
+
assert n == 2 or n == 3
|
|
80
|
+
|
|
81
|
+
# Add closing coordinates if not provided
|
|
82
|
+
if ob[0][0] != ob[-1][0] or ob[0][1] != ob[-1][1]:
|
|
83
|
+
M = m + 1
|
|
84
|
+
else:
|
|
85
|
+
M = m
|
|
86
|
+
|
|
87
|
+
# Create a coordinate sequence
|
|
88
|
+
if update_geom is not None:
|
|
89
|
+
cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
|
|
90
|
+
if n != update_ndim:
|
|
91
|
+
raise ValueError, \
|
|
92
|
+
"Wrong coordinate dimensions; this geometry has dimensions: %d" \
|
|
93
|
+
% update_ndim
|
|
94
|
+
else:
|
|
95
|
+
cs = lgeos.GEOSCoordSeq_create(M, n)
|
|
96
|
+
|
|
97
|
+
# add to coordinate sequence
|
|
98
|
+
for i in xrange(m):
|
|
99
|
+
coords = ob[i]
|
|
100
|
+
dx = c_double(coords[0])
|
|
101
|
+
dy = c_double(coords[1])
|
|
102
|
+
dz = None
|
|
103
|
+
if n == 3:
|
|
104
|
+
dz = c_double(coords[2])
|
|
105
|
+
|
|
106
|
+
# Because of a bug in the GEOS C API,
|
|
107
|
+
# always set X before Y
|
|
108
|
+
lgeos.GEOSCoordSeq_setX(cs, i, dx)
|
|
109
|
+
lgeos.GEOSCoordSeq_setY(cs, i, dy)
|
|
110
|
+
if n == 3:
|
|
111
|
+
lgeos.GEOSCoordSeq_setZ(cs, i, dz)
|
|
112
|
+
|
|
113
|
+
# Add closing coordinates to sequence?
|
|
114
|
+
if M > m:
|
|
115
|
+
coords = ob[0]
|
|
116
|
+
dx = c_double(coords[0])
|
|
117
|
+
dy = c_double(coords[1])
|
|
118
|
+
dz = None
|
|
119
|
+
if n == 3:
|
|
120
|
+
dz = c_double(coords[2])
|
|
121
|
+
|
|
122
|
+
# Because of a bug in the GEOS C API,
|
|
123
|
+
# always set X before Y
|
|
124
|
+
lgeos.GEOSCoordSeq_setX(cs, M-1, dx)
|
|
125
|
+
lgeos.GEOSCoordSeq_setY(cs, M-1, dy)
|
|
126
|
+
if n == 3:
|
|
127
|
+
lgeos.GEOSCoordSeq_setZ(cs, M-1, dz)
|
|
128
|
+
|
|
129
|
+
if update_geom is not None:
|
|
130
|
+
return None
|
|
131
|
+
else:
|
|
132
|
+
return (lgeos.GEOSGeom_createLinearRing(cs), n)
|
|
133
|
+
|
|
134
|
+
def update_linearring_from_py(geom, ob):
|
|
135
|
+
geos_linearring_from_py(ob, geom._geom, geom._ndim)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class LinearRing(LineString):
|
|
139
|
+
|
|
140
|
+
"""A linear ring.
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
_ndim = 2
|
|
144
|
+
|
|
145
|
+
def __init__(self, coordinates=None):
|
|
146
|
+
"""Initialize.
|
|
147
|
+
|
|
148
|
+
Parameters
|
|
149
|
+
----------
|
|
150
|
+
coordinates : sequence or array
|
|
151
|
+
This may be an object that satisfies the numpy array protocol,
|
|
152
|
+
providing an M x 2 or M x 3 (with z) array, or it may be a sequence
|
|
153
|
+
of x, y (,z) coordinate sequences.
|
|
154
|
+
|
|
155
|
+
Rings are implicitly closed. There is no need to specific a final
|
|
156
|
+
coordinate pair identical to the first.
|
|
157
|
+
|
|
158
|
+
Example
|
|
159
|
+
-------
|
|
160
|
+
>>> ring = LinearRing( ((0.,0.), (0.,1.), (1.,1.), (1.,0.)) )
|
|
161
|
+
|
|
162
|
+
Produces a 1x1 square.
|
|
163
|
+
"""
|
|
164
|
+
BaseGeometry.__init__(self)
|
|
165
|
+
|
|
166
|
+
if coordinates is None:
|
|
167
|
+
# allow creation of null lines, to support unpickling
|
|
168
|
+
pass
|
|
169
|
+
else:
|
|
170
|
+
self._geom, self._ndims = geos_linearring_from_py(coordinates)
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def __geo_interface__(self):
|
|
174
|
+
return {
|
|
175
|
+
'type': 'LinearRing',
|
|
176
|
+
'coordinates': tuple(self.coords)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
# Coordinate access
|
|
180
|
+
|
|
181
|
+
def set_coords(self, coordinates):
|
|
182
|
+
update_linearring_from_py(self, coordinates)
|
|
183
|
+
|
|
184
|
+
coords = property(BaseGeometry.get_coords, set_coords)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class LinearRingAdapter(LineStringAdapter):
|
|
188
|
+
|
|
189
|
+
@property
|
|
190
|
+
def _geom(self):
|
|
191
|
+
"""Keeps the GEOS geometry in synch with the context."""
|
|
192
|
+
return geos_linearring_from_py(self.context)[0]
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def __geo_interface__(self):
|
|
196
|
+
return {
|
|
197
|
+
'type': 'LinearRing',
|
|
198
|
+
'coordinates': tuple(self.coords)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
coords = property(BaseGeometry.get_coords)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def asLinearRing(context):
|
|
205
|
+
return LinearRingAdapter(context)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class InteriorRingSequence(object):
|
|
209
|
+
|
|
210
|
+
_factory = None
|
|
211
|
+
_geom = None
|
|
212
|
+
_ndim = None
|
|
213
|
+
_index = 0
|
|
214
|
+
_length = 0
|
|
215
|
+
|
|
216
|
+
def __init__(self, geom):
|
|
217
|
+
self._geom = geom._geom
|
|
218
|
+
self._ndim = geom._ndim
|
|
219
|
+
|
|
220
|
+
def __iter__(self):
|
|
221
|
+
self._index = 0
|
|
222
|
+
self._length = self.__len__()
|
|
223
|
+
return self
|
|
224
|
+
|
|
225
|
+
def next(self):
|
|
226
|
+
if self._index < self._length:
|
|
227
|
+
g = LinearRing()
|
|
228
|
+
g._owned = True
|
|
229
|
+
g._geom = lgeos.GEOSGetInteriorRingN(self._geom, self._index)
|
|
230
|
+
self._index += 1
|
|
231
|
+
return g
|
|
232
|
+
else:
|
|
233
|
+
raise StopIteration
|
|
234
|
+
|
|
235
|
+
def __len__(self):
|
|
236
|
+
return lgeos.GEOSGetNumInteriorRings(self._geom)
|
|
237
|
+
|
|
238
|
+
def __getitem__(self, i):
|
|
239
|
+
M = self.__len__()
|
|
240
|
+
if i + M < 0 or i >= M:
|
|
241
|
+
raise IndexError, "index out of range"
|
|
242
|
+
if i < 0:
|
|
243
|
+
ii = M + i
|
|
244
|
+
else:
|
|
245
|
+
ii = i
|
|
246
|
+
g = LinearRing()
|
|
247
|
+
g._owned = True
|
|
248
|
+
g._geom = lgeos.GEOSGetInteriorRingN(self._geom, ii)
|
|
249
|
+
return g
|
|
250
|
+
|
|
251
|
+
@property
|
|
252
|
+
def _longest(self):
|
|
253
|
+
max = 0
|
|
254
|
+
for g in iter(self):
|
|
255
|
+
l = len(g.coords)
|
|
256
|
+
if l > max:
|
|
257
|
+
max = l
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def geos_polygon_from_py(shell, holes=None):
|
|
261
|
+
if shell is not None:
|
|
262
|
+
geos_shell, ndims = geos_linearring_from_py(shell)
|
|
263
|
+
## Polygon geometry takes ownership of the ring
|
|
264
|
+
#self._exterior._owned = True
|
|
265
|
+
|
|
266
|
+
if holes:
|
|
267
|
+
ob = holes
|
|
268
|
+
L = len(ob)
|
|
269
|
+
try:
|
|
270
|
+
N = len(ob[0][0])
|
|
271
|
+
except:
|
|
272
|
+
import pdb; pdb.set_trace()
|
|
273
|
+
assert L >= 1
|
|
274
|
+
assert N == 2 or N == 3
|
|
275
|
+
|
|
276
|
+
# Array of pointers to ring geometries
|
|
277
|
+
geos_holes = (c_void_p * L)()
|
|
278
|
+
|
|
279
|
+
# add to coordinate sequence
|
|
280
|
+
for l in xrange(L):
|
|
281
|
+
geom, ndims = geos_linearring_from_py(ob[l])
|
|
282
|
+
geos_holes[l] = cast(geom, c_void_p)
|
|
283
|
+
|
|
284
|
+
else:
|
|
285
|
+
geos_holes = POINTER(c_void_p)()
|
|
286
|
+
L = 0
|
|
287
|
+
|
|
288
|
+
return (
|
|
289
|
+
lgeos.GEOSGeom_createPolygon(
|
|
290
|
+
c_void_p(geos_shell),
|
|
291
|
+
geos_holes,
|
|
292
|
+
L
|
|
293
|
+
),
|
|
294
|
+
ndims
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
class Polygon(BaseGeometry):
|
|
298
|
+
|
|
299
|
+
"""A line string, also known as a polyline.
|
|
300
|
+
"""
|
|
301
|
+
|
|
302
|
+
_exterior = None
|
|
303
|
+
_interiors = []
|
|
304
|
+
_ndim = 2
|
|
305
|
+
|
|
306
|
+
def __init__(self, shell=None, holes=None):
|
|
307
|
+
"""Initialize.
|
|
308
|
+
|
|
309
|
+
Parameters
|
|
310
|
+
----------
|
|
311
|
+
exterior : sequence or array
|
|
312
|
+
This may be an object that satisfies the numpy array protocol,
|
|
313
|
+
providing an M x 2 or M x 3 (with z) array, or it may be a sequence
|
|
314
|
+
of x, y (,z) coordinate sequences.
|
|
315
|
+
|
|
316
|
+
Example
|
|
317
|
+
-------
|
|
318
|
+
>>> coords = ((0., 0.), (0., 1.), (1., 1.), (1., 0.), (0., 0.))
|
|
319
|
+
>>> polygon = Polygon(coords)
|
|
320
|
+
"""
|
|
321
|
+
BaseGeometry.__init__(self)
|
|
322
|
+
|
|
323
|
+
if shell is not None:
|
|
324
|
+
self._geom, self._ndims = geos_polygon_from_py(shell, holes)
|
|
325
|
+
|
|
326
|
+
@property
|
|
327
|
+
def exterior(self):
|
|
328
|
+
if self._exterior is None:
|
|
329
|
+
# A polygon created from the abstract factory will have a null
|
|
330
|
+
# _exterior attribute.
|
|
331
|
+
ring = lgeos.GEOSGetExteriorRing(self._geom)
|
|
332
|
+
self._exterior = LinearRing()
|
|
333
|
+
self._exterior._geom = ring
|
|
334
|
+
self._exterior._owned = True
|
|
335
|
+
return self._exterior
|
|
336
|
+
|
|
337
|
+
@property
|
|
338
|
+
def interiors(self):
|
|
339
|
+
return InteriorRingSequence(self)
|
|
340
|
+
|
|
341
|
+
@property
|
|
342
|
+
def ctypes(self):
|
|
343
|
+
if not self._ctypes_data:
|
|
344
|
+
self._ctypes_data = self.exterior.ctypes
|
|
345
|
+
return self._ctypes_data
|
|
346
|
+
|
|
347
|
+
@property
|
|
348
|
+
def __array_interface__(self):
|
|
349
|
+
raise NotImplementedError, \
|
|
350
|
+
"A polygon does not itself provide the array interface. Its rings do."
|
|
351
|
+
|
|
352
|
+
@property
|
|
353
|
+
def coords(self):
|
|
354
|
+
raise NotImplementedError, \
|
|
355
|
+
"Component rings have coordinate sequences, but the polygon does not"
|
|
356
|
+
|
|
357
|
+
@property
|
|
358
|
+
def __geo_interface__(self):
|
|
359
|
+
coords = [tuple(self.exterior.coords)]
|
|
360
|
+
for hole in self.interiors:
|
|
361
|
+
coords.append(tuple(hole.coords))
|
|
362
|
+
return {
|
|
363
|
+
'type': 'Polygon',
|
|
364
|
+
'coordinates': tuple(coords)
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
class PolygonAdapter(Polygon):
|
|
369
|
+
|
|
370
|
+
"""Adapts sequences of sequences or numpy arrays to the polygon
|
|
371
|
+
interface.
|
|
372
|
+
"""
|
|
373
|
+
|
|
374
|
+
context = None
|
|
375
|
+
|
|
376
|
+
def __init__(self, shell, holes=None):
|
|
377
|
+
self.shell = shell
|
|
378
|
+
self.holes = holes
|
|
379
|
+
|
|
380
|
+
# Override base class __del__
|
|
381
|
+
def __del__(self):
|
|
382
|
+
pass
|
|
383
|
+
|
|
384
|
+
@property
|
|
385
|
+
def _ndim(self):
|
|
386
|
+
try:
|
|
387
|
+
# From array protocol
|
|
388
|
+
array = self.shell.__array_interface__
|
|
389
|
+
n = array['shape'][1]
|
|
390
|
+
assert n == 2 or n == 3
|
|
391
|
+
return n
|
|
392
|
+
except AttributeError:
|
|
393
|
+
# Fall back on list
|
|
394
|
+
return len(self.shell[0])
|
|
395
|
+
|
|
396
|
+
@property
|
|
397
|
+
def _geom(self):
|
|
398
|
+
"""Keeps the GEOS geometry in synch with the context."""
|
|
399
|
+
return geos_polygon_from_py(self.shell, self.holes)[0]
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def asPolygon(shell, holes=None):
|
|
403
|
+
"""Factory for PolygonAdapter instances."""
|
|
404
|
+
return PolygonAdapter(shell, holes)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
# Test runner
|
|
408
|
+
def _test():
|
|
409
|
+
import doctest
|
|
410
|
+
doctest.testmod()
|
|
411
|
+
|
|
412
|
+
if __name__ == "__main__":
|
|
413
|
+
_test()
|
|
414
|
+
|
|
Binary file
|