kcl_lib/std/
axis_or_reference.rs

1//! Types for referencing an axis or edge.
2
3use anyhow::Result;
4use kcmc::length_unit::LengthUnit;
5use kittycad_modeling_cmds::{self as kcmc};
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8
9use crate::{errors::KclError, std::fillet::EdgeReference};
10
11/// A 2D axis or tagged edge.
12#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
13#[ts(export)]
14#[serde(untagged)]
15pub enum Axis2dOrEdgeReference {
16    /// 2D axis and origin.
17    Axis(AxisAndOrigin2d),
18    /// Tagged edge.
19    Edge(EdgeReference),
20}
21
22/// A 2D axis and origin.
23#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
24#[ts(export)]
25#[serde(rename_all = "camelCase")]
26pub enum AxisAndOrigin2d {
27    /// X-axis.
28    #[serde(rename = "X", alias = "x")]
29    X,
30    /// Y-axis.
31    #[serde(rename = "Y", alias = "y")]
32    Y,
33    /// Flip the X-axis.
34    #[serde(rename = "-X", alias = "-x")]
35    NegX,
36    /// Flip the Y-axis.
37    #[serde(rename = "-Y", alias = "-y")]
38    NegY,
39    Custom {
40        /// The axis.
41        axis: [f64; 2],
42        /// The origin.
43        origin: [f64; 2],
44    },
45}
46
47impl AxisAndOrigin2d {
48    /// Get the axis and origin.
49    pub fn axis_and_origin(&self) -> Result<(kcmc::shared::Point3d<f64>, kcmc::shared::Point3d<LengthUnit>), KclError> {
50        let (axis, origin) = match self {
51            AxisAndOrigin2d::X => ([1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
52            AxisAndOrigin2d::Y => ([0.0, 1.0, 0.0], [0.0, 0.0, 0.0]),
53            AxisAndOrigin2d::NegX => ([-1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
54            AxisAndOrigin2d::NegY => ([0.0, -1.0, 0.0], [0.0, 0.0, 0.0]),
55            AxisAndOrigin2d::Custom { axis, origin } => ([axis[0], axis[1], 0.0], [origin[0], origin[1], 0.0]),
56        };
57
58        Ok((
59            kcmc::shared::Point3d {
60                x: axis[0],
61                y: axis[1],
62                z: axis[2],
63            },
64            kcmc::shared::Point3d {
65                x: LengthUnit(origin[0]),
66                y: LengthUnit(origin[1]),
67                z: LengthUnit(origin[2]),
68            },
69        ))
70    }
71}
72
73/// A 3D axis or tagged edge.
74#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
75#[ts(export)]
76#[serde(untagged)]
77pub enum Axis3dOrEdgeReference {
78    /// 3D axis and origin.
79    Axis(AxisAndOrigin3d),
80    /// Tagged edge.
81    Edge(EdgeReference),
82}
83
84/// A 3D axis and origin.
85#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
86#[ts(export)]
87#[serde(rename_all = "camelCase")]
88pub enum AxisAndOrigin3d {
89    /// X-axis.
90    #[serde(rename = "X", alias = "x")]
91    X,
92    /// Y-axis.
93    #[serde(rename = "Y", alias = "y")]
94    Y,
95    /// Z-axis.
96    #[serde(rename = "Z", alias = "z")]
97    Z,
98    /// Flip the X-axis.
99    #[serde(rename = "-X", alias = "-x")]
100    NegX,
101    /// Flip the Y-axis.
102    #[serde(rename = "-Y", alias = "-y")]
103    NegY,
104    /// Flip the Z-axis.
105    #[serde(rename = "-Z", alias = "-z")]
106    NegZ,
107    Custom {
108        /// The axis.
109        axis: [f64; 3],
110        /// The origin.
111        origin: [f64; 3],
112    },
113}
114
115impl AxisAndOrigin3d {
116    /// Get the axis and origin.
117    pub fn axis_and_origin(&self) -> Result<(kcmc::shared::Point3d<f64>, kcmc::shared::Point3d<LengthUnit>), KclError> {
118        let (axis, origin) = match self {
119            AxisAndOrigin3d::X => ([1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
120            AxisAndOrigin3d::Y => ([0.0, 1.0, 0.0], [0.0, 0.0, 0.0]),
121            AxisAndOrigin3d::Z => ([0.0, 0.0, 1.0], [0.0, 0.0, 0.0]),
122            AxisAndOrigin3d::NegX => ([-1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
123            AxisAndOrigin3d::NegY => ([0.0, -1.0, 0.0], [0.0, 0.0, 0.0]),
124            AxisAndOrigin3d::NegZ => ([0.0, 0.0, -1.0], [0.0, 0.0, 0.0]),
125            AxisAndOrigin3d::Custom { axis, origin } => {
126                ([axis[0], axis[1], axis[2]], [origin[0], origin[1], origin[2]])
127            }
128        };
129
130        Ok((
131            kcmc::shared::Point3d {
132                x: axis[0],
133                y: axis[1],
134                z: axis[2],
135            },
136            kcmc::shared::Point3d {
137                x: LengthUnit(origin[0]),
138                y: LengthUnit(origin[1]),
139                z: LengthUnit(origin[2]),
140            },
141        ))
142    }
143}
144
145#[cfg(test)]
146mod tests {
147
148    use pretty_assertions::assert_eq;
149
150    use crate::std::axis_or_reference::{
151        Axis2dOrEdgeReference, Axis3dOrEdgeReference, AxisAndOrigin2d, AxisAndOrigin3d,
152    };
153
154    #[test]
155    fn test_deserialize_revolve_axis_2d() {
156        let data = Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::X);
157        let mut str_json = serde_json::to_string(&data).unwrap();
158        assert_eq!(str_json, "\"X\"");
159
160        str_json = "\"Y\"".to_string();
161        let data: Axis2dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
162        assert_eq!(data, Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::Y));
163
164        str_json = "\"-Y\"".to_string();
165        let data: Axis2dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
166        assert_eq!(data, Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::NegY));
167
168        str_json = "\"-x\"".to_string();
169        let data: Axis2dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
170        assert_eq!(data, Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::NegX));
171
172        let data = Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::Custom {
173            axis: [0.0, -1.0],
174            origin: [1.0, 0.0],
175        });
176        str_json = serde_json::to_string(&data).unwrap();
177        assert_eq!(str_json, r#"{"custom":{"axis":[0.0,-1.0],"origin":[1.0,0.0]}}"#);
178
179        str_json = r#"{"custom": {"axis": [0,-1], "origin": [1,2.0]}}"#.to_string();
180        let data: Axis2dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
181        assert_eq!(
182            data,
183            Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::Custom {
184                axis: [0.0, -1.0],
185                origin: [1.0, 2.0]
186            })
187        );
188    }
189
190    #[test]
191    fn test_deserialize_revolve_axis_3d() {
192        let data = Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::X);
193        let mut str_json = serde_json::to_string(&data).unwrap();
194        assert_eq!(str_json, "\"X\"");
195
196        str_json = "\"Y\"".to_string();
197        let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
198        assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::Y));
199
200        str_json = "\"Z\"".to_string();
201        let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
202        assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::Z));
203
204        str_json = "\"-Y\"".to_string();
205        let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
206        assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::NegY));
207
208        str_json = "\"-x\"".to_string();
209        let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
210        assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::NegX));
211
212        str_json = "\"-z\"".to_string();
213        let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
214        assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::NegZ));
215
216        let data = Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::Custom {
217            axis: [0.0, -1.0, 0.0],
218            origin: [1.0, 0.0, 0.0],
219        });
220        str_json = serde_json::to_string(&data).unwrap();
221        assert_eq!(str_json, r#"{"custom":{"axis":[0.0,-1.0,0.0],"origin":[1.0,0.0,0.0]}}"#);
222
223        str_json = r#"{"custom": {"axis": [0,-1,0], "origin": [1,2.0,0]}}"#.to_string();
224        let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
225        assert_eq!(
226            data,
227            Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::Custom {
228                axis: [0.0, -1.0, 0.0],
229                origin: [1.0, 2.0, 0.0]
230            })
231        );
232    }
233}