Compare commits
14 Commits
achalmers/
...
v0.24.2
Author | SHA1 | Date | |
---|---|---|---|
60e187bd3e | |||
c64175425b | |||
36464e6984 | |||
2f0002e53c | |||
482833c88f | |||
d9d0a72306 | |||
65cd9fab64 | |||
5e41e382ce | |||
1e3cb00092 | |||
d1a2bd01ca | |||
aca13d087b | |||
fcdde3e482 | |||
a1df3d0ffc | |||
1852e6167b |
13
README.md
@ -135,9 +135,18 @@ After it runs you should just need to push the push the branch and open a PR (it
|
|||||||
|
|
||||||
The PR may serve as a place to discuss the human-readable changelog and extra QA.
|
The PR may serve as a place to discuss the human-readable changelog and extra QA.
|
||||||
|
|
||||||
2. Merge the PR
|
2. Smoke test the artifact from the above PR
|
||||||
|
We don't have a strict process, but click around and check for anything obvious
|
||||||
|
One of the artifacts is called updater-test, because we don't have a way to test this fully automated, we have a semi-automated process.
|
||||||
|
|
||||||
|
Download updater-test zip file, install the app, run it, expect an updater prompt to v0.99.99, install it and check that the app comes back at that version (on both macOS and Windows).
|
||||||
|
|
||||||
|
3. Merge the PR
|
||||||
|
|
||||||
|
|
||||||
|
4. Profit (A new Action kicks in at https://github.com/KittyCAD/modeling-app/actions if the PR was correctly named)
|
||||||
|
|
||||||
|
|
||||||
3. Profit (A new Action kicks in at https://github.com/KittyCAD/modeling-app/actions if the PR was correctly named)
|
|
||||||
|
|
||||||
## Fuzzing the parser
|
## Fuzzing the parser
|
||||||
|
|
||||||
|
@ -3099,6 +3099,49 @@ const sketch002 = startSketchOn(extrude001, $seg01)
|
|||||||
).not.toBeDisabled()
|
).not.toBeDisabled()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('Fillet button states test', async ({ page }) => {
|
||||||
|
const u = await getUtils(page)
|
||||||
|
await page.addInitScript(async () => {
|
||||||
|
localStorage.setItem(
|
||||||
|
'persistCode',
|
||||||
|
`const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([-5, -5], %)
|
||||||
|
|> line([0, 10], %)
|
||||||
|
|> line([10, 0], %)
|
||||||
|
|> line([0, -10], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
await page.setViewportSize({ width: 1000, height: 500 })
|
||||||
|
await u.waitForAuthSkipAppStart()
|
||||||
|
await u.openDebugPanel()
|
||||||
|
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||||
|
await u.closeDebugPanel()
|
||||||
|
|
||||||
|
const selectSegment = () => page.getByText(`line([10, 0], %)`).click()
|
||||||
|
const selectClose = () => page.getByText(`close(%)`).click()
|
||||||
|
const clickEmpty = () => page.mouse.click(950, 100)
|
||||||
|
|
||||||
|
// expect fillet button without any bodies in the scene
|
||||||
|
await selectSegment()
|
||||||
|
await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
|
||||||
|
await clickEmpty()
|
||||||
|
await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
|
||||||
|
|
||||||
|
// test fillet button with the body in the scene
|
||||||
|
const codeToAdd = `${await u.codeLocator.allInnerTexts()}
|
||||||
|
const extrude001 = extrude(10, sketch001)`
|
||||||
|
await u.codeLocator.fill(codeToAdd)
|
||||||
|
await selectSegment()
|
||||||
|
await expect(page.getByRole('button', { name: 'Fillet' })).toBeEnabled()
|
||||||
|
await selectClose()
|
||||||
|
await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
|
||||||
|
await clickEmpty()
|
||||||
|
await expect(page.getByRole('button', { name: 'Fillet' })).toBeEnabled()
|
||||||
|
})
|
||||||
|
|
||||||
const removeAfterFirstParenthesis = (inputString: string) => {
|
const removeAfterFirstParenthesis = (inputString: string) => {
|
||||||
const index = inputString.indexOf('(')
|
const index = inputString.indexOf('(')
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
@ -3500,11 +3543,62 @@ test.describe('Command bar tests', () => {
|
|||||||
`const extrude001 = extrude(${KCL_DEFAULT_LENGTH}, sketch001)`
|
`const extrude001 = extrude(${KCL_DEFAULT_LENGTH}, sketch001)`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
test('Command bar works and can change a setting', async ({ page }) => {
|
|
||||||
|
test('Fillet from command bar', async ({ page }) => {
|
||||||
|
await page.addInitScript(async () => {
|
||||||
|
localStorage.setItem(
|
||||||
|
'persistCode',
|
||||||
|
`const sketch001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-5, -5], %)
|
||||||
|
|> line([0, 10], %)
|
||||||
|
|> line([10, 0], %)
|
||||||
|
|> line([0, -10], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(-10, sketch001)`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const u = await getUtils(page)
|
||||||
|
await page.setViewportSize({ width: 1000, height: 500 })
|
||||||
|
await u.waitForAuthSkipAppStart()
|
||||||
|
await u.openDebugPanel()
|
||||||
|
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||||
|
await u.closeDebugPanel()
|
||||||
|
|
||||||
|
const selectSegment = () => page.getByText(`line([0, -10], %)`).click()
|
||||||
|
|
||||||
|
await selectSegment()
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await page.getByRole('button', { name: 'Fillet' }).click()
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await page.keyboard.press('Enter')
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await page.keyboard.press('Enter')
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await expect(page.locator('.cm-activeLine')).toContainText(
|
||||||
|
`fillet({ radius: ${KCL_DEFAULT_LENGTH}, tags: [seg01] }, %)`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Command bar can change a setting, and switch back and forth between arguments', async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
await page.setViewportSize({ width: 1200, height: 500 })
|
||||||
await u.waitForAuthSkipAppStart()
|
await u.waitForAuthSkipAppStart()
|
||||||
|
|
||||||
|
const commandBarButton = page.getByRole('button', { name: 'Commands' })
|
||||||
|
const cmdSearchBar = page.getByPlaceholder('Search commands')
|
||||||
|
const themeOption = page.getByRole('option', {
|
||||||
|
name: 'theme',
|
||||||
|
exact: false,
|
||||||
|
})
|
||||||
|
const commandLevelArgButton = page.getByRole('button', { name: 'level' })
|
||||||
|
const commandThemeArgButton = page.getByRole('button', { name: 'value' })
|
||||||
|
// This selector changes after we set the setting
|
||||||
|
let commandOptionInput = page.getByPlaceholder('Select an option')
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('button', { name: 'Start Sketch' })
|
page.getByRole('button', { name: 'Start Sketch' })
|
||||||
).not.toBeDisabled()
|
).not.toBeDisabled()
|
||||||
@ -3515,23 +3609,17 @@ test.describe('Command bar tests', () => {
|
|||||||
.or(page.getByRole('button', { name: '⌘K' }))
|
.or(page.getByRole('button', { name: '⌘K' }))
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
let cmdSearchBar = page.getByPlaceholder('Search commands')
|
|
||||||
await expect(cmdSearchBar).toBeVisible()
|
await expect(cmdSearchBar).toBeVisible()
|
||||||
await page.keyboard.press('Escape')
|
await page.keyboard.press('Escape')
|
||||||
cmdSearchBar = page.getByPlaceholder('Search commands')
|
|
||||||
await expect(cmdSearchBar).not.toBeVisible()
|
await expect(cmdSearchBar).not.toBeVisible()
|
||||||
|
|
||||||
// Now try the same, but with the keyboard shortcut, check focus
|
// Now try the same, but with the keyboard shortcut, check focus
|
||||||
await page.keyboard.press('Meta+K')
|
await page.keyboard.press('Meta+K')
|
||||||
cmdSearchBar = page.getByPlaceholder('Search commands')
|
|
||||||
await expect(cmdSearchBar).toBeVisible()
|
await expect(cmdSearchBar).toBeVisible()
|
||||||
await expect(cmdSearchBar).toBeFocused()
|
await expect(cmdSearchBar).toBeFocused()
|
||||||
|
|
||||||
// Try typing in the command bar
|
// Try typing in the command bar
|
||||||
await page.keyboard.type('theme')
|
await cmdSearchBar.fill('theme')
|
||||||
const themeOption = page.getByRole('option', {
|
|
||||||
name: 'Settings · app · theme',
|
|
||||||
})
|
|
||||||
await expect(themeOption).toBeVisible()
|
await expect(themeOption).toBeVisible()
|
||||||
await themeOption.click()
|
await themeOption.click()
|
||||||
const themeInput = page.getByPlaceholder('Select an option')
|
const themeInput = page.getByPlaceholder('Select an option')
|
||||||
@ -3553,6 +3641,24 @@ test.describe('Command bar tests', () => {
|
|||||||
).toBeVisible()
|
).toBeVisible()
|
||||||
// Check that the theme changed
|
// Check that the theme changed
|
||||||
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
|
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
|
||||||
|
|
||||||
|
commandOptionInput = page.getByPlaceholder('system')
|
||||||
|
|
||||||
|
// Test case for https://github.com/KittyCAD/modeling-app/issues/2882
|
||||||
|
await commandBarButton.click()
|
||||||
|
await cmdSearchBar.focus()
|
||||||
|
await cmdSearchBar.fill('theme')
|
||||||
|
await themeOption.click()
|
||||||
|
await expect(commandThemeArgButton).toBeDisabled()
|
||||||
|
await commandOptionInput.focus()
|
||||||
|
await commandOptionInput.fill('lig')
|
||||||
|
await commandLevelArgButton.click()
|
||||||
|
await expect(commandLevelArgButton).toBeDisabled()
|
||||||
|
|
||||||
|
// Test case for https://github.com/KittyCAD/modeling-app/issues/2881
|
||||||
|
await commandThemeArgButton.click()
|
||||||
|
await expect(commandThemeArgButton).toBeDisabled()
|
||||||
|
await expect(commandLevelArgButton).toHaveText('level: project')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('Command bar keybinding works from code editor and can change a setting', async ({
|
test('Command bar keybinding works from code editor and can change a setting', async ({
|
||||||
@ -3577,7 +3683,7 @@ test.describe('Command bar tests', () => {
|
|||||||
await expect(cmdSearchBar).toBeFocused()
|
await expect(cmdSearchBar).toBeFocused()
|
||||||
|
|
||||||
// Try typing in the command bar
|
// Try typing in the command bar
|
||||||
await page.keyboard.type('theme')
|
await cmdSearchBar.fill('theme')
|
||||||
const themeOption = page.getByRole('option', {
|
const themeOption = page.getByRole('option', {
|
||||||
name: 'Settings · app · theme',
|
name: 'Settings · app · theme',
|
||||||
})
|
})
|
||||||
@ -3648,7 +3754,9 @@ test.describe('Command bar tests', () => {
|
|||||||
await page.mouse.click(700, 200)
|
await page.mouse.click(700, 200)
|
||||||
|
|
||||||
// Assert that we're on the distance step
|
// Assert that we're on the distance step
|
||||||
await expect(page.getByRole('button', { name: 'distance' })).toBeDisabled()
|
await expect(
|
||||||
|
page.getByRole('button', { name: 'distance', exact: false })
|
||||||
|
).toBeDisabled()
|
||||||
|
|
||||||
// Assert that the an alternative variable name is chosen,
|
// Assert that the an alternative variable name is chosen,
|
||||||
// since the default variable name is already in use (distance)
|
// since the default variable name is already in use (distance)
|
||||||
@ -3663,11 +3771,12 @@ test.describe('Command bar tests', () => {
|
|||||||
|
|
||||||
// Review step and argument hotkeys
|
// Review step and argument hotkeys
|
||||||
await expect(submitButton).toBeEnabled()
|
await expect(submitButton).toBeEnabled()
|
||||||
await page.keyboard.press('Backspace')
|
await expect(submitButton).toBeFocused()
|
||||||
|
await submitButton.press('Backspace')
|
||||||
|
|
||||||
// Assert we're back on the distance step
|
// Assert we're back on the distance step
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('button', { name: 'Distance 5', exact: false })
|
page.getByRole('button', { name: 'distance', exact: false })
|
||||||
).toBeDisabled()
|
).toBeDisabled()
|
||||||
|
|
||||||
await continueButton.click()
|
await continueButton.click()
|
||||||
@ -3724,6 +3833,7 @@ const extrude001 = extrude(distance001, sketch001)`.replace(
|
|||||||
// Click in the scene a couple times to draw a line
|
// Click in the scene a couple times to draw a line
|
||||||
// so tangential arc is valid
|
// so tangential arc is valid
|
||||||
await page.mouse.click(700, 200)
|
await page.mouse.click(700, 200)
|
||||||
|
await page.mouse.move(700, 300, { steps: 5 })
|
||||||
await page.mouse.click(700, 300)
|
await page.mouse.click(700, 300)
|
||||||
|
|
||||||
// switch to tangential arc via command bar
|
// switch to tangential arc via command bar
|
||||||
@ -4682,10 +4792,10 @@ test.describe('Sketch tests', () => {
|
|||||||
// click extrude
|
// click extrude
|
||||||
await page.getByRole('button', { name: 'Extrude' }).click()
|
await page.getByRole('button', { name: 'Extrude' }).click()
|
||||||
|
|
||||||
// sketch selection should already have been made. "Selection 1 face" only show up when the selection has been made already
|
// sketch selection should already have been made. "Selection: 1 face" only show up when the selection has been made already
|
||||||
// otherwise the cmdbar would be waiting for a selection.
|
// otherwise the cmdbar would be waiting for a selection.
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('button', { name: 'Selection 1 face' })
|
page.getByRole('button', { name: 'selection : 1 face', exact: false })
|
||||||
).toBeVisible()
|
).toBeVisible()
|
||||||
})
|
})
|
||||||
test("Existing sketch with bad code delete user's code", async ({ page }) => {
|
test("Existing sketch with bad code delete user's code", async ({ page }) => {
|
||||||
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "untitled-app",
|
"name": "untitled-app",
|
||||||
"version": "0.24.1",
|
"version": "0.24.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.17.0",
|
"@codemirror/autocomplete": "^6.17.0",
|
||||||
|
@ -30,7 +30,7 @@ import { URI } from 'vscode-uri'
|
|||||||
import { LanguageServerClient } from '../client'
|
import { LanguageServerClient } from '../client'
|
||||||
import { CompletionItemKindMap } from './autocomplete'
|
import { CompletionItemKindMap } from './autocomplete'
|
||||||
import { addToken, SemanticToken } from './semantic-tokens'
|
import { addToken, SemanticToken } from './semantic-tokens'
|
||||||
import { deferExecution, posToOffset, formatMarkdownContents } from './util'
|
import { posToOffset, formatMarkdownContents } from './util'
|
||||||
import lspAutocompleteExt from './autocomplete'
|
import lspAutocompleteExt from './autocomplete'
|
||||||
import lspHoverExt from './hover'
|
import lspHoverExt from './hover'
|
||||||
import lspFormatExt from './format'
|
import lspFormatExt from './format'
|
||||||
|
@ -80,5 +80,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"productName": "Zoo Modeling App",
|
"productName": "Zoo Modeling App",
|
||||||
"version": "0.24.1"
|
"version": "0.24.2"
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
canRectangleTool,
|
canRectangleTool,
|
||||||
isEditingExistingSketch,
|
isEditingExistingSketch,
|
||||||
} from 'machines/modelingMachine'
|
} from 'machines/modelingMachine'
|
||||||
|
import { DEV } from 'env'
|
||||||
|
|
||||||
export function Toolbar({
|
export function Toolbar({
|
||||||
className = '',
|
className = '',
|
||||||
@ -118,6 +119,16 @@ export function Toolbar({
|
|||||||
}),
|
}),
|
||||||
{ enabled: !disableAllButtons, scopes: ['modeling'] }
|
{ enabled: !disableAllButtons, scopes: ['modeling'] }
|
||||||
)
|
)
|
||||||
|
const disableFillet = !state.can('Fillet') || disableAllButtons
|
||||||
|
useHotkeys(
|
||||||
|
'f',
|
||||||
|
() =>
|
||||||
|
commandBarSend({
|
||||||
|
type: 'Find and select command',
|
||||||
|
data: { name: 'Fillet', groupId: 'modeling' },
|
||||||
|
}),
|
||||||
|
{ enabled: !disableFillet, scopes: ['modeling'] }
|
||||||
|
)
|
||||||
|
|
||||||
function handleToolbarButtonsWheelEvent(ev: WheelEvent<HTMLSpanElement>) {
|
function handleToolbarButtonsWheelEvent(ev: WheelEvent<HTMLSpanElement>) {
|
||||||
const span = toolbarButtonsRef.current
|
const span = toolbarButtonsRef.current
|
||||||
@ -404,6 +415,36 @@ export function Toolbar({
|
|||||||
</ActionButton>
|
</ActionButton>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
|
{state.matches('idle') && (DEV || (window as any)._enableFillet) && (
|
||||||
|
<li className="contents">
|
||||||
|
<ActionButton
|
||||||
|
className={buttonClassName}
|
||||||
|
Element="button"
|
||||||
|
onClick={() =>
|
||||||
|
commandBarSend({
|
||||||
|
type: 'Find and select command',
|
||||||
|
data: { name: 'Fillet', groupId: 'modeling' },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
disabled={disableFillet}
|
||||||
|
title={disableFillet ? 'fillet' : "edge can't be filleted"}
|
||||||
|
iconStart={{
|
||||||
|
icon: 'fillet', // todo: add fillet icon
|
||||||
|
iconClassName,
|
||||||
|
bgClassName,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Fillet
|
||||||
|
<Tooltip
|
||||||
|
delay={1250}
|
||||||
|
position="bottom"
|
||||||
|
className="!px-2 !text-xs"
|
||||||
|
>
|
||||||
|
Shortcut: F
|
||||||
|
</Tooltip>
|
||||||
|
</ActionButton>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
</menu>
|
</menu>
|
||||||
)
|
)
|
||||||
|
@ -41,6 +41,7 @@ function CommandArgOptionInput({
|
|||||||
)
|
)
|
||||||
const inputRef = useRef<HTMLInputElement>(null)
|
const inputRef = useRef<HTMLInputElement>(null)
|
||||||
const formRef = useRef<HTMLFormElement>(null)
|
const formRef = useRef<HTMLFormElement>(null)
|
||||||
|
const [shouldSubmitOnChange, setShouldSubmitOnChange] = useState(false)
|
||||||
const [selectedOption, setSelectedOption] = useState<
|
const [selectedOption, setSelectedOption] = useState<
|
||||||
CommandArgumentOption<unknown>
|
CommandArgumentOption<unknown>
|
||||||
>(currentOption || resolvedOptions[0])
|
>(currentOption || resolvedOptions[0])
|
||||||
@ -82,8 +83,10 @@ function CommandArgOptionInput({
|
|||||||
// We deal with the whole option object internally
|
// We deal with the whole option object internally
|
||||||
setSelectedOption(option)
|
setSelectedOption(option)
|
||||||
|
|
||||||
// But we only submit the value
|
// But we only submit the value itself
|
||||||
onSubmit(option.value)
|
if (shouldSubmitOnChange) {
|
||||||
|
onSubmit(option.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||||
@ -94,7 +97,18 @@ function CommandArgOptionInput({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form id="arg-form" onSubmit={handleSubmit} ref={formRef}>
|
<form
|
||||||
|
id="arg-form"
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
ref={formRef}
|
||||||
|
onKeyDownCapture={(e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
setShouldSubmitOnChange(true)
|
||||||
|
} else {
|
||||||
|
setShouldSubmitOnChange(false)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Combobox
|
<Combobox
|
||||||
value={selectedOption}
|
value={selectedOption}
|
||||||
onChange={handleSelectOption}
|
onChange={handleSelectOption}
|
||||||
@ -118,6 +132,12 @@ function CommandArgOptionInput({
|
|||||||
if (event.key === 'Backspace' && !event.currentTarget.value) {
|
if (event.key === 'Backspace' && !event.currentTarget.value) {
|
||||||
stepBack()
|
stepBack()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
setShouldSubmitOnChange(true)
|
||||||
|
} else {
|
||||||
|
setShouldSubmitOnChange(false)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
value={query}
|
value={query}
|
||||||
placeholder={
|
placeholder={
|
||||||
@ -136,6 +156,9 @@ function CommandArgOptionInput({
|
|||||||
<Combobox.Options
|
<Combobox.Options
|
||||||
static
|
static
|
||||||
className="overflow-y-auto max-h-96 cursor-pointer"
|
className="overflow-y-auto max-h-96 cursor-pointer"
|
||||||
|
onMouseDown={() => {
|
||||||
|
setShouldSubmitOnChange(true)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{filteredOptions?.map((option) => (
|
{filteredOptions?.map((option) => (
|
||||||
<Combobox.Option
|
<Combobox.Option
|
||||||
|
@ -114,6 +114,7 @@ function CommandBarHeader({ children }: React.PropsWithChildren<{}>) {
|
|||||||
>
|
>
|
||||||
{argName}
|
{argName}
|
||||||
</span>
|
</span>
|
||||||
|
<span className="sr-only">: </span>
|
||||||
{argValue ? (
|
{argValue ? (
|
||||||
arg.inputType === 'selection' ? (
|
arg.inputType === 'selection' ? (
|
||||||
getSelectionTypeDisplayText(argValue as Selections)
|
getSelectionTypeDisplayText(argValue as Selections)
|
||||||
|
@ -3,6 +3,7 @@ import { useCommandsContext } from 'hooks/useCommandsContext'
|
|||||||
import { useKclContext } from 'lang/KclProvider'
|
import { useKclContext } from 'lang/KclProvider'
|
||||||
import { CommandArgument } from 'lib/commandTypes'
|
import { CommandArgument } from 'lib/commandTypes'
|
||||||
import {
|
import {
|
||||||
|
Selection,
|
||||||
canSubmitSelectionArg,
|
canSubmitSelectionArg,
|
||||||
getSelectionType,
|
getSelectionType,
|
||||||
getSelectionTypeDisplayText,
|
getSelectionTypeDisplayText,
|
||||||
@ -11,6 +12,25 @@ import { modelingMachine } from 'machines/modelingMachine'
|
|||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { StateFrom } from 'xstate'
|
import { StateFrom } from 'xstate'
|
||||||
|
|
||||||
|
const semanticEntityNames: { [key: string]: Array<Selection['type']> } = {
|
||||||
|
face: ['extrude-wall', 'start-cap', 'end-cap'],
|
||||||
|
edge: ['edge', 'line', 'arc'],
|
||||||
|
point: ['point', 'line-end', 'line-mid'],
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSemanticSelectionType(selectionType: Array<Selection['type']>) {
|
||||||
|
const semanticSelectionType = new Set()
|
||||||
|
selectionType.forEach((type) => {
|
||||||
|
Object.entries(semanticEntityNames).forEach(([entity, entityTypes]) => {
|
||||||
|
if (entityTypes.includes(type)) {
|
||||||
|
semanticSelectionType.add(entity)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return Array.from(semanticSelectionType)
|
||||||
|
}
|
||||||
|
|
||||||
const selectionSelector = (snapshot: StateFrom<typeof modelingMachine>) =>
|
const selectionSelector = (snapshot: StateFrom<typeof modelingMachine>) =>
|
||||||
snapshot.context.selectionRanges
|
snapshot.context.selectionRanges
|
||||||
|
|
||||||
@ -85,7 +105,9 @@ function CommandBarSelectionInput({
|
|||||||
>
|
>
|
||||||
{canSubmitSelection
|
{canSubmitSelection
|
||||||
? getSelectionTypeDisplayText(selection) + ' selected'
|
? getSelectionTypeDisplayText(selection) + ' selected'
|
||||||
: `Please select ${arg.multiple ? 'one or more faces' : 'one face'}`}
|
: `Please select ${
|
||||||
|
arg.multiple ? 'one or more ' : 'one '
|
||||||
|
}${getSemanticSelectionType(arg.selectionTypes).join(' or ')}`}
|
||||||
<input
|
<input
|
||||||
id="selection"
|
id="selection"
|
||||||
name="selection"
|
name="selection"
|
||||||
|
@ -187,6 +187,22 @@ const CustomIconMap = {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
|
fillet: (
|
||||||
|
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M8 5H5V15H15V12C15 8.13401 11.866 5 8 5ZM5 4H4V5V15V16H5H15H16V15V12C16 7.58172 12.4183 4 8 4H5Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M4.5 3.5H5.5H8.5C12.9183 3.5 16.5 7.08172 16.5 11.5V14.5V15.5H16V12C16 7.58172 12.4182 4 7.99996 4H4.5V3.5Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
file: (
|
file: (
|
||||||
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path
|
<path
|
||||||
|
@ -72,6 +72,7 @@ import { uuidv4 } from 'lib/utils'
|
|||||||
import { err, trap } from 'lib/trap'
|
import { err, trap } from 'lib/trap'
|
||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
import { modelingMachineEvent } from 'editor/manager'
|
import { modelingMachineEvent } from 'editor/manager'
|
||||||
|
import { hasValidFilletSelection } from 'lang/modifyAst/addFillet'
|
||||||
|
|
||||||
type MachineContext<T extends AnyStateMachine> = {
|
type MachineContext<T extends AnyStateMachine> = {
|
||||||
state: StateFrom<T>
|
state: StateFrom<T>
|
||||||
@ -164,7 +165,7 @@ export const ModelingMachineProvider = ({
|
|||||||
|
|
||||||
store.videoElement?.pause()
|
store.videoElement?.pause()
|
||||||
kclManager.executeCode(true).then(() => {
|
kclManager.executeCode(true).then(() => {
|
||||||
if (engineCommandManager.engineConnection?.freezeFrame) return
|
if (engineCommandManager.engineConnection?.idleMode) return
|
||||||
|
|
||||||
store.videoElement?.play()
|
store.videoElement?.play()
|
||||||
})
|
})
|
||||||
@ -444,6 +445,12 @@ export const ModelingMachineProvider = ({
|
|||||||
if (selectionRanges.codeBasedSelections.length <= 0) return false
|
if (selectionRanges.codeBasedSelections.length <= 0) return false
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
'has valid fillet selection': ({ selectionRanges }) =>
|
||||||
|
hasValidFilletSelection({
|
||||||
|
selectionRanges,
|
||||||
|
ast: kclManager.ast,
|
||||||
|
code: codeManager.code,
|
||||||
|
}),
|
||||||
'Selection is on face': ({ selectionRanges }, { data }) => {
|
'Selection is on face': ({ selectionRanges }, { data }) => {
|
||||||
if (data?.forceNewSketch) return false
|
if (data?.forceNewSketch) return false
|
||||||
if (!isSingleCursorInPipe(selectionRanges, kclManager.ast))
|
if (!isSingleCursorInPipe(selectionRanges, kclManager.ast))
|
||||||
@ -494,7 +501,6 @@ export const ModelingMachineProvider = ({
|
|||||||
kclManager.ast,
|
kclManager.ast,
|
||||||
data.sketchPathToNode,
|
data.sketchPathToNode,
|
||||||
data.extrudePathToNode,
|
data.extrudePathToNode,
|
||||||
kclManager.programMemory,
|
|
||||||
data.cap
|
data.cap
|
||||||
)
|
)
|
||||||
if (trap(sketched)) return Promise.reject(sketched)
|
if (trap(sketched)) return Promise.reject(sketched)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { DEV } from 'env'
|
|
||||||
import { MouseEventHandler, useEffect, useRef, useState } from 'react'
|
import { MouseEventHandler, useEffect, useRef, useState } from 'react'
|
||||||
import { getNormalisedCoordinates } from '../lib/utils'
|
import { getNormalisedCoordinates } from '../lib/utils'
|
||||||
import Loading from './Loading'
|
import Loading from './Loading'
|
||||||
@ -11,6 +10,10 @@ import { btnName } from 'lib/cameraControls'
|
|||||||
import { sendSelectEventToEngine } from 'lib/selections'
|
import { sendSelectEventToEngine } from 'lib/selections'
|
||||||
import { kclManager, engineCommandManager, sceneInfra } from 'lib/singletons'
|
import { kclManager, engineCommandManager, sceneInfra } from 'lib/singletons'
|
||||||
import { useAppStream } from 'AppState'
|
import { useAppStream } from 'AppState'
|
||||||
|
import {
|
||||||
|
EngineConnectionStateType,
|
||||||
|
DisconnectingType,
|
||||||
|
} from 'lang/std/engineConnection'
|
||||||
|
|
||||||
export const Stream = () => {
|
export const Stream = () => {
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
@ -20,15 +23,28 @@ export const Stream = () => {
|
|||||||
const { settings } = useSettingsAuthContext()
|
const { settings } = useSettingsAuthContext()
|
||||||
const { state, send, context } = useModelingContext()
|
const { state, send, context } = useModelingContext()
|
||||||
const { mediaStream } = useAppStream()
|
const { mediaStream } = useAppStream()
|
||||||
const { overallState } = useNetworkContext()
|
const { overallState, immediateState } = useNetworkContext()
|
||||||
const [isFreezeFrame, setIsFreezeFrame] = useState(false)
|
const [isFreezeFrame, setIsFreezeFrame] = useState(false)
|
||||||
|
const [isPaused, setIsPaused] = useState(false)
|
||||||
|
|
||||||
const IDLE = true
|
const IDLE = settings.context.app.streamIdleMode.current
|
||||||
|
|
||||||
const isNetworkOkay =
|
const isNetworkOkay =
|
||||||
overallState === NetworkHealthState.Ok ||
|
overallState === NetworkHealthState.Ok ||
|
||||||
overallState === NetworkHealthState.Weak
|
overallState === NetworkHealthState.Weak
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
immediateState.type === EngineConnectionStateType.Disconnecting &&
|
||||||
|
immediateState.value.type === DisconnectingType.Pause
|
||||||
|
) {
|
||||||
|
setIsPaused(true)
|
||||||
|
}
|
||||||
|
if (immediateState.type === EngineConnectionStateType.Connecting) {
|
||||||
|
setIsPaused(false)
|
||||||
|
}
|
||||||
|
}, [immediateState])
|
||||||
|
|
||||||
// Linux has a default behavior to paste text on middle mouse up
|
// Linux has a default behavior to paste text on middle mouse up
|
||||||
// This adds a listener to block that pasting if the click target
|
// This adds a listener to block that pasting if the click target
|
||||||
// is not a text input, so users can move in the 3D scene with
|
// is not a text input, so users can move in the 3D scene with
|
||||||
@ -65,25 +81,28 @@ export const Stream = () => {
|
|||||||
sceneInfra.modelingSend({ type: 'Cancel' })
|
sceneInfra.modelingSend({ type: 'Cancel' })
|
||||||
// Give video time to pause
|
// Give video time to pause
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
engineCommandManager.tearDown()
|
engineCommandManager.tearDown({ idleMode: true })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Teardown everything if we go hidden or reconnect
|
const onVisibilityChange = () => {
|
||||||
if (IDLE && DEV) {
|
if (globalThis.window.document.visibilityState === 'hidden') {
|
||||||
if (globalThis?.window?.document) {
|
clearTimeout(timeoutIdIdleA)
|
||||||
globalThis.window.document.onvisibilitychange = () => {
|
timeoutIdIdleA = setTimeout(teardown, IDLE_TIME_MS)
|
||||||
if (globalThis.window.document.visibilityState === 'hidden') {
|
} else if (!engineCommandManager.engineConnection?.isReady()) {
|
||||||
clearTimeout(timeoutIdIdleA)
|
clearTimeout(timeoutIdIdleA)
|
||||||
timeoutIdIdleA = setTimeout(teardown, IDLE_TIME_MS)
|
engineCommandManager.engineConnection?.connect(true)
|
||||||
} else if (!engineCommandManager.engineConnection?.isReady()) {
|
|
||||||
clearTimeout(timeoutIdIdleA)
|
|
||||||
engineCommandManager.engineConnection?.connect(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Teardown everything if we go hidden or reconnect
|
||||||
|
if (IDLE) {
|
||||||
|
globalThis?.window?.document?.addEventListener(
|
||||||
|
'visibilitychange',
|
||||||
|
onVisibilityChange
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
let timeoutIdIdleB: ReturnType<typeof setTimeout> | undefined = undefined
|
let timeoutIdIdleB: ReturnType<typeof setTimeout> | undefined = undefined
|
||||||
|
|
||||||
const onAnyInput = () => {
|
const onAnyInput = () => {
|
||||||
@ -93,7 +112,7 @@ export const Stream = () => {
|
|||||||
timeoutIdIdleB = setTimeout(teardown, IDLE_TIME_MS)
|
timeoutIdIdleB = setTimeout(teardown, IDLE_TIME_MS)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IDLE && DEV) {
|
if (IDLE) {
|
||||||
globalThis?.window?.document?.addEventListener('keydown', onAnyInput)
|
globalThis?.window?.document?.addEventListener('keydown', onAnyInput)
|
||||||
globalThis?.window?.document?.addEventListener('mousemove', onAnyInput)
|
globalThis?.window?.document?.addEventListener('mousemove', onAnyInput)
|
||||||
globalThis?.window?.document?.addEventListener('mousedown', onAnyInput)
|
globalThis?.window?.document?.addEventListener('mousedown', onAnyInput)
|
||||||
@ -101,7 +120,7 @@ export const Stream = () => {
|
|||||||
globalThis?.window?.document?.addEventListener('touchstart', onAnyInput)
|
globalThis?.window?.document?.addEventListener('touchstart', onAnyInput)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IDLE && DEV) {
|
if (IDLE) {
|
||||||
timeoutIdIdleB = setTimeout(teardown, IDLE_TIME_MS)
|
timeoutIdIdleB = setTimeout(teardown, IDLE_TIME_MS)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +128,14 @@ export const Stream = () => {
|
|||||||
globalThis?.window?.document?.removeEventListener('paste', handlePaste, {
|
globalThis?.window?.document?.removeEventListener('paste', handlePaste, {
|
||||||
capture: true,
|
capture: true,
|
||||||
})
|
})
|
||||||
if (IDLE && DEV) {
|
if (IDLE) {
|
||||||
|
clearTimeout(timeoutIdIdleA)
|
||||||
|
clearTimeout(timeoutIdIdleB)
|
||||||
|
|
||||||
|
globalThis?.window?.document?.removeEventListener(
|
||||||
|
'visibilitychange',
|
||||||
|
onVisibilityChange
|
||||||
|
)
|
||||||
globalThis?.window?.document?.removeEventListener('keydown', onAnyInput)
|
globalThis?.window?.document?.removeEventListener('keydown', onAnyInput)
|
||||||
globalThis?.window?.document?.removeEventListener(
|
globalThis?.window?.document?.removeEventListener(
|
||||||
'mousemove',
|
'mousemove',
|
||||||
@ -126,7 +152,7 @@ export const Stream = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [])
|
}, [IDLE])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsFirstRender(kclManager.isFirstRender)
|
setIsFirstRender(kclManager.isFirstRender)
|
||||||
@ -249,6 +275,32 @@ export const Stream = () => {
|
|||||||
<ClientSideScene
|
<ClientSideScene
|
||||||
cameraControls={settings.context.modeling.mouseControls.current}
|
cameraControls={settings.context.modeling.mouseControls.current}
|
||||||
/>
|
/>
|
||||||
|
{isPaused && (
|
||||||
|
<div className="text-center absolute inset-0">
|
||||||
|
<div
|
||||||
|
className="flex flex-col items-center justify-center h-screen"
|
||||||
|
data-testid="paused"
|
||||||
|
>
|
||||||
|
<div className="border-primary border p-2 rounded-sm">
|
||||||
|
<svg
|
||||||
|
width="8"
|
||||||
|
height="12"
|
||||||
|
viewBox="0 0 8 12"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M2 12V0H0V12H2ZM8 12V0H6V12H8Z"
|
||||||
|
fill="var(--primary)"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<p className="text-base mt-2 text-primary bold">Paused</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{(!isNetworkOkay || isLoading || isFirstRender) && !isFreezeFrame && (
|
{(!isNetworkOkay || isLoading || isFirstRender) && !isFreezeFrame && (
|
||||||
<div className="text-center absolute inset-0">
|
<div className="text-center absolute inset-0">
|
||||||
<Loading>
|
<Loading>
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
import { createContext, useContext } from 'react'
|
import { createContext, useContext } from 'react'
|
||||||
import {
|
import {
|
||||||
ConnectingTypeGroup,
|
ConnectingTypeGroup,
|
||||||
|
EngineConnectionStateType,
|
||||||
|
EngineConnectionState,
|
||||||
initialConnectingTypeGroupState,
|
initialConnectingTypeGroupState,
|
||||||
} from '../lang/std/engineConnection'
|
} from '../lang/std/engineConnection'
|
||||||
import { NetworkStatus, NetworkHealthState } from './useNetworkStatus'
|
import { NetworkStatus, NetworkHealthState } from './useNetworkStatus'
|
||||||
|
|
||||||
export const NetworkContext = createContext<NetworkStatus>({
|
export const NetworkContext = createContext<NetworkStatus>({
|
||||||
|
immediateState: {
|
||||||
|
type: EngineConnectionStateType.Disconnected,
|
||||||
|
} as EngineConnectionState,
|
||||||
hasIssues: undefined,
|
hasIssues: undefined,
|
||||||
overallState: NetworkHealthState.Disconnected,
|
overallState: NetworkHealthState.Disconnected,
|
||||||
internetConnected: true,
|
internetConnected: true,
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
EngineCommandManagerEvents,
|
EngineCommandManagerEvents,
|
||||||
EngineConnectionEvents,
|
EngineConnectionEvents,
|
||||||
EngineConnectionStateType,
|
EngineConnectionStateType,
|
||||||
|
EngineConnectionState,
|
||||||
ErrorType,
|
ErrorType,
|
||||||
initialConnectingTypeGroupState,
|
initialConnectingTypeGroupState,
|
||||||
} from '../lang/std/engineConnection'
|
} from '../lang/std/engineConnection'
|
||||||
@ -19,6 +20,7 @@ export enum NetworkHealthState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface NetworkStatus {
|
export interface NetworkStatus {
|
||||||
|
immediateState: EngineConnectionState
|
||||||
hasIssues: boolean | undefined
|
hasIssues: boolean | undefined
|
||||||
overallState: NetworkHealthState
|
overallState: NetworkHealthState
|
||||||
internetConnected: boolean
|
internetConnected: boolean
|
||||||
@ -33,6 +35,9 @@ export interface NetworkStatus {
|
|||||||
// Must be called from one place in the application.
|
// Must be called from one place in the application.
|
||||||
// We've chosen the <Router /> component for this.
|
// We've chosen the <Router /> component for this.
|
||||||
export function useNetworkStatus() {
|
export function useNetworkStatus() {
|
||||||
|
const [immediateState, setImmediateState] = useState<EngineConnectionState>({
|
||||||
|
type: EngineConnectionStateType.Disconnected,
|
||||||
|
})
|
||||||
const [steps, setSteps] = useState(
|
const [steps, setSteps] = useState(
|
||||||
structuredClone(initialConnectingTypeGroupState)
|
structuredClone(initialConnectingTypeGroupState)
|
||||||
)
|
)
|
||||||
@ -126,6 +131,7 @@ export function useNetworkStatus() {
|
|||||||
const onConnectionStateChange = ({
|
const onConnectionStateChange = ({
|
||||||
detail: engineConnectionState,
|
detail: engineConnectionState,
|
||||||
}: CustomEvent) => {
|
}: CustomEvent) => {
|
||||||
|
setImmediateState(engineConnectionState)
|
||||||
setSteps((steps) => {
|
setSteps((steps) => {
|
||||||
let nextSteps = structuredClone(steps)
|
let nextSteps = structuredClone(steps)
|
||||||
|
|
||||||
@ -215,6 +221,7 @@ export function useNetworkStatus() {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
immediateState,
|
||||||
hasIssues,
|
hasIssues,
|
||||||
overallState,
|
overallState,
|
||||||
internetConnected,
|
internetConnected,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useLayoutEffect, useEffect, useRef, useState } from 'react'
|
import { useLayoutEffect, useEffect, useRef } from 'react'
|
||||||
import { engineCommandManager, kclManager } from 'lib/singletons'
|
import { engineCommandManager, kclManager } from 'lib/singletons'
|
||||||
import { deferExecution } from 'lib/utils'
|
import { deferExecution } from 'lib/utils'
|
||||||
import { Themes } from 'lib/theme'
|
import { Themes } from 'lib/theme'
|
||||||
|
@ -304,7 +304,6 @@ describe('testing sketchOnExtrudedFace', () => {
|
|||||||
const ast = parse(code)
|
const ast = parse(code)
|
||||||
if (err(ast)) throw ast
|
if (err(ast)) throw ast
|
||||||
|
|
||||||
const programMemory = await enginelessExecutor(ast)
|
|
||||||
const segmentSnippet = `line([9.7, 9.19], %)`
|
const segmentSnippet = `line([9.7, 9.19], %)`
|
||||||
const segmentRange: [number, number] = [
|
const segmentRange: [number, number] = [
|
||||||
code.indexOf(segmentSnippet),
|
code.indexOf(segmentSnippet),
|
||||||
@ -321,8 +320,7 @@ describe('testing sketchOnExtrudedFace', () => {
|
|||||||
const extruded = sketchOnExtrudedFace(
|
const extruded = sketchOnExtrudedFace(
|
||||||
ast,
|
ast,
|
||||||
segmentPathToNode,
|
segmentPathToNode,
|
||||||
extrudePathToNode,
|
extrudePathToNode
|
||||||
programMemory
|
|
||||||
)
|
)
|
||||||
if (err(extruded)) throw extruded
|
if (err(extruded)) throw extruded
|
||||||
const { modifiedAst } = extruded
|
const { modifiedAst } = extruded
|
||||||
@ -345,7 +343,6 @@ const sketch001 = startSketchOn(part001, seg01)`)
|
|||||||
|> extrude(5 + 7, %)`
|
|> extrude(5 + 7, %)`
|
||||||
const ast = parse(code)
|
const ast = parse(code)
|
||||||
if (err(ast)) throw ast
|
if (err(ast)) throw ast
|
||||||
const programMemory = await enginelessExecutor(ast)
|
|
||||||
const segmentSnippet = `close(%)`
|
const segmentSnippet = `close(%)`
|
||||||
const segmentRange: [number, number] = [
|
const segmentRange: [number, number] = [
|
||||||
code.indexOf(segmentSnippet),
|
code.indexOf(segmentSnippet),
|
||||||
@ -362,8 +359,7 @@ const sketch001 = startSketchOn(part001, seg01)`)
|
|||||||
const extruded = sketchOnExtrudedFace(
|
const extruded = sketchOnExtrudedFace(
|
||||||
ast,
|
ast,
|
||||||
segmentPathToNode,
|
segmentPathToNode,
|
||||||
extrudePathToNode,
|
extrudePathToNode
|
||||||
programMemory
|
|
||||||
)
|
)
|
||||||
if (err(extruded)) throw extruded
|
if (err(extruded)) throw extruded
|
||||||
const { modifiedAst } = extruded
|
const { modifiedAst } = extruded
|
||||||
@ -386,7 +382,6 @@ const sketch001 = startSketchOn(part001, seg01)`)
|
|||||||
|> extrude(5 + 7, %)`
|
|> extrude(5 + 7, %)`
|
||||||
const ast = parse(code)
|
const ast = parse(code)
|
||||||
if (err(ast)) throw ast
|
if (err(ast)) throw ast
|
||||||
const programMemory = await enginelessExecutor(ast)
|
|
||||||
const sketchSnippet = `startProfileAt([3.58, 2.06], %)`
|
const sketchSnippet = `startProfileAt([3.58, 2.06], %)`
|
||||||
const sketchRange: [number, number] = [
|
const sketchRange: [number, number] = [
|
||||||
code.indexOf(sketchSnippet),
|
code.indexOf(sketchSnippet),
|
||||||
@ -404,7 +399,6 @@ const sketch001 = startSketchOn(part001, seg01)`)
|
|||||||
ast,
|
ast,
|
||||||
sketchPathToNode,
|
sketchPathToNode,
|
||||||
extrudePathToNode,
|
extrudePathToNode,
|
||||||
programMemory,
|
|
||||||
'end'
|
'end'
|
||||||
)
|
)
|
||||||
if (err(extruded)) throw extruded
|
if (err(extruded)) throw extruded
|
||||||
@ -436,7 +430,6 @@ const sketch001 = startSketchOn(part001, 'END')`)
|
|||||||
const part001 = extrude(5 + 7, sketch001)`
|
const part001 = extrude(5 + 7, sketch001)`
|
||||||
const ast = parse(code)
|
const ast = parse(code)
|
||||||
if (err(ast)) throw ast
|
if (err(ast)) throw ast
|
||||||
const programMemory = await enginelessExecutor(ast)
|
|
||||||
const segmentSnippet = `line([4.99, -0.46], %)`
|
const segmentSnippet = `line([4.99, -0.46], %)`
|
||||||
const segmentRange: [number, number] = [
|
const segmentRange: [number, number] = [
|
||||||
code.indexOf(segmentSnippet),
|
code.indexOf(segmentSnippet),
|
||||||
@ -453,8 +446,7 @@ const sketch001 = startSketchOn(part001, 'END')`)
|
|||||||
const updatedAst = sketchOnExtrudedFace(
|
const updatedAst = sketchOnExtrudedFace(
|
||||||
ast,
|
ast,
|
||||||
segmentPathToNode,
|
segmentPathToNode,
|
||||||
extrudePathToNode,
|
extrudePathToNode
|
||||||
programMemory
|
|
||||||
)
|
)
|
||||||
if (err(updatedAst)) throw updatedAst
|
if (err(updatedAst)) throw updatedAst
|
||||||
const newCode = recast(updatedAst.modifiedAst)
|
const newCode = recast(updatedAst.modifiedAst)
|
||||||
|
@ -349,7 +349,6 @@ export function sketchOnExtrudedFace(
|
|||||||
node: Program,
|
node: Program,
|
||||||
sketchPathToNode: PathToNode,
|
sketchPathToNode: PathToNode,
|
||||||
extrudePathToNode: PathToNode,
|
extrudePathToNode: PathToNode,
|
||||||
programMemory: ProgramMemory,
|
|
||||||
cap: 'none' | 'start' | 'end' = 'none'
|
cap: 'none' | 'start' | 'end' = 'none'
|
||||||
): { modifiedAst: Program; pathToNode: PathToNode } | Error {
|
): { modifiedAst: Program; pathToNode: PathToNode } | Error {
|
||||||
let _node = { ...node }
|
let _node = { ...node }
|
||||||
@ -388,7 +387,6 @@ export function sketchOnExtrudedFace(
|
|||||||
if (cap === 'none') {
|
if (cap === 'none') {
|
||||||
const __tag = addTagForSketchOnFace(
|
const __tag = addTagForSketchOnFace(
|
||||||
{
|
{
|
||||||
previousProgramMemory: programMemory,
|
|
||||||
pathToNode: sketchPathToNode,
|
pathToNode: sketchPathToNode,
|
||||||
node: _node,
|
node: _node,
|
||||||
},
|
},
|
||||||
|
315
src/lang/modifyAst/addFillet.test.ts
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
import {
|
||||||
|
parse,
|
||||||
|
recast,
|
||||||
|
initPromise,
|
||||||
|
PathToNode,
|
||||||
|
Value,
|
||||||
|
Program,
|
||||||
|
CallExpression,
|
||||||
|
} from '../wasm'
|
||||||
|
import { addFillet, isTagUsedInFillet } from './addFillet'
|
||||||
|
import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst'
|
||||||
|
import { createLiteral } from 'lang/modifyAst'
|
||||||
|
import { err } from 'lib/trap'
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await initPromise // Initialize the WASM environment before running tests
|
||||||
|
})
|
||||||
|
|
||||||
|
const runFilletTest = async (
|
||||||
|
code: string,
|
||||||
|
segmentSnippet: string,
|
||||||
|
extrudeSnippet: string,
|
||||||
|
radius = createLiteral(5) as Value,
|
||||||
|
expectedCode: string
|
||||||
|
) => {
|
||||||
|
const astOrError = parse(code)
|
||||||
|
if (astOrError instanceof Error) {
|
||||||
|
return new Error('AST not found')
|
||||||
|
}
|
||||||
|
|
||||||
|
const ast = astOrError as Program
|
||||||
|
|
||||||
|
const segmentRange: [number, number] = [
|
||||||
|
code.indexOf(segmentSnippet),
|
||||||
|
code.indexOf(segmentSnippet) + segmentSnippet.length,
|
||||||
|
]
|
||||||
|
const pathToSegmentNode: PathToNode = getNodePathFromSourceRange(
|
||||||
|
ast,
|
||||||
|
segmentRange
|
||||||
|
)
|
||||||
|
|
||||||
|
const extrudeRange: [number, number] = [
|
||||||
|
code.indexOf(extrudeSnippet),
|
||||||
|
code.indexOf(extrudeSnippet) + extrudeSnippet.length,
|
||||||
|
]
|
||||||
|
|
||||||
|
const pathToExtrudeNode: PathToNode = getNodePathFromSourceRange(
|
||||||
|
ast,
|
||||||
|
extrudeRange
|
||||||
|
)
|
||||||
|
if (pathToExtrudeNode instanceof Error) {
|
||||||
|
return new Error('Path to extrude node not found')
|
||||||
|
}
|
||||||
|
|
||||||
|
// const radius = createLiteral(5) as Value
|
||||||
|
|
||||||
|
const result = addFillet(ast, pathToSegmentNode, pathToExtrudeNode, radius)
|
||||||
|
if (result instanceof Error) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
const { modifiedAst } = result
|
||||||
|
const newCode = recast(modifiedAst)
|
||||||
|
|
||||||
|
expect(newCode).toContain(expectedCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Testing addFillet', () => {
|
||||||
|
/**
|
||||||
|
* 1. Ideal Case
|
||||||
|
*/
|
||||||
|
|
||||||
|
it('should add a fillet to a specific segment after extrusion, clean', async () => {
|
||||||
|
const code = `
|
||||||
|
const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([2.16, 49.67], %)
|
||||||
|
|> line([101.49, 139.93], %)
|
||||||
|
|> line([60.04, -55.72], %)
|
||||||
|
|> line([1.29, -115.74], %)
|
||||||
|
|> line([-87.24, -47.08], %)
|
||||||
|
|> tangentialArcTo([56.15, -94.58], %)
|
||||||
|
|> tangentialArcTo([14.68, -104.52], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(50, sketch001)
|
||||||
|
`
|
||||||
|
const segmentSnippet = `line([60.04, -55.72], %)`
|
||||||
|
const extrudeSnippet = `const extrude001 = extrude(50, sketch001)`
|
||||||
|
const radius = createLiteral(5) as Value
|
||||||
|
const expectedCode = `const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([2.16, 49.67], %)
|
||||||
|
|> line([101.49, 139.93], %)
|
||||||
|
|> line([60.04, -55.72], %, $seg01)
|
||||||
|
|> line([1.29, -115.74], %)
|
||||||
|
|> line([-87.24, -47.08], %)
|
||||||
|
|> tangentialArcTo([56.15, -94.58], %)
|
||||||
|
|> tangentialArcTo([14.68, -104.52], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(50, sketch001)
|
||||||
|
|> fillet({ radius: 5, tags: [seg01] }, %)`
|
||||||
|
|
||||||
|
await runFilletTest(
|
||||||
|
code,
|
||||||
|
segmentSnippet,
|
||||||
|
extrudeSnippet,
|
||||||
|
radius,
|
||||||
|
expectedCode
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2. Case of existing tag in the other line
|
||||||
|
*/
|
||||||
|
|
||||||
|
it('should add a fillet to a specific segment after extrusion with existing tag in any other line', async () => {
|
||||||
|
const code = `
|
||||||
|
const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([2.16, 49.67], %)
|
||||||
|
|> line([101.49, 139.93], %)
|
||||||
|
|> line([60.04, -55.72], %)
|
||||||
|
|> line([1.29, -115.74], %)
|
||||||
|
|> line([-87.24, -47.08], %, $seg01)
|
||||||
|
|> tangentialArcTo([56.15, -94.58], %)
|
||||||
|
|> tangentialArcTo([14.68, -104.52], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(50, sketch001)
|
||||||
|
`
|
||||||
|
const segmentSnippet = `line([60.04, -55.72], %)`
|
||||||
|
const extrudeSnippet = `const extrude001 = extrude(50, sketch001)`
|
||||||
|
const radius = createLiteral(5) as Value
|
||||||
|
const expectedCode = `const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([2.16, 49.67], %)
|
||||||
|
|> line([101.49, 139.93], %)
|
||||||
|
|> line([60.04, -55.72], %, $seg02)
|
||||||
|
|> line([1.29, -115.74], %)
|
||||||
|
|> line([-87.24, -47.08], %, $seg01)
|
||||||
|
|> tangentialArcTo([56.15, -94.58], %)
|
||||||
|
|> tangentialArcTo([14.68, -104.52], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(50, sketch001)
|
||||||
|
|> fillet({ radius: 5, tags: [seg02] }, %)`
|
||||||
|
|
||||||
|
await runFilletTest(
|
||||||
|
code,
|
||||||
|
segmentSnippet,
|
||||||
|
extrudeSnippet,
|
||||||
|
radius,
|
||||||
|
expectedCode
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 3. Case of existing tag in the fillet line
|
||||||
|
*/
|
||||||
|
|
||||||
|
it('should add a fillet to a specific segment after extrusion with existing tag in that exact line', async () => {
|
||||||
|
const code = `
|
||||||
|
const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([2.16, 49.67], %)
|
||||||
|
|> line([101.49, 139.93], %)
|
||||||
|
|> line([60.04, -55.72], %)
|
||||||
|
|> line([1.29, -115.74], %)
|
||||||
|
|> line([-87.24, -47.08], %, $seg03)
|
||||||
|
|> tangentialArcTo([56.15, -94.58], %)
|
||||||
|
|> tangentialArcTo([14.68, -104.52], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(50, sketch001)
|
||||||
|
`
|
||||||
|
const segmentSnippet = `line([-87.24, -47.08], %, $seg03)`
|
||||||
|
const extrudeSnippet = `const extrude001 = extrude(50, sketch001)`
|
||||||
|
const radius = createLiteral(5) as Value
|
||||||
|
const expectedCode = `const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([2.16, 49.67], %)
|
||||||
|
|> line([101.49, 139.93], %)
|
||||||
|
|> line([60.04, -55.72], %)
|
||||||
|
|> line([1.29, -115.74], %)
|
||||||
|
|> line([-87.24, -47.08], %, $seg03)
|
||||||
|
|> tangentialArcTo([56.15, -94.58], %)
|
||||||
|
|> tangentialArcTo([14.68, -104.52], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(50, sketch001)
|
||||||
|
|> fillet({ radius: 5, tags: [seg03] }, %)`
|
||||||
|
|
||||||
|
await runFilletTest(
|
||||||
|
code,
|
||||||
|
segmentSnippet,
|
||||||
|
extrudeSnippet,
|
||||||
|
radius,
|
||||||
|
expectedCode
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4. Case of existing fillet on some other segment
|
||||||
|
*/
|
||||||
|
|
||||||
|
it('should add another fillet after the existing fillet', async () => {
|
||||||
|
const code = `const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([2.16, 49.67], %)
|
||||||
|
|> line([101.49, 139.93], %)
|
||||||
|
|> line([60.04, -55.72], %)
|
||||||
|
|> line([1.29, -115.74], %)
|
||||||
|
|> line([-87.24, -47.08], %, $seg03)
|
||||||
|
|> tangentialArcTo([56.15, -94.58], %)
|
||||||
|
|> tangentialArcTo([14.68, -104.52], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(50, sketch001)
|
||||||
|
|> fillet({ radius: 10, tags: [seg03] }, %)`
|
||||||
|
const segmentSnippet = `line([60.04, -55.72], %)`
|
||||||
|
const extrudeSnippet = `const extrude001 = extrude(50, sketch001)`
|
||||||
|
const radius = createLiteral(5) as Value
|
||||||
|
const expectedCode = `const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([2.16, 49.67], %)
|
||||||
|
|> line([101.49, 139.93], %)
|
||||||
|
|> line([60.04, -55.72], %, $seg01)
|
||||||
|
|> line([1.29, -115.74], %)
|
||||||
|
|> line([-87.24, -47.08], %, $seg03)
|
||||||
|
|> tangentialArcTo([56.15, -94.58], %)
|
||||||
|
|> tangentialArcTo([14.68, -104.52], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(50, sketch001)
|
||||||
|
|> fillet({ radius: 10, tags: [seg03] }, %)
|
||||||
|
|> fillet({ radius: 5, tags: [seg01] }, %)`
|
||||||
|
|
||||||
|
await runFilletTest(
|
||||||
|
code,
|
||||||
|
segmentSnippet,
|
||||||
|
extrudeSnippet,
|
||||||
|
radius,
|
||||||
|
expectedCode
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Testing isTagUsedInFillet', () => {
|
||||||
|
const code = `const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([7.72, 4.13], %)
|
||||||
|
|> line([7.11, 3.48], %, $seg01)
|
||||||
|
|> line([-3.29, -13.85], %)
|
||||||
|
|> line([-6.37, 3.88], %, $seg02)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(-5, sketch001)
|
||||||
|
|> fillet({
|
||||||
|
radius: 1.11,
|
||||||
|
tags: [
|
||||||
|
getOppositeEdge(seg01, %),
|
||||||
|
seg01,
|
||||||
|
getPreviousAdjacentEdge(seg02, %)
|
||||||
|
]
|
||||||
|
}, %)
|
||||||
|
`
|
||||||
|
it('should correctly identify getOppositeEdge and baseEdge edges', () => {
|
||||||
|
const ast = parse(code)
|
||||||
|
if (err(ast)) return
|
||||||
|
const lineOfInterest = `line([7.11, 3.48], %, $seg01)`
|
||||||
|
const range: [number, number] = [
|
||||||
|
code.indexOf(lineOfInterest),
|
||||||
|
code.indexOf(lineOfInterest) + lineOfInterest.length,
|
||||||
|
]
|
||||||
|
const pathToNode = getNodePathFromSourceRange(ast, range)
|
||||||
|
if (err(pathToNode)) return
|
||||||
|
const callExp = getNodeFromPath<CallExpression>(
|
||||||
|
ast,
|
||||||
|
pathToNode,
|
||||||
|
'CallExpression'
|
||||||
|
)
|
||||||
|
if (err(callExp)) return
|
||||||
|
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
||||||
|
expect(edges).toEqual(['getOppositeEdge', 'baseEdge'])
|
||||||
|
})
|
||||||
|
it('should correctly identify getPreviousAdjacentEdge edges', () => {
|
||||||
|
const ast = parse(code)
|
||||||
|
if (err(ast)) return
|
||||||
|
const lineOfInterest = `line([-6.37, 3.88], %, $seg02)`
|
||||||
|
const range: [number, number] = [
|
||||||
|
code.indexOf(lineOfInterest),
|
||||||
|
code.indexOf(lineOfInterest) + lineOfInterest.length,
|
||||||
|
]
|
||||||
|
const pathToNode = getNodePathFromSourceRange(ast, range)
|
||||||
|
if (err(pathToNode)) return
|
||||||
|
const callExp = getNodeFromPath<CallExpression>(
|
||||||
|
ast,
|
||||||
|
pathToNode,
|
||||||
|
'CallExpression'
|
||||||
|
)
|
||||||
|
if (err(callExp)) return
|
||||||
|
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
||||||
|
expect(edges).toEqual(['getPreviousAdjacentEdge'])
|
||||||
|
})
|
||||||
|
it('should correctly identify no edges', () => {
|
||||||
|
const ast = parse(code)
|
||||||
|
if (err(ast)) return
|
||||||
|
const lineOfInterest = `line([-3.29, -13.85], %)`
|
||||||
|
const range: [number, number] = [
|
||||||
|
code.indexOf(lineOfInterest),
|
||||||
|
code.indexOf(lineOfInterest) + lineOfInterest.length,
|
||||||
|
]
|
||||||
|
const pathToNode = getNodePathFromSourceRange(ast, range)
|
||||||
|
if (err(pathToNode)) return
|
||||||
|
const callExp = getNodeFromPath<CallExpression>(
|
||||||
|
ast,
|
||||||
|
pathToNode,
|
||||||
|
'CallExpression'
|
||||||
|
)
|
||||||
|
if (err(callExp)) return
|
||||||
|
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
||||||
|
expect(edges).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
404
src/lang/modifyAst/addFillet.ts
Normal file
@ -0,0 +1,404 @@
|
|||||||
|
import {
|
||||||
|
ArrayExpression,
|
||||||
|
CallExpression,
|
||||||
|
ObjectExpression,
|
||||||
|
PathToNode,
|
||||||
|
Program,
|
||||||
|
Value,
|
||||||
|
VariableDeclaration,
|
||||||
|
VariableDeclarator,
|
||||||
|
} from '../wasm'
|
||||||
|
import {
|
||||||
|
createCallExpressionStdLib,
|
||||||
|
createLiteral,
|
||||||
|
createPipeSubstitution,
|
||||||
|
createObjectExpression,
|
||||||
|
createArrayExpression,
|
||||||
|
createIdentifier,
|
||||||
|
createPipeExpression,
|
||||||
|
} from '../modifyAst'
|
||||||
|
import {
|
||||||
|
getNodeFromPath,
|
||||||
|
getNodePathFromSourceRange,
|
||||||
|
hasSketchPipeBeenExtruded,
|
||||||
|
traverse,
|
||||||
|
} from '../queryAst'
|
||||||
|
import {
|
||||||
|
addTagForSketchOnFace,
|
||||||
|
getTagFromCallExpression,
|
||||||
|
sketchLineHelperMap,
|
||||||
|
} from '../std/sketch'
|
||||||
|
import { err } from 'lib/trap'
|
||||||
|
import { Selections, canFilletSelection } from 'lib/selections'
|
||||||
|
|
||||||
|
export function addFillet(
|
||||||
|
node: Program,
|
||||||
|
pathToSegmentNode: PathToNode,
|
||||||
|
pathToExtrudeNode: PathToNode,
|
||||||
|
radius = createLiteral(5) as Value
|
||||||
|
// shouldPipe = false, // TODO: Implement this feature
|
||||||
|
): { modifiedAst: Program; pathToFilletNode: PathToNode } | Error {
|
||||||
|
// close ast to make mutations safe
|
||||||
|
let _node: Program = JSON.parse(JSON.stringify(node))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Tag to the Segment Expression
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Find the specific sketch segment to tag with the new tag
|
||||||
|
const sketchSegmentChunk = getNodeFromPath(
|
||||||
|
_node,
|
||||||
|
pathToSegmentNode,
|
||||||
|
'CallExpression'
|
||||||
|
)
|
||||||
|
if (err(sketchSegmentChunk)) return sketchSegmentChunk
|
||||||
|
const { node: sketchSegmentNode } = sketchSegmentChunk as {
|
||||||
|
node: CallExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether selection is a valid segment from sketchLineHelpersMap
|
||||||
|
if (!(sketchSegmentNode.callee.name in sketchLineHelperMap)) {
|
||||||
|
return new Error('Selection is not a sketch segment')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add tag to the sketch segment or use existing tag
|
||||||
|
const taggedSegment = addTagForSketchOnFace(
|
||||||
|
{
|
||||||
|
// previousProgramMemory: programMemory,
|
||||||
|
pathToNode: pathToSegmentNode,
|
||||||
|
node: _node,
|
||||||
|
},
|
||||||
|
sketchSegmentNode.callee.name
|
||||||
|
)
|
||||||
|
if (err(taggedSegment)) return taggedSegment
|
||||||
|
const { tag } = taggedSegment
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find Extrude Expression automatically
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 1. Get the sketch name
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Fillet to the Extrude expression
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Create the fillet call expression in one line
|
||||||
|
const filletCall = createCallExpressionStdLib('fillet', [
|
||||||
|
createObjectExpression({
|
||||||
|
radius: radius,
|
||||||
|
tags: createArrayExpression([createIdentifier(tag)]),
|
||||||
|
}),
|
||||||
|
createPipeSubstitution(),
|
||||||
|
])
|
||||||
|
|
||||||
|
// Locate the extrude call
|
||||||
|
const extrudeChunk = getNodeFromPath<VariableDeclaration>(
|
||||||
|
_node,
|
||||||
|
pathToExtrudeNode,
|
||||||
|
'VariableDeclaration'
|
||||||
|
)
|
||||||
|
if (err(extrudeChunk)) return extrudeChunk
|
||||||
|
const { node: extrudeVarDecl } = extrudeChunk
|
||||||
|
|
||||||
|
const extrudeDeclarator = extrudeVarDecl.declarations[0]
|
||||||
|
const extrudeInit = extrudeDeclarator.init
|
||||||
|
|
||||||
|
if (
|
||||||
|
!extrudeDeclarator ||
|
||||||
|
(extrudeInit.type !== 'CallExpression' &&
|
||||||
|
extrudeInit.type !== 'PipeExpression')
|
||||||
|
) {
|
||||||
|
return new Error('Extrude PipeExpression / CallExpression not found.')
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine if extrude is in a PipeExpression or CallExpression
|
||||||
|
|
||||||
|
// CallExpression - no fillet
|
||||||
|
// PipeExpression - fillet exists
|
||||||
|
|
||||||
|
const getPathToNodeOfFilletLiteral = (
|
||||||
|
pathToExtrudeNode: PathToNode,
|
||||||
|
extrudeDeclarator: VariableDeclarator,
|
||||||
|
tag: string
|
||||||
|
): PathToNode => {
|
||||||
|
let pathToFilletObj: any
|
||||||
|
let inFillet = false
|
||||||
|
traverse(extrudeDeclarator.init, {
|
||||||
|
enter(node, path) {
|
||||||
|
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
||||||
|
inFillet = true
|
||||||
|
}
|
||||||
|
if (inFillet && node.type === 'ObjectExpression') {
|
||||||
|
const hasTag = node.properties.some((prop) => {
|
||||||
|
const isTagProp = prop.key.name === 'tags'
|
||||||
|
if (isTagProp && prop.value.type === 'ArrayExpression') {
|
||||||
|
return prop.value.elements.some(
|
||||||
|
(element) =>
|
||||||
|
element.type === 'Identifier' && element.name === tag
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
if (!hasTag) return false
|
||||||
|
pathToFilletObj = path
|
||||||
|
node.properties.forEach((prop, index) => {
|
||||||
|
if (prop.key.name === 'radius') {
|
||||||
|
pathToFilletObj.push(
|
||||||
|
['properties', 'ObjectExpression'],
|
||||||
|
[index, 'index'],
|
||||||
|
['value', 'Property']
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
leave(node) {
|
||||||
|
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
||||||
|
inFillet = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
let indexOfPipeExpression = pathToExtrudeNode.findIndex(
|
||||||
|
(path) => path[1] === 'PipeExpression'
|
||||||
|
)
|
||||||
|
indexOfPipeExpression =
|
||||||
|
indexOfPipeExpression === -1
|
||||||
|
? pathToExtrudeNode.length
|
||||||
|
: indexOfPipeExpression
|
||||||
|
|
||||||
|
return [
|
||||||
|
...pathToExtrudeNode.slice(0, indexOfPipeExpression),
|
||||||
|
...pathToFilletObj,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extrudeInit.type === 'CallExpression') {
|
||||||
|
// 1. no fillet case
|
||||||
|
extrudeDeclarator.init = createPipeExpression([extrudeInit, filletCall])
|
||||||
|
return {
|
||||||
|
modifiedAst: _node,
|
||||||
|
pathToFilletNode: getPathToNodeOfFilletLiteral(
|
||||||
|
pathToExtrudeNode,
|
||||||
|
extrudeDeclarator,
|
||||||
|
tag
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else if (extrudeInit.type === 'PipeExpression') {
|
||||||
|
// 2. fillet case
|
||||||
|
|
||||||
|
// there are 2 options here:
|
||||||
|
|
||||||
|
const existingFilletCall = extrudeInit.body.find((node) => {
|
||||||
|
return node.type === 'CallExpression' && node.callee.name === 'fillet'
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!existingFilletCall || existingFilletCall.type !== 'CallExpression') {
|
||||||
|
return new Error('Fillet CallExpression not found.')
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the existing fillet has the same tag as the new fillet
|
||||||
|
let filletTag = null
|
||||||
|
if (existingFilletCall.arguments[0].type === 'ObjectExpression') {
|
||||||
|
const properties = (existingFilletCall.arguments[0] as ObjectExpression)
|
||||||
|
.properties
|
||||||
|
const tagsProperty = properties.find((prop) => prop.key.name === 'tags')
|
||||||
|
if (tagsProperty && tagsProperty.value.type === 'ArrayExpression') {
|
||||||
|
const elements = (tagsProperty.value as ArrayExpression).elements
|
||||||
|
if (elements.length > 0 && elements[0].type === 'Identifier') {
|
||||||
|
filletTag = elements[0].name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new Error('Expected an ObjectExpression node')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filletTag !== tag) {
|
||||||
|
extrudeInit.body.push(filletCall)
|
||||||
|
return {
|
||||||
|
modifiedAst: _node,
|
||||||
|
pathToFilletNode: getPathToNodeOfFilletLiteral(
|
||||||
|
pathToExtrudeNode,
|
||||||
|
extrudeDeclarator,
|
||||||
|
tag
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new Error('Unsupported extrude type.')
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Error('Unsupported extrude type.')
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hasValidFilletSelection = ({
|
||||||
|
selectionRanges,
|
||||||
|
ast,
|
||||||
|
code,
|
||||||
|
}: {
|
||||||
|
selectionRanges: Selections
|
||||||
|
ast: Program
|
||||||
|
code: string
|
||||||
|
}) => {
|
||||||
|
// case 0: check if there is anything filletable in the scene
|
||||||
|
let extrudeExists = false
|
||||||
|
traverse(ast, {
|
||||||
|
enter(node) {
|
||||||
|
if (node.type === 'CallExpression' && node.callee.name === 'extrude') {
|
||||||
|
extrudeExists = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (!extrudeExists) return false
|
||||||
|
|
||||||
|
// case 1: nothing selected, test whether the extrusion exists
|
||||||
|
if (selectionRanges) {
|
||||||
|
if (selectionRanges.codeBasedSelections.length === 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const range0 = selectionRanges.codeBasedSelections[0].range[0]
|
||||||
|
const codeLength = code.length
|
||||||
|
if (range0 === codeLength) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 2: sketch segment selected, test whether it is extruded
|
||||||
|
// TODO: add loft / sweep check
|
||||||
|
if (selectionRanges.codeBasedSelections.length > 0) {
|
||||||
|
const isExtruded = hasSketchPipeBeenExtruded(
|
||||||
|
selectionRanges.codeBasedSelections[0],
|
||||||
|
ast
|
||||||
|
)
|
||||||
|
if (isExtruded) {
|
||||||
|
const pathToSelectedNode = getNodePathFromSourceRange(
|
||||||
|
ast,
|
||||||
|
selectionRanges.codeBasedSelections[0].range
|
||||||
|
)
|
||||||
|
const segmentNode = getNodeFromPath<CallExpression>(
|
||||||
|
ast,
|
||||||
|
pathToSelectedNode,
|
||||||
|
'CallExpression'
|
||||||
|
)
|
||||||
|
if (err(segmentNode)) return false
|
||||||
|
if (segmentNode.node.type === 'CallExpression') {
|
||||||
|
const segmentName = segmentNode.node.callee.name
|
||||||
|
if (segmentName in sketchLineHelperMap) {
|
||||||
|
const edges = isTagUsedInFillet({
|
||||||
|
ast,
|
||||||
|
callExp: segmentNode.node,
|
||||||
|
})
|
||||||
|
// edge has already been filleted
|
||||||
|
if (
|
||||||
|
['edge', 'default'].includes(
|
||||||
|
selectionRanges.codeBasedSelections[0].type
|
||||||
|
) &&
|
||||||
|
edges.includes('baseEdge')
|
||||||
|
)
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return canFilletSelection(selectionRanges)
|
||||||
|
}
|
||||||
|
|
||||||
|
type EdgeTypes =
|
||||||
|
| 'baseEdge'
|
||||||
|
| 'getNextAdjacentEdge'
|
||||||
|
| 'getPreviousAdjacentEdge'
|
||||||
|
| 'getOppositeEdge'
|
||||||
|
|
||||||
|
export const isTagUsedInFillet = ({
|
||||||
|
ast,
|
||||||
|
callExp,
|
||||||
|
}: {
|
||||||
|
ast: Program
|
||||||
|
callExp: CallExpression
|
||||||
|
}): Array<EdgeTypes> => {
|
||||||
|
const tag = getTagFromCallExpression(callExp)
|
||||||
|
if (err(tag)) return []
|
||||||
|
|
||||||
|
let inFillet = false
|
||||||
|
let inObj = false
|
||||||
|
let inTagHelper: EdgeTypes | '' = ''
|
||||||
|
const edges: Array<EdgeTypes> = []
|
||||||
|
traverse(ast, {
|
||||||
|
enter: (node) => {
|
||||||
|
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
||||||
|
inFillet = true
|
||||||
|
}
|
||||||
|
if (inFillet && node.type === 'ObjectExpression') {
|
||||||
|
node.properties.forEach((prop) => {
|
||||||
|
if (
|
||||||
|
prop.key.name === 'tags' &&
|
||||||
|
prop.value.type === 'ArrayExpression'
|
||||||
|
) {
|
||||||
|
inObj = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
inObj &&
|
||||||
|
inFillet &&
|
||||||
|
node.type === 'CallExpression' &&
|
||||||
|
(node.callee.name === 'getOppositeEdge' ||
|
||||||
|
node.callee.name === 'getNextAdjacentEdge' ||
|
||||||
|
node.callee.name === 'getPreviousAdjacentEdge')
|
||||||
|
) {
|
||||||
|
inTagHelper = node.callee.name
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
inObj &&
|
||||||
|
inFillet &&
|
||||||
|
!inTagHelper &&
|
||||||
|
node.type === 'Identifier' &&
|
||||||
|
node.name === tag
|
||||||
|
) {
|
||||||
|
edges.push('baseEdge')
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
inObj &&
|
||||||
|
inFillet &&
|
||||||
|
inTagHelper &&
|
||||||
|
node.type === 'Identifier' &&
|
||||||
|
node.name === tag
|
||||||
|
) {
|
||||||
|
edges.push(inTagHelper)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
leave: (node) => {
|
||||||
|
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
||||||
|
inFillet = false
|
||||||
|
}
|
||||||
|
if (inFillet && node.type === 'ObjectExpression') {
|
||||||
|
node.properties.forEach((prop) => {
|
||||||
|
if (
|
||||||
|
prop.key.name === 'tags' &&
|
||||||
|
prop.value.type === 'ArrayExpression'
|
||||||
|
) {
|
||||||
|
inObj = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
inObj &&
|
||||||
|
inFillet &&
|
||||||
|
node.type === 'CallExpression' &&
|
||||||
|
(node.callee.name === 'getOppositeEdge' ||
|
||||||
|
node.callee.name === 'getNextAdjacentEdge' ||
|
||||||
|
node.callee.name === 'getPreviousAdjacentEdge')
|
||||||
|
) {
|
||||||
|
inTagHelper = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return edges
|
||||||
|
}
|
@ -143,6 +143,7 @@ export enum DisconnectingType {
|
|||||||
Error = 'error',
|
Error = 'error',
|
||||||
Timeout = 'timeout',
|
Timeout = 'timeout',
|
||||||
Quit = 'quit',
|
Quit = 'quit',
|
||||||
|
Pause = 'pause',
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sorted by severity
|
// Sorted by severity
|
||||||
@ -200,6 +201,7 @@ export type DisconnectingValue =
|
|||||||
| State<DisconnectingType.Error, ErrorType>
|
| State<DisconnectingType.Error, ErrorType>
|
||||||
| State<DisconnectingType.Timeout, void>
|
| State<DisconnectingType.Timeout, void>
|
||||||
| State<DisconnectingType.Quit, void>
|
| State<DisconnectingType.Quit, void>
|
||||||
|
| State<DisconnectingType.Pause, void>
|
||||||
|
|
||||||
// These are ordered by the expected sequence.
|
// These are ordered by the expected sequence.
|
||||||
export enum ConnectingType {
|
export enum ConnectingType {
|
||||||
@ -300,7 +302,7 @@ class EngineConnection extends EventTarget {
|
|||||||
pc?: RTCPeerConnection
|
pc?: RTCPeerConnection
|
||||||
unreliableDataChannel?: RTCDataChannel
|
unreliableDataChannel?: RTCDataChannel
|
||||||
mediaStream?: MediaStream
|
mediaStream?: MediaStream
|
||||||
freezeFrame: boolean = false
|
idleMode: boolean = false
|
||||||
|
|
||||||
onIceCandidate = function (
|
onIceCandidate = function (
|
||||||
this: RTCPeerConnection,
|
this: RTCPeerConnection,
|
||||||
@ -391,10 +393,10 @@ class EngineConnection extends EventTarget {
|
|||||||
this.pingPongSpan = { ping: undefined, pong: undefined }
|
this.pingPongSpan = { ping: undefined, pong: undefined }
|
||||||
|
|
||||||
// Without an interval ping, our connection will timeout.
|
// Without an interval ping, our connection will timeout.
|
||||||
// If this.freezeFrame is true we skip this logic so only reconnect
|
// If this.idleMode is true we skip this logic so only reconnect
|
||||||
// happens on mouse move
|
// happens on mouse move
|
||||||
this.pingIntervalId = setInterval(() => {
|
this.pingIntervalId = setInterval(() => {
|
||||||
if (this.freezeFrame) return
|
if (this.idleMode) return
|
||||||
|
|
||||||
switch (this.state.type as EngineConnectionStateType) {
|
switch (this.state.type as EngineConnectionStateType) {
|
||||||
case EngineConnectionStateType.ConnectionEstablished:
|
case EngineConnectionStateType.ConnectionEstablished:
|
||||||
@ -456,8 +458,8 @@ class EngineConnection extends EventTarget {
|
|||||||
return this.state.type === EngineConnectionStateType.ConnectionEstablished
|
return this.state.type === EngineConnectionStateType.ConnectionEstablished
|
||||||
}
|
}
|
||||||
|
|
||||||
tearDown(opts?: { freeze: boolean }) {
|
tearDown(opts?: { idleMode: boolean }) {
|
||||||
this.freezeFrame = opts?.freeze ?? false
|
this.idleMode = opts?.idleMode ?? false
|
||||||
this.disconnectAll()
|
this.disconnectAll()
|
||||||
clearInterval(this.pingIntervalId)
|
clearInterval(this.pingIntervalId)
|
||||||
|
|
||||||
@ -497,10 +499,19 @@ class EngineConnection extends EventTarget {
|
|||||||
this.onNetworkStatusReady
|
this.onNetworkStatusReady
|
||||||
)
|
)
|
||||||
|
|
||||||
this.state = {
|
this.state = opts?.idleMode
|
||||||
type: EngineConnectionStateType.Disconnecting,
|
? {
|
||||||
value: { type: DisconnectingType.Quit },
|
type: EngineConnectionStateType.Disconnecting,
|
||||||
}
|
value: {
|
||||||
|
type: DisconnectingType.Pause,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
type: EngineConnectionStateType.Disconnecting,
|
||||||
|
value: {
|
||||||
|
type: DisconnectingType.Quit,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1099,8 +1110,6 @@ class EngineConnection extends EventTarget {
|
|||||||
this.unreliableDataChannel?.readyState === 'closed'
|
this.unreliableDataChannel?.readyState === 'closed'
|
||||||
if (allClosed) {
|
if (allClosed) {
|
||||||
// Do not notify the rest of the program that we have cut off anything.
|
// Do not notify the rest of the program that we have cut off anything.
|
||||||
if (this.freezeFrame) return
|
|
||||||
|
|
||||||
this.state = { type: EngineConnectionStateType.Disconnected }
|
this.state = { type: EngineConnectionStateType.Disconnected }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1738,7 +1747,7 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tearDown() {
|
tearDown(opts?: { idleMode: boolean }) {
|
||||||
if (this.engineConnection) {
|
if (this.engineConnection) {
|
||||||
this.engineConnection.removeEventListener(
|
this.engineConnection.removeEventListener(
|
||||||
EngineConnectionEvents.Opened,
|
EngineConnectionEvents.Opened,
|
||||||
@ -1757,7 +1766,7 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
this.onEngineConnectionNewTrack as EventListener
|
this.onEngineConnectionNewTrack as EventListener
|
||||||
)
|
)
|
||||||
|
|
||||||
this.engineConnection?.tearDown()
|
this.engineConnection?.tearDown(opts)
|
||||||
this.engineConnection = undefined
|
this.engineConnection = undefined
|
||||||
|
|
||||||
// Our window.tearDown assignment causes this case to happen which is
|
// Our window.tearDown assignment causes this case to happen which is
|
||||||
@ -1765,7 +1774,7 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
} else if (this.engineCommandManager?.engineConnection) {
|
} else if (this.engineCommandManager?.engineConnection) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.engineCommandManager?.engineConnection?.tearDown()
|
this.engineCommandManager?.engineConnection?.tearDown(opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async startNewSession() {
|
async startNewSession() {
|
||||||
|
@ -221,7 +221,7 @@ describe('testing addTagForSketchOnFace', () => {
|
|||||||
const pathToNode = getNodePathFromSourceRange(ast, sourceRange)
|
const pathToNode = getNodePathFromSourceRange(ast, sourceRange)
|
||||||
const sketchOnFaceRetVal = addTagForSketchOnFace(
|
const sketchOnFaceRetVal = addTagForSketchOnFace(
|
||||||
{
|
{
|
||||||
previousProgramMemory: programMemory,
|
// previousProgramMemory: programMemory, // redundant?
|
||||||
pathToNode,
|
pathToNode,
|
||||||
node: ast,
|
node: ast,
|
||||||
},
|
},
|
||||||
|
@ -28,7 +28,6 @@ import { createPipeExpression, splitPathAtPipeExpression } from '../modifyAst'
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
SketchLineHelper,
|
SketchLineHelper,
|
||||||
ModifyAstBase,
|
|
||||||
TransformCallback,
|
TransformCallback,
|
||||||
ConstrainInfo,
|
ConstrainInfo,
|
||||||
RawValues,
|
RawValues,
|
||||||
@ -37,6 +36,7 @@ import {
|
|||||||
SingleValueInput,
|
SingleValueInput,
|
||||||
VarValueKeys,
|
VarValueKeys,
|
||||||
ArrayOrObjItemInput,
|
ArrayOrObjItemInput,
|
||||||
|
AddTagInfo,
|
||||||
} from 'lang/std/stdTypes'
|
} from 'lang/std/stdTypes'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -308,6 +308,18 @@ function singleRawValueHelper(
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTag(index = 2): SketchLineHelper['getTag'] {
|
||||||
|
return (callExp: CallExpression) => {
|
||||||
|
if (callExp.type !== 'CallExpression')
|
||||||
|
return new Error('Not a CallExpression')
|
||||||
|
const arg = callExp.arguments?.[index]
|
||||||
|
if (!arg) return new Error('No argument')
|
||||||
|
if (arg.type !== 'TagDeclarator')
|
||||||
|
return new Error('Tag not a TagDeclarator')
|
||||||
|
return arg.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const lineTo: SketchLineHelper = {
|
export const lineTo: SketchLineHelper = {
|
||||||
add: ({
|
add: ({
|
||||||
node,
|
node,
|
||||||
@ -377,6 +389,7 @@ export const lineTo: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp, ...args) =>
|
getConstraintInfo: (callExp, ...args) =>
|
||||||
commonConstraintInfoHelper(
|
commonConstraintInfoHelper(
|
||||||
@ -503,6 +516,7 @@ export const line: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp, ...args) =>
|
getConstraintInfo: (callExp, ...args) =>
|
||||||
commonConstraintInfoHelper(
|
commonConstraintInfoHelper(
|
||||||
@ -563,6 +577,7 @@ export const xLineTo: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp, ...args) =>
|
getConstraintInfo: (callExp, ...args) =>
|
||||||
horzVertConstraintInfoHelper(
|
horzVertConstraintInfoHelper(
|
||||||
@ -623,6 +638,7 @@ export const yLineTo: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp, ...args) =>
|
getConstraintInfo: (callExp, ...args) =>
|
||||||
horzVertConstraintInfoHelper(
|
horzVertConstraintInfoHelper(
|
||||||
@ -682,6 +698,7 @@ export const xLine: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp, ...args) =>
|
getConstraintInfo: (callExp, ...args) =>
|
||||||
horzVertConstraintInfoHelper(
|
horzVertConstraintInfoHelper(
|
||||||
@ -738,6 +755,7 @@ export const yLine: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp, ...args) =>
|
getConstraintInfo: (callExp, ...args) =>
|
||||||
horzVertConstraintInfoHelper(
|
horzVertConstraintInfoHelper(
|
||||||
@ -830,6 +848,7 @@ export const tangentialArcTo: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp: CallExpression, code, pathToNode) => {
|
getConstraintInfo: (callExp: CallExpression, code, pathToNode) => {
|
||||||
if (callExp.type !== 'CallExpression') return []
|
if (callExp.type !== 'CallExpression') return []
|
||||||
@ -948,6 +967,7 @@ export const angledLine: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp, ...args) =>
|
getConstraintInfo: (callExp, ...args) =>
|
||||||
commonConstraintInfoHelper(
|
commonConstraintInfoHelper(
|
||||||
@ -1044,6 +1064,7 @@ export const angledLineOfXLength: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp, ...args) =>
|
getConstraintInfo: (callExp, ...args) =>
|
||||||
commonConstraintInfoHelper(
|
commonConstraintInfoHelper(
|
||||||
@ -1140,6 +1161,7 @@ export const angledLineOfYLength: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp, ...args) =>
|
getConstraintInfo: (callExp, ...args) =>
|
||||||
commonConstraintInfoHelper(
|
commonConstraintInfoHelper(
|
||||||
@ -1227,6 +1249,7 @@ export const angledLineToX: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp, ...args) =>
|
getConstraintInfo: (callExp, ...args) =>
|
||||||
commonConstraintInfoHelper(
|
commonConstraintInfoHelper(
|
||||||
@ -1316,6 +1339,7 @@ export const angledLineToY: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp, ...args) =>
|
getConstraintInfo: (callExp, ...args) =>
|
||||||
commonConstraintInfoHelper(
|
commonConstraintInfoHelper(
|
||||||
@ -1440,6 +1464,7 @@ export const angledLineThatIntersects: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getTag: getTag(),
|
||||||
addTag: addTag(),
|
addTag: addTag(),
|
||||||
getConstraintInfo: (callExp: CallExpression, code, pathToNode) => {
|
getConstraintInfo: (callExp: CallExpression, code, pathToNode) => {
|
||||||
if (callExp.type !== 'CallExpression') return []
|
if (callExp.type !== 'CallExpression') return []
|
||||||
@ -1792,10 +1817,7 @@ export function replaceSketchLine({
|
|||||||
return { modifiedAst, valueUsedInTransform, pathToNode }
|
return { modifiedAst, valueUsedInTransform, pathToNode }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addTagForSketchOnFace(
|
export function addTagForSketchOnFace(a: AddTagInfo, expressionName: string) {
|
||||||
a: ModifyAstBase,
|
|
||||||
expressionName: string
|
|
||||||
) {
|
|
||||||
if (expressionName === 'close') {
|
if (expressionName === 'close') {
|
||||||
return addTag(1)(a)
|
return addTag(1)(a)
|
||||||
}
|
}
|
||||||
@ -1806,6 +1828,17 @@ export function addTagForSketchOnFace(
|
|||||||
return new Error(`"${expressionName}" is not a sketch line helper`)
|
return new Error(`"${expressionName}" is not a sketch line helper`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getTagFromCallExpression(
|
||||||
|
callExp: CallExpression
|
||||||
|
): string | Error {
|
||||||
|
if (callExp.callee.name === 'close') return getTag(1)(callExp)
|
||||||
|
if (callExp.callee.name in sketchLineHelperMap) {
|
||||||
|
const { getTag } = sketchLineHelperMap[callExp.callee.name]
|
||||||
|
return getTag(callExp)
|
||||||
|
}
|
||||||
|
return new Error(`"${callExp.callee.name}" is not a sketch line helper`)
|
||||||
|
}
|
||||||
|
|
||||||
function isAngleLiteral(lineArugement: Value): boolean {
|
function isAngleLiteral(lineArugement: Value): boolean {
|
||||||
return lineArugement?.type === 'ArrayExpression'
|
return lineArugement?.type === 'ArrayExpression'
|
||||||
? isLiteralArrayOrStatic(lineArugement.elements[0])
|
? isLiteralArrayOrStatic(lineArugement.elements[0])
|
||||||
@ -1816,9 +1849,7 @@ function isAngleLiteral(lineArugement: Value): boolean {
|
|||||||
: false
|
: false
|
||||||
}
|
}
|
||||||
|
|
||||||
type addTagFn = (
|
type addTagFn = (a: AddTagInfo) => { modifiedAst: Program; tag: string } | Error
|
||||||
a: ModifyAstBase
|
|
||||||
) => { modifiedAst: Program; tag: string } | Error
|
|
||||||
|
|
||||||
function addTag(tagIndex = 2): addTagFn {
|
function addTag(tagIndex = 2): addTagFn {
|
||||||
return ({ node, pathToNode }) => {
|
return ({ node, pathToNode }) => {
|
||||||
|
@ -32,6 +32,11 @@ export interface ModifyAstBase {
|
|||||||
pathToNode: PathToNode
|
pathToNode: PathToNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AddTagInfo {
|
||||||
|
node: Program
|
||||||
|
pathToNode: PathToNode
|
||||||
|
}
|
||||||
|
|
||||||
interface addCall extends ModifyAstBase {
|
interface addCall extends ModifyAstBase {
|
||||||
to: [number, number]
|
to: [number, number]
|
||||||
from: [number, number]
|
from: [number, number]
|
||||||
@ -127,7 +132,8 @@ export interface SketchLineHelper {
|
|||||||
pathToNode: PathToNode
|
pathToNode: PathToNode
|
||||||
}
|
}
|
||||||
| Error
|
| Error
|
||||||
addTag: (a: ModifyAstBase) =>
|
getTag: (a: CallExpression) => string | Error
|
||||||
|
addTag: (a: AddTagInfo) =>
|
||||||
| {
|
| {
|
||||||
modifiedAst: Program
|
modifiedAst: Program
|
||||||
tag: string
|
tag: string
|
||||||
|
@ -27,6 +27,11 @@ export type ModelingCommandSchema = {
|
|||||||
// result: (typeof EXTRUSION_RESULTS)[number]
|
// result: (typeof EXTRUSION_RESULTS)[number]
|
||||||
distance: KclCommandValue
|
distance: KclCommandValue
|
||||||
}
|
}
|
||||||
|
Fillet: {
|
||||||
|
// todo
|
||||||
|
selection: Selections
|
||||||
|
radius: KclCommandValue
|
||||||
|
}
|
||||||
'change tool': {
|
'change tool': {
|
||||||
tool: SketchTool
|
tool: SketchTool
|
||||||
}
|
}
|
||||||
@ -185,4 +190,36 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Fillet: {
|
||||||
|
// todo
|
||||||
|
description: 'Fillet edge',
|
||||||
|
icon: 'fillet',
|
||||||
|
needsReview: true,
|
||||||
|
args: {
|
||||||
|
selection: {
|
||||||
|
inputType: 'selection',
|
||||||
|
selectionTypes: [
|
||||||
|
'default',
|
||||||
|
'line-end',
|
||||||
|
'line-mid',
|
||||||
|
'extrude-wall', // to fix: accespts only this selection type
|
||||||
|
'start-cap',
|
||||||
|
'end-cap',
|
||||||
|
'point',
|
||||||
|
'edge',
|
||||||
|
'line',
|
||||||
|
'arc',
|
||||||
|
'all',
|
||||||
|
],
|
||||||
|
multiple: true, // TODO: multiple selection like in extrude command
|
||||||
|
required: true,
|
||||||
|
skip: true,
|
||||||
|
},
|
||||||
|
radius: {
|
||||||
|
inputType: 'kcl',
|
||||||
|
defaultValue: KCL_DEFAULT_LENGTH,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ export const ONBOARDING_PROJECT_NAME = 'Tutorial Project $nn'
|
|||||||
export const KCL_DEFAULT_CONSTANT_PREFIXES = {
|
export const KCL_DEFAULT_CONSTANT_PREFIXES = {
|
||||||
SKETCH: 'sketch',
|
SKETCH: 'sketch',
|
||||||
EXTRUDE: 'extrude',
|
EXTRUDE: 'extrude',
|
||||||
|
SEGMENT: 'seg',
|
||||||
} as const
|
} as const
|
||||||
/** The default KCL length expression */
|
/** The default KCL length expression */
|
||||||
export const KCL_DEFAULT_LENGTH = `5`
|
export const KCL_DEFAULT_LENGTH = `5`
|
||||||
|
@ -406,6 +406,17 @@ export function canExtrudeSelection(selection: Selections) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function canFilletSelection(selection: Selections) {
|
||||||
|
const commonNodes = selection.codeBasedSelections.map((_, i) =>
|
||||||
|
buildCommonNodeFromSelection(selection, i)
|
||||||
|
) // TODO FILLET DUMMY PLACEHOLDER
|
||||||
|
return (
|
||||||
|
!!isSketchPipe(selection) &&
|
||||||
|
commonNodes.every((n) => nodeHasClose(n)) &&
|
||||||
|
commonNodes.every((n) => !nodeHasExtrude(n))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function canExtrudeSelectionItem(selection: Selections, i: number) {
|
function canExtrudeSelectionItem(selection: Selections, i: number) {
|
||||||
const commonNode = buildCommonNodeFromSelection(selection, i)
|
const commonNode = buildCommonNodeFromSelection(selection, i)
|
||||||
|
|
||||||
|
@ -163,6 +163,17 @@ export function createSettings() {
|
|||||||
validate: (v) => typeof v === 'boolean',
|
validate: (v) => typeof v === 'boolean',
|
||||||
hideOnPlatform: 'both', //for now
|
hideOnPlatform: 'both', //for now
|
||||||
}),
|
}),
|
||||||
|
/**
|
||||||
|
* Stream resource saving behavior toggle
|
||||||
|
*/
|
||||||
|
streamIdleMode: new Setting<boolean>({
|
||||||
|
defaultValue: false,
|
||||||
|
description: 'Toggle stream idling, saving bandwidth and battery',
|
||||||
|
validate: (v) => typeof v === 'boolean',
|
||||||
|
commandConfig: {
|
||||||
|
inputType: 'boolean',
|
||||||
|
},
|
||||||
|
}),
|
||||||
onboardingStatus: new Setting<string>({
|
onboardingStatus: new Setting<string>({
|
||||||
defaultValue: '',
|
defaultValue: '',
|
||||||
validate: (v) => typeof v === 'string',
|
validate: (v) => typeof v === 'string',
|
||||||
|
@ -38,6 +38,7 @@ function configurationToSettingsPayload(
|
|||||||
: undefined,
|
: undefined,
|
||||||
onboardingStatus: configuration?.settings?.app?.onboarding_status,
|
onboardingStatus: configuration?.settings?.app?.onboarding_status,
|
||||||
dismissWebBanner: configuration?.settings?.app?.dismiss_web_banner,
|
dismissWebBanner: configuration?.settings?.app?.dismiss_web_banner,
|
||||||
|
streamIdleMode: configuration?.settings?.app?.stream_idle_mode,
|
||||||
projectDirectory: configuration?.settings?.project?.directory,
|
projectDirectory: configuration?.settings?.project?.directory,
|
||||||
enableSSAO: configuration?.settings?.modeling?.enable_ssao,
|
enableSSAO: configuration?.settings?.modeling?.enable_ssao,
|
||||||
},
|
},
|
||||||
@ -75,6 +76,7 @@ function projectConfigurationToSettingsPayload(
|
|||||||
: undefined,
|
: undefined,
|
||||||
onboardingStatus: configuration?.settings?.app?.onboarding_status,
|
onboardingStatus: configuration?.settings?.app?.onboarding_status,
|
||||||
dismissWebBanner: configuration?.settings?.app?.dismiss_web_banner,
|
dismissWebBanner: configuration?.settings?.app?.dismiss_web_banner,
|
||||||
|
streamIdleMode: configuration?.settings?.app?.stream_idle_mode,
|
||||||
enableSSAO: configuration?.settings?.modeling?.enable_ssao,
|
enableSSAO: configuration?.settings?.modeling?.enable_ssao,
|
||||||
},
|
},
|
||||||
modeling: {
|
modeling: {
|
||||||
|
@ -37,4 +37,7 @@ if (typeof window !== 'undefined') {
|
|||||||
document.addEventListener('mousemove', (e) =>
|
document.addEventListener('mousemove', (e) =>
|
||||||
console.log(`await page.mouse.click(${e.clientX}, ${e.clientY})`)
|
console.log(`await page.mouse.click(${e.clientX}, ${e.clientY})`)
|
||||||
)
|
)
|
||||||
|
;(window as any).enableFillet = () => {
|
||||||
|
;(window as any)._enableFillet = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import { PrevVariable, findAllPreviousVariables } from 'lang/queryAst'
|
|||||||
import { Value, parse } from 'lang/wasm'
|
import { Value, parse } from 'lang/wasm'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { executeAst } from 'lang/langHelpers'
|
import { executeAst } from 'lang/langHelpers'
|
||||||
import { trap } from 'lib/trap'
|
import { err, trap } from 'lib/trap'
|
||||||
|
|
||||||
const isValidVariableName = (name: string) =>
|
const isValidVariableName = (name: string) =>
|
||||||
/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)
|
/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)
|
||||||
@ -86,6 +86,7 @@ export function useCalculateKclExpression({
|
|||||||
const execAstAndSetResult = async () => {
|
const execAstAndSetResult = async () => {
|
||||||
const _code = `const __result__ = ${value}`
|
const _code = `const __result__ = ${value}`
|
||||||
const ast = parse(_code)
|
const ast = parse(_code)
|
||||||
|
if (err(ast)) return
|
||||||
if (trap(ast, { suppress: true })) return
|
if (trap(ast, { suppress: true })) return
|
||||||
|
|
||||||
const _programMem: any = { root: {}, return: null }
|
const _programMem: any = { root: {}, return: null }
|
||||||
|
@ -203,7 +203,7 @@ export const commandBarMachine = createMachine(
|
|||||||
'Change current argument': {
|
'Change current argument': {
|
||||||
target: 'Gathering arguments',
|
target: 'Gathering arguments',
|
||||||
internal: true,
|
internal: true,
|
||||||
actions: ['Remove current argument and set a new one'],
|
actions: ['Set current argument'],
|
||||||
},
|
},
|
||||||
|
|
||||||
'Deselect command': {
|
'Deselect command': {
|
||||||
@ -359,29 +359,13 @@ export const commandBarMachine = createMachine(
|
|||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case 'Edit argument':
|
case 'Edit argument':
|
||||||
return event.data.arg
|
return event.data.arg
|
||||||
|
case 'Change current argument':
|
||||||
|
return Object.values(event.data)[0]
|
||||||
default:
|
default:
|
||||||
return context.currentArgument
|
return context.currentArgument
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
'Remove current argument and set a new one': assign({
|
|
||||||
argumentsToSubmit: (context, event) => {
|
|
||||||
if (
|
|
||||||
event.type !== 'Change current argument' ||
|
|
||||||
!context.currentArgument
|
|
||||||
)
|
|
||||||
return context.argumentsToSubmit
|
|
||||||
const { name } = context.currentArgument
|
|
||||||
|
|
||||||
const { [name]: _, ...rest } = context.argumentsToSubmit
|
|
||||||
return rest
|
|
||||||
},
|
|
||||||
currentArgument: (context, event) => {
|
|
||||||
if (event.type !== 'Change current argument')
|
|
||||||
return context.currentArgument
|
|
||||||
return Object.values(event.data)[0]
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
'Clear argument data': assign({
|
'Clear argument data': assign({
|
||||||
selectedCommand: undefined,
|
selectedCommand: undefined,
|
||||||
currentArgument: undefined,
|
currentArgument: undefined,
|
||||||
|
@ -63,6 +63,12 @@ export const settingsMachine = createMachine(
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'set.app.streamIdleMode': {
|
||||||
|
target: 'persisting settings',
|
||||||
|
|
||||||
|
actions: ['setSettingAtLevel', 'toastSuccess'],
|
||||||
|
},
|
||||||
|
|
||||||
'set.modeling.highlightEdges': {
|
'set.modeling.highlightEdges': {
|
||||||
target: 'persisting settings',
|
target: 'persisting settings',
|
||||||
|
|
||||||
|
72
src/wasm-lib/Cargo.lock
generated
@ -169,7 +169,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -180,7 +180,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -191,7 +191,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -431,7 +431,7 @@ dependencies = [
|
|||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -631,7 +631,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strsim 0.10.0",
|
"strsim 0.10.0",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -642,7 +642,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -697,7 +697,7 @@ checksum = "4078275de501a61ceb9e759d37bdd3d7210e654dbc167ac1a3678ef4435ed57b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -726,7 +726,7 @@ dependencies = [
|
|||||||
"rustfmt-wrapper",
|
"rustfmt-wrapper",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_tokenstream",
|
"serde_tokenstream",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -737,7 +737,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -764,7 +764,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -936,7 +936,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1026,7 +1026,7 @@ dependencies = [
|
|||||||
"inflections",
|
"inflections",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1448,7 +1448,7 @@ dependencies = [
|
|||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1824,7 +1824,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"regex-syntax 0.8.3",
|
"regex-syntax 0.8.3",
|
||||||
"structmeta",
|
"structmeta",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1877,7 +1877,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2041,7 +2041,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-macros-backend",
|
"pyo3-macros-backend",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2054,7 +2054,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-build-config",
|
"pyo3-build-config",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2516,7 +2516,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"serde_derive_internals",
|
"serde_derive_internals",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2590,7 +2590,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2601,7 +2601,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2624,7 +2624,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2645,7 +2645,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"serde",
|
"serde",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2782,7 +2782,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"structmeta-derive",
|
"structmeta-derive",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2793,7 +2793,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2837,9 +2837,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.70"
|
version = "2.0.71"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
|
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -2860,7 +2860,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2943,7 +2943,7 @@ checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3039,7 +3039,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3192,7 +3192,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3220,7 +3220,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3297,7 +3297,7 @@ checksum = "c88cc88fd23b5a04528f3a8436024f20010a16ec18eb23c164b1242f65860130"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3455,7 +3455,7 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3516,7 +3516,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3551,7 +3551,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
@ -3876,7 +3876,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -20,7 +20,7 @@ quote = "1"
|
|||||||
regex = "1.10"
|
regex = "1.10"
|
||||||
serde = { version = "1.0.204", features = ["derive"] }
|
serde = { version = "1.0.204", features = ["derive"] }
|
||||||
serde_tokenstream = "0.2"
|
serde_tokenstream = "0.2"
|
||||||
syn = { version = "2.0.70", features = ["full"] }
|
syn = { version = "2.0.71", features = ["full"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
|
@ -837,7 +837,7 @@ fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> pr
|
|||||||
|
|
||||||
// Read the output file.
|
// Read the output file.
|
||||||
let actual = image::io::Reader::open(output_file).unwrap().decode().unwrap();
|
let actual = image::io::Reader::open(output_file).unwrap().decode().unwrap();
|
||||||
twenty_twenty::assert_image(&format!("tests/outputs/{}.png", #test_name_str), &actual, 1.0);
|
twenty_twenty::assert_image(&format!("tests/outputs/{}.png", #test_name_str), &actual, 0.99);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ mod test_examples_someFn {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_someFn0"),
|
&format!("tests/outputs/{}.png", "serial_test_example_someFn0"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ mod test_examples_someFn {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_someFn0"),
|
&format!("tests/outputs/{}.png", "serial_test_example_someFn0"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ mod test_examples_show {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
|
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ mod test_examples_show {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_show1"),
|
&format!("tests/outputs/{}.png", "serial_test_example_show1"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ mod test_examples_show {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
|
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ mod test_examples_my_func {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_my_func0"),
|
&format!("tests/outputs/{}.png", "serial_test_example_my_func0"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +178,7 @@ mod test_examples_my_func {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_my_func1"),
|
&format!("tests/outputs/{}.png", "serial_test_example_my_func1"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ mod test_examples_line_to {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_line_to0"),
|
&format!("tests/outputs/{}.png", "serial_test_example_line_to0"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +178,7 @@ mod test_examples_line_to {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_line_to1"),
|
&format!("tests/outputs/{}.png", "serial_test_example_line_to1"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ mod test_examples_min {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_min0"),
|
&format!("tests/outputs/{}.png", "serial_test_example_min0"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ mod test_examples_min {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_min1"),
|
&format!("tests/outputs/{}.png", "serial_test_example_min1"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ mod test_examples_show {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
|
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ mod test_examples_import {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_import0"),
|
&format!("tests/outputs/{}.png", "serial_test_example_import0"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ mod test_examples_import {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_import0"),
|
&format!("tests/outputs/{}.png", "serial_test_example_import0"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ mod test_examples_import {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_import0"),
|
&format!("tests/outputs/{}.png", "serial_test_example_import0"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ mod test_examples_show {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
|
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
|
||||||
&actual,
|
&actual,
|
||||||
1.0,
|
0.99,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ databake = "0.1.8"
|
|||||||
kcl-lib = { path = "../kcl" }
|
kcl-lib = { path = "../kcl" }
|
||||||
proc-macro2 = "1"
|
proc-macro2 = "1"
|
||||||
quote = "1"
|
quote = "1"
|
||||||
syn = { version = "2.0.70", features = ["full"] }
|
syn = { version = "2.0.71", features = ["full"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1.4.0"
|
pretty_assertions = "1.4.0"
|
||||||
|
@ -98,6 +98,10 @@ harness = false
|
|||||||
name = "compiler_benchmark_iai"
|
name = "compiler_benchmark_iai"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "digest_benchmark"
|
||||||
|
harness = false
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "lsp_semantic_tokens_benchmark_criterion"
|
name = "lsp_semantic_tokens_benchmark_criterion"
|
||||||
harness = false
|
harness = false
|
||||||
|
31
src/wasm-lib/kcl/benches/digest_benchmark.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
|
|
||||||
|
pub fn bench_digest(c: &mut Criterion) {
|
||||||
|
for (name, file) in [
|
||||||
|
("pipes_on_pipes", PIPES_PROGRAM),
|
||||||
|
("big_kitt", KITT_PROGRAM),
|
||||||
|
("cube", CUBE_PROGRAM),
|
||||||
|
("math", MATH_PROGRAM),
|
||||||
|
("mike_stress_test", MIKE_STRESS_TEST_PROGRAM),
|
||||||
|
] {
|
||||||
|
let tokens = kcl_lib::token::lexer(file).unwrap();
|
||||||
|
let prog = kcl_lib::parser::Parser::new(tokens).ast().unwrap();
|
||||||
|
c.bench_function(&format!("digest_{name}"), move |b| {
|
||||||
|
let prog = prog.clone();
|
||||||
|
|
||||||
|
b.iter(move || {
|
||||||
|
let mut prog = prog.clone();
|
||||||
|
prog.compute_digest();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, bench_digest);
|
||||||
|
criterion_main!(benches);
|
||||||
|
|
||||||
|
const KITT_PROGRAM: &str = include_str!("../../tests/executor/inputs/kittycad_svg.kcl");
|
||||||
|
const PIPES_PROGRAM: &str = include_str!("../../tests/executor/inputs/pipes_on_pipes.kcl");
|
||||||
|
const CUBE_PROGRAM: &str = include_str!("../../tests/executor/inputs/cube.kcl");
|
||||||
|
const MATH_PROGRAM: &str = include_str!("../../tests/executor/inputs/math.kcl");
|
||||||
|
const MIKE_STRESS_TEST_PROGRAM: &str = include_str!("../../tests/executor/inputs/mike_stress_test.kcl");
|
@ -100,18 +100,6 @@ impl ProgramMemory {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all TagDeclarators and TagIdentifiers in the memory.
|
|
||||||
pub fn get_tags(&self) -> HashMap<String, MemoryItem> {
|
|
||||||
self.root
|
|
||||||
.values()
|
|
||||||
.filter_map(|item| match item {
|
|
||||||
MemoryItem::TagDeclarator(t) => Some((t.name.to_string(), item.clone())),
|
|
||||||
MemoryItem::TagIdentifier(t) => Some((t.value.to_string(), item.clone())),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect::<HashMap<String, MemoryItem>>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ProgramMemory {
|
impl Default for ProgramMemory {
|
||||||
|
@ -232,7 +232,7 @@ impl crate::lsp::backend::Backend for Backend {
|
|||||||
// Lets update the ast.
|
// Lets update the ast.
|
||||||
let parser = crate::parser::Parser::new(tokens.clone());
|
let parser = crate::parser::Parser::new(tokens.clone());
|
||||||
let result = parser.ast();
|
let result = parser.ast();
|
||||||
let ast = match result {
|
let mut ast = match result {
|
||||||
Ok(ast) => ast,
|
Ok(ast) => ast,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
self.add_to_diagnostics(¶ms, &[err], true).await;
|
self.add_to_diagnostics(¶ms, &[err], true).await;
|
||||||
@ -243,6 +243,11 @@ impl crate::lsp::backend::Backend for Backend {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Here we will want to store the digest and compare, but for now
|
||||||
|
// we're doing this in a non-load-bearing capacity so we can remove
|
||||||
|
// this if it backfires and only hork the LSP.
|
||||||
|
ast.compute_digest();
|
||||||
|
|
||||||
// Check if the ast changed.
|
// Check if the ast changed.
|
||||||
let ast_changed = match self.ast_map.get(&filename) {
|
let ast_changed = match self.ast_map.get(&filename) {
|
||||||
Some(old_ast) => {
|
Some(old_ast) => {
|
||||||
|
@ -2371,9 +2371,12 @@ async fn serial_test_kcl_lsp_full_to_empty_file_updates_ast_and_memory() {
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
let mut default_hashed = crate::ast::types::Program::default();
|
||||||
|
default_hashed.compute_digest();
|
||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||||
assert_eq!(ast, crate::ast::types::Program::default());
|
assert_eq!(ast, default_hashed);
|
||||||
// Get the memory.
|
// Get the memory.
|
||||||
let memory = server.memory_map.get("file:///test.kcl").unwrap().clone();
|
let memory = server.memory_map.get("file:///test.kcl").unwrap().clone();
|
||||||
assert_eq!(memory, ProgramMemory::default());
|
assert_eq!(memory, ProgramMemory::default());
|
||||||
@ -2835,9 +2838,12 @@ async fn serial_test_kcl_lsp_cant_execute_set() {
|
|||||||
let units = server.executor_ctx().await.clone().unwrap().settings.units;
|
let units = server.executor_ctx().await.clone().unwrap().settings.units;
|
||||||
assert_eq!(units, crate::settings::types::UnitLength::Mm);
|
assert_eq!(units, crate::settings::types::UnitLength::Mm);
|
||||||
|
|
||||||
|
let mut default_hashed = crate::ast::types::Program::default();
|
||||||
|
default_hashed.compute_digest();
|
||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||||
assert!(ast != crate::ast::types::Program::default());
|
assert!(ast != default_hashed);
|
||||||
// Get the memory.
|
// Get the memory.
|
||||||
let memory = server.memory_map.get("file:///test.kcl").unwrap().clone();
|
let memory = server.memory_map.get("file:///test.kcl").unwrap().clone();
|
||||||
// Now it should be the default memory.
|
// Now it should be the default memory.
|
||||||
|
@ -234,6 +234,9 @@ pub struct AppSettings {
|
|||||||
/// This setting only applies to the web app. And is temporary until we have Linux support.
|
/// This setting only applies to the web app. And is temporary until we have Linux support.
|
||||||
#[serde(default, alias = "dismissWebBanner", skip_serializing_if = "is_default")]
|
#[serde(default, alias = "dismissWebBanner", skip_serializing_if = "is_default")]
|
||||||
pub dismiss_web_banner: bool,
|
pub dismiss_web_banner: bool,
|
||||||
|
/// When the user is idle, and this is true, the stream will be torn down.
|
||||||
|
#[serde(default, alias = "streamIdleMode", skip_serializing_if = "is_default")]
|
||||||
|
stream_idle_mode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: When we remove backwards compatibility with the old settings file, we can remove this.
|
// TODO: When we remove backwards compatibility with the old settings file, we can remove this.
|
||||||
@ -651,6 +654,7 @@ textWrapping = true
|
|||||||
theme_color: None,
|
theme_color: None,
|
||||||
dismiss_web_banner: false,
|
dismiss_web_banner: false,
|
||||||
enable_ssao: None,
|
enable_ssao: None,
|
||||||
|
stream_idle_mode: false,
|
||||||
},
|
},
|
||||||
modeling: ModelingSettings {
|
modeling: ModelingSettings {
|
||||||
base_unit: UnitLength::In,
|
base_unit: UnitLength::In,
|
||||||
@ -710,6 +714,7 @@ includeSettings = false
|
|||||||
theme_color: None,
|
theme_color: None,
|
||||||
dismiss_web_banner: false,
|
dismiss_web_banner: false,
|
||||||
enable_ssao: None,
|
enable_ssao: None,
|
||||||
|
stream_idle_mode: false,
|
||||||
},
|
},
|
||||||
modeling: ModelingSettings {
|
modeling: ModelingSettings {
|
||||||
base_unit: UnitLength::Yd,
|
base_unit: UnitLength::Yd,
|
||||||
@ -774,6 +779,7 @@ defaultProjectName = "projects-$nnn"
|
|||||||
theme_color: None,
|
theme_color: None,
|
||||||
dismiss_web_banner: false,
|
dismiss_web_banner: false,
|
||||||
enable_ssao: None,
|
enable_ssao: None,
|
||||||
|
stream_idle_mode: false,
|
||||||
},
|
},
|
||||||
modeling: ModelingSettings {
|
modeling: ModelingSettings {
|
||||||
base_unit: UnitLength::Yd,
|
base_unit: UnitLength::Yd,
|
||||||
@ -850,6 +856,7 @@ projectDirectory = "/Users/macinatormax/Documents/kittycad-modeling-projects""#;
|
|||||||
theme_color: None,
|
theme_color: None,
|
||||||
dismiss_web_banner: false,
|
dismiss_web_banner: false,
|
||||||
enable_ssao: None,
|
enable_ssao: None,
|
||||||
|
stream_idle_mode: false,
|
||||||
},
|
},
|
||||||
modeling: ModelingSettings {
|
modeling: ModelingSettings {
|
||||||
base_unit: UnitLength::Mm,
|
base_unit: UnitLength::Mm,
|
||||||
|
@ -123,6 +123,7 @@ includeSettings = false
|
|||||||
theme_color: None,
|
theme_color: None,
|
||||||
dismiss_web_banner: false,
|
dismiss_web_banner: false,
|
||||||
enable_ssao: None,
|
enable_ssao: None,
|
||||||
|
stream_idle_mode: false,
|
||||||
},
|
},
|
||||||
modeling: ModelingSettings {
|
modeling: ModelingSettings {
|
||||||
base_unit: UnitLength::Yd,
|
base_unit: UnitLength::Yd,
|
||||||
|
1013
src/wasm-lib/kcl/src/std/args.rs
Normal file
@ -4,6 +4,10 @@ use kcl_lib::{
|
|||||||
settings::types::UnitLength,
|
settings::types::UnitLength,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The minimum permissible difference between asserted twenty-twenty images.
|
||||||
|
/// i.e. how different the current model snapshot can be from the previous saved one.
|
||||||
|
const MIN_DIFF: f64 = 0.99;
|
||||||
|
|
||||||
// mod server;
|
// mod server;
|
||||||
|
|
||||||
async fn new_context(units: UnitLength) -> Result<ExecutorContext> {
|
async fn new_context(units: UnitLength) -> Result<ExecutorContext> {
|
||||||
@ -83,35 +87,35 @@ const part002 = startSketchOn(part001, here)
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn serial_test_riddle_small() {
|
async fn serial_test_riddle_small() {
|
||||||
let code = include_str!("inputs/riddle_small.kcl");
|
let code = include_str!("inputs/riddle_small.kcl");
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/riddle_small.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/riddle_small.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn serial_test_lego() {
|
async fn serial_test_lego() {
|
||||||
let code = include_str!("inputs/lego.kcl");
|
let code = include_str!("inputs/lego.kcl");
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/lego.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/lego.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn serial_test_pipe_as_arg() {
|
async fn serial_test_pipe_as_arg() {
|
||||||
let code = include_str!("inputs/pipe_as_arg.kcl");
|
let code = include_str!("inputs/pipe_as_arg.kcl");
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/pipe_as_arg.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/pipe_as_arg.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn serial_test_pentagon_fillet_sugar() {
|
async fn serial_test_pentagon_fillet_sugar() {
|
||||||
let code = include_str!("inputs/pentagon_fillet_sugar.kcl");
|
let code = include_str!("inputs/pentagon_fillet_sugar.kcl");
|
||||||
let result = execute_and_snapshot(code, UnitLength::Cm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Cm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/pentagon_fillet_sugar.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/pentagon_fillet_sugar.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -139,14 +143,14 @@ const part002 = startSketchOn(part001, "start")
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_start.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_start.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn serial_test_mike_stress_lines() {
|
async fn serial_test_mike_stress_lines() {
|
||||||
let code = include_str!("inputs/mike_stress_test.kcl");
|
let code = include_str!("inputs/mike_stress_test.kcl");
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/mike_stress_test.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/mike_stress_test.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -174,7 +178,7 @@ const part002 = startSketchOn(part001, "END")
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_end.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_end.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -205,7 +209,7 @@ const part002 = startSketchOn(part001, "END")
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/sketch_on_face_end_negative_extrude.png",
|
"tests/executor/outputs/sketch_on_face_end_negative_extrude.png",
|
||||||
&result,
|
&result,
|
||||||
0.999,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +246,7 @@ async fn serial_test_basic_fillet_cube_start() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/basic_fillet_cube_start.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/basic_fillet_cube_start.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -259,7 +263,7 @@ async fn serial_test_basic_fillet_cube_end() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/basic_fillet_cube_end.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/basic_fillet_cube_end.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -279,7 +283,7 @@ async fn serial_test_basic_fillet_cube_close_opposite() {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/basic_fillet_cube_close_opposite.png",
|
"tests/executor/outputs/basic_fillet_cube_close_opposite.png",
|
||||||
&result,
|
&result,
|
||||||
0.999,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +303,7 @@ async fn serial_test_basic_fillet_cube_next_adjacent() {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/basic_fillet_cube_next_adjacent.png",
|
"tests/executor/outputs/basic_fillet_cube_next_adjacent.png",
|
||||||
&result,
|
&result,
|
||||||
0.999,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +323,7 @@ async fn serial_test_basic_fillet_cube_previous_adjacent() {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/basic_fillet_cube_previous_adjacent.png",
|
"tests/executor/outputs/basic_fillet_cube_previous_adjacent.png",
|
||||||
&result,
|
&result,
|
||||||
0.999,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,7 +345,7 @@ const fnBox = box(3, 6, 10)
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/function_sketch.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/function_sketch.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -364,7 +368,7 @@ const thing = box([0,0], 3, 6, 10)"#;
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/function_sketch_with_position.png",
|
"tests/executor/outputs/function_sketch_with_position.png",
|
||||||
&result,
|
&result,
|
||||||
0.999,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,7 +386,7 @@ async fn serial_test_execute_with_angled_line() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/angled_line.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/angled_line.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -408,7 +412,7 @@ const bracket = startSketchOn('XY')
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/parametric.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/parametric.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -442,7 +446,7 @@ const bracket = startSketchAt([0, 0])
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/parametric_with_tan_arc.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/parametric_with_tan_arc.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -470,7 +474,7 @@ async fn serial_test_execute_i_shape() {
|
|||||||
let code = include_str!("inputs/i_shape.kcl");
|
let code = include_str!("inputs/i_shape.kcl");
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/i_shape.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/i_shape.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -479,7 +483,7 @@ async fn serial_test_execute_pipes_on_pipes() {
|
|||||||
let code = include_str!("inputs/pipes_on_pipes.kcl");
|
let code = include_str!("inputs/pipes_on_pipes.kcl");
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/pipes_on_pipes.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/pipes_on_pipes.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -487,7 +491,7 @@ async fn serial_test_execute_cylinder() {
|
|||||||
let code = include_str!("inputs/cylinder.kcl");
|
let code = include_str!("inputs/cylinder.kcl");
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/cylinder.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/cylinder.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -495,7 +499,7 @@ async fn serial_test_execute_kittycad_svg() {
|
|||||||
let code = include_str!("inputs/kittycad_svg.kcl");
|
let code = include_str!("inputs/kittycad_svg.kcl");
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/kittycad_svg.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/kittycad_svg.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -523,7 +527,7 @@ const pt2 = b2.value[0]
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/member_expression_sketch_group.png",
|
"tests/executor/outputs/member_expression_sketch_group.png",
|
||||||
&result,
|
&result,
|
||||||
1.0,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,7 +540,7 @@ async fn serial_test_helix_defaults() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/helix_defaults.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/helix_defaults.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -551,7 +555,7 @@ async fn serial_test_helix_defaults_negative_extrude() {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/helix_defaults_negative_extrude.png",
|
"tests/executor/outputs/helix_defaults_negative_extrude.png",
|
||||||
&result,
|
&result,
|
||||||
1.0,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,7 +568,7 @@ async fn serial_test_helix_ccw() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/helix_ccw.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/helix_ccw.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -576,7 +580,7 @@ async fn serial_test_helix_with_length() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/helix_with_length.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/helix_with_length.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -591,7 +595,7 @@ async fn serial_test_dimensions_match() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/dimensions_match.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/dimensions_match.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -608,7 +612,7 @@ const body = startSketchOn('XY')
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/close_arc.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/close_arc.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -634,7 +638,7 @@ let thing = box(-12, -15, 10)
|
|||||||
box(-20, -5, 10)"#;
|
box(-20, -5, 10)"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/negative_args.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/negative_args.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -647,7 +651,7 @@ async fn serial_test_basic_tangential_arc() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/tangential_arc.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/tangential_arc.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -660,7 +664,11 @@ async fn serial_test_basic_tangential_arc_with_point() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/tangential_arc_with_point.png", &result, 0.999);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/tangential_arc_with_point.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -673,7 +681,7 @@ async fn serial_test_basic_tangential_arc_to() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/tangential_arc_to.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/tangential_arc_to.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -703,7 +711,7 @@ box(-20, -5, 10, 'xy')"#;
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/different_planes_same_drawing.png",
|
"tests/executor/outputs/different_planes_same_drawing.png",
|
||||||
&result,
|
&result,
|
||||||
0.999,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -762,7 +770,7 @@ const part004 = startSketchOn('YZ')
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/lots_of_planes.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/lots_of_planes.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -779,7 +787,7 @@ async fn serial_test_holes() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/holes.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/holes.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -798,7 +806,7 @@ async fn optional_params() {
|
|||||||
const thing = other_circle([2, 2], 20)
|
const thing = other_circle([2, 2], 20)
|
||||||
"#;
|
"#;
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/optional_params.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/optional_params.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -834,7 +842,7 @@ const part = roundedRectangle([0, 0], 20, 20, 4)
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/rounded_with_holes.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/rounded_with_holes.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -842,7 +850,7 @@ async fn serial_test_top_level_expression() {
|
|||||||
let code = r#"startSketchOn('XY') |> circle([0,0], 22, %) |> extrude(14, %)"#;
|
let code = r#"startSketchOn('XY') |> circle([0,0], 22, %) |> extrude(14, %)"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/top_level_expression.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/top_level_expression.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -859,7 +867,7 @@ const part = startSketchOn('XY')
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/patterns_linear_basic_with_math.png",
|
"tests/executor/outputs/patterns_linear_basic_with_math.png",
|
||||||
&result,
|
&result,
|
||||||
0.999,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,7 +880,7 @@ async fn serial_test_patterns_linear_basic() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -888,7 +896,7 @@ async fn serial_test_patterns_linear_basic_3d() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic_3d.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic_3d.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -903,7 +911,7 @@ async fn serial_test_patterns_linear_basic_negative_distance() {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/patterns_linear_basic_negative_distance.png",
|
"tests/executor/outputs/patterns_linear_basic_negative_distance.png",
|
||||||
&result,
|
&result,
|
||||||
0.999,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -919,7 +927,7 @@ async fn serial_test_patterns_linear_basic_negative_axis() {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/patterns_linear_basic_negative_axis.png",
|
"tests/executor/outputs/patterns_linear_basic_negative_axis.png",
|
||||||
&result,
|
&result,
|
||||||
0.999,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -941,7 +949,11 @@ const rectangle = startSketchOn('XY')
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic_holes.png", &result, 0.999);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/patterns_linear_basic_holes.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -953,7 +965,11 @@ async fn serial_test_patterns_circular_basic_2d() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/patterns_circular_basic_2d.png", &result, 0.999);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/patterns_circular_basic_2d.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -969,7 +985,11 @@ async fn serial_test_patterns_circular_basic_3d() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/patterns_circular_basic_3d.png", &result, 0.999);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/patterns_circular_basic_3d.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -988,7 +1008,7 @@ async fn serial_test_patterns_circular_3d_tilted_axis() {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/patterns_circular_3d_tilted_axis.png",
|
"tests/executor/outputs/patterns_circular_3d_tilted_axis.png",
|
||||||
&result,
|
&result,
|
||||||
0.999,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1009,7 +1029,7 @@ async fn serial_test_import_obj_with_mtl() {
|
|||||||
let code = r#"const model = import("tests/executor/inputs/cube.obj")"#;
|
let code = r#"const model = import("tests/executor/inputs/cube.obj")"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/import_obj_with_mtl.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/import_obj_with_mtl.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1017,7 +1037,11 @@ async fn serial_test_import_obj_with_mtl_units() {
|
|||||||
let code = r#"const model = import("tests/executor/inputs/cube.obj", {type: "obj", units: "m"})"#;
|
let code = r#"const model = import("tests/executor/inputs/cube.obj", {type: "obj", units: "m"})"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/import_obj_with_mtl_units.png", &result, 0.999);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/import_obj_with_mtl_units.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1025,7 +1049,7 @@ async fn serial_test_import_gltf_with_bin() {
|
|||||||
let code = r#"const model = import("tests/executor/inputs/cube.gltf")"#;
|
let code = r#"const model = import("tests/executor/inputs/cube.gltf")"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/import_gltf_with_bin.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/import_gltf_with_bin.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1033,7 +1057,7 @@ async fn serial_test_import_gltf_embedded() {
|
|||||||
let code = r#"const model = import("tests/executor/inputs/cube-embedded.gltf")"#;
|
let code = r#"const model = import("tests/executor/inputs/cube-embedded.gltf")"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/import_gltf_embedded.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/import_gltf_embedded.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1041,7 +1065,7 @@ async fn serial_test_import_glb() {
|
|||||||
let code = r#"const model = import("tests/executor/inputs/cube.glb")"#;
|
let code = r#"const model = import("tests/executor/inputs/cube.glb")"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/import_glb.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/import_glb.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1049,7 +1073,7 @@ async fn serial_test_import_glb_no_assign() {
|
|||||||
let code = r#"import("tests/executor/inputs/cube.glb")"#;
|
let code = r#"import("tests/executor/inputs/cube.glb")"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/import_glb_no_assign.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/import_glb_no_assign.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1082,7 +1106,7 @@ const myCube = cube([0,0], 10)
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/cube_mm.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/cube_mm.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1103,7 +1127,7 @@ const myCube = cube([0,0], 10)
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Cm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Cm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/cube_cm.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/cube_cm.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1124,7 +1148,7 @@ const myCube = cube([0,0], 10)
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::M).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::M).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/cube_m.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/cube_m.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1145,7 +1169,7 @@ const myCube = cube([0,0], 10)
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::In).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::In).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/cube_in.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/cube_in.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1166,7 +1190,7 @@ const myCube = cube([0,0], 10)
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Ft).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Ft).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/cube_ft.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/cube_ft.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1187,7 +1211,7 @@ const myCube = cube([0,0], 10)
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Yd).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Yd).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/cube_yd.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/cube_yd.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1256,7 +1280,7 @@ const part003 = startSketchOn(part002, "end")
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_of_face.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_of_face.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1301,7 +1325,7 @@ const part002 = startSketchOn(part001, "end")
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_circle.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_circle.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1325,7 +1349,11 @@ const part002 = startSketchOn(part001, "end")
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_circle_tagged.png", &result, 1.0);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/sketch_on_face_circle_tagged.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1391,7 +1419,7 @@ async fn serial_test_big_number_angle_to_match_length_x() {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/big_number_angle_to_match_length_x.png",
|
"tests/executor/outputs/big_number_angle_to_match_length_x.png",
|
||||||
&result,
|
&result,
|
||||||
1.0,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1412,7 +1440,7 @@ async fn serial_test_big_number_angle_to_match_length_y() {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/big_number_angle_to_match_length_y.png",
|
"tests/executor/outputs/big_number_angle_to_match_length_y.png",
|
||||||
&result,
|
&result,
|
||||||
1.0,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1433,7 +1461,7 @@ async fn serial_test_simple_revolve() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1453,7 +1481,7 @@ async fn serial_test_simple_revolve_uppercase() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_uppercase.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_uppercase.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1473,7 +1501,7 @@ async fn serial_test_simple_revolve_negative() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_negative.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_negative.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1543,7 +1571,11 @@ async fn serial_test_simple_revolve_custom_angle() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_custom_angle.png", &result, 1.0);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/simple_revolve_custom_angle.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1563,7 +1595,11 @@ async fn serial_test_simple_revolve_custom_axis() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_custom_axis.png", &result, 1.0);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/simple_revolve_custom_axis.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1587,7 +1623,7 @@ const sketch001 = startSketchOn(box, "end")
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_edge.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_edge.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1638,7 +1674,11 @@ const sketch001 = startSketchOn(box, "END")
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_face_circle_edge.png", &result, 1.0);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/revolve_on_face_circle_edge.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1660,7 +1700,7 @@ const sketch001 = startSketchOn(box, "END")
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_face_circle.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_face_circle.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1686,7 +1726,7 @@ const sketch001 = startSketchOn(box, "end")
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_face.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_face.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1700,7 +1740,7 @@ async fn serial_test_basic_revolve_circle() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/basic_revolve_circle.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/basic_revolve_circle.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1727,7 +1767,11 @@ const part002 = startSketchOn(part001, 'end')
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_sketch_on_edge.png", &result, 1.0);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/simple_revolve_sketch_on_edge.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1788,7 +1832,7 @@ const plumbus1 = make_circle(p, b,$arc_b, [0, 0], 2.5)
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/plumbus_fillets.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/plumbus_fillets.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1826,7 +1870,11 @@ capScrew([0, 0.5, 0], 50, 37.5, 50, 25)
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/member_expression_in_params.png", &result, 1.0);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/member_expression_in_params.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1944,7 +1992,7 @@ async fn serial_test_xz_plane() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/xz_plane.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/xz_plane.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1958,7 +2006,7 @@ async fn serial_test_neg_xz_plane() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/neg_xz_plane.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/neg_xz_plane.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1985,7 +2033,11 @@ const pattn2 = patternLinear3d({
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/linear_pattern3d_a_pattern.png", &result, 1.0);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/linear_pattern3d_a_pattern.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -2008,7 +2060,11 @@ const pattn2 = patternCircular3d({axis: [0,0, 1], center: [-20, -20, -20], repet
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/circular_pattern3d_a_pattern.png", &result, 1.0);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/circular_pattern3d_a_pattern.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -2037,7 +2093,7 @@ extrude(10, sketch001)
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/array_of_sketches.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/array_of_sketches.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -2103,7 +2159,7 @@ const sketch001 = startSketchOn(bracket, 'seg01')
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/sketch_on_face_after_fillets_referencing_face.png",
|
"tests/executor/outputs/sketch_on_face_after_fillets_referencing_face.png",
|
||||||
&result,
|
&result,
|
||||||
1.0,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2140,7 +2196,11 @@ const pattn1 = patternLinear3d({
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/pattern3d_array_of_extrudes.png", &result, 1.0);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/pattern3d_array_of_extrudes.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -2191,7 +2251,7 @@ const baseExtrusion = extrude(width, sketch001)
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/fillets_referencing_other_fillets.png",
|
"tests/executor/outputs/fillets_referencing_other_fillets.png",
|
||||||
&result,
|
&result,
|
||||||
1.0,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2243,7 +2303,7 @@ const baseExtrusion = extrude(width, sketch001)
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/chamfers_referencing_other_chamfers.png",
|
"tests/executor/outputs/chamfers_referencing_other_chamfers.png",
|
||||||
&result,
|
&result,
|
||||||
1.0,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2302,7 +2362,7 @@ const pattn1 = patternLinear3d({
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/linear_pattern3d_filleted_sketch.png",
|
"tests/executor/outputs/linear_pattern3d_filleted_sketch.png",
|
||||||
&result,
|
&result,
|
||||||
1.0,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2333,7 +2393,7 @@ const pattn2 = patternCircular3d({axis: [0,0, 1], center: [-20, -20, -20], repet
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/circular_pattern3d_filleted_sketch.png",
|
"tests/executor/outputs/circular_pattern3d_filleted_sketch.png",
|
||||||
&result,
|
&result,
|
||||||
1.0,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2364,7 +2424,7 @@ const pattn2 = patternCircular3d({axis: [0,0, 1], center: [-20, -20, -20], repet
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/circular_pattern3d_chamfered_sketch.png",
|
"tests/executor/outputs/circular_pattern3d_chamfered_sketch.png",
|
||||||
&result,
|
&result,
|
||||||
1.0,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2429,7 +2489,11 @@ const sketch001 = startSketchOn(part001, 'chamfer1')
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_of_chamfer.png", &result, 1.0);
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/sketch_on_face_of_chamfer.png",
|
||||||
|
&result,
|
||||||
|
MIN_DIFF,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -2463,21 +2527,21 @@ let p = triangle(200)
|
|||||||
async fn serial_test_global_tags() {
|
async fn serial_test_global_tags() {
|
||||||
let code = include_str!("inputs/global-tags.kcl");
|
let code = include_str!("inputs/global-tags.kcl");
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/global_tags.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/global_tags.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn serial_test_pattern_vase() {
|
async fn serial_test_pattern_vase() {
|
||||||
let code = include_str!("inputs/pattern_vase.kcl");
|
let code = include_str!("inputs/pattern_vase.kcl");
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/pattern_vase.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/pattern_vase.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn serial_test_scoped_tags() {
|
async fn serial_test_scoped_tags() {
|
||||||
let code = include_str!("inputs/scoped-tags.kcl");
|
let code = include_str!("inputs/scoped-tags.kcl");
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/scoped_tags.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/scoped_tags.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -2487,7 +2551,7 @@ async fn serial_test_order_sketch_extrude_in_order() {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/order-sketch-extrude-in-order.png",
|
"tests/executor/outputs/order-sketch-extrude-in-order.png",
|
||||||
&result,
|
&result,
|
||||||
0.999,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2498,7 +2562,7 @@ async fn serial_test_order_sketch_extrude_out_of_order() {
|
|||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/order-sketch-extrude-out-of-order.png",
|
"tests/executor/outputs/order-sketch-extrude-out-of-order.png",
|
||||||
&result,
|
&result,
|
||||||
0.999,
|
MIN_DIFF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2506,5 +2570,5 @@ async fn serial_test_order_sketch_extrude_out_of_order() {
|
|||||||
async fn serial_test_extrude_custom_plane() {
|
async fn serial_test_extrude_custom_plane() {
|
||||||
let code = include_str!("inputs/extrude-custom-plane.kcl");
|
let code = include_str!("inputs/extrude-custom-plane.kcl");
|
||||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/extrude-custom-plane.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/extrude-custom-plane.png", &result, MIN_DIFF);
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 165 KiB |