models.py

6.6 kB · python · 221 lines

1import io2import numpy as np3from copy import deepcopy4from typing import Any, Dict, List, Optional, Tuple, TYPE_CHECKING5from mrlypy.core.enums import Mode6from mrlypy.core.errors import MrlyError78if TYPE_CHECKING:9    from mrlypy.core.colors import Color10    from mrlypy.two.models import Cell2d1112class Cell3d:1314    def __init__(15        self,16        width: Optional[int] = None,17        height: Optional[int] = None,18        depth: Optional[int] = None,19        types: Optional[np.ndarray] = None,20        colors: Optional[np.ndarray] = None,21        tags: Optional[np.ndarray] = None,22    ):23        self._width = width24        self._height = height25        self._depth = depth26        self._types = types27        self._colors = colors28        self._tags = tags2930    @property31    def width(self) -> int:32        if self._types is not None:33            return self._types.shape[2]34        if self._colors is not None:35            return self._colors.shape[2]36        if self._tags is not None:37            return self._tags.shape[2]38        if self._width is not None:39            return self._width40        raise MrlyError("Cell3d has no data and no dimensions")4142    @property43    def height(self) -> int:44        if self._types is not None:45            return self._types.shape[1]46        if self._colors is not None:47            return self._colors.shape[1]48        if self._tags is not None:49            return self._tags.shape[1]50        if self._height is not None:51            return self._height52        raise MrlyError("Cell3d has no data and no dimensions")5354    @property55    def depth(self) -> int:56        if self._types is not None:57            return self._types.shape[0]58        if self._colors is not None:59            return self._colors.shape[0]60        if self._tags is not None:61            return self._tags.shape[0]62        if self._depth is not None:63            return self._depth64        raise MrlyError("Cell3d has no data and no dimensions")6566    @property67    def types(self) -> np.ndarray:68        if self._types is None:69            self._types = np.zeros((self.depth, self.height, self.width), dtype=np.uint8)70        return self._types7172    @types.setter73    def types(self, value: np.ndarray):74        self._types = value7576    @property77    def colors(self) -> np.ndarray:78        if self._colors is None:79            self._colors = np.zeros((self.depth, self.height, self.width, 4), dtype=np.uint8)80        return self._colors8182    @colors.setter83    def colors(self, value: Optional[np.ndarray]):84        self._colors = value8586    @property87    def tags(self) -> np.ndarray:88        if self._tags is None:89            self._tags = np.zeros((self.depth, self.height, self.width), dtype=np.uint8)90        return self._tags9192    @tags.setter93    def tags(self, value: Optional[np.ndarray]):94        self._tags = value9596    # MAIN9798    def shape(self) -> Tuple[int, int, int]:99        return (self.depth, self.height, self.width)100101    def __repr__(self) -> str:102        return f"Cell3d(width={self.width}, height={self.height}, depth={self.depth})"103104    def copy(self) -> "Cell3d":105        return deepcopy(self)106107    def to_2d(self) -> "Cell2d":108        from mrlypy.two.models import Cell2d109        return Cell2d(types=self.types[0])110111    @classmethod112    def from_2d(cls, cell: "Cell2d") -> "Cell3d":113        types = cell.types[np.newaxis, :, :]114        return cls(types=types)115116    def extrude(self, depth: int = 1) -> "Cell3d":117        if depth < 1:118            raise MrlyError("Extrusion depth must be at least 1.")119        self.types = np.repeat(self.types, depth, axis=0)120        return self121122    # SERIALIZER123124    def to_dict(self) -> Dict[str, Any]:125        from . import serializer126        return serializer.to_dict_3d(self)127128    @classmethod129    def from_dict(cls, data: Dict[str, Any]) -> "Cell3d":130        from . import serializer131        return serializer.from_dict_3d(data)132133    def to_array(self) -> np.ndarray:134        from . import serializer135        return serializer.to_array_3d(self)136137    @classmethod138    def from_array(cls, array: np.ndarray) -> "Cell3d":139        from . import serializer140        return serializer.from_array_3d(array)141142    def to_list(self) -> List[List[List[int]]]:143        from . import serializer144        return serializer.to_list_3d(self)145146    @classmethod147    def from_list(cls, list: List[List[List[int]]]) -> "Cell3d":148        from . import serializer149        return serializer.from_list_3d(list)150151    def to_strings(self) -> List[List[str]]:152        from . import serializer153        return serializer.to_strings_3d(self)154155    @classmethod156    def from_strings(cls, data: List[List[str]]) -> "Cell3d":157        from . import serializer158        return serializer.from_strings_3d(data)159160    # GEOMETRY161162    def invert(self) -> "Cell3d":163        from . import geometry164        return geometry.invert_3d(self)165166    def anti(self) -> "Cell3d":167        from . import geometry168        return geometry.invert_3d(self)169170    def pad(self, count: int = 1, value: int = 0) -> "Cell3d":171        from . import geometry172        return geometry.pad_3d(self, count, value)173174    def rotate(self, k: int = 1, axes: Tuple[int, int] = (1, 2)) -> "Cell3d":175        from . import geometry176        return geometry.rotate_3d(self, k, axes)177178    def fractal(self, level: int = 1) -> "Cell3d":179        from . import geometry180        return geometry.fractal_3d(self, level)181182    def tile(self, width: int, height: int, depth: int) -> "Cell3d":183        from . import geometry184        return geometry.tile_3d(self, width, height, depth)185186    def layers(self, dtype: np.dtype = np.dtype(np.uint8)) -> "Cell3d":187        from . import geometry188        return geometry.layers_3d(self, dtype)189190    def neighbors(self, mode: str = "constant") -> "Cell3d":191        from . import geometry192        return geometry.neighbors_3d(self, mode)193194    # CENSUS195196    def census(self) -> Dict[str, int]:197        from mrlypy.core import census198        return census.census_3d(self.types)199200    # PAINTER201202    def paint(self, palette: Optional[Dict[int, List["Color"]]] = None, mode: Optional[Mode] = None) -> "Cell3d":203        from . import painter204        return painter.paint_3d(self, palette, mode)205206    # RENDERER207208    def text(self, mapping: Optional[Dict[int, str]] = None) -> List[str]:209        from . import renderer210        return renderer.text_3d(self.types, mapping)211212    def to_obj(self) -> str:213        from . import renderer214        with io.StringIO() as f:215            renderer.to_obj(self, f)216            return f.getvalue()217218    def save_obj(self, filename: str) -> None:219        from . import renderer220        with open(filename, "w") as f:221            renderer.to_obj(self, f)