Compare commits
6 Commits
nightly-v2
...
jtran/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
| cbfe3db203 | |||
| 615b7feabb | |||
| 5743b9ced0 | |||
| 8896d06028 | |||
| 1f217ef50b | |||
| 5ef5c6280c |
4
.github/workflows/e2e-tests.yml
vendored
4
.github/workflows/e2e-tests.yml
vendored
@ -142,7 +142,7 @@ jobs:
|
||||
# TODO: break this in its own job, for now it's not slowing down the overall execution as ubuntu is the quickest,
|
||||
# but we could do better. This forces a large 1/1 shard of all 20 snapshot tests that runs in about 3 minutes.
|
||||
run: |
|
||||
PLATFORM=web yarn playwright test --config=playwright.config.ts --retries="3" --update-snapshots --grep=@snapshot --shard=1/1
|
||||
PLATFORM=web yarn playwright test --config=playwright.config.ts --retries="3" --update-snapshots --grep=@snapshot --trace=on --shard=1/1
|
||||
env:
|
||||
CI: true
|
||||
NODE_ENV: development
|
||||
@ -153,7 +153,7 @@ jobs:
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ !cancelled() && (success() || failure()) }}
|
||||
with:
|
||||
name: playwright-report-${{ matrix.os }}-snapshot-${{ matrix.shardIndex }}-${{ github.sha }}
|
||||
name: playwright-report-snapshots-${{ matrix.os }}-snapshot-${{ matrix.shardIndex }}-${{ github.sha }}
|
||||
path: playwright-report/
|
||||
include-hidden-files: true
|
||||
retention-days: 30
|
||||
|
||||
@ -82,6 +82,16 @@ export class ToolbarFixture {
|
||||
startSketchPlaneSelection = async () =>
|
||||
doAndWaitForImageDiff(this.page, () => this.startSketchBtn.click(), 500)
|
||||
|
||||
exitSketch = async () => {
|
||||
await this.exitSketchBtn.click()
|
||||
await expect(
|
||||
this.page.getByRole('button', { name: 'Start Sketch' })
|
||||
).toBeVisible()
|
||||
await expect(
|
||||
this.page.getByRole('button', { name: 'Start Sketch' })
|
||||
).not.toBeDisabled()
|
||||
}
|
||||
|
||||
editSketch = async () => {
|
||||
await this.editSketchBtn.first().click()
|
||||
// One of the rare times we want to allow a arbitrary wait
|
||||
|
||||
@ -170,8 +170,7 @@ test.describe('Point-and-click tests', { tag: ['@skipWin'] }, () => {
|
||||
})
|
||||
|
||||
await test.step('Clean up so that `_sketchOnAChamfer` util can be called again', async () => {
|
||||
await toolbar.exitSketchBtn.click()
|
||||
await scene.waitForExecutionDone()
|
||||
await toolbar.exitSketch()
|
||||
})
|
||||
await test.step('Check there is no errors after code created in previous steps executes', async () => {
|
||||
await editor.expectState({
|
||||
@ -202,7 +201,9 @@ test.describe('Point-and-click tests', { tag: ['@skipWin'] }, () => {
|
||||
}, file)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await expect(
|
||||
page.getByTestId('model-state-indicator-receive-reliable')
|
||||
).toBeVisible()
|
||||
|
||||
const sketchOnAChamfer = _sketchOnAChamfer(page, editor, toolbar, scene)
|
||||
|
||||
@ -390,6 +391,7 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
|
||||
}, file)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
await scene.waitForExecutionDone()
|
||||
|
||||
const sketchOnAChamfer = _sketchOnAChamfer(page, editor, toolbar, scene)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
@ -775,7 +775,7 @@ profile003 = startProfileAt([40.16, -120.48], sketch006)
|
||||
)
|
||||
`)
|
||||
await expect(
|
||||
page.getByTestId('model-state-indicator-execution-done')
|
||||
page.getByTestId('model-state-indicator-receive-reliable')
|
||||
).toBeVisible()
|
||||
|
||||
await u.openAndClearDebugPanel()
|
||||
|
||||
@ -22,7 +22,7 @@ import {
|
||||
UnreliableSubscription,
|
||||
} from 'lang/std/engineConnection'
|
||||
import { EngineCommand } from 'lang/std/artifactGraph'
|
||||
import { toSync, uuidv4 } from 'lib/utils'
|
||||
import { toSync, uuidv4, getNormalisedCoordinates } from 'lib/utils'
|
||||
import { deg2Rad } from 'lib/utils2d'
|
||||
import { isReducedMotion, roundOff, throttle } from 'lib/utils'
|
||||
import * as TWEEN from '@tweenjs/tween.js'
|
||||
@ -109,6 +109,7 @@ export class CameraControls {
|
||||
interactionGuards: MouseGuard = cameraMouseDragGuards.Zoo
|
||||
isFovAnimationInProgress = false
|
||||
perspectiveFovBeforeOrtho = 45
|
||||
|
||||
// NOTE: Duplicated state across Provider and singleton. Mapped from settingsMachine
|
||||
_setting_allowOrbitInSketchMode = false
|
||||
get isPerspective() {
|
||||
@ -456,11 +457,19 @@ export class CameraControls {
|
||||
if (this.syncDirection === 'engineToClient') {
|
||||
const newCmdId = uuidv4()
|
||||
|
||||
// Nonsense to do anything until the video stream is established.
|
||||
if (!this.engineCommandManager.elVideo) return
|
||||
|
||||
const { x, y } = getNormalisedCoordinates(
|
||||
event,
|
||||
this.engineCommandManager.elVideo,
|
||||
this.engineCommandManager.streamDimensions
|
||||
)
|
||||
this.throttledEngCmd({
|
||||
type: 'modeling_cmd_req',
|
||||
cmd: {
|
||||
type: 'highlight_set_entity',
|
||||
selected_at_window: { x: event.clientX, y: event.clientY },
|
||||
selected_at_window: { x, y },
|
||||
},
|
||||
cmd_id: newCmdId,
|
||||
})
|
||||
|
||||
@ -309,7 +309,7 @@ const FileTreeItem = ({
|
||||
{hasRuntimeError && (
|
||||
<p
|
||||
className={
|
||||
'absolute m-0 p-0 bottom-3 left-6 w-3 h-3 flex items-center justify-center text-[9px] font-semibold text-white bg-red-600 rounded-full border border-red-300 dark:border-red-800 z-50 hover:cursor-pointer hover:scale-[2] transition-transform duration-200'
|
||||
'absolute m-0 p-0 bottom-3 left-6 w-3 h-3 flex items-center justify-center text-[9px] font-semibold text-white bg-primary hue-rotate-90 rounded-full border border-chalkboard-10 dark:border-chalkboard-80 z-50 hover:cursor-pointer hover:scale-[2] transition-transform duration-200'
|
||||
}
|
||||
title={`Click to view notifications`}
|
||||
>
|
||||
|
||||
@ -171,7 +171,7 @@ export const sidebarPanes: SidebarPane[] = [
|
||||
// editorManager.scrollToFirstErrorDiagnosticIfExists()
|
||||
},
|
||||
className:
|
||||
'absolute m-0 p-0 bottom-4 left-4 w-3 h-3 flex items-center justify-center text-[9px] font-semibold text-white bg-red-600 rounded-full border border-red-300 dark:border-red-800 z-50 hover:cursor-pointer hover:scale-[2] transition-transform duration-200',
|
||||
'absolute m-0 p-0 bottom-4 left-4 w-3 h-3 flex items-center justify-center text-[9px] font-semibold text-white bg-primary hue-rotate-90 rounded-full border border-chalkboard-10 dark:border-chalkboard-80 z-50 hover:cursor-pointer hover:scale-[2] transition-transform duration-200',
|
||||
title: 'Project files have runtime errors',
|
||||
},
|
||||
},
|
||||
|
||||
@ -47,6 +47,8 @@ export const Stream = () => {
|
||||
overallState === NetworkHealthState.Ok ||
|
||||
overallState === NetworkHealthState.Weak
|
||||
|
||||
engineCommandManager.elVideo = videoRef.current
|
||||
|
||||
/**
|
||||
* Execute code and show a "building scene message"
|
||||
* in Stream.tsx in the meantime.
|
||||
@ -272,7 +274,7 @@ export const Stream = () => {
|
||||
|
||||
if (btnName(e.nativeEvent).left) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
sendSelectEventToEngine(e, videoRef.current)
|
||||
sendSelectEventToEngine(e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,7 +296,7 @@ export const Stream = () => {
|
||||
return
|
||||
}
|
||||
|
||||
sendSelectEventToEngine(e, videoRef.current)
|
||||
sendSelectEventToEngine(e)
|
||||
.then(({ entity_id }) => {
|
||||
if (!entity_id) {
|
||||
// No entity selected. This is benign
|
||||
|
||||
@ -101,10 +101,7 @@ export function useSetupEngineManager(
|
||||
streamRef?.current?.offsetWidth ?? 0,
|
||||
streamRef?.current?.offsetHeight ?? 0
|
||||
)
|
||||
engineCommandManager.handleResize({
|
||||
streamWidth: width,
|
||||
streamHeight: height,
|
||||
})
|
||||
engineCommandManager.handleResize(engineCommandManager.streamDimensions)
|
||||
}, 500)
|
||||
|
||||
const onOnline = () => {
|
||||
|
||||
@ -116,7 +116,11 @@ const runGetPathToExtrudeForSegmentSelectionTest = async (
|
||||
}
|
||||
if (!extrudeInSketchPipe) {
|
||||
const init = expectedExtrudeNode.init
|
||||
if (init.type !== 'CallExpression' && init.type !== 'PipeExpression') {
|
||||
if (
|
||||
init.type !== 'CallExpression' &&
|
||||
init.type !== 'CallExpressionKw' &&
|
||||
init.type !== 'PipeExpression'
|
||||
) {
|
||||
return new Error(
|
||||
'Expected extrude expression is not a CallExpression or PipeExpression'
|
||||
)
|
||||
@ -129,25 +133,33 @@ const runGetPathToExtrudeForSegmentSelectionTest = async (
|
||||
// ast
|
||||
const ast = assertParse(code)
|
||||
|
||||
// selection
|
||||
// range
|
||||
const segmentRange = topLevelRange(
|
||||
code.indexOf(selectedSegmentSnippet),
|
||||
code.indexOf(selectedSegmentSnippet) + selectedSegmentSnippet.length
|
||||
)
|
||||
const selection: Selection = {
|
||||
codeRef: codeRefFromRange(segmentRange, ast),
|
||||
}
|
||||
|
||||
// executeAst and artifactGraph
|
||||
await kclManager.executeAst({ ast })
|
||||
const artifactGraph = engineCommandManager.artifactGraph
|
||||
|
||||
// find artifact
|
||||
const maybeArtifact = [...artifactGraph].find(([, artifact]) => {
|
||||
if (!('codeRef' in artifact && artifact.codeRef)) return false
|
||||
return isOverlap(artifact.codeRef.range, segmentRange)
|
||||
})
|
||||
|
||||
// build selection
|
||||
const selection: Selection = {
|
||||
codeRef: codeRefFromRange(segmentRange, ast),
|
||||
artifact: maybeArtifact ? maybeArtifact[1] : undefined,
|
||||
}
|
||||
|
||||
// get extrude expression
|
||||
const pathResult = getPathToExtrudeForSegmentSelection(
|
||||
ast,
|
||||
selection,
|
||||
artifactGraph,
|
||||
dependencies
|
||||
artifactGraph
|
||||
)
|
||||
if (err(pathResult)) return pathResult
|
||||
const { pathToExtrudeNode } = pathResult
|
||||
@ -234,6 +246,56 @@ extrude003 = extrude(sketch003, length = -15)`
|
||||
expectedExtrudeSnippet
|
||||
)
|
||||
})
|
||||
it('should return the correct paths for a (piped) extrude based on the other body (face)', async () => {
|
||||
const code = `sketch001 = startSketchOn('XY')
|
||||
|> startProfileAt([-25, -25], %)
|
||||
|> yLine(50, %)
|
||||
|> xLine(50, %)
|
||||
|> yLine(-50, %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> extrude(length = 50)
|
||||
sketch002 = startSketchOn(sketch001, 'END')
|
||||
|> startProfileAt([-15, -15], %)
|
||||
|> yLine(30, %)
|
||||
|> xLine(30, %)
|
||||
|> yLine(-30, %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> extrude(length = 30)`
|
||||
const selectedSegmentSnippet = `xLine(30, %)`
|
||||
const expectedExtrudeSnippet = `extrude(length = 30)`
|
||||
await runGetPathToExtrudeForSegmentSelectionTest(
|
||||
code,
|
||||
selectedSegmentSnippet,
|
||||
expectedExtrudeSnippet
|
||||
)
|
||||
})
|
||||
it('should return the correct paths for a (non-piped) extrude based on the other body (face)', async () => {
|
||||
const code = `sketch001 = startSketchOn('XY')
|
||||
|> startProfileAt([-25, -25], %)
|
||||
|> yLine(50, %)
|
||||
|> xLine(50, %)
|
||||
|> yLine(-50, %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
extrude001 = extrude(sketch001, length = 50)
|
||||
sketch002 = startSketchOn(extrude001, 'END')
|
||||
|> startProfileAt([-15, -15], %)
|
||||
|> yLine(30, %)
|
||||
|> xLine(30, %)
|
||||
|> yLine(-30, %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
extrude002 = extrude(sketch002, length = 30)`
|
||||
const selectedSegmentSnippet = `xLine(30, %)`
|
||||
const expectedExtrudeSnippet = `extrude002 = extrude(sketch002, length = 30)`
|
||||
await runGetPathToExtrudeForSegmentSelectionTest(
|
||||
code,
|
||||
selectedSegmentSnippet,
|
||||
expectedExtrudeSnippet
|
||||
)
|
||||
})
|
||||
it('should not return any path for missing extrusion', async () => {
|
||||
const code = `sketch001 = startSketchOn('XY')
|
||||
|> startProfileAt([-30, 30], %)
|
||||
|
||||
@ -10,7 +10,6 @@ import {
|
||||
Program,
|
||||
VariableDeclaration,
|
||||
VariableDeclarator,
|
||||
sketchFromKclValue,
|
||||
} from '../wasm'
|
||||
import {
|
||||
createCallExpressionStdLib,
|
||||
@ -35,11 +34,11 @@ import {
|
||||
sketchLineHelperMap,
|
||||
sketchLineHelperMapKw,
|
||||
} from '../std/sketch'
|
||||
import { err, trap } from 'lib/trap'
|
||||
import { err } from 'lib/trap'
|
||||
import { Selection, Selections } from 'lib/selections'
|
||||
import { KclCommandValue } from 'lib/commandTypes'
|
||||
import { isArray } from 'lib/utils'
|
||||
import { Artifact, getSweepFromSuspectedPath } from 'lang/std/artifactGraph'
|
||||
import { Artifact, getSweepArtifactFromSelection } from 'lang/std/artifactGraph'
|
||||
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
||||
import { findKwArg } from 'lang/util'
|
||||
import { KclManager } from 'lang/KclSingleton'
|
||||
@ -121,8 +120,7 @@ export function modifyAstWithEdgeTreatmentAndTag(
|
||||
const result = getPathToExtrudeForSegmentSelection(
|
||||
clonedAstForGetExtrude,
|
||||
selection,
|
||||
artifactGraph,
|
||||
dependencies
|
||||
artifactGraph
|
||||
)
|
||||
if (err(result)) return result
|
||||
const { pathToSegmentNode, pathToExtrudeNode } = result
|
||||
@ -279,39 +277,19 @@ function insertParametersIntoAst(
|
||||
export function getPathToExtrudeForSegmentSelection(
|
||||
ast: Program,
|
||||
selection: Selection,
|
||||
artifactGraph: ArtifactGraph,
|
||||
dependencies: {
|
||||
kclManager: KclManager
|
||||
engineCommandManager: EngineCommandManager
|
||||
editorManager: EditorManager
|
||||
codeManager: CodeManager
|
||||
}
|
||||
artifactGraph: ArtifactGraph
|
||||
): { pathToSegmentNode: PathToNode; pathToExtrudeNode: PathToNode } | Error {
|
||||
const pathToSegmentNode = getNodePathFromSourceRange(
|
||||
ast,
|
||||
selection.codeRef?.range
|
||||
)
|
||||
|
||||
const varDecNode = getNodeFromPath<VariableDeclaration>(
|
||||
ast,
|
||||
pathToSegmentNode,
|
||||
'VariableDeclaration'
|
||||
)
|
||||
if (err(varDecNode)) return varDecNode
|
||||
const sketchVar = varDecNode.node.declaration.id.name
|
||||
|
||||
const sketch = sketchFromKclValue(
|
||||
dependencies.kclManager.variables[sketchVar],
|
||||
sketchVar
|
||||
)
|
||||
if (trap(sketch)) return sketch
|
||||
|
||||
const extrusion = getSweepFromSuspectedPath(sketch.id, artifactGraph)
|
||||
if (err(extrusion)) return extrusion
|
||||
const sweepArtifact = getSweepArtifactFromSelection(selection, artifactGraph)
|
||||
if (err(sweepArtifact)) return sweepArtifact
|
||||
|
||||
const pathToExtrudeNode = getNodePathFromSourceRange(
|
||||
ast,
|
||||
extrusion.codeRef.range
|
||||
sweepArtifact.codeRef.range
|
||||
)
|
||||
if (err(pathToExtrudeNode)) return pathToExtrudeNode
|
||||
|
||||
|
||||
@ -13,36 +13,23 @@ import {
|
||||
createLiteral,
|
||||
createIdentifier,
|
||||
findUniqueName,
|
||||
createCallExpressionStdLib,
|
||||
createObjectExpression,
|
||||
createArrayExpression,
|
||||
createVariableDeclaration,
|
||||
createCallExpressionStdLibKw,
|
||||
createLabeledArg,
|
||||
} from 'lang/modifyAst'
|
||||
import { KCL_DEFAULT_CONSTANT_PREFIXES } from 'lib/constants'
|
||||
import { KclManager } from 'lang/KclSingleton'
|
||||
import { EngineCommandManager } from 'lang/std/engineConnection'
|
||||
import EditorManager from 'editor/manager'
|
||||
import CodeManager from 'lang/codeManager'
|
||||
|
||||
export function addShell({
|
||||
node,
|
||||
selection,
|
||||
artifactGraph,
|
||||
thickness,
|
||||
dependencies,
|
||||
}: {
|
||||
node: Node<Program>
|
||||
selection: Selections
|
||||
artifactGraph: ArtifactGraph
|
||||
thickness: Expr
|
||||
dependencies: {
|
||||
kclManager: KclManager
|
||||
engineCommandManager: EngineCommandManager
|
||||
editorManager: EditorManager
|
||||
codeManager: CodeManager
|
||||
}
|
||||
}): Error | { modifiedAst: Node<Program>; pathToNode: PathToNode } {
|
||||
const modifiedAst = structuredClone(node)
|
||||
|
||||
@ -55,8 +42,7 @@ export function addShell({
|
||||
const extrudeLookupResult = getPathToExtrudeForSegmentSelection(
|
||||
clonedAstForGetExtrude,
|
||||
graphSelection,
|
||||
artifactGraph,
|
||||
dependencies
|
||||
artifactGraph
|
||||
)
|
||||
if (err(extrudeLookupResult)) {
|
||||
return new Error("Couldn't find extrude")
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
} from 'lang/wasm'
|
||||
import { Models } from '@kittycad/lib'
|
||||
import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils'
|
||||
import { Selection } from 'lib/selections'
|
||||
import { err } from 'lib/trap'
|
||||
import { Cap, Plane, Wall } from 'wasm-lib/kcl/bindings/Artifact'
|
||||
import { CapSubType } from 'wasm-lib/kcl/bindings/Artifact'
|
||||
@ -455,6 +456,47 @@ export function getSweepFromSuspectedPath(
|
||||
)
|
||||
}
|
||||
|
||||
export function getSweepArtifactFromSelection(
|
||||
selection: Selection,
|
||||
artifactGraph: ArtifactGraph
|
||||
): SweepArtifact | Error {
|
||||
let sweepArtifact: Artifact | null = null
|
||||
if (selection.artifact?.type === 'sweepEdge') {
|
||||
const _artifact = getArtifactOfTypes(
|
||||
{ key: selection.artifact.sweepId, types: ['sweep'] },
|
||||
artifactGraph
|
||||
)
|
||||
if (err(_artifact)) return _artifact
|
||||
sweepArtifact = _artifact
|
||||
} else if (selection.artifact?.type === 'segment') {
|
||||
const _pathArtifact = getArtifactOfTypes(
|
||||
{ key: selection.artifact.pathId, types: ['path'] },
|
||||
artifactGraph
|
||||
)
|
||||
if (err(_pathArtifact)) return _pathArtifact
|
||||
if (!_pathArtifact.sweepId) return new Error('Path does not have a sweepId')
|
||||
const _artifact = getArtifactOfTypes(
|
||||
{ key: _pathArtifact.sweepId, types: ['sweep'] },
|
||||
artifactGraph
|
||||
)
|
||||
if (err(_artifact)) return _artifact
|
||||
sweepArtifact = _artifact
|
||||
} else if (
|
||||
selection.artifact?.type === 'cap' ||
|
||||
selection.artifact?.type === 'wall'
|
||||
) {
|
||||
const _artifact = getArtifactOfTypes(
|
||||
{ key: selection.artifact.sweepId, types: ['sweep'] },
|
||||
artifactGraph
|
||||
)
|
||||
if (err(_artifact)) return _artifact
|
||||
sweepArtifact = _artifact
|
||||
}
|
||||
if (!sweepArtifact) return new Error('No sweep artifact found')
|
||||
|
||||
return sweepArtifact
|
||||
}
|
||||
|
||||
export function getCodeRefsByArtifactId(
|
||||
id: string,
|
||||
artifactGraph: ArtifactGraph
|
||||
|
||||
@ -1447,11 +1447,17 @@ export class EngineCommandManager extends EventTarget {
|
||||
commandId: string
|
||||
}
|
||||
settings: SettingsViaQueryString
|
||||
width: number = 1337
|
||||
height: number = 1337
|
||||
|
||||
streamDimensions = {
|
||||
// Random defaults that are overwritten pretty much immediately
|
||||
width: 1337,
|
||||
height: 1337,
|
||||
}
|
||||
|
||||
elVideo: HTMLVideoElement | null = null
|
||||
|
||||
/**
|
||||
* Export intent traxcks the intent of the export. If it is null there is no
|
||||
* Export intent tracks the intent of the export. If it is null there is no
|
||||
* export in progress. Otherwise it is an enum value of the intent.
|
||||
* Another export cannot be started if one is already in progress.
|
||||
*/
|
||||
@ -1554,15 +1560,14 @@ export class EngineCommandManager extends EventTarget {
|
||||
return
|
||||
}
|
||||
|
||||
this.width = width
|
||||
this.height = height
|
||||
this.streamDimensions = {
|
||||
width,
|
||||
height,
|
||||
}
|
||||
|
||||
// If we already have an engine connection, just need to resize the stream.
|
||||
if (this.engineConnection) {
|
||||
this.handleResize({
|
||||
streamWidth: width,
|
||||
streamHeight: height,
|
||||
})
|
||||
this.handleResize(this.streamDimensions)
|
||||
return
|
||||
}
|
||||
|
||||
@ -1858,27 +1863,22 @@ export class EngineCommandManager extends EventTarget {
|
||||
return
|
||||
}
|
||||
|
||||
handleResize({
|
||||
streamWidth,
|
||||
streamHeight,
|
||||
}: {
|
||||
streamWidth: number
|
||||
streamHeight: number
|
||||
}) {
|
||||
handleResize({ width, height }: { width: number; height: number }) {
|
||||
if (!this.engineConnection?.isReady()) {
|
||||
return
|
||||
}
|
||||
|
||||
this.width = streamWidth
|
||||
this.height = streamHeight
|
||||
this.streamDimensions = {
|
||||
width,
|
||||
height,
|
||||
}
|
||||
|
||||
const resizeCmd: EngineCommand = {
|
||||
type: 'modeling_cmd_req',
|
||||
cmd_id: uuidv4(),
|
||||
cmd: {
|
||||
type: 'reconfigure_stream',
|
||||
width: streamWidth,
|
||||
height: streamHeight,
|
||||
...this.streamDimensions,
|
||||
fps: 60,
|
||||
},
|
||||
}
|
||||
|
||||
@ -646,16 +646,17 @@ export function codeToIdSelections(
|
||||
}
|
||||
|
||||
export async function sendSelectEventToEngine(
|
||||
e: MouseEvent | React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
el: HTMLVideoElement
|
||||
e: React.MouseEvent<HTMLDivElement, MouseEvent>
|
||||
) {
|
||||
const { x, y } = getNormalisedCoordinates({
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
el,
|
||||
streamWidth: engineCommandManager.width,
|
||||
streamHeight: engineCommandManager.height,
|
||||
})
|
||||
// No video stream to normalise against, return immediately
|
||||
if (!engineCommandManager.elVideo)
|
||||
return Promise.reject('video element not ready')
|
||||
|
||||
const { x, y } = getNormalisedCoordinates(
|
||||
e,
|
||||
engineCommandManager.elVideo,
|
||||
engineCommandManager.streamDimensions
|
||||
)
|
||||
const res = await engineCommandManager.sendSceneCommand({
|
||||
type: 'modeling_cmd_req',
|
||||
cmd: {
|
||||
|
||||
@ -161,25 +161,20 @@ export function toSync<F extends AsyncFn<F>>(
|
||||
}
|
||||
}
|
||||
|
||||
export function getNormalisedCoordinates({
|
||||
clientX,
|
||||
clientY,
|
||||
streamWidth,
|
||||
streamHeight,
|
||||
el,
|
||||
}: {
|
||||
clientX: number
|
||||
clientY: number
|
||||
streamWidth: number
|
||||
streamHeight: number
|
||||
el: HTMLElement
|
||||
}) {
|
||||
const { left, top, width, height } = el?.getBoundingClientRect()
|
||||
const browserX = clientX - left
|
||||
const browserY = clientY - top
|
||||
export function getNormalisedCoordinates(
|
||||
e: PointerEvent | React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
elVideo: HTMLVideoElement,
|
||||
streamDimensions: {
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
) {
|
||||
const { left, top, width, height } = elVideo?.getBoundingClientRect()
|
||||
const browserX = e.clientX - left
|
||||
const browserY = e.clientY - top
|
||||
return {
|
||||
x: Math.round((browserX / width) * streamWidth),
|
||||
y: Math.round((browserY / height) * streamHeight),
|
||||
x: Math.round((browserX / width) * streamDimensions.width),
|
||||
y: Math.round((browserY / height) * streamDimensions.height),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1995,12 +1995,6 @@ export const modelingMachine = setup({
|
||||
// Extract inputs
|
||||
const ast = kclManager.ast
|
||||
const { selection, thickness } = input
|
||||
const dependencies = {
|
||||
kclManager,
|
||||
engineCommandManager,
|
||||
editorManager,
|
||||
codeManager,
|
||||
}
|
||||
|
||||
// Insert the thickness variable if it exists
|
||||
if (
|
||||
@ -2026,7 +2020,6 @@ export const modelingMachine = setup({
|
||||
'variableName' in thickness
|
||||
? thickness.variableIdentifierAst
|
||||
: thickness.valueAst,
|
||||
dependencies,
|
||||
})
|
||||
if (err(shellResult)) {
|
||||
return err(shellResult)
|
||||
|
||||
6
src/wasm-lib/Cargo.lock
generated
6
src/wasm-lib/Cargo.lock
generated
@ -730,7 +730,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "derive-docs"
|
||||
version = "0.1.38"
|
||||
version = "0.1.39"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"anyhow",
|
||||
@ -1724,7 +1724,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.2.38"
|
||||
version = "0.2.39"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx 0.5.1",
|
||||
@ -1791,7 +1791,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-test-server"
|
||||
version = "0.1.38"
|
||||
version = "0.1.39"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"hyper 0.14.32",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "derive-docs"
|
||||
description = "A tool for generating documentation from Rust derive macros"
|
||||
version = "0.1.38"
|
||||
version = "0.1.39"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-test-server"
|
||||
description = "A test server for KCL"
|
||||
version = "0.1.38"
|
||||
version = "0.1.39"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-lib"
|
||||
description = "KittyCAD Language implementation and tools"
|
||||
version = "0.2.38"
|
||||
version = "0.2.39"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
||||
@ -2048,3 +2048,24 @@ mod import_file_parse_error {
|
||||
super::execute(TEST_NAME, true).await
|
||||
}
|
||||
}
|
||||
mod assembly_simplified_walkie {
|
||||
const TEST_NAME: &str = "assembly_simplified_walkie";
|
||||
|
||||
/// Test parsing KCL.
|
||||
#[test]
|
||||
fn parse() {
|
||||
super::parse(TEST_NAME)
|
||||
}
|
||||
|
||||
/// Test that parsing and unparsing KCL produces the original KCL input.
|
||||
#[test]
|
||||
fn unparse() {
|
||||
super::unparse(TEST_NAME)
|
||||
}
|
||||
|
||||
/// Test that KCL is executed correctly.
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_execute() {
|
||||
super::execute(TEST_NAME, true).await
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,6 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
description: Artifact graph flowchart assembly_simplified_walkie.kcl
|
||||
extension: md
|
||||
snapshot_kind: binary
|
||||
---
|
||||
@ -0,0 +1,219 @@
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph path3 [Path]
|
||||
3["Path<br>[1358, 1517, 3]"]
|
||||
4["Segment<br>[1523, 1618, 3]"]
|
||||
5["Segment<br>[1624, 1785, 3]"]
|
||||
6["Segment<br>[1791, 1886, 3]"]
|
||||
7["Segment<br>[1892, 2056, 3]"]
|
||||
8["Segment<br>[2062, 2158, 3]"]
|
||||
9["Segment<br>[2164, 2327, 3]"]
|
||||
10["Segment<br>[2333, 2428, 3]"]
|
||||
11["Segment<br>[2434, 2441, 3]"]
|
||||
12[Solid2d]
|
||||
end
|
||||
subgraph path41 [Path]
|
||||
41["Path<br>[1119, 1160, 5]"]
|
||||
42["Segment<br>[1168, 1263, 5]"]
|
||||
43["Segment<br>[1271, 1367, 5]"]
|
||||
44["Segment<br>[1375, 1461, 5]"]
|
||||
45["Segment<br>[1469, 1476, 5]"]
|
||||
46[Solid2d]
|
||||
end
|
||||
subgraph path63 [Path]
|
||||
63["Path<br>[503, 596, 4]"]
|
||||
64["Segment<br>[602, 639, 4]"]
|
||||
65["Segment<br>[645, 683, 4]"]
|
||||
66["Segment<br>[689, 727, 4]"]
|
||||
67["Segment<br>[733, 751, 4]"]
|
||||
68[Solid2d]
|
||||
end
|
||||
1["Plane<br>[358, 387, 3]"]
|
||||
2["Plane<br>[1322, 1351, 3]"]
|
||||
13["Sweep Extrusion<br>[2790, 2826, 3]"]
|
||||
14[Wall]
|
||||
15[Wall]
|
||||
16[Wall]
|
||||
17[Wall]
|
||||
18[Wall]
|
||||
19[Wall]
|
||||
20[Wall]
|
||||
21[Wall]
|
||||
22["Cap Start"]
|
||||
23["Cap End"]
|
||||
24["SweepEdge Opposite"]
|
||||
25["SweepEdge Adjacent"]
|
||||
26["SweepEdge Opposite"]
|
||||
27["SweepEdge Adjacent"]
|
||||
28["SweepEdge Opposite"]
|
||||
29["SweepEdge Adjacent"]
|
||||
30["SweepEdge Opposite"]
|
||||
31["SweepEdge Adjacent"]
|
||||
32["SweepEdge Opposite"]
|
||||
33["SweepEdge Adjacent"]
|
||||
34["SweepEdge Opposite"]
|
||||
35["SweepEdge Adjacent"]
|
||||
36["SweepEdge Opposite"]
|
||||
37["SweepEdge Adjacent"]
|
||||
38["SweepEdge Opposite"]
|
||||
39["SweepEdge Adjacent"]
|
||||
40["Plane<br>[405, 442, 0]"]
|
||||
47["Sweep Extrusion<br>[1495, 1542, 5]"]
|
||||
48[Wall]
|
||||
49[Wall]
|
||||
50[Wall]
|
||||
51[Wall]
|
||||
52["Cap Start"]
|
||||
53["Cap End"]
|
||||
54["SweepEdge Opposite"]
|
||||
55["SweepEdge Adjacent"]
|
||||
56["SweepEdge Opposite"]
|
||||
57["SweepEdge Adjacent"]
|
||||
58["SweepEdge Opposite"]
|
||||
59["SweepEdge Adjacent"]
|
||||
60["SweepEdge Opposite"]
|
||||
61["SweepEdge Adjacent"]
|
||||
62["Plane<br>[467, 497, 4]"]
|
||||
69["Sweep Extrusion<br>[797, 849, 4]"]
|
||||
70[Wall]
|
||||
71[Wall]
|
||||
72[Wall]
|
||||
73[Wall]
|
||||
74["Cap Start"]
|
||||
75["Cap End"]
|
||||
76["SweepEdge Opposite"]
|
||||
77["SweepEdge Adjacent"]
|
||||
78["SweepEdge Opposite"]
|
||||
79["SweepEdge Adjacent"]
|
||||
80["SweepEdge Opposite"]
|
||||
81["SweepEdge Adjacent"]
|
||||
82["SweepEdge Opposite"]
|
||||
83["SweepEdge Adjacent"]
|
||||
2 --- 3
|
||||
3 --- 4
|
||||
3 --- 5
|
||||
3 --- 6
|
||||
3 --- 7
|
||||
3 --- 8
|
||||
3 --- 9
|
||||
3 --- 10
|
||||
3 --- 11
|
||||
3 ---- 13
|
||||
3 --- 12
|
||||
4 --- 21
|
||||
4 --- 38
|
||||
4 --- 39
|
||||
5 --- 20
|
||||
5 --- 36
|
||||
5 --- 37
|
||||
6 --- 19
|
||||
6 --- 34
|
||||
6 --- 35
|
||||
7 --- 18
|
||||
7 --- 32
|
||||
7 --- 33
|
||||
8 --- 17
|
||||
8 --- 30
|
||||
8 --- 31
|
||||
9 --- 16
|
||||
9 --- 28
|
||||
9 --- 29
|
||||
10 --- 15
|
||||
10 --- 26
|
||||
10 --- 27
|
||||
11 --- 14
|
||||
11 --- 24
|
||||
11 --- 25
|
||||
13 --- 14
|
||||
13 --- 15
|
||||
13 --- 16
|
||||
13 --- 17
|
||||
13 --- 18
|
||||
13 --- 19
|
||||
13 --- 20
|
||||
13 --- 21
|
||||
13 --- 22
|
||||
13 --- 23
|
||||
13 --- 24
|
||||
13 --- 25
|
||||
13 --- 26
|
||||
13 --- 27
|
||||
13 --- 28
|
||||
13 --- 29
|
||||
13 --- 30
|
||||
13 --- 31
|
||||
13 --- 32
|
||||
13 --- 33
|
||||
13 --- 34
|
||||
13 --- 35
|
||||
13 --- 36
|
||||
13 --- 37
|
||||
13 --- 38
|
||||
13 --- 39
|
||||
40 --- 41
|
||||
41 --- 42
|
||||
41 --- 43
|
||||
41 --- 44
|
||||
41 --- 45
|
||||
41 ---- 47
|
||||
41 --- 46
|
||||
42 --- 48
|
||||
42 --- 54
|
||||
42 --- 55
|
||||
43 --- 49
|
||||
43 --- 56
|
||||
43 --- 57
|
||||
44 --- 50
|
||||
44 --- 58
|
||||
44 --- 59
|
||||
45 --- 51
|
||||
45 --- 60
|
||||
45 --- 61
|
||||
47 --- 48
|
||||
47 --- 49
|
||||
47 --- 50
|
||||
47 --- 51
|
||||
47 --- 52
|
||||
47 --- 53
|
||||
47 --- 54
|
||||
47 --- 55
|
||||
47 --- 56
|
||||
47 --- 57
|
||||
47 --- 58
|
||||
47 --- 59
|
||||
47 --- 60
|
||||
47 --- 61
|
||||
62 --- 63
|
||||
63 --- 64
|
||||
63 --- 65
|
||||
63 --- 66
|
||||
63 --- 67
|
||||
63 ---- 69
|
||||
63 --- 68
|
||||
64 --- 73
|
||||
64 --- 82
|
||||
64 --- 83
|
||||
65 --- 72
|
||||
65 --- 80
|
||||
65 --- 81
|
||||
66 --- 71
|
||||
66 --- 78
|
||||
66 --- 79
|
||||
67 --- 70
|
||||
67 --- 76
|
||||
67 --- 77
|
||||
69 --- 70
|
||||
69 --- 71
|
||||
69 --- 72
|
||||
69 --- 73
|
||||
69 --- 74
|
||||
69 --- 75
|
||||
69 --- 76
|
||||
69 --- 77
|
||||
69 --- 78
|
||||
69 --- 79
|
||||
69 --- 80
|
||||
69 --- 81
|
||||
69 --- 82
|
||||
69 --- 83
|
||||
```
|
||||
428
src/wasm-lib/kcl/tests/assembly_simplified_walkie/ast.snap
Normal file
428
src/wasm-lib/kcl/tests/assembly_simplified_walkie/ast.snap
Normal file
@ -0,0 +1,428 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
description: Result of parsing assembly_simplified_walkie.kcl
|
||||
---
|
||||
{
|
||||
"Ok": {
|
||||
"body": [
|
||||
{
|
||||
"end": 112,
|
||||
"path": {
|
||||
"type": "Kcl",
|
||||
"filename": "case.kcl"
|
||||
},
|
||||
"selector": {
|
||||
"type": "None",
|
||||
"alias": null
|
||||
},
|
||||
"start": 95,
|
||||
"type": "ImportStatement",
|
||||
"type": "ImportStatement"
|
||||
},
|
||||
{
|
||||
"end": 151,
|
||||
"path": {
|
||||
"type": "Kcl",
|
||||
"filename": "talk-button.kcl"
|
||||
},
|
||||
"selector": {
|
||||
"type": "None",
|
||||
"alias": {
|
||||
"end": 151,
|
||||
"name": "talkButton",
|
||||
"start": 141,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"start": 113,
|
||||
"type": "ImportStatement",
|
||||
"type": "ImportStatement"
|
||||
},
|
||||
{
|
||||
"end": 183,
|
||||
"path": {
|
||||
"type": "Kcl",
|
||||
"filename": "button.kcl"
|
||||
},
|
||||
"selector": {
|
||||
"type": "List",
|
||||
"items": [
|
||||
{
|
||||
"alias": null,
|
||||
"end": 165,
|
||||
"name": {
|
||||
"end": 165,
|
||||
"name": "button",
|
||||
"start": 159,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"start": 159,
|
||||
"type": "ImportItem"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start": 152,
|
||||
"type": "ImportStatement",
|
||||
"type": "ImportStatement"
|
||||
},
|
||||
{
|
||||
"end": 289,
|
||||
"path": {
|
||||
"type": "Kcl",
|
||||
"filename": "globals.kcl"
|
||||
},
|
||||
"selector": {
|
||||
"type": "List",
|
||||
"items": [
|
||||
{
|
||||
"alias": null,
|
||||
"end": 196,
|
||||
"name": {
|
||||
"end": 196,
|
||||
"name": "width",
|
||||
"start": 191,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"start": 191,
|
||||
"type": "ImportItem"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"end": 204,
|
||||
"name": {
|
||||
"end": 204,
|
||||
"name": "height",
|
||||
"start": 198,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"start": 198,
|
||||
"type": "ImportItem"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"end": 215,
|
||||
"name": {
|
||||
"end": 215,
|
||||
"name": "thickness",
|
||||
"start": 206,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"start": 206,
|
||||
"type": "ImportItem"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"end": 228,
|
||||
"name": {
|
||||
"end": 228,
|
||||
"name": "screenWidth",
|
||||
"start": 217,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"start": 217,
|
||||
"type": "ImportItem"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"end": 242,
|
||||
"name": {
|
||||
"end": 242,
|
||||
"name": "screenHeight",
|
||||
"start": 230,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"start": 230,
|
||||
"type": "ImportItem"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"end": 259,
|
||||
"name": {
|
||||
"end": 259,
|
||||
"name": "screenYPosition",
|
||||
"start": 244,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"start": 244,
|
||||
"type": "ImportItem"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"end": 270,
|
||||
"name": {
|
||||
"end": 270,
|
||||
"name": "tolerance",
|
||||
"start": 261,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"start": 261,
|
||||
"type": "ImportItem"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start": 184,
|
||||
"type": "ImportStatement",
|
||||
"type": "ImportStatement"
|
||||
},
|
||||
{
|
||||
"end": 314,
|
||||
"expression": {
|
||||
"end": 314,
|
||||
"name": "case",
|
||||
"start": 310,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
"start": 310,
|
||||
"type": "ExpressionStatement",
|
||||
"type": "ExpressionStatement"
|
||||
},
|
||||
{
|
||||
"end": 443,
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"elements": [
|
||||
{
|
||||
"argument": {
|
||||
"end": 378,
|
||||
"left": {
|
||||
"end": 366,
|
||||
"left": {
|
||||
"end": 362,
|
||||
"name": "screenWidth",
|
||||
"start": 351,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
"operator": "/",
|
||||
"right": {
|
||||
"end": 366,
|
||||
"raw": "2",
|
||||
"start": 365,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 2.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
"start": 351,
|
||||
"type": "BinaryExpression",
|
||||
"type": "BinaryExpression"
|
||||
},
|
||||
"operator": "+",
|
||||
"right": {
|
||||
"end": 378,
|
||||
"name": "tolerance",
|
||||
"start": 369,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
"start": 351,
|
||||
"type": "BinaryExpression",
|
||||
"type": "BinaryExpression"
|
||||
},
|
||||
"end": 378,
|
||||
"operator": "-",
|
||||
"start": 349,
|
||||
"type": "UnaryExpression",
|
||||
"type": "UnaryExpression"
|
||||
},
|
||||
{
|
||||
"end": 398,
|
||||
"name": "screenYPosition",
|
||||
"start": 383,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
],
|
||||
"end": 400,
|
||||
"start": 345,
|
||||
"type": "ArrayExpression",
|
||||
"type": "ArrayExpression"
|
||||
},
|
||||
{
|
||||
"end": 403,
|
||||
"raw": "0",
|
||||
"start": 402,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 0.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"type": "Identifier",
|
||||
"name": "offset"
|
||||
},
|
||||
"arg": {
|
||||
"end": 441,
|
||||
"name": "thickness",
|
||||
"start": 432,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"end": 416,
|
||||
"name": "offsetPlane",
|
||||
"start": 405,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 442,
|
||||
"start": 405,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": {
|
||||
"end": 421,
|
||||
"raw": "\"XZ\"",
|
||||
"start": 417,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "XZ"
|
||||
}
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"end": 344,
|
||||
"name": "button",
|
||||
"start": 338,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 443,
|
||||
"start": 338,
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 338,
|
||||
"type": "ExpressionStatement",
|
||||
"type": "ExpressionStatement"
|
||||
},
|
||||
{
|
||||
"end": 481,
|
||||
"expression": {
|
||||
"end": 481,
|
||||
"name": "talkButton",
|
||||
"start": 471,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
"start": 471,
|
||||
"type": "ExpressionStatement",
|
||||
"type": "ExpressionStatement"
|
||||
}
|
||||
],
|
||||
"end": 482,
|
||||
"innerAttrs": [
|
||||
{
|
||||
"end": 33,
|
||||
"name": {
|
||||
"end": 9,
|
||||
"name": "settings",
|
||||
"start": 1,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"end": 32,
|
||||
"key": {
|
||||
"end": 27,
|
||||
"name": "defaultLengthUnit",
|
||||
"start": 10,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"start": 10,
|
||||
"type": "ObjectProperty",
|
||||
"value": {
|
||||
"end": 32,
|
||||
"name": "in",
|
||||
"start": 30,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
}
|
||||
],
|
||||
"start": 0,
|
||||
"type": "Annotation"
|
||||
}
|
||||
],
|
||||
"nonCodeMeta": {
|
||||
"nonCodeNodes": {
|
||||
"3": [
|
||||
{
|
||||
"end": 309,
|
||||
"start": 289,
|
||||
"type": "NonCodeNode",
|
||||
"value": {
|
||||
"type": "newLineBlockComment",
|
||||
"value": "Import the case",
|
||||
"style": "line"
|
||||
}
|
||||
}
|
||||
],
|
||||
"4": [
|
||||
{
|
||||
"end": 337,
|
||||
"start": 314,
|
||||
"type": "NonCodeNode",
|
||||
"value": {
|
||||
"type": "newLineBlockComment",
|
||||
"value": "Import the buttons",
|
||||
"style": "line"
|
||||
}
|
||||
}
|
||||
],
|
||||
"5": [
|
||||
{
|
||||
"end": 470,
|
||||
"start": 443,
|
||||
"type": "NonCodeNode",
|
||||
"value": {
|
||||
"type": "newLineBlockComment",
|
||||
"value": "Import the talk button",
|
||||
"style": "line"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"startNodes": [
|
||||
{
|
||||
"end": 36,
|
||||
"start": 33,
|
||||
"type": "NonCodeNode",
|
||||
"value": {
|
||||
"type": "newLine"
|
||||
}
|
||||
},
|
||||
{
|
||||
"end": 64,
|
||||
"start": 36,
|
||||
"type": "NonCodeNode",
|
||||
"value": {
|
||||
"type": "blockComment",
|
||||
"value": "Part of the Walkie Talkie",
|
||||
"style": "line"
|
||||
}
|
||||
},
|
||||
{
|
||||
"end": 94,
|
||||
"start": 65,
|
||||
"type": "NonCodeNode",
|
||||
"value": {
|
||||
"type": "blockComment",
|
||||
"value": "Import parts and constants",
|
||||
"style": "line"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"start": 0
|
||||
}
|
||||
}
|
||||
74
src/wasm-lib/kcl/tests/assembly_simplified_walkie/button.kcl
Normal file
74
src/wasm-lib/kcl/tests/assembly_simplified_walkie/button.kcl
Normal file
@ -0,0 +1,74 @@
|
||||
// Walkie Talkie button
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import constants
|
||||
//import screenHeight, buttonWidth, tolerance, buttonHeight, buttonThickness from 'globals.kcl'
|
||||
export height = 4
|
||||
export width = 2.5
|
||||
export thickness = 1
|
||||
export chamferLength = .325
|
||||
export offset = .125
|
||||
export screenWidth = 1.75
|
||||
export screenHeight = 1
|
||||
export screenYPosition = height / 2 - 0.75
|
||||
export screenDepth = -.0625
|
||||
export speakerBoxWidth = 1.25
|
||||
export speakerBoxHeight = 1.25
|
||||
|
||||
// antenna
|
||||
export antennaBaseWidth = .5
|
||||
export antennaBaseHeight = .25
|
||||
export antennaTopWidth = .30
|
||||
export antennaTopHeight = .05
|
||||
|
||||
// button
|
||||
export buttonWidth = .15
|
||||
export tolerance = 0.020
|
||||
export buttonHeight = screenHeight / 2 - tolerance
|
||||
export buttonThickness = .040
|
||||
|
||||
// case
|
||||
export squareHoleSideLength = 0.0625
|
||||
export caseTolerance = 0.010
|
||||
|
||||
// knob
|
||||
export knobDiameter = .5
|
||||
export knobHeight = .25
|
||||
export knobRadius = 0.050
|
||||
|
||||
// talk-button
|
||||
export talkButtonSideLength = 0.5
|
||||
export talkButtonHeight = 0.050
|
||||
|
||||
|
||||
// Create a function for the button
|
||||
export fn button(origin, rotation, plane) {
|
||||
buttonSketch = startSketchOn(plane)
|
||||
|> startProfileAt([origin[0], origin[1]], %)
|
||||
|> angledLine({
|
||||
angle = 180 + rotation,
|
||||
length = buttonWidth
|
||||
}, %, $tag1)
|
||||
|> angledLine({
|
||||
angle = 270 + rotation,
|
||||
length = buttonHeight
|
||||
}, %, $tag2)
|
||||
|> angledLine({
|
||||
angle = 0 + rotation,
|
||||
length = buttonWidth
|
||||
}, %)
|
||||
|> close()
|
||||
buttonExtrude = extrude(buttonSketch, length = buttonThickness)
|
||||
|> chamfer(
|
||||
length = .050,
|
||||
tags = [
|
||||
getNextAdjacentEdge(tag1),
|
||||
getNextAdjacentEdge(tag2)
|
||||
]
|
||||
)
|
||||
|> appearance(color = "#ff0000")
|
||||
|
||||
return buttonExtrude
|
||||
}
|
||||
85
src/wasm-lib/kcl/tests/assembly_simplified_walkie/case.kcl
Normal file
85
src/wasm-lib/kcl/tests/assembly_simplified_walkie/case.kcl
Normal file
@ -0,0 +1,85 @@
|
||||
// Walkie talkie case
|
||||
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Import constants and Zoo logo
|
||||
import width, height, chamferLength, offset, screenWidth, screenHeight, screenYPosition, screenDepth, speakerBoxWidth, speakerBoxHeight, squareHoleSideLength, caseTolerance from "globals.kcl"
|
||||
// import zLogo, oLogo, oLogo2 from "zoo-logo.kcl"
|
||||
|
||||
plane = offsetPlane("XZ", offset = 1)
|
||||
|
||||
fn screenHole(sketchStart) {
|
||||
sketch006 = startSketchOn(sketchStart)
|
||||
|> startProfileAt([-screenWidth / 2, screenYPosition], %)
|
||||
|> xLine(screenWidth, %)
|
||||
|> yLine(-screenHeight, %)
|
||||
|> xLine(-screenWidth, %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
return sketch006
|
||||
}
|
||||
|
||||
fn squareHolePattern(plane, x, y) {
|
||||
fn transformX(i) {
|
||||
return { translate = [.125 * i, 0] }
|
||||
}
|
||||
fn transformY(i) {
|
||||
return { translate = [0, -.125 * i] }
|
||||
}
|
||||
squareHolePatternSketch = startSketchOn(plane)
|
||||
|> startProfileAt([-x, -y], %)
|
||||
|> line(end = [squareHoleSideLength / 2, 0])
|
||||
|> line(end = [0, -squareHoleSideLength / 2])
|
||||
|> line(end = [-squareHoleSideLength / 2, 0])
|
||||
|> close()
|
||||
|> patternTransform2d(instances = 13, transform = transformX)
|
||||
|> patternTransform2d(instances = 11, transform = transformY)
|
||||
return squareHolePatternSketch
|
||||
}
|
||||
sketch005 = startSketchOn(offsetPlane("XZ", offset = 1))
|
||||
|> startProfileAt([
|
||||
-width / 2 + offset + caseTolerance,
|
||||
height / 2 - (chamferLength + (offset + caseTolerance) / 2 * cos(toRadians(45)))
|
||||
], %)
|
||||
|> angledLineToY({
|
||||
angle = 45,
|
||||
to = height / 2 - (offset + caseTolerance)
|
||||
}, %)
|
||||
|> line(endAbsolute = [
|
||||
width / 2 - (chamferLength + (offset + caseTolerance) / 2 * cos(toRadians(45))),
|
||||
height / 2 - (offset + caseTolerance)
|
||||
])
|
||||
|> angledLineToX({
|
||||
angle = -45,
|
||||
to = width / 2 - (offset + caseTolerance)
|
||||
}, %)
|
||||
|> line(endAbsolute = [
|
||||
width / 2 - (offset + caseTolerance),
|
||||
-(height / 2 - (chamferLength + (offset + caseTolerance) / 2 * cos(toRadians(45))))
|
||||
])
|
||||
|> angledLineToY({
|
||||
angle = -135,
|
||||
to = -height / 2 + offset + caseTolerance
|
||||
}, %)
|
||||
|> line(endAbsolute = [
|
||||
-(width / 2 - (chamferLength + (offset + caseTolerance) / 2 * cos(toRadians(45)))),
|
||||
-height / 2 + offset + caseTolerance
|
||||
])
|
||||
|> angledLineToX({
|
||||
angle = -225,
|
||||
to = -width / 2 + offset + caseTolerance
|
||||
}, %)
|
||||
|> close()
|
||||
// |> hole(screenHole(plane), %)
|
||||
// |> hole(squareHolePattern(plane, .75, .125), %)
|
||||
// |> hole(zLogo(plane, [-.30, -1.825], .20), %)
|
||||
// |> hole(oLogo(plane, [-.075, -1.825], .20), %)
|
||||
// |> hole(oLogo2(plane, [-.075, -1.825], .20), %)
|
||||
// |> hole(oLogo(plane, [.175, -1.825], .20), %)
|
||||
// |> hole(oLogo2(plane, [.175, -1.825], .20), %)
|
||||
|
||||
extrude(sketch005, length = -0.0625)
|
||||
|> appearance(color = '#D0FF01', metalness = 0, roughness = 50)
|
||||
@ -0,0 +1,14 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
description: Error from executing assembly_simplified_walkie.kcl
|
||||
---
|
||||
KCL Semantic error
|
||||
|
||||
× semantic: Error loading imported file. Open it to view more details.
|
||||
│ tests/assembly_simplified_walkie/talk-button.kcl: Modeling command failed:
|
||||
│ [ApiError { error_code: BadRequest, message: "Chamfer failed" }]
|
||||
╭─[21:1]
|
||||
20 │ // Import the talk button
|
||||
21 │ talkButton
|
||||
· ──────────
|
||||
╰────
|
||||
@ -0,0 +1,42 @@
|
||||
// Global constants for the walkie talkie
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// body
|
||||
export height = 4
|
||||
export width = 2.5
|
||||
export thickness = 1
|
||||
export chamferLength = .325
|
||||
export offset = .125
|
||||
export screenWidth = 1.75
|
||||
export screenHeight = 1
|
||||
export screenYPosition = height / 2 - 0.75
|
||||
export screenDepth = -.0625
|
||||
export speakerBoxWidth = 1.25
|
||||
export speakerBoxHeight = 1.25
|
||||
|
||||
// antenna
|
||||
export antennaBaseWidth = .5
|
||||
export antennaBaseHeight = .25
|
||||
export antennaTopWidth = .30
|
||||
export antennaTopHeight = .05
|
||||
|
||||
// button
|
||||
export buttonWidth = .15
|
||||
export tolerance = 0.020
|
||||
export buttonHeight = screenHeight / 2 - tolerance
|
||||
export buttonThickness = .040
|
||||
|
||||
// case
|
||||
export squareHoleSideLength = 0.0625
|
||||
export caseTolerance = 0.010
|
||||
|
||||
// knob
|
||||
export knobDiameter = .5
|
||||
export knobHeight = .25
|
||||
export knobRadius = 0.050
|
||||
|
||||
// talk-button
|
||||
export talkButtonSideLength = 0.5
|
||||
export talkButtonHeight = 0.050
|
||||
21
src/wasm-lib/kcl/tests/assembly_simplified_walkie/input.kcl
Normal file
21
src/wasm-lib/kcl/tests/assembly_simplified_walkie/input.kcl
Normal file
@ -0,0 +1,21 @@
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Part of the Walkie Talkie
|
||||
// Import parts and constants
|
||||
import "case.kcl"
|
||||
import "talk-button.kcl" as talkButton
|
||||
import button from "button.kcl"
|
||||
import width, height, thickness, screenWidth, screenHeight, screenYPosition, tolerance from "globals.kcl"
|
||||
|
||||
// Import the case
|
||||
case
|
||||
|
||||
// Import the buttons
|
||||
button([
|
||||
-(screenWidth / 2 + tolerance),
|
||||
screenYPosition
|
||||
], 0, offsetPlane("XZ", offset = thickness))
|
||||
|
||||
// Import the talk button
|
||||
talkButton
|
||||
198
src/wasm-lib/kcl/tests/assembly_simplified_walkie/ops.snap
Normal file
198
src/wasm-lib/kcl/tests/assembly_simplified_walkie/ops.snap
Normal file
@ -0,0 +1,198 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
description: Operations executed assembly_simplified_walkie.kcl
|
||||
---
|
||||
[
|
||||
{
|
||||
"labeledArgs": {
|
||||
"offset": {
|
||||
"value": {
|
||||
"type": "Number",
|
||||
"value": 1.0,
|
||||
"ty": {
|
||||
"type": "Default",
|
||||
"len": {
|
||||
"type": "Inches"
|
||||
},
|
||||
"angle": {
|
||||
"type": "Degrees"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
432,
|
||||
441,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"name": "offsetPlane",
|
||||
"sourceRange": [
|
||||
405,
|
||||
442,
|
||||
0
|
||||
],
|
||||
"type": "StdLibCall",
|
||||
"unlabeledArg": {
|
||||
"value": {
|
||||
"type": "String",
|
||||
"value": "XZ"
|
||||
},
|
||||
"sourceRange": [
|
||||
417,
|
||||
421,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "UserDefinedFunctionCall",
|
||||
"name": "button",
|
||||
"functionSourceRange": [
|
||||
1046,
|
||||
1759,
|
||||
5
|
||||
],
|
||||
"unlabeledArg": null,
|
||||
"labeledArgs": {},
|
||||
"sourceRange": [
|
||||
338,
|
||||
443,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"labeledArgs": {
|
||||
"data": {
|
||||
"value": {
|
||||
"type": "Plane",
|
||||
"artifact_id": "[uuid]"
|
||||
},
|
||||
"sourceRange": [
|
||||
1105,
|
||||
1110,
|
||||
5
|
||||
]
|
||||
}
|
||||
},
|
||||
"name": "startSketchOn",
|
||||
"sourceRange": [
|
||||
1091,
|
||||
1111,
|
||||
5
|
||||
],
|
||||
"type": "StdLibCall",
|
||||
"unlabeledArg": null
|
||||
},
|
||||
{
|
||||
"labeledArgs": {
|
||||
"length": {
|
||||
"value": {
|
||||
"type": "Number",
|
||||
"value": 0.04,
|
||||
"ty": {
|
||||
"type": "Default",
|
||||
"len": {
|
||||
"type": "Inches"
|
||||
},
|
||||
"angle": {
|
||||
"type": "Degrees"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
1526,
|
||||
1541,
|
||||
5
|
||||
]
|
||||
}
|
||||
},
|
||||
"name": "extrude",
|
||||
"sourceRange": [
|
||||
1495,
|
||||
1542,
|
||||
5
|
||||
],
|
||||
"type": "StdLibCall",
|
||||
"unlabeledArg": {
|
||||
"value": {
|
||||
"type": "Sketch",
|
||||
"value": {
|
||||
"artifactId": "[uuid]"
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
1503,
|
||||
1515,
|
||||
5
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"labeledArgs": {
|
||||
"length": {
|
||||
"value": {
|
||||
"type": "Number",
|
||||
"value": 0.05,
|
||||
"ty": {
|
||||
"type": "Default",
|
||||
"len": {
|
||||
"type": "Inches"
|
||||
},
|
||||
"angle": {
|
||||
"type": "Degrees"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
1577,
|
||||
1581,
|
||||
5
|
||||
]
|
||||
},
|
||||
"tags": {
|
||||
"value": {
|
||||
"type": "Array",
|
||||
"value": [
|
||||
{
|
||||
"type": "Uuid",
|
||||
"value": "[uuid]"
|
||||
},
|
||||
{
|
||||
"type": "Uuid",
|
||||
"value": "[uuid]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
1599,
|
||||
1686,
|
||||
5
|
||||
]
|
||||
}
|
||||
},
|
||||
"name": "chamfer",
|
||||
"sourceRange": [
|
||||
1550,
|
||||
1695,
|
||||
5
|
||||
],
|
||||
"type": "StdLibCall",
|
||||
"unlabeledArg": {
|
||||
"value": {
|
||||
"type": "Solid",
|
||||
"value": {
|
||||
"artifactId": "[uuid]"
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "UserDefinedFunctionReturn"
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,46 @@
|
||||
// Walkie talkie talk button
|
||||
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Import constants
|
||||
import width, thickness, talkButtonSideLength, talkButtonHeight from "globals.kcl"
|
||||
|
||||
talkButtonPlane = {
|
||||
plane = {
|
||||
origin = {
|
||||
x = width / 2,
|
||||
y = -thickness / 2,
|
||||
z = .5
|
||||
},
|
||||
xAxis = { x = 0, y = 1, z = 0 },
|
||||
yAxis = { x = 0, y = 0, z = 1 },
|
||||
zAxis = { x = 1, y = 0, z = 0 }
|
||||
}
|
||||
}
|
||||
|
||||
// Create the talk button sketch
|
||||
talkButtonSketch = startSketchOn(talkButtonPlane)
|
||||
|> startProfileAt([
|
||||
-talkButtonSideLength / 2,
|
||||
talkButtonSideLength / 2
|
||||
], %)
|
||||
|> xLine(talkButtonSideLength, %, $tag1)
|
||||
|> yLine(-talkButtonSideLength, %, $tag2)
|
||||
|> xLine(-talkButtonSideLength, %, $tag3)
|
||||
|> close(tag = $tag4)
|
||||
|
||||
// Create the talk button and apply fillets
|
||||
extrude(talkButtonSketch, length = talkButtonHeight)
|
||||
|> fillet(
|
||||
radius = 0.050,
|
||||
tags = [
|
||||
getNextAdjacentEdge(tag1),
|
||||
getNextAdjacentEdge(tag2),
|
||||
getNextAdjacentEdge(tag3),
|
||||
getNextAdjacentEdge(tag4)
|
||||
]
|
||||
)
|
||||
|> appearance(color = '#D0FF01', metalness = 90, roughness = 90)
|
||||
Reference in New Issue
Block a user