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 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::new(
63 format!("Expected a line segment with a path, found `{:?}`", line),
64 vec![args.source_range],
65 ))
66 })?;
67 let (p, ty) = path.end_point_components();
68 let point = [TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)];
70
71 Ok(point)
72}
73
74pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
76 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
77 let result = inner_segment_end_x(&tag, exec_state, args.clone())?;
78
79 Ok(args.make_user_val_from_f64_with_type(result))
80}
81
82#[stdlib {
96 name = "segEndX",
97 keywords = true,
98 unlabeled_first = true,
99 args = {
100 tag = { docs = "The line segment being queried by its tag"},
101 },
102 tags = ["sketch"]
103}]
104fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
105 let line = args.get_tag_engine_info(exec_state, tag)?;
106 let path = line.path.clone().ok_or_else(|| {
107 KclError::Type(KclErrorDetails::new(
108 format!("Expected a line segment with a path, found `{:?}`", line),
109 vec![args.source_range],
110 ))
111 })?;
112
113 Ok(TyF64::new(path.get_base().to[0], path.get_base().units.into()))
114}
115
116pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
118 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
119 let result = inner_segment_end_y(&tag, exec_state, args.clone())?;
120
121 Ok(args.make_user_val_from_f64_with_type(result))
122}
123
124#[stdlib {
139 name = "segEndY",
140 keywords = true,
141 unlabeled_first = true,
142 args = {
143 tag = { docs = "The line segment being queried by its tag"},
144 },
145 tags = ["sketch"]
146}]
147fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
148 let line = args.get_tag_engine_info(exec_state, tag)?;
149 let path = line.path.clone().ok_or_else(|| {
150 KclError::Type(KclErrorDetails::new(
151 format!("Expected a line segment with a path, found `{:?}`", line),
152 vec![args.source_range],
153 ))
154 })?;
155
156 Ok(path.get_to()[1].clone())
157}
158
159pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
161 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
162 let pt = inner_segment_start(&tag, exec_state, args.clone())?;
163
164 args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty.clone())
165}
166
167#[stdlib {
193 name = "segStart",
194 keywords = true,
195 unlabeled_first = true,
196 args = {
197 tag = { docs = "The line segment being queried by its tag"},
198 },
199 tags = ["sketch"]
200}]
201fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
202 let line = args.get_tag_engine_info(exec_state, tag)?;
203 let path = line.path.clone().ok_or_else(|| {
204 KclError::Type(KclErrorDetails::new(
205 format!("Expected a line segment with a path, found `{:?}`", line),
206 vec![args.source_range],
207 ))
208 })?;
209 let (p, ty) = path.start_point_components();
210 let point = [TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)];
212
213 Ok(point)
214}
215
216pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
218 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
219 let result = inner_segment_start_x(&tag, exec_state, args.clone())?;
220
221 Ok(args.make_user_val_from_f64_with_type(result))
222}
223
224#[stdlib {
238 name = "segStartX",
239 keywords = true,
240 unlabeled_first = true,
241 args = {
242 tag = { docs = "The line segment being queried by its tag"},
243 },
244 tags = ["sketch"]
245}]
246fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
247 let line = args.get_tag_engine_info(exec_state, tag)?;
248 let path = line.path.clone().ok_or_else(|| {
249 KclError::Type(KclErrorDetails::new(
250 format!("Expected a line segment with a path, found `{:?}`", line),
251 vec![args.source_range],
252 ))
253 })?;
254
255 Ok(path.get_from()[0].clone())
256}
257
258pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
260 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
261 let result = inner_segment_start_y(&tag, exec_state, args.clone())?;
262
263 Ok(args.make_user_val_from_f64_with_type(result))
264}
265
266#[stdlib {
281 name = "segStartY",
282 keywords = true,
283 unlabeled_first = true,
284 args = {
285 tag = { docs = "The line segment being queried by its tag"},
286 },
287 tags = ["sketch"]
288}]
289fn inner_segment_start_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
290 let line = args.get_tag_engine_info(exec_state, tag)?;
291 let path = line.path.clone().ok_or_else(|| {
292 KclError::Type(KclErrorDetails::new(
293 format!("Expected a line segment with a path, found `{:?}`", line),
294 vec![args.source_range],
295 ))
296 })?;
297
298 Ok(path.get_from()[1].clone())
299}
300pub async fn last_segment_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
302 let sketch =
303 args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
304 let result = inner_last_segment_x(sketch, args.clone())?;
305
306 Ok(args.make_user_val_from_f64_with_type(result))
307}
308
309#[stdlib {
324 name = "lastSegX",
325 keywords = true,
326 unlabeled_first = true,
327 args = {
328 sketch = { docs = "The sketch whose line segment is being queried"},
329 },
330 tags = ["sketch"]
331}]
332fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
333 let last_line = sketch
334 .paths
335 .last()
336 .ok_or_else(|| {
337 KclError::Type(KclErrorDetails::new(
338 format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
339 vec![args.source_range],
340 ))
341 })?
342 .get_base();
343
344 Ok(TyF64::new(last_line.to[0], last_line.units.into()))
345}
346
347pub async fn last_segment_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
349 let sketch =
350 args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
351 let result = inner_last_segment_y(sketch, args.clone())?;
352
353 Ok(args.make_user_val_from_f64_with_type(result))
354}
355
356#[stdlib {
371 name = "lastSegY",
372 keywords = true,
373 unlabeled_first = true,
374 args = {
375 sketch = { docs = "The sketch whose line segment is being queried"},
376 },
377 tags = ["sketch"]
378}]
379fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
380 let last_line = sketch
381 .paths
382 .last()
383 .ok_or_else(|| {
384 KclError::Type(KclErrorDetails::new(
385 format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
386 vec![args.source_range],
387 ))
388 })?
389 .get_base();
390
391 Ok(TyF64::new(last_line.to[1], last_line.units.into()))
392}
393
394pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
396 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
397 let result = inner_segment_length(&tag, exec_state, args.clone())?;
398 Ok(args.make_user_val_from_f64_with_type(result))
399}
400
401#[stdlib {
421 name = "segLen",
422 keywords = true,
423 unlabeled_first = true,
424 args = {
425 tag = { docs = "The line segment being queried by its tag"},
426 },
427 tags = ["sketch"]
428}]
429fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
430 let line = args.get_tag_engine_info(exec_state, tag)?;
431 let path = line.path.clone().ok_or_else(|| {
432 KclError::Type(KclErrorDetails::new(
433 format!("Expected a line segment with a path, found `{:?}`", line),
434 vec![args.source_range],
435 ))
436 })?;
437
438 Ok(path.length())
439}
440
441pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
443 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
444
445 let result = inner_segment_angle(&tag, exec_state, args.clone())?;
446 Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
447}
448
449#[stdlib {
465 name = "segAng",
466 keywords = true,
467 unlabeled_first = true,
468 args = {
469 tag = { docs = "The line segment being queried by its tag"},
470 },
471 tags = ["sketch"]
472}]
473fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
474 let line = args.get_tag_engine_info(exec_state, tag)?;
475 let path = line.path.clone().ok_or_else(|| {
476 KclError::Type(KclErrorDetails::new(
477 format!("Expected a line segment with a path, found `{:?}`", line),
478 vec![args.source_range],
479 ))
480 })?;
481
482 let result = between(path.get_base().from, path.get_base().to);
483
484 Ok(result.to_degrees())
485}
486
487pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
489 let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
490
491 let result = inner_tangent_to_end(&tag, exec_state, args.clone()).await?;
492 Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
493}
494
495#[stdlib {
567 name = "tangentToEnd",
568 keywords = true,
569 unlabeled_first = true,
570 args = {
571 tag = { docs = "The line segment being queried by its tag"},
572 },
573 tags = ["sketch"]
574}]
575async fn inner_tangent_to_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
576 let line = args.get_tag_engine_info(exec_state, tag)?;
577 let path = line.path.clone().ok_or_else(|| {
578 KclError::Type(KclErrorDetails::new(
579 format!("Expected a line segment with a path, found `{:?}`", line),
580 vec![args.source_range],
581 ))
582 })?;
583
584 let from = untype_point(path.get_to()).0;
585
586 let tangent_info = path.get_tangential_info();
588 let tan_previous_point = tangent_info.tan_previous_point(from);
589
590 let previous_end_tangent = Angle::from_radians(f64::atan2(
593 from[1] - tan_previous_point[1],
594 from[0] - tan_previous_point[0],
595 ));
596
597 Ok(previous_end_tangent.to_degrees())
598}