2023-08-24 15:34:51 -07:00
|
|
|
//! Functions related to line segments.
|
|
|
|
|
2023-08-29 14:12:48 -07:00
|
|
|
use anyhow::Result;
|
|
|
|
use derive_docs::stdlib;
|
2024-11-25 13:07:03 -05:00
|
|
|
use kittycad_modeling_cmds::shared::Angle;
|
2023-08-29 14:12:48 -07:00
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
use crate::{
|
|
|
|
errors::{KclError, KclErrorDetails},
|
2024-12-07 07:16:04 +13:00
|
|
|
execution::{ExecState, KclValue, Point2d, Sketch, TagIdentifier},
|
2024-06-19 13:57:50 -07:00
|
|
|
std::{utils::between, Args},
|
2023-08-24 15:34:51 -07:00
|
|
|
};
|
|
|
|
|
2024-11-05 14:10:35 -06:00
|
|
|
/// Returns the point at the end of the given segment.
|
|
|
|
pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
|
|
let tag: TagIdentifier = args.get_data()?;
|
|
|
|
let result = inner_segment_end(&tag, exec_state, args.clone())?;
|
|
|
|
|
|
|
|
args.make_user_val_from_point(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Compute the ending point of the provided line segment.
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// w = 15
|
|
|
|
/// cube = startSketchAt([0, 0])
|
|
|
|
/// |> line([w, 0], %, $line1)
|
|
|
|
/// |> line([0, w], %, $line2)
|
|
|
|
/// |> line([-w, 0], %, $line3)
|
|
|
|
/// |> line([0, -w], %, $line4)
|
|
|
|
/// |> close(%)
|
|
|
|
/// |> extrude(5, %)
|
|
|
|
///
|
2024-12-12 11:33:37 -05:00
|
|
|
/// fn cylinder(radius, tag) {
|
2024-11-05 14:10:35 -06:00
|
|
|
/// return startSketchAt([0, 0])
|
2024-11-25 09:21:55 +13:00
|
|
|
/// |> circle({ radius = radius, center = segEnd(tag) }, %)
|
2024-11-05 14:10:35 -06:00
|
|
|
/// |> extrude(radius, %)
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// cylinder(1, line1)
|
|
|
|
/// cylinder(2, line2)
|
|
|
|
/// cylinder(3, line3)
|
|
|
|
/// cylinder(4, line4)
|
|
|
|
/// ```
|
|
|
|
#[stdlib {
|
|
|
|
name = "segEnd",
|
|
|
|
}]
|
|
|
|
fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[f64; 2], KclError> {
|
|
|
|
let line = args.get_tag_engine_info(exec_state, tag)?;
|
|
|
|
let path = line.path.clone().ok_or_else(|| {
|
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
|
|
|
|
Ok(path.get_base().to)
|
|
|
|
}
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
/// Returns the segment end of x.
|
2024-09-16 15:10:33 -04:00
|
|
|
pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-07-27 22:56:46 -07:00
|
|
|
let tag: TagIdentifier = args.get_data()?;
|
2024-09-16 15:10:33 -04:00
|
|
|
let result = inner_segment_end_x(&tag, exec_state, args.clone())?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
2024-11-14 17:27:19 -06:00
|
|
|
Ok(args.make_user_val_from_f64(result))
|
2023-08-25 13:41:04 -07:00
|
|
|
}
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
/// Compute the ending point of the provided line segment along the 'x' axis.
|
2024-03-13 12:56:46 -07:00
|
|
|
///
|
|
|
|
/// ```no_run
|
2024-12-12 11:33:37 -05:00
|
|
|
/// exampleSketch = startSketchOn('XZ')
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> startProfileAt([0, 0], %)
|
2024-07-27 17:59:41 -07:00
|
|
|
/// |> line([20, 0], %, $thing)
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> line([0, 5], %)
|
2024-07-27 22:56:46 -07:00
|
|
|
/// |> line([segEndX(thing), 0], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> line([-20, 10], %)
|
|
|
|
/// |> close(%)
|
|
|
|
///
|
2024-12-12 11:33:37 -05:00
|
|
|
/// example = extrude(5, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
#[stdlib {
|
|
|
|
name = "segEndX",
|
|
|
|
}]
|
2024-09-16 15:10:33 -04:00
|
|
|
fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
|
|
|
let line = args.get_tag_engine_info(exec_state, tag)?;
|
2024-10-28 20:20:45 -04:00
|
|
|
let path = line.path.clone().ok_or_else(|| {
|
2024-07-28 00:30:04 -07:00
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
|
2024-10-25 09:27:40 -05:00
|
|
|
Ok(path.get_base().to[0])
|
2023-08-24 15:34:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the segment end of y.
|
2024-09-16 15:10:33 -04:00
|
|
|
pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-07-27 22:56:46 -07:00
|
|
|
let tag: TagIdentifier = args.get_data()?;
|
2024-09-16 15:10:33 -04:00
|
|
|
let result = inner_segment_end_y(&tag, exec_state, args.clone())?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
2024-11-14 17:27:19 -06:00
|
|
|
Ok(args.make_user_val_from_f64(result))
|
2023-08-25 13:41:04 -07:00
|
|
|
}
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
/// Compute the ending point of the provided line segment along the 'y' axis.
|
2024-03-13 12:56:46 -07:00
|
|
|
///
|
|
|
|
/// ```no_run
|
2024-12-12 11:33:37 -05:00
|
|
|
/// exampleSketch = startSketchOn('XZ')
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
/// |> line([20, 0], %)
|
2024-07-27 17:59:41 -07:00
|
|
|
/// |> line([0, 3], %, $thing)
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> line([-10, 0], %)
|
2024-07-27 22:56:46 -07:00
|
|
|
/// |> line([0, segEndY(thing)], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
/// |> close(%)
|
|
|
|
///
|
2024-12-12 11:33:37 -05:00
|
|
|
/// example = extrude(5, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
#[stdlib {
|
|
|
|
name = "segEndY",
|
|
|
|
}]
|
2024-09-16 15:10:33 -04:00
|
|
|
fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
|
|
|
let line = args.get_tag_engine_info(exec_state, tag)?;
|
2024-10-28 20:20:45 -04:00
|
|
|
let path = line.path.clone().ok_or_else(|| {
|
2024-07-28 00:30:04 -07:00
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
|
2024-10-25 09:27:40 -05:00
|
|
|
Ok(path.get_to()[1])
|
2023-08-24 15:34:51 -07:00
|
|
|
}
|
|
|
|
|
2024-11-05 14:10:35 -06:00
|
|
|
/// Returns the point at the start of the given segment.
|
|
|
|
pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
|
|
let tag: TagIdentifier = args.get_data()?;
|
|
|
|
let result = inner_segment_start(&tag, exec_state, args.clone())?;
|
|
|
|
|
|
|
|
args.make_user_val_from_point(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Compute the starting point of the provided line segment.
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// w = 15
|
|
|
|
/// cube = startSketchAt([0, 0])
|
|
|
|
/// |> line([w, 0], %, $line1)
|
|
|
|
/// |> line([0, w], %, $line2)
|
|
|
|
/// |> line([-w, 0], %, $line3)
|
|
|
|
/// |> line([0, -w], %, $line4)
|
|
|
|
/// |> close(%)
|
|
|
|
/// |> extrude(5, %)
|
|
|
|
///
|
2024-12-12 11:33:37 -05:00
|
|
|
/// fn cylinder(radius, tag) {
|
2024-11-05 14:10:35 -06:00
|
|
|
/// return startSketchAt([0, 0])
|
2024-11-25 09:21:55 +13:00
|
|
|
/// |> circle({ radius = radius, center = segStart(tag) }, %)
|
2024-11-05 14:10:35 -06:00
|
|
|
/// |> extrude(radius, %)
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// cylinder(1, line1)
|
|
|
|
/// cylinder(2, line2)
|
|
|
|
/// cylinder(3, line3)
|
|
|
|
/// cylinder(4, line4)
|
|
|
|
/// ```
|
|
|
|
#[stdlib {
|
|
|
|
name = "segStart",
|
|
|
|
}]
|
|
|
|
fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[f64; 2], KclError> {
|
|
|
|
let line = args.get_tag_engine_info(exec_state, tag)?;
|
|
|
|
let path = line.path.clone().ok_or_else(|| {
|
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
|
|
|
|
Ok(path.get_from().to_owned())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the segment start of x.
|
|
|
|
pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
|
|
let tag: TagIdentifier = args.get_data()?;
|
|
|
|
let result = inner_segment_start_x(&tag, exec_state, args.clone())?;
|
|
|
|
|
2024-11-14 17:27:19 -06:00
|
|
|
Ok(args.make_user_val_from_f64(result))
|
2024-11-05 14:10:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Compute the starting point of the provided line segment along the 'x' axis.
|
|
|
|
///
|
|
|
|
/// ```no_run
|
2024-12-12 11:33:37 -05:00
|
|
|
/// exampleSketch = startSketchOn('XZ')
|
2024-11-05 14:10:35 -06:00
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
/// |> line([20, 0], %, $thing)
|
|
|
|
/// |> line([0, 5], %)
|
|
|
|
/// |> line([20 - segStartX(thing), 0], %)
|
|
|
|
/// |> line([-20, 10], %)
|
|
|
|
/// |> close(%)
|
|
|
|
///
|
2024-12-12 11:33:37 -05:00
|
|
|
/// example = extrude(5, exampleSketch)
|
2024-11-05 14:10:35 -06:00
|
|
|
/// ```
|
|
|
|
#[stdlib {
|
|
|
|
name = "segStartX",
|
|
|
|
}]
|
|
|
|
fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
|
|
|
let line = args.get_tag_engine_info(exec_state, tag)?;
|
|
|
|
let path = line.path.clone().ok_or_else(|| {
|
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
|
|
|
|
Ok(path.get_from()[0])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the segment start of y.
|
|
|
|
pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
|
|
let tag: TagIdentifier = args.get_data()?;
|
|
|
|
let result = inner_segment_start_y(&tag, exec_state, args.clone())?;
|
|
|
|
|
2024-11-14 17:27:19 -06:00
|
|
|
Ok(args.make_user_val_from_f64(result))
|
2024-11-05 14:10:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Compute the starting point of the provided line segment along the 'y' axis.
|
|
|
|
///
|
|
|
|
/// ```no_run
|
2024-12-12 11:33:37 -05:00
|
|
|
/// exampleSketch = startSketchOn('XZ')
|
2024-11-05 14:10:35 -06:00
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
/// |> line([20, 0], %)
|
|
|
|
/// |> line([0, 3], %, $thing)
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
/// |> line([0, 20-segStartY(thing)], %)
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
/// |> close(%)
|
|
|
|
///
|
2024-12-12 11:33:37 -05:00
|
|
|
/// example = extrude(5, exampleSketch)
|
2024-11-05 14:10:35 -06:00
|
|
|
/// ```
|
|
|
|
#[stdlib {
|
|
|
|
name = "segStartY",
|
|
|
|
}]
|
|
|
|
fn inner_segment_start_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
|
|
|
let line = args.get_tag_engine_info(exec_state, tag)?;
|
|
|
|
let path = line.path.clone().ok_or_else(|| {
|
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
|
|
|
|
Ok(path.get_from()[1])
|
|
|
|
}
|
2023-08-24 15:34:51 -07:00
|
|
|
/// Returns the last segment of x.
|
2024-09-16 15:10:33 -04:00
|
|
|
pub async fn last_segment_x(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-09-27 15:44:44 -07:00
|
|
|
let sketch = args.get_sketch()?;
|
|
|
|
let result = inner_last_segment_x(sketch, args.clone())?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
2024-11-14 17:27:19 -06:00
|
|
|
Ok(args.make_user_val_from_f64(result))
|
2023-08-25 13:41:04 -07:00
|
|
|
}
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
/// Extract the 'x' axis value of the last line segment in the provided 2-d
|
|
|
|
/// sketch.
|
2024-03-13 12:56:46 -07:00
|
|
|
///
|
|
|
|
/// ```no_run
|
2024-12-12 11:33:37 -05:00
|
|
|
/// exampleSketch = startSketchOn("XZ")
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
/// |> line([5, 0], %)
|
|
|
|
/// |> line([20, 5], %)
|
2024-08-06 20:27:26 -04:00
|
|
|
/// |> line([lastSegX(%), 0], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> line([-15, 0], %)
|
|
|
|
/// |> close(%)
|
|
|
|
///
|
2024-12-12 11:33:37 -05:00
|
|
|
/// example = extrude(5, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
#[stdlib {
|
|
|
|
name = "lastSegX",
|
|
|
|
}]
|
2024-09-27 15:44:44 -07:00
|
|
|
fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<f64, KclError> {
|
|
|
|
let last_line = sketch
|
2024-10-23 12:42:54 -05:00
|
|
|
.paths
|
2023-08-24 15:34:51 -07:00
|
|
|
.last()
|
|
|
|
.ok_or_else(|| {
|
|
|
|
KclError::Type(KclErrorDetails {
|
2024-09-27 15:44:44 -07:00
|
|
|
message: format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
|
2023-08-24 15:34:51 -07:00
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?
|
|
|
|
.get_base();
|
|
|
|
|
2023-08-25 13:41:04 -07:00
|
|
|
Ok(last_line.to[0])
|
2023-08-24 15:34:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the last segment of y.
|
2024-09-16 15:10:33 -04:00
|
|
|
pub async fn last_segment_y(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-09-27 15:44:44 -07:00
|
|
|
let sketch = args.get_sketch()?;
|
|
|
|
let result = inner_last_segment_y(sketch, args.clone())?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
2024-11-14 17:27:19 -06:00
|
|
|
Ok(args.make_user_val_from_f64(result))
|
2023-08-25 13:41:04 -07:00
|
|
|
}
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
/// Extract the 'y' axis value of the last line segment in the provided 2-d
|
|
|
|
/// sketch.
|
2024-03-13 12:56:46 -07:00
|
|
|
///
|
|
|
|
/// ```no_run
|
2024-12-12 11:33:37 -05:00
|
|
|
/// exampleSketch = startSketchOn("XZ")
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
/// |> line([5, 0], %)
|
|
|
|
/// |> line([20, 5], %)
|
|
|
|
/// |> line([0, lastSegY(%)], %)
|
|
|
|
/// |> line([-15, 0], %)
|
|
|
|
/// |> close(%)
|
|
|
|
///
|
2024-12-12 11:33:37 -05:00
|
|
|
/// example = extrude(5, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
#[stdlib {
|
|
|
|
name = "lastSegY",
|
|
|
|
}]
|
2024-09-27 15:44:44 -07:00
|
|
|
fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<f64, KclError> {
|
|
|
|
let last_line = sketch
|
2024-10-23 12:42:54 -05:00
|
|
|
.paths
|
2023-08-24 15:34:51 -07:00
|
|
|
.last()
|
|
|
|
.ok_or_else(|| {
|
|
|
|
KclError::Type(KclErrorDetails {
|
2024-09-27 15:44:44 -07:00
|
|
|
message: format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
|
2023-08-24 15:34:51 -07:00
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?
|
|
|
|
.get_base();
|
|
|
|
|
2023-08-25 13:41:04 -07:00
|
|
|
Ok(last_line.to[1])
|
2023-08-24 15:34:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the length of the segment.
|
2024-09-16 15:10:33 -04:00
|
|
|
pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-07-27 22:56:46 -07:00
|
|
|
let tag: TagIdentifier = args.get_data()?;
|
2024-09-16 15:10:33 -04:00
|
|
|
let result = inner_segment_length(&tag, exec_state, args.clone())?;
|
2024-11-14 17:27:19 -06:00
|
|
|
Ok(args.make_user_val_from_f64(result))
|
2023-08-25 13:41:04 -07:00
|
|
|
}
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
/// Compute the length of the provided line segment.
|
2024-03-13 12:56:46 -07:00
|
|
|
///
|
|
|
|
/// ```no_run
|
2024-12-12 11:33:37 -05:00
|
|
|
/// exampleSketch = startSketchOn("XZ")
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
/// |> angledLine({
|
2024-11-25 09:21:55 +13:00
|
|
|
/// angle = 60,
|
|
|
|
/// length = 10,
|
2024-07-27 17:59:41 -07:00
|
|
|
/// }, %, $thing)
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> tangentialArc({
|
2024-11-25 09:21:55 +13:00
|
|
|
/// offset = -120,
|
|
|
|
/// radius = 5,
|
2024-05-14 17:10:47 -07:00
|
|
|
/// }, %)
|
|
|
|
/// |> angledLine({
|
2024-11-25 09:21:55 +13:00
|
|
|
/// angle = -60,
|
|
|
|
/// length = segLen(thing),
|
2024-05-14 17:10:47 -07:00
|
|
|
/// }, %)
|
|
|
|
/// |> close(%)
|
|
|
|
///
|
2024-12-12 11:33:37 -05:00
|
|
|
/// example = extrude(5, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
#[stdlib {
|
|
|
|
name = "segLen",
|
|
|
|
}]
|
2024-09-16 15:10:33 -04:00
|
|
|
fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
|
|
|
let line = args.get_tag_engine_info(exec_state, tag)?;
|
2024-10-28 20:20:45 -04:00
|
|
|
let path = line.path.clone().ok_or_else(|| {
|
2024-07-28 00:30:04 -07:00
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?;
|
2024-07-27 22:56:46 -07:00
|
|
|
|
2024-10-25 09:27:40 -05:00
|
|
|
let result = path.length();
|
2023-08-25 13:41:04 -07:00
|
|
|
|
|
|
|
Ok(result)
|
2023-08-24 15:34:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the angle of the segment.
|
2024-09-16 15:10:33 -04:00
|
|
|
pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-07-27 22:56:46 -07:00
|
|
|
let tag: TagIdentifier = args.get_data()?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
2024-09-16 15:10:33 -04:00
|
|
|
let result = inner_segment_angle(&tag, exec_state, args.clone())?;
|
2024-11-14 17:27:19 -06:00
|
|
|
Ok(args.make_user_val_from_f64(result))
|
2023-08-25 13:41:04 -07:00
|
|
|
}
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
/// Compute the angle (in degrees) of the provided line segment.
|
2024-03-13 12:56:46 -07:00
|
|
|
///
|
|
|
|
/// ```no_run
|
2024-12-12 11:33:37 -05:00
|
|
|
/// exampleSketch = startSketchOn('XZ')
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
/// |> line([10, 0], %)
|
2024-07-27 17:59:41 -07:00
|
|
|
/// |> line([5, 10], %, $seg01)
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> line([-10, 0], %)
|
2024-07-27 22:56:46 -07:00
|
|
|
/// |> angledLine([segAng(seg01), 10], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> line([-10, 0], %)
|
2024-07-27 22:56:46 -07:00
|
|
|
/// |> angledLine([segAng(seg01), -15], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> close(%)
|
|
|
|
///
|
2024-12-12 11:33:37 -05:00
|
|
|
/// example = extrude(4, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
#[stdlib {
|
|
|
|
name = "segAng",
|
|
|
|
}]
|
2024-09-16 15:10:33 -04:00
|
|
|
fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
|
|
|
let line = args.get_tag_engine_info(exec_state, tag)?;
|
2024-10-28 20:20:45 -04:00
|
|
|
let path = line.path.clone().ok_or_else(|| {
|
2024-07-28 00:30:04 -07:00
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?;
|
2024-07-27 22:56:46 -07:00
|
|
|
|
2024-10-25 09:27:40 -05:00
|
|
|
let result = between(path.get_from().into(), path.get_to().into());
|
2023-08-25 13:41:04 -07:00
|
|
|
|
2024-09-18 17:04:04 -05:00
|
|
|
Ok(result.to_degrees())
|
2023-08-24 15:34:51 -07:00
|
|
|
}
|
|
|
|
|
2024-11-25 13:07:03 -05:00
|
|
|
/// Returns the angle coming out of the end of the segment in degrees.
|
|
|
|
pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
|
|
let tag: TagIdentifier = args.get_data()?;
|
|
|
|
|
|
|
|
let result = inner_tangent_to_end(&tag, exec_state, args.clone()).await?;
|
|
|
|
Ok(args.make_user_val_from_f64(result))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the angle coming out of the end of the segment in degrees.
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// // Horizontal pill.
|
|
|
|
/// pillSketch = startSketchOn('XZ')
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
/// |> line([20, 0], %)
|
|
|
|
/// |> tangentialArcToRelative([0, 10], %, $arc1)
|
|
|
|
/// |> angledLine({
|
|
|
|
/// angle: tangentToEnd(arc1),
|
|
|
|
/// length: 20,
|
|
|
|
/// }, %)
|
|
|
|
/// |> tangentialArcToRelative([0, -10], %)
|
|
|
|
/// |> close(%)
|
|
|
|
///
|
|
|
|
/// pillExtrude = extrude(10, pillSketch)
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// // Vertical pill. Use absolute coordinate for arc.
|
|
|
|
/// pillSketch = startSketchOn('XZ')
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
/// |> line([0, 20], %)
|
|
|
|
/// |> tangentialArcTo([10, 20], %, $arc1)
|
|
|
|
/// |> angledLine({
|
|
|
|
/// angle: tangentToEnd(arc1),
|
|
|
|
/// length: 20,
|
|
|
|
/// }, %)
|
|
|
|
/// |> tangentialArcToRelative([-10, 0], %)
|
|
|
|
/// |> close(%)
|
|
|
|
///
|
|
|
|
/// pillExtrude = extrude(10, pillSketch)
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// rectangleSketch = startSketchOn('XZ')
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
/// |> line([10, 0], %, $seg1)
|
|
|
|
/// |> angledLine({
|
|
|
|
/// angle: tangentToEnd(seg1),
|
|
|
|
/// length: 10,
|
|
|
|
/// }, %)
|
|
|
|
/// |> line([0, 10], %)
|
|
|
|
/// |> line([-20, 0], %)
|
|
|
|
/// |> close(%)
|
|
|
|
///
|
|
|
|
/// rectangleExtrude = extrude(10, rectangleSketch)
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// bottom = startSketchOn("XY")
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
/// |> arcTo({
|
|
|
|
/// end: [10, 10],
|
|
|
|
/// interior: [5, 1]
|
|
|
|
/// }, %, $arc1)
|
|
|
|
/// |> angledLine([tangentToEnd(arc1), 20], %)
|
|
|
|
/// |> close(%)
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// circSketch = startSketchOn("XY")
|
|
|
|
/// |> circle({ center: [0, 0], radius: 3 }, %, $circ)
|
|
|
|
///
|
|
|
|
/// triangleSketch = startSketchOn("XY")
|
|
|
|
/// |> startProfileAt([-5, 0], %)
|
|
|
|
/// |> angledLine([tangentToEnd(circ), 10], %)
|
|
|
|
/// |> line([-15, 0], %)
|
|
|
|
/// |> close(%)
|
|
|
|
/// ```
|
|
|
|
#[stdlib {
|
|
|
|
name = "tangentToEnd",
|
|
|
|
}]
|
|
|
|
async fn inner_tangent_to_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
|
|
|
let line = args.get_tag_engine_info(exec_state, tag)?;
|
|
|
|
let path = line.path.clone().ok_or_else(|| {
|
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
|
|
|
|
let from = Point2d::from(path.get_to());
|
|
|
|
|
|
|
|
// Undocumented voodoo from get_tangential_arc_to_info
|
|
|
|
let tangent_info = path.get_tangential_info();
|
|
|
|
let tan_previous_point = tangent_info.tan_previous_point(from.into());
|
|
|
|
|
|
|
|
// Calculate the end point from the angle and radius.
|
|
|
|
// atan2 outputs radians.
|
|
|
|
let previous_end_tangent = Angle::from_radians(f64::atan2(
|
|
|
|
from.y - tan_previous_point[1],
|
|
|
|
from.x - tan_previous_point[0],
|
|
|
|
));
|
|
|
|
|
|
|
|
Ok(previous_end_tangent.to_degrees())
|
|
|
|
}
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
/// Returns the angle to match the given length for x.
|
2024-09-16 15:10:33 -04:00
|
|
|
pub async fn angle_to_match_length_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-09-27 15:44:44 -07:00
|
|
|
let (tag, to, sketch) = args.get_tag_to_number_sketch()?;
|
|
|
|
let result = inner_angle_to_match_length_x(&tag, to, sketch, exec_state, args.clone())?;
|
2024-11-14 17:27:19 -06:00
|
|
|
Ok(args.make_user_val_from_f64(result))
|
2023-08-25 13:41:04 -07:00
|
|
|
}
|
|
|
|
|
2024-11-13 06:04:35 -08:00
|
|
|
/// Returns the angle to match the given length for x.
|
2024-03-13 12:56:46 -07:00
|
|
|
///
|
|
|
|
/// ```no_run
|
2024-12-12 11:33:37 -05:00
|
|
|
/// sketch001 = startSketchOn('XZ')
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> startProfileAt([0, 0], %)
|
2024-07-27 17:59:41 -07:00
|
|
|
/// |> line([2, 5], %, $seg01)
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> angledLineToX([
|
2024-07-27 17:59:41 -07:00
|
|
|
/// -angleToMatchLengthX(seg01, 7, %),
|
2024-05-14 17:10:47 -07:00
|
|
|
/// 10
|
|
|
|
/// ], %)
|
|
|
|
/// |> close(%)
|
|
|
|
///
|
2024-12-12 11:33:37 -05:00
|
|
|
/// extrusion = extrude(5, sketch001)
|
2024-03-13 12:56:46 -07:00
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
#[stdlib {
|
|
|
|
name = "angleToMatchLengthX",
|
|
|
|
}]
|
|
|
|
fn inner_angle_to_match_length_x(
|
2024-07-27 22:56:46 -07:00
|
|
|
tag: &TagIdentifier,
|
2023-08-25 13:41:04 -07:00
|
|
|
to: f64,
|
2024-09-27 15:44:44 -07:00
|
|
|
sketch: Sketch,
|
2024-09-16 15:10:33 -04:00
|
|
|
exec_state: &mut ExecState,
|
2023-09-20 18:27:08 -07:00
|
|
|
args: Args,
|
2023-08-25 13:41:04 -07:00
|
|
|
) -> Result<f64, KclError> {
|
2024-09-16 15:10:33 -04:00
|
|
|
let line = args.get_tag_engine_info(exec_state, tag)?;
|
2024-10-28 20:20:45 -04:00
|
|
|
let path = line.path.clone().ok_or_else(|| {
|
2024-07-28 00:30:04 -07:00
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?;
|
2024-07-27 22:56:46 -07:00
|
|
|
|
2024-10-25 09:27:40 -05:00
|
|
|
let length = path.length();
|
2023-08-24 15:34:51 -07:00
|
|
|
|
2024-09-27 15:44:44 -07:00
|
|
|
let last_line = sketch
|
2024-10-23 12:42:54 -05:00
|
|
|
.paths
|
2023-08-24 15:34:51 -07:00
|
|
|
.last()
|
|
|
|
.ok_or_else(|| {
|
|
|
|
KclError::Type(KclErrorDetails {
|
2024-09-27 15:44:44 -07:00
|
|
|
message: format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
|
2023-08-24 15:34:51 -07:00
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?
|
|
|
|
.get_base();
|
|
|
|
|
|
|
|
let diff = (to - last_line.to[0]).abs();
|
|
|
|
|
2024-03-21 14:14:32 +11:00
|
|
|
let angle_r = (diff / length).acos();
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
|
|
if diff > length {
|
2023-08-25 13:41:04 -07:00
|
|
|
Ok(0.0)
|
2023-08-24 15:34:51 -07:00
|
|
|
} else {
|
2023-09-13 22:25:41 -06:00
|
|
|
Ok(angle_r.to_degrees())
|
2023-08-24 15:34:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the angle to match the given length for y.
|
2024-09-16 15:10:33 -04:00
|
|
|
pub async fn angle_to_match_length_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-09-27 15:44:44 -07:00
|
|
|
let (tag, to, sketch) = args.get_tag_to_number_sketch()?;
|
|
|
|
let result = inner_angle_to_match_length_y(&tag, to, sketch, exec_state, args.clone())?;
|
2024-11-14 17:27:19 -06:00
|
|
|
Ok(args.make_user_val_from_f64(result))
|
2023-08-25 13:41:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the angle to match the given length for y.
|
2024-03-13 12:56:46 -07:00
|
|
|
///
|
|
|
|
/// ```no_run
|
2024-12-12 11:33:37 -05:00
|
|
|
/// sketch001 = startSketchOn('XZ')
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> startProfileAt([0, 0], %)
|
2024-07-27 17:59:41 -07:00
|
|
|
/// |> line([1, 2], %, $seg01)
|
2024-05-14 17:10:47 -07:00
|
|
|
/// |> angledLine({
|
2024-11-25 09:21:55 +13:00
|
|
|
/// angle = angleToMatchLengthY(seg01, 15, %),
|
|
|
|
/// length = 5,
|
2024-05-14 17:10:47 -07:00
|
|
|
/// }, %)
|
|
|
|
/// |> yLineTo(0, %)
|
|
|
|
/// |> close(%)
|
|
|
|
///
|
2024-12-12 11:33:37 -05:00
|
|
|
/// extrusion = extrude(5, sketch001)
|
2024-03-13 12:56:46 -07:00
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
#[stdlib {
|
|
|
|
name = "angleToMatchLengthY",
|
|
|
|
}]
|
|
|
|
fn inner_angle_to_match_length_y(
|
2024-07-27 22:56:46 -07:00
|
|
|
tag: &TagIdentifier,
|
2023-08-25 13:41:04 -07:00
|
|
|
to: f64,
|
2024-09-27 15:44:44 -07:00
|
|
|
sketch: Sketch,
|
2024-09-16 15:10:33 -04:00
|
|
|
exec_state: &mut ExecState,
|
2023-09-20 18:27:08 -07:00
|
|
|
args: Args,
|
2023-08-25 13:41:04 -07:00
|
|
|
) -> Result<f64, KclError> {
|
2024-09-16 15:10:33 -04:00
|
|
|
let line = args.get_tag_engine_info(exec_state, tag)?;
|
2024-10-28 20:20:45 -04:00
|
|
|
let path = line.path.clone().ok_or_else(|| {
|
2024-07-28 00:30:04 -07:00
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
|
2024-10-25 09:27:40 -05:00
|
|
|
let length = path.length();
|
2023-08-24 15:34:51 -07:00
|
|
|
|
2024-09-27 15:44:44 -07:00
|
|
|
let last_line = sketch
|
2024-10-23 12:42:54 -05:00
|
|
|
.paths
|
2023-08-24 15:34:51 -07:00
|
|
|
.last()
|
|
|
|
.ok_or_else(|| {
|
|
|
|
KclError::Type(KclErrorDetails {
|
2024-09-27 15:44:44 -07:00
|
|
|
message: format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
|
2023-08-24 15:34:51 -07:00
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
})
|
|
|
|
})?
|
|
|
|
.get_base();
|
|
|
|
|
|
|
|
let diff = (to - last_line.to[1]).abs();
|
|
|
|
|
2024-03-21 14:14:32 +11:00
|
|
|
let angle_r = (diff / length).asin();
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
|
|
if diff > length {
|
2023-08-25 13:41:04 -07:00
|
|
|
Ok(0.0)
|
2023-08-24 15:34:51 -07:00
|
|
|
} else {
|
2023-09-13 22:25:41 -06:00
|
|
|
Ok(angle_r.to_degrees())
|
2023-08-24 15:34:51 -07:00
|
|
|
}
|
|
|
|
}
|