shapely 1.2b5__tar.gz → 1.2b7__tar.gz
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.
- {Shapely-1.2b5 → Shapely-1.2b7}/CHANGES.txt +8 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/PKG-INFO +4 -4
- {Shapely-1.2b5 → Shapely-1.2b7}/README.txt +3 -3
- {Shapely-1.2b5 → Shapely-1.2b7}/Shapely.egg-info/PKG-INFO +4 -4
- Shapely-1.2b7/examples/dissolve.py +53 -0
- Shapely-1.2b7/examples/intersect.py +81 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/setup.py +1 -1
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/base.py +26 -6
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/collection.py +1 -1
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/linestring.py +4 -18
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/point.py +7 -18
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/polygon.py +7 -35
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/proxy.py +18 -11
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geos.py +2 -1
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/__init__.py +3 -0
- Shapely-1.2b5/examples/dissolve.py +0 -52
- Shapely-1.2b5/examples/intersect.py +0 -80
- {Shapely-1.2b5 → Shapely-1.2b7}/CREDITS.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/LICENSE.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/MANIFEST.in +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/Shapely.egg-info/SOURCES.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/Shapely.egg-info/dependency_links.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/Shapely.egg-info/top_level.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/setup.cfg +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/__init__.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/coords.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/ctypes_declarations.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/__init__.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/geo.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/multilinestring.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/multipoint.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/multipolygon.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geoms.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/impl.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/iterops.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/linref.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/ops.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/predicates.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/prepared.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/Array.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/GeoInterface.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/IterOps.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/LineString.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/MultiLineString.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/MultiPoint.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/MultiPolygon.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/Operations.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/Persist.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/Point.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/Polygon.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/Predicates.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/attribute-chains.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/binascii_hex.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/dimensions.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/invalid_intersection.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/linear-referencing.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/linemerge.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/polygonize.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/test_doctests.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/test_equality.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/test_geomseq.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/test_prepared.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/test_xy.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/threading_test.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/wkt_locale.txt +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/topology.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/wkb.py +0 -0
- {Shapely-1.2b5 → Shapely-1.2b7}/shapely/wkt.py +0 -0
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
All tickets are children of http://trac.gispython.org/lab/ticket.
|
|
2
2
|
|
|
3
|
+
1.2b7 (2010-04-22)
|
|
4
|
+
------------------
|
|
5
|
+
- Memory leak associated with new empty geometry state fixed.
|
|
6
|
+
|
|
7
|
+
1.2b6 (2010-04-13)
|
|
8
|
+
------------------
|
|
9
|
+
- Broken GeometryCollection fixed.
|
|
10
|
+
|
|
3
11
|
1.2b5 (2010-04-09)
|
|
4
12
|
------------------
|
|
5
13
|
- Objects can be constructed from others of the same type, thereby making
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 1.0
|
|
2
2
|
Name: Shapely
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2b7
|
|
4
4
|
Summary: Planar geometries, predicates, and operations
|
|
5
5
|
Home-page: http://trac.gispython.org/lab/wiki/Shapely
|
|
6
6
|
Author: Sean Gillies
|
|
@@ -10,9 +10,9 @@ Description:
|
|
|
10
10
|
Shapely
|
|
11
11
|
=======
|
|
12
12
|
|
|
13
|
-
.. image:: http://
|
|
14
|
-
:width:
|
|
15
|
-
:height:
|
|
13
|
+
.. image:: http://farm3.static.flickr.com/2738/4511827859_b5822043b7_o_d.png
|
|
14
|
+
:width: 800
|
|
15
|
+
:height: 400
|
|
16
16
|
|
|
17
17
|
Shapely is a BSD-licensed Python package for manipulation and analysis of
|
|
18
18
|
planar geometries. It is not concerned with data formats or coordinate
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Shapely
|
|
3
3
|
=======
|
|
4
4
|
|
|
5
|
-
.. image:: http://
|
|
6
|
-
:width:
|
|
7
|
-
:height:
|
|
5
|
+
.. image:: http://farm3.static.flickr.com/2738/4511827859_b5822043b7_o_d.png
|
|
6
|
+
:width: 800
|
|
7
|
+
:height: 400
|
|
8
8
|
|
|
9
9
|
Shapely is a BSD-licensed Python package for manipulation and analysis of
|
|
10
10
|
planar geometries. It is not concerned with data formats or coordinate
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 1.0
|
|
2
2
|
Name: Shapely
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2b7
|
|
4
4
|
Summary: Planar geometries, predicates, and operations
|
|
5
5
|
Home-page: http://trac.gispython.org/lab/wiki/Shapely
|
|
6
6
|
Author: Sean Gillies
|
|
@@ -10,9 +10,9 @@ Description:
|
|
|
10
10
|
Shapely
|
|
11
11
|
=======
|
|
12
12
|
|
|
13
|
-
.. image:: http://
|
|
14
|
-
:width:
|
|
15
|
-
:height:
|
|
13
|
+
.. image:: http://farm3.static.flickr.com/2738/4511827859_b5822043b7_o_d.png
|
|
14
|
+
:width: 800
|
|
15
|
+
:height: 400
|
|
16
16
|
|
|
17
17
|
Shapely is a BSD-licensed Python package for manipulation and analysis of
|
|
18
18
|
planar geometries. It is not concerned with data formats or coordinate
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# dissolve.py
|
|
2
|
+
#
|
|
3
|
+
# Demonstrate how Shapely can be used to build up a collection of patches by
|
|
4
|
+
# dissolving circular regions and how Shapely supports plotting of the results.
|
|
5
|
+
|
|
6
|
+
from functools import partial
|
|
7
|
+
import random
|
|
8
|
+
|
|
9
|
+
import pylab
|
|
10
|
+
|
|
11
|
+
from shapely.geometry import Point
|
|
12
|
+
from shapely.ops import cascaded_union
|
|
13
|
+
|
|
14
|
+
# Use a partial function to make 100 points uniformly distributed in a 40x40
|
|
15
|
+
# box centered on 0,0.
|
|
16
|
+
r = partial(random.uniform, -20.0, 20.0)
|
|
17
|
+
points = [Point(r(), r()) for i in range(100)]
|
|
18
|
+
|
|
19
|
+
# Buffer the points, producing 100 polygon spots
|
|
20
|
+
spots = [p.buffer(2.5) for p in points]
|
|
21
|
+
|
|
22
|
+
# Perform a cascaded union of the polygon spots, dissolving them into a
|
|
23
|
+
# collection of polygon patches
|
|
24
|
+
patches = cascaded_union(spots)
|
|
25
|
+
|
|
26
|
+
if __name__ == "__main__":
|
|
27
|
+
# Illustrate the results using matplotlib's pylab interface
|
|
28
|
+
pylab.figure(num=None, figsize=(4, 4), dpi=180)
|
|
29
|
+
|
|
30
|
+
for patch in patches.geoms:
|
|
31
|
+
assert patch.geom_type in ['Polygon']
|
|
32
|
+
assert patch.is_valid
|
|
33
|
+
|
|
34
|
+
# Fill and outline each patch
|
|
35
|
+
x, y = patch.exterior.xy
|
|
36
|
+
pylab.fill(x, y, color='#cccccc', aa=True)
|
|
37
|
+
pylab.plot(x, y, color='#666666', aa=True, lw=1.0)
|
|
38
|
+
|
|
39
|
+
# Do the same for the holes of the patch
|
|
40
|
+
for hole in patch.interiors:
|
|
41
|
+
x, y = hole.xy
|
|
42
|
+
pylab.fill(x, y, color='#ffffff', aa=True)
|
|
43
|
+
pylab.plot(x, y, color='#999999', aa=True, lw=1.0)
|
|
44
|
+
|
|
45
|
+
# Plot the original points
|
|
46
|
+
pylab.plot([p.x for p in points], [p.y for p in points], 'b,', alpha=0.75)
|
|
47
|
+
|
|
48
|
+
# Write the number of patches and the total patch area to the figure
|
|
49
|
+
pylab.text(-25, 25,
|
|
50
|
+
"Patches: %d, total area: %.2f" % (len(patches.geoms), patches.area))
|
|
51
|
+
|
|
52
|
+
pylab.savefig('dissolve.png')
|
|
53
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# intersect.py
|
|
2
|
+
#
|
|
3
|
+
# Demonstrate how Shapely can be used to analyze and plot the intersection of
|
|
4
|
+
# a trajectory and regions in space.
|
|
5
|
+
|
|
6
|
+
from functools import partial
|
|
7
|
+
import random
|
|
8
|
+
|
|
9
|
+
import pylab
|
|
10
|
+
|
|
11
|
+
from shapely.geometry import LineString, Point
|
|
12
|
+
from shapely.ops import cascaded_union
|
|
13
|
+
|
|
14
|
+
# Build patches as in dissolved.py
|
|
15
|
+
r = partial(random.uniform, -20.0, 20.0)
|
|
16
|
+
points = [Point(r(), r()) for i in range(100)]
|
|
17
|
+
spots = [p.buffer(2.5) for p in points]
|
|
18
|
+
patches = cascaded_union(spots)
|
|
19
|
+
|
|
20
|
+
# Represent the following geolocation parameters
|
|
21
|
+
#
|
|
22
|
+
# initial position: -25, -25
|
|
23
|
+
# heading: 45.0
|
|
24
|
+
# speed: 50*sqrt(2)
|
|
25
|
+
#
|
|
26
|
+
# as a line
|
|
27
|
+
vector = LineString(((-25.0, -25.0), (25.0, 25.0)))
|
|
28
|
+
|
|
29
|
+
# Find intercepted and missed patches. List the former so we can count them
|
|
30
|
+
# later
|
|
31
|
+
intercepts = [patch for patch in patches.geoms if vector.intersects(patch)]
|
|
32
|
+
misses = (patch for patch in patches.geoms if not vector.intersects(patch))
|
|
33
|
+
|
|
34
|
+
# Plot the intersection
|
|
35
|
+
intersection = vector.intersection(patches)
|
|
36
|
+
assert intersection.geom_type in ['MultiLineString']
|
|
37
|
+
|
|
38
|
+
if __name__ == "__main__":
|
|
39
|
+
# Illustrate the results using matplotlib's pylab interface
|
|
40
|
+
pylab.figure(num=None, figsize=(4, 4), dpi=180)
|
|
41
|
+
|
|
42
|
+
# Plot the misses
|
|
43
|
+
for spot in misses:
|
|
44
|
+
x, y = spot.exterior.xy
|
|
45
|
+
pylab.fill(x, y, color='#cccccc', aa=True)
|
|
46
|
+
pylab.plot(x, y, color='#999999', aa=True, lw=1.0)
|
|
47
|
+
|
|
48
|
+
# Do the same for the holes of the patch
|
|
49
|
+
for hole in spot.interiors:
|
|
50
|
+
x, y = hole.xy
|
|
51
|
+
pylab.fill(x, y, color='#ffffff', aa=True)
|
|
52
|
+
pylab.plot(x, y, color='#999999', aa=True, lw=1.0)
|
|
53
|
+
|
|
54
|
+
# Plot the intercepts
|
|
55
|
+
for spot in intercepts:
|
|
56
|
+
x, y = spot.exterior.xy
|
|
57
|
+
pylab.fill(x, y, color='red', alpha=0.25, aa=True)
|
|
58
|
+
pylab.plot(x, y, color='red', alpha=0.5, aa=True, lw=1.0)
|
|
59
|
+
|
|
60
|
+
# Do the same for the holes of the patch
|
|
61
|
+
for hole in spot.interiors:
|
|
62
|
+
x, y = hole.xy
|
|
63
|
+
pylab.fill(x, y, color='#ffffff', aa=True)
|
|
64
|
+
pylab.plot(x, y, color='red', alpha=0.5, aa=True, lw=1.0)
|
|
65
|
+
|
|
66
|
+
# Draw the projected trajectory
|
|
67
|
+
pylab.arrow(-25, -25, 50, 50, color='#999999', aa=True,
|
|
68
|
+
head_width=1.0, head_length=1.0)
|
|
69
|
+
|
|
70
|
+
for segment in intersection.geoms:
|
|
71
|
+
x, y = segment.xy
|
|
72
|
+
pylab.plot(x, y, color='red', aa=True, lw=1.5)
|
|
73
|
+
|
|
74
|
+
# Write the number of patches and the total patch area to the figure
|
|
75
|
+
pylab.text(-28, 25,
|
|
76
|
+
"Patches: %d/%d (%d), total length: %.1f" \
|
|
77
|
+
% (len(intercepts), len(patches.geoms),
|
|
78
|
+
len(intersection.geoms), intersection.length))
|
|
79
|
+
|
|
80
|
+
pylab.savefig('intersect.png')
|
|
81
|
+
|
|
@@ -16,7 +16,7 @@ readme_text = file('README.txt', 'rb').read()
|
|
|
16
16
|
setup_args = dict(
|
|
17
17
|
metadata_version = '1.2',
|
|
18
18
|
name = 'Shapely',
|
|
19
|
-
version = '1.
|
|
19
|
+
version = '1.2b7',
|
|
20
20
|
requires_python = '>=2.5,<3',
|
|
21
21
|
requires_external = 'libgeos_c (>=3.1)',
|
|
22
22
|
description = 'Planar geometries, predicates, and operations',
|
|
@@ -53,6 +53,7 @@ def exceptNull(func):
|
|
|
53
53
|
return func(*args, **kwargs)
|
|
54
54
|
return wrapper
|
|
55
55
|
|
|
56
|
+
EMPTY = wkb.deserialize('010700000000000000'.decode('hex'))
|
|
56
57
|
|
|
57
58
|
class BaseGeometry(object):
|
|
58
59
|
"""
|
|
@@ -78,7 +79,7 @@ class BaseGeometry(object):
|
|
|
78
79
|
# _owned : bool
|
|
79
80
|
# True if this object's GEOS geometry is owned by another as in the case
|
|
80
81
|
# of a multipart geometry member.
|
|
81
|
-
__geom__ =
|
|
82
|
+
__geom__ = EMPTY
|
|
82
83
|
__p__ = None
|
|
83
84
|
_ctypes_data = None
|
|
84
85
|
_ndim = None
|
|
@@ -88,13 +89,18 @@ class BaseGeometry(object):
|
|
|
88
89
|
# Backend config
|
|
89
90
|
impl = DefaultImplementation
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
@property
|
|
93
|
+
def _is_empty(self):
|
|
94
|
+
return self.__geom__ in [EMPTY, None]
|
|
93
95
|
|
|
94
|
-
def
|
|
95
|
-
if self.
|
|
96
|
+
def empty(self):
|
|
97
|
+
if not (self._owned or self._is_empty):
|
|
96
98
|
from shapely.geos import lgeos
|
|
97
99
|
lgeos.GEOSGeom_destroy(self.__geom__)
|
|
100
|
+
self.__geom__ = EMPTY
|
|
101
|
+
|
|
102
|
+
def __del__(self):
|
|
103
|
+
self.empty()
|
|
98
104
|
self.__geom__ = None
|
|
99
105
|
self.__p__ = None
|
|
100
106
|
|
|
@@ -106,12 +112,14 @@ class BaseGeometry(object):
|
|
|
106
112
|
return (self.__class__, (), self.to_wkb())
|
|
107
113
|
|
|
108
114
|
def __setstate__(self, state):
|
|
115
|
+
self.empty()
|
|
109
116
|
self.__geom__ = wkb.deserialize(state)
|
|
110
117
|
|
|
111
118
|
# The _geom property
|
|
112
119
|
def _get_geom(self):
|
|
113
120
|
return self.__geom__
|
|
114
121
|
def _set_geom(self, val):
|
|
122
|
+
self.empty()
|
|
115
123
|
self.__geom__ = val
|
|
116
124
|
_geom = property(_get_geom, _set_geom)
|
|
117
125
|
|
|
@@ -320,7 +328,7 @@ class BaseGeometry(object):
|
|
|
320
328
|
@property
|
|
321
329
|
def is_empty(self):
|
|
322
330
|
"""True if the set of points in this geometry is empty, else False"""
|
|
323
|
-
return bool(self.impl['is_empty'](self))
|
|
331
|
+
return bool(self.impl['is_empty'](self)) or (self._geom is None)
|
|
324
332
|
|
|
325
333
|
@property
|
|
326
334
|
def is_ring(self):
|
|
@@ -460,6 +468,18 @@ class BaseMultipartGeometry(BaseGeometry):
|
|
|
460
468
|
else:
|
|
461
469
|
return iter([])
|
|
462
470
|
|
|
471
|
+
def __len__(self):
|
|
472
|
+
if not self.is_empty:
|
|
473
|
+
return len(self.geoms)
|
|
474
|
+
else:
|
|
475
|
+
return 0
|
|
476
|
+
|
|
477
|
+
def __getitem__(self, index):
|
|
478
|
+
if not self.is_empty:
|
|
479
|
+
return self.geoms[index]
|
|
480
|
+
else:
|
|
481
|
+
return ()[index]
|
|
482
|
+
|
|
463
483
|
|
|
464
484
|
class GeometrySequence(object):
|
|
465
485
|
"""
|
|
@@ -37,14 +37,8 @@ class LineString(BaseGeometry):
|
|
|
37
37
|
2.0
|
|
38
38
|
"""
|
|
39
39
|
BaseGeometry.__init__(self)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def _init_geom(self, coordinates):
|
|
43
|
-
if coordinates is None:
|
|
44
|
-
# allow creation of null lines, to support unpickling
|
|
45
|
-
pass
|
|
46
|
-
else:
|
|
47
|
-
self._geom, self._ndim = geos_linestring_from_py(coordinates)
|
|
40
|
+
if coordinates is not None:
|
|
41
|
+
self._set_coords(coordinates)
|
|
48
42
|
|
|
49
43
|
@property
|
|
50
44
|
def __geo_interface__(self):
|
|
@@ -66,14 +60,9 @@ class LineString(BaseGeometry):
|
|
|
66
60
|
__array_interface__ = property(array_interface)
|
|
67
61
|
|
|
68
62
|
# Coordinate access
|
|
69
|
-
|
|
70
63
|
def _set_coords(self, coordinates):
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
self.__geom__ = None
|
|
74
|
-
if self._geom is None:
|
|
75
|
-
self._init_geom(coordinates)
|
|
76
|
-
update_linestring_from_py(self, coordinates)
|
|
64
|
+
self.empty()
|
|
65
|
+
self._geom, self._ndim = geos_linestring_from_py(coordinates)
|
|
77
66
|
|
|
78
67
|
coords = property(BaseGeometry._get_coords, _set_coords)
|
|
79
68
|
|
|
@@ -94,9 +83,6 @@ class LineString(BaseGeometry):
|
|
|
94
83
|
|
|
95
84
|
class LineStringAdapter(CachingGeometryProxy, LineString):
|
|
96
85
|
|
|
97
|
-
context = None
|
|
98
|
-
_owned = False
|
|
99
|
-
|
|
100
86
|
def __init__(self, context):
|
|
101
87
|
self.context = context
|
|
102
88
|
self.factory = geos_linestring_from_py
|
|
@@ -45,17 +45,8 @@ class Point(BaseGeometry):
|
|
|
45
45
|
Easting, northing, and elevation.
|
|
46
46
|
"""
|
|
47
47
|
BaseGeometry.__init__(self)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def _init_geom(self, *args):
|
|
51
|
-
if len(args) == 0:
|
|
52
|
-
# allow creation of null points, to support unpickling
|
|
53
|
-
pass
|
|
54
|
-
else:
|
|
55
|
-
if len(args) == 1:
|
|
56
|
-
self._geom, self._ndim = geos_point_from_py(args[0])
|
|
57
|
-
else:
|
|
58
|
-
self._geom, self._ndim = geos_point_from_py(tuple(args))
|
|
48
|
+
if len(args) > 0:
|
|
49
|
+
self._set_coords(*args)
|
|
59
50
|
|
|
60
51
|
# Coordinate getters and setters
|
|
61
52
|
|
|
@@ -110,14 +101,12 @@ class Point(BaseGeometry):
|
|
|
110
101
|
|
|
111
102
|
# Coordinate access
|
|
112
103
|
|
|
113
|
-
def _set_coords(self,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
self.
|
|
117
|
-
if self._geom is None:
|
|
118
|
-
self._init_geom(coordinates)
|
|
104
|
+
def _set_coords(self, *args):
|
|
105
|
+
self.empty()
|
|
106
|
+
if len(args) == 1:
|
|
107
|
+
self._geom, self._ndim = geos_point_from_py(args[0])
|
|
119
108
|
else:
|
|
120
|
-
|
|
109
|
+
self._geom, self._ndim = geos_point_from_py(tuple(args))
|
|
121
110
|
|
|
122
111
|
coords = property(BaseGeometry._get_coords, _set_coords)
|
|
123
112
|
|
|
@@ -20,11 +20,6 @@ class LinearRing(LineString):
|
|
|
20
20
|
invalid and operations on it may fail.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
|
-
_ndim = None
|
|
24
|
-
__geom__ = None
|
|
25
|
-
__p__ = None
|
|
26
|
-
_owned = False
|
|
27
|
-
|
|
28
23
|
def __init__(self, coordinates=None):
|
|
29
24
|
"""
|
|
30
25
|
Parameters
|
|
@@ -46,14 +41,8 @@ class LinearRing(LineString):
|
|
|
46
41
|
4.0
|
|
47
42
|
"""
|
|
48
43
|
BaseGeometry.__init__(self)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def _init_geom(self, coordinates):
|
|
52
|
-
if coordinates is None:
|
|
53
|
-
# allow creation of null lines, to support unpickling
|
|
54
|
-
pass
|
|
55
|
-
else:
|
|
56
|
-
self._geom, self._ndim = geos_linearring_from_py(coordinates)
|
|
44
|
+
if coordinates is not None:
|
|
45
|
+
self._set_coords(coordinates)
|
|
57
46
|
|
|
58
47
|
@property
|
|
59
48
|
def __geo_interface__(self):
|
|
@@ -67,30 +56,19 @@ class LinearRing(LineString):
|
|
|
67
56
|
_get_coords = BaseGeometry._get_coords
|
|
68
57
|
|
|
69
58
|
def _set_coords(self, coordinates):
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
self.__geom__ = None
|
|
73
|
-
if self._geom is None:
|
|
74
|
-
self._init_geom(coordinates)
|
|
75
|
-
update_linearring_from_py(self, coordinates)
|
|
59
|
+
self.empty()
|
|
60
|
+
self._geom, self._ndim = geos_linearring_from_py(coordinates)
|
|
76
61
|
|
|
77
62
|
coords = property(_get_coords, _set_coords)
|
|
78
63
|
|
|
79
64
|
|
|
80
65
|
class LinearRingAdapter(LineStringAdapter):
|
|
81
66
|
|
|
82
|
-
context = None
|
|
83
|
-
__geom__ = None
|
|
84
67
|
__p__ = None
|
|
85
|
-
_owned = False
|
|
86
68
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if self.__geom__ is not None:
|
|
91
|
-
lgeos.GEOSGeom_destroy(self.__geom)
|
|
92
|
-
self.__geom, n = geos_linearring_from_py(self.context)
|
|
93
|
-
return self.__geom
|
|
69
|
+
def __init__(self, context):
|
|
70
|
+
self.context = context
|
|
71
|
+
self.factory = geos_linearring_from_py
|
|
94
72
|
|
|
95
73
|
@property
|
|
96
74
|
def __geo_interface__(self):
|
|
@@ -194,8 +172,6 @@ class Polygon(BaseGeometry):
|
|
|
194
172
|
_exterior = None
|
|
195
173
|
_interiors = []
|
|
196
174
|
_ndim = 2
|
|
197
|
-
__geom__ = None
|
|
198
|
-
_owned = False
|
|
199
175
|
|
|
200
176
|
def __init__(self, shell=None, holes=None):
|
|
201
177
|
"""
|
|
@@ -276,10 +252,6 @@ class Polygon(BaseGeometry):
|
|
|
276
252
|
|
|
277
253
|
class PolygonAdapter(PolygonProxy, Polygon):
|
|
278
254
|
|
|
279
|
-
context = None
|
|
280
|
-
__geom__ = None
|
|
281
|
-
_owned = False
|
|
282
|
-
|
|
283
255
|
def __init__(self, shell, holes=None):
|
|
284
256
|
self.shell = shell
|
|
285
257
|
self.holes = holes
|
|
@@ -2,27 +2,37 @@
|
|
|
2
2
|
"""
|
|
3
3
|
|
|
4
4
|
from shapely.geos import lgeos
|
|
5
|
+
from shapely import wkb
|
|
6
|
+
|
|
7
|
+
EMPTY = wkb.deserialize('010700000000000000'.decode('hex'))
|
|
5
8
|
|
|
6
9
|
|
|
7
10
|
class CachingGeometryProxy(object):
|
|
8
11
|
|
|
9
12
|
context = None
|
|
10
13
|
factory = None
|
|
11
|
-
__geom__ =
|
|
14
|
+
__geom__ = EMPTY
|
|
12
15
|
_gtag = None
|
|
13
16
|
|
|
14
17
|
def __init__(self, context):
|
|
15
18
|
self.context = context
|
|
16
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
|
+
|
|
17
30
|
@property
|
|
18
31
|
def _geom(self):
|
|
19
32
|
"""Keeps the GEOS geometry in synch with the context."""
|
|
20
33
|
gtag = self.gtag()
|
|
21
|
-
if gtag != self._gtag:
|
|
22
|
-
|
|
23
|
-
lgeos.GEOSGeom_destroy(self.__geom__)
|
|
24
|
-
self.__geom__, n = self.factory(self.context)
|
|
25
|
-
elif self.__geom__ is None:
|
|
34
|
+
if gtag != self._gtag or self._is_empty:
|
|
35
|
+
self.empty()
|
|
26
36
|
self.__geom__, n = self.factory(self.context)
|
|
27
37
|
self._gtag = gtag
|
|
28
38
|
return self.__geom__
|
|
@@ -37,11 +47,8 @@ class PolygonProxy(CachingGeometryProxy):
|
|
|
37
47
|
def _geom(self):
|
|
38
48
|
"""Keeps the GEOS geometry in synch with the context."""
|
|
39
49
|
gtag = self.gtag()
|
|
40
|
-
if gtag != self._gtag:
|
|
41
|
-
|
|
42
|
-
lgeos.GEOSGeom_destroy(self.__geom__)
|
|
43
|
-
self.__geom__, n = self.factory(self.context[0], self.context[1])
|
|
44
|
-
elif self.__geom__ is None:
|
|
50
|
+
if gtag != self._gtag or self._is_empty:
|
|
51
|
+
self.empty()
|
|
45
52
|
self.__geom__, n = self.factory(self.context[0], self.context[1])
|
|
46
53
|
self._gtag = gtag
|
|
47
54
|
return self.__geom__
|
|
@@ -136,6 +136,7 @@ if geos_c_version >= (1,5,0):
|
|
|
136
136
|
# Handle special case.
|
|
137
137
|
_lgeos.initGEOS_r.restype = c_void_p
|
|
138
138
|
_lgeos.initGEOS_r.argtypes = [c_void_p, c_void_p]
|
|
139
|
+
_lgeos.finishGEOS_r.argtypes = [c_void_p]
|
|
139
140
|
|
|
140
141
|
# Exceptions
|
|
141
142
|
|
|
@@ -160,7 +161,7 @@ def notice_handler(fmt, list):
|
|
|
160
161
|
notice_h = CFUNCTYPE(None, c_char_p, c_char_p)(notice_handler)
|
|
161
162
|
|
|
162
163
|
def cleanup():
|
|
163
|
-
if _lgeos is not None:
|
|
164
|
+
if _lgeos is not None :
|
|
164
165
|
_lgeos.finishGEOS()
|
|
165
166
|
|
|
166
167
|
atexit.register(cleanup)
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
from unittest import TestSuite
|
|
2
2
|
|
|
3
3
|
import test_doctests, test_prepared, test_equality, test_geomseq, test_xy
|
|
4
|
+
import test_collection, test_emptiness
|
|
4
5
|
|
|
5
6
|
def test_suite():
|
|
6
7
|
suite = TestSuite()
|
|
7
8
|
suite.addTest(test_doctests.test_suite())
|
|
8
9
|
suite.addTest(test_prepared.test_suite())
|
|
10
|
+
suite.addTest(test_emptiness.test_suite())
|
|
9
11
|
suite.addTest(test_equality.test_suite())
|
|
10
12
|
suite.addTest(test_geomseq.test_suite())
|
|
11
13
|
suite.addTest(test_xy.test_suite())
|
|
14
|
+
suite.addTest(test_collection.test_suite())
|
|
12
15
|
return suite
|
|
13
16
|
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# dissolve.py
|
|
2
|
-
#
|
|
3
|
-
# Demonstrate how Shapely can be used to build up a collection of patches by
|
|
4
|
-
# dissolving circular regions and how Shapely supports plotting of the results.
|
|
5
|
-
|
|
6
|
-
from functools import partial
|
|
7
|
-
import random
|
|
8
|
-
|
|
9
|
-
import pylab
|
|
10
|
-
|
|
11
|
-
from shapely.geometry import Point
|
|
12
|
-
from shapely.ops import cascaded_union
|
|
13
|
-
|
|
14
|
-
# Use a partial function to make 100 points uniformly distributed in a 40x40
|
|
15
|
-
# box centered on 0,0.
|
|
16
|
-
r = partial(random.uniform, -20.0, 20.0)
|
|
17
|
-
points = [Point(r(), r()) for i in range(100)]
|
|
18
|
-
|
|
19
|
-
# Buffer the points, producing 100 polygon spots
|
|
20
|
-
spots = [p.buffer(2.5) for p in points]
|
|
21
|
-
|
|
22
|
-
# Perform a cascaded union of the polygon spots, dissolving them into a
|
|
23
|
-
# collection of polygon patches
|
|
24
|
-
patches = cascaded_union(spots)
|
|
25
|
-
|
|
26
|
-
# Illustrate the results using matplotlib's pylab interface
|
|
27
|
-
pylab.figure(num=None, figsize=(4, 4), dpi=180)
|
|
28
|
-
|
|
29
|
-
for patch in patches.geoms:
|
|
30
|
-
assert patch.geom_type in ['Polygon']
|
|
31
|
-
assert patch.is_valid
|
|
32
|
-
|
|
33
|
-
# Fill and outline each patch
|
|
34
|
-
x, y = patch.exterior.xy
|
|
35
|
-
pylab.fill(x, y, color='#cccccc', aa=True)
|
|
36
|
-
pylab.plot(x, y, color='#666666', aa=True, lw=1.0)
|
|
37
|
-
|
|
38
|
-
# Do the same for the holes of the patch
|
|
39
|
-
for hole in patch.interiors:
|
|
40
|
-
x, y = hole.xy
|
|
41
|
-
pylab.fill(x, y, color='#ffffff', aa=True)
|
|
42
|
-
pylab.plot(x, y, color='#999999', aa=True, lw=1.0)
|
|
43
|
-
|
|
44
|
-
# Plot the original points
|
|
45
|
-
pylab.plot([p.x for p in points], [p.y for p in points], 'b,', alpha=0.75)
|
|
46
|
-
|
|
47
|
-
# Write the number of patches and the total patch area to the figure
|
|
48
|
-
pylab.text(-25, 25,
|
|
49
|
-
"Patches: %d, total area: %.2f" % (len(patches.geoms), patches.area))
|
|
50
|
-
|
|
51
|
-
pylab.savefig('dissolve.png')
|
|
52
|
-
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
# intersect.py
|
|
2
|
-
#
|
|
3
|
-
# Demonstrate how Shapely can be used to analyze and plot the intersection of
|
|
4
|
-
# a trajectory and regions in space.
|
|
5
|
-
|
|
6
|
-
from functools import partial
|
|
7
|
-
import random
|
|
8
|
-
|
|
9
|
-
import pylab
|
|
10
|
-
|
|
11
|
-
from shapely.geometry import LineString, Point
|
|
12
|
-
from shapely.ops import cascaded_union
|
|
13
|
-
|
|
14
|
-
# Build patches as in dissolved.py
|
|
15
|
-
r = partial(random.uniform, -20.0, 20.0)
|
|
16
|
-
points = [Point(r(), r()) for i in range(100)]
|
|
17
|
-
spots = [p.buffer(2.5) for p in points]
|
|
18
|
-
patches = cascaded_union(spots)
|
|
19
|
-
|
|
20
|
-
# Represent the following geolocation parameters
|
|
21
|
-
#
|
|
22
|
-
# initial position: -25, -25
|
|
23
|
-
# heading: 45.0
|
|
24
|
-
# speed: 50*sqrt(2)
|
|
25
|
-
#
|
|
26
|
-
# as a line
|
|
27
|
-
vector = LineString(((-25.0, -25.0), (25.0, 25.0)))
|
|
28
|
-
|
|
29
|
-
# Find intercepted and missed patches. List the former so we can count them
|
|
30
|
-
# later
|
|
31
|
-
intercepts = [patch for patch in patches.geoms if vector.intersects(patch)]
|
|
32
|
-
misses = (patch for patch in patches.geoms if not vector.intersects(patch))
|
|
33
|
-
|
|
34
|
-
# Illustrate the results using matplotlib's pylab interface
|
|
35
|
-
pylab.figure(num=None, figsize=(4, 4), dpi=180)
|
|
36
|
-
|
|
37
|
-
# Plot the misses
|
|
38
|
-
for spot in misses:
|
|
39
|
-
x, y = spot.exterior.xy
|
|
40
|
-
pylab.fill(x, y, color='#cccccc', aa=True)
|
|
41
|
-
pylab.plot(x, y, color='#999999', aa=True, lw=1.0)
|
|
42
|
-
|
|
43
|
-
# Do the same for the holes of the patch
|
|
44
|
-
for hole in spot.interiors:
|
|
45
|
-
x, y = hole.xy
|
|
46
|
-
pylab.fill(x, y, color='#ffffff', aa=True)
|
|
47
|
-
pylab.plot(x, y, color='#999999', aa=True, lw=1.0)
|
|
48
|
-
|
|
49
|
-
# Plot the intercepts
|
|
50
|
-
for spot in intercepts:
|
|
51
|
-
x, y = spot.exterior.xy
|
|
52
|
-
pylab.fill(x, y, color='red', alpha=0.25, aa=True)
|
|
53
|
-
pylab.plot(x, y, color='red', alpha=0.5, aa=True, lw=1.0)
|
|
54
|
-
|
|
55
|
-
# Do the same for the holes of the patch
|
|
56
|
-
for hole in spot.interiors:
|
|
57
|
-
x, y = hole.xy
|
|
58
|
-
pylab.fill(x, y, color='#ffffff', aa=True)
|
|
59
|
-
pylab.plot(x, y, color='red', alpha=0.5, aa=True, lw=1.0)
|
|
60
|
-
|
|
61
|
-
# Draw the projected trajectory
|
|
62
|
-
pylab.arrow(-25, -25, 50, 50, color='#999999', aa=True,
|
|
63
|
-
head_width=1.0, head_length=1.0)
|
|
64
|
-
|
|
65
|
-
# Plot the intersection
|
|
66
|
-
intersection = vector.intersection(patches)
|
|
67
|
-
assert intersection.geom_type in ['MultiLineString']
|
|
68
|
-
|
|
69
|
-
for segment in intersection.geoms:
|
|
70
|
-
x, y = segment.xy
|
|
71
|
-
pylab.plot(x, y, color='red', aa=True, lw=1.5)
|
|
72
|
-
|
|
73
|
-
# Write the number of patches and the total patch area to the figure
|
|
74
|
-
pylab.text(-28, 25,
|
|
75
|
-
"Patches: %d/%d (%d), total length: %.1f" \
|
|
76
|
-
% (len(intercepts), len(patches.geoms),
|
|
77
|
-
len(intersection.geoms), intersection.length))
|
|
78
|
-
|
|
79
|
-
pylab.savefig('intersect.png')
|
|
80
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|