# 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

"""
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 even-odd rule is used to determine if a particular
point is contained by the mask.
"""

polygons: Sequence[Polygon]
"""
The constituent polygons of this `Mask`.
"""

@staticmethod
"""
"""
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 point-like (`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])

"""
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:

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 even-odd 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 even-odd rule is used to determine if a particular
point is contained by the mask.
"""

polygons: Sequence[Polygon]
"""
The constituent polygons of this `Mask`.
"""

@staticmethod
"""
"""
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 point-like (`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])

"""
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:

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 a `MaskJson`.

Expand source code
``````@staticmethod
"""
"""
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` or `float`), in which case the mask will be scaled by the same factor on both axes, or a point-like (`Tuple[float, float]` or `Point`), 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 point-like (`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]``````