Merge branch 'main' into cut-release-v0.25.1
This commit is contained in:
		| @ -364,45 +364,48 @@ test.describe('Testing settings', () => { | ||||
|     async ({ browser: _ }, testInfo) => { | ||||
|       const { electronApp, page } = await setupElectron({ | ||||
|         testInfo, | ||||
|         folderSetupFn: async () => {}, | ||||
|         folderSetupFn: async (dir) => { | ||||
|           const bracketDir = join(dir, 'project-000') | ||||
|           await fsp.mkdir(bracketDir, { recursive: true }) | ||||
|           await fsp.copyFile( | ||||
|             executorInputPath('cube.kcl'), | ||||
|             join(bracketDir, 'main.kcl') | ||||
|           ) | ||||
|           await fsp.copyFile( | ||||
|             executorInputPath('cylinder.kcl'), | ||||
|             join(bracketDir, '2.kcl') | ||||
|           ) | ||||
|         }, | ||||
|       }) | ||||
|       const kclCube = await fsp.readFile(executorInputPath('cube.kcl'), 'utf-8') | ||||
|       const kclCylinder = await fsp.readFile( | ||||
|         executorInputPath('cylinder.kcl'), | ||||
|         'utf8' | ||||
|       ) | ||||
|  | ||||
|       const { | ||||
|         openKclCodePanel, | ||||
|         openFilePanel, | ||||
|         createAndSelectProject, | ||||
|         pasteCodeInEditor, | ||||
|         createNewFileAndSelect, | ||||
|         waitForPageLoad, | ||||
|         selectFile, | ||||
|         editorTextMatches, | ||||
|       } = await getUtils(page, test) | ||||
|  | ||||
|       await page.setViewportSize({ width: 1200, height: 500 }) | ||||
|       page.on('console', console.log) | ||||
|  | ||||
|       await test.step('Precondition: No projects exist', async () => { | ||||
|       await test.step('Precondition: Open to second project file', async () => { | ||||
|         await expect(page.getByTestId('home-section')).toBeVisible() | ||||
|         const projectLinksPre = page.getByTestId('project-link') | ||||
|         await expect(projectLinksPre).toHaveCount(0) | ||||
|         await page.getByText('project-000').click() | ||||
|         await waitForPageLoad() | ||||
|         await openKclCodePanel() | ||||
|         await openFilePanel() | ||||
|         await editorTextMatches(kclCube) | ||||
|  | ||||
|         await selectFile('2.kcl') | ||||
|         await editorTextMatches(kclCylinder) | ||||
|       }) | ||||
|  | ||||
|       await createAndSelectProject('project-000') | ||||
|  | ||||
|       await openKclCodePanel() | ||||
|       const kclCube = await fsp.readFile( | ||||
|         'src/wasm-lib/tests/executor/inputs/cube.kcl', | ||||
|         'utf-8' | ||||
|       ) | ||||
|       await pasteCodeInEditor(kclCube) | ||||
|  | ||||
|       await openFilePanel() | ||||
|       await createNewFileAndSelect('2.kcl') | ||||
|  | ||||
|       const kclCylinder = await fsp.readFile( | ||||
|         'src/wasm-lib/tests/executor/inputs/cylinder.kcl', | ||||
|         'utf-8' | ||||
|       ) | ||||
|       await pasteCodeInEditor(kclCylinder) | ||||
|  | ||||
|       const settingsOpenButton = page.getByRole('link', { | ||||
|         name: 'settings Settings', | ||||
|       }) | ||||
| @ -410,6 +413,9 @@ test.describe('Testing settings', () => { | ||||
|  | ||||
|       await test.step('Open and close settings', async () => { | ||||
|         await settingsOpenButton.click() | ||||
|         await expect( | ||||
|           page.getByRole('heading', { name: 'Settings', exact: true }) | ||||
|         ).toBeVisible() | ||||
|         await settingsCloseButton.click() | ||||
|       }) | ||||
|  | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; | ||||
| use kcl_lib::test_server; | ||||
| use kcl_lib::{settings::types::UnitLength::Mm, test_server}; | ||||
| use tokio::runtime::Runtime; | ||||
|  | ||||
| pub fn bench_execute(c: &mut Criterion) { | ||||
| @ -13,26 +13,42 @@ pub fn bench_execute(c: &mut Criterion) { | ||||
|         // Configure Criterion.rs to detect smaller differences and increase sample size to improve | ||||
|         // precision and counteract the resulting noise. | ||||
|         group.sample_size(10); | ||||
|         group.bench_with_input(BenchmarkId::new("execute_", name), &code, |b, &s| { | ||||
|         group.bench_with_input(BenchmarkId::new("execute", name), &code, |b, &s| { | ||||
|             let rt = Runtime::new().unwrap(); | ||||
|  | ||||
|             // Spawn a future onto the runtime | ||||
|             b.iter(|| { | ||||
|                 rt.block_on(test_server::execute_and_snapshot( | ||||
|                     s, | ||||
|                     kcl_lib::settings::types::UnitLength::Mm, | ||||
|                 )) | ||||
|                 .unwrap(); | ||||
|                 rt.block_on(test_server::execute_and_snapshot(s, Mm)).unwrap(); | ||||
|             }); | ||||
|         }); | ||||
|         group.finish(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| criterion_group!(benches, bench_execute); | ||||
| pub fn bench_lego(c: &mut Criterion) { | ||||
|     let mut group = c.benchmark_group("executor_lego_pattern"); | ||||
|     // Configure Criterion.rs to detect smaller differences and increase sample size to improve | ||||
|     // precision and counteract the resulting noise. | ||||
|     group.sample_size(10); | ||||
|     // Create lego bricks with N x 10 bumps, where N is each element of `sizes`. | ||||
|     let sizes = vec![1, 2, 4]; | ||||
|     for size in sizes { | ||||
|         group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| { | ||||
|             let rt = Runtime::new().unwrap(); | ||||
|             let code = LEGO_PROGRAM.replace("{{N}}", &size.to_string()); | ||||
|             // Spawn a future onto the runtime | ||||
|             b.iter(|| { | ||||
|                 rt.block_on(test_server::execute_and_snapshot(&code, Mm)).unwrap(); | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
|     group.finish(); | ||||
| } | ||||
|  | ||||
| criterion_group!(benches, bench_lego, bench_execute); | ||||
| criterion_main!(benches); | ||||
|  | ||||
| const KITT_PROGRAM: &str = include_str!("../../tests/executor/inputs/kittycad_svg.kcl"); | ||||
| const CUBE_PROGRAM: &str = include_str!("../../tests/executor/inputs/cube.kcl"); | ||||
| const SERVER_RACK_HEAVY_PROGRAM: &str = include_str!("../../tests/executor/inputs/server-rack-heavy.kcl"); | ||||
| const SERVER_RACK_LITE_PROGRAM: &str = include_str!("../../tests/executor/inputs/server-rack-lite.kcl"); | ||||
| const LEGO_PROGRAM: &str = include_str!("../../tests/executor/inputs/slow_lego.kcl.tmpl"); | ||||
|  | ||||
| @ -1,8 +1,10 @@ | ||||
| //! Functions related to extruding. | ||||
|  | ||||
| use std::collections::HashMap; | ||||
|  | ||||
| use anyhow::Result; | ||||
| use derive_docs::stdlib; | ||||
| use kittycad::types::ExtrusionFaceCapType; | ||||
| use kittycad::types::{ExtrusionFaceCapType, ExtrusionFaceInfo}; | ||||
| use schemars::JsonSchema; | ||||
| use uuid::Uuid; | ||||
|  | ||||
| @ -99,7 +101,7 @@ async fn inner_extrude(length: f64, sketch_group_set: SketchGroupSet, args: Args | ||||
|         ) | ||||
|         .await?; | ||||
|  | ||||
|         args.send_modeling_cmd( | ||||
|         args.batch_modeling_cmd( | ||||
|             id, | ||||
|             kittycad::types::ModelingCmd::Extrude { | ||||
|                 target: sketch_group.id, | ||||
| @ -112,7 +114,7 @@ async fn inner_extrude(length: f64, sketch_group_set: SketchGroupSet, args: Args | ||||
|         // Disable the sketch mode. | ||||
|         args.batch_modeling_cmd(uuid::Uuid::new_v4(), kittycad::types::ModelingCmd::SketchModeDisable {}) | ||||
|             .await?; | ||||
|         extrude_groups.push(do_post_extrude(sketch_group.clone(), length, id, args.clone()).await?); | ||||
|         extrude_groups.push(do_post_extrude(sketch_group.clone(), length, args.clone()).await?); | ||||
|     } | ||||
|  | ||||
|     Ok(extrude_groups.into()) | ||||
| @ -121,7 +123,6 @@ async fn inner_extrude(length: f64, sketch_group_set: SketchGroupSet, args: Args | ||||
| pub(crate) async fn do_post_extrude( | ||||
|     sketch_group: SketchGroup, | ||||
|     length: f64, | ||||
|     id: Uuid, | ||||
|     args: Args, | ||||
| ) -> Result<Box<ExtrudeGroup>, KclError> { | ||||
|     // Bring the object to the front of the scene. | ||||
| @ -165,7 +166,7 @@ pub(crate) async fn do_post_extrude( | ||||
|  | ||||
|     let solid3d_info = args | ||||
|         .send_modeling_cmd( | ||||
|             id, | ||||
|             uuid::Uuid::new_v4(), | ||||
|             kittycad::types::ModelingCmd::Solid3DGetExtrusionFaceInfo { | ||||
|                 edge_id, | ||||
|                 object_id: sketch_group.id, | ||||
| @ -218,26 +219,11 @@ pub(crate) async fn do_post_extrude( | ||||
|         .await?; | ||||
|     } | ||||
|  | ||||
|     // Create a hashmap for quick id lookup | ||||
|     let mut face_id_map = std::collections::HashMap::new(); | ||||
|     // creating fake ids for start and end caps is to make extrudes mock-execute safe | ||||
|     let (mut start_cap_id, mut end_cap_id) = if args.ctx.is_mock { | ||||
|         (Some(Uuid::new_v4()), Some(Uuid::new_v4())) | ||||
|     } else { | ||||
|         (None, None) | ||||
|     }; | ||||
|     for face_info in face_infos { | ||||
|         match face_info.cap { | ||||
|             ExtrusionFaceCapType::Bottom => start_cap_id = face_info.face_id, | ||||
|             ExtrusionFaceCapType::Top => end_cap_id = face_info.face_id, | ||||
|             ExtrusionFaceCapType::None => { | ||||
|                 if let Some(curve_id) = face_info.curve_id { | ||||
|                     face_id_map.insert(curve_id, face_info.face_id); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     let Faces { | ||||
|         sides: face_id_map, | ||||
|         start_cap_id, | ||||
|         end_cap_id, | ||||
|     } = analyze_faces(&args, face_infos); | ||||
|     // Iterate over the sketch_group.value array and add face_id to GeoMeta | ||||
|     let new_value = sketch_group | ||||
|         .value | ||||
| @ -301,3 +287,37 @@ pub(crate) async fn do_post_extrude( | ||||
|         edge_cuts: vec![], | ||||
|     })) | ||||
| } | ||||
|  | ||||
| #[derive(Default)] | ||||
| struct Faces { | ||||
|     /// Maps curve ID to face ID for each side. | ||||
|     sides: HashMap<Uuid, Option<Uuid>>, | ||||
|     /// Top face ID. | ||||
|     end_cap_id: Option<Uuid>, | ||||
|     /// Bottom face ID. | ||||
|     start_cap_id: Option<Uuid>, | ||||
| } | ||||
|  | ||||
| fn analyze_faces(args: &Args, face_infos: Vec<ExtrusionFaceInfo>) -> Faces { | ||||
|     let mut faces = Faces { | ||||
|         sides: HashMap::with_capacity(face_infos.len()), | ||||
|         ..Default::default() | ||||
|     }; | ||||
|     if args.ctx.is_mock { | ||||
|         // Create fake IDs for start and end caps, to make extrudes mock-execute safe | ||||
|         faces.start_cap_id = Some(Uuid::new_v4()); | ||||
|         faces.end_cap_id = Some(Uuid::new_v4()); | ||||
|     } | ||||
|     for face_info in face_infos { | ||||
|         match face_info.cap { | ||||
|             ExtrusionFaceCapType::Bottom => faces.start_cap_id = face_info.face_id, | ||||
|             ExtrusionFaceCapType::Top => faces.end_cap_id = face_info.face_id, | ||||
|             ExtrusionFaceCapType::None => { | ||||
|                 if let Some(curve_id) = face_info.curve_id { | ||||
|                     faces.sides.insert(curve_id, face_info.face_id); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     faces | ||||
| } | ||||
|  | ||||
| @ -170,5 +170,5 @@ async fn inner_loft( | ||||
|     .await?; | ||||
|  | ||||
|     // Using the first sketch as the base curve, idk we might want to change this later. | ||||
|     do_post_extrude(sketch_groups[0].clone(), 0.0, id, args).await | ||||
|     do_post_extrude(sketch_groups[0].clone(), 0.0, args).await | ||||
| } | ||||
|  | ||||
| @ -299,7 +299,7 @@ async fn inner_revolve( | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     do_post_extrude(sketch_group, 0.0, id, args).await | ||||
|     do_post_extrude(sketch_group, 0.0, args).await | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
|  | ||||
							
								
								
									
										81
									
								
								src/wasm-lib/tests/executor/inputs/slow_lego.kcl.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/wasm-lib/tests/executor/inputs/slow_lego.kcl.tmpl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | ||||
| // 2x8 Lego Brick | ||||
| // A standard Lego brick with 2 bumps wide and 8 bumps long. | ||||
| // Define constants | ||||
| const lbumps = 10 // number of bumps long | ||||
| const wbumps = {{N}} // number of bumps wide | ||||
| const pitch = 8.0 | ||||
| const clearance = 0.1 | ||||
| const bumpDiam = 4.8 | ||||
| const bumpHeight = 1.8 | ||||
| const height = 9.6 | ||||
| const t = (pitch - (2 * clearance) - bumpDiam) / 2.0 | ||||
| const totalLength = lbumps * pitch - (2.0 * clearance) | ||||
| const totalWidth = wbumps * pitch - (2.0 * clearance) | ||||
| // Create the plane for the pegs. This is a hack so that the pegs can be patterned along the face of the lego base. | ||||
| const pegFace = { | ||||
|   plane: { | ||||
|     origin: { x: 0, y: 0, z: height }, | ||||
|     xAxis: { x: 1, y: 0, z: 0 }, | ||||
|     yAxis: { x: 0, y: 1, z: 0 }, | ||||
|     zAxis: { x: 0, y: 0, z: 1 } | ||||
|   } | ||||
| } | ||||
| // Create the plane for the tubes underneath the lego. This is a hack so that the tubes can be patterned underneath the lego. | ||||
| const tubeFace = { | ||||
|     plane: { | ||||
|     origin: { x: 0, y: 0, z: height - t }, | ||||
|     xAxis: { x: 1, y: 0, z: 0 }, | ||||
|     yAxis: { x: 0, y: 1, z: 0 }, | ||||
|     zAxis: { x: 0, y: 0, z: 1 } | ||||
|   } | ||||
| } | ||||
| // Make the base | ||||
| const s = startSketchOn('XY') | ||||
|   |> startProfileAt([-totalWidth / 2, -totalLength / 2], %) | ||||
|   |> line([totalWidth, 0], %) | ||||
|   |> line([0, totalLength], %) | ||||
|   |> line([-totalWidth, 0], %) | ||||
|   |> close(%) | ||||
|   |> extrude(height, %) | ||||
|  | ||||
| // Sketch and extrude a rectangular shape to create the shell underneath the lego. This is a hack until we have a shell function. | ||||
| const shellExtrude = startSketchOn(s, "start") | ||||
|   |> startProfileAt([ | ||||
|        -(totalWidth / 2 - t), | ||||
|        -(totalLength / 2 - t) | ||||
|      ], %) | ||||
|   |> line([totalWidth - (2 * t), 0], %) | ||||
|   |> line([0, totalLength - (2 * t)], %) | ||||
|   |> line([-(totalWidth - (2 * t)), 0], %) | ||||
|   |> close(%) | ||||
|   |> extrude(-(height - t), %) | ||||
|  | ||||
| fn tr = (i) => { | ||||
|   let j = i + 1 | ||||
|   let x = (j/wbumps) * pitch | ||||
|   let y = (j % wbumps) * pitch | ||||
|   return { | ||||
|     translate: [x, y, 0], | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Create the pegs on the top of the base | ||||
| const totalBumps = (wbumps * lbumps)-1 | ||||
| const peg = startSketchOn(s, 'end') | ||||
|   |> circle([ | ||||
|        -(pitch*(wbumps-1)/2), | ||||
|        -(pitch*(lbumps-1)/2) | ||||
|      ], bumpDiam / 2, %) | ||||
|   |> patternLinear2d({ | ||||
|        axis: [1, 0], | ||||
|        repetitions: wbumps-1, | ||||
|        distance: pitch | ||||
|      }, %) | ||||
|   |> patternLinear2d({ | ||||
|        axis: [0, 1], | ||||
|        repetitions: lbumps-1, | ||||
|        distance: pitch | ||||
|      }, %) | ||||
|   |> extrude(bumpHeight, %) | ||||
|   // |> patternTransform(int(totalBumps-1), tr, %) | ||||
|  | ||||
		Reference in New Issue
	
	Block a user