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 pt = inner_segment_end(&tag, exec_state, args.clone())?;
21
22 args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty.clone())
23}
24
25#[stdlib {
51 name = "segEnd",
52 unlabeled_first = true,
53 args = {
54 tag = { docs = "The line segment being queried by its tag"},
55 },
56 tags = ["sketch"]
57}]
58fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
59 let line = args.get_tag_engine_info(exec_state, tag)?;
60 let path = line.path.clone().ok_or_else(|| {
61 KclError::Type(KclErrorDetails::new(
62 format!("Expected a line segment with a path, found `{:?}`", line),
63 vec![args.source_range],
64 ))
65 })?;
66 let (p, ty) = path.end_point_components();
67 let point = [TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)];
69
70 Ok(point)
71}
72
73pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
75 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
76 let result = inner_segment_end_x(&tag, exec_state, args.clone())?;
77
78 Ok(args.make_user_val_from_f64_with_type(result))
79}
80
81#[stdlib {
95 name = "segEndX",
96 unlabeled_first = true,
97 args = {
98 tag = { docs = "The line segment being queried by its tag"},
99 },
100 tags = ["sketch"]
101}]
102fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
103 let line = args.get_tag_engine_info(exec_state, tag)?;
104 let path = line.path.clone().ok_or_else(|| {
105 KclError::Type(KclErrorDetails::new(
106 format!("Expected a line segment with a path, found `{:?}`", line),
107 vec![args.source_range],
108 ))
109 })?;
110
111 Ok(TyF64::new(path.get_base().to[0], path.get_base().units.into()))
112}
113
114pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
116 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
117 let result = inner_segment_end_y(&tag, exec_state, args.clone())?;
118
119 Ok(args.make_user_val_from_f64_with_type(result))
120}
121
122#[stdlib {
137 name = "segEndY",
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::new(
148 format!("Expected a line segment with a path, found `{:?}`", line),
149 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 pt = inner_segment_start(&tag, exec_state, args.clone())?;
160
161 args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty.clone())
162}
163
164#[stdlib {
190 name = "segStart",
191 unlabeled_first = true,
192 args = {
193 tag = { docs = "The line segment being queried by its tag"},
194 },
195 tags = ["sketch"]
196}]
197fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
198 let line = args.get_tag_engine_info(exec_state, tag)?;
199 let path = line.path.clone().ok_or_else(|| {
200 KclError::Type(KclErrorDetails::new(
201 format!("Expected a line segment with a path, found `{:?}`", line),
202 vec![args.source_range],
203 ))
204 })?;
205 let (p, ty) = path.start_point_components();
206 let point = [TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)];
208
209 Ok(point)
210}
211
212pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
214 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
215 let result = inner_segment_start_x(&tag, exec_state, args.clone())?;
216
217 Ok(args.make_user_val_from_f64_with_type(result))
218}
219
220#[stdlib {
234 name = "segStartX",
235 unlabeled_first = true,
236 args = {
237 tag = { docs = "The line segment being queried by its tag"},
238 },
239 tags = ["sketch"]
240}]
241fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
242 let line = args.get_tag_engine_info(exec_state, tag)?;
243 let path = line.path.clone().ok_or_else(|| {
244 KclError::Type(KclErrorDetails::new(
245 format!("Expected a line segment with a path, found `{:?}`", line),
246 vec![args.source_range],
247 ))
248 })?;
249
250 Ok(path.get_from()[0].clone())
251}
252
253pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
255 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
256 let result = inner_segment_start_y(&tag, exec_state, args.clone())?;
257
258 Ok(args.make_user_val_from_f64_with_type(result))
259}
260
261#[stdlib {
276 name = "segStartY",
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::new(
287 format!("Expected a line segment with a path, found `{:?}`", line),
288 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 unlabeled_first = true,
320 args = {
321 sketch = { docs = "The sketch whose line segment is being queried"},
322 },
323 tags = ["sketch"]
324}]
325fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
326 let last_line = sketch
327 .paths
328 .last()
329 .ok_or_else(|| {
330 KclError::Type(KclErrorDetails::new(
331 format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
332 vec![args.source_range],
333 ))
334 })?
335 .get_base();
336
337 Ok(TyF64::new(last_line.to[0], last_line.units.into()))
338}
339
340pub async fn last_segment_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
342 let sketch =
343 args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
344 let result = inner_last_segment_y(sketch, args.clone())?;
345
346 Ok(args.make_user_val_from_f64_with_type(result))
347}
348
349#[stdlib {
364 name = "lastSegY",
365 unlabeled_first = true,
366 args = {
367 sketch = { docs = "The sketch whose line segment is being queried"},
368 },
369 tags = ["sketch"]
370}]
371fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
372 let last_line = sketch
373 .paths
374 .last()
375 .ok_or_else(|| {
376 KclError::Type(KclErrorDetails::new(
377 format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
378 vec![args.source_range],
379 ))
380 })?
381 .get_base();
382
383 Ok(TyF64::new(last_line.to[1], last_line.units.into()))
384}
385
386pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
388 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
389 let result = inner_segment_length(&tag, exec_state, args.clone())?;
390 Ok(args.make_user_val_from_f64_with_type(result))
391}
392
393#[stdlib {
413 name = "segLen",
414 unlabeled_first = true,
415 args = {
416 tag = { docs = "The line segment being queried by its tag"},
417 },
418 tags = ["sketch"]
419}]
420fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
421 let line = args.get_tag_engine_info(exec_state, tag)?;
422 let path = line.path.clone().ok_or_else(|| {
423 KclError::Type(KclErrorDetails::new(
424 format!("Expected a line segment with a path, found `{:?}`", line),
425 vec![args.source_range],
426 ))
427 })?;
428
429 Ok(path.length())
430}
431
432pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
434 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
435
436 let result = inner_segment_angle(&tag, exec_state, args.clone())?;
437 Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
438}
439
440#[stdlib {
456 name = "segAng",
457 unlabeled_first = true,
458 args = {
459 tag = { docs = "The line segment being queried by its tag"},
460 },
461 tags = ["sketch"]
462}]
463fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
464 let line = args.get_tag_engine_info(exec_state, tag)?;
465 let path = line.path.clone().ok_or_else(|| {
466 KclError::Type(KclErrorDetails::new(
467 format!("Expected a line segment with a path, found `{:?}`", line),
468 vec![args.source_range],
469 ))
470 })?;
471
472 let result = between(path.get_base().from, path.get_base().to);
473
474 Ok(result.to_degrees())
475}
476
477pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
479 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
480
481 let result = inner_tangent_to_end(&tag, exec_state, args.clone()).await?;
482 Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
483}
484
485#[stdlib {
557 name = "tangentToEnd",
558 unlabeled_first = true,
559 args = {
560 tag = { docs = "The line segment being queried by its tag"},
561 },
562 tags = ["sketch"]
563}]
564async fn inner_tangent_to_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
565 let line = args.get_tag_engine_info(exec_state, tag)?;
566 let path = line.path.clone().ok_or_else(|| {
567 KclError::Type(KclErrorDetails::new(
568 format!("Expected a line segment with a path, found `{:?}`", line),
569 vec![args.source_range],
570 ))
571 })?;
572
573 let from = untype_point(path.get_to()).0;
574
575 let tangent_info = path.get_tangential_info();
577 let tan_previous_point = tangent_info.tan_previous_point(from);
578
579 let previous_end_tangent = Angle::from_radians(f64::atan2(
582 from[1] - tan_previous_point[1],
583 from[0] - tan_previous_point[0],
584 ));
585
586 Ok(previous_end_tangent.to_degrees())
587}