From e7d2289a14b17bea12f2fe5984d25156c930d747 Mon Sep 17 00:00:00 2001 From: Ben Crabbe Date: Fri, 16 May 2025 23:02:30 +0100 Subject: [PATCH] Revolve adjacency info (#7008) * check edge colinear * cleanup * revert cargo.toml * revert cargo.toml properly * undo yarn.lock * clippy * add new sim test * move tolerance2 * typo Signed-off-by: Jess Frazelle * fmt Signed-off-by: Jess Frazelle * update snap Signed-off-by: Jess Frazelle * push real snap Signed-off-by: Jess Frazelle * update tests Signed-off-by: Jess Frazelle --------- Signed-off-by: Jess Frazelle Co-authored-by: Jess Frazelle Co-authored-by: Jess Frazelle --- _typos.toml | 3 +- rust/Cargo.lock | 102 +++++ rust/kcl-lib/Cargo.toml | 1 + rust/kcl-lib/src/simulation_tests.rs | 22 ++ rust/kcl-lib/src/std/clone.rs | 1 + rust/kcl-lib/src/std/extrude.rs | 7 +- rust/kcl-lib/src/std/loft.rs | 1 + rust/kcl-lib/src/std/revolve.rs | 28 +- rust/kcl-lib/src/std/sweep.rs | 1 + .../revolve-colinear/artifact_commands.snap | 210 ++++++++++ .../artifact_graph_flowchart.snap | 6 + .../artifact_graph_flowchart.snap.md | 52 +++ rust/kcl-lib/tests/revolve-colinear/ast.snap | 372 ++++++++++++++++++ rust/kcl-lib/tests/revolve-colinear/input.kcl | 7 + rust/kcl-lib/tests/revolve-colinear/ops.snap | 105 +++++ .../revolve-colinear/program_memory.snap | 179 +++++++++ .../tests/revolve-colinear/rendered_model.png | Bin 0 -> 93302 bytes .../tests/revolve-colinear/unparsed.snap | 11 + 18 files changed, 1103 insertions(+), 5 deletions(-) create mode 100644 rust/kcl-lib/tests/revolve-colinear/artifact_commands.snap create mode 100644 rust/kcl-lib/tests/revolve-colinear/artifact_graph_flowchart.snap create mode 100644 rust/kcl-lib/tests/revolve-colinear/artifact_graph_flowchart.snap.md create mode 100644 rust/kcl-lib/tests/revolve-colinear/ast.snap create mode 100644 rust/kcl-lib/tests/revolve-colinear/input.kcl create mode 100644 rust/kcl-lib/tests/revolve-colinear/ops.snap create mode 100644 rust/kcl-lib/tests/revolve-colinear/program_memory.snap create mode 100644 rust/kcl-lib/tests/revolve-colinear/rendered_model.png create mode 100644 rust/kcl-lib/tests/revolve-colinear/unparsed.snap diff --git a/_typos.toml b/_typos.toml index 2677ece60..1b2e6286b 100644 --- a/_typos.toml +++ b/_typos.toml @@ -21,7 +21,7 @@ extend-exclude = [ ] [default.extend-words] -metalness = "metalness" # appearance API +metalness = "metalness" # appearance API Hom = "Hom" # short for homogenous typ = "typ" # used to declare a variable named 'type' which is a reserved keyword in Rust ue = "ue" # short for UnaryExpression @@ -29,6 +29,7 @@ THRE = "THRE" # Weird bug that wrongly detects THREEjs as a typo nwo = "nwo" # don't know what this is about tbh "ot" = "ot" # some abbreviation, idk what "oe" = "oe" # some abbreviation, idk what +"colinear" = "colinear" # some engine shit, kidding [default] extend-ignore-identifiers-re = [ diff --git a/rust/Cargo.lock b/rust/Cargo.lock index a2f999b25..cdb6deaf5 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1935,6 +1935,7 @@ dependencies = [ "measurements", "miette", "mime_guess", + "nalgebra-glm", "parse-display 0.10.0", "pretty_assertions", "pyo3", @@ -2254,6 +2255,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + [[package]] name = "measurements" version = "0.11.0" @@ -2374,6 +2385,33 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "nalgebra" +version = "0.33.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b" +dependencies = [ + "approx 0.5.1", + "matrixmultiply", + "num-complex", + "num-rational", + "num-traits 0.2.19", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-glm" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e441f43bccdf40cb6bd4294321e6983c5bc7b9886112d19fd4c9813976b117e4" +dependencies = [ + "approx 0.5.1", + "nalgebra", + "num-traits 0.2.19", + "simba", +] + [[package]] name = "newline-converter" version = "0.3.0" @@ -2413,6 +2451,15 @@ dependencies = [ "num-traits 0.2.19", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits 0.2.19", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -2443,6 +2490,17 @@ dependencies = [ "num-modular", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits 0.2.19", +] + [[package]] name = "num-traits" version = "0.1.43" @@ -2596,6 +2654,12 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pbkdf2" version = "0.12.2" @@ -3094,6 +3158,12 @@ dependencies = [ "getrandom 0.3.1", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.10.0" @@ -3377,6 +3447,15 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "safe_arch" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +dependencies = [ + "bytemuck", +] + [[package]] name = "same-file" version = "1.0.6" @@ -3632,6 +3711,19 @@ dependencies = [ "libc", ] +[[package]] +name = "simba" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa" +dependencies = [ + "approx 0.5.1", + "num-complex", + "num-traits 0.2.19", + "paste", + "wide", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -4732,6 +4824,16 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "wide" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b5576b9a81633f3e8df296ce0063042a73507636cbe956c61133dd7034ab22" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/rust/kcl-lib/Cargo.toml b/rust/kcl-lib/Cargo.toml index 69159aeb7..310aef0c9 100644 --- a/rust/kcl-lib/Cargo.toml +++ b/rust/kcl-lib/Cargo.toml @@ -50,6 +50,7 @@ lazy_static = { workspace = true } measurements = "0.11.0" miette = { workspace = true } mime_guess = "2.0.5" +nalgebra-glm = "0.19.0" parse-display = "0.10.0" pyo3 = { workspace = true, optional = true } regex = "1.11.1" diff --git a/rust/kcl-lib/src/simulation_tests.rs b/rust/kcl-lib/src/simulation_tests.rs index 83d4c70b0..36bb77a64 100644 --- a/rust/kcl-lib/src/simulation_tests.rs +++ b/rust/kcl-lib/src/simulation_tests.rs @@ -3107,6 +3107,28 @@ mod sketch_on_face_union { super::execute(TEST_NAME, true).await } } +mod revolve_colinear { + const TEST_NAME: &str = "revolve-colinear"; + + /// Test parsing KCL. + #[test] + fn parse() { + super::parse(TEST_NAME) + } + + /// Test that parsing and unparsing KCL produces the original KCL input. + #[tokio::test(flavor = "multi_thread")] + async fn unparse() { + super::unparse(TEST_NAME).await + } + + /// Test that KCL is executed correctly. + #[tokio::test(flavor = "multi_thread")] + #[ignore] // until https://github.com/KittyCAD/engine/pull/3417 lands + async fn kcl_test_execute() { + super::execute(TEST_NAME, true).await + } +} mod subtract_regression07 { const TEST_NAME: &str = "subtract_regression07"; diff --git a/rust/kcl-lib/src/std/clone.rs b/rust/kcl-lib/src/std/clone.rs index ae7c4725c..57651eaa0 100644 --- a/rust/kcl-lib/src/std/clone.rs +++ b/rust/kcl-lib/src/std/clone.rs @@ -161,6 +161,7 @@ async fn fix_tags_and_references( }, exec_state, args, + None, ) .await?; diff --git a/rust/kcl-lib/src/std/extrude.rs b/rust/kcl-lib/src/std/extrude.rs index e450be2f2..d06d787df 100644 --- a/rust/kcl-lib/src/std/extrude.rs +++ b/rust/kcl-lib/src/std/extrude.rs @@ -220,6 +220,7 @@ async fn inner_extrude( }, exec_state, &args, + None, ) .await?, ); @@ -234,6 +235,7 @@ pub(crate) struct NamedCapTags<'a> { pub end: Option<&'a TagNode>, } +#[allow(clippy::too_many_arguments)] pub(crate) async fn do_post_extrude<'a>( sketch: &Sketch, #[cfg(feature = "artifact-graph")] solid_id: ArtifactId, @@ -242,6 +244,7 @@ pub(crate) async fn do_post_extrude<'a>( named_cap_tags: &'a NamedCapTags<'a>, exec_state: &mut ExecState, args: &Args, + edge_id: Option, ) -> Result { // Bring the object to the front of the scene. // See: https://github.com/KittyCAD/modeling-app/issues/806 @@ -251,7 +254,9 @@ pub(crate) async fn do_post_extrude<'a>( ) .await?; - let any_edge_id = if let Some(edge_id) = sketch.mirror { + let any_edge_id = if let Some(id) = edge_id { + id + } else if let Some(edge_id) = sketch.mirror { edge_id } else { // The "get extrusion face info" API call requires *any* edge on the sketch being extruded. diff --git a/rust/kcl-lib/src/std/loft.rs b/rust/kcl-lib/src/std/loft.rs index 2a5b8485a..a4237d3ae 100644 --- a/rust/kcl-lib/src/std/loft.rs +++ b/rust/kcl-lib/src/std/loft.rs @@ -187,6 +187,7 @@ async fn inner_loft( }, exec_state, &args, + None, ) .await?, )) diff --git a/rust/kcl-lib/src/std/revolve.rs b/rust/kcl-lib/src/std/revolve.rs index 1413186b2..16bdca022 100644 --- a/rust/kcl-lib/src/std/revolve.rs +++ b/rust/kcl-lib/src/std/revolve.rs @@ -20,6 +20,8 @@ use crate::{ std::{axis_or_reference::Axis2dOrEdgeReference, extrude::do_post_extrude, Args}, }; +extern crate nalgebra_glm as glm; + /// Revolve a sketch or set of sketches around an axis. pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result { let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?; @@ -131,8 +133,9 @@ async fn inner_revolve( let mut solids = Vec::new(); for sketch in &sketches { let id = exec_state.next_uuid(); + let tolerance = tolerance.as_ref().map(|t| t.to_mm()).unwrap_or(DEFAULT_TOLERANCE); - match &axis { + let direction = match &axis { Axis2dOrEdgeReference::Axis { direction, origin } => { args.batch_modeling_cmd( id, @@ -149,12 +152,13 @@ async fn inner_revolve( y: LengthUnit(origin[1].to_mm()), z: LengthUnit(0.0), }, - tolerance: LengthUnit(tolerance.as_ref().map(|t| t.to_mm()).unwrap_or(DEFAULT_TOLERANCE)), + tolerance: LengthUnit(tolerance), axis_is_2d: true, opposite: opposite.clone(), }), ) .await?; + glm::DVec2::new(direction[0].to_mm(), direction[1].to_mm()) } Axis2dOrEdgeReference::Edge(edge) => { let edge_id = edge.get_engine_id(exec_state, &args)?; @@ -164,12 +168,29 @@ async fn inner_revolve( angle, target: sketch.id.into(), edge_id, - tolerance: LengthUnit(tolerance.as_ref().map(|t| t.to_mm()).unwrap_or(DEFAULT_TOLERANCE)), + tolerance: LengthUnit(tolerance), opposite: opposite.clone(), }), ) .await?; + //TODO: fix me! Need to be able to calculate this to ensure the path isn't colinear + glm::DVec2::new(0.0, 1.0) } + }; + + let mut edge_id = None; + // If an edge lies on the axis of revolution it will not exist after the revolve, so + // it cannot be used to retrieve data about the solid + for path in sketch.paths.clone() { + let from = path.get_from(); + let to = path.get_to(); + + let dir = glm::DVec2::new(to[0].n - from[0].n, to[1].n - from[1].n); + if glm::are_collinear2d(&dir, &direction, tolerance) { + continue; + } + edge_id = Some(path.get_id()); + break; } solids.push( @@ -185,6 +206,7 @@ async fn inner_revolve( }, exec_state, &args, + edge_id, ) .await?, ); diff --git a/rust/kcl-lib/src/std/sweep.rs b/rust/kcl-lib/src/std/sweep.rs index 0bfbc0267..732c8fd77 100644 --- a/rust/kcl-lib/src/std/sweep.rs +++ b/rust/kcl-lib/src/std/sweep.rs @@ -228,6 +228,7 @@ async fn inner_sweep( }, exec_state, &args, + None, ) .await?, ); diff --git a/rust/kcl-lib/tests/revolve-colinear/artifact_commands.snap b/rust/kcl-lib/tests/revolve-colinear/artifact_commands.snap new file mode 100644 index 000000000..9c91526e9 --- /dev/null +++ b/rust/kcl-lib/tests/revolve-colinear/artifact_commands.snap @@ -0,0 +1,210 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Artifact commands revolve-colinear.kcl +--- +[ + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "edge_lines_visible", + "hidden": false + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "object_visible", + "object_id": "[uuid]", + "hidden": true + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "object_visible", + "object_id": "[uuid]", + "hidden": true + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "make_plane", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "x_axis": { + "x": 1.0, + "y": 0.0, + "z": 0.0 + }, + "y_axis": { + "x": 0.0, + "y": 0.0, + "z": 1.0 + }, + "size": 60.0, + "clobber": false, + "hide": true + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": { + "x": 0.0, + "y": -1.0, + "z": 0.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "move_path_pen", + "path": "[uuid]", + "to": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "start_path" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 0.0, + "y": 2.0, + "z": 0.0 + }, + "relative": true + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 1.0, + "y": 0.0, + "z": 0.0 + }, + "relative": true + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 0.0, + "y": -2.0, + "z": 0.0 + }, + "relative": true + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "close_path", + "path_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "object_bring_to_front", + "object_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "revolve", + "target": "[uuid]", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "axis": { + "x": 0.0, + "y": 1.0, + "z": 0.0 + }, + "axis_is_2d": true, + "angle": { + "unit": "degrees", + "value": 360.0 + }, + "tolerance": 0.0000001, + "opposite": "None" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_adjacency_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_extrusion_face_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + } +] diff --git a/rust/kcl-lib/tests/revolve-colinear/artifact_graph_flowchart.snap b/rust/kcl-lib/tests/revolve-colinear/artifact_graph_flowchart.snap new file mode 100644 index 000000000..88364e6e3 --- /dev/null +++ b/rust/kcl-lib/tests/revolve-colinear/artifact_graph_flowchart.snap @@ -0,0 +1,6 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Artifact graph flowchart revolve-colinear.kcl +extension: md +snapshot_kind: binary +--- diff --git a/rust/kcl-lib/tests/revolve-colinear/artifact_graph_flowchart.snap.md b/rust/kcl-lib/tests/revolve-colinear/artifact_graph_flowchart.snap.md new file mode 100644 index 000000000..12800ed18 --- /dev/null +++ b/rust/kcl-lib/tests/revolve-colinear/artifact_graph_flowchart.snap.md @@ -0,0 +1,52 @@ +```mermaid +flowchart LR + subgraph path2 [Path] + 2["Path
[29, 54, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 3["Segment
[60, 77, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 2 }] + 4["Segment
[83, 100, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 3 }] + 5["Segment
[106, 124, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 4 }] + 6["Segment
[130, 137, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 5 }] + 7[Solid2d] + end + 1["Plane
[6, 23, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 0 }] + 8["Sweep Revolve
[143, 160, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 6 }] + 9[Wall] + %% face_code_ref=Missing NodePath + 10[Wall] + %% face_code_ref=Missing NodePath + 11[Wall] + %% face_code_ref=Missing NodePath + 12["SweepEdge Adjacent"] + 13["SweepEdge Adjacent"] + 1 --- 2 + 2 --- 3 + 2 --- 4 + 2 --- 5 + 2 --- 6 + 2 --- 7 + 2 ---- 8 + 8 <--x 4 + 4 --- 10 + 4 --- 12 + 8 <--x 5 + 5 --- 9 + 5 --- 13 + 8 <--x 6 + 6 --- 11 + 8 --- 9 + 8 --- 10 + 8 --- 11 + 8 --- 12 + 8 --- 13 + 12 <--x 9 + 9 --- 13 + 10 --- 12 + 13 <--x 11 +``` diff --git a/rust/kcl-lib/tests/revolve-colinear/ast.snap b/rust/kcl-lib/tests/revolve-colinear/ast.snap new file mode 100644 index 000000000..08b0103ee --- /dev/null +++ b/rust/kcl-lib/tests/revolve-colinear/ast.snap @@ -0,0 +1,372 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of parsing revolve-colinear.kcl +--- +{ + "Ok": { + "body": [ + { + "commentStart": 0, + "declaration": { + "commentStart": 0, + "end": 0, + "id": { + "commentStart": 0, + "end": 0, + "name": "sk0", + "start": 0, + "type": "Identifier" + }, + "init": { + "body": [ + { + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "name": { + "commentStart": 0, + "end": 0, + "name": "startSketchOn", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "name": { + "commentStart": 0, + "end": 0, + "name": "XZ", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "name": "at", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "elements": [ + { + "commentStart": 0, + "end": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + }, + { + "commentStart": 0, + "end": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + } + ], + "end": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "name": { + "commentStart": 0, + "end": 0, + "name": "startProfile", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "name": "length", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "name": { + "commentStart": 0, + "end": 0, + "name": "yLine", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "name": "length", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "raw": "1", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 1.0, + "suffix": "None" + } + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "name": { + "commentStart": 0, + "end": 0, + "name": "xLine", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "name": "length", + "start": 0, + "type": "Identifier" + }, + "arg": { + "argument": { + "commentStart": 0, + "end": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + }, + "commentStart": 0, + "end": 0, + "operator": "-", + "start": 0, + "type": "UnaryExpression", + "type": "UnaryExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "name": { + "commentStart": 0, + "end": 0, + "name": "yLine", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "name": { + "commentStart": 0, + "end": 0, + "name": "close", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "name": "axis", + "start": 0, + "type": "Identifier" + }, + "arg": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "name": { + "commentStart": 0, + "end": 0, + "name": "Y", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "name": { + "commentStart": 0, + "end": 0, + "name": "revolve", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + } + ], + "commentStart": 0, + "end": 0, + "start": 0, + "type": "PipeExpression", + "type": "PipeExpression" + }, + "start": 0, + "type": "VariableDeclarator" + }, + "end": 0, + "kind": "const", + "start": 0, + "type": "VariableDeclaration", + "type": "VariableDeclaration" + } + ], + "commentStart": 0, + "end": 0, + "start": 0 + } +} diff --git a/rust/kcl-lib/tests/revolve-colinear/input.kcl b/rust/kcl-lib/tests/revolve-colinear/input.kcl new file mode 100644 index 000000000..6fe44bfc8 --- /dev/null +++ b/rust/kcl-lib/tests/revolve-colinear/input.kcl @@ -0,0 +1,7 @@ +sk0 = startSketchOn(XZ) + |> startProfile(at = [0, 0]) + |> yLine(length = 2) + |> xLine(length = 1) + |> yLine(length = -2) + |> close() + |> revolve(axis = Y) diff --git a/rust/kcl-lib/tests/revolve-colinear/ops.snap b/rust/kcl-lib/tests/revolve-colinear/ops.snap new file mode 100644 index 000000000..814edd5ca --- /dev/null +++ b/rust/kcl-lib/tests/revolve-colinear/ops.snap @@ -0,0 +1,105 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Operations executed revolve-colinear.kcl +--- +[ + { + "labeledArgs": {}, + "name": "startSketchOn", + "sourceRange": [], + "type": "StdLibCall", + "unlabeledArg": { + "value": { + "type": "Plane", + "artifact_id": "[uuid]" + }, + "sourceRange": [] + } + }, + { + "type": "KclStdLibCall", + "name": "revolve", + "unlabeledArg": { + "value": { + "type": "Sketch", + "value": { + "artifactId": "[uuid]" + } + }, + "sourceRange": [] + }, + "labeledArgs": { + "axis": { + "value": { + "type": "Object", + "value": { + "direction": { + "type": "Array", + "value": [ + { + "type": "Number", + "value": 0.0, + "ty": { + "type": "Default", + "len": { + "type": "Mm" + }, + "angle": { + "type": "Degrees" + } + } + }, + { + "type": "Number", + "value": 1.0, + "ty": { + "type": "Default", + "len": { + "type": "Mm" + }, + "angle": { + "type": "Degrees" + } + } + } + ] + }, + "origin": { + "type": "Array", + "value": [ + { + "type": "Number", + "value": 0.0, + "ty": { + "type": "Default", + "len": { + "type": "Mm" + }, + "angle": { + "type": "Degrees" + } + } + }, + { + "type": "Number", + "value": 0.0, + "ty": { + "type": "Default", + "len": { + "type": "Mm" + }, + "angle": { + "type": "Degrees" + } + } + } + ] + } + } + }, + "sourceRange": [] + } + }, + "sourceRange": [] + } +] diff --git a/rust/kcl-lib/tests/revolve-colinear/program_memory.snap b/rust/kcl-lib/tests/revolve-colinear/program_memory.snap new file mode 100644 index 000000000..324a5c58c --- /dev/null +++ b/rust/kcl-lib/tests/revolve-colinear/program_memory.snap @@ -0,0 +1,179 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Variables in memory after executing revolve-colinear.kcl +--- +{ + "sk0": { + "type": "Solid", + "value": { + "type": "Solid", + "id": "[uuid]", + "artifactId": "[uuid]", + "value": [ + { + "faceId": "[uuid]", + "id": "[uuid]", + "sourceRange": [], + "tag": null, + "type": "extrudePlane" + }, + { + "faceId": "[uuid]", + "id": "[uuid]", + "sourceRange": [], + "tag": null, + "type": "extrudePlane" + }, + { + "faceId": "[uuid]", + "id": "[uuid]", + "sourceRange": [], + "tag": null, + "type": "extrudePlane" + } + ], + "sketch": { + "type": "Sketch", + "id": "[uuid]", + "paths": [ + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + 0.0, + 0.0 + ], + "tag": null, + "to": [ + 0.0, + 2.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + 0.0, + 2.0 + ], + "tag": null, + "to": [ + 1.0, + 2.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + 1.0, + 2.0 + ], + "tag": null, + "to": [ + 1.0, + 0.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + 1.0, + 0.0 + ], + "tag": null, + "to": [ + 0.0, + 0.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + } + ], + "on": { + "artifactId": "[uuid]", + "id": "[uuid]", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "units": { + "type": "Mm" + } + }, + "type": "plane", + "value": "XZ", + "xAxis": { + "x": 1.0, + "y": 0.0, + "z": 0.0, + "units": { + "type": "Unknown" + } + }, + "yAxis": { + "x": 0.0, + "y": 0.0, + "z": 1.0, + "units": { + "type": "Unknown" + } + } + }, + "start": { + "from": [ + 0.0, + 0.0 + ], + "to": [ + 0.0, + 0.0 + ], + "units": { + "type": "Mm" + }, + "tag": null, + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + } + }, + "artifactId": "[uuid]", + "originalId": "[uuid]", + "units": { + "type": "Mm" + } + }, + "height": 0.0, + "startCapId": null, + "endCapId": null, + "units": { + "type": "Mm" + }, + "sectional": false + } + } +} diff --git a/rust/kcl-lib/tests/revolve-colinear/rendered_model.png b/rust/kcl-lib/tests/revolve-colinear/rendered_model.png new file mode 100644 index 0000000000000000000000000000000000000000..eb8ac95b2fc199a978a382319aca5277e14f8ce9 GIT binary patch literal 93302 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 literal 0 HcmV?d00001 diff --git a/rust/kcl-lib/tests/revolve-colinear/unparsed.snap b/rust/kcl-lib/tests/revolve-colinear/unparsed.snap new file mode 100644 index 000000000..bf876898a --- /dev/null +++ b/rust/kcl-lib/tests/revolve-colinear/unparsed.snap @@ -0,0 +1,11 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of unparsing revolve-colinear.kcl +--- +sk0 = startSketchOn(XZ) + |> startProfile(at = [0, 0]) + |> yLine(length = 2) + |> xLine(length = 1) + |> yLine(length = -2) + |> close() + |> revolve(axis = Y)