From ebf78d104b90dbbb3b41cc3fbec75bf39dd836f2 Mon Sep 17 00:00:00 2001 From: Huite Bootsma Date: Sat, 12 Aug 2023 12:34:37 +0200 Subject: [PATCH] Add Ugrid2d.bounding_polygon --- docs/api.rst | 1 + docs/changelog.rst | 4 ++++ tests/test_ugrid2d.py | 7 +++++++ xugrid/ugrid/ugrid2d.py | 16 ++++++++++++++++ 4 files changed, 28 insertions(+) diff --git a/docs/api.rst b/docs/api.rst index 9bd632543..4fc251fc8 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -257,6 +257,7 @@ UGRID2D Topology Ugrid2d.bounds Ugrid2d.edge_bounds Ugrid2d.face_bounds + Ugrid2d.polygon_bounds Ugrid2d.node_node_connectivity Ugrid2d.node_edge_connectivity diff --git a/docs/changelog.rst b/docs/changelog.rst index f142a4ec4..cf9314e1b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -32,6 +32,8 @@ Added - :meth:`xugrid.UgridDatasetAccessor.rename` and :meth:`xugrid.UgridDataArrayAccessor.rename` to rename both topology and the associated dimensions. +- :meth:`xugrid.Ugrid2d.polygon_bounds` has been added to get a polygon + describing the bounds of the grid. Fixed ~~~~~ @@ -46,6 +48,8 @@ Fixed reference system). - :meth:`xugrid.UgridDatasetAccessor.to_geodataframe` will no longer error when converting a UgridDataset that does not contain any variables. +- :meth:`xugrid.OverlapRegridder.regrid` will no longer give incorrect results + on repeated calls with the "mode" method. Changed ~~~~~~~ diff --git a/tests/test_ugrid2d.py b/tests/test_ugrid2d.py index 2d7c79f3c..e772a6bd8 100644 --- a/tests/test_ugrid2d.py +++ b/tests/test_ugrid2d.py @@ -901,6 +901,13 @@ def test_from_geodataframe(): assert isinstance(grid, xugrid.Ugrid2d) +def test_bounding_polygon(): + grid = grid2d() + polygon = grid.bounding_polygon() + assert isinstance(polygon, shapely.Polygon) + assert np.allclose(grid.bounds, polygon.bounds) + + def test_to_shapely(): grid = grid2d() diff --git a/xugrid/ugrid/ugrid2d.py b/xugrid/ugrid/ugrid2d.py index 754c7f08a..33782602e 100644 --- a/xugrid/ugrid/ugrid2d.py +++ b/xugrid/ugrid/ugrid2d.py @@ -1671,3 +1671,19 @@ def to_shapely(self, dim): f"Dimension {dim} is not a face, node, or edge dimension of the" " Ugrid2d topology." ) + + def bounding_polygon(self) -> "shapely.Polygon": # type: ignore # noqa + """ + Construct the bounding polygon of the grid. + + This polygon may include holes if the grid also contains holes. + """ + import shapely + + def _bbox_area(bounds): + return (bounds[2] - bounds[0]) * (bounds[3] - bounds[1]) + + edges = self.node_coordinates[self.boundary_node_connectivity] + collection = shapely.polygonize(shapely.linestrings(edges)) + polygon = max(collection.geoms, key=lambda x: _bbox_area(x.bounds)) + return polygon