diff --git a/flake.nix b/flake.nix index 3b5eaa344e4..f5116b2860e 100644 --- a/flake.nix +++ b/flake.nix @@ -92,6 +92,7 @@ NODE_ENV = "development"; RUSTFMT = "${pkgs.nightlyRustfmt}/bin/rustfmt"; CHROMEDRIVER = "${pkgs.chromedriver}/bin/chromedriver"; + PYO3_PYTHON = "${pkgs.python3Full}/bin/python3"; }; } ); diff --git a/rust/kcl-lib/src/execution/geometry.rs b/rust/kcl-lib/src/execution/geometry.rs index cd5c3bd9486..d6712bc25a7 100644 --- a/rust/kcl-lib/src/execution/geometry.rs +++ b/rust/kcl-lib/src/execution/geometry.rs @@ -657,6 +657,9 @@ pub struct Sketch { /// If the sketch includes a mirror. #[serde(skip)] pub mirror: Option, + /// If the sketch is a clone of another sketch. + #[serde(skip)] + pub clone: Option, pub units: UnitLength, /// Metadata. #[serde(skip)] diff --git a/rust/kcl-lib/src/std/clone.rs b/rust/kcl-lib/src/std/clone.rs index 505f0ba4bc0..428c5593160 100644 --- a/rust/kcl-lib/src/std/clone.rs +++ b/rust/kcl-lib/src/std/clone.rs @@ -111,6 +111,7 @@ async fn fix_tags_and_references( match new_geometry { GeometryWithImportedGeometry::ImportedGeometry(_) => {} GeometryWithImportedGeometry::Sketch(sketch) => { + sketch.clone = Some(old_geometry_id); fix_sketch_tags_and_references(sketch, &entity_id_map, exec_state, None).await?; } GeometryWithImportedGeometry::Solid(solid) => { @@ -155,6 +156,7 @@ async fn fix_tags_and_references( exec_state, args, None, + None, ) .await?; diff --git a/rust/kcl-lib/src/std/extrude.rs b/rust/kcl-lib/src/std/extrude.rs index 76aa000dda1..9198b83bc86 100644 --- a/rust/kcl-lib/src/std/extrude.rs +++ b/rust/kcl-lib/src/std/extrude.rs @@ -313,6 +313,7 @@ async fn inner_extrude( exec_state, &args, None, + None, ) .await?, ); @@ -337,6 +338,7 @@ pub(crate) async fn do_post_extrude<'a>( exec_state: &mut ExecState, args: &Args, edge_id: Option, + clone_id_map: Option<&HashMap>, // old sketch id -> new sketch id ) -> Result { // Bring the object to the front of the scene. // See: https://github.com/KittyCAD/modeling-app/issues/806 @@ -423,12 +425,29 @@ pub(crate) async fn do_post_extrude<'a>( if let Some(Some(actual_face_id)) = face_id_map.get(&path.get_base().geo_meta.id) { surface_of(path, *actual_face_id) } else if no_engine_commands { + crate::log::logln!( + "No face ID found for path ID {:?}, but in no-engine-commands mode, so faking it", + path.get_base().geo_meta.id + ); // Only pre-populate the extrude surface if we are in mock mode. fake_extrude_surface(exec_state, path) + } else if sketch.clone.is_some() + && let Some(clone_map) = clone_id_map + { + let new_path = clone_map.get(&path.get_base().geo_meta.id)?; + match face_id_map.get(new_path) { + Some(Some(actual_face_id)) => clone_surface_of(path, *new_path, *actual_face_id), + _ => None, + } } else { + crate::log::logln!( + "No face ID found for path ID {:?}, and not in no-engine-commands mode, so skipping it", + path.get_base().geo_meta.id + ); None } }); + new_value.extend(outer_surfaces); let inner_surfaces = sketch.inner_paths.iter().flat_map(|path| { if let Some(Some(actual_face_id)) = face_id_map.get(&path.get_base().geo_meta.id) { @@ -586,6 +605,51 @@ fn surface_of(path: &Path, actual_face_id: Uuid) -> Option { } } +fn clone_surface_of(path: &Path, clone_path_id: Uuid, actual_face_id: Uuid) -> Option { + match path { + Path::Arc { .. } + | Path::TangentialArc { .. } + | Path::TangentialArcTo { .. } + // TODO: (bc) fix me + | Path::Ellipse { .. } + | Path::Conic {.. } + | Path::Circle { .. } + | Path::CircleThreePoint { .. } => { + let extrude_surface = ExtrudeSurface::ExtrudeArc(crate::execution::ExtrudeArc { + face_id: actual_face_id, + tag: path.get_base().tag.clone(), + geo_meta: GeoMeta { + id: clone_path_id, + metadata: path.get_base().geo_meta.metadata, + }, + }); + Some(extrude_surface) + } + Path::Base { .. } | Path::ToPoint { .. } | Path::Horizontal { .. } | Path::AngledLineTo { .. } => { + let extrude_surface = ExtrudeSurface::ExtrudePlane(crate::execution::ExtrudePlane { + face_id: actual_face_id, + tag: path.get_base().tag.clone(), + geo_meta: GeoMeta { + id: clone_path_id, + metadata: path.get_base().geo_meta.metadata, + }, + }); + Some(extrude_surface) + } + Path::ArcThreePoint { .. } => { + let extrude_surface = ExtrudeSurface::ExtrudeArc(crate::execution::ExtrudeArc { + face_id: actual_face_id, + tag: path.get_base().tag.clone(), + geo_meta: GeoMeta { + id: clone_path_id, + metadata: path.get_base().geo_meta.metadata, + }, + }); + Some(extrude_surface) + } + } +} + /// Create a fake extrude surface to report for mock execution, when there's no engine response. fn fake_extrude_surface(exec_state: &mut ExecState, path: &Path) -> Option { let extrude_surface = ExtrudeSurface::ExtrudePlane(crate::execution::ExtrudePlane { diff --git a/rust/kcl-lib/src/std/loft.rs b/rust/kcl-lib/src/std/loft.rs index ec830dcbcde..364cc7e0724 100644 --- a/rust/kcl-lib/src/std/loft.rs +++ b/rust/kcl-lib/src/std/loft.rs @@ -104,6 +104,7 @@ async fn inner_loft( exec_state, &args, None, + None, ) .await?, )) diff --git a/rust/kcl-lib/src/std/revolve.rs b/rust/kcl-lib/src/std/revolve.rs index dc032f2dbc9..ce7f73d898d 100644 --- a/rust/kcl-lib/src/std/revolve.rs +++ b/rust/kcl-lib/src/std/revolve.rs @@ -208,6 +208,7 @@ async fn inner_revolve( exec_state, &args, edge_id, + None, ) .await?, ); diff --git a/rust/kcl-lib/src/std/sketch.rs b/rust/kcl-lib/src/std/sketch.rs index 0f09dafbb0f..e56ca25e99c 100644 --- a/rust/kcl-lib/src/std/sketch.rs +++ b/rust/kcl-lib/src/std/sketch.rs @@ -1169,6 +1169,7 @@ pub(crate) async fn inner_start_profile( inner_paths: vec![], units, mirror: Default::default(), + clone: Default::default(), meta: vec![args.source_range.into()], tags: if let Some(tag) = &tag { let mut tag_identifier: TagIdentifier = tag.into(); diff --git a/rust/kcl-lib/src/std/sweep.rs b/rust/kcl-lib/src/std/sweep.rs index 8e0d19fe6b5..1e2b416c510 100644 --- a/rust/kcl-lib/src/std/sweep.rs +++ b/rust/kcl-lib/src/std/sweep.rs @@ -108,6 +108,7 @@ async fn inner_sweep( exec_state, &args, None, + None, ) .await?, );