diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 81241a6..58e98b7 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.8.1 +current_version = 0.8.2 commit = True tag = True diff --git a/CHANGELOG.md b/CHANGELOG.md index bc9a97e..78f4735 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.8.2] - 2024-09-21 +### Added + - within_polygon helper function ## [0.8.1] - 2024-07-03 bumpversion required to trigger updated build pipeline diff --git a/nzshm_common/__init__.py b/nzshm_common/__init__.py index e98d3a7..780ff2f 100644 --- a/nzshm_common/__init__.py +++ b/nzshm_common/__init__.py @@ -1,6 +1,6 @@ __author__ = "GNS Science" __email__ = 'nshm@gns.cri.nz' -__version__ = '0.8.1' +__version__ = '0.8.2' from .location import location diff --git a/nzshm_common/geometry/geometry.py b/nzshm_common/geometry/geometry.py index 4522218..a98b935 100644 --- a/nzshm_common/geometry/geometry.py +++ b/nzshm_common/geometry/geometry.py @@ -1,9 +1,13 @@ """Simple polygon builder methods.""" import math +from typing import TYPE_CHECKING, Iterable, List import shapely.wkt -from shapely.geometry import Polygon +from shapely.geometry import Point, Polygon + +if TYPE_CHECKING: # pragma: no cover + from nzshm_common import CodedLocation def create_hexagon(edge: float, x: float, y: float): @@ -52,3 +56,23 @@ def backarc_polygon() -> Polygon: """ return shapely.wkt.loads(BA_POLYGON_WKT) + + +# TODO: consider if this function and any of the geometry operation functions belong in thier own repo. This +# would remove dependencies from what is supposed to be a pure python library and allow us to consolodate +# all geometry operations into one lib (including those in solvis and eq-fault-geom) +def within_polygon(locations: Iterable['CodedLocation'], polygon: Polygon) -> List[bool]: + """ + Check if points are within a given polygon. + Uses shapley.geometry.Polygon.contains() which will be false for points on the polygon boundary. + + Args: + locations: the points to check + polygon: the polygon + + Returns: + A list of boolian values True if the point is within the polygon and False if not + """ + + points = [Point(loc.lon, loc.lat) for loc in locations] + return [polygon.contains(point) for point in points] diff --git a/pyproject.toml b/pyproject.toml index 73d59bd..476d8cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "nzshm-common" -version = "0.8.1" +version = "0.8.2" homepage = "https://github.com/GNS-Science/nzshm-common-py" description = "A small pure python library for shared NZ NSHM data like locations." authors = ["GNS Science "] diff --git a/tests/test_geometry.py b/tests/test_geometry.py index ece4279..e02c044 100644 --- a/tests/test_geometry.py +++ b/tests/test_geometry.py @@ -1,12 +1,17 @@ import math import unittest +from nzshm_common import CodedLocation from nzshm_common.grids import RegionGrid, load_grid try: import shapely # noqa - from nzshm_common.geometry.geometry import create_hexagon, create_square_tile # these require shapely + from nzshm_common.geometry.geometry import ( # these require shapely + create_hexagon, + create_square_tile, + within_polygon, + ) HAVE_SHAPELY = True except ImportError: @@ -106,3 +111,21 @@ def test_adjacent_hexagons_pt1(self): print('cell spacing', cells[0].distance(cells[1])) self.assertAlmostEqual(cells[0].distance(cells[1]), 0.0) + + +@unittest.skipUnless(HAVE_SHAPELY, "Test requires optional shapely module.") +def test_within_polygon(): + coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)) + polygon = shapely.geometry.Polygon(coords) + locations = [ + CodedLocation(0, 0, 0.001), + CodedLocation(2, 2, 0.001), + CodedLocation(0.5, 2, 0.001), + CodedLocation(0.5, 0.5, 0.001), + ] + within_expected = [False, False, False, True] + + within = within_polygon(locations, polygon) + + assert len(within) == len(within_expected) + assert within == within_expected