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.
Files changed (68) hide show
  1. {Shapely-1.2b5 → Shapely-1.2b7}/CHANGES.txt +8 -0
  2. {Shapely-1.2b5 → Shapely-1.2b7}/PKG-INFO +4 -4
  3. {Shapely-1.2b5 → Shapely-1.2b7}/README.txt +3 -3
  4. {Shapely-1.2b5 → Shapely-1.2b7}/Shapely.egg-info/PKG-INFO +4 -4
  5. Shapely-1.2b7/examples/dissolve.py +53 -0
  6. Shapely-1.2b7/examples/intersect.py +81 -0
  7. {Shapely-1.2b5 → Shapely-1.2b7}/setup.py +1 -1
  8. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/base.py +26 -6
  9. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/collection.py +1 -1
  10. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/linestring.py +4 -18
  11. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/point.py +7 -18
  12. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/polygon.py +7 -35
  13. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/proxy.py +18 -11
  14. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geos.py +2 -1
  15. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/__init__.py +3 -0
  16. Shapely-1.2b5/examples/dissolve.py +0 -52
  17. Shapely-1.2b5/examples/intersect.py +0 -80
  18. {Shapely-1.2b5 → Shapely-1.2b7}/CREDITS.txt +0 -0
  19. {Shapely-1.2b5 → Shapely-1.2b7}/LICENSE.txt +0 -0
  20. {Shapely-1.2b5 → Shapely-1.2b7}/MANIFEST.in +0 -0
  21. {Shapely-1.2b5 → Shapely-1.2b7}/Shapely.egg-info/SOURCES.txt +0 -0
  22. {Shapely-1.2b5 → Shapely-1.2b7}/Shapely.egg-info/dependency_links.txt +0 -0
  23. {Shapely-1.2b5 → Shapely-1.2b7}/Shapely.egg-info/top_level.txt +0 -0
  24. {Shapely-1.2b5 → Shapely-1.2b7}/setup.cfg +0 -0
  25. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/__init__.py +0 -0
  26. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/coords.py +0 -0
  27. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/ctypes_declarations.py +0 -0
  28. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/__init__.py +0 -0
  29. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/geo.py +0 -0
  30. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/multilinestring.py +0 -0
  31. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/multipoint.py +0 -0
  32. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geometry/multipolygon.py +0 -0
  33. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/geoms.py +0 -0
  34. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/impl.py +0 -0
  35. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/iterops.py +0 -0
  36. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/linref.py +0 -0
  37. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/ops.py +0 -0
  38. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/predicates.py +0 -0
  39. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/prepared.py +0 -0
  40. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/Array.txt +0 -0
  41. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/GeoInterface.txt +0 -0
  42. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/IterOps.txt +0 -0
  43. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/LineString.txt +0 -0
  44. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/MultiLineString.txt +0 -0
  45. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/MultiPoint.txt +0 -0
  46. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/MultiPolygon.txt +0 -0
  47. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/Operations.txt +0 -0
  48. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/Persist.txt +0 -0
  49. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/Point.txt +0 -0
  50. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/Polygon.txt +0 -0
  51. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/Predicates.txt +0 -0
  52. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/attribute-chains.txt +0 -0
  53. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/binascii_hex.txt +0 -0
  54. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/dimensions.txt +0 -0
  55. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/invalid_intersection.txt +0 -0
  56. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/linear-referencing.txt +0 -0
  57. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/linemerge.txt +0 -0
  58. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/polygonize.txt +0 -0
  59. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/test_doctests.py +0 -0
  60. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/test_equality.py +0 -0
  61. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/test_geomseq.py +0 -0
  62. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/test_prepared.py +0 -0
  63. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/test_xy.py +0 -0
  64. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/threading_test.py +0 -0
  65. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/tests/wkt_locale.txt +0 -0
  66. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/topology.py +0 -0
  67. {Shapely-1.2b5 → Shapely-1.2b7}/shapely/wkb.py +0 -0
  68. {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.2b5
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://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.2b5
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://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.2b5',
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__ = None
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
- def __init__(self):
92
- self.__geom__ = wkb.deserialize('010700000000000000'.decode('hex'))
92
+ @property
93
+ def _is_empty(self):
94
+ return self.__geom__ in [EMPTY, None]
93
95
 
94
- def __del__(self):
95
- if self.__geom__ is not None and not self._owned:
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
  """
@@ -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):
@@ -37,14 +37,8 @@ class LineString(BaseGeometry):
37
37
  2.0
38
38
  """
39
39
  BaseGeometry.__init__(self)
40
- self._init_geom(coordinates)
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
- if self.is_empty:
72
- lgeos.GEOSGeom_destroy(self.__geom__)
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
- self._init_geom(*args)
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, coordinates):
114
- if self.is_empty:
115
- lgeos.GEOSGeom_destroy(self.__geom__)
116
- self.__geom__ = None
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
- update_point_from_py(self, coordinates)
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
- self._init_geom(coordinates)
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
- if self.is_empty:
71
- lgeos.GEOSGeom_destroy(self.__geom__)
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
- @property
88
- def _geom(self):
89
- """Keeps the GEOS geometry in synch with the context."""
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__ = None
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
- if self.__geom__ is not None:
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
- if self.__geom__ is not None:
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