First draft of a feature tree pane (#4782)

This commit is contained in:
Frank Noirot
2024-12-20 16:19:59 -05:00
committed by GitHub
parent 1d06cc7845
commit c02e31a530
78 changed files with 1466 additions and 65 deletions

180
src/lib/operations.ts Normal file
View File

@ -0,0 +1,180 @@
import { CustomIconName } from 'components/CustomIcon'
import { Operation } from 'wasm-lib/kcl/bindings/Operation'
interface StdLibCallInfo {
label: string
icon: CustomIconName
}
const stdLibMap: Record<string, StdLibCallInfo> = {
chamfer: {
label: 'Chamfer',
icon: 'chamfer3d',
},
extrude: {
label: 'Extrude',
icon: 'extrude',
},
fillet: {
label: 'Fillet',
icon: 'fillet3d',
},
hole: {
label: 'Hole',
icon: 'hole',
},
hollow: {
label: 'Hollow',
icon: 'hollow',
},
import: {
label: 'Import',
icon: 'import',
},
loft: {
label: 'Loft',
icon: 'loft',
},
offsetPlane: {
label: 'Offset Plane',
icon: 'plane',
},
patternCircular2d: {
label: 'Circular Pattern',
icon: 'patternCircular2d',
},
patternCircular3d: {
label: 'Circular Pattern',
icon: 'patternCircular3d',
},
patternLinear2d: {
label: 'Linear Pattern',
icon: 'patternLinear2d',
},
patternLinear3d: {
label: 'Linear Pattern',
icon: 'patternLinear3d',
},
revolve: {
label: 'Revolve',
icon: 'revolve',
},
shell: {
label: 'Shell',
icon: 'shell',
},
startSketchOn: {
label: 'Sketch',
icon: 'sketch',
},
sweep: {
label: 'Sweep',
icon: 'sweep',
},
}
/**
* Returns the label of the operation
*/
export function getOperationLabel(op: Operation): string {
switch (op.type) {
case 'StdLibCall':
return stdLibMap[op.name]?.label ?? op.name
case 'UserDefinedFunctionCall':
return op.name ?? 'Anonymous custom function'
case 'UserDefinedFunctionReturn':
return 'User function return'
}
}
/**
* Returns the icon of the operation
*/
export function getOperationIcon(op: Operation): CustomIconName {
switch (op.type) {
case 'StdLibCall':
return stdLibMap[op.name]?.icon ?? 'questionMark'
default:
return 'make-variable'
}
}
/**
* Apply all filters to a list of operations.
*/
export function filterOperations(operations: Operation[]): Operation[] {
return operationFilters.reduce((ops, filterFn) => filterFn(ops), operations)
}
/**
* The filters to apply to a list of operations
* for use in the feature tree UI
*/
const operationFilters = [
isNotUserFunctionWithNoOperations,
isNotInsideUserFunction,
isNotUserFunctionReturn,
]
/**
* A filter to exclude everything that occurs inside a UserDefinedFunctionCall
* and its corresponding UserDefinedFunctionReturn from a list of operations.
* This works even when there are nested function calls.
*/
function isNotInsideUserFunction(operations: Operation[]): Operation[] {
const ops: Operation[] = []
let depth = 0
for (const op of operations) {
if (depth === 0) {
ops.push(op)
}
if (op.type === 'UserDefinedFunctionCall') {
depth++
}
if (op.type === 'UserDefinedFunctionReturn') {
depth--
console.assert(
depth >= 0,
'Unbalanced UserDefinedFunctionCall and UserDefinedFunctionReturn; too many returns'
)
}
}
// Depth could be non-zero here if there was an error in execution.
return ops
}
/**
* A filter to exclude UserDefinedFunctionCall operations and their
* corresponding UserDefinedFunctionReturn that don't have any operations inside
* them from a list of operations.
*/
function isNotUserFunctionWithNoOperations(
operations: Operation[]
): Operation[] {
return operations.filter((op, index) => {
if (
op.type === 'UserDefinedFunctionCall' &&
// If this is a call at the end of the array, it's preserved.
index < operations.length - 1 &&
operations[index + 1].type === 'UserDefinedFunctionReturn'
)
return false
if (
op.type === 'UserDefinedFunctionReturn' &&
// If this return is at the beginning of the array, it's preserved.
index > 0 &&
operations[index - 1].type === 'UserDefinedFunctionCall'
)
return false
return true
})
}
/**
* A filter to exclude UserDefinedFunctionReturn operations from a list of
* operations.
*/
function isNotUserFunctionReturn(ops: Operation[]): Operation[] {
return ops.filter((op) => op.type !== 'UserDefinedFunctionReturn')
}