shapely 1.2.13__py2.6-win-amd64.egg → 1.2.18__py2.6-win-amd64.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.
Files changed (122) hide show
  1. EGG-INFO/PKG-INFO +451 -376
  2. EGG-INFO/native_libs.txt +2 -0
  3. EGG-INFO/not-zip-safe +1 -1
  4. shapely/DLLs/geos.dll +0 -0
  5. shapely/DLLs/geos_c.dll +0 -0
  6. shapely/__init__.py +1 -2
  7. shapely/__init__.pyc +0 -0
  8. shapely/affinity.py +252 -0
  9. shapely/affinity.pyc +0 -0
  10. shapely/algorithms/__init__.pyc +0 -0
  11. shapely/algorithms/cga.pyc +0 -0
  12. shapely/coords.py +53 -21
  13. shapely/coords.pyc +0 -0
  14. shapely/ctypes_declarations.py +16 -3
  15. shapely/ctypes_declarations.pyc +0 -0
  16. shapely/examples/__init__.pyc +0 -0
  17. shapely/examples/dissolve.pyc +0 -0
  18. shapely/examples/geoms.pyc +0 -0
  19. shapely/examples/intersect.pyc +0 -0
  20. shapely/examples/world.pyc +0 -0
  21. shapely/ftools.pyc +0 -0
  22. shapely/geometry/__init__.py +4 -4
  23. shapely/geometry/__init__.pyc +0 -0
  24. shapely/geometry/base.py +155 -54
  25. shapely/geometry/base.pyc +0 -0
  26. shapely/geometry/collection.pyc +0 -0
  27. shapely/geometry/geo.py +2 -2
  28. shapely/geometry/geo.pyc +0 -0
  29. shapely/geometry/linestring.py +24 -19
  30. shapely/geometry/linestring.pyc +0 -0
  31. shapely/geometry/multilinestring.py +2 -2
  32. shapely/geometry/multilinestring.pyc +0 -0
  33. shapely/geometry/multipoint.py +4 -0
  34. shapely/geometry/multipoint.pyc +0 -0
  35. shapely/geometry/multipolygon.py +8 -5
  36. shapely/geometry/multipolygon.pyc +0 -0
  37. shapely/geometry/point.py +7 -0
  38. shapely/geometry/point.pyc +0 -0
  39. shapely/geometry/polygon.py +28 -9
  40. shapely/geometry/polygon.pyc +0 -0
  41. shapely/geometry/proxy.py +1 -3
  42. shapely/geometry/proxy.pyc +0 -0
  43. shapely/geos.py +45 -14
  44. shapely/geos.pyc +0 -0
  45. shapely/impl.py +8 -5
  46. shapely/impl.pyc +0 -0
  47. shapely/iterops.pyc +0 -0
  48. shapely/linref.pyc +0 -0
  49. shapely/ops.py +125 -3
  50. shapely/ops.pyc +0 -0
  51. shapely/predicates.pyc +0 -0
  52. shapely/prepared.pyc +0 -0
  53. shapely/speedups/__init__.pyc +0 -0
  54. shapely/speedups/_speedups.c +5201 -0
  55. shapely/speedups/_speedups.pyc +0 -0
  56. shapely/speedups/_speedups.pyd +0 -0
  57. shapely/tests/Array.txt +86 -0
  58. shapely/tests/GeoInterface.txt +69 -0
  59. shapely/tests/IterOps.txt +31 -0
  60. shapely/tests/LineString.txt +134 -0
  61. shapely/tests/MultiLineString.txt +81 -0
  62. shapely/tests/MultiPoint.txt +101 -0
  63. shapely/tests/MultiPolygon.txt +71 -0
  64. shapely/tests/Operations.txt +89 -0
  65. shapely/tests/Operators.txt +18 -0
  66. shapely/tests/Persist.txt +35 -0
  67. shapely/tests/Point.txt +148 -0
  68. shapely/tests/Polygon.txt +143 -0
  69. shapely/tests/Predicates.txt +51 -0
  70. shapely/tests/__init__.py +10 -1
  71. shapely/tests/__init__.pyc +0 -0
  72. shapely/tests/attribute-chains.txt +38 -0
  73. shapely/tests/binascii_hex.txt +47 -0
  74. shapely/tests/cascaded_union.txt +26 -0
  75. shapely/tests/dimensions.txt +17 -0
  76. shapely/tests/invalid_intersection.txt +29 -0
  77. shapely/tests/linemerge.txt +61 -0
  78. shapely/tests/polygonize.txt +40 -0
  79. shapely/tests/test_affinity.py +239 -0
  80. shapely/tests/test_affinity.pyc +0 -0
  81. shapely/tests/test_box.pyc +0 -0
  82. shapely/tests/test_cga.pyc +0 -0
  83. shapely/tests/test_collection.py +15 -0
  84. shapely/tests/test_collection.pyc +0 -0
  85. shapely/tests/test_delegated.pyc +0 -0
  86. shapely/tests/test_dlls.py +1 -1
  87. shapely/tests/test_dlls.pyc +0 -0
  88. shapely/tests/test_doctests.pyc +0 -0
  89. shapely/tests/test_emptiness.py +41 -8
  90. shapely/tests/test_emptiness.pyc +0 -0
  91. shapely/tests/test_equality.pyc +0 -0
  92. shapely/tests/test_geomseq.pyc +0 -0
  93. shapely/tests/test_getitem.py +113 -0
  94. shapely/tests/test_getitem.pyc +0 -0
  95. shapely/tests/test_linear_referencing.pyc +0 -0
  96. shapely/tests/test_mapping.pyc +0 -0
  97. shapely/tests/test_ndarrays.py +35 -0
  98. shapely/tests/test_ndarrays.pyc +0 -0
  99. shapely/tests/test_pickle.py +15 -0
  100. shapely/tests/test_pickle.pyc +0 -0
  101. shapely/tests/test_prepared.pyc +0 -0
  102. shapely/tests/test_products_z.pyc +0 -0
  103. shapely/tests/test_singularity.pyc +0 -0
  104. shapely/tests/test_speedups.pyc +0 -0
  105. shapely/tests/test_styles.py +17 -0
  106. shapely/tests/test_styles.pyc +0 -0
  107. shapely/tests/test_transform.py +61 -0
  108. shapely/tests/test_transform.pyc +0 -0
  109. shapely/tests/test_unary_union.py +40 -0
  110. shapely/tests/test_unary_union.pyc +0 -0
  111. shapely/tests/test_validation.pyc +0 -0
  112. shapely/tests/test_xy.pyc +0 -0
  113. shapely/tests/threading_test.pyc +0 -0
  114. shapely/tests/wkt_locale.txt +28 -0
  115. shapely/topology.pyc +0 -0
  116. shapely/validation.pyc +0 -0
  117. shapely/wkb.py +3 -17
  118. shapely/wkb.pyc +0 -0
  119. shapely/wkt.py +3 -13
  120. shapely/wkt.pyc +0 -0
  121. DLLs/geos.dll +0 -0
  122. DLLs/geos_c.dll +0 -0
shapely/geometry/base.py CHANGED
@@ -1,24 +1,24 @@
1
1
  """Base geometry class and utilities
2
2
  """
3
3
 
4
+ from ctypes import pointer, c_size_t, c_char_p, c_void_p
4
5
  import sys
5
6
  import warnings
6
7
 
7
8
  from shapely.coords import CoordinateSequence
8
9
  from shapely.ftools import wraps
9
- from shapely.geos import lgeos
10
+ from shapely.geos import lgeos, ReadingError
10
11
  from shapely.impl import DefaultImplementation, delegated
11
- from shapely import wkb, wkt
12
12
 
13
13
  GEOMETRY_TYPES = [
14
14
  'Point',
15
- 'LineString',
16
- 'LinearRing',
17
- 'Polygon',
18
- 'MultiPoint',
19
- 'MultiLineString',
20
- 'MultiPolygon',
21
- 'GeometryCollection'
15
+ 'LineString',
16
+ 'LinearRing',
17
+ 'Polygon',
18
+ 'MultiPoint',
19
+ 'MultiLineString',
20
+ 'MultiPolygon',
21
+ 'GeometryCollection'
22
22
  ]
23
23
 
24
24
  def geometry_type_name(g):
@@ -34,9 +34,9 @@ def geom_factory(g, parent=None):
34
34
  geom_type = geometry_type_name(g)
35
35
  # TODO: check cost of dynamic import by profiling
36
36
  mod = __import__(
37
- 'shapely.geometry',
38
- globals(),
39
- locals(),
37
+ 'shapely.geometry',
38
+ globals(),
39
+ locals(),
40
40
  [geom_type],
41
41
  )
42
42
  ob.__class__ = getattr(mod, geom_type)
@@ -48,6 +48,34 @@ def geom_factory(g, parent=None):
48
48
  ob._ndim = 2
49
49
  return ob
50
50
 
51
+ def geom_from_wkt(data):
52
+ geom = lgeos.GEOSGeomFromWKT(c_char_p(data))
53
+ if not geom:
54
+ raise ReadingError, \
55
+ "Could not create geometry because of errors while reading input."
56
+ return geom_factory(geom)
57
+
58
+ def geom_to_wkt(ob):
59
+ if ob is None or ob._geom is None:
60
+ raise ValueError("Null geometry supports no operations")
61
+ return lgeos.GEOSGeomToWKT(ob._geom)
62
+
63
+ def deserialize_wkb(data):
64
+ geom = lgeos.GEOSGeomFromWKB_buf(c_char_p(data), c_size_t(len(data)));
65
+ if not geom:
66
+ raise ReadingError(
67
+ "Could not create geometry because of errors while reading input.")
68
+ return geom
69
+
70
+ def geom_from_wkb(data):
71
+ return geom_factory(deserialize_wkb(data))
72
+
73
+ def geom_to_wkb(ob):
74
+ if ob is None or ob._geom is None:
75
+ raise ValueError("Null geometry supports no operations")
76
+ size = c_size_t()
77
+ return lgeos.GEOSGeomToWKB_buf(c_void_p(ob._geom), pointer(size))
78
+
51
79
  def exceptNull(func):
52
80
  """Decorator which helps avoid GEOS operations on null pointers."""
53
81
  @wraps(func)
@@ -57,7 +85,17 @@ def exceptNull(func):
57
85
  return func(*args, **kwargs)
58
86
  return wrapper
59
87
 
60
- EMPTY = wkb.deserialize('010700000000000000'.decode('hex'))
88
+ class CAP_STYLE(object):
89
+ round = 1
90
+ flat = 2
91
+ square = 3
92
+
93
+ class JOIN_STYLE(object):
94
+ round = 1
95
+ mitre = 2
96
+ bevel = 3
97
+
98
+ EMPTY = deserialize_wkb('010700000000000000'.decode('hex'))
61
99
 
62
100
  class BaseGeometry(object):
63
101
  """
@@ -89,7 +127,7 @@ class BaseGeometry(object):
89
127
  _ndim = None
90
128
  _crs = None
91
129
  _owned = False
92
-
130
+
93
131
  # Backend config
94
132
  impl = DefaultImplementation
95
133
 
@@ -124,8 +162,12 @@ class BaseGeometry(object):
124
162
 
125
163
  def __setstate__(self, state):
126
164
  self.empty()
127
- self.__geom__ = wkb.deserialize(state)
128
-
165
+ self.__geom__ = deserialize_wkb(state)
166
+ if lgeos.methods['has_z'](self.__geom__):
167
+ self._ndim = 3
168
+ else:
169
+ self._ndim = 2
170
+
129
171
  # The _geom property
130
172
  def _get_geom(self):
131
173
  return self.__geom__
@@ -134,6 +176,21 @@ class BaseGeometry(object):
134
176
  self.__geom__ = val
135
177
  _geom = property(_get_geom, _set_geom)
136
178
 
179
+ # Operators
180
+ # ---------
181
+
182
+ def __and__(self, other):
183
+ return self.intersection(other)
184
+
185
+ def __or__(self, other):
186
+ return self.union(other)
187
+
188
+ def __sub__(self, other):
189
+ return self.difference(other)
190
+
191
+ def __xor__(self, other):
192
+ return self.symmetric_difference(other)
193
+
137
194
  # Array and ctypes interfaces
138
195
  # ---------------------------
139
196
 
@@ -194,18 +251,18 @@ class BaseGeometry(object):
194
251
 
195
252
  def geometryType(self):
196
253
  return geometry_type_name(self._geom)
197
-
254
+
198
255
  @property
199
256
  def type(self):
200
257
  return self.geometryType()
201
258
 
202
259
  def to_wkb(self):
203
- return wkb.dumps(self)
260
+ return geom_to_wkb(self)
204
261
 
205
262
  def to_wkt(self):
206
- return wkt.dumps(self)
263
+ return geom_to_wkt(self)
207
264
 
208
- geom_type = property(geometryType,
265
+ geom_type = property(geometryType,
209
266
  doc="""Name of the geometry's type, such as 'Point'"""
210
267
  )
211
268
  wkt = property(to_wkt,
@@ -236,7 +293,7 @@ class BaseGeometry(object):
236
293
  @property
237
294
  def boundary(self):
238
295
  """Returns a lower dimension geometry that bounds the object
239
-
296
+
240
297
  The boundary of a polygon is a line, the boundary of a line is a
241
298
  collection of points. The boundary of a point is an empty (null)
242
299
  collection.
@@ -250,7 +307,7 @@ class BaseGeometry(object):
250
307
  return ()
251
308
  else:
252
309
  return self.impl['bounds'](self)
253
-
310
+
254
311
  @property
255
312
  def centroid(self):
256
313
  """Returns the geometric center of the object"""
@@ -263,12 +320,12 @@ class BaseGeometry(object):
263
320
 
264
321
  @property
265
322
  def convex_hull(self):
266
- """Imagine an elastic band stretched around the geometry: that's a
323
+ """Imagine an elastic band stretched around the geometry: that's a
267
324
  convex hull, more or less
268
325
 
269
326
  The convex hull of a three member multipoint, for example, is a
270
327
  triangular polygon.
271
- """
328
+ """
272
329
  return geom_factory(self.impl['convex_hull'](self))
273
330
 
274
331
  @property
@@ -276,16 +333,32 @@ class BaseGeometry(object):
276
333
  """A figure that envelopes the geometry"""
277
334
  return geom_factory(self.impl['envelope'](self))
278
335
 
279
- def buffer(self, distance, resolution=16, quadsegs=None):
280
- """Returns a geometry with an envelope at a distance from the object's
336
+ def buffer(self, distance, resolution=16, quadsegs=None,
337
+ cap_style=CAP_STYLE.round, join_style=JOIN_STYLE.round,
338
+ mitre_limit=0):
339
+ """Returns a geometry with an envelope at a distance from the object's
281
340
  envelope
282
-
341
+
283
342
  A negative distance has a "shrink" effect. A zero distance may be used
284
343
  to "tidy" a polygon. The resolution of the buffer around each vertex of
285
344
  the object increases by increasing the resolution keyword parameter
286
345
  or second positional parameter. Note: the use of a `quadsegs` parameter
287
346
  is deprecated and will be gone from the next major release.
288
347
 
348
+ The styles of caps are: CAP_STYLE.round (1), CAP_STYLE.flat (2), and
349
+ CAP_STYLE.square (3).
350
+
351
+ The styles of joins between offset segments are: JOIN_STYLE.round (1),
352
+ JOIN_STYLE.mitre (2), and JOIN_STYLE.bevel (3).
353
+
354
+ The mitre limit ratio is used for very sharp corners. The mitre ratio
355
+ is the ratio of the distance from the corner to the end of the mitred
356
+ offset corner. When two line segments meet at a sharp angle, a miter
357
+ join will extend the original geometry. To prevent unreasonable
358
+ geometry, the mitre limit allows controlling the maximum length of the
359
+ join corner. Corners with a ratio which exceed the limit will be
360
+ beveled.
361
+
289
362
  Example:
290
363
 
291
364
  >>> from shapely.wkt import loads
@@ -296,19 +369,35 @@ class BaseGeometry(object):
296
369
  3.1415138011443009
297
370
  >>> g.buffer(1.0, 3).area # triangle approximation
298
371
  3.0
372
+ >>> list(g.buffer(1.0, cap_style='square').exterior.coords)
373
+ [(1.0, 1.0), (1.0, -1.0), (-1.0, -1.0), (-1.0, 1.0), (1.0, 1.0)]
374
+ >>> g.buffer(1.0, cap_style='square').area
375
+ 4.0
299
376
  """
377
+
300
378
  if quadsegs is not None:
301
379
  warnings.warn(
302
- "The `quadsegs` argument is deprecated. Use `resolution`.",
380
+ "The `quadsegs` argument is deprecated. Use `resolution`.",
303
381
  DeprecationWarning)
304
382
  res = quadsegs
305
383
  else:
306
384
  res = resolution
307
- return geom_factory(self.impl['buffer'](self, distance, res))
385
+
386
+ if cap_style == CAP_STYLE.round and join_style == JOIN_STYLE.round:
387
+ return geom_factory(self.impl['buffer'](self, distance, res))
388
+
389
+ if 'buffer_with_style' not in self.impl:
390
+ raise NotImplementedError("Styled buffering not available for "
391
+ "GEOS versions < 3.2.")
392
+
393
+ return geom_factory(self.impl['buffer_with_style'](self, distance, res,
394
+ cap_style,
395
+ join_style,
396
+ mitre_limit))
308
397
 
309
398
  @delegated
310
399
  def simplify(self, tolerance, preserve_topology=True):
311
- """Returns a simplified geometry produced by the Douglas-Puecker
400
+ """Returns a simplified geometry produced by the Douglas-Puecker
312
401
  algorithm
313
402
 
314
403
  Coordinates of the simplified geometry will be no more than the
@@ -328,13 +417,13 @@ class BaseGeometry(object):
328
417
  def difference(self, other):
329
418
  """Returns the difference of the geometries"""
330
419
  return geom_factory(self.impl['difference'](self, other))
331
-
420
+
332
421
  def intersection(self, other):
333
422
  """Returns the intersection of the geometries"""
334
423
  return geom_factory(self.impl['intersection'](self, other))
335
424
 
336
425
  def symmetric_difference(self, other):
337
- """Returns the symmetric difference of the geometries
426
+ """Returns the symmetric difference of the geometries
338
427
  (Shapely geometry)"""
339
428
  return geom_factory(self.impl['symmetric_difference'](self, other))
340
429
 
@@ -354,7 +443,7 @@ class BaseGeometry(object):
354
443
  @property
355
444
  def is_empty(self):
356
445
  """True if the set of points in this geometry is empty, else False"""
357
- return bool(self.impl['is_empty'](self)) or (self._geom is None)
446
+ return (self._geom is None) or bool(self.impl['is_empty'](self))
358
447
 
359
448
  @property
360
449
  def is_ring(self):
@@ -363,13 +452,13 @@ class BaseGeometry(object):
363
452
 
364
453
  @property
365
454
  def is_simple(self):
366
- """True if the geometry is simple, meaning that any self-intersections
455
+ """True if the geometry is simple, meaning that any self-intersections
367
456
  are only at boundary points, else False"""
368
457
  return bool(self.impl['is_simple'](self))
369
458
 
370
459
  @property
371
460
  def is_valid(self):
372
- """True if the geometry is valid (definition depends on sub-class),
461
+ """True if the geometry is valid (definition depends on sub-class),
373
462
  else False"""
374
463
  return bool(self.impl['is_valid'](self))
375
464
 
@@ -377,7 +466,7 @@ class BaseGeometry(object):
377
466
  # -----------------
378
467
 
379
468
  def relate(self, other):
380
- """Returns the DE-9IM intersection matrix for the two geometries
469
+ """Returns the DE-9IM intersection matrix for the two geometries
381
470
  (string)"""
382
471
  return self.impl['relate'](self, other)
383
472
 
@@ -414,13 +503,13 @@ class BaseGeometry(object):
414
503
  return bool(self.impl['within'](self, other))
415
504
 
416
505
  def equals_exact(self, other, tolerance):
417
- """Returns True if geometries are equal to within a specified
506
+ """Returns True if geometries are equal to within a specified
418
507
  tolerance"""
419
508
  # return BinaryPredicateOp('equals_exact', self)(other, tolerance)
420
509
  return bool(self.impl['equals_exact'](self, other, tolerance))
421
510
 
422
511
  def almost_equals(self, other, decimal=6):
423
- """Returns True if geometries are equal at all coordinates to a
512
+ """Returns True if geometries are equal at all coordinates to a
424
513
  specified decimal place"""
425
514
  return self.equals_exact(other, 0.5 * 10**(-decimal))
426
515
 
@@ -429,22 +518,22 @@ class BaseGeometry(object):
429
518
 
430
519
  @delegated
431
520
  def project(self, other, normalized=False):
432
- """Returns the distance along this geometry to a point nearest the
521
+ """Returns the distance along this geometry to a point nearest the
433
522
  specified point
434
-
523
+
435
524
  If the normalized arg is True, return the distance normalized to the
436
525
  length of the linear geometry.
437
- """
526
+ """
438
527
  if normalized:
439
528
  op = self.impl['project_normalized']
440
529
  else:
441
530
  op = self.impl['project']
442
531
  return op(self, other)
443
-
532
+
444
533
  @delegated
445
534
  def interpolate(self, distance, normalized=False):
446
535
  """Return a point at the specified distance along a linear geometry
447
-
536
+
448
537
  If the normalized arg is True, the distance will be interpreted as a
449
538
  fraction of the geometry's length.
450
539
  """
@@ -537,7 +626,7 @@ class GeometrySequence(object):
537
626
  def _update(self):
538
627
  self._geom = self.__p__._geom
539
628
  self._ndim = self.__p__._ndim
540
-
629
+
541
630
  def _get_geom_item(self, i):
542
631
  g = self.shape_factory()
543
632
  g._owned = True
@@ -548,23 +637,35 @@ class GeometrySequence(object):
548
637
 
549
638
  def __iter__(self):
550
639
  self._update()
551
- for i in range(self.__len__()):
640
+ for i in xrange(self.__len__()):
552
641
  yield self._get_geom_item(i)
553
642
 
554
643
  def __len__(self):
555
644
  self._update()
556
645
  return lgeos.GEOSGetNumGeometries(self._geom)
557
646
 
558
- def __getitem__(self, i):
647
+ def __getitem__(self, key):
559
648
  self._update()
560
- M = self.__len__()
561
- if i + M < 0 or i >= M:
562
- raise IndexError("index out of range")
563
- if i < 0:
564
- ii = M + i
649
+ m = self.__len__()
650
+ if isinstance(key, int):
651
+ if key + m < 0 or key >= m:
652
+ raise IndexError("index out of range")
653
+ if key < 0:
654
+ i = m + key
655
+ else:
656
+ i = key
657
+ return self._get_geom_item(i)
658
+ elif isinstance(key, slice):
659
+ if type(self) == HeterogeneousGeometrySequence:
660
+ raise TypeError(
661
+ "Heterogenous geometry collections are not sliceable")
662
+ res = []
663
+ start, stop, stride = key.indices(m)
664
+ for i in xrange(start, stop, stride):
665
+ res.append(self._get_geom_item(i))
666
+ return type(self.__p__)(res or None)
565
667
  else:
566
- ii = i
567
- return self._get_geom_item(i)
668
+ raise TypeError("key must be an index or slice")
568
669
 
569
670
  @property
570
671
  def _longest(self):
@@ -585,7 +686,7 @@ class HeterogeneousGeometrySequence(GeometrySequence):
585
686
 
586
687
  def _get_geom_item(self, i):
587
688
  sub = lgeos.GEOSGetGeometryN(self._geom, i)
588
- g = geom_factory(sub)
689
+ g = geom_factory(sub, parent=self)
589
690
  g._owned = True
590
691
  return g
591
692
 
shapely/geometry/base.pyc CHANGED
Binary file
Binary file
shapely/geometry/geo.py CHANGED
@@ -11,14 +11,14 @@ from multipolygon import MultiPolygon, MultiPolygonAdapter
11
11
 
12
12
 
13
13
  def box(minx, miny, maxx, maxy, ccw=True):
14
- """Return a rectangular polygon with configurable normal vector"""
14
+ """Returns a rectangular polygon with configurable normal vector"""
15
15
  coords = [(maxx, miny), (maxx, maxy), (minx, maxy), (minx, miny)]
16
16
  if not ccw:
17
17
  coords = coords[::-1]
18
18
  return Polygon(coords)
19
19
 
20
20
  def shape(context):
21
- """Return a new, independent geometry with coordinates *copied* from the
21
+ """Returns a new, independent geometry with coordinates *copied* from the
22
22
  context.
23
23
  """
24
24
  if hasattr(context, "__geo_interface__"):
shapely/geometry/geo.pyc CHANGED
Binary file
@@ -4,8 +4,9 @@
4
4
  from ctypes import c_double, cast, POINTER
5
5
  from ctypes import ArgumentError
6
6
 
7
+ from shapely.coords import required
7
8
  from shapely.geos import lgeos, TopologicalError
8
- from shapely.geometry.base import BaseGeometry, geom_factory
9
+ from shapely.geometry.base import BaseGeometry, geom_factory, JOIN_STYLE
9
10
  from shapely.geometry.proxy import CachingGeometryProxy
10
11
 
11
12
  __all__ = ['LineString', 'asLineString']
@@ -14,7 +15,7 @@ __all__ = ['LineString', 'asLineString']
14
15
  class LineString(BaseGeometry):
15
16
  """
16
17
  A one-dimensional figure comprising one or more line segments
17
-
18
+
18
19
  A LineString has non-zero length and zero area. It may approximate a curve
19
20
  and need not be straight. Unlike a LinearRing, a LineString is not closed.
20
21
  """
@@ -56,7 +57,7 @@ class LineString(BaseGeometry):
56
57
  def array_interface(self):
57
58
  """Provide the Numpy array protocol."""
58
59
  return self.coords.array_interface()
59
-
60
+
60
61
  __array_interface__ = property(array_interface)
61
62
 
62
63
  # Coordinate access
@@ -69,9 +70,9 @@ class LineString(BaseGeometry):
69
70
  @property
70
71
  def xy(self):
71
72
  """Separate arrays of X and Y coordinate values
72
-
73
+
73
74
  Example:
74
-
75
+
75
76
  >>> x, y = LineString(((0, 0), (1, 1))).xy
76
77
  >>> list(x)
77
78
  [0.0, 1.0]
@@ -79,22 +80,23 @@ class LineString(BaseGeometry):
79
80
  [0.0, 1.0]
80
81
  """
81
82
  return self.coords.xy
82
-
83
+
83
84
  def parallel_offset(
84
- self, distance, side,
85
- resolution=16, join_style=1, mitre_limit=1.0):
86
-
85
+ self, distance, side,
86
+ resolution=16, join_style=JOIN_STYLE.round, mitre_limit=1.0):
87
+
87
88
  """Returns a LineString or MultiLineString geometry at a distance from
88
89
  the object on its right or its left side.
89
-
90
+
90
91
  Distance must be a positive float value. The side parameter may be
91
92
  'left' or 'right'. The resolution of the buffer around each vertex of
92
93
  the object increases by increasing the resolution keyword parameter or
93
94
  third positional parameter.
94
-
95
+
95
96
  The join style is for outside corners between line segments. Accepted
96
- values are 1 => ROUND, 2 => MITRE, 3 => BEVEL.
97
-
97
+ values are JOIN_STYLE.round (1), JOIN_STYLE.mitre (2), and
98
+ JOIN_STYLE.bevel (3).
99
+
98
100
  The mitre ratio limit is used for very sharp corners. It is the ratio
99
101
  of the distance from the corner to the end of the mitred offset corner.
100
102
  When two line segments meet at a sharp angle, a miter join will extend
@@ -104,11 +106,11 @@ class LineString(BaseGeometry):
104
106
 
105
107
  try:
106
108
  return geom_factory(self.impl['parallel_offset'](
107
- self, distance, resolution, join_style, mitre_limit,
109
+ self, distance, resolution, join_style, mitre_limit,
108
110
  bool(side=='left')))
109
111
  except WindowsError:
110
112
  raise TopologicalError()
111
-
113
+
112
114
 
113
115
  class LineStringAdapter(CachingGeometryProxy, LineString):
114
116
 
@@ -151,6 +153,9 @@ def asLineString(context):
151
153
 
152
154
 
153
155
  def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
156
+ # If numpy is present, we use numpy.require to ensure that we have a
157
+ # C-continguous array that owns its data. View data will be copied.
158
+ ob = required(ob)
154
159
  try:
155
160
  # From array protocol
156
161
  array = ob.__array_interface__
@@ -194,7 +199,7 @@ def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
194
199
  except IndexError:
195
200
  raise ValueError("Inconsistent coordinate dimensionality")
196
201
 
197
- # Because of a bug in the GEOS C API,
202
+ # Because of a bug in the GEOS C API,
198
203
  # always set X before Y
199
204
  lgeos.GEOSCoordSeq_setX(cs, i, dx)
200
205
  lgeos.GEOSCoordSeq_setY(cs, i, dy)
@@ -223,11 +228,11 @@ def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
223
228
  % update_ndim)
224
229
  else:
225
230
  cs = lgeos.GEOSCoordSeq_create(m, n)
226
-
231
+
227
232
  # add to coordinate sequence
228
233
  for i in xrange(m):
229
234
  coords = ob[i]
230
- # Because of a bug in the GEOS C API,
235
+ # Because of a bug in the GEOS C API,
231
236
  # always set X before Y
232
237
  lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
233
238
  lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
@@ -236,7 +241,7 @@ def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
236
241
  lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
237
242
  except IndexError:
238
243
  raise ValueError("Inconsistent coordinate dimensionality")
239
-
244
+
240
245
  if update_geom is not None:
241
246
  return None
242
247
  else:
Binary file
@@ -40,8 +40,8 @@ class MultiLineString(BaseMultipartGeometry):
40
40
  """
41
41
  super(MultiLineString, self).__init__()
42
42
 
43
- if lines is None:
44
- # allow creation of null lines, to support unpickling
43
+ if not lines:
44
+ # allow creation of empty multilinestrings, to support unpickling
45
45
  pass
46
46
  else:
47
47
  self._geom, self._ndim = geos_multilinestring_from_py(lines)
Binary file
@@ -4,6 +4,7 @@
4
4
  from ctypes import byref, c_double, c_void_p, cast, POINTER
5
5
  from ctypes import ArgumentError
6
6
 
7
+ from shapely.coords import required
7
8
  from shapely.geos import lgeos
8
9
  from shapely.geometry.base import BaseMultipartGeometry, exceptNull
9
10
  from shapely.geometry.point import Point, geos_point_from_py
@@ -128,6 +129,9 @@ def asMultiPoint(context):
128
129
 
129
130
 
130
131
  def geos_multipoint_from_py(ob):
132
+ # If numpy is present, we use numpy.require to ensure that we have a
133
+ # C-continguous array that owns its data. View data will be copied.
134
+ ob = required(ob)
131
135
  try:
132
136
  # From array protocol
133
137
  array = ob.__array_interface__
Binary file
@@ -50,8 +50,8 @@ class MultiPolygon(BaseMultipartGeometry):
50
50
  """
51
51
  super(MultiPolygon, self).__init__()
52
52
 
53
- if polygons is None:
54
- # allow creation of null collections, to support unpickling
53
+ if not polygons:
54
+ # allow creation of empty multipolygons, to support unpickling
55
55
  pass
56
56
  elif context_type == 'polygons':
57
57
  self._geom, self._ndim = geos_multipolygon_from_polygons(polygons)
@@ -69,7 +69,7 @@ class MultiPolygon(BaseMultipartGeometry):
69
69
  coords.append(tuple(geom.exterior.coords))
70
70
  for hole in geom.interiors:
71
71
  coords.append(tuple(hole.coords))
72
- allcoords.append(coords)
72
+ allcoords.append(tuple(coords))
73
73
  return {
74
74
  'type': 'MultiPolygon',
75
75
  'coordinates': allcoords
@@ -109,8 +109,9 @@ def asMultiPolygon(context):
109
109
  def geos_multipolygon_from_py(ob):
110
110
  """ob must provide Python geo interface coordinates."""
111
111
  L = len(ob)
112
- N = len(ob[0][0][0])
113
112
  assert L >= 1
113
+
114
+ N = len(ob[0][0][0])
114
115
  assert N == 2 or N == 3
115
116
 
116
117
  subs = (c_void_p * L)()
@@ -124,12 +125,14 @@ def geos_multipolygon_from_polygons(ob):
124
125
  """ob must be either a sequence or array of sequences or arrays."""
125
126
  obs = getattr(ob, 'geoms', None) or ob
126
127
  L = len(obs)
128
+ assert L >= 1
129
+
127
130
  exemplar = obs[0]
128
131
  try:
129
132
  N = len(exemplar[0][0])
130
133
  except TypeError:
131
134
  N = exemplar._ndim
132
- assert L >= 1
135
+
133
136
  assert N == 2 or N == 3
134
137
 
135
138
  subs = (c_void_p * L)()
Binary file