Sketch on chamfer UI (#3918)
* sketch on chamfer start * working * step app from getting in weird state when selection face to sketch on * sketch on chamfer tests * clean up * fix test * fix click selections for chamfers, add tests * fixture setup (#3964) * initial break up * rename main fixture file * add more expect state pattern * add fixture comment * add comments to chamfer function * typos * works without pipeExpr
This commit is contained in:
@ -54,6 +54,7 @@ import { roundOff, getLength, getAngle } from 'lib/utils'
|
||||
import { err } from 'lib/trap'
|
||||
import { perpendicularDistance } from 'sketch-helpers'
|
||||
import { TagDeclarator } from 'wasm-lib/kcl/bindings/TagDeclarator'
|
||||
import { EdgeCutInfo } from 'machines/modelingMachine'
|
||||
|
||||
const STRAIGHT_SEGMENT_ERR = new Error(
|
||||
'Invalid input, expected "straight-segment"'
|
||||
@ -2080,13 +2081,170 @@ export function replaceSketchLine({
|
||||
return { modifiedAst, valueUsedInTransform, pathToNode }
|
||||
}
|
||||
|
||||
/** Ostensibly should be used to add a chamfer tag to a chamfer call expression
|
||||
*
|
||||
* However things get complicated in situations like:
|
||||
* ```ts
|
||||
* |> chamfer({
|
||||
* length: 1,
|
||||
* tags: [tag1, tagOfInterest]
|
||||
* }, %)
|
||||
* ```
|
||||
* Because tag declarator is not allowed on a chamfer with more than one tag,
|
||||
* They must be pulled apart into separate chamfer calls:
|
||||
* ```ts
|
||||
* |> chamfer({
|
||||
* length: 1,
|
||||
* tags: [tag1]
|
||||
* }, %)
|
||||
* |> chamfer({
|
||||
* length: 1,
|
||||
* tags: [tagOfInterest]
|
||||
* }, %, $newTagDeclarator)
|
||||
* ```
|
||||
*/
|
||||
function addTagToChamfer(
|
||||
tagInfo: AddTagInfo,
|
||||
edgeCutMeta: EdgeCutInfo | null
|
||||
):
|
||||
| {
|
||||
modifiedAst: Program
|
||||
tag: string
|
||||
}
|
||||
| Error {
|
||||
const _node = structuredClone(tagInfo.node)
|
||||
let pipeIndex = 0
|
||||
for (let i = 0; i < tagInfo.pathToNode.length; i++) {
|
||||
if (tagInfo.pathToNode[i][1] === 'PipeExpression') {
|
||||
pipeIndex = Number(tagInfo.pathToNode[i + 1][0])
|
||||
break
|
||||
}
|
||||
}
|
||||
const pipeExpr = getNodeFromPath<PipeExpression>(
|
||||
_node,
|
||||
tagInfo.pathToNode,
|
||||
'PipeExpression'
|
||||
)
|
||||
const variableDec = getNodeFromPath<VariableDeclarator>(
|
||||
_node,
|
||||
tagInfo.pathToNode,
|
||||
'VariableDeclarator'
|
||||
)
|
||||
if (err(pipeExpr)) return pipeExpr
|
||||
if (err(variableDec)) return variableDec
|
||||
const isPipeExpression = pipeExpr.node.type === 'PipeExpression'
|
||||
|
||||
console.log('pipeExpr', pipeExpr, variableDec)
|
||||
// const callExpr = isPipeExpression ? pipeExpr.node.body[pipeIndex] : variableDec.node.init
|
||||
const callExpr = isPipeExpression
|
||||
? pipeExpr.node.body[pipeIndex]
|
||||
: variableDec.node.init
|
||||
if (callExpr.type !== 'CallExpression')
|
||||
return new Error('no chamfer call Expr')
|
||||
const chamferObjArg = callExpr.arguments[0]
|
||||
if (chamferObjArg.type !== 'ObjectExpression')
|
||||
return new Error('first argument should be an object expression')
|
||||
const inputTags = getObjExprProperty(chamferObjArg, 'tags')
|
||||
if (!inputTags) return new Error('no tags property')
|
||||
if (inputTags.expr.type !== 'ArrayExpression')
|
||||
return new Error('tags should be an array expression')
|
||||
|
||||
const isChamferBreakUpNeeded = inputTags.expr.elements.length > 1
|
||||
if (!isChamferBreakUpNeeded) {
|
||||
return addTag(2)(tagInfo)
|
||||
}
|
||||
|
||||
// There's more than one input tag, we need to break that chamfer call into a separate chamfer call
|
||||
// so that it can have a tag declarator added.
|
||||
const tagIndexToPullOut = inputTags.expr.elements.findIndex((tag) => {
|
||||
// e.g. chamfer({ tags: [tagOfInterest, tag2] }, %)
|
||||
// ^^^^^^^^^^^^^
|
||||
const elementMatchesBaseTagType =
|
||||
edgeCutMeta?.subType === 'base' &&
|
||||
tag.type === 'Identifier' &&
|
||||
tag.name === edgeCutMeta.tagName
|
||||
if (elementMatchesBaseTagType) return true
|
||||
|
||||
// e.g. chamfer({ tags: [getOppositeEdge(tagOfInterest), tag2] }, %)
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
const tagMatchesOppositeTagType =
|
||||
edgeCutMeta?.subType === 'opposite' &&
|
||||
tag.type === 'CallExpression' &&
|
||||
tag.callee.name === 'getOppositeEdge' &&
|
||||
tag.arguments[0].type === 'Identifier' &&
|
||||
tag.arguments[0].name === edgeCutMeta.tagName
|
||||
if (tagMatchesOppositeTagType) return true
|
||||
|
||||
// e.g. chamfer({ tags: [getNextAdjacentEdge(tagOfInterest), tag2] }, %)
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
const tagMatchesAdjacentTagType =
|
||||
edgeCutMeta?.subType === 'adjacent' &&
|
||||
tag.type === 'CallExpression' &&
|
||||
(tag.callee.name === 'getNextAdjacentEdge' ||
|
||||
tag.callee.name === 'getPrevAdjacentEdge') &&
|
||||
tag.arguments[0].type === 'Identifier' &&
|
||||
tag.arguments[0].name === edgeCutMeta.tagName
|
||||
if (tagMatchesAdjacentTagType) return true
|
||||
return false
|
||||
})
|
||||
if (tagIndexToPullOut === -1) return new Error('tag not found')
|
||||
// get the tag we're pulling out
|
||||
const tagToPullOut = inputTags.expr.elements[tagIndexToPullOut]
|
||||
// and remove it from the original chamfer call
|
||||
// [pullOutTag, tag2] to [tag2]
|
||||
inputTags.expr.elements.splice(tagIndexToPullOut, 1)
|
||||
|
||||
// get the length of the chamfer we're breaking up, as the new chamfer will have the same length
|
||||
const chamferLength = getObjExprProperty(chamferObjArg, 'length')
|
||||
if (!chamferLength) return new Error('no chamfer length')
|
||||
const tagDec = createTagDeclarator(findUniqueName(_node, 'seg', 2))
|
||||
const solid3dIdentifierUsedInOriginalChamfer = callExpr.arguments[1]
|
||||
const newExpressionToInsert = createCallExpression('chamfer', [
|
||||
createObjectExpression({
|
||||
length: chamferLength.expr,
|
||||
// single tag to add to the new chamfer call
|
||||
tags: createArrayExpression([tagToPullOut]),
|
||||
}),
|
||||
isPipeExpression
|
||||
? createPipeSubstitution()
|
||||
: solid3dIdentifierUsedInOriginalChamfer,
|
||||
tagDec,
|
||||
])
|
||||
|
||||
// insert the new chamfer call with the tag declarator, add its above the original
|
||||
// alternatively we could use `pipeIndex + 1` to insert it below the original
|
||||
if (isPipeExpression) {
|
||||
pipeExpr.node.body.splice(pipeIndex, 0, newExpressionToInsert)
|
||||
} else {
|
||||
console.log('yo', createPipeExpression([newExpressionToInsert, callExpr]))
|
||||
callExpr.arguments[1] = createPipeSubstitution()
|
||||
variableDec.node.init = createPipeExpression([
|
||||
newExpressionToInsert,
|
||||
callExpr,
|
||||
])
|
||||
}
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
tag: tagDec.value,
|
||||
}
|
||||
}
|
||||
|
||||
export function addTagForSketchOnFace(
|
||||
tagInfo: AddTagInfo,
|
||||
expressionName: string
|
||||
) {
|
||||
expressionName: string,
|
||||
edgeCutMeta: EdgeCutInfo | null
|
||||
):
|
||||
| {
|
||||
modifiedAst: Program
|
||||
tag: string
|
||||
}
|
||||
| Error {
|
||||
if (expressionName === 'close') {
|
||||
return addTag(1)(tagInfo)
|
||||
}
|
||||
if (expressionName === 'chamfer') {
|
||||
return addTagToChamfer(tagInfo, edgeCutMeta)
|
||||
}
|
||||
if (expressionName in sketchLineHelperMap) {
|
||||
const { addTag } = sketchLineHelperMap[expressionName]
|
||||
return addTag(tagInfo)
|
||||
|
Reference in New Issue
Block a user