shapely 1.0b2__py2.4.egg → 1.0b4__py2.4.egg

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
EGG-INFO/PKG-INFO CHANGED
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: Shapely
3
- Version: 1.0b2
3
+ Version: 1.0b4
4
4
  Summary: Geospatial geometries, predicates, and operations
5
5
  Home-page: http://trac.gispython.org/projects/PCL/wiki/Shapely
6
6
  Author: Sean Gillies
@@ -23,7 +23,7 @@ Description: Shapely
23
23
  Dependencies
24
24
  ------------
25
25
 
26
- * libgeos_c (2.2.3, also reported to work with 3.0 after small modifications.)
26
+ * libgeos_c (2.2.3 or 3.0.0+)
27
27
  * Python ctypes_ (standard in Python 2.5+)
28
28
 
29
29
  .. _ctypes: http://pypi.python.org/pypi/ctypes/
@@ -124,7 +124,7 @@ Description: Shapely
124
124
  For current information about this project, see the wiki_.
125
125
 
126
126
  .. _wiki: http://trac.gispython.org/projects/PCL/wiki/Shapely
127
- .. _manual: http://trac.gispython.org/projects/PCL/wiki/ShapelyManual
127
+ .. _manual: http://gispython.org/shapely/manual.html
128
128
 
129
129
  If you have questions, please consider joining our community list:
130
130
 
EGG-INFO/SOURCES.txt CHANGED
@@ -11,6 +11,8 @@ Shapely.egg-info/requires.txt
11
11
  Shapely.egg-info/top_level.txt
12
12
  examples/geoms.py
13
13
  examples/world.py
14
+ manual/manual.txt
15
+ manual/style.css
14
16
  shapely/__init__.py
15
17
  shapely/geos.py
16
18
  shapely/iterops.py
shapely/geometry/base.py CHANGED
@@ -5,7 +5,7 @@ Base geometry class and utilities.
5
5
  from ctypes import string_at, byref, c_int, c_size_t, c_char_p, c_double
6
6
  import sys
7
7
 
8
- from shapely.geos import lgeos
8
+ from shapely.geos import lgeos, free, allocated_c_char_p
9
9
  from shapely.predicates import BinaryPredicate, UnaryPredicate
10
10
  from shapely.topology import BinaryTopologicalOp, UnaryTopologicalOp
11
11
 
@@ -22,6 +22,8 @@ GEOMETRY_TYPES = [
22
22
  ]
23
23
 
24
24
  def geometry_type_name(g):
25
+ if g is None:
26
+ raise ValueError, "Null geometry has no type"
25
27
  return GEOMETRY_TYPES[lgeos.GEOSGeomTypeId(g)]
26
28
 
27
29
  # Abstract geometry factory for use with topological methods below
@@ -156,23 +158,42 @@ class GeometrySequence(object):
156
158
  max = l
157
159
 
158
160
 
161
+ def exceptNull(func):
162
+ """Decorator which helps avoid GEOS operations on null pointers."""
163
+ def wrapper(*args, **kwargs):
164
+ # self is the first arg
165
+ if args[0]._geom is None:
166
+ raise ValueError, "Null geometry supports no operations"
167
+ return func(*args, **kwargs)
168
+ return wrapper
169
+
170
+ def exceptEitherNull(func):
171
+ """Decorator which avoids GEOS operations on one or more null pointers."""
172
+ def wrapper(*args, **kwargs):
173
+ # self is the first arg
174
+ if args[0]._geom is None or args[1]._geom is None:
175
+ raise ValueError, "Null geometry supports no operations"
176
+ return func(*args, **kwargs)
177
+ return wrapper
178
+
179
+
159
180
  class BaseGeometry(object):
160
181
 
161
182
  """Provides GEOS spatial predicates and topological operations.
162
183
  """
163
184
 
164
- _geom = None
185
+ __geom = None # See _geom property below
165
186
  _ctypes_data = None
166
187
  _ndim = None
167
188
  _crs = None
168
189
  _owned = False
169
190
 
170
191
  def __init__(self):
171
- self._geom = lgeos.GEOSGeomFromWKT(c_char_p('GEOMETRYCOLLECTION EMPTY'))
192
+ self.__geom = None
172
193
 
173
194
  def __del__(self):
174
- if self._geom is not None and not self._owned:
175
- lgeos.GEOSGeom_destroy(self._geom)
195
+ if self.__geom is not None and not self._owned:
196
+ lgeos.GEOSGeom_destroy(self.__geom)
176
197
 
177
198
  def __str__(self):
178
199
  return self.to_wkt()
@@ -189,11 +210,20 @@ class BaseGeometry(object):
189
210
  return (self.__class__, (), self.to_wkb())
190
211
 
191
212
  def __setstate__(self, state):
192
- self._geom = lgeos.GEOSGeomFromWKB_buf(
213
+ self.__geom = lgeos.GEOSGeomFromWKB_buf(
193
214
  c_char_p(state),
194
215
  c_size_t(len(state))
195
216
  )
196
217
 
218
+ # _geom has been made a property with the GEOS geometry pointer stored
219
+ # in __geom so that geometries and geometry adapters can share __del__
220
+
221
+ def get_geom(self):
222
+ return self.__geom
223
+ def set_geom(self, val):
224
+ self.__geom = val
225
+ _geom = property(get_geom, set_geom)
226
+
197
227
  # Array and ctypes interfaces
198
228
 
199
229
  @property
@@ -222,6 +252,7 @@ class BaseGeometry(object):
222
252
  """Provide the Numpy array protocol."""
223
253
  raise NotImplementedError
224
254
 
255
+ @exceptNull
225
256
  def get_coords(self):
226
257
  return CoordinateSequence(self)
227
258
 
@@ -243,19 +274,34 @@ class BaseGeometry(object):
243
274
 
244
275
  # Type of geometry and its representations
245
276
 
277
+ @exceptNull
246
278
  def geometryType(self):
247
279
  """Returns a string representing the geometry type, e.g. 'Polygon'."""
248
280
  return geometry_type_name(self._geom)
249
281
 
282
+ @exceptNull
250
283
  def to_wkb(self):
251
284
  """Returns a WKB byte string representation of the geometry."""
285
+ func = lgeos.GEOSGeomToWKB_buf
252
286
  size = c_int()
253
- bytes = lgeos.GEOSGeomToWKB_buf(self._geom, byref(size))
254
- return string_at(bytes, size.value)
255
-
287
+ def errcheck(result, func, argtuple):
288
+ retval = string_at(result, size.value)[:]
289
+ free(result)
290
+ return retval
291
+ func.errcheck = errcheck
292
+ return func(self._geom, byref(size))
293
+
294
+ @exceptNull
256
295
  def to_wkt(self):
257
296
  """Returns a WKT string representation of the geometry."""
258
- return string_at(lgeos.GEOSGeomToWKT(self._geom))
297
+ func = lgeos.GEOSGeomToWKT
298
+ def errcheck(result, func, argtuple):
299
+ retval = result.value
300
+ free(result)
301
+ return retval
302
+ func.restype = allocated_c_char_p
303
+ func.errcheck = errcheck
304
+ return lgeos.GEOSGeomToWKT(self._geom)
259
305
 
260
306
  geom_type = property(geometryType)
261
307
  wkt = property(to_wkt)
@@ -264,17 +310,20 @@ class BaseGeometry(object):
264
310
  # Basic geometry properties
265
311
 
266
312
  @property
313
+ @exceptNull
267
314
  def area(self):
268
315
  a = c_double()
269
316
  retval = lgeos.GEOSArea(self._geom, byref(a))
270
317
  return a.value
271
318
 
272
319
  @property
320
+ @exceptNull
273
321
  def length(self):
274
322
  len = c_double()
275
323
  retval = lgeos.GEOSLength(self._geom, byref(len))
276
324
  return len.value
277
325
 
326
+ @exceptEitherNull
278
327
  def distance(self, other):
279
328
  d = c_double()
280
329
  retval = lgeos.GEOSDistance(self._geom, other._geom, byref(d))
@@ -295,15 +344,22 @@ class BaseGeometry(object):
295
344
  centroid = UnaryTopologicalOp(lgeos.GEOSGetCentroid, geom_factory)
296
345
 
297
346
  # Buffer has a unique distance argument, so not a descriptor
347
+ @exceptNull
298
348
  def buffer(self, distance, quadsegs=16):
299
349
  return geom_factory(
300
350
  lgeos.GEOSBuffer(self._geom, c_double(distance), c_int(quadsegs))
301
351
  )
302
352
 
303
353
  # Relate has a unique string return value
354
+ @exceptNull
304
355
  def relate(self, other):
305
356
  func = lgeos.GEOSRelate
306
- func.restype = c_char_p
357
+ def errcheck(result, func, argtuple):
358
+ retval = result.value
359
+ free(result)
360
+ return retval
361
+ func.restype = allocated_c_char_p
362
+ func.errcheck = errcheck
307
363
  return lgeos.GEOSRelate(self._geom, other._geom)
308
364
 
309
365
  # Binary predicates
@@ -331,6 +387,7 @@ class BaseGeometry(object):
331
387
  has_z = UnaryPredicate(lgeos.GEOSHasZ)
332
388
 
333
389
  @property
390
+ @exceptNull
334
391
  def bounds(self):
335
392
  env = self.envelope
336
393
  if env.geom_type != 'Polygon':
shapely/geometry/base.pyc CHANGED
Binary file
@@ -6,7 +6,7 @@ from ctypes import byref, c_double, c_int, cast, POINTER, pointer
6
6
  from ctypes import ArgumentError
7
7
 
8
8
  from shapely.geos import lgeos
9
- from shapely.geometry.base import BaseGeometry
9
+ from shapely.geometry.base import BaseGeometry, exceptNull
10
10
 
11
11
 
12
12
  def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
@@ -86,7 +86,7 @@ def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
86
86
  if update_geom is not None:
87
87
  return None
88
88
  else:
89
- return (lgeos.GEOSGeom_createLineString(cs), n)
89
+ return lgeos.GEOSGeom_createLineString(cs), n
90
90
 
91
91
  def update_linestring_from_py(geom, ob):
92
92
  geos_linestring_from_py(ob, geom._geom, geom._ndim)
@@ -118,7 +118,9 @@ class LineString(BaseGeometry):
118
118
  Each result in a line string from (0.0, 0.0) to (1.0, 2.0).
119
119
  """
120
120
  BaseGeometry.__init__(self)
121
+ self._init_geom(coordinates)
121
122
 
123
+ def _init_geom(self, coordinates):
122
124
  if coordinates is None:
123
125
  # allow creation of null lines, to support unpickling
124
126
  pass
@@ -133,6 +135,7 @@ class LineString(BaseGeometry):
133
135
  }
134
136
 
135
137
  @property
138
+ @exceptNull
136
139
  def ctypes(self):
137
140
  if not self._ctypes_data:
138
141
  cs = lgeos.GEOSGeom_getCoordSeq(self._geom)
@@ -164,6 +167,8 @@ class LineString(BaseGeometry):
164
167
  # Coordinate access
165
168
 
166
169
  def set_coords(self, coordinates):
170
+ if self._geom is None:
171
+ self._init_geom(coordinates)
167
172
  update_linestring_from_py(self, coordinates)
168
173
 
169
174
  coords = property(BaseGeometry.get_coords, set_coords)
@@ -176,14 +181,12 @@ class LineStringAdapter(LineString):
176
181
  """
177
182
 
178
183
  context = None
184
+ __geom = None
185
+ _owned = False
179
186
 
180
187
  def __init__(self, context):
181
188
  self.context = context
182
189
 
183
- # Override base class __del__
184
- def __del__(self):
185
- pass
186
-
187
190
  @property
188
191
  def _ndim(self):
189
192
  try:
@@ -199,7 +202,10 @@ class LineStringAdapter(LineString):
199
202
  @property
200
203
  def _geom(self):
201
204
  """Keeps the GEOS geometry in synch with the context."""
202
- return geos_linestring_from_py(self.context)[0]
205
+ if self.__geom is not None:
206
+ lgeos.GEOSGeom_destroy(self.__geom)
207
+ self.__geom, n = geos_linestring_from_py(self.context)
208
+ return self.__geom
203
209
 
204
210
  @property
205
211
  def __array_interface__(self):
Binary file
@@ -5,7 +5,7 @@ Multi-part collection of linestrings.
5
5
  from ctypes import byref, c_double, c_int, c_void_p, cast, POINTER, pointer
6
6
 
7
7
  from shapely.geos import lgeos
8
- from shapely.geometry.base import BaseGeometry, GeometrySequence
8
+ from shapely.geometry.base import BaseGeometry, GeometrySequence, exceptNull
9
9
  from shapely.geometry.linestring import LineString, geos_linestring_from_py
10
10
 
11
11
 
@@ -102,6 +102,7 @@ class MultiLineString(BaseGeometry):
102
102
  "Multi-part geometries do not provide a coordinate sequence"
103
103
 
104
104
  @property
105
+ @exceptNull
105
106
  def geoms(self):
106
107
  return GeometrySequence(self, LineString)
107
108
 
@@ -113,14 +114,12 @@ class MultiLineStringAdapter(MultiLineString):
113
114
  """
114
115
 
115
116
  context = None
117
+ __geom = None
118
+ _owned = False
116
119
 
117
120
  def __init__(self, context):
118
121
  self.context = context
119
122
 
120
- # Override base class __del__
121
- def __del__(self):
122
- pass
123
-
124
123
  @property
125
124
  def _ndim(self):
126
125
  try:
@@ -136,7 +135,10 @@ class MultiLineStringAdapter(MultiLineString):
136
135
  @property
137
136
  def _geom(self):
138
137
  """Keeps the GEOS geometry in synch with the context."""
139
- return geos_multilinestring_from_py(self.context)[0]
138
+ if self.__geom is not None:
139
+ lgeos.GEOSGeom_destroy(self.__geom)
140
+ self.__geom = geos_multilinestring_from_py(self.context)[0]
141
+ return self.__geom
140
142
 
141
143
 
142
144
  def asMultiLineString(context):
Binary file
@@ -5,7 +5,7 @@ Multiple points.
5
5
  from ctypes import byref, c_double, c_int, c_void_p, cast, POINTER, pointer
6
6
 
7
7
  from shapely.geos import lgeos
8
- from shapely.geometry.base import BaseGeometry, GeometrySequence
8
+ from shapely.geometry.base import BaseGeometry, GeometrySequence, exceptNull
9
9
  from shapely.geometry.point import Point, geos_point_from_py
10
10
 
11
11
 
@@ -44,7 +44,7 @@ def geos_multipoint_from_py(ob):
44
44
  geom, ndims = geos_point_from_py(coords)
45
45
  subs[i] = cast(geom, c_void_p)
46
46
 
47
- return (lgeos.GEOSGeom_createCollection(4, subs, m), n)
47
+ return lgeos.GEOSGeom_createCollection(4, subs, m), n
48
48
 
49
49
 
50
50
  class MultiPoint(BaseGeometry):
@@ -81,6 +81,7 @@ class MultiPoint(BaseGeometry):
81
81
 
82
82
 
83
83
  @property
84
+ @exceptNull
84
85
  def __geo_interface__(self):
85
86
  return {
86
87
  'type': 'MultiPoint',
@@ -88,6 +89,7 @@ class MultiPoint(BaseGeometry):
88
89
  }
89
90
 
90
91
  @property
92
+ @exceptNull
91
93
  def ctypes(self):
92
94
  if not self._ctypes_data:
93
95
  temp = c_double()
@@ -108,6 +110,7 @@ class MultiPoint(BaseGeometry):
108
110
  self._ctypes_data = data
109
111
  return self._ctypes_data
110
112
 
113
+ @exceptNull
111
114
  def array_interface(self):
112
115
  """Provide the Numpy array protocol."""
113
116
  ai = self.array_interface_base
@@ -121,6 +124,7 @@ class MultiPoint(BaseGeometry):
121
124
  "Multipart geometries do not themselves provide coordinate sequences"
122
125
 
123
126
  @property
127
+ @exceptNull
124
128
  def geoms(self):
125
129
  return GeometrySequence(self, Point)
126
130
 
@@ -132,14 +136,12 @@ class MultiPointAdapter(MultiPoint):
132
136
  """
133
137
 
134
138
  context = None
139
+ __geom = None
140
+ _owned = False
135
141
 
136
142
  def __init__(self, context):
137
143
  self.context = context
138
144
 
139
- # Override base class __del__
140
- def __del__(self):
141
- pass
142
-
143
145
  @property
144
146
  def _ndim(self):
145
147
  try:
@@ -155,7 +157,10 @@ class MultiPointAdapter(MultiPoint):
155
157
  @property
156
158
  def _geom(self):
157
159
  """Keeps the GEOS geometry in synch with the context."""
158
- return geos_multipoint_from_py(self.context)[0]
160
+ if self.__geom is not None:
161
+ lgeos.GEOSGeom_destroy(self.__geom)
162
+ self.__geom, n = geos_multipoint_from_py(self.context)
163
+ return self.__geom
159
164
 
160
165
  @property
161
166
  def __array_interface__(self):
Binary file
@@ -5,7 +5,7 @@ Multi-part collection of polygons.
5
5
  from ctypes import byref, c_double, c_int, c_void_p, cast, POINTER, pointer
6
6
 
7
7
  from shapely.geos import lgeos
8
- from shapely.geometry.base import BaseGeometry, GeometrySequence
8
+ from shapely.geometry.base import BaseGeometry, GeometrySequence, exceptNull
9
9
  from shapely.geometry.polygon import Polygon, geos_polygon_from_py
10
10
 
11
11
 
@@ -88,6 +88,7 @@ class MultiPolygon(BaseGeometry):
88
88
  "Multi-part geometries do not provide a coordinate sequence"
89
89
 
90
90
  @property
91
+ @exceptNull
91
92
  def geoms(self):
92
93
  return GeometrySequence(self, Polygon)
93
94
 
@@ -99,14 +100,12 @@ class MultiPolygonAdapter(MultiPolygon):
99
100
  """
100
101
 
101
102
  context = None
103
+ __geom = None
104
+ _owned = False
102
105
 
103
106
  def __init__(self, context):
104
107
  self.context = context
105
108
 
106
- # Override base class __del__
107
- def __del__(self):
108
- pass
109
-
110
109
  @property
111
110
  def _ndim(self):
112
111
  try:
@@ -122,7 +121,10 @@ class MultiPolygonAdapter(MultiPolygon):
122
121
  @property
123
122
  def _geom(self):
124
123
  """Keeps the GEOS geometry in synch with the context."""
125
- return geos_multipolygon_from_py(self.context)[0]
124
+ if self.__geom is not None:
125
+ lgeos.GEOSGeom_destroy(self.__geom)
126
+ self.__geom = geos_multipolygon_from_py(self.context)[0]
127
+ return self.__geom
126
128
 
127
129
 
128
130
  def asMultiPolygon(context):
Binary file
shapely/geometry/point.py CHANGED
@@ -9,6 +9,7 @@ from ctypes import cast, POINTER
9
9
 
10
10
  from shapely.geos import lgeos, DimensionError
11
11
  from shapely.geometry.base import BaseGeometry, CoordinateSequence
12
+ from shapely.geometry.base import exceptNull
12
13
 
13
14
 
14
15
  def geos_point_from_py(ob, update_geom=None, update_ndim=0):
@@ -33,8 +34,12 @@ def geos_point_from_py(ob, update_geom=None, update_ndim=0):
33
34
  dz = c_double(cp[2])
34
35
  ndim = 3
35
36
  except AttributeError:
36
- # Fall back on list
37
- coords = ob
37
+ # Fall back on the case of Python sequence data
38
+ # Accept either (x, y) or [(x, y)]
39
+ if type(ob[0]) == type(tuple()):
40
+ coords = ob[0]
41
+ else:
42
+ coords = ob
38
43
  n = len(coords)
39
44
  dx = c_double(coords[0])
40
45
  dy = c_double(coords[1])
@@ -60,7 +65,7 @@ def geos_point_from_py(ob, update_geom=None, update_ndim=0):
60
65
  if update_geom:
61
66
  return None
62
67
  else:
63
- return (lgeos.GEOSGeom_createPoint(cs), n)
68
+ return lgeos.GEOSGeom_createPoint(cs), n
64
69
 
65
70
  def update_point_from_py(geom, ob):
66
71
  geos_point_from_py(ob, geom._geom, geom._ndim)
@@ -102,7 +107,9 @@ class Point(BaseGeometry):
102
107
  Easting, northing, and elevation.
103
108
  """
104
109
  BaseGeometry.__init__(self)
110
+ self._init_geom(*args)
105
111
 
112
+ def _init_geom(self, *args):
106
113
  if len(args) == 0:
107
114
  # allow creation of null points, to support unpickling
108
115
  pass
@@ -115,6 +122,7 @@ class Point(BaseGeometry):
115
122
  # Coordinate getters and setters
116
123
 
117
124
  @property
125
+ @exceptNull
118
126
  def x(self):
119
127
  """Return x coordinate."""
120
128
  cs = lgeos.GEOSGeom_getCoordSeq(self._geom)
@@ -123,6 +131,7 @@ class Point(BaseGeometry):
123
131
  return d.value
124
132
 
125
133
  @property
134
+ @exceptNull
126
135
  def y(self):
127
136
  """Return y coordinate."""
128
137
  cs = lgeos.GEOSGeom_getCoordSeq(self._geom)
@@ -131,6 +140,7 @@ class Point(BaseGeometry):
131
140
  return d.value
132
141
 
133
142
  @property
143
+ @exceptNull
134
144
  def z(self):
135
145
  """Return z coordinate."""
136
146
  if self._ndim != 3:
@@ -141,6 +151,7 @@ class Point(BaseGeometry):
141
151
  return d.value
142
152
 
143
153
  @property
154
+ @exceptNull
144
155
  def __geo_interface__(self):
145
156
  return {
146
157
  'type': 'Point',
@@ -148,6 +159,7 @@ class Point(BaseGeometry):
148
159
  }
149
160
 
150
161
  @property
162
+ @exceptNull
151
163
  def ctypes(self):
152
164
  if not self._ctypes_data:
153
165
  array_type = c_double * self._ndim
@@ -167,6 +179,7 @@ class Point(BaseGeometry):
167
179
  __array_interface__ = property(array_interface)
168
180
 
169
181
  @property
182
+ @exceptNull
170
183
  def bounds(self):
171
184
  cs = lgeos.GEOSGeom_getCoordSeq(self._geom)
172
185
  x = c_double()
@@ -178,7 +191,10 @@ class Point(BaseGeometry):
178
191
  # Coordinate access
179
192
 
180
193
  def set_coords(self, coordinates):
181
- update_point_from_py(self, coordinates)
194
+ if self._geom is None:
195
+ self._init_geom(coordinates)
196
+ else:
197
+ update_point_from_py(self, coordinates)
182
198
 
183
199
  coords = property(BaseGeometry.get_coords, set_coords)
184
200
 
@@ -189,14 +205,12 @@ class PointAdapter(Point):
189
205
  """
190
206
 
191
207
  context = None
208
+ __geom = None
209
+ _owned = False
192
210
 
193
211
  def __init__(self, context):
194
212
  self.context = context
195
213
 
196
- # Override base class __del__
197
- def __del__(self):
198
- pass
199
-
200
214
  @property
201
215
  def _ndim(self):
202
216
  try:
@@ -212,7 +226,10 @@ class PointAdapter(Point):
212
226
  @property
213
227
  def _geom(self):
214
228
  """Keeps the GEOS geometry in synch with the context."""
215
- return geos_point_from_py(self.context)[0]
229
+ if self.__geom is not None:
230
+ lgeos.GEOSGeom_destroy(self.__geom)
231
+ self.__geom, n = geos_point_from_py(self.context)
232
+ return self.__geom
216
233
 
217
234
  # TODO: reimplement x, y, z properties without calling invoking _geom
218
235
 
Binary file
@@ -5,7 +5,7 @@ Polygons and their linear ring components.
5
5
  from ctypes import byref, c_double, c_int, c_void_p, cast, POINTER, pointer
6
6
 
7
7
  from shapely.geos import lgeos
8
- from shapely.geometry.base import BaseGeometry
8
+ from shapely.geometry.base import BaseGeometry, exceptNull
9
9
  from shapely.geometry.linestring import LineString, LineStringAdapter
10
10
 
11
11
 
@@ -129,7 +129,7 @@ def geos_linearring_from_py(ob, update_geom=None, update_ndim=0):
129
129
  if update_geom is not None:
130
130
  return None
131
131
  else:
132
- return (lgeos.GEOSGeom_createLinearRing(cs), n)
132
+ return lgeos.GEOSGeom_createLinearRing(cs), n
133
133
 
134
134
  def update_linearring_from_py(geom, ob):
135
135
  geos_linearring_from_py(ob, geom._geom, geom._ndim)
@@ -141,6 +141,8 @@ class LinearRing(LineString):
141
141
  """
142
142
 
143
143
  _ndim = 2
144
+ __geom = None
145
+ _owned = False
144
146
 
145
147
  def __init__(self, coordinates=None):
146
148
  """Initialize.
@@ -162,7 +164,9 @@ class LinearRing(LineString):
162
164
  Produces a 1x1 square.
163
165
  """
164
166
  BaseGeometry.__init__(self)
167
+ self._init_geom(coordinates)
165
168
 
169
+ def _init_geom(self, coordinates):
166
170
  if coordinates is None:
167
171
  # allow creation of null lines, to support unpickling
168
172
  pass
@@ -179,6 +183,8 @@ class LinearRing(LineString):
179
183
  # Coordinate access
180
184
 
181
185
  def set_coords(self, coordinates):
186
+ if self._geom is None:
187
+ self._init_geom(coordinates)
182
188
  update_linearring_from_py(self, coordinates)
183
189
 
184
190
  coords = property(BaseGeometry.get_coords, set_coords)
@@ -186,10 +192,17 @@ class LinearRing(LineString):
186
192
 
187
193
  class LinearRingAdapter(LineStringAdapter):
188
194
 
195
+ context = None
196
+ __geom = None
197
+ _owned = False
198
+
189
199
  @property
190
200
  def _geom(self):
191
201
  """Keeps the GEOS geometry in synch with the context."""
192
- return geos_linearring_from_py(self.context)[0]
202
+ if self.__geom is not None:
203
+ lgeos.GEOSGeom_destroy(self.__geom)
204
+ self.__geom, n = geos_linearring_from_py(self.context)
205
+ return self.__geom
193
206
 
194
207
  @property
195
208
  def __geo_interface__(self):
@@ -260,9 +273,6 @@ class InteriorRingSequence(object):
260
273
  def geos_polygon_from_py(shell, holes=None):
261
274
  if shell is not None:
262
275
  geos_shell, ndims = geos_linearring_from_py(shell)
263
- ## Polygon geometry takes ownership of the ring
264
- #self._exterior._owned = True
265
-
266
276
  if holes:
267
277
  ob = holes
268
278
  L = len(ob)
@@ -302,6 +312,8 @@ class Polygon(BaseGeometry):
302
312
  _exterior = None
303
313
  _interiors = []
304
314
  _ndim = 2
315
+ __geom = None
316
+ _owned = False
305
317
 
306
318
  def __init__(self, shell=None, holes=None):
307
319
  """Initialize.
@@ -324,6 +336,7 @@ class Polygon(BaseGeometry):
324
336
  self._geom, self._ndims = geos_polygon_from_py(shell, holes)
325
337
 
326
338
  @property
339
+ @exceptNull
327
340
  def exterior(self):
328
341
  if self._exterior is None:
329
342
  # A polygon created from the abstract factory will have a null
@@ -335,6 +348,7 @@ class Polygon(BaseGeometry):
335
348
  return self._exterior
336
349
 
337
350
  @property
351
+ @exceptNull
338
352
  def interiors(self):
339
353
  return InteriorRingSequence(self)
340
354
 
@@ -372,15 +386,13 @@ class PolygonAdapter(Polygon):
372
386
  """
373
387
 
374
388
  context = None
389
+ __geom = None
390
+ _owned = False
375
391
 
376
392
  def __init__(self, shell, holes=None):
377
393
  self.shell = shell
378
394
  self.holes = holes
379
395
 
380
- # Override base class __del__
381
- def __del__(self):
382
- pass
383
-
384
396
  @property
385
397
  def _ndim(self):
386
398
  try:
@@ -396,10 +408,13 @@ class PolygonAdapter(Polygon):
396
408
  @property
397
409
  def _geom(self):
398
410
  """Keeps the GEOS geometry in synch with the context."""
399
- return geos_polygon_from_py(self.shell, self.holes)[0]
411
+ if self.__geom is not None:
412
+ lgeos.GEOSGeom_destroy(self.__geom)
413
+ self.__geom = geos_polygon_from_py(self.shell, self.holes)[0]
414
+ return self.__geom
400
415
 
401
416
 
402
- def asPolygon(shell, holes):
417
+ def asPolygon(shell, holes=None):
403
418
  """Factory for PolygonAdapter instances."""
404
419
  return PolygonAdapter(shell, holes)
405
420
 
Binary file
shapely/geos.py CHANGED
@@ -3,7 +3,7 @@ Exports the libgeos_c shared lib, GEOS-specific exceptions, and utilities.
3
3
  """
4
4
 
5
5
  import atexit
6
- from ctypes import CDLL, CFUNCTYPE, c_char_p
6
+ from ctypes import cdll, CDLL, CFUNCTYPE, c_char_p
7
7
  from ctypes.util import find_library
8
8
  import sys
9
9
 
@@ -16,8 +16,10 @@ if sys.platform == 'win32':
16
16
  lgeos = CDLL('libgeos_c-1.dll')
17
17
  except:
18
18
  raise
19
+ free = cdll.msvcrt.free
19
20
  elif sys.platform == 'darwin':
20
21
  lgeos = CDLL(find_library('geos_c'))
22
+ free = CDLL(find_library('libc')).free
21
23
  else:
22
24
  # Try the major versioned name first, falling back on the unversioned name.
23
25
  try:
@@ -26,6 +28,12 @@ else:
26
28
  lgeos = CDLL('libgeos_c.so')
27
29
  except:
28
30
  raise
31
+ free = CDLL('libc.so.6').free
32
+
33
+
34
+ class allocated_c_char_p(c_char_p):
35
+ pass
36
+
29
37
 
30
38
  # Exceptions
31
39
 
shapely/geos.pyc CHANGED
Binary file
shapely/iterops.py CHANGED
@@ -2,7 +2,7 @@
2
2
  """
3
3
 
4
4
  from ctypes import c_char_p, c_size_t
5
- from shapely.geos import lgeos
5
+ from shapely.geos import lgeos, free
6
6
 
7
7
 
8
8
  def geos_from_geometry(geom):
@@ -28,20 +28,22 @@ class BinaryPredicateIterator(object):
28
28
  return self
29
29
 
30
30
  def __call__(self, geom, iterator, value=True):
31
- geos_geom = geos_from_geometry(geom)
31
+ if geom._geom is None:
32
+ raise ValueError, "Null geometry supports no operations"
32
33
  for item in iterator:
33
34
  try:
34
- geom, ob = item
35
+ this_geom, ob = item
35
36
  except TypeError:
36
- geom = item
37
- ob = geom
38
- retval = self.fn(geos_geom, geos_from_geometry(geom))
37
+ this_geom = item
38
+ ob = this_geom
39
+ if this_geom._geom is None:
40
+ raise ValueError, "Null geometry supports no operations"
41
+ retval = self.fn(geom._geom, this_geom._geom)
39
42
  if retval == 2:
40
43
  raise PredicateError, "Failed to evaluate %s" % repr(self.fn)
41
44
  elif bool(retval) == value:
42
45
  yield ob
43
46
 
44
-
45
47
  # utilities
46
48
  disjoint = BinaryPredicateIterator(lgeos.GEOSDisjoint)
47
49
  touches = BinaryPredicateIterator(lgeos.GEOSTouches)
shapely/iterops.pyc CHANGED
Binary file
shapely/predicates.py CHANGED
@@ -16,16 +16,20 @@ class BinaryPredicate(object):
16
16
 
17
17
  def __init__(self, fn):
18
18
  self.fn = fn
19
+ def errcheck(result, func, argtuple):
20
+ if result == 2:
21
+ raise PredicateError, "Failed to evaluate %s" % repr(self.fn)
22
+ return result
23
+ self.fn.errcheck = errcheck
19
24
 
20
25
  def __get__(self, obj, objtype=None):
21
26
  self.context = obj
22
27
  return self
23
28
 
24
29
  def __call__(self, other):
25
- retval = self.fn(self.context._geom, other._geom)
26
- if retval == 2:
27
- raise PredicateError, "Failed to evaluate %s" % repr(self.fn)
28
- return bool(retval)
30
+ if self.context._geom is None or other._geom is None:
31
+ raise ValueError, "Null geometry supports no operations"
32
+ return bool(self.fn(self.context._geom, other._geom))
29
33
 
30
34
 
31
35
  # A data descriptor
@@ -38,12 +42,16 @@ class UnaryPredicate(object):
38
42
 
39
43
  def __init__(self, fn):
40
44
  self.fn = fn
45
+ def errcheck(result, func, argtuple):
46
+ if result == 2:
47
+ raise PredicateError, "Failed to evaluate %s" % repr(self.fn)
48
+ return result
49
+ self.fn.errcheck = errcheck
41
50
 
42
51
  def __get__(self, obj, objtype=None):
43
- retval = self.fn(obj._geom)
44
- if retval == 2:
45
- raise PredicateError, "Failed to evaluate %s" % repr(self.fn)
46
- return bool(retval)
52
+ if obj._geom is None:
53
+ raise ValueError, "Null geometry supports no operations"
54
+ return bool(self.fn(obj._geom))
47
55
 
48
56
  def __set__(self, obj, value=None):
49
57
  raise AttributeError, "Attribute is read-only"
shapely/predicates.pyc CHANGED
Binary file
shapely/topology.py CHANGED
@@ -26,6 +26,8 @@ class BinaryTopologicalOp(object):
26
26
  return self
27
27
 
28
28
  def __call__(self, other):
29
+ if self.context._geom is None or other._geom is None:
30
+ raise ValueError, "Null geometry supports no operations"
29
31
  product = self.fn(self.context._geom, other._geom)
30
32
  if not product:
31
33
  # Check validity of geometries
@@ -55,6 +57,8 @@ class UnaryTopologicalOp(object):
55
57
  self.factory = factory
56
58
 
57
59
  def __get__(self, obj, objtype=None):
60
+ if obj._geom is None:
61
+ raise ValueError, "Null geometry supports no operations"
58
62
  return self.factory(self.fn(obj._geom))
59
63
 
60
64
  def __set__(self, obj, value=None):
shapely/topology.pyc CHANGED
Binary file
shapely/wkb.py CHANGED
@@ -4,7 +4,7 @@ Load/dump geometries using the well-known binary (WKB) format.
4
4
 
5
5
  from ctypes import byref, c_int, c_size_t, c_char_p, string_at
6
6
 
7
- from shapely.geos import lgeos, ReadingError
7
+ from shapely.geos import lgeos, free, ReadingError
8
8
  from shapely.geometry.base import geom_factory
9
9
 
10
10
 
@@ -25,9 +25,14 @@ def load(fp):
25
25
 
26
26
  def dumps(ob):
27
27
  """Dump a WKB representation of a geometry to a byte string."""
28
+ func = lgeos.GEOSGeomToWKB_buf
28
29
  size = c_int()
29
- bytes = lgeos.GEOSGeomToWKB_buf(ob._geom, byref(size))
30
- return string_at(bytes, size.value)
30
+ def errcheck(result, func, argtuple):
31
+ retval = string_at(result, size.value)[:]
32
+ free(result)
33
+ return retval
34
+ func.errcheck = errcheck
35
+ return func(ob._geom, byref(size))
31
36
 
32
37
  def dump(ob, fp):
33
38
  """Dump a geometry to an open file."""
shapely/wkb.pyc CHANGED
Binary file
shapely/wkt.py CHANGED
@@ -4,7 +4,7 @@ Load/dump geometries using the well-known text (WKT) format.
4
4
 
5
5
  from ctypes import byref, c_int, c_size_t, c_char_p, string_at
6
6
 
7
- from shapely.geos import lgeos, ReadingError
7
+ from shapely.geos import lgeos, free, allocated_c_char_p, ReadingError
8
8
  from shapely.geometry.base import geom_factory
9
9
 
10
10
 
@@ -25,7 +25,14 @@ def load(fp):
25
25
 
26
26
  def dumps(ob):
27
27
  """Dump a WKB representation of a geometry to a byte string."""
28
- return string_at(lgeos.GEOSGeomToWKT(ob._geom))
28
+ func = lgeos.GEOSGeomToWKT
29
+ def errcheck(result, func, argtuple):
30
+ retval = result.value
31
+ free(result)
32
+ return retval
33
+ func.restype = allocated_c_char_p
34
+ func.errcheck = errcheck
35
+ return lgeos.GEOSGeomToWKT(ob._geom)
29
36
 
30
37
  def dump(ob, fp):
31
38
  """Dump a geometry to an open file."""
shapely/wkt.pyc CHANGED
Binary file