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