diff --git a/src/Toolbar.tsx b/src/Toolbar.tsx index 76f032a4a..fcf637013 100644 --- a/src/Toolbar.tsx +++ b/src/Toolbar.tsx @@ -10,6 +10,7 @@ import { SetHorzVertDistance } from './components/Toolbar/SetHorzVertDistance' import { SetAngleLength } from './components/Toolbar/SetAngleLength' import { ConvertToVariable } from './components/Toolbar/ConvertVariable' import { SetAbsDistance } from './components/Toolbar/SetAbsDistance' +import { SetAngleBetween } from './components/Toolbar/setAngleBetween' export const Toolbar = () => { const { @@ -178,6 +179,7 @@ export const Toolbar = () => { + ) } diff --git a/src/components/Toolbar/SetHorzVertDistance.tsx b/src/components/Toolbar/SetHorzVertDistance.tsx index 6bf9baf8a..bd69d5b81 100644 --- a/src/components/Toolbar/SetHorzVertDistance.tsx +++ b/src/components/Toolbar/SetHorzVertDistance.tsx @@ -17,10 +17,7 @@ import { getTransformInfos, } from '../../lang/std/sketchcombos' import { GetInfoModal } from '../SetHorVertDistanceModal' -import { - createIdentifier, - createVariableDeclaration, -} from '../../lang/modifyAst' +import { createVariableDeclaration } from '../../lang/modifyAst' import { removeDoubleNegatives } from '../AvailableVarsHelpers' const getModalInfo = create(GetInfoModal as any) diff --git a/src/components/Toolbar/setAngleBetween.tsx b/src/components/Toolbar/setAngleBetween.tsx new file mode 100644 index 000000000..e515238b4 --- /dev/null +++ b/src/components/Toolbar/setAngleBetween.tsx @@ -0,0 +1,153 @@ +import { useState, useEffect } from 'react' +import { create } from 'react-modal-promise' +import { toolTips, useStore } from '../../useStore' +import { + BinaryPart, + Value, + VariableDeclarator, +} from '../../lang/abstractSyntaxTree' +import { + getNodePathFromSourceRange, + getNodeFromPath, +} from '../../lang/queryAst' +import { isSketchVariablesLinked } from '../../lang/std/sketchConstraints' +import { + TransformInfo, + transformSecondarySketchLinesTagFirst, + getTransformInfos, +} from '../../lang/std/sketchcombos' +import { GetInfoModal } from '../SetHorVertDistanceModal' +import { createVariableDeclaration } from '../../lang/modifyAst' +import { removeDoubleNegatives } from '../AvailableVarsHelpers' + +const getModalInfo = create(GetInfoModal as any) + +export const SetAngleBetween = () => { + const { guiMode, selectionRanges, ast, programMemory, updateAst } = useStore( + (s) => ({ + guiMode: s.guiMode, + ast: s.ast, + updateAst: s.updateAst, + selectionRanges: s.selectionRanges, + programMemory: s.programMemory, + }) + ) + const [enable, setEnable] = useState(false) + const [transformInfos, setTransformInfos] = useState() + useEffect(() => { + if (!ast) return + const paths = selectionRanges.codeBasedSelections.map(({ range }) => + getNodePathFromSourceRange(ast, range) + ) + const nodes = paths.map( + (pathToNode) => getNodeFromPath(ast, pathToNode).node + ) + const varDecs = paths.map( + (pathToNode) => + getNodeFromPath( + ast, + pathToNode, + 'VariableDeclarator' + )?.node + ) + const primaryLine = varDecs[0] + const secondaryVarDecs = varDecs.slice(1) + const isOthersLinkedToPrimary = secondaryVarDecs.every((secondary) => + isSketchVariablesLinked(secondary, primaryLine, ast) + ) + const isAllTooltips = nodes.every( + (node) => + node?.type === 'CallExpression' && + toolTips.includes(node.callee.name as any) + ) + + const theTransforms = getTransformInfos( + { + ...selectionRanges, + codeBasedSelections: selectionRanges.codeBasedSelections.slice(1), + }, + ast, + 'setAngleBetween' + ) + setTransformInfos(theTransforms) + + const _enableEqual = + secondaryVarDecs.length === 1 && + isAllTooltips && + isOthersLinkedToPrimary && + theTransforms.every(Boolean) + setEnable(_enableEqual) + }, [guiMode, selectionRanges]) + if (guiMode.mode !== 'sketch') return null + + return ( + + ) +} diff --git a/src/lang/std/sketch.ts b/src/lang/std/sketch.ts index 14ca63b57..c6f66efa6 100644 --- a/src/lang/std/sketch.ts +++ b/src/lang/std/sketch.ts @@ -953,7 +953,15 @@ export const angledLineToX: SketchLineHelper = { previousSketch ) }, - add: ({ node, pathToNode, to, from, createCallback, replaceExisting }) => { + add: ({ + node, + pathToNode, + to, + from, + createCallback, + replaceExisting, + referencedSegment, + }) => { const _node = { ...node } const { node: pipe } = getNodeFromPath( _node, @@ -963,7 +971,10 @@ export const angledLineToX: SketchLineHelper = { const angle = createLiteral(roundOff(getAngle(from, to), 0)) const xArg = createLiteral(roundOff(to[0], 2)) if (replaceExisting && createCallback) { - const { callExp, valueUsedInTransform } = createCallback([angle, xArg]) + const { callExp, valueUsedInTransform } = createCallback( + [angle, xArg], + referencedSegment + ) const { index: callIndex } = splitPathAtPipeExpression(pathToNode) pipe.body[callIndex] = callExp return { @@ -1038,7 +1049,15 @@ export const angledLineToY: SketchLineHelper = { previousSketch ) }, - add: ({ node, pathToNode, to, from, createCallback, replaceExisting }) => { + add: ({ + node, + pathToNode, + to, + from, + createCallback, + replaceExisting, + referencedSegment, + }) => { const _node = { ...node } const { node: pipe } = getNodeFromPath( _node, @@ -1049,7 +1068,10 @@ export const angledLineToY: SketchLineHelper = { const yArg = createLiteral(roundOff(to[1], 2)) if (replaceExisting && createCallback) { - const { callExp, valueUsedInTransform } = createCallback([angle, yArg]) + const { callExp, valueUsedInTransform } = createCallback( + [angle, yArg], + referencedSegment + ) const { index: callIndex } = splitPathAtPipeExpression(pathToNode) pipe.body[callIndex] = callExp return { diff --git a/src/lang/std/sketchcombos.ts b/src/lang/std/sketchcombos.ts index 355b1befa..31b140d53 100644 --- a/src/lang/std/sketchcombos.ts +++ b/src/lang/std/sketchcombos.ts @@ -13,6 +13,7 @@ import { getNodePathFromSourceRange, } from '../queryAst' import { + createBinaryExpression, createBinaryExpressionWithUnary, createCallExpression, createIdentifier, @@ -25,7 +26,7 @@ import { import { createFirstArg, getFirstArg, replaceSketchLine } from './sketch' import { ProgramMemory } from '../executor' import { getSketchSegmentFromSourceRange } from './sketchConstraints' -import { getAngle, roundOff } from '../../lib/utils' +import { getAngle, roundOff, normaliseAngle } from '../../lib/utils' type LineInputsType = | 'xAbsolute' @@ -48,6 +49,7 @@ export type ConstraintType = | 'removeConstrainingValues' | 'xAbs' | 'yAbs' + | 'setAngleBetween' function createCallWrapper( a: TooTip, @@ -294,13 +296,12 @@ const setAbsDistanceCreateNode = isXOrYLine = false, index = xOrY === 'x' ? 0 : 1 ): TransformInfo['createNode'] => - ({ tag, forceValueUsedInTransform, ...rest }) => { - return (args, referencedSegment, ...rest2) => { + ({ tag, forceValueUsedInTransform }) => { + return (args, referencedSegment) => { const valueUsedInTransform = roundOff( getArgLiteralVal(args?.[index]) - (referencedSegment?.to?.[index] || 0), 2 ) - console.log(rest, rest2) const val = (forceValueUsedInTransform as BinaryPart) || createLiteral(valueUsedInTransform) @@ -434,6 +435,49 @@ const setAngledIntersectForAngledLines: TransformInfo['createNode'] = }) } +const setAngleBetweenCreateNode = + (tranformToType: 'none' | 'xAbs' | 'yAbs'): TransformInfo['createNode'] => + ({ referenceSegName, tag, forceValueUsedInTransform, varValA, varValB }) => { + return (args, referencedSegment) => { + const refAngle = referencedSegment + ? getAngle(referencedSegment?.from, referencedSegment?.to) + : 0 + let valueUsedInTransform = roundOff( + normaliseAngle( + (args[0].type === 'Literal' ? Number(args[0].value) : 0) - refAngle + ) + ) + let firstHalfValue = createSegAngle(referenceSegName) as BinaryPart + if (Math.abs(valueUsedInTransform) > 90) { + firstHalfValue = createBinaryExpression([ + firstHalfValue, + '+', + createIdentifier('_180'), + ]) + valueUsedInTransform = normaliseAngle(valueUsedInTransform - 180) + } + const binExp = createBinaryExpressionWithUnary([ + firstHalfValue, + (forceValueUsedInTransform as BinaryPart) || + createLiteral(valueUsedInTransform), + ]) + return createCallWrapper( + tranformToType === 'none' + ? 'angledLine' + : tranformToType === 'xAbs' + ? 'angledLineToX' + : 'angledLineToY', + tranformToType === 'none' + ? [binExp, args[1]] + : tranformToType === 'xAbs' + ? [binExp, varValA] + : [binExp, varValB], + tag, + valueUsedInTransform + ) + } + } + const transformMap: TransformMap = { line: { xRelative: { @@ -543,6 +587,10 @@ const transformMap: TransformMap = { tooltip: 'angledLineThatIntersects', createNode: setAngledIntersectLineForLines, }, + setAngleBetween: { + tooltip: 'angledLine', + createNode: setAngleBetweenCreateNode('none'), + }, }, }, lineTo: { @@ -594,6 +642,10 @@ const transformMap: TransformMap = { () => createCallWrapper('xLineTo', varValA, tag), }, + setAngleBetween: { + tooltip: 'angledLineToX', + createNode: setAngleBetweenCreateNode('xAbs'), + }, }, yAbsolute: { equalLength: { @@ -636,6 +688,10 @@ const transformMap: TransformMap = { ) }, }, + setAngleBetween: { + tooltip: 'angledLineToY', + createNode: setAngleBetweenCreateNode('yAbs'), + }, }, }, angledLine: {