Add 'remove constraining values' UI (#80)

This commit is contained in:
Kurt Hutten
2023-03-22 03:02:37 +11:00
committed by GitHub
parent 45091d3c4f
commit ab1639b8b4
4 changed files with 198 additions and 3 deletions

View File

@ -2,6 +2,7 @@ import { useStore, toolTips } from './useStore'
import { extrudeSketch, sketchOnExtrudedFace } from './lang/modifyAst' import { extrudeSketch, sketchOnExtrudedFace } from './lang/modifyAst'
import { getNodePathFromSourceRange } from './lang/queryAst' import { getNodePathFromSourceRange } from './lang/queryAst'
import { HorzVert } from './components/Toolbar/HorzVert' import { HorzVert } from './components/Toolbar/HorzVert'
import { RemoveConstrainingValues } from './components/Toolbar/RemoveConstrainingValues'
import { EqualLength } from './components/Toolbar/EqualLength' import { EqualLength } from './components/Toolbar/EqualLength'
import { EqualAngle } from './components/Toolbar/EqualAngle' import { EqualAngle } from './components/Toolbar/EqualAngle'
import { Intersect } from './components/Toolbar/Intersect' import { Intersect } from './components/Toolbar/Intersect'
@ -170,6 +171,7 @@ export const Toolbar = () => {
<SetAngleLength angleOrLength="setAngle" /> <SetAngleLength angleOrLength="setAngle" />
<SetAngleLength angleOrLength="setLength" /> <SetAngleLength angleOrLength="setLength" />
<Intersect /> <Intersect />
<RemoveConstrainingValues />
</div> </div>
) )
} }

View File

@ -0,0 +1,76 @@
import { useState, useEffect } from 'react'
import { toolTips, useStore } from '../../useStore'
import { Value } from '../../lang/abstractSyntaxTree'
import {
getNodePathFromSourceRange,
getNodeFromPath,
} from '../../lang/queryAst'
import {
TransformInfo,
getRemoveConstraintsTransforms,
transformAstSketchLines,
} from '../../lang/std/sketchcombos'
export const RemoveConstrainingValues = () => {
const { guiMode, selectionRanges, ast, programMemory, updateAst } = useStore(
(s) => ({
guiMode: s.guiMode,
ast: s.ast,
updateAst: s.updateAst,
selectionRanges: s.selectionRanges,
programMemory: s.programMemory,
})
)
const [enableHorz, setEnableHorz] = useState(false)
const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
useEffect(() => {
if (!ast) return
const paths = selectionRanges.map((selectionRange) =>
getNodePathFromSourceRange(ast, selectionRange)
)
const nodes = paths.map(
(pathToNode) => getNodeFromPath<Value>(ast, pathToNode).node
)
const isAllTooltips = nodes.every(
(node) =>
node?.type === 'CallExpression' &&
toolTips.includes(node.callee.name as any)
)
const theTransforms = getRemoveConstraintsTransforms(
selectionRanges,
ast,
'removeConstrainingValues'
)
setTransformInfos(theTransforms)
const _enableHorz = isAllTooltips && theTransforms.every(Boolean)
setEnableHorz(_enableHorz)
}, [guiMode, selectionRanges])
if (guiMode.mode !== 'sketch') return null
return (
<button
onClick={() =>
transformInfos &&
ast &&
updateAst(
transformAstSketchLines({
ast,
selectionRanges,
transformInfos,
programMemory,
referenceSegName: '',
})?.modifiedAst
)
}
className={`border m-1 px-1 rounded text-xs ${
enableHorz ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
}`}
disabled={!enableHorz}
title="yo dawg"
>
RemoveConstrainingValues
</button>
)
}

View File

@ -1666,7 +1666,10 @@ function getFirstArgValuesForXYLineFns(callExpression: CallExpression): {
if (length) { if (length) {
return { val: length, tag } return { val: length, tag }
} }
throw new Error('expected ArrayExpression or ObjectExpression') console.warn('expected ArrayExpression or ObjectExpression')
return {
val: createLiteral(1),
}
} }
const getAngledLineThatIntersects = ( const getAngledLineThatIntersects = (

View File

@ -45,6 +45,7 @@ export type ConstraintType =
| 'setAngle' | 'setAngle'
| 'setLength' | 'setLength'
| 'intersect' | 'intersect'
| 'removeConstrainingValues'
function createCallWrapper( function createCallWrapper(
a: TooTip, a: TooTip,
@ -939,6 +940,86 @@ const transformMap: TransformMap = {
}, },
} }
export function getRemoveConstraintsTransform(
sketchFnExp: CallExpression,
constraintType: ConstraintType
): TransformInfo | false {
let name = sketchFnExp.callee.name as TooTip
if (!toolTips.includes(name)) {
return false
}
const xyLineMap: {
[key in TooTip]?: TooTip
} = {
xLine: 'line',
yLine: 'line',
xLineTo: 'lineTo',
yLineTo: 'lineTo',
}
const _name = xyLineMap[name]
if (_name) {
name = _name
}
const transformInfo: TransformInfo = {
tooltip: 'line',
// tooltip: name,
createNode:
({ tag, referenceSegName }) =>
(args) => {
return createCallWrapper('line', args, tag)
// The following commented changes values to hardcode, but keeps the line type the same, maybe that's useful?
// if (name === 'angledLineThatIntersects') {
// return intersectCallWrapper({
// fnName: name,
// angleVal: args[0],
// offsetVal: args[1],
// intersectTag: createLiteral(referenceSegName),
// tag,
// })
// }
// return createCallWrapper(name, args, tag)
},
}
// check if the function is locked down and so can't be transformed
const firstArg = getFirstArg(sketchFnExp)
if (Array.isArray(firstArg.val)) {
const [a, b] = firstArg.val
if (a?.type !== 'Literal' && b?.type !== 'Literal') {
return transformInfo
}
} else {
if (firstArg.val?.type !== 'Literal') {
return transformInfo
}
}
// check if the function has no constraints
const isTwoValFree =
Array.isArray(firstArg.val) &&
firstArg.val?.[0]?.type === 'Literal' &&
firstArg.val?.[1]?.type === 'Literal'
if (isTwoValFree) {
return false
}
const isOneValFree =
!Array.isArray(firstArg.val) && firstArg.val?.type === 'Literal'
if (isOneValFree) {
return transformInfo
}
// check what constraints the function has
const lineInputType = getConstraintType(firstArg.val, name)
if (lineInputType) {
return transformInfo
}
return false
}
export function getTransformMapPath( export function getTransformMapPath(
sketchFnExp: CallExpression, sketchFnExp: CallExpression,
constraintType: ConstraintType constraintType: ConstraintType
@ -1068,6 +1149,28 @@ export function getTransformInfos(
return theTransforms return theTransforms
} }
export function getRemoveConstraintsTransforms(
selectionRanges: Ranges,
ast: Program,
constraintType: ConstraintType
): TransformInfo[] {
// return ()
const paths = selectionRanges.map((selectionRange) =>
getNodePathFromSourceRange(ast, selectionRange)
)
const nodes = paths.map(
(pathToNode) => getNodeFromPath<Value>(ast, pathToNode).node
)
const theTransforms = nodes.map((node) => {
if (node?.type === 'CallExpression')
return getRemoveConstraintsTransform(node, constraintType)
return false
}) as TransformInfo[]
return theTransforms
}
export function transformSecondarySketchLinesTagFirst({ export function transformSecondarySketchLinesTagFirst({
ast, ast,
selectionRanges, selectionRanges,
@ -1151,6 +1254,17 @@ export function transformAstSketchLines({
const varDec = getNode<VariableDeclarator>('VariableDeclarator').node const varDec = getNode<VariableDeclarator>('VariableDeclarator').node
const { val, tag: callBackTag } = getFirstArg(callExp) const { val, tag: callBackTag } = getFirstArg(callExp)
const _referencedSegmentNameVal =
callExp.arguments[0]?.type === 'ObjectExpression' &&
callExp.arguments[0].properties?.find(
(prop) => prop.key.name === 'intersectTag'
)?.value
const _referencedSegmentName =
referenceSegName ||
(_referencedSegmentNameVal &&
_referencedSegmentNameVal.type === 'Literal' &&
String(_referencedSegmentNameVal.value)) ||
''
const [varValA, varValB] = Array.isArray(val) ? val : [val, val] const [varValA, varValB] = Array.isArray(val) ? val : [val, val]
const varName = varDec.id.name const varName = varDec.id.name
@ -1160,7 +1274,7 @@ export function transformAstSketchLines({
const seg = getSketchSegmentFromSourceRange(sketchGroup, range) const seg = getSketchSegmentFromSourceRange(sketchGroup, range)
const referencedSegment = referencedSegmentRange const referencedSegment = referencedSegmentRange
? getSketchSegmentFromSourceRange(sketchGroup, referencedSegmentRange) ? getSketchSegmentFromSourceRange(sketchGroup, referencedSegmentRange)
: sketchGroup.value.find((path) => path.name === referenceSegName) : sketchGroup.value.find((path) => path.name === _referencedSegmentName)
const { to, from } = seg const { to, from } = seg
const { modifiedAst, valueUsedInTransform } = replaceSketchLine({ const { modifiedAst, valueUsedInTransform } = replaceSketchLine({
node: node, node: node,
@ -1171,7 +1285,7 @@ export function transformAstSketchLines({
to, to,
from, from,
createCallback: callBack({ createCallback: callBack({
referenceSegName, referenceSegName: _referencedSegmentName,
varValA, varValA,
varValB, varValB,
tag: callBackTag, tag: callBackTag,