Refactor Fillet Logic to Combine Multiple Tags Within the Same Fillet Expression (#4058)
* combine tags + tests * delete getFilletTag function * fix playwright test * make eslint happy * delete missed 'const' * delete const rev2
This commit is contained in:
@ -80,9 +80,11 @@ extrude001 = extrude(-10, sketch001)`
|
|||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await page.getByRole('button', { name: 'Fillet' }).click()
|
await page.getByRole('button', { name: 'Fillet' }).click()
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await page.keyboard.press('Enter')
|
await page.keyboard.press('Enter') // skip selection
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await page.keyboard.press('Enter')
|
await page.keyboard.press('Enter') // accept default radius
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await page.keyboard.press('Enter') // submit
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await expect(page.locator('.cm-activeLine')).toContainText(
|
await expect(page.locator('.cm-activeLine')).toContainText(
|
||||||
`fillet({ radius: ${KCL_DEFAULT_LENGTH}, tags: [seg01] }, %)`
|
`fillet({ radius: ${KCL_DEFAULT_LENGTH}, tags: [seg01] }, %)`
|
||||||
|
@ -10,11 +10,10 @@ import {
|
|||||||
VariableDeclarator,
|
VariableDeclarator,
|
||||||
} from '../wasm'
|
} from '../wasm'
|
||||||
import {
|
import {
|
||||||
addFillet,
|
|
||||||
getPathToExtrudeForSegmentSelection,
|
getPathToExtrudeForSegmentSelection,
|
||||||
hasValidFilletSelection,
|
hasValidFilletSelection,
|
||||||
isTagUsedInFillet,
|
isTagUsedInFillet,
|
||||||
modifyAstWithFilletAndTag,
|
modifyAstCloneWithFilletAndTag,
|
||||||
} from './addFillet'
|
} from './addFillet'
|
||||||
import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst'
|
import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst'
|
||||||
import { createLiteral } from 'lang/modifyAst'
|
import { createLiteral } from 'lang/modifyAst'
|
||||||
@ -116,16 +115,14 @@ const runGetPathToExtrudeForSegmentSelectionTest = async (
|
|||||||
otherSelections: [],
|
otherSelections: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
// programMemory and artifactGraph
|
// executeAst and artifactGraph
|
||||||
await kclManager.executeAst({ ast })
|
await kclManager.executeAst({ ast })
|
||||||
const programMemory = kclManager.programMemory
|
|
||||||
const artifactGraph = engineCommandManager.artifactGraph
|
const artifactGraph = engineCommandManager.artifactGraph
|
||||||
|
|
||||||
// get extrude expression
|
// get extrude expression
|
||||||
const pathResult = getPathToExtrudeForSegmentSelection(
|
const pathResult = getPathToExtrudeForSegmentSelection(
|
||||||
ast,
|
ast,
|
||||||
selection,
|
selection,
|
||||||
programMemory,
|
|
||||||
artifactGraph
|
artifactGraph
|
||||||
)
|
)
|
||||||
if (err(pathResult)) return pathResult
|
if (err(pathResult)) return pathResult
|
||||||
@ -230,226 +227,7 @@ extrude003 = extrude(-15, sketch003)`
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const runFilletTest = async (
|
const runModifyAstCloneWithFilletAndTag = async (
|
||||||
code: string,
|
|
||||||
segmentSnippet: string,
|
|
||||||
extrudeSnippet: string,
|
|
||||||
radius = createLiteral(5),
|
|
||||||
expectedCode: string
|
|
||||||
) => {
|
|
||||||
const astOrError = parse(code)
|
|
||||||
if (err(astOrError)) {
|
|
||||||
return new Error('AST not found')
|
|
||||||
}
|
|
||||||
|
|
||||||
const ast = astOrError
|
|
||||||
|
|
||||||
const segmentRange: [number, number] = [
|
|
||||||
code.indexOf(segmentSnippet),
|
|
||||||
code.indexOf(segmentSnippet) + segmentSnippet.length,
|
|
||||||
]
|
|
||||||
const pathToSegmentNode: PathToNode = getNodePathFromSourceRange(
|
|
||||||
ast,
|
|
||||||
segmentRange
|
|
||||||
)
|
|
||||||
|
|
||||||
const extrudeRange: [number, number] = [
|
|
||||||
code.indexOf(extrudeSnippet),
|
|
||||||
code.indexOf(extrudeSnippet) + extrudeSnippet.length,
|
|
||||||
]
|
|
||||||
|
|
||||||
const pathToExtrudeNode: PathToNode = getNodePathFromSourceRange(
|
|
||||||
ast,
|
|
||||||
extrudeRange
|
|
||||||
)
|
|
||||||
if (err(pathToExtrudeNode)) {
|
|
||||||
return new Error('Path to extrude node not found')
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = addFillet(ast, pathToSegmentNode, pathToExtrudeNode, radius)
|
|
||||||
if (err(result)) {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
const { modifiedAst } = result
|
|
||||||
const newCode = recast(modifiedAst)
|
|
||||||
|
|
||||||
expect(newCode).toContain(expectedCode)
|
|
||||||
}
|
|
||||||
describe('Testing addFillet', () => {
|
|
||||||
/**
|
|
||||||
* 1. Ideal Case
|
|
||||||
*/
|
|
||||||
|
|
||||||
it('should add a fillet to a specific segment after extrusion, clean', async () => {
|
|
||||||
const code = `
|
|
||||||
sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([2.16, 49.67], %)
|
|
||||||
|> line([101.49, 139.93], %)
|
|
||||||
|> line([60.04, -55.72], %)
|
|
||||||
|> line([1.29, -115.74], %)
|
|
||||||
|> line([-87.24, -47.08], %)
|
|
||||||
|> tangentialArcTo([56.15, -94.58], %)
|
|
||||||
|> tangentialArcTo([14.68, -104.52], %)
|
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
||||||
|> close(%)
|
|
||||||
extrude001 = extrude(50, sketch001)
|
|
||||||
`
|
|
||||||
const segmentSnippet = `line([60.04, -55.72], %)`
|
|
||||||
const extrudeSnippet = `extrude001 = extrude(50, sketch001)`
|
|
||||||
const radius = createLiteral(5)
|
|
||||||
const expectedCode = `sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([2.16, 49.67], %)
|
|
||||||
|> line([101.49, 139.93], %)
|
|
||||||
|> line([60.04, -55.72], %, $seg01)
|
|
||||||
|> line([1.29, -115.74], %)
|
|
||||||
|> line([-87.24, -47.08], %)
|
|
||||||
|> tangentialArcTo([56.15, -94.58], %)
|
|
||||||
|> tangentialArcTo([14.68, -104.52], %)
|
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
||||||
|> close(%)
|
|
||||||
extrude001 = extrude(50, sketch001)
|
|
||||||
|> fillet({ radius: 5, tags: [seg01] }, %)`
|
|
||||||
|
|
||||||
await runFilletTest(
|
|
||||||
code,
|
|
||||||
segmentSnippet,
|
|
||||||
extrudeSnippet,
|
|
||||||
radius,
|
|
||||||
expectedCode
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 2. Case of existing tag in the other line
|
|
||||||
*/
|
|
||||||
|
|
||||||
it('should add a fillet to a specific segment after extrusion with existing tag in any other line', async () => {
|
|
||||||
const code = `
|
|
||||||
sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([2.16, 49.67], %)
|
|
||||||
|> line([101.49, 139.93], %)
|
|
||||||
|> line([60.04, -55.72], %)
|
|
||||||
|> line([1.29, -115.74], %)
|
|
||||||
|> line([-87.24, -47.08], %, $seg01)
|
|
||||||
|> tangentialArcTo([56.15, -94.58], %)
|
|
||||||
|> tangentialArcTo([14.68, -104.52], %)
|
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
||||||
|> close(%)
|
|
||||||
extrude001 = extrude(50, sketch001)
|
|
||||||
`
|
|
||||||
const segmentSnippet = `line([60.04, -55.72], %)`
|
|
||||||
const extrudeSnippet = `extrude001 = extrude(50, sketch001)`
|
|
||||||
const radius = createLiteral(5)
|
|
||||||
const expectedCode = `sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([2.16, 49.67], %)
|
|
||||||
|> line([101.49, 139.93], %)
|
|
||||||
|> line([60.04, -55.72], %, $seg02)
|
|
||||||
|> line([1.29, -115.74], %)
|
|
||||||
|> line([-87.24, -47.08], %, $seg01)
|
|
||||||
|> tangentialArcTo([56.15, -94.58], %)
|
|
||||||
|> tangentialArcTo([14.68, -104.52], %)
|
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
||||||
|> close(%)
|
|
||||||
extrude001 = extrude(50, sketch001)
|
|
||||||
|> fillet({ radius: 5, tags: [seg02] }, %)`
|
|
||||||
|
|
||||||
await runFilletTest(
|
|
||||||
code,
|
|
||||||
segmentSnippet,
|
|
||||||
extrudeSnippet,
|
|
||||||
radius,
|
|
||||||
expectedCode
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 3. Case of existing tag in the fillet line
|
|
||||||
*/
|
|
||||||
|
|
||||||
it('should add a fillet to a specific segment after extrusion with existing tag in that exact line', async () => {
|
|
||||||
const code = `
|
|
||||||
sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([2.16, 49.67], %)
|
|
||||||
|> line([101.49, 139.93], %)
|
|
||||||
|> line([60.04, -55.72], %)
|
|
||||||
|> line([1.29, -115.74], %)
|
|
||||||
|> line([-87.24, -47.08], %, $seg03)
|
|
||||||
|> tangentialArcTo([56.15, -94.58], %)
|
|
||||||
|> tangentialArcTo([14.68, -104.52], %)
|
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
||||||
|> close(%)
|
|
||||||
extrude001 = extrude(50, sketch001)
|
|
||||||
`
|
|
||||||
const segmentSnippet = `line([-87.24, -47.08], %, $seg03)`
|
|
||||||
const extrudeSnippet = `extrude001 = extrude(50, sketch001)`
|
|
||||||
const radius = createLiteral(5)
|
|
||||||
const expectedCode = `sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([2.16, 49.67], %)
|
|
||||||
|> line([101.49, 139.93], %)
|
|
||||||
|> line([60.04, -55.72], %)
|
|
||||||
|> line([1.29, -115.74], %)
|
|
||||||
|> line([-87.24, -47.08], %, $seg03)
|
|
||||||
|> tangentialArcTo([56.15, -94.58], %)
|
|
||||||
|> tangentialArcTo([14.68, -104.52], %)
|
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
||||||
|> close(%)
|
|
||||||
extrude001 = extrude(50, sketch001)
|
|
||||||
|> fillet({ radius: 5, tags: [seg03] }, %)`
|
|
||||||
|
|
||||||
await runFilletTest(
|
|
||||||
code,
|
|
||||||
segmentSnippet,
|
|
||||||
extrudeSnippet,
|
|
||||||
radius,
|
|
||||||
expectedCode
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 4. Case of existing fillet on some other segment
|
|
||||||
*/
|
|
||||||
|
|
||||||
it('should add another fillet after the existing fillet', async () => {
|
|
||||||
const code = `sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([2.16, 49.67], %)
|
|
||||||
|> line([101.49, 139.93], %)
|
|
||||||
|> line([60.04, -55.72], %)
|
|
||||||
|> line([1.29, -115.74], %)
|
|
||||||
|> line([-87.24, -47.08], %, $seg03)
|
|
||||||
|> tangentialArcTo([56.15, -94.58], %)
|
|
||||||
|> tangentialArcTo([14.68, -104.52], %)
|
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
||||||
|> close(%)
|
|
||||||
extrude001 = extrude(50, sketch001)
|
|
||||||
|> fillet({ radius: 10, tags: [seg03] }, %)`
|
|
||||||
const segmentSnippet = `line([60.04, -55.72], %)`
|
|
||||||
const extrudeSnippet = `extrude001 = extrude(50, sketch001)`
|
|
||||||
const radius = createLiteral(5)
|
|
||||||
const expectedCode = `sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([2.16, 49.67], %)
|
|
||||||
|> line([101.49, 139.93], %)
|
|
||||||
|> line([60.04, -55.72], %, $seg01)
|
|
||||||
|> line([1.29, -115.74], %)
|
|
||||||
|> line([-87.24, -47.08], %, $seg03)
|
|
||||||
|> tangentialArcTo([56.15, -94.58], %)
|
|
||||||
|> tangentialArcTo([14.68, -104.52], %)
|
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
||||||
|> close(%)
|
|
||||||
extrude001 = extrude(50, sketch001)
|
|
||||||
|> fillet({ radius: 10, tags: [seg03] }, %)
|
|
||||||
|> fillet({ radius: 5, tags: [seg01] }, %)`
|
|
||||||
|
|
||||||
await runFilletTest(
|
|
||||||
code,
|
|
||||||
segmentSnippet,
|
|
||||||
extrudeSnippet,
|
|
||||||
radius,
|
|
||||||
expectedCode
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const runModifyAstWithFilletAndTagTest = async (
|
|
||||||
code: string,
|
code: string,
|
||||||
selectionSnippets: Array<string>,
|
selectionSnippets: Array<string>,
|
||||||
radiusValue: number,
|
radiusValue: number,
|
||||||
@ -484,11 +262,11 @@ const runModifyAstWithFilletAndTagTest = async (
|
|||||||
valueCalculated: radiusValue.toString(),
|
valueCalculated: radiusValue.toString(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// programMemory and artifactGraph
|
// executeAst
|
||||||
await kclManager.executeAst({ ast })
|
await kclManager.executeAst({ ast })
|
||||||
|
|
||||||
// apply fillet to selection
|
// apply fillet to selection
|
||||||
const result = modifyAstWithFilletAndTag(ast, selection, radius)
|
const result = modifyAstCloneWithFilletAndTag(ast, selection, radius)
|
||||||
if (err(result)) {
|
if (err(result)) {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -499,7 +277,7 @@ const runModifyAstWithFilletAndTagTest = async (
|
|||||||
expect(newCode).toContain(expectedCode)
|
expect(newCode).toContain(expectedCode)
|
||||||
}
|
}
|
||||||
describe('Testing applyFilletToSelection', () => {
|
describe('Testing applyFilletToSelection', () => {
|
||||||
it('should add a fillet to a specific segment after extrusion', async () => {
|
it('should add a fillet to a specific segment', async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
@ -520,14 +298,100 @@ extrude001 = extrude(-15, sketch001)`
|
|||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius: 3, tags: [seg01] }, %)`
|
|> fillet({ radius: 3, tags: [seg01] }, %)`
|
||||||
|
|
||||||
await runModifyAstWithFilletAndTagTest(
|
await runModifyAstCloneWithFilletAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
radiusValue,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet to the 2 segments of a single extrusion', async () => {
|
it('should add a fillet to an already tagged segment', async () => {
|
||||||
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, 10], %)
|
||||||
|
|> line([20, 0], %)
|
||||||
|
|> line([0, -20], %, $seg01)
|
||||||
|
|> line([-20, 0], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude001 = extrude(-15, sketch001)`
|
||||||
|
const segmentSnippets = ['line([0, -20], %, $seg01)']
|
||||||
|
const radiusValue = 3
|
||||||
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, 10], %)
|
||||||
|
|> line([20, 0], %)
|
||||||
|
|> line([0, -20], %, $seg01)
|
||||||
|
|> line([-20, 0], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude001 = extrude(-15, sketch001)
|
||||||
|
|> fillet({ radius: 3, tags: [seg01] }, %)`
|
||||||
|
|
||||||
|
await runModifyAstCloneWithFilletAndTag(
|
||||||
|
code,
|
||||||
|
segmentSnippets,
|
||||||
|
radiusValue,
|
||||||
|
expectedCode
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it('should add a fillet with existing tag on other segment', async () => {
|
||||||
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, 10], %)
|
||||||
|
|> line([20, 0], %, $seg01)
|
||||||
|
|> line([0, -20], %)
|
||||||
|
|> line([-20, 0], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude001 = extrude(-15, sketch001)`
|
||||||
|
const segmentSnippets = ['line([-20, 0], %)']
|
||||||
|
const radiusValue = 3
|
||||||
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, 10], %)
|
||||||
|
|> line([20, 0], %, $seg01)
|
||||||
|
|> line([0, -20], %)
|
||||||
|
|> line([-20, 0], %, $seg02)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude001 = extrude(-15, sketch001)
|
||||||
|
|> fillet({ radius: 3, tags: [seg02] }, %)`
|
||||||
|
|
||||||
|
await runModifyAstCloneWithFilletAndTag(
|
||||||
|
code,
|
||||||
|
segmentSnippets,
|
||||||
|
radiusValue,
|
||||||
|
expectedCode
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it('should add a fillet with existing fillet on other segment', async () => {
|
||||||
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, 10], %)
|
||||||
|
|> line([20, 0], %, $seg01)
|
||||||
|
|> line([0, -20], %)
|
||||||
|
|> line([-20, 0], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude001 = extrude(-15, sketch001)
|
||||||
|
|> fillet({ radius: 5, tags: [seg01] }, %)`
|
||||||
|
const segmentSnippets = ['line([-20, 0], %)']
|
||||||
|
const radiusValue = 3
|
||||||
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, 10], %)
|
||||||
|
|> line([20, 0], %, $seg01)
|
||||||
|
|> line([0, -20], %)
|
||||||
|
|> line([-20, 0], %, $seg02)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude001 = extrude(-15, sketch001)
|
||||||
|
|> fillet({ radius: 5, tags: [seg01] }, %)
|
||||||
|
|> fillet({ radius: 3, tags: [seg02] }, %)`
|
||||||
|
|
||||||
|
await runModifyAstCloneWithFilletAndTag(
|
||||||
|
code,
|
||||||
|
segmentSnippets,
|
||||||
|
radiusValue,
|
||||||
|
expectedCode
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it('should add a fillet to two segments of a single extrusion', async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
@ -546,47 +410,16 @@ extrude001 = extrude(-15, sketch001)`
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius: 3, tags: [seg01] }, %)
|
|> fillet({ radius: 3, tags: [seg01, seg02] }, %)`
|
||||||
|> fillet({ radius: 3, tags: [seg02] }, %)`
|
|
||||||
|
|
||||||
await runModifyAstWithFilletAndTagTest(
|
await runModifyAstCloneWithFilletAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
radiusValue,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet when the extrude variable previously had an fillet', async () => {
|
it('should add fillets to two bodies', async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, 10], %)
|
|
||||||
|> line([20, 0], %)
|
|
||||||
|> line([0, -20], %)
|
|
||||||
|> line([-20, 0], %, $seg01)
|
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
||||||
|> close(%)
|
|
||||||
extrude001 = extrude(-15, sketch001)
|
|
||||||
|> fillet({ radius: 3, tags: [seg01] }, %)` // <--- one fillet already there on input code
|
|
||||||
const segmentSnippets = ['line([20, 0], %)']
|
|
||||||
const radiusValue = 3
|
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, 10], %)
|
|
||||||
|> line([20, 0], %, $seg02)
|
|
||||||
|> line([0, -20], %)
|
|
||||||
|> line([-20, 0], %, $seg01)
|
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
||||||
|> close(%)
|
|
||||||
extrude001 = extrude(-15, sketch001)
|
|
||||||
|> fillet({ radius: 3, tags: [seg01] }, %)
|
|
||||||
|> fillet({ radius: 3, tags: [seg02] }, %)` // <-- able to add a new one
|
|
||||||
|
|
||||||
await runModifyAstWithFilletAndTagTest(
|
|
||||||
code,
|
|
||||||
segmentSnippets,
|
|
||||||
radiusValue,
|
|
||||||
expectedCode
|
|
||||||
)
|
|
||||||
})
|
|
||||||
it('should add the fillets to 2 bodies', async () => {
|
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
@ -603,28 +436,32 @@ sketch002 = startSketchOn('XY')
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude002 = extrude(-25, sketch002)` // <--- body 2
|
extrude002 = extrude(-25, sketch002)` // <--- body 2
|
||||||
const segmentSnippets = ['line([0, -20], %)', 'line([0, -15], %)']
|
const segmentSnippets = [
|
||||||
|
'line([20, 0], %)',
|
||||||
|
'line([-20, 0], %)',
|
||||||
|
'line([0, -15], %)',
|
||||||
|
]
|
||||||
const radiusValue = 3
|
const radiusValue = 3
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %, $seg01)
|
|> line([0, -20], %)
|
||||||
|> line([-20, 0], %)
|
|> line([-20, 0], %, $seg02)
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius: 3, tags: [seg01] }, %)
|
|> fillet({ radius: 3, tags: [seg01, seg02] }, %)
|
||||||
sketch002 = startSketchOn('XY')
|
sketch002 = startSketchOn('XY')
|
||||||
|> startProfileAt([30, 10], %)
|
|> startProfileAt([30, 10], %)
|
||||||
|> line([15, 0], %)
|
|> line([15, 0], %)
|
||||||
|> line([0, -15], %, $seg02)
|
|> line([0, -15], %, $seg03)
|
||||||
|> line([-15, 0], %)
|
|> line([-15, 0], %)
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude002 = extrude(-25, sketch002)
|
extrude002 = extrude(-25, sketch002)
|
||||||
|> fillet({ radius: 3, tags: [seg02] }, %)` // <-- able to add a new one
|
|> fillet({ radius: 3, tags: [seg03] }, %)` // <-- able to add a new one
|
||||||
|
|
||||||
await runModifyAstWithFilletAndTagTest(
|
await runModifyAstCloneWithFilletAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
radiusValue,
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
import {
|
import {
|
||||||
ArrayExpression,
|
|
||||||
CallExpression,
|
CallExpression,
|
||||||
ObjectExpression,
|
ObjectExpression,
|
||||||
PathToNode,
|
PathToNode,
|
||||||
Program,
|
Program,
|
||||||
ProgramMemory,
|
|
||||||
Expr,
|
|
||||||
VariableDeclaration,
|
VariableDeclaration,
|
||||||
VariableDeclarator,
|
VariableDeclarator,
|
||||||
sketchFromKclValue,
|
sketchFromKclValue,
|
||||||
} from '../wasm'
|
} from '../wasm'
|
||||||
import {
|
import {
|
||||||
createCallExpressionStdLib,
|
createCallExpressionStdLib,
|
||||||
createLiteral,
|
|
||||||
createPipeSubstitution,
|
createPipeSubstitution,
|
||||||
createObjectExpression,
|
createObjectExpression,
|
||||||
createArrayExpression,
|
createArrayExpression,
|
||||||
@ -39,70 +35,142 @@ import {
|
|||||||
} from 'lang/std/artifactGraph'
|
} from 'lang/std/artifactGraph'
|
||||||
import { kclManager, engineCommandManager, editorManager } from 'lib/singletons'
|
import { kclManager, engineCommandManager, editorManager } from 'lib/singletons'
|
||||||
|
|
||||||
/**
|
// Apply Fillet To Selection
|
||||||
* Apply Fillet To Selection
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function applyFilletToSelection(
|
export function applyFilletToSelection(
|
||||||
ast: Program,
|
ast: Program,
|
||||||
selection: Selections,
|
selection: Selections,
|
||||||
radius: KclCommandValue
|
radius: KclCommandValue
|
||||||
): void | Error {
|
): void | Error {
|
||||||
// 1. clone ast
|
// 1. clone and modify with fillet and tag
|
||||||
let clonedAst = structuredClone(ast)
|
const result = modifyAstCloneWithFilletAndTag(ast, selection, radius)
|
||||||
|
|
||||||
// 2. modify ast clone with fillet and tag
|
|
||||||
const result = modifyAstWithFilletAndTag(clonedAst, selection, radius)
|
|
||||||
if (err(result)) return result
|
if (err(result)) return result
|
||||||
const { modifiedAst, pathToFilletNode } = result
|
const { modifiedAst, pathToFilletNode } = result
|
||||||
|
|
||||||
// 3. update ast
|
// 2. update ast
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
updateAstAndFocus(modifiedAst, pathToFilletNode)
|
updateAstAndFocus(modifiedAst, pathToFilletNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function modifyAstWithFilletAndTag(
|
export function modifyAstCloneWithFilletAndTag(
|
||||||
ast: Program,
|
ast: Program,
|
||||||
selection: Selections,
|
selection: Selections,
|
||||||
radius: KclCommandValue
|
radius: KclCommandValue
|
||||||
): { modifiedAst: Program; pathToFilletNode: Array<PathToNode> } | Error {
|
): { modifiedAst: Program; pathToFilletNode: Array<PathToNode> } | Error {
|
||||||
const astResult = insertRadiusIntoAst(ast, radius)
|
|
||||||
if (err(astResult)) return astResult
|
|
||||||
|
|
||||||
const programMemory = kclManager.programMemory
|
|
||||||
const artifactGraph = engineCommandManager.artifactGraph
|
|
||||||
|
|
||||||
let clonedAst = structuredClone(ast)
|
let clonedAst = structuredClone(ast)
|
||||||
const clonedAstForGetExtrude = structuredClone(ast)
|
const clonedAstForGetExtrude = structuredClone(ast)
|
||||||
let pathToFilletNodes: Array<PathToNode> = []
|
|
||||||
|
const astResult = insertRadiusIntoAst(clonedAst, radius)
|
||||||
|
if (err(astResult)) return astResult
|
||||||
|
|
||||||
|
const artifactGraph = engineCommandManager.artifactGraph
|
||||||
|
|
||||||
|
// Step 1: modify ast with tags and group them by extrude nodes (bodies)
|
||||||
|
const extrudeToTagsMap: Map<PathToNode, string[]> = new Map()
|
||||||
|
const lookupMap: Map<string, PathToNode> = new Map() // work around for Map key comparison
|
||||||
|
|
||||||
for (const selectionRange of selection.codeBasedSelections) {
|
for (const selectionRange of selection.codeBasedSelections) {
|
||||||
const singleSelection = {
|
const singleSelection = {
|
||||||
codeBasedSelections: [selectionRange],
|
codeBasedSelections: [selectionRange],
|
||||||
otherSelections: [],
|
otherSelections: [],
|
||||||
}
|
}
|
||||||
const getPathToExtrudeForSegmentSelectionResult =
|
|
||||||
getPathToExtrudeForSegmentSelection(
|
|
||||||
clonedAstForGetExtrude,
|
|
||||||
singleSelection,
|
|
||||||
programMemory,
|
|
||||||
artifactGraph
|
|
||||||
)
|
|
||||||
if (err(getPathToExtrudeForSegmentSelectionResult))
|
|
||||||
return getPathToExtrudeForSegmentSelectionResult
|
|
||||||
const { pathToSegmentNode, pathToExtrudeNode } =
|
|
||||||
getPathToExtrudeForSegmentSelectionResult
|
|
||||||
|
|
||||||
const addFilletResult = addFillet(
|
const result = getPathToExtrudeForSegmentSelection(
|
||||||
clonedAst,
|
clonedAstForGetExtrude,
|
||||||
pathToSegmentNode,
|
singleSelection,
|
||||||
pathToExtrudeNode,
|
artifactGraph
|
||||||
'variableName' in radius ? radius.variableIdentifierAst : radius.valueAst
|
|
||||||
)
|
)
|
||||||
if (trap(addFilletResult)) return addFilletResult
|
if (err(result)) return result
|
||||||
const { modifiedAst, pathToFilletNode } = addFilletResult
|
const { pathToSegmentNode, pathToExtrudeNode } = result
|
||||||
clonedAst = modifiedAst
|
|
||||||
pathToFilletNodes.push(pathToFilletNode)
|
const tagResult = mutateAstWithTagForSketchSegment(
|
||||||
|
clonedAst,
|
||||||
|
pathToSegmentNode
|
||||||
|
)
|
||||||
|
if (err(tagResult)) return tagResult
|
||||||
|
const { tag } = tagResult
|
||||||
|
|
||||||
|
// Group tags by their corresponding extrude node
|
||||||
|
const extrudeKey = JSON.stringify(pathToExtrudeNode)
|
||||||
|
|
||||||
|
if (lookupMap.has(extrudeKey)) {
|
||||||
|
const existingPath = lookupMap.get(extrudeKey)
|
||||||
|
if (!existingPath) return new Error('Path to extrude node not found.')
|
||||||
|
extrudeToTagsMap.get(existingPath)?.push(tag)
|
||||||
|
} else {
|
||||||
|
lookupMap.set(extrudeKey, pathToExtrudeNode)
|
||||||
|
extrudeToTagsMap.set(pathToExtrudeNode, [tag])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Apply fillet(s) for each extrude node (body)
|
||||||
|
let pathToFilletNodes: Array<PathToNode> = []
|
||||||
|
for (const [pathToExtrudeNode, tags] of extrudeToTagsMap.entries()) {
|
||||||
|
// Create a fillet expression with multiple tags
|
||||||
|
const radiusValue =
|
||||||
|
'variableName' in radius ? radius.variableIdentifierAst : radius.valueAst
|
||||||
|
const filletCall = createCallExpressionStdLib('fillet', [
|
||||||
|
createObjectExpression({
|
||||||
|
radius: radiusValue,
|
||||||
|
tags: createArrayExpression(tags.map((tag) => createIdentifier(tag))),
|
||||||
|
}),
|
||||||
|
createPipeSubstitution(),
|
||||||
|
])
|
||||||
|
|
||||||
|
// Locate the extrude call
|
||||||
|
const locatedExtrudeDeclarator = locateExtrudeDeclarator(
|
||||||
|
clonedAst,
|
||||||
|
pathToExtrudeNode
|
||||||
|
)
|
||||||
|
if (err(locatedExtrudeDeclarator)) return locatedExtrudeDeclarator
|
||||||
|
const { extrudeDeclarator } = locatedExtrudeDeclarator
|
||||||
|
|
||||||
|
// Modify the extrude expression to include this fillet expression
|
||||||
|
// CallExpression - no fillet
|
||||||
|
// PipeExpression - fillet exists
|
||||||
|
|
||||||
|
let pathToFilletNode: PathToNode = []
|
||||||
|
|
||||||
|
if (extrudeDeclarator.init.type === 'CallExpression') {
|
||||||
|
// 1. case when no fillet exists
|
||||||
|
|
||||||
|
// modify ast with new fillet call by mutating the extrude node
|
||||||
|
extrudeDeclarator.init = createPipeExpression([
|
||||||
|
extrudeDeclarator.init,
|
||||||
|
filletCall,
|
||||||
|
])
|
||||||
|
|
||||||
|
// get path to the fillet node
|
||||||
|
pathToFilletNode = getPathToNodeOfFilletLiteral(
|
||||||
|
pathToExtrudeNode,
|
||||||
|
extrudeDeclarator,
|
||||||
|
tags[0]
|
||||||
|
)
|
||||||
|
pathToFilletNodes.push(pathToFilletNode)
|
||||||
|
} else if (extrudeDeclarator.init.type === 'PipeExpression') {
|
||||||
|
// 2. case when fillet exists
|
||||||
|
|
||||||
|
const existingFilletCall = extrudeDeclarator.init.body.find((node) => {
|
||||||
|
return node.type === 'CallExpression' && node.callee.name === 'fillet'
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!existingFilletCall || existingFilletCall.type !== 'CallExpression') {
|
||||||
|
return new Error('Fillet CallExpression not found.')
|
||||||
|
}
|
||||||
|
|
||||||
|
// mutate the extrude node with the new fillet call
|
||||||
|
extrudeDeclarator.init.body.push(filletCall)
|
||||||
|
|
||||||
|
// get path to the fillet node
|
||||||
|
pathToFilletNode = getPathToNodeOfFilletLiteral(
|
||||||
|
pathToExtrudeNode,
|
||||||
|
extrudeDeclarator,
|
||||||
|
tags[0]
|
||||||
|
)
|
||||||
|
pathToFilletNodes.push(pathToFilletNode)
|
||||||
|
} else {
|
||||||
|
return new Error('Unsupported extrude type.')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return { modifiedAst: clonedAst, pathToFilletNode: pathToFilletNodes }
|
return { modifiedAst: clonedAst, pathToFilletNode: pathToFilletNodes }
|
||||||
}
|
}
|
||||||
@ -131,7 +199,6 @@ function insertRadiusIntoAst(
|
|||||||
export function getPathToExtrudeForSegmentSelection(
|
export function getPathToExtrudeForSegmentSelection(
|
||||||
ast: Program,
|
ast: Program,
|
||||||
selection: Selections,
|
selection: Selections,
|
||||||
programMemory: ProgramMemory,
|
|
||||||
artifactGraph: ArtifactGraph
|
artifactGraph: ArtifactGraph
|
||||||
): { pathToSegmentNode: PathToNode; pathToExtrudeNode: PathToNode } | Error {
|
): { pathToSegmentNode: PathToNode; pathToExtrudeNode: PathToNode } | Error {
|
||||||
const pathToSegmentNode = getNodePathFromSourceRange(
|
const pathToSegmentNode = getNodePathFromSourceRange(
|
||||||
@ -177,40 +244,6 @@ async function updateAstAndFocus(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add Fillet
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function addFillet(
|
|
||||||
ast: Program,
|
|
||||||
pathToSegmentNode: PathToNode,
|
|
||||||
pathToExtrudeNode: PathToNode,
|
|
||||||
radius: Expr = createLiteral(5)
|
|
||||||
): { modifiedAst: Program; pathToFilletNode: PathToNode } | Error {
|
|
||||||
// Clone AST to ensure safe mutations
|
|
||||||
const astClone = structuredClone(ast)
|
|
||||||
|
|
||||||
// Modify AST clone : TAG the sketch segment and retrieve tag
|
|
||||||
const segmentResult = mutateAstWithTagForSketchSegment(
|
|
||||||
astClone,
|
|
||||||
pathToSegmentNode
|
|
||||||
)
|
|
||||||
if (err(segmentResult)) return segmentResult
|
|
||||||
const { tag } = segmentResult
|
|
||||||
|
|
||||||
// Modify AST clone : Insert FILLET node and retrieve path to fillet
|
|
||||||
const filletResult = mutateAstWithFilletNode(
|
|
||||||
astClone,
|
|
||||||
pathToExtrudeNode,
|
|
||||||
radius,
|
|
||||||
tag
|
|
||||||
)
|
|
||||||
if (err(filletResult)) return filletResult
|
|
||||||
const { pathToFilletNode } = filletResult
|
|
||||||
|
|
||||||
return { modifiedAst: astClone, pathToFilletNode }
|
|
||||||
}
|
|
||||||
|
|
||||||
function mutateAstWithTagForSketchSegment(
|
function mutateAstWithTagForSketchSegment(
|
||||||
astClone: Program,
|
astClone: Program,
|
||||||
pathToSegmentNode: PathToNode
|
pathToSegmentNode: PathToNode
|
||||||
@ -243,91 +276,6 @@ function mutateAstWithTagForSketchSegment(
|
|||||||
return { modifiedAst: astClone, tag }
|
return { modifiedAst: astClone, tag }
|
||||||
}
|
}
|
||||||
|
|
||||||
function mutateAstWithFilletNode(
|
|
||||||
astClone: Program,
|
|
||||||
pathToExtrudeNode: PathToNode,
|
|
||||||
radius: Expr,
|
|
||||||
tag: string
|
|
||||||
): { modifiedAst: Program; pathToFilletNode: PathToNode } | Error {
|
|
||||||
// Locate the extrude call
|
|
||||||
const locatedExtrudeDeclarator = locateExtrudeDeclarator(
|
|
||||||
astClone,
|
|
||||||
pathToExtrudeNode
|
|
||||||
)
|
|
||||||
if (err(locatedExtrudeDeclarator)) return locatedExtrudeDeclarator
|
|
||||||
const { extrudeDeclarator } = locatedExtrudeDeclarator
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare changes to the AST
|
|
||||||
*/
|
|
||||||
|
|
||||||
const filletCall = createCallExpressionStdLib('fillet', [
|
|
||||||
createObjectExpression({
|
|
||||||
radius: radius,
|
|
||||||
tags: createArrayExpression([createIdentifier(tag)]),
|
|
||||||
}),
|
|
||||||
createPipeSubstitution(),
|
|
||||||
])
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mutate the AST
|
|
||||||
*/
|
|
||||||
|
|
||||||
// CallExpression - no fillet
|
|
||||||
// PipeExpression - fillet exists
|
|
||||||
|
|
||||||
let pathToFilletNode: PathToNode = []
|
|
||||||
|
|
||||||
if (extrudeDeclarator.init.type === 'CallExpression') {
|
|
||||||
// 1. case when no fillet exists
|
|
||||||
|
|
||||||
// modify ast with new fillet call by mutating the extrude node
|
|
||||||
extrudeDeclarator.init = createPipeExpression([
|
|
||||||
extrudeDeclarator.init,
|
|
||||||
filletCall,
|
|
||||||
])
|
|
||||||
|
|
||||||
// get path to the fillet node
|
|
||||||
pathToFilletNode = getPathToNodeOfFilletLiteral(
|
|
||||||
pathToExtrudeNode,
|
|
||||||
extrudeDeclarator,
|
|
||||||
tag
|
|
||||||
)
|
|
||||||
|
|
||||||
return { modifiedAst: astClone, pathToFilletNode }
|
|
||||||
} else if (extrudeDeclarator.init.type === 'PipeExpression') {
|
|
||||||
// 2. case when fillet exists
|
|
||||||
|
|
||||||
const existingFilletCall = extrudeDeclarator.init.body.find((node) => {
|
|
||||||
return node.type === 'CallExpression' && node.callee.name === 'fillet'
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!existingFilletCall || existingFilletCall.type !== 'CallExpression') {
|
|
||||||
return new Error('Fillet CallExpression not found.')
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the existing fillet has the same tag as the new fillet
|
|
||||||
const filletTag = getFilletTag(existingFilletCall)
|
|
||||||
|
|
||||||
if (filletTag !== tag) {
|
|
||||||
// mutate the extrude node with the new fillet call
|
|
||||||
extrudeDeclarator.init.body.push(filletCall)
|
|
||||||
return {
|
|
||||||
modifiedAst: astClone,
|
|
||||||
pathToFilletNode: getPathToNodeOfFilletLiteral(
|
|
||||||
pathToExtrudeNode,
|
|
||||||
extrudeDeclarator,
|
|
||||||
tag
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return new Error('Unsupported extrude type.')
|
|
||||||
}
|
|
||||||
|
|
||||||
return { modifiedAst: astClone, pathToFilletNode }
|
|
||||||
}
|
|
||||||
|
|
||||||
function locateExtrudeDeclarator(
|
function locateExtrudeDeclarator(
|
||||||
node: Program,
|
node: Program,
|
||||||
pathToExtrudeNode: PathToNode
|
pathToExtrudeNode: PathToNode
|
||||||
@ -424,24 +372,7 @@ function getPathToRadiusLiteral(node: ObjectExpression, path: any): PathToNode {
|
|||||||
return pathToFilletObj
|
return pathToFilletObj
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFilletTag(existingFilletCall: CallExpression): string | null {
|
// Button states
|
||||||
if (existingFilletCall.arguments[0].type === 'ObjectExpression') {
|
|
||||||
const properties = (existingFilletCall.arguments[0] as ObjectExpression)
|
|
||||||
.properties
|
|
||||||
const tagsProperty = properties.find((prop) => prop.key.name === 'tags')
|
|
||||||
if (tagsProperty && tagsProperty.value.type === 'ArrayExpression') {
|
|
||||||
const elements = (tagsProperty.value as ArrayExpression).elements
|
|
||||||
if (elements.length > 0 && elements[0].type === 'Identifier') {
|
|
||||||
return elements[0].name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Button states
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const hasValidFilletSelection = ({
|
export const hasValidFilletSelection = ({
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
|
@ -258,7 +258,6 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Fillet: {
|
Fillet: {
|
||||||
// todo
|
|
||||||
description: 'Fillet edge',
|
description: 'Fillet edge',
|
||||||
icon: 'fillet',
|
icon: 'fillet',
|
||||||
needsReview: true,
|
needsReview: true,
|
||||||
@ -269,7 +268,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
'default',
|
'default',
|
||||||
'line-end',
|
'line-end',
|
||||||
'line-mid',
|
'line-mid',
|
||||||
'extrude-wall', // to fix: accepts only this selection type
|
'extrude-wall',
|
||||||
'solid2D',
|
'solid2D',
|
||||||
'start-cap',
|
'start-cap',
|
||||||
'end-cap',
|
'end-cap',
|
||||||
@ -279,9 +278,9 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
'arc',
|
'arc',
|
||||||
'all',
|
'all',
|
||||||
],
|
],
|
||||||
multiple: true, // TODO: multiple selection like in extrude command
|
multiple: true,
|
||||||
required: true,
|
required: true,
|
||||||
skip: true,
|
skip: false,
|
||||||
},
|
},
|
||||||
radius: {
|
radius: {
|
||||||
inputType: 'kcl',
|
inputType: 'kcl',
|
||||||
|
Reference in New Issue
Block a user