KCL: Convert bezierCurve to use keyword args (#6381)

This commit is contained in:
Adam Chalmers
2025-04-20 20:10:27 -05:00
committed by GitHub
parent 0a35722595
commit 790613e708
13 changed files with 5540 additions and 845 deletions

View File

@ -653,40 +653,6 @@ impl Args {
FromArgs::from_args(self, 0)
}
pub(crate) fn get_data_and_sketch_and_tag<'a, T>(
&'a self,
exec_state: &mut ExecState,
) -> Result<(T, Sketch, Option<TagNode>), KclError>
where
T: FromKclValue<'a> + Sized,
{
let data: T = FromArgs::from_args(self, 0)?;
let Some(arg1) = self.args.get(1) else {
return Err(KclError::Semantic(KclErrorDetails {
message: "Expected a sketch for second argument".to_owned(),
source_ranges: vec![self.source_range],
}));
};
let sarg = arg1
.value
.coerce(&RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)
.map_err(|_| {
KclError::Type(KclErrorDetails {
message: format!(
"Expected a sketch for second argument, found {}",
arg1.value.human_friendly_type()
),
source_ranges: vec![self.source_range],
})
})?;
let sketch = match sarg {
KclValue::Sketch { value } => *value,
_ => unreachable!(),
};
let tag: Option<TagNode> = FromArgs::from_args(self, 2)?;
Ok((data, sketch, tag))
}
pub(crate) fn get_data_and_sketch_surface(&self) -> Result<([TyF64; 2], SketchSurface, Option<TagNode>), KclError> {
FromArgs::from_args(self, 0)
}
@ -1095,16 +1061,6 @@ impl<'a> FromKclValue<'a> for kittycad_modeling_cmds::coord::Direction {
}
}
impl<'a> FromKclValue<'a> for super::sketch::BezierData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?;
let_field_of!(obj, to);
let_field_of!(obj, control1);
let_field_of!(obj, control2);
Some(Self { to, control1, control2 })
}
}
impl<'a> FromKclValue<'a> for FaceTag {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let case1 = || match arg.as_str() {

View File

@ -71,11 +71,11 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
/// )
/// |> line(end = [5, 0])
/// |> line(end = [0, 10])
/// |> bezierCurve({
/// control1 = [-10, 0],
/// control2 = [2, 10],
/// to = [-5, 10],
/// }, %)
/// |> bezierCurve(
/// control1 = [-10, 0],
/// control2 = [2, 10],
/// end = [-5, 10],
/// )
/// |> line(end = [-5, -2])
/// |> close()
/// |> extrude(length = 10)
@ -91,11 +91,11 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
/// )
/// |> line(end = [10, 0])
/// |> line(end = [5, 0])
/// |> bezierCurve({
/// control1 = [-3, 0],
/// control2 = [2, 10],
/// to = [-5, 10],
/// }, %)
/// |> bezierCurve(
/// control1 = [-3, 0],
/// control2 = [2, 10],
/// end = [-5, 10],
/// )
/// |> line(end = [-4, 10])
/// |> line(end = [-5, -2])
/// |> close()
@ -113,11 +113,11 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
/// )
/// |> line(end = [10, 0])
/// |> line(end = [5, 0])
/// |> bezierCurve({
/// control1 = [-3, 0],
/// control2 = [2, 10],
/// to = [-5, 10],
/// }, %)
/// |> bezierCurve(
/// control1 = [-3, 0],
/// control2 = [2, 10],
/// end = [-5, 10],
/// )
/// |> line(end = [-4, 10])
/// |> line(end = [-5, -2])
/// |> close()
@ -135,11 +135,11 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
/// )
/// |> line(end = [10, 0])
/// |> line(end = [5, 0])
/// |> bezierCurve({
/// control1 = [-3, 0],
/// control2 = [2, 10],
/// to = [-5, 10],
/// }, %)
/// |> bezierCurve(
/// control1 = [-3, 0],
/// control2 = [2, 10],
/// end = [-5, 10],
/// )
/// |> line(end = [-4, 10])
/// |> line(end = [-5, -2])
/// |> close()

View File

@ -198,26 +198,6 @@ async fn inner_involute_circular(
end.x += from.x;
end.y += from.y;
// let path_json = path_to_json();
// let end = args
// .send_modeling_cmd(
// exec_state.next_uuid(),
// ModelingCmd::EngineUtilEvaluatePath(mcmd::EngineUtilEvaluatePath { path_json, t: 1.0 }),
// )
// .await?;
// let end = match end {
// kittycad_modeling_cmds::websocket::OkWebSocketResponseData::Modeling {
// modeling_response: OkModelingCmdResponse::EngineUtilEvaluatePath(eval_path),
// } => eval_path.pos,
// other => {
// return Err(KclError::Engine(KclErrorDetails {
// source_ranges: vec![args.source_range],
// message: format!("Expected EngineUtilEvaluatePath response but found {other:?}"),
// }))
// }
// };
let current_path = Path::ToPoint {
base: BasePath {
from: from.into(),
@ -2189,24 +2169,16 @@ async fn inner_tangential_arc_to_point(
Ok(new_sketch)
}
/// Data to draw a bezier curve.
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct BezierData {
/// The to point.
pub to: [TyF64; 2],
/// The first control point.
pub control1: [TyF64; 2],
/// The second control point.
pub control2: [TyF64; 2],
}
/// Draw a bezier curve.
pub async fn bezier_curve(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, sketch, tag): (BezierData, Sketch, Option<TagNode>) = args.get_data_and_sketch_and_tag(exec_state)?;
let sketch =
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let end: [TyF64; 2] = args.get_kw_arg_typed("end", &RuntimeType::point2d(), exec_state)?;
let control1: [TyF64; 2] = args.get_kw_arg_typed("control1", &RuntimeType::point2d(), exec_state)?;
let control2: [TyF64; 2] = args.get_kw_arg_typed("control2", &RuntimeType::point2d(), exec_state)?;
let tag = args.get_kw_arg_opt("tag")?;
let new_sketch = inner_bezier_curve(data, sketch, tag, exec_state, args).await?;
let new_sketch = inner_bezier_curve(sketch, control1, control2, end, tag, exec_state, args).await?;
Ok(KclValue::Sketch {
value: Box::new(new_sketch),
})
@ -2220,11 +2192,11 @@ pub async fn bezier_curve(exec_state: &mut ExecState, args: Args) -> Result<KclV
/// exampleSketch = startSketchOn(XZ)
/// |> startProfileAt([0, 0], %)
/// |> line(end = [0, 10])
/// |> bezierCurve({
/// to = [10, 10],
/// |> bezierCurve(
/// control1 = [5, 0],
/// control2 = [5, 10]
/// }, %)
/// control2 = [5, 10],
/// end = [10, 10],
/// )
/// |> line(endAbsolute = [10, 0])
/// |> close()
///
@ -2232,10 +2204,21 @@ pub async fn bezier_curve(exec_state: &mut ExecState, args: Args) -> Result<KclV
/// ```
#[stdlib {
name = "bezierCurve",
keywords = true,
unlabeled_first = true,
args = {
sketch = { docs = "Which sketch should this path be added to?"},
end = { docs = "How far away (along the X and Y axes) should this line go?" },
control1 = { docs = "First control point for the cubic" },
control2 = { docs = "Second control point for the cubic" },
tag = { docs = "Create a new tag which refers to this line"},
}
}]
async fn inner_bezier_curve(
data: BezierData,
sketch: Sketch,
control1: [TyF64; 2],
control2: [TyF64; 2],
end: [TyF64; 2],
tag: Option<TagNode>,
exec_state: &mut ExecState,
args: Args,
@ -2243,8 +2226,8 @@ async fn inner_bezier_curve(
let from = sketch.current_pen_position()?;
let relative = true;
let delta = data.to.clone();
let to = [from.x + data.to[0].n, from.y + data.to[1].n];
let delta = end.clone();
let to = [from.x + end[0].n, from.y + end[1].n];
let id = exec_state.next_uuid();
@ -2253,12 +2236,8 @@ async fn inner_bezier_curve(
ModelingCmd::from(mcmd::ExtendPath {
path: sketch.id.into(),
segment: PathSegment::Bezier {
control1: KPoint2d::from(untype_point(data.control1).0)
.with_z(0.0)
.map(LengthUnit),
control2: KPoint2d::from(untype_point(data.control2).0)
.with_z(0.0)
.map(LengthUnit),
control1: KPoint2d::from(untype_point(control1).0).with_z(0.0).map(LengthUnit),
control2: KPoint2d::from(untype_point(control2).0).with_z(0.0).map(LengthUnit),
end: KPoint2d::from(untype_point(delta).0).with_z(0.0).map(LengthUnit),
relative,
},