Update code mods for extrude so that new top-level constants are created (#2549)
* Make sketch and extrude produce separate top-level constants * Fix most tests * Add a breaking test for sketch on face AST mod * Use `extrude` instead of `part` * Implement @Irev-Dev's branch changes from https://github.com/KittyCAD/modeling-app/pull/2472 * Get extrude on face working * Update incorrect sketch on face test * Update unit tests * Fix up E2E test changes * fmt * Fix a couple of goofed up test updates * More specific names for paths to node sent to modelingMachine * Bump down playwright workers for now * Slightly more explicit type coercion * Update snapshot tests * Missed one other new flow test that wasn't updated to use "sketch001" * Typo * Damn missed one more sorry * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Re-run CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * I think the multiple sketches test reverted from under me --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
@ -93,7 +93,7 @@ test('Basic sketch', async ({ page }) => {
|
|||||||
await page.mouse.click(700, 200)
|
await page.mouse.click(700, 200)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
`const part001 = startSketchOn('XZ')`
|
`const sketch001 = startSketchOn('XZ')`
|
||||||
)
|
)
|
||||||
await u.closeDebugPanel()
|
await u.closeDebugPanel()
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ test('Basic sketch', async ({ page }) => {
|
|||||||
const startXPx = 600
|
const startXPx = 600
|
||||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)`)
|
|> startProfileAt(${commonPoints.startAt}, %)`)
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
@ -110,20 +110,20 @@ test('Basic sketch', async ({ page }) => {
|
|||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|> startProfileAt(${commonPoints.startAt}, %)
|
||||||
|> line([${commonPoints.num1}, 0], %)`)
|
|> line([${commonPoints.num1}, 0], %)`)
|
||||||
|
|
||||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|> startProfileAt(${commonPoints.startAt}, %)
|
||||||
|> line([${commonPoints.num1}, 0], %)
|
|> line([${commonPoints.num1}, 0], %)
|
||||||
|> line([0, ${commonPoints.num1}], %)`)
|
|> line([0, ${commonPoints.num1}], %)`)
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await page.mouse.click(startXPx, 500 - PUR * 20)
|
await page.mouse.click(startXPx, 500 - PUR * 20)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|> startProfileAt(${commonPoints.startAt}, %)
|
||||||
|> line([${commonPoints.num1}, 0], %)
|
|> line([${commonPoints.num1}, 0], %)
|
||||||
|> line([0, ${commonPoints.num1}], %)
|
|> line([0, ${commonPoints.num1}], %)
|
||||||
@ -149,7 +149,7 @@ test('Basic sketch', async ({ page }) => {
|
|||||||
await page.getByRole('button', { name: 'Equal Length' }).click()
|
await page.getByRole('button', { name: 'Equal Length' }).click()
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|> startProfileAt(${commonPoints.startAt}, %)
|
||||||
|> line([${commonPoints.num1}, 0], %, 'seg01')
|
|> line([${commonPoints.num1}, 0], %, 'seg01')
|
||||||
|> line([0, ${commonPoints.num1}], %)
|
|> line([0, ${commonPoints.num1}], %)
|
||||||
@ -331,7 +331,7 @@ test('if you click the format button it formats your code', async ({
|
|||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||||
|
|
||||||
await page.click('.cm-content')
|
await page.click('.cm-content')
|
||||||
await page.keyboard.type(`const part001 = startSketchOn('XY')
|
await page.keyboard.type(`const sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, -10], %)
|
|> startProfileAt([-10, -10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, 20], %)
|
|> line([0, 20], %)
|
||||||
@ -341,7 +341,7 @@ test('if you click the format button it formats your code', async ({
|
|||||||
await page.click('button:has-text("Format code")')
|
await page.click('button:has-text("Format code")')
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XY')
|
.toHaveText(`const sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, -10], %)
|
|> startProfileAt([-10, -10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, 20], %)
|
|> line([0, 20], %)
|
||||||
@ -356,7 +356,7 @@ test('if you use the format keyboard binding it formats your code', async ({
|
|||||||
await page.addInitScript(async () => {
|
await page.addInitScript(async () => {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'persistCode',
|
'persistCode',
|
||||||
`const part001 = startSketchOn('XY')
|
`const sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, -10], %)
|
|> startProfileAt([-10, -10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, 20], %)
|
|> line([0, 20], %)
|
||||||
@ -392,7 +392,7 @@ test('if you use the format keyboard binding it formats your code', async ({
|
|||||||
await page.keyboard.press('Alt+Shift+KeyF')
|
await page.keyboard.press('Alt+Shift+KeyF')
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XY')
|
.toHaveText(`const sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, -10], %)
|
|> startProfileAt([-10, -10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, 20], %)
|
|> line([0, 20], %)
|
||||||
@ -605,7 +605,7 @@ test('executes on load', async ({ page }) => {
|
|||||||
await page.addInitScript(async () => {
|
await page.addInitScript(async () => {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'persistCode',
|
'persistCode',
|
||||||
`const part001 = startSketchOn('-XZ')
|
`const sketch001 = startSketchOn('-XZ')
|
||||||
|> startProfileAt([-6.95, 4.98], %)
|
|> startProfileAt([-6.95, 4.98], %)
|
||||||
|> line([25.1, 0.41], %)
|
|> line([25.1, 0.41], %)
|
||||||
|> line([0.73, -14.93], %)
|
|> line([0.73, -14.93], %)
|
||||||
@ -623,16 +623,16 @@ test('executes on load', async ({ page }) => {
|
|||||||
})
|
})
|
||||||
await variablesTabButton.click()
|
await variablesTabButton.click()
|
||||||
|
|
||||||
// can find part001 in the variables summary (pretty-json-container, makes sure we're not looking in the code editor)
|
// can find sketch001 in the variables summary (pretty-json-container, makes sure we're not looking in the code editor)
|
||||||
// part001 only shows up in the variables summary if it's been executed
|
// sketch001 only shows up in the variables summary if it's been executed
|
||||||
await page.waitForFunction(() => {
|
await page.waitForFunction(() => {
|
||||||
const variablesElement = document.querySelector(
|
const variablesElement = document.querySelector(
|
||||||
'.pretty-json-container'
|
'.pretty-json-container'
|
||||||
) as HTMLDivElement
|
) as HTMLDivElement
|
||||||
return variablesElement.innerHTML.includes('part001')
|
return variablesElement.innerHTML.includes('sketch001')
|
||||||
})
|
})
|
||||||
await expect(
|
await expect(
|
||||||
page.locator('.pretty-json-container >> text=part001')
|
page.locator('.pretty-json-container >> text=sketch001')
|
||||||
).toBeVisible()
|
).toBeVisible()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -698,7 +698,7 @@ const sketchOnPlaneAndBackSideTest = async (
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const code = `const part001 = startSketchOn('${plane}')
|
const code = `const sketch001 = startSketchOn('${plane}')
|
||||||
|> startProfileAt([1.14, -1.54], %)`
|
|> startProfileAt([1.14, -1.54], %)`
|
||||||
|
|
||||||
await u.openDebugPanel()
|
await u.openDebugPanel()
|
||||||
@ -787,7 +787,7 @@ test('Auto complete works', async ({ page }) => {
|
|||||||
// and arrowing down to an option
|
// and arrowing down to an option
|
||||||
|
|
||||||
await page.click('.cm-content')
|
await page.click('.cm-content')
|
||||||
await page.keyboard.type('const part001 = start')
|
await page.keyboard.type('const sketch001 = start')
|
||||||
|
|
||||||
// expect there to be six auto complete options
|
// expect there to be six auto complete options
|
||||||
await expect(page.locator('.cm-completionLabel')).toHaveCount(6)
|
await expect(page.locator('.cm-completionLabel')).toHaveCount(6)
|
||||||
@ -827,7 +827,7 @@ test('Auto complete works', async ({ page }) => {
|
|||||||
await expect(page.locator('.cm-completionLabel')).not.toBeVisible()
|
await expect(page.locator('.cm-completionLabel')).not.toBeVisible()
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([3.14, 12], %)
|
|> startProfileAt([3.14, 12], %)
|
||||||
|> xLine(5, %) // lin`)
|
|> xLine(5, %) // lin`)
|
||||||
})
|
})
|
||||||
@ -1182,28 +1182,28 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
|
|||||||
await u.closeDebugPanel()
|
await u.closeDebugPanel()
|
||||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)`)
|
|> startProfileAt(${commonPoints.startAt}, %)`)
|
||||||
|
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
|
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|> startProfileAt(${commonPoints.startAt}, %)
|
||||||
|> line([${commonPoints.num1}, 0], %)`)
|
|> line([${commonPoints.num1}, 0], %)`)
|
||||||
|
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|> startProfileAt(${commonPoints.startAt}, %)
|
||||||
|> line([${commonPoints.num1}, 0], %)
|
|> line([${commonPoints.num1}, 0], %)
|
||||||
|> line([0, ${commonPoints.num1}], %)`)
|
|> line([0, ${commonPoints.num1}], %)`)
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await page.mouse.click(startXPx, 500 - PUR * 20)
|
await page.mouse.click(startXPx, 500 - PUR * 20)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|> startProfileAt(${commonPoints.startAt}, %)
|
||||||
|> line([${commonPoints.num1}, 0], %)
|
|> line([${commonPoints.num1}, 0], %)
|
||||||
|> line([0, ${commonPoints.num1}], %)
|
|> line([0, ${commonPoints.num1}], %)
|
||||||
@ -1433,7 +1433,7 @@ test.describe('Command bar tests', () => {
|
|||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'persistCode',
|
'persistCode',
|
||||||
`const distance = sqrt(20)
|
`const distance = sqrt(20)
|
||||||
const part001 = startSketchOn('XZ')
|
const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([-6.95, 10.98], %)
|
|> startProfileAt([-6.95, 10.98], %)
|
||||||
|> line([25.1, 0.41], %)
|
|> line([25.1, 0.41], %)
|
||||||
|> line([0.73, -20.93], %)
|
|> line([0.73, -20.93], %)
|
||||||
@ -1503,13 +1503,16 @@ test.describe('Command bar tests', () => {
|
|||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
`const distance = sqrt(20)
|
`const distance = sqrt(20)
|
||||||
const distance001 = ${KCL_DEFAULT_LENGTH}
|
const distance001 = ${KCL_DEFAULT_LENGTH}
|
||||||
const part001 = startSketchOn('XZ')
|
const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([-6.95, 10.98], %)
|
|> startProfileAt([-6.95, 10.98], %)
|
||||||
|> line([25.1, 0.41], %)
|
|> line([25.1, 0.41], %)
|
||||||
|> line([0.73, -20.93], %)
|
|> line([0.73, -20.93], %)
|
||||||
|> line([-23.44, 0.52], %)
|
|> line([-23.44, 0.52], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(distance001, %)`.replace(/(\r\n|\n|\r)/gm, '') // remove newlines
|
const extrude001 = extrude(distance001, sketch001)`.replace(
|
||||||
|
/(\r\n|\n|\r)/gm,
|
||||||
|
''
|
||||||
|
) // remove newlines
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -1538,7 +1541,7 @@ test('Can add multiple sketches', async ({ page }) => {
|
|||||||
200
|
200
|
||||||
)
|
)
|
||||||
|
|
||||||
let codeStr = "const part001 = startSketchOn('XY')"
|
let codeStr = "const sketch001 = startSketchOn('XY')"
|
||||||
|
|
||||||
await page.mouse.click(center.x, viewportSize.height * 0.55)
|
await page.mouse.click(center.x, viewportSize.height * 0.55)
|
||||||
await expectCodeToBe(codeStr)
|
await expectCodeToBe(codeStr)
|
||||||
@ -1576,7 +1579,7 @@ test('Can add multiple sketches', async ({ page }) => {
|
|||||||
// so selecting the plane again is a bit easier.
|
// so selecting the plane again is a bit easier.
|
||||||
await page.mouse.click(center.x + 30, center.y)
|
await page.mouse.click(center.x + 30, center.y)
|
||||||
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
|
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
|
||||||
codeStr += "const part002 = startSketchOn('XY')"
|
codeStr += "const sketch002 = startSketchOn('XY')"
|
||||||
await expectCodeToBe(codeStr)
|
await expectCodeToBe(codeStr)
|
||||||
await u.closeDebugPanel()
|
await u.closeDebugPanel()
|
||||||
|
|
||||||
@ -1763,14 +1766,14 @@ test("Various pipe expressions should and shouldn't allow edit and or extrude",
|
|||||||
|> line([-27.65, -2.78], %)
|
|> line([-27.65, -2.78], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(5, %)
|
|> extrude(5, %)
|
||||||
const part002 = startSketchOn('XZ')
|
const sketch002 = startSketchOn('XZ')
|
||||||
${extrudeAndEditAllowed}
|
${extrudeAndEditAllowed}
|
||||||
|> line([10.32, 6.47], %)
|
|> line([10.32, 6.47], %)
|
||||||
|> line([9.71, -6.16], %)
|
|> line([9.71, -6.16], %)
|
||||||
|> line([-3.08, -9.86], %)
|
|> line([-3.08, -9.86], %)
|
||||||
|> line([-12.02, -1.54], %)
|
|> line([-12.02, -1.54], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
const part003 = startSketchOn('XZ')
|
const sketch003 = startSketchOn('XZ')
|
||||||
${editOnly}
|
${editOnly}
|
||||||
|> line([27.55, -1.65], %)
|
|> line([27.55, -1.65], %)
|
||||||
|> line([4.95, -8], %)
|
|> line([4.95, -8], %)
|
||||||
@ -1778,7 +1781,7 @@ const part003 = startSketchOn('XZ')
|
|||||||
|> line([-15.79, 17.08], %)
|
|> line([-15.79, 17.08], %)
|
||||||
|
|
||||||
fn yohey = (pos) => {
|
fn yohey = (pos) => {
|
||||||
const part004 = startSketchOn('XZ')
|
const sketch004 = startSketchOn('XZ')
|
||||||
${extrudeAndEditBlockedInFunction}
|
${extrudeAndEditBlockedInFunction}
|
||||||
|> line([27.55, -1.65], %)
|
|> line([27.55, -1.65], %)
|
||||||
|> line([4.95, -10.53], %)
|
|> line([4.95, -10.53], %)
|
||||||
@ -1833,15 +1836,15 @@ fn yohey = (pos) => {
|
|||||||
page.getByRole('button', { name: 'Edit Sketch' })
|
page.getByRole('button', { name: 'Edit Sketch' })
|
||||||
).not.toBeVisible()
|
).not.toBeVisible()
|
||||||
|
|
||||||
// selecting an editable sketch but clicking "start sktech" should start a new sketch and not edit the existing one
|
// selecting an editable sketch but clicking "start sketch" should start a new sketch and not edit the existing one
|
||||||
await page.getByText(selectionsSnippets.extrudeAndEditAllowed).click()
|
await page.getByText(selectionsSnippets.extrudeAndEditAllowed).click()
|
||||||
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
||||||
await page.getByTestId('KCL Code').click()
|
await page.getByTestId('KCL Code').click()
|
||||||
await page.mouse.click(734, 134)
|
await page.mouse.click(734, 134)
|
||||||
await page.getByTestId('KCL Code').click()
|
await page.getByTestId('KCL Code').click()
|
||||||
// expect main content to contain `part005` i.e. started a new sketch
|
// expect main content to contain `sketch005` i.e. started a new sketch
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
/part005 = startSketchOn\('XZ'\)/
|
/sketch001 = startSketchOn\('XZ'\)/
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1869,7 +1872,7 @@ test('Deselecting line tool should mean nothing happens on click', async ({
|
|||||||
await page.mouse.click(700, 200)
|
await page.mouse.click(700, 200)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
`const part001 = startSketchOn('XZ')`
|
`const sketch001 = startSketchOn('XZ')`
|
||||||
)
|
)
|
||||||
|
|
||||||
await page.waitForTimeout(600)
|
await page.waitForTimeout(600)
|
||||||
@ -1997,7 +2000,7 @@ test('Can edit segments by dragging their handles', async ({ page }) => {
|
|||||||
await page.addInitScript(async () => {
|
await page.addInitScript(async () => {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'persistCode',
|
'persistCode',
|
||||||
`const part001 = startSketchOn('XZ')
|
`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([4.61, -14.01], %)
|
|> startProfileAt([4.61, -14.01], %)
|
||||||
|> line([12.73, -0.09], %)
|
|> line([12.73, -0.09], %)
|
||||||
|> tangentialArcTo([24.95, -5.38], %)`
|
|> tangentialArcTo([24.95, -5.38], %)`
|
||||||
@ -2079,7 +2082,7 @@ test('Can edit segments by dragging their handles', async ({ page }) => {
|
|||||||
|
|
||||||
// expect the code to have changed
|
// expect the code to have changed
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([6.44, -12.07], %)
|
|> startProfileAt([6.44, -12.07], %)
|
||||||
|> line([14.72, 1.97], %)
|
|> line([14.72, 1.97], %)
|
||||||
|> tangentialArcTo([26.92, -3.32], %)`)
|
|> tangentialArcTo([26.92, -3.32], %)`)
|
||||||
@ -2097,7 +2100,7 @@ const doSnapAtDifferentScales = async (
|
|||||||
await u.waitForAuthSkipAppStart()
|
await u.waitForAuthSkipAppStart()
|
||||||
await u.openDebugPanel()
|
await u.openDebugPanel()
|
||||||
|
|
||||||
const code = `const part001 = startSketchOn('-XZ')
|
const code = `const sketch001 = startSketchOn('-XZ')
|
||||||
|> startProfileAt([${roundOff(scale * 87.68)}, ${roundOff(scale * 43.84)}], %)
|
|> startProfileAt([${roundOff(scale * 87.68)}, ${roundOff(scale * 43.84)}], %)
|
||||||
|> line([${roundOff(scale * 175.36)}, 0], %)
|
|> line([${roundOff(scale * 175.36)}, 0], %)
|
||||||
|> line([0, -${roundOff(scale * 175.36) + fudge}], %)
|
|> line([0, -${roundOff(scale * 175.36) + fudge}], %)
|
||||||
@ -2120,7 +2123,7 @@ const doSnapAtDifferentScales = async (
|
|||||||
// select a plane
|
// select a plane
|
||||||
await page.mouse.click(700, 200)
|
await page.mouse.click(700, 200)
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
`const part001 = startSketchOn('-XZ')`
|
`const sketch001 = startSketchOn('-XZ')`
|
||||||
)
|
)
|
||||||
|
|
||||||
let prevContent = await page.locator('.cm-content').innerText()
|
let prevContent = await page.locator('.cm-content').innerText()
|
||||||
@ -2182,7 +2185,7 @@ test('Sketch on face', async ({ page }) => {
|
|||||||
await page.addInitScript(async () => {
|
await page.addInitScript(async () => {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'persistCode',
|
'persistCode',
|
||||||
`const part001 = startSketchOn('XZ')
|
`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([3.29, 7.86], %)
|
|> startProfileAt([3.29, 7.86], %)
|
||||||
|> line([2.48, 2.44], %)
|
|> line([2.48, 2.44], %)
|
||||||
|> line([2.66, 1.17], %)
|
|> line([2.66, 1.17], %)
|
||||||
@ -2195,7 +2198,7 @@ test('Sketch on face', async ({ page }) => {
|
|||||||
|> line([-3.86, -2.73], %)
|
|> line([-3.86, -2.73], %)
|
||||||
|> line([-17.67, 0.85], %)
|
|> line([-17.67, 0.85], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(5 + 7, %)`
|
const extrude001 = extrude(5 + 7, sketch001)`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -2249,7 +2252,7 @@ test('Sketch on face', async ({ page }) => {
|
|||||||
previousCodeContent = await page.locator('.cm-content').innerText()
|
previousCodeContent = await page.locator('.cm-content').innerText()
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toContainText(`const part002 = startSketchOn(part001, 'seg01')
|
.toContainText(`const sketch002 = startSketchOn(extrude001, 'seg01')
|
||||||
|> startProfileAt([-12.94, 6.6], %)
|
|> startProfileAt([-12.94, 6.6], %)
|
||||||
|> line([2.45, -0.2], %)
|
|> line([2.45, -0.2], %)
|
||||||
|> line([-2.6, -1.25], %)
|
|> line([-2.6, -1.25], %)
|
||||||
@ -2288,7 +2291,7 @@ test('Sketch on face', async ({ page }) => {
|
|||||||
await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent)
|
await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent)
|
||||||
previousCodeContent = await page.locator('.cm-content').innerText()
|
previousCodeContent = await page.locator('.cm-content').innerText()
|
||||||
|
|
||||||
const result = makeTemplate`const part002 = startSketchOn(part001, 'seg01')
|
const result = makeTemplate`const sketch002 = startSketchOn(extrude001, 'seg01')
|
||||||
|> startProfileAt([-12.83, 6.7], %)
|
|> startProfileAt([-12.83, 6.7], %)
|
||||||
|> line([${[2.28, 2.35]}, -${0.07}], %)
|
|> line([${[2.28, 2.35]}, -${0.07}], %)
|
||||||
|> line([-3.05, -1.47], %)
|
|> line([-3.05, -1.47], %)
|
||||||
@ -2317,7 +2320,7 @@ test('Sketch on face', async ({ page }) => {
|
|||||||
await page.keyboard.press('Enter')
|
await page.keyboard.press('Enter')
|
||||||
|
|
||||||
const result2 = result.genNext`
|
const result2 = result.genNext`
|
||||||
|> extrude(${[5, 5]} + 7, %)`
|
const sketch002 = extrude(${[5, 5]} + 7, sketch002)`
|
||||||
await expect(page.locator('.cm-content')).toHaveText(result2.regExp)
|
await expect(page.locator('.cm-content')).toHaveText(result2.regExp)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -2325,7 +2328,7 @@ test('Can code mod a line length', async ({ page }) => {
|
|||||||
await page.addInitScript(async () => {
|
await page.addInitScript(async () => {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'persistCode',
|
'persistCode',
|
||||||
`const part001 = startSketchOn('XY')
|
`const sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, -10], %)
|
|> startProfileAt([-10, -10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, 20], %)
|
|> line([0, 20], %)
|
||||||
@ -2363,7 +2366,7 @@ test('Can code mod a line length', async ({ page }) => {
|
|||||||
await page.getByText('Add constraining value').click()
|
await page.getByText('Add constraining value').click()
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
`const length001 = 20const part001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> angledLine([90, length001], %) |> xLine(-20, %)`
|
`const length001 = 20const sketch001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> angledLine([90, length001], %) |> xLine(-20, %)`
|
||||||
)
|
)
|
||||||
|
|
||||||
// Make sure we didn't pop out of sketch mode.
|
// Make sure we didn't pop out of sketch mode.
|
||||||
@ -2385,7 +2388,7 @@ test('Extrude from command bar selects extrude line after', async ({
|
|||||||
await page.addInitScript(async () => {
|
await page.addInitScript(async () => {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'persistCode',
|
'persistCode',
|
||||||
`const part001 = startSketchOn('XY')
|
`const sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, -10], %)
|
|> startProfileAt([-10, -10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, 20], %)
|
|> line([0, 20], %)
|
||||||
@ -2415,7 +2418,7 @@ test('Extrude from command bar selects extrude line after', async ({
|
|||||||
await page.keyboard.press('Enter')
|
await page.keyboard.press('Enter')
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await expect(page.locator('.cm-activeLine')).toHaveText(
|
await expect(page.locator('.cm-activeLine')).toHaveText(
|
||||||
` |> extrude(${KCL_DEFAULT_LENGTH}, %)`
|
`const extrude001 = extrude(${KCL_DEFAULT_LENGTH}, sketch001)`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -4663,7 +4666,7 @@ test('Engine disconnect & reconnect in sketch mode', async ({ page }) => {
|
|||||||
await page.mouse.click(700, 200)
|
await page.mouse.click(700, 200)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
`const part001 = startSketchOn('XZ')`
|
`const sketch001 = startSketchOn('XZ')`
|
||||||
)
|
)
|
||||||
await u.closeDebugPanel()
|
await u.closeDebugPanel()
|
||||||
|
|
||||||
@ -4672,7 +4675,7 @@ test('Engine disconnect & reconnect in sketch mode', async ({ page }) => {
|
|||||||
const startXPx = 600
|
const startXPx = 600
|
||||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)`)
|
|> startProfileAt(${commonPoints.startAt}, %)`)
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
@ -4680,7 +4683,7 @@ test('Engine disconnect & reconnect in sketch mode', async ({ page }) => {
|
|||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|> startProfileAt(${commonPoints.startAt}, %)
|
||||||
|> line([${commonPoints.num1}, 0], %)`)
|
|> line([${commonPoints.num1}, 0], %)`)
|
||||||
|
|
||||||
@ -4743,14 +4746,14 @@ test('Engine disconnect & reconnect in sketch mode', async ({ page }) => {
|
|||||||
// Ensure we can continue sketching
|
// Ensure we can continue sketching
|
||||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|> startProfileAt(${commonPoints.startAt}, %)
|
||||||
|> line([${commonPoints.num1}, 0], %)
|
|> line([${commonPoints.num1}, 0], %)
|
||||||
|> line([-11.64, 11.11], %)`)
|
|> line([-11.64, 11.11], %)`)
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await page.mouse.click(startXPx, 500 - PUR * 20)
|
await page.mouse.click(startXPx, 500 - PUR * 20)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|> startProfileAt(${commonPoints.startAt}, %)
|
||||||
|> line([${commonPoints.num1}, 0], %)
|
|> line([${commonPoints.num1}, 0], %)
|
||||||
|> line([-11.64, 11.11], %)
|
|> line([-11.64, 11.11], %)
|
||||||
|
@ -406,7 +406,7 @@ test('Draft segments should look right', async ({ page, context }) => {
|
|||||||
await page.mouse.click(700, 200)
|
await page.mouse.click(700, 200)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
`const part001 = startSketchOn('XZ')`
|
`const sketch001 = startSketchOn('XZ')`
|
||||||
)
|
)
|
||||||
|
|
||||||
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
|
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
|
||||||
@ -414,7 +414,7 @@ test('Draft segments should look right', async ({ page, context }) => {
|
|||||||
const startXPx = 600
|
const startXPx = 600
|
||||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([9.06, -12.22], %)`)
|
|> startProfileAt([9.06, -12.22], %)`)
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
@ -428,7 +428,7 @@ test('Draft segments should look right', async ({ page, context }) => {
|
|||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([9.06, -12.22], %)
|
|> startProfileAt([9.06, -12.22], %)
|
||||||
|> line([9.14, 0], %)`)
|
|> line([9.14, 0], %)`)
|
||||||
|
|
||||||
@ -465,7 +465,7 @@ test('Draft rectangles should look right', async ({ page, context }) => {
|
|||||||
await page.mouse.click(700, 200)
|
await page.mouse.click(700, 200)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
`const part001 = startSketchOn('XZ')`
|
`const sketch001 = startSketchOn('XZ')`
|
||||||
)
|
)
|
||||||
|
|
||||||
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
|
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
|
||||||
@ -514,7 +514,7 @@ test.describe('Client side scene scale should match engine scale', () => {
|
|||||||
await page.mouse.click(700, 200)
|
await page.mouse.click(700, 200)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
`const part001 = startSketchOn('XZ')`
|
`const sketch001 = startSketchOn('XZ')`
|
||||||
)
|
)
|
||||||
|
|
||||||
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
|
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
|
||||||
@ -522,7 +522,7 @@ test.describe('Client side scene scale should match engine scale', () => {
|
|||||||
const startXPx = 600
|
const startXPx = 600
|
||||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([9.06, -12.22], %)`)
|
|> startProfileAt([9.06, -12.22], %)`)
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
@ -532,7 +532,7 @@ test.describe('Client side scene scale should match engine scale', () => {
|
|||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([9.06, -12.22], %)
|
|> startProfileAt([9.06, -12.22], %)
|
||||||
|> line([9.14, 0], %)`)
|
|> line([9.14, 0], %)`)
|
||||||
|
|
||||||
@ -542,7 +542,7 @@ test.describe('Client side scene scale should match engine scale', () => {
|
|||||||
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
|
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([9.06, -12.22], %)
|
|> startProfileAt([9.06, -12.22], %)
|
||||||
|> line([9.14, 0], %)
|
|> line([9.14, 0], %)
|
||||||
|> tangentialArcTo([27.34, -3.08], %)`)
|
|> tangentialArcTo([27.34, -3.08], %)`)
|
||||||
@ -617,7 +617,7 @@ test.describe('Client side scene scale should match engine scale', () => {
|
|||||||
await page.mouse.click(700, 200)
|
await page.mouse.click(700, 200)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
`const part001 = startSketchOn('XZ')`
|
`const sketch001 = startSketchOn('XZ')`
|
||||||
)
|
)
|
||||||
|
|
||||||
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
|
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
|
||||||
@ -625,7 +625,7 @@ test.describe('Client side scene scale should match engine scale', () => {
|
|||||||
const startXPx = 600
|
const startXPx = 600
|
||||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([230.03, -310.32], %)`)
|
|> startProfileAt([230.03, -310.32], %)`)
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
@ -635,7 +635,7 @@ test.describe('Client side scene scale should match engine scale', () => {
|
|||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([230.03, -310.32], %)
|
|> startProfileAt([230.03, -310.32], %)
|
||||||
|> line([232.2, 0], %)`)
|
|> line([232.2, 0], %)`)
|
||||||
|
|
||||||
@ -645,7 +645,7 @@ test.describe('Client side scene scale should match engine scale', () => {
|
|||||||
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
|
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('XZ')
|
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([230.03, -310.32], %)
|
|> startProfileAt([230.03, -310.32], %)
|
||||||
|> line([232.2, 0], %)
|
|> line([232.2, 0], %)
|
||||||
|> tangentialArcTo([694.43, -78.12], %)`)
|
|> tangentialArcTo([694.43, -78.12], %)`)
|
||||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 66 KiB |
@ -93,7 +93,10 @@ import { createGridHelper, orthoScale, perspScale } from './helpers'
|
|||||||
import { Models } from '@kittycad/lib'
|
import { Models } from '@kittycad/lib'
|
||||||
import { uuidv4 } from 'lib/utils'
|
import { uuidv4 } from 'lib/utils'
|
||||||
import { SegmentOverlayPayload, SketchDetails } from 'machines/modelingMachine'
|
import { SegmentOverlayPayload, SketchDetails } from 'machines/modelingMachine'
|
||||||
import { EngineCommandManager } from 'lang/std/engineConnection'
|
import {
|
||||||
|
ArtifactMapCommand,
|
||||||
|
EngineCommandManager,
|
||||||
|
} from 'lang/std/engineConnection'
|
||||||
import {
|
import {
|
||||||
getRectangleCallExpressions,
|
getRectangleCallExpressions,
|
||||||
updateRectangleSketch,
|
updateRectangleSketch,
|
||||||
@ -759,14 +762,6 @@ export class SceneEntities {
|
|||||||
|
|
||||||
_ast = parse(recast(_ast))
|
_ast = parse(recast(_ast))
|
||||||
|
|
||||||
console.log('onClick', {
|
|
||||||
sketchInit: sketchInit,
|
|
||||||
_ast,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
truncatedAst,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Update the primary AST and unequip the rectangle tool
|
// Update the primary AST and unequip the rectangle tool
|
||||||
await kclManager.executeAstMock(_ast)
|
await kclManager.executeAstMock(_ast)
|
||||||
sceneInfra.modelingSend({ type: 'CancelSketch' })
|
sceneInfra.modelingSend({ type: 'CancelSketch' })
|
||||||
@ -1422,6 +1417,30 @@ export class SceneEntities {
|
|||||||
return ['plane', entity_id]
|
return ['plane', entity_id]
|
||||||
}
|
}
|
||||||
const artifact = this.engineCommandManager.artifactMap[entity_id]
|
const artifact = this.engineCommandManager.artifactMap[entity_id]
|
||||||
|
// If we clicked on an extrude wall, we climb up the parent Id
|
||||||
|
// to get the sketch profile's face ID. If we clicked on an endcap,
|
||||||
|
// we already have it.
|
||||||
|
const targetId =
|
||||||
|
'additionalData' in artifact &&
|
||||||
|
artifact.additionalData?.type === 'cap'
|
||||||
|
? entity_id
|
||||||
|
: artifact.parentId
|
||||||
|
|
||||||
|
// tsc cannot infer that target can have extrusions
|
||||||
|
// from the commandType (why?) so we need to cast it
|
||||||
|
const target = this.engineCommandManager.artifactMap?.[
|
||||||
|
targetId || ''
|
||||||
|
] as ArtifactMapCommand & { extrusions?: string[] }
|
||||||
|
|
||||||
|
// TODO: We get the first extrusion command ID,
|
||||||
|
// which is fine while backend systems only support one extrusion.
|
||||||
|
// but we need to more robustly handle resolving to the correct extrusion
|
||||||
|
// if there are multiple.
|
||||||
|
const extrusions =
|
||||||
|
this.engineCommandManager.artifactMap?.[
|
||||||
|
target?.extrusions?.[0] || ''
|
||||||
|
]
|
||||||
|
|
||||||
if (artifact?.commandType !== 'solid3d_get_extrusion_face_info')
|
if (artifact?.commandType !== 'solid3d_get_extrusion_face_info')
|
||||||
return ['other', entity_id]
|
return ['other', entity_id]
|
||||||
|
|
||||||
@ -1429,10 +1448,13 @@ export class SceneEntities {
|
|||||||
if (!faceInfo?.origin || !faceInfo?.z_axis || !faceInfo?.y_axis)
|
if (!faceInfo?.origin || !faceInfo?.z_axis || !faceInfo?.y_axis)
|
||||||
return ['other', entity_id]
|
return ['other', entity_id]
|
||||||
const { z_axis, y_axis, origin } = faceInfo
|
const { z_axis, y_axis, origin } = faceInfo
|
||||||
const pathToNode = getNodePathFromSourceRange(
|
const sketchPathToNode = getNodePathFromSourceRange(
|
||||||
kclManager.ast,
|
kclManager.ast,
|
||||||
artifact.range
|
artifact.range
|
||||||
)
|
)
|
||||||
|
const extrudePathToNode = extrusions?.range
|
||||||
|
? getNodePathFromSourceRange(kclManager.ast, extrusions.range)
|
||||||
|
: []
|
||||||
|
|
||||||
sceneInfra.modelingSend({
|
sceneInfra.modelingSend({
|
||||||
type: 'Select default plane',
|
type: 'Select default plane',
|
||||||
@ -1443,7 +1465,8 @@ export class SceneEntities {
|
|||||||
position: [origin.x, origin.y, origin.z].map(
|
position: [origin.x, origin.y, origin.z].map(
|
||||||
(num) => num / sceneInfra._baseUnitMultiplier
|
(num) => num / sceneInfra._baseUnitMultiplier
|
||||||
) as [number, number, number],
|
) as [number, number, number],
|
||||||
extrudeSegmentPathToNode: pathToNode,
|
sketchPathToNode,
|
||||||
|
extrudePathToNode,
|
||||||
cap:
|
cap:
|
||||||
artifact?.additionalData?.type === 'cap'
|
artifact?.additionalData?.type === 'cap'
|
||||||
? artifact.additionalData.info
|
? artifact.additionalData.info
|
||||||
@ -1455,7 +1478,6 @@ export class SceneEntities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const faceResult = await checkExtrudeFaceClick()
|
const faceResult = await checkExtrudeFaceClick()
|
||||||
console.log('faceResult', faceResult)
|
|
||||||
if (faceResult[0] === 'face') return
|
if (faceResult[0] === 'face') return
|
||||||
|
|
||||||
if (!args || !args.intersects?.[0]) return
|
if (!args || !args.intersects?.[0]) return
|
||||||
|
@ -453,7 +453,8 @@ export const ModelingMachineProvider = ({
|
|||||||
const { modifiedAst, pathToNode: pathToNewSketchNode } =
|
const { modifiedAst, pathToNode: pathToNewSketchNode } =
|
||||||
sketchOnExtrudedFace(
|
sketchOnExtrudedFace(
|
||||||
kclManager.ast,
|
kclManager.ast,
|
||||||
data.extrudeSegmentPathToNode,
|
data.sketchPathToNode,
|
||||||
|
data.extrudePathToNode,
|
||||||
kclManager.programMemory,
|
kclManager.programMemory,
|
||||||
data.cap
|
data.cap
|
||||||
)
|
)
|
||||||
|
@ -125,7 +125,7 @@ describe('Testing addSketchTo', () => {
|
|||||||
'yz'
|
'yz'
|
||||||
)
|
)
|
||||||
const str = recast(result.modifiedAst)
|
const str = recast(result.modifiedAst)
|
||||||
expect(str).toBe(`const part001 = startSketchOn('YZ')
|
expect(str).toBe(`const sketch001 = startSketchOn('YZ')
|
||||||
|> startProfileAt('default', %)
|
|> startProfileAt('default', %)
|
||||||
|> line('default', %)
|
|> line('default', %)
|
||||||
`)
|
`)
|
||||||
@ -291,14 +291,25 @@ describe('testing sketchOnExtrudedFace', () => {
|
|||||||
|> extrude(5 + 7, %)`
|
|> extrude(5 + 7, %)`
|
||||||
const ast = parse(code)
|
const ast = parse(code)
|
||||||
const programMemory = await enginelessExecutor(ast)
|
const programMemory = await enginelessExecutor(ast)
|
||||||
const snippet = `line([9.7, 9.19], %)`
|
const segmentSnippet = `line([9.7, 9.19], %)`
|
||||||
const range: [number, number] = [
|
const segmentRange: [number, number] = [
|
||||||
code.indexOf(snippet),
|
code.indexOf(segmentSnippet),
|
||||||
code.indexOf(snippet) + snippet.length,
|
code.indexOf(segmentSnippet) + segmentSnippet.length,
|
||||||
]
|
]
|
||||||
const pathToNode = getNodePathFromSourceRange(ast, range)
|
const segmentPathToNode = getNodePathFromSourceRange(ast, segmentRange)
|
||||||
|
const extrudeSnippet = `extrude(5 + 7, %)`
|
||||||
|
const extrudeRange: [number, number] = [
|
||||||
|
code.indexOf(extrudeSnippet),
|
||||||
|
code.indexOf(extrudeSnippet) + extrudeSnippet.length,
|
||||||
|
]
|
||||||
|
const extrudePathToNode = getNodePathFromSourceRange(ast, extrudeRange)
|
||||||
|
|
||||||
const { modifiedAst } = sketchOnExtrudedFace(ast, pathToNode, programMemory)
|
const { modifiedAst } = sketchOnExtrudedFace(
|
||||||
|
ast,
|
||||||
|
segmentPathToNode,
|
||||||
|
extrudePathToNode,
|
||||||
|
programMemory
|
||||||
|
)
|
||||||
const newCode = recast(modifiedAst)
|
const newCode = recast(modifiedAst)
|
||||||
expect(newCode).toContain(`const part001 = startSketchOn('-XZ')
|
expect(newCode).toContain(`const part001 = startSketchOn('-XZ')
|
||||||
|> startProfileAt([3.58, 2.06], %)
|
|> startProfileAt([3.58, 2.06], %)
|
||||||
@ -306,7 +317,7 @@ describe('testing sketchOnExtrudedFace', () => {
|
|||||||
|> line([8.62, -9.57], %)
|
|> line([8.62, -9.57], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(5 + 7, %)
|
|> extrude(5 + 7, %)
|
||||||
const part002 = startSketchOn(part001, 'seg01')`)
|
const sketch001 = startSketchOn(part001, 'seg01')`)
|
||||||
})
|
})
|
||||||
test('it should be able to extrude on close segments', async () => {
|
test('it should be able to extrude on close segments', async () => {
|
||||||
const code = `const part001 = startSketchOn('-XZ')
|
const code = `const part001 = startSketchOn('-XZ')
|
||||||
@ -317,14 +328,25 @@ const part002 = startSketchOn(part001, 'seg01')`)
|
|||||||
|> extrude(5 + 7, %)`
|
|> extrude(5 + 7, %)`
|
||||||
const ast = parse(code)
|
const ast = parse(code)
|
||||||
const programMemory = await enginelessExecutor(ast)
|
const programMemory = await enginelessExecutor(ast)
|
||||||
const snippet = `close(%)`
|
const segmentSnippet = `close(%)`
|
||||||
const range: [number, number] = [
|
const segmentRange: [number, number] = [
|
||||||
code.indexOf(snippet),
|
code.indexOf(segmentSnippet),
|
||||||
code.indexOf(snippet) + snippet.length,
|
code.indexOf(segmentSnippet) + segmentSnippet.length,
|
||||||
]
|
]
|
||||||
const pathToNode = getNodePathFromSourceRange(ast, range)
|
const segmentPathToNode = getNodePathFromSourceRange(ast, segmentRange)
|
||||||
|
const extrudeSnippet = `extrude(5 + 7, %)`
|
||||||
|
const extrudeRange: [number, number] = [
|
||||||
|
code.indexOf(extrudeSnippet),
|
||||||
|
code.indexOf(extrudeSnippet) + extrudeSnippet.length,
|
||||||
|
]
|
||||||
|
const extrudePathToNode = getNodePathFromSourceRange(ast, extrudeRange)
|
||||||
|
|
||||||
const { modifiedAst } = sketchOnExtrudedFace(ast, pathToNode, programMemory)
|
const { modifiedAst } = sketchOnExtrudedFace(
|
||||||
|
ast,
|
||||||
|
segmentPathToNode,
|
||||||
|
extrudePathToNode,
|
||||||
|
programMemory
|
||||||
|
)
|
||||||
const newCode = recast(modifiedAst)
|
const newCode = recast(modifiedAst)
|
||||||
expect(newCode).toContain(`const part001 = startSketchOn('-XZ')
|
expect(newCode).toContain(`const part001 = startSketchOn('-XZ')
|
||||||
|> startProfileAt([3.58, 2.06], %)
|
|> startProfileAt([3.58, 2.06], %)
|
||||||
@ -332,7 +354,7 @@ const part002 = startSketchOn(part001, 'seg01')`)
|
|||||||
|> line([8.62, -9.57], %)
|
|> line([8.62, -9.57], %)
|
||||||
|> close(%, 'seg01')
|
|> close(%, 'seg01')
|
||||||
|> extrude(5 + 7, %)
|
|> extrude(5 + 7, %)
|
||||||
const part002 = startSketchOn(part001, 'seg01')`)
|
const sketch001 = startSketchOn(part001, 'seg01')`)
|
||||||
})
|
})
|
||||||
test('it should be able to extrude on start-end caps', async () => {
|
test('it should be able to extrude on start-end caps', async () => {
|
||||||
const code = `const part001 = startSketchOn('-XZ')
|
const code = `const part001 = startSketchOn('-XZ')
|
||||||
@ -343,16 +365,23 @@ const part002 = startSketchOn(part001, 'seg01')`)
|
|||||||
|> extrude(5 + 7, %)`
|
|> extrude(5 + 7, %)`
|
||||||
const ast = parse(code)
|
const ast = parse(code)
|
||||||
const programMemory = await enginelessExecutor(ast)
|
const programMemory = await enginelessExecutor(ast)
|
||||||
const snippet = `startProfileAt([3.58, 2.06], %)`
|
const sketchSnippet = `startProfileAt([3.58, 2.06], %)`
|
||||||
const range: [number, number] = [
|
const sketchRange: [number, number] = [
|
||||||
code.indexOf(snippet),
|
code.indexOf(sketchSnippet),
|
||||||
code.indexOf(snippet) + snippet.length,
|
code.indexOf(sketchSnippet) + sketchSnippet.length,
|
||||||
]
|
]
|
||||||
const pathToNode = getNodePathFromSourceRange(ast, range)
|
const sketchPathToNode = getNodePathFromSourceRange(ast, sketchRange)
|
||||||
|
const extrudeSnippet = `extrude(5 + 7, %)`
|
||||||
|
const extrudeRange: [number, number] = [
|
||||||
|
code.indexOf(extrudeSnippet),
|
||||||
|
code.indexOf(extrudeSnippet) + extrudeSnippet.length,
|
||||||
|
]
|
||||||
|
const extrudePathToNode = getNodePathFromSourceRange(ast, extrudeRange)
|
||||||
|
|
||||||
const { modifiedAst } = sketchOnExtrudedFace(
|
const { modifiedAst } = sketchOnExtrudedFace(
|
||||||
ast,
|
ast,
|
||||||
pathToNode,
|
sketchPathToNode,
|
||||||
|
extrudePathToNode,
|
||||||
programMemory,
|
programMemory,
|
||||||
'end'
|
'end'
|
||||||
)
|
)
|
||||||
@ -363,7 +392,47 @@ const part002 = startSketchOn(part001, 'seg01')`)
|
|||||||
|> line([8.62, -9.57], %)
|
|> line([8.62, -9.57], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(5 + 7, %)
|
|> extrude(5 + 7, %)
|
||||||
const part002 = startSketchOn(part001, 'END')`)
|
const sketch001 = startSketchOn(part001, 'END')`)
|
||||||
|
})
|
||||||
|
test('it should ensure that the new sketch is inserted after the extrude', async () => {
|
||||||
|
const code = `const sketch001 = startSketchOn('-XZ')
|
||||||
|
|> startProfileAt([3.29, 7.86], %)
|
||||||
|
|> line([2.48, 2.44], %)
|
||||||
|
|> line([2.66, 1.17], %)
|
||||||
|
|> line([3.75, 0.46], %)
|
||||||
|
|> line([4.99, -0.46], %)
|
||||||
|
|> line([3.3, -2.12], %)
|
||||||
|
|> line([2.16, -3.33], %)
|
||||||
|
|> line([0.85, -3.08], %)
|
||||||
|
|> line([-0.18, -3.36], %)
|
||||||
|
|> line([-3.86, -2.73], %)
|
||||||
|
|> line([-17.67, 0.85], %)
|
||||||
|
|> close(%)
|
||||||
|
const part001 = extrude(5 + 7, sketch001)`
|
||||||
|
const ast = parse(code)
|
||||||
|
const programMemory = await enginelessExecutor(ast)
|
||||||
|
const segmentSnippet = `line([4.99, -0.46], %)`
|
||||||
|
const segmentRange: [number, number] = [
|
||||||
|
code.indexOf(segmentSnippet),
|
||||||
|
code.indexOf(segmentSnippet) + segmentSnippet.length,
|
||||||
|
]
|
||||||
|
const segmentPathToNode = getNodePathFromSourceRange(ast, segmentRange)
|
||||||
|
const extrudeSnippet = `extrude(5 + 7, sketch001)`
|
||||||
|
const extrudeRange: [number, number] = [
|
||||||
|
code.indexOf(extrudeSnippet),
|
||||||
|
code.indexOf(extrudeSnippet) + extrudeSnippet.length,
|
||||||
|
]
|
||||||
|
const extrudePathToNode = getNodePathFromSourceRange(ast, extrudeRange)
|
||||||
|
|
||||||
|
const { modifiedAst } = sketchOnExtrudedFace(
|
||||||
|
ast,
|
||||||
|
segmentPathToNode,
|
||||||
|
extrudePathToNode,
|
||||||
|
programMemory
|
||||||
|
)
|
||||||
|
const newCode = recast(modifiedAst)
|
||||||
|
expect(newCode).toContain(`const part001 = extrude(5 + 7, sketch001)
|
||||||
|
const sketch002 = startSketchOn(part001, 'seg01')`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ import {
|
|||||||
} from './std/sketchcombos'
|
} from './std/sketchcombos'
|
||||||
import { DefaultPlaneStr } from 'clientSideScene/sceneEntities'
|
import { DefaultPlaneStr } from 'clientSideScene/sceneEntities'
|
||||||
import { isOverlap, roundOff } from 'lib/utils'
|
import { isOverlap, roundOff } from 'lib/utils'
|
||||||
|
import { KCL_DEFAULT_CONSTANT_PREFIXES } from 'lib/constants'
|
||||||
import { ConstrainInfo } from './std/stdTypes'
|
import { ConstrainInfo } from './std/stdTypes'
|
||||||
|
|
||||||
export function startSketchOnDefault(
|
export function startSketchOnDefault(
|
||||||
@ -42,7 +43,8 @@ export function startSketchOnDefault(
|
|||||||
name = ''
|
name = ''
|
||||||
): { modifiedAst: Program; id: string; pathToNode: PathToNode } {
|
): { modifiedAst: Program; id: string; pathToNode: PathToNode } {
|
||||||
const _node = { ...node }
|
const _node = { ...node }
|
||||||
const _name = name || findUniqueName(node, 'part')
|
const _name =
|
||||||
|
name || findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.SKETCH)
|
||||||
|
|
||||||
const startSketchOn = createCallExpressionStdLib('startSketchOn', [
|
const startSketchOn = createCallExpressionStdLib('startSketchOn', [
|
||||||
createLiteral(axis),
|
createLiteral(axis),
|
||||||
@ -109,7 +111,8 @@ export function addSketchTo(
|
|||||||
name = ''
|
name = ''
|
||||||
): { modifiedAst: Program; id: string; pathToNode: PathToNode } {
|
): { modifiedAst: Program; id: string; pathToNode: PathToNode } {
|
||||||
const _node = { ...node }
|
const _node = { ...node }
|
||||||
const _name = name || findUniqueName(node, 'part')
|
const _name =
|
||||||
|
name || findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.SKETCH)
|
||||||
|
|
||||||
const startSketchOn = createCallExpressionStdLib('startSketchOn', [
|
const startSketchOn = createCallExpressionStdLib('startSketchOn', [
|
||||||
createLiteral(axis.toUpperCase()),
|
createLiteral(axis.toUpperCase()),
|
||||||
@ -242,7 +245,7 @@ export function mutateObjExpProp(
|
|||||||
export function extrudeSketch(
|
export function extrudeSketch(
|
||||||
node: Program,
|
node: Program,
|
||||||
pathToNode: PathToNode,
|
pathToNode: PathToNode,
|
||||||
shouldPipe = true,
|
shouldPipe = false,
|
||||||
distance = createLiteral(4) as Value
|
distance = createLiteral(4) as Value
|
||||||
): {
|
): {
|
||||||
modifiedAst: Program
|
modifiedAst: Program
|
||||||
@ -293,12 +296,22 @@ export function extrudeSketch(
|
|||||||
pathToExtrudeArg,
|
pathToExtrudeArg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const name = findUniqueName(node, 'part')
|
|
||||||
|
// We're not creating a pipe expression,
|
||||||
|
// but rather a separate constant for the extrusion
|
||||||
|
const name = findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.EXTRUDE)
|
||||||
const VariableDeclaration = createVariableDeclaration(name, extrudeCall)
|
const VariableDeclaration = createVariableDeclaration(name, extrudeCall)
|
||||||
_node.body.splice(_node.body.length, 0, VariableDeclaration)
|
|
||||||
|
const sketchIndexInPathToNode =
|
||||||
|
pathToDecleration.findIndex((a) => a[0] === 'body') + 1
|
||||||
|
const sketchIndexInBody = pathToDecleration[
|
||||||
|
sketchIndexInPathToNode
|
||||||
|
][0] as number
|
||||||
|
_node.body.splice(sketchIndexInBody + 1, 0, VariableDeclaration)
|
||||||
|
|
||||||
const pathToExtrudeArg: PathToNode = [
|
const pathToExtrudeArg: PathToNode = [
|
||||||
['body', ''],
|
['body', ''],
|
||||||
[_node.body.length, 'index'],
|
[sketchIndexInBody + 1, 'index'],
|
||||||
['declarations', 'VariableDeclaration'],
|
['declarations', 'VariableDeclaration'],
|
||||||
[0, 'index'],
|
[0, 'index'],
|
||||||
['init', 'VariableDeclarator'],
|
['init', 'VariableDeclarator'],
|
||||||
@ -306,7 +319,7 @@ export function extrudeSketch(
|
|||||||
[0, 'index'],
|
[0, 'index'],
|
||||||
]
|
]
|
||||||
return {
|
return {
|
||||||
modifiedAst: node,
|
modifiedAst: _node,
|
||||||
pathToNode: [...pathToNode.slice(0, -1), [-1, 'index']],
|
pathToNode: [...pathToNode.slice(0, -1), [-1, 'index']],
|
||||||
pathToExtrudeArg,
|
pathToExtrudeArg,
|
||||||
}
|
}
|
||||||
@ -314,31 +327,41 @@ export function extrudeSketch(
|
|||||||
|
|
||||||
export function sketchOnExtrudedFace(
|
export function sketchOnExtrudedFace(
|
||||||
node: Program,
|
node: Program,
|
||||||
pathToNode: PathToNode,
|
sketchPathToNode: PathToNode,
|
||||||
|
extrudePathToNode: PathToNode,
|
||||||
programMemory: ProgramMemory,
|
programMemory: ProgramMemory,
|
||||||
cap: 'none' | 'start' | 'end' = 'none'
|
cap: 'none' | 'start' | 'end' = 'none'
|
||||||
): { modifiedAst: Program; pathToNode: PathToNode } {
|
): { modifiedAst: Program; pathToNode: PathToNode } {
|
||||||
let _node = { ...node }
|
let _node = { ...node }
|
||||||
const newSketchName = findUniqueName(node, 'part')
|
const newSketchName = findUniqueName(
|
||||||
|
node,
|
||||||
|
KCL_DEFAULT_CONSTANT_PREFIXES.SKETCH
|
||||||
|
)
|
||||||
const { node: oldSketchNode } = getNodeFromPath<VariableDeclarator>(
|
const { node: oldSketchNode } = getNodeFromPath<VariableDeclarator>(
|
||||||
_node,
|
_node,
|
||||||
pathToNode,
|
sketchPathToNode,
|
||||||
'VariableDeclarator',
|
'VariableDeclarator',
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
const oldSketchName = oldSketchNode.id.name
|
const oldSketchName = oldSketchNode.id.name
|
||||||
const { node: expression } = getNodeFromPath<CallExpression>(
|
const { node: expression } = getNodeFromPath<CallExpression>(
|
||||||
_node,
|
_node,
|
||||||
pathToNode,
|
sketchPathToNode,
|
||||||
'CallExpression'
|
'CallExpression'
|
||||||
)
|
)
|
||||||
|
const { node: extrudeVarDec } = getNodeFromPath<VariableDeclarator>(
|
||||||
|
_node,
|
||||||
|
extrudePathToNode,
|
||||||
|
'VariableDeclarator'
|
||||||
|
)
|
||||||
|
const extrudeName = extrudeVarDec.id?.name
|
||||||
|
|
||||||
let _tag = ''
|
let _tag = ''
|
||||||
if (cap === 'none') {
|
if (cap === 'none') {
|
||||||
const { modifiedAst, tag } = addTagForSketchOnFace(
|
const { modifiedAst, tag } = addTagForSketchOnFace(
|
||||||
{
|
{
|
||||||
previousProgramMemory: programMemory,
|
previousProgramMemory: programMemory,
|
||||||
pathToNode,
|
pathToNode: sketchPathToNode,
|
||||||
node: _node,
|
node: _node,
|
||||||
},
|
},
|
||||||
expression.callee.name
|
expression.callee.name
|
||||||
@ -352,13 +375,16 @@ export function sketchOnExtrudedFace(
|
|||||||
const newSketch = createVariableDeclaration(
|
const newSketch = createVariableDeclaration(
|
||||||
newSketchName,
|
newSketchName,
|
||||||
createCallExpressionStdLib('startSketchOn', [
|
createCallExpressionStdLib('startSketchOn', [
|
||||||
createIdentifier(oldSketchName),
|
createIdentifier(extrudeName ? extrudeName : oldSketchName),
|
||||||
createLiteral(_tag),
|
createLiteral(_tag),
|
||||||
]),
|
]),
|
||||||
'const'
|
'const'
|
||||||
)
|
)
|
||||||
|
|
||||||
const expressionIndex = pathToNode[1][0] as number
|
const expressionIndex = Math.max(
|
||||||
|
sketchPathToNode[1][0] as number,
|
||||||
|
extrudePathToNode[1][0] as number
|
||||||
|
)
|
||||||
_node.body.splice(expressionIndex + 1, 0, newSketch)
|
_node.body.splice(expressionIndex + 1, 0, newSketch)
|
||||||
const newpathToNode: PathToNode = [
|
const newpathToNode: PathToNode = [
|
||||||
['body', ''],
|
['body', ''],
|
||||||
|
@ -12,22 +12,43 @@ let lastMessage = ''
|
|||||||
// TODO(paultag): This ought to be tweakable.
|
// TODO(paultag): This ought to be tweakable.
|
||||||
const pingIntervalMs = 10000
|
const pingIntervalMs = 10000
|
||||||
|
|
||||||
interface CommandInfo {
|
type CommandTypes = Models['ModelingCmd_type']['type'] | 'batch'
|
||||||
commandType: CommandTypes
|
|
||||||
range: SourceRange
|
type CommandInfo =
|
||||||
pathToNode: PathToNode
|
| {
|
||||||
parentId?: string
|
commandType: 'extrude'
|
||||||
additionalData?:
|
// commandType: CommandTypes
|
||||||
| {
|
range: SourceRange
|
||||||
type: 'cap'
|
pathToNode: PathToNode
|
||||||
info: 'start' | 'end'
|
/// uuid of the entity to extrude
|
||||||
}
|
target: string
|
||||||
| {
|
parentId?: string
|
||||||
type: 'batch-ids'
|
}
|
||||||
ids: string[]
|
| {
|
||||||
info?: null
|
commandType: 'start_path'
|
||||||
}
|
// commandType: CommandTypes
|
||||||
}
|
range: SourceRange
|
||||||
|
pathToNode: PathToNode
|
||||||
|
/// uuid of the entity that have been extruded
|
||||||
|
extrusions: string[]
|
||||||
|
parentId?: string
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
commandType: CommandTypes
|
||||||
|
range: SourceRange
|
||||||
|
pathToNode: PathToNode
|
||||||
|
parentId?: string
|
||||||
|
additionalData?:
|
||||||
|
| {
|
||||||
|
type: 'cap'
|
||||||
|
info: 'start' | 'end'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'batch-ids'
|
||||||
|
ids: string[]
|
||||||
|
info?: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function isHighlightSetEntity_type(
|
function isHighlightSetEntity_type(
|
||||||
data: any
|
data: any
|
||||||
@ -38,13 +59,13 @@ function isHighlightSetEntity_type(
|
|||||||
type WebSocketResponse = Models['WebSocketResponse_type']
|
type WebSocketResponse = Models['WebSocketResponse_type']
|
||||||
type OkWebSocketResponseData = Models['OkWebSocketResponseData_type']
|
type OkWebSocketResponseData = Models['OkWebSocketResponseData_type']
|
||||||
|
|
||||||
interface ResultCommand extends CommandInfo {
|
type ResultCommand = CommandInfo & {
|
||||||
type: 'result'
|
type: 'result'
|
||||||
data: any
|
data: any
|
||||||
raw: WebSocketResponse
|
raw: WebSocketResponse
|
||||||
headVertexId?: string
|
headVertexId?: string
|
||||||
}
|
}
|
||||||
interface FailedCommand extends CommandInfo {
|
type FailedCommand = CommandInfo & {
|
||||||
type: 'failed'
|
type: 'failed'
|
||||||
errors: Models['FailureWebSocketResponse_type']['errors']
|
errors: Models['FailureWebSocketResponse_type']['errors']
|
||||||
}
|
}
|
||||||
@ -57,12 +78,14 @@ interface ResolveCommand {
|
|||||||
data?: Models['OkModelingCmdResponse_type']
|
data?: Models['OkModelingCmdResponse_type']
|
||||||
errors?: Models['FailureWebSocketResponse_type']['errors']
|
errors?: Models['FailureWebSocketResponse_type']['errors']
|
||||||
}
|
}
|
||||||
interface PendingCommand extends CommandInfo {
|
type PendingCommand = CommandInfo & {
|
||||||
type: 'pending'
|
type: 'pending'
|
||||||
promise: Promise<any>
|
promise: Promise<any>
|
||||||
resolve: (val: ResolveCommand) => void
|
resolve: (val: ResolveCommand) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ArtifactMapCommand = ResultCommand | PendingCommand | FailedCommand
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ArtifactMap is a client-side representation of the artifacts that
|
* The ArtifactMap is a client-side representation of the artifacts that
|
||||||
* have been sent to the server-side engine. It is used to keep track of
|
* have been sent to the server-side engine. It is used to keep track of
|
||||||
@ -72,7 +95,7 @@ interface PendingCommand extends CommandInfo {
|
|||||||
* lines of KCL code that generated them.
|
* lines of KCL code that generated them.
|
||||||
*/
|
*/
|
||||||
export interface ArtifactMap {
|
export interface ArtifactMap {
|
||||||
[commandId: string]: ResultCommand | PendingCommand | FailedCommand
|
[commandId: string]: ArtifactMapCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NewTrackArgs {
|
interface NewTrackArgs {
|
||||||
@ -988,8 +1011,6 @@ class EngineConnection extends EventTarget {
|
|||||||
export type EngineCommand = Models['WebSocketRequest_type']
|
export type EngineCommand = Models['WebSocketRequest_type']
|
||||||
type ModelTypes = Models['OkModelingCmdResponse_type']['type']
|
type ModelTypes = Models['OkModelingCmdResponse_type']['type']
|
||||||
|
|
||||||
type CommandTypes = Models['ModelingCmd_type']['type'] | 'batch'
|
|
||||||
|
|
||||||
type UnreliableResponses = Extract<
|
type UnreliableResponses = Extract<
|
||||||
Models['OkModelingCmdResponse_type'],
|
Models['OkModelingCmdResponse_type'],
|
||||||
{ type: 'highlight_set_entity' | 'camera_drag_move' }
|
{ type: 'highlight_set_entity' | 'camera_drag_move' }
|
||||||
@ -1814,9 +1835,12 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
if (command.type === 'solid3d_get_extrusion_face_info') {
|
if (command.type === 'solid3d_get_extrusion_face_info') {
|
||||||
const edgeArtifact = this.artifactMap[command.edge_id]
|
const edgeArtifact = this.artifactMap[command.edge_id]
|
||||||
// edges's parent id is to the original "start_path" artifact
|
// edges's parent id is to the original "start_path" artifact
|
||||||
if (edgeArtifact?.parentId) return edgeArtifact.parentId
|
if (edgeArtifact && edgeArtifact.parentId) {
|
||||||
|
return edgeArtifact.parentId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (command.type === 'close_path') return command.path_id
|
if (command.type === 'close_path') return command.path_id
|
||||||
|
if (command.type === 'extrude') return command.target
|
||||||
// handle other commands that have a parent here
|
// handle other commands that have a parent here
|
||||||
}
|
}
|
||||||
const pathToNode = ast
|
const pathToNode = ast
|
||||||
@ -1831,6 +1855,33 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
promise,
|
promise,
|
||||||
resolve,
|
resolve,
|
||||||
}
|
}
|
||||||
|
if (command.type === 'extrude') {
|
||||||
|
this.artifactMap[id] = {
|
||||||
|
range: range || [0, 0],
|
||||||
|
pathToNode,
|
||||||
|
type: 'pending',
|
||||||
|
commandType: 'extrude',
|
||||||
|
parentId: getParentId(),
|
||||||
|
promise,
|
||||||
|
target: command.target,
|
||||||
|
resolve,
|
||||||
|
}
|
||||||
|
const target = this.artifactMap[command.target]
|
||||||
|
if (target.commandType === 'start_path') {
|
||||||
|
// tsc cannot infer that target can have extrusions
|
||||||
|
// from the commandType (why?) so we need to cast it
|
||||||
|
const typedTarget = target as (
|
||||||
|
| PendingCommand
|
||||||
|
| ResultCommand
|
||||||
|
| FailedCommand
|
||||||
|
) & { extrusions?: string[] }
|
||||||
|
if (typedTarget?.extrusions?.length) {
|
||||||
|
typedTarget.extrusions.push(id)
|
||||||
|
} else {
|
||||||
|
typedTarget.extrusions = [id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return promise
|
return promise
|
||||||
}
|
}
|
||||||
async handlePendingBatchCommand(
|
async handlePendingBatchCommand(
|
||||||
|
@ -44,5 +44,13 @@ export const RELEVANT_FILE_TYPES = [
|
|||||||
] as const
|
] as const
|
||||||
/** The default name for a tutorial project */
|
/** The default name for a tutorial project */
|
||||||
export const ONBOARDING_PROJECT_NAME = 'Tutorial Project $nn'
|
export const ONBOARDING_PROJECT_NAME = 'Tutorial Project $nn'
|
||||||
|
/**
|
||||||
|
* The default starting constant name for various modeling operations.
|
||||||
|
* These are used to generate unique names for new objects.
|
||||||
|
* */
|
||||||
|
export const KCL_DEFAULT_CONSTANT_PREFIXES = {
|
||||||
|
SKETCH: 'sketch',
|
||||||
|
EXTRUDE: 'extrude',
|
||||||
|
} as const
|
||||||
/** The default KCL length expression */
|
/** The default KCL length expression */
|
||||||
export const KCL_DEFAULT_LENGTH = `5`
|
export const KCL_DEFAULT_LENGTH = `5`
|
||||||
|
@ -145,7 +145,8 @@ export type ModelingMachineEvent =
|
|||||||
| {
|
| {
|
||||||
type: 'extrudeFace'
|
type: 'extrudeFace'
|
||||||
position: [number, number, number]
|
position: [number, number, number]
|
||||||
extrudeSegmentPathToNode: PathToNode
|
sketchPathToNode: PathToNode
|
||||||
|
extrudePathToNode: PathToNode
|
||||||
cap: 'start' | 'end' | 'none'
|
cap: 'start' | 'end' | 'none'
|
||||||
faceId: string
|
faceId: string
|
||||||
}
|
}
|
||||||
@ -883,7 +884,7 @@ export const modelingMachine = createMachine(
|
|||||||
const { modifiedAst, pathToExtrudeArg } = extrudeSketch(
|
const { modifiedAst, pathToExtrudeArg } = extrudeSketch(
|
||||||
ast,
|
ast,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
true,
|
false,
|
||||||
'variableName' in distance
|
'variableName' in distance
|
||||||
? distance.variableIdentifierAst
|
? distance.variableIdentifierAst
|
||||||
: distance.valueAst
|
: distance.valueAst
|
||||||
|