Compare commits

...

4 Commits

Author SHA1 Message Date
8b0510a244 fmt 2024-03-15 09:09:45 -04:00
5c6483ae67 Add a grackle variant of import 2024-03-15 09:05:27 -04:00
7700d01403 Move startsketchAt into a new 'sketch' module 2024-03-15 09:03:12 -04:00
b212ff4470 Grackle: implement StartSketchAt stdlib function 2024-03-15 09:03:12 -04:00
8 changed files with 690 additions and 512 deletions

938
src/wasm-lib/Cargo.lock generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -121,6 +121,10 @@ impl BindingScope {
"close".into(), "close".into(),
EpBinding::from(KclFunction::Close(native_functions::sketch::Close)), EpBinding::from(KclFunction::Close(native_functions::sketch::Close)),
), ),
(
"import".into(),
EpBinding::from(KclFunction::ImportFile(native_functions::import_files::ImportFiles)),
),
]), ]),
parent: None, parent: None,
} }

View File

@ -264,6 +264,7 @@ impl Planner {
KclFunction::LineTo(f) => f.call(&mut ctx, args)?, KclFunction::LineTo(f) => f.call(&mut ctx, args)?,
KclFunction::Add(f) => f.call(&mut ctx, args)?, KclFunction::Add(f) => f.call(&mut ctx, args)?,
KclFunction::Close(f) => f.call(&mut ctx, args)?, KclFunction::Close(f) => f.call(&mut ctx, args)?,
KclFunction::ImportFile(f) => f.call(&mut self.next_addr, args)?,
KclFunction::UserDefined(f) => { KclFunction::UserDefined(f) => {
let UserDefinedFunction { let UserDefinedFunction {
params_optional, params_optional,
@ -631,6 +632,7 @@ enum KclFunction {
Id(native_functions::Id), Id(native_functions::Id),
StartSketchAt(native_functions::sketch::StartSketchAt), StartSketchAt(native_functions::sketch::StartSketchAt),
LineTo(native_functions::sketch::LineTo), LineTo(native_functions::sketch::LineTo),
ImportFile(native_functions::import_files::ImportFiles),
Add(native_functions::Add), Add(native_functions::Add),
UserDefined(UserDefinedFunction), UserDefined(UserDefinedFunction),
Extrude(native_functions::sketch::Extrude), Extrude(native_functions::sketch::Extrude),

View File

@ -7,6 +7,7 @@ use kittycad_execution_plan_traits::Address;
use crate::{CompileError, EpBinding, EvalPlan}; use crate::{CompileError, EpBinding, EvalPlan};
pub mod import_files;
pub mod sketch; pub mod sketch;
/// The identity function. Always returns its first input. /// The identity function. Always returns its first input.

View File

@ -0,0 +1,116 @@
//! Standard library functions involved in importing files.
use kittycad_execution_plan::{api_request::ApiRequest, import_files, Instruction};
use kittycad_execution_plan_traits::{Address, InMemory, MemoryArea, Primitive};
use kittycad_modeling_cmds::ModelingCmdEndpoint;
use uuid::Uuid;
use crate::{binding_scope::EpBinding, error::CompileError, EvalPlan};
use super::Callable;
#[derive(Debug, Clone)]
#[cfg_attr(test, derive(Eq, PartialEq))]
pub struct ImportFiles;
/// Import a CAD file.
/// For formats lacking unit data (STL, OBJ, PLY), the default import unit is millimeters.
/// Otherwise you can specify the unit by passing in the options parameter.
/// If you import a gltf file, we will try to find the bin file and import it as well.
impl Callable for ImportFiles {
fn call(&self, addr_retval: &mut Address, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
let mut instructions: Vec<Instruction> = vec![];
let fn_name = "import";
let required_args = 1;
let args_len = args.len();
let mut args_iter = args.into_iter();
let EpBinding::Single(file_path) = args_iter.next().ok_or_else(|| CompileError::NotEnoughArgs {
fn_name: fn_name.into(),
required: required_args,
actual: args_len,
})?
else {
panic!("file path must be a single value.")
};
let file_format = if let Some(EpBinding::Map {
length_at: e,
properties: format_props,
}) = args_iter.next()
{
let mut input_format_vals: Vec<InMemory> = vec![];
if let Some(EpBinding::Single(addr_type)) = format_props.get("type") {
input_format_vals.push((*addr_type).into());
}
if let Some(EpBinding::Single(addr_units)) = format_props.get("units") {
input_format_vals.push((*addr_units).into());
}
if let Some(EpBinding::Map {
length_at: _,
properties: coords_props,
}) = format_props.get("coords")
{
if let Some(EpBinding::Map {
length_at: _,
properties: forward_props,
}) = coords_props.get("forward")
{
if let Some(EpBinding::Single(addr_coords_forward_axis)) = forward_props.get("axis") {
input_format_vals.push((*addr_coords_forward_axis).into());
}
if let Some(EpBinding::Single(addr_coords_forward_direction)) = forward_props.get("direction") {
input_format_vals.push((*addr_coords_forward_direction).into());
}
}
if let Some(EpBinding::Map {
length_at: _,
properties: up_props,
}) = coords_props.get("up")
{
if let Some(EpBinding::Single(addr_coords_up_axis)) = up_props.get("axis") {
input_format_vals.push((*addr_coords_up_axis).into());
}
if let Some(EpBinding::Single(addr_coords_up_direction)) = up_props.get("direction") {
input_format_vals.push((*addr_coords_up_direction).into());
}
}
}
input_format_vals
} else {
vec![]
};
if let Some(_) = args_iter.next() {
return Err(CompileError::TooManyArgs {
fn_name: fn_name.into(),
maximum: 2,
actual: args_len,
});
}
let mut import_files_arguments = vec![file_path.into()];
import_files_arguments.extend(file_format);
instructions.push(Instruction::ImportFiles(import_files::ImportFiles {
store_response: Some(MemoryArea::Stack),
arguments: import_files_arguments,
}));
instructions.push(Instruction::ApiRequest(ApiRequest {
endpoint: ModelingCmdEndpoint::ImportFiles,
store_response: Some(*addr_retval),
arguments: vec![InMemory::StackPop],
cmd_id: Uuid::new_v4().into(),
}));
let retval_without_enclosing_enum_variant_name = *addr_retval + 1;
Ok(EvalPlan {
instructions,
binding: EpBinding::Single(retval_without_enclosing_enum_variant_name),
})
}
}

View File

@ -2,6 +2,7 @@ use std::{collections::HashMap, env};
use ep::{sketch_types, Destination, UnaryArithmetic}; use ep::{sketch_types, Destination, UnaryArithmetic};
use ept::{ListHeader, ObjectHeader}; use ept::{ListHeader, ObjectHeader};
use kittycad_execution_plan_traits::ReadMemory;
use kittycad_modeling_cmds::shared::Point2d; use kittycad_modeling_cmds::shared::Point2d;
use kittycad_modeling_session::SessionBuilder; use kittycad_modeling_session::SessionBuilder;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
@ -1328,3 +1329,143 @@ fn mod_and_pow() {
] ]
); );
} }
#[tokio::test]
async fn import_file_cube_stl() {
let program = "let x = import(\"samples/cube.stl\", { type: \"stl\", units: \"mm\", coords: { forward: { axis: \"Y\", direction: \"negative\" }, up: { axis: \"Z\", direction: \"positive\" } } })";
let (_plan, scope) = must_plan(program);
let Some(EpBinding::Single(x)) = scope.get("x") else {
panic!("Unexpected binding for variable 'x': {:?}", scope.get("x"));
};
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
.ast()
.unwrap();
let mem = crate::execute(ast, Some(test_client().await)).await.unwrap();
let mut expected_format =
kittycad_modeling_cmds::format::InputFormat::Stl(kittycad_modeling_cmds::format::stl::import::Options {
coords: kittycad_execution_plan::import_files::ZOO_COORD_SYSTEM,
units: kittycad_modeling_cmds::units::UnitLength::Millimeters,
});
let imported_geometry = mem
.get_composite::<kittycad_modeling_cmds::ok_response::output::ImportedGeometry>(*x)
.unwrap();
use ept::ReadMemory;
assert_eq!(
imported_geometry.0,
kittycad_modeling_cmds::ok_response::output::ImportedGeometry {
id: imported_geometry.0.id,
value: vec!["cube.stl".to_string()],
}
);
}
#[tokio::test]
async fn import_file_cube_stl_no_options() {
let program = "let x = import(\"samples/cube.stl\")";
let (_plan, scope) = must_plan(program);
let Some(EpBinding::Single(x)) = scope.get("x") else {
panic!("Unexpected binding for variable 'x': {:?}", scope.get("x"));
};
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
.ast()
.unwrap();
let mem = crate::execute(ast, Some(test_client().await)).await.unwrap();
let mut expected_format =
kittycad_modeling_cmds::format::InputFormat::Stl(kittycad_modeling_cmds::format::stl::import::Options {
coords: kittycad_execution_plan::import_files::ZOO_COORD_SYSTEM,
units: kittycad_modeling_cmds::units::UnitLength::Millimeters,
});
let imported_geometry = mem
.get_composite::<kittycad_modeling_cmds::ok_response::output::ImportedGeometry>(*x)
.unwrap();
use ept::ReadMemory;
assert_eq!(
imported_geometry.0,
kittycad_modeling_cmds::ok_response::output::ImportedGeometry {
id: imported_geometry.0.id,
value: vec!["cube.stl".to_string()],
}
);
}
#[tokio::test]
async fn import_file_cube_stl_options_missing_param() {
let program = "let x = import(\"samples/cube.stl\", { type: \"stx\", coords: { forward: { axis: \"Y\", direction: \"negative\" }, up: { axis: \"Z\", direction: \"positive\" } } })";
let (_plan, scope) = must_plan(program);
let Some(EpBinding::Single(x)) = scope.get("x") else {
panic!("Unexpected binding for variable 'x': {:?}", scope.get("x"));
};
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
.ast()
.unwrap();
let mem = crate::execute(ast, Some(test_client().await)).await.unwrap();
let mut expected_format =
kittycad_modeling_cmds::format::InputFormat::Stl(kittycad_modeling_cmds::format::stl::import::Options {
coords: kittycad_execution_plan::import_files::ZOO_COORD_SYSTEM,
units: kittycad_modeling_cmds::units::UnitLength::Millimeters,
});
let imported_geometry = mem
.get_composite::<kittycad_modeling_cmds::ok_response::output::ImportedGeometry>(*x)
.unwrap();
use ept::ReadMemory;
assert_eq!(
imported_geometry.0,
kittycad_modeling_cmds::ok_response::output::ImportedGeometry {
id: imported_geometry.0.id,
value: vec!["cube.stl".to_string()],
}
);
}
#[tokio::test]
async fn import_file_cube_stl_format_mismatch() {
let program = "let x = import(\"samples/cube.stl\", { type: \"step\" })";
let (_plan, scope) = must_plan(program);
let Some(EpBinding::Single(x)) = scope.get("x") else {
panic!("Unexpected binding for variable 'x': {:?}", scope.get("x"));
};
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
.ast()
.unwrap();
let mem = crate::execute(ast, Some(test_client().await)).await.unwrap();
let mut expected_format =
kittycad_modeling_cmds::format::InputFormat::Stl(kittycad_modeling_cmds::format::stl::import::Options {
coords: kittycad_execution_plan::import_files::ZOO_COORD_SYSTEM,
units: kittycad_modeling_cmds::units::UnitLength::Millimeters,
});
let imported_geometry = mem
.get_composite::<kittycad_modeling_cmds::ok_response::output::ImportedGeometry>(*x)
.unwrap();
use ept::ReadMemory;
assert_eq!(
imported_geometry.0,
kittycad_modeling_cmds::ok_response::output::ImportedGeometry {
id: imported_geometry.0.id,
value: vec!["cube.stl".to_string()],
}
);
}