1use glam::{DVec2, DVec3};
17use rscad_core::DynamicObject;
18
19use crate::CsgBackend;
20
21pub trait DynamicBackend: CsgBackend {
23 const SKETCH_IS_CSG: bool = false;
28
29 fn cube(size: [f64; 3]) -> Self::CsgType;
30 fn sphere(radius: f64, segments: usize, stacks: usize) -> Self::CsgType;
32 fn cylinder(radius: f64, height: f64, segments: usize) -> Self::CsgType;
33 fn cone(radius: f64, height: f64, segments: usize) -> Self::CsgType;
34
35 fn circle(radius: f64, segments: usize) -> Self::SketchType;
36 fn square(size: [f64; 2]) -> Self::SketchType;
37 fn polygon(points: &[[f64; 2]]) -> Self::SketchType;
38 fn sketch(loops: &[Vec<DVec2>]) -> Self::SketchType;
41
42 fn offset(
46 sketch: Self::SketchType,
47 _delta: f64,
48 _round: bool,
49 _chamfer: bool,
50 _segments: usize,
51 ) -> Self::SketchType {
52 sketch
53 }
54
55 fn sketch_as_csg(_sketch: Self::SketchType) -> Self::CsgType {
58 Self::empty_csg()
59 }
60 fn csg_as_sketch(_csg: Self::CsgType) -> Self::SketchType {
63 Self::empty_sketch()
64 }
65
66 fn union_all(items: Vec<Self::CsgType>) -> Self::CsgType {
68 items.into_iter().fold(Self::empty_csg(), Self::union)
69 }
70 fn union_all_2d(items: Vec<Self::SketchType>) -> Self::SketchType {
71 items.into_iter().fold(Self::empty_sketch(), Self::union_2d)
72 }
73}
74
75impl<B: DynamicBackend> crate::ToCsg<B> for DynamicObject {
76 fn to_csg(&self) -> B::CsgType {
77 dynamic_to_csg::<B>(self)
78 }
79}
80
81impl<B: DynamicBackend> crate::ToSketch<B> for DynamicObject {
82 fn to_sketch(&self) -> B::SketchType {
83 dynamic_to_sketch::<B>(self)
84 }
85}
86
87pub fn dynamic_to_csg<B: DynamicBackend>(obj: &DynamicObject) -> B::CsgType {
89 match obj {
90 DynamicObject::Cube { size } => B::cube(*size),
91 DynamicObject::Sphere {
92 radius,
93 segments,
94 stacks,
95 } => B::sphere(*radius, *segments, *stacks),
96 DynamicObject::Cylinder {
97 radius,
98 height,
99 segments,
100 } => B::cylinder(*radius, *height, *segments),
101 DynamicObject::Cone {
102 radius,
103 height,
104 segments,
105 } => B::cone(*radius, *height, *segments),
106 DynamicObject::Circle { .. }
107 | DynamicObject::Square { .. }
108 | DynamicObject::Polygon { .. }
109 | DynamicObject::Sketch { .. }
110 | DynamicObject::Offset { .. } => {
111 if B::SKETCH_IS_CSG {
112 B::sketch_as_csg(dynamic_to_sketch::<B>(obj))
113 } else {
114 B::empty_csg()
115 }
116 }
117 DynamicObject::Union { children } | DynamicObject::Group { children } => {
118 B::union_all(children.iter().map(dynamic_to_csg::<B>).collect())
119 }
120 DynamicObject::Difference { children } => match children.as_slice() {
121 [] => B::empty_csg(),
122 [first, rest @ ..] => rest.iter().fold(dynamic_to_csg::<B>(first), |acc, c| {
123 B::difference(acc, dynamic_to_csg::<B>(c))
124 }),
125 },
126 DynamicObject::Intersection { children } => match children.as_slice() {
127 [] => B::empty_csg(),
128 [first, rest @ ..] => rest.iter().fold(dynamic_to_csg::<B>(first), |acc, c| {
129 B::intersection(acc, dynamic_to_csg::<B>(c))
130 }),
131 },
132 DynamicObject::Translate { offset, child } => {
133 B::translate(dynamic_to_csg::<B>(child), DVec3::from_array(*offset))
134 }
135 DynamicObject::Rotate { angles, child } => {
136 B::rotate(dynamic_to_csg::<B>(child), DVec3::from_array(*angles))
137 }
138 DynamicObject::Scale { factors, child } => {
139 B::scale(dynamic_to_csg::<B>(child), DVec3::from_array(*factors))
140 }
141 DynamicObject::Mirror { axis, child } => {
142 B::mirror(dynamic_to_csg::<B>(child), DVec3::from_array(*axis))
143 }
144 DynamicObject::Color { color, child } => {
145 B::color(dynamic_to_csg::<B>(child), color.map(|c| c as f32))
146 }
147 DynamicObject::Material { child, .. } => dynamic_to_csg::<B>(child),
149 DynamicObject::LinearExtrude {
150 height,
151 twist,
152 scale,
153 slices,
154 child,
155 } => B::extrude(
156 dynamic_to_sketch::<B>(child),
157 *height,
158 *twist,
159 *scale,
160 *slices,
161 ),
162 DynamicObject::Revolve {
163 angle_degrees,
164 segments,
165 child,
166 } => B::revolve(dynamic_to_sketch::<B>(child), *angle_degrees, *segments),
167 DynamicObject::EdgeFeature { data, child } => {
170 dynamic_to_csg::<B>(&rscad_core::feature::lower(data, child).0)
171 }
172 DynamicObject::Empty => B::empty_csg(),
173 }
174}
175
176pub fn dynamic_to_sketch<B: DynamicBackend>(obj: &DynamicObject) -> B::SketchType {
178 match obj {
179 DynamicObject::Circle { radius, segments } => B::circle(*radius, *segments),
180 DynamicObject::Square { size } => B::square(*size),
181 DynamicObject::Polygon { points } => B::polygon(points),
182 DynamicObject::Sketch { data } => {
183 let profile =
184 rscad_core::sketch::profile_loops(data, rscad_core::sketch::DEFAULT_ARC_SEGMENTS);
185 B::sketch(&profile.loops)
186 }
187 DynamicObject::Offset {
188 delta,
189 round,
190 chamfer,
191 segments,
192 child,
193 } => B::offset(
194 dynamic_to_sketch::<B>(child),
195 *delta,
196 *round,
197 *chamfer,
198 *segments,
199 ),
200 DynamicObject::Cube { .. }
201 | DynamicObject::Sphere { .. }
202 | DynamicObject::Cylinder { .. }
203 | DynamicObject::Cone { .. }
204 | DynamicObject::LinearExtrude { .. }
205 | DynamicObject::Revolve { .. }
206 | DynamicObject::EdgeFeature { .. } => {
207 if B::SKETCH_IS_CSG {
208 B::csg_as_sketch(dynamic_to_csg::<B>(obj))
209 } else {
210 B::empty_sketch()
211 }
212 }
213 DynamicObject::Union { children } | DynamicObject::Group { children } => {
214 B::union_all_2d(children.iter().map(dynamic_to_sketch::<B>).collect())
215 }
216 DynamicObject::Difference { children } => match children.as_slice() {
217 [] => B::empty_sketch(),
218 [first, rest @ ..] => rest.iter().fold(dynamic_to_sketch::<B>(first), |acc, c| {
219 B::difference_2d(acc, dynamic_to_sketch::<B>(c))
220 }),
221 },
222 DynamicObject::Intersection { children } => match children.as_slice() {
223 [] => B::empty_sketch(),
224 [first, rest @ ..] => rest.iter().fold(dynamic_to_sketch::<B>(first), |acc, c| {
225 B::intersection_2d(acc, dynamic_to_sketch::<B>(c))
226 }),
227 },
228 DynamicObject::Translate { offset, child } => {
229 B::translate_2d(dynamic_to_sketch::<B>(child), DVec3::from_array(*offset))
230 }
231 DynamicObject::Rotate { angles, child } => {
232 B::rotate_2d(dynamic_to_sketch::<B>(child), DVec3::from_array(*angles))
233 }
234 DynamicObject::Scale { factors, child } => {
235 B::scale_2d(dynamic_to_sketch::<B>(child), DVec3::from_array(*factors))
236 }
237 DynamicObject::Mirror { axis, child } => {
238 B::mirror_2d(dynamic_to_sketch::<B>(child), DVec3::from_array(*axis))
239 }
240 DynamicObject::Color { color, child } => {
241 B::color_2d(dynamic_to_sketch::<B>(child), color.map(|c| c as f32))
242 }
243 DynamicObject::Material { child, .. } => dynamic_to_sketch::<B>(child),
244 DynamicObject::Empty => B::empty_sketch(),
245 }
246}