Compare commits
	
		
			4 Commits
		
	
	
		
			franknoiro
			...
			lee/native
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8b0510a244 | |||
| 5c6483ae67 | |||
| 7700d01403 | |||
| b212ff4470 | 
							
								
								
									
										938
									
								
								src/wasm-lib/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										938
									
								
								src/wasm-lib/Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								src/wasm-lib/grackle/samples/cube.stl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/wasm-lib/grackle/samples/cube.stl
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										0
									
								
								src/wasm-lib/grackle/samples/empty-file.stl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/wasm-lib/grackle/samples/empty-file.stl
									
									
									
									
									
										Normal file
									
								
							| @ -121,6 +121,10 @@ impl BindingScope { | ||||
|                     "close".into(), | ||||
|                     EpBinding::from(KclFunction::Close(native_functions::sketch::Close)), | ||||
|                 ), | ||||
|                 ( | ||||
|                     "import".into(), | ||||
|                     EpBinding::from(KclFunction::ImportFile(native_functions::import_files::ImportFiles)), | ||||
|                 ), | ||||
|             ]), | ||||
|             parent: None, | ||||
|         } | ||||
|  | ||||
| @ -264,6 +264,7 @@ impl Planner { | ||||
|                     KclFunction::LineTo(f) => f.call(&mut ctx, args)?, | ||||
|                     KclFunction::Add(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) => { | ||||
|                         let UserDefinedFunction { | ||||
|                             params_optional, | ||||
| @ -631,6 +632,7 @@ enum KclFunction { | ||||
|     Id(native_functions::Id), | ||||
|     StartSketchAt(native_functions::sketch::StartSketchAt), | ||||
|     LineTo(native_functions::sketch::LineTo), | ||||
|     ImportFile(native_functions::import_files::ImportFiles), | ||||
|     Add(native_functions::Add), | ||||
|     UserDefined(UserDefinedFunction), | ||||
|     Extrude(native_functions::sketch::Extrude), | ||||
|  | ||||
| @ -7,6 +7,7 @@ use kittycad_execution_plan_traits::Address; | ||||
|  | ||||
| use crate::{CompileError, EpBinding, EvalPlan}; | ||||
|  | ||||
| pub mod import_files; | ||||
| pub mod sketch; | ||||
|  | ||||
| /// The identity function. Always returns its first input. | ||||
|  | ||||
							
								
								
									
										116
									
								
								src/wasm-lib/grackle/src/native_functions/import_files.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								src/wasm-lib/grackle/src/native_functions/import_files.rs
									
									
									
									
									
										Normal 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), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| @ -2,6 +2,7 @@ use std::{collections::HashMap, env}; | ||||
|  | ||||
| use ep::{sketch_types, Destination, UnaryArithmetic}; | ||||
| use ept::{ListHeader, ObjectHeader}; | ||||
| use kittycad_execution_plan_traits::ReadMemory; | ||||
| use kittycad_modeling_cmds::shared::Point2d; | ||||
| use kittycad_modeling_session::SessionBuilder; | ||||
| 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()], | ||||
|         } | ||||
|     ); | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	