Compare commits
2 Commits
kurt-speed
...
franknoiro
Author | SHA1 | Date | |
---|---|---|---|
29070a9b04 | |||
e3861f9380 |
@ -1,6 +1,5 @@
|
||||
VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands
|
||||
VITE_KC_API_BASE_URL=https://api.dev.zoo.dev
|
||||
VITE_KC_SITE_BASE_URL=https://dev.zoo.dev
|
||||
VITE_KC_WASM_OVERRIDE_URL=""
|
||||
VITE_KC_SKIP_AUTH=false
|
||||
VITE_KC_CONNECTION_TIMEOUT_MS=5000
|
||||
|
@ -1,6 +1,5 @@
|
||||
VITE_KC_API_WS_MODELING_URL=wss://api.zoo.dev/ws/modeling/commands
|
||||
VITE_KC_API_BASE_URL=https://api.zoo.dev
|
||||
VITE_KC_SITE_BASE_URL=https://zoo.dev
|
||||
VITE_KC_WASM_OVERRIDE_URL=""
|
||||
VITE_KC_SKIP_AUTH=false
|
||||
VITE_KC_CONNECTION_TIMEOUT_MS=15000
|
||||
|
35
.github/workflows/playwright.yml
vendored
@ -14,31 +14,9 @@ permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
check-wasm-lib-changes:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
url: ${{ steps.set-output.outputs.url }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # Fetches all history for all branches and tags
|
||||
|
||||
- name: Check for changes in src/wasm-lib
|
||||
id: set-output
|
||||
run: |
|
||||
if git diff --quiet origin/main...HEAD -- src/wasm-lib; then
|
||||
echo "url=https://app.zoo.dev" >> $GITHUB_OUTPUT
|
||||
echo "No changes detected in src/wasm-lib"
|
||||
else
|
||||
echo "Changes detected in src/wasm-lib"
|
||||
echo "url=" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
|
||||
playwright-ubuntu:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
needs: check-wasm-lib-changes
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
@ -50,19 +28,13 @@ jobs:
|
||||
run: yarn
|
||||
- name: Install Playwright Browsers
|
||||
run: yarn playwright install --with-deps
|
||||
- name: Print WASM Lib Changes URL
|
||||
run: |
|
||||
echo "WASM Lib Changes URL: ${{ needs.check-wasm-lib-changes.outputs.url }}"
|
||||
- name: Setup Rust
|
||||
if: ${{ needs.check-wasm-lib-changes.outputs.url }} == ''
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
- name: Cache wasm
|
||||
if: ${{ needs.check-wasm-lib-changes.outputs.url }} == ''
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: './src/wasm-lib'
|
||||
- name: build wasm
|
||||
if: ${{ needs.check-wasm-lib-changes.outputs.url }} == ''
|
||||
run: yarn build:wasm
|
||||
- name: build web
|
||||
run: yarn build:local
|
||||
@ -72,7 +44,6 @@ jobs:
|
||||
CI: true
|
||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}
|
||||
WASM_OVERRIDE: ${{ steps.check-wasm-lib-changes.outputs.url }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
@ -108,7 +79,6 @@ jobs:
|
||||
env:
|
||||
CI: true
|
||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
WASM_OVERRIDE: ${{ steps.check-wasm-lib-changes.outputs.url }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
@ -119,7 +89,6 @@ jobs:
|
||||
playwright-macos:
|
||||
timeout-minutes: 60
|
||||
runs-on: macos-14
|
||||
needs: check-wasm-lib-changes
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
@ -131,15 +100,12 @@ jobs:
|
||||
- name: Install Playwright Browsers
|
||||
run: yarn playwright install --with-deps
|
||||
- name: Setup Rust
|
||||
if: needs.check-wasm-lib-changes.outputs.url == ''
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
- name: Cache wasm
|
||||
if: needs.check-wasm-lib-changes.outputs.url == ''
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: './src/wasm-lib'
|
||||
- name: build wasm
|
||||
if: needs.check-wasm-lib-changes.outputs.url == ''
|
||||
run: yarn build:wasm
|
||||
- name: build web
|
||||
run: yarn build:local
|
||||
@ -150,7 +116,6 @@ jobs:
|
||||
env:
|
||||
CI: true
|
||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
WASM_OVERRIDE: ${{ steps.check-wasm-lib-changes.outputs.url }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
|
@ -9,7 +9,7 @@ Extrudes by a given amount.
|
||||
|
||||
|
||||
```js
|
||||
extrude(length: number, sketch_group_set: SketchGroupSet) -> ExtrudeGroupSet
|
||||
extrude(length: number, sketch_group: SketchGroup) -> ExtrudeGroup
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -29,7 +29,7 @@ startSketchOn('XY')
|
||||
### Arguments
|
||||
|
||||
* `length`: `number` (REQUIRED)
|
||||
* `sketch_group_set`: `SketchGroupSet` - A sketch group or a group of sketch groups. (REQUIRED)
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The plane id or face id of the sketch group.
|
||||
@ -110,7 +110,6 @@ startSketchOn('XY')
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
type: "sketchGroup",
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
// The from point.
|
||||
@ -194,15 +193,12 @@ startSketchOn('XY')
|
||||
y: number,
|
||||
z: number,
|
||||
},
|
||||
} |
|
||||
{
|
||||
type: "sketchGroups",
|
||||
}
|
||||
```
|
||||
|
||||
### Returns
|
||||
|
||||
`ExtrudeGroupSet` - A extrude group or a group of extrude groups.
|
||||
`ExtrudeGroup` - An extrude group is a collection of extrude surfaces.
|
||||
```js
|
||||
{
|
||||
// The id of the extrusion end cap
|
||||
@ -282,7 +278,6 @@ startSketchOn('XY')
|
||||
}],
|
||||
// The id of the extrusion start cap
|
||||
startCapId: uuid,
|
||||
type: "extrudeGroup",
|
||||
// The extrude surfaces.
|
||||
value: [{
|
||||
// The face id for the extrude plane.
|
||||
@ -332,9 +327,6 @@ startSketchOn('XY')
|
||||
y: number,
|
||||
z: number,
|
||||
},
|
||||
} |
|
||||
{
|
||||
type: "extrudeGroups",
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -9,7 +9,7 @@ A linear pattern on a 2D sketch.
|
||||
|
||||
|
||||
```js
|
||||
patternLinear2d(data: LinearPattern2dData, sketch_group_set: SketchGroupSet) -> [SketchGroup]
|
||||
patternLinear2d(data: LinearPattern2dData, sketch_group: SketchGroup) -> [SketchGroup]
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -39,7 +39,7 @@ const part = startSketchOn('XY')
|
||||
repetitions: number,
|
||||
}
|
||||
```
|
||||
* `sketch_group_set`: `SketchGroupSet` - A sketch group or a group of sketch groups. (REQUIRED)
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The plane id or face id of the sketch group.
|
||||
@ -120,7 +120,6 @@ const part = startSketchOn('XY')
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
type: "sketchGroup",
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
// The from point.
|
||||
@ -204,9 +203,6 @@ const part = startSketchOn('XY')
|
||||
y: number,
|
||||
z: number,
|
||||
},
|
||||
} |
|
||||
{
|
||||
type: "sketchGroups",
|
||||
}
|
||||
```
|
||||
|
||||
|
7550
docs/kcl/std.json
@ -1035,7 +1035,6 @@ const part001 = startSketchOn('-XZ')
|
||||
})
|
||||
|
||||
test('Can add multiple sketches', async ({ page }) => {
|
||||
test.skip(process.platform === 'darwin', 'Can add multiple sketches')
|
||||
const u = getUtils(page)
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
const PUR = 400 / 37.5 //pixeltoUnitRatio
|
||||
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 45 KiB |
@ -7,7 +7,6 @@ export const TEST_SETTINGS = {
|
||||
theme: Themes.Dark,
|
||||
onboardingStatus: 'dismissed',
|
||||
projectDirectory: '',
|
||||
enableSSAO: false,
|
||||
},
|
||||
modeling: {
|
||||
defaultUnit: 'in',
|
||||
|
@ -6,7 +6,7 @@ import { PNG } from 'pngjs'
|
||||
|
||||
async function waitForPageLoad(page: Page) {
|
||||
// wait for 'Loading stream...' spinner
|
||||
await page.getByTestId('loading-stream').waitFor()
|
||||
// await page.getByTestId('loading-stream').waitFor()
|
||||
// wait for all spinners to be gone
|
||||
await page.getByTestId('loading').waitFor({ state: 'detached' })
|
||||
|
||||
|
@ -18,7 +18,7 @@ export default defineConfig({
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 3 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 2 : 1,
|
||||
workers: process.env.CI ? 1 : 1,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: 'html',
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
@ -72,7 +72,7 @@ export default defineConfig({
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
webServer: {
|
||||
command: 'VITE_KC_WASM_OVERRIDE_URL=$WASM_OVERRIDE yarn serve',
|
||||
command: 'yarn serve',
|
||||
// url: 'http://127.0.0.1:3000',
|
||||
reuseExistingServer: !process.env.CI,
|
||||
},
|
||||
|
36
src-tauri/Cargo.lock
generated
@ -1592,7 +1592,7 @@ version = "0.18.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"heck",
|
||||
"proc-macro-crate 2.0.2",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
@ -1735,12 +1735,6 @@ version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
@ -4328,7 +4322,7 @@ version = "0.24.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
@ -4417,7 +4411,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5fa6fb9ee296c0dc2df41a656ca7948546d061958115ddb0bcaae43ad0d17d2"
|
||||
dependencies = [
|
||||
"cfg-expr",
|
||||
"heck 0.4.1",
|
||||
"heck",
|
||||
"pkg-config",
|
||||
"toml 0.7.8",
|
||||
"version-compare",
|
||||
@ -4514,7 +4508,7 @@ dependencies = [
|
||||
"getrandom 0.2.14",
|
||||
"glob",
|
||||
"gtk",
|
||||
"heck 0.4.1",
|
||||
"heck",
|
||||
"http 1.1.0",
|
||||
"jni",
|
||||
"libc",
|
||||
@ -4549,15 +4543,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.0.0-beta.13"
|
||||
version = "2.0.0-beta.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abcf98a9b4527567c3e5ca9723431d121e001c2145651b3fa044d22b5e025a7e"
|
||||
checksum = "33de24aabe2b9c340d67005800cb6dd40aac5283126a42896fc8eec0b87cbe45"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
"dirs-next",
|
||||
"glob",
|
||||
"heck 0.5.0",
|
||||
"heck",
|
||||
"json-patch",
|
||||
"schemars",
|
||||
"semver",
|
||||
@ -4602,7 +4596,7 @@ version = "2.0.0-beta.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b096f63f2724a1280ae0f5a34d0731de18ca18305e2ef6e5e9a39bb2710e8a85"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
@ -4629,9 +4623,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-dialog"
|
||||
version = "2.0.0-beta.6"
|
||||
version = "2.0.0-beta.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87caf6f2b704b0d27b4c64ef1fdd1f6ef97e2f5293216e230ad1efe61de54131"
|
||||
checksum = "db4476c824a1488a52f4672d2b419a71fbf3dc97249013ef3c2c08fae2a23b71"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"log",
|
||||
@ -4666,9 +4660,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-http"
|
||||
version = "2.0.0-beta.6"
|
||||
version = "2.0.0-beta.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7c32962a2e2141b3bc034e5c04f363635965e59435794b6bdcf97a027f0925a"
|
||||
checksum = "f27b2c90ed5473e1c068f523927fa0024212bc3a3f3a47c2a9c0b10b4b2e3ee4"
|
||||
dependencies = [
|
||||
"data-url",
|
||||
"http 1.1.0",
|
||||
@ -4806,16 +4800,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.0.0-beta.13"
|
||||
version = "2.0.0-beta.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4709765385f035338ecc330f3fba753b8ee283c659c235da9768949cdb25469"
|
||||
checksum = "760ac613d7f0de95067bcbcbcea175fe1df88fc4ab59c7f0b2cc2d01dc16a199"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"cargo_metadata",
|
||||
"ctor",
|
||||
"dunce",
|
||||
"glob",
|
||||
"heck 0.5.0",
|
||||
"heck",
|
||||
"html5ever",
|
||||
"infer",
|
||||
"json-patch",
|
||||
|
@ -12,7 +12,7 @@ rust-version = "1.70"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.0.0-beta.13", features = [] }
|
||||
tauri-build = { version = "2.0.0-beta.12", features = [] }
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
@ -21,9 +21,9 @@ oauth2 = "4.4.2"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tauri = { version = "2.0.0-beta.15", features = [ "devtools", "unstable"] }
|
||||
tauri-plugin-dialog = { version = "2.0.0-beta.6" }
|
||||
tauri-plugin-dialog = { version = "2.0.0-beta.5" }
|
||||
tauri-plugin-fs = { version = "2.0.0-beta.6" }
|
||||
tauri-plugin-http = { version = "2.0.0-beta.6" }
|
||||
tauri-plugin-http = { version = "2.0.0-beta.5" }
|
||||
tauri-plugin-os = { version = "2.0.0-beta.2" }
|
||||
tauri-plugin-process = { version = "2.0.0-beta.2" }
|
||||
tauri-plugin-shell = { version = "2.0.0-beta.2" }
|
||||
|
@ -193,6 +193,35 @@ export const Toolbar = () => {
|
||||
Rectangle
|
||||
</ActionButton>
|
||||
</li>
|
||||
<li className="contents" key="circle-button">
|
||||
<ActionButton
|
||||
className={buttonClassName}
|
||||
Element="button"
|
||||
onClick={() =>
|
||||
state.matches('Sketch.Circle tool')
|
||||
? send('CancelSketch')
|
||||
: send('Equip circle tool')
|
||||
}
|
||||
aria-pressed={state.matches('Sketch.Circle tool')}
|
||||
icon={{
|
||||
icon: 'circle',
|
||||
iconClassName,
|
||||
bgClassName,
|
||||
}}
|
||||
disabled={
|
||||
(!state.can('Equip circle tool') &&
|
||||
!state.matches('Sketch.Circle tool')) ||
|
||||
disableAllButtons
|
||||
}
|
||||
title={
|
||||
state.can('Equip circle tool')
|
||||
? 'Circle'
|
||||
: 'Can only be used when a sketch is empty currently'
|
||||
}
|
||||
>
|
||||
Circle
|
||||
</ActionButton>
|
||||
</li>
|
||||
</>
|
||||
)}
|
||||
{state.matches('Sketch.SketchIdle') &&
|
||||
|
@ -97,6 +97,7 @@ import {
|
||||
getRectangleCallExpressions,
|
||||
updateRectangleSketch,
|
||||
} from 'lib/rectangleTool'
|
||||
import { circleAsCallExpressions, updateCircleSketch } from 'lib/circleTool'
|
||||
|
||||
type DraftSegment = 'line' | 'tangentialArcTo'
|
||||
|
||||
@ -580,7 +581,7 @@ export class SceneEntities {
|
||||
...this.mouseEnterLeaveCallbacks(),
|
||||
})
|
||||
}
|
||||
setupRectangleOriginListener = () => {
|
||||
setupOriginListener = (type: 'circle' | 'rectangle') => {
|
||||
sceneInfra.setCallbacks({
|
||||
onClick: (args) => {
|
||||
const twoD = args.intersectionPoint?.twoD
|
||||
@ -589,7 +590,7 @@ export class SceneEntities {
|
||||
return
|
||||
}
|
||||
sceneInfra.modelingSend({
|
||||
type: 'Add rectangle origin',
|
||||
type: `Add ${type} origin`,
|
||||
data: [twoD.x, twoD.y],
|
||||
})
|
||||
},
|
||||
@ -747,6 +748,154 @@ export class SceneEntities {
|
||||
},
|
||||
})
|
||||
}
|
||||
setupDraftCircle = async (
|
||||
sketchPathToNode: PathToNode,
|
||||
forward: [number, number, number],
|
||||
up: [number, number, number],
|
||||
sketchOrigin: [number, number, number],
|
||||
circleOrigin: [x: number, y: number]
|
||||
) => {
|
||||
let _ast = JSON.parse(JSON.stringify(kclManager.ast))
|
||||
|
||||
const variableDeclarationName =
|
||||
getNodeFromPath<VariableDeclaration>(
|
||||
_ast,
|
||||
sketchPathToNode || [],
|
||||
'VariableDeclaration'
|
||||
)?.node?.declarations?.[0]?.id?.name || ''
|
||||
|
||||
const tags: [string] = [findUniqueName(_ast, 'circle')]
|
||||
|
||||
const startSketchOn = getNodeFromPath<VariableDeclaration>(
|
||||
_ast,
|
||||
sketchPathToNode || [],
|
||||
'VariableDeclaration'
|
||||
)?.node?.declarations
|
||||
|
||||
const startSketchOnInit = startSketchOn?.[0]?.init
|
||||
startSketchOn[0].init = createPipeExpression([
|
||||
startSketchOnInit,
|
||||
...circleAsCallExpressions(circleOrigin, tags),
|
||||
])
|
||||
|
||||
_ast = parse(recast(_ast))
|
||||
|
||||
const { programMemoryOverride, truncatedAst } = await this.setupSketch({
|
||||
sketchPathToNode,
|
||||
forward,
|
||||
up,
|
||||
position: sketchOrigin,
|
||||
maybeModdedAst: _ast,
|
||||
draftExpressionsIndices: { start: 0, end: 1 },
|
||||
})
|
||||
|
||||
sceneInfra.setCallbacks({
|
||||
onMove: async (args) => {
|
||||
// Update the radius of the draft rectangle
|
||||
const pathToNodeTwo = JSON.parse(JSON.stringify(sketchPathToNode))
|
||||
pathToNodeTwo[1][0] = 0
|
||||
|
||||
const sketchInit = getNodeFromPath<VariableDeclaration>(
|
||||
truncatedAst,
|
||||
pathToNodeTwo || [],
|
||||
'VariableDeclaration'
|
||||
)?.node?.declarations?.[0]?.init
|
||||
|
||||
const x = (args.intersectionPoint.twoD.x || 0) - circleOrigin[0]
|
||||
const y = (args.intersectionPoint.twoD.y || 0) - circleOrigin[1]
|
||||
|
||||
if (sketchInit.type === 'PipeExpression') {
|
||||
updateCircleSketch(sketchInit, x, y, tags[0])
|
||||
}
|
||||
|
||||
const { programMemory } = await executeAst({
|
||||
ast: truncatedAst,
|
||||
useFakeExecutor: true,
|
||||
engineCommandManager: this.engineCommandManager,
|
||||
programMemoryOverride,
|
||||
})
|
||||
this.sceneProgramMemory = programMemory
|
||||
const sketchGroup = programMemory.root[
|
||||
variableDeclarationName
|
||||
] as SketchGroup
|
||||
const sgPaths = sketchGroup.value
|
||||
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
|
||||
|
||||
this.updateSegment(
|
||||
sketchGroup.start,
|
||||
0,
|
||||
0,
|
||||
_ast,
|
||||
orthoFactor,
|
||||
sketchGroup
|
||||
)
|
||||
sgPaths.forEach((seg, index) =>
|
||||
this.updateSegment(seg, index, 0, _ast, orthoFactor, sketchGroup)
|
||||
)
|
||||
},
|
||||
onClick: async (args) => {
|
||||
// Commit the circle to the full AST/code and return to sketch.idle
|
||||
const radiusPoint = args.intersectionPoint?.twoD
|
||||
if (!radiusPoint || args.mouseEvent.button !== 0) return
|
||||
|
||||
const x = roundOff((radiusPoint.x || 0) - circleOrigin[0])
|
||||
const y = roundOff((radiusPoint.y || 0) - circleOrigin[1])
|
||||
|
||||
const sketchInit = getNodeFromPath<VariableDeclaration>(
|
||||
_ast,
|
||||
sketchPathToNode || [],
|
||||
'VariableDeclaration'
|
||||
)?.node?.declarations?.[0]?.init
|
||||
|
||||
if (sketchInit.type === 'PipeExpression') {
|
||||
updateCircleSketch(sketchInit, x, y, tags[0])
|
||||
|
||||
_ast = parse(recast(_ast))
|
||||
|
||||
console.log('onClick', {
|
||||
sketchInit: sketchInit,
|
||||
_ast,
|
||||
x,
|
||||
y,
|
||||
truncatedAst,
|
||||
})
|
||||
|
||||
// Update the primary AST and unequip the rectangle tool
|
||||
await kclManager.executeAstMock(_ast)
|
||||
sceneInfra.modelingSend({ type: 'CancelSketch' })
|
||||
|
||||
const { programMemory } = await executeAst({
|
||||
ast: _ast,
|
||||
useFakeExecutor: true,
|
||||
engineCommandManager: this.engineCommandManager,
|
||||
programMemoryOverride,
|
||||
})
|
||||
|
||||
// Prepare to update the THREEjs scene
|
||||
this.sceneProgramMemory = programMemory
|
||||
const sketchGroup = programMemory.root[
|
||||
variableDeclarationName
|
||||
] as SketchGroup
|
||||
const sgPaths = sketchGroup.value
|
||||
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
|
||||
|
||||
// Update the starting segment of the THREEjs scene
|
||||
this.updateSegment(
|
||||
sketchGroup.start,
|
||||
0,
|
||||
0,
|
||||
_ast,
|
||||
orthoFactor,
|
||||
sketchGroup
|
||||
)
|
||||
// Update the rest of the segments of the THREEjs scene
|
||||
sgPaths.forEach((seg, index) =>
|
||||
this.updateSegment(seg, index, 0, _ast, orthoFactor, sketchGroup)
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
setupSketchIdleCallbacks = ({
|
||||
pathToNode,
|
||||
up,
|
||||
|
@ -3,12 +3,13 @@ import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||
import { useKclContext } from 'lang/KclProvider'
|
||||
import { CommandArgument } from 'lib/commandTypes'
|
||||
import {
|
||||
ResolvedSelectionType,
|
||||
canSubmitSelectionArg,
|
||||
getSelectionType,
|
||||
getSelectionTypeDisplayText,
|
||||
} from 'lib/selections'
|
||||
import { modelingMachine } from 'machines/modelingMachine'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useHotkeys } from 'react-hotkeys-hook'
|
||||
import { StateFrom } from 'xstate'
|
||||
|
||||
@ -29,13 +30,13 @@ function CommandBarSelectionInput({
|
||||
const { commandBarState, commandBarSend } = useCommandsContext()
|
||||
const [hasSubmitted, setHasSubmitted] = useState(false)
|
||||
const selection = useSelector(arg.machineActor, selectionSelector)
|
||||
const initSelectionsByType = useCallback(() => {
|
||||
const selectionRangeEnd = selection.codeBasedSelections[0]?.range[1]
|
||||
return !selectionRangeEnd || selectionRangeEnd === code.length
|
||||
const [selectionsByType, setSelectionsByType] = useState<
|
||||
'none' | ResolvedSelectionType[]
|
||||
>(
|
||||
selection.codeBasedSelections[0]?.range[1] === code.length
|
||||
? 'none'
|
||||
: getSelectionType(selection)
|
||||
}, [selection, code])
|
||||
const selectionsByType = initSelectionsByType()
|
||||
)
|
||||
const [canSubmitSelection, setCanSubmitSelection] = useState<boolean>(
|
||||
canSubmitSelectionArg(selectionsByType, arg)
|
||||
)
|
||||
@ -50,14 +51,17 @@ function CommandBarSelectionInput({
|
||||
inputRef.current?.focus()
|
||||
}, [selection, inputRef])
|
||||
|
||||
useEffect(() => {
|
||||
setSelectionsByType(
|
||||
selection.codeBasedSelections[0]?.range[1] === code.length
|
||||
? 'none'
|
||||
: getSelectionType(selection)
|
||||
)
|
||||
}, [selection])
|
||||
|
||||
// Fast-forward through this arg if it's marked as skippable
|
||||
// and we have a valid selection already
|
||||
useEffect(() => {
|
||||
console.log('selection input effect', {
|
||||
selectionsByType,
|
||||
canSubmitSelection,
|
||||
arg,
|
||||
})
|
||||
setCanSubmitSelection(canSubmitSelectionArg(selectionsByType, arg))
|
||||
const argValue = commandBarState.context.argumentsToSubmit[arg.name]
|
||||
if (canSubmitSelection && arg.skip && argValue === undefined) {
|
||||
|
@ -61,6 +61,16 @@ const CustomIconMap = {
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
circle: (
|
||||
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M10 2.5C9.01509 2.5 8.03982 2.69399 7.12988 3.0709C6.21994 3.44781 5.39314 4.00026 4.6967 4.6967C4.00026 5.39314 3.44782 6.21993 3.07091 7.12987C2.694 8.03981 2.5 9.01508 2.5 10C2.5 10.9849 2.69399 11.9602 3.0709 12.8701C3.44781 13.7801 4.00026 14.6069 4.6967 15.3033C5.39314 15.9997 6.21993 16.5522 7.12987 16.9291C8.03982 17.306 9.01509 17.5 10 17.5C10.9849 17.5 11.9602 17.306 12.8701 16.9291C13.7801 16.5522 14.6069 15.9997 15.3033 15.3033C15.9997 14.6069 16.5522 13.7801 16.9291 12.8701C17.306 11.9602 17.5 10.9849 17.5 10C17.5 9.01509 17.306 8.03982 16.9291 7.12988C16.5522 6.21993 15.9997 5.39314 15.3033 4.6967C14.6069 4.00026 13.7801 3.44781 12.8701 3.0709C11.9602 2.69399 10.9849 2.5 10 2.5ZM6.7472 2.14702C7.77847 1.71986 8.88377 1.5 10 1.5C11.1162 1.5 12.2215 1.71986 13.2528 2.14702C14.2841 2.57419 15.2211 3.20029 16.0104 3.98959C16.7997 4.77889 17.4258 5.71592 17.853 6.74719C18.2801 7.77846 18.5 8.88377 18.5 10C18.5 11.1162 18.2801 12.2215 17.853 13.2528C17.4258 14.2841 16.7997 15.2211 16.0104 16.0104C15.2211 16.7997 14.2841 17.4258 13.2528 17.853C12.2215 18.2801 11.1162 18.5 10 18.5C8.88376 18.5 7.77846 18.2801 6.74719 17.853C5.71592 17.4258 4.77889 16.7997 3.98959 16.0104C3.20029 15.2211 2.57419 14.2841 2.14702 13.2528C1.71986 12.2215 1.5 11.1162 1.5 10C1.5 8.88376 1.71986 7.77845 2.14703 6.74719C2.57419 5.71592 3.2003 4.77889 3.9896 3.98959C4.7789 3.20029 5.71593 2.57419 6.7472 2.14702Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
clipboardCheckmark: (
|
||||
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
|
@ -77,7 +77,7 @@ export const ModelingMachineProvider = ({
|
||||
auth,
|
||||
settings: {
|
||||
context: {
|
||||
app: { theme, enableSSAO },
|
||||
app: { theme },
|
||||
modeling: { defaultUnit, highlightEdges },
|
||||
},
|
||||
},
|
||||
@ -87,7 +87,6 @@ export const ModelingMachineProvider = ({
|
||||
useSetupEngineManager(streamRef, token, {
|
||||
theme: theme.current,
|
||||
highlightEdges: highlightEdges.current,
|
||||
enableSSAO: enableSSAO.current,
|
||||
})
|
||||
const { htmlRef } = useStore((s) => ({
|
||||
htmlRef: s.htmlRef,
|
||||
@ -268,12 +267,10 @@ export const ModelingMachineProvider = ({
|
||||
'has valid extrude selection': ({ selectionRanges }) => {
|
||||
// A user can begin extruding if they either have 1+ faces selected or nothing selected
|
||||
// TODO: I believe this guard only allows for extruding a single face at a time
|
||||
if (selectionRanges.codeBasedSelections.length < 1) return false
|
||||
const isPipe = isSketchPipe(selectionRanges)
|
||||
|
||||
if (
|
||||
selectionRanges.codeBasedSelections.length === 0 ||
|
||||
isSelectionLastLine(selectionRanges, codeManager.code)
|
||||
)
|
||||
if (isSelectionLastLine(selectionRanges, codeManager.code))
|
||||
return true
|
||||
if (!isPipe) return false
|
||||
|
||||
|
@ -7,12 +7,7 @@ import React, { createContext, useEffect } from 'react'
|
||||
import useStateMachineCommands from '../hooks/useStateMachineCommands'
|
||||
import { settingsMachine } from 'machines/settingsMachine'
|
||||
import { toast } from 'react-hot-toast'
|
||||
import {
|
||||
getThemeColorForEngine,
|
||||
getOppositeTheme,
|
||||
setThemeClass,
|
||||
Themes,
|
||||
} from 'lib/theme'
|
||||
import { getThemeColorForEngine, setThemeClass, Themes } from 'lib/theme'
|
||||
import decamelize from 'decamelize'
|
||||
import {
|
||||
AnyStateMachine,
|
||||
@ -104,9 +99,6 @@ export const SettingsAuthProviderBase = ({
|
||||
{
|
||||
context: loadedSettings,
|
||||
actions: {
|
||||
//TODO: batch all these and if that's difficult to do from tsx,
|
||||
// make it easy to do
|
||||
|
||||
setClientSideSceneUnits: (context, event) => {
|
||||
const newBaseUnit =
|
||||
event.type === 'set.modeling.defaultUnit'
|
||||
@ -123,16 +115,6 @@ export const SettingsAuthProviderBase = ({
|
||||
color: getThemeColorForEngine(context.app.theme.current),
|
||||
},
|
||||
})
|
||||
|
||||
const opposingTheme = getOppositeTheme(context.app.theme.current)
|
||||
engineCommandManager.sendSceneCommand({
|
||||
cmd_id: uuidv4(),
|
||||
type: 'modeling_cmd_req',
|
||||
cmd: {
|
||||
type: 'set_default_system_properties',
|
||||
color: getThemeColorForEngine(opposingTheme),
|
||||
},
|
||||
})
|
||||
},
|
||||
setEngineEdges: (context) => {
|
||||
engineCommandManager.sendSceneCommand({
|
||||
|
@ -7,7 +7,5 @@ export const VITE_KC_API_BASE_URL = import.meta.env.VITE_KC_API_BASE_URL
|
||||
export const VITE_KC_SITE_BASE_URL = import.meta.env.VITE_KC_SITE_BASE_URL
|
||||
export const VITE_KC_CONNECTION_TIMEOUT_MS = import.meta.env
|
||||
.VITE_KC_CONNECTION_TIMEOUT_MS
|
||||
export const VITE_KC_WASM_OVERRIDE_URL = import.meta.env
|
||||
.VITE_KC_WASM_OVERRIDE_URL
|
||||
export const TEST = import.meta.env.TEST
|
||||
export const DEV = import.meta.env.DEV
|
||||
|
@ -11,11 +11,9 @@ export function useSetupEngineManager(
|
||||
settings = {
|
||||
theme: Themes.System,
|
||||
highlightEdges: true,
|
||||
enableSSAO: true,
|
||||
} as {
|
||||
theme: Themes
|
||||
highlightEdges: boolean
|
||||
enableSSAO: boolean
|
||||
}
|
||||
) {
|
||||
const {
|
||||
|
@ -4,7 +4,7 @@ import { Models } from '@kittycad/lib'
|
||||
import { exportSave } from 'lib/exportSave'
|
||||
import { uuidv4 } from 'lib/utils'
|
||||
import { getNodePathFromSourceRange } from 'lang/queryAst'
|
||||
import { Themes, getThemeColorForEngine, getOppositeTheme } from 'lib/theme'
|
||||
import { Themes, getThemeColorForEngine } from 'lib/theme'
|
||||
import { DefaultPlanes } from 'wasm-lib/kcl/bindings/DefaultPlanes'
|
||||
|
||||
let lastMessage = ''
|
||||
@ -941,7 +941,6 @@ export class EngineCommandManager {
|
||||
settings = {
|
||||
theme: Themes.Dark,
|
||||
highlightEdges: true,
|
||||
enableSSAO: true,
|
||||
},
|
||||
}: {
|
||||
setMediaStream: (stream: MediaStream) => void
|
||||
@ -954,7 +953,6 @@ export class EngineCommandManager {
|
||||
settings?: {
|
||||
theme: Themes
|
||||
highlightEdges: boolean
|
||||
enableSSAO: boolean
|
||||
}
|
||||
}) {
|
||||
this.makeDefaultPlanes = makeDefaultPlanes
|
||||
@ -971,8 +969,7 @@ export class EngineCommandManager {
|
||||
return
|
||||
}
|
||||
|
||||
const additionalSettings = settings.enableSSAO ? '&post_effect=ssao' : ''
|
||||
const url = `${VITE_KC_API_WS_MODELING_URL}?video_res_width=${width}&video_res_height=${height}${additionalSettings}`
|
||||
const url = `${VITE_KC_API_WS_MODELING_URL}?video_res_width=${width}&video_res_height=${height}`
|
||||
this.engineConnection = new EngineConnection({
|
||||
engineCommandManager: this,
|
||||
url,
|
||||
@ -992,18 +989,6 @@ export class EngineCommandManager {
|
||||
color: getThemeColorForEngine(settings.theme),
|
||||
},
|
||||
})
|
||||
|
||||
// Sets the default line colors
|
||||
const opposingTheme = getOppositeTheme(settings.theme)
|
||||
this.sendSceneCommand({
|
||||
cmd_id: uuidv4(),
|
||||
type: 'modeling_cmd_req',
|
||||
cmd: {
|
||||
type: 'set_default_system_properties',
|
||||
color: getThemeColorForEngine(opposingTheme),
|
||||
},
|
||||
})
|
||||
|
||||
// Set the edge lines visibility
|
||||
this.sendSceneCommand({
|
||||
type: 'modeling_cmd_req',
|
||||
@ -1341,17 +1326,6 @@ export class EngineCommandManager {
|
||||
this.lastArtifactMap = this.artifactMap
|
||||
this.artifactMap = {}
|
||||
await this.initPlanes()
|
||||
await this.sendSceneCommand({
|
||||
type: 'modeling_cmd_req',
|
||||
cmd_id: uuidv4(),
|
||||
cmd: {
|
||||
type: 'make_axes_gizmo',
|
||||
clobber: false,
|
||||
// If true, axes gizmo will be placed in the corner of the screen.
|
||||
// If false, it will be placed at the origin of the scene.
|
||||
gizmo_mode: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
subscribeTo<T extends ModelTypes>({
|
||||
event,
|
||||
|
@ -25,7 +25,7 @@ import { AppInfo } from 'wasm-lib/kcl/bindings/AppInfo'
|
||||
import { CoreDumpManager } from 'lib/coredump'
|
||||
import openWindow from 'lib/openWindow'
|
||||
import { DefaultPlanes } from 'wasm-lib/kcl/bindings/DefaultPlanes'
|
||||
import { TEST, VITE_KC_WASM_OVERRIDE_URL } from 'env'
|
||||
import { TEST } from 'env'
|
||||
|
||||
export type { Program } from '../wasm-lib/kcl/bindings/Program'
|
||||
export type { Value } from '../wasm-lib/kcl/bindings/Value'
|
||||
@ -76,19 +76,18 @@ export type { MemoryItem } from '../wasm-lib/kcl/bindings/MemoryItem'
|
||||
export type { ExtrudeSurface } from '../wasm-lib/kcl/bindings/ExtrudeSurface'
|
||||
|
||||
export const wasmUrl = () => {
|
||||
const baseUrl = VITE_KC_WASM_OVERRIDE_URL
|
||||
? VITE_KC_WASM_OVERRIDE_URL
|
||||
: typeof window === 'undefined'
|
||||
? 'http://127.0.0.1:3000'
|
||||
: window.location.origin.includes('tauri://localhost')
|
||||
? 'tauri://localhost' // custom protocol for macOS
|
||||
: window.location.origin.includes('tauri.localhost')
|
||||
? 'http://tauri.localhost' // fallback for Windows
|
||||
: window.location.origin.includes('localhost')
|
||||
? 'http://localhost:3000'
|
||||
: window.location.origin && window.location.origin !== 'null'
|
||||
? window.location.origin
|
||||
: 'http://localhost:3000'
|
||||
const baseUrl =
|
||||
typeof window === 'undefined'
|
||||
? 'http://127.0.0.1:3000'
|
||||
: window.location.origin.includes('tauri://localhost')
|
||||
? 'tauri://localhost' // custom protocol for macOS
|
||||
: window.location.origin.includes('tauri.localhost')
|
||||
? 'http://tauri.localhost' // fallback for Windows
|
||||
: window.location.origin.includes('localhost')
|
||||
? 'http://localhost:3000'
|
||||
: window.location.origin && window.location.origin !== 'null'
|
||||
? window.location.origin
|
||||
: 'http://localhost:3000'
|
||||
const fullUrl = baseUrl + '/wasm_lib_bg.wasm'
|
||||
console.log(`Full URL for WASM: ${fullUrl}`)
|
||||
|
||||
|
59
src/lib/circleTool.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import {
|
||||
createArrayExpression,
|
||||
createBinaryExpression,
|
||||
createCallExpressionStdLib,
|
||||
createLiteral,
|
||||
createPipeSubstitution,
|
||||
} from 'lang/modifyAst'
|
||||
import { roundOff } from './utils'
|
||||
import {
|
||||
ArrayExpression,
|
||||
CallExpression,
|
||||
Literal,
|
||||
PipeExpression,
|
||||
} from 'lang/wasm'
|
||||
|
||||
/**
|
||||
* Returns AST expressions for this KCL code:
|
||||
* const yo = startSketchOn('XY')
|
||||
* |> circle([0, 0], 0, %)
|
||||
*/
|
||||
export const circleAsCallExpressions = (
|
||||
circleOrigin: [number, number],
|
||||
tags: [string]
|
||||
) => [
|
||||
createCallExpressionStdLib('circle', [
|
||||
createArrayExpression([
|
||||
createLiteral(roundOff(circleOrigin[0])),
|
||||
createLiteral(roundOff(circleOrigin[1])),
|
||||
]),
|
||||
createLiteral(10),
|
||||
createPipeSubstitution(),
|
||||
createLiteral(tags[0]),
|
||||
]),
|
||||
]
|
||||
|
||||
/**
|
||||
* Mutates the pipeExpression to update the circle sketch
|
||||
* @param pipeExpression
|
||||
* @param x
|
||||
* @param y
|
||||
* @param tag
|
||||
*/
|
||||
export function updateCircleSketch(
|
||||
pipeExpression: PipeExpression,
|
||||
x: number,
|
||||
y: number,
|
||||
tag: string
|
||||
) {
|
||||
const circle = pipeExpression.body[1] as CallExpression
|
||||
const origin = circle.arguments[0] as ArrayExpression
|
||||
const originX = (origin.elements[0] as Literal).value
|
||||
const originY = (origin.elements[1] as Literal).value
|
||||
|
||||
const radius = roundOff(
|
||||
Math.sqrt((x - Number(originX)) ** 2 + (y - Number(originY)) ** 2)
|
||||
)
|
||||
|
||||
;(circle.arguments[1] as Literal) = createLiteral(radius)
|
||||
}
|
@ -420,13 +420,7 @@ export function getSelectionTypeDisplayText(
|
||||
const selectionsByType = getSelectionType(selection)
|
||||
|
||||
return (selectionsByType as Exclude<typeof selectionsByType, 'none'>)
|
||||
.map(
|
||||
// Hack for showing "face" instead of "extrude-wall" in command bar text
|
||||
([type, count]) =>
|
||||
`${count} ${type.replace('extrude-wall', 'face')}${
|
||||
count > 1 ? 's' : ''
|
||||
}`
|
||||
)
|
||||
.map(([type, count]) => `${count} ${type}${count > 1 ? 's' : ''}`)
|
||||
.join(', ')
|
||||
}
|
||||
|
||||
|
@ -156,13 +156,6 @@ export function createSettings() {
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
enableSSAO: new Setting<boolean>({
|
||||
defaultValue: true,
|
||||
description:
|
||||
'Whether or not Screen Space Ambient Occlusion (SSAO) is enabled',
|
||||
validate: (v) => typeof v === 'boolean',
|
||||
hideOnPlatform: 'both', //for now
|
||||
}),
|
||||
onboardingStatus: new Setting<string>({
|
||||
defaultValue: '',
|
||||
validate: (v) => typeof v === 'string',
|
||||
|
@ -23,17 +23,6 @@ export function setThemeClass(theme: Themes) {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the resolved theme in use (Dark || Light)
|
||||
export function getResolvedTheme(theme: Themes) {
|
||||
return theme === Themes.System ? getSystemTheme() : theme
|
||||
}
|
||||
|
||||
// Returns the opposing theme
|
||||
export function getOppositeTheme(theme: Themes) {
|
||||
const resolvedTheme = getResolvedTheme(theme)
|
||||
return resolvedTheme === Themes.Dark ? Themes.Light : Themes.Dark
|
||||
}
|
||||
|
||||
/**
|
||||
* The engine takes RGBA values from 0-1
|
||||
* So we convert from the conventional 0-255 found in Figma
|
||||
@ -41,7 +30,7 @@ export function getOppositeTheme(theme: Themes) {
|
||||
* @returns { r: number, g: number, b: number, a: number }
|
||||
*/
|
||||
export function getThemeColorForEngine(theme: Themes) {
|
||||
const resolvedTheme = getResolvedTheme(theme)
|
||||
const resolvedTheme = theme === Themes.System ? getSystemTheme() : theme
|
||||
const dark = 28 / 255
|
||||
const light = 249 / 255
|
||||
return resolvedTheme === Themes.Dark
|
||||
|
@ -31,11 +31,9 @@ export function useCalculateKclExpression({
|
||||
newVariableInsertIndex: number
|
||||
setNewVariableName: (a: string) => void
|
||||
} {
|
||||
const { programMemory, code } = useKclContext()
|
||||
const { programMemory } = useKclContext()
|
||||
const { context } = useModelingContext()
|
||||
const selectionRange:
|
||||
| (typeof context.selectionRanges.codeBasedSelections)[number]['range']
|
||||
| undefined = context.selectionRanges.codeBasedSelections[0]?.range
|
||||
const selectionRange = context.selectionRanges.codeBasedSelections[0].range
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
const [availableVarInfo, setAvailableVarInfo] = useState<
|
||||
ReturnType<typeof findAllPreviousVariables>
|
||||
@ -69,7 +67,7 @@ export function useCalculateKclExpression({
|
||||
} else {
|
||||
setIsNewVariableNameUnique(true)
|
||||
}
|
||||
}, [programMemory, newVariableName])
|
||||
}, [newVariableName])
|
||||
|
||||
useEffect(() => {
|
||||
if (!programMemory || !selectionRange) return
|
||||
@ -83,8 +81,8 @@ export function useCalculateKclExpression({
|
||||
|
||||
useEffect(() => {
|
||||
const execAstAndSetResult = async () => {
|
||||
const _code = `const __result__ = ${value}`
|
||||
const ast = parse(_code)
|
||||
const code = `const __result__ = ${value}`
|
||||
const ast = parse(code)
|
||||
const _programMem: any = { root: {}, return: null }
|
||||
availableVarInfo.variables.forEach(({ key, value }) => {
|
||||
_programMem.root[key] = { type: 'userVal', value, __meta: [] }
|
||||
@ -113,7 +111,7 @@ export function useCalculateKclExpression({
|
||||
setCalcResult('NAN')
|
||||
setValueNode(null)
|
||||
})
|
||||
}, [value, availableVarInfo, code, kclManager.programMemory])
|
||||
}, [value, availableVarInfo])
|
||||
|
||||
return {
|
||||
valueNode,
|
||||
|
@ -6,10 +6,10 @@
|
||||
serial-integration = { max-threads = 4 }
|
||||
|
||||
[profile.default]
|
||||
slow-timeout = { period = "30s", terminate-after = 1 }
|
||||
slow-timeout = { period = "10s", terminate-after = 1 }
|
||||
|
||||
[profile.ci]
|
||||
slow-timeout = { period = "50s", terminate-after = 5 }
|
||||
slow-timeout = { period = "30s", terminate-after = 5 }
|
||||
|
||||
[[profile.default.overrides]]
|
||||
filter = "test(serial_test_)"
|
||||
|
6
src/wasm-lib/Cargo.lock
generated
@ -1854,7 +1854,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.1.50"
|
||||
version = "0.1.49"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx 0.5.1",
|
||||
@ -2004,9 +2004,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-modeling-cmds"
|
||||
version = "0.2.21"
|
||||
version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e326955e8f315590a1926c17ff6a6082d3013f472c881aba56d73bfa170cf5b3"
|
||||
checksum = "f93f7904109e445ab3dcfbaa4f0f4396d1df22c701075cdce4a7e491701796af"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
|
@ -65,7 +65,7 @@ kittycad = { version = "0.3.0", default-features = false, features = ["js", "req
|
||||
kittycad-execution-plan = "0.1.5"
|
||||
kittycad-execution-plan-macros = "0.1.9"
|
||||
kittycad-execution-plan-traits = "0.1.14"
|
||||
kittycad-modeling-cmds = "0.2.21"
|
||||
kittycad-modeling-cmds = "0.2.20"
|
||||
kittycad-modeling-session = "0.1.4"
|
||||
|
||||
[[test]]
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-lib"
|
||||
description = "KittyCAD Language implementation and tools"
|
||||
version = "0.1.50"
|
||||
version = "0.1.49"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -62,11 +62,7 @@ impl StdLibFnArg {
|
||||
}
|
||||
|
||||
pub fn get_autocomplete_snippet(&self, index: usize) -> Result<Option<(usize, String)>> {
|
||||
if self.type_ == "SketchGroup"
|
||||
|| self.type_ == "ExtrudeGroup"
|
||||
|| self.type_ == "SketchSurface"
|
||||
|| self.type_ == "SketchGroupSet"
|
||||
{
|
||||
if self.type_ == "SketchGroup" || self.type_ == "ExtrudeGroup" || self.type_ == "SketchSurface" {
|
||||
return Ok(Some((index, format!("${{{}:{}}}", index, "%"))));
|
||||
}
|
||||
get_autocomplete_snippet_from_schema(&self.schema.clone(), index)
|
||||
@ -323,12 +319,7 @@ pub fn get_type_string_from_schema(schema: &schemars::schema::Schema) -> Result<
|
||||
if let Some(format) = &o.format {
|
||||
if format == "uuid" {
|
||||
return Ok((Primitive::Uuid.to_string(), false));
|
||||
} else if format == "double"
|
||||
|| format == "uint"
|
||||
|| format == "int64"
|
||||
|| format == "uint32"
|
||||
|| format == "uint64"
|
||||
{
|
||||
} else if format == "double" || format == "uint" || format == "int64" || format == "uint32" {
|
||||
return Ok((Primitive::Number.to_string(), false));
|
||||
} else {
|
||||
anyhow::bail!("unknown format: {}", format);
|
||||
@ -465,12 +456,7 @@ pub fn get_autocomplete_snippet_from_schema(
|
||||
if let Some(format) = &o.format {
|
||||
if format == "uuid" {
|
||||
return Ok(Some((index, format!(r#"${{{}:"tag_or_edge_fn"}}"#, index))));
|
||||
} else if format == "double"
|
||||
|| format == "uint"
|
||||
|| format == "int64"
|
||||
|| format == "uint32"
|
||||
|| format == "uint64"
|
||||
{
|
||||
} else if format == "double" || format == "uint" || format == "int64" || format == "uint32" {
|
||||
return Ok(Some((index, format!(r#"${{{}:3.14}}"#, index))));
|
||||
} else {
|
||||
anyhow::bail!("unknown format: {}", format);
|
||||
@ -624,12 +610,7 @@ pub fn get_autocomplete_string_from_schema(schema: &schemars::schema::Schema) ->
|
||||
if let Some(format) = &o.format {
|
||||
if format == "uuid" {
|
||||
return Ok(Primitive::Uuid.to_string());
|
||||
} else if format == "double"
|
||||
|| format == "uint"
|
||||
|| format == "int64"
|
||||
|| format == "uint32"
|
||||
|| format == "uint64"
|
||||
{
|
||||
} else if format == "double" || format == "uint" || format == "int64" || format == "uint32" {
|
||||
return Ok(Primitive::Number.to_string());
|
||||
} else {
|
||||
anyhow::bail!("unknown format: {}", format);
|
||||
|
@ -191,15 +191,6 @@ pub enum SketchGroupSet {
|
||||
SketchGroups(Vec<Box<SketchGroup>>),
|
||||
}
|
||||
|
||||
/// A extrude group or a group of extrude groups.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
pub enum ExtrudeGroupSet {
|
||||
ExtrudeGroup(Box<ExtrudeGroup>),
|
||||
ExtrudeGroups(Vec<Box<ExtrudeGroup>>),
|
||||
}
|
||||
|
||||
/// Data for an imported geometry.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
|
@ -7,23 +7,17 @@ use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{
|
||||
ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, ExtrudeTransform, GeoMeta, MemoryItem, Path, SketchGroup,
|
||||
SketchGroupSet, SketchSurface,
|
||||
},
|
||||
executor::{ExtrudeGroup, ExtrudeSurface, ExtrudeTransform, GeoMeta, MemoryItem, Path, SketchGroup, SketchSurface},
|
||||
std::Args,
|
||||
};
|
||||
|
||||
/// Extrudes by a given amount.
|
||||
pub async fn extrude(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (length, sketch_group_set) = args.get_number_sketch_group_set()?;
|
||||
let (length, sketch_group) = args.get_number_sketch_group()?;
|
||||
|
||||
let result = inner_extrude(length, sketch_group_set, args).await?;
|
||||
let result = inner_extrude(length, sketch_group, args).await?;
|
||||
|
||||
match result {
|
||||
ExtrudeGroupSet::ExtrudeGroup(extrude_group) => Ok(MemoryItem::ExtrudeGroup(extrude_group)),
|
||||
ExtrudeGroupSet::ExtrudeGroups(extrude_groups) => Ok(MemoryItem::ExtrudeGroups { value: extrude_groups }),
|
||||
}
|
||||
Ok(MemoryItem::ExtrudeGroup(result))
|
||||
}
|
||||
|
||||
/// Extrudes by a given amount.
|
||||
@ -40,33 +34,21 @@ pub async fn extrude(args: Args) -> Result<MemoryItem, KclError> {
|
||||
#[stdlib {
|
||||
name = "extrude"
|
||||
}]
|
||||
async fn inner_extrude(length: f64, sketch_group_set: SketchGroupSet, args: Args) -> Result<ExtrudeGroupSet, KclError> {
|
||||
async fn inner_extrude(length: f64, sketch_group: Box<SketchGroup>, args: Args) -> Result<Box<ExtrudeGroup>, KclError> {
|
||||
let id = uuid::Uuid::new_v4();
|
||||
|
||||
// Extrude the element(s).
|
||||
let sketch_groups = match sketch_group_set {
|
||||
SketchGroupSet::SketchGroup(sketch_group) => vec![sketch_group],
|
||||
SketchGroupSet::SketchGroups(sketch_groups) => sketch_groups,
|
||||
};
|
||||
let mut extrude_groups = Vec::new();
|
||||
for sketch_group in sketch_groups.iter() {
|
||||
args.send_modeling_cmd(
|
||||
id,
|
||||
kittycad::types::ModelingCmd::Extrude {
|
||||
target: sketch_group.id,
|
||||
distance: length,
|
||||
cap: true,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
extrude_groups.push(do_post_extrude(sketch_group.clone(), length, id, args.clone()).await?);
|
||||
}
|
||||
// Extrude the element.
|
||||
args.send_modeling_cmd(
|
||||
id,
|
||||
kittycad::types::ModelingCmd::Extrude {
|
||||
target: sketch_group.id,
|
||||
distance: length,
|
||||
cap: true,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
if extrude_groups.len() == 1 {
|
||||
Ok(ExtrudeGroupSet::ExtrudeGroup(extrude_groups.pop().unwrap()))
|
||||
} else {
|
||||
Ok(ExtrudeGroupSet::ExtrudeGroups(extrude_groups))
|
||||
}
|
||||
do_post_extrude(sketch_group, length, id, args).await
|
||||
}
|
||||
|
||||
pub(crate) async fn do_post_extrude(
|
||||
|
@ -11,7 +11,6 @@ pub mod revolve;
|
||||
pub mod segment;
|
||||
pub mod shapes;
|
||||
pub mod sketch;
|
||||
pub mod types;
|
||||
pub mod utils;
|
||||
|
||||
use std::collections::HashMap;
|
||||
@ -629,49 +628,6 @@ impl Args {
|
||||
Ok((data, sketch_group))
|
||||
}
|
||||
|
||||
fn get_data_and_sketch_group_set<T: serde::de::DeserializeOwned>(&self) -> Result<(T, SketchGroupSet), 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_set = if let MemoryItem::SketchGroup(sg) = second_value {
|
||||
SketchGroupSet::SketchGroup(sg.clone())
|
||||
} else if let MemoryItem::SketchGroups { value } = second_value {
|
||||
SketchGroupSet::SketchGroups(value.clone())
|
||||
} else {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: format!(
|
||||
"Expected a SketchGroup or Vector of SketchGroups as the second argument, found `{:?}`",
|
||||
self.args
|
||||
),
|
||||
source_ranges: vec![self.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
Ok((data, sketch_set))
|
||||
}
|
||||
|
||||
fn get_data_and_sketch_group_and_tag<T: serde::de::DeserializeOwned>(
|
||||
&self,
|
||||
) -> Result<(T, Box<SketchGroup>, Option<String>), KclError> {
|
||||
@ -867,7 +823,7 @@ impl Args {
|
||||
Ok((segment_name, to_number, sketch_group))
|
||||
}
|
||||
|
||||
fn get_number_sketch_group_set(&self) -> Result<(f64, SketchGroupSet), KclError> {
|
||||
fn get_number_sketch_group(&self) -> Result<(f64, Box<SketchGroup>), KclError> {
|
||||
// Iterate over our args, the first argument should be a number.
|
||||
// The second argument should be a SketchGroup.
|
||||
let first_value = self
|
||||
@ -890,21 +846,16 @@ impl Args {
|
||||
})
|
||||
})?;
|
||||
|
||||
let sketch_set = if let MemoryItem::SketchGroup(sg) = second_value {
|
||||
SketchGroupSet::SketchGroup(sg.clone())
|
||||
} else if let MemoryItem::SketchGroups { value } = second_value {
|
||||
SketchGroupSet::SketchGroups(value.clone())
|
||||
let sketch_group = if let MemoryItem::SketchGroup(sg) = second_value {
|
||||
sg.clone()
|
||||
} else {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: format!(
|
||||
"Expected a SketchGroup or Vector of SketchGroups as the second argument, found `{:?}`",
|
||||
self.args
|
||||
),
|
||||
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
|
||||
source_ranges: vec![self.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
Ok((number, sketch_set))
|
||||
Ok((number, sketch_group))
|
||||
}
|
||||
|
||||
fn get_path_name_extrude_group(&self) -> Result<(String, Box<ExtrudeGroup>), KclError> {
|
||||
|
@ -8,8 +8,8 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{ExtrudeGroup, Geometries, Geometry, MemoryItem, SketchGroup, SketchGroupSet},
|
||||
std::{types::Uint, Args},
|
||||
executor::{ExtrudeGroup, Geometries, Geometry, MemoryItem, SketchGroup},
|
||||
std::Args,
|
||||
};
|
||||
|
||||
/// Data for a linear pattern on a 2D sketch.
|
||||
@ -20,7 +20,7 @@ pub struct LinearPattern2dData {
|
||||
/// The number of repetitions. Must be greater than 0.
|
||||
/// This excludes the original entity. For example, if `repetitions` is 1,
|
||||
/// the original entity will be copied once.
|
||||
pub repetitions: Uint,
|
||||
pub repetitions: u32,
|
||||
/// The distance between each repetition. This can also be referred to as spacing.
|
||||
pub distance: f64,
|
||||
/// The axis of the pattern. This is a 2D vector.
|
||||
@ -35,7 +35,7 @@ pub struct LinearPattern3dData {
|
||||
/// The number of repetitions. Must be greater than 0.
|
||||
/// This excludes the original entity. For example, if `repetitions` is 1,
|
||||
/// the original entity will be copied once.
|
||||
pub repetitions: Uint,
|
||||
pub repetitions: u32,
|
||||
/// The distance between each repetition. This can also be referred to as spacing.
|
||||
pub distance: f64,
|
||||
/// The axis of the pattern.
|
||||
@ -57,8 +57,8 @@ impl LinearPattern {
|
||||
|
||||
pub fn repetitions(&self) -> u32 {
|
||||
match self {
|
||||
LinearPattern::TwoD(lp) => lp.repetitions.u32(),
|
||||
LinearPattern::ThreeD(lp) => lp.repetitions.u32(),
|
||||
LinearPattern::TwoD(lp) => lp.repetitions,
|
||||
LinearPattern::ThreeD(lp) => lp.repetitions,
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ impl LinearPattern {
|
||||
|
||||
/// A linear pattern on a 2D sketch.
|
||||
pub async fn pattern_linear_2d(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group_set): (LinearPattern2dData, SketchGroupSet) = args.get_data_and_sketch_group_set()?;
|
||||
let (data, sketch_group): (LinearPattern2dData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
|
||||
if data.axis == [0.0, 0.0] {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
@ -83,7 +83,7 @@ pub async fn pattern_linear_2d(args: Args) -> Result<MemoryItem, KclError> {
|
||||
}));
|
||||
}
|
||||
|
||||
let sketch_groups = inner_pattern_linear_2d(data, sketch_group_set, args).await?;
|
||||
let sketch_groups = inner_pattern_linear_2d(data, sketch_group, args).await?;
|
||||
Ok(MemoryItem::SketchGroups { value: sketch_groups })
|
||||
}
|
||||
|
||||
@ -99,33 +99,23 @@ pub async fn pattern_linear_2d(args: Args) -> Result<MemoryItem, KclError> {
|
||||
}]
|
||||
async fn inner_pattern_linear_2d(
|
||||
data: LinearPattern2dData,
|
||||
sketch_group_set: SketchGroupSet,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
args: Args,
|
||||
) -> Result<Vec<Box<SketchGroup>>, KclError> {
|
||||
let starting_sketch_groups = match sketch_group_set {
|
||||
SketchGroupSet::SketchGroup(sketch_group) => vec![sketch_group],
|
||||
SketchGroupSet::SketchGroups(sketch_groups) => sketch_groups,
|
||||
let geometries = pattern_linear(
|
||||
LinearPattern::TwoD(data),
|
||||
Geometry::SketchGroup(sketch_group),
|
||||
args.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let Geometries::SketchGroups(sketch_groups) = geometries else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected a vec of sketch groups".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
let mut sketch_groups = Vec::new();
|
||||
for sketch_group in starting_sketch_groups.iter() {
|
||||
let geometries = pattern_linear(
|
||||
LinearPattern::TwoD(data.clone()),
|
||||
Geometry::SketchGroup(sketch_group.clone()),
|
||||
args.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let Geometries::SketchGroups(new_sketch_groups) = geometries else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected a vec of sketch groups".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
sketch_groups.extend(new_sketch_groups);
|
||||
}
|
||||
|
||||
Ok(sketch_groups)
|
||||
}
|
||||
|
||||
@ -185,19 +175,6 @@ async fn inner_pattern_linear_3d(
|
||||
|
||||
async fn pattern_linear(data: LinearPattern, geometry: Geometry, args: Args) -> Result<Geometries, KclError> {
|
||||
let id = uuid::Uuid::new_v4();
|
||||
println!(
|
||||
"id: {:#?}",
|
||||
ModelingCmd::EntityLinearPattern {
|
||||
axis: kittycad::types::Point3D {
|
||||
x: data.axis()[0],
|
||||
y: data.axis()[1],
|
||||
z: data.axis()[2],
|
||||
},
|
||||
entity_id: geometry.id(),
|
||||
num_repetitions: data.repetitions(),
|
||||
spacing: data.distance(),
|
||||
}
|
||||
);
|
||||
|
||||
let resp = args
|
||||
.send_modeling_cmd(
|
||||
@ -257,7 +234,7 @@ pub struct CircularPattern2dData {
|
||||
/// The number of repetitions. Must be greater than 0.
|
||||
/// This excludes the original entity. For example, if `repetitions` is 1,
|
||||
/// the original entity will be copied once.
|
||||
pub repetitions: Uint,
|
||||
pub repetitions: u32,
|
||||
/// The center about which to make the pattern. This is a 2D vector.
|
||||
pub center: [f64; 2],
|
||||
/// The arc angle (in degrees) to place the repetitions. Must be greater than 0.
|
||||
@ -274,7 +251,7 @@ pub struct CircularPattern3dData {
|
||||
/// The number of repetitions. Must be greater than 0.
|
||||
/// This excludes the original entity. For example, if `repetitions` is 1,
|
||||
/// the original entity will be copied once.
|
||||
pub repetitions: Uint,
|
||||
pub repetitions: u32,
|
||||
/// The axis around which to make the pattern. This is a 3D vector.
|
||||
pub axis: [f64; 3],
|
||||
/// The center about which to make the pattern. This is a 3D vector.
|
||||
@ -307,8 +284,8 @@ impl CircularPattern {
|
||||
|
||||
pub fn repetitions(&self) -> u32 {
|
||||
match self {
|
||||
CircularPattern::TwoD(lp) => lp.repetitions.u32(),
|
||||
CircularPattern::ThreeD(lp) => lp.repetitions.u32(),
|
||||
CircularPattern::TwoD(lp) => lp.repetitions,
|
||||
CircularPattern::ThreeD(lp) => lp.repetitions,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
//! Custom types for various standard library types.
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A Uint that allows us to do math but rounds to a uint.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize, ts_rs::TS)]
|
||||
#[ts(export)]
|
||||
pub struct Uint(f64);
|
||||
|
||||
impl Uint {
|
||||
pub fn new(value: f64) -> Self {
|
||||
if value < 0.0 {
|
||||
panic!("Uint cannot be negative");
|
||||
}
|
||||
Self(value)
|
||||
}
|
||||
|
||||
pub fn value(&self) -> f64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn u32(&self) -> u32 {
|
||||
self.0.round() as u32
|
||||
}
|
||||
|
||||
pub fn u64(&self) -> u64 {
|
||||
self.0.round() as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl JsonSchema for Uint {
|
||||
fn schema_name() -> String {
|
||||
"Uint".to_string()
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||
gen.subschema_for::<u32>()
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
// Lego Brick
|
||||
|
||||
const lbumps = 10 // number of bumps long
|
||||
const wbumps = 6 // number of bumps wide
|
||||
|
||||
const pitch = 8.0
|
||||
const clearance = 0.1
|
||||
const bumpDiam = 4.8
|
||||
const bumpHeight = 1.8
|
||||
const height = 3.2
|
||||
|
||||
|
||||
const t = (pitch - (2 * clearance) - bumpDiam) / 2.0
|
||||
const postDiam = pitch - t // works out to 6.5
|
||||
const total_length = lbumps * pitch - (2.0 * clearance)
|
||||
const total_width = wbumps * pitch - (2.0 * clearance)
|
||||
|
||||
const lSegments = total_length / (lbumps + 1)
|
||||
const wSegments = total_width / (wbumps + 1)
|
||||
|
||||
// make the base
|
||||
const s = startSketchOn('XY')
|
||||
|> startProfileAt([-total_width / 2, -total_length / 2], %)
|
||||
|> line([total_width, 0], %)
|
||||
|> line([0, total_length], %)
|
||||
|> line([-total_width, 0], %)
|
||||
|> close(%)
|
||||
|> extrude(height, %)
|
||||
|
||||
const shellExtrude = startSketchOn(s, "start")
|
||||
|> startProfileAt([
|
||||
-(total_width / 2 - t),
|
||||
-(total_length / 2 - t)
|
||||
], %)
|
||||
|> line([total_width - (2 * t), 0], %)
|
||||
|> line([0, total_length - (2 * t)], %)
|
||||
|> line([-(total_width - (2 * t)), 0], %)
|
||||
|> close(%)
|
||||
|> extrude(-(height - t), %)
|
||||
|
||||
const peg = startSketchOn(s, "end")
|
||||
|> circle([
|
||||
-(total_width / 2 - wSegments),
|
||||
-(total_length / 2 - lSegments)
|
||||
], bumpDiam / 2, %)
|
||||
|> patternLinear2d({
|
||||
axis: [1, 0],
|
||||
repetitions: 5,
|
||||
distance: 7
|
||||
}, %)
|
||||
|> patternLinear2d({
|
||||
axis: [0, 1],
|
||||
repetitions: 9,
|
||||
distance: 7
|
||||
}, %)
|
||||
|> extrude(bumpHeight, %)
|
@ -115,15 +115,6 @@ async fn serial_test_riddle_small() {
|
||||
twenty_twenty::assert_image("tests/executor/outputs/riddle_small.png", &result, 0.999);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_lego() {
|
||||
let code = include_str!("inputs/lego.kcl");
|
||||
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||
.await
|
||||
.unwrap();
|
||||
twenty_twenty::assert_image("tests/executor/outputs/lego.png", &result, 0.999);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_pentagon_fillet_desugar() {
|
||||
let code = include_str!("inputs/pentagon_fillet_desugar.kcl");
|
||||
@ -939,32 +930,11 @@ async fn serial_test_top_level_expression() {
|
||||
twenty_twenty::assert_image("tests/executor/outputs/top_level_expression.png", &result, 0.999);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_patterns_linear_basic_with_math() {
|
||||
let code = r#"const num = 12
|
||||
const distance = 5
|
||||
const part = startSketchOn('XY')
|
||||
|> circle([0,0], 2, %)
|
||||
|> patternLinear2d({axis: [0,1], repetitions: num -1, distance: distance - 1}, %)
|
||||
|> extrude(1, %)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||
.await
|
||||
.unwrap();
|
||||
twenty_twenty::assert_image(
|
||||
"tests/executor/outputs/patterns_linear_basic_with_math.png",
|
||||
&result,
|
||||
0.999,
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_patterns_linear_basic() {
|
||||
let code = r#"const part = startSketchOn('XY')
|
||||
|> circle([0,0], 2, %)
|
||||
|> patternLinear2d({axis: [0,1], repetitions: 12, distance: 4}, %)
|
||||
|> extrude(1, %)
|
||||
|> patternLinear2d({axis: [0,1], repetitions: 12, distance: 2}, %)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||
|
Before Width: | Height: | Size: 199 KiB |
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 112 KiB |