88from typing import TYPE_CHECKING , Any , Generic , Literal , TypeVar , cast
99
1010import numpy
11+ import shapely
1112import xarray
12- from shapely import unary_union
1313from shapely .geometry import MultiPolygon , Point , Polygon
1414from shapely .geometry .base import BaseGeometry
1515from shapely .strtree import STRtree
1616
1717from emsarray import utils
1818from emsarray .compat .shapely import SpatialIndex
19- from emsarray .exceptions import NoSuchCoordinateError
19+ from emsarray .exceptions import InvalidPolygonWarning , NoSuchCoordinateError
2020from emsarray .operations import depth , point_extraction
2121from emsarray .plot import (
2222 _requires_plot , animate_on_figure , make_plot_title , plot_on_figure ,
@@ -1264,8 +1264,8 @@ def make_quiver(
12641264
12651265 return Quiver (axes , x , y , * values , ** kwargs )
12661266
1267- @property
1268- @abc . abstractmethod
1267+ @cached_property
1268+ @utils . timed_func
12691269 def polygons (self ) -> numpy .ndarray :
12701270 """A :class:`numpy.ndarray` of :class:`shapely.Polygon` instances
12711271 representing the cells in this dataset.
@@ -1286,6 +1286,24 @@ def polygons(self) -> numpy.ndarray:
12861286 :meth:`ravel_index`
12871287 :attr:`mask`
12881288 """
1289+ polygons = self ._make_polygons ()
1290+
1291+ not_none = (polygons != None ) # noqa: E711
1292+ invalid_polygon_indices = numpy .flatnonzero (not_none & ~ shapely .is_valid (polygons ))
1293+ if len (invalid_polygon_indices ):
1294+ indices_str = numpy .array2string (
1295+ invalid_polygon_indices , max_line_width = None , threshold = 5 )
1296+ warnings .warn (
1297+ f"Dropping invalid polygons at indices { indices_str } " ,
1298+ category = InvalidPolygonWarning )
1299+ polygons [invalid_polygon_indices ] = None
1300+ not_none [invalid_polygon_indices ] = False
1301+
1302+ polygons .flags .writeable = False
1303+ return polygons
1304+
1305+ @abc .abstractmethod
1306+ def _make_polygons (self ) -> numpy .ndarray :
12891307 pass
12901308
12911309 @cached_property
@@ -1337,7 +1355,7 @@ def geometry(self) -> Polygon | MultiPolygon:
13371355 This is equivalent to the union of all polygons in the dataset,
13381356 although specific conventions may have a simpler way of constructing this.
13391357 """
1340- return unary_union (self .polygons [self .mask ])
1358+ return shapely . unary_union (self .polygons [self .mask ])
13411359
13421360 @cached_property
13431361 def bounds (self ) -> Bounds :
0 commit comments