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,
97 placement: Transform3,
107 },
108}
109
110impl SolidOperation {
111 pub(crate) fn references(&self, out: &mut Vec<NodeId>) {
112 match self {
113 Self::Extrusion { profile, .. } | Self::Revolution { profile, .. } => {
114 out.push(*profile)
115 }
116 Self::TaperedExtrusion {
117 start_profile,
118 end_profile,
119 ..
120 }
121 | Self::TaperedRevolution {
122 start_profile,
123 end_profile,
124 ..
125 } => out.extend([*start_profile, *end_profile]),
126 Self::SweptDisk { directrix, .. } => out.push(*directrix),
127 Self::FixedReferenceSweep {
128 profile, directrix, ..
129 } => out.extend([*profile, *directrix]),
130 Self::SurfaceCurveSweep {
131 profile,
132 directrix,
133 reference_surface,
134 ..
135 } => out.extend([*profile, *directrix, *reference_surface]),
136 Self::SectionedSpine { spine, sections } => {
137 out.push(*spine);
138 out.extend(sections.iter().map(|section| section.profile));
139 }
140 Self::Boolean { left, right, .. } => out.extend([*left, *right]),
141 Self::BoundedHalfSpace {
142 half_space,
143 boundary,
144 ..
145 } => out.extend([*half_space, *boundary]),
146 }
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153 use crate::graph::GeometryGraphBuilder;
154 use crate::node::GeometryNode;
155 use axiolid_core::Vec3;
156
157 fn directrix(builder: &mut GeometryGraphBuilder) -> NodeId {
158 builder.push(GeometryNode::Point3(Vec3::ZERO)).unwrap()
159 }
160
161 #[test]
167 fn a_fillet_radius_is_not_a_node_reference() {
168 let mut builder = GeometryGraphBuilder::default();
169 let curve = directrix(&mut builder);
170
171 let sharp = SolidOperation::SweptDisk {
172 directrix: curve,
173 radius: 0.05,
174 inner_radius: None,
175 parameter_range: None,
176 fillet_radius: None,
177 };
178 let rounded = SolidOperation::SweptDisk {
179 directrix: curve,
180 radius: 0.05,
181 inner_radius: None,
182 parameter_range: None,
183 fillet_radius: Some(0.09),
184 };
185
186 let mut sharp_refs = Vec::new();
187 sharp.references(&mut sharp_refs);
188 let mut rounded_refs = Vec::new();
189 rounded.references(&mut rounded_refs);
190
191 assert_eq!(sharp_refs, vec![curve]);
192 assert_eq!(
193 sharp_refs, rounded_refs,
194 "a fillet changes geometry, not the reference graph"
195 );
196 }
197
198 #[test]
204 fn a_fillet_radius_distinguishes_two_otherwise_identical_sweeps() {
205 let mut builder = GeometryGraphBuilder::default();
206 let curve = directrix(&mut builder);
207
208 let common = |fillet| SolidOperation::SweptDisk {
209 directrix: curve,
210 radius: 0.05,
211 inner_radius: Some(0.04),
212 parameter_range: Some((0.0, 2.0)),
213 fillet_radius: fillet,
214 };
215 assert_ne!(common(None), common(Some(0.09)));
216 assert_eq!(common(Some(0.09)), common(Some(0.09)));
217 }
218}