Source code for scistag.shapestag.shape

"""
Implements the :class:`Shape: class, the base element for all dynamic Shapes
which can be rendered into a canvas.
"""
from __future__ import annotations
import hashlib
import typing
from abc import abstractmethod
from dataclasses import dataclass

from scistag.imagestag import Canvas, Colors, Bounding2D, Image


[docs]@dataclass class Shape: """ Defines a shape which can be rendered """ shape_class: str = "" "The shape's class" bounding: Bounding2D = Bounding2D((0.0, 0.0, 0.0, 0.0)) "The region to be covered overall" HASHABLE_PROPERTIES: typing.ClassVar = {"shape_class"} def __init__(self, class_name: str, hashable_properties: set[str]): """ Initializer :param class_name: The class name :param hashable_properties: The properties which can automatically get hashed by value to string conversion. """ super().__init__() self.shape_class = class_name "The shape's class" self.__dict__["_hashable_properties"] = hashable_properties "The properties which can be used to create a unique hash"
[docs] @abstractmethod def draw(self, target: Canvas, options: dict | None = None): """ Draws the shape into the defined canvas :param target: The canvas to render onto :param options: Advanced options, such as the cache in which the shape might be cached. """ pass
[docs] def to_image(self, background_color=Colors.TRANSPARENT) -> Image: """ Renders the shape to an image. The shape needs to either specify it's bounding or it's size as member variable to be convertible. :param background_color: The background color """ bounding: Bounding2D = self.bounding offset = bounding.pos.to_tuple() # to see the whole object and as it is painted relative # we need to invert the offset, e.g. an object starting at # -50, -50 has to start painting relative 50, 50 so -50, -50 # is still in the image (in this case at 0,0) offset = (-offset[0], -offset[1]) size = bounding.get_size_tuple() tar = Canvas(size=size, default_color=background_color) if offset != (0.0, 0.0): tar.add_offset_shift(offset) self.draw(tar) return tar.to_image()
[docs] def get_hash(self) -> str: """ A unique hash of the data in this shape. Is used to cache the shape's renderings when it has not been modified. :return: The hash value """ data = [] for element in self.__dict__["hashable_properties"]: element_data = self.__dict__[element] if isinstance(element, list): for index, data in enumerate(element_data): data.append(f"@{element}.{index}") data.append(str(data)) else: data.append(f"@{element}") data.append(str(element_data)) return hashlib.md5(bytearray(";".join(data), "utf-8")).hexdigest()