Source code for eradiate.scenes.shapes._core

from __future__ import annotations

from abc import ABC

import attrs

from ..bsdfs import BSDF, bsdf_factory
from ..core import BoundingBox, InstanceSceneElement, NodeSceneElement, Ref
from ..._factory import Factory
from ...attrs import documented, get_doc, parse_docs

shape_factory = Factory()
shape_factory.register_lazy_batch(
    [
        ("_cuboid.CuboidShape", "cuboid", {}),
        ("_rectangle.RectangleShape", "rectangle", {}),
        ("_sphere.SphereShape", "sphere", {}),
        ("_filemesh.FileMeshShape", "file_mesh", {}),
        ("_buffermesh.BufferMeshShape", "buffer_mesh", {}),
    ],
    cls_prefix="eradiate.scenes.shapes",
)


[docs] @parse_docs @attrs.define(eq=False, slots=False) class Shape: """ Abstract interface for all shape scene elements. Notes ----- * This class is to be used as a mixin. """ id: str | None = documented( attrs.field( default="shape", validator=attrs.validators.optional(attrs.validators.instance_of(str)), ), doc=get_doc(NodeSceneElement, "id", "doc"), type=get_doc(NodeSceneElement, "id", "type"), init_type=get_doc(NodeSceneElement, "id", "init_type"), default='"shape"', ) bsdf: BSDF | Ref | None = documented( attrs.field( default=None, converter=attrs.converters.optional(bsdf_factory.convert), validator=attrs.validators.optional( attrs.validators.instance_of((BSDF, Ref)) ), ), doc="BSDF attached to the shape. If a dictionary is passed, it is " "interpreted by :class:`bsdf_factory.convert() <.Factory>`. " "If unset, no BSDF will be specified during the kernel dictionary " "generation: the kernel's default will be used. If a :class:`.BSDF` " "instance (or a corresponding dictionary specification) is passed, " "its `id` member is automatically overridden.", type="BSDF or Ref or None", init_type="BSDF or Ref or dict, optional", ) def __attrs_post_init__(self): self.update() def update(self) -> None: # Inherit docstring # Normalize child BSDF ID if isinstance(self.bsdf, BSDF): self.bsdf.id = self._bsdf_id @property def bbox(self) -> BoundingBox: """ :class:`.BoundingBox` : Shape bounding box. Default implementation raises a :class:`NotImplementedError`. """ raise NotImplementedError @property def _bsdf_id(self) -> str: return f"{self.id}_bsdf" @property def objects(self) -> dict[str, NodeSceneElement] | None: # Inherit docstring if self.bsdf is None: return None else: return {"bsdf": self.bsdf}
[docs] @attrs.define(eq=False, slots=False) class ShapeNode(Shape, NodeSceneElement, ABC): """ Interface for shapes which can be represented as Mitsuba scene dictionary nodes. """ pass
[docs] @attrs.define(eq=False, slots=False) class ShapeInstance(Shape, InstanceSceneElement, ABC): """ Interface for shapes which have to be expanded as Mitsuba objects. """ pass