Refactor addFillet into addEdgeTreatment Function Supporting Chamfers (#4593)
* refactor code mod and tests * tsc * make lint happy * remove dumby data Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch> --------- Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
This commit is contained in:
@ -82,7 +82,7 @@ import { getVarNameModal } from 'hooks/useToolbarGuards'
|
|||||||
import { err, reportRejection, trap } from 'lib/trap'
|
import { err, reportRejection, trap } from 'lib/trap'
|
||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
import { modelingMachineEvent } from 'editor/manager'
|
import { modelingMachineEvent } from 'editor/manager'
|
||||||
import { hasValidFilletSelection } from 'lang/modifyAst/addFillet'
|
import { hasValidEdgeTreatmentSelection } from 'lang/modifyAst/addFillet'
|
||||||
import {
|
import {
|
||||||
ExportIntent,
|
ExportIntent,
|
||||||
EngineConnectionStateType,
|
EngineConnectionStateType,
|
||||||
@ -576,8 +576,10 @@ export const ModelingMachineProvider = ({
|
|||||||
if (selectionRanges.graphSelections.length <= 0) return false
|
if (selectionRanges.graphSelections.length <= 0) return false
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
'has valid fillet selection': ({ context: { selectionRanges } }) => {
|
'has valid edge treatment selection': ({
|
||||||
return hasValidFilletSelection({
|
context: { selectionRanges },
|
||||||
|
}) => {
|
||||||
|
return hasValidEdgeTreatmentSelection({
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
ast: kclManager.ast,
|
ast: kclManager.ast,
|
||||||
code: codeManager.code,
|
code: codeManager.code,
|
||||||
|
@ -10,10 +10,14 @@ import {
|
|||||||
VariableDeclarator,
|
VariableDeclarator,
|
||||||
} from '../wasm'
|
} from '../wasm'
|
||||||
import {
|
import {
|
||||||
|
EdgeTreatmentType,
|
||||||
getPathToExtrudeForSegmentSelection,
|
getPathToExtrudeForSegmentSelection,
|
||||||
hasValidFilletSelection,
|
hasValidEdgeTreatmentSelection,
|
||||||
isTagUsedInFillet,
|
isTagUsedInEdgeTreatment,
|
||||||
modifyAstWithFilletAndTag,
|
modifyAstWithEdgeTreatmentAndTag,
|
||||||
|
FilletParameters,
|
||||||
|
ChamferParameters,
|
||||||
|
EdgeTreatmentParameters,
|
||||||
} from './addFillet'
|
} from './addFillet'
|
||||||
import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst'
|
import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst'
|
||||||
import { createLiteral } from 'lang/modifyAst'
|
import { createLiteral } from 'lang/modifyAst'
|
||||||
@ -21,7 +25,6 @@ import { err } from 'lib/trap'
|
|||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { engineCommandManager, kclManager } from 'lib/singletons'
|
import { engineCommandManager, kclManager } from 'lib/singletons'
|
||||||
import { VITE_KC_DEV_TOKEN } from 'env'
|
import { VITE_KC_DEV_TOKEN } from 'env'
|
||||||
import { KclCommandValue } from 'lib/commandTypes'
|
|
||||||
import { isOverlap } from 'lib/utils'
|
import { isOverlap } from 'lib/utils'
|
||||||
import { codeRefFromRange } from 'lang/std/artifactGraph'
|
import { codeRefFromRange } from 'lang/std/artifactGraph'
|
||||||
|
|
||||||
@ -253,10 +256,10 @@ extrude003 = extrude(-15, sketch003)`
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const runModifyAstCloneWithFilletAndTag = async (
|
const runModifyAstCloneWithEdgeTreatmentAndTag = async (
|
||||||
code: string,
|
code: string,
|
||||||
selectionSnippets: Array<string>,
|
selectionSnippets: Array<string>,
|
||||||
radiusValue: number,
|
parameters: EdgeTreatmentParameters,
|
||||||
expectedCode: string
|
expectedCode: string
|
||||||
) => {
|
) => {
|
||||||
// ast
|
// ast
|
||||||
@ -274,13 +277,6 @@ const runModifyAstCloneWithFilletAndTag = async (
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
// radius
|
|
||||||
const radius: KclCommandValue = {
|
|
||||||
valueAst: createLiteral(radiusValue),
|
|
||||||
valueText: radiusValue.toString(),
|
|
||||||
valueCalculated: radiusValue.toString(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// executeAst
|
// executeAst
|
||||||
await kclManager.executeAst({ ast })
|
await kclManager.executeAst({ ast })
|
||||||
const artifactGraph = engineCommandManager.artifactGraph
|
const artifactGraph = engineCommandManager.artifactGraph
|
||||||
@ -299,8 +295,8 @@ const runModifyAstCloneWithFilletAndTag = async (
|
|||||||
otherSelections: [],
|
otherSelections: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply fillet to selection
|
// apply edge treatment to seleciton
|
||||||
const result = modifyAstWithFilletAndTag(ast, selection, radius)
|
const result = modifyAstWithEdgeTreatmentAndTag(ast, selection, parameters)
|
||||||
if (err(result)) {
|
if (err(result)) {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -310,9 +306,42 @@ const runModifyAstCloneWithFilletAndTag = async (
|
|||||||
|
|
||||||
expect(newCode).toContain(expectedCode)
|
expect(newCode).toContain(expectedCode)
|
||||||
}
|
}
|
||||||
describe('Testing applyFilletToSelection', () => {
|
const createFilletParameters = (radiusValue: number): FilletParameters => ({
|
||||||
it('should add a fillet to a specific segment', async () => {
|
type: EdgeTreatmentType.Fillet,
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
radius: {
|
||||||
|
valueAst: createLiteral(radiusValue),
|
||||||
|
valueText: radiusValue.toString(),
|
||||||
|
valueCalculated: radiusValue.toString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const createChamferParameters = (lengthValue: number): ChamferParameters => ({
|
||||||
|
type: EdgeTreatmentType.Chamfer,
|
||||||
|
length: {
|
||||||
|
valueAst: createLiteral(lengthValue),
|
||||||
|
valueText: lengthValue.toString(),
|
||||||
|
valueCalculated: lengthValue.toString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// Iterate tests over all edge treatment types
|
||||||
|
Object.values(EdgeTreatmentType).forEach(
|
||||||
|
(edgeTreatmentType: EdgeTreatmentType) => {
|
||||||
|
// create parameters based on the edge treatment type
|
||||||
|
let parameterName: string
|
||||||
|
let parameters: EdgeTreatmentParameters
|
||||||
|
if (edgeTreatmentType === EdgeTreatmentType.Fillet) {
|
||||||
|
parameterName = 'radius'
|
||||||
|
parameters = createFilletParameters(3)
|
||||||
|
} else if (edgeTreatmentType === EdgeTreatmentType.Chamfer) {
|
||||||
|
parameterName = 'length'
|
||||||
|
parameters = createChamferParameters(3)
|
||||||
|
} else {
|
||||||
|
// Handle future edge treatments
|
||||||
|
return new Error(`Unsupported edge treatment type: ${edgeTreatmentType}`)
|
||||||
|
}
|
||||||
|
// run tests
|
||||||
|
describe(`Testing modifyAstCloneWithEdgeTreatmentAndTag with ${edgeTreatmentType}s`, () => {
|
||||||
|
it(`should add a ${edgeTreatmentType} to a specific segment`, async () => {
|
||||||
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -320,9 +349,8 @@ describe('Testing applyFilletToSelection', () => {
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)`
|
extrude001 = extrude(-15, sketch001)`
|
||||||
const segmentSnippets = ['line([0, -20], %)']
|
const segmentSnippets = ['line([0, -20], %)']
|
||||||
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], %)
|
||||||
|> line([0, -20], %, $seg01)
|
|> line([0, -20], %, $seg01)
|
||||||
@ -330,17 +358,17 @@ 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] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet to the sketch pipe', async () => {
|
it(`should add a ${edgeTreatmentType} to the sketch pipe`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -348,9 +376,8 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(-15, %)`
|
|> extrude(-15, %)`
|
||||||
const segmentSnippets = ['line([0, -20], %)']
|
const segmentSnippets = ['line([0, -20], %)']
|
||||||
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], %)
|
||||||
|> line([0, -20], %, $seg01)
|
|> line([0, -20], %, $seg01)
|
||||||
@ -358,17 +385,17 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(-15, %)
|
|> extrude(-15, %)
|
||||||
|> fillet({ radius = 3, tags = [seg01] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet to an already tagged segment', async () => {
|
it(`should add a ${edgeTreatmentType} to an already tagged segment`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, -20], %, $seg01)
|
|> line([0, -20], %, $seg01)
|
||||||
@ -376,9 +403,8 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)`
|
extrude001 = extrude(-15, sketch001)`
|
||||||
const segmentSnippets = ['line([0, -20], %, $seg01)']
|
const segmentSnippets = ['line([0, -20], %, $seg01)']
|
||||||
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], %)
|
||||||
|> line([0, -20], %, $seg01)
|
|> line([0, -20], %, $seg01)
|
||||||
@ -386,17 +412,17 @@ 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] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet with existing tag on other segment', async () => {
|
it(`should add a ${edgeTreatmentType} with existing tag on other segment`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -404,9 +430,8 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)`
|
extrude001 = extrude(-15, sketch001)`
|
||||||
const segmentSnippets = ['line([-20, 0], %)']
|
const segmentSnippets = ['line([-20, 0], %)']
|
||||||
const radiusValue = 3
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -414,17 +439,17 @@ extrude001 = extrude(-15, sketch001)`
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 3, tags = [seg02] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg02] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet with existing fillet on other segment', async () => {
|
it(`should add a ${edgeTreatmentType} with existing fillet on other segment`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -433,9 +458,8 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 5, tags = [seg01] }, %)`
|
|> fillet({ radius = 5, tags = [seg01] }, %)`
|
||||||
const segmentSnippets = ['line([-20, 0], %)']
|
const segmentSnippets = ['line([-20, 0], %)']
|
||||||
const radiusValue = 3
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -444,27 +468,27 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 5, tags = [seg01] }, %)
|
|> fillet({ radius = 5, tags = [seg01] }, %)
|
||||||
|> fillet({ radius = 3, tags = [seg02] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg02] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet to two segments of a single extrusion', async () => {
|
it(`should add a ${edgeTreatmentType} with existing chamfer on other segment`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
|> line([-20, 0], %)
|
|> line([-20, 0], %)
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)`
|
extrude001 = extrude(-15, sketch001)
|
||||||
const segmentSnippets = ['line([20, 0], %)', 'line([-20, 0], %)']
|
|> chamfer({ length: 5, tags: [seg01] }, %)`
|
||||||
const radiusValue = 3
|
const segmentSnippets = ['line([-20, 0], %)']
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -472,17 +496,45 @@ 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, seg02] }, %)`
|
|> chamfer({ length: 5, tags: [seg01] }, %)
|
||||||
|
|> ${edgeTreatmentType}({ ${parameterName}: 3, tags: [seg02] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add fillets to two bodies', async () => {
|
it(`should add a ${edgeTreatmentType} to two segments of a single extrusion`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, 10], %)
|
||||||
|
|> line([20, 0], %)
|
||||||
|
|> line([0, -20], %)
|
||||||
|
|> line([-20, 0], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude001 = extrude(-15, sketch001)`
|
||||||
|
const segmentSnippets = ['line([20, 0], %)', 'line([-20, 0], %)']
|
||||||
|
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)
|
||||||
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01, seg02] }, %)`
|
||||||
|
|
||||||
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
|
code,
|
||||||
|
segmentSnippets,
|
||||||
|
parameters,
|
||||||
|
expectedCode
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it(`should add ${edgeTreatmentType}s to two bodies`, async () => {
|
||||||
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -498,13 +550,12 @@ 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 = [
|
const segmentSnippets = [
|
||||||
'line([20, 0], %)',
|
'line([20, 0], %)',
|
||||||
'line([-20, 0], %)',
|
'line([-20, 0], %)',
|
||||||
'line([0, -15], %)',
|
'line([0, -15], %)',
|
||||||
]
|
]
|
||||||
const radiusValue = 3
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -512,7 +563,7 @@ extrude002 = extrude(-25, sketch002)` // <--- body 2
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 3, tags = [seg01, seg02] }, %)
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01, seg02] }, %)
|
||||||
sketch002 = startSketchOn('XY')
|
sketch002 = startSketchOn('XY')
|
||||||
|> startProfileAt([30, 10], %)
|
|> startProfileAt([30, 10], %)
|
||||||
|> line([15, 0], %)
|
|> line([15, 0], %)
|
||||||
@ -521,18 +572,20 @@ sketch002 = startSketchOn('XY')
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude002 = extrude(-25, sketch002)
|
extrude002 = extrude(-25, sketch002)
|
||||||
|> fillet({ radius = 3, tags = [seg03] }, %)` // <-- able to add a new one
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg03] }, %)` // <-- able to add a new one
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
describe('Testing isTagUsedInFillet', () => {
|
describe('Testing isTagUsedInEdgeTreatment', () => {
|
||||||
const code = `sketch001 = startSketchOn('XZ')
|
const code = `sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([7.72, 4.13], %)
|
|> startProfileAt([7.72, 4.13], %)
|
||||||
|> line([7.11, 3.48], %, $seg01)
|
|> line([7.11, 3.48], %, $seg01)
|
||||||
@ -565,7 +618,7 @@ extrude001 = extrude(-5, sketch001)
|
|||||||
'CallExpression'
|
'CallExpression'
|
||||||
)
|
)
|
||||||
if (err(callExp)) return
|
if (err(callExp)) return
|
||||||
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
const edges = isTagUsedInEdgeTreatment({ ast, callExp: callExp.node })
|
||||||
expect(edges).toEqual(['getOppositeEdge', 'baseEdge'])
|
expect(edges).toEqual(['getOppositeEdge', 'baseEdge'])
|
||||||
})
|
})
|
||||||
it('should correctly identify getPreviousAdjacentEdge edges', () => {
|
it('should correctly identify getPreviousAdjacentEdge edges', () => {
|
||||||
@ -584,7 +637,7 @@ extrude001 = extrude(-5, sketch001)
|
|||||||
'CallExpression'
|
'CallExpression'
|
||||||
)
|
)
|
||||||
if (err(callExp)) return
|
if (err(callExp)) return
|
||||||
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
const edges = isTagUsedInEdgeTreatment({ ast, callExp: callExp.node })
|
||||||
expect(edges).toEqual(['getPreviousAdjacentEdge'])
|
expect(edges).toEqual(['getPreviousAdjacentEdge'])
|
||||||
})
|
})
|
||||||
it('should correctly identify no edges', () => {
|
it('should correctly identify no edges', () => {
|
||||||
@ -603,7 +656,7 @@ extrude001 = extrude(-5, sketch001)
|
|||||||
'CallExpression'
|
'CallExpression'
|
||||||
)
|
)
|
||||||
if (err(callExp)) return
|
if (err(callExp)) return
|
||||||
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
const edges = isTagUsedInEdgeTreatment({ ast, callExp: callExp.node })
|
||||||
expect(edges).toEqual([])
|
expect(edges).toEqual([])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -638,7 +691,7 @@ describe('Testing button states', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// state
|
// state
|
||||||
const buttonState = hasValidFilletSelection({
|
const buttonState = hasValidEdgeTreatmentSelection({
|
||||||
ast,
|
ast,
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
code,
|
code,
|
||||||
|
@ -44,32 +44,49 @@ import {
|
|||||||
} from 'lib/singletons'
|
} from 'lib/singletons'
|
||||||
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
||||||
|
|
||||||
// Apply Fillet To Selection
|
// Edge Treatment Types
|
||||||
|
export enum EdgeTreatmentType {
|
||||||
|
Chamfer = 'chamfer',
|
||||||
|
Fillet = 'fillet',
|
||||||
|
}
|
||||||
|
|
||||||
export function applyFilletToSelection(
|
export interface ChamferParameters {
|
||||||
|
type: EdgeTreatmentType.Chamfer
|
||||||
|
length: KclCommandValue
|
||||||
|
}
|
||||||
|
export interface FilletParameters {
|
||||||
|
type: EdgeTreatmentType.Fillet
|
||||||
|
radius: KclCommandValue
|
||||||
|
}
|
||||||
|
export type EdgeTreatmentParameters = ChamferParameters | FilletParameters
|
||||||
|
|
||||||
|
// Apply Edge Treatment (Fillet or Chamfer) To Selection
|
||||||
|
export function applyEdgeTreatmentToSelection(
|
||||||
ast: Node<Program>,
|
ast: Node<Program>,
|
||||||
selection: Selections,
|
selection: Selections,
|
||||||
radius: KclCommandValue
|
parameters: EdgeTreatmentParameters
|
||||||
): void | Error {
|
): void | Error {
|
||||||
// 1. clone and modify with fillet and tag
|
// 1. clone and modify with edge treatment and tag
|
||||||
const result = modifyAstWithFilletAndTag(ast, selection, radius)
|
const result = modifyAstWithEdgeTreatmentAndTag(ast, selection, parameters)
|
||||||
if (err(result)) return result
|
if (err(result)) return result
|
||||||
const { modifiedAst, pathToFilletNode } = result
|
const { modifiedAst, pathToEdgeTreatmentNode } = result
|
||||||
|
|
||||||
// 2. 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, pathToEdgeTreatmentNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function modifyAstWithFilletAndTag(
|
export function modifyAstWithEdgeTreatmentAndTag(
|
||||||
ast: Node<Program>,
|
ast: Node<Program>,
|
||||||
selections: Selections,
|
selections: Selections,
|
||||||
radius: KclCommandValue
|
parameters: EdgeTreatmentParameters
|
||||||
): { modifiedAst: Node<Program>; pathToFilletNode: Array<PathToNode> } | Error {
|
):
|
||||||
|
| { modifiedAst: Node<Program>; pathToEdgeTreatmentNode: Array<PathToNode> }
|
||||||
|
| Error {
|
||||||
let clonedAst = structuredClone(ast)
|
let clonedAst = structuredClone(ast)
|
||||||
const clonedAstForGetExtrude = structuredClone(ast)
|
const clonedAstForGetExtrude = structuredClone(ast)
|
||||||
|
|
||||||
const astResult = insertRadiusIntoAst(clonedAst, radius)
|
const astResult = insertParametersIntoAst(clonedAst, parameters)
|
||||||
if (err(astResult)) return astResult
|
if (err(astResult)) return astResult
|
||||||
|
|
||||||
const artifactGraph = engineCommandManager.artifactGraph
|
const artifactGraph = engineCommandManager.artifactGraph
|
||||||
@ -119,21 +136,26 @@ export function modifyAstWithFilletAndTag(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Apply fillet(s) for each extrude node (body)
|
// Step 2: Apply edge treatments for each extrude node (body)
|
||||||
let pathToFilletNodes: Array<PathToNode> = []
|
let pathToEdgeTreatmentNodes: Array<PathToNode> = []
|
||||||
for (const [pathToExtrudeNode, tagInfos] of extrudeToTagsMap.entries()) {
|
for (const [pathToExtrudeNode, tagInfos] of extrudeToTagsMap.entries()) {
|
||||||
// Create a fillet expression with multiple tags
|
// Create an edge treatment expression with multiple tags
|
||||||
const radiusValue =
|
|
||||||
'variableName' in radius ? radius.variableIdentifierAst : radius.valueAst
|
|
||||||
|
|
||||||
|
// edge treatment parameter
|
||||||
|
const parameterResult = getParameterNameAndValue(parameters)
|
||||||
|
if (err(parameterResult)) return parameterResult
|
||||||
|
const { parameterName, parameterValue } = parameterResult
|
||||||
|
|
||||||
|
// tag calls
|
||||||
const tagCalls = tagInfos.map(({ tag, artifact }) => {
|
const tagCalls = tagInfos.map(({ tag, artifact }) => {
|
||||||
return getEdgeTagCall(tag, artifact)
|
return getEdgeTagCall(tag, artifact)
|
||||||
})
|
})
|
||||||
const firstTag = tagCalls[0] // can be Identifier or CallExpression (for opposite and adjacent edges)
|
const firstTag = tagCalls[0] // can be Identifier or CallExpression (for opposite and adjacent edges)
|
||||||
|
|
||||||
const filletCall = createCallExpressionStdLib('fillet', [
|
// edge treatment call
|
||||||
|
const edgeTreatmentCall = createCallExpressionStdLib(parameters.type, [
|
||||||
createObjectExpression({
|
createObjectExpression({
|
||||||
radius: radiusValue,
|
[parameterName]: parameterValue,
|
||||||
tags: createArrayExpression(tagCalls),
|
tags: createArrayExpression(tagCalls),
|
||||||
}),
|
}),
|
||||||
createPipeSubstitution(),
|
createPipeSubstitution(),
|
||||||
@ -147,64 +169,89 @@ export function modifyAstWithFilletAndTag(
|
|||||||
if (err(locatedExtrudeDeclarator)) return locatedExtrudeDeclarator
|
if (err(locatedExtrudeDeclarator)) return locatedExtrudeDeclarator
|
||||||
const { extrudeDeclarator } = locatedExtrudeDeclarator
|
const { extrudeDeclarator } = locatedExtrudeDeclarator
|
||||||
|
|
||||||
// Modify the extrude expression to include this fillet expression
|
// Modify the extrude expression to include this edge treatment expression
|
||||||
// CallExpression - no fillet
|
// CallExpression - no edge treatment
|
||||||
// PipeExpression - fillet exists or extrude in sketch pipe
|
// PipeExpression - edge treatment exists or body in sketch pipe
|
||||||
|
|
||||||
let pathToFilletNode: PathToNode = []
|
let pathToEdgeTreatmentNode: PathToNode
|
||||||
|
|
||||||
if (extrudeDeclarator.init.type === 'CallExpression') {
|
if (extrudeDeclarator.init.type === 'CallExpression') {
|
||||||
// 1. case when no fillet exists
|
// 1. case when no edge treatment exists
|
||||||
|
|
||||||
// modify ast with new fillet call by mutating the extrude node
|
// modify ast with new edge treatment call by mutating the extrude node
|
||||||
extrudeDeclarator.init = createPipeExpression([
|
extrudeDeclarator.init = createPipeExpression([
|
||||||
extrudeDeclarator.init,
|
extrudeDeclarator.init,
|
||||||
filletCall,
|
edgeTreatmentCall,
|
||||||
])
|
])
|
||||||
|
|
||||||
// get path to the fillet node
|
// get path to the edge treatment node
|
||||||
pathToFilletNode = getPathToNodeOfFilletLiteral(
|
pathToEdgeTreatmentNode = getPathToNodeOfEdgeTreatmentLiteral(
|
||||||
pathToExtrudeNode,
|
pathToExtrudeNode,
|
||||||
extrudeDeclarator,
|
extrudeDeclarator,
|
||||||
firstTag
|
firstTag,
|
||||||
|
parameters
|
||||||
)
|
)
|
||||||
pathToFilletNodes.push(pathToFilletNode)
|
pathToEdgeTreatmentNodes.push(pathToEdgeTreatmentNode)
|
||||||
} else if (extrudeDeclarator.init.type === 'PipeExpression') {
|
} else if (extrudeDeclarator.init.type === 'PipeExpression') {
|
||||||
// 2. case when fillet exists or extrude in sketch pipe
|
// 2. case when edge treatment exists or extrude in sketch pipe
|
||||||
|
|
||||||
// mutate the extrude node with the new fillet call
|
// mutate the extrude node with the new edge treatment call
|
||||||
extrudeDeclarator.init.body.push(filletCall)
|
extrudeDeclarator.init.body.push(edgeTreatmentCall)
|
||||||
|
|
||||||
// get path to the fillet node
|
// get path to the edge treatment node
|
||||||
pathToFilletNode = getPathToNodeOfFilletLiteral(
|
pathToEdgeTreatmentNode = getPathToNodeOfEdgeTreatmentLiteral(
|
||||||
pathToExtrudeNode,
|
pathToExtrudeNode,
|
||||||
extrudeDeclarator,
|
extrudeDeclarator,
|
||||||
firstTag
|
firstTag,
|
||||||
|
parameters
|
||||||
)
|
)
|
||||||
pathToFilletNodes.push(pathToFilletNode)
|
pathToEdgeTreatmentNodes.push(pathToEdgeTreatmentNode)
|
||||||
} else {
|
} else {
|
||||||
return new Error('Unsupported extrude type.')
|
return new Error('Unsupported extrude type.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { modifiedAst: clonedAst, pathToFilletNode: pathToFilletNodes }
|
return {
|
||||||
|
modifiedAst: clonedAst,
|
||||||
|
pathToEdgeTreatmentNode: pathToEdgeTreatmentNodes,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertRadiusIntoAst(
|
function insertParametersIntoAst(
|
||||||
ast: Program,
|
ast: Program,
|
||||||
radius: KclCommandValue
|
parameters: EdgeTreatmentParameters
|
||||||
): { ast: Program } | Error {
|
): { ast: Program } | Error {
|
||||||
try {
|
try {
|
||||||
// Validate and update AST
|
const newAst = structuredClone(ast)
|
||||||
|
|
||||||
|
// handle radius parameter
|
||||||
if (
|
if (
|
||||||
'variableName' in radius &&
|
parameters.type === EdgeTreatmentType.Fillet &&
|
||||||
radius.variableName &&
|
'variableName' in parameters.radius &&
|
||||||
radius.insertIndex !== undefined
|
parameters.radius.variableName &&
|
||||||
|
parameters.radius.insertIndex !== undefined
|
||||||
) {
|
) {
|
||||||
const newAst = structuredClone(ast)
|
newAst.body.splice(
|
||||||
newAst.body.splice(radius.insertIndex, 0, radius.variableDeclarationAst)
|
parameters.radius.insertIndex,
|
||||||
return { ast: newAst }
|
0,
|
||||||
|
parameters.radius.variableDeclarationAst
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return { ast }
|
// handle length parameter
|
||||||
|
if (
|
||||||
|
parameters.type === EdgeTreatmentType.Chamfer &&
|
||||||
|
'variableName' in parameters.length &&
|
||||||
|
parameters.length.variableName &&
|
||||||
|
parameters.length.insertIndex !== undefined
|
||||||
|
) {
|
||||||
|
newAst.body.splice(
|
||||||
|
parameters.length.insertIndex,
|
||||||
|
0,
|
||||||
|
parameters.length.variableDeclarationAst
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle upcoming parameters here (for blend, bevel, etc.)
|
||||||
|
return { ast: newAst }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return new Error(`Failed to handle AST: ${(error as Error).message}`)
|
return new Error(`Failed to handle AST: ${(error as Error).message}`)
|
||||||
}
|
}
|
||||||
@ -248,10 +295,10 @@ export function getPathToExtrudeForSegmentSelection(
|
|||||||
|
|
||||||
async function updateAstAndFocus(
|
async function updateAstAndFocus(
|
||||||
modifiedAst: Node<Program>,
|
modifiedAst: Node<Program>,
|
||||||
pathToFilletNode: Array<PathToNode>
|
pathToEdgeTreatmentNode: Array<PathToNode>
|
||||||
) {
|
) {
|
||||||
const updatedAst = await kclManager.updateAst(modifiedAst, true, {
|
const updatedAst = await kclManager.updateAst(modifiedAst, true, {
|
||||||
focusPath: pathToFilletNode,
|
focusPath: pathToEdgeTreatmentNode,
|
||||||
})
|
})
|
||||||
|
|
||||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||||
@ -340,27 +387,38 @@ function locateExtrudeDeclarator(
|
|||||||
return { extrudeDeclarator }
|
return { extrudeDeclarator }
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPathToNodeOfFilletLiteral(
|
function getPathToNodeOfEdgeTreatmentLiteral(
|
||||||
pathToExtrudeNode: PathToNode,
|
pathToExtrudeNode: PathToNode,
|
||||||
extrudeDeclarator: VariableDeclarator,
|
extrudeDeclarator: VariableDeclarator,
|
||||||
tag: Identifier | CallExpression
|
tag: Identifier | CallExpression,
|
||||||
|
parameters: EdgeTreatmentParameters
|
||||||
): PathToNode {
|
): PathToNode {
|
||||||
let pathToFilletObj: PathToNode = []
|
let pathToEdgeTreatmentObj: PathToNode = []
|
||||||
let inFillet = false
|
let inEdgeTreatment = false
|
||||||
|
|
||||||
traverse(extrudeDeclarator.init, {
|
traverse(extrudeDeclarator.init, {
|
||||||
enter(node, path) {
|
enter(node, path) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = true
|
node.type === 'CallExpression' &&
|
||||||
|
node.callee.name === parameters.type
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = true
|
||||||
}
|
}
|
||||||
if (inFillet && node.type === 'ObjectExpression') {
|
if (inEdgeTreatment && node.type === 'ObjectExpression') {
|
||||||
if (!hasTag(node, tag)) return false
|
if (!hasTag(node, tag)) return false
|
||||||
pathToFilletObj = getPathToRadiusLiteral(node, path)
|
pathToEdgeTreatmentObj = getPathToEdgeTreatmentParameterLiteral(
|
||||||
|
node,
|
||||||
|
path,
|
||||||
|
parameters
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave(node) {
|
leave(node) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = false
|
node.type === 'CallExpression' &&
|
||||||
|
node.callee.name === parameters.type
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -375,7 +433,7 @@ function getPathToNodeOfFilletLiteral(
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
...pathToExtrudeNode.slice(0, indexOfPipeExpression),
|
...pathToExtrudeNode.slice(0, indexOfPipeExpression),
|
||||||
...pathToFilletObj,
|
...pathToEdgeTreatmentObj,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,23 +466,62 @@ function hasTag(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPathToRadiusLiteral(node: ObjectExpression, path: any): PathToNode {
|
function getPathToEdgeTreatmentParameterLiteral(
|
||||||
let pathToFilletObj = path
|
node: ObjectExpression,
|
||||||
|
path: any,
|
||||||
|
parameters: EdgeTreatmentParameters
|
||||||
|
): PathToNode {
|
||||||
|
let pathToEdgeTreatmentObj = path
|
||||||
|
const parameterResult = getParameterNameAndValue(parameters)
|
||||||
|
if (err(parameterResult)) return pathToEdgeTreatmentObj
|
||||||
|
const { parameterName } = parameterResult
|
||||||
|
|
||||||
node.properties.forEach((prop, index) => {
|
node.properties.forEach((prop, index) => {
|
||||||
if (prop.key.name === 'radius') {
|
if (prop.key.name === parameterName) {
|
||||||
pathToFilletObj.push(
|
pathToEdgeTreatmentObj.push(
|
||||||
['properties', 'ObjectExpression'],
|
['properties', 'ObjectExpression'],
|
||||||
[index, 'index'],
|
[index, 'index'],
|
||||||
['value', 'Property']
|
['value', 'Property']
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return pathToFilletObj
|
return pathToEdgeTreatmentObj
|
||||||
|
}
|
||||||
|
|
||||||
|
function getParameterNameAndValue(
|
||||||
|
parameters: EdgeTreatmentParameters
|
||||||
|
): { parameterName: string; parameterValue: Expr } | Error {
|
||||||
|
if (parameters.type === EdgeTreatmentType.Fillet) {
|
||||||
|
const parameterValue =
|
||||||
|
'variableName' in parameters.radius
|
||||||
|
? parameters.radius.variableIdentifierAst
|
||||||
|
: parameters.radius.valueAst
|
||||||
|
return { parameterName: 'radius', parameterValue }
|
||||||
|
} else if (parameters.type === EdgeTreatmentType.Chamfer) {
|
||||||
|
const parameterValue =
|
||||||
|
'variableName' in parameters.length
|
||||||
|
? parameters.length.variableIdentifierAst
|
||||||
|
: parameters.length.valueAst
|
||||||
|
return { parameterName: 'length', parameterValue }
|
||||||
|
} else {
|
||||||
|
return new Error('Unsupported edge treatment type}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type Guards
|
||||||
|
function isEdgeTreatmentType(name: string): name is EdgeTreatmentType {
|
||||||
|
return name === EdgeTreatmentType.Chamfer || name === EdgeTreatmentType.Fillet
|
||||||
|
}
|
||||||
|
function isEdgeType(name: string): name is EdgeTypes {
|
||||||
|
return (
|
||||||
|
name === 'getNextAdjacentEdge' ||
|
||||||
|
name === 'getPreviousAdjacentEdge' ||
|
||||||
|
name === 'getOppositeEdge'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Button states
|
// Button states
|
||||||
|
export const hasValidEdgeTreatmentSelection = ({
|
||||||
export const hasValidFilletSelection = ({
|
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
ast,
|
ast,
|
||||||
code,
|
code,
|
||||||
@ -433,11 +530,14 @@ export const hasValidFilletSelection = ({
|
|||||||
ast: Node<Program>
|
ast: Node<Program>
|
||||||
code: string
|
code: string
|
||||||
}) => {
|
}) => {
|
||||||
// check if there is anything filletable in the scene
|
// check if there is anything valid for the edge treatment in the scene
|
||||||
let extrudeExists = false
|
let extrudeExists = false
|
||||||
traverse(ast, {
|
traverse(ast, {
|
||||||
enter(node) {
|
enter(node) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'extrude') {
|
if (
|
||||||
|
node.type === 'CallExpression' &&
|
||||||
|
(node.callee.name === 'extrude' || node.callee.name === 'revolve')
|
||||||
|
) {
|
||||||
extrudeExists = true
|
extrudeExists = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -494,32 +594,39 @@ export const hasValidFilletSelection = ({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// check if tag is used in fillet
|
// check if tag is used in edge treatment
|
||||||
if (tagExists && selection.artifact) {
|
if (tagExists && selection.artifact) {
|
||||||
// create tag call
|
// create tag call
|
||||||
let tagCall: Expr = getEdgeTagCall(tag, selection.artifact)
|
let tagCall: Expr = getEdgeTagCall(tag, selection.artifact)
|
||||||
|
|
||||||
// check if tag is used in fillet
|
// check if tag is used in edge treatment
|
||||||
let inFillet = false
|
let inEdgeTreatment = false
|
||||||
let tagUsedInFillet = false
|
let tagUsedInEdgeTreatment = false
|
||||||
|
|
||||||
traverse(ast, {
|
traverse(ast, {
|
||||||
enter(node) {
|
enter(node) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = true
|
node.type === 'CallExpression' &&
|
||||||
|
isEdgeTreatmentType(node.callee.name)
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = true
|
||||||
}
|
}
|
||||||
if (inFillet && node.type === 'ObjectExpression') {
|
if (inEdgeTreatment && node.type === 'ObjectExpression') {
|
||||||
if (hasTag(node, tagCall)) {
|
if (hasTag(node, tagCall)) {
|
||||||
tagUsedInFillet = true
|
tagUsedInEdgeTreatment = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave(node) {
|
leave(node) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = false
|
node.type === 'CallExpression' &&
|
||||||
|
isEdgeTreatmentType(node.callee.name)
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (tagUsedInFillet) {
|
if (tagUsedInEdgeTreatment) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -533,7 +640,7 @@ type EdgeTypes =
|
|||||||
| 'getPreviousAdjacentEdge'
|
| 'getPreviousAdjacentEdge'
|
||||||
| 'getOppositeEdge'
|
| 'getOppositeEdge'
|
||||||
|
|
||||||
export const isTagUsedInFillet = ({
|
export const isTagUsedInEdgeTreatment = ({
|
||||||
ast,
|
ast,
|
||||||
callExp,
|
callExp,
|
||||||
}: {
|
}: {
|
||||||
@ -543,16 +650,21 @@ export const isTagUsedInFillet = ({
|
|||||||
const tag = getTagFromCallExpression(callExp)
|
const tag = getTagFromCallExpression(callExp)
|
||||||
if (err(tag)) return []
|
if (err(tag)) return []
|
||||||
|
|
||||||
let inFillet = false
|
let inEdgeTreatment = false
|
||||||
let inObj = false
|
let inObj = false
|
||||||
let inTagHelper: EdgeTypes | '' = ''
|
let inTagHelper: EdgeTypes | '' = ''
|
||||||
const edges: Array<EdgeTypes> = []
|
const edges: Array<EdgeTypes> = []
|
||||||
|
|
||||||
traverse(ast, {
|
traverse(ast, {
|
||||||
enter: (node) => {
|
enter: (node) => {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
// Check if we are entering an edge treatment call
|
||||||
inFillet = true
|
if (
|
||||||
|
node.type === 'CallExpression' &&
|
||||||
|
isEdgeTreatmentType(node.callee.name)
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = true
|
||||||
}
|
}
|
||||||
if (inFillet && node.type === 'ObjectExpression') {
|
if (inEdgeTreatment && node.type === 'ObjectExpression') {
|
||||||
node.properties.forEach((prop) => {
|
node.properties.forEach((prop) => {
|
||||||
if (
|
if (
|
||||||
prop.key.name === 'tags' &&
|
prop.key.name === 'tags' &&
|
||||||
@ -564,17 +676,15 @@ export const isTagUsedInFillet = ({
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inObj &&
|
inObj &&
|
||||||
inFillet &&
|
inEdgeTreatment &&
|
||||||
node.type === 'CallExpression' &&
|
node.type === 'CallExpression' &&
|
||||||
(node.callee.name === 'getOppositeEdge' ||
|
isEdgeType(node.callee.name)
|
||||||
node.callee.name === 'getNextAdjacentEdge' ||
|
|
||||||
node.callee.name === 'getPreviousAdjacentEdge')
|
|
||||||
) {
|
) {
|
||||||
inTagHelper = node.callee.name
|
inTagHelper = node.callee.name
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inObj &&
|
inObj &&
|
||||||
inFillet &&
|
inEdgeTreatment &&
|
||||||
!inTagHelper &&
|
!inTagHelper &&
|
||||||
node.type === 'Identifier' &&
|
node.type === 'Identifier' &&
|
||||||
node.name === tag
|
node.name === tag
|
||||||
@ -583,7 +693,7 @@ export const isTagUsedInFillet = ({
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inObj &&
|
inObj &&
|
||||||
inFillet &&
|
inEdgeTreatment &&
|
||||||
inTagHelper &&
|
inTagHelper &&
|
||||||
node.type === 'Identifier' &&
|
node.type === 'Identifier' &&
|
||||||
node.name === tag
|
node.name === tag
|
||||||
@ -592,10 +702,13 @@ export const isTagUsedInFillet = ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave: (node) => {
|
leave: (node) => {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = false
|
node.type === 'CallExpression' &&
|
||||||
|
isEdgeTreatmentType(node.callee.name)
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = false
|
||||||
}
|
}
|
||||||
if (inFillet && node.type === 'ObjectExpression') {
|
if (inEdgeTreatment && node.type === 'ObjectExpression') {
|
||||||
node.properties.forEach((prop) => {
|
node.properties.forEach((prop) => {
|
||||||
if (
|
if (
|
||||||
prop.key.name === 'tags' &&
|
prop.key.name === 'tags' &&
|
||||||
@ -607,11 +720,9 @@ export const isTagUsedInFillet = ({
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inObj &&
|
inObj &&
|
||||||
inFillet &&
|
inEdgeTreatment &&
|
||||||
node.type === 'CallExpression' &&
|
node.type === 'CallExpression' &&
|
||||||
(node.callee.name === 'getOppositeEdge' ||
|
isEdgeType(node.callee.name)
|
||||||
node.callee.name === 'getNextAdjacentEdge' ||
|
|
||||||
node.callee.name === 'getPreviousAdjacentEdge')
|
|
||||||
) {
|
) {
|
||||||
inTagHelper = ''
|
inTagHelper = ''
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,11 @@ import {
|
|||||||
extrudeSketch,
|
extrudeSketch,
|
||||||
revolveSketch,
|
revolveSketch,
|
||||||
} from 'lang/modifyAst'
|
} from 'lang/modifyAst'
|
||||||
import { applyFilletToSelection } from 'lang/modifyAst/addFillet'
|
import {
|
||||||
|
applyEdgeTreatmentToSelection,
|
||||||
|
EdgeTreatmentType,
|
||||||
|
FilletParameters,
|
||||||
|
} from 'lang/modifyAst/addFillet'
|
||||||
import { getNodeFromPath } from '../lang/queryAst'
|
import { getNodeFromPath } from '../lang/queryAst'
|
||||||
import {
|
import {
|
||||||
applyConstraintEqualAngle,
|
applyConstraintEqualAngle,
|
||||||
@ -383,7 +387,7 @@ export const modelingMachine = setup({
|
|||||||
guards: {
|
guards: {
|
||||||
'Selection is on face': () => false,
|
'Selection is on face': () => false,
|
||||||
'has valid sweep selection': () => false,
|
'has valid sweep selection': () => false,
|
||||||
'has valid fillet selection': () => false,
|
'has valid edge treatment selection': () => false,
|
||||||
'Has exportable geometry': () => false,
|
'Has exportable geometry': () => false,
|
||||||
'has valid selection for deletion': () => false,
|
'has valid selection for deletion': () => false,
|
||||||
'has made first point': ({ context }) => {
|
'has made first point': ({ context }) => {
|
||||||
@ -739,14 +743,19 @@ export const modelingMachine = setup({
|
|||||||
// Extract inputs
|
// Extract inputs
|
||||||
const ast = kclManager.ast
|
const ast = kclManager.ast
|
||||||
const { selection, radius } = event.data
|
const { selection, radius } = event.data
|
||||||
|
const parameters: FilletParameters = {
|
||||||
|
type: EdgeTreatmentType.Fillet,
|
||||||
|
radius,
|
||||||
|
}
|
||||||
|
|
||||||
// Apply fillet to selection
|
// Apply fillet to selection
|
||||||
const applyFilletToSelectionResult = applyFilletToSelection(
|
const applyEdgeTreatmentToSelectionResult = applyEdgeTreatmentToSelection(
|
||||||
ast,
|
ast,
|
||||||
selection,
|
selection,
|
||||||
radius
|
parameters
|
||||||
)
|
)
|
||||||
if (err(applyFilletToSelectionResult)) return applyFilletToSelectionResult
|
if (err(applyEdgeTreatmentToSelectionResult))
|
||||||
|
return applyEdgeTreatmentToSelectionResult
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
||||||
@ -1563,7 +1572,7 @@ export const modelingMachine = setup({
|
|||||||
|
|
||||||
Fillet: {
|
Fillet: {
|
||||||
target: 'idle',
|
target: 'idle',
|
||||||
guard: 'has valid fillet selection', // TODO: fix selections
|
guard: 'has valid edge treatment selection',
|
||||||
actions: ['AST fillet'],
|
actions: ['AST fillet'],
|
||||||
reenter: false,
|
reenter: false,
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user