shapely 1.2b4__tar.gz → 1.2b6__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.2b4 → Shapely-1.2b6}/CHANGES.txt +16 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/PKG-INFO +4 -4
- {Shapely-1.2b4 → Shapely-1.2b6}/README.txt +3 -3
- {Shapely-1.2b4 → Shapely-1.2b6}/Shapely.egg-info/PKG-INFO +4 -4
- Shapely-1.2b6/examples/dissolve.py +53 -0
- Shapely-1.2b6/examples/intersect.py +81 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/setup.py +1 -1
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/base.py +27 -6
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/collection.py +1 -1
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/linestring.py +108 -120
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/multilinestring.py +54 -60
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/multipoint.py +57 -57
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/multipolygon.py +48 -43
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/point.py +81 -76
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/polygon.py +178 -180
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/LineString.txt +10 -6
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/MultiLineString.txt +18 -1
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/MultiPoint.txt +17 -1
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/MultiPolygon.txt +17 -1
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/Point.txt +10 -10
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/Polygon.txt +3 -7
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/__init__.py +2 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/test_geomseq.py +2 -5
- Shapely-1.2b4/examples/dissolve.py +0 -52
- Shapely-1.2b4/examples/intersect.py +0 -80
- {Shapely-1.2b4 → Shapely-1.2b6}/CREDITS.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/LICENSE.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/MANIFEST.in +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/Shapely.egg-info/SOURCES.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/Shapely.egg-info/dependency_links.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/Shapely.egg-info/top_level.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/setup.cfg +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/__init__.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/coords.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/ctypes_declarations.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/__init__.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/geo.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/proxy.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geoms.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geos.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/impl.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/iterops.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/linref.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/ops.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/predicates.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/prepared.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/Array.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/GeoInterface.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/IterOps.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/Operations.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/Persist.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/Predicates.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/attribute-chains.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/binascii_hex.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/dimensions.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/invalid_intersection.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/linear-referencing.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/linemerge.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/polygonize.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/test_doctests.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/test_equality.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/test_prepared.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/test_xy.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/threading_test.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/wkt_locale.txt +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/topology.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/wkb.py +0 -0
- {Shapely-1.2b4 → Shapely-1.2b6}/shapely/wkt.py +0 -0
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
All tickets are children of http://trac.gispython.org/lab/ticket.
|
|
2
2
|
|
|
3
|
+
1.2b6 (2010-04-13)
|
|
4
|
+
------------------
|
|
5
|
+
- Broken GeometryCollection fixed.
|
|
6
|
+
|
|
7
|
+
1.2b5 (2010-04-09)
|
|
8
|
+
------------------
|
|
9
|
+
- Objects can be constructed from others of the same type, thereby making
|
|
10
|
+
copies. Collections can be constructed from sequences of objects, also making
|
|
11
|
+
copies.
|
|
12
|
+
- Collections are now iterators over their component objects.
|
|
13
|
+
- New code for manual figures, using the descartes package.
|
|
14
|
+
|
|
15
|
+
1.2b4 (2010-03-19)
|
|
16
|
+
------------------
|
|
17
|
+
- Adds support for the "sunos5" platform.
|
|
18
|
+
|
|
3
19
|
1.2b3 (2010-02-28)
|
|
4
20
|
------------------
|
|
5
21
|
- Only provide simplification implementations for GEOS C API >= 1.5.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 1.0
|
|
2
2
|
Name: Shapely
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2b6
|
|
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.2b6
|
|
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.2b6',
|
|
20
20
|
requires_python = '>=2.5,<3',
|
|
21
21
|
requires_external = 'libgeos_c (>=3.1)',
|
|
22
22
|
description = 'Planar geometries, predicates, and operations',
|
|
@@ -48,8 +48,8 @@ def exceptNull(func):
|
|
|
48
48
|
"""Decorator which helps avoid GEOS operations on null pointers."""
|
|
49
49
|
@wraps(func)
|
|
50
50
|
def wrapper(*args, **kwargs):
|
|
51
|
-
if not args[0]._geom:
|
|
52
|
-
raise ValueError("Null geometry supports no operations")
|
|
51
|
+
if not args[0]._geom or args[0].is_empty:
|
|
52
|
+
raise ValueError("Null/empty geometry supports no operations")
|
|
53
53
|
return func(*args, **kwargs)
|
|
54
54
|
return wrapper
|
|
55
55
|
|
|
@@ -84,12 +84,12 @@ class BaseGeometry(object):
|
|
|
84
84
|
_ndim = None
|
|
85
85
|
_crs = None
|
|
86
86
|
_owned = False
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
# Backend config
|
|
89
89
|
impl = DefaultImplementation
|
|
90
90
|
|
|
91
91
|
def __init__(self):
|
|
92
|
-
self.__geom__ =
|
|
92
|
+
self.__geom__ = wkb.deserialize('010700000000000000'.decode('hex'))
|
|
93
93
|
|
|
94
94
|
def __del__(self):
|
|
95
95
|
if self.__geom__ is not None and not self._owned:
|
|
@@ -227,8 +227,11 @@ class BaseGeometry(object):
|
|
|
227
227
|
@property
|
|
228
228
|
def bounds(self):
|
|
229
229
|
"""Returns minimum bounding region (minx, miny, maxx, maxy)"""
|
|
230
|
-
|
|
231
|
-
|
|
230
|
+
if self.is_empty:
|
|
231
|
+
return ()
|
|
232
|
+
else:
|
|
233
|
+
return self.impl['bounds'](self)
|
|
234
|
+
|
|
232
235
|
@property
|
|
233
236
|
def centroid(self):
|
|
234
237
|
"""Returns the geometric center of the polygon"""
|
|
@@ -451,6 +454,24 @@ class BaseMultipartGeometry(BaseGeometry):
|
|
|
451
454
|
def geoms(self):
|
|
452
455
|
return GeometrySequence(self, self.shape_factory)
|
|
453
456
|
|
|
457
|
+
def __iter__(self):
|
|
458
|
+
if not self.is_empty:
|
|
459
|
+
return iter(self.geoms)
|
|
460
|
+
else:
|
|
461
|
+
return iter([])
|
|
462
|
+
|
|
463
|
+
def __len__(self):
|
|
464
|
+
if not self.is_empty:
|
|
465
|
+
return len(self.geoms)
|
|
466
|
+
else:
|
|
467
|
+
return 0
|
|
468
|
+
|
|
469
|
+
def __getitem__(self, index):
|
|
470
|
+
if not self.is_empty:
|
|
471
|
+
return self.geoms[index]
|
|
472
|
+
else:
|
|
473
|
+
return ()[index]
|
|
474
|
+
|
|
454
475
|
|
|
455
476
|
class GeometrySequence(object):
|
|
456
477
|
"""
|
|
@@ -11,107 +11,6 @@ from shapely.geometry.proxy import CachingGeometryProxy
|
|
|
11
11
|
__all__ = ['LineString', 'asLineString']
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
|
|
15
|
-
try:
|
|
16
|
-
# From array protocol
|
|
17
|
-
array = ob.__array_interface__
|
|
18
|
-
assert len(array['shape']) == 2
|
|
19
|
-
m = array['shape'][0]
|
|
20
|
-
if m < 2:
|
|
21
|
-
raise ValueError(
|
|
22
|
-
"LineStrings must have at least 2 coordinate tuples")
|
|
23
|
-
try:
|
|
24
|
-
n = array['shape'][1]
|
|
25
|
-
except IndexError:
|
|
26
|
-
raise ValueError(
|
|
27
|
-
"Input %s is the wrong shape for a LineString" % str(ob))
|
|
28
|
-
assert n == 2 or n == 3
|
|
29
|
-
|
|
30
|
-
# Make pointer to the coordinate array
|
|
31
|
-
try:
|
|
32
|
-
cp = cast(array['data'][0], POINTER(c_double))
|
|
33
|
-
except ArgumentError:
|
|
34
|
-
cp = array['data']
|
|
35
|
-
|
|
36
|
-
# Create a coordinate sequence
|
|
37
|
-
if update_geom is not None:
|
|
38
|
-
cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
|
|
39
|
-
if n != update_ndim:
|
|
40
|
-
raise ValueError(
|
|
41
|
-
"Wrong coordinate dimensions; this geometry has dimensions: %d" \
|
|
42
|
-
% update_ndim)
|
|
43
|
-
else:
|
|
44
|
-
cs = lgeos.GEOSCoordSeq_create(m, n)
|
|
45
|
-
|
|
46
|
-
# add to coordinate sequence
|
|
47
|
-
for i in xrange(m):
|
|
48
|
-
dx = c_double(cp[n*i])
|
|
49
|
-
dy = c_double(cp[n*i+1])
|
|
50
|
-
dz = None
|
|
51
|
-
if n == 3:
|
|
52
|
-
try:
|
|
53
|
-
dz = c_double(cp[n*i+2])
|
|
54
|
-
except IndexError:
|
|
55
|
-
raise ValueError("Inconsistent coordinate dimensionality")
|
|
56
|
-
|
|
57
|
-
# Because of a bug in the GEOS C API,
|
|
58
|
-
# always set X before Y
|
|
59
|
-
lgeos.GEOSCoordSeq_setX(cs, i, dx)
|
|
60
|
-
lgeos.GEOSCoordSeq_setY(cs, i, dy)
|
|
61
|
-
if n == 3:
|
|
62
|
-
lgeos.GEOSCoordSeq_setZ(cs, i, dz)
|
|
63
|
-
|
|
64
|
-
except AttributeError:
|
|
65
|
-
# Fall back on list
|
|
66
|
-
m = len(ob)
|
|
67
|
-
if m < 2:
|
|
68
|
-
raise ValueError(
|
|
69
|
-
"LineStrings must have at least 2 coordinate tuples")
|
|
70
|
-
try:
|
|
71
|
-
n = len(ob[0])
|
|
72
|
-
except TypeError:
|
|
73
|
-
raise ValueError(
|
|
74
|
-
"Input %s is the wrong shape for a LineString" % str(ob))
|
|
75
|
-
assert n == 2 or n == 3
|
|
76
|
-
|
|
77
|
-
# Create a coordinate sequence
|
|
78
|
-
if update_geom is not None:
|
|
79
|
-
cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
|
|
80
|
-
if n != update_ndim:
|
|
81
|
-
raise ValueError(
|
|
82
|
-
"Wrong coordinate dimensions; this geometry has dimensions: %d" \
|
|
83
|
-
% update_ndim)
|
|
84
|
-
else:
|
|
85
|
-
cs = lgeos.GEOSCoordSeq_create(m, n)
|
|
86
|
-
|
|
87
|
-
# add to coordinate sequence
|
|
88
|
-
for i in xrange(m):
|
|
89
|
-
coords = ob[i]
|
|
90
|
-
dx = c_double(coords[0])
|
|
91
|
-
dy = c_double(coords[1])
|
|
92
|
-
dz = None
|
|
93
|
-
if n == 3:
|
|
94
|
-
try:
|
|
95
|
-
dz = c_double(coords[2])
|
|
96
|
-
except IndexError:
|
|
97
|
-
raise ValueError("Inconsistent coordinate dimensionality")
|
|
98
|
-
|
|
99
|
-
# Because of a bug in the GEOS C API,
|
|
100
|
-
# always set X before Y
|
|
101
|
-
lgeos.GEOSCoordSeq_setX(cs, i, dx)
|
|
102
|
-
lgeos.GEOSCoordSeq_setY(cs, i, dy)
|
|
103
|
-
if n == 3:
|
|
104
|
-
lgeos.GEOSCoordSeq_setZ(cs, i, dz)
|
|
105
|
-
|
|
106
|
-
if update_geom is not None:
|
|
107
|
-
return None
|
|
108
|
-
else:
|
|
109
|
-
return lgeos.GEOSGeom_createLineString(cs), n
|
|
110
|
-
|
|
111
|
-
def update_linestring_from_py(geom, ob):
|
|
112
|
-
geos_linestring_from_py(ob, geom._geom, geom._ndim)
|
|
113
|
-
|
|
114
|
-
|
|
115
14
|
class LineString(BaseGeometry):
|
|
116
15
|
"""
|
|
117
16
|
A one-dimensional figure comprising one or more line segments
|
|
@@ -121,29 +20,21 @@ class LineString(BaseGeometry):
|
|
|
121
20
|
"""
|
|
122
21
|
|
|
123
22
|
def __init__(self, coordinates=None):
|
|
124
|
-
"""
|
|
125
|
-
|
|
23
|
+
"""
|
|
126
24
|
Parameters
|
|
127
25
|
----------
|
|
128
|
-
|
|
129
26
|
coordinates : sequence
|
|
130
|
-
A sequence of (x, y [,z]) numeric coordinate pairs or triples
|
|
27
|
+
A sequence of (x, y [,z]) numeric coordinate pairs or triples or
|
|
28
|
+
an object that provides the numpy array interface, including another
|
|
29
|
+
instance of LineString.
|
|
131
30
|
|
|
132
31
|
Example
|
|
133
32
|
-------
|
|
134
|
-
|
|
135
33
|
Create a line with two segments
|
|
136
34
|
|
|
137
35
|
>>> a = LineString([[0, 0], [1, 0], [1, 1]])
|
|
138
36
|
>>> a.length
|
|
139
37
|
2.0
|
|
140
|
-
|
|
141
|
-
Copy it by exploiting API symmetry
|
|
142
|
-
|
|
143
|
-
>>> b = LineString(a.coords)
|
|
144
|
-
>>> b.equals(a)
|
|
145
|
-
True
|
|
146
|
-
|
|
147
38
|
"""
|
|
148
39
|
BaseGeometry.__init__(self)
|
|
149
40
|
self._init_geom(coordinates)
|
|
@@ -177,6 +68,9 @@ class LineString(BaseGeometry):
|
|
|
177
68
|
# Coordinate access
|
|
178
69
|
|
|
179
70
|
def _set_coords(self, coordinates):
|
|
71
|
+
if self.is_empty:
|
|
72
|
+
lgeos.GEOSGeom_destroy(self.__geom__)
|
|
73
|
+
self.__geom__ = None
|
|
180
74
|
if self._geom is None:
|
|
181
75
|
self._init_geom(coordinates)
|
|
182
76
|
update_linestring_from_py(self, coordinates)
|
|
@@ -194,17 +88,12 @@ class LineString(BaseGeometry):
|
|
|
194
88
|
[0.0, 1.0]
|
|
195
89
|
>>> list(y)
|
|
196
90
|
[0.0, 1.0]
|
|
197
|
-
|
|
198
91
|
"""
|
|
199
92
|
return self.coords.xy
|
|
200
93
|
|
|
201
94
|
|
|
202
95
|
class LineStringAdapter(CachingGeometryProxy, LineString):
|
|
203
96
|
|
|
204
|
-
"""Adapts Python coordinate pairs or a numpy array to the line string
|
|
205
|
-
interface
|
|
206
|
-
"""
|
|
207
|
-
|
|
208
97
|
context = None
|
|
209
98
|
_owned = False
|
|
210
99
|
|
|
@@ -242,15 +131,114 @@ class LineStringAdapter(CachingGeometryProxy, LineString):
|
|
|
242
131
|
|
|
243
132
|
|
|
244
133
|
def asLineString(context):
|
|
245
|
-
"""
|
|
134
|
+
"""Adapt an object the LineString interface"""
|
|
246
135
|
return LineStringAdapter(context)
|
|
247
136
|
|
|
137
|
+
|
|
138
|
+
def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
|
|
139
|
+
try:
|
|
140
|
+
# From array protocol
|
|
141
|
+
array = ob.__array_interface__
|
|
142
|
+
assert len(array['shape']) == 2
|
|
143
|
+
m = array['shape'][0]
|
|
144
|
+
if m < 2:
|
|
145
|
+
raise ValueError(
|
|
146
|
+
"LineStrings must have at least 2 coordinate tuples")
|
|
147
|
+
try:
|
|
148
|
+
n = array['shape'][1]
|
|
149
|
+
except IndexError:
|
|
150
|
+
raise ValueError(
|
|
151
|
+
"Input %s is the wrong shape for a LineString" % str(ob))
|
|
152
|
+
assert n == 2 or n == 3
|
|
153
|
+
|
|
154
|
+
# Make pointer to the coordinate array
|
|
155
|
+
try:
|
|
156
|
+
cp = cast(array['data'][0], POINTER(c_double))
|
|
157
|
+
except ArgumentError:
|
|
158
|
+
cp = array['data']
|
|
159
|
+
|
|
160
|
+
# Create a coordinate sequence
|
|
161
|
+
if update_geom is not None:
|
|
162
|
+
cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
|
|
163
|
+
if n != update_ndim:
|
|
164
|
+
raise ValueError(
|
|
165
|
+
"Wrong coordinate dimensions; this geometry has dimensions: %d" \
|
|
166
|
+
% update_ndim)
|
|
167
|
+
else:
|
|
168
|
+
cs = lgeos.GEOSCoordSeq_create(m, n)
|
|
169
|
+
|
|
170
|
+
# add to coordinate sequence
|
|
171
|
+
for i in xrange(m):
|
|
172
|
+
dx = c_double(cp[n*i])
|
|
173
|
+
dy = c_double(cp[n*i+1])
|
|
174
|
+
dz = None
|
|
175
|
+
if n == 3:
|
|
176
|
+
try:
|
|
177
|
+
dz = c_double(cp[n*i+2])
|
|
178
|
+
except IndexError:
|
|
179
|
+
raise ValueError("Inconsistent coordinate dimensionality")
|
|
180
|
+
|
|
181
|
+
# Because of a bug in the GEOS C API,
|
|
182
|
+
# always set X before Y
|
|
183
|
+
lgeos.GEOSCoordSeq_setX(cs, i, dx)
|
|
184
|
+
lgeos.GEOSCoordSeq_setY(cs, i, dy)
|
|
185
|
+
if n == 3:
|
|
186
|
+
lgeos.GEOSCoordSeq_setZ(cs, i, dz)
|
|
187
|
+
|
|
188
|
+
except AttributeError:
|
|
189
|
+
# Fall back on list
|
|
190
|
+
m = len(ob)
|
|
191
|
+
if m < 2:
|
|
192
|
+
raise ValueError(
|
|
193
|
+
"LineStrings must have at least 2 coordinate tuples")
|
|
194
|
+
try:
|
|
195
|
+
n = len(ob[0])
|
|
196
|
+
except TypeError:
|
|
197
|
+
raise ValueError(
|
|
198
|
+
"Input %s is the wrong shape for a LineString" % str(ob))
|
|
199
|
+
assert n == 2 or n == 3
|
|
200
|
+
|
|
201
|
+
# Create a coordinate sequence
|
|
202
|
+
if update_geom is not None:
|
|
203
|
+
cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
|
|
204
|
+
if n != update_ndim:
|
|
205
|
+
raise ValueError(
|
|
206
|
+
"Wrong coordinate dimensions; this geometry has dimensions: %d" \
|
|
207
|
+
% update_ndim)
|
|
208
|
+
else:
|
|
209
|
+
cs = lgeos.GEOSCoordSeq_create(m, n)
|
|
210
|
+
|
|
211
|
+
# add to coordinate sequence
|
|
212
|
+
for i in xrange(m):
|
|
213
|
+
coords = ob[i]
|
|
214
|
+
dx = c_double(coords[0])
|
|
215
|
+
dy = c_double(coords[1])
|
|
216
|
+
dz = None
|
|
217
|
+
if n == 3:
|
|
218
|
+
try:
|
|
219
|
+
dz = c_double(coords[2])
|
|
220
|
+
except IndexError:
|
|
221
|
+
raise ValueError("Inconsistent coordinate dimensionality")
|
|
222
|
+
|
|
223
|
+
# Because of a bug in the GEOS C API,
|
|
224
|
+
# always set X before Y
|
|
225
|
+
lgeos.GEOSCoordSeq_setX(cs, i, dx)
|
|
226
|
+
lgeos.GEOSCoordSeq_setY(cs, i, dy)
|
|
227
|
+
if n == 3:
|
|
228
|
+
lgeos.GEOSCoordSeq_setZ(cs, i, dz)
|
|
248
229
|
|
|
230
|
+
if update_geom is not None:
|
|
231
|
+
return None
|
|
232
|
+
else:
|
|
233
|
+
return lgeos.GEOSGeom_createLineString(cs), n
|
|
234
|
+
|
|
235
|
+
def update_linestring_from_py(geom, ob):
|
|
236
|
+
geos_linestring_from_py(ob, geom._geom, geom._ndim)
|
|
237
|
+
|
|
249
238
|
# Test runner
|
|
250
239
|
def _test():
|
|
251
240
|
import doctest
|
|
252
241
|
doctest.testmod()
|
|
253
242
|
|
|
254
|
-
|
|
255
243
|
if __name__ == "__main__":
|
|
256
244
|
_test()
|