Skip to content

Commit

Permalink
Add tangentialArcTo to grackle stdlib
Browse files Browse the repository at this point in the history
  • Loading branch information
iterion committed Mar 14, 2024
1 parent f40cdab commit abf6bb4
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/wasm-lib/grackle/src/binding_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ impl BindingScope {
"lineTo".into(),
EpBinding::from(KclFunction::LineTo(native_functions::sketch::LineTo)),
),
(
"tangentialArcTo".into(),
EpBinding::from(KclFunction::TangentialArcTo(native_functions::sketch::TangentialArcTo)),
),
(
"extrude".into(),
EpBinding::from(KclFunction::Extrude(native_functions::sketch::Extrude)),
Expand Down
2 changes: 2 additions & 0 deletions src/wasm-lib/grackle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ impl Planner {
KclFunction::StartSketchAt(f) => f.call(&mut ctx, args)?,
KclFunction::Extrude(f) => f.call(&mut ctx, args)?,
KclFunction::LineTo(f) => f.call(&mut ctx, args)?,
KclFunction::TangentialArcTo(f) => f.call(&mut ctx, args)?,
KclFunction::Add(f) => f.call(&mut ctx, args)?,
KclFunction::Close(f) => f.call(&mut ctx, args)?,
KclFunction::UserDefined(f) => {
Expand Down Expand Up @@ -631,6 +632,7 @@ enum KclFunction {
Id(native_functions::Id),
StartSketchAt(native_functions::sketch::StartSketchAt),
LineTo(native_functions::sketch::LineTo),
TangentialArcTo(native_functions::sketch::TangentialArcTo),
Add(native_functions::Add),
UserDefined(UserDefinedFunction),
Extrude(native_functions::sketch::Extrude),
Expand Down
2 changes: 1 addition & 1 deletion src/wasm-lib/grackle/src/native_functions/sketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
pub mod helpers;
pub mod stdlib_functions;

pub use stdlib_functions::{Close, Extrude, LineTo, StartSketchAt};
pub use stdlib_functions::{Close, Extrude, LineTo, StartSketchAt, TangentialArcTo};
131 changes: 131 additions & 0 deletions src/wasm-lib/grackle/src/native_functions/sketch/stdlib_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,3 +394,134 @@ impl Callable for StartSketchAt {
})
}
}

#[derive(Debug, Clone)]
#[cfg_attr(test, derive(Eq, PartialEq))]
pub struct TangentialArcTo;

impl Callable for TangentialArcTo {
fn call(
&self,
ctx: &mut crate::native_functions::Context<'_>,
args: Vec<EpBinding>,
) -> Result<EvalPlan, CompileError> {
let mut instructions = Vec::new();
let fn_name = "tangential_arc_to";
// Get both required params.
let mut args_iter = args.into_iter();
let Some(to) = args_iter.next() else {
return Err(CompileError::NotEnoughArgs {
fn_name: fn_name.into(),
required: 2,
actual: 0,
});
};
let Some(sketch_group) = args_iter.next() else {
return Err(CompileError::NotEnoughArgs {
fn_name: fn_name.into(),
required: 2,
actual: 1,
});
};
let tag = match args_iter.next() {
Some(a) => a,
None => {
// Write an empty string and use that.
let empty_string_addr = ctx.next_address.offset_by(1);
instructions.push(Instruction::SetPrimitive {
address: empty_string_addr,
value: String::new().into(),
});
EpBinding::Single(empty_string_addr)
}
};
// Check the type of required params.
let to = arg_point2d(to, fn_name, &mut instructions, ctx, 0)?;
let sg = sg_binding(sketch_group, fn_name, "sketch group", 1)?;
let tag = single_binding(tag, fn_name, "string tag", 2)?;
let id = Uuid::new_v4();
// Start of the path segment (which is a straight line).
let length_of_3d_point = Point3d::<f64>::default().into_parts().len();
let start_of_tangential_arc = ctx.next_address.offset_by(1);
// Reserve space for the line's end, and the `relative: bool` field.
ctx.next_address.offset_by(length_of_3d_point + 1);
let new_sg_index = ctx.assign_sketch_group();
instructions.extend([
// Push the `to` 2D point onto the stack.
Instruction::Copy {
source: to,
length: 2,
destination: Destination::StackPush,
},
// Make it a 3D point.
Instruction::StackExtend { data: vec![0.0.into()] },
// Append the new path segment to memory.
// First comes its tag.
Instruction::SetPrimitive {
address: start_of_tangential_arc,
value: "TangentialArcTo".to_owned().into(),
},
// Then its to
Instruction::StackPop {
destination: Some(Destination::Address(start_of_tangential_arc + 1)),
},
// Then its `angle_snap_increment` field.
Instruction::SetPrimitive {
address: start_of_tangential_arc + 1 + length_of_3d_point,
value: Primitive::from("None".to_owned()),
},
// Push the path ID onto the stack.
Instruction::SketchGroupCopyFrom {
destination: Destination::StackPush,
length: 1,
source: sg,
offset: SketchGroup::path_id_offset(),
},
// Send the ExtendPath request
Instruction::ApiRequest(ApiRequest {
endpoint: ModelingCmdEndpoint::ExtendPath,
store_response: None,
arguments: vec![
// Path ID
InMemory::StackPop,
// Segment
InMemory::Address(start_of_tangential_arc),
],
cmd_id: id.into(),
}),
// Push the new segment in SketchGroup format.
// Path tag.
Instruction::StackPush {
data: vec![Primitive::from("ToPoint".to_owned())],
},
// `BasePath::from` point.
Instruction::SketchGroupGetLastPoint {
source: sg,
destination: Destination::StackExtend,
},
// `BasePath::to` point.
Instruction::Copy {
source: start_of_tangential_arc + 1,
length: 2,
destination: Destination::StackExtend,
},
// `BasePath::name` string.
Instruction::Copy {
source: tag,
length: 1,
destination: Destination::StackExtend,
},
// Update the SketchGroup with its new segment.
Instruction::SketchGroupAddSegment {
destination: new_sg_index,
segment: InMemory::StackPop,
source: sg,
},
]);

Ok(EvalPlan {
instructions,
binding: EpBinding::SketchGroup { index: new_sg_index },
})
}
}
85 changes: 84 additions & 1 deletion src/wasm-lib/grackle/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1052,7 +1052,7 @@ fn kcvm_dbg(kcl_program: &str) {
let (plan, _scope, _) = must_plan(kcl_program);
let plan_json = serde_json::to_string_pretty(&plan).unwrap();
std::fs::write(
"/Users/adamchalmers/kc-repos/modeling-api/execution-plan-debugger/test_input.json",
"/Users/iterion/Development/modeling-api/execution-plan-debugger/test_input.json",
plan_json,
)
.unwrap();
Expand Down Expand Up @@ -1132,6 +1132,89 @@ async fn stdlib_cube_partial() {
// std::fs::write("image.png", out).unwrap();
}

#[tokio::test]
async fn stdlib_cube_with_tangential_arc_to() {
let program = r#"
let cube = startSketchAt([10.0, 10.0], "adam")
|> lineTo([200.0 , 10.0], %, "side0")
|> tangentialArcTo([210.0, 20.0], %, "arc")
|> lineTo([210.0 , 210.0], %, "side1")
|> lineTo([ 10.0 , 210.0], %, "side2")
|> lineTo([ 10.0 , 10.0], %, "side3")
|> close(%)
|> extrude(100.0, %)
"#;
kcvm_dbg(program);
let (_plan, _scope, last_address) = must_plan(program);
assert_eq!(last_address, Address::ZERO + 80);
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
.ast()
.unwrap();
let mut client = Some(test_client().await);
let mem = match crate::execute(ast, &mut client).await {
Ok(mem) => mem,
Err(e) => panic!("{e}"),
};
let sg = &mem.sketch_groups.last().unwrap();
assert_eq!(
sg.path_rest,
vec![
sketch_types::PathSegment::ToPoint {
base: sketch_types::BasePath {
from: Point2d { x: 10.0, y: 10.0 },
to: Point2d { x: 200.0, y: 10.0 },
name: "side0".into(),
}
},
sketch_types::PathSegment::ToPoint {
base: sketch_types::BasePath {
from: Point2d { x: 200.0, y: 10.0 },
to: Point2d { x: 210.0, y: 20.0 },
name: "arc".into(),
}
},
sketch_types::PathSegment::ToPoint {
base: sketch_types::BasePath {
from: Point2d { x: 210.0, y: 20.0 },
to: Point2d { x: 210.0, y: 210.0 },
name: "side1".into(),
}
},
sketch_types::PathSegment::ToPoint {
base: sketch_types::BasePath {
from: Point2d { x: 210.0, y: 210.0 },
to: Point2d { x: 10.0, y: 210.0 },
name: "side2".into(),
}
},
sketch_types::PathSegment::ToPoint {
base: sketch_types::BasePath {
from: Point2d { x: 10.0, y: 210.0 },
to: Point2d { x: 10.0, y: 10.0 },
name: "side3".into(),
}
},
]
);
// use kittycad_modeling_cmds::{each_cmd, ok_response::OkModelingCmdResponse, ImageFormat};
// let out = client
// .unwrap()
// .run_command(
// uuid::Uuid::new_v4().into(),
// each_cmd::TakeSnapshot {
// format: ImageFormat::Png,
// },
// )
// .await
// .unwrap();
// let out = match out {
// OkModelingCmdResponse::TakeSnapshot(b) => b,
// other => panic!("wrong output: {other:?}"),
// };
// let out: Vec<u8> = out.contents.into();
// std::fs::write("image.png", out).unwrap();
}

async fn test_client() -> Session {
let kittycad_api_token = env::var("KITTYCAD_API_TOKEN").expect("You must set $KITTYCAD_API_TOKEN");
let kittycad_api_client = kittycad::Client::new(kittycad_api_token);
Expand Down

0 comments on commit abf6bb4

Please sign in to comment.