Compare commits
20 Commits
lee/native
...
kcl_prelud
Author | SHA1 | Date | |
---|---|---|---|
ddce447c0b | |||
e8769eb543 | |||
46358b41a2 | |||
59274b76bf | |||
d11d363f19 | |||
f22ad7c4e7 | |||
1913519f68 | |||
4b9d4fd45b | |||
78e6816b06 | |||
6607ea1663 | |||
644a8ef3ca | |||
e3e132c0d5 | |||
be3fed8427 | |||
cefa6f85fe | |||
47ff4623bd | |||
69ff651201 | |||
788ae5dbab | |||
816870253e | |||
4987965731 | |||
042ceb42fd |
@ -1,3 +1,3 @@
|
||||
[codespell]
|
||||
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo
|
||||
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey
|
||||
skip: **/target,node_modules,build,**/Cargo.lock
|
||||
|
50
.github/workflows/cargo-build.yml
vendored
50
.github/workflows/cargo-build.yml
vendored
@ -1,50 +0,0 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- '**.rs'
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
- '**/rust-toolchain.toml'
|
||||
- .github/workflows/cargo-build.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.rs'
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
- '**/rust-toolchain.toml'
|
||||
- .github/workflows/cargo-build.yml
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
name: cargo build
|
||||
jobs:
|
||||
cargobuild:
|
||||
name: cargo build
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
dir: ['src/wasm-lib']
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install latest rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
|
||||
- name: install dependencies
|
||||
if: matrix.dir == 'src-tauri'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
|
||||
- name: Rust Cache
|
||||
uses: Swatinem/rust-cache@v2.6.1
|
||||
|
||||
- name: Run cargo build
|
||||
run: |
|
||||
cd "${{ matrix.dir }}"
|
||||
cargo build --all
|
||||
shell: bash
|
6
.github/workflows/cargo-clippy.yml
vendored
6
.github/workflows/cargo-clippy.yml
vendored
@ -9,12 +9,6 @@ on:
|
||||
- '**.rs'
|
||||
- .github/workflows/cargo-clippy.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
- '**/rust-toolchain.toml'
|
||||
- '**.rs'
|
||||
- .github/workflows/cargo-build.yml
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
4
.github/workflows/cargo-test.yml
vendored
4
.github/workflows/cargo-test.yml
vendored
@ -3,7 +3,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- src/wasm-lib/**.rs'
|
||||
- 'src/wasm-lib/**.rs'
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
- '**/rust-toolchain.toml'
|
||||
@ -11,7 +11,7 @@ on:
|
||||
|
||||
pull_request:
|
||||
paths:
|
||||
- src/wasm-lib/**.rs'
|
||||
- 'src/wasm-lib/**.rs'
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
- '**/rust-toolchain.toml'
|
||||
|
36
.github/workflows/check-exampleKcl.yml
vendored
Normal file
36
.github/workflows/check-exampleKcl.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: Check Onboarding KCL
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
paths:
|
||||
- 'src/lib/exampleKcl.ts'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Comment on PR
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const message = '`src/lib/exampleKcl.ts` has been updated in this PR, please review and update the `src/routes/onboarding`, if needed.';
|
||||
const issue_number = context.payload.pull_request.number;
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
|
||||
// Post a comment on the PR
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number,
|
||||
body: message,
|
||||
});
|
@ -17,7 +17,7 @@ angleToMatchLengthX(segment_name: string, to: number, sketch_group: SketchGroup)
|
||||
```js
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [1, 3.82], tag: 'seg01' }, %)
|
||||
|> line([1, 3.82], %, 'seg01')
|
||||
|> angledLineToX([
|
||||
-angleToMatchLengthX('seg01', 10, %),
|
||||
5
|
||||
|
@ -17,7 +17,7 @@ angleToMatchLengthY(segment_name: string, to: number, sketch_group: SketchGroup)
|
||||
```js
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [1, 3.82], tag: 'seg01' }, %)
|
||||
|> line([1, 3.82], %, 'seg01')
|
||||
|> angledLineToX([
|
||||
-angleToMatchLengthY('seg01', 10, %),
|
||||
5
|
||||
|
@ -9,7 +9,7 @@ Draw an angled line.
|
||||
|
||||
|
||||
```js
|
||||
angledLine(data: AngledLineData, sketch_group: SketchGroup) -> SketchGroup
|
||||
angledLine(data: AngledLineData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -17,7 +17,7 @@ angledLine(data: AngledLineData, sketch_group: SketchGroup) -> SketchGroup
|
||||
```js
|
||||
startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> angledLine({ angle: 45, length: 10, tag: "edge1" }, %)
|
||||
|> angledLine({ angle: 45, length: 10 }, %, "edge1")
|
||||
|> line([10, 10], %)
|
||||
|> line([0, 10], %)
|
||||
|> close(%, "edge2")
|
||||
@ -33,8 +33,6 @@ startSketchOn('XY')
|
||||
angle: number,
|
||||
// The length of the line.
|
||||
length: number,
|
||||
// The tag.
|
||||
tag: string,
|
||||
} |
|
||||
[number, number]
|
||||
```
|
||||
@ -202,6 +200,7 @@ startSketchOn('XY')
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Draw an angled line of a given x length.
|
||||
|
||||
|
||||
```js
|
||||
angledLineOfXLength(data: AngledLineData, sketch_group: SketchGroup) -> SketchGroup
|
||||
angledLineOfXLength(data: AngledLineData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -17,7 +17,7 @@ angledLineOfXLength(data: AngledLineData, sketch_group: SketchGroup) -> SketchGr
|
||||
```js
|
||||
startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> angledLineOfXLength({ angle: 45, length: 10, tag: "edge1" }, %)
|
||||
|> angledLineOfXLength({ angle: 45, length: 10 }, %, "edge1")
|
||||
|> line([10, 10], %)
|
||||
|> line([0, 10], %)
|
||||
|> close(%, "edge2")
|
||||
@ -33,8 +33,6 @@ startSketchOn('XZ')
|
||||
angle: number,
|
||||
// The length of the line.
|
||||
length: number,
|
||||
// The tag.
|
||||
tag: string,
|
||||
} |
|
||||
[number, number]
|
||||
```
|
||||
@ -202,6 +200,7 @@ startSketchOn('XZ')
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Draw an angled line of a given y length.
|
||||
|
||||
|
||||
```js
|
||||
angledLineOfYLength(data: AngledLineData, sketch_group: SketchGroup) -> SketchGroup
|
||||
angledLineOfYLength(data: AngledLineData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -17,7 +17,7 @@ angledLineOfYLength(data: AngledLineData, sketch_group: SketchGroup) -> SketchGr
|
||||
```js
|
||||
startSketchOn('YZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> angledLineOfYLength({ angle: 45, length: 10, tag: "edge1" }, %)
|
||||
|> angledLineOfYLength({ angle: 45, length: 10 }, %, "edge1")
|
||||
|> line([10, 10], %)
|
||||
|> line([0, 10], %)
|
||||
|> close(%, "edge2")
|
||||
@ -34,8 +34,6 @@ startSketchOn('YZ')
|
||||
angle: number,
|
||||
// The length of the line.
|
||||
length: number,
|
||||
// The tag.
|
||||
tag: string,
|
||||
} |
|
||||
[number, number]
|
||||
```
|
||||
@ -203,6 +201,7 @@ startSketchOn('YZ')
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Draw an angled line that intersects with a given line.
|
||||
|
||||
|
||||
```js
|
||||
angledLineThatIntersects(data: AngledLineThatIntersectsData, sketch_group: SketchGroup) -> SketchGroup
|
||||
angledLineThatIntersects(data: AngledLineThatIntersectsData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -17,14 +17,13 @@ angledLineThatIntersects(data: AngledLineThatIntersectsData, sketch_group: Sketc
|
||||
```js
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo({ to: [2, 2], tag: "yo" }, %)
|
||||
|> lineTo([2, 2], %, "yo")
|
||||
|> lineTo([3, 1], %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 180,
|
||||
intersectTag: 'yo',
|
||||
offset: 12,
|
||||
tag: "yo2"
|
||||
}, %)
|
||||
offset: 12
|
||||
}, %, "yo2")
|
||||
|> line([4, 0], %)
|
||||
|> close(%, "yo3")
|
||||
|> extrude(10, %)
|
||||
@ -41,8 +40,6 @@ const part001 = startSketchOn('XY')
|
||||
intersectTag: string,
|
||||
// The offset from the intersecting line.
|
||||
offset: number,
|
||||
// The tag.
|
||||
tag: string,
|
||||
}
|
||||
```
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
@ -209,6 +206,7 @@ const part001 = startSketchOn('XY')
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Draw an angled line to a given x coordinate.
|
||||
|
||||
|
||||
```js
|
||||
angledLineToX(data: AngledLineToData, sketch_group: SketchGroup) -> SketchGroup
|
||||
angledLineToX(data: AngledLineToData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -17,7 +17,7 @@ angledLineToX(data: AngledLineToData, sketch_group: SketchGroup) -> SketchGroup
|
||||
```js
|
||||
startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> angledLineToX({ angle: 45, to: 10, tag: "edge1" }, %)
|
||||
|> angledLineToX({ angle: 45, to: 10 }, %, "edge1")
|
||||
|> line([10, 10], %)
|
||||
|> line([0, 10], %)
|
||||
|> close(%, "edge2")
|
||||
@ -32,12 +32,9 @@ startSketchOn('XY')
|
||||
{
|
||||
// The angle of the line.
|
||||
angle: number,
|
||||
// The tag.
|
||||
tag: string,
|
||||
// The point to draw to.
|
||||
to: number,
|
||||
} |
|
||||
[number, number]
|
||||
}
|
||||
```
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
```js
|
||||
@ -203,6 +200,7 @@ startSketchOn('XY')
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Draw an angled line to a given y coordinate.
|
||||
|
||||
|
||||
```js
|
||||
angledLineToY(data: AngledLineToData, sketch_group: SketchGroup) -> SketchGroup
|
||||
angledLineToY(data: AngledLineToData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -17,7 +17,7 @@ angledLineToY(data: AngledLineToData, sketch_group: SketchGroup) -> SketchGroup
|
||||
```js
|
||||
startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> angledLineToY({ angle: 45, to: 10, tag: "edge1" }, %)
|
||||
|> angledLineToY({ angle: 45, to: 10 }, %, "edge1")
|
||||
|> line([10, 10], %)
|
||||
|> line([0, 10], %)
|
||||
|> close(%, "edge2")
|
||||
@ -31,12 +31,9 @@ startSketchOn('XY')
|
||||
{
|
||||
// The angle of the line.
|
||||
angle: number,
|
||||
// The tag.
|
||||
tag: string,
|
||||
// The point to draw to.
|
||||
to: number,
|
||||
} |
|
||||
[number, number]
|
||||
}
|
||||
```
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
```js
|
||||
@ -202,6 +199,7 @@ startSketchOn('XY')
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Draw an arc.
|
||||
|
||||
|
||||
```js
|
||||
arc(data: ArcData, sketch_group: SketchGroup) -> SketchGroup
|
||||
arc(data: ArcData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -20,9 +20,8 @@ startSketchOn('-YZ')
|
||||
|> arc({
|
||||
angle_start: 0,
|
||||
angle_end: 360,
|
||||
radius: 10,
|
||||
tag: "edge1"
|
||||
}, %)
|
||||
radius: 10
|
||||
}, %, "edge1")
|
||||
|> extrude(10, %)
|
||||
```
|
||||
|
||||
@ -37,16 +36,12 @@ startSketchOn('-YZ')
|
||||
angle_start: number,
|
||||
// The radius.
|
||||
radius: number,
|
||||
// The tag.
|
||||
tag: string,
|
||||
} |
|
||||
{
|
||||
// The center.
|
||||
center: [number, number],
|
||||
// The radius.
|
||||
radius: number,
|
||||
// The tag.
|
||||
tag: string,
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
}
|
||||
@ -215,6 +210,7 @@ startSketchOn('-YZ')
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Draw a bezier curve.
|
||||
|
||||
|
||||
```js
|
||||
bezierCurve(data: BezierData, sketch_group: SketchGroup) -> SketchGroup
|
||||
bezierCurve(data: BezierData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -20,9 +20,8 @@ startSketchOn('XY')
|
||||
|> bezierCurve({
|
||||
to: [10, 10],
|
||||
control1: [5, 0],
|
||||
control2: [5, 10],
|
||||
tag: "edge1"
|
||||
}, %)
|
||||
control2: [5, 10]
|
||||
}, %, "edge1")
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
```
|
||||
@ -36,8 +35,6 @@ startSketchOn('XY')
|
||||
control1: [number, number],
|
||||
// The second control point.
|
||||
control2: [number, number],
|
||||
// The tag.
|
||||
tag: string,
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
}
|
||||
@ -206,6 +203,7 @@ startSketchOn('XY')
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -17,9 +17,9 @@ fillet(data: FilletData, extrude_group: ExtrudeGroup) -> ExtrudeGroup
|
||||
```js
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [0, 10], tag: "thing" }, %)
|
||||
|> line([0, 10], %, "thing")
|
||||
|> line([10, 0], %)
|
||||
|> line({ to: [0, -10], tag: "thing2" }, %)
|
||||
|> line([0, -10], %, "thing2")
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
|> fillet({ radius: 2, tags: ["thing", "thing2"] }, %)
|
||||
|
@ -19,7 +19,7 @@ const box = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, 10], %)
|
||||
|> line([10, 0], %)
|
||||
|> line({ to: [0, -10], tag: "surface" }, %)
|
||||
|> line([0, -10], %, "surface")
|
||||
|> close(%)
|
||||
|> extrude(5, %)
|
||||
|
||||
|
@ -17,9 +17,9 @@ getNextAdjacentEdge(tag: String, extrude_group: ExtrudeGroup) -> Uuid
|
||||
```js
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [0, 10], tag: "thing" }, %)
|
||||
|> line({ to: [10, 0], tag: "thing1" }, %)
|
||||
|> line({ to: [0, -10], tag: "thing2" }, %)
|
||||
|> line([0, 10], %, "thing")
|
||||
|> line([10, 0], %, "thing1")
|
||||
|> line([0, -10], %, "thing2")
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
|> fillet({
|
||||
|
@ -17,9 +17,9 @@ getOppositeEdge(tag: String, extrude_group: ExtrudeGroup) -> Uuid
|
||||
```js
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [0, 10], tag: "thing" }, %)
|
||||
|> line([0, 10], %, "thing")
|
||||
|> line([10, 0], %)
|
||||
|> line({ to: [0, -10], tag: "thing2" }, %)
|
||||
|> line([0, -10], %, "thing2")
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
|> fillet({
|
||||
|
@ -17,9 +17,9 @@ getPreviousAdjacentEdge(tag: String, extrude_group: ExtrudeGroup) -> Uuid
|
||||
```js
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [0, 10], tag: "thing" }, %)
|
||||
|> line({ to: [10, 0], tag: "thing1" }, %)
|
||||
|> line({ to: [0, -10], tag: "thing2" }, %)
|
||||
|> line([0, 10], %, "thing")
|
||||
|> line([10, 0], %, "thing1")
|
||||
|> line([0, -10], %, "thing2")
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
|> fillet({
|
||||
|
@ -17,7 +17,7 @@ lastSegX(sketch_group: SketchGroup) -> number
|
||||
```js
|
||||
startSketchOn("YZ")
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [5, 0], tag: "thing" }, %)
|
||||
|> line([5, 0], %, "thing")
|
||||
|> line([5, 5], %)
|
||||
|> line([0, lastSegX(%)], %)
|
||||
|> close(%)
|
||||
|
@ -17,7 +17,7 @@ lastSegY(sketch_group: SketchGroup) -> number
|
||||
```js
|
||||
startSketchOn("YZ")
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [5, 0], tag: "thing" }, %)
|
||||
|> line([5, 0], %, "thing")
|
||||
|> line([5, 5], %)
|
||||
|> line([0, lastSegY(%)], %)
|
||||
|> close(%)
|
||||
|
@ -9,7 +9,7 @@ Draw a line.
|
||||
|
||||
|
||||
```js
|
||||
line(data: LineData, sketch_group: SketchGroup) -> SketchGroup
|
||||
line(delta: [number], sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -18,23 +18,14 @@ line(data: LineData, sketch_group: SketchGroup) -> SketchGroup
|
||||
startSketchOn('-XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([10, 10], %)
|
||||
|> line({ to: [20, 10], tag: "edge1" }, %)
|
||||
|> line([20, 10], %, "edge1")
|
||||
|> close(%, "edge2")
|
||||
|> extrude(10, %)
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
* `data`: `LineData` - Data to draw a line. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The tag.
|
||||
tag: string,
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
} |
|
||||
[number, number]
|
||||
```
|
||||
* `delta`: `[number]` (REQUIRED)
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
@ -199,6 +190,7 @@ startSketchOn('-XY')
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Draw a line to a point.
|
||||
|
||||
|
||||
```js
|
||||
lineTo(data: LineToData, sketch_group: SketchGroup) -> SketchGroup
|
||||
lineTo(to: [number], sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -18,18 +18,9 @@ lineTo(data: LineToData, sketch_group: SketchGroup) -> SketchGroup
|
||||
fn rectShape = (pos, w, l) => {
|
||||
const rr = startSketchOn('YZ')
|
||||
|> startProfileAt([pos[0] - (w / 2), pos[1] - (l / 2)], %)
|
||||
|> lineTo({
|
||||
to: [pos[0] + w / 2, pos[1] - (l / 2)],
|
||||
tag: "edge1"
|
||||
}, %)
|
||||
|> lineTo({
|
||||
to: [pos[0] + w / 2, pos[1] + l / 2],
|
||||
tag: "edge2"
|
||||
}, %)
|
||||
|> lineTo({
|
||||
to: [pos[0] - (w / 2), pos[1] + l / 2],
|
||||
tag: "edge3"
|
||||
}, %)
|
||||
|> lineTo([pos[0] + w / 2, pos[1] - (l / 2)], %, "edge1")
|
||||
|> lineTo([pos[0] + w / 2, pos[1] + l / 2], %, "edge2")
|
||||
|> lineTo([pos[0] - (w / 2), pos[1] + l / 2], %, "edge3")
|
||||
|> close(%, "edge4")
|
||||
return rr
|
||||
}
|
||||
@ -40,16 +31,7 @@ const part = rectShape([0, 0], 20, 20)
|
||||
|
||||
### Arguments
|
||||
|
||||
* `data`: `LineToData` - Data to draw a line to a point. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The tag.
|
||||
tag: string,
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
} |
|
||||
[number, number]
|
||||
```
|
||||
* `to`: `[number]` (REQUIRED)
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
@ -214,6 +196,7 @@ const part = rectShape([0, 0], 20, 20)
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -18,7 +18,7 @@ segAng(segment_name: string, sketch_group: SketchGroup) -> number
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([4.83, 12.56], %)
|
||||
|> line([15.1, 2.48], %)
|
||||
|> line({ to: [3.15, -9.85], tag: 'seg01' }, %)
|
||||
|> line([3.15, -9.85], %, 'seg01')
|
||||
|> line([-15.17, -4.1], %)
|
||||
|> angledLine([segAng('seg01', %), 12.35], %)
|
||||
|> line([-13.02, 10.03], %)
|
||||
|
@ -17,7 +17,7 @@ segEndX(segment_name: string, sketch_group: SketchGroup) -> number
|
||||
```js
|
||||
startSketchOn("YZ")
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [5, 0], tag: "thing" }, %)
|
||||
|> line([5, 0], %, "thing")
|
||||
|> line([5, 5], %)
|
||||
|> line([segEndX("thing", %), 5], %)
|
||||
|> close(%)
|
||||
|
@ -17,7 +17,7 @@ segEndY(segment_name: string, sketch_group: SketchGroup) -> number
|
||||
```js
|
||||
startSketchOn("YZ")
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [5, 0], tag: "thing" }, %)
|
||||
|> line([5, 0], %, "thing")
|
||||
|> line([5, 5], %)
|
||||
|> line([segEndY("thing", %), 5], %)
|
||||
|> close(%)
|
||||
|
@ -17,7 +17,7 @@ segLen(segment_name: string, sketch_group: SketchGroup) -> number
|
||||
```js
|
||||
startSketchOn("YZ")
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [5, 0], tag: "thing" }, %)
|
||||
|> line([5, 0], %, "thing")
|
||||
|> line([5, 5], %)
|
||||
|> line([0, segLen("thing", %)], %)
|
||||
|> close(%)
|
||||
|
@ -9,7 +9,7 @@ Start a profile at a given point.
|
||||
|
||||
|
||||
```js
|
||||
startProfileAt(data: LineData, sketch_surface: SketchSurface) -> SketchGroup
|
||||
startProfileAt(to: [number], sketch_surface: SketchSurface, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -22,16 +22,7 @@ startSketchOn('XY')
|
||||
|
||||
### Arguments
|
||||
|
||||
* `data`: `LineData` - Data to draw a line. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The tag.
|
||||
tag: string,
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
} |
|
||||
[number, number]
|
||||
```
|
||||
* `to`: `[number]` (REQUIRED)
|
||||
* `sketch_surface`: `SketchSurface` - A sketch group type. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
@ -93,6 +84,7 @@ startSketchOn('XY')
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Start a sketch at a given point on the 'XY' plane.
|
||||
|
||||
|
||||
```js
|
||||
startSketchAt(data: LineData) -> SketchGroup
|
||||
startSketchAt(data: [number]) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -21,16 +21,7 @@ startSketchAt([0, 0])
|
||||
|
||||
### Arguments
|
||||
|
||||
* `data`: `LineData` - Data to draw a line. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The tag.
|
||||
tag: string,
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
} |
|
||||
[number, number]
|
||||
```
|
||||
* `data`: `[number]` (REQUIRED)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -18,7 +18,7 @@ startSketchOn(data: SketchData, tag?: SketchOnFaceTag) -> SketchSurface
|
||||
startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([10, 10], %)
|
||||
|> line({ to: [20, 10], tag: "edge1" }, %)
|
||||
|> line([20, 10], %, "edge1")
|
||||
|> close(%, "edge2")
|
||||
```
|
||||
|
||||
@ -40,7 +40,7 @@ const box = cube([0, 0], 20)
|
||||
const part001 = startSketchOn(box, "start")
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([10, 10], %)
|
||||
|> line({ to: [20, 10], tag: "edge1" }, %)
|
||||
|> line([20, 10], %, "edge1")
|
||||
|> close(%)
|
||||
|> extrude(20, %)
|
||||
```
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,7 @@ Draw an arc.
|
||||
|
||||
|
||||
```js
|
||||
tangentialArc(data: TangentialArcData, sketch_group: SketchGroup) -> SketchGroup
|
||||
tangentialArc(data: TangentialArcData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -17,8 +17,8 @@ tangentialArc(data: TangentialArcData, sketch_group: SketchGroup) -> SketchGroup
|
||||
```js
|
||||
startSketchOn('-YZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [10, 10], tag: "edge0" }, %)
|
||||
|> tangentialArc({ radius: 10, offset: 90, tag: "edge1" }, %)
|
||||
|> line([10, 10], %, "edge1")
|
||||
|> tangentialArc({ radius: 10, offset: 90 }, %, "edge1")
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
```
|
||||
@ -33,12 +33,6 @@ startSketchOn('-YZ')
|
||||
// Radius of the arc. Not to be confused with Raiders of the Lost Ark.
|
||||
radius: number,
|
||||
} |
|
||||
{
|
||||
// The tag.
|
||||
tag: string,
|
||||
// Where the arc should end. Must lie in the same plane as the current path pen position. Must not be colinear with current path pen position.
|
||||
to: [number, number],
|
||||
} |
|
||||
[number, number]
|
||||
```
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
@ -205,6 +199,7 @@ startSketchOn('-YZ')
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -17,7 +17,7 @@ tangentialArcTo(to: [number], sketch_group: SketchGroup, tag?: String) -> Sketch
|
||||
```js
|
||||
startSketchOn('-YZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [10, 10], tag: "edge0" }, %)
|
||||
|> line([10, 10], %, "edge0")
|
||||
|> tangentialArcTo([10, 0], %)
|
||||
|> close(%)
|
||||
```
|
||||
|
@ -9,7 +9,7 @@ Draw a line on the x-axis.
|
||||
|
||||
|
||||
```js
|
||||
xLine(data: AxisLineData, sketch_group: SketchGroup) -> SketchGroup
|
||||
xLine(length: number, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -25,16 +25,7 @@ startSketchOn('YZ')
|
||||
|
||||
### Arguments
|
||||
|
||||
* `data`: `AxisLineData` - Data to draw a line on an axis. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The length of the line.
|
||||
length: number,
|
||||
// The tag.
|
||||
tag: string,
|
||||
} |
|
||||
number
|
||||
```
|
||||
* `length`: `number` (REQUIRED)
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
@ -199,6 +190,7 @@ number
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Draw a line to a point on the x-axis.
|
||||
|
||||
|
||||
```js
|
||||
xLineTo(data: AxisLineToData, sketch_group: SketchGroup) -> SketchGroup
|
||||
xLineTo(to: number, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -17,7 +17,7 @@ xLineTo(data: AxisLineToData, sketch_group: SketchGroup) -> SketchGroup
|
||||
```js
|
||||
startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> xLineTo({ to: 10, tag: "edge1" }, %)
|
||||
|> xLineTo(10, %, "edge1")
|
||||
|> line([10, 10], %)
|
||||
|> close(%, "edge2")
|
||||
|> extrude(10, %)
|
||||
@ -25,16 +25,7 @@ startSketchOn('XY')
|
||||
|
||||
### Arguments
|
||||
|
||||
* `data`: `AxisLineToData` - Data to draw a line to a point on an axis. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The tag.
|
||||
tag: string,
|
||||
// The to point.
|
||||
to: number,
|
||||
} |
|
||||
number
|
||||
```
|
||||
* `to`: `number` (REQUIRED)
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
@ -199,6 +190,7 @@ number
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Draw a line on the y-axis.
|
||||
|
||||
|
||||
```js
|
||||
yLine(data: AxisLineData, sketch_group: SketchGroup) -> SketchGroup
|
||||
yLine(length: number, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -25,16 +25,7 @@ startSketchOn('XY')
|
||||
|
||||
### Arguments
|
||||
|
||||
* `data`: `AxisLineData` - Data to draw a line on an axis. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The length of the line.
|
||||
length: number,
|
||||
// The tag.
|
||||
tag: string,
|
||||
} |
|
||||
number
|
||||
```
|
||||
* `length`: `number` (REQUIRED)
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
@ -199,6 +190,7 @@ number
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Draw a line to a point on the y-axis.
|
||||
|
||||
|
||||
```js
|
||||
yLineTo(data: AxisLineToData, sketch_group: SketchGroup) -> SketchGroup
|
||||
yLineTo(to: number, sketch_group: SketchGroup, tag?: String) -> SketchGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -17,7 +17,7 @@ yLineTo(data: AxisLineToData, sketch_group: SketchGroup) -> SketchGroup
|
||||
```js
|
||||
startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> yLineTo({ to: 10, tag: "edge1" }, %)
|
||||
|> yLineTo(10, %, "edge1")
|
||||
|> line([10, 10], %)
|
||||
|> close(%, "edge2")
|
||||
|> extrude(10, %)
|
||||
@ -26,16 +26,7 @@ startSketchOn('XZ')
|
||||
|
||||
### Arguments
|
||||
|
||||
* `data`: `AxisLineToData` - Data to draw a line to a point on an axis. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The tag.
|
||||
tag: string,
|
||||
// The to point.
|
||||
to: number,
|
||||
} |
|
||||
number
|
||||
```
|
||||
* `to`: `number` (REQUIRED)
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
@ -200,6 +191,7 @@ number
|
||||
},
|
||||
}
|
||||
```
|
||||
* `tag`: `String` (OPTIONAL)
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -130,7 +130,7 @@ test('Basic sketch', async ({ page }) => {
|
||||
await expect(page.locator('.cm-content'))
|
||||
.toHaveText(`const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt(${commonPoints.startAt}, %)
|
||||
|> line({ to: [${commonPoints.num1}, 0], tag: 'seg01' }, %)
|
||||
|> line([${commonPoints.num1}, 0], %, 'seg01')
|
||||
|> line([0, ${commonPoints.num1}], %)
|
||||
|> angledLine([180, segLen('seg01', %)], %)`)
|
||||
})
|
||||
|
@ -55,10 +55,9 @@ const part001 = startSketchOn('-XZ')
|
||||
|> angledLineToY({
|
||||
angle: topAng,
|
||||
to: totalHeightHalf,
|
||||
tag: 'seg04'
|
||||
}, %)
|
||||
|> xLineTo({ to: totalLen, tag: 'seg03' }, %)
|
||||
|> yLine({ length: -armThick, tag: 'seg01' }, %)
|
||||
}, %, 'seg04')
|
||||
|> xLineTo(totalLen, %, 'seg03')
|
||||
|> yLine(-armThick, %, 'seg01')
|
||||
|> angledLineThatIntersects({
|
||||
angle: HALF_TURN,
|
||||
offset: -armThick,
|
||||
@ -68,8 +67,7 @@ const part001 = startSketchOn('-XZ')
|
||||
|> angledLineToY({
|
||||
angle: -bottomAng,
|
||||
to: -totalHeightHalf - armThick,
|
||||
tag: 'seg02'
|
||||
}, %)
|
||||
}, %, 'seg02')
|
||||
|> xLineTo(segEndX('seg03', %) + 0, %)
|
||||
|> yLine(-segLen('seg01', %), %)
|
||||
|> angledLineThatIntersects({
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "untitled-app",
|
||||
"version": "0.15.6",
|
||||
"version": "0.16.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.10.2",
|
||||
|
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@ -3876,7 +3876,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-fs-extra"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#d95a1b382f512a0be748e7a89e0f8fc4278010e2"
|
||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#6db4320e98a4278d605dd05d4d87e1433939a7cd"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
|
@ -7,7 +7,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "zoo-modeling-app",
|
||||
"version": "0.15.6"
|
||||
"version": "0.16.0"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
|
@ -59,6 +59,7 @@ const router = createBrowserRouter([
|
||||
{
|
||||
loader: fileLoader,
|
||||
id: paths.FILE,
|
||||
path: paths.FILE + '/:id',
|
||||
element: (
|
||||
<Auth>
|
||||
<FileMachineProvider>
|
||||
@ -74,8 +75,11 @@ const router = createBrowserRouter([
|
||||
),
|
||||
children: [
|
||||
{
|
||||
path: paths.FILE + '/:id',
|
||||
loader: onboardingRedirectLoader,
|
||||
index: true,
|
||||
element: <></>,
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
path: makeUrlPathRelative(paths.SETTINGS),
|
||||
|
@ -30,7 +30,7 @@ describe('NetworkHealthIndicator tests', () => {
|
||||
fireEvent.click(screen.getByTestId('network-toggle'))
|
||||
|
||||
expect(screen.getByTestId('network')).toHaveTextContent(
|
||||
NETWORK_HEALTH_TEXT[NetworkHealthState.Issue]
|
||||
NETWORK_HEALTH_TEXT[NetworkHealthState.Ok]
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -6,8 +6,7 @@ import {
|
||||
ConnectingTypeGroup,
|
||||
DisconnectingType,
|
||||
engineCommandManager,
|
||||
EngineCommandManagerEvents,
|
||||
EngineConnectionEvents,
|
||||
EngineConnectionState,
|
||||
EngineConnectionStateType,
|
||||
ErrorType,
|
||||
initialConnectingTypeGroupState,
|
||||
@ -82,35 +81,37 @@ const overallConnectionStateIcon: Record<
|
||||
}
|
||||
|
||||
export function useNetworkStatus() {
|
||||
const [steps, setSteps] = useState(
|
||||
structuredClone(initialConnectingTypeGroupState)
|
||||
)
|
||||
const [steps, setSteps] = useState(initialConnectingTypeGroupState)
|
||||
const [internetConnected, setInternetConnected] = useState<boolean>(true)
|
||||
const [overallState, setOverallState] = useState<NetworkHealthState>(
|
||||
NetworkHealthState.Disconnected
|
||||
NetworkHealthState.Ok
|
||||
)
|
||||
const [pingPongHealth, setPingPongHealth] = useState<'OK' | 'BAD'>('BAD')
|
||||
const [hasCopied, setHasCopied] = useState<boolean>(false)
|
||||
|
||||
const [error, setError] = useState<ErrorType | undefined>(undefined)
|
||||
|
||||
const hasIssue = (i: [ConnectingType, boolean | undefined]) =>
|
||||
i[1] === undefined ? i[1] : !i[1]
|
||||
const issues: Record<ConnectingTypeGroup, boolean> = {
|
||||
[ConnectingTypeGroup.WebSocket]: steps[ConnectingTypeGroup.WebSocket].some(
|
||||
(a: [ConnectingType, boolean | undefined]) => a[1] === false
|
||||
),
|
||||
[ConnectingTypeGroup.ICE]: steps[ConnectingTypeGroup.ICE].some(
|
||||
(a: [ConnectingType, boolean | undefined]) => a[1] === false
|
||||
),
|
||||
[ConnectingTypeGroup.WebRTC]: steps[ConnectingTypeGroup.WebRTC].some(
|
||||
(a: [ConnectingType, boolean | undefined]) => a[1] === false
|
||||
),
|
||||
}
|
||||
|
||||
const [issues, setIssues] = useState<
|
||||
Record<ConnectingTypeGroup, boolean | undefined>
|
||||
>({
|
||||
[ConnectingTypeGroup.WebSocket]: undefined,
|
||||
[ConnectingTypeGroup.ICE]: undefined,
|
||||
[ConnectingTypeGroup.WebRTC]: undefined,
|
||||
})
|
||||
const hasIssues: boolean =
|
||||
issues[ConnectingTypeGroup.WebSocket] ||
|
||||
issues[ConnectingTypeGroup.ICE] ||
|
||||
issues[ConnectingTypeGroup.WebRTC]
|
||||
|
||||
const [hasIssues, setHasIssues] = useState<boolean | undefined>(undefined)
|
||||
useEffect(() => {
|
||||
setOverallState(
|
||||
!internetConnected
|
||||
? NetworkHealthState.Disconnected
|
||||
: hasIssues || hasIssues === undefined
|
||||
: hasIssues
|
||||
? NetworkHealthState.Issue
|
||||
: NetworkHealthState.Ok
|
||||
)
|
||||
@ -133,59 +134,19 @@ export function useNetworkStatus() {
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
console.log(pingPongHealth)
|
||||
}, [pingPongHealth])
|
||||
|
||||
useEffect(() => {
|
||||
const issues = {
|
||||
[ConnectingTypeGroup.WebSocket]: steps[
|
||||
ConnectingTypeGroup.WebSocket
|
||||
].reduce(
|
||||
(acc: boolean | undefined, a) =>
|
||||
acc === true || acc === undefined ? acc : hasIssue(a),
|
||||
false
|
||||
),
|
||||
[ConnectingTypeGroup.ICE]: steps[ConnectingTypeGroup.ICE].reduce(
|
||||
(acc: boolean | undefined, a) =>
|
||||
acc === true || acc === undefined ? acc : hasIssue(a),
|
||||
false
|
||||
),
|
||||
[ConnectingTypeGroup.WebRTC]: steps[ConnectingTypeGroup.WebRTC].reduce(
|
||||
(acc: boolean | undefined, a) =>
|
||||
acc === true || acc === undefined ? acc : hasIssue(a),
|
||||
false
|
||||
),
|
||||
}
|
||||
setIssues(issues)
|
||||
}, [steps])
|
||||
|
||||
useEffect(() => {
|
||||
setHasIssues(
|
||||
issues[ConnectingTypeGroup.WebSocket] ||
|
||||
issues[ConnectingTypeGroup.ICE] ||
|
||||
issues[ConnectingTypeGroup.WebRTC]
|
||||
)
|
||||
}, [issues])
|
||||
|
||||
useEffect(() => {
|
||||
const onPingPongChange = ({ detail: state }: CustomEvent) => {
|
||||
setPingPongHealth(state)
|
||||
}
|
||||
|
||||
const onConnectionStateChange = ({
|
||||
detail: engineConnectionState,
|
||||
}: CustomEvent) => {
|
||||
setSteps((steps) => {
|
||||
let nextSteps = structuredClone(steps)
|
||||
engineCommandManager.onConnectionStateChange(
|
||||
(engineConnectionState: EngineConnectionState) => {
|
||||
let hasSetAStep = false
|
||||
|
||||
if (
|
||||
engineConnectionState.type === EngineConnectionStateType.Connecting
|
||||
) {
|
||||
const groups = Object.values(nextSteps)
|
||||
const groups = Object.values(steps)
|
||||
for (let group of groups) {
|
||||
for (let step of group) {
|
||||
if (step[0] !== engineConnectionState.value.type) continue
|
||||
step[1] = true
|
||||
hasSetAStep = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -193,7 +154,7 @@ export function useNetworkStatus() {
|
||||
if (
|
||||
engineConnectionState.type === EngineConnectionStateType.Disconnecting
|
||||
) {
|
||||
const groups = Object.values(nextSteps)
|
||||
const groups = Object.values(steps)
|
||||
for (let group of groups) {
|
||||
for (let step of group) {
|
||||
if (
|
||||
@ -204,6 +165,7 @@ export function useNetworkStatus() {
|
||||
?.type === step[0]
|
||||
) {
|
||||
step[1] = false
|
||||
hasSetAStep = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -214,50 +176,11 @@ export function useNetworkStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the state of all steps if we have disconnected.
|
||||
if (
|
||||
engineConnectionState.type === EngineConnectionStateType.Disconnected
|
||||
) {
|
||||
return structuredClone(initialConnectingTypeGroupState)
|
||||
if (hasSetAStep) {
|
||||
setSteps(steps)
|
||||
}
|
||||
|
||||
return nextSteps
|
||||
})
|
||||
}
|
||||
|
||||
const onEngineAvailable = ({ detail: engineConnection }: CustomEvent) => {
|
||||
engineConnection.addEventListener(
|
||||
EngineConnectionEvents.PingPongChanged,
|
||||
onPingPongChange as EventListener
|
||||
)
|
||||
engineConnection.addEventListener(
|
||||
EngineConnectionEvents.ConnectionStateChanged,
|
||||
onConnectionStateChange as EventListener
|
||||
)
|
||||
}
|
||||
|
||||
engineCommandManager.addEventListener(
|
||||
EngineCommandManagerEvents.EngineAvailable,
|
||||
onEngineAvailable as EventListener
|
||||
)
|
||||
|
||||
return () => {
|
||||
engineCommandManager.removeEventListener(
|
||||
EngineCommandManagerEvents.EngineAvailable,
|
||||
onEngineAvailable as EventListener
|
||||
)
|
||||
|
||||
// When the component is unmounted these should be assigned, but it's possible
|
||||
// the component mounts and unmounts before engine is available.
|
||||
engineCommandManager.engineConnection?.addEventListener(
|
||||
EngineConnectionEvents.PingPongChanged,
|
||||
onPingPongChange as EventListener
|
||||
)
|
||||
engineCommandManager.engineConnection?.addEventListener(
|
||||
EngineConnectionEvents.ConnectionStateChanged,
|
||||
onConnectionStateChange as EventListener
|
||||
)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return {
|
||||
@ -269,7 +192,6 @@ export function useNetworkStatus() {
|
||||
error,
|
||||
setHasCopied,
|
||||
hasCopied,
|
||||
pingPongHealth,
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,18 +256,18 @@ export const NetworkHealthIndicator = () => {
|
||||
size="lg"
|
||||
icon={
|
||||
hasIssueToIcon[
|
||||
String(issues[name as ConnectingTypeGroup])
|
||||
issues[name as ConnectingTypeGroup].toString()
|
||||
]
|
||||
}
|
||||
iconClassName={
|
||||
hasIssueToIconColors[
|
||||
String(issues[name as ConnectingTypeGroup])
|
||||
issues[name as ConnectingTypeGroup].toString()
|
||||
].icon
|
||||
}
|
||||
bgClassName={
|
||||
'rounded-sm ' +
|
||||
hasIssueToIconColors[
|
||||
String(issues[name as ConnectingTypeGroup])
|
||||
issues[name as ConnectingTypeGroup].toString()
|
||||
].bg
|
||||
}
|
||||
/>
|
||||
|
@ -32,7 +32,6 @@ export const Stream = ({ className = '' }: { className?: string }) => {
|
||||
const { state } = useModelingContext()
|
||||
const { isExecuting } = useKclContext()
|
||||
const { overallState } = useNetworkStatus()
|
||||
|
||||
const isNetworkOkay = overallState === NetworkHealthState.Ok
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -360,7 +360,7 @@ describe('testing pipe operator special', () => {
|
||||
test('pipe operator with sketch', () => {
|
||||
let code = `const mySketch = startSketchAt([0, 0])
|
||||
|> lineTo([2, 3], %)
|
||||
|> lineTo({ to: [0, 1], tag: "myPath" }, %)
|
||||
|> lineTo([0, 1], %, "myPath")
|
||||
|> lineTo([1, 1], %)
|
||||
|> rx(45, %)
|
||||
`
|
||||
@ -370,18 +370,18 @@ describe('testing pipe operator special', () => {
|
||||
{
|
||||
type: 'VariableDeclaration',
|
||||
start: 0,
|
||||
end: 145,
|
||||
end: 132,
|
||||
kind: 'const',
|
||||
declarations: [
|
||||
{
|
||||
type: 'VariableDeclarator',
|
||||
start: 6,
|
||||
end: 145,
|
||||
end: 132,
|
||||
id: { type: 'Identifier', start: 6, end: 14, name: 'mySketch' },
|
||||
init: {
|
||||
type: 'PipeExpression',
|
||||
start: 17,
|
||||
end: 145,
|
||||
end: 132,
|
||||
body: [
|
||||
{
|
||||
type: 'CallExpression',
|
||||
@ -457,7 +457,7 @@ describe('testing pipe operator special', () => {
|
||||
{
|
||||
type: 'CallExpression',
|
||||
start: 67,
|
||||
end: 107,
|
||||
end: 94,
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
start: 67,
|
||||
@ -466,121 +466,92 @@ describe('testing pipe operator special', () => {
|
||||
},
|
||||
arguments: [
|
||||
{
|
||||
type: 'ObjectExpression',
|
||||
start: 74,
|
||||
end: 103,
|
||||
properties: [
|
||||
{
|
||||
type: 'ObjectProperty',
|
||||
start: 76,
|
||||
end: 86,
|
||||
key: {
|
||||
type: 'Identifier',
|
||||
start: 76,
|
||||
end: 78,
|
||||
name: 'to',
|
||||
},
|
||||
value: {
|
||||
type: 'ArrayExpression',
|
||||
start: 80,
|
||||
end: 86,
|
||||
start: 74,
|
||||
end: 80,
|
||||
elements: [
|
||||
{
|
||||
type: 'Literal',
|
||||
start: 81,
|
||||
end: 82,
|
||||
start: 75,
|
||||
end: 76,
|
||||
value: 0,
|
||||
raw: '0',
|
||||
},
|
||||
{
|
||||
type: 'Literal',
|
||||
start: 84,
|
||||
end: 85,
|
||||
start: 78,
|
||||
end: 79,
|
||||
value: 1,
|
||||
raw: '1',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{ type: 'PipeSubstitution', start: 82, end: 83 },
|
||||
{
|
||||
type: 'ObjectProperty',
|
||||
start: 88,
|
||||
end: 101,
|
||||
key: {
|
||||
type: 'Identifier',
|
||||
start: 88,
|
||||
end: 91,
|
||||
name: 'tag',
|
||||
},
|
||||
value: {
|
||||
type: 'Literal',
|
||||
start: 93,
|
||||
end: 101,
|
||||
start: 85,
|
||||
end: 93,
|
||||
value: 'myPath',
|
||||
raw: '"myPath"',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{ type: 'PipeSubstitution', start: 105, end: 106 },
|
||||
],
|
||||
optional: false,
|
||||
},
|
||||
{
|
||||
type: 'CallExpression',
|
||||
start: 113,
|
||||
end: 130,
|
||||
start: 100,
|
||||
end: 117,
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
start: 113,
|
||||
end: 119,
|
||||
start: 100,
|
||||
end: 106,
|
||||
name: 'lineTo',
|
||||
},
|
||||
arguments: [
|
||||
{
|
||||
type: 'ArrayExpression',
|
||||
start: 120,
|
||||
end: 126,
|
||||
start: 107,
|
||||
end: 113,
|
||||
elements: [
|
||||
{
|
||||
type: 'Literal',
|
||||
start: 121,
|
||||
end: 122,
|
||||
start: 108,
|
||||
end: 109,
|
||||
value: 1,
|
||||
raw: '1',
|
||||
},
|
||||
{
|
||||
type: 'Literal',
|
||||
start: 124,
|
||||
end: 125,
|
||||
start: 111,
|
||||
end: 112,
|
||||
value: 1,
|
||||
raw: '1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{ type: 'PipeSubstitution', start: 128, end: 129 },
|
||||
{ type: 'PipeSubstitution', start: 115, end: 116 },
|
||||
],
|
||||
optional: false,
|
||||
},
|
||||
{
|
||||
type: 'CallExpression',
|
||||
start: 136,
|
||||
end: 145,
|
||||
start: 123,
|
||||
end: 132,
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
start: 136,
|
||||
end: 138,
|
||||
start: 123,
|
||||
end: 125,
|
||||
name: 'rx',
|
||||
},
|
||||
arguments: [
|
||||
{
|
||||
type: 'Literal',
|
||||
start: 139,
|
||||
end: 141,
|
||||
start: 126,
|
||||
end: 128,
|
||||
value: 45,
|
||||
raw: '45',
|
||||
},
|
||||
{ type: 'PipeSubstitution', start: 143, end: 144 },
|
||||
{ type: 'PipeSubstitution', start: 130, end: 131 },
|
||||
],
|
||||
optional: false,
|
||||
},
|
||||
@ -1502,11 +1473,11 @@ const key = 'c'`
|
||||
})
|
||||
it('comments nested within a block statement', () => {
|
||||
const code = `const mySketch = startSketchAt([0,0])
|
||||
|> lineTo({ to: [0, 1], tag: 'myPath' }, %)
|
||||
|> lineTo([0, 1], %, 'myPath')
|
||||
|> lineTo([1, 1], %) /* this is
|
||||
a comment
|
||||
spanning a few lines */
|
||||
|> lineTo({ to: [1,0], tag: "rightPath" }, %)
|
||||
|> lineTo([1,0], %, "rightPath")
|
||||
|> close(%)
|
||||
`
|
||||
|
||||
@ -1516,8 +1487,8 @@ const key = 'c'`
|
||||
.nonCodeNodes
|
||||
expect(sketchNonCodeMeta[indexOfSecondLineToExpression][0]).toEqual({
|
||||
type: 'NonCodeNode',
|
||||
start: 106,
|
||||
end: 163,
|
||||
start: 93,
|
||||
end: 150,
|
||||
value: {
|
||||
type: 'inlineComment',
|
||||
style: 'block',
|
||||
@ -1529,7 +1500,7 @@ const key = 'c'`
|
||||
const code = [
|
||||
'const mySk1 = startSketchAt([0, 0])',
|
||||
' |> lineTo([1, 1], %)',
|
||||
' |> lineTo({to: [0, 1], tag: "myPath"}, %)',
|
||||
' |> lineTo([0, 1], %, "myPath")',
|
||||
' |> lineTo([1, 1], %)',
|
||||
'// a comment',
|
||||
' |> rx(90, %)',
|
||||
@ -1540,8 +1511,8 @@ const key = 'c'`
|
||||
.nonCodeNodes[3][0]
|
||||
expect(sketchNonCodeMeta).toEqual({
|
||||
type: 'NonCodeNode',
|
||||
start: 125,
|
||||
end: 138,
|
||||
start: 114,
|
||||
end: 127,
|
||||
value: {
|
||||
type: 'blockComment',
|
||||
value: 'a comment',
|
||||
|
@ -94,7 +94,7 @@ const mySketch001 = startSketchOn('XY')
|
||||
const sk1 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo([-2.5, 0], %)
|
||||
|> lineTo({ to: [0, 10], tag: "p" }, %)
|
||||
|> lineTo([0, 10], %, "p")
|
||||
|> lineTo([2.5, 0], %)
|
||||
// |> rx(45, %)
|
||||
// |> translate([1,0,1], %)
|
||||
@ -104,7 +104,7 @@ const theExtrude = extrude(2, sk1)
|
||||
const sk2 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo([-2.5, 0], %)
|
||||
|> lineTo({ to: [0, 3], tag: "p" }, %)
|
||||
|> lineTo([0, 3], %, "p")
|
||||
|> lineTo([2.5, 0], %)
|
||||
// |> transform(theTransf, %)
|
||||
|> extrude(2, %)
|
||||
@ -143,7 +143,7 @@ const sk2 = startSketchOn('XY')
|
||||
xAxis: { x: 1, y: 0, z: 0 },
|
||||
yAxis: { x: 0, y: 1, z: 0 },
|
||||
zAxis: { x: 0, y: 0, z: 1 },
|
||||
__meta: [{ sourceRange: [356, 381] }],
|
||||
__meta: [{ sourceRange: [343, 368] }],
|
||||
},
|
||||
])
|
||||
})
|
||||
|
@ -43,9 +43,9 @@ const newVar = myVar + 1`
|
||||
it('sketch declaration', async () => {
|
||||
let code = `const mySketch = startSketchOn('XY')
|
||||
|> startProfileAt([0,0], %)
|
||||
|> lineTo({to: [0,2], tag: "myPath"}, %)
|
||||
|> lineTo([0,2], %, "myPath")
|
||||
|> lineTo([2,3], %)
|
||||
|> lineTo({ to: [5,-1], tag: "rightPath" }, %)
|
||||
|> lineTo([5,-1], %, "rightPath")
|
||||
// |> close(%)
|
||||
`
|
||||
const { root } = await exe(code)
|
||||
@ -57,7 +57,7 @@ const newVar = myVar + 1`
|
||||
to: [0, 2],
|
||||
from: [0, 0],
|
||||
__geoMeta: {
|
||||
sourceRange: [72, 109],
|
||||
sourceRange: [72, 98],
|
||||
id: expect.any(String),
|
||||
},
|
||||
name: 'myPath',
|
||||
@ -68,7 +68,7 @@ const newVar = myVar + 1`
|
||||
from: [0, 2],
|
||||
name: '',
|
||||
__geoMeta: {
|
||||
sourceRange: [115, 131],
|
||||
sourceRange: [104, 120],
|
||||
id: expect.any(String),
|
||||
},
|
||||
},
|
||||
@ -77,7 +77,7 @@ const newVar = myVar + 1`
|
||||
to: [5, -1],
|
||||
from: [2, 3],
|
||||
__geoMeta: {
|
||||
sourceRange: [137, 180],
|
||||
sourceRange: [126, 156],
|
||||
id: expect.any(String),
|
||||
},
|
||||
name: 'rightPath',
|
||||
@ -99,7 +99,7 @@ const newVar = myVar + 1`
|
||||
// const code = [
|
||||
// 'const mySk1 = startSketchAt([0,0])',
|
||||
// ' |> lineTo([1,1], %)',
|
||||
// ' |> lineTo({to: [0, 1], tag: "myPath"}, %)',
|
||||
// ' |> lineTo([0, 1], %, "myPath")',
|
||||
// ' |> lineTo([1, 1], %)',
|
||||
// 'const rotated = rx(90, mySk1)',
|
||||
// ].join('\n')
|
||||
@ -126,7 +126,7 @@ const newVar = myVar + 1`
|
||||
"const mySk1 = startSketchOn('XY')",
|
||||
' |> startProfileAt([0,0], %)',
|
||||
' |> lineTo([1,1], %)',
|
||||
' |> lineTo({to: [0, 1], tag: "myPath"}, %)',
|
||||
' |> lineTo([0, 1], %, "myPath")',
|
||||
' |> lineTo([1,1], %)',
|
||||
// ' |> rx(90, %)',
|
||||
].join('\n')
|
||||
@ -159,7 +159,7 @@ const newVar = myVar + 1`
|
||||
to: [0, 1],
|
||||
from: [1, 1],
|
||||
__geoMeta: {
|
||||
sourceRange: [91, 129],
|
||||
sourceRange: [91, 118],
|
||||
id: expect.any(String),
|
||||
},
|
||||
name: 'myPath',
|
||||
@ -170,7 +170,7 @@ const newVar = myVar + 1`
|
||||
from: [0, 1],
|
||||
name: '',
|
||||
__geoMeta: {
|
||||
sourceRange: [135, 151],
|
||||
sourceRange: [124, 140],
|
||||
id: expect.any(String),
|
||||
},
|
||||
},
|
||||
@ -341,7 +341,7 @@ describe('testing math operators', () => {
|
||||
`const myVar = 3`,
|
||||
`const part001 = startSketchOn('XY')`,
|
||||
` |> startProfileAt([0, 0], %)`,
|
||||
` |> line({ to: [3, 4], tag: 'seg01' }, %)`,
|
||||
` |> line([3, 4], %, 'seg01')`,
|
||||
` |> line([`,
|
||||
` min(segLen('seg01', %), myVar),`,
|
||||
` -legLen(segLen('seg01', %), myVar)`,
|
||||
|
@ -9,10 +9,10 @@ describe('testing getNodePathFromSourceRange', () => {
|
||||
const myVar = 5
|
||||
const sk3 = startSketchAt([0, 0])
|
||||
|> lineTo([1, 2], %)
|
||||
|> lineTo({ to: [3, 4], tag: 'yo' }, %)
|
||||
|> lineTo([3, 4], %, 'yo')
|
||||
|> close(%)
|
||||
`
|
||||
const subStr = "lineTo({ to: [3, 4], tag: 'yo' }, %)"
|
||||
const subStr = "lineTo([3, 4], %, 'yo')"
|
||||
const lineToSubstringIndex = code.indexOf(subStr)
|
||||
const sourceRange: [number, number] = [
|
||||
lineToSubstringIndex,
|
||||
|
@ -152,25 +152,25 @@ describe('Testing giveSketchFnCallTag', () => {
|
||||
code,
|
||||
'line([0, 0.83], %)'
|
||||
)
|
||||
expect(newCode).toContain("line({ to: [0, 0.83], tag: 'seg01' }, %)")
|
||||
expect(newCode).toContain("line([0, 0.83], %, 'seg01')")
|
||||
expect(tag).toBe('seg01')
|
||||
expect(isTagExisting).toBe(false)
|
||||
})
|
||||
it('Should create a unique tag if seg01 already exists', () => {
|
||||
let _code = code.replace(
|
||||
'line([-2.57, -0.13], %)',
|
||||
"line({ to: [-2.57, -0.13], tag: 'seg01' }, %)"
|
||||
"line([-2.57, -0.13], %, 'seg01')"
|
||||
)
|
||||
const { newCode, tag, isTagExisting } = giveSketchFnCallTagTestHelper(
|
||||
_code,
|
||||
'line([0, 0.83], %)'
|
||||
)
|
||||
expect(newCode).toContain("line({ to: [0, 0.83], tag: 'seg02' }, %)")
|
||||
expect(newCode).toContain("line([0, 0.83], %, 'seg02')")
|
||||
expect(tag).toBe('seg02')
|
||||
expect(isTagExisting).toBe(false)
|
||||
})
|
||||
it('Should return existing tag if it already exists', () => {
|
||||
const lineButWithTag = "line({ to: [-2.57, -0.13], tag: 'butts' }, %)"
|
||||
const lineButWithTag = "line([-2.57, -0.13], %, 'butts')"
|
||||
let _code = code.replace('line([-2.57, -0.13], %)', lineButWithTag)
|
||||
const { newCode, tag, isTagExisting } = giveSketchFnCallTagTestHelper(
|
||||
_code,
|
||||
|
@ -23,11 +23,7 @@ import {
|
||||
getNodePathFromSourceRange,
|
||||
isNodeSafeToReplace,
|
||||
} from './queryAst'
|
||||
import {
|
||||
addTagForSketchOnFace,
|
||||
getFirstArg,
|
||||
createFirstArg,
|
||||
} from './std/sketch'
|
||||
import { addTagForSketchOnFace } from './std/sketch'
|
||||
import { isLiteralArrayOrStatic } from './std/sketchcombos'
|
||||
import { DefaultPlaneStr } from 'clientSideScene/sceneEntities'
|
||||
import { roundOff } from 'lib/utils'
|
||||
@ -606,23 +602,26 @@ export function giveSketchFnCallTag(
|
||||
path,
|
||||
'CallExpression'
|
||||
)
|
||||
const firstArg = getFirstArg(primaryCallExp)
|
||||
const isTagExisting = !!firstArg.tag
|
||||
const tagValue = (firstArg.tag ||
|
||||
createLiteral(tag || findUniqueName(ast, 'seg', 2))) as Literal
|
||||
const tagStr = String(tagValue.value)
|
||||
const newFirstArg = createFirstArg(
|
||||
primaryCallExp.callee.name as ToolTip,
|
||||
firstArg.val,
|
||||
tagValue
|
||||
)
|
||||
primaryCallExp.arguments[0] = newFirstArg
|
||||
// Tag is always 3rd expression now, using arg index feels brittle
|
||||
// but we can come up with a better way to identify tag later.
|
||||
const thirdArg = primaryCallExp.arguments?.[2]
|
||||
const tagLiteral =
|
||||
thirdArg || (createLiteral(tag || findUniqueName(ast, 'seg', 2)) as Literal)
|
||||
const isTagExisting = !!thirdArg
|
||||
if (!isTagExisting) {
|
||||
primaryCallExp.arguments[2] = tagLiteral
|
||||
}
|
||||
if ('value' in tagLiteral) {
|
||||
// Now TypeScript knows tagLiteral has a value property
|
||||
return {
|
||||
modifiedAst: ast,
|
||||
tag: tagStr,
|
||||
tag: String(tagLiteral.value),
|
||||
isTagExisting,
|
||||
pathToNode: path,
|
||||
}
|
||||
} else {
|
||||
throw new Error('Unable to assign tag without value')
|
||||
}
|
||||
}
|
||||
|
||||
export function moveValueIntoNewVariable(
|
||||
|
@ -250,7 +250,7 @@ describe('testing doesPipeHave', () => {
|
||||
it('finds close', () => {
|
||||
const exampleCode = `const length001 = 2
|
||||
const part001 = startSketchAt([-1.41, 3.46])
|
||||
|> line({ to: [19.49, 1.16], tag: 'seg01' }, %)
|
||||
|> line([19.49, 1.16], %, 'seg01')
|
||||
|> angledLine([-35, length001], %)
|
||||
|> line([-3.22, -7.36], %)
|
||||
|> angledLine([-175, segLen('seg01', %)], %)
|
||||
@ -267,7 +267,7 @@ const part001 = startSketchAt([-1.41, 3.46])
|
||||
it('finds extrude', () => {
|
||||
const exampleCode = `const length001 = 2
|
||||
const part001 = startSketchAt([-1.41, 3.46])
|
||||
|> line({ to: [19.49, 1.16], tag: 'seg01' }, %)
|
||||
|> line([19.49, 1.16], %, 'seg01')
|
||||
|> angledLine([-35, length001], %)
|
||||
|> line([-3.22, -7.36], %)
|
||||
|> angledLine([-175, segLen('seg01', %)], %)
|
||||
@ -285,7 +285,7 @@ const part001 = startSketchAt([-1.41, 3.46])
|
||||
it('does NOT find close', () => {
|
||||
const exampleCode = `const length001 = 2
|
||||
const part001 = startSketchAt([-1.41, 3.46])
|
||||
|> line({ to: [19.49, 1.16], tag: 'seg01' }, %)
|
||||
|> line([19.49, 1.16], %, 'seg01')
|
||||
|> angledLine([-35, length001], %)
|
||||
|> line([-3.22, -7.36], %)
|
||||
|> angledLine([-175, segLen('seg01', %)], %)
|
||||
@ -314,7 +314,7 @@ describe('testing hasExtrudeSketchGroup', () => {
|
||||
it('find sketch group', async () => {
|
||||
const exampleCode = `const length001 = 2
|
||||
const part001 = startSketchAt([-1.41, 3.46])
|
||||
|> line({ to: [19.49, 1.16], tag: 'seg01' }, %)
|
||||
|> line([19.49, 1.16], %, 'seg01')
|
||||
|> angledLine([-35, length001], %)
|
||||
|> line([-3.22, -7.36], %)
|
||||
|> angledLine([-175, segLen('seg01', %)], %)`
|
||||
@ -330,7 +330,7 @@ const part001 = startSketchAt([-1.41, 3.46])
|
||||
it('find extrude group', async () => {
|
||||
const exampleCode = `const length001 = 2
|
||||
const part001 = startSketchAt([-1.41, 3.46])
|
||||
|> line({ to: [19.49, 1.16], tag: 'seg01' }, %)
|
||||
|> line([19.49, 1.16], %, 'seg01')
|
||||
|> angledLine([-35, length001], %)
|
||||
|> line([-3.22, -7.36], %)
|
||||
|> angledLine([-175, segLen('seg01', %)], %)
|
||||
|
@ -64,9 +64,9 @@ log(5, myVar)
|
||||
})
|
||||
it('recast sketch declaration', () => {
|
||||
let code = `const mySketch = startSketchAt([0, 0])
|
||||
|> lineTo({ to: [0, 1], tag: "myPath" }, %)
|
||||
|> lineTo([0, 1], %, "myPath")
|
||||
|> lineTo([1, 1], %)
|
||||
|> lineTo({ to: [1, 0], tag: "rightPath" }, %)
|
||||
|> lineTo([1, 0], %, "rightPath")
|
||||
|> close(%)
|
||||
`
|
||||
const { ast } = code2ast(code)
|
||||
@ -77,7 +77,7 @@ log(5, myVar)
|
||||
const code = [
|
||||
'const mySk1 = startSketchAt([0, 0])',
|
||||
' |> lineTo([1, 1], %)',
|
||||
' |> lineTo({ to: [0, 1], tag: "myTag" }, %)',
|
||||
' |> lineTo([0, 1], %, "myTag")',
|
||||
' |> lineTo([1, 1], %)',
|
||||
' |> rx(90, %)',
|
||||
].join('\n')
|
||||
@ -237,7 +237,7 @@ const key = 'c'
|
||||
const code = [
|
||||
'const mySk1 = startSketchAt([0, 0])',
|
||||
' |> lineTo([1, 1], %)',
|
||||
' |> lineTo({ to: [0, 1], tag: "myTag" }, %)',
|
||||
' |> lineTo([0, 1], %, "myTag")',
|
||||
' |> lineTo([1, 1], %)',
|
||||
' // a comment',
|
||||
' |> rx(90, %)',
|
||||
@ -253,7 +253,7 @@ const key = 'c'
|
||||
const mySk1 = startSketchAt([0, 0])
|
||||
|> lineTo([1, 1], %)
|
||||
// comment here
|
||||
|> lineTo({ to: [0, 1], tag: 'myTag' }, %)
|
||||
|> lineTo([0, 1], %, 'myTag')
|
||||
|> lineTo([1, 1], %) /* and
|
||||
here
|
||||
*/
|
||||
@ -275,7 +275,7 @@ const mySk1 = startSketchAt([0, 0])
|
||||
const mySk1 = startSketchAt([0, 0])
|
||||
|> lineTo([1, 1], %)
|
||||
// comment here
|
||||
|> lineTo({ to: [0, 1], tag: 'myTag' }, %)
|
||||
|> lineTo([0, 1], %, 'myTag')
|
||||
|> lineTo([1, 1], %) /* and
|
||||
here */
|
||||
// a comment between pipe expression statements
|
||||
@ -321,7 +321,7 @@ describe('testing call Expressions in BinaryExpressions and UnaryExpressions', (
|
||||
describe('it recasts wrapped object expressions in pipe bodies with correct indentation', () => {
|
||||
it('with a single line', () => {
|
||||
const code = `const part001 = startSketchAt([-0.01, -0.08])
|
||||
|> line({ to: [0.62, 4.15], tag: 'seg01' }, %)
|
||||
|> line([0.62, 4.15], %, 'seg01')
|
||||
|> line([2.77, -1.24], %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 201,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { PathToNode, Program, SourceRange } from 'lang/wasm'
|
||||
import { VITE_KC_API_WS_MODELING_URL } from 'env'
|
||||
import { VITE_KC_API_WS_MODELING_URL, VITE_KC_CONNECTION_TIMEOUT_MS } from 'env'
|
||||
import { Models } from '@kittycad/lib'
|
||||
import { exportSave } from 'lib/exportSave'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
@ -8,9 +8,6 @@ import { sceneInfra } from 'clientSideScene/sceneInfra'
|
||||
|
||||
let lastMessage = ''
|
||||
|
||||
// TODO(paultag): This ought to be tweakable.
|
||||
const pingIntervalMs = 10000
|
||||
|
||||
interface CommandInfo {
|
||||
commandType: CommandTypes
|
||||
range: SourceRange
|
||||
@ -40,6 +37,11 @@ export interface ArtifactMap {
|
||||
[key: string]: ResultCommand | PendingCommand | FailedCommand
|
||||
}
|
||||
|
||||
interface NewTrackArgs {
|
||||
conn: EngineConnection
|
||||
mediaStream: MediaStream
|
||||
}
|
||||
|
||||
// This looks funny, I know. This is needed because node and the browser
|
||||
// disagree as to the type. In a browser it's a number, but in node it's a
|
||||
// "Timeout".
|
||||
@ -156,28 +158,10 @@ export type EngineConnectionState =
|
||||
| State<EngineConnectionStateType.Disconnecting, DisconnectingValue>
|
||||
| State<EngineConnectionStateType.Disconnected, void>
|
||||
|
||||
export type PingPongState = 'OK' | 'BAD'
|
||||
|
||||
export enum EngineConnectionEvents {
|
||||
// Fires for each ping-pong success or failure.
|
||||
PingPongChanged = 'ping-pong-changed', // (state: PingPongState) => void
|
||||
|
||||
// For now, this is only used by the NetworkHealthIndicator.
|
||||
// We can eventually use it for more, but one step at a time.
|
||||
ConnectionStateChanged = 'connection-state-changed', // (state: EngineConnectionState) => void
|
||||
|
||||
// These are used for the EngineCommandManager and were created
|
||||
// before onConnectionStateChange existed.
|
||||
ConnectionStarted = 'connection-started', // (engineConnection: EngineConnection) => void
|
||||
Opened = 'opened', // (engineConnection: EngineConnection) => void
|
||||
Closed = 'closed', // (engineConnection: EngineConnection) => void
|
||||
NewTrack = 'new-track', // (track: NewTrackArgs) => void
|
||||
}
|
||||
|
||||
// EngineConnection encapsulates the connection(s) to the Engine
|
||||
// for the EngineCommandManager; namely, the underlying WebSocket
|
||||
// and WebRTC connections.
|
||||
class EngineConnection extends EventTarget {
|
||||
class EngineConnection {
|
||||
websocket?: WebSocket
|
||||
pc?: RTCPeerConnection
|
||||
unreliableDataChannel?: RTCDataChannel
|
||||
@ -211,12 +195,7 @@ class EngineConnection extends EventTarget {
|
||||
}
|
||||
}
|
||||
this._state = next
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.ConnectionStateChanged, {
|
||||
detail: this._state,
|
||||
})
|
||||
)
|
||||
this.onConnectionStateChange(this._state)
|
||||
}
|
||||
|
||||
private failedConnTimeout: Timeout | null
|
||||
@ -224,39 +203,74 @@ class EngineConnection extends EventTarget {
|
||||
readonly url: string
|
||||
private readonly token?: string
|
||||
|
||||
// For now, this is only used by the NetworkHealthIndicator.
|
||||
// We can eventually use it for more, but one step at a time.
|
||||
private onConnectionStateChange: (state: EngineConnectionState) => void
|
||||
|
||||
// These are used for the EngineCommandManager and were created
|
||||
// before onConnectionStateChange existed.
|
||||
private onEngineConnectionOpen: (engineConnection: EngineConnection) => void
|
||||
private onConnectionStarted: (engineConnection: EngineConnection) => void
|
||||
private onClose: (engineConnection: EngineConnection) => void
|
||||
private onNewTrack: (track: NewTrackArgs) => void
|
||||
|
||||
// TODO: actual type is ClientMetrics
|
||||
private webrtcStatsCollector?: () => Promise<ClientMetrics>
|
||||
|
||||
private pingPongSpan: { ping?: Date; pong?: Date }
|
||||
|
||||
constructor({ url, token }: { url: string; token?: string }) {
|
||||
super()
|
||||
|
||||
constructor({
|
||||
url,
|
||||
token,
|
||||
onConnectionStateChange = () => {},
|
||||
onNewTrack = () => {},
|
||||
onEngineConnectionOpen = () => {},
|
||||
onConnectionStarted = () => {},
|
||||
onClose = () => {},
|
||||
}: {
|
||||
url: string
|
||||
token?: string
|
||||
onConnectionStateChange?: (state: EngineConnectionState) => void
|
||||
onEngineConnectionOpen?: (engineConnection: EngineConnection) => void
|
||||
onConnectionStarted?: (engineConnection: EngineConnection) => void
|
||||
onClose?: (engineConnection: EngineConnection) => void
|
||||
onNewTrack?: (track: NewTrackArgs) => void
|
||||
}) {
|
||||
this.url = url
|
||||
this.token = token
|
||||
this.failedConnTimeout = null
|
||||
this.onConnectionStateChange = onConnectionStateChange
|
||||
this.onEngineConnectionOpen = onEngineConnectionOpen
|
||||
this.onConnectionStarted = onConnectionStarted
|
||||
|
||||
this.pingPongSpan = { ping: undefined, pong: undefined }
|
||||
this.onClose = onClose
|
||||
this.onNewTrack = onNewTrack
|
||||
|
||||
// TODO(paultag): This ought to be tweakable.
|
||||
const pingIntervalMs = 10000
|
||||
|
||||
// Without an interval ping, our connection will timeout.
|
||||
setInterval(() => {
|
||||
let pingInterval = setInterval(() => {
|
||||
switch (this.state.type as EngineConnectionStateType) {
|
||||
case EngineConnectionStateType.ConnectionEstablished:
|
||||
this.send({ type: 'ping' })
|
||||
this.pingPongSpan.ping = new Date()
|
||||
break
|
||||
case EngineConnectionStateType.Disconnecting:
|
||||
case EngineConnectionStateType.Disconnected:
|
||||
// Reconnect if we have disconnected.
|
||||
if (!this.isConnecting()) this.connect()
|
||||
clearInterval(pingInterval)
|
||||
break
|
||||
default:
|
||||
if (this.isConnecting()) break
|
||||
// Means we never could do an initial connection. Reconnect everything.
|
||||
if (!this.pingPongSpan.ping) this.connect()
|
||||
break
|
||||
}
|
||||
}, pingIntervalMs)
|
||||
|
||||
const connectionTimeoutMs = VITE_KC_CONNECTION_TIMEOUT_MS
|
||||
let connectRetryInterval = setInterval(() => {
|
||||
if (this.state.type !== EngineConnectionStateType.Disconnected) return
|
||||
|
||||
// Only try reconnecting when completely disconnected.
|
||||
clearInterval(connectRetryInterval)
|
||||
console.log('Trying to reconnect')
|
||||
this.connect()
|
||||
}, connectionTimeoutMs)
|
||||
}
|
||||
|
||||
isConnecting() {
|
||||
@ -338,11 +352,7 @@ class EngineConnection extends EventTarget {
|
||||
// dance is it safest to connect the video tracks / stream
|
||||
case 'connected':
|
||||
// Let the browser attach to the video stream now
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.NewTrack, {
|
||||
detail: { conn: this, mediaStream: this.mediaStream! },
|
||||
})
|
||||
)
|
||||
this.onNewTrack({ conn: this, mediaStream: this.mediaStream! })
|
||||
break
|
||||
case 'failed':
|
||||
this.disconnectAll()
|
||||
@ -458,9 +468,7 @@ class EngineConnection extends EventTarget {
|
||||
// Everything is now connected.
|
||||
this.state = { type: EngineConnectionStateType.ConnectionEstablished }
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.Opened, { detail: this })
|
||||
)
|
||||
this.onEngineConnectionOpen(this)
|
||||
})
|
||||
|
||||
this.unreliableDataChannel.addEventListener('close', (event) => {
|
||||
@ -502,10 +510,6 @@ class EngineConnection extends EventTarget {
|
||||
},
|
||||
}
|
||||
|
||||
// Send an initial ping
|
||||
this.send({ type: 'ping' })
|
||||
this.pingPongSpan.ping = new Date()
|
||||
|
||||
// This is required for when KCMA is running stand-alone / within Tauri.
|
||||
// Otherwise when run in a browser, the token is sent implicitly via
|
||||
// the Cookie header.
|
||||
@ -571,34 +575,12 @@ failed cmd type was ${artifactThatFailed?.commandType}`
|
||||
let resp = message.resp
|
||||
|
||||
// If there's no body to the response, we can bail here.
|
||||
// !resp.type is usually "pong" response for our "ping"
|
||||
if (!resp || !resp.type) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (resp.type) {
|
||||
case 'pong':
|
||||
this.pingPongSpan.pong = new Date()
|
||||
if (this.pingPongSpan.ping && this.pingPongSpan.pong) {
|
||||
if (
|
||||
Math.abs(
|
||||
this.pingPongSpan.pong.valueOf() -
|
||||
this.pingPongSpan.ping.valueOf()
|
||||
) >= pingIntervalMs
|
||||
) {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.PingPongChanged, {
|
||||
detail: 'BAD',
|
||||
})
|
||||
)
|
||||
} else {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.PingPongChanged, {
|
||||
detail: 'OK',
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'ice_server_info':
|
||||
let ice_servers = resp.data?.ice_servers
|
||||
|
||||
@ -745,11 +727,27 @@ failed cmd type was ${artifactThatFailed?.commandType}`
|
||||
}
|
||||
})
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.ConnectionStarted, {
|
||||
detail: this,
|
||||
})
|
||||
)
|
||||
const connectionTimeoutMs = VITE_KC_CONNECTION_TIMEOUT_MS
|
||||
if (this.failedConnTimeout) {
|
||||
clearTimeout(this.failedConnTimeout)
|
||||
this.failedConnTimeout = null
|
||||
}
|
||||
this.failedConnTimeout = setTimeout(() => {
|
||||
if (this.isReady()) {
|
||||
return
|
||||
}
|
||||
this.failedConnTimeout = null
|
||||
this.state = {
|
||||
type: EngineConnectionStateType.Disconnecting,
|
||||
value: {
|
||||
type: DisconnectingType.Timeout,
|
||||
},
|
||||
}
|
||||
this.disconnectAll()
|
||||
this.finalizeIfAllConnectionsClosed()
|
||||
}, connectionTimeoutMs)
|
||||
|
||||
this.onConnectionStarted(this)
|
||||
}
|
||||
unreliableSend(message: object | string) {
|
||||
// TODO(paultag): Add in logic to determine the connection state and
|
||||
@ -798,8 +796,6 @@ interface UnreliableSubscription<T extends UnreliableResponses['type']> {
|
||||
callback: (data: Extract<UnreliableResponses, { type: T }>) => void
|
||||
}
|
||||
|
||||
// TODO: Should eventually be replaced with native EventTarget event system,
|
||||
// as it manages events in a more familiar way to other developers.
|
||||
export interface Subscription<T extends ModelTypes> {
|
||||
event: T
|
||||
callback: (
|
||||
@ -827,11 +823,7 @@ export type CommandLog =
|
||||
data: null
|
||||
}
|
||||
|
||||
export enum EngineCommandManagerEvents {
|
||||
EngineAvailable = 'engine-available',
|
||||
}
|
||||
|
||||
export class EngineCommandManager extends EventTarget {
|
||||
export class EngineCommandManager {
|
||||
artifactMap: ArtifactMap = {}
|
||||
lastArtifactMap: ArtifactMap = {}
|
||||
sceneCommandArtifacts: ArtifactMap = {}
|
||||
@ -865,9 +857,10 @@ export class EngineCommandManager extends EventTarget {
|
||||
}
|
||||
} = {} as any
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
callbacksEngineStateConnection: ((state: EngineConnectionState) => void)[] =
|
||||
[]
|
||||
|
||||
constructor() {
|
||||
this.engineConnection = undefined
|
||||
;(async () => {
|
||||
// circular dependency needs one to be lazy loaded
|
||||
@ -908,17 +901,12 @@ export class EngineCommandManager extends EventTarget {
|
||||
this.engineConnection = new EngineConnection({
|
||||
url,
|
||||
token,
|
||||
})
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineCommandManagerEvents.EngineAvailable, {
|
||||
detail: this.engineConnection,
|
||||
})
|
||||
)
|
||||
|
||||
this.engineConnection.addEventListener(
|
||||
EngineConnectionEvents.Opened,
|
||||
() => {
|
||||
onConnectionStateChange: (state: EngineConnectionState) => {
|
||||
for (let cb of this.callbacksEngineStateConnection) {
|
||||
cb(state)
|
||||
}
|
||||
},
|
||||
onEngineConnectionOpen: () => {
|
||||
// Make the axis gizmo.
|
||||
// We do this after the connection opened to avoid a race condition.
|
||||
// Connected opened is the last thing that happens when the stream
|
||||
@ -953,27 +941,15 @@ export class EngineCommandManager extends EventTarget {
|
||||
setIsStreamReady(true)
|
||||
executeCode(undefined, true)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
this.engineConnection.addEventListener(
|
||||
EngineConnectionEvents.Closed,
|
||||
() => {
|
||||
},
|
||||
onClose: () => {
|
||||
setIsStreamReady(false)
|
||||
}
|
||||
)
|
||||
|
||||
this.engineConnection.addEventListener(
|
||||
EngineConnectionEvents.ConnectionStarted,
|
||||
(({ detail: engineConnection }: CustomEvent) => {
|
||||
engineConnection?.pc?.addEventListener(
|
||||
'datachannel',
|
||||
(event: RTCDataChannelEvent) => {
|
||||
},
|
||||
onConnectionStarted: (engineConnection) => {
|
||||
engineConnection?.pc?.addEventListener('datachannel', (event) => {
|
||||
let unreliableDataChannel = event.channel
|
||||
|
||||
unreliableDataChannel.addEventListener(
|
||||
'message',
|
||||
(event: MessageEvent) => {
|
||||
unreliableDataChannel.addEventListener('message', (event) => {
|
||||
const result: UnreliableResponses = JSON.parse(event.data)
|
||||
Object.values(
|
||||
this.unreliableSubscriptions[result.type] || {}
|
||||
@ -993,16 +969,12 @@ export class EngineCommandManager extends EventTarget {
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// When the EngineConnection starts a connection, we want to register
|
||||
// callbacks into the WebSocket/PeerConnection.
|
||||
engineConnection.websocket?.addEventListener(
|
||||
'message',
|
||||
(event: MessageEvent) => {
|
||||
engineConnection.websocket?.addEventListener('message', (event) => {
|
||||
if (event.data instanceof ArrayBuffer) {
|
||||
// If the data is an ArrayBuffer, it's the result of an export command,
|
||||
// because in all other cases we send JSON strings. But in the case of
|
||||
@ -1027,14 +999,9 @@ export class EngineCommandManager extends EventTarget {
|
||||
this.handleFailedModelingCommand(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}) as EventListener
|
||||
)
|
||||
|
||||
this.engineConnection.addEventListener(EngineConnectionEvents.NewTrack, (({
|
||||
detail: { mediaStream },
|
||||
}: CustomEvent) => {
|
||||
})
|
||||
},
|
||||
onNewTrack: ({ mediaStream }) => {
|
||||
console.log('received track', mediaStream)
|
||||
|
||||
mediaStream.getVideoTracks()[0].addEventListener('mute', () => {
|
||||
@ -1044,7 +1011,8 @@ export class EngineCommandManager extends EventTarget {
|
||||
})
|
||||
|
||||
setMediaStream(mediaStream)
|
||||
}) as EventListener)
|
||||
},
|
||||
})
|
||||
|
||||
this.engineConnection?.connect()
|
||||
}
|
||||
@ -1234,6 +1202,9 @@ export class EngineCommandManager extends EventTarget {
|
||||
) {
|
||||
delete this.unreliableSubscriptions[event][id]
|
||||
}
|
||||
onConnectionStateChange(callback: (state: EngineConnectionState) => void) {
|
||||
this.callbacksEngineStateConnection.push(callback)
|
||||
}
|
||||
endSession() {
|
||||
// TODO: instead of sending a single command with `object_ids: Object.keys(this.artifactMap)`
|
||||
// we need to loop over them each individually because if the engine doesn't recognise a single
|
||||
|
@ -206,9 +206,7 @@ describe('testing addTagForSketchOnFace', () => {
|
||||
},
|
||||
'lineTo'
|
||||
)
|
||||
const expectedCode = genCode(
|
||||
"lineTo({ to: [-1.59, -1.54], tag: 'seg01' }, %)"
|
||||
)
|
||||
const expectedCode = genCode("lineTo([-1.59, -1.54], %, 'seg01')")
|
||||
expect(recast(modifiedAst)).toBe(expectedCode)
|
||||
})
|
||||
})
|
||||
|
@ -53,40 +53,34 @@ export function getCoordsFromPaths(skGroup: SketchGroup, index = 0): Coords2d {
|
||||
|
||||
export function createFirstArg(
|
||||
sketchFn: ToolTip,
|
||||
val: Value | [Value, Value] | [Value, Value, Value],
|
||||
tag?: Value
|
||||
val: Value | [Value, Value] | [Value, Value, Value]
|
||||
): Value {
|
||||
if (!tag) {
|
||||
if (Array.isArray(val)) {
|
||||
return createArrayExpression(val)
|
||||
}
|
||||
return val
|
||||
}
|
||||
if (Array.isArray(val)) {
|
||||
if (['line', 'lineTo'].includes(sketchFn))
|
||||
return createObjectExpression({ to: createArrayExpression(val), tag })
|
||||
if (
|
||||
['angledLine', 'angledLineOfXLength', 'angledLineOfYLength'].includes(
|
||||
sketchFn
|
||||
[
|
||||
'angledLine',
|
||||
'angledLineOfXLength',
|
||||
'angledLineOfYLength',
|
||||
'angledLineToX',
|
||||
'angledLineToY',
|
||||
'line',
|
||||
'lineTo',
|
||||
].includes(sketchFn)
|
||||
)
|
||||
)
|
||||
return createObjectExpression({ angle: val[0], length: val[1], tag })
|
||||
if (['angledLineToX', 'angledLineToY'].includes(sketchFn))
|
||||
return createObjectExpression({ angle: val[0], to: val[1], tag })
|
||||
return createArrayExpression(val)
|
||||
if (['angledLineThatIntersects'].includes(sketchFn) && val[2])
|
||||
return createObjectExpression({
|
||||
angle: val[0],
|
||||
offset: val[1],
|
||||
intersectTag: val[2],
|
||||
tag,
|
||||
})
|
||||
} else {
|
||||
if (['xLine', 'yLine'].includes(sketchFn))
|
||||
return createObjectExpression({ length: val, tag })
|
||||
if (['xLineTo', 'yLineTo'].includes(sketchFn))
|
||||
return createObjectExpression({ to: val, tag })
|
||||
if (['startSketchAt'].includes(sketchFn))
|
||||
return createObjectExpression({ to: val, tag })
|
||||
if (
|
||||
['startSketchAt', 'xLine', 'xLineTo', 'yLine', 'yLineTo'].includes(
|
||||
sketchFn
|
||||
)
|
||||
)
|
||||
return val
|
||||
}
|
||||
throw new Error('all sketch line types should have been covered')
|
||||
}
|
||||
@ -155,7 +149,7 @@ export const lineTo: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('default'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const line: SketchLineHelper = {
|
||||
@ -246,7 +240,7 @@ export const line: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('default'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const xLineTo: SketchLineHelper = {
|
||||
@ -294,7 +288,7 @@ export const xLineTo: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('default'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const yLineTo: SketchLineHelper = {
|
||||
@ -342,7 +336,7 @@ export const yLineTo: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('default'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const xLine: SketchLineHelper = {
|
||||
@ -392,7 +386,7 @@ export const xLine: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('length'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const yLine: SketchLineHelper = {
|
||||
@ -436,7 +430,7 @@ export const yLine: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('length'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const tangentialArcTo: SketchLineHelper = {
|
||||
@ -516,7 +510,7 @@ export const tangentialArcTo: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
// TODO copy-paste from angledLine
|
||||
addTag: addTagWithTo('angleLength'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
export const angledLine: SketchLineHelper = {
|
||||
add: ({
|
||||
@ -582,7 +576,7 @@ export const angledLine: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('angleLength'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const angledLineOfXLength: SketchLineHelper = {
|
||||
@ -655,7 +649,7 @@ export const angledLineOfXLength: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('angleLength'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const angledLineOfYLength: SketchLineHelper = {
|
||||
@ -729,7 +723,7 @@ export const angledLineOfYLength: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('angleLength'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const angledLineToX: SketchLineHelper = {
|
||||
@ -798,7 +792,7 @@ export const angledLineToX: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('angleTo'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const angledLineToY: SketchLineHelper = {
|
||||
@ -868,7 +862,7 @@ export const angledLineToY: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('angleTo'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const angledLineThatIntersects: SketchLineHelper = {
|
||||
@ -957,7 +951,7 @@ export const angledLineThatIntersects: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('angleTo'), // TODO might be wrong
|
||||
addTag: addTag(), // TODO might be wrong
|
||||
}
|
||||
|
||||
export const updateStartProfileAtArgs: SketchLineHelper['updateArgs'] = ({
|
||||
@ -1180,77 +1174,32 @@ function isAngleLiteral(lineArugement: Value): boolean {
|
||||
|
||||
type addTagFn = (a: ModifyAstBase) => { modifiedAst: Program; tag: string }
|
||||
|
||||
function addTagWithTo(
|
||||
argType: 'angleLength' | 'angleTo' | 'default' | 'length'
|
||||
): addTagFn {
|
||||
function addTag(): addTagFn {
|
||||
return ({ node, pathToNode }) => {
|
||||
let tagName = findUniqueName(node, 'seg', 2)
|
||||
const _node = { ...node }
|
||||
const { node: callExpression } = getNodeFromPath<CallExpression>(
|
||||
const { node: primaryCallExp } = getNodeFromPath<CallExpression>(
|
||||
_node,
|
||||
pathToNode
|
||||
)
|
||||
const firstArg = callExpression.arguments?.[0]
|
||||
if (firstArg.type === 'ObjectExpression') {
|
||||
const existingTagName = firstArg.properties?.find(
|
||||
(prop) => prop.key.name === 'tag'
|
||||
)
|
||||
if (!existingTagName) {
|
||||
mutateObjExpProp(
|
||||
callExpression.arguments?.[0],
|
||||
createLiteral(tagName),
|
||||
'tag'
|
||||
pathToNode,
|
||||
'CallExpression'
|
||||
)
|
||||
// Tag is always 3rd expression now, using arg index feels brittle
|
||||
// but we can come up with a better way to identify tag later.
|
||||
const thirdArg = primaryCallExp.arguments?.[2]
|
||||
const tagLiteral =
|
||||
thirdArg || (createLiteral(findUniqueName(_node, 'seg', 2)) as Literal)
|
||||
const isTagExisting = !!thirdArg
|
||||
if (!isTagExisting) {
|
||||
primaryCallExp.arguments[2] = tagLiteral
|
||||
}
|
||||
if ('value' in tagLiteral) {
|
||||
// Now TypeScript knows tagLiteral has a value property
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
tag: String(tagLiteral.value),
|
||||
}
|
||||
} else {
|
||||
tagName = `${(existingTagName.value as Literal).value}`
|
||||
throw new Error('Unable to assign tag without value')
|
||||
}
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
tag: tagName,
|
||||
}
|
||||
}
|
||||
if (firstArg.type === 'ArrayExpression') {
|
||||
const objExp =
|
||||
argType === 'default'
|
||||
? createObjectExpression({
|
||||
to: firstArg,
|
||||
tag: createLiteral(tagName),
|
||||
})
|
||||
: argType === 'angleLength'
|
||||
? createObjectExpression({
|
||||
angle: firstArg.elements[0],
|
||||
length: firstArg.elements[1],
|
||||
tag: createLiteral(tagName),
|
||||
})
|
||||
: createObjectExpression({
|
||||
angle: firstArg.elements[0],
|
||||
to: firstArg.elements[1],
|
||||
tag: createLiteral(tagName),
|
||||
})
|
||||
callExpression.arguments[0] = objExp
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
tag: tagName,
|
||||
}
|
||||
}
|
||||
if (firstArg.type === 'Literal') {
|
||||
const objExp =
|
||||
argType === 'length'
|
||||
? createObjectExpression({
|
||||
length: firstArg,
|
||||
tag: createLiteral(tagName),
|
||||
})
|
||||
: createObjectExpression({
|
||||
to: firstArg,
|
||||
tag: createLiteral(tagName),
|
||||
})
|
||||
callExpression.arguments[0] = objExp
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
tag: tagName,
|
||||
}
|
||||
}
|
||||
throw new Error('lineTo must be called with an object or array')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,29 +54,17 @@ describe('testing swapping out sketch calls with xLine/xLineTo', () => {
|
||||
const bigExampleArr = [
|
||||
`const part001 = startSketchOn('XY')`,
|
||||
` |> startProfileAt([0, 0], %)`,
|
||||
` |> lineTo({ to: [1, 1], tag: 'abc1' }, %)`,
|
||||
` |> line({ to: [-2.04, -0.7], tag: 'abc2' }, %)`,
|
||||
` |> angledLine({`,
|
||||
` angle: 157,`,
|
||||
` length: 1.69,`,
|
||||
` tag: 'abc3'`,
|
||||
` }, %)`,
|
||||
` |> angledLineOfXLength({`,
|
||||
` angle: 217,`,
|
||||
` length: 0.86,`,
|
||||
` tag: 'abc4'`,
|
||||
` }, %)`,
|
||||
` |> angledLineOfYLength({`,
|
||||
` angle: 104,`,
|
||||
` length: 1.58,`,
|
||||
` tag: 'abc5'`,
|
||||
` }, %)`,
|
||||
` |> angledLineToX({ angle: 55, to: -2.89, tag: 'abc6' }, %)`,
|
||||
` |> angledLineToY({ angle: 330, to: 2.53, tag: 'abc7' }, %)`,
|
||||
` |> xLine({ length: 1.47, tag: 'abc8' }, %)`,
|
||||
` |> yLine({ length: 1.57, tag: 'abc9' }, %)`,
|
||||
` |> xLineTo({ to: 1.49, tag: 'abc10' }, %)`,
|
||||
` |> yLineTo({ to: 2.64, tag: 'abc11' }, %)`,
|
||||
` |> lineTo([1, 1], %, 'abc1')`,
|
||||
` |> line([-2.04, -0.7], %, 'abc2')`,
|
||||
` |> angledLine({ angle: 157, length: 1.69 }, %, 'abc3')`,
|
||||
` |> angledLineOfXLength({ angle: 217, length: 0.86 }, %, 'abc4')`,
|
||||
` |> angledLineOfYLength({ angle: 104, length: 1.58 }, %, 'abc5')`,
|
||||
` |> angledLineToX({ angle: 55, to: -2.89 }, %, 'abc6')`,
|
||||
` |> angledLineToY({ angle: 330, to: 2.53 }, %, 'abc7')`,
|
||||
` |> xLine(1.47, %, 'abc8')`,
|
||||
` |> yLine(1.57, %, 'abc9')`,
|
||||
` |> xLineTo(1.49, %, 'abc10')`,
|
||||
` |> yLineTo(2.64, %, 'abc11')`,
|
||||
` |> lineTo([2.55, 3.58], %) // lineTo`,
|
||||
` |> line([0.73, -0.75], %)`,
|
||||
` |> angledLine([63, 1.38], %) // angledLine`,
|
||||
@ -91,8 +79,8 @@ describe('testing swapping out sketch calls with xLine/xLineTo', () => {
|
||||
]
|
||||
const bigExample = bigExampleArr.join('\n')
|
||||
it('line with tag converts to xLine', async () => {
|
||||
const callToSwap = "line({ to: [-2.04, -0.7], tag: 'abc2' }, %)"
|
||||
const expectedLine = "xLine({ length: -2.04, tag: 'abc2' }, %)"
|
||||
const callToSwap = "line([-2.04, -0.7], %, 'abc2')"
|
||||
const expectedLine = "xLine(-2.04, %, 'abc2')"
|
||||
const { newCode, originalRange } = await testingSwapSketchFnCall({
|
||||
inputCode: bigExample,
|
||||
callToSwap,
|
||||
@ -117,10 +105,10 @@ describe('testing swapping out sketch calls with xLine/xLineTo', () => {
|
||||
it('lineTo with tag converts to xLineTo', async () => {
|
||||
const { newCode, originalRange } = await testingSwapSketchFnCall({
|
||||
inputCode: bigExample,
|
||||
callToSwap: "lineTo({ to: [1, 1], tag: 'abc1' }, %)",
|
||||
callToSwap: "lineTo([1, 1], %, 'abc1')",
|
||||
constraintType: 'horizontal',
|
||||
})
|
||||
const expectedLine = "xLineTo({ to: 1, tag: 'abc1' }, %)"
|
||||
const expectedLine = "xLineTo(1, %, 'abc1')"
|
||||
expect(newCode).toContain(expectedLine)
|
||||
// new line should start at the same place as the old line
|
||||
expect(originalRange[0]).toBe(newCode.indexOf(expectedLine))
|
||||
@ -139,16 +127,11 @@ describe('testing swapping out sketch calls with xLine/xLineTo', () => {
|
||||
it('angledLine with tag converts to xLine', async () => {
|
||||
const { newCode, originalRange } = await testingSwapSketchFnCall({
|
||||
inputCode: bigExample,
|
||||
callToSwap: [
|
||||
`angledLine({`,
|
||||
` angle: 157,`,
|
||||
` length: 1.69,`,
|
||||
` tag: 'abc3'`,
|
||||
` }, %)`,
|
||||
].join('\n'),
|
||||
callToSwap: "angledLine({ angle: 157, length: 1.69 }, %, 'abc3')",
|
||||
constraintType: 'horizontal',
|
||||
})
|
||||
const expectedLine = "xLine({ length: -1.56, tag: 'abc3' }, %)"
|
||||
const expectedLine = "xLine(-1.56, %, 'abc3')"
|
||||
console.log(newCode)
|
||||
expect(newCode).toContain(expectedLine)
|
||||
// new line should start at the same place as the old line
|
||||
expect(originalRange[0]).toBe(newCode.indexOf(expectedLine))
|
||||
@ -167,16 +150,11 @@ describe('testing swapping out sketch calls with xLine/xLineTo', () => {
|
||||
it('angledLineOfXLength with tag converts to xLine', async () => {
|
||||
const { newCode, originalRange } = await testingSwapSketchFnCall({
|
||||
inputCode: bigExample,
|
||||
callToSwap: [
|
||||
`angledLineOfXLength({`,
|
||||
` angle: 217,`,
|
||||
` length: 0.86,`,
|
||||
` tag: 'abc4'`,
|
||||
` }, %)`,
|
||||
].join('\n'),
|
||||
callToSwap:
|
||||
"angledLineOfXLength({ angle: 217, length: 0.86 }, %, 'abc4')",
|
||||
constraintType: 'horizontal',
|
||||
})
|
||||
const expectedLine = "xLine({ length: -0.86, tag: 'abc4' }, %)"
|
||||
const expectedLine = "xLine(-0.86, %, 'abc4')"
|
||||
// hmm "-0.86" is correct since the angle is 104, but need to make sure this is compatible `-myVar`
|
||||
expect(newCode).toContain(expectedLine)
|
||||
// new line should start at the same place as the old line
|
||||
@ -196,16 +174,11 @@ describe('testing swapping out sketch calls with xLine/xLineTo', () => {
|
||||
it('angledLineOfYLength with tag converts to yLine', async () => {
|
||||
const { newCode, originalRange } = await testingSwapSketchFnCall({
|
||||
inputCode: bigExample,
|
||||
callToSwap: [
|
||||
`angledLineOfYLength({`,
|
||||
` angle: 104,`,
|
||||
` length: 1.58,`,
|
||||
` tag: 'abc5'`,
|
||||
` }, %)`,
|
||||
].join('\n'),
|
||||
callToSwap:
|
||||
"angledLineOfYLength({ angle: 104, length: 1.58 }, %, 'abc5')",
|
||||
constraintType: 'vertical',
|
||||
})
|
||||
const expectedLine = "yLine({ length: 1.58, tag: 'abc5' }, %)"
|
||||
const expectedLine = "yLine(1.58, %, 'abc5')"
|
||||
expect(newCode).toContain(expectedLine)
|
||||
// new line should start at the same place as the old line
|
||||
expect(originalRange[0]).toBe(newCode.indexOf(expectedLine))
|
||||
@ -224,10 +197,10 @@ describe('testing swapping out sketch calls with xLine/xLineTo', () => {
|
||||
it('angledLineToX with tag converts to xLineTo', async () => {
|
||||
const { newCode, originalRange } = await testingSwapSketchFnCall({
|
||||
inputCode: bigExample,
|
||||
callToSwap: "angledLineToX({ angle: 55, to: -2.89, tag: 'abc6' }, %)",
|
||||
callToSwap: "angledLineToX({ angle: 55, to: -2.89 }, %, 'abc6')",
|
||||
constraintType: 'horizontal',
|
||||
})
|
||||
const expectedLine = "xLineTo({ to: -2.89, tag: 'abc6' }, %)"
|
||||
const expectedLine = "xLineTo(-2.89, %, 'abc6')"
|
||||
expect(newCode).toContain(expectedLine)
|
||||
// new line should start at the same place as the old line
|
||||
expect(originalRange[0]).toBe(newCode.indexOf(expectedLine))
|
||||
@ -246,10 +219,10 @@ describe('testing swapping out sketch calls with xLine/xLineTo', () => {
|
||||
it('angledLineToY with tag converts to yLineTo', async () => {
|
||||
const { newCode, originalRange } = await testingSwapSketchFnCall({
|
||||
inputCode: bigExample,
|
||||
callToSwap: "angledLineToY({ angle: 330, to: 2.53, tag: 'abc7' }, %)",
|
||||
callToSwap: "angledLineToY({ angle: 330, to: 2.53 }, %, 'abc7')",
|
||||
constraintType: 'vertical',
|
||||
})
|
||||
const expectedLine = "yLineTo({ to: 2.53, tag: 'abc7' }, %)"
|
||||
const expectedLine = "yLineTo(2.53, %, 'abc7')"
|
||||
expect(newCode).toContain(expectedLine)
|
||||
// new line should start at the same place as the old line
|
||||
expect(originalRange[0]).toBe(newCode.indexOf(expectedLine))
|
||||
|
@ -131,7 +131,7 @@ const myAng = 40
|
||||
const myAng2 = 134
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [1, 3.82], tag: 'seg01' }, %) // ln-should-get-tag
|
||||
|> line([1, 3.82], %, 'seg01') // ln-should-get-tag
|
||||
|> angledLineToX([
|
||||
-angleToMatchLengthX('seg01', myVar, %),
|
||||
myVar
|
||||
@ -485,8 +485,7 @@ const part001 = startSketchOn('XY')
|
||||
|> angledLine({
|
||||
angle: halfArmAngle,
|
||||
length: 2.45,
|
||||
tag: 'seg01bing'
|
||||
}, %) // partial
|
||||
}, %, 'seg01bing') // partial
|
||||
|> xLine(4.4, %) // partial
|
||||
|> yLine(-1, %) // partial
|
||||
|> xLine(-4.2 + 0, %) // full
|
||||
|
@ -60,11 +60,12 @@ function createCallWrapper(
|
||||
tag?: Value,
|
||||
valueUsedInTransform?: number
|
||||
): ReturnType<TransformCallback> {
|
||||
const args = [createFirstArg(a, val), createPipeSubstitution()]
|
||||
if (tag) {
|
||||
args.push(tag)
|
||||
}
|
||||
return {
|
||||
callExp: createCallExpression(a, [
|
||||
createFirstArg(a, val, tag),
|
||||
createPipeSubstitution(),
|
||||
]),
|
||||
callExp: createCallExpression(a, args),
|
||||
valueUsedInTransform,
|
||||
}
|
||||
}
|
||||
@ -89,14 +90,15 @@ function intersectCallWrapper({
|
||||
offset: offsetVal,
|
||||
intersectTag,
|
||||
}
|
||||
if (tag) {
|
||||
firstArg['tag'] = tag
|
||||
}
|
||||
return {
|
||||
callExp: createCallExpression(fnName, [
|
||||
const args: Value[] = [
|
||||
createObjectExpression(firstArg),
|
||||
createPipeSubstitution(),
|
||||
]),
|
||||
]
|
||||
if (tag) {
|
||||
args.push(tag)
|
||||
}
|
||||
return {
|
||||
callExp: createCallExpression(fnName, args),
|
||||
valueUsedInTransform,
|
||||
}
|
||||
}
|
||||
@ -1419,7 +1421,8 @@ export function transformAstSketchLines({
|
||||
const callExp = getNode<CallExpression>('CallExpression')?.node
|
||||
const varDec = getNode<VariableDeclarator>('VariableDeclarator').node
|
||||
|
||||
const { val, tag: callBackTag } = getFirstArg(callExp)
|
||||
const { val } = getFirstArg(callExp)
|
||||
const callBackTag = callExp.arguments[2]
|
||||
const _referencedSegmentNameVal =
|
||||
callExp.arguments[0]?.type === 'ObjectExpression' &&
|
||||
callExp.arguments[0].properties?.find(
|
||||
|
@ -7,14 +7,13 @@ describe('testing angledLineThatIntersects', () => {
|
||||
it('angledLineThatIntersects should intersect with another line', async () => {
|
||||
const code = (offset: string) => `const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo({to:[2, 2], tag: "yo"}, %)
|
||||
|> lineTo([2, 2], %, "yo")
|
||||
|> lineTo([3, 1], %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 180,
|
||||
intersectTag: 'yo',
|
||||
offset: ${offset},
|
||||
tag: "yo2"
|
||||
}, %)
|
||||
}, %, "yo2")
|
||||
const intersect = segEndX('yo2', part001)`
|
||||
const { root } = await enginelessExecutor(parse(code('-1')))
|
||||
expect(root.intersect.value).toBe(1 + Math.sqrt(2))
|
||||
|
@ -1,29 +1,38 @@
|
||||
export const bracket = `const sigmaAllow = 15000 // psi
|
||||
const width = 11 // inch
|
||||
const p = 150 // Force on shelf - lbs
|
||||
const distance = 12 // inches
|
||||
const FOS = 2
|
||||
const thickness = sqrt(distance * p * FOS * 6 / ( sigmaAllow * width ))
|
||||
const filletR = thickness * 2
|
||||
const shelfMountL = 9
|
||||
const wallMountL = 8
|
||||
export const bracket = `// Shelf Bracket
|
||||
// This is a shelf bracket made out of 6061-T6 aluminum sheet metal. The required thickness is calculated based on a point load of 300 lbs applied to the end of the shelf. There are two brackets holding up the shelf, so the moment experienced is divided by 2. The shelf is 1 foot long from the wall.
|
||||
|
||||
const sigmaAllow = 35000 // psi
|
||||
const width = 6 // inch
|
||||
const p = 300 // Force on shelf - lbs
|
||||
const distance = 12 // inches
|
||||
const M = 12 * 300 / 2 // Moment experienced at fixed end of bracket
|
||||
const FOS = 2 // Factor of safety of 2
|
||||
const shelfMountL = 8 // The length of the bracket holding up the shelf is 6 inches
|
||||
const wallMountL = 8 // the length of the bracket
|
||||
|
||||
|
||||
// Calculate the thickness off the allowable bending stress and factor of safety
|
||||
const thickness = sqrt(6 * M * FOS / (width * sigmaAllow))
|
||||
|
||||
// 0.25 inch fillet radius
|
||||
const filletR = 0.25
|
||||
|
||||
// Sketch the bracket and extrude with fillets
|
||||
const bracket = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, wallMountL], %)
|
||||
|> tangentialArc({
|
||||
radius: filletR,
|
||||
offset: 90
|
||||
}, %)
|
||||
|> line([0, wallMountL], %, 'outerEdge')
|
||||
|> line([-shelfMountL, 0], %)
|
||||
|> line([0, -thickness], %)
|
||||
|> line([shelfMountL, 0], %)
|
||||
|> tangentialArc({
|
||||
radius: filletR - thickness,
|
||||
offset: -90
|
||||
}, %)
|
||||
|> line([0, -wallMountL], %)
|
||||
|> line([shelfMountL - thickness, 0], %, 'innerEdge')
|
||||
|> line([0, -wallMountL + thickness], %)
|
||||
|> close(%)
|
||||
|> extrude(width, %)
|
||||
|
||||
|> fillet({
|
||||
radius: filletR,
|
||||
tags: [getNextAdjacentEdge('innerEdge', %)]
|
||||
}, %)
|
||||
|> fillet({
|
||||
radius: filletR + thickness,
|
||||
tags: [getNextAdjacentEdge('outerEdge', %)]
|
||||
}, %)
|
||||
`
|
||||
|
@ -61,7 +61,7 @@ export default function ParametricModeling() {
|
||||
<p className="my-4">
|
||||
We are able to easily calculate the thickness of the material based
|
||||
on the width of the bracket to meet a set safety factor on{' '}
|
||||
<em className="text-energy-60 dark:text-energy-20">line 6</em>.
|
||||
<em className="text-energy-60 dark:text-energy-20">line 14</em>.
|
||||
</p>
|
||||
</section>
|
||||
<OnboardingButtons
|
||||
|
24
src/wasm-lib/Cargo.lock
generated
24
src/wasm-lib/Cargo.lock
generated
@ -1471,7 +1471,9 @@ dependencies = [
|
||||
name = "grackle"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"kcl-lib",
|
||||
"kcl-macros",
|
||||
"kittycad",
|
||||
"kittycad-execution-plan",
|
||||
"kittycad-execution-plan-macros",
|
||||
@ -1482,6 +1484,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"twenty-twenty",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
@ -2007,7 +2010,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#4dfeb5c9ce2cc3fb853dd14cf948a922f3724ef4"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"insta",
|
||||
@ -2027,7 +2030,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan-macros"
|
||||
version = "0.1.9"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#4dfeb5c9ce2cc3fb853dd14cf948a922f3724ef4"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2037,7 +2040,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan-traits"
|
||||
version = "0.1.13"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#4dfeb5c9ce2cc3fb853dd14cf948a922f3724ef4"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"thiserror",
|
||||
@ -2046,8 +2049,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-modeling-cmds"
|
||||
version = "0.1.30"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#4dfeb5c9ce2cc3fb853dd14cf948a922f3724ef4"
|
||||
version = "0.1.32"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -2075,7 +2078,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kittycad-modeling-cmds-macros"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#4dfeb5c9ce2cc3fb853dd14cf948a922f3724ef4"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2085,11 +2088,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kittycad-modeling-session"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#4dfeb5c9ce2cc3fb853dd14cf948a922f3724ef4"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"kittycad",
|
||||
"kittycad-modeling-cmds",
|
||||
"lsystem",
|
||||
"reqwest",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
@ -2187,6 +2191,12 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lsystem"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23c47210f2a9f5ae2073e7b847026e3233bcb012aa6845201c69c26481762a81"
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.3"
|
||||
|
@ -6,7 +6,9 @@ description = "A new executor for KCL which compiles to Execution Plans"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
image = { version = "0.24.7", default-features = false, features = ["png"] }
|
||||
kcl-lib = { path = "../kcl" }
|
||||
kcl-macros = { path = "../kcl-macros/" }
|
||||
kittycad = { workspace = true }
|
||||
kittycad-execution-plan = { workspace = true }
|
||||
kittycad-execution-plan-traits = { workspace = true }
|
||||
@ -15,6 +17,7 @@ kittycad-modeling-cmds = { workspace = true }
|
||||
kittycad-modeling-session = { workspace = true }
|
||||
thiserror = "1.0.57"
|
||||
tokio = { version = "1.36.0", features = ["macros", "rt"] }
|
||||
twenty-twenty = "0.7.0"
|
||||
uuid = "1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
|
BIN
src/wasm-lib/grackle/fixtures/cube_lineTo.png
Normal file
BIN
src/wasm-lib/grackle/fixtures/cube_lineTo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 80 KiB |
BIN
src/wasm-lib/grackle/fixtures/cube_xyLine.png
Normal file
BIN
src/wasm-lib/grackle/fixtures/cube_xyLine.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 81 KiB |
@ -2,13 +2,16 @@ use std::collections::HashMap;
|
||||
|
||||
use kcl_lib::ast::types::{LiteralIdentifier, LiteralValue};
|
||||
|
||||
use kittycad_execution_plan::constants;
|
||||
use kittycad_execution_plan_traits::Primitive;
|
||||
|
||||
use super::{native_functions, Address};
|
||||
use crate::{CompileError, KclFunction};
|
||||
|
||||
/// KCL values which can be written to KCEP memory.
|
||||
/// This is recursive. For example, the bound value might be an array, which itself contains bound values.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub enum EpBinding {
|
||||
/// A KCL value which gets stored in a particular address in KCEP memory.
|
||||
Single(Address),
|
||||
@ -23,6 +26,8 @@ pub enum EpBinding {
|
||||
properties: HashMap<String, EpBinding>,
|
||||
},
|
||||
/// Not associated with a KCEP address.
|
||||
Constant(Primitive),
|
||||
/// Not associated with a KCEP address.
|
||||
Function(KclFunction),
|
||||
/// SketchGroups have their own storage.
|
||||
SketchGroup { index: usize },
|
||||
@ -52,11 +57,13 @@ impl EpBinding {
|
||||
EpBinding::SketchGroup { .. } => Err(CompileError::CannotIndex),
|
||||
EpBinding::Single(_) => Err(CompileError::CannotIndex),
|
||||
EpBinding::Function(_) => Err(CompileError::CannotIndex),
|
||||
EpBinding::Constant(_) => Err(CompileError::CannotIndex),
|
||||
},
|
||||
// Objects can be indexed by string properties.
|
||||
LiteralValue::String(property) => match self {
|
||||
EpBinding::Single(_) => Err(CompileError::NoProperties),
|
||||
EpBinding::Function(_) => Err(CompileError::NoProperties),
|
||||
EpBinding::Constant(_) => Err(CompileError::CannotIndex),
|
||||
EpBinding::SketchGroup { .. } => Err(CompileError::NoProperties),
|
||||
EpBinding::Sequence { .. } => Err(CompileError::ArrayDoesNotHaveProperties),
|
||||
EpBinding::Map {
|
||||
@ -103,8 +110,58 @@ impl BindingScope {
|
||||
// TODO: Actually put the stdlib prelude in here,
|
||||
// things like `startSketchAt` and `line`.
|
||||
ep_bindings: HashMap::from([
|
||||
("E".into(), EpBinding::Constant(constants::E)),
|
||||
("PI".into(), EpBinding::Constant(constants::PI)),
|
||||
("id".into(), EpBinding::from(KclFunction::Id(native_functions::Id))),
|
||||
("abs".into(), EpBinding::from(KclFunction::Abs(native_functions::Abs))),
|
||||
(
|
||||
"acos".into(),
|
||||
EpBinding::from(KclFunction::Acos(native_functions::Acos)),
|
||||
),
|
||||
(
|
||||
"asin".into(),
|
||||
EpBinding::from(KclFunction::Asin(native_functions::Asin)),
|
||||
),
|
||||
(
|
||||
"atan".into(),
|
||||
EpBinding::from(KclFunction::Atan(native_functions::Atan)),
|
||||
),
|
||||
(
|
||||
"ceil".into(),
|
||||
EpBinding::from(KclFunction::Ceil(native_functions::Ceil)),
|
||||
),
|
||||
("cos".into(), EpBinding::from(KclFunction::Cos(native_functions::Cos))),
|
||||
(
|
||||
"floor".into(),
|
||||
EpBinding::from(KclFunction::Floor(native_functions::Floor)),
|
||||
),
|
||||
("ln".into(), EpBinding::from(KclFunction::Ln(native_functions::Ln))),
|
||||
(
|
||||
"log10".into(),
|
||||
EpBinding::from(KclFunction::Log10(native_functions::Log10)),
|
||||
),
|
||||
(
|
||||
"log2".into(),
|
||||
EpBinding::from(KclFunction::Log2(native_functions::Log2)),
|
||||
),
|
||||
("sin".into(), EpBinding::from(KclFunction::Sin(native_functions::Sin))),
|
||||
(
|
||||
"sqrt".into(),
|
||||
EpBinding::from(KclFunction::Sqrt(native_functions::Sqrt)),
|
||||
),
|
||||
("tan".into(), EpBinding::from(KclFunction::Tan(native_functions::Tan))),
|
||||
(
|
||||
"toDegrees".into(),
|
||||
EpBinding::from(KclFunction::ToDegrees(native_functions::ToDegrees)),
|
||||
),
|
||||
(
|
||||
"toRadians".into(),
|
||||
EpBinding::from(KclFunction::ToRadians(native_functions::ToRadians)),
|
||||
),
|
||||
("add".into(), EpBinding::from(KclFunction::Add(native_functions::Add))),
|
||||
("log".into(), EpBinding::from(KclFunction::Log(native_functions::Log))),
|
||||
("max".into(), EpBinding::from(KclFunction::Max(native_functions::Max))),
|
||||
("min".into(), EpBinding::from(KclFunction::Min(native_functions::Min))),
|
||||
(
|
||||
"startSketchAt".into(),
|
||||
EpBinding::from(KclFunction::StartSketchAt(native_functions::sketch::StartSketchAt)),
|
||||
@ -113,6 +170,26 @@ impl BindingScope {
|
||||
"lineTo".into(),
|
||||
EpBinding::from(KclFunction::LineTo(native_functions::sketch::LineTo)),
|
||||
),
|
||||
(
|
||||
"line".into(),
|
||||
EpBinding::from(KclFunction::Line(native_functions::sketch::Line)),
|
||||
),
|
||||
(
|
||||
"xLineTo".into(),
|
||||
EpBinding::from(KclFunction::XLineTo(native_functions::sketch::XLineTo)),
|
||||
),
|
||||
(
|
||||
"xLine".into(),
|
||||
EpBinding::from(KclFunction::XLine(native_functions::sketch::XLine)),
|
||||
),
|
||||
(
|
||||
"yLineTo".into(),
|
||||
EpBinding::from(KclFunction::YLineTo(native_functions::sketch::YLineTo)),
|
||||
),
|
||||
(
|
||||
"yLine".into(),
|
||||
EpBinding::from(KclFunction::YLine(native_functions::sketch::YLine)),
|
||||
),
|
||||
(
|
||||
"extrude".into(),
|
||||
EpBinding::from(KclFunction::Extrude(native_functions::sketch::Extrude)),
|
||||
|
@ -76,7 +76,7 @@ impl From<ExecutionFailed> for Error {
|
||||
) -> Self {
|
||||
Self::Execution {
|
||||
error,
|
||||
instruction,
|
||||
instruction: instruction.expect("no instruction"),
|
||||
instruction_index,
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ use kcl_lib::{
|
||||
ast,
|
||||
ast::types::{BodyItem, FunctionExpressionParts, KclNone, LiteralValue, Program},
|
||||
};
|
||||
extern crate alloc;
|
||||
use kcl_macros::parse_file;
|
||||
use kcl_value_group::into_single_value;
|
||||
use kittycad_execution_plan::{self as ep, Destination, Instruction};
|
||||
use kittycad_execution_plan_traits as ept;
|
||||
@ -24,9 +26,11 @@ use self::{
|
||||
};
|
||||
|
||||
/// Execute a KCL program by compiling into an execution plan, then running that.
|
||||
pub async fn execute(ast: Program, session: &mut Option<Session>) -> Result<ep::Memory, Error> {
|
||||
/// Include a `prelude.kcl` inlined as a `Program` struct thanks to a proc_macro `parse!`.
|
||||
/// This makes additional functions available to the user.
|
||||
pub async fn execute(ast_user: Program, session: &mut Option<Session>) -> Result<ep::Memory, Error> {
|
||||
let mut planner = Planner::new();
|
||||
let (plan, _retval) = planner.build_plan(ast)?;
|
||||
let (plan, _retval) = planner.build_plan(ast_user)?;
|
||||
let mut mem = ep::Memory::default();
|
||||
ep::execute(&mut mem, plan, session).await?;
|
||||
Ok(mem)
|
||||
@ -54,7 +58,9 @@ impl Planner {
|
||||
|
||||
/// If successful, return the KCEP instructions for executing the given program.
|
||||
/// If the program is a function with a return, then it also returns the KCL function's return value.
|
||||
fn build_plan(&mut self, program: Program) -> Result<(Vec<Instruction>, Option<EpBinding>), CompileError> {
|
||||
fn build_plan(&mut self, ast_user: Program) -> Result<(Vec<Instruction>, Option<EpBinding>), CompileError> {
|
||||
let ast_prelude = parse_file!("./prelude.kcl");
|
||||
let program = ast_prelude.merge(ast_user);
|
||||
program
|
||||
.body
|
||||
.into_iter()
|
||||
@ -259,9 +265,32 @@ impl Planner {
|
||||
binding,
|
||||
} = match callee {
|
||||
KclFunction::Id(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Abs(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Acos(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Asin(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Atan(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Ceil(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Cos(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Floor(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Ln(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Log10(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Log2(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Sin(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Sqrt(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Tan(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::ToDegrees(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::ToRadians(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Log(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Max(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Min(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::StartSketchAt(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Extrude(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::LineTo(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Line(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::XLineTo(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::XLine(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::YLineTo(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::YLine(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Add(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Close(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::UserDefined(f) => {
|
||||
@ -629,9 +658,32 @@ impl Eq for UserDefinedFunction {}
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
enum KclFunction {
|
||||
Id(native_functions::Id),
|
||||
Abs(native_functions::Abs),
|
||||
Acos(native_functions::Acos),
|
||||
Asin(native_functions::Asin),
|
||||
Atan(native_functions::Atan),
|
||||
Ceil(native_functions::Ceil),
|
||||
Cos(native_functions::Cos),
|
||||
Floor(native_functions::Floor),
|
||||
Ln(native_functions::Ln),
|
||||
Log10(native_functions::Log10),
|
||||
Log2(native_functions::Log2),
|
||||
Sin(native_functions::Sin),
|
||||
Sqrt(native_functions::Sqrt),
|
||||
Tan(native_functions::Tan),
|
||||
ToDegrees(native_functions::ToDegrees),
|
||||
ToRadians(native_functions::ToRadians),
|
||||
StartSketchAt(native_functions::sketch::StartSketchAt),
|
||||
LineTo(native_functions::sketch::LineTo),
|
||||
Line(native_functions::sketch::Line),
|
||||
XLineTo(native_functions::sketch::XLineTo),
|
||||
XLine(native_functions::sketch::XLine),
|
||||
YLineTo(native_functions::sketch::YLineTo),
|
||||
YLine(native_functions::sketch::YLine),
|
||||
Add(native_functions::Add),
|
||||
Log(native_functions::Log),
|
||||
Max(native_functions::Max),
|
||||
Min(native_functions::Min),
|
||||
UserDefined(UserDefinedFunction),
|
||||
Extrude(native_functions::sketch::Extrude),
|
||||
Close(native_functions::sketch::Close),
|
||||
|
@ -2,18 +2,15 @@
|
||||
//! This includes some of the stdlib, e.g. `startSketchAt`.
|
||||
//! But some other stdlib functions will be written in KCL.
|
||||
|
||||
use kittycad_execution_plan::{BinaryArithmetic, Destination, Instruction};
|
||||
use kittycad_execution_plan::{
|
||||
BinaryArithmetic, BinaryOperation, Destination, Instruction, Operand, UnaryArithmetic, UnaryOperation,
|
||||
};
|
||||
use kittycad_execution_plan_traits::Address;
|
||||
|
||||
use crate::{CompileError, EpBinding, EvalPlan};
|
||||
|
||||
pub mod sketch;
|
||||
|
||||
/// The identity function. Always returns its first input.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct Id;
|
||||
|
||||
pub trait Callable {
|
||||
fn call(&self, ctx: &mut Context<'_>, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError>;
|
||||
}
|
||||
@ -32,6 +29,65 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Unary operator macro to quickly create new bindings.
|
||||
macro_rules! define_unary {
|
||||
() => {};
|
||||
($fn_name:ident$( $rest:ident)*) => {
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct $fn_name;
|
||||
|
||||
impl Callable for $fn_name {
|
||||
fn call(&self, ctx: &mut Context<'_>, mut args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||
if args.len() > 1 {
|
||||
return Err(CompileError::TooManyArgs {
|
||||
fn_name: "$fn_name".into(),
|
||||
maximum: 1,
|
||||
actual: args.len(),
|
||||
});
|
||||
}
|
||||
|
||||
let not_enough_args = CompileError::NotEnoughArgs {
|
||||
fn_name: "$fn_name".into(),
|
||||
required: 1,
|
||||
actual: args.len(),
|
||||
};
|
||||
|
||||
let EpBinding::Single(arg0) = args.pop().ok_or(not_enough_args.clone())? else {
|
||||
return Err(CompileError::InvalidOperand("A single value binding is expected"));
|
||||
};
|
||||
|
||||
let destination = ctx.next_address.offset_by(1);
|
||||
let instructions = vec![
|
||||
Instruction::UnaryArithmetic {
|
||||
arithmetic: UnaryArithmetic {
|
||||
operation: UnaryOperation::$fn_name,
|
||||
operand: Operand::Reference(arg0)
|
||||
},
|
||||
destination: Destination::Address(destination)
|
||||
}
|
||||
];
|
||||
|
||||
Ok(EvalPlan {
|
||||
instructions,
|
||||
binding: EpBinding::Single(destination),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
define_unary!($($rest)*);
|
||||
};
|
||||
}
|
||||
|
||||
define_unary!(Abs Acos Asin Atan Ceil Cos Floor Ln Log10 Log2 Sin Sqrt Tan ToDegrees ToRadians);
|
||||
|
||||
/// The identity function. Always returns its first input.
|
||||
/// Implemented purely on the KCL side so it doesn't need to be in the
|
||||
/// define_unary! macro above.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct Id;
|
||||
|
||||
impl Callable for Id {
|
||||
fn call(&self, _: &mut Context<'_>, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||
if args.len() > 1 {
|
||||
@ -56,27 +112,30 @@ impl Callable for Id {
|
||||
}
|
||||
}
|
||||
|
||||
/// A test function that adds two numbers.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct Add;
|
||||
/// Binary operator macro to quickly create new bindings.
|
||||
macro_rules! define_binary {
|
||||
() => {};
|
||||
($fn_name:ident$( $rest:ident)*) => {
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct $fn_name;
|
||||
|
||||
impl Callable for Add {
|
||||
impl Callable for $fn_name {
|
||||
fn call(&self, ctx: &mut Context<'_>, mut args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||
let len = args.len();
|
||||
if len > 2 {
|
||||
return Err(CompileError::TooManyArgs {
|
||||
fn_name: "add".into(),
|
||||
fn_name: "$fn_name".into(),
|
||||
maximum: 2,
|
||||
actual: len,
|
||||
});
|
||||
}
|
||||
let not_enough_args = CompileError::NotEnoughArgs {
|
||||
fn_name: "add".into(),
|
||||
fn_name: "$fn_name".into(),
|
||||
required: 2,
|
||||
actual: len,
|
||||
};
|
||||
const ERR: &str = "cannot use composite values (e.g. array) as arguments to Add";
|
||||
const ERR: &str = "cannot use composite values (e.g. array) as arguments to $fn_name";
|
||||
let EpBinding::Single(arg1) = args.pop().ok_or(not_enough_args.clone())? else {
|
||||
return Err(CompileError::InvalidOperand(ERR));
|
||||
};
|
||||
@ -87,13 +146,19 @@ impl Callable for Add {
|
||||
Ok(EvalPlan {
|
||||
instructions: vec![Instruction::BinaryArithmetic {
|
||||
arithmetic: BinaryArithmetic {
|
||||
operation: kittycad_execution_plan::BinaryOperation::Add,
|
||||
operand0: kittycad_execution_plan::Operand::Reference(arg0),
|
||||
operand1: kittycad_execution_plan::Operand::Reference(arg1),
|
||||
operation: BinaryOperation::$fn_name,
|
||||
operand0: Operand::Reference(arg0),
|
||||
operand1: Operand::Reference(arg1),
|
||||
},
|
||||
destination: Destination::Address(destination),
|
||||
}],
|
||||
binding: EpBinding::Single(destination),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
define_binary!($($rest)*);
|
||||
};
|
||||
}
|
||||
|
||||
define_binary!(Add Log Max Min);
|
||||
|
@ -3,4 +3,4 @@
|
||||
pub mod helpers;
|
||||
pub mod stdlib_functions;
|
||||
|
||||
pub use stdlib_functions::{Close, Extrude, LineTo, StartSketchAt};
|
||||
pub use stdlib_functions::{Close, Extrude, Line, LineTo, StartSketchAt, XLine, XLineTo, YLine, YLineTo};
|
||||
|
@ -67,6 +67,12 @@ pub fn sg_binding(
|
||||
actual: "function".to_owned(),
|
||||
arg_number,
|
||||
}),
|
||||
EpBinding::Constant(_) => Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: "constant".to_owned(),
|
||||
arg_number,
|
||||
}),
|
||||
}
|
||||
}
|
||||
pub fn single_binding(
|
||||
@ -101,6 +107,12 @@ pub fn single_binding(
|
||||
actual: "function".to_owned(),
|
||||
arg_number,
|
||||
}),
|
||||
EpBinding::Constant(_) => Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: "constant".to_owned(),
|
||||
arg_number,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,10 +148,16 @@ pub fn sequence_binding(
|
||||
actual: "function".to_owned(),
|
||||
arg_number,
|
||||
}),
|
||||
EpBinding::Constant(_) => Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: "constant".to_owned(),
|
||||
arg_number,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract a 2D point from an argument to a Cabble.
|
||||
/// Extract a 2D point from an argument to a KCL Function.
|
||||
pub fn arg_point2d(
|
||||
arg: EpBinding,
|
||||
fn_name: &'static str,
|
||||
@ -148,7 +166,7 @@ pub fn arg_point2d(
|
||||
arg_number: usize,
|
||||
) -> Result<Address, CompileError> {
|
||||
let expected = "2D point (array with length 2)";
|
||||
let elements = sequence_binding(arg, "startSketchAt", "an array of length 2", arg_number)?;
|
||||
let elements = sequence_binding(arg, fn_name, "an array of length 2", arg_number)?;
|
||||
if elements.len() != 2 {
|
||||
return Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
@ -165,12 +183,12 @@ pub fn arg_point2d(
|
||||
let start_z = start + 2;
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: single_binding(elements[0].clone(), "startSketchAt", "number", arg_number)?,
|
||||
source: single_binding(elements[0].clone(), fn_name, "number", arg_number)?,
|
||||
destination: Destination::Address(start_x),
|
||||
length: 1,
|
||||
},
|
||||
Instruction::Copy {
|
||||
source: single_binding(elements[1].clone(), "startSketchAt", "number", arg_number)?,
|
||||
source: single_binding(elements[1].clone(), fn_name, "number", arg_number)?,
|
||||
destination: Destination::Address(start_y),
|
||||
length: 1,
|
||||
},
|
||||
|
@ -1,7 +1,7 @@
|
||||
use kittycad_execution_plan::{
|
||||
api_request::ApiRequest,
|
||||
sketch_types::{self, Axes, BasePath, Plane, SketchGroup},
|
||||
Destination, Instruction,
|
||||
BinaryArithmetic, BinaryOperation, Destination, Instruction, Operand,
|
||||
};
|
||||
use kittycad_execution_plan_traits::{Address, InMemory, Primitive, Value};
|
||||
use kittycad_modeling_cmds::{
|
||||
@ -13,6 +13,22 @@ use uuid::Uuid;
|
||||
use super::helpers::{arg_point2d, no_arg_api_call, sg_binding, single_binding, stack_api_call};
|
||||
use crate::{binding_scope::EpBinding, error::CompileError, native_functions::Callable, EvalPlan};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum At {
|
||||
RelativeXY,
|
||||
AbsoluteXY,
|
||||
RelativeX,
|
||||
AbsoluteX,
|
||||
RelativeY,
|
||||
AbsoluteY,
|
||||
}
|
||||
|
||||
impl At {
|
||||
pub fn is_relative(&self) -> bool {
|
||||
*self == At::RelativeX || *self == At::RelativeY || *self == At::RelativeXY
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct Close;
|
||||
@ -140,25 +156,124 @@ impl Callable for LineTo {
|
||||
&self,
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
args: Vec<EpBinding>,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
LineBare::call(ctx, "lineTo", args, LineBareOptions { at: At::AbsoluteXY })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct Line;
|
||||
|
||||
impl Callable for Line {
|
||||
fn call(
|
||||
&self,
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
args: Vec<EpBinding>,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
LineBare::call(ctx, "line", args, LineBareOptions { at: At::RelativeXY })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct XLineTo;
|
||||
|
||||
impl Callable for XLineTo {
|
||||
fn call(
|
||||
&self,
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
args: Vec<EpBinding>,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
LineBare::call(ctx, "xLineTo", args, LineBareOptions { at: At::AbsoluteX })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct XLine;
|
||||
|
||||
impl Callable for XLine {
|
||||
fn call(
|
||||
&self,
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
args: Vec<EpBinding>,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
LineBare::call(ctx, "xLine", args, LineBareOptions { at: At::RelativeX })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct YLineTo;
|
||||
|
||||
impl Callable for YLineTo {
|
||||
fn call(
|
||||
&self,
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
args: Vec<EpBinding>,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
LineBare::call(ctx, "yLineTo", args, LineBareOptions { at: At::AbsoluteY })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct YLine;
|
||||
|
||||
impl Callable for YLine {
|
||||
fn call(
|
||||
&self,
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
args: Vec<EpBinding>,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
LineBare::call(ctx, "yLine", args, LineBareOptions { at: At::RelativeY })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
/// Exposes all the possible arguments the `line` modeling command can take.
|
||||
/// Reduces code for the other line functions needed.
|
||||
/// We do not expose this to the developer since it does not align with
|
||||
/// the documentation (there is no "lineBare").
|
||||
pub struct LineBare;
|
||||
|
||||
/// Used to configure the call to handle different line variants.
|
||||
pub struct LineBareOptions {
|
||||
/// Where to start coordinates at, ex: At::RelativeXY.
|
||||
at: At,
|
||||
}
|
||||
|
||||
impl LineBare {
|
||||
fn call(
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
fn_name: &'static str,
|
||||
args: Vec<EpBinding>,
|
||||
opts: LineBareOptions,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
let mut instructions = Vec::new();
|
||||
let fn_name = "lineTo";
|
||||
// Get both required params.
|
||||
|
||||
let required = 2;
|
||||
|
||||
let mut args_iter = args.into_iter();
|
||||
|
||||
let Some(to) = args_iter.next() else {
|
||||
return Err(CompileError::NotEnoughArgs {
|
||||
fn_name: fn_name.into(),
|
||||
required: 2,
|
||||
actual: 0,
|
||||
required,
|
||||
actual: args_iter.count(),
|
||||
});
|
||||
};
|
||||
|
||||
let Some(sketch_group) = args_iter.next() else {
|
||||
return Err(CompileError::NotEnoughArgs {
|
||||
fn_name: fn_name.into(),
|
||||
required: 2,
|
||||
actual: 1,
|
||||
required,
|
||||
actual: args_iter.count(),
|
||||
});
|
||||
};
|
||||
|
||||
let tag = match args_iter.next() {
|
||||
Some(a) => a,
|
||||
None => {
|
||||
@ -171,26 +286,90 @@ impl Callable for LineTo {
|
||||
EpBinding::Single(empty_string_addr)
|
||||
}
|
||||
};
|
||||
|
||||
// Check the type of required params.
|
||||
let to = arg_point2d(to, fn_name, &mut instructions, ctx, 0)?;
|
||||
// We don't check `to` here because it can take on either a
|
||||
// EpBinding::Sequence or EpBinding::Single.
|
||||
|
||||
let sg = sg_binding(sketch_group, fn_name, "sketch group", 1)?;
|
||||
let tag = single_binding(tag, fn_name, "string tag", 2)?;
|
||||
let id = Uuid::new_v4();
|
||||
|
||||
// Start of the path segment (which is a straight line).
|
||||
let length_of_3d_point = Point3d::<f64>::default().into_parts().len();
|
||||
let start_of_line = ctx.next_address.offset_by(1);
|
||||
|
||||
// Reserve space for the line's end, and the `relative: bool` field.
|
||||
ctx.next_address.offset_by(length_of_3d_point + 1);
|
||||
let new_sg_index = ctx.assign_sketch_group();
|
||||
instructions.extend([
|
||||
|
||||
// Copy based on the options.
|
||||
match opts {
|
||||
LineBareOptions { at: At::AbsoluteXY, .. } | LineBareOptions { at: At::RelativeXY, .. } => {
|
||||
// Push the `to` 2D point onto the stack.
|
||||
let EpBinding::Sequence { elements, length_at: _ } = to.clone() else {
|
||||
return Err(CompileError::InvalidOperand("Must pass a list of length 2"));
|
||||
};
|
||||
let &[EpBinding::Single(el0), EpBinding::Single(el1)] = elements.as_slice() else {
|
||||
return Err(CompileError::InvalidOperand("Must pass a sequence here."));
|
||||
};
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: to,
|
||||
length: 2,
|
||||
// X
|
||||
source: el0,
|
||||
length: 1,
|
||||
destination: Destination::StackPush,
|
||||
},
|
||||
// Make it a 3D point.
|
||||
Instruction::StackExtend { data: vec![0.0.into()] },
|
||||
Instruction::Copy {
|
||||
// Y
|
||||
source: el1,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::StackExtend { data: vec![0.0.into()] }, // Z
|
||||
]);
|
||||
}
|
||||
LineBareOptions { at: At::AbsoluteX, .. } | LineBareOptions { at: At::RelativeX, .. } => {
|
||||
let EpBinding::Single(addr) = to else {
|
||||
return Err(CompileError::InvalidOperand("Must pass a single value here."));
|
||||
};
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
// X
|
||||
source: addr,
|
||||
length: 1,
|
||||
destination: Destination::StackPush,
|
||||
},
|
||||
Instruction::StackExtend {
|
||||
data: vec![Primitive::from(0.0)],
|
||||
}, // Y
|
||||
Instruction::StackExtend {
|
||||
data: vec![Primitive::from(0.0)],
|
||||
}, // Z
|
||||
]);
|
||||
}
|
||||
LineBareOptions { at: At::AbsoluteY, .. } | LineBareOptions { at: At::RelativeY, .. } => {
|
||||
let EpBinding::Single(addr) = to else {
|
||||
return Err(CompileError::InvalidOperand("Must pass a single value here."));
|
||||
};
|
||||
instructions.extend([
|
||||
Instruction::StackPush {
|
||||
data: vec![Primitive::from(0.0)],
|
||||
}, // X
|
||||
Instruction::Copy {
|
||||
// Y
|
||||
source: addr,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::StackExtend {
|
||||
data: vec![Primitive::from(0.0)],
|
||||
}, // Z
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
instructions.extend([
|
||||
// Append the new path segment to memory.
|
||||
// First comes its tag.
|
||||
Instruction::SetPrimitive {
|
||||
@ -204,7 +383,7 @@ impl Callable for LineTo {
|
||||
// Then its `relative` field.
|
||||
Instruction::SetPrimitive {
|
||||
address: start_of_line + 1 + length_of_3d_point,
|
||||
value: false.into(),
|
||||
value: opts.at.is_relative().into(),
|
||||
},
|
||||
// Push the path ID onto the stack.
|
||||
Instruction::SketchGroupCopyFrom {
|
||||
@ -231,16 +410,159 @@ impl Callable for LineTo {
|
||||
data: vec![Primitive::from("ToPoint".to_owned())],
|
||||
},
|
||||
// `BasePath::from` point.
|
||||
// Place them in the secondary stack to prepare ToPoint structure.
|
||||
Instruction::SketchGroupGetLastPoint {
|
||||
source: sg,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
|
||||
// Reserve space for the segment last point
|
||||
let to_point_from = ctx.next_address.offset_by(2);
|
||||
|
||||
instructions.extend([
|
||||
// Copy to the primary stack as well to be worked with.
|
||||
Instruction::SketchGroupGetLastPoint {
|
||||
source: sg,
|
||||
destination: Destination::Address(to_point_from),
|
||||
},
|
||||
]);
|
||||
|
||||
// `BasePath::to` point.
|
||||
Instruction::Copy {
|
||||
source: start_of_line + 1,
|
||||
length: 2,
|
||||
|
||||
// The copy here depends on the incoming `to` data.
|
||||
// Sometimes it's a list, sometimes it's single datum.
|
||||
// And the relative/not relative matters. When relative, we need to
|
||||
// copy coords from `from` into the new `to` coord that don't change.
|
||||
// At least everything else can be built up from these "primitives".
|
||||
if let EpBinding::Sequence { elements, length_at: _ } = to.clone() {
|
||||
if let &[EpBinding::Single(el0), EpBinding::Single(el1)] = elements.as_slice() {
|
||||
match opts {
|
||||
// ToPoint { from: { x1, y1 }, to: { x1 + x2, y1 + y2 } }
|
||||
LineBareOptions { at: At::RelativeXY, .. } => {
|
||||
instructions.extend([
|
||||
Instruction::BinaryArithmetic {
|
||||
arithmetic: BinaryArithmetic {
|
||||
operation: BinaryOperation::Add,
|
||||
operand0: Operand::Reference(to_point_from + 0),
|
||||
operand1: Operand::Reference(el0),
|
||||
},
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::BinaryArithmetic {
|
||||
arithmetic: BinaryArithmetic {
|
||||
operation: BinaryOperation::Add,
|
||||
operand0: Operand::Reference(to_point_from + 1),
|
||||
operand1: Operand::Reference(el1),
|
||||
},
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
}
|
||||
// ToPoint { from: { x1, y1 }, to: { x2, y2 } }
|
||||
LineBareOptions { at: At::AbsoluteXY, .. } => {
|
||||
// Otherwise just directly copy the new points.
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: el0,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::Copy {
|
||||
source: el1,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
}
|
||||
_ => {
|
||||
return Err(CompileError::InvalidOperand(
|
||||
"A Sequence with At::...X or At::...Y is not valid here. Must be At::...XY.",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let EpBinding::Single(addr) = to {
|
||||
match opts {
|
||||
// ToPoint { from: { x1, y1 }, to: { x1 + x2, y1 } }
|
||||
LineBareOptions { at: At::RelativeX } => {
|
||||
instructions.extend([
|
||||
Instruction::BinaryArithmetic {
|
||||
arithmetic: BinaryArithmetic {
|
||||
operation: BinaryOperation::Add,
|
||||
operand0: Operand::Reference(to_point_from + 0),
|
||||
operand1: Operand::Reference(addr),
|
||||
},
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::Copy {
|
||||
source: to_point_from + 1,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
}
|
||||
// ToPoint { from: { x1, y1 }, to: { x2, y1 } }
|
||||
LineBareOptions { at: At::AbsoluteX } => {
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: addr,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::Copy {
|
||||
source: to_point_from + 1,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
}
|
||||
// ToPoint { from: { x1, y1 }, to: { x1, y1 + y2 } }
|
||||
LineBareOptions { at: At::RelativeY } => {
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: to_point_from + 0,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::BinaryArithmetic {
|
||||
arithmetic: BinaryArithmetic {
|
||||
operation: BinaryOperation::Add,
|
||||
operand0: Operand::Reference(to_point_from + 1),
|
||||
operand1: Operand::Reference(addr),
|
||||
},
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
}
|
||||
// ToPoint { from: { x1, y1 }, to: { x1, y2 } }
|
||||
LineBareOptions { at: At::AbsoluteY } => {
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: to_point_from + 0,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::Copy {
|
||||
source: addr,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
}
|
||||
_ => {
|
||||
return Err(CompileError::InvalidOperand(
|
||||
"A Single binding with At::...XY is not valid here.",
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(CompileError::InvalidOperand(
|
||||
"Must be a sequence or single value binding.",
|
||||
));
|
||||
}
|
||||
|
||||
instructions.extend([
|
||||
// `BasePath::name` string.
|
||||
Instruction::Copy {
|
||||
source: tag,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::{collections::HashMap, env};
|
||||
|
||||
use ep::{sketch_types, Destination, UnaryArithmetic};
|
||||
use ept::{ListHeader, ObjectHeader};
|
||||
use ep::{constants, sketch_types, Destination, UnaryArithmetic};
|
||||
use ept::{ListHeader, ObjectHeader, Primitive};
|
||||
use kittycad_modeling_cmds::shared::Point2d;
|
||||
use kittycad_modeling_session::SessionBuilder;
|
||||
use pretty_assertions::assert_eq;
|
||||
@ -1048,14 +1048,10 @@ fn store_object_with_array_property() {
|
||||
|
||||
/// Write the program's plan to the KCVM debugger's normal input file.
|
||||
#[allow(unused)]
|
||||
fn kcvm_dbg(kcl_program: &str) {
|
||||
fn kcvm_dbg(kcl_program: &str, path: &str) {
|
||||
let (plan, _scope, _) = must_plan(kcl_program);
|
||||
let plan_json = serde_json::to_string_pretty(&plan).unwrap();
|
||||
std::fs::write(
|
||||
"/Users/adamchalmers/kc-repos/modeling-api/execution-plan-debugger/test_input.json",
|
||||
plan_json,
|
||||
)
|
||||
.unwrap();
|
||||
std::fs::write(path, plan_json).unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@ -1069,8 +1065,6 @@ async fn stdlib_cube_partial() {
|
||||
|> close(%)
|
||||
|> extrude(100.0, %)
|
||||
"#;
|
||||
let (_plan, _scope, last_address) = must_plan(program);
|
||||
assert_eq!(last_address, Address::ZERO + 66);
|
||||
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
||||
.ast()
|
||||
.unwrap();
|
||||
@ -1113,23 +1107,115 @@ async fn stdlib_cube_partial() {
|
||||
},
|
||||
]
|
||||
);
|
||||
// use kittycad_modeling_cmds::{each_cmd, ok_response::OkModelingCmdResponse, ImageFormat};
|
||||
// let out = client
|
||||
// .unwrap()
|
||||
// .run_command(
|
||||
// uuid::Uuid::new_v4().into(),
|
||||
// each_cmd::TakeSnapshot {
|
||||
// format: ImageFormat::Png,
|
||||
// },
|
||||
// )
|
||||
// .await
|
||||
// .unwrap();
|
||||
// let out = match out {
|
||||
// OkModelingCmdResponse::TakeSnapshot(b) => b,
|
||||
// other => panic!("wrong output: {other:?}"),
|
||||
// };
|
||||
// let out: Vec<u8> = out.contents.into();
|
||||
// std::fs::write("image.png", out).unwrap();
|
||||
use kittycad_modeling_cmds::{each_cmd, ok_response::OkModelingCmdResponse, ImageFormat};
|
||||
let out = client
|
||||
.unwrap()
|
||||
.run_command(
|
||||
uuid::Uuid::new_v4().into(),
|
||||
kittycad_modeling_cmds::ModelingCmd::from(each_cmd::TakeSnapshot {
|
||||
format: ImageFormat::Png,
|
||||
}),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let out = match out {
|
||||
OkModelingCmdResponse::TakeSnapshot(kittycad_modeling_cmds::output::TakeSnapshot { contents: b }) => b,
|
||||
other => panic!("wrong output: {other:?}"),
|
||||
};
|
||||
|
||||
use image::io::Reader as ImageReader;
|
||||
let img = ImageReader::new(std::io::Cursor::new(out))
|
||||
.with_guessed_format()
|
||||
.unwrap()
|
||||
.decode()
|
||||
.unwrap();
|
||||
twenty_twenty::assert_image("fixtures/cube_lineTo.png", &img, 0.9999);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn stdlib_cube_xline_yline() {
|
||||
let program = r#"
|
||||
let cube = startSketchAt([0.0, 0.0], "adam")
|
||||
|> xLine(210.0, %, "side0")
|
||||
|> yLine(210.0, %, "side1")
|
||||
|> xLine(-210.0, %, "side2")
|
||||
|> yLine(-210.0, %, "side3")
|
||||
|> close(%)
|
||||
|> extrude(100.0, %)
|
||||
"#;
|
||||
kcvm_dbg(
|
||||
program,
|
||||
"/home/lee/Code/Zoo/modeling-api/execution-plan-debugger/cube_xyline.json",
|
||||
);
|
||||
let (_plan, _scope, _last_address) = must_plan(program);
|
||||
|
||||
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
||||
.ast()
|
||||
.unwrap();
|
||||
let mut client = Some(test_client().await);
|
||||
let mem = match crate::execute(ast, &mut client).await {
|
||||
Ok(mem) => mem,
|
||||
Err(e) => panic!("{e}"),
|
||||
};
|
||||
let sg = &mem.sketch_groups.last().unwrap();
|
||||
assert_eq!(
|
||||
sg.path_rest,
|
||||
vec![
|
||||
sketch_types::PathSegment::ToPoint {
|
||||
base: sketch_types::BasePath {
|
||||
from: Point2d { x: 0.0, y: 0.0 },
|
||||
to: Point2d { x: 210.0, y: 0.0 },
|
||||
name: "side0".into(),
|
||||
}
|
||||
},
|
||||
sketch_types::PathSegment::ToPoint {
|
||||
base: sketch_types::BasePath {
|
||||
from: Point2d { x: 210.0, y: 0.0 },
|
||||
to: Point2d { x: 210.0, y: 210.0 },
|
||||
name: "side1".into(),
|
||||
}
|
||||
},
|
||||
sketch_types::PathSegment::ToPoint {
|
||||
base: sketch_types::BasePath {
|
||||
from: Point2d { x: 210.0, y: 210.0 },
|
||||
to: Point2d { x: 0.0, y: 210.0 },
|
||||
name: "side2".into(),
|
||||
}
|
||||
},
|
||||
sketch_types::PathSegment::ToPoint {
|
||||
base: sketch_types::BasePath {
|
||||
from: Point2d { x: 0.0, y: 210.0 },
|
||||
to: Point2d { x: 0.0, y: 0.0 },
|
||||
name: "side3".into(),
|
||||
}
|
||||
},
|
||||
]
|
||||
);
|
||||
use kittycad_modeling_cmds::{each_cmd, ok_response::OkModelingCmdResponse, ImageFormat};
|
||||
let out = client
|
||||
.unwrap()
|
||||
.run_command(
|
||||
uuid::Uuid::new_v4().into(),
|
||||
kittycad_modeling_cmds::ModelingCmd::from(each_cmd::TakeSnapshot {
|
||||
format: ImageFormat::Png,
|
||||
}),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let out = match out {
|
||||
OkModelingCmdResponse::TakeSnapshot(kittycad_modeling_cmds::output::TakeSnapshot { contents: b }) => b,
|
||||
other => panic!("wrong output: {other:?}"),
|
||||
};
|
||||
|
||||
use image::io::Reader as ImageReader;
|
||||
let img = ImageReader::new(std::io::Cursor::new(out))
|
||||
.with_guessed_format()
|
||||
.unwrap()
|
||||
.decode()
|
||||
.unwrap();
|
||||
twenty_twenty::assert_image("fixtures/cube_xyLine.png", &img, 0.9999);
|
||||
}
|
||||
|
||||
async fn test_client() -> Session {
|
||||
@ -1328,3 +1414,51 @@ fn mod_and_pow() {
|
||||
]
|
||||
);
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn cos_sin_pi() {
|
||||
let program = "
|
||||
let x = cos(45.0)*10
|
||||
let y = sin(45.0)*10
|
||||
let z = PI
|
||||
";
|
||||
let (_plan, scope, _) = must_plan(program);
|
||||
let Some(EpBinding::Single(x)) = scope.get("x") else {
|
||||
panic!("Unexpected binding for variable 'x': {:?}", scope.get("x"));
|
||||
};
|
||||
let Some(EpBinding::Single(y)) = scope.get("y") else {
|
||||
panic!("Unexpected binding for variable 'y': {:?}", scope.get("y"));
|
||||
};
|
||||
let Some(EpBinding::Constant(z)) = scope.get("z") else {
|
||||
panic!("Unexpected binding for variable 'z': {:?}", scope.get("z"));
|
||||
};
|
||||
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
||||
.ast()
|
||||
.unwrap();
|
||||
let mem = crate::execute(ast, &mut None).await.unwrap();
|
||||
use ept::ReadMemory;
|
||||
assert_eq!(*mem.get(x).unwrap(), Primitive::from(5.253219888177298));
|
||||
assert_eq!(*mem.get(y).unwrap(), Primitive::from(8.509035245341185));
|
||||
|
||||
// Constants don't live in memory.
|
||||
assert_eq!(*z, constants::PI);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn kcl_prelude() {
|
||||
let program = "
|
||||
let the_answer_to_the_universe_is = hey_from_one_of_the_devs_of_the_past_i_wish_you_a_great_day_and_maybe_gave_you_a_little_smile_as_youve_found_this()
|
||||
";
|
||||
let (_plan, scope, _) = must_plan(program);
|
||||
let Some(EpBinding::Single(the_answer_to_the_universe_is)) = scope.get("the_answer_to_the_universe_is") else {
|
||||
panic!(
|
||||
"Unexpected binding for variable 'the_answer_to_the_universe_is': {:?}",
|
||||
scope.get("the_answer_to_the_universe_is")
|
||||
);
|
||||
};
|
||||
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
||||
.ast()
|
||||
.unwrap();
|
||||
let mem = crate::execute(ast, &mut None).await.unwrap();
|
||||
use ept::ReadMemory;
|
||||
assert_eq!(*mem.get(the_answer_to_the_universe_is).unwrap(), Primitive::from(42i64));
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ use syn::{parse_macro_input, LitStr};
|
||||
/// This macro takes exactly one argument: A string literal containing KCL.
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// extern crate alloc;
|
||||
/// use kcl_compile_macro::parse_kcl;
|
||||
/// let ast: kcl_lib::ast::types::Program = parse_kcl!("const y = 4");
|
||||
/// ```
|
||||
@ -21,3 +20,14 @@ pub fn parse(input: TokenStream) -> TokenStream {
|
||||
let ast_struct = ast.bake(&Default::default());
|
||||
quote!(#ast_struct).into()
|
||||
}
|
||||
|
||||
/// Same as `parse!` but read in a file.
|
||||
#[proc_macro]
|
||||
pub fn parse_file(input: TokenStream) -> TokenStream {
|
||||
let file_name = parse_macro_input!(input as LitStr);
|
||||
let kcl_src = std::fs::read_to_string(file_name.value()).unwrap();
|
||||
let tokens = kcl_lib::token::lexer(&kcl_src);
|
||||
let ast = kcl_lib::parser::Parser::new(tokens).ast().unwrap();
|
||||
let ast_struct = ast.bake(&Default::default());
|
||||
quote!(#ast_struct).into()
|
||||
}
|
||||
|
218
src/wasm-lib/kcl/fuzz/Cargo.lock
generated
218
src/wasm-lib/kcl/fuzz/Cargo.lock
generated
@ -7,6 +7,10 @@ name = "Inflector"
|
||||
version = "0.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
@ -45,10 +49,25 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.80"
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
@ -92,7 +111,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -103,7 +122,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -268,12 +287,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.29"
|
||||
version = "0.4.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d87d9d13be47a5b7c3907137f1290b0459a7f80efb26be8c52afb11963bccb02"
|
||||
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -320,6 +344,21 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
@ -368,7 +407,7 @@ checksum = "377af281d8f23663862a7c84623bc5dcf7f8c44b13c7496a590bdc157f941a43"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@ -380,10 +419,11 @@ checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
|
||||
|
||||
[[package]]
|
||||
name = "derive-docs"
|
||||
version = "0.1.6"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "834580a8bd697658876ed8c9f7727e49f01d34f5b859ca921ac5b99ffc6adf77"
|
||||
checksum = "b4e18a04fe569a325dd50743821f2605057ff5c4b48e60512270b4406907825b"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"convert_case",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
@ -391,7 +431,7 @@ dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_tokenstream",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -521,7 +561,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -592,7 +632,7 @@ dependencies = [
|
||||
"inflections",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -739,6 +779,29 @@ dependencies = [
|
||||
"tokio-rustls 0.24.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.4.0"
|
||||
@ -807,22 +870,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.68"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
|
||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.1.42"
|
||||
version = "0.1.46"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx",
|
||||
"async-recursion",
|
||||
"async-trait",
|
||||
"bson",
|
||||
"chrono",
|
||||
"dashmap",
|
||||
"databake",
|
||||
"derive-docs",
|
||||
@ -833,12 +897,14 @@ dependencies = [
|
||||
"kittycad-execution-plan-macros",
|
||||
"kittycad-execution-plan-traits",
|
||||
"lazy_static",
|
||||
"mime_guess",
|
||||
"parse-display 0.9.0",
|
||||
"reqwest",
|
||||
"ropey",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
@ -849,6 +915,7 @@ dependencies = [
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"winnow",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -861,9 +928,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad"
|
||||
version = "0.2.54"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13958174d876353f429ea8230dc92fe86f164819cea2e51bbf22e01a4c2a496e"
|
||||
checksum = "f8aa5906d0730bd90f6b3331fe57c04951d00743169a29ee96408767b4060605"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -877,6 +944,7 @@ dependencies = [
|
||||
"http 0.2.9",
|
||||
"itertools",
|
||||
"log",
|
||||
"mime_guess",
|
||||
"parse-display 0.8.2",
|
||||
"phonenumber",
|
||||
"rand",
|
||||
@ -899,14 +967,13 @@ source = "git+https://github.com/KittyCAD/modeling-api?branch=main#1e6ef9601686c
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan-traits"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3ec8efd57b59697eb140b63c0ffe7db44fdfe5a55f14e45513411eba2280ba5"
|
||||
version = "0.1.13"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"thiserror",
|
||||
@ -1028,9 +1095,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.10"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
||||
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
@ -1171,7 +1238,7 @@ dependencies = [
|
||||
"regex",
|
||||
"regex-syntax 0.7.5",
|
||||
"structmeta 0.2.0",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1185,7 +1252,7 @@ dependencies = [
|
||||
"regex",
|
||||
"regex-syntax 0.8.2",
|
||||
"structmeta 0.3.0",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1232,7 +1299,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1404,9 +1471,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.24"
|
||||
version = "0.11.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
|
||||
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||
dependencies = [
|
||||
"base64 0.21.3",
|
||||
"bytes",
|
||||
@ -1692,7 +1759,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1726,7 +1793,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1738,7 +1805,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1776,6 +1843,17 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
@ -1847,7 +1925,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta-derive 0.2.0",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1859,7 +1937,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta-derive 0.3.0",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1870,7 +1948,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1881,7 +1959,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1925,9 +2003,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.50"
|
||||
version = "2.0.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
|
||||
checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1948,7 +2026,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2004,7 +2082,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2077,7 +2155,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2183,7 +2261,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2212,7 +2290,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2250,7 +2328,7 @@ dependencies = [
|
||||
"Inflector",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
@ -2382,9 +2460,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
|
||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
@ -2392,24 +2470,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
|
||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.41"
|
||||
version = "0.4.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
|
||||
checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@ -2419,9 +2497,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
|
||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@ -2429,22 +2507,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
|
||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
@ -2461,9 +2539,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.68"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
|
||||
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@ -2506,6 +2584,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
@ -2680,3 +2767,14 @@ name = "zeroize"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
@ -351,6 +351,31 @@ impl Program {
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Merge two `Program`s together.
|
||||
pub fn merge(self, ast_other: Program) -> Program {
|
||||
let mut body_new: Vec<BodyItem> = vec![];
|
||||
body_new.extend(self.body);
|
||||
body_new.extend(ast_other.body);
|
||||
|
||||
let mut non_code_nodes_new: HashMap<usize, Vec<NonCodeNode>> = HashMap::new();
|
||||
non_code_nodes_new.extend(self.non_code_meta.non_code_nodes);
|
||||
non_code_nodes_new.extend(ast_other.non_code_meta.non_code_nodes);
|
||||
|
||||
let mut start_new: Vec<NonCodeNode> = vec![];
|
||||
start_new.extend(self.non_code_meta.start);
|
||||
start_new.extend(ast_other.non_code_meta.start);
|
||||
|
||||
Program {
|
||||
start: self.start,
|
||||
end: self.end + (ast_other.end - ast_other.start),
|
||||
body: body_new,
|
||||
non_code_meta: NonCodeMeta {
|
||||
non_code_nodes: non_code_nodes_new,
|
||||
start: start_new,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ValueMeta {
|
||||
@ -2519,8 +2544,18 @@ impl UnaryExpression {
|
||||
}
|
||||
|
||||
fn recast(&self, options: &FormatOptions) -> String {
|
||||
match self.argument {
|
||||
BinaryPart::Literal(_)
|
||||
| BinaryPart::Identifier(_)
|
||||
| BinaryPart::MemberExpression(_)
|
||||
| BinaryPart::CallExpression(_) => {
|
||||
format!("{}{}", &self.operator, self.argument.recast(options, 0))
|
||||
}
|
||||
BinaryPart::BinaryExpression(_) | BinaryPart::UnaryExpression(_) => {
|
||||
format!("{}({})", &self.operator, self.argument.recast(options, 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_result(
|
||||
&self,
|
||||
@ -3351,7 +3386,7 @@ const mySk1 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo([1, 1], %)
|
||||
// comment here
|
||||
|> lineTo({ to: [0, 1], tag: 'myTag' }, %)
|
||||
|> lineTo([0, 1], %, 'myTag')
|
||||
|> lineTo([1, 1], %)
|
||||
/* and
|
||||
here
|
||||
@ -3374,7 +3409,7 @@ const mySk1 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo([1, 1], %)
|
||||
// comment here
|
||||
|> lineTo({ to: [0, 1], tag: 'myTag' }, %)
|
||||
|> lineTo([0, 1], %, 'myTag')
|
||||
|> lineTo([1, 1], %)
|
||||
/* and
|
||||
here */
|
||||
@ -3392,7 +3427,7 @@ const mySk1 = startSketchOn('XY')
|
||||
fn test_recast_multiline_object() {
|
||||
let some_program_string = r#"const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([-0.01, -0.08], %)
|
||||
|> line({ to: [0.62, 4.15], tag: 'seg01' }, %)
|
||||
|> line([0.62, 4.15], %, 'seg01')
|
||||
|> line([2.77, -1.24], %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 201,
|
||||
@ -3482,7 +3517,7 @@ const myAng = 40
|
||||
const myAng2 = 134
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [1, 3.82], tag: 'seg01' }, %) // ln-should-get-tag
|
||||
|> line([1, 3.82], %, 'seg01') // ln-should-get-tag
|
||||
|> angledLineToX([
|
||||
-angleToMatchLengthX('seg01', myVar, %),
|
||||
myVar
|
||||
@ -3508,7 +3543,7 @@ const myAng = 40
|
||||
const myAng2 = 134
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [1, 3.82], tag: 'seg01' }, %) // ln-should-get-tag
|
||||
|> line([1, 3.82], %, 'seg01') // ln-should-get-tag
|
||||
|> angledLineToX([
|
||||
-angleToMatchLengthX('seg01', myVar, %),
|
||||
myVar
|
||||
@ -3774,6 +3809,25 @@ const firstExtrude = startSketchOn('XY')
|
||||
assert_eq!(recasted.trim(), some_program_string);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_recast_math_negate_parens() {
|
||||
let some_program_string = r#"const wallMountL = 3.82
|
||||
const thickness = 0.5
|
||||
|
||||
startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, -(wallMountL - thickness)], %)
|
||||
|> line([0, -(5 - thickness)], %)
|
||||
|> line([0, -(5 - 1)], %)
|
||||
|> line([0, -(-5 - 1)], %)"#;
|
||||
let tokens = crate::token::lexer(some_program_string);
|
||||
let parser = crate::parser::Parser::new(tokens);
|
||||
let program = parser.ast().unwrap();
|
||||
|
||||
let recasted = program.recast(&Default::default(), 0);
|
||||
assert_eq!(recasted.trim(), some_program_string);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_recast_math_nested_parens() {
|
||||
let some_program_string = r#"const distance = 5
|
||||
|
@ -1323,14 +1323,13 @@ const newVar = myVar + 1"#;
|
||||
format!(
|
||||
r#"const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo({{to:[2, 2], tag: "yo"}}, %)
|
||||
|> lineTo([2, 2], %, "yo")
|
||||
|> lineTo([3, 1], %)
|
||||
|> angledLineThatIntersects({{
|
||||
angle: 180,
|
||||
intersectTag: 'yo',
|
||||
offset: {},
|
||||
tag: "yo2"
|
||||
}}, %)
|
||||
}}, %, 'yo2')
|
||||
const intersect = segEndX('yo2', part001)"#,
|
||||
offset
|
||||
)
|
||||
@ -1387,7 +1386,7 @@ const yo2 = hmm([identifierGuy + 5])"#;
|
||||
let ast = r#"const myVar = 3
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [3, 4], tag: 'seg01' }, %)
|
||||
|> line([3, 4], %, 'seg01')
|
||||
|> line([
|
||||
min(segLen('seg01', %), myVar),
|
||||
-legLen(segLen('seg01', %), myVar)
|
||||
@ -1402,7 +1401,7 @@ const part001 = startSketchOn('XY')
|
||||
let ast = r#"const myVar = 3
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line({ to: [3, 4], tag: 'seg01' }, %)
|
||||
|> line([3, 4], %, 'seg01')
|
||||
|> line([
|
||||
min(segLen('seg01', %), myVar),
|
||||
legLen(segLen('seg01', %), myVar)
|
||||
|
@ -1124,24 +1124,13 @@ async fn test_copilot_lsp_completions_raw() {
|
||||
let completions = server
|
||||
.get_completions(
|
||||
"kcl".to_string(),
|
||||
r#"// Create a cube.
|
||||
fn cube = (pos, scale) => {
|
||||
const sg = startSketchOn('XY')
|
||||
|> startProfileAt(pos, %)
|
||||
|> line([0, scale], %)
|
||||
|> line([scale, 0], %)
|
||||
|> line([0, -scale], %)
|
||||
|
||||
return sg
|
||||
}
|
||||
|
||||
const part001 = cube([0,0], 20)
|
||||
|> close(%)
|
||||
|> extrude(20, %)
|
||||
|
||||
"#
|
||||
r#"const bracket = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
"#
|
||||
.to_string(),
|
||||
r#" |> close(%)
|
||||
|> extrude(10, %)"#
|
||||
.to_string(),
|
||||
r#""#.to_string(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@ -1154,24 +1143,13 @@ const part001 = cube([0,0], 20)
|
||||
let completions_hit_cache = server
|
||||
.get_completions(
|
||||
"kcl".to_string(),
|
||||
r#"// Create a cube.
|
||||
fn cube = (pos, scale) => {
|
||||
const sg = startSketchOn('XY')
|
||||
|> startProfileAt(pos, %)
|
||||
|> line([0, scale], %)
|
||||
|> line([scale, 0], %)
|
||||
|> line([0, -scale], %)
|
||||
|
||||
return sg
|
||||
}
|
||||
|
||||
const part001 = cube([0,0], 20)
|
||||
|> close(%)
|
||||
|> extrude(20, %)
|
||||
|
||||
"#
|
||||
r#"const bracket = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
"#
|
||||
.to_string(),
|
||||
r#" |> close(%)
|
||||
|> extrude(10, %)"#
|
||||
.to_string(),
|
||||
r#""#.to_string(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@ -1202,23 +1180,13 @@ async fn test_copilot_lsp_completions() {
|
||||
insert_spaces: true,
|
||||
language_id: "kcl".to_string(),
|
||||
path: "file:///test.copilot".to_string(),
|
||||
position: crate::lsp::copilot::types::CopilotPosition { line: 0, character: 1 },
|
||||
position: crate::lsp::copilot::types::CopilotPosition { line: 3, character: 3 },
|
||||
relative_path: "test.copilot".to_string(),
|
||||
source: r#"// Create a cube.
|
||||
fn cube = (pos, scale) => {
|
||||
const sg = startSketchOn('XY')
|
||||
|> startProfileAt(pos, %)
|
||||
|> line([0, scale], %)
|
||||
|> line([scale, 0], %)
|
||||
|> line([0, -scale], %)
|
||||
source: r#"const bracket = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|
||||
return sg
|
||||
}
|
||||
|
||||
const part001 = cube([0,0], 20)
|
||||
|> close(%)
|
||||
|> extrude(20, %)
|
||||
|
||||
|> extrude(10, %)
|
||||
"#
|
||||
.to_string(),
|
||||
tab_size: 4,
|
||||
|
@ -2903,9 +2903,9 @@ mod snapshot_tests {
|
||||
snapshot_test!(
|
||||
af,
|
||||
r#"const mySketch = startSketchAt([0,0])
|
||||
|> lineTo({ to: [0, 1], tag: 'myPath' }, %)
|
||||
|> lineTo([0, 1], %, 'myPath')
|
||||
|> lineTo([1, 1], %)
|
||||
|> lineTo({ to: [1,0], tag: "rightPath" }, %)
|
||||
|> lineTo([1, 0], %, 'rightPath')
|
||||
|> close(%)"#
|
||||
);
|
||||
snapshot_test!(
|
||||
|
@ -4,18 +4,18 @@ expression: actual
|
||||
---
|
||||
{
|
||||
"start": 0,
|
||||
"end": 192,
|
||||
"end": 167,
|
||||
"body": [
|
||||
{
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration",
|
||||
"start": 0,
|
||||
"end": 192,
|
||||
"end": 167,
|
||||
"declarations": [
|
||||
{
|
||||
"type": "VariableDeclarator",
|
||||
"start": 6,
|
||||
"end": 192,
|
||||
"end": 167,
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"start": 6,
|
||||
@ -26,7 +26,7 @@ expression: actual
|
||||
"type": "PipeExpression",
|
||||
"type": "PipeExpression",
|
||||
"start": 17,
|
||||
"end": 192,
|
||||
"end": 167,
|
||||
"body": [
|
||||
{
|
||||
"type": "CallExpression",
|
||||
@ -71,7 +71,7 @@ expression: actual
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression",
|
||||
"start": 49,
|
||||
"end": 89,
|
||||
"end": 76,
|
||||
"callee": {
|
||||
"type": "Identifier",
|
||||
"start": 49,
|
||||
@ -80,107 +80,77 @@ expression: actual
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"type": "ObjectExpression",
|
||||
"type": "ObjectExpression",
|
||||
"type": "ArrayExpression",
|
||||
"type": "ArrayExpression",
|
||||
"start": 56,
|
||||
"end": 85,
|
||||
"properties": [
|
||||
{
|
||||
"type": "ObjectProperty",
|
||||
"start": 58,
|
||||
"end": 68,
|
||||
"key": {
|
||||
"type": "Identifier",
|
||||
"start": 58,
|
||||
"end": 60,
|
||||
"name": "to"
|
||||
},
|
||||
"value": {
|
||||
"type": "ArrayExpression",
|
||||
"type": "ArrayExpression",
|
||||
"start": 62,
|
||||
"end": 68,
|
||||
"end": 62,
|
||||
"elements": [
|
||||
{
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"start": 63,
|
||||
"end": 64,
|
||||
"start": 57,
|
||||
"end": 58,
|
||||
"value": 0,
|
||||
"raw": "0"
|
||||
},
|
||||
{
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"start": 66,
|
||||
"end": 67,
|
||||
"start": 60,
|
||||
"end": 61,
|
||||
"value": 1,
|
||||
"raw": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ObjectProperty",
|
||||
"start": 70,
|
||||
"end": 83,
|
||||
"key": {
|
||||
"type": "Identifier",
|
||||
"start": 70,
|
||||
"end": 73,
|
||||
"name": "tag"
|
||||
"type": "PipeSubstitution",
|
||||
"type": "PipeSubstitution",
|
||||
"start": 64,
|
||||
"end": 65
|
||||
},
|
||||
"value": {
|
||||
{
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"start": 75,
|
||||
"end": 83,
|
||||
"start": 67,
|
||||
"end": 75,
|
||||
"value": "myPath",
|
||||
"raw": "'myPath'"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "PipeSubstitution",
|
||||
"type": "PipeSubstitution",
|
||||
"start": 87,
|
||||
"end": 88
|
||||
}
|
||||
],
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression",
|
||||
"start": 101,
|
||||
"end": 118,
|
||||
"start": 88,
|
||||
"end": 105,
|
||||
"callee": {
|
||||
"type": "Identifier",
|
||||
"start": 101,
|
||||
"end": 107,
|
||||
"start": 88,
|
||||
"end": 94,
|
||||
"name": "lineTo"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"type": "ArrayExpression",
|
||||
"type": "ArrayExpression",
|
||||
"start": 108,
|
||||
"end": 114,
|
||||
"start": 95,
|
||||
"end": 101,
|
||||
"elements": [
|
||||
{
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"start": 109,
|
||||
"end": 110,
|
||||
"start": 96,
|
||||
"end": 97,
|
||||
"value": 1,
|
||||
"raw": "1"
|
||||
},
|
||||
{
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"start": 112,
|
||||
"end": 113,
|
||||
"start": 99,
|
||||
"end": 100,
|
||||
"value": 1,
|
||||
"raw": "1"
|
||||
}
|
||||
@ -189,8 +159,8 @@ expression: actual
|
||||
{
|
||||
"type": "PipeSubstitution",
|
||||
"type": "PipeSubstitution",
|
||||
"start": 116,
|
||||
"end": 117
|
||||
"start": 103,
|
||||
"end": 104
|
||||
}
|
||||
],
|
||||
"optional": false
|
||||
@ -198,82 +168,52 @@ expression: actual
|
||||
{
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression",
|
||||
"start": 130,
|
||||
"end": 172,
|
||||
"callee": {
|
||||
"type": "Identifier",
|
||||
"start": 130,
|
||||
"end": 136,
|
||||
"name": "lineTo"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"type": "ObjectExpression",
|
||||
"type": "ObjectExpression",
|
||||
"start": 137,
|
||||
"end": 168,
|
||||
"properties": [
|
||||
{
|
||||
"type": "ObjectProperty",
|
||||
"start": 139,
|
||||
"end": 148,
|
||||
"key": {
|
||||
"type": "Identifier",
|
||||
"start": 139,
|
||||
"end": 141,
|
||||
"name": "to"
|
||||
},
|
||||
"value": {
|
||||
"type": "ArrayExpression",
|
||||
"type": "ArrayExpression",
|
||||
"start": 143,
|
||||
"end": 148,
|
||||
"elements": [
|
||||
{
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"start": 144,
|
||||
"end": 145,
|
||||
"value": 1,
|
||||
"raw": "1"
|
||||
},
|
||||
{
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"start": 146,
|
||||
"start": 117,
|
||||
"end": 147,
|
||||
"callee": {
|
||||
"type": "Identifier",
|
||||
"start": 117,
|
||||
"end": 123,
|
||||
"name": "lineTo"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"type": "ArrayExpression",
|
||||
"type": "ArrayExpression",
|
||||
"start": 124,
|
||||
"end": 130,
|
||||
"elements": [
|
||||
{
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"start": 125,
|
||||
"end": 126,
|
||||
"value": 1,
|
||||
"raw": "1"
|
||||
},
|
||||
{
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"start": 128,
|
||||
"end": 129,
|
||||
"value": 0,
|
||||
"raw": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ObjectProperty",
|
||||
"start": 150,
|
||||
"end": 166,
|
||||
"key": {
|
||||
"type": "Identifier",
|
||||
"start": 150,
|
||||
"end": 153,
|
||||
"name": "tag"
|
||||
"type": "PipeSubstitution",
|
||||
"type": "PipeSubstitution",
|
||||
"start": 132,
|
||||
"end": 133
|
||||
},
|
||||
"value": {
|
||||
{
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"start": 155,
|
||||
"end": 166,
|
||||
"start": 135,
|
||||
"end": 146,
|
||||
"value": "rightPath",
|
||||
"raw": "\"rightPath\""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "PipeSubstitution",
|
||||
"type": "PipeSubstitution",
|
||||
"start": 170,
|
||||
"end": 171
|
||||
"raw": "'rightPath'"
|
||||
}
|
||||
],
|
||||
"optional": false
|
||||
@ -281,20 +221,20 @@ expression: actual
|
||||
{
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression",
|
||||
"start": 184,
|
||||
"end": 192,
|
||||
"start": 159,
|
||||
"end": 167,
|
||||
"callee": {
|
||||
"type": "Identifier",
|
||||
"start": 184,
|
||||
"end": 189,
|
||||
"start": 159,
|
||||
"end": 164,
|
||||
"name": "close"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"type": "PipeSubstitution",
|
||||
"type": "PipeSubstitution",
|
||||
"start": 190,
|
||||
"end": 191
|
||||
"start": 165,
|
||||
"end": 166
|
||||
}
|
||||
],
|
||||
"optional": false
|
||||
|
@ -196,7 +196,7 @@ pub async fn get_extrude_wall_transform(args: Args) -> Result<MemoryItem, KclErr
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line({to: [0, -10], tag: "surface"}, %)
|
||||
/// |> line([0, -10], %, "surface")
|
||||
/// |> close(%)
|
||||
/// |> extrude(5, %)
|
||||
///
|
||||
|
@ -48,9 +48,9 @@ pub async fn fillet(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// ```no_run
|
||||
/// const part001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([0,0], %)
|
||||
/// |> line({to: [0, 10], tag: "thing"}, %)
|
||||
/// |> line([0, 10], %, "thing")
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line({to: [0, -10], tag: "thing2"}, %)
|
||||
/// |> line([0, -10], %, "thing2")
|
||||
/// |> close(%)
|
||||
/// |> extrude(10, %)
|
||||
/// |> fillet({radius: 2, tags: ["thing", "thing2"]}, %)
|
||||
@ -130,9 +130,9 @@ pub async fn get_opposite_edge(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// ```no_run
|
||||
/// const part001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([0,0], %)
|
||||
/// |> line({to: [0, 10], tag: "thing"}, %)
|
||||
/// |> line([0, 10], %, "thing")
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line({to: [0, -10], tag: "thing2"}, %)
|
||||
/// |> line([0, -10], %, "thing2")
|
||||
/// |> close(%)
|
||||
/// |> extrude(10, %)
|
||||
/// |> fillet({radius: 2, tags: ["thing", getOppositeEdge("thing", %)]}, %)
|
||||
@ -199,9 +199,9 @@ pub async fn get_next_adjacent_edge(args: Args) -> Result<MemoryItem, KclError>
|
||||
/// ```no_run
|
||||
/// const part001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([0,0], %)
|
||||
/// |> line({to: [0, 10], tag: "thing"}, %)
|
||||
/// |> line({to: [10, 0], tag: "thing1"}, %)
|
||||
/// |> line({to: [0, -10], tag: "thing2"}, %)
|
||||
/// |> line([0, 10], %, "thing")
|
||||
/// |> line([10, 0], %, "thing1")
|
||||
/// |> line([0, -10], %, "thing2")
|
||||
/// |> close(%)
|
||||
/// |> extrude(10, %)
|
||||
/// |> fillet({radius: 2, tags: [getNextAdjacentEdge("thing", %)]}, %)
|
||||
@ -277,9 +277,9 @@ pub async fn get_previous_adjacent_edge(args: Args) -> Result<MemoryItem, KclErr
|
||||
/// ```no_run
|
||||
/// const part001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([0,0], %)
|
||||
/// |> line({to: [0, 10], tag: "thing"}, %)
|
||||
/// |> line({to: [10, 0], tag: "thing1"}, %)
|
||||
/// |> line({to: [0, -10], tag: "thing2"}, %)
|
||||
/// |> line([0, 10], %, "thing")
|
||||
/// |> line([10, 0], %, "thing1")
|
||||
/// |> line([0, -10], %, "thing2")
|
||||
/// |> close(%)
|
||||
/// |> extrude(10, %)
|
||||
/// |> fillet({radius: 2, tags: [getPreviousAdjacentEdge("thing2", %)]}, %)
|
||||
|
@ -622,7 +622,54 @@ impl Args {
|
||||
Ok((data, sketch_group))
|
||||
}
|
||||
|
||||
fn get_data_and_sketch_surface<T: serde::de::DeserializeOwned>(&self) -> Result<(T, SketchSurface), KclError> {
|
||||
fn get_data_and_sketch_group_and_tag<T: serde::de::DeserializeOwned>(
|
||||
&self,
|
||||
) -> Result<(T, Box<SketchGroup>, Option<String>), KclError> {
|
||||
let first_value = self
|
||||
.args
|
||||
.first()
|
||||
.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
|
||||
source_ranges: vec![self.source_range],
|
||||
})
|
||||
})?
|
||||
.get_json_value()?;
|
||||
|
||||
let data: T = serde_json::from_value(first_value).map_err(|e| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Failed to deserialize struct from JSON: {}", e),
|
||||
source_ranges: vec![self.source_range],
|
||||
})
|
||||
})?;
|
||||
|
||||
let second_value = self.args.get(1).ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
|
||||
source_ranges: vec![self.source_range],
|
||||
})
|
||||
})?;
|
||||
|
||||
let sketch_group = if let MemoryItem::SketchGroup(sg) = second_value {
|
||||
sg.clone()
|
||||
} else {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
|
||||
source_ranges: vec![self.source_range],
|
||||
}));
|
||||
};
|
||||
let tag = if let Some(tag) = self.args.get(2) {
|
||||
tag.get_json_opt()?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok((data, sketch_group, tag))
|
||||
}
|
||||
|
||||
fn get_data_and_sketch_surface<T: serde::de::DeserializeOwned>(
|
||||
&self,
|
||||
) -> Result<(T, SketchSurface, Option<String>), KclError> {
|
||||
let first_value = self
|
||||
.args
|
||||
.first()
|
||||
@ -661,8 +708,13 @@ impl Args {
|
||||
source_ranges: vec![self.source_range],
|
||||
}));
|
||||
};
|
||||
let tag = if let Some(tag) = self.args.get(2) {
|
||||
tag.get_json_opt()?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok((data, sketch_surface))
|
||||
Ok((data, sketch_surface, tag))
|
||||
}
|
||||
|
||||
fn get_data_and_extrude_group<T: serde::de::DeserializeOwned>(&self) -> Result<(T, Box<ExtrudeGroup>), KclError> {
|
||||
|
@ -24,7 +24,7 @@ pub async fn segment_end_x(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// ```no_run
|
||||
/// startSketchOn("YZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line({ to: [5, 0], tag: "thing" }, %)
|
||||
/// |> line([5, 0], %, "thing")
|
||||
/// |> line([5, 5], %)
|
||||
/// |> line([segEndX("thing", %), 5], %)
|
||||
/// |> close(%)
|
||||
@ -60,7 +60,7 @@ pub async fn segment_end_y(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// ```no_run
|
||||
/// startSketchOn("YZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line({ to: [5, 0], tag: "thing" }, %)
|
||||
/// |> line([5, 0], %, "thing")
|
||||
/// |> line([5, 5], %)
|
||||
/// |> line([segEndY("thing", %), 5], %)
|
||||
/// |> close(%)
|
||||
@ -96,7 +96,7 @@ pub async fn last_segment_x(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// ```no_run
|
||||
/// startSketchOn("YZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line({ to: [5, 0], tag: "thing" }, %)
|
||||
/// |> line([5, 0], %, "thing")
|
||||
/// |> line([5, 5], %)
|
||||
/// |> line([0, lastSegX(%)], %)
|
||||
/// |> close(%)
|
||||
@ -136,7 +136,7 @@ pub async fn last_segment_y(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// ```no_run
|
||||
/// startSketchOn("YZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line({ to: [5, 0], tag: "thing" }, %)
|
||||
/// |> line([5, 0], %, "thing")
|
||||
/// |> line([5, 5], %)
|
||||
/// |> line([0, lastSegY(%)], %)
|
||||
/// |> close(%)
|
||||
@ -175,7 +175,7 @@ pub async fn segment_length(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// ```no_run
|
||||
/// startSketchOn("YZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line({ to: [5, 0], tag: "thing" }, %)
|
||||
/// |> line([5, 0], %, "thing")
|
||||
/// |> line([5, 5], %)
|
||||
/// |> line([0, segLen("thing", %)], %)
|
||||
/// |> close(%)
|
||||
@ -215,7 +215,7 @@ pub async fn segment_angle(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// const part001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([4.83, 12.56], %)
|
||||
/// |> line([15.1, 2.48], %)
|
||||
/// |> line({ to: [3.15, -9.85], tag: 'seg01' }, %)
|
||||
/// |> line([3.15, -9.85], %, 'seg01')
|
||||
/// |> line([-15.17, -4.1], %)
|
||||
/// |> angledLine([segAng('seg01', %), 12.35], %)
|
||||
/// |> line([-13.02, 10.03], %)
|
||||
@ -254,7 +254,7 @@ pub async fn angle_to_match_length_x(args: Args) -> Result<MemoryItem, KclError>
|
||||
/// ```no_run
|
||||
/// const part001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line({ to: [1, 3.82], tag: 'seg01' }, %)
|
||||
/// |> line([1, 3.82], %, 'seg01')
|
||||
/// |> angledLineToX([
|
||||
/// -angleToMatchLengthX('seg01', 10, %),
|
||||
/// 5
|
||||
@ -320,7 +320,7 @@ pub async fn angle_to_match_length_y(args: Args) -> Result<MemoryItem, KclError>
|
||||
/// ```no_run
|
||||
/// const part001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line({ to: [1, 3.82], tag: 'seg01' }, %)
|
||||
/// |> line([1, 3.82], %, 'seg01')
|
||||
/// |> angledLineToX([
|
||||
/// -angleToMatchLengthY('seg01', 10, %),
|
||||
/// 5
|
||||
|
@ -58,11 +58,8 @@ async fn inner_circle(
|
||||
SketchSurfaceOrGroup::SketchSurface(surface) => surface,
|
||||
SketchSurfaceOrGroup::SketchGroup(group) => group.on,
|
||||
};
|
||||
let mut sketch_group = crate::std::sketch::inner_start_profile_at(
|
||||
crate::std::sketch::LineData::Point([center[0] + radius, center[1]]),
|
||||
sketch_surface,
|
||||
args.clone(),
|
||||
)
|
||||
let mut sketch_group =
|
||||
crate::std::sketch::inner_start_profile_at([center[0] + radius, center[1]], sketch_surface, None, args.clone())
|
||||
.await?;
|
||||
|
||||
// Call arc.
|
||||
@ -71,9 +68,9 @@ async fn inner_circle(
|
||||
angle_start: 0.0,
|
||||
angle_end: 360.0,
|
||||
radius,
|
||||
tag,
|
||||
},
|
||||
sketch_group,
|
||||
tag,
|
||||
args.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
@ -23,27 +23,12 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
/// Data to draw a line to a point.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase", untagged)]
|
||||
pub enum LineToData {
|
||||
/// A point with a tag.
|
||||
PointWithTag {
|
||||
/// The to point.
|
||||
to: [f64; 2],
|
||||
/// The tag.
|
||||
tag: String,
|
||||
},
|
||||
/// A point.
|
||||
Point([f64; 2]),
|
||||
}
|
||||
|
||||
/// Draw a line to a point.
|
||||
pub async fn line_to(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (LineToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (to, sketch_group, tag): ([f64; 2], Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_line_to(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_line_to(to, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -53,18 +38,9 @@ pub async fn line_to(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// fn rectShape = (pos, w, l) => {
|
||||
/// const rr = startSketchOn('YZ')
|
||||
/// |> startProfileAt([pos[0] - (w / 2), pos[1] - (l / 2)], %)
|
||||
/// |> lineTo({
|
||||
/// to: [pos[0] + w / 2, pos[1] - (l / 2)],
|
||||
/// tag: "edge1"
|
||||
/// }, %)
|
||||
/// |> lineTo({
|
||||
/// to: [pos[0] + w / 2, pos[1] + l / 2],
|
||||
/// tag: "edge2"
|
||||
/// }, %)
|
||||
/// |> lineTo({
|
||||
/// to: [pos[0] - (w / 2), pos[1] + l / 2],
|
||||
/// tag: "edge3"
|
||||
/// }, %)
|
||||
/// |> lineTo([pos[0] + w / 2, pos[1] - (l / 2)], %, "edge1")
|
||||
/// |> lineTo([pos[0] + w / 2, pos[1] + l / 2], %, "edge2")
|
||||
/// |> lineTo([pos[0] - (w / 2), pos[1] + l / 2], %, "edge3")
|
||||
/// |> close(%, "edge4")
|
||||
/// return rr
|
||||
/// }
|
||||
@ -76,16 +52,12 @@ pub async fn line_to(args: Args) -> Result<MemoryItem, KclError> {
|
||||
name = "lineTo",
|
||||
}]
|
||||
async fn inner_line_to(
|
||||
data: LineToData,
|
||||
to: [f64; 2],
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let from = sketch_group.get_coords_from_paths()?;
|
||||
let to = match data {
|
||||
LineToData::PointWithTag { to, .. } => to,
|
||||
LineToData::Point(to) => to,
|
||||
};
|
||||
|
||||
let id = uuid::Uuid::new_v4();
|
||||
|
||||
args.send_modeling_cmd(
|
||||
@ -108,11 +80,7 @@ async fn inner_line_to(
|
||||
base: BasePath {
|
||||
from: from.into(),
|
||||
to,
|
||||
name: if let LineToData::PointWithTag { tag, .. } = data {
|
||||
tag.to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
name: tag.unwrap_or("".to_string()),
|
||||
geo_meta: GeoMeta {
|
||||
id,
|
||||
metadata: args.source_range.into(),
|
||||
@ -126,27 +94,11 @@ async fn inner_line_to(
|
||||
Ok(new_sketch_group)
|
||||
}
|
||||
|
||||
/// Data to draw a line to a point on an axis.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase", untagged)]
|
||||
pub enum AxisLineToData {
|
||||
/// A point with a tag.
|
||||
PointWithTag {
|
||||
/// The to point.
|
||||
to: f64,
|
||||
/// The tag.
|
||||
tag: String,
|
||||
},
|
||||
/// A point.
|
||||
Point(f64),
|
||||
}
|
||||
|
||||
/// Draw a line to a point on the x-axis.
|
||||
pub async fn x_line_to(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (AxisLineToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (to, sketch_group, tag): (f64, Box<SketchGroup>, Option<String>) = args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_x_line_to(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_x_line_to(to, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -155,10 +107,7 @@ pub async fn x_line_to(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// ```no_run
|
||||
/// startSketchOn('XY')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> xLineTo({
|
||||
/// to: 10,
|
||||
/// tag: "edge1"
|
||||
/// }, %)
|
||||
/// |> xLineTo(10, %, "edge1")
|
||||
/// |> line([10, 10], %)
|
||||
/// |> close(%, "edge2")
|
||||
/// |> extrude(10, %)
|
||||
@ -167,27 +116,23 @@ pub async fn x_line_to(args: Args) -> Result<MemoryItem, KclError> {
|
||||
name = "xLineTo",
|
||||
}]
|
||||
async fn inner_x_line_to(
|
||||
data: AxisLineToData,
|
||||
to: f64,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let from = sketch_group.get_coords_from_paths()?;
|
||||
|
||||
let line_to_data = match data {
|
||||
AxisLineToData::PointWithTag { to, tag } => LineToData::PointWithTag { to: [to, from.y], tag },
|
||||
AxisLineToData::Point(data) => LineToData::Point([data, from.y]),
|
||||
};
|
||||
|
||||
let new_sketch_group = inner_line_to(line_to_data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_line_to([to, from.y], sketch_group, tag, args).await?;
|
||||
|
||||
Ok(new_sketch_group)
|
||||
}
|
||||
|
||||
/// Draw a line to a point on the y-axis.
|
||||
pub async fn y_line_to(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (AxisLineToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (to, sketch_group, tag): (f64, Box<SketchGroup>, Option<String>) = args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_y_line_to(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_y_line_to(to, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -196,10 +141,7 @@ pub async fn y_line_to(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// ```no_run
|
||||
/// startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> yLineTo({
|
||||
/// to: 10,
|
||||
/// tag: "edge1"
|
||||
/// }, %)
|
||||
/// |> yLineTo(10, %, "edge1")
|
||||
/// |> line([10, 10], %)
|
||||
/// |> close(%, "edge2")
|
||||
/// |> extrude(10, %)
|
||||
@ -209,42 +151,23 @@ pub async fn y_line_to(args: Args) -> Result<MemoryItem, KclError> {
|
||||
name = "yLineTo",
|
||||
}]
|
||||
async fn inner_y_line_to(
|
||||
data: AxisLineToData,
|
||||
to: f64,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let from = sketch_group.get_coords_from_paths()?;
|
||||
|
||||
let line_to_data = match data {
|
||||
AxisLineToData::PointWithTag { to, tag } => LineToData::PointWithTag { to: [from.x, to], tag },
|
||||
AxisLineToData::Point(data) => LineToData::Point([from.x, data]),
|
||||
};
|
||||
|
||||
let new_sketch_group = inner_line_to(line_to_data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_line_to([from.x, to], sketch_group, tag, args).await?;
|
||||
Ok(new_sketch_group)
|
||||
}
|
||||
|
||||
/// Data to draw a line.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase", untagged)]
|
||||
pub enum LineData {
|
||||
/// A point with a tag.
|
||||
PointWithTag {
|
||||
/// The to point.
|
||||
to: [f64; 2],
|
||||
/// The tag.
|
||||
tag: String,
|
||||
},
|
||||
/// A point.
|
||||
Point([f64; 2]),
|
||||
}
|
||||
|
||||
/// Draw a line.
|
||||
pub async fn line(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (LineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (delta, sketch_group, tag): ([f64; 2], Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_line(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_line(delta, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -254,22 +177,21 @@ pub async fn line(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// startSketchOn('-XY')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 10], %)
|
||||
/// |> line({to: [20, 10], tag: "edge1"}, %)
|
||||
/// |> line([20, 10], %, "edge1")
|
||||
/// |> close(%, "edge2")
|
||||
/// |> extrude(10, %)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "line",
|
||||
}]
|
||||
async fn inner_line(data: LineData, sketch_group: Box<SketchGroup>, args: Args) -> Result<Box<SketchGroup>, KclError> {
|
||||
async fn inner_line(
|
||||
delta: [f64; 2],
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let from = sketch_group.get_coords_from_paths()?;
|
||||
let inner_args = match &data {
|
||||
LineData::PointWithTag { to, .. } => *to,
|
||||
LineData::Point(to) => *to,
|
||||
};
|
||||
|
||||
let delta = inner_args;
|
||||
let to = [from.x + inner_args[0], from.y + inner_args[1]];
|
||||
let to = [from.x + delta[0], from.y + delta[1]];
|
||||
|
||||
let id = uuid::Uuid::new_v4();
|
||||
|
||||
@ -293,11 +215,7 @@ async fn inner_line(data: LineData, sketch_group: Box<SketchGroup>, args: Args)
|
||||
base: BasePath {
|
||||
from: from.into(),
|
||||
to,
|
||||
name: if let LineData::PointWithTag { tag, .. } = data {
|
||||
tag.to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
name: tag.unwrap_or("".to_string()),
|
||||
geo_meta: GeoMeta {
|
||||
id,
|
||||
metadata: args.source_range.into(),
|
||||
@ -311,27 +229,12 @@ async fn inner_line(data: LineData, sketch_group: Box<SketchGroup>, args: Args)
|
||||
Ok(new_sketch_group)
|
||||
}
|
||||
|
||||
/// Data to draw a line on an axis.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase", untagged)]
|
||||
pub enum AxisLineData {
|
||||
/// The length with a tag.
|
||||
LengthWithTag {
|
||||
/// The length of the line.
|
||||
length: f64,
|
||||
/// The tag.
|
||||
tag: String,
|
||||
},
|
||||
/// The length.
|
||||
Length(f64),
|
||||
}
|
||||
|
||||
/// Draw a line on the x-axis.
|
||||
pub async fn x_line(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (AxisLineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (length, sketch_group, tag): (f64, Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_x_line(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_x_line(length, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -349,24 +252,20 @@ pub async fn x_line(args: Args) -> Result<MemoryItem, KclError> {
|
||||
name = "xLine",
|
||||
}]
|
||||
async fn inner_x_line(
|
||||
data: AxisLineData,
|
||||
length: f64,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let line_data = match data {
|
||||
AxisLineData::LengthWithTag { length, tag } => LineData::PointWithTag { to: [length, 0.0], tag },
|
||||
AxisLineData::Length(length) => LineData::Point([length, 0.0]),
|
||||
};
|
||||
|
||||
let new_sketch_group = inner_line(line_data, sketch_group, args).await?;
|
||||
Ok(new_sketch_group)
|
||||
inner_line([length, 0.0], sketch_group, tag, args).await
|
||||
}
|
||||
|
||||
/// Draw a line on the y-axis.
|
||||
pub async fn y_line(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (AxisLineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (length, sketch_group, tag): (f64, Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_y_line(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_y_line(length, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -384,17 +283,12 @@ pub async fn y_line(args: Args) -> Result<MemoryItem, KclError> {
|
||||
name = "yLine",
|
||||
}]
|
||||
async fn inner_y_line(
|
||||
data: AxisLineData,
|
||||
length: f64,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let line_data = match data {
|
||||
AxisLineData::LengthWithTag { length, tag } => LineData::PointWithTag { to: [0.0, length], tag },
|
||||
AxisLineData::Length(length) => LineData::Point([0.0, length]),
|
||||
};
|
||||
|
||||
let new_sketch_group = inner_line(line_data, sketch_group, args).await?;
|
||||
Ok(new_sketch_group)
|
||||
inner_line([0.0, length], sketch_group, tag, args).await
|
||||
}
|
||||
|
||||
/// Data to draw an angled line.
|
||||
@ -402,34 +296,23 @@ async fn inner_y_line(
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase", untagged)]
|
||||
pub enum AngledLineData {
|
||||
/// An angle and length with a tag.
|
||||
AngleWithTag {
|
||||
/// An angle and length with explicitly named parameters
|
||||
AngleAndLengthNamed {
|
||||
/// The angle of the line.
|
||||
angle: f64,
|
||||
/// The length of the line.
|
||||
length: f64,
|
||||
/// The tag.
|
||||
tag: String,
|
||||
},
|
||||
/// An angle and length.
|
||||
AngleAndLength([f64; 2]),
|
||||
}
|
||||
|
||||
impl AngledLineData {
|
||||
pub fn into_inner_line(self, to: [f64; 2]) -> LineData {
|
||||
if let AngledLineData::AngleWithTag { tag, .. } = self {
|
||||
LineData::PointWithTag { to, tag }
|
||||
} else {
|
||||
LineData::Point(to)
|
||||
}
|
||||
}
|
||||
/// An angle and length given as a pair
|
||||
AngleAndLengthPair([f64; 2]),
|
||||
}
|
||||
|
||||
/// Draw an angled line.
|
||||
pub async fn angled_line(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (AngledLineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (data, sketch_group, tag): (AngledLineData, Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_angled_line(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_angled_line(data, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -441,8 +324,7 @@ pub async fn angled_line(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// |> angledLine({
|
||||
/// angle: 45,
|
||||
/// length: 10,
|
||||
/// tag: "edge1"
|
||||
/// }, %)
|
||||
/// }, %, "edge1")
|
||||
/// |> line([10, 10], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> close(%, "edge2")
|
||||
@ -454,12 +336,13 @@ pub async fn angled_line(args: Args) -> Result<MemoryItem, KclError> {
|
||||
async fn inner_angled_line(
|
||||
data: AngledLineData,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let from = sketch_group.get_coords_from_paths()?;
|
||||
let (angle, length) = match &data {
|
||||
AngledLineData::AngleWithTag { angle, length, .. } => (*angle, *length),
|
||||
AngledLineData::AngleAndLength(angle_and_length) => (angle_and_length[0], angle_and_length[1]),
|
||||
let (angle, length) = match data {
|
||||
AngledLineData::AngleAndLengthNamed { angle, length } => (angle, length),
|
||||
AngledLineData::AngleAndLengthPair(pair) => (pair[0], pair[1]),
|
||||
};
|
||||
|
||||
//double check me on this one - mike
|
||||
@ -477,11 +360,7 @@ async fn inner_angled_line(
|
||||
base: BasePath {
|
||||
from: from.into(),
|
||||
to,
|
||||
name: if let AngledLineData::AngleWithTag { tag, .. } = data {
|
||||
tag.to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
name: tag.unwrap_or("".to_string()),
|
||||
geo_meta: GeoMeta {
|
||||
id,
|
||||
metadata: args.source_range.into(),
|
||||
@ -512,9 +391,10 @@ async fn inner_angled_line(
|
||||
|
||||
/// Draw an angled line of a given x length.
|
||||
pub async fn angled_line_of_x_length(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (AngledLineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (data, sketch_group, tag): (AngledLineData, Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_angled_line_of_x_length(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_angled_line_of_x_length(data, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -526,8 +406,7 @@ pub async fn angled_line_of_x_length(args: Args) -> Result<MemoryItem, KclError>
|
||||
/// |> angledLineOfXLength({
|
||||
/// angle: 45,
|
||||
/// length: 10,
|
||||
/// tag: "edge1"
|
||||
/// }, %)
|
||||
/// }, %, "edge1")
|
||||
/// |> line([10, 10], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> close(%, "edge2")
|
||||
@ -539,16 +418,17 @@ pub async fn angled_line_of_x_length(args: Args) -> Result<MemoryItem, KclError>
|
||||
async fn inner_angled_line_of_x_length(
|
||||
data: AngledLineData,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let (angle, length) = match &data {
|
||||
AngledLineData::AngleWithTag { angle, length, .. } => (*angle, *length),
|
||||
AngledLineData::AngleAndLength(angle_and_length) => (angle_and_length[0], angle_and_length[1]),
|
||||
let (angle, length) = match data {
|
||||
AngledLineData::AngleAndLengthNamed { angle, length } => (angle, length),
|
||||
AngledLineData::AngleAndLengthPair(pair) => (pair[0], pair[1]),
|
||||
};
|
||||
|
||||
let to = get_y_component(Angle::from_degrees(angle), length);
|
||||
|
||||
let new_sketch_group = inner_line(data.into_inner_line(to.into()), sketch_group, args).await?;
|
||||
let new_sketch_group = inner_line(to.into(), sketch_group, tag, args).await?;
|
||||
|
||||
Ok(new_sketch_group)
|
||||
}
|
||||
@ -556,36 +436,20 @@ async fn inner_angled_line_of_x_length(
|
||||
/// Data to draw an angled line to a point.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase", untagged)]
|
||||
pub enum AngledLineToData {
|
||||
/// An angle and point with a tag.
|
||||
AngleWithTag {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AngledLineToData {
|
||||
/// The angle of the line.
|
||||
angle: f64,
|
||||
/// The point to draw to.
|
||||
to: f64,
|
||||
/// The tag.
|
||||
tag: String,
|
||||
},
|
||||
/// An angle and point to draw to.
|
||||
AngleAndPoint([f64; 2]),
|
||||
}
|
||||
|
||||
impl AngledLineToData {
|
||||
pub fn into_inner_line(self, x_to: f64, y_to: f64) -> LineToData {
|
||||
if let AngledLineToData::AngleWithTag { tag, .. } = self {
|
||||
LineToData::PointWithTag { to: [x_to, y_to], tag }
|
||||
} else {
|
||||
LineToData::Point([x_to, y_to])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw an angled line to a given x coordinate.
|
||||
pub async fn angled_line_to_x(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (AngledLineToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (data, sketch_group, tag): (AngledLineToData, Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_angled_line_to_x(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_angled_line_to_x(data, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -597,8 +461,7 @@ pub async fn angled_line_to_x(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// |> angledLineToX({
|
||||
/// angle: 45,
|
||||
/// to: 10,
|
||||
/// tag: "edge1"
|
||||
/// }, %)
|
||||
/// }, %, "edge1")
|
||||
/// |> line([10, 10], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> close(%, "edge2")
|
||||
@ -611,27 +474,26 @@ pub async fn angled_line_to_x(args: Args) -> Result<MemoryItem, KclError> {
|
||||
async fn inner_angled_line_to_x(
|
||||
data: AngledLineToData,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let from = sketch_group.get_coords_from_paths()?;
|
||||
let (angle, x_to) = match &data {
|
||||
AngledLineToData::AngleWithTag { angle, to, .. } => (*angle, *to),
|
||||
AngledLineToData::AngleAndPoint(angle_and_to) => (angle_and_to[0], angle_and_to[1]),
|
||||
};
|
||||
let AngledLineToData { angle, to: x_to } = data;
|
||||
|
||||
let x_component = x_to - from.x;
|
||||
let y_component = x_component * f64::tan(angle.to_radians());
|
||||
let y_to = from.y + y_component;
|
||||
|
||||
let new_sketch_group = inner_line_to(data.into_inner_line(x_to, y_to), sketch_group, args).await?;
|
||||
let new_sketch_group = inner_line_to([x_to, y_to], sketch_group, tag, args).await?;
|
||||
Ok(new_sketch_group)
|
||||
}
|
||||
|
||||
/// Draw an angled line of a given y length.
|
||||
pub async fn angled_line_of_y_length(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (AngledLineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (data, sketch_group, tag): (AngledLineData, Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_angled_line_of_y_length(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_angled_line_of_y_length(data, sketch_group, tag, args).await?;
|
||||
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
@ -644,8 +506,7 @@ pub async fn angled_line_of_y_length(args: Args) -> Result<MemoryItem, KclError>
|
||||
/// |> angledLineOfYLength({
|
||||
/// angle: 45,
|
||||
/// length: 10,
|
||||
/// tag: "edge1"
|
||||
/// }, %)
|
||||
/// }, %, "edge1")
|
||||
/// |> line([10, 10], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> close(%, "edge2")
|
||||
@ -658,25 +519,27 @@ pub async fn angled_line_of_y_length(args: Args) -> Result<MemoryItem, KclError>
|
||||
async fn inner_angled_line_of_y_length(
|
||||
data: AngledLineData,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let (angle, length) = match &data {
|
||||
AngledLineData::AngleWithTag { angle, length, .. } => (*angle, *length),
|
||||
AngledLineData::AngleAndLength(angle_and_length) => (angle_and_length[0], angle_and_length[1]),
|
||||
let (angle, length) = match data {
|
||||
AngledLineData::AngleAndLengthNamed { angle, length } => (angle, length),
|
||||
AngledLineData::AngleAndLengthPair(pair) => (pair[0], pair[1]),
|
||||
};
|
||||
|
||||
let to = get_x_component(Angle::from_degrees(angle), length);
|
||||
|
||||
let new_sketch_group = inner_line(data.into_inner_line(to.into()), sketch_group, args).await?;
|
||||
let new_sketch_group = inner_line(to.into(), sketch_group, tag, args).await?;
|
||||
|
||||
Ok(new_sketch_group)
|
||||
}
|
||||
|
||||
/// Draw an angled line to a given y coordinate.
|
||||
pub async fn angled_line_to_y(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (AngledLineToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (data, sketch_group, tag): (AngledLineToData, Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_angled_line_to_y(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_angled_line_to_y(data, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -688,8 +551,7 @@ pub async fn angled_line_to_y(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// |> angledLineToY({
|
||||
/// angle: 45,
|
||||
/// to: 10,
|
||||
/// tag: "edge1"
|
||||
/// }, %)
|
||||
/// }, %, "edge1")
|
||||
/// |> line([10, 10], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> close(%, "edge2")
|
||||
@ -701,19 +563,17 @@ pub async fn angled_line_to_y(args: Args) -> Result<MemoryItem, KclError> {
|
||||
async fn inner_angled_line_to_y(
|
||||
data: AngledLineToData,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let from = sketch_group.get_coords_from_paths()?;
|
||||
let (angle, y_to) = match &data {
|
||||
AngledLineToData::AngleWithTag { angle, to, .. } => (*angle, *to),
|
||||
AngledLineToData::AngleAndPoint(angle_and_to) => (angle_and_to[0], angle_and_to[1]),
|
||||
};
|
||||
let AngledLineToData { angle, to: y_to } = data;
|
||||
|
||||
let y_component = y_to - from.y;
|
||||
let x_component = y_component / f64::tan(angle.to_radians());
|
||||
let x_to = from.x + x_component;
|
||||
|
||||
let new_sketch_group = inner_line_to(data.into_inner_line(x_to, y_to), sketch_group, args).await?;
|
||||
let new_sketch_group = inner_line_to([x_to, y_to], sketch_group, tag, args).await?;
|
||||
Ok(new_sketch_group)
|
||||
}
|
||||
|
||||
@ -729,14 +589,13 @@ pub struct AngledLineThatIntersectsData {
|
||||
pub intersect_tag: String,
|
||||
/// The offset from the intersecting line.
|
||||
pub offset: Option<f64>,
|
||||
/// The tag.
|
||||
pub tag: Option<String>,
|
||||
}
|
||||
|
||||
/// Draw an angled line that intersects with a given line.
|
||||
pub async fn angled_line_that_intersects(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (AngledLineThatIntersectsData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let new_sketch_group = inner_angled_line_that_intersects(data, sketch_group, args).await?;
|
||||
let (data, sketch_group, tag): (AngledLineThatIntersectsData, Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
let new_sketch_group = inner_angled_line_that_intersects(data, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -745,14 +604,13 @@ pub async fn angled_line_that_intersects(args: Args) -> Result<MemoryItem, KclEr
|
||||
/// ```no_run
|
||||
/// const part001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> lineTo({to:[2, 2], tag: "yo"}, %)
|
||||
/// |> lineTo([2, 2], %, "yo")
|
||||
/// |> lineTo([3, 1], %)
|
||||
/// |> angledLineThatIntersects({
|
||||
/// angle: 180,
|
||||
/// intersectTag: 'yo',
|
||||
/// offset: 12,
|
||||
/// tag: "yo2"
|
||||
/// }, %)
|
||||
/// }, %, "yo2")
|
||||
/// |> line([4, 0], %)
|
||||
/// |> close(%, "yo3")
|
||||
/// |> extrude(10, %)
|
||||
@ -763,6 +621,7 @@ pub async fn angled_line_that_intersects(args: Args) -> Result<MemoryItem, KclEr
|
||||
async fn inner_angled_line_that_intersects(
|
||||
data: AngledLineThatIntersectsData,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let intersect_path = sketch_group
|
||||
@ -786,19 +645,13 @@ async fn inner_angled_line_that_intersects(
|
||||
from,
|
||||
);
|
||||
|
||||
let line_to_data = if let Some(tag) = data.tag {
|
||||
LineToData::PointWithTag { to: to.into(), tag }
|
||||
} else {
|
||||
LineToData::Point(to.into())
|
||||
};
|
||||
|
||||
let new_sketch_group = inner_line_to(line_to_data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_line_to(to.into(), sketch_group, tag, args).await?;
|
||||
Ok(new_sketch_group)
|
||||
}
|
||||
|
||||
/// Start a sketch at a given point.
|
||||
pub async fn start_sketch_at(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let data: LineData = args.get_data()?;
|
||||
let data: [f64; 2] = args.get_data()?;
|
||||
|
||||
let sketch_group = inner_start_sketch_at(data, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(sketch_group))
|
||||
@ -813,11 +666,11 @@ pub async fn start_sketch_at(args: Args) -> Result<MemoryItem, KclError> {
|
||||
#[stdlib {
|
||||
name = "startSketchAt",
|
||||
}]
|
||||
async fn inner_start_sketch_at(data: LineData, args: Args) -> Result<Box<SketchGroup>, KclError> {
|
||||
async fn inner_start_sketch_at(data: [f64; 2], args: Args) -> Result<Box<SketchGroup>, KclError> {
|
||||
// Let's assume it's the XY plane for now, this is just for backwards compatibility.
|
||||
let xy_plane = PlaneData::XY;
|
||||
let sketch_surface = inner_start_sketch_on(SketchData::Plane(xy_plane), None, args.clone()).await?;
|
||||
let sketch_group = inner_start_profile_at(data, sketch_surface, args).await?;
|
||||
let sketch_group = inner_start_profile_at(data, sketch_surface, None, args).await?;
|
||||
Ok(sketch_group)
|
||||
}
|
||||
|
||||
@ -959,7 +812,7 @@ pub async fn start_sketch_on(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// startSketchOn('XY')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 10], %)
|
||||
/// |> line({to: [20, 10], tag: "edge1"}, %)
|
||||
/// |> line([20, 10], %, "edge1")
|
||||
/// |> close(%, "edge2")
|
||||
/// ```
|
||||
///
|
||||
@ -981,7 +834,7 @@ pub async fn start_sketch_on(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// const part001 = startSketchOn(box, "start")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 10], %)
|
||||
/// |> line({to: [20, 10], tag: "edge1"}, %)
|
||||
/// |> line([20, 10], %, "edge1")
|
||||
/// |> close(%)
|
||||
/// |> extrude(20, %)
|
||||
/// ```
|
||||
@ -1204,9 +1057,9 @@ async fn start_sketch_on_plane(data: PlaneData, args: Args) -> Result<Box<Plane>
|
||||
|
||||
/// Start a profile at a given point.
|
||||
pub async fn start_profile_at(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_surface): (LineData, SketchSurface) = args.get_data_and_sketch_surface()?;
|
||||
let (start, sketch_surface, tag): ([f64; 2], SketchSurface, Option<String>) = args.get_data_and_sketch_surface()?;
|
||||
|
||||
let sketch_group = inner_start_profile_at(data, sketch_surface, args).await?;
|
||||
let sketch_group = inner_start_profile_at(start, sketch_surface, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(sketch_group))
|
||||
}
|
||||
|
||||
@ -1221,15 +1074,11 @@ pub async fn start_profile_at(args: Args) -> Result<MemoryItem, KclError> {
|
||||
name = "startProfileAt",
|
||||
}]
|
||||
pub(crate) async fn inner_start_profile_at(
|
||||
data: LineData,
|
||||
to: [f64; 2],
|
||||
sketch_surface: SketchSurface,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let to = match &data {
|
||||
LineData::PointWithTag { to, .. } => *to,
|
||||
LineData::Point(to) => *to,
|
||||
};
|
||||
|
||||
let id = uuid::Uuid::new_v4();
|
||||
let path_id = uuid::Uuid::new_v4();
|
||||
|
||||
@ -1250,11 +1099,7 @@ pub(crate) async fn inner_start_profile_at(
|
||||
let current_path = BasePath {
|
||||
from: to,
|
||||
to,
|
||||
name: if let LineData::PointWithTag { tag, .. } = data {
|
||||
tag.to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
name: tag.unwrap_or("".to_string()),
|
||||
geo_meta: GeoMeta {
|
||||
id,
|
||||
metadata: args.source_range.into(),
|
||||
@ -1360,9 +1205,6 @@ pub enum ArcData {
|
||||
angle_end: f64,
|
||||
/// The radius.
|
||||
radius: f64,
|
||||
/// The tag.
|
||||
#[serde(default)]
|
||||
tag: Option<String>,
|
||||
},
|
||||
/// Center, to and radius with an optional tag.
|
||||
CenterToRadius {
|
||||
@ -1372,17 +1214,15 @@ pub enum ArcData {
|
||||
to: [f64; 2],
|
||||
/// The radius.
|
||||
radius: f64,
|
||||
/// The tag.
|
||||
#[serde(default)]
|
||||
tag: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Draw an arc.
|
||||
pub async fn arc(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (ArcData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (data, sketch_group, tag): (ArcData, Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_arc(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_arc(data, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -1395,8 +1235,7 @@ pub async fn arc(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// angle_start: 0,
|
||||
/// angle_end: 360,
|
||||
/// radius: 10,
|
||||
/// tag: "edge1"
|
||||
/// }, %)
|
||||
/// }, %, "edge1")
|
||||
/// |> extrude(10, %)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
@ -1405,6 +1244,7 @@ pub async fn arc(args: Args) -> Result<MemoryItem, KclError> {
|
||||
pub(crate) async fn inner_arc(
|
||||
data: ArcData,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let from: Point2d = sketch_group.get_coords_from_paths()?;
|
||||
@ -1414,14 +1254,13 @@ pub(crate) async fn inner_arc(
|
||||
angle_start,
|
||||
angle_end,
|
||||
radius,
|
||||
..
|
||||
} => {
|
||||
let a_start = Angle::from_degrees(*angle_start);
|
||||
let a_end = Angle::from_degrees(*angle_end);
|
||||
let (center, end) = arc_center_and_end(from, a_start, a_end, *radius);
|
||||
(center, a_start, a_end, *radius, end)
|
||||
}
|
||||
ArcData::CenterToRadius { center, to, radius, .. } => {
|
||||
ArcData::CenterToRadius { center, to, radius } => {
|
||||
let (angle_start, angle_end) = arc_angles(from, center.into(), to.into(), *radius, args.source_range)?;
|
||||
(center.into(), angle_start, angle_end, *radius, to.into())
|
||||
}
|
||||
@ -1448,10 +1287,7 @@ pub(crate) async fn inner_arc(
|
||||
base: BasePath {
|
||||
from: from.into(),
|
||||
to: end.into(),
|
||||
name: match data {
|
||||
ArcData::AnglesAndRadius { tag, .. } => tag.unwrap_or_default().to_string(),
|
||||
ArcData::CenterToRadius { tag, .. } => tag.unwrap_or_default().to_string(),
|
||||
},
|
||||
name: tag.unwrap_or("".to_string()),
|
||||
geo_meta: GeoMeta {
|
||||
id,
|
||||
metadata: args.source_range.into(),
|
||||
@ -1477,22 +1313,16 @@ pub enum TangentialArcData {
|
||||
/// Offset of the arc, in degrees.
|
||||
offset: f64,
|
||||
},
|
||||
/// A point with a tag.
|
||||
PointWithTag {
|
||||
/// Where the arc should end. Must lie in the same plane as the current path pen position. Must not be colinear with current path pen position.
|
||||
to: [f64; 2],
|
||||
/// The tag.
|
||||
tag: String,
|
||||
},
|
||||
/// A point where the arc should end. Must lie in the same plane as the current path pen position. Must not be colinear with current path pen position.
|
||||
Point([f64; 2]),
|
||||
}
|
||||
|
||||
/// Draw a tangential arc.
|
||||
pub async fn tangential_arc(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (TangentialArcData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (data, sketch_group, tag): (TangentialArcData, Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_tangential_arc(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_tangential_arc(data, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -1501,12 +1331,11 @@ pub async fn tangential_arc(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// ```no_run
|
||||
/// startSketchOn('-YZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line({to: [10, 10], tag: "edge0"}, %)
|
||||
/// |> line([10, 10], %, "edge1")
|
||||
/// |> tangentialArc({
|
||||
/// radius: 10,
|
||||
/// offset: 90,
|
||||
/// tag: "edge1"
|
||||
/// }, %)
|
||||
/// }, %, "edge1")
|
||||
/// |> close(%)
|
||||
/// |> extrude(10, %)
|
||||
/// ```
|
||||
@ -1516,6 +1345,7 @@ pub async fn tangential_arc(args: Args) -> Result<MemoryItem, KclError> {
|
||||
async fn inner_tangential_arc(
|
||||
data: TangentialArcData,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let from: Point2d = sketch_group.get_coords_from_paths()?;
|
||||
@ -1545,11 +1375,6 @@ async fn inner_tangential_arc(
|
||||
.await?;
|
||||
to.into()
|
||||
}
|
||||
TangentialArcData::PointWithTag { to, .. } => {
|
||||
args.send_modeling_cmd(id, tan_arc_to(&sketch_group, to)).await?;
|
||||
|
||||
*to
|
||||
}
|
||||
TangentialArcData::Point(to) => {
|
||||
args.send_modeling_cmd(id, tan_arc_to(&sketch_group, to)).await?;
|
||||
|
||||
@ -1563,10 +1388,7 @@ async fn inner_tangential_arc(
|
||||
base: BasePath {
|
||||
from: from.into(),
|
||||
to,
|
||||
name: match data {
|
||||
TangentialArcData::PointWithTag { tag, .. } => tag.to_string(),
|
||||
TangentialArcData::Point(_) | TangentialArcData::RadiusAndOffset { .. } => "".to_string(),
|
||||
},
|
||||
name: tag.unwrap_or("".to_string()),
|
||||
geo_meta: GeoMeta {
|
||||
id,
|
||||
metadata: args.source_range.into(),
|
||||
@ -1628,7 +1450,7 @@ pub async fn tangential_arc_to(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// ```no_run
|
||||
/// startSketchOn('-YZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line({to: [10, 10], tag: "edge0"}, %)
|
||||
/// |> line([10, 10], %, "edge0")
|
||||
/// |> tangentialArcTo([10, 0], %)
|
||||
/// |> close(%)
|
||||
/// ```
|
||||
@ -1691,15 +1513,14 @@ pub struct BezierData {
|
||||
control1: [f64; 2],
|
||||
/// The second control point.
|
||||
control2: [f64; 2],
|
||||
/// The tag.
|
||||
tag: Option<String>,
|
||||
}
|
||||
|
||||
/// Draw a bezier curve.
|
||||
pub async fn bezier_curve(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (BezierData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (data, sketch_group, tag): (BezierData, Box<SketchGroup>, Option<String>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
let new_sketch_group = inner_bezier_curve(data, sketch_group, args).await?;
|
||||
let new_sketch_group = inner_bezier_curve(data, sketch_group, tag, args).await?;
|
||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||
}
|
||||
|
||||
@ -1712,8 +1533,7 @@ pub async fn bezier_curve(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// to: [10, 10],
|
||||
/// control1: [5, 0],
|
||||
/// control2: [5, 10],
|
||||
/// tag: "edge1"
|
||||
/// }, %)
|
||||
/// }, %, "edge1")
|
||||
/// |> close(%)
|
||||
/// |> extrude(10, %)
|
||||
/// ```
|
||||
@ -1723,6 +1543,7 @@ pub async fn bezier_curve(args: Args) -> Result<MemoryItem, KclError> {
|
||||
async fn inner_bezier_curve(
|
||||
data: BezierData,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
tag: Option<String>,
|
||||
args: Args,
|
||||
) -> Result<Box<SketchGroup>, KclError> {
|
||||
let from = sketch_group.get_coords_from_paths()?;
|
||||
@ -1763,7 +1584,7 @@ async fn inner_bezier_curve(
|
||||
base: BasePath {
|
||||
from: from.into(),
|
||||
to,
|
||||
name: data.tag.unwrap_or_default().to_string(),
|
||||
name: tag.unwrap_or_default().to_string(),
|
||||
geo_meta: GeoMeta {
|
||||
id,
|
||||
metadata: args.source_range.into(),
|
||||
@ -1863,28 +1684,7 @@ mod tests {
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::std::sketch::{LineData, PlaneData};
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_line_data() {
|
||||
let data = LineData::Point([0.0, 1.0]);
|
||||
let mut str_json = serde_json::to_string(&data).unwrap();
|
||||
assert_eq!(str_json, "[0.0,1.0]");
|
||||
|
||||
str_json = "[0, 1]".to_string();
|
||||
let data: LineData = serde_json::from_str(&str_json).unwrap();
|
||||
assert_eq!(data, LineData::Point([0.0, 1.0]));
|
||||
|
||||
str_json = "{ \"to\": [0.0, 1.0], \"tag\": \"thing\" }".to_string();
|
||||
let data: LineData = serde_json::from_str(&str_json).unwrap();
|
||||
assert_eq!(
|
||||
data,
|
||||
LineData::PointWithTag {
|
||||
to: [0.0, 1.0],
|
||||
tag: "thing".to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
use crate::std::sketch::PlaneData;
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_plane_data() {
|
||||
|
3
src/wasm-lib/prelude.kcl
Normal file
3
src/wasm-lib/prelude.kcl
Normal file
@ -0,0 +1,3 @@
|
||||
fn hey_from_one_of_the_devs_of_the_past_i_wish_you_a_great_day_and_maybe_gave_you_a_little_smile_as_youve_found_this = () => {
|
||||
return 42
|
||||
}
|
@ -87,7 +87,7 @@ async fn execute_and_snapshot(code: &str, units: kittycad::types::UnitLength) ->
|
||||
async fn serial_test_sketch_on_face() {
|
||||
let code = r#"const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([11.19, 28.35], %)
|
||||
|> line({to: [28.67, -13.25], tag: "here"}, %)
|
||||
|> line([28.67, -13.25], %, "here")
|
||||
|> line([-4.12, -22.81], %)
|
||||
|> line([-33.24, 14.55], %)
|
||||
|> close(%)
|
||||
@ -206,9 +206,9 @@ const part002 = startSketchOn(part001, "END")
|
||||
async fn serial_test_fillet_duplicate_tags() {
|
||||
let code = r#"const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0,0], %)
|
||||
|> line({to: [0, 10], tag: "thing"}, %)
|
||||
|> line([0, 10], %, "thing")
|
||||
|> line([10, 0], %)
|
||||
|> line({to: [0, -10], tag: "thing2"}, %)
|
||||
|> line([0, -10], %, "thing2")
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
|> fillet({radius: 0.5, tags: ["thing", "thing"]}, %)
|
||||
@ -218,7 +218,7 @@ async fn serial_test_fillet_duplicate_tags() {
|
||||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.err().unwrap().to_string(),
|
||||
r#"type: KclErrorDetails { source_ranges: [SourceRange([227, 277])], message: "Duplicate tags are not allowed." }"#,
|
||||
r#"type: KclErrorDetails { source_ranges: [SourceRange([205, 255])], message: "Duplicate tags are not allowed." }"#,
|
||||
);
|
||||
}
|
||||
|
||||
@ -226,9 +226,9 @@ async fn serial_test_fillet_duplicate_tags() {
|
||||
async fn serial_test_basic_fillet_cube_start() {
|
||||
let code = r#"const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0,0], %)
|
||||
|> line({to: [0, 10], tag: "thing"}, %)
|
||||
|> line([0, 10], %, "thing")
|
||||
|> line([10, 0], %)
|
||||
|> line({to: [0, -10], tag: "thing2"}, %)
|
||||
|> line([0, -10], %, "thing2")
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
|> fillet({radius: 2, tags: ["thing", "thing2"]}, %)
|
||||
@ -244,9 +244,9 @@ async fn serial_test_basic_fillet_cube_start() {
|
||||
async fn serial_test_basic_fillet_cube_end() {
|
||||
let code = r#"const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0,0], %)
|
||||
|> line({to: [0, 10], tag: "thing"}, %)
|
||||
|> line([0, 10], %, "thing")
|
||||
|> line([10, 0], %)
|
||||
|> line({to: [0, -10], tag: "thing2"}, %)
|
||||
|> line([0, -10], %, "thing2")
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
|> fillet({radius: 2, tags: ["thing", getOppositeEdge("thing", %)]}, %)
|
||||
@ -263,9 +263,9 @@ async fn serial_test_basic_fillet_cube_end() {
|
||||
async fn serial_test_basic_fillet_cube_close_opposite() {
|
||||
let code = r#"const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0,0], %)
|
||||
|> line({to: [0, 10], tag: "thing"}, %)
|
||||
|> line([0, 10], %, "thing")
|
||||
|> line([10, 0], %)
|
||||
|> line({to: [0, -10], tag: "thing2"}, %)
|
||||
|> line([0, -10], %, "thing2")
|
||||
|> close(%, "thing3")
|
||||
|> extrude(10, %)
|
||||
|> fillet({radius: 2, tags: ["thing3", getOppositeEdge("thing3", %)]}, %)
|
||||
@ -286,9 +286,9 @@ async fn serial_test_basic_fillet_cube_close_opposite() {
|
||||
async fn serial_test_basic_fillet_cube_next_adjacent() {
|
||||
let code = r#"const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0,0], %)
|
||||
|> line({to: [0, 10], tag: "thing"}, %)
|
||||
|> line({to: [10, 0], tag: "thing1"}, %)
|
||||
|> line({to: [0, -10], tag: "thing2"}, %)
|
||||
|> line([0, 10], %, "thing")
|
||||
|> line([10, 0], %, "thing1")
|
||||
|> line([0, -10], %, "thing2")
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
|> fillet({radius: 2, tags: [getNextAdjacentEdge("thing", %)]}, %)
|
||||
@ -308,9 +308,9 @@ async fn serial_test_basic_fillet_cube_next_adjacent() {
|
||||
async fn serial_test_basic_fillet_cube_previous_adjacent() {
|
||||
let code = r#"const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0,0], %)
|
||||
|> line({to: [0, 10], tag: "thing"}, %)
|
||||
|> line({to: [10, 0], tag: "thing1"}, %)
|
||||
|> line({to: [0, -10], tag: "thing2"}, %)
|
||||
|> line([0, 10], %, "thing")
|
||||
|> line([10, 0], %, "thing1")
|
||||
|> line([0, -10], %, "thing2")
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
|> fillet({radius: 2, tags: [getPreviousAdjacentEdge("thing2", %)]}, %)
|
||||
@ -380,7 +380,7 @@ async fn serial_test_execute_with_angled_line() {
|
||||
let code = r#"const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([4.83, 12.56], %)
|
||||
|> line([15.1, 2.48], %)
|
||||
|> line({ to: [3.15, -9.85], tag: 'seg01' }, %)
|
||||
|> line([3.15, -9.85], %, 'seg01')
|
||||
|> line([-15.17, -4.1], %)
|
||||
|> angledLine([segAng('seg01', %), 12.35], %)
|
||||
|> line([-13.02, 10.03], %)
|
||||
@ -1177,7 +1177,7 @@ async fn serial_test_error_sketch_on_arc_face() {
|
||||
let code = r#"fn cube = (pos, scale) => {
|
||||
const sg = startSketchOn('XY')
|
||||
|> startProfileAt(pos, %)
|
||||
|> tangentialArc({ to: [0, scale], tag: "here" }, %)
|
||||
|> tangentialArc([0, scale], %, "here")
|
||||
|> line([scale, 0], %)
|
||||
|> line([0, -scale], %)
|
||||
|
||||
@ -1201,7 +1201,7 @@ const part002 = startSketchOn(part001, "here")
|
||||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.err().unwrap().to_string(),
|
||||
r#"type: KclErrorDetails { source_ranges: [SourceRange([294, 324])], message: "Cannot sketch on a non-planar surface: `here`" }"#
|
||||
r#"type: KclErrorDetails { source_ranges: [SourceRange([281, 311])], message: "Cannot sketch on a non-planar surface: `here`" }"#
|
||||
);
|
||||
}
|
||||
|
||||
@ -1325,18 +1325,9 @@ async fn serial_test_stdlib_kcl_error_circle() {
|
||||
fn rectShape = (pos, w, l) => {
|
||||
const rr = startSketchOn('XY')
|
||||
|> startProfileAt([pos[0] - (w / 2), pos[1] - (l / 2)], %)
|
||||
|> lineTo({
|
||||
to: [pos[0] + w / 2, pos[1] - (l / 2)],
|
||||
tag: "edge1"
|
||||
}, %)
|
||||
|> lineTo({
|
||||
to: [pos[0] + w / 2, pos[1] + l / 2],
|
||||
tag: "edge2"
|
||||
}, %)
|
||||
|> lineTo({
|
||||
to: [pos[0] - (w / 2), pos[1] + l / 2],
|
||||
tag: "edge3"
|
||||
}, %)
|
||||
|> lineTo([pos[0] + w / 2, pos[1] - (l / 2)], %, "edge1")
|
||||
|> lineTo([pos[0] + w / 2, pos[1] + l / 2], %, "edge2")
|
||||
|> lineTo([pos[0] - (w / 2), pos[1] + l / 2], %, "edge3")
|
||||
|> close(%, "edge4")
|
||||
return rr
|
||||
}
|
||||
@ -1367,6 +1358,6 @@ const part = rectShape([0, 0], 20, 20)
|
||||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.err().unwrap().to_string(),
|
||||
r#"type: KclErrorDetails { source_ranges: [SourceRange([987, 1036])], message: "Expected a [number, number] as the first argument, found `[UserVal(UserVal { value: String(\"XY\"), meta: [Metadata { source_range: SourceRange([994, 998]) }] }), UserVal(UserVal { value: Array [Number(-6.0), Number(6)], meta: [Metadata { source_range: SourceRange([1000, 1023]) }] }), UserVal(UserVal { value: Number(1), meta: [Metadata { source_range: SourceRange([856, 857]) }] })]`" }"#
|
||||
r#"type: KclErrorDetails { source_ranges: [SourceRange([891, 940])], message: "Expected a [number, number] as the first argument, found `[UserVal(UserVal { value: String(\"XY\"), meta: [Metadata { source_range: SourceRange([898, 902]) }] }), UserVal(UserVal { value: Array [Number(-6.0), Number(6)], meta: [Metadata { source_range: SourceRange([904, 927]) }] }), UserVal(UserVal { value: Number(1), meta: [Metadata { source_range: SourceRange([760, 761]) }] })]`" }"#
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user