diff --git a/src/Toolbar.tsx b/src/Toolbar.tsx index fc0e3418d..5ddf9042f 100644 --- a/src/Toolbar.tsx +++ b/src/Toolbar.tsx @@ -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 = () => { + ) } diff --git a/src/components/Toolbar/RemoveConstrainingValues.tsx b/src/components/Toolbar/RemoveConstrainingValues.tsx new file mode 100644 index 000000000..3fd7c3ba5 --- /dev/null +++ b/src/components/Toolbar/RemoveConstrainingValues.tsx @@ -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() + useEffect(() => { + if (!ast) return + const paths = selectionRanges.map((selectionRange) => + getNodePathFromSourceRange(ast, selectionRange) + ) + const nodes = paths.map( + (pathToNode) => getNodeFromPath(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 ( + + ) +} diff --git a/src/lang/std/sketch.ts b/src/lang/std/sketch.ts index 5522bfd35..c73b7fccd 100644 --- a/src/lang/std/sketch.ts +++ b/src/lang/std/sketch.ts @@ -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 = ( diff --git a/src/lang/std/sketchcombos.ts b/src/lang/std/sketchcombos.ts index 963ff2955..eea45bd72 100644 --- a/src/lang/std/sketchcombos.ts +++ b/src/lang/std/sketchcombos.ts @@ -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(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').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,