Compare commits
25 Commits
pierremtb/
...
v0.53.0
Author | SHA1 | Date | |
---|---|---|---|
129b91518f | |||
c0aa763c3b | |||
319c60d4fa | |||
66f95d25f6 | |||
72ab72cea1 | |||
4e1e9f9c6e | |||
8b14d32879 | |||
7c5170dc16 | |||
a07dbc3aac | |||
7d3294ff78 | |||
121c393466 | |||
c6ec54c138 | |||
1f6b90d383 | |||
c45c2e27ba | |||
5832890dbb | |||
6f2e6d14b6 | |||
0d899694b2 | |||
7bd5e7365d | |||
a63e51e2ad | |||
1b8eee86a1 | |||
6d50278d34 | |||
35844842de | |||
843e772094 | |||
9d0518dfeb | |||
d33d399c31 |
9
.github/workflows/build-apps.yml
vendored
9
.github/workflows/build-apps.yml
vendored
@ -207,6 +207,13 @@ jobs:
|
||||
smctl.exe keypair ls
|
||||
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
|
||||
smksp_cert_sync.exe
|
||||
smctl windows certsync
|
||||
# This last line `smctl windows certsync` was added after windows codesign failures started happening
|
||||
# with nightly-v25.4.10. It looks like `smksp_cert_sync.exe` used to do the sync to the local cert store,
|
||||
# but stopped doing it overnight. This extra call that I randomly got from this azure-related doc page
|
||||
# https://docs.digicert.com/en/digicert-keylocker/code-signing/sign-with-third-party-signing-tools/windows-applications/sign-azure-apps-with-signtool-using-ksp-library.html#sync-certificates--windows-only--618365
|
||||
# seems to be doing that extra sync that we need for scripts/sign-win.js to work.
|
||||
# TODO: we still need to make sign-win.js errors fail the workflow, see issue #6276
|
||||
shell: cmd
|
||||
|
||||
- name: Build the app (debug)
|
||||
@ -378,7 +385,7 @@ jobs:
|
||||
NOTES: ${{ needs.prepare-files.outputs.notes }}
|
||||
PUB_DATE: ${{ github.event.repository.updated_at }}
|
||||
WEBSITE_DIR: ${{ env.IS_NIGHTLY == 'true' && 'dl.zoo.dev/releases/modeling-app/nightly' || 'dl.zoo.dev/releases/modeling-app' }}
|
||||
URL_CODED_NAME: ${{ env.IS_NIGHTLY == 'true' && 'Zoo%20Modeling%20App%20%28Nightly%29' || 'Zoo%20Modeling%20App' }}
|
||||
URL_CODED_NAME: ${{ env.IS_NIGHTLY == 'true' && 'Zoo%20Design%20Studio%20%28Nightly%29' || 'Zoo%20Design%20Studio' }}
|
||||
run: |
|
||||
RELEASE_DIR=https://${WEBSITE_DIR}
|
||||
jq --null-input \
|
||||
|
10
.github/workflows/e2e-tests.yml
vendored
10
.github/workflows/e2e-tests.yml
vendored
@ -231,6 +231,11 @@ jobs:
|
||||
env:
|
||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}
|
||||
TAB_API_URL: ${{ secrets.TAB_API_URL }}
|
||||
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
||||
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
TARGET: web
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}
|
||||
@ -365,6 +370,11 @@ jobs:
|
||||
env:
|
||||
FAIL_ON_CONSOLE_ERRORS: true
|
||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
TAB_API_URL: ${{ secrets.TAB_API_URL }}
|
||||
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
||||
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
TARGET: desktop
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ needs.conditions.outputs.should-run == 'true' && always() }}
|
||||
|
55
.github/workflows/nix.yml
vendored
Normal file
55
.github/workflows/nix.yml
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
name: Test Nix Flake
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
nix-flake-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
- name: nix flake check for all platforms
|
||||
run: |
|
||||
nix flake check --all-systems
|
||||
|
||||
nix-build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
- name: nix build . for x86_64-linux
|
||||
run: nix build .
|
||||
|
||||
nix-build-macos:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
- name: nix build . for x86_64-darwin
|
||||
run: nix build .
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -26,6 +26,7 @@ yarn-error.log*
|
||||
.idea
|
||||
.vscode
|
||||
.helix
|
||||
result
|
||||
|
||||
# rust
|
||||
rust/target
|
||||
|
2
Makefile
2
Makefile
@ -17,7 +17,7 @@ WASM_PACK ?= $(USERPROFILE)/.cargo/bin/wasm-pack.exe
|
||||
else
|
||||
CARGO ?= ~/.cargo/bin/cargo
|
||||
WASM_PACK ?= ~/.cargo/bin/wasm-pack
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: install
|
||||
install: node_modules/.yarn-integrity $(CARGO) $(WASM_PACK) ## Install dependencies
|
||||
|
@ -188,9 +188,9 @@ example = extrude(exampleSketch, length = 1)
|
||||
sweepPath = startSketchOn(XZ)
|
||||
|> startProfileAt([0.05, 0.05], %)
|
||||
|> line(end = [0, 7])
|
||||
|> tangentialArc({ offset = 90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = 90, radius = 5)
|
||||
|> line(end = [-3, 0])
|
||||
|> tangentialArc({ offset = -90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = -90, radius = 5)
|
||||
|> line(end = [0, 7])
|
||||
|
||||
pipeHole = startSketchOn(XY)
|
||||
|
@ -65,7 +65,7 @@ case = startSketchOn(-XZ)
|
||||
|> startProfileAt([-size, -size], %)
|
||||
|> line(end = [2 * size, 0])
|
||||
|> line(end = [0, 2 * size])
|
||||
|> tangentialArcTo([-size, size], %)
|
||||
|> tangentialArc(endAbsolute = [-size, size])
|
||||
|> close()
|
||||
|> extrude(length = 65)
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -77,6 +77,7 @@ layout: manual
|
||||
* [`helix`](kcl/std-helix)
|
||||
* [`hole`](kcl/hole)
|
||||
* [`hollow`](kcl/hollow)
|
||||
* [`intersect`](kcl/intersect)
|
||||
* [`lastSegX`](kcl/lastSegX)
|
||||
* [`lastSegY`](kcl/lastSegY)
|
||||
* [`legAngX`](kcl/legAngX)
|
||||
@ -123,14 +124,14 @@ layout: manual
|
||||
* [`sqrt`](kcl/sqrt)
|
||||
* [`startProfileAt`](kcl/startProfileAt)
|
||||
* [`startSketchOn`](kcl/startSketchOn)
|
||||
* [`subtract`](kcl/subtract)
|
||||
* [`sweep`](kcl/sweep)
|
||||
* [`tangentToEnd`](kcl/tangentToEnd)
|
||||
* [`tangentialArc`](kcl/tangentialArc)
|
||||
* [`tangentialArcTo`](kcl/tangentialArcTo)
|
||||
* [`tangentialArcToRelative`](kcl/tangentialArcToRelative)
|
||||
* [`toDegrees`](kcl/toDegrees)
|
||||
* [`toRadians`](kcl/toRadians)
|
||||
* [`translate`](kcl/translate)
|
||||
* [`union`](kcl/union)
|
||||
* [`xLine`](kcl/xLine)
|
||||
* [`yLine`](kcl/yLine)
|
||||
* **std::math**
|
||||
|
File diff suppressed because one or more lines are too long
@ -57,7 +57,7 @@ case = startSketchOn(XY)
|
||||
|> startProfileAt([-size, -size], %)
|
||||
|> line(end = [2 * size, 0])
|
||||
|> line(end = [0, 2 * size])
|
||||
|> tangentialArcTo([-size, size], %)
|
||||
|> tangentialArc(endAbsolute = [-size, size])
|
||||
|> close(%)
|
||||
|> extrude(length = 65)
|
||||
|
||||
@ -88,7 +88,7 @@ case = startSketchOn(XY)
|
||||
|> startProfileAt([-size, -size], %)
|
||||
|> line(end = [2 * size, 0])
|
||||
|> line(end = [0, 2 * size])
|
||||
|> tangentialArcTo([-size, size], %)
|
||||
|> tangentialArc(endAbsolute = [-size, size])
|
||||
|> close(%)
|
||||
|> extrude(length = 65)
|
||||
|
||||
|
@ -65,9 +65,9 @@ rotate(
|
||||
sweepPath = startSketchOn(XZ)
|
||||
|> startProfileAt([0.05, 0.05], %)
|
||||
|> line(end = [0, 7])
|
||||
|> tangentialArc({ offset = 90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = 90, radius = 5)
|
||||
|> line(end = [-3, 0])
|
||||
|> tangentialArc({ offset = -90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = -90, radius = 5)
|
||||
|> line(end = [0, 7])
|
||||
|
||||
// Create a hole for the pipe.
|
||||
@ -90,9 +90,9 @@ sweepSketch = startSketchOn(XY)
|
||||
sweepPath = startSketchOn(XZ)
|
||||
|> startProfileAt([0.05, 0.05], %)
|
||||
|> line(end = [0, 7])
|
||||
|> tangentialArc({ offset = 90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = 90, radius = 5)
|
||||
|> line(end = [-3, 0])
|
||||
|> tangentialArc({ offset = -90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = -90, radius = 5)
|
||||
|> line(end = [0, 7])
|
||||
|
||||
// Create a hole for the pipe.
|
||||
@ -115,9 +115,9 @@ sweepSketch = startSketchOn(XY)
|
||||
sweepPath = startSketchOn(XZ)
|
||||
|> startProfileAt([0.05, 0.05], %)
|
||||
|> line(end = [0, 7])
|
||||
|> tangentialArc({ offset = 90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = 90, radius = 5)
|
||||
|> line(end = [-3, 0])
|
||||
|> tangentialArc({ offset = -90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = -90, radius = 5)
|
||||
|> line(end = [0, 7])
|
||||
|
||||
// Create a hole for the pipe.
|
||||
@ -162,7 +162,7 @@ circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
|
||||
sketch002 = startSketchOn(YZ)
|
||||
sweepPath = startProfileAt([0, 0], sketch002)
|
||||
|> yLine(length = 231.81)
|
||||
|> tangentialArc({ radius = 80, offset = -90 }, %)
|
||||
|> tangentialArc(radius = 80, angle = -90)
|
||||
|> xLine(length = 384.93)
|
||||
|
||||
parts = sweep([rectangleSketch, circleSketch], path = sweepPath)
|
||||
|
@ -49,9 +49,9 @@ scale(
|
||||
sweepPath = startSketchOn(XZ)
|
||||
|> startProfileAt([0.05, 0.05], %)
|
||||
|> line(end = [0, 7])
|
||||
|> tangentialArc({ offset = 90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = 90, radius = 5)
|
||||
|> line(end = [-3, 0])
|
||||
|> tangentialArc({ offset = -90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = -90, radius = 5)
|
||||
|> line(end = [0, 7])
|
||||
|
||||
// Create a hole for the pipe.
|
||||
@ -96,7 +96,7 @@ circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
|
||||
sketch002 = startSketchOn(YZ)
|
||||
sweepPath = startProfileAt([0, 0], sketch002)
|
||||
|> yLine(length = 231.81)
|
||||
|> tangentialArc({ radius = 80, offset = -90 }, %)
|
||||
|> tangentialArc(radius = 80, angle = -90)
|
||||
|> xLine(length = 384.93)
|
||||
|
||||
parts = sweep([rectangleSketch, circleSketch], path = sweepPath)
|
||||
|
@ -30,7 +30,7 @@ segLen(tag: TagIdentifier): number
|
||||
exampleSketch = startSketchOn(XZ)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> angledLine(angle = 60, length = 10, tag = $thing)
|
||||
|> tangentialArc({ offset = -120, radius = 5 }, %)
|
||||
|> tangentialArc(angle = -120, radius = 5)
|
||||
|> angledLine(angle = -60, length = segLen(thing))
|
||||
|> close()
|
||||
|
||||
|
@ -103,7 +103,7 @@ case = startSketchOn(-XZ)
|
||||
|> startProfileAt([-size, -size], %)
|
||||
|> line(end = [2 * size, 0])
|
||||
|> line(end = [0, 2 * size])
|
||||
|> tangentialArcTo([-size, size], %)
|
||||
|> tangentialArc(endAbsolute = [-size, size])
|
||||
|> close()
|
||||
|> extrude(length = 65)
|
||||
|
||||
@ -128,7 +128,7 @@ case = startSketchOn(XY)
|
||||
|> startProfileAt([-size, -size], %)
|
||||
|> line(end = [2 * size, 0])
|
||||
|> line(end = [0, 2 * size])
|
||||
|> tangentialArcTo([-size, size], %)
|
||||
|> tangentialArc(endAbsolute = [-size, size])
|
||||
|> close()
|
||||
|> extrude(length = 65)
|
||||
|
||||
@ -156,7 +156,7 @@ case = startSketchOn(XY)
|
||||
|> startProfileAt([-size, -size], %)
|
||||
|> line(end = [2 * size, 0])
|
||||
|> line(end = [0, 2 * size])
|
||||
|> tangentialArcTo([-size, size], %)
|
||||
|> tangentialArc(endAbsolute = [-size, size])
|
||||
|> close()
|
||||
|> extrude(length = 65)
|
||||
|
||||
|
@ -103,9 +103,9 @@ example = extrude(sketch001, length = 10)
|
||||
sketch0011 = startSketchOn(XY)
|
||||
|> startProfileAt([6.77, 0], %)
|
||||
|> yLine(length = 1.27)
|
||||
|> tangentialArcTo([5.96, 2.37], %)
|
||||
|> tangentialArcTo([-6.2, 2.44], %)
|
||||
|> tangentialArcTo([-6.6, 1.82], %)
|
||||
|> tangentialArc(endAbsolute = [5.96, 2.37])
|
||||
|> tangentialArc(endAbsolute = [-6.2, 2.44])
|
||||
|> tangentialArc(endAbsolute = [-6.6, 1.82])
|
||||
|> yLine(length = -1.82)
|
||||
|> mirror2d( axis = X )
|
||||
|> extrude(length = 10)
|
||||
|
21562
docs/kcl/std.json
21562
docs/kcl/std.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -47,9 +47,9 @@ sweep(
|
||||
sweepPath = startSketchOn(XZ)
|
||||
|> startProfileAt([0.05, 0.05], %)
|
||||
|> line(end = [0, 7])
|
||||
|> tangentialArc({ offset = 90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = 90, radius = 5)
|
||||
|> line(end = [-3, 0])
|
||||
|> tangentialArc({ offset = -90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = -90, radius = 5)
|
||||
|> line(end = [0, 7])
|
||||
|
||||
// Create a hole for the pipe.
|
||||
@ -102,7 +102,7 @@ circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
|
||||
sketch002 = startSketchOn(YZ)
|
||||
sweepPath = startProfileAt([0, 0], sketch002)
|
||||
|> yLine(length = 231.81)
|
||||
|> tangentialArc({ radius = 80, offset = -90 }, %)
|
||||
|> tangentialArc(radius = 80, angle = -90)
|
||||
|> xLine(length = 384.93)
|
||||
|
||||
sweep([rectangleSketch, circleSketch], path = sweepPath)
|
||||
@ -120,7 +120,7 @@ circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
|
||||
sketch002 = startSketchOn(YZ)
|
||||
sweepPath = startProfileAt([0, 0], sketch002)
|
||||
|> yLine(length = 231.81)
|
||||
|> tangentialArc({ radius = 80, offset = -90 }, %)
|
||||
|> tangentialArc(radius = 80, angle = -90)
|
||||
|> xLine(length = 384.93)
|
||||
|
||||
sweep(circleSketch, path = sweepPath, sectional = true)
|
||||
|
@ -31,9 +31,9 @@ tangentToEnd(tag: TagIdentifier): number
|
||||
pillSketch = startSketchOn(XZ)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line(end = [20, 0])
|
||||
|> tangentialArcToRelative([0, 10], %, $arc1)
|
||||
|> tangentialArc(end = [0, 10], tag = $arc1)
|
||||
|> angledLine(angle = tangentToEnd(arc1), length = 20)
|
||||
|> tangentialArcToRelative([0, -10], %)
|
||||
|> tangentialArc(end = [0, -10])
|
||||
|> close()
|
||||
|
||||
pillExtrude = extrude(pillSketch, length = 10)
|
||||
@ -46,9 +46,9 @@ pillExtrude = extrude(pillSketch, length = 10)
|
||||
pillSketch = startSketchOn(XZ)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line(end = [0, 20])
|
||||
|> tangentialArcTo([10, 20], %, $arc1)
|
||||
|> tangentialArc(endAbsolute = [10, 20], tag = $arc1)
|
||||
|> angledLine(angle = tangentToEnd(arc1), length = 20)
|
||||
|> tangentialArcToRelative([-10, 0], %)
|
||||
|> tangentialArc(end = [-10, 0])
|
||||
|> close()
|
||||
|
||||
pillExtrude = extrude(pillSketch, length = 10)
|
||||
|
File diff suppressed because one or more lines are too long
@ -45,9 +45,9 @@ translate(
|
||||
sweepPath = startSketchOn(XZ)
|
||||
|> startProfileAt([0.05, 0.05], %)
|
||||
|> line(end = [0, 7])
|
||||
|> tangentialArc({ offset = 90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = 90, radius = 5)
|
||||
|> line(end = [-3, 0])
|
||||
|> tangentialArc({ offset = -90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = -90, radius = 5)
|
||||
|> line(end = [0, 7])
|
||||
|
||||
// Create a hole for the pipe.
|
||||
@ -97,7 +97,7 @@ circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
|
||||
sketch002 = startSketchOn(YZ)
|
||||
sweepPath = startProfileAt([0, 0], sketch002)
|
||||
|> yLine(length = 231.81)
|
||||
|> tangentialArc({ radius = 80, offset = -90 }, %)
|
||||
|> tangentialArc(radius = 80, angle = -90)
|
||||
|> xLine(length = 384.93)
|
||||
|
||||
parts = sweep([rectangleSketch, circleSketch], path = sweepPath)
|
||||
|
@ -252,7 +252,7 @@ Data for an imported geometry.
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: [`ImportedGeometry`](/docs/kcl/types/ImportedGeometry)| | No |
|
||||
| `type` |enum: `ImportedGeometry`| | No |
|
||||
| `id` |[`string`](/docs/kcl/types/string)| The ID of the imported geometry. | No |
|
||||
| `value` |`[` [`string`](/docs/kcl/types/string) `]`| The original file paths. | No |
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -920,7 +920,7 @@ sketch001 = startSketchOn(XZ)
|
||||
`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([4.61, -14.01], %)
|
||||
|> line(end = [12.73, -0.09])
|
||||
|> tangentialArcTo([24.95, -5.38], %)
|
||||
|> tangentialArc(endAbsolute = [24.95, -5.38])
|
||||
|> close()`
|
||||
)
|
||||
})
|
||||
@ -969,7 +969,7 @@ sketch001 = startSketchOn(XZ)
|
||||
|
||||
// expect the code to have changed
|
||||
await expect(page.locator('.cm-content')).toHaveText(
|
||||
`sketch001 = startSketchOn(XZ) |> startProfileAt([4.61, -14.01], %) |> line(end = [12.73, -0.09]) |> tangentialArcTo([24.95, -5.38], %) |> close()extrude001 = extrude(sketch001, length = 5)`
|
||||
`sketch001 = startSketchOn(XZ) |> startProfileAt([4.61, -14.01], %) |> line(end = [12.73, -0.09]) |> tangentialArc(endAbsolute = [24.95, -5.38]) |> close()extrude001 = extrude(sketch001, length = 5)`
|
||||
)
|
||||
|
||||
// Now hit undo
|
||||
@ -982,7 +982,7 @@ sketch001 = startSketchOn(XZ)
|
||||
.toHaveText(`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([4.61, -14.01], %)
|
||||
|> line(end = [12.73, -0.09])
|
||||
|> tangentialArcTo([24.95, -5.38], %)
|
||||
|> tangentialArc(endAbsolute = [24.95, -5.38])
|
||||
|> close()`)
|
||||
})
|
||||
|
||||
@ -998,7 +998,7 @@ sketch001 = startSketchOn(XZ)
|
||||
sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([4.61, -10.01], %)
|
||||
|> line(end = [12.73, -0.09])
|
||||
|> tangentialArcTo([24.95, -0.38], %)
|
||||
|> tangentialArc(endAbsolute = [24.95, -0.38])
|
||||
|> close()
|
||||
|> extrude(length = 5)`
|
||||
)
|
||||
@ -1072,7 +1072,7 @@ sketch001 = startSketchOn(XZ)
|
||||
// we wait so it saves the code
|
||||
await page.waitForTimeout(800)
|
||||
|
||||
// drag tangentialArcTo handle
|
||||
// drag tangentialArc handle
|
||||
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
|
||||
await page.dragAndDrop('#stream', '#stream', {
|
||||
sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 },
|
||||
@ -1089,7 +1089,7 @@ sketch001 = startSketchOn(XZ)
|
||||
`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([2.71, -2.71], %)
|
||||
|> line(end = [15.4, -2.78])
|
||||
|> tangentialArcTo([27.6, -3.05], %)
|
||||
|> tangentialArc(endAbsolute = [27.6, -3.05])
|
||||
|> close()
|
||||
|> extrude(length = 5)`,
|
||||
{ shouldNormalise: true }
|
||||
@ -1104,7 +1104,7 @@ sketch001 = startSketchOn(XZ)
|
||||
`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([2.71, -2.71], %)
|
||||
|> line(end = [15.4, -2.78])
|
||||
|> tangentialArcTo([24.95, -0.38], %)
|
||||
|> tangentialArc(endAbsolute = [24.95, -0.38])
|
||||
|> close()
|
||||
|> extrude(length = 5)`,
|
||||
{ shouldNormalise: true }
|
||||
@ -1119,7 +1119,7 @@ sketch001 = startSketchOn(XZ)
|
||||
`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([2.71, -2.71], %)
|
||||
|> line(end = [12.73, -0.09])
|
||||
|> tangentialArcTo([24.95, -0.38], %)
|
||||
|> tangentialArc(endAbsolute = [24.95, -0.38])
|
||||
|> close()
|
||||
|> extrude(length = 5)`,
|
||||
{ shouldNormalise: true }
|
||||
@ -1135,7 +1135,7 @@ sketch001 = startSketchOn(XZ)
|
||||
`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([4.61, -10.01], %)
|
||||
|> line(end = [12.73, -0.09])
|
||||
|> tangentialArcTo([24.95, -0.38], %)
|
||||
|> tangentialArc(endAbsolute = [24.95, -0.38])
|
||||
|> close()
|
||||
|> extrude(length = 5)`,
|
||||
{ shouldNormalise: true }
|
||||
@ -1144,7 +1144,7 @@ sketch001 = startSketchOn(XZ)
|
||||
)
|
||||
|
||||
test(
|
||||
`Can use the import stdlib function on a local OBJ file`,
|
||||
`Can import a local OBJ file`,
|
||||
{ tag: '@electron' },
|
||||
async ({ page, context }, testInfo) => {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
@ -1194,7 +1194,7 @@ sketch001 = startSketchOn(XZ)
|
||||
.toBeLessThan(15)
|
||||
})
|
||||
await test.step(`Write the import function line`, async () => {
|
||||
await u.codeLocator.fill(`import('cube.obj')`)
|
||||
await u.codeLocator.fill(`import 'cube.obj'\ncube`)
|
||||
await page.waitForTimeout(800)
|
||||
})
|
||||
await test.step(`Reset the camera before checking`, async () => {
|
||||
|
@ -99,7 +99,6 @@ export class HomePageFixture {
|
||||
createAndGoToProject = async (projectTitle = 'untitled') => {
|
||||
await this.projectsLoaded()
|
||||
await this.projectButtonNew.click()
|
||||
await this.projectTextName.click()
|
||||
await this.projectTextName.fill(projectTitle)
|
||||
await this.projectButtonContinue.click()
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ export class SceneFixture {
|
||||
settled = async (cmdBar: CmdBarFixture) => {
|
||||
const u = await getUtils(this.page)
|
||||
|
||||
await expect(this.startEditSketchBtn).not.toBeDisabled()
|
||||
await expect(this.startEditSketchBtn).not.toBeDisabled({ timeout: 15_000 })
|
||||
await expect(this.startEditSketchBtn).toBeVisible()
|
||||
|
||||
await cmdBar.openCmdBar()
|
||||
|
63
e2e/playwright/lib/api-reporter.ts
Normal file
63
e2e/playwright/lib/api-reporter.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import type { Reporter, TestCase, TestResult } from '@playwright/test/reporter'
|
||||
|
||||
class MyAPIReporter implements Reporter {
|
||||
onTestEnd(test: TestCase, result: TestResult): void {
|
||||
if (!process.env.TAB_API_URL || !process.env.TAB_API_KEY) {
|
||||
return
|
||||
}
|
||||
|
||||
const payload = {
|
||||
// Required information
|
||||
project: 'https://github.com/KittyCAD/modeling-app',
|
||||
branch: process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME || '',
|
||||
commit: process.env.CI_COMMIT_SHA || process.env.GITHUB_SHA || '',
|
||||
test: test.titlePath().slice(2).join(' › '),
|
||||
status: result.status,
|
||||
// Optional information
|
||||
duration: result.duration / 1000,
|
||||
message: result.error?.stack,
|
||||
target: process.env.TARGET || null,
|
||||
platform: process.env.RUNNER_OS || process.platform,
|
||||
// Extra test and result data
|
||||
annotations: test.annotations.map((a) => a.type),
|
||||
retries: result.retry,
|
||||
// Extra environment variables
|
||||
CI_COMMIT_SHA: process.env.CI_COMMIT_SHA || null,
|
||||
CI_PR_NUMBER: process.env.CI_PR_NUMBER || null,
|
||||
GITHUB_BASE_REF: process.env.GITHUB_BASE_REF || null,
|
||||
GITHUB_EVENT_NAME: process.env.GITHUB_EVENT_NAME || null,
|
||||
GITHUB_HEAD_REF: process.env.GITHUB_HEAD_REF || null,
|
||||
GITHUB_REF_NAME: process.env.GITHUB_REF_NAME || null,
|
||||
GITHUB_REF: process.env.GITHUB_REF || null,
|
||||
GITHUB_SHA: process.env.GITHUB_SHA || null,
|
||||
GITHUB_WORKFLOW: process.env.GITHUB_WORKFLOW || null,
|
||||
RUNNER_ARCH: process.env.RUNNER_ARCH || null,
|
||||
}
|
||||
|
||||
void (async () => {
|
||||
try {
|
||||
const response = await fetch(`${process.env.TAB_API_URL}/api/results`, {
|
||||
method: 'POST',
|
||||
headers: new Headers({
|
||||
'Content-Type': 'application/json',
|
||||
'X-API-Key': process.env.TAB_API_KEY || '',
|
||||
}),
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
|
||||
if (!response.ok && !process.env.CI) {
|
||||
console.error(
|
||||
'TAB API - Failed to send test result:',
|
||||
await response.text()
|
||||
)
|
||||
}
|
||||
} catch {
|
||||
if (!process.env.CI) {
|
||||
console.error('TAB API - Unable to send test result')
|
||||
}
|
||||
}
|
||||
})()
|
||||
}
|
||||
}
|
||||
|
||||
export default MyAPIReporter
|
@ -6,7 +6,9 @@ import type { NamedView } from '@rust/kcl-lib/bindings/NamedView'
|
||||
|
||||
import {
|
||||
createProject,
|
||||
perProjectsettingsToToml,
|
||||
orRunWhenFullSuiteEnabled,
|
||||
perProjectSettingsToToml,
|
||||
runningOnMac,
|
||||
tomlToPerProjectSettings,
|
||||
} from '@e2e/playwright/test-utils'
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
@ -57,11 +59,13 @@ function tomlStringOverWriteNamedViewUuids(toml: string): string {
|
||||
settings.settings.app.named_views = remappedNamedViews
|
||||
}
|
||||
}
|
||||
return perProjectsettingsToToml(settings)
|
||||
return perProjectSettingsToToml(settings)
|
||||
}
|
||||
|
||||
test.describe('Named view tests', () => {
|
||||
test.skip() // TODO: Jace is working on these
|
||||
if (runningOnMac()) {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
}
|
||||
test('Verify project.toml is not created', async ({ page }, testInfo) => {
|
||||
// Create project and load it
|
||||
const projectName = 'named-views'
|
||||
@ -105,6 +109,9 @@ test.describe('Named view tests', () => {
|
||||
PROJECT_SETTINGS_FILE_NAME
|
||||
)
|
||||
|
||||
const toastMessage = page.getByText('Named view uuid1 created.')
|
||||
await expect(toastMessage).toBeInViewport()
|
||||
|
||||
// Expect project.toml to be generated on disk since a named view was created
|
||||
await expect(async () => {
|
||||
let exists = await fileExists(tempProjectSettingsFilePath)
|
||||
@ -130,7 +137,6 @@ test.describe('Named view tests', () => {
|
||||
}, testInfo) => {
|
||||
const projectName = 'named-views'
|
||||
const myNamedView1 = 'uuid1'
|
||||
const myNamedView2 = 'uuid2'
|
||||
|
||||
// Create project and go into the project
|
||||
await createProject({ name: projectName, page })
|
||||
@ -142,6 +148,9 @@ test.describe('Named view tests', () => {
|
||||
await cmdBar.argumentInput.fill(myNamedView1)
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
let toastMessage = page.getByText('Named view uuid1 created.')
|
||||
await expect(toastMessage).toBeInViewport()
|
||||
|
||||
// Generate file paths for project.toml
|
||||
const projectDirName = testInfo.outputPath('electron-test-projects-dir')
|
||||
const tempProjectSettingsFilePath = join(
|
||||
@ -170,17 +179,20 @@ test.describe('Named view tests', () => {
|
||||
// Delete a named view
|
||||
await cmdBar.openCmdBar()
|
||||
await cmdBar.chooseCommand('delete named view')
|
||||
cmdBar.selectOption({ name: myNamedView2 })
|
||||
cmdBar.selectOption({ name: myNamedView1 })
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
toastMessage = page.getByText('Named view uuid1 removed.')
|
||||
await expect(toastMessage).toBeInViewport()
|
||||
|
||||
await expect(async () => {
|
||||
// Read project.toml into memory again since we deleted a named view
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
|
||||
// // Write the entire tomlString to a snapshot.
|
||||
// // There are many key/value pairs to check this is a safer match.
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-deleted')
|
||||
}).toPass()
|
||||
})
|
||||
@ -202,6 +214,9 @@ test.describe('Named view tests', () => {
|
||||
await cmdBar.argumentInput.fill(myNamedView)
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
let toastMessage = page.getByText('Named view uuid1 created.')
|
||||
await expect(toastMessage).toBeInViewport()
|
||||
|
||||
// Generate file paths for project.toml
|
||||
const projectDirName = testInfo.outputPath('electron-test-projects-dir')
|
||||
const tempProjectSettingsFilePath = join(
|
||||
@ -258,26 +273,19 @@ test.describe('Named view tests', () => {
|
||||
await cmdBar.argumentInput.fill(myNamedView1)
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
await page.waitForTimeout(1000)
|
||||
let toastMessage = page.getByText('Named view uuid1 created.')
|
||||
await expect(toastMessage).toBeInViewport()
|
||||
|
||||
const orbitMouseStart = { x: 800, y: 130 }
|
||||
const orbitMouseEnd = { x: 0, y: 130 }
|
||||
await page.mouse.move(orbitMouseStart.x, orbitMouseStart.y)
|
||||
await page.mouse.down({ button: 'middle' })
|
||||
await page.mouse.move(orbitMouseEnd.x, orbitMouseEnd.y, {
|
||||
steps: 3,
|
||||
})
|
||||
await page.mouse.up({ button: 'middle' })
|
||||
|
||||
await page.waitForTimeout(1000)
|
||||
await scene.moveCameraTo({ x: 608, y: 0, z: 0 }, { x: 0, y: 0, z: 0 })
|
||||
await page.waitForTimeout(2500)
|
||||
|
||||
await cmdBar.openCmdBar()
|
||||
await cmdBar.chooseCommand('create named view')
|
||||
await cmdBar.argumentInput.fill(myNamedView2)
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
// Wait a moment for the project.toml to get written to disk with the new view point
|
||||
await page.waitForTimeout(1000)
|
||||
toastMessage = page.getByText('Named view uuid2 created.')
|
||||
await expect(toastMessage).toBeInViewport()
|
||||
|
||||
// Generate paths for the project.toml
|
||||
const tempProjectSettingsFilePath = join(
|
||||
|
@ -1,16 +1,5 @@
|
||||
[settings]
|
||||
app = { }
|
||||
modeling = { }
|
||||
text_editor = { }
|
||||
command_bar = { }
|
||||
|
||||
[settings.app.named_views.0656fb1a-9640-473e-b334-591dc70c0138]
|
||||
name = "uuid1"
|
||||
eye_offset = 1_378.0059
|
||||
fov_y = 45
|
||||
is_ortho = false
|
||||
ortho_scale_enabled = true
|
||||
ortho_scale_factor = 1.6
|
||||
pivot_position = [ 0, 0, 0 ]
|
||||
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
|
||||
world_coord_system = "right_handed_up_z"
|
||||
version = 1
|
||||
|
@ -17,12 +17,12 @@ version = 1
|
||||
|
||||
[settings.app.named_views.c810cf04-c6cc-4a4a-8b11-17bf445dcab7]
|
||||
name = "uuid2"
|
||||
eye_offset = 1_378.0059
|
||||
eye_offset = 608
|
||||
fov_y = 45
|
||||
is_ortho = false
|
||||
ortho_scale_enabled = true
|
||||
ortho_scale_factor = 1.6
|
||||
pivot_position = [ 1_826.5239, 0.0, 0.0 ]
|
||||
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
|
||||
pivot_position = [ 0, 0, 0 ]
|
||||
pivot_rotation = [ 0.5, 0.5, 0.5, 0.5 ]
|
||||
world_coord_system = "right_handed_up_z"
|
||||
version = 1
|
||||
|
@ -550,7 +550,7 @@ openSketch = startSketchOn(XY)
|
||||
|> startProfileAt([-5, 0], %)
|
||||
|> line(endAbsolute = [0, 5])
|
||||
|> xLine(length = 5)
|
||||
|> tangentialArcTo([10, 0], %)
|
||||
|> tangentialArc(endAbsolute = [10, 0])
|
||||
`
|
||||
const viewPortSize = { width: 1000, height: 500 }
|
||||
await page.setBodyDimensions(viewPortSize)
|
||||
@ -634,8 +634,8 @@ openSketch = startSketchOn(XY)
|
||||
// Wait for enter sketch mode to complete
|
||||
await page.waitForTimeout(500)
|
||||
await editor.expectState({
|
||||
activeLines: [`|>tangentialArcTo([10,0],%)`],
|
||||
highlightedCode: 'tangentialArcTo([10,0],%)',
|
||||
activeLines: [`|>tangentialArc(endAbsolute=[10,0])`],
|
||||
highlightedCode: 'tangentialArc(endAbsolute=[10,0])',
|
||||
diagnostics: [],
|
||||
})
|
||||
})
|
||||
@ -1624,7 +1624,7 @@ profile001 = circle(sketch001, center = [0, 0], radius = 500)
|
||||
sketch002 = startSketchOn(XZ)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> xLine(length = -500)
|
||||
|> tangentialArcTo([-2000, 500], %)`,
|
||||
|> tangentialArc(endAbsolute = [-2000, 500])`,
|
||||
},
|
||||
{
|
||||
targetType: 'rectangle',
|
||||
@ -1640,7 +1640,7 @@ profile001 = startProfileAt([-400, -400], sketch001)
|
||||
sketch002 = startSketchOn(XZ)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> xLine(length = -500)
|
||||
|> tangentialArcTo([-2000, 500], %)`,
|
||||
|> tangentialArc(endAbsolute = [-2000, 500])`,
|
||||
},
|
||||
]
|
||||
sweepCases.map(({ initialCode, targetType, testPoint }) => {
|
||||
|
@ -68,12 +68,10 @@ test.describe('edit with AI example snapshots', () => {
|
||||
body1CapCoords.x,
|
||||
body1CapCoords.y
|
||||
)
|
||||
const yellow: [number, number, number] = [179, 179, 131]
|
||||
const submittingToast = page.getByText('Submitting to Text-to-CAD API...')
|
||||
|
||||
await test.step('wait for scene to load select body and check selection came through', async () => {
|
||||
await clickBody1Cap()
|
||||
await scene.expectPixelColor(yellow, body1CapCoords, 20)
|
||||
await editor.expectState({
|
||||
highlightedCode: '',
|
||||
activeLines: ['|>startProfileAt([-73.64,-42.89],%)'],
|
||||
|
@ -63,7 +63,7 @@ test.describe('Sketch tests', { tag: ['@skipWin'] }, () => {
|
||||
part002 = startSketchOn(-XZ)
|
||||
${startProfileAt3}
|
||||
|> xLine(length = width / 4)
|
||||
|> tangentialArcTo([width / 2, 0], %)
|
||||
|> tangentialArc(endAbsolute = [width / 2, 0])
|
||||
|> xLine(length = -width / 4 + wireRadius)
|
||||
|> yLine(length = wireOffset)
|
||||
|> arc({
|
||||
@ -119,7 +119,7 @@ test.describe('Sketch tests', { tag: ['@skipWin'] }, () => {
|
||||
sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([2.61, -4.01], %)
|
||||
|> xLine(length = 8.73)
|
||||
|> tangentialArcTo([8.33, -1.31], %)`
|
||||
|> tangentialArc(endAbsolute = [8.33, -1.31])`
|
||||
)
|
||||
})
|
||||
|
||||
@ -130,7 +130,7 @@ sketch001 = startSketchOn(XZ)
|
||||
|
||||
await expect(async () => {
|
||||
await page.mouse.click(700, 200)
|
||||
await page.getByText('tangentialArcTo([8.33, -1.31], %)').click()
|
||||
await page.getByText('tangentialArc(endAbsolute = [8.33, -1.31])').click()
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Edit Sketch' })
|
||||
).toBeEnabled({ timeout: 2000 })
|
||||
@ -139,7 +139,7 @@ sketch001 = startSketchOn(XZ)
|
||||
|
||||
await page.waitForTimeout(600) // wait for animation
|
||||
|
||||
await page.getByText('tangentialArcTo([8.33, -1.31], %)').click()
|
||||
await page.getByText('tangentialArc(endAbsolute = [8.33, -1.31])').click()
|
||||
await page.keyboard.press('End')
|
||||
await page.keyboard.down('Shift')
|
||||
await page.keyboard.press('ArrowUp')
|
||||
@ -212,7 +212,7 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
|
||||
`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([4.61, -14.01], %)
|
||||
|> line(end = [12.73, -0.09])
|
||||
|> tangentialArcTo([24.95, -5.38], %)
|
||||
|> tangentialArc(endAbsolute = [24.95, -5.38])
|
||||
|> arcTo({
|
||||
interior = [20.18, -1.7],
|
||||
end = [11.82, -1.16]
|
||||
@ -262,7 +262,7 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
|
||||
await expect(u.codeLocator).toHaveText(`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([4.61, -14.01], %)
|
||||
|> line(end = [12.73, -0.09])
|
||||
|> tangentialArcTo([24.95, -5.38], %)
|
||||
|> tangentialArc(endAbsolute = [24.95, -5.38])
|
||||
|> arcTo({
|
||||
interior = [20.18, -1.7],
|
||||
end = [11.82, -1.16]
|
||||
@ -326,7 +326,7 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
|
||||
prevContent = await page.locator('.cm-content').innerText()
|
||||
}
|
||||
|
||||
// drag tangentialArcTo handle
|
||||
// drag tangentialArc handle
|
||||
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
|
||||
await page.mouse.move(tangentEnd.x, tangentEnd.y - 5)
|
||||
await page.mouse.down()
|
||||
@ -407,7 +407,7 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
|
||||
.toHaveText(`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([6.44, -12.07], %)
|
||||
|> line(end = [14.72, 1.97])
|
||||
|> tangentialArcTo([26.92, -3.32], %)
|
||||
|> tangentialArc(endAbsolute = [26.92, -3.32])
|
||||
|> arcTo({
|
||||
interior = [18.11, -3.73],
|
||||
end = [9.77, -3.19]
|
||||
@ -577,7 +577,7 @@ sketch001 = startSketchOn(XZ)
|
||||
sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([4.61, -10.01], %)
|
||||
|> line(end = [12.73, -0.09])
|
||||
|> tangentialArcTo([24.95, -0.38], %)
|
||||
|> tangentialArc(endAbsolute = [24.95, -0.38])
|
||||
|> close()
|
||||
|> extrude(length = 5)`
|
||||
)
|
||||
@ -646,7 +646,7 @@ sketch001 = startSketchOn(XZ)
|
||||
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
||||
prevContent = await page.locator('.cm-content').innerText()
|
||||
|
||||
// drag tangentialArcTo handle
|
||||
// drag tangentialArc handle
|
||||
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
|
||||
await page.dragAndDrop('#stream', '#stream', {
|
||||
sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 },
|
||||
@ -663,7 +663,7 @@ sketch001 = startSketchOn(XZ)
|
||||
`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([7.12, -12.68], %)
|
||||
|> line(end = [12.68, -1.09])
|
||||
|> tangentialArcTo([24.89, 0.68], %)
|
||||
|> tangentialArc(endAbsolute = [24.89, 0.68])
|
||||
|> close()
|
||||
|> extrude(length = 5)`,
|
||||
{ shouldNormalise: true }
|
||||
@ -685,7 +685,7 @@ sketch001 = startSketchOn(XZ)
|
||||
sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([4.61, -14.01], %)
|
||||
|> line(end = [12.73, -0.09])
|
||||
|> tangentialArcTo([24.95, -5.38], %)
|
||||
|> tangentialArc(endAbsolute = [24.95, -5.38])
|
||||
|> close()
|
||||
|> revolve(axis = X)`
|
||||
)
|
||||
@ -757,7 +757,7 @@ sketch001 = startSketchOn(XZ)
|
||||
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
||||
prevContent = await page.locator('.cm-content').innerText()
|
||||
|
||||
// drag tangentialArcTo handle
|
||||
// drag tangentialArc handle
|
||||
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
|
||||
await page.mouse.move(tangentEnd.x, tangentEnd.y - 5)
|
||||
await page.mouse.down()
|
||||
@ -771,7 +771,7 @@ sketch001 = startSketchOn(XZ)
|
||||
`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([6.44, -12.07], %)
|
||||
|> line(end = [14.72, 1.97])
|
||||
|> tangentialArcTo([24.95, -5.38], %)
|
||||
|> tangentialArc(endAbsolute = [24.95, -5.38])
|
||||
|> line(end = [1.97, 2.06])
|
||||
|> close()
|
||||
|> revolve(axis = X)`,
|
||||
@ -1653,7 +1653,7 @@ profile003 = startProfileAt([206.63, -56.73], sketch001)
|
||||
await page.waitForTimeout(600)
|
||||
})
|
||||
|
||||
const codeFromTangentialArc = ` |> tangentialArcTo([39.49, 88.22], %)`
|
||||
const codeFromTangentialArc = ` |> tangentialArc(endAbsolute = [39.49, 88.22])`
|
||||
await test.step('check that tangential tool does not snap to other profile starts', async () => {
|
||||
await toolbar.tangentialArcBtn.click()
|
||||
await page.waitForTimeout(1000)
|
||||
@ -1675,7 +1675,7 @@ profile003 = startProfileAt([206.63, -56.73], sketch001)
|
||||
// check pixel is now gray at tanArcLocation to verify code has executed
|
||||
await scene.expectPixelColor([26, 26, 26], tanArcLocation, 15)
|
||||
await editor.expectEditor.not.toContain(
|
||||
`tangentialArcTo([39.49, 88.22], %)`
|
||||
`tangentialArc(endAbsolute = [39.49, 88.22])`
|
||||
)
|
||||
})
|
||||
|
||||
@ -1876,7 +1876,7 @@ profile003 = startProfileAt([206.63, -56.73], sketch001)
|
||||
|
||||
await endArcStartLine()
|
||||
await editor.expectEditor.toContain(
|
||||
`|> tangentialArcTo([16.61, 4.14], %)`
|
||||
`|> tangentialArc(endAbsolute = [16.61, 4.14])`
|
||||
)
|
||||
|
||||
// Add a three-point arc segment
|
||||
@ -2416,7 +2416,7 @@ sketch001 = startSketchOn(XZ)
|
||||
profile001 = startProfileAt([-63.43, 193.08], sketch001)
|
||||
|> line(end = [168.52, 149.87])
|
||||
|> line(end = [190.29, -39.18])
|
||||
|> tangentialArcTo([319.63, 129.65], %)
|
||||
|> tangentialArc(endAbsolute = [319.63, 129.65])
|
||||
|> line(end = [-217.65, -21.76])
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
@ -588,6 +588,7 @@ test(
|
||||
'Draft circle should look right',
|
||||
{ tag: '@snapshot' },
|
||||
async ({ page, context, cmdBar, scene }) => {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
const u = await getUtils(page)
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
const PUR = 400 / 37.5 //pixeltoUnitRatio
|
||||
@ -683,7 +684,7 @@ test.describe(
|
||||
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
|
||||
|
||||
code += `
|
||||
|> tangentialArcTo([551.2, -62.01], %)`
|
||||
|> tangentialArc(endAbsolute = [551.2, -62.01])`
|
||||
await expect(u.codeLocator).toHaveText(code)
|
||||
|
||||
// click tangential arc tool again to unequip it
|
||||
@ -777,7 +778,7 @@ test.describe(
|
||||
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
|
||||
|
||||
code += `
|
||||
|> tangentialArcTo([551.2, -62.01], %)`
|
||||
|> tangentialArc(endAbsolute = [551.2, -62.01])`
|
||||
await expect(u.codeLocator).toHaveText(code)
|
||||
|
||||
await page
|
||||
|
@ -98,7 +98,7 @@ part001 = startSketchOn(XZ)
|
||||
intersectTag: a,
|
||||
offset: 0
|
||||
}, %)
|
||||
|> tangentialArcTo([13.14 + 0, 13.14], %)
|
||||
|> tangentialArc(endAbsolute = [13.14 + 0, 13.14])
|
||||
|> close()
|
||||
|> extrude(length = 5 + 7)
|
||||
`
|
||||
|
15
e2e/playwright/stress-test.spec.ts
Normal file
15
e2e/playwright/stress-test.spec.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { createProject } from '@e2e/playwright/test-utils'
|
||||
import { test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
test.describe('Stress test', () => {
|
||||
test('Create project and load stress test', async ({
|
||||
cmdBar,
|
||||
scene,
|
||||
page,
|
||||
}, testInfo) => {
|
||||
const projectName = 'stress-test-project'
|
||||
// Create and load project
|
||||
await createProject({ name: projectName, page })
|
||||
await scene.settled(cmdBar)
|
||||
})
|
||||
})
|
@ -1140,7 +1140,7 @@ export function tomlToPerProjectSettings(
|
||||
return TOML.parse(toml)
|
||||
}
|
||||
|
||||
export function perProjectsettingsToToml(
|
||||
export function perProjectSettingsToToml(
|
||||
settings: DeepPartial<ProjectConfiguration>
|
||||
) {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
|
@ -229,7 +229,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)
|
||||
|> tangentialArcTo([5 + 3.14 + 13, 20 + 3.14], %)
|
||||
|> tangentialArc(endAbsolute = [5 + 3.14 + 13, 20 + 3.14])
|
||||
`
|
||||
)
|
||||
})
|
||||
@ -477,7 +477,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)
|
||||
|> tangentialArcTo([3.14 + 13, 3.14], %)
|
||||
|> tangentialArc(endAbsolute = [3.14 + 13, 3.14])
|
||||
`
|
||||
)
|
||||
localStorage.setItem('disableAxis', 'true')
|
||||
@ -602,7 +602,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)
|
||||
|> tangentialArcTo([3.14 + 13, 1.14], %)
|
||||
|> tangentialArc(endAbsolute = [3.14 + 13, 1.14])
|
||||
`
|
||||
)
|
||||
localStorage.setItem('disableAxis', 'true')
|
||||
@ -735,11 +735,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|
||||
locator: '[data-overlay-toolbar-index="11"]',
|
||||
})
|
||||
})
|
||||
test('for segment [tangentialArcTo]', async ({
|
||||
page,
|
||||
editor,
|
||||
homePage,
|
||||
}) => {
|
||||
test('for segment [tangentialArc]', async ({ page, editor, homePage }) => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
@ -762,7 +758,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)
|
||||
|> tangentialArcTo([3.14 + 13, -3.14], %)
|
||||
|> tangentialArc(endAbsolute = [3.14 + 13, -3.14])
|
||||
`
|
||||
)
|
||||
localStorage.setItem('disableAxis', 'true')
|
||||
@ -787,28 +783,29 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|
||||
const clickUnconstrained = _clickUnconstrained(page, editor)
|
||||
const clickConstrained = _clickConstrained(page, editor)
|
||||
|
||||
const tangentialArcTo = await u.getBoundingBox(
|
||||
'[data-overlay-index="12"]'
|
||||
)
|
||||
const tangentialArc = await u.getBoundingBox('[data-overlay-index="12"]')
|
||||
let ang = await u.getAngle('[data-overlay-index="12"]')
|
||||
console.log('tangentialArcTo')
|
||||
console.log('tangentialArc')
|
||||
await clickConstrained({
|
||||
hoverPos: { x: tangentialArcTo.x, y: tangentialArcTo.y },
|
||||
hoverPos: { x: tangentialArc.x, y: tangentialArc.y },
|
||||
constraintType: 'xAbsolute',
|
||||
expectBeforeUnconstrained: 'tangentialArcTo([3.14 + 13, -3.14], %)',
|
||||
expectAfterUnconstrained: 'tangentialArcTo([16.14, -3.14], %)',
|
||||
expectFinal: 'tangentialArcTo([xAbs001, -3.14], %)',
|
||||
expectBeforeUnconstrained:
|
||||
'tangentialArc(endAbsolute = [3.14 + 13, -3.14])',
|
||||
expectAfterUnconstrained: 'tangentialArc(endAbsolute = [16.14, -3.14])',
|
||||
expectFinal: 'tangentialArc(endAbsolute = [xAbs001, -3.14])',
|
||||
ang: ang + 180,
|
||||
steps: 6,
|
||||
locator: '[data-overlay-toolbar-index="12"]',
|
||||
})
|
||||
console.log('tangentialArcTo2')
|
||||
console.log('tangentialArc2')
|
||||
await clickUnconstrained({
|
||||
hoverPos: { x: tangentialArcTo.x, y: tangentialArcTo.y },
|
||||
hoverPos: { x: tangentialArc.x, y: tangentialArc.y },
|
||||
constraintType: 'yAbsolute',
|
||||
expectBeforeUnconstrained: 'tangentialArcTo([xAbs001, -3.14], %)',
|
||||
expectAfterUnconstrained: 'tangentialArcTo([xAbs001, yAbs001], %)',
|
||||
expectFinal: 'tangentialArcTo([xAbs001, -3.14], %)',
|
||||
expectBeforeUnconstrained:
|
||||
'tangentialArc(endAbsolute = [xAbs001, -3.14])',
|
||||
expectAfterUnconstrained:
|
||||
'tangentialArc(endAbsolute = [xAbs001, yAbs001])',
|
||||
expectFinal: 'tangentialArc(endAbsolute = [xAbs001, -3.14])',
|
||||
ang: ang + 180,
|
||||
steps: 10,
|
||||
locator: '[data-overlay-toolbar-index="12"]',
|
||||
@ -1091,7 +1088,7 @@ part001 = startSketchOn(XZ)
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)
|
||||
|> tangentialArcTo([3.14 + 13, 1.14], %)
|
||||
|> tangentialArc(endAbsolute = [3.14 + 13, 1.14])
|
||||
|> arcTo({
|
||||
interior = [16.25, 5.12],
|
||||
end = [21.61, 4.15]
|
||||
@ -1161,8 +1158,8 @@ part001 = startSketchOn(XZ)
|
||||
ang = await u.getAngle('[data-overlay-index="12"]')
|
||||
await deleteSegmentSequence({
|
||||
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
|
||||
codeToBeDeleted: 'tangentialArcTo([3.14 + 13, 1.14], %)',
|
||||
stdLibFnName: 'tangentialArcTo',
|
||||
codeToBeDeleted: 'tangentialArc(endAbsolute = [3.14 + 13, 1.14])',
|
||||
stdLibFnName: 'tangentialArc',
|
||||
ang: ang + 180,
|
||||
steps: 6,
|
||||
locator: '[data-overlay-toolbar-index="12"]',
|
||||
|
@ -535,7 +535,7 @@ part001 = startSketchOn(XZ)
|
||||
intersectTag = a,
|
||||
offset = 0
|
||||
}, %)
|
||||
|> tangentialArcTo([13.14 + 0, 13.14], %)
|
||||
|> tangentialArc(endAbsolute = [13.14 + 0, 13.14])
|
||||
|> close()
|
||||
|> extrude(length = 5 + 7)
|
||||
`
|
||||
@ -574,7 +574,7 @@ part001 = startSketchOn(XZ)
|
||||
|
||||
const extrusionTopCap: Coords2d = [800, 240]
|
||||
const flatExtrusionFace: Coords2d = [960, 160]
|
||||
const tangentialArcTo: Coords2d = [840, 160]
|
||||
const tangentialArc: Coords2d = [840, 160]
|
||||
const close: Coords2d = [720, 200]
|
||||
const nothing: Coords2d = [600, 200]
|
||||
const closeEdge: Coords2d = [744, 233]
|
||||
@ -671,28 +671,28 @@ part001 = startSketchOn(XZ)
|
||||
)
|
||||
|
||||
await checkCodeAtHoverPosition(
|
||||
'tangentialArcTo',
|
||||
tangentialArcTo,
|
||||
'tangentialArcTo([13.14+0,13.14],%)extrude(length=5+7)',
|
||||
'tangentialArcTo([13.14 + 0, 13.14], %)'
|
||||
'tangentialArc',
|
||||
tangentialArc,
|
||||
'tangentialArc(endAbsolute=[13.14+0,13.14])extrude(length=5+7)',
|
||||
'tangentialArc(endAbsolute = [13.14 + 0, 13.14])'
|
||||
)
|
||||
await checkCodeAtHoverPosition(
|
||||
'tangentialArcEdge',
|
||||
tangentialArcEdge,
|
||||
`tangentialArcTo([13.14+0,13.14],%)`,
|
||||
'tangentialArcTo([13.14 + 0, 13.14], %)'
|
||||
`tangentialArc(endAbsolute=[13.14+0,13.14])`,
|
||||
'tangentialArc(endAbsolute = [13.14 + 0, 13.14])'
|
||||
)
|
||||
await checkCodeAtHoverPosition(
|
||||
'tangentialArcOppositeEdge',
|
||||
tangentialArcOppositeEdge,
|
||||
`tangentialArcTo([13.14+0,13.14],%)`,
|
||||
'tangentialArcTo([13.14 + 0, 13.14], %)'
|
||||
`tangentialArc(endAbsolute=[13.14+0,13.14])`,
|
||||
'tangentialArc(endAbsolute = [13.14 + 0, 13.14])'
|
||||
)
|
||||
await checkCodeAtHoverPosition(
|
||||
'tangentialArcAdjacentEdge',
|
||||
tangentialArcAdjacentEdge,
|
||||
`tangentialArcTo([13.14+0,13.14],%)`,
|
||||
'tangentialArcTo([13.14 + 0, 13.14], %)'
|
||||
`tangentialArc(endAbsolute=[13.14+0,13.14])`,
|
||||
'tangentialArc(endAbsolute = [13.14 + 0, 13.14])'
|
||||
)
|
||||
|
||||
await checkCodeAtHoverPosition(
|
||||
@ -940,7 +940,7 @@ part001 = startSketchOn(XZ)
|
||||
},
|
||||
{
|
||||
pos: [1107, 161],
|
||||
expectedCode: 'tangentialArcTo([167.95, -28.85], %)',
|
||||
expectedCode: 'tangentialArc(endAbsolute = [167.95, -28.85])',
|
||||
},
|
||||
] as const
|
||||
await page.addInitScript(
|
||||
|
77
flake.lock
generated
77
flake.lock
generated
@ -1,6 +1,56 @@
|
||||
{
|
||||
"nodes": {
|
||||
"naersk": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1743800763,
|
||||
"narHash": "sha256-YFKV+fxEpMgP5VsUcM6Il28lI0NlpM7+oB1XxbBAYCw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"rev": "ed0232117731a4c19d3ee93aa0c382a8fe754b01",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1744157173,
|
||||
"narHash": "sha256-bWSjxDwq7iVePrhmA7tY2dyMWHuNJo8knkO4y+q4ZkY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6a39c6e495eefabc935d8ddf66aa45d85b85fa3f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1744157173,
|
||||
"narHash": "sha256-bWSjxDwq7iVePrhmA7tY2dyMWHuNJo8knkO4y+q4ZkY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6a39c6e495eefabc935d8ddf66aa45d85b85fa3f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1736320768,
|
||||
"narHash": "sha256-nIYdTAiKIGnFNugbomgBJR+Xv5F1ZQU+HfaBqJKroC0=",
|
||||
@ -16,38 +66,23 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1728538411,
|
||||
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"naersk": "naersk",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1736476219,
|
||||
"narHash": "sha256-+qyv3QqdZCdZ3cSO/cbpEY6tntyYjfe1bB12mdpNFaY=",
|
||||
"lastModified": 1744338850,
|
||||
"narHash": "sha256-pwMIVmsb8fjjT92n5XFDqCsplcX70qVMMT7NulumPXs=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "de30cc5963da22e9742bbbbb9a3344570ed237b9",
|
||||
"rev": "5e64aecc018e6f775572609e7d7485fdba6985a7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
136
flake.nix
136
flake.nix
@ -1,84 +1,96 @@
|
||||
{
|
||||
description = "modeling-app development environment";
|
||||
description = "zoo.dev modeling-app";
|
||||
|
||||
# Flake inputs
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
rust-overlay.url = "github:oxalica/rust-overlay"; # A helper for Rust + Nix
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
naersk.url = "github:nix-community/naersk";
|
||||
};
|
||||
|
||||
# Flake outputs
|
||||
outputs = { self, nixpkgs, rust-overlay }:
|
||||
let
|
||||
# Overlays enable you to customize the Nixpkgs attribute set
|
||||
overlays = [
|
||||
# Makes a `rust-bin` attribute available in Nixpkgs
|
||||
(import rust-overlay)
|
||||
# Provides a `rustToolchain` attribute for Nixpkgs that we can use to
|
||||
# create a Rust environment
|
||||
(self: super: {
|
||||
rustToolchain = super. rust-bin.stable.latest.default.override {
|
||||
targets = [ "wasm32-unknown-unknown" ];
|
||||
extensions = [ "rustfmt" "llvm-tools-preview" "rust-src" ];
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
rust-overlay,
|
||||
naersk,
|
||||
}: let
|
||||
overlays = [
|
||||
(import rust-overlay)
|
||||
(self: super: {
|
||||
rustToolchain = super.rust-bin.stable.latest.default.override {
|
||||
targets = ["wasm32-unknown-unknown"];
|
||||
extensions = ["rustfmt" "llvm-tools-preview" "rust-src"];
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
allSystems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
|
||||
forAllSystems = f:
|
||||
nixpkgs.lib.genAttrs allSystems (system:
|
||||
f {
|
||||
pkgs = import nixpkgs {
|
||||
inherit overlays system;
|
||||
};
|
||||
})
|
||||
(self: super: {
|
||||
cargo-llvm-cov = super.cargo-llvm-cov.overrideAttrs(oa: {
|
||||
doCheck = false; doInstallCheck = false;
|
||||
});
|
||||
})
|
||||
];
|
||||
|
||||
# Systems supported
|
||||
allSystems = [
|
||||
"x86_64-linux" # 64-bit Intel/AMD Linux
|
||||
"aarch64-linux" # 64-bit ARM Linux
|
||||
"x86_64-darwin" # 64-bit Intel macOS
|
||||
"aarch64-darwin" # 64-bit ARM macOS
|
||||
];
|
||||
|
||||
# Helper to provide system-specific attributes
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs allSystems (system: f {
|
||||
pkgs = import nixpkgs { inherit overlays system; config.allowBroken = true; };
|
||||
});
|
||||
|
||||
in
|
||||
{
|
||||
# Development environment output
|
||||
devShells = forAllSystems ({ pkgs }: {
|
||||
default = pkgs.mkShell {
|
||||
# The Nix packages provided in the environment
|
||||
packages = (with pkgs; [
|
||||
# The package provided by our custom overlay. Includes cargo, Clippy, cargo-fmt,
|
||||
# rustdoc, rustfmt, and other tools.
|
||||
system = system;
|
||||
});
|
||||
in {
|
||||
devShells = forAllSystems ({pkgs, ...}: {
|
||||
default = pkgs.mkShell {
|
||||
packages =
|
||||
(with pkgs; [
|
||||
rustToolchain
|
||||
|
||||
cargo-llvm-cov
|
||||
cargo-nextest
|
||||
|
||||
just
|
||||
postgresql.lib
|
||||
openssl
|
||||
pkg-config
|
||||
|
||||
nodejs_22
|
||||
yarn
|
||||
|
||||
electron
|
||||
playwright-driver.browsers
|
||||
]) ++ pkgs.lib.optionals pkgs.stdenv.isDarwin (with pkgs; [
|
||||
wasm-pack
|
||||
python3Full
|
||||
])
|
||||
++ pkgs.lib.optionals pkgs.stdenv.isDarwin (with pkgs; [
|
||||
libiconv
|
||||
darwin.apple_sdk.frameworks.Security
|
||||
]);
|
||||
|
||||
TARGET_CC = "${pkgs.stdenv.cc}/bin/${pkgs.stdenv.cc.targetPrefix}cc";
|
||||
LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
|
||||
ELECTRON_OVERRIDE_DIST_PATH = "${pkgs.electron}/bin/";
|
||||
PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS = true;
|
||||
PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH = "${pkgs.playwright-driver.browsers}/chromium-1091/chrome-linux/chrome";
|
||||
PLAYWRIGHT_BROWSERS_PATH = "${pkgs.playwright-driver.browsers}";
|
||||
NODE_ENV = "development";
|
||||
};
|
||||
});
|
||||
};
|
||||
TARGET_CC = "${pkgs.stdenv.cc}/bin/${pkgs.stdenv.cc.targetPrefix}cc";
|
||||
LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
|
||||
ELECTRON_OVERRIDE_DIST_PATH = "${pkgs.electron}/bin/";
|
||||
PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS = true;
|
||||
PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH = "${pkgs.playwright-driver.browsers}/chromium-1091/chrome-linux/chrome";
|
||||
PLAYWRIGHT_BROWSERS_PATH = "${pkgs.playwright-driver.browsers}";
|
||||
NODE_ENV = "development";
|
||||
};
|
||||
});
|
||||
|
||||
packages = forAllSystems ({
|
||||
pkgs,
|
||||
system,
|
||||
}: let
|
||||
naersk-lib = pkgs.callPackage naersk {
|
||||
cargo = pkgs.rustToolchain;
|
||||
rustc = pkgs.rustToolchain;
|
||||
};
|
||||
in {
|
||||
kcl-language-server = naersk-lib.buildPackage {
|
||||
pname = "kcl-language-server";
|
||||
version = "0.1.0";
|
||||
release = true;
|
||||
|
||||
src = ./rust;
|
||||
|
||||
cargoBuildOptions = opt: opt ++ ["-p" "kcl-language-server"];
|
||||
buildInputs = [pkgs.openssl pkgs.pkg-config];
|
||||
};
|
||||
default = self.packages.${system}.kcl-language-server;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -234,7 +234,7 @@
|
||||
"ts-node": "^10.0.0",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.29.0",
|
||||
"vite": "^5.4.17",
|
||||
"vite": "^5.4.18",
|
||||
"vite-plugin-package-version": "^1.1.0",
|
||||
"vite-plugin-top-level-await": "^1.5.0",
|
||||
"vite-tsconfig-paths": "^4.3.2",
|
||||
|
@ -834,9 +834,9 @@ vite-tsconfig-paths@^5.1.4:
|
||||
tsconfck "^3.0.3"
|
||||
|
||||
"vite@^5.0.0 || ^6.0.0":
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-6.2.5.tgz#d093b5fe8eb96e594761584a966ab13f24457820"
|
||||
integrity sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA==
|
||||
version "6.2.6"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-6.2.6.tgz#7f0ccf2fdc0c1eda079ce258508728e2473d3f61"
|
||||
integrity sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==
|
||||
dependencies:
|
||||
esbuild "^0.25.0"
|
||||
postcss "^8.5.3"
|
||||
|
@ -389,6 +389,13 @@ export class LanguageServerPlugin implements PluginValue {
|
||||
}
|
||||
|
||||
if (insertText && insertTextFormat === 2) {
|
||||
// We end with ${} so you can jump to the end of the snippet.
|
||||
// After the last argument.
|
||||
// This is not standard from the lsp so we add it here.
|
||||
if (insertText.endsWith(')')) {
|
||||
// We have a function its safe to insert the ${} at the end.
|
||||
insertText = insertText + '${}'
|
||||
}
|
||||
return snippetCompletion(insertText, completion)
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ export default defineConfig({
|
||||
[process.env.CI ? 'dot' : 'list'],
|
||||
['json', { outputFile: './test-results/report.json' }],
|
||||
['html'],
|
||||
['./e2e/playwright/lib/api-reporter.ts'],
|
||||
],
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
|
@ -45,6 +45,7 @@ export default defineConfig({
|
||||
['dot'],
|
||||
['json', { outputFile: './test-results/report.json' }],
|
||||
['html'],
|
||||
['./e2e/playwright/lib/api-reporter.ts'],
|
||||
],
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
|
@ -10,25 +10,25 @@ fn dividerSketch(plane) {
|
||||
sketch000 = startSketchOn(plane)
|
||||
|> startProfileAt([-16.82, 21.2], %)
|
||||
|> line(end = [-0.13, -1.27])
|
||||
|> tangentialArcTo([-15.94, profileStartY(%) - 7.73], %)
|
||||
|> tangentialArcTo([-16.6, profileStartY(%) - 15.52], %)
|
||||
|> tangentialArcTo([-18.38, profileStartY(%) - 18.63], %)
|
||||
|> tangentialArc(endAbsolute = [-15.94, profileStartY(%) - 7.73])
|
||||
|> tangentialArc(endAbsolute = [-16.6, profileStartY(%) - 15.52])
|
||||
|> tangentialArc(endAbsolute = [-18.38, profileStartY(%) - 18.63])
|
||||
|> line(end = [-1.25, -2.6])
|
||||
|> xLine(length = 6.04)
|
||||
|> line(end = [6.68, 7.87])
|
||||
|> tangentialArcTo([10.06, profileStartY(%) - 12.69], %)
|
||||
|> tangentialArc(endAbsolute = [10.06, profileStartY(%) - 12.69])
|
||||
|> line(end = [7.28, -8.47])
|
||||
|> xLine(length = 5.98)
|
||||
|> line(end = [-1.3, 3.01])
|
||||
|> tangentialArcTo([22.45, profileStartY(%) - 2.84], %)
|
||||
|> tangentialArcTo([25.08, profileStartY(%) + 6.42], %)
|
||||
|> tangentialArc(endAbsolute = [22.45, profileStartY(%) - 2.84])
|
||||
|> tangentialArc(endAbsolute = [25.08, profileStartY(%) + 6.42])
|
||||
|> line(end = [2.35, 16.36])
|
||||
|> line(end = [1.78, 1.15])
|
||||
|> tangentialArcTo([23.93, profileStartY(%) + 27.29], %)
|
||||
|> tangentialArc(endAbsolute = [23.93, profileStartY(%) + 27.29])
|
||||
|> line(end = [-1.92, 0.21])
|
||||
|> line(end = [-3.74, -26.54])
|
||||
|> tangentialArcTo([15.13, profileStartY(%) - 1.72], %)
|
||||
|> tangentialArcTo(profileStart(%), %)
|
||||
|> tangentialArc(endAbsolute = [15.13, profileStartY(%) - 1.72])
|
||||
|> tangentialArc(endAbsolute = profileStart(%))
|
||||
|> close()
|
||||
return sketch000
|
||||
}
|
||||
|
@ -17,66 +17,42 @@ brakeCaliperSketch = startSketchOn(XY)
|
||||
0,
|
||||
rotorTotalThickness + caliperTolerance - caliperInnerEdgeRadius
|
||||
])
|
||||
|> tangentialArc({
|
||||
offset = 90,
|
||||
radius = caliperInnerEdgeRadius
|
||||
}, %)
|
||||
|> tangentialArc(angle = 90, radius = caliperInnerEdgeRadius)
|
||||
|> line(end = [
|
||||
-caliperPadLength + 2 * caliperInnerEdgeRadius,
|
||||
0
|
||||
])
|
||||
|> tangentialArc({
|
||||
offset = -90,
|
||||
radius = caliperInnerEdgeRadius
|
||||
}, %)
|
||||
|> tangentialArc(angle = -90, radius = caliperInnerEdgeRadius)
|
||||
|> line(end = [
|
||||
0,
|
||||
caliperThickness - (caliperInnerEdgeRadius * 2)
|
||||
])
|
||||
|> tangentialArc({
|
||||
offset = -90,
|
||||
radius = caliperInnerEdgeRadius
|
||||
}, %)
|
||||
|> tangentialArc(angle = -90, radius = caliperInnerEdgeRadius)
|
||||
|> line(end = [
|
||||
caliperPadLength + caliperThickness - caliperOuterEdgeRadius - caliperInnerEdgeRadius,
|
||||
0
|
||||
])
|
||||
|> tangentialArc({
|
||||
offset = -90,
|
||||
radius = caliperOuterEdgeRadius
|
||||
}, %)
|
||||
|> tangentialArc(angle = -90, radius = caliperOuterEdgeRadius)
|
||||
|> line(end = [
|
||||
0,
|
||||
-2 * caliperTolerance - (2 * caliperThickness) - rotorTotalThickness + 2 * caliperOuterEdgeRadius
|
||||
])
|
||||
|> tangentialArc({
|
||||
offset = -90,
|
||||
radius = caliperOuterEdgeRadius
|
||||
}, %)
|
||||
|> tangentialArc(angle = -90, radius = caliperOuterEdgeRadius)
|
||||
|> line(end = [
|
||||
-caliperPadLength - caliperThickness + caliperOuterEdgeRadius + caliperInnerEdgeRadius,
|
||||
0
|
||||
])
|
||||
|> tangentialArc({
|
||||
offset = -90,
|
||||
radius = caliperInnerEdgeRadius
|
||||
}, %)
|
||||
|> tangentialArc(angle = -90, radius = caliperInnerEdgeRadius)
|
||||
|> line(end = [
|
||||
0,
|
||||
caliperThickness - (2 * caliperInnerEdgeRadius)
|
||||
])
|
||||
|> tangentialArc({
|
||||
offset = -90,
|
||||
radius = caliperInnerEdgeRadius
|
||||
}, %)
|
||||
|> tangentialArc(angle = -90, radius = caliperInnerEdgeRadius)
|
||||
|> line(end = [
|
||||
caliperPadLength - (2 * caliperInnerEdgeRadius),
|
||||
0
|
||||
])
|
||||
|> tangentialArc({
|
||||
offset = 90,
|
||||
radius = caliperInnerEdgeRadius
|
||||
}, %)
|
||||
|> tangentialArc(angle = 90, radius = caliperInnerEdgeRadius)
|
||||
|> close()
|
||||
|
||||
// Revolve the brake caliper sketch
|
||||
|
@ -17,7 +17,7 @@ tireSketch = startSketchOn(XY)
|
||||
],
|
||||
tag = $edge1,
|
||||
)
|
||||
|> tangentialArc({ offset = -90, radius = bendRadius }, %)
|
||||
|> tangentialArc(angle = -90, radius = bendRadius)
|
||||
|> line(endAbsolute = [
|
||||
tireOuterDiameter / 2,
|
||||
tireDepth / 2 - tireTreadOffset
|
||||
@ -36,7 +36,7 @@ tireSketch = startSketchOn(XY)
|
||||
tireOuterDiameter / 2,
|
||||
-tireDepth / 2 + bendRadius
|
||||
])
|
||||
|> tangentialArc({ offset = -90, radius = bendRadius }, %)
|
||||
|> tangentialArc(angle = -90, radius = bendRadius)
|
||||
|> line(endAbsolute = [tireInnerDiameter / 2, -tireDepth / 2], tag = $edge2)
|
||||
|> close()
|
||||
|
||||
|
@ -26,7 +26,7 @@ fn lug(plane, length, diameter) {
|
||||
|> angledLine(angle = 70, lengthY = lugHeadLength)
|
||||
|> xLine(endAbsolute = lugDiameter / 2)
|
||||
|> yLine(endAbsolute = lugLength)
|
||||
|> tangentialArc({ offset = 90, radius = fromMm(3) }, %)
|
||||
|> tangentialArc(angle = 90, radius = fromMm(3))
|
||||
|> xLine(endAbsolute = 0 + .001, tag = $c1)
|
||||
|> yLine(endAbsolute = lugThreadDepth)
|
||||
|> xLine(endAbsolute = lugThreadDiameter)
|
||||
|
@ -19,17 +19,11 @@ fn cycloidalGear(gearPitch, gearHeight, holeDiameter, helixAngle) {
|
||||
angleEnd = -90 + helixAngleP,
|
||||
radius = gearPitch
|
||||
}, %)
|
||||
|> tangentialArc({
|
||||
radius = gearPitch * 1.67,
|
||||
offset = 60
|
||||
}, %)
|
||||
|> tangentialArc({ radius = gearPitch, offset = -180 }, %)
|
||||
|> tangentialArc({
|
||||
radius = gearPitch * 1.67,
|
||||
offset = 60
|
||||
}, %)
|
||||
|> tangentialArc({ radius = gearPitch, offset = -180 }, %)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(radius = gearPitch * 1.67, angle = 60)
|
||||
|> tangentialArc(radius = gearPitch, angle = -180)
|
||||
|> tangentialArc(radius = gearPitch * 1.67, angle = 60)
|
||||
|> tangentialArc(radius = gearPitch, angle = -180)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close(%)
|
||||
|> hole(circle(center = [0, 0], radius = holeDiameter / 2), %)
|
||||
return gearProfile
|
||||
|
@ -184,15 +184,15 @@ handlePlane = startSketchOn(offsetPlane(XY, offset = handleHeightAboveTheFloor))
|
||||
|
||||
handleProfilePath = startProfileAt([0 + handleOffset, 0], handlePlane)
|
||||
|> yLine(length = -handleLengthSegmentA)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
handleFillet + handleOffset,
|
||||
-handleDepth
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = handleLengthSegmentB)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
handleOffset + handleWidth,
|
||||
-handleLengthSegmentA
|
||||
], %)
|
||||
])
|
||||
|> yLine(length = handleLengthSegmentA)
|
||||
handleSectionPlane = startSketchOn(XZ)
|
||||
handleProfileSection = circle(
|
||||
|
@ -33,9 +33,9 @@ fn primaryTube(n, angle001, length001, length002, length003) {
|
||||
sweepPath = startSketchOn(sweepPlane)
|
||||
|> startProfileAt([0, plateHeight], %)
|
||||
|> line(end = [0, length001])
|
||||
|> tangentialArc({ offset = -80, radius = bendRadius }, %, $arc01)
|
||||
|> tangentialArc(angle = -80, radius = bendRadius, tag = $arc01)
|
||||
|> angledLine(angle = tangentToEnd(arc01), length = length002)
|
||||
|> tangentialArc({ offset = 85, radius = bendRadius }, %, $arc02)
|
||||
|> tangentialArc(angle = 85, radius = bendRadius, tag = $arc02)
|
||||
|> angledLine(angle = tangentToEnd(arc02), length = length003)
|
||||
|
||||
// Create the cross section of each tube and sweep them
|
||||
@ -57,21 +57,21 @@ primaryTube(3, 25.2, 5, 5, 3)
|
||||
flangeSketch = startSketchOn(XY)
|
||||
|> startProfileAt([3 + 1.3, -1.25], %)
|
||||
|> xLine(length = -2.6, tag = $seg01)
|
||||
|> tangentialArc({ radius = .3, offset = -40 }, %)
|
||||
|> tangentialArc({ radius = .9, offset = 80 }, %)
|
||||
|> tangentialArc({ radius = .3, offset = -40 }, %)
|
||||
|> tangentialArc(radius = .3, angle = -40)
|
||||
|> tangentialArc(radius = .9, angle = 80)
|
||||
|> tangentialArc(radius = .3, angle = -40)
|
||||
|> xLine(length = -1.4, tag = $seg03)
|
||||
|> yLine(length = segLen(seg01), tag = $seg04)
|
||||
|> xLine(length = 3.1, tag = $seg05)
|
||||
|> tangentialArc({ radius = .3, offset = -40 }, %)
|
||||
|> tangentialArc({ radius = 1.5, offset = 80 }, %)
|
||||
|> tangentialArc({ radius = .3, offset = -40 }, %)
|
||||
|> tangentialArc(radius = .3, angle = -40)
|
||||
|> tangentialArc(radius = 1.5, angle = 80)
|
||||
|> tangentialArc(radius = .3, angle = -40)
|
||||
|> xLine(length = segLen(seg05), tag = $seg07)
|
||||
|> yLine(endAbsolute = profileStartY(%), tag = $seg08)
|
||||
|> xLine(length = -segLen(seg03), tag = $seg09)
|
||||
|> tangentialArc({ radius = .3, offset = -40 }, %)
|
||||
|> tangentialArc({ radius = .9, offset = 80 }, %)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(radius = .3, angle = -40)
|
||||
|> tangentialArc(radius = .9, angle = 80)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
// Create openings in the flange to accommodate each tube
|
||||
|
@ -36,9 +36,9 @@ fn slot(sketch1, start, end, width) {
|
||||
ystart = width / 2 * sin(toRadians(angle - 90)) + start[1]
|
||||
slotSketch = startProfileAt([xstart, ystart], sketch1)
|
||||
|> angledLine(angle = angle, length = dist)
|
||||
|> tangentialArc({ radius = width / 2, offset = 180 }, %)
|
||||
|> tangentialArc(radius = width / 2, angle = 180)
|
||||
|> angledLine(angle = angle, length = -dist)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
return slotSketch
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ sketch006 = startSketchOn(XZ)
|
||||
|> yLine(length = 10)
|
||||
|> line(end = [0.6, 0])
|
||||
|> yLine(length = -.05)
|
||||
|> tangentialArc({ radius = 0.6, offset = -90 }, %)
|
||||
|> tangentialArc(radius = 0.6, angle = -90)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> revolve(axis = Y)
|
||||
@ -192,15 +192,15 @@ sketch011 = startSketchOn(XZ)
|
||||
sketch012 = startSketchOn(offsetPlane(XZ, offset = handleThickness / 2))
|
||||
|> startProfileAt([2.3, 6.4], %)
|
||||
|> line(end = [0.56, 0])
|
||||
|> tangentialArcTo([4.1, 5.26], %)
|
||||
|> tangentialArcTo([4.17, 1.6], %)
|
||||
|> tangentialArcTo([3.13, 0.61], %)
|
||||
|> tangentialArc(endAbsolute = [4.1, 5.26])
|
||||
|> tangentialArc(endAbsolute = [4.17, 1.6])
|
||||
|> tangentialArc(endAbsolute = [3.13, 0.61])
|
||||
|> line(end = [-1.09, 0])
|
||||
|> line(end = [0, 0.43])
|
||||
|> line(end = [0.99, -0.02])
|
||||
|> tangentialArcTo([3.63, 1.6], %)
|
||||
|> tangentialArcTo([3.56, 5.15], %)
|
||||
|> tangentialArcTo([2.72, 5.88], %)
|
||||
|> tangentialArc(endAbsolute = [3.63, 1.6])
|
||||
|> tangentialArc(endAbsolute = [3.56, 5.15])
|
||||
|> tangentialArc(endAbsolute = [2.72, 5.88])
|
||||
|> line(end = [-0.4, 0])
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
@ -24,13 +24,13 @@ rackBody = startSketchOn(XY)
|
||||
fn tooth() {
|
||||
toothSketch = startSketchOn(XY)
|
||||
|> startProfileAt([-length / 2 + 0.567672, minHeight], %)
|
||||
|> tangentialArcToRelative([0.157636, 0.110378], %)
|
||||
|> tangentialArc(end = [0.157636, 0.110378])
|
||||
|> line(end = [0.329118, 0.904244])
|
||||
|> tangentialArcToRelative([0.157636, 0.110378], %)
|
||||
|> tangentialArc(end = [0.157636, 0.110378])
|
||||
|> line(end = [0.186505, 0])
|
||||
|> tangentialArcToRelative([0.157636, -0.110378], %)
|
||||
|> tangentialArc(end = [0.157636, -0.110378])
|
||||
|> line(end = [0.329118, -0.904244])
|
||||
|> tangentialArcToRelative([0.157636, -0.110378], %)
|
||||
|> tangentialArc(end = [0.157636, -0.110378])
|
||||
|> close()
|
||||
|> extrude(length = width)
|
||||
return toothSketch
|
||||
@ -44,7 +44,7 @@ teeth = tooth()
|
||||
endCapTooth = startSketchOn(XY)
|
||||
|> startProfileAt([-length / 2, 11.849525], %)
|
||||
|> line(end = [0.314524, -0.864147])
|
||||
|> tangentialArcToRelative([0.157636, -0.110378], %)
|
||||
|> tangentialArc(end = [0.157636, -0.110378])
|
||||
|> line(endAbsolute = [-length / 2, minHeight])
|
||||
|> close()
|
||||
|> extrude(length = width)
|
||||
@ -53,7 +53,7 @@ endCapTooth = startSketchOn(XY)
|
||||
endCapTooth2 = startSketchOn(XY)
|
||||
|> startProfileAt([length / 2, 11.849525], %)
|
||||
|> line(end = [-0.314524, -0.864147])
|
||||
|> tangentialArcToRelative([-0.157636, -0.110378], %)
|
||||
|> tangentialArc(end = [-0.157636, -0.110378])
|
||||
|> line(endAbsolute = [length / 2, minHeight])
|
||||
|> close()
|
||||
|> extrude(length = width)
|
||||
|
@ -18,7 +18,7 @@ iBeam = startSketchOn(-XZ)
|
||||
|> xLine(length = flangeWidth / 2)
|
||||
|> yLine(length = -flangeThickness)
|
||||
|> xLine(endAbsolute = webThickness / 2 + rootRadius)
|
||||
|> tangentialArc({ radius = rootRadius, offset = 90 }, %)
|
||||
|> tangentialArc(radius = rootRadius, angle = 90)
|
||||
|> yLine(endAbsolute = 0)
|
||||
|> mirror2d(axis = X)
|
||||
|> mirror2d(axis = Y)
|
||||
|
@ -74,11 +74,11 @@ fn keyFn(originStart, keyWidth, keyHeight, repeats, color) {
|
||||
radius = 0.1
|
||||
}, %)
|
||||
|> angledLine(angle = 0, length = keyWidth - .2, tag = $rectangleSegmentA001)
|
||||
|> tangentialArc({ radius = 0.1, offset = 90 }, %)
|
||||
|> tangentialArc(radius = 0.1, angle = 90)
|
||||
|> angledLine(angle = segAng(rectangleSegmentA001) + 90, length = keyHeight - .2, tag = $rectangleSegmentB001)
|
||||
|> tangentialArc({ radius = 0.1, offset = 90 }, %)
|
||||
|> tangentialArc(radius = 0.1, angle = 90)
|
||||
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001)
|
||||
|> tangentialArc({ radius = 0.1, offset = 90 }, %)
|
||||
|> tangentialArc(radius = 0.1, angle = 90)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $rectangleSegmentD001)
|
||||
|> close()
|
||||
|> extrude(length = keyDepth)
|
||||
|
@ -69,7 +69,7 @@ customPlane = {
|
||||
}
|
||||
sketch003 = startSketchOn(customPlane)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> tangentialArc({ offset = 60, radius = height }, %)
|
||||
|> tangentialArc(angle = 60, radius = height)
|
||||
|> angledLine(angle = 60, endAbsoluteY = 0)
|
||||
|> close()
|
||||
|> extrude(length = wallThickness)
|
||||
@ -85,11 +85,11 @@ sketch004 = startSketchOn(sketch002, 'END')
|
||||
|> angledLine(angle = 60, endAbsoluteY = segEndY(seg01))
|
||||
|> yLine(endAbsolute = height)
|
||||
|> xLine(length = wallThickness)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
(frontLength - wallsWidth) / 2 + wallsWidth,
|
||||
height - ((height - exitHeight) / 2)
|
||||
], %)
|
||||
|> tangentialArcTo([frontLength, exitHeight], %)
|
||||
])
|
||||
|> tangentialArc(endAbsolute = [frontLength, exitHeight])
|
||||
|> yLine(endAbsolute = 0)
|
||||
|> close(tag = $seg04)
|
||||
|> extrude(length = wallThickness)
|
||||
@ -110,11 +110,11 @@ sketch005 = startSketchOn(customPlane2)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> yLine(endAbsolute = height)
|
||||
|> xLine(endAbsolute = wallsWidth)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
(frontLength - wallsWidth) / 2 + wallsWidth,
|
||||
height - ((height - exitHeight) / 2)
|
||||
], %)
|
||||
|> tangentialArcTo([frontLength, exitHeight], %)
|
||||
])
|
||||
|> tangentialArc(endAbsolute = [frontLength, exitHeight])
|
||||
|> yLine(endAbsolute = 0, tag = $seg03)
|
||||
|> close()
|
||||
|> extrude(length = wallThickness)
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 57 KiB |
@ -37,49 +37,25 @@ bracketProfile = startSketchOn(XZ)
|
||||
0
|
||||
], %)
|
||||
|> xLine(length = flangeLength)
|
||||
|> tangentialArc({
|
||||
radius = exteriorBendRadius,
|
||||
offset = bendAngle
|
||||
}, %)
|
||||
|> tangentialArc(radius = exteriorBendRadius, angle = bendAngle)
|
||||
|> angledLine(angle = bendAngle, endAbsoluteY = hatHeight - thickness, tag = $seg01)
|
||||
|> tangentialArc({
|
||||
radius = interiorBendRadius,
|
||||
offset = -bendAngle
|
||||
}, %)
|
||||
|> tangentialArc(radius = interiorBendRadius, angle = -bendAngle)
|
||||
|> xLine(endAbsolute = 0, tag = $seg02)
|
||||
|> xLine(length = segLen(seg02))
|
||||
|> tangentialArc({
|
||||
radius = interiorBendRadius,
|
||||
offset = -bendAngle
|
||||
}, %)
|
||||
|> tangentialArc(radius = interiorBendRadius, angle = -bendAngle)
|
||||
|> angledLine(angle = -bendAngle, length = segLen(seg01))
|
||||
|> tangentialArc({
|
||||
radius = exteriorBendRadius,
|
||||
offset = bendAngle
|
||||
}, %)
|
||||
|> tangentialArc(radius = exteriorBendRadius, angle = bendAngle)
|
||||
|> xLine(length = flangeLength)
|
||||
|> yLine(length = thickness, tag = $seg03)
|
||||
|> xLine(length = -flangeLength, tag = $seg04)
|
||||
|> tangentialArc({
|
||||
radius = interiorBendRadius,
|
||||
offset = -bendAngle
|
||||
}, %)
|
||||
|> tangentialArc(radius = interiorBendRadius, angle = -bendAngle)
|
||||
|> angledLine(angle = 180 - bendAngle, length = segLen(seg01))
|
||||
|> tangentialArc({
|
||||
radius = exteriorBendRadius,
|
||||
offset = bendAngle
|
||||
}, %)
|
||||
|> tangentialArc(radius = exteriorBendRadius, angle = bendAngle)
|
||||
|> xLine(endAbsolute = 0, tag = $seg05)
|
||||
|> xLine(length = -segLen(seg05))
|
||||
|> tangentialArc({
|
||||
radius = exteriorBendRadius,
|
||||
offset = bendAngle
|
||||
}, %)
|
||||
|> tangentialArc(radius = exteriorBendRadius, angle = bendAngle)
|
||||
|> angledLine(angle = bendAngle - 180, length = segLen(seg01))
|
||||
|> tangentialArc({
|
||||
radius = interiorBendRadius,
|
||||
offset = -bendAngle
|
||||
}, %)
|
||||
|> tangentialArc(radius = interiorBendRadius, angle = -bendAngle)
|
||||
|> xLine(length = -flangeLength, tag = $seg06)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg07)
|
||||
|> close()
|
||||
|
48
rust/Cargo.lock
generated
48
rust/Cargo.lock
generated
@ -1780,7 +1780,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-bumper"
|
||||
version = "0.1.58"
|
||||
version = "0.1.60"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1791,7 +1791,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-derive-docs"
|
||||
version = "0.1.58"
|
||||
version = "0.1.60"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"anyhow",
|
||||
@ -1810,7 +1810,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-directory-test-macro"
|
||||
version = "0.1.58"
|
||||
version = "0.1.60"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1819,7 +1819,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-language-server"
|
||||
version = "0.2.58"
|
||||
version = "0.2.60"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1840,7 +1840,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-language-server-release"
|
||||
version = "0.1.58"
|
||||
version = "0.1.60"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1860,7 +1860,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.2.58"
|
||||
version = "0.2.60"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx 0.5.1",
|
||||
@ -1928,7 +1928,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-python-bindings"
|
||||
version = "0.3.58"
|
||||
version = "0.3.60"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"kcl-lib",
|
||||
@ -1943,7 +1943,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-test-server"
|
||||
version = "0.1.58"
|
||||
version = "0.1.60"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"hyper 0.14.32",
|
||||
@ -1956,7 +1956,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-to-core"
|
||||
version = "0.1.58"
|
||||
version = "0.1.60"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1970,7 +1970,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-wasm-lib"
|
||||
version = "0.1.58"
|
||||
version = "0.1.60"
|
||||
dependencies = [
|
||||
"bson",
|
||||
"console_error_panic_hook",
|
||||
@ -2033,9 +2033,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-modeling-cmds"
|
||||
version = "0.2.110"
|
||||
version = "0.2.113"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdfd16800a12a2eaefff53958bd871875c246e669274269f7caefc25d19641ad"
|
||||
checksum = "fa1c927569925425a1b03711617c384a30cb7554394e8a6a01266910b22421de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -2762,9 +2762,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3"
|
||||
version = "0.24.0"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f1c6c3591120564d64db2261bec5f910ae454f01def849b9c22835a84695e86"
|
||||
checksum = "17da310086b068fbdcefbba30aeb3721d5bb9af8db4987d6735b2183ca567229"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"indoc",
|
||||
@ -2781,9 +2781,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-build-config"
|
||||
version = "0.24.0"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9b6c2b34cf71427ea37c7001aefbaeb85886a074795e35f161f5aecc7620a7a"
|
||||
checksum = "e27165889bd793000a098bb966adc4300c312497ea25cf7a690a9f0ac5aa5fc1"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"target-lexicon",
|
||||
@ -2791,9 +2791,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-ffi"
|
||||
version = "0.24.0"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5507651906a46432cdda02cd02dd0319f6064f1374c9147c45b978621d2c3a9c"
|
||||
checksum = "05280526e1dbf6b420062f3ef228b78c0c54ba94e157f5cb724a609d0f2faabc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pyo3-build-config",
|
||||
@ -2801,9 +2801,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-macros"
|
||||
version = "0.24.0"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0d394b5b4fd8d97d48336bb0dd2aebabad39f1d294edd6bcd2cccf2eefe6f42"
|
||||
checksum = "5c3ce5686aa4d3f63359a5100c62a127c9f15e8398e5fdeb5deef1fed5cd5f44"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"pyo3-macros-backend",
|
||||
@ -2813,9 +2813,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-macros-backend"
|
||||
version = "0.24.0"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd72da09cfa943b1080f621f024d2ef7e2773df7badd51aa30a2be1f8caa7c8e"
|
||||
checksum = "f4cf6faa0cbfb0ed08e89beb8103ae9724eb4750e3a78084ba4017cbe94f3855"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@ -3956,9 +3956,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.44.1"
|
||||
version = "1.44.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
|
||||
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
|
@ -36,10 +36,10 @@ dashmap = { version = "6.1.0" }
|
||||
http = "1"
|
||||
indexmap = "2.7.0"
|
||||
kittycad = { version = "0.3.36", default-features = false, features = ["js", "requests"] }
|
||||
kittycad-modeling-cmds = { version = "0.2.110", features = ["ts-rs", "websocket"] }
|
||||
kittycad-modeling-cmds = { version = "0.2.113", features = ["ts-rs", "websocket"] }
|
||||
lazy_static = "1.5.0"
|
||||
miette = "7.5.0"
|
||||
pyo3 = { version = "0.24.0" }
|
||||
pyo3 = { version = "0.24.1" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1" }
|
||||
slog = "2.7.0"
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
[package]
|
||||
name = "kcl-bumper"
|
||||
version = "0.1.58"
|
||||
version = "0.1.60"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/KittyCAD/modeling-api"
|
||||
rust-version = "1.76"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-derive-docs"
|
||||
description = "A tool for generating documentation from Rust derive macros"
|
||||
version = "0.1.58"
|
||||
version = "0.1.60"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-directory-test-macro"
|
||||
description = "A tool for generating tests from a directory of kcl files"
|
||||
version = "0.1.58"
|
||||
version = "0.1.60"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kcl-language-server-release"
|
||||
version = "0.1.58"
|
||||
version = "0.1.60"
|
||||
edition = "2021"
|
||||
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
publish = false
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "kcl-language-server"
|
||||
description = "A language server for KCL."
|
||||
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
version = "0.2.58"
|
||||
version = "0.2.60"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@ -32,7 +32,7 @@ tracing-subscriber = { workspace = true }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
signal-hook = "0.3.17"
|
||||
tokio = { version = "1.43.0", features = ["full"] }
|
||||
tokio = { version = "1.44.2", features = ["full"] }
|
||||
tower-lsp = { version = "0.20.0", features = ["proposed"] }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
|
@ -9,7 +9,10 @@ export async function createClient(
|
||||
serverOptions: lc.ServerOptions
|
||||
): Promise<lc.LanguageClient> {
|
||||
const clientOptions: lc.LanguageClientOptions = {
|
||||
documentSelector: [{ scheme: 'file', language: 'kcl' }],
|
||||
documentSelector: [
|
||||
{ scheme: 'file', language: 'kcl' },
|
||||
{ scheme: 'untitled', language: 'kcl' },
|
||||
],
|
||||
initializationOptions,
|
||||
traceOutputChannel,
|
||||
outputChannel,
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-lib"
|
||||
description = "KittyCAD Language implementation and tools"
|
||||
version = "0.2.58"
|
||||
version = "0.2.60"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
@ -103,7 +103,7 @@ tokio-tungstenite = { version = "0.24.0", features = [
|
||||
tower-lsp = { workspace = true, features = ["proposed", "default"] }
|
||||
|
||||
[features]
|
||||
default = ["engine"]
|
||||
default = ["cli", "engine"]
|
||||
cli = ["dep:clap", "kittycad/clap"]
|
||||
dhat-heap = ["dep:dhat"]
|
||||
# For the lsp server, when run with stdout for rpc we want to disable println.
|
||||
@ -126,7 +126,7 @@ insta = { version = "1.41.1", features = ["json", "filters", "redactions"] }
|
||||
kcl-directory-test-macro = { version = "0.1", path = "../kcl-directory-test-macro" }
|
||||
miette = { version = "7.5.0", features = ["fancy"] }
|
||||
pretty_assertions = "1.4.1"
|
||||
tokio = { version = "1.41.1", features = ["rt-multi-thread", "macros", "time"] }
|
||||
tokio = { version = "1.44.2", features = ["rt-multi-thread", "macros", "time"] }
|
||||
twenty-twenty = "0.8.0"
|
||||
|
||||
[lints]
|
||||
|
@ -10,41 +10,41 @@ let corner_radius = 5.0
|
||||
let brace_base = startSketchOn(XY)
|
||||
|> startProfileAt([corner_radius, 0], %)
|
||||
|> line(end = [width - corner_radius, 0.0])
|
||||
|> tangentialArcToRelative([corner_radius, corner_radius], %)
|
||||
|> tangentialArc(end = [corner_radius, corner_radius])
|
||||
|> yLine(length = 25.0 - corner_radius)
|
||||
|> tangentialArcToRelative([-corner_radius, corner_radius], %)
|
||||
|> tangentialArc(end = [-corner_radius, corner_radius])
|
||||
|> xLine(length = -(d_wrist_circumference[0] - (corner_radius * 2)))
|
||||
|> tangentialArcToRelative([-corner_radius, corner_radius], %)
|
||||
|> tangentialArc(end = [-corner_radius, corner_radius])
|
||||
|> yLine(length = length - 25.0 - 23.0 - (corner_radius * 2))
|
||||
|> tangentialArcToRelative([corner_radius, corner_radius], %)
|
||||
|> tangentialArc(end = [corner_radius, corner_radius])
|
||||
|> xLine(length = 15.0 - (corner_radius * 2))
|
||||
|> tangentialArcToRelative([corner_radius, corner_radius], %)
|
||||
|> tangentialArc(end = [corner_radius, corner_radius])
|
||||
|> yLine(length = 23.0 - corner_radius)
|
||||
|> tangentialArcToRelative([-corner_radius, corner_radius], %)
|
||||
|> tangentialArc(end = [-corner_radius, corner_radius])
|
||||
|> xLine(length = -(hand_thickness + 15.0 + 15.0 - (corner_radius * 2)))
|
||||
|> tangentialArcToRelative([-corner_radius, -corner_radius], %)
|
||||
|> tangentialArc(end = [-corner_radius, -corner_radius])
|
||||
|> yLine(length = -(23.0 - corner_radius))
|
||||
|> tangentialArcToRelative([corner_radius, -corner_radius], %)
|
||||
|> tangentialArc(end = [corner_radius, -corner_radius])
|
||||
|> xLine(length = 15.0 - (corner_radius * 2))
|
||||
|> tangentialArcToRelative([corner_radius, -corner_radius], %)
|
||||
|> tangentialArc(end = [corner_radius, -corner_radius])
|
||||
|> yLine(length = -(length - 25.0 - 23.0 - (corner_radius * 2)))
|
||||
|> tangentialArcToRelative([-corner_radius, -corner_radius], %)
|
||||
|> tangentialArc(end = [-corner_radius, -corner_radius])
|
||||
|> xLine(length = -(d_wrist_circumference[1] + d_wrist_circumference[2] + d_wrist_circumference[3] - hand_thickness - corner_radius))
|
||||
|> tangentialArcToRelative([-corner_radius, -corner_radius], %)
|
||||
|> tangentialArc(end = [-corner_radius, -corner_radius])
|
||||
|> yLine(length = -(25.0 - corner_radius))
|
||||
|> tangentialArcToRelative([corner_radius, -corner_radius], %)
|
||||
|> tangentialArc(end = [corner_radius, -corner_radius])
|
||||
|> close()
|
||||
|
||||
let inner = startSketchOn(XY)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> xLine(length = 1.0)
|
||||
|> tangentialArcToRelative([corner_radius, corner_radius], %)
|
||||
|> tangentialArc(end = [corner_radius, corner_radius])
|
||||
|> yLine(length = 25.0 - (corner_radius * 2))
|
||||
|> tangentialArcToRelative([-corner_radius, corner_radius], %)
|
||||
|> tangentialArc(end = [-corner_radius, corner_radius])
|
||||
|> xLine(length = -1.0)
|
||||
|> tangentialArcToRelative([-corner_radius, -corner_radius], %)
|
||||
|> tangentialArc(end = [-corner_radius, -corner_radius])
|
||||
|> yLine(length = -(25.0 - (corner_radius * 2)))
|
||||
|> tangentialArcToRelative([corner_radius, -corner_radius], %)
|
||||
|> tangentialArc(end = [corner_radius, -corner_radius])
|
||||
|> close()
|
||||
|
||||
let final = brace_base
|
||||
|
@ -11,17 +11,17 @@ const wallMountL = 8
|
||||
const bracket = startSketchOn(XY)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line(end = [0, wallMountL])
|
||||
|> tangentialArc({
|
||||
radius: filletR,
|
||||
offset: 90
|
||||
}, %)
|
||||
|> tangentialArc(
|
||||
radius = filletR,
|
||||
angle = 90,
|
||||
)
|
||||
|> line(end = [-shelfMountL, 0])
|
||||
|> line(end = [0, -thickness])
|
||||
|> line(end = [shelfMountL, 0])
|
||||
|> tangentialArc({
|
||||
radius: filletR - thickness,
|
||||
offset: -90
|
||||
}, %)
|
||||
|> tangentialArc(
|
||||
radius = filletR - thickness,
|
||||
angle = -90,
|
||||
)
|
||||
|> line(end = [0, -wallMountL])
|
||||
|> close()
|
||||
|> extrude(length = width)
|
||||
|
@ -763,9 +763,9 @@ const sketch010fl = startSketchOn(extrude001fl, 'START')
|
||||
originStart[2] + .81 - (.438 / 2)
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([-0.66 - originStart[0],originStart[2] + .81 + .438 / 2], %)
|
||||
|> tangentialArc(endAbsolute = [-0.66 - originStart[0],originStart[2] + .81 + .438 / 2])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, 1],
|
||||
@ -781,12 +781,12 @@ const sketch011fl = startSketchOn(extrude001fl, 'START')
|
||||
originStart[2] + railHeight * 1.75 / 2 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
-0.66 - originStart[0],originStart[2]+
|
||||
railHeight * 1.75 / 2 - (.438 / 2)
|
||||
], %)
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0],
|
||||
originStart[2] + railHeight * 1.75 / 2 - (.438 / 2)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
const extrude011fl = extrude(sketch011fl, length = -thickness)
|
||||
@ -798,12 +798,12 @@ const sketch012fl = startSketchOn(extrude001fl, 'START')
|
||||
railHeight * 1.75 - .81 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0], originStart[2]+
|
||||
railHeight * 1.75 - .81 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, -1],
|
||||
@ -1006,12 +1006,12 @@ const sketch010fr = startSketchOn(extrude001fr, 'START')
|
||||
originStart[2] + .81 - (.438 / 2)
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0],
|
||||
originStart[2] + .81 + .438 / 2
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, 1],
|
||||
@ -1027,12 +1027,12 @@ const sketch011fr = startSketchOn(extrude001fr, 'START')
|
||||
originStart[2] + railHeight * 1.75 / 2 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0],
|
||||
originStart[2] + railHeight * 1.75 / 2 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
const extrude011fr = extrude(sketch011fr, length = -thickness)
|
||||
@ -1044,12 +1044,12 @@ const sketch012fr = startSketchOn(extrude001fr, 'START')
|
||||
originStart[2] + railHeight * 1.75 - .81 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0],
|
||||
originStart[2] + railHeight * 1.75 - .81 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, -1],
|
||||
@ -1252,12 +1252,12 @@ const sketch010rr = startSketchOn(extrude001rr, 'START')
|
||||
originStart[2] + .81 - (.438 / 2)
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0]+1.5-serverDepth,
|
||||
originStart[2] + .81 + .438 / 2
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, 1],
|
||||
@ -1273,12 +1273,12 @@ const sketch011rr = startSketchOn(extrude001rr, 'START')
|
||||
originStart[2] + railHeight * 1.75 / 2 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0]+1.5-serverDepth,
|
||||
originStart[2] + railHeight * 1.75 / 2 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
const extrude011rr = extrude(sketch011rr, length = -thickness)
|
||||
@ -1290,12 +1290,12 @@ const sketch012rr = startSketchOn(extrude001rr, 'START')
|
||||
originStart[2] + railHeight * 1.75 - .81 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0]+1.5-serverDepth,
|
||||
originStart[2] + railHeight * 1.75 - .81 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, -1],
|
||||
@ -1497,12 +1497,12 @@ const sketch010rl = startSketchOn(extrude001rl, 'START')
|
||||
originStart[2] + .81 - (.438 / 2)
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0] - serverDepth + 1.5,
|
||||
originStart[2] + .81 + .438 / 2
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, 1],
|
||||
@ -1518,12 +1518,12 @@ const sketch011rl = startSketchOn(extrude001rl, 'START')
|
||||
originStart[2] + railHeight * 1.75 / 2 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0] - serverDepth + 1.5,
|
||||
originStart[2] + railHeight * 1.75 / 2 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
const extrude011rl = extrude(sketch011rl, length = -thickness)
|
||||
@ -1535,12 +1535,12 @@ const sketch012rl = startSketchOn(extrude001rl, 'START')
|
||||
originStart[2] + railHeight * 1.75 - .81 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0] - serverDepth + 1.5,
|
||||
originStart[2] + railHeight * 1.75 - .81 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, -1],
|
||||
@ -1593,15 +1593,15 @@ fn streamServer = (serverPos) => {
|
||||
|> xLine(length = 0.2)
|
||||
|> yLine(length = -0.36)
|
||||
|> xLine(length = 0.5)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
0.3,
|
||||
17.15 + 4.114 + 1 + serverPos * 1.75 - 11.114
|
||||
], %)
|
||||
])
|
||||
|> yLine(length = -1.77)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.13,
|
||||
14.89 + 4.114 + 1 + serverPos * 1.75 - 11.114
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.52)
|
||||
|> yLine(length = -0.42)
|
||||
|> line(end = [0.34, -0.15])
|
||||
@ -1617,15 +1617,15 @@ fn streamServer = (serverPos) => {
|
||||
|> xLine(length = 0.2)
|
||||
|> yLine(length = -0.36)
|
||||
|> xLine(length = 0.5)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
0.3,
|
||||
17.15 + 4.114 + 1 + serverPos * 1.75 - 11.114
|
||||
], %)
|
||||
])
|
||||
|> yLine(length = -1.77)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.13,
|
||||
14.89 + 4.114 + 1 + serverPos * 1.75 - 11.114
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.52)
|
||||
|> yLine(length = -0.42)
|
||||
|> line(end = [0.34, -0.15])
|
||||
|
@ -676,12 +676,12 @@ const sketch010fl = startSketchOn(extrude001fl, 'START')
|
||||
originStart[2] + .81 - (.438 / 2)
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0],
|
||||
originStart[2] + .81 + .438 / 2
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, 1],
|
||||
@ -697,12 +697,12 @@ const sketch011fl = startSketchOn(extrude001fl, 'START')
|
||||
originStart[2] + railHeight * 1.75 / 2 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0],
|
||||
originStart[2] + railHeight * 1.75 / 2 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
const extrude011fl = extrude(sketch011fl, length = -thickness)
|
||||
@ -714,12 +714,12 @@ const sketch012fl = startSketchOn(extrude001fl, 'START')
|
||||
originStart[2] + railHeight * 1.75 - .81 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0],
|
||||
originStart[2] + railHeight * 1.75 - .81 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, -1],
|
||||
@ -814,12 +814,12 @@ const sketch010fr = startSketchOn(extrude001fr, 'START')
|
||||
originStart[2] + .81 - (.438 / 2)
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0],
|
||||
originStart[2] + .81 + .438 / 2
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, 1],
|
||||
@ -835,12 +835,12 @@ const sketch011fr = startSketchOn(extrude001fr, 'START')
|
||||
originStart[2] + railHeight * 1.75 / 2 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0],
|
||||
originStart[2] + railHeight * 1.75 / 2 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
const extrude011fr = extrude(sketch011fr, length = -thickness)
|
||||
@ -852,12 +852,12 @@ const sketch012fr = startSketchOn(extrude001fr, 'START')
|
||||
originStart[2] + railHeight * 1.75 - .81 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0],
|
||||
originStart[2] + railHeight * 1.75 - .81 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, -1],
|
||||
@ -952,12 +952,12 @@ const sketch010rr = startSketchOn(extrude001rr, 'START')
|
||||
originStart[2] + .81 - (.438 / 2)
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0] + 1.5 - serverDepth,
|
||||
originStart[2] + .81 + .438 / 2
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, 1],
|
||||
@ -973,12 +973,12 @@ const sketch011rr = startSketchOn(extrude001rr, 'START')
|
||||
originStart[2] + railHeight * 1.75 / 2 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0] + 1.5 - serverDepth,
|
||||
originStart[2] + railHeight * 1.75 / 2 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
const extrude011rr = extrude(sketch011rr, length = -thickness)
|
||||
@ -990,12 +990,12 @@ const sketch012rr = startSketchOn(extrude001rr, 'START')
|
||||
originStart[2] + railHeight * 1.75 - .81 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0] + 1.5 - serverDepth,
|
||||
originStart[2] + railHeight * 1.75 - .81 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, -1],
|
||||
@ -1089,12 +1089,12 @@ const sketch010rl = startSketchOn(extrude001rl, 'START')
|
||||
originStart[2] + .81 - (.438 / 2)
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0] - serverDepth + 1.5,
|
||||
originStart[2] + .81 + .438 / 2
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, 1],
|
||||
@ -1110,12 +1110,12 @@ const sketch011rl = startSketchOn(extrude001rl, 'START')
|
||||
originStart[2] + railHeight * 1.75 / 2 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0] - serverDepth + 1.5,
|
||||
originStart[2] + railHeight * 1.75 / 2 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
const extrude011rl = extrude(sketch011rl, length = -thickness)
|
||||
@ -1127,12 +1127,12 @@ const sketch012rl = startSketchOn(extrude001rl, 'START')
|
||||
originStart[2] + railHeight * 1.75 - .81 + .438 / 2
|
||||
], %)
|
||||
|> xLine(length = 0.75 - .438)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.66 - originStart[0] - serverDepth + 1.5,
|
||||
originStart[2] + railHeight * 1.75 - .81 - (.438 / 2)
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.75 + .438)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(
|
||||
axis = [0, -1],
|
||||
@ -1184,15 +1184,15 @@ fn streamServer = (serverPos) => {
|
||||
|> xLine(length = 0.2)
|
||||
|> yLine(length = -0.36)
|
||||
|> xLine(length = 0.5)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
0.3,
|
||||
17.15 + 4.114 + 1 + serverPos * 1.75 - 11.114
|
||||
], %)
|
||||
])
|
||||
|> yLine(length = -1.77)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.13,
|
||||
14.89 + 4.114 + 1 + serverPos * 1.75 - 11.114
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.52)
|
||||
|> yLine(length = -0.42)
|
||||
|> line(end = [0.34, -0.15])
|
||||
@ -1208,15 +1208,15 @@ fn streamServer = (serverPos) => {
|
||||
|> xLine(length = 0.2)
|
||||
|> yLine(length = -0.36)
|
||||
|> xLine(length = 0.5)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
0.3,
|
||||
17.15 + 4.114 + 1 + serverPos * 1.75 - 11.114
|
||||
], %)
|
||||
])
|
||||
|> yLine(length = -1.77)
|
||||
|> tangentialArcTo([
|
||||
|> tangentialArc(endAbsolute = [
|
||||
-0.13,
|
||||
14.89 + 4.114 + 1 + serverPos * 1.75 - 11.114
|
||||
], %)
|
||||
])
|
||||
|> xLine(length = -0.52)
|
||||
|> yLine(length = -0.42)
|
||||
|> line(end = [0.34, -0.15])
|
||||
|
@ -10,16 +10,17 @@ startSketchOn(XY)
|
||||
angle = angleStart,
|
||||
length = .000001,
|
||||
)
|
||||
|> tangentialArc({
|
||||
offset: angleOffset,
|
||||
|> tangentialArc(
|
||||
angle = angleOffset,
|
||||
radius: r,
|
||||
}, %, $arc1)
|
||||
|> tangentialArc({
|
||||
offset: angleOffset,
|
||||
radius: 0.5*r,
|
||||
}, %, $arc2)
|
||||
|> tangentialArc({
|
||||
offset: -angleOffset,
|
||||
radius: 0.5*r,
|
||||
}, %, $arc3)
|
||||
tag = $arc1,
|
||||
)
|
||||
|> tangentialArc(
|
||||
angle = angleOffset,
|
||||
radius = 0.5*r,
|
||||
tag = $arc2)
|
||||
|> tangentialArc(
|
||||
angle = -angleOffset,
|
||||
radius = 0.5*r,
|
||||
tag = $arc3)
|
||||
|> xLine(endAbsolute = 1)
|
||||
|
@ -1,6 +1,6 @@
|
||||
const boxSketch = startSketchOn(XY)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line(end = [0, 10])
|
||||
|> tangentialArc({radius: 5, offset: 90}, %)
|
||||
|> tangentialArc(radius = 5, angle = 90)
|
||||
|> line(end = [5, -15])
|
||||
|> extrude(length = 10)
|
||||
|
@ -159,7 +159,7 @@ async fn kcl_test_basic_tangential_arc_with_point() {
|
||||
let code = r#"boxSketch = startSketchOn(XY)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line(end = [0, 10])
|
||||
|> tangentialArcToRelative([-5, 5], %)
|
||||
|> tangentialArc(end = [-5, 5])
|
||||
|> line(end = [5, -15])
|
||||
|> extrude(length = 10)
|
||||
"#;
|
||||
@ -173,7 +173,7 @@ async fn kcl_test_basic_tangential_arc_to() {
|
||||
let code = r#"boxSketch = startSketchOn(XY)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line(end = [0, 10])
|
||||
|> tangentialArcTo([-5, 15], %)
|
||||
|> tangentialArc(endAbsolute = [-5, 15])
|
||||
|> line(end = [5, -15])
|
||||
|> extrude(length = 10)
|
||||
"#;
|
||||
@ -224,14 +224,14 @@ wallMountL = 8
|
||||
bracket = startSketchOn(XY)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line(end = [0, wallMountL])
|
||||
|> tangentialArc({ radius= filletR, offset: 90 }, %)
|
||||
|> tangentialArc(radius = filletR, angle = 90 )
|
||||
|> line(end = [-shelfMountL, 0])
|
||||
|> line(end = [0, -thickness])
|
||||
|> line(end = [shelfMountL, 0])
|
||||
|> tangentialArc({
|
||||
radius= filletR - thickness,
|
||||
offset: -90
|
||||
}, %)
|
||||
|> tangentialArc(
|
||||
radius = filletR - thickness,
|
||||
angle = -90,
|
||||
)
|
||||
|> line(end = [0, -wallMountL])
|
||||
|> close()
|
||||
|> extrude(length = width)
|
||||
@ -306,7 +306,7 @@ thing = other_circle([2, 2], 20)
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_rounded_with_holes() {
|
||||
let code = r#"fn tarc = (to, sktch, tag?) => {
|
||||
return tangentialArcTo(to, sktch, tag)
|
||||
return tangentialArc(sktch, endAbsolute = to, tag = tag)
|
||||
}
|
||||
|
||||
fn roundedRectangle = (pos, w, l, cornerRadius) => {
|
||||
@ -705,7 +705,7 @@ async fn kcl_test_error_sketch_on_arc_face() {
|
||||
let code = r#"fn cube = (pos, scale) => {
|
||||
sg = startSketchOn(XY)
|
||||
|> startProfileAt(pos, %)
|
||||
|> tangentialArcToRelative([0, scale], %, $here)
|
||||
|> tangentialArc(end = [0, scale], tag = $here)
|
||||
|> line(end = [scale, 0])
|
||||
|> line(end = [0, -scale])
|
||||
|
||||
@ -1342,7 +1342,7 @@ async fn kcl_test_error_empty_start_sketch_on_string() {
|
||||
|> line(end = [190.03, -118.13])
|
||||
|> line(end = [-33.38, -202.86])
|
||||
|> line(end = [-315.86, -64.2])
|
||||
|> tangentialArcTo([-147.66, 121.34], %)
|
||||
|> tangentialArc(endAbsolute = [-147.66, 121.34])
|
||||
|> close()
|
||||
|> extrude(length = 100)
|
||||
|
||||
@ -1352,10 +1352,11 @@ secondSketch = startSketchOn(part001, '')
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, None).await;
|
||||
assert!(result.is_err());
|
||||
let err = result.unwrap_err();
|
||||
let err = err.as_kcl_error().unwrap();
|
||||
assert_eq!(
|
||||
result.err().unwrap().to_string(),
|
||||
r#"semantic: KclErrorDetails { source_ranges: [SourceRange([297, 299, 0])], message: "Argument at index 1 was supposed to be type Option<FaceTag> but found string (text)" }"#
|
||||
err.message(),
|
||||
"Argument at index 1 was supposed to be type Option<FaceTag> but found string (text)"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -444,12 +444,11 @@ impl FnData {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
pub(super) fn to_autocomplete_snippet(&self) -> String {
|
||||
if self.name == "loft" {
|
||||
return "loft([${0:sketch000}, ${1:sketch001}])${}".to_owned();
|
||||
return "loft([${0:sketch000}, ${1:sketch001}])".to_owned();
|
||||
} else if self.name == "hole" {
|
||||
return "hole(${0:holeSketch}, ${1:%})${}".to_owned();
|
||||
return "hole(${0:holeSketch}, ${1:%})".to_owned();
|
||||
}
|
||||
let mut args = Vec::new();
|
||||
let mut index = 0;
|
||||
@ -459,9 +458,7 @@ impl FnData {
|
||||
args.push(arg_str);
|
||||
}
|
||||
}
|
||||
// We end with ${} so you can jump to the end of the snippet.
|
||||
// After the last argument.
|
||||
format!("{}({})${{}}", self.preferred_name, args.join(", "))
|
||||
format!("{}({})", self.preferred_name, args.join(", "))
|
||||
}
|
||||
|
||||
fn to_signature_help(&self) -> SignatureHelp {
|
||||
|
@ -498,12 +498,17 @@ pub trait StdLibFn: std::fmt::Debug + Send + Sync {
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn to_autocomplete_snippet(&self) -> Result<String> {
|
||||
if self.name() == "loft" {
|
||||
return Ok("loft([${0:sketch000}, ${1:sketch001}])${}".to_string());
|
||||
return Ok("loft([${0:sketch000}, ${1:sketch001}])".to_string());
|
||||
} else if self.name() == "union" {
|
||||
return Ok("union([${0:extrude001}, ${1:extrude002}])".to_string());
|
||||
} else if self.name() == "subtract" {
|
||||
return Ok("subtract([${0:extrude001}], tools = [${1:extrude002}])".to_string());
|
||||
} else if self.name() == "intersect" {
|
||||
return Ok("intersect([${0:extrude001}, ${1:extrude002}])".to_string());
|
||||
} else if self.name() == "hole" {
|
||||
return Ok("hole(${0:holeSketch}, ${1:%})${}".to_string());
|
||||
return Ok("hole(${0:holeSketch}, ${1:%})".to_string());
|
||||
}
|
||||
let in_keyword_fn = self.keyword_arguments();
|
||||
let mut args = Vec::new();
|
||||
@ -514,9 +519,7 @@ pub trait StdLibFn: std::fmt::Debug + Send + Sync {
|
||||
args.push(arg_str);
|
||||
}
|
||||
}
|
||||
// We end with ${} so you can jump to the end of the snippet.
|
||||
// After the last argument.
|
||||
Ok(format!("{}({})${{}}", self.name(), args.join(", ")))
|
||||
Ok(format!("{}({})", self.name(), args.join(", ")))
|
||||
}
|
||||
|
||||
fn to_signature_help(&self) -> SignatureHelp {
|
||||
@ -890,29 +893,26 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_line() {
|
||||
let line_fn: Box<dyn StdLibFn> = Box::new(crate::std::sketch::Line);
|
||||
let snippet = line_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"line(${0:%}, end = [${1:3.14}, ${2:3.14}])${}"#);
|
||||
assert_eq!(snippet, r#"line(${0:%}, end = [${1:3.14}, ${2:3.14}])"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_extrude() {
|
||||
let extrude_fn: Box<dyn StdLibFn> = Box::new(crate::std::extrude::Extrude);
|
||||
let snippet = extrude_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"extrude(${0:%}, length = ${1:3.14})${}"#);
|
||||
assert_eq!(snippet, r#"extrude(${0:%}, length = ${1:3.14})"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_fillet() {
|
||||
let fillet_fn: Box<dyn StdLibFn> = Box::new(crate::std::fillet::Fillet);
|
||||
let snippet = fillet_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(
|
||||
snippet,
|
||||
r#"fillet(${0:%}, radius = ${1:3.14}, tags = [${2:"tag_or_edge_fn"}])${}"#
|
||||
r#"fillet(${0:%}, radius = ${1:3.14}, tags = [${2:"tag_or_edge_fn"}])"#
|
||||
);
|
||||
}
|
||||
|
||||
@ -920,18 +920,17 @@ mod tests {
|
||||
fn get_autocomplete_snippet_start_sketch_on() {
|
||||
let start_sketch_on_fn: Box<dyn StdLibFn> = Box::new(crate::std::sketch::StartSketchOn);
|
||||
let snippet = start_sketch_on_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"startSketchOn(${0:"XY"})${}"#);
|
||||
assert_eq!(snippet, r#"startSketchOn(${0:"XY"})"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_pattern_circular_3d() {
|
||||
// We test this one specifically because it has ints and floats and strings.
|
||||
let pattern_fn: Box<dyn StdLibFn> = Box::new(crate::std::patterns::PatternCircular3D);
|
||||
let snippet = pattern_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(
|
||||
snippet,
|
||||
r#"patternCircular3d(${0:%}, instances = ${1:10}, axis = [${2:3.14}, ${3:3.14}, ${4:3.14}], center = [${5:3.14}, ${6:3.14}, ${7:3.14}], arcDegrees = ${8:3.14}, rotateDuplicates = ${9:false})${}"#
|
||||
r#"patternCircular3d(${0:%}, instances = ${1:10}, axis = [${2:3.14}, ${3:3.14}, ${4:3.14}], center = [${5:3.14}, ${6:3.14}, ${7:3.14}], arcDegrees = ${8:3.14}, rotateDuplicates = ${9:false})"#
|
||||
);
|
||||
}
|
||||
|
||||
@ -942,11 +941,10 @@ mod tests {
|
||||
panic!();
|
||||
};
|
||||
let snippet = revolve_fn.to_autocomplete_snippet();
|
||||
assert_eq!(snippet, r#"revolve(axis = ${0:X})${}"#);
|
||||
assert_eq!(snippet, r#"revolve(axis = ${0:X})"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_circle() {
|
||||
let data = kcl_doc::walk_prelude();
|
||||
let DocData::Fn(circle_fn) = data.into_iter().find(|d| d.name() == "circle").unwrap() else {
|
||||
@ -955,12 +953,11 @@ mod tests {
|
||||
let snippet = circle_fn.to_autocomplete_snippet();
|
||||
assert_eq!(
|
||||
snippet,
|
||||
r#"circle(center = [${0:3.14}, ${1:3.14}], radius = ${2:3.14})${}"#
|
||||
r#"circle(center = [${0:3.14}, ${1:3.14}], radius = ${2:3.14})"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_arc() {
|
||||
let arc_fn: Box<dyn StdLibFn> = Box::new(crate::std::sketch::Arc);
|
||||
let snippet = arc_fn.to_autocomplete_snippet().unwrap();
|
||||
@ -970,7 +967,7 @@ mod tests {
|
||||
angleStart = ${0:3.14},
|
||||
angleEnd = ${1:3.14},
|
||||
radius = ${2:3.14},
|
||||
}, ${3:%})${}"#
|
||||
}, ${3:%})"#
|
||||
);
|
||||
}
|
||||
|
||||
@ -978,17 +975,16 @@ mod tests {
|
||||
fn get_autocomplete_snippet_map() {
|
||||
let map_fn: Box<dyn StdLibFn> = Box::new(crate::std::array::Map);
|
||||
let snippet = map_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"map(${0:[0..9]})${}"#);
|
||||
assert_eq!(snippet, r#"map(${0:[0..9]})"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_pattern_linear_2d() {
|
||||
let pattern_fn: Box<dyn StdLibFn> = Box::new(crate::std::patterns::PatternLinear2D);
|
||||
let snippet = pattern_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(
|
||||
snippet,
|
||||
r#"patternLinear2d(${0:%}, instances = ${1:10}, distance = ${2:3.14}, axis = [${3:3.14}, ${4:3.14}])${}"#
|
||||
r#"patternLinear2d(${0:%}, instances = ${1:10}, distance = ${2:3.14}, axis = [${3:3.14}, ${4:3.14}])"#
|
||||
);
|
||||
}
|
||||
|
||||
@ -998,36 +994,32 @@ mod tests {
|
||||
let snippet = appearance_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(
|
||||
snippet,
|
||||
r#"appearance(${0:%}, color = ${1:"#.to_owned() + "\"#" + r#"ff0000"})${}"#
|
||||
r#"appearance(${0:%}, color = ${1:"#.to_owned() + "\"#" + r#"ff0000"})"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_loft() {
|
||||
let loft_fn: Box<dyn StdLibFn> = Box::new(crate::std::loft::Loft);
|
||||
let snippet = loft_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"loft([${0:sketch000}, ${1:sketch001}])${}"#);
|
||||
assert_eq!(snippet, r#"loft([${0:sketch000}, ${1:sketch001}])"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_sweep() {
|
||||
let sweep_fn: Box<dyn StdLibFn> = Box::new(crate::std::sweep::Sweep);
|
||||
let snippet = sweep_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"sweep(${0:%}, path = ${1:sketch000})${}"#);
|
||||
assert_eq!(snippet, r#"sweep(${0:%}, path = ${1:sketch000})"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_hole() {
|
||||
let hole_fn: Box<dyn StdLibFn> = Box::new(crate::std::sketch::Hole);
|
||||
let snippet = hole_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"hole(${0:holeSketch}, ${1:%})${}"#);
|
||||
assert_eq!(snippet, r#"hole(${0:holeSketch}, ${1:%})"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_helix() {
|
||||
let data = kcl_doc::walk_prelude();
|
||||
let DocData::Fn(helix_fn) = data.into_iter().find(|d| d.name() == "helix").unwrap() else {
|
||||
@ -1036,36 +1028,32 @@ mod tests {
|
||||
let snippet = helix_fn.to_autocomplete_snippet();
|
||||
assert_eq!(
|
||||
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})"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_union() {
|
||||
let union_fn: Box<dyn StdLibFn> = Box::new(crate::std::csg::Union);
|
||||
let snippet = union_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"union(${0:%})${}"#);
|
||||
assert_eq!(snippet, r#"union([${0:extrude001}, ${1:extrude002}])"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_subtract() {
|
||||
let subtract_fn: Box<dyn StdLibFn> = Box::new(crate::std::csg::Subtract);
|
||||
let snippet = subtract_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"subtract(${0:%}, tools = ${1:%})${}"#);
|
||||
assert_eq!(snippet, r#"subtract([${0:extrude001}], tools = [${1:extrude002}])"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_intersect() {
|
||||
let intersect_fn: Box<dyn StdLibFn> = Box::new(crate::std::csg::Intersect);
|
||||
let snippet = intersect_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"intersect(${0:%})${}"#);
|
||||
assert_eq!(snippet, r#"intersect([${0:extrude001}, ${1:extrude002}])"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_get_common_edge() {
|
||||
let get_common_edge_fn: Box<dyn StdLibFn> = Box::new(crate::std::edge::GetCommonEdge);
|
||||
let snippet = get_common_edge_fn.to_autocomplete_snippet().unwrap();
|
||||
@ -1073,40 +1061,34 @@ mod tests {
|
||||
snippet,
|
||||
r#"getCommonEdge(faces = [{
|
||||
value = ${0:"string"},
|
||||
}])${}"#
|
||||
}])"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_scale() {
|
||||
let scale_fn: Box<dyn StdLibFn> = Box::new(crate::std::transform::Scale);
|
||||
let snippet = scale_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(
|
||||
snippet,
|
||||
r#"scale(${0:%}, x = ${1:3.14}, y = ${2:3.14}, z = ${3:3.14})${}"#
|
||||
);
|
||||
assert_eq!(snippet, r#"scale(${0:%}, x = ${1:3.14}, y = ${2:3.14}, z = ${3:3.14})"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_translate() {
|
||||
let translate_fn: Box<dyn StdLibFn> = Box::new(crate::std::transform::Translate);
|
||||
let snippet = translate_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(
|
||||
snippet,
|
||||
r#"translate(${0:%}, x = ${1:3.14}, y = ${2:3.14}, z = ${3:3.14})${}"#
|
||||
r#"translate(${0:%}, x = ${1:3.14}, y = ${2:3.14}, z = ${3:3.14})"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::literal_string_with_formatting_args)]
|
||||
fn get_autocomplete_snippet_rotate() {
|
||||
let rotate_fn: Box<dyn StdLibFn> = Box::new(crate::std::transform::Rotate);
|
||||
let snippet = rotate_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(
|
||||
snippet,
|
||||
r#"rotate(${0:%}, roll = ${1:3.14}, pitch = ${2:3.14}, yaw = ${3:3.14})${}"#
|
||||
r#"rotate(${0:%}, roll = ${1:3.14}, pitch = ${2:3.14}, yaw = ${3:3.14})"#
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@ pub(crate) const SETTINGS_UNIT_ANGLE: &str = "defaultAngleUnit";
|
||||
pub(super) const NO_PRELUDE: &str = "no_std";
|
||||
|
||||
pub(super) const IMPORT_FORMAT: &str = "format";
|
||||
pub(super) const IMPORT_FORMAT_VALUES: [&str; 9] = ["fbx", "gltf", "glb", "obj", "ply", "sldprt", "stp", "step", "stl"];
|
||||
pub(super) const IMPORT_COORDS: &str = "coords";
|
||||
pub(super) const IMPORT_COORDS_VALUES: [(&str, &System); 3] =
|
||||
[("zoo", KITTYCAD), ("opengl", OPENGL), ("vulkan", VULKAN)];
|
||||
|
@ -115,6 +115,30 @@ impl CodeRef {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS)]
|
||||
#[ts(export_to = "Artifact.ts")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompositeSolid {
|
||||
pub id: ArtifactId,
|
||||
pub sub_type: CompositeSolidSubType,
|
||||
/// Constituent solids of the composite solid.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub solid_ids: Vec<ArtifactId>,
|
||||
/// Tool solids used for asymmetric operations like subtract.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub tool_ids: Vec<ArtifactId>,
|
||||
pub code_ref: CodeRef,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS)]
|
||||
#[ts(export_to = "Artifact.ts")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum CompositeSolidSubType {
|
||||
Intersect,
|
||||
Subtract,
|
||||
Union,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS)]
|
||||
#[ts(export_to = "Artifact.ts")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@ -318,6 +342,7 @@ pub struct Helix {
|
||||
#[ts(export_to = "Artifact.ts")]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
pub enum Artifact {
|
||||
CompositeSolid(CompositeSolid),
|
||||
Plane(Plane),
|
||||
Path(Path),
|
||||
Segment(Segment),
|
||||
@ -336,6 +361,7 @@ pub enum Artifact {
|
||||
impl Artifact {
|
||||
pub(crate) fn id(&self) -> ArtifactId {
|
||||
match self {
|
||||
Artifact::CompositeSolid(a) => a.id,
|
||||
Artifact::Plane(a) => a.id,
|
||||
Artifact::Path(a) => a.id,
|
||||
Artifact::Segment(a) => a.id,
|
||||
@ -355,6 +381,7 @@ impl Artifact {
|
||||
#[expect(dead_code)]
|
||||
pub(crate) fn code_ref(&self) -> Option<&CodeRef> {
|
||||
match self {
|
||||
Artifact::CompositeSolid(a) => Some(&a.code_ref),
|
||||
Artifact::Plane(a) => Some(&a.code_ref),
|
||||
Artifact::Path(a) => Some(&a.code_ref),
|
||||
Artifact::Segment(a) => Some(&a.code_ref),
|
||||
@ -375,6 +402,7 @@ impl Artifact {
|
||||
/// type, return the new artifact which should be used as a replacement.
|
||||
fn merge(&mut self, new: Artifact) -> Option<Artifact> {
|
||||
match self {
|
||||
Artifact::CompositeSolid(a) => a.merge(new),
|
||||
Artifact::Plane(a) => a.merge(new),
|
||||
Artifact::Path(a) => a.merge(new),
|
||||
Artifact::Segment(a) => a.merge(new),
|
||||
@ -392,6 +420,18 @@ impl Artifact {
|
||||
}
|
||||
}
|
||||
|
||||
impl CompositeSolid {
|
||||
fn merge(&mut self, new: Artifact) -> Option<Artifact> {
|
||||
let Artifact::CompositeSolid(new) = new else {
|
||||
return Some(new);
|
||||
};
|
||||
merge_ids(&mut self.solid_ids, new.solid_ids);
|
||||
merge_ids(&mut self.tool_ids, new.tool_ids);
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Plane {
|
||||
fn merge(&mut self, new: Artifact) -> Option<Artifact> {
|
||||
let Artifact::Plane(new) = new else {
|
||||
@ -1047,6 +1087,85 @@ fn artifacts_to_update(
|
||||
// the helix here, but it's not useful right now.
|
||||
return Ok(return_arr);
|
||||
}
|
||||
ModelingCmd::BooleanIntersection(_) | ModelingCmd::BooleanSubtract(_) | ModelingCmd::BooleanUnion(_) => {
|
||||
let (sub_type, solid_ids, tool_ids) = match cmd {
|
||||
ModelingCmd::BooleanIntersection(intersection) => {
|
||||
let solid_ids = intersection
|
||||
.solid_ids
|
||||
.iter()
|
||||
.copied()
|
||||
.map(ArtifactId::new)
|
||||
.collect::<Vec<_>>();
|
||||
(CompositeSolidSubType::Intersect, solid_ids, Vec::new())
|
||||
}
|
||||
ModelingCmd::BooleanSubtract(subtract) => {
|
||||
let solid_ids = subtract
|
||||
.target_ids
|
||||
.iter()
|
||||
.copied()
|
||||
.map(ArtifactId::new)
|
||||
.collect::<Vec<_>>();
|
||||
let tool_ids = subtract
|
||||
.tool_ids
|
||||
.iter()
|
||||
.copied()
|
||||
.map(ArtifactId::new)
|
||||
.collect::<Vec<_>>();
|
||||
(CompositeSolidSubType::Subtract, solid_ids, tool_ids)
|
||||
}
|
||||
ModelingCmd::BooleanUnion(union) => {
|
||||
let solid_ids = union.solid_ids.iter().copied().map(ArtifactId::new).collect::<Vec<_>>();
|
||||
(CompositeSolidSubType::Union, solid_ids, Vec::new())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let mut new_solid_ids = vec![id];
|
||||
|
||||
match response {
|
||||
OkModelingCmdResponse::BooleanIntersection(intersection) => intersection
|
||||
.extra_solid_ids
|
||||
.iter()
|
||||
.copied()
|
||||
.map(ArtifactId::new)
|
||||
.for_each(|id| new_solid_ids.push(id)),
|
||||
OkModelingCmdResponse::BooleanSubtract(subtract) => subtract
|
||||
.extra_solid_ids
|
||||
.iter()
|
||||
.copied()
|
||||
.map(ArtifactId::new)
|
||||
.for_each(|id| new_solid_ids.push(id)),
|
||||
OkModelingCmdResponse::BooleanUnion(union) => union
|
||||
.extra_solid_ids
|
||||
.iter()
|
||||
.copied()
|
||||
.map(ArtifactId::new)
|
||||
.for_each(|id| new_solid_ids.push(id)),
|
||||
_ => {}
|
||||
}
|
||||
let return_arr = new_solid_ids
|
||||
.into_iter()
|
||||
// Extra solid IDs may include the command's ID. Make sure we
|
||||
// don't create a duplicate.
|
||||
.filter(|solid_id| *solid_id != id)
|
||||
.map(|solid_id| {
|
||||
Artifact::CompositeSolid(CompositeSolid {
|
||||
id: solid_id,
|
||||
sub_type,
|
||||
solid_ids: solid_ids.clone(),
|
||||
tool_ids: tool_ids.clone(),
|
||||
code_ref: CodeRef {
|
||||
range,
|
||||
path_to_node: path_to_node.clone(),
|
||||
},
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// TODO: Should we add the reverse graph edges?
|
||||
|
||||
return Ok(return_arr);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,11 @@ impl Artifact {
|
||||
/// the graph. This should be disjoint with `child_ids`.
|
||||
pub(crate) fn back_edges(&self) -> Vec<ArtifactId> {
|
||||
match self {
|
||||
Artifact::CompositeSolid(a) => {
|
||||
let mut ids = a.solid_ids.clone();
|
||||
ids.extend(a.tool_ids.iter());
|
||||
ids
|
||||
}
|
||||
Artifact::Plane(_) => Vec::new(),
|
||||
Artifact::Path(a) => vec![a.plane_id],
|
||||
Artifact::Segment(a) => vec![a.path_id],
|
||||
@ -87,6 +92,11 @@ impl Artifact {
|
||||
/// the graph.
|
||||
pub(crate) fn child_ids(&self) -> Vec<ArtifactId> {
|
||||
match self {
|
||||
Artifact::CompositeSolid(_) => {
|
||||
// Note: Don't include these since they're parents: solid_ids,
|
||||
// tool_ids.
|
||||
Vec::new()
|
||||
}
|
||||
Artifact::Plane(a) => a.path_ids.clone(),
|
||||
Artifact::Path(a) => {
|
||||
// Note: Don't include these since they're parents: plane_id.
|
||||
@ -213,6 +223,7 @@ impl ArtifactGraph {
|
||||
let id = artifact.id();
|
||||
|
||||
let grouped = match artifact {
|
||||
Artifact::CompositeSolid(_) => false,
|
||||
Artifact::Plane(_) => false,
|
||||
Artifact::Path(_) => {
|
||||
groups.entry(id).or_insert_with(Vec::new).push(id);
|
||||
@ -278,6 +289,15 @@ impl ArtifactGraph {
|
||||
}
|
||||
|
||||
match artifact {
|
||||
Artifact::CompositeSolid(composite_solid) => {
|
||||
writeln!(
|
||||
output,
|
||||
"{prefix}{}[\"CompositeSolid {:?}<br>{:?}\"]",
|
||||
id,
|
||||
composite_solid.sub_type,
|
||||
code_ref_display(&composite_solid.code_ref)
|
||||
)?;
|
||||
}
|
||||
Artifact::Plane(plane) => {
|
||||
writeln!(
|
||||
output,
|
||||
|
@ -939,25 +939,40 @@ impl Node<BinaryExpression> {
|
||||
if self.operator == BinaryOperator::Add || self.operator == BinaryOperator::Or {
|
||||
if let (KclValue::Solid { value: left }, KclValue::Solid { value: right }) = (&left_value, &right_value) {
|
||||
let args = crate::std::Args::new(Default::default(), self.into(), ctx.clone(), None);
|
||||
let result =
|
||||
crate::std::csg::inner_union(vec![*left.clone(), *right.clone()], exec_state, args).await?;
|
||||
let result = crate::std::csg::inner_union(
|
||||
vec![*left.clone(), *right.clone()],
|
||||
Default::default(),
|
||||
exec_state,
|
||||
args,
|
||||
)
|
||||
.await?;
|
||||
return Ok(result.into());
|
||||
}
|
||||
} else if self.operator == BinaryOperator::Sub {
|
||||
// Check if we have solids.
|
||||
if let (KclValue::Solid { value: left }, KclValue::Solid { value: right }) = (&left_value, &right_value) {
|
||||
let args = crate::std::Args::new(Default::default(), self.into(), ctx.clone(), None);
|
||||
let result =
|
||||
crate::std::csg::inner_subtract(vec![*left.clone()], vec![*right.clone()], exec_state, args)
|
||||
.await?;
|
||||
let result = crate::std::csg::inner_subtract(
|
||||
vec![*left.clone()],
|
||||
vec![*right.clone()],
|
||||
Default::default(),
|
||||
exec_state,
|
||||
args,
|
||||
)
|
||||
.await?;
|
||||
return Ok(result.into());
|
||||
}
|
||||
} else if self.operator == BinaryOperator::And {
|
||||
// Check if we have solids.
|
||||
if let (KclValue::Solid { value: left }, KclValue::Solid { value: right }) = (&left_value, &right_value) {
|
||||
let args = crate::std::Args::new(Default::default(), self.into(), ctx.clone(), None);
|
||||
let result =
|
||||
crate::std::csg::inner_intersect(vec![*left.clone(), *right.clone()], exec_state, args).await?;
|
||||
let result = crate::std::csg::inner_intersect(
|
||||
vec![*left.clone(), *right.clone()],
|
||||
Default::default(),
|
||||
exec_state,
|
||||
args,
|
||||
)
|
||||
.await?;
|
||||
return Ok(result.into());
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ pub(super) fn format_from_annotations(
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
message: format!(
|
||||
"Unknown format for import, expected one of: {}",
|
||||
annotations::IMPORT_FORMAT_VALUES.join(", ")
|
||||
crate::IMPORT_FILE_EXTENSIONS.join(", ")
|
||||
),
|
||||
source_ranges: vec![p.as_source_range()],
|
||||
})
|
||||
|
@ -11,9 +11,7 @@ pub use cache::{bust_cache, clear_mem_cache};
|
||||
pub use cad_op::Operation;
|
||||
pub use geometry::*;
|
||||
pub use id_generator::IdGenerator;
|
||||
pub(crate) use import::{
|
||||
import_foreign, send_to_engine as send_import_to_engine, PreImportedGeometry, ZOO_COORD_SYSTEM,
|
||||
};
|
||||
pub(crate) use import::PreImportedGeometry;
|
||||
use indexmap::IndexMap;
|
||||
pub use kcl_value::{KclObjectFields, KclValue};
|
||||
use kcmc::{
|
||||
|
@ -7,6 +7,7 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::types::NumericType;
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails, Severity},
|
||||
execution::{
|
||||
@ -22,8 +23,6 @@ use crate::{
|
||||
CompilationError,
|
||||
};
|
||||
|
||||
use super::types::NumericType;
|
||||
|
||||
/// State for executing a program.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExecState {
|
||||
|
@ -807,6 +807,7 @@ pub enum UnitAngle {
|
||||
impl UnitAngle {
|
||||
fn adjust_to(self, value: f64, to: UnitAngle) -> f64 {
|
||||
use std::f64::consts::PI;
|
||||
|
||||
use UnitAngle::*;
|
||||
|
||||
if !*CHECK_NUMERIC_TYPES {
|
||||
@ -1171,9 +1172,8 @@ impl KclValue {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::execution::{parse_execute, ExecTestResults};
|
||||
|
||||
use super::*;
|
||||
use crate::execution::{parse_execute, ExecTestResults};
|
||||
|
||||
fn values(exec_state: &mut ExecState) -> Vec<KclValue> {
|
||||
vec![
|
||||
|
@ -131,11 +131,36 @@ pub mod pretty {
|
||||
pub use crate::{parsing::token::NumericSuffix, unparser::format_number};
|
||||
}
|
||||
|
||||
#[cfg(feature = "cli")]
|
||||
use clap::ValueEnum;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::log::{log, logln};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
|
||||
pub static ref IMPORT_FILE_EXTENSIONS: Vec<String> = {
|
||||
let mut import_file_extensions = vec!["stp".to_string(), "glb".to_string(), "fbxb".to_string()];
|
||||
#[cfg(feature = "cli")]
|
||||
let named_extensions = kittycad::types::FileImportFormat::value_variants()
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<String>>();
|
||||
#[cfg(not(feature = "cli"))]
|
||||
let named_extensions = vec![]; // We don't really need this outside of the CLI.
|
||||
// Add all the default import formats.
|
||||
import_file_extensions.extend_from_slice(&named_extensions);
|
||||
import_file_extensions
|
||||
};
|
||||
|
||||
pub static ref RELEVANT_FILE_EXTENSIONS: Vec<String> = {
|
||||
let mut relevant_extensions = IMPORT_FILE_EXTENSIONS.clone();
|
||||
relevant_extensions.push("kcl".to_string());
|
||||
relevant_extensions
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Program {
|
||||
#[serde(flatten)]
|
||||
|
@ -3418,3 +3418,148 @@ async fn kcl_test_kcl_lsp_multi_file_error() {
|
||||
|
||||
server.executor_ctx().await.clone().unwrap().close().await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_kcl_lsp_on_hover_untitled_file_scheme() {
|
||||
let server = kcl_lsp_server(true).await.unwrap();
|
||||
|
||||
// Send open file.
|
||||
server
|
||||
.did_open(tower_lsp::lsp_types::DidOpenTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentItem {
|
||||
uri: "untitled:Untitled-1".try_into().unwrap(),
|
||||
language_id: "kcl".to_string(),
|
||||
version: 1,
|
||||
text: r#"startSketchOn(XY)
|
||||
foo = 42
|
||||
foo
|
||||
|
||||
fn bar(x: string): string {
|
||||
return x
|
||||
}
|
||||
|
||||
bar("an arg")
|
||||
|
||||
startSketchOn(XY)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line(end = [10, 0])
|
||||
|> line(end = [0, 10])
|
||||
"#
|
||||
.to_string(),
|
||||
},
|
||||
})
|
||||
.await;
|
||||
|
||||
// Std lib call
|
||||
let hover = server
|
||||
.hover(tower_lsp::lsp_types::HoverParams {
|
||||
text_document_position_params: tower_lsp::lsp_types::TextDocumentPositionParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentIdentifier {
|
||||
uri: "untitled:Untitled-1".try_into().unwrap(),
|
||||
},
|
||||
position: tower_lsp::lsp_types::Position { line: 0, character: 2 },
|
||||
},
|
||||
work_done_progress_params: Default::default(),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
match hover.unwrap().contents {
|
||||
tower_lsp::lsp_types::HoverContents::Markup(tower_lsp::lsp_types::MarkupContent { value, .. }) => {
|
||||
assert!(value.contains("startSketchOn"));
|
||||
assert!(value.contains(": SketchSurface"));
|
||||
assert!(value.contains("Start a new 2-dimensional sketch on a specific"));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
// Variable use
|
||||
let hover = server
|
||||
.hover(tower_lsp::lsp_types::HoverParams {
|
||||
text_document_position_params: tower_lsp::lsp_types::TextDocumentPositionParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentIdentifier {
|
||||
uri: "untitled:Untitled-1".try_into().unwrap(),
|
||||
},
|
||||
position: tower_lsp::lsp_types::Position { line: 2, character: 1 },
|
||||
},
|
||||
work_done_progress_params: Default::default(),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
match hover.unwrap().contents {
|
||||
tower_lsp::lsp_types::HoverContents::Markup(tower_lsp::lsp_types::MarkupContent { value, .. }) => {
|
||||
assert!(value.contains("foo: number = 42"));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
// User-defined function call.
|
||||
let hover = server
|
||||
.hover(tower_lsp::lsp_types::HoverParams {
|
||||
text_document_position_params: tower_lsp::lsp_types::TextDocumentPositionParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentIdentifier {
|
||||
uri: "untitled:Untitled-1".try_into().unwrap(),
|
||||
},
|
||||
position: tower_lsp::lsp_types::Position { line: 8, character: 1 },
|
||||
},
|
||||
work_done_progress_params: Default::default(),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
match hover.unwrap().contents {
|
||||
tower_lsp::lsp_types::HoverContents::Markup(tower_lsp::lsp_types::MarkupContent { value, .. }) => {
|
||||
assert!(value.contains("bar(x: string): string"));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
// Variable inside a function
|
||||
let hover = server
|
||||
.hover(tower_lsp::lsp_types::HoverParams {
|
||||
text_document_position_params: tower_lsp::lsp_types::TextDocumentPositionParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentIdentifier {
|
||||
uri: "untitled:Untitled-1".try_into().unwrap(),
|
||||
},
|
||||
position: tower_lsp::lsp_types::Position { line: 5, character: 9 },
|
||||
},
|
||||
work_done_progress_params: Default::default(),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
match hover.unwrap().contents {
|
||||
tower_lsp::lsp_types::HoverContents::Markup(tower_lsp::lsp_types::MarkupContent { value, .. }) => {
|
||||
assert!(value.contains("x: string"));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
// std function KwArg
|
||||
let hover = server
|
||||
.hover(tower_lsp::lsp_types::HoverParams {
|
||||
text_document_position_params: tower_lsp::lsp_types::TextDocumentPositionParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentIdentifier {
|
||||
uri: "untitled:Untitled-1".try_into().unwrap(),
|
||||
},
|
||||
position: tower_lsp::lsp_types::Position {
|
||||
line: 12,
|
||||
character: 11,
|
||||
},
|
||||
},
|
||||
work_done_progress_params: Default::default(),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
match hover.unwrap().contents {
|
||||
tower_lsp::lsp_types::HoverContents::Markup(tower_lsp::lsp_types::MarkupContent { value, .. }) => {
|
||||
assert!(value.contains("end?: [number]"));
|
||||
assert!(value.contains("How far away (along the X and Y axes) should this line go?"));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
server.executor_ctx().await.clone().unwrap().close().await;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ use crate::{
|
||||
token::{Token, TokenSlice, TokenType},
|
||||
PIPE_OPERATOR, PIPE_SUBSTITUTION_OPERATOR,
|
||||
},
|
||||
SourceRange,
|
||||
SourceRange, IMPORT_FILE_EXTENSIONS,
|
||||
};
|
||||
|
||||
thread_local! {
|
||||
@ -1803,11 +1803,6 @@ fn import_stmt(i: &mut TokenSlice) -> PResult<BoxNode<ImportStatement>> {
|
||||
end = alias.end;
|
||||
*selector_alias = Some(alias);
|
||||
}
|
||||
|
||||
ParseContext::warn(CompilationError::err(
|
||||
SourceRange::new(start, path.end, path.module_id),
|
||||
"Importing a whole module is experimental, likely to be buggy, and likely to change",
|
||||
));
|
||||
}
|
||||
|
||||
let path_string = match path.inner.value {
|
||||
@ -1843,8 +1838,6 @@ fn import_stmt(i: &mut TokenSlice) -> PResult<BoxNode<ImportStatement>> {
|
||||
))
|
||||
}
|
||||
|
||||
const FOREIGN_IMPORT_EXTENSIONS: [&str; 8] = ["fbx", "gltf", "glb", "obj", "ply", "sldprt", "step", "stl"];
|
||||
|
||||
/// Validates the path string in an `import` statement.
|
||||
///
|
||||
/// `var_name` is `true` if the path will be used as a variable name.
|
||||
@ -1909,12 +1902,11 @@ fn validate_path_string(path_string: String, var_name: bool, path_range: SourceR
|
||||
|
||||
ImportPath::Std { path: segments }
|
||||
} else if path_string.contains('.') {
|
||||
// TODO should allow other extensions if there is a format attribute.
|
||||
let extn = &path_string[path_string.rfind('.').unwrap() + 1..];
|
||||
if !FOREIGN_IMPORT_EXTENSIONS.contains(&extn) {
|
||||
let extn = std::path::Path::new(&path_string).extension().unwrap_or_default();
|
||||
if !IMPORT_FILE_EXTENSIONS.contains(&extn.to_string_lossy().to_string()) {
|
||||
ParseContext::warn(CompilationError::err(
|
||||
path_range,
|
||||
format!("unsupported import path format. KCL files can be imported from the current project, CAD files with the following formats are supported: {}", FOREIGN_IMPORT_EXTENSIONS.join(", ")),
|
||||
format!("unsupported import path format. KCL files can be imported from the current project, CAD files with the following formats are supported: {}", IMPORT_FILE_EXTENSIONS.join(", ")),
|
||||
))
|
||||
}
|
||||
ImportPath::Foreign { path: path_string }
|
||||
@ -1922,7 +1914,7 @@ fn validate_path_string(path_string: String, var_name: bool, path_range: SourceR
|
||||
return Err(ErrMode::Cut(
|
||||
CompilationError::fatal(
|
||||
path_range,
|
||||
format!("unsupported import path format. KCL files can be imported from the current project, CAD files with the following formats are supported: {}", FOREIGN_IMPORT_EXTENSIONS.join(", ")),
|
||||
format!("unsupported import path format. KCL files can be imported from the current project, CAD files with the following formats are supported: {}", IMPORT_FILE_EXTENSIONS.join(", ")),
|
||||
)
|
||||
.into(),
|
||||
));
|
||||
@ -4498,21 +4490,9 @@ export fn cos(num: number(rad)): number(_) {}"#;
|
||||
|
||||
#[test]
|
||||
fn warn_import() {
|
||||
let some_program_string = r#"import "foo.kcl""#;
|
||||
let (_, errs) = assert_no_err(some_program_string);
|
||||
assert_eq!(errs.len(), 1, "{errs:#?}");
|
||||
|
||||
let some_program_string = r#"import "foo.obj""#;
|
||||
let (_, errs) = assert_no_err(some_program_string);
|
||||
assert_eq!(errs.len(), 1, "{errs:#?}");
|
||||
|
||||
let some_program_string = r#"import "foo.sldprt""#;
|
||||
let (_, errs) = assert_no_err(some_program_string);
|
||||
assert_eq!(errs.len(), 1, "{errs:#?}");
|
||||
|
||||
let some_program_string = r#"import "foo.bad""#;
|
||||
let (_, errs) = assert_no_err(some_program_string);
|
||||
assert_eq!(errs.len(), 2, "{errs:#?}");
|
||||
assert_eq!(errs.len(), 1, "{errs:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -241,15 +241,9 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
||||
/// sweepPath = startSketchOn(XZ)
|
||||
/// |> startProfileAt([0.05, 0.05], %)
|
||||
/// |> line(end = [0, 7])
|
||||
/// |> tangentialArc({
|
||||
/// offset: 90,
|
||||
/// radius: 5
|
||||
/// }, %)
|
||||
/// |> tangentialArc(angle = 90, radius = 5)
|
||||
/// |> line(end = [-3, 0])
|
||||
/// |> tangentialArc({
|
||||
/// offset: -90,
|
||||
/// radius: 5
|
||||
/// }, %)
|
||||
/// |> tangentialArc(angle = -90, radius = 5)
|
||||
/// |> line(end = [0, 7])
|
||||
///
|
||||
/// pipeHole = startSketchOn(XY)
|
||||
|
@ -151,6 +151,10 @@ impl Args {
|
||||
let Some(arg) = self.kw_args.labeled.get(label) else {
|
||||
return Ok(None);
|
||||
};
|
||||
if let KclValue::KclNone { .. } = arg.value {
|
||||
// It is set, but it's an optional parameter that wasn't provided.
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
T::from_kcl_val(&arg.value).map(Some).ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
@ -664,10 +668,6 @@ impl Args {
|
||||
FromArgs::from_args(self, 0)
|
||||
}
|
||||
|
||||
pub(crate) fn get_import_data(&self) -> Result<(String, Option<crate::std::import::ImportFormat>), KclError> {
|
||||
FromArgs::from_args(self, 0)
|
||||
}
|
||||
|
||||
pub(crate) fn get_sketch_data_and_optional_tag(
|
||||
&self,
|
||||
) -> Result<(super::sketch::SketchData, Option<FaceTag>), KclError> {
|
||||
@ -1077,35 +1077,6 @@ macro_rules! let_field_of {
|
||||
};
|
||||
}
|
||||
|
||||
impl<'a> FromKclValue<'a> for crate::std::import::ImportFormat {
|
||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||
let obj = arg.as_object()?;
|
||||
let_field_of!(obj, typ "format");
|
||||
match typ {
|
||||
"fbx" => Some(Self::Fbx {}),
|
||||
"gltf" => Some(Self::Gltf {}),
|
||||
"sldprt" => Some(Self::Sldprt {}),
|
||||
"step" => Some(Self::Step {}),
|
||||
"stl" => {
|
||||
let_field_of!(obj, coords?);
|
||||
let_field_of!(obj, units);
|
||||
Some(Self::Stl { coords, units })
|
||||
}
|
||||
"obj" => {
|
||||
let_field_of!(obj, coords?);
|
||||
let_field_of!(obj, units);
|
||||
Some(Self::Obj { coords, units })
|
||||
}
|
||||
"ply" => {
|
||||
let_field_of!(obj, coords?);
|
||||
let_field_of!(obj, units);
|
||||
Some(Self::Ply { coords, units })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromKclValue<'a> for super::sketch::AngledLineThatIntersectsData {
|
||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||
let obj = arg.as_object()?;
|
||||
|
@ -2,6 +2,13 @@
|
||||
|
||||
use anyhow::Result;
|
||||
use kcl_derive_docs::stdlib;
|
||||
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, ModelingCmd};
|
||||
use kittycad_modeling_cmds::{
|
||||
self as kcmc,
|
||||
ok_response::OkModelingCmdResponse,
|
||||
output::{BooleanIntersection, BooleanSubtract, BooleanUnion},
|
||||
websocket::OkWebSocketResponseData,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
@ -9,10 +16,13 @@ use crate::{
|
||||
std::Args,
|
||||
};
|
||||
|
||||
use super::DEFAULT_TOLERANCE;
|
||||
|
||||
/// Union two or more solids into a single solid.
|
||||
pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let solids: Vec<Solid> =
|
||||
args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::Union(vec![RuntimeType::solids()]), exec_state)?;
|
||||
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
||||
|
||||
if solids.len() < 2 {
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
@ -21,7 +31,7 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
}));
|
||||
}
|
||||
|
||||
let solids = inner_union(solids, exec_state, args).await?;
|
||||
let solids = inner_union(solids, tolerance, exec_state, args).await?;
|
||||
Ok(solids.into())
|
||||
}
|
||||
|
||||
@ -30,18 +40,19 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// ```no_run
|
||||
/// // Union two cubes using the stdlib functions.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> 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])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = cube([20, 10])
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// unionedPart = union([part001, part002])
|
||||
/// ```
|
||||
@ -51,18 +62,19 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// // NOTE: This will not work when using codemods through the UI.
|
||||
/// // Codemods will generate the stdlib function call instead.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> 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])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = cube([20, 10])
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// // This is the equivalent of: union([part001, part002])
|
||||
/// unionedPart = part001 + part002
|
||||
@ -73,18 +85,19 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// // NOTE: This will not work when using codemods through the UI.
|
||||
/// // Codemods will generate the stdlib function call instead.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> 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])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = cube([20, 10])
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// // This is the equivalent of: union([part001, part002])
|
||||
/// // Programmers will understand `|` as a union operation, but mechanical engineers
|
||||
@ -96,31 +109,64 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
feature_tree_operation = true,
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
deprecated = true,
|
||||
args = {
|
||||
solids = {docs = "The solids to union."},
|
||||
tolerance = {docs = "The tolerance to use for the union operation."},
|
||||
}
|
||||
}]
|
||||
pub(crate) async fn inner_union(
|
||||
solids: Vec<Solid>,
|
||||
tolerance: Option<f64>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Vec<Solid>, KclError> {
|
||||
let solid_out_id = exec_state.next_uuid();
|
||||
|
||||
let mut solid = solids[0].clone();
|
||||
solid.id = solid_out_id;
|
||||
let mut new_solids = vec![solid.clone()];
|
||||
|
||||
if args.ctx.no_engine_commands().await {
|
||||
return Ok(new_solids);
|
||||
}
|
||||
|
||||
// Flush the fillets for the solids.
|
||||
args.flush_batch_for_solids(exec_state, &solids).await?;
|
||||
|
||||
// TODO: call the engine union operation.
|
||||
// TODO: figure out all the shit after for the faces etc.
|
||||
let result = args
|
||||
.send_modeling_cmd(
|
||||
solid_out_id,
|
||||
ModelingCmd::from(mcmd::BooleanUnion {
|
||||
solid_ids: solids.iter().map(|s| s.id).collect(),
|
||||
tolerance: LengthUnit(tolerance.unwrap_or(DEFAULT_TOLERANCE)),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// For now just return the first solid.
|
||||
// Til we have a proper implementation.
|
||||
Ok(vec![solids[0].clone()])
|
||||
let OkWebSocketResponseData::Modeling {
|
||||
modeling_response: OkModelingCmdResponse::BooleanUnion(BooleanUnion { extra_solid_ids }),
|
||||
} = result
|
||||
else {
|
||||
return Err(KclError::Internal(KclErrorDetails {
|
||||
message: "Failed to get the result of the union operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
// If we have more solids, set those as well.
|
||||
if !extra_solid_ids.is_empty() {
|
||||
solid.id = extra_solid_ids[0];
|
||||
new_solids.push(solid.clone());
|
||||
}
|
||||
|
||||
Ok(new_solids)
|
||||
}
|
||||
|
||||
/// Intersect returns the shared volume between multiple solids, preserving only
|
||||
/// overlapping regions.
|
||||
pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let solids: Vec<Solid> = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
|
||||
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
||||
|
||||
if solids.len() < 2 {
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
@ -129,7 +175,7 @@ pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
}));
|
||||
}
|
||||
|
||||
let solids = inner_intersect(solids, exec_state, args).await?;
|
||||
let solids = inner_intersect(solids, tolerance, exec_state, args).await?;
|
||||
Ok(solids.into())
|
||||
}
|
||||
|
||||
@ -144,18 +190,19 @@ pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
/// ```no_run
|
||||
/// // Intersect two cubes using the stdlib functions.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> 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])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = cube([8, 8])
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// intersectedPart = intersect([part001, part002])
|
||||
/// ```
|
||||
@ -165,18 +212,19 @@ pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
/// // NOTE: This will not work when using codemods through the UI.
|
||||
/// // Codemods will generate the stdlib function call instead.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> 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])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = cube([8, 8])
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// // This is the equivalent of: intersect([part001, part002])
|
||||
/// intersectedPart = part001 & part002
|
||||
@ -186,25 +234,57 @@ pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
feature_tree_operation = true,
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
deprecated = true,
|
||||
args = {
|
||||
solids = {docs = "The solids to intersect."},
|
||||
tolerance = {docs = "The tolerance to use for the intersection operation."},
|
||||
}
|
||||
}]
|
||||
pub(crate) async fn inner_intersect(
|
||||
solids: Vec<Solid>,
|
||||
tolerance: Option<f64>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Vec<Solid>, KclError> {
|
||||
let solid_out_id = exec_state.next_uuid();
|
||||
|
||||
let mut solid = solids[0].clone();
|
||||
solid.id = solid_out_id;
|
||||
let mut new_solids = vec![solid.clone()];
|
||||
|
||||
if args.ctx.no_engine_commands().await {
|
||||
return Ok(new_solids);
|
||||
}
|
||||
|
||||
// Flush the fillets for the solids.
|
||||
args.flush_batch_for_solids(exec_state, &solids).await?;
|
||||
|
||||
// TODO: call the engine union operation.
|
||||
// TODO: figure out all the shit after for the faces etc.
|
||||
let result = args
|
||||
.send_modeling_cmd(
|
||||
solid_out_id,
|
||||
ModelingCmd::from(mcmd::BooleanIntersection {
|
||||
solid_ids: solids.iter().map(|s| s.id).collect(),
|
||||
tolerance: LengthUnit(tolerance.unwrap_or(DEFAULT_TOLERANCE)),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// For now just return the first solid.
|
||||
// Til we have a proper implementation.
|
||||
Ok(vec![solids[0].clone()])
|
||||
let OkWebSocketResponseData::Modeling {
|
||||
modeling_response: OkModelingCmdResponse::BooleanIntersection(BooleanIntersection { extra_solid_ids }),
|
||||
} = result
|
||||
else {
|
||||
return Err(KclError::Internal(KclErrorDetails {
|
||||
message: "Failed to get the result of the intersection operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
// If we have more solids, set those as well.
|
||||
if !extra_solid_ids.is_empty() {
|
||||
solid.id = extra_solid_ids[0];
|
||||
new_solids.push(solid.clone());
|
||||
}
|
||||
|
||||
Ok(new_solids)
|
||||
}
|
||||
|
||||
/// Subtract removes tool solids from base solids, leaving the remaining material.
|
||||
@ -212,7 +292,23 @@ pub async fn subtract(exec_state: &mut ExecState, args: Args) -> Result<KclValue
|
||||
let solids: Vec<Solid> = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
|
||||
let tools: Vec<Solid> = args.get_kw_arg_typed("tools", &RuntimeType::solids(), exec_state)?;
|
||||
|
||||
let solids = inner_subtract(solids, tools, exec_state, args).await?;
|
||||
if solids.len() > 1 {
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
message: "Only one solid is allowed for a subtract operation, currently.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
if tools.len() > 1 {
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
message: "Only one tool is allowed for a subtract operation, currently.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
||||
|
||||
let solids = inner_subtract(solids, tools, tolerance, exec_state, args).await?;
|
||||
Ok(solids.into())
|
||||
}
|
||||
|
||||
@ -227,20 +323,19 @@ pub async fn subtract(exec_state: &mut ExecState, args: Args) -> Result<KclValue
|
||||
/// ```no_run
|
||||
/// // Subtract a cylinder from a cube using the stdlib functions.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> 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])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = startSketchOn('XY')
|
||||
/// |> circle(center = [0, 0], radius = 2)
|
||||
/// |> extrude(length = 10)
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// subtractedPart = subtract([part001], tools=[part002])
|
||||
/// ```
|
||||
@ -250,20 +345,19 @@ pub async fn subtract(exec_state: &mut ExecState, args: Args) -> Result<KclValue
|
||||
/// // NOTE: This will not work when using codemods through the UI.
|
||||
/// // Codemods will generate the stdlib function call instead.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> 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])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = startSketchOn('XY')
|
||||
/// |> circle(center = [0, 0], radius = 2)
|
||||
/// |> extrude(length = 10)
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// // This is the equivalent of: subtract([part001], tools=[part002])
|
||||
/// subtractedPart = part001 - part002
|
||||
@ -273,26 +367,59 @@ pub async fn subtract(exec_state: &mut ExecState, args: Args) -> Result<KclValue
|
||||
feature_tree_operation = true,
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
deprecated = true,
|
||||
args = {
|
||||
solids = {docs = "The solids to use as the base to subtract from."},
|
||||
tools = {docs = "The solids to subtract."},
|
||||
tolerance = {docs = "The tolerance to use for the subtraction operation."},
|
||||
}
|
||||
}]
|
||||
pub(crate) async fn inner_subtract(
|
||||
solids: Vec<Solid>,
|
||||
tools: Vec<Solid>,
|
||||
tolerance: Option<f64>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Vec<Solid>, KclError> {
|
||||
let solid_out_id = exec_state.next_uuid();
|
||||
|
||||
let mut solid = solids[0].clone();
|
||||
solid.id = solid_out_id;
|
||||
let mut new_solids = vec![solid.clone()];
|
||||
|
||||
if args.ctx.no_engine_commands().await {
|
||||
return Ok(new_solids);
|
||||
}
|
||||
|
||||
// Flush the fillets for the solids and the tools.
|
||||
let combined_solids = solids.iter().chain(tools.iter()).cloned().collect::<Vec<Solid>>();
|
||||
args.flush_batch_for_solids(exec_state, &combined_solids).await?;
|
||||
|
||||
// TODO: call the engine union operation.
|
||||
// TODO: figure out all the shit after for the faces etc.
|
||||
let result = args
|
||||
.send_modeling_cmd(
|
||||
solid_out_id,
|
||||
ModelingCmd::from(mcmd::BooleanSubtract {
|
||||
target_ids: solids.iter().map(|s| s.id).collect(),
|
||||
tool_ids: tools.iter().map(|s| s.id).collect(),
|
||||
tolerance: LengthUnit(tolerance.unwrap_or(DEFAULT_TOLERANCE)),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// For now just return the first solid.
|
||||
// Til we have a proper implementation.
|
||||
Ok(vec![solids[0].clone()])
|
||||
let OkWebSocketResponseData::Modeling {
|
||||
modeling_response: OkModelingCmdResponse::BooleanSubtract(BooleanSubtract { extra_solid_ids }),
|
||||
} = result
|
||||
else {
|
||||
return Err(KclError::Internal(KclErrorDetails {
|
||||
message: "Failed to get the result of the subtract operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
// If we have more solids, set those as well.
|
||||
if !extra_solid_ids.is_empty() {
|
||||
solid.id = extra_solid_ids[0];
|
||||
new_solids.push(solid.clone());
|
||||
}
|
||||
|
||||
Ok(new_solids)
|
||||
}
|
||||
|
@ -9,8 +9,7 @@ use kcmc::{
|
||||
length_unit::LengthUnit,
|
||||
ok_response::OkModelingCmdResponse,
|
||||
output::ExtrusionFaceInfo,
|
||||
shared::ExtrusionFaceCapType,
|
||||
shared::Opposite,
|
||||
shared::{ExtrusionFaceCapType, Opposite},
|
||||
websocket::{ModelingCmdReq, OkWebSocketResponseData},
|
||||
ModelingCmd,
|
||||
};
|
||||
|
@ -1,181 +0,0 @@
|
||||
//! Standard library functions involved in importing files.
|
||||
|
||||
use anyhow::Result;
|
||||
use kcl_derive_docs::stdlib;
|
||||
use kcmc::{coord::System, format::InputFormat3d, units::UnitLength};
|
||||
use kittycad_modeling_cmds as kcmc;
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{import_foreign, send_import_to_engine, ExecState, ImportedGeometry, KclValue, ZOO_COORD_SYSTEM},
|
||||
std::Args,
|
||||
};
|
||||
|
||||
/// Import format specifier
|
||||
#[derive(serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema)]
|
||||
#[cfg_attr(feature = "tabled", derive(tabled::Tabled))]
|
||||
#[serde(tag = "format")]
|
||||
pub enum ImportFormat {
|
||||
/// Autodesk Filmbox (FBX) format
|
||||
#[serde(rename = "fbx")]
|
||||
Fbx {},
|
||||
/// Binary glTF 2.0. We refer to this as glTF since that is how our customers refer to
|
||||
/// it, but this can also import binary glTF (glb).
|
||||
#[serde(rename = "gltf")]
|
||||
Gltf {},
|
||||
/// Wavefront OBJ format.
|
||||
#[serde(rename = "obj")]
|
||||
Obj {
|
||||
/// Co-ordinate system of input data.
|
||||
/// Defaults to the [KittyCAD co-ordinate system.
|
||||
coords: Option<System>,
|
||||
/// The units of the input data. This is very important for correct scaling and when
|
||||
/// calculating physics properties like mass, etc.
|
||||
/// Defaults to millimeters.
|
||||
units: UnitLength,
|
||||
},
|
||||
/// The PLY Polygon File Format.
|
||||
#[serde(rename = "ply")]
|
||||
Ply {
|
||||
/// Co-ordinate system of input data.
|
||||
/// Defaults to the [KittyCAD co-ordinate system.
|
||||
coords: Option<System>,
|
||||
/// The units of the input data. This is very important for correct scaling and when
|
||||
/// calculating physics properties like mass, etc.
|
||||
/// Defaults to millimeters.
|
||||
units: UnitLength,
|
||||
},
|
||||
/// SolidWorks part (SLDPRT) format.
|
||||
#[serde(rename = "sldprt")]
|
||||
Sldprt {},
|
||||
/// ISO 10303-21 (STEP) format.
|
||||
#[serde(rename = "step")]
|
||||
Step {},
|
||||
/// *ST**ereo**L**ithography format.
|
||||
#[serde(rename = "stl")]
|
||||
Stl {
|
||||
/// Co-ordinate system of input data.
|
||||
/// Defaults to the [KittyCAD co-ordinate system.
|
||||
coords: Option<System>,
|
||||
/// The units of the input data. This is very important for correct scaling and when
|
||||
/// calculating physics properties like mass, etc.
|
||||
/// Defaults to millimeters.
|
||||
units: UnitLength,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ImportFormat> for InputFormat3d {
|
||||
fn from(format: ImportFormat) -> Self {
|
||||
match format {
|
||||
ImportFormat::Fbx {} => InputFormat3d::Fbx(Default::default()),
|
||||
ImportFormat::Gltf {} => InputFormat3d::Gltf(Default::default()),
|
||||
ImportFormat::Obj { coords, units } => InputFormat3d::Obj(kcmc::format::obj::import::Options {
|
||||
coords: coords.unwrap_or(ZOO_COORD_SYSTEM),
|
||||
units,
|
||||
}),
|
||||
ImportFormat::Ply { coords, units } => InputFormat3d::Ply(kcmc::format::ply::import::Options {
|
||||
coords: coords.unwrap_or(ZOO_COORD_SYSTEM),
|
||||
units,
|
||||
}),
|
||||
ImportFormat::Sldprt {} => InputFormat3d::Sldprt(kcmc::format::sldprt::import::Options {
|
||||
split_closed_faces: false,
|
||||
}),
|
||||
ImportFormat::Step {} => InputFormat3d::Step(kcmc::format::step::import::Options {
|
||||
split_closed_faces: false,
|
||||
}),
|
||||
ImportFormat::Stl { coords, units } => InputFormat3d::Stl(kcmc::format::stl::import::Options {
|
||||
coords: coords.unwrap_or(ZOO_COORD_SYSTEM),
|
||||
units,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Import a CAD file.
|
||||
/// For formats lacking unit data (STL, OBJ, PLY), the default import unit is millimeters.
|
||||
/// Otherwise you can specify the unit by passing in the options parameter.
|
||||
/// If you import a gltf file, we will try to find the bin file and import it as well.
|
||||
///
|
||||
/// Import paths are relative to the current project directory. This only works in the desktop app
|
||||
/// not in browser.
|
||||
pub async fn import(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (file_path, options): (String, Option<ImportFormat>) = args.get_import_data()?;
|
||||
|
||||
let imported_geometry = inner_import(file_path, options, exec_state, args).await?;
|
||||
Ok(KclValue::ImportedGeometry(imported_geometry))
|
||||
}
|
||||
|
||||
/// Import a CAD file.
|
||||
///
|
||||
/// **DEPRECATED** Prefer to use import statements.
|
||||
///
|
||||
/// For formats lacking unit data (such as STL, OBJ, or PLY files), the default
|
||||
/// unit of measurement is millimeters. Alternatively you may specify the unit
|
||||
/// by passing your desired measurement unit in the options parameter. When
|
||||
/// importing a GLTF file, the bin file will be imported as well. Import paths
|
||||
/// are relative to the current project directory.
|
||||
///
|
||||
/// Note: The import command currently only works when using the native
|
||||
/// Design Studio.
|
||||
///
|
||||
/// ```no_run
|
||||
/// model = import("tests/inputs/cube.obj")
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// model = import("tests/inputs/cube.obj", {format: "obj", units: "m"})
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// model = import("tests/inputs/cube.gltf")
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// model = import("tests/inputs/cube.sldprt")
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// model = import("tests/inputs/cube.step")
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// import height, buildSketch from 'common.kcl'
|
||||
///
|
||||
/// plane = 'XZ'
|
||||
/// margin = 2
|
||||
/// s1 = buildSketch(plane, [0, 0])
|
||||
/// s2 = buildSketch(plane, [0, height() + margin])
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "import",
|
||||
feature_tree_operation = true,
|
||||
deprecated = true,
|
||||
tags = [],
|
||||
}]
|
||||
async fn inner_import(
|
||||
file_path: String,
|
||||
options: Option<ImportFormat>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<ImportedGeometry, KclError> {
|
||||
if file_path.is_empty() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "No file path was provided.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
let format = options.map(InputFormat3d::from);
|
||||
send_import_to_engine(
|
||||
import_foreign(
|
||||
std::path::Path::new(&file_path),
|
||||
format,
|
||||
exec_state,
|
||||
&args.ctx,
|
||||
args.source_range,
|
||||
)
|
||||
.await?,
|
||||
&args.ctx,
|
||||
)
|
||||
.await
|
||||
}
|
@ -12,7 +12,6 @@ pub mod edge;
|
||||
pub mod extrude;
|
||||
pub mod fillet;
|
||||
pub mod helix;
|
||||
pub mod import;
|
||||
pub mod loft;
|
||||
pub mod math;
|
||||
pub mod mirror;
|
||||
@ -86,8 +85,6 @@ lazy_static! {
|
||||
Box::new(crate::std::sketch::Arc),
|
||||
Box::new(crate::std::sketch::ArcTo),
|
||||
Box::new(crate::std::sketch::TangentialArc),
|
||||
Box::new(crate::std::sketch::TangentialArcTo),
|
||||
Box::new(crate::std::sketch::TangentialArcToRelative),
|
||||
Box::new(crate::std::sketch::BezierCurve),
|
||||
Box::new(crate::std::sketch::Hole),
|
||||
Box::new(crate::std::patterns::PatternLinear2D),
|
||||
@ -111,7 +108,6 @@ lazy_static! {
|
||||
Box::new(crate::std::sweep::Sweep),
|
||||
Box::new(crate::std::loft::Loft),
|
||||
Box::new(crate::std::planes::OffsetPlane),
|
||||
Box::new(crate::std::import::Import),
|
||||
Box::new(crate::std::math::Acos),
|
||||
Box::new(crate::std::math::Asin),
|
||||
Box::new(crate::std::math::Atan),
|
||||
|
@ -824,7 +824,7 @@ pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result
|
||||
/// |> startProfileAt([-size, -size], %)
|
||||
/// |> line(end = [2 * size, 0])
|
||||
/// |> line(end = [0, 2 * size])
|
||||
/// |> tangentialArcTo([-size, size], %)
|
||||
/// |> tangentialArc(endAbsolute = [-size, size])
|
||||
/// |> close(%)
|
||||
/// |> extrude(length = 65)
|
||||
///
|
||||
@ -852,7 +852,7 @@ pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result
|
||||
/// |> startProfileAt([-size, -size], %)
|
||||
/// |> line(end = [2 * size, 0])
|
||||
/// |> line(end = [0, 2 * size])
|
||||
/// |> tangentialArcTo([-size, size], %)
|
||||
/// |> tangentialArc(endAbsolute = [-size, size])
|
||||
/// |> close(%)
|
||||
/// |> extrude(length = 65)
|
||||
///
|
||||
|
@ -1,7 +1,12 @@
|
||||
//! Standard library revolution surfaces.
|
||||
|
||||
use anyhow::Result;
|
||||
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, shared::Angle, shared::Opposite, ModelingCmd};
|
||||
use kcmc::{
|
||||
each_cmd as mcmd,
|
||||
length_unit::LengthUnit,
|
||||
shared::{Angle, Opposite},
|
||||
ModelingCmd,
|
||||
};
|
||||
use kittycad_modeling_cmds::{self as kcmc, shared::Point3d};
|
||||
|
||||
use super::DEFAULT_TOLERANCE;
|
||||
|
@ -393,10 +393,7 @@ pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<Kc
|
||||
/// length = 10,
|
||||
/// tag = $thing,
|
||||
/// )
|
||||
/// |> tangentialArc({
|
||||
/// offset = -120,
|
||||
/// radius = 5,
|
||||
/// }, %)
|
||||
/// |> tangentialArc(angle = -120, radius = 5)
|
||||
/// |> angledLine(
|
||||
/// angle = -60,
|
||||
/// length = segLen(thing),
|
||||
@ -485,12 +482,12 @@ pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<Kc
|
||||
/// pillSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line(end = [20, 0])
|
||||
/// |> tangentialArcToRelative([0, 10], %, $arc1)
|
||||
/// |> tangentialArc(end = [0, 10], tag = $arc1)
|
||||
/// |> angledLine(
|
||||
/// angle = tangentToEnd(arc1),
|
||||
/// length = 20,
|
||||
/// )
|
||||
/// |> tangentialArcToRelative([0, -10], %)
|
||||
/// |> tangentialArc(end = [0, -10])
|
||||
/// |> close()
|
||||
///
|
||||
/// pillExtrude = extrude(pillSketch, length = 10)
|
||||
@ -501,12 +498,12 @@ pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<Kc
|
||||
/// pillSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line(end = [0, 20])
|
||||
/// |> tangentialArcTo([10, 20], %, $arc1)
|
||||
/// |> tangentialArc(endAbsolute = [10, 20], tag = $arc1)
|
||||
/// |> angledLine(
|
||||
/// angle = tangentToEnd(arc1),
|
||||
/// length = 20,
|
||||
/// )
|
||||
/// |> tangentialArcToRelative([-10, 0], %)
|
||||
/// |> tangentialArc(end = [-10, 0])
|
||||
/// |> close()
|
||||
///
|
||||
/// pillExtrude = extrude(pillSketch, length = 10)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user