Add 'remove constraining values' UI (#80)
This commit is contained in:
@ -2,6 +2,7 @@ import { useStore, toolTips } from './useStore'
|
||||
import { extrudeSketch, sketchOnExtrudedFace } from './lang/modifyAst'
|
||||
import { getNodePathFromSourceRange } from './lang/queryAst'
|
||||
import { HorzVert } from './components/Toolbar/HorzVert'
|
||||
import { RemoveConstrainingValues } from './components/Toolbar/RemoveConstrainingValues'
|
||||
import { EqualLength } from './components/Toolbar/EqualLength'
|
||||
import { EqualAngle } from './components/Toolbar/EqualAngle'
|
||||
import { Intersect } from './components/Toolbar/Intersect'
|
||||
@ -170,6 +171,7 @@ export const Toolbar = () => {
|
||||
<SetAngleLength angleOrLength="setAngle" />
|
||||
<SetAngleLength angleOrLength="setLength" />
|
||||
<Intersect />
|
||||
<RemoveConstrainingValues />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
76
src/components/Toolbar/RemoveConstrainingValues.tsx
Normal file
76
src/components/Toolbar/RemoveConstrainingValues.tsx
Normal 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>
|
||||
)
|
||||
}
|
@ -1666,7 +1666,10 @@ function getFirstArgValuesForXYLineFns(callExpression: CallExpression): {
|
||||
if (length) {
|
||||
return { val: length, tag }
|
||||
}
|
||||
throw new Error('expected ArrayExpression or ObjectExpression')
|
||||
console.warn('expected ArrayExpression or ObjectExpression')
|
||||
return {
|
||||
val: createLiteral(1),
|
||||
}
|
||||
}
|
||||
|
||||
const getAngledLineThatIntersects = (
|
||||
|
@ -45,6 +45,7 @@ export type ConstraintType =
|
||||
| 'setAngle'
|
||||
| 'setLength'
|
||||
| 'intersect'
|
||||
| 'removeConstrainingValues'
|
||||
|
||||
function createCallWrapper(
|
||||
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(
|
||||
sketchFnExp: CallExpression,
|
||||
constraintType: ConstraintType
|
||||
@ -1068,6 +1149,28 @@ export function getTransformInfos(
|
||||
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({
|
||||
ast,
|
||||
selectionRanges,
|
||||
@ -1151,6 +1254,17 @@ export function transformAstSketchLines({
|
||||
const varDec = getNode<VariableDeclarator>('VariableDeclarator').node
|
||||
|
||||
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 varName = varDec.id.name
|
||||
@ -1160,7 +1274,7 @@ export function transformAstSketchLines({
|
||||
const seg = getSketchSegmentFromSourceRange(sketchGroup, range)
|
||||
const referencedSegment = referencedSegmentRange
|
||||
? getSketchSegmentFromSourceRange(sketchGroup, referencedSegmentRange)
|
||||
: sketchGroup.value.find((path) => path.name === referenceSegName)
|
||||
: sketchGroup.value.find((path) => path.name === _referencedSegmentName)
|
||||
const { to, from } = seg
|
||||
const { modifiedAst, valueUsedInTransform } = replaceSketchLine({
|
||||
node: node,
|
||||
@ -1171,7 +1285,7 @@ export function transformAstSketchLines({
|
||||
to,
|
||||
from,
|
||||
createCallback: callBack({
|
||||
referenceSegName,
|
||||
referenceSegName: _referencedSegmentName,
|
||||
varValA,
|
||||
varValB,
|
||||
tag: callBackTag,
|
||||
|
Reference in New Issue
Block a user