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:
Kurt Hutten
2024-09-26 18:25:05 +10:00
committed by GitHub
parent 90f0f13d26
commit 579151a9bb
25 changed files with 1627 additions and 352 deletions

View File

@ -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)