use std::{
any::Any,
fmt::Debug,
ops::{Add, Mul, Sub},
rc::Rc,
};
use nalgebra as na;
use crate::scad_display::ScadDisplay as _;
pub type Unit = f64;
pub type Container2D<T> = na::Vector2<T>;
pub type Container3D<T> = na::Vector3<T>;
pub type Point2D = Container2D<Unit>;
pub type Point3D = Container3D<Unit>;
pub type AffineMatrix2D = na::Matrix2x3<Unit>;
pub type AffineMatrix3D = na::Matrix3x4<Unit>;
pub const INDENT: usize = 2;
pub trait ScadBuilder: Default {
type Sentence;
type Error: Debug;
fn build_scad(&self) -> Result<Self::Sentence, Self::Error>;
}
pub trait ScadBuildable: Sized {
type Builder: ScadBuilder;
type Target;
fn build_with<T: FnOnce(&mut Self::Builder)>(builder_config: T) -> Self::Target
where
Self::Target: From<<<Self as ScadBuildable>::Builder as ScadBuilder>::Sentence>,
{
let mut builder = Self::Builder::default();
builder_config(&mut builder);
let sentence = builder.build_scad().expect("required fields are not set");
sentence.into()
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum DimensionMarker {
Object2D,
Object3D,
ObjectMixed,
}
pub trait DimensionType {
const MARKER: DimensionMarker;
}
#[derive(Clone, Copy, Debug, Default)]
pub struct D2;
impl DimensionType for D2 {
const MARKER: DimensionMarker = DimensionMarker::Object2D;
}
#[derive(Clone, Copy, Debug, Default)]
pub struct D3;
impl DimensionType for D3 {
const MARKER: DimensionMarker = DimensionMarker::Object3D;
}
#[derive(Clone, Copy, Debug, Default)]
pub struct DMixed;
impl DimensionType for DMixed {
const MARKER: DimensionMarker = DimensionMarker::ObjectMixed;
}
pub trait ScadObjectTrait {
fn to_code(&self) -> String;
fn get_type(&self) -> DimensionMarker;
}
#[derive(Clone, Debug)]
pub struct ScadObjectGeneric<D: DimensionType> {
pub(crate) inner: Rc<ScadObjectImpl>,
pub(crate) phantom: std::marker::PhantomData<D>,
}
impl<D: DimensionType> ScadObjectGeneric<D> {
pub fn from_impl(inner: Rc<ScadObjectImpl>) -> Self {
if D::MARKER != DimensionMarker::ObjectMixed {
debug_assert!(
inner.get_type() == D::MARKER,
"dimension marker mismatch at construction"
);
}
Self {
inner,
phantom: std::marker::PhantomData,
}
}
pub fn commented(mut self, comment: &str) -> Self {
let already_wrapped = match &*self.inner {
ScadObjectImpl::Object2D(rc) => rc
.as_any()
.downcast_ref::<ScadObjectImplWithComment>()
.is_some(),
ScadObjectImpl::Object3D(rc) => rc
.as_any()
.downcast_ref::<ScadObjectImplWithComment>()
.is_some(),
ScadObjectImpl::ObjectMixed(rc) => rc
.as_any()
.downcast_ref::<ScadObjectImplWithComment>()
.is_some(),
};
if !already_wrapped {
let old_inner = Rc::clone(&self.inner);
let new_impl = match old_inner.get_type() {
DimensionMarker::Object2D => ScadObjectImpl::Object2D(Rc::new(
ScadObjectImplWithComment::new(old_inner, comment.to_string()),
)),
DimensionMarker::Object3D => ScadObjectImpl::Object3D(Rc::new(
ScadObjectImplWithComment::new(old_inner, comment.to_string()),
)),
DimensionMarker::ObjectMixed => ScadObjectImpl::ObjectMixed(Rc::new(
ScadObjectImplWithComment::new(old_inner, comment.to_string()),
)),
};
self.inner = Rc::new(new_impl);
}
self
}
pub fn to_code(&self) -> String {
self.inner.to_code()
}
pub fn into_wrapper(self) -> ScadObjectWrapperToDeprecated {
ScadObjectWrapperToDeprecated {
inner: Rc::downgrade(&self.inner),
}
}
}
#[derive(Clone, Debug)]
pub struct ScadObjectWrapperToDeprecated {
pub(crate) inner: std::rc::Weak<ScadObjectImpl>,
}
impl ScadObjectWrapperToDeprecated {
pub fn to_code(&self) -> String {
match self.inner.upgrade() {
Some(rc) => rc.to_code(),
_ => String::new(),
}
}
pub fn get_type(&self) -> DimensionMarker {
match self.inner.upgrade() {
Some(rc) => rc.get_type(),
_ => DimensionMarker::ObjectMixed,
}
}
}
pub enum ScadObjectImpl {
Object2D(Rc<dyn ScadObjectRepr2D>),
Object3D(Rc<dyn ScadObjectRepr3D>),
ObjectMixed(Rc<dyn ScadObjectReprMixed>),
}
impl ScadObjectImpl {
pub fn to_code(&self) -> String {
match self {
Self::Object2D(v) => v.as_ref().to_code(),
Self::Object3D(v) => v.as_ref().to_code(),
Self::ObjectMixed(v) => v.as_ref().to_code(),
}
}
pub const fn get_type(&self) -> DimensionMarker {
match self {
Self::Object2D(_) => DimensionMarker::Object2D,
Self::Object3D(_) => DimensionMarker::Object3D,
Self::ObjectMixed(_) => DimensionMarker::ObjectMixed,
}
}
}
impl Clone for ScadObjectImpl {
fn clone(&self) -> Self {
match self {
Self::Object2D(rc) => Self::Object2D(Rc::clone(rc)),
Self::Object3D(rc) => Self::Object3D(Rc::clone(rc)),
Self::ObjectMixed(rc) => Self::ObjectMixed(Rc::clone(rc)),
}
}
}
impl Debug for ScadObjectImpl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Object2D(_) => f.debug_tuple("ScadObjectImpl::Object2D").finish(),
Self::Object3D(_) => f.debug_tuple("ScadObjectImpl::Object3D").finish(),
Self::ObjectMixed(_) => f.debug_tuple("ScadObjectImpl::ObjectMixed").finish(),
}
}
}
pub trait ScadObjectRepr2D: Any {
fn to_code(&self) -> String;
fn as_any(&self) -> &dyn Any;
}
pub trait ScadObjectRepr3D: Any {
fn to_code(&self) -> String;
fn as_any(&self) -> &dyn Any;
}
pub trait ScadObjectReprMixed: Any {
fn to_code(&self) -> String;
fn as_any(&self) -> &dyn Any;
}
#[derive(Debug, Clone)]
pub struct ScadObjectImplWithComment {
pub child: Rc<ScadObjectImpl>,
pub comment: String,
}
impl ScadObjectImplWithComment {
pub const fn new(child: Rc<ScadObjectImpl>, comment: String) -> Self {
Self { child, comment }
}
fn prefixed_code(&self) -> String {
format!("/* {} */\n{}", self.comment, self.child.to_code())
}
}
impl ScadObjectRepr2D for ScadObjectImplWithComment {
fn to_code(&self) -> String {
self.prefixed_code()
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl ScadObjectRepr3D for ScadObjectImplWithComment {
fn to_code(&self) -> String {
self.prefixed_code()
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl ScadObjectReprMixed for ScadObjectImplWithComment {
fn to_code(&self) -> String {
self.prefixed_code()
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl ScadObjectRepr2D for crate::scad_2d::ScadObject2D {
fn to_code(&self) -> String {
self.repr_scad()
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl ScadObjectRepr3D for crate::scad_3d::ScadObject3D {
fn to_code(&self) -> String {
self.repr_scad()
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl ScadObjectReprMixed for crate::scad_mixed::ScadObjectMixed {
fn to_code(&self) -> String {
self.repr_scad()
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub type ScadObjectUntyped = ScadObjectGeneric<DMixed>;
pub type ScadObject = ScadObjectUntyped;
pub type ScadObject2D = ScadObjectGeneric<D2>;
pub type ScadObject3D = ScadObjectGeneric<D3>;
fn flatten_union_parts_2d(rc: &Rc<ScadObjectImpl>, parts: &mut Vec<ScadObjectImpl>) {
if let ScadObjectImpl::Object2D(inner_enum_rc) = &**rc {
if let Some(concrete) = inner_enum_rc
.as_any()
.downcast_ref::<crate::scad_2d::ScadObject2D>()
{
match concrete {
crate::scad_2d::ScadObject2D::Modifier(m) => {
if let crate::scad_2d::ScadModifierBody2D::Union(_) = m.body {
if let ScadObjectImpl::Object2D(child_enum_rc) = &*m.child {
if let Some(crate::scad_2d::ScadObject2D::Block(b)) = child_enum_rc
.as_any()
.downcast_ref::<crate::scad_2d::ScadObject2D>()
{
for obj in &b.objects {
parts.push(obj.clone());
}
return;
}
}
}
}
crate::scad_2d::ScadObject2D::Block(b) => {
for obj in &b.objects {
parts.push(obj.clone());
}
return;
}
_ => {}
}
}
}
parts.push((**rc).clone());
}
fn create_union_object_2d(parts: Vec<ScadObjectImpl>) -> ScadObject {
let block = crate::scad_2d::ScadBlock2D { objects: parts };
let obj_enum = crate::scad_2d::ScadObject2D::Block(block);
let rc_impl_child = Rc::new(ScadObjectImpl::Object2D(Rc::new(obj_enum)));
let body = crate::scad_sentence::Union::new();
let m = crate::scad_2d::ScadModifier2D::try_new(body.into(), Rc::clone(&rc_impl_child))
.expect("Union modifier requires: Object2D");
let o = crate::scad_2d::ScadObject2D::Modifier(m);
let rc_impl = Rc::new(ScadObjectImpl::Object2D(Rc::new(o)));
ScadObject::from_impl(rc_impl)
}
fn flatten_union_parts_3d(rc: &Rc<ScadObjectImpl>, parts: &mut Vec<ScadObjectImpl>) {
if let ScadObjectImpl::Object3D(inner_enum_rc) = &**rc {
if let Some(concrete) = inner_enum_rc
.as_any()
.downcast_ref::<crate::scad_3d::ScadObject3D>()
{
match concrete {
crate::scad_3d::ScadObject3D::Modifier(m) => {
if let crate::scad_3d::ScadModifierBody3D::Union(_) = m.body {
if let ScadObjectImpl::Object3D(child_enum_rc) = &*m.child {
if let Some(crate::scad_3d::ScadObject3D::Block(b)) = child_enum_rc
.as_any()
.downcast_ref::<crate::scad_3d::ScadObject3D>()
{
for obj in &b.objects {
parts.push(obj.clone());
}
return;
}
}
}
}
crate::scad_3d::ScadObject3D::Block(b) => {
for obj in &b.objects {
parts.push(obj.clone());
}
return;
}
_ => {}
}
}
}
parts.push((**rc).clone());
}
fn create_union_object_3d(parts: Vec<ScadObjectImpl>) -> ScadObject {
let block = crate::scad_3d::ScadBlock3D { objects: parts };
let obj_enum = crate::scad_3d::ScadObject3D::Block(block);
let rc_impl_child = Rc::new(ScadObjectImpl::Object3D(Rc::new(obj_enum)));
let body = crate::scad_sentence::Union::new();
let m = crate::scad_3d::ScadModifier3D::try_new(body.into(), Rc::clone(&rc_impl_child))
.expect("Union modifier requires: Object3D");
let o = crate::scad_3d::ScadObject3D::Modifier(m);
let rc_impl = Rc::new(ScadObjectImpl::Object3D(Rc::new(o)));
ScadObject::from_impl(rc_impl)
}
fn flatten_difference_parts_2d(rc: &Rc<ScadObjectImpl>, parts: &mut Vec<ScadObjectImpl>) {
if let ScadObjectImpl::Object2D(inner_enum_rc) = &**rc {
if let Some(concrete) = inner_enum_rc
.as_any()
.downcast_ref::<crate::scad_2d::ScadObject2D>()
{
match concrete {
crate::scad_2d::ScadObject2D::Modifier(m) => {
if let crate::scad_2d::ScadModifierBody2D::Difference(_) = m.body {
if let ScadObjectImpl::Object2D(child_enum_rc) = &*m.child {
if let Some(crate::scad_2d::ScadObject2D::Block(b)) = child_enum_rc
.as_any()
.downcast_ref::<crate::scad_2d::ScadObject2D>()
{
for obj in &b.objects {
parts.push(obj.clone());
}
return;
}
}
}
}
crate::scad_2d::ScadObject2D::Block(b) => {
for obj in &b.objects {
parts.push(obj.clone());
}
return;
}
_ => {}
}
}
}
parts.push((**rc).clone());
}
fn create_difference_object_2d(parts: Vec<ScadObjectImpl>) -> ScadObject {
let block = crate::scad_2d::ScadBlock2D { objects: parts };
let obj_enum = crate::scad_2d::ScadObject2D::Block(block);
let rc_child = Rc::new(ScadObjectImpl::Object2D(Rc::new(obj_enum)));
let body = crate::scad_sentence::Difference::new();
let m = crate::scad_2d::ScadModifier2D::try_new(body.into(), Rc::clone(&rc_child))
.expect("Difference modifier requires: Object2D");
let o = crate::scad_2d::ScadObject2D::Modifier(m);
let rc_impl = Rc::new(ScadObjectImpl::Object2D(Rc::new(o)));
ScadObject::from_impl(rc_impl)
}
fn flatten_difference_parts_3d(rc: &Rc<ScadObjectImpl>, parts: &mut Vec<ScadObjectImpl>) {
if let ScadObjectImpl::Object3D(inner_enum_rc) = &**rc {
if let Some(concrete) = inner_enum_rc
.as_any()
.downcast_ref::<crate::scad_3d::ScadObject3D>()
{
match concrete {
crate::scad_3d::ScadObject3D::Modifier(m) => {
if let crate::scad_3d::ScadModifierBody3D::Difference(_) = m.body {
if let ScadObjectImpl::Object3D(child_enum_rc) = &*m.child {
if let Some(crate::scad_3d::ScadObject3D::Block(b)) = child_enum_rc
.as_any()
.downcast_ref::<crate::scad_3d::ScadObject3D>()
{
for obj in &b.objects {
parts.push(obj.clone());
}
return;
}
}
}
}
crate::scad_3d::ScadObject3D::Block(b) => {
for obj in &b.objects {
parts.push(obj.clone());
}
return;
}
_ => {}
}
}
}
parts.push((**rc).clone());
}
fn create_difference_object_3d(parts: Vec<ScadObjectImpl>) -> ScadObject {
let block = crate::scad_3d::ScadBlock3D { objects: parts };
let obj_enum = crate::scad_3d::ScadObject3D::Block(block);
let rc_impl_child = Rc::new(ScadObjectImpl::Object3D(Rc::new(obj_enum)));
let body = crate::scad_sentence::Difference::new();
let m = crate::scad_3d::ScadModifier3D::try_new(body.into(), Rc::clone(&rc_impl_child))
.expect("Difference modifier requires: Object3D");
let o = crate::scad_3d::ScadObject3D::Modifier(m);
let rc_impl = Rc::new(ScadObjectImpl::Object3D(Rc::new(o)));
ScadObject::from_impl(rc_impl)
}
fn flatten_intersection_parts_2d(rc: &Rc<ScadObjectImpl>, parts: &mut Vec<ScadObjectImpl>) {
if let ScadObjectImpl::Object2D(inner_enum_rc) = &**rc {
if let Some(concrete) = inner_enum_rc
.as_any()
.downcast_ref::<crate::scad_2d::ScadObject2D>()
{
match concrete {
crate::scad_2d::ScadObject2D::Modifier(m) => {
if let crate::scad_2d::ScadModifierBody2D::Intersection(_) = m.body {
if let ScadObjectImpl::Object2D(child_enum_rc) = &*m.child {
if let Some(crate::scad_2d::ScadObject2D::Block(b)) = child_enum_rc
.as_any()
.downcast_ref::<crate::scad_2d::ScadObject2D>()
{
for obj in &b.objects {
parts.push(obj.clone());
}
return;
}
}
}
}
crate::scad_2d::ScadObject2D::Block(b) => {
for obj in &b.objects {
parts.push(obj.clone());
}
return;
}
_ => {}
}
}
}
parts.push((**rc).clone());
}
fn create_intersection_object_2d(parts: Vec<ScadObjectImpl>) -> ScadObject {
let block = crate::scad_2d::ScadBlock2D { objects: parts };
let obj_enum = crate::scad_2d::ScadObject2D::Block(block);
let rc_child = Rc::new(ScadObjectImpl::Object2D(Rc::new(obj_enum)));
let body = crate::scad_sentence::Intersection::new();
let m = crate::scad_2d::ScadModifier2D::try_new(body.into(), Rc::clone(&rc_child))
.expect("Intersection modifier requires: Object2D");
let o = crate::scad_2d::ScadObject2D::Modifier(m);
let rc_impl = Rc::new(ScadObjectImpl::Object2D(Rc::new(o)));
ScadObject::from_impl(rc_impl)
}
fn flatten_intersection_parts_3d(rc: &Rc<ScadObjectImpl>, parts: &mut Vec<ScadObjectImpl>) {
if let ScadObjectImpl::Object3D(inner_enum_rc) = &**rc {
if let Some(concrete) = inner_enum_rc
.as_any()
.downcast_ref::<crate::scad_3d::ScadObject3D>()
{
match concrete {
crate::scad_3d::ScadObject3D::Modifier(m) => {
if let crate::scad_3d::ScadModifierBody3D::Intersection(_) = m.body {
if let ScadObjectImpl::Object3D(child_enum_rc) = &*m.child {
if let Some(crate::scad_3d::ScadObject3D::Block(b)) = child_enum_rc
.as_any()
.downcast_ref::<crate::scad_3d::ScadObject3D>()
{
for obj in &b.objects {
parts.push(obj.clone());
}
return;
}
}
}
}
crate::scad_3d::ScadObject3D::Block(b) => {
for obj in &b.objects {
parts.push(obj.clone());
}
return;
}
_ => {}
}
}
}
parts.push((**rc).clone());
}
fn create_intersection_object_3d(parts: Vec<ScadObjectImpl>) -> ScadObject {
let block = crate::scad_3d::ScadBlock3D { objects: parts };
let obj_enum = crate::scad_3d::ScadObject3D::Block(block);
let rc_impl_child = Rc::new(ScadObjectImpl::Object3D(Rc::new(obj_enum)));
let body = crate::scad_sentence::Intersection::new();
let m = crate::scad_3d::ScadModifier3D::try_new(body.into(), Rc::clone(&rc_impl_child))
.expect("Intersection modifier requires: Object3D");
let o = crate::scad_3d::ScadObject3D::Modifier(m);
let rc_impl = Rc::new(ScadObjectImpl::Object3D(Rc::new(o)));
ScadObject::from_impl(rc_impl)
}
impl Add for ScadObject2D {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let mut parts: Vec<ScadObjectImpl> = Vec::new();
flatten_union_parts_2d(&self.inner, &mut parts);
flatten_union_parts_2d(&rhs.inner, &mut parts);
create_union_object_2d(parts).into()
}
}
impl Add for ScadObject3D {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let mut parts: Vec<ScadObjectImpl> = Vec::new();
flatten_union_parts_3d(&self.inner, &mut parts);
flatten_union_parts_3d(&rhs.inner, &mut parts);
create_union_object_3d(parts).into()
}
}
impl Add<ScadObject> for ScadObject2D {
type Output = ScadObject;
fn add(self, rhs: ScadObject) -> Self::Output {
ScadObject::from(self) + rhs
}
}
impl Add<ScadObject2D> for ScadObject {
type Output = Self;
fn add(self, rhs: ScadObject2D) -> Self::Output {
self + Self::from(rhs)
}
}
impl Add<ScadObject> for ScadObject3D {
type Output = ScadObject;
fn add(self, rhs: ScadObject) -> Self::Output {
ScadObject::from(self) + rhs
}
}
impl Add<ScadObject3D> for ScadObject {
type Output = Self;
fn add(self, rhs: ScadObject3D) -> Self::Output {
self + Self::from(rhs)
}
}
impl Add for ScadObject {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let left_rc = self.inner;
let right_rc = rhs.inner;
let left_type = left_rc.get_type();
let right_type = right_rc.get_type();
if left_type == DimensionMarker::ObjectMixed || right_type == DimensionMarker::ObjectMixed {
let parts: Vec<ScadObjectImpl> =
vec![Rc::unwrap_or_clone(left_rc), Rc::unwrap_or_clone(right_rc)];
let block = crate::scad_mixed::ScadBlockMixed::new(&parts);
let child = crate::scad_mixed::ScadObjectMixed::Block(block);
let rc_child = Rc::new(ScadObjectImpl::ObjectMixed(Rc::new(child)));
let body = crate::scad_sentence::Union::new();
let modifier = crate::scad_mixed::ScadModifierMixed::new(body.into(), rc_child);
let o = crate::scad_mixed::ScadObjectMixed::Modifier(modifier);
let rc_impl = Rc::new(ScadObjectImpl::ObjectMixed(Rc::new(o)));
return Self::from_impl(rc_impl);
}
assert!(
left_type == right_type,
"`{}` is not allowed",
match (left_type, right_type) {
(DimensionMarker::Object2D, DimensionMarker::Object3D) => "Object2D + Object3D",
(DimensionMarker::Object3D, DimensionMarker::Object2D) => "Object3D + Object2D",
_ => "Mismatched dimensions",
}
);
match left_type {
DimensionMarker::Object2D => {
let mut parts: Vec<ScadObjectImpl> = Vec::new();
flatten_union_parts_2d(&left_rc, &mut parts);
flatten_union_parts_2d(&right_rc, &mut parts);
create_union_object_2d(parts)
}
DimensionMarker::Object3D => {
let mut parts: Vec<ScadObjectImpl> = Vec::new();
flatten_union_parts_3d(&left_rc, &mut parts);
flatten_union_parts_3d(&right_rc, &mut parts);
create_union_object_3d(parts)
}
DimensionMarker::ObjectMixed => unreachable!(),
}
}
}
impl Sub for ScadObject2D {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let mut parts: Vec<ScadObjectImpl> = Vec::new();
flatten_difference_parts_2d(&self.inner, &mut parts);
parts.push(Rc::unwrap_or_clone(rhs.inner));
create_difference_object_2d(parts).into()
}
}
impl Sub for ScadObject3D {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let mut parts: Vec<ScadObjectImpl> = Vec::new();
flatten_difference_parts_3d(&self.inner, &mut parts);
parts.push(Rc::unwrap_or_clone(rhs.inner));
create_difference_object_3d(parts).into()
}
}
impl Sub<ScadObject> for ScadObject2D {
type Output = ScadObject;
fn sub(self, rhs: ScadObject) -> Self::Output {
ScadObject::from(self) - rhs
}
}
impl Sub<ScadObject2D> for ScadObject {
type Output = Self;
fn sub(self, rhs: ScadObject2D) -> Self::Output {
self - Self::from(rhs)
}
}
impl Sub<ScadObject> for ScadObject3D {
type Output = ScadObject;
fn sub(self, rhs: ScadObject) -> Self::Output {
ScadObject::from(self) - rhs
}
}
impl Sub<ScadObject3D> for ScadObject {
type Output = Self;
fn sub(self, rhs: ScadObject3D) -> Self::Output {
self - Self::from(rhs)
}
}
impl Sub for ScadObject {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let left_rc = self.inner;
let right_rc = rhs.inner;
let left_type = left_rc.get_type();
let right_type = right_rc.get_type();
if left_type == DimensionMarker::ObjectMixed || right_type == DimensionMarker::ObjectMixed {
let parts: Vec<ScadObjectImpl> =
vec![Rc::unwrap_or_clone(left_rc), Rc::unwrap_or_clone(right_rc)];
let block = crate::scad_mixed::ScadBlockMixed::new(&parts);
let child = crate::scad_mixed::ScadObjectMixed::Block(block);
let rc_child = Rc::new(ScadObjectImpl::ObjectMixed(Rc::new(child)));
let body = crate::scad_sentence::Difference::new();
let modifier = crate::scad_mixed::ScadModifierMixed::new(body.into(), rc_child);
let o = crate::scad_mixed::ScadObjectMixed::Modifier(modifier);
let rc_impl = Rc::new(ScadObjectImpl::ObjectMixed(Rc::new(o)));
return Self::from_impl(rc_impl);
}
assert!(
left_type == right_type,
"`{}` is not allowed",
match (left_type, right_type) {
(DimensionMarker::Object2D, DimensionMarker::Object3D) => "Object2D - Object3D",
(DimensionMarker::Object3D, DimensionMarker::Object2D) => "Object3D - Object2D",
_ => "Mismatched dimensions",
}
);
match left_type {
DimensionMarker::Object2D => {
let mut parts: Vec<ScadObjectImpl> = Vec::new();
flatten_difference_parts_2d(&left_rc, &mut parts);
parts.push(Rc::unwrap_or_clone(right_rc));
create_difference_object_2d(parts)
}
DimensionMarker::Object3D => {
let mut parts: Vec<ScadObjectImpl> = Vec::new();
flatten_difference_parts_3d(&left_rc, &mut parts);
parts.push(Rc::unwrap_or_clone(right_rc));
create_difference_object_3d(parts)
}
DimensionMarker::ObjectMixed => unreachable!(),
}
}
}
impl Mul for ScadObject2D {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
let mut parts: Vec<ScadObjectImpl> = Vec::new();
flatten_intersection_parts_2d(&self.inner, &mut parts);
flatten_intersection_parts_2d(&rhs.inner, &mut parts);
create_intersection_object_2d(parts).into()
}
}
impl Mul for ScadObject3D {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
let mut parts: Vec<ScadObjectImpl> = Vec::new();
flatten_intersection_parts_3d(&self.inner, &mut parts);
flatten_intersection_parts_3d(&rhs.inner, &mut parts);
create_intersection_object_3d(parts).into()
}
}
impl Mul<ScadObject> for ScadObject2D {
type Output = ScadObject;
fn mul(self, rhs: ScadObject) -> Self::Output {
ScadObject::from(self) * rhs
}
}
impl Mul<ScadObject2D> for ScadObject {
type Output = Self;
fn mul(self, rhs: ScadObject2D) -> Self::Output {
self * Self::from(rhs)
}
}
impl Mul<ScadObject> for ScadObject3D {
type Output = ScadObject;
fn mul(self, rhs: ScadObject) -> Self::Output {
ScadObject::from(self) * rhs
}
}
impl Mul<ScadObject3D> for ScadObject {
type Output = Self;
fn mul(self, rhs: ScadObject3D) -> Self::Output {
self * Self::from(rhs)
}
}
impl Mul for ScadObject {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
let left_rc = self.inner;
let right_rc = rhs.inner;
let left_type = left_rc.get_type();
let right_type = right_rc.get_type();
if left_type == DimensionMarker::ObjectMixed || right_type == DimensionMarker::ObjectMixed {
let parts: Vec<ScadObjectImpl> =
vec![Rc::unwrap_or_clone(left_rc), Rc::unwrap_or_clone(right_rc)];
let block = crate::scad_mixed::ScadBlockMixed::new(&parts);
let child = crate::scad_mixed::ScadObjectMixed::Block(block);
let rc_child = Rc::new(ScadObjectImpl::ObjectMixed(Rc::new(child)));
let body = crate::scad_sentence::Intersection::new();
let modifier = crate::scad_mixed::ScadModifierMixed::new(body.into(), rc_child);
let o = crate::scad_mixed::ScadObjectMixed::Modifier(modifier);
let rc_impl = Rc::new(ScadObjectImpl::ObjectMixed(Rc::new(o)));
return Self::from_impl(rc_impl);
}
assert!(
left_type == right_type,
"`{}` is not allowed",
match (left_type, right_type) {
(DimensionMarker::Object2D, DimensionMarker::Object3D) => "Object2D * Object3D",
(DimensionMarker::Object3D, DimensionMarker::Object2D) => "Object3D * Object2D",
_ => "Mismatched dimensions",
}
);
match left_type {
DimensionMarker::Object2D => {
let mut parts: Vec<ScadObjectImpl> = Vec::new();
flatten_intersection_parts_2d(&left_rc, &mut parts);
flatten_intersection_parts_2d(&right_rc, &mut parts);
create_intersection_object_2d(parts)
}
DimensionMarker::Object3D => {
let mut parts: Vec<ScadObjectImpl> = Vec::new();
flatten_intersection_parts_3d(&left_rc, &mut parts);
flatten_intersection_parts_3d(&right_rc, &mut parts);
create_intersection_object_3d(parts)
}
DimensionMarker::ObjectMixed => unreachable!(),
}
}
}
impl From<ScadObjectGeneric<D2>> for ScadObjectGeneric<DMixed> {
fn from(val: ScadObjectGeneric<D2>) -> Self {
Self::from_impl(val.inner)
}
}
impl From<ScadObjectGeneric<D3>> for ScadObjectGeneric<DMixed> {
fn from(val: ScadObjectGeneric<D3>) -> Self {
Self::from_impl(val.inner)
}
}
impl From<ScadObjectGeneric<DMixed>> for ScadObjectGeneric<D2> {
fn from(val: ScadObjectGeneric<DMixed>) -> Self {
assert!(
val.inner.get_type() == D2::MARKER,
"dimension mismatch: expected 2D object, found {:?}",
val.inner.get_type()
);
Self::from_impl(val.inner)
}
}
impl From<ScadObjectGeneric<DMixed>> for ScadObjectGeneric<D3> {
fn from(val: ScadObjectGeneric<DMixed>) -> Self {
assert!(
val.inner.get_type() == D3::MARKER,
"dimension mismatch: expected 3D object, found {:?}",
val.inner.get_type()
);
Self::from_impl(val.inner)
}
}