1use anyhow::Result;
4use kcl_derive_docs::stdlib;
5use kittycad_modeling_cmds::shared::Angle;
6
7use super::utils::untype_point;
8use crate::{
9 errors::{KclError, KclErrorDetails},
10 execution::{
11 types::{NumericType, PrimitiveType, RuntimeType},
12 ExecState, KclValue, Sketch, TagIdentifier,
13 },
14 std::{args::TyF64, utils::between, Args},
15};
16
17pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
19 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
20 let result = inner_segment_end(&tag, exec_state, args.clone())?;
21
22 args.make_user_val_from_point(result)
23}
24
25#[stdlib {
51 name = "segEnd",
52 keywords = true,
53 unlabeled_first = true,
54 args = {
55 tag = { docs = "The line segment being queried by its tag"},
56 },
57 tags = ["sketch"]
58}]
59fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
60 let line = args.get_tag_engine_info(exec_state, tag)?;
61 let path = line.path.clone().ok_or_else(|| {
62 KclError::Type(KclErrorDetails {
63 message: format!("Expected a line segment with a path, found `{:?}`", line),
64 source_ranges: vec![args.source_range],
65 })
66 })?;
67
68 Ok(path.get_to().clone())
69}
70
71pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
73 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
74 let result = inner_segment_end_x(&tag, exec_state, args.clone())?;
75
76 Ok(args.make_user_val_from_f64_with_type(result))
77}
78
79#[stdlib {
93 name = "segEndX",
94 keywords = true,
95 unlabeled_first = true,
96 args = {
97 tag = { docs = "The line segment being queried by its tag"},
98 },
99 tags = ["sketch"]
100}]
101fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
102 let line = args.get_tag_engine_info(exec_state, tag)?;
103 let path = line.path.clone().ok_or_else(|| {
104 KclError::Type(KclErrorDetails {
105 message: format!("Expected a line segment with a path, found `{:?}`", line),
106 source_ranges: vec![args.source_range],
107 })
108 })?;
109
110 Ok(TyF64::new(path.get_base().to[0], path.get_base().units.into()))
111}
112
113pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
115 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
116 let result = inner_segment_end_y(&tag, exec_state, args.clone())?;
117
118 Ok(args.make_user_val_from_f64_with_type(result))
119}
120
121#[stdlib {
136 name = "segEndY",
137 keywords = true,
138 unlabeled_first = true,
139 args = {
140 tag = { docs = "The line segment being queried by its tag"},
141 },
142 tags = ["sketch"]
143}]
144fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
145 let line = args.get_tag_engine_info(exec_state, tag)?;
146 let path = line.path.clone().ok_or_else(|| {
147 KclError::Type(KclErrorDetails {
148 message: format!("Expected a line segment with a path, found `{:?}`", line),
149 source_ranges: vec![args.source_range],
150 })
151 })?;
152
153 Ok(path.get_to()[1].clone())
154}
155
156pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
158 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
159 let result = inner_segment_start(&tag, exec_state, args.clone())?;
160
161 args.make_user_val_from_point(result)
162}
163
164#[stdlib {
190 name = "segStart",
191 keywords = true,
192 unlabeled_first = true,
193 args = {
194 tag = { docs = "The line segment being queried by its tag"},
195 },
196 tags = ["sketch"]
197}]
198fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
199 let line = args.get_tag_engine_info(exec_state, tag)?;
200 let path = line.path.clone().ok_or_else(|| {
201 KclError::Type(KclErrorDetails {
202 message: format!("Expected a line segment with a path, found `{:?}`", line),
203 source_ranges: vec![args.source_range],
204 })
205 })?;
206
207 Ok(path.get_from().to_owned())
208}
209
210pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
212 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
213 let result = inner_segment_start_x(&tag, exec_state, args.clone())?;
214
215 Ok(args.make_user_val_from_f64_with_type(result))
216}
217
218#[stdlib {
232 name = "segStartX",
233 keywords = true,
234 unlabeled_first = true,
235 args = {
236 tag = { docs = "The line segment being queried by its tag"},
237 },
238 tags = ["sketch"]
239}]
240fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
241 let line = args.get_tag_engine_info(exec_state, tag)?;
242 let path = line.path.clone().ok_or_else(|| {
243 KclError::Type(KclErrorDetails {
244 message: format!("Expected a line segment with a path, found `{:?}`", line),
245 source_ranges: vec![args.source_range],
246 })
247 })?;
248
249 Ok(path.get_from()[0].clone())
250}
251
252pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
254 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
255 let result = inner_segment_start_y(&tag, exec_state, args.clone())?;
256
257 Ok(args.make_user_val_from_f64_with_type(result))
258}
259
260#[stdlib {
275 name = "segStartY",
276 keywords = true,
277 unlabeled_first = true,
278 args = {
279 tag = { docs = "The line segment being queried by its tag"},
280 },
281 tags = ["sketch"]
282}]
283fn inner_segment_start_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
284 let line = args.get_tag_engine_info(exec_state, tag)?;
285 let path = line.path.clone().ok_or_else(|| {
286 KclError::Type(KclErrorDetails {
287 message: format!("Expected a line segment with a path, found `{:?}`", line),
288 source_ranges: vec![args.source_range],
289 })
290 })?;
291
292 Ok(path.get_from()[1].clone())
293}
294pub async fn last_segment_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
296 let sketch =
297 args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
298 let result = inner_last_segment_x(sketch, args.clone())?;
299
300 Ok(args.make_user_val_from_f64_with_type(result))
301}
302
303#[stdlib {
318 name = "lastSegX",
319 keywords = true,
320 unlabeled_first = true,
321 args = {
322 sketch = { docs = "The sketch whose line segment is being queried"},
323 },
324 tags = ["sketch"]
325}]
326fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
327 let last_line = sketch
328 .paths
329 .last()
330 .ok_or_else(|| {
331 KclError::Type(KclErrorDetails {
332 message: format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
333 source_ranges: vec![args.source_range],
334 })
335 })?
336 .get_base();
337
338 Ok(TyF64::new(last_line.to[0], last_line.units.into()))
339}
340
341pub async fn last_segment_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
343 let sketch =
344 args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
345 let result = inner_last_segment_y(sketch, args.clone())?;
346
347 Ok(args.make_user_val_from_f64_with_type(result))
348}
349
350#[stdlib {
365 name = "lastSegY",
366 keywords = true,
367 unlabeled_first = true,
368 args = {
369 sketch = { docs = "The sketch whose line segment is being queried"},
370 },
371 tags = ["sketch"]
372}]
373fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
374 let last_line = sketch
375 .paths
376 .last()
377 .ok_or_else(|| {
378 KclError::Type(KclErrorDetails {
379 message: format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
380 source_ranges: vec![args.source_range],
381 })
382 })?
383 .get_base();
384
385 Ok(TyF64::new(last_line.to[1], last_line.units.into()))
386}
387
388pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
390 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
391 let result = inner_segment_length(&tag, exec_state, args.clone())?;
392 Ok(args.make_user_val_from_f64_with_type(result))
393}
394
395#[stdlib {
415 name = "segLen",
416 keywords = true,
417 unlabeled_first = true,
418 args = {
419 tag = { docs = "The line segment being queried by its tag"},
420 },
421 tags = ["sketch"]
422}]
423fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
424 let line = args.get_tag_engine_info(exec_state, tag)?;
425 let path = line.path.clone().ok_or_else(|| {
426 KclError::Type(KclErrorDetails {
427 message: format!("Expected a line segment with a path, found `{:?}`", line),
428 source_ranges: vec![args.source_range],
429 })
430 })?;
431
432 Ok(path.length())
433}
434
435pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
437 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
438
439 let result = inner_segment_angle(&tag, exec_state, args.clone())?;
440 Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
441}
442
443#[stdlib {
459 name = "segAng",
460 keywords = true,
461 unlabeled_first = true,
462 args = {
463 tag = { docs = "The line segment being queried by its tag"},
464 },
465 tags = ["sketch"]
466}]
467fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
468 let line = args.get_tag_engine_info(exec_state, tag)?;
469 let path = line.path.clone().ok_or_else(|| {
470 KclError::Type(KclErrorDetails {
471 message: format!("Expected a line segment with a path, found `{:?}`", line),
472 source_ranges: vec![args.source_range],
473 })
474 })?;
475
476 let result = between(path.get_base().from, path.get_base().to);
477
478 Ok(result.to_degrees())
479}
480
481pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
483 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
484
485 let result = inner_tangent_to_end(&tag, exec_state, args.clone()).await?;
486 Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
487}
488
489#[stdlib {
561 name = "tangentToEnd",
562 keywords = true,
563 unlabeled_first = true,
564 args = {
565 tag = { docs = "The line segment being queried by its tag"},
566 },
567 tags = ["sketch"]
568}]
569async fn inner_tangent_to_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
570 let line = args.get_tag_engine_info(exec_state, tag)?;
571 let path = line.path.clone().ok_or_else(|| {
572 KclError::Type(KclErrorDetails {
573 message: format!("Expected a line segment with a path, found `{:?}`", line),
574 source_ranges: vec![args.source_range],
575 })
576 })?;
577
578 let from = untype_point(path.get_to()).0;
579
580 let tangent_info = path.get_tangential_info();
582 let tan_previous_point = tangent_info.tan_previous_point(from);
583
584 let previous_end_tangent = Angle::from_radians(f64::atan2(
587 from[1] - tan_previous_point[1],
588 from[0] - tan_previous_point[0],
589 ));
590
591 Ok(previous_end_tangent.to_degrees())
592}