2024-05-24 20:54:42 +10:00
|
|
|
import { TransformCallback, VarValues } from './stdTypes'
|
2024-07-02 17:16:27 +10:00
|
|
|
import { ToolTip, toolTips } from 'lang/langHelpers'
|
2023-10-16 21:20:05 +11:00
|
|
|
import { Selections, Selection } from 'lib/selections'
|
2024-06-24 11:45:40 -04:00
|
|
|
import { cleanErrs, err } from 'lib/trap'
|
2023-03-02 21:19:11 +11:00
|
|
|
import {
|
|
|
|
CallExpression,
|
|
|
|
Program,
|
|
|
|
Value,
|
2023-04-06 12:45:56 +10:00
|
|
|
BinaryPart,
|
2023-03-02 21:19:11 +11:00
|
|
|
VariableDeclarator,
|
2023-09-29 11:11:01 -07:00
|
|
|
PathToNode,
|
|
|
|
ProgramMemory,
|
|
|
|
} from '../wasm'
|
2023-03-03 20:35:48 +11:00
|
|
|
import {
|
|
|
|
getNodeFromPath,
|
|
|
|
getNodeFromPathCurry,
|
|
|
|
getNodePathFromSourceRange,
|
2023-04-06 12:45:56 +10:00
|
|
|
isValueZero,
|
2023-03-03 20:35:48 +11:00
|
|
|
} from '../queryAst'
|
2023-03-02 21:19:11 +11:00
|
|
|
import {
|
2024-05-24 20:54:42 +10:00
|
|
|
createArrayExpression,
|
2023-04-05 21:06:20 +10:00
|
|
|
createBinaryExpression,
|
2023-04-02 17:20:11 +10:00
|
|
|
createBinaryExpressionWithUnary,
|
2023-03-02 21:19:11 +11:00
|
|
|
createCallExpression,
|
2023-03-10 08:48:50 +11:00
|
|
|
createIdentifier,
|
2023-03-02 21:19:11 +11:00
|
|
|
createLiteral,
|
2023-03-19 18:46:39 +11:00
|
|
|
createObjectExpression,
|
2023-03-02 21:19:11 +11:00
|
|
|
createPipeSubstitution,
|
|
|
|
createUnaryExpression,
|
|
|
|
giveSketchFnCallTag,
|
|
|
|
} from '../modifyAst'
|
2024-05-24 20:54:42 +10:00
|
|
|
import {
|
|
|
|
createFirstArg,
|
|
|
|
getConstraintInfo,
|
|
|
|
getFirstArg,
|
|
|
|
replaceSketchLine,
|
|
|
|
} from './sketch'
|
|
|
|
import {
|
|
|
|
getSketchSegmentFromPathToNode,
|
|
|
|
getSketchSegmentFromSourceRange,
|
|
|
|
} from './sketchConstraints'
|
2023-04-05 21:06:20 +10:00
|
|
|
import { getAngle, roundOff, normaliseAngle } from '../../lib/utils'
|
2023-03-02 21:19:11 +11:00
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
export type LineInputsType =
|
2023-03-02 21:19:11 +11:00
|
|
|
| 'xAbsolute'
|
|
|
|
| 'yAbsolute'
|
|
|
|
| 'xRelative'
|
|
|
|
| 'yRelative'
|
|
|
|
| 'angle'
|
|
|
|
| 'length'
|
2024-05-24 20:54:42 +10:00
|
|
|
| 'intersectionOffset'
|
|
|
|
| 'intersectionTag'
|
2023-03-02 21:19:11 +11:00
|
|
|
|
|
|
|
export type ConstraintType =
|
|
|
|
| 'equalLength'
|
|
|
|
| 'vertical'
|
|
|
|
| 'horizontal'
|
2023-03-17 21:15:46 +11:00
|
|
|
| 'equalAngle'
|
2023-03-05 07:34:56 +11:00
|
|
|
| 'setHorzDistance'
|
|
|
|
| 'setVertDistance'
|
2023-03-10 08:48:50 +11:00
|
|
|
| 'setAngle'
|
|
|
|
| 'setLength'
|
2023-03-19 18:46:39 +11:00
|
|
|
| 'intersect'
|
2023-03-22 03:02:37 +11:00
|
|
|
| 'removeConstrainingValues'
|
2023-04-05 15:08:46 +10:00
|
|
|
| 'xAbs'
|
|
|
|
| 'yAbs'
|
2023-04-05 21:06:20 +10:00
|
|
|
| 'setAngleBetween'
|
2023-03-02 21:19:11 +11:00
|
|
|
|
|
|
|
function createCallWrapper(
|
2023-09-15 11:48:23 -04:00
|
|
|
a: ToolTip,
|
2023-03-02 21:19:11 +11:00
|
|
|
val: [Value, Value] | Value,
|
2023-03-07 15:45:59 +11:00
|
|
|
tag?: Value,
|
|
|
|
valueUsedInTransform?: number
|
|
|
|
): ReturnType<TransformCallback> {
|
2024-03-15 17:03:42 -04:00
|
|
|
const args = [createFirstArg(a, val), createPipeSubstitution()]
|
|
|
|
if (tag) {
|
|
|
|
args.push(tag)
|
|
|
|
}
|
2024-06-24 11:45:40 -04:00
|
|
|
|
|
|
|
const [hasErr, argsWOutErr] = cleanErrs(args)
|
|
|
|
if (hasErr) {
|
|
|
|
console.error(args)
|
|
|
|
return {
|
|
|
|
callExp: createCallExpression('', []),
|
|
|
|
valueUsedInTransform: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-07 15:45:59 +11:00
|
|
|
return {
|
2024-06-24 11:45:40 -04:00
|
|
|
callExp: createCallExpression(a, argsWOutErr),
|
2023-03-07 15:45:59 +11:00
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
2023-03-02 21:19:11 +11:00
|
|
|
}
|
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
/**
|
|
|
|
* Abstracts creation of a callExpression ready for use for a sketchCombo transform
|
|
|
|
* Assume it exists within a pipe and adds the pipe substitution
|
|
|
|
* @param tool line, lineTo, angledLine, etc
|
|
|
|
* @param val The first argument to the function
|
|
|
|
* @param tag
|
|
|
|
* @param valueUsedInTransform
|
|
|
|
* @returns
|
|
|
|
*/
|
|
|
|
function createStdlibCallExpression(
|
|
|
|
tool: ToolTip,
|
|
|
|
val: Value,
|
|
|
|
tag?: Value,
|
|
|
|
valueUsedInTransform?: number
|
|
|
|
): ReturnType<TransformCallback> {
|
|
|
|
const args = [val, createPipeSubstitution()]
|
|
|
|
if (tag) {
|
|
|
|
args.push(tag)
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
callExp: createCallExpression(tool, args),
|
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-19 18:46:39 +11:00
|
|
|
function intersectCallWrapper({
|
|
|
|
fnName,
|
|
|
|
angleVal,
|
|
|
|
offsetVal,
|
|
|
|
intersectTag,
|
|
|
|
tag,
|
|
|
|
valueUsedInTransform,
|
|
|
|
}: {
|
|
|
|
fnName: string
|
|
|
|
angleVal: Value
|
|
|
|
offsetVal: Value
|
|
|
|
intersectTag: Value
|
|
|
|
tag?: Value
|
|
|
|
valueUsedInTransform?: number
|
|
|
|
}): ReturnType<TransformCallback> {
|
|
|
|
const firstArg: any = {
|
|
|
|
angle: angleVal,
|
|
|
|
offset: offsetVal,
|
|
|
|
intersectTag,
|
|
|
|
}
|
2024-03-15 17:03:42 -04:00
|
|
|
const args: Value[] = [
|
|
|
|
createObjectExpression(firstArg),
|
|
|
|
createPipeSubstitution(),
|
|
|
|
]
|
2023-03-19 18:46:39 +11:00
|
|
|
if (tag) {
|
2024-03-15 17:03:42 -04:00
|
|
|
args.push(tag)
|
2023-03-19 18:46:39 +11:00
|
|
|
}
|
|
|
|
return {
|
2024-03-15 17:03:42 -04:00
|
|
|
callExp: createCallExpression(fnName, args),
|
2023-03-19 18:46:39 +11:00
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-02 21:19:11 +11:00
|
|
|
export type TransformInfo = {
|
2023-09-15 11:48:23 -04:00
|
|
|
tooltip: ToolTip
|
2023-03-02 21:19:11 +11:00
|
|
|
createNode: (a: {
|
2024-05-24 20:54:42 +10:00
|
|
|
varValues: VarValues
|
2023-03-02 21:19:11 +11:00
|
|
|
varValA: Value // x / angle
|
|
|
|
varValB: Value // y / length or x y for angledLineOfXlength etc
|
|
|
|
referenceSegName: string
|
|
|
|
tag?: Value
|
2023-03-07 15:45:59 +11:00
|
|
|
forceValueUsedInTransform?: Value
|
|
|
|
}) => TransformCallback
|
2023-03-02 21:19:11 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
type TransformMap = {
|
2023-09-15 11:48:23 -04:00
|
|
|
[key in ToolTip]?: {
|
2023-03-02 21:19:11 +11:00
|
|
|
[key in LineInputsType | 'free']?: {
|
|
|
|
[key in ConstraintType]?: TransformInfo
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-10 14:55:16 +11:00
|
|
|
const xyLineSetLength =
|
|
|
|
(
|
|
|
|
xOrY: 'xLine' | 'yLine',
|
|
|
|
referenceSeg = false
|
|
|
|
): TransformInfo['createNode'] =>
|
|
|
|
({ referenceSegName, tag, forceValueUsedInTransform }) =>
|
|
|
|
(args) => {
|
|
|
|
const segRef = createSegLen(referenceSegName)
|
|
|
|
const lineVal = forceValueUsedInTransform
|
|
|
|
? forceValueUsedInTransform
|
|
|
|
: referenceSeg
|
|
|
|
? segRef
|
|
|
|
: args[0]
|
|
|
|
return createCallWrapper(xOrY, lineVal, tag, getArgLiteralVal(args[0]))
|
|
|
|
}
|
|
|
|
|
2023-03-10 08:48:50 +11:00
|
|
|
const basicAngledLineCreateNode =
|
|
|
|
(
|
|
|
|
referenceSeg: 'ang' | 'len' | 'none' = 'none',
|
|
|
|
valToForce: 'ang' | 'len' | 'none' = 'none',
|
|
|
|
varValToUse: 'ang' | 'len' | 'none' = 'none'
|
|
|
|
): TransformInfo['createNode'] =>
|
|
|
|
({ referenceSegName, tag, forceValueUsedInTransform, varValA, varValB }) =>
|
2024-05-24 20:54:42 +10:00
|
|
|
(args, _, path) => {
|
2023-03-17 21:15:46 +11:00
|
|
|
const refAng = path ? getAngle(path?.from, path?.to) : 0
|
2023-03-10 08:48:50 +11:00
|
|
|
const nonForcedAng =
|
|
|
|
varValToUse === 'ang'
|
|
|
|
? varValA
|
|
|
|
: referenceSeg === 'ang'
|
2023-03-17 21:15:46 +11:00
|
|
|
? getClosesAngleDirection(
|
|
|
|
args[0],
|
|
|
|
refAng,
|
|
|
|
createSegAngle(referenceSegName) as BinaryPart
|
|
|
|
)
|
2023-03-10 08:48:50 +11:00
|
|
|
: args[0]
|
|
|
|
const nonForcedLen =
|
|
|
|
varValToUse === 'len'
|
|
|
|
? varValB
|
|
|
|
: referenceSeg === 'len'
|
|
|
|
? createSegLen(referenceSegName)
|
|
|
|
: args[1]
|
|
|
|
const shouldForceAng = valToForce === 'ang' && forceValueUsedInTransform
|
|
|
|
const shouldForceLen = valToForce === 'len' && forceValueUsedInTransform
|
|
|
|
return createCallWrapper(
|
2023-03-02 21:19:11 +11:00
|
|
|
'angledLine',
|
2023-03-10 08:48:50 +11:00
|
|
|
[
|
|
|
|
shouldForceAng ? forceValueUsedInTransform : nonForcedAng,
|
|
|
|
shouldForceLen ? forceValueUsedInTransform : nonForcedLen,
|
|
|
|
],
|
|
|
|
tag,
|
|
|
|
getArgLiteralVal(valToForce === 'ang' ? args[0] : args[1])
|
2023-03-02 21:19:11 +11:00
|
|
|
)
|
2023-03-10 08:48:50 +11:00
|
|
|
}
|
2023-03-02 21:19:11 +11:00
|
|
|
const angledLineAngleCreateNode: TransformInfo['createNode'] =
|
|
|
|
({ referenceSegName, varValA, tag }) =>
|
|
|
|
() =>
|
|
|
|
createCallWrapper(
|
|
|
|
'angledLine',
|
|
|
|
[varValA, createSegLen(referenceSegName)],
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
|
|
|
|
const getMinAndSegLenVals = (
|
|
|
|
referenceSegName: string,
|
|
|
|
varVal: Value
|
|
|
|
): [Value, BinaryPart] => {
|
|
|
|
const segLenVal = createSegLen(referenceSegName)
|
|
|
|
return [
|
|
|
|
createCallExpression('min', [segLenVal, varVal]),
|
|
|
|
createCallExpression('legLen', [segLenVal, varVal]),
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
const getMinAndSegAngVals = (
|
|
|
|
referenceSegName: string,
|
|
|
|
varVal: Value,
|
|
|
|
fnName: 'legAngX' | 'legAngY' = 'legAngX'
|
|
|
|
): [Value, BinaryPart] => {
|
|
|
|
const minVal = createCallExpression('min', [
|
|
|
|
createSegLen(referenceSegName),
|
|
|
|
varVal,
|
|
|
|
])
|
|
|
|
const legAngle = createCallExpression(fnName, [
|
|
|
|
createSegLen(referenceSegName),
|
|
|
|
varVal,
|
|
|
|
])
|
|
|
|
return [minVal, legAngle]
|
|
|
|
}
|
|
|
|
|
|
|
|
const getSignedLeg = (arg: Value, legLenVal: BinaryPart) =>
|
|
|
|
arg.type === 'Literal' && Number(arg.value) < 0
|
|
|
|
? createUnaryExpression(legLenVal)
|
|
|
|
: legLenVal
|
|
|
|
|
|
|
|
const getLegAng = (arg: Value, legAngleVal: BinaryPart) => {
|
|
|
|
const ang = (arg.type === 'Literal' && Number(arg.value)) || 0
|
|
|
|
const normalisedAngle = ((ang % 360) + 360) % 360 // between 0 and 360
|
|
|
|
const truncatedTo90 = Math.floor(normalisedAngle / 90) * 90
|
2023-04-02 17:20:11 +10:00
|
|
|
const binExp = createBinaryExpressionWithUnary([
|
2023-03-02 21:19:11 +11:00
|
|
|
createLiteral(truncatedTo90),
|
|
|
|
legAngleVal,
|
|
|
|
])
|
2023-03-10 08:48:50 +11:00
|
|
|
return truncatedTo90 === 0 ? legAngleVal : binExp
|
2023-03-02 21:19:11 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
const getAngleLengthSign = (arg: Value, legAngleVal: BinaryPart) => {
|
|
|
|
const ang = (arg.type === 'Literal' && Number(arg.value)) || 0
|
|
|
|
const normalisedAngle = ((ang % 180) + 180) % 180 // between 0 and 180
|
|
|
|
return normalisedAngle > 90 ? createUnaryExpression(legAngleVal) : legAngleVal
|
|
|
|
}
|
|
|
|
|
2023-03-17 21:15:46 +11:00
|
|
|
function getClosesAngleDirection(
|
|
|
|
arg: Value,
|
|
|
|
refAngle: number,
|
|
|
|
angleVal: BinaryPart
|
|
|
|
) {
|
|
|
|
const currentAng = (arg.type === 'Literal' && Number(arg.value)) || 0
|
|
|
|
const angDiff = Math.abs(currentAng - refAngle)
|
|
|
|
const normalisedAngle = ((angDiff % 360) + 360) % 360 // between 0 and 180
|
|
|
|
return normalisedAngle > 90
|
2023-04-02 17:20:11 +10:00
|
|
|
? createBinaryExpressionWithUnary([angleVal, createLiteral(180)])
|
2023-03-17 21:15:46 +11:00
|
|
|
: angleVal
|
|
|
|
}
|
|
|
|
|
2023-03-05 07:34:56 +11:00
|
|
|
const setHorzVertDistanceCreateNode =
|
2023-03-07 15:45:59 +11:00
|
|
|
(
|
|
|
|
xOrY: 'x' | 'y',
|
|
|
|
index = xOrY === 'x' ? 0 : 1
|
|
|
|
): TransformInfo['createNode'] =>
|
|
|
|
({ referenceSegName, tag, forceValueUsedInTransform }) => {
|
2024-05-24 20:54:42 +10:00
|
|
|
return (args, _, referencedSegment) => {
|
2023-03-07 15:45:59 +11:00
|
|
|
const valueUsedInTransform = roundOff(
|
|
|
|
getArgLiteralVal(args?.[index]) - (referencedSegment?.to?.[index] || 0),
|
|
|
|
2
|
|
|
|
)
|
2023-04-06 12:45:56 +10:00
|
|
|
let finalValue: Value = createBinaryExpressionWithUnary([
|
2023-03-07 15:45:59 +11:00
|
|
|
createSegEnd(referenceSegName, !index),
|
|
|
|
(forceValueUsedInTransform as BinaryPart) ||
|
|
|
|
createLiteral(valueUsedInTransform),
|
|
|
|
])
|
2023-04-06 12:45:56 +10:00
|
|
|
if (isValueZero(forceValueUsedInTransform)) {
|
|
|
|
finalValue = createSegEnd(referenceSegName, !index)
|
|
|
|
}
|
2023-03-05 07:34:56 +11:00
|
|
|
return createCallWrapper(
|
|
|
|
'lineTo',
|
2023-04-06 12:45:56 +10:00
|
|
|
!index ? [finalValue, args[1]] : [args[0], finalValue],
|
2023-03-07 15:45:59 +11:00
|
|
|
tag,
|
|
|
|
valueUsedInTransform
|
2023-03-05 07:34:56 +11:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2023-03-17 21:15:46 +11:00
|
|
|
const setHorzVertDistanceForAngleLineCreateNode =
|
|
|
|
(
|
|
|
|
xOrY: 'x' | 'y',
|
|
|
|
index = xOrY === 'x' ? 0 : 1
|
|
|
|
): TransformInfo['createNode'] =>
|
|
|
|
({ referenceSegName, tag, forceValueUsedInTransform, varValA }) => {
|
2024-05-24 20:54:42 +10:00
|
|
|
return (args, _, referencedSegment) => {
|
2023-03-17 21:15:46 +11:00
|
|
|
const valueUsedInTransform = roundOff(
|
|
|
|
getArgLiteralVal(args?.[1]) - (referencedSegment?.to?.[index] || 0),
|
|
|
|
2
|
|
|
|
)
|
2023-04-02 17:20:11 +10:00
|
|
|
const binExp = createBinaryExpressionWithUnary([
|
2023-03-17 21:15:46 +11:00
|
|
|
createSegEnd(referenceSegName, !index),
|
|
|
|
(forceValueUsedInTransform as BinaryPart) ||
|
|
|
|
createLiteral(valueUsedInTransform),
|
|
|
|
])
|
|
|
|
return createCallWrapper(
|
|
|
|
xOrY === 'x' ? 'angledLineToX' : 'angledLineToY',
|
2023-04-02 17:20:11 +10:00
|
|
|
[varValA, binExp],
|
2023-03-17 21:15:46 +11:00
|
|
|
tag,
|
|
|
|
valueUsedInTransform
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-05 15:08:46 +10:00
|
|
|
const setAbsDistanceCreateNode =
|
|
|
|
(
|
|
|
|
xOrY: 'x' | 'y',
|
|
|
|
isXOrYLine = false,
|
|
|
|
index = xOrY === 'x' ? 0 : 1
|
|
|
|
): TransformInfo['createNode'] =>
|
2024-05-31 14:00:32 +10:00
|
|
|
({ tag, forceValueUsedInTransform }) =>
|
|
|
|
(args) => {
|
|
|
|
const valueUsedInTransform = roundOff(getArgLiteralVal(args?.[index]), 2)
|
|
|
|
const val =
|
|
|
|
(forceValueUsedInTransform as BinaryPart) ||
|
|
|
|
createLiteral(valueUsedInTransform)
|
|
|
|
if (isXOrYLine) {
|
2023-04-05 15:08:46 +10:00
|
|
|
return createCallWrapper(
|
2024-05-31 14:00:32 +10:00
|
|
|
xOrY === 'x' ? 'xLineTo' : 'yLineTo',
|
|
|
|
val,
|
2023-04-05 15:08:46 +10:00
|
|
|
tag,
|
|
|
|
valueUsedInTransform
|
|
|
|
)
|
|
|
|
}
|
2024-05-31 14:00:32 +10:00
|
|
|
return createCallWrapper(
|
|
|
|
'lineTo',
|
|
|
|
!index ? [val, args[1]] : [args[0], val],
|
|
|
|
tag,
|
|
|
|
valueUsedInTransform
|
|
|
|
)
|
2023-04-05 15:08:46 +10:00
|
|
|
}
|
|
|
|
const setAbsDistanceForAngleLineCreateNode =
|
2024-05-31 14:00:32 +10:00
|
|
|
(xOrY: 'x' | 'y'): TransformInfo['createNode'] =>
|
2023-04-05 15:08:46 +10:00
|
|
|
({ tag, forceValueUsedInTransform, varValA }) => {
|
2024-05-24 20:54:42 +10:00
|
|
|
return (args) => {
|
2023-12-01 20:18:51 +11:00
|
|
|
const valueUsedInTransform = roundOff(getArgLiteralVal(args?.[1]), 2)
|
2023-04-05 15:08:46 +10:00
|
|
|
const val =
|
|
|
|
(forceValueUsedInTransform as BinaryPart) ||
|
|
|
|
createLiteral(valueUsedInTransform)
|
|
|
|
return createCallWrapper(
|
|
|
|
xOrY === 'x' ? 'angledLineToX' : 'angledLineToY',
|
|
|
|
[varValA, val],
|
|
|
|
tag,
|
|
|
|
valueUsedInTransform
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-17 21:15:46 +11:00
|
|
|
const setHorVertDistanceForXYLines =
|
|
|
|
(xOrY: 'x' | 'y'): TransformInfo['createNode'] =>
|
|
|
|
({ referenceSegName, tag, forceValueUsedInTransform }) => {
|
2024-05-24 20:54:42 +10:00
|
|
|
return (args, _, referencedSegment) => {
|
2023-03-17 21:15:46 +11:00
|
|
|
const index = xOrY === 'x' ? 0 : 1
|
|
|
|
const valueUsedInTransform = roundOff(
|
|
|
|
getArgLiteralVal(args?.[index]) - (referencedSegment?.to?.[index] || 0),
|
|
|
|
2
|
|
|
|
)
|
2023-04-02 17:20:11 +10:00
|
|
|
const makeBinExp = createBinaryExpressionWithUnary([
|
2023-03-17 21:15:46 +11:00
|
|
|
createSegEnd(referenceSegName, xOrY === 'x'),
|
|
|
|
(forceValueUsedInTransform as BinaryPart) ||
|
|
|
|
createLiteral(valueUsedInTransform),
|
|
|
|
])
|
|
|
|
return createCallWrapper(
|
|
|
|
xOrY === 'x' ? 'xLineTo' : 'yLineTo',
|
|
|
|
makeBinExp,
|
|
|
|
tag,
|
|
|
|
valueUsedInTransform
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2023-03-05 07:34:56 +11:00
|
|
|
|
|
|
|
const setHorzVertDistanceConstraintLineCreateNode =
|
|
|
|
(isX: boolean): TransformInfo['createNode'] =>
|
|
|
|
({ referenceSegName, tag, varValA, varValB }) => {
|
|
|
|
const varVal = (isX ? varValB : varValA) as BinaryPart
|
2023-04-02 17:20:11 +10:00
|
|
|
const varValBinExp = createBinaryExpressionWithUnary([
|
2023-03-05 07:34:56 +11:00
|
|
|
createLastSeg(!isX),
|
|
|
|
varVal,
|
|
|
|
])
|
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
return (args, _, referencedSegment) => {
|
2023-03-05 07:34:56 +11:00
|
|
|
const makeBinExp = (index: 0 | 1) => {
|
|
|
|
const arg = getArgLiteralVal(args?.[index])
|
2023-04-02 17:20:11 +10:00
|
|
|
return createBinaryExpressionWithUnary([
|
2023-03-05 07:34:56 +11:00
|
|
|
createSegEnd(referenceSegName, isX),
|
|
|
|
createLiteral(
|
|
|
|
roundOff(arg - (referencedSegment?.to?.[index] || 0), 2)
|
|
|
|
),
|
|
|
|
])
|
|
|
|
}
|
|
|
|
return createCallWrapper(
|
|
|
|
'lineTo',
|
|
|
|
isX ? [makeBinExp(0), varValBinExp] : [varValBinExp, makeBinExp(1)],
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-19 18:46:39 +11:00
|
|
|
const setAngledIntersectLineForLines: TransformInfo['createNode'] =
|
|
|
|
({ referenceSegName, tag, forceValueUsedInTransform }) =>
|
|
|
|
(args) => {
|
|
|
|
const valueUsedInTransform = roundOff(
|
|
|
|
args[1].type === 'Literal' ? Number(args[1].value) : 0,
|
|
|
|
2
|
|
|
|
)
|
|
|
|
const angle = args[0].type === 'Literal' ? Number(args[0].value) : 0
|
2024-02-11 18:26:09 -08:00
|
|
|
const varNamMap: { [key: number]: string } = {
|
|
|
|
0: 'ZERO',
|
|
|
|
90: 'QUARTER_TURN',
|
|
|
|
180: 'HALF_TURN',
|
|
|
|
270: 'THREE_QUARTER_TURN',
|
|
|
|
}
|
2023-04-01 21:25:00 +11:00
|
|
|
const angleVal = [0, 90, 180, 270].includes(angle)
|
2024-02-11 18:26:09 -08:00
|
|
|
? createIdentifier(varNamMap[angle])
|
2023-04-01 21:25:00 +11:00
|
|
|
: createLiteral(angle)
|
2023-03-19 18:46:39 +11:00
|
|
|
return intersectCallWrapper({
|
|
|
|
fnName: 'angledLineThatIntersects',
|
2023-04-01 21:25:00 +11:00
|
|
|
angleVal,
|
2023-03-19 18:46:39 +11:00
|
|
|
offsetVal:
|
|
|
|
forceValueUsedInTransform || createLiteral(valueUsedInTransform),
|
2024-06-24 22:39:04 -07:00
|
|
|
intersectTag: createIdentifier(referenceSegName),
|
2023-03-19 18:46:39 +11:00
|
|
|
tag,
|
|
|
|
valueUsedInTransform,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
const setAngledIntersectForAngledLines: TransformInfo['createNode'] =
|
|
|
|
({ referenceSegName, tag, forceValueUsedInTransform, varValA }) =>
|
|
|
|
(args) => {
|
|
|
|
const valueUsedInTransform = roundOff(
|
|
|
|
args[1].type === 'Literal' ? Number(args[1].value) : 0,
|
|
|
|
2
|
|
|
|
)
|
|
|
|
// const angle = args[0].type === 'Literal' ? Number(args[0].value) : 0
|
|
|
|
return intersectCallWrapper({
|
|
|
|
fnName: 'angledLineThatIntersects',
|
|
|
|
angleVal: varValA,
|
|
|
|
offsetVal:
|
|
|
|
forceValueUsedInTransform || createLiteral(valueUsedInTransform),
|
2024-06-24 22:39:04 -07:00
|
|
|
intersectTag: createIdentifier(referenceSegName),
|
2023-03-19 18:46:39 +11:00
|
|
|
tag,
|
|
|
|
valueUsedInTransform,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-04-05 21:06:20 +10:00
|
|
|
const setAngleBetweenCreateNode =
|
|
|
|
(tranformToType: 'none' | 'xAbs' | 'yAbs'): TransformInfo['createNode'] =>
|
|
|
|
({ referenceSegName, tag, forceValueUsedInTransform, varValA, varValB }) => {
|
2024-05-24 20:54:42 +10:00
|
|
|
return (args, _, referencedSegment) => {
|
2023-04-05 21:06:20 +10:00
|
|
|
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,
|
|
|
|
'+',
|
2024-02-11 18:26:09 -08:00
|
|
|
createIdentifier('HALF_TURN'),
|
2023-04-05 21:06:20 +10:00
|
|
|
])
|
|
|
|
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
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-02 21:19:11 +11:00
|
|
|
const transformMap: TransformMap = {
|
|
|
|
line: {
|
|
|
|
xRelative: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'line',
|
|
|
|
createNode: ({ referenceSegName, varValA, tag }) => {
|
|
|
|
const [minVal, legLenVal] = getMinAndSegLenVals(
|
|
|
|
referenceSegName,
|
|
|
|
varValA
|
|
|
|
)
|
|
|
|
return (args) =>
|
|
|
|
createCallWrapper(
|
|
|
|
'line',
|
|
|
|
[minVal, getSignedLeg(args[1], legLenVal)],
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
horizontal: {
|
|
|
|
tooltip: 'xLine',
|
|
|
|
createNode:
|
|
|
|
({ varValA, tag }) =>
|
|
|
|
() =>
|
|
|
|
createCallWrapper('xLine', varValA, tag),
|
|
|
|
},
|
2023-03-05 07:34:56 +11:00
|
|
|
setVertDistance: {
|
|
|
|
tooltip: 'lineTo',
|
|
|
|
createNode: setHorzVertDistanceConstraintLineCreateNode(false),
|
|
|
|
},
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
yRelative: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'line',
|
|
|
|
createNode: ({ referenceSegName, varValB, tag }) => {
|
|
|
|
const [minVal, legLenVal] = getMinAndSegLenVals(
|
|
|
|
referenceSegName,
|
|
|
|
varValB
|
|
|
|
)
|
|
|
|
return (args) =>
|
|
|
|
createCallWrapper(
|
|
|
|
'line',
|
|
|
|
[getSignedLeg(args[0], legLenVal), minVal],
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
vertical: {
|
|
|
|
tooltip: 'yLine',
|
|
|
|
createNode:
|
|
|
|
({ varValB, tag }) =>
|
|
|
|
() =>
|
|
|
|
createCallWrapper('yLine', varValB, tag),
|
|
|
|
},
|
2023-03-05 07:34:56 +11:00
|
|
|
setHorzDistance: {
|
|
|
|
tooltip: 'lineTo',
|
|
|
|
createNode: setHorzVertDistanceConstraintLineCreateNode(true),
|
|
|
|
},
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
free: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLine',
|
2023-03-10 08:48:50 +11:00
|
|
|
createNode: basicAngledLineCreateNode('len'),
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
horizontal: {
|
|
|
|
tooltip: 'xLine',
|
|
|
|
createNode:
|
|
|
|
({ tag }) =>
|
|
|
|
(args) =>
|
|
|
|
createCallWrapper('xLine', args[0], tag),
|
|
|
|
},
|
|
|
|
vertical: {
|
|
|
|
tooltip: 'yLine',
|
|
|
|
createNode:
|
|
|
|
({ tag }) =>
|
|
|
|
(args) =>
|
|
|
|
createCallWrapper('yLine', args[1], tag),
|
|
|
|
},
|
2023-03-05 07:34:56 +11:00
|
|
|
setHorzDistance: {
|
|
|
|
tooltip: 'lineTo',
|
2023-03-07 15:45:59 +11:00
|
|
|
createNode: setHorzVertDistanceCreateNode('x'),
|
2023-03-05 07:34:56 +11:00
|
|
|
},
|
2023-04-05 15:08:46 +10:00
|
|
|
xAbs: {
|
|
|
|
tooltip: 'lineTo',
|
|
|
|
createNode: setAbsDistanceCreateNode('x'),
|
|
|
|
},
|
2023-03-05 07:34:56 +11:00
|
|
|
setVertDistance: {
|
|
|
|
tooltip: 'lineTo',
|
2023-03-07 15:45:59 +11:00
|
|
|
createNode: setHorzVertDistanceCreateNode('y'),
|
2023-03-05 07:34:56 +11:00
|
|
|
},
|
2023-04-05 15:08:46 +10:00
|
|
|
yAbs: {
|
|
|
|
tooltip: 'lineTo',
|
|
|
|
createNode: setAbsDistanceCreateNode('y'),
|
|
|
|
},
|
2023-03-10 08:48:50 +11:00
|
|
|
setAngle: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode: basicAngledLineCreateNode('none', 'ang'),
|
|
|
|
},
|
|
|
|
setLength: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode: basicAngledLineCreateNode('none', 'len'),
|
|
|
|
},
|
2023-03-17 21:15:46 +11:00
|
|
|
equalAngle: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode: basicAngledLineCreateNode('ang'),
|
|
|
|
},
|
2023-03-19 18:46:39 +11:00
|
|
|
intersect: {
|
|
|
|
tooltip: 'angledLineThatIntersects',
|
|
|
|
createNode: setAngledIntersectLineForLines,
|
|
|
|
},
|
2023-04-05 21:06:20 +10:00
|
|
|
setAngleBetween: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode: setAngleBetweenCreateNode('none'),
|
|
|
|
},
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
},
|
|
|
|
lineTo: {
|
|
|
|
free: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLine',
|
2023-03-10 08:48:50 +11:00
|
|
|
createNode: basicAngledLineCreateNode('len'),
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
horizontal: {
|
|
|
|
tooltip: 'xLineTo',
|
|
|
|
createNode:
|
|
|
|
({ tag }) =>
|
|
|
|
(args) =>
|
|
|
|
createCallWrapper('xLineTo', args[0], tag),
|
|
|
|
},
|
|
|
|
vertical: {
|
|
|
|
tooltip: 'yLineTo',
|
|
|
|
createNode:
|
|
|
|
({ tag }) =>
|
|
|
|
(args) =>
|
|
|
|
createCallWrapper('yLineTo', args[1], tag),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
xAbsolute: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLineToX',
|
|
|
|
createNode:
|
|
|
|
({ referenceSegName, varValA, tag }) =>
|
|
|
|
(args) => {
|
|
|
|
const angleToMatchLengthXCall = createCallExpression(
|
|
|
|
'angleToMatchLengthX',
|
|
|
|
[
|
2024-06-24 22:39:04 -07:00
|
|
|
createIdentifier(referenceSegName),
|
2023-03-02 21:19:11 +11:00
|
|
|
varValA,
|
|
|
|
createPipeSubstitution(),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
return createCallWrapper(
|
|
|
|
'angledLineToX',
|
|
|
|
[getAngleLengthSign(args[0], angleToMatchLengthXCall), varValA],
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
horizontal: {
|
|
|
|
tooltip: 'xLineTo',
|
|
|
|
createNode:
|
|
|
|
({ varValA, tag }) =>
|
|
|
|
() =>
|
|
|
|
createCallWrapper('xLineTo', varValA, tag),
|
|
|
|
},
|
2023-04-05 21:06:20 +10:00
|
|
|
setAngleBetween: {
|
|
|
|
tooltip: 'angledLineToX',
|
|
|
|
createNode: setAngleBetweenCreateNode('xAbs'),
|
|
|
|
},
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
yAbsolute: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLineToY',
|
|
|
|
createNode:
|
|
|
|
({ referenceSegName, varValB, tag }) =>
|
|
|
|
(args) => {
|
|
|
|
const angleToMatchLengthYCall = createCallExpression(
|
|
|
|
'angleToMatchLengthY',
|
|
|
|
[
|
2024-06-24 22:39:04 -07:00
|
|
|
createIdentifier(referenceSegName),
|
2023-03-02 21:19:11 +11:00
|
|
|
varValB,
|
|
|
|
createPipeSubstitution(),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
return createCallWrapper(
|
|
|
|
'angledLineToY',
|
|
|
|
[getAngleLengthSign(args[0], angleToMatchLengthYCall), varValB],
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
vertical: {
|
|
|
|
tooltip: 'yLineTo',
|
|
|
|
createNode:
|
|
|
|
({ varValB, tag }) =>
|
|
|
|
() =>
|
|
|
|
createCallWrapper('yLineTo', varValB, tag),
|
|
|
|
},
|
2023-03-10 14:55:16 +11:00
|
|
|
setAngle: {
|
|
|
|
tooltip: 'angledLineToY',
|
|
|
|
createNode:
|
|
|
|
({ varValB, tag, forceValueUsedInTransform }) =>
|
|
|
|
(args) => {
|
|
|
|
return createCallWrapper(
|
|
|
|
'angledLineToY',
|
|
|
|
[forceValueUsedInTransform || args[0], varValB],
|
|
|
|
tag,
|
|
|
|
getArgLiteralVal(args[0])
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
2023-04-05 21:06:20 +10:00
|
|
|
setAngleBetween: {
|
|
|
|
tooltip: 'angledLineToY',
|
|
|
|
createNode: setAngleBetweenCreateNode('yAbs'),
|
|
|
|
},
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
},
|
|
|
|
angledLine: {
|
|
|
|
angle: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode:
|
|
|
|
({ referenceSegName, varValA, tag }) =>
|
|
|
|
() =>
|
|
|
|
createCallWrapper(
|
|
|
|
'angledLine',
|
|
|
|
[varValA, createSegLen(referenceSegName)],
|
|
|
|
tag
|
|
|
|
),
|
|
|
|
},
|
2023-03-10 08:48:50 +11:00
|
|
|
setLength: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode: basicAngledLineCreateNode('none', 'len', 'ang'),
|
|
|
|
},
|
2023-03-17 21:15:46 +11:00
|
|
|
setVertDistance: {
|
|
|
|
tooltip: 'angledLineToY',
|
|
|
|
createNode: setHorzVertDistanceForAngleLineCreateNode('y'),
|
|
|
|
},
|
2023-04-05 15:08:46 +10:00
|
|
|
yAbs: {
|
|
|
|
tooltip: 'angledLineToY',
|
|
|
|
createNode: setAbsDistanceForAngleLineCreateNode('y'),
|
|
|
|
},
|
2023-03-17 21:15:46 +11:00
|
|
|
setHorzDistance: {
|
|
|
|
tooltip: 'angledLineToX',
|
|
|
|
createNode: setHorzVertDistanceForAngleLineCreateNode('x'),
|
|
|
|
},
|
2023-04-05 15:08:46 +10:00
|
|
|
xAbs: {
|
|
|
|
tooltip: 'angledLineToX',
|
|
|
|
createNode: setAbsDistanceForAngleLineCreateNode('x'),
|
|
|
|
},
|
2023-03-19 18:46:39 +11:00
|
|
|
intersect: {
|
|
|
|
tooltip: 'angledLineThatIntersects',
|
|
|
|
createNode: setAngledIntersectForAngledLines,
|
|
|
|
},
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
free: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLine',
|
2023-03-10 08:48:50 +11:00
|
|
|
createNode: basicAngledLineCreateNode('len'),
|
2023-04-21 12:18:20 +10:00
|
|
|
},
|
|
|
|
setLength: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode: basicAngledLineCreateNode('none', 'len'),
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
vertical: {
|
|
|
|
tooltip: 'yLine',
|
|
|
|
createNode:
|
|
|
|
({ tag }) =>
|
|
|
|
(args) =>
|
|
|
|
createCallWrapper('yLine', args[1], tag),
|
|
|
|
},
|
|
|
|
horizontal: {
|
|
|
|
tooltip: 'xLine',
|
|
|
|
createNode:
|
|
|
|
({ tag }) =>
|
|
|
|
(args) =>
|
|
|
|
createCallWrapper('xLine', args[0], tag),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
length: {
|
|
|
|
vertical: {
|
|
|
|
tooltip: 'yLine',
|
|
|
|
createNode:
|
|
|
|
({ varValB, tag }) =>
|
|
|
|
([arg0]) => {
|
|
|
|
const val =
|
|
|
|
arg0.type === 'Literal' && Number(arg0.value) < 0
|
|
|
|
? createUnaryExpression(varValB as BinaryPart)
|
|
|
|
: varValB
|
|
|
|
return createCallWrapper('yLine', val, tag)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
horizontal: {
|
|
|
|
tooltip: 'xLine',
|
|
|
|
createNode:
|
|
|
|
({ varValB, tag }) =>
|
|
|
|
([arg0]) => {
|
|
|
|
const val =
|
|
|
|
arg0.type === 'Literal' && Number(arg0.value) < 0
|
|
|
|
? createUnaryExpression(varValB as BinaryPart)
|
|
|
|
: varValB
|
|
|
|
return createCallWrapper('xLine', val, tag)
|
|
|
|
},
|
|
|
|
},
|
2023-03-10 08:48:50 +11:00
|
|
|
setAngle: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode: basicAngledLineCreateNode('len', 'ang', 'len'),
|
|
|
|
},
|
2023-04-14 07:49:36 +10:00
|
|
|
equalAngle: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode: basicAngledLineCreateNode('ang', 'len', 'len'),
|
|
|
|
},
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
},
|
|
|
|
angledLineOfXLength: {
|
|
|
|
free: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLine',
|
2023-03-10 08:48:50 +11:00
|
|
|
createNode: basicAngledLineCreateNode('len'),
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
horizontal: {
|
|
|
|
tooltip: 'xLine',
|
|
|
|
createNode:
|
|
|
|
({ tag }) =>
|
|
|
|
(args) =>
|
|
|
|
createCallWrapper('xLine', args[0], tag),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
angle: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode: angledLineAngleCreateNode,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
xRelative: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLineOfXLength',
|
|
|
|
createNode: ({ referenceSegName, varValB, tag }) => {
|
|
|
|
const [minVal, legAngle] = getMinAndSegAngVals(
|
|
|
|
referenceSegName,
|
|
|
|
varValB
|
|
|
|
)
|
|
|
|
return (args) =>
|
|
|
|
createCallWrapper(
|
|
|
|
'angledLineOfXLength',
|
|
|
|
[getLegAng(args[0], legAngle), minVal],
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
horizontal: {
|
|
|
|
tooltip: 'xLine',
|
|
|
|
createNode:
|
|
|
|
({ varValB, tag }) =>
|
|
|
|
([arg0]) => {
|
|
|
|
const val =
|
|
|
|
arg0.type === 'Literal' && Number(arg0.value) < 0
|
|
|
|
? createUnaryExpression(varValB as BinaryPart)
|
|
|
|
: varValB
|
|
|
|
return createCallWrapper('xLine', val, tag)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
angledLineOfYLength: {
|
|
|
|
free: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLine',
|
2023-03-10 08:48:50 +11:00
|
|
|
createNode: basicAngledLineCreateNode('len'),
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
vertical: {
|
|
|
|
tooltip: 'yLine',
|
|
|
|
createNode:
|
|
|
|
({ tag }) =>
|
|
|
|
(args) =>
|
|
|
|
createCallWrapper('yLine', args[1], tag),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
angle: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode: angledLineAngleCreateNode,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
yRelative: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLineOfYLength',
|
|
|
|
createNode: ({ referenceSegName, varValB, tag }) => {
|
|
|
|
const [minVal, legAngle] = getMinAndSegAngVals(
|
|
|
|
referenceSegName,
|
|
|
|
varValB,
|
|
|
|
'legAngY'
|
|
|
|
)
|
|
|
|
return (args) =>
|
|
|
|
createCallWrapper(
|
|
|
|
'angledLineOfXLength',
|
|
|
|
[getLegAng(args[0], legAngle), minVal],
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
vertical: {
|
|
|
|
tooltip: 'yLine',
|
|
|
|
createNode:
|
|
|
|
({ varValB, tag }) =>
|
|
|
|
([arg0]) => {
|
|
|
|
const val =
|
|
|
|
arg0.type === 'Literal' && Number(arg0.value) < 0
|
|
|
|
? createUnaryExpression(varValB as BinaryPart)
|
|
|
|
: varValB
|
|
|
|
return createCallWrapper('yLine', val, tag)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
angledLineToX: {
|
|
|
|
free: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLine',
|
2023-03-10 08:48:50 +11:00
|
|
|
createNode: basicAngledLineCreateNode('len'),
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
horizontal: {
|
|
|
|
tooltip: 'xLineTo',
|
|
|
|
createNode:
|
|
|
|
({ tag }) =>
|
|
|
|
(args) =>
|
|
|
|
createCallWrapper('xLineTo', args[0], tag),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
angle: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode: angledLineAngleCreateNode,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
xAbsolute: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLineToX',
|
|
|
|
createNode:
|
|
|
|
({ referenceSegName, varValB, tag }) =>
|
|
|
|
(args) => {
|
|
|
|
const angleToMatchLengthXCall = createCallExpression(
|
|
|
|
'angleToMatchLengthX',
|
|
|
|
[
|
2024-06-24 22:39:04 -07:00
|
|
|
createIdentifier(referenceSegName),
|
2023-03-02 21:19:11 +11:00
|
|
|
varValB,
|
|
|
|
createPipeSubstitution(),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
return createCallWrapper(
|
|
|
|
'angledLineToX',
|
|
|
|
[getAngleLengthSign(args[0], angleToMatchLengthXCall), varValB],
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
horizontal: {
|
|
|
|
tooltip: 'xLineTo',
|
|
|
|
createNode:
|
|
|
|
({ varValB, tag }) =>
|
|
|
|
([arg0]) =>
|
|
|
|
createCallWrapper('xLineTo', varValB, tag),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
angledLineToY: {
|
|
|
|
free: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLine',
|
2023-03-10 08:48:50 +11:00
|
|
|
createNode: basicAngledLineCreateNode('len'),
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
vertical: {
|
|
|
|
tooltip: 'yLineTo',
|
|
|
|
createNode:
|
|
|
|
({ tag }) =>
|
|
|
|
(args) =>
|
|
|
|
createCallWrapper('yLineTo', args[1], tag),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
angle: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLine',
|
|
|
|
createNode: angledLineAngleCreateNode,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
yAbsolute: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'angledLineToY',
|
|
|
|
createNode:
|
|
|
|
({ referenceSegName, varValB, tag }) =>
|
|
|
|
(args) => {
|
|
|
|
const angleToMatchLengthXCall = createCallExpression(
|
|
|
|
'angleToMatchLengthY',
|
|
|
|
[
|
2024-06-24 22:39:04 -07:00
|
|
|
createIdentifier(referenceSegName),
|
2023-03-02 21:19:11 +11:00
|
|
|
varValB,
|
|
|
|
createPipeSubstitution(),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
return createCallWrapper(
|
|
|
|
'angledLineToY',
|
|
|
|
[getAngleLengthSign(args[0], angleToMatchLengthXCall), varValB],
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
vertical: {
|
|
|
|
tooltip: 'yLineTo',
|
|
|
|
createNode:
|
|
|
|
({ varValB, tag }) =>
|
|
|
|
() =>
|
|
|
|
createCallWrapper('yLineTo', varValB, tag),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
xLine: {
|
|
|
|
free: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'xLine',
|
|
|
|
createNode:
|
|
|
|
({ referenceSegName, tag }) =>
|
2023-03-10 14:55:16 +11:00
|
|
|
(arg) => {
|
|
|
|
const argVal = getArgLiteralVal(arg[0])
|
|
|
|
const segLen = createSegLen(referenceSegName) as BinaryPart
|
|
|
|
const val = argVal > 0 ? segLen : createUnaryExpression(segLen)
|
|
|
|
return createCallWrapper('xLine', val, tag, argVal)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
setHorzDistance: {
|
|
|
|
tooltip: 'xLineTo',
|
2023-03-17 21:15:46 +11:00
|
|
|
createNode: setHorVertDistanceForXYLines('x'),
|
2023-03-10 14:55:16 +11:00
|
|
|
},
|
|
|
|
setLength: {
|
|
|
|
tooltip: 'xLine',
|
|
|
|
createNode: xyLineSetLength('xLine'),
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
2023-03-19 18:46:39 +11:00
|
|
|
intersect: {
|
|
|
|
tooltip: 'angledLineThatIntersects',
|
|
|
|
createNode: setAngledIntersectLineForLines,
|
|
|
|
},
|
2023-04-05 15:08:46 +10:00
|
|
|
xAbs: {
|
|
|
|
tooltip: 'xLineTo',
|
|
|
|
createNode: setAbsDistanceCreateNode('x', true),
|
|
|
|
},
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
},
|
|
|
|
yLine: {
|
|
|
|
free: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'yLine',
|
|
|
|
createNode:
|
|
|
|
({ referenceSegName, tag }) =>
|
2023-04-02 09:34:56 +10:00
|
|
|
(arg) => {
|
|
|
|
const argVal = getArgLiteralVal(arg[0])
|
|
|
|
let segLen = createSegLen(referenceSegName) as BinaryPart
|
|
|
|
if (argVal < 0) segLen = createUnaryExpression(segLen)
|
|
|
|
return createCallWrapper('yLine', segLen, tag, argVal)
|
|
|
|
},
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
2023-03-10 14:55:16 +11:00
|
|
|
setLength: {
|
|
|
|
tooltip: 'yLine',
|
|
|
|
createNode: xyLineSetLength('yLine'),
|
|
|
|
},
|
2023-03-17 21:15:46 +11:00
|
|
|
setVertDistance: {
|
|
|
|
tooltip: 'yLineTo',
|
|
|
|
createNode: setHorVertDistanceForXYLines('y'),
|
|
|
|
},
|
2023-03-19 18:46:39 +11:00
|
|
|
intersect: {
|
|
|
|
tooltip: 'angledLineThatIntersects',
|
|
|
|
createNode: setAngledIntersectLineForLines,
|
|
|
|
},
|
2023-04-05 15:08:46 +10:00
|
|
|
yAbs: {
|
|
|
|
tooltip: 'yLineTo',
|
|
|
|
createNode: setAbsDistanceCreateNode('y', true),
|
|
|
|
},
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
},
|
|
|
|
xLineTo: {
|
|
|
|
free: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'xLine',
|
|
|
|
createNode:
|
|
|
|
({ referenceSegName, tag }) =>
|
|
|
|
() =>
|
|
|
|
createCallWrapper('xLine', createSegLen(referenceSegName), tag),
|
|
|
|
},
|
2023-03-17 21:15:46 +11:00
|
|
|
setLength: {
|
|
|
|
tooltip: 'xLine',
|
|
|
|
createNode: xyLineSetLength('xLine'),
|
|
|
|
},
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
},
|
|
|
|
yLineTo: {
|
|
|
|
free: {
|
|
|
|
equalLength: {
|
|
|
|
tooltip: 'yLine',
|
|
|
|
createNode:
|
|
|
|
({ referenceSegName, tag }) =>
|
|
|
|
() =>
|
|
|
|
createCallWrapper('yLine', createSegLen(referenceSegName), tag),
|
|
|
|
},
|
2023-03-17 21:15:46 +11:00
|
|
|
setLength: {
|
|
|
|
tooltip: 'yLine',
|
|
|
|
createNode: xyLineSetLength('yLine'),
|
|
|
|
},
|
2023-03-02 21:19:11 +11:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-03-22 03:02:37 +11:00
|
|
|
export function getRemoveConstraintsTransform(
|
|
|
|
sketchFnExp: CallExpression,
|
|
|
|
constraintType: ConstraintType
|
|
|
|
): TransformInfo | false {
|
2023-09-15 11:48:23 -04:00
|
|
|
let name = sketchFnExp.callee.name as ToolTip
|
2023-03-22 03:02:37 +11:00
|
|
|
if (!toolTips.includes(name)) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
const xyLineMap: {
|
2023-09-15 11:48:23 -04:00
|
|
|
[key in ToolTip]?: ToolTip
|
2023-03-22 03:02:37 +11:00
|
|
|
} = {
|
|
|
|
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],
|
2024-06-24 22:39:04 -07:00
|
|
|
// intersectTag: createIdentifier(referenceSegName),
|
2023-03-22 03:02:37 +11:00
|
|
|
// tag,
|
|
|
|
// })
|
|
|
|
// }
|
|
|
|
// return createCallWrapper(name, args, tag)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if the function is locked down and so can't be transformed
|
|
|
|
const firstArg = getFirstArg(sketchFnExp)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(firstArg)) {
|
|
|
|
console.error(firstArg)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-09-13 07:23:14 -07:00
|
|
|
if (isNotLiteralArrayOrStatic(firstArg.val)) {
|
|
|
|
return transformInfo
|
2023-03-22 03:02:37 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// check if the function has no constraints
|
|
|
|
const isTwoValFree =
|
2023-09-13 07:23:14 -07:00
|
|
|
Array.isArray(firstArg.val) && isLiteralArrayOrStatic(firstArg.val)
|
2023-03-22 03:02:37 +11:00
|
|
|
if (isTwoValFree) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
const isOneValFree =
|
2023-09-13 07:23:14 -07:00
|
|
|
!Array.isArray(firstArg.val) && isLiteralArrayOrStatic(firstArg.val)
|
2023-03-22 03:02:37 +11:00
|
|
|
if (isOneValFree) {
|
|
|
|
return transformInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
// check what constraints the function has
|
|
|
|
const lineInputType = getConstraintType(firstArg.val, name)
|
|
|
|
if (lineInputType) {
|
|
|
|
return transformInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
export function removeSingleConstraint({
|
|
|
|
pathToCallExp,
|
|
|
|
arrayIndex,
|
|
|
|
objectProperty,
|
|
|
|
ast,
|
|
|
|
}: {
|
|
|
|
pathToCallExp: PathToNode
|
|
|
|
arrayIndex?: number
|
|
|
|
objectProperty?: string
|
|
|
|
ast: Program
|
|
|
|
}): TransformInfo | false {
|
|
|
|
const callExp = getNodeFromPath<CallExpression>(
|
|
|
|
ast,
|
|
|
|
pathToCallExp,
|
|
|
|
'CallExpression'
|
2024-06-24 11:45:40 -04:00
|
|
|
)
|
|
|
|
if (err(callExp)) {
|
|
|
|
console.error(callExp)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if (callExp.node.type !== 'CallExpression') {
|
|
|
|
console.error(new Error('Invalid node type'))
|
|
|
|
return false
|
|
|
|
}
|
2024-05-24 20:54:42 +10:00
|
|
|
|
|
|
|
const transform: TransformInfo = {
|
2024-06-24 11:45:40 -04:00
|
|
|
tooltip: callExp.node.callee.name as any,
|
2024-05-24 20:54:42 +10:00
|
|
|
createNode:
|
|
|
|
({ tag, referenceSegName, varValues }) =>
|
|
|
|
(_, rawValues) => {
|
|
|
|
if (objectProperty) {
|
|
|
|
const expression: Parameters<typeof createObjectExpression>[0] = {}
|
|
|
|
varValues.forEach((varValue) => {
|
|
|
|
if (
|
|
|
|
varValue.type !== 'objectProperty' &&
|
|
|
|
varValue.type !== 'arrayOrObjItem'
|
|
|
|
)
|
|
|
|
return
|
|
|
|
const literal = rawValues.find(
|
|
|
|
(rawValue) =>
|
|
|
|
(rawValue.type === 'objectProperty' ||
|
|
|
|
rawValue.type === 'arrayOrObjItem') &&
|
|
|
|
rawValue.key === objectProperty
|
|
|
|
)?.value
|
|
|
|
const value =
|
|
|
|
(varValue.key === objectProperty && literal) || varValue.value
|
|
|
|
expression[varValue.key] = value
|
|
|
|
})
|
|
|
|
const objExp = createObjectExpression(expression)
|
|
|
|
return createStdlibCallExpression(
|
2024-06-24 11:45:40 -04:00
|
|
|
callExp.node.callee.name as any,
|
2024-05-24 20:54:42 +10:00
|
|
|
objExp,
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if (typeof arrayIndex === 'number') {
|
|
|
|
const values = varValues.map((varValue) => {
|
|
|
|
if (
|
|
|
|
(varValue.type === 'arrayItem' ||
|
|
|
|
varValue.type === 'arrayOrObjItem') &&
|
|
|
|
varValue.index === arrayIndex
|
|
|
|
) {
|
|
|
|
const literal = rawValues.find(
|
|
|
|
(rawValue) =>
|
|
|
|
(rawValue.type === 'arrayItem' ||
|
|
|
|
rawValue.type === 'arrayOrObjItem') &&
|
|
|
|
rawValue.index === arrayIndex
|
|
|
|
)?.value
|
|
|
|
return (
|
|
|
|
(varValue.index === arrayIndex && literal) || varValue.value
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return varValue.value
|
|
|
|
})
|
|
|
|
return createStdlibCallExpression(
|
2024-06-24 11:45:40 -04:00
|
|
|
callExp.node.callee.name as any,
|
2024-05-24 20:54:42 +10:00
|
|
|
createArrayExpression(values),
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// if (typeof arrayIndex !== 'number' || !objectProperty) must be single value input xLine, yLineTo etc
|
|
|
|
|
|
|
|
return createCallWrapper(
|
2024-06-24 11:45:40 -04:00
|
|
|
callExp.node.callee.name as any,
|
2024-05-24 20:54:42 +10:00
|
|
|
rawValues[0].value,
|
|
|
|
tag
|
|
|
|
)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return transform
|
|
|
|
}
|
|
|
|
|
2023-04-01 16:47:00 +11:00
|
|
|
function getTransformMapPath(
|
2023-03-02 21:19:11 +11:00
|
|
|
sketchFnExp: CallExpression,
|
|
|
|
constraintType: ConstraintType
|
|
|
|
):
|
|
|
|
| {
|
2023-09-15 11:48:23 -04:00
|
|
|
toolTip: ToolTip
|
2023-03-02 21:19:11 +11:00
|
|
|
lineInputType: LineInputsType | 'free'
|
|
|
|
constraintType: ConstraintType
|
|
|
|
}
|
|
|
|
| false {
|
2023-09-15 11:48:23 -04:00
|
|
|
const name = sketchFnExp.callee.name as ToolTip
|
2023-03-02 21:19:11 +11:00
|
|
|
if (!toolTips.includes(name)) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if the function is locked down and so can't be transformed
|
|
|
|
const firstArg = getFirstArg(sketchFnExp)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(firstArg)) {
|
|
|
|
console.error(firstArg)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-09-13 07:23:14 -07:00
|
|
|
if (isNotLiteralArrayOrStatic(firstArg.val)) {
|
|
|
|
return false
|
2023-03-02 21:19:11 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// check if the function has no constraints
|
2023-09-13 07:23:14 -07:00
|
|
|
if (isLiteralArrayOrStatic(firstArg.val)) {
|
2023-03-02 21:19:11 +11:00
|
|
|
const info = transformMap?.[name]?.free?.[constraintType]
|
|
|
|
if (info)
|
|
|
|
return {
|
|
|
|
toolTip: name,
|
|
|
|
lineInputType: 'free',
|
|
|
|
constraintType,
|
|
|
|
}
|
|
|
|
// if (info) return info
|
|
|
|
}
|
|
|
|
|
|
|
|
// check what constraints the function has
|
|
|
|
const lineInputType = getConstraintType(firstArg.val, name)
|
|
|
|
if (lineInputType) {
|
|
|
|
const info = transformMap?.[name]?.[lineInputType]?.[constraintType]
|
|
|
|
if (info)
|
|
|
|
return {
|
|
|
|
toolTip: name,
|
|
|
|
lineInputType,
|
|
|
|
constraintType,
|
|
|
|
}
|
|
|
|
// if (info) return info
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getTransformInfo(
|
|
|
|
sketchFnExp: CallExpression,
|
|
|
|
constraintType: ConstraintType
|
|
|
|
): TransformInfo | false {
|
|
|
|
const path = getTransformMapPath(sketchFnExp, constraintType)
|
|
|
|
if (!path) return false
|
|
|
|
const { toolTip, lineInputType, constraintType: _constraintType } = path
|
|
|
|
const info = transformMap?.[toolTip]?.[lineInputType]?.[_constraintType]
|
|
|
|
if (!info) return false
|
|
|
|
return info
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getConstraintType(
|
2023-04-03 16:05:25 +10:00
|
|
|
val: Value | [Value, Value] | [Value, Value, Value],
|
2023-09-15 11:48:23 -04:00
|
|
|
fnName: ToolTip
|
2023-03-02 21:19:11 +11:00
|
|
|
): LineInputsType | null {
|
|
|
|
// this function assumes that for two val sketch functions that one arg is locked down not both
|
|
|
|
// and for one val sketch functions that the arg is NOT locked down
|
|
|
|
// these conditions should have been checked previously.
|
|
|
|
// completely locked down or not locked down at all does not depend on the fnName so we can check that first
|
|
|
|
const isArr = Array.isArray(val)
|
|
|
|
if (!isArr) {
|
|
|
|
if (fnName === 'xLine') return 'yRelative'
|
|
|
|
if (fnName === 'yLine') return 'xRelative'
|
|
|
|
if (fnName === 'xLineTo') return 'yAbsolute'
|
|
|
|
if (fnName === 'yLineTo') return 'xAbsolute'
|
|
|
|
} else {
|
2023-09-13 07:23:14 -07:00
|
|
|
const isFirstArgLockedDown = isNotLiteralArrayOrStatic(val[0])
|
2023-03-02 21:19:11 +11:00
|
|
|
if (fnName === 'line')
|
|
|
|
return isFirstArgLockedDown ? 'xRelative' : 'yRelative'
|
|
|
|
if (fnName === 'lineTo')
|
|
|
|
return isFirstArgLockedDown ? 'xAbsolute' : 'yAbsolute'
|
|
|
|
if (fnName === 'angledLine')
|
|
|
|
return isFirstArgLockedDown ? 'angle' : 'length'
|
|
|
|
if (fnName === 'angledLineOfXLength')
|
|
|
|
return isFirstArgLockedDown ? 'angle' : 'xRelative'
|
|
|
|
if (fnName === 'angledLineToX')
|
|
|
|
return isFirstArgLockedDown ? 'angle' : 'xAbsolute'
|
|
|
|
if (fnName === 'angledLineOfYLength')
|
|
|
|
return isFirstArgLockedDown ? 'angle' : 'yRelative'
|
|
|
|
if (fnName === 'angledLineToY')
|
|
|
|
return isFirstArgLockedDown ? 'angle' : 'yAbsolute'
|
|
|
|
}
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getTransformInfos(
|
2023-04-03 16:05:25 +10:00
|
|
|
selectionRanges: Selections,
|
2023-03-02 21:19:11 +11:00
|
|
|
ast: Program,
|
|
|
|
constraintType: ConstraintType
|
|
|
|
): TransformInfo[] {
|
2023-04-03 16:05:25 +10:00
|
|
|
const paths = selectionRanges.codeBasedSelections.map(({ range }) =>
|
|
|
|
getNodePathFromSourceRange(ast, range)
|
2023-03-02 21:19:11 +11:00
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodes = paths.map((pathToNode) =>
|
|
|
|
getNodeFromPath<Value>(ast, pathToNode, 'CallExpression')
|
2023-03-02 21:19:11 +11:00
|
|
|
)
|
|
|
|
|
2023-04-02 17:20:11 +10:00
|
|
|
try {
|
2024-06-24 11:45:40 -04:00
|
|
|
const theTransforms = nodes.map((nodeMeta) => {
|
|
|
|
if (err(nodeMeta)) {
|
|
|
|
console.error(nodeMeta)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
const node = nodeMeta.node
|
2023-04-02 17:20:11 +10:00
|
|
|
if (node?.type === 'CallExpression')
|
|
|
|
return getTransformInfo(node, constraintType)
|
2023-03-02 21:19:11 +11:00
|
|
|
|
2023-04-02 17:20:11 +10:00
|
|
|
return false
|
|
|
|
}) as TransformInfo[]
|
|
|
|
return theTransforms
|
|
|
|
} catch (error) {
|
2023-09-25 17:28:03 +10:00
|
|
|
console.log('error', error)
|
2023-04-02 17:20:11 +10:00
|
|
|
return []
|
|
|
|
}
|
2023-03-02 21:19:11 +11:00
|
|
|
}
|
|
|
|
|
2023-03-22 03:02:37 +11:00
|
|
|
export function getRemoveConstraintsTransforms(
|
2023-04-03 16:05:25 +10:00
|
|
|
selectionRanges: Selections,
|
2023-03-22 03:02:37 +11:00
|
|
|
ast: Program,
|
|
|
|
constraintType: ConstraintType
|
2024-06-24 11:45:40 -04:00
|
|
|
): TransformInfo[] | Error {
|
2023-03-22 03:02:37 +11:00
|
|
|
// return ()
|
2023-04-03 16:05:25 +10:00
|
|
|
const paths = selectionRanges.codeBasedSelections.map((selectionRange) =>
|
|
|
|
getNodePathFromSourceRange(ast, selectionRange.range)
|
2023-03-22 03:02:37 +11:00
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodes = paths.map((pathToNode) =>
|
|
|
|
getNodeFromPath<Value>(ast, pathToNode)
|
2023-03-22 03:02:37 +11:00
|
|
|
)
|
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
const theTransforms = nodes.map((nodeMeta) => {
|
|
|
|
// Typescript is not smart enough to know node will never be Error
|
|
|
|
// here, but we'll place a condition anyway
|
|
|
|
if (err(nodeMeta)) {
|
|
|
|
console.error(nodeMeta)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
const node = nodeMeta.node
|
2023-03-22 03:02:37 +11:00
|
|
|
if (node?.type === 'CallExpression')
|
|
|
|
return getRemoveConstraintsTransform(node, constraintType)
|
|
|
|
|
|
|
|
return false
|
|
|
|
}) as TransformInfo[]
|
|
|
|
return theTransforms
|
|
|
|
}
|
|
|
|
|
2023-10-11 13:36:54 +11:00
|
|
|
export type PathToNodeMap = { [key: number]: PathToNode }
|
2023-04-14 07:49:36 +10:00
|
|
|
|
2023-03-07 15:45:59 +11:00
|
|
|
export function transformSecondarySketchLinesTagFirst({
|
2023-03-02 21:19:11 +11:00
|
|
|
ast,
|
|
|
|
selectionRanges,
|
|
|
|
transformInfos,
|
|
|
|
programMemory,
|
2023-03-07 15:45:59 +11:00
|
|
|
forceSegName,
|
|
|
|
forceValueUsedInTransform,
|
2023-03-02 21:19:11 +11:00
|
|
|
}: {
|
|
|
|
ast: Program
|
2023-04-03 16:05:25 +10:00
|
|
|
selectionRanges: Selections
|
2023-03-02 21:19:11 +11:00
|
|
|
transformInfos: TransformInfo[]
|
|
|
|
programMemory: ProgramMemory
|
2023-03-07 15:45:59 +11:00
|
|
|
forceSegName?: string
|
|
|
|
forceValueUsedInTransform?: Value
|
2024-06-24 11:45:40 -04:00
|
|
|
}):
|
|
|
|
| {
|
|
|
|
modifiedAst: Program
|
|
|
|
valueUsedInTransform?: number
|
|
|
|
pathToNodeMap: PathToNodeMap
|
|
|
|
tagInfo: {
|
|
|
|
tag: string
|
|
|
|
isTagExisting: boolean
|
|
|
|
}
|
|
|
|
}
|
|
|
|
| Error {
|
2023-03-07 15:45:59 +11:00
|
|
|
// let node = JSON.parse(JSON.stringify(ast))
|
2023-04-03 16:05:25 +10:00
|
|
|
const primarySelection = selectionRanges.codeBasedSelections[0].range
|
2023-03-02 21:19:11 +11:00
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
const _tag = giveSketchFnCallTag(ast, primarySelection, forceSegName)
|
|
|
|
if (err(_tag)) return _tag
|
|
|
|
const { modifiedAst, tag, isTagExisting, pathToNode } = _tag
|
2023-03-02 21:19:11 +11:00
|
|
|
|
2023-04-14 07:49:36 +10:00
|
|
|
const result = transformAstSketchLines({
|
|
|
|
ast: modifiedAst,
|
|
|
|
selectionRanges: {
|
|
|
|
...selectionRanges,
|
|
|
|
codeBasedSelections: selectionRanges.codeBasedSelections.slice(1),
|
|
|
|
},
|
|
|
|
referencedSegmentRange: primarySelection,
|
|
|
|
transformInfos,
|
|
|
|
programMemory,
|
|
|
|
referenceSegName: tag,
|
|
|
|
forceValueUsedInTransform,
|
|
|
|
})
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(result)) return result
|
|
|
|
|
2023-04-14 07:49:36 +10:00
|
|
|
const updatedPathToNodeMap = incrementPathToNodeMap(result.pathToNodeMap)
|
|
|
|
updatedPathToNodeMap[0] = pathToNode
|
|
|
|
|
2023-03-07 15:45:59 +11:00
|
|
|
return {
|
2023-04-14 07:49:36 +10:00
|
|
|
...result,
|
|
|
|
pathToNodeMap: updatedPathToNodeMap,
|
2023-03-07 15:45:59 +11:00
|
|
|
tagInfo: {
|
|
|
|
tag,
|
|
|
|
isTagExisting,
|
|
|
|
},
|
|
|
|
}
|
2023-03-02 21:19:11 +11:00
|
|
|
}
|
|
|
|
|
2023-04-14 07:49:36 +10:00
|
|
|
function incrementPathToNodeMap(
|
|
|
|
pathToNodeMap: PathToNodeMap,
|
|
|
|
increment = 1
|
|
|
|
): PathToNodeMap {
|
|
|
|
const newMap: PathToNodeMap = {}
|
|
|
|
Object.entries(pathToNodeMap).forEach(([key, path]) => {
|
|
|
|
newMap[Number(key) + increment] = path
|
|
|
|
})
|
|
|
|
return newMap
|
|
|
|
}
|
|
|
|
|
2023-03-07 15:45:59 +11:00
|
|
|
export function transformAstSketchLines({
|
2023-03-02 21:19:11 +11:00
|
|
|
ast,
|
|
|
|
selectionRanges,
|
|
|
|
transformInfos,
|
|
|
|
programMemory,
|
2023-03-07 15:45:59 +11:00
|
|
|
referenceSegName,
|
|
|
|
forceValueUsedInTransform,
|
2023-03-17 21:15:46 +11:00
|
|
|
referencedSegmentRange,
|
2023-03-02 21:19:11 +11:00
|
|
|
}: {
|
|
|
|
ast: Program
|
2024-05-24 20:54:42 +10:00
|
|
|
selectionRanges: Selections | PathToNode[]
|
2023-03-02 21:19:11 +11:00
|
|
|
transformInfos: TransformInfo[]
|
|
|
|
programMemory: ProgramMemory
|
2023-03-07 15:45:59 +11:00
|
|
|
referenceSegName: string
|
|
|
|
forceValueUsedInTransform?: Value
|
2023-04-03 16:05:25 +10:00
|
|
|
referencedSegmentRange?: Selection['range']
|
2024-06-24 11:45:40 -04:00
|
|
|
}):
|
|
|
|
| {
|
|
|
|
modifiedAst: Program
|
|
|
|
valueUsedInTransform?: number
|
|
|
|
pathToNodeMap: PathToNodeMap
|
|
|
|
}
|
|
|
|
| Error {
|
2023-03-02 21:19:11 +11:00
|
|
|
// deep clone since we are mutating in a loop, of which any could fail
|
|
|
|
let node = JSON.parse(JSON.stringify(ast))
|
2023-03-07 15:45:59 +11:00
|
|
|
let _valueUsedInTransform // TODO should this be an array?
|
2023-04-14 07:49:36 +10:00
|
|
|
const pathToNodeMap: PathToNodeMap = {}
|
2023-03-02 21:19:11 +11:00
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
const processSelection = (_pathToNode: PathToNode, index: number) => {
|
2023-03-07 15:45:59 +11:00
|
|
|
const callBack = transformInfos?.[index].createNode
|
2023-03-02 21:19:11 +11:00
|
|
|
const transformTo = transformInfos?.[index].tooltip
|
2024-05-24 20:54:42 +10:00
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
if (!callBack || !transformTo) return new Error('no callback helper')
|
2023-03-02 21:19:11 +11:00
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
const getNode = getNodeFromPathCurry(node, _pathToNode)
|
2023-03-07 15:45:59 +11:00
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
const callExp = getNode<CallExpression>('CallExpression')
|
|
|
|
if (err(callExp)) return callExp
|
|
|
|
const varDec = getNode<VariableDeclarator>('VariableDeclarator')
|
|
|
|
if (err(varDec)) return varDec
|
2023-03-07 15:45:59 +11:00
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
const firstArg = getFirstArg(callExp.node)
|
|
|
|
if (err(firstArg)) return firstArg
|
|
|
|
const callBackTag = callExp.node.arguments[2]
|
2023-03-22 03:02:37 +11:00
|
|
|
const _referencedSegmentNameVal =
|
2024-06-24 11:45:40 -04:00
|
|
|
callExp.node.arguments[0]?.type === 'ObjectExpression' &&
|
|
|
|
callExp.node.arguments[0].properties?.find(
|
2023-03-22 03:02:37 +11:00
|
|
|
(prop) => prop.key.name === 'intersectTag'
|
|
|
|
)?.value
|
|
|
|
const _referencedSegmentName =
|
|
|
|
referenceSegName ||
|
|
|
|
(_referencedSegmentNameVal &&
|
2024-06-24 22:39:04 -07:00
|
|
|
_referencedSegmentNameVal.type === 'Identifier' &&
|
|
|
|
String(_referencedSegmentNameVal.name)) ||
|
2023-03-22 03:02:37 +11:00
|
|
|
''
|
2024-06-24 11:45:40 -04:00
|
|
|
const { val } = firstArg
|
2023-03-02 21:19:11 +11:00
|
|
|
const [varValA, varValB] = Array.isArray(val) ? val : [val, val]
|
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
const varValues: VarValues = []
|
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
getConstraintInfo(callExp.node, '', _pathToNode).forEach((a) => {
|
2024-05-24 20:54:42 +10:00
|
|
|
if (
|
|
|
|
a.type === 'tangentialWithPrevious' ||
|
|
|
|
a.type === 'horizontal' ||
|
|
|
|
a.type === 'vertical'
|
|
|
|
)
|
|
|
|
return
|
2024-06-24 11:45:40 -04:00
|
|
|
|
|
|
|
const nodeMeta = getNodeFromPath<Value>(ast, a.pathToNode)
|
|
|
|
if (err(nodeMeta)) return
|
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
if (a?.argPosition?.type === 'arrayItem') {
|
|
|
|
varValues.push({
|
|
|
|
type: 'arrayItem',
|
|
|
|
index: a.argPosition.index,
|
2024-06-24 11:45:40 -04:00
|
|
|
value: nodeMeta.node,
|
2024-05-24 20:54:42 +10:00
|
|
|
argType: a.type,
|
|
|
|
})
|
|
|
|
} else if (a?.argPosition?.type === 'objectProperty') {
|
|
|
|
varValues.push({
|
|
|
|
type: 'objectProperty',
|
|
|
|
key: a.argPosition.key,
|
2024-06-24 11:45:40 -04:00
|
|
|
value: nodeMeta.node,
|
2024-05-24 20:54:42 +10:00
|
|
|
argType: a.type,
|
|
|
|
})
|
|
|
|
} else if (a?.argPosition?.type === 'singleValue') {
|
|
|
|
varValues.push({
|
|
|
|
type: 'singleValue',
|
|
|
|
argType: a.type,
|
2024-06-24 11:45:40 -04:00
|
|
|
value: nodeMeta.node,
|
2024-05-24 20:54:42 +10:00
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
const varName = varDec.node.id.name
|
2024-06-22 02:21:13 -07:00
|
|
|
let sketchGroup = programMemory.root?.[varName]
|
|
|
|
if (sketchGroup.type === 'ExtrudeGroup') {
|
|
|
|
sketchGroup = sketchGroup.sketchGroup
|
|
|
|
}
|
2023-09-12 18:10:27 -07:00
|
|
|
if (!sketchGroup || sketchGroup.type !== 'SketchGroup')
|
2024-06-24 11:45:40 -04:00
|
|
|
return new Error('not a sketch group')
|
|
|
|
const segMeta = getSketchSegmentFromPathToNode(
|
2024-05-24 20:54:42 +10:00
|
|
|
sketchGroup,
|
|
|
|
ast,
|
|
|
|
_pathToNode
|
2023-04-14 07:49:36 +10:00
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(segMeta)) return segMeta
|
|
|
|
|
|
|
|
const seg = segMeta.segment
|
|
|
|
let referencedSegment
|
|
|
|
if (referencedSegmentRange) {
|
|
|
|
const _segment = getSketchSegmentFromSourceRange(
|
|
|
|
sketchGroup,
|
|
|
|
referencedSegmentRange
|
|
|
|
)
|
|
|
|
if (err(_segment)) return _segment
|
|
|
|
referencedSegment = _segment.segment
|
|
|
|
} else {
|
|
|
|
referencedSegment = sketchGroup.value.find(
|
2024-06-24 14:45:07 -07:00
|
|
|
(path) => path.tag?.value === _referencedSegmentName
|
2024-06-24 11:45:40 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
const { to, from } = seg
|
|
|
|
const replacedSketchLine = replaceSketchLine({
|
|
|
|
node: node,
|
|
|
|
programMemory,
|
|
|
|
pathToNode: _pathToNode,
|
|
|
|
referencedSegment,
|
|
|
|
fnName: transformTo || (callExp.node.callee.name as ToolTip),
|
|
|
|
to,
|
|
|
|
from,
|
|
|
|
createCallback: callBack({
|
|
|
|
referenceSegName: _referencedSegmentName,
|
|
|
|
varValues,
|
|
|
|
varValA,
|
|
|
|
varValB,
|
|
|
|
tag: callBackTag,
|
|
|
|
forceValueUsedInTransform,
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
if (err(replacedSketchLine)) return replacedSketchLine
|
2023-03-07 15:45:59 +11:00
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
const { modifiedAst, valueUsedInTransform, pathToNode } = replacedSketchLine
|
2023-03-02 21:19:11 +11:00
|
|
|
node = modifiedAst
|
2023-04-14 07:49:36 +10:00
|
|
|
pathToNodeMap[index] = pathToNode
|
2023-03-07 15:45:59 +11:00
|
|
|
if (typeof valueUsedInTransform === 'number') {
|
|
|
|
_valueUsedInTransform = valueUsedInTransform
|
|
|
|
}
|
2024-05-24 20:54:42 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
if ('codeBasedSelections' in selectionRanges) {
|
2024-06-24 11:45:40 -04:00
|
|
|
// If the processing of any of the selections failed, return the first error
|
|
|
|
const maybeProcessErrors = selectionRanges.codeBasedSelections
|
|
|
|
.map(({ range }, index) =>
|
|
|
|
processSelection(getNodePathFromSourceRange(node, range), index)
|
|
|
|
)
|
|
|
|
.filter(err)
|
|
|
|
|
|
|
|
if (maybeProcessErrors.length) return maybeProcessErrors[0]
|
2024-05-24 20:54:42 +10:00
|
|
|
} else {
|
2024-06-24 11:45:40 -04:00
|
|
|
const maybeProcessErrors = selectionRanges.map(processSelection).filter(err)
|
|
|
|
if (maybeProcessErrors.length) return maybeProcessErrors[0]
|
2024-05-24 20:54:42 +10:00
|
|
|
}
|
|
|
|
|
2023-04-14 07:49:36 +10:00
|
|
|
return {
|
|
|
|
modifiedAst: node,
|
|
|
|
valueUsedInTransform: _valueUsedInTransform,
|
|
|
|
pathToNodeMap,
|
|
|
|
}
|
2023-03-02 21:19:11 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
function createSegLen(referenceSegName: string): Value {
|
|
|
|
return createCallExpression('segLen', [
|
2024-06-24 22:39:04 -07:00
|
|
|
createIdentifier(referenceSegName),
|
2023-03-02 21:19:11 +11:00
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
}
|
2023-03-05 07:34:56 +11:00
|
|
|
|
2023-03-10 08:48:50 +11:00
|
|
|
function createSegAngle(referenceSegName: string): Value {
|
2023-03-17 21:15:46 +11:00
|
|
|
return createCallExpression('segAng', [
|
2024-06-24 22:39:04 -07:00
|
|
|
createIdentifier(referenceSegName),
|
2023-03-10 08:48:50 +11:00
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
}
|
|
|
|
|
2023-03-05 07:34:56 +11:00
|
|
|
function createSegEnd(referenceSegName: string, isX: boolean): CallExpression {
|
|
|
|
return createCallExpression(isX ? 'segEndX' : 'segEndY', [
|
2024-06-24 22:39:04 -07:00
|
|
|
createIdentifier(referenceSegName),
|
2023-03-05 07:34:56 +11:00
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
}
|
|
|
|
|
|
|
|
function createLastSeg(isX: boolean): CallExpression {
|
|
|
|
return createCallExpression(isX ? 'lastSegX' : 'lastSegY', [
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
}
|
|
|
|
|
|
|
|
function getArgLiteralVal(arg: Value): number {
|
|
|
|
return arg?.type === 'Literal' ? Number(arg.value) : 0
|
|
|
|
}
|
2023-03-19 21:25:22 +11:00
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
export type ConstraintLevel = 'free' | 'partial' | 'full'
|
|
|
|
|
2023-03-19 21:25:22 +11:00
|
|
|
export function getConstraintLevelFromSourceRange(
|
2023-04-03 16:05:25 +10:00
|
|
|
cursorRange: Selection['range'],
|
2024-06-24 11:45:40 -04:00
|
|
|
ast: Program | Error
|
|
|
|
): Error | { range: [number, number]; level: ConstraintLevel } {
|
|
|
|
if (err(ast)) return ast
|
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(
|
2023-03-19 21:25:22 +11:00
|
|
|
ast,
|
2023-04-01 16:47:00 +11:00
|
|
|
getNodePathFromSourceRange(ast, cursorRange),
|
|
|
|
'CallExpression'
|
2023-03-19 21:25:22 +11:00
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
|
|
|
|
const { node: sketchFnExp } = nodeMeta
|
2023-09-15 11:48:23 -04:00
|
|
|
const name = sketchFnExp?.callee?.name as ToolTip
|
2024-02-11 12:59:00 +11:00
|
|
|
const range: [number, number] = [sketchFnExp.start, sketchFnExp.end]
|
|
|
|
if (!toolTips.includes(name)) return { level: 'free', range: range }
|
2023-03-19 21:25:22 +11:00
|
|
|
|
|
|
|
const firstArg = getFirstArg(sketchFnExp)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(firstArg)) return firstArg
|
2023-03-19 21:25:22 +11:00
|
|
|
|
|
|
|
// check if the function is fully constrained
|
2023-09-13 07:23:14 -07:00
|
|
|
if (isNotLiteralArrayOrStatic(firstArg.val)) {
|
2024-02-11 12:59:00 +11:00
|
|
|
return { level: 'full', range: range }
|
2023-03-19 21:25:22 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// check if the function has no constraints
|
|
|
|
const isTwoValFree =
|
2023-09-13 07:23:14 -07:00
|
|
|
Array.isArray(firstArg.val) && isLiteralArrayOrStatic(firstArg.val)
|
2023-03-19 21:25:22 +11:00
|
|
|
const isOneValFree =
|
2023-09-13 07:23:14 -07:00
|
|
|
!Array.isArray(firstArg.val) && isLiteralArrayOrStatic(firstArg.val)
|
2023-03-19 21:25:22 +11:00
|
|
|
|
2024-02-11 12:59:00 +11:00
|
|
|
if (isTwoValFree) return { level: 'free', range: range }
|
|
|
|
if (isOneValFree) return { level: 'partial', range: range }
|
2023-03-19 21:25:22 +11:00
|
|
|
|
2024-02-11 12:59:00 +11:00
|
|
|
return { level: 'partial', range: range }
|
2023-03-19 21:25:22 +11:00
|
|
|
}
|
2023-09-13 07:23:14 -07:00
|
|
|
|
|
|
|
export function isLiteralArrayOrStatic(
|
|
|
|
val: Value | [Value, Value] | [Value, Value, Value] | undefined
|
|
|
|
): boolean {
|
|
|
|
if (!val) return false
|
|
|
|
|
|
|
|
if (Array.isArray(val)) {
|
Remove just one enum (#1096)
# Problem
This is my proposal for fixing #1107 . I've only done it for one stdlib function, `tangentialArcTo` -- if y'all like it, I'll apply this idea to the rest of the stdlib.
Previously, if users want to put a tag on the arc, the function's parameters change type.
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is object
tangentialArcTo({to: [x, y], tag: "myTag"}, %)
```
# Solution
My proposal in #1006 is that KCL should have optional values. This means we can change the stdlib `tangentialArcTo` function to use them. In this PR, the calls are now like
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is array still, but we now pass a tag at the end.
tangentialArcTo([x, y], %, "myTag")
```
This adds an "option" type to KCL typesystem, but it's not really revealed to users (no KCL types are revealed to users right now, they write untyped code and only interact with types when they get type errors upon executing programs). Also adds a None type, which is the default case of the Optional enum.
2023-12-18 23:49:32 -06:00
|
|
|
const a = val[0]
|
|
|
|
const b = val[1]
|
2023-09-13 07:23:14 -07:00
|
|
|
return isLiteralArrayOrStatic(a) && isLiteralArrayOrStatic(b)
|
|
|
|
}
|
|
|
|
return (
|
|
|
|
val.type === 'Literal' ||
|
|
|
|
(val.type === 'UnaryExpression' && val.argument.type === 'Literal')
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isNotLiteralArrayOrStatic(
|
|
|
|
val: Value | [Value, Value] | [Value, Value, Value]
|
|
|
|
): boolean {
|
|
|
|
if (Array.isArray(val)) {
|
Remove just one enum (#1096)
# Problem
This is my proposal for fixing #1107 . I've only done it for one stdlib function, `tangentialArcTo` -- if y'all like it, I'll apply this idea to the rest of the stdlib.
Previously, if users want to put a tag on the arc, the function's parameters change type.
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is object
tangentialArcTo({to: [x, y], tag: "myTag"}, %)
```
# Solution
My proposal in #1006 is that KCL should have optional values. This means we can change the stdlib `tangentialArcTo` function to use them. In this PR, the calls are now like
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is array still, but we now pass a tag at the end.
tangentialArcTo([x, y], %, "myTag")
```
This adds an "option" type to KCL typesystem, but it's not really revealed to users (no KCL types are revealed to users right now, they write untyped code and only interact with types when they get type errors upon executing programs). Also adds a None type, which is the default case of the Optional enum.
2023-12-18 23:49:32 -06:00
|
|
|
const a = val[0]
|
|
|
|
const b = val[1]
|
2023-09-13 07:23:14 -07:00
|
|
|
return isNotLiteralArrayOrStatic(a) && isNotLiteralArrayOrStatic(b)
|
|
|
|
}
|
|
|
|
return (
|
|
|
|
(val.type !== 'Literal' && val.type !== 'UnaryExpression') ||
|
|
|
|
(val.type === 'UnaryExpression' && val.argument.type !== 'Literal')
|
|
|
|
)
|
|
|
|
}
|