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.
Files changed (68) hide show
  1. {Shapely-1.2b4 → Shapely-1.2b6}/CHANGES.txt +16 -0
  2. {Shapely-1.2b4 → Shapely-1.2b6}/PKG-INFO +4 -4
  3. {Shapely-1.2b4 → Shapely-1.2b6}/README.txt +3 -3
  4. {Shapely-1.2b4 → Shapely-1.2b6}/Shapely.egg-info/PKG-INFO +4 -4
  5. Shapely-1.2b6/examples/dissolve.py +53 -0
  6. Shapely-1.2b6/examples/intersect.py +81 -0
  7. {Shapely-1.2b4 → Shapely-1.2b6}/setup.py +1 -1
  8. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/base.py +27 -6
  9. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/collection.py +1 -1
  10. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/linestring.py +108 -120
  11. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/multilinestring.py +54 -60
  12. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/multipoint.py +57 -57
  13. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/multipolygon.py +48 -43
  14. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/point.py +81 -76
  15. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/polygon.py +178 -180
  16. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/LineString.txt +10 -6
  17. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/MultiLineString.txt +18 -1
  18. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/MultiPoint.txt +17 -1
  19. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/MultiPolygon.txt +17 -1
  20. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/Point.txt +10 -10
  21. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/Polygon.txt +3 -7
  22. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/__init__.py +2 -0
  23. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/test_geomseq.py +2 -5
  24. Shapely-1.2b4/examples/dissolve.py +0 -52
  25. Shapely-1.2b4/examples/intersect.py +0 -80
  26. {Shapely-1.2b4 → Shapely-1.2b6}/CREDITS.txt +0 -0
  27. {Shapely-1.2b4 → Shapely-1.2b6}/LICENSE.txt +0 -0
  28. {Shapely-1.2b4 → Shapely-1.2b6}/MANIFEST.in +0 -0
  29. {Shapely-1.2b4 → Shapely-1.2b6}/Shapely.egg-info/SOURCES.txt +0 -0
  30. {Shapely-1.2b4 → Shapely-1.2b6}/Shapely.egg-info/dependency_links.txt +0 -0
  31. {Shapely-1.2b4 → Shapely-1.2b6}/Shapely.egg-info/top_level.txt +0 -0
  32. {Shapely-1.2b4 → Shapely-1.2b6}/setup.cfg +0 -0
  33. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/__init__.py +0 -0
  34. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/coords.py +0 -0
  35. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/ctypes_declarations.py +0 -0
  36. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/__init__.py +0 -0
  37. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/geo.py +0 -0
  38. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geometry/proxy.py +0 -0
  39. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geoms.py +0 -0
  40. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/geos.py +0 -0
  41. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/impl.py +0 -0
  42. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/iterops.py +0 -0
  43. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/linref.py +0 -0
  44. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/ops.py +0 -0
  45. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/predicates.py +0 -0
  46. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/prepared.py +0 -0
  47. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/Array.txt +0 -0
  48. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/GeoInterface.txt +0 -0
  49. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/IterOps.txt +0 -0
  50. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/Operations.txt +0 -0
  51. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/Persist.txt +0 -0
  52. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/Predicates.txt +0 -0
  53. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/attribute-chains.txt +0 -0
  54. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/binascii_hex.txt +0 -0
  55. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/dimensions.txt +0 -0
  56. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/invalid_intersection.txt +0 -0
  57. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/linear-referencing.txt +0 -0
  58. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/linemerge.txt +0 -0
  59. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/polygonize.txt +0 -0
  60. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/test_doctests.py +0 -0
  61. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/test_equality.py +0 -0
  62. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/test_prepared.py +0 -0
  63. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/test_xy.py +0 -0
  64. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/threading_test.py +0 -0
  65. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/tests/wkt_locale.txt +0 -0
  66. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/topology.py +0 -0
  67. {Shapely-1.2b4 → Shapely-1.2b6}/shapely/wkb.py +0 -0
  68. {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.2b4
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://gispython.org/images/shapely-med.png
14
- :width: 640
15
- :height: 320
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://gispython.org/images/shapely-med.png
6
- :width: 640
7
- :height: 320
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.2b4
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://gispython.org/images/shapely-med.png
14
- :width: 640
15
- :height: 320
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.2b4',
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__ = None
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
- return self.impl['bounds'](self)
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
  """
@@ -16,7 +16,7 @@ class GeometryCollection(BaseMultipartGeometry):
16
16
  """
17
17
 
18
18
  def __init__(self):
19
- BaseMultiPartGeometry.__init__(self)
19
+ BaseMultipartGeometry.__init__(self)
20
20
 
21
21
  @property
22
22
  def __geo_interface__(self):
@@ -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
- """Initialize a linestring instance
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
- """Factory for PointAdapter instances."""
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()