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)