1use anyhow::Result;
4use kittycad_modeling_cmds::shared::Angle;
5
6use super::utils::untype_point;
7use crate::{
8 errors::{KclError, KclErrorDetails},
9 execution::{
10 ExecState, KclValue, Sketch, TagIdentifier,
11 types::{NumericType, PrimitiveType, RuntimeType},
12 },
13 std::{Args, args::TyF64, utils::between},
14};
15
16pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
18 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tagged_edge(), exec_state)?;
19 let pt = inner_segment_end(&tag, exec_state, args.clone())?;
20
21 args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty)
22}
23
24fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
25 let line = args.get_tag_engine_info(exec_state, tag)?;
26 let path = line.path.clone().ok_or_else(|| {
27 KclError::new_type(KclErrorDetails::new(
28 format!("Expected a line segment with a path, found `{line:?}`"),
29 vec![args.source_range],
30 ))
31 })?;
32 let (p, ty) = path.end_point_components();
33 let point = [TyF64::new(p[0], ty), TyF64::new(p[1], ty)];
35
36 Ok(point)
37}
38
39pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
41 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tagged_edge(), exec_state)?;
42 let result = inner_segment_end_x(&tag, exec_state, args.clone())?;
43
44 Ok(args.make_user_val_from_f64_with_type(result))
45}
46
47fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
48 let line = args.get_tag_engine_info(exec_state, tag)?;
49 let path = line.path.clone().ok_or_else(|| {
50 KclError::new_type(KclErrorDetails::new(
51 format!("Expected a line segment with a path, found `{line:?}`"),
52 vec![args.source_range],
53 ))
54 })?;
55
56 Ok(TyF64::new(path.get_base().to[0], path.get_base().units.into()))
57}
58
59pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
61 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tagged_edge(), exec_state)?;
62 let result = inner_segment_end_y(&tag, exec_state, args.clone())?;
63
64 Ok(args.make_user_val_from_f64_with_type(result))
65}
66
67fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
68 let line = args.get_tag_engine_info(exec_state, tag)?;
69 let path = line.path.clone().ok_or_else(|| {
70 KclError::new_type(KclErrorDetails::new(
71 format!("Expected a line segment with a path, found `{line:?}`"),
72 vec![args.source_range],
73 ))
74 })?;
75
76 Ok(path.get_to()[1].clone())
77}
78
79pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
81 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tagged_edge(), exec_state)?;
82 let pt = inner_segment_start(&tag, exec_state, args.clone())?;
83
84 args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty)
85}
86
87fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
88 let line = args.get_tag_engine_info(exec_state, tag)?;
89 let path = line.path.clone().ok_or_else(|| {
90 KclError::new_type(KclErrorDetails::new(
91 format!("Expected a line segment with a path, found `{line:?}`"),
92 vec![args.source_range],
93 ))
94 })?;
95 let (p, ty) = path.start_point_components();
96 let point = [TyF64::new(p[0], ty), TyF64::new(p[1], ty)];
98
99 Ok(point)
100}
101
102pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
104 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tagged_edge(), exec_state)?;
105 let result = inner_segment_start_x(&tag, exec_state, args.clone())?;
106
107 Ok(args.make_user_val_from_f64_with_type(result))
108}
109
110fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
111 let line = args.get_tag_engine_info(exec_state, tag)?;
112 let path = line.path.clone().ok_or_else(|| {
113 KclError::new_type(KclErrorDetails::new(
114 format!("Expected a line segment with a path, found `{line:?}`"),
115 vec![args.source_range],
116 ))
117 })?;
118
119 Ok(path.get_from()[0].clone())
120}
121
122pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
124 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tagged_edge(), exec_state)?;
125 let result = inner_segment_start_y(&tag, exec_state, args.clone())?;
126
127 Ok(args.make_user_val_from_f64_with_type(result))
128}
129
130fn inner_segment_start_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
131 let line = args.get_tag_engine_info(exec_state, tag)?;
132 let path = line.path.clone().ok_or_else(|| {
133 KclError::new_type(KclErrorDetails::new(
134 format!("Expected a line segment with a path, found `{line:?}`"),
135 vec![args.source_range],
136 ))
137 })?;
138
139 Ok(path.get_from()[1].clone())
140}
141pub async fn last_segment_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
143 let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
144 let result = inner_last_segment_x(sketch, args.clone())?;
145
146 Ok(args.make_user_val_from_f64_with_type(result))
147}
148
149fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
150 let last_line = sketch
151 .paths
152 .last()
153 .ok_or_else(|| {
154 KclError::new_type(KclErrorDetails::new(
155 format!("Expected a Sketch with at least one segment, found `{sketch:?}`"),
156 vec![args.source_range],
157 ))
158 })?
159 .get_base();
160
161 Ok(TyF64::new(last_line.to[0], last_line.units.into()))
162}
163
164pub async fn last_segment_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
166 let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
167 let result = inner_last_segment_y(sketch, args.clone())?;
168
169 Ok(args.make_user_val_from_f64_with_type(result))
170}
171
172fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
173 let last_line = sketch
174 .paths
175 .last()
176 .ok_or_else(|| {
177 KclError::new_type(KclErrorDetails::new(
178 format!("Expected a Sketch with at least one segment, found `{sketch:?}`"),
179 vec![args.source_range],
180 ))
181 })?
182 .get_base();
183
184 Ok(TyF64::new(last_line.to[1], last_line.units.into()))
185}
186
187pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
189 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tagged_edge(), exec_state)?;
190 let result = inner_segment_length(&tag, exec_state, args.clone())?;
191 Ok(args.make_user_val_from_f64_with_type(result))
192}
193
194fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
195 let line = args.get_tag_engine_info(exec_state, tag)?;
196 let path = line.path.clone().ok_or_else(|| {
197 KclError::new_type(KclErrorDetails::new(
198 format!("Expected a line segment with a path, found `{line:?}`"),
199 vec![args.source_range],
200 ))
201 })?;
202
203 Ok(path.length())
204}
205
206pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
208 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tagged_edge(), exec_state)?;
209
210 let result = inner_segment_angle(&tag, exec_state, args.clone())?;
211 Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
212}
213
214fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
215 let line = args.get_tag_engine_info(exec_state, tag)?;
216 let path = line.path.clone().ok_or_else(|| {
217 KclError::new_type(KclErrorDetails::new(
218 format!("Expected a line segment with a path, found `{line:?}`"),
219 vec![args.source_range],
220 ))
221 })?;
222
223 let result = between(path.get_base().from, path.get_base().to);
224
225 Ok(result.to_degrees())
226}
227
228pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
230 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tagged_edge(), exec_state)?;
231
232 let result = inner_tangent_to_end(&tag, exec_state, args.clone()).await?;
233 Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
234}
235
236async fn inner_tangent_to_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
237 let line = args.get_tag_engine_info(exec_state, tag)?;
238 let path = line.path.clone().ok_or_else(|| {
239 KclError::new_type(KclErrorDetails::new(
240 format!("Expected a line segment with a path, found `{line:?}`"),
241 vec![args.source_range],
242 ))
243 })?;
244
245 let from = untype_point(path.get_to()).0;
246
247 let tangent_info = path.get_tangential_info();
249 let tan_previous_point = tangent_info.tan_previous_point(from);
250
251 let previous_end_tangent = Angle::from_radians(libm::atan2(
254 from[1] - tan_previous_point[1],
255 from[0] - tan_previous_point[0],
256 ));
257
258 Ok(previous_end_tangent.to_degrees())
259}