2023-02-21 10:50:45 +11:00
|
|
|
import {
|
|
|
|
ProgramMemory,
|
|
|
|
Path,
|
|
|
|
SketchGroup,
|
|
|
|
SourceRange,
|
|
|
|
PathToNode,
|
2023-02-12 10:56:45 +11:00
|
|
|
Program,
|
|
|
|
PipeExpression,
|
|
|
|
CallExpression,
|
|
|
|
VariableDeclarator,
|
2024-08-12 15:38:42 -05:00
|
|
|
Expr,
|
2023-02-12 10:56:45 +11:00
|
|
|
Literal,
|
2023-03-19 18:46:39 +11:00
|
|
|
VariableDeclaration,
|
2024-06-24 22:39:04 -07:00
|
|
|
Identifier,
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
sketchGroupFromKclValue,
|
2024-05-24 20:54:42 +10:00
|
|
|
} from 'lang/wasm'
|
2023-03-03 20:35:48 +11:00
|
|
|
import {
|
|
|
|
getNodeFromPath,
|
|
|
|
getNodeFromPathCurry,
|
|
|
|
getNodePathFromSourceRange,
|
2024-05-24 20:54:42 +10:00
|
|
|
} from 'lang/queryAst'
|
|
|
|
import {
|
|
|
|
LineInputsType,
|
|
|
|
isLiteralArrayOrStatic,
|
|
|
|
isNotLiteralArrayOrStatic,
|
|
|
|
} from 'lang/std/sketchcombos'
|
2024-07-02 17:16:27 +10:00
|
|
|
import { toolTips, ToolTip } from 'lang/langHelpers'
|
2024-06-30 04:53:47 +10:00
|
|
|
import { createPipeExpression, splitPathAtPipeExpression } from '../modifyAst'
|
2023-02-12 10:56:45 +11:00
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
import {
|
|
|
|
SketchLineHelper,
|
|
|
|
TransformCallback,
|
|
|
|
ConstrainInfo,
|
|
|
|
RawValues,
|
|
|
|
ArrayItemInput,
|
|
|
|
ObjectPropertyInput,
|
|
|
|
SingleValueInput,
|
|
|
|
VarValueKeys,
|
|
|
|
ArrayOrObjItemInput,
|
2024-07-15 19:20:32 +10:00
|
|
|
AddTagInfo,
|
2024-05-24 20:54:42 +10:00
|
|
|
} from 'lang/std/stdTypes'
|
2023-02-12 10:56:45 +11:00
|
|
|
|
|
|
|
import {
|
|
|
|
createLiteral,
|
2024-06-24 22:39:04 -07:00
|
|
|
createTagDeclarator,
|
2023-02-12 10:56:45 +11:00
|
|
|
createCallExpression,
|
|
|
|
createArrayExpression,
|
|
|
|
createPipeSubstitution,
|
|
|
|
createObjectExpression,
|
|
|
|
mutateArrExp,
|
|
|
|
mutateObjExpProp,
|
|
|
|
findUniqueName,
|
2024-05-24 20:54:42 +10:00
|
|
|
} from 'lang/modifyAst'
|
|
|
|
import { roundOff, getLength, getAngle } from 'lib/utils'
|
2024-06-24 11:45:40 -04:00
|
|
|
import { err } from 'lib/trap'
|
2023-08-24 17:28:59 -07:00
|
|
|
import { perpendicularDistance } from 'sketch-helpers'
|
2024-06-24 22:39:04 -07:00
|
|
|
import { TagDeclarator } from 'wasm-lib/kcl/bindings/TagDeclarator'
|
2023-02-12 10:56:45 +11:00
|
|
|
|
|
|
|
export type Coords2d = [number, number]
|
|
|
|
|
|
|
|
export function getCoordsFromPaths(skGroup: SketchGroup, index = 0): Coords2d {
|
|
|
|
const currentPath = skGroup?.value?.[index]
|
|
|
|
if (!currentPath && skGroup?.start) {
|
2023-03-17 08:27:40 +11:00
|
|
|
return skGroup.start.to
|
2023-02-12 10:56:45 +11:00
|
|
|
} else if (!currentPath) {
|
|
|
|
return [0, 0]
|
|
|
|
}
|
2024-02-11 12:59:00 +11:00
|
|
|
if (currentPath.type === 'ToPoint') {
|
2023-02-12 10:56:45 +11:00
|
|
|
return [currentPath.to[0], currentPath.to[1]]
|
|
|
|
}
|
|
|
|
return [0, 0]
|
|
|
|
}
|
|
|
|
|
2023-03-02 21:19:11 +11:00
|
|
|
export function createFirstArg(
|
2023-09-15 11:48:23 -04:00
|
|
|
sketchFn: ToolTip,
|
2024-08-12 15:38:42 -05:00
|
|
|
val: Expr | [Expr, Expr] | [Expr, Expr, Expr]
|
|
|
|
): Expr | Error {
|
2023-02-21 10:50:45 +11:00
|
|
|
if (Array.isArray(val)) {
|
|
|
|
if (
|
2024-03-15 17:03:42 -04:00
|
|
|
[
|
|
|
|
'angledLine',
|
|
|
|
'angledLineOfXLength',
|
|
|
|
'angledLineOfYLength',
|
|
|
|
'angledLineToX',
|
|
|
|
'angledLineToY',
|
|
|
|
'line',
|
|
|
|
'lineTo',
|
|
|
|
].includes(sketchFn)
|
2023-02-21 10:50:45 +11:00
|
|
|
)
|
2024-03-15 17:03:42 -04:00
|
|
|
return createArrayExpression(val)
|
2023-04-03 16:05:25 +10:00
|
|
|
if (['angledLineThatIntersects'].includes(sketchFn) && val[2])
|
|
|
|
return createObjectExpression({
|
|
|
|
angle: val[0],
|
|
|
|
offset: val[1],
|
|
|
|
intersectTag: val[2],
|
|
|
|
})
|
2023-02-21 10:50:45 +11:00
|
|
|
} else {
|
2024-03-15 17:03:42 -04:00
|
|
|
if (
|
|
|
|
['startSketchAt', 'xLine', 'xLineTo', 'yLine', 'yLineTo'].includes(
|
|
|
|
sketchFn
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return val
|
2023-02-21 10:50:45 +11:00
|
|
|
}
|
2024-06-24 11:45:40 -04:00
|
|
|
return new Error('Missing sketch line type')
|
2023-02-21 10:50:45 +11:00
|
|
|
}
|
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
type AbbreviatedInput =
|
|
|
|
| ArrayItemInput<any>['index']
|
|
|
|
| ObjectPropertyInput<any>['key']
|
|
|
|
| SingleValueInput<any>['type']
|
|
|
|
| undefined
|
|
|
|
|
|
|
|
const constrainInfo = (
|
|
|
|
a: ConstrainInfo['type'],
|
|
|
|
b: ConstrainInfo['isConstrained'],
|
|
|
|
c: ConstrainInfo['value'],
|
|
|
|
f: ConstrainInfo['stdLibFnName'],
|
|
|
|
g: AbbreviatedInput,
|
|
|
|
d: ConstrainInfo['sourceRange'],
|
|
|
|
e: ConstrainInfo['pathToNode']
|
|
|
|
): ConstrainInfo => ({
|
|
|
|
type: a,
|
|
|
|
isConstrained: b,
|
|
|
|
value: c,
|
|
|
|
sourceRange: d,
|
|
|
|
argPosition:
|
|
|
|
g === 'singleValue'
|
|
|
|
? { type: 'singleValue' }
|
|
|
|
: typeof g === 'number'
|
|
|
|
? { type: 'arrayItem', index: g }
|
|
|
|
: typeof g === 'string'
|
|
|
|
? { type: 'objectProperty', key: g }
|
|
|
|
: undefined,
|
|
|
|
pathToNode: e,
|
|
|
|
stdLibFnName: f,
|
|
|
|
})
|
|
|
|
|
|
|
|
const commonConstraintInfoHelper = (
|
|
|
|
callExp: CallExpression,
|
|
|
|
inputConstrainTypes: [ConstrainInfo['type'], ConstrainInfo['type']],
|
|
|
|
stdLibFnName: ConstrainInfo['stdLibFnName'],
|
|
|
|
abbreviatedInputs: [
|
|
|
|
{
|
|
|
|
arrayInput?: 0 | 1
|
|
|
|
objInput?: ObjectPropertyInput<any>['key']
|
|
|
|
},
|
|
|
|
{
|
|
|
|
arrayInput?: 0 | 1
|
|
|
|
objInput?: ObjectPropertyInput<any>['key']
|
|
|
|
}
|
|
|
|
],
|
|
|
|
code: string,
|
|
|
|
pathToNode: PathToNode
|
|
|
|
) => {
|
|
|
|
if (callExp.type !== 'CallExpression') return []
|
|
|
|
const firstArg = callExp.arguments?.[0]
|
|
|
|
const isArr = firstArg.type === 'ArrayExpression'
|
|
|
|
if (!isArr && firstArg.type !== 'ObjectExpression') return []
|
|
|
|
const pathToArrayExpression: PathToNode = [
|
|
|
|
...pathToNode,
|
|
|
|
['arguments', 'CallExpression'],
|
|
|
|
[0, 'index'],
|
|
|
|
isArr
|
|
|
|
? ['elements', 'ArrayExpression']
|
|
|
|
: ['properties', 'ObjectExpression'],
|
|
|
|
]
|
|
|
|
const pathToFirstArg: PathToNode = isArr
|
|
|
|
? [...pathToArrayExpression, [0, 'index']]
|
|
|
|
: [
|
|
|
|
...pathToArrayExpression,
|
|
|
|
[
|
|
|
|
firstArg.properties.findIndex(
|
|
|
|
(a) => a.key.name === abbreviatedInputs[0].objInput
|
|
|
|
),
|
|
|
|
'index',
|
|
|
|
],
|
|
|
|
['value', 'Property'],
|
|
|
|
]
|
|
|
|
|
|
|
|
const pathToSecondArg: PathToNode = isArr
|
|
|
|
? [...pathToArrayExpression, [1, 'index']]
|
|
|
|
: [
|
|
|
|
...pathToArrayExpression,
|
|
|
|
[
|
|
|
|
firstArg.properties.findIndex(
|
|
|
|
(a) => a.key.name === abbreviatedInputs[1].objInput
|
|
|
|
),
|
|
|
|
'index',
|
|
|
|
],
|
|
|
|
['value', 'Property'],
|
|
|
|
]
|
|
|
|
|
|
|
|
const input1 = isArr
|
|
|
|
? firstArg.elements[0]
|
|
|
|
: firstArg.properties.find(
|
|
|
|
(a) => a.key.name === abbreviatedInputs[0].objInput
|
|
|
|
)?.value
|
|
|
|
const input2 = isArr
|
|
|
|
? firstArg.elements[1]
|
|
|
|
: firstArg.properties.find(
|
|
|
|
(a) => a.key.name === abbreviatedInputs[1].objInput
|
|
|
|
)?.value
|
|
|
|
|
|
|
|
const constraints: ConstrainInfo[] = []
|
|
|
|
if (input1)
|
|
|
|
constraints.push(
|
|
|
|
constrainInfo(
|
|
|
|
inputConstrainTypes[0],
|
|
|
|
isNotLiteralArrayOrStatic(input1),
|
|
|
|
code.slice(input1.start, input1.end),
|
|
|
|
stdLibFnName,
|
|
|
|
isArr ? abbreviatedInputs[0].arrayInput : abbreviatedInputs[0].objInput,
|
|
|
|
[input1.start, input1.end],
|
|
|
|
pathToFirstArg
|
|
|
|
)
|
|
|
|
)
|
|
|
|
if (input2)
|
|
|
|
constraints.push(
|
|
|
|
constrainInfo(
|
|
|
|
inputConstrainTypes[1],
|
|
|
|
isNotLiteralArrayOrStatic(input2),
|
|
|
|
code.slice(input2.start, input2.end),
|
|
|
|
stdLibFnName,
|
|
|
|
isArr ? abbreviatedInputs[1].arrayInput : abbreviatedInputs[1].objInput,
|
|
|
|
[input2.start, input2.end],
|
|
|
|
pathToSecondArg
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
return constraints
|
|
|
|
}
|
|
|
|
|
|
|
|
const horzVertConstraintInfoHelper = (
|
|
|
|
callExp: CallExpression,
|
|
|
|
inputConstrainTypes: [ConstrainInfo['type'], ConstrainInfo['type']],
|
|
|
|
stdLibFnName: ConstrainInfo['stdLibFnName'],
|
|
|
|
abbreviatedInput: AbbreviatedInput,
|
|
|
|
code: string,
|
|
|
|
pathToNode: PathToNode
|
|
|
|
) => {
|
|
|
|
if (callExp.type !== 'CallExpression') return []
|
|
|
|
const firstArg = callExp.arguments?.[0]
|
|
|
|
const callee = callExp.callee
|
|
|
|
const pathToFirstArg: PathToNode = [
|
|
|
|
...pathToNode,
|
|
|
|
['arguments', 'CallExpression'],
|
|
|
|
[0, 'index'],
|
|
|
|
]
|
|
|
|
const pathToCallee: PathToNode = [...pathToNode, ['callee', 'CallExpression']]
|
|
|
|
return [
|
|
|
|
constrainInfo(
|
|
|
|
inputConstrainTypes[0],
|
|
|
|
true,
|
|
|
|
callee.name,
|
|
|
|
stdLibFnName,
|
|
|
|
undefined,
|
|
|
|
[callee.start, callee.end],
|
|
|
|
pathToCallee
|
|
|
|
),
|
|
|
|
constrainInfo(
|
|
|
|
inputConstrainTypes[1],
|
|
|
|
isNotLiteralArrayOrStatic(callExp.arguments?.[0]),
|
|
|
|
code.slice(firstArg.start, firstArg.end),
|
|
|
|
stdLibFnName,
|
|
|
|
abbreviatedInput,
|
|
|
|
[firstArg.start, firstArg.end],
|
|
|
|
pathToFirstArg
|
|
|
|
),
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
function arrayRawValuesHelper(a: Array<[Literal, LineInputsType]>): RawValues {
|
|
|
|
return a.map(
|
|
|
|
([literal, argType], index): ArrayItemInput<Literal> => ({
|
|
|
|
type: 'arrayItem',
|
|
|
|
index: index === 0 ? 0 : 1,
|
|
|
|
argType,
|
|
|
|
value: literal,
|
|
|
|
})
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
function arrOrObjectRawValuesHelper(
|
|
|
|
a: Array<[Literal, LineInputsType, VarValueKeys]>
|
|
|
|
): RawValues {
|
|
|
|
return a.map(
|
|
|
|
([literal, argType, key], index): ArrayOrObjItemInput<Literal> => ({
|
|
|
|
type: 'arrayOrObjItem',
|
|
|
|
// key: argType,w
|
|
|
|
index: index === 0 ? 0 : 1,
|
|
|
|
key,
|
|
|
|
argType,
|
|
|
|
value: literal,
|
|
|
|
})
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
function singleRawValueHelper(
|
|
|
|
literal: Literal,
|
|
|
|
argType: LineInputsType
|
|
|
|
): RawValues {
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
type: 'singleValue',
|
|
|
|
argType,
|
|
|
|
value: literal,
|
|
|
|
},
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
2024-07-15 19:20:32 +10:00
|
|
|
function getTag(index = 2): SketchLineHelper['getTag'] {
|
|
|
|
return (callExp: CallExpression) => {
|
|
|
|
if (callExp.type !== 'CallExpression')
|
|
|
|
return new Error('Not a CallExpression')
|
|
|
|
const arg = callExp.arguments?.[index]
|
|
|
|
if (!arg) return new Error('No argument')
|
|
|
|
if (arg.type !== 'TagDeclarator')
|
|
|
|
return new Error('Tag not a TagDeclarator')
|
|
|
|
return arg.value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
export const lineTo: SketchLineHelper = {
|
2023-03-05 07:34:56 +11:00
|
|
|
add: ({
|
|
|
|
node,
|
|
|
|
pathToNode,
|
|
|
|
to,
|
|
|
|
createCallback,
|
|
|
|
replaceExisting,
|
|
|
|
referencedSegment,
|
|
|
|
}) => {
|
2023-02-12 10:56:45 +11:00
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<PipeExpression>(
|
2023-02-12 10:56:45 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'PipeExpression'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: pipe } = nodeMeta
|
2023-03-05 07:34:56 +11:00
|
|
|
|
2024-08-12 15:38:42 -05:00
|
|
|
const newVals: [Expr, Expr] = [
|
2023-03-05 07:34:56 +11:00
|
|
|
createLiteral(roundOff(to[0], 2)),
|
|
|
|
createLiteral(roundOff(to[1], 2)),
|
|
|
|
]
|
|
|
|
|
2023-03-07 15:45:59 +11:00
|
|
|
const newLine = createCallExpression('lineTo', [
|
|
|
|
createArrayExpression(newVals),
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
2023-04-01 16:47:00 +11:00
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
2023-03-07 15:45:59 +11:00
|
|
|
if (replaceExisting && createCallback) {
|
2023-03-10 08:48:50 +11:00
|
|
|
const { callExp, valueUsedInTransform } = createCallback(
|
|
|
|
newVals,
|
2024-05-24 20:54:42 +10:00
|
|
|
arrayRawValuesHelper([
|
|
|
|
[createLiteral(roundOff(to[0], 2)), 'xAbsolute'],
|
|
|
|
[createLiteral(roundOff(to[1], 2)), 'yAbsolute'],
|
|
|
|
]),
|
2023-03-10 08:48:50 +11:00
|
|
|
referencedSegment
|
|
|
|
)
|
|
|
|
pipe.body[callIndex] = callExp
|
2023-03-07 15:45:59 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
2023-03-10 08:48:50 +11:00
|
|
|
valueUsedInTransform: valueUsedInTransform,
|
2023-03-07 15:45:59 +11:00
|
|
|
}
|
2023-03-05 07:34:56 +11:00
|
|
|
} else {
|
|
|
|
pipe.body = [...pipe.body, newLine]
|
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
updateArgs: ({ node, pathToNode, to }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: callExpression } = nodeMeta
|
2023-02-12 10:56:45 +11:00
|
|
|
|
|
|
|
const toArrExp = createArrayExpression([
|
|
|
|
createLiteral(to[0]),
|
|
|
|
createLiteral(to[1]),
|
|
|
|
])
|
|
|
|
|
|
|
|
mutateArrExp(callExpression.arguments?.[0], toArrExp) ||
|
|
|
|
mutateObjExpProp(callExpression.arguments?.[0], toArrExp, 'to')
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-03-17 18:24:03 +11:00
|
|
|
addTag: addTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
getConstraintInfo: (callExp, ...args) =>
|
|
|
|
commonConstraintInfoHelper(
|
|
|
|
callExp,
|
|
|
|
['xAbsolute', 'yAbsolute'],
|
|
|
|
'lineTo',
|
|
|
|
[{ arrayInput: 0 }, { arrayInput: 1 }],
|
|
|
|
...args
|
|
|
|
),
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
export const line: SketchLineHelper = {
|
|
|
|
add: ({
|
|
|
|
node,
|
|
|
|
previousProgramMemory,
|
|
|
|
pathToNode,
|
|
|
|
to,
|
2023-03-02 21:19:11 +11:00
|
|
|
from,
|
|
|
|
replaceExisting,
|
2023-03-17 21:15:46 +11:00
|
|
|
referencedSegment,
|
2023-03-02 21:19:11 +11:00
|
|
|
createCallback,
|
2024-04-03 13:22:56 +11:00
|
|
|
spliceBetween,
|
2023-02-12 10:56:45 +11:00
|
|
|
}) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<PipeExpression | CallExpression>(
|
2023-02-12 10:56:45 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'PipeExpression'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: pipe } = nodeMeta
|
|
|
|
const nodeMeta2 = getNodeFromPath<VariableDeclarator>(
|
2023-02-12 10:56:45 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'VariableDeclarator'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(nodeMeta2)) return nodeMeta2
|
|
|
|
const { node: varDec } = nodeMeta2
|
2023-03-02 21:19:11 +11:00
|
|
|
|
|
|
|
const newXVal = createLiteral(roundOff(to[0] - from[0], 2))
|
|
|
|
const newYVal = createLiteral(roundOff(to[1] - from[1], 2))
|
|
|
|
|
2024-04-03 13:22:56 +11:00
|
|
|
if (spliceBetween && !createCallback && pipe.type === 'PipeExpression') {
|
|
|
|
const callExp = createCallExpression('line', [
|
|
|
|
createArrayExpression([newXVal, newYVal]),
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
const pathToNodeIndex = pathToNode.findIndex(
|
|
|
|
(x) => x[1] === 'PipeExpression'
|
|
|
|
)
|
|
|
|
const pipeIndex = pathToNode[pathToNodeIndex + 1][0]
|
|
|
|
if (typeof pipeIndex === 'undefined' || typeof pipeIndex === 'string') {
|
2024-06-24 11:45:40 -04:00
|
|
|
return new Error('pipeIndex is undefined')
|
2024-04-03 13:22:56 +11:00
|
|
|
}
|
|
|
|
pipe.body = [
|
|
|
|
...pipe.body.slice(0, pipeIndex),
|
|
|
|
callExp,
|
|
|
|
...pipe.body.slice(pipeIndex),
|
|
|
|
]
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-13 08:36:47 +10:00
|
|
|
if (replaceExisting && createCallback && pipe.type !== 'CallExpression') {
|
2023-04-01 16:47:00 +11:00
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
2023-03-17 21:15:46 +11:00
|
|
|
const { callExp, valueUsedInTransform } = createCallback(
|
|
|
|
[newXVal, newYVal],
|
2024-05-24 20:54:42 +10:00
|
|
|
arrayRawValuesHelper([
|
|
|
|
[createLiteral(roundOff(to[0] - from[0], 2)), 'xRelative'],
|
|
|
|
[createLiteral(roundOff(to[1] - from[1], 2)), 'yRelative'],
|
|
|
|
]),
|
2023-03-17 21:15:46 +11:00
|
|
|
referencedSegment
|
|
|
|
)
|
|
|
|
pipe.body[callIndex] = callExp
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
2024-06-24 11:45:40 -04:00
|
|
|
pathToNode: [...pathToNode],
|
2023-03-17 21:15:46 +11:00
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
2023-03-02 21:19:11 +11:00
|
|
|
}
|
|
|
|
|
2023-03-17 21:15:46 +11:00
|
|
|
const callExp = createCallExpression('line', [
|
|
|
|
createArrayExpression([newXVal, newYVal]),
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
2023-09-13 08:36:47 +10:00
|
|
|
if (pipe.type === 'PipeExpression') {
|
|
|
|
pipe.body = [...pipe.body, callExp]
|
2023-10-14 03:47:46 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode: [
|
|
|
|
...pathToNode,
|
|
|
|
['body', 'PipeExpression'],
|
|
|
|
[pipe.body.length - 1, 'CallExpression'],
|
|
|
|
],
|
|
|
|
}
|
2023-09-13 08:36:47 +10:00
|
|
|
} else {
|
|
|
|
varDec.init = createPipeExpression([varDec.init, callExp])
|
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
updateArgs: ({ node, pathToNode, to, from }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: callExpression } = nodeMeta
|
2023-02-12 10:56:45 +11:00
|
|
|
|
|
|
|
const toArrExp = createArrayExpression([
|
|
|
|
createLiteral(roundOff(to[0] - from[0], 2)),
|
|
|
|
createLiteral(roundOff(to[1] - from[1], 2)),
|
|
|
|
])
|
|
|
|
|
2023-09-13 08:36:47 +10:00
|
|
|
if (callExpression.arguments?.[0].type === 'ObjectExpression') {
|
2023-03-19 18:46:39 +11:00
|
|
|
mutateObjExpProp(callExpression.arguments?.[0], toArrExp, 'to')
|
2023-03-17 15:53:20 +11:00
|
|
|
} else {
|
2023-03-19 18:46:39 +11:00
|
|
|
mutateArrExp(callExpression.arguments?.[0], toArrExp)
|
2023-03-17 15:53:20 +11:00
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-03-17 18:24:03 +11:00
|
|
|
addTag: addTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
getConstraintInfo: (callExp, ...args) =>
|
|
|
|
commonConstraintInfoHelper(
|
|
|
|
callExp,
|
|
|
|
['xRelative', 'yRelative'],
|
|
|
|
'line',
|
|
|
|
[{ arrayInput: 0 }, { arrayInput: 1 }],
|
|
|
|
...args
|
|
|
|
),
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
export const xLineTo: SketchLineHelper = {
|
2023-02-21 10:50:45 +11:00
|
|
|
add: ({ node, pathToNode, to, replaceExisting, createCallback }) => {
|
2023-02-12 10:56:45 +11:00
|
|
|
const _node = { ...node }
|
2023-02-21 10:50:45 +11:00
|
|
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
2024-06-24 11:45:40 -04:00
|
|
|
const _node1 = getNode<PipeExpression>('PipeExpression')
|
|
|
|
if (err(_node1)) return _node1
|
|
|
|
const { node: pipe } = _node1
|
2023-02-21 10:50:45 +11:00
|
|
|
|
|
|
|
const newVal = createLiteral(roundOff(to[0], 2))
|
|
|
|
|
2023-03-17 21:15:46 +11:00
|
|
|
if (replaceExisting && createCallback) {
|
2023-04-01 16:47:00 +11:00
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
2024-05-24 20:54:42 +10:00
|
|
|
const { callExp, valueUsedInTransform } = createCallback(
|
|
|
|
[newVal, newVal],
|
|
|
|
singleRawValueHelper(newVal, 'xAbsolute')
|
|
|
|
)
|
2023-03-17 21:15:46 +11:00
|
|
|
pipe.body[callIndex] = callExp
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
2023-02-21 10:50:45 +11:00
|
|
|
}
|
2023-03-17 21:15:46 +11:00
|
|
|
const callExp = createCallExpression('xLineTo', [
|
|
|
|
newVal,
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
pipe.body = [...pipe.body, callExp]
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2023-03-19 18:46:39 +11:00
|
|
|
updateArgs: ({ node, pathToNode, to }) => {
|
2023-02-12 10:56:45 +11:00
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: callExpression } = nodeMeta
|
2023-02-12 10:56:45 +11:00
|
|
|
const newX = createLiteral(roundOff(to[0], 2))
|
2023-09-13 07:23:14 -07:00
|
|
|
if (isLiteralArrayOrStatic(callExpression.arguments?.[0])) {
|
2023-02-12 10:56:45 +11:00
|
|
|
callExpression.arguments[0] = newX
|
|
|
|
} else {
|
|
|
|
mutateObjExpProp(callExpression.arguments?.[0], newX, 'to')
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-03-17 18:24:03 +11:00
|
|
|
addTag: addTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
getConstraintInfo: (callExp, ...args) =>
|
|
|
|
horzVertConstraintInfoHelper(
|
|
|
|
callExp,
|
|
|
|
['horizontal', 'xAbsolute'],
|
|
|
|
'xLineTo',
|
|
|
|
'singleValue',
|
|
|
|
...args
|
|
|
|
),
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
export const yLineTo: SketchLineHelper = {
|
2023-02-21 10:50:45 +11:00
|
|
|
add: ({ node, pathToNode, to, replaceExisting, createCallback }) => {
|
2023-02-12 10:56:45 +11:00
|
|
|
const _node = { ...node }
|
2023-02-21 10:50:45 +11:00
|
|
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
2024-06-24 11:45:40 -04:00
|
|
|
const _node1 = getNode<PipeExpression>('PipeExpression')
|
|
|
|
if (err(_node1)) return _node1
|
|
|
|
const { node: pipe } = _node1
|
2023-02-21 10:50:45 +11:00
|
|
|
|
|
|
|
const newVal = createLiteral(roundOff(to[1], 2))
|
2023-03-17 21:15:46 +11:00
|
|
|
|
|
|
|
if (replaceExisting && createCallback) {
|
2023-04-01 16:47:00 +11:00
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
2024-05-24 20:54:42 +10:00
|
|
|
const { callExp, valueUsedInTransform } = createCallback(
|
|
|
|
[newVal, newVal],
|
|
|
|
singleRawValueHelper(newVal, 'yAbsolute')
|
|
|
|
)
|
2023-03-17 21:15:46 +11:00
|
|
|
pipe.body[callIndex] = callExp
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
2023-02-21 10:50:45 +11:00
|
|
|
}
|
2023-03-17 21:15:46 +11:00
|
|
|
const callExp = createCallExpression('yLineTo', [
|
|
|
|
newVal,
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
pipe.body = [...pipe.body, callExp]
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
updateArgs: ({ node, pathToNode, to, from }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: callExpression } = nodeMeta
|
2023-02-12 10:56:45 +11:00
|
|
|
const newY = createLiteral(roundOff(to[1], 2))
|
2023-09-13 07:23:14 -07:00
|
|
|
if (isLiteralArrayOrStatic(callExpression.arguments?.[0])) {
|
2023-02-12 10:56:45 +11:00
|
|
|
callExpression.arguments[0] = newY
|
|
|
|
} else {
|
|
|
|
mutateObjExpProp(callExpression.arguments?.[0], newY, 'to')
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-03-17 18:24:03 +11:00
|
|
|
addTag: addTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
getConstraintInfo: (callExp, ...args) =>
|
|
|
|
horzVertConstraintInfoHelper(
|
|
|
|
callExp,
|
|
|
|
['vertical', 'yAbsolute'],
|
|
|
|
'yLineTo',
|
|
|
|
'singleValue',
|
|
|
|
...args
|
|
|
|
),
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
export const xLine: SketchLineHelper = {
|
2023-02-21 10:50:45 +11:00
|
|
|
add: ({ node, pathToNode, to, from, replaceExisting, createCallback }) => {
|
2023-02-12 10:56:45 +11:00
|
|
|
const _node = { ...node }
|
2023-02-21 10:50:45 +11:00
|
|
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
2024-06-24 11:45:40 -04:00
|
|
|
const _node1 = getNode<PipeExpression>('PipeExpression')
|
|
|
|
if (err(_node1)) return _node1
|
|
|
|
const { node: pipe } = _node1
|
2023-02-21 10:50:45 +11:00
|
|
|
|
|
|
|
const newVal = createLiteral(roundOff(to[0] - from[0], 2))
|
|
|
|
const firstArg = newVal
|
2023-03-10 14:55:16 +11:00
|
|
|
|
|
|
|
if (replaceExisting && createCallback) {
|
2023-04-01 16:47:00 +11:00
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
2024-05-24 20:54:42 +10:00
|
|
|
const { callExp, valueUsedInTransform } = createCallback(
|
|
|
|
[firstArg, firstArg],
|
|
|
|
singleRawValueHelper(firstArg, 'xRelative')
|
|
|
|
)
|
2023-03-10 14:55:16 +11:00
|
|
|
pipe.body[callIndex] = callExp
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
2023-03-10 14:55:16 +11:00
|
|
|
|
|
|
|
const newLine = createCallExpression('xLine', [
|
|
|
|
firstArg,
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
pipe.body = [...pipe.body, newLine]
|
2023-02-21 10:50:45 +11:00
|
|
|
return { modifiedAst: _node, pathToNode }
|
2023-02-12 10:56:45 +11:00
|
|
|
},
|
|
|
|
updateArgs: ({ node, pathToNode, to, from }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: callExpression } = nodeMeta
|
2023-02-12 10:56:45 +11:00
|
|
|
const newX = createLiteral(roundOff(to[0] - from[0], 2))
|
2023-09-13 07:23:14 -07:00
|
|
|
if (isLiteralArrayOrStatic(callExpression.arguments?.[0])) {
|
2023-02-12 10:56:45 +11:00
|
|
|
callExpression.arguments[0] = newX
|
|
|
|
} else {
|
|
|
|
mutateObjExpProp(callExpression.arguments?.[0], newX, 'length')
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-03-17 18:24:03 +11:00
|
|
|
addTag: addTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
getConstraintInfo: (callExp, ...args) =>
|
|
|
|
horzVertConstraintInfoHelper(
|
|
|
|
callExp,
|
|
|
|
['horizontal', 'xRelative'],
|
|
|
|
'xLine',
|
|
|
|
'singleValue',
|
|
|
|
...args
|
|
|
|
),
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
export const yLine: SketchLineHelper = {
|
2023-02-21 10:50:45 +11:00
|
|
|
add: ({ node, pathToNode, to, from, replaceExisting, createCallback }) => {
|
2023-02-12 10:56:45 +11:00
|
|
|
const _node = { ...node }
|
2023-02-21 10:50:45 +11:00
|
|
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
2024-06-24 11:45:40 -04:00
|
|
|
const _node1 = getNode<PipeExpression>('PipeExpression')
|
|
|
|
if (err(_node1)) return _node1
|
|
|
|
const { node: pipe } = _node1
|
2023-02-21 10:50:45 +11:00
|
|
|
const newVal = createLiteral(roundOff(to[1] - from[1], 2))
|
2023-03-10 14:55:16 +11:00
|
|
|
if (replaceExisting && createCallback) {
|
2023-04-01 16:47:00 +11:00
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
2024-05-24 20:54:42 +10:00
|
|
|
const { callExp, valueUsedInTransform } = createCallback(
|
|
|
|
[newVal, newVal],
|
|
|
|
singleRawValueHelper(newVal, 'yRelative')
|
|
|
|
)
|
2023-03-10 14:55:16 +11:00
|
|
|
pipe.body[callIndex] = callExp
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
2023-03-10 14:55:16 +11:00
|
|
|
|
|
|
|
const newLine = createCallExpression('yLine', [
|
|
|
|
newVal,
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
pipe.body = [...pipe.body, newLine]
|
2023-02-21 10:50:45 +11:00
|
|
|
return { modifiedAst: _node, pathToNode }
|
2023-02-12 10:56:45 +11:00
|
|
|
},
|
|
|
|
updateArgs: ({ node, pathToNode, to, from }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: callExpression } = nodeMeta
|
2023-02-12 10:56:45 +11:00
|
|
|
const newY = createLiteral(roundOff(to[1] - from[1], 2))
|
2023-09-13 07:23:14 -07:00
|
|
|
if (isLiteralArrayOrStatic(callExpression.arguments?.[0])) {
|
2023-02-12 10:56:45 +11:00
|
|
|
callExpression.arguments[0] = newY
|
|
|
|
} else {
|
|
|
|
mutateObjExpProp(callExpression.arguments?.[0], newY, 'length')
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-03-17 18:24:03 +11:00
|
|
|
addTag: addTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
getConstraintInfo: (callExp, ...args) =>
|
|
|
|
horzVertConstraintInfoHelper(
|
|
|
|
callExp,
|
|
|
|
['vertical', 'yRelative'],
|
|
|
|
'yLine',
|
|
|
|
'singleValue',
|
|
|
|
...args
|
|
|
|
),
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
2024-02-11 12:59:00 +11:00
|
|
|
export const tangentialArcTo: SketchLineHelper = {
|
|
|
|
add: ({
|
|
|
|
node,
|
|
|
|
pathToNode,
|
|
|
|
to,
|
|
|
|
createCallback,
|
|
|
|
replaceExisting,
|
|
|
|
referencedSegment,
|
|
|
|
}) => {
|
|
|
|
const _node = { ...node }
|
|
|
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
2024-06-24 11:45:40 -04:00
|
|
|
const _node1 = getNode<PipeExpression | CallExpression>('PipeExpression')
|
|
|
|
if (err(_node1)) return _node1
|
|
|
|
const { node: pipe } = _node1
|
|
|
|
const _node2 = getNodeFromPath<VariableDeclarator>(
|
2024-02-11 12:59:00 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'VariableDeclarator'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(_node2)) return _node2
|
|
|
|
const { node: varDec } = _node2
|
2024-02-11 12:59:00 +11:00
|
|
|
|
|
|
|
const toX = createLiteral(roundOff(to[0], 2))
|
|
|
|
const toY = createLiteral(roundOff(to[1], 2))
|
|
|
|
|
|
|
|
if (replaceExisting && createCallback && pipe.type !== 'CallExpression') {
|
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
|
|
|
const { callExp, valueUsedInTransform } = createCallback(
|
|
|
|
[toX, toY],
|
2024-05-24 20:54:42 +10:00
|
|
|
arrayRawValuesHelper([
|
|
|
|
[createLiteral(roundOff(to[0], 2)), 'xAbsolute'],
|
|
|
|
[createLiteral(roundOff(to[1], 2)), 'yAbsolute'],
|
|
|
|
]),
|
2024-02-11 12:59:00 +11:00
|
|
|
referencedSegment
|
|
|
|
)
|
|
|
|
pipe.body[callIndex] = callExp
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const newLine = createCallExpression('tangentialArcTo', [
|
|
|
|
createArrayExpression([toX, toY]),
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
if (pipe.type === 'PipeExpression') {
|
|
|
|
pipe.body = [...pipe.body, newLine]
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode: [
|
|
|
|
...pathToNode,
|
|
|
|
['body', 'PipeExpression'],
|
|
|
|
[pipe.body.length - 1, 'CallExpression'],
|
|
|
|
],
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
varDec.init = createPipeExpression([varDec.init, newLine])
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
updateArgs: ({ node, pathToNode, to, from }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: callExpression } = nodeMeta
|
2024-02-11 12:59:00 +11:00
|
|
|
const x = createLiteral(roundOff(to[0], 2))
|
|
|
|
const y = createLiteral(roundOff(to[1], 2))
|
|
|
|
|
|
|
|
const firstArg = callExpression.arguments?.[0]
|
|
|
|
if (!mutateArrExp(firstArg, createArrayExpression([x, y]))) {
|
|
|
|
mutateObjExpProp(firstArg, createArrayExpression([x, y]), 'to')
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-03-17 18:24:03 +11:00
|
|
|
addTag: addTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
getConstraintInfo: (callExp: CallExpression, code, pathToNode) => {
|
|
|
|
if (callExp.type !== 'CallExpression') return []
|
|
|
|
const firstArg = callExp.arguments?.[0]
|
|
|
|
if (firstArg.type !== 'ArrayExpression') return []
|
|
|
|
const callee = callExp.callee
|
|
|
|
const pathToCallee: PathToNode = [
|
|
|
|
...pathToNode,
|
|
|
|
['callee', 'CallExpression'],
|
|
|
|
]
|
|
|
|
const pathToArrayExpression: PathToNode = [
|
|
|
|
...pathToNode,
|
|
|
|
['arguments', 'CallExpression'],
|
|
|
|
[0, 'index'],
|
|
|
|
['elements', 'ArrayExpression'],
|
|
|
|
]
|
|
|
|
const pathToFirstArg: PathToNode = [...pathToArrayExpression, [0, 'index']]
|
|
|
|
const pathToSecondArg: PathToNode = [...pathToArrayExpression, [1, 'index']]
|
|
|
|
return [
|
|
|
|
constrainInfo(
|
|
|
|
'tangentialWithPrevious',
|
|
|
|
true,
|
|
|
|
callee.name,
|
|
|
|
'tangentialArcTo',
|
|
|
|
undefined,
|
|
|
|
[callee.start, callee.end],
|
|
|
|
pathToCallee
|
|
|
|
),
|
|
|
|
constrainInfo(
|
|
|
|
'xAbsolute',
|
|
|
|
isNotLiteralArrayOrStatic(firstArg.elements[0]),
|
|
|
|
code.slice(firstArg.elements[0].start, firstArg.elements[0].end),
|
|
|
|
'tangentialArcTo',
|
|
|
|
0,
|
|
|
|
[firstArg.elements[0].start, firstArg.elements[0].end],
|
|
|
|
pathToFirstArg
|
|
|
|
),
|
|
|
|
constrainInfo(
|
|
|
|
'yAbsolute',
|
|
|
|
isNotLiteralArrayOrStatic(firstArg.elements[1]),
|
|
|
|
code.slice(firstArg.elements[1].start, firstArg.elements[1].end),
|
|
|
|
'tangentialArcTo',
|
|
|
|
1,
|
|
|
|
[firstArg.elements[1].start, firstArg.elements[1].end],
|
|
|
|
pathToSecondArg
|
|
|
|
),
|
|
|
|
]
|
|
|
|
},
|
2024-02-11 12:59:00 +11:00
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
export const angledLine: SketchLineHelper = {
|
2023-03-17 21:15:46 +11:00
|
|
|
add: ({
|
|
|
|
node,
|
|
|
|
pathToNode,
|
|
|
|
to,
|
|
|
|
from,
|
|
|
|
createCallback,
|
|
|
|
replaceExisting,
|
|
|
|
referencedSegment,
|
|
|
|
}) => {
|
2023-02-12 10:56:45 +11:00
|
|
|
const _node = { ...node }
|
2023-03-02 21:19:11 +11:00
|
|
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
2024-06-24 11:45:40 -04:00
|
|
|
const _node1 = getNode<PipeExpression>('PipeExpression')
|
|
|
|
if (err(_node1)) return _node1
|
|
|
|
const { node: pipe } = _node1
|
2023-03-02 21:19:11 +11:00
|
|
|
|
|
|
|
const newAngleVal = createLiteral(roundOff(getAngle(from, to), 0))
|
|
|
|
const newLengthVal = createLiteral(roundOff(getLength(from, to), 2))
|
2023-03-10 08:48:50 +11:00
|
|
|
const newLine = createCallExpression('angledLine', [
|
|
|
|
createArrayExpression([newAngleVal, newLengthVal]),
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
2023-03-02 21:19:11 +11:00
|
|
|
|
2023-03-10 08:48:50 +11:00
|
|
|
if (replaceExisting && createCallback) {
|
2023-04-01 16:47:00 +11:00
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
2023-03-17 21:15:46 +11:00
|
|
|
const { callExp, valueUsedInTransform } = createCallback(
|
|
|
|
[newAngleVal, newLengthVal],
|
2024-05-24 20:54:42 +10:00
|
|
|
arrOrObjectRawValuesHelper([
|
|
|
|
[newAngleVal, 'angle', 'angle'],
|
|
|
|
[newLengthVal, 'length', 'length'],
|
|
|
|
]),
|
2023-03-17 21:15:46 +11:00
|
|
|
referencedSegment
|
|
|
|
)
|
2023-03-10 08:48:50 +11:00
|
|
|
pipe.body[callIndex] = callExp
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
2023-03-02 21:19:11 +11:00
|
|
|
} else {
|
|
|
|
pipe.body = [...pipe.body, newLine]
|
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
updateArgs: ({ node, pathToNode, to, from }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: callExpression } = nodeMeta
|
2023-02-12 10:56:45 +11:00
|
|
|
const angle = roundOff(getAngle(from, to), 0)
|
|
|
|
const lineLength = roundOff(getLength(from, to), 2)
|
|
|
|
|
|
|
|
const angleLit = createLiteral(angle)
|
|
|
|
const lengthLit = createLiteral(lineLength)
|
|
|
|
|
|
|
|
const firstArg = callExpression.arguments?.[0]
|
|
|
|
if (!mutateArrExp(firstArg, createArrayExpression([angleLit, lengthLit]))) {
|
|
|
|
mutateObjExpProp(firstArg, angleLit, 'angle')
|
|
|
|
mutateObjExpProp(firstArg, lengthLit, 'length')
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-03-17 18:24:03 +11:00
|
|
|
addTag: addTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
getConstraintInfo: (callExp, ...args) =>
|
|
|
|
commonConstraintInfoHelper(
|
|
|
|
callExp,
|
|
|
|
['angle', 'length'],
|
|
|
|
'angledLine',
|
|
|
|
[
|
|
|
|
{ arrayInput: 0, objInput: 'angle' },
|
|
|
|
{ arrayInput: 1, objInput: 'length' },
|
|
|
|
],
|
|
|
|
...args
|
|
|
|
),
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
export const angledLineOfXLength: SketchLineHelper = {
|
|
|
|
add: ({
|
|
|
|
node,
|
|
|
|
previousProgramMemory,
|
|
|
|
pathToNode,
|
|
|
|
to,
|
2023-03-02 21:19:11 +11:00
|
|
|
from,
|
|
|
|
createCallback,
|
|
|
|
replaceExisting,
|
2023-02-12 10:56:45 +11:00
|
|
|
}) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<PipeExpression>(
|
2023-02-12 10:56:45 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'PipeExpression'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: pipe } = nodeMeta
|
|
|
|
const nodeMeta2 = getNodeFromPath<VariableDeclarator>(
|
2023-02-12 10:56:45 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'VariableDeclarator'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(nodeMeta2)) return nodeMeta2
|
|
|
|
const { node: varDec } = nodeMeta2
|
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
const variableName = varDec.id.name
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
const sketch = sketchGroupFromKclValue(
|
|
|
|
previousProgramMemory?.get(variableName),
|
|
|
|
variableName
|
|
|
|
)
|
|
|
|
if (err(sketch)) {
|
|
|
|
return sketch
|
2024-06-24 11:45:40 -04:00
|
|
|
}
|
2023-03-02 21:19:11 +11:00
|
|
|
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
|
|
|
const xLength = createLiteral(roundOff(Math.abs(from[0] - to[0]), 2) || 0.1)
|
|
|
|
const newLine = createCallback
|
2024-05-24 20:54:42 +10:00
|
|
|
? createCallback(
|
|
|
|
[angle, xLength],
|
|
|
|
arrOrObjectRawValuesHelper([
|
|
|
|
[angle, 'angle', 'angle'],
|
|
|
|
[xLength, 'xRelative', 'length'],
|
|
|
|
])
|
|
|
|
).callExp
|
2023-03-02 21:19:11 +11:00
|
|
|
: createCallExpression('angledLineOfXLength', [
|
|
|
|
createArrayExpression([angle, xLength]),
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
2023-04-01 16:47:00 +11:00
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
2023-03-02 21:19:11 +11:00
|
|
|
if (replaceExisting) {
|
|
|
|
pipe.body[callIndex] = newLine
|
|
|
|
} else {
|
|
|
|
pipe.body = [...pipe.body, newLine]
|
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
updateArgs: ({ node, pathToNode, to, from }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: callExpression } = nodeMeta
|
2023-02-12 10:56:45 +11:00
|
|
|
const angle = roundOff(getAngle(from, to), 0)
|
|
|
|
const xLength = roundOff(Math.abs(to[0] - from[0]), 2)
|
|
|
|
|
|
|
|
const firstArg = callExpression.arguments?.[0]
|
|
|
|
const adjustedXLength = isAngleLiteral(firstArg)
|
|
|
|
? Math.abs(xLength)
|
|
|
|
: xLength // todo make work for variable angle > 180
|
|
|
|
|
|
|
|
const angleLit = createLiteral(angle)
|
|
|
|
const lengthLit = createLiteral(adjustedXLength)
|
|
|
|
|
|
|
|
if (!mutateArrExp(firstArg, createArrayExpression([angleLit, lengthLit]))) {
|
|
|
|
mutateObjExpProp(firstArg, angleLit, 'angle')
|
|
|
|
mutateObjExpProp(firstArg, lengthLit, 'length')
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-03-17 18:24:03 +11:00
|
|
|
addTag: addTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
getConstraintInfo: (callExp, ...args) =>
|
|
|
|
commonConstraintInfoHelper(
|
|
|
|
callExp,
|
|
|
|
['angle', 'xRelative'],
|
|
|
|
'angledLineOfXLength',
|
|
|
|
[
|
|
|
|
{ arrayInput: 0, objInput: 'angle' },
|
|
|
|
{ arrayInput: 1, objInput: 'length' },
|
|
|
|
],
|
|
|
|
...args
|
|
|
|
),
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
export const angledLineOfYLength: SketchLineHelper = {
|
|
|
|
add: ({
|
|
|
|
node,
|
|
|
|
previousProgramMemory,
|
|
|
|
pathToNode,
|
|
|
|
to,
|
2023-03-02 21:19:11 +11:00
|
|
|
from,
|
|
|
|
createCallback,
|
|
|
|
replaceExisting,
|
2023-02-12 10:56:45 +11:00
|
|
|
}) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<PipeExpression>(
|
2023-02-12 10:56:45 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'PipeExpression'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: pipe } = nodeMeta
|
|
|
|
const nodeMeta2 = getNodeFromPath<VariableDeclarator>(
|
2023-02-12 10:56:45 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'VariableDeclarator'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(nodeMeta2)) return nodeMeta2
|
|
|
|
const { node: varDec } = nodeMeta2
|
2023-02-12 10:56:45 +11:00
|
|
|
const variableName = varDec.id.name
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
const sketch = sketchGroupFromKclValue(
|
|
|
|
previousProgramMemory?.get(variableName),
|
|
|
|
variableName
|
|
|
|
)
|
|
|
|
if (err(sketch)) return sketch
|
2023-03-02 21:19:11 +11:00
|
|
|
|
|
|
|
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
|
|
|
const yLength = createLiteral(roundOff(Math.abs(from[1] - to[1]), 2) || 0.1)
|
|
|
|
const newLine = createCallback
|
2024-05-24 20:54:42 +10:00
|
|
|
? createCallback(
|
|
|
|
[angle, yLength],
|
|
|
|
arrOrObjectRawValuesHelper([
|
|
|
|
[angle, 'angle', 'angle'],
|
|
|
|
[yLength, 'yRelative', 'length'],
|
|
|
|
])
|
|
|
|
).callExp
|
2023-03-02 21:19:11 +11:00
|
|
|
: createCallExpression('angledLineOfYLength', [
|
|
|
|
createArrayExpression([angle, yLength]),
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
2023-04-01 16:47:00 +11:00
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
2023-03-02 21:19:11 +11:00
|
|
|
if (replaceExisting) {
|
|
|
|
pipe.body[callIndex] = newLine
|
|
|
|
} else {
|
|
|
|
pipe.body = [...pipe.body, newLine]
|
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
updateArgs: ({ node, pathToNode, to, from }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
const { node: callExpression } = nodeMeta
|
2023-02-12 10:56:45 +11:00
|
|
|
const angle = roundOff(getAngle(from, to), 0)
|
|
|
|
const yLength = roundOff(to[1] - from[1], 2)
|
|
|
|
|
|
|
|
const firstArg = callExpression.arguments?.[0]
|
|
|
|
const adjustedYLength = isAngleLiteral(firstArg)
|
|
|
|
? Math.abs(yLength)
|
|
|
|
: yLength // todo make work for variable angle > 180
|
|
|
|
|
|
|
|
const angleLit = createLiteral(angle)
|
|
|
|
const lengthLit = createLiteral(adjustedYLength)
|
|
|
|
|
|
|
|
if (!mutateArrExp(firstArg, createArrayExpression([angleLit, lengthLit]))) {
|
|
|
|
mutateObjExpProp(firstArg, angleLit, 'angle')
|
|
|
|
mutateObjExpProp(firstArg, lengthLit, 'length')
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-03-17 18:24:03 +11:00
|
|
|
addTag: addTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
getConstraintInfo: (callExp, ...args) =>
|
|
|
|
commonConstraintInfoHelper(
|
|
|
|
callExp,
|
|
|
|
['angle', 'yRelative'],
|
|
|
|
'angledLineOfYLength',
|
|
|
|
[
|
|
|
|
{ arrayInput: 0, objInput: 'angle' },
|
|
|
|
{ arrayInput: 1, objInput: 'length' },
|
|
|
|
],
|
|
|
|
...args
|
|
|
|
),
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
export const angledLineToX: SketchLineHelper = {
|
2023-04-05 21:06:20 +10:00
|
|
|
add: ({
|
|
|
|
node,
|
|
|
|
pathToNode,
|
|
|
|
to,
|
|
|
|
from,
|
|
|
|
createCallback,
|
|
|
|
replaceExisting,
|
|
|
|
referencedSegment,
|
|
|
|
}) => {
|
2023-02-12 10:56:45 +11:00
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<PipeExpression>(
|
2023-02-12 10:56:45 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'PipeExpression'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
|
|
|
|
const { node: pipe } = nodeMeta
|
2023-03-02 21:19:11 +11:00
|
|
|
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
|
|
|
const xArg = createLiteral(roundOff(to[0], 2))
|
2023-03-17 08:27:40 +11:00
|
|
|
if (replaceExisting && createCallback) {
|
2023-04-05 21:06:20 +10:00
|
|
|
const { callExp, valueUsedInTransform } = createCallback(
|
|
|
|
[angle, xArg],
|
2024-05-24 20:54:42 +10:00
|
|
|
arrOrObjectRawValuesHelper([
|
|
|
|
[angle, 'angle', 'angle'],
|
|
|
|
[xArg, 'xAbsolute', 'to'],
|
|
|
|
]),
|
2023-04-05 21:06:20 +10:00
|
|
|
referencedSegment
|
|
|
|
)
|
2023-04-01 16:47:00 +11:00
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
2023-03-17 08:27:40 +11:00
|
|
|
pipe.body[callIndex] = callExp
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
2023-03-02 21:19:11 +11:00
|
|
|
}
|
2023-03-17 08:27:40 +11:00
|
|
|
|
|
|
|
const callExp = createCallExpression('angledLineToX', [
|
|
|
|
createArrayExpression([angle, xArg]),
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
pipe.body = [...pipe.body, callExp]
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
updateArgs: ({ node, pathToNode, to, from }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
|
|
|
|
const { node: callExpression } = nodeMeta
|
2023-02-12 10:56:45 +11:00
|
|
|
const angle = roundOff(getAngle(from, to), 0)
|
|
|
|
const xLength = roundOff(to[0], 2)
|
|
|
|
|
|
|
|
const firstArg = callExpression.arguments?.[0]
|
|
|
|
const adjustedXLength = xLength
|
|
|
|
|
|
|
|
const angleLit = createLiteral(angle)
|
|
|
|
const lengthLit = createLiteral(adjustedXLength)
|
|
|
|
|
|
|
|
if (!mutateArrExp(firstArg, createArrayExpression([angleLit, lengthLit]))) {
|
|
|
|
mutateObjExpProp(firstArg, angleLit, 'angle')
|
|
|
|
mutateObjExpProp(firstArg, lengthLit, 'to')
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-03-17 18:24:03 +11:00
|
|
|
addTag: addTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
getConstraintInfo: (callExp, ...args) =>
|
|
|
|
commonConstraintInfoHelper(
|
|
|
|
callExp,
|
|
|
|
['angle', 'xAbsolute'],
|
|
|
|
'angledLineToX',
|
|
|
|
[
|
|
|
|
{ arrayInput: 0, objInput: 'angle' },
|
|
|
|
{ arrayInput: 1, objInput: 'to' },
|
|
|
|
],
|
|
|
|
...args
|
|
|
|
),
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
export const angledLineToY: SketchLineHelper = {
|
2023-04-05 21:06:20 +10:00
|
|
|
add: ({
|
|
|
|
node,
|
|
|
|
pathToNode,
|
|
|
|
to,
|
|
|
|
from,
|
|
|
|
createCallback,
|
|
|
|
replaceExisting,
|
|
|
|
referencedSegment,
|
|
|
|
}) => {
|
2023-02-12 10:56:45 +11:00
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<PipeExpression>(
|
2023-02-12 10:56:45 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'PipeExpression'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
|
|
|
|
const { node: pipe } = nodeMeta
|
|
|
|
|
2023-03-02 21:19:11 +11:00
|
|
|
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
|
|
|
const yArg = createLiteral(roundOff(to[1], 2))
|
2023-03-10 14:55:16 +11:00
|
|
|
|
|
|
|
if (replaceExisting && createCallback) {
|
2023-04-05 21:06:20 +10:00
|
|
|
const { callExp, valueUsedInTransform } = createCallback(
|
|
|
|
[angle, yArg],
|
2024-05-24 20:54:42 +10:00
|
|
|
arrOrObjectRawValuesHelper([
|
|
|
|
[angle, 'angle', 'angle'],
|
|
|
|
[yArg, 'yAbsolute', 'to'],
|
|
|
|
]),
|
2023-04-05 21:06:20 +10:00
|
|
|
referencedSegment
|
|
|
|
)
|
2023-04-01 16:47:00 +11:00
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
2023-03-10 14:55:16 +11:00
|
|
|
pipe.body[callIndex] = callExp
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
2023-03-02 21:19:11 +11:00
|
|
|
}
|
2023-03-10 14:55:16 +11:00
|
|
|
|
|
|
|
const newLine = createCallExpression('angledLineToY', [
|
|
|
|
createArrayExpression([angle, yArg]),
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
pipe.body = [...pipe.body, newLine]
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
updateArgs: ({ node, pathToNode, to, from }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
|
|
|
|
const { node: callExpression } = nodeMeta
|
2023-02-12 10:56:45 +11:00
|
|
|
const angle = roundOff(getAngle(from, to), 0)
|
|
|
|
const xLength = roundOff(to[1], 2)
|
|
|
|
|
|
|
|
const firstArg = callExpression.arguments?.[0]
|
|
|
|
const adjustedXLength = xLength
|
|
|
|
|
|
|
|
const angleLit = createLiteral(angle)
|
|
|
|
const lengthLit = createLiteral(adjustedXLength)
|
|
|
|
|
|
|
|
if (!mutateArrExp(firstArg, createArrayExpression([angleLit, lengthLit]))) {
|
|
|
|
mutateObjExpProp(firstArg, angleLit, 'angle')
|
|
|
|
mutateObjExpProp(firstArg, lengthLit, 'to')
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-03-17 18:24:03 +11:00
|
|
|
addTag: addTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
getConstraintInfo: (callExp, ...args) =>
|
|
|
|
commonConstraintInfoHelper(
|
|
|
|
callExp,
|
|
|
|
['angle', 'yAbsolute'],
|
|
|
|
'angledLineToY',
|
|
|
|
[
|
|
|
|
{ arrayInput: 0, objInput: 'angle' },
|
|
|
|
{ arrayInput: 1, objInput: 'to' },
|
|
|
|
],
|
|
|
|
...args
|
|
|
|
),
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
2023-03-19 18:46:39 +11:00
|
|
|
export const angledLineThatIntersects: SketchLineHelper = {
|
|
|
|
add: ({
|
|
|
|
node,
|
|
|
|
pathToNode,
|
|
|
|
to,
|
|
|
|
from,
|
|
|
|
createCallback,
|
|
|
|
replaceExisting,
|
|
|
|
referencedSegment,
|
|
|
|
}) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<PipeExpression>(
|
2023-03-19 18:46:39 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'PipeExpression'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
|
|
|
|
const { node: pipe } = nodeMeta
|
|
|
|
|
2023-03-19 18:46:39 +11:00
|
|
|
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
2024-06-24 11:45:40 -04:00
|
|
|
if (!referencedSegment) {
|
|
|
|
return new Error('referencedSegment must be provided')
|
|
|
|
}
|
|
|
|
|
2023-03-19 18:46:39 +11:00
|
|
|
const offset = createLiteral(
|
|
|
|
roundOff(
|
|
|
|
perpendicularDistance(
|
|
|
|
referencedSegment?.from,
|
|
|
|
referencedSegment?.to,
|
|
|
|
to
|
|
|
|
),
|
|
|
|
2
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
if (replaceExisting && createCallback) {
|
2024-05-24 20:54:42 +10:00
|
|
|
const { callExp, valueUsedInTransform } = createCallback(
|
|
|
|
[angle, offset],
|
|
|
|
[
|
|
|
|
{
|
|
|
|
type: 'objectProperty',
|
|
|
|
key: 'angle',
|
|
|
|
value: angle,
|
|
|
|
argType: 'angle',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'objectProperty',
|
|
|
|
key: 'offset',
|
|
|
|
value: offset,
|
|
|
|
argType: 'intersectionOffset',
|
|
|
|
},
|
|
|
|
]
|
|
|
|
)
|
2023-04-01 16:47:00 +11:00
|
|
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
2023-03-19 18:46:39 +11:00
|
|
|
pipe.body[callIndex] = callExp
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
valueUsedInTransform,
|
|
|
|
}
|
|
|
|
}
|
2024-06-24 11:45:40 -04:00
|
|
|
return new Error('not implemented')
|
2023-03-19 18:46:39 +11:00
|
|
|
},
|
|
|
|
updateArgs: ({ node, pathToNode, to, from, previousProgramMemory }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
|
|
|
|
const { node: callExpression } = nodeMeta
|
2023-03-19 18:46:39 +11:00
|
|
|
const angle = roundOff(getAngle(from, to), 0)
|
|
|
|
|
|
|
|
const firstArg = callExpression.arguments?.[0]
|
|
|
|
const intersectTag =
|
|
|
|
firstArg.type === 'ObjectExpression'
|
|
|
|
? firstArg.properties.find((p) => p.key.name === 'intersectTag')
|
|
|
|
?.value || createLiteral('')
|
|
|
|
: createLiteral('')
|
|
|
|
const intersectTagName =
|
2024-06-24 22:39:04 -07:00
|
|
|
intersectTag.type === 'Identifier' ? intersectTag.name : ''
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta2 = getNodeFromPath<VariableDeclaration>(
|
2023-03-19 18:46:39 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'VariableDeclaration'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(nodeMeta2)) return nodeMeta2
|
2023-03-19 18:46:39 +11:00
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
const { node: varDec } = nodeMeta2
|
2023-03-19 18:46:39 +11:00
|
|
|
const varName = varDec.declarations[0].id.name
|
Remove KclValue::SketchGroup variant (#3446)
We can store Rust types like `SketchGroup` as their own variant of `KclValue`, or as `KclValue::UserVal`. Sometimes we store in one and try to read from the other, which fails. This causes bugs, like #3338.
Instead, we should use either ::SketchGroup or ::UserVal, and stop using the other. If we stopped using ::UserVal, we'd need a new variant for every Rust type we wanted to build, including user-defined types. So I don't think that's practical.
Instead, we should store every KCL value by de/serializing it into UserVal. This is a first step along that path, removing just the SketchGroup variants. If it goes well, we can remove the other specialized variants too.
My only concern is there might be performance implications from how frequently we convert between serde_json::Value and Rust types via Serde. But I'm not too worried -- there's no parsing JSON strings, just traversing serde_json::Value trees. This isn't great for performance but I think it'll probably be miniscule in comparison to doing all the API calls.
2024-08-21 11:06:48 -05:00
|
|
|
const sketchGroup = sketchGroupFromKclValue(
|
|
|
|
previousProgramMemory.get(varName),
|
|
|
|
varName
|
|
|
|
)
|
|
|
|
if (err(sketchGroup)) return sketchGroup
|
2023-03-19 18:46:39 +11:00
|
|
|
const intersectPath = sketchGroup.value.find(
|
2024-06-24 14:45:07 -07:00
|
|
|
({ tag }: Path) => tag && tag.value === intersectTagName
|
2023-03-19 18:46:39 +11:00
|
|
|
)
|
|
|
|
let offset = 0
|
|
|
|
if (intersectPath) {
|
|
|
|
offset = roundOff(
|
|
|
|
perpendicularDistance(intersectPath?.from, intersectPath?.to, to),
|
|
|
|
2
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const angleLit = createLiteral(angle)
|
|
|
|
|
|
|
|
mutateObjExpProp(firstArg, angleLit, 'angle')
|
|
|
|
mutateObjExpProp(firstArg, createLiteral(offset), 'offset')
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
},
|
2024-07-15 19:20:32 +10:00
|
|
|
getTag: getTag(),
|
2024-05-24 20:54:42 +10:00
|
|
|
addTag: addTag(),
|
|
|
|
getConstraintInfo: (callExp: CallExpression, code, pathToNode) => {
|
|
|
|
if (callExp.type !== 'CallExpression') return []
|
|
|
|
const firstArg = callExp.arguments?.[0]
|
|
|
|
if (firstArg.type !== 'ObjectExpression') return []
|
|
|
|
const angleIndex = firstArg.properties.findIndex(
|
|
|
|
(p) => p.key.name === 'angle'
|
|
|
|
)
|
|
|
|
const offsetIndex = firstArg.properties.findIndex(
|
|
|
|
(p) => p.key.name === 'offset'
|
|
|
|
)
|
|
|
|
const intersectTag = firstArg.properties.findIndex(
|
|
|
|
(p) => p.key.name === 'intersectTag'
|
|
|
|
)
|
|
|
|
const returnVal = []
|
|
|
|
const pathToObjectExp: PathToNode = [
|
|
|
|
...pathToNode,
|
|
|
|
['arguments', 'CallExpression'],
|
|
|
|
[0, 'index'],
|
|
|
|
['properties', 'ObjectExpression'],
|
|
|
|
]
|
|
|
|
if (angleIndex !== -1) {
|
|
|
|
const angle = firstArg.properties[angleIndex]?.value
|
|
|
|
const pathToAngleProp: PathToNode = [
|
|
|
|
...pathToObjectExp,
|
|
|
|
[angleIndex, 'index'],
|
|
|
|
['value', 'Property'],
|
|
|
|
]
|
|
|
|
returnVal.push(
|
|
|
|
constrainInfo(
|
|
|
|
'angle',
|
|
|
|
isNotLiteralArrayOrStatic(angle),
|
|
|
|
code.slice(angle.start, angle.end),
|
|
|
|
'angledLineThatIntersects',
|
|
|
|
'angle',
|
|
|
|
[angle.start, angle.end],
|
|
|
|
pathToAngleProp
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if (offsetIndex !== -1) {
|
|
|
|
const offset = firstArg.properties[offsetIndex]?.value
|
|
|
|
const pathToOffsetProp: PathToNode = [
|
|
|
|
...pathToObjectExp,
|
|
|
|
[offsetIndex, 'index'],
|
|
|
|
['value', 'Property'],
|
|
|
|
]
|
|
|
|
returnVal.push(
|
|
|
|
constrainInfo(
|
|
|
|
'intersectionOffset',
|
|
|
|
isNotLiteralArrayOrStatic(offset),
|
|
|
|
code.slice(offset.start, offset.end),
|
|
|
|
'angledLineThatIntersects',
|
|
|
|
'offset',
|
|
|
|
[offset.start, offset.end],
|
|
|
|
pathToOffsetProp
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if (intersectTag !== -1) {
|
2024-06-24 22:39:04 -07:00
|
|
|
const tag = firstArg.properties[intersectTag]?.value as Identifier
|
2024-05-24 20:54:42 +10:00
|
|
|
const pathToTagProp: PathToNode = [
|
|
|
|
...pathToObjectExp,
|
|
|
|
[intersectTag, 'index'],
|
|
|
|
['value', 'Property'],
|
|
|
|
]
|
2024-06-24 22:39:04 -07:00
|
|
|
const info = constrainInfo(
|
|
|
|
'intersectionTag',
|
|
|
|
// This will always be a tag identifier.
|
|
|
|
false,
|
|
|
|
code.slice(tag.start, tag.end),
|
|
|
|
'angledLineThatIntersects',
|
|
|
|
'intersectTag',
|
|
|
|
[tag.start, tag.end],
|
|
|
|
pathToTagProp
|
2024-05-24 20:54:42 +10:00
|
|
|
)
|
2024-06-24 22:39:04 -07:00
|
|
|
returnVal.push(info)
|
2024-05-24 20:54:42 +10:00
|
|
|
}
|
|
|
|
return returnVal
|
|
|
|
},
|
2023-03-19 18:46:39 +11:00
|
|
|
}
|
|
|
|
|
2024-03-02 08:48:30 +11:00
|
|
|
export const updateStartProfileAtArgs: SketchLineHelper['updateArgs'] = ({
|
|
|
|
node,
|
|
|
|
pathToNode,
|
|
|
|
to,
|
|
|
|
}) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
|
|
|
|
if (err(nodeMeta)) {
|
|
|
|
console.error(nodeMeta)
|
|
|
|
return {
|
|
|
|
modifiedAst: {
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
|
|
|
body: [],
|
2024-07-09 12:24:42 -04:00
|
|
|
digest: null,
|
2024-06-24 11:45:40 -04:00
|
|
|
nonCodeMeta: {
|
|
|
|
start: [],
|
|
|
|
nonCodeNodes: [],
|
2024-07-09 12:24:42 -04:00
|
|
|
digest: null,
|
2024-06-24 11:45:40 -04:00
|
|
|
},
|
|
|
|
},
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
2024-03-02 08:48:30 +11:00
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
const { node: callExpression } = nodeMeta
|
2024-03-02 08:48:30 +11:00
|
|
|
const toArrExp = createArrayExpression([
|
|
|
|
createLiteral(roundOff(to[0])),
|
|
|
|
createLiteral(roundOff(to[1])),
|
|
|
|
])
|
|
|
|
|
|
|
|
mutateArrExp(callExpression.arguments?.[0], toArrExp) ||
|
|
|
|
mutateObjExpProp(callExpression.arguments?.[0], toArrExp, 'to')
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
export const sketchLineHelperMap: { [key: string]: SketchLineHelper } = {
|
|
|
|
line,
|
|
|
|
lineTo,
|
|
|
|
xLine,
|
|
|
|
yLine,
|
|
|
|
xLineTo,
|
|
|
|
yLineTo,
|
|
|
|
angledLine,
|
|
|
|
angledLineOfXLength,
|
|
|
|
angledLineOfYLength,
|
|
|
|
angledLineToX,
|
|
|
|
angledLineToY,
|
2023-03-19 18:46:39 +11:00
|
|
|
angledLineThatIntersects,
|
2024-02-11 12:59:00 +11:00
|
|
|
tangentialArcTo,
|
2023-02-12 10:56:45 +11:00
|
|
|
} as const
|
|
|
|
|
|
|
|
export function changeSketchArguments(
|
|
|
|
node: Program,
|
|
|
|
programMemory: ProgramMemory,
|
|
|
|
sourceRange: SourceRange,
|
|
|
|
args: [number, number],
|
|
|
|
from: [number, number]
|
2024-06-24 11:45:40 -04:00
|
|
|
): { modifiedAst: Program; pathToNode: PathToNode } | Error {
|
2023-02-12 10:56:45 +11:00
|
|
|
const _node = { ...node }
|
|
|
|
const thePath = getNodePathFromSourceRange(_node, sourceRange)
|
2024-06-24 11:45:40 -04:00
|
|
|
const nodeMeta = getNodeFromPath<CallExpression>(_node, thePath)
|
|
|
|
if (err(nodeMeta)) return nodeMeta
|
|
|
|
|
|
|
|
const { node: callExpression, shallowPath } = nodeMeta
|
2023-02-12 10:56:45 +11:00
|
|
|
|
|
|
|
if (callExpression?.callee?.name in sketchLineHelperMap) {
|
|
|
|
const { updateArgs } = sketchLineHelperMap[callExpression.callee.name]
|
2024-06-24 11:45:40 -04:00
|
|
|
if (!updateArgs) {
|
|
|
|
return new Error('not a sketch line helper')
|
|
|
|
}
|
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
return updateArgs({
|
|
|
|
node: _node,
|
|
|
|
previousProgramMemory: programMemory,
|
2023-04-01 16:47:00 +11:00
|
|
|
pathToNode: shallowPath,
|
2023-02-12 10:56:45 +11:00
|
|
|
to: args,
|
|
|
|
from,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
return new Error(`not a sketch line helper: ${callExpression?.callee?.name}`)
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
export function getConstraintInfo(
|
|
|
|
callExpression: CallExpression,
|
|
|
|
code: string,
|
|
|
|
pathToNode: PathToNode
|
|
|
|
): ConstrainInfo[] {
|
|
|
|
const fnName = callExpression?.callee?.name || ''
|
|
|
|
if (!(fnName in sketchLineHelperMap)) return []
|
|
|
|
return sketchLineHelperMap[fnName].getConstraintInfo(
|
|
|
|
callExpression,
|
|
|
|
code,
|
|
|
|
pathToNode
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-09-14 09:34:37 -04:00
|
|
|
export function compareVec2Epsilon(
|
|
|
|
vec1: [number, number],
|
2024-02-11 12:59:00 +11:00
|
|
|
vec2: [number, number],
|
|
|
|
compareEpsilon = 0.015625 // or 2^-6
|
2023-09-14 09:34:37 -04:00
|
|
|
) {
|
|
|
|
const xDifference = Math.abs(vec1[0] - vec2[0])
|
2023-11-08 20:27:53 +11:00
|
|
|
const yDifference = Math.abs(vec1[1] - vec2[1])
|
2023-09-14 09:34:37 -04:00
|
|
|
return xDifference < compareEpsilon && yDifference < compareEpsilon
|
|
|
|
}
|
|
|
|
|
2024-02-11 12:59:00 +11:00
|
|
|
// this version uses this distance of the two points instead of comparing x and y separately
|
|
|
|
export function compareVec2Epsilon2(
|
|
|
|
vec1: [number, number],
|
|
|
|
vec2: [number, number],
|
|
|
|
compareEpsilon = 0.015625 // or 2^-6
|
|
|
|
) {
|
|
|
|
const xDifference = Math.abs(vec1[0] - vec2[0])
|
|
|
|
const yDifference = Math.abs(vec1[1] - vec2[1])
|
|
|
|
const distance = Math.sqrt(
|
|
|
|
xDifference * xDifference + yDifference * yDifference
|
|
|
|
)
|
|
|
|
return distance < compareEpsilon
|
|
|
|
}
|
|
|
|
|
2024-04-03 13:22:56 +11:00
|
|
|
interface CreateLineFnCallArgs {
|
|
|
|
node: Program
|
|
|
|
programMemory: ProgramMemory
|
|
|
|
to: [number, number]
|
|
|
|
from: [number, number]
|
|
|
|
fnName: ToolTip
|
|
|
|
pathToNode: PathToNode
|
|
|
|
spliceBetween?: boolean
|
|
|
|
}
|
|
|
|
|
2023-02-21 10:50:45 +11:00
|
|
|
export function addNewSketchLn({
|
2023-03-17 15:53:20 +11:00
|
|
|
node: _node,
|
2023-02-21 10:50:45 +11:00
|
|
|
programMemory: previousProgramMemory,
|
|
|
|
to,
|
|
|
|
fnName,
|
|
|
|
pathToNode,
|
2023-10-18 07:30:03 +11:00
|
|
|
from,
|
2024-04-03 13:22:56 +11:00
|
|
|
spliceBetween = false,
|
2024-06-24 11:45:40 -04:00
|
|
|
}: CreateLineFnCallArgs):
|
|
|
|
| {
|
|
|
|
modifiedAst: Program
|
|
|
|
pathToNode: PathToNode
|
|
|
|
}
|
|
|
|
| Error {
|
2024-07-25 20:11:46 -04:00
|
|
|
const node = structuredClone(_node)
|
2023-03-21 19:02:18 +11:00
|
|
|
const { add, updateArgs } = sketchLineHelperMap?.[fnName] || {}
|
2024-06-24 11:45:40 -04:00
|
|
|
if (!add || !updateArgs) {
|
|
|
|
return new Error('not a sketch line helper')
|
|
|
|
}
|
|
|
|
|
2023-11-01 07:39:31 -04:00
|
|
|
getNodeFromPath<VariableDeclarator>(node, pathToNode, 'VariableDeclarator')
|
|
|
|
getNodeFromPath<PipeExpression | CallExpression>(
|
2023-02-21 10:50:45 +11:00
|
|
|
node,
|
|
|
|
pathToNode,
|
2023-11-01 07:39:31 -04:00
|
|
|
'PipeExpression'
|
2023-02-21 10:50:45 +11:00
|
|
|
)
|
|
|
|
return add({
|
|
|
|
node,
|
|
|
|
previousProgramMemory,
|
|
|
|
pathToNode,
|
|
|
|
to,
|
|
|
|
from,
|
|
|
|
replaceExisting: false,
|
2024-04-03 13:22:56 +11:00
|
|
|
spliceBetween,
|
2023-02-21 10:50:45 +11:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-05-23 00:53:15 -04:00
|
|
|
export function addCallExpressionsToPipe({
|
|
|
|
node,
|
|
|
|
pathToNode,
|
|
|
|
expressions,
|
|
|
|
}: {
|
|
|
|
node: Program
|
|
|
|
programMemory: ProgramMemory
|
|
|
|
pathToNode: PathToNode
|
|
|
|
expressions: CallExpression[]
|
|
|
|
}) {
|
|
|
|
const _node = { ...node }
|
|
|
|
const pipeExpression = getNodeFromPath<PipeExpression>(
|
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'PipeExpression'
|
2024-06-24 11:45:40 -04:00
|
|
|
)
|
|
|
|
if (err(pipeExpression)) return pipeExpression
|
|
|
|
|
|
|
|
if (pipeExpression.node.type !== 'PipeExpression') {
|
|
|
|
return new Error('not a pipe expression')
|
|
|
|
}
|
|
|
|
pipeExpression.node.body = [...pipeExpression.node.body, ...expressions]
|
2024-05-23 00:53:15 -04:00
|
|
|
return _node
|
|
|
|
}
|
|
|
|
|
2023-09-14 09:34:37 -04:00
|
|
|
export function addCloseToPipe({
|
|
|
|
node,
|
|
|
|
pathToNode,
|
|
|
|
}: {
|
|
|
|
node: Program
|
|
|
|
programMemory: ProgramMemory
|
|
|
|
pathToNode: PathToNode
|
|
|
|
}) {
|
|
|
|
const _node = { ...node }
|
|
|
|
const closeExpression = createCallExpression('close', [
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
const pipeExpression = getNodeFromPath<PipeExpression>(
|
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'PipeExpression'
|
2024-06-24 11:45:40 -04:00
|
|
|
)
|
|
|
|
if (err(pipeExpression)) return pipeExpression
|
|
|
|
|
|
|
|
if (pipeExpression.node.type !== 'PipeExpression') {
|
|
|
|
return new Error('not a pipe expression')
|
|
|
|
}
|
|
|
|
pipeExpression.node.body = [...pipeExpression.node.body, closeExpression]
|
2023-09-14 09:34:37 -04:00
|
|
|
return _node
|
|
|
|
}
|
|
|
|
|
2023-02-21 10:50:45 +11:00
|
|
|
export function replaceSketchLine({
|
|
|
|
node,
|
|
|
|
programMemory,
|
2024-05-24 20:54:42 +10:00
|
|
|
pathToNode: _pathToNode,
|
2023-02-21 10:50:45 +11:00
|
|
|
fnName,
|
|
|
|
to,
|
|
|
|
from,
|
|
|
|
createCallback,
|
2023-03-05 07:34:56 +11:00
|
|
|
referencedSegment,
|
2023-02-21 10:50:45 +11:00
|
|
|
}: {
|
|
|
|
node: Program
|
|
|
|
programMemory: ProgramMemory
|
2024-05-24 20:54:42 +10:00
|
|
|
pathToNode: PathToNode
|
2023-09-15 11:48:23 -04:00
|
|
|
fnName: ToolTip
|
2023-02-21 10:50:45 +11:00
|
|
|
to: [number, number]
|
|
|
|
from: [number, number]
|
|
|
|
createCallback: TransformCallback
|
2023-03-05 07:34:56 +11:00
|
|
|
referencedSegment?: Path
|
2024-06-24 11:45:40 -04:00
|
|
|
}):
|
|
|
|
| {
|
|
|
|
modifiedAst: Program
|
|
|
|
valueUsedInTransform?: number
|
|
|
|
pathToNode: PathToNode
|
|
|
|
}
|
|
|
|
| Error {
|
|
|
|
if (![...toolTips, 'intersect'].includes(fnName)) {
|
|
|
|
return new Error('not a tooltip')
|
|
|
|
}
|
2023-02-21 10:50:45 +11:00
|
|
|
const _node = { ...node }
|
|
|
|
|
|
|
|
const { add } = sketchLineHelperMap[fnName]
|
2024-06-24 11:45:40 -04:00
|
|
|
const addRetVal = add({
|
2023-02-21 10:50:45 +11:00
|
|
|
node: _node,
|
|
|
|
previousProgramMemory: programMemory,
|
2024-05-24 20:54:42 +10:00
|
|
|
pathToNode: _pathToNode,
|
2023-03-05 07:34:56 +11:00
|
|
|
referencedSegment,
|
2023-02-21 10:50:45 +11:00
|
|
|
to,
|
|
|
|
from,
|
|
|
|
replaceExisting: true,
|
|
|
|
createCallback,
|
|
|
|
})
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(addRetVal)) return addRetVal
|
|
|
|
|
|
|
|
const { modifiedAst, valueUsedInTransform, pathToNode } = addRetVal
|
2023-04-14 07:49:36 +10:00
|
|
|
return { modifiedAst, valueUsedInTransform, pathToNode }
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
2024-07-15 19:20:32 +10:00
|
|
|
export function addTagForSketchOnFace(a: AddTagInfo, expressionName: string) {
|
2024-03-22 10:23:04 +11:00
|
|
|
if (expressionName === 'close') {
|
|
|
|
return addTag(1)(a)
|
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
if (expressionName in sketchLineHelperMap) {
|
|
|
|
const { addTag } = sketchLineHelperMap[expressionName]
|
|
|
|
return addTag(a)
|
|
|
|
}
|
2024-06-24 11:45:40 -04:00
|
|
|
return new Error(`"${expressionName}" is not a sketch line helper`)
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
2024-07-15 19:20:32 +10:00
|
|
|
export function getTagFromCallExpression(
|
|
|
|
callExp: CallExpression
|
|
|
|
): string | Error {
|
|
|
|
if (callExp.callee.name === 'close') return getTag(1)(callExp)
|
|
|
|
if (callExp.callee.name in sketchLineHelperMap) {
|
|
|
|
const { getTag } = sketchLineHelperMap[callExp.callee.name]
|
|
|
|
return getTag(callExp)
|
|
|
|
}
|
|
|
|
return new Error(`"${callExp.callee.name}" is not a sketch line helper`)
|
|
|
|
}
|
|
|
|
|
2024-08-12 15:38:42 -05:00
|
|
|
function isAngleLiteral(lineArugement: Expr): boolean {
|
2023-02-12 10:56:45 +11:00
|
|
|
return lineArugement?.type === 'ArrayExpression'
|
2023-09-13 07:23:14 -07:00
|
|
|
? isLiteralArrayOrStatic(lineArugement.elements[0])
|
2023-02-12 10:56:45 +11:00
|
|
|
: lineArugement?.type === 'ObjectExpression'
|
2023-09-13 07:23:14 -07:00
|
|
|
? isLiteralArrayOrStatic(
|
|
|
|
lineArugement.properties.find(({ key }) => key.name === 'angle')?.value
|
|
|
|
)
|
2023-02-12 10:56:45 +11:00
|
|
|
: false
|
|
|
|
}
|
|
|
|
|
2024-07-15 19:20:32 +10:00
|
|
|
type addTagFn = (a: AddTagInfo) => { modifiedAst: Program; tag: string } | Error
|
2023-02-12 10:56:45 +11:00
|
|
|
|
2024-03-22 10:23:04 +11:00
|
|
|
function addTag(tagIndex = 2): addTagFn {
|
2023-02-12 10:56:45 +11:00
|
|
|
return ({ node, pathToNode }) => {
|
|
|
|
const _node = { ...node }
|
2024-06-24 11:45:40 -04:00
|
|
|
const callExpr = getNodeFromPath<CallExpression>(
|
2023-02-12 10:56:45 +11:00
|
|
|
_node,
|
2024-03-17 18:24:03 +11:00
|
|
|
pathToNode,
|
|
|
|
'CallExpression'
|
2023-02-12 10:56:45 +11:00
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(callExpr)) return callExpr
|
|
|
|
|
|
|
|
const { node: primaryCallExp } = callExpr
|
|
|
|
|
2024-03-17 18:24:03 +11:00
|
|
|
// Tag is always 3rd expression now, using arg index feels brittle
|
|
|
|
// but we can come up with a better way to identify tag later.
|
2024-03-22 10:23:04 +11:00
|
|
|
const thirdArg = primaryCallExp.arguments?.[tagIndex]
|
2024-06-24 22:39:04 -07:00
|
|
|
const tagDeclarator =
|
|
|
|
thirdArg ||
|
|
|
|
(createTagDeclarator(findUniqueName(_node, 'seg', 2)) as TagDeclarator)
|
2024-03-17 18:24:03 +11:00
|
|
|
const isTagExisting = !!thirdArg
|
|
|
|
if (!isTagExisting) {
|
2024-06-24 22:39:04 -07:00
|
|
|
primaryCallExp.arguments[tagIndex] = tagDeclarator
|
2024-03-17 18:24:03 +11:00
|
|
|
}
|
2024-06-24 22:39:04 -07:00
|
|
|
if ('value' in tagDeclarator) {
|
|
|
|
// Now TypeScript knows tagDeclarator has a value property
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
2024-06-24 22:39:04 -07:00
|
|
|
tag: String(tagDeclarator.value),
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
2024-03-15 17:03:42 -04:00
|
|
|
} else {
|
2024-06-24 11:45:40 -04:00
|
|
|
return new Error('Unable to assign tag without value')
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getYComponent(
|
|
|
|
angleDegree: number,
|
|
|
|
xComponent: number
|
|
|
|
): [number, number] {
|
|
|
|
const normalisedAngle = ((angleDegree % 360) + 360) % 360 // between 0 and 360
|
|
|
|
let yComponent = xComponent * Math.tan((normalisedAngle * Math.PI) / 180)
|
|
|
|
const sign = normalisedAngle > 90 && normalisedAngle <= 270 ? -1 : 1
|
|
|
|
return [sign * xComponent, sign * yComponent]
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getXComponent(
|
|
|
|
angleDegree: number,
|
|
|
|
yComponent: number
|
|
|
|
): [number, number] {
|
|
|
|
const normalisedAngle = ((angleDegree % 360) + 360) % 360 // between 0 and 360
|
|
|
|
let xComponent = yComponent / Math.tan((normalisedAngle * Math.PI) / 180)
|
|
|
|
const sign = normalisedAngle > 180 && normalisedAngle <= 360 ? -1 : 1
|
|
|
|
return [sign * xComponent, sign * yComponent]
|
|
|
|
}
|
2023-02-21 10:50:45 +11:00
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
function getFirstArgValuesForXYFns(callExpression: CallExpression):
|
|
|
|
| {
|
2024-08-12 15:38:42 -05:00
|
|
|
val: [Expr, Expr]
|
|
|
|
tag?: Expr
|
2024-06-24 11:45:40 -04:00
|
|
|
}
|
|
|
|
| Error {
|
2023-02-21 10:50:45 +11:00
|
|
|
// used for lineTo, line
|
|
|
|
const firstArg = callExpression.arguments[0]
|
|
|
|
if (firstArg.type === 'ArrayExpression') {
|
|
|
|
return { val: [firstArg.elements[0], firstArg.elements[1]] }
|
|
|
|
}
|
|
|
|
if (firstArg.type === 'ObjectExpression') {
|
|
|
|
const to = firstArg.properties.find((p) => p.key.name === 'to')?.value
|
|
|
|
const tag = firstArg.properties.find((p) => p.key.name === 'tag')?.value
|
|
|
|
if (to?.type === 'ArrayExpression') {
|
|
|
|
const [x, y] = to.elements
|
|
|
|
return { val: [x, y], tag }
|
|
|
|
}
|
|
|
|
}
|
2024-06-24 11:45:40 -04:00
|
|
|
return new Error('expected ArrayExpression or ObjectExpression')
|
2023-02-21 10:50:45 +11:00
|
|
|
}
|
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
function getFirstArgValuesForAngleFns(callExpression: CallExpression):
|
|
|
|
| {
|
2024-08-12 15:38:42 -05:00
|
|
|
val: [Expr, Expr]
|
|
|
|
tag?: Expr
|
2024-06-24 11:45:40 -04:00
|
|
|
}
|
|
|
|
| Error {
|
2023-02-21 10:50:45 +11:00
|
|
|
// used for angledLine, angledLineOfXLength, angledLineToX, angledLineOfYLength, angledLineToY
|
|
|
|
const firstArg = callExpression.arguments[0]
|
|
|
|
if (firstArg.type === 'ArrayExpression') {
|
|
|
|
return { val: [firstArg.elements[0], firstArg.elements[1]] }
|
|
|
|
}
|
|
|
|
if (firstArg.type === 'ObjectExpression') {
|
|
|
|
const tag = firstArg.properties.find((p) => p.key.name === 'tag')?.value
|
|
|
|
const angle = firstArg.properties.find((p) => p.key.name === 'angle')?.value
|
|
|
|
const secondArgName = ['angledLineToX', 'angledLineToY'].includes(
|
2023-09-15 11:48:23 -04:00
|
|
|
callExpression?.callee?.name as ToolTip
|
2023-02-21 10:50:45 +11:00
|
|
|
)
|
|
|
|
? 'to'
|
|
|
|
: 'length'
|
|
|
|
const length = firstArg.properties.find(
|
|
|
|
(p) => p.key.name === secondArgName
|
|
|
|
)?.value
|
|
|
|
if (angle && length) {
|
|
|
|
return { val: [angle, length], tag }
|
|
|
|
}
|
|
|
|
}
|
2024-06-24 11:45:40 -04:00
|
|
|
return new Error('expected ArrayExpression or ObjectExpression')
|
2023-02-21 10:50:45 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
function getFirstArgValuesForXYLineFns(callExpression: CallExpression): {
|
2024-08-12 15:38:42 -05:00
|
|
|
val: Expr
|
|
|
|
tag?: Expr
|
2023-02-21 10:50:45 +11:00
|
|
|
} {
|
|
|
|
// used for xLine, yLine, xLineTo, yLineTo
|
|
|
|
const firstArg = callExpression.arguments[0]
|
|
|
|
if (firstArg.type !== 'ObjectExpression') {
|
|
|
|
return { val: firstArg }
|
|
|
|
}
|
|
|
|
const tag = firstArg.properties.find((p) => p.key.name === 'tag')?.value
|
2023-03-17 08:27:40 +11:00
|
|
|
const secondArgName = ['xLineTo', 'yLineTo', 'startSketchAt'].includes(
|
2023-02-21 10:50:45 +11:00
|
|
|
// const secondArgName = ['xLineTo', 'yLineTo', 'angledLineToX', 'angledLineToY'].includes(
|
|
|
|
callExpression?.callee?.name
|
|
|
|
)
|
|
|
|
? 'to'
|
|
|
|
: 'length'
|
|
|
|
const length = firstArg.properties.find(
|
|
|
|
(p) => p.key.name === secondArgName
|
|
|
|
)?.value
|
|
|
|
if (length) {
|
|
|
|
return { val: length, tag }
|
|
|
|
}
|
2023-03-22 03:02:37 +11:00
|
|
|
console.warn('expected ArrayExpression or ObjectExpression')
|
|
|
|
return {
|
|
|
|
val: createLiteral(1),
|
|
|
|
}
|
2023-02-21 10:50:45 +11:00
|
|
|
}
|
|
|
|
|
2023-03-19 18:46:39 +11:00
|
|
|
const getAngledLineThatIntersects = (
|
|
|
|
callExp: CallExpression
|
2024-06-24 11:45:40 -04:00
|
|
|
):
|
|
|
|
| {
|
2024-08-12 15:38:42 -05:00
|
|
|
val: [Expr, Expr, Expr]
|
|
|
|
tag?: Expr
|
2024-06-24 11:45:40 -04:00
|
|
|
}
|
|
|
|
| Error => {
|
2023-03-19 18:46:39 +11:00
|
|
|
const firstArg = callExp.arguments[0]
|
|
|
|
if (firstArg.type === 'ObjectExpression') {
|
|
|
|
const tag = firstArg.properties.find((p) => p.key.name === 'tag')?.value
|
|
|
|
const angle = firstArg.properties.find((p) => p.key.name === 'angle')?.value
|
|
|
|
const offset = firstArg.properties.find(
|
|
|
|
(p) => p.key.name === 'offset'
|
|
|
|
)?.value
|
2023-04-03 16:05:25 +10:00
|
|
|
const intersectTag = firstArg.properties.find(
|
|
|
|
(p) => p.key.name === 'intersectTag'
|
|
|
|
)?.value
|
|
|
|
if (angle && offset && intersectTag) {
|
|
|
|
return { val: [angle, offset, intersectTag], tag }
|
2023-03-19 18:46:39 +11:00
|
|
|
}
|
|
|
|
}
|
2024-06-24 11:45:40 -04:00
|
|
|
return new Error('expected ArrayExpression or ObjectExpression')
|
2023-03-19 18:46:39 +11:00
|
|
|
}
|
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
export function getFirstArg(callExp: CallExpression):
|
|
|
|
| {
|
2024-08-12 15:38:42 -05:00
|
|
|
val: Expr | [Expr, Expr] | [Expr, Expr, Expr]
|
|
|
|
tag?: Expr
|
2024-06-24 11:45:40 -04:00
|
|
|
}
|
|
|
|
| Error {
|
2023-03-02 21:19:11 +11:00
|
|
|
const name = callExp?.callee?.name
|
|
|
|
if (['lineTo', 'line'].includes(name)) {
|
|
|
|
return getFirstArgValuesForXYFns(callExp)
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
[
|
|
|
|
'angledLine',
|
|
|
|
'angledLineOfXLength',
|
|
|
|
'angledLineToX',
|
|
|
|
'angledLineOfYLength',
|
|
|
|
'angledLineToY',
|
|
|
|
].includes(name)
|
|
|
|
) {
|
|
|
|
return getFirstArgValuesForAngleFns(callExp)
|
|
|
|
}
|
|
|
|
if (['xLine', 'yLine', 'xLineTo', 'yLineTo'].includes(name)) {
|
|
|
|
return getFirstArgValuesForXYLineFns(callExp)
|
|
|
|
}
|
2023-03-17 08:27:40 +11:00
|
|
|
if (['startSketchAt'].includes(name)) {
|
|
|
|
return getFirstArgValuesForXYLineFns(callExp)
|
|
|
|
}
|
2023-03-19 18:46:39 +11:00
|
|
|
if (['angledLineThatIntersects'].includes(name)) {
|
|
|
|
return getAngledLineThatIntersects(callExp)
|
|
|
|
}
|
2024-02-11 12:59:00 +11:00
|
|
|
if (['tangentialArcTo'].includes(name)) {
|
|
|
|
// TODO probably needs it's own implementation
|
|
|
|
return getFirstArgValuesForXYFns(callExp)
|
|
|
|
}
|
2024-06-24 11:45:40 -04:00
|
|
|
return new Error('unexpected call expression: ' + name)
|
2023-02-21 10:50:45 +11:00
|
|
|
}
|