Compare commits

..

1 Commits

Author SHA1 Message Date
310693c1aa updates
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-04 12:24:29 -07:00
835 changed files with 109892 additions and 113652 deletions

View File

@ -1,3 +1,3 @@
[codespell] [codespell]
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,atleast,ue,afterall,ser,fromM,FromM ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,atleast,ue,afterall,ser
skip: **/target,node_modules,build,dist,./out,**/Cargo.lock,./docs/kcl/*.md,.yarn.lock,**/yarn.lock,./openapi/*.json,./packages/codemirror-lang-kcl/test/all.test.ts,./public/kcl-samples,./rust/kcl-lib/tests/kcl_samples,tsconfig.tsbuildinfo skip: **/target,node_modules,build,dist,./out,**/Cargo.lock,./docs/kcl/*.md,.yarn.lock,**/yarn.lock,./openapi/*.json,./packages/codemirror-lang-kcl/test/all.test.ts,./public/kcl-samples,./rust/kcl-lib/tests/kcl_samples,tsconfig.tsbuildinfo

View File

@ -1,24 +0,0 @@
#!/bin/bash
set -euo pipefail
# Install vector
brew tap vectordotdev/brew && brew install vector
# Configure vector
mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i '' "s#OS_NAME#${OS_NAME}#g" /tmp/vector.toml
sed -i '' "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i '' "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i '' "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i '' "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i '' "s#GH_ACTIONS_AXIOM_TOKEN#${GH_ACTIONS_AXIOM_TOKEN}#g" /tmp/vector.toml
# Display settings
echo
echo 'Vector config:'
cat /tmp/vector.toml
echo
# Start in the background
$(brew --prefix)/opt/vector/bin/vector --config /tmp/vector.toml &

View File

@ -1,24 +0,0 @@
#!/bin/bash
set -euo pipefail
# Install vector
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev | bash -s -- -y
# Configure vector
mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i "s#OS_NAME#${OS_NAME}#g" /tmp/vector.toml
sed -i "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i "s#GH_ACTIONS_AXIOM_TOKEN#${GH_ACTIONS_AXIOM_TOKEN}#g" /tmp/vector.toml
# Display settings
echo
echo 'Vector config:'
cat /tmp/vector.toml
echo
# Start in background
${HOME}/.vector/bin/vector --config /tmp/vector.toml &

View File

@ -24,7 +24,7 @@ jobs:
uses: actions-rust-lang/setup-rust-toolchain@v1 uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
cache: false # Configured below. cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
with: with:
tool: wasm-pack tool: wasm-pack
- name: Rust Cache - name: Rust Cache

View File

@ -77,7 +77,7 @@ jobs:
with: with:
cache: false # Configured below. cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }} if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
with: with:
tool: wasm-pack tool: wasm-pack
@ -207,13 +207,6 @@ jobs:
smctl.exe keypair ls smctl.exe keypair ls
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
smksp_cert_sync.exe smksp_cert_sync.exe
smctl windows certsync
# This last line `smctl windows certsync` was added after windows codesign failures started happening
# with nightly-v25.4.10. It looks like `smksp_cert_sync.exe` used to do the sync to the local cert store,
# but stopped doing it overnight. This extra call that I randomly got from this azure-related doc page
# https://docs.digicert.com/en/digicert-keylocker/code-signing/sign-with-third-party-signing-tools/windows-applications/sign-azure-apps-with-signtool-using-ksp-library.html#sync-certificates--windows-only--618365
# seems to be doing that extra sync that we need for scripts/sign-win.js to work.
# TODO: we still need to make sign-win.js errors fail the workflow, see issue #6276
shell: cmd shell: cmd
- name: Build the app (debug) - name: Build the app (debug)
@ -385,7 +378,7 @@ jobs:
NOTES: ${{ needs.prepare-files.outputs.notes }} NOTES: ${{ needs.prepare-files.outputs.notes }}
PUB_DATE: ${{ github.event.repository.updated_at }} PUB_DATE: ${{ github.event.repository.updated_at }}
WEBSITE_DIR: ${{ env.IS_NIGHTLY == 'true' && 'dl.zoo.dev/releases/modeling-app/nightly' || 'dl.zoo.dev/releases/modeling-app' }} WEBSITE_DIR: ${{ env.IS_NIGHTLY == 'true' && 'dl.zoo.dev/releases/modeling-app/nightly' || 'dl.zoo.dev/releases/modeling-app' }}
URL_CODED_NAME: ${{ env.IS_NIGHTLY == 'true' && 'Zoo%20Design%20Studio%20%28Nightly%29' || 'Zoo%20Design%20Studio' }} URL_CODED_NAME: ${{ env.IS_NIGHTLY == 'true' && 'Zoo%20Modeling%20App%20%28Nightly%29' || 'Zoo%20Modeling%20App' }}
run: | run: |
RELEASE_DIR=https://${WEBSITE_DIR} RELEASE_DIR=https://${WEBSITE_DIR}
jq --null-input \ jq --null-input \

View File

@ -34,11 +34,20 @@ jobs:
uses: actions-rust-lang/setup-rust-toolchain@v1 uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
cache: false # Configured below. cache: false # Configured below.
- name: Start Vector - name: Install vector
run: .github/ci-cd-scripts/start-vector-ubuntu.sh run: |
env: curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }} chmod +x /tmp/vector.sh
OS_NAME: ${{ env.OS_NAME }} /tmp/vector.sh -y -no-modify-path
mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i "s#GH_ACTIONS_AXIOM_TOKEN#${{secrets.GH_ACTIONS_AXIOM_TOKEN}}#g" /tmp/vector.toml
cat /tmp/vector.toml
${HOME}/.vector/bin/vector --config /tmp/vector.toml &
- uses: taiki-e/install-action@cargo-llvm-cov - uses: taiki-e/install-action@cargo-llvm-cov
- uses: taiki-e/install-action@nextest - uses: taiki-e/install-action@nextest
- name: Install just - name: Install just

View File

@ -140,7 +140,7 @@ jobs:
with: with:
cache: false # Configured below. cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }} if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
with: with:
tool: wasm-pack tool: wasm-pack
@ -231,11 +231,6 @@ jobs:
env: env:
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }} snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}
TAB_API_URL: ${{ secrets.TAB_API_URL }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
TARGET: web
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }} if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}
@ -286,7 +281,7 @@ jobs:
os: os:
- "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64" - "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
- namespace-profile-macos-8-cores - namespace-profile-macos-8-cores
- windows-latest-8-cores - windows-latest
shardIndex: [1, 2, 3, 4] shardIndex: [1, 2, 3, 4]
shardTotal: [4] shardTotal: [4]
# Disable macos and windows tests on hourly e2e tests since we only care # Disable macos and windows tests on hourly e2e tests since we only care
@ -297,7 +292,7 @@ jobs:
exclude: exclude:
- os: namespace-profile-macos-8-cores - os: namespace-profile-macos-8-cores
isScheduled: true isScheduled: true
- os: windows-latest-8-cores - os: windows-latest
isScheduled: true isScheduled: true
# TODO: add ref here for main and latest release tag # TODO: add ref here for main and latest release tag
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
@ -344,12 +339,22 @@ jobs:
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
run: yarn tronb:vite:dev run: yarn tronb:vite:dev
- name: Start Vector - name: Install vector
if: ${{ needs.conditions.outputs.should-run == 'true' && !contains(matrix.os, 'windows') }} if: ${{ needs.conditions.outputs.should-run == 'true' && contains(matrix.os, 'ubuntu') }}
run: .github/ci-cd-scripts/start-vector-${{ env.OS_NAME }}.sh shell: bash
env: run: |
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }} curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
OS_NAME: ${{ env.OS_NAME }} chmod +x /tmp/vector.sh
/tmp/vector.sh -y -no-modify-path
mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i "s#GH_ACTIONS_AXIOM_TOKEN#${{secrets.GH_ACTIONS_AXIOM_TOKEN}}#g" /tmp/vector.toml
cat /tmp/vector.toml
${HOME}/.vector/bin/vector --config /tmp/vector.toml &
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }} if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}
@ -370,11 +375,6 @@ jobs:
env: env:
FAIL_ON_CONSOLE_ERRORS: true FAIL_ON_CONSOLE_ERRORS: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
TAB_API_URL: ${{ secrets.TAB_API_URL }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
TARGET: desktop
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && always() }} if: ${{ needs.conditions.outputs.should-run == 'true' && always() }}

View File

@ -1,55 +0,0 @@
name: Test Nix Flake
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
nix-flake-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: nix flake check for all platforms
run: |
nix flake check --all-systems
nix-build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: nix build . for x86_64-linux
run: nix build .
nix-build-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: nix build . for x86_64-darwin
run: nix build .

View File

@ -51,7 +51,7 @@ jobs:
with: with:
cache: false # Configured below. cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
with: with:
tool: wasm-pack tool: wasm-pack
@ -191,7 +191,7 @@ jobs:
cache: 'yarn' cache: 'yarn'
- run: yarn install - run: yarn install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
with: with:
tool: wasm-pack tool: wasm-pack
@ -236,7 +236,7 @@ jobs:
cache: 'yarn' cache: 'yarn'
- run: yarn install - run: yarn install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
with: with:
tool: wasm-pack tool: wasm-pack

View File

@ -8,7 +8,6 @@ include = ["/tmp/github-actions.log"]
type = "remap" type = "remap"
inputs = [ "github-actions-file" ] inputs = [ "github-actions-file" ]
source = ''' source = '''
.platform = "OS_NAME"
.action = "GITHUB_WORKFLOW" .action = "GITHUB_WORKFLOW"
.repo = "GITHUB_REPOSITORY" .repo = "GITHUB_REPOSITORY"
.sha = "GITHUB_SHA" .sha = "GITHUB_SHA"

1
.gitignore vendored
View File

@ -26,7 +26,6 @@ yarn-error.log*
.idea .idea
.vscode .vscode
.helix .helix
result
# rust # rust
rust/target rust/target

View File

@ -5,18 +5,11 @@ all: install build check
# INSTALL # INSTALL
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
export WINDOWS := true CARGO ?= ~/.cargo/bin/cargo.exe
ifndef MSYSTEM WASM_PACK ?= ~/.cargo/bin/wasm-pack.exe
export POWERSHELL := true
endif
endif
ifdef WINDOWS
CARGO ?= $(USERPROFILE)/.cargo/bin/cargo.exe
WASM_PACK ?= $(USERPROFILE)/.cargo/bin/wasm-pack.exe
else else
CARGO ?= ~/.cargo/bin/cargo CARGO ?= ~/.cargo/bin/cargo
WASM_PACK ?= ~/.cargo/bin/wasm-pack WASM_PACK ?= ~/.cargo/bin/wasm-pack
endif endif
.PHONY: install .PHONY: install
@ -24,21 +17,21 @@ install: node_modules/.yarn-integrity $(CARGO) $(WASM_PACK) ## Install dependenc
node_modules/.yarn-integrity: package.json yarn.lock node_modules/.yarn-integrity: package.json yarn.lock
yarn install yarn install
ifdef POWERSHELL ifeq ($(OS),Windows_NT)
@ type nul > $@ @ type nul > $@
else else
@ touch $@ @ touch $@
endif endif
$(CARGO): $(CARGO):
ifdef WINDOWS ifeq ($(OS),Windows_NT)
yarn install:rust:windows yarn install:rust:windows
else else
yarn install:rust yarn install:rust
endif endif
$(WASM_PACK): $(WASM_PACK):
ifdef WINDOWS ifeq ($(OS),Windows_NT)
yarn install:wasm-pack:cargo yarn install:wasm-pack:cargo
else else
yarn install:wasm-pack:sh yarn install:wasm-pack:sh
@ -64,7 +57,7 @@ build-web: install public/kcl_wasm_lib_bg.wasm build/index.html
build-desktop: install public/kcl_wasm_lib_bg.wasm .vite/build/main.js build-desktop: install public/kcl_wasm_lib_bg.wasm .vite/build/main.js
public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES) $(RUST_SOURCES) public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES) $(RUST_SOURCES)
ifdef WINDOWS ifeq ($(OS),Windows_NT)
yarn build:wasm:dev:windows yarn build:wasm:dev:windows
else else
yarn build:wasm:dev yarn build:wasm:dev
@ -147,8 +140,8 @@ endif
.PHONY: clean .PHONY: clean
clean: ## Delete all artifacts clean: ## Delete all artifacts
ifdef POWERSHELL ifeq ($(OS),Windows_NT)
git clean --force -d -x --exclude=.env* --exclude=**/*.env git clean --force -d -X
else else
rm -rf .vite/ build/ rm -rf .vite/ build/
rm -rf trace.zip playwright-report/ test-results/ rm -rf trace.zip playwright-report/ test-results/
@ -159,7 +152,7 @@ endif
.PHONY: help .PHONY: help
help: install help: install
ifdef POWERSHELL ifeq ($(OS),Windows_NT)
@ powershell -Command "Get-Content $(MAKEFILE_LIST) | Select-String -Pattern '^[^\s]+:.*##\s.*$$' | ForEach-Object { $$line = $$_.Line -split ':.*?##\s+'; Write-Host -NoNewline $$line[0].PadRight(30) -ForegroundColor Cyan; Write-Host $$line[1] }" @ powershell -Command "Get-Content $(MAKEFILE_LIST) | Select-String -Pattern '^[^\s]+:.*##\s.*$$' | ForEach-Object { $$line = $$_.Line -split ':.*?##\s+'; Write-Host -NoNewline $$line[0].PadRight(30) -ForegroundColor Cyan; Write-Host $$line[1] }"
else else
@ grep -E '^[^[:space:]]+:.*## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' @ grep -E '^[^[:space:]]+:.*## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

View File

@ -36,9 +36,9 @@ myAngle = -120
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [8, 0]) |> line(end = [8, 0])
|> angledLine(angle = abs(myAngle), length = 5) |> angledLine({ angle = abs(myAngle), length = 5 }, %)
|> line(end = [-5, 0]) |> line(end = [-5, 0])
|> angledLine(angle = myAngle, length = 5) |> angledLine({ angle = myAngle, length = 5 }, %)
|> close() |> close()
baseExtrusion = extrude(sketch001, length = 5) baseExtrusion = extrude(sketch001, length = 5)

View File

@ -33,7 +33,10 @@ acos(num: number): number
```js ```js
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = toDegrees(acos(0.5)), length = 10) |> angledLine({
angle = toDegrees(acos(0.5)),
length = 10
}, %)
|> line(end = [5, 0]) |> line(end = [5, 0])
|> line(endAbsolute = [12, 0]) |> line(endAbsolute = [12, 0])
|> close() |> close()

View File

@ -36,7 +36,7 @@ angleToMatchLengthX(
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [2, 5], tag = $seg01) |> line(end = [2, 5], tag = $seg01)
|> angledLine(angle = -angleToMatchLengthX(seg01, 7, %), endAbsoluteX = 10) |> angledLineToX([-angleToMatchLengthX(seg01, 7, %), 10], %)
|> close() |> close()
extrusion = extrude(sketch001, length = 5) extrusion = extrude(sketch001, length = 5)

View File

@ -36,7 +36,10 @@ angleToMatchLengthY(
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [1, 2], tag = $seg01) |> line(end = [1, 2], tag = $seg01)
|> angledLine(angle = angleToMatchLengthY(seg01, 15, %), length = 5) |> angledLine({
angle = angleToMatchLengthY(seg01, 15, %),
length = 5
}, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -10,13 +10,8 @@ Draw a line segment relative to the current origin using the polar measure of so
```js ```js
angledLine( angledLine(
data: AngledLineData,
sketch: Sketch, sketch: Sketch,
angle: number,
length?: number,
lengthX?: number,
lengthY?: number,
endAbsoluteX?: number,
endAbsoluteY?: number,
tag?: TagDeclarator, tag?: TagDeclarator,
): Sketch ): Sketch
``` ```
@ -26,14 +21,9 @@ angledLine(
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | Which sketch should this path be added to? | Yes | | `data` | [`AngledLineData`](/docs/kcl/types/AngledLineData) | Data to draw an angled line. | Yes |
| `angle` | [`number`](/docs/kcl/types/number) | Which angle should the line be drawn at? | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | | Yes |
| `length` | [`number`](/docs/kcl/types/number) | Draw the line this distance along the given angle. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No | | [`tag`](/docs/kcl/types/tag) | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No |
| `lengthX` | [`number`](/docs/kcl/types/number) | Draw the line this distance along the X axis. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| `lengthY` | [`number`](/docs/kcl/types/number) | Draw the line this distance along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| `endAbsoluteX` | [`number`](/docs/kcl/types/number) | Draw the line along the given angle until it reaches this point along the X axis. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| `endAbsoluteY` | [`number`](/docs/kcl/types/number) | Draw the line along the given angle until it reaches this point along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| [`tag`](/docs/kcl/types/tag) | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | Create a new tag which refers to this line | No |
### Returns ### Returns
@ -46,7 +36,7 @@ angledLine(
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> yLine(endAbsolute = 15) |> yLine(endAbsolute = 15)
|> angledLine(angle = 30, length = 15) |> angledLine({ angle = 30, length = 15 }, %)
|> line(end = [8, -10]) |> line(end = [8, -10])
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

48
docs/kcl/angledLineToX.md Normal file

File diff suppressed because one or more lines are too long

48
docs/kcl/angledLineToY.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -188,9 +188,9 @@ example = extrude(exampleSketch, length = 1)
sweepPath = startSketchOn(XZ) sweepPath = startSketchOn(XZ)
|> startProfileAt([0.05, 0.05], %) |> startProfileAt([0.05, 0.05], %)
|> line(end = [0, 7]) |> line(end = [0, 7])
|> tangentialArc(angle = 90, radius = 5) |> tangentialArc({ offset = 90, radius = 5 }, %)
|> line(end = [-3, 0]) |> line(end = [-3, 0])
|> tangentialArc(angle = -90, radius = 5) |> tangentialArc({ offset = -90, radius = 5 }, %)
|> line(end = [0, 7]) |> line(end = [0, 7])
pipeHole = startSketchOn(XY) pipeHole = startSketchOn(XY)

View File

@ -33,7 +33,10 @@ asin(num: number): number
```js ```js
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = toDegrees(asin(0.5)), length = 20) |> angledLine({
angle = toDegrees(asin(0.5)),
length = 20
}, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -33,7 +33,10 @@ atan(num: number): number
```js ```js
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = toDegrees(atan(1.25)), length = 20) |> angledLine({
angle = toDegrees(atan(1.25)),
length = 20
}, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -37,7 +37,10 @@ atan2(
```js ```js
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = toDegrees(atan2(1.25, 2)), length = 20) |> angledLine({
angle = toDegrees(atan2(1.25, 2)),
length = 20
}, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

File diff suppressed because one or more lines are too long

View File

@ -17,10 +17,10 @@ std::math::E: number = 2.71828182845904523536028747135266250_
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine( |> angledLine({
angle = 30, angle = 30,
length = 2 * E ^ 2, length = 2 * E ^ 2,
) }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -18,7 +18,7 @@ std::math::PI: number = 3.14159265358979323846264338327950288_
circumference = 70 circumference = 70
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> circle(center = [0, 0], radius = circumference / (2 * PI)) |> circle(center = [0, 0], radius = circumference/ (2 * PI))
example = extrude(exampleSketch, length = 5) example = extrude(exampleSketch, length = 5)
``` ```

View File

@ -17,10 +17,10 @@ std::math::TAU: number = 6.28318530717958647692528676655900577_
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine( |> angledLine({
angle = 50, angle = 50,
length = 10 * TAU, length = 10 * TAU,
) }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -30,7 +30,7 @@ e(): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 30, length = 2 * e() ^ 2) |> angledLine({ angle = 30, length = 2 * e() ^ 2 }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

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

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

View File

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

View File

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

View File

@ -65,7 +65,7 @@ case = startSketchOn(-XZ)
|> startProfileAt([-size, -size], %) |> startProfileAt([-size, -size], %)
|> line(end = [2 * size, 0]) |> line(end = [2 * size, 0])
|> line(end = [0, 2 * size]) |> line(end = [0, 2 * size])
|> tangentialArc(endAbsolute = [-size, size]) |> tangentialArcTo([-size, size], %)
|> close() |> close()
|> extrude(length = 65) |> extrude(length = 65)

80
docs/kcl/import.md Normal file

File diff suppressed because one or more lines are too long

40
docs/kcl/inch.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -43,7 +43,11 @@ layout: manual
* [`angleToMatchLengthX`](kcl/angleToMatchLengthX) * [`angleToMatchLengthX`](kcl/angleToMatchLengthX)
* [`angleToMatchLengthY`](kcl/angleToMatchLengthY) * [`angleToMatchLengthY`](kcl/angleToMatchLengthY)
* [`angledLine`](kcl/angledLine) * [`angledLine`](kcl/angledLine)
* [`angledLineOfXLength`](kcl/angledLineOfXLength)
* [`angledLineOfYLength`](kcl/angledLineOfYLength)
* [`angledLineThatIntersects`](kcl/angledLineThatIntersects) * [`angledLineThatIntersects`](kcl/angledLineThatIntersects)
* [`angledLineToX`](kcl/angledLineToX)
* [`angledLineToY`](kcl/angledLineToY)
* [`appearance`](kcl/appearance) * [`appearance`](kcl/appearance)
* [`arc`](kcl/arc) * [`arc`](kcl/arc)
* [`arcTo`](kcl/arcTo) * [`arcTo`](kcl/arcTo)
@ -61,15 +65,11 @@ layout: manual
* [`chamfer`](kcl/chamfer) * [`chamfer`](kcl/chamfer)
* [`circleThreePoint`](kcl/circleThreePoint) * [`circleThreePoint`](kcl/circleThreePoint)
* [`close`](kcl/close) * [`close`](kcl/close)
* [`cm`](kcl/cm)
* [`extrude`](kcl/extrude) * [`extrude`](kcl/extrude)
* [`fillet`](kcl/fillet) * [`fillet`](kcl/fillet)
* [`floor`](kcl/floor) * [`floor`](kcl/floor)
* [`fromCm`](kcl/fromCm) * [`ft`](kcl/ft)
* [`fromFt`](kcl/fromFt)
* [`fromInches`](kcl/fromInches)
* [`fromM`](kcl/fromM)
* [`fromMm`](kcl/fromMm)
* [`fromYd`](kcl/fromYd)
* [`getCommonEdge`](kcl/getCommonEdge) * [`getCommonEdge`](kcl/getCommonEdge)
* [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge) * [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge)
* [`getOppositeEdge`](kcl/getOppositeEdge) * [`getOppositeEdge`](kcl/getOppositeEdge)
@ -77,7 +77,7 @@ layout: manual
* [`helix`](kcl/std-helix) * [`helix`](kcl/std-helix)
* [`hole`](kcl/hole) * [`hole`](kcl/hole)
* [`hollow`](kcl/hollow) * [`hollow`](kcl/hollow)
* [`intersect`](kcl/intersect) * [`inch`](kcl/inch)
* [`lastSegX`](kcl/lastSegX) * [`lastSegX`](kcl/lastSegX)
* [`lastSegY`](kcl/lastSegY) * [`lastSegY`](kcl/lastSegY)
* [`legAngX`](kcl/legAngX) * [`legAngX`](kcl/legAngX)
@ -89,9 +89,11 @@ layout: manual
* [`log`](kcl/log) * [`log`](kcl/log)
* [`log10`](kcl/log10) * [`log10`](kcl/log10)
* [`log2`](kcl/log2) * [`log2`](kcl/log2)
* [`m`](kcl/m)
* [`map`](kcl/map) * [`map`](kcl/map)
* [`max`](kcl/max) * [`max`](kcl/max)
* [`min`](kcl/min) * [`min`](kcl/min)
* [`mm`](kcl/mm)
* [`offsetPlane`](kcl/offsetPlane) * [`offsetPlane`](kcl/offsetPlane)
* [`patternCircular2d`](kcl/patternCircular2d) * [`patternCircular2d`](kcl/patternCircular2d)
* [`patternCircular3d`](kcl/patternCircular3d) * [`patternCircular3d`](kcl/patternCircular3d)
@ -99,6 +101,7 @@ layout: manual
* [`patternLinear3d`](kcl/patternLinear3d) * [`patternLinear3d`](kcl/patternLinear3d)
* [`patternTransform`](kcl/patternTransform) * [`patternTransform`](kcl/patternTransform)
* [`patternTransform2d`](kcl/patternTransform2d) * [`patternTransform2d`](kcl/patternTransform2d)
* [`polar`](kcl/polar)
* [`polygon`](kcl/polygon) * [`polygon`](kcl/polygon)
* [`pop`](kcl/pop) * [`pop`](kcl/pop)
* [`pow`](kcl/pow) * [`pow`](kcl/pow)
@ -124,22 +127,22 @@ layout: manual
* [`sqrt`](kcl/sqrt) * [`sqrt`](kcl/sqrt)
* [`startProfileAt`](kcl/startProfileAt) * [`startProfileAt`](kcl/startProfileAt)
* [`startSketchOn`](kcl/startSketchOn) * [`startSketchOn`](kcl/startSketchOn)
* [`subtract`](kcl/subtract)
* [`sweep`](kcl/sweep) * [`sweep`](kcl/sweep)
* [`tangentToEnd`](kcl/tangentToEnd) * [`tangentToEnd`](kcl/tangentToEnd)
* [`tangentialArc`](kcl/tangentialArc) * [`tangentialArc`](kcl/tangentialArc)
* [`tangentialArcTo`](kcl/tangentialArcTo)
* [`tangentialArcToRelative`](kcl/tangentialArcToRelative)
* [`toDegrees`](kcl/toDegrees) * [`toDegrees`](kcl/toDegrees)
* [`toRadians`](kcl/toRadians) * [`toRadians`](kcl/toRadians)
* [`translate`](kcl/translate) * [`translate`](kcl/translate)
* [`union`](kcl/union)
* [`xLine`](kcl/xLine) * [`xLine`](kcl/xLine)
* [`yLine`](kcl/yLine) * [`yLine`](kcl/yLine)
* [`yd`](kcl/yd)
* **std::math** * **std::math**
* [`E`](kcl/consts/std-math-E) * [`E`](kcl/consts/std-math-E)
* [`PI`](kcl/consts/std-math-PI) * [`PI`](kcl/consts/std-math-PI)
* [`TAU`](kcl/consts/std-math-TAU) * [`TAU`](kcl/consts/std-math-TAU)
* [`cos`](kcl/std-math-cos) * [`cos`](kcl/std-math-cos)
* [`polar`](kcl/std-math-polar)
* [`sin`](kcl/std-math-sin) * [`sin`](kcl/std-math-sin)
* [`tan`](kcl/std-math-tan) * [`tan`](kcl/std-math-tan)
* **std::sketch** * **std::sketch**

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -33,7 +33,10 @@ max(args: [number]): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 70, length = max(15, 31, 4, 13, 22)) |> angledLine({
angle = 70,
length = max(15, 31, 4, 13, 22)
}, %)
|> line(end = [20, 0]) |> line(end = [20, 0])
|> close() |> close()

View File

@ -33,7 +33,10 @@ min(args: [number]): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 70, length = min(15, 31, 4, 13, 22)) |> angledLine({
angle = 70,
length = min(15, 31, 4, 13, 22)
}, %)
|> line(end = [20, 0]) |> line(end = [20, 0])
|> close() |> close()

File diff suppressed because one or more lines are too long

View File

@ -57,7 +57,7 @@ case = startSketchOn(XY)
|> startProfileAt([-size, -size], %) |> startProfileAt([-size, -size], %)
|> line(end = [2 * size, 0]) |> line(end = [2 * size, 0])
|> line(end = [0, 2 * size]) |> line(end = [0, 2 * size])
|> tangentialArc(endAbsolute = [-size, size]) |> tangentialArcTo([-size, size], %)
|> close(%) |> close(%)
|> extrude(length = 65) |> extrude(length = 65)
@ -88,7 +88,7 @@ case = startSketchOn(XY)
|> startProfileAt([-size, -size], %) |> startProfileAt([-size, -size], %)
|> line(end = [2 * size, 0]) |> line(end = [2 * size, 0])
|> line(end = [0, 2 * size]) |> line(end = [0, 2 * size])
|> tangentialArc(endAbsolute = [-size, size]) |> tangentialArcTo([-size, size], %)
|> close(%) |> close(%)
|> extrude(length = 65) |> extrude(length = 65)

43
docs/kcl/polar.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -37,7 +37,7 @@ pow(
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 50, length = pow(5, 2)) |> angledLine({ angle = 50, length = pow(5, 2) }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -29,8 +29,11 @@ profileStart(sketch: Sketch): [number]
```js ```js
sketch001 = startSketchOn(XY) sketch001 = startSketchOn(XY)
|> startProfileAt([5, 2], %) |> startProfileAt([5, 2], %)
|> angledLine(angle = 120, length = 50, tag = $seg01) |> angledLine({ angle = 120, length = 50 }, %, $seg01)
|> angledLine(angle = segAng(seg01) + 120, length = 50) |> angledLine({
angle = segAng(seg01) + 120,
length = 50
}, %)
|> line(end = profileStart(%)) |> line(end = profileStart(%))
|> close() |> close()
|> extrude(length = 20) |> 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

View File

@ -78,7 +78,7 @@ assertEqual(sum, 6, 0.00001, "1 + 2 + 3 summed is 6")
```js ```js
// Declare a function that sketches a decagon. // Declare a function that sketches a decagon.
fn decagon(radius) { fn decagon(radius) {
// Each side of the decagon is turned this many radians from the previous angle. // Each side of the decagon is turned this many degrees from the previous angle.
stepAngle = 1 / 10 * TAU stepAngle = 1 / 10 * TAU
// Start the decagon sketch at this point. // Start the decagon sketch at this point.

View File

@ -65,9 +65,9 @@ rotate(
sweepPath = startSketchOn(XZ) sweepPath = startSketchOn(XZ)
|> startProfileAt([0.05, 0.05], %) |> startProfileAt([0.05, 0.05], %)
|> line(end = [0, 7]) |> line(end = [0, 7])
|> tangentialArc(angle = 90, radius = 5) |> tangentialArc({ offset = 90, radius = 5 }, %)
|> line(end = [-3, 0]) |> line(end = [-3, 0])
|> tangentialArc(angle = -90, radius = 5) |> tangentialArc({ offset = -90, radius = 5 }, %)
|> line(end = [0, 7]) |> line(end = [0, 7])
// Create a hole for the pipe. // Create a hole for the pipe.
@ -90,9 +90,9 @@ sweepSketch = startSketchOn(XY)
sweepPath = startSketchOn(XZ) sweepPath = startSketchOn(XZ)
|> startProfileAt([0.05, 0.05], %) |> startProfileAt([0.05, 0.05], %)
|> line(end = [0, 7]) |> line(end = [0, 7])
|> tangentialArc(angle = 90, radius = 5) |> tangentialArc({ offset = 90, radius = 5 }, %)
|> line(end = [-3, 0]) |> line(end = [-3, 0])
|> tangentialArc(angle = -90, radius = 5) |> tangentialArc({ offset = -90, radius = 5 }, %)
|> line(end = [0, 7]) |> line(end = [0, 7])
// Create a hole for the pipe. // Create a hole for the pipe.
@ -115,9 +115,9 @@ sweepSketch = startSketchOn(XY)
sweepPath = startSketchOn(XZ) sweepPath = startSketchOn(XZ)
|> startProfileAt([0.05, 0.05], %) |> startProfileAt([0.05, 0.05], %)
|> line(end = [0, 7]) |> line(end = [0, 7])
|> tangentialArc(angle = 90, radius = 5) |> tangentialArc({ offset = 90, radius = 5 }, %)
|> line(end = [-3, 0]) |> line(end = [-3, 0])
|> tangentialArc(angle = -90, radius = 5) |> tangentialArc({ offset = -90, radius = 5 }, %)
|> line(end = [0, 7]) |> line(end = [0, 7])
// Create a hole for the pipe. // Create a hole for the pipe.
@ -151,9 +151,15 @@ cube
sketch001 = startSketchOn(XY) sketch001 = startSketchOn(XY)
rectangleSketch = startProfileAt([-200, 23.86], sketch001) rectangleSketch = startProfileAt([-200, 23.86], sketch001)
|> angledLine(angle = 0, length = 73.47, tag = $rectangleSegmentA001) |> angledLine([0, 73.47], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 50.61) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001)) segAng(rectangleSegmentA001) - 90,
50.61
], %)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
@ -162,7 +168,7 @@ circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
sketch002 = startSketchOn(YZ) sketch002 = startSketchOn(YZ)
sweepPath = startProfileAt([0, 0], sketch002) sweepPath = startProfileAt([0, 0], sketch002)
|> yLine(length = 231.81) |> yLine(length = 231.81)
|> tangentialArc(radius = 80, angle = -90) |> tangentialArc({ radius = 80, offset = -90 }, %)
|> xLine(length = 384.93) |> xLine(length = 384.93)
parts = sweep([rectangleSketch, circleSketch], path = sweepPath) parts = sweep([rectangleSketch, circleSketch], path = sweepPath)

View File

@ -49,9 +49,9 @@ scale(
sweepPath = startSketchOn(XZ) sweepPath = startSketchOn(XZ)
|> startProfileAt([0.05, 0.05], %) |> startProfileAt([0.05, 0.05], %)
|> line(end = [0, 7]) |> line(end = [0, 7])
|> tangentialArc(angle = 90, radius = 5) |> tangentialArc({ offset = 90, radius = 5 }, %)
|> line(end = [-3, 0]) |> line(end = [-3, 0])
|> tangentialArc(angle = -90, radius = 5) |> tangentialArc({ offset = -90, radius = 5 }, %)
|> line(end = [0, 7]) |> line(end = [0, 7])
// Create a hole for the pipe. // Create a hole for the pipe.
@ -85,9 +85,15 @@ cube
sketch001 = startSketchOn(XY) sketch001 = startSketchOn(XY)
rectangleSketch = startProfileAt([-200, 23.86], sketch001) rectangleSketch = startProfileAt([-200, 23.86], sketch001)
|> angledLine(angle = 0, length = 73.47, tag = $rectangleSegmentA001) |> angledLine([0, 73.47], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 50.61) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001)) segAng(rectangleSegmentA001) - 90,
50.61
], %)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
@ -96,7 +102,7 @@ circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
sketch002 = startSketchOn(YZ) sketch002 = startSketchOn(YZ)
sweepPath = startProfileAt([0, 0], sketch002) sweepPath = startProfileAt([0, 0], sketch002)
|> yLine(length = 231.81) |> yLine(length = 231.81)
|> tangentialArc(radius = 80, angle = -90) |> tangentialArc({ radius = 80, offset = -90 }, %)
|> xLine(length = 384.93) |> xLine(length = 384.93)
parts = sweep([rectangleSketch, circleSketch], path = sweepPath) parts = sweep([rectangleSketch, circleSketch], path = sweepPath)

View File

@ -32,9 +32,9 @@ exampleSketch = startSketchOn(XZ)
|> line(end = [10, 0]) |> line(end = [10, 0])
|> line(end = [5, 10], tag = $seg01) |> line(end = [5, 10], tag = $seg01)
|> line(end = [-10, 0]) |> line(end = [-10, 0])
|> angledLine(angle = segAng(seg01), length = 10) |> angledLine([segAng(seg01), 10], %)
|> line(end = [-10, 0]) |> line(end = [-10, 0])
|> angledLine(angle = segAng(seg01), length = -15) |> angledLine([segAng(seg01), -15], %)
|> close() |> close()
example = extrude(exampleSketch, length = 4) example = extrude(exampleSketch, length = 4)

View File

@ -29,9 +29,9 @@ segLen(tag: TagIdentifier): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 60, length = 10, tag = $thing) |> angledLine({ angle = 60, length = 10 }, %, $thing)
|> tangentialArc(angle = -120, radius = 5) |> tangentialArc({ offset = -120, radius = 5 }, %)
|> angledLine(angle = -60, length = segLen(thing)) |> angledLine({ angle = -60, length = segLen(thing) }, %)
|> close() |> close()
example = extrude(exampleSketch, length = 5) example = extrude(exampleSketch, length = 5)

View File

@ -6,7 +6,7 @@ layout: manual
# KCL Settings # KCL Settings
There are three levels of settings available in Zoo Design Studio: There are three levels of settings available in the KittyCAD Design Studiolication:
1. [User Settings](/docs/kcl/settings/user): Global settings that apply to all projects, stored in `user.toml` 1. [User Settings](/docs/kcl/settings/user): Global settings that apply to all projects, stored in `user.toml`
2. [Project Settings](/docs/kcl/settings/project): Settings specific to a project, stored in `project.toml` 2. [Project Settings](/docs/kcl/settings/project): Settings specific to a project, stored in `project.toml`
@ -14,7 +14,7 @@ There are three levels of settings available in Zoo Design Studio:
## Configuration Files ## Configuration Files
Zoo Design Studio uses TOML files for configuration: The KittyCAD Design Studio uses TOML files for configuration:
* **User Settings**: `user.toml` - See [complete documentation](/docs/kcl/settings/user) * **User Settings**: `user.toml` - See [complete documentation](/docs/kcl/settings/user)
* **Project Settings**: `project.toml` - See [complete documentation](/docs/kcl/settings/project) * **Project Settings**: `project.toml` - See [complete documentation](/docs/kcl/settings/project)

View File

@ -96,7 +96,7 @@ Permanently dismiss the banner warning to download the desktop app. This setting
##### stream_idle_mode ##### stream_idle_mode
When the user is idle, teardown the stream after some time. When the user is idle, and this is true, the stream will be torn down.
**Default:** None **Default:** None

View File

@ -103,7 +103,7 @@ case = startSketchOn(-XZ)
|> startProfileAt([-size, -size], %) |> startProfileAt([-size, -size], %)
|> line(end = [2 * size, 0]) |> line(end = [2 * size, 0])
|> line(end = [0, 2 * size]) |> line(end = [0, 2 * size])
|> tangentialArc(endAbsolute = [-size, size]) |> tangentialArcTo([-size, size], %)
|> close() |> close()
|> extrude(length = 65) |> extrude(length = 65)
@ -128,7 +128,7 @@ case = startSketchOn(XY)
|> startProfileAt([-size, -size], %) |> startProfileAt([-size, -size], %)
|> line(end = [2 * size, 0]) |> line(end = [2 * size, 0])
|> line(end = [0, 2 * size]) |> line(end = [0, 2 * size])
|> tangentialArc(endAbsolute = [-size, size]) |> tangentialArcTo([-size, size], %)
|> close() |> close()
|> extrude(length = 65) |> extrude(length = 65)
@ -156,7 +156,7 @@ case = startSketchOn(XY)
|> startProfileAt([-size, -size], %) |> startProfileAt([-size, -size], %)
|> line(end = [2 * size, 0]) |> line(end = [2 * size, 0])
|> line(end = [0, 2 * size]) |> line(end = [0, 2 * size])
|> tangentialArc(endAbsolute = [-size, size]) |> tangentialArcTo([-size, size], %)
|> close() |> close()
|> extrude(length = 65) |> extrude(length = 65)

View File

@ -33,7 +33,7 @@ sqrt(num: number): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 50, length = sqrt(2500)) |> angledLine({ angle = 50, length = sqrt(2500) }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -9,15 +9,7 @@ Create a helix.
```js ```js
helix( helix(revolutions: number(_), angleStart: number(deg), ccw?: bool, radius?: number(mm), axis?: Axis3d | Edge, length?: number(mm), cylinder?: Solid): Helix
revolutions: number(_),
angleStart: number(deg),
ccw?: bool,
radius?: number(mm),
axis?: Axis3d | Edge,
length?: number(mm),
cylinder?: Solid,
): Helix
``` ```

View File

@ -29,10 +29,10 @@ cos(@num: number(rad)): number(_)
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine( |> angledLine({
angle = 30, angle = 30,
length = 3 / cos(toRadians(30)), length = 3 / cos(toRadians(30)),
) }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

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,10 +29,10 @@ tan(@num: number(rad)): number(_)
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine( |> angledLine({
angle = 50, angle = 50,
length = 50 * tan(1/2), length = 50 * tan(1/2),
) }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

File diff suppressed because one or more lines are too long

View File

@ -6,16 +6,10 @@ layout: manual
Construct a 2-dimensional circle, of the specified radius, centered at Construct a 2-dimensional circle, of the specified radius, centered atthe provided (x, y) origin point.
the provided (x, y) origin point.
```js ```js
circle( circle(@sketch_or_surface: Sketch | Plane | Face, center: Point2d, radius: number, tag?: tag): Sketch
@sketch_or_surface: Sketch | Plane | Face,
center: Point2d,
radius: number,
tag?: tag,
): Sketch
``` ```

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -47,9 +47,9 @@ sweep(
sweepPath = startSketchOn(XZ) sweepPath = startSketchOn(XZ)
|> startProfileAt([0.05, 0.05], %) |> startProfileAt([0.05, 0.05], %)
|> line(end = [0, 7]) |> line(end = [0, 7])
|> tangentialArc(angle = 90, radius = 5) |> tangentialArc({ offset = 90, radius = 5 }, %)
|> line(end = [-3, 0]) |> line(end = [-3, 0])
|> tangentialArc(angle = -90, radius = 5) |> tangentialArc({ offset = -90, radius = 5 }, %)
|> line(end = [0, 7]) |> line(end = [0, 7])
// Create a hole for the pipe. // Create a hole for the pipe.
@ -91,9 +91,15 @@ springSketch = startSketchOn(YZ)
sketch001 = startSketchOn(XY) sketch001 = startSketchOn(XY)
rectangleSketch = startProfileAt([-200, 23.86], sketch001) rectangleSketch = startProfileAt([-200, 23.86], sketch001)
|> angledLine(angle = 0, length = 73.47, tag = $rectangleSegmentA001) |> angledLine([0, 73.47], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 50.61) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001)) segAng(rectangleSegmentA001) - 90,
50.61
], %)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
@ -102,7 +108,7 @@ circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
sketch002 = startSketchOn(YZ) sketch002 = startSketchOn(YZ)
sweepPath = startProfileAt([0, 0], sketch002) sweepPath = startProfileAt([0, 0], sketch002)
|> yLine(length = 231.81) |> yLine(length = 231.81)
|> tangentialArc(radius = 80, angle = -90) |> tangentialArc({ radius = 80, offset = -90 }, %)
|> xLine(length = 384.93) |> xLine(length = 384.93)
sweep([rectangleSketch, circleSketch], path = sweepPath) sweep([rectangleSketch, circleSketch], path = sweepPath)
@ -120,7 +126,7 @@ circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
sketch002 = startSketchOn(YZ) sketch002 = startSketchOn(YZ)
sweepPath = startProfileAt([0, 0], sketch002) sweepPath = startProfileAt([0, 0], sketch002)
|> yLine(length = 231.81) |> yLine(length = 231.81)
|> tangentialArc(radius = 80, angle = -90) |> tangentialArc({ radius = 80, offset = -90 }, %)
|> xLine(length = 384.93) |> xLine(length = 384.93)
sweep(circleSketch, path = sweepPath, sectional = true) sweep(circleSketch, path = sweepPath, sectional = true)

View File

@ -31,9 +31,12 @@ tangentToEnd(tag: TagIdentifier): number
pillSketch = startSketchOn(XZ) pillSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [20, 0]) |> line(end = [20, 0])
|> tangentialArc(end = [0, 10], tag = $arc1) |> tangentialArcToRelative([0, 10], %, $arc1)
|> angledLine(angle = tangentToEnd(arc1), length = 20) |> angledLine({
|> tangentialArc(end = [0, -10]) angle = tangentToEnd(arc1),
length = 20
}, %)
|> tangentialArcToRelative([0, -10], %)
|> close() |> close()
pillExtrude = extrude(pillSketch, length = 10) pillExtrude = extrude(pillSketch, length = 10)
@ -46,9 +49,12 @@ pillExtrude = extrude(pillSketch, length = 10)
pillSketch = startSketchOn(XZ) pillSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [0, 20]) |> line(end = [0, 20])
|> tangentialArc(endAbsolute = [10, 20], tag = $arc1) |> tangentialArcTo([10, 20], %, $arc1)
|> angledLine(angle = tangentToEnd(arc1), length = 20) |> angledLine({
|> tangentialArc(end = [-10, 0]) angle = tangentToEnd(arc1),
length = 20
}, %)
|> tangentialArcToRelative([-10, 0], %)
|> close() |> close()
pillExtrude = extrude(pillSketch, length = 10) pillExtrude = extrude(pillSketch, length = 10)
@ -60,7 +66,10 @@ pillExtrude = extrude(pillSketch, length = 10)
rectangleSketch = startSketchOn(XZ) rectangleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [10, 0], tag = $seg1) |> line(end = [10, 0], tag = $seg1)
|> angledLine(angle = tangentToEnd(seg1), length = 10) |> angledLine({
angle = tangentToEnd(seg1),
length = 10
}, %)
|> line(end = [0, 10]) |> line(end = [0, 10])
|> line(end = [-20, 0]) |> line(end = [-20, 0])
|> close() |> close()
@ -74,7 +83,7 @@ rectangleExtrude = extrude(rectangleSketch, length = 10)
bottom = startSketchOn(XY) bottom = startSketchOn(XY)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> arcTo({ end = [10, 10], interior = [5, 1] }, %, $arc1) |> arcTo({ end = [10, 10], interior = [5, 1] }, %, $arc1)
|> angledLine(angle = tangentToEnd(arc1), length = 20) |> angledLine([tangentToEnd(arc1), 20], %)
|> close() |> close()
``` ```
@ -86,7 +95,7 @@ circSketch = startSketchOn(XY)
triangleSketch = startSketchOn(XY) triangleSketch = startSketchOn(XY)
|> startProfileAt([-5, 0], %) |> startProfileAt([-5, 0], %)
|> angledLine(angle = tangentToEnd(circ), length = 10) |> angledLine([tangentToEnd(circ), 10], %)
|> line(end = [-15, 0]) |> line(end = [-15, 0])
|> close() |> close()
``` ```

File diff suppressed because one or more lines are too long

View File

@ -35,7 +35,7 @@ tangentialArcTo(
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 60, length = 10) |> angledLine({ angle = 60, length = 10 }, %)
|> tangentialArcTo([15, 15], %) |> tangentialArcTo([15, 15], %)
|> line(end = [10, -15]) |> line(end = [10, -15])
|> close() |> close()

View File

@ -35,7 +35,7 @@ tangentialArcToRelative(
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 45, length = 10) |> angledLine({ angle = 45, length = 10 }, %)
|> tangentialArcToRelative([0, -10], %) |> tangentialArcToRelative([0, -10], %)
|> line(end = [-10, 0]) |> line(end = [-10, 0])
|> close() |> close()

View File

@ -30,7 +30,7 @@ tau(): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 50, length = 10 * tau()) |> angledLine({ angle = 50, length = 10 * tau() }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -33,7 +33,10 @@ toDegrees(num: number): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 50, length = 70 * cos(toDegrees(pi() / 4))) |> angledLine({
angle = 50,
length = 70 * cos(toDegrees(pi() / 4))
}, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -33,7 +33,10 @@ toRadians(num: number): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 50, length = 70 * cos(toRadians(45))) |> angledLine({
angle = 50,
length = 70 * cos(toRadians(45))
}, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -45,9 +45,9 @@ translate(
sweepPath = startSketchOn(XZ) sweepPath = startSketchOn(XZ)
|> startProfileAt([0.05, 0.05], %) |> startProfileAt([0.05, 0.05], %)
|> line(end = [0, 7]) |> line(end = [0, 7])
|> tangentialArc(angle = 90, radius = 5) |> tangentialArc({ offset = 90, radius = 5 }, %)
|> line(end = [-3, 0]) |> line(end = [-3, 0])
|> tangentialArc(angle = -90, radius = 5) |> tangentialArc({ offset = -90, radius = 5 }, %)
|> line(end = [0, 7]) |> line(end = [0, 7])
// Create a hole for the pipe. // Create a hole for the pipe.
@ -86,9 +86,15 @@ cube
sketch001 = startSketchOn(XY) sketch001 = startSketchOn(XY)
rectangleSketch = startProfileAt([-200, 23.86], sketch001) rectangleSketch = startProfileAt([-200, 23.86], sketch001)
|> angledLine(angle = 0, length = 73.47, tag = $rectangleSegmentA001) |> angledLine([0, 73.47], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 50.61) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001)) segAng(rectangleSegmentA001) - 90,
50.61
], %)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
@ -97,7 +103,7 @@ circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
sketch002 = startSketchOn(YZ) sketch002 = startSketchOn(YZ)
sweepPath = startProfileAt([0, 0], sketch002) sweepPath = startProfileAt([0, 0], sketch002)
|> yLine(length = 231.81) |> yLine(length = 231.81)
|> tangentialArc(radius = 80, angle = -90) |> tangentialArc({ radius = 80, offset = -90 }, %)
|> xLine(length = 384.93) |> xLine(length = 384.93)
parts = sweep([rectangleSketch, circleSketch], path = sweepPath) parts = sweep([rectangleSketch, circleSketch], path = sweepPath)

View File

@ -184,17 +184,15 @@ way:
```norun ```norun
startSketchOn('XZ') startSketchOn('XZ')
|> startProfileAt(origin, %) |> startProfileAt(origin, %)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001) |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001) - 90, angle = segAng(rectangleSegmentA001) - 90,
length = 196.99, length = 196.99,
tag = $rectangleSegmentB001, }, %, $rectangleSegmentB001)
) |> angledLine({
|> angledLine(
angle = segAng(rectangleSegmentA001), angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001), length = -segLen(rectangleSegmentA001),
tag = $rectangleSegmentC001, }, %, $rectangleSegmentC001)
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
``` ```
@ -219,17 +217,15 @@ However if the code was written like this:
fn rect(origin) { fn rect(origin) {
return startSketchOn('XZ') return startSketchOn('XZ')
|> startProfileAt(origin, %) |> startProfileAt(origin, %)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001) |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001) - 90, angle = segAng(rectangleSegmentA001) - 90,
length = 196.99, length = 196.99
tag = $rectangleSegmentB001, }, %, $rectangleSegmentB001)
) |> angledLine({
|> angledLine(
angle = segAng(rectangleSegmentA001), angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001) length = -segLen(rectangleSegmentA001)
tag = $rectangleSegmentC001, }, %, $rectangleSegmentC001)
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
} }
@ -249,17 +245,15 @@ For example the following code works.
fn rect(origin) { fn rect(origin) {
return startSketchOn('XZ') return startSketchOn('XZ')
|> startProfileAt(origin, %) |> startProfileAt(origin, %)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001) |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001) - 90, angle = segAng(rectangleSegmentA001) - 90,
length = 196.99, length = 196.99
tag = $rectangleSegmentB001, }, %, $rectangleSegmentB001)
) |> angledLine({
|> angledLine(
angle = segAng(rectangleSegmentA001), angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001) length = -segLen(rectangleSegmentA001)
tag = $rectangleSegmentC001, }, %, $rectangleSegmentC001)
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
} }

View File

@ -252,7 +252,7 @@ Data for an imported geometry.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `ImportedGeometry`| | No | | `type` |enum: [`ImportedGeometry`](/docs/kcl/types/ImportedGeometry)| | No |
| `id` |[`string`](/docs/kcl/types/string)| The ID of the imported geometry. | No | | `id` |[`string`](/docs/kcl/types/string)| The ID of the imported geometry. | No |
| `value` |`[` [`string`](/docs/kcl/types/string) `]`| The original file paths. | No | | `value` |`[` [`string`](/docs/kcl/types/string) `]`| The original file paths. | No |

View File

@ -0,0 +1,22 @@
---
title: "PolarCoordsData"
excerpt: "Data for polar coordinates."
layout: manual
---
Data for polar coordinates.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `angle` |[`number`](/docs/kcl/types/number)| The angle of the line (in degrees). | No |
| `length` |[`number`](/docs/kcl/types/number)| The length of the line. | No |

View File

@ -14,17 +14,15 @@ way:
```js ```js
startSketchOn('XZ') startSketchOn('XZ')
|> startProfileAt(origin, %) |> startProfileAt(origin, %)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001) |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001) - 90, angle = segAng(rectangleSegmentA001) - 90,
length = 196.99, length = 196.99,
tag = $rectangleSegmentB001, }, %, $rectangleSegmentB001)
) |> angledLine({
|> angledLine(
angle = segAng(rectangleSegmentA001), angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001), length = -segLen(rectangleSegmentA001),
tag = $rectangleSegmentC001, }, %, $rectangleSegmentC001)
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
``` ```
@ -48,16 +46,15 @@ However if the code was written like this:
fn rect(origin) { fn rect(origin) {
return startSketchOn('XZ') return startSketchOn('XZ')
|> startProfileAt(origin, %) |> startProfileAt(origin, %)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001) |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001) - 90, angle = segAng(rectangleSegmentA001) - 90,
length = 196.99, length = 196.99
tag = $rectangleSegmentB001) }, %, $rectangleSegmentB001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001), angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001), length = -segLen(rectangleSegmentA001)
tag = $rectangleSegmentC001 }, %, $rectangleSegmentC001)
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
} }
@ -77,15 +74,15 @@ For example the following code works.
fn rect(origin) { fn rect(origin) {
return startSketchOn('XZ') return startSketchOn('XZ')
|> startProfileAt(origin, %) |> startProfileAt(origin, %)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001) |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001) - 90, angle = segAng(rectangleSegmentA001) - 90,
length = 196.99 length = 196.99
, %, $rectangleSegmentB001) }, %, $rectangleSegmentB001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001), angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001) length = -segLen(rectangleSegmentA001)
, %, $rectangleSegmentC001) }, %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
} }

File diff suppressed because one or more lines are too long

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

@ -137,7 +137,7 @@ async function doBasicSketch(
await page.waitForTimeout(100) await page.waitForTimeout(100)
} }
await page.getByRole('button', { name: 'constraints: open menu' }).click() await page.getByRole('button', { name: 'Length: open menu' }).click()
await page.getByRole('button', { name: 'Equal Length' }).click() await page.getByRole('button', { name: 'Equal Length' }).click()
// Open the code pane. // Open the code pane.

View File

@ -38,7 +38,7 @@ test.describe('Point and click for boolean workflows', () => {
path.resolve( path.resolve(
__dirname, __dirname,
'../../', '../../',
'./rust/kcl-lib/e2e/executor/inputs/boolean-setup-with-sketch-on-faces.kcl' './rust/kcl-lib/e2e/executor/inputs/boolean-setup-with'
), ),
'utf-8' 'utf-8'
) )
@ -46,6 +46,8 @@ test.describe('Point and click for boolean workflows', () => {
localStorage.setItem('persistCode', file) localStorage.setItem('persistCode', file)
}, file) }, file)
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.waitForExecutionDone()
await scene.settled(cmdBar) await scene.settled(cmdBar)
// Test coordinates for selection - these might need adjustment based on actual scene layout // Test coordinates for selection - these might need adjustment based on actual scene layout
@ -75,7 +77,6 @@ test.describe('Point and click for boolean workflows', () => {
// Select first object in the scene, expect there to be a pixel diff from the selection color change // Select first object in the scene, expect there to be a pixel diff from the selection color change
await clickFirstObject({ pixelDiff: 50 }) await clickFirstObject({ pixelDiff: 50 })
await page.waitForTimeout(1000)
// For subtract, we need to proceed to the next step before selecting the second object // For subtract, we need to proceed to the next step before selecting the second object
if (operationName !== 'subtract') { if (operationName !== 'subtract') {
@ -86,8 +87,6 @@ test.describe('Point and click for boolean workflows', () => {
// Select second object // Select second object
await clickSecondObject({ pixelDiff: 50 }) await clickSecondObject({ pixelDiff: 50 })
await page.waitForTimeout(1000)
// Confirm the operation in the command bar // Confirm the operation in the command bar
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()

View File

@ -4,7 +4,6 @@ import { uuidv4 } from '@src/lib/utils'
import type { HomePageFixture } from '@e2e/playwright/fixtures/homePageFixture' import type { HomePageFixture } from '@e2e/playwright/fixtures/homePageFixture'
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture' import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
import { getUtils } from '@e2e/playwright/test-utils' import { getUtils } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
@ -16,7 +15,6 @@ test.describe(
page: Page, page: Page,
homePage: HomePageFixture, homePage: HomePageFixture,
scene: SceneFixture, scene: SceneFixture,
toolbar: ToolbarFixture,
plane: string, plane: string,
clickCoords: { x: number; y: number } clickCoords: { x: number; y: number }
) => { ) => {
@ -61,12 +59,9 @@ test.describe(
await u.sendCustomCmd(updateCamCommand) await u.sendCustomCmd(updateCamCommand)
await u.closeDebugPanel() await u.closeDebugPanel()
await page.mouse.click(clickCoords.x, clickCoords.y) await page.mouse.click(clickCoords.x, clickCoords.y)
await page.waitForTimeout(600) // wait for animation await page.waitForTimeout(600) // wait for animation
await toolbar.waitUntilSketchingReady()
await expect( await expect(
page.getByRole('button', { name: 'line Line', exact: true }) page.getByRole('button', { name: 'line Line', exact: true })
).toBeVisible() ).toBeVisible()
@ -122,12 +117,11 @@ test.describe(
] ]
for (const config of planeConfigs) { for (const config of planeConfigs) {
test(config.plane, async ({ page, homePage, scene, toolbar }) => { test(config.plane, async ({ page, homePage, scene }) => {
await sketchOnPlaneAndBackSideTest( await sketchOnPlaneAndBackSideTest(
page, page,
homePage, homePage,
scene, scene,
toolbar,
config.plane, config.plane,
config.coords config.coords
) )

View File

@ -15,7 +15,6 @@ test.describe('Code pane and errors', { tag: ['@skipWin'] }, () => {
page, page,
homePage, homePage,
scene, scene,
cmdBar,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
@ -37,7 +36,7 @@ extrude001 = extrude(sketch001, length = 5)`
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// Ensure no badge is present // Ensure no badge is present
const codePaneButtonHolder = page.locator('#code-button-holder') const codePaneButtonHolder = page.locator('#code-button-holder')
@ -172,8 +171,6 @@ extrude001 = extrude(sketch001, length = 5)`
context, context,
page, page,
homePage, homePage,
scene,
cmdBar,
}) => { }) => {
// Load the app with the working starter code // Load the app with the working starter code
await context.addInitScript((code) => { await context.addInitScript((code) => {
@ -183,7 +180,9 @@ extrude001 = extrude(sketch001, length = 5)`
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) // FIXME: await scene.waitForExecutionDone() does not work. It still fails.
// I needed to increase this timeout to get this to pass.
await page.waitForTimeout(10000)
// Ensure badge is present // Ensure badge is present
const codePaneButtonHolder = page.locator('#code-button-holder') const codePaneButtonHolder = page.locator('#code-button-holder')

View File

@ -317,13 +317,9 @@ test.describe('Command bar tests', { tag: ['@skipWin'] }, () => {
test('Can switch between sketch tools via command bar', async ({ test('Can switch between sketch tools via command bar', async ({
page, page,
homePage, homePage,
scene,
cmdBar,
toolbar,
}) => { }) => {
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar)
const sketchButton = page.getByRole('button', { name: 'Start Sketch' }) const sketchButton = page.getByRole('button', { name: 'Start Sketch' })
const cmdBarButton = page.getByRole('button', { name: 'Commands' }) const cmdBarButton = page.getByRole('button', { name: 'Commands' })
@ -347,9 +343,7 @@ test.describe('Command bar tests', { tag: ['@skipWin'] }, () => {
// Start a sketch // Start a sketch
await sketchButton.click() await sketchButton.click()
await page.mouse.click(700, 200) await page.mouse.click(700, 200)
await toolbar.waitUntilSketchingReady()
// Switch between sketch tools via the command bar // Switch between sketch tools via the command bar
await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true') await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')

View File

@ -11,7 +11,7 @@ import { expect, test } from '@e2e/playwright/zoo-test'
test( test(
'export works on the first try', 'export works on the first try',
{ tag: ['@electron', '@skipLocalEngine'] }, { tag: ['@electron', '@skipLocalEngine'] },
async ({ page, context, scene, tronApp, cmdBar }, testInfo) => { async ({ page, context, scene, tronApp }, testInfo) => {
if (!tronApp) { if (!tronApp) {
fail() fail()
} }
@ -32,41 +32,53 @@ test(
}) })
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await test.step('on open of project', async () => { page.on('console', console.log)
// Open the project
const projectName = page.getByText(`bracket`)
await expect(projectName).toBeVisible()
await projectName.click()
await scene.settled(cmdBar)
// Expect zero errors in gutter await test.step('on open of project', async () => {
await expect(page.getByText(`bracket`)).toBeVisible()
// open the project
await page.getByText(`bracket`).click()
// expect zero errors in guter
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
// Click the export button // export the model
const exportButton = page.getByTestId('export-pane-button') const exportButton = page.getByTestId('export-pane-button')
await expect(exportButton).toBeVisible() await expect(exportButton).toBeVisible()
await scene.waitForExecutionDone()
const gltfOption = page.getByText('glTF')
const submitButton = page.getByText('Confirm Export')
const exportingToastMessage = page.getByText(`Exporting...`)
const errorToastMessage = page.getByText(`Error while exporting`)
const engineErrorToastMessage = page.getByText(`Nothing to export`)
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
// The open file's name is `main.kcl`, so the export file name should be `main.gltf`
const exportFileName = `main.gltf`
// Click the export button
await exportButton.click() await exportButton.click()
// Select the first format option
const gltfOption = cmdBar.selectOption({ name: 'glTF' })
const exportFileName = `main.gltf` // source file is named `main.kcl`
await expect(gltfOption).toBeVisible() await expect(gltfOption).toBeVisible()
await expect(page.getByText('STL')).toBeVisible()
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
// Click the checkbox // Click the checkbox
const submitButton = page.getByText('Confirm Export')
await expect(submitButton).toBeVisible() await expect(submitButton).toBeVisible()
await page.waitForTimeout(500)
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
// Find the toast.
// Look out for the toast message // Look out for the toast message
const exportingToastMessage = page.getByText(`Exporting...`)
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
await expect(exportingToastMessage).toBeVisible() await expect(exportingToastMessage).toBeVisible()
await expect(alreadyExportingToastMessage).not.toBeVisible() await expect(alreadyExportingToastMessage).not.toBeVisible()
// Expect it to succeed // Expect it to succeed.
const errorToastMessage = page.getByText(`Error while exporting`)
const engineErrorToastMessage = page.getByText(`Nothing to export`)
await expect(errorToastMessage).not.toBeVisible() await expect(errorToastMessage).not.toBeVisible()
await expect(engineErrorToastMessage).not.toBeVisible() await expect(engineErrorToastMessage).not.toBeVisible()
@ -74,7 +86,6 @@ test(
await expect(successToastMessage).toBeVisible() await expect(successToastMessage).toBeVisible()
await expect(exportingToastMessage).not.toBeVisible() await expect(exportingToastMessage).not.toBeVisible()
// Check for the exported file
const firstFileFullPath = path.resolve( const firstFileFullPath = path.resolve(
getPlaywrightDownloadDir(tronApp.projectDirName), getPlaywrightDownloadDir(tronApp.projectDirName),
exportFileName exportFileName
@ -101,50 +112,60 @@ test(
const u = await getUtils(page) const u = await getUtils(page)
await u.openFilePanel() await u.openFilePanel()
// Click on the other file
const otherKclButton = page.getByRole('button', { name: 'other.kcl' }) const otherKclButton = page.getByRole('button', { name: 'other.kcl' })
// Click the file
await otherKclButton.click() await otherKclButton.click()
// Close the file pane // Close the file pane
await u.closeFilePanel() await u.closeFilePanel()
await scene.settled(cmdBar)
// Expect zero errors in gutter // FIXME: await scene.waitForExecutionDone() does not work. The modeling indicator stays in -receive-reliable and not execution done
await page.waitForTimeout(10000)
// expect zero errors in guter
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
// Click the export button // export the model
const exportButton = page.getByTestId('export-pane-button') const exportButton = page.getByTestId('export-pane-button')
await expect(exportButton).toBeVisible() await expect(exportButton).toBeVisible()
const gltfOption = page.getByText('glTF')
const submitButton = page.getByText('Confirm Export')
const exportingToastMessage = page.getByText(`Exporting...`)
const errorToastMessage = page.getByText(`Error while exporting`)
const engineErrorToastMessage = page.getByText(`Nothing to export`)
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
// The open file's name is `other.kcl`, so the export file name should be `other.gltf`
const exportFileName = `other.gltf`
// Click the export button
await exportButton.click() await exportButton.click()
// Select the first format option
const gltfOption = cmdBar.selectOption({ name: 'glTF' })
const exportFileName = `other.gltf` // source file is named `other.kcl`
await expect(gltfOption).toBeVisible() await expect(gltfOption).toBeVisible()
await expect(page.getByText('STL')).toBeVisible()
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
// Click the checkbox // Click the checkbox
const submitButton = page.getByText('Confirm Export')
await expect(submitButton).toBeVisible() await expect(submitButton).toBeVisible()
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
// Find the toast.
// Look out for the toast message // Look out for the toast message
const exportingToastMessage = page.getByText(`Exporting...`)
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
await expect(exportingToastMessage).toBeVisible() 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`)
await expect(errorToastMessage).not.toBeVisible()
await expect(engineErrorToastMessage).not.toBeVisible()
const successToastMessage = page.getByText(`Exported successfully`) const successToastMessage = page.getByText(`Exported successfully`)
await expect(successToastMessage).toBeVisible() await test.step('Check the success toast message shows and nothing else', async () =>
await expect(exportingToastMessage).not.toBeVisible() Promise.all([
expect(alreadyExportingToastMessage).not.toBeVisible(),
expect(errorToastMessage).not.toBeVisible(),
expect(engineErrorToastMessage).not.toBeVisible(),
expect(successToastMessage).toBeVisible(),
expect(exportingToastMessage).not.toBeVisible(),
]))
// Check for the exported file=
const secondFileFullPath = path.resolve( const secondFileFullPath = path.resolve(
getPlaywrightDownloadDir(tronApp.projectDirName), getPlaywrightDownloadDir(tronApp.projectDirName),
exportFileName exportFileName

View File

@ -78,14 +78,12 @@ sketch001 = startSketchOn(XY)
// Ensure we execute the first time. // Ensure we execute the first time.
await u.openDebugPanel() await u.openDebugPanel()
await expect await expect(
.poll(() => page.locator('[data-receive-command-type="scene_clear_all"]')
page.locator('[data-receive-command-type="scene_clear_all"]').count() ).toHaveCount(1)
) await expect(
.toBe(1) page.locator('[data-message-type="execution-done"]')
await expect ).toHaveCount(2)
.poll(() => page.locator('[data-message-type="execution-done"]').count())
.toBe(2)
// Add whitespace to the end of the code. // Add whitespace to the end of the code.
await u.codeLocator.click() await u.codeLocator.click()
@ -112,14 +110,12 @@ sketch001 = startSketchOn(XY)
test('ensure we use the cache, and do not clear on append', async ({ test('ensure we use the cache, and do not clear on append', async ({
homePage, homePage,
page, page,
scene,
cmdBar,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await u.waitForPageLoad()
await u.codeLocator.click() await u.codeLocator.click()
await page.keyboard.type(`sketch001 = startSketchOn(XY) await page.keyboard.type(`sketch001 = startSketchOn(XY)
@ -503,7 +499,7 @@ sketch_001 = startSketchOn(XY)
await page.keyboard.press('ArrowLeft') await page.keyboard.press('ArrowLeft')
await page.keyboard.press('ArrowRight') await page.keyboard.press('ArrowRight')
await scene.connectionEstablished() await scene.waitForExecutionDone()
// error in guter // error in guter
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible() await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
@ -920,7 +916,7 @@ sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -5.38]) |> tangentialArcTo([24.95, -5.38], %)
|> close()` |> close()`
) )
}) })
@ -969,7 +965,7 @@ sketch001 = startSketchOn(XZ)
// expect the code to have changed // expect the code to have changed
await expect(page.locator('.cm-content')).toHaveText( await expect(page.locator('.cm-content')).toHaveText(
`sketch001 = startSketchOn(XZ) |> startProfileAt([4.61, -14.01], %) |> line(end = [12.73, -0.09]) |> tangentialArc(endAbsolute = [24.95, -5.38]) |> close()extrude001 = extrude(sketch001, length = 5)` `sketch001 = startSketchOn(XZ) |> startProfileAt([4.61, -14.01], %) |> line(end = [12.73, -0.09]) |> tangentialArcTo([24.95, -5.38], %) |> close()extrude001 = extrude(sketch001, length = 5)`
) )
// Now hit undo // Now hit undo
@ -982,7 +978,7 @@ sketch001 = startSketchOn(XZ)
.toHaveText(`sketch001 = startSketchOn(XZ) .toHaveText(`sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -5.38]) |> tangentialArcTo([24.95, -5.38], %)
|> close()`) |> close()`)
}) })
@ -998,7 +994,7 @@ sketch001 = startSketchOn(XZ)
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -0.38]) |> tangentialArcTo([24.95, -0.38], %)
|> close() |> close()
|> extrude(length = 5)` |> extrude(length = 5)`
) )
@ -1072,7 +1068,7 @@ sketch001 = startSketchOn(XZ)
// we wait so it saves the code // we wait so it saves the code
await page.waitForTimeout(800) await page.waitForTimeout(800)
// drag tangentialArc handle // drag tangentialArcTo handle
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]') const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
await page.dragAndDrop('#stream', '#stream', { await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 }, sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 },
@ -1089,7 +1085,7 @@ sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([2.71, -2.71], %) |> startProfileAt([2.71, -2.71], %)
|> line(end = [15.4, -2.78]) |> line(end = [15.4, -2.78])
|> tangentialArc(endAbsolute = [27.6, -3.05]) |> tangentialArcTo([27.6, -3.05], %)
|> close() |> close()
|> extrude(length = 5)`, |> extrude(length = 5)`,
{ shouldNormalise: true } { shouldNormalise: true }
@ -1104,7 +1100,7 @@ sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([2.71, -2.71], %) |> startProfileAt([2.71, -2.71], %)
|> line(end = [15.4, -2.78]) |> line(end = [15.4, -2.78])
|> tangentialArc(endAbsolute = [24.95, -0.38]) |> tangentialArcTo([24.95, -0.38], %)
|> close() |> close()
|> extrude(length = 5)`, |> extrude(length = 5)`,
{ shouldNormalise: true } { shouldNormalise: true }
@ -1119,7 +1115,7 @@ sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([2.71, -2.71], %) |> startProfileAt([2.71, -2.71], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -0.38]) |> tangentialArcTo([24.95, -0.38], %)
|> close() |> close()
|> extrude(length = 5)`, |> extrude(length = 5)`,
{ shouldNormalise: true } { shouldNormalise: true }
@ -1135,7 +1131,7 @@ sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -0.38]) |> tangentialArcTo([24.95, -0.38], %)
|> close() |> close()
|> extrude(length = 5)`, |> extrude(length = 5)`,
{ shouldNormalise: true } { shouldNormalise: true }
@ -1144,7 +1140,7 @@ sketch001 = startSketchOn(XZ)
) )
test( test(
`Can import a local OBJ file`, `Can use the import stdlib function on a local OBJ file`,
{ tag: '@electron' }, { tag: '@electron' },
async ({ page, context }, testInfo) => { async ({ page, context }, testInfo) => {
test.fixme(orRunWhenFullSuiteEnabled()) test.fixme(orRunWhenFullSuiteEnabled())
@ -1194,7 +1190,7 @@ sketch001 = startSketchOn(XZ)
.toBeLessThan(15) .toBeLessThan(15)
}) })
await test.step(`Write the import function line`, async () => { await test.step(`Write the import function line`, async () => {
await u.codeLocator.fill(`import 'cube.obj'\ncube`) await u.codeLocator.fill(`import('cube.obj')`)
await page.waitForTimeout(800) await page.waitForTimeout(800)
}) })
await test.step(`Reset the camera before checking`, async () => { await test.step(`Reset the camera before checking`, async () => {
@ -1319,85 +1315,4 @@ sketch001 = startSketchOn(XZ)
const element = page.locator('[data-overlay-index="1"]') const element = page.locator('[data-overlay-index="1"]')
await expect(element).toHaveAttribute('data-overlay-visible', 'true') await expect(element).toHaveAttribute('data-overlay-visible', 'true')
}) })
test(`Only show axis planes when there are no errors`, async ({
page,
homePage,
scene,
cmdBar,
}) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
profile001 = circle(sketch001, center = [-100.0, -100.0], radius = 50.0)
sketch002 = startSketchOn(XZ)
profile002 = circle(sketch002, center = [-100.0, 100.0], radius = 50.0)
extrude001 = extrude(profile002, length = 0)` // length = 0 is causing the error
)
})
const viewportSize = { width: 1200, height: 800 }
await page.setBodyDimensions(viewportSize)
await homePage.goToModelingScene()
await scene.connectionEstablished()
await scene.settled(cmdBar)
await scene.expectPixelColor(
TEST_COLORS.DARK_MODE_BKGD,
// This is a position where the blue part of the axis plane is visible if its rendered
{ x: viewportSize.width * 0.75, y: viewportSize.height * 0.2 },
15
)
})
test(`test-toolbar-buttons`, async ({
page,
homePage,
toolbar,
scene,
cmdBar,
}) => {
await test.step('Load an empty file', async () => {
await page.addInitScript(async () => {
localStorage.setItem('persistCode', '')
})
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
// wait until scene is ready to be interacted with
await scene.connectionEstablished()
await scene.settled(cmdBar)
})
await test.step('Test toolbar button correct selection', async () => {
await toolbar.expectToolbarMode.toBe('modeling')
await toolbar.startSketchPlaneSelection()
// Click on a default plane
await page.mouse.click(700, 200)
// tools cannot be selected immediately, couldn't find an event to await instead.
await page.waitForTimeout(1000)
await toolbar.selectCenterRectangle()
await expect(page.getByTestId('center-rectangle')).toHaveAttribute(
'aria-pressed',
'true'
)
})
await test.step('Test Toolbar dropdown remembering last selection', async () => {
// Select another tool
await page.getByTestId('circle-center').click()
// center-rectangle should still be the active option in the rectangle dropdown
await expect(page.getByTestId('center-rectangle')).toBeVisible()
})
})
}) })

View File

@ -19,7 +19,7 @@ length001 = timesFive(1) * 5
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([20, 10], %) |> startProfileAt([20, 10], %)
|> line(end = [10, 10]) |> line(end = [10, 10])
|> angledLine(angle = -45, length = length001) |> angledLine([-45, length001], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
revolve001 = revolve(sketch001, axis = X) revolve001 = revolve(sketch001, axis = X)
@ -38,9 +38,15 @@ extrude001 = extrude(sketch002, length = 10)
const FEATURE_TREE_SKETCH_CODE = `sketch001 = startSketchOn(XZ) const FEATURE_TREE_SKETCH_CODE = `sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 0, length = 4, tag = $rectangleSegmentA001) |> angledLine([0, 4], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 2, tag = $rectangleSegmentB001) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001) segAng(rectangleSegmentA001) - 90,
2
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close(%) |> close(%)
extrude001 = extrude(sketch001, length = 10) extrude001 = extrude(sketch001, length = 10)
@ -58,7 +64,7 @@ test.describe('Feature Tree pane', () => {
test( test(
'User can go to definition and go to function definition', 'User can go to definition and go to function definition',
{ tag: '@electron' }, { tag: '@electron' },
async ({ context, homePage, scene, editor, toolbar, cmdBar, page }) => { async ({ context, homePage, scene, editor, toolbar }) => {
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
const bracketDir = join(dir, 'test-sample') const bracketDir = join(dir, 'test-sample')
await fsp.mkdir(bracketDir, { recursive: true }) await fsp.mkdir(bracketDir, { recursive: true })
@ -80,13 +86,9 @@ test.describe('Feature Tree pane', () => {
sortBy: 'last-modified-desc', sortBy: 'last-modified-desc',
}) })
await homePage.openProject('test-sample') await homePage.openProject('test-sample')
await scene.connectionEstablished() await scene.waitForExecutionDone()
await scene.settled(cmdBar) await editor.closePane()
await toolbar.openFeatureTreePane() await toolbar.openFeatureTreePane()
await expect
.poll(() => page.getByText('Feature tree').count())
.toBeGreaterThan(1)
}) })
async function testViewSource({ async function testViewSource({
@ -252,7 +254,7 @@ test.describe('Feature Tree pane', () => {
sortBy: 'last-modified-desc', sortBy: 'last-modified-desc',
}) })
await homePage.openProject('test-sample') await homePage.openProject('test-sample')
await scene.settled(cmdBar) await scene.waitForExecutionDone()
await toolbar.openFeatureTreePane() await toolbar.openFeatureTreePane()
}) })
@ -337,7 +339,7 @@ test.describe('Feature Tree pane', () => {
sortBy: 'last-modified-desc', sortBy: 'last-modified-desc',
}) })
await homePage.openProject('test-sample') await homePage.openProject('test-sample')
await scene.settled(cmdBar) await scene.waitForExecutionDone()
await toolbar.openFeatureTreePane() await toolbar.openFeatureTreePane()
}) })
@ -412,7 +414,8 @@ profile003 = startProfileAt([0, -4.93], sketch001)
const planeColor: [number, number, number] = [74, 74, 74] const planeColor: [number, number, number] = [74, 74, 74]
await homePage.openProject('test-sample') await homePage.openProject('test-sample')
await scene.settled(cmdBar) // FIXME: @lf94 has a better way to verify execution completion, in a PR rn
await scene.waitForExecutionDone()
await test.step(`Verify we see the sketch`, async () => { await test.step(`Verify we see the sketch`, async () => {
await scene.expectPixelColor(sketchColor, testPoint, 10) await scene.expectPixelColor(sketchColor, testPoint, 10)

View File

@ -47,7 +47,6 @@ test.describe('integrations tests', () => {
await scene.connectionEstablished() await scene.connectionEstablished()
await scene.settled(cmdBar) await scene.settled(cmdBar)
await clickObj() await clickObj()
await page.waitForTimeout(1000)
await scene.moveNoWhere() await scene.moveNoWhere()
await editor.expectState({ await editor.expectState({
activeLines: [ activeLines: [
@ -73,11 +72,11 @@ test.describe('integrations tests', () => {
}) })
await test.step('setup for next assertion', async () => { await test.step('setup for next assertion', async () => {
await toolbar.openFile('main.kcl') await toolbar.openFile('main.kcl')
await page.waitForTimeout(1000)
await scene.settled(cmdBar)
await clickObj() await clickObj()
await page.waitForTimeout(1000)
await scene.moveNoWhere() await scene.moveNoWhere()
await page.waitForTimeout(1000)
await editor.expectState({ await editor.expectState({
activeLines: [ activeLines: [
'|>startProfileAt([75.8,317.2],%)//[$startCapTag,$EndCapTag]', '|>startProfileAt([75.8,317.2],%)//[$startCapTag,$EndCapTag]',
@ -90,7 +89,7 @@ test.describe('integrations tests', () => {
await toolbar.expectFileTreeState(['main.kcl', fileName]) await toolbar.expectFileTreeState(['main.kcl', fileName])
}) })
await test.step('check sketch mode is exited when opening a different file', async () => { await test.step('check sketch mode is exited when opening a different file', async () => {
await toolbar.openFile(fileName) await toolbar.openFile(fileName, { wait: false })
// check we're out of sketch mode // check we're out of sketch mode
await expect(toolbar.exitSketchBtn).not.toBeVisible() await expect(toolbar.exitSketchBtn).not.toBeVisible()

View File

@ -112,16 +112,22 @@ export class CmdBarFixture {
* and assumes we are past the `pickCommand` step. * and assumes we are past the `pickCommand` step.
*/ */
progressCmdBar = async (shouldFuzzProgressMethod = true) => { progressCmdBar = async (shouldFuzzProgressMethod = true) => {
await this.page.waitForTimeout(2000) // FIXME: Progressing the command bar is a race condition. We have an async useEffect that reports the final state via useCalculateKclExpression. If this does not run quickly enough, it will not "fail" the continue because you can press continue if the state is not ready. E2E tests do not know this.
const arrowButton = this.page.getByRole('button', { // Wait 1250ms to assume the await executeAst of the KCL input field is finished
name: 'arrow right Continue', await this.page.waitForTimeout(1250)
}) if (shouldFuzzProgressMethod || Math.random() > 0.5) {
if (await arrowButton.isVisible()) { const arrowButton = this.page.getByRole('button', {
await arrowButton.click() name: 'arrow right Continue',
})
if (await arrowButton.isVisible()) {
await arrowButton.click()
} else {
await this.page
.getByRole('button', { name: 'checkmark Submit command' })
.click()
}
} else { } else {
await this.page await this.page.keyboard.press('Enter')
.getByRole('button', { name: 'checkmark Submit command' })
.click()
} }
} }

View File

@ -39,8 +39,7 @@ export class AuthenticatedApp {
} }
async initialise(code = '') { async initialise(code = '') {
const testDir = this.testInfo.outputPath('electron-test-projects-dir') await setup(this.context, this.page, this.testInfo)
await setup(this.context, this.page, testDir, this.testInfo)
const u = await getUtils(this.page) const u = await getUtils(this.page)
await this.page.addInitScript(async (code) => { await this.page.addInitScript(async (code) => {
@ -103,11 +102,11 @@ export class ElectronZoo {
return resolve(undefined) return resolve(undefined)
} }
if (Date.now() - timeA > 3000) { if (Date.now() - timeA > 10000) {
return resolve(undefined) return resolve(undefined)
} }
setTimeout(checkDisconnected, 1) setTimeout(checkDisconnected, 0)
} }
checkDisconnected() checkDisconnected()
}) })
@ -129,9 +128,11 @@ export class ElectronZoo {
const that = this const that = this
const options = { const options = {
timeout: 120000,
args: ['.', '--no-sandbox'], args: ['.', '--no-sandbox'],
env: { env: {
...process.env, ...process.env,
TEST_SETTINGS_FILE_KEY: this.projectDirName,
IS_PLAYWRIGHT: 'true', IS_PLAYWRIGHT: 'true',
}, },
...(process.env.ELECTRON_OVERRIDE_DIST_PATH ...(process.env.ELECTRON_OVERRIDE_DIST_PATH
@ -199,14 +200,7 @@ export class ElectronZoo {
await this.context.tracing.startChunk() await this.context.tracing.startChunk()
// THIS IS ABSOLUTELY NECESSARY TO CHANGE THE PROJECT DIRECTORY BETWEEN await setup(this.context, this.page, testInfo)
// TESTS BECAUSE OF THE ELECTRON INSTANCE REUSE.
await this.electron?.evaluate(({ app }, projectDirName) => {
// @ts-ignore can't declaration merge see main.ts
app.testProperty['TEST_SETTINGS_FILE_KEY'] = projectDirName
}, this.projectDirName)
await setup(this.context, this.page, this.projectDirName, testInfo)
await this.cleanProjectDir() await this.cleanProjectDir()
@ -256,6 +250,11 @@ export class ElectronZoo {
// return app.reuseWindowForTest(); // return app.reuseWindowForTest();
// }); // });
await this.electron?.evaluate(({ app }, projectDirName) => {
// @ts-ignore can't declaration merge see main.ts
app.testProperty['TEST_SETTINGS_FILE_KEY'] = projectDirName
}, this.projectDirName)
// Always start at the root view // Always start at the root view
await this.page.goto(this.firstUrl) await this.page.goto(this.firstUrl)
@ -279,9 +278,8 @@ export class ElectronZoo {
// Not a problem if it already exists. // Not a problem if it already exists.
} }
const tempSettingsFilePath = path.resolve( const tempSettingsFilePath = path.join(
this.projectDirName, this.projectDirName,
'..',
SETTINGS_FILE_NAME SETTINGS_FILE_NAME
) )

View File

@ -99,6 +99,7 @@ export class HomePageFixture {
createAndGoToProject = async (projectTitle = 'untitled') => { createAndGoToProject = async (projectTitle = 'untitled') => {
await this.projectsLoaded() await this.projectsLoaded()
await this.projectButtonNew.click() await this.projectButtonNew.click()
await this.projectTextName.click()
await this.projectTextName.fill(projectTitle) await this.projectTextName.fill(projectTitle)
await this.projectButtonContinue.click() await this.projectButtonContinue.click()
} }

View File

@ -43,15 +43,21 @@ type DragFromHandler = (
export class SceneFixture { export class SceneFixture {
public page: Page public page: Page
public streamWrapper!: Locator public streamWrapper!: Locator
public loadingIndicator!: Locator
public networkToggleConnected!: Locator public networkToggleConnected!: Locator
public startEditSketchBtn!: Locator public startEditSketchBtn!: Locator
get exeIndicator() {
return this.page
.getByTestId('model-state-indicator-execution-done')
.or(this.page.getByTestId('model-state-indicator-receive-reliable'))
}
constructor(page: Page) { constructor(page: Page) {
this.page = page this.page = page
this.streamWrapper = page.getByTestId('stream') this.streamWrapper = page.getByTestId('stream')
this.networkToggleConnected = page this.networkToggleConnected = page.getByTestId('network-toggle-ok')
.getByTestId('network-toggle-ok') this.loadingIndicator = this.streamWrapper.getByTestId('loading')
.or(page.getByTestId('network-toggle-other'))
this.startEditSketchBtn = page this.startEditSketchBtn = page
.getByRole('button', { name: 'Start Sketch' }) .getByRole('button', { name: 'Start Sketch' })
.or(page.getByRole('button', { name: 'Edit Sketch' })) .or(page.getByRole('button', { name: 'Edit Sketch' }))
@ -225,6 +231,10 @@ export class SceneFixture {
} }
} }
waitForExecutionDone = async () => {
await expect(this.exeIndicator).toBeVisible({ timeout: 30000 })
}
connectionEstablished = async () => { connectionEstablished = async () => {
const timeout = 30000 const timeout = 30000
await expect(this.networkToggleConnected).toBeVisible({ timeout }) await expect(this.networkToggleConnected).toBeVisible({ timeout })
@ -233,9 +243,6 @@ export class SceneFixture {
settled = async (cmdBar: CmdBarFixture) => { settled = async (cmdBar: CmdBarFixture) => {
const u = await getUtils(this.page) const u = await getUtils(this.page)
await expect(this.startEditSketchBtn).not.toBeDisabled({ timeout: 15_000 })
await expect(this.startEditSketchBtn).toBeVisible()
await cmdBar.openCmdBar() await cmdBar.openCmdBar()
await cmdBar.chooseCommand('Settings · app · show debug panel') await cmdBar.chooseCommand('Settings · app · show debug panel')
await cmdBar.selectOption({ name: 'on' }).click() await cmdBar.selectOption({ name: 'on' }).click()
@ -243,6 +250,10 @@ export class SceneFixture {
await u.openDebugPanel() await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]') await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel() await u.closeDebugPanel()
await this.waitForExecutionDone()
await expect(this.startEditSketchBtn).not.toBeDisabled()
await expect(this.startEditSketchBtn).toBeVisible()
} }
expectPixelColor = async ( expectPixelColor = async (

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