shapely 1.2.8__py2.7-win-amd64.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.
- DLLs/geos.dll +0 -0
- DLLs/geos_c.dll +0 -0
- EGG-INFO/PKG-INFO +173 -0
- EGG-INFO/not-zip-safe +1 -0
- EGG-INFO/scripts/dissolve.py +53 -0
- EGG-INFO/scripts/intersect.py +81 -0
- shapely/__init__.py +1 -0
- shapely/__init__.pyc +0 -0
- shapely/coords.py +167 -0
- shapely/coords.pyc +0 -0
- shapely/ctypes_declarations.py +279 -0
- shapely/ctypes_declarations.pyc +0 -0
- shapely/ftools.py +78 -0
- shapely/ftools.pyc +0 -0
- shapely/geometry/__init__.py +20 -0
- shapely/geometry/__init__.pyc +0 -0
- shapely/geometry/base.py +595 -0
- shapely/geometry/base.pyc +0 -0
- shapely/geometry/collection.py +43 -0
- shapely/geometry/collection.pyc +0 -0
- shapely/geometry/geo.py +68 -0
- shapely/geometry/geo.pyc +0 -0
- shapely/geometry/linestring.py +259 -0
- shapely/geometry/linestring.pyc +0 -0
- shapely/geometry/multilinestring.py +133 -0
- shapely/geometry/multilinestring.pyc +0 -0
- shapely/geometry/multipoint.py +180 -0
- shapely/geometry/multipoint.pyc +0 -0
- shapely/geometry/multipolygon.py +154 -0
- shapely/geometry/multipolygon.pyc +0 -0
- shapely/geometry/point.py +241 -0
- shapely/geometry/point.pyc +0 -0
- shapely/geometry/polygon.py +449 -0
- shapely/geometry/polygon.pyc +0 -0
- shapely/geometry/proxy.py +54 -0
- shapely/geometry/proxy.pyc +0 -0
- shapely/geos.py +373 -0
- shapely/geos.pyc +0 -0
- shapely/impl.py +119 -0
- shapely/impl.pyc +0 -0
- shapely/iterops.py +53 -0
- shapely/iterops.pyc +0 -0
- shapely/linref.py +26 -0
- shapely/linref.pyc +0 -0
- shapely/ops.py +87 -0
- shapely/ops.pyc +0 -0
- shapely/predicates.py +24 -0
- shapely/predicates.pyc +0 -0
- shapely/prepared.py +58 -0
- shapely/prepared.pyc +0 -0
- shapely/topology.py +62 -0
- shapely/topology.pyc +0 -0
- shapely/validation.py +7 -0
- shapely/validation.pyc +0 -0
- shapely/wkb.py +39 -0
- shapely/wkb.pyc +0 -0
- shapely/wkt.py +34 -0
- shapely/wkt.pyc +0 -0
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
"""Polygons and their linear ring components
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
from ctypes import c_double, c_void_p, cast, POINTER
|
|
5
|
+
from ctypes import ArgumentError
|
|
6
|
+
import weakref
|
|
7
|
+
from shapely.geos import lgeos
|
|
8
|
+
from shapely.geometry.base import BaseGeometry
|
|
9
|
+
from shapely.geometry.linestring import LineString, LineStringAdapter
|
|
10
|
+
from shapely.geometry.proxy import PolygonProxy
|
|
11
|
+
|
|
12
|
+
__all__ = ['Polygon', 'asPolygon', 'LinearRing', 'asLinearRing']
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class LinearRing(LineString):
|
|
16
|
+
"""
|
|
17
|
+
A closed one-dimensional feature comprising one or more line segments
|
|
18
|
+
|
|
19
|
+
A LinearRing that crosses itself or touches itself at a single point is
|
|
20
|
+
invalid and operations on it may fail.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, coordinates=None):
|
|
24
|
+
"""
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
coordinates : sequence
|
|
28
|
+
A sequence of (x, y [,z]) numeric coordinate pairs or triples
|
|
29
|
+
|
|
30
|
+
Rings are implicitly closed. There is no need to specific a final
|
|
31
|
+
coordinate pair identical to the first.
|
|
32
|
+
|
|
33
|
+
Example
|
|
34
|
+
-------
|
|
35
|
+
Construct a square ring.
|
|
36
|
+
|
|
37
|
+
>>> ring = LinearRing( ((0, 0), (0, 1), (1 ,1 ), (1 , 0)) )
|
|
38
|
+
>>> ring.is_closed
|
|
39
|
+
True
|
|
40
|
+
>>> ring.length
|
|
41
|
+
4.0
|
|
42
|
+
"""
|
|
43
|
+
BaseGeometry.__init__(self)
|
|
44
|
+
if coordinates is not None:
|
|
45
|
+
self._set_coords(coordinates)
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def __geo_interface__(self):
|
|
49
|
+
return {
|
|
50
|
+
'type': 'LinearRing',
|
|
51
|
+
'coordinates': tuple(self.coords)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Coordinate access
|
|
55
|
+
|
|
56
|
+
_get_coords = BaseGeometry._get_coords
|
|
57
|
+
|
|
58
|
+
def _set_coords(self, coordinates):
|
|
59
|
+
self.empty()
|
|
60
|
+
self._geom, self._ndim = geos_linearring_from_py(coordinates)
|
|
61
|
+
|
|
62
|
+
coords = property(_get_coords, _set_coords)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class LinearRingAdapter(LineStringAdapter):
|
|
66
|
+
|
|
67
|
+
__p__ = None
|
|
68
|
+
|
|
69
|
+
def __init__(self, context):
|
|
70
|
+
self.context = context
|
|
71
|
+
self.factory = geos_linearring_from_py
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def __geo_interface__(self):
|
|
75
|
+
return {
|
|
76
|
+
'type': 'LinearRing',
|
|
77
|
+
'coordinates': tuple(self.coords)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
coords = property(BaseGeometry._get_coords)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def asLinearRing(context):
|
|
84
|
+
"""Adapt an object to the LinearRing interface"""
|
|
85
|
+
return LinearRingAdapter(context)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class InteriorRingSequence(object):
|
|
89
|
+
|
|
90
|
+
_factory = None
|
|
91
|
+
_geom = None
|
|
92
|
+
__p__ = None
|
|
93
|
+
_ndim = None
|
|
94
|
+
_index = 0
|
|
95
|
+
_length = 0
|
|
96
|
+
__rings__ = None
|
|
97
|
+
_gtag = None
|
|
98
|
+
|
|
99
|
+
def __init__(self, parent):
|
|
100
|
+
self.__p__ = parent
|
|
101
|
+
self._geom = parent._geom
|
|
102
|
+
self._ndim = parent._ndim
|
|
103
|
+
|
|
104
|
+
def __iter__(self):
|
|
105
|
+
self._index = 0
|
|
106
|
+
self._length = self.__len__()
|
|
107
|
+
return self
|
|
108
|
+
|
|
109
|
+
def next(self):
|
|
110
|
+
if self._index < self._length:
|
|
111
|
+
ring = self._get_ring(self._index)
|
|
112
|
+
self._index += 1
|
|
113
|
+
return ring
|
|
114
|
+
else:
|
|
115
|
+
raise StopIteration
|
|
116
|
+
|
|
117
|
+
def __len__(self):
|
|
118
|
+
return lgeos.GEOSGetNumInteriorRings(self._geom)
|
|
119
|
+
|
|
120
|
+
def __getitem__(self, i):
|
|
121
|
+
M = self.__len__()
|
|
122
|
+
if i + M < 0 or i >= M:
|
|
123
|
+
raise IndexError("index out of range")
|
|
124
|
+
if i < 0:
|
|
125
|
+
ii = M + i
|
|
126
|
+
else:
|
|
127
|
+
ii = i
|
|
128
|
+
return self._get_ring(i)
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def _longest(self):
|
|
132
|
+
max = 0
|
|
133
|
+
for g in iter(self):
|
|
134
|
+
l = len(g.coords)
|
|
135
|
+
if l > max:
|
|
136
|
+
max = l
|
|
137
|
+
|
|
138
|
+
def gtag(self):
|
|
139
|
+
return hash(repr(self.__p__))
|
|
140
|
+
|
|
141
|
+
def _get_ring(self, i):
|
|
142
|
+
gtag = self.gtag()
|
|
143
|
+
if gtag != self._gtag:
|
|
144
|
+
self.__rings__ = {}
|
|
145
|
+
if i not in self.__rings__:
|
|
146
|
+
g = lgeos.GEOSGetInteriorRingN(self._geom, i)
|
|
147
|
+
ring = LinearRing()
|
|
148
|
+
ring.__geom__ = g
|
|
149
|
+
ring.__p__ = self
|
|
150
|
+
ring._owned = True
|
|
151
|
+
ring._ndim = self._ndim
|
|
152
|
+
self.__rings__[i] = weakref.ref(ring)
|
|
153
|
+
return self.__rings__[i]()
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class Polygon(BaseGeometry):
|
|
157
|
+
"""
|
|
158
|
+
A two-dimensional figure bounded by a linear ring
|
|
159
|
+
|
|
160
|
+
A polygon has a non-zero area. It may have one or more negative-space
|
|
161
|
+
"holes" which are also bounded by linear rings. If any rings cross each
|
|
162
|
+
other, the feature is invalid and operations on it may fail.
|
|
163
|
+
|
|
164
|
+
Attributes
|
|
165
|
+
----------
|
|
166
|
+
exterior : LinearRing
|
|
167
|
+
The ring which bounds the positive space of the polygon.
|
|
168
|
+
interiors : sequence
|
|
169
|
+
A sequence of rings which bound all existing holes.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
_exterior = None
|
|
173
|
+
_interiors = []
|
|
174
|
+
_ndim = 2
|
|
175
|
+
|
|
176
|
+
def __init__(self, shell=None, holes=None):
|
|
177
|
+
"""
|
|
178
|
+
Parameters
|
|
179
|
+
----------
|
|
180
|
+
shell : sequence
|
|
181
|
+
A sequence of (x, y [,z]) numeric coordinate pairs or triples
|
|
182
|
+
holes : sequence
|
|
183
|
+
A sequence of objects which satisfy the same requirements as the
|
|
184
|
+
shell parameters above
|
|
185
|
+
|
|
186
|
+
Example
|
|
187
|
+
-------
|
|
188
|
+
Create a square polygon with no holes
|
|
189
|
+
|
|
190
|
+
>>> coords = ((0., 0.), (0., 1.), (1., 1.), (1., 0.), (0., 0.))
|
|
191
|
+
>>> polygon = Polygon(coords)
|
|
192
|
+
>>> polygon.area
|
|
193
|
+
1.0
|
|
194
|
+
"""
|
|
195
|
+
BaseGeometry.__init__(self)
|
|
196
|
+
|
|
197
|
+
if shell is not None:
|
|
198
|
+
self._geom, self._ndim = geos_polygon_from_py(shell, holes)
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def exterior(self):
|
|
202
|
+
if self.is_empty:
|
|
203
|
+
return None
|
|
204
|
+
elif self._exterior is None or self._exterior() is None:
|
|
205
|
+
g = lgeos.GEOSGetExteriorRing(self._geom)
|
|
206
|
+
ring = LinearRing()
|
|
207
|
+
ring.__geom__ = g
|
|
208
|
+
ring.__p__ = self
|
|
209
|
+
ring._owned = True
|
|
210
|
+
ring._ndim = self._ndim
|
|
211
|
+
self._exterior = weakref.ref(ring)
|
|
212
|
+
return self._exterior()
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def interiors(self):
|
|
216
|
+
if self.is_empty:
|
|
217
|
+
return []
|
|
218
|
+
return InteriorRingSequence(self)
|
|
219
|
+
|
|
220
|
+
@property
|
|
221
|
+
def ctypes(self):
|
|
222
|
+
if not self._ctypes_data:
|
|
223
|
+
self._ctypes_data = self.exterior.ctypes
|
|
224
|
+
return self._ctypes_data
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def __array_interface__(self):
|
|
228
|
+
raise NotImplementedError(
|
|
229
|
+
"A polygon does not itself provide the array interface. Its rings do.")
|
|
230
|
+
|
|
231
|
+
def _get_coords(self):
|
|
232
|
+
raise NotImplementedError(
|
|
233
|
+
"Component rings have coordinate sequences, but the polygon does not")
|
|
234
|
+
|
|
235
|
+
def _set_coords(self, ob):
|
|
236
|
+
raise NotImplementedError(
|
|
237
|
+
"Component rings have coordinate sequences, but the polygon does not")
|
|
238
|
+
|
|
239
|
+
@property
|
|
240
|
+
def coords(self):
|
|
241
|
+
raise NotImplementedError(
|
|
242
|
+
"Component rings have coordinate sequences, but the polygon does not")
|
|
243
|
+
|
|
244
|
+
@property
|
|
245
|
+
def __geo_interface__(self):
|
|
246
|
+
coords = [tuple(self.exterior.coords)]
|
|
247
|
+
for hole in self.interiors:
|
|
248
|
+
coords.append(tuple(hole.coords))
|
|
249
|
+
return {
|
|
250
|
+
'type': 'Polygon',
|
|
251
|
+
'coordinates': tuple(coords)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class PolygonAdapter(PolygonProxy, Polygon):
|
|
256
|
+
|
|
257
|
+
def __init__(self, shell, holes=None):
|
|
258
|
+
self.shell = shell
|
|
259
|
+
self.holes = holes
|
|
260
|
+
self.context = (shell, holes)
|
|
261
|
+
self.factory = geos_polygon_from_py
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def _ndim(self):
|
|
265
|
+
try:
|
|
266
|
+
# From array protocol
|
|
267
|
+
array = self.shell.__array_interface__
|
|
268
|
+
n = array['shape'][1]
|
|
269
|
+
assert n == 2 or n == 3
|
|
270
|
+
return n
|
|
271
|
+
except AttributeError:
|
|
272
|
+
# Fall back on list
|
|
273
|
+
return len(self.shell[0])
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def asPolygon(shell, holes=None):
|
|
277
|
+
"""Adapt objects to the Polygon interface"""
|
|
278
|
+
return PolygonAdapter(shell, holes)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def geos_linearring_from_py(ob, update_geom=None, update_ndim=0):
|
|
282
|
+
try:
|
|
283
|
+
# From array protocol
|
|
284
|
+
array = ob.__array_interface__
|
|
285
|
+
assert len(array['shape']) == 2
|
|
286
|
+
m = array['shape'][0]
|
|
287
|
+
n = array['shape'][1]
|
|
288
|
+
if m < 3:
|
|
289
|
+
raise ValueError(
|
|
290
|
+
"A LinearRing must have at least 3 coordinate tuples")
|
|
291
|
+
assert n == 2 or n == 3
|
|
292
|
+
|
|
293
|
+
# Make pointer to the coordinate array
|
|
294
|
+
try:
|
|
295
|
+
cp = cast(array['data'][0], POINTER(c_double))
|
|
296
|
+
except ArgumentError:
|
|
297
|
+
cp = array['data']
|
|
298
|
+
|
|
299
|
+
# Add closing coordinates to sequence?
|
|
300
|
+
if cp[0] != cp[m*n-n] or cp[1] != cp[m*n-n+1]:
|
|
301
|
+
M = m + 1
|
|
302
|
+
else:
|
|
303
|
+
M = m
|
|
304
|
+
|
|
305
|
+
# Create a coordinate sequence
|
|
306
|
+
if update_geom is not None:
|
|
307
|
+
cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
|
|
308
|
+
if n != update_ndim:
|
|
309
|
+
raise ValueError(
|
|
310
|
+
"Wrong coordinate dimensions; this geometry has dimensions: %d" \
|
|
311
|
+
% update_ndim)
|
|
312
|
+
else:
|
|
313
|
+
cs = lgeos.GEOSCoordSeq_create(M, n)
|
|
314
|
+
|
|
315
|
+
# add to coordinate sequence
|
|
316
|
+
for i in xrange(m):
|
|
317
|
+
dx = c_double(cp[n*i])
|
|
318
|
+
dy = c_double(cp[n*i+1])
|
|
319
|
+
dz = None
|
|
320
|
+
if n == 3:
|
|
321
|
+
dz = c_double(cp[n*i+2])
|
|
322
|
+
|
|
323
|
+
# Because of a bug in the GEOS C API,
|
|
324
|
+
# always set X before Y
|
|
325
|
+
lgeos.GEOSCoordSeq_setX(cs, i, dx)
|
|
326
|
+
lgeos.GEOSCoordSeq_setY(cs, i, dy)
|
|
327
|
+
if n == 3:
|
|
328
|
+
lgeos.GEOSCoordSeq_setZ(cs, i, dz)
|
|
329
|
+
|
|
330
|
+
# Add closing coordinates to sequence?
|
|
331
|
+
if M > m:
|
|
332
|
+
dx = c_double(cp[0])
|
|
333
|
+
dy = c_double(cp[1])
|
|
334
|
+
dz = None
|
|
335
|
+
if n == 3:
|
|
336
|
+
dz = c_double(cp[2])
|
|
337
|
+
|
|
338
|
+
# Because of a bug in the GEOS C API,
|
|
339
|
+
# always set X before Y
|
|
340
|
+
lgeos.GEOSCoordSeq_setX(cs, M-1, dx)
|
|
341
|
+
lgeos.GEOSCoordSeq_setY(cs, M-1, dy)
|
|
342
|
+
if n == 3:
|
|
343
|
+
lgeos.GEOSCoordSeq_setZ(cs, M-1, dz)
|
|
344
|
+
|
|
345
|
+
except AttributeError:
|
|
346
|
+
# Fall back on list
|
|
347
|
+
m = len(ob)
|
|
348
|
+
n = len(ob[0])
|
|
349
|
+
if m < 3:
|
|
350
|
+
raise ValueError(
|
|
351
|
+
"A LinearRing must have at least 3 coordinate tuples")
|
|
352
|
+
assert (n == 2 or n == 3)
|
|
353
|
+
|
|
354
|
+
# Add closing coordinates if not provided
|
|
355
|
+
if m == 3 or ob[0][0] != ob[-1][0] or ob[0][1] != ob[-1][1]:
|
|
356
|
+
M = m + 1
|
|
357
|
+
else:
|
|
358
|
+
M = m
|
|
359
|
+
|
|
360
|
+
# Create a coordinate sequence
|
|
361
|
+
if update_geom is not None:
|
|
362
|
+
cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
|
|
363
|
+
if n != update_ndim:
|
|
364
|
+
raise ValueError(
|
|
365
|
+
"Wrong coordinate dimensions; this geometry has dimensions: %d" \
|
|
366
|
+
% update_ndim)
|
|
367
|
+
else:
|
|
368
|
+
cs = lgeos.GEOSCoordSeq_create(M, n)
|
|
369
|
+
|
|
370
|
+
# add to coordinate sequence
|
|
371
|
+
for i in xrange(m):
|
|
372
|
+
coords = ob[i]
|
|
373
|
+
dx = c_double(coords[0])
|
|
374
|
+
dy = c_double(coords[1])
|
|
375
|
+
dz = None
|
|
376
|
+
if n == 3:
|
|
377
|
+
dz = c_double(coords[2])
|
|
378
|
+
|
|
379
|
+
# Because of a bug in the GEOS C API,
|
|
380
|
+
# always set X before Y
|
|
381
|
+
lgeos.GEOSCoordSeq_setX(cs, i, dx)
|
|
382
|
+
lgeos.GEOSCoordSeq_setY(cs, i, dy)
|
|
383
|
+
if n == 3:
|
|
384
|
+
lgeos.GEOSCoordSeq_setZ(cs, i, dz)
|
|
385
|
+
|
|
386
|
+
# Add closing coordinates to sequence?
|
|
387
|
+
if M > m:
|
|
388
|
+
coords = ob[0]
|
|
389
|
+
dx = c_double(coords[0])
|
|
390
|
+
dy = c_double(coords[1])
|
|
391
|
+
dz = None
|
|
392
|
+
if n == 3:
|
|
393
|
+
dz = c_double(coords[2])
|
|
394
|
+
|
|
395
|
+
# Because of a bug in the GEOS C API,
|
|
396
|
+
# always set X before Y
|
|
397
|
+
lgeos.GEOSCoordSeq_setX(cs, M-1, dx)
|
|
398
|
+
lgeos.GEOSCoordSeq_setY(cs, M-1, dy)
|
|
399
|
+
if n == 3:
|
|
400
|
+
lgeos.GEOSCoordSeq_setZ(cs, M-1, dz)
|
|
401
|
+
|
|
402
|
+
if update_geom is not None:
|
|
403
|
+
return None
|
|
404
|
+
else:
|
|
405
|
+
return lgeos.GEOSGeom_createLinearRing(cs), n
|
|
406
|
+
|
|
407
|
+
def update_linearring_from_py(geom, ob):
|
|
408
|
+
geos_linearring_from_py(ob, geom._geom, geom._ndim)
|
|
409
|
+
|
|
410
|
+
def geos_polygon_from_py(shell, holes=None):
|
|
411
|
+
if shell is not None:
|
|
412
|
+
geos_shell, ndim = geos_linearring_from_py(shell)
|
|
413
|
+
if holes:
|
|
414
|
+
ob = holes
|
|
415
|
+
L = len(ob)
|
|
416
|
+
exemplar = ob[0]
|
|
417
|
+
try:
|
|
418
|
+
N = len(exemplar[0])
|
|
419
|
+
except TypeError:
|
|
420
|
+
N = exemplar._ndim
|
|
421
|
+
assert L >= 1
|
|
422
|
+
assert N == 2 or N == 3
|
|
423
|
+
|
|
424
|
+
# Array of pointers to ring geometries
|
|
425
|
+
geos_holes = (c_void_p * L)()
|
|
426
|
+
|
|
427
|
+
# add to coordinate sequence
|
|
428
|
+
for l in xrange(L):
|
|
429
|
+
geom, ndim = geos_linearring_from_py(ob[l])
|
|
430
|
+
geos_holes[l] = cast(geom, c_void_p)
|
|
431
|
+
else:
|
|
432
|
+
geos_holes = POINTER(c_void_p)()
|
|
433
|
+
L = 0
|
|
434
|
+
return (
|
|
435
|
+
lgeos.GEOSGeom_createPolygon(
|
|
436
|
+
c_void_p(geos_shell),
|
|
437
|
+
geos_holes,
|
|
438
|
+
L
|
|
439
|
+
),
|
|
440
|
+
ndim
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
# Test runner
|
|
444
|
+
def _test():
|
|
445
|
+
import doctest
|
|
446
|
+
doctest.testmod()
|
|
447
|
+
|
|
448
|
+
if __name__ == "__main__":
|
|
449
|
+
_test()
|
|
Binary file
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Proxy for coordinates stored outside Shapely geometries
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
from shapely.geos import lgeos
|
|
5
|
+
from shapely import wkb
|
|
6
|
+
|
|
7
|
+
EMPTY = wkb.deserialize('010700000000000000'.decode('hex'))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CachingGeometryProxy(object):
|
|
11
|
+
|
|
12
|
+
context = None
|
|
13
|
+
factory = None
|
|
14
|
+
__geom__ = EMPTY
|
|
15
|
+
_gtag = None
|
|
16
|
+
|
|
17
|
+
def __init__(self, context):
|
|
18
|
+
self.context = context
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def _is_empty(self):
|
|
22
|
+
return self.__geom__ in [EMPTY, None]
|
|
23
|
+
|
|
24
|
+
def empty(self):
|
|
25
|
+
if not self._is_empty:
|
|
26
|
+
from shapely.geos import lgeos
|
|
27
|
+
lgeos.GEOSGeom_destroy(self.__geom__)
|
|
28
|
+
self.__geom__ = EMPTY
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def _geom(self):
|
|
32
|
+
"""Keeps the GEOS geometry in synch with the context."""
|
|
33
|
+
gtag = self.gtag()
|
|
34
|
+
if gtag != self._gtag or self._is_empty:
|
|
35
|
+
self.empty()
|
|
36
|
+
self.__geom__, n = self.factory(self.context)
|
|
37
|
+
self._gtag = gtag
|
|
38
|
+
return self.__geom__
|
|
39
|
+
|
|
40
|
+
def gtag(self):
|
|
41
|
+
return hash(repr(self.context))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class PolygonProxy(CachingGeometryProxy):
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def _geom(self):
|
|
48
|
+
"""Keeps the GEOS geometry in synch with the context."""
|
|
49
|
+
gtag = self.gtag()
|
|
50
|
+
if gtag != self._gtag or self._is_empty:
|
|
51
|
+
self.empty()
|
|
52
|
+
self.__geom__, n = self.factory(self.context[0], self.context[1])
|
|
53
|
+
self._gtag = gtag
|
|
54
|
+
return self.__geom__
|
|
Binary file
|