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