Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into DOC-document-canoni…
Browse files Browse the repository at this point in the history
…cal-form
  • Loading branch information
theroggy committed Mar 12, 2024
2 parents 7830f9c + 72a440d commit b4eb283
Show file tree
Hide file tree
Showing 19 changed files with 686 additions and 65 deletions.
3 changes: 2 additions & 1 deletion .circleci/config.yml
Expand Up @@ -4,7 +4,7 @@ jobs:
linux-aarch64-wheels:
working_directory: ~/linux-aarch64-wheels
machine:
image: ubuntu-2004:2022.04.1
image: default
# resource_class is what tells CircleCI to use an ARM worker for native arm builds
# https://circleci.com/product/features/resource-classes/
resource_class: arm.medium
Expand Down Expand Up @@ -39,5 +39,6 @@ workflows:
only:
- main
- maint-2.0
- wheels-linux-aarch64
tags:
only: /.*/
21 changes: 20 additions & 1 deletion .github/workflows/release.yml
Expand Up @@ -13,6 +13,9 @@ on:
- "MANIFEST.in"
- "pyproject.toml"
- "setup.py"
schedule:
# in addition run weekly for nightly upload in case no other commits happened
- cron: '34 2 * * 0'

jobs:
build_sdist:
Expand Down Expand Up @@ -125,7 +128,6 @@ jobs:
CIBW_ENVIRONMENT_MACOS:
GEOS_INSTALL=${{ runner.temp }}/geos-${{ env.GEOS_VERSION }}
GEOS_CONFIG=${{ runner.temp }}/geos-${{ env.GEOS_VERSION }}/bin/geos-config
LDFLAGS=-Wl,-rpath,${{ runner.temp }}/geos-${{ env.GEOS_VERSION }}/lib
MACOSX_DEPLOYMENT_TARGET=10.9
CMAKE_OSX_ARCHITECTURES='${{ matrix.cmake_osx_architectures }}'
CIBW_ENVIRONMENT_WINDOWS:
Expand Down Expand Up @@ -153,6 +155,23 @@ jobs:
path: ./wheelhouse/*.whl
retention-days: 5

nightly_upload:
name: Upload nightly wheels
needs: [build_wheels]
runs-on: ubuntu-latest
if: github.repository == 'shapely/shapely' && github.ref == 'refs/heads/main'
steps:
- uses: actions/download-artifact@v4
with:
pattern: release-*
merge-multiple: true
path: dist
- name: Upload wheels to Anaconda Cloud
uses: scientific-python/upload-nightly-action@b67d7fcc0396e1128a474d1ab2b48aa94680f9fc # 0.5.0
with:
artifacts_path: dist
anaconda_nightly_upload_token: ${{secrets.ANACONDA_ORG_UPLOAD_TOKEN}}

publish:
name: Publish on GitHub and PyPI
needs: [build_wheels, build_sdist]
Expand Down
1 change: 1 addition & 0 deletions ci/install_geos.sh
Expand Up @@ -56,6 +56,7 @@ build_geos(){
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=${GEOS_INSTALL} \
-DCMAKE_INSTALL_LIBDIR=lib \
-DCMAKE_INSTALL_NAME_DIR=${GEOS_INSTALL}/lib \
${BUILD_TESTING} \
..
cmake --build . -j 4
Expand Down
9 changes: 9 additions & 0 deletions docs/installation.rst
Expand Up @@ -25,6 +25,15 @@ Shapely is available on the conda-forge channel. Install as follows::

$ conda install shapely --channel conda-forge

Installation of the development version using nightly wheels
------------------------------------------------------------

If you want to test the latest development version of Shapely, the easiest way
to get this version is by installing it from the Scientific Python index of
nightly wheel packages::

python -m pip install --pre --upgrade --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple shapely


Installation from source with custom GEOS libary
------------------------------------------------
Expand Down
19 changes: 17 additions & 2 deletions docs/manual.rst
Expand Up @@ -914,8 +914,8 @@ example will be shown for each.

.. attribute:: object.has_z

Returns ``True`` if the feature has not only `x` and `y`, but also `z`
coordinates for 3D (or so-called, 2.5D) geometries.
Returns ``True`` if the feature has `z` coordinates, either with XYZ or XYZM
coordinate types.

.. code-block:: pycon
Expand All @@ -924,6 +924,21 @@ example will be shown for each.
>>> Point(0, 0, 0).has_z
True
.. attribute:: object.has_m

Returns ``True`` if the feature has `m` coordinates, either with XYM or XYZM
coordinate types.

`New in version 2.1 with GEOS 3.12`.

.. code-block:: pycon
>>> Point(0, 0, 0).has_m
False
>>> from shapely import from_wkt
>>> from_wkt("POINT M (0 0 0)").has_m
True
.. attribute:: object.is_ccw

Returns ``True`` if coordinates are in counter-clockwise order (bounding a
Expand Down
12 changes: 9 additions & 3 deletions shapely/_geometry.py
Expand Up @@ -121,12 +121,18 @@ def get_dimensions(geometry, **kwargs):

@multithreading_enabled
def get_coordinate_dimension(geometry, **kwargs):
"""Returns the dimensionality of the coordinates in a geometry (2 or 3).
"""Returns the dimensionality of the coordinates in a geometry (2, 3 or 4).
Returns -1 for missing geometries (``None`` values).
The return value can be one of the following:
* Return 2 for geometries with XY coordinate types,
* Return 3 for XYZ or XYM coordinate types
(distinguished by :meth:`has_z` or :meth:`has_m`),
* Return 4 for XYZM coordinate types,
* Return -1 for missing geometries (``None`` values).
Note that with GEOS < 3.12, if the first Z coordinate equals ``nan``, this function
will return ``2``.
will return ``2``. Geometries with M coordinates are supported with GEOS >= 3.12.
Parameters
----------
Expand Down
8 changes: 6 additions & 2 deletions shapely/geometry/base.py
Expand Up @@ -619,10 +619,14 @@ def union(self, other, grid_size=None):

@property
def has_z(self):
"""True if the geometry's coordinate sequence(s) have z values (are
3-dimensional)"""
"""True if the geometry's coordinate sequence(s) have z values"""
return bool(shapely.has_z(self))

@property
def has_m(self):
"""True if the geometry's coordinate sequence(s) have m values"""
return bool(shapely.has_m(self))

@property
def is_empty(self):
"""True if the set of points in this geometry is empty, else False"""
Expand Down
2 changes: 1 addition & 1 deletion shapely/geometry/polygon.py
Expand Up @@ -10,7 +10,7 @@
from shapely.geometry.linestring import LineString
from shapely.geometry.point import Point

__all__ = ["Polygon", "LinearRing"]
__all__ = ["orient", "Polygon", "LinearRing"]


def _unpickle_linearring(wkb):
Expand Down
26 changes: 17 additions & 9 deletions shapely/io.py
@@ -1,6 +1,6 @@
import numpy as np

from shapely import lib
from shapely import geos_version, lib
from shapely._enum import ParamEnum

# include ragged array functions here for reference documentation purpose
Expand Down Expand Up @@ -33,7 +33,7 @@ def to_wkt(
geometry,
rounding_precision=6,
trim=True,
output_dimension=3,
output_dimension=None,
old_3d=False,
**kwargs,
):
Expand All @@ -58,8 +58,10 @@ def to_wkt(
-1 to indicate the full precision.
trim : bool, default True
If True, trim unnecessary decimals (trailing zeros).
output_dimension : int, default 3
The output dimension for the WKT string. Supported values are 2 and 3.
output_dimension : int, default None
The output dimension for the WKT string. Supported values are 2, 3 and
4 for GEOS 3.12+. Default None will automatically choose 3 or 4,
depending on the version of GEOS.
Specifying 3 means that up to 3 dimensions will be written but 2D
geometries will still be represented as 2D in the WKT string.
old_3d : bool, default False
Expand Down Expand Up @@ -97,7 +99,9 @@ def to_wkt(
raise TypeError("rounding_precision only accepts scalar values")
if not np.isscalar(trim):
raise TypeError("trim only accepts scalar values")
if not np.isscalar(output_dimension):
if output_dimension is None:
output_dimension = 3 if geos_version < (3, 12, 0) else 4
elif not np.isscalar(output_dimension):
raise TypeError("output_dimension only accepts scalar values")
if not np.isscalar(old_3d):
raise TypeError("old_3d only accepts scalar values")
Expand All @@ -115,7 +119,7 @@ def to_wkt(
def to_wkb(
geometry,
hex=False,
output_dimension=3,
output_dimension=None,
byte_order=-1,
include_srid=False,
flavor="extended",
Expand All @@ -141,8 +145,10 @@ def to_wkb(
hex : bool, default False
If true, export the WKB as a hexidecimal string. The default is to
return a binary bytes object.
output_dimension : int, default 3
The output dimension for the WKB. Supported values are 2 and 3.
output_dimension : int, default None
The output dimension for the WKB. Supported values are 2, 3 and 4 for
GEOS 3.12+. Default None will automatically choose 3 or 4, depending on
the version of GEOS.
Specifying 3 means that up to 3 dimensions will be written but 2D
geometries will still be represented as 2D in the WKB represenation.
byte_order : int, default -1
Expand Down Expand Up @@ -173,7 +179,9 @@ def to_wkb(
"""
if not np.isscalar(hex):
raise TypeError("hex only accepts scalar values")
if not np.isscalar(output_dimension):
if output_dimension is None:
output_dimension = 3 if geos_version < (3, 12, 0) else 4
elif not np.isscalar(output_dimension):
raise TypeError("output_dimension only accepts scalar values")
if not np.isscalar(byte_order):
raise TypeError("byte_order only accepts scalar values")
Expand Down
35 changes: 33 additions & 2 deletions shapely/predicates.py
Expand Up @@ -7,6 +7,7 @@

__all__ = [
"has_z",
"has_m",
"is_ccw",
"is_closed",
"is_empty",
Expand Down Expand Up @@ -40,7 +41,7 @@

@multithreading_enabled
def has_z(geometry, **kwargs):
"""Returns True if a geometry has a Z coordinate.
"""Returns True if a geometry has Z coordinates.
Note that for GEOS < 3.12 this function returns False if the (first) Z coordinate
equals NaN.
Expand All @@ -53,7 +54,7 @@ def has_z(geometry, **kwargs):
See also
--------
get_coordinate_dimension
get_coordinate_dimension, has_m
Examples
--------
Expand All @@ -68,6 +69,36 @@ def has_z(geometry, **kwargs):
return lib.has_z(geometry, **kwargs)


@multithreading_enabled
@requires_geos("3.12.0")
def has_m(geometry, **kwargs):
"""Returns True if a geometry has M coordinates.
Parameters
----------
geometry : Geometry or array_like
**kwargs
See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
See also
--------
get_coordinate_dimension, has_z
Examples
--------
>>> from shapely import from_wkt
>>> has_m(from_wkt("POINT (0 0)"))
False
>>> has_m(from_wkt("POINT Z (0 0 0)"))
False
>>> has_m(from_wkt("POINT M (0 0 0)"))
True
>>> has_m(from_wkt("POINT ZM (0 0 0 0)"))
True
"""
return lib.has_m(geometry, **kwargs)


@multithreading_enabled
def is_ccw(geometry, **kwargs):
"""Returns True if a linestring or linearring is counterclockwise.
Expand Down
4 changes: 2 additions & 2 deletions shapely/testing.py
Expand Up @@ -106,8 +106,8 @@ def assert_geometries_equal(
if normalize:
x = shapely.normalize(x)
y = shapely.normalize(y)
x = np.array(x, copy=False)
y = np.array(y, copy=False)
x = np.asarray(x)
y = np.asarray(y)

is_scalar = x.ndim == 0 or y.ndim == 0

Expand Down

0 comments on commit b4eb283

Please sign in to comment.