1use axiolid_core::{BooleanOperator, Point3, Scalar, Transform3, Vec3};
4
5use crate::NodeId;
6
7#[derive(Debug, Clone, Copy, PartialEq)]
9pub struct Section {
10 pub profile: NodeId,
12 pub placement: Transform3,
14}
15
16#[non_exhaustive]
18#[derive(Debug, Clone, PartialEq)]
19pub enum SolidOperation {
20 Extrusion {
22 profile: NodeId,
23 direction: Vec3,
24 depth: Scalar,
25 },
26 TaperedExtrusion {
28 start_profile: NodeId,
29 end_profile: NodeId,
30 direction: Vec3,
31 depth: Scalar,
32 },
33 Revolution {
35 profile: NodeId,
36 axis_origin: Point3,
37 axis_direction: Vec3,
38 angle: Scalar,
39 },
40 TaperedRevolution {
42 start_profile: NodeId,
43 end_profile: NodeId,
44 axis_origin: Point3,
45 axis_direction: Vec3,
46 angle: Scalar,
47 },
48 SweptDisk {
61 directrix: NodeId,
62 radius: Scalar,
63 inner_radius: Option<Scalar>,
64 parameter_range: Option<(Scalar, Scalar)>,
65 fillet_radius: Option<Scalar>,
67 },
68 FixedReferenceSweep {
70 profile: NodeId,
71 directrix: NodeId,
72 reference_direction: Vec3,
73 parameter_range: Option<(Scalar, Scalar)>,
74 },
75 SurfaceCurveSweep {
77 profile: NodeId,
78 directrix: NodeId,
79 reference_surface: NodeId,
80 parameter_range: Option<(Scalar, Scalar)>,
81 },
82 SectionedSpine {
84 spine: NodeId,
85 sections: Vec<Section>,
86 },
87 Boolean {
89 left: NodeId,
90 right: NodeId,
91 operator: BooleanOperator,
92 },
93 BoundedHalfSpace {
95 half_space: NodeId,
96 boundary: NodeId,
99 placement: Transform3,
109 },
110}
111
112impl SolidOperation {
113 pub(crate) fn references(&self, out: &mut Vec<NodeId>) {
114 match self {
115 Self::Extrusion { profile, .. } | Self::Revolution { profile, .. } => {
116 out.push(*profile)
117 }
118 Self::TaperedExtrusion {
119 start_profile,
120 end_profile,
121 ..
122 }
123 | Self::TaperedRevolution {
124 start_profile,
125 end_profile,
126 ..
127 } => out.extend([*start_profile, *end_profile]),
128 Self::SweptDisk { directrix, .. } => out.push(*directrix),
129 Self::FixedReferenceSweep {
130 profile, directrix, ..
131 } => out.extend([*profile, *directrix]),
132 Self::SurfaceCurveSweep {
133 profile,
134 directrix,
135 reference_surface,
136 ..
137 } => out.extend([*profile, *directrix, *reference_surface]),
138 Self::SectionedSpine { spine, sections } => {
139 out.push(*spine);
140 out.extend(sections.iter().map(|section| section.profile));
141 }
142 Self::Boolean { left, right, .. } => out.extend([*left, *right]),
143 Self::BoundedHalfSpace {
144 half_space,
145 boundary,
146 ..
147 } => out.extend([*half_space, *boundary]),
148 }
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155 use crate::graph::GeometryGraphBuilder;
156 use crate::node::GeometryNode;
157 use axiolid_core::Vec3;
158
159 fn directrix(builder: &mut GeometryGraphBuilder) -> NodeId {
160 builder.push(GeometryNode::Point3(Vec3::ZERO)).unwrap()
161 }
162
163 #[test]
169 fn a_fillet_radius_is_not_a_node_reference() {
170 let mut builder = GeometryGraphBuilder::default();
171 let curve = directrix(&mut builder);
172
173 let sharp = SolidOperation::SweptDisk {
174 directrix: curve,
175 radius: 0.05,
176 inner_radius: None,
177 parameter_range: None,
178 fillet_radius: None,
179 };
180 let rounded = SolidOperation::SweptDisk {
181 directrix: curve,
182 radius: 0.05,
183 inner_radius: None,
184 parameter_range: None,
185 fillet_radius: Some(0.09),
186 };
187
188 let mut sharp_refs = Vec::new();
189 sharp.references(&mut sharp_refs);
190 let mut rounded_refs = Vec::new();
191 rounded.references(&mut rounded_refs);
192
193 assert_eq!(sharp_refs, vec![curve]);
194 assert_eq!(
195 sharp_refs, rounded_refs,
196 "a fillet changes geometry, not the reference graph"
197 );
198 }
199
200 #[test]
206 fn a_fillet_radius_distinguishes_two_otherwise_identical_sweeps() {
207 let mut builder = GeometryGraphBuilder::default();
208 let curve = directrix(&mut builder);
209
210 let common = |fillet| SolidOperation::SweptDisk {
211 directrix: curve,
212 radius: 0.05,
213 inner_radius: Some(0.04),
214 parameter_range: Some((0.0, 2.0)),
215 fillet_radius: fillet,
216 };
217 assert_ne!(common(None), common(Some(0.09)));
218 assert_eq!(common(Some(0.09)), common(Some(0.09)));
219 }
220}