use ambassador::Delegate;
use derive_builder::Builder;
use derive_more::derive::From;
use crate::{
common::{AffineMatrix2D, DimensionType as _, Point2D, Unit},
internal::generate_sentence_repr,
scad_display::{ambassador_impl_ScadDisplay, ScadDisplay},
value_type::Angle,
};
use crate::common::D2;
macro_rules! __impl_apply_2d {
($mod_ty:ident) => {
__impl_apply_to_modifier!(
apply_to,
$mod_ty,
$crate::scad_2d::ScadModifierBody2D,
$crate::common::ScadObjectGeneric<$crate::common::D2>, $crate::scad_2d::ScadModifier2D,
$crate::scad_2d::ScadObject2D,
$crate::common::ScadObjectImpl::Object2D,
$crate::common::D2, $crate::common::D2 );
__impl_panicking_modifier_methods!($mod_ty, D2);
};
}
macro_rules! __impl_apply_3d {
($mod_ty:ident) => {
__impl_apply_to_modifier!(
apply_to,
$mod_ty,
$crate::scad_2d::ScadModifierBody2D, $crate::common::ScadObjectGeneric<$crate::common::D2>, $crate::scad_2d::ScadModifier2D, $crate::scad_2d::ScadObject2D, $crate::common::ScadObjectImpl::Object2D, $crate::common::D2, $crate::common::D3 );
__impl_panicking_modifier_methods!($mod_ty, D2);
};
}
#[derive(Builder, Debug, Clone, Copy)]
pub struct Translate2D {
#[builder(setter(into))]
pub v: Point2D,
}
__impl_builder_modifier!(Translate2D);
__impl_modifier_chaining!(Translate2D);
__impl_apply_2d!(Translate2D);
impl ScadDisplay for Translate2D {
fn repr_scad(&self) -> String {
generate_sentence_repr("translate", __generate_scad_options!(("", self.v);))
}
}
#[derive(Builder, Debug, Clone, Copy)]
pub struct Rotate2D {
#[builder(setter(custom))]
pub a: Angle,
}
__impl_builder_modifier!(Rotate2D);
__impl_modifier_chaining!(Rotate2D);
__impl_apply_2d!(Rotate2D);
impl Rotate2DBuilder {
pub const fn deg(&mut self, value: Unit) -> &mut Self {
let new = self;
new.a = Some(Angle::Deg(value));
new
}
pub const fn rad(&mut self, value: Unit) -> &mut Self {
let new = self;
new.a = Some(Angle::Rad(value));
new
}
}
impl ScadDisplay for Rotate2D {
fn repr_scad(&self) -> String {
generate_sentence_repr("rotate", __generate_scad_options!(("a", self.a);))
}
}
#[derive(Builder, Debug, Clone, Copy)]
pub struct Scale2D {
#[builder(setter(into))]
pub v: Point2D,
}
__impl_builder_modifier!(Scale2D);
__impl_modifier_chaining!(Scale2D);
__impl_apply_2d!(Scale2D);
impl ScadDisplay for Scale2D {
fn repr_scad(&self) -> String {
generate_sentence_repr("scale", __generate_scad_options!(("", self.v);))
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, From, Delegate)]
#[delegate(ScadDisplay)]
pub enum ResizeAuto2D {
B(bool),
V([bool; 2]),
}
#[derive(Builder, Debug, Clone, Copy)]
pub struct Resize2D {
#[builder(setter(into))]
pub size: Point2D,
#[builder(setter(into, strip_option), default)]
pub auto: Option<ResizeAuto2D>,
}
__impl_builder_modifier!(Resize2D);
__impl_modifier_chaining!(Resize2D);
__impl_apply_2d!(Resize2D);
impl ScadDisplay for Resize2D {
fn repr_scad(&self) -> String {
generate_sentence_repr(
"resize",
__generate_scad_options!(
("", self.size); opt: (("auto", self.auto);)
),
)
}
}
#[derive(Builder, Debug, Clone, Copy)]
pub struct Mirror2D {
#[builder(setter(into))]
pub v: Point2D,
}
__impl_builder_modifier!(Mirror2D);
__impl_modifier_chaining!(Mirror2D);
__impl_apply_2d!(Mirror2D);
impl ScadDisplay for Mirror2D {
fn repr_scad(&self) -> String {
generate_sentence_repr("mirror", __generate_scad_options!(("", self.v);))
}
}
#[derive(Builder, Debug, Clone, Copy)]
pub struct MultMatrix2D {
#[builder(setter(into))]
pub m: AffineMatrix2D,
}
__impl_builder_modifier!(MultMatrix2D);
__impl_modifier_chaining!(MultMatrix2D);
__impl_apply_2d!(MultMatrix2D);
impl ScadDisplay for MultMatrix2D {
fn repr_scad(&self) -> String {
generate_sentence_repr("multmatrix", __generate_scad_options!(("m", self.m);))
}
}
#[derive(Copy, Clone, Debug, PartialEq, Delegate)]
#[delegate(ScadDisplay)]
pub enum OffsetSize {
R(Unit),
Delta(Unit),
}
impl OffsetSize {
pub const fn name(self) -> &'static str {
match self {
Self::R(_) => "r",
Self::Delta(_) => "delta",
}
}
}
#[derive(Builder, Debug, Clone, Copy)]
pub struct Offset {
#[builder(setter(custom))]
pub size: OffsetSize,
#[builder(setter(into, strip_option), default)]
pub chamfer: Option<bool>,
#[builder(setter(into, strip_option), default)]
pub fa: Option<Unit>,
#[builder(setter(into, strip_option), default)]
pub r#fn: Option<u64>,
#[builder(setter(into, strip_option), default)]
pub fs: Option<Unit>,
}
__impl_builder_modifier!(Offset);
__impl_modifier_chaining!(Offset);
__impl_apply_2d!(Offset);
impl OffsetBuilder {
pub const fn r(&mut self, value: Unit) -> &mut Self {
let new = self;
new.size = Some(OffsetSize::R(value));
new
}
pub const fn delta(&mut self, value: Unit) -> &mut Self {
let new = self;
new.size = Some(OffsetSize::Delta(value));
new
}
}
impl ScadDisplay for Offset {
fn repr_scad(&self) -> String {
generate_sentence_repr(
"offset",
__generate_scad_options!(
(self.size.name(), self.size);
opt: (
("chamfer", self.chamfer);
("$fa", self.fa);
("$fn", self.r#fn);
("$fs", self.fs);
)
),
)
}
}
#[derive(Builder, Debug, Clone, Copy)]
pub struct Projection {
#[builder(setter(into, strip_option), default)]
pub cut: Option<bool>,
}
__impl_builder_modifier!(Projection);
__impl_modifier_chaining!(Projection);
__impl_apply_3d!(Projection);
impl ScadDisplay for Projection {
fn repr_scad(&self) -> String {
generate_sentence_repr(
"projection",
__generate_scad_options!(opt: (("cut", self.cut);)),
)
}
}
#[cfg(test)]
mod tests {
use std::f64::consts::PI;
use super::*;
#[test]
fn test_translate2d() {
assert_eq!(
Translate2DBuilder::default()
.v([8., -4.])
.build()
.unwrap()
.repr_scad(),
"translate([8, -4])"
);
}
#[test]
fn test_rotate2d() {
assert_eq!(
Rotate2DBuilder::default()
.deg(45.)
.build()
.unwrap()
.repr_scad(),
"rotate(a = 45)"
);
assert_eq!(
Rotate2DBuilder::default()
.rad(PI / 4.)
.build()
.unwrap()
.repr_scad(),
"rotate(a = 45)"
);
}
#[test]
fn test_mirror2d() {
assert_eq!(
Mirror2DBuilder::default()
.v([1., -1.])
.build()
.unwrap()
.repr_scad(),
"mirror([1, -1])"
);
}
#[test]
fn test_scale2d() {
assert_eq!(
Scale2DBuilder::default()
.v([3., 2.])
.build()
.unwrap()
.repr_scad(),
"scale([3, 2])"
);
}
#[test]
fn test_resize2d() {
let mut r1 = Resize2DBuilder::default();
_ = r1.size([3., 2.]);
assert_eq!(r1.clone().build().unwrap().repr_scad(), "resize([3, 2])");
assert_eq!(
r1.clone().auto(true).build().unwrap().repr_scad(),
"resize([3, 2], auto = true)"
);
assert_eq!(
r1.auto([true, false]).build().unwrap().repr_scad(),
"resize([3, 2], auto = [true, false])"
);
}
#[test]
fn test_multimatrix2d() {
let m = AffineMatrix2D::new(1., 2., 3., 4., 5., 6.);
assert_eq!(
MultMatrix2DBuilder::default()
.m(m)
.build()
.unwrap()
.repr_scad(),
"multmatrix(m = [[1, 2, 0, 3], [4, 5, 0, 6], [0, 0, 1, 0]])"
);
}
#[test]
fn test_offset() {
assert_eq!(
OffsetBuilder::default().r(1.).build().unwrap().repr_scad(),
"offset(r = 1)"
);
assert_eq!(
OffsetBuilder::default()
.delta(2.)
.build()
.unwrap()
.repr_scad(),
"offset(delta = 2)"
);
assert_eq!(
OffsetBuilder::default()
.r(1.)
.chamfer(true)
.fs(10)
.build()
.unwrap()
.repr_scad(),
"offset(r = 1, chamfer = true, $fs = 10)"
);
}
#[test]
fn test_projection() {
assert_eq!(
ProjectionBuilder::default().build().unwrap().repr_scad(),
"projection()"
);
assert_eq!(
ProjectionBuilder::default()
.cut(true)
.build()
.unwrap()
.repr_scad(),
"projection(cut = true)"
);
}
}