2023-08-24 15:34:51 -07:00
|
|
|
|
//! Functions related to sketching.
|
|
|
|
|
|
2024-07-05 16:53:13 -07:00
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
2023-08-29 14:12:48 -07:00
|
|
|
|
use anyhow::Result;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
use derive_docs::stdlib;
|
2024-09-18 17:04:04 -05:00
|
|
|
|
use kcmc::shared::Point2d as KPoint2d; // Point2d is already defined in this pkg, to impl ts_rs traits.
|
2024-09-19 14:06:29 -07:00
|
|
|
|
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, shared::Angle, ModelingCmd};
|
2024-09-18 17:04:04 -05:00
|
|
|
|
use kittycad_modeling_cmds as kcmc;
|
|
|
|
|
use kittycad_modeling_cmds::shared::PathSegment;
|
2024-02-13 10:26:09 -08:00
|
|
|
|
use parse_display::{Display, FromStr};
|
2023-08-25 13:41:04 -07:00
|
|
|
|
use schemars::JsonSchema;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
|
|
|
|
use crate::{
|
2024-06-24 14:45:07 -07:00
|
|
|
|
ast::types::TagDeclarator,
|
2023-08-24 15:34:51 -07:00
|
|
|
|
errors::{KclError, KclErrorDetails},
|
2023-10-05 14:27:48 -07:00
|
|
|
|
executor::{
|
2024-09-16 15:10:33 -04:00
|
|
|
|
BasePath, ExecState, ExtrudeGroup, Face, GeoMeta, KclValue, Path, Plane, PlaneType, Point2d, Point3d,
|
|
|
|
|
SketchGroup, SketchGroupSet, SketchSurface, TagEngineInfo, TagIdentifier, UserVal,
|
2023-10-05 14:27:48 -07:00
|
|
|
|
},
|
2023-08-24 15:34:51 -07:00
|
|
|
|
std::{
|
2024-02-11 15:08:54 -08:00
|
|
|
|
utils::{
|
|
|
|
|
arc_angles, arc_center_and_end, get_tangent_point_from_previous_arc, get_tangential_arc_to_info,
|
|
|
|
|
get_x_component, get_y_component, intersection_with_parallel_line, TangentialArcInfoInput,
|
|
|
|
|
},
|
2024-06-23 23:04:32 -07:00
|
|
|
|
Args,
|
2023-08-24 15:34:51 -07:00
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-23 23:04:32 -07:00
|
|
|
|
/// A tag for a face.
|
2024-07-27 22:56:46 -07:00
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
2024-06-23 23:04:32 -07:00
|
|
|
|
#[ts(export)]
|
|
|
|
|
#[serde(rename_all = "snake_case", untagged)]
|
|
|
|
|
pub enum FaceTag {
|
|
|
|
|
StartOrEnd(StartOrEnd),
|
2024-06-24 14:45:07 -07:00
|
|
|
|
/// A tag for the face.
|
2024-07-27 22:56:46 -07:00
|
|
|
|
Tag(Box<TagIdentifier>),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl std::fmt::Display for FaceTag {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
match self {
|
|
|
|
|
FaceTag::Tag(t) => write!(f, "{}", t),
|
|
|
|
|
FaceTag::StartOrEnd(StartOrEnd::Start) => write!(f, "start"),
|
|
|
|
|
FaceTag::StartOrEnd(StartOrEnd::End) => write!(f, "end"),
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-23 23:04:32 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FaceTag {
|
|
|
|
|
/// Get the face id from the tag.
|
|
|
|
|
pub async fn get_face_id(
|
|
|
|
|
&self,
|
|
|
|
|
extrude_group: &ExtrudeGroup,
|
2024-09-16 15:10:33 -04:00
|
|
|
|
exec_state: &mut ExecState,
|
2024-06-23 23:04:32 -07:00
|
|
|
|
args: &Args,
|
|
|
|
|
must_be_planar: bool,
|
|
|
|
|
) -> Result<uuid::Uuid, KclError> {
|
|
|
|
|
match self {
|
2024-09-16 15:10:33 -04:00
|
|
|
|
FaceTag::Tag(ref t) => args.get_adjacent_face_to_tag(exec_state, t, must_be_planar).await,
|
2024-06-23 23:04:32 -07:00
|
|
|
|
FaceTag::StartOrEnd(StartOrEnd::Start) => extrude_group.start_cap_id.ok_or_else(|| {
|
|
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
|
message: "Expected a start face".to_string(),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
})
|
|
|
|
|
}),
|
|
|
|
|
FaceTag::StartOrEnd(StartOrEnd::End) => extrude_group.end_cap_id.ok_or_else(|| {
|
|
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
|
message: "Expected an end face".to_string(),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
})
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, FromStr, Display)]
|
|
|
|
|
#[ts(export)]
|
|
|
|
|
#[serde(rename_all = "snake_case")]
|
|
|
|
|
#[display(style = "snake_case")]
|
|
|
|
|
pub enum StartOrEnd {
|
|
|
|
|
/// The start face as in before you extruded. This could also be known as the bottom
|
|
|
|
|
/// face. But we do not call it bottom because it would be the top face if you
|
|
|
|
|
/// extruded it in the opposite direction or flipped the camera.
|
|
|
|
|
#[serde(rename = "start", alias = "START")]
|
|
|
|
|
Start,
|
|
|
|
|
/// The end face after you extruded. This could also be known as the top
|
|
|
|
|
/// face. But we do not call it top because it would be the bottom face if you
|
|
|
|
|
/// extruded it in the opposite direction or flipped the camera.
|
|
|
|
|
#[serde(rename = "end", alias = "END")]
|
|
|
|
|
End,
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
|
/// Draw a line to a point.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn line_to(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (to, sketch_group, tag): ([f64; 2], SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_line_to(to, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Draw a line from the current origin to some absolute (x, y) point.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn("XZ")
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> lineTo([10, 0], %)
|
|
|
|
|
/// |> lineTo([0, 10], %)
|
|
|
|
|
/// |> lineTo([-10, 0], %)
|
|
|
|
|
/// |> close(%)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// const example = extrude(5, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "lineTo",
|
|
|
|
|
}]
|
2023-09-20 18:27:08 -07:00
|
|
|
|
async fn inner_line_to(
|
2024-03-15 17:03:42 -04:00
|
|
|
|
to: [f64; 2],
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-20 18:27:08 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from = sketch_group.current_pen_position()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
let id = uuid::Uuid::new_v4();
|
2023-08-31 22:19:23 -07:00
|
|
|
|
|
2024-06-19 13:57:50 -07:00
|
|
|
|
args.batch_modeling_cmd(
|
2023-08-31 22:19:23 -07:00
|
|
|
|
id,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::ExtendPath {
|
|
|
|
|
path: sketch_group.id.into(),
|
|
|
|
|
segment: PathSegment::Line {
|
|
|
|
|
end: KPoint2d::from(to).with_z(0.0).map(LengthUnit),
|
2023-09-20 17:36:26 -07:00
|
|
|
|
relative: false,
|
2023-08-31 22:19:23 -07:00
|
|
|
|
},
|
2024-09-18 17:04:04 -05:00
|
|
|
|
}),
|
2023-09-20 18:27:08 -07:00
|
|
|
|
)
|
|
|
|
|
.await?;
|
2023-08-31 22:19:23 -07:00
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
|
let current_path = Path::ToPoint {
|
|
|
|
|
base: BasePath {
|
|
|
|
|
from: from.into(),
|
|
|
|
|
to,
|
2024-07-27 22:56:46 -07:00
|
|
|
|
tag: tag.clone(),
|
2023-08-24 15:34:51 -07:00
|
|
|
|
geo_meta: GeoMeta {
|
|
|
|
|
id,
|
|
|
|
|
metadata: args.source_range.into(),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-27 22:56:46 -07:00
|
|
|
|
let mut new_sketch_group = sketch_group.clone();
|
|
|
|
|
if let Some(tag) = &tag {
|
|
|
|
|
new_sketch_group.add_tag(tag, ¤t_path);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
|
new_sketch_group.value.push(current_path);
|
|
|
|
|
|
|
|
|
|
Ok(new_sketch_group)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Draw a line to a point on the x-axis.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn x_line_to(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (to, sketch_group, tag): (f64, SketchGroup, Option<TagDeclarator>) =
|
2024-06-24 14:45:07 -07:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_x_line_to(to, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-25 13:41:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-05 23:26:19 -05:00
|
|
|
|
/// Draw a line parallel to the X axis, that ends at the given X.
|
|
|
|
|
/// E.g. if the previous line ended at (1, 1),
|
|
|
|
|
/// then xLineTo(4) draws a line from (1, 1) to (4, 1)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> xLineTo(15, %)
|
|
|
|
|
/// |> angledLine({
|
|
|
|
|
/// angle: 80,
|
|
|
|
|
/// length: 15,
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> line([8, -10], %)
|
|
|
|
|
/// |> xLineTo(40, %)
|
|
|
|
|
/// |> angledLine({
|
|
|
|
|
/// angle: 135,
|
|
|
|
|
/// length: 30,
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> xLineTo(10, %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "xLineTo",
|
|
|
|
|
}]
|
2023-09-20 18:27:08 -07:00
|
|
|
|
async fn inner_x_line_to(
|
2024-03-15 17:03:42 -04:00
|
|
|
|
to: f64,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-20 18:27:08 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from = sketch_group.current_pen_position()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_line_to([to, from.y], sketch_group, tag, args).await?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
|
|
|
|
|
Ok(new_sketch_group)
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Draw a line to a point on the y-axis.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn y_line_to(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (to, sketch_group, tag): (f64, SketchGroup, Option<TagDeclarator>) =
|
2024-06-24 14:45:07 -07:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_y_line_to(to, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-25 13:41:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-05 23:26:19 -05:00
|
|
|
|
/// Draw a line parallel to the Y axis, that ends at the given Y.
|
|
|
|
|
/// E.g. if the previous line ended at (1, 1),
|
|
|
|
|
/// then yLineTo(4) draws a line from (1, 1) to (1, 4)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn("XZ")
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// |> angledLine({
|
|
|
|
|
/// angle: 50,
|
|
|
|
|
/// length: 45,
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> yLineTo(0, %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(5, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "yLineTo",
|
|
|
|
|
}]
|
2023-09-20 18:27:08 -07:00
|
|
|
|
async fn inner_y_line_to(
|
2024-03-15 17:03:42 -04:00
|
|
|
|
to: f64,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-20 18:27:08 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from = sketch_group.current_pen_position()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_line_to([from.x, to], sketch_group, tag, args).await?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
Ok(new_sketch_group)
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Draw a line.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn line(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (delta, sketch_group, tag): ([f64; 2], SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_line(delta, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Draw a line relative to the current origin to a specified (x, y) away
|
|
|
|
|
/// from the current position.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn("XZ")
|
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> line([25, 15], %)
|
|
|
|
|
/// |> line([5, -6], %)
|
|
|
|
|
/// |> line([-10, -10], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(5, exampleSketch)
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// const exampleSketch = startSketchOn("XZ")
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> line([10, 0], %)
|
|
|
|
|
/// |> line([0, 10], %)
|
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(5, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "line",
|
|
|
|
|
}]
|
2024-03-15 17:03:42 -04:00
|
|
|
|
async fn inner_line(
|
|
|
|
|
delta: [f64; 2],
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from = sketch_group.current_pen_position()?;
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let to = [from.x + delta[0], from.y + delta[1]];
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
|
|
|
|
let id = uuid::Uuid::new_v4();
|
|
|
|
|
|
2024-06-19 13:57:50 -07:00
|
|
|
|
args.batch_modeling_cmd(
|
2023-08-24 15:34:51 -07:00
|
|
|
|
id,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::ExtendPath {
|
|
|
|
|
path: sketch_group.id.into(),
|
|
|
|
|
segment: PathSegment::Line {
|
|
|
|
|
end: KPoint2d::from(delta).with_z(0.0).map(LengthUnit),
|
2023-09-20 17:36:26 -07:00
|
|
|
|
relative: true,
|
2023-08-24 15:34:51 -07:00
|
|
|
|
},
|
2024-09-18 17:04:04 -05:00
|
|
|
|
}),
|
2023-09-20 18:27:08 -07:00
|
|
|
|
)
|
|
|
|
|
.await?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
|
|
|
|
let current_path = Path::ToPoint {
|
|
|
|
|
base: BasePath {
|
|
|
|
|
from: from.into(),
|
|
|
|
|
to,
|
2024-07-27 22:56:46 -07:00
|
|
|
|
tag: tag.clone(),
|
2023-08-24 15:34:51 -07:00
|
|
|
|
geo_meta: GeoMeta {
|
|
|
|
|
id,
|
|
|
|
|
metadata: args.source_range.into(),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-27 22:56:46 -07:00
|
|
|
|
let mut new_sketch_group = sketch_group.clone();
|
|
|
|
|
if let Some(tag) = &tag {
|
|
|
|
|
new_sketch_group.add_tag(tag, ¤t_path);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
|
new_sketch_group.value.push(current_path);
|
|
|
|
|
|
|
|
|
|
Ok(new_sketch_group)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Draw a line on the x-axis.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn x_line(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (length, sketch_group, tag): (f64, SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_x_line(length, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-25 13:41:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Draw a line relative to the current origin to a specified distance away
|
|
|
|
|
/// from the current position along the 'x' axis.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> xLine(15, %)
|
|
|
|
|
/// |> angledLine({
|
|
|
|
|
/// angle: 80,
|
|
|
|
|
/// length: 15,
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> line([8, -10], %)
|
|
|
|
|
/// |> xLine(10, %)
|
|
|
|
|
/// |> angledLine({
|
|
|
|
|
/// angle: 120,
|
|
|
|
|
/// length: 30,
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> xLine(-15, %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "xLine",
|
|
|
|
|
}]
|
2023-09-20 18:27:08 -07:00
|
|
|
|
async fn inner_x_line(
|
2024-03-15 17:03:42 -04:00
|
|
|
|
length: f64,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-20 18:27:08 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-03-15 17:03:42 -04:00
|
|
|
|
inner_line([length, 0.0], sketch_group, tag, args).await
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Draw a line on the y-axis.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn y_line(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (length, sketch_group, tag): (f64, SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_y_line(length, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-25 13:41:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Draw a line relative to the current origin to a specified distance away
|
|
|
|
|
/// from the current position along the 'y' axis.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> yLine(15, %)
|
|
|
|
|
/// |> angledLine({
|
|
|
|
|
/// angle: 30,
|
|
|
|
|
/// length: 15,
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> line([8, -10], %)
|
|
|
|
|
/// |> yLine(-5, %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "yLine",
|
|
|
|
|
}]
|
2023-09-20 18:27:08 -07:00
|
|
|
|
async fn inner_y_line(
|
2024-03-15 17:03:42 -04:00
|
|
|
|
length: f64,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-20 18:27:08 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-03-15 17:03:42 -04:00
|
|
|
|
inner_line([0.0, length], sketch_group, tag, args).await
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-25 13:41:04 -07:00
|
|
|
|
/// Data to draw an angled line.
|
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
2023-08-24 15:34:51 -07:00
|
|
|
|
#[ts(export)]
|
|
|
|
|
#[serde(rename_all = "camelCase", untagged)]
|
|
|
|
|
pub enum AngledLineData {
|
2024-03-15 17:03:42 -04:00
|
|
|
|
/// An angle and length with explicitly named parameters
|
|
|
|
|
AngleAndLengthNamed {
|
2024-07-28 22:45:40 -07:00
|
|
|
|
/// The angle of the line (in degrees).
|
2023-08-24 15:34:51 -07:00
|
|
|
|
angle: f64,
|
2023-08-25 13:41:04 -07:00
|
|
|
|
/// The length of the line.
|
2023-08-24 15:34:51 -07:00
|
|
|
|
length: f64,
|
|
|
|
|
},
|
2024-03-15 17:03:42 -04:00
|
|
|
|
/// An angle and length given as a pair
|
|
|
|
|
AngleAndLengthPair([f64; 2]),
|
2023-10-24 10:30:14 -07:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
|
/// Draw an angled line.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn angled_line(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (data, sketch_group, tag): (AngledLineData, SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_angled_line(data, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-25 13:41:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Draw a line segment relative to the current origin using the polar
|
|
|
|
|
/// measure of some angle and distance.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-03-15 17:03:42 -04:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> yLineTo(15, %)
|
2024-03-15 17:03:42 -04:00
|
|
|
|
/// |> angledLine({
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// angle: 30,
|
|
|
|
|
/// length: 15,
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> line([8, -10], %)
|
|
|
|
|
/// |> yLineTo(0, %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "angledLine",
|
|
|
|
|
}]
|
2023-09-20 18:27:08 -07:00
|
|
|
|
async fn inner_angled_line(
|
2023-08-25 13:41:04 -07:00
|
|
|
|
data: AngledLineData,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-20 18:27:08 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from = sketch_group.current_pen_position()?;
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let (angle, length) = match data {
|
|
|
|
|
AngledLineData::AngleAndLengthNamed { angle, length } => (angle, length),
|
|
|
|
|
AngledLineData::AngleAndLengthPair(pair) => (pair[0], pair[1]),
|
2023-08-24 15:34:51 -07:00
|
|
|
|
};
|
2023-09-20 17:36:26 -07:00
|
|
|
|
|
|
|
|
|
//double check me on this one - mike
|
|
|
|
|
let delta: [f64; 2] = [
|
|
|
|
|
length * f64::cos(angle.to_radians()),
|
|
|
|
|
length * f64::sin(angle.to_radians()),
|
2023-08-24 15:34:51 -07:00
|
|
|
|
];
|
2023-09-20 17:36:26 -07:00
|
|
|
|
let relative = true;
|
|
|
|
|
|
|
|
|
|
let to: [f64; 2] = [from.x + delta[0], from.y + delta[1]];
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
|
|
|
|
let id = uuid::Uuid::new_v4();
|
|
|
|
|
|
2024-06-19 13:57:50 -07:00
|
|
|
|
args.batch_modeling_cmd(
|
2023-09-11 17:14:41 -07:00
|
|
|
|
id,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::ExtendPath {
|
|
|
|
|
path: sketch_group.id.into(),
|
|
|
|
|
segment: PathSegment::Line {
|
|
|
|
|
end: KPoint2d::from(delta).with_z(0.0).map(LengthUnit),
|
2023-09-20 17:36:26 -07:00
|
|
|
|
relative,
|
2023-09-11 17:14:41 -07:00
|
|
|
|
},
|
2024-09-18 17:04:04 -05:00
|
|
|
|
}),
|
2023-09-20 18:27:08 -07:00
|
|
|
|
)
|
|
|
|
|
.await?;
|
2023-09-11 17:14:41 -07:00
|
|
|
|
|
2024-07-05 16:53:13 -07:00
|
|
|
|
let current_path = Path::ToPoint {
|
|
|
|
|
base: BasePath {
|
|
|
|
|
from: from.into(),
|
|
|
|
|
to,
|
2024-07-27 22:56:46 -07:00
|
|
|
|
tag: tag.clone(),
|
2024-07-05 16:53:13 -07:00
|
|
|
|
geo_meta: GeoMeta {
|
|
|
|
|
id,
|
|
|
|
|
metadata: args.source_range.into(),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-27 22:56:46 -07:00
|
|
|
|
let mut new_sketch_group = sketch_group.clone();
|
|
|
|
|
if let Some(tag) = &tag {
|
|
|
|
|
new_sketch_group.add_tag(tag, ¤t_path);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
|
new_sketch_group.value.push(current_path);
|
2023-08-25 13:41:04 -07:00
|
|
|
|
Ok(new_sketch_group)
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Draw an angled line of a given x length.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn angled_line_of_x_length(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (data, sketch_group, tag): (AngledLineData, SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_angled_line_of_x_length(data, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-25 13:41:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Create a line segment from the current 2-dimensional sketch origin
|
|
|
|
|
/// along some angle (in degrees) for some relative length in the 'x' dimension.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// const sketch001 = startSketchOn('XZ')
|
2024-03-15 17:03:42 -04:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
2024-07-27 17:59:41 -07:00
|
|
|
|
/// |> angledLineOfXLength({ angle: 45, length: 10 }, %, $edge1)
|
|
|
|
|
/// |> angledLineOfXLength({ angle: -15, length: 20 }, %, $edge2)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> line([0, -5], %)
|
2024-07-27 17:59:41 -07:00
|
|
|
|
/// |> close(%, $edge3)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
///
|
|
|
|
|
/// const extrusion = extrude(10, sketch001)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "angledLineOfXLength",
|
|
|
|
|
}]
|
2023-09-20 18:27:08 -07:00
|
|
|
|
async fn inner_angled_line_of_x_length(
|
2023-08-25 13:41:04 -07:00
|
|
|
|
data: AngledLineData,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-20 18:27:08 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let (angle, length) = match data {
|
|
|
|
|
AngledLineData::AngleAndLengthNamed { angle, length } => (angle, length),
|
|
|
|
|
AngledLineData::AngleAndLengthPair(pair) => (pair[0], pair[1]),
|
2023-08-24 15:34:51 -07:00
|
|
|
|
};
|
|
|
|
|
|
2024-07-28 20:36:18 -07:00
|
|
|
|
if angle.abs() == 270.0 {
|
|
|
|
|
return Err(KclError::Type(KclErrorDetails {
|
|
|
|
|
message: "Cannot have an x constrained angle of 270 degrees".to_string(),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if angle.abs() == 90.0 {
|
|
|
|
|
return Err(KclError::Type(KclErrorDetails {
|
|
|
|
|
message: "Cannot have an x constrained angle of 90 degrees".to_string(),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-14 15:51:26 -06:00
|
|
|
|
let to = get_y_component(Angle::from_degrees(angle), length);
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_line(to.into(), sketch_group, tag, args).await?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2023-08-25 13:41:04 -07:00
|
|
|
|
Ok(new_sketch_group)
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-25 13:41:04 -07:00
|
|
|
|
/// Data to draw an angled line to a point.
|
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
2023-08-24 15:34:51 -07:00
|
|
|
|
#[ts(export)]
|
2024-03-15 17:03:42 -04:00
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
|
pub struct AngledLineToData {
|
|
|
|
|
/// The angle of the line.
|
|
|
|
|
angle: f64,
|
|
|
|
|
/// The point to draw to.
|
|
|
|
|
to: f64,
|
2023-10-24 10:30:14 -07:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
|
/// Draw an angled line to a given x coordinate.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn angled_line_to_x(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (data, sketch_group, tag): (AngledLineToData, SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_angled_line_to_x(data, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-25 13:41:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Create a line segment from the current 2-dimensional sketch origin
|
|
|
|
|
/// along some angle (in degrees) for some length, ending at the provided value
|
|
|
|
|
/// in the 'x' dimension.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-03-15 17:03:42 -04:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> angledLineToX({ angle: 30, to: 10 }, %)
|
2024-03-15 17:03:42 -04:00
|
|
|
|
/// |> line([0, 10], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "angledLineToX",
|
|
|
|
|
}]
|
2023-09-20 18:27:08 -07:00
|
|
|
|
async fn inner_angled_line_to_x(
|
2023-08-25 13:41:04 -07:00
|
|
|
|
data: AngledLineToData,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-20 18:27:08 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from = sketch_group.current_pen_position()?;
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let AngledLineToData { angle, to: x_to } = data;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-07-28 20:36:18 -07:00
|
|
|
|
if angle.abs() == 270.0 {
|
|
|
|
|
return Err(KclError::Type(KclErrorDetails {
|
|
|
|
|
message: "Cannot have an x constrained angle of 270 degrees".to_string(),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if angle.abs() == 90.0 {
|
|
|
|
|
return Err(KclError::Type(KclErrorDetails {
|
|
|
|
|
message: "Cannot have an x constrained angle of 90 degrees".to_string(),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
|
let x_component = x_to - from.x;
|
2023-09-13 22:25:41 -06:00
|
|
|
|
let y_component = x_component * f64::tan(angle.to_radians());
|
2023-08-24 15:34:51 -07:00
|
|
|
|
let y_to = from.y + y_component;
|
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_line_to([x_to, y_to], sketch_group, tag, args).await?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
Ok(new_sketch_group)
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Draw an angled line of a given y length.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn angled_line_of_y_length(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (data, sketch_group, tag): (AngledLineData, SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_angled_line_of_y_length(data, sketch_group, tag, args).await?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-25 13:41:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Create a line segment from the current 2-dimensional sketch origin
|
|
|
|
|
/// along some angle (in degrees) for some relative length in the 'y' dimension.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-03-15 17:03:42 -04:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> line([10, 0], %)
|
|
|
|
|
/// |> angledLineOfYLength({ angle: 45, length: 10 }, %)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// |> line([0, 10], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> angledLineOfYLength({ angle: 135, length: 10 }, %)
|
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
|
/// |> line([0, -30], %)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "angledLineOfYLength",
|
|
|
|
|
}]
|
2023-09-20 18:27:08 -07:00
|
|
|
|
async fn inner_angled_line_of_y_length(
|
2023-08-25 13:41:04 -07:00
|
|
|
|
data: AngledLineData,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-20 18:27:08 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let (angle, length) = match data {
|
|
|
|
|
AngledLineData::AngleAndLengthNamed { angle, length } => (angle, length),
|
|
|
|
|
AngledLineData::AngleAndLengthPair(pair) => (pair[0], pair[1]),
|
2023-08-24 15:34:51 -07:00
|
|
|
|
};
|
|
|
|
|
|
2024-07-28 20:36:18 -07:00
|
|
|
|
if angle.abs() == 0.0 {
|
|
|
|
|
return Err(KclError::Type(KclErrorDetails {
|
|
|
|
|
message: "Cannot have a y constrained angle of 0 degrees".to_string(),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if angle.abs() == 180.0 {
|
|
|
|
|
return Err(KclError::Type(KclErrorDetails {
|
|
|
|
|
message: "Cannot have a y constrained angle of 180 degrees".to_string(),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-14 15:51:26 -06:00
|
|
|
|
let to = get_x_component(Angle::from_degrees(angle), length);
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_line(to.into(), sketch_group, tag, args).await?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2023-08-25 13:41:04 -07:00
|
|
|
|
Ok(new_sketch_group)
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Draw an angled line to a given y coordinate.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn angled_line_to_y(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (data, sketch_group, tag): (AngledLineToData, SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_angled_line_to_y(data, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-25 13:41:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Create a line segment from the current 2-dimensional sketch origin
|
|
|
|
|
/// along some angle (in degrees) for some length, ending at the provided value
|
|
|
|
|
/// in the 'y' dimension.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-03-15 17:03:42 -04:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> angledLineToY({ angle: 60, to: 20 }, %)
|
|
|
|
|
/// |> line([-20, 0], %)
|
|
|
|
|
/// |> angledLineToY({ angle: 70, to: 10 }, %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "angledLineToY",
|
|
|
|
|
}]
|
2023-09-20 18:27:08 -07:00
|
|
|
|
async fn inner_angled_line_to_y(
|
2023-08-25 13:41:04 -07:00
|
|
|
|
data: AngledLineToData,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-20 18:27:08 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from = sketch_group.current_pen_position()?;
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let AngledLineToData { angle, to: y_to } = data;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-07-28 20:36:18 -07:00
|
|
|
|
if angle.abs() == 0.0 {
|
|
|
|
|
return Err(KclError::Type(KclErrorDetails {
|
|
|
|
|
message: "Cannot have a y constrained angle of 0 degrees".to_string(),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if angle.abs() == 180.0 {
|
|
|
|
|
return Err(KclError::Type(KclErrorDetails {
|
|
|
|
|
message: "Cannot have a y constrained angle of 180 degrees".to_string(),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
|
let y_component = y_to - from.y;
|
2023-09-13 22:25:41 -06:00
|
|
|
|
let x_component = y_component / f64::tan(angle.to_radians());
|
2023-08-24 15:34:51 -07:00
|
|
|
|
let x_to = from.x + x_component;
|
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_line_to([x_to, y_to], sketch_group, tag, args).await?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
Ok(new_sketch_group)
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-25 13:41:04 -07:00
|
|
|
|
/// Data for drawing an angled line that intersects with a given line.
|
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
2023-08-24 15:34:51 -07:00
|
|
|
|
#[ts(export)]
|
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
|
// TODO: make sure the docs on the args below are correct.
|
2023-10-24 10:30:14 -07:00
|
|
|
|
pub struct AngledLineThatIntersectsData {
|
2023-08-24 15:34:51 -07:00
|
|
|
|
/// The angle of the line.
|
|
|
|
|
pub angle: f64,
|
|
|
|
|
/// The tag of the line to intersect with.
|
2024-06-24 14:45:07 -07:00
|
|
|
|
pub intersect_tag: TagIdentifier,
|
2023-08-24 15:34:51 -07:00
|
|
|
|
/// The offset from the intersecting line.
|
|
|
|
|
pub offset: Option<f64>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Draw an angled line that intersects with a given line.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn angled_line_that_intersects(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (data, sketch_group, tag): (AngledLineThatIntersectsData, SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2024-09-16 15:10:33 -04:00
|
|
|
|
let new_sketch_group = inner_angled_line_that_intersects(data, sketch_group, tag, exec_state, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-25 13:41:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Draw an angled line from the current origin, constructing a line segment
|
|
|
|
|
/// such that the newly created line intersects the desired target line
|
|
|
|
|
/// segment.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-03-15 17:03:42 -04:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> lineTo([5, 10], %)
|
2024-07-27 17:59:41 -07:00
|
|
|
|
/// |> lineTo([-10, 10], %, $lineToIntersect)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> lineTo([0, 20], %)
|
2024-03-15 17:03:42 -04:00
|
|
|
|
/// |> angledLineThatIntersects({
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// angle: 80,
|
2024-07-27 17:59:41 -07:00
|
|
|
|
/// intersectTag: lineToIntersect,
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// offset: 10
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "angledLineThatIntersects",
|
|
|
|
|
}]
|
2023-09-20 18:27:08 -07:00
|
|
|
|
async fn inner_angled_line_that_intersects(
|
2023-10-24 10:30:14 -07:00
|
|
|
|
data: AngledLineThatIntersectsData,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2024-09-16 15:10:33 -04:00
|
|
|
|
exec_state: &mut ExecState,
|
2023-09-20 18:27:08 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-09-16 15:10:33 -04:00
|
|
|
|
let intersect_path = args.get_tag_engine_info(exec_state, &data.intersect_tag)?;
|
2024-07-28 00:30:04 -07:00
|
|
|
|
let path = intersect_path.path.clone().ok_or_else(|| {
|
|
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
|
message: format!("Expected an intersect path with a path, found `{:?}`", intersect_path),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
})
|
|
|
|
|
})?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from = sketch_group.current_pen_position()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
let to = intersection_with_parallel_line(
|
2024-07-28 00:30:04 -07:00
|
|
|
|
&[path.from.into(), path.to.into()],
|
2023-08-24 15:34:51 -07:00
|
|
|
|
data.offset.unwrap_or_default(),
|
|
|
|
|
data.angle,
|
2023-09-14 15:51:26 -06:00
|
|
|
|
from,
|
2023-08-24 15:34:51 -07:00
|
|
|
|
);
|
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_line_to(to.into(), sketch_group, tag, args).await?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
Ok(new_sketch_group)
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Start a sketch at a given point.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn start_sketch_at(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let data: [f64; 2] = args.get_data()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-09-16 15:10:33 -04:00
|
|
|
|
let sketch_group = inner_start_sketch_at(data, exec_state, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(sketch_group.meta.clone(), sketch_group))
|
2023-08-25 13:41:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Start a new 2-dimensional sketch at a given point on the 'XY' plane.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// const exampleSketch = startSketchAt([0, 0])
|
|
|
|
|
/// |> line([10, 0], %)
|
|
|
|
|
/// |> line([0, 10], %)
|
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(5, exampleSketch)
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// const exampleSketch = startSketchAt([10, 10])
|
|
|
|
|
/// |> line([10, 0], %)
|
|
|
|
|
/// |> line([0, 10], %)
|
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(5, exampleSketch)
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// const exampleSketch = startSketchAt([-10, 23])
|
|
|
|
|
/// |> line([10, 0], %)
|
|
|
|
|
/// |> line([0, 10], %)
|
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(5, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "startSketchAt",
|
|
|
|
|
}]
|
2024-09-16 15:10:33 -04:00
|
|
|
|
async fn inner_start_sketch_at(
|
|
|
|
|
data: [f64; 2],
|
|
|
|
|
exec_state: &mut ExecState,
|
|
|
|
|
args: Args,
|
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2023-10-05 14:27:48 -07:00
|
|
|
|
// Let's assume it's the XY plane for now, this is just for backwards compatibility.
|
|
|
|
|
let xy_plane = PlaneData::XY;
|
2024-09-16 15:10:33 -04:00
|
|
|
|
let sketch_surface = inner_start_sketch_on(SketchData::Plane(xy_plane), None, exec_state, &args).await?;
|
|
|
|
|
let sketch_group = inner_start_profile_at(data, sketch_surface, None, exec_state, args).await?;
|
2023-10-05 14:27:48 -07:00
|
|
|
|
Ok(sketch_group)
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-12 18:08:42 -08:00
|
|
|
|
/// Data for start sketch on.
|
|
|
|
|
/// You can start a sketch on a plane or an extrude group.
|
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
|
|
|
|
#[ts(export)]
|
|
|
|
|
#[serde(rename_all = "camelCase", untagged)]
|
|
|
|
|
pub enum SketchData {
|
|
|
|
|
Plane(PlaneData),
|
|
|
|
|
ExtrudeGroup(Box<ExtrudeGroup>),
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-05 14:27:48 -07:00
|
|
|
|
/// Data for a plane.
|
2024-06-04 16:28:32 -05:00
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
2023-10-05 14:27:48 -07:00
|
|
|
|
#[ts(export)]
|
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
|
pub enum PlaneData {
|
|
|
|
|
/// The XY plane.
|
|
|
|
|
#[serde(rename = "XY", alias = "xy")]
|
|
|
|
|
XY,
|
|
|
|
|
/// The opposite side of the XY plane.
|
|
|
|
|
#[serde(rename = "-XY", alias = "-xy")]
|
|
|
|
|
NegXY,
|
|
|
|
|
/// The XZ plane.
|
|
|
|
|
#[serde(rename = "XZ", alias = "xz")]
|
|
|
|
|
XZ,
|
|
|
|
|
/// The opposite side of the XZ plane.
|
|
|
|
|
#[serde(rename = "-XZ", alias = "-xz")]
|
|
|
|
|
NegXZ,
|
|
|
|
|
/// The YZ plane.
|
|
|
|
|
#[serde(rename = "YZ", alias = "yz")]
|
|
|
|
|
YZ,
|
|
|
|
|
/// The opposite side of the YZ plane.
|
|
|
|
|
#[serde(rename = "-YZ", alias = "-yz")]
|
|
|
|
|
NegYZ,
|
|
|
|
|
/// A defined plane.
|
|
|
|
|
Plane {
|
|
|
|
|
/// Origin of the plane.
|
|
|
|
|
origin: Box<Point3d>,
|
|
|
|
|
/// What should the plane’s X axis be?
|
2024-07-29 13:18:55 -07:00
|
|
|
|
#[serde(rename = "xAxis", alias = "x_axis")]
|
2023-10-05 14:27:48 -07:00
|
|
|
|
x_axis: Box<Point3d>,
|
|
|
|
|
/// What should the plane’s Y axis be?
|
2024-07-29 13:18:55 -07:00
|
|
|
|
#[serde(rename = "yAxis", alias = "y_axis")]
|
2023-10-05 14:27:48 -07:00
|
|
|
|
y_axis: Box<Point3d>,
|
|
|
|
|
/// The z-axis (normal).
|
2024-07-29 13:18:55 -07:00
|
|
|
|
#[serde(rename = "zAxis", alias = "z_axis")]
|
2023-10-05 14:27:48 -07:00
|
|
|
|
z_axis: Box<Point3d>,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<PlaneData> for Plane {
|
|
|
|
|
fn from(value: PlaneData) -> Self {
|
|
|
|
|
let id = uuid::Uuid::new_v4();
|
|
|
|
|
match value {
|
|
|
|
|
PlaneData::XY => Plane {
|
|
|
|
|
id,
|
|
|
|
|
origin: Point3d::new(0.0, 0.0, 0.0),
|
|
|
|
|
x_axis: Point3d::new(1.0, 0.0, 0.0),
|
|
|
|
|
y_axis: Point3d::new(0.0, 1.0, 0.0),
|
|
|
|
|
z_axis: Point3d::new(0.0, 0.0, 1.0),
|
|
|
|
|
value: PlaneType::XY,
|
|
|
|
|
meta: vec![],
|
|
|
|
|
},
|
|
|
|
|
PlaneData::NegXY => Plane {
|
|
|
|
|
id,
|
|
|
|
|
origin: Point3d::new(0.0, 0.0, 0.0),
|
|
|
|
|
x_axis: Point3d::new(1.0, 0.0, 0.0),
|
|
|
|
|
y_axis: Point3d::new(0.0, 1.0, 0.0),
|
|
|
|
|
z_axis: Point3d::new(0.0, 0.0, -1.0),
|
|
|
|
|
value: PlaneType::XY,
|
|
|
|
|
meta: vec![],
|
|
|
|
|
},
|
|
|
|
|
PlaneData::XZ => Plane {
|
|
|
|
|
id,
|
|
|
|
|
origin: Point3d::new(0.0, 0.0, 0.0),
|
|
|
|
|
x_axis: Point3d::new(1.0, 0.0, 0.0),
|
|
|
|
|
y_axis: Point3d::new(0.0, 0.0, 1.0),
|
2024-05-21 23:35:33 -07:00
|
|
|
|
z_axis: Point3d::new(0.0, -1.0, 0.0),
|
2023-10-05 14:27:48 -07:00
|
|
|
|
value: PlaneType::XZ,
|
|
|
|
|
meta: vec![],
|
|
|
|
|
},
|
|
|
|
|
PlaneData::NegXZ => Plane {
|
|
|
|
|
id,
|
|
|
|
|
origin: Point3d::new(0.0, 0.0, 0.0),
|
2024-05-21 23:35:33 -07:00
|
|
|
|
x_axis: Point3d::new(-1.0, 0.0, 0.0),
|
2023-10-05 14:27:48 -07:00
|
|
|
|
y_axis: Point3d::new(0.0, 0.0, 1.0),
|
2024-05-21 23:35:33 -07:00
|
|
|
|
z_axis: Point3d::new(0.0, 1.0, 0.0),
|
2023-10-05 14:27:48 -07:00
|
|
|
|
value: PlaneType::XZ,
|
|
|
|
|
meta: vec![],
|
|
|
|
|
},
|
|
|
|
|
PlaneData::YZ => Plane {
|
|
|
|
|
id,
|
|
|
|
|
origin: Point3d::new(0.0, 0.0, 0.0),
|
|
|
|
|
x_axis: Point3d::new(0.0, 1.0, 0.0),
|
|
|
|
|
y_axis: Point3d::new(0.0, 0.0, 1.0),
|
|
|
|
|
z_axis: Point3d::new(1.0, 0.0, 0.0),
|
|
|
|
|
value: PlaneType::YZ,
|
|
|
|
|
meta: vec![],
|
|
|
|
|
},
|
|
|
|
|
PlaneData::NegYZ => Plane {
|
|
|
|
|
id,
|
|
|
|
|
origin: Point3d::new(0.0, 0.0, 0.0),
|
|
|
|
|
x_axis: Point3d::new(0.0, 1.0, 0.0),
|
|
|
|
|
y_axis: Point3d::new(0.0, 0.0, 1.0),
|
|
|
|
|
z_axis: Point3d::new(-1.0, 0.0, 0.0),
|
|
|
|
|
value: PlaneType::YZ,
|
|
|
|
|
meta: vec![],
|
|
|
|
|
},
|
|
|
|
|
PlaneData::Plane {
|
|
|
|
|
origin,
|
|
|
|
|
x_axis,
|
|
|
|
|
y_axis,
|
|
|
|
|
z_axis,
|
|
|
|
|
} => Plane {
|
|
|
|
|
id,
|
|
|
|
|
origin: *origin,
|
|
|
|
|
x_axis: *x_axis,
|
|
|
|
|
y_axis: *y_axis,
|
|
|
|
|
z_axis: *z_axis,
|
|
|
|
|
value: PlaneType::Custom,
|
|
|
|
|
meta: vec![],
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-12 18:08:42 -08:00
|
|
|
|
/// Start a sketch on a specific plane or face.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn start_sketch_on(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-06-23 23:04:32 -07:00
|
|
|
|
let (data, tag): (SketchData, Option<FaceTag>) = args.get_data_and_optional_tag()?;
|
2023-10-05 14:27:48 -07:00
|
|
|
|
|
2024-09-16 15:10:33 -04:00
|
|
|
|
match inner_start_sketch_on(data, tag, exec_state, &args).await? {
|
2024-08-12 16:53:24 -05:00
|
|
|
|
SketchSurface::Plane(plane) => Ok(KclValue::Plane(plane)),
|
|
|
|
|
SketchSurface::Face(face) => Ok(KclValue::Face(face)),
|
2024-02-12 18:08:42 -08:00
|
|
|
|
}
|
2023-10-05 14:27:48 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Start a new 2-dimensional sketch on a specific plane or face.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn("XY")
|
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> line([10, 0], %)
|
|
|
|
|
/// |> line([0, 10], %)
|
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(5, exampleSketch)
|
|
|
|
|
///
|
|
|
|
|
/// const exampleSketch002 = startSketchOn(example, 'end')
|
|
|
|
|
/// |> startProfileAt([1, 1], %)
|
|
|
|
|
/// |> line([8, 0], %)
|
|
|
|
|
/// |> line([0, 8], %)
|
|
|
|
|
/// |> line([-8, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example002 = extrude(5, exampleSketch002)
|
|
|
|
|
///
|
|
|
|
|
/// const exampleSketch003 = startSketchOn(example002, 'end')
|
|
|
|
|
/// |> startProfileAt([2, 2], %)
|
|
|
|
|
/// |> line([6, 0], %)
|
|
|
|
|
/// |> line([0, 6], %)
|
|
|
|
|
/// |> line([-6, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example003 = extrude(5, exampleSketch003)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn("XY")
|
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> line([10, 0], %)
|
2024-07-27 17:59:41 -07:00
|
|
|
|
/// |> line([0, 10], %, $sketchingFace)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
|
/// |> close(%)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
2024-07-27 17:59:41 -07:00
|
|
|
|
/// const exampleSketch002 = startSketchOn(example, sketchingFace)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> startProfileAt([1, 1], %)
|
|
|
|
|
/// |> line([8, 0], %)
|
|
|
|
|
/// |> line([0, 8], %)
|
|
|
|
|
/// |> line([-8, 0], %)
|
2024-07-27 17:59:41 -07:00
|
|
|
|
/// |> close(%, $sketchingFace002)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// const example002 = extrude(10, exampleSketch002)
|
|
|
|
|
///
|
2024-07-27 17:59:41 -07:00
|
|
|
|
/// const exampleSketch003 = startSketchOn(example002, sketchingFace002)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> startProfileAt([-8, 12], %)
|
|
|
|
|
/// |> line([0, 6], %)
|
|
|
|
|
/// |> line([6, 0], %)
|
|
|
|
|
/// |> line([0, -6], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example003 = extrude(5, exampleSketch003)
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// const exampleSketch = startSketchOn('XY')
|
|
|
|
|
/// |> startProfileAt([4, 12], %)
|
|
|
|
|
/// |> line([2, 0], %)
|
|
|
|
|
/// |> line([0, -6], %)
|
|
|
|
|
/// |> line([4, -6], %)
|
|
|
|
|
/// |> line([0, -6], %)
|
|
|
|
|
/// |> line([-3.75, -4.5], %)
|
|
|
|
|
/// |> line([0, -5.5], %)
|
|
|
|
|
/// |> line([-2, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = revolve({ axis: 'y', angle: 180 }, exampleSketch)
|
|
|
|
|
///
|
|
|
|
|
/// const exampleSketch002 = startSketchOn(example, 'end')
|
|
|
|
|
/// |> startProfileAt([4.5, -5], %)
|
|
|
|
|
/// |> line([0, 5], %)
|
|
|
|
|
/// |> line([5, 0], %)
|
|
|
|
|
/// |> line([0, -5], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example002 = extrude(5, exampleSketch002)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2024-05-23 19:28:13 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// const a1 = startSketchOn({
|
|
|
|
|
/// plane: {
|
|
|
|
|
/// origin: { x: 0, y: 0, z: 0 },
|
2024-07-29 13:18:55 -07:00
|
|
|
|
/// xAxis: { x: 1, y: 0, z: 0 },
|
|
|
|
|
/// yAxis: { x: 0, y: 1, z: 0 },
|
|
|
|
|
/// zAxis: { x: 0, y: 0, z: 1 }
|
2024-05-23 19:28:13 -07:00
|
|
|
|
/// }
|
|
|
|
|
/// })
|
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> line([100.0, 0], %)
|
|
|
|
|
/// |> yLine(-100.0, %)
|
|
|
|
|
/// |> xLine(-100.0, %)
|
|
|
|
|
/// |> yLine(100.0, %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
/// |> extrude(3.14, %)
|
|
|
|
|
/// ```
|
2023-10-05 14:27:48 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "startSketchOn",
|
|
|
|
|
}]
|
2024-09-16 15:10:33 -04:00
|
|
|
|
async fn inner_start_sketch_on(
|
|
|
|
|
data: SketchData,
|
|
|
|
|
tag: Option<FaceTag>,
|
|
|
|
|
exec_state: &mut ExecState,
|
|
|
|
|
args: &Args,
|
|
|
|
|
) -> Result<SketchSurface, KclError> {
|
2024-02-12 18:08:42 -08:00
|
|
|
|
match data {
|
|
|
|
|
SketchData::Plane(plane_data) => {
|
|
|
|
|
let plane = start_sketch_on_plane(plane_data, args).await?;
|
|
|
|
|
Ok(SketchSurface::Plane(plane))
|
|
|
|
|
}
|
|
|
|
|
SketchData::ExtrudeGroup(extrude_group) => {
|
|
|
|
|
let Some(tag) = tag else {
|
|
|
|
|
return Err(KclError::Type(KclErrorDetails {
|
|
|
|
|
message: "Expected a tag for the face to sketch on".to_string(),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
}));
|
|
|
|
|
};
|
2024-09-16 15:10:33 -04:00
|
|
|
|
let face = start_sketch_on_face(extrude_group, tag, exec_state, args).await?;
|
2024-02-12 18:08:42 -08:00
|
|
|
|
Ok(SketchSurface::Face(face))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-13 10:26:09 -08:00
|
|
|
|
async fn start_sketch_on_face(
|
|
|
|
|
extrude_group: Box<ExtrudeGroup>,
|
2024-06-23 23:04:32 -07:00
|
|
|
|
tag: FaceTag,
|
2024-09-16 15:10:33 -04:00
|
|
|
|
exec_state: &mut ExecState,
|
|
|
|
|
args: &Args,
|
2024-02-13 10:26:09 -08:00
|
|
|
|
) -> Result<Box<Face>, KclError> {
|
2024-09-16 15:10:33 -04:00
|
|
|
|
let extrude_plane_id = tag.get_face_id(&extrude_group, exec_state, args, true).await?;
|
2024-02-12 18:08:42 -08:00
|
|
|
|
|
|
|
|
|
Ok(Box::new(Face {
|
2024-06-21 19:54:18 -07:00
|
|
|
|
id: extrude_plane_id,
|
2024-02-12 18:08:42 -08:00
|
|
|
|
value: tag.to_string(),
|
|
|
|
|
// TODO: get this from the extrude plane data.
|
2024-06-21 23:50:30 -07:00
|
|
|
|
x_axis: extrude_group.sketch_group.on.x_axis(),
|
|
|
|
|
y_axis: extrude_group.sketch_group.on.y_axis(),
|
|
|
|
|
z_axis: extrude_group.sketch_group.on.z_axis(),
|
2024-06-23 19:19:24 -07:00
|
|
|
|
extrude_group,
|
2024-02-12 18:08:42 -08:00
|
|
|
|
meta: vec![args.source_range.into()],
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-16 15:10:33 -04:00
|
|
|
|
async fn start_sketch_on_plane(data: PlaneData, args: &Args) -> Result<Box<Plane>, KclError> {
|
2023-10-05 14:27:48 -07:00
|
|
|
|
let mut plane: Plane = data.clone().into();
|
2024-04-15 17:18:32 -07:00
|
|
|
|
|
|
|
|
|
// Get the default planes.
|
|
|
|
|
let default_planes = args.ctx.engine.default_planes(args.source_range).await?;
|
2023-10-05 14:27:48 -07:00
|
|
|
|
|
|
|
|
|
plane.id = match data {
|
2024-04-15 17:18:32 -07:00
|
|
|
|
PlaneData::XY => default_planes.xy,
|
|
|
|
|
PlaneData::XZ => default_planes.xz,
|
|
|
|
|
PlaneData::YZ => default_planes.yz,
|
|
|
|
|
PlaneData::NegXY => default_planes.neg_xy,
|
|
|
|
|
PlaneData::NegXZ => default_planes.neg_xz,
|
|
|
|
|
PlaneData::NegYZ => default_planes.neg_yz,
|
2023-10-05 14:27:48 -07:00
|
|
|
|
PlaneData::Plane {
|
|
|
|
|
origin,
|
|
|
|
|
x_axis,
|
|
|
|
|
y_axis,
|
|
|
|
|
z_axis: _,
|
|
|
|
|
} => {
|
2024-04-15 17:18:32 -07:00
|
|
|
|
// Create the custom plane on the fly.
|
|
|
|
|
let id = uuid::Uuid::new_v4();
|
2024-06-19 13:57:50 -07:00
|
|
|
|
args.batch_modeling_cmd(
|
2023-10-05 14:27:48 -07:00
|
|
|
|
id,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::MakePlane {
|
2023-10-05 14:27:48 -07:00
|
|
|
|
clobber: false,
|
|
|
|
|
origin: (*origin).into(),
|
2024-09-18 17:04:04 -05:00
|
|
|
|
size: LengthUnit(60.0),
|
2023-10-05 14:27:48 -07:00
|
|
|
|
x_axis: (*x_axis).into(),
|
|
|
|
|
y_axis: (*y_axis).into(),
|
2023-10-05 19:54:31 -07:00
|
|
|
|
hide: Some(true),
|
2024-09-18 17:04:04 -05:00
|
|
|
|
}),
|
2023-10-05 14:27:48 -07:00
|
|
|
|
)
|
|
|
|
|
.await?;
|
2024-04-15 17:18:32 -07:00
|
|
|
|
|
2024-02-11 12:59:00 +11:00
|
|
|
|
id
|
|
|
|
|
}
|
2023-10-05 14:27:48 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(Box::new(plane))
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Start a new profile at a given point.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn start_profile_at(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-06-24 14:45:07 -07:00
|
|
|
|
let (start, sketch_surface, tag): ([f64; 2], SketchSurface, Option<TagDeclarator>) =
|
|
|
|
|
args.get_data_and_sketch_surface()?;
|
2023-10-05 14:27:48 -07:00
|
|
|
|
|
2024-09-16 15:10:33 -04:00
|
|
|
|
let sketch_group = inner_start_profile_at(start, sketch_surface, tag, exec_state, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(sketch_group.meta.clone(), sketch_group))
|
2023-10-05 14:27:48 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Start a new profile at a given point.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> line([10, 0], %)
|
|
|
|
|
/// |> line([0, 10], %)
|
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(5, exampleSketch)
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// const exampleSketch = startSketchOn('-XZ')
|
|
|
|
|
/// |> startProfileAt([10, 10], %)
|
|
|
|
|
/// |> line([10, 0], %)
|
|
|
|
|
/// |> line([0, 10], %)
|
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(5, exampleSketch)
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// const exampleSketch = startSketchOn('-XZ')
|
|
|
|
|
/// |> startProfileAt([-10, 23], %)
|
|
|
|
|
/// |> line([10, 0], %)
|
|
|
|
|
/// |> line([0, 10], %)
|
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(5, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-10-05 14:27:48 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "startProfileAt",
|
|
|
|
|
}]
|
2024-03-13 17:16:57 -07:00
|
|
|
|
pub(crate) async fn inner_start_profile_at(
|
2024-03-15 17:03:42 -04:00
|
|
|
|
to: [f64; 2],
|
2024-02-12 18:08:42 -08:00
|
|
|
|
sketch_surface: SketchSurface,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2024-09-16 15:10:33 -04:00
|
|
|
|
exec_state: &mut ExecState,
|
2024-02-12 18:08:42 -08:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-06-23 19:19:24 -07:00
|
|
|
|
if let SketchSurface::Face(face) = &sketch_surface {
|
2024-06-22 14:31:37 -07:00
|
|
|
|
// Flush the batch for our fillets/chamfers if there are any.
|
|
|
|
|
// If we do not do these for sketch on face, things will fail with face does not exist.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
args.flush_batch_for_extrude_group_set(exec_state, face.extrude_group.clone().into())
|
2024-06-23 19:19:24 -07:00
|
|
|
|
.await?;
|
2024-06-22 14:31:37 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-21 19:54:18 -07:00
|
|
|
|
// Enter sketch mode on the surface.
|
|
|
|
|
// We call this here so you can reuse the sketch surface for multiple sketches.
|
|
|
|
|
let id = uuid::Uuid::new_v4();
|
|
|
|
|
args.batch_modeling_cmd(
|
|
|
|
|
id,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::EnableSketchMode {
|
2024-06-21 19:54:18 -07:00
|
|
|
|
animated: false,
|
|
|
|
|
ortho: false,
|
|
|
|
|
entity_id: sketch_surface.id(),
|
|
|
|
|
adjust_camera: false,
|
|
|
|
|
planar_normal: if let SketchSurface::Plane(plane) = &sketch_surface {
|
|
|
|
|
// We pass in the normal for the plane here.
|
2024-09-04 23:27:12 -05:00
|
|
|
|
Some(plane.z_axis.into())
|
2024-06-21 19:54:18 -07:00
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
},
|
2024-09-18 17:04:04 -05:00
|
|
|
|
}),
|
2024-06-21 19:54:18 -07:00
|
|
|
|
)
|
|
|
|
|
.await?;
|
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
|
let id = uuid::Uuid::new_v4();
|
|
|
|
|
let path_id = uuid::Uuid::new_v4();
|
|
|
|
|
|
2024-09-18 17:04:04 -05:00
|
|
|
|
args.batch_modeling_cmd(path_id, ModelingCmd::from(mcmd::StartPath {}))
|
|
|
|
|
.await?;
|
2024-06-19 13:57:50 -07:00
|
|
|
|
args.batch_modeling_cmd(
|
2023-08-24 15:34:51 -07:00
|
|
|
|
id,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::MovePathPen {
|
|
|
|
|
path: path_id.into(),
|
|
|
|
|
to: KPoint2d::from(to).with_z(0.0).map(LengthUnit),
|
|
|
|
|
}),
|
2023-09-20 18:27:08 -07:00
|
|
|
|
)
|
|
|
|
|
.await?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
|
|
|
|
let current_path = BasePath {
|
|
|
|
|
from: to,
|
|
|
|
|
to,
|
2024-07-05 16:53:13 -07:00
|
|
|
|
tag: tag.clone(),
|
2023-08-24 15:34:51 -07:00
|
|
|
|
geo_meta: GeoMeta {
|
|
|
|
|
id,
|
|
|
|
|
metadata: args.source_range.into(),
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let sketch_group = SketchGroup {
|
|
|
|
|
id: path_id,
|
2024-07-29 21:30:25 -07:00
|
|
|
|
original_id: path_id,
|
2024-02-16 16:42:01 -08:00
|
|
|
|
on: sketch_surface.clone(),
|
2023-08-24 15:34:51 -07:00
|
|
|
|
value: vec![],
|
|
|
|
|
meta: vec![args.source_range.into()],
|
2024-07-05 16:53:13 -07:00
|
|
|
|
tags: if let Some(tag) = &tag {
|
2024-07-27 22:56:46 -07:00
|
|
|
|
let mut tag_identifier: TagIdentifier = tag.into();
|
|
|
|
|
tag_identifier.info = Some(TagEngineInfo {
|
|
|
|
|
id: current_path.geo_meta.id,
|
|
|
|
|
sketch_group: path_id,
|
2024-07-28 00:30:04 -07:00
|
|
|
|
path: Some(current_path.clone()),
|
2024-07-27 22:56:46 -07:00
|
|
|
|
surface: None,
|
|
|
|
|
});
|
|
|
|
|
HashMap::from([(tag.name.to_string(), tag_identifier)])
|
2024-07-05 16:53:13 -07:00
|
|
|
|
} else {
|
|
|
|
|
Default::default()
|
|
|
|
|
},
|
2024-07-27 22:56:46 -07:00
|
|
|
|
start: current_path,
|
2023-08-24 15:34:51 -07:00
|
|
|
|
};
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(sketch_group)
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-21 03:44:02 -04:00
|
|
|
|
/// Returns the X component of the sketch profile start point.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn profile_start_x(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let sketch_group: SketchGroup = args.get_sketch_group()?;
|
2024-05-21 03:44:02 -04:00
|
|
|
|
let x = inner_profile_start_x(sketch_group)?;
|
|
|
|
|
args.make_user_val_from_f64(x)
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Extract the provided 2-dimensional sketch group's profile's origin's 'x'
|
|
|
|
|
/// value.
|
|
|
|
|
///
|
2024-05-21 03:44:02 -04:00
|
|
|
|
/// ```no_run
|
|
|
|
|
/// const sketch001 = startSketchOn('XY')
|
|
|
|
|
/// |> startProfileAt([5, 2], %)
|
|
|
|
|
/// |> angledLine([-26.6, 50], %)
|
|
|
|
|
/// |> angledLine([90, 50], %)
|
|
|
|
|
/// |> angledLineToX({ angle: 30, to: profileStartX(%) }, %)
|
|
|
|
|
/// ```
|
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "profileStartX"
|
|
|
|
|
}]
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
pub(crate) fn inner_profile_start_x(sketch_group: SketchGroup) -> Result<f64, KclError> {
|
2024-05-21 03:44:02 -04:00
|
|
|
|
Ok(sketch_group.start.to[0])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the Y component of the sketch profile start point.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn profile_start_y(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let sketch_group: SketchGroup = args.get_sketch_group()?;
|
2024-05-21 03:44:02 -04:00
|
|
|
|
let x = inner_profile_start_y(sketch_group)?;
|
|
|
|
|
args.make_user_val_from_f64(x)
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Extract the provided 2-dimensional sketch group's profile's origin's 'y'
|
|
|
|
|
/// value.
|
|
|
|
|
///
|
2024-05-21 03:44:02 -04:00
|
|
|
|
/// ```no_run
|
|
|
|
|
/// const sketch001 = startSketchOn('XY')
|
|
|
|
|
/// |> startProfileAt([5, 2], %)
|
|
|
|
|
/// |> angledLine({ angle: -60, length: 14 }, %)
|
|
|
|
|
/// |> angledLineToY({ angle: 30, to: profileStartY(%) }, %)
|
|
|
|
|
/// ```
|
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "profileStartY"
|
|
|
|
|
}]
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
pub(crate) fn inner_profile_start_y(sketch_group: SketchGroup) -> Result<f64, KclError> {
|
2024-05-21 03:44:02 -04:00
|
|
|
|
Ok(sketch_group.start.to[1])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the sketch profile start point.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn profile_start(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let sketch_group: SketchGroup = args.get_sketch_group()?;
|
2024-05-21 03:44:02 -04:00
|
|
|
|
let point = inner_profile_start(sketch_group)?;
|
2024-08-12 16:53:24 -05:00
|
|
|
|
Ok(KclValue::UserVal(UserVal {
|
2024-05-21 03:44:02 -04:00
|
|
|
|
value: serde_json::to_value(point).map_err(|e| {
|
|
|
|
|
KclError::Type(KclErrorDetails {
|
|
|
|
|
message: format!("Failed to convert point to json: {}", e),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
})
|
|
|
|
|
})?,
|
|
|
|
|
meta: Default::default(),
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Extract the provided 2-dimensional sketch group's profile's origin
|
|
|
|
|
/// value.
|
|
|
|
|
///
|
2024-05-21 03:44:02 -04:00
|
|
|
|
/// ```no_run
|
|
|
|
|
/// const sketch001 = startSketchOn('XY')
|
|
|
|
|
/// |> startProfileAt([5, 2], %)
|
2024-07-27 17:59:41 -07:00
|
|
|
|
/// |> angledLine({ angle: 120, length: 50 }, %, $seg01)
|
2024-07-27 22:56:46 -07:00
|
|
|
|
/// |> angledLine({ angle: segAng(seg01) + 120, length: 50 }, %)
|
2024-05-21 03:44:02 -04:00
|
|
|
|
/// |> lineTo(profileStart(%), %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
/// |> extrude(20, %)
|
|
|
|
|
/// ```
|
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "profileStart"
|
|
|
|
|
}]
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
pub(crate) fn inner_profile_start(sketch_group: SketchGroup) -> Result<[f64; 2], KclError> {
|
2024-05-21 03:44:02 -04:00
|
|
|
|
Ok(sketch_group.start.to)
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
|
/// Close the current sketch.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn close(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (sketch_group, tag): (SketchGroup, Option<TagDeclarator>) = args.get_sketch_group_and_optional_tag()?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
|
2024-03-07 12:35:56 -08:00
|
|
|
|
let new_sketch_group = inner_close(sketch_group, tag, args).await?;
|
2023-08-25 13:41:04 -07:00
|
|
|
|
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-25 13:41:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Construct a line segment from the current origin back to the profile's
|
|
|
|
|
/// origin, ensuring the resulting 2-dimensional sketch is not open-ended.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// startSketchOn('XZ')
|
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> line([10, 10], %)
|
|
|
|
|
/// |> line([10, 0], %)
|
|
|
|
|
/// |> close(%)
|
2024-04-25 02:31:18 -07:00
|
|
|
|
/// |> extrude(10, %)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('-XZ')
|
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> line([10, 0], %)
|
|
|
|
|
/// |> line([0, 10], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-25 13:41:04 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "close",
|
|
|
|
|
}]
|
2024-03-13 17:16:57 -07:00
|
|
|
|
pub(crate) async fn inner_close(
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2024-03-07 12:35:56 -08:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from = sketch_group.current_pen_position()?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
let to: Point2d = sketch_group.start.from.into();
|
|
|
|
|
|
|
|
|
|
let id = uuid::Uuid::new_v4();
|
|
|
|
|
|
2024-06-19 13:57:50 -07:00
|
|
|
|
args.batch_modeling_cmd(
|
2023-08-24 15:34:51 -07:00
|
|
|
|
id,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::ClosePath {
|
2023-08-24 15:34:51 -07:00
|
|
|
|
path_id: sketch_group.id,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
}),
|
2023-09-20 18:27:08 -07:00
|
|
|
|
)
|
|
|
|
|
.await?;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2024-02-16 16:42:01 -08:00
|
|
|
|
// If we are sketching on a plane we can close the sketch group now.
|
|
|
|
|
if let SketchSurface::Plane(_) = sketch_group.on {
|
2023-10-05 14:27:48 -07:00
|
|
|
|
// We were on a plane, disable the sketch mode.
|
2024-09-18 17:04:04 -05:00
|
|
|
|
args.batch_modeling_cmd(
|
|
|
|
|
uuid::Uuid::new_v4(),
|
|
|
|
|
ModelingCmd::SketchModeDisable(mcmd::SketchModeDisable {}),
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
2023-10-05 14:27:48 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-27 22:56:46 -07:00
|
|
|
|
let current_path = Path::ToPoint {
|
2023-08-24 15:34:51 -07:00
|
|
|
|
base: BasePath {
|
|
|
|
|
from: from.into(),
|
|
|
|
|
to: to.into(),
|
2024-07-27 22:56:46 -07:00
|
|
|
|
tag: tag.clone(),
|
2023-08-24 15:34:51 -07:00
|
|
|
|
geo_meta: GeoMeta {
|
|
|
|
|
id,
|
|
|
|
|
metadata: args.source_range.into(),
|
|
|
|
|
},
|
|
|
|
|
},
|
2024-07-27 22:56:46 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut new_sketch_group = sketch_group.clone();
|
|
|
|
|
if let Some(tag) = &tag {
|
|
|
|
|
new_sketch_group.add_tag(tag, ¤t_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new_sketch_group.value.push(current_path);
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
2023-08-25 13:41:04 -07:00
|
|
|
|
Ok(new_sketch_group)
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-31 22:19:23 -07:00
|
|
|
|
/// Data to draw an arc.
|
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
|
|
|
|
#[ts(export)]
|
|
|
|
|
#[serde(rename_all = "camelCase", untagged)]
|
|
|
|
|
pub enum ArcData {
|
2024-03-07 15:35:26 -08:00
|
|
|
|
/// Angles and radius with an optional tag.
|
2023-08-31 22:19:23 -07:00
|
|
|
|
AnglesAndRadius {
|
|
|
|
|
/// The start angle.
|
2024-07-29 13:18:55 -07:00
|
|
|
|
#[serde(rename = "angleStart", alias = "angle_start")]
|
2024-09-26 16:33:49 -07:00
|
|
|
|
#[schemars(range(min = -360.0, max = 360.0))]
|
2023-08-31 22:19:23 -07:00
|
|
|
|
angle_start: f64,
|
|
|
|
|
/// The end angle.
|
2024-07-29 13:18:55 -07:00
|
|
|
|
#[serde(rename = "angleEnd", alias = "angle_end")]
|
2024-09-26 16:33:49 -07:00
|
|
|
|
#[schemars(range(min = -360.0, max = 360.0))]
|
2023-08-31 22:19:23 -07:00
|
|
|
|
angle_end: f64,
|
|
|
|
|
/// The radius.
|
|
|
|
|
radius: f64,
|
|
|
|
|
},
|
2024-03-07 15:35:26 -08:00
|
|
|
|
/// Center, to and radius with an optional tag.
|
2023-08-31 22:19:23 -07:00
|
|
|
|
CenterToRadius {
|
|
|
|
|
/// The center.
|
|
|
|
|
center: [f64; 2],
|
|
|
|
|
/// The to point.
|
|
|
|
|
to: [f64; 2],
|
|
|
|
|
/// The radius.
|
|
|
|
|
radius: f64,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Draw an arc.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn arc(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (data, sketch_group, tag): (ArcData, SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-31 22:19:23 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_arc(data, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-31 22:19:23 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Starting at the current sketch's origin, draw a curved line segment along
|
|
|
|
|
/// an imaginary circle of the specified radius.
|
|
|
|
|
///
|
|
|
|
|
/// The arc is constructed such that the current position of the sketch is
|
|
|
|
|
/// placed along an imaginary circle of the specified radius, at angleStart
|
|
|
|
|
/// degrees. The resulting arc is the segment of the imaginary circle from
|
|
|
|
|
/// that origin point to angleEnd, radius away from the center of the imaginary
|
|
|
|
|
/// circle.
|
|
|
|
|
///
|
|
|
|
|
/// Unless this makes a lot of sense and feels like what you're looking
|
|
|
|
|
/// for to construct your shape, you're likely looking for tangentialArc.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> line([10, 0], %)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// |> arc({
|
2024-07-29 13:18:55 -07:00
|
|
|
|
/// angleStart: 0,
|
|
|
|
|
/// angleEnd: 280,
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// radius: 16
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-31 22:19:23 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "arc",
|
|
|
|
|
}]
|
2024-03-13 17:16:57 -07:00
|
|
|
|
pub(crate) async fn inner_arc(
|
|
|
|
|
data: ArcData,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2024-03-13 17:16:57 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from: Point2d = sketch_group.current_pen_position()?;
|
2023-08-31 22:19:23 -07:00
|
|
|
|
|
|
|
|
|
let (center, angle_start, angle_end, radius, end) = match &data {
|
|
|
|
|
ArcData::AnglesAndRadius {
|
|
|
|
|
angle_start,
|
|
|
|
|
angle_end,
|
|
|
|
|
radius,
|
|
|
|
|
} => {
|
2023-09-14 15:51:26 -06:00
|
|
|
|
let a_start = Angle::from_degrees(*angle_start);
|
|
|
|
|
let a_end = Angle::from_degrees(*angle_end);
|
|
|
|
|
let (center, end) = arc_center_and_end(from, a_start, a_end, *radius);
|
|
|
|
|
(center, a_start, a_end, *radius, end)
|
2023-08-31 22:19:23 -07:00
|
|
|
|
}
|
2024-03-15 17:03:42 -04:00
|
|
|
|
ArcData::CenterToRadius { center, to, radius } => {
|
2023-09-14 15:51:26 -06:00
|
|
|
|
let (angle_start, angle_end) = arc_angles(from, center.into(), to.into(), *radius, args.source_range)?;
|
2023-08-31 22:19:23 -07:00
|
|
|
|
(center.into(), angle_start, angle_end, *radius, to.into())
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-28 16:09:54 -07:00
|
|
|
|
if angle_start == angle_end {
|
|
|
|
|
return Err(KclError::Type(KclErrorDetails {
|
|
|
|
|
message: "Arc start and end angles must be different".to_string(),
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-31 22:19:23 -07:00
|
|
|
|
let id = uuid::Uuid::new_v4();
|
|
|
|
|
|
2024-06-19 13:57:50 -07:00
|
|
|
|
args.batch_modeling_cmd(
|
2023-08-31 22:19:23 -07:00
|
|
|
|
id,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::ExtendPath {
|
|
|
|
|
path: sketch_group.id.into(),
|
|
|
|
|
segment: PathSegment::Arc {
|
2024-01-02 13:13:41 -06:00
|
|
|
|
start: angle_start,
|
|
|
|
|
end: angle_end,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
center: KPoint2d::from(center).map(LengthUnit),
|
|
|
|
|
radius: LengthUnit(radius),
|
2023-09-20 17:36:26 -07:00
|
|
|
|
relative: false,
|
2023-08-31 22:19:23 -07:00
|
|
|
|
},
|
2024-09-18 17:04:04 -05:00
|
|
|
|
}),
|
2023-09-20 18:27:08 -07:00
|
|
|
|
)
|
|
|
|
|
.await?;
|
2023-09-20 17:36:26 -07:00
|
|
|
|
|
2023-08-31 22:19:23 -07:00
|
|
|
|
let current_path = Path::ToPoint {
|
|
|
|
|
base: BasePath {
|
|
|
|
|
from: from.into(),
|
|
|
|
|
to: end.into(),
|
2024-07-27 22:56:46 -07:00
|
|
|
|
tag: tag.clone(),
|
2023-08-31 22:19:23 -07:00
|
|
|
|
geo_meta: GeoMeta {
|
|
|
|
|
id,
|
|
|
|
|
metadata: args.source_range.into(),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-27 22:56:46 -07:00
|
|
|
|
let mut new_sketch_group = sketch_group.clone();
|
|
|
|
|
if let Some(tag) = &tag {
|
|
|
|
|
new_sketch_group.add_tag(tag, ¤t_path);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-31 22:19:23 -07:00
|
|
|
|
new_sketch_group.value.push(current_path);
|
|
|
|
|
|
|
|
|
|
Ok(new_sketch_group)
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-12 11:50:54 -05:00
|
|
|
|
/// Data to draw a tangential arc.
|
2023-09-29 14:41:14 -07:00
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, ts_rs::TS)]
|
|
|
|
|
#[ts(export)]
|
|
|
|
|
#[serde(rename_all = "camelCase", untagged)]
|
2023-10-12 11:50:54 -05:00
|
|
|
|
pub enum TangentialArcData {
|
2023-09-29 14:41:14 -07:00
|
|
|
|
RadiusAndOffset {
|
|
|
|
|
/// Radius of the arc.
|
|
|
|
|
/// Not to be confused with Raiders of the Lost Ark.
|
|
|
|
|
radius: f64,
|
|
|
|
|
/// Offset of the arc, in degrees.
|
|
|
|
|
offset: f64,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-12 11:50:54 -05:00
|
|
|
|
/// Draw a tangential arc.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn tangential_arc(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (data, sketch_group, tag): (TangentialArcData, SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-09-29 14:41:14 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_tangential_arc(data, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-09-29 14:41:14 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Starting at the current sketch's origin, draw a curved line segment along
|
|
|
|
|
/// some part of an imaginary circle of the specified radius.
|
|
|
|
|
///
|
|
|
|
|
/// The arc is constructed such that the last line segment is placed tangent
|
|
|
|
|
/// to the imaginary circle of the specified radius. The resulting arc is the
|
|
|
|
|
/// segment of the imaginary circle from that tangent point for 'offset'
|
|
|
|
|
/// degrees along the imaginary circle.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-03-15 17:03:42 -04:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> angledLine({
|
|
|
|
|
/// angle: 60,
|
|
|
|
|
/// length: 10,
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> tangentialArc({ radius: 10, offset: -120 }, %)
|
|
|
|
|
/// |> angledLine({
|
|
|
|
|
/// angle: -60,
|
|
|
|
|
/// length: 10,
|
|
|
|
|
/// }, %)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// |> close(%)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-09-29 14:41:14 -07:00
|
|
|
|
#[stdlib {
|
2023-10-12 11:50:54 -05:00
|
|
|
|
name = "tangentialArc",
|
2023-09-29 14:41:14 -07:00
|
|
|
|
}]
|
2023-10-12 11:50:54 -05:00
|
|
|
|
async fn inner_tangential_arc(
|
|
|
|
|
data: TangentialArcData,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-29 14:41:14 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from: Point2d = sketch_group.current_pen_position()?;
|
2024-08-07 18:35:41 -05:00
|
|
|
|
// next set of lines is some undocumented voodoo from get_tangential_arc_to_info
|
|
|
|
|
let tangent_info = sketch_group.get_tangential_info_from_paths(); //this function desperately needs some documentation
|
|
|
|
|
let tan_previous_point = if tangent_info.is_center {
|
|
|
|
|
get_tangent_point_from_previous_arc(tangent_info.center_or_tangent_point, tangent_info.ccw, from.into())
|
|
|
|
|
} else {
|
|
|
|
|
tangent_info.center_or_tangent_point
|
|
|
|
|
};
|
2023-09-29 14:41:14 -07:00
|
|
|
|
|
|
|
|
|
let id = uuid::Uuid::new_v4();
|
|
|
|
|
|
2024-08-07 18:35:41 -05:00
|
|
|
|
let (center, to, ccw) = match data {
|
2023-10-12 11:50:54 -05:00
|
|
|
|
TangentialArcData::RadiusAndOffset { radius, offset } => {
|
2024-08-07 18:35:41 -05:00
|
|
|
|
// KCL stdlib types use degrees.
|
|
|
|
|
let offset = Angle::from_degrees(offset);
|
|
|
|
|
|
2023-09-29 14:41:14 -07:00
|
|
|
|
// Calculate the end point from the angle and radius.
|
2024-08-07 18:35:41 -05:00
|
|
|
|
// atan2 outputs radians.
|
|
|
|
|
let previous_end_tangent = Angle::from_radians(f64::atan2(
|
|
|
|
|
from.y - tan_previous_point[1],
|
|
|
|
|
from.x - tan_previous_point[0],
|
|
|
|
|
));
|
|
|
|
|
// make sure the arc center is on the correct side to guarantee deterministic behavior
|
|
|
|
|
// note the engine automatically rejects an offset of zero, if we want to flag that at KCL too to avoid engine errors
|
2024-09-18 17:04:04 -05:00
|
|
|
|
let ccw = offset.to_degrees() > 0.0;
|
2024-08-07 18:35:41 -05:00
|
|
|
|
let tangent_to_arc_start_angle = if ccw {
|
|
|
|
|
// CCW turn
|
|
|
|
|
Angle::from_degrees(-90.0)
|
|
|
|
|
} else {
|
|
|
|
|
// CW turn
|
|
|
|
|
Angle::from_degrees(90.0)
|
|
|
|
|
};
|
|
|
|
|
// may need some logic and / or modulo on the various angle values to prevent them from going "backwards"
|
|
|
|
|
// but the above logic *should* capture that behavior
|
|
|
|
|
let start_angle = previous_end_tangent + tangent_to_arc_start_angle;
|
|
|
|
|
let end_angle = start_angle + offset;
|
|
|
|
|
let (center, to) = arc_center_and_end(from, start_angle, end_angle, radius);
|
2023-09-29 14:41:14 -07:00
|
|
|
|
|
2024-06-19 13:57:50 -07:00
|
|
|
|
args.batch_modeling_cmd(
|
2023-09-29 14:41:14 -07:00
|
|
|
|
id,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::ExtendPath {
|
|
|
|
|
path: sketch_group.id.into(),
|
|
|
|
|
segment: PathSegment::TangentialArc {
|
|
|
|
|
radius: LengthUnit(radius),
|
|
|
|
|
offset,
|
|
|
|
|
},
|
|
|
|
|
}),
|
2023-09-29 14:41:14 -07:00
|
|
|
|
)
|
|
|
|
|
.await?;
|
2024-08-07 18:35:41 -05:00
|
|
|
|
(center, to.into(), ccw)
|
2023-09-29 14:41:14 -07:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-02-22 19:07:17 -08:00
|
|
|
|
let current_path = Path::TangentialArc {
|
2024-08-07 18:35:41 -05:00
|
|
|
|
ccw,
|
|
|
|
|
center: center.into(),
|
2023-09-29 14:41:14 -07:00
|
|
|
|
base: BasePath {
|
|
|
|
|
from: from.into(),
|
|
|
|
|
to,
|
2024-07-27 22:56:46 -07:00
|
|
|
|
tag: tag.clone(),
|
2023-09-29 14:41:14 -07:00
|
|
|
|
geo_meta: GeoMeta {
|
|
|
|
|
id,
|
|
|
|
|
metadata: args.source_range.into(),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-27 22:56:46 -07:00
|
|
|
|
let mut new_sketch_group = sketch_group.clone();
|
|
|
|
|
if let Some(tag) = &tag {
|
|
|
|
|
new_sketch_group.add_tag(tag, ¤t_path);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-29 14:41:14 -07:00
|
|
|
|
new_sketch_group.value.push(current_path);
|
|
|
|
|
|
|
|
|
|
Ok(new_sketch_group)
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-24 10:30:14 -07:00
|
|
|
|
fn tan_arc_to(sketch_group: &SketchGroup, to: &[f64; 2]) -> ModelingCmd {
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::ExtendPath {
|
|
|
|
|
path: sketch_group.id.into(),
|
|
|
|
|
segment: PathSegment::TangentialArcTo {
|
2023-10-24 10:30:14 -07:00
|
|
|
|
angle_snap_increment: None,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
to: KPoint2d::from(*to).with_z(0.0).map(LengthUnit),
|
2023-10-24 10:30:14 -07:00
|
|
|
|
},
|
2024-09-18 17:04:04 -05:00
|
|
|
|
})
|
2023-10-24 10:30:14 -07:00
|
|
|
|
}
|
|
|
|
|
|
2023-10-12 11:50:54 -05:00
|
|
|
|
/// Draw a tangential arc to a specific point.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn tangential_arc_to(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-08-30 13:44:20 -05:00
|
|
|
|
let (to, sketch_group, tag): ([f64; 2], SketchGroup, Option<TagDeclarator>) =
|
|
|
|
|
super::args::FromArgs::from_args(&args, 0)?;
|
2023-09-29 14:41:14 -07:00
|
|
|
|
|
Remove just one enum (#1096)
# Problem
This is my proposal for fixing #1107 . I've only done it for one stdlib function, `tangentialArcTo` -- if y'all like it, I'll apply this idea to the rest of the stdlib.
Previously, if users want to put a tag on the arc, the function's parameters change type.
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is object
tangentialArcTo({to: [x, y], tag: "myTag"}, %)
```
# Solution
My proposal in #1006 is that KCL should have optional values. This means we can change the stdlib `tangentialArcTo` function to use them. In this PR, the calls are now like
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is array still, but we now pass a tag at the end.
tangentialArcTo([x, y], %, "myTag")
```
This adds an "option" type to KCL typesystem, but it's not really revealed to users (no KCL types are revealed to users right now, they write untyped code and only interact with types when they get type errors upon executing programs). Also adds a None type, which is the default case of the Optional enum.
2023-12-18 23:49:32 -06:00
|
|
|
|
let new_sketch_group = inner_tangential_arc_to(to, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-09-29 14:41:14 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-30 13:44:20 -05:00
|
|
|
|
/// Draw a tangential arc to point some distance away..
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn tangential_arc_to_relative(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2024-08-30 13:44:20 -05:00
|
|
|
|
let (delta, sketch_group, tag): ([f64; 2], SketchGroup, Option<TagDeclarator>) =
|
|
|
|
|
super::args::FromArgs::from_args(&args, 0)?;
|
|
|
|
|
|
|
|
|
|
let new_sketch_group = inner_tangential_arc_to_relative(delta, sketch_group, tag, args).await?;
|
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Starting at the current sketch's origin, draw a curved line segment along
|
|
|
|
|
/// some part of an imaginary circle until it reaches the desired (x, y)
|
|
|
|
|
/// coordinates.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> angledLine({
|
|
|
|
|
/// angle: 60,
|
|
|
|
|
/// length: 10,
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> tangentialArcTo([15, 15], %)
|
|
|
|
|
/// |> line([10, -15], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-09-29 14:41:14 -07:00
|
|
|
|
#[stdlib {
|
2023-10-12 11:50:54 -05:00
|
|
|
|
name = "tangentialArcTo",
|
2023-09-29 14:41:14 -07:00
|
|
|
|
}]
|
2023-10-12 11:50:54 -05:00
|
|
|
|
async fn inner_tangential_arc_to(
|
Remove just one enum (#1096)
# Problem
This is my proposal for fixing #1107 . I've only done it for one stdlib function, `tangentialArcTo` -- if y'all like it, I'll apply this idea to the rest of the stdlib.
Previously, if users want to put a tag on the arc, the function's parameters change type.
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is object
tangentialArcTo({to: [x, y], tag: "myTag"}, %)
```
# Solution
My proposal in #1006 is that KCL should have optional values. This means we can change the stdlib `tangentialArcTo` function to use them. In this PR, the calls are now like
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is array still, but we now pass a tag at the end.
tangentialArcTo([x, y], %, "myTag")
```
This adds an "option" type to KCL typesystem, but it's not really revealed to users (no KCL types are revealed to users right now, they write untyped code and only interact with types when they get type errors upon executing programs). Also adds a None type, which is the default case of the Optional enum.
2023-12-18 23:49:32 -06:00
|
|
|
|
to: [f64; 2],
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-29 14:41:14 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from: Point2d = sketch_group.current_pen_position()?;
|
2024-02-11 12:59:00 +11:00
|
|
|
|
let tangent_info = sketch_group.get_tangential_info_from_paths();
|
|
|
|
|
let tan_previous_point = if tangent_info.is_center {
|
|
|
|
|
get_tangent_point_from_previous_arc(tangent_info.center_or_tangent_point, tangent_info.ccw, from.into())
|
|
|
|
|
} else {
|
|
|
|
|
tangent_info.center_or_tangent_point
|
|
|
|
|
};
|
Remove just one enum (#1096)
# Problem
This is my proposal for fixing #1107 . I've only done it for one stdlib function, `tangentialArcTo` -- if y'all like it, I'll apply this idea to the rest of the stdlib.
Previously, if users want to put a tag on the arc, the function's parameters change type.
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is object
tangentialArcTo({to: [x, y], tag: "myTag"}, %)
```
# Solution
My proposal in #1006 is that KCL should have optional values. This means we can change the stdlib `tangentialArcTo` function to use them. In this PR, the calls are now like
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is array still, but we now pass a tag at the end.
tangentialArcTo([x, y], %, "myTag")
```
This adds an "option" type to KCL typesystem, but it's not really revealed to users (no KCL types are revealed to users right now, they write untyped code and only interact with types when they get type errors upon executing programs). Also adds a None type, which is the default case of the Optional enum.
2023-12-18 23:49:32 -06:00
|
|
|
|
let [to_x, to_y] = to;
|
2024-02-11 12:59:00 +11:00
|
|
|
|
let result = get_tangential_arc_to_info(TangentialArcInfoInput {
|
|
|
|
|
arc_start_point: [from.x, from.y],
|
|
|
|
|
arc_end_point: to,
|
|
|
|
|
tan_previous_point,
|
|
|
|
|
obtuse: true,
|
|
|
|
|
});
|
2023-09-29 14:41:14 -07:00
|
|
|
|
|
Remove just one enum (#1096)
# Problem
This is my proposal for fixing #1107 . I've only done it for one stdlib function, `tangentialArcTo` -- if y'all like it, I'll apply this idea to the rest of the stdlib.
Previously, if users want to put a tag on the arc, the function's parameters change type.
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is object
tangentialArcTo({to: [x, y], tag: "myTag"}, %)
```
# Solution
My proposal in #1006 is that KCL should have optional values. This means we can change the stdlib `tangentialArcTo` function to use them. In this PR, the calls are now like
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is array still, but we now pass a tag at the end.
tangentialArcTo([x, y], %, "myTag")
```
This adds an "option" type to KCL typesystem, but it's not really revealed to users (no KCL types are revealed to users right now, they write untyped code and only interact with types when they get type errors upon executing programs). Also adds a None type, which is the default case of the Optional enum.
2023-12-18 23:49:32 -06:00
|
|
|
|
let delta = [to_x - from.x, to_y - from.y];
|
2023-09-29 14:41:14 -07:00
|
|
|
|
let id = uuid::Uuid::new_v4();
|
2024-06-19 13:57:50 -07:00
|
|
|
|
args.batch_modeling_cmd(id, tan_arc_to(&sketch_group, &delta)).await?;
|
2023-09-29 14:41:14 -07:00
|
|
|
|
|
2024-02-11 12:59:00 +11:00
|
|
|
|
let current_path = Path::TangentialArcTo {
|
2023-09-29 14:41:14 -07:00
|
|
|
|
base: BasePath {
|
|
|
|
|
from: from.into(),
|
Remove just one enum (#1096)
# Problem
This is my proposal for fixing #1107 . I've only done it for one stdlib function, `tangentialArcTo` -- if y'all like it, I'll apply this idea to the rest of the stdlib.
Previously, if users want to put a tag on the arc, the function's parameters change type.
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is object
tangentialArcTo({to: [x, y], tag: "myTag"}, %)
```
# Solution
My proposal in #1006 is that KCL should have optional values. This means we can change the stdlib `tangentialArcTo` function to use them. In this PR, the calls are now like
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is array still, but we now pass a tag at the end.
tangentialArcTo([x, y], %, "myTag")
```
This adds an "option" type to KCL typesystem, but it's not really revealed to users (no KCL types are revealed to users right now, they write untyped code and only interact with types when they get type errors upon executing programs). Also adds a None type, which is the default case of the Optional enum.
2023-12-18 23:49:32 -06:00
|
|
|
|
to,
|
2024-07-27 22:56:46 -07:00
|
|
|
|
tag: tag.clone(),
|
2023-09-29 14:41:14 -07:00
|
|
|
|
geo_meta: GeoMeta {
|
|
|
|
|
id,
|
|
|
|
|
metadata: args.source_range.into(),
|
|
|
|
|
},
|
|
|
|
|
},
|
2024-02-11 12:59:00 +11:00
|
|
|
|
center: result.center,
|
|
|
|
|
ccw: result.ccw > 0,
|
2023-09-29 14:41:14 -07:00
|
|
|
|
};
|
|
|
|
|
|
2024-07-27 22:56:46 -07:00
|
|
|
|
let mut new_sketch_group = sketch_group.clone();
|
|
|
|
|
if let Some(tag) = &tag {
|
|
|
|
|
new_sketch_group.add_tag(tag, ¤t_path);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-29 14:41:14 -07:00
|
|
|
|
new_sketch_group.value.push(current_path);
|
|
|
|
|
|
|
|
|
|
Ok(new_sketch_group)
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-30 13:44:20 -05:00
|
|
|
|
/// Starting at the current sketch's origin, draw a curved line segment along
|
|
|
|
|
/// some part of an imaginary circle until it reaches a point the given (x, y)
|
|
|
|
|
/// distance away.
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> angledLine({
|
|
|
|
|
/// angle: 45,
|
|
|
|
|
/// length: 10,
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> tangentialArcToRelative([0, -10], %)
|
|
|
|
|
/// |> line([-10, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
|
|
|
|
/// ```
|
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "tangentialArcToRelative",
|
|
|
|
|
}]
|
|
|
|
|
async fn inner_tangential_arc_to_relative(
|
|
|
|
|
delta: [f64; 2],
|
|
|
|
|
sketch_group: SketchGroup,
|
|
|
|
|
tag: Option<TagDeclarator>,
|
|
|
|
|
args: Args,
|
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
|
|
|
|
let from: Point2d = sketch_group.current_pen_position()?;
|
|
|
|
|
let tangent_info = sketch_group.get_tangential_info_from_paths();
|
|
|
|
|
let tan_previous_point = if tangent_info.is_center {
|
|
|
|
|
get_tangent_point_from_previous_arc(tangent_info.center_or_tangent_point, tangent_info.ccw, from.into())
|
|
|
|
|
} else {
|
|
|
|
|
tangent_info.center_or_tangent_point
|
|
|
|
|
};
|
|
|
|
|
let [dx, dy] = delta;
|
|
|
|
|
let result = get_tangential_arc_to_info(TangentialArcInfoInput {
|
|
|
|
|
arc_start_point: [from.x, from.y],
|
|
|
|
|
arc_end_point: [from.x + dx, from.y + dy],
|
|
|
|
|
tan_previous_point,
|
|
|
|
|
obtuse: true,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if result.center[0].is_infinite() {
|
|
|
|
|
return Err(KclError::Semantic(KclErrorDetails {
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
message:
|
|
|
|
|
"could not sketch tangential arc, because its center would be infinitely far away in the X direction"
|
|
|
|
|
.to_owned(),
|
|
|
|
|
}));
|
|
|
|
|
} else if result.center[1].is_infinite() {
|
|
|
|
|
return Err(KclError::Semantic(KclErrorDetails {
|
|
|
|
|
source_ranges: vec![args.source_range],
|
|
|
|
|
message:
|
|
|
|
|
"could not sketch tangential arc, because its center would be infinitely far away in the Y direction"
|
|
|
|
|
.to_owned(),
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let id = uuid::Uuid::new_v4();
|
|
|
|
|
args.batch_modeling_cmd(id, tan_arc_to(&sketch_group, &delta)).await?;
|
|
|
|
|
|
|
|
|
|
let current_path = Path::TangentialArcTo {
|
|
|
|
|
base: BasePath {
|
|
|
|
|
from: from.into(),
|
|
|
|
|
to: delta,
|
|
|
|
|
tag: tag.clone(),
|
|
|
|
|
geo_meta: GeoMeta {
|
|
|
|
|
id,
|
|
|
|
|
metadata: args.source_range.into(),
|
|
|
|
|
},
|
|
|
|
|
},
|
2024-09-18 17:04:04 -05:00
|
|
|
|
center: result.center,
|
2024-08-30 13:44:20 -05:00
|
|
|
|
ccw: result.ccw > 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut new_sketch_group = sketch_group.clone();
|
|
|
|
|
if let Some(tag) = &tag {
|
|
|
|
|
new_sketch_group.add_tag(tag, ¤t_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new_sketch_group.value.push(current_path);
|
|
|
|
|
|
|
|
|
|
Ok(new_sketch_group)
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-31 22:19:23 -07:00
|
|
|
|
/// Data to draw a bezier curve.
|
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
|
|
|
|
#[ts(export)]
|
2024-03-07 15:35:26 -08:00
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
|
pub struct BezierData {
|
|
|
|
|
/// The to point.
|
|
|
|
|
to: [f64; 2],
|
|
|
|
|
/// The first control point.
|
|
|
|
|
control1: [f64; 2],
|
|
|
|
|
/// The second control point.
|
|
|
|
|
control2: [f64; 2],
|
2023-08-31 22:19:23 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Draw a bezier curve.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn bezier_curve(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (data, sketch_group, tag): (BezierData, SketchGroup, Option<TagDeclarator>) =
|
2024-03-15 17:03:42 -04:00
|
|
|
|
args.get_data_and_sketch_group_and_tag()?;
|
2023-08-31 22:19:23 -07:00
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
|
let new_sketch_group = inner_bezier_curve(data, sketch_group, tag, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-08-31 22:19:23 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Draw a smooth, continuous, curved line segment from the current origin to
|
|
|
|
|
/// the desired (x, y), using a number of control points to shape the curve's
|
|
|
|
|
/// shape.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XZ')
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> line([0, 10], %)
|
|
|
|
|
/// |> bezierCurve({
|
|
|
|
|
/// to: [10, 10],
|
|
|
|
|
/// control1: [5, 0],
|
|
|
|
|
/// control2: [5, 10]
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// |> lineTo([10, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(10, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-08-31 22:19:23 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "bezierCurve",
|
|
|
|
|
}]
|
2023-09-20 18:27:08 -07:00
|
|
|
|
async fn inner_bezier_curve(
|
2023-09-19 14:20:14 -07:00
|
|
|
|
data: BezierData,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
tag: Option<TagDeclarator>,
|
2023-09-20 18:27:08 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
2024-05-30 17:48:59 -05:00
|
|
|
|
let from = sketch_group.current_pen_position()?;
|
2023-08-31 22:19:23 -07:00
|
|
|
|
|
2023-09-20 17:36:26 -07:00
|
|
|
|
let relative = true;
|
2024-03-07 15:35:26 -08:00
|
|
|
|
let delta = data.to;
|
|
|
|
|
let to = [from.x + data.to[0], from.y + data.to[1]];
|
2023-08-31 22:19:23 -07:00
|
|
|
|
|
|
|
|
|
let id = uuid::Uuid::new_v4();
|
|
|
|
|
|
2024-06-19 13:57:50 -07:00
|
|
|
|
args.batch_modeling_cmd(
|
2023-08-31 22:19:23 -07:00
|
|
|
|
id,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::ExtendPath {
|
|
|
|
|
path: sketch_group.id.into(),
|
|
|
|
|
segment: PathSegment::Bezier {
|
|
|
|
|
control1: KPoint2d::from(data.control1).with_z(0.0).map(LengthUnit),
|
|
|
|
|
control2: KPoint2d::from(data.control2).with_z(0.0).map(LengthUnit),
|
|
|
|
|
end: KPoint2d::from(delta).with_z(0.0).map(LengthUnit),
|
2023-09-20 17:36:26 -07:00
|
|
|
|
relative,
|
2023-08-31 22:19:23 -07:00
|
|
|
|
},
|
2024-09-18 17:04:04 -05:00
|
|
|
|
}),
|
2023-09-20 18:27:08 -07:00
|
|
|
|
)
|
|
|
|
|
.await?;
|
2023-08-31 22:19:23 -07:00
|
|
|
|
|
|
|
|
|
let current_path = Path::ToPoint {
|
|
|
|
|
base: BasePath {
|
|
|
|
|
from: from.into(),
|
|
|
|
|
to,
|
2024-07-27 22:56:46 -07:00
|
|
|
|
tag: tag.clone(),
|
2023-08-31 22:19:23 -07:00
|
|
|
|
geo_meta: GeoMeta {
|
|
|
|
|
id,
|
|
|
|
|
metadata: args.source_range.into(),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-27 22:56:46 -07:00
|
|
|
|
let mut new_sketch_group = sketch_group.clone();
|
|
|
|
|
if let Some(tag) = &tag {
|
|
|
|
|
new_sketch_group.add_tag(tag, ¤t_path);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-31 22:19:23 -07:00
|
|
|
|
new_sketch_group.value.push(current_path);
|
|
|
|
|
|
|
|
|
|
Ok(new_sketch_group)
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-13 12:02:46 -07:00
|
|
|
|
/// Use a sketch to cut a hole in another sketch.
|
2024-09-16 15:10:33 -04:00
|
|
|
|
pub async fn hole(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
let (hole_sketch_group, sketch_group): (SketchGroupSet, SketchGroup) = args.get_sketch_groups()?;
|
2023-10-13 12:02:46 -07:00
|
|
|
|
|
|
|
|
|
let new_sketch_group = inner_hole(hole_sketch_group, sketch_group, args).await?;
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
2023-10-13 12:02:46 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 20:27:26 -04:00
|
|
|
|
/// Use a 2-dimensional sketch to cut a hole in another 2-dimensional sketch.
|
2024-03-13 12:56:46 -07:00
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// const exampleSketch = startSketchOn('XY')
|
|
|
|
|
/// |> startProfileAt([0, 0], %)
|
|
|
|
|
/// |> line([0, 5], %)
|
|
|
|
|
/// |> line([5, 0], %)
|
|
|
|
|
/// |> line([0, -5], %)
|
|
|
|
|
/// |> close(%)
|
2024-09-23 22:42:51 +10:00
|
|
|
|
/// |> hole(circle({ center: [1, 1], radius: .25 }, %), %)
|
|
|
|
|
/// |> hole(circle({ center: [1, 4], radius: .25 }, %), %)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
///
|
|
|
|
|
/// const example = extrude(1, exampleSketch)
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// fn squareHoleSketch = () => {
|
|
|
|
|
/// const squareSketch = startSketchOn('-XZ')
|
|
|
|
|
/// |> startProfileAt([-1, -1], %)
|
|
|
|
|
/// |> line([2, 0], %)
|
|
|
|
|
/// |> line([0, 2], %)
|
|
|
|
|
/// |> line([-2, 0], %)
|
|
|
|
|
/// |> close(%)
|
|
|
|
|
/// return squareSketch
|
|
|
|
|
/// }
|
2024-05-22 09:15:38 -07:00
|
|
|
|
///
|
|
|
|
|
/// const exampleSketch = startSketchOn('-XZ')
|
2024-09-23 22:42:51 +10:00
|
|
|
|
/// |> circle({ center: [0, 0], radius: 3 }, %)
|
2024-05-14 17:10:47 -07:00
|
|
|
|
/// |> hole(squareHoleSketch(), %)
|
2024-05-22 09:15:38 -07:00
|
|
|
|
/// const example = extrude(1, exampleSketch)
|
2024-03-13 12:56:46 -07:00
|
|
|
|
/// ```
|
2023-10-13 12:02:46 -07:00
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "hole",
|
|
|
|
|
}]
|
|
|
|
|
async fn inner_hole(
|
2024-02-11 15:08:54 -08:00
|
|
|
|
hole_sketch_group: SketchGroupSet,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
sketch_group: SketchGroup,
|
2023-10-13 12:02:46 -07:00
|
|
|
|
args: Args,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
|
) -> Result<SketchGroup, KclError> {
|
|
|
|
|
let hole_sketch_groups: Vec<SketchGroup> = hole_sketch_group.into();
|
2024-06-23 23:04:32 -07:00
|
|
|
|
for hole_sketch_group in hole_sketch_groups {
|
|
|
|
|
args.batch_modeling_cmd(
|
|
|
|
|
uuid::Uuid::new_v4(),
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::Solid2dAddHole {
|
2024-06-23 23:04:32 -07:00
|
|
|
|
object_id: sketch_group.id,
|
|
|
|
|
hole_id: hole_sketch_group.id,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
}),
|
2024-06-23 23:04:32 -07:00
|
|
|
|
)
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
// suggestion (mike)
|
|
|
|
|
// we also hide the source hole since its essentially "consumed" by this operation
|
|
|
|
|
args.batch_modeling_cmd(
|
|
|
|
|
uuid::Uuid::new_v4(),
|
2024-09-18 17:04:04 -05:00
|
|
|
|
ModelingCmd::from(mcmd::ObjectVisible {
|
2024-06-23 23:04:32 -07:00
|
|
|
|
object_id: hole_sketch_group.id,
|
|
|
|
|
hidden: true,
|
2024-09-18 17:04:04 -05:00
|
|
|
|
}),
|
2024-06-23 23:04:32 -07:00
|
|
|
|
)
|
|
|
|
|
.await?;
|
2024-02-11 15:08:54 -08:00
|
|
|
|
}
|
2023-10-13 12:02:46 -07:00
|
|
|
|
|
|
|
|
|
Ok(sketch_group)
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
|
|
|
|
|
use pretty_assertions::assert_eq;
|
|
|
|
|
|
2024-06-24 14:45:07 -07:00
|
|
|
|
use crate::{executor::TagIdentifier, std::sketch::PlaneData};
|
2023-10-05 14:27:48 -07:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_deserialize_plane_data() {
|
|
|
|
|
let data = PlaneData::XY;
|
|
|
|
|
let mut str_json = serde_json::to_string(&data).unwrap();
|
|
|
|
|
assert_eq!(str_json, "\"XY\"");
|
|
|
|
|
|
|
|
|
|
str_json = "\"YZ\"".to_string();
|
|
|
|
|
let data: PlaneData = serde_json::from_str(&str_json).unwrap();
|
|
|
|
|
assert_eq!(data, PlaneData::YZ);
|
|
|
|
|
|
|
|
|
|
str_json = "\"-YZ\"".to_string();
|
|
|
|
|
let data: PlaneData = serde_json::from_str(&str_json).unwrap();
|
|
|
|
|
assert_eq!(data, PlaneData::NegYZ);
|
|
|
|
|
|
|
|
|
|
str_json = "\"-xz\"".to_string();
|
|
|
|
|
let data: PlaneData = serde_json::from_str(&str_json).unwrap();
|
|
|
|
|
assert_eq!(data, PlaneData::NegXZ);
|
|
|
|
|
}
|
2024-02-13 10:26:09 -08:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_deserialize_sketch_on_face_tag() {
|
|
|
|
|
let data = "start";
|
|
|
|
|
let mut str_json = serde_json::to_string(&data).unwrap();
|
|
|
|
|
assert_eq!(str_json, "\"start\"");
|
|
|
|
|
|
|
|
|
|
str_json = "\"end\"".to_string();
|
2024-06-23 23:04:32 -07:00
|
|
|
|
let data: crate::std::sketch::FaceTag = serde_json::from_str(&str_json).unwrap();
|
2024-02-13 10:26:09 -08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
data,
|
2024-06-23 23:04:32 -07:00
|
|
|
|
crate::std::sketch::FaceTag::StartOrEnd(crate::std::sketch::StartOrEnd::End)
|
2024-02-13 10:26:09 -08:00
|
|
|
|
);
|
|
|
|
|
|
2024-07-27 17:59:41 -07:00
|
|
|
|
str_json = serde_json::to_string(&TagIdentifier {
|
|
|
|
|
value: "thing".to_string(),
|
2024-07-27 22:56:46 -07:00
|
|
|
|
info: None,
|
2024-07-27 17:59:41 -07:00
|
|
|
|
meta: Default::default(),
|
|
|
|
|
})
|
|
|
|
|
.unwrap();
|
2024-06-23 23:04:32 -07:00
|
|
|
|
let data: crate::std::sketch::FaceTag = serde_json::from_str(&str_json).unwrap();
|
2024-06-24 14:45:07 -07:00
|
|
|
|
assert_eq!(
|
|
|
|
|
data,
|
2024-07-27 22:56:46 -07:00
|
|
|
|
crate::std::sketch::FaceTag::Tag(Box::new(TagIdentifier {
|
2024-06-24 14:45:07 -07:00
|
|
|
|
value: "thing".to_string(),
|
2024-07-27 22:56:46 -07:00
|
|
|
|
info: None,
|
2024-06-24 14:45:07 -07:00
|
|
|
|
meta: Default::default()
|
2024-07-27 22:56:46 -07:00
|
|
|
|
}))
|
2024-06-24 14:45:07 -07:00
|
|
|
|
);
|
2024-02-13 10:26:09 -08:00
|
|
|
|
|
|
|
|
|
str_json = "\"END\"".to_string();
|
2024-06-23 23:04:32 -07:00
|
|
|
|
let data: crate::std::sketch::FaceTag = serde_json::from_str(&str_json).unwrap();
|
2024-02-13 10:26:09 -08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
data,
|
2024-06-23 23:04:32 -07:00
|
|
|
|
crate::std::sketch::FaceTag::StartOrEnd(crate::std::sketch::StartOrEnd::End)
|
2024-02-13 10:26:09 -08:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
str_json = "\"start\"".to_string();
|
2024-06-23 23:04:32 -07:00
|
|
|
|
let data: crate::std::sketch::FaceTag = serde_json::from_str(&str_json).unwrap();
|
2024-02-13 10:26:09 -08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
data,
|
2024-06-23 23:04:32 -07:00
|
|
|
|
crate::std::sketch::FaceTag::StartOrEnd(crate::std::sketch::StartOrEnd::Start)
|
2024-02-13 10:26:09 -08:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
str_json = "\"START\"".to_string();
|
2024-06-23 23:04:32 -07:00
|
|
|
|
let data: crate::std::sketch::FaceTag = serde_json::from_str(&str_json).unwrap();
|
2024-02-13 10:26:09 -08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
data,
|
2024-06-23 23:04:32 -07:00
|
|
|
|
crate::std::sketch::FaceTag::StartOrEnd(crate::std::sketch::StartOrEnd::Start)
|
2024-02-13 10:26:09 -08:00
|
|
|
|
);
|
|
|
|
|
}
|
2023-08-24 15:34:51 -07:00
|
|
|
|
}
|