Compare commits
11 Commits
v0.51.0
...
nrc-std-ax
Author | SHA1 | Date | |
---|---|---|---|
87dfda28a9 | |||
42f44e11f5 | |||
16ad7ff77a | |||
71b9e40bd9 | |||
4f35197a96 | |||
40b0cf5fd3 | |||
355e6acf0d | |||
4ff38e7f44 | |||
1dcd3b84b7 | |||
2957216bd3 | |||
11160f0b40 |
@ -1,5 +1,6 @@
|
|||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
DEV=true
|
DEV=true
|
||||||
|
|
||||||
VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands
|
VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands
|
||||||
VITE_KC_API_BASE_URL=https://api.dev.zoo.dev
|
VITE_KC_API_BASE_URL=https://api.dev.zoo.dev
|
||||||
VITE_KC_SITE_BASE_URL=https://dev.zoo.dev
|
VITE_KC_SITE_BASE_URL=https://dev.zoo.dev
|
||||||
@ -8,3 +9,5 @@ VITE_KC_SKIP_AUTH=false
|
|||||||
VITE_KC_CONNECTION_TIMEOUT_MS=5000
|
VITE_KC_CONNECTION_TIMEOUT_MS=5000
|
||||||
# ONLY add your token in .env.development.local if you want to skip auth, otherwise this token takes precedence!
|
# ONLY add your token in .env.development.local if you want to skip auth, otherwise this token takes precedence!
|
||||||
#VITE_KC_DEV_TOKEN="your token from dev.zoo.dev should go in .env.development.local"
|
#VITE_KC_DEV_TOKEN="your token from dev.zoo.dev should go in .env.development.local"
|
||||||
|
|
||||||
|
FAIL_ON_CONSOLE_ERRORS=true
|
||||||
|
10
.envrc
@ -1,3 +1,13 @@
|
|||||||
|
# Load optional shared environment variables
|
||||||
source_up_if_exists
|
source_up_if_exists
|
||||||
|
|
||||||
|
# Load default development environment variables
|
||||||
|
dotenv .env.development
|
||||||
|
|
||||||
|
# Load optional environment variables overrides
|
||||||
|
dotenv_if_exists .env.development.local
|
||||||
|
|
||||||
|
# Load optional testing environment variables
|
||||||
|
dotenv_if_exists e2e/playwright/playwright-secrets.env
|
||||||
|
|
||||||
use flake .
|
use flake .
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
"plugin:react-hooks/recommended"
|
"plugin:react-hooks/recommended"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"@typescript-eslint/no-empty-object-type": "error",
|
||||||
"@typescript-eslint/no-floating-promises": "error",
|
"@typescript-eslint/no-floating-promises": "error",
|
||||||
"@typescript-eslint/no-misused-promises": "error",
|
"@typescript-eslint/no-misused-promises": "error",
|
||||||
"@typescript-eslint/no-unused-vars": ["error", {
|
"@typescript-eslint/no-unused-vars": ["error", {
|
||||||
|
2
.github/workflows/update-e2e-branch.yml
vendored
@ -38,7 +38,7 @@ jobs:
|
|||||||
# Get a new SHA to prevent overwriting the commit status on main
|
# Get a new SHA to prevent overwriting the commit status on main
|
||||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
git config --local user.name "github-actions[bot]"
|
git config --local user.name "github-actions[bot]"
|
||||||
git commit --amend --message="[all-e2e] $(git log --max-count=1 --pretty=%B)"
|
git commit --allow-empty --message="[all-e2e] $(git log --max-count=1 --pretty=%B)"
|
||||||
|
|
||||||
# Overwrite the branch
|
# Overwrite the branch
|
||||||
git remote set-url origin https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/${{ github.repository }}.git
|
git remote set-url origin https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/${{ github.repository }}.git
|
||||||
|
@ -54,7 +54,7 @@ example = extrude(exampleSketch, length = 5)
|
|||||||
// Add color to a revolved solid.
|
// Add color to a revolved solid.
|
||||||
sketch001 = startSketchOn(XY)
|
sketch001 = startSketchOn(XY)
|
||||||
|> circle(center = [15, 0], radius = 5)
|
|> circle(center = [15, 0], radius = 5)
|
||||||
|> revolve(angle = 360, axis = 'y')
|
|> revolve(angle = 360, axis = Y)
|
||||||
|> appearance(color = '#ff0000', metalness = 90, roughness = 90)
|
|> appearance(color = '#ff0000', metalness = 90, roughness = 90)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -9,13 +9,12 @@ layout: manual
|
|||||||
|
|
||||||
### `std`
|
### `std`
|
||||||
|
|
||||||
- [`HALF_TURN`](/docs/kcl/consts/std-HALF_TURN)
|
- [`X`](/docs/kcl/consts/std-X)
|
||||||
- [`QUARTER_TURN`](/docs/kcl/consts/std-QUARTER_TURN)
|
|
||||||
- [`THREE_QUARTER_TURN`](/docs/kcl/consts/std-THREE_QUARTER_TURN)
|
|
||||||
- [`XY`](/docs/kcl/consts/std-XY)
|
- [`XY`](/docs/kcl/consts/std-XY)
|
||||||
- [`XZ`](/docs/kcl/consts/std-XZ)
|
- [`XZ`](/docs/kcl/consts/std-XZ)
|
||||||
|
- [`Y`](/docs/kcl/consts/std-Y)
|
||||||
- [`YZ`](/docs/kcl/consts/std-YZ)
|
- [`YZ`](/docs/kcl/consts/std-YZ)
|
||||||
- [`ZERO`](/docs/kcl/consts/std-ZERO)
|
- [`Z`](/docs/kcl/consts/std-Z)
|
||||||
|
|
||||||
### `std::math`
|
### `std::math`
|
||||||
|
|
||||||
@ -23,3 +22,10 @@ layout: manual
|
|||||||
- [`PI`](/docs/kcl/consts/std-math-PI)
|
- [`PI`](/docs/kcl/consts/std-math-PI)
|
||||||
- [`TAU`](/docs/kcl/consts/std-math-TAU)
|
- [`TAU`](/docs/kcl/consts/std-math-TAU)
|
||||||
|
|
||||||
|
### `std::turns`
|
||||||
|
|
||||||
|
- [`HALF_TURN`](/docs/kcl/consts/std-turns-HALF_TURN)
|
||||||
|
- [`QUARTER_TURN`](/docs/kcl/consts/std-turns-QUARTER_TURN)
|
||||||
|
- [`THREE_QUARTER_TURN`](/docs/kcl/consts/std-turns-THREE_QUARTER_TURN)
|
||||||
|
- [`ZERO`](/docs/kcl/consts/std-turns-ZERO)
|
||||||
|
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
title: "std::HALF_TURN"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```js
|
|
||||||
std::HALF_TURN: number(deg) = 180deg
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
title: "std::QUARTER_TURN"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```js
|
|
||||||
std::QUARTER_TURN: number(deg) = 90deg
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
title: "std::THREE_QUARTER_TURN"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```js
|
|
||||||
std::THREE_QUARTER_TURN: number(deg) = 270deg
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: "std::ZERO"
|
title: "std::X"
|
||||||
excerpt: ""
|
excerpt: ""
|
||||||
layout: manual
|
layout: manual
|
||||||
---
|
---
|
||||||
@ -9,7 +9,7 @@ layout: manual
|
|||||||
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
std::ZERO: number = 0
|
std::X
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
15
docs/kcl/consts/std-Y.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "std::Y"
|
||||||
|
excerpt: ""
|
||||||
|
layout: manual
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
std::Y
|
||||||
|
```
|
||||||
|
|
||||||
|
|
15
docs/kcl/consts/std-Z.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "std::Z"
|
||||||
|
excerpt: ""
|
||||||
|
layout: manual
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
std::Z
|
||||||
|
```
|
||||||
|
|
||||||
|
|
15
docs/kcl/consts/std-turns-HALF_TURN.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "std::turns::HALF_TURN"
|
||||||
|
excerpt: ""
|
||||||
|
layout: manual
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
std::turns::HALF_TURN: number(deg) = 180deg
|
||||||
|
```
|
||||||
|
|
||||||
|
|
15
docs/kcl/consts/std-turns-QUARTER_TURN.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "std::turns::QUARTER_TURN"
|
||||||
|
excerpt: ""
|
||||||
|
layout: manual
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
std::turns::QUARTER_TURN: number(deg) = 90deg
|
||||||
|
```
|
||||||
|
|
||||||
|
|
15
docs/kcl/consts/std-turns-THREE_QUARTER_TURN.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "std::turns::THREE_QUARTER_TURN"
|
||||||
|
excerpt: ""
|
||||||
|
layout: manual
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
std::turns::THREE_QUARTER_TURN: number(deg) = 270deg
|
||||||
|
```
|
||||||
|
|
||||||
|
|
15
docs/kcl/consts/std-turns-ZERO.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "std::turns::ZERO"
|
||||||
|
excerpt: ""
|
||||||
|
layout: manual
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
std::turns::ZERO: number = 0
|
||||||
|
```
|
||||||
|
|
||||||
|
|
@ -22,20 +22,22 @@ layout: manual
|
|||||||
* [`string`](kcl/types/string)
|
* [`string`](kcl/types/string)
|
||||||
* [`tag`](kcl/types/tag)
|
* [`tag`](kcl/types/tag)
|
||||||
* **std**
|
* **std**
|
||||||
|
* [`Axis2d`](kcl/types/Axis2d)
|
||||||
|
* [`Axis3d`](kcl/types/Axis3d)
|
||||||
|
* [`Edge`](kcl/types/Edge)
|
||||||
* [`Face`](kcl/types/Face)
|
* [`Face`](kcl/types/Face)
|
||||||
* [`HALF_TURN`](kcl/consts/std-HALF_TURN)
|
|
||||||
* [`Helix`](kcl/types/Helix)
|
* [`Helix`](kcl/types/Helix)
|
||||||
* [`Plane`](kcl/types/Plane)
|
* [`Plane`](kcl/types/Plane)
|
||||||
* [`Point2d`](kcl/types/Point2d)
|
* [`Point2d`](kcl/types/Point2d)
|
||||||
* [`Point3d`](kcl/types/Point3d)
|
* [`Point3d`](kcl/types/Point3d)
|
||||||
* [`QUARTER_TURN`](kcl/consts/std-QUARTER_TURN)
|
|
||||||
* [`Sketch`](kcl/types/Sketch)
|
* [`Sketch`](kcl/types/Sketch)
|
||||||
* [`Solid`](kcl/types/Solid)
|
* [`Solid`](kcl/types/Solid)
|
||||||
* [`THREE_QUARTER_TURN`](kcl/consts/std-THREE_QUARTER_TURN)
|
* [`X`](kcl/consts/std-X)
|
||||||
* [`XY`](kcl/consts/std-XY)
|
* [`XY`](kcl/consts/std-XY)
|
||||||
* [`XZ`](kcl/consts/std-XZ)
|
* [`XZ`](kcl/consts/std-XZ)
|
||||||
|
* [`Y`](kcl/consts/std-Y)
|
||||||
* [`YZ`](kcl/consts/std-YZ)
|
* [`YZ`](kcl/consts/std-YZ)
|
||||||
* [`ZERO`](kcl/consts/std-ZERO)
|
* [`Z`](kcl/consts/std-Z)
|
||||||
* [`abs`](kcl/abs)
|
* [`abs`](kcl/abs)
|
||||||
* [`acos`](kcl/acos)
|
* [`acos`](kcl/acos)
|
||||||
* [`angleToMatchLengthX`](kcl/angleToMatchLengthX)
|
* [`angleToMatchLengthX`](kcl/angleToMatchLengthX)
|
||||||
@ -72,7 +74,7 @@ layout: manual
|
|||||||
* [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge)
|
* [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge)
|
||||||
* [`getOppositeEdge`](kcl/getOppositeEdge)
|
* [`getOppositeEdge`](kcl/getOppositeEdge)
|
||||||
* [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge)
|
* [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge)
|
||||||
* [`helix`](kcl/helix)
|
* [`helix`](kcl/std-helix)
|
||||||
* [`hole`](kcl/hole)
|
* [`hole`](kcl/hole)
|
||||||
* [`hollow`](kcl/hollow)
|
* [`hollow`](kcl/hollow)
|
||||||
* [`inch`](kcl/inch)
|
* [`inch`](kcl/inch)
|
||||||
@ -91,7 +93,6 @@ layout: manual
|
|||||||
* [`map`](kcl/map)
|
* [`map`](kcl/map)
|
||||||
* [`max`](kcl/max)
|
* [`max`](kcl/max)
|
||||||
* [`min`](kcl/min)
|
* [`min`](kcl/min)
|
||||||
* [`mirror2d`](kcl/mirror2d)
|
|
||||||
* [`mm`](kcl/mm)
|
* [`mm`](kcl/mm)
|
||||||
* [`offsetPlane`](kcl/offsetPlane)
|
* [`offsetPlane`](kcl/offsetPlane)
|
||||||
* [`patternCircular2d`](kcl/patternCircular2d)
|
* [`patternCircular2d`](kcl/patternCircular2d)
|
||||||
@ -110,7 +111,7 @@ layout: manual
|
|||||||
* [`push`](kcl/push)
|
* [`push`](kcl/push)
|
||||||
* [`reduce`](kcl/reduce)
|
* [`reduce`](kcl/reduce)
|
||||||
* [`rem`](kcl/rem)
|
* [`rem`](kcl/rem)
|
||||||
* [`revolve`](kcl/revolve)
|
* [`revolve`](kcl/std-revolve)
|
||||||
* [`rotate`](kcl/rotate)
|
* [`rotate`](kcl/rotate)
|
||||||
* [`round`](kcl/round)
|
* [`round`](kcl/round)
|
||||||
* [`scale`](kcl/scale)
|
* [`scale`](kcl/scale)
|
||||||
@ -146,3 +147,9 @@ layout: manual
|
|||||||
* [`tan`](kcl/std-math-tan)
|
* [`tan`](kcl/std-math-tan)
|
||||||
* **std::sketch**
|
* **std::sketch**
|
||||||
* [`circle`](kcl/std-sketch-circle)
|
* [`circle`](kcl/std-sketch-circle)
|
||||||
|
* [`mirror2d`](kcl/std-sketch-mirror2d)
|
||||||
|
* **std::turns**
|
||||||
|
* [`turns::HALF_TURN`](kcl/consts/std-turns-HALF_TURN)
|
||||||
|
* [`turns::QUARTER_TURN`](kcl/consts/std-turns-QUARTER_TURN)
|
||||||
|
* [`turns::THREE_QUARTER_TURN`](kcl/consts/std-turns-THREE_QUARTER_TURN)
|
||||||
|
* [`turns::ZERO`](kcl/consts/std-turns-ZERO)
|
||||||
|
@ -146,7 +146,7 @@ exampleSketch = startSketchOn(XY)
|
|||||||
|> line(end = [-2, 0])
|
|> line(end = [-2, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|
|
||||||
example = revolve(exampleSketch, axis = 'y', angle = 180)
|
example = revolve(exampleSketch, axis = Y, angle = 180)
|
||||||
|
|
||||||
exampleSketch002 = startSketchOn(example, 'end')
|
exampleSketch002 = startSketchOn(example, 'end')
|
||||||
|> startProfileAt([4.5, -5], %)
|
|> startProfileAt([4.5, -5], %)
|
||||||
@ -177,7 +177,7 @@ exampleSketch = startSketchOn(XY)
|
|||||||
|
|
||||||
example = revolve(
|
example = revolve(
|
||||||
exampleSketch,
|
exampleSketch,
|
||||||
axis = 'y',
|
axis = Y,
|
||||||
angle = 180,
|
angle = 180,
|
||||||
tagEnd = $end01,
|
tagEnd = $end01,
|
||||||
)
|
)
|
||||||
|
116
docs/kcl/std-helix.md
Normal file
246
docs/kcl/std-revolve.md
Normal file
98
docs/kcl/std-sketch-mirror2d.md
Normal file
17412
docs/kcl/std.json
@ -74,7 +74,7 @@ helixPath = helix(
|
|||||||
revolutions = 4,
|
revolutions = 4,
|
||||||
length = 10,
|
length = 10,
|
||||||
radius = 5,
|
radius = 5,
|
||||||
axis = 'Z',
|
axis = Z,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create a spring by sweeping around the helix path.
|
// Create a spring by sweeping around the helix path.
|
||||||
|
12
docs/kcl/types/Axis2d.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
title: "std::Axis2d"
|
||||||
|
excerpt: "An infinte line in 2d space."
|
||||||
|
layout: manual
|
||||||
|
---
|
||||||
|
|
||||||
|
An infinte line in 2d space.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
12
docs/kcl/types/Axis3d.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
title: "std::Axis3d"
|
||||||
|
excerpt: "An infinte line in 3d space."
|
||||||
|
layout: manual
|
||||||
|
---
|
||||||
|
|
||||||
|
An infinte line in 3d space.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
12
docs/kcl/types/Edge.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
title: "std::Edge"
|
||||||
|
excerpt: "The edge of a solid."
|
||||||
|
layout: manual
|
||||||
|
---
|
||||||
|
|
||||||
|
The edge of a solid.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -21,7 +21,7 @@ sketch001 = startSketchOn(XZ)
|
|||||||
|> angledLine([-45, length001], %)
|
|> angledLine([-45, length001], %)
|
||||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|> close()
|
|> close()
|
||||||
revolve001 = revolve(sketch001, axis = "X")
|
revolve001 = revolve(sketch001, axis = X)
|
||||||
triangle()
|
triangle()
|
||||||
|> extrude(length = 30)
|
|> extrude(length = 30)
|
||||||
plane001 = offsetPlane(XY, offset = 10)
|
plane001 = offsetPlane(XY, offset = 10)
|
||||||
@ -126,7 +126,7 @@ test.describe('Feature Tree pane', () => {
|
|||||||
await testViewSource({
|
await testViewSource({
|
||||||
operationName: 'Revolve',
|
operationName: 'Revolve',
|
||||||
operationIndex: 0,
|
operationIndex: 0,
|
||||||
expectedActiveLine: 'revolve001 = revolve(sketch001, axis = "X")',
|
expectedActiveLine: 'revolve001 = revolve(sketch001, axis = X)',
|
||||||
})
|
})
|
||||||
await testViewSource({
|
await testViewSource({
|
||||||
operationName: 'Triangle',
|
operationName: 'Triangle',
|
||||||
|
@ -257,6 +257,46 @@ export const isErrorWhitelisted = (exception: Error) => {
|
|||||||
project: 'Google Chrome',
|
project: 'Google Chrome',
|
||||||
foundInSpec: 'e2e/playwright/testing-settings.spec.ts',
|
foundInSpec: 'e2e/playwright/testing-settings.spec.ts',
|
||||||
},
|
},
|
||||||
|
// TODO: fix this error in the code
|
||||||
|
{
|
||||||
|
name: 'TypeError',
|
||||||
|
message: "Cannot read properties of undefined (reading 'length')",
|
||||||
|
stack: '',
|
||||||
|
project: 'Google Chrome',
|
||||||
|
foundInSpec: '', // many tests are impacted by this error
|
||||||
|
},
|
||||||
|
// TODO: fix this error in the code
|
||||||
|
{
|
||||||
|
name: 'ReferenceError',
|
||||||
|
message: '_testUtils is not defined',
|
||||||
|
stack: '',
|
||||||
|
project: 'Google Chrome',
|
||||||
|
foundInSpec: 'e2e/playwright/snapshot-tests.spec.ts',
|
||||||
|
},
|
||||||
|
// TODO: fix this error in the code
|
||||||
|
{
|
||||||
|
name: 'TypeError',
|
||||||
|
message: 'Failed to fetch',
|
||||||
|
stack: '',
|
||||||
|
project: 'Google Chrome',
|
||||||
|
foundInSpec: 'e2e/playwright/snapshot-tests.spec.ts',
|
||||||
|
},
|
||||||
|
// TODO: fix this error in the code
|
||||||
|
{
|
||||||
|
name: 'ReferenceError',
|
||||||
|
message: 'originalCode is not defined',
|
||||||
|
stack: '',
|
||||||
|
project: 'Google Chrome',
|
||||||
|
foundInSpec: 'e2e/playwright/onboarding-tests.spec.ts',
|
||||||
|
},
|
||||||
|
// TODO: fix this error in the code
|
||||||
|
{
|
||||||
|
name: 'ReferenceError',
|
||||||
|
message: 'createNewVariableCheckbox is not defined',
|
||||||
|
stack: '',
|
||||||
|
project: 'Google Chrome',
|
||||||
|
foundInSpec: 'e2e/playwright/testing-constraints.spec.ts',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const cleanString = (str: string) => str.replace(/[`"]/g, '')
|
const cleanString = (str: string) => str.replace(/[`"]/g, '')
|
||||||
|
@ -1082,8 +1082,8 @@ openSketch = startSketchOn(XY)
|
|||||||
}) => {
|
}) => {
|
||||||
// One dumb hardcoded screen pixel value
|
// One dumb hardcoded screen pixel value
|
||||||
const testPoint = { x: 620, y: 257 }
|
const testPoint = { x: 620, y: 257 }
|
||||||
const expectedOutput = `helix001 = helix( revolutions = 1, angleStart = 360, ccw = false, radius = 5, axis = 'X', length = 5,)`
|
const expectedOutput = `helix001 = helix( axis = 'X', radius = 5, length = 5, revolutions = 1, angleStart = 360, ccw = false,)`
|
||||||
const expectedLine = `revolutions=1,`
|
const expectedLine = `axis='X',`
|
||||||
|
|
||||||
await homePage.goToModelingScene()
|
await homePage.goToModelingScene()
|
||||||
|
|
||||||
@ -1091,17 +1091,17 @@ openSketch = startSketchOn(XY)
|
|||||||
await toolbar.helixButton.click()
|
await toolbar.helixButton.click()
|
||||||
await cmdBar.expectState({
|
await cmdBar.expectState({
|
||||||
stage: 'arguments',
|
stage: 'arguments',
|
||||||
currentArgKey: 'axisOrEdge',
|
currentArgKey: 'mode',
|
||||||
currentArgValue: '',
|
currentArgValue: '',
|
||||||
headerArguments: {
|
headerArguments: {
|
||||||
|
Mode: '',
|
||||||
AngleStart: '',
|
AngleStart: '',
|
||||||
AxisOrEdge: '',
|
Revolutions: '',
|
||||||
CounterClockWise: '',
|
|
||||||
Length: '',
|
Length: '',
|
||||||
Radius: '',
|
Radius: '',
|
||||||
Revolutions: '',
|
CounterClockWise: '',
|
||||||
},
|
},
|
||||||
highlightedHeaderArg: 'axisOrEdge',
|
highlightedHeaderArg: 'mode',
|
||||||
commandName: 'Helix',
|
commandName: 'Helix',
|
||||||
})
|
})
|
||||||
await cmdBar.progressCmdBar()
|
await cmdBar.progressCmdBar()
|
||||||
@ -1110,7 +1110,19 @@ openSketch = startSketchOn(XY)
|
|||||||
await cmdBar.progressCmdBar()
|
await cmdBar.progressCmdBar()
|
||||||
await cmdBar.progressCmdBar()
|
await cmdBar.progressCmdBar()
|
||||||
await cmdBar.progressCmdBar()
|
await cmdBar.progressCmdBar()
|
||||||
await cmdBar.progressCmdBar()
|
await cmdBar.expectState({
|
||||||
|
stage: 'review',
|
||||||
|
headerArguments: {
|
||||||
|
Mode: 'Axis',
|
||||||
|
Axis: 'X',
|
||||||
|
AngleStart: '360',
|
||||||
|
Revolutions: '1',
|
||||||
|
Length: '5',
|
||||||
|
Radius: '5',
|
||||||
|
CounterClockWise: '',
|
||||||
|
},
|
||||||
|
commandName: 'Helix',
|
||||||
|
})
|
||||||
await cmdBar.progressCmdBar()
|
await cmdBar.progressCmdBar()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1134,30 +1146,31 @@ openSketch = startSketchOn(XY)
|
|||||||
await cmdBar.expectState({
|
await cmdBar.expectState({
|
||||||
commandName: 'Helix',
|
commandName: 'Helix',
|
||||||
stage: 'arguments',
|
stage: 'arguments',
|
||||||
currentArgKey: 'length',
|
currentArgKey: 'CounterClockWise',
|
||||||
currentArgValue: initialInput,
|
currentArgValue: '',
|
||||||
headerArguments: {
|
headerArguments: {
|
||||||
AngleStart: '360',
|
|
||||||
Axis: 'X',
|
Axis: 'X',
|
||||||
CounterClockWise: '',
|
AngleStart: '360',
|
||||||
Length: initialInput,
|
|
||||||
Radius: '5',
|
|
||||||
Revolutions: '1',
|
Revolutions: '1',
|
||||||
|
Radius: '5',
|
||||||
|
Length: initialInput,
|
||||||
|
CounterClockWise: '',
|
||||||
},
|
},
|
||||||
highlightedHeaderArg: 'length',
|
highlightedHeaderArg: 'CounterClockWise',
|
||||||
})
|
})
|
||||||
|
await page.keyboard.press('Shift+Backspace')
|
||||||
await expect(cmdBar.currentArgumentInput).toBeVisible()
|
await expect(cmdBar.currentArgumentInput).toBeVisible()
|
||||||
await cmdBar.currentArgumentInput.locator('.cm-content').fill(newInput)
|
await cmdBar.currentArgumentInput.locator('.cm-content').fill(newInput)
|
||||||
await cmdBar.progressCmdBar()
|
await cmdBar.progressCmdBar()
|
||||||
await cmdBar.expectState({
|
await cmdBar.expectState({
|
||||||
stage: 'review',
|
stage: 'review',
|
||||||
headerArguments: {
|
headerArguments: {
|
||||||
AngleStart: '360',
|
|
||||||
Axis: 'X',
|
Axis: 'X',
|
||||||
CounterClockWise: '',
|
AngleStart: '360',
|
||||||
Length: newInput,
|
|
||||||
Radius: '5',
|
|
||||||
Revolutions: '1',
|
Revolutions: '1',
|
||||||
|
Radius: '5',
|
||||||
|
Length: newInput,
|
||||||
|
CounterClockWise: '',
|
||||||
},
|
},
|
||||||
commandName: 'Helix',
|
commandName: 'Helix',
|
||||||
})
|
})
|
||||||
@ -1181,14 +1194,14 @@ openSketch = startSketchOn(XY)
|
|||||||
{
|
{
|
||||||
selectionType: 'segment',
|
selectionType: 'segment',
|
||||||
testPoint: { x: 513, y: 221 },
|
testPoint: { x: 513, y: 221 },
|
||||||
expectedOutput: `helix001 = helix( revolutions = 20, angleStart = 0, ccw = true, radius = 1, axis = seg01, length = 100,)`,
|
expectedOutput: `helix001 = helix( axis = seg01, radius = 1, length = 100, revolutions = 20, angleStart = 0, ccw = false,)`,
|
||||||
expectedEditedOutput: `helix001 = helix( revolutions = 20, angleStart = 0, ccw = true, radius = 1, axis = seg01, length = 50,)`,
|
expectedEditedOutput: `helix001 = helix( axis = seg01, radius = 1, length = 50, revolutions = 20, angleStart = 0, ccw = false,)`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selectionType: 'sweepEdge',
|
selectionType: 'sweepEdge',
|
||||||
testPoint: { x: 564, y: 364 },
|
testPoint: { x: 564, y: 364 },
|
||||||
expectedOutput: `helix001 = helix( revolutions = 20, angleStart = 0, ccw = true, radius = 1, axis = getOppositeEdge(seg01), length = 100,)`,
|
expectedOutput: `helix001 = helix( axis = getOppositeEdge(seg01), radius = 1, length = 100, revolutions = 20, angleStart = 0, ccw = false,)`,
|
||||||
expectedEditedOutput: `helix001 = helix( revolutions = 20, angleStart = 0, ccw = true, radius = 1, axis = getOppositeEdge(seg01), length = 50,)`,
|
expectedEditedOutput: `helix001 = helix( axis = getOppositeEdge(seg01), radius = 1, length = 50, revolutions = 20, angleStart = 0, ccw = false,)`,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
helixCases.map(
|
helixCases.map(
|
||||||
@ -1225,17 +1238,17 @@ openSketch = startSketchOn(XY)
|
|||||||
await toolbar.helixButton.click()
|
await toolbar.helixButton.click()
|
||||||
await cmdBar.expectState({
|
await cmdBar.expectState({
|
||||||
stage: 'arguments',
|
stage: 'arguments',
|
||||||
currentArgKey: 'axisOrEdge',
|
currentArgKey: 'mode',
|
||||||
currentArgValue: '',
|
currentArgValue: '',
|
||||||
headerArguments: {
|
headerArguments: {
|
||||||
AngleStart: '',
|
AngleStart: '',
|
||||||
AxisOrEdge: '',
|
Mode: '',
|
||||||
CounterClockWise: '',
|
CounterClockWise: '',
|
||||||
Length: '',
|
Length: '',
|
||||||
Radius: '',
|
Radius: '',
|
||||||
Revolutions: '',
|
Revolutions: '',
|
||||||
},
|
},
|
||||||
highlightedHeaderArg: 'axisOrEdge',
|
highlightedHeaderArg: 'mode',
|
||||||
commandName: 'Helix',
|
commandName: 'Helix',
|
||||||
})
|
})
|
||||||
await cmdBar.selectOption({ name: 'Edge' }).click()
|
await cmdBar.selectOption({ name: 'Edge' }).click()
|
||||||
@ -1246,7 +1259,6 @@ openSketch = startSketchOn(XY)
|
|||||||
await cmdBar.progressCmdBar()
|
await cmdBar.progressCmdBar()
|
||||||
await page.keyboard.insertText('0')
|
await page.keyboard.insertText('0')
|
||||||
await cmdBar.progressCmdBar()
|
await cmdBar.progressCmdBar()
|
||||||
await cmdBar.selectOption({ name: 'True' }).click()
|
|
||||||
await page.keyboard.insertText('1')
|
await page.keyboard.insertText('1')
|
||||||
await cmdBar.progressCmdBar()
|
await cmdBar.progressCmdBar()
|
||||||
await page.keyboard.insertText('100')
|
await page.keyboard.insertText('100')
|
||||||
@ -1254,13 +1266,13 @@ openSketch = startSketchOn(XY)
|
|||||||
await cmdBar.expectState({
|
await cmdBar.expectState({
|
||||||
stage: 'review',
|
stage: 'review',
|
||||||
headerArguments: {
|
headerArguments: {
|
||||||
AngleStart: '0',
|
Mode: 'Edge',
|
||||||
AxisOrEdge: 'Edge',
|
|
||||||
Edge: `1 ${selectionType}`,
|
Edge: `1 ${selectionType}`,
|
||||||
CounterClockWise: '',
|
AngleStart: '0',
|
||||||
Length: '100',
|
|
||||||
Radius: '1',
|
|
||||||
Revolutions: '20',
|
Revolutions: '20',
|
||||||
|
Radius: '1',
|
||||||
|
Length: '100',
|
||||||
|
CounterClockWise: '',
|
||||||
},
|
},
|
||||||
commandName: 'Helix',
|
commandName: 'Helix',
|
||||||
})
|
})
|
||||||
@ -1285,17 +1297,18 @@ openSketch = startSketchOn(XY)
|
|||||||
await cmdBar.expectState({
|
await cmdBar.expectState({
|
||||||
commandName: 'Helix',
|
commandName: 'Helix',
|
||||||
stage: 'arguments',
|
stage: 'arguments',
|
||||||
currentArgKey: 'length',
|
currentArgKey: 'CounterClockWise',
|
||||||
currentArgValue: initialInput,
|
currentArgValue: '',
|
||||||
headerArguments: {
|
headerArguments: {
|
||||||
AngleStart: '0',
|
AngleStart: '0',
|
||||||
CounterClockWise: '',
|
|
||||||
Length: initialInput,
|
|
||||||
Radius: '1',
|
|
||||||
Revolutions: '20',
|
Revolutions: '20',
|
||||||
|
Radius: '1',
|
||||||
|
Length: initialInput,
|
||||||
|
CounterClockWise: '',
|
||||||
},
|
},
|
||||||
highlightedHeaderArg: 'length',
|
highlightedHeaderArg: 'CounterClockWise',
|
||||||
})
|
})
|
||||||
|
await page.keyboard.press('Shift+Backspace')
|
||||||
await expect(cmdBar.currentArgumentInput).toBeVisible()
|
await expect(cmdBar.currentArgumentInput).toBeVisible()
|
||||||
await cmdBar.currentArgumentInput
|
await cmdBar.currentArgumentInput
|
||||||
.locator('.cm-content')
|
.locator('.cm-content')
|
||||||
@ -1305,10 +1318,10 @@ openSketch = startSketchOn(XY)
|
|||||||
stage: 'review',
|
stage: 'review',
|
||||||
headerArguments: {
|
headerArguments: {
|
||||||
AngleStart: '0',
|
AngleStart: '0',
|
||||||
CounterClockWise: '',
|
|
||||||
Length: newInput,
|
|
||||||
Radius: '1',
|
|
||||||
Revolutions: '20',
|
Revolutions: '20',
|
||||||
|
Radius: '1',
|
||||||
|
Length: newInput,
|
||||||
|
CounterClockWise: '',
|
||||||
},
|
},
|
||||||
commandName: 'Helix',
|
commandName: 'Helix',
|
||||||
})
|
})
|
||||||
@ -1336,6 +1349,141 @@ openSketch = startSketchOn(XY)
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
test('Helix point-and-click on cylinder', async ({
|
||||||
|
context,
|
||||||
|
page,
|
||||||
|
homePage,
|
||||||
|
scene,
|
||||||
|
editor,
|
||||||
|
toolbar,
|
||||||
|
cmdBar,
|
||||||
|
}) => {
|
||||||
|
const initialCode = `sketch001 = startSketchOn(XY)
|
||||||
|
profile001 = circle(
|
||||||
|
sketch001,
|
||||||
|
center = [0, 0],
|
||||||
|
radius = 100,
|
||||||
|
tag = $seg01,
|
||||||
|
)
|
||||||
|
extrude001 = extrude(profile001, length = 100)
|
||||||
|
`
|
||||||
|
await context.addInitScript((initialCode) => {
|
||||||
|
localStorage.setItem('persistCode', initialCode)
|
||||||
|
}, initialCode)
|
||||||
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||||
|
await homePage.goToModelingScene()
|
||||||
|
await scene.waitForExecutionDone()
|
||||||
|
|
||||||
|
// One dumb hardcoded screen pixel value
|
||||||
|
const testPoint = { x: 620, y: 257 }
|
||||||
|
const [clickOnWall] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
||||||
|
const expectedOutput = `helix001 = helix( cylinder = extrude001, revolutions = 1, angleStart = 360, ccw = false,)`
|
||||||
|
const expectedLine = `cylinder = extrude001,`
|
||||||
|
const expectedEditedOutput = `helix001 = helix( cylinder = extrude001, revolutions = 1, angleStart = 360, ccw = true,)`
|
||||||
|
|
||||||
|
await test.step(`Go through the command bar flow`, async () => {
|
||||||
|
await toolbar.helixButton.click()
|
||||||
|
await cmdBar.expectState({
|
||||||
|
stage: 'arguments',
|
||||||
|
currentArgKey: 'mode',
|
||||||
|
currentArgValue: '',
|
||||||
|
headerArguments: {
|
||||||
|
Mode: '',
|
||||||
|
AngleStart: '',
|
||||||
|
Revolutions: '',
|
||||||
|
Length: '',
|
||||||
|
Radius: '',
|
||||||
|
CounterClockWise: '',
|
||||||
|
},
|
||||||
|
highlightedHeaderArg: 'mode',
|
||||||
|
commandName: 'Helix',
|
||||||
|
})
|
||||||
|
await cmdBar.selectOption({ name: 'Cylinder' }).click()
|
||||||
|
await cmdBar.expectState({
|
||||||
|
stage: 'arguments',
|
||||||
|
currentArgKey: 'cylinder',
|
||||||
|
currentArgValue: '',
|
||||||
|
headerArguments: {
|
||||||
|
Mode: 'Cylinder',
|
||||||
|
Cylinder: '',
|
||||||
|
AngleStart: '',
|
||||||
|
Revolutions: '',
|
||||||
|
CounterClockWise: '',
|
||||||
|
},
|
||||||
|
highlightedHeaderArg: 'cylinder',
|
||||||
|
commandName: 'Helix',
|
||||||
|
})
|
||||||
|
await clickOnWall()
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
await cmdBar.expectState({
|
||||||
|
stage: 'review',
|
||||||
|
headerArguments: {
|
||||||
|
Mode: 'Cylinder',
|
||||||
|
Cylinder: '1 face',
|
||||||
|
AngleStart: '360',
|
||||||
|
Revolutions: '1',
|
||||||
|
CounterClockWise: '',
|
||||||
|
},
|
||||||
|
commandName: 'Helix',
|
||||||
|
})
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
})
|
||||||
|
|
||||||
|
await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
|
||||||
|
await editor.expectEditor.toContain(expectedOutput)
|
||||||
|
await editor.expectState({
|
||||||
|
diagnostics: [],
|
||||||
|
activeLines: [expectedLine],
|
||||||
|
highlightedCode: '',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
await test.step(`Edit helix through the feature tree`, async () => {
|
||||||
|
await editor.closePane()
|
||||||
|
const operationButton = await toolbar.getFeatureTreeOperation('Helix', 0)
|
||||||
|
await operationButton.dblclick()
|
||||||
|
await cmdBar.expectState({
|
||||||
|
commandName: 'Helix',
|
||||||
|
stage: 'arguments',
|
||||||
|
currentArgKey: 'CounterClockWise',
|
||||||
|
currentArgValue: '',
|
||||||
|
headerArguments: {
|
||||||
|
AngleStart: '360',
|
||||||
|
Revolutions: '1',
|
||||||
|
CounterClockWise: '',
|
||||||
|
},
|
||||||
|
highlightedHeaderArg: 'CounterClockWise',
|
||||||
|
})
|
||||||
|
await cmdBar.selectOption({ name: 'True' }).click()
|
||||||
|
await cmdBar.expectState({
|
||||||
|
stage: 'review',
|
||||||
|
headerArguments: {
|
||||||
|
AngleStart: '360',
|
||||||
|
Revolutions: '1',
|
||||||
|
CounterClockWise: 'true',
|
||||||
|
},
|
||||||
|
commandName: 'Helix',
|
||||||
|
})
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
await toolbar.closePane('feature-tree')
|
||||||
|
await toolbar.openPane('code')
|
||||||
|
await editor.expectEditor.toContain(expectedEditedOutput)
|
||||||
|
await editor.closePane()
|
||||||
|
})
|
||||||
|
|
||||||
|
await test.step('Delete helix via feature tree selection', async () => {
|
||||||
|
await toolbar.openPane('feature-tree')
|
||||||
|
const operationButton = await toolbar.getFeatureTreeOperation('Helix', 0)
|
||||||
|
await operationButton.click({ button: 'left' })
|
||||||
|
await page.keyboard.press('Delete')
|
||||||
|
await toolbar.closePane('feature-tree')
|
||||||
|
await toolbar.openPane('code')
|
||||||
|
await editor.expectEditor.not.toContain(expectedEditedOutput)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
const loftPointAndClickCases = [
|
const loftPointAndClickCases = [
|
||||||
{ shouldPreselect: true },
|
{ shouldPreselect: true },
|
||||||
{ shouldPreselect: false },
|
{ shouldPreselect: false },
|
||||||
@ -3321,7 +3469,7 @@ segAng(rectangleSegmentA002),
|
|||||||
await cmdBar.progressCmdBar()
|
await cmdBar.progressCmdBar()
|
||||||
await cmdBar.progressCmdBar()
|
await cmdBar.progressCmdBar()
|
||||||
|
|
||||||
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = 'X')`
|
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = X)`
|
||||||
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
|
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
|
||||||
})
|
})
|
||||||
test('revolve surface around edge from an extruded solid2d', async ({
|
test('revolve surface around edge from an extruded solid2d', async ({
|
||||||
|
@ -473,6 +473,9 @@ test.describe('Can export from electron app', () => {
|
|||||||
if (!tronApp) {
|
if (!tronApp) {
|
||||||
fail()
|
fail()
|
||||||
}
|
}
|
||||||
|
if (runningOnWindows()) {
|
||||||
|
test.fixme(orRunWhenFullSuiteEnabled())
|
||||||
|
}
|
||||||
|
|
||||||
await context.folderSetupFn(async (dir) => {
|
await context.folderSetupFn(async (dir) => {
|
||||||
const bracketDir = path.join(dir, 'bracket')
|
const bracketDir = path.join(dir, 'bracket')
|
||||||
|
@ -778,6 +778,19 @@ plane002 = offsetPlane(XZ, offset = -2 * x)`
|
|||||||
await editor.expectEditor.not.toContain(`plane002`)
|
await editor.expectEditor.not.toContain(`plane002`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test.fail(
|
||||||
|
'Console errors cause tests to fail',
|
||||||
|
async ({ page, homePage }) => {
|
||||||
|
const u = await getUtils(page)
|
||||||
|
await homePage.goToModelingScene()
|
||||||
|
await u.openAndClearDebugPanel()
|
||||||
|
|
||||||
|
await page.getByTestId('custom-cmd-input').fill('foobar')
|
||||||
|
await page.getByTestId('custom-cmd-send-button').scrollIntoViewIfNeeded()
|
||||||
|
await page.getByTestId('custom-cmd-send-button').click()
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
async function clickExportButton(page: Page) {
|
async function clickExportButton(page: Page) {
|
||||||
|
@ -674,7 +674,7 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
|
|||||||
|> line(end = [12.73, -0.09])
|
|> line(end = [12.73, -0.09])
|
||||||
|> tangentialArcTo([24.95, -5.38], %)
|
|> tangentialArcTo([24.95, -5.38], %)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = "X")`
|
|> revolve(axis = X)`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -761,7 +761,7 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
|
|||||||
|> tangentialArcTo([24.95, -5.38], %)
|
|> tangentialArcTo([24.95, -5.38], %)
|
||||||
|> line(end = [1.97, 2.06])
|
|> line(end = [1.97, 2.06])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = "X")`)
|
|> revolve(axis = X)`)
|
||||||
})
|
})
|
||||||
test('Can add multiple sketches', async ({ page, homePage }) => {
|
test('Can add multiple sketches', async ({ page, homePage }) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
@ -1209,7 +1209,7 @@ profile001 = startProfileAt([${roundOff(scale * 69.6)}, ${roundOff(
|
|||||||
|> xLine(endAbsolute = 0 + .001)
|
|> xLine(endAbsolute = 0 + .001)
|
||||||
|> yLine(endAbsolute = 0)
|
|> yLine(endAbsolute = 0)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = "Y")
|
|> revolve(axis = Y)
|
||||||
|
|
||||||
return lugSketch
|
return lugSketch
|
||||||
}
|
}
|
||||||
|
@ -76,11 +76,11 @@ part001 = startSketchOn(-XZ)
|
|||||||
|> xLine(endAbsolute = totalLen, tag = $seg03)
|
|> xLine(endAbsolute = totalLen, tag = $seg03)
|
||||||
|> yLine(length = -armThick, tag = $seg01)
|
|> yLine(length = -armThick, tag = $seg01)
|
||||||
|> angledLineThatIntersects({
|
|> angledLineThatIntersects({
|
||||||
angle = HALF_TURN,
|
angle = turns::HALF_TURN,
|
||||||
offset = -armThick,
|
offset = -armThick,
|
||||||
intersectTag = seg04
|
intersectTag = seg04
|
||||||
}, %)
|
}, %)
|
||||||
|> angledLineToY([segAng(seg04, %) + 180, ZERO], %)
|
|> angledLineToY([segAng(seg04, %) + 180, turns::ZERO], %)
|
||||||
|> angledLineToY({
|
|> angledLineToY({
|
||||||
angle = -bottomAng,
|
angle = -bottomAng,
|
||||||
to = -totalHeightHalf - armThick,
|
to = -totalHeightHalf - armThick,
|
||||||
@ -88,12 +88,12 @@ part001 = startSketchOn(-XZ)
|
|||||||
|> xLine(length = endAbsolute = segEndX(seg03) + 0)
|
|> xLine(length = endAbsolute = segEndX(seg03) + 0)
|
||||||
|> yLine(length = -segLen(seg01, %))
|
|> yLine(length = -segLen(seg01, %))
|
||||||
|> angledLineThatIntersects({
|
|> angledLineThatIntersects({
|
||||||
angle = HALF_TURN,
|
angle = turns::HALF_TURN,
|
||||||
offset = -armThick,
|
offset = -armThick,
|
||||||
intersectTag = seg02
|
intersectTag = seg02
|
||||||
}, %)
|
}, %)
|
||||||
|> angledLineToY([segAng(seg02, %) + 180, -baseHeight], %)
|
|> angledLineToY([segAng(seg02, %) + 180, -baseHeight], %)
|
||||||
|> xLine(endAbsolute = ZERO)
|
|> xLine(endAbsolute = turns::ZERO)
|
||||||
|> close()
|
|> close()
|
||||||
|> extrude(length = 4)`
|
|> extrude(length = 4)`
|
||||||
)
|
)
|
||||||
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
@ -935,26 +935,19 @@ export async function setup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function failOnConsoleErrors(page: Page, testInfo?: TestInfo) {
|
function failOnConsoleErrors(page: Page, testInfo?: TestInfo) {
|
||||||
// enabled for chrome for now
|
|
||||||
if (page.context().browser()?.browserType().name() === 'chromium') {
|
|
||||||
// No idea wtf exception is
|
|
||||||
page.on('pageerror', (exception: any) => {
|
page.on('pageerror', (exception: any) => {
|
||||||
if (isErrorWhitelisted(exception)) {
|
if (isErrorWhitelisted(exception)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Only disable this environment variable if you want to collect console errors
|
||||||
// only set this env var to false if you want to collect console errors
|
if (process.env.FAIL_ON_CONSOLE_ERRORS !== 'false') {
|
||||||
// This can be configured in the GH workflow. This should be set to true by default (we want tests to fail when
|
// Use expect to prevent page from closing and not cleaning up
|
||||||
// unwhitelisted console errors are detected).
|
|
||||||
if (process.env.FAIL_ON_CONSOLE_ERRORS === 'true') {
|
|
||||||
// Fail when running on CI and FAIL_ON_CONSOLE_ERRORS is set
|
|
||||||
// use expect to prevent page from closing and not cleaning up
|
|
||||||
expect(`An error was detected in the console: \r\n message:${exception.message} \r\n name:${exception.name} \r\n stack:${exception.stack}
|
expect(`An error was detected in the console: \r\n message:${exception.message} \r\n name:${exception.name} \r\n stack:${exception.stack}
|
||||||
|
|
||||||
*Either fix the console error or add it to the whitelist defined in ./lib/console-error-whitelist.ts (if the error can be safely ignored)
|
*Either fix the console error or add it to the whitelist defined in ./lib/console-error-whitelist.ts (if the error can be safely ignored)
|
||||||
`).toEqual('Console error detected')
|
`).toEqual('Console error detected')
|
||||||
} else {
|
} else {
|
||||||
// the (test-results/exceptions.txt) file will be uploaded as part of an upload artifact in GH
|
// Add errors to `test-results/exceptions.txt` as a test artifact
|
||||||
fsp
|
fsp
|
||||||
.appendFile(
|
.appendFile(
|
||||||
'./test-results/exceptions.txt',
|
'./test-results/exceptions.txt',
|
||||||
@ -976,7 +969,6 @@ function failOnConsoleErrors(page: Page, testInfo?: TestInfo) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
export async function isOutOfViewInScrollContainer(
|
export async function isOutOfViewInScrollContainer(
|
||||||
element: Locator,
|
element: Locator,
|
||||||
container: Locator
|
container: Locator
|
||||||
|
@ -486,13 +486,13 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
|||||||
testName: 'Add variable, selecting axis',
|
testName: 'Add variable, selecting axis',
|
||||||
addVariable: true,
|
addVariable: true,
|
||||||
axisSelect: true,
|
axisSelect: true,
|
||||||
value: 'QUARTER_TURN - angle001',
|
value: 'turns::QUARTER_TURN - angle001',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: 'No variable, selecting axis',
|
testName: 'No variable, selecting axis',
|
||||||
addVariable: false,
|
addVariable: false,
|
||||||
axisSelect: true,
|
axisSelect: true,
|
||||||
value: 'QUARTER_TURN - 7',
|
value: 'turns::QUARTER_TURN - 7',
|
||||||
},
|
},
|
||||||
] as const
|
] as const
|
||||||
for (const { testName, addVariable, value, axisSelect } of cases) {
|
for (const { testName, addVariable, value, axisSelect } of cases) {
|
||||||
@ -935,12 +935,12 @@ part002 = startSketchOn(XZ)
|
|||||||
test.describe('Axis & segment - no modal constraints', () => {
|
test.describe('Axis & segment - no modal constraints', () => {
|
||||||
const cases = [
|
const cases = [
|
||||||
{
|
{
|
||||||
codeAfter: `|> line(endAbsolute = [154.9, ZERO])`,
|
codeAfter: `|> line(endAbsolute = [154.9, turns::ZERO])`,
|
||||||
axisClick: { x: 950, y: 250 },
|
axisClick: { x: 950, y: 250 },
|
||||||
constraintName: 'Snap To X',
|
constraintName: 'Snap To X',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
codeAfter: `|> line(endAbsolute = [ZERO, 61.34])`,
|
codeAfter: `|> line(endAbsolute = [turns::ZERO, 61.34])`,
|
||||||
axisClick: { x: 600, y: 150 },
|
axisClick: { x: 600, y: 150 },
|
||||||
constraintName: 'Snap To Y',
|
constraintName: 'Snap To Y',
|
||||||
},
|
},
|
||||||
|
@ -319,7 +319,7 @@ part009 = startSketchOn(XY)
|
|||||||
|> line(end = [0, pipeLength])
|
|> line(end = [0, pipeLength])
|
||||||
|> angledLineToX({ angle = 60, to = pipeLargeDia }, %)
|
|> angledLineToX({ angle = 60, to = pipeLargeDia }, %)
|
||||||
|> close()
|
|> close()
|
||||||
rev = revolve(part009, axis = 'y')
|
rev = revolve(part009, axis = Y)
|
||||||
sketch006 = startSketchOn(XY)
|
sketch006 = startSketchOn(XY)
|
||||||
profile001 = circle(
|
profile001 = circle(
|
||||||
sketch006,
|
sketch006,
|
||||||
@ -376,7 +376,7 @@ profile003 = startProfileAt([40.16, -120.48], sketch006)
|
|||||||
await page.waitForTimeout(200)
|
await page.waitForTimeout(200)
|
||||||
|
|
||||||
await expect(u.codeLocator).not.toContainText(
|
await expect(u.codeLocator).not.toContainText(
|
||||||
`rev = revolve(part009, axis: 'y')`
|
`rev = revolve(part009, axis: Y)`
|
||||||
)
|
)
|
||||||
|
|
||||||
// FIXME (commented section below), this test would select a wall that had a sketch on it, and delete the underlying extrude
|
// FIXME (commented section below), this test would select a wall that had a sketch on it, and delete the underlying extrude
|
||||||
|
@ -67,11 +67,11 @@ part001 = startSketchOn(-XZ)
|
|||||||
|> xLine(endAbsolute = totalLen, tag = $seg03)
|
|> xLine(endAbsolute = totalLen, tag = $seg03)
|
||||||
|> yLine(length = -armThick, tag = $seg01)
|
|> yLine(length = -armThick, tag = $seg01)
|
||||||
|> angledLineThatIntersects({
|
|> angledLineThatIntersects({
|
||||||
angle = HALF_TURN,
|
angle = turns::HALF_TURN,
|
||||||
offset = -armThick,
|
offset = -armThick,
|
||||||
intersectTag = seg04
|
intersectTag = seg04
|
||||||
}, %)
|
}, %)
|
||||||
|> angledLineToY([segAng(seg04) + 180, ZERO], %)
|
|> angledLineToY([segAng(seg04) + 180, turns::ZERO], %)
|
||||||
|> angledLineToY({
|
|> angledLineToY({
|
||||||
angle = -bottomAng,
|
angle = -bottomAng,
|
||||||
to = -totalHeightHalf - armThick,
|
to = -totalHeightHalf - armThick,
|
||||||
@ -79,12 +79,12 @@ part001 = startSketchOn(-XZ)
|
|||||||
|> xLine(endAbsolute = segEndX(seg03) + 0)
|
|> xLine(endAbsolute = segEndX(seg03) + 0)
|
||||||
|> yLine(length = -segLen(seg01))
|
|> yLine(length = -segLen(seg01))
|
||||||
|> angledLineThatIntersects({
|
|> angledLineThatIntersects({
|
||||||
angle = HALF_TURN,
|
angle = turns::HALF_TURN,
|
||||||
offset = -armThick,
|
offset = -armThick,
|
||||||
intersectTag = seg02
|
intersectTag = seg02
|
||||||
}, %)
|
}, %)
|
||||||
|> angledLineToY([segAng(seg02) + 180, -baseHeight], %)
|
|> angledLineToY([segAng(seg02) + 180, -baseHeight], %)
|
||||||
|> xLine(endAbsolute = ZERO)
|
|> xLine(endAbsolute = turns::ZERO)
|
||||||
|> close()
|
|> close()
|
||||||
|> extrude(length = 4)`
|
|> extrude(length = 4)`
|
||||||
)
|
)
|
||||||
|
@ -41,6 +41,8 @@ When you submit a PR to add or modify KCL samples, images and STEP files will be
|
|||||||
[](cycloidal-gear/main.kcl)
|
[](cycloidal-gear/main.kcl)
|
||||||
#### [dodecahedron](dodecahedron/main.kcl) ([screenshot](screenshots/dodecahedron.png))
|
#### [dodecahedron](dodecahedron/main.kcl) ([screenshot](screenshots/dodecahedron.png))
|
||||||
[](dodecahedron/main.kcl)
|
[](dodecahedron/main.kcl)
|
||||||
|
#### [dual-basin-utility-sink](dual-basin-utility-sink/main.kcl) ([screenshot](screenshots/dual-basin-utility-sink.png))
|
||||||
|
[](dual-basin-utility-sink/main.kcl)
|
||||||
#### [enclosure](enclosure/main.kcl) ([screenshot](screenshots/enclosure.png))
|
#### [enclosure](enclosure/main.kcl) ([screenshot](screenshots/enclosure.png))
|
||||||
[](enclosure/main.kcl)
|
[](enclosure/main.kcl)
|
||||||
#### [exhaust-manifold](exhaust-manifold/main.kcl) ([screenshot](screenshots/exhaust-manifold.png))
|
#### [exhaust-manifold](exhaust-manifold/main.kcl) ([screenshot](screenshots/exhaust-manifold.png))
|
||||||
@ -75,6 +77,8 @@ When you submit a PR to add or modify KCL samples, images and STEP files will be
|
|||||||
[](kitt/main.kcl)
|
[](kitt/main.kcl)
|
||||||
#### [lego](lego/main.kcl) ([screenshot](screenshots/lego.png))
|
#### [lego](lego/main.kcl) ([screenshot](screenshots/lego.png))
|
||||||
[](lego/main.kcl)
|
[](lego/main.kcl)
|
||||||
|
#### [makeup-mirror](makeup-mirror/main.kcl) ([screenshot](screenshots/makeup-mirror.png))
|
||||||
|
[](makeup-mirror/main.kcl)
|
||||||
#### [mounting-plate](mounting-plate/main.kcl) ([screenshot](screenshots/mounting-plate.png))
|
#### [mounting-plate](mounting-plate/main.kcl) ([screenshot](screenshots/mounting-plate.png))
|
||||||
[](mounting-plate/main.kcl)
|
[](mounting-plate/main.kcl)
|
||||||
#### [multi-axis-robot](multi-axis-robot/main.kcl) ([screenshot](screenshots/multi-axis-robot.png))
|
#### [multi-axis-robot](multi-axis-robot/main.kcl) ([screenshot](screenshots/multi-axis-robot.png))
|
||||||
|
@ -35,7 +35,7 @@ ballsSketch = startSketchOn(XY)
|
|||||||
|> close()
|
|> close()
|
||||||
|
|
||||||
// Revolve the ball to make a sphere and pattern around the inside wall
|
// Revolve the ball to make a sphere and pattern around the inside wall
|
||||||
balls = revolve(ballsSketch, axis = "X")
|
balls = revolve(ballsSketch, axis = X)
|
||||||
|> patternCircular3d(
|
|> patternCircular3d(
|
||||||
arcDegrees = 360,
|
arcDegrees = 360,
|
||||||
axis = [0, 0, 1],
|
axis = [0, 0, 1],
|
||||||
@ -60,7 +60,7 @@ chainSketch = startSketchOn(XY)
|
|||||||
|> close()
|
|> close()
|
||||||
|
|
||||||
// Revolve the chain sketch
|
// Revolve the chain sketch
|
||||||
chainHead = revolve(chainSketch, axis = "X")
|
chainHead = revolve(chainSketch, axis = X)
|
||||||
|> patternCircular3d(
|
|> patternCircular3d(
|
||||||
arcDegrees = 360,
|
arcDegrees = 360,
|
||||||
axis = [0, 0, 1],
|
axis = [0, 0, 1],
|
||||||
@ -80,7 +80,7 @@ linkSketch = startSketchOn(XZ)
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Revolve the link sketch
|
// Revolve the link sketch
|
||||||
linkRevolve = revolve(linkSketch, axis = 'Y', angle = 360 / nBalls)
|
linkRevolve = revolve(linkSketch, axis = Y, angle = 360 / nBalls)
|
||||||
|> patternCircular3d(
|
|> patternCircular3d(
|
||||||
arcDegrees = 360,
|
arcDegrees = 360,
|
||||||
axis = [0, 0, 1],
|
axis = [0, 0, 1],
|
||||||
|
@ -80,5 +80,5 @@ brakeCaliperSketch = startSketchOn(XY)
|
|||||||
|> close()
|
|> close()
|
||||||
|
|
||||||
// Revolve the brake caliper sketch
|
// Revolve the brake caliper sketch
|
||||||
revolve(brakeCaliperSketch, axis = "Y", angle = -70)
|
revolve(brakeCaliperSketch, axis = Y, angle = -70)
|
||||||
|> appearance(color = "#c82d2d", metalness = 90, roughness = 90)
|
|> appearance(color = "#c82d2d", metalness = 90, roughness = 90)
|
||||||
|
@ -41,5 +41,5 @@ tireSketch = startSketchOn(XY)
|
|||||||
|> close()
|
|> close()
|
||||||
|
|
||||||
// Revolve the sketch to create the tire
|
// Revolve the sketch to create the tire
|
||||||
revolve(tireSketch, axis = "Y")
|
revolve(tireSketch, axis = Y)
|
||||||
|> appearance(color = "#0f0f0f", roughness = 80)
|
|> appearance(color = "#0f0f0f", roughness = 80)
|
||||||
|
@ -54,7 +54,7 @@ wheelCenterInner = startSketchOn(XY)
|
|||||||
|> yLine(endAbsolute = 0)
|
|> yLine(endAbsolute = 0)
|
||||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = 'y')
|
|> revolve(axis = Y)
|
||||||
|> appearance(color = "#ffffff", metalness = 0, roughness = 0)
|
|> appearance(color = "#ffffff", metalness = 0, roughness = 0)
|
||||||
|
|
||||||
wheelCenterOuter = startSketchOn(XY)
|
wheelCenterOuter = startSketchOn(XY)
|
||||||
@ -68,7 +68,7 @@ wheelCenterOuter = startSketchOn(XY)
|
|||||||
|> yLine(endAbsolute = -wheelWidth / 20)
|
|> yLine(endAbsolute = -wheelWidth / 20)
|
||||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = 'y')
|
|> revolve(axis = Y)
|
||||||
|> appearance(color = "#ffffff", metalness = 0, roughness = 0)
|
|> appearance(color = "#ffffff", metalness = 0, roughness = 0)
|
||||||
|
|
||||||
// Write a function that defines the spoke geometry, patterns and extrudes it
|
// Write a function that defines the spoke geometry, patterns and extrudes it
|
||||||
@ -173,5 +173,5 @@ startSketchOn(XY)
|
|||||||
|> xLine(length = wheelWidth * 0.03)
|
|> xLine(length = wheelWidth * 0.03)
|
||||||
|> yLine(length = wheelWidth * 0.05)
|
|> yLine(length = wheelWidth * 0.05)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = 'y')
|
|> revolve(axis = Y)
|
||||||
|> appearance(color = "#ffffff", metalness = 0, roughness = 0)
|
|> appearance(color = "#ffffff", metalness = 0, roughness = 0)
|
||||||
|
@ -32,7 +32,7 @@ fn lug(plane, length, diameter) {
|
|||||||
|> xLine(endAbsolute = lugThreadDiameter)
|
|> xLine(endAbsolute = lugThreadDiameter)
|
||||||
|> yLine(endAbsolute = 0)
|
|> yLine(endAbsolute = 0)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = "Y")
|
|> revolve(axis = Y)
|
||||||
|> appearance(color = "#dbcd70", roughness = 90, metalness = 90)
|
|> appearance(color = "#dbcd70", roughness = 90, metalness = 90)
|
||||||
return lugSketch
|
return lugSketch
|
||||||
}
|
}
|
||||||
|
200
public/kcl-samples/dual-basin-utility-sink/main.kcl
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
// Dual-Basin Utility Sink
|
||||||
|
// A stainless steel sink unit with dual rectangular basins and six under-counter storage compartments.
|
||||||
|
|
||||||
|
@settings(defaultLengthUnit = mm)
|
||||||
|
|
||||||
|
// globals
|
||||||
|
tableHeight = 850
|
||||||
|
tableWidth = 3400
|
||||||
|
tableDepth = 400
|
||||||
|
|
||||||
|
profileThickness = 13
|
||||||
|
metalThickness = 2
|
||||||
|
|
||||||
|
blockCount = 3
|
||||||
|
blockWidth = (tableWidth-profileThickness) / 3
|
||||||
|
blockHeight = tableHeight - metalThickness - 0.5
|
||||||
|
blockDepth = tableDepth - profileThickness
|
||||||
|
|
||||||
|
blockSubdivisionCount = 2
|
||||||
|
blockSubdivisionWidth = blockWidth / blockSubdivisionCount
|
||||||
|
|
||||||
|
// Geometry
|
||||||
|
floorPlane = startSketchOn(XY)
|
||||||
|
|
||||||
|
// legs
|
||||||
|
legHeight = blockHeight - profileThickness
|
||||||
|
legCount = blockCount + 1
|
||||||
|
|
||||||
|
legBody = startProfileAt([0, 0], floorPlane)
|
||||||
|
|> yLine(length=profileThickness)
|
||||||
|
|> xLine(length=profileThickness)
|
||||||
|
|> yLine(length=-profileThickness)
|
||||||
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
|> close()
|
||||||
|
|> patternLinear2d(axis = [1, 0], instances = legCount, distance = blockWidth)
|
||||||
|
|> patternLinear2d(axis = [0, 1], instances = 2, distance = blockDepth)
|
||||||
|
|> extrude(length = legHeight)
|
||||||
|
|
||||||
|
// lower belt
|
||||||
|
lowerBeltHeightAboveTheFloor = 150
|
||||||
|
lowerBeltLengthX = blockWidth - profileThickness
|
||||||
|
|
||||||
|
lowerBeltPlane = startSketchOn(offsetPlane(XY, offset = lowerBeltHeightAboveTheFloor))
|
||||||
|
lowerBeltBodyX = startProfileAt([profileThickness, 0], lowerBeltPlane)
|
||||||
|
|> yLine(length=profileThickness)
|
||||||
|
|> xLine(length=lowerBeltLengthX)
|
||||||
|
|> yLine(length=-profileThickness)
|
||||||
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
|> close()
|
||||||
|
|> patternLinear2d(axis = [1, 0], instances = blockCount, distance = blockWidth)
|
||||||
|
|> patternLinear2d(axis = [0, 1], instances = 2, distance = blockDepth)
|
||||||
|
|> extrude(length = profileThickness)
|
||||||
|
|
||||||
|
lowerBeltLengthY = blockDepth - profileThickness
|
||||||
|
lowerBeltBodyY = startProfileAt([0, profileThickness], lowerBeltPlane)
|
||||||
|
|> yLine(length=lowerBeltLengthY)
|
||||||
|
|> xLine(length=profileThickness)
|
||||||
|
|> yLine(length=-lowerBeltLengthY)
|
||||||
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
|> close()
|
||||||
|
|> patternLinear2d(axis = [1, 0], instances = 2, distance = tableWidth-profileThickness)
|
||||||
|
|> extrude(length = profileThickness)
|
||||||
|
|
||||||
|
// pillars
|
||||||
|
pillarHeightAboveTheFloor = lowerBeltHeightAboveTheFloor + profileThickness
|
||||||
|
pillarPlane = startSketchOn(offsetPlane(XY, offset = pillarHeightAboveTheFloor))
|
||||||
|
pillarTotalHeight = blockHeight - profileThickness - pillarHeightAboveTheFloor
|
||||||
|
|
||||||
|
pillarBody = startProfileAt([blockSubdivisionWidth, 0], pillarPlane)
|
||||||
|
|> yLine(length=profileThickness)
|
||||||
|
|> xLine(length=profileThickness)
|
||||||
|
|> yLine(length=-profileThickness)
|
||||||
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
|> close()
|
||||||
|
|> patternLinear2d(axis = [1, 0], instances = blockCount, distance = blockWidth)
|
||||||
|
|> patternLinear2d(axis = [0, 1], instances = 2, distance = blockDepth)
|
||||||
|
|> extrude(length = pillarTotalHeight)
|
||||||
|
|
||||||
|
// upper belt
|
||||||
|
upperBeltPlane = startSketchOn(offsetPlane(XY, offset = blockHeight))
|
||||||
|
|
||||||
|
upperBeltBodyX = startProfileAt([0, 0], upperBeltPlane)
|
||||||
|
|> yLine(length=profileThickness)
|
||||||
|
|> xLine(length=tableWidth)
|
||||||
|
|> yLine(length=-profileThickness)
|
||||||
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
|> close()
|
||||||
|
|> patternLinear2d(axis = [0, 1], instances = 2, distance = blockDepth)
|
||||||
|
|> extrude(length = -profileThickness)
|
||||||
|
|
||||||
|
upperBeltLengthY = blockDepth - profileThickness
|
||||||
|
upperBeltBodyY = startProfileAt([0, profileThickness], upperBeltPlane)
|
||||||
|
|> yLine(length=upperBeltLengthY)
|
||||||
|
|> xLine(length=profileThickness)
|
||||||
|
|> yLine(length=-upperBeltLengthY)
|
||||||
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
|> close()
|
||||||
|
|> patternLinear2d(axis = [1, 0], instances = 2, distance = tableWidth-profileThickness)
|
||||||
|
|> extrude(length = -profileThickness)
|
||||||
|
|
||||||
|
// sink
|
||||||
|
tableTopPlane = startSketchOn(offsetPlane(XY, offset = tableHeight))
|
||||||
|
tableTopBody = startProfileAt([0, 0], tableTopPlane)
|
||||||
|
|> yLine(length=tableDepth)
|
||||||
|
|> xLine(length=tableWidth)
|
||||||
|
|> yLine(length=-tableDepth)
|
||||||
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
|> close()
|
||||||
|
|> extrude(length = -metalThickness)
|
||||||
|
|
||||||
|
sinkCount = 2
|
||||||
|
sinkWidth = 1000
|
||||||
|
sinkLength = 250
|
||||||
|
sinkDepth = 200
|
||||||
|
sinkOffsetFront = 40
|
||||||
|
sinkOffsetLeft = 350
|
||||||
|
sinkSpacing = tableWidth - sinkWidth - sinkOffsetLeft*2
|
||||||
|
|
||||||
|
sinkPlaneOutside = startSketchOn(tableTopBody, 'START')
|
||||||
|
sinkBodyOutside = startProfileAt([-sinkOffsetLeft, sinkOffsetFront], sinkPlaneOutside)
|
||||||
|
|> yLine(length=sinkLength)
|
||||||
|
|> xLine(length=-sinkWidth)
|
||||||
|
|> yLine(length=-sinkLength)
|
||||||
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
|> close()
|
||||||
|
|> patternLinear2d(axis = [-1, 0], instances = sinkCount, distance = sinkSpacing)
|
||||||
|
|> extrude(length = sinkDepth)
|
||||||
|
|
||||||
|
sinkPlaneInside = startSketchOn(tableTopBody, 'END')
|
||||||
|
sinkBodyInside = startProfileAt([sinkOffsetLeft+metalThickness, sinkOffsetFront+metalThickness], sinkPlaneInside)
|
||||||
|
|> yLine(length=sinkLength-metalThickness*2)
|
||||||
|
|> xLine(length=sinkWidth-metalThickness*2)
|
||||||
|
|> yLine(length=-sinkLength+metalThickness*2)
|
||||||
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
|> close()
|
||||||
|
|> patternLinear2d(axis = [1, 0], instances = sinkCount, distance = sinkSpacing)
|
||||||
|
|> extrude(length = -sinkDepth)
|
||||||
|
|
||||||
|
// door panels
|
||||||
|
doorGap = 2
|
||||||
|
doorWidth = blockSubdivisionWidth - profileThickness - doorGap*2
|
||||||
|
doorStart = profileThickness+doorGap
|
||||||
|
doorHeightAboveTheFloor = pillarHeightAboveTheFloor + doorGap
|
||||||
|
doorHeight = blockHeight - doorHeightAboveTheFloor - profileThickness - doorGap
|
||||||
|
doorCount = blockCount * blockSubdivisionCount
|
||||||
|
|
||||||
|
doorPlane = startSketchOn(offsetPlane(XY, offset = doorHeightAboveTheFloor))
|
||||||
|
doorBody = startProfileAt([doorStart, 0], doorPlane)
|
||||||
|
|> yLine(length=profileThickness)
|
||||||
|
|> xLine(length=doorWidth)
|
||||||
|
|> yLine(length=-profileThickness)
|
||||||
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
|> close()
|
||||||
|
|> patternLinear2d(axis = [1, 0], instances = doorCount, distance = blockSubdivisionWidth)
|
||||||
|
|> extrude(length = doorHeight)
|
||||||
|
|
||||||
|
// side panels
|
||||||
|
panelWidth = blockDepth - profileThickness - doorGap*2
|
||||||
|
panelCount = doorCount + 1
|
||||||
|
panelSpacing = tableWidth - profileThickness
|
||||||
|
panelBody = startProfileAt([0, doorStart], doorPlane)
|
||||||
|
|> yLine(length=panelWidth)
|
||||||
|
|> xLine(length=profileThickness)
|
||||||
|
|> yLine(length=-panelWidth)
|
||||||
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
|> close()
|
||||||
|
|> patternLinear2d(axis = [1, 0], instances = 2, distance = panelSpacing)
|
||||||
|
|> extrude(length = doorHeight)
|
||||||
|
|
||||||
|
// handle
|
||||||
|
handleDepth = 40
|
||||||
|
handleWidth = 120
|
||||||
|
handleFillet = 20
|
||||||
|
handleHeightAboveTheFloor = 780
|
||||||
|
handleOffset = doorStart + doorWidth / 2 - (handleWidth / 2)
|
||||||
|
handleLengthSegmentA = handleDepth - handleFillet
|
||||||
|
handleLengthSegmentB = handleWidth - (handleFillet * 2)
|
||||||
|
|
||||||
|
handlePlane = startSketchOn(offsetPlane(XY, offset = handleHeightAboveTheFloor))
|
||||||
|
|
||||||
|
handleProfilePath = startProfileAt([0 + handleOffset, 0], handlePlane)
|
||||||
|
|> yLine(length=-handleLengthSegmentA)
|
||||||
|
|> tangentialArcTo([
|
||||||
|
handleFillet + handleOffset,
|
||||||
|
-handleDepth
|
||||||
|
], %)
|
||||||
|
|> xLine(length=handleLengthSegmentB)
|
||||||
|
|> tangentialArcTo([
|
||||||
|
handleOffset + handleWidth,
|
||||||
|
-handleLengthSegmentA
|
||||||
|
], %)
|
||||||
|
|> yLine(length=handleLengthSegmentA)
|
||||||
|
handleSectionPlane = startSketchOn(XZ)
|
||||||
|
handleProfileSection = circle(
|
||||||
|
handleSectionPlane,
|
||||||
|
center = [handleOffset, handleHeightAboveTheFloor],
|
||||||
|
radius = 2)
|
||||||
|
|
||||||
|
handleBody = sweep(handleProfileSection, path = handleProfilePath)
|
||||||
|
|> patternLinear3d(axis = [1, 0, 0], instances = doorCount, distance = blockSubdivisionWidth)
|
@ -23,7 +23,7 @@ sketch001 = startSketchOn(XZ)
|
|||||||
], %, $rectangleSegmentC001)
|
], %, $rectangleSegmentC001)
|
||||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(angle = 360, axis = 'Y')
|
|> revolve(angle = 360, axis = Y)
|
||||||
|
|
||||||
// Create an angled plane to sketch the supports
|
// Create an angled plane to sketch the supports
|
||||||
plane001 = {
|
plane001 = {
|
||||||
@ -132,7 +132,7 @@ sketch005 = startSketchOn(XZ)
|
|||||||
|> xLine(endAbsolute = 0.15)
|
|> xLine(endAbsolute = 0.15)
|
||||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = 'y')
|
|> revolve(axis = Y)
|
||||||
|
|
||||||
// Plunger and stem
|
// Plunger and stem
|
||||||
sketch006 = startSketchOn(XZ)
|
sketch006 = startSketchOn(XZ)
|
||||||
@ -145,7 +145,7 @@ sketch006 = startSketchOn(XZ)
|
|||||||
|> tangentialArc({ radius = 0.6, offset = -90 }, %)
|
|> tangentialArc({ radius = 0.6, offset = -90 }, %)
|
||||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = 'y')
|
|> revolve(axis = Y)
|
||||||
|
|
||||||
// Spiral plate
|
// Spiral plate
|
||||||
sketch007 = startSketchOn(offsetPlane(XY, offset = 1.12))
|
sketch007 = startSketchOn(offsetPlane(XY, offset = 1.12))
|
||||||
@ -201,7 +201,7 @@ sketch011 = startSketchOn(XZ)
|
|||||||
}, %)
|
}, %)
|
||||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = 'y')
|
|> revolve(axis = Y)
|
||||||
|
|
||||||
// Draw and extrude handle
|
// Draw and extrude handle
|
||||||
sketch012 = startSketchOn(offsetPlane(XZ, offset = handleThickness / 2))
|
sketch012 = startSketchOn(offsetPlane(XZ, offset = handleThickness / 2))
|
||||||
|
@ -48,11 +48,9 @@ sides = patternCircular3d(
|
|||||||
|
|
||||||
// define an axis axis000
|
// define an axis axis000
|
||||||
axis000 = {
|
axis000 = {
|
||||||
custom = {
|
direction = [0.0, 1.0],
|
||||||
axis = [0.0, 1.0],
|
|
||||||
origin = [cornerRadius, cornerRadius]
|
origin = [cornerRadius, cornerRadius]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// create a single corner of the bin
|
// create a single corner of the bin
|
||||||
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius)), angle = -90, axis = axis000)
|
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius)), angle = -90, axis = axis000)
|
||||||
|
@ -45,11 +45,9 @@ sides = patternCircular3d(
|
|||||||
|
|
||||||
// define an axis axis000
|
// define an axis axis000
|
||||||
axis000 = {
|
axis000 = {
|
||||||
custom = {
|
direction = [0.0, 1.0],
|
||||||
axis = [0.0, 1.0],
|
|
||||||
origin = [cornerRadius, cornerRadius]
|
origin = [cornerRadius, cornerRadius]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// create a single corner of the bin
|
// create a single corner of the bin
|
||||||
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius)), angle = -90, axis = axis000)
|
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius)), angle = -90, axis = axis000)
|
||||||
|
@ -65,14 +65,12 @@ sides = patternCircular3d(
|
|||||||
|
|
||||||
// define an axis axis000
|
// define an axis axis000
|
||||||
axis000 = {
|
axis000 = {
|
||||||
custom = {
|
direction = [0.0, 1.0],
|
||||||
axis = [0.0, 1.0],
|
|
||||||
origin = [
|
origin = [
|
||||||
cornerRadius + binTol,
|
cornerRadius + binTol,
|
||||||
cornerRadius + binTol
|
cornerRadius + binTol
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// create a single corner of the bin
|
// create a single corner of the bin
|
||||||
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius + binTol)), angle = -90, axis = axis000)
|
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius + binTol)), angle = -90, axis = axis000)
|
||||||
@ -272,11 +270,9 @@ lipWidths = patternCircular3d(
|
|||||||
|
|
||||||
// define an axis axis000
|
// define an axis axis000
|
||||||
axis001 = {
|
axis001 = {
|
||||||
custom = {
|
direction = [0.0, 1.0],
|
||||||
axis = [0.0, 1.0],
|
|
||||||
origin = [cornerRadius, cornerRadius]
|
origin = [cornerRadius, cornerRadius]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// create a single corner of the bin
|
// create a single corner of the bin
|
||||||
lipSingleLengthCorner = revolve(lipFace(plane000), angle = -90, axis = axis001)
|
lipSingleLengthCorner = revolve(lipFace(plane000), angle = -90, axis = axis001)
|
||||||
|
@ -58,14 +58,12 @@ sides = patternCircular3d(
|
|||||||
|
|
||||||
// define an axis axis000
|
// define an axis axis000
|
||||||
axis000 = {
|
axis000 = {
|
||||||
custom = {
|
direction = [0.0, 1.0],
|
||||||
axis = [0.0, 1.0],
|
|
||||||
origin = [
|
origin = [
|
||||||
cornerRadius + binTol,
|
cornerRadius + binTol,
|
||||||
cornerRadius + binTol
|
cornerRadius + binTol
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// create a single corner of the bin
|
// create a single corner of the bin
|
||||||
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius + binTol)), angle = -90, axis = axis000)
|
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius + binTol)), angle = -90, axis = axis000)
|
||||||
|
@ -20,6 +20,6 @@ sketch001 = startSketchOn(-XZ)
|
|||||||
|> xLine(endAbsolute = webThickness / 2 + rootRadius)
|
|> xLine(endAbsolute = webThickness / 2 + rootRadius)
|
||||||
|> tangentialArc({ radius = rootRadius, offset = 90 }, %)
|
|> tangentialArc({ radius = rootRadius, offset = 90 }, %)
|
||||||
|> yLine(endAbsolute = 0)
|
|> yLine(endAbsolute = 0)
|
||||||
|> mirror2d({ axis = 'X' }, %)
|
|> mirror2d(axis = X)
|
||||||
|> mirror2d({ axis = 'Y' }, %)
|
|> mirror2d(axis = Y)
|
||||||
|> extrude(length = beamLength)
|
|> extrude(length = beamLength)
|
||||||
|
75
public/kcl-samples/makeup-mirror/main.kcl
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// Makeup Mirror
|
||||||
|
// A circular vanity mirror mounted on a swiveling arm with pivot joints, used for personal grooming.
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
@settings(defaultLengthUnit = mm)
|
||||||
|
|
||||||
|
// hinge
|
||||||
|
hingeRadius = 8
|
||||||
|
hingeHeight = hingeRadius * 3
|
||||||
|
hingeGap = 0.5
|
||||||
|
|
||||||
|
// arm
|
||||||
|
armLength = 170
|
||||||
|
armRadius = 5
|
||||||
|
|
||||||
|
// mirror
|
||||||
|
mirrorRadius = 170 / 2
|
||||||
|
mirrorThickness = 10
|
||||||
|
archToMirrorGap = 5
|
||||||
|
archThickness = 1
|
||||||
|
archRadius = mirrorRadius + archToMirrorGap
|
||||||
|
|
||||||
|
// Geometry
|
||||||
|
// hinge
|
||||||
|
fn hingeFn(x, y, z) {
|
||||||
|
hingeBody = startSketchOn(offsetPlane(XY, offset = z))
|
||||||
|
|> circle(center = [x, y], radius = hingeRadius)
|
||||||
|
|> extrude(length = hingeHeight)
|
||||||
|
return hingeBody
|
||||||
|
}
|
||||||
|
|
||||||
|
hingePartA1 = hingeFn(0, 0, 0)
|
||||||
|
hingePartA2 = hingeFn(0, 0, hingeHeight + hingeGap)
|
||||||
|
hingePartA3 = hingeFn(0, 0, hingeHeight * 2 + hingeGap * 2)
|
||||||
|
|
||||||
|
hingePartB2 = hingeFn(armLength, 0, hingeHeight + hingeGap)
|
||||||
|
hingePartB3 = hingeFn(armLength, 0, hingeHeight * 2 + hingeGap * 2)
|
||||||
|
|
||||||
|
hingePartC2 = hingeFn(armLength, -armLength, hingeHeight * 2 + hingeGap * 2)
|
||||||
|
hingePartC3 = hingeFn(armLength, -armLength, hingeHeight * 3 + hingeGap * 3)
|
||||||
|
|
||||||
|
// arm
|
||||||
|
fn armFn(plane, offset, altitude) {
|
||||||
|
armBody = startSketchOn(plane)
|
||||||
|
|> circle(center = [offset, altitude], radius = armRadius)
|
||||||
|
|> extrude(length = armLength)
|
||||||
|
return armBody
|
||||||
|
}
|
||||||
|
|
||||||
|
armPartA = armFn(YZ, 0, hingeHeight * 1.5 + hingeGap)
|
||||||
|
armPartB = armFn(XZ, armLength, hingeHeight * 2.5 + hingeGap * 2)
|
||||||
|
|
||||||
|
// mirror
|
||||||
|
fn mirrorFn(plane, offsetX, offsetY, altitude, radius, tiefe, gestellR, gestellD) {
|
||||||
|
armPlane = startSketchOn(offsetPlane(plane, offset = offsetY - (tiefe / 2)))
|
||||||
|
armBody = circle(armPlane, center = [offsetX, altitude], radius = radius)
|
||||||
|
|> extrude(length = tiefe)
|
||||||
|
|
||||||
|
archBody = startProfileAt([offsetX-gestellR, altitude], armPlane)
|
||||||
|
|> xLine(length = gestellD)
|
||||||
|
|> arcTo({
|
||||||
|
interior = [offsetX, altitude-gestellR],
|
||||||
|
end = [offsetX+gestellR, altitude]
|
||||||
|
}, %)
|
||||||
|
|> xLine(length = gestellD)
|
||||||
|
|> arcTo({
|
||||||
|
interior = [offsetX, altitude-gestellR-gestellD],
|
||||||
|
end = [profileStartX(%), profileStartY(%)]
|
||||||
|
}, %)
|
||||||
|
|> close()
|
||||||
|
|> extrude(length = tiefe)
|
||||||
|
return armBody
|
||||||
|
}
|
||||||
|
|
||||||
|
mirror = mirrorFn(XZ, armLength, armLength, hingeHeight * 4 + hingeGap * 3 + mirrorRadius+archToMirrorGap+archThickness, mirrorRadius, mirrorThickness, archRadius, archThickness)
|
@ -62,6 +62,13 @@
|
|||||||
"title": "Hollow Dodecahedron",
|
"title": "Hollow Dodecahedron",
|
||||||
"description": "A regular dodecahedron or pentagonal dodecahedron is a dodecahedron composed of regular pentagonal faces, three meeting at each vertex. This example shows constructing the individual faces of the dodecahedron and extruding inwards."
|
"description": "A regular dodecahedron or pentagonal dodecahedron is a dodecahedron composed of regular pentagonal faces, three meeting at each vertex. This example shows constructing the individual faces of the dodecahedron and extruding inwards."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"file": "main.kcl",
|
||||||
|
"pathFromProjectDirectoryToFirstFile": "dual-basin-utility-sink/main.kcl",
|
||||||
|
"multipleFiles": false,
|
||||||
|
"title": "Dual-Basin Utility Sink",
|
||||||
|
"description": "A stainless steel sink unit with dual rectangular basins and six under-counter storage compartments."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"file": "main.kcl",
|
"file": "main.kcl",
|
||||||
"pathFromProjectDirectoryToFirstFile": "enclosure/main.kcl",
|
"pathFromProjectDirectoryToFirstFile": "enclosure/main.kcl",
|
||||||
@ -181,6 +188,13 @@
|
|||||||
"title": "Lego Brick",
|
"title": "Lego Brick",
|
||||||
"description": "A standard Lego brick. This is a small, plastic construction block toy that can be interlocked with other blocks to build various structures, models, and figures. There are a lot of hacks used in this code."
|
"description": "A standard Lego brick. This is a small, plastic construction block toy that can be interlocked with other blocks to build various structures, models, and figures. There are a lot of hacks used in this code."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"file": "main.kcl",
|
||||||
|
"pathFromProjectDirectoryToFirstFile": "makeup-mirror/main.kcl",
|
||||||
|
"multipleFiles": false,
|
||||||
|
"title": "Makeup Mirror",
|
||||||
|
"description": "A circular vanity mirror mounted on a swiveling arm with pivot joints, used for personal grooming."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"file": "main.kcl",
|
"file": "main.kcl",
|
||||||
"pathFromProjectDirectoryToFirstFile": "mounting-plate/main.kcl",
|
"pathFromProjectDirectoryToFirstFile": "mounting-plate/main.kcl",
|
||||||
|
@ -24,4 +24,4 @@ pipeProfile = outerProfile
|
|||||||
|> hole(innerProfile, %)
|
|> hole(innerProfile, %)
|
||||||
|
|
||||||
// revolve the pipe profile at the desired angle
|
// revolve the pipe profile at the desired angle
|
||||||
pipe = revolve(pipeProfile, axis = 'Y', angle = bendAngle)
|
pipe = revolve(pipeProfile, axis = Y, angle = bendAngle)
|
||||||
|
@ -33,4 +33,4 @@ pipeSketch = startSketchOn(XY)
|
|||||||
|> close()
|
|> close()
|
||||||
|
|
||||||
// Revolve the sketch to create the pipe
|
// Revolve the sketch to create the pipe
|
||||||
pipe = revolve(pipeSketch, axis = 'y')
|
pipe = revolve(pipeSketch, axis = Y)
|
||||||
|
@ -34,10 +34,8 @@ part001 = revolve(
|
|||||||
sketch001,
|
sketch001,
|
||||||
angle = 90,
|
angle = 90,
|
||||||
axis = {
|
axis = {
|
||||||
custom = {
|
direction = [1.0, 0.0],
|
||||||
axis = [1.0, 0.0],
|
|
||||||
origin = [0.0, height + .0001]
|
origin = [0.0, height + .0001]
|
||||||
}
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ radius = 10
|
|||||||
depth = 30
|
depth = 30
|
||||||
distanceToInsideEdge = slateWidthHalf + templateThickness + templateGap
|
distanceToInsideEdge = slateWidthHalf + templateThickness + templateGap
|
||||||
sketch001 = startSketchOn(XZ)
|
sketch001 = startSketchOn(XZ)
|
||||||
|> startProfileAt([ZERO, depth + templateGap], %)
|
|> startProfileAt([turns::ZERO, depth + templateGap], %)
|
||||||
|> xLine(length = slateWidthHalf - radius, tag = $seg01)
|
|> xLine(length = slateWidthHalf - radius, tag = $seg01)
|
||||||
|> arc({
|
|> arc({
|
||||||
angleEnd = 0,
|
angleEnd = 0,
|
||||||
@ -28,7 +28,7 @@ sketch001 = startSketchOn(XZ)
|
|||||||
|> yLine(length = templateThickness * 2, tag = $seg08)
|
|> yLine(length = templateThickness * 2, tag = $seg08)
|
||||||
|> xLine(endAbsolute = segEndX(seg02) + 0, tag = $seg05)
|
|> xLine(endAbsolute = segEndX(seg02) + 0, tag = $seg05)
|
||||||
|> yLine(endAbsolute = segEndY(seg01) + templateThickness, tag = $seg10)
|
|> yLine(endAbsolute = segEndY(seg01) + templateThickness, tag = $seg10)
|
||||||
|> xLine(endAbsolute = ZERO, tag = $seg04)
|
|> xLine(endAbsolute = turns::ZERO, tag = $seg04)
|
||||||
|> xLine(length = -segLen(seg04))
|
|> xLine(length = -segLen(seg04))
|
||||||
|> yLine(length = -segLen(seg10))
|
|> yLine(length = -segLen(seg10))
|
||||||
|> xLine(length = -segLen(seg05))
|
|> xLine(length = -segLen(seg05))
|
||||||
|
@ -28,7 +28,7 @@ sketch001 = startSketchOn(XZ)
|
|||||||
|> yLine(endAbsolute = -templateGap * 2 - (templateDiameter / 2), tag = $seg05)
|
|> yLine(endAbsolute = -templateGap * 2 - (templateDiameter / 2), tag = $seg05)
|
||||||
|> xLine(endAbsolute = slateWidthHalf + templateThickness, tag = $seg04)
|
|> xLine(endAbsolute = slateWidthHalf + templateThickness, tag = $seg04)
|
||||||
|> yLine(length = -length002, tag = $seg03)
|
|> yLine(length = -length002, tag = $seg03)
|
||||||
|> xLine(endAbsolute = ZERO, tag = $seg02)
|
|> xLine(endAbsolute = turns::ZERO, tag = $seg02)
|
||||||
// |> line(end = [7.78, 11.16])
|
// |> line(end = [7.78, 11.16])
|
||||||
|> xLine(length = -segLen(seg02))
|
|> xLine(length = -segLen(seg02))
|
||||||
|> yLine(length = segLen(seg03))
|
|> yLine(length = segLen(seg03))
|
||||||
|
BIN
public/kcl-samples/screenshots/dual-basin-utility-sink.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
public/kcl-samples/screenshots/makeup-mirror.png
Normal file
After Width: | Height: | Size: 62 KiB |
@ -21,7 +21,7 @@ export fn knob() {
|
|||||||
}, %)
|
}, %)
|
||||||
|> xLine(endAbsolute = 0.0001)
|
|> xLine(endAbsolute = 0.0001)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = "Y")
|
|> revolve(axis = Y)
|
||||||
|> appearance(color = '#D0FF01', metalness = 90, roughness = 50)
|
|> appearance(color = '#D0FF01', metalness = 90, roughness = 50)
|
||||||
|
|
||||||
return knob
|
return knob
|
||||||
|
@ -876,7 +876,7 @@ async fn kcl_test_simple_revolve() {
|
|||||||
|> line(end = [0, -5.5])
|
|> line(end = [0, -5.5])
|
||||||
|> line(end = [-2, 0])
|
|> line(end = [-2, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = 'y')
|
|> revolve(axis = Y)
|
||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@ -896,7 +896,7 @@ async fn kcl_test_simple_revolve_uppercase() {
|
|||||||
|> line(end = [0, -5.5])
|
|> line(end = [0, -5.5])
|
||||||
|> line(end = [-2, 0])
|
|> line(end = [-2, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = 'Y')
|
|> revolve(axis = Y)
|
||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@ -916,7 +916,7 @@ async fn kcl_test_simple_revolve_negative() {
|
|||||||
|> line(end = [0, -5.5])
|
|> line(end = [0, -5.5])
|
||||||
|> line(end = [-2, 0])
|
|> line(end = [-2, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = '-Y', angle = 180)
|
|> revolve(axis = -Y, angle = 180)
|
||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@ -936,7 +936,7 @@ async fn kcl_test_revolve_bad_angle_low() {
|
|||||||
|> line(end = [0, -5.5])
|
|> line(end = [0, -5.5])
|
||||||
|> line(end = [-2, 0])
|
|> line(end = [-2, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = 'y', angle = -455)
|
|> revolve(axis = Y, angle = -455)
|
||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@ -962,7 +962,7 @@ async fn kcl_test_revolve_bad_angle_high() {
|
|||||||
|> line(end = [0, -5.5])
|
|> line(end = [0, -5.5])
|
||||||
|> line(end = [-2, 0])
|
|> line(end = [-2, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = 'y', angle = 455)
|
|> revolve(axis = Y, angle = 455)
|
||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@ -988,7 +988,7 @@ async fn kcl_test_simple_revolve_custom_angle() {
|
|||||||
|> line(end = [0, -5.5])
|
|> line(end = [0, -5.5])
|
||||||
|> line(end = [-2, 0])
|
|> line(end = [-2, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = 'y', angle = 180)
|
|> revolve(axis = Y, angle = 180)
|
||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@ -1008,7 +1008,7 @@ async fn kcl_test_simple_revolve_custom_axis() {
|
|||||||
|> line(end = [0, -5.5])
|
|> line(end = [0, -5.5])
|
||||||
|> line(end = [-2, 0])
|
|> line(end = [-2, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = {custom: {axis: [0, -1], origin: [0,0]}}, angle = 180)
|
|> revolve(axis = { direction = [0, -1], origin: [0,0] }, angle = 180)
|
||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@ -1106,7 +1106,7 @@ sketch001 = startSketchOn(box, "END")
|
|||||||
|> circle(center = [10,10], radius= 4 )
|
|> circle(center = [10,10], radius= 4 )
|
||||||
|> revolve(
|
|> revolve(
|
||||||
angle = -90,
|
angle = -90,
|
||||||
axis = 'y'
|
axis = Y
|
||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@ -1131,7 +1131,7 @@ sketch001 = startSketchOn(box, "end")
|
|||||||
|> line(end = [0, 10])
|
|> line(end = [0, 10])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(
|
|> revolve(
|
||||||
axis = 'y',
|
axis = Y,
|
||||||
angle = -90,
|
angle = -90,
|
||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
@ -1146,7 +1146,7 @@ async fn kcl_test_basic_revolve_circle() {
|
|||||||
|> circle(center = [15, 0], radius= 5)
|
|> circle(center = [15, 0], radius= 5)
|
||||||
|> revolve(
|
|> revolve(
|
||||||
angle = 360,
|
angle = 360,
|
||||||
axis = 'y'
|
axis = Y
|
||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@ -1166,7 +1166,7 @@ async fn kcl_test_simple_revolve_sketch_on_edge() {
|
|||||||
|> line(end = [0, -5.5])
|
|> line(end = [0, -5.5])
|
||||||
|> line(end = [-2, 0])
|
|> line(end = [-2, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve(axis = 'y', angle = 180)
|
|> revolve(axis = Y, angle = 180)
|
||||||
|
|
||||||
part002 = startSketchOn(part001, 'end')
|
part002 = startSketchOn(part001, 'end')
|
||||||
|> startProfileAt([4.5, -5], %)
|
|> startProfileAt([4.5, -5], %)
|
||||||
|
@ -23,8 +23,9 @@ use crate::{
|
|||||||
const TYPES_DIR: &str = "../../docs/kcl/types";
|
const TYPES_DIR: &str = "../../docs/kcl/types";
|
||||||
const LANG_TOPICS: [&str; 5] = ["Types", "Modules", "Settings", "Known Issues", "Constants"];
|
const LANG_TOPICS: [&str; 5] = ["Types", "Modules", "Settings", "Known Issues", "Constants"];
|
||||||
// These types are declared in std.
|
// These types are declared in std.
|
||||||
const DECLARED_TYPES: [&str; 11] = [
|
const DECLARED_TYPES: [&str; 14] = [
|
||||||
"number", "string", "tag", "bool", "Sketch", "Solid", "Plane", "Helix", "Face", "Point2d", "Point3d",
|
"number", "string", "tag", "bool", "Sketch", "Solid", "Plane", "Helix", "Face", "Edge", "Point2d", "Point3d",
|
||||||
|
"Axis2d", "Axis3d",
|
||||||
];
|
];
|
||||||
|
|
||||||
fn init_handlebars() -> Result<handlebars::Handlebars<'static>> {
|
fn init_handlebars() -> Result<handlebars::Handlebars<'static>> {
|
||||||
@ -339,9 +340,9 @@ fn generate_index(combined: &IndexMap<String, Box<dyn StdLibFn>>, kcl_lib: &[Doc
|
|||||||
}
|
}
|
||||||
|
|
||||||
functions.entry(d.mod_name()).or_default().push(match d {
|
functions.entry(d.mod_name()).or_default().push(match d {
|
||||||
DocData::Fn(f) => (f.name.clone(), d.file_name()),
|
DocData::Fn(f) => (f.preferred_name.clone(), d.file_name()),
|
||||||
DocData::Const(c) => (c.name.clone(), d.file_name()),
|
DocData::Const(c) => (c.preferred_name.clone(), d.file_name()),
|
||||||
DocData::Ty(t) => (t.name.clone(), d.file_name()),
|
DocData::Ty(t) => (t.preferred_name.clone(), d.file_name()),
|
||||||
});
|
});
|
||||||
|
|
||||||
if let DocData::Const(c) = d {
|
if let DocData::Const(c) = d {
|
||||||
|
@ -9,7 +9,7 @@ use tower_lsp::lsp_types::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
execution::annotations,
|
execution::annotations,
|
||||||
parsing::{
|
parsing::{
|
||||||
ast::types::{Annotation, Node, PrimitiveType, Type, VariableKind},
|
ast::types::{Annotation, ImportSelector, Node, PrimitiveType, Type, VariableKind},
|
||||||
token::NumericSuffix,
|
token::NumericSuffix,
|
||||||
},
|
},
|
||||||
ModuleId,
|
ModuleId,
|
||||||
@ -17,7 +17,7 @@ use crate::{
|
|||||||
|
|
||||||
pub fn walk_prelude() -> Vec<DocData> {
|
pub fn walk_prelude() -> Vec<DocData> {
|
||||||
let mut visitor = CollectionVisitor::default();
|
let mut visitor = CollectionVisitor::default();
|
||||||
visitor.visit_module("prelude").unwrap();
|
visitor.visit_module("prelude", "").unwrap();
|
||||||
visitor.result
|
visitor.result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ struct CollectionVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CollectionVisitor {
|
impl CollectionVisitor {
|
||||||
fn visit_module(&mut self, name: &str) -> Result<(), String> {
|
fn visit_module(&mut self, name: &str, preferred_prefix: &str) -> Result<(), String> {
|
||||||
let old_name = std::mem::replace(&mut self.name, name.to_owned());
|
let old_name = std::mem::replace(&mut self.name, name.to_owned());
|
||||||
let source = crate::modules::read_std(name).unwrap();
|
let source = crate::modules::read_std(name).unwrap();
|
||||||
let parsed = crate::parsing::parse_str(source, ModuleId::from_usize(self.id))
|
let parsed = crate::parsing::parse_str(source, ModuleId::from_usize(self.id))
|
||||||
@ -40,14 +40,16 @@ impl CollectionVisitor {
|
|||||||
for n in &parsed.body {
|
for n in &parsed.body {
|
||||||
match n {
|
match n {
|
||||||
crate::parsing::ast::types::BodyItem::ImportStatement(import) if !import.visibility.is_default() => {
|
crate::parsing::ast::types::BodyItem::ImportStatement(import) if !import.visibility.is_default() => {
|
||||||
// Only supports glob imports for now.
|
|
||||||
assert!(matches!(
|
|
||||||
import.selector,
|
|
||||||
crate::parsing::ast::types::ImportSelector::Glob(..)
|
|
||||||
));
|
|
||||||
match &import.path {
|
match &import.path {
|
||||||
crate::parsing::ast::types::ImportPath::Std { path } => {
|
crate::parsing::ast::types::ImportPath::Std { path } => {
|
||||||
self.visit_module(&path[1])?;
|
match import.selector {
|
||||||
|
ImportSelector::Glob(..) => self.visit_module(&path[1], "")?,
|
||||||
|
ImportSelector::None { .. } => {
|
||||||
|
self.visit_module(&path[1], &format!("{}::", import.module_name().unwrap()))?
|
||||||
|
}
|
||||||
|
// Only supports glob or whole-module imports for now.
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p => return Err(format!("Unexpected import: `{p}`")),
|
p => return Err(format!("Unexpected import: `{p}`")),
|
||||||
}
|
}
|
||||||
@ -59,8 +61,8 @@ impl CollectionVisitor {
|
|||||||
format!("std::{}::", self.name)
|
format!("std::{}::", self.name)
|
||||||
};
|
};
|
||||||
let mut dd = match var.kind {
|
let mut dd = match var.kind {
|
||||||
VariableKind::Fn => DocData::Fn(FnData::from_ast(var, qual_name)),
|
VariableKind::Fn => DocData::Fn(FnData::from_ast(var, qual_name, preferred_prefix)),
|
||||||
VariableKind::Const => DocData::Const(ConstData::from_ast(var, qual_name)),
|
VariableKind::Const => DocData::Const(ConstData::from_ast(var, qual_name, preferred_prefix)),
|
||||||
};
|
};
|
||||||
|
|
||||||
dd.with_meta(&var.outer_attrs);
|
dd.with_meta(&var.outer_attrs);
|
||||||
@ -77,7 +79,7 @@ impl CollectionVisitor {
|
|||||||
} else {
|
} else {
|
||||||
format!("std::{}::", self.name)
|
format!("std::{}::", self.name)
|
||||||
};
|
};
|
||||||
let mut dd = DocData::Ty(TyData::from_ast(ty, qual_name));
|
let mut dd = DocData::Ty(TyData::from_ast(ty, qual_name, preferred_prefix));
|
||||||
|
|
||||||
dd.with_meta(&ty.outer_attrs);
|
dd.with_meta(&ty.outer_attrs);
|
||||||
for a in &ty.outer_attrs {
|
for a in &ty.outer_attrs {
|
||||||
@ -200,6 +202,8 @@ impl DocData {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ConstData {
|
pub struct ConstData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
/// How the const is indexed, etc.
|
||||||
|
pub preferred_name: String,
|
||||||
/// The fully qualified name.
|
/// The fully qualified name.
|
||||||
pub qual_name: String,
|
pub qual_name: String,
|
||||||
pub value: Option<String>,
|
pub value: Option<String>,
|
||||||
@ -216,7 +220,11 @@ pub struct ConstData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ConstData {
|
impl ConstData {
|
||||||
fn from_ast(var: &crate::parsing::ast::types::VariableDeclaration, mut qual_name: String) -> Self {
|
fn from_ast(
|
||||||
|
var: &crate::parsing::ast::types::VariableDeclaration,
|
||||||
|
mut qual_name: String,
|
||||||
|
preferred_prefix: &str,
|
||||||
|
) -> Self {
|
||||||
assert_eq!(var.kind, crate::parsing::ast::types::VariableKind::Const);
|
assert_eq!(var.kind, crate::parsing::ast::types::VariableKind::Const);
|
||||||
|
|
||||||
let (value, ty) = match &var.declaration.init {
|
let (value, ty) = match &var.declaration.init {
|
||||||
@ -240,6 +248,7 @@ impl ConstData {
|
|||||||
let name = var.declaration.id.name.clone();
|
let name = var.declaration.id.name.clone();
|
||||||
qual_name.push_str(&name);
|
qual_name.push_str(&name);
|
||||||
ConstData {
|
ConstData {
|
||||||
|
preferred_name: format!("{preferred_prefix}{name}"),
|
||||||
name,
|
name,
|
||||||
qual_name,
|
qual_name,
|
||||||
value,
|
value,
|
||||||
@ -272,7 +281,7 @@ impl ConstData {
|
|||||||
detail.push_str(ty);
|
detail.push_str(ty);
|
||||||
}
|
}
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: self.name.clone(),
|
label: self.preferred_name.clone(),
|
||||||
label_details: Some(CompletionItemLabelDetails {
|
label_details: Some(CompletionItemLabelDetails {
|
||||||
detail: self.value.clone(),
|
detail: self.value.clone(),
|
||||||
description: None,
|
description: None,
|
||||||
@ -306,6 +315,8 @@ impl ConstData {
|
|||||||
pub struct FnData {
|
pub struct FnData {
|
||||||
/// The name of the function.
|
/// The name of the function.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
/// How the function is indexed, etc.
|
||||||
|
pub preferred_name: String,
|
||||||
/// The fully qualified name.
|
/// The fully qualified name.
|
||||||
pub qual_name: String,
|
pub qual_name: String,
|
||||||
/// The args of the function.
|
/// The args of the function.
|
||||||
@ -326,7 +337,11 @@ pub struct FnData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FnData {
|
impl FnData {
|
||||||
fn from_ast(var: &crate::parsing::ast::types::VariableDeclaration, mut qual_name: String) -> Self {
|
fn from_ast(
|
||||||
|
var: &crate::parsing::ast::types::VariableDeclaration,
|
||||||
|
mut qual_name: String,
|
||||||
|
preferred_prefix: &str,
|
||||||
|
) -> Self {
|
||||||
assert_eq!(var.kind, crate::parsing::ast::types::VariableKind::Fn);
|
assert_eq!(var.kind, crate::parsing::ast::types::VariableKind::Fn);
|
||||||
let crate::parsing::ast::types::Expr::FunctionExpression(expr) = &var.declaration.init else {
|
let crate::parsing::ast::types::Expr::FunctionExpression(expr) = &var.declaration.init else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
@ -345,6 +360,7 @@ impl FnData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FnData {
|
FnData {
|
||||||
|
preferred_name: format!("{preferred_prefix}{name}"),
|
||||||
name,
|
name,
|
||||||
qual_name,
|
qual_name,
|
||||||
args: expr.params.iter().map(ArgData::from_ast).collect(),
|
args: expr.params.iter().map(ArgData::from_ast).collect(),
|
||||||
@ -443,7 +459,7 @@ impl FnData {
|
|||||||
}
|
}
|
||||||
// We end with ${} so you can jump to the end of the snippet.
|
// We end with ${} so you can jump to the end of the snippet.
|
||||||
// After the last argument.
|
// After the last argument.
|
||||||
format!("{}({})${{}}", self.name, args.join(", "))
|
format!("{}({})${{}}", self.preferred_name, args.join(", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_signature_help(&self) -> SignatureHelp {
|
fn to_signature_help(&self) -> SignatureHelp {
|
||||||
@ -452,7 +468,7 @@ impl FnData {
|
|||||||
|
|
||||||
SignatureHelp {
|
SignatureHelp {
|
||||||
signatures: vec![SignatureInformation {
|
signatures: vec![SignatureInformation {
|
||||||
label: self.name.clone(),
|
label: self.preferred_name.clone(),
|
||||||
documentation: self.short_docs().map(|s| {
|
documentation: self.short_docs().map(|s| {
|
||||||
Documentation::MarkupContent(MarkupContent {
|
Documentation::MarkupContent(MarkupContent {
|
||||||
kind: MarkupKind::Markdown,
|
kind: MarkupKind::Markdown,
|
||||||
@ -492,6 +508,7 @@ pub struct ArgData {
|
|||||||
pub ty: Option<String>,
|
pub ty: Option<String>,
|
||||||
/// If the argument is required.
|
/// If the argument is required.
|
||||||
pub kind: ArgKind,
|
pub kind: ArgKind,
|
||||||
|
pub override_in_snippet: Option<bool>,
|
||||||
/// Additional information that could be used instead of the type's description.
|
/// Additional information that could be used instead of the type's description.
|
||||||
/// This is helpful if the type is really basic, like "number" -- that won't tell the user much about
|
/// This is helpful if the type is really basic, like "number" -- that won't tell the user much about
|
||||||
/// how this argument is meant to be used.
|
/// how this argument is meant to be used.
|
||||||
@ -512,6 +529,7 @@ impl ArgData {
|
|||||||
name: arg.identifier.name.clone(),
|
name: arg.identifier.name.clone(),
|
||||||
ty: arg.type_.as_ref().map(|t| t.to_string()),
|
ty: arg.type_.as_ref().map(|t| t.to_string()),
|
||||||
docs: None,
|
docs: None,
|
||||||
|
override_in_snippet: None,
|
||||||
kind: if arg.labeled {
|
kind: if arg.labeled {
|
||||||
ArgKind::Labelled(arg.optional())
|
ArgKind::Labelled(arg.optional())
|
||||||
} else {
|
} else {
|
||||||
@ -519,26 +537,54 @@ impl ArgData {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for attr in &arg.identifier.outer_attrs {
|
||||||
|
if let Annotation {
|
||||||
|
name: None,
|
||||||
|
properties: Some(props),
|
||||||
|
..
|
||||||
|
} = &attr.inner
|
||||||
|
{
|
||||||
|
for p in props {
|
||||||
|
match &*p.key.name {
|
||||||
|
"include_in_snippet" => {
|
||||||
|
if let Some(b) = p.value.literal_bool() {
|
||||||
|
result.override_in_snippet = Some(b);
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"Invalid value for `include_in_snippet`, expected bool literal, found {:?}",
|
||||||
|
p.value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result.with_comments(&arg.identifier.pre_comments);
|
result.with_comments(&arg.identifier.pre_comments);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_autocomplete_snippet(&self, index: usize) -> Option<(usize, String)> {
|
pub fn get_autocomplete_snippet(&self, index: usize) -> Option<(usize, String)> {
|
||||||
|
match self.override_in_snippet {
|
||||||
|
Some(false) => return None,
|
||||||
|
None if !self.kind.required() => return None,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
let label = if self.kind == ArgKind::Special {
|
let label = if self.kind == ArgKind::Special {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
format!("{} = ", self.name)
|
format!("{} = ", self.name)
|
||||||
};
|
};
|
||||||
match self.ty.as_deref() {
|
match self.ty.as_deref() {
|
||||||
Some(s) if ["Sketch", "Solid", "Plane | Face", "Sketch | Plane | Face"].contains(&s) => {
|
Some(s) if s.starts_with("number") => Some((index, format!(r#"{label}${{{}:3.14}}"#, index))),
|
||||||
Some((index, format!("{label}${{{}:{}}}", index, "%")))
|
Some("Point2d") => Some((
|
||||||
}
|
|
||||||
Some("number") if self.kind.required() => Some((index, format!(r#"{label}${{{}:3.14}}"#, index))),
|
|
||||||
Some("Point2d") if self.kind.required() => Some((
|
|
||||||
index + 1,
|
index + 1,
|
||||||
format!(r#"{label}[${{{}:3.14}}, ${{{}:3.14}}]"#, index, index + 1),
|
format!(r#"{label}[${{{}:3.14}}, ${{{}:3.14}}]"#, index, index + 1),
|
||||||
)),
|
)),
|
||||||
Some("Point3d") if self.kind.required() => Some((
|
Some("Point3d") => Some((
|
||||||
index + 2,
|
index + 2,
|
||||||
format!(
|
format!(
|
||||||
r#"{label}[${{{}:3.14}}, ${{{}:3.14}}, ${{{}:3.14}}]"#,
|
r#"{label}[${{{}:3.14}}, ${{{}:3.14}}, ${{{}:3.14}}]"#,
|
||||||
@ -547,8 +593,10 @@ impl ArgData {
|
|||||||
index + 2
|
index + 2
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
Some("string") if self.kind.required() => Some((index, format!(r#"{label}${{{}:"string"}}"#, index))),
|
Some("Axis2d | Edge") | Some("Axis3d | Edge") => Some((index, format!(r#"{label}${{{}:X}}"#, index))),
|
||||||
Some("bool") if self.kind.required() => Some((index, format!(r#"{label}${{{}:false}}"#, index))),
|
|
||||||
|
Some("string") => Some((index, format!(r#"{label}${{{}:"string"}}"#, index))),
|
||||||
|
Some("bool") => Some((index, format!(r#"{label}${{{}:false}}"#, index))),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -580,6 +628,8 @@ impl ArgKind {
|
|||||||
pub struct TyData {
|
pub struct TyData {
|
||||||
/// The name of the function.
|
/// The name of the function.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
/// How the type is indexed, etc.
|
||||||
|
pub preferred_name: String,
|
||||||
/// The fully qualified name.
|
/// The fully qualified name.
|
||||||
pub qual_name: String,
|
pub qual_name: String,
|
||||||
pub properties: Properties,
|
pub properties: Properties,
|
||||||
@ -597,7 +647,11 @@ pub struct TyData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TyData {
|
impl TyData {
|
||||||
fn from_ast(ty: &crate::parsing::ast::types::TypeDeclaration, mut qual_name: String) -> Self {
|
fn from_ast(
|
||||||
|
ty: &crate::parsing::ast::types::TypeDeclaration,
|
||||||
|
mut qual_name: String,
|
||||||
|
preferred_prefix: &str,
|
||||||
|
) -> Self {
|
||||||
let name = ty.name.name.clone();
|
let name = ty.name.name.clone();
|
||||||
qual_name.push_str(&name);
|
qual_name.push_str(&name);
|
||||||
let mut referenced_types = HashSet::new();
|
let mut referenced_types = HashSet::new();
|
||||||
@ -606,6 +660,7 @@ impl TyData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TyData {
|
TyData {
|
||||||
|
preferred_name: format!("{preferred_prefix}{name}"),
|
||||||
name,
|
name,
|
||||||
qual_name,
|
qual_name,
|
||||||
properties: Properties {
|
properties: Properties {
|
||||||
@ -641,7 +696,7 @@ impl TyData {
|
|||||||
|
|
||||||
fn to_completion_item(&self) -> CompletionItem {
|
fn to_completion_item(&self) -> CompletionItem {
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: self.name.clone(),
|
label: self.preferred_name.clone(),
|
||||||
label_details: self.alias.as_ref().map(|t| CompletionItemLabelDetails {
|
label_details: self.alias.as_ref().map(|t| CompletionItemLabelDetails {
|
||||||
detail: Some(format!("type {} = {t}", self.name)),
|
detail: Some(format!("type {} = {t}", self.name)),
|
||||||
description: None,
|
description: None,
|
||||||
@ -658,7 +713,7 @@ impl TyData {
|
|||||||
preselect: None,
|
preselect: None,
|
||||||
sort_text: None,
|
sort_text: None,
|
||||||
filter_text: None,
|
filter_text: None,
|
||||||
insert_text: Some(self.name.clone()),
|
insert_text: Some(self.preferred_name.clone()),
|
||||||
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
insert_text_mode: None,
|
insert_text_mode: None,
|
||||||
text_edit: None,
|
text_edit: None,
|
||||||
|
@ -1000,9 +1000,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_autocomplete_snippet_revolve() {
|
fn get_autocomplete_snippet_revolve() {
|
||||||
let revolve_fn: Box<dyn StdLibFn> = Box::new(crate::std::revolve::Revolve);
|
let data = kcl_doc::walk_prelude();
|
||||||
let snippet = revolve_fn.to_autocomplete_snippet().unwrap();
|
let DocData::Fn(revolve_fn) = data.into_iter().find(|d| d.name() == "revolve").unwrap() else {
|
||||||
assert_eq!(snippet, r#"revolve(${0:%}, axis = ${1:"X"})${}"#);
|
panic!();
|
||||||
|
};
|
||||||
|
let snippet = revolve_fn.to_autocomplete_snippet();
|
||||||
|
assert_eq!(snippet, r#"revolve(axis = ${0:X})${}"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1015,7 +1018,7 @@ mod tests {
|
|||||||
let snippet = circle_fn.to_autocomplete_snippet();
|
let snippet = circle_fn.to_autocomplete_snippet();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snippet,
|
snippet,
|
||||||
r#"circle(${0:%}, center = [${1:3.14}, ${2:3.14}], radius = ${3:3.14})${}"#
|
r#"circle(center = [${0:3.14}, ${1:3.14}], radius = ${2:3.14})${}"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1089,11 +1092,14 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[allow(clippy::literal_string_with_formatting_args)]
|
#[allow(clippy::literal_string_with_formatting_args)]
|
||||||
fn get_autocomplete_snippet_helix() {
|
fn get_autocomplete_snippet_helix() {
|
||||||
let helix_fn: Box<dyn StdLibFn> = Box::new(crate::std::helix::Helix);
|
let data = kcl_doc::walk_prelude();
|
||||||
let snippet = helix_fn.to_autocomplete_snippet().unwrap();
|
let DocData::Fn(helix_fn) = data.into_iter().find(|d| d.name() == "helix").unwrap() else {
|
||||||
|
panic!();
|
||||||
|
};
|
||||||
|
let snippet = helix_fn.to_autocomplete_snippet();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snippet,
|
snippet,
|
||||||
r#"helix(revolutions = ${0:3.14}, angleStart = ${1:3.14}, radius = ${2:3.14}, axis = ${3:"X"}, length = ${4:3.14})${}"#
|
r#"helix(revolutions = ${0:3.14}, angleStart = ${1:3.14}, radius = ${2:3.14}, axis = ${3:X}, length = ${4:3.14})${}"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,19 @@ pub enum Operation {
|
|||||||
is_error: bool,
|
is_error: bool,
|
||||||
},
|
},
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
KclStdLibCall {
|
||||||
|
name: String,
|
||||||
|
/// The unlabeled argument to the function.
|
||||||
|
unlabeled_arg: Option<OpArg>,
|
||||||
|
/// The labeled keyword arguments to the function.
|
||||||
|
labeled_args: IndexMap<String, OpArg>,
|
||||||
|
/// The source range of the operation in the source code.
|
||||||
|
source_range: SourceRange,
|
||||||
|
/// True if the operation resulted in an error.
|
||||||
|
#[serde(default, skip_serializing_if = "is_false")]
|
||||||
|
is_error: bool,
|
||||||
|
},
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
UserDefinedFunctionCall {
|
UserDefinedFunctionCall {
|
||||||
/// The name of the user-defined function being called. Anonymous
|
/// The name of the user-defined function being called. Anonymous
|
||||||
/// functions have no name.
|
/// functions have no name.
|
||||||
@ -49,6 +62,7 @@ impl Operation {
|
|||||||
pub(crate) fn set_std_lib_call_is_error(&mut self, is_err: bool) {
|
pub(crate) fn set_std_lib_call_is_error(&mut self, is_err: bool) {
|
||||||
match self {
|
match self {
|
||||||
Self::StdLibCall { ref mut is_error, .. } => *is_error = is_err,
|
Self::StdLibCall { ref mut is_error, .. } => *is_error = is_err,
|
||||||
|
Self::KclStdLibCall { ref mut is_error, .. } => *is_error = is_err,
|
||||||
Self::UserDefinedFunctionCall { .. } | Self::UserDefinedFunctionReturn => {}
|
Self::UserDefinedFunctionCall { .. } | Self::UserDefinedFunctionReturn => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
|||||||
use async_recursion::async_recursion;
|
use async_recursion::async_recursion;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
use super::kcl_value::TypeDef;
|
use super::{kcl_value::TypeDef, types::PrimitiveType};
|
||||||
use crate::{
|
use crate::{
|
||||||
engine::ExecutionKind,
|
engine::ExecutionKind,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
@ -1031,6 +1031,15 @@ impl Node<UnaryExpression> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let value = &self.argument.get_result(exec_state, ctx).await?;
|
let value = &self.argument.get_result(exec_state, ctx).await?;
|
||||||
|
let err = || {
|
||||||
|
KclError::Semantic(KclErrorDetails {
|
||||||
|
message: format!(
|
||||||
|
"You can only negate numbers, planes, or lines, but this is a {}",
|
||||||
|
value.human_friendly_type()
|
||||||
|
),
|
||||||
|
source_ranges: vec![self.into()],
|
||||||
|
})
|
||||||
|
};
|
||||||
match value {
|
match value {
|
||||||
KclValue::Number { value, ty, .. } => {
|
KclValue::Number { value, ty, .. } => {
|
||||||
let meta = vec![Metadata {
|
let meta = vec![Metadata {
|
||||||
@ -1052,13 +1061,63 @@ impl Node<UnaryExpression> {
|
|||||||
plane.id = exec_state.next_uuid();
|
plane.id = exec_state.next_uuid();
|
||||||
Ok(KclValue::Plane { value: plane })
|
Ok(KclValue::Plane { value: plane })
|
||||||
}
|
}
|
||||||
_ => Err(KclError::Semantic(KclErrorDetails {
|
KclValue::Object { value: values, meta } => {
|
||||||
message: format!(
|
// Special-case for negating line-like objects.
|
||||||
"You can only negate numbers or planes, but this is a {}",
|
let Some(direction) = values.get("direction") else {
|
||||||
value.human_friendly_type()
|
return Err(err());
|
||||||
),
|
};
|
||||||
source_ranges: vec![self.into()],
|
|
||||||
})),
|
let direction = match direction {
|
||||||
|
KclValue::MixedArray { value: values, meta } => {
|
||||||
|
let values = values
|
||||||
|
.iter()
|
||||||
|
.map(|v| match v {
|
||||||
|
KclValue::Number { value, ty, meta } => Ok(KclValue::Number {
|
||||||
|
value: *value * -1.0,
|
||||||
|
ty: ty.clone(),
|
||||||
|
meta: meta.clone(),
|
||||||
|
}),
|
||||||
|
_ => Err(err()),
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
KclValue::MixedArray {
|
||||||
|
value: values,
|
||||||
|
meta: meta.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KclValue::HomArray {
|
||||||
|
value: values,
|
||||||
|
ty: ty @ RuntimeType::Primitive(PrimitiveType::Number(_)),
|
||||||
|
} => {
|
||||||
|
let values = values
|
||||||
|
.iter()
|
||||||
|
.map(|v| match v {
|
||||||
|
KclValue::Number { value, ty, meta } => Ok(KclValue::Number {
|
||||||
|
value: *value * -1.0,
|
||||||
|
ty: ty.clone(),
|
||||||
|
meta: meta.clone(),
|
||||||
|
}),
|
||||||
|
_ => Err(err()),
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
KclValue::HomArray {
|
||||||
|
value: values,
|
||||||
|
ty: ty.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return Err(err()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut value = values.clone();
|
||||||
|
value.insert("direction".to_owned(), direction);
|
||||||
|
Ok(KclValue::Object {
|
||||||
|
value,
|
||||||
|
meta: meta.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => Err(err()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2145,6 +2204,27 @@ impl FunctionSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let op = if props.include_in_feature_tree {
|
||||||
|
let op_labeled_args = args
|
||||||
|
.kw_args
|
||||||
|
.labeled
|
||||||
|
.iter()
|
||||||
|
.map(|(k, arg)| (k.clone(), OpArg::new(OpKclValue::from(&arg.value), arg.source_range)))
|
||||||
|
.collect();
|
||||||
|
Some(Operation::KclStdLibCall {
|
||||||
|
// TODO
|
||||||
|
name: String::new(),
|
||||||
|
unlabeled_arg: args
|
||||||
|
.unlabeled_kw_arg_unconverted()
|
||||||
|
.map(|arg| OpArg::new(OpKclValue::from(&arg.value), arg.source_range)),
|
||||||
|
labeled_args: op_labeled_args,
|
||||||
|
source_range: callsite,
|
||||||
|
is_error: false,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Attempt to call the function.
|
// Attempt to call the function.
|
||||||
exec_state.mut_stack().push_new_env_for_rust_call();
|
exec_state.mut_stack().push_new_env_for_rust_call();
|
||||||
let mut result = {
|
let mut result = {
|
||||||
@ -2152,7 +2232,15 @@ impl FunctionSource {
|
|||||||
let result = func(exec_state, args).await;
|
let result = func(exec_state, args).await;
|
||||||
exec_state.mut_stack().pop_env();
|
exec_state.mut_stack().pop_env();
|
||||||
|
|
||||||
// TODO support recording op into the feature tree
|
if let Some(mut op) = op {
|
||||||
|
op.set_std_lib_call_is_error(result.is_err());
|
||||||
|
// Track call operation. We do this after the call
|
||||||
|
// since things like patternTransform may call user code
|
||||||
|
// before running, and we will likely want to use the
|
||||||
|
// return value. The call takes ownership of the args,
|
||||||
|
// so we need to build the op before the call.
|
||||||
|
exec_state.global.operations.push(op);
|
||||||
|
}
|
||||||
result
|
result
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
@ -56,6 +56,20 @@ impl RuntimeType {
|
|||||||
RuntimeType::Primitive(PrimitiveType::ImportedGeometry)
|
RuntimeType::Primitive(PrimitiveType::ImportedGeometry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `[number; 2]`
|
||||||
|
pub fn point2d() -> Self {
|
||||||
|
RuntimeType::Array(Box::new(RuntimeType::number_any()), ArrayLen::Known(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `[number; 3]`
|
||||||
|
pub fn point3d() -> Self {
|
||||||
|
RuntimeType::Array(Box::new(RuntimeType::number_any()), ArrayLen::Known(3))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn number_any() -> Self {
|
||||||
|
RuntimeType::Primitive(PrimitiveType::Number(NumericType::Any))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_parsed(
|
pub fn from_parsed(
|
||||||
value: Type,
|
value: Type,
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
@ -93,21 +107,27 @@ impl RuntimeType {
|
|||||||
AstPrimitiveType::Number(suffix) => RuntimeType::Primitive(PrimitiveType::Number(
|
AstPrimitiveType::Number(suffix) => RuntimeType::Primitive(PrimitiveType::Number(
|
||||||
NumericType::from_parsed(suffix, &exec_state.mod_local.settings),
|
NumericType::from_parsed(suffix, &exec_state.mod_local.settings),
|
||||||
)),
|
)),
|
||||||
AstPrimitiveType::Named(name) => {
|
AstPrimitiveType::Named(name) => Self::from_alias(&name.name, exec_state, source_range)?,
|
||||||
|
AstPrimitiveType::Tag => RuntimeType::Primitive(PrimitiveType::Tag),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_alias(
|
||||||
|
alias: &str,
|
||||||
|
exec_state: &mut ExecState,
|
||||||
|
source_range: SourceRange,
|
||||||
|
) -> Result<Self, CompilationError> {
|
||||||
let ty_val = exec_state
|
let ty_val = exec_state
|
||||||
.stack()
|
.stack()
|
||||||
.get(&format!("{}{}", memory::TYPE_PREFIX, name.name), source_range)
|
.get(&format!("{}{}", memory::TYPE_PREFIX, alias), source_range)
|
||||||
.map_err(|_| CompilationError::err(source_range, format!("Unknown type: {}", name.name)))?;
|
.map_err(|_| CompilationError::err(source_range, format!("Unknown type: {}", alias)))?;
|
||||||
|
|
||||||
match ty_val {
|
Ok(match ty_val {
|
||||||
KclValue::Type { value, .. } => match value {
|
KclValue::Type { value, .. } => match value {
|
||||||
TypeDef::RustRepr(ty, _) => RuntimeType::Primitive(ty.clone()),
|
TypeDef::RustRepr(ty, _) => RuntimeType::Primitive(ty.clone()),
|
||||||
TypeDef::Alias(ty) => ty.clone(),
|
TypeDef::Alias(ty) => ty.clone(),
|
||||||
},
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
|
||||||
}
|
|
||||||
AstPrimitiveType::Tag => RuntimeType::Primitive(PrimitiveType::Tag),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +163,35 @@ impl RuntimeType {
|
|||||||
(Object(t1), Object(t2)) => t2
|
(Object(t1), Object(t2)) => t2
|
||||||
.iter()
|
.iter()
|
||||||
.all(|(f, t)| t1.iter().any(|(ff, tt)| f == ff && tt.subtype(t))),
|
.all(|(f, t)| t1.iter().any(|(ff, tt)| f == ff && tt.subtype(t))),
|
||||||
|
// Equality between Axis types and there object representation.
|
||||||
|
(Object(t1), Primitive(PrimitiveType::Axis2d)) => {
|
||||||
|
t1.iter()
|
||||||
|
.any(|(n, t)| n == "origin" && t.subtype(&RuntimeType::point2d()))
|
||||||
|
&& t1
|
||||||
|
.iter()
|
||||||
|
.any(|(n, t)| n == "direction" && t.subtype(&RuntimeType::point2d()))
|
||||||
|
}
|
||||||
|
(Object(t1), Primitive(PrimitiveType::Axis3d)) => {
|
||||||
|
t1.iter()
|
||||||
|
.any(|(n, t)| n == "origin" && t.subtype(&RuntimeType::point3d()))
|
||||||
|
&& t1
|
||||||
|
.iter()
|
||||||
|
.any(|(n, t)| n == "direction" && t.subtype(&RuntimeType::point3d()))
|
||||||
|
}
|
||||||
|
(Primitive(PrimitiveType::Axis2d), Object(t2)) => {
|
||||||
|
t2.iter()
|
||||||
|
.any(|(n, t)| n == "origin" && t.subtype(&RuntimeType::point2d()))
|
||||||
|
&& t2
|
||||||
|
.iter()
|
||||||
|
.any(|(n, t)| n == "direction" && t.subtype(&RuntimeType::point2d()))
|
||||||
|
}
|
||||||
|
(Primitive(PrimitiveType::Axis3d), Object(t2)) => {
|
||||||
|
t2.iter()
|
||||||
|
.any(|(n, t)| n == "origin" && t.subtype(&RuntimeType::point3d()))
|
||||||
|
&& t2
|
||||||
|
.iter()
|
||||||
|
.any(|(n, t)| n == "direction" && t.subtype(&RuntimeType::point3d()))
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,11 +262,11 @@ impl ArrayLen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// True if the length constraint is satisfied by the supplied length.
|
/// True if the length constraint is satisfied by the supplied length.
|
||||||
fn satisfied(self, len: usize) -> bool {
|
fn satisfied(self, len: usize, allow_shrink: bool) -> Option<usize> {
|
||||||
match self {
|
match self {
|
||||||
ArrayLen::None => true,
|
ArrayLen::None => Some(len),
|
||||||
ArrayLen::NonEmpty => len > 0,
|
ArrayLen::NonEmpty => (len > 0).then_some(len),
|
||||||
ArrayLen::Known(s) => len == s,
|
ArrayLen::Known(s) => (if allow_shrink { len >= s } else { len == s }).then_some(s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -233,6 +282,9 @@ pub enum PrimitiveType {
|
|||||||
Plane,
|
Plane,
|
||||||
Helix,
|
Helix,
|
||||||
Face,
|
Face,
|
||||||
|
Edge,
|
||||||
|
Axis2d,
|
||||||
|
Axis3d,
|
||||||
ImportedGeometry,
|
ImportedGeometry,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,6 +300,9 @@ impl PrimitiveType {
|
|||||||
PrimitiveType::Plane => "Planes".to_owned(),
|
PrimitiveType::Plane => "Planes".to_owned(),
|
||||||
PrimitiveType::Helix => "Helices".to_owned(),
|
PrimitiveType::Helix => "Helices".to_owned(),
|
||||||
PrimitiveType::Face => "Faces".to_owned(),
|
PrimitiveType::Face => "Faces".to_owned(),
|
||||||
|
PrimitiveType::Edge => "Edges".to_owned(),
|
||||||
|
PrimitiveType::Axis2d => "2d axes".to_owned(),
|
||||||
|
PrimitiveType::Axis3d => "3d axes".to_owned(),
|
||||||
PrimitiveType::ImportedGeometry => "imported geometries".to_owned(),
|
PrimitiveType::ImportedGeometry => "imported geometries".to_owned(),
|
||||||
PrimitiveType::Tag => "tags".to_owned(),
|
PrimitiveType::Tag => "tags".to_owned(),
|
||||||
}
|
}
|
||||||
@ -273,6 +328,9 @@ impl fmt::Display for PrimitiveType {
|
|||||||
PrimitiveType::Solid => write!(f, "Solid"),
|
PrimitiveType::Solid => write!(f, "Solid"),
|
||||||
PrimitiveType::Plane => write!(f, "Plane"),
|
PrimitiveType::Plane => write!(f, "Plane"),
|
||||||
PrimitiveType::Face => write!(f, "Face"),
|
PrimitiveType::Face => write!(f, "Face"),
|
||||||
|
PrimitiveType::Edge => write!(f, "Edge"),
|
||||||
|
PrimitiveType::Axis2d => write!(f, "Axis2d"),
|
||||||
|
PrimitiveType::Axis3d => write!(f, "Axis3d"),
|
||||||
PrimitiveType::Helix => write!(f, "Helix"),
|
PrimitiveType::Helix => write!(f, "Helix"),
|
||||||
PrimitiveType::ImportedGeometry => write!(f, "imported geometry"),
|
PrimitiveType::ImportedGeometry => write!(f, "imported geometry"),
|
||||||
}
|
}
|
||||||
@ -298,6 +356,10 @@ impl NumericType {
|
|||||||
NumericType::Known(UnitType::Count)
|
NumericType::Known(UnitType::Count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mm() -> Self {
|
||||||
|
NumericType::Known(UnitType::Length(UnitLen::Mm))
|
||||||
|
}
|
||||||
|
|
||||||
/// Combine two types when we expect them to be equal.
|
/// Combine two types when we expect them to be equal.
|
||||||
pub fn combine_eq(self, other: &NumericType) -> NumericType {
|
pub fn combine_eq(self, other: &NumericType) -> NumericType {
|
||||||
if &self == other {
|
if &self == other {
|
||||||
@ -541,7 +603,7 @@ impl KclValue {
|
|||||||
pub fn coerce(&self, ty: &RuntimeType, exec_state: &mut ExecState) -> Option<KclValue> {
|
pub fn coerce(&self, ty: &RuntimeType, exec_state: &mut ExecState) -> Option<KclValue> {
|
||||||
match ty {
|
match ty {
|
||||||
RuntimeType::Primitive(ty) => self.coerce_to_primitive_type(ty, exec_state),
|
RuntimeType::Primitive(ty) => self.coerce_to_primitive_type(ty, exec_state),
|
||||||
RuntimeType::Array(ty, len) => self.coerce_to_array_type(ty, *len, exec_state),
|
RuntimeType::Array(ty, len) => self.coerce_to_array_type(ty, *len, exec_state, false),
|
||||||
RuntimeType::Tuple(tys) => self.coerce_to_tuple_type(tys, exec_state),
|
RuntimeType::Tuple(tys) => self.coerce_to_tuple_type(tys, exec_state),
|
||||||
RuntimeType::Union(tys) => self.coerce_to_union_type(tys, exec_state),
|
RuntimeType::Union(tys) => self.coerce_to_union_type(tys, exec_state),
|
||||||
RuntimeType::Object(tys) => self.coerce_to_object_type(tys, exec_state),
|
RuntimeType::Object(tys) => self.coerce_to_object_type(tys, exec_state),
|
||||||
@ -609,6 +671,55 @@ impl KclValue {
|
|||||||
KclValue::Helix { .. } => Some(value.clone()),
|
KclValue::Helix { .. } => Some(value.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
PrimitiveType::Edge => match value {
|
||||||
|
KclValue::Uuid { .. } => Some(value.clone()),
|
||||||
|
KclValue::TagIdentifier { .. } => Some(value.clone()),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
PrimitiveType::Axis2d => match value {
|
||||||
|
KclValue::Object { value: values, meta } => {
|
||||||
|
if values.get("origin")?.has_type(&RuntimeType::point2d())
|
||||||
|
&& values.get("direction")?.has_type(&RuntimeType::point2d())
|
||||||
|
{
|
||||||
|
return Some(value.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let origin = values.get("origin").and_then(|p| {
|
||||||
|
p.coerce_to_array_type(&RuntimeType::number_any(), ArrayLen::Known(2), exec_state, true)
|
||||||
|
})?;
|
||||||
|
let direction = values.get("direction").and_then(|p| {
|
||||||
|
p.coerce_to_array_type(&RuntimeType::number_any(), ArrayLen::Known(2), exec_state, true)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Some(KclValue::Object {
|
||||||
|
value: [("origin".to_owned(), origin), ("direction".to_owned(), direction)].into(),
|
||||||
|
meta: meta.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
PrimitiveType::Axis3d => match value {
|
||||||
|
KclValue::Object { value: values, meta } => {
|
||||||
|
if values.get("origin")?.has_type(&RuntimeType::point3d())
|
||||||
|
&& values.get("direction")?.has_type(&RuntimeType::point3d())
|
||||||
|
{
|
||||||
|
return Some(value.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let origin = values.get("origin").and_then(|p| {
|
||||||
|
p.coerce_to_array_type(&RuntimeType::number_any(), ArrayLen::Known(3), exec_state, true)
|
||||||
|
})?;
|
||||||
|
let direction = values.get("direction").and_then(|p| {
|
||||||
|
p.coerce_to_array_type(&RuntimeType::number_any(), ArrayLen::Known(3), exec_state, true)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Some(KclValue::Object {
|
||||||
|
value: [("origin".to_owned(), origin), ("direction".to_owned(), direction)].into(),
|
||||||
|
meta: meta.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
PrimitiveType::ImportedGeometry => match value {
|
PrimitiveType::ImportedGeometry => match value {
|
||||||
KclValue::ImportedGeometry { .. } => Some(value.clone()),
|
KclValue::ImportedGeometry { .. } => Some(value.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -621,60 +732,35 @@ impl KclValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coerce_to_array_type(&self, ty: &RuntimeType, len: ArrayLen, exec_state: &mut ExecState) -> Option<KclValue> {
|
fn coerce_to_array_type(
|
||||||
|
&self,
|
||||||
|
ty: &RuntimeType,
|
||||||
|
len: ArrayLen,
|
||||||
|
exec_state: &mut ExecState,
|
||||||
|
allow_shrink: bool,
|
||||||
|
) -> Option<KclValue> {
|
||||||
match self {
|
match self {
|
||||||
KclValue::HomArray { value, ty: aty } if aty == ty => {
|
KclValue::HomArray { value, ty: aty } if aty.subtype(ty) => {
|
||||||
let value = match len {
|
len.satisfied(value.len(), allow_shrink).map(|len| KclValue::HomArray {
|
||||||
ArrayLen::None => value.clone(),
|
value: value[..len].to_vec(),
|
||||||
ArrayLen::NonEmpty => {
|
ty: aty.clone(),
|
||||||
if value.is_empty() {
|
})
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
value if len.satisfied(1, false).is_some() && value.has_type(ty) => Some(KclValue::HomArray {
|
||||||
value.clone()
|
|
||||||
}
|
|
||||||
ArrayLen::Known(n) => {
|
|
||||||
if n != value.len() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
value[..n].to_vec()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(KclValue::HomArray { value, ty: ty.clone() })
|
|
||||||
}
|
|
||||||
value if len.satisfied(1) && value.has_type(ty) => Some(KclValue::HomArray {
|
|
||||||
value: vec![value.clone()],
|
value: vec![value.clone()],
|
||||||
ty: ty.clone(),
|
ty: ty.clone(),
|
||||||
}),
|
}),
|
||||||
KclValue::MixedArray { value, .. } => {
|
KclValue::MixedArray { value, .. } => {
|
||||||
let value = match len {
|
let len = len.satisfied(value.len(), allow_shrink)?;
|
||||||
ArrayLen::None => value.clone(),
|
|
||||||
ArrayLen::NonEmpty => {
|
|
||||||
if value.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
value.clone()
|
let value = value[..len]
|
||||||
}
|
|
||||||
ArrayLen::Known(n) => {
|
|
||||||
if n != value.len() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
value[..n].to_vec()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let value = value
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| v.coerce(ty, exec_state))
|
.map(|v| v.coerce(ty, exec_state))
|
||||||
.collect::<Option<Vec<_>>>()?;
|
.collect::<Option<Vec<_>>>()?;
|
||||||
|
|
||||||
Some(KclValue::HomArray { value, ty: ty.clone() })
|
Some(KclValue::HomArray { value, ty: ty.clone() })
|
||||||
}
|
}
|
||||||
KclValue::KclNone { .. } if len.satisfied(0) => Some(KclValue::HomArray {
|
KclValue::KclNone { .. } if len.satisfied(0, false).is_some() => Some(KclValue::HomArray {
|
||||||
value: Vec::new(),
|
value: Vec::new(),
|
||||||
ty: ty.clone(),
|
ty: ty.clone(),
|
||||||
}),
|
}),
|
||||||
@ -1251,4 +1337,119 @@ mod test {
|
|||||||
assert!(count.coerce(&tyb, &mut exec_state).is_none());
|
assert!(count.coerce(&tyb, &mut exec_state).is_none());
|
||||||
assert!(count.coerce(&tyb2, &mut exec_state).is_none());
|
assert!(count.coerce(&tyb2, &mut exec_state).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn coerce_axes() {
|
||||||
|
let mut exec_state = ExecState::new(&crate::ExecutorContext::new_mock().await);
|
||||||
|
|
||||||
|
// Subtyping
|
||||||
|
assert!(RuntimeType::Primitive(PrimitiveType::Axis2d).subtype(&RuntimeType::Primitive(PrimitiveType::Axis2d)));
|
||||||
|
assert!(RuntimeType::Primitive(PrimitiveType::Axis3d).subtype(&RuntimeType::Primitive(PrimitiveType::Axis3d)));
|
||||||
|
assert!(!RuntimeType::Primitive(PrimitiveType::Axis3d).subtype(&RuntimeType::Primitive(PrimitiveType::Axis2d)));
|
||||||
|
assert!(!RuntimeType::Primitive(PrimitiveType::Axis2d).subtype(&RuntimeType::Primitive(PrimitiveType::Axis3d)));
|
||||||
|
|
||||||
|
// Coercion
|
||||||
|
let a2d = KclValue::Object {
|
||||||
|
value: [
|
||||||
|
(
|
||||||
|
"origin".to_owned(),
|
||||||
|
KclValue::HomArray {
|
||||||
|
value: vec![
|
||||||
|
KclValue::Number {
|
||||||
|
value: 0.0,
|
||||||
|
ty: NumericType::mm(),
|
||||||
|
meta: Vec::new(),
|
||||||
|
},
|
||||||
|
KclValue::Number {
|
||||||
|
value: 0.0,
|
||||||
|
ty: NumericType::mm(),
|
||||||
|
meta: Vec::new(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ty: RuntimeType::Primitive(PrimitiveType::Number(NumericType::mm())),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"direction".to_owned(),
|
||||||
|
KclValue::HomArray {
|
||||||
|
value: vec![
|
||||||
|
KclValue::Number {
|
||||||
|
value: 1.0,
|
||||||
|
ty: NumericType::mm(),
|
||||||
|
meta: Vec::new(),
|
||||||
|
},
|
||||||
|
KclValue::Number {
|
||||||
|
value: 0.0,
|
||||||
|
ty: NumericType::mm(),
|
||||||
|
meta: Vec::new(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ty: RuntimeType::Primitive(PrimitiveType::Number(NumericType::mm())),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
meta: Vec::new(),
|
||||||
|
};
|
||||||
|
let a3d = KclValue::Object {
|
||||||
|
value: [
|
||||||
|
(
|
||||||
|
"origin".to_owned(),
|
||||||
|
KclValue::HomArray {
|
||||||
|
value: vec![
|
||||||
|
KclValue::Number {
|
||||||
|
value: 0.0,
|
||||||
|
ty: NumericType::mm(),
|
||||||
|
meta: Vec::new(),
|
||||||
|
},
|
||||||
|
KclValue::Number {
|
||||||
|
value: 0.0,
|
||||||
|
ty: NumericType::mm(),
|
||||||
|
meta: Vec::new(),
|
||||||
|
},
|
||||||
|
KclValue::Number {
|
||||||
|
value: 0.0,
|
||||||
|
ty: NumericType::mm(),
|
||||||
|
meta: Vec::new(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ty: RuntimeType::Primitive(PrimitiveType::Number(NumericType::mm())),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"direction".to_owned(),
|
||||||
|
KclValue::HomArray {
|
||||||
|
value: vec![
|
||||||
|
KclValue::Number {
|
||||||
|
value: 1.0,
|
||||||
|
ty: NumericType::mm(),
|
||||||
|
meta: Vec::new(),
|
||||||
|
},
|
||||||
|
KclValue::Number {
|
||||||
|
value: 0.0,
|
||||||
|
ty: NumericType::mm(),
|
||||||
|
meta: Vec::new(),
|
||||||
|
},
|
||||||
|
KclValue::Number {
|
||||||
|
value: 1.0,
|
||||||
|
ty: NumericType::mm(),
|
||||||
|
meta: Vec::new(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ty: RuntimeType::Primitive(PrimitiveType::Number(NumericType::mm())),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
meta: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let ty2d = RuntimeType::Primitive(PrimitiveType::Axis2d);
|
||||||
|
let ty3d = RuntimeType::Primitive(PrimitiveType::Axis3d);
|
||||||
|
|
||||||
|
assert_coerce_results(&a2d, &ty2d, &a2d, &mut exec_state);
|
||||||
|
assert_coerce_results(&a3d, &ty3d, &a3d, &mut exec_state);
|
||||||
|
assert_coerce_results(&a3d, &ty2d, &a2d, &mut exec_state);
|
||||||
|
assert!(a2d.coerce(&ty3d, &mut exec_state).is_none());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ const Part001 = startSketchOn('XY')
|
|||||||
|> line([0, pipeLength], %)
|
|> line([0, pipeLength], %)
|
||||||
|> angledLineToX({ angle: 60, to: pipeLargeDia }, %)
|
|> angledLineToX({ angle: 60, to: pipeLargeDia }, %)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis: 'y' }, %)
|
|> revolve({ axis = Y }, %)
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -156,7 +156,7 @@ const part001 = startSketchOn('XY')
|
|||||||
|> line([0, pipeLength], %)
|
|> line([0, pipeLength], %)
|
||||||
|> angledLineToX({ angle: 60, to: pipeLargeDia }, %)
|
|> angledLineToX({ angle: 60, to: pipeLargeDia }, %)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis: 'y' }, %)
|
|> revolve({ axis = Y }, %)
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1632,7 +1632,7 @@ insideRevolve = startSketchOn(XZ)
|
|||||||
|> line(end = [0, -thickness])
|
|> line(end = [0, -thickness])
|
||||||
|> line(end = [-overHangLength, 0])
|
|> line(end = [-overHangLength, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis: 'y' }, %)
|
|> revolve({ axis = Y }, %)
|
||||||
|
|
||||||
// Sketch and revolve one of the balls and duplicate it using a circular pattern. (This is currently a workaround, we have a bug with rotating on a sketch that touches the rotation axis)
|
// Sketch and revolve one of the balls and duplicate it using a circular pattern. (This is currently a workaround, we have a bug with rotating on a sketch that touches the rotation axis)
|
||||||
sphere = startSketchOn(XZ)
|
sphere = startSketchOn(XZ)
|
||||||
@ -1647,7 +1647,7 @@ sphere = startSketchOn(XZ)
|
|||||||
radius: sphereDia / 2 - 0.05
|
radius: sphereDia / 2 - 0.05
|
||||||
}, %)
|
}, %)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis: 'x' }, %)
|
|> revolve({ axis = X }, %)
|
||||||
|> patternCircular3d(
|
|> patternCircular3d(
|
||||||
axis = [0, 0, 1],
|
axis = [0, 0, 1],
|
||||||
center = [0, 0, 0],
|
center = [0, 0, 0],
|
||||||
@ -1671,7 +1671,7 @@ outsideRevolve = startSketchOn(XZ)
|
|||||||
|> line(end = [0, thickness])
|
|> line(end = [0, thickness])
|
||||||
|> line(end = [overHangLength - thickness, 0])
|
|> line(end = [overHangLength - thickness, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis: 'y' }, %)"#
|
|> revolve({ axis = Y }, %)"#
|
||||||
.to_string(),
|
.to_string(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -1705,7 +1705,7 @@ outsideRevolve = startSketchOn(XZ)
|
|||||||
start: tower_lsp::lsp_types::Position { line: 0, character: 0 },
|
start: tower_lsp::lsp_types::Position { line: 0, character: 0 },
|
||||||
end: tower_lsp::lsp_types::Position {
|
end: tower_lsp::lsp_types::Position {
|
||||||
line: 60,
|
line: 60,
|
||||||
character: 30
|
character: 29
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -1732,7 +1732,7 @@ insideRevolve = startSketchOn(XZ)
|
|||||||
|> line(end = [0, -thickness])
|
|> line(end = [0, -thickness])
|
||||||
|> line(end = [-overHangLength, 0])
|
|> line(end = [-overHangLength, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis = 'y' }, %)
|
|> revolve({ axis = Y }, %)
|
||||||
|
|
||||||
// Sketch and revolve one of the balls and duplicate it using a circular pattern. (This is currently a workaround, we have a bug with rotating on a sketch that touches the rotation axis)
|
// Sketch and revolve one of the balls and duplicate it using a circular pattern. (This is currently a workaround, we have a bug with rotating on a sketch that touches the rotation axis)
|
||||||
sphere = startSketchOn(XZ)
|
sphere = startSketchOn(XZ)
|
||||||
@ -1747,7 +1747,7 @@ sphere = startSketchOn(XZ)
|
|||||||
radius = sphereDia / 2 - 0.05
|
radius = sphereDia / 2 - 0.05
|
||||||
}, %)
|
}, %)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis = 'x' }, %)
|
|> revolve({ axis = X }, %)
|
||||||
|> patternCircular3d(
|
|> patternCircular3d(
|
||||||
axis = [0, 0, 1],
|
axis = [0, 0, 1],
|
||||||
center = [0, 0, 0],
|
center = [0, 0, 0],
|
||||||
@ -1771,7 +1771,7 @@ outsideRevolve = startSketchOn(XZ)
|
|||||||
|> line(end = [0, thickness])
|
|> line(end = [0, thickness])
|
||||||
|> line(end = [overHangLength - thickness, 0])
|
|> line(end = [overHangLength - thickness, 0])
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis = 'y' }, %)"#
|
|> revolve({ axis = Y }, %)"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ pub(crate) fn read_std(mod_name: &str) -> Option<&'static str> {
|
|||||||
"prelude" => Some(include_str!("../std/prelude.kcl")),
|
"prelude" => Some(include_str!("../std/prelude.kcl")),
|
||||||
"math" => Some(include_str!("../std/math.kcl")),
|
"math" => Some(include_str!("../std/math.kcl")),
|
||||||
"sketch" => Some(include_str!("../std/sketch.kcl")),
|
"sketch" => Some(include_str!("../std/sketch.kcl")),
|
||||||
|
"turns" => Some(include_str!("../std/turns.kcl")),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1609,10 +1609,9 @@ impl ImportStatement {
|
|||||||
return Some(alias.name.clone());
|
return Some(alias.name.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut parts = match &self.path {
|
match &self.path {
|
||||||
ImportPath::Kcl { filename: s } | ImportPath::Foreign { path: s } => s.split('.'),
|
ImportPath::Kcl { filename: s } | ImportPath::Foreign { path: s } => {
|
||||||
_ => return None,
|
let mut parts = s.split('.');
|
||||||
};
|
|
||||||
let path = parts.next()?;
|
let path = parts.next()?;
|
||||||
let _ext = parts.next()?;
|
let _ext = parts.next()?;
|
||||||
let rest = parts.next();
|
let rest = parts.next();
|
||||||
@ -1623,6 +1622,9 @@ impl ImportStatement {
|
|||||||
|
|
||||||
path.rsplit(&['/', '\\']).next().map(str::to_owned)
|
path.rsplit(&['/', '\\']).next().map(str::to_owned)
|
||||||
}
|
}
|
||||||
|
ImportPath::Std { path } => path.last().cloned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&ImportStatement> for Vec<CompletionItem> {
|
impl From<&ImportStatement> for Vec<CompletionItem> {
|
||||||
|
@ -152,7 +152,12 @@ const STR_DEPRECATIONS: [(&str, &str); 6] = [
|
|||||||
("-YZ", "-YZ"),
|
("-YZ", "-YZ"),
|
||||||
];
|
];
|
||||||
const FN_DEPRECATIONS: [(&str, &str); 3] = [("pi", "PI"), ("e", "E"), ("tau", "TAU")];
|
const FN_DEPRECATIONS: [(&str, &str); 3] = [("pi", "PI"), ("e", "E"), ("tau", "TAU")];
|
||||||
const CONST_DEPRECATIONS: [(&str, &str); 0] = [];
|
const CONST_DEPRECATIONS: [(&str, &str); 4] = [
|
||||||
|
("ZERO", "turns::ZERO"),
|
||||||
|
("QUARTER_TURN", "turns::QUARTER_TURN"),
|
||||||
|
("HALF_TURN", "turns::HALF_TURN"),
|
||||||
|
("THREE_QUARTER_TURN", "turns::THREE_QUARTER_TURN"),
|
||||||
|
];
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum DeprecationKind {
|
pub enum DeprecationKind {
|
||||||
|
@ -286,6 +286,11 @@ fn non_code_node(i: &mut TokenSlice) -> PResult<Node<NonCodeNode>> {
|
|||||||
alt((non_code_node_leading_whitespace, non_code_node_no_leading_whitespace)).parse_next(i)
|
alt((non_code_node_leading_whitespace, non_code_node_no_leading_whitespace)).parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn outer_annotation(i: &mut TokenSlice) -> PResult<Node<Annotation>> {
|
||||||
|
peek((at_sign, open_paren)).parse_next(i)?;
|
||||||
|
annotation(i)
|
||||||
|
}
|
||||||
|
|
||||||
fn annotation(i: &mut TokenSlice) -> PResult<Node<Annotation>> {
|
fn annotation(i: &mut TokenSlice) -> PResult<Node<Annotation>> {
|
||||||
let at = at_sign.parse_next(i)?;
|
let at = at_sign.parse_next(i)?;
|
||||||
let name = opt(binding_name).parse_next(i)?;
|
let name = opt(binding_name).parse_next(i)?;
|
||||||
@ -1823,14 +1828,6 @@ fn import_stmt(i: &mut TokenSlice) -> PResult<BoxNode<ImportStatement>> {
|
|||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
));
|
));
|
||||||
} else if matches!(path, ImportPath::Std { .. }) && matches!(selector, ImportSelector::None { .. }) {
|
|
||||||
return Err(ErrMode::Cut(
|
|
||||||
CompilationError::fatal(
|
|
||||||
SourceRange::new(start, end, module_id),
|
|
||||||
"the standard library cannot be imported as a part",
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Node::boxed(
|
Ok(Node::boxed(
|
||||||
@ -2910,13 +2907,17 @@ struct ParamDescription {
|
|||||||
arg_name: Token,
|
arg_name: Token,
|
||||||
type_: std::option::Option<Node<Type>>,
|
type_: std::option::Option<Node<Type>>,
|
||||||
default_value: Option<DefaultParamVal>,
|
default_value: Option<DefaultParamVal>,
|
||||||
|
attr: Option<Node<Annotation>>,
|
||||||
comments: Option<Node<Vec<String>>>,
|
comments: Option<Node<Vec<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parameter(i: &mut TokenSlice) -> PResult<ParamDescription> {
|
fn parameter(i: &mut TokenSlice) -> PResult<ParamDescription> {
|
||||||
let (_, comments, found_at_sign, arg_name, question_mark, _, type_, _ws, default_literal) = (
|
let (_, comments, _, attr, _, found_at_sign, arg_name, question_mark, _, type_, _ws, default_literal) = (
|
||||||
opt(whitespace),
|
opt(whitespace),
|
||||||
opt(comments),
|
opt(comments),
|
||||||
|
opt(whitespace),
|
||||||
|
opt(outer_annotation),
|
||||||
|
opt(whitespace),
|
||||||
opt(at_sign),
|
opt(at_sign),
|
||||||
any.verify(|token: &Token| !matches!(token.token_type, TokenType::Brace) || token.value != ")"),
|
any.verify(|token: &Token| !matches!(token.token_type, TokenType::Brace) || token.value != ")"),
|
||||||
opt(question_mark),
|
opt(question_mark),
|
||||||
@ -2941,6 +2942,7 @@ fn parameter(i: &mut TokenSlice) -> PResult<ParamDescription> {
|
|||||||
return Err(ErrMode::Backtrack(ContextError::from(e)));
|
return Err(ErrMode::Backtrack(ContextError::from(e)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
attr,
|
||||||
comments,
|
comments,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -2962,6 +2964,7 @@ fn parameters(i: &mut TokenSlice) -> PResult<Vec<Parameter>> {
|
|||||||
arg_name,
|
arg_name,
|
||||||
type_,
|
type_,
|
||||||
default_value,
|
default_value,
|
||||||
|
attr,
|
||||||
comments,
|
comments,
|
||||||
}| {
|
}| {
|
||||||
let mut identifier = Node::<Identifier>::try_from(arg_name)?;
|
let mut identifier = Node::<Identifier>::try_from(arg_name)?;
|
||||||
@ -2969,6 +2972,9 @@ fn parameters(i: &mut TokenSlice) -> PResult<Vec<Parameter>> {
|
|||||||
identifier.comment_start = comments.start;
|
identifier.comment_start = comments.start;
|
||||||
identifier.pre_comments = comments.inner;
|
identifier.pre_comments = comments.inner;
|
||||||
}
|
}
|
||||||
|
if let Some(attr) = attr {
|
||||||
|
identifier.outer_attrs.push(attr);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Parameter {
|
Ok(Parameter {
|
||||||
identifier,
|
identifier,
|
||||||
|
@ -75,7 +75,7 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
|||||||
/// This will work on any solid, including extruded solids, revolved solids, and shelled solids.
|
/// This will work on any solid, including extruded solids, revolved solids, and shelled solids.
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// // Add color to an extruded solid.
|
/// // Add color to an extruded solid.
|
||||||
/// exampleSketch = startSketchOn("XZ")
|
/// exampleSketch = startSketchOn(XZ)
|
||||||
/// |> startProfileAt([0, 0], %)
|
/// |> startProfileAt([0, 0], %)
|
||||||
/// |> line(endAbsolute = [10, 0])
|
/// |> line(endAbsolute = [10, 0])
|
||||||
/// |> line(endAbsolute = [0, 10])
|
/// |> line(endAbsolute = [0, 10])
|
||||||
@ -89,9 +89,9 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
|||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// // Add color to a revolved solid.
|
/// // Add color to a revolved solid.
|
||||||
/// sketch001 = startSketchOn('XY')
|
/// sketch001 = startSketchOn(XY)
|
||||||
/// |> circle( center = [15, 0], radius = 5 )
|
/// |> circle( center = [15, 0], radius = 5 )
|
||||||
/// |> revolve( angle = 360, axis = 'y')
|
/// |> revolve( angle = 360, axis = Y)
|
||||||
/// |> appearance(
|
/// |> appearance(
|
||||||
/// color = '#ff0000',
|
/// color = '#ff0000',
|
||||||
/// metalness = 90,
|
/// metalness = 90,
|
||||||
@ -102,7 +102,7 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// // Add color to different solids.
|
/// // Add color to different solids.
|
||||||
/// fn cube(center) {
|
/// fn cube(center) {
|
||||||
/// return startSketchOn('XY')
|
/// return startSketchOn(XY)
|
||||||
/// |> startProfileAt([center[0] - 10, center[1] - 10], %)
|
/// |> startProfileAt([center[0] - 10, center[1] - 10], %)
|
||||||
/// |> line(endAbsolute = [center[0] + 10, center[1] - 10])
|
/// |> line(endAbsolute = [center[0] + 10, center[1] - 10])
|
||||||
/// |> line(endAbsolute = [center[0] + 10, center[1] + 10])
|
/// |> line(endAbsolute = [center[0] + 10, center[1] + 10])
|
||||||
@ -122,7 +122,7 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// // You can set the appearance before or after you shell it will yield the same result.
|
/// // You can set the appearance before or after you shell it will yield the same result.
|
||||||
/// // This example shows setting the appearance _after_ the shell.
|
/// // This example shows setting the appearance _after_ the shell.
|
||||||
/// firstSketch = startSketchOn('XY')
|
/// firstSketch = startSketchOn(XY)
|
||||||
/// |> startProfileAt([-12, 12], %)
|
/// |> startProfileAt([-12, 12], %)
|
||||||
/// |> line(end = [24, 0])
|
/// |> line(end = [24, 0])
|
||||||
/// |> line(end = [0, -24])
|
/// |> line(end = [0, -24])
|
||||||
@ -145,7 +145,7 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// // You can set the appearance before or after you shell it will yield the same result.
|
/// // You can set the appearance before or after you shell it will yield the same result.
|
||||||
/// // This example shows setting the appearance _before_ the shell.
|
/// // This example shows setting the appearance _before_ the shell.
|
||||||
/// firstSketch = startSketchOn('XY')
|
/// firstSketch = startSketchOn(XY)
|
||||||
/// |> startProfileAt([-12, 12], %)
|
/// |> startProfileAt([-12, 12], %)
|
||||||
/// |> line(end = [24, 0])
|
/// |> line(end = [24, 0])
|
||||||
/// |> line(end = [0, -24])
|
/// |> line(end = [0, -24])
|
||||||
@ -168,7 +168,7 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// // Setting the appearance of a 3D pattern can be done _before_ or _after_ the pattern.
|
/// // Setting the appearance of a 3D pattern can be done _before_ or _after_ the pattern.
|
||||||
/// // This example shows _before_ the pattern.
|
/// // This example shows _before_ the pattern.
|
||||||
/// exampleSketch = startSketchOn('XZ')
|
/// exampleSketch = startSketchOn(XZ)
|
||||||
/// |> startProfileAt([0, 0], %)
|
/// |> startProfileAt([0, 0], %)
|
||||||
/// |> line(end = [0, 2])
|
/// |> line(end = [0, 2])
|
||||||
/// |> line(end = [3, 1])
|
/// |> line(end = [3, 1])
|
||||||
@ -191,7 +191,7 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// // Setting the appearance of a 3D pattern can be done _before_ or _after_ the pattern.
|
/// // Setting the appearance of a 3D pattern can be done _before_ or _after_ the pattern.
|
||||||
/// // This example shows _after_ the pattern.
|
/// // This example shows _after_ the pattern.
|
||||||
/// exampleSketch = startSketchOn('XZ')
|
/// exampleSketch = startSketchOn(XZ)
|
||||||
/// |> startProfileAt([0, 0], %)
|
/// |> startProfileAt([0, 0], %)
|
||||||
/// |> line(end = [0, 2])
|
/// |> line(end = [0, 2])
|
||||||
/// |> line(end = [3, 1])
|
/// |> line(end = [3, 1])
|
||||||
@ -213,7 +213,7 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
|||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// // Color the result of a 2D pattern that was extruded.
|
/// // Color the result of a 2D pattern that was extruded.
|
||||||
/// exampleSketch = startSketchOn('XZ')
|
/// exampleSketch = startSketchOn(XZ)
|
||||||
/// |> startProfileAt([.5, 25], %)
|
/// |> startProfileAt([.5, 25], %)
|
||||||
/// |> line(end = [0, 5])
|
/// |> line(end = [0, 5])
|
||||||
/// |> line(end = [-1, 0])
|
/// |> line(end = [-1, 0])
|
||||||
@ -238,7 +238,7 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
|||||||
/// // Color the result of a sweep.
|
/// // Color the result of a sweep.
|
||||||
///
|
///
|
||||||
/// // Create a path for the sweep.
|
/// // Create a path for the sweep.
|
||||||
/// sweepPath = startSketchOn('XZ')
|
/// sweepPath = startSketchOn(XZ)
|
||||||
/// |> startProfileAt([0.05, 0.05], %)
|
/// |> startProfileAt([0.05, 0.05], %)
|
||||||
/// |> line(end = [0, 7])
|
/// |> line(end = [0, 7])
|
||||||
/// |> tangentialArc({
|
/// |> tangentialArc({
|
||||||
@ -252,13 +252,13 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
|||||||
/// }, %)
|
/// }, %)
|
||||||
/// |> line(end = [0, 7])
|
/// |> line(end = [0, 7])
|
||||||
///
|
///
|
||||||
/// pipeHole = startSketchOn('XY')
|
/// pipeHole = startSketchOn(XY)
|
||||||
/// |> circle(
|
/// |> circle(
|
||||||
/// center = [0, 0],
|
/// center = [0, 0],
|
||||||
/// radius = 1.5,
|
/// radius = 1.5,
|
||||||
/// )
|
/// )
|
||||||
///
|
///
|
||||||
/// sweepSketch = startSketchOn('XY')
|
/// sweepSketch = startSketchOn(XY)
|
||||||
/// |> circle(
|
/// |> circle(
|
||||||
/// center = [0, 0],
|
/// center = [0, 0],
|
||||||
/// radius = 2,
|
/// radius = 2,
|
||||||
|
@ -154,6 +154,22 @@ impl Args {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_kw_arg_opt_typed<T>(
|
||||||
|
&self,
|
||||||
|
label: &str,
|
||||||
|
ty: &RuntimeType,
|
||||||
|
exec_state: &mut ExecState,
|
||||||
|
) -> Result<Option<T>, KclError>
|
||||||
|
where
|
||||||
|
T: for<'a> FromKclValue<'a>,
|
||||||
|
{
|
||||||
|
if self.kw_args.labeled.get(label).is_none() {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.get_kw_arg_typed(label, ty, exec_state).map(Some)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a keyword argument. If not set, returns Err.
|
/// Get a keyword argument. If not set, returns Err.
|
||||||
pub(crate) fn get_kw_arg<'a, T>(&'a self, label: &str) -> Result<T, KclError>
|
pub(crate) fn get_kw_arg<'a, T>(&'a self, label: &str) -> Result<T, KclError>
|
||||||
where
|
where
|
||||||
@ -675,37 +691,6 @@ impl Args {
|
|||||||
FromArgs::from_args(self, 0)
|
FromArgs::from_args(self, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_data_and_sketches<'a, T>(
|
|
||||||
&'a self,
|
|
||||||
exec_state: &mut ExecState,
|
|
||||||
) -> Result<(T, Vec<Sketch>), KclError>
|
|
||||||
where
|
|
||||||
T: serde::de::DeserializeOwned + FromArgs<'a>,
|
|
||||||
{
|
|
||||||
let data: T = FromArgs::from_args(self, 0)?;
|
|
||||||
let Some(arg1) = self.args.get(1) else {
|
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
|
||||||
message: "Expected one or more sketches for second argument".to_owned(),
|
|
||||||
source_ranges: vec![self.source_range],
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
let sarg = arg1
|
|
||||||
.value
|
|
||||||
.coerce(&RuntimeType::sketches(), exec_state)
|
|
||||||
.ok_or(KclError::Type(KclErrorDetails {
|
|
||||||
message: format!(
|
|
||||||
"Expected one or more sketches for second argument, found {}",
|
|
||||||
arg1.value.human_friendly_type()
|
|
||||||
),
|
|
||||||
source_ranges: vec![self.source_range],
|
|
||||||
}))?;
|
|
||||||
let sketches = match sarg {
|
|
||||||
KclValue::HomArray { value, .. } => value.iter().map(|v| v.as_sketch().unwrap().clone()).collect(),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
Ok((data, sketches))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn get_data_and_sketch_and_tag<'a, T>(
|
pub(crate) fn get_data_and_sketch_and_tag<'a, T>(
|
||||||
&'a self,
|
&'a self,
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
@ -1583,50 +1568,6 @@ impl<'a> FromKclValue<'a> for super::sketch::SketchData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FromKclValue<'a> for super::axis_or_reference::AxisAndOrigin2d {
|
|
||||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
|
||||||
// Case 1: predefined planes.
|
|
||||||
if let Some(s) = arg.as_str() {
|
|
||||||
return match s {
|
|
||||||
"X" | "x" => Some(Self::X),
|
|
||||||
"Y" | "y" => Some(Self::Y),
|
|
||||||
"-X" | "-x" => Some(Self::NegX),
|
|
||||||
"-Y" | "-y" => Some(Self::NegY),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// Case 2: custom planes.
|
|
||||||
let obj = arg.as_object()?;
|
|
||||||
let_field_of!(obj, custom, &KclObjectFields);
|
|
||||||
let_field_of!(custom, origin);
|
|
||||||
let_field_of!(custom, axis);
|
|
||||||
Some(Self::Custom { axis, origin })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FromKclValue<'a> for super::axis_or_reference::AxisAndOrigin3d {
|
|
||||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
|
||||||
// Case 1: predefined planes.
|
|
||||||
if let Some(s) = arg.as_str() {
|
|
||||||
return match s {
|
|
||||||
"X" | "x" => Some(Self::X),
|
|
||||||
"Y" | "y" => Some(Self::Y),
|
|
||||||
"Z" | "z" => Some(Self::Z),
|
|
||||||
"-X" | "-x" => Some(Self::NegX),
|
|
||||||
"-Y" | "-y" => Some(Self::NegY),
|
|
||||||
"-Z" | "-z" => Some(Self::NegZ),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// Case 2: custom planes.
|
|
||||||
let obj = arg.as_object()?;
|
|
||||||
let_field_of!(obj, custom, &KclObjectFields);
|
|
||||||
let_field_of!(custom, origin);
|
|
||||||
let_field_of!(custom, axis);
|
|
||||||
Some(Self::Custom { axis, origin })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FromKclValue<'a> for super::fillet::EdgeReference {
|
impl<'a> FromKclValue<'a> for super::fillet::EdgeReference {
|
||||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||||
let id = arg.as_uuid().map(Self::Uuid);
|
let id = arg.as_uuid().map(Self::Uuid);
|
||||||
@ -1637,25 +1578,27 @@ impl<'a> FromKclValue<'a> for super::fillet::EdgeReference {
|
|||||||
|
|
||||||
impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis2dOrEdgeReference {
|
impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis2dOrEdgeReference {
|
||||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||||
let case1 = super::axis_or_reference::AxisAndOrigin2d::from_kcl_val;
|
let case1 = |arg: &KclValue| {
|
||||||
|
let obj = arg.as_object()?;
|
||||||
|
let_field_of!(obj, direction);
|
||||||
|
let_field_of!(obj, origin);
|
||||||
|
Some(Self::Axis { direction, origin })
|
||||||
|
};
|
||||||
let case2 = super::fillet::EdgeReference::from_kcl_val;
|
let case2 = super::fillet::EdgeReference::from_kcl_val;
|
||||||
case1(arg).map(Self::Axis).or_else(|| case2(arg).map(Self::Edge))
|
case1(arg).or_else(|| case2(arg).map(Self::Edge))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis3dOrEdgeReference {
|
impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis3dOrEdgeReference {
|
||||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||||
let case1 = super::axis_or_reference::AxisAndOrigin3d::from_kcl_val;
|
let case1 = |arg: &KclValue| {
|
||||||
let case2 = super::fillet::EdgeReference::from_kcl_val;
|
|
||||||
case1(arg).map(Self::Axis).or_else(|| case2(arg).map(Self::Edge))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FromKclValue<'a> for super::mirror::Mirror2dData {
|
|
||||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
|
||||||
let obj = arg.as_object()?;
|
let obj = arg.as_object()?;
|
||||||
let_field_of!(obj, axis);
|
let_field_of!(obj, direction);
|
||||||
Some(Self { axis })
|
let_field_of!(obj, origin);
|
||||||
|
Some(Self::Axis { direction, origin })
|
||||||
|
};
|
||||||
|
let case2 = super::fillet::EdgeReference::from_kcl_val;
|
||||||
|
case1(arg).or_else(|| case2(arg).map(Self::Edge))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,233 +1,21 @@
|
|||||||
//! Types for referencing an axis or edge.
|
//! Types for referencing an axis or edge.
|
||||||
|
|
||||||
use anyhow::Result;
|
use crate::std::fillet::EdgeReference;
|
||||||
use kcmc::length_unit::LengthUnit;
|
|
||||||
use kittycad_modeling_cmds::{self as kcmc};
|
|
||||||
use schemars::JsonSchema;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{errors::KclError, std::fillet::EdgeReference};
|
|
||||||
|
|
||||||
/// A 2D axis or tagged edge.
|
/// A 2D axis or tagged edge.
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[ts(export)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum Axis2dOrEdgeReference {
|
pub enum Axis2dOrEdgeReference {
|
||||||
/// 2D axis and origin.
|
/// 2D axis and origin.
|
||||||
Axis(AxisAndOrigin2d),
|
Axis { direction: [f64; 2], origin: [f64; 2] },
|
||||||
/// Tagged edge.
|
/// Tagged edge.
|
||||||
Edge(EdgeReference),
|
Edge(EdgeReference),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A 2D axis and origin.
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
|
||||||
#[ts(export)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub enum AxisAndOrigin2d {
|
|
||||||
/// X-axis.
|
|
||||||
#[serde(rename = "X", alias = "x")]
|
|
||||||
X,
|
|
||||||
/// Y-axis.
|
|
||||||
#[serde(rename = "Y", alias = "y")]
|
|
||||||
Y,
|
|
||||||
/// Flip the X-axis.
|
|
||||||
#[serde(rename = "-X", alias = "-x")]
|
|
||||||
NegX,
|
|
||||||
/// Flip the Y-axis.
|
|
||||||
#[serde(rename = "-Y", alias = "-y")]
|
|
||||||
NegY,
|
|
||||||
Custom {
|
|
||||||
/// The axis.
|
|
||||||
axis: [f64; 2],
|
|
||||||
/// The origin.
|
|
||||||
origin: [f64; 2],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AxisAndOrigin2d {
|
|
||||||
/// Get the axis and origin.
|
|
||||||
pub fn axis_and_origin(&self) -> Result<(kcmc::shared::Point3d<f64>, kcmc::shared::Point3d<LengthUnit>), KclError> {
|
|
||||||
let (axis, origin) = match self {
|
|
||||||
AxisAndOrigin2d::X => ([1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
|
|
||||||
AxisAndOrigin2d::Y => ([0.0, 1.0, 0.0], [0.0, 0.0, 0.0]),
|
|
||||||
AxisAndOrigin2d::NegX => ([-1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
|
|
||||||
AxisAndOrigin2d::NegY => ([0.0, -1.0, 0.0], [0.0, 0.0, 0.0]),
|
|
||||||
AxisAndOrigin2d::Custom { axis, origin } => ([axis[0], axis[1], 0.0], [origin[0], origin[1], 0.0]),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((
|
|
||||||
kcmc::shared::Point3d {
|
|
||||||
x: axis[0],
|
|
||||||
y: axis[1],
|
|
||||||
z: axis[2],
|
|
||||||
},
|
|
||||||
kcmc::shared::Point3d {
|
|
||||||
x: LengthUnit(origin[0]),
|
|
||||||
y: LengthUnit(origin[1]),
|
|
||||||
z: LengthUnit(origin[2]),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A 3D axis or tagged edge.
|
/// A 3D axis or tagged edge.
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[ts(export)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum Axis3dOrEdgeReference {
|
pub enum Axis3dOrEdgeReference {
|
||||||
/// 3D axis and origin.
|
/// 3D axis and origin.
|
||||||
Axis(AxisAndOrigin3d),
|
Axis { direction: [f64; 3], origin: [f64; 3] },
|
||||||
/// Tagged edge.
|
/// Tagged edge.
|
||||||
Edge(EdgeReference),
|
Edge(EdgeReference),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A 3D axis and origin.
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
|
||||||
#[ts(export)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub enum AxisAndOrigin3d {
|
|
||||||
/// X-axis.
|
|
||||||
#[serde(rename = "X", alias = "x")]
|
|
||||||
X,
|
|
||||||
/// Y-axis.
|
|
||||||
#[serde(rename = "Y", alias = "y")]
|
|
||||||
Y,
|
|
||||||
/// Z-axis.
|
|
||||||
#[serde(rename = "Z", alias = "z")]
|
|
||||||
Z,
|
|
||||||
/// Flip the X-axis.
|
|
||||||
#[serde(rename = "-X", alias = "-x")]
|
|
||||||
NegX,
|
|
||||||
/// Flip the Y-axis.
|
|
||||||
#[serde(rename = "-Y", alias = "-y")]
|
|
||||||
NegY,
|
|
||||||
/// Flip the Z-axis.
|
|
||||||
#[serde(rename = "-Z", alias = "-z")]
|
|
||||||
NegZ,
|
|
||||||
Custom {
|
|
||||||
/// The axis.
|
|
||||||
axis: [f64; 3],
|
|
||||||
/// The origin.
|
|
||||||
origin: [f64; 3],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AxisAndOrigin3d {
|
|
||||||
/// Get the axis and origin.
|
|
||||||
pub fn axis_and_origin(&self) -> Result<(kcmc::shared::Point3d<f64>, kcmc::shared::Point3d<LengthUnit>), KclError> {
|
|
||||||
let (axis, origin) = match self {
|
|
||||||
AxisAndOrigin3d::X => ([1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
|
|
||||||
AxisAndOrigin3d::Y => ([0.0, 1.0, 0.0], [0.0, 0.0, 0.0]),
|
|
||||||
AxisAndOrigin3d::Z => ([0.0, 0.0, 1.0], [0.0, 0.0, 0.0]),
|
|
||||||
AxisAndOrigin3d::NegX => ([-1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
|
|
||||||
AxisAndOrigin3d::NegY => ([0.0, -1.0, 0.0], [0.0, 0.0, 0.0]),
|
|
||||||
AxisAndOrigin3d::NegZ => ([0.0, 0.0, -1.0], [0.0, 0.0, 0.0]),
|
|
||||||
AxisAndOrigin3d::Custom { axis, origin } => {
|
|
||||||
([axis[0], axis[1], axis[2]], [origin[0], origin[1], origin[2]])
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((
|
|
||||||
kcmc::shared::Point3d {
|
|
||||||
x: axis[0],
|
|
||||||
y: axis[1],
|
|
||||||
z: axis[2],
|
|
||||||
},
|
|
||||||
kcmc::shared::Point3d {
|
|
||||||
x: LengthUnit(origin[0]),
|
|
||||||
y: LengthUnit(origin[1]),
|
|
||||||
z: LengthUnit(origin[2]),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
|
|
||||||
use crate::std::axis_or_reference::{
|
|
||||||
Axis2dOrEdgeReference, Axis3dOrEdgeReference, AxisAndOrigin2d, AxisAndOrigin3d,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_deserialize_revolve_axis_2d() {
|
|
||||||
let data = Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::X);
|
|
||||||
let mut str_json = serde_json::to_string(&data).unwrap();
|
|
||||||
assert_eq!(str_json, "\"X\"");
|
|
||||||
|
|
||||||
str_json = "\"Y\"".to_string();
|
|
||||||
let data: Axis2dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
|
|
||||||
assert_eq!(data, Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::Y));
|
|
||||||
|
|
||||||
str_json = "\"-Y\"".to_string();
|
|
||||||
let data: Axis2dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
|
|
||||||
assert_eq!(data, Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::NegY));
|
|
||||||
|
|
||||||
str_json = "\"-x\"".to_string();
|
|
||||||
let data: Axis2dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
|
|
||||||
assert_eq!(data, Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::NegX));
|
|
||||||
|
|
||||||
let data = Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::Custom {
|
|
||||||
axis: [0.0, -1.0],
|
|
||||||
origin: [1.0, 0.0],
|
|
||||||
});
|
|
||||||
str_json = serde_json::to_string(&data).unwrap();
|
|
||||||
assert_eq!(str_json, r#"{"custom":{"axis":[0.0,-1.0],"origin":[1.0,0.0]}}"#);
|
|
||||||
|
|
||||||
str_json = r#"{"custom": {"axis": [0,-1], "origin": [1,2.0]}}"#.to_string();
|
|
||||||
let data: Axis2dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
data,
|
|
||||||
Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::Custom {
|
|
||||||
axis: [0.0, -1.0],
|
|
||||||
origin: [1.0, 2.0]
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_deserialize_revolve_axis_3d() {
|
|
||||||
let data = Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::X);
|
|
||||||
let mut str_json = serde_json::to_string(&data).unwrap();
|
|
||||||
assert_eq!(str_json, "\"X\"");
|
|
||||||
|
|
||||||
str_json = "\"Y\"".to_string();
|
|
||||||
let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
|
|
||||||
assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::Y));
|
|
||||||
|
|
||||||
str_json = "\"Z\"".to_string();
|
|
||||||
let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
|
|
||||||
assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::Z));
|
|
||||||
|
|
||||||
str_json = "\"-Y\"".to_string();
|
|
||||||
let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
|
|
||||||
assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::NegY));
|
|
||||||
|
|
||||||
str_json = "\"-x\"".to_string();
|
|
||||||
let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
|
|
||||||
assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::NegX));
|
|
||||||
|
|
||||||
str_json = "\"-z\"".to_string();
|
|
||||||
let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
|
|
||||||
assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::NegZ));
|
|
||||||
|
|
||||||
let data = Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::Custom {
|
|
||||||
axis: [0.0, -1.0, 0.0],
|
|
||||||
origin: [1.0, 0.0, 0.0],
|
|
||||||
});
|
|
||||||
str_json = serde_json::to_string(&data).unwrap();
|
|
||||||
assert_eq!(str_json, r#"{"custom":{"axis":[0.0,-1.0,0.0],"origin":[1.0,0.0,0.0]}}"#);
|
|
||||||
|
|
||||||
str_json = r#"{"custom": {"axis": [0,-1,0], "origin": [1,2.0,0]}}"#.to_string();
|
|
||||||
let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
data,
|
|
||||||
Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::Custom {
|
|
||||||
axis: [0.0, -1.0, 0.0],
|
|
||||||
origin: [1.0, 2.0, 0.0]
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
//! Standard library helices.
|
//! Standard library helices.
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use kcl_derive_docs::stdlib;
|
|
||||||
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, shared::Angle, ModelingCmd};
|
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, shared::Angle, ModelingCmd};
|
||||||
use kittycad_modeling_cmds as kcmc;
|
use kittycad_modeling_cmds::{self as kcmc, shared::Point3d};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::KclError,
|
errors::KclError,
|
||||||
execution::{ExecState, Helix as HelixValue, KclValue, Solid},
|
execution::{
|
||||||
|
types::{PrimitiveType, RuntimeType},
|
||||||
|
ExecState, Helix as HelixValue, KclValue, Solid,
|
||||||
|
},
|
||||||
std::{axis_or_reference::Axis3dOrEdgeReference, Args},
|
std::{axis_or_reference::Axis3dOrEdgeReference, Args},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -17,7 +19,14 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
|||||||
let revolutions = args.get_kw_arg("revolutions")?;
|
let revolutions = args.get_kw_arg("revolutions")?;
|
||||||
let ccw = args.get_kw_arg_opt("ccw")?;
|
let ccw = args.get_kw_arg_opt("ccw")?;
|
||||||
let radius = args.get_kw_arg_opt("radius")?;
|
let radius = args.get_kw_arg_opt("radius")?;
|
||||||
let axis = args.get_kw_arg_opt("axis")?;
|
let axis: Option<Axis3dOrEdgeReference> = args.get_kw_arg_opt_typed(
|
||||||
|
"axis",
|
||||||
|
&RuntimeType::Union(vec![
|
||||||
|
RuntimeType::Primitive(PrimitiveType::Edge),
|
||||||
|
RuntimeType::Primitive(PrimitiveType::Axis3d),
|
||||||
|
]),
|
||||||
|
exec_state,
|
||||||
|
)?;
|
||||||
let length = args.get_kw_arg_opt("length")?;
|
let length = args.get_kw_arg_opt("length")?;
|
||||||
let cylinder = args.get_kw_arg_opt("cylinder")?;
|
let cylinder = args.get_kw_arg_opt("cylinder")?;
|
||||||
|
|
||||||
@ -84,100 +93,6 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
|||||||
Ok(KclValue::Helix { value })
|
Ok(KclValue::Helix { value })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a helix.
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // Create a helix around the Z axis.
|
|
||||||
/// helixPath = helix(
|
|
||||||
/// angleStart = 0,
|
|
||||||
/// ccw = true,
|
|
||||||
/// revolutions = 5,
|
|
||||||
/// length = 10,
|
|
||||||
/// radius = 5,
|
|
||||||
/// axis = 'Z',
|
|
||||||
/// )
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// // Create a spring by sweeping around the helix path.
|
|
||||||
/// springSketch = startSketchOn('YZ')
|
|
||||||
/// |> circle( center = [0, 0], radius = 0.5)
|
|
||||||
/// |> sweep(path = helixPath)
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // Create a helix around an edge.
|
|
||||||
/// helper001 = startSketchOn('XZ')
|
|
||||||
/// |> startProfileAt([0, 0], %)
|
|
||||||
/// |> line(end = [0, 10], tag = $edge001)
|
|
||||||
///
|
|
||||||
/// helixPath = helix(
|
|
||||||
/// angleStart = 0,
|
|
||||||
/// ccw = true,
|
|
||||||
/// revolutions = 5,
|
|
||||||
/// length = 10,
|
|
||||||
/// radius = 5,
|
|
||||||
/// axis = edge001,
|
|
||||||
/// )
|
|
||||||
///
|
|
||||||
/// // Create a spring by sweeping around the helix path.
|
|
||||||
/// springSketch = startSketchOn('XY')
|
|
||||||
/// |> circle( center = [0, 0], radius = 0.5 )
|
|
||||||
/// |> sweep(path = helixPath)
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // Create a helix around a custom axis.
|
|
||||||
/// helixPath = helix(
|
|
||||||
/// angleStart = 0,
|
|
||||||
/// ccw = true,
|
|
||||||
/// revolutions = 5,
|
|
||||||
/// length = 10,
|
|
||||||
/// radius = 5,
|
|
||||||
/// axis = {
|
|
||||||
/// custom = {
|
|
||||||
/// axis = [0, 0, 1.0],
|
|
||||||
/// origin = [0, 0.25, 0]
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// )
|
|
||||||
///
|
|
||||||
/// // Create a spring by sweeping around the helix path.
|
|
||||||
/// springSketch = startSketchOn('XY')
|
|
||||||
/// |> circle( center = [0, 0], radius = 1 )
|
|
||||||
/// |> sweep(path = helixPath)
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // Create a helix on a cylinder.
|
|
||||||
///
|
|
||||||
/// part001 = startSketchOn('XY')
|
|
||||||
/// |> circle( center= [5, 5], radius= 10 )
|
|
||||||
/// |> extrude(length = 10)
|
|
||||||
///
|
|
||||||
/// helix(
|
|
||||||
/// angleStart = 0,
|
|
||||||
/// ccw = true,
|
|
||||||
/// revolutions = 16,
|
|
||||||
/// cylinder = part001,
|
|
||||||
/// )
|
|
||||||
/// ```
|
|
||||||
#[stdlib {
|
|
||||||
name = "helix",
|
|
||||||
keywords = true,
|
|
||||||
unlabeled_first = false,
|
|
||||||
args = {
|
|
||||||
revolutions = { docs = "Number of revolutions."},
|
|
||||||
angle_start = { docs = "Start angle (in degrees)."},
|
|
||||||
ccw = { docs = "Is the helix rotation counter clockwise? The default is `false`.", include_in_snippet = false},
|
|
||||||
radius = { docs = "Radius of the helix.", include_in_snippet = true},
|
|
||||||
axis = { docs = "Axis to use for the helix.", include_in_snippet = true},
|
|
||||||
length = { docs = "Length of the helix. This is not necessary if the helix is created around an edge. If not given the length of the edge is used.", include_in_snippet = true},
|
|
||||||
cylinder = { docs = "Cylinder to create the helix on.", include_in_snippet = false},
|
|
||||||
},
|
|
||||||
feature_tree_operation = true,
|
|
||||||
}]
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
async fn inner_helix(
|
async fn inner_helix(
|
||||||
revolutions: f64,
|
revolutions: f64,
|
||||||
@ -221,9 +136,7 @@ async fn inner_helix(
|
|||||||
.await?;
|
.await?;
|
||||||
} else if let (Some(axis), Some(radius)) = (axis, radius) {
|
} else if let (Some(axis), Some(radius)) = (axis, radius) {
|
||||||
match axis {
|
match axis {
|
||||||
Axis3dOrEdgeReference::Axis(axis) => {
|
Axis3dOrEdgeReference::Axis { direction, origin } => {
|
||||||
let (axis, origin) = axis.axis_and_origin()?;
|
|
||||||
|
|
||||||
// Make sure they gave us a length.
|
// Make sure they gave us a length.
|
||||||
let Some(length) = length else {
|
let Some(length) = length else {
|
||||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails {
|
return Err(KclError::Semantic(crate::errors::KclErrorDetails {
|
||||||
@ -240,8 +153,16 @@ async fn inner_helix(
|
|||||||
length: LengthUnit(length),
|
length: LengthUnit(length),
|
||||||
revolutions,
|
revolutions,
|
||||||
start_angle: Angle::from_degrees(angle_start),
|
start_angle: Angle::from_degrees(angle_start),
|
||||||
axis,
|
axis: Point3d {
|
||||||
center: origin,
|
x: direction[0],
|
||||||
|
y: direction[1],
|
||||||
|
z: direction[2],
|
||||||
|
},
|
||||||
|
center: Point3d {
|
||||||
|
x: LengthUnit(origin[0]),
|
||||||
|
y: LengthUnit(origin[1]),
|
||||||
|
z: LengthUnit(origin[2]),
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -1,109 +1,39 @@
|
|||||||
//! Standard library mirror.
|
//! Standard library mirror.
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use kcl_derive_docs::stdlib;
|
|
||||||
use kcmc::{each_cmd as mcmd, ModelingCmd};
|
use kcmc::{each_cmd as mcmd, ModelingCmd};
|
||||||
use kittycad_modeling_cmds::{self as kcmc};
|
use kittycad_modeling_cmds::{self as kcmc, length_unit::LengthUnit, shared::Point3d};
|
||||||
use schemars::JsonSchema;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::KclError,
|
errors::KclError,
|
||||||
execution::{ExecState, KclValue, Sketch},
|
execution::{
|
||||||
|
types::{PrimitiveType, RuntimeType},
|
||||||
|
ExecState, KclValue, Sketch,
|
||||||
|
},
|
||||||
std::{axis_or_reference::Axis2dOrEdgeReference, Args},
|
std::{axis_or_reference::Axis2dOrEdgeReference, Args},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Data for a mirror.
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
|
||||||
#[ts(export)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct Mirror2dData {
|
|
||||||
/// Axis to use as mirror.
|
|
||||||
pub axis: Axis2dOrEdgeReference,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mirror a sketch.
|
/// Mirror a sketch.
|
||||||
///
|
///
|
||||||
/// Only works on unclosed sketches for now.
|
/// Only works on unclosed sketches for now.
|
||||||
pub async fn mirror_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn mirror_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let (data, sketch_set): (Mirror2dData, Vec<Sketch>) = args.get_data_and_sketches(exec_state)?;
|
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
|
||||||
|
let axis = args.get_kw_arg_typed(
|
||||||
|
"axis",
|
||||||
|
&RuntimeType::Union(vec![
|
||||||
|
RuntimeType::Primitive(PrimitiveType::Edge),
|
||||||
|
RuntimeType::Primitive(PrimitiveType::Axis2d),
|
||||||
|
]),
|
||||||
|
exec_state,
|
||||||
|
)?;
|
||||||
|
|
||||||
let sketches = inner_mirror_2d(data, sketch_set, exec_state, args).await?;
|
let sketches = inner_mirror_2d(sketches, axis, exec_state, args).await?;
|
||||||
Ok(sketches.into())
|
Ok(sketches.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mirror a sketch.
|
|
||||||
///
|
|
||||||
/// Only works on unclosed sketches for now.
|
|
||||||
///
|
|
||||||
/// Mirror occurs around a local sketch axis rather than a global axis.
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // Mirror an un-closed sketch across the Y axis.
|
|
||||||
/// sketch001 = startSketchOn('XZ')
|
|
||||||
/// |> startProfileAt([0, 10], %)
|
|
||||||
/// |> line(end = [15, 0])
|
|
||||||
/// |> line(end = [-7, -3])
|
|
||||||
/// |> line(end = [9, -1])
|
|
||||||
/// |> line(end = [-8, -5])
|
|
||||||
/// |> line(end = [9, -3])
|
|
||||||
/// |> line(end = [-8, -3])
|
|
||||||
/// |> line(end = [9, -1])
|
|
||||||
/// |> line(end = [-19, -0])
|
|
||||||
/// |> mirror2d({axis = 'Y'}, %)
|
|
||||||
///
|
|
||||||
/// example = extrude(sketch001, length = 10)
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // Mirror a un-closed sketch across the Y axis.
|
|
||||||
/// sketch001 = startSketchOn('XZ')
|
|
||||||
/// |> startProfileAt([0, 8.5], %)
|
|
||||||
/// |> line(end = [20, -8.5])
|
|
||||||
/// |> line(end = [-20, -8.5])
|
|
||||||
/// |> mirror2d({axis = 'Y'}, %)
|
|
||||||
///
|
|
||||||
/// example = extrude(sketch001, length = 10)
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // Mirror a un-closed sketch across an edge.
|
|
||||||
/// helper001 = startSketchOn('XZ')
|
|
||||||
/// |> startProfileAt([0, 0], %)
|
|
||||||
/// |> line(end = [0, 10], tag = $edge001)
|
|
||||||
///
|
|
||||||
/// sketch001 = startSketchOn('XZ')
|
|
||||||
/// |> startProfileAt([0, 8.5], %)
|
|
||||||
/// |> line(end = [20, -8.5])
|
|
||||||
/// |> line(end = [-20, -8.5])
|
|
||||||
/// |> mirror2d({axis = edge001}, %)
|
|
||||||
///
|
|
||||||
/// // example = extrude(sketch001, length = 10)
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // Mirror an un-closed sketch across a custom axis.
|
|
||||||
/// sketch001 = startSketchOn('XZ')
|
|
||||||
/// |> startProfileAt([0, 8.5], %)
|
|
||||||
/// |> line(end = [20, -8.5])
|
|
||||||
/// |> line(end = [-20, -8.5])
|
|
||||||
/// |> mirror2d({
|
|
||||||
/// axis = {
|
|
||||||
/// custom = {
|
|
||||||
/// axis = [0.0, 1.0],
|
|
||||||
/// origin = [0.0, 0.0]
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }, %)
|
|
||||||
///
|
|
||||||
/// example = extrude(sketch001, length = 10)
|
|
||||||
/// ```
|
|
||||||
#[stdlib {
|
|
||||||
name = "mirror2d",
|
|
||||||
}]
|
|
||||||
async fn inner_mirror_2d(
|
async fn inner_mirror_2d(
|
||||||
data: Mirror2dData,
|
|
||||||
sketches: Vec<Sketch>,
|
sketches: Vec<Sketch>,
|
||||||
|
axis: Axis2dOrEdgeReference,
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
args: Args,
|
args: Args,
|
||||||
) -> Result<Vec<Sketch>, KclError> {
|
) -> Result<Vec<Sketch>, KclError> {
|
||||||
@ -113,16 +43,22 @@ async fn inner_mirror_2d(
|
|||||||
return Ok(starting_sketches);
|
return Ok(starting_sketches);
|
||||||
}
|
}
|
||||||
|
|
||||||
match data.axis {
|
match axis {
|
||||||
Axis2dOrEdgeReference::Axis(axis) => {
|
Axis2dOrEdgeReference::Axis { direction, origin } => {
|
||||||
let (axis, origin) = axis.axis_and_origin()?;
|
|
||||||
|
|
||||||
args.batch_modeling_cmd(
|
args.batch_modeling_cmd(
|
||||||
exec_state.next_uuid(),
|
exec_state.next_uuid(),
|
||||||
ModelingCmd::from(mcmd::EntityMirror {
|
ModelingCmd::from(mcmd::EntityMirror {
|
||||||
ids: starting_sketches.iter().map(|sketch| sketch.id).collect(),
|
ids: starting_sketches.iter().map(|sketch| sketch.id).collect(),
|
||||||
axis,
|
axis: Point3d {
|
||||||
point: origin,
|
x: direction[0],
|
||||||
|
y: direction[1],
|
||||||
|
z: 0.0,
|
||||||
|
},
|
||||||
|
point: Point3d {
|
||||||
|
x: LengthUnit(origin[0]),
|
||||||
|
y: LengthUnit(origin[1]),
|
||||||
|
z: LengthUnit(0.0),
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -26,7 +26,6 @@ pub mod shell;
|
|||||||
pub mod sketch;
|
pub mod sketch;
|
||||||
pub mod sweep;
|
pub mod sweep;
|
||||||
pub mod transform;
|
pub mod transform;
|
||||||
pub mod types;
|
|
||||||
pub mod units;
|
pub mod units;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
@ -96,7 +95,6 @@ lazy_static! {
|
|||||||
Box::new(crate::std::sketch::TangentialArcToRelative),
|
Box::new(crate::std::sketch::TangentialArcToRelative),
|
||||||
Box::new(crate::std::sketch::BezierCurve),
|
Box::new(crate::std::sketch::BezierCurve),
|
||||||
Box::new(crate::std::sketch::Hole),
|
Box::new(crate::std::sketch::Hole),
|
||||||
Box::new(crate::std::mirror::Mirror2D),
|
|
||||||
Box::new(crate::std::patterns::PatternLinear2D),
|
Box::new(crate::std::patterns::PatternLinear2D),
|
||||||
Box::new(crate::std::patterns::PatternLinear3D),
|
Box::new(crate::std::patterns::PatternLinear3D),
|
||||||
Box::new(crate::std::patterns::PatternCircular2D),
|
Box::new(crate::std::patterns::PatternCircular2D),
|
||||||
@ -113,10 +111,8 @@ lazy_static! {
|
|||||||
Box::new(crate::std::edge::GetNextAdjacentEdge),
|
Box::new(crate::std::edge::GetNextAdjacentEdge),
|
||||||
Box::new(crate::std::edge::GetPreviousAdjacentEdge),
|
Box::new(crate::std::edge::GetPreviousAdjacentEdge),
|
||||||
Box::new(crate::std::edge::GetCommonEdge),
|
Box::new(crate::std::edge::GetCommonEdge),
|
||||||
Box::new(crate::std::helix::Helix),
|
|
||||||
Box::new(crate::std::shell::Shell),
|
Box::new(crate::std::shell::Shell),
|
||||||
Box::new(crate::std::shell::Hollow),
|
Box::new(crate::std::shell::Hollow),
|
||||||
Box::new(crate::std::revolve::Revolve),
|
|
||||||
Box::new(crate::std::sweep::Sweep),
|
Box::new(crate::std::sweep::Sweep),
|
||||||
Box::new(crate::std::loft::Loft),
|
Box::new(crate::std::loft::Loft),
|
||||||
Box::new(crate::std::planes::OffsetPlane),
|
Box::new(crate::std::planes::OffsetPlane),
|
||||||
@ -177,6 +173,7 @@ pub fn get_stdlib_fn(name: &str) -> Option<Box<dyn StdLibFn>> {
|
|||||||
pub struct StdFnProps {
|
pub struct StdFnProps {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub deprecated: bool,
|
pub deprecated: bool,
|
||||||
|
pub include_in_feature_tree: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdFnProps {
|
impl StdFnProps {
|
||||||
@ -184,8 +181,14 @@ impl StdFnProps {
|
|||||||
Self {
|
Self {
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
deprecated: false,
|
deprecated: false,
|
||||||
|
include_in_feature_tree: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn include_in_feature_tree(mut self) -> Self {
|
||||||
|
self.include_in_feature_tree = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProps) {
|
pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProps) {
|
||||||
@ -206,6 +209,18 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp
|
|||||||
|e, a| Box::pin(crate::std::shapes::circle(e, a)),
|
|e, a| Box::pin(crate::std::shapes::circle(e, a)),
|
||||||
StdFnProps::default("std::sketch::circle"),
|
StdFnProps::default("std::sketch::circle"),
|
||||||
),
|
),
|
||||||
|
("prelude", "helix") => (
|
||||||
|
|e, a| Box::pin(crate::std::helix::helix(e, a)),
|
||||||
|
StdFnProps::default("std::helix").include_in_feature_tree(),
|
||||||
|
),
|
||||||
|
("sketch", "mirror2d") => (
|
||||||
|
|e, a| Box::pin(crate::std::mirror::mirror_2d(e, a)),
|
||||||
|
StdFnProps::default("std::sketch::mirror2d"),
|
||||||
|
),
|
||||||
|
("prelude", "revolve") => (
|
||||||
|
|e, a| Box::pin(crate::std::revolve::revolve(e, a)),
|
||||||
|
StdFnProps::default("std::revolve").include_in_feature_tree(),
|
||||||
|
),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,6 +232,9 @@ pub(crate) fn std_ty(path: &str, fn_name: &str) -> (PrimitiveType, StdFnProps) {
|
|||||||
("prelude", "Plane") => (PrimitiveType::Plane, StdFnProps::default("std::Plane")),
|
("prelude", "Plane") => (PrimitiveType::Plane, StdFnProps::default("std::Plane")),
|
||||||
("prelude", "Face") => (PrimitiveType::Face, StdFnProps::default("std::Face")),
|
("prelude", "Face") => (PrimitiveType::Face, StdFnProps::default("std::Face")),
|
||||||
("prelude", "Helix") => (PrimitiveType::Helix, StdFnProps::default("std::Helix")),
|
("prelude", "Helix") => (PrimitiveType::Helix, StdFnProps::default("std::Helix")),
|
||||||
|
("prelude", "Edge") => (PrimitiveType::Edge, StdFnProps::default("std::Edge")),
|
||||||
|
("prelude", "Axis2d") => (PrimitiveType::Axis2d, StdFnProps::default("std::Axis2d")),
|
||||||
|
("prelude", "Axis3d") => (PrimitiveType::Axis3d, StdFnProps::default("std::Axis3d")),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
//! Standard library revolution surfaces.
|
//! Standard library revolution surfaces.
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use kcl_derive_docs::stdlib;
|
|
||||||
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, shared::Angle, ModelingCmd};
|
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, shared::Angle, ModelingCmd};
|
||||||
use kittycad_modeling_cmds::{self as kcmc};
|
use kittycad_modeling_cmds::{self as kcmc, shared::Point3d};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
execution::{types::RuntimeType, ExecState, KclValue, Sketch, Solid},
|
execution::{
|
||||||
|
types::{PrimitiveType, RuntimeType},
|
||||||
|
ExecState, KclValue, Sketch, Solid,
|
||||||
|
},
|
||||||
parsing::ast::types::TagNode,
|
parsing::ast::types::TagNode,
|
||||||
std::{axis_or_reference::Axis2dOrEdgeReference, extrude::do_post_extrude, fillet::default_tolerance, Args},
|
std::{axis_or_reference::Axis2dOrEdgeReference, extrude::do_post_extrude, fillet::default_tolerance, Args},
|
||||||
};
|
};
|
||||||
@ -15,7 +17,14 @@ use crate::{
|
|||||||
/// Revolve a sketch or set of sketches around an axis.
|
/// Revolve a sketch or set of sketches around an axis.
|
||||||
pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
|
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
|
||||||
let axis: Axis2dOrEdgeReference = args.get_kw_arg("axis")?;
|
let axis = args.get_kw_arg_typed(
|
||||||
|
"axis",
|
||||||
|
&RuntimeType::Union(vec![
|
||||||
|
RuntimeType::Primitive(PrimitiveType::Edge),
|
||||||
|
RuntimeType::Primitive(PrimitiveType::Axis2d),
|
||||||
|
]),
|
||||||
|
exec_state,
|
||||||
|
)?;
|
||||||
let angle = args.get_kw_arg_opt("angle")?;
|
let angle = args.get_kw_arg_opt("angle")?;
|
||||||
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
||||||
let tag_start = args.get_kw_arg_opt("tagStart")?;
|
let tag_start = args.get_kw_arg_opt("tagStart")?;
|
||||||
@ -25,215 +34,6 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|||||||
Ok(value.into())
|
Ok(value.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rotate a sketch around some provided axis, creating a solid from its extent.
|
|
||||||
///
|
|
||||||
/// This, like extrude, is able to create a 3-dimensional solid from a
|
|
||||||
/// 2-dimensional sketch. However, unlike extrude, this creates a solid
|
|
||||||
/// by using the extent of the sketch as its revolved around an axis rather
|
|
||||||
/// than using the extent of the sketch linearly translated through a third
|
|
||||||
/// dimension.
|
|
||||||
///
|
|
||||||
/// Revolve occurs around a local sketch axis rather than a global axis.
|
|
||||||
///
|
|
||||||
/// You can provide more than one sketch to revolve, and they will all be
|
|
||||||
/// revolved around the same axis.
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// part001 = startSketchOn('XY')
|
|
||||||
/// |> startProfileAt([4, 12], %)
|
|
||||||
/// |> line(end = [2, 0])
|
|
||||||
/// |> line(end = [0, -6])
|
|
||||||
/// |> line(end = [4, -6])
|
|
||||||
/// |> line(end = [0, -6])
|
|
||||||
/// |> line(end = [-3.75, -4.5])
|
|
||||||
/// |> line(end = [0, -5.5])
|
|
||||||
/// |> line(end = [-2, 0])
|
|
||||||
/// |> close()
|
|
||||||
/// |> revolve(axis = 'y') // default angle is 360
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // A donut shape.
|
|
||||||
/// sketch001 = startSketchOn('XY')
|
|
||||||
/// |> circle( center = [15, 0], radius = 5 )
|
|
||||||
/// |> revolve(
|
|
||||||
/// angle = 360,
|
|
||||||
/// axis = 'y'
|
|
||||||
/// )
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// part001 = startSketchOn('XY')
|
|
||||||
/// |> startProfileAt([4, 12], %)
|
|
||||||
/// |> line(end = [2, 0])
|
|
||||||
/// |> line(end = [0, -6])
|
|
||||||
/// |> line(end = [4, -6])
|
|
||||||
/// |> line(end = [0, -6])
|
|
||||||
/// |> line(end = [-3.75, -4.5])
|
|
||||||
/// |> line(end = [0, -5.5])
|
|
||||||
/// |> line(end = [-2, 0])
|
|
||||||
/// |> close()
|
|
||||||
/// |> revolve(axis = 'y', angle = 180)
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// part001 = startSketchOn('XY')
|
|
||||||
/// |> startProfileAt([4, 12], %)
|
|
||||||
/// |> line(end = [2, 0])
|
|
||||||
/// |> line(end = [0, -6])
|
|
||||||
/// |> line(end = [4, -6])
|
|
||||||
/// |> line(end = [0, -6])
|
|
||||||
/// |> line(end = [-3.75, -4.5])
|
|
||||||
/// |> line(end = [0, -5.5])
|
|
||||||
/// |> line(end = [-2, 0])
|
|
||||||
/// |> close()
|
|
||||||
/// |> revolve(axis = 'y', angle = 180)
|
|
||||||
///
|
|
||||||
/// part002 = startSketchOn(part001, 'end')
|
|
||||||
/// |> startProfileAt([4.5, -5], %)
|
|
||||||
/// |> line(end = [0, 5])
|
|
||||||
/// |> line(end = [5, 0])
|
|
||||||
/// |> line(end = [0, -5])
|
|
||||||
/// |> close()
|
|
||||||
/// |> extrude(length = 5)
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// box = startSketchOn('XY')
|
|
||||||
/// |> startProfileAt([0, 0], %)
|
|
||||||
/// |> line(end = [0, 20])
|
|
||||||
/// |> line(end = [20, 0])
|
|
||||||
/// |> line(end = [0, -20])
|
|
||||||
/// |> close()
|
|
||||||
/// |> extrude(length = 20)
|
|
||||||
///
|
|
||||||
/// sketch001 = startSketchOn(box, "END")
|
|
||||||
/// |> circle( center = [10,10], radius = 4 )
|
|
||||||
/// |> revolve(
|
|
||||||
/// angle = -90,
|
|
||||||
/// axis = 'y'
|
|
||||||
/// )
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// box = startSketchOn('XY')
|
|
||||||
/// |> startProfileAt([0, 0], %)
|
|
||||||
/// |> line(end = [0, 20])
|
|
||||||
/// |> line(end = [20, 0])
|
|
||||||
/// |> line(end = [0, -20], tag = $revolveAxis)
|
|
||||||
/// |> close()
|
|
||||||
/// |> extrude(length = 20)
|
|
||||||
///
|
|
||||||
/// sketch001 = startSketchOn(box, "END")
|
|
||||||
/// |> circle( center = [10,10], radius = 4 )
|
|
||||||
/// |> revolve(
|
|
||||||
/// angle = 90,
|
|
||||||
/// axis = getOppositeEdge(revolveAxis)
|
|
||||||
/// )
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// box = startSketchOn('XY')
|
|
||||||
/// |> startProfileAt([0, 0], %)
|
|
||||||
/// |> line(end = [0, 20])
|
|
||||||
/// |> line(end = [20, 0])
|
|
||||||
/// |> line(end = [0, -20], tag = $revolveAxis)
|
|
||||||
/// |> close()
|
|
||||||
/// |> extrude(length = 20)
|
|
||||||
///
|
|
||||||
/// sketch001 = startSketchOn(box, "END")
|
|
||||||
/// |> circle( center = [10,10], radius = 4 )
|
|
||||||
/// |> revolve(
|
|
||||||
/// angle = 90,
|
|
||||||
/// axis = getOppositeEdge(revolveAxis),
|
|
||||||
/// tolerance = 0.0001
|
|
||||||
/// )
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// sketch001 = startSketchOn('XY')
|
|
||||||
/// |> startProfileAt([10, 0], %)
|
|
||||||
/// |> line(end = [5, -5])
|
|
||||||
/// |> line(end = [5, 5])
|
|
||||||
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|
||||||
/// |> close()
|
|
||||||
///
|
|
||||||
/// part001 = revolve(
|
|
||||||
/// sketch001,
|
|
||||||
/// axis = {
|
|
||||||
/// custom: {
|
|
||||||
/// axis = [0.0, 1.0],
|
|
||||||
/// origin: [0.0, 0.0]
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// )
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // Revolve two sketches around the same axis.
|
|
||||||
///
|
|
||||||
/// sketch001 = startSketchOn('XY')
|
|
||||||
/// profile001 = startProfileAt([4, 8], sketch001)
|
|
||||||
/// |> xLine(length = 3)
|
|
||||||
/// |> yLine(length = -3)
|
|
||||||
/// |> xLine(length = -3)
|
|
||||||
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|
||||||
/// |> close()
|
|
||||||
///
|
|
||||||
/// profile002 = startProfileAt([-5, 8], sketch001)
|
|
||||||
/// |> xLine(length = 3)
|
|
||||||
/// |> yLine(length = -3)
|
|
||||||
/// |> xLine(length = -3)
|
|
||||||
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|
||||||
/// |> close()
|
|
||||||
///
|
|
||||||
/// revolve(
|
|
||||||
/// [profile001, profile002],
|
|
||||||
/// axis = "X",
|
|
||||||
/// )
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // Revolve around a path that has not been extruded.
|
|
||||||
///
|
|
||||||
/// profile001 = startSketchOn('XY')
|
|
||||||
/// |> startProfileAt([0, 0], %)
|
|
||||||
/// |> line(end = [0, 20], tag = $revolveAxis)
|
|
||||||
/// |> line(end = [20, 0])
|
|
||||||
/// |> line(end = [0, -20])
|
|
||||||
/// |> close(%)
|
|
||||||
///
|
|
||||||
/// sketch001 = startSketchOn('XY')
|
|
||||||
/// |> circle(center = [-10, 10], radius = 4)
|
|
||||||
/// |> revolve(angle = 90, axis = revolveAxis)
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // Revolve around a path that has not been extruded or closed.
|
|
||||||
///
|
|
||||||
/// profile001 = startSketchOn('XY')
|
|
||||||
/// |> startProfileAt([0, 0], %)
|
|
||||||
/// |> line(end = [0, 20], tag = $revolveAxis)
|
|
||||||
/// |> line(end = [20, 0])
|
|
||||||
///
|
|
||||||
/// sketch001 = startSketchOn('XY')
|
|
||||||
/// |> circle(center = [-10, 10], radius = 4)
|
|
||||||
/// |> revolve(angle = 90, axis = revolveAxis)
|
|
||||||
/// ```
|
|
||||||
#[stdlib {
|
|
||||||
name = "revolve",
|
|
||||||
feature_tree_operation = true,
|
|
||||||
keywords = true,
|
|
||||||
unlabeled_first = true,
|
|
||||||
args = {
|
|
||||||
sketches = { docs = "The sketch or set of sketches that should be revolved" },
|
|
||||||
axis = { docs = "Axis of revolution." },
|
|
||||||
angle = { docs = "Angle to revolve (in degrees). Default is 360." },
|
|
||||||
tolerance = { docs = "Tolerance for the revolve operation." },
|
|
||||||
tag_start = { docs = "A named tag for the face at the start of the revolve, i.e. the original sketch" },
|
|
||||||
tag_end = { docs = "A named tag for the face at the end of the revolve" },
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
async fn inner_revolve(
|
async fn inner_revolve(
|
||||||
sketches: Vec<Sketch>,
|
sketches: Vec<Sketch>,
|
||||||
@ -264,15 +64,22 @@ async fn inner_revolve(
|
|||||||
let id = exec_state.next_uuid();
|
let id = exec_state.next_uuid();
|
||||||
|
|
||||||
match &axis {
|
match &axis {
|
||||||
Axis2dOrEdgeReference::Axis(axis) => {
|
Axis2dOrEdgeReference::Axis { direction, origin } => {
|
||||||
let (axis, origin) = axis.axis_and_origin()?;
|
|
||||||
args.batch_modeling_cmd(
|
args.batch_modeling_cmd(
|
||||||
id,
|
id,
|
||||||
ModelingCmd::from(mcmd::Revolve {
|
ModelingCmd::from(mcmd::Revolve {
|
||||||
angle,
|
angle,
|
||||||
target: sketch.id.into(),
|
target: sketch.id.into(),
|
||||||
axis,
|
axis: Point3d {
|
||||||
origin,
|
x: direction[0],
|
||||||
|
y: direction[1],
|
||||||
|
z: 0.0,
|
||||||
|
},
|
||||||
|
origin: Point3d {
|
||||||
|
x: LengthUnit(origin[0]),
|
||||||
|
y: LengthUnit(origin[1]),
|
||||||
|
z: LengthUnit(0.0),
|
||||||
|
},
|
||||||
tolerance: LengthUnit(tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
tolerance: LengthUnit(tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
||||||
axis_is_2d: true,
|
axis_is_2d: true,
|
||||||
}),
|
}),
|
||||||
|
@ -1021,7 +1021,7 @@ pub async fn start_sketch_on(exec_state: &mut ExecState, args: Args) -> Result<K
|
|||||||
/// |> line(end = [-2, 0])
|
/// |> line(end = [-2, 0])
|
||||||
/// |> close()
|
/// |> close()
|
||||||
///
|
///
|
||||||
/// example = revolve(exampleSketch, axis = 'y', angle = 180)
|
/// example = revolve(exampleSketch, axis = Y, angle = 180)
|
||||||
///
|
///
|
||||||
/// exampleSketch002 = startSketchOn(example, 'end')
|
/// exampleSketch002 = startSketchOn(example, 'end')
|
||||||
/// |> startProfileAt([4.5, -5], %)
|
/// |> startProfileAt([4.5, -5], %)
|
||||||
@ -1047,7 +1047,7 @@ pub async fn start_sketch_on(exec_state: &mut ExecState, args: Args) -> Result<K
|
|||||||
/// |> line(end = [-2, 0])
|
/// |> line(end = [-2, 0])
|
||||||
/// |> close()
|
/// |> close()
|
||||||
///
|
///
|
||||||
/// example = revolve(exampleSketch, axis = 'y', angle = 180, tagEnd = $end01)
|
/// example = revolve(exampleSketch, axis = Y, angle = 180, tagEnd = $end01)
|
||||||
///
|
///
|
||||||
/// exampleSketch002 = startSketchOn(example, end01)
|
/// exampleSketch002 = startSketchOn(example, end01)
|
||||||
/// |> startProfileAt([4.5, -5], %)
|
/// |> startProfileAt([4.5, -5], %)
|
||||||
|
@ -54,7 +54,7 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
|||||||
/// // Create a pipe using a sweep.
|
/// // Create a pipe using a sweep.
|
||||||
///
|
///
|
||||||
/// // Create a path for the sweep.
|
/// // Create a path for the sweep.
|
||||||
/// sweepPath = startSketchOn('XZ')
|
/// sweepPath = startSketchOn(XZ)
|
||||||
/// |> startProfileAt([0.05, 0.05], %)
|
/// |> startProfileAt([0.05, 0.05], %)
|
||||||
/// |> line(end = [0, 7])
|
/// |> line(end = [0, 7])
|
||||||
/// |> tangentialArc({
|
/// |> tangentialArc({
|
||||||
@ -69,13 +69,13 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
|||||||
/// |> line(end = [0, 7])
|
/// |> line(end = [0, 7])
|
||||||
///
|
///
|
||||||
/// // Create a hole for the pipe.
|
/// // Create a hole for the pipe.
|
||||||
/// pipeHole = startSketchOn('XY')
|
/// pipeHole = startSketchOn(XY)
|
||||||
/// |> circle(
|
/// |> circle(
|
||||||
/// center = [0, 0],
|
/// center = [0, 0],
|
||||||
/// radius = 1.5,
|
/// radius = 1.5,
|
||||||
/// )
|
/// )
|
||||||
///
|
///
|
||||||
/// sweepSketch = startSketchOn('XY')
|
/// sweepSketch = startSketchOn(XY)
|
||||||
/// |> circle(
|
/// |> circle(
|
||||||
/// center = [0, 0],
|
/// center = [0, 0],
|
||||||
/// radius = 2,
|
/// radius = 2,
|
||||||
@ -94,12 +94,12 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
|||||||
/// revolutions = 4,
|
/// revolutions = 4,
|
||||||
/// length = 10,
|
/// length = 10,
|
||||||
/// radius = 5,
|
/// radius = 5,
|
||||||
/// axis = 'Z',
|
/// axis = Z,
|
||||||
/// )
|
/// )
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// // Create a spring by sweeping around the helix path.
|
/// // Create a spring by sweeping around the helix path.
|
||||||
/// springSketch = startSketchOn('YZ')
|
/// springSketch = startSketchOn(YZ)
|
||||||
/// |> circle( center = [0, 0], radius = 1)
|
/// |> circle( center = [0, 0], radius = 1)
|
||||||
/// |> sweep(path = helixPath)
|
/// |> sweep(path = helixPath)
|
||||||
/// ```
|
/// ```
|
||||||
@ -107,7 +107,7 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
|||||||
/// ```
|
/// ```
|
||||||
/// // Sweep two sketches along the same path.
|
/// // Sweep two sketches along the same path.
|
||||||
///
|
///
|
||||||
/// sketch001 = startSketchOn('XY')
|
/// sketch001 = startSketchOn(XY)
|
||||||
/// rectangleSketch = startProfileAt([-200, 23.86], sketch001)
|
/// rectangleSketch = startProfileAt([-200, 23.86], sketch001)
|
||||||
/// |> angledLine([0, 73.47], %, $rectangleSegmentA001)
|
/// |> angledLine([0, 73.47], %, $rectangleSegmentA001)
|
||||||
/// |> angledLine([
|
/// |> angledLine([
|
||||||
@ -123,7 +123,7 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
|||||||
///
|
///
|
||||||
/// circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
|
/// circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
|
||||||
///
|
///
|
||||||
/// sketch002 = startSketchOn('YZ')
|
/// sketch002 = startSketchOn(YZ)
|
||||||
/// sweepPath = startProfileAt([0, 0], sketch002)
|
/// sweepPath = startProfileAt([0, 0], sketch002)
|
||||||
/// |> yLine(length = 231.81)
|
/// |> yLine(length = 231.81)
|
||||||
/// |> tangentialArc({
|
/// |> tangentialArc({
|
||||||
@ -137,7 +137,7 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
|||||||
/// ```
|
/// ```
|
||||||
/// // Sectionally sweep one sketch along the path
|
/// // Sectionally sweep one sketch along the path
|
||||||
///
|
///
|
||||||
/// sketch001 = startSketchOn('XY')
|
/// sketch001 = startSketchOn(XY)
|
||||||
/// circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
|
/// circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
|
||||||
///
|
///
|
||||||
/// sketch002 = startSketchOn('YZ')
|
/// sketch002 = startSketchOn('YZ')
|
||||||
|
@ -1 +0,0 @@
|
|||||||
|
|
@ -1235,7 +1235,7 @@ insideRevolve = startSketchOn(XZ)
|
|||||||
|> line([0, -thickness], %)
|
|> line([0, -thickness], %)
|
||||||
|> line([-overHangLength, 0], %)
|
|> line([-overHangLength, 0], %)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis: 'y' }, %)
|
|> revolve({ axis = Y }, %)
|
||||||
|
|
||||||
// Sketch and revolve one of the balls and duplicate it using a circular pattern. (This is currently a workaround, we have a bug with rotating on a sketch that touches the rotation axis)
|
// Sketch and revolve one of the balls and duplicate it using a circular pattern. (This is currently a workaround, we have a bug with rotating on a sketch that touches the rotation axis)
|
||||||
sphere = startSketchOn(XZ)
|
sphere = startSketchOn(XZ)
|
||||||
@ -1250,7 +1250,7 @@ sphere = startSketchOn(XZ)
|
|||||||
radius = sphereDia / 2 - 0.05
|
radius = sphereDia / 2 - 0.05
|
||||||
}, %)
|
}, %)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis: 'x' }, %)
|
|> revolve({ axis = X }, %)
|
||||||
|> patternCircular3d(
|
|> patternCircular3d(
|
||||||
axis = [0, 0, 1],
|
axis = [0, 0, 1],
|
||||||
center = [0, 0, 0],
|
center = [0, 0, 0],
|
||||||
@ -1274,7 +1274,7 @@ outsideRevolve = startSketchOn(XZ)
|
|||||||
|> line([0, thickness], %)
|
|> line([0, thickness], %)
|
||||||
|> line([overHangLength - thickness, 0], %)
|
|> line([overHangLength - thickness, 0], %)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis: 'y' }, %)"#;
|
|> revolve({ axis = Y }, %)"#;
|
||||||
let program = crate::parsing::top_level_parse(some_program_string).unwrap();
|
let program = crate::parsing::top_level_parse(some_program_string).unwrap();
|
||||||
|
|
||||||
let recasted = program.recast(&Default::default(), 0);
|
let recasted = program.recast(&Default::default(), 0);
|
||||||
@ -1301,7 +1301,7 @@ insideRevolve = startSketchOn(XZ)
|
|||||||
|> line([0, -thickness], %)
|
|> line([0, -thickness], %)
|
||||||
|> line([-overHangLength, 0], %)
|
|> line([-overHangLength, 0], %)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis = 'y' }, %)
|
|> revolve({ axis = Y }, %)
|
||||||
|
|
||||||
// Sketch and revolve one of the balls and duplicate it using a circular pattern. (This is currently a workaround, we have a bug with rotating on a sketch that touches the rotation axis)
|
// Sketch and revolve one of the balls and duplicate it using a circular pattern. (This is currently a workaround, we have a bug with rotating on a sketch that touches the rotation axis)
|
||||||
sphere = startSketchOn(XZ)
|
sphere = startSketchOn(XZ)
|
||||||
@ -1316,7 +1316,7 @@ sphere = startSketchOn(XZ)
|
|||||||
radius = sphereDia / 2 - 0.05
|
radius = sphereDia / 2 - 0.05
|
||||||
}, %)
|
}, %)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis = 'x' }, %)
|
|> revolve({ axis = X }, %)
|
||||||
|> patternCircular3d(
|
|> patternCircular3d(
|
||||||
axis = [0, 0, 1],
|
axis = [0, 0, 1],
|
||||||
center = [0, 0, 0],
|
center = [0, 0, 0],
|
||||||
@ -1340,7 +1340,7 @@ outsideRevolve = startSketchOn(XZ)
|
|||||||
|> line([0, thickness], %)
|
|> line([0, thickness], %)
|
||||||
|> line([overHangLength - thickness, 0], %)
|
|> line([overHangLength - thickness, 0], %)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis = 'y' }, %)
|
|> revolve({ axis = Y }, %)
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1613,9 +1613,9 @@ fn bracketSketch = (w, d, t) => {
|
|||||||
s = startSketchOn({
|
s = startSketchOn({
|
||||||
plane: {
|
plane: {
|
||||||
origin: { x = 0, y = length / 2 + thk, z = 0 },
|
origin: { x = 0, y = length / 2 + thk, z = 0 },
|
||||||
x_axis: { x = 1, y = 0, z = 0 },
|
x_axis = { x = 1, y = 0, z = 0 },
|
||||||
y_axis: { x = 0, y = 0, z = 1 },
|
y_axis = { x = 0, y = 0, z = 1 },
|
||||||
z_axis: { x = 0, y = 1, z = 0 }
|
z_axis = { x = 0, y = 1, z = 0 }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|> startProfileAt([-w / 2 - t, d + t], %)
|
|> startProfileAt([-w / 2 - t, d + t], %)
|
||||||
@ -1645,9 +1645,9 @@ bracket_body = bracketSketch(width, depth, thk)
|
|||||||
tabs_r = startSketchOn({
|
tabs_r = startSketchOn({
|
||||||
plane: {
|
plane: {
|
||||||
origin: { x = 0, y = 0, z = depth + thk },
|
origin: { x = 0, y = 0, z = depth + thk },
|
||||||
x_axis: { x = 1, y = 0, z = 0 },
|
x_axis = { x = 1, y = 0, z = 0 },
|
||||||
y_axis: { x = 0, y = 1, z = 0 },
|
y_axis = { x = 0, y = 1, z = 0 },
|
||||||
z_axis: { x = 0, y = 0, z = 1 }
|
z_axis = { x = 0, y = 0, z = 1 }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|> startProfileAt([width / 2 + thk, length / 2 + thk], %)
|
|> startProfileAt([width / 2 + thk, length / 2 + thk], %)
|
||||||
@ -2528,9 +2528,9 @@ fn f() {
|
|||||||
sketch002 = startSketchOn({
|
sketch002 = startSketchOn({
|
||||||
plane: {
|
plane: {
|
||||||
origin: { x = 1, y = 2, z = 3 },
|
origin: { x = 1, y = 2, z = 3 },
|
||||||
x_axis: { x = 4, y = 5, z = 6 },
|
x_axis = { x = 4, y = 5, z = 6 },
|
||||||
y_axis: { x = 7, y = 8, z = 9 },
|
y_axis = { x = 7, y = 8, z = 9 },
|
||||||
z_axis: { x = 10, y = 11, z = 12 }
|
z_axis = { x = 10, y = 11, z = 12 }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
"#;
|
"#;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
export import * from "std::math"
|
export import * from "std::math"
|
||||||
export import * from "std::sketch"
|
export import * from "std::sketch"
|
||||||
|
export import "std::turns"
|
||||||
|
|
||||||
/// A number
|
/// A number
|
||||||
///
|
///
|
||||||
@ -233,6 +234,10 @@ export type Face
|
|||||||
@(impl = std_rust)
|
@(impl = std_rust)
|
||||||
export type Helix
|
export type Helix
|
||||||
|
|
||||||
|
/// The edge of a solid.
|
||||||
|
@(impl = std_rust)
|
||||||
|
export type Edge
|
||||||
|
|
||||||
/// A point in two dimensional space.
|
/// A point in two dimensional space.
|
||||||
///
|
///
|
||||||
/// `Point2d` is an alias for a two-element array of [number](/docs/kcl/types/number)s. To write a value
|
/// `Point2d` is an alias for a two-element array of [number](/docs/kcl/types/number)s. To write a value
|
||||||
@ -245,11 +250,6 @@ export type Point2d = [number; 2]
|
|||||||
/// with type `Point3d`, use an array, e.g., `[0, 0, 0]` or `[5.0, 3.14, 6.8]`.
|
/// with type `Point3d`, use an array, e.g., `[0, 0, 0]` or `[5.0, 3.14, 6.8]`.
|
||||||
export type Point3d = [number; 3]
|
export type Point3d = [number; 3]
|
||||||
|
|
||||||
export ZERO = 0
|
|
||||||
export QUARTER_TURN = 90deg
|
|
||||||
export HALF_TURN = 180deg
|
|
||||||
export THREE_QUARTER_TURN = 270deg
|
|
||||||
|
|
||||||
export XY = {
|
export XY = {
|
||||||
origin = { x = 0, y = 0, z = 0 },
|
origin = { x = 0, y = 0, z = 0 },
|
||||||
xAxis = { x = 1, y = 0, z = 0 },
|
xAxis = { x = 1, y = 0, z = 0 },
|
||||||
@ -270,3 +270,330 @@ export YZ = {
|
|||||||
yAxis = { x = 0, y = 0, z = 1 },
|
yAxis = { x = 0, y = 0, z = 1 },
|
||||||
zAxis = { x = 1, y = 0, z = 0 },
|
zAxis = { x = 1, y = 0, z = 0 },
|
||||||
}: Plane
|
}: Plane
|
||||||
|
|
||||||
|
/// An infinte line in 2d space.
|
||||||
|
@(impl = std_rust)
|
||||||
|
export type Axis2d
|
||||||
|
|
||||||
|
/// An infinte line in 3d space.
|
||||||
|
@(impl = std_rust)
|
||||||
|
export type Axis3d
|
||||||
|
|
||||||
|
export X = {
|
||||||
|
origin = [0, 0, 0],
|
||||||
|
direction = [1, 0, 0],
|
||||||
|
}: Axis3d
|
||||||
|
|
||||||
|
export Y = {
|
||||||
|
origin = [0, 0, 0],
|
||||||
|
direction = [0, 1, 0],
|
||||||
|
}: Axis3d
|
||||||
|
|
||||||
|
export Z = {
|
||||||
|
origin = [0, 0, 0],
|
||||||
|
direction = [0, 0, 1],
|
||||||
|
}: Axis3d
|
||||||
|
|
||||||
|
/// Create a helix.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Create a helix around the Z axis.
|
||||||
|
/// helixPath = helix(
|
||||||
|
/// angleStart = 0,
|
||||||
|
/// ccw = true,
|
||||||
|
/// revolutions = 5,
|
||||||
|
/// length = 10,
|
||||||
|
/// radius = 5,
|
||||||
|
/// axis = Z,
|
||||||
|
/// )
|
||||||
|
///
|
||||||
|
/// // Create a spring by sweeping around the helix path.
|
||||||
|
/// springSketch = startSketchOn(YZ)
|
||||||
|
/// |> circle( center = [0, 0], radius = 0.5)
|
||||||
|
/// |> sweep(path = helixPath)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Create a helix around an edge.
|
||||||
|
/// helper001 = startSketchOn(XZ)
|
||||||
|
/// |> startProfileAt([0, 0], %)
|
||||||
|
/// |> line(end = [0, 10], tag = $edge001)
|
||||||
|
///
|
||||||
|
/// helixPath = helix(
|
||||||
|
/// angleStart = 0,
|
||||||
|
/// ccw = true,
|
||||||
|
/// revolutions = 5,
|
||||||
|
/// length = 10,
|
||||||
|
/// radius = 5,
|
||||||
|
/// axis = edge001,
|
||||||
|
/// )
|
||||||
|
///
|
||||||
|
/// // Create a spring by sweeping around the helix path.
|
||||||
|
/// springSketch = startSketchOn(XY)
|
||||||
|
/// |> circle( center = [0, 0], radius = 0.5 )
|
||||||
|
/// |> sweep(path = helixPath)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Create a helix around a custom axis.
|
||||||
|
/// helixPath = helix(
|
||||||
|
/// angleStart = 0,
|
||||||
|
/// ccw = true,
|
||||||
|
/// revolutions = 5,
|
||||||
|
/// length = 10,
|
||||||
|
/// radius = 5,
|
||||||
|
/// axis = {
|
||||||
|
/// direction = [0, 0, 1.0],
|
||||||
|
/// origin = [0, 0.25, 0]
|
||||||
|
/// }
|
||||||
|
/// )
|
||||||
|
///
|
||||||
|
/// // Create a spring by sweeping around the helix path.
|
||||||
|
/// springSketch = startSketchOn(XY)
|
||||||
|
/// |> circle( center = [0, 0], radius = 1 )
|
||||||
|
/// |> sweep(path = helixPath)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Create a helix on a cylinder.
|
||||||
|
///
|
||||||
|
/// part001 = startSketchOn(XY)
|
||||||
|
/// |> circle( center= [5, 5], radius= 10 )
|
||||||
|
/// |> extrude(length = 10)
|
||||||
|
///
|
||||||
|
/// helix(
|
||||||
|
/// angleStart = 0,
|
||||||
|
/// ccw = true,
|
||||||
|
/// revolutions = 16,
|
||||||
|
/// cylinder = part001,
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
@(impl = std_rust)
|
||||||
|
export fn helix(
|
||||||
|
/// Number of revolutions.
|
||||||
|
revolutions: number(_),
|
||||||
|
/// Start angle (in degrees).
|
||||||
|
angleStart: number(deg),
|
||||||
|
/// Is the helix rotation counter clockwise? The default is `false`.
|
||||||
|
ccw?: bool,
|
||||||
|
/// Radius of the helix.
|
||||||
|
@(include_in_snippet = true)
|
||||||
|
radius?: number(mm),
|
||||||
|
/// Axis to use for the helix.
|
||||||
|
@(include_in_snippet = true)
|
||||||
|
axis?: Axis3d | Edge,
|
||||||
|
/// Length of the helix. This is not necessary if the helix is created around an edge. If not given the length of the edge is used.
|
||||||
|
@(include_in_snippet = true)
|
||||||
|
length?: number(mm),
|
||||||
|
/// Cylinder to create the helix on.
|
||||||
|
cylinder?: Solid,
|
||||||
|
): Helix {}
|
||||||
|
|
||||||
|
/// Rotate a sketch around some provided axis, creating a solid from its extent.
|
||||||
|
///
|
||||||
|
/// This, like extrude, is able to create a 3-dimensional solid from a
|
||||||
|
/// 2-dimensional sketch. However, unlike extrude, this creates a solid
|
||||||
|
/// by using the extent of the sketch as its revolved around an axis rather
|
||||||
|
/// than using the extent of the sketch linearly translated through a third
|
||||||
|
/// dimension.
|
||||||
|
///
|
||||||
|
/// Revolve occurs around a local sketch axis rather than a global axis.
|
||||||
|
///
|
||||||
|
/// You can provide more than one sketch to revolve, and they will all be
|
||||||
|
/// revolved around the same axis.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// part001 = startSketchOn(XY)
|
||||||
|
/// |> startProfileAt([4, 12], %)
|
||||||
|
/// |> line(end = [2, 0])
|
||||||
|
/// |> line(end = [0, -6])
|
||||||
|
/// |> line(end = [4, -6])
|
||||||
|
/// |> line(end = [0, -6])
|
||||||
|
/// |> line(end = [-3.75, -4.5])
|
||||||
|
/// |> line(end = [0, -5.5])
|
||||||
|
/// |> line(end = [-2, 0])
|
||||||
|
/// |> close()
|
||||||
|
/// |> revolve(axis = Y) // default angle is 360
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // A donut shape.
|
||||||
|
/// sketch001 = startSketchOn(XY)
|
||||||
|
/// |> circle( center = [15, 0], radius = 5 )
|
||||||
|
/// |> revolve(
|
||||||
|
/// angle = 360,
|
||||||
|
/// axis = Y,
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// part001 = startSketchOn(XY)
|
||||||
|
/// |> startProfileAt([4, 12], %)
|
||||||
|
/// |> line(end = [2, 0])
|
||||||
|
/// |> line(end = [0, -6])
|
||||||
|
/// |> line(end = [4, -6])
|
||||||
|
/// |> line(end = [0, -6])
|
||||||
|
/// |> line(end = [-3.75, -4.5])
|
||||||
|
/// |> line(end = [0, -5.5])
|
||||||
|
/// |> line(end = [-2, 0])
|
||||||
|
/// |> close()
|
||||||
|
/// |> revolve(axis = Y, angle = 180)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// part001 = startSketchOn(XY)
|
||||||
|
/// |> startProfileAt([4, 12], %)
|
||||||
|
/// |> line(end = [2, 0])
|
||||||
|
/// |> line(end = [0, -6])
|
||||||
|
/// |> line(end = [4, -6])
|
||||||
|
/// |> line(end = [0, -6])
|
||||||
|
/// |> line(end = [-3.75, -4.5])
|
||||||
|
/// |> line(end = [0, -5.5])
|
||||||
|
/// |> line(end = [-2, 0])
|
||||||
|
/// |> close()
|
||||||
|
/// |> revolve(axis = Y, angle = 180)
|
||||||
|
///
|
||||||
|
/// part002 = startSketchOn(part001, 'end')
|
||||||
|
/// |> startProfileAt([4.5, -5], %)
|
||||||
|
/// |> line(end = [0, 5])
|
||||||
|
/// |> line(end = [5, 0])
|
||||||
|
/// |> line(end = [0, -5])
|
||||||
|
/// |> close()
|
||||||
|
/// |> extrude(length = 5)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// box = startSketchOn(XY)
|
||||||
|
/// |> startProfileAt([0, 0], %)
|
||||||
|
/// |> line(end = [0, 20])
|
||||||
|
/// |> line(end = [20, 0])
|
||||||
|
/// |> line(end = [0, -20])
|
||||||
|
/// |> close()
|
||||||
|
/// |> extrude(length = 20)
|
||||||
|
///
|
||||||
|
/// sketch001 = startSketchOn(box, "END")
|
||||||
|
/// |> circle( center = [10,10], radius = 4 )
|
||||||
|
/// |> revolve(
|
||||||
|
/// angle = -90,
|
||||||
|
/// axis = Y
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// box = startSketchOn(XY)
|
||||||
|
/// |> startProfileAt([0, 0], %)
|
||||||
|
/// |> line(end = [0, 20])
|
||||||
|
/// |> line(end = [20, 0])
|
||||||
|
/// |> line(end = [0, -20], tag = $revolveAxis)
|
||||||
|
/// |> close()
|
||||||
|
/// |> extrude(length = 20)
|
||||||
|
///
|
||||||
|
/// sketch001 = startSketchOn(box, "END")
|
||||||
|
/// |> circle( center = [10,10], radius = 4 )
|
||||||
|
/// |> revolve(
|
||||||
|
/// angle = 90,
|
||||||
|
/// axis = getOppositeEdge(revolveAxis)
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// box = startSketchOn(XY)
|
||||||
|
/// |> startProfileAt([0, 0], %)
|
||||||
|
/// |> line(end = [0, 20])
|
||||||
|
/// |> line(end = [20, 0])
|
||||||
|
/// |> line(end = [0, -20], tag = $revolveAxis)
|
||||||
|
/// |> close()
|
||||||
|
/// |> extrude(length = 20)
|
||||||
|
///
|
||||||
|
/// sketch001 = startSketchOn(box, "END")
|
||||||
|
/// |> circle( center = [10,10], radius = 4 )
|
||||||
|
/// |> revolve(
|
||||||
|
/// angle = 90,
|
||||||
|
/// axis = getOppositeEdge(revolveAxis),
|
||||||
|
/// tolerance = 0.0001
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// sketch001 = startSketchOn(XY)
|
||||||
|
/// |> startProfileAt([10, 0], %)
|
||||||
|
/// |> line(end = [5, -5])
|
||||||
|
/// |> line(end = [5, 5])
|
||||||
|
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
/// |> close()
|
||||||
|
///
|
||||||
|
/// part001 = revolve(
|
||||||
|
/// sketch001,
|
||||||
|
/// axis = {
|
||||||
|
/// direction = [0.0, 1.0],
|
||||||
|
/// origin: [0.0, 0.0]
|
||||||
|
/// }
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Revolve two sketches around the same axis.
|
||||||
|
///
|
||||||
|
/// sketch001 = startSketchOn(XY)
|
||||||
|
/// profile001 = startProfileAt([4, 8], sketch001)
|
||||||
|
/// |> xLine(length = 3)
|
||||||
|
/// |> yLine(length = -3)
|
||||||
|
/// |> xLine(length = -3)
|
||||||
|
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
/// |> close()
|
||||||
|
///
|
||||||
|
/// profile002 = startProfileAt([-5, 8], sketch001)
|
||||||
|
/// |> xLine(length = 3)
|
||||||
|
/// |> yLine(length = -3)
|
||||||
|
/// |> xLine(length = -3)
|
||||||
|
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||||
|
/// |> close()
|
||||||
|
///
|
||||||
|
/// revolve(
|
||||||
|
/// [profile001, profile002],
|
||||||
|
/// axis = X,
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Revolve around a path that has not been extruded.
|
||||||
|
///
|
||||||
|
/// profile001 = startSketchOn(XY)
|
||||||
|
/// |> startProfileAt([0, 0], %)
|
||||||
|
/// |> line(end = [0, 20], tag = $revolveAxis)
|
||||||
|
/// |> line(end = [20, 0])
|
||||||
|
/// |> line(end = [0, -20])
|
||||||
|
/// |> close(%)
|
||||||
|
///
|
||||||
|
/// sketch001 = startSketchOn(XY)
|
||||||
|
/// |> circle(center = [-10, 10], radius = 4)
|
||||||
|
/// |> revolve(angle = 90, axis = revolveAxis)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Revolve around a path that has not been extruded or closed.
|
||||||
|
///
|
||||||
|
/// profile001 = startSketchOn(XY)
|
||||||
|
/// |> startProfileAt([0, 0], %)
|
||||||
|
/// |> line(end = [0, 20], tag = $revolveAxis)
|
||||||
|
/// |> line(end = [20, 0])
|
||||||
|
///
|
||||||
|
/// sketch001 = startSketchOn(XY)
|
||||||
|
/// |> circle(center = [-10, 10], radius = 4)
|
||||||
|
/// |> revolve(angle = 90, axis = revolveAxis)
|
||||||
|
/// ```
|
||||||
|
@(impl = std_rust)
|
||||||
|
export fn revolve(
|
||||||
|
/// The sketch or set of sketches that should be revolved
|
||||||
|
@sketches: [Sketch; 1+],
|
||||||
|
/// Axis of revolution.
|
||||||
|
axis: Axis2d | Edge,
|
||||||
|
/// Angle to revolve (in degrees). Default is 360.
|
||||||
|
angle?: number(deg),
|
||||||
|
/// Tolerance for the revolve operation.
|
||||||
|
tolerance?: number(mm),
|
||||||
|
/// A named tag for the face at the start of the revolve, i.e. the original sketch.
|
||||||
|
tagStart?: tag,
|
||||||
|
/// A named tag for the face at the end of the revolve.
|
||||||
|
tagEnd?: tag,
|
||||||
|
): Solid {}
|
||||||
|
@ -32,3 +32,74 @@ export fn circle(
|
|||||||
/// Create a new tag which refers to this circle.
|
/// Create a new tag which refers to this circle.
|
||||||
tag?: tag,
|
tag?: tag,
|
||||||
): Sketch {}
|
): Sketch {}
|
||||||
|
|
||||||
|
/// Mirror a sketch.
|
||||||
|
///
|
||||||
|
/// Only works on unclosed sketches for now.
|
||||||
|
///
|
||||||
|
/// Mirror occurs around a local sketch axis rather than a global axis.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Mirror an un-closed sketch across the Y axis.
|
||||||
|
/// sketch001 = startSketchOn(XZ)
|
||||||
|
/// |> startProfileAt([0, 10], %)
|
||||||
|
/// |> line(end = [15, 0])
|
||||||
|
/// |> line(end = [-7, -3])
|
||||||
|
/// |> line(end = [9, -1])
|
||||||
|
/// |> line(end = [-8, -5])
|
||||||
|
/// |> line(end = [9, -3])
|
||||||
|
/// |> line(end = [-8, -3])
|
||||||
|
/// |> line(end = [9, -1])
|
||||||
|
/// |> line(end = [-19, -0])
|
||||||
|
/// |> mirror2d(axis = Y)
|
||||||
|
///
|
||||||
|
/// example = extrude(sketch001, length = 10)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Mirror a un-closed sketch across the Y axis.
|
||||||
|
/// sketch001 = startSketchOn(XZ)
|
||||||
|
/// |> startProfileAt([0, 8.5], %)
|
||||||
|
/// |> line(end = [20, -8.5])
|
||||||
|
/// |> line(end = [-20, -8.5])
|
||||||
|
/// |> mirror2d(axis = Y)
|
||||||
|
///
|
||||||
|
/// example = extrude(sketch001, length = 10)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Mirror a un-closed sketch across an edge.
|
||||||
|
/// helper001 = startSketchOn(XZ)
|
||||||
|
/// |> startProfileAt([0, 0], %)
|
||||||
|
/// |> line(end = [0, 10], tag = $edge001)
|
||||||
|
///
|
||||||
|
/// sketch001 = startSketchOn(XZ)
|
||||||
|
/// |> startProfileAt([0, 8.5], %)
|
||||||
|
/// |> line(end = [20, -8.5])
|
||||||
|
/// |> line(end = [-20, -8.5])
|
||||||
|
/// |> mirror2d(axis = edge001)
|
||||||
|
///
|
||||||
|
/// // example = extrude(sketch001, length = 10)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Mirror an un-closed sketch across a custom axis.
|
||||||
|
/// sketch001 = startSketchOn(XZ)
|
||||||
|
/// |> startProfileAt([0, 8.5], %)
|
||||||
|
/// |> line(end = [20, -8.5])
|
||||||
|
/// |> line(end = [-20, -8.5])
|
||||||
|
/// |> mirror2d(
|
||||||
|
/// axis = {
|
||||||
|
/// direction = [0.0, 1.0],
|
||||||
|
/// origin = [0.0, 0.0]
|
||||||
|
/// })
|
||||||
|
///
|
||||||
|
/// example = extrude(sketch001, length = 10)
|
||||||
|
/// ```
|
||||||
|
@(impl = std_rust)
|
||||||
|
export fn mirror2d(
|
||||||
|
/// The sketch or sketches to be reflected.
|
||||||
|
@sketches: [Sketch; 1+],
|
||||||
|
/// The axis to refect around.
|
||||||
|
axis: Axis2d | Edge,
|
||||||
|
): Sketch {}
|
||||||
|
6
rust/kcl-lib/std/turns.kcl
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
@no_std
|
||||||
|
|
||||||
|
export ZERO = 0
|
||||||
|
export QUARTER_TURN = 90deg
|
||||||
|
export HALF_TURN = 180deg
|
||||||
|
export THREE_QUARTER_TURN = 270deg
|
@ -1,25 +1,25 @@
|
|||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR
|
flowchart LR
|
||||||
subgraph path2 [Path]
|
subgraph path2 [Path]
|
||||||
2["Path<br>[76, 113, 4]"]
|
2["Path<br>[76, 113, 5]"]
|
||||||
3["Segment<br>[119, 136, 4]"]
|
3["Segment<br>[119, 136, 5]"]
|
||||||
4["Segment<br>[142, 160, 4]"]
|
4["Segment<br>[142, 160, 5]"]
|
||||||
5["Segment<br>[166, 184, 4]"]
|
5["Segment<br>[166, 184, 5]"]
|
||||||
6["Segment<br>[190, 246, 4]"]
|
6["Segment<br>[190, 246, 5]"]
|
||||||
7["Segment<br>[252, 259, 4]"]
|
7["Segment<br>[252, 259, 5]"]
|
||||||
8[Solid2d]
|
8[Solid2d]
|
||||||
end
|
end
|
||||||
subgraph path25 [Path]
|
subgraph path25 [Path]
|
||||||
25["Path<br>[76, 111, 5]"]
|
25["Path<br>[76, 111, 6]"]
|
||||||
26["Segment<br>[117, 134, 5]"]
|
26["Segment<br>[117, 134, 6]"]
|
||||||
27["Segment<br>[140, 158, 5]"]
|
27["Segment<br>[140, 158, 6]"]
|
||||||
28["Segment<br>[164, 182, 5]"]
|
28["Segment<br>[164, 182, 6]"]
|
||||||
29["Segment<br>[188, 244, 5]"]
|
29["Segment<br>[188, 244, 6]"]
|
||||||
30["Segment<br>[250, 257, 5]"]
|
30["Segment<br>[250, 257, 6]"]
|
||||||
31[Solid2d]
|
31[Solid2d]
|
||||||
end
|
end
|
||||||
1["Plane<br>[47, 66, 4]"]
|
1["Plane<br>[47, 66, 5]"]
|
||||||
9["Sweep Extrusion<br>[265, 287, 4]"]
|
9["Sweep Extrusion<br>[265, 287, 5]"]
|
||||||
10[Wall]
|
10[Wall]
|
||||||
11[Wall]
|
11[Wall]
|
||||||
12[Wall]
|
12[Wall]
|
||||||
@ -34,8 +34,8 @@ flowchart LR
|
|||||||
21["SweepEdge Adjacent"]
|
21["SweepEdge Adjacent"]
|
||||||
22["SweepEdge Opposite"]
|
22["SweepEdge Opposite"]
|
||||||
23["SweepEdge Adjacent"]
|
23["SweepEdge Adjacent"]
|
||||||
24["Plane<br>[47, 66, 5]"]
|
24["Plane<br>[47, 66, 6]"]
|
||||||
32["Sweep Extrusion<br>[263, 285, 5]"]
|
32["Sweep Extrusion<br>[263, 285, 6]"]
|
||||||
33[Wall]
|
33[Wall]
|
||||||
34[Wall]
|
34[Wall]
|
||||||
35[Wall]
|
35[Wall]
|
||||||
|
@ -5,10 +5,10 @@ description: Variables in memory after executing assembly_mixed_units_cubes.kcl
|
|||||||
{
|
{
|
||||||
"cubeIn": {
|
"cubeIn": {
|
||||||
"type": "Module",
|
"type": "Module",
|
||||||
"value": 4
|
"value": 5
|
||||||
},
|
},
|
||||||
"cubeMm": {
|
"cubeMm": {
|
||||||
"type": "Module",
|
"type": "Module",
|
||||||
"value": 5
|
"value": 6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR
|
flowchart LR
|
||||||
subgraph path2 [Path]
|
subgraph path2 [Path]
|
||||||
2["Path<br>[197, 232, 4]"]
|
2["Path<br>[197, 232, 5]"]
|
||||||
3["Segment<br>[197, 232, 4]"]
|
3["Segment<br>[197, 232, 5]"]
|
||||||
4[Solid2d]
|
4[Solid2d]
|
||||||
end
|
end
|
||||||
subgraph path6 [Path]
|
subgraph path6 [Path]
|
||||||
6["Path<br>[113, 148, 5]"]
|
6["Path<br>[113, 148, 6]"]
|
||||||
7["Segment<br>[113, 148, 5]"]
|
7["Segment<br>[113, 148, 6]"]
|
||||||
8[Solid2d]
|
8[Solid2d]
|
||||||
end
|
end
|
||||||
1["Plane<br>[172, 191, 4]"]
|
1["Plane<br>[172, 191, 5]"]
|
||||||
5["Plane<br>[88, 107, 5]"]
|
5["Plane<br>[88, 107, 6]"]
|
||||||
1 --- 2
|
1 --- 2
|
||||||
2 --- 3
|
2 --- 3
|
||||||
2 --- 4
|
2 --- 4
|
||||||
|
@ -5,10 +5,10 @@ description: Variables in memory after executing assembly_non_default_units.kcl
|
|||||||
{
|
{
|
||||||
"other1": {
|
"other1": {
|
||||||
"type": "Module",
|
"type": "Module",
|
||||||
"value": 4
|
"value": 5
|
||||||
},
|
},
|
||||||
"other2": {
|
"other2": {
|
||||||
"type": "Module",
|
"type": "Module",
|
||||||
"value": 5
|
"value": 6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,6 +148,22 @@ description: Operations executed crazy_multi_profile.kcl
|
|||||||
"type": "UserDefinedFunctionReturn"
|
"type": "UserDefinedFunctionReturn"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"type": "UserDefinedFunctionCall",
|
||||||
|
"name": "revolve",
|
||||||
|
"functionSourceRange": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"unlabeledArg": {
|
||||||
|
"value": {
|
||||||
|
"type": "Sketch",
|
||||||
|
"value": {
|
||||||
|
"artifactId": "[uuid]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
},
|
||||||
"labeledArgs": {
|
"labeledArgs": {
|
||||||
"angle": {
|
"angle": {
|
||||||
"value": {
|
"value": {
|
||||||
@ -173,19 +189,55 @@ description: Operations executed crazy_multi_profile.kcl
|
|||||||
"sourceRange": []
|
"sourceRange": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "revolve",
|
"sourceRange": []
|
||||||
"sourceRange": [],
|
},
|
||||||
"type": "StdLibCall",
|
{
|
||||||
|
"type": "KclStdLibCall",
|
||||||
|
"name": "",
|
||||||
"unlabeledArg": {
|
"unlabeledArg": {
|
||||||
"value": {
|
"value": {
|
||||||
|
"type": "Array",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
"type": "Sketch",
|
"type": "Sketch",
|
||||||
"value": {
|
"value": {
|
||||||
"artifactId": "[uuid]"
|
"artifactId": "[uuid]"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
},
|
||||||
|
"labeledArgs": {
|
||||||
|
"angle": {
|
||||||
|
"value": {
|
||||||
|
"type": "Number",
|
||||||
|
"value": 45.0,
|
||||||
|
"ty": {
|
||||||
|
"type": "Default",
|
||||||
|
"len": {
|
||||||
|
"type": "Mm"
|
||||||
|
},
|
||||||
|
"angle": {
|
||||||
|
"type": "Degrees"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
},
|
||||||
|
"axis": {
|
||||||
|
"value": {
|
||||||
|
"type": "Uuid",
|
||||||
|
"value": "[uuid]"
|
||||||
},
|
},
|
||||||
"sourceRange": []
|
"sourceRange": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "UserDefinedFunctionReturn"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"labeledArgs": {
|
"labeledArgs": {
|
||||||
"length": {
|
"length": {
|
||||||
@ -338,6 +390,22 @@ description: Operations executed crazy_multi_profile.kcl
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"type": "UserDefinedFunctionCall",
|
||||||
|
"name": "revolve",
|
||||||
|
"functionSourceRange": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"unlabeledArg": {
|
||||||
|
"value": {
|
||||||
|
"type": "Sketch",
|
||||||
|
"value": {
|
||||||
|
"artifactId": "[uuid]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
},
|
||||||
"labeledArgs": {
|
"labeledArgs": {
|
||||||
"angle": {
|
"angle": {
|
||||||
"value": {
|
"value": {
|
||||||
@ -364,17 +432,54 @@ description: Operations executed crazy_multi_profile.kcl
|
|||||||
"sourceRange": []
|
"sourceRange": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "revolve",
|
"sourceRange": []
|
||||||
"sourceRange": [],
|
},
|
||||||
"type": "StdLibCall",
|
{
|
||||||
|
"type": "KclStdLibCall",
|
||||||
|
"name": "",
|
||||||
"unlabeledArg": {
|
"unlabeledArg": {
|
||||||
"value": {
|
"value": {
|
||||||
|
"type": "Array",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
"type": "Sketch",
|
"type": "Sketch",
|
||||||
"value": {
|
"value": {
|
||||||
"artifactId": "[uuid]"
|
"artifactId": "[uuid]"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
},
|
||||||
|
"labeledArgs": {
|
||||||
|
"angle": {
|
||||||
|
"value": {
|
||||||
|
"type": "Number",
|
||||||
|
"value": 45.0,
|
||||||
|
"ty": {
|
||||||
|
"type": "Default",
|
||||||
|
"len": {
|
||||||
|
"type": "Mm"
|
||||||
|
},
|
||||||
|
"angle": {
|
||||||
|
"type": "Degrees"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
},
|
||||||
|
"axis": {
|
||||||
|
"value": {
|
||||||
|
"type": "TagIdentifier",
|
||||||
|
"value": "seg02",
|
||||||
|
"artifact_id": "[uuid]"
|
||||||
},
|
},
|
||||||
"sourceRange": []
|
"sourceRange": []
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "UserDefinedFunctionReturn"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -117,6 +117,14 @@ description: Operations executed helix_ccw.kcl
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"type": "UserDefinedFunctionCall",
|
||||||
|
"name": "helix",
|
||||||
|
"functionSourceRange": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"unlabeledArg": null,
|
||||||
"labeledArgs": {
|
"labeledArgs": {
|
||||||
"angleStart": {
|
"angleStart": {
|
||||||
"value": {
|
"value": {
|
||||||
@ -167,9 +175,11 @@ description: Operations executed helix_ccw.kcl
|
|||||||
"sourceRange": []
|
"sourceRange": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "helix",
|
"sourceRange": []
|
||||||
"sourceRange": [],
|
},
|
||||||
"type": "StdLibCall",
|
{
|
||||||
|
"type": "KclStdLibCall",
|
||||||
|
"name": "",
|
||||||
"unlabeledArg": {
|
"unlabeledArg": {
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Solid",
|
"type": "Solid",
|
||||||
@ -178,6 +188,60 @@ description: Operations executed helix_ccw.kcl
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sourceRange": []
|
"sourceRange": []
|
||||||
|
},
|
||||||
|
"labeledArgs": {
|
||||||
|
"angleStart": {
|
||||||
|
"value": {
|
||||||
|
"type": "Number",
|
||||||
|
"value": 0.0,
|
||||||
|
"ty": {
|
||||||
|
"type": "Default",
|
||||||
|
"len": {
|
||||||
|
"type": "Mm"
|
||||||
|
},
|
||||||
|
"angle": {
|
||||||
|
"type": "Degrees"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
},
|
||||||
|
"ccw": {
|
||||||
|
"value": {
|
||||||
|
"type": "Bool",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
},
|
||||||
|
"cylinder": {
|
||||||
|
"value": {
|
||||||
|
"type": "Solid",
|
||||||
|
"value": {
|
||||||
|
"artifactId": "[uuid]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
},
|
||||||
|
"revolutions": {
|
||||||
|
"value": {
|
||||||
|
"type": "Number",
|
||||||
|
"value": 16.0,
|
||||||
|
"ty": {
|
||||||
|
"type": "Default",
|
||||||
|
"len": {
|
||||||
|
"type": "Mm"
|
||||||
|
},
|
||||||
|
"angle": {
|
||||||
|
"type": "Degrees"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sourceRange": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "UserDefinedFunctionReturn"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|