[python-shapely] 01/06: Imported Upstream version 1.6~b1
Bas Couwenberg
sebastic at debian.org
Mon Dec 12 17:54:38 UTC 2016
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository python-shapely.
commit 2f464bb56d88be7005304856db6be8b25f566534
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Mon Dec 12 18:34:38 2016 +0100
Imported Upstream version 1.6~b1
---
CHANGES.txt | 18 ++++
README.rst | 78 +++++++++--------
setup.py | 21 ++---
shapely/__init__.py | 2 +-
shapely/coords.py | 21 -----
shapely/geometry/linestring.py | 154 +++++++++++----------------------
shapely/geometry/multipoint.py | 67 +++------------
shapely/geometry/point.py | 74 +++++-----------
shapely/geometry/polygon.py | 190 +++++++++++++++--------------------------
shapely/speedups/_speedups.pyx | 12 ++-
tests/test_linestring.py | 5 ++
tests/test_ndarrays.py | 8 +-
tests/test_point.py | 5 ++
tests/test_vectorized.py | 13 +--
14 files changed, 250 insertions(+), 418 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 922c051..ffe9922 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,24 @@
Changes
=======
+1.6b1 (2016-12-12)
+------------------
+
+Bug fixes:
+
+- Implemented __array_interface__ for empty Points and LineStrings (#403).
+
+1.6a3 (2016-12-01)
+------------------
+
+Bug fixes:
+
+- Remove accidental hard requirement of Numpy (#431).
+
+Packaging:
+
+- Put Numpy in an optional requirement set named "vectorized" (#431).
+
1.6a2 (2016-11-09)
------------------
diff --git a/README.rst b/README.rst
index 8bbbff9..28d8bfd 100644
--- a/README.rst
+++ b/README.rst
@@ -2,17 +2,16 @@
Shapely
=======
-Manipulation and analysis of geometric objects in the Cartesian plane.
-
.. image:: https://travis-ci.org/Toblerity/Shapely.png?branch=master
:target: https://travis-ci.org/Toblerity/Shapely
-.. image:: https://coveralls.io/repos/github/Toblerity/Shapely/badge.svg?branch=master
:target: https://coveralls.io/github/Toblerity/Shapely?branch=master
-.. image:: http://farm3.staticflickr.com/2738/4511827859_b5822043b7_o_d.png
+Manipulation and analysis of geometric objects in the Cartesian plane.
+
+.. image:: https://c2.staticflickr.com/6/5560/31301790086_b3472ea4e9_c.jpg
:width: 800
- :height: 400
+ :height: 378
Shapely is a BSD-licensed Python package for manipulation and analysis of
planar geometric objects. It is based on the widely deployed `GEOS
@@ -28,46 +27,61 @@ but can be readily integrated with packages that are. For more details, see:
Requirements
============
-Shapely 1.5.x requires
+Shapely 1.6.x requires
* Python >=2.6 (including Python 3.x)
-* GEOS >=3.3 (Shapely 1.2.x requires only GEOS 3.1 but YMMV)
+* GEOS >=3.3
-Installing Shapely
-==================
+Installing Shapely (1.6b1)
+==========================
-Windows users should download an executable installer from
-http://www.lfd.uci.edu/~gohlke/pythonlibs/#shapely or PyPI (if available).
+Windows users have two good installation options: the wheels at
+http://www.lfd.uci.edu/~gohlke/pythonlibs/#shapely and the
+Anaconda platform's [conda-forge](https://conda-forge.github.io/)
+channel.
-On other systems, acquire the GEOS by any means (`brew install geos` on OS X or
-`apt-get install libgeos-dev` on Debian/Ubuntu), make sure that it is on the
-system library path, and install Shapely from the Python package index.
+OS X users can get Shapely wheels with GEOS included from the
+Python Package Index with a recent version of pip (8+):
.. code-block:: console
- $ pip install shapely
+ $ pip install shapely==1.6b1
-If you've installed GEOS to a non-standard location, the geos-config program
-will be used to get compiler and linker options. If it is not on the PATH,
-it can be specified with a GEOS_CONFIG environment variable, e.g.:
+A few extra speedups that require Numpy can be had by running
.. code-block:: console
- $ GEOS_CONFIG=/path/to/geos-config pip install shapely
+ $ pip install shapely[vectorized]==1.6b1
-If your system's GEOS version is < 3.3.0 you cannot use Shapely 1.3+ and must
-stick to 1.2.x as shown below.
+If you want to build Shapely from source for compatibility with
+other modules that depend on GEOS (such as cartopy or osgeo.ogr)
+you may ignore the binary wheels.
.. code-block:: console
- $ pip install shapely<1.3
+ $ pip install shapely --no-binary shapely
-Or, if you're using pip 6+
+Binary wheels are also available for Linux. To get them, use `pip shapely
+shapely==1.6b1`. To avoid them, use `pip install shapely --no-binary
+shapely==1.6b1`.
+
+In other situations, install `geos_c` libs and headers by any means
+(for example, `brew install geos` on OS X or
+`apt-get install libgeos-dev` on Debian/Ubuntu) and install Shapely
+from the Python package index.
.. code-block:: console
- $ pip install shapely~=1.2
+ $ pip install shapely
+
+If you've installed GEOS to a standard location, the geos-config program
+will be used to get compiler and linker options. If geos-config is not on
+your executable, it can be specified with a GEOS_CONFIG environment
+variable, e.g.:
+
+.. code-block:: console
+ $ GEOS_CONFIG=/path/to/geos-config pip install shapely
Shapely is also provided by popular Python distributions like Canopy (Enthought)
and Anaconda (Continuum Analytics).
@@ -133,21 +147,13 @@ We use py.test to run Shapely's suite of unittests and doctests.
.. code-block:: console
- (env)$ py.test tests
-
-Roadmap and Maintenance
-=======================
-
-Shapely 1.2.x is a maintenance-only branch which supports Python 2.4-2.6, but
-not Python 3+. There will be no new features in Shapely 1.2.x and only fixes
-for major bugs.
-
-Shapely 1.4.x is a maintenance-only branch supporting Pythons 2.7 and 3.3+.
+ (env)$ python -m pytest
Support
=======
-Please discuss Shapely with us at
-http://lists.gispython.org/mailman/listinfo/community.
+Questions about using Shapely may be asked on the `GIS StackExchange
+<http://gis.stackexchange.com/questions/tagged/shapely>`__ using the "shapely"
+tag.
Bugs may be reported at https://github.com/Toblerity/Shapely/issues.
diff --git a/setup.py b/setup.py
index 814c22b..7418d5a 100755
--- a/setup.py
+++ b/setup.py
@@ -178,8 +178,9 @@ with open('CHANGES.txt', 'r', **open_kwds) as fp:
long_description = readme + '\n\n' + credits + '\n\n' + changes
extra_reqs = {
- 'test': ['pytest', 'pytest-cov', 'numpy>=1.4.1', 'packaging']
-}
+ 'test': ['pytest', 'pytest-cov', 'packaging'],
+ 'vectorized': ['numpy']}
+
extra_reqs['all'] = list(it.chain.from_iterable(extra_reqs.values()))
# Make a dict of setup arguments. Some items will be updated as
@@ -302,8 +303,8 @@ def construct_build_ext(build_ext):
build_ext.build_extension(self, ext)
except ext_errors as x:
raise BuildFailed(x)
- return WrappedBuildExt
+ return WrappedBuildExt
if (hasattr(platform, 'python_implementation')
and platform.python_implementation() == 'PyPy'):
@@ -311,7 +312,6 @@ if (hasattr(platform, 'python_implementation')
ext_modules = []
libraries = []
-
if os.path.exists("MANIFEST.in"):
pyx_file = "shapely/speedups/_speedups.pyx"
c_file = "shapely/speedups/_speedups.c"
@@ -333,15 +333,9 @@ if os.path.exists("MANIFEST.in"):
log.warn("speedup extension not found")
ext_modules = [
- Extension(
- "shapely.speedups._speedups",
- ["shapely/speedups/_speedups.c"],
- include_dirs=include_dirs,
- library_dirs=library_dirs,
- libraries=libraries,
- extra_link_args=extra_link_args,
- ),
-]
+ Extension("shapely.speedups._speedups", ["shapely/speedups/_speedups.c"],
+ include_dirs=include_dirs, library_dirs=library_dirs,
+ libraries=libraries, extra_link_args=extra_link_args)]
cmd_classes = setup_args.setdefault('cmdclass', {})
@@ -370,7 +364,6 @@ except ImportError:
log.info("Numpy or Cython not available, shapely.vectorized submodule "
"not being built.")
-
try:
# try building with speedups
existing_build_ext = setup_args['cmdclass'].\
diff --git a/shapely/__init__.py b/shapely/__init__.py
index 909cbfd..8f4c864 100644
--- a/shapely/__init__.py
+++ b/shapely/__init__.py
@@ -1 +1 @@
-__version__ = "1.6a2"
+__version__ = "1.6b1"
diff --git a/shapely/coords.py b/shapely/coords.py
index bfac400..427d171 100644
--- a/shapely/coords.py
+++ b/shapely/coords.py
@@ -11,27 +11,6 @@ from shapely.topology import Validating
if sys.version_info[0] < 3:
range = xrange
-try:
- import numpy
- has_numpy = True
-except ImportError:
- has_numpy = False
-
-def required(ob):
- """Return an object that meets Shapely requirements for self-owned
- C-continguous data, copying if necessary, or just return the original
- object."""
- if hasattr(ob, '__array_interface__'):
- if ob.__array_interface__.get('strides') and not has_numpy:
- # raise an error if strided. See issue #52.
- raise ValueError("C-contiguous data is required")
- else:
- # numpy.require will just return (ob) if it is already
- # float64 and well-behaved.
- return numpy.require(ob, numpy.float64, ["C", "OWNDATA"])
- else:
- return ob
-
class CoordinateSequence(object):
"""
diff --git a/shapely/geometry/linestring.py b/shapely/geometry/linestring.py
index 8be43bb..9bba6cf 100644
--- a/shapely/geometry/linestring.py
+++ b/shapely/geometry/linestring.py
@@ -8,7 +8,6 @@ if sys.version_info[0] < 3:
from ctypes import c_double, cast, POINTER
-from shapely.coords import required
from shapely.geos import lgeos, TopologicalError
from shapely.geometry.base import (
BaseGeometry, geom_factory, JOIN_STYLE, geos_geom_from_py
@@ -84,7 +83,11 @@ class LineString(BaseGeometry):
def array_interface(self):
"""Provide the Numpy array protocol."""
- return self.coords.array_interface()
+ if self.is_empty:
+ ai = {'version': 3, 'typestr': '<f8', 'shape': (0,), 'data': (c_double * 0)()}
+ else:
+ ai = self.coords.array_interface()
+ return ai
__array_interface__ = property(array_interface)
@@ -187,112 +190,62 @@ def asLineString(context):
def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
# If a LineString is passed in, clone it and return
- # If a LinearRing is passed in, clone the coord seq and return a LineString
+ # If a LinearRing is passed in, clone the coord seq and return a
+ # LineString.
+ #
+ # NB: access to coordinates using the array protocol has been moved
+ # entirely to the speedups module.
+
if isinstance(ob, LineString):
if type(ob) == LineString:
return geos_geom_from_py(ob)
else:
return geos_geom_from_py(ob, lgeos.GEOSGeom_createLineString)
- # If numpy is present, we use numpy.require to ensure that we have a
- # C-continguous array that owns its data. View data will be copied.
- ob = required(ob)
try:
- # From array protocol
- array = ob.__array_interface__
- assert len(array['shape']) == 2
- m = array['shape'][0]
- if m < 2:
- raise ValueError(
- "LineStrings must have at least 2 coordinate tuples")
- try:
- n = array['shape'][1]
- except IndexError:
- raise ValueError(
- "Input %s is the wrong shape for a LineString" % str(ob))
- assert n == 2 or n == 3
+ m = len(ob)
+ except TypeError: # Iterators, e.g. Python 3 zip
+ ob = list(ob)
+ m = len(ob)
- # Make pointer to the coordinate array
- if isinstance(array['data'], tuple):
- # numpy tuple (addr, read-only)
- cp = cast(array['data'][0], POINTER(c_double))
- else:
- cp = array['data']
-
- # Create a coordinate sequence
- if update_geom is not None:
- cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
- if n != update_ndim:
- raise ValueError(
- "Wrong coordinate dimensions; this geometry has "
- "dimensions: %d" % update_ndim)
- else:
- cs = lgeos.GEOSCoordSeq_create(m, n)
-
- # add to coordinate sequence
- for i in range(m):
- dx = c_double(cp[n*i])
- dy = c_double(cp[n*i+1])
- dz = None
- if n == 3:
- try:
- dz = c_double(cp[n*i+2])
- except IndexError:
- raise ValueError("Inconsistent coordinate dimensionality")
-
- # Because of a bug in the GEOS C API,
- # always set X before Y
- lgeos.GEOSCoordSeq_setX(cs, i, dx)
- lgeos.GEOSCoordSeq_setY(cs, i, dy)
- if n == 3:
- lgeos.GEOSCoordSeq_setZ(cs, i, dz)
-
- except AttributeError:
- # Fall back on list
- try:
- m = len(ob)
- except TypeError: # Iterators, e.g. Python 3 zip
- ob = list(ob)
- m = len(ob)
+ if m == 0:
+ return None
- if m == 0:
- return None
+ def _coords(o):
+ if isinstance(o, Point):
+ return o.coords[0]
+ else:
+ return o
- def _coords(o):
- if isinstance(o, Point):
- return o.coords[0]
- else:
- return o
+ try:
+ n = len(_coords(ob[0]))
+ except TypeError:
+ raise ValueError(
+ "Input %s is the wrong shape for a LineString" % str(ob))
+ assert n == 2 or n == 3
- try:
- n = len(_coords(ob[0]))
- except TypeError:
+ # Create a coordinate sequence
+ if update_geom is not None:
+ cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
+ if n != update_ndim:
raise ValueError(
- "Input %s is the wrong shape for a LineString" % str(ob))
- assert n == 2 or n == 3
-
- # Create a coordinate sequence
- if update_geom is not None:
- cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
- if n != update_ndim:
- raise ValueError(
- "Wrong coordinate dimensions; this geometry has "
- "dimensions: %d" % update_ndim)
- else:
- cs = lgeos.GEOSCoordSeq_create(m, n)
-
- # add to coordinate sequence
- for i in range(m):
- coords = _coords(ob[i])
- # Because of a bug in the GEOS C API,
- # always set X before Y
- lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
- lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
- if n == 3:
- try:
- lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
- except IndexError:
- raise ValueError("Inconsistent coordinate dimensionality")
+ "Wrong coordinate dimensions; this geometry has "
+ "dimensions: %d" % update_ndim)
+ else:
+ cs = lgeos.GEOSCoordSeq_create(m, n)
+
+ # add to coordinate sequence
+ for i in range(m):
+ coords = _coords(ob[i])
+ # Because of a bug in the GEOS C API,
+ # always set X before Y
+ lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
+ lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
+ if n == 3:
+ try:
+ lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
+ except IndexError:
+ raise ValueError("Inconsistent coordinate dimensionality")
if update_geom is not None:
return None
@@ -302,12 +255,3 @@ def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
def update_linestring_from_py(geom, ob):
geos_linestring_from_py(ob, geom._geom, geom._ndim)
-
-
-# Test runner
-def _test():
- import doctest
- doctest.testmod()
-
-if __name__ == "__main__":
- _test()
diff --git a/shapely/geometry/multipoint.py b/shapely/geometry/multipoint.py
index d9f8908..55c5d65 100644
--- a/shapely/geometry/multipoint.py
+++ b/shapely/geometry/multipoint.py
@@ -9,11 +9,9 @@ if sys.version_info[0] < 3:
from ctypes import byref, c_double, c_void_p, cast, POINTER
from ctypes import ArgumentError
-from shapely.coords import required
from shapely.geos import lgeos
from shapely.geometry.base import (
- BaseMultipartGeometry, exceptNull, geos_geom_from_py
-)
+ BaseMultipartGeometry, exceptNull, geos_geom_from_py)
from shapely.geometry import point
from shapely.geometry.proxy import CachingGeometryProxy
@@ -98,7 +96,7 @@ class MultiPoint(BaseMultipartGeometry):
array_type = c_double * (m * n)
data = array_type()
for i in range(m):
- g = self.geoms[i]._geom
+ g = self.geoms[i]._geom
cs = lgeos.GEOSGeom_getCoordSeq(g)
lgeos.GEOSCoordSeq_getX(cs, 0, byref(temp))
data[n*i] = temp.value
@@ -158,57 +156,20 @@ def geos_multipoint_from_py(ob):
if isinstance(ob, MultiPoint):
return geos_geom_from_py(ob)
- # If numpy is present, we use numpy.require to ensure that we have a
- # C-continguous array that owns its data. View data will be copied.
- ob = required(ob)
+ m = len(ob)
try:
- # From array protocol
- array = ob.__array_interface__
- assert len(array['shape']) == 2
- m = array['shape'][0]
- n = array['shape'][1]
- assert m >= 1
- assert n == 2 or n == 3
-
- # Make pointer to the coordinate array
- if isinstance(array['data'], tuple):
- # numpy tuple (addr, read-only)
- cp = cast(array['data'][0], POINTER(c_double))
- else:
- cp = array['data']
+ n = len(ob[0])
+ except TypeError:
+ n = ob[0]._ndim
+ assert n == 2 or n == 3
- # Array of pointers to sub-geometries
- subs = (c_void_p * m)()
+ # Array of pointers to point geometries
+ subs = (c_void_p * m)()
- for i in range(m):
- geom, ndims = point.geos_point_from_py(cp[n*i:n*i+2])
- subs[i] = cast(geom, c_void_p)
+ # add to coordinate sequence
+ for i in range(m):
+ coords = ob[i]
+ geom, ndims = point.geos_point_from_py(coords)
+ subs[i] = cast(geom, c_void_p)
- except AttributeError:
- # Fall back on list
- m = len(ob)
- try:
- n = len(ob[0])
- except TypeError:
- n = ob[0]._ndim
- assert n == 2 or n == 3
-
- # Array of pointers to point geometries
- subs = (c_void_p * m)()
-
- # add to coordinate sequence
- for i in range(m):
- coords = ob[i]
- geom, ndims = point.geos_point_from_py(coords)
- subs[i] = cast(geom, c_void_p)
-
return lgeos.GEOSGeom_createCollection(4, subs, m), n
-
-# Test runner
-def _test():
- import doctest
- doctest.testmod()
-
-
-if __name__ == "__main__":
- _test()
diff --git a/shapely/geometry/point.py b/shapely/geometry/point.py
index 0b8720b..70d0eeb 100644
--- a/shapely/geometry/point.py
+++ b/shapely/geometry/point.py
@@ -4,7 +4,6 @@
from ctypes import c_double
from ctypes import cast, POINTER
-from shapely.coords import required
from shapely.errors import DimensionError
from shapely.geos import lgeos
from shapely.geometry.base import BaseGeometry, geos_geom_from_py
@@ -110,8 +109,11 @@ class Point(BaseGeometry):
def array_interface(self):
"""Provide the Numpy array protocol."""
- ai = self.array_interface_base
- ai.update({'shape': (self._ndim,)})
+ if self.is_empty:
+ ai = {'version': 3, 'typestr': '<f8', 'shape': (0,), 'data': (c_double * 0)()}
+ else:
+ ai = self.array_interface_base
+ ai.update({'shape': (self._ndim,)})
return ai
__array_interface__ = property(array_interface)
@@ -195,49 +197,20 @@ def geos_point_from_py(ob, update_geom=None, update_ndim=0):
if isinstance(ob, Point):
return geos_geom_from_py(ob)
- # If numpy is present, we use numpy.require to ensure that we have a
- # C-continguous array that owns its data. View data will be copied.
- ob = required(ob)
- try:
- # From array protocol
- array = ob.__array_interface__
- assert len(array['shape']) == 1
- n = array['shape'][0]
- assert n == 2 or n == 3
-
- dz = None
- da = array['data']
- if isinstance(da, tuple):
- cdata = da[0]
- # If we had numpy, we would do
- # from numpy.ctypeslib import as_ctypes
- # cp = as_ctypes(ob) - check that code?
- cp = cast(cdata, POINTER(c_double))
- dx = c_double(cp[0])
- dy = c_double(cp[1])
- if n == 3:
- dz = c_double(cp[2])
- else:
- dx, dy = da[0:2]
- if n == 3:
- dz = da[2]
-
- except AttributeError:
- # Fall back on the case of Python sequence data
- # Accept either (x, y) or [(x, y)]
- if not hasattr(ob, '__getitem__'): # Iterators, e.g. Python 3 zip
- ob = list(ob)
-
- if isinstance(ob[0], tuple):
- coords = ob[0]
- else:
- coords = ob
- n = len(coords)
- dx = c_double(coords[0])
- dy = c_double(coords[1])
- dz = None
- if n == 3:
- dz = c_double(coords[2])
+ # Accept either (x, y) or [(x, y)]
+ if not hasattr(ob, '__getitem__'): # Iterators, e.g. Python 3 zip
+ ob = list(ob)
+
+ if isinstance(ob[0], tuple):
+ coords = ob[0]
+ else:
+ coords = ob
+ n = len(coords)
+ dx = c_double(coords[0])
+ dy = c_double(coords[1])
+ dz = None
+ if n == 3:
+ dz = c_double(coords[2])
if update_geom:
cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
@@ -262,12 +235,3 @@ def geos_point_from_py(ob, update_geom=None, update_ndim=0):
def update_point_from_py(geom, ob):
geos_point_from_py(ob, geom._geom, geom._ndim)
-
-
-# Test runner
-def _test():
- import doctest
- doctest.testmod()
-
-if __name__ == "__main__":
- _test()
diff --git a/shapely/geometry/polygon.py b/shapely/geometry/polygon.py
index e492fae..9602df5 100644
--- a/shapely/geometry/polygon.py
+++ b/shapely/geometry/polygon.py
@@ -11,7 +11,7 @@ from ctypes import ArgumentError
import weakref
from shapely.algorithms.cga import signed_area
-from shapely.coords import required
+#from shapely.coords import required
from shapely.geos import lgeos
from shapely.geometry.base import BaseGeometry, geos_geom_from_py
from shapely.geometry.linestring import LineString, LineStringAdapter
@@ -374,6 +374,7 @@ def asPolygon(shell, holes=None):
"""Adapt objects to the Polygon interface"""
return PolygonAdapter(shell, holes)
+
def orient(polygon, sign=1.0):
s = float(sign)
rings = []
@@ -389,136 +390,92 @@ def orient(polygon, sign=1.0):
rings.append(list(ring.coords)[::-1])
return Polygon(rings[0], rings[1:])
+
def geos_linearring_from_py(ob, update_geom=None, update_ndim=0):
# If a LinearRing is passed in, clone it and return
- # If a LineString is passed in, clone the coord seq and return a LinearRing
+ # If a LineString is passed in, clone the coord seq and return a
+ # LinearRing.
+ #
+ # NB: access to coordinates using the array protocol has been moved
+ # entirely to the speedups module.
+
if isinstance(ob, LineString):
if type(ob) == LinearRing:
return geos_geom_from_py(ob)
+ elif ob.is_closed and len(ob.coords) >= 4:
+ return geos_geom_from_py(ob, lgeos.GEOSGeom_createLinearRing)
else:
- if ob.is_closed and len(ob.coords) >= 4:
- return geos_geom_from_py(ob, lgeos.GEOSGeom_createLinearRing)
+ ob = list(ob.coords)
- # If numpy is present, we use numpy.require to ensure that we have a
- # C-continguous array that owns its data. View data will be copied.
- ob = required(ob)
try:
- # From array protocol
- array = ob.__array_interface__
- assert len(array['shape']) == 2
- m = array['shape'][0]
- n = array['shape'][1]
- if m < 3:
- raise ValueError(
- "A LinearRing must have at least 3 coordinate tuples")
- assert n == 2 or n == 3
+ m = len(ob)
+ except TypeError: # Iterators, e.g. Python 3 zip
+ ob = list(ob)
+ m = len(ob)
- # Make pointer to the coordinate array
- if isinstance(array['data'], tuple):
- # numpy tuple (addr, read-only)
- cp = cast(array['data'][0], POINTER(c_double))
- else:
- cp = array['data']
+ if m == 0:
+ return None
- # Add closing coordinates to sequence?
- if cp[0] != cp[m*n-n] or cp[1] != cp[m*n-n+1]:
- M = m + 1
- else:
- M = m
-
- # Create a coordinate sequence
- if update_geom is not None:
- cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
- if n != update_ndim:
- raise ValueError(
- "Wrong coordinate dimensions; this geometry has dimensions: %d" \
- % update_ndim)
- else:
- cs = lgeos.GEOSCoordSeq_create(M, n)
-
- # add to coordinate sequence
- for i in range(m):
- # Because of a bug in the GEOS C API,
- # always set X before Y
- lgeos.GEOSCoordSeq_setX(cs, i, cp[n*i])
- lgeos.GEOSCoordSeq_setY(cs, i, cp[n*i+1])
- if n == 3:
- lgeos.GEOSCoordSeq_setZ(cs, i, cp[n*i+2])
-
- # Add closing coordinates to sequence?
- if M > m:
- # Because of a bug in the GEOS C API,
- # always set X before Y
- lgeos.GEOSCoordSeq_setX(cs, M-1, cp[0])
- lgeos.GEOSCoordSeq_setY(cs, M-1, cp[1])
- if n == 3:
- lgeos.GEOSCoordSeq_setZ(cs, M-1, cp[2])
-
- except AttributeError:
- # Fall back on list
- try:
- m = len(ob)
- except TypeError: # Iterators, e.g. Python 3 zip
- ob = list(ob)
- m = len(ob)
+ n = len(ob[0])
+ if m < 3:
+ raise ValueError(
+ "A LinearRing must have at least 3 coordinate tuples")
+ assert (n == 2 or n == 3)
- if m == 0:
- return None
+ # Add closing coordinates if not provided
+ if m == 3 or ob[0][0] != ob[-1][0] or ob[0][1] != ob[-1][1]:
+ M = m + 1
+ else:
+ M = m
- n = len(ob[0])
- if m < 3:
+ # Create a coordinate sequence
+ if update_geom is not None:
+ if n != update_ndim:
raise ValueError(
- "A LinearRing must have at least 3 coordinate tuples")
- assert (n == 2 or n == 3)
-
- # Add closing coordinates if not provided
- if m == 3 or ob[0][0] != ob[-1][0] or ob[0][1] != ob[-1][1]:
- M = m + 1
- else:
- M = m
-
- # Create a coordinate sequence
- if update_geom is not None:
- cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
- if n != update_ndim:
- raise ValueError(
- "Wrong coordinate dimensions; this geometry has dimensions: %d" \
- % update_ndim)
- else:
- cs = lgeos.GEOSCoordSeq_create(M, n)
-
- # add to coordinate sequence
- for i in range(m):
- coords = ob[i]
- # Because of a bug in the GEOS C API,
- # always set X before Y
- lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
- lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
- if n == 3:
- try:
- lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
- except IndexError:
- raise ValueError("Inconsistent coordinate dimensionality")
-
- # Add closing coordinates to sequence?
- if M > m:
- coords = ob[0]
- # Because of a bug in the GEOS C API,
- # always set X before Y
- lgeos.GEOSCoordSeq_setX(cs, M-1, coords[0])
- lgeos.GEOSCoordSeq_setY(cs, M-1, coords[1])
- if n == 3:
- lgeos.GEOSCoordSeq_setZ(cs, M-1, coords[2])
+ "Coordinate dimensions mismatch: target geom has {} dims, "
+ "update geom has {} dims".format(n, update_ndim))
+ cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
+ else:
+ cs = lgeos.GEOSCoordSeq_create(M, n)
+
+ # add to coordinate sequence
+ for i in range(m):
+ coords = ob[i]
+ # Because of a bug in the GEOS C API,
+ # always set X before Y
+ lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
+ lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
+ if n == 3:
+ try:
+ lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
+ except IndexError:
+ raise ValueError("Inconsistent coordinate dimensionality")
+
+ # Add closing coordinates to sequence?
+ if M > m:
+ coords = ob[0]
+ # Because of a bug in the GEOS C API,
+ # always set X before Y
+ lgeos.GEOSCoordSeq_setX(cs, M-1, coords[0])
+ lgeos.GEOSCoordSeq_setY(cs, M-1, coords[1])
+ if n == 3:
+ lgeos.GEOSCoordSeq_setZ(cs, M-1, coords[2])
if update_geom is not None:
return None
else:
return lgeos.GEOSGeom_createLinearRing(cs), n
+
def update_linearring_from_py(geom, ob):
geos_linearring_from_py(ob, geom._geom, geom._ndim)
+
def geos_polygon_from_py(shell, holes=None):
+
+ if shell is None:
+ return None
+
if isinstance(shell, Polygon):
return geos_geom_from_py(shell)
@@ -526,6 +483,7 @@ def geos_polygon_from_py(shell, holes=None):
ret = geos_linearring_from_py(shell)
if ret is None:
return None
+
geos_shell, ndim = ret
if holes is not None and len(holes) > 0:
ob = holes
@@ -550,19 +508,7 @@ def geos_polygon_from_py(shell, holes=None):
else:
geos_holes = POINTER(c_void_p)()
L = 0
+
return (
lgeos.GEOSGeom_createPolygon(
- c_void_p(geos_shell),
- geos_holes,
- L
- ),
- ndim
- )
-
-# Test runner
-def _test():
- import doctest
- doctest.testmod()
-
-if __name__ == "__main__":
- _test()
+ c_void_p(geos_shell), geos_holes, L), ndim)
diff --git a/shapely/speedups/_speedups.pyx b/shapely/speedups/_speedups.pyx
index 458b135..72da797 100644
--- a/shapely/speedups/_speedups.pyx
+++ b/shapely/speedups/_speedups.pyx
@@ -6,8 +6,8 @@
# Transcription to cython: Copyright (c) 2011, Oliver Tonnhofer
import ctypes
+import numpy
-from shapely.coords import required
from shapely.geos import lgeos
from shapely.geometry import Point, LineString, LinearRing
from shapely.geometry.base import geom_factory
@@ -32,6 +32,16 @@ def destroy(geom):
GEOSGeom_destroy_r(cast_handle(lgeos.geos_handle), cast_geom(geom))
+def required(ob):
+ """Return an object that meets Shapely requirements for self-owned
+ C-continguous data, copying if necessary, or just return the original
+ object."""
+ if hasattr(ob, '__array_interface__'):
+ return numpy.require(ob, numpy.float64, ["C", "OWNDATA"])
+ else:
+ return ob
+
+
def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
cdef double *cp
cdef GEOSContextHandle_t handle = cast_handle(lgeos.geos_handle)
diff --git a/tests/test_linestring.py b/tests/test_linestring.py
index 2c50a5b..90c5fa8 100644
--- a/tests/test_linestring.py
+++ b/tests/test_linestring.py
@@ -154,6 +154,11 @@ class LineStringTestCase(unittest.TestCase):
b = asarray(line)
assert_array_equal(b, array([[0., 0.], [2., 2.], [1., 1.]]))
+ # Test array interface of empty linestring
+ le = LineString()
+ a = asarray(le)
+ assert(a.shape[0], 0)
+
def test_suite():
return unittest.TestLoader().loadTestsFromTestCase(LineStringTestCase)
diff --git a/tests/test_ndarrays.py b/tests/test_ndarrays.py
index e9b9f6d..f8db1dd 100644
--- a/tests/test_ndarrays.py
+++ b/tests/test_ndarrays.py
@@ -20,10 +20,10 @@ class TransposeTestCase(unittest.TestCase):
@unittest.skipIf(not numpy, 'numpy not installed')
def test_multipoint(self):
- a = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]])
- t = a.T
- s = geometry.asMultiPoint(t)
- coords = reduce(lambda x, y: x + y, [list(g.coords) for g in s])
+ arr = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]])
+ tarr = arr.T
+ shape = geometry.asMultiPoint(tarr)
+ coords = reduce(lambda x, y: x + y, [list(g.coords) for g in shape])
self.assertEqual(
coords,
[(1.0, 3.0), (1.0, 4.0), (2.0, 4.0), (2.0, 3.0), (1.0, 3.0)]
diff --git a/tests/test_point.py b/tests/test_point.py
index d481a3a..452d034 100644
--- a/tests/test_point.py
+++ b/tests/test_point.py
@@ -134,6 +134,11 @@ class LineStringTestCase(unittest.TestCase):
p = Point(*list(a))
self.assertEqual(p.coords[:], [(1.0, 1.0, 0.0)])
+ # Test array interface of empty geometry
+ pe = Point()
+ a = asarray(pe)
+ self.assertEqual(a.shape[0], 0)
+
def test_suite():
return unittest.TestLoader().loadTestsFromTestCase(LineStringTestCase)
diff --git a/tests/test_vectorized.py b/tests/test_vectorized.py
index ea1d956..549b354 100644
--- a/tests/test_vectorized.py
+++ b/tests/test_vectorized.py
@@ -1,16 +1,18 @@
from . import unittest, numpy
from shapely.geometry import Point, box, MultiPolygon
-from shapely.vectorized import contains, touches
+
try:
import numpy as np
+ has_numpy = True
except ImportError:
- pass
+ has_numpy = False
- at unittest.skipIf(not numpy, 'numpy required')
+ at unittest.skipIf(not has_numpy, 'numpy required')
class VectorizedContainsTestCase(unittest.TestCase):
def assertContainsResults(self, geom, x, y):
+ from shapely.vectorized import contains
result = contains(geom, x, y)
x = np.asanyarray(x)
y = np.asanyarray(y)
@@ -85,9 +87,10 @@ class VectorizedContainsTestCase(unittest.TestCase):
self.assertContainsResults(self.construct_torus(), *g.exterior.xy)
- at unittest.skipIf(not numpy, 'numpy required')
+ at unittest.skipIf(not has_numpy, 'numpy required')
class VectorizedTouchesTestCase(unittest.TestCase):
def test_touches(self):
+ from shapely.vectorized import touches
y, x = np.mgrid[-2:3:6j, -1:3:5j]
geom = box(0, -1, 2, 2)
result = touches(geom, x, y)
@@ -99,8 +102,6 @@ class VectorizedTouchesTestCase(unittest.TestCase):
[False, False, False, False, False]], dtype=bool)
from numpy.testing import assert_array_equal
assert_array_equal(result, expected)
-
-
def test_suite():
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/python-shapely.git
More information about the Pkg-grass-devel
mailing list