Compare commits

..

1 Commits

Author SHA1 Message Date
dac3c0c224 Delete test that is covering a basic assumption 2025-05-13 12:46:28 -04:00
1041 changed files with 520141 additions and 257472 deletions

View File

@ -13,7 +13,7 @@ env:
IS_NIGHTLY: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
@ -123,6 +123,18 @@ jobs:
- id: export_notes
run: echo "notes=`cat release-notes.md`" >> "$GITHUB_OUTPUT"
- name: Prepare electron-builder.yml file for updater test
if: ${{ env.IS_RELEASE == 'true' }}
run: |
yq -i '.publish[0].url = "https://dl.zoo.dev/releases/modeling-app/updater-test"' electron-builder.yml
- uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}
with:
name: prepared-files-updater-test
path: |
electron-builder.yml
build-apps:
needs: [prepare-files]
@ -247,6 +259,49 @@ jobs:
# TODO: add the 'Build for Mac TestFlight (nightly)' stage back
# The steps below are for updater-test builds, only on release
- uses: actions/download-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}
name: prepared-files-updater-test
- name: Copy updated electron-builder.yml file for updater test
if: ${{ env.IS_RELEASE == 'true' }}
run: |
ls -R prepared-files-updater-test
cp prepared-files-updater-test/electron-builder.yml electron-builder.yml
- name: Build the app (updater-test)
if: ${{ env.IS_RELEASE == 'true' }}
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }}
WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }}
run: npm run tronb:package:prod
- uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}
with:
name: updater-test-arm64-${{ matrix.platform }}
path: |
out/*-arm64-win.exe
out/*-arm64-mac.dmg
out/*-arm64-linux.AppImage
- uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}
with:
name: updater-test-x64-${{ matrix.platform }}
path: |
out/*-x64-win.exe
out/*-x64-mac.dmg
out/*-x86_64-linux.AppImage
upload-apps-release:
runs-on: ubuntu-22.04

View File

@ -40,7 +40,7 @@ jobs:
- name: Install dependencies
run: npm install
- name: Download Wasm cache
- name: Download Wasm Cache
id: download-wasm
if: ${{ github.event_name != 'schedule' && steps.filter.outputs.rust == 'false' }}
uses: dawidd6/action-download-artifact@v7
@ -52,7 +52,7 @@ jobs:
branch: main
path: rust/kcl-wasm-lib/pkg
- name: Build Wasm condition
- name: Build WASM condition
id: wasm
run: |
set -euox pipefail
@ -70,7 +70,7 @@ jobs:
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install Rust
- name: Install rust
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
@ -81,7 +81,7 @@ jobs:
with:
tool: wasm-pack
- name: Use Rust cache
- name: Rust Cache
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
uses: Swatinem/rust-cache@v2
with:
@ -117,7 +117,7 @@ jobs:
- uses: actions/download-artifact@v4
name: prepared-wasm
- name: Copy prepared Wasm
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
@ -133,17 +133,20 @@ jobs:
id: deps-install
run: npm install
- name: Cache browsers
- name: Cache Playwright Browsers
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright/
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }}
- name: Install browsers
- name: Install Playwright Browsers
run: npm run playwright install --with-deps
- name: Capture snapshots
- name: build web
run: npm run tronb:vite:dev
- name: Run ubuntu/chrome snapshots
uses: nick-fields/retry@v3.0.2
with:
shell: bash
@ -167,7 +170,7 @@ jobs:
retention-days: 30
overwrite: true
- name: Check diff
- name: Check for changes
if: ${{ github.ref != 'refs/heads/main' }}
shell: bash
id: git-check
@ -178,8 +181,9 @@ jobs:
else echo "modified=false" >> $GITHUB_OUTPUT
fi
- name: Commit changes
if: ${{ steps.git-check.outputs.modified == 'true' }}
- name: Commit changes, if any
# TODO: find a more reliable way to detect visual changes
if: ${{ false && steps.git-check.outputs.modified == 'true' }}
shell: bash
run: |
git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots
@ -189,7 +193,7 @@ jobs:
git fetch origin
echo ${{ github.head_ref }}
git checkout ${{ github.head_ref }}
git commit --message "Update snapshots" || true
git commit -m "A snapshot a day keeps the bugs away! 📷🐛" || true
git push
git push origin ${{ github.head_ref }}
@ -230,16 +234,10 @@ jobs:
shardTotal: 8
- os: namespace-profile-macos-8-cores
shardIndex: 1
shardTotal: 2
- os: namespace-profile-macos-8-cores
shardIndex: 2
shardTotal: 2
shardTotal: 1
- os: windows-latest-8-cores
shardIndex: 1
shardTotal: 2
- os: windows-latest-8-cores
shardIndex: 2
shardTotal: 2
shardTotal: 1
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4

View File

@ -130,7 +130,7 @@ git tag $VERSION
git push origin --tags
```
This will trigger the `build-apps` workflow, set the version, build & sign the apps, and generate release files.
This will trigger the `build-apps` workflow, set the version, build & sign the apps, and generate release files as well as updater-test artifacts.
The workflow should be listed right away [in this list](https://github.com/KittyCAD/modeling-app/actions/workflows/build-apps.yml?query=event%3Apush)).
@ -142,10 +142,13 @@ The release builds can be found under the `out-{arch}-{platform}` zip files, at
Manually test against this [list](https://github.com/KittyCAD/modeling-app/issues/3588) across Windows, MacOS, Linux and posting results as comments in the issue.
A prompt should show up asking for a downgrade to the last release version. Running through that at the end of testing
and making sure the current release candidate has the ability to be updated to what electron-updater points to is critical,
but what is actually being downloaded and installed isn't.
If the prompt doesn't show up, start the app in command line to grab the electron-updater logs. This is likely an issue with the current build that needs addressing.
##### Updater-test builds
The other `build-apps` output in the release `build-apps` workflow (triggered by 2.) is `updater-test-{arch}-{platform}`. It's a semi-automated process: for macOS, Windows, and Linux, download the corresponding updater-test artifact file, install the app, run it, expect an updater prompt to a dummy v0.255.255, install it and check that the app comes back at that version.
The only difference with these builds is that they point to a different update location on the release bucket, with this dummy v0.255.255 always available. This helps ensuring that the version we release will be able to update to the next one available.
If the prompt doesn't show up, start the app in command line to grab the electron-updater logs. This is likely an issue with the current build that needs addressing (or the updater-test location in the storage bucket).
```
# Windows (PowerShell)

View File

@ -34,7 +34,7 @@ The 3D view in Design Studio is just a video stream from our hosted geometry eng
- WebSockets (via [KittyCAD TS client](https://github.com/KittyCAD/kittycad.ts))
- Code Editor
- [CodeMirror](https://codemirror.net/)
- [Custom WASM LSP Server](https://github.com/KittyCAD/modeling-app/tree/main/rust/kcl-lib/src/lsp/kcl)
- Custom WASM LSP Server
- Modeling
- [KittyCAD TypeScript client](https://github.com/KittyCAD/kittycad.ts)

View File

@ -46,7 +46,7 @@ angledLine(
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> yLine(endAbsolute = 15)
|> angledLine(angle = 30deg, length = 15)
|> angledLine(angle = 30, length = 15)
|> line(end = [8, -10])
|> yLine(endAbsolute = 0)
|> close()

View File

@ -42,7 +42,7 @@ exampleSketch = startSketchOn(XZ)
|> line(endAbsolute = [5, 10])
|> line(endAbsolute = [-10, 10], tag = $lineToIntersect)
|> line(endAbsolute = [0, 20])
|> angledLineThatIntersects(angle = 80deg, intersectTag = lineToIntersect, offset = 10)
|> angledLineThatIntersects(angle = 80, intersectTag = lineToIntersect, offset = 10)
|> close()
example = extrude(exampleSketch, length = 10)

File diff suppressed because one or more lines are too long

View File

@ -46,7 +46,7 @@ Unless this makes a lot of sense and feels like what you're looking for to const
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> line(end = [10, 0])
|> arc(angleStart = 0deg, angleEnd = 280deg, radius = 16)
|> arc(angleStart = 0, angleEnd = 280, radius = 16)
|> close()
example = extrude(exampleSketch, length = 10)
```

View File

@ -19,7 +19,7 @@ E: number = 2.71828182845904523536028747135266250_
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(
angle = 30deg,
angle = 30,
length = 2 * E ^ 2,
)
|> yLine(endAbsolute = 0)

View File

@ -19,7 +19,7 @@ TAU: number = 6.28318530717958647692528676655900577_
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(
angle = 50deg,
angle = 50,
length = 10 * TAU,
)
|> yLine(endAbsolute = 0)

View File

@ -1,16 +0,0 @@
---
title: "sweep::SKETCH_PLANE"
subtitle: "Constant in std::sweep"
excerpt: "Local/relative to a position centered within the plane being sketched on"
layout: manual
---
Local/relative to a position centered within the plane being sketched on
```kcl
sweep::SKETCH_PLANE: string = 'sketchPlane'
```

View File

@ -1,16 +0,0 @@
---
title: "sweep::TRAJECTORY"
subtitle: "Constant in std::sweep"
excerpt: "Local/relative to the trajectory curve"
layout: manual
---
Local/relative to the trajectory curve
```kcl
sweep::TRAJECTORY: string = 'trajectoryCurve'
```

View File

@ -42,7 +42,7 @@ You can provide more than one sketch to extrude, and they will all be extruded i
example = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> line(end = [10, 0])
|> arc(angleStart = 120deg, angleEnd = 0deg, radius = 5)
|> arc(angleStart = 120, angleEnd = 0, radius = 5)
|> line(end = [5, 0])
|> line(end = [0, 10])
|> bezierCurve(control1 = [-10, 0], control2 = [2, 10], end = [-5, 10])
@ -56,7 +56,7 @@ example = startSketchOn(XZ)
```kcl
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [-10, 0])
|> arc(angleStart = 120deg, angleEnd = -60deg, radius = 5)
|> arc(angleStart = 120, angleEnd = -60, radius = 5)
|> line(end = [10, 0])
|> line(end = [5, 0])
|> bezierCurve(control1 = [-3, 0], control2 = [2, 10], end = [-5, 10])
@ -72,7 +72,7 @@ example = extrude(exampleSketch, length = 10)
```kcl
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [-10, 0])
|> arc(angleStart = 120deg, angleEnd = -60deg, radius = 5)
|> arc(angleStart = 120, angleEnd = -60, radius = 5)
|> line(end = [10, 0])
|> line(end = [5, 0])
|> bezierCurve(control1 = [-3, 0], control2 = [2, 10], end = [-5, 10])
@ -88,7 +88,7 @@ example = extrude(exampleSketch, length = 20, symmetric = true)
```kcl
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [-10, 0])
|> arc(angleStart = 120deg, angleEnd = -60deg, radius = 5)
|> arc(angleStart = 120, angleEnd = -60, radius = 5)
|> line(end = [10, 0])
|> line(end = [5, 0])
|> bezierCurve(control1 = [-3, 0], control2 = [2, 10], end = [-5, 10])

View File

@ -80,7 +80,7 @@ fn decagon(@radius) {
// Start the decagon sketch at this point.
startOfDecagonSketch = startSketchOn(XY)
|> startProfile(at = [(cos(0deg)*radius), (sin(0deg) * radius)])
|> startProfile(at = [(cos(0)*radius), (sin(0) * radius)])
// Use a `reduce` to draw the remaining decagon sides.
// For each number in the array 1..10, run the given function,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -27,7 +27,7 @@ abs(@input: number): number
### Examples
```kcl
myAngle = -120deg
myAngle = -120
sketch001 = startSketchOn(XZ)
|> startProfile(at = [0, 0])

View File

@ -30,7 +30,7 @@ cos(@num: number(Angle)): number(_)
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(
angle = 30deg,
angle = 30,
length = 3 / cos(30deg),
)
|> yLine(endAbsolute = 0)

View File

@ -30,7 +30,7 @@ max(@input: [number; 1+]): number
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(
angle = 70deg,
angle = 70,
length = max([15, 31, 4, 13, 22])
)
|> line(end = [20, 0])

View File

@ -30,7 +30,7 @@ min(@input: [number; 1+]): number
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(
angle = 70deg,
angle = 70,
length = min([15, 31, 4, 13, 22])
)
|> line(end = [20, 0])

View File

@ -34,7 +34,7 @@ cartesian (x/y/z grid) coordinates.
```kcl
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> line(end = polar(angle = 30deg, length = 5), tag = $thing)
|> line(end = polar(angle = 30, length = 5), tag = $thing)
|> line(end = [0, 5])
|> line(end = [segEndX(thing), 0])
|> line(end = [-20, 10])

View File

@ -34,7 +34,7 @@ pow(
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(
angle = 50deg,
angle = 50,
length = pow(5, exp = 2),
)
|> yLine(endAbsolute = 0)

View File

@ -30,7 +30,7 @@ sin(@num: number(Angle)): number(_)
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(
angle = 50deg,
angle = 50,
length = 15 / sin(135deg),
)
|> yLine(endAbsolute = 0)

View File

@ -30,7 +30,7 @@ sqrt(@input: number): number
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(
angle = 50deg,
angle = 50,
length = sqrt(2500),
)
|> yLine(endAbsolute = 0)

View File

@ -30,7 +30,7 @@ tan(@num: number(Angle)): number(_)
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(
angle = 50deg,
angle = 50,
length = 50 * tan((1/2): number(rad)),
)
|> yLine(endAbsolute = 0)

File diff suppressed because one or more lines are too long

View File

@ -30,7 +30,7 @@ units::toDegrees(@num: number(Angle)): number(deg)
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(
angle = 50deg,
angle = 50,
length = 70 * cos(units::toDegrees((PI/4): number(rad))),
)
|> yLine(endAbsolute = 0)

View File

@ -30,8 +30,8 @@ units::toRadians(@num: number(Angle)): number(rad)
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(
angle = 50deg,
length = 70 * cos(units::toRadians(45deg)),
angle = 50,
length = 70 * cos(units::toRadians(45)),
)
|> yLine(endAbsolute = 0)
|> close()

View File

@ -30,10 +30,10 @@ getNextAdjacentEdge(@edge: TagIdentifier): Uuid
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> line(end = [10, 0])
|> angledLine(angle = 60deg, length = 10)
|> angledLine(angle = 120deg, length = 10)
|> angledLine(angle = 60, length = 10)
|> angledLine(angle = 120, length = 10)
|> line(end = [-10, 0])
|> angledLine(angle = 240deg, length = 10, tag = $referenceEdge)
|> angledLine(angle = 240, length = 10, tag = $referenceEdge)
|> close()
example = extrude(exampleSketch, length = 5)

View File

@ -30,10 +30,10 @@ getOppositeEdge(@edge: TagIdentifier): Uuid
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> line(end = [10, 0])
|> angledLine(angle = 60deg, length = 10)
|> angledLine(angle = 120deg, length = 10)
|> angledLine(angle = 60, length = 10)
|> angledLine(angle = 120, length = 10)
|> line(end = [-10, 0])
|> angledLine(angle = 240deg, length = 10, tag = $referenceEdge)
|> angledLine(angle = 240, length = 10, tag = $referenceEdge)
|> close()
example = extrude(exampleSketch, length = 5)

View File

@ -30,10 +30,10 @@ getPreviousAdjacentEdge(@edge: TagIdentifier): Uuid
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> line(end = [10, 0])
|> angledLine(angle = 60deg, length = 10)
|> angledLine(angle = 120deg, length = 10)
|> angledLine(angle = 60, length = 10)
|> angledLine(angle = 120, length = 10)
|> line(end = [-10, 0])
|> angledLine(angle = 240deg, length = 10, tag = $referenceEdge)
|> angledLine(angle = 240, length = 10, tag = $referenceEdge)
|> close()
example = extrude(exampleSketch, length = 5)

View File

@ -128,9 +128,6 @@ layout: manual
* [`E`](/docs/kcl-std/consts/std-math-E)
* [`PI`](/docs/kcl-std/consts/std-math-PI)
* [`TAU`](/docs/kcl-std/consts/std-math-TAU)
* [**std::sweep**](/docs/kcl-std/modules/std-sweep)
* [`sweep::SKETCH_PLANE`](/docs/kcl-std/consts/std-sweep-SKETCH_PLANE)
* [`sweep::TRAJECTORY`](/docs/kcl-std/consts/std-sweep-TRAJECTORY)
* [**std::turns**](/docs/kcl-std/modules/std-turns)
* [`turns::HALF_TURN`](/docs/kcl-std/consts/std-turns-HALF_TURN)
* [`turns::QUARTER_TURN`](/docs/kcl-std/consts/std-turns-QUARTER_TURN)

View File

@ -43,11 +43,11 @@ a = 10
b = 14
startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> involuteCircular(startRadius = a, endRadius = b, angle = 60deg)
|> involuteCircular(startRadius = a, endRadius = b, angle = 60)
|> involuteCircular(
startRadius = a,
endRadius = b,
angle = 60deg,
angle = 60,
reverse = true,
)
```

File diff suppressed because one or more lines are too long

View File

@ -1,17 +0,0 @@
---
title: "sweep"
subtitle: "Module in std"
excerpt: ""
layout: manual
---
## Functions and constants
* [`sweep::SKETCH_PLANE`](/docs/kcl-std/consts/std-sweep-SKETCH_PLANE)
* [`sweep::TRAJECTORY`](/docs/kcl-std/consts/std-sweep-TRAJECTORY)

View File

@ -19,7 +19,6 @@ You might also want the [KCL language reference](/docs/kcl-lang) or the [KCL gui
* [`math`](/docs/kcl-std/modules/std-math)
* [`sketch`](/docs/kcl-std/modules/std-sketch)
* [`solid`](/docs/kcl-std/modules/std-solid)
* [`sweep::sweep`](/docs/kcl-std/modules/std-sweep)
* [`transform`](/docs/kcl-std/modules/std-transform)
* [`turns::turns`](/docs/kcl-std/modules/std-turns)
* [`types`](/docs/kcl-std/modules/std-types)

View File

@ -48,7 +48,7 @@ exampleSketch = startSketchOn(XZ)
|> patternCircular2d(
center = [0, 0],
instances = 13,
arcDegrees = 360deg,
arcDegrees = 360,
rotateDuplicates = true,
)

View File

@ -49,7 +49,7 @@ example = extrude(exampleSketch, length = -5)
axis = [1, -1, 0],
center = [10, -20, 0],
instances = 11,
arcDegrees = 360deg,
arcDegrees = 360,
rotateDuplicates = true,
)
```

View File

@ -123,7 +123,7 @@ fn transform(@i) {
pow(0.9, exp = i)
],
// Turn by 15 degrees each time.
rotation = { angle = 15deg * i, origin = "local" }
rotation = { angle = 15 * i, origin = "local" }
}
}
@ -158,7 +158,7 @@ fn transform(@i) {
return {
translate = [0, 0, -i * width],
rotation = {
angle = 90deg * i,
angle = 90 * i,
// Rotate around the overall scene's origin.
origin = "global"
}
@ -204,7 +204,7 @@ fn transform(@i) {
// Transform functions can return multiple transforms. They'll be applied in order.
return [
{ translate = [30 * i, 0, 0] },
{ rotation = { angle = 45deg * i } }
{ rotation = { angle = 45 * i } }
]
}
startSketchOn(XY)

View File

@ -29,8 +29,8 @@ profileStart(@profile: Sketch): [number]
```kcl
sketch001 = startSketchOn(XY)
|> startProfile(at = [5, 2])
|> angledLine(angle = 120deg, length = 50, tag = $seg01)
|> angledLine(angle = segAng(seg01) + 120deg, length = 50)
|> angledLine(angle = 120, length = 50, tag = $seg01)
|> angledLine(angle = segAng(seg01) + 120, length = 50)
|> line(end = profileStart(%))
|> close()
|> extrude(length = 20)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -29,9 +29,9 @@ segLen(@tag: TagIdentifier): number
```kcl
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(angle = 60deg, length = 10, tag = $thing)
|> tangentialArc(angle = -120deg, radius = 5)
|> angledLine(angle = -60deg, length = segLen(thing))
|> angledLine(angle = 60, length = 10, tag = $thing)
|> tangentialArc(angle = -120, radius = 5)
|> angledLine(angle = -60, length = segLen(thing))
|> close()
example = extrude(exampleSketch, length = 5)

View File

@ -146,7 +146,7 @@ exampleSketch = startSketchOn(XY)
|> line(end = [-2, 0])
|> close()
example = revolve(exampleSketch, axis = Y, angle = 180deg)
example = revolve(exampleSketch, axis = Y, angle = 180)
exampleSketch002 = startSketchOn(example, face = END)
|> startProfile(at = [4.5, -5])
@ -178,7 +178,7 @@ exampleSketch = startSketchOn(XY)
example = revolve(
exampleSketch,
axis = Y,
angle = 180deg,
angle = 180,
tagEnd = $end01,
)

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -41,7 +41,7 @@ When using radius and angle, draw a curved line segment along part of an imagina
```kcl
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(angle = 45deg, length = 10)
|> angledLine(angle = 45, length = 10)
|> tangentialArc(end = [0, -10])
|> line(end = [-10, 0])
|> close()
@ -54,7 +54,7 @@ example = extrude(exampleSketch, length = 10)
```kcl
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(angle = 60deg, length = 10)
|> angledLine(angle = 60, length = 10)
|> tangentialArc(endAbsolute = [15, 15])
|> line(end = [10, -15])
|> close()
@ -67,9 +67,9 @@ example = extrude(exampleSketch, length = 10)
```kcl
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(angle = 60deg, length = 10)
|> tangentialArc(radius = 10, angle = -120deg)
|> angledLine(angle = -60deg, length = 10)
|> angledLine(angle = 60, length = 10)
|> tangentialArc(radius = 10, angle = -120)
|> angledLine(angle = -60, length = 10)
|> close()
example = extrude(exampleSketch, length = 10)

File diff suppressed because one or more lines are too long

View File

@ -15,9 +15,9 @@ way:
```js
startSketchOn(XZ)
|> startProfile(at = origin)
|> angledLine(angle = 0deg, length = 191.26, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001)
|> angledLine(
angle = segAng(rectangleSegmentA001) - 90deg,
angle = segAng(rectangleSegmentA001) - 90,
length = 196.99,
tag = $rectangleSegmentB001,
)
@ -49,9 +49,9 @@ However if the code was written like this:
fn rect(origin) {
return startSketchOn(XZ)
|> startProfile(at = origin)
|> angledLine(angle = 0deg, length = 191.26, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001)
|> angledLine(
angle = segAng(rectangleSegmentA001) - 90deg,
angle = segAng(rectangleSegmentA001) - 90,
length = 196.99,
tag = $rectangleSegmentB001)
|> angledLine(
@ -78,9 +78,9 @@ For example the following code works.
fn rect(origin) {
return startSketchOn(XZ)
|> startProfile(at = origin)
|> angledLine(angle = 0deg, length = 191.26, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001)
|> angledLine(
angle = segAng(rectangleSegmentA001) - 90deg,
angle = segAng(rectangleSegmentA001) - 90,
length = 196.99
tag = $rectangleSegmentB001,
)

View File

@ -38,10 +38,10 @@ xLine(
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> xLine(length = 15)
|> angledLine(angle = 80deg, length = 15)
|> angledLine(angle = 80, length = 15)
|> line(end = [8, -10])
|> xLine(length = 10)
|> angledLine(angle = 120deg, length = 30)
|> angledLine(angle = 120, length = 30)
|> xLine(length = -15)
|> close()

View File

@ -38,7 +38,7 @@ yLine(
exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> yLine(length = 15)
|> angledLine(angle = 30deg, length = 15)
|> angledLine(angle = 30, length = 15)
|> line(end = [8, -10])
|> yLine(length = -5)
|> close()

View File

@ -134,6 +134,8 @@ extrude001 = extrude(sketch001, length = 5)`
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
await page.waitForTimeout(1000)
// Ensure badge is present
const codePaneButtonHolder = page.locator('#code-button-holder')
await expect(codePaneButtonHolder).toContainText('notification', {
@ -156,14 +158,10 @@ extrude001 = extrude(sketch001, length = 5)`
await expect(
page
.getByText(
'Solid3D revolve failed: sketch profile must lie entirely on one side of the revolution axis'
'Modeling command failed: [ApiError { error_code: InternalEngine, message: "Solid3D revolve failed: sketch profile must lie entirely on one side of the revolution axis" }]'
)
.first()
).toBeVisible()
// Make sure ApiError is not on the page.
// This ensures we didn't nest the json
await expect(page.getByText('ApiError')).not.toBeVisible()
})
test('When error is not in view WITH LINTS you can click the badge to scroll to it', async ({
@ -181,7 +179,7 @@ extrude001 = extrude(sketch001, length = 5)`
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
// await scene.settled(cmdBar)
await scene.settled(cmdBar)
// Ensure badge is present
const codePaneButtonHolder = page.locator('#code-button-holder')

View File

@ -58,6 +58,12 @@ test(
await expect(submitButton).toBeVisible()
await page.keyboard.press('Enter')
// Look out for the toast message
const exportingToastMessage = page.getByText(`Exporting...`)
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
await expect(exportingToastMessage).toBeVisible()
await expect(alreadyExportingToastMessage).not.toBeVisible()
// Expect it to succeed
const errorToastMessage = page.getByText(`Error while exporting`)
const engineErrorToastMessage = page.getByText(`Nothing to export`)
@ -66,6 +72,7 @@ test(
const successToastMessage = page.getByText(`Exported successfully`)
await expect(successToastMessage).toBeVisible()
await expect(exportingToastMessage).not.toBeVisible()
// Check for the exported file
const firstFileFullPath = path.resolve(

View File

@ -912,7 +912,7 @@ a1 = startSketchOn(offsetPlane(XY, offset = 10))
|> close()
|> revolve(
axis = revolveAxis,
angle = 90deg
angle = 90
)
`
)
@ -1533,6 +1533,7 @@ sketch001 = startSketchOn(XZ)
await homePage.goToModelingScene()
await scene.connectionEstablished()
await scene.settled(cmdBar)
await scene.expectPixelColor(
TEST_COLORS.DARK_MODE_BKGD,

View File

@ -38,7 +38,7 @@ extrude001 = extrude(sketch002, length = 10)
const FEATURE_TREE_SKETCH_CODE = `sketch001 = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(angle = 0deg, length = 4, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 4, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 2, tag = $rectangleSegmentB001)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])

View File

@ -155,12 +155,6 @@ export class CmdBarFixture {
}
}
closeCmdBar = async () => {
const cmdBarCloseBtn = this.page.getByTestId('command-bar-close-button')
await cmdBarCloseBtn.click()
await expect(this.cmdBarElement).not.toBeVisible()
}
get cmdSearchInput() {
return this.page.getByTestId('cmd-bar-search')
}
@ -304,27 +298,4 @@ export class CmdBarFixture {
`Monitoring text-to-cad API requests. Output will be saved to: ${outputPath}`
)
}
async toBeOpened() {
// Check that the command bar is opened
await expect(this.cmdBarElement).toBeVisible({ timeout: 10_000 })
}
async expectArgValue(value: string) {
// Check the placeholder project name exists
const actualArgument = await this.cmdBarElement
.getByTestId('cmd-bar-arg-value')
.inputValue()
const expectedArgument = value
expect(actualArgument).toBe(expectedArgument)
}
async expectCommandName(value: string) {
// Check the placeholder project name exists
const actual = await this.cmdBarElement
.getByTestId('command-name')
.textContent()
const expected = value
expect(actual).toBe(expected)
}
}

View File

@ -24,7 +24,6 @@ export class HomePageFixture {
projectTextName!: Locator
sortByDateBtn!: Locator
sortByNameBtn!: Locator
appHeader!: Locator
tutorialBtn!: Locator
constructor(page: Page) {
@ -45,7 +44,6 @@ export class HomePageFixture {
this.sortByDateBtn = this.page.getByTestId('home-sort-by-modified')
this.sortByNameBtn = this.page.getByTestId('home-sort-by-name')
this.appHeader = this.page.getByTestId('app-header')
this.tutorialBtn = this.page.getByTestId('home-tutorial-button')
}
@ -127,11 +125,4 @@ export class HomePageFixture {
await this.createAndGoToProject(name)
}
isNativeFileMenuCreated = async () => {
await expect(this.appHeader).toHaveAttribute(
'data-native-file-menu',
'true'
)
}
}

View File

@ -46,7 +46,6 @@ export class SceneFixture {
public networkToggleConnected!: Locator
public engineConnectionsSpinner!: Locator
public startEditSketchBtn!: Locator
public appHeader!: Locator
constructor(page: Page) {
this.page = page
@ -58,7 +57,6 @@ export class SceneFixture {
this.startEditSketchBtn = page
.getByRole('button', { name: 'Start Sketch' })
.or(page.getByRole('button', { name: 'Edit Sketch' }))
this.appHeader = this.page.getByTestId('app-header')
}
private _serialiseScene = async (): Promise<SceneSerialised> => {
const camera = await this.getCameraInfo()
@ -282,13 +280,6 @@ export class SceneFixture {
await expect(buttonToTest).toBeVisible()
await buttonToTest.click()
}
isNativeFileMenuCreated = async () => {
await expect(this.appHeader).toHaveAttribute(
'data-native-file-menu',
'true'
)
}
}
function isColourArray(

View File

@ -16,7 +16,7 @@ test.describe('Import UI tests', () => {
path.join(projectDir, 'toBeImported.kcl'),
`sketch001 = startSketchOn(XZ)
profile001 = startProfile(sketch001, at = [281.54, 305.81])
|> angledLine(angle = 0deg, length = 123.43, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 123.43, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 85.99)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -33,7 +33,7 @@ importedCube
sketch001 = startSketchOn(XZ)
profile001 = startProfile(sketch001, at = [-134.53, -56.17])
|> angledLine(angle = 0deg, length = 79.05, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 79.05, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 76.28)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $seg01)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)

File diff suppressed because it is too large Load Diff

View File

@ -365,7 +365,7 @@ test.describe('Point-and-click tests', () => {
clickCoords: { x: 677, y: 87 },
cameraPos: { x: -6200, y: 1500, z: 6200 },
cameraTarget: { x: 8300, y: 1100, z: 4800 },
beforeChamferSnippet: `angledLine(angle = 0deg, length = 268.43, tag = $rectangleSegmentA001)chamfer(
beforeChamferSnippet: `angledLine(angle = 0, length = 268.43, tag = $rectangleSegmentA001)chamfer(
length = 30,
tags = [
getNextAdjacentEdge(yo),
@ -407,7 +407,7 @@ test.describe('Point-and-click tests', () => {
sketch001 = startSketchOn(XZ)
|> startProfile(at = [75.8, 317.2]) // [$startCapTag, $EndCapTag]
|> angledLine(angle = 0deg, length = 268.43, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 268.43, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 217.26, tag = $seg01)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $yo)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
@ -419,28 +419,28 @@ extrude001 = extrude(sketch001, length = 100)
|> chamfer(length = 30, tags = [getNextAdjacentEdge(yo)], tag = $seg06)
sketch002 = startSketchOn(extrude001, face = seg03)
profile001 = startProfile(sketch002, at = [205.96, 254.59])
|> angledLine(angle = 0deg, length = 11.39, tag = $rectangleSegmentA002)
|> angledLine(angle = 0, length = 11.39, tag = $rectangleSegmentA002)
|> angledLine(angle = segAng(rectangleSegmentA002) - 90, length = 105.26)
|> angledLine(angle = segAng(rectangleSegmentA002), length = -segLen(rectangleSegmentA002))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
sketch003 = startSketchOn(extrude001, face = seg04)
profile002 = startProfile(sketch003, at = [-209.64, 255.28])
|> angledLine(angle = 0deg, length = 11.56, tag = $rectangleSegmentA003)
|> angledLine(angle = 0, length = 11.56, tag = $rectangleSegmentA003)
|> angledLine(angle = segAng(rectangleSegmentA003) - 90, length = 106.84)
|> angledLine(angle = segAng(rectangleSegmentA003), length = -segLen(rectangleSegmentA003))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
sketch004 = startSketchOn(extrude001, face = seg05)
profile003 = startProfile(sketch004, at = [82.57, 322.96])
|> angledLine(angle = 0deg, length = 11.16, tag = $rectangleSegmentA004)
|> angledLine(angle = 0, length = 11.16, tag = $rectangleSegmentA004)
|> angledLine(angle = segAng(rectangleSegmentA004) - 90, length = 103.07)
|> angledLine(angle = segAng(rectangleSegmentA004), length = -segLen(rectangleSegmentA004))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
sketch005 = startSketchOn(extrude001, face = seg06)
profile004 = startProfile(sketch005, at = [-23.43, 19.69])
|> angledLine(angle = 0deg, length = 9.1, tag = $rectangleSegmentA005)
|> angledLine(angle = 0, length = 9.1, tag = $rectangleSegmentA005)
|> angledLine(angle = segAng(rectangleSegmentA005) - 90, length = 84.07)
|> angledLine(angle = segAng(rectangleSegmentA005), length = -segLen(rectangleSegmentA005))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -504,7 +504,7 @@ profile004 = startProfile(sketch005, at = [-23.43, 19.69])
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfile(at = [75.8, 317.2])
|> angledLine(angle = 0deg, length = 268.43, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 268.43, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 217.26, tag = $seg01)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $yo)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
@ -526,7 +526,7 @@ chamf = chamfer(
)
sketch002 = startSketchOn(extrude001, face = seg03)
profile001 = startProfile(sketch002, at = [205.96, 254.59])
|> angledLine(angle = 0deg, length = 11.39, tag = $rectangleSegmentA002)
|> angledLine(angle = 0, length = 11.39, tag = $rectangleSegmentA002)
|> angledLine(angle = segAng(rectangleSegmentA002) - 90, length = 105.26)
|> angledLine(angle = segAng(rectangleSegmentA002), length = -segLen(rectangleSegmentA002))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -1776,7 +1776,7 @@ sketch002 = startSketchOn(XZ)
initialCode: `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(YZ)
profile001 = startProfile(sketch001, at = [-400, -400])
|> angledLine(angle = 0deg, length = 800, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 800, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) + 90, length = 800)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -1931,37 +1931,50 @@ sketch002 = startSketchOn(XZ)
})
})
test(`Sweep point-and-click helix`, async ({
test(`Sweep point-and-click failing validation`, async ({
context,
page,
homePage,
scene,
editor,
toolbar,
cmdBar,
}) => {
const circleCode = `circle(sketch001, center = [0, -1], radius = .1)`
const initialCode = `helix001 = helix(
axis = X,
radius = 1,
length = 10,
revolutions = 10,
angleStart = 0,
ccw = false,
)
sketch001 = startSketchOn(XZ)
profile001 = ${circleCode}`
const sweepDeclaration = 'sweep001 = sweep(profile001, path = helix001)'
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(YZ)
|> circle(
center = [0, 0],
radius = 500
)
sketch002 = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> xLine(length = -500)
|> line(endAbsolute = [-2000, 500])
`
await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode)
}, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await scene.settled(cmdBar)
await test.step(`Add sweep through the command bar flow`, async () => {
await toolbar.openPane('feature-tree')
// One dumb hardcoded screen pixel value
const testPoint = { x: 700, y: 250 }
const [clickOnSketch1] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
const [clickOnSketch2] = scene.makeMouseHelpers(
testPoint.x - 50,
testPoint.y
)
await test.step(`Look for sketch001`, async () => {
await toolbar.closePane('code')
await scene.expectPixelColor([53, 53, 53], testPoint, 15)
})
await test.step(`Go through the command bar flow and fail validation with a toast`, async () => {
await toolbar.sweepButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({
commandName: 'Sweep',
currentArgKey: 'sketches',
@ -1974,8 +1987,7 @@ profile001 = ${circleCode}`
highlightedHeaderArg: 'sketches',
stage: 'arguments',
})
await editor.scrollToText(circleCode)
await page.getByText(circleCode).click()
await clickOnSketch1()
await cmdBar.progressCmdBar()
await cmdBar.expectState({
commandName: 'Sweep',
@ -1989,39 +2001,11 @@ profile001 = ${circleCode}`
highlightedHeaderArg: 'path',
stage: 'arguments',
})
const helix = await toolbar.getFeatureTreeOperation('Helix', 0)
await helix.click()
await cmdBar.expectState({
commandName: 'Sweep',
currentArgKey: 'path',
currentArgValue: '',
headerArguments: {
Sectional: '',
Sketches: '1 face',
Path: '',
},
highlightedHeaderArg: 'path',
stage: 'arguments',
})
await clickOnSketch2()
await cmdBar.progressCmdBar()
await cmdBar.expectState({
commandName: 'Sweep',
headerArguments: {
Sketches: '1 face',
Path: '1 helix',
Sectional: '',
},
stage: 'review',
})
await cmdBar.progressCmdBar()
await editor.expectEditor.toContain(sweepDeclaration)
})
await test.step('Delete sweep via feature tree selection', async () => {
const sweep = await toolbar.getFeatureTreeOperation('Sweep', 0)
await sweep.click()
await page.keyboard.press('Delete')
await editor.expectEditor.not.toContain(sweepDeclaration)
await expect(
page.getByText('Unable to sweep with the current selection. Reason:')
).toBeVisible()
})
})
@ -3643,6 +3627,67 @@ profile001 = startProfile(sketch001, at = [-20, 20])
})
})
test(`Shell dry-run validation rejects sweeps`, async ({
context,
page,
homePage,
scene,
editor,
toolbar,
cmdBar,
}) => {
const initialCode = `sketch001 = startSketchOn(YZ)
|> circle(
center = [0, 0],
radius = 500
)
sketch002 = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> xLine(length = -2000)
sweep001 = sweep(sketch001, path = sketch002)
`
await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode)
}, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await scene.settled(cmdBar)
// One dumb hardcoded screen pixel value
const testPoint = { x: 500, y: 250 }
const [clickOnSweep] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
await test.step(`Confirm sweep exists`, async () => {
await toolbar.closePane('code')
await scene.expectPixelColor([231, 231, 231], testPoint, 15)
})
await test.step(`Go through the Shell flow and fail validation with a toast`, async () => {
await toolbar.shellButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({
stage: 'arguments',
currentArgKey: 'selection',
currentArgValue: '',
headerArguments: {
Selection: '',
Thickness: '',
},
highlightedHeaderArg: 'selection',
commandName: 'Shell',
})
await clickOnSweep()
await page.waitForTimeout(500)
await cmdBar.progressCmdBar()
await expect(
page.getByText('Unable to shell with the current selection. Reason:')
).toBeVisible()
await page.waitForTimeout(1000)
})
})
test.describe('Revolve point and click workflows', () => {
test('Base case workflow, auto spam continue in command bar', async ({
context,
@ -3656,7 +3701,7 @@ profile001 = startProfile(sketch001, at = [-20, 20])
const initialCode = `
sketch001 = startSketchOn(XZ)
|> startProfile(at = [-100.0, 100.0])
|> angledLine(angle = 0deg, length = 200.0, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 200.0, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 200, tag = $rectangleSegmentB001)
|> angledLine(
angle=segAng(rectangleSegmentA001),
@ -3668,7 +3713,7 @@ tag=$rectangleSegmentC001,
extrude001 = extrude(sketch001, length = 200)
sketch002 = startSketchOn(extrude001, face = rectangleSegmentA001)
|> startProfile(at = [-66.77, 84.81])
|> angledLine(angle = 180deg, length = 27.08, tag = $rectangleSegmentA002)
|> angledLine(angle = 180, length = 27.08, tag = $rectangleSegmentA002)
|> angledLine(
angle=segAng(rectangleSegmentA002) - 90,
length=27.8,
@ -3702,7 +3747,7 @@ tag=$rectangleSegmentC002,
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360deg, axis = X)`
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = X)`
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
// Edit flow
@ -3735,7 +3780,7 @@ tag=$rectangleSegmentC002,
await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree')
await editor.expectEditor.toContain(
newCodeToFind.replace('angle = 360deg', 'angle = ' + newAngle)
newCodeToFind.replace('angle = 360', 'angle = ' + newAngle)
)
})
test('revolve surface around edge from an extruded solid2d', async ({
@ -3749,7 +3794,7 @@ tag=$rectangleSegmentC002,
}) => {
const initialCode = `sketch001 = startSketchOn(XZ)
|> startProfile(at = [-102.57, 101.72])
|> angledLine(angle = 0deg, length = 202.6, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 202.6, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 202.6, tag = $rectangleSegmentB001)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -3775,13 +3820,13 @@ sketch002 = startSketchOn(extrude001, face = rectangleSegmentA001)
await toolbar.revolveButton.click()
await cmdBar.progressCmdBar()
await page.getByText('Edge', { exact: true }).click()
const lineCodeToSelection = `angledLine(angle = 0deg, length = 202.6, tag = $rectangleSegmentA001)`
const lineCodeToSelection = `angledLine(angle = 0, length = 202.6, tag = $rectangleSegmentA001)`
await page.getByText(lineCodeToSelection).click()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360deg, axis = rectangleSegmentA001)`
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = rectangleSegmentA001)`
await editor.expectEditor.toContain(newCodeToFind)
// Edit flow
@ -3819,7 +3864,7 @@ sketch002 = startSketchOn(extrude001, face = rectangleSegmentA001)
await toolbar.closePane('feature-tree')
await editor.expectEditor.toContain('angle001 = ' + newAngle)
await editor.expectEditor.toContain(
newCodeToFind.replace('angle = 360deg', 'angle = angle001')
newCodeToFind.replace('angle = 360', 'angle = angle001')
)
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
})
@ -3838,7 +3883,7 @@ sketch002 = startSketchOn(extrude001, face = rectangleSegmentA001)
|> xLine(length = 2.6)
sketch001 = startSketchOn(-XY)
|> startProfile(at = [-0.48, 1.25])
|> angledLine(angle = 0deg, length = 2.38, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 2.38, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 2.4, tag = $rectangleSegmentB001)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -3876,7 +3921,7 @@ sketch002 = startSketchOn(extrude001, face = rectangleSegmentA001)
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
const newCodeToFind = `revolve001 = revolve(sketch003, angle = 360deg, axis = seg01)`
const newCodeToFind = `revolve001 = revolve(sketch003, angle = 360, axis = seg01)`
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
// Edit flow
@ -3909,7 +3954,7 @@ sketch002 = startSketchOn(extrude001, face = rectangleSegmentA001)
await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree')
await editor.expectEditor.toContain(
newCodeToFind.replace('angle = 360deg', 'angle = ' + newAngle)
newCodeToFind.replace('angle = 360', 'angle = ' + newAngle)
)
})
})
@ -4893,39 +4938,9 @@ path001 = startProfile(sketch001, at = [0, 0])
await page.getByTestId('context-menu-delete').click()
await scene.settled(cmdBar)
await editor.expectEditor.not.toContain(
`revolve001 = revolve([profile001, profile002], axis = XY, angle = 180deg)`,
`revolve001 = revolve([profile001, profile002], axis = XY, angle = 180)`,
{ shouldNormalise: true }
)
})
})
test(`Point and click codemods can't run on KCL errors`, async ({
context,
page,
homePage,
scene,
editor,
toolbar,
cmdBar,
}) => {
const badCode = `sketch001 = startSketchOn(XZ)
profile001 = circle(sketch001, center = [0, 0], radius = 1)
extrude001 = extrude(profile001 length = 1)`
await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode)
}, badCode)
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await scene.connectionEstablished()
await test.step(`Start Sketch is disabled`, async () => {
await expect(toolbar.startSketchBtn).not.toBeEnabled()
await editor.expectEditor.toContain(badCode, { shouldNormalise: true })
})
await test.step(`Helix is disabled`, async () => {
await expect(toolbar.helixButton).not.toBeEnabled()
await editor.expectEditor.toContain(badCode, { shouldNormalise: true })
})
})
})

View File

@ -1818,6 +1818,7 @@ test(
'extrude-custom-plane.kcl',
'extrude-inside-fn-with-tags.kcl',
'fillet-and-shell.kcl',
'fillet_duplicate_tags.kcl',
'focusrite_scarlett_mounting_bracket.kcl',
'function_sketch.kcl',
'function_sketch_with_position.kcl',
@ -1825,6 +1826,7 @@ test(
'helix_defaults.kcl',
'helix_defaults_negative_extrude.kcl',
'helix_with_length.kcl',
'i_shape.kcl',
'kittycad_svg.kcl',
'lego.kcl',
'lsystem.kcl',

View File

@ -47,7 +47,7 @@ b
const importedFile = `sketch003 = startSketchOn(XY)
|> startProfile(at = [52.92, 157.81])
|> angledLine(angle = 0deg, length = 176.4, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 176.4, tag = $rectangleSegmentA001)
|> angledLine(
angle = segAng(rectangleSegmentA001) - 90,
length = 53.4,

View File

@ -23,7 +23,7 @@ sketch002 = startSketchOn(XZ)
extrude002 = extrude(sketch002, length = 50)
sketch003 = startSketchOn(XY)
|> startProfile(at = [52.92, 157.81])
|> angledLine(angle = 0deg, length = 176.4, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 176.4, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 53.4, tag = $rectangleSegmentB001)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])

View File

@ -19,12 +19,11 @@ test.describe('Regression tests', () => {
context,
page,
homePage,
scene,
}) => {
// because the model has `line([0,0]..` it is valid code, but the model is invalid
// regression test for https://github.com/KittyCAD/modeling-app/issues/3251
// Since the bad model also found as issue with the artifact graph, which in tern blocked the editor diognostics
// const u = await getUtils(page)
const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
'persistCode',
@ -41,8 +40,7 @@ test.describe('Regression tests', () => {
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await scene.connectionEstablished()
// await u.waitForPageLoad()
await u.waitForPageLoad()
// error in guter
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
@ -53,11 +51,8 @@ test.describe('Regression tests', () => {
// the close doesn't work
// when https://github.com/KittyCAD/modeling-app/issues/3268 is closed
// this test will need updating
const crypticErrorText = `Cannot close a path that is non-planar or with duplicate vertices.
Internal engine error on request`
const crypticErrorText = `ApiError`
await expect(page.getByText(crypticErrorText).first()).toBeVisible()
// Ensure we didn't nest the json.
await expect(page.getByText('ApiError')).not.toBeVisible()
})
test('user should not have to press down twice in cmdbar', async ({
page,
@ -72,7 +67,7 @@ Internal engine error on request`
'persistCode',
`sketch001 = startSketchOn(XY)
|> startProfile(at = [82.33, 238.21])
|> angledLine(angle = 0deg, length = 288.63, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 288.63, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 197.97, tag = $rectangleSegmentB001)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -190,8 +185,8 @@ extrude001 = extrude(sketch001, length = 50)
page.locator('.pretty-json-container >> text=myVar:"67')
).toBeVisible()
})
test('ProgramMemory can be serialised', async ({ page, homePage, scene }) => {
// const u = await getUtils(page)
test('ProgramMemory can be serialised', async ({ page, homePage }) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
@ -216,12 +211,11 @@ extrude001 = extrude(sketch001, length = 50)
// Listen for all console events and push the message text to an array
page.on('console', (message) => messages.push(message.text()))
await homePage.goToModelingScene()
// await u.waitForPageLoad()
await scene.connectionEstablished()
await u.waitForPageLoad()
// wait for execution done
// await u.openDebugPanel()
// await u.expectCmdLog('[data-message-type="execution-done"]')
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
const forbiddenMessages = ['cannot serialize tagged newtype variant']
forbiddenMessages.forEach((forbiddenMessage) => {
@ -235,7 +229,6 @@ extrude001 = extrude(sketch001, length = 50)
context,
page,
homePage,
scene,
}) => {
const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio
@ -245,7 +238,7 @@ extrude001 = extrude(sketch001, length = 50)
'persistCode',
`exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(angle = 50deg, length = 45 )
|> angledLine(angle = 50, length = 45 )
|> yLine(endAbsolute = 0)
|> close()
|>
@ -254,10 +247,11 @@ extrude001 = extrude(sketch001, length = 50)
shell(exampleSketch, faces = ['end'], thickness = 0.25)`
)
})
await homePage.goToModelingScene()
await scene.connectionEstablished()
await expect(async () => {
await homePage.goToModelingScene()
await u.waitForPageLoad()
// error in guter
await expect(page.locator('.cm-lint-marker-error')).toBeVisible({
timeout: 1_000,
@ -301,7 +295,7 @@ extrude001 = extrude(sketch001, length = 50)
page.locator('.cm-content')
).toContainText(`exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(angle = 50deg, length = 45 )
|> angledLine(angle = 50, length = 45 )
|> yLine(endAbsolute = 0)
|> close()
@ -321,7 +315,7 @@ extrude001 = extrude(sketch001, length = 50)
`@settings(defaultLengthUnit = mm)
sketch002 = startSketchOn(XY)
profile002 = startProfile(sketch002, at = [72.24, -52.05])
|> angledLine(angle = 0deg, length = 181.26, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 181.26, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 21.54)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -335,10 +329,10 @@ extrude002 = extrude(profile002, length = 150)
)
const websocketPromise = page.waitForEvent('websocket')
await toolbar.closePane('code')
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await toolbar.closePane('code')
const websocket = await websocketPromise
await scene.connectionEstablished()
@ -551,49 +545,10 @@ extrude002 = extrude(profile002, length = 150)
expect(alreadyExportingToastMessage).not.toBeVisible(),
])
const count = await successToastMessage.count()
await expect(count).toBeGreaterThanOrEqual(2)
await expect(successToastMessage).toHaveCount(2)
})
})
test(
`Network health indicator only appears in modeling view`,
{ tag: '@electron' },
async ({ context, page }) => {
await context.folderSetupFn(async (dir) => {
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
path.join(bracketDir, 'main.kcl')
)
})
await page.setBodyDimensions({ width: 1200, height: 500 })
// Locators
const projectsHeading = page.getByRole('heading', {
name: 'Projects',
})
const projectLink = page.getByRole('link', { name: 'bracket' })
const networkHealthIndicator = page.getByTestId('network-toggle')
await test.step('Check the home page', async () => {
await expect(projectsHeading).toBeVisible()
await expect(projectLink).toBeVisible()
await expect(networkHealthIndicator).not.toBeVisible()
})
await test.step('Open the project', async () => {
await projectLink.click()
})
await test.step('Check the modeling view', async () => {
await expect(projectsHeading).not.toBeVisible()
await expect(networkHealthIndicator).toBeVisible()
})
}
)
test(`View gizmo stays visible even when zoomed out all the way`, async ({
page,
homePage,

View File

@ -1222,7 +1222,7 @@ profile001 = startProfile(sketch001, at = [299.72, 230.82])
fn lug(origin, length, diameter, plane) {
lugSketch = startSketchOn(plane)
|> startProfile(at = [origin[0] + lugDiameter / 2, origin[1]])
|> angledLine(angle = 60deg, lengthY = lugHeadLength)
|> angledLine(angle = 60, lengthY = lugHeadLength)
|> xLine(endAbsolute = 0 + .001)
|> yLine(endAbsolute = 0)
|> close()
@ -1287,7 +1287,7 @@ extrude001 = extrude(profile001, length = 200)
|> translate(x = 3.14, y = 3.14, z = -50.154)
sketch002 = startSketchOn(XY)
profile002 = startProfile(sketch002, at = [72.2, -52.05])
|> angledLine(angle = 0deg, length = 181.26, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 181.26, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 21.54)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $mySeg)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg01)
@ -1365,18 +1365,18 @@ solid001 = subtract([extrude001], tools = [extrude002])
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`fn in2mm(@inches) {
`fn in2mm = (inches) => {
return inches * 25.4
}
railTop = in2mm(.748)
railSide = in2mm(.024)
railBaseWidth = in2mm(.612)
railWideWidth = in2mm(.835)
railBaseLength = in2mm(.200)
railClampable = in2mm(.200)
const railTop = in2mm(.748)
const railSide = in2mm(.024)
const railBaseWidth = in2mm(.612)
const railWideWidth = in2mm(.835)
const railBaseLength = in2mm(.200)
const railClampable = in2mm(.200)
rail = startSketchOn(XZ)
const rail = startSketchOn(XZ)
|> startProfile(at = [-railTop / 2, railClampable + railBaseLength])
|> line(endAbsolute = [
railTop / 2,
@ -2058,7 +2058,7 @@ profile003 = startProfile(sketch001, at = [206.63, -56.73])
)
await crnRect1point2()
await editor.expectEditor.toContain(
`|> angledLine(angle = 0deg, length = 2.37, tag = $rectangleSegmentA001)
`|> angledLine(angle = 0, length = 2.37, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 7.8)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -2073,7 +2073,7 @@ profile003 = startProfile(sketch001, at = [206.63, -56.73])
await crnRect2point2()
await page.waitForTimeout(300)
await editor.expectEditor.toContain(
`|> angledLine(angle = 0deg, length = 5.49, tag = $rectangleSegmentA002)
`|> angledLine(angle = 0, length = 5.49, tag = $rectangleSegmentA002)
|> angledLine(angle = segAng(rectangleSegmentA002) - 90, length = 4.14)
|> angledLine(angle = segAng(rectangleSegmentA002), length = -segLen(rectangleSegmentA002))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -2092,7 +2092,7 @@ profile003 = startProfile(sketch001, at = [206.63, -56.73])
await cntrRect1point2()
await page.waitForTimeout(300)
await editor.expectEditor.toContain(
`|> angledLine(angle = 0deg, length = 7.06, tag = $rectangleSegmentA003)
`|> angledLine(angle = 0, length = 7.06, tag = $rectangleSegmentA003)
|> angledLine(angle = segAng(rectangleSegmentA003) + 90, length = 4.34)
|> angledLine(angle = segAng(rectangleSegmentA003), length = -segLen(rectangleSegmentA003))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -2108,7 +2108,7 @@ profile003 = startProfile(sketch001, at = [206.63, -56.73])
await cntrRect2point2()
await page.waitForTimeout(300)
await editor.expectEditor.toContain(
`|> angledLine(angle = 0deg, length = 3.12, tag = $rectangleSegmentA004)
`|> angledLine(angle = 0, length = 3.12, tag = $rectangleSegmentA004)
|> angledLine(angle = segAng(rectangleSegmentA004) + 90, length = 6.24)
|> angledLine(angle = segAng(rectangleSegmentA004), length = -segLen(rectangleSegmentA004))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -2258,7 +2258,7 @@ profile001 = startProfile(sketch001, at = [6.24, 4.54])
|> line(end = [8.61, 0.74])
|> line(end = [10.99, -5.22])
profile002 = startProfile(sketch001, at = [11.19, 5.02])
|> angledLine(angle = 0deg, length = 10.78, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 10.78, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 4.14)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -2370,7 +2370,7 @@ profile004 = circleThreePoint(sketch001, p1 = [13.44, -6.8], p2 = [13.39, -2.07]
await page.waitForTimeout(100)
await rectEnd()
await editor.expectEditor.toContain(
`|> angledLine(angle = 180deg, length = 1.97, tag = $rectangleSegmentA002)
`|> angledLine(angle = 180, length = 1.97, tag = $rectangleSegmentA002)
|> angledLine(angle = segAng(rectangleSegmentA002) + 90, length = 3.89)
|> angledLine(angle = segAng(rectangleSegmentA002), length = -segLen(rectangleSegmentA002))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -2396,7 +2396,7 @@ profile001 = startProfile(sketch001, at = [6.24, 4.54])
|> line(end = [8.61, 0.74])
|> line(end = [10.99, -5.22])
profile002 = startProfile(sketch001, at = [11.19, 5.02])
|> angledLine(angle = 0deg, length = 10.78, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 10.78, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 4.14)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -2501,7 +2501,7 @@ profile001 = startProfile(sketch001, at = [-63.43, 193.08])
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
profile003 = startProfile(sketch001, at = [16.79, 38.24])
|> angledLine(angle = 0deg, length = 182.82, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 182.82, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 105.71)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -2726,7 +2726,7 @@ profile002 = startProfile(sketch002, at = [0.75, 13.46])
|> line(end = [4.52, 3.79])
|> line(end = [5.98, -2.81])
profile003 = startProfile(sketch002, at = [3.19, 13.3])
|> angledLine(angle = 0deg, length = 6.64, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 6.64, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 2.81)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -2744,7 +2744,7 @@ profile006 = startProfile(sketch002, at = [9.65, 3.82])
|> close()
revolve001 = revolve(
profile004,
angle = 45deg,
angle = 45,
axis = getNextAdjacentEdge(seg01)
)
extrude002 = extrude(profile006, length = 4)
@ -2768,14 +2768,14 @@ profile010 = circle(
radius = 2.67
)
profile011 = startProfile(sketch003, at = [5.07, -6.39])
|> angledLine(angle = 0deg, length = 4.54, tag = $rectangleSegmentA002)
|> angledLine(angle = 0, length = 4.54, tag = $rectangleSegmentA002)
|> angledLine(angle = segAng(rectangleSegmentA002) - 90, length = 4.17)
|> angledLine(angle = segAng(rectangleSegmentA002), length = -segLen(rectangleSegmentA002))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
extrude003 = extrude(profile011, length = 2.5)
// TODO this breaks the test,
// revolve002 = revolve(profile008, angle = 45deg, axis = seg02)
// revolve002 = revolve(profile008, angle = 45, axis = seg02)
`
)
})
@ -2921,7 +2921,7 @@ loft([profile001, profile002])
)
await rect1Crn2()
await editor.expectEditor.toContain(
`angledLine(angle = 0deg, length = 113.01, tag = $rectangleSegmentA001)`
`angledLine(angle = 0, length = 113.01, tag = $rectangleSegmentA001)`
)
})
test('Can enter sketch loft edges offsetPlane and continue sketch', async ({
@ -2990,7 +2990,7 @@ loft([profile001, profile002])
)
await rect1Crn2()
await editor.expectEditor.toContain(
`angledLine(angle = 0deg, length = 106.42], tag = $rectangleSegmentA001)`
`angledLine(angle = 0, length = 106.42], tag = $rectangleSegmentA001)`
)
await page.waitForTimeout(100)
})
@ -3212,7 +3212,7 @@ test.describe('manual edits during sketch mode', () => {
extrude001 = extrude(profile001, length = 500)
sketch002 = startSketchOn(extrude001, face = seg01)
profile002 = startProfile(sketch002, at = [83.39, 329.15])
|> angledLine(angle = 0deg, length = 119.61, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 119.61, tag = $rectangleSegmentA001)
|> angledLine(length = 156.54, angle = -28)
|> angledLine(
angle = -151,
@ -3348,7 +3348,7 @@ profile001 = startProfile(sketch001, at = [106.68, 89.77])
extrude001 = extrude(profile001, length = 500)
sketch002 = startSketchOn(extrude001, face = seg01)
profile002 = startProfile(sketch002, at = [83.39, 329.15])
|> angledLine(angle = 0deg, length = 119.61, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 119.61, tag = $rectangleSegmentA001)
|> angledLine(length = 219.2, angle = -56)
|> angledLine(angle = -151, length = 116.27)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -3387,7 +3387,7 @@ profile003 = startProfile(sketch002, at = [-201.08, 254.17])
extrude001 = extrude(profile001, length = 500)
sketch002 = startSketchOn(extrude001, face = seg01)
profile002 = startProfile(sketch002, at = [83.39, 329.15])
|> angledLine(angle = 0deg, length = 119.61, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 119.61, tag = $rectangleSegmentA001)
|> angledLine(length = 156.54, angle = -28)
|> angledLine(
angle = -151,
@ -3496,69 +3496,6 @@ profile001 = startProfile(sketch001, at = [-102.72, 237.44])
).toBeVisible()
})
// Ensure feature tree is not showing previous file's content when switching to a file with KCL errors.
test('Feature tree shows correct sketch count per file', async ({
context,
homePage,
scene,
toolbar,
cmdBar,
page,
}) => {
const u = await getUtils(page)
// Setup project with files.
const GOOD_KCL = `sketch001 = startSketchOn(XZ)
profile001 = startProfile(sketch001, at = [220.81, 253.8])
|> line(end = [132.84, -151.31])
|> line(end = [25.51, 167.15])
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
sketch002 = startSketchOn(XZ)
profile002 = startProfile(sketch002, at = [158.35, -70.82])
|> line(end = [73.9, -152.19])
|> line(end = [85.33, 135.48])
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()`
const ERROR_KCL = `sketch001 = startSketchOn(XZ)
profile001 = startProfile(sketch001, at = [127.56, 179.02])
|> line(end = [132.84, -112.6])
|> line(end = [85.33, 234.01])
|> line(enfd = [-137.23, -54.55])`
await context.folderSetupFn(async (dir) => {
const projectDir = path.join(dir, 'multi-file-sketch-test')
await fs.mkdir(projectDir, { recursive: true })
await Promise.all([
fs.writeFile(path.join(projectDir, 'good.kcl'), GOOD_KCL, 'utf-8'),
fs.writeFile(path.join(projectDir, 'error.kcl'), ERROR_KCL, 'utf-8'),
])
})
await page.setBodyDimensions({ width: 1000, height: 800 })
await homePage.openProject('multi-file-sketch-test')
await scene.connectionEstablished()
await u.closeDebugPanel()
await toolbar.openFeatureTreePane()
await toolbar.openPane('files')
await toolbar.openFile('good.kcl')
await expect(
toolbar.featureTreePane.getByRole('button', { name: 'Sketch' })
).toHaveCount(2)
await toolbar.openFile('error.kcl')
await expect(
toolbar.featureTreePane.getByRole('button', { name: 'Sketch' })
).toHaveCount(0)
})
test('adding a syntax error, recovers after fixing', async ({
page,
homePage,

View File

@ -1,3 +1,4 @@
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
import { TEST_SETTINGS, TEST_SETTINGS_KEY } from '@e2e/playwright/storageStates'
@ -8,7 +9,6 @@ import {
settingsToToml,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
test.beforeEach(async ({ page, context }) => {
// Make the user avatar image always 404
@ -766,7 +766,7 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
})
})
test('theme persists', async ({ page, context, homePage }) => {
test('theme persists', async ({ page, context }) => {
const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
@ -784,7 +784,7 @@ test('theme persists', async ({ page, context, homePage }) => {
await page.setViewportSize({ width: 1200, height: 500 })
await homePage.goToModelingScene()
await u.waitForAuthSkipAppStart()
await page.waitForTimeout(500)
// await page.getByRole('link', { name: 'Settings Settings (tooltip)' }).click()
@ -812,7 +812,7 @@ test('theme persists', async ({ page, context, homePage }) => {
// Disconnect and reconnect to check the theme persists through a reload
// Expect the network to be down
await expect(networkToggle).toContainText('Problem')
await expect(networkToggle).toContainText('Offline')
// simulate network up
await u.emulateNetworkConditions({
@ -845,7 +845,7 @@ test.describe('code color goober', { tag: '@snapshot' }, () => {
sweepPath = startSketchOn(XZ)
|> startProfile(at = [0.05, 0.05])
|> line(end = [0, 7])
|> tangentialArc(angle = 90deg, radius = 5)
|> tangentialArc(angle = 90, radius = 5)
|> line(end = [-3, 0])
|> tangentialArc(angle = -90, radius = 5)
|> line(end = [0, 7])
@ -873,50 +873,6 @@ sweepSketch = startSketchOn(XY)
mask: lowerRightMasks(page),
})
})
test('code color goober works with single quotes', async ({
page,
context,
scene,
cmdBar,
}) => {
const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`// Create a pipe using a sweep.
// Create a path for the sweep.
sweepPath = startSketchOn(XZ)
|> startProfile(at = [0.05, 0.05])
|> line(end = [0, 7])
|> tangentialArc(angle = 90deg, radius = 5)
|> line(end = [-3, 0])
|> tangentialArc(angle = -90, radius = 5)
|> line(end = [0, 7])
sweepSketch = startSketchOn(XY)
|> startProfile(at = [2, 0])
|> arc(angleStart = 0, angleEnd = 360, radius = 2)
|> sweep(path = sweepPath)
|> appearance(
color = '#bb00ff',
metalness = 90,
roughness = 90
)
`
)
})
await page.setViewportSize({ width: 1200, height: 1000 })
await u.waitForAuthSkipAppStart()
await scene.settled(cmdBar)
await expect(page, 'expect small color widget').toHaveScreenshot({
maxDiffPixels: 100,
mask: lowerRightMasks(page),
})
})
test('code color goober opening window', async ({
page,
@ -934,7 +890,7 @@ sweepSketch = startSketchOn(XY)
sweepPath = startSketchOn(XZ)
|> startProfile(at = [0.05, 0.05])
|> line(end = [0, 7])
|> tangentialArc(angle = 90deg, radius = 5)
|> tangentialArc(angle = 90, radius = 5)
|> line(end = [-3, 0])
|> tangentialArc(angle = -90, radius = 5)
|> line(end = [0, 7])

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

View File

@ -62,16 +62,16 @@ export const TEST_CODE_GIZMO = `@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
|> startProfile(at = [20, 0])
|> line(end = [7.13, 4 + 0])
|> angledLine(angle = 3deg + 0, length = 3.14 + 0 )
|> angledLine(angle = 3 + 0, length = 3.14 + 0 )
|> line(endAbsolute = [20.14 + 0, -0.14 + 0])
|> xLine(endAbsolute = 29 + 0)
|> yLine(length = -3.14 + 0, tag = $a)
|> xLine(length = 1.63)
|> angledLine(angle = 3deg + 0, lengthX = 3.14 )
|> angledLine(angle = 30deg, lengthY = 3 + 0 )
|> angledLine(angle = 22.14deg + 0, endAbsoluteX = 12)
|> angledLine(angle = 30deg, endAbsoluteY = 11.14)
|> angledLineThatIntersects(angle = 3.14deg, intersectTag = a, offset = 0)
|> angledLine(angle = 3 + 0, lengthX = 3.14 )
|> angledLine(angle = 30, lengthY = 3 + 0 )
|> angledLine(angle = 22.14 + 0, endAbsoluteX = 12)
|> angledLine(angle = 30, endAbsoluteY = 11.14)
|> angledLineThatIntersects(angle = 3.14, intersectTag = a, offset = 0)
|> tangentialArc(endAbsolute = [13.14 + 0, 13.14])
|> close()
|> extrude(length = 5 + 7)
@ -122,7 +122,7 @@ sketch001 = startSketchOn(box, face = revolveAxis)
|> close()
|> revolve(
axis = revolveAxis,
angle = 90deg
angle = 90
)
sketch001 = startSketchOn(XZ)

View File

@ -1,257 +1,236 @@
import type { EngineCommand } from '@src/lang/std/artifactGraph'
import { uuidv4 } from '@src/lib/utils'
import {
commonPoints,
getUtils,
TEST_COLORS,
circleMove,
} from '@e2e/playwright/test-utils'
import { commonPoints, getUtils } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Test network related behaviors', () => {
test(
'simulate network down and network little widget',
{ tag: '@skipLocalEngine' },
async ({ page, homePage }) => {
const networkToggleConnectedText = page.getByText('Connected')
const networkToggleWeakText = page.getByText('Network health (Weak)')
test.describe(
'Test network and connection issues',
{
tag: ['@macos', '@windows'],
},
() => {
test(
'simulate network down and network little widget',
{ tag: '@skipLocalEngine' },
async ({ page, homePage }) => {
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 })
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
await homePage.goToModelingScene()
const networkToggle = page.getByTestId('network-toggle')
const networkToggle = page.getByTestId('network-toggle')
// This is how we wait until the stream is online
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled({ timeout: 15000 })
// This is how we wait until the stream is online
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled({ timeout: 15000 })
const networkWidget = page.locator('[data-testid="network-toggle"]')
await expect(networkWidget).toBeVisible()
await networkWidget.hover()
const networkWidget = page.locator('[data-testid="network-toggle"]')
await expect(networkWidget).toBeVisible()
await networkWidget.hover()
const networkPopover = page.locator('[data-testid="network-popover"]')
await expect(networkPopover).not.toBeVisible()
const networkPopover = page.locator('[data-testid="network-popover"]')
await expect(networkPopover).not.toBeVisible()
// (First check) Expect the network to be up
await expect(networkToggle).toContainText('Connected')
// (First check) Expect the network to be up
await expect(
networkToggleConnectedText.or(networkToggleWeakText)
).toBeVisible()
// Click the network widget
await networkWidget.click()
// Click the network widget
await networkWidget.click()
// Check the modal opened.
await expect(networkPopover).toBeVisible()
// Check the modal opened.
await expect(networkPopover).toBeVisible()
// Click off the modal.
await page.mouse.click(100, 100)
await expect(networkPopover).not.toBeVisible()
// Click off the modal.
await page.mouse.click(100, 100)
await expect(networkPopover).not.toBeVisible()
// Turn off the network
await u.emulateNetworkConditions({
offline: true,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
uploadThroughput: -1,
})
// Turn off the network
await u.emulateNetworkConditions({
offline: true,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
uploadThroughput: -1,
})
// Expect the network to be down
await expect(networkToggle).toContainText('Problem')
// Expect the network to be down
await expect(networkToggle).toContainText('Problem')
// Click the network widget
await networkWidget.click()
// Click the network widget
await networkWidget.click()
// Check the modal opened.
await expect(networkPopover).toBeVisible()
// Check the modal opened.
await expect(networkPopover).toBeVisible()
// Click off the modal.
await page.mouse.click(0, 0)
await expect(networkPopover).not.toBeVisible()
// Click off the modal.
await page.mouse.click(0, 0)
await expect(networkPopover).not.toBeVisible()
// Turn back on the network
await u.emulateNetworkConditions({
offline: false,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
uploadThroughput: -1,
})
// Turn back on the network
await u.emulateNetworkConditions({
offline: false,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
uploadThroughput: -1,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled({ timeout: 15000 })
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled({ timeout: 15000 })
// (Second check) expect the network to be up
await expect(networkToggle).toContainText('Connected')
}
)
// (Second check) expect the network to be up
await expect(
networkToggleConnectedText.or(networkToggleWeakText)
).toBeVisible()
}
)
test(
'Engine disconnect & reconnect in sketch mode',
{ tag: '@skipLocalEngine' },
async ({ page, homePage, toolbar, scene, cmdBar }) => {
const networkToggle = page.getByTestId('network-toggle')
test(
'Engine disconnect & reconnect in sketch mode',
{ tag: '@skipLocalEngine' },
async ({ page, homePage, toolbar, scene, cmdBar }) => {
const networkToggle = page.getByTestId('network-toggle')
const networkToggleConnectedText = page.getByText('Connected')
const networkToggleWeakText = page.getByText('Network health (Weak)')
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio
await homePage.goToModelingScene()
await u.waitForPageLoad()
await homePage.goToModelingScene()
await u.waitForPageLoad()
await u.openDebugPanel()
// click on "Start Sketch" button
await u.clearCommandLogs()
await page.getByRole('button', { name: 'Start Sketch' }).click()
await page.waitForTimeout(100)
await u.openDebugPanel()
// click on "Start Sketch" button
await u.clearCommandLogs()
await page.getByRole('button', { name: 'Start Sketch' }).click()
await page.waitForTimeout(100)
// select a plane
await page.mouse.click(700, 200)
// select a plane
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`sketch001 = startSketchOn(XZ)`
)
await u.closeDebugPanel()
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)`
)
await u.closeDebugPanel()
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content')).toHaveText(
`sketch001 = startSketchOn(XZ)profile001 = startProfile(sketch001, at = ${commonPoints.startAt})`
)
await page.waitForTimeout(100)
const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfile(sketch001, at = ${commonPoints.startAt})`
)
await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(100)
await expect(
page.locator('.cm-content')
).toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfile(sketch001, at = ${commonPoints.startAt})
await expect(
page.locator('.cm-content')
).toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfile(sketch001, at = ${commonPoints.startAt})
|> xLine(length = ${commonPoints.num1})`)
// Expect the network to be up
await networkToggle.hover()
await expect(
networkToggleConnectedText.or(networkToggleWeakText)
).toBeVisible()
// Expect the network to be up
await expect(networkToggle).toContainText('Connected')
// simulate network down
await u.emulateNetworkConditions({
offline: true,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
uploadThroughput: -1,
})
// simulate network down
await u.emulateNetworkConditions({
offline: true,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
uploadThroughput: -1,
})
// Expect the network to be down
await networkToggle.hover()
await expect(networkToggle).toContainText('Problem')
// Expect the network to be down
await expect(networkToggle).toContainText('Problem')
// Ensure we are not in sketch mode
await expect(
page.getByRole('button', { name: 'Exit Sketch' })
).not.toBeVisible()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeVisible()
// Ensure we are not in sketch mode
await expect(
page.getByRole('button', { name: 'Exit Sketch' })
).not.toBeVisible()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeVisible()
// simulate network up
await u.emulateNetworkConditions({
offline: false,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
uploadThroughput: -1,
})
// simulate network up
await u.emulateNetworkConditions({
offline: false,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
uploadThroughput: -1,
})
// Wait for the app to be ready for use
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled({ timeout: 15000 })
// Wait for the app to be ready for use
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled({ timeout: 15000 })
// Expect the network to be up
await networkToggle.hover()
await expect(
networkToggleConnectedText.or(networkToggleWeakText)
).toBeVisible()
// Expect the network to be up
await expect(networkToggle).toContainText('Connected')
await scene.settled(cmdBar)
await scene.settled(cmdBar)
// Click off the code pane.
await page.mouse.click(100, 100)
// Click off the code pane.
await page.mouse.click(100, 100)
// select a line
await page
.getByText(`startProfile(sketch001, at = ${commonPoints.startAt})`)
.click()
// select a line
await page
.getByText(`startProfile(sketch001, at = ${commonPoints.startAt})`)
.click()
// enter sketch again
await toolbar.editSketch()
// enter sketch again
await toolbar.editSketch()
// Click the line tool
await page
.getByRole('button', { name: 'line Line', exact: true })
.click()
// Click the line tool
await page.getByRole('button', { name: 'line Line', exact: true }).click()
await page.waitForTimeout(150)
await page.waitForTimeout(150)
const camCommand: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_look_at',
center: { x: 109, y: 0, z: -152 },
vantage: { x: 115, y: -505, z: -152 },
up: { x: 0, y: 0, z: 1 },
},
}
const updateCamCommand: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_get_settings',
},
}
await toolbar.openPane('debug')
await u.sendCustomCmd(camCommand)
await page.waitForTimeout(100)
await u.sendCustomCmd(updateCamCommand)
await page.waitForTimeout(100)
const camCommand: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_look_at',
center: { x: 109, y: 0, z: -152 },
vantage: { x: 115, y: -505, z: -152 },
up: { x: 0, y: 0, z: 1 },
},
}
const updateCamCommand: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_get_settings',
},
}
await toolbar.openPane('debug')
await u.sendCustomCmd(camCommand)
await page.waitForTimeout(100)
await u.sendCustomCmd(updateCamCommand)
await page.waitForTimeout(100)
// click to continue profile
await page.mouse.click(1007, 400)
await page.waitForTimeout(100)
// Ensure we can continue sketching
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
await expect
.poll(u.normalisedEditorCode)
.toBe(`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
// click to continue profile
await page.mouse.click(1007, 400)
await page.waitForTimeout(100)
// Ensure we can continue sketching
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
await expect
.poll(u.normalisedEditorCode)
.toBe(`sketch001 = startSketchOn(XZ)
profile001 = startProfile(sketch001, at = [12.34, -12.34])
|> xLine(length = 12.34)
|> line(end = [-12.34, 12.34])
`)
await page.waitForTimeout(100)
await page.mouse.click(startXPx, 500 - PUR * 20)
await page.waitForTimeout(100)
await page.mouse.click(startXPx, 500 - PUR * 20)
await expect
.poll(u.normalisedEditorCode)
.toBe(`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
await expect
.poll(u.normalisedEditorCode)
.toBe(`sketch001 = startSketchOn(XZ)
profile001 = startProfile(sketch001, at = [12.34, -12.34])
|> xLine(length = 12.34)
|> line(end = [-12.34, 12.34])
@ -259,105 +238,22 @@ profile001 = startProfile(sketch001, at = [12.34, -12.34])
`)
// Unequip line tool
await page.keyboard.press('Escape')
// Make sure we didn't pop out of sketch mode.
await expect(
page.getByRole('button', { name: 'Exit Sketch' })
).toBeVisible()
await expect(
page.getByRole('button', { name: 'line Line', exact: true })
).not.toHaveAttribute('aria-pressed', 'true')
// Unequip line tool
await page.keyboard.press('Escape')
// Make sure we didn't pop out of sketch mode.
await expect(
page.getByRole('button', { name: 'Exit Sketch' })
).toBeVisible()
await expect(
page.getByRole('button', { name: 'line Line', exact: true })
).not.toHaveAttribute('aria-pressed', 'true')
// Exit sketch
await page.keyboard.press('Escape')
await expect(
page.getByRole('button', { name: 'Exit Sketch' })
).not.toBeVisible()
}
)
test(
'Paused stream freezes view frame, unpause reconnect is seamless to user',
{ tag: ['@electron', '@skipLocalEngine'] },
async ({ page, homePage, scene, cmdBar, toolbar, tronApp }) => {
const networkToggle = page.getByTestId('network-toggle')
const networkToggleConnectedText = page.getByText('Connected')
const networkToggleWeakText = page.getByText('Network health (Weak)')
if (!tronApp) {
fail()
// Exit sketch
await page.keyboard.press('Escape')
await expect(
page.getByRole('button', { name: 'Exit Sketch' })
).not.toBeVisible()
}
await tronApp.cleanProjectDir({
app: {
stream_idle_mode: 5000,
},
})
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XY)
profile001 = startProfile(sketch001, at = [0.0, 0.0])
|> line(end = [10.0, 0])
|> line(end = [0, 10.0])
|> close()`
)
})
const dim = { width: 1200, height: 500 }
await page.setBodyDimensions(dim)
await test.step('Go to modeling scene', async () => {
await homePage.goToModelingScene()
await scene.settled(cmdBar)
})
await test.step('Verify pausing behavior', async () => {
// Wait 5s + 1s to pause.
await page.waitForTimeout(6000)
// We should now be paused. To the user, it should appear we're still
// connected.
await networkToggle.hover()
await expect(
networkToggleConnectedText.or(networkToggleWeakText)
).toBeVisible()
const center = {
x: dim.width / 2,
y: dim.height / 2,
}
let probe = { x: 0, y: 0 }
// ... and the model's still visibly there
probe.x = center.x + dim.width / 100
probe.y = center.y
await scene.expectPixelColor(TEST_COLORS.GREY, probe, 15)
probe = { ...center }
// Now move the mouse around to unpause!
await circleMove(page, probe.x, probe.y, 20, 10)
// ONCE AGAIN! Check the view area hasn't changed at all.
// Check the pixel a couple times as it reconnects.
// NOTE: Remember, idle behavior is still on at this point -
// if this test takes longer than 5s shit WILL go south!
probe.x = center.x + dim.width / 100
probe.y = center.y
await scene.expectPixelColor(TEST_COLORS.GREY, probe, 15)
await page.waitForTimeout(1000)
await scene.expectPixelColor(TEST_COLORS.GREY, probe, 15)
probe = { ...center }
// Ensure we're still connected
await networkToggle.hover()
await expect(
networkToggleConnectedText.or(networkToggleWeakText)
).toBeVisible()
})
}
)
})
)
}
)

View File

@ -21,7 +21,6 @@ export const token = process.env.token || ''
import type { ProjectConfiguration } from '@rust/kcl-lib/bindings/ProjectConfiguration'
import type { ElectronZoo } from '@e2e/playwright/fixtures/fixtureSetup'
import { isErrorWhitelisted } from '@e2e/playwright/lib/console-error-whitelist'
import { TEST_SETTINGS, TEST_SETTINGS_KEY } from '@e2e/playwright/storageStates'
import { test } from '@e2e/playwright/zoo-test'
@ -44,8 +43,6 @@ export const lowerRightMasks = (page: Page) => [
export type TestColor = [number, number, number]
export const TEST_COLORS: { [key: string]: TestColor } = {
WHITE: [249, 249, 249],
OFFWHITE: [237, 237, 237],
GREY: [142, 142, 142],
YELLOW: [255, 255, 0],
BLUE: [0, 0, 255],
DARK_MODE_BKGD: [27, 27, 27],
@ -812,6 +809,8 @@ export const doExport = async (
await page.getByRole('button', { name: 'Submit command' }).click()
// This usually happens immediately after. If we're too slow we don't
// catch it.
await expect(page.getByText('Exported successfully')).toBeVisible()
if (exportFrom === 'sidebarButton' || exportFrom === 'commandBar') {
@ -1152,77 +1151,3 @@ export function perProjectSettingsToToml(
// eslint-disable-next-line no-restricted-syntax
return TOML.stringify(settings as any)
}
export async function clickElectronNativeMenuById(
tronApp: ElectronZoo,
menuId: string
) {
const clickWasTriggered = await tronApp.electron.evaluate(
async ({ app }, menuId) => {
if (!app || !app.applicationMenu) {
return false
}
const menu = app.applicationMenu.getMenuItemById(menuId)
if (!menu) return false
menu.click()
return true
},
menuId
)
expect(clickWasTriggered).toBe(true)
}
export async function findElectronNativeMenuById(
tronApp: ElectronZoo,
menuId: string
) {
const found = await tronApp.electron.evaluate(async ({ app }, menuId) => {
if (!app || !app.applicationMenu) {
return false
}
const menu = app.applicationMenu.getMenuItemById(menuId)
if (!menu) return false
return true
}, menuId)
expect(found).toBe(true)
}
export async function openSettingsExpectText(page: Page, text: string) {
const settings = page.getByTestId('settings-dialog-panel')
await expect(settings).toBeVisible()
// You are viewing the user tab
const actualText = settings.getByText(text)
await expect(actualText).toBeVisible()
}
export async function openSettingsExpectLocator(page: Page, selector: string) {
const settings = page.getByTestId('settings-dialog-panel')
await expect(settings).toBeVisible()
// You are viewing the keybindings tab
const settingsLocator = settings.locator(selector)
await expect(settingsLocator).toBeVisible()
}
/**
* A developer helper function to make playwright send all the console logs to stdout
* Call this within your E2E test and pass in the page or the tronApp to get as many
* logs piped to stdout for debugging
*/
export async function enableConsoleLogEverything({
page,
tronApp,
}: { page?: Page; tronApp?: ElectronZoo }) {
page?.on('console', (msg) => {
console.log(`[Page-log]: ${msg.text()}`)
})
tronApp?.electron.on('window', async (electronPage) => {
electronPage.on('console', (msg) => {
console.log(`[Renderer] ${msg.type()}: ${msg.text()}`)
})
})
tronApp?.electron.on('console', (msg) => {
console.log(`[Main] ${msg.type()}: ${msg.text()}`)
})
}

View File

@ -57,7 +57,7 @@ test.describe('Testing constraints', () => {
.click()
await expect(page.locator('.cm-content')).toHaveText(
`length001 = 20sketch001 = startSketchOn(XY) |> startProfile(at = [-10, -10]) |> line(end = [20, 0]) |> angledLine(angle = 90deg, length = length001) |> xLine(length = -20)`
`length001 = 20sketch001 = startSketchOn(XY) |> startProfile(at = [-10, -10]) |> line(end = [20, 0]) |> angledLine(angle = 90, length = length001) |> xLine(length = -20)`
)
// Make sure we didn't pop out of sketch mode.
@ -852,7 +852,7 @@ part002 = startSketchOn(XZ)
test.describe('Two segment - no modal constraints', () => {
const cases = [
{
codeAfter: `|> angledLine(angle = 83deg, length = segLen(seg01))`,
codeAfter: `|> angledLine(angle = 83, length = segLen(seg01))`,
constraintName: 'Equal Length',
},
{
@ -1174,7 +1174,7 @@ test.describe('Electron constraint tests', () => {
await cmdBar.progressCmdBar()
await editor.expectEditor.toContain('length001 = 15.3')
await editor.expectEditor.toContain(
'|> angledLine(angle = 9deg, length = length001)'
'|> angledLine(angle = 9, length = length001)'
)
})

View File

@ -259,7 +259,7 @@ test.describe(`Testing gizmo, fixture-based`, () => {
`@settings(defaultLengthUnit = in)
sketch002 = startSketchOn(XZ)
|> startProfile(at = [-108.83, -57.48])
|> angledLine(angle = 0deg, length = 105.13, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 105.13, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 77.9)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> close()

View File

@ -33,8 +33,8 @@ test.describe('Testing loading external models', () => {
// Locators and constants
const newSample = {
file: 'pillow-block-bearing' + FILE_EXT,
title: 'Pillow Block Bearing',
file: 'parametric-bearing-pillow-block' + FILE_EXT,
title: 'Parametric Bearing Pillow Block',
}
const commandBarButton = page.getByRole('button', { name: 'Commands' })
const samplesCommandOption = page.getByRole('option', {
@ -100,9 +100,9 @@ test.describe('Testing loading external models', () => {
// Locators and constants
const sampleOne = {
file: 'ball-bearing' + FILE_EXT,
title: 'Ball Bearing',
file1: 'ball-bearing-1' + FILE_EXT,
file: 'parametric-bearing-pillow-block' + FILE_EXT,
title: 'Parametric Bearing Pillow Block',
file1: 'parametric-bearing-pillow-block-1' + FILE_EXT,
}
const projectCard = page.getByRole('link', { name: 'bracket' })
const overwriteWarning = page.getByText(

View File

@ -207,17 +207,17 @@ test.describe('Testing segment overlays', () => {
part001 = startSketchOn(XZ)
|> startProfile(at = [5 + 0, 20 + 0])
|> line(end = [0.5, -14 + 0])
|> angledLine(angle = 3deg + 0, length = 32 + 0)
|> angledLine(angle = 3 + 0, length = 32 + 0)
|> line(endAbsolute = [5 + 33, 20 + 11.5 + 0])
|> xLine(endAbsolute = 5 + 9 - 5)
|> yLine(endAbsolute = 20 + -10.77, tag = $a)
|> xLine(length = 26.04)
|> yLine(length = 21.14 + 0)
|> angledLine(angle = 181deg + 0, lengthX = 23.14)
|> angledLine(angle = 181 + 0, lengthX = 23.14)
|> angledLine(angle = -91, lengthY = 19 + 0)
|> angledLine(angle = 3deg + 0, endAbsoluteX = 5 + 26)
|> angledLine(angle = 89deg, endAbsoluteY = 20 + 9.14 + 0)
|> angledLineThatIntersects(angle = 4.14deg, intersectTag = a, offset = 9)
|> angledLine(angle = 3 + 0, endAbsoluteX = 5 + 26)
|> angledLine(angle = 89, endAbsoluteY = 20 + 9.14 + 0)
|> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
|> tangentialArc(endAbsolute = [5 + 3.14 + 13, 20 + 3.14])
`
)
@ -295,9 +295,8 @@ test.describe('Testing segment overlays', () => {
await clickConstrained({
hoverPos: { x: angledLine.x, y: angledLine.y },
constraintType: 'angle',
expectBeforeUnconstrained:
'angledLine(angle = 3deg + 0, length = 32 + 0)',
expectAfterUnconstrained: 'angledLine(angle = 3deg, length = 32 + 0)',
expectBeforeUnconstrained: 'angledLine(angle = 3 + 0, length = 32 + 0)',
expectAfterUnconstrained: 'angledLine(angle = 3, length = 32 + 0)',
expectFinal: 'angledLine(angle = angle001, length = 32 + 0)',
ang: ang + 180,
locator: '[data-overlay-toolbar-index="1"]',
@ -384,7 +383,7 @@ test.describe('Testing segment overlays', () => {
|> yLine(endAbsolute = -10.77, tag = $a)
|> xLine(length = 26.04)
|> yLine(length = 21.14 + 0)
|> angledLine(angle = 181deg + 0, lengthX = 23.14)
|> angledLine(angle = 181 + 0, lengthX = 23.14)
`
)
})
@ -451,17 +450,17 @@ test.describe('Testing segment overlays', () => {
part001 = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> line(end = [0.5, -14 + 0])
|> angledLine(angle = 3deg + 0, length = 32 + 0)
|> angledLine(angle = 3 + 0, length = 32 + 0)
|> line(endAbsolute = [33, 11.5 + 0])
|> xLine(endAbsolute = 9 - 5)
|> yLine(endAbsolute = -10.77, tag = $a)
|> xLine(length = 26.04)
|> yLine(length = 21.14 + 0)
|> angledLine(angle = 181deg + 0, lengthX = 23.14)
|> angledLine(angle = 181 + 0, lengthX = 23.14)
|> angledLine(angle = -91, lengthY = 19 + 0)
|> angledLine(angle = 3deg + 0, endAbsoluteX = 26)
|> angledLine(angle = 89deg, endAbsoluteY = 9.14 + 0)
|> angledLineThatIntersects(angle = 4.14deg, intersectTag = a, offset = 9)
|> angledLine(angle = 3 + 0, endAbsoluteX = 26)
|> angledLine(angle = 89, endAbsoluteY = 9.14 + 0)
|> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
|> tangentialArc(endAbsolute = [3.14 + 13, 3.14])
`
)
@ -512,7 +511,7 @@ test.describe('Testing segment overlays', () => {
hoverPos: { x: angledLineOfXLength.x, y: angledLineOfXLength.y },
constraintType: 'angle',
expectBeforeUnconstrained:
'angledLine(angle = 181deg + 0, lengthX = 23.14)',
'angledLine(angle = 181 + 0, lengthX = 23.14)',
expectAfterUnconstrained: 'angledLine(angle = -179, lengthX = 23.14)',
expectFinal: 'angledLine(angle = angle001, lengthX = 23.14)',
ang: ang + 180,
@ -572,17 +571,17 @@ test.describe('Testing segment overlays', () => {
part001 = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> line(end = [0.5, -14 + 0])
|> angledLine(angle = 3deg + 0, length = 32 + 0)
|> angledLine(angle = 3 + 0, length = 32 + 0)
|> line(endAbsolute = [33, 11.5 + 0])
|> xLine(endAbsolute = 9 - 5)
|> yLine(endAbsolute = -10.77, tag = $a)
|> xLine(length = 26.04)
|> yLine(length = 21.14 + 0)
|> angledLine(angle = 181deg + 0, lengthX = 23.14)
|> angledLine(angle = 181 + 0, lengthX = 23.14)
|> angledLine(angle = -91, lengthY = 19 + 0)
|> angledLine(angle = 3deg + 0, endAbsoluteX = 26)
|> angledLine(angle = 89deg, endAbsoluteY = 9.14 + 0)
|> angledLineThatIntersects(angle = 4.14deg, intersectTag = a, offset = 9)
|> angledLine(angle = 3 + 0, endAbsoluteX = 26)
|> angledLine(angle = 89, endAbsoluteY = 9.14 + 0)
|> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
|> tangentialArc(endAbsolute = [3.14 + 13, 1.14])
`
)
@ -617,8 +616,8 @@ test.describe('Testing segment overlays', () => {
hoverPos: { x: angledLineToX.x, y: angledLineToX.y },
constraintType: 'angle',
expectBeforeUnconstrained:
'angledLine(angle = 3deg + 0, endAbsoluteX = 26)',
expectAfterUnconstrained: 'angledLine(angle = 3deg, endAbsoluteX = 26)',
'angledLine(angle = 3 + 0, endAbsoluteX = 26)',
expectAfterUnconstrained: 'angledLine(angle = 3, endAbsoluteX = 26)',
expectFinal: 'angledLine(angle = angle001, endAbsoluteX = 26)',
ang: ang + 180,
locator: '[data-overlay-toolbar-index="9"]',
@ -642,9 +641,9 @@ test.describe('Testing segment overlays', () => {
await clickUnconstrained({
hoverPos: { x: angledLineToY.x, y: angledLineToY.y },
constraintType: 'angle',
expectBeforeUnconstrained: 'angledLine(angle = 89deg, to = 9.14 + 0)',
expectBeforeUnconstrained: 'angledLine(angle = 89, to = 9.14 + 0)',
expectAfterUnconstrained: 'angledLine(angle = angle002, to = 9.14 + 0)',
expectFinal: 'angledLine(angle = 89deg, to = 9.14 + 0)',
expectFinal: 'angledLine(angle = 89, to = 9.14 + 0)',
steps: process.platform === 'darwin' ? 8 : 9,
ang: ang + 180,
locator: '[data-overlay-toolbar-index="10"]',
@ -654,10 +653,9 @@ test.describe('Testing segment overlays', () => {
hoverPos: { x: angledLineToY.x, y: angledLineToY.y },
constraintType: 'yAbsolute',
expectBeforeUnconstrained:
'angledLine(angle = 89deg, endAbsoluteY = 9.14 + 0)',
expectAfterUnconstrained:
'angledLine(angle = 89deg, endAbsoluteY = 9.14)',
expectFinal: 'angledLine(angle = 89deg, endAbsoluteY = yAbs001)',
'angledLine(angle = 89, endAbsoluteY = 9.14 + 0)',
expectAfterUnconstrained: 'angledLine(angle = 89, endAbsoluteY = 9.14)',
expectFinal: 'angledLine(angle = 89, endAbsoluteY = yAbs001)',
ang: ang + 180,
locator: '[data-overlay-toolbar-index="10"]',
})
@ -673,7 +671,7 @@ test.describe('Testing segment overlays', () => {
y: angledLineThatIntersects.y,
},
constraintType: 'angle',
expectBeforeUnconstrained: `angledLineThatIntersects(angle = 4.14deg, intersectTag = a, offset = 9)`,
expectBeforeUnconstrained: `angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)`,
expectAfterUnconstrained: `angledLineThatIntersects(angle = angle003, intersectTag = a,offset = 9)`,
expectFinal: `angledLineThatIntersects(angle = -176, offset = 9, intersectTag = a)`,
ang: ang + 180,
@ -707,17 +705,17 @@ test.describe('Testing segment overlays', () => {
part001 = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> line(end = [0.5, -14 + 0])
|> angledLine(angle = 3deg + 0, length = 32 + 0)
|> angledLine(angle = 3 + 0, length = 32 + 0)
|> line(endAbsolute = [33, 11.5 + 0])
|> xLine(endAbsolute = 9 - 5)
|> yLine(endAbsolute = -10.77, tag = $a)
|> xLine(length = 26.04)
|> yLine(length = 21.14 + 0)
|> angledLine(angle = 181deg + 0, lengthX = 23.14)
|> angledLine(angle = 181 + 0, lengthX = 23.14)
|> angledLine(angle = -91, lengthY = 19 + 0)
|> angledLine(angle = 3deg + 0, endAbsoluteX = 26)
|> angledLine(angle = 89deg, endAbsoluteY = 9.14 + 0)
|> angledLineThatIntersects(angle = 4.14deg, intersectTag = a, offset = 9)
|> angledLine(angle = 3 + 0, endAbsoluteX = 26)
|> angledLine(angle = 89, endAbsoluteY = 9.14 + 0)
|> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
|> tangentialArc(endAbsolute = [3.14 + 13, -3.14])
`
)
@ -994,17 +992,17 @@ part001 = startSketchOn(XZ)
part001 = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> line(end = [0.5, -14 + 0])
|> angledLine(angle = 3deg + 0, length = 32 + 0)
|> angledLine(angle = 3 + 0, length = 32 + 0)
|> line(endAbsolute = [33, 11.5 + 0])
|> xLine(endAbsolute = 9 - 5)
|> yLine(endAbsolute = -10.77, tag = $a)
|> xLine(length = 26.04)
|> yLine(length = 21.14 + 0)
|> angledLine(angle = 181deg + 0, lengthX = 23.14)
|> angledLine(angle = 181 + 0, lengthX = 23.14)
|> angledLine(angle = -91, lengthY = 19 + 0)
|> angledLine(angle = 3deg + 0, endAbsoluteX = 26)
|> angledLine(angle = 89deg, endAbsoluteY = 9.14 + 0)
|> angledLineThatIntersects(angle = 4.14deg, intersectTag = a, offset = 9)
|> angledLine(angle = 3 + 0, endAbsoluteX = 26)
|> angledLine(angle = 89, endAbsoluteY = 9.14 + 0)
|> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
|> tangentialArc(endAbsolute = [3.14 + 13, 1.14])
|> arc(interiorAbsolute = [16.25, 5.12], endAbsolute = [21.61, 4.15])
|> arc(angleStart = 40.27, angleEnd = -38.05, radius = 9.03)
@ -1080,7 +1078,7 @@ part001 = startSketchOn(XZ)
ang = await u.getAngle(`[data-overlay-index="${overlayIndex}"]`)
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: `angledLineThatIntersects(angle = 4.14deg, intersectTag = a, offset = 9)`,
codeToBeDeleted: `angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)`,
stdLibFnName: 'angledLineThatIntersects',
ang: ang + 180,
steps: 7,
@ -1093,7 +1091,7 @@ part001 = startSketchOn(XZ)
ang = await u.getAngle(`[data-overlay-index="${overlayIndex}"]`)
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'angledLine(angle = 89deg, endAbsoluteY = 9.14 + 0)',
codeToBeDeleted: 'angledLine(angle = 89, endAbsoluteY = 9.14 + 0)',
stdLibFnName: 'angledLineToY',
ang: ang + 180,
locator: `[data-overlay-toolbar-index="${overlayIndex}"]`,
@ -1105,7 +1103,7 @@ part001 = startSketchOn(XZ)
ang = await u.getAngle(`[data-overlay-index="${overlayIndex}"]`)
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'angledLine(angle = 3deg + 0, endAbsoluteX = 26)',
codeToBeDeleted: 'angledLine(angle = 3 + 0, endAbsoluteX = 26)',
stdLibFnName: 'angledLineToX',
ang: ang + 180,
locator: `[data-overlay-toolbar-index="${overlayIndex}"]`,
@ -1129,7 +1127,7 @@ part001 = startSketchOn(XZ)
ang = await u.getAngle(`[data-overlay-index="${overlayIndex}"]`)
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'angledLine(angle = 181deg + 0, lengthX = 23.14)',
codeToBeDeleted: 'angledLine(angle = 181 + 0, lengthX = 23.14)',
stdLibFnName: 'angledLineOfXLength',
ang: ang + 180,
locator: `[data-overlay-toolbar-index="${overlayIndex}"]`,
@ -1224,7 +1222,7 @@ part001 = startSketchOn(XZ)
ang = await u.getAngle(`[data-overlay-index="${overlayIndex}"]`)
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'angledLine(angle = 3deg + 0, length = 32 + 0)',
codeToBeDeleted: 'angledLine(angle = 3 + 0, length = 32 + 0)',
stdLibFnName: 'angledLine',
ang: ang + 180,
locator: `[data-overlay-toolbar-index="${overlayIndex}"]`,
@ -1247,19 +1245,19 @@ part001 = startSketchOn(XZ)
test.describe('Testing delete with dependent segments', () => {
const cases = [
'line(end = [22, 2], tag = $seg01)',
'angledLine(angle = 5deg, length = 23.03, tag = $seg01)',
'angledLine(angle = 5, length = 23.03, tag = $seg01)',
'xLine(length = 23, tag = $seg01)',
'yLine(length = -8, tag = $seg01)',
'xLine(endAbsolute = 30, tag = $seg01)',
'yLine(endAbsolute = -4, tag = $seg01)',
'angledLine(angle = 3deg, lengthX = 30, tag = $seg01)',
'angledLine(angle = 3deg, lengthY = 1.5, tag = $seg01)',
'angledLine(angle = 3deg, endAbsoluteX = 30, tag = $seg01)',
'angledLine(angle = 3deg, endAbsoluteY = 7, tag = $seg01)',
'angledLine(angle = 3, lengthX = 30, tag = $seg01)',
'angledLine(angle = 3, lengthY = 1.5, tag = $seg01)',
'angledLine(angle = 3, endAbsoluteX = 30, tag = $seg01)',
'angledLine(angle = 3, endAbsoluteY = 7, tag = $seg01)',
]
for (const doesHaveTagOutsideSketch of [true, false]) {
for (const lineOfInterest of cases) {
const isObj = lineOfInterest.includes('{ angle = 3deg,')
const isObj = lineOfInterest.includes('{ angle = 3,')
test(`${lineOfInterest}${isObj ? '-[obj-input]' : ''}${
doesHaveTagOutsideSketch ? '-[tagOutsideSketch]' : ''
}`, async ({ page, editor, homePage }) => {
@ -1385,7 +1383,7 @@ part001 = startSketchOn(XZ)
},
{
before: `angledLine(angle = 5deg + 0, length = 23.03 + 0, tag = $seg01)`,
before: `angledLine(angle = 5 + 0, length = 23.03 + 0, tag = $seg01)`,
after: `line(end = [22.94, 2.01], tag = $seg01)`,
},
{
@ -1405,19 +1403,19 @@ part001 = startSketchOn(XZ)
after: `line(end = [0, -10], tag = $seg01)`,
},
{
before: `angledLine(angle = 3deg + 0, lengthX = 30 + 0, tag = $seg01)`,
before: `angledLine(angle = 3 + 0, lengthX = 30 + 0, tag = $seg01)`,
after: `line(end = [30, 1.57], tag = $seg01)`,
},
{
before: `angledLine(angle = 3deg + 0, lengthY = 1.5 + 0, tag = $seg01)`,
before: `angledLine(angle = 3 + 0, lengthY = 1.5 + 0, tag = $seg01)`,
after: `line(end = [28.62, 1.5], tag = $seg01)`,
},
{
before: `angledLine(angle = 3deg + 0, endAbsoluteX = 30 + 0, tag = $seg01)`,
before: `angledLine(angle = 3 + 0, endAbsoluteX = 30 + 0, tag = $seg01)`,
after: `line(end = [25, 1.31], tag = $seg01)`,
},
{
before: `angledLine(angle = 3deg + 0, endAbsoluteY = 7 + 0, tag = $seg01)`,
before: `angledLine(angle = 3 + 0, endAbsoluteY = 7 + 0, tag = $seg01)`,
after: `line(end = [19.08, 1], tag = $seg01)`,
},
]

View File

@ -307,15 +307,15 @@ part009 = startSketchOn(XY)
|> startProfile(at = [pipeLargeDia - (thickness / 2), 38])
|> line(end = [thickness, 0])
|> line(end = [0, -1])
|> angledLine(angle = 60deg, endAbsoluteX = pipeSmallDia + thickness)
|> angledLine(angle = 60, endAbsoluteX = pipeSmallDia + thickness)
|> line(end = [0, -pipeLength])
|> angledLine(angle = -60, endAbsoluteX = pipeLargeDia + thickness)
|> line(end = [0, -1])
|> line(end = [-thickness, 0])
|> line(end = [0, 1])
|> angledLine(angle = 120deg, endAbsoluteX = pipeSmallDia)
|> angledLine(angle = 120, endAbsoluteX = pipeSmallDia)
|> line(end = [0, pipeLength])
|> angledLine(angle = 60deg, endAbsoluteX = pipeLargeDia)
|> angledLine(angle = 60, endAbsoluteX = pipeLargeDia)
|> close()
rev = revolve(part009, axis = Y)
sketch006 = startSketchOn(XY)
@ -325,7 +325,7 @@ profile001 = circle(
radius = 17.96
)
profile002 = startProfile(sketch006, at = [86.92, -63.81])
|> angledLine(angle = 0deg, length = 63.81, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 63.81, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 17.05)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -464,7 +464,7 @@ profile002 = startProfile(sketch002, at = [-11.08, 2.39])
|> close()
extrude001 = extrude(profile002, length = 15)
profile001 = startProfile(sketch001, at = [7.49, 9.96])
|> angledLine(angle = 0deg, length = 5.05, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 5.05, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 4.81)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -513,16 +513,16 @@ profile001 = startProfile(sketch001, at = [7.49, 9.96])
part001 = startSketchOn(XZ)
|> startProfile(at = [20, 0])
|> line(end = [7.13, 4 + 0])
|> angledLine(angle = 3deg + 0, length = 3.14 + 0 )
|> angledLine(angle = 3 + 0, length = 3.14 + 0 )
|> line(endAbsolute = [20.14 + 0, -0.14 + 0])
|> xLine(endAbsolute = 29 + 0)
|> yLine(length = -3.14 + 0, tag = $a)
|> xLine(length = 1.63)
|> angledLine(angle = 3deg + 0, lengthX = 3.14)
|> angledLine(angle = 30deg, lengthY = 3 + 0)
|> angledLine(angle = 22.14deg + 0, endAbsoluteX = 12)
|> angledLine(angle = 30deg, endAbsoluteY = 11.14)
|> angledLineThatIntersects(angle = 3.14deg, intersectTag = a, offset = 0)
|> angledLine(angle = 3 + 0, lengthX = 3.14)
|> angledLine(angle = 30, lengthY = 3 + 0)
|> angledLine(angle = 22.14 + 0, endAbsoluteX = 12)
|> angledLine(angle = 30, endAbsoluteY = 11.14)
|> angledLineThatIntersects(angle = 3.14, intersectTag = a, offset = 0)
|> tangentialArc(endAbsolute = [13.14 + 0, 13.14])
|> close()
|> extrude(length = 5 + 7)
@ -655,7 +655,7 @@ part001 = startSketchOn(XZ)
'flatExtrusionFace',
flatExtrusionFace,
`angledLineThatIntersects(angle=3.14,intersectTag=a,offset=0)extrude(length=5+7)`,
'angledLineThatIntersects(angle = 3.14deg, intersectTag = a, offset = 0)'
'angledLineThatIntersects(angle = 3.14, intersectTag = a, offset = 0)'
)
await checkCodeAtHoverPosition(
@ -707,19 +707,19 @@ part001 = startSketchOn(XZ)
'straightSegmentEdge',
straightSegmentEdge,
`angledLine(angle=30,endAbsoluteY=11.14)`,
'angledLine(angle = 30deg, endAbsoluteY = 11.14)'
'angledLine(angle = 30, endAbsoluteY = 11.14)'
)
await checkCodeAtHoverPosition(
'straightSegmentOppositeEdge',
straightSegmentOppositeEdge,
`angledLine(angle=30,endAbsoluteY=11.14)`,
'angledLine(angle = 30deg, endAbsoluteY = 11.14)'
'angledLine(angle = 30, endAbsoluteY = 11.14)'
)
await checkCodeAtHoverPosition(
'straightSegmentAdjacentEdge',
straightSegmentAdjacentEdge,
`angledLineThatIntersects(angle=3.14,intersectTag=a,offset=0)`,
'angledLineThatIntersects(angle = 3.14deg, intersectTag = a, offset = 0)'
'angledLineThatIntersects(angle = 3.14, intersectTag = a, offset = 0)'
)
await page.waitForTimeout(200)
@ -728,7 +728,7 @@ part001 = startSketchOn(XZ)
await u.codeLocator.fill(`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfile(at = [75.8, 317.2]) // [$startCapTag, $EndCapTag]
|> angledLine(angle = 0deg, length = 268.43, tag = $rectangleSegmentA001)
|> angledLine(angle = 0, length = 268.43, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 217.26, tag = $seg01)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $yo)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)

View File

@ -74,7 +74,7 @@
LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
ELECTRON_OVERRIDE_DIST_PATH =
if pkgs.stdenv.isDarwin
then "${pkgs.electron}/Applications/Electron.app/Contents/MacOS/"
then "${pkgs.electron}/Applications"
else "${pkgs.electron}/bin";
PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS = true;
PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH = "${pkgs.playwright-driver.browsers}/chromium-1091/chrome-linux/chrome";

View File

@ -19,7 +19,7 @@ fn rail8020(originStart, railHeight, railLength) {
|> xLine(length = 0.06 * railHeight, tag = $edge1)
|> yLine(length = 0.087 * railHeight, tag = $edge2)
|> xLine(length = -0.183 * railHeight, tag = $edge3)
|> angledLine(angle = 45deg, endAbsoluteY = (1 - 0.356) / 2 * railHeight + originStart[1], tag = $edge4)
|> angledLine(angle = 45, endAbsoluteY = (1 - 0.356) / 2 * railHeight + originStart[1], tag = $edge4)
|> xLine(length = 0.232 * railHeight, tag = $edge5)
|> angledLine(angle = -45, endAbsoluteY = 0.087 * railHeight + originStart[1], tag = $edge6)
|> xLine(length = -0.183 * railHeight, tag = $edge7)
@ -37,9 +37,9 @@ fn rail8020(originStart, railHeight, railLength) {
|> yLine(length = 0.06 * railHeight, tag = $edge9)
|> xLine(length = -0.087 * railHeight, tag = $edge10)
|> yLine(length = -0.183 * railHeight, tag = $edge11) // edge11
|> angledLine(angle = 135deg, endAbsoluteX = ((1 - 0.356) / 2 + 0.356) * railHeight + originStart[0], tag = $edge12) // edge12
|> angledLine(angle = 135, endAbsoluteX = ((1 - 0.356) / 2 + 0.356) * railHeight + originStart[0], tag = $edge12) // edge12
|> yLine(length = 0.232 * railHeight, tag = $edge13) // 13
|> angledLine(angle = 45deg, endAbsoluteX = (1 - 0.087) * railHeight + originStart[0], tag = $edge14) // 14
|> angledLine(angle = 45, endAbsoluteX = (1 - 0.087) * railHeight + originStart[0], tag = $edge14) // 14
|> yLine(length = -0.183 * railHeight, tag = $edge15) // 15
|> xLine(length = 0.087 * railHeight, tag = $edge16)
|> yLine(length = 0.06 * railHeight)
@ -55,9 +55,9 @@ fn rail8020(originStart, railHeight, railLength) {
|> xLine(length = -0.06 * railHeight, tag = $edge17)
|> yLine(length = -0.087 * railHeight, tag = $edge18)
|> xLine(length = 0.183 * railHeight, tag = $edge19)
|> angledLine(angle = 45deg, endAbsoluteY = ((1 - 0.356) / 2 + 0.356) * railHeight + originStart[1], tag = $edge20)
|> angledLine(angle = 45, endAbsoluteY = ((1 - 0.356) / 2 + 0.356) * railHeight + originStart[1], tag = $edge20)
|> xLine(length = -0.232 * railHeight, tag = $edge21)
|> angledLine(angle = 135deg, endAbsoluteY = (1 - 0.087) * railHeight + originStart[1], tag = $edge22)
|> angledLine(angle = 135, endAbsoluteY = (1 - 0.087) * railHeight + originStart[1], tag = $edge22)
|> xLine(length = 0.183 * railHeight, tag = $edge23)
|> yLine(length = 0.087 * railHeight, tag = $edge24)
|> xLine(length = -0.06 * railHeight)
@ -73,9 +73,9 @@ fn rail8020(originStart, railHeight, railLength) {
|> yLine(length = -0.06 * railHeight, tag = $edge25)
|> xLine(length = 0.087 * railHeight, tag = $edge26)
|> yLine(length = 0.183 * railHeight, tag = $edge27)
|> angledLine(angle = 135deg, endAbsoluteX = (1 - 0.356) / 2 * railHeight + originStart[0], tag = $edge28)
|> angledLine(angle = 135, endAbsoluteX = (1 - 0.356) / 2 * railHeight + originStart[0], tag = $edge28)
|> yLine(length = -0.232 * railHeight, tag = $edge29)
|> angledLine(angle = 45deg, endAbsoluteX = 0.087 * railHeight + originStart[0], tag = $edge30)
|> angledLine(angle = 45, endAbsoluteX = 0.087 * railHeight + originStart[0], tag = $edge30)
|> yLine(length = 0.183 * railHeight, tag = $edge31)
|> xLine(length = -0.087 * railHeight, tag = $edge32)
|> yLine(length = -0.06 * railHeight)

View File

@ -31,24 +31,14 @@ When you submit a PR to add or modify KCL samples, images will be generated and
[![ball-bearing](screenshots/ball-bearing.png)](ball-bearing/main.kcl)
#### [bench](bench/main.kcl) ([screenshot](screenshots/bench.png))
[![bench](screenshots/bench.png)](bench/main.kcl)
#### [bone-plate](bone-plate/main.kcl) ([screenshot](screenshots/bone-plate.png))
[![bone-plate](screenshots/bone-plate.png)](bone-plate/main.kcl)
#### [bottle](bottle/main.kcl) ([screenshot](screenshots/bottle.png))
[![bottle](screenshots/bottle.png)](bottle/main.kcl)
#### [bracket](bracket/main.kcl) ([screenshot](screenshots/bracket.png))
[![bracket](screenshots/bracket.png)](bracket/main.kcl)
#### [car-wheel-assembly](car-wheel-assembly/main.kcl) ([screenshot](screenshots/car-wheel-assembly.png))
[![car-wheel-assembly](screenshots/car-wheel-assembly.png)](car-wheel-assembly/main.kcl)
#### [cold-plate](cold-plate/main.kcl) ([screenshot](screenshots/cold-plate.png))
[![cold-plate](screenshots/cold-plate.png)](cold-plate/main.kcl)
#### [color-cube](color-cube/main.kcl) ([screenshot](screenshots/color-cube.png))
[![color-cube](screenshots/color-cube.png)](color-cube/main.kcl)
#### [counterdrilled-weldment](counterdrilled-weldment/main.kcl) ([screenshot](screenshots/counterdrilled-weldment.png))
[![counterdrilled-weldment](screenshots/counterdrilled-weldment.png)](counterdrilled-weldment/main.kcl)
#### [countersunk-plate](countersunk-plate/main.kcl) ([screenshot](screenshots/countersunk-plate.png))
[![countersunk-plate](screenshots/countersunk-plate.png)](countersunk-plate/main.kcl)
#### [cpu-cooler](cpu-cooler/main.kcl) ([screenshot](screenshots/cpu-cooler.png))
[![cpu-cooler](screenshots/cpu-cooler.png)](cpu-cooler/main.kcl)
#### [cycloidal-gear](cycloidal-gear/main.kcl) ([screenshot](screenshots/cycloidal-gear.png))
[![cycloidal-gear](screenshots/cycloidal-gear.png)](cycloidal-gear/main.kcl)
#### [dodecahedron](dodecahedron/main.kcl) ([screenshot](screenshots/dodecahedron.png))
@ -65,6 +55,8 @@ When you submit a PR to add or modify KCL samples, images will be generated and
[![food-service-spatula](screenshots/food-service-spatula.png)](food-service-spatula/main.kcl)
#### [french-press](french-press/main.kcl) ([screenshot](screenshots/french-press.png))
[![french-press](screenshots/french-press.png)](french-press/main.kcl)
#### [gear](gear/main.kcl) ([screenshot](screenshots/gear.png))
[![gear](screenshots/gear.png)](gear/main.kcl)
#### [gear-rack](gear-rack/main.kcl) ([screenshot](screenshots/gear-rack.png))
[![gear-rack](screenshots/gear-rack.png)](gear-rack/main.kcl)
#### [gridfinity-baseplate](gridfinity-baseplate/main.kcl) ([screenshot](screenshots/gridfinity-baseplate.png))
@ -75,18 +67,6 @@ When you submit a PR to add or modify KCL samples, images will be generated and
[![gridfinity-bins](screenshots/gridfinity-bins.png)](gridfinity-bins/main.kcl)
#### [gridfinity-bins-stacking-lip](gridfinity-bins-stacking-lip/main.kcl) ([screenshot](screenshots/gridfinity-bins-stacking-lip.png))
[![gridfinity-bins-stacking-lip](screenshots/gridfinity-bins-stacking-lip.png)](gridfinity-bins-stacking-lip/main.kcl)
#### [hammer](hammer/main.kcl) ([screenshot](screenshots/hammer.png))
[![hammer](screenshots/hammer.png)](hammer/main.kcl)
#### [helical-gear](helical-gear/main.kcl) ([screenshot](screenshots/helical-gear.png))
[![helical-gear](screenshots/helical-gear.png)](helical-gear/main.kcl)
#### [helical-planetary-gearset](helical-planetary-gearset/main.kcl) ([screenshot](screenshots/helical-planetary-gearset.png))
[![helical-planetary-gearset](screenshots/helical-planetary-gearset.png)](helical-planetary-gearset/main.kcl)
#### [helium-tank](helium-tank/main.kcl) ([screenshot](screenshots/helium-tank.png))
[![helium-tank](screenshots/helium-tank.png)](helium-tank/main.kcl)
#### [herringbone-gear](herringbone-gear/main.kcl) ([screenshot](screenshots/herringbone-gear.png))
[![herringbone-gear](screenshots/herringbone-gear.png)](herringbone-gear/main.kcl)
#### [herringbone-planetary-gearset](herringbone-planetary-gearset/main.kcl) ([screenshot](screenshots/herringbone-planetary-gearset.png))
[![herringbone-planetary-gearset](screenshots/herringbone-planetary-gearset.png)](herringbone-planetary-gearset/main.kcl)
#### [hex-nut](hex-nut/main.kcl) ([screenshot](screenshots/hex-nut.png))
[![hex-nut](screenshots/hex-nut.png)](hex-nut/main.kcl)
#### [i-beam](i-beam/main.kcl) ([screenshot](screenshots/i-beam.png))
@ -103,8 +83,8 @@ When you submit a PR to add or modify KCL samples, images will be generated and
[![mounting-plate](screenshots/mounting-plate.png)](mounting-plate/main.kcl)
#### [multi-axis-robot](multi-axis-robot/main.kcl) ([screenshot](screenshots/multi-axis-robot.png))
[![multi-axis-robot](screenshots/multi-axis-robot.png)](multi-axis-robot/main.kcl)
#### [pillow-block-bearing](pillow-block-bearing/main.kcl) ([screenshot](screenshots/pillow-block-bearing.png))
[![pillow-block-bearing](screenshots/pillow-block-bearing.png)](pillow-block-bearing/main.kcl)
#### [parametric-bearing-pillow-block](parametric-bearing-pillow-block/main.kcl) ([screenshot](screenshots/parametric-bearing-pillow-block.png))
[![parametric-bearing-pillow-block](screenshots/parametric-bearing-pillow-block.png)](parametric-bearing-pillow-block/main.kcl)
#### [pipe](pipe/main.kcl) ([screenshot](screenshots/pipe.png))
[![pipe](screenshots/pipe.png)](pipe/main.kcl)
#### [pipe-flange-assembly](pipe-flange-assembly/main.kcl) ([screenshot](screenshots/pipe-flange-assembly.png))
@ -113,8 +93,6 @@ When you submit a PR to add or modify KCL samples, images will be generated and
[![pipe-with-bend](screenshots/pipe-with-bend.png)](pipe-with-bend/main.kcl)
#### [poopy-shoe](poopy-shoe/main.kcl) ([screenshot](screenshots/poopy-shoe.png))
[![poopy-shoe](screenshots/poopy-shoe.png)](poopy-shoe/main.kcl)
#### [prosthetic-hip](prosthetic-hip/main.kcl) ([screenshot](screenshots/prosthetic-hip.png))
[![prosthetic-hip](screenshots/prosthetic-hip.png)](prosthetic-hip/main.kcl)
#### [router-template-cross-bar](router-template-cross-bar/main.kcl) ([screenshot](screenshots/router-template-cross-bar.png))
[![router-template-cross-bar](screenshots/router-template-cross-bar.png)](router-template-cross-bar/main.kcl)
#### [router-template-slate](router-template-slate/main.kcl) ([screenshot](screenshots/router-template-slate.png))
@ -123,20 +101,10 @@ When you submit a PR to add or modify KCL samples, images will be generated and
[![sheet-metal-bracket](screenshots/sheet-metal-bracket.png)](sheet-metal-bracket/main.kcl)
#### [socket-head-cap-screw](socket-head-cap-screw/main.kcl) ([screenshot](screenshots/socket-head-cap-screw.png))
[![socket-head-cap-screw](screenshots/socket-head-cap-screw.png)](socket-head-cap-screw/main.kcl)
#### [spur-gear](spur-gear/main.kcl) ([screenshot](screenshots/spur-gear.png))
[![spur-gear](screenshots/spur-gear.png)](spur-gear/main.kcl)
#### [spur-reduction-gearset](spur-reduction-gearset/main.kcl) ([screenshot](screenshots/spur-reduction-gearset.png))
[![spur-reduction-gearset](screenshots/spur-reduction-gearset.png)](spur-reduction-gearset/main.kcl)
#### [surgical-drill-guide](surgical-drill-guide/main.kcl) ([screenshot](screenshots/surgical-drill-guide.png))
[![surgical-drill-guide](screenshots/surgical-drill-guide.png)](surgical-drill-guide/main.kcl)
#### [tooling-nest-block](tooling-nest-block/main.kcl) ([screenshot](screenshots/tooling-nest-block.png))
[![tooling-nest-block](screenshots/tooling-nest-block.png)](tooling-nest-block/main.kcl)
#### [utility-sink](utility-sink/main.kcl) ([screenshot](screenshots/utility-sink.png))
[![utility-sink](screenshots/utility-sink.png)](utility-sink/main.kcl)
#### [walkie-talkie](walkie-talkie/main.kcl) ([screenshot](screenshots/walkie-talkie.png))
[![walkie-talkie](screenshots/walkie-talkie.png)](walkie-talkie/main.kcl)
#### [washer](washer/main.kcl) ([screenshot](screenshots/washer.png))
[![washer](screenshots/washer.png)](washer/main.kcl)
#### [wing-spar](wing-spar/main.kcl) ([screenshot](screenshots/wing-spar.png))
[![wing-spar](screenshots/wing-spar.png)](wing-spar/main.kcl)

View File

@ -11,8 +11,8 @@ import * from "parameters.kcl"
// Bottom mounting face
bottomFaceSketch = startSketchOn(XY)
|> startProfile(at = [-fanSize / 2, -fanSize / 2])
|> angledLine(angle = 0deg, length = fanSize, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) + 90deg, length = fanSize, tag = $rectangleSegmentB001)
|> angledLine(angle = 0, length = fanSize, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) + 90, length = fanSize, tag = $rectangleSegmentB001)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $rectangleSegmentD001)
|> close()
@ -50,12 +50,12 @@ bottomFaceSketch = startSketchOn(XY)
// Add large openings to the bottom face to allow airflow through the fan
airflowPattern = startSketchOn(bottomFaceSketch, face = END)
|> startProfile(at = [fanSize * 7 / 25, -fanSize * 9 / 25])
|> angledLine(angle = 140deg, length = fanSize * 12 / 25, tag = $seg01)
|> tangentialArc(radius = fanSize * 1 / 50, angle = 90deg)
|> angledLine(angle = -130deg, length = fanSize * 8 / 25)
|> tangentialArc(radius = fanSize * 1 / 50, angle = 90deg)
|> angledLine(angle = segAng(seg01) + 180deg, length = fanSize * 2 / 25)
|> tangentialArc(radius = fanSize * 8 / 25, angle = 40deg)
|> angledLine(angle = 140, length = fanSize * 12 / 25, tag = $seg01)
|> tangentialArc(radius = fanSize * 1 / 50, angle = 90)
|> angledLine(angle = -130, length = fanSize * 8 / 25)
|> tangentialArc(radius = fanSize * 1 / 50, angle = 90)
|> angledLine(angle = segAng(seg01) + 180, length = fanSize * 2 / 25)
|> tangentialArc(radius = fanSize * 8 / 25, angle = 40)
|> xLine(length = fanSize * 3 / 25)
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
@ -75,13 +75,13 @@ bodyMiddle = startSketchOn(bottomFaceSketch, face = END)
housingMiddleLength / 2,
-housingMiddleLength / 2 - housingMiddleRadius
])
|> tangentialArc(radius = housingMiddleRadius, angle = 90deg)
|> tangentialArc(radius = housingMiddleRadius, angle = 90)
|> yLine(length = housingMiddleLength)
|> tangentialArc(radius = housingMiddleRadius, angle = 90deg)
|> tangentialArc(radius = housingMiddleRadius, angle = 90)
|> xLine(length = -housingMiddleLength)
|> tangentialArc(radius = housingMiddleRadius, angle = 90deg)
|> tangentialArc(radius = housingMiddleRadius, angle = 90)
|> yLine(length = -housingMiddleLength)
|> tangentialArc(radius = housingMiddleRadius, angle = 90deg)
|> tangentialArc(radius = housingMiddleRadius, angle = 90)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> extrude(length = fanHeight - 4 - 4)
@ -93,8 +93,8 @@ bodyFanHole = startSketchOn(bodyMiddle, face = END)
// Top mounting face. Cut a hole in the face to accommodate the fan
topFaceSketch = startSketchOn(bodyMiddle, face = END)
topHoles = startProfile(topFaceSketch, at = [-fanSize / 2, -fanSize / 2])
|> angledLine(angle = 0deg, length = fanSize, tag = $rectangleSegmentA002)
|> angledLine(angle = segAng(rectangleSegmentA002) + 90deg, length = fanSize, tag = $rectangleSegmentB002)
|> angledLine(angle = 0, length = fanSize, tag = $rectangleSegmentA002)
|> angledLine(angle = segAng(rectangleSegmentA002) + 90, length = fanSize, tag = $rectangleSegmentB002)
|> angledLine(angle = segAng(rectangleSegmentA002), length = -segLen(rectangleSegmentA002), tag = $rectangleSegmentC002)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $rectangleSegmentD002)
|> close()

View File

@ -11,11 +11,11 @@ import * from "parameters.kcl"
fanCenter = startSketchOn(XZ)
|> startProfile(at = [-0.0001, fanHeight])
|> xLine(endAbsolute = -15 + 1.5)
|> tangentialArc(radius = 1.5, angle = 90deg)
|> tangentialArc(radius = 1.5, angle = 90)
|> yLine(endAbsolute = 4.5)
|> xLine(endAbsolute = -13)
|> yLine(endAbsolute = profileStartY(%) - 5)
|> tangentialArc(radius = 1, angle = -90deg)
|> tangentialArc(radius = 1, angle = -90)
|> xLine(endAbsolute = -1)
|> yLine(length = 2)
|> xLine(length = -0.15)
@ -39,32 +39,32 @@ fn fanBlade(offsetHeight, startAngle: number(deg)) {
15 * cos(startAngle),
15 * sin(startAngle)
])
|> arc(angleStart = startAngle, angleEnd = startAngle + 1deg, radius = 15)
|> arc(angleStart = startAngle, angleEnd = startAngle + 14, radius = 15)
|> arc(
endAbsolute = [
fanSize * 22 / 50 * cos(startAngle - 20deg),
fanSize * 22 / 50 * sin(startAngle - 20deg)
fanSize * 22 / 50 * cos(startAngle - 20),
fanSize * 22 / 50 * sin(startAngle - 20)
],
interiorAbsolute = [
fanSize * 11 / 50 * cos(startAngle + 3deg),
fanSize * 11 / 50 * sin(startAngle + 3deg)
fanSize * 11 / 50 * cos(startAngle + 3),
fanSize * 11 / 50 * sin(startAngle + 3)
],
)
|> arc(
endAbsolute = [
fanSize * 22 / 50 * cos(startAngle - 24deg),
fanSize * 22 / 50 * sin(startAngle - 24deg)
fanSize * 22 / 50 * cos(startAngle - 24),
fanSize * 22 / 50 * sin(startAngle - 24)
],
interiorAbsolute = [
fanSize * 22 / 50 * cos(startAngle - 22deg),
fanSize * 22 / 50 * sin(startAngle - 22deg)
fanSize * 22 / 50 * cos(startAngle - 22),
fanSize * 22 / 50 * sin(startAngle - 22)
],
)
|> arc(
endAbsolute = [profileStartX(%), profileStartY(%)],
interiorAbsolute = [
fanSize * 11 / 50 * cos(startAngle - 5deg),
fanSize * 11 / 50 * sin(startAngle - 5deg)
fanSize * 11 / 50 * cos(startAngle - 5),
fanSize * 11 / 50 * sin(startAngle - 5)
],
)
|> close()
@ -73,9 +73,9 @@ fn fanBlade(offsetHeight, startAngle: number(deg)) {
// Loft the fan blade cross sections into a single blade, then pattern them about the fan center
crossSections = [
fanBlade(offsetHeight = 4.5, startAngle = 50deg),
fanBlade(offsetHeight = (fanHeight - 2 - 4) / 2, startAngle = 30deg),
fanBlade(offsetHeight = fanHeight - 2, startAngle = 0deg)
fanBlade(offsetHeight = 4.5, startAngle = 50),
fanBlade(offsetHeight = (fanHeight - 2 - 4) / 2, startAngle = 30),
fanBlade(offsetHeight = fanHeight - 2, startAngle = 0)
]
loft(crossSections)
|> appearance(color = "#f3e2d8")
@ -83,6 +83,6 @@ loft(crossSections)
instances = 9,
axis = [0, 0, 1],
center = [0, 0, 0],
arcDegrees = 360deg,
arcDegrees = 360,
rotateDuplicates = true,
)

View File

@ -27,13 +27,13 @@ insideWall = extrude(insideWallSketch, length = overallThickness)
// Create the sketch of one of the balls
ballsSketch = startSketchOn(XY)
|> startProfile(at = [shaftDia / 2 + wallThickness, 0.001])
|> arc(angleStart = 180deg, angleEnd = 0deg, radius = sphereDia / 2)
|> arc(angleStart = 180, angleEnd = 0, radius = sphereDia / 2)
|> close()
// Revolve the ball to make a sphere and pattern around the inside wall
balls = revolve(ballsSketch, axis = X)
|> patternCircular3d(
arcDegrees = 360deg,
arcDegrees = 360,
axis = [0, 0, 1],
center = [0, 0, 0],
instances = nBalls,
@ -44,9 +44,9 @@ balls = revolve(ballsSketch, axis = X)
chainSketch = startSketchOn(XY)
|> startProfile(at = [
shaftDia / 2 + wallThickness + sphereDia / 2 - (chainWidth / 2),
0.125 * sin(60deg)
0.125 * sin(60)
])
|> arc(angleStart = 120deg, angleEnd = 60deg, radius = sphereDia / 2)
|> arc(angleStart = 120, angleEnd = 60, radius = sphereDia / 2)
|> line(end = [0, chainThickness])
|> line(end = [-chainWidth, 0])
|> close()
@ -54,7 +54,7 @@ chainSketch = startSketchOn(XY)
// Revolve the chain sketch
chainHead = revolve(chainSketch, axis = X)
|> patternCircular3d(
arcDegrees = 360deg,
arcDegrees = 360,
axis = [0, 0, 1],
center = [0, 0, 0],
instances = nBalls,
@ -72,9 +72,9 @@ linkSketch = startSketchOn(XZ)
)
// Revolve the link sketch
linkRevolve = revolve(linkSketch, axis = Y, angle = 360deg / nBalls)
linkRevolve = revolve(linkSketch, axis = Y, angle = 360 / nBalls)
|> patternCircular3d(
arcDegrees = 360deg,
arcDegrees = 360,
axis = [0, 0, 1],
center = [0, 0, 0],
instances = nBalls,

View File

@ -57,9 +57,9 @@ fn connectorSketch(@plane, start) {
export fn connector(@plane, length) {
connectorSketch(plane, start = [-12, 8])
|> extrude(length)
|> extrude(length = length)
connectorSketch(plane, start = [16, 8])
|> extrude(length)
|> extrude(length = length)
return 0
}
@ -79,18 +79,18 @@ fn seatSlatSketch(@plane) {
export fn seatSlats(@plane, length) {
seatSlatSketch(plane)
|> extrude(length)
|> extrude(length = length)
return 0
}
fn backSlatsSketch(@plane) {
sketch004 = startSketchOn(plane)
|> startProfile(at = [22, 38.5])
|> angledLine(angle = 173deg, length = 2)
|> angledLine(angle = 173, length = 2)
|> line(end = [-1.74, 2.03])
|> angledLine(angle = 82deg, length = 6.6)
|> angledLine(angle = 82, length = 6.6)
|> line(end = [2.23, 1.42])
|> angledLine(angle = -7deg, length = 2)
|> angledLine(angle = -7, length = 2)
|> line(endAbsolute = profileStart(%))
|> close()
|> patternLinear2d(instances = 2, distance = 11, axis = [-0.137, -1])
@ -99,7 +99,7 @@ fn backSlatsSketch(@plane) {
export fn backSlats(@plane, length) {
b = backSlatsSketch(plane)
|> extrude(length)
|> extrude(length = length)
return b
}
@ -107,7 +107,7 @@ fn armRestPath(@plane) {
sketch005 = startSketchOn(plane)
|> startProfile(at = [20, 33])
|> xLine(length = -20)
|> arc(angleStart = 90deg, angleEnd = 180deg, radius = 10)
|> arc(angleStart = 90, angleEnd = 180, radius = 10)
return sketch005
}

View File

@ -1,55 +0,0 @@
// Bone Plate
// A bone plate is a medical device used in orthopedics to stabilize and fix bone fractures during the healing process. They are typically made of stainless steel or titanium and are secured to the bone with screws. Bone plates come in various types, including locking, compression, and bridge plates, each with specific applications
// Set units
@settings(defaultLengthUnit = mm)
// Define parameters
boltSize = 4.5
// Revolve the profile of a compression plate designed to fit a bone
plateRevolve = startSketchOn(YZ)
|> startProfile(at = [22.9, 0])
|> arc(angleStart = 180deg, angleEnd = 176deg, radius = 120)
|> arc(angleStart = -60deg, angleEnd = 54deg, radius = 5)
|> arc(angleStart = 180deg, angleEnd = 176deg, radius = 120)
|> arc(angleStart = -60deg, angleEnd = 54deg, radius = 5)
|> arc(angleStart = 180deg, angleEnd = 176deg, radius = 120)
|> arc(angleStart = -60deg, angleEnd = 54deg, radius = 5)
|> arc(angleStart = 180deg, angleEnd = 174deg, radius = 170)
|> tangentialArc(endAbsolute = [41.8, 91.88])
|> tangentialArc(endAbsolute = [56.92, 117.08], tag = $seg01)
|> angledLine(angle = tangentToEnd(seg01), length = 23.16)
|> tangentialArc(endAbsolute = [60.93, 140.44], tag = $seg02)
|> angledLine(angle = tangentToEnd(seg02), length = 25.65)
|> tangentialArc(endAbsolute = [48.35, 85.53])
|> tangentialArc(endAbsolute = [35.2, 67.73], tag = $seg03)
|> angledLine(angle = tangentToEnd(seg03), length = 49.06)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> revolve(axis = Y, angle = 65deg, symmetric = true)
// Create a hole sketch with the size and location of each bolt hole
holeSketch = startSketchOn(XZ)
hole01 = circle(holeSketch, center = [0, 12.25], radius = boltSize / 2)
|> extrude(length = -100)
hole02 = circle(holeSketch, center = [0, 29.5], radius = boltSize / 2)
|> extrude(length = -100)
hole03 = circle(holeSketch, center = [0, 46.25], radius = boltSize / 2)
|> extrude(length = -100)
hole04 = circle(holeSketch, center = [0, 77], radius = boltSize / 2)
|> extrude(length = -100)
hole05 = circle(holeSketch, center = [0, 100], radius = boltSize / 2)
|> extrude(length = -100)
hole06 = circle(holeSketch, center = [0, 130], radius = boltSize / 2)
|> extrude(length = -100)
hole07 = circle(holeSketch, center = [-20, 130], radius = boltSize / 2)
|> extrude(length = -100)
hole08 = circle(holeSketch, center = [20, 130], radius = boltSize / 2)
|> extrude(length = -100)
// Cut each guiding clearance hole from the bone plate
solid001 = subtract([plateRevolve], tools = union([hole01, hole02]))
solid002 = subtract([solid001], tools = union([hole03, hole04]))
solid003 = subtract([solid002], tools = union([hole05, hole06]))
solid004 = subtract([solid003], tools = union([hole07, hole08]))

View File

@ -17,44 +17,44 @@ brakeCaliperSketch = startSketchOn(XY)
0,
rotorTotalThickness + caliperTolerance - caliperInnerEdgeRadius
])
|> tangentialArc(angle = 90deg, radius = caliperInnerEdgeRadius)
|> tangentialArc(angle = 90, radius = caliperInnerEdgeRadius)
|> line(end = [
-caliperPadLength + 2 * caliperInnerEdgeRadius,
0
])
|> tangentialArc(angle = -90deg, radius = caliperInnerEdgeRadius)
|> tangentialArc(angle = -90, radius = caliperInnerEdgeRadius)
|> line(end = [
0,
caliperThickness - (caliperInnerEdgeRadius * 2)
])
|> tangentialArc(angle = -90deg, radius = caliperInnerEdgeRadius)
|> tangentialArc(angle = -90, radius = caliperInnerEdgeRadius)
|> line(end = [
caliperPadLength + caliperThickness - caliperOuterEdgeRadius - caliperInnerEdgeRadius,
0
])
|> tangentialArc(angle = -90deg, radius = caliperOuterEdgeRadius)
|> tangentialArc(angle = -90, radius = caliperOuterEdgeRadius)
|> line(end = [
0,
-2 * caliperTolerance - (2 * caliperThickness) - rotorTotalThickness + 2 * caliperOuterEdgeRadius
])
|> tangentialArc(angle = -90deg, radius = caliperOuterEdgeRadius)
|> tangentialArc(angle = -90, radius = caliperOuterEdgeRadius)
|> line(end = [
-caliperPadLength - caliperThickness + caliperOuterEdgeRadius + caliperInnerEdgeRadius,
0
])
|> tangentialArc(angle = -90deg, radius = caliperInnerEdgeRadius)
|> tangentialArc(angle = -90, radius = caliperInnerEdgeRadius)
|> line(end = [
0,
caliperThickness - (2 * caliperInnerEdgeRadius)
])
|> tangentialArc(angle = -90deg, radius = caliperInnerEdgeRadius)
|> tangentialArc(angle = -90, radius = caliperInnerEdgeRadius)
|> line(end = [
caliperPadLength - (2 * caliperInnerEdgeRadius),
0
])
|> tangentialArc(angle = 90deg, radius = caliperInnerEdgeRadius)
|> tangentialArc(angle = 90, radius = caliperInnerEdgeRadius)
|> close()
// Revolve the brake caliper sketch
revolve(brakeCaliperSketch, axis = Y, angle = -70deg)
revolve(brakeCaliperSketch, axis = Y, angle = -70)
|> appearance(color = "#c82d2d", metalness = 90, roughness = 90)

View File

@ -17,7 +17,7 @@ tireSketch = startSketchOn(XY)
],
tag = $edge1,
)
|> tangentialArc(angle = -90deg, 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(angle = -90deg, radius = bendRadius)
|> tangentialArc(angle = -90, radius = bendRadius)
|> line(endAbsolute = [tireInnerDiameter / 2, -tireDepth / 2], tag = $edge2)
|> close()

View File

@ -17,10 +17,10 @@ customPlane = {
fn lug(plane, length, diameter) {
lugSketch = startSketchOn(customPlane)
|> startProfile(at = [0 + diameter / 2, 0])
|> angledLine(angle = 70deg, lengthY = lugHeadLength)
|> angledLine(angle = 70, lengthY = lugHeadLength)
|> xLine(endAbsolute = lugDiameter / 2)
|> yLine(endAbsolute = lugLength)
|> tangentialArc(angle = 90deg, radius = 3mm)
|> tangentialArc(angle = 90, radius = 3mm)
|> xLine(endAbsolute = 0 + .001, tag = $c1)
|> yLine(endAbsolute = lugThreadDepth)
|> xLine(endAbsolute = lugThreadDiameter)

View File

@ -24,7 +24,7 @@ carWheel
// Place the lug nuts
lugNut
|> patternCircular3d(
arcDegrees = 360deg,
arcDegrees = 360,
axis = [0, 1, 0],
center = [0, 0, 0],
instances = lugCount,

View File

@ -12,7 +12,7 @@ export wheelWidth = 9.5
export wheelDiameter = 19
export spokeCount = 6
export spokeGap = 0.2
export spokeAngle = 0.02deg
export spokeAngle = 0.02
export spokeThickness = 0.95
// Lug Nut

View File

@ -1,67 +0,0 @@
// Cold Plate
// A cold plate is a thermal management device used to remove heat from a device or component, typically by transferring heat to a liquid coolant that flows through the plate. It's a conductive cooling solution, commonly made of materials like aluminum or copper, with internal channels or tubes for the coolant
// Set units
@settings(defaultLengthUnit = in)
// Define parameters
tubeDiameter = 5 / 8
wallThickness = 0.080
bendRadius = 1
// Create the cold plate with indentions to secure each pass of the brazed copper tube
coldPlate = startSketchOn(YZ)
|> startProfile(at = [0, tubeDiameter * 2])
|> xLine(length = bendRadius - (tubeDiameter / 2))
|> yLine(length = -tubeDiameter)
|> tangentialArc(angle = 180deg, radius = tubeDiameter / 2)
|> yLine(length = tubeDiameter)
|> xLine(length = bendRadius * 2 - tubeDiameter, tag = $seg07)
|> yLine(length = -tubeDiameter, tag = $seg09)
|> tangentialArc(angle = 180deg, radius = tubeDiameter / 2)
|> yLine(length = tubeDiameter, tag = $seg08)
|> xLine(length = bendRadius - (tubeDiameter / 2))
|> angledLine(angle = -77deg, length = tubeDiameter / 3)
|> tangentialArc(angle = 77deg, radius = tubeDiameter, tag = $seg01)
|> angledLine(angle = tangentToEnd(seg01), length = 1)
|> yLine(endAbsolute = 0)
|> xLine(endAbsolute = 0)
|> mirror2d(axis = Y)
|> close()
|> extrude(length = 10, symmetric = true)
// Sketch the path for the copper tube to follow
copperTubePath = startSketchOn(offsetPlane(XY, offset = tubeDiameter))
|> startProfile(at = [-7.35, -bendRadius * 3])
|> xLine(length = 14.13, tag = $seg05)
|> tangentialArc(angle = 180deg, radius = bendRadius, tag = $seg02)
|> angledLine(angle = tangentToEnd(seg02), length = 13.02, tag = $seg06)
|> tangentialArc(angle = -180deg, radius = bendRadius, tag = $seg03)
|> angledLine(angle = tangentToEnd(seg03), length = segLen(seg06))
|> tangentialArc(angle = 180deg, radius = bendRadius, tag = $seg04)
|> angledLine(angle = tangentToEnd(seg04), length = segLen(seg05))
// Create the profile for the inner and outer diameter of the hollow copper tube
tubeWall = startSketchOn(offsetPlane(YZ, offset = -7.35))
|> circle(center = [-bendRadius * 3, tubeDiameter], radius = tubeDiameter / 2)
|> subtract2d(%, tool = circle(center = [-bendRadius * 3, tubeDiameter], radius = tubeDiameter / 2 - wallThickness))
|> sweep(path = copperTubePath)
|> appearance(color = "#b81b0a")
// Model a brazed cap to cover each tube. Constrain the caps using the walls of the plate
brazedCap = startSketchOn(YZ)
|> startProfile(at = segEnd(seg07))
|> arc(interiorAbsolute = [bendRadius * 3, tubeDiameter * 1.85], endAbsolute = segEnd(seg08))
|> yLine(endAbsolute = segStartY(seg08))
|> arc(
interiorAbsolute = [
bendRadius * 3,
segEndY(seg09) + tubeDiameter / 2
],
endAbsolute = segEnd(seg09),
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> extrude(length = 10, symmetric = true)
|> patternLinear3d(instances = 4, distance = bendRadius * 2, axis = [0, -1, 0])
|> appearance(color = "#6b261e")

View File

@ -23,8 +23,8 @@ tealPlane = offsetPlane(YZ, offset = -halfSize)
fn sketchRectangle(profile, color) {
return profile
|> startProfile(at = [-halfSize, halfSize])
|> angledLine(angle = 0deg, length = size, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90deg, length = size, tag = $rectangleSegmentB001)
|> angledLine(angle = 0, length = size, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = size, tag = $rectangleSegmentB001)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()

View File

@ -1,120 +0,0 @@
// Counterdrilled Weldment
// A metal weldment consisting of a counterdrilled plate, a centrally mounted housing tube, and four structural support fins.
// Set units
@settings(defaultLengthUnit = in)
// Define parameters
boltSpacingX = 5
boltSpacingY = 3
boltDiameter = 1 / 4
counterdrillDiameter = 7 / 16
counterdrillDepth = 3 / 16
tubeInnerDiameter = 1 + 1 / 4
tubeThickness = 0.115
tubeHeight = 2
stockThickness = .5
// Calculate the dimensions of the block using the specified bolt spacing. The size of the block can be defined by adding a multiple of the counterdrill diameter to the bolt spacing
blockLength = boltSpacingX + boltDiameter * 6
blockWidth = boltSpacingY + boltDiameter * 6
// Draw the base plate
plateSketch = startSketchOn(XY)
|> startProfile(at = [-blockLength / 2, -blockWidth / 2])
|> angledLine(angle = 0deg, length = blockLength, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) + 90deg, length = blockWidth, tag = $rectangleSegmentB001)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $rectangleSegmentD001)
|> close()
|> subtract2d(tool = circle(center = [0, 0], radius = tubeInnerDiameter / 2))
plateBody = extrude(plateSketch, length = stockThickness)
|> chamfer(
length = boltDiameter * 2,
tags = [
getNextAdjacentEdge(rectangleSegmentB001),
getNextAdjacentEdge(rectangleSegmentA001),
getNextAdjacentEdge(rectangleSegmentC001),
getNextAdjacentEdge(rectangleSegmentD001)
],
)
// Define hole positions
holePositions = [
[-boltSpacingX / 2, -boltSpacingY / 2],
[-boltSpacingX / 2, boltSpacingY / 2],
[boltSpacingX / 2, -boltSpacingY / 2],
[boltSpacingX / 2, boltSpacingY / 2]
]
// Function to create a counterdrilled hole
fn counterdrill(@holePosition) {
cbdrill = startSketchOn(plateBody, face = END)
|> circle(center = holePosition, radius = counterdrillDiameter / 2)
|> extrude(length = -counterdrillDepth)
cbBolt = startSketchOn(cbdrill, face = START)
|> circle(center = holePosition, radius = boltDiameter / 2, tag = $hole01)
|> extrude(length = -stockThickness + counterdrillDepth)
// Use a chamfer to create a 90-degree counterdrill edge
|> chamfer(length = (counterdrillDiameter - boltDiameter) / 2 * sqrt(2), tags = [hole01])
return { }
}
// Place a counterdrilled hole at each bolt hole position
map(holePositions, f = counterdrill)
// Drill a small pin hole in the side of the tube
pinhole = startSketchOn(YZ)
|> circle(center = [0, 2.2], radius = 0.125)
|> extrude(length = -10)
// Model the central tube and subtract the pin hole
centralTube = startSketchOn(offsetPlane(XY, offset = stockThickness))
|> circle(center = [0, 0], radius = tubeInnerDiameter / 2 + tubeThickness)
|> subtract2d(tool = circle(center = [0, 0], radius = tubeInnerDiameter / 2))
|> extrude(length = tubeHeight)
|> subtract(tools = [pinhole])
// Create a function to create a fin which spans from the central tube to the bolt hole
fn fin(@i) {
diagPlane = {
origin = [0.0, 0.0, 0.0],
xAxis = [
boltSpacingX / 2 * i,
boltSpacingY / 2,
0.0
],
yAxis = [0.0, 0.0, 1.0]
}
finSketch = startSketchOn(diagPlane)
|> startProfile(at = [
tubeInnerDiameter / 2 + tubeThickness,
stockThickness
])
|> xLine(endAbsolute = sqrt((boltSpacingX / 2) ^ 2 + (boltSpacingY / 2) ^ 2) - counterdrillDiameter)
|> yLine(length = 0.15)
|> line(endAbsolute = [
profileStartX(%) + 0.15,
stockThickness + tubeHeight * .8
])
|> xLine(length = -0.15)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> extrude(length = tubeThickness, symmetric = true)
// Use a circular pattern to create an identical fin on the opposite side
otherFin = patternCircular3d(
finSketch,
instances = 2,
axis = [0, 0, 1],
center = [0, 0, 0],
arcDegrees = 360,
rotateDuplicates = true,
)
return { }
}
// Place a pair of support fins along each diagonal axis of the bolt pattern
fin(1)
fin(-1)

View File

@ -1,50 +0,0 @@
// Plate with countersunk holes
// A small mounting plate with a countersunk hole at each end
// Set units
@settings(defaultLengthUnit = in)
// Define parameters
boltSpacing = 5
boltDiameter = 1 / 4
centerHoleDiameter = 1 + 3 / 4
plateThickness = 0.375
// Check that the plate is thick enough to countersink a hole
// assertGreaterThan(plateThickness, boltDiameter, "This plate is not thick enough for the necessary countersink dimensions")
// A bit of math to calculate the tangent line between the two diameters
r1 = centerHoleDiameter / 2 * 1.5 + .35
r2 = boltDiameter * 2 + .25
d = boltSpacing / 2
tangentAngle = asin((r1 - r2) / d)
tangentLength = (r1 - r2) / tan(tangentAngle)
plateBody = startSketchOn(XY)
// Use polar coordinates to start the sketch at the tangent point of the larger radius
|> startProfile(at = polar(angle = 90deg - tangentAngle, length = r1))
|> angledLine(angle = -tangentAngle, length = tangentLength)
|> tangentialArc(radius = r2, angle = (tangentAngle - 90deg) * 2)
|> angledLine(angle = tangentAngle, length = -tangentLength)
|> tangentialArc(radius = r1, angle = -tangentAngle * 2)
|> angledLine(angle = -tangentAngle, length = -tangentLength)
|> tangentialArc(radius = r2, angle = (tangentAngle - 90deg) * 2)
|> angledLine(angle = tangentAngle, length = tangentLength)
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> subtract2d(tool = circle(center = [0, 0], radius = centerHoleDiameter / 2 * 1.5))
|> extrude(%, length = plateThickness)
// Function to create a countersunk hole
fn countersink(@holePosition) {
startSketchOn(plateBody, face = END)
|> circle(center = [holePosition, 0], radius = boltDiameter / 2, tag = $hole01)
|> extrude(length = -plateThickness)
// Use a chamfer to create a 90-degree countersink
|> chamfer(length = boltDiameter, tags = [hole01])
return { }
}
// Place a countersunk hole at each bolt hole position
countersink(-boltSpacing / 2)
countersink(boltSpacing / 2)

View File

@ -1,153 +0,0 @@
// Fan Housing
// The plastic housing that contains the fan and the motor
// Set units
@settings(defaultLengthUnit = mm)
// Import parameters
import * from "parameters.kcl"
// Model the housing which holds the motor, the fan, and the mounting provisions
// Bottom mounting face
bottomFaceSketch = startSketchOn(YZ)
|> startProfile(at = [-fanSize / 2, -fanSize / 2])
|> angledLine(angle = 0deg, length = fanSize, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) + 90deg, length = fanSize, tag = $rectangleSegmentB001)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $rectangleSegmentD001)
|> close()
|> subtract2d(tool = circle(center = [0, 0], radius = 4))
|> subtract2d(tool = circle(
center = [
mountingHoleSpacing / 2,
mountingHoleSpacing / 2
],
radius = mountingHoleSize / 2,
))
|> subtract2d(tool = circle(
center = [
-mountingHoleSpacing / 2,
mountingHoleSpacing / 2
],
radius = mountingHoleSize / 2,
))
|> subtract2d(tool = circle(
center = [
mountingHoleSpacing / 2,
-mountingHoleSpacing / 2
],
radius = mountingHoleSize / 2,
))
|> subtract2d(tool = circle(
center = [
-mountingHoleSpacing / 2,
-mountingHoleSpacing / 2
],
radius = mountingHoleSize / 2,
))
|> extrude(length = 4)
// Add large openings to the bottom face to allow airflow through the fan
airflowPattern = startSketchOn(bottomFaceSketch, face = END)
|> startProfile(at = [fanSize * 7 / 25, -fanSize * 9 / 25])
|> angledLine(angle = 140deg, length = fanSize * 12 / 25, tag = $seg01)
|> tangentialArc(radius = fanSize * 1 / 50, angle = 90deg)
|> angledLine(angle = -130deg, length = fanSize * 8 / 25)
|> tangentialArc(radius = fanSize * 1 / 50, angle = 90deg)
|> angledLine(angle = segAng(seg01) + 180deg, length = fanSize * 2 / 25)
|> tangentialArc(radius = fanSize * 8 / 25, angle = 40deg)
|> xLine(length = fanSize * 3 / 25)
|> tangentialArc(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> patternCircular2d(
instances = 4,
center = [0, 0],
arcDegrees = 360,
rotateDuplicates = true,
)
|> extrude(length = -4)
// Create the middle segment of the fan housing body
housingMiddleLength = fanSize / 3
housingMiddleRadius = fanSize / 3 - 1
bodyMiddle = startSketchOn(bottomFaceSketch, face = END)
|> startProfile(at = [
housingMiddleLength / 2,
-housingMiddleLength / 2 - housingMiddleRadius
])
|> tangentialArc(radius = housingMiddleRadius, angle = 90deg)
|> yLine(length = housingMiddleLength)
|> tangentialArc(radius = housingMiddleRadius, angle = 90deg)
|> xLine(length = -housingMiddleLength)
|> tangentialArc(radius = housingMiddleRadius, angle = 90deg)
|> yLine(length = -housingMiddleLength)
|> tangentialArc(radius = housingMiddleRadius, angle = 90deg)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> extrude(length = fanHeight - 4 - 4)
// Cut a hole in the body to accommodate the fan
bodyFanHole = startSketchOn(bodyMiddle, face = END)
|> circle(center = [0, 0], radius = fanSize * 23 / 50)
|> extrude(length = -(fanHeight - 4 - 4))
// Top mounting face. Cut a hole in the face to accommodate the fan
topFaceSketch = startSketchOn(bodyMiddle, face = END)
topHoles = startProfile(topFaceSketch, at = [-fanSize / 2, -fanSize / 2])
|> angledLine(angle = 0deg, length = fanSize, tag = $rectangleSegmentA002)
|> angledLine(angle = segAng(rectangleSegmentA002) + 90deg, length = fanSize, tag = $rectangleSegmentB002)
|> angledLine(angle = segAng(rectangleSegmentA002), length = -segLen(rectangleSegmentA002), tag = $rectangleSegmentC002)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $rectangleSegmentD002)
|> close()
|> subtract2d(tool = circle(center = [0, 0], radius = fanSize * 23 / 50))
|> subtract2d(tool = circle(
center = [
mountingHoleSpacing / 2,
mountingHoleSpacing / 2
],
radius = mountingHoleSize / 2,
))
|> subtract2d(tool = circle(
center = [
-mountingHoleSpacing / 2,
mountingHoleSpacing / 2
],
radius = mountingHoleSize / 2,
))
|> subtract2d(tool = circle(
center = [
mountingHoleSpacing / 2,
-mountingHoleSpacing / 2
],
radius = mountingHoleSize / 2,
))
|> subtract2d(tool = circle(
center = [
-mountingHoleSpacing / 2,
-mountingHoleSpacing / 2
],
radius = mountingHoleSize / 2,
))
|> extrude(length = 4)
// Create a housing for the electric motor to sit
motorHousing = startSketchOn(bottomFaceSketch, face = END)
|> circle(center = [0, 0], radius = 11.2)
|> extrude(length = 16)
startSketchOn(motorHousing, face = END)
|> circle(center = [0, 0], radius = 10)
|> extrude(length = -16)
|> appearance(color = "#a55e2c")
|> fillet(
radius = abs(fanSize - mountingHoleSpacing) / 2,
tags = [
getNextAdjacentEdge(rectangleSegmentA001),
getNextAdjacentEdge(rectangleSegmentB001),
getNextAdjacentEdge(rectangleSegmentC001),
getNextAdjacentEdge(rectangleSegmentD001),
getNextAdjacentEdge(rectangleSegmentA002),
getNextAdjacentEdge(rectangleSegmentB002),
getNextAdjacentEdge(rectangleSegmentC002),
getNextAdjacentEdge(rectangleSegmentD002)
],
)

View File

@ -1,71 +0,0 @@
// Fan
// Spinning axial fan that moves airflow
// Set units
@settings(defaultLengthUnit = mm)
// Import parameters
import * from "parameters.kcl"
// Model the center of the fan
fanCenter = startSketchOn(YZ)
|> circle(center = [0, 0], radius = fanHeight / 2, tag = $centerBend)
|> extrude(%, length = fanHeight)
|> fillet(radius = 1.5, tags = [getOppositeEdge(centerBend)])
// Create a function for a lofted fan blade cross section that rotates about the center hub of the fan
fn fanBlade(offsetHeight, startAngle) {
fanBlade = startSketchOn(offsetPlane(YZ, offset = offsetHeight))
|> startProfile(at = [
15 * cos(startAngle),
15 * sin(startAngle)
])
|> arc(angleStart = startAngle, angleEnd = startAngle + 14deg, radius = 15)
|> arc(
endAbsolute = [
fanSize * 22 / 50 * cos(startAngle - 20deg),
fanSize * 22 / 50 * sin(startAngle - 20deg)
],
interiorAbsolute = [
fanSize * 11 / 50 * cos(startAngle + 3deg),
fanSize * 11 / 50 * sin(startAngle + 3deg)
],
)
|> arc(
endAbsolute = [
fanSize * 22 / 50 * cos(startAngle - 24deg),
fanSize * 22 / 50 * sin(startAngle - 24deg)
],
interiorAbsolute = [
fanSize * 22 / 50 * cos(startAngle - 22deg),
fanSize * 22 / 50 * sin(startAngle - 22deg)
],
)
|> arc(
endAbsolute = [profileStartX(%), profileStartY(%)],
interiorAbsolute = [
fanSize * 11 / 50 * cos(startAngle - 5deg),
fanSize * 11 / 50 * sin(startAngle - 5deg)
],
)
|> close()
return fanBlade
}
// Loft the fan blade cross sections into a single blade, then pattern them about the fan center
crossSections = [
fanBlade(offsetHeight = 4.5, startAngle = 50deg),
fanBlade(offsetHeight = (fanHeight - 2 - 4) / 2, startAngle = 30deg),
fanBlade(offsetHeight = fanHeight - 2, startAngle = 0deg)
]
bladeLoft = loft(crossSections)
|> patternCircular3d(
instances = 9,
axis = [1, 0, 0],
center = [0, 0, 0],
arcDegrees = 360deg,
rotateDuplicates = true,
)
[fanCenter, bladeLoft]
|> appearance(color = "#110803")

View File

@ -1,171 +0,0 @@
// Heat Sink
// Conductive metal device made from brazed tubes and fins
// Set units
@settings(defaultLengthUnit = mm)
// Import parameters
import * from "parameters.kcl"
// Draw the sweep path for the outermost tubes
endTubePath = startSketchOn(offsetPlane(YZ, offset = -20))
|> startProfile(at = [fanSize / 4, fanSize + 38])
|> yLine(endAbsolute = bendRadius + 10, tag = $seg01)
|> tangentialArc(radius = bendRadius, angle = -90deg)
|> xLine(endAbsolute = 0, tag = $seg02)
|> xLine(length = -segLen(seg02))
|> tangentialArc(radius = bendRadius, angle = -90deg)
|> yLine(length = segLen(seg01))
// Sweep and translate the outermost tube on each end
endTube = startSketchOn(offsetPlane(XY, offset = fanSize + 38))
|> circle(center = [-20, fanSize / 4], radius = 3)
|> subtract2d(tool = circle(center = [-20, fanSize / 4], radius = 2.5))
|> sweep(path = endTubePath)
|> patternCircular3d(
%,
instances = 2,
axis = [0, 0, 1],
center = [0, 0, 0],
arcDegrees = 360deg,
rotateDuplicates = false,
)
// Draw the sweep path for the 4 interior tubes
centerTubePath = startSketchOn(offsetPlane(YZ, offset = -4))
|> startProfile(at = [fanSize / 2.67, fanSize + 38])
|> yLine(endAbsolute = bendRadius + 15 + 10)
|> tangentialArc(radius = bendRadius, angle = -45deg)
|> angledLine(angle = -135deg, lengthY = 15)
|> tangentialArc(radius = bendRadius, angle = -45deg)
|> xLine(endAbsolute = 0, tag = $seg03)
|> xLine(length = -segLen(seg03))
|> tangentialArc(radius = bendRadius, angle = -155deg)
|> tangentialArc(radius = bendRadius, angle = 65deg)
|> yLine(endAbsolute = fanSize + 38)
// Draw the profile and sweep the 4 interior tubes
centerTube = startSketchOn(offsetPlane(XY, offset = fanSize + 38))
|> circle(center = [-4, fanSize / 2.67], radius = 3)
|> subtract2d(tool = circle(center = [-4, fanSize / 2.67], radius = 2.5))
|> sweep(path = centerTubePath)
|> patternCircular3d(
%,
instances = 2,
axis = [0, 0, 1],
center = [-4 * 2, 0, 0],
arcDegrees = 360,
rotateDuplicates = true,
)
|> patternLinear3d(
%,
instances = 2,
distance = 4 * 4,
axis = [1, 0, 0],
)
// Draw a heat fin with built-in clips to secure the mounting wire. Pattern the fin upwards by the height of the fan
heatFins = startSketchOn(offsetPlane(XY, offset = 45))
|> startProfile(at = [0, -fanSize / 2])
|> xLine(length = 9)
|> angledLine(angle = -60deg, length = 2.5, tag = $seg04)
|> xLine(length = 0.75)
|> arc(interiorAbsolute = [lastSegX(%) + 1, lastSegY(%) + 1.2], endAbsolute = [lastSegX(%) + 2, lastSegY(%)])
|> xLine(length = 0.75)
|> angledLine(angle = 60deg, length = segLen(seg04))
|> xLine(endAbsolute = heatSinkDepth / 2 - 3)
|> tangentialArc(angle = 90deg, radius = 3)
|> yLine(endAbsolute = 0)
|> mirror2d(axis = X)
|> mirror2d(axis = Y)
|> close()
|> extrude(length = 1)
|> patternLinear3d(
%,
instances = 31,
distance = (fanSize - 10) / 30,
axis = [0, 0, 1],
)
// Create the mounting base for the CPU cooler. The base should consist of two pieces that secure around each of the tubes at the bottom
coolerBase = startSketchOn(-XZ)
baseLower = startProfile(coolerBase, at = [0, 10])
|> xLine(length = -0.9)
|> arc(angleStart = 0deg, angleEnd = -180deg, radius = 3.1)
|> xLine(length = -1.8)
|> arc(angleStart = 0deg, angleEnd = -180deg, radius = 3)
|> xLine(length = -1.8)
|> arc(angleStart = 0deg, angleEnd = -180deg, radius = 3)
|> xLine(length = -1.8)
|> xLine(length = -2)
|> yLine(length = -10)
|> xLine(endAbsolute = 0)
|> mirror2d(axis = Y)
|> extrude(length = 2 * segLen(seg02), symmetric = true)
baseUpper = startProfile(coolerBase, at = [0, 10])
|> xLine(length = -0.9)
|> arc(angleStart = 0deg, angleEnd = 180deg, radius = 3.1)
|> xLine(length = -1.8)
|> arc(angleStart = 0deg, angleEnd = 180deg, radius = 3)
|> xLine(length = -1.8)
|> arc(angleStart = 0deg, angleEnd = 180deg, radius = 3)
|> xLine(length = -1.8)
|> xLine(length = -1)
|> yLine(length = 4)
|> tangentialArc(angle = -90deg, radius = 2)
|> xLine(endAbsolute = 0)
|> mirror2d(axis = Y)
|> extrude(length = 2 * segLen(seg02) * 3 / 4, symmetric = true)
// Create a flexible mounting bracket to secure the heat sink to the motherboard once adhered
mountingBracket = startSketchOn(XZ)
|> startProfile(at = [-10, 16])
|> xLine(length = -20)
|> tangentialArc(angle = 20deg, radius = bendRadius)
|> angledLine(angle = -160deg, length = 14, tag = $seg09)
|> tangentialArc(angle = -30deg, radius = bendRadius + sheetThickness)
|> angledLine(angle = 170deg, length = 21.5, tag = $seg04Q)
|> angledLine(angle = 170deg - 90deg, length = sheetThickness, tag = $seg08)
|> angledLine(angle = segAng(seg04Q) + 180deg, length = segLen(seg04Q), tag = $seg05E)
|> tangentialArc(angle = 30deg, radius = bendRadius)
|> angledLine(angle = segAng(seg09) + 180deg, length = segLen(seg09))
|> tangentialArc(angle = -20deg, radius = bendRadius + sheetThickness)
|> xLine(endAbsolute = profileStartX(%))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg07)
|> close()
|> extrude(
length = 16,
symmetric = true,
tagEnd = $capEnd001,
tagStart = $capStart001,
)
|> fillet(
radius = 2,
tags = [
getCommonEdge(faces = [seg07, capEnd001]),
getCommonEdge(faces = [seg08, capEnd001]),
getCommonEdge(faces = [seg08, capStart001]),
getCommonEdge(faces = [seg07, capStart001])
],
)
// Create a clearance hole in the bracket for an M3 screw and countersink the hole
thruHole = startSketchOn(mountingBracket, face = seg05E)
|> circle(center = [70, 0], radius = 3.4 / 2, tag = $seg06E)
|> extrude(length = -sheetThickness)
|> chamfer(
length = sheetThickness * 0.75,
tags = [
getCommonEdge(faces = [seg05E, seg06E])
],
)
// Duplicate the bracket to the other side of the heat sink base
|> patternCircular3d(
instances = 2,
axis = [0, 0, 1],
center = [0, 0, 0],
arcDegrees = 360deg,
rotateDuplicates = true,
)

View File

@ -1,51 +0,0 @@
// CPU Cooler
// A CPU cooler is a device designed to dissipate heat generated by the CPU of a computer. They consist of a brazed heat sink made from aluminum or copper alloys, and one or two axial fans to move airflow across the heat sink.
// Set units
@settings(defaultLengthUnit = mm)
// Import all parts and parameters into assembly file
import * from "parameters.kcl"
import "fan-housing.kcl" as fanHousing
import "motor.kcl" as motor
import "fan.kcl" as fan
import "heat-sink.kcl" as heatSink
import "mounting-wire.kcl" as mountingWire
import "removable-sticker.kcl" as removableSticker
// Produce the model for each imported part
heatSink
fn translatePart(part) {
part
|> translate(x = heatSinkDepth / 2, z = 40 + fanSize / 2)
|> patternLinear3d(
%,
instances = 2,
distance = heatSinkDepth + fanHeight,
axis = [-1, 0, 0],
)
return { }
}
translatePart(part = fanHousing)
translatePart(part = motor)
translatePart(part = fan)
mountingWire
|> patternCircular3d(
%,
instances = 2,
axis = [0, 1, 0],
center = [0, 0, 40 + fanSize / 2],
arcDegrees = 360deg,
rotateDuplicates = true,
)
|> patternCircular3d(
%,
instances = 2,
axis = [0, 0, 1],
center = [0, 0, 0],
arcDegrees = 360deg,
rotateDuplicates = true,
)
removableSticker

Some files were not shown because too many files have changed in this diff Show More