shapely 1.5.5__tar.gz → 1.5.7__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 (110) hide show
  1. {Shapely-1.5.5 → Shapely-1.5.7}/CHANGES.txt +9 -0
  2. {Shapely-1.5.5/Shapely.egg-info → Shapely-1.5.7}/PKG-INFO +10 -1
  3. {Shapely-1.5.5 → Shapely-1.5.7/Shapely.egg-info}/PKG-INFO +10 -1
  4. {Shapely-1.5.5 → Shapely-1.5.7}/Shapely.egg-info/SOURCES.txt +2 -0
  5. Shapely-1.5.7/VERSION.txt +1 -0
  6. {Shapely-1.5.5 → Shapely-1.5.7}/setup.py +2 -75
  7. Shapely-1.5.7/shapely/__init__.py +1 -0
  8. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/ctypes_declarations.py +1 -1
  9. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/geometry/base.py +54 -31
  10. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/geometry/linestring.py +18 -15
  11. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/geometry/multilinestring.py +17 -19
  12. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/geometry/multipoint.py +17 -21
  13. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/geometry/multipolygon.py +17 -22
  14. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/geometry/point.py +18 -18
  15. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/geometry/polygon.py +22 -14
  16. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/geos.py +28 -13
  17. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/speedups/_speedups.c +125 -135
  18. Shapely-1.5.7/tests/test_geos_err_handler.py +33 -0
  19. Shapely-1.5.7/tests/test_svg.py +192 -0
  20. Shapely-1.5.5/VERSION.txt +0 -1
  21. Shapely-1.5.5/shapely/__init__.py +0 -1
  22. {Shapely-1.5.5 → Shapely-1.5.7}/CREDITS.txt +0 -0
  23. {Shapely-1.5.5 → Shapely-1.5.7}/LICENSE.txt +0 -0
  24. {Shapely-1.5.5 → Shapely-1.5.7}/README.rst +0 -0
  25. {Shapely-1.5.5 → Shapely-1.5.7}/Shapely.egg-info/dependency_links.txt +0 -0
  26. {Shapely-1.5.5 → Shapely-1.5.7}/Shapely.egg-info/top_level.txt +0 -0
  27. {Shapely-1.5.5 → Shapely-1.5.7}/docs/design.rst +0 -0
  28. {Shapely-1.5.5 → Shapely-1.5.7}/docs/index.rst +0 -0
  29. {Shapely-1.5.5 → Shapely-1.5.7}/docs/manual.rst +0 -0
  30. {Shapely-1.5.5 → Shapely-1.5.7}/docs/project.rst +0 -0
  31. {Shapely-1.5.5 → Shapely-1.5.7}/setup.cfg +1 -1
  32. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/_geos.pxi +0 -0
  33. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/affinity.py +0 -0
  34. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/algorithms/__init__.py +0 -0
  35. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/algorithms/cga.py +0 -0
  36. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/coords.py +0 -0
  37. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/examples/__init__.py +0 -0
  38. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/examples/dissolve.py +0 -0
  39. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/examples/geoms.py +0 -0
  40. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/examples/intersect.py +0 -0
  41. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/ftools.py +0 -0
  42. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/geometry/__init__.py +0 -0
  43. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/geometry/collection.py +0 -0
  44. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/geometry/geo.py +0 -0
  45. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/geometry/proxy.py +0 -0
  46. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/impl.py +0 -0
  47. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/iterops.py +0 -0
  48. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/linref.py +0 -0
  49. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/ops.py +0 -0
  50. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/predicates.py +0 -0
  51. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/prepared.py +0 -0
  52. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/speedups/__init__.py +0 -0
  53. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/speedups/_speedups.pyx +0 -0
  54. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/strtree.py +0 -0
  55. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/topology.py +0 -0
  56. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/validation.py +0 -0
  57. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/vectorized/__init__.py +0 -0
  58. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/vectorized/_vectorized.pyx +0 -0
  59. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/wkb.py +0 -0
  60. {Shapely-1.5.5 → Shapely-1.5.7}/shapely/wkt.py +0 -0
  61. {Shapely-1.5.5 → Shapely-1.5.7}/tests/__init__.py +0 -0
  62. {Shapely-1.5.5 → Shapely-1.5.7}/tests/binascii_hex.txt +0 -0
  63. {Shapely-1.5.5 → Shapely-1.5.7}/tests/conftest.py +0 -0
  64. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_affinity.py +0 -0
  65. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_box.py +0 -0
  66. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_cga.py +0 -0
  67. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_collection.py +0 -0
  68. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_coords.py +0 -0
  69. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_delaunay.py +0 -0
  70. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_delegated.py +0 -0
  71. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_dlls.py +0 -0
  72. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_doctests.py +0 -0
  73. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_emptiness.py +0 -0
  74. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_equality.py +0 -0
  75. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_geointerface.py +0 -0
  76. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_geomseq.py +0 -0
  77. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_getitem.py +0 -0
  78. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_hash.py +0 -0
  79. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_invalid_geometries.py +0 -0
  80. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_iterops.py +0 -0
  81. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_linear_referencing.py +0 -0
  82. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_linemerge.py +0 -0
  83. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_linestring.py +0 -0
  84. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_locale.py +0 -0
  85. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_mapping.py +0 -0
  86. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_multilinestring.py +0 -0
  87. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_multipoint.py +0 -0
  88. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_multipolygon.py +0 -0
  89. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_ndarrays.py +0 -0
  90. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_nearest.py +0 -0
  91. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_operations.py +0 -0
  92. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_operators.py +0 -0
  93. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_persist.py +0 -0
  94. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_pickle.py +0 -0
  95. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_point.py +0 -0
  96. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_polygon.py +0 -0
  97. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_polygonize.py +0 -0
  98. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_predicates.py +0 -0
  99. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_prepared.py +0 -0
  100. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_products_z.py +0 -0
  101. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_singularity.py +0 -0
  102. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_snap.py +0 -0
  103. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_strtree.py +0 -0
  104. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_styles.py +0 -0
  105. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_transform.py +0 -0
  106. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_union.py +0 -0
  107. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_validation.py +0 -0
  108. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_vectorized.py +0 -0
  109. {Shapely-1.5.5 → Shapely-1.5.7}/tests/test_xy.py +0 -0
  110. {Shapely-1.5.5 → Shapely-1.5.7}/tests/threading_test.py +0 -0
@@ -1,6 +1,15 @@
1
1
  Changes
2
2
  =======
3
3
 
4
+ 1.5.6 (2015-03-16)
5
+ ------------------
6
+ - Test and fix buggy error and notice handlers (#249).
7
+
8
+ 1.5.6 (2015-02-02)
9
+ ------------------
10
+ - Fix setup regression (#232, #234).
11
+ - SVG representation improvements (#233, #237).
12
+
4
13
  1.5.5 (2015-01-20)
5
14
  ------------------
6
15
  - MANIFEST changes to restore _geox.pxi (#231).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: Shapely
3
- Version: 1.5.5
3
+ Version: 1.5.7
4
4
  Summary: Geometric objects, predicates, and operations
5
5
  Home-page: https://github.com/Toblerity/Shapely
6
6
  Author: Sean Gillies
@@ -215,6 +215,15 @@ Description: =======
215
215
  Changes
216
216
  =======
217
217
 
218
+ 1.5.6 (2015-03-16)
219
+ ------------------
220
+ - Test and fix buggy error and notice handlers (#249).
221
+
222
+ 1.5.6 (2015-02-02)
223
+ ------------------
224
+ - Fix setup regression (#232, #234).
225
+ - SVG representation improvements (#233, #237).
226
+
218
227
  1.5.5 (2015-01-20)
219
228
  ------------------
220
229
  - MANIFEST changes to restore _geox.pxi (#231).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: Shapely
3
- Version: 1.5.5
3
+ Version: 1.5.7
4
4
  Summary: Geometric objects, predicates, and operations
5
5
  Home-page: https://github.com/Toblerity/Shapely
6
6
  Author: Sean Gillies
@@ -215,6 +215,15 @@ Description: =======
215
215
  Changes
216
216
  =======
217
217
 
218
+ 1.5.6 (2015-03-16)
219
+ ------------------
220
+ - Test and fix buggy error and notice handlers (#249).
221
+
222
+ 1.5.6 (2015-02-02)
223
+ ------------------
224
+ - Fix setup regression (#232, #234).
225
+ - SVG representation improvements (#233, #237).
226
+
218
227
  1.5.5 (2015-01-20)
219
228
  ------------------
220
229
  - MANIFEST changes to restore _geox.pxi (#231).
@@ -68,6 +68,7 @@ tests/test_emptiness.py
68
68
  tests/test_equality.py
69
69
  tests/test_geointerface.py
70
70
  tests/test_geomseq.py
71
+ tests/test_geos_err_handler.py
71
72
  tests/test_getitem.py
72
73
  tests/test_hash.py
73
74
  tests/test_invalid_geometries.py
@@ -96,6 +97,7 @@ tests/test_singularity.py
96
97
  tests/test_snap.py
97
98
  tests/test_strtree.py
98
99
  tests/test_styles.py
100
+ tests/test_svg.py
99
101
  tests/test_transform.py
100
102
  tests/test_union.py
101
103
  tests/test_validation.py
@@ -0,0 +1 @@
1
+ 1.5.7
@@ -2,19 +2,15 @@
2
2
 
3
3
  from __future__ import print_function
4
4
 
5
- import ctypes
6
- import ctypes.util
7
5
  try:
8
6
  # If possible, use setuptools
9
7
  from setuptools import setup
10
8
  from setuptools.extension import Extension
11
9
  from setuptools.command.build_ext import build_ext as distutils_build_ext
12
- from setuptools.command.install import install
13
10
  except ImportError:
14
11
  from distutils.core import setup
15
12
  from distutils.extension import Extension
16
13
  from distutils.command.build_ext import build_ext as distutils_build_ext
17
- from distutils.command.install import install
18
14
  from distutils.cmd import Command
19
15
  from distutils.errors import CCompilerError, DistutilsExecError, \
20
16
  DistutilsPlatformError
@@ -23,7 +19,6 @@ import errno
23
19
  import glob
24
20
  import os
25
21
  import platform
26
- import re
27
22
  import shutil
28
23
  import subprocess
29
24
  import sys
@@ -58,74 +53,6 @@ with open('CHANGES.txt', 'r', **open_kwds) as fp:
58
53
 
59
54
  long_description = readme + '\n\n' + credits + '\n\n' + changes
60
55
 
61
- # Fail installation if we can't find a GEOS shared library with the right
62
- # version. We ship it with Shapely for Windows, so no need to check on that
63
- # platform. Code below copied from shapely/geos.py.
64
- class InstallCommand(install):
65
-
66
- def run(self):
67
- def load_dll(libname, fallbacks=None):
68
- lib = ctypes.util.find_library(libname)
69
- if lib is not None:
70
- try:
71
- return ctypes.CDLL(lib)
72
- except OSError:
73
- pass
74
- if fallbacks is not None:
75
- for name in fallbacks:
76
- try:
77
- return ctypes.CDLL(name)
78
- except OSError:
79
- # move on to the next fallback
80
- pass
81
- # No shared library was loaded. Raise OSError.
82
- raise OSError(
83
- "Could not find library %s or load any of its variants %s" % (
84
- libname, fallbacks or []))
85
-
86
- if sys.platform.startswith('linux'):
87
- _lgeos = load_dll(
88
- 'geos_c', fallbacks=['libgeos_c.so.1', 'libgeos_c.so'])
89
- elif sys.platform == 'darwin':
90
- if hasattr(sys, 'frozen'):
91
- # .app file from py2app
92
- alt_paths = [os.path.join(os.environ['RESOURCEPATH'],
93
- '..', 'Frameworks', 'libgeos_c.dylib')]
94
- else:
95
- alt_paths = [
96
- # The Framework build from Kyng Chaos:
97
- "/Library/Frameworks/GEOS.framework/Versions/Current/GEOS",
98
- # macports
99
- '/opt/local/lib/libgeos_c.dylib',
100
- ]
101
- _lgeos = load_dll('geos_c', fallbacks=alt_paths)
102
- elif sys.platform == 'sunos5':
103
- _lgeos = load_dll(
104
- 'geos_c', fallbacks=['libgeos_c.so.1', 'libgeos_c.so'])
105
- else: # other *nix systems
106
- _lgeos = load_dll(
107
- 'geos_c', fallbacks=['libgeos_c.so.1', 'libgeos_c.so'])
108
-
109
- GEOSversion = _lgeos.GEOSversion
110
- GEOSversion.restype = ctypes.c_char_p
111
- GEOSversion.argtypes = []
112
- geos_version_string = GEOSversion()
113
- if sys.version_info[0] >= 3:
114
- geos_version_string = geos_version_string.decode('ascii')
115
- res = re.findall(r'(\d+)\.(\d+)\.(\d+)', geos_version_string)
116
- assert len(res) == 2, res
117
- geos_version = tuple(int(x) for x in res[0])
118
- shapely_version = tuple(int(x) for x in version.split('.'))
119
-
120
- if shapely_version >= (1, 3):
121
- if geos_version >= (3, 3):
122
- install.run(self)
123
- else:
124
- print(
125
- "Shapely >= 1.3 requires GEOS >= 3.3. "
126
- "Install GEOS 3.3+ and reinstall Shapely.")
127
- sys.exit(1)
128
-
129
56
  setup_args = dict(
130
57
  name = 'Shapely',
131
58
  version = version,
@@ -147,7 +74,7 @@ setup_args = dict(
147
74
  'shapely.speedups',
148
75
  'shapely.vectorized',
149
76
  ],
150
- cmdclass = {'install': InstallCommand},
77
+ cmdclass = {},
151
78
  classifiers = [
152
79
  'Development Status :: 5 - Production/Stable',
153
80
  'Intended Audience :: Developers',
@@ -162,7 +89,7 @@ setup_args = dict(
162
89
  data_files = [('shapely', ['shapely/_geos.pxi'])]
163
90
  )
164
91
 
165
- # Add DLLs to Windows packages.
92
+ # Add DLLs for Windows
166
93
  if sys.platform == 'win32':
167
94
  try:
168
95
  os.mkdir('shapely/DLLs')
@@ -0,0 +1 @@
1
+ __version__ = "1.5.7"
@@ -14,7 +14,7 @@ class allocated_c_char_p(c_char_p):
14
14
  '''char pointer return type'''
15
15
  pass
16
16
 
17
- EXCEPTION_HANDLER_FUNCTYPE = CFUNCTYPE(None, c_char_p, c_char_p)
17
+ EXCEPTION_HANDLER_FUNCTYPE = CFUNCTYPE(None, c_char_p, c_void_p)
18
18
 
19
19
 
20
20
  def prototype(lgeos, geos_version):
@@ -353,35 +353,47 @@ class BaseGeometry(object):
353
353
  """WKB hex representation of the geometry"""
354
354
  return WKBWriter(lgeos).write_hex(self)
355
355
 
356
- def svg(self, scale_factor=1.):
357
- """
358
- SVG representation of the geometry. Scale factor is multiplied by
359
- the size of the SVG symbol so it can be scaled consistently for a
360
- consistent appearance based on the canvas size.
361
- """
356
+ def svg(self, scale_factor=1., **kwargs):
357
+ """Raises NotImplementedError"""
362
358
  raise NotImplementedError
363
359
 
364
360
  def _repr_svg_(self):
365
361
  """SVG representation for iPython notebook"""
366
- #Pick an arbitrary size for the SVG canvas
367
-
368
-
369
- xmin, ymin, xmax, ymax = self.buffer(1).bounds
370
- x_size = min([max([100., xmax - xmin]), 300])
371
- y_size = min([max([100., ymax - ymin]), 300])
372
- try:
373
- scale_factor = max([xmax - xmin, ymax - ymin]) / max([x_size, y_size])
374
- except ZeroDivisionError:
375
- scale_factor = 1
376
- buffered_box = "{0} {1} {2} {3}".format(xmin, ymin, xmax - xmin, ymax - ymin)
377
- return """<svg
378
- preserveAspectRatio="xMinYMin meet"
379
- viewBox="{0}"
380
- width="{1}"
381
- height="{2}"
382
- transform="translate(0, {1}),scale(1, -1)">
383
- {3}
384
- </svg>""".format(buffered_box, x_size, y_size, self.svg(scale_factor))
362
+ svg_top = '<svg xmlns="http://www.w3.org/2000/svg" ' \
363
+ 'xmlns:xlink="http://www.w3.org/1999/xlink" '
364
+ if self.is_empty:
365
+ return svg_top + '/>'
366
+ else:
367
+ # Establish SVG canvas that will fit all the data + small space
368
+ xmin, ymin, xmax, ymax = self.bounds
369
+ if xmin == xmax and ymin == ymax:
370
+ # This is a point; buffer using an arbitrary size
371
+ xmin, ymin, xmax, ymax = self.buffer(1).bounds
372
+ else:
373
+ # Expand bounds by a fraction of the data ranges
374
+ expand = 0.04 # or 4%, same as R plots
375
+ widest_part = max([xmax - xmin, ymax - ymin])
376
+ expand_amount = widest_part * expand
377
+ xmin -= expand_amount
378
+ ymin -= expand_amount
379
+ xmax += expand_amount
380
+ ymax += expand_amount
381
+ dx = xmax - xmin
382
+ dy = ymax - ymin
383
+ width = min([max([100., dx]), 300])
384
+ height = min([max([100., dy]), 300])
385
+ try:
386
+ scale_factor = max([dx, dy]) / max([width, height])
387
+ except ZeroDivisionError:
388
+ scale_factor = 1.
389
+ view_box = "{0} {1} {2} {3}".format(xmin, ymin, dx, dy)
390
+ transform = "matrix(1,0,0,-1,0,{0})".format(ymax + ymin)
391
+ return svg_top + (
392
+ 'width="{1}" height="{2}" viewBox="{0}" '
393
+ 'preserveAspectRatio="xMinYMin meet">'
394
+ '<g transform="{3}">{4}</g></svg>'
395
+ ).format(view_box, width, height, transform,
396
+ self.svg(scale_factor))
385
397
 
386
398
  @property
387
399
  def geom_type(self):
@@ -744,13 +756,24 @@ class BaseMultipartGeometry(BaseGeometry):
744
756
 
745
757
  __hash__ = object.__hash__
746
758
 
747
- def svg(self, scale_factor=1.):
748
- """
749
- SVG representation of the geometry. Scale factor is multiplied by
750
- the size of the SVG symbol so it can be scaled consistently for a
751
- consistent appearance based on the canvas size.
759
+ def svg(self, scale_factor=1., color=None):
760
+ """Returns a group of SVG elements for the multipart geometry.
761
+
762
+ Parameters
763
+ ==========
764
+ scale_factor : float
765
+ Multiplication factor for the SVG stroke-width. Default is 1.
766
+ color : str, optional
767
+ Hex string for stroke or fill color. Default is to use "#66cc99"
768
+ if geometry is valid, and "#ff3333" if invalid.
752
769
  """
753
- return "\n".join([g.svg(scale_factor) for g in self])
770
+ if self.is_empty:
771
+ return '<g />'
772
+ if color is None:
773
+ color = "#66cc99" if self.is_valid else "#ff3333"
774
+ return '<g>' + \
775
+ ''.join(p.svg(scale_factor, color) for p in self) + \
776
+ '</g>'
754
777
 
755
778
 
756
779
  class GeometrySequence(object):
@@ -55,23 +55,26 @@ class LineString(BaseGeometry):
55
55
  'coordinates': tuple(self.coords)
56
56
  }
57
57
 
58
- def svg(self, scale_factor=1.):
59
- """
60
- SVG representation of the geometry. Scale factor is multiplied by
61
- the size of the SVG symbol so it can be scaled consistently for a
62
- consistent appearance based on the canvas size.
58
+ def svg(self, scale_factor=1., stroke_color=None):
59
+ """Returns SVG polyline element for the LineString geometry.
60
+
61
+ Parameters
62
+ ==========
63
+ scale_factor : float
64
+ Multiplication factor for the SVG stroke-width. Default is 1.
65
+ stroke_color : str, optional
66
+ Hex string for stroke color. Default is to use "#66cc99" if
67
+ geometry is valid, and "#ff3333" if invalid.
63
68
  """
69
+ if self.is_empty:
70
+ return '<g />'
71
+ if stroke_color is None:
72
+ stroke_color = "#66cc99" if self.is_valid else "#ff3333"
64
73
  pnt_format = " ".join(["{0},{1}".format(*c) for c in self.coords])
65
- return """<polyline
66
- fill="none"
67
- stroke="{2}"
68
- stroke-width={1}
69
- points="{0}"
70
- opacity=".8"
71
- />""".format(
72
- pnt_format,
73
- 2.*scale_factor,
74
- "#66cc99" if self.is_valid else "#ff3333")
74
+ return (
75
+ '<polyline fill="none" stroke="{2}" stroke-width="{1}" '
76
+ 'points="{0}" opacity="0.8" />'
77
+ ).format(pnt_format, 2. * scale_factor, stroke_color)
75
78
 
76
79
  @property
77
80
  def ctypes(self):
@@ -61,26 +61,24 @@ class MultiLineString(BaseMultipartGeometry):
61
61
  'coordinates': tuple(tuple(c for c in g.coords) for g in self.geoms)
62
62
  }
63
63
 
64
- def svg(self, scale_factor=1.):
65
- """
66
- SVG representation of the geometry. Scale factor is multiplied by
67
- the size of the SVG symbol so it can be scaled consistently for a
68
- consistent appearance based on the canvas size.
64
+ def svg(self, scale_factor=1., stroke_color=None):
65
+ """Returns a group of SVG polyline elements for the LineString geometry.
66
+
67
+ Parameters
68
+ ==========
69
+ scale_factor : float
70
+ Multiplication factor for the SVG stroke-width. Default is 1.
71
+ stroke_color : str, optional
72
+ Hex string for stroke color. Default is to use "#66cc99" if
73
+ geometry is valid, and "#ff3333" if invalid.
69
74
  """
70
- parts = []
71
- for part in self.geoms:
72
- pnt_format = " ".join(["{0},{1}".format(*c) for c in part.coords])
73
- parts.append("""<polyline
74
- fill="none"
75
- stroke="{2}"
76
- stroke-width={1}
77
- points="{0}"
78
- opacity=".8"
79
- />""".format(
80
- pnt_format,
81
- 2.*scale_factor,
82
- "#66cc99" if self.is_valid else "#ff3333"))
83
- return "\n".join(parts)
75
+ if self.is_empty:
76
+ return '<g />'
77
+ if stroke_color is None:
78
+ stroke_color = "#66cc99" if self.is_valid else "#ff3333"
79
+ return '<g>' + \
80
+ ''.join(p.svg(scale_factor, stroke_color) for p in self) + \
81
+ '</g>'
84
82
 
85
83
 
86
84
  class MultiLineStringAdapter(CachingGeometryProxy, MultiLineString):
@@ -69,28 +69,24 @@ class MultiPoint(BaseMultipartGeometry):
69
69
  'coordinates': tuple([g.coords[0] for g in self.geoms])
70
70
  }
71
71
 
72
- def svg(self, scale_factor=1.):
73
- """
74
- SVG representation of the geometry. Scale factor is multiplied by
75
- the size of the SVG symbol so it can be scaled consistently for a
76
- consistent appearance based on the canvas size.
72
+ def svg(self, scale_factor=1., fill_color=None):
73
+ """Returns a group of SVG circle elements for the MultiPoint geometry.
74
+
75
+ Parameters
76
+ ==========
77
+ scale_factor : float
78
+ Multiplication factor for the SVG circle diameters. Default is 1.
79
+ fill_color : str, optional
80
+ Hex string for fill color. Default is to use "#66cc99" if
81
+ geometry is valid, and "#ff3333" if invalid.
77
82
  """
78
-
79
- parts = []
80
- for part in self.geoms:
81
- parts.append("""<circle
82
- cx="{0.x}"
83
- cy="{0.y}"
84
- r="{1}"
85
- stroke="#555555"
86
- stroke-width="{2}"
87
- fill="{3}"
88
- opacity=".6"
89
- />""".format(
90
- part,
91
- 3*scale_factor,
92
- 1*scale_factor, "#66cc99" if self.is_valid else "#ff3333"))
93
- return "\n".join(parts)
83
+ if self.is_empty:
84
+ return '<g />'
85
+ if fill_color is None:
86
+ fill_color = "#66cc99" if self.is_valid else "#ff3333"
87
+ return '<g>' + \
88
+ ''.join(p.svg(scale_factor, fill_color) for p in self) + \
89
+ '</g>'
94
90
 
95
91
  @property
96
92
  @exceptNull
@@ -80,29 +80,24 @@ class MultiPolygon(BaseMultipartGeometry):
80
80
  'coordinates': allcoords
81
81
  }
82
82
 
83
- def svg(self, scale_factor=1.):
84
- """
85
- SVG representation of the geometry. Scale factor is multiplied by
86
- the size of the SVG symbol so it can be scaled consistently for a
87
- consistent appearance based on the canvas size.
83
+ def svg(self, scale_factor=1., fill_color=None):
84
+ """Returns group of SVG path elements for the MultiPolygon geometry.
85
+
86
+ Parameters
87
+ ==========
88
+ scale_factor : float
89
+ Multiplication factor for the SVG stroke-width. Default is 1.
90
+ fill_color : str, optional
91
+ Hex string for fill color. Default is to use "#66cc99" if
92
+ geometry is valid, and "#ff3333" if invalid.
88
93
  """
89
- parts = []
90
- for part in self.geoms:
91
- exterior_coords = [["{0},{1}".format(*c) for c in part.exterior.coords]]
92
- interior_coords = [
93
- ["{0},{1}".format(*c) for c in interior.coords]
94
- for interior in part.interiors ]
95
- path = " ".join([
96
- "M {0} L {1} z".format(coords[0], " L ".join(coords[1:]))
97
- for coords in exterior_coords + interior_coords ])
98
- parts.append(
99
- """<g fill-rule="evenodd" fill="{2}" stroke="#555555"
100
- stroke-width="{0}" opacity="0.6">
101
- <path d="{1}" /></g>""".format(
102
- 2. * scale_factor,
103
- path,
104
- "#66cc99" if self.is_valid else "#ff3333"))
105
- return "\n".join(parts)
94
+ if self.is_empty:
95
+ return '<g />'
96
+ if fill_color is None:
97
+ fill_color = "#66cc99" if self.is_valid else "#ff3333"
98
+ return '<g>' + \
99
+ ''.join(p.svg(scale_factor, fill_color) for p in self) + \
100
+ '</g>'
106
101
 
107
102
 
108
103
  class MultiPolygonAdapter(CachingGeometryProxy, MultiPolygon):
@@ -74,25 +74,25 @@ class Point(BaseGeometry):
74
74
  'coordinates': self.coords[0]
75
75
  }
76
76
 
77
- def svg(self, scale_factor=1.):
78
- """
79
- SVG representation of the geometry. Scale factor is multiplied by
80
- the size of the SVG symbol so it can be scaled consistently for a
81
- consistent appearance based on the canvas size.
77
+ def svg(self, scale_factor=1., fill_color=None):
78
+ """Returns SVG circle element for the Point geometry.
79
+
80
+ Parameters
81
+ ==========
82
+ scale_factor : float
83
+ Multiplication factor for the SVG circle diameter. Default is 1.
84
+ fill_color : str, optional
85
+ Hex string for fill color. Default is to use "#66cc99" if
86
+ geometry is valid, and "#ff3333" if invalid.
82
87
  """
83
- return """<circle
84
- cx="{0.x}"
85
- cy="{0.y}"
86
- r="{1}"
87
- stroke="#555555"
88
- stroke-width="{2}"
89
- fill="{3}"
90
- opacity=".6"
91
- />""".format(
92
- self,
93
- 3 * scale_factor,
94
- 1 * scale_factor,
95
- "#66cc99" if self.is_valid else "#ff3333")
88
+ if self.is_empty:
89
+ return '<g />'
90
+ if fill_color is None:
91
+ fill_color = "#66cc99" if self.is_valid else "#ff3333"
92
+ return (
93
+ '<circle cx="{0.x}" cy="{0.y}" r="{1}" '
94
+ 'stroke="#555555" stroke-width="{2}" fill="{3}" opacity="0.6" />'
95
+ ).format(self, 3. * scale_factor, 1. * scale_factor, fill_color)
96
96
 
97
97
  @property
98
98
  def ctypes(self):
@@ -300,25 +300,33 @@ class Polygon(BaseGeometry):
300
300
  'coordinates': tuple(coords)
301
301
  }
302
302
 
303
- def svg(self, scale_factor=1.):
304
- """
305
- SVG representation of the geometry. Scale factor is multiplied by
306
- the size of the SVG symbol so it can be scaled consistently for a
307
- consistent appearance based on the canvas size.
303
+ def svg(self, scale_factor=1., fill_color=None):
304
+ """Returns SVG path element for the Polygon geometry.
305
+
306
+ Parameters
307
+ ==========
308
+ scale_factor : float
309
+ Multiplication factor for the SVG stroke-width. Default is 1.
310
+ fill_color : str, optional
311
+ Hex string for fill color. Default is to use "#66cc99" if
312
+ geometry is valid, and "#ff3333" if invalid.
308
313
  """
309
- exterior_coords = [["{0},{1}".format(*c) for c in self.exterior.coords]]
314
+ if self.is_empty:
315
+ return '<g />'
316
+ if fill_color is None:
317
+ fill_color = "#66cc99" if self.is_valid else "#ff3333"
318
+ exterior_coords = [
319
+ ["{0},{1}".format(*c) for c in self.exterior.coords]]
310
320
  interior_coords = [
311
321
  ["{0},{1}".format(*c) for c in interior.coords]
312
- for interior in self.interiors ]
322
+ for interior in self.interiors]
313
323
  path = " ".join([
314
324
  "M {0} L {1} z".format(coords[0], " L ".join(coords[1:]))
315
- for coords in exterior_coords + interior_coords ])
316
- return """
317
- <g fill-rule="evenodd" fill="{2}" stroke="#555555"
318
- stroke-width="{0}" opacity="0.6">
319
- <path d="{1}" />
320
- </g>""".format(
321
- 2.*scale_factor, path, "#66cc99" if self.is_valid else "#ff3333")
325
+ for coords in exterior_coords + interior_coords])
326
+ return (
327
+ '<path fill-rule="evenodd" fill="{2}" stroke="#555555" '
328
+ 'stroke-width="{0}" opacity="0.6" d="{1}" />'
329
+ ).format(2. * scale_factor, path, fill_color)
322
330
 
323
331
 
324
332
  class PolygonAdapter(PolygonProxy, Polygon):
@@ -8,7 +8,8 @@ import sys
8
8
  import atexit
9
9
  import logging
10
10
  import threading
11
- from ctypes import CDLL, cdll, pointer, c_void_p, c_size_t, c_char_p, string_at
11
+ from ctypes import CDLL, cdll, pointer, string_at, cast, POINTER
12
+ from ctypes import c_void_p, c_size_t, c_char_p, c_int, c_float
12
13
  from ctypes.util import find_library
13
14
 
14
15
  from . import ftools
@@ -184,19 +185,33 @@ class TopologicalError(Exception):
184
185
  class PredicateError(Exception):
185
186
  pass
186
187
 
187
-
188
- def error_handler(fmt, *args):
189
- if sys.version_info[0] >= 3:
188
+ # While this function can take any number of positional arguments when
189
+ # called from Python and GEOS expects its error handler to accept any
190
+ # number of arguments (like printf), I'm unable to get ctypes to make
191
+ # a callback object from this function that will accept any number of
192
+ # arguments.
193
+ #
194
+ # At the moment, functions in the GEOS C API only pass 0 or 1 arguments
195
+ # to the error handler. We can deal with this, but when if that changes,
196
+ # Shapely may break.
197
+
198
+ def handler(level):
199
+ def callback(fmt, *args):
190
200
  fmt = fmt.decode('ascii')
191
- args = [arg.decode('ascii') for arg in args]
192
- LOG.error(fmt, *args)
193
-
194
-
195
- def notice_handler(fmt, args):
196
- if sys.version_info[0] >= 3:
197
- fmt = fmt.decode('ascii')
198
- args = args.decode('ascii')
199
- LOG.warning(fmt, args)
201
+ conversions = re.findall(r'%.', fmt)
202
+ log_vals = []
203
+ for spec, arg in zip(conversions, args):
204
+ if spec == '%s' and arg is not None:
205
+ log_vals.append(string_at(arg).decode('ascii'))
206
+ else:
207
+ LOG.error("An error occurred, but the format string "
208
+ "'%s' could not be converted.", fmt)
209
+ return
210
+ getattr(LOG, level)(fmt, *log_vals)
211
+ return callback
212
+
213
+ error_handler = handler('error')
214
+ notice_handler = handler('warning')
200
215
 
201
216
  error_h = EXCEPTION_HANDLER_FUNCTYPE(error_handler)
202
217
  notice_h = EXCEPTION_HANDLER_FUNCTYPE(notice_handler)