shapely 1.0__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 +173 -0
- EGG-INFO/SOURCES.txt +52 -0
- EGG-INFO/dependency_links.txt +1 -0
- EGG-INFO/not-zip-safe +1 -0
- EGG-INFO/requires.txt +2 -0
- EGG-INFO/top_level.txt +1 -0
- shapely/__init__.py +1 -0
- shapely/__init__.pyc +0 -0
- shapely/geometry/__init__.py +9 -0
- shapely/geometry/__init__.pyc +0 -0
- shapely/geometry/base.py +415 -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 +234 -0
- shapely/geometry/linestring.pyc +0 -0
- shapely/geometry/multilinestring.py +157 -0
- shapely/geometry/multilinestring.pyc +0 -0
- shapely/geometry/multipoint.py +187 -0
- shapely/geometry/multipoint.pyc +0 -0
- shapely/geometry/multipolygon.py +143 -0
- shapely/geometry/multipolygon.pyc +0 -0
- shapely/geometry/point.py +259 -0
- shapely/geometry/point.pyc +0 -0
- shapely/geometry/polygon.py +429 -0
- shapely/geometry/polygon.pyc +0 -0
- shapely/geos.py +80 -0
- shapely/geos.pyc +0 -0
- shapely/iterops.py +56 -0
- shapely/iterops.pyc +0 -0
- shapely/kml.py +0 -0
- shapely/kml.pyc +0 -0
- shapely/predicates.py +58 -0
- shapely/predicates.pyc +0 -0
- shapely/topology.py +66 -0
- shapely/topology.pyc +0 -0
- shapely/wkb.py +40 -0
- shapely/wkb.pyc +0 -0
- shapely/wkt.py +40 -0
- shapely/wkt.pyc +0 -0
|
@@ -0,0 +1,429 @@
|
|
|
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, exceptNull
|
|
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
|
+
__geom = None
|
|
145
|
+
_owned = False
|
|
146
|
+
|
|
147
|
+
def __init__(self, coordinates=None):
|
|
148
|
+
"""Initialize.
|
|
149
|
+
|
|
150
|
+
Parameters
|
|
151
|
+
----------
|
|
152
|
+
coordinates : sequence or array
|
|
153
|
+
This may be an object that satisfies the numpy array protocol,
|
|
154
|
+
providing an M x 2 or M x 3 (with z) array, or it may be a sequence
|
|
155
|
+
of x, y (,z) coordinate sequences.
|
|
156
|
+
|
|
157
|
+
Rings are implicitly closed. There is no need to specific a final
|
|
158
|
+
coordinate pair identical to the first.
|
|
159
|
+
|
|
160
|
+
Example
|
|
161
|
+
-------
|
|
162
|
+
>>> ring = LinearRing( ((0.,0.), (0.,1.), (1.,1.), (1.,0.)) )
|
|
163
|
+
|
|
164
|
+
Produces a 1x1 square.
|
|
165
|
+
"""
|
|
166
|
+
BaseGeometry.__init__(self)
|
|
167
|
+
self._init_geom(coordinates)
|
|
168
|
+
|
|
169
|
+
def _init_geom(self, coordinates):
|
|
170
|
+
if coordinates is None:
|
|
171
|
+
# allow creation of null lines, to support unpickling
|
|
172
|
+
pass
|
|
173
|
+
else:
|
|
174
|
+
self._geom, self._ndims = geos_linearring_from_py(coordinates)
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def __geo_interface__(self):
|
|
178
|
+
return {
|
|
179
|
+
'type': 'LinearRing',
|
|
180
|
+
'coordinates': tuple(self.coords)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
# Coordinate access
|
|
184
|
+
|
|
185
|
+
def set_coords(self, coordinates):
|
|
186
|
+
if self._geom is None:
|
|
187
|
+
self._init_geom(coordinates)
|
|
188
|
+
update_linearring_from_py(self, coordinates)
|
|
189
|
+
|
|
190
|
+
coords = property(BaseGeometry.get_coords, set_coords)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class LinearRingAdapter(LineStringAdapter):
|
|
194
|
+
|
|
195
|
+
context = None
|
|
196
|
+
__geom = None
|
|
197
|
+
_owned = False
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def _geom(self):
|
|
201
|
+
"""Keeps the GEOS geometry in synch with the context."""
|
|
202
|
+
if self.__geom is not None:
|
|
203
|
+
lgeos.GEOSGeom_destroy(self.__geom)
|
|
204
|
+
self.__geom, n = geos_linearring_from_py(self.context)
|
|
205
|
+
return self.__geom
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def __geo_interface__(self):
|
|
209
|
+
return {
|
|
210
|
+
'type': 'LinearRing',
|
|
211
|
+
'coordinates': tuple(self.coords)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
coords = property(BaseGeometry.get_coords)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def asLinearRing(context):
|
|
218
|
+
return LinearRingAdapter(context)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class InteriorRingSequence(object):
|
|
222
|
+
|
|
223
|
+
_factory = None
|
|
224
|
+
_geom = None
|
|
225
|
+
_ndim = None
|
|
226
|
+
_index = 0
|
|
227
|
+
_length = 0
|
|
228
|
+
|
|
229
|
+
def __init__(self, geom):
|
|
230
|
+
self._geom = geom._geom
|
|
231
|
+
self._ndim = geom._ndim
|
|
232
|
+
|
|
233
|
+
def __iter__(self):
|
|
234
|
+
self._index = 0
|
|
235
|
+
self._length = self.__len__()
|
|
236
|
+
return self
|
|
237
|
+
|
|
238
|
+
def next(self):
|
|
239
|
+
if self._index < self._length:
|
|
240
|
+
g = LinearRing()
|
|
241
|
+
g._owned = True
|
|
242
|
+
g._geom = lgeos.GEOSGetInteriorRingN(self._geom, self._index)
|
|
243
|
+
self._index += 1
|
|
244
|
+
return g
|
|
245
|
+
else:
|
|
246
|
+
raise StopIteration
|
|
247
|
+
|
|
248
|
+
def __len__(self):
|
|
249
|
+
return lgeos.GEOSGetNumInteriorRings(self._geom)
|
|
250
|
+
|
|
251
|
+
def __getitem__(self, i):
|
|
252
|
+
M = self.__len__()
|
|
253
|
+
if i + M < 0 or i >= M:
|
|
254
|
+
raise IndexError, "index out of range"
|
|
255
|
+
if i < 0:
|
|
256
|
+
ii = M + i
|
|
257
|
+
else:
|
|
258
|
+
ii = i
|
|
259
|
+
g = LinearRing()
|
|
260
|
+
g._owned = True
|
|
261
|
+
g._geom = lgeos.GEOSGetInteriorRingN(self._geom, ii)
|
|
262
|
+
return g
|
|
263
|
+
|
|
264
|
+
@property
|
|
265
|
+
def _longest(self):
|
|
266
|
+
max = 0
|
|
267
|
+
for g in iter(self):
|
|
268
|
+
l = len(g.coords)
|
|
269
|
+
if l > max:
|
|
270
|
+
max = l
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def geos_polygon_from_py(shell, holes=None):
|
|
274
|
+
if shell is not None:
|
|
275
|
+
geos_shell, ndims = geos_linearring_from_py(shell)
|
|
276
|
+
if holes:
|
|
277
|
+
ob = holes
|
|
278
|
+
L = len(ob)
|
|
279
|
+
try:
|
|
280
|
+
N = len(ob[0][0])
|
|
281
|
+
except:
|
|
282
|
+
import pdb; pdb.set_trace()
|
|
283
|
+
assert L >= 1
|
|
284
|
+
assert N == 2 or N == 3
|
|
285
|
+
|
|
286
|
+
# Array of pointers to ring geometries
|
|
287
|
+
geos_holes = (c_void_p * L)()
|
|
288
|
+
|
|
289
|
+
# add to coordinate sequence
|
|
290
|
+
for l in xrange(L):
|
|
291
|
+
geom, ndims = geos_linearring_from_py(ob[l])
|
|
292
|
+
geos_holes[l] = cast(geom, c_void_p)
|
|
293
|
+
|
|
294
|
+
else:
|
|
295
|
+
geos_holes = POINTER(c_void_p)()
|
|
296
|
+
L = 0
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
lgeos.GEOSGeom_createPolygon(
|
|
300
|
+
c_void_p(geos_shell),
|
|
301
|
+
geos_holes,
|
|
302
|
+
L
|
|
303
|
+
),
|
|
304
|
+
ndims
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
class Polygon(BaseGeometry):
|
|
308
|
+
|
|
309
|
+
"""A line string, also known as a polyline.
|
|
310
|
+
"""
|
|
311
|
+
|
|
312
|
+
_exterior = None
|
|
313
|
+
_interiors = []
|
|
314
|
+
_ndim = 2
|
|
315
|
+
__geom = None
|
|
316
|
+
_owned = False
|
|
317
|
+
|
|
318
|
+
def __init__(self, shell=None, holes=None):
|
|
319
|
+
"""Initialize.
|
|
320
|
+
|
|
321
|
+
Parameters
|
|
322
|
+
----------
|
|
323
|
+
exterior : sequence or array
|
|
324
|
+
This may be an object that satisfies the numpy array protocol,
|
|
325
|
+
providing an M x 2 or M x 3 (with z) array, or it may be a sequence
|
|
326
|
+
of x, y (,z) coordinate sequences.
|
|
327
|
+
|
|
328
|
+
Example
|
|
329
|
+
-------
|
|
330
|
+
>>> coords = ((0., 0.), (0., 1.), (1., 1.), (1., 0.), (0., 0.))
|
|
331
|
+
>>> polygon = Polygon(coords)
|
|
332
|
+
"""
|
|
333
|
+
BaseGeometry.__init__(self)
|
|
334
|
+
|
|
335
|
+
if shell is not None:
|
|
336
|
+
self._geom, self._ndims = geos_polygon_from_py(shell, holes)
|
|
337
|
+
|
|
338
|
+
@property
|
|
339
|
+
@exceptNull
|
|
340
|
+
def exterior(self):
|
|
341
|
+
if self._exterior is None:
|
|
342
|
+
# A polygon created from the abstract factory will have a null
|
|
343
|
+
# _exterior attribute.
|
|
344
|
+
ring = lgeos.GEOSGetExteriorRing(self._geom)
|
|
345
|
+
self._exterior = LinearRing()
|
|
346
|
+
self._exterior._geom = ring
|
|
347
|
+
self._exterior._owned = True
|
|
348
|
+
return self._exterior
|
|
349
|
+
|
|
350
|
+
@property
|
|
351
|
+
@exceptNull
|
|
352
|
+
def interiors(self):
|
|
353
|
+
return InteriorRingSequence(self)
|
|
354
|
+
|
|
355
|
+
@property
|
|
356
|
+
def ctypes(self):
|
|
357
|
+
if not self._ctypes_data:
|
|
358
|
+
self._ctypes_data = self.exterior.ctypes
|
|
359
|
+
return self._ctypes_data
|
|
360
|
+
|
|
361
|
+
@property
|
|
362
|
+
def __array_interface__(self):
|
|
363
|
+
raise NotImplementedError, \
|
|
364
|
+
"A polygon does not itself provide the array interface. Its rings do."
|
|
365
|
+
|
|
366
|
+
@property
|
|
367
|
+
def coords(self):
|
|
368
|
+
raise NotImplementedError, \
|
|
369
|
+
"Component rings have coordinate sequences, but the polygon does not"
|
|
370
|
+
|
|
371
|
+
@property
|
|
372
|
+
def __geo_interface__(self):
|
|
373
|
+
coords = [tuple(self.exterior.coords)]
|
|
374
|
+
for hole in self.interiors:
|
|
375
|
+
coords.append(tuple(hole.coords))
|
|
376
|
+
return {
|
|
377
|
+
'type': 'Polygon',
|
|
378
|
+
'coordinates': tuple(coords)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
class PolygonAdapter(Polygon):
|
|
383
|
+
|
|
384
|
+
"""Adapts sequences of sequences or numpy arrays to the polygon
|
|
385
|
+
interface.
|
|
386
|
+
"""
|
|
387
|
+
|
|
388
|
+
context = None
|
|
389
|
+
__geom = None
|
|
390
|
+
_owned = False
|
|
391
|
+
|
|
392
|
+
def __init__(self, shell, holes=None):
|
|
393
|
+
self.shell = shell
|
|
394
|
+
self.holes = holes
|
|
395
|
+
|
|
396
|
+
@property
|
|
397
|
+
def _ndim(self):
|
|
398
|
+
try:
|
|
399
|
+
# From array protocol
|
|
400
|
+
array = self.shell.__array_interface__
|
|
401
|
+
n = array['shape'][1]
|
|
402
|
+
assert n == 2 or n == 3
|
|
403
|
+
return n
|
|
404
|
+
except AttributeError:
|
|
405
|
+
# Fall back on list
|
|
406
|
+
return len(self.shell[0])
|
|
407
|
+
|
|
408
|
+
@property
|
|
409
|
+
def _geom(self):
|
|
410
|
+
"""Keeps the GEOS geometry in synch with the context."""
|
|
411
|
+
if self.__geom is not None:
|
|
412
|
+
lgeos.GEOSGeom_destroy(self.__geom)
|
|
413
|
+
self.__geom = geos_polygon_from_py(self.shell, self.holes)[0]
|
|
414
|
+
return self.__geom
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def asPolygon(shell, holes=None):
|
|
418
|
+
"""Factory for PolygonAdapter instances."""
|
|
419
|
+
return PolygonAdapter(shell, holes)
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
# Test runner
|
|
423
|
+
def _test():
|
|
424
|
+
import doctest
|
|
425
|
+
doctest.testmod()
|
|
426
|
+
|
|
427
|
+
if __name__ == "__main__":
|
|
428
|
+
_test()
|
|
429
|
+
|
|
Binary file
|
shapely/geos.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Exports the libgeos_c shared lib, GEOS-specific exceptions, and utilities.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import atexit
|
|
6
|
+
from ctypes import cdll, CDLL, CFUNCTYPE, c_char_p
|
|
7
|
+
from ctypes.util import find_library
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
import shapely
|
|
12
|
+
|
|
13
|
+
if sys.platform == 'win32':
|
|
14
|
+
try:
|
|
15
|
+
local_dlls = os.path.abspath(os.__file__ + "../../../DLLs")
|
|
16
|
+
original_path = os.environ['PATH']
|
|
17
|
+
os.environ['PATH'] = "%s;%s" % (local_dlls, original_path)
|
|
18
|
+
lgeos = CDLL("geos.dll")
|
|
19
|
+
except (ImportError, WindowsError):
|
|
20
|
+
raise
|
|
21
|
+
def free(m):
|
|
22
|
+
try:
|
|
23
|
+
cdll.msvcrt.free(m)
|
|
24
|
+
except WindowsError:
|
|
25
|
+
# XXX: See http://trac.gispython.org/projects/PCL/ticket/149
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
elif sys.platform == 'darwin':
|
|
29
|
+
lgeos = CDLL(find_library('geos_c'))
|
|
30
|
+
free = CDLL(find_library('libc')).free
|
|
31
|
+
else:
|
|
32
|
+
# Try the major versioned name first, falling back on the unversioned name.
|
|
33
|
+
try:
|
|
34
|
+
lgeos = CDLL('libgeos_c.so.1')
|
|
35
|
+
except ImportError:
|
|
36
|
+
lgeos = CDLL('libgeos_c.so')
|
|
37
|
+
except:
|
|
38
|
+
raise
|
|
39
|
+
free = CDLL('libc.so.6').free
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class allocated_c_char_p(c_char_p):
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Exceptions
|
|
47
|
+
|
|
48
|
+
class ReadingError(Exception):
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
class DimensionError(Exception):
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
class TopologicalError(Exception):
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
class PredicateError(Exception):
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# GEOS error handlers, which currently do nothing.
|
|
62
|
+
|
|
63
|
+
def error_handler(fmt, list):
|
|
64
|
+
pass
|
|
65
|
+
error_h = CFUNCTYPE(None, c_char_p, c_char_p)(error_handler)
|
|
66
|
+
|
|
67
|
+
def notice_handler(fmt, list):
|
|
68
|
+
pass
|
|
69
|
+
notice_h = CFUNCTYPE(None, c_char_p, c_char_p)(notice_handler)
|
|
70
|
+
|
|
71
|
+
# Register a cleanup function
|
|
72
|
+
|
|
73
|
+
def cleanup():
|
|
74
|
+
lgeos.finishGEOS()
|
|
75
|
+
|
|
76
|
+
atexit.register(cleanup)
|
|
77
|
+
|
|
78
|
+
lgeos.initGEOS(notice_h, error_h)
|
|
79
|
+
|
|
80
|
+
|
shapely/geos.pyc
ADDED
|
Binary file
|
shapely/iterops.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
from ctypes import c_char_p, c_size_t
|
|
5
|
+
from shapely.geos import lgeos, free
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def geos_from_geometry(geom):
|
|
9
|
+
data = geom.to_wkb()
|
|
10
|
+
return lgeos.GEOSGeomFromWKB_buf(
|
|
11
|
+
c_char_p(data),
|
|
12
|
+
c_size_t(len(data))
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
class BinaryPredicateIterator(object):
|
|
16
|
+
|
|
17
|
+
"""A generating non-data descriptor.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
fn = None
|
|
21
|
+
context = None
|
|
22
|
+
|
|
23
|
+
def __init__(self, fn):
|
|
24
|
+
self.fn = fn
|
|
25
|
+
|
|
26
|
+
def __get__(self, obj, objtype=None):
|
|
27
|
+
self.context = obj
|
|
28
|
+
return self
|
|
29
|
+
|
|
30
|
+
def __call__(self, geom, iterator, value=True):
|
|
31
|
+
if geom._geom is None:
|
|
32
|
+
raise ValueError, "Null geometry supports no operations"
|
|
33
|
+
for item in iterator:
|
|
34
|
+
try:
|
|
35
|
+
this_geom, ob = item
|
|
36
|
+
except TypeError:
|
|
37
|
+
this_geom = item
|
|
38
|
+
ob = this_geom
|
|
39
|
+
if this_geom._geom is None:
|
|
40
|
+
raise ValueError, "Null geometry supports no operations"
|
|
41
|
+
retval = self.fn(geom._geom, this_geom._geom)
|
|
42
|
+
if retval == 2:
|
|
43
|
+
raise PredicateError, "Failed to evaluate %s" % repr(self.fn)
|
|
44
|
+
elif bool(retval) == value:
|
|
45
|
+
yield ob
|
|
46
|
+
|
|
47
|
+
# utilities
|
|
48
|
+
disjoint = BinaryPredicateIterator(lgeos.GEOSDisjoint)
|
|
49
|
+
touches = BinaryPredicateIterator(lgeos.GEOSTouches)
|
|
50
|
+
intersects = BinaryPredicateIterator(lgeos.GEOSIntersects)
|
|
51
|
+
crosses = BinaryPredicateIterator(lgeos.GEOSCrosses)
|
|
52
|
+
within = BinaryPredicateIterator(lgeos.GEOSWithin)
|
|
53
|
+
contains = BinaryPredicateIterator(lgeos.GEOSContains)
|
|
54
|
+
overlaps = BinaryPredicateIterator(lgeos.GEOSOverlaps)
|
|
55
|
+
equals = BinaryPredicateIterator(lgeos.GEOSEquals)
|
|
56
|
+
|
shapely/iterops.pyc
ADDED
|
Binary file
|
shapely/kml.py
ADDED
|
File without changes
|
shapely/kml.pyc
ADDED
|
Binary file
|
shapely/predicates.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Support for GEOS spatial predicates.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from shapely.geos import PredicateError
|
|
6
|
+
|
|
7
|
+
# Predicates
|
|
8
|
+
|
|
9
|
+
class BinaryPredicate(object):
|
|
10
|
+
|
|
11
|
+
"""A callable non-data descriptor.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
fn = None
|
|
15
|
+
context = None
|
|
16
|
+
|
|
17
|
+
def __init__(self, fn):
|
|
18
|
+
self.fn = fn
|
|
19
|
+
def errcheck(result, func, argtuple):
|
|
20
|
+
if result == 2:
|
|
21
|
+
raise PredicateError, "Failed to evaluate %s" % repr(self.fn)
|
|
22
|
+
return result
|
|
23
|
+
self.fn.errcheck = errcheck
|
|
24
|
+
|
|
25
|
+
def __get__(self, obj, objtype=None):
|
|
26
|
+
self.context = obj
|
|
27
|
+
return self
|
|
28
|
+
|
|
29
|
+
def __call__(self, other):
|
|
30
|
+
if self.context._geom is None or other._geom is None:
|
|
31
|
+
raise ValueError, "Null geometry supports no operations"
|
|
32
|
+
return bool(self.fn(self.context._geom, other._geom))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# A data descriptor
|
|
36
|
+
class UnaryPredicate(object):
|
|
37
|
+
|
|
38
|
+
"""A data descriptor.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
fn = None
|
|
42
|
+
|
|
43
|
+
def __init__(self, fn):
|
|
44
|
+
self.fn = fn
|
|
45
|
+
def errcheck(result, func, argtuple):
|
|
46
|
+
if result == 2:
|
|
47
|
+
raise PredicateError, "Failed to evaluate %s" % repr(self.fn)
|
|
48
|
+
return result
|
|
49
|
+
self.fn.errcheck = errcheck
|
|
50
|
+
|
|
51
|
+
def __get__(self, obj, objtype=None):
|
|
52
|
+
if obj._geom is None:
|
|
53
|
+
raise ValueError, "Null geometry supports no operations"
|
|
54
|
+
return bool(self.fn(obj._geom))
|
|
55
|
+
|
|
56
|
+
def __set__(self, obj, value=None):
|
|
57
|
+
raise AttributeError, "Attribute is read-only"
|
|
58
|
+
|
shapely/predicates.pyc
ADDED
|
Binary file
|
shapely/topology.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Support for GEOS topological operations.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from shapely.geos import TopologicalError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BinaryTopologicalOp(object):
|
|
9
|
+
|
|
10
|
+
"""A callable non-data descriptor.
|
|
11
|
+
|
|
12
|
+
Wraps a GEOS function. The factory is a callable which wraps results in
|
|
13
|
+
the appropriate shapely geometry class.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
fn = None
|
|
17
|
+
context = None
|
|
18
|
+
factory = None
|
|
19
|
+
|
|
20
|
+
def __init__(self, fn, factory):
|
|
21
|
+
self.fn = fn
|
|
22
|
+
self.factory = factory
|
|
23
|
+
|
|
24
|
+
def __get__(self, obj, objtype=None):
|
|
25
|
+
self.context = obj
|
|
26
|
+
return self
|
|
27
|
+
|
|
28
|
+
def __call__(self, other):
|
|
29
|
+
if self.context._geom is None or other._geom is None:
|
|
30
|
+
raise ValueError, "Null geometry supports no operations"
|
|
31
|
+
product = self.fn(self.context._geom, other._geom)
|
|
32
|
+
if not product:
|
|
33
|
+
# Check validity of geometries
|
|
34
|
+
if not self.context.is_valid:
|
|
35
|
+
raise TopologicalError, \
|
|
36
|
+
"The operation '%s' produced a null geometry. Likely cause is invalidity of the geometry %s" % (self.fn.__name__, repr(self.context))
|
|
37
|
+
elif not other.is_valid:
|
|
38
|
+
raise TopologicalError, \
|
|
39
|
+
"The operation '%s' produced a null geometry. Likely cause is invalidity of the 'other' geometry %s" % (self.fn.__name__, repr(other))
|
|
40
|
+
|
|
41
|
+
return self.factory(product)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class UnaryTopologicalOp(object):
|
|
45
|
+
|
|
46
|
+
"""A data descriptor.
|
|
47
|
+
|
|
48
|
+
Wraps a GEOS function. The factory is a callable which wraps results in
|
|
49
|
+
the appropriate shapely geometry class.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
fn = None
|
|
53
|
+
factory = None
|
|
54
|
+
|
|
55
|
+
def __init__(self, fn, factory):
|
|
56
|
+
self.fn = fn
|
|
57
|
+
self.factory = factory
|
|
58
|
+
|
|
59
|
+
def __get__(self, obj, objtype=None):
|
|
60
|
+
if obj._geom is None:
|
|
61
|
+
raise ValueError, "Null geometry supports no operations"
|
|
62
|
+
return self.factory(self.fn(obj._geom))
|
|
63
|
+
|
|
64
|
+
def __set__(self, obj, value=None):
|
|
65
|
+
raise AttributeError, "Attribute is read-only"
|
|
66
|
+
|
shapely/topology.pyc
ADDED
|
Binary file
|