use std::rc::Rc;
use ambassador::Delegate;
use derive_more::derive::From;
use crate::{
common::DimensionMarker,
internal::{block_repr, modifier_repr, primitive_repr},
prelude::{
Color, Cube, Cylinder, Difference, Hull, Import3D, Intersection, LinearExtrude, Minkowski,
Mirror3D, MultMatrix3D, Polyhedron, Resize3D, Rotate3D, RotateExtrude, Scale3D, Sphere,
Surface, Translate3D, Union,
},
scad_display::{ambassador_impl_ScadDisplay, ScadDisplay},
};
#[derive(Debug, Clone, From)]
pub enum ScadObject3D {
Primitive(ScadPrimitive3D),
Modifier(ScadModifier3D),
Block(ScadBlock3D),
}
impl ScadDisplay for ScadObject3D {
fn repr_scad(&self) -> String {
match self {
Self::Primitive(p) => p.repr_scad(),
Self::Modifier(m) => m.repr_scad(),
Self::Block(b) => b.repr_scad(),
}
}
}
#[derive(Debug, Clone, From)]
pub struct ScadPrimitive3D {
pub body: ScadPrimitiveBody3D,
}
impl ScadPrimitive3D {
pub const fn new(body: ScadPrimitiveBody3D) -> Self {
Self { body }
}
}
impl ScadDisplay for ScadPrimitive3D {
fn repr_scad(&self) -> String {
primitive_repr(&self.body)
}
}
impl From<ScadPrimitive3D> for crate::common::ScadObjectGeneric<crate::common::D3> {
fn from(val: ScadPrimitive3D) -> Self {
let o = ScadObject3D::Primitive(val);
let rc_o = Rc::new(o);
let rc_impl = Rc::new(crate::common::ScadObjectImpl::Object3D(rc_o));
Self::from_impl(rc_impl)
}
}
#[derive(Debug, Clone, From)]
pub struct ScadModifier3D {
pub body: ScadModifierBody3D,
pub child: Rc<crate::common::ScadObjectImpl>,
}
impl ScadModifier3D {
pub fn try_new(
body: ScadModifierBody3D,
child: Rc<crate::common::ScadObjectImpl>,
) -> Option<Self> {
(child.get_type() == body.get_children_type()).then_some(Self { body, child })
}
}
impl ScadDisplay for ScadModifier3D {
fn repr_scad(&self) -> String {
modifier_repr(&self.body, &self.child)
}
}
#[derive(Debug, Clone, From)]
pub struct ScadBlock3D {
pub objects: Vec<crate::common::ScadObjectImpl>,
}
impl ScadDisplay for ScadBlock3D {
fn repr_scad(&self) -> String {
block_repr(&self.objects)
}
}
impl ScadBlock3D {
pub fn try_new(objects: &[crate::common::ScadObjectImpl]) -> Option<Self> {
objects
.iter()
.all(|o| o.get_type() == DimensionMarker::Object3D)
.then_some(Self {
objects: objects.to_vec(),
})
}
}
__impl_from_scad_for_collection_with_try_new!(
crate::common::D3,
ScadBlock3D,
ScadObject3D,
crate::common::ScadObjectImpl::Object3D,
"Internal error: Vec<T> or &[T] for D3 should always produce a valid ScadBlock3D"
);
#[derive(Debug, Clone, Delegate)] #[delegate(ScadDisplay)]
pub enum ScadPrimitiveBody3D {
Cube(Cube),
Cylinder(Cylinder),
Import(Import3D),
Polyhedron(Polyhedron),
Sphere(Sphere),
Surface(Surface),
}
impl From<Cube> for ScadPrimitiveBody3D {
fn from(val: Cube) -> Self {
Self::Cube(val)
}
}
impl From<Cylinder> for ScadPrimitiveBody3D {
fn from(val: Cylinder) -> Self {
Self::Cylinder(val)
}
}
impl From<Import3D> for ScadPrimitiveBody3D {
fn from(val: Import3D) -> Self {
Self::Import(val)
}
}
impl From<Polyhedron> for ScadPrimitiveBody3D {
fn from(val: Polyhedron) -> Self {
Self::Polyhedron(val)
}
}
impl From<Sphere> for ScadPrimitiveBody3D {
fn from(val: Sphere) -> Self {
Self::Sphere(val)
}
}
impl From<Surface> for ScadPrimitiveBody3D {
fn from(val: Surface) -> Self {
Self::Surface(val)
}
}
#[derive(Debug, Clone, Delegate, From)]
#[delegate(ScadDisplay)]
pub enum ScadModifierBody3D {
Color(Color),
Difference(Difference),
Hull(Hull),
Intersection(Intersection),
LinearExtrude(LinearExtrude),
Minkowski(Minkowski),
Mirror(Mirror3D),
MultMatrix(MultMatrix3D),
Resize(Resize3D),
Rotate(Rotate3D),
RotateExtrude(RotateExtrude),
Scale(Scale3D),
Translate(Translate3D),
Union(Union),
}
impl ScadModifierBody3D {
pub(crate) const fn get_children_type(&self) -> DimensionMarker {
match self {
Self::Color(_)
| Self::Difference(_)
| Self::Hull(_)
| Self::Intersection(_)
| Self::Minkowski(_)
| Self::Mirror(_)
| Self::MultMatrix(_)
| Self::Resize(_)
| Self::Rotate(_)
| Self::Scale(_)
| Self::Translate(_)
| Self::Union(_) => DimensionMarker::Object3D,
Self::LinearExtrude(_) | Self::RotateExtrude(_) => DimensionMarker::Object2D,
}
}
}
impl From<ScadObject3D> for crate::common::ScadObjectGeneric<crate::common::D3> {
fn from(val: ScadObject3D) -> Self {
let rc_o = Rc::new(val);
let rc_impl = Rc::new(crate::common::ScadObjectImpl::Object3D(rc_o));
Self::from_impl(rc_impl)
}
}