Skip to main content

kcl_lib/std/
axis_or_reference.rs

1//! Types for referencing an axis or edge.
2
3use kittycad_modeling_cmds::shared::EdgeSpecifier as ModelingEdgeSpecifier;
4
5use super::args::TyF64;
6use crate::KclError;
7use crate::errors::KclErrorDetails;
8use crate::execution::Plane;
9use crate::execution::Segment;
10use crate::execution::SegmentKind;
11use crate::execution::Sketch;
12use crate::execution::Solid;
13use crate::execution::TagIdentifier;
14use crate::std::fillet::EdgeReference;
15use crate::std::sketch::FaceTag;
16
17/// A 2D axis or tagged edge.
18#[derive(Debug, Clone, PartialEq)]
19pub enum Axis2dOrEdgeReference {
20    /// 2D axis and origin.
21    Axis { direction: [TyF64; 2], origin: [TyF64; 2] },
22    /// Tagged edge
23    Edge(EdgeReference),
24    /// Edge specifier with side faces, end faces, and index.
25    EdgeSpecifier(ModelingEdgeSpecifier),
26}
27
28/// A 3D mirror target.
29#[derive(Debug, Clone, PartialEq)]
30pub enum MirrorAcross3d {
31    /// 3D axis and origin.
32    Axis {
33        direction: Box<[TyF64; 3]>,
34        origin: Box<[TyF64; 3]>,
35    },
36    /// Tagged edge.
37    Edge(Box<EdgeReference>),
38    /// A plane.
39    Plane(Box<Plane>),
40}
41
42impl Axis2dOrEdgeReference {
43    /// Use a sketch-solve segment by finding its engine ID.
44    pub fn from_segment(segment: &Segment) -> Result<Self, KclError> {
45        match &segment.kind {
46            SegmentKind::Line { .. } => Ok(Self::Edge(EdgeReference::Uuid(segment.id))),
47            SegmentKind::Point { .. } => Err(KclError::new_type(KclErrorDetails {
48                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
49                backtrace: Default::default(),
50                message: "Cannot use a point as an axis".to_owned(),
51            })),
52            SegmentKind::Arc { .. } => Err(KclError::new_type(KclErrorDetails {
53                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
54                backtrace: Default::default(),
55                message: "Cannot use an arc as an axis".to_owned(),
56            })),
57            SegmentKind::Circle { .. } => Err(KclError::new_type(KclErrorDetails {
58                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
59                backtrace: Default::default(),
60                message: "Cannot use a circle as an axis".to_owned(),
61            })),
62            SegmentKind::ControlPointSpline { .. } => Err(KclError::new_type(KclErrorDetails {
63                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
64                backtrace: Default::default(),
65                message: "Cannot use a control point spline as an axis".to_owned(),
66            })),
67        }
68    }
69}
70
71impl MirrorAcross3d {
72    /// Use a sketch-solve segment by finding its engine ID.
73    pub fn from_segment(segment: &Segment) -> Result<Self, KclError> {
74        match &segment.kind {
75            SegmentKind::Line { .. } => Ok(Self::Edge(Box::new(EdgeReference::Uuid(segment.id)))),
76            SegmentKind::Point { .. } => Err(KclError::new_type(KclErrorDetails {
77                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
78                backtrace: Default::default(),
79                message: "Cannot use a point as an axis".to_owned(),
80            })),
81            SegmentKind::Arc { .. } => Err(KclError::new_type(KclErrorDetails {
82                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
83                backtrace: Default::default(),
84                message: "Cannot use an arc as an axis".to_owned(),
85            })),
86            SegmentKind::Circle { .. } => Err(KclError::new_type(KclErrorDetails {
87                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
88                backtrace: Default::default(),
89                message: "Cannot use a circle as an axis".to_owned(),
90            })),
91            SegmentKind::ControlPointSpline { .. } => Err(KclError::new_type(KclErrorDetails {
92                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
93                backtrace: Default::default(),
94                message: "Cannot use a control point spline as an axis".to_owned(),
95            })),
96        }
97    }
98}
99
100/// A 3D axis or tagged edge.
101#[allow(clippy::large_enum_variant)]
102#[derive(Debug, Clone, PartialEq)]
103pub enum Axis3dOrEdgeReference {
104    /// 3D axis and origin.
105    Axis { direction: [TyF64; 3], origin: [TyF64; 3] },
106    /// Tagged edge
107    Edge(EdgeReference),
108    /// Edge specifier with side faces, end faces, and index.
109    EdgeSpecifier(ModelingEdgeSpecifier),
110}
111
112impl Axis3dOrEdgeReference {
113    /// Use a sketch-solve segment by finding its engine ID.
114    pub fn from_segment(segment: &Segment) -> Result<Self, KclError> {
115        match &segment.kind {
116            SegmentKind::Line { .. } => Ok(Self::Edge(EdgeReference::Uuid(segment.id))),
117            SegmentKind::Point { .. } => Err(KclError::new_type(KclErrorDetails {
118                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
119                backtrace: Default::default(),
120                message: "Cannot use a point as an axis".to_owned(),
121            })),
122            SegmentKind::Arc { .. } => Err(KclError::new_type(KclErrorDetails {
123                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
124                backtrace: Default::default(),
125                message: "Cannot use an arc as an axis".to_owned(),
126            })),
127            SegmentKind::Circle { .. } => Err(KclError::new_type(KclErrorDetails {
128                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
129                backtrace: Default::default(),
130                message: "Cannot use a circle as an axis".to_owned(),
131            })),
132            SegmentKind::ControlPointSpline { .. } => Err(KclError::new_type(KclErrorDetails {
133                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
134                backtrace: Default::default(),
135                message: "Cannot use a control point spline as an axis".to_owned(),
136            })),
137        }
138    }
139}
140
141/// A 3D point or tagged edge.
142#[allow(clippy::large_enum_variant)]
143#[derive(Debug, Clone, PartialEq)]
144pub enum Point3dOrEdgeReference {
145    /// 3D point and origin.
146    Point([TyF64; 3]),
147    /// Tagged edge.
148    Edge(EdgeReference),
149}
150
151impl Point3dOrEdgeReference {
152    /// Use a sketch-solve segment by finding its engine ID.
153    pub fn from_segment(segment: &Segment) -> Result<Self, KclError> {
154        match &segment.kind {
155            SegmentKind::Line { .. } => Ok(Self::Edge(EdgeReference::Uuid(segment.id))),
156            SegmentKind::Point { position, .. } => Ok(Self::Point([
157                position[0].clone(),
158                position[1].clone(),
159                TyF64::count(0.0),
160            ])),
161            SegmentKind::Arc { .. } => Err(KclError::new_type(KclErrorDetails {
162                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
163                backtrace: Default::default(),
164                message: "Cannot use an arc as a 3D point or edge reference".to_owned(),
165            })),
166            SegmentKind::Circle { .. } => Err(KclError::new_type(KclErrorDetails {
167                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
168                backtrace: Default::default(),
169                message: "Cannot use a circle as a 3D point or edge reference".to_owned(),
170            })),
171            SegmentKind::ControlPointSpline { .. } => Err(KclError::new_type(KclErrorDetails {
172                source_ranges: segment.meta.iter().map(|meta| meta.source_range).collect(),
173                backtrace: Default::default(),
174                message: "Cannot use a control point spline as a 3D point or edge reference".to_owned(),
175            })),
176        }
177    }
178}
179
180/// A 2D axis or a raw point2d.
181#[derive(Debug, Clone, PartialEq)]
182pub enum Axis2dOrPoint2d {
183    /// 2D axis and origin.
184    Axis { direction: [TyF64; 2], origin: [TyF64; 2] },
185    /// Raw point2d.
186    Point([TyF64; 2]),
187}
188
189impl Axis2dOrPoint2d {
190    /// Convert to a 2D axis.
191    pub fn to_point2d(&self) -> [TyF64; 2] {
192        match self {
193            Axis2dOrPoint2d::Axis { direction, origin: _ } => direction.clone(),
194            Axis2dOrPoint2d::Point(point) => point.clone(),
195        }
196    }
197}
198
199/// A 3D axis or a raw point3d.
200#[derive(Debug, Clone, PartialEq)]
201pub enum Axis3dOrPoint3d {
202    /// 3D axis and origin.
203    Axis { direction: [TyF64; 3], origin: [TyF64; 3] },
204    /// Raw point3d.
205    Point([TyF64; 3]),
206}
207
208impl Axis3dOrPoint3d {
209    /// Convert to a 3D axis.
210    pub fn to_point3d(&self) -> [TyF64; 3] {
211        match self {
212            Axis3dOrPoint3d::Axis { direction, origin: _ } => direction.clone(),
213            Axis3dOrPoint3d::Point(point) => point.clone(),
214        }
215    }
216
217    pub fn axis_origin(&self) -> Option<[TyF64; 3]> {
218        match self {
219            Axis3dOrPoint3d::Axis { origin, .. } => Some(origin.clone()),
220            Axis3dOrPoint3d::Point(..) => None,
221        }
222    }
223}
224
225/// A raw point3d, 3D axis, Edge, Face, Solid or Tag.
226#[allow(clippy::large_enum_variant)]
227#[derive(Debug, Clone, PartialEq)]
228pub enum Point3dAxis3dOrGeometryReference {
229    /// Raw point3d.
230    Point([TyF64; 3]),
231    /// 3D axis and origin.
232    Axis { direction: [TyF64; 3], origin: [TyF64; 3] },
233    /// Plane.
234    Plane(Box<Plane>),
235    /// Edge Reference.
236    Edge(EdgeReference),
237    /// Face.
238    Face(FaceTag),
239    /// Sketch.
240    Sketch(Box<Sketch>),
241    /// Solid.
242    Solid(Box<Solid>),
243    /// Tagged edge or face.
244    TaggedEdgeOrFace(TagIdentifier),
245    /// Extrude-to edge: `{ sideFaces = [...], endFaces = [...], index? }` (face tags or UUIDs).
246    EdgeToReference(super::edge::UnresolvedEdgeSpecifier),
247}