use std::rc::Rc;
use ambassador::Delegate;
use derive_more::derive::From;
use crate::{
common::DimensionMarker,
internal::{block_repr, modifier_repr, primitive_repr},
prelude::{
Circle, Color, Difference, Hull, Import2D, Intersection, Minkowski, Mirror2D, MultMatrix2D,
Offset, Polygon, Projection, Resize2D, Rotate2D, Scale2D, Square, Text, Translate2D, Union,
},
scad_display::{ambassador_impl_ScadDisplay, ScadDisplay},
};
#[derive(Debug, Clone, From)]
pub enum ScadObject2D {
Primitive(ScadPrimitive2D),
Modifier(ScadModifier2D),
Block(ScadBlock2D),
}
impl ScadDisplay for ScadObject2D {
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 ScadPrimitive2D {
pub body: ScadPrimitiveBody2D,
}
impl ScadPrimitive2D {
pub const fn new(body: ScadPrimitiveBody2D) -> Self {
Self { body }
}
}
impl ScadDisplay for ScadPrimitive2D {
fn repr_scad(&self) -> String {
primitive_repr(&self.body)
}
}
impl From<ScadPrimitive2D> for crate::common::ScadObjectGeneric<crate::common::D2> {
fn from(val: ScadPrimitive2D) -> Self {
let o = ScadObject2D::Primitive(val);
let rc_o = Rc::new(o);
let rc_impl = Rc::new(crate::common::ScadObjectImpl::Object2D(rc_o));
Self::from_impl(rc_impl)
}
}
#[derive(Debug, Clone, From)]
pub struct ScadModifier2D {
pub body: ScadModifierBody2D,
pub child: Rc<crate::common::ScadObjectImpl>,
}
impl ScadModifier2D {
pub fn try_new(
body: ScadModifierBody2D,
child: Rc<crate::common::ScadObjectImpl>,
) -> Option<Self> {
(child.get_type() == body.get_children_type()).then_some(Self { body, child })
}
}
impl ScadDisplay for ScadModifier2D {
fn repr_scad(&self) -> String {
modifier_repr(&self.body, &self.child)
}
}
#[derive(Debug, Clone, From)]
pub struct ScadBlock2D {
pub objects: Vec<crate::common::ScadObjectImpl>,
}
impl ScadDisplay for ScadBlock2D {
fn repr_scad(&self) -> String {
block_repr(&self.objects)
}
}
impl ScadBlock2D {
pub fn try_new(objects: &[crate::common::ScadObjectImpl]) -> Option<Self> {
objects
.iter()
.all(|o| o.get_type() == DimensionMarker::Object2D)
.then_some(Self {
objects: objects.to_vec(),
})
}
}
__impl_from_scad_for_collection_with_try_new!(
crate::common::D2,
ScadBlock2D,
ScadObject2D,
crate::common::ScadObjectImpl::Object2D,
"Internal error: Vec<T> or &[T] for D2 should always produce a valid ScadBlock2D"
);
impl From<ScadObject2D> for crate::common::ScadObjectGeneric<crate::common::D2> {
fn from(val: ScadObject2D) -> Self {
let rc_o = Rc::new(val);
let rc_impl = Rc::new(crate::common::ScadObjectImpl::Object2D(rc_o));
Self::from_impl(rc_impl)
}
}
#[derive(Debug, Clone, Delegate)] #[delegate(ScadDisplay)]
pub enum ScadPrimitiveBody2D {
Circle(Circle),
Import(Import2D),
Polygon(Polygon),
Square(Square),
Text(Text),
}
impl From<Circle> for ScadPrimitiveBody2D {
fn from(val: Circle) -> Self {
Self::Circle(val)
}
}
impl From<Import2D> for ScadPrimitiveBody2D {
fn from(val: Import2D) -> Self {
Self::Import(val)
}
}
impl From<Polygon> for ScadPrimitiveBody2D {
fn from(val: Polygon) -> Self {
Self::Polygon(val)
}
}
impl From<Square> for ScadPrimitiveBody2D {
fn from(val: Square) -> Self {
Self::Square(val)
}
}
impl From<Text> for ScadPrimitiveBody2D {
fn from(val: Text) -> Self {
Self::Text(val)
}
}
#[derive(Debug, Clone, Delegate, From)]
#[delegate(ScadDisplay)]
pub enum ScadModifierBody2D {
Color(Color),
Difference(Difference),
Hull(Hull),
Intersection(Intersection),
Minkowski(Minkowski),
Mirror(Mirror2D),
MultMatrix(MultMatrix2D),
Offset(Offset),
Projection(Projection),
Resize(Resize2D),
Rotate(Rotate2D),
Scale(Scale2D),
Translate(Translate2D),
Union(Union),
}
impl ScadModifierBody2D {
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::Offset(_)
| Self::Resize(_)
| Self::Rotate(_)
| Self::Scale(_)
| Self::Translate(_)
| Self::Union(_) => DimensionMarker::Object2D,
Self::Projection(_) => DimensionMarker::Object3D,
}
}
}