Allow point-and-click Substract to take in multiple solids and tools (#7614)
* Allow point-and-click Substract to take in multiple tools Fixes #7612 * Change target to solids for consistency and make it support multi select too * Improve err message * Update src/lang/modifyAst/boolean.ts Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> * Update src/lang/modifyAst/boolean.ts Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch> * Good bot * Reduce array to single value if len 1 * Remove console.log --------- Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
This commit is contained in:
@ -12,7 +12,7 @@ test.describe('Point and click for boolean workflows', () => {
|
||||
},
|
||||
{
|
||||
name: 'subtract',
|
||||
code: 'subtract([extrude001], tools = [extrude006])',
|
||||
code: 'subtract(extrude001, tools = extrude006)',
|
||||
},
|
||||
{
|
||||
name: 'intersect',
|
||||
@ -81,6 +81,8 @@ test.describe('Point and click for boolean workflows', () => {
|
||||
if (operationName !== 'subtract') {
|
||||
// should down shift key to select multiple objects
|
||||
await page.keyboard.down('Shift')
|
||||
} else {
|
||||
await cmdBar.progressCmdBar()
|
||||
}
|
||||
|
||||
// Select second object
|
||||
@ -103,8 +105,8 @@ test.describe('Point and click for boolean workflows', () => {
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
Tool: '1 path',
|
||||
Target: '1 path',
|
||||
Solids: '1 path',
|
||||
Tools: '1 path',
|
||||
},
|
||||
commandName,
|
||||
})
|
||||
|
@ -23,13 +23,13 @@ import type {
|
||||
VariableDeclaration,
|
||||
} from '@src/lang/wasm'
|
||||
import { EXECUTION_TYPE_REAL } from '@src/lib/constants'
|
||||
import type { Selection, Selections } from '@src/lib/selections'
|
||||
import type { Selections } from '@src/lib/selections'
|
||||
import { err } from '@src/lib/trap'
|
||||
import { isArray } from '@src/lib/utils'
|
||||
|
||||
export async function applySubtractFromTargetOperatorSelections(
|
||||
target: Selection,
|
||||
tool: Selection,
|
||||
solids: Selections,
|
||||
tools: Selections,
|
||||
dependencies: {
|
||||
kclManager: KclManager
|
||||
engineCommandManager: EngineCommandManager
|
||||
@ -38,28 +38,28 @@ export async function applySubtractFromTargetOperatorSelections(
|
||||
}
|
||||
): Promise<Error | void> {
|
||||
const ast = dependencies.kclManager.ast
|
||||
if (!target.artifact || !tool.artifact) {
|
||||
return new Error('No artifact found')
|
||||
}
|
||||
const orderedChildrenTarget = findAllChildrenAndOrderByPlaceInCode(
|
||||
target.artifact,
|
||||
const lastSolidsVars = getLastVariableDeclarationsFromSelections(
|
||||
solids,
|
||||
ast,
|
||||
dependencies.kclManager.artifactGraph
|
||||
)
|
||||
const orderedChildrenTool = findAllChildrenAndOrderByPlaceInCode(
|
||||
tool.artifact,
|
||||
if (err(lastSolidsVars) || lastSolidsVars.length < 1) {
|
||||
return new Error('Not enough or invalid solids variables found')
|
||||
}
|
||||
|
||||
const lastToolsVars = getLastVariableDeclarationsFromSelections(
|
||||
tools,
|
||||
ast,
|
||||
dependencies.kclManager.artifactGraph
|
||||
)
|
||||
|
||||
const lastVarTarget = getLastVariable(orderedChildrenTarget, ast)
|
||||
const lastVarTool = getLastVariable(orderedChildrenTool, ast)
|
||||
|
||||
if (!lastVarTarget || !lastVarTool) {
|
||||
return new Error('No variable found')
|
||||
if (err(lastToolsVars) || lastToolsVars.length < 1) {
|
||||
return new Error('Not enough or invalid tools variables found')
|
||||
}
|
||||
|
||||
const modifiedAst = booleanSubtractAstMod({
|
||||
ast,
|
||||
targets: [lastVarTarget?.variableDeclaration?.node],
|
||||
tools: [lastVarTool?.variableDeclaration.node],
|
||||
solids: lastSolidsVars,
|
||||
tools: lastToolsVars,
|
||||
})
|
||||
|
||||
await updateModelingState(modifiedAst, EXECUTION_TYPE_REAL, dependencies)
|
||||
@ -75,34 +75,13 @@ export async function applyUnionFromTargetOperatorSelections(
|
||||
}
|
||||
): Promise<Error | void> {
|
||||
const ast = dependencies.kclManager.ast
|
||||
|
||||
const artifacts: Artifact[] = []
|
||||
for (const selection of solids.graphSelections) {
|
||||
if (selection.artifact) {
|
||||
artifacts.push(selection.artifact)
|
||||
}
|
||||
}
|
||||
|
||||
if (artifacts.length < 2) {
|
||||
return new Error('Not enough artifacts selected')
|
||||
}
|
||||
|
||||
const orderedChildrenEach = artifacts.map((artifact) =>
|
||||
findAllChildrenAndOrderByPlaceInCode(
|
||||
artifact,
|
||||
const lastVars = getLastVariableDeclarationsFromSelections(
|
||||
solids,
|
||||
ast,
|
||||
dependencies.kclManager.artifactGraph
|
||||
)
|
||||
)
|
||||
|
||||
const lastVars: VariableDeclaration[] = []
|
||||
for (const orderedArtifactLeaves of orderedChildrenEach) {
|
||||
const lastVar = getLastVariable(orderedArtifactLeaves, ast)
|
||||
if (!lastVar) continue
|
||||
lastVars.push(lastVar.variableDeclaration.node)
|
||||
}
|
||||
|
||||
if (lastVars.length < 2) {
|
||||
return new Error('Not enough variables found')
|
||||
if (err(lastVars) || lastVars.length < 2) {
|
||||
return new Error('Not enough or invalid solids variables found')
|
||||
}
|
||||
|
||||
const modifiedAst = booleanUnionAstMod({
|
||||
@ -122,23 +101,36 @@ export async function applyIntersectFromTargetOperatorSelections(
|
||||
}
|
||||
): Promise<Error | void> {
|
||||
const ast = dependencies.kclManager.ast
|
||||
const lastVars = getLastVariableDeclarationsFromSelections(
|
||||
solids,
|
||||
ast,
|
||||
dependencies.kclManager.artifactGraph
|
||||
)
|
||||
if (err(lastVars) || lastVars.length < 2) {
|
||||
return new Error('Not enough or invalid solids variables found')
|
||||
}
|
||||
|
||||
const modifiedAst = booleanIntersectAstMod({
|
||||
ast,
|
||||
solids: lastVars,
|
||||
})
|
||||
await updateModelingState(modifiedAst, EXECUTION_TYPE_REAL, dependencies)
|
||||
}
|
||||
|
||||
function getLastVariableDeclarationsFromSelections(
|
||||
selections: Selections,
|
||||
ast: Node<Program>,
|
||||
artifactGraph: ArtifactGraph
|
||||
): Error | VariableDeclaration[] {
|
||||
const artifacts: Artifact[] = []
|
||||
for (const selection of solids.graphSelections) {
|
||||
for (const selection of selections.graphSelections) {
|
||||
if (selection.artifact) {
|
||||
artifacts.push(selection.artifact)
|
||||
}
|
||||
}
|
||||
|
||||
if (artifacts.length < 2) {
|
||||
return new Error('Not enough artifacts selected')
|
||||
}
|
||||
|
||||
const orderedChildrenEach = artifacts.map((artifact) =>
|
||||
findAllChildrenAndOrderByPlaceInCode(
|
||||
artifact,
|
||||
dependencies.kclManager.artifactGraph
|
||||
)
|
||||
findAllChildrenAndOrderByPlaceInCode(artifact, artifactGraph)
|
||||
)
|
||||
|
||||
const lastVars: VariableDeclaration[] = []
|
||||
@ -148,15 +140,7 @@ export async function applyIntersectFromTargetOperatorSelections(
|
||||
lastVars.push(lastVar.variableDeclaration.node)
|
||||
}
|
||||
|
||||
if (lastVars.length < 2) {
|
||||
return new Error('Not enough variables found')
|
||||
}
|
||||
|
||||
const modifiedAst = booleanIntersectAstMod({
|
||||
ast,
|
||||
solids: lastVars,
|
||||
})
|
||||
await updateModelingState(modifiedAst, EXECUTION_TYPE_REAL, dependencies)
|
||||
return lastVars
|
||||
}
|
||||
|
||||
/** returns all children of a given artifact, and sorts them DESC by start sourceRange
|
||||
@ -271,25 +255,27 @@ export function getLastVariable(
|
||||
|
||||
export function booleanSubtractAstMod({
|
||||
ast,
|
||||
targets,
|
||||
solids,
|
||||
tools,
|
||||
}: {
|
||||
ast: Node<Program>
|
||||
targets: VariableDeclaration[]
|
||||
solids: VariableDeclaration[]
|
||||
tools: VariableDeclaration[]
|
||||
}): Node<Program> {
|
||||
const newAst = structuredClone(ast)
|
||||
const newVarName = findUniqueName(newAst, 'solid')
|
||||
const createArrExpr = (varDecs: VariableDeclaration[]) =>
|
||||
createArrayExpression(
|
||||
varDecs.map((varDec) => createLocalName(varDec.declaration.id.name))
|
||||
const createArrExpr = (varDecs: VariableDeclaration[]) => {
|
||||
const names = varDecs.map((varDec) =>
|
||||
createLocalName(varDec.declaration.id.name)
|
||||
)
|
||||
const targetsArrayExpression = createArrExpr(targets)
|
||||
return names.length === 1 ? names[0] : createArrayExpression(names)
|
||||
}
|
||||
const solidsArrayExpression = createArrExpr(solids)
|
||||
const toolsArrayExpression = createArrExpr(tools)
|
||||
|
||||
const newVarDec = createVariableDeclaration(
|
||||
newVarName,
|
||||
createCallExpressionStdLibKw('subtract', targetsArrayExpression, [
|
||||
createCallExpressionStdLibKw('subtract', solidsArrayExpression, [
|
||||
createLabeledArg('tools', toolsArrayExpression),
|
||||
])
|
||||
)
|
||||
|
@ -204,8 +204,8 @@ export type ModelingCommandSchema = {
|
||||
variableName: string
|
||||
}
|
||||
'Boolean Subtract': {
|
||||
target: Selections
|
||||
tool: Selections
|
||||
solids: Selections
|
||||
tools: Selections
|
||||
}
|
||||
'Boolean Union': {
|
||||
solids: Selections
|
||||
@ -595,23 +595,21 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
||||
icon: 'booleanSubtract',
|
||||
needsReview: true,
|
||||
args: {
|
||||
target: {
|
||||
solids: {
|
||||
inputType: 'selection',
|
||||
selectionTypes: ['path'],
|
||||
selectionFilter: ['object'],
|
||||
multiple: false,
|
||||
multiple: true,
|
||||
required: true,
|
||||
skip: true,
|
||||
hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit),
|
||||
},
|
||||
tool: {
|
||||
tools: {
|
||||
clearSelectionFirst: true,
|
||||
inputType: 'selection',
|
||||
selectionTypes: ['path'],
|
||||
selectionFilter: ['object'],
|
||||
multiple: false,
|
||||
multiple: true,
|
||||
required: true,
|
||||
skip: false,
|
||||
hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit),
|
||||
},
|
||||
},
|
||||
|
@ -3570,17 +3570,17 @@ export const modelingMachine = setup({
|
||||
return Promise.reject(new Error(NO_INPUT_PROVIDED_MESSAGE))
|
||||
}
|
||||
|
||||
const { target, tool } = input
|
||||
const { solids, tools } = input
|
||||
if (
|
||||
!target.graphSelections[0].artifact ||
|
||||
!tool.graphSelections[0].artifact
|
||||
!solids.graphSelections.some((selection) => selection.artifact) ||
|
||||
!tools.graphSelections.some((selection) => selection.artifact)
|
||||
) {
|
||||
return Promise.reject(new Error('No artifact in selections found'))
|
||||
}
|
||||
|
||||
await applySubtractFromTargetOperatorSelections(
|
||||
target.graphSelections[0],
|
||||
tool.graphSelections[0],
|
||||
const result = await applySubtractFromTargetOperatorSelections(
|
||||
solids,
|
||||
tools,
|
||||
{
|
||||
kclManager,
|
||||
codeManager,
|
||||
@ -3588,6 +3588,9 @@ export const modelingMachine = setup({
|
||||
editorManager,
|
||||
}
|
||||
)
|
||||
if (err(result)) {
|
||||
return Promise.reject(result)
|
||||
}
|
||||
}
|
||||
),
|
||||
boolUnionAstMod: fromPromise(
|
||||
@ -3605,12 +3608,15 @@ export const modelingMachine = setup({
|
||||
return Promise.reject(new Error('No artifact in selections found'))
|
||||
}
|
||||
|
||||
await applyUnionFromTargetOperatorSelections(solids, {
|
||||
const result = await applyUnionFromTargetOperatorSelections(solids, {
|
||||
kclManager,
|
||||
codeManager,
|
||||
engineCommandManager,
|
||||
editorManager,
|
||||
})
|
||||
if (err(result)) {
|
||||
return Promise.reject(result)
|
||||
}
|
||||
}
|
||||
),
|
||||
boolIntersectAstMod: fromPromise(
|
||||
@ -3628,12 +3634,18 @@ export const modelingMachine = setup({
|
||||
return Promise.reject(new Error('No artifact in selections found'))
|
||||
}
|
||||
|
||||
await applyIntersectFromTargetOperatorSelections(solids, {
|
||||
const result = await applyIntersectFromTargetOperatorSelections(
|
||||
solids,
|
||||
{
|
||||
kclManager,
|
||||
codeManager,
|
||||
engineCommandManager,
|
||||
editorManager,
|
||||
})
|
||||
}
|
||||
)
|
||||
if (err(result)) {
|
||||
return Promise.reject(result)
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
|
Reference in New Issue
Block a user