Compare commits

...

83 Commits

Author SHA1 Message Date
274631024e Add test snapshots on two tests 2025-03-28 14:41:39 -04:00
29ab4679c4 Merge branch 'main' into pierremtb/issue5504-Add-edit-flow-for-Revolve 2025-03-28 13:51:30 -04:00
f7501e3cef Fix edit insert order 2025-03-28 13:18:27 -04:00
8fbdac439b Merge branch 'main' into pierremtb/issue5504-Add-edit-flow-for-Revolve 2025-03-28 12:25:23 -04:00
05add6b038 Lint 2025-03-28 07:34:41 -04:00
7364877539 Add edit flow for Revolve
Fixes #5504
2025-03-28 07:03:57 -04:00
327bd31a84 Add edit flow for Revolve
Fixes #5504
2025-03-26 07:59:46 -04:00
4292ba84f0 A snapshot a day keeps the bugs away! 📷🐛 2025-03-25 19:37:32 +00:00
848f7ec074 Fix third test 2025-03-25 15:27:36 -04:00
a61f4def7c Update from main, add proper error returns 2025-03-25 07:26:17 -04:00
afb3517446 Lint 2025-03-24 17:22:22 -04:00
483a390e9e A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 20:55:23 +00:00
8abd2481dc A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 20:45:42 +00:00
e8bf7f63a3 A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 20:36:00 +00:00
2aba760f88 A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 20:26:36 +00:00
08283391aa Update from main 2025-03-24 16:12:02 -04:00
bae2a717ad A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 18:13:40 +00:00
6c07e506d3 Clean up 2025-03-24 14:03:28 -04:00
6405b7f12c A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 17:59:54 +00:00
79c7478e8e Merge branch 'pierremtb/issue5504-Add-edit-flow-for-Revolve' of https://github.com/KittyCAD/modeling-app into pierremtb/issue5504-Add-edit-flow-for-Revolve 2025-03-24 13:50:14 -04:00
b11df628a6 Move to fromPromise actor, fix test 2025-03-24 13:50:12 -04:00
c974e87d24 A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 17:41:55 +00:00
71d450249e A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 17:31:05 +00:00
3d6ca78e15 A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 17:21:07 +00:00
4d7d4aa8e0 A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 17:11:40 +00:00
e24a608c82 A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 17:01:50 +00:00
dff3a9f1b8 Merge branch 'pierremtb/issue5393-Add-edge-and-segment-selection-in-point-and-click-Helix-flow' into pierremtb/issue5504-Add-edit-flow-for-Revolve 2025-03-24 12:51:33 -04:00
657d99209a Merge branch 'pierremtb/adhoc/update-helix-snaps' into pierremtb/issue5393-Add-edge-and-segment-selection-in-point-and-click-Helix-flow 2025-03-24 12:51:12 -04:00
acf56c5f2b Another one :djkhaled: 2025-03-24 12:46:19 -04:00
3029c40641 A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 16:44:11 +00:00
3255606221 Merge branch 'pierremtb/issue5393-Add-edge-and-segment-selection-in-point-and-click-Helix-flow' into pierremtb/issue5504-Add-edit-flow-for-Revolve 2025-03-24 12:34:03 -04:00
714ea0f0d0 A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 16:26:18 +00:00
b11054d16e A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 16:23:28 +00:00
1de8fb4c21 A snapshot a day keeps the bugs away! 📷🐛 2025-03-24 16:16:46 +00:00
2538f87861 Update 2020 snapshots after helix change 2025-03-24 12:10:04 -04:00
fc7f74249d Update 2020 snapshots after helix change 2025-03-24 12:09:06 -04:00
2475ef784a Remove uneeded return 2025-03-24 12:07:02 -04:00
9e1963a78c Rebase on helix branch 2025-03-24 11:36:00 -04:00
20b52f9d6a Merge branch 'main' into pierremtb/issue5504-Add-edit-flow-for-Revolve 2025-03-24 11:04:57 -04:00
0ee1de43f9 Fix tsc 2025-03-24 10:58:31 -04:00
1ec7e0540b Use displayName: 'CounterClockWise' cause ccw not cutting it 2025-03-24 10:17:45 -04:00
e5e243ef1e Fix up tests after ccw change 2025-03-24 10:13:12 -04:00
0ea2f6f63b Update from main 2025-03-24 10:05:08 -04:00
30df930006 Clean up, add edit steps to three e2e tests 2025-03-23 07:50:16 -04:00
f17760522b A snapshot a day keeps the bugs away! 📷🐛 2025-03-23 11:19:14 +00:00
acd26dbfb6 WIP: Add edit flow for Revolve
Fixes #5504
2025-03-23 07:10:06 -04:00
149f920901 Clean up snapshots 2025-03-20 18:39:09 -04:00
0df9e676b4 Add edge and segment selection in point-and-click Helix flow
Fixes #5393
2025-03-20 18:38:13 -04:00
e2d12321db A snapshot a day keeps the bugs away! 📷🐛 2025-03-20 00:11:47 +00:00
3b58e97644 A snapshot a day keeps the bugs away! 📷🐛 2025-03-20 00:02:10 +00:00
35a1a14ac3 Lint 2025-03-19 19:52:32 -04:00
8f95414700 Update from main 2025-03-19 19:51:55 -04:00
907a6f1dfa Merge branch 'main' into pierremtb/issue5393-Add-edge-and-segment-selection-in-point-and-click-Helix-flow 2025-03-19 17:21:54 -04:00
343e2d591d Add support for sweepEdge and tests 2025-03-19 17:12:49 -04:00
50a648881f A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 17:51:35 +00:00
fb7cbd1fbd Add skip: true for edge helix to be consistent with axis as options 2025-03-19 13:36:57 -04:00
c50c6ef325 A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 17:35:12 +00:00
1ecaba1ace Use updateModelingState in codemod 2025-03-19 13:24:30 -04:00
6f6656fa49 A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 17:18:07 +00:00
7cbc1dd988 Add edge and segment selection in point-and-click Helix flow
Fixes #5393
2025-03-19 13:07:57 -04:00
e9148ca50a A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 15:15:58 +00:00
a8f6263a1c A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 15:05:43 +00:00
5a9762a456 A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 14:55:58 +00:00
262e799a91 A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 14:46:17 +00:00
487e33c000 A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 14:36:03 +00:00
a065bee335 Merge branch 'pierremtb/issue5393-Add-edge-and-segment-selection-in-point-and-click-Helix-flow' of https://github.com/KittyCAD/modeling-app into pierremtb/issue5393-Add-edge-and-segment-selection-in-point-and-click-Helix-flow 2025-03-19 10:25:54 -04:00
d2f784e50a Add utility function for shared code between revolve and helix 2025-03-19 10:25:49 -04:00
dd33bf8ced A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 14:22:45 +00:00
f490b91923 A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 14:11:28 +00:00
dd4923282a A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 14:01:42 +00:00
bb85781c42 A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 13:51:25 +00:00
4df74e87ab A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 13:41:39 +00:00
e77e3e064a A snapshot a day keeps the bugs away! 📷🐛 2025-03-19 13:22:35 +00:00
ea7608ad67 Add edge and segment selection in point-and-click Helix flow
Fixes #5393
2025-03-19 09:13:02 -04:00
195b72e899 A snapshot a day keeps the bugs away! 📷🐛 2025-03-18 18:29:54 +00:00
b675809424 A snapshot a day keeps the bugs away! 📷🐛 2025-03-18 18:10:55 +00:00
75a68efde6 A snapshot a day keeps the bugs away! 📷🐛 2025-03-18 18:01:03 +00:00
968e90f507 A snapshot a day keeps the bugs away! 📷🐛 2025-03-18 17:51:45 +00:00
32b088f9bc Working edge based helix edit 2025-03-18 13:42:29 -04:00
8c5d8fc4cf A snapshot a day keeps the bugs away! 📷🐛 2025-03-18 17:38:37 +00:00
bf5837c249 A snapshot a day keeps the bugs away! 📷🐛 2025-03-18 17:29:16 +00:00
1a97eaa8f5 A snapshot a day keeps the bugs away! 📷🐛 2025-03-18 17:19:39 +00:00
03e4de6099 WIP: Add edge and segment selection in point-and-click Helix flow
Fixes #5393
2025-03-18 13:10:00 -04:00
11 changed files with 500 additions and 191 deletions

View File

@ -3409,17 +3409,16 @@ sweep001 = sweep(sketch001, path = sketch002)
}) })
}) })
test.describe('Revolve point and click workflows', () => { test('Revolve point-and-click base case workflow with auto spam continue in command bar', async ({
test('Base case workflow, auto spam continue in command bar', async ({ context,
context, page,
page, homePage,
homePage, scene,
scene, editor,
editor, toolbar,
toolbar, cmdBar,
cmdBar, }) => {
}) => { const initialCode = `
const initialCode = `
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([-100.0, 100.0], %) |> startProfileAt([-100.0, 100.0], %)
|> angledLine([0, 200.0], %, $rectangleSegmentA001) |> angledLine([0, 200.0], %, $rectangleSegmentA001)
@ -3446,13 +3445,14 @@ segAng(rectangleSegmentA002),
|> close() |> close()
` `
await context.addInitScript((initialCode) => { await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode) localStorage.setItem('persistCode', initialCode)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.waitForExecutionDone() await scene.waitForExecutionDone()
await test.step('Add revolve through the command bar and code selection', async () => {
// select line of code // select line of code
const codeToSelecton = `segAng(rectangleSegmentA002) - 90,` const codeToSelecton = `segAng(rectangleSegmentA002) - 90,`
// revolve // revolve
@ -3462,47 +3462,76 @@ segAng(rectangleSegmentA002),
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await editor.snapshot({ name: 'revolve-base-add' })
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = 'X')`
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
}) })
test('revolve surface around edge from an extruded solid2d', async ({
context, await test.step('Edit flow', async () => {
page, const newAngle = '90'
homePage, await toolbar.openPane('feature-tree')
scene, const operationButton = await toolbar.getFeatureTreeOperation(
editor, 'Revolve',
toolbar, 0
cmdBar, )
}) => { await operationButton.dblclick({ button: 'left' })
const initialCode = ` await cmdBar.expectState({
sketch001 = startSketchOn(XZ) commandName: 'Revolve',
|> startProfileAt([-102.57, 101.72], %) currentArgKey: 'angle',
|> angledLine([0, 202.6], %, $rectangleSegmentA001) currentArgValue: '360',
|> angledLine([ headerArguments: {
segAng(rectangleSegmentA001) - 90, Angle: '360',
202.6 },
], %, $rectangleSegmentB001) highlightedHeaderArg: 'angle',
|> angledLine([ stage: 'arguments',
segAng(rectangleSegmentA001), })
-segLen(rectangleSegmentA001) await page.keyboard.insertText(newAngle)
], %, $rectangleSegmentC001) await cmdBar.progressCmdBar()
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) await cmdBar.expectState({
|> close() stage: 'review',
headerArguments: {
Angle: newAngle,
},
commandName: 'Revolve',
})
await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree')
await editor.snapshot({ name: 'revolve-base-edit' })
})
})
test('Revolve point-and-click surface around edge from an extruded solid2d', async ({
context,
page,
homePage,
scene,
editor,
toolbar,
cmdBar,
}) => {
const initialCode = `sketch001 = startSketchOn(XZ)
|> startProfileAt([-102.57, 101.72], %)
|> angledLine([0, 202.6], %, $rectangleSegmentA001)
|> angledLine([
segAng(rectangleSegmentA001) - 90,
202.6
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
extrude001 = extrude(sketch001, length = 50) extrude001 = extrude(sketch001, length = 50)
sketch002 = startSketchOn(extrude001, rectangleSegmentA001) sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
|> circle( |> circle(center = [-11.34, 10.0], radius = 8.69)
center = [-11.34, 10.0],
radius = 8.69
)
` `
await context.addInitScript((initialCode) => { await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode) localStorage.setItem('persistCode', initialCode)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.waitForExecutionDone() await scene.waitForExecutionDone()
await test.step('Add through the command bar and code selection', async () => {
// select line of code // select line of code
const codeToSelecton = `center = [-11.34, 10.0]` const codeToSelecton = `center = [-11.34, 10.0]`
// revolve // revolve
@ -3512,61 +3541,118 @@ radius = 8.69
const lineCodeToSelection = `|> angledLine([0, 202.6], %, $rectangleSegmentA001)` const lineCodeToSelection = `|> angledLine([0, 202.6], %, $rectangleSegmentA001)`
await page.getByText(lineCodeToSelection).click() await page.getByText(lineCodeToSelection).click()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = getOppositeEdge(rectangleSegmentA001)) ` await cmdBar.progressCmdBar()
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy() await editor.snapshot({ name: 'revolve-solid-edge-add' })
}) })
test('revolve sketch circle around line segment from startProfileAt sketch', async ({
context, await test.step('Edit flow', async () => {
page, const newAngle = '180'
homePage, await toolbar.openPane('feature-tree')
scene, const operationButton = await toolbar.getFeatureTreeOperation('Revolve', 0)
editor, await operationButton.dblclick({ button: 'left' })
toolbar, await cmdBar.expectState({
cmdBar, commandName: 'Revolve',
}) => { currentArgKey: 'angle',
const initialCode = ` currentArgValue: '360',
sketch002 = startSketchOn(XY) headerArguments: {
|> startProfileAt([-2.02, 1.79], %) Angle: '360',
|> xLine(length = 2.6) },
sketch001 = startSketchOn('-XY') highlightedHeaderArg: 'angle',
|> startProfileAt([-0.48, 1.25], %) stage: 'arguments',
|> angledLine([0, 2.38], %, $rectangleSegmentA001) })
|> angledLine([segAng(rectangleSegmentA001) - 90, 2.4], %, $rectangleSegmentB001) await page.keyboard.insertText(newAngle)
|> angledLine([ await cmdBar.progressCmdBar()
segAng(rectangleSegmentA001), await cmdBar.expectState({
-segLen(rectangleSegmentA001) stage: 'review',
], %, $rectangleSegmentC001) headerArguments: {
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) Angle: newAngle,
|> close() },
extrude001 = extrude(sketch001, length = 5) commandName: 'Revolve',
sketch003 = startSketchOn(extrude001, 'START') })
|> circle( await cmdBar.progressCmdBar()
center = [-0.69, 0.56], await toolbar.closePane('feature-tree')
radius = 0.28 await editor.snapshot({ name: 'revolve-solid-edge-edit' })
) })
})
test('Revolve point-and-click sketch circle around line segment from startProfileAt sketch', async ({
context,
page,
homePage,
scene,
editor,
toolbar,
cmdBar,
}) => {
const initialCode = `sketch002 = startSketchOn(XY)
|> startProfileAt([-2.02, 1.79], %)
|> xLine(length = 2.6)
sketch001 = startSketchOn(-XY)
|> startProfileAt([-0.48, 1.25], %)
|> angledLine([0, 2.38], %, $rectangleSegmentA001)
|> angledLine([segAng(rectangleSegmentA001) - 90, 2.4], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
extrude001 = extrude(sketch001, length = 5)
sketch003 = startSketchOn(extrude001, 'START')
|> circle(center = [-0.69, 0.56], radius = 0.28)
` `
await context.addInitScript((initialCode) => { await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode) localStorage.setItem('persistCode', initialCode)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.waitForExecutionDone() await scene.waitForExecutionDone()
// select line of code // select line of code
const codeToSelecton = `center = [-0.69, 0.56]` const codeToSelecton = `center = [-0.69, 0.56]`
// revolve // revolve
await page.getByText(codeToSelecton).click() await page.getByText(codeToSelecton).click()
await toolbar.revolveButton.click() await toolbar.revolveButton.click()
await page.getByText('Edge', { exact: true }).click() await page.getByText('Edge', { exact: true }).click()
const lineCodeToSelection = `|> xLine(length = 2.6)` const lineCodeToSelection = `|> xLine(length = 2.6)`
await page.getByText(lineCodeToSelection).click() await page.getByText(lineCodeToSelection).click()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
const newCodeToFind = `revolve001 = revolve(sketch003, angle = 360, axis = seg01)` const newCodeToFind = `revolve001 = revolve(sketch003, angle = 360, axis = seg01)`
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy() expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
// Edit flow
const newAngle = '270'
await toolbar.openPane('feature-tree')
const operationButton = await toolbar.getFeatureTreeOperation('Revolve', 0)
await operationButton.dblclick({ button: 'left' })
await cmdBar.expectState({
commandName: 'Revolve',
currentArgKey: 'angle',
currentArgValue: '360',
headerArguments: {
Angle: '360',
},
highlightedHeaderArg: 'angle',
stage: 'arguments',
}) })
await page.keyboard.insertText(newAngle)
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Angle: newAngle,
},
commandName: 'Revolve',
})
await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree')
await editor.expectEditor.toContain(
newCodeToFind.replace('angle = 360', 'angle = ' + newAngle)
)
}) })
test(`Set appearance`, async ({ test(`Set appearance`, async ({

View File

@ -0,0 +1 @@
sketch001 = startSketchOn(XZ) |> startProfileAt([-100.0, 100.0], %) |> angledLine([0, 200.0], %, $rectangleSegmentA001) |> angledLine([segAng(rectangleSegmentA001) - 90, 200], %, $rectangleSegmentB001) |> angledLine([ segAng(rectangleSegmentA001), -segLen(rectangleSegmentA001) ], %, $rectangleSegmentC001) |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> close()extrude001 = extrude(sketch001, length = 200)sketch002 = startSketchOn(extrude001, rectangleSegmentA001) |> startProfileAt([-66.77, 84.81], %) |> angledLine([180, 27.08], %, $rectangleSegmentA002) |> angledLine([ segAng(rectangleSegmentA002) - 90, 27.8 ], %, $rectangleSegmentB002) |> angledLine([ segAng(rectangleSegmentA002), -segLen(rectangleSegmentA002) ], %, $rectangleSegmentC002) |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> close()revolve001 = revolve(sketch002, angle = 360, axis = 'X')

View File

@ -0,0 +1 @@
sketch001 = startSketchOn(XZ) |> startProfileAt([-100.0, 100.0], %) |> angledLine([0, 200.0], %, $rectangleSegmentA001) |> angledLine([segAng(rectangleSegmentA001) - 90, 200], %, $rectangleSegmentB001) |> angledLine([ segAng(rectangleSegmentA001), -segLen(rectangleSegmentA001) ], %, $rectangleSegmentC001) |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> close()extrude001 = extrude(sketch001, length = 200)sketch002 = startSketchOn(extrude001, rectangleSegmentA001) |> startProfileAt([-66.77, 84.81], %) |> angledLine([180, 27.08], %, $rectangleSegmentA002) |> angledLine([ segAng(rectangleSegmentA002) - 90, 27.8 ], %, $rectangleSegmentB002) |> angledLine([ segAng(rectangleSegmentA002), -segLen(rectangleSegmentA002) ], %, $rectangleSegmentC002) |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> close()revolve001 = revolve(sketch002, angle = 360, axis = 'X')

View File

@ -0,0 +1 @@
sketch001 = startSketchOn(XZ) |> startProfileAt([-102.57, 101.72], %) |> angledLine([0, 202.6], %, $rectangleSegmentA001) |> angledLine([ segAng(rectangleSegmentA001) - 90, 202.6 ], %, $rectangleSegmentB001) |> angledLine([ segAng(rectangleSegmentA001), -segLen(rectangleSegmentA001) ], %, $rectangleSegmentC001) |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> close()extrude001 = extrude(sketch001, length = 50)sketch002 = startSketchOn(extrude001, rectangleSegmentA001) |> circle(center = [-11.34, 10.0], radius = 8.69)revolve001 = revolve(sketch002, angle = 360, axis = rectangleSegmentA001)

View File

@ -0,0 +1 @@
sketch001 = startSketchOn(XZ) |> startProfileAt([-102.57, 101.72], %) |> angledLine([0, 202.6], %, $rectangleSegmentA001) |> angledLine([ segAng(rectangleSegmentA001) - 90, 202.6 ], %, $rectangleSegmentB001) |> angledLine([ segAng(rectangleSegmentA001), -segLen(rectangleSegmentA001) ], %, $rectangleSegmentC001) |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> close()extrude001 = extrude(sketch001, length = 50)sketch002 = startSketchOn(extrude001, rectangleSegmentA001) |> circle(center = [-11.34, 10.0], radius = 8.69)revolve001 = revolve(sketch002, angle = 360, axis = rectangleSegmentA001)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -320,6 +320,7 @@ export function mutateAstWithTagForSketchSegment(
// Check whether selection is a valid segment // Check whether selection is a valid segment
if ( if (
!segmentNode.node.callee ||
!( !(
segmentNode.node.callee.name.name in sketchLineHelperMap || segmentNode.node.callee.name.name in sketchLineHelperMap ||
segmentNode.node.callee.name.name in sketchLineHelperMapKw segmentNode.node.callee.name.name in sketchLineHelperMapKw

View File

@ -4,9 +4,7 @@ import {
Program, Program,
PathToNode, PathToNode,
Expr, Expr,
CallExpression,
VariableDeclarator, VariableDeclarator,
CallExpressionKw,
ArtifactGraph, ArtifactGraph,
} from 'lang/wasm' } from 'lang/wasm'
import { Selections } from 'lib/selections' import { Selections } from 'lib/selections'
@ -47,13 +45,6 @@ export function getAxisExpressionAndIndex(
ast, ast,
edge.graphSelections[0]?.codeRef.range edge.graphSelections[0]?.codeRef.range
) )
const lineNode = getNodeFromPath<CallExpression | CallExpressionKw>(
ast,
pathToAxisSelection,
['CallExpression', 'CallExpressionKw']
)
if (err(lineNode)) return lineNode
const tagResult = mutateAstWithTagForSketchSegment(ast, pathToAxisSelection) const tagResult = mutateAstWithTagForSketchSegment(ast, pathToAxisSelection)
// Have the tag whether it is already created or a new one is generated // Have the tag whether it is already created or a new one is generated
@ -90,12 +81,14 @@ export function getAxisExpressionAndIndex(
export function revolveSketch( export function revolveSketch(
ast: Node<Program>, ast: Node<Program>,
pathToSketchNode: PathToNode, pathToSketchNode: PathToNode,
angle: Expr = createLiteral(4), angle: Expr,
axisOrEdge: 'Axis' | 'Edge', axisOrEdge: 'Axis' | 'Edge',
axis: string, axis: string | undefined,
edge: Selections, edge: Selections | undefined,
artifactGraph: ArtifactGraph, artifactGraph: ArtifactGraph,
artifact?: Artifact artifact?: Artifact,
variableName?: string,
insertIndex?: number
): ):
| { | {
modifiedAst: Node<Program> modifiedAst: Node<Program>
@ -121,7 +114,12 @@ export function revolveSketch(
if (err(sketchVariableDeclaratorNode)) return sketchVariableDeclaratorNode if (err(sketchVariableDeclaratorNode)) return sketchVariableDeclaratorNode
const { node: sketchVariableDeclarator } = sketchVariableDeclaratorNode const { node: sketchVariableDeclarator } = sketchVariableDeclaratorNode
const getAxisResult = getAxisExpressionAndIndex(axisOrEdge, axis, edge, ast) const getAxisResult = getAxisExpressionAndIndex(
axisOrEdge,
axis,
edge,
clonedAst
)
if (err(getAxisResult)) return getAxisResult if (err(getAxisResult)) return getAxisResult
const { generatedAxis, axisIndexIfAxis } = getAxisResult const { generatedAxis, axisIndexIfAxis } = getAxisResult
if (!generatedAxis) return new Error('Generated axis selection is missing.') if (!generatedAxis) return new Error('Generated axis selection is missing.')
@ -134,21 +132,30 @@ export function revolveSketch(
// We're not creating a pipe expression, // We're not creating a pipe expression,
// but rather a separate constant for the extrusion // but rather a separate constant for the extrusion
const name = findUniqueName(clonedAst, KCL_DEFAULT_CONSTANT_PREFIXES.REVOLVE) const name =
const VariableDeclaration = createVariableDeclaration(name, revolveCall) variableName ??
const lastSketchNodePath = findUniqueName(clonedAst, KCL_DEFAULT_CONSTANT_PREFIXES.REVOLVE)
orderedSketchNodePaths[orderedSketchNodePaths.length - 1] const declaration = createVariableDeclaration(name, revolveCall)
let sketchIndexInBody = Number(lastSketchNodePath[1][0])
if (typeof sketchIndexInBody !== 'number') { let sketchIndexInBody: number | undefined
return new Error('expected sketchIndexInBody to be a number') // If it's an edit flow (no change on selection yet)
if (insertIndex) {
sketchIndexInBody = insertIndex
} else {
const lastSketchNodePath =
orderedSketchNodePaths[orderedSketchNodePaths.length - 1]
sketchIndexInBody = Number(lastSketchNodePath[1][0])
if (typeof sketchIndexInBody !== 'number') {
return new Error('expected sketchIndexInBody to be a number')
}
// If an axis was selected in KCL, find the max index to insert the revolve command
if (axisIndexIfAxis) {
sketchIndexInBody = Math.max(sketchIndexInBody, axisIndexIfAxis)
}
} }
// If an axis was selected in KCL, find the max index to insert the revolve command clonedAst.body.splice(sketchIndexInBody + 1, 0, declaration)
if (axisIndexIfAxis) {
sketchIndexInBody = Math.max(sketchIndexInBody, axisIndexIfAxis)
}
clonedAst.body.splice(sketchIndexInBody + 1, 0, VariableDeclaration)
const pathToRevolveArg: PathToNode = [ const pathToRevolveArg: PathToNode = [
['body', ''], ['body', ''],

View File

@ -77,11 +77,15 @@ export type ModelingCommandSchema = {
thickness: KclCommandValue thickness: KclCommandValue
} }
Revolve: { Revolve: {
// Enables editing workflow
nodeToEdit?: PathToNode
// Flow arg
axisOrEdge: 'Axis' | 'Edge'
// KCL stdlib arguments
selection: Selections selection: Selections
angle: KclCommandValue angle: KclCommandValue
axisOrEdge: 'Axis' | 'Edge' axis: string | undefined
axis: string edge: Selections | undefined
edge: Selections
} }
Fillet: { Fillet: {
// Enables editing workflow // Enables editing workflow
@ -472,6 +476,13 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
icon: 'revolve', icon: 'revolve',
needsReview: true, needsReview: true,
args: { args: {
nodeToEdit: {
description:
'Path to the node in the AST to edit. Never shown to the user.',
skip: true,
inputType: 'text',
required: false,
},
selection: { selection: {
inputType: 'selection', inputType: 'selection',
selectionTypes: ['solid2d', 'segment'], selectionTypes: ['solid2d', 'segment'],
@ -500,6 +511,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
{ name: 'X Axis', isCurrent: true, value: 'X' }, { name: 'X Axis', isCurrent: true, value: 'X' },
{ name: 'Y Axis', isCurrent: false, value: 'Y' }, { name: 'Y Axis', isCurrent: false, value: 'Y' },
], ],
hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit),
}, },
edge: { edge: {
required: (commandContext) => required: (commandContext) =>

View File

@ -810,6 +810,166 @@ const prepareToEditHelix: PrepareToEditCallback = async ({ operation }) => {
} }
} }
const prepareToEditRevolve: PrepareToEditCallback = async ({
operation,
artifact,
}) => {
const baseCommand = {
name: 'Revolve',
groupId: 'modeling',
}
if (
!artifact ||
!('pathId' in artifact) ||
operation.type !== 'StdLibCall' ||
!operation.labeledArgs
) {
return { reason: 'Wrong operation type or artifact' }
}
// We have to go a little roundabout to get from the original artifact
// to the solid2DId that we need to pass to the command.
const pathArtifact = getArtifactOfTypes(
{
key: artifact.pathId,
types: ['path'],
},
engineCommandManager.artifactGraph
)
if (
err(pathArtifact) ||
pathArtifact.type !== 'path' ||
!pathArtifact.solid2dId
) {
return { reason: "Couldn't find related path artifact" }
}
const solid2DArtifact = getArtifactOfTypes(
{
key: pathArtifact.solid2dId,
types: ['solid2d'],
},
engineCommandManager.artifactGraph
)
if (err(solid2DArtifact) || solid2DArtifact.type !== 'solid2d') {
return { reason: "Couldn't find related solid2d artifact" }
}
const selection = {
graphSelections: [
{
artifact: solid2DArtifact,
codeRef: pathArtifact.codeRef,
},
],
otherSelections: [],
}
// axis options string arg
if (!('axis' in operation.labeledArgs) || !operation.labeledArgs.axis) {
return { reason: "Couldn't find axis argument" }
}
const axisValue = operation.labeledArgs.axis.value
let axisOrEdge: 'Axis' | 'Edge' | undefined
let axis: string | undefined
let edge: Selections | undefined
if (axisValue.type === 'String') {
// default axis casee
axisOrEdge = 'Axis'
axis = axisValue.value
} else if (axisValue.type === 'TagIdentifier' && axisValue.artifact_id) {
// segment case
axisOrEdge = 'Edge'
const artifact = getArtifactOfTypes(
{
key: axisValue.artifact_id,
types: ['segment'],
},
engineCommandManager.artifactGraph
)
if (err(artifact)) {
return { reason: "Couldn't find related edge artifact" }
}
edge = {
graphSelections: [
{
artifact,
codeRef: artifact.codeRef,
},
],
otherSelections: [],
}
} else if (axisValue.type === 'Uuid') {
// sweepEdge case
axisOrEdge = 'Edge'
const artifact = getArtifactOfTypes(
{
key: axisValue.value,
types: ['sweepEdge'],
},
engineCommandManager.artifactGraph
)
if (err(artifact)) {
return { reason: "Couldn't find related edge artifact" }
}
const codeRef = getSweepEdgeCodeRef(
artifact,
engineCommandManager.artifactGraph
)
if (err(codeRef)) {
return { reason: "Couldn't find related edge code ref" }
}
edge = {
graphSelections: [
{
artifact,
codeRef,
},
],
otherSelections: [],
}
} else {
return { reason: 'The type of the axis argument is unsupported' }
}
// angle kcl arg
if (!('angle' in operation.labeledArgs) || !operation.labeledArgs.angle) {
return { reason: "Couldn't find angle argument" }
}
const angle = await stringToKclExpression(
codeManager.code.slice(
operation.labeledArgs.angle.sourceRange[0],
operation.labeledArgs.angle.sourceRange[1]
)
)
if (err(angle) || 'errors' in angle) {
return { reason: 'Error in angle argument retrieval' }
}
// Assemble the default argument values for the Offset Plane command,
// with `nodeToEdit` set, which will let the Offset Plane actor know
// to edit the node that corresponds to the StdLibCall.
const argDefaultValues: ModelingCommandSchema['Revolve'] = {
axisOrEdge,
axis,
edge,
selection,
angle,
nodeToEdit: getNodePathFromSourceRange(
kclManager.ast,
sourceRangeFromRust(operation.sourceRange)
),
}
return {
...baseCommand,
argDefaultValues,
}
}
/** /**
* A map of standard library calls to their corresponding information * A map of standard library calls to their corresponding information
* for use in the feature tree UI. * for use in the feature tree UI.
@ -882,6 +1042,7 @@ export const stdLibMap: Record<string, StdLibCallInfo> = {
revolve: { revolve: {
label: 'Revolve', label: 'Revolve',
icon: 'revolve', icon: 'revolve',
prepareToEdit: prepareToEditRevolve,
supportsAppearance: true, supportsAppearance: true,
}, },
shell: { shell: {

View File

@ -735,62 +735,6 @@ export const modelingMachine = setup({
sketchDetails: event.output, sketchDetails: event.output,
} }
}), }),
'AST revolve': ({ context: { store }, event }) => {
if (event.type !== 'Revolve') return
;(async () => {
if (!event.data) return
const { selection, angle, axis, edge, axisOrEdge } = event.data
let ast = kclManager.ast
if (
'variableName' in angle &&
angle.variableName &&
angle.insertIndex !== undefined
) {
const newBody = [...ast.body]
newBody.splice(angle.insertIndex, 0, angle.variableDeclarationAst)
ast.body = newBody
}
// This is the selection of the sketch that will be revolved
const pathToNode = getNodePathFromSourceRange(
ast,
selection.graphSelections[0]?.codeRef.range
)
const revolveSketchRes = revolveSketch(
ast,
pathToNode,
'variableName' in angle
? angle.variableIdentifierAst
: angle.valueAst,
axisOrEdge,
axis,
edge,
engineCommandManager.artifactGraph,
selection.graphSelections[0]?.artifact
)
if (trap(revolveSketchRes)) return
const { modifiedAst, pathToRevolveArg } = revolveSketchRes
await updateModelingState(
modifiedAst,
EXECUTION_TYPE_REAL,
{
kclManager,
editorManager,
codeManager,
},
{
focusPath: [pathToRevolveArg],
zoomToFit: true,
zoomOnRangeAndType: {
range: selection.graphSelections[0]?.codeRef.range,
type: 'path',
},
}
)
})().catch(reportRejection)
},
'set selection filter to curves only': () => { 'set selection filter to curves only': () => {
;(async () => { ;(async () => {
await engineCommandManager.sendSceneCommand({ await engineCommandManager.sendSceneCommand({
@ -1839,6 +1783,85 @@ export const modelingMachine = setup({
} }
) )
}), }),
revolveAstMod: fromPromise<
unknown,
ModelingCommandSchema['Revolve'] | undefined
>(async ({ input }) => {
if (!input) return new Error('No input provided')
const { nodeToEdit, selection, angle, axis, edge, axisOrEdge } = input
let ast = kclManager.ast
let variableName: string | undefined = undefined
let insertIndex: number | undefined = undefined
// If this is an edit flow, first we're going to remove the old extrusion
if (nodeToEdit && typeof nodeToEdit[1][0] === 'number') {
// Extract the plane name from the node to edit
const nameNode = getNodeFromPath<VariableDeclaration>(
ast,
nodeToEdit,
'VariableDeclaration'
)
if (err(nameNode)) {
console.error('Error extracting plane name')
} else {
variableName = nameNode.node.declaration.id.name
}
// Removing the old extrusion statement
const newBody = [...ast.body]
newBody.splice(nodeToEdit[1][0], 1)
ast.body = newBody
insertIndex = nodeToEdit[1][0]
}
if (
'variableName' in angle &&
angle.variableName &&
angle.insertIndex !== undefined
) {
const newBody = [...ast.body]
newBody.splice(angle.insertIndex, 0, angle.variableDeclarationAst)
ast.body = newBody
}
// This is the selection of the sketch that will be revolved
const pathToNode = getNodePathFromSourceRange(
ast,
selection.graphSelections[0]?.codeRef.range
)
const revolveSketchRes = revolveSketch(
ast,
pathToNode,
'variableName' in angle ? angle.variableIdentifierAst : angle.valueAst,
axisOrEdge,
axis,
edge,
engineCommandManager.artifactGraph,
selection.graphSelections[0]?.artifact,
variableName,
insertIndex
)
if (trap(revolveSketchRes)) return
const { modifiedAst, pathToRevolveArg } = revolveSketchRes
await updateModelingState(
modifiedAst,
EXECUTION_TYPE_REAL,
{
kclManager,
editorManager,
codeManager,
},
{
focusPath: [pathToRevolveArg],
zoomToFit: true,
zoomOnRangeAndType: {
range: selection.graphSelections[0]?.codeRef.range,
type: 'path',
},
}
)
}),
offsetPlaneAstMod: fromPromise( offsetPlaneAstMod: fromPromise(
async ({ async ({
input, input,
@ -2769,9 +2792,8 @@ export const modelingMachine = setup({
}, },
Revolve: { Revolve: {
target: 'idle', target: 'Applying revolve',
actions: ['AST revolve'], reenter: true,
reenter: false,
}, },
Sweep: { Sweep: {
@ -4025,6 +4047,22 @@ export const modelingMachine = setup({
}, },
}, },
'Applying revolve': {
invoke: {
src: 'revolveAstMod',
id: 'revolveAstMod',
input: ({ event }) => {
if (event.type !== 'Revolve') return undefined
return event.data
},
onDone: ['idle'],
onError: {
target: 'idle',
actions: 'toastError',
},
},
},
'Applying offset plane': { 'Applying offset plane': {
invoke: { invoke: {
src: 'offsetPlaneAstMod', src: 'offsetPlaneAstMod',