pytrace 0.3.3

A Python library for ray tracing and image generation
Documentation
use crate::external::*;
use pyo3::prelude::*;
use pyo3::PyObjectProtocol;
use pytrace_core::internal;
use std::sync::Arc;

macro_rules! internalize {
    ( $caller:ident, $member:ident, f64 ) => {
        $caller.$member
    };
    ( $caller:ident, $member:ident, $t:tt ) => {
        $caller.$member.to_internal()
    };
}

macro_rules! printable {
    ( $caller:ident, $item:ident, f64 ) => {
        $caller.$item
    };
    ( $caller:ident, $item:ident, $t:tt ) => {
        $caller.$item.__repr__().ok().unwrap()
    };
}

macro_rules! dvp {
    (
        $(
            #[sig=$sig:tt]
            #[repr=$repr:tt]
            #[str=$str:tt]
            $name:ident {
                $( $member:ident : $t:tt ($alias:ident), )*
            };
        )*
    ) => {
        $(
            #[pyclass]
            #[derive(Copy, Clone)]
            #[text_signature = $sig]
            pub struct $name {
                $(
                    pub $member: $t,
                )*
                pub texture: Texture,
            }

            #[pymethods]
            impl $name {
                #[new]
                #[allow(clippy::new_ret_no_self)]
                pub fn new( $( $member: $t, )* texture: Texture ) -> Construct {
                    Primitive {
                        obj: Arc::new(Self {
                            $( $member, )*
                            texture,
                        }),
                    }.wrap()
                }
            }

            impl ToInternal for $name {
                fn to_internal(&self) -> internal::Primitive {
                    internal:: $name {
                        $( $alias: internalize![self, $member, $t], )*
                        texture: self.texture.to_internal(),
                    }.build()
                }

                fn display(&self) -> String {
                    self.__str__().ok().unwrap()
                }
            }

            #[pyproto]
            impl PyObjectProtocol for $name {
                fn __repr__(self) -> PyResult<String> {
                    Ok(format!($repr, $( printable!(self, $member, $t) ),*))
                }

                fn __str__(self) -> PyResult<String> {
                    Ok(format!($str, $( printable!(self, $member, $t) ),*))
                }
            }
        )*
    }
}

dvp! {
    #[sig="(center, radius, texture, /)"]
    #[repr="Sphere({}, {})"]
    #[str="<Sphere object at {} with radius {}>"]
    Sphere {
        center: Vec (center),
        radius: f64 (radius),
    };

    #[sig="(origin, normal, texture, /)"]
    #[repr="InfinitePlane({}, {})"]
    #[str="<InfinitePlane object at {} with normal {}>"]
    InfinitePlane {
        origin: Vec (orig),
        normal: Vec (normal),
    };

    #[sig="(vertex, edge1, edge2, texture, /)"]
    #[repr="Triangle({}, {}, {})"]
    #[str="<Triangle object at {} with edges {}, {}>"]
    Triangle {
        vertex: Vec (a),
        edge1: Vec (u),
        edge2: Vec (v),
    };

    #[sig="(vertex, edge1, edge2, texture, /)"]
    #[repr="Parallelogram({}, {}, {})"]
    #[str="<Parallelogram object at {} with edges {}, {}>"]
    Parallelogram {
        vertex: Vec (a),
        edge1: Vec (u),
        edge2: Vec (v),
    };

    #[sig="(vertex, edge1, edge2, edge3, texture, /)"]
    #[repr="Rhomboid({}, {}, {}, {})"]
    #[str="<Rhomboid object at {} with edges {}, {}, {}>"]
    Rhomboid {
        vertex: Vec (a),
        edge1: Vec (u),
        edge2: Vec (v),
        edge3: Vec (w),
    };

    #[sig="(center1, center2, radius, texture, /)"]
    #[repr="EmptyCylinder({}, {}, {})"]
    #[str="<EmptyCylinder object between {} and {} with radius {}>"]
    EmptyCylinder {
        center1: Vec (center1),
        center2: Vec (center2),
        radius: f64 (radius),
    };

    #[sig="(center, normal, radius, texture, /)"]
    #[repr="Disc({}, {}, {})"]
    #[str="<Disc object at {} with normal {} and radius {}>"]
    Disc {
        center: Vec (center),
        normal: Vec (normal),
        radius: f64 (radius),
    };

    #[sig="(center1, center2, radius, texture, /)"]
    #[repr="Cylinder({}, {}, {})"]
    #[str="<Cylinder object between {} and {} with radius {}>"]
    Cylinder {
        center1: Vec (center1),
        center2: Vec (center2),
        radius: f64 (radius),
    };

    #[sig="(vertex, direction, angle, begin, end, texture, /)"]
    #[repr="EmptyCone({}, {}, {}, {}, {})"]
    #[str="<EmptyCone object at {} with direction {}, angle {}, from {} to {}>"]
    EmptyCone {
        vertex: Vec (orig),
        direction: Vec (dir),
        angle: f64 (angle),
        begin: f64 (begin),
        end: f64 (end),
    };

    #[sig="(vertex, direction, angle, begin, end, texture, /)"]
    #[repr="Cone({}, {}, {}, {}, {})"]
    #[str="<Cone object at {} with direction {}, angle {}, from {} to {}>"]
    Cone{
        vertex: Vec (orig),
        direction: Vec (dir),
        angle: f64 (angle),
        begin: f64 (begin),
        end: f64 (end),
    };
}