Module datatap.geometry.mask
Expand source code
from __future__ import annotations
from datatap.geometry.point import Point
from typing import Generator, Sequence, Tuple, Union
from .polygon import Polygon, PolygonJson
from ..utils import basic_repr
MaskJson = Sequence[PolygonJson]
class Mask:
"""
The shape resulting from XORing a set of polygons in 2D space.
Generally, the expectation is that the polygons have no edge itersections; specifically, that for any pair of
polygons in the mask, either they have no intersection or one completely contains the other. However, there is no
assertion that this is the case, and generally speaking, the evenodd rule is used to determine if a particular
point is contained by the mask.
"""
polygons: Sequence[Polygon]
"""
The constituent polygons of this `Mask`.
"""
@staticmethod
def from_json(json: MaskJson) > Mask:
"""
Creates a `Mask` from a `MaskJson`.
"""
return Mask([Polygon.from_json(poly) for poly in json])
def __init__(self, polygons: Sequence[Polygon]):
self.polygons = polygons
if len(self.polygons) < 1:
raise ValueError(f"A mask must have at least one polygon; failed on mask {repr(self)}")
def scale(self, factor: Union[float, int, Tuple[float, float], Point]) > Mask:
"""
Resizes the mask according to `factor`. The scaling factor can either be
a scalar (`int` or `float`), in which case the mask will be scaled by
the same factor on both axes, or a pointlike (`Tuple[float, float]`
or `Point`), in which case the mask will be scaled independently on each
axis.
"""
return Mask([p.scale(factor) for p in self.polygons])
def to_json(self) > MaskJson:
"""
Serializes this object as a `MaskJson`.
"""
return [polygon.to_json() for polygon in self.polygons]
def assert_valid(self) > None:
"""
Asserts that this mask is valid on the unit plane.
"""
for polygon in self.polygons:
polygon.assert_valid()
# TODO(mdsavage): check for invalid polygon intersections?
def __repr__(self) > str:
return basic_repr("Mask", self.polygons)
def __eq__(self, other: Mask) > bool:
# TODO(mdsavage): currently, this requires the polygons to be in the same order, not just represent the same mask
if not isinstance(other, Mask): # type: ignore  pyright complains about the isinstance check being redundant
return NotImplemented
return self.polygons == other.polygons
def __iter__(self) > Generator[Polygon, None, None]:
yield from self.polygons
Classes
class Mask (polygons: Sequence[Polygon])

The shape resulting from XORing a set of polygons in 2D space.
Generally, the expectation is that the polygons have no edge itersections; specifically, that for any pair of polygons in the mask, either they have no intersection or one completely contains the other. However, there is no assertion that this is the case, and generally speaking, the evenodd rule is used to determine if a particular point is contained by the mask.
Expand source code
class Mask: """ The shape resulting from XORing a set of polygons in 2D space. Generally, the expectation is that the polygons have no edge itersections; specifically, that for any pair of polygons in the mask, either they have no intersection or one completely contains the other. However, there is no assertion that this is the case, and generally speaking, the evenodd rule is used to determine if a particular point is contained by the mask. """ polygons: Sequence[Polygon] """ The constituent polygons of this `Mask`. """ @staticmethod def from_json(json: MaskJson) > Mask: """ Creates a `Mask` from a `MaskJson`. """ return Mask([Polygon.from_json(poly) for poly in json]) def __init__(self, polygons: Sequence[Polygon]): self.polygons = polygons if len(self.polygons) < 1: raise ValueError(f"A mask must have at least one polygon; failed on mask {repr(self)}") def scale(self, factor: Union[float, int, Tuple[float, float], Point]) > Mask: """ Resizes the mask according to `factor`. The scaling factor can either be a scalar (`int` or `float`), in which case the mask will be scaled by the same factor on both axes, or a pointlike (`Tuple[float, float]` or `Point`), in which case the mask will be scaled independently on each axis. """ return Mask([p.scale(factor) for p in self.polygons]) def to_json(self) > MaskJson: """ Serializes this object as a `MaskJson`. """ return [polygon.to_json() for polygon in self.polygons] def assert_valid(self) > None: """ Asserts that this mask is valid on the unit plane. """ for polygon in self.polygons: polygon.assert_valid() # TODO(mdsavage): check for invalid polygon intersections? def __repr__(self) > str: return basic_repr("Mask", self.polygons) def __eq__(self, other: Mask) > bool: # TODO(mdsavage): currently, this requires the polygons to be in the same order, not just represent the same mask if not isinstance(other, Mask): # type: ignore  pyright complains about the isinstance check being redundant return NotImplemented return self.polygons == other.polygons def __iter__(self) > Generator[Polygon, None, None]: yield from self.polygons
Class variables
var polygons : Sequence[Polygon]

The constituent polygons of this
Mask
.
Static methods
def from_json(json: MaskJson) ‑> Mask

Creates a
Mask
from aMaskJson
.Expand source code
@staticmethod def from_json(json: MaskJson) > Mask: """ Creates a `Mask` from a `MaskJson`. """ return Mask([Polygon.from_json(poly) for poly in json])
Methods
def assert_valid(self) ‑> None

Asserts that this mask is valid on the unit plane.
Expand source code
def assert_valid(self) > None: """ Asserts that this mask is valid on the unit plane. """ for polygon in self.polygons: polygon.assert_valid() # TODO(mdsavage): check for invalid polygon intersections?
def scale(self, factor: Union[float, int, Tuple[float, float], Point]) ‑> Mask

Resizes the mask according to
factor
. The scaling factor can either be a scalar (int
orfloat
), in which case the mask will be scaled by the same factor on both axes, or a pointlike (Tuple[float, float]
orPoint
), in which case the mask will be scaled independently on each axis.Expand source code
def scale(self, factor: Union[float, int, Tuple[float, float], Point]) > Mask: """ Resizes the mask according to `factor`. The scaling factor can either be a scalar (`int` or `float`), in which case the mask will be scaled by the same factor on both axes, or a pointlike (`Tuple[float, float]` or `Point`), in which case the mask will be scaled independently on each axis. """ return Mask([p.scale(factor) for p in self.polygons])
def to_json(self) ‑> Sequence[Sequence[Tuple[float, float]]]

Serializes this object as a
MaskJson
.Expand source code
def to_json(self) > MaskJson: """ Serializes this object as a `MaskJson`. """ return [polygon.to_json() for polygon in self.polygons]