Merge branch 'franknoirot/adhoc/appearance-tweaks-modeling-view' into franknoirot/adhoc/split-sidebar
This commit is contained in:
		
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -109,3 +109,98 @@ Coordinate systems: | ||||
| - `zoo` (the default), forward: -Y, up: +Z, handedness: right | ||||
| - `opengl`, forward: +Z, up: +Y, handedness: right | ||||
| - `vulkan`, forward: +Z, up: -Y, handedness: left | ||||
|  | ||||
| ### Performance | ||||
|  | ||||
| Parallelized foreign-file imports now let you overlap file reads, initialization, | ||||
| and rendering. To maximize throughput, you need to understand the three distinct | ||||
| stages—reading, initializing (background render start), and invocation (blocking) | ||||
| —and structure your code to defer blocking operations until the end. | ||||
|  | ||||
| #### Foreign Import Execution Stages | ||||
|  | ||||
| 1. **Import (Read) Stage**   | ||||
|    ```norun | ||||
|    import "tests/inputs/cube.step" as cube | ||||
|    ```   | ||||
|    - Reads the file from disk and makes its API available.   | ||||
|    - **Does _not_** start Engine rendering or block your script. | ||||
|  | ||||
| 2. **Initialization (Background Render) Stage**   | ||||
|    ```norun | ||||
|    import "tests/inputs/cube.step" as cube | ||||
|  | ||||
|    myCube = cube    // <- This line starts background rendering | ||||
|    ```   | ||||
|    - Invoking the imported symbol (assignment or plain call) triggers Engine rendering _in the background_.   | ||||
|    - This kick‑starts the render pipeline but doesn’t block—you can continue other work while the Engine processes the model. | ||||
|  | ||||
| 3. **Invocation (Blocking) Stage**   | ||||
|    ```norun | ||||
|    import "tests/inputs/cube.step" as cube | ||||
|  | ||||
|    myCube = cube | ||||
|  | ||||
|    myCube | ||||
|     |> translate(z=10) // <- This line blocks | ||||
|    ```   | ||||
|    - Any method call (e.g., `translate`, `scale`, `rotate`) waits for the background render to finish before applying transformations.   | ||||
|    - This is the only point where your script will block. | ||||
|  | ||||
| > **Nuance:**  Foreign imports differ from pure KCL modules—calling the same import symbol multiple times (e.g., `screw` twice) starts background rendering twice. | ||||
|  | ||||
| #### Best Practices | ||||
|  | ||||
| ##### 1. Defer Blocking Calls | ||||
| Initialize early but delay all transformations until after your heavy computation: | ||||
| ```norun | ||||
| import "tests/inputs/cube.step" as cube     // 1) Read | ||||
|  | ||||
| myCube = cube                               // 2) Background render starts | ||||
|  | ||||
|  | ||||
| // --- perform other operations and calculations or setup here --- | ||||
|  | ||||
|  | ||||
| myCube | ||||
|   |> translate(z=10)                        // 3) Blocks only here | ||||
| ``` | ||||
|  | ||||
| ##### 2. Encapsulate Imports in Modules | ||||
| Keep `main.kcl` free of reads and initialization; wrap them: | ||||
|  | ||||
| ```norun | ||||
| // imports.kcl | ||||
| import "tests/inputs/cube.step" as cube    // Read only | ||||
|  | ||||
|  | ||||
| export myCube = cube                      // Kick off rendering | ||||
| ``` | ||||
|  | ||||
| ```norun | ||||
| // main.kcl | ||||
| import myCube from "imports.kcl"  // Import the initialized object  | ||||
|  | ||||
|  | ||||
| // ... computations ... | ||||
|  | ||||
|  | ||||
| myCube | ||||
|   |> translate(z=10)              // Blocking call at the end | ||||
| ``` | ||||
|  | ||||
| ##### 3. Avoid Immediate Method Calls | ||||
|  | ||||
| ```norun | ||||
| import "tests/inputs/cube.step" as cube | ||||
|  | ||||
| cube | ||||
|   |> translate(z=10)              // Blocks immediately, negating parallelism | ||||
| ``` | ||||
|  | ||||
| Both calling methods right on `cube` immediately or leaving an implicit import without assignment introduce blocking. | ||||
|  | ||||
| #### Future Improvements | ||||
|  | ||||
| Upcoming releases will auto‑analyze dependencies and only block when truly necessary. Until then, explicit deferral and modular wrapping give you the best performance. | ||||
|  | ||||
|  | ||||
| @ -53,7 +53,7 @@ rotate( | ||||
|  | ||||
| ### Returns | ||||
|  | ||||
| [`SolidOrSketchOrImportedGeometry`](/docs/kcl/types/SolidOrSketchOrImportedGeometry) - Data for a solid or an imported geometry. | ||||
| [`SolidOrSketchOrImportedGeometry`](/docs/kcl/types/SolidOrSketchOrImportedGeometry) - Data for a solid, sketch, or an imported geometry. | ||||
|  | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| @ -37,7 +37,7 @@ scale( | ||||
|  | ||||
| ### Returns | ||||
|  | ||||
| [`SolidOrSketchOrImportedGeometry`](/docs/kcl/types/SolidOrSketchOrImportedGeometry) - Data for a solid or an imported geometry. | ||||
| [`SolidOrSketchOrImportedGeometry`](/docs/kcl/types/SolidOrSketchOrImportedGeometry) - Data for a solid, sketch, or an imported geometry. | ||||
|  | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| @ -28101,14 +28101,62 @@ | ||||
|     "args": [ | ||||
|       { | ||||
|         "name": "solids", | ||||
|         "type": "[Solid]", | ||||
|         "type": "SolidOrImportedGeometry", | ||||
|         "schema": { | ||||
|           "$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema", | ||||
|           "title": "Array_of_Solid", | ||||
|           "type": "array", | ||||
|           "items": { | ||||
|             "$ref": "#/components/schemas/Solid" | ||||
|           }, | ||||
|           "title": "SolidOrImportedGeometry", | ||||
|           "description": "Data for a solid or an imported geometry.", | ||||
|           "oneOf": [ | ||||
|             { | ||||
|               "description": "Data for an imported geometry.", | ||||
|               "type": "object", | ||||
|               "required": [ | ||||
|                 "id", | ||||
|                 "type", | ||||
|                 "value" | ||||
|               ], | ||||
|               "properties": { | ||||
|                 "type": { | ||||
|                   "type": "string", | ||||
|                   "enum": [ | ||||
|                     "importedGeometry" | ||||
|                   ] | ||||
|                 }, | ||||
|                 "id": { | ||||
|                   "description": "The ID of the imported geometry.", | ||||
|                   "type": "string", | ||||
|                   "format": "uuid" | ||||
|                 }, | ||||
|                 "value": { | ||||
|                   "description": "The original file paths.", | ||||
|                   "type": "array", | ||||
|                   "items": { | ||||
|                     "type": "string" | ||||
|                   } | ||||
|                 } | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": [ | ||||
|                 "object", | ||||
|                 "array" | ||||
|               ], | ||||
|               "items": { | ||||
|                 "$ref": "#/components/schemas/Solid" | ||||
|               }, | ||||
|               "required": [ | ||||
|                 "type" | ||||
|               ], | ||||
|               "properties": { | ||||
|                 "type": { | ||||
|                   "type": "string", | ||||
|                   "enum": [ | ||||
|                     "solidSet" | ||||
|                   ] | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           ], | ||||
|           "definitions": { | ||||
|             "Solid": { | ||||
|               "type": "object", | ||||
| @ -34571,14 +34619,62 @@ | ||||
|     ], | ||||
|     "returnValue": { | ||||
|       "name": "", | ||||
|       "type": "[Solid]", | ||||
|       "type": "SolidOrImportedGeometry", | ||||
|       "schema": { | ||||
|         "$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema", | ||||
|         "title": "Array_of_Solid", | ||||
|         "type": "array", | ||||
|         "items": { | ||||
|           "$ref": "#/components/schemas/Solid" | ||||
|         }, | ||||
|         "title": "SolidOrImportedGeometry", | ||||
|         "description": "Data for a solid or an imported geometry.", | ||||
|         "oneOf": [ | ||||
|           { | ||||
|             "description": "Data for an imported geometry.", | ||||
|             "type": "object", | ||||
|             "required": [ | ||||
|               "id", | ||||
|               "type", | ||||
|               "value" | ||||
|             ], | ||||
|             "properties": { | ||||
|               "type": { | ||||
|                 "type": "string", | ||||
|                 "enum": [ | ||||
|                   "importedGeometry" | ||||
|                 ] | ||||
|               }, | ||||
|               "id": { | ||||
|                 "description": "The ID of the imported geometry.", | ||||
|                 "type": "string", | ||||
|                 "format": "uuid" | ||||
|               }, | ||||
|               "value": { | ||||
|                 "description": "The original file paths.", | ||||
|                 "type": "array", | ||||
|                 "items": { | ||||
|                   "type": "string" | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           }, | ||||
|           { | ||||
|             "type": [ | ||||
|               "object", | ||||
|               "array" | ||||
|             ], | ||||
|             "items": { | ||||
|               "$ref": "#/components/schemas/Solid" | ||||
|             }, | ||||
|             "required": [ | ||||
|               "type" | ||||
|             ], | ||||
|             "properties": { | ||||
|               "type": { | ||||
|                 "type": "string", | ||||
|                 "enum": [ | ||||
|                   "solidSet" | ||||
|                 ] | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         ], | ||||
|         "definitions": { | ||||
|           "Solid": { | ||||
|             "type": "object", | ||||
| @ -36198,7 +36294,8 @@ | ||||
|       "// Setting the appearance of a 3D pattern can be done _before_ or _after_ the pattern.\n// This example shows _before_ the pattern.\nexampleSketch = startSketchOn(XZ)\n  |> startProfileAt([0, 0], %)\n  |> line(end = [0, 2])\n  |> line(end = [3, 1])\n  |> line(end = [0, -4])\n  |> close()\n\nexample = extrude(exampleSketch, length = 1)\n  |> appearance(color = '#ff0000', metalness = 90, roughness = 90)\n  |> patternLinear3d(axis = [1, 0, 1], instances = 7, distance = 6)", | ||||
|       "// Setting the appearance of a 3D pattern can be done _before_ or _after_ the pattern.\n// This example shows _after_ the pattern.\nexampleSketch = startSketchOn(XZ)\n  |> startProfileAt([0, 0], %)\n  |> line(end = [0, 2])\n  |> line(end = [3, 1])\n  |> line(end = [0, -4])\n  |> close()\n\nexample = extrude(exampleSketch, length = 1)\n  |> patternLinear3d(axis = [1, 0, 1], instances = 7, distance = 6)\n  |> appearance(color = '#ff0000', metalness = 90, roughness = 90)", | ||||
|       "// Color the result of a 2D pattern that was extruded.\nexampleSketch = startSketchOn(XZ)\n  |> startProfileAt([.5, 25], %)\n  |> line(end = [0, 5])\n  |> line(end = [-1, 0])\n  |> line(end = [0, -5])\n  |> close()\n  |> patternCircular2d(\n       center = [0, 0],\n       instances = 13,\n       arcDegrees = 360,\n       rotateDuplicates = true,\n     )\n\nexample = extrude(exampleSketch, length = 1)\n  |> appearance(color = '#ff0000', metalness = 90, roughness = 90)", | ||||
|       "// Color the result of a sweep.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n  |> startProfileAt([0.05, 0.05], %)\n  |> line(end = [0, 7])\n  |> tangentialArc(angle = 90, radius = 5)\n  |> line(end = [-3, 0])\n  |> tangentialArc(angle = -90, radius = 5)\n  |> line(end = [0, 7])\n\npipeHole = startSketchOn(XY)\n  |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n  |> circle(center = [0, 0], radius = 2)\n  |> hole(pipeHole, %)\n  |> sweep(path = sweepPath)\n  |> appearance(color = \"#ff0000\", metalness = 50, roughness = 50)" | ||||
|       "// Color the result of a sweep.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n  |> startProfileAt([0.05, 0.05], %)\n  |> line(end = [0, 7])\n  |> tangentialArc(angle = 90, radius = 5)\n  |> line(end = [-3, 0])\n  |> tangentialArc(angle = -90, radius = 5)\n  |> line(end = [0, 7])\n\npipeHole = startSketchOn(XY)\n  |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n  |> circle(center = [0, 0], radius = 2)\n  |> hole(pipeHole, %)\n  |> sweep(path = sweepPath)\n  |> appearance(color = \"#ff0000\", metalness = 50, roughness = 50)", | ||||
|       "// Change the appearance of an imported model.\n\n\nimport \"tests/inputs/cube.sldprt\" as cube\n\ncube\n// |> appearance(\n// color = \"#ff0000\",\n// metalness = 50,\n// roughness = 50\n// )" | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
| @ -249578,7 +249675,7 @@ | ||||
|         "schema": { | ||||
|           "$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema", | ||||
|           "title": "SolidOrSketchOrImportedGeometry", | ||||
|           "description": "Data for a solid or an imported geometry.", | ||||
|           "description": "Data for a solid, sketch, or an imported geometry.", | ||||
|           "oneOf": [ | ||||
|             { | ||||
|               "description": "Data for an imported geometry.", | ||||
| @ -260975,7 +261072,7 @@ | ||||
|       "schema": { | ||||
|         "$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema", | ||||
|         "title": "SolidOrSketchOrImportedGeometry", | ||||
|         "description": "Data for a solid or an imported geometry.", | ||||
|         "description": "Data for a solid, sketch, or an imported geometry.", | ||||
|         "oneOf": [ | ||||
|           { | ||||
|             "description": "Data for an imported geometry.", | ||||
| @ -262721,7 +262818,7 @@ | ||||
|         "schema": { | ||||
|           "$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema", | ||||
|           "title": "SolidOrSketchOrImportedGeometry", | ||||
|           "description": "Data for a solid or an imported geometry.", | ||||
|           "description": "Data for a solid, sketch, or an imported geometry.", | ||||
|           "oneOf": [ | ||||
|             { | ||||
|               "description": "Data for an imported geometry.", | ||||
| @ -270879,7 +270976,7 @@ | ||||
|       "schema": { | ||||
|         "$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema", | ||||
|         "title": "SolidOrSketchOrImportedGeometry", | ||||
|         "description": "Data for a solid or an imported geometry.", | ||||
|         "description": "Data for a solid, sketch, or an imported geometry.", | ||||
|         "oneOf": [ | ||||
|           { | ||||
|             "description": "Data for an imported geometry.", | ||||
| @ -319774,7 +319871,7 @@ | ||||
|         "schema": { | ||||
|           "$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema", | ||||
|           "title": "SolidOrSketchOrImportedGeometry", | ||||
|           "description": "Data for a solid or an imported geometry.", | ||||
|           "description": "Data for a solid, sketch, or an imported geometry.", | ||||
|           "oneOf": [ | ||||
|             { | ||||
|               "description": "Data for an imported geometry.", | ||||
| @ -327932,7 +328029,7 @@ | ||||
|       "schema": { | ||||
|         "$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema", | ||||
|         "title": "SolidOrSketchOrImportedGeometry", | ||||
|         "description": "Data for a solid or an imported geometry.", | ||||
|         "description": "Data for a solid, sketch, or an imported geometry.", | ||||
|         "oneOf": [ | ||||
|           { | ||||
|             "description": "Data for an imported geometry.", | ||||
|  | ||||
| @ -33,7 +33,7 @@ translate( | ||||
|  | ||||
| ### Returns | ||||
|  | ||||
| [`SolidOrSketchOrImportedGeometry`](/docs/kcl/types/SolidOrSketchOrImportedGeometry) - Data for a solid or an imported geometry. | ||||
| [`SolidOrSketchOrImportedGeometry`](/docs/kcl/types/SolidOrSketchOrImportedGeometry) - Data for a solid, sketch, or an imported geometry. | ||||
|  | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| @ -1,10 +1,10 @@ | ||||
| --- | ||||
| title: "SolidOrSketchOrImportedGeometry" | ||||
| excerpt: "Data for a solid or an imported geometry." | ||||
| excerpt: "Data for a solid, sketch, or an imported geometry." | ||||
| layout: manual | ||||
| --- | ||||
|  | ||||
| Data for a solid or an imported geometry. | ||||
| Data for a solid, sketch, or an imported geometry. | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -405,10 +405,6 @@ test.describe('Point-and-click assemblies tests', () => { | ||||
|         ) | ||||
|         await scene.settled(cmdBar) | ||||
|  | ||||
|         // TODO: remove this once #5780 is fixed | ||||
|         await page.reload() | ||||
|  | ||||
|         await scene.settled(cmdBar) | ||||
|         await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() | ||||
|         await toolbar.closePane('code') | ||||
|         await scene.expectPixelColor(partColor, partPoint, tolerance) | ||||
| @ -453,10 +449,6 @@ test.describe('Point-and-click assemblies tests', () => { | ||||
|         ) | ||||
|         await scene.settled(cmdBar) | ||||
|  | ||||
|         // TODO: remove this once #5780 is fixed | ||||
|         await page.reload() | ||||
|         await scene.settled(cmdBar) | ||||
|  | ||||
|         await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() | ||||
|         await toolbar.closePane('code') | ||||
|         await scene.expectPixelColor(partColor, partPoint, tolerance) | ||||
|  | ||||
| @ -3105,23 +3105,25 @@ test.describe('manual edits during sketch mode', () => { | ||||
|     await test.step('Edit sketch by dragging handle', async () => { | ||||
|       await page.waitForTimeout(500) | ||||
|       await expect | ||||
|         .poll(async () => { | ||||
|           await editor.expectEditor.toContain('length = 156.54, angle = -28') | ||||
|           await page.mouse.move(handle1Location.x, handle1Location.y) | ||||
|           await page.mouse.down() | ||||
|           await page.mouse.move( | ||||
|             handle1Location.x + 50, | ||||
|             handle1Location.y + 50, | ||||
|             { | ||||
|               steps: 5, | ||||
|             } | ||||
|           ) | ||||
|           await page.mouse.up() | ||||
|           await editor.expectEditor.toContain('length = 231.59, angle = -34') | ||||
|           return true | ||||
|         }) | ||||
|         .poll( | ||||
|           async () => { | ||||
|             await editor.expectEditor.toContain('length = 156.54, angle = -28') | ||||
|             await page.mouse.move(handle1Location.x, handle1Location.y) | ||||
|             await page.mouse.down() | ||||
|             await page.mouse.move( | ||||
|               handle1Location.x + 50, | ||||
|               handle1Location.y + 50, | ||||
|               { | ||||
|                 steps: 5, | ||||
|               } | ||||
|             ) | ||||
|             await page.mouse.up() | ||||
|             await editor.expectEditor.toContain('length = 231.59, angle = -34') | ||||
|             return true | ||||
|           }, | ||||
|           { timeout: 10_000 } | ||||
|         ) | ||||
|         .toBeTruthy() | ||||
|       // await page.waitForTimeout(1000) // Wait for update | ||||
|     }) | ||||
|  | ||||
|     await test.step('Delete variables and wait for re-execution', async () => { | ||||
| @ -3137,16 +3139,19 @@ test.describe('manual edits during sketch mode', () => { | ||||
|       await editor.expectEditor.toContain('length = 231.59, angle = -34') | ||||
|       await page.waitForTimeout(500) | ||||
|       await expect | ||||
|         .poll(async () => { | ||||
|           await page.mouse.move(handle2Location.x, handle2Location.y) | ||||
|           await page.mouse.down() | ||||
|           await page.mouse.move(handle2Location.x, handle2Location.y - 50, { | ||||
|             steps: 5, | ||||
|           }) | ||||
|           await page.mouse.up() | ||||
|           await editor.expectEditor.toContain('length = 167.36, angle = -14') | ||||
|           return true | ||||
|         }) | ||||
|         .poll( | ||||
|           async () => { | ||||
|             await page.mouse.move(handle2Location.x, handle2Location.y) | ||||
|             await page.mouse.down() | ||||
|             await page.mouse.move(handle2Location.x, handle2Location.y - 50, { | ||||
|               steps: 5, | ||||
|             }) | ||||
|             await page.mouse.up() | ||||
|             await editor.expectEditor.toContain('length = 167.36, angle = -14') | ||||
|             return true | ||||
|           }, | ||||
|           { timeout: 10_000 } | ||||
|         ) | ||||
|         .toBeTruthy() | ||||
|     }) | ||||
|  | ||||
| @ -3165,17 +3170,20 @@ test.describe('manual edits during sketch mode', () => { | ||||
|     await test.step('edit sketch again', async () => { | ||||
|       await page.waitForTimeout(500) // Wait for deferred execution | ||||
|       await expect | ||||
|         .poll(async () => { | ||||
|           await editor.expectEditor.toContain('length = 167.36, angle = -14') | ||||
|           await page.mouse.move(handle3Location.x, handle3Location.y) | ||||
|           await page.mouse.down() | ||||
|           await page.mouse.move(handle3Location.x, handle3Location.y + 110, { | ||||
|             steps: 5, | ||||
|           }) | ||||
|           await page.mouse.up() | ||||
|           await editor.expectEditor.toContain('length = 219.2, angle = -56') | ||||
|           return true | ||||
|         }) | ||||
|         .poll( | ||||
|           async () => { | ||||
|             await editor.expectEditor.toContain('length = 167.36, angle = -14') | ||||
|             await page.mouse.move(handle3Location.x, handle3Location.y) | ||||
|             await page.mouse.down() | ||||
|             await page.mouse.move(handle3Location.x, handle3Location.y + 110, { | ||||
|               steps: 5, | ||||
|             }) | ||||
|             await page.mouse.up() | ||||
|             await editor.expectEditor.toContain('length = 219.2, angle = -56') | ||||
|             return true | ||||
|           }, | ||||
|           { timeout: 10_000 } | ||||
|         ) | ||||
|         .toBeTruthy() | ||||
|     }) | ||||
|  | ||||
|  | ||||
| @ -44,7 +44,9 @@ | ||||
|         packages = | ||||
|           (with pkgs; [ | ||||
|             rustToolchain | ||||
|             cargo-criterion | ||||
|             cargo-nextest | ||||
|             cargo-sort | ||||
|             just | ||||
|             postgresql.lib | ||||
|             openssl | ||||
|  | ||||
| @ -25,10 +25,14 @@ When you submit a PR to add or modify KCL samples, images and STEP files will be | ||||
| --- | ||||
| #### [80-20-rail](80-20-rail/main.kcl) ([screenshot](screenshots/80-20-rail.png)) | ||||
| [](80-20-rail/main.kcl) | ||||
| #### [axial-fan](axial-fan/main.kcl) ([screenshot](screenshots/axial-fan.png)) | ||||
| [](axial-fan/main.kcl) | ||||
| #### [ball-bearing](ball-bearing/main.kcl) ([screenshot](screenshots/ball-bearing.png)) | ||||
| [](ball-bearing/main.kcl) | ||||
| #### [bench](bench/main.kcl) ([screenshot](screenshots/bench.png)) | ||||
| [](bench/main.kcl) | ||||
| #### [bottle](bottle/main.kcl) ([screenshot](screenshots/bottle.png)) | ||||
| [](bottle/main.kcl) | ||||
| #### [bracket](bracket/main.kcl) ([screenshot](screenshots/bracket.png)) | ||||
| [](bracket/main.kcl) | ||||
| #### [car-wheel-assembly](car-wheel-assembly/main.kcl) ([screenshot](screenshots/car-wheel-assembly.png)) | ||||
|  | ||||
							
								
								
									
										153
									
								
								public/kcl-samples/axial-fan/fan-housing.kcl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								public/kcl-samples/axial-fan/fan-housing.kcl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,153 @@ | ||||
| // Fan Housing | ||||
| // The plastic housing that contains the fan and the motor | ||||
|  | ||||
| // Set units | ||||
| @settings(defaultLengthUnit = mm) | ||||
|  | ||||
| // Import parameters | ||||
| import * from "parameters.kcl" | ||||
|  | ||||
| // Model the housing which holds the motor, the fan, and the mounting provisions | ||||
| // Bottom mounting face | ||||
| bottomFaceSketch = startSketchOn(XY) | ||||
|   |> startProfileAt([-fanSize / 2, -fanSize / 2], %) | ||||
|   |> angledLine(angle = 0, length = fanSize, tag = $rectangleSegmentA001) | ||||
|   |> angledLine(angle = segAng(rectangleSegmentA001) + 90, length = fanSize, tag = $rectangleSegmentB001) | ||||
|   |> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001) | ||||
|   |> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $rectangleSegmentD001) | ||||
|   |> close() | ||||
|   |> hole(circle(center = [0, 0], radius = 4), %) | ||||
|   |> hole(circle( | ||||
|        center = [ | ||||
|          mountingHoleSpacing / 2, | ||||
|          mountingHoleSpacing / 2 | ||||
|        ], | ||||
|        radius = mountingHoleSize / 2, | ||||
|      ), %) | ||||
|   |> hole(circle( | ||||
|        center = [ | ||||
|          -mountingHoleSpacing / 2, | ||||
|          mountingHoleSpacing / 2 | ||||
|        ], | ||||
|        radius = mountingHoleSize / 2, | ||||
|      ), %) | ||||
|   |> hole(circle( | ||||
|        center = [ | ||||
|          mountingHoleSpacing / 2, | ||||
|          -mountingHoleSpacing / 2 | ||||
|        ], | ||||
|        radius = mountingHoleSize / 2, | ||||
|      ), %) | ||||
|   |> hole(circle( | ||||
|        center = [ | ||||
|          -mountingHoleSpacing / 2, | ||||
|          -mountingHoleSpacing / 2 | ||||
|        ], | ||||
|        radius = mountingHoleSize / 2, | ||||
|      ), %) | ||||
|   |> extrude(length = 4) | ||||
|  | ||||
| // Add large openings to the bottom face to allow airflow through the fan | ||||
| airflowPattern = startSketchOn(bottomFaceSketch, face = END) | ||||
|   |> startProfileAt([fanSize * 7 / 25, -fanSize * 9 / 25], %) | ||||
|   |> angledLine(angle = 140, length = fanSize * 12 / 25, tag = $seg01) | ||||
|   |> tangentialArc(radius = fanSize * 1 / 50, angle = 90) | ||||
|   |> angledLine(angle = -130, length = fanSize * 8 / 25) | ||||
|   |> tangentialArc(radius = fanSize * 1 / 50, angle = 90) | ||||
|   |> angledLine(angle = segAng(seg01) + 180, length = fanSize * 2 / 25) | ||||
|   |> tangentialArc(radius = fanSize * 8 / 25, angle = 40) | ||||
|   |> xLine(length = fanSize * 3 / 25) | ||||
|   |> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)]) | ||||
|   |> close() | ||||
|   |> patternCircular2d( | ||||
|        instances = 4, | ||||
|        center = [0, 0], | ||||
|        arcDegrees = 360, | ||||
|        rotateDuplicates = true, | ||||
|      ) | ||||
|   |> extrude(length = -4) | ||||
|  | ||||
| // Create the middle segment of the fan housing body | ||||
| housingMiddleLength = fanSize / 3 | ||||
| housingMiddleRadius = fanSize / 3 - 1 | ||||
| bodyMiddle = startSketchOn(bottomFaceSketch, face = END) | ||||
|   |> startProfileAt([ | ||||
|        housingMiddleLength / 2, | ||||
|        -housingMiddleLength / 2 - housingMiddleRadius | ||||
|      ], %) | ||||
|   |> tangentialArc(radius = housingMiddleRadius, angle = 90) | ||||
|   |> yLine(length = housingMiddleLength) | ||||
|   |> tangentialArc(radius = housingMiddleRadius, angle = 90) | ||||
|   |> xLine(length = -housingMiddleLength) | ||||
|   |> tangentialArc(radius = housingMiddleRadius, angle = 90) | ||||
|   |> yLine(length = -housingMiddleLength) | ||||
|   |> tangentialArc(radius = housingMiddleRadius, angle = 90) | ||||
|   |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) | ||||
|   |> extrude(length = fanHeight - 4 - 4) | ||||
|  | ||||
| // Cut a hole in the body to accommodate the fan | ||||
| bodyFanHole = startSketchOn(bodyMiddle, face = END) | ||||
|   |> circle(center = [0, 0], radius = fanSize * 23 / 50) | ||||
|   |> extrude(length = -(fanHeight - 4 - 4)) | ||||
|  | ||||
| // Top mounting face. Cut a hole in the face to accommodate the fan | ||||
| topFaceSketch = startSketchOn(bodyMiddle, face = END) | ||||
| topHoles = startProfileAt([-fanSize / 2, -fanSize / 2], topFaceSketch) | ||||
|   |> angledLine(angle = 0, length = fanSize, tag = $rectangleSegmentA002) | ||||
|   |> angledLine(angle = segAng(rectangleSegmentA002) + 90, length = fanSize, tag = $rectangleSegmentB002) | ||||
|   |> angledLine(angle = segAng(rectangleSegmentA002), length = -segLen(rectangleSegmentA002), tag = $rectangleSegmentC002) | ||||
|   |> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $rectangleSegmentD002) | ||||
|   |> close() | ||||
|   |> hole(circle(center = [0, 0], radius = fanSize * 23 / 50), %) | ||||
|   |> hole(circle( | ||||
|        center = [ | ||||
|          mountingHoleSpacing / 2, | ||||
|          mountingHoleSpacing / 2 | ||||
|        ], | ||||
|        radius = mountingHoleSize / 2, | ||||
|      ), %) | ||||
|   |> hole(circle( | ||||
|        center = [ | ||||
|          -mountingHoleSpacing / 2, | ||||
|          mountingHoleSpacing / 2 | ||||
|        ], | ||||
|        radius = mountingHoleSize / 2, | ||||
|      ), %) | ||||
|   |> hole(circle( | ||||
|        center = [ | ||||
|          mountingHoleSpacing / 2, | ||||
|          -mountingHoleSpacing / 2 | ||||
|        ], | ||||
|        radius = mountingHoleSize / 2, | ||||
|      ), %) | ||||
|   |> hole(circle( | ||||
|        center = [ | ||||
|          -mountingHoleSpacing / 2, | ||||
|          -mountingHoleSpacing / 2 | ||||
|        ], | ||||
|        radius = mountingHoleSize / 2, | ||||
|      ), %) | ||||
|   |> extrude(length = 4) | ||||
|  | ||||
| // Create a housing for the electric motor to sit | ||||
| motorHousing = startSketchOn(bottomFaceSketch, face = END) | ||||
|   |> circle(center = [0, 0], radius = 11.2) | ||||
|   |> extrude(length = 16) | ||||
|  | ||||
| startSketchOn(motorHousing, face = END) | ||||
|   |> circle(center = [0, 0], radius = 10) | ||||
|   |> extrude(length = -16) | ||||
|   |> appearance(color = "#a55e2c") | ||||
|   |> fillet( | ||||
|        radius = abs(fanSize - mountingHoleSpacing) / 2, | ||||
|        tags = [ | ||||
|          getNextAdjacentEdge(rectangleSegmentA001), | ||||
|          getNextAdjacentEdge(rectangleSegmentB001), | ||||
|          getNextAdjacentEdge(rectangleSegmentC001), | ||||
|          getNextAdjacentEdge(rectangleSegmentD001), | ||||
|          getNextAdjacentEdge(rectangleSegmentA002), | ||||
|          getNextAdjacentEdge(rectangleSegmentB002), | ||||
|          getNextAdjacentEdge(rectangleSegmentC002), | ||||
|          getNextAdjacentEdge(rectangleSegmentD002) | ||||
|        ], | ||||
|      ) | ||||
							
								
								
									
										92
									
								
								public/kcl-samples/axial-fan/fan.kcl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								public/kcl-samples/axial-fan/fan.kcl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | ||||
| // Fan | ||||
| // Spinning axial fan that moves airflow | ||||
|  | ||||
| // Set units | ||||
| @settings(defaultLengthUnit = mm) | ||||
|  | ||||
| // Import parameters | ||||
| import * from "parameters.kcl" | ||||
|  | ||||
| // Model the center of the fan | ||||
| fanCenter = startSketchOn(XZ) | ||||
|   |> startProfileAt([-0.0001, fanHeight], %) | ||||
|   |> xLine(endAbsolute = -15 + 1.5) | ||||
|   |> tangentialArc(radius = 1.5, angle = 90) | ||||
|   |> yLine(endAbsolute = 4.5) | ||||
|   |> xLine(endAbsolute = -13) | ||||
|   |> yLine(endAbsolute = profileStartY(%) - 5) | ||||
|   |> tangentialArc(radius = 1, angle = -90) | ||||
|   |> xLine(endAbsolute = -1) | ||||
|   |> yLine(length = 2) | ||||
|   |> xLine(length = -0.15) | ||||
|   |> line(endAbsolute = [ | ||||
|        profileStartX(%) - 1, | ||||
|        profileStartY(%) - 1.4 | ||||
|      ]) | ||||
|   |> xLine(endAbsolute = profileStartX(%)) | ||||
|   |> yLine(endAbsolute = profileStartY(%)) | ||||
|   |> close() | ||||
|   |> revolve(axis = { | ||||
|        direction = [0.0, 1.0], | ||||
|        origin = [0.0, 0.0] | ||||
|      }) | ||||
|   |> appearance(color = "#f3e2d8") | ||||
|  | ||||
| // Create a function for a lofted fan blade cross section that rotates about the center hub of the fan | ||||
| fn fanBlade(offsetHeight, startAngle) { | ||||
|   fanBlade = startSketchOn(offsetPlane(XY, offset = offsetHeight)) | ||||
|     |> startProfileAt([ | ||||
|          15 * cos(toRadians(startAngle)), | ||||
|          15 * sin(toRadians(startAngle)) | ||||
|        ], %) | ||||
|     |> arc({ | ||||
|          angleStart = startAngle, | ||||
|          angleEnd = startAngle + 14, | ||||
|          radius = 15 | ||||
|        }, %) | ||||
|     |> arcTo({ | ||||
|          end = [ | ||||
|            fanSize * 22 / 50 * cos(toRadians(startAngle - 20)), | ||||
|            fanSize * 22 / 50 * sin(toRadians(startAngle - 20)) | ||||
|          ], | ||||
|          interior = [ | ||||
|            fanSize * 11 / 50 * cos(toRadians(startAngle + 3)), | ||||
|            fanSize * 11 / 50 * sin(toRadians(startAngle + 3)) | ||||
|          ] | ||||
|        }, %) | ||||
|     |> arcTo({ | ||||
|          end = [ | ||||
|            fanSize * 22 / 50 * cos(toRadians(startAngle - 24)), | ||||
|            fanSize * 22 / 50 * sin(toRadians(startAngle - 24)) | ||||
|          ], | ||||
|          interior = [ | ||||
|            fanSize * 22 / 50 * cos(toRadians(startAngle - 22)), | ||||
|            fanSize * 22 / 50 * sin(toRadians(startAngle - 22)) | ||||
|          ] | ||||
|        }, %) | ||||
|     |> arcTo({ | ||||
|          end = [profileStartX(%), profileStartY(%)], | ||||
|          interior = [ | ||||
|            fanSize * 11 / 50 * cos(toRadians(startAngle - 5)), | ||||
|            fanSize * 11 / 50 * sin(toRadians(startAngle - 5)) | ||||
|          ] | ||||
|        }, %) | ||||
|     |> close() | ||||
|   return fanBlade | ||||
| } | ||||
|  | ||||
| // Loft the fan blade cross sections into a single blade, then pattern them about the fan center | ||||
| loft([ | ||||
|        fanBlade(4.5, 50), | ||||
|        fanBlade((fanHeight - 2 - 4) / 2, 30), | ||||
|        fanBlade(fanHeight - 2, 0) | ||||
|      ]) | ||||
|   |> appearance(color = "#f3e2d8") | ||||
|   |> patternCircular3d( | ||||
|        %, | ||||
|        instances = 9, | ||||
|        axis = [0, 0, 1], | ||||
|        center = [0, 0, 0], | ||||
|        arcDegrees = 360, | ||||
|        rotateDuplicates = true, | ||||
|      ) | ||||
							
								
								
									
										15
									
								
								public/kcl-samples/axial-fan/main.kcl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								public/kcl-samples/axial-fan/main.kcl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| // PC Fan | ||||
| // A small axial fan, used to push or draw airflow over components to remove excess heat | ||||
|  | ||||
| // Set units | ||||
| @settings(defaultLengthUnit = mm) | ||||
|  | ||||
| // Import all parts into assembly file | ||||
| import "fan-housing.kcl" as fanHousing | ||||
| import "motor.kcl" as motor | ||||
| import "fan.kcl" as fan | ||||
|  | ||||
| // Produce the model for each imported part | ||||
| fanHousing | ||||
| motor | ||||
| fan | ||||
							
								
								
									
										22
									
								
								public/kcl-samples/axial-fan/motor.kcl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								public/kcl-samples/axial-fan/motor.kcl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| // Motor | ||||
| // A small electric motor to power the fan | ||||
|  | ||||
| // Set Units | ||||
| @settings(defaultLengthUnit = mm) | ||||
|  | ||||
| // Import Parameters | ||||
| import * from "parameters.kcl" | ||||
|  | ||||
| // Model the motor body and stem | ||||
|  | ||||
|  | ||||
| topFacePlane = offsetPlane(XY, offset = 4) | ||||
| motorBody = startSketchOn(topFacePlane) | ||||
|   |> circle(center = [0, 0], radius = 10, tag = $seg04) | ||||
|   |> extrude(length = 17) | ||||
|   |> appearance(color = "#021b55") | ||||
|   |> fillet(radius = 2, tags = [getOppositeEdge(seg04), seg04]) | ||||
| startSketchOn(offsetPlane(XY, offset = 21)) | ||||
|   |> circle(center = [0, 0], radius = 1) | ||||
|   |> extrude(length = 3.8) | ||||
|   |> appearance(color = "#dbc89e") | ||||
							
								
								
									
										10
									
								
								public/kcl-samples/axial-fan/parameters.kcl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								public/kcl-samples/axial-fan/parameters.kcl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| // Global parameters for the axial fan | ||||
|  | ||||
| // Set units | ||||
| @settings(defaultLengthUnit = mm) | ||||
|  | ||||
| // Define Parameters | ||||
| export fanSize = 120 | ||||
| export fanHeight = 25 | ||||
| export mountingHoleSpacing = 105 | ||||
| export mountingHoleSize = 4.5 | ||||
							
								
								
									
										35
									
								
								public/kcl-samples/bottle/main.kcl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								public/kcl-samples/bottle/main.kcl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| // Bottle | ||||
| // A simple bottle with a hollow, watertight interior | ||||
|  | ||||
| // Set Units | ||||
| @settings(defaultLengthUnit = mm) | ||||
|  | ||||
| // Input dimensions to define the bottle | ||||
| bottleWidth = 80 | ||||
| bottleLength = 125 | ||||
| bottleHeight = 220 | ||||
| neckDepth = 18 | ||||
| neckDiameter = 45 | ||||
| wallThickness = 4 | ||||
|  | ||||
| // Create a rounded body for the bottle | ||||
| bottleBody = startSketchOn(XY) | ||||
|   |> startProfileAt([-bottleLength / 2, 0], %) | ||||
|   |> yLine(length = bottleWidth / 3) | ||||
|   |> arcTo({ | ||||
|        end = [bottleLength / 2, bottleWidth / 3], | ||||
|        interior = [0, bottleWidth / 2] | ||||
|      }, %) | ||||
|   |> yLine(endAbsolute = 0) | ||||
|   |> mirror2d(axis = X) | ||||
|   |> close() | ||||
|   |> extrude(length = bottleHeight - neckDepth) | ||||
|  | ||||
| // Create a neck centered at the top of the bottle | ||||
| bottleNeck = startSketchOn(bottleBody, face = END) | ||||
|   |> circle(center = [0, 0], radius = neckDiameter / 2) | ||||
|   |> extrude(length = neckDepth) | ||||
|  | ||||
| // Define a shell operation so that the entire body and neck are hollow, with only the top face opened | ||||
| bottleShell = shell(bottleNeck, faces = [END], thickness = wallThickness) | ||||
|   |> appearance(%, color = "#0078c2") | ||||
| @ -6,6 +6,13 @@ | ||||
|     "title": "80/20 Rail", | ||||
|     "description": "An 80/20 extruded aluminum linear rail. T-slot profile adjustable by profile height, rail length, and origin position" | ||||
|   }, | ||||
|   { | ||||
|     "file": "main.kcl", | ||||
|     "pathFromProjectDirectoryToFirstFile": "axial-fan/main.kcl", | ||||
|     "multipleFiles": true, | ||||
|     "title": "PC Fan", | ||||
|     "description": "A small axial fan, used to push or draw airflow over components to remove excess heat" | ||||
|   }, | ||||
|   { | ||||
|     "file": "main.kcl", | ||||
|     "pathFromProjectDirectoryToFirstFile": "ball-bearing/main.kcl", | ||||
| @ -20,6 +27,13 @@ | ||||
|     "title": "Bench", | ||||
|     "description": "This is a slight remix of Depep1's original 3D Boaty (https://www.printables.com/model/1141963-3d-boaty). This is a tool used for benchmarking 3D FDM printers for bed adhesion, overhangs, bridging and top surface quality. The name of this file is a bit of misnomer, the shape of the object is a typical park bench." | ||||
|   }, | ||||
|   { | ||||
|     "file": "main.kcl", | ||||
|     "pathFromProjectDirectoryToFirstFile": "bottle/main.kcl", | ||||
|     "multipleFiles": false, | ||||
|     "title": "Bottle", | ||||
|     "description": "A simple bottle with a hollow, watertight interior" | ||||
|   }, | ||||
|   { | ||||
|     "file": "main.kcl", | ||||
|     "pathFromProjectDirectoryToFirstFile": "bracket/main.kcl", | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								public/kcl-samples/screenshots/axial-fan.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/kcl-samples/screenshots/axial-fan.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 105 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/kcl-samples/screenshots/bottle.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/kcl-samples/screenshots/bottle.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 70 KiB | 
							
								
								
									
										89
									
								
								rust/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										89
									
								
								rust/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -535,7 +535,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" | ||||
| dependencies = [ | ||||
|  "lazy_static", | ||||
|  "windows-sys 0.52.0", | ||||
|  "windows-sys 0.59.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| @ -758,7 +758,7 @@ dependencies = [ | ||||
|  "hashbrown 0.14.5", | ||||
|  "lock_api", | ||||
|  "once_cell", | ||||
|  "parking_lot_core", | ||||
|  "parking_lot_core 0.9.10", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| @ -772,7 +772,7 @@ dependencies = [ | ||||
|  "hashbrown 0.14.5", | ||||
|  "lock_api", | ||||
|  "once_cell", | ||||
|  "parking_lot_core", | ||||
|  "parking_lot_core 0.9.10", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| @ -847,7 +847,7 @@ dependencies = [ | ||||
|  "backtrace", | ||||
|  "lazy_static", | ||||
|  "mintex", | ||||
|  "parking_lot", | ||||
|  "parking_lot 0.12.3", | ||||
|  "rustc-hash 1.1.0", | ||||
|  "serde", | ||||
|  "serde_json", | ||||
| @ -954,7 +954,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
|  "windows-sys 0.52.0", | ||||
|  "windows-sys 0.59.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| @ -1697,6 +1697,18 @@ dependencies = [ | ||||
|  "similar", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "instant" | ||||
| version = "0.1.13" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
|  "js-sys", | ||||
|  "wasm-bindgen", | ||||
|  "web-sys", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "ipnet" | ||||
| version = "2.11.0" | ||||
| @ -1711,7 +1723,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" | ||||
| dependencies = [ | ||||
|  "hermit-abi", | ||||
|  "libc", | ||||
|  "windows-sys 0.52.0", | ||||
|  "windows-sys 0.59.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| @ -1885,6 +1897,7 @@ dependencies = [ | ||||
|  "image", | ||||
|  "indexmap 2.8.0", | ||||
|  "insta", | ||||
|  "instant", | ||||
|  "itertools 0.13.0", | ||||
|  "js-sys", | ||||
|  "kcl-derive-docs", | ||||
| @ -1921,6 +1934,7 @@ dependencies = [ | ||||
|  "validator", | ||||
|  "wasm-bindgen", | ||||
|  "wasm-bindgen-futures", | ||||
|  "wasm-timer", | ||||
|  "web-sys", | ||||
|  "web-time", | ||||
|  "winnow 0.6.24", | ||||
| @ -2460,6 +2474,17 @@ dependencies = [ | ||||
|  "unicode-width 0.2.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "parking_lot" | ||||
| version = "0.11.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" | ||||
| dependencies = [ | ||||
|  "instant", | ||||
|  "lock_api", | ||||
|  "parking_lot_core 0.8.6", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "parking_lot" | ||||
| version = "0.12.3" | ||||
| @ -2467,7 +2492,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" | ||||
| dependencies = [ | ||||
|  "lock_api", | ||||
|  "parking_lot_core", | ||||
|  "parking_lot_core 0.9.10", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "parking_lot_core" | ||||
| version = "0.8.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
|  "instant", | ||||
|  "libc", | ||||
|  "redox_syscall 0.2.16", | ||||
|  "smallvec", | ||||
|  "winapi", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| @ -2478,7 +2517,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
|  "libc", | ||||
|  "redox_syscall", | ||||
|  "redox_syscall 0.5.10", | ||||
|  "smallvec", | ||||
|  "windows-targets 0.52.6", | ||||
| ] | ||||
| @ -2883,7 +2922,7 @@ dependencies = [ | ||||
|  "once_cell", | ||||
|  "socket2", | ||||
|  "tracing", | ||||
|  "windows-sys 0.52.0", | ||||
|  "windows-sys 0.59.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| @ -3018,6 +3057,15 @@ dependencies = [ | ||||
|  "rand_core 0.3.1", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "redox_syscall" | ||||
| version = "0.2.16" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" | ||||
| dependencies = [ | ||||
|  "bitflags 1.3.2", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "redox_syscall" | ||||
| version = "0.5.10" | ||||
| @ -3211,7 +3259,7 @@ dependencies = [ | ||||
|  "errno", | ||||
|  "libc", | ||||
|  "linux-raw-sys", | ||||
|  "windows-sys 0.52.0", | ||||
|  "windows-sys 0.59.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| @ -3809,7 +3857,7 @@ dependencies = [ | ||||
|  "getrandom 0.3.1", | ||||
|  "once_cell", | ||||
|  "rustix", | ||||
|  "windows-sys 0.52.0", | ||||
|  "windows-sys 0.59.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| @ -3984,7 +4032,7 @@ dependencies = [ | ||||
|  "bytes", | ||||
|  "libc", | ||||
|  "mio", | ||||
|  "parking_lot", | ||||
|  "parking_lot 0.12.3", | ||||
|  "pin-project-lite", | ||||
|  "signal-hook-registry", | ||||
|  "socket2", | ||||
| @ -4581,6 +4629,21 @@ dependencies = [ | ||||
|  "web-sys", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "wasm-timer" | ||||
| version = "0.2.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" | ||||
| dependencies = [ | ||||
|  "futures", | ||||
|  "js-sys", | ||||
|  "parking_lot 0.11.2", | ||||
|  "pin-utils", | ||||
|  "wasm-bindgen", | ||||
|  "wasm-bindgen-futures", | ||||
|  "web-sys", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "web-sys" | ||||
| version = "0.3.77" | ||||
| @ -4632,7 +4695,7 @@ version = "0.1.9" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" | ||||
| dependencies = [ | ||||
|  "windows-sys 0.52.0", | ||||
|  "windows-sys 0.59.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
|  | ||||
| @ -89,14 +89,17 @@ winnow = "=0.6.24" | ||||
| zip = { workspace = true } | ||||
|  | ||||
| [target.'cfg(target_arch = "wasm32")'.dependencies] | ||||
| instant = { version = "0.1.13", features = ["wasm-bindgen", "inaccurate"] } | ||||
| js-sys = { version = "0.3.72" } | ||||
| tokio = { workspace = true, features = ["sync", "time"] } | ||||
| tower-lsp = { workspace = true, features = ["runtime-agnostic"] } | ||||
| wasm-bindgen = "0.2.99" | ||||
| wasm-bindgen-futures = "0.4.49" | ||||
| wasm-timer = "0.2.5" | ||||
| web-sys = { version = "0.3.76", features = ["console"] } | ||||
|  | ||||
| [target.'cfg(not(target_arch = "wasm32"))'.dependencies] | ||||
| instant = "0.1.13" | ||||
| tokio = { workspace = true, features = ["full"] } | ||||
| tokio-tungstenite = { version = "0.24.0", features = [ | ||||
|     "rustls-tls-native-roots", | ||||
|  | ||||
| @ -2109,7 +2109,7 @@ async fn kcl_test_better_type_names() { | ||||
|         }, | ||||
|         None => todo!(), | ||||
|     }; | ||||
|     assert_eq!(err, "This function expected the input argument to be one or more Solids but it's actually of type Sketch. You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`"); | ||||
|     assert_eq!(err, "This function expected the input argument to be one or more Solids or imported geometry but it's actually of type Sketch. You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`"); | ||||
| } | ||||
|  | ||||
| #[tokio::test(flavor = "multi_thread")] | ||||
|  | ||||
| @ -133,6 +133,7 @@ impl StdLibFnArg { | ||||
|             || self.type_ == "[Solid]" | ||||
|             || self.type_ == "SketchSurface" | ||||
|             || self.type_ == "SketchOrSurface" | ||||
|             || self.type_ == "SolidOrImportedGeometry" | ||||
|             || self.type_ == "SolidOrSketchOrImportedGeometry") | ||||
|             && (self.required || self.include_in_snippet) | ||||
|         { | ||||
|  | ||||
| @ -45,6 +45,7 @@ pub struct EngineConnection { | ||||
|     batch: Arc<RwLock<Vec<(WebSocketRequest, SourceRange)>>>, | ||||
|     batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>, | ||||
|     artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>, | ||||
|     ids_of_async_commands: Arc<RwLock<IndexMap<Uuid, SourceRange>>>, | ||||
|  | ||||
|     /// The default planes for the scene. | ||||
|     default_planes: Arc<RwLock<Option<DefaultPlanes>>>, | ||||
| @ -115,6 +116,17 @@ impl Drop for TcpReadHandle { | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct ResponsesInformation { | ||||
|     /// The responses from the engine. | ||||
|     responses: Arc<RwLock<IndexMap<uuid::Uuid, WebSocketResponse>>>, | ||||
| } | ||||
|  | ||||
| impl ResponsesInformation { | ||||
|     pub async fn add(&self, id: Uuid, response: WebSocketResponse) { | ||||
|         self.responses.write().await.insert(id, response); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Requests to send to the engine, and a way to await a response. | ||||
| struct ToEngineReq { | ||||
|     /// The request to send | ||||
| @ -227,10 +239,13 @@ impl EngineConnection { | ||||
|         let session_data: Arc<RwLock<Option<ModelingSessionData>>> = Arc::new(RwLock::new(None)); | ||||
|         let session_data2 = session_data.clone(); | ||||
|         let responses: Arc<RwLock<IndexMap<uuid::Uuid, WebSocketResponse>>> = Arc::new(RwLock::new(IndexMap::new())); | ||||
|         let responses_clone = responses.clone(); | ||||
|         let ids_of_async_commands: Arc<RwLock<IndexMap<Uuid, SourceRange>>> = Arc::new(RwLock::new(IndexMap::new())); | ||||
|         let socket_health = Arc::new(RwLock::new(SocketHealth::Active)); | ||||
|         let pending_errors = Arc::new(RwLock::new(Vec::new())); | ||||
|         let pending_errors_clone = pending_errors.clone(); | ||||
|         let responses_information = ResponsesInformation { | ||||
|             responses: responses.clone(), | ||||
|         }; | ||||
|  | ||||
|         let socket_health_tcp_read = socket_health.clone(); | ||||
|         let tcp_read_handle = tokio::spawn(async move { | ||||
| @ -244,8 +259,7 @@ impl EngineConnection { | ||||
|                             WebSocketResponse::Success(SuccessWebSocketResponse { | ||||
|                                 resp: OkWebSocketResponseData::ModelingBatch { responses }, | ||||
|                                 .. | ||||
|                             }) => | ||||
|                             { | ||||
|                             }) => { | ||||
|                                 #[expect( | ||||
|                                     clippy::iter_over_hash_type, | ||||
|                                     reason = "modeling command uses a HashMap and keys are random, so we don't really have a choice" | ||||
| @ -254,26 +268,32 @@ impl EngineConnection { | ||||
|                                     let id: uuid::Uuid = (*resp_id).into(); | ||||
|                                     match batch_response { | ||||
|                                         BatchResponse::Success { response } => { | ||||
|                                             responses_clone.write().await.insert( | ||||
|                                                 id, | ||||
|                                                 WebSocketResponse::Success(SuccessWebSocketResponse { | ||||
|                                                     success: true, | ||||
|                                                     request_id: Some(id), | ||||
|                                                     resp: OkWebSocketResponseData::Modeling { | ||||
|                                                         modeling_response: response.clone(), | ||||
|                                                     }, | ||||
|                                                 }), | ||||
|                                             ); | ||||
|                                             // If the id is in our ids of async commands, remove | ||||
|                                             // it. | ||||
|                                             responses_information | ||||
|                                                 .add( | ||||
|                                                     id, | ||||
|                                                     WebSocketResponse::Success(SuccessWebSocketResponse { | ||||
|                                                         success: true, | ||||
|                                                         request_id: Some(id), | ||||
|                                                         resp: OkWebSocketResponseData::Modeling { | ||||
|                                                             modeling_response: response.clone(), | ||||
|                                                         }, | ||||
|                                                     }), | ||||
|                                                 ) | ||||
|                                                 .await; | ||||
|                                         } | ||||
|                                         BatchResponse::Failure { errors } => { | ||||
|                                             responses_clone.write().await.insert( | ||||
|                                                 id, | ||||
|                                                 WebSocketResponse::Failure(FailureWebSocketResponse { | ||||
|                                                     success: false, | ||||
|                                                     request_id: Some(id), | ||||
|                                                     errors: errors.clone(), | ||||
|                                                 }), | ||||
|                                             ); | ||||
|                                             responses_information | ||||
|                                                 .add( | ||||
|                                                     id, | ||||
|                                                     WebSocketResponse::Failure(FailureWebSocketResponse { | ||||
|                                                         success: false, | ||||
|                                                         request_id: Some(id), | ||||
|                                                         errors: errors.clone(), | ||||
|                                                     }), | ||||
|                                                 ) | ||||
|                                                 .await; | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
| @ -291,14 +311,16 @@ impl EngineConnection { | ||||
|                                 errors, | ||||
|                             }) => { | ||||
|                                 if let Some(id) = request_id { | ||||
|                                     responses_clone.write().await.insert( | ||||
|                                         *id, | ||||
|                                         WebSocketResponse::Failure(FailureWebSocketResponse { | ||||
|                                             success: false, | ||||
|                                             request_id: *request_id, | ||||
|                                             errors: errors.clone(), | ||||
|                                         }), | ||||
|                                     ); | ||||
|                                     responses_information | ||||
|                                         .add( | ||||
|                                             *id, | ||||
|                                             WebSocketResponse::Failure(FailureWebSocketResponse { | ||||
|                                                 success: false, | ||||
|                                                 request_id: *request_id, | ||||
|                                                 errors: errors.clone(), | ||||
|                                             }), | ||||
|                                         ) | ||||
|                                         .await; | ||||
|                                 } else { | ||||
|                                     // Add it to our pending errors. | ||||
|                                     let mut pe = pending_errors_clone.write().await; | ||||
| @ -314,7 +336,7 @@ impl EngineConnection { | ||||
|                         } | ||||
|  | ||||
|                         if let Some(id) = id { | ||||
|                             responses_clone.write().await.insert(id, ws_resp.clone()); | ||||
|                             responses_information.add(id, ws_resp.clone()).await; | ||||
|                         } | ||||
|                     } | ||||
|                     Err(e) => { | ||||
| @ -341,6 +363,7 @@ impl EngineConnection { | ||||
|             batch: Arc::new(RwLock::new(Vec::new())), | ||||
|             batch_end: Arc::new(RwLock::new(IndexMap::new())), | ||||
|             artifact_commands: Arc::new(RwLock::new(Vec::new())), | ||||
|             ids_of_async_commands, | ||||
|             default_planes: Default::default(), | ||||
|             session_data, | ||||
|             stats: Default::default(), | ||||
| @ -366,6 +389,10 @@ impl EngineManager for EngineConnection { | ||||
|         self.artifact_commands.clone() | ||||
|     } | ||||
|  | ||||
|     fn ids_of_async_commands(&self) -> Arc<RwLock<IndexMap<Uuid, SourceRange>>> { | ||||
|         self.ids_of_async_commands.clone() | ||||
|     } | ||||
|  | ||||
|     fn stats(&self) -> &EngineStats { | ||||
|         &self.stats | ||||
|     } | ||||
| @ -386,13 +413,13 @@ impl EngineManager for EngineConnection { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     async fn inner_send_modeling_cmd( | ||||
|     async fn inner_fire_modeling_cmd( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
|         _id: uuid::Uuid, | ||||
|         source_range: SourceRange, | ||||
|         cmd: WebSocketRequest, | ||||
|         _id_to_source_range: HashMap<Uuid, SourceRange>, | ||||
|     ) -> Result<WebSocketResponse, KclError> { | ||||
|     ) -> Result<(), KclError> { | ||||
|         let (tx, rx) = oneshot::channel(); | ||||
|  | ||||
|         // Send the request to the engine, via the actor. | ||||
| @ -424,6 +451,19 @@ impl EngineManager for EngineConnection { | ||||
|                 }) | ||||
|             })?; | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     async fn inner_send_modeling_cmd( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
|         source_range: SourceRange, | ||||
|         cmd: WebSocketRequest, | ||||
|         id_to_source_range: HashMap<Uuid, SourceRange>, | ||||
|     ) -> Result<WebSocketResponse, KclError> { | ||||
|         self.inner_fire_modeling_cmd(id, source_range, cmd, id_to_source_range) | ||||
|             .await?; | ||||
|  | ||||
|         // Wait for the response. | ||||
|         let current_time = std::time::Instant::now(); | ||||
|         while current_time.elapsed().as_secs() < 60 { | ||||
|  | ||||
| @ -12,7 +12,7 @@ use kcmc::{ | ||||
|         WebSocketResponse, | ||||
|     }, | ||||
| }; | ||||
| use kittycad_modeling_cmds::{self as kcmc}; | ||||
| use kittycad_modeling_cmds::{self as kcmc, websocket::ModelingCmdReq, ImportFiles, ModelingCmd}; | ||||
| use tokio::sync::RwLock; | ||||
| use uuid::Uuid; | ||||
|  | ||||
| @ -29,6 +29,8 @@ pub struct EngineConnection { | ||||
|     batch: Arc<RwLock<Vec<(WebSocketRequest, SourceRange)>>>, | ||||
|     batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>, | ||||
|     artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>, | ||||
|     ids_of_async_commands: Arc<RwLock<IndexMap<Uuid, SourceRange>>>, | ||||
|     responses: Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>>, | ||||
|     /// The default planes for the scene. | ||||
|     default_planes: Arc<RwLock<Option<DefaultPlanes>>>, | ||||
|     stats: EngineStats, | ||||
| @ -40,6 +42,8 @@ impl EngineConnection { | ||||
|             batch: Arc::new(RwLock::new(Vec::new())), | ||||
|             batch_end: Arc::new(RwLock::new(IndexMap::new())), | ||||
|             artifact_commands: Arc::new(RwLock::new(Vec::new())), | ||||
|             ids_of_async_commands: Arc::new(RwLock::new(IndexMap::new())), | ||||
|             responses: Arc::new(RwLock::new(IndexMap::new())), | ||||
|             default_planes: Default::default(), | ||||
|             stats: Default::default(), | ||||
|         }) | ||||
| @ -57,7 +61,7 @@ impl crate::engine::EngineManager for EngineConnection { | ||||
|     } | ||||
|  | ||||
|     fn responses(&self) -> Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>> { | ||||
|         Arc::new(RwLock::new(IndexMap::new())) | ||||
|         self.responses.clone() | ||||
|     } | ||||
|  | ||||
|     fn stats(&self) -> &EngineStats { | ||||
| @ -68,6 +72,10 @@ impl crate::engine::EngineManager for EngineConnection { | ||||
|         self.artifact_commands.clone() | ||||
|     } | ||||
|  | ||||
|     fn ids_of_async_commands(&self) -> Arc<RwLock<IndexMap<Uuid, SourceRange>>> { | ||||
|         self.ids_of_async_commands.clone() | ||||
|     } | ||||
|  | ||||
|     fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> { | ||||
|         self.default_planes.clone() | ||||
|     } | ||||
| @ -80,6 +88,25 @@ impl crate::engine::EngineManager for EngineConnection { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     async fn inner_fire_modeling_cmd( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
|         source_range: SourceRange, | ||||
|         cmd: WebSocketRequest, | ||||
|         id_to_source_range: HashMap<Uuid, SourceRange>, | ||||
|     ) -> Result<(), KclError> { | ||||
|         // Pop off the id we care about. | ||||
|         self.ids_of_async_commands.write().await.swap_remove(&id); | ||||
|  | ||||
|         // Add the response to our responses. | ||||
|         let response = self | ||||
|             .inner_send_modeling_cmd(id, source_range, cmd, id_to_source_range) | ||||
|             .await?; | ||||
|         self.responses().write().await.insert(id, response); | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     async fn inner_send_modeling_cmd( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
| @ -109,6 +136,20 @@ impl crate::engine::EngineManager for EngineConnection { | ||||
|                     success: true, | ||||
|                 })) | ||||
|             } | ||||
|             WebSocketRequest::ModelingCmdReq(ModelingCmdReq { | ||||
|                 cmd: ModelingCmd::ImportFiles(ImportFiles { .. }), | ||||
|                 cmd_id, | ||||
|             }) => Ok(WebSocketResponse::Success(SuccessWebSocketResponse { | ||||
|                 request_id: Some(id), | ||||
|                 resp: OkWebSocketResponseData::Modeling { | ||||
|                     modeling_response: OkModelingCmdResponse::ImportFiles( | ||||
|                         kittycad_modeling_cmds::output::ImportFiles { | ||||
|                             object_id: cmd_id.into(), | ||||
|                         }, | ||||
|                     ), | ||||
|                 }, | ||||
|                 success: true, | ||||
|             })), | ||||
|             WebSocketRequest::ModelingCmdReq(_) => Ok(WebSocketResponse::Success(SuccessWebSocketResponse { | ||||
|                 request_id: Some(id), | ||||
|                 resp: OkWebSocketResponseData::Modeling { | ||||
|  | ||||
| @ -22,6 +22,15 @@ extern "C" { | ||||
|     #[derive(Debug, Clone)] | ||||
|     pub type EngineCommandManager; | ||||
|  | ||||
|     #[wasm_bindgen(method, js_name = fireModelingCommandFromWasm, catch)] | ||||
|     fn fire_modeling_cmd_from_wasm( | ||||
|         this: &EngineCommandManager, | ||||
|         id: String, | ||||
|         rangeStr: String, | ||||
|         cmdStr: String, | ||||
|         idToRangeStr: String, | ||||
|     ) -> Result<(), js_sys::Error>; | ||||
|  | ||||
|     #[wasm_bindgen(method, js_name = sendModelingCommandFromWasm, catch)] | ||||
|     fn send_modeling_cmd_from_wasm( | ||||
|         this: &EngineCommandManager, | ||||
| @ -38,33 +47,128 @@ extern "C" { | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct EngineConnection { | ||||
|     manager: Arc<EngineCommandManager>, | ||||
|     response_context: Arc<ResponseContext>, | ||||
|     batch: Arc<RwLock<Vec<(WebSocketRequest, SourceRange)>>>, | ||||
|     batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>, | ||||
|     responses: Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>>, | ||||
|     artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>, | ||||
|     ids_of_async_commands: Arc<RwLock<IndexMap<Uuid, SourceRange>>>, | ||||
|     /// The default planes for the scene. | ||||
|     default_planes: Arc<RwLock<Option<DefaultPlanes>>>, | ||||
|     stats: EngineStats, | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct ResponseContext { | ||||
|     responses: Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>>, | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| impl ResponseContext { | ||||
|     #[wasm_bindgen(constructor)] | ||||
|     pub fn new() -> Self { | ||||
|         Self { | ||||
|             responses: Arc::new(RwLock::new(IndexMap::new())), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Add a response to the context. | ||||
|     pub async fn send_response(&self, data: js_sys::Uint8Array) -> Result<(), JsValue> { | ||||
|         let ws_result: WebSocketResponse = match bson::from_slice(&data.to_vec()) { | ||||
|             Ok(res) => res, | ||||
|             Err(_) => { | ||||
|                 // We don't care about the error if we can't parse it. | ||||
|                 return Ok(()); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         let id = match &ws_result { | ||||
|             WebSocketResponse::Success(res) => res.request_id, | ||||
|             WebSocketResponse::Failure(res) => res.request_id, | ||||
|         }; | ||||
|  | ||||
|         let Some(id) = id else { | ||||
|             // We only care if we have an id. | ||||
|             return Ok(()); | ||||
|         }; | ||||
|  | ||||
|         // Add this response to our responses. | ||||
|         self.add(id, ws_result.clone()).await; | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl ResponseContext { | ||||
|     pub async fn add(&self, id: Uuid, response: WebSocketResponse) { | ||||
|         self.responses.write().await.insert(id, response); | ||||
|     } | ||||
|  | ||||
|     pub fn responses(&self) -> Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>> { | ||||
|         self.responses.clone() | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Safety: WebAssembly will only ever run in a single-threaded context. | ||||
| unsafe impl Send for EngineConnection {} | ||||
| unsafe impl Sync for EngineConnection {} | ||||
|  | ||||
| impl EngineConnection { | ||||
|     pub async fn new(manager: EngineCommandManager) -> Result<EngineConnection, JsValue> { | ||||
|     pub async fn new( | ||||
|         manager: EngineCommandManager, | ||||
|         response_context: Arc<ResponseContext>, | ||||
|     ) -> Result<EngineConnection, JsValue> { | ||||
|         #[allow(clippy::arc_with_non_send_sync)] | ||||
|         Ok(EngineConnection { | ||||
|             manager: Arc::new(manager), | ||||
|             batch: Arc::new(RwLock::new(Vec::new())), | ||||
|             batch_end: Arc::new(RwLock::new(IndexMap::new())), | ||||
|             responses: Arc::new(RwLock::new(IndexMap::new())), | ||||
|             response_context, | ||||
|             artifact_commands: Arc::new(RwLock::new(Vec::new())), | ||||
|             ids_of_async_commands: Arc::new(RwLock::new(IndexMap::new())), | ||||
|             default_planes: Default::default(), | ||||
|             stats: Default::default(), | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     async fn do_fire_modeling_cmd( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
|         source_range: SourceRange, | ||||
|         cmd: WebSocketRequest, | ||||
|         id_to_source_range: HashMap<uuid::Uuid, SourceRange>, | ||||
|     ) -> Result<(), KclError> { | ||||
|         let source_range_str = serde_json::to_string(&source_range).map_err(|e| { | ||||
|             KclError::Engine(KclErrorDetails { | ||||
|                 message: format!("Failed to serialize source range: {:?}", e), | ||||
|                 source_ranges: vec![source_range], | ||||
|             }) | ||||
|         })?; | ||||
|         let cmd_str = serde_json::to_string(&cmd).map_err(|e| { | ||||
|             KclError::Engine(KclErrorDetails { | ||||
|                 message: format!("Failed to serialize modeling command: {:?}", e), | ||||
|                 source_ranges: vec![source_range], | ||||
|             }) | ||||
|         })?; | ||||
|         let id_to_source_range_str = serde_json::to_string(&id_to_source_range).map_err(|e| { | ||||
|             KclError::Engine(KclErrorDetails { | ||||
|                 message: format!("Failed to serialize id to source range: {:?}", e), | ||||
|                 source_ranges: vec![source_range], | ||||
|             }) | ||||
|         })?; | ||||
|  | ||||
|         self.manager | ||||
|             .fire_modeling_cmd_from_wasm(id.to_string(), source_range_str, cmd_str, id_to_source_range_str) | ||||
|             .map_err(|e| { | ||||
|                 KclError::Engine(KclErrorDetails { | ||||
|                     message: e.to_string().into(), | ||||
|                     source_ranges: vec![source_range], | ||||
|                 }) | ||||
|             })?; | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     async fn do_send_modeling_cmd( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
| @ -151,7 +255,7 @@ impl crate::engine::EngineManager for EngineConnection { | ||||
|     } | ||||
|  | ||||
|     fn responses(&self) -> Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>> { | ||||
|         self.responses.clone() | ||||
|         self.response_context.responses.clone() | ||||
|     } | ||||
|  | ||||
|     fn stats(&self) -> &EngineStats { | ||||
| @ -162,6 +266,10 @@ impl crate::engine::EngineManager for EngineConnection { | ||||
|         self.artifact_commands.clone() | ||||
|     } | ||||
|  | ||||
|     fn ids_of_async_commands(&self) -> Arc<RwLock<IndexMap<Uuid, SourceRange>>> { | ||||
|         self.ids_of_async_commands.clone() | ||||
|     } | ||||
|  | ||||
|     fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> { | ||||
|         self.default_planes.clone() | ||||
|     } | ||||
| @ -193,6 +301,19 @@ impl crate::engine::EngineManager for EngineConnection { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     async fn inner_fire_modeling_cmd( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
|         source_range: SourceRange, | ||||
|         cmd: WebSocketRequest, | ||||
|         id_to_source_range: HashMap<Uuid, SourceRange>, | ||||
|     ) -> Result<(), KclError> { | ||||
|         self.do_fire_modeling_cmd(id, source_range, cmd, id_to_source_range) | ||||
|             .await?; | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     async fn inner_send_modeling_cmd( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
| @ -204,9 +325,7 @@ impl crate::engine::EngineManager for EngineConnection { | ||||
|             .do_send_modeling_cmd(id, source_range, cmd, id_to_source_range) | ||||
|             .await?; | ||||
|  | ||||
|         let mut responses = self.responses.write().await; | ||||
|         responses.insert(id, ws_result.clone()); | ||||
|         drop(responses); | ||||
|         self.response_context.add(id, ws_result.clone()).await; | ||||
|  | ||||
|         Ok(ws_result) | ||||
|     } | ||||
|  | ||||
| @ -76,6 +76,9 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { | ||||
|     /// Get the artifact commands that have accumulated so far. | ||||
|     fn artifact_commands(&self) -> Arc<RwLock<Vec<ArtifactCommand>>>; | ||||
|  | ||||
|     /// Get the ids of the async commands we are waiting for. | ||||
|     fn ids_of_async_commands(&self) -> Arc<RwLock<IndexMap<Uuid, SourceRange>>>; | ||||
|  | ||||
|     /// Take the batch of commands that have accumulated so far and clear them. | ||||
|     async fn take_batch(&self) -> Vec<(WebSocketRequest, SourceRange)> { | ||||
|         std::mem::take(&mut *self.batch().write().await) | ||||
| @ -96,6 +99,11 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { | ||||
|         std::mem::take(&mut *self.artifact_commands().write().await) | ||||
|     } | ||||
|  | ||||
|     /// Take the ids of async commands that have accumulated so far and clear them. | ||||
|     async fn take_ids_of_async_commands(&self) -> IndexMap<Uuid, SourceRange> { | ||||
|         std::mem::take(&mut *self.ids_of_async_commands().write().await) | ||||
|     } | ||||
|  | ||||
|     /// Take the responses that have accumulated so far and clear them. | ||||
|     async fn take_responses(&self) -> IndexMap<Uuid, WebSocketResponse> { | ||||
|         std::mem::take(&mut *self.responses().write().await) | ||||
| @ -136,8 +144,18 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { | ||||
|     async fn clear_queues(&self) { | ||||
|         self.batch().write().await.clear(); | ||||
|         self.batch_end().write().await.clear(); | ||||
|         self.ids_of_async_commands().write().await.clear(); | ||||
|     } | ||||
|  | ||||
|     /// Send a modeling command and do not wait for the response message. | ||||
|     async fn inner_fire_modeling_cmd( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
|         source_range: SourceRange, | ||||
|         cmd: WebSocketRequest, | ||||
|         id_to_source_range: HashMap<Uuid, SourceRange>, | ||||
|     ) -> Result<(), crate::errors::KclError>; | ||||
|  | ||||
|     /// Send a modeling command and wait for the response message. | ||||
|     async fn inner_send_modeling_cmd( | ||||
|         &self, | ||||
| @ -180,6 +198,68 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Ensure a specific async command has been completed. | ||||
|     async fn ensure_async_command_completed( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
|         source_range: Option<SourceRange>, | ||||
|     ) -> Result<OkWebSocketResponseData, KclError> { | ||||
|         let source_range = if let Some(source_range) = source_range { | ||||
|             source_range | ||||
|         } else { | ||||
|             // Look it up if we don't have it. | ||||
|             self.ids_of_async_commands() | ||||
|                 .read() | ||||
|                 .await | ||||
|                 .get(&id) | ||||
|                 .cloned() | ||||
|                 .unwrap_or_default() | ||||
|         }; | ||||
|  | ||||
|         let current_time = instant::Instant::now(); | ||||
|         while current_time.elapsed().as_secs() < 60 { | ||||
|             let responses = self.responses().read().await.clone(); | ||||
|             let Some(resp) = responses.get(&id) else { | ||||
|                 // Sleep for a little so we don't hog the CPU. | ||||
|                 // No seriously WE DO NOT WANT TO PAUSE THE WHOLE APP ON THE JS SIDE. | ||||
|                 let duration = instant::Duration::from_millis(100); | ||||
|                 #[cfg(target_arch = "wasm32")] | ||||
|                 wasm_timer::Delay::new(duration).await.map_err(|err| { | ||||
|                     KclError::Internal(KclErrorDetails { | ||||
|                         message: format!("Failed to sleep: {:?}", err), | ||||
|                         source_ranges: vec![source_range], | ||||
|                     }) | ||||
|                 })?; | ||||
|                 #[cfg(not(target_arch = "wasm32"))] | ||||
|                 tokio::time::sleep(duration).await; | ||||
|                 continue; | ||||
|             }; | ||||
|  | ||||
|             // If the response is an error, return it. | ||||
|             // Parsing will do that and we can ignore the result, we don't care. | ||||
|             let response = self.parse_websocket_response(resp.clone(), source_range)?; | ||||
|             return Ok(response); | ||||
|         } | ||||
|  | ||||
|         Err(KclError::Engine(KclErrorDetails { | ||||
|             message: "async command timed out".to_string(), | ||||
|             source_ranges: vec![source_range], | ||||
|         })) | ||||
|     } | ||||
|  | ||||
|     /// Ensure ALL async commands have been completed. | ||||
|     async fn ensure_async_commands_completed(&self) -> Result<(), KclError> { | ||||
|         // Check if all async commands have been completed. | ||||
|         let ids = self.take_ids_of_async_commands().await; | ||||
|  | ||||
|         // Try to get them from the responses. | ||||
|         for (id, source_range) in ids { | ||||
|             self.ensure_async_command_completed(id, Some(source_range)).await?; | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Set the visibility of edges. | ||||
|     async fn set_edge_visibility( | ||||
|         &self, | ||||
| @ -342,6 +422,36 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static { | ||||
|         self.run_batch(requests, source_range).await | ||||
|     } | ||||
|  | ||||
|     /// Send the modeling cmd async and don't wait for the response. | ||||
|     /// Add it to our list of async commands. | ||||
|     async fn async_modeling_cmd( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
|         source_range: SourceRange, | ||||
|         cmd: &ModelingCmd, | ||||
|     ) -> Result<(), crate::errors::KclError> { | ||||
|         // Add the command ID to the list of async commands. | ||||
|         self.ids_of_async_commands().write().await.insert(id, source_range); | ||||
|  | ||||
|         // Add to artifact commands. | ||||
|         self.handle_artifact_command(cmd, id.into(), &HashMap::from([(id, source_range)])) | ||||
|             .await?; | ||||
|  | ||||
|         // Fire off the command now, but don't wait for the response, we don't care about it. | ||||
|         self.inner_fire_modeling_cmd( | ||||
|             id, | ||||
|             source_range, | ||||
|             WebSocketRequest::ModelingCmdReq(ModelingCmdReq { | ||||
|                 cmd: cmd.clone(), | ||||
|                 cmd_id: id.into(), | ||||
|             }), | ||||
|             HashMap::from([(id, source_range)]), | ||||
|         ) | ||||
|         .await?; | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Run the batch for the specific commands. | ||||
|     async fn run_batch( | ||||
|         &self, | ||||
|  | ||||
| @ -15,6 +15,8 @@ use crate::{ | ||||
|     std::{args::TyF64, sketch::PlaneData}, | ||||
| }; | ||||
|  | ||||
| use super::ExecutorContext; | ||||
|  | ||||
| type Point2D = kcmc::shared::Point2d<f64>; | ||||
| type Point3D = kcmc::shared::Point3d<f64>; | ||||
|  | ||||
| @ -76,9 +78,45 @@ pub struct ImportedGeometry { | ||||
|     pub value: Vec<String>, | ||||
|     #[serde(skip)] | ||||
|     pub meta: Vec<Metadata>, | ||||
|     /// If the imported geometry has completed. | ||||
|     #[serde(skip)] | ||||
|     completed: bool, | ||||
| } | ||||
|  | ||||
| /// Data for a solid or an imported geometry. | ||||
| impl ImportedGeometry { | ||||
|     pub fn new(id: uuid::Uuid, value: Vec<String>, meta: Vec<Metadata>) -> Self { | ||||
|         Self { | ||||
|             id, | ||||
|             value, | ||||
|             meta, | ||||
|             completed: false, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async fn wait_for_finish(&mut self, ctx: &ExecutorContext) -> Result<(), KclError> { | ||||
|         if self.completed { | ||||
|             return Ok(()); | ||||
|         } | ||||
|  | ||||
|         ctx.engine | ||||
|             .ensure_async_command_completed(self.id, self.meta.first().map(|m| m.source_range)) | ||||
|             .await?; | ||||
|  | ||||
|         self.completed = true; | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub async fn id(&mut self, ctx: &ExecutorContext) -> Result<uuid::Uuid, KclError> { | ||||
|         if !self.completed { | ||||
|             self.wait_for_finish(ctx).await?; | ||||
|         } | ||||
|  | ||||
|         Ok(self.id) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Data for a solid, sketch, or an imported geometry. | ||||
| #[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[ts(export)] | ||||
| #[serde(tag = "type", rename_all = "camelCase")] | ||||
| @ -128,11 +166,61 @@ impl From<SolidOrSketchOrImportedGeometry> for crate::execution::KclValue { | ||||
| } | ||||
|  | ||||
| impl SolidOrSketchOrImportedGeometry { | ||||
|     pub(crate) fn ids(&self) -> Vec<uuid::Uuid> { | ||||
|     pub(crate) async fn ids(&mut self, ctx: &ExecutorContext) -> Result<Vec<uuid::Uuid>, KclError> { | ||||
|         match self { | ||||
|             SolidOrSketchOrImportedGeometry::ImportedGeometry(s) => vec![s.id], | ||||
|             SolidOrSketchOrImportedGeometry::SolidSet(s) => s.iter().map(|s| s.id).collect(), | ||||
|             SolidOrSketchOrImportedGeometry::SketchSet(s) => s.iter().map(|s| s.id).collect(), | ||||
|             SolidOrSketchOrImportedGeometry::ImportedGeometry(s) => { | ||||
|                 let id = s.id(ctx).await?; | ||||
|  | ||||
|                 Ok(vec![id]) | ||||
|             } | ||||
|             SolidOrSketchOrImportedGeometry::SolidSet(s) => Ok(s.iter().map(|s| s.id).collect()), | ||||
|             SolidOrSketchOrImportedGeometry::SketchSet(s) => Ok(s.iter().map(|s| s.id).collect()), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Data for a solid or an imported geometry. | ||||
| #[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[ts(export)] | ||||
| #[serde(tag = "type", rename_all = "camelCase")] | ||||
| #[allow(clippy::vec_box)] | ||||
| pub enum SolidOrImportedGeometry { | ||||
|     ImportedGeometry(Box<ImportedGeometry>), | ||||
|     SolidSet(Vec<Solid>), | ||||
| } | ||||
|  | ||||
| impl From<SolidOrImportedGeometry> for crate::execution::KclValue { | ||||
|     fn from(value: SolidOrImportedGeometry) -> Self { | ||||
|         match value { | ||||
|             SolidOrImportedGeometry::ImportedGeometry(s) => crate::execution::KclValue::ImportedGeometry(*s), | ||||
|             SolidOrImportedGeometry::SolidSet(mut s) => { | ||||
|                 if s.len() == 1 { | ||||
|                     crate::execution::KclValue::Solid { | ||||
|                         value: Box::new(s.pop().unwrap()), | ||||
|                     } | ||||
|                 } else { | ||||
|                     crate::execution::KclValue::HomArray { | ||||
|                         value: s | ||||
|                             .into_iter() | ||||
|                             .map(|s| crate::execution::KclValue::Solid { value: Box::new(s) }) | ||||
|                             .collect(), | ||||
|                         ty: crate::execution::types::RuntimeType::solid(), | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl SolidOrImportedGeometry { | ||||
|     pub(crate) async fn ids(&mut self, ctx: &ExecutorContext) -> Result<Vec<uuid::Uuid>, KclError> { | ||||
|         match self { | ||||
|             SolidOrImportedGeometry::ImportedGeometry(s) => { | ||||
|                 let id = s.id(ctx).await?; | ||||
|  | ||||
|                 Ok(vec![id]) | ||||
|             } | ||||
|             SolidOrImportedGeometry::SolidSet(s) => Ok(s.iter().map(|s| s.id).collect()), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -5,10 +5,8 @@ use kcmc::{ | ||||
|     coord::{System, KITTYCAD}, | ||||
|     each_cmd as mcmd, | ||||
|     format::InputFormat3d, | ||||
|     ok_response::OkModelingCmdResponse, | ||||
|     shared::FileImportFormat, | ||||
|     units::UnitLength, | ||||
|     websocket::OkWebSocketResponseData, | ||||
|     ImportFile, ModelingCmd, | ||||
| }; | ||||
| use kittycad_modeling_cmds as kcmc; | ||||
| @ -289,34 +287,17 @@ pub struct PreImportedGeometry { | ||||
| } | ||||
|  | ||||
| pub async fn send_to_engine(pre: PreImportedGeometry, ctxt: &ExecutorContext) -> Result<ImportedGeometry, KclError> { | ||||
|     if ctxt.no_engine_commands().await { | ||||
|         return Ok(ImportedGeometry { | ||||
|             id: pre.id, | ||||
|             value: pre.command.files.iter().map(|f| f.path.to_string()).collect(), | ||||
|             meta: vec![pre.source_range.into()], | ||||
|         }); | ||||
|     } | ||||
|     let imported_geometry = ImportedGeometry::new( | ||||
|         pre.id, | ||||
|         pre.command.files.iter().map(|f| f.path.to_string()).collect(), | ||||
|         vec![pre.source_range.into()], | ||||
|     ); | ||||
|  | ||||
|     let resp = ctxt | ||||
|         .engine | ||||
|         .send_modeling_cmd(pre.id, pre.source_range, &ModelingCmd::from(pre.command.clone())) | ||||
|     ctxt.engine | ||||
|         .async_modeling_cmd(pre.id, pre.source_range, &ModelingCmd::from(pre.command.clone())) | ||||
|         .await?; | ||||
|  | ||||
|     let OkWebSocketResponseData::Modeling { | ||||
|         modeling_response: OkModelingCmdResponse::ImportFiles(imported_files), | ||||
|     } = &resp | ||||
|     else { | ||||
|         return Err(KclError::Engine(KclErrorDetails { | ||||
|             message: format!("ImportFiles response was not as expected: {:?}", resp), | ||||
|             source_ranges: vec![pre.source_range], | ||||
|         })); | ||||
|     }; | ||||
|  | ||||
|     Ok(ImportedGeometry { | ||||
|         id: imported_files.object_id, | ||||
|         value: pre.command.files.iter().map(|f| f.path.to_string()).collect(), | ||||
|         meta: vec![pre.source_range.into()], | ||||
|     }) | ||||
|     Ok(imported_geometry) | ||||
| } | ||||
|  | ||||
| /// Get the source format from the extension. | ||||
|  | ||||
| @ -947,7 +947,7 @@ impl ExecutorContext { | ||||
|                 exec_state.global.artifact_graph.clone(), | ||||
|                 module_id_to_module_path, | ||||
|                 exec_state.global.id_to_source.clone(), | ||||
|                 default_planes, | ||||
|                 default_planes.clone(), | ||||
|             ) | ||||
|         })?; | ||||
|  | ||||
| @ -957,6 +957,7 @@ impl ExecutorContext { | ||||
|             cache::write_old_memory((mem, exec_state.global.module_infos.clone())).await; | ||||
|         } | ||||
|         let session_data = self.engine.get_session_data().await; | ||||
|  | ||||
|         Ok((env_ref, session_data)) | ||||
|     } | ||||
|  | ||||
| @ -984,6 +985,9 @@ impl ExecutorContext { | ||||
|             ) | ||||
|             .await; | ||||
|  | ||||
|         // Ensure all the async commands completed. | ||||
|         self.engine.ensure_async_commands_completed().await?; | ||||
|  | ||||
|         // If we errored out and early-returned, there might be commands which haven't been executed | ||||
|         // and should be dropped. | ||||
|         self.engine.clear_queues().await; | ||||
|  | ||||
| @ -1338,11 +1338,11 @@ mod test { | ||||
|                 value: Box::new(Plane::from_plane_data(crate::std::sketch::PlaneData::XY, exec_state)), | ||||
|             }, | ||||
|             // No easy way to make a Face, Sketch, Solid, or Helix | ||||
|             KclValue::ImportedGeometry(crate::execution::ImportedGeometry { | ||||
|                 id: uuid::Uuid::nil(), | ||||
|                 value: Vec::new(), | ||||
|                 meta: Vec::new(), | ||||
|             }), | ||||
|             KclValue::ImportedGeometry(crate::execution::ImportedGeometry::new( | ||||
|                 uuid::Uuid::nil(), | ||||
|                 Vec::new(), | ||||
|                 Vec::new(), | ||||
|             )), | ||||
|             // Other values don't have types | ||||
|         ] | ||||
|     } | ||||
|  | ||||
| @ -109,7 +109,7 @@ pub mod exec { | ||||
| pub mod wasm_engine { | ||||
|     pub use crate::{ | ||||
|         coredump::wasm::{CoreDumpManager, CoreDumper}, | ||||
|         engine::conn_wasm::{EngineCommandManager, EngineConnection}, | ||||
|         engine::conn_wasm::{EngineCommandManager, EngineConnection, ResponseContext}, | ||||
|         fs::wasm::{FileManager, FileSystemManager}, | ||||
|     }; | ||||
| } | ||||
|  | ||||
| @ -2579,3 +2579,24 @@ mod tangent_to_3_point_arc { | ||||
|         super::execute(TEST_NAME, true).await | ||||
|     } | ||||
| } | ||||
| mod import_async { | ||||
|     const TEST_NAME: &str = "import_async"; | ||||
|  | ||||
|     /// 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")] | ||||
|     async fn kcl_test_execute() { | ||||
|         super::execute(TEST_NAME, true).await | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -13,7 +13,7 @@ use crate::{ | ||||
|     errors::{KclError, KclErrorDetails}, | ||||
|     execution::{ | ||||
|         types::{NumericType, PrimitiveType, RuntimeType}, | ||||
|         ExecState, KclValue, Solid, | ||||
|         ExecState, KclValue, SolidOrImportedGeometry, | ||||
|     }, | ||||
|     std::Args, | ||||
| }; | ||||
| @ -43,7 +43,11 @@ struct AppearanceData { | ||||
|  | ||||
| /// Set the appearance of a solid. This only works on solids, not sketches or individual paths. | ||||
| pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { | ||||
|     let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?; | ||||
|     let solids = args.get_unlabeled_kw_arg_typed( | ||||
|         "solids", | ||||
|         &RuntimeType::Union(vec![RuntimeType::solids(), RuntimeType::imported()]), | ||||
|         exec_state, | ||||
|     )?; | ||||
|  | ||||
|     let color: String = args.get_kw_arg("color")?; | ||||
|     let count_ty = RuntimeType::Primitive(PrimitiveType::Number(NumericType::count())); | ||||
| @ -270,6 +274,19 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal | ||||
| ///         roughness = 50 | ||||
| ///     ) | ||||
| /// ``` | ||||
| /// | ||||
| /// ```no_run | ||||
| /// // Change the appearance of an imported model. | ||||
| /// | ||||
| /// import "tests/inputs/cube.sldprt" as cube | ||||
| /// | ||||
| /// cube | ||||
| /// //    |> appearance( | ||||
| /// //        color = "#ff0000", | ||||
| /// //        metalness = 50, | ||||
| /// //        roughness = 50 | ||||
| /// //    ) | ||||
| /// ``` | ||||
| #[stdlib { | ||||
|     name = "appearance", | ||||
|     keywords = true, | ||||
| @ -282,14 +299,16 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal | ||||
|     } | ||||
| }] | ||||
| async fn inner_appearance( | ||||
|     solids: Vec<Solid>, | ||||
|     solids: SolidOrImportedGeometry, | ||||
|     color: String, | ||||
|     metalness: Option<f64>, | ||||
|     roughness: Option<f64>, | ||||
|     exec_state: &mut ExecState, | ||||
|     args: Args, | ||||
| ) -> Result<Vec<Solid>, KclError> { | ||||
|     for solid in &solids { | ||||
| ) -> Result<SolidOrImportedGeometry, KclError> { | ||||
|     let mut solids = solids.clone(); | ||||
|  | ||||
|     for solid_id in solids.ids(&args.ctx).await? { | ||||
|         // Set the material properties. | ||||
|         let rgb = rgba_simple::RGB::<f32>::from_hex(&color).map_err(|err| { | ||||
|             KclError::Semantic(KclErrorDetails { | ||||
| @ -308,7 +327,7 @@ async fn inner_appearance( | ||||
|         args.batch_modeling_cmd( | ||||
|             exec_state.next_uuid(), | ||||
|             ModelingCmd::from(mcmd::ObjectSetMaterialParamsPbr { | ||||
|                 object_id: solid.id, | ||||
|                 object_id: solid_id, | ||||
|                 color, | ||||
|                 metalness: metalness.unwrap_or_default() as f32 / 100.0, | ||||
|                 roughness: roughness.unwrap_or_default() as f32 / 100.0, | ||||
|  | ||||
| @ -28,6 +28,9 @@ use crate::{ | ||||
|     ModuleId, | ||||
| }; | ||||
|  | ||||
| const ERROR_STRING_SKETCH_TO_SOLID_HELPER: &str = | ||||
|     "You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`"; | ||||
|  | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Arg { | ||||
|     /// The evaluated argument. | ||||
| @ -220,18 +223,19 @@ impl Args { | ||||
|                 ty.human_friendly_type(), | ||||
|             ); | ||||
|             let suggestion = match (ty, actual_type_name) { | ||||
|                 (RuntimeType::Primitive(PrimitiveType::Solid), "Sketch") => Some( | ||||
|                     "You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`", | ||||
|                 ), | ||||
|                 (RuntimeType::Array(t, _), "Sketch") if **t == RuntimeType::Primitive(PrimitiveType::Solid) => Some( | ||||
|                     "You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`", | ||||
|                 ), | ||||
|                 (RuntimeType::Primitive(PrimitiveType::Solid), "Sketch") => Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER), | ||||
|                 (RuntimeType::Array(t, _), "Sketch") if **t == RuntimeType::Primitive(PrimitiveType::Solid) => { | ||||
|                     Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER) | ||||
|                 } | ||||
|                 _ => None, | ||||
|             }; | ||||
|             let message = match suggestion { | ||||
|             let mut message = match suggestion { | ||||
|                 None => msg_base, | ||||
|                 Some(sugg) => format!("{msg_base}. {sugg}"), | ||||
|             }; | ||||
|             if message.contains("one or more Solids or imported geometry but it's actually of type Sketch") { | ||||
|                 message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}"); | ||||
|             } | ||||
|             KclError::Semantic(KclErrorDetails { | ||||
|                 source_ranges: arg.source_ranges(), | ||||
|                 message, | ||||
| @ -343,18 +347,20 @@ impl Args { | ||||
|                 ty.human_friendly_type(), | ||||
|             ); | ||||
|             let suggestion = match (ty, actual_type_name) { | ||||
|                 (RuntimeType::Primitive(PrimitiveType::Solid), "Sketch") => Some( | ||||
|                     "You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`", | ||||
|                 ), | ||||
|                 (RuntimeType::Array(ty, _), "Sketch") if **ty == RuntimeType::Primitive(PrimitiveType::Solid) => Some( | ||||
|                     "You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`", | ||||
|                 ), | ||||
|                 (RuntimeType::Primitive(PrimitiveType::Solid), "Sketch") => Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER), | ||||
|                 (RuntimeType::Array(ty, _), "Sketch") if **ty == RuntimeType::Primitive(PrimitiveType::Solid) => { | ||||
|                     Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER) | ||||
|                 } | ||||
|                 _ => None, | ||||
|             }; | ||||
|             let message = match suggestion { | ||||
|             let mut message = match suggestion { | ||||
|                 None => msg_base, | ||||
|                 Some(sugg) => format!("{msg_base}. {sugg}"), | ||||
|             }; | ||||
|  | ||||
|             if message.contains("one or more Solids or imported geometry but it's actually of type Sketch") { | ||||
|                 message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}"); | ||||
|             } | ||||
|             KclError::Semantic(KclErrorDetails { | ||||
|                 source_ranges: arg.source_ranges(), | ||||
|                 message, | ||||
| @ -1396,6 +1402,26 @@ impl<'a> FromKclValue<'a> for crate::execution::SolidOrSketchOrImportedGeometry | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> FromKclValue<'a> for crate::execution::SolidOrImportedGeometry { | ||||
|     fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { | ||||
|         match arg { | ||||
|             KclValue::Solid { value } => Some(Self::SolidSet(vec![(**value).clone()])), | ||||
|             KclValue::HomArray { value, .. } => { | ||||
|                 let mut solids = vec![]; | ||||
|                 for item in value { | ||||
|                     match item { | ||||
|                         KclValue::Solid { value } => solids.push((**value).clone()), | ||||
|                         _ => return None, | ||||
|                     } | ||||
|                 } | ||||
|                 Some(Self::SolidSet(solids)) | ||||
|             } | ||||
|             KclValue::ImportedGeometry(value) => Some(Self::ImportedGeometry(Box::new(value.clone()))), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> FromKclValue<'a> for super::sketch::SketchData { | ||||
|     fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { | ||||
|         // Order is critical since PlaneData is a subset of Plane. | ||||
|  | ||||
| @ -171,7 +171,8 @@ async fn inner_scale( | ||||
|         args.flush_batch_for_solids(exec_state, solids).await?; | ||||
|     } | ||||
|  | ||||
|     for object_id in objects.ids() { | ||||
|     let mut objects = objects.clone(); | ||||
|     for object_id in objects.ids(&args.ctx).await? { | ||||
|         let id = exec_state.next_uuid(); | ||||
|  | ||||
|         args.batch_modeling_cmd( | ||||
| @ -409,7 +410,8 @@ async fn inner_translate( | ||||
|         args.flush_batch_for_solids(exec_state, solids).await?; | ||||
|     } | ||||
|  | ||||
|     for object_id in objects.ids() { | ||||
|     let mut objects = objects.clone(); | ||||
|     for object_id in objects.ids(&args.ctx).await? { | ||||
|         let id = exec_state.next_uuid(); | ||||
|  | ||||
|         args.batch_modeling_cmd( | ||||
| @ -774,7 +776,8 @@ async fn inner_rotate( | ||||
|         args.flush_batch_for_solids(exec_state, solids).await?; | ||||
|     } | ||||
|  | ||||
|     for object_id in objects.ids() { | ||||
|     let mut objects = objects.clone(); | ||||
|     for object_id in objects.ids(&args.ctx).await? { | ||||
|         let id = exec_state.next_uuid(); | ||||
|  | ||||
|         if let (Some(axis), Some(angle)) = (axis, angle) { | ||||
|  | ||||
							
								
								
									
										5575229
									
								
								rust/kcl-lib/tests/import_async/artifact_commands.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5575229
									
								
								rust/kcl-lib/tests/import_async/artifact_commands.snap
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -0,0 +1,6 @@ | ||||
| --- | ||||
| source: kcl-lib/src/simulation_tests.rs | ||||
| description: Artifact graph flowchart import_async.kcl | ||||
| extension: md | ||||
| snapshot_kind: binary | ||||
| --- | ||||
							
								
								
									
										503
									
								
								rust/kcl-lib/tests/import_async/artifact_graph_flowchart.snap.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										503
									
								
								rust/kcl-lib/tests/import_async/artifact_graph_flowchart.snap.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,503 @@ | ||||
| ```mermaid | ||||
| flowchart LR | ||||
|   subgraph path3 [Path] | ||||
|     3["Path<br>[1035, 1085, 0]"] | ||||
|     4["Segment<br>[1035, 1085, 0]"] | ||||
|     5[Solid2d] | ||||
|   end | ||||
|   subgraph path13 [Path] | ||||
|     13["Path<br>[1562, 1599, 0]"] | ||||
|     14["Segment<br>[1250, 1288, 0]"] | ||||
|     15["Segment<br>[1250, 1288, 0]"] | ||||
|     16["Segment<br>[1250, 1288, 0]"] | ||||
|     17["Segment<br>[1250, 1288, 0]"] | ||||
|     18["Segment<br>[1250, 1288, 0]"] | ||||
|     19["Segment<br>[1250, 1288, 0]"] | ||||
|     20["Segment<br>[1250, 1288, 0]"] | ||||
|     21["Segment<br>[1250, 1288, 0]"] | ||||
|     22["Segment<br>[1250, 1288, 0]"] | ||||
|     23["Segment<br>[1250, 1288, 0]"] | ||||
|     24["Segment<br>[1250, 1288, 0]"] | ||||
|     25["Segment<br>[1250, 1288, 0]"] | ||||
|     26["Segment<br>[1250, 1288, 0]"] | ||||
|     27["Segment<br>[1250, 1288, 0]"] | ||||
|     28["Segment<br>[1250, 1288, 0]"] | ||||
|     29["Segment<br>[1250, 1288, 0]"] | ||||
|     30["Segment<br>[1250, 1288, 0]"] | ||||
|     31["Segment<br>[1250, 1288, 0]"] | ||||
|     32["Segment<br>[1250, 1288, 0]"] | ||||
|     33["Segment<br>[1250, 1288, 0]"] | ||||
|     34["Segment<br>[1250, 1288, 0]"] | ||||
|     35["Segment<br>[1250, 1288, 0]"] | ||||
|     36["Segment<br>[1250, 1288, 0]"] | ||||
|     37["Segment<br>[1250, 1288, 0]"] | ||||
|     38["Segment<br>[1250, 1288, 0]"] | ||||
|     39["Segment<br>[1250, 1288, 0]"] | ||||
|     40["Segment<br>[1250, 1288, 0]"] | ||||
|     41["Segment<br>[1250, 1288, 0]"] | ||||
|     42["Segment<br>[1250, 1288, 0]"] | ||||
|     43["Segment<br>[1250, 1288, 0]"] | ||||
|     44["Segment<br>[1250, 1288, 0]"] | ||||
|     45["Segment<br>[1250, 1288, 0]"] | ||||
|     46["Segment<br>[1250, 1288, 0]"] | ||||
|     47["Segment<br>[1250, 1288, 0]"] | ||||
|     48["Segment<br>[1250, 1288, 0]"] | ||||
|     49["Segment<br>[1250, 1288, 0]"] | ||||
|     50["Segment<br>[1250, 1288, 0]"] | ||||
|     51["Segment<br>[1250, 1288, 0]"] | ||||
|     52["Segment<br>[1250, 1288, 0]"] | ||||
|     53["Segment<br>[1250, 1288, 0]"] | ||||
|     54["Segment<br>[1250, 1288, 0]"] | ||||
|     55["Segment<br>[1250, 1288, 0]"] | ||||
|     56["Segment<br>[1250, 1288, 0]"] | ||||
|     57["Segment<br>[1250, 1288, 0]"] | ||||
|     58["Segment<br>[1250, 1288, 0]"] | ||||
|     59["Segment<br>[1250, 1288, 0]"] | ||||
|     60["Segment<br>[1250, 1288, 0]"] | ||||
|     61["Segment<br>[1250, 1288, 0]"] | ||||
|     62["Segment<br>[1250, 1288, 0]"] | ||||
|     63["Segment<br>[1250, 1288, 0]"] | ||||
|     64["Segment<br>[1250, 1288, 0]"] | ||||
|     65["Segment<br>[1250, 1288, 0]"] | ||||
|     66["Segment<br>[1250, 1288, 0]"] | ||||
|     67["Segment<br>[1250, 1288, 0]"] | ||||
|     68["Segment<br>[1250, 1288, 0]"] | ||||
|     69["Segment<br>[1250, 1288, 0]"] | ||||
|     70["Segment<br>[1250, 1288, 0]"] | ||||
|     71["Segment<br>[1250, 1288, 0]"] | ||||
|     72["Segment<br>[1250, 1288, 0]"] | ||||
|     73["Segment<br>[1250, 1288, 0]"] | ||||
|     74["Segment<br>[1250, 1288, 0]"] | ||||
|     75["Segment<br>[1250, 1288, 0]"] | ||||
|     76["Segment<br>[1250, 1288, 0]"] | ||||
|     77["Segment<br>[1250, 1288, 0]"] | ||||
|     78["Segment<br>[1250, 1288, 0]"] | ||||
|     79["Segment<br>[1250, 1288, 0]"] | ||||
|     80["Segment<br>[1250, 1288, 0]"] | ||||
|     81["Segment<br>[1250, 1288, 0]"] | ||||
|     82["Segment<br>[1250, 1288, 0]"] | ||||
|     83["Segment<br>[1250, 1288, 0]"] | ||||
|     84["Segment<br>[1250, 1288, 0]"] | ||||
|     85["Segment<br>[1250, 1288, 0]"] | ||||
|     86["Segment<br>[1250, 1288, 0]"] | ||||
|     87["Segment<br>[1250, 1288, 0]"] | ||||
|     88["Segment<br>[1250, 1288, 0]"] | ||||
|     89["Segment<br>[1250, 1288, 0]"] | ||||
|     90["Segment<br>[1250, 1288, 0]"] | ||||
|     91["Segment<br>[1250, 1288, 0]"] | ||||
|     92["Segment<br>[1250, 1288, 0]"] | ||||
|     93["Segment<br>[1250, 1288, 0]"] | ||||
|     94["Segment<br>[1250, 1288, 0]"] | ||||
|     95["Segment<br>[1250, 1288, 0]"] | ||||
|     96["Segment<br>[1250, 1288, 0]"] | ||||
|     97["Segment<br>[1250, 1288, 0]"] | ||||
|     98["Segment<br>[1250, 1288, 0]"] | ||||
|     99["Segment<br>[1250, 1288, 0]"] | ||||
|     100["Segment<br>[1250, 1288, 0]"] | ||||
|     101["Segment<br>[1250, 1288, 0]"] | ||||
|     102["Segment<br>[1250, 1288, 0]"] | ||||
|     103["Segment<br>[1250, 1288, 0]"] | ||||
|     104["Segment<br>[1250, 1288, 0]"] | ||||
|     105["Segment<br>[1250, 1288, 0]"] | ||||
|     106["Segment<br>[1250, 1288, 0]"] | ||||
|     107["Segment<br>[1250, 1288, 0]"] | ||||
|     108["Segment<br>[1250, 1288, 0]"] | ||||
|     109["Segment<br>[1250, 1288, 0]"] | ||||
|     110["Segment<br>[1250, 1288, 0]"] | ||||
|     111["Segment<br>[1250, 1288, 0]"] | ||||
|     112["Segment<br>[1250, 1288, 0]"] | ||||
|     113["Segment<br>[1250, 1288, 0]"] | ||||
|     114["Segment<br>[1250, 1288, 0]"] | ||||
|     115["Segment<br>[1651, 1753, 0]"] | ||||
|     116["Segment<br>[1478, 1508, 0]"] | ||||
|     117["Segment<br>[1478, 1508, 0]"] | ||||
|     118["Segment<br>[1478, 1508, 0]"] | ||||
|     119["Segment<br>[1478, 1508, 0]"] | ||||
|     120["Segment<br>[1478, 1508, 0]"] | ||||
|     121["Segment<br>[1478, 1508, 0]"] | ||||
|     122["Segment<br>[1478, 1508, 0]"] | ||||
|     123["Segment<br>[1478, 1508, 0]"] | ||||
|     124["Segment<br>[1478, 1508, 0]"] | ||||
|     125["Segment<br>[1478, 1508, 0]"] | ||||
|     126["Segment<br>[1478, 1508, 0]"] | ||||
|     127["Segment<br>[1478, 1508, 0]"] | ||||
|     128["Segment<br>[1478, 1508, 0]"] | ||||
|     129["Segment<br>[1478, 1508, 0]"] | ||||
|     130["Segment<br>[1478, 1508, 0]"] | ||||
|     131["Segment<br>[1478, 1508, 0]"] | ||||
|     132["Segment<br>[1478, 1508, 0]"] | ||||
|     133["Segment<br>[1478, 1508, 0]"] | ||||
|     134["Segment<br>[1478, 1508, 0]"] | ||||
|     135["Segment<br>[1478, 1508, 0]"] | ||||
|     136["Segment<br>[1478, 1508, 0]"] | ||||
|     137["Segment<br>[1478, 1508, 0]"] | ||||
|     138["Segment<br>[1478, 1508, 0]"] | ||||
|     139["Segment<br>[1478, 1508, 0]"] | ||||
|     140["Segment<br>[1478, 1508, 0]"] | ||||
|     141["Segment<br>[1478, 1508, 0]"] | ||||
|     142["Segment<br>[1478, 1508, 0]"] | ||||
|     143["Segment<br>[1478, 1508, 0]"] | ||||
|     144["Segment<br>[1478, 1508, 0]"] | ||||
|     145["Segment<br>[1478, 1508, 0]"] | ||||
|     146["Segment<br>[1478, 1508, 0]"] | ||||
|     147["Segment<br>[1478, 1508, 0]"] | ||||
|     148["Segment<br>[1478, 1508, 0]"] | ||||
|     149["Segment<br>[1478, 1508, 0]"] | ||||
|     150["Segment<br>[1478, 1508, 0]"] | ||||
|     151["Segment<br>[1478, 1508, 0]"] | ||||
|     152["Segment<br>[1478, 1508, 0]"] | ||||
|     153["Segment<br>[1478, 1508, 0]"] | ||||
|     154["Segment<br>[1478, 1508, 0]"] | ||||
|     155["Segment<br>[1478, 1508, 0]"] | ||||
|     156["Segment<br>[1478, 1508, 0]"] | ||||
|     157["Segment<br>[1478, 1508, 0]"] | ||||
|     158["Segment<br>[1478, 1508, 0]"] | ||||
|     159["Segment<br>[1478, 1508, 0]"] | ||||
|     160["Segment<br>[1478, 1508, 0]"] | ||||
|     161["Segment<br>[1478, 1508, 0]"] | ||||
|     162["Segment<br>[1478, 1508, 0]"] | ||||
|     163["Segment<br>[1478, 1508, 0]"] | ||||
|     164["Segment<br>[1478, 1508, 0]"] | ||||
|     165["Segment<br>[1478, 1508, 0]"] | ||||
|     166["Segment<br>[1478, 1508, 0]"] | ||||
|     167["Segment<br>[1478, 1508, 0]"] | ||||
|     168["Segment<br>[1478, 1508, 0]"] | ||||
|     169["Segment<br>[1478, 1508, 0]"] | ||||
|     170["Segment<br>[1478, 1508, 0]"] | ||||
|     171["Segment<br>[1478, 1508, 0]"] | ||||
|     172["Segment<br>[1478, 1508, 0]"] | ||||
|     173["Segment<br>[1478, 1508, 0]"] | ||||
|     174["Segment<br>[1478, 1508, 0]"] | ||||
|     175["Segment<br>[1478, 1508, 0]"] | ||||
|     176["Segment<br>[1478, 1508, 0]"] | ||||
|     177["Segment<br>[1478, 1508, 0]"] | ||||
|     178["Segment<br>[1478, 1508, 0]"] | ||||
|     179["Segment<br>[1478, 1508, 0]"] | ||||
|     180["Segment<br>[1478, 1508, 0]"] | ||||
|     181["Segment<br>[1478, 1508, 0]"] | ||||
|     182["Segment<br>[1478, 1508, 0]"] | ||||
|     183["Segment<br>[1478, 1508, 0]"] | ||||
|     184["Segment<br>[1478, 1508, 0]"] | ||||
|     185["Segment<br>[1478, 1508, 0]"] | ||||
|     186["Segment<br>[1478, 1508, 0]"] | ||||
|     187["Segment<br>[1478, 1508, 0]"] | ||||
|     188["Segment<br>[1478, 1508, 0]"] | ||||
|     189["Segment<br>[1478, 1508, 0]"] | ||||
|     190["Segment<br>[1478, 1508, 0]"] | ||||
|     191["Segment<br>[1478, 1508, 0]"] | ||||
|     192["Segment<br>[1478, 1508, 0]"] | ||||
|     193["Segment<br>[1478, 1508, 0]"] | ||||
|     194["Segment<br>[1478, 1508, 0]"] | ||||
|     195["Segment<br>[1478, 1508, 0]"] | ||||
|     196["Segment<br>[1478, 1508, 0]"] | ||||
|     197["Segment<br>[1478, 1508, 0]"] | ||||
|     198["Segment<br>[1478, 1508, 0]"] | ||||
|     199["Segment<br>[1478, 1508, 0]"] | ||||
|     200["Segment<br>[1478, 1508, 0]"] | ||||
|     201["Segment<br>[1478, 1508, 0]"] | ||||
|     202["Segment<br>[1478, 1508, 0]"] | ||||
|     203["Segment<br>[1478, 1508, 0]"] | ||||
|     204["Segment<br>[1478, 1508, 0]"] | ||||
|     205["Segment<br>[1478, 1508, 0]"] | ||||
|     206["Segment<br>[1478, 1508, 0]"] | ||||
|     207["Segment<br>[1478, 1508, 0]"] | ||||
|     208["Segment<br>[1478, 1508, 0]"] | ||||
|     209["Segment<br>[1478, 1508, 0]"] | ||||
|     210["Segment<br>[1478, 1508, 0]"] | ||||
|     211["Segment<br>[1478, 1508, 0]"] | ||||
|     212["Segment<br>[1478, 1508, 0]"] | ||||
|     213["Segment<br>[1478, 1508, 0]"] | ||||
|     214["Segment<br>[1478, 1508, 0]"] | ||||
|     215["Segment<br>[1478, 1508, 0]"] | ||||
|     216["Segment<br>[1478, 1508, 0]"] | ||||
|     217["Segment<br>[1799, 1806, 0]"] | ||||
|     218[Solid2d] | ||||
|   end | ||||
|   subgraph path220 [Path] | ||||
|     220["Path<br>[2287, 2387, 0]"] | ||||
|     221["Segment<br>[2393, 2420, 0]"] | ||||
|     222["Segment<br>[2426, 2454, 0]"] | ||||
|     223["Segment<br>[2460, 2488, 0]"] | ||||
|     224["Segment<br>[2494, 2614, 0]"] | ||||
|     225["Segment<br>[2620, 2729, 0]"] | ||||
|     226["Segment<br>[2735, 2742, 0]"] | ||||
|     227[Solid2d] | ||||
|   end | ||||
|   1["Plane<br>[168, 185, 0]"] | ||||
|   2["Plane<br>[1012, 1029, 0]"] | ||||
|   6["Sweep Extrusion<br>[1091, 1119, 0]"] | ||||
|   7[Wall] | ||||
|   8["Cap Start"] | ||||
|   9["Cap End"] | ||||
|   10["SweepEdge Opposite"] | ||||
|   11["SweepEdge Adjacent"] | ||||
|   12["Plane<br>[1539, 1556, 0]"] | ||||
|   219["Sweep Extrusion<br>[1812, 1840, 0]"] | ||||
|   228["Sweep Extrusion<br>[2748, 2777, 0]"] | ||||
|   229[Wall] | ||||
|   230[Wall] | ||||
|   231[Wall] | ||||
|   232[Wall] | ||||
|   233["SweepEdge Opposite"] | ||||
|   234["SweepEdge Adjacent"] | ||||
|   235["SweepEdge Opposite"] | ||||
|   236["SweepEdge Adjacent"] | ||||
|   237["SweepEdge Opposite"] | ||||
|   238["SweepEdge Adjacent"] | ||||
|   239["SweepEdge Opposite"] | ||||
|   240["SweepEdge Adjacent"] | ||||
|   241["StartSketchOnFace<br>[2250, 2281, 0]"] | ||||
|   2 --- 3 | ||||
|   3 --- 4 | ||||
|   3 ---- 6 | ||||
|   3 --- 5 | ||||
|   4 --- 7 | ||||
|   4 --- 10 | ||||
|   4 --- 11 | ||||
|   6 --- 7 | ||||
|   6 --- 8 | ||||
|   6 --- 9 | ||||
|   6 --- 10 | ||||
|   6 --- 11 | ||||
|   9 --- 220 | ||||
|   12 --- 13 | ||||
|   13 --- 14 | ||||
|   13 --- 15 | ||||
|   13 --- 16 | ||||
|   13 --- 17 | ||||
|   13 --- 18 | ||||
|   13 --- 19 | ||||
|   13 --- 20 | ||||
|   13 --- 21 | ||||
|   13 --- 22 | ||||
|   13 --- 23 | ||||
|   13 --- 24 | ||||
|   13 --- 25 | ||||
|   13 --- 26 | ||||
|   13 --- 27 | ||||
|   13 --- 28 | ||||
|   13 --- 29 | ||||
|   13 --- 30 | ||||
|   13 --- 31 | ||||
|   13 --- 32 | ||||
|   13 --- 33 | ||||
|   13 --- 34 | ||||
|   13 --- 35 | ||||
|   13 --- 36 | ||||
|   13 --- 37 | ||||
|   13 --- 38 | ||||
|   13 --- 39 | ||||
|   13 --- 40 | ||||
|   13 --- 41 | ||||
|   13 --- 42 | ||||
|   13 --- 43 | ||||
|   13 --- 44 | ||||
|   13 --- 45 | ||||
|   13 --- 46 | ||||
|   13 --- 47 | ||||
|   13 --- 48 | ||||
|   13 --- 49 | ||||
|   13 --- 50 | ||||
|   13 --- 51 | ||||
|   13 --- 52 | ||||
|   13 --- 53 | ||||
|   13 --- 54 | ||||
|   13 --- 55 | ||||
|   13 --- 56 | ||||
|   13 --- 57 | ||||
|   13 --- 58 | ||||
|   13 --- 59 | ||||
|   13 --- 60 | ||||
|   13 --- 61 | ||||
|   13 --- 62 | ||||
|   13 --- 63 | ||||
|   13 --- 64 | ||||
|   13 --- 65 | ||||
|   13 --- 66 | ||||
|   13 --- 67 | ||||
|   13 --- 68 | ||||
|   13 --- 69 | ||||
|   13 --- 70 | ||||
|   13 --- 71 | ||||
|   13 --- 72 | ||||
|   13 --- 73 | ||||
|   13 --- 74 | ||||
|   13 --- 75 | ||||
|   13 --- 76 | ||||
|   13 --- 77 | ||||
|   13 --- 78 | ||||
|   13 --- 79 | ||||
|   13 --- 80 | ||||
|   13 --- 81 | ||||
|   13 --- 82 | ||||
|   13 --- 83 | ||||
|   13 --- 84 | ||||
|   13 --- 85 | ||||
|   13 --- 86 | ||||
|   13 --- 87 | ||||
|   13 --- 88 | ||||
|   13 --- 89 | ||||
|   13 --- 90 | ||||
|   13 --- 91 | ||||
|   13 --- 92 | ||||
|   13 --- 93 | ||||
|   13 --- 94 | ||||
|   13 --- 95 | ||||
|   13 --- 96 | ||||
|   13 --- 97 | ||||
|   13 --- 98 | ||||
|   13 --- 99 | ||||
|   13 --- 100 | ||||
|   13 --- 101 | ||||
|   13 --- 102 | ||||
|   13 --- 103 | ||||
|   13 --- 104 | ||||
|   13 --- 105 | ||||
|   13 --- 106 | ||||
|   13 --- 107 | ||||
|   13 --- 108 | ||||
|   13 --- 109 | ||||
|   13 --- 110 | ||||
|   13 --- 111 | ||||
|   13 --- 112 | ||||
|   13 --- 113 | ||||
|   13 --- 114 | ||||
|   13 --- 115 | ||||
|   13 --- 116 | ||||
|   13 --- 117 | ||||
|   13 --- 118 | ||||
|   13 --- 119 | ||||
|   13 --- 120 | ||||
|   13 --- 121 | ||||
|   13 --- 122 | ||||
|   13 --- 123 | ||||
|   13 --- 124 | ||||
|   13 --- 125 | ||||
|   13 --- 126 | ||||
|   13 --- 127 | ||||
|   13 --- 128 | ||||
|   13 --- 129 | ||||
|   13 --- 130 | ||||
|   13 --- 131 | ||||
|   13 --- 132 | ||||
|   13 --- 133 | ||||
|   13 --- 134 | ||||
|   13 --- 135 | ||||
|   13 --- 136 | ||||
|   13 --- 137 | ||||
|   13 --- 138 | ||||
|   13 --- 139 | ||||
|   13 --- 140 | ||||
|   13 --- 141 | ||||
|   13 --- 142 | ||||
|   13 --- 143 | ||||
|   13 --- 144 | ||||
|   13 --- 145 | ||||
|   13 --- 146 | ||||
|   13 --- 147 | ||||
|   13 --- 148 | ||||
|   13 --- 149 | ||||
|   13 --- 150 | ||||
|   13 --- 151 | ||||
|   13 --- 152 | ||||
|   13 --- 153 | ||||
|   13 --- 154 | ||||
|   13 --- 155 | ||||
|   13 --- 156 | ||||
|   13 --- 157 | ||||
|   13 --- 158 | ||||
|   13 --- 159 | ||||
|   13 --- 160 | ||||
|   13 --- 161 | ||||
|   13 --- 162 | ||||
|   13 --- 163 | ||||
|   13 --- 164 | ||||
|   13 --- 165 | ||||
|   13 --- 166 | ||||
|   13 --- 167 | ||||
|   13 --- 168 | ||||
|   13 --- 169 | ||||
|   13 --- 170 | ||||
|   13 --- 171 | ||||
|   13 --- 172 | ||||
|   13 --- 173 | ||||
|   13 --- 174 | ||||
|   13 --- 175 | ||||
|   13 --- 176 | ||||
|   13 --- 177 | ||||
|   13 --- 178 | ||||
|   13 --- 179 | ||||
|   13 --- 180 | ||||
|   13 --- 181 | ||||
|   13 --- 182 | ||||
|   13 --- 183 | ||||
|   13 --- 184 | ||||
|   13 --- 185 | ||||
|   13 --- 186 | ||||
|   13 --- 187 | ||||
|   13 --- 188 | ||||
|   13 --- 189 | ||||
|   13 --- 190 | ||||
|   13 --- 191 | ||||
|   13 --- 192 | ||||
|   13 --- 193 | ||||
|   13 --- 194 | ||||
|   13 --- 195 | ||||
|   13 --- 196 | ||||
|   13 --- 197 | ||||
|   13 --- 198 | ||||
|   13 --- 199 | ||||
|   13 --- 200 | ||||
|   13 --- 201 | ||||
|   13 --- 202 | ||||
|   13 --- 203 | ||||
|   13 --- 204 | ||||
|   13 --- 205 | ||||
|   13 --- 206 | ||||
|   13 --- 207 | ||||
|   13 --- 208 | ||||
|   13 --- 209 | ||||
|   13 --- 210 | ||||
|   13 --- 211 | ||||
|   13 --- 212 | ||||
|   13 --- 213 | ||||
|   13 --- 214 | ||||
|   13 --- 215 | ||||
|   13 --- 216 | ||||
|   13 --- 217 | ||||
|   13 ---- 219 | ||||
|   13 --- 218 | ||||
|   220 --- 221 | ||||
|   220 --- 222 | ||||
|   220 --- 223 | ||||
|   220 --- 224 | ||||
|   220 --- 225 | ||||
|   220 --- 226 | ||||
|   220 ---- 228 | ||||
|   220 --- 227 | ||||
|   221 --- 232 | ||||
|   221 --- 239 | ||||
|   221 --- 240 | ||||
|   222 --- 231 | ||||
|   222 --- 237 | ||||
|   222 --- 238 | ||||
|   223 --- 230 | ||||
|   223 --- 235 | ||||
|   223 --- 236 | ||||
|   225 --- 229 | ||||
|   225 --- 233 | ||||
|   225 --- 234 | ||||
|   228 --- 229 | ||||
|   228 --- 230 | ||||
|   228 --- 231 | ||||
|   228 --- 232 | ||||
|   228 --- 233 | ||||
|   228 --- 234 | ||||
|   228 --- 235 | ||||
|   228 --- 236 | ||||
|   228 --- 237 | ||||
|   228 --- 238 | ||||
|   228 --- 239 | ||||
|   228 --- 240 | ||||
|   9 <--x 241 | ||||
| ``` | ||||
							
								
								
									
										5103
									
								
								rust/kcl-lib/tests/import_async/ast.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5103
									
								
								rust/kcl-lib/tests/import_async/ast.snap
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										117
									
								
								rust/kcl-lib/tests/import_async/input.kcl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								rust/kcl-lib/tests/import_async/input.kcl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,117 @@ | ||||
| @(lengthUnit = m) | ||||
| import "../../e2e/executor/inputs/2-5-long-m8-chc-screw.stl" as screw | ||||
|  | ||||
| // Set units | ||||
| @settings(defaultLengthUnit = mm) | ||||
|  | ||||
| myScrew = screw | ||||
|  | ||||
|  | ||||
| surface001 = startSketchOn(XY) | ||||
|  | ||||
| // Define parameters | ||||
| nTeeth = 21 | ||||
| module = 0.5 | ||||
| pitchDiameter = module * nTeeth | ||||
| pressureAngle = 20 | ||||
| addendum = module | ||||
| deddendum = 1.25 * module | ||||
| baseDiameter = pitchDiameter * cos(toRadians(pressureAngle)) | ||||
| tipDiameter = pitchDiameter + 2 * module | ||||
| gearHeight = 3 | ||||
|  | ||||
| // Interpolate points along the involute curve | ||||
| cmo = 101 | ||||
| rs = map([0..cmo], fn(i) { | ||||
|   return baseDiameter / 2 + i / cmo * (tipDiameter - baseDiameter) / 2 | ||||
| }) | ||||
|  | ||||
| // Calculate operating pressure angle | ||||
| angles = map(rs, fn(r) { | ||||
|   return toDegrees(  acos(baseDiameter / 2 / r)) | ||||
| }) | ||||
|  | ||||
| // Calculate the involute function | ||||
| invas = map(angles, fn(a) { | ||||
|   return tan(toRadians(a)) - toRadians(a) | ||||
| }) | ||||
|  | ||||
| // Map the involute curve | ||||
| xs = map([0..cmo], fn(i) { | ||||
|   return rs[i] * cos(invas[i]) | ||||
| }) | ||||
|  | ||||
| ys = map([0..cmo], fn(i) { | ||||
|   return rs[i] * sin(invas[i]) | ||||
| }) | ||||
|  | ||||
| // Extrude the gear body | ||||
| body = startSketchOn(XY) | ||||
|   |> circle(center = [0, 0], radius = baseDiameter / 2) | ||||
|   |> extrude(length = gearHeight) | ||||
|  | ||||
| toothAngle = 360 / nTeeth / 1.5 | ||||
|  | ||||
| // Plot the involute curve | ||||
| fn leftInvolute(i, sg) { | ||||
|   j = 100 - i // iterate backwards | ||||
|   return line(sg, endAbsolute = [xs[j], ys[j]]) | ||||
| } | ||||
|  | ||||
| fn rightInvolute(i, sg) { | ||||
|   x = rs[i] * cos(toRadians(-toothAngle + toDegrees(atan(ys[i] / xs[i])))) | ||||
|   y = -rs[i] * sin(toRadians(-toothAngle + toDegrees(atan(ys[i] / xs[i])))) | ||||
|   return line(sg, endAbsolute = [x, y]) | ||||
| } | ||||
|  | ||||
| // Draw gear teeth | ||||
| start = startSketchOn(XY) | ||||
|   |> startProfileAt([xs[101], ys[101]], %) | ||||
| teeth = reduce([0..100], start, leftInvolute) | ||||
|   |> arc({ | ||||
|        angleStart = 0, | ||||
|        angleEnd = toothAngle, | ||||
|        radius = baseDiameter / 2 | ||||
|      }, %) | ||||
|   |> reduce([1..101], %, rightInvolute) | ||||
|   |> close() | ||||
|   |> extrude(length = gearHeight) | ||||
|   |> patternCircular3d( | ||||
|        axis = [0, 0, 1], | ||||
|        center = [0, 0, 0], | ||||
|        instances = nTeeth, | ||||
|        arcDegrees = 360, | ||||
|        rotateDuplicates = true, | ||||
|      ) | ||||
|  | ||||
| // Define the constants of the keyway and the bore hole | ||||
| keywayWidth = 0.250 | ||||
| keywayDepth = keywayWidth / 2 | ||||
| holeDiam = 2 | ||||
| holeRadius = 1 | ||||
| startAngle = asin(keywayWidth / 2 / holeRadius) | ||||
|  | ||||
| // Sketch the keyway and center hole and extrude | ||||
| keyWay = startSketchOn(body, face = END) | ||||
|   |> startProfileAt([ | ||||
|        holeRadius * cos(startAngle), | ||||
|        holeRadius * sin(startAngle) | ||||
|      ], %) | ||||
|   |> xLine(length = keywayDepth) | ||||
|   |> yLine(length = -keywayWidth) | ||||
|   |> xLine(length = -keywayDepth) | ||||
|   |> arc({ | ||||
|        angleEnd = 180, | ||||
|        angleStart = -1 * toDegrees(startAngle) + 360, | ||||
|        radius = holeRadius | ||||
|      }, %) | ||||
|   |> arc({ | ||||
|        angleEnd = toDegrees(startAngle), | ||||
|        angleStart = 180, | ||||
|        radius = holeRadius | ||||
|      }, %) | ||||
|   |> close() | ||||
|   |> extrude(length = -gearHeight) | ||||
|  | ||||
| myScrew | ||||
|   |> translate(y=10) | ||||
							
								
								
									
										9529
									
								
								rust/kcl-lib/tests/import_async/ops.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9529
									
								
								rust/kcl-lib/tests/import_async/ops.snap
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										89754
									
								
								rust/kcl-lib/tests/import_async/program_memory.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89754
									
								
								rust/kcl-lib/tests/import_async/program_memory.snap
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								rust/kcl-lib/tests/import_async/rendered_model.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								rust/kcl-lib/tests/import_async/rendered_model.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 55 KiB | 
							
								
								
									
										120
									
								
								rust/kcl-lib/tests/import_async/unparsed.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								rust/kcl-lib/tests/import_async/unparsed.snap
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,120 @@ | ||||
| --- | ||||
| source: kcl-lib/src/simulation_tests.rs | ||||
| description: Result of unparsing import_async.kcl | ||||
| --- | ||||
| // Set units | ||||
| @settings(defaultLengthUnit = mm) | ||||
|  | ||||
| @(lengthUnit = m) | ||||
| import "../../e2e/executor/inputs/2-5-long-m8-chc-screw.stl" as screw | ||||
|  | ||||
| myScrew = screw | ||||
|  | ||||
| surface001 = startSketchOn(XY) | ||||
|  | ||||
| // Define parameters | ||||
| nTeeth = 21 | ||||
| module = 0.5 | ||||
| pitchDiameter = module * nTeeth | ||||
| pressureAngle = 20 | ||||
| addendum = module | ||||
| deddendum = 1.25 * module | ||||
| baseDiameter = pitchDiameter * cos(toRadians(pressureAngle)) | ||||
| tipDiameter = pitchDiameter + 2 * module | ||||
| gearHeight = 3 | ||||
|  | ||||
| // Interpolate points along the involute curve | ||||
| cmo = 101 | ||||
| rs = map([0..cmo], fn(i) { | ||||
|   return baseDiameter / 2 + i / cmo * (tipDiameter - baseDiameter) / 2 | ||||
| }) | ||||
|  | ||||
| // Calculate operating pressure angle | ||||
| angles = map(rs, fn(r) { | ||||
|   return toDegrees(  acos(baseDiameter / 2 / r)) | ||||
| }) | ||||
|  | ||||
| // Calculate the involute function | ||||
| invas = map(angles, fn(a) { | ||||
|   return tan(toRadians(a)) - toRadians(a) | ||||
| }) | ||||
|  | ||||
| // Map the involute curve | ||||
| xs = map([0..cmo], fn(i) { | ||||
|   return rs[i] * cos(invas[i]) | ||||
| }) | ||||
|  | ||||
| ys = map([0..cmo], fn(i) { | ||||
|   return rs[i] * sin(invas[i]) | ||||
| }) | ||||
|  | ||||
| // Extrude the gear body | ||||
| body = startSketchOn(XY) | ||||
|   |> circle(center = [0, 0], radius = baseDiameter / 2) | ||||
|   |> extrude(length = gearHeight) | ||||
|  | ||||
| toothAngle = 360 / nTeeth / 1.5 | ||||
|  | ||||
| // Plot the involute curve | ||||
| fn leftInvolute(i, sg) { | ||||
|   j = 100 - i // iterate backwards | ||||
|   return line(sg, endAbsolute = [xs[j], ys[j]]) | ||||
| } | ||||
|  | ||||
| fn rightInvolute(i, sg) { | ||||
|   x = rs[i] * cos(toRadians(-toothAngle + toDegrees(atan(ys[i] / xs[i])))) | ||||
|   y = -rs[i] * sin(toRadians(-toothAngle + toDegrees(atan(ys[i] / xs[i])))) | ||||
|   return line(sg, endAbsolute = [x, y]) | ||||
| } | ||||
|  | ||||
| // Draw gear teeth | ||||
| start = startSketchOn(XY) | ||||
|   |> startProfileAt([xs[101], ys[101]], %) | ||||
| teeth = reduce([0..100], start, leftInvolute) | ||||
|   |> arc({ | ||||
|        angleStart = 0, | ||||
|        angleEnd = toothAngle, | ||||
|        radius = baseDiameter / 2 | ||||
|      }, %) | ||||
|   |> reduce([1..101], %, rightInvolute) | ||||
|   |> close() | ||||
|   |> extrude(length = gearHeight) | ||||
|   |> patternCircular3d( | ||||
|        axis = [0, 0, 1], | ||||
|        center = [0, 0, 0], | ||||
|        instances = nTeeth, | ||||
|        arcDegrees = 360, | ||||
|        rotateDuplicates = true, | ||||
|      ) | ||||
|  | ||||
| // Define the constants of the keyway and the bore hole | ||||
| keywayWidth = 0.250 | ||||
| keywayDepth = keywayWidth / 2 | ||||
| holeDiam = 2 | ||||
| holeRadius = 1 | ||||
| startAngle = asin(keywayWidth / 2 / holeRadius) | ||||
|  | ||||
| // Sketch the keyway and center hole and extrude | ||||
| keyWay = startSketchOn(body, face = END) | ||||
|   |> startProfileAt([ | ||||
|        holeRadius * cos(startAngle), | ||||
|        holeRadius * sin(startAngle) | ||||
|      ], %) | ||||
|   |> xLine(length = keywayDepth) | ||||
|   |> yLine(length = -keywayWidth) | ||||
|   |> xLine(length = -keywayDepth) | ||||
|   |> arc({ | ||||
|        angleEnd = 180, | ||||
|        angleStart = -1 * toDegrees(startAngle) + 360, | ||||
|        radius = holeRadius | ||||
|      }, %) | ||||
|   |> arc({ | ||||
|        angleEnd = toDegrees(startAngle), | ||||
|        angleStart = 180, | ||||
|        radius = holeRadius | ||||
|      }, %) | ||||
|   |> close() | ||||
|   |> extrude(length = -gearHeight) | ||||
|  | ||||
| myScrew | ||||
|   |> translate(y = 10) | ||||
							
								
								
									
										5506
									
								
								rust/kcl-lib/tests/kcl_samples/axial-fan/artifact_commands.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5506
									
								
								rust/kcl-lib/tests/kcl_samples/axial-fan/artifact_commands.snap
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -0,0 +1,6 @@ | ||||
| --- | ||||
| source: kcl-lib/src/simulation_tests.rs | ||||
| description: Artifact graph flowchart axial-fan.kcl | ||||
| extension: md | ||||
| snapshot_kind: binary | ||||
| --- | ||||
| @ -0,0 +1,754 @@ | ||||
| ```mermaid | ||||
| flowchart LR | ||||
|   subgraph path2 [Path] | ||||
|     2["Path<br>[323, 370, 5]"] | ||||
|     3["Segment<br>[376, 444, 5]"] | ||||
|     4["Segment<br>[450, 550, 5]"] | ||||
|     5["Segment<br>[556, 673, 5]"] | ||||
|     6["Segment<br>[679, 764, 5]"] | ||||
|     7["Segment<br>[770, 777, 5]"] | ||||
|     8[Solid2d] | ||||
|   end | ||||
|   subgraph path9 [Path] | ||||
|     9["Path<br>[788, 823, 5]"] | ||||
|     10["Segment<br>[788, 823, 5]"] | ||||
|     11[Solid2d] | ||||
|   end | ||||
|   subgraph path12 [Path] | ||||
|     12["Path<br>[838, 985, 5]"] | ||||
|     13["Segment<br>[838, 985, 5]"] | ||||
|     14[Solid2d] | ||||
|   end | ||||
|   subgraph path15 [Path] | ||||
|     15["Path<br>[1000, 1148, 5]"] | ||||
|     16["Segment<br>[1000, 1148, 5]"] | ||||
|     17[Solid2d] | ||||
|   end | ||||
|   subgraph path18 [Path] | ||||
|     18["Path<br>[1163, 1311, 5]"] | ||||
|     19["Segment<br>[1163, 1311, 5]"] | ||||
|     20[Solid2d] | ||||
|   end | ||||
|   subgraph path21 [Path] | ||||
|     21["Path<br>[1326, 1475, 5]"] | ||||
|     22["Segment<br>[1326, 1475, 5]"] | ||||
|     23[Solid2d] | ||||
|   end | ||||
|   subgraph path39 [Path] | ||||
|     39["Path<br>[1646, 1702, 5]"] | ||||
|     40["Segment<br>[1708, 1773, 5]"] | ||||
|     41["Segment<br>[1779, 1831, 5]"] | ||||
|     42["Segment<br>[1837, 1888, 5]"] | ||||
|     43["Segment<br>[1894, 1946, 5]"] | ||||
|     44["Segment<br>[1952, 2018, 5]"] | ||||
|     45["Segment<br>[2024, 2076, 5]"] | ||||
|     46["Segment<br>[2082, 2114, 5]"] | ||||
|     47["Segment<br>[2120, 2185, 5]"] | ||||
|     48["Segment<br>[2191, 2198, 5]"] | ||||
|     49[Solid2d] | ||||
|   end | ||||
|   subgraph path78 [Path] | ||||
|     78["Path<br>[2547, 2660, 5]"] | ||||
|     79["Segment<br>[2666, 2721, 5]"] | ||||
|     80["Segment<br>[2727, 2762, 5]"] | ||||
|     81["Segment<br>[2768, 2823, 5]"] | ||||
|     82["Segment<br>[2829, 2865, 5]"] | ||||
|     83["Segment<br>[2871, 2926, 5]"] | ||||
|     84["Segment<br>[2932, 2968, 5]"] | ||||
|     85["Segment<br>[2974, 3029, 5]"] | ||||
|     86["Segment<br>[3035, 3091, 5]"] | ||||
|   end | ||||
|   subgraph path113 [Path] | ||||
|     113["Path<br>[3240, 3291, 5]"] | ||||
|     114["Segment<br>[3240, 3291, 5]"] | ||||
|     115[Solid2d] | ||||
|   end | ||||
|   subgraph path120 [Path] | ||||
|     120["Path<br>[3470, 3529, 5]"] | ||||
|     121["Segment<br>[3535, 3603, 5]"] | ||||
|     122["Segment<br>[3609, 3709, 5]"] | ||||
|     123["Segment<br>[3715, 3832, 5]"] | ||||
|     124["Segment<br>[3838, 3923, 5]"] | ||||
|     125["Segment<br>[3929, 3936, 5]"] | ||||
|     126[Solid2d] | ||||
|   end | ||||
|   subgraph path127 [Path] | ||||
|     127["Path<br>[3947, 3998, 5]"] | ||||
|     128["Segment<br>[3947, 3998, 5]"] | ||||
|     129[Solid2d] | ||||
|   end | ||||
|   subgraph path130 [Path] | ||||
|     130["Path<br>[4013, 4160, 5]"] | ||||
|     131["Segment<br>[4013, 4160, 5]"] | ||||
|     132[Solid2d] | ||||
|   end | ||||
|   subgraph path133 [Path] | ||||
|     133["Path<br>[4175, 4323, 5]"] | ||||
|     134["Segment<br>[4175, 4323, 5]"] | ||||
|     135[Solid2d] | ||||
|   end | ||||
|   subgraph path136 [Path] | ||||
|     136["Path<br>[4338, 4486, 5]"] | ||||
|     137["Segment<br>[4338, 4486, 5]"] | ||||
|     138[Solid2d] | ||||
|   end | ||||
|   subgraph path139 [Path] | ||||
|     139["Path<br>[4501, 4650, 5]"] | ||||
|     140["Segment<br>[4501, 4650, 5]"] | ||||
|     141[Solid2d] | ||||
|   end | ||||
|   subgraph path157 [Path] | ||||
|     157["Path<br>[4795, 4833, 5]"] | ||||
|     158["Segment<br>[4795, 4833, 5]"] | ||||
|     159[Solid2d] | ||||
|   end | ||||
|   subgraph path165 [Path] | ||||
|     165["Path<br>[4906, 4942, 5]"] | ||||
|     166["Segment<br>[4906, 4942, 5]"] | ||||
|     167[Solid2d] | ||||
|   end | ||||
|   subgraph path181 [Path] | ||||
|     181["Path<br>[277, 327, 6]"] | ||||
|     182["Segment<br>[277, 327, 6]"] | ||||
|     183[Solid2d] | ||||
|   end | ||||
|   subgraph path191 [Path] | ||||
|     191["Path<br>[502, 537, 6]"] | ||||
|     192["Segment<br>[502, 537, 6]"] | ||||
|     193[Solid2d] | ||||
|   end | ||||
|   subgraph path203 [Path] | ||||
|     203["Path<br>[216, 255, 7]"] | ||||
|     204["Segment<br>[261, 291, 7]"] | ||||
|     205["Segment<br>[297, 336, 7]"] | ||||
|     206["Segment<br>[342, 366, 7]"] | ||||
|     207["Segment<br>[372, 396, 7]"] | ||||
|     208["Segment<br>[402, 443, 7]"] | ||||
|     209["Segment<br>[449, 487, 7]"] | ||||
|     210["Segment<br>[493, 516, 7]"] | ||||
|     211["Segment<br>[522, 539, 7]"] | ||||
|     212["Segment<br>[545, 566, 7]"] | ||||
|     213["Segment<br>[572, 659, 7]"] | ||||
|     214["Segment<br>[665, 702, 7]"] | ||||
|     215["Segment<br>[708, 745, 7]"] | ||||
|     216["Segment<br>[751, 758, 7]"] | ||||
|     217[Solid2d] | ||||
|   end | ||||
|   subgraph path243 [Path] | ||||
|     243["Path<br>[1100, 1212, 7]"] | ||||
|     244["Segment<br>[1220, 1330, 7]"] | ||||
|     245["Segment<br>[1338, 1672, 7]"] | ||||
|     246["Segment<br>[1680, 2016, 7]"] | ||||
|     247["Segment<br>[2024, 2255, 7]"] | ||||
|     248["Segment<br>[2263, 2270, 7]"] | ||||
|     249[Solid2d] | ||||
|   end | ||||
|   subgraph path251 [Path] | ||||
|     251["Path<br>[1100, 1212, 7]"] | ||||
|     252["Segment<br>[1220, 1330, 7]"] | ||||
|     253["Segment<br>[1338, 1672, 7]"] | ||||
|     254["Segment<br>[1680, 2016, 7]"] | ||||
|     255["Segment<br>[2024, 2255, 7]"] | ||||
|     256["Segment<br>[2263, 2270, 7]"] | ||||
|     257[Solid2d] | ||||
|   end | ||||
|   subgraph path259 [Path] | ||||
|     259["Path<br>[1100, 1212, 7]"] | ||||
|     264["Segment<br>[2263, 2270, 7]"] | ||||
|     265[Solid2d] | ||||
|   end | ||||
|   1["Plane<br>[300, 317, 5]"] | ||||
|   24["Sweep Extrusion<br>[1485, 1504, 5]"] | ||||
|   25[Wall] | ||||
|   26[Wall] | ||||
|   27[Wall] | ||||
|   28[Wall] | ||||
|   29["Cap Start"] | ||||
|   30["Cap End"] | ||||
|   31["SweepEdge Opposite"] | ||||
|   32["SweepEdge Adjacent"] | ||||
|   33["SweepEdge Opposite"] | ||||
|   34["SweepEdge Adjacent"] | ||||
|   35["SweepEdge Opposite"] | ||||
|   36["SweepEdge Adjacent"] | ||||
|   37["SweepEdge Opposite"] | ||||
|   38["SweepEdge Adjacent"] | ||||
|   50["Sweep Extrusion<br>[2338, 2358, 5]"] | ||||
|   51[Wall] | ||||
|   52[Wall] | ||||
|   53[Wall] | ||||
|   54[Wall] | ||||
|   55[Wall] | ||||
|   56[Wall] | ||||
|   57[Wall] | ||||
|   58[Wall] | ||||
|   59["SweepEdge Opposite"] | ||||
|   60["SweepEdge Adjacent"] | ||||
|   61["SweepEdge Opposite"] | ||||
|   62["SweepEdge Adjacent"] | ||||
|   63["SweepEdge Opposite"] | ||||
|   64["SweepEdge Adjacent"] | ||||
|   65["SweepEdge Opposite"] | ||||
|   66["SweepEdge Adjacent"] | ||||
|   67["SweepEdge Opposite"] | ||||
|   68["SweepEdge Adjacent"] | ||||
|   69["SweepEdge Opposite"] | ||||
|   70["SweepEdge Adjacent"] | ||||
|   71["SweepEdge Opposite"] | ||||
|   72["SweepEdge Adjacent"] | ||||
|   73["SweepEdge Opposite"] | ||||
|   74["SweepEdge Adjacent"] | ||||
|   75["Sweep Extrusion<br>[2338, 2358, 5]"] | ||||
|   76["Sweep Extrusion<br>[2338, 2358, 5]"] | ||||
|   77["Sweep Extrusion<br>[2338, 2358, 5]"] | ||||
|   87["Sweep Extrusion<br>[3097, 3132, 5]"] | ||||
|   88[Wall] | ||||
|   89[Wall] | ||||
|   90[Wall] | ||||
|   91[Wall] | ||||
|   92[Wall] | ||||
|   93[Wall] | ||||
|   94[Wall] | ||||
|   95[Wall] | ||||
|   96["Cap End"] | ||||
|   97["SweepEdge Opposite"] | ||||
|   98["SweepEdge Adjacent"] | ||||
|   99["SweepEdge Opposite"] | ||||
|   100["SweepEdge Adjacent"] | ||||
|   101["SweepEdge Opposite"] | ||||
|   102["SweepEdge Adjacent"] | ||||
|   103["SweepEdge Opposite"] | ||||
|   104["SweepEdge Adjacent"] | ||||
|   105["SweepEdge Opposite"] | ||||
|   106["SweepEdge Adjacent"] | ||||
|   107["SweepEdge Opposite"] | ||||
|   108["SweepEdge Adjacent"] | ||||
|   109["SweepEdge Opposite"] | ||||
|   110["SweepEdge Adjacent"] | ||||
|   111["SweepEdge Opposite"] | ||||
|   112["SweepEdge Adjacent"] | ||||
|   116["Sweep Extrusion<br>[3297, 3335, 5]"] | ||||
|   117[Wall] | ||||
|   118["SweepEdge Opposite"] | ||||
|   119["SweepEdge Adjacent"] | ||||
|   142["Sweep Extrusion<br>[4660, 4679, 5]"] | ||||
|   143[Wall] | ||||
|   144[Wall] | ||||
|   145[Wall] | ||||
|   146[Wall] | ||||
|   147["Cap Start"] | ||||
|   148["Cap End"] | ||||
|   149["SweepEdge Opposite"] | ||||
|   150["SweepEdge Adjacent"] | ||||
|   151["SweepEdge Opposite"] | ||||
|   152["SweepEdge Adjacent"] | ||||
|   153["SweepEdge Opposite"] | ||||
|   154["SweepEdge Adjacent"] | ||||
|   155["SweepEdge Opposite"] | ||||
|   156["SweepEdge Adjacent"] | ||||
|   160["Sweep Extrusion<br>[4839, 4859, 5]"] | ||||
|   161[Wall] | ||||
|   162["Cap End"] | ||||
|   163["SweepEdge Opposite"] | ||||
|   164["SweepEdge Adjacent"] | ||||
|   168["Sweep Extrusion<br>[4948, 4969, 5]"] | ||||
|   169[Wall] | ||||
|   170["SweepEdge Opposite"] | ||||
|   171["SweepEdge Adjacent"] | ||||
|   172["EdgeCut Fillet<br>[5010, 5521, 5]"] | ||||
|   173["EdgeCut Fillet<br>[5010, 5521, 5]"] | ||||
|   174["EdgeCut Fillet<br>[5010, 5521, 5]"] | ||||
|   175["EdgeCut Fillet<br>[5010, 5521, 5]"] | ||||
|   176["EdgeCut Fillet<br>[5010, 5521, 5]"] | ||||
|   177["EdgeCut Fillet<br>[5010, 5521, 5]"] | ||||
|   178["EdgeCut Fillet<br>[5010, 5521, 5]"] | ||||
|   179["EdgeCut Fillet<br>[5010, 5521, 5]"] | ||||
|   180["Plane<br>[204, 231, 6]"] | ||||
|   184["Sweep Extrusion<br>[333, 353, 6]"] | ||||
|   185[Wall] | ||||
|   186["Cap Start"] | ||||
|   187["Cap End"] | ||||
|   188["SweepEdge Opposite"] | ||||
|   189["SweepEdge Adjacent"] | ||||
|   190["Plane<br>[467, 495, 6]"] | ||||
|   194["Sweep Extrusion<br>[543, 564, 6]"] | ||||
|   195[Wall] | ||||
|   196["Cap Start"] | ||||
|   197["Cap End"] | ||||
|   198["SweepEdge Opposite"] | ||||
|   199["SweepEdge Adjacent"] | ||||
|   200["EdgeCut Fillet<br>[394, 452, 6]"] | ||||
|   201["EdgeCut Fillet<br>[394, 452, 6]"] | ||||
|   202["Plane<br>[193, 210, 7]"] | ||||
|   218["Sweep Revolve<br>[764, 846, 7]"] | ||||
|   219[Wall] | ||||
|   220[Wall] | ||||
|   221[Wall] | ||||
|   222[Wall] | ||||
|   223[Wall] | ||||
|   224[Wall] | ||||
|   225[Wall] | ||||
|   226[Wall] | ||||
|   227[Wall] | ||||
|   228[Wall] | ||||
|   229[Wall] | ||||
|   230[Wall] | ||||
|   231["SweepEdge Adjacent"] | ||||
|   232["SweepEdge Adjacent"] | ||||
|   233["SweepEdge Adjacent"] | ||||
|   234["SweepEdge Adjacent"] | ||||
|   235["SweepEdge Adjacent"] | ||||
|   236["SweepEdge Adjacent"] | ||||
|   237["SweepEdge Adjacent"] | ||||
|   238["SweepEdge Adjacent"] | ||||
|   239["SweepEdge Adjacent"] | ||||
|   240["SweepEdge Adjacent"] | ||||
|   241["SweepEdge Adjacent"] | ||||
|   242["Plane<br>[1053, 1091, 7]"] | ||||
|   250["Plane<br>[1053, 1091, 7]"] | ||||
|   258["Plane<br>[1053, 1091, 7]"] | ||||
|   260["SweepEdge Opposite"] | ||||
|   261["SweepEdge Opposite"] | ||||
|   262["SweepEdge Opposite"] | ||||
|   263["SweepEdge Opposite"] | ||||
|   266["Sweep Loft<br>[2389, 2509, 7]"] | ||||
|   267[Wall] | ||||
|   268[Wall] | ||||
|   269[Wall] | ||||
|   270[Wall] | ||||
|   271["Cap End"] | ||||
|   272["Cap End"] | ||||
|   273["SweepEdge Adjacent"] | ||||
|   274["SweepEdge Adjacent"] | ||||
|   275["SweepEdge Adjacent"] | ||||
|   276["SweepEdge Adjacent"] | ||||
|   277["StartSketchOnFace<br>[1597, 1640, 5]"] | ||||
|   278["StartSketchOnFace<br>[2498, 2541, 5]"] | ||||
|   279["StartSketchOnFace<br>[3197, 3234, 5]"] | ||||
|   280["StartSketchOnFace<br>[3421, 3458, 5]"] | ||||
|   281["StartSketchOnFace<br>[4746, 4789, 5]"] | ||||
|   282["StartSketchOnFace<br>[4861, 4900, 5]"] | ||||
|   283["StartSketchOnPlane<br>[244, 271, 6]"] | ||||
|   284["StartSketchOnPlane<br>[453, 496, 6]"] | ||||
|   285["StartSketchOnPlane<br>[1039, 1092, 7]"] | ||||
|   286["StartSketchOnPlane<br>[1039, 1092, 7]"] | ||||
|   287["StartSketchOnPlane<br>[1039, 1092, 7]"] | ||||
|   1 --- 2 | ||||
|   1 --- 9 | ||||
|   1 --- 12 | ||||
|   1 --- 15 | ||||
|   1 --- 18 | ||||
|   1 --- 21 | ||||
|   2 --- 3 | ||||
|   2 --- 4 | ||||
|   2 --- 5 | ||||
|   2 --- 6 | ||||
|   2 --- 7 | ||||
|   2 ---- 24 | ||||
|   2 --- 8 | ||||
|   3 --- 25 | ||||
|   3 --- 31 | ||||
|   3 --- 32 | ||||
|   4 --- 26 | ||||
|   4 --- 33 | ||||
|   4 --- 34 | ||||
|   5 --- 27 | ||||
|   5 --- 35 | ||||
|   5 --- 36 | ||||
|   6 --- 28 | ||||
|   6 --- 37 | ||||
|   6 --- 38 | ||||
|   9 --- 10 | ||||
|   9 --- 11 | ||||
|   12 --- 13 | ||||
|   12 --- 14 | ||||
|   15 --- 16 | ||||
|   15 --- 17 | ||||
|   18 --- 19 | ||||
|   18 --- 20 | ||||
|   21 --- 22 | ||||
|   21 --- 23 | ||||
|   24 --- 25 | ||||
|   24 --- 26 | ||||
|   24 --- 27 | ||||
|   24 --- 28 | ||||
|   24 --- 29 | ||||
|   24 --- 30 | ||||
|   24 --- 31 | ||||
|   24 --- 32 | ||||
|   24 --- 33 | ||||
|   24 --- 34 | ||||
|   24 --- 35 | ||||
|   24 --- 36 | ||||
|   24 --- 37 | ||||
|   24 --- 38 | ||||
|   30 --- 39 | ||||
|   30 --- 78 | ||||
|   30 --- 157 | ||||
|   39 --- 40 | ||||
|   39 --- 41 | ||||
|   39 --- 42 | ||||
|   39 --- 43 | ||||
|   39 --- 44 | ||||
|   39 --- 45 | ||||
|   39 --- 46 | ||||
|   39 --- 47 | ||||
|   39 --- 48 | ||||
|   39 ---- 50 | ||||
|   39 --- 49 | ||||
|   40 --- 51 | ||||
|   40 --- 59 | ||||
|   40 --- 60 | ||||
|   41 --- 52 | ||||
|   41 --- 61 | ||||
|   41 --- 62 | ||||
|   42 --- 53 | ||||
|   42 --- 63 | ||||
|   42 --- 64 | ||||
|   43 --- 54 | ||||
|   43 --- 65 | ||||
|   43 --- 66 | ||||
|   44 --- 55 | ||||
|   44 --- 67 | ||||
|   44 --- 68 | ||||
|   45 --- 56 | ||||
|   45 --- 69 | ||||
|   45 --- 70 | ||||
|   46 --- 57 | ||||
|   46 --- 71 | ||||
|   46 --- 72 | ||||
|   47 --- 58 | ||||
|   47 --- 73 | ||||
|   47 --- 74 | ||||
|   50 --- 51 | ||||
|   50 --- 52 | ||||
|   50 --- 53 | ||||
|   50 --- 54 | ||||
|   50 --- 55 | ||||
|   50 --- 56 | ||||
|   50 --- 57 | ||||
|   50 --- 58 | ||||
|   50 --- 59 | ||||
|   50 --- 60 | ||||
|   50 --- 61 | ||||
|   50 --- 62 | ||||
|   50 --- 63 | ||||
|   50 --- 64 | ||||
|   50 --- 65 | ||||
|   50 --- 66 | ||||
|   50 --- 67 | ||||
|   50 --- 68 | ||||
|   50 --- 69 | ||||
|   50 --- 70 | ||||
|   50 --- 71 | ||||
|   50 --- 72 | ||||
|   50 --- 73 | ||||
|   50 --- 74 | ||||
|   78 --- 79 | ||||
|   78 --- 80 | ||||
|   78 --- 81 | ||||
|   78 --- 82 | ||||
|   78 --- 83 | ||||
|   78 --- 84 | ||||
|   78 --- 85 | ||||
|   78 --- 86 | ||||
|   78 ---- 87 | ||||
|   79 --- 88 | ||||
|   79 --- 97 | ||||
|   79 --- 98 | ||||
|   80 --- 89 | ||||
|   80 --- 99 | ||||
|   80 --- 100 | ||||
|   81 --- 90 | ||||
|   81 --- 101 | ||||
|   81 --- 102 | ||||
|   82 --- 91 | ||||
|   82 --- 103 | ||||
|   82 --- 104 | ||||
|   83 --- 92 | ||||
|   83 --- 105 | ||||
|   83 --- 106 | ||||
|   84 --- 93 | ||||
|   84 --- 107 | ||||
|   84 --- 108 | ||||
|   85 --- 94 | ||||
|   85 --- 109 | ||||
|   85 --- 110 | ||||
|   86 --- 95 | ||||
|   86 --- 111 | ||||
|   86 --- 112 | ||||
|   87 --- 88 | ||||
|   87 --- 89 | ||||
|   87 --- 90 | ||||
|   87 --- 91 | ||||
|   87 --- 92 | ||||
|   87 --- 93 | ||||
|   87 --- 94 | ||||
|   87 --- 95 | ||||
|   87 --- 96 | ||||
|   87 --- 97 | ||||
|   87 --- 98 | ||||
|   87 --- 99 | ||||
|   87 --- 100 | ||||
|   87 --- 101 | ||||
|   87 --- 102 | ||||
|   87 --- 103 | ||||
|   87 --- 104 | ||||
|   87 --- 105 | ||||
|   87 --- 106 | ||||
|   87 --- 107 | ||||
|   87 --- 108 | ||||
|   87 --- 109 | ||||
|   87 --- 110 | ||||
|   87 --- 111 | ||||
|   87 --- 112 | ||||
|   96 --- 113 | ||||
|   96 --- 120 | ||||
|   96 --- 127 | ||||
|   96 --- 130 | ||||
|   96 --- 133 | ||||
|   96 --- 136 | ||||
|   96 --- 139 | ||||
|   113 --- 114 | ||||
|   113 ---- 116 | ||||
|   113 --- 115 | ||||
|   114 --- 117 | ||||
|   114 --- 118 | ||||
|   114 --- 119 | ||||
|   116 --- 117 | ||||
|   116 --- 118 | ||||
|   116 --- 119 | ||||
|   120 --- 121 | ||||
|   120 --- 122 | ||||
|   120 --- 123 | ||||
|   120 --- 124 | ||||
|   120 --- 125 | ||||
|   120 ---- 142 | ||||
|   120 --- 126 | ||||
|   121 --- 143 | ||||
|   121 --- 149 | ||||
|   121 --- 150 | ||||
|   122 --- 144 | ||||
|   122 --- 151 | ||||
|   122 --- 152 | ||||
|   123 --- 145 | ||||
|   123 --- 153 | ||||
|   123 --- 154 | ||||
|   124 --- 146 | ||||
|   124 --- 155 | ||||
|   124 --- 156 | ||||
|   127 --- 128 | ||||
|   127 --- 129 | ||||
|   130 --- 131 | ||||
|   130 --- 132 | ||||
|   133 --- 134 | ||||
|   133 --- 135 | ||||
|   136 --- 137 | ||||
|   136 --- 138 | ||||
|   139 --- 140 | ||||
|   139 --- 141 | ||||
|   142 --- 143 | ||||
|   142 --- 144 | ||||
|   142 --- 145 | ||||
|   142 --- 146 | ||||
|   142 --- 147 | ||||
|   142 --- 148 | ||||
|   142 --- 149 | ||||
|   142 --- 150 | ||||
|   142 --- 151 | ||||
|   142 --- 152 | ||||
|   142 --- 153 | ||||
|   142 --- 154 | ||||
|   142 --- 155 | ||||
|   142 --- 156 | ||||
|   157 --- 158 | ||||
|   157 ---- 160 | ||||
|   157 --- 159 | ||||
|   158 --- 161 | ||||
|   158 --- 163 | ||||
|   158 --- 164 | ||||
|   160 --- 161 | ||||
|   160 --- 162 | ||||
|   160 --- 163 | ||||
|   160 --- 164 | ||||
|   162 --- 165 | ||||
|   165 --- 166 | ||||
|   165 ---- 168 | ||||
|   165 --- 167 | ||||
|   166 --- 169 | ||||
|   166 --- 170 | ||||
|   166 --- 171 | ||||
|   168 --- 169 | ||||
|   168 --- 170 | ||||
|   168 --- 171 | ||||
|   32 <--x 172 | ||||
|   34 <--x 173 | ||||
|   36 <--x 174 | ||||
|   38 <--x 175 | ||||
|   150 <--x 176 | ||||
|   152 <--x 177 | ||||
|   154 <--x 178 | ||||
|   156 <--x 179 | ||||
|   180 --- 181 | ||||
|   181 --- 182 | ||||
|   181 ---- 184 | ||||
|   181 --- 183 | ||||
|   182 --- 185 | ||||
|   182 --- 188 | ||||
|   182 --- 189 | ||||
|   182 --- 201 | ||||
|   184 --- 185 | ||||
|   184 --- 186 | ||||
|   184 --- 187 | ||||
|   184 --- 188 | ||||
|   184 --- 189 | ||||
|   190 --- 191 | ||||
|   191 --- 192 | ||||
|   191 ---- 194 | ||||
|   191 --- 193 | ||||
|   192 --- 195 | ||||
|   192 --- 198 | ||||
|   192 --- 199 | ||||
|   194 --- 195 | ||||
|   194 --- 196 | ||||
|   194 --- 197 | ||||
|   194 --- 198 | ||||
|   194 --- 199 | ||||
|   188 <--x 200 | ||||
|   202 --- 203 | ||||
|   203 --- 204 | ||||
|   203 --- 205 | ||||
|   203 --- 206 | ||||
|   203 --- 207 | ||||
|   203 --- 208 | ||||
|   203 --- 209 | ||||
|   203 --- 210 | ||||
|   203 --- 211 | ||||
|   203 --- 212 | ||||
|   203 --- 213 | ||||
|   203 --- 214 | ||||
|   203 --- 215 | ||||
|   203 --- 216 | ||||
|   203 ---- 218 | ||||
|   203 --- 217 | ||||
|   204 --- 219 | ||||
|   204 x--> 231 | ||||
|   205 --- 220 | ||||
|   205 --- 231 | ||||
|   206 --- 221 | ||||
|   206 --- 232 | ||||
|   207 --- 222 | ||||
|   207 --- 233 | ||||
|   208 --- 223 | ||||
|   208 --- 234 | ||||
|   209 --- 224 | ||||
|   209 --- 235 | ||||
|   210 --- 225 | ||||
|   210 --- 236 | ||||
|   211 --- 226 | ||||
|   211 --- 237 | ||||
|   212 --- 227 | ||||
|   212 --- 238 | ||||
|   213 --- 228 | ||||
|   213 --- 239 | ||||
|   214 --- 229 | ||||
|   214 --- 240 | ||||
|   215 --- 230 | ||||
|   215 --- 241 | ||||
|   218 --- 219 | ||||
|   218 --- 220 | ||||
|   218 --- 221 | ||||
|   218 --- 222 | ||||
|   218 --- 223 | ||||
|   218 --- 224 | ||||
|   218 --- 225 | ||||
|   218 --- 226 | ||||
|   218 --- 227 | ||||
|   218 --- 228 | ||||
|   218 --- 229 | ||||
|   218 --- 230 | ||||
|   218 <--x 204 | ||||
|   218 --- 231 | ||||
|   218 <--x 205 | ||||
|   218 <--x 206 | ||||
|   218 --- 232 | ||||
|   218 <--x 207 | ||||
|   218 --- 233 | ||||
|   218 <--x 208 | ||||
|   218 --- 234 | ||||
|   218 <--x 209 | ||||
|   218 --- 235 | ||||
|   218 <--x 210 | ||||
|   218 --- 236 | ||||
|   218 <--x 211 | ||||
|   218 --- 237 | ||||
|   218 <--x 212 | ||||
|   218 --- 238 | ||||
|   218 <--x 213 | ||||
|   218 --- 239 | ||||
|   218 <--x 214 | ||||
|   218 --- 240 | ||||
|   218 <--x 215 | ||||
|   218 --- 241 | ||||
|   242 --- 243 | ||||
|   243 --- 244 | ||||
|   243 --- 245 | ||||
|   243 --- 246 | ||||
|   243 --- 247 | ||||
|   243 --- 248 | ||||
|   243 ---- 266 | ||||
|   243 --- 249 | ||||
|   244 --- 267 | ||||
|   244 --- 260 | ||||
|   244 --- 273 | ||||
|   245 --- 268 | ||||
|   245 --- 261 | ||||
|   245 --- 274 | ||||
|   246 --- 269 | ||||
|   246 --- 262 | ||||
|   246 --- 275 | ||||
|   247 --- 270 | ||||
|   247 --- 263 | ||||
|   247 --- 276 | ||||
|   250 --- 251 | ||||
|   251 --- 252 | ||||
|   251 --- 253 | ||||
|   251 --- 254 | ||||
|   251 --- 255 | ||||
|   251 --- 256 | ||||
|   251 x---> 266 | ||||
|   251 --- 257 | ||||
|   258 --- 259 | ||||
|   259 x--> 260 | ||||
|   259 x--> 261 | ||||
|   259 x--> 262 | ||||
|   259 x--> 263 | ||||
|   259 --- 264 | ||||
|   259 x---> 266 | ||||
|   259 --- 265 | ||||
|   266 --- 260 | ||||
|   266 --- 261 | ||||
|   266 --- 262 | ||||
|   266 --- 263 | ||||
|   266 --- 267 | ||||
|   266 --- 268 | ||||
|   266 --- 269 | ||||
|   266 --- 270 | ||||
|   266 --- 271 | ||||
|   266 --- 272 | ||||
|   266 --- 273 | ||||
|   266 --- 274 | ||||
|   266 --- 275 | ||||
|   266 --- 276 | ||||
|   30 <--x 277 | ||||
|   30 <--x 278 | ||||
|   96 <--x 279 | ||||
|   96 <--x 280 | ||||
|   30 <--x 281 | ||||
|   162 <--x 282 | ||||
|   180 <--x 283 | ||||
|   190 <--x 284 | ||||
|   242 <--x 285 | ||||
|   250 <--x 286 | ||||
|   258 <--x 287 | ||||
| ``` | ||||
							
								
								
									
										220
									
								
								rust/kcl-lib/tests/kcl_samples/axial-fan/ast.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								rust/kcl-lib/tests/kcl_samples/axial-fan/ast.snap
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,220 @@ | ||||
| --- | ||||
| source: kcl-lib/src/simulation_tests.rs | ||||
| description: Result of parsing axial-fan.kcl | ||||
| --- | ||||
| { | ||||
|   "Ok": { | ||||
|     "body": [ | ||||
|       { | ||||
|         "commentStart": 0, | ||||
|         "end": 0, | ||||
|         "path": { | ||||
|           "type": "Kcl", | ||||
|           "filename": "fan-housing.kcl" | ||||
|         }, | ||||
|         "preComments": [ | ||||
|           "// Import all parts into assembly file" | ||||
|         ], | ||||
|         "selector": { | ||||
|           "type": "None", | ||||
|           "alias": { | ||||
|             "commentStart": 0, | ||||
|             "end": 0, | ||||
|             "name": "fanHousing", | ||||
|             "start": 0, | ||||
|             "type": "Identifier" | ||||
|           } | ||||
|         }, | ||||
|         "start": 0, | ||||
|         "type": "ImportStatement", | ||||
|         "type": "ImportStatement" | ||||
|       }, | ||||
|       { | ||||
|         "commentStart": 0, | ||||
|         "end": 0, | ||||
|         "path": { | ||||
|           "type": "Kcl", | ||||
|           "filename": "motor.kcl" | ||||
|         }, | ||||
|         "selector": { | ||||
|           "type": "None", | ||||
|           "alias": { | ||||
|             "commentStart": 0, | ||||
|             "end": 0, | ||||
|             "name": "motor", | ||||
|             "start": 0, | ||||
|             "type": "Identifier" | ||||
|           } | ||||
|         }, | ||||
|         "start": 0, | ||||
|         "type": "ImportStatement", | ||||
|         "type": "ImportStatement" | ||||
|       }, | ||||
|       { | ||||
|         "commentStart": 0, | ||||
|         "end": 0, | ||||
|         "path": { | ||||
|           "type": "Kcl", | ||||
|           "filename": "fan.kcl" | ||||
|         }, | ||||
|         "selector": { | ||||
|           "type": "None", | ||||
|           "alias": { | ||||
|             "commentStart": 0, | ||||
|             "end": 0, | ||||
|             "name": "fan", | ||||
|             "start": 0, | ||||
|             "type": "Identifier" | ||||
|           } | ||||
|         }, | ||||
|         "start": 0, | ||||
|         "type": "ImportStatement", | ||||
|         "type": "ImportStatement" | ||||
|       }, | ||||
|       { | ||||
|         "commentStart": 0, | ||||
|         "end": 0, | ||||
|         "expression": { | ||||
|           "abs_path": false, | ||||
|           "commentStart": 0, | ||||
|           "end": 0, | ||||
|           "name": { | ||||
|             "commentStart": 0, | ||||
|             "end": 0, | ||||
|             "name": "fanHousing", | ||||
|             "start": 0, | ||||
|             "type": "Identifier" | ||||
|           }, | ||||
|           "path": [], | ||||
|           "start": 0, | ||||
|           "type": "Name", | ||||
|           "type": "Name" | ||||
|         }, | ||||
|         "preComments": [ | ||||
|           "", | ||||
|           "", | ||||
|           "// Produce the model for each imported part" | ||||
|         ], | ||||
|         "start": 0, | ||||
|         "type": "ExpressionStatement", | ||||
|         "type": "ExpressionStatement" | ||||
|       }, | ||||
|       { | ||||
|         "commentStart": 0, | ||||
|         "end": 0, | ||||
|         "expression": { | ||||
|           "abs_path": false, | ||||
|           "commentStart": 0, | ||||
|           "end": 0, | ||||
|           "name": { | ||||
|             "commentStart": 0, | ||||
|             "end": 0, | ||||
|             "name": "motor", | ||||
|             "start": 0, | ||||
|             "type": "Identifier" | ||||
|           }, | ||||
|           "path": [], | ||||
|           "start": 0, | ||||
|           "type": "Name", | ||||
|           "type": "Name" | ||||
|         }, | ||||
|         "start": 0, | ||||
|         "type": "ExpressionStatement", | ||||
|         "type": "ExpressionStatement" | ||||
|       }, | ||||
|       { | ||||
|         "commentStart": 0, | ||||
|         "end": 0, | ||||
|         "expression": { | ||||
|           "abs_path": false, | ||||
|           "commentStart": 0, | ||||
|           "end": 0, | ||||
|           "name": { | ||||
|             "commentStart": 0, | ||||
|             "end": 0, | ||||
|             "name": "fan", | ||||
|             "start": 0, | ||||
|             "type": "Identifier" | ||||
|           }, | ||||
|           "path": [], | ||||
|           "start": 0, | ||||
|           "type": "Name", | ||||
|           "type": "Name" | ||||
|         }, | ||||
|         "start": 0, | ||||
|         "type": "ExpressionStatement", | ||||
|         "type": "ExpressionStatement" | ||||
|       } | ||||
|     ], | ||||
|     "commentStart": 0, | ||||
|     "end": 0, | ||||
|     "innerAttrs": [ | ||||
|       { | ||||
|         "commentStart": 0, | ||||
|         "end": 0, | ||||
|         "name": { | ||||
|           "commentStart": 0, | ||||
|           "end": 0, | ||||
|           "name": "settings", | ||||
|           "start": 0, | ||||
|           "type": "Identifier" | ||||
|         }, | ||||
|         "preComments": [ | ||||
|           "// PC Fan", | ||||
|           "// A small axial fan, used to push or draw airflow over components to remove excess heat", | ||||
|           "", | ||||
|           "", | ||||
|           "// Set units" | ||||
|         ], | ||||
|         "properties": [ | ||||
|           { | ||||
|             "commentStart": 0, | ||||
|             "end": 0, | ||||
|             "key": { | ||||
|               "commentStart": 0, | ||||
|               "end": 0, | ||||
|               "name": "defaultLengthUnit", | ||||
|               "start": 0, | ||||
|               "type": "Identifier" | ||||
|             }, | ||||
|             "start": 0, | ||||
|             "type": "ObjectProperty", | ||||
|             "value": { | ||||
|               "abs_path": false, | ||||
|               "commentStart": 0, | ||||
|               "end": 0, | ||||
|               "name": { | ||||
|                 "commentStart": 0, | ||||
|                 "end": 0, | ||||
|                 "name": "mm", | ||||
|                 "start": 0, | ||||
|                 "type": "Identifier" | ||||
|               }, | ||||
|               "path": [], | ||||
|               "start": 0, | ||||
|               "type": "Name", | ||||
|               "type": "Name" | ||||
|             } | ||||
|           } | ||||
|         ], | ||||
|         "start": 0, | ||||
|         "type": "Annotation" | ||||
|       } | ||||
|     ], | ||||
|     "nonCodeMeta": { | ||||
|       "nonCodeNodes": {}, | ||||
|       "startNodes": [ | ||||
|         { | ||||
|           "commentStart": 0, | ||||
|           "end": 0, | ||||
|           "start": 0, | ||||
|           "type": "NonCodeNode", | ||||
|           "value": { | ||||
|             "type": "newLine" | ||||
|           } | ||||
|         } | ||||
|       ] | ||||
|     }, | ||||
|     "start": 0 | ||||
|   } | ||||
| } | ||||
							
								
								
									
										2098
									
								
								rust/kcl-lib/tests/kcl_samples/axial-fan/ops.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2098
									
								
								rust/kcl-lib/tests/kcl_samples/axial-fan/ops.snap
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										18
									
								
								rust/kcl-lib/tests/kcl_samples/axial-fan/program_memory.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								rust/kcl-lib/tests/kcl_samples/axial-fan/program_memory.snap
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| --- | ||||
| source: kcl-lib/src/simulation_tests.rs | ||||
| description: Variables in memory after executing axial-fan.kcl | ||||
| --- | ||||
| { | ||||
|   "fan": { | ||||
|     "type": "Module", | ||||
|     "value": 7 | ||||
|   }, | ||||
|   "fanHousing": { | ||||
|     "type": "Module", | ||||
|     "value": 5 | ||||
|   }, | ||||
|   "motor": { | ||||
|     "type": "Module", | ||||
|     "value": 6 | ||||
|   } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								rust/kcl-lib/tests/kcl_samples/axial-fan/rendered_model.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								rust/kcl-lib/tests/kcl_samples/axial-fan/rendered_model.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 105 KiB | 
							
								
								
									
										544
									
								
								rust/kcl-lib/tests/kcl_samples/bottle/artifact_commands.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										544
									
								
								rust/kcl-lib/tests/kcl_samples/bottle/artifact_commands.snap
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,544 @@ | ||||
| --- | ||||
| source: kcl-lib/src/simulation_tests.rs | ||||
| description: Artifact commands bottle.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": "set_scene_units", | ||||
|       "unit": "mm" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "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": 1.0, | ||||
|         "z": 0.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": 0.0, | ||||
|         "z": 1.0 | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "start_path" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "move_path_pen", | ||||
|       "path": "[uuid]", | ||||
|       "to": { | ||||
|         "x": -62.5, | ||||
|         "y": 0.0, | ||||
|         "z": 0.0 | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "sketch_mode_disable" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "extend_path", | ||||
|       "path": "[uuid]", | ||||
|       "segment": { | ||||
|         "type": "line", | ||||
|         "end": { | ||||
|           "x": 0.0, | ||||
|           "y": 26.6667, | ||||
|           "z": 0.0 | ||||
|         }, | ||||
|         "relative": true | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "extend_path", | ||||
|       "path": "[uuid]", | ||||
|       "segment": { | ||||
|         "type": "arc_to", | ||||
|         "interior": { | ||||
|           "x": 0.0, | ||||
|           "y": 40.0, | ||||
|           "z": 0.0 | ||||
|         }, | ||||
|         "end": { | ||||
|           "x": 62.5, | ||||
|           "y": 26.6667, | ||||
|           "z": 0.0 | ||||
|         }, | ||||
|         "relative": false | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "extend_path", | ||||
|       "path": "[uuid]", | ||||
|       "segment": { | ||||
|         "type": "line", | ||||
|         "end": { | ||||
|           "x": 62.5, | ||||
|           "y": 0.0, | ||||
|           "z": 0.0 | ||||
|         }, | ||||
|         "relative": false | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "entity_mirror", | ||||
|       "ids": [ | ||||
|         "[uuid]" | ||||
|       ], | ||||
|       "axis": { | ||||
|         "x": 1.0, | ||||
|         "y": 0.0, | ||||
|         "z": 0.0 | ||||
|       }, | ||||
|       "point": { | ||||
|         "x": 0.0, | ||||
|         "y": 0.0, | ||||
|         "z": 0.0 | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "entity_get_all_child_uuids", | ||||
|       "entity_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "close_path", | ||||
|       "path_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "enable_sketch_mode", | ||||
|       "entity_id": "[uuid]", | ||||
|       "ortho": false, | ||||
|       "animated": false, | ||||
|       "adjust_camera": false, | ||||
|       "planar_normal": { | ||||
|         "x": 0.0, | ||||
|         "y": 0.0, | ||||
|         "z": 1.0 | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "extrude", | ||||
|       "target": "[uuid]", | ||||
|       "distance": 202.0, | ||||
|       "faces": null, | ||||
|       "opposite": "None" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "sketch_mode_disable" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "object_bring_to_front", | ||||
|       "object_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_extrusion_face_info", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_opposite_edge", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]", | ||||
|       "face_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_next_adjacent_edge", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]", | ||||
|       "face_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_opposite_edge", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]", | ||||
|       "face_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_next_adjacent_edge", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]", | ||||
|       "face_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_opposite_edge", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]", | ||||
|       "face_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_next_adjacent_edge", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]", | ||||
|       "face_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_opposite_edge", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]", | ||||
|       "face_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_next_adjacent_edge", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]", | ||||
|       "face_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_opposite_edge", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]", | ||||
|       "face_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_next_adjacent_edge", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]", | ||||
|       "face_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "enable_sketch_mode", | ||||
|       "entity_id": "[uuid]", | ||||
|       "ortho": false, | ||||
|       "animated": false, | ||||
|       "adjust_camera": false, | ||||
|       "planar_normal": null | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "start_path" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "move_path_pen", | ||||
|       "path": "[uuid]", | ||||
|       "to": { | ||||
|         "x": 22.5, | ||||
|         "y": 0.0, | ||||
|         "z": 0.0 | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "sketch_mode_disable" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "extend_path", | ||||
|       "path": "[uuid]", | ||||
|       "segment": { | ||||
|         "type": "arc", | ||||
|         "center": { | ||||
|           "x": 0.0, | ||||
|           "y": 0.0 | ||||
|         }, | ||||
|         "radius": 22.5, | ||||
|         "start": { | ||||
|           "unit": "degrees", | ||||
|           "value": 0.0 | ||||
|         }, | ||||
|         "end": { | ||||
|           "unit": "degrees", | ||||
|           "value": 360.0 | ||||
|         }, | ||||
|         "relative": false | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "close_path", | ||||
|       "path_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "enable_sketch_mode", | ||||
|       "entity_id": "[uuid]", | ||||
|       "ortho": false, | ||||
|       "animated": false, | ||||
|       "adjust_camera": false, | ||||
|       "planar_normal": null | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "extrude", | ||||
|       "target": "[uuid]", | ||||
|       "distance": 18.0, | ||||
|       "faces": null, | ||||
|       "opposite": "None" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "sketch_mode_disable" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "object_bring_to_front", | ||||
|       "object_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_extrusion_face_info", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_opposite_edge", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]", | ||||
|       "face_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_get_next_adjacent_edge", | ||||
|       "object_id": "[uuid]", | ||||
|       "edge_id": "[uuid]", | ||||
|       "face_id": "[uuid]" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "solid3d_shell_face", | ||||
|       "object_id": "[uuid]", | ||||
|       "face_ids": [ | ||||
|         "[uuid]" | ||||
|       ], | ||||
|       "shell_thickness": 4.0, | ||||
|       "hollow": false | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "object_set_material_params_pbr", | ||||
|       "object_id": "[uuid]", | ||||
|       "color": { | ||||
|         "r": 0.0, | ||||
|         "g": 0.47058824, | ||||
|         "b": 0.7607843, | ||||
|         "a": 100.0 | ||||
|       }, | ||||
|       "metalness": 0.0, | ||||
|       "roughness": 0.0, | ||||
|       "ambient_occlusion": 0.0 | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "set_scene_units", | ||||
|       "unit": "mm" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "set_scene_units", | ||||
|       "unit": "mm" | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "cmdId": "[uuid]", | ||||
|     "range": [], | ||||
|     "command": { | ||||
|       "type": "set_scene_units", | ||||
|       "unit": "mm" | ||||
|     } | ||||
|   } | ||||
| ] | ||||
| @ -0,0 +1,6 @@ | ||||
| --- | ||||
| source: kcl-lib/src/simulation_tests.rs | ||||
| description: Artifact graph flowchart bottle.kcl | ||||
| extension: md | ||||
| snapshot_kind: binary | ||||
| --- | ||||
| @ -0,0 +1,44 @@ | ||||
| ```mermaid | ||||
| flowchart LR | ||||
|   subgraph path2 [Path] | ||||
|     2["Path<br>[337, 378, 0]"] | ||||
|     3["Segment<br>[384, 415, 0]"] | ||||
|     4["Segment<br>[421, 528, 0]"] | ||||
|     5["Segment<br>[534, 556, 0]"] | ||||
|     6["Segment<br>[586, 593, 0]"] | ||||
|     7[Solid2d] | ||||
|   end | ||||
|   subgraph path10 [Path] | ||||
|     10["Path<br>[750, 800, 0]"] | ||||
|     11["Segment<br>[750, 800, 0]"] | ||||
|     12[Solid2d] | ||||
|   end | ||||
|   1["Plane<br>[314, 331, 0]"] | ||||
|   8["Sweep Extrusion<br>[599, 641, 0]"] | ||||
|   9["Plane<br>[750, 800, 0]"] | ||||
|   13["Sweep Extrusion<br>[806, 833, 0]"] | ||||
|   14[Wall] | ||||
|   15["Cap End"] | ||||
|   16["SweepEdge Opposite"] | ||||
|   17["SweepEdge Adjacent"] | ||||
|   18["StartSketchOnFace<br>[707, 744, 0]"] | ||||
|   1 --- 2 | ||||
|   2 --- 3 | ||||
|   2 --- 4 | ||||
|   2 --- 5 | ||||
|   2 --- 6 | ||||
|   2 ---- 8 | ||||
|   2 --- 7 | ||||
|   9 --- 10 | ||||
|   10 --- 11 | ||||
|   10 ---- 13 | ||||
|   10 --- 12 | ||||
|   11 --- 14 | ||||
|   11 --- 16 | ||||
|   11 --- 17 | ||||
|   13 --- 14 | ||||
|   13 --- 15 | ||||
|   13 --- 16 | ||||
|   13 --- 17 | ||||
|   9 <--x 18 | ||||
| ``` | ||||
							
								
								
									
										1401
									
								
								rust/kcl-lib/tests/kcl_samples/bottle/ast.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1401
									
								
								rust/kcl-lib/tests/kcl_samples/bottle/ast.snap
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										152
									
								
								rust/kcl-lib/tests/kcl_samples/bottle/ops.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								rust/kcl-lib/tests/kcl_samples/bottle/ops.snap
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,152 @@ | ||||
| --- | ||||
| source: kcl-lib/src/simulation_tests.rs | ||||
| description: Operations executed bottle.kcl | ||||
| --- | ||||
| [ | ||||
|   { | ||||
|     "labeledArgs": { | ||||
|       "planeOrSolid": { | ||||
|         "value": { | ||||
|           "type": "Plane", | ||||
|           "artifact_id": "[uuid]" | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|       } | ||||
|     }, | ||||
|     "name": "startSketchOn", | ||||
|     "sourceRange": [], | ||||
|     "type": "StdLibCall", | ||||
|     "unlabeledArg": null | ||||
|   }, | ||||
|   { | ||||
|     "labeledArgs": { | ||||
|       "length": { | ||||
|         "value": { | ||||
|           "type": "Number", | ||||
|           "value": 202.0, | ||||
|           "ty": { | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|       } | ||||
|     }, | ||||
|     "name": "extrude", | ||||
|     "sourceRange": [], | ||||
|     "type": "StdLibCall", | ||||
|     "unlabeledArg": { | ||||
|       "value": { | ||||
|         "type": "Sketch", | ||||
|         "value": { | ||||
|           "artifactId": "[uuid]" | ||||
|         } | ||||
|       }, | ||||
|       "sourceRange": [] | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "labeledArgs": { | ||||
|       "face": { | ||||
|         "value": { | ||||
|           "type": "String", | ||||
|           "value": "end" | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|       } | ||||
|     }, | ||||
|     "name": "startSketchOn", | ||||
|     "sourceRange": [], | ||||
|     "type": "StdLibCall", | ||||
|     "unlabeledArg": { | ||||
|       "value": { | ||||
|         "type": "Solid", | ||||
|         "value": { | ||||
|           "artifactId": "[uuid]" | ||||
|         } | ||||
|       }, | ||||
|       "sourceRange": [] | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "labeledArgs": { | ||||
|       "length": { | ||||
|         "value": { | ||||
|           "type": "Number", | ||||
|           "value": 18.0, | ||||
|           "ty": { | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|       } | ||||
|     }, | ||||
|     "name": "extrude", | ||||
|     "sourceRange": [], | ||||
|     "type": "StdLibCall", | ||||
|     "unlabeledArg": { | ||||
|       "value": { | ||||
|         "type": "Sketch", | ||||
|         "value": { | ||||
|           "artifactId": "[uuid]" | ||||
|         } | ||||
|       }, | ||||
|       "sourceRange": [] | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     "labeledArgs": { | ||||
|       "faces": { | ||||
|         "value": { | ||||
|           "type": "Array", | ||||
|           "value": [ | ||||
|             { | ||||
|               "type": "String", | ||||
|               "value": "end" | ||||
|             } | ||||
|           ] | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|       }, | ||||
|       "thickness": { | ||||
|         "value": { | ||||
|           "type": "Number", | ||||
|           "value": 4.0, | ||||
|           "ty": { | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|       } | ||||
|     }, | ||||
|     "name": "shell", | ||||
|     "sourceRange": [], | ||||
|     "type": "StdLibCall", | ||||
|     "unlabeledArg": { | ||||
|       "value": { | ||||
|         "type": "Solid", | ||||
|         "value": { | ||||
|           "artifactId": "[uuid]" | ||||
|         } | ||||
|       }, | ||||
|       "sourceRange": [] | ||||
|     } | ||||
|   } | ||||
| ] | ||||
							
								
								
									
										817
									
								
								rust/kcl-lib/tests/kcl_samples/bottle/program_memory.snap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										817
									
								
								rust/kcl-lib/tests/kcl_samples/bottle/program_memory.snap
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,817 @@ | ||||
| --- | ||||
| source: kcl-lib/src/simulation_tests.rs | ||||
| description: Variables in memory after executing bottle.kcl | ||||
| --- | ||||
| { | ||||
|   "bottleBody": { | ||||
|     "type": "Solid", | ||||
|     "value": { | ||||
|       "type": "Solid", | ||||
|       "id": "[uuid]", | ||||
|       "artifactId": "[uuid]", | ||||
|       "value": [], | ||||
|       "sketch": { | ||||
|         "type": "Sketch", | ||||
|         "id": "[uuid]", | ||||
|         "paths": [ | ||||
|           { | ||||
|             "__geoMeta": { | ||||
|               "id": "[uuid]", | ||||
|               "sourceRange": [] | ||||
|             }, | ||||
|             "from": [ | ||||
|               -62.5, | ||||
|               0.0 | ||||
|             ], | ||||
|             "tag": null, | ||||
|             "to": [ | ||||
|               -62.5, | ||||
|               26.6667 | ||||
|             ], | ||||
|             "type": "ToPoint", | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           { | ||||
|             "__geoMeta": { | ||||
|               "id": "[uuid]", | ||||
|               "sourceRange": [] | ||||
|             }, | ||||
|             "from": [ | ||||
|               -62.5, | ||||
|               26.6667 | ||||
|             ], | ||||
|             "p1": [ | ||||
|               -62.5, | ||||
|               26.666666666666668 | ||||
|             ], | ||||
|             "p2": [ | ||||
|               0.0, | ||||
|               40.0 | ||||
|             ], | ||||
|             "p3": [ | ||||
|               62.5, | ||||
|               26.666666666666668 | ||||
|             ], | ||||
|             "tag": null, | ||||
|             "to": [ | ||||
|               62.5, | ||||
|               26.6667 | ||||
|             ], | ||||
|             "type": "ArcThreePoint", | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           { | ||||
|             "__geoMeta": { | ||||
|               "id": "[uuid]", | ||||
|               "sourceRange": [] | ||||
|             }, | ||||
|             "from": [ | ||||
|               62.5, | ||||
|               26.6667 | ||||
|             ], | ||||
|             "tag": null, | ||||
|             "to": [ | ||||
|               62.5, | ||||
|               0.0 | ||||
|             ], | ||||
|             "type": "ToPoint", | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           { | ||||
|             "__geoMeta": { | ||||
|               "id": "[uuid]", | ||||
|               "sourceRange": [] | ||||
|             }, | ||||
|             "from": [ | ||||
|               62.5, | ||||
|               0.0 | ||||
|             ], | ||||
|             "tag": null, | ||||
|             "to": [ | ||||
|               -62.5, | ||||
|               0.0 | ||||
|             ], | ||||
|             "type": "ToPoint", | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           } | ||||
|         ], | ||||
|         "on": { | ||||
|           "type": "plane", | ||||
|           "id": "[uuid]", | ||||
|           "artifactId": "[uuid]", | ||||
|           "value": "XY", | ||||
|           "origin": { | ||||
|             "x": 0.0, | ||||
|             "y": 0.0, | ||||
|             "z": 0.0, | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           "xAxis": { | ||||
|             "x": 1.0, | ||||
|             "y": 0.0, | ||||
|             "z": 0.0, | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           "yAxis": { | ||||
|             "x": 0.0, | ||||
|             "y": 1.0, | ||||
|             "z": 0.0, | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           "zAxis": { | ||||
|             "x": 0.0, | ||||
|             "y": 0.0, | ||||
|             "z": 1.0, | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           "units": { | ||||
|             "type": "Mm" | ||||
|           } | ||||
|         }, | ||||
|         "start": { | ||||
|           "from": [ | ||||
|             -62.5, | ||||
|             0.0 | ||||
|           ], | ||||
|           "to": [ | ||||
|             -62.5, | ||||
|             0.0 | ||||
|           ], | ||||
|           "units": { | ||||
|             "type": "Mm" | ||||
|           }, | ||||
|           "tag": null, | ||||
|           "__geoMeta": { | ||||
|             "id": "[uuid]", | ||||
|             "sourceRange": [] | ||||
|           } | ||||
|         }, | ||||
|         "artifactId": "[uuid]", | ||||
|         "originalId": "[uuid]", | ||||
|         "units": { | ||||
|           "type": "Mm" | ||||
|         } | ||||
|       }, | ||||
|       "height": 202.0, | ||||
|       "startCapId": "[uuid]", | ||||
|       "endCapId": "[uuid]", | ||||
|       "units": { | ||||
|         "type": "Mm" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "bottleHeight": { | ||||
|     "type": "Number", | ||||
|     "value": 220.0, | ||||
|     "ty": { | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "bottleLength": { | ||||
|     "type": "Number", | ||||
|     "value": 125.0, | ||||
|     "ty": { | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "bottleNeck": { | ||||
|     "type": "Solid", | ||||
|     "value": { | ||||
|       "type": "Solid", | ||||
|       "id": "[uuid]", | ||||
|       "artifactId": "[uuid]", | ||||
|       "value": [ | ||||
|         { | ||||
|           "faceId": "[uuid]", | ||||
|           "id": "[uuid]", | ||||
|           "sourceRange": [], | ||||
|           "tag": null, | ||||
|           "type": "extrudeArc" | ||||
|         } | ||||
|       ], | ||||
|       "sketch": { | ||||
|         "type": "Sketch", | ||||
|         "id": "[uuid]", | ||||
|         "paths": [ | ||||
|           { | ||||
|             "__geoMeta": { | ||||
|               "id": "[uuid]", | ||||
|               "sourceRange": [] | ||||
|             }, | ||||
|             "ccw": true, | ||||
|             "center": [ | ||||
|               0.0, | ||||
|               0.0 | ||||
|             ], | ||||
|             "from": [ | ||||
|               22.5, | ||||
|               0.0 | ||||
|             ], | ||||
|             "radius": 22.5, | ||||
|             "tag": null, | ||||
|             "to": [ | ||||
|               22.5, | ||||
|               0.0 | ||||
|             ], | ||||
|             "type": "Circle", | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           } | ||||
|         ], | ||||
|         "on": { | ||||
|           "type": "face", | ||||
|           "id": "[uuid]", | ||||
|           "artifactId": "[uuid]", | ||||
|           "value": "end", | ||||
|           "xAxis": { | ||||
|             "x": 1.0, | ||||
|             "y": 0.0, | ||||
|             "z": 0.0, | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           "yAxis": { | ||||
|             "x": 0.0, | ||||
|             "y": 1.0, | ||||
|             "z": 0.0, | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           "zAxis": { | ||||
|             "x": 0.0, | ||||
|             "y": 0.0, | ||||
|             "z": 1.0, | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           "solid": { | ||||
|             "type": "Solid", | ||||
|             "id": "[uuid]", | ||||
|             "artifactId": "[uuid]", | ||||
|             "value": [], | ||||
|             "sketch": { | ||||
|               "type": "Sketch", | ||||
|               "id": "[uuid]", | ||||
|               "paths": [ | ||||
|                 { | ||||
|                   "__geoMeta": { | ||||
|                     "id": "[uuid]", | ||||
|                     "sourceRange": [] | ||||
|                   }, | ||||
|                   "from": [ | ||||
|                     -62.5, | ||||
|                     0.0 | ||||
|                   ], | ||||
|                   "tag": null, | ||||
|                   "to": [ | ||||
|                     -62.5, | ||||
|                     26.6667 | ||||
|                   ], | ||||
|                   "type": "ToPoint", | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 { | ||||
|                   "__geoMeta": { | ||||
|                     "id": "[uuid]", | ||||
|                     "sourceRange": [] | ||||
|                   }, | ||||
|                   "from": [ | ||||
|                     -62.5, | ||||
|                     26.6667 | ||||
|                   ], | ||||
|                   "p1": [ | ||||
|                     -62.5, | ||||
|                     26.666666666666668 | ||||
|                   ], | ||||
|                   "p2": [ | ||||
|                     0.0, | ||||
|                     40.0 | ||||
|                   ], | ||||
|                   "p3": [ | ||||
|                     62.5, | ||||
|                     26.666666666666668 | ||||
|                   ], | ||||
|                   "tag": null, | ||||
|                   "to": [ | ||||
|                     62.5, | ||||
|                     26.6667 | ||||
|                   ], | ||||
|                   "type": "ArcThreePoint", | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 { | ||||
|                   "__geoMeta": { | ||||
|                     "id": "[uuid]", | ||||
|                     "sourceRange": [] | ||||
|                   }, | ||||
|                   "from": [ | ||||
|                     62.5, | ||||
|                     26.6667 | ||||
|                   ], | ||||
|                   "tag": null, | ||||
|                   "to": [ | ||||
|                     62.5, | ||||
|                     0.0 | ||||
|                   ], | ||||
|                   "type": "ToPoint", | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 { | ||||
|                   "__geoMeta": { | ||||
|                     "id": "[uuid]", | ||||
|                     "sourceRange": [] | ||||
|                   }, | ||||
|                   "from": [ | ||||
|                     62.5, | ||||
|                     0.0 | ||||
|                   ], | ||||
|                   "tag": null, | ||||
|                   "to": [ | ||||
|                     -62.5, | ||||
|                     0.0 | ||||
|                   ], | ||||
|                   "type": "ToPoint", | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 } | ||||
|               ], | ||||
|               "on": { | ||||
|                 "type": "plane", | ||||
|                 "id": "[uuid]", | ||||
|                 "artifactId": "[uuid]", | ||||
|                 "value": "XY", | ||||
|                 "origin": { | ||||
|                   "x": 0.0, | ||||
|                   "y": 0.0, | ||||
|                   "z": 0.0, | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 "xAxis": { | ||||
|                   "x": 1.0, | ||||
|                   "y": 0.0, | ||||
|                   "z": 0.0, | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 "yAxis": { | ||||
|                   "x": 0.0, | ||||
|                   "y": 1.0, | ||||
|                   "z": 0.0, | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 "zAxis": { | ||||
|                   "x": 0.0, | ||||
|                   "y": 0.0, | ||||
|                   "z": 1.0, | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 "units": { | ||||
|                   "type": "Mm" | ||||
|                 } | ||||
|               }, | ||||
|               "start": { | ||||
|                 "from": [ | ||||
|                   -62.5, | ||||
|                   0.0 | ||||
|                 ], | ||||
|                 "to": [ | ||||
|                   -62.5, | ||||
|                   0.0 | ||||
|                 ], | ||||
|                 "units": { | ||||
|                   "type": "Mm" | ||||
|                 }, | ||||
|                 "tag": null, | ||||
|                 "__geoMeta": { | ||||
|                   "id": "[uuid]", | ||||
|                   "sourceRange": [] | ||||
|                 } | ||||
|               }, | ||||
|               "artifactId": "[uuid]", | ||||
|               "originalId": "[uuid]", | ||||
|               "units": { | ||||
|                 "type": "Mm" | ||||
|               } | ||||
|             }, | ||||
|             "height": 202.0, | ||||
|             "startCapId": "[uuid]", | ||||
|             "endCapId": "[uuid]", | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           "units": { | ||||
|             "type": "Mm" | ||||
|           } | ||||
|         }, | ||||
|         "start": { | ||||
|           "from": [ | ||||
|             22.5, | ||||
|             0.0 | ||||
|           ], | ||||
|           "to": [ | ||||
|             22.5, | ||||
|             0.0 | ||||
|           ], | ||||
|           "units": { | ||||
|             "type": "Mm" | ||||
|           }, | ||||
|           "tag": null, | ||||
|           "__geoMeta": { | ||||
|             "id": "[uuid]", | ||||
|             "sourceRange": [] | ||||
|           } | ||||
|         }, | ||||
|         "artifactId": "[uuid]", | ||||
|         "originalId": "[uuid]", | ||||
|         "units": { | ||||
|           "type": "Mm" | ||||
|         } | ||||
|       }, | ||||
|       "height": 18.0, | ||||
|       "startCapId": null, | ||||
|       "endCapId": "[uuid]", | ||||
|       "units": { | ||||
|         "type": "Mm" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "bottleShell": { | ||||
|     "type": "Solid", | ||||
|     "value": { | ||||
|       "type": "Solid", | ||||
|       "id": "[uuid]", | ||||
|       "artifactId": "[uuid]", | ||||
|       "value": [ | ||||
|         { | ||||
|           "faceId": "[uuid]", | ||||
|           "id": "[uuid]", | ||||
|           "sourceRange": [], | ||||
|           "tag": null, | ||||
|           "type": "extrudeArc" | ||||
|         } | ||||
|       ], | ||||
|       "sketch": { | ||||
|         "type": "Sketch", | ||||
|         "id": "[uuid]", | ||||
|         "paths": [ | ||||
|           { | ||||
|             "__geoMeta": { | ||||
|               "id": "[uuid]", | ||||
|               "sourceRange": [] | ||||
|             }, | ||||
|             "ccw": true, | ||||
|             "center": [ | ||||
|               0.0, | ||||
|               0.0 | ||||
|             ], | ||||
|             "from": [ | ||||
|               22.5, | ||||
|               0.0 | ||||
|             ], | ||||
|             "radius": 22.5, | ||||
|             "tag": null, | ||||
|             "to": [ | ||||
|               22.5, | ||||
|               0.0 | ||||
|             ], | ||||
|             "type": "Circle", | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           } | ||||
|         ], | ||||
|         "on": { | ||||
|           "type": "face", | ||||
|           "id": "[uuid]", | ||||
|           "artifactId": "[uuid]", | ||||
|           "value": "end", | ||||
|           "xAxis": { | ||||
|             "x": 1.0, | ||||
|             "y": 0.0, | ||||
|             "z": 0.0, | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           "yAxis": { | ||||
|             "x": 0.0, | ||||
|             "y": 1.0, | ||||
|             "z": 0.0, | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           "zAxis": { | ||||
|             "x": 0.0, | ||||
|             "y": 0.0, | ||||
|             "z": 1.0, | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           "solid": { | ||||
|             "type": "Solid", | ||||
|             "id": "[uuid]", | ||||
|             "artifactId": "[uuid]", | ||||
|             "value": [], | ||||
|             "sketch": { | ||||
|               "type": "Sketch", | ||||
|               "id": "[uuid]", | ||||
|               "paths": [ | ||||
|                 { | ||||
|                   "__geoMeta": { | ||||
|                     "id": "[uuid]", | ||||
|                     "sourceRange": [] | ||||
|                   }, | ||||
|                   "from": [ | ||||
|                     -62.5, | ||||
|                     0.0 | ||||
|                   ], | ||||
|                   "tag": null, | ||||
|                   "to": [ | ||||
|                     -62.5, | ||||
|                     26.6667 | ||||
|                   ], | ||||
|                   "type": "ToPoint", | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 { | ||||
|                   "__geoMeta": { | ||||
|                     "id": "[uuid]", | ||||
|                     "sourceRange": [] | ||||
|                   }, | ||||
|                   "from": [ | ||||
|                     -62.5, | ||||
|                     26.6667 | ||||
|                   ], | ||||
|                   "p1": [ | ||||
|                     -62.5, | ||||
|                     26.666666666666668 | ||||
|                   ], | ||||
|                   "p2": [ | ||||
|                     0.0, | ||||
|                     40.0 | ||||
|                   ], | ||||
|                   "p3": [ | ||||
|                     62.5, | ||||
|                     26.666666666666668 | ||||
|                   ], | ||||
|                   "tag": null, | ||||
|                   "to": [ | ||||
|                     62.5, | ||||
|                     26.6667 | ||||
|                   ], | ||||
|                   "type": "ArcThreePoint", | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 { | ||||
|                   "__geoMeta": { | ||||
|                     "id": "[uuid]", | ||||
|                     "sourceRange": [] | ||||
|                   }, | ||||
|                   "from": [ | ||||
|                     62.5, | ||||
|                     26.6667 | ||||
|                   ], | ||||
|                   "tag": null, | ||||
|                   "to": [ | ||||
|                     62.5, | ||||
|                     0.0 | ||||
|                   ], | ||||
|                   "type": "ToPoint", | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 { | ||||
|                   "__geoMeta": { | ||||
|                     "id": "[uuid]", | ||||
|                     "sourceRange": [] | ||||
|                   }, | ||||
|                   "from": [ | ||||
|                     62.5, | ||||
|                     0.0 | ||||
|                   ], | ||||
|                   "tag": null, | ||||
|                   "to": [ | ||||
|                     -62.5, | ||||
|                     0.0 | ||||
|                   ], | ||||
|                   "type": "ToPoint", | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 } | ||||
|               ], | ||||
|               "on": { | ||||
|                 "type": "plane", | ||||
|                 "id": "[uuid]", | ||||
|                 "artifactId": "[uuid]", | ||||
|                 "value": "XY", | ||||
|                 "origin": { | ||||
|                   "x": 0.0, | ||||
|                   "y": 0.0, | ||||
|                   "z": 0.0, | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 "xAxis": { | ||||
|                   "x": 1.0, | ||||
|                   "y": 0.0, | ||||
|                   "z": 0.0, | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 "yAxis": { | ||||
|                   "x": 0.0, | ||||
|                   "y": 1.0, | ||||
|                   "z": 0.0, | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 "zAxis": { | ||||
|                   "x": 0.0, | ||||
|                   "y": 0.0, | ||||
|                   "z": 1.0, | ||||
|                   "units": { | ||||
|                     "type": "Mm" | ||||
|                   } | ||||
|                 }, | ||||
|                 "units": { | ||||
|                   "type": "Mm" | ||||
|                 } | ||||
|               }, | ||||
|               "start": { | ||||
|                 "from": [ | ||||
|                   -62.5, | ||||
|                   0.0 | ||||
|                 ], | ||||
|                 "to": [ | ||||
|                   -62.5, | ||||
|                   0.0 | ||||
|                 ], | ||||
|                 "units": { | ||||
|                   "type": "Mm" | ||||
|                 }, | ||||
|                 "tag": null, | ||||
|                 "__geoMeta": { | ||||
|                   "id": "[uuid]", | ||||
|                   "sourceRange": [] | ||||
|                 } | ||||
|               }, | ||||
|               "artifactId": "[uuid]", | ||||
|               "originalId": "[uuid]", | ||||
|               "units": { | ||||
|                 "type": "Mm" | ||||
|               } | ||||
|             }, | ||||
|             "height": 202.0, | ||||
|             "startCapId": "[uuid]", | ||||
|             "endCapId": "[uuid]", | ||||
|             "units": { | ||||
|               "type": "Mm" | ||||
|             } | ||||
|           }, | ||||
|           "units": { | ||||
|             "type": "Mm" | ||||
|           } | ||||
|         }, | ||||
|         "start": { | ||||
|           "from": [ | ||||
|             22.5, | ||||
|             0.0 | ||||
|           ], | ||||
|           "to": [ | ||||
|             22.5, | ||||
|             0.0 | ||||
|           ], | ||||
|           "units": { | ||||
|             "type": "Mm" | ||||
|           }, | ||||
|           "tag": null, | ||||
|           "__geoMeta": { | ||||
|             "id": "[uuid]", | ||||
|             "sourceRange": [] | ||||
|           } | ||||
|         }, | ||||
|         "artifactId": "[uuid]", | ||||
|         "originalId": "[uuid]", | ||||
|         "units": { | ||||
|           "type": "Mm" | ||||
|         } | ||||
|       }, | ||||
|       "height": 18.0, | ||||
|       "startCapId": null, | ||||
|       "endCapId": "[uuid]", | ||||
|       "units": { | ||||
|         "type": "Mm" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "bottleWidth": { | ||||
|     "type": "Number", | ||||
|     "value": 80.0, | ||||
|     "ty": { | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "neckDepth": { | ||||
|     "type": "Number", | ||||
|     "value": 18.0, | ||||
|     "ty": { | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "neckDiameter": { | ||||
|     "type": "Number", | ||||
|     "value": 45.0, | ||||
|     "ty": { | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "wallThickness": { | ||||
|     "type": "Number", | ||||
|     "value": 4.0, | ||||
|     "ty": { | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								rust/kcl-lib/tests/kcl_samples/bottle/rendered_model.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								rust/kcl-lib/tests/kcl_samples/bottle/rendered_model.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 70 KiB | 
							
								
								
									
										
											BIN
										
									
								
								rust/kcl-lib/tests/outputs/serial_test_example_appearance9.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								rust/kcl-lib/tests/outputs/serial_test_example_appearance9.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 74 KiB | 
| @ -23,6 +23,7 @@ pub struct EngineConnection { | ||||
|     batch: Arc<RwLock<Vec<(WebSocketRequest, kcl_lib::SourceRange)>>>, | ||||
|     batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, kcl_lib::SourceRange)>>>, | ||||
|     core_test: Arc<RwLock<String>>, | ||||
|     ids_of_async_commands: Arc<RwLock<IndexMap<Uuid, kcl_lib::SourceRange>>>, | ||||
|     /// The default planes for the scene. | ||||
|     default_planes: Arc<RwLock<Option<DefaultPlanes>>>, | ||||
|     stats: EngineStats, | ||||
| @ -37,6 +38,7 @@ impl EngineConnection { | ||||
|             batch_end: Arc::new(RwLock::new(IndexMap::new())), | ||||
|             core_test: result, | ||||
|             default_planes: Default::default(), | ||||
|             ids_of_async_commands: Arc::new(RwLock::new(IndexMap::new())), | ||||
|             stats: Default::default(), | ||||
|         }) | ||||
|     } | ||||
| @ -379,6 +381,10 @@ impl kcl_lib::EngineManager for EngineConnection { | ||||
|         Arc::new(RwLock::new(Vec::new())) | ||||
|     } | ||||
|  | ||||
|     fn ids_of_async_commands(&self) -> Arc<RwLock<IndexMap<Uuid, kcl_lib::SourceRange>>> { | ||||
|         self.ids_of_async_commands.clone() | ||||
|     } | ||||
|  | ||||
|     fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> { | ||||
|         self.default_planes.clone() | ||||
|     } | ||||
| @ -391,6 +397,25 @@ impl kcl_lib::EngineManager for EngineConnection { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     async fn inner_fire_modeling_cmd( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
|         source_range: kcl_lib::SourceRange, | ||||
|         cmd: WebSocketRequest, | ||||
|         id_to_source_range: HashMap<Uuid, kcl_lib::SourceRange>, | ||||
|     ) -> Result<(), KclError> { | ||||
|         // Pop off the id we care about. | ||||
|         self.ids_of_async_commands.write().await.swap_remove(&id); | ||||
|  | ||||
|         // Add the response to our responses. | ||||
|         let response = self | ||||
|             .inner_send_modeling_cmd(id, source_range, cmd, id_to_source_range) | ||||
|             .await?; | ||||
|         self.responses().write().await.insert(id, response); | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     async fn inner_send_modeling_cmd( | ||||
|         &self, | ||||
|         id: uuid::Uuid, | ||||
|  | ||||
| @ -9,6 +9,7 @@ use wasm_bindgen::prelude::*; | ||||
| #[wasm_bindgen] | ||||
| pub struct Context { | ||||
|     engine: Arc<Box<dyn EngineManager>>, | ||||
|     response_context: Arc<kcl_lib::wasm_engine::ResponseContext>, | ||||
|     fs: Arc<FileManager>, | ||||
|     mock_engine: Arc<Box<dyn EngineManager>>, | ||||
| } | ||||
| @ -22,9 +23,10 @@ impl Context { | ||||
|     ) -> Result<Self, JsValue> { | ||||
|         console_error_panic_hook::set_once(); | ||||
|  | ||||
|         let response_context = Arc::new(kcl_lib::wasm_engine::ResponseContext::new()); | ||||
|         Ok(Self { | ||||
|             engine: Arc::new(Box::new( | ||||
|                 kcl_lib::wasm_engine::EngineConnection::new(engine_manager) | ||||
|                 kcl_lib::wasm_engine::EngineConnection::new(engine_manager, response_context.clone()) | ||||
|                     .await | ||||
|                     .map_err(|e| format!("{:?}", e))?, | ||||
|             )), | ||||
| @ -34,6 +36,7 @@ impl Context { | ||||
|                     .await | ||||
|                     .map_err(|e| format!("{:?}", e))?, | ||||
|             )), | ||||
|             response_context, | ||||
|         }) | ||||
|     } | ||||
|  | ||||
| @ -100,6 +103,12 @@ impl Context { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Send a response to kcl lib's engine. | ||||
|     #[wasm_bindgen(js_name = sendResponse)] | ||||
|     pub async fn send_response(&self, data: js_sys::Uint8Array) -> Result<(), JsValue> { | ||||
|         self.response_context.send_response(data).await | ||||
|     } | ||||
|  | ||||
|     /// Execute a program in mock mode. | ||||
|     #[wasm_bindgen(js_name = executeMock)] | ||||
|     pub async fn execute_mock( | ||||
|  | ||||
| @ -127,7 +127,7 @@ export const CreateNewVariable = ({ | ||||
|           autoFocus={true} | ||||
|           autoCapitalize="off" | ||||
|           autoCorrect="off" | ||||
|           className={`font-mono flex-1 sm:text-sm px-2 py-1 rounded-sm bg-chalkboard-10 dark:bg-chalkboard-90 text-chalkboard-90 dark:text-chalkboard-10 ${ | ||||
|           className={`flex-1 sm:text-sm px-2 py-1 rounded-sm bg-chalkboard-10 dark:bg-chalkboard-90 text-chalkboard-90 dark:text-chalkboard-10 ${ | ||||
|             !shouldCreateVariable ? 'opacity-50' : '' | ||||
|           }`} | ||||
|           value={newVariableName} | ||||
|  | ||||
| @ -628,8 +628,8 @@ const CustomIconMap = { | ||||
|       xmlns="http://www.w3.org/2000/svg" | ||||
|     > | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         fillRule="evenodd" | ||||
|         clipRule="evenodd" | ||||
|         d="M4 3H4.5H11H11.2071L11.3536 3.14645L15.8536 7.64646L16 7.7929V8.00001V11.3773C15.6992 11.1362 15.3628 10.9376 15 10.7908V8.50001H11H10.5V8.00001V4H5V16H9.79076C9.93763 16.3628 10.1362 16.6992 10.3773 17H4.5H4V16.5V3.5V3ZM11.5 4.70711L14.2929 7.50001H11.5V4.70711ZM13.8123 17.3904L16.3123 15.3904L15.6877 14.6096L14 15.9597V12H13V15.9597L11.3123 14.6096L10.6877 15.3904L13.1877 17.3904L13.5 17.6403L13.8123 17.3904Z" | ||||
|         fill="currentColor" | ||||
|       /> | ||||
|  | ||||
| @ -18,7 +18,7 @@ | ||||
| .header { | ||||
|   @apply z-10 relative rounded-tr; | ||||
|   @apply flex h-[41px] items-center justify-between gap-2 px-2; | ||||
|   @apply font-mono text-xs font-bold select-none text-chalkboard-90; | ||||
|   @apply text-xs select-none text-chalkboard-90; | ||||
|   @apply bg-chalkboard-10 border-b border-chalkboard-30; | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| .button { | ||||
|   @apply flex justify-between items-center gap-2 px-2 py-1 text-left border-none rounded-sm; | ||||
|   @apply font-mono !no-underline text-xs font-bold select-none text-chalkboard-90; | ||||
|   @apply !no-underline text-xs select-none text-chalkboard-90; | ||||
|   @apply ui-active:bg-primary/10 ui-active:text-primary ui-active:text-inherit; | ||||
|   @apply transition-colors ease-out; | ||||
|   @apply m-0; | ||||
|  | ||||
| @ -1617,6 +1617,12 @@ export class EngineCommandManager extends EventTarget { | ||||
|           return | ||||
|         } | ||||
|  | ||||
|         // In either case we want to send the response back over the wire to | ||||
|         // the rust side. | ||||
|         this.rustContext?.sendResponse(message).catch((err) => { | ||||
|           console.error('Error sending response to rust', err) | ||||
|         }) | ||||
|  | ||||
|         const pending = this.pendingCommands[message.request_id || ''] | ||||
|  | ||||
|         if (pending && !message.success) { | ||||
| @ -1931,6 +1937,46 @@ export class EngineCommandManager extends EventTarget { | ||||
|         return e | ||||
|       }) | ||||
|   } | ||||
|   /** | ||||
|    * A wrapper around the sendCommand where all inputs are JSON strings | ||||
|    * | ||||
|    * This one does not wait for a response. | ||||
|    */ | ||||
|   fireModelingCommandFromWasm( | ||||
|     id: string, | ||||
|     rangeStr: string, | ||||
|     commandStr: string, | ||||
|     idToRangeStr: string | ||||
|   ): void | Error { | ||||
|     if (this.engineConnection === undefined) | ||||
|       return new Error('engineConnection is undefined') | ||||
|     if ( | ||||
|       !this.engineConnection?.isReady() && | ||||
|       !this.engineConnection.isUsingConnectionLite | ||||
|     ) | ||||
|       return new Error('engineConnection is not ready') | ||||
|     if (id === undefined) return new Error('id is undefined') | ||||
|     if (rangeStr === undefined) return new Error('rangeStr is undefined') | ||||
|     if (commandStr === undefined) return new Error('commandStr is undefined') | ||||
|     const range: SourceRange = JSON.parse(rangeStr) | ||||
|     const command: EngineCommand = JSON.parse(commandStr) | ||||
|     const idToRangeMap: { [key: string]: SourceRange } = | ||||
|       JSON.parse(idToRangeStr) | ||||
|  | ||||
|     // Current executeAst is stale, going to interrupt, a new executeAst will trigger | ||||
|     // Used in conjunction with rejectAllModelingCommands | ||||
|     if (this?.kclManager?.executeIsStale) { | ||||
|       return new Error(EXECUTE_AST_INTERRUPT_ERROR_MESSAGE) | ||||
|     } | ||||
|  | ||||
|     // We purposely don't wait for a response here | ||||
|     // eslint-disable-next-line @typescript-eslint/no-floating-promises | ||||
|     this.sendCommand(id, { | ||||
|       command, | ||||
|       range, | ||||
|       idToRangeMap, | ||||
|     }) | ||||
|   } | ||||
|   /** | ||||
|    * A wrapper around the sendCommand where all inputs are JSON strings | ||||
|    */ | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| import toast from 'react-hot-toast' | ||||
|  | ||||
| import { BSON } from 'bson' | ||||
| import type { Configuration } from '@rust/kcl-lib/bindings/Configuration' | ||||
| import type { DefaultPlanes } from '@rust/kcl-lib/bindings/DefaultPlanes' | ||||
| import type { KclError as RustKclError } from '@rust/kcl-lib/bindings/KclError' | ||||
| @ -24,6 +25,7 @@ import { err, reportRejection } from '@src/lib/trap' | ||||
| import type { DeepPartial } from '@src/lib/types' | ||||
| import type { ModuleType } from '@src/lib/wasm_lib_wrapper' | ||||
| import { getModule } from '@src/lib/wasm_lib_wrapper' | ||||
| import type { Models } from '@kittycad/lib/dist/types/src' | ||||
|  | ||||
| export default class RustContext { | ||||
|   private wasmInitFailed: boolean = true | ||||
| @ -58,6 +60,7 @@ export default class RustContext { | ||||
|   // Create a new context instance | ||||
|   async create(): Promise<Context> { | ||||
|     this.rustInstance = getModule() | ||||
|  | ||||
|     // We need this await here, DO NOT REMOVE it even if your editor says it's | ||||
|     // unnecessary. The constructor of the module is async and it will not | ||||
|     // resolve if you don't await it. | ||||
| @ -203,6 +206,21 @@ export default class RustContext { | ||||
|     return this.defaultPlanes[key] | ||||
|   } | ||||
|  | ||||
|   // Send a response back to the rust side, that we got back from the engine. | ||||
|   async sendResponse( | ||||
|     response: Models['WebSocketResponse_type'] | ||||
|   ): Promise<void> { | ||||
|     const instance = await this._checkInstance() | ||||
|  | ||||
|     try { | ||||
|       const serialized = BSON.serialize(response) | ||||
|       await instance.sendResponse(serialized) | ||||
|     } catch (e: any) { | ||||
|       const err = errFromErrWithOutputs(e) | ||||
|       return Promise.reject(err) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Helper to check if context instance exists | ||||
|   private async _checkInstance(): Promise<Context> { | ||||
|     if (!this.ctxInstance) { | ||||
|  | ||||
		Reference in New Issue
	
	Block a user