From 017fac70416ea500e1da918f69c798eda8871040 Mon Sep 17 00:00:00 2001 From: Jess Frazelle Date: Sat, 29 Mar 2025 21:23:11 -0700 Subject: [PATCH] use deterministic ids in more places (#6064) * dont redact the ids now that they are deterministic Signed-off-by: Jess Frazelle pass arouund id generator more Signed-off-by: Jess Frazelle change the anme space Signed-off-by: Jess Frazelle updates and re-run Signed-off-by: Jess Frazelle updates Signed-off-by: Jess Frazelle * fixups Signed-off-by: Jess Frazelle * fixes Signed-off-by: Jess Frazelle * cleanup old files Signed-off-by: Jess Frazelle * cleanup old files Signed-off-by: Jess Frazelle --------- Signed-off-by: Jess Frazelle --- rust/kcl-lib/Cargo.toml | 5 - rust/kcl-lib/e2e/modify/main.rs | 232 ----------------- rust/kcl-lib/src/engine/mod.rs | 33 ++- rust/kcl-lib/src/execution/exec_ast.rs | 10 +- rust/kcl-lib/src/execution/id_generator.rs | 2 +- rust/kcl-lib/src/execution/mod.rs | 6 +- rust/kcl-lib/src/lib.rs | 2 +- rust/kcl-lib/src/parsing/ast/mod.rs | 1 - rust/kcl-lib/src/parsing/ast/modify.rs | 285 --------------------- rust/kcl-lib/src/std/appearance.rs | 5 +- 10 files changed, 38 insertions(+), 543 deletions(-) delete mode 100644 rust/kcl-lib/e2e/modify/main.rs delete mode 100644 rust/kcl-lib/src/parsing/ast/modify.rs diff --git a/rust/kcl-lib/Cargo.toml b/rust/kcl-lib/Cargo.toml index 31d1e326f..f771c73fc 100644 --- a/rust/kcl-lib/Cargo.toml +++ b/rust/kcl-lib/Cargo.toml @@ -153,8 +153,3 @@ harness = false name = "executor" path = "e2e/executor/main.rs" required-features = ["engine"] - -[[test]] -name = "modify" -path = "e2e/modify/main.rs" -required-features = ["engine"] diff --git a/rust/kcl-lib/e2e/modify/main.rs b/rust/kcl-lib/e2e/modify/main.rs deleted file mode 100644 index c443437f4..000000000 --- a/rust/kcl-lib/e2e/modify/main.rs +++ /dev/null @@ -1,232 +0,0 @@ -use anyhow::Result; -use kcl_lib::{ - exec::{KclValue, PlaneType}, - modify_ast_for_sketch, ExecState, ExecutorContext, ModuleId, Program, SourceRange, -}; -use kittycad_modeling_cmds::{each_cmd as mcmd, length_unit::LengthUnit, shared::Point3d, ModelingCmd}; -use pretty_assertions::assert_eq; - -/// Setup the engine and parse code for an ast. -async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, ModuleId, uuid::Uuid)> { - let program = Program::parse_no_errs(code)?; - let ctx = kcl_lib::ExecutorContext::new_with_default_client(Default::default()).await?; - let mut exec_state = ExecState::new(&ctx); - let result = ctx.run(&program, &mut exec_state).await?; - let outcome = exec_state.to_wasm_outcome(result.0).await; - - // We need to get the sketch ID. - let KclValue::Sketch { value: sketch } = outcome.variables.get(name).unwrap() else { - anyhow::bail!("part001 not found in: {:?}", outcome.variables); - }; - let sketch_id = sketch.id; - - let plane_id = uuid::Uuid::new_v4(); - ctx.engine - .send_modeling_cmd( - plane_id, - SourceRange::default(), - &ModelingCmd::from(mcmd::MakePlane { - clobber: false, - origin: Point3d::default(), - size: LengthUnit(60.0), - x_axis: Point3d { x: 1.0, y: 0.0, z: 0.0 }, - y_axis: Point3d { x: 0.0, y: 1.0, z: 0.0 }, - hide: Some(true), - }), - ) - .await?; - - // Enter sketch mode. - // We can't get control points without being in sketch mode. - // You can however get path info without sketch mode. - ctx.engine - .send_modeling_cmd( - uuid::Uuid::new_v4(), - SourceRange::default(), - &ModelingCmd::from(mcmd::EnableSketchMode { - animated: false, - ortho: true, - entity_id: plane_id, - planar_normal: Some(Point3d { x: 0.0, y: 0.0, z: 1.0 }), - adjust_camera: false, - }), - ) - .await?; - - Ok((ctx, program, ModuleId::default(), sketch_id)) -} - -#[tokio::test(flavor = "multi_thread")] -async fn kcl_test_modify_sketch_part001() { - let name = "part001"; - let code = format!( - r#"{} = startSketchOn(XY) - |> startProfileAt([8.41, 5.78], %) - |> line(end = [7.37, -11]) - |> line(end = [-8.69, -3.75]) - |> line(end = [-5, 4.25]) -"#, - name - ); - - let (ctx, program, module_id, sketch_id) = setup(&code, name).await.unwrap(); - let mut new_program = program.clone(); - let new_code = modify_ast_for_sketch(&ctx.engine, &mut new_program, module_id, name, PlaneType::XY, sketch_id) - .await - .unwrap(); - - // Make sure the code is the same. - assert_eq!(code, new_code); - // Make sure the program is the same. - assert_eq!(new_program, program); -} - -#[tokio::test(flavor = "multi_thread")] -async fn kcl_test_modify_sketch_part002() { - let name = "part002"; - let code = format!( - r#"{} = startSketchOn(XY) - |> startProfileAt([8.41, 5.78], %) - |> line(end = [7.42, -8.62]) - |> line(end = [-6.38, -3.51]) - |> line(end = [-3.77, 3.56]) -"#, - name - ); - - let (ctx, program, module_id, sketch_id) = setup(&code, name).await.unwrap(); - let mut new_program = program.clone(); - let new_code = modify_ast_for_sketch(&ctx.engine, &mut new_program, module_id, name, PlaneType::XY, sketch_id) - .await - .unwrap(); - - // Make sure the code is the same. - assert_eq!(code, new_code); - // Make sure the program is the same. - assert_eq!(new_program, program); -} - -#[tokio::test(flavor = "multi_thread")] -#[ignore] // until KittyCAD/engine#1434 is fixed. -async fn kcl_test_modify_close_sketch() { - let name = "part002"; - let code = format!( - r#"{} = startSketchOn(XY) - |> startProfileAt([7.91, 3.89], %) - |> line(end = [7.42, -8.62]) - |> line(end = [-6.38, -3.51]) - |> line(end = [-3.77, 3.56]) - |> close() -"#, - name - ); - - let (ctx, program, module_id, sketch_id) = setup(&code, name).await.unwrap(); - let mut new_program = program.clone(); - let new_code = modify_ast_for_sketch(&ctx.engine, &mut new_program, module_id, name, PlaneType::XY, sketch_id) - .await - .unwrap(); - - // Make sure the code is the same. - assert_eq!(code, new_code); - // Make sure the program is the same. - assert_eq!(new_program, program); -} - -#[tokio::test(flavor = "multi_thread")] -async fn kcl_test_modify_line_to_close_sketch() { - let name = "part002"; - let code = format!( - r#"const {} = startSketchOn(XY) - |> startProfileAt([7.91, 3.89], %) - |> line(end = [7.42, -8.62]) - |> line(end = [-6.38, -3.51]) - |> line(end = [-3.77, 3.56]) - |> line(endAbsolute = [7.91, 3.89]) -"#, - name - ); - - let (ctx, program, module_id, sketch_id) = setup(&code, name).await.unwrap(); - let mut new_program = program.clone(); - let new_code = modify_ast_for_sketch(&ctx.engine, &mut new_program, module_id, name, PlaneType::XY, sketch_id) - .await - .unwrap(); - - // Make sure the code is the same. - assert_eq!( - new_code, - format!( - r#"{} = startSketchOn(XY) - |> startProfileAt([7.91, 3.89], %) - |> line(end = [7.42, -8.62]) - |> line(end = [-6.38, -3.51]) - |> line(end = [-3.77, 3.56]) - |> close() -"#, - name - ) - ); -} - -#[tokio::test(flavor = "multi_thread")] -async fn kcl_test_modify_with_constraint() { - let name = "part002"; - let code = format!( - r#"const thing = 12 -const {} = startSketchOn(XY) - |> startProfileAt([7.91, 3.89], %) - |> line(end = [7.42, -8.62]) - |> line(end = [-6.38, -3.51]) - |> line(end = [-3.77, 3.56]) - |> line(endAbsolute = [thing, 3.89]) -"#, - name - ); - - let (ctx, program, module_id, sketch_id) = setup(&code, name).await.unwrap(); - let mut new_program = program.clone(); - let result = modify_ast_for_sketch(&ctx.engine, &mut new_program, module_id, name, PlaneType::XY, sketch_id).await; - - assert!(result.is_err()); - assert_eq!( - result.unwrap_err().message(), - "Sketch part002 is constrained `partial` and cannot be modified", - ); -} - -#[tokio::test(flavor = "multi_thread")] -async fn kcl_test_modify_line_should_close_sketch() { - let name = "part003"; - let code = format!( - r#"const {} = startSketchOn(XY) - |> startProfileAt([13.69, 3.8], %) - |> line(end = [4.23, -11.79]) - |> line(end = [-10.7, -1.16]) - |> line(end = [-3.72, 8.69]) - |> line(end = [10.19, 4.26]) -"#, - name - ); - - let (ctx, program, module_id, sketch_id) = setup(&code, name).await.unwrap(); - let mut new_program = program.clone(); - let new_code = modify_ast_for_sketch(&ctx.engine, &mut new_program, module_id, name, PlaneType::XY, sketch_id) - .await - .unwrap(); - - // Make sure the code is the same. - assert_eq!( - new_code, - format!( - r#"{} = startSketchOn(XY) - |> startProfileAt([13.69, 3.8], %) - |> line(end = [4.23, -11.79]) - |> line(end = [-10.7, -1.16]) - |> line(end = [-3.72, 8.69]) - |> close() -"#, - name - ) - ); -} diff --git a/rust/kcl-lib/src/engine/mod.rs b/rust/kcl-lib/src/engine/mod.rs index fd20fcd80..3a2711850 100644 --- a/rust/kcl-lib/src/engine/mod.rs +++ b/rust/kcl-lib/src/engine/mod.rs @@ -170,7 +170,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { self.clear_queues().await; self.batch_modeling_cmd( - uuid::Uuid::new_v4(), + id_generator.next_uuid(), source_range, &ModelingCmd::SceneClearAll(mcmd::SceneClearAll::default()), ) @@ -195,9 +195,10 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { &self, visible: bool, source_range: SourceRange, + id_generator: &mut IdGenerator, ) -> Result<(), crate::errors::KclError> { self.batch_modeling_cmd( - uuid::Uuid::new_v4(), + id_generator.next_uuid(), source_range, &ModelingCmd::from(mcmd::EdgeLinesVisible { hidden: !visible }), ) @@ -231,10 +232,11 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { &self, units: crate::UnitLength, source_range: SourceRange, + id_generator: &mut IdGenerator, ) -> Result<(), crate::errors::KclError> { // Before we even start executing the program, set the units. self.batch_modeling_cmd( - uuid::Uuid::new_v4(), + id_generator.next_uuid(), source_range, &ModelingCmd::from(mcmd::SetSceneUnits { unit: units.into() }), ) @@ -248,15 +250,18 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { &self, settings: &crate::ExecutorSettings, source_range: SourceRange, + id_generator: &mut IdGenerator, ) -> Result<(), crate::errors::KclError> { // Set the edge visibility. - self.set_edge_visibility(settings.highlight_edges, source_range).await?; + self.set_edge_visibility(settings.highlight_edges, source_range, id_generator) + .await?; // Change the units. - self.set_units(settings.units, source_range).await?; + self.set_units(settings.units, source_range, id_generator).await?; // Send the command to show the grid. - self.modify_grid(!settings.show_grid, source_range).await?; + self.modify_grid(!settings.show_grid, source_range, id_generator) + .await?; // We do not have commands for changing ssao on the fly. @@ -502,6 +507,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { y_axis: Point3d, color: Option, source_range: SourceRange, + id_generator: &mut IdGenerator, ) -> Result { // Create new default planes. let default_size = 100.0; @@ -524,7 +530,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { if let Some(color) = color { // Set the color. self.batch_modeling_cmd( - uuid::Uuid::new_v4(), + id_generator.next_uuid(), source_range, &ModelingCmd::from(mcmd::PlaneSetColor { color, plane_id }), ) @@ -615,7 +621,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { for (name, plane_id, x_axis, y_axis, color) in plane_settings { planes.insert( name, - self.make_default_plane(plane_id, x_axis, y_axis, color, source_range) + self.make_default_plane(plane_id, x_axis, y_axis, color, source_range, id_generator) .await?, ); } @@ -701,10 +707,15 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { })) } - async fn modify_grid(&self, hidden: bool, source_range: SourceRange) -> Result<(), KclError> { + async fn modify_grid( + &self, + hidden: bool, + source_range: SourceRange, + id_generator: &mut IdGenerator, + ) -> Result<(), KclError> { // Hide/show the grid. self.batch_modeling_cmd( - uuid::Uuid::new_v4(), + id_generator.next_uuid(), source_range, &ModelingCmd::from(mcmd::ObjectVisible { hidden, @@ -715,7 +726,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { // Hide/show the grid scale text. self.batch_modeling_cmd( - uuid::Uuid::new_v4(), + id_generator.next_uuid(), source_range, &ModelingCmd::from(mcmd::ObjectVisible { hidden, diff --git a/rust/kcl-lib/src/execution/exec_ast.rs b/rust/kcl-lib/src/execution/exec_ast.rs index cf95ad554..5877889f8 100644 --- a/rust/kcl-lib/src/execution/exec_ast.rs +++ b/rust/kcl-lib/src/execution/exec_ast.rs @@ -64,7 +64,11 @@ impl ExecutorContext { let new_units = exec_state.length_unit(); if !self.engine.execution_kind().await.is_isolated() { self.engine - .set_units(new_units.into(), annotation.as_source_range()) + .set_units( + new_units.into(), + annotation.as_source_range(), + exec_state.id_generator(), + ) .await?; } } else { @@ -143,7 +147,9 @@ impl ExecutorContext { // command and we'd need to flush the batch again. // This avoids that. if !exec_kind.is_isolated() && new_units != old_units && *path != ModulePath::Main { - self.engine.set_units(old_units.into(), Default::default()).await?; + self.engine + .set_units(old_units.into(), Default::default(), exec_state.id_generator()) + .await?; } self.engine.replace_execution_kind(original_execution).await; diff --git a/rust/kcl-lib/src/execution/id_generator.rs b/rust/kcl-lib/src/execution/id_generator.rs index e1cd37e0a..4fb1d0890 100644 --- a/rust/kcl-lib/src/execution/id_generator.rs +++ b/rust/kcl-lib/src/execution/id_generator.rs @@ -2,7 +2,7 @@ use crate::execution::ModuleId; -const NAMESPACE_KCL: uuid::Uuid = uuid::uuid!("efcd6508-4ce6-4a09-8317-e6a6994a3cd7"); +const NAMESPACE_KCL: uuid::Uuid = uuid::uuid!("8bda3118-75eb-58c7-a866-bef1dcb495e7"); /// A generator for ArtifactIds that can be stable across executions. #[derive(Debug, Clone, Default, PartialEq)] diff --git a/rust/kcl-lib/src/execution/mod.rs b/rust/kcl-lib/src/execution/mod.rs index 7306a90f7..be32e1de1 100644 --- a/rust/kcl-lib/src/execution/mod.rs +++ b/rust/kcl-lib/src/execution/mod.rs @@ -618,7 +618,7 @@ impl ExecutorContext { if reapply_settings && self .engine - .reapply_settings(&self.settings, Default::default()) + .reapply_settings(&self.settings, Default::default(), old_state.id_generator()) .await .is_err() { @@ -636,7 +636,7 @@ impl ExecutorContext { CacheResult::NoAction(true) => { if self .engine - .reapply_settings(&self.settings, Default::default()) + .reapply_settings(&self.settings, Default::default(), old_state.id_generator()) .await .is_ok() { @@ -737,7 +737,7 @@ impl ExecutorContext { // Re-apply the settings, in case the cache was busted. self.engine - .reapply_settings(&self.settings, Default::default()) + .reapply_settings(&self.settings, Default::default(), exec_state.id_generator()) .await .map_err(KclErrorWithOutputs::no_outputs)?; diff --git a/rust/kcl-lib/src/lib.rs b/rust/kcl-lib/src/lib.rs index f8d2c31a8..953ec6dac 100644 --- a/rust/kcl-lib/src/lib.rs +++ b/rust/kcl-lib/src/lib.rs @@ -93,7 +93,7 @@ pub use lsp::{ kcl::{Backend as KclLspBackend, Server as KclLspServerSubCommand}, }; pub use modules::ModuleId; -pub use parsing::ast::{modify::modify_ast_for_sketch, types::FormatOptions}; +pub use parsing::ast::types::FormatOptions; pub use settings::types::{project::ProjectConfiguration, Configuration, UnitLength}; pub use source_range::SourceRange; #[cfg(not(target_arch = "wasm32"))] diff --git a/rust/kcl-lib/src/parsing/ast/mod.rs b/rust/kcl-lib/src/parsing/ast/mod.rs index 5f58caf9c..ed23328e3 100644 --- a/rust/kcl-lib/src/parsing/ast/mod.rs +++ b/rust/kcl-lib/src/parsing/ast/mod.rs @@ -1,5 +1,4 @@ pub(crate) mod digest; -pub mod modify; pub mod types; use crate::{ diff --git a/rust/kcl-lib/src/parsing/ast/modify.rs b/rust/kcl-lib/src/parsing/ast/modify.rs deleted file mode 100644 index a55da9180..000000000 --- a/rust/kcl-lib/src/parsing/ast/modify.rs +++ /dev/null @@ -1,285 +0,0 @@ -use std::sync::Arc; - -use kcmc::{ - each_cmd as mcmd, ok_response::OkModelingCmdResponse, shared::PathCommand, websocket::OkWebSocketResponseData, - ModelingCmd, -}; -use kittycad_modeling_cmds as kcmc; - -use super::types::{CallExpressionKw, Identifier, LabeledArg, LiteralValue}; -use crate::{ - engine::EngineManager, - errors::{KclError, KclErrorDetails}, - execution::Point2d, - parsing::ast::types::{ - ArrayExpression, CallExpression, ConstraintLevel, FormatOptions, Literal, Node, PipeExpression, - PipeSubstitution, VariableDeclarator, - }, - source_range::SourceRange, - ModuleId, Program, -}; - -type Point3d = kcmc::shared::Point3d; - -#[derive(Debug)] -/// The control point data for a curve or line. -struct ControlPointData { - /// The control points for the curve or line. - points: Vec, - /// The command that created this curve or line. - _command: PathCommand, - /// The id of the curve or line. - _id: uuid::Uuid, -} - -const EPSILON: f64 = 0.015625; // or 2^-6 - -/// Update the AST to reflect the new state of the program after something like -/// a move or a new line. -pub async fn modify_ast_for_sketch( - engine: &Arc>, - program: &mut Program, - module_id: ModuleId, - // The name of the sketch. - sketch_name: &str, - // The type of plane the sketch is on. `XY` or `XZ`, etc - plane: crate::execution::PlaneType, - // The ID of the parent sketch. - sketch_id: uuid::Uuid, -) -> Result { - // First we need to check if this sketch is constrained (even partially). - // If it is, we cannot modify it. - - // Get the information about the sketch. - if let Some(ast_sketch) = program.ast.get_variable(sketch_name) { - let constraint_level = match ast_sketch { - super::types::Definition::Variable(var) => var.get_constraint_level(), - super::types::Definition::Import(import) => import.get_constraint_level(), - super::types::Definition::Type(_) => ConstraintLevel::Ignore { - source_ranges: Vec::new(), - }, - }; - match &constraint_level { - ConstraintLevel::None { source_ranges: _ } => {} - ConstraintLevel::Ignore { source_ranges: _ } => {} - ConstraintLevel::Partial { - source_ranges: _, - levels, - } => { - return Err(KclError::Engine(KclErrorDetails { - message: format!( - "Sketch {} is constrained `{}` and cannot be modified", - sketch_name, constraint_level - ), - source_ranges: levels.get_all_partial_or_full_source_ranges(), - })); - } - ConstraintLevel::Full { source_ranges } => { - return Err(KclError::Engine(KclErrorDetails { - message: format!( - "Sketch {} is constrained `{}` and cannot be modified", - sketch_name, constraint_level - ), - source_ranges: source_ranges.clone(), - })); - } - } - } - - // Let's start by getting the path info. - - // Let's get the path info. - let resp = engine - .send_modeling_cmd( - uuid::Uuid::new_v4(), - SourceRange::default(), - &ModelingCmd::PathGetInfo(mcmd::PathGetInfo { path_id: sketch_id }), - ) - .await?; - - let OkWebSocketResponseData::Modeling { - modeling_response: OkModelingCmdResponse::PathGetInfo(path_info), - } = &resp - else { - return Err(KclError::Engine(KclErrorDetails { - message: format!("Get path info response was not as expected: {:?}", resp), - source_ranges: vec![SourceRange::default()], - })); - }; - - // Now let's get the control points for all the segments. - // TODO: We should probably await all these at once so we aren't going one by one. - // But I guess this is fine for now. - // We absolutely have to preserve the order of the control points. - let mut control_points = Vec::new(); - for segment in &path_info.segments { - if let Some(command_id) = &segment.command_id { - let cmd = ModelingCmd::from(mcmd::CurveGetControlPoints { - curve_id: (*command_id).into(), - }); - let h = engine.send_modeling_cmd(uuid::Uuid::new_v4(), SourceRange::default(), &cmd); - - let OkWebSocketResponseData::Modeling { - modeling_response: OkModelingCmdResponse::CurveGetControlPoints(data), - } = h.await? - else { - return Err(KclError::Engine(KclErrorDetails { - message: format!("Curve get control points response was not as expected: {:?}", resp), - source_ranges: vec![SourceRange::default()], - })); - }; - - control_points.push(ControlPointData { - points: data.control_points.clone(), - _command: segment.command, - _id: (*command_id).into(), - }); - } - } - - if control_points.is_empty() { - return Err(KclError::Engine(KclErrorDetails { - message: format!("No control points found for sketch {}", sketch_name), - source_ranges: vec![SourceRange::default()], - })); - } - - let first_control_points = control_points.first().ok_or_else(|| { - KclError::Engine(KclErrorDetails { - message: format!("No control points found for sketch {}", sketch_name), - source_ranges: vec![SourceRange::default()], - }) - })?; - - let mut additional_lines = Vec::new(); - let mut last_point = first_control_points.points[1]; - for control_point in control_points[1..].iter() { - additional_lines.push([ - (control_point.points[1].x - last_point.x), - (control_point.points[1].y - last_point.y), - ]); - last_point = Point3d { - x: control_point.points[1].x, - y: control_point.points[1].y, - z: control_point.points[1].z, - }; - } - - // Okay now let's recalculate the sketch from the control points. - let start_sketch_at_end = Point3d { - x: (first_control_points.points[1].x - first_control_points.points[0].x), - y: (first_control_points.points[1].y - first_control_points.points[0].y), - z: (first_control_points.points[1].z - first_control_points.points[0].z), - }; - let sketch = create_start_sketch_on( - sketch_name, - [first_control_points.points[0].x, first_control_points.points[0].y], - [start_sketch_at_end.x, start_sketch_at_end.y], - plane, - additional_lines, - )?; - - // Add the sketch back to the program. - program.ast.replace_variable(sketch_name, sketch); - - let recasted = program.ast.recast(&FormatOptions::default(), 0); - - // Re-parse the ast so we get the correct source ranges. - program.ast = crate::parsing::parse_str(&recasted, module_id).parse_errs_as_err()?; - - Ok(recasted) -} - -/// Create a pipe expression that starts a sketch at the given point and draws a line to the given point. -fn create_start_sketch_on( - name: &str, - start: [f64; 2], - end: [f64; 2], - plane: crate::execution::PlaneType, - additional_lines: Vec<[f64; 2]>, -) -> Result, KclError> { - let start_sketch_on = CallExpression::new("startSketchOn", vec![Literal::new(plane.to_string().into()).into()])?; - let start_profile_at = CallExpression::new( - "startProfileAt", - vec![ - ArrayExpression::new(vec![ - Literal::new(LiteralValue::from_f64_no_uom(round_before_recast(start[0]))).into(), - Literal::new(LiteralValue::from_f64_no_uom(round_before_recast(start[1]))).into(), - ]) - .into(), - PipeSubstitution::new().into(), - ], - )?; - - // Keep track of where we are so we can close the sketch if we need to. - let mut current_position = Point2d { - x: start[0], - y: start[1], - }; - current_position.x += end[0]; - current_position.y += end[1]; - - let expr = ArrayExpression::new(vec![ - Literal::new(LiteralValue::from_f64_no_uom(round_before_recast(end[0]))).into(), - Literal::new(LiteralValue::from_f64_no_uom(round_before_recast(end[1]))).into(), - ]) - .into(); - let initial_line = CallExpressionKw::new( - "line", - None, - vec![LabeledArg { - label: Node::no_src(super::types::Identifier { - name: "end".to_owned(), - digest: None, - }), - arg: expr, - }], - )?; - - let mut pipe_body = vec![start_sketch_on.into(), start_profile_at.into(), initial_line.into()]; - - for (index, line) in additional_lines.iter().enumerate() { - current_position.x += line[0]; - current_position.y += line[1]; - - // If we are on the last line, check if we have to close the sketch. - if index == additional_lines.len() - 1 { - let diff_x = (current_position.x - start[0]).abs(); - let diff_y = (current_position.y - start[1]).abs(); - // Compare the end of the last line to the start of the first line. - // This is a bit more lenient if you look at the value of epsilon. - if diff_x <= EPSILON && diff_y <= EPSILON { - // We have to close the sketch. - let close = CallExpressionKw::new("close", None, vec![])?; - pipe_body.push(close.into()); - break; - } - } - - // TODO: we should check if we should close the sketch. - let expr = ArrayExpression::new(vec![ - Literal::new(LiteralValue::from_f64_no_uom(round_before_recast(line[0]))).into(), - Literal::new(LiteralValue::from_f64_no_uom(round_before_recast(line[1]))).into(), - ]) - .into(); - let line = CallExpressionKw::new( - "line", - None, - vec![LabeledArg { - arg: expr, - label: Node::no_src(Identifier { - name: "end".to_owned(), - digest: None, - }), - }], - )?; - pipe_body.push(line.into()); - } - - Ok(VariableDeclarator::new(name, PipeExpression::new(pipe_body).into())) -} - -fn round_before_recast(num: f64) -> f64 { - // We use 2 decimal places. - (num * 100.0).round() / 100.0 -} diff --git a/rust/kcl-lib/src/std/appearance.rs b/rust/kcl-lib/src/std/appearance.rs index c19620bf9..d92552a2f 100644 --- a/rust/kcl-lib/src/std/appearance.rs +++ b/rust/kcl-lib/src/std/appearance.rs @@ -66,7 +66,7 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result, roughness: Option, + exec_state: &mut ExecState, args: Args, ) -> Result, KclError> { for solid in &solids { @@ -306,7 +307,7 @@ async fn inner_appearance( }; args.batch_modeling_cmd( - uuid::Uuid::new_v4(), + exec_state.next_uuid(), ModelingCmd::from(mcmd::ObjectSetMaterialParamsPbr { object_id: solid.id, color,