some more type hinting magic

This commit is contained in:
Laura Klünder 2022-04-08 00:00:55 +02:00
parent ff00daca9d
commit e1a1ae8bc4
2 changed files with 18 additions and 9 deletions

View file

@ -29,7 +29,7 @@ def hybrid_union(geoms):
return HybridGeometry(geom=unary_union(tuple(geom.geom for geom in geoms)), return HybridGeometry(geom=unary_union(tuple(geom.geom for geom in geoms)),
faces=tuple(chain(*(geom.faces for geom in geoms))), faces=tuple(chain(*(geom.faces for geom in geoms))),
add_faces=add_faces, add_faces=add_faces,
crop_ids=reduce(operator.or_, (other.crop_ids for other in geoms), set())) crop_ids=reduce(operator.or_, (other.crop_ids for other in geoms), frozenset()))
THybridGeometry = TypeVar("THybridGeometry", bound="HybridGeometry") THybridGeometry = TypeVar("THybridGeometry", bound="HybridGeometry")
@ -51,7 +51,7 @@ class HybridGeometry:
add_faces: dict = field(default_factory=dict) # todo: specify type more precisely add_faces: dict = field(default_factory=dict) # todo: specify type more precisely
@classmethod @classmethod
def create(cls, geom, face_centers) -> THybridGeometry: def create(cls, geom, face_centers: np.ndarray[tuple[int, Literal[2]], np.uint32]) -> THybridGeometry:
""" """
Create from existing facets and just select the ones that lie inside this polygon. Create from existing facets and just select the ones that lie inside this polygon.
""" """
@ -61,7 +61,10 @@ class HybridGeometry:
set(np.argwhere(shapely_to_mpl(subgeom).contains_points(face_centers)).flatten()) set(np.argwhere(shapely_to_mpl(subgeom).contains_points(face_centers)).flatten())
for subgeom in assert_multipolygon(geom) for subgeom in assert_multipolygon(geom)
) )
return HybridGeometry(geom, tuple(f for f in faces if f)) # todo: wtf? that is the wrong typing
faces = tuple(reduce(operator.or_, faces, set()))
return HybridGeometry(geom, faces) # old code had wrong typing
# return HybridGeometry(geom, tuple(f for f in faces if f)) # old code had wrong typing
@classmethod @classmethod
def create_full(cls, geom: BaseGeometry, def create_full(cls, geom: BaseGeometry,

View file

@ -1,5 +1,6 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from dataclasses import InitVar, dataclass, field from dataclasses import InitVar, dataclass, field
from typing import Literal
import numpy as np import numpy as np
from matplotlib.path import Path from matplotlib.path import Path
@ -11,11 +12,15 @@ from c3nav.mapdata.utils.geometry import assert_multipolygon
class MplPathProxy(ABC): class MplPathProxy(ABC):
@abstractmethod @abstractmethod
def intersects_path(self, path): def intersects_path(self, path: Path) -> bool:
pass pass
@abstractmethod @abstractmethod
def contains_point(self, point): def contains_point(self, point: tuple[int, int]) -> bool:
pass
@abstractmethod
def contains_points(self, points: np.ndarray[tuple[int, Literal[2]], np.uint32]) -> bool:
pass pass
@ -23,11 +28,11 @@ class MplPathProxy(ABC):
class MplPolygonPath(MplPathProxy): class MplPolygonPath(MplPathProxy):
polygon: InitVar[Polygon] polygon: InitVar[Polygon]
exterior: Path = field(init=False) exterior: Path = field(init=False)
interiors: list[Path] = field(init=False) interiors: tuple[Path, ...] = field(init=False)
def __post_init__(self, polygon): def __post_init__(self, polygon):
self.exterior = linearring_to_mpl_path(polygon.exterior) self.exterior = linearring_to_mpl_path(polygon.exterior)
self.interiors = [linearring_to_mpl_path(interior) for interior in polygon.interiors] self.interiors = tuple(linearring_to_mpl_path(interior) for interior in polygon.interiors)
@property @property
def exteriors(self): def exteriors(self):
@ -52,6 +57,7 @@ class MplPolygonPath(MplPathProxy):
return False return False
def contains_points(self, points): def contains_points(self, points):
# noinspection PyTypeChecker
result = self.exterior.contains_points(points) result = self.exterior.contains_points(points)
for interior in self.interiors: for interior in self.interiors:
if not result.any(): if not result.any():
@ -72,11 +78,11 @@ class MplPolygonPath(MplPathProxy):
@dataclass(slots=True) @dataclass(slots=True)
class MplMultipolygonPath(MplPathProxy): class MplMultipolygonPath(MplPathProxy):
polygons: list[MplPolygonPath] = field(init=False) polygons: tuple[MplPolygonPath, ...] = field(init=False)
polygons_: InitVar[Polygon | MultiPolygon | GeometryCollection] polygons_: InitVar[Polygon | MultiPolygon | GeometryCollection]
def __post_init__(self, polygons_): def __post_init__(self, polygons_):
self.polygons = [MplPolygonPath(polygon) for polygon in assert_multipolygon(polygons_)] self.polygons = tuple(MplPolygonPath(polygon) for polygon in assert_multipolygon(polygons_))
@property @property
def exteriors(self): def exteriors(self):