Symbols overlay (#2033)
* start of overlay work
* add new icons
* add constraint symbols
* add three dots
* add primary colours
* refactor how we get constraint info for overlays
* refactor how we get constraint info for overlays
* get symbols working for tangential arc too
* extra data on constraint info
* add initial delete
* fix types and circular dep issue after rebase
* fix quirk with horz vert line overlays
* fix setup and tear down of overlays
* remove overlays that are too small
* throttle overlay updates and prove tests selecting html instead of hardcoded px coords
* initial show overaly on segment hover
* remove overlays when tool is equipped
* dounce overlay updates
* tsc
* make higlighting robust to small changes in source ranges
* replace with variable for unconstrained values, and improve styles for popover
* background tweak
* make overlays unconstrain inputs
* fix small regression
* write query for finding related tag references
* make delete segment safe
* typo
* un used imports
* test deleteSegmentFromPipeExpression
* add getConstraintInfo test
* test removeSingleConstraintInfo
* more tests
* tsc
* add tests for overlay buttons
* rename tests
* fmt
* better naming structure
* more reliablity
* more test tweaks
* fix selection test
* add delete segments with overlays tests
* dependant tag tests for segment delet
* typo
* test clean up
* fix some perf issus
* clean up
* clean up
* make things a little more dry
* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)
* trigger ci
* Make constraint hover popovers readable on light mode
* Touch up the new variable dialog
* Little touch-up to three-dot menu style
* fix highlight issue
* fmt
* use optional chain
* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)"
This reverts commit be3d61e4a3.
* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)
* disable var panel in sketch mode
* fix overlay tests after mergi in main
* test tweak
* try fix ubuntu
* fmt
* more test tweaks
* tweak
* tweaks
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
This commit is contained in:
@ -5,9 +5,16 @@ import {
|
||||
getYComponent,
|
||||
getXComponent,
|
||||
addCloseToPipe,
|
||||
getConstraintInfo,
|
||||
} from './sketch'
|
||||
import { parse, recast, initPromise } from '../wasm'
|
||||
import { getNodePathFromSourceRange } from '../queryAst'
|
||||
import {
|
||||
parse,
|
||||
recast,
|
||||
initPromise,
|
||||
SourceRange,
|
||||
CallExpression,
|
||||
} from '../wasm'
|
||||
import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst'
|
||||
import { enginelessExecutor } from '../../lib/testHelpers'
|
||||
|
||||
const eachQuad: [number, [number, number]][] = [
|
||||
@ -212,3 +219,884 @@ describe('testing addTagForSketchOnFace', () => {
|
||||
expect(recast(modifiedAst)).toBe(expectedCode)
|
||||
})
|
||||
})
|
||||
|
||||
describe('testing getConstraintInfo', () => {
|
||||
describe('object notation', () => {
|
||||
const code = `const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([0,0], %)
|
||||
|> line([3, 4], %)
|
||||
|> angledLine({
|
||||
angle: 3.14,
|
||||
length: 3.14,
|
||||
}, %)
|
||||
|> lineTo([6.14, 3.14], %)
|
||||
|> xLineTo(8, %)
|
||||
|> yLineTo(5, %)
|
||||
|> yLine(3.14, %, 'a')
|
||||
|> xLine(3.14, %)
|
||||
|> angledLineOfXLength({
|
||||
angle: 3.14,
|
||||
length: 3.14,
|
||||
}, %)
|
||||
|> angledLineOfYLength({
|
||||
angle: 30,
|
||||
length: 3,
|
||||
}, %)
|
||||
|> angledLineToX({
|
||||
angle: 12.14,
|
||||
to: 12,
|
||||
}, %)
|
||||
|> angledLineToY({
|
||||
angle: 30,
|
||||
to: 10.14,
|
||||
}, %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 3.14,
|
||||
intersectTag: 'a',
|
||||
offset: 0
|
||||
}, %)
|
||||
|> tangentialArcTo([3.14, 13.14], %)`
|
||||
const ast = parse(code)
|
||||
test.each([
|
||||
[
|
||||
'line',
|
||||
[
|
||||
{
|
||||
type: 'xRelative',
|
||||
isConstrained: false,
|
||||
value: '3',
|
||||
sourceRange: [78, 79],
|
||||
argPosition: { type: 'arrayItem', index: 0 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'line',
|
||||
},
|
||||
{
|
||||
type: 'yRelative',
|
||||
isConstrained: false,
|
||||
value: '4',
|
||||
sourceRange: [81, 82],
|
||||
argPosition: { type: 'arrayItem', index: 1 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'line',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
`angledLine(`,
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [117, 121],
|
||||
argPosition: { type: 'objectProperty', key: 'angle' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLine',
|
||||
},
|
||||
{
|
||||
type: 'length',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [135, 139],
|
||||
argPosition: { type: 'objectProperty', key: 'length' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLine',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'lineTo',
|
||||
[
|
||||
{
|
||||
type: 'xAbsolute',
|
||||
isConstrained: false,
|
||||
value: '6.14',
|
||||
sourceRange: [162, 166],
|
||||
argPosition: { type: 'arrayItem', index: 0 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'lineTo',
|
||||
},
|
||||
{
|
||||
type: 'yAbsolute',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [168, 172],
|
||||
argPosition: { type: 'arrayItem', index: 1 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'lineTo',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'xLineTo',
|
||||
[
|
||||
{
|
||||
type: 'horizontal',
|
||||
isConstrained: true,
|
||||
value: 'xLineTo',
|
||||
sourceRange: [183, 190],
|
||||
argPosition: undefined,
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'xLineTo',
|
||||
},
|
||||
{
|
||||
type: 'xAbsolute',
|
||||
isConstrained: false,
|
||||
value: '8',
|
||||
sourceRange: [191, 192],
|
||||
argPosition: { type: 'singleValue' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'xLineTo',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'yLineTo',
|
||||
[
|
||||
{
|
||||
type: 'vertical',
|
||||
isConstrained: true,
|
||||
value: 'yLineTo',
|
||||
sourceRange: [202, 209],
|
||||
argPosition: undefined,
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'yLineTo',
|
||||
},
|
||||
{
|
||||
type: 'yAbsolute',
|
||||
isConstrained: false,
|
||||
value: '5',
|
||||
sourceRange: [210, 211],
|
||||
argPosition: { type: 'singleValue' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'yLineTo',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'yLine(',
|
||||
[
|
||||
{
|
||||
type: 'vertical',
|
||||
isConstrained: true,
|
||||
value: 'yLine',
|
||||
sourceRange: [221, 226],
|
||||
argPosition: undefined,
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'yLine',
|
||||
},
|
||||
{
|
||||
type: 'yRelative',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [227, 231],
|
||||
argPosition: { type: 'singleValue' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'yLine',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'xLine(',
|
||||
[
|
||||
{
|
||||
type: 'horizontal',
|
||||
isConstrained: true,
|
||||
value: 'xLine',
|
||||
sourceRange: [246, 251],
|
||||
argPosition: undefined,
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'xLine',
|
||||
},
|
||||
{
|
||||
type: 'xRelative',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [252, 256],
|
||||
argPosition: { type: 'singleValue' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'xLine',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineOfXLength',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [299, 303],
|
||||
argPosition: { type: 'objectProperty', key: 'angle' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineOfXLength',
|
||||
},
|
||||
{
|
||||
type: 'xRelative',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [317, 321],
|
||||
argPosition: { type: 'objectProperty', key: 'length' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineOfXLength',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineOfYLength',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: false,
|
||||
value: '30',
|
||||
sourceRange: [369, 371],
|
||||
argPosition: { type: 'objectProperty', key: 'angle' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineOfYLength',
|
||||
},
|
||||
{
|
||||
type: 'yRelative',
|
||||
isConstrained: false,
|
||||
value: '3',
|
||||
sourceRange: [385, 386],
|
||||
argPosition: { type: 'objectProperty', key: 'length' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineOfYLength',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineToX',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: false,
|
||||
value: '12.14',
|
||||
sourceRange: [428, 433],
|
||||
argPosition: { type: 'objectProperty', key: 'angle' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineToX',
|
||||
},
|
||||
{
|
||||
type: 'xAbsolute',
|
||||
isConstrained: false,
|
||||
value: '12',
|
||||
sourceRange: [443, 445],
|
||||
argPosition: { type: 'objectProperty', key: 'to' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineToX',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineToY',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: false,
|
||||
value: '30',
|
||||
sourceRange: [487, 489],
|
||||
argPosition: { type: 'objectProperty', key: 'angle' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineToY',
|
||||
},
|
||||
{
|
||||
type: 'yAbsolute',
|
||||
isConstrained: false,
|
||||
value: '10.14',
|
||||
sourceRange: [499, 504],
|
||||
argPosition: { type: 'objectProperty', key: 'to' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineToY',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineThatIntersects',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [557, 561],
|
||||
argPosition: { type: 'objectProperty', key: 'angle' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineThatIntersects',
|
||||
},
|
||||
{
|
||||
type: 'intersectionOffset',
|
||||
isConstrained: false,
|
||||
value: '0',
|
||||
sourceRange: [598, 599],
|
||||
argPosition: { type: 'objectProperty', key: 'offset' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineThatIntersects',
|
||||
},
|
||||
{
|
||||
type: 'intersectionTag',
|
||||
isConstrained: false,
|
||||
value: "'a'",
|
||||
sourceRange: [581, 584],
|
||||
argPosition: {
|
||||
key: 'intersectTag',
|
||||
type: 'objectProperty',
|
||||
},
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineThatIntersects',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'tangentialArcTo',
|
||||
[
|
||||
{
|
||||
type: 'tangentialWithPrevious',
|
||||
isConstrained: true,
|
||||
value: 'tangentialArcTo',
|
||||
sourceRange: [613, 628],
|
||||
argPosition: undefined,
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'tangentialArcTo',
|
||||
},
|
||||
{
|
||||
type: 'xAbsolute',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [630, 634],
|
||||
argPosition: { type: 'arrayItem', index: 0 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'tangentialArcTo',
|
||||
},
|
||||
{
|
||||
type: 'yAbsolute',
|
||||
isConstrained: false,
|
||||
value: '13.14',
|
||||
sourceRange: [636, 641],
|
||||
argPosition: { type: 'arrayItem', index: 1 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'tangentialArcTo',
|
||||
},
|
||||
],
|
||||
],
|
||||
])('testing %s when inputs are unconstrained', (functionName, expected) => {
|
||||
const sourceRange: SourceRange = [
|
||||
code.indexOf(functionName),
|
||||
code.indexOf(functionName) + functionName.length,
|
||||
]
|
||||
const pathToNode = getNodePathFromSourceRange(ast, sourceRange)
|
||||
const callExp = getNodeFromPath<CallExpression>(
|
||||
ast,
|
||||
pathToNode,
|
||||
'CallExpression'
|
||||
).node
|
||||
const result = getConstraintInfo(callExp, code, pathToNode)
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
})
|
||||
describe('array notation', () => {
|
||||
const code = `const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([3, 4], %)
|
||||
|> angledLine([3.14, 3.14], %)
|
||||
|> lineTo([6.14, 3.14], %)
|
||||
|> xLineTo(8, %)
|
||||
|> yLineTo(5, %)
|
||||
|> yLine(3.14, %, 'a')
|
||||
|> xLine(3.14, %)
|
||||
|> angledLineOfXLength([3.14, 3.14], %)
|
||||
|> angledLineOfYLength([30, 3], %)
|
||||
|> angledLineToX([12, 12], %)
|
||||
|> angledLineToY([30, 10], %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 3.14,
|
||||
intersectTag: 'a',
|
||||
offset: 0
|
||||
}, %)
|
||||
|> tangentialArcTo([3.14, 13.14], %)`
|
||||
const ast = parse(code)
|
||||
test.each([
|
||||
[
|
||||
`angledLine(`,
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [112, 116],
|
||||
argPosition: { type: 'arrayItem', index: 0 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLine',
|
||||
},
|
||||
{
|
||||
type: 'length',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [118, 122],
|
||||
argPosition: { type: 'arrayItem', index: 1 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLine',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineOfXLength',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [278, 282],
|
||||
argPosition: { type: 'arrayItem', index: 0 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineOfXLength',
|
||||
},
|
||||
{
|
||||
type: 'xRelative',
|
||||
isConstrained: false,
|
||||
value: '3.14',
|
||||
sourceRange: [284, 288],
|
||||
argPosition: { type: 'arrayItem', index: 1 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineOfXLength',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineOfYLength',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: false,
|
||||
value: '30',
|
||||
sourceRange: [322, 324],
|
||||
argPosition: { type: 'arrayItem', index: 0 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineOfYLength',
|
||||
},
|
||||
{
|
||||
type: 'yRelative',
|
||||
isConstrained: false,
|
||||
value: '3',
|
||||
sourceRange: [326, 327],
|
||||
argPosition: { type: 'arrayItem', index: 1 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineOfYLength',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineToX',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: false,
|
||||
value: '12',
|
||||
sourceRange: [355, 357],
|
||||
argPosition: { type: 'arrayItem', index: 0 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineToX',
|
||||
},
|
||||
{
|
||||
type: 'xAbsolute',
|
||||
isConstrained: false,
|
||||
value: '12',
|
||||
sourceRange: [359, 361],
|
||||
argPosition: { type: 'arrayItem', index: 1 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineToX',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineToY',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: false,
|
||||
value: '30',
|
||||
sourceRange: [389, 391],
|
||||
argPosition: { type: 'arrayItem', index: 0 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineToY',
|
||||
},
|
||||
{
|
||||
type: 'yAbsolute',
|
||||
isConstrained: false,
|
||||
value: '10',
|
||||
sourceRange: [393, 395],
|
||||
argPosition: { type: 'arrayItem', index: 1 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineToY',
|
||||
},
|
||||
],
|
||||
],
|
||||
])('testing %s when inputs are unconstrained', (functionName, expected) => {
|
||||
const sourceRange: SourceRange = [
|
||||
code.indexOf(functionName),
|
||||
code.indexOf(functionName) + functionName.length,
|
||||
]
|
||||
const pathToNode = getNodePathFromSourceRange(ast, sourceRange)
|
||||
const callExp = getNodeFromPath<CallExpression>(
|
||||
ast,
|
||||
pathToNode,
|
||||
'CallExpression'
|
||||
).node
|
||||
const result = getConstraintInfo(callExp, code, pathToNode)
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
})
|
||||
describe('constrained', () => {
|
||||
const code = `const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([3 + 0, 4 + 0], %)
|
||||
|> angledLine({ angle: 3.14 + 0, length: 3.14 + 0 }, %)
|
||||
|> lineTo([6.14 + 0, 3.14 + 0], %)
|
||||
|> xLineTo(8 + 0, %)
|
||||
|> yLineTo(5 + 0, %)
|
||||
|> yLine(3.14 + 0, %, 'a')
|
||||
|> xLine(3.14 + 0, %)
|
||||
|> angledLineOfXLength({ angle: 3.14 + 0, length: 3.14 + 0 }, %)
|
||||
|> angledLineOfYLength({ angle: 30 + 0, length: 3 + 0 }, %)
|
||||
|> angledLineToX({ angle: 12.14 + 0, to: 12 + 0 }, %)
|
||||
|> angledLineToY({ angle: 30 + 0, to: 10.14 + 0 }, %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 3.14 + 0,
|
||||
intersectTag: 'a',
|
||||
offset: 0 + 0
|
||||
}, %)
|
||||
|> tangentialArcTo([3.14 + 0, 13.14 + 0], %)`
|
||||
const ast = parse(code)
|
||||
test.each([
|
||||
[
|
||||
'line',
|
||||
[
|
||||
{
|
||||
type: 'xRelative',
|
||||
isConstrained: true,
|
||||
value: '3 + 0',
|
||||
sourceRange: [83, 88],
|
||||
argPosition: { type: 'arrayItem', index: 0 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'line',
|
||||
},
|
||||
{
|
||||
type: 'yRelative',
|
||||
isConstrained: true,
|
||||
value: '4 + 0',
|
||||
sourceRange: [90, 95],
|
||||
argPosition: { type: 'arrayItem', index: 1 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'line',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
`angledLine(`,
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: true,
|
||||
value: '3.14 + 0',
|
||||
sourceRange: [128, 136],
|
||||
argPosition: { type: 'objectProperty', key: 'angle' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLine',
|
||||
},
|
||||
{
|
||||
type: 'length',
|
||||
isConstrained: true,
|
||||
value: '3.14 + 0',
|
||||
sourceRange: [146, 154],
|
||||
argPosition: { type: 'objectProperty', key: 'length' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLine',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'lineTo',
|
||||
[
|
||||
{
|
||||
type: 'xAbsolute',
|
||||
isConstrained: true,
|
||||
value: '6.14 + 0',
|
||||
sourceRange: [176, 184],
|
||||
argPosition: { type: 'arrayItem', index: 0 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'lineTo',
|
||||
},
|
||||
{
|
||||
type: 'yAbsolute',
|
||||
isConstrained: true,
|
||||
value: '3.14 + 0',
|
||||
sourceRange: [186, 194],
|
||||
argPosition: { type: 'arrayItem', index: 1 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'lineTo',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'xLineTo',
|
||||
[
|
||||
{
|
||||
type: 'horizontal',
|
||||
isConstrained: true,
|
||||
value: 'xLineTo',
|
||||
sourceRange: [207, 214],
|
||||
argPosition: undefined,
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'xLineTo',
|
||||
},
|
||||
{
|
||||
type: 'xAbsolute',
|
||||
isConstrained: true,
|
||||
value: '8 + 0',
|
||||
sourceRange: [215, 220],
|
||||
argPosition: { type: 'singleValue' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'xLineTo',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'yLineTo',
|
||||
[
|
||||
{
|
||||
type: 'vertical',
|
||||
isConstrained: true,
|
||||
value: 'yLineTo',
|
||||
sourceRange: [232, 239],
|
||||
argPosition: undefined,
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'yLineTo',
|
||||
},
|
||||
{
|
||||
type: 'yAbsolute',
|
||||
isConstrained: true,
|
||||
value: '5 + 0',
|
||||
sourceRange: [240, 245],
|
||||
argPosition: { type: 'singleValue' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'yLineTo',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'yLine(',
|
||||
[
|
||||
{
|
||||
type: 'vertical',
|
||||
isConstrained: true,
|
||||
value: 'yLine',
|
||||
sourceRange: [257, 262],
|
||||
argPosition: undefined,
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'yLine',
|
||||
},
|
||||
{
|
||||
type: 'yRelative',
|
||||
isConstrained: true,
|
||||
value: '3.14 + 0',
|
||||
sourceRange: [263, 271],
|
||||
argPosition: { type: 'singleValue' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'yLine',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'xLine(',
|
||||
[
|
||||
{
|
||||
type: 'horizontal',
|
||||
isConstrained: true,
|
||||
value: 'xLine',
|
||||
sourceRange: [288, 293],
|
||||
argPosition: undefined,
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'xLine',
|
||||
},
|
||||
{
|
||||
type: 'xRelative',
|
||||
isConstrained: true,
|
||||
value: '3.14 + 0',
|
||||
sourceRange: [294, 302],
|
||||
argPosition: { type: 'singleValue' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'xLine',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineOfXLength',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: true,
|
||||
value: '3.14 + 0',
|
||||
sourceRange: [343, 351],
|
||||
argPosition: { type: 'objectProperty', key: 'angle' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineOfXLength',
|
||||
},
|
||||
{
|
||||
type: 'xRelative',
|
||||
isConstrained: true,
|
||||
value: '3.14 + 0',
|
||||
sourceRange: [361, 369],
|
||||
argPosition: { type: 'objectProperty', key: 'length' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineOfXLength',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineOfYLength',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: true,
|
||||
value: '30 + 0',
|
||||
sourceRange: [412, 418],
|
||||
argPosition: { type: 'objectProperty', key: 'angle' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineOfYLength',
|
||||
},
|
||||
{
|
||||
type: 'yRelative',
|
||||
isConstrained: true,
|
||||
value: '3 + 0',
|
||||
sourceRange: [428, 433],
|
||||
argPosition: { type: 'objectProperty', key: 'length' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineOfYLength',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineToX',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: true,
|
||||
value: '12.14 + 0',
|
||||
sourceRange: [470, 479],
|
||||
argPosition: { type: 'objectProperty', key: 'angle' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineToX',
|
||||
},
|
||||
{
|
||||
type: 'xAbsolute',
|
||||
isConstrained: true,
|
||||
value: '12 + 0',
|
||||
sourceRange: [485, 491],
|
||||
argPosition: { type: 'objectProperty', key: 'to' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineToX',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineToY',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: true,
|
||||
value: '30 + 0',
|
||||
sourceRange: [528, 534],
|
||||
argPosition: { type: 'objectProperty', key: 'angle' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineToY',
|
||||
},
|
||||
{
|
||||
type: 'yAbsolute',
|
||||
isConstrained: true,
|
||||
value: '10.14 + 0',
|
||||
sourceRange: [540, 549],
|
||||
argPosition: { type: 'objectProperty', key: 'to' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineToY',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'angledLineThatIntersects',
|
||||
[
|
||||
{
|
||||
type: 'angle',
|
||||
isConstrained: true,
|
||||
value: '3.14 + 0',
|
||||
sourceRange: [606, 614],
|
||||
argPosition: { type: 'objectProperty', key: 'angle' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineThatIntersects',
|
||||
},
|
||||
{
|
||||
type: 'intersectionOffset',
|
||||
isConstrained: true,
|
||||
value: '0 + 0',
|
||||
sourceRange: [661, 666],
|
||||
argPosition: { type: 'objectProperty', key: 'offset' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineThatIntersects',
|
||||
},
|
||||
{
|
||||
type: 'intersectionTag',
|
||||
isConstrained: false,
|
||||
value: "'a'",
|
||||
sourceRange: [639, 642],
|
||||
argPosition: { key: 'intersectTag', type: 'objectProperty' },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'angledLineThatIntersects',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'tangentialArcTo',
|
||||
[
|
||||
{
|
||||
type: 'tangentialWithPrevious',
|
||||
isConstrained: true,
|
||||
value: 'tangentialArcTo',
|
||||
sourceRange: [687, 702],
|
||||
argPosition: undefined,
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'tangentialArcTo',
|
||||
},
|
||||
{
|
||||
type: 'xAbsolute',
|
||||
isConstrained: true,
|
||||
value: '3.14 + 0',
|
||||
sourceRange: [704, 712],
|
||||
argPosition: { type: 'arrayItem', index: 0 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'tangentialArcTo',
|
||||
},
|
||||
{
|
||||
type: 'yAbsolute',
|
||||
isConstrained: true,
|
||||
value: '13.14 + 0',
|
||||
sourceRange: [714, 723],
|
||||
argPosition: { type: 'arrayItem', index: 1 },
|
||||
pathToNode: expect.any(Array),
|
||||
stdLibFnName: 'tangentialArcTo',
|
||||
},
|
||||
],
|
||||
],
|
||||
])('testing %s when inputs are unconstrained', (functionName, expected) => {
|
||||
const sourceRange: SourceRange = [
|
||||
code.indexOf(functionName),
|
||||
code.indexOf(functionName) + functionName.length,
|
||||
]
|
||||
const pathToNode = getNodePathFromSourceRange(ast, sourceRange)
|
||||
const callExp = getNodeFromPath<CallExpression>(
|
||||
ast,
|
||||
pathToNode,
|
||||
'CallExpression'
|
||||
).node
|
||||
const result = getConstraintInfo(callExp, code, pathToNode)
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -11,17 +11,32 @@ import {
|
||||
Value,
|
||||
Literal,
|
||||
VariableDeclaration,
|
||||
} from '../wasm'
|
||||
} from 'lang/wasm'
|
||||
import {
|
||||
getNodeFromPath,
|
||||
getNodeFromPathCurry,
|
||||
getNodePathFromSourceRange,
|
||||
} from '../queryAst'
|
||||
import { isLiteralArrayOrStatic } from './sketchcombos'
|
||||
} from 'lang/queryAst'
|
||||
import {
|
||||
LineInputsType,
|
||||
isLiteralArrayOrStatic,
|
||||
isNotLiteralArrayOrStatic,
|
||||
} from 'lang/std/sketchcombos'
|
||||
import { toolTips, ToolTip } from '../../useStore'
|
||||
import { createPipeExpression, splitPathAtPipeExpression } from '../modifyAst'
|
||||
|
||||
import { SketchLineHelper, ModifyAstBase, TransformCallback } from './stdTypes'
|
||||
import {
|
||||
SketchLineHelper,
|
||||
ModifyAstBase,
|
||||
TransformCallback,
|
||||
ConstrainInfo,
|
||||
RawValues,
|
||||
ArrayItemInput,
|
||||
ObjectPropertyInput,
|
||||
SingleValueInput,
|
||||
VarValueKeys,
|
||||
ArrayOrObjItemInput,
|
||||
} from 'lang/std/stdTypes'
|
||||
|
||||
import {
|
||||
createLiteral,
|
||||
@ -32,8 +47,8 @@ import {
|
||||
mutateArrExp,
|
||||
mutateObjExpProp,
|
||||
findUniqueName,
|
||||
} from '../modifyAst'
|
||||
import { roundOff, getLength, getAngle } from '../../lib/utils'
|
||||
} from 'lang/modifyAst'
|
||||
import { roundOff, getLength, getAngle } from 'lib/utils'
|
||||
import { perpendicularDistance } from 'sketch-helpers'
|
||||
|
||||
export type Coords2d = [number, number]
|
||||
@ -85,6 +100,210 @@ export function createFirstArg(
|
||||
throw new Error('all sketch line types should have been covered')
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
export const lineTo: SketchLineHelper = {
|
||||
add: ({
|
||||
node,
|
||||
@ -114,6 +333,10 @@ export const lineTo: SketchLineHelper = {
|
||||
if (replaceExisting && createCallback) {
|
||||
const { callExp, valueUsedInTransform } = createCallback(
|
||||
newVals,
|
||||
arrayRawValuesHelper([
|
||||
[createLiteral(roundOff(to[0], 2)), 'xAbsolute'],
|
||||
[createLiteral(roundOff(to[1], 2)), 'yAbsolute'],
|
||||
]),
|
||||
referencedSegment
|
||||
)
|
||||
pipe.body[callIndex] = callExp
|
||||
@ -150,6 +373,14 @@ export const lineTo: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
getConstraintInfo: (callExp, ...args) =>
|
||||
commonConstraintInfoHelper(
|
||||
callExp,
|
||||
['xAbsolute', 'yAbsolute'],
|
||||
'lineTo',
|
||||
[{ arrayInput: 0 }, { arrayInput: 1 }],
|
||||
...args
|
||||
),
|
||||
}
|
||||
|
||||
export const line: SketchLineHelper = {
|
||||
@ -207,6 +438,10 @@ export const line: SketchLineHelper = {
|
||||
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
||||
const { callExp, valueUsedInTransform } = createCallback(
|
||||
[newXVal, newYVal],
|
||||
arrayRawValuesHelper([
|
||||
[createLiteral(roundOff(to[0] - from[0], 2)), 'xRelative'],
|
||||
[createLiteral(roundOff(to[1] - from[1], 2)), 'yRelative'],
|
||||
]),
|
||||
referencedSegment
|
||||
)
|
||||
pipe.body[callIndex] = callExp
|
||||
@ -266,6 +501,14 @@ export const line: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
getConstraintInfo: (callExp, ...args) =>
|
||||
commonConstraintInfoHelper(
|
||||
callExp,
|
||||
['xRelative', 'yRelative'],
|
||||
'line',
|
||||
[{ arrayInput: 0 }, { arrayInput: 1 }],
|
||||
...args
|
||||
),
|
||||
}
|
||||
|
||||
export const xLineTo: SketchLineHelper = {
|
||||
@ -278,7 +521,10 @@ export const xLineTo: SketchLineHelper = {
|
||||
|
||||
if (replaceExisting && createCallback) {
|
||||
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
||||
const { callExp, valueUsedInTransform } = createCallback([newVal, newVal])
|
||||
const { callExp, valueUsedInTransform } = createCallback(
|
||||
[newVal, newVal],
|
||||
singleRawValueHelper(newVal, 'xAbsolute')
|
||||
)
|
||||
pipe.body[callIndex] = callExp
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
@ -314,6 +560,14 @@ export const xLineTo: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
getConstraintInfo: (callExp, ...args) =>
|
||||
horzVertConstraintInfoHelper(
|
||||
callExp,
|
||||
['horizontal', 'xAbsolute'],
|
||||
'xLineTo',
|
||||
'singleValue',
|
||||
...args
|
||||
),
|
||||
}
|
||||
|
||||
export const yLineTo: SketchLineHelper = {
|
||||
@ -326,7 +580,10 @@ export const yLineTo: SketchLineHelper = {
|
||||
|
||||
if (replaceExisting && createCallback) {
|
||||
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
||||
const { callExp, valueUsedInTransform } = createCallback([newVal, newVal])
|
||||
const { callExp, valueUsedInTransform } = createCallback(
|
||||
[newVal, newVal],
|
||||
singleRawValueHelper(newVal, 'yAbsolute')
|
||||
)
|
||||
pipe.body[callIndex] = callExp
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
@ -362,6 +619,14 @@ export const yLineTo: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
getConstraintInfo: (callExp, ...args) =>
|
||||
horzVertConstraintInfoHelper(
|
||||
callExp,
|
||||
['vertical', 'yAbsolute'],
|
||||
'yLineTo',
|
||||
'singleValue',
|
||||
...args
|
||||
),
|
||||
}
|
||||
|
||||
export const xLine: SketchLineHelper = {
|
||||
@ -375,10 +640,10 @@ export const xLine: SketchLineHelper = {
|
||||
|
||||
if (replaceExisting && createCallback) {
|
||||
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
||||
const { callExp, valueUsedInTransform } = createCallback([
|
||||
firstArg,
|
||||
firstArg,
|
||||
])
|
||||
const { callExp, valueUsedInTransform } = createCallback(
|
||||
[firstArg, firstArg],
|
||||
singleRawValueHelper(firstArg, 'xRelative')
|
||||
)
|
||||
pipe.body[callIndex] = callExp
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
@ -412,6 +677,14 @@ export const xLine: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
getConstraintInfo: (callExp, ...args) =>
|
||||
horzVertConstraintInfoHelper(
|
||||
callExp,
|
||||
['horizontal', 'xRelative'],
|
||||
'xLine',
|
||||
'singleValue',
|
||||
...args
|
||||
),
|
||||
}
|
||||
|
||||
export const yLine: SketchLineHelper = {
|
||||
@ -422,7 +695,10 @@ export const yLine: SketchLineHelper = {
|
||||
const newVal = createLiteral(roundOff(to[1] - from[1], 2))
|
||||
if (replaceExisting && createCallback) {
|
||||
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
||||
const { callExp, valueUsedInTransform } = createCallback([newVal, newVal])
|
||||
const { callExp, valueUsedInTransform } = createCallback(
|
||||
[newVal, newVal],
|
||||
singleRawValueHelper(newVal, 'yRelative')
|
||||
)
|
||||
pipe.body[callIndex] = callExp
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
@ -456,6 +732,14 @@ export const yLine: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
getConstraintInfo: (callExp, ...args) =>
|
||||
horzVertConstraintInfoHelper(
|
||||
callExp,
|
||||
['vertical', 'yRelative'],
|
||||
'yLine',
|
||||
'singleValue',
|
||||
...args
|
||||
),
|
||||
}
|
||||
|
||||
export const tangentialArcTo: SketchLineHelper = {
|
||||
@ -485,6 +769,10 @@ export const tangentialArcTo: SketchLineHelper = {
|
||||
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
||||
const { callExp, valueUsedInTransform } = createCallback(
|
||||
[toX, toY],
|
||||
arrayRawValuesHelper([
|
||||
[createLiteral(roundOff(to[0], 2)), 'xAbsolute'],
|
||||
[createLiteral(roundOff(to[1], 2)), 'yAbsolute'],
|
||||
]),
|
||||
referencedSegment
|
||||
)
|
||||
pipe.body[callIndex] = callExp
|
||||
@ -534,8 +822,54 @@ export const tangentialArcTo: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
// TODO copy-paste from angledLine
|
||||
addTag: addTag(),
|
||||
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
|
||||
),
|
||||
]
|
||||
},
|
||||
}
|
||||
export const angledLine: SketchLineHelper = {
|
||||
add: ({
|
||||
@ -562,6 +896,10 @@ export const angledLine: SketchLineHelper = {
|
||||
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
||||
const { callExp, valueUsedInTransform } = createCallback(
|
||||
[newAngleVal, newLengthVal],
|
||||
arrOrObjectRawValuesHelper([
|
||||
[newAngleVal, 'angle', 'angle'],
|
||||
[newLengthVal, 'length', 'length'],
|
||||
]),
|
||||
referencedSegment
|
||||
)
|
||||
pipe.body[callIndex] = callExp
|
||||
@ -602,6 +940,17 @@ export const angledLine: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
getConstraintInfo: (callExp, ...args) =>
|
||||
commonConstraintInfoHelper(
|
||||
callExp,
|
||||
['angle', 'length'],
|
||||
'angledLine',
|
||||
[
|
||||
{ arrayInput: 0, objInput: 'angle' },
|
||||
{ arrayInput: 1, objInput: 'length' },
|
||||
],
|
||||
...args
|
||||
),
|
||||
}
|
||||
|
||||
export const angledLineOfXLength: SketchLineHelper = {
|
||||
@ -631,7 +980,13 @@ export const angledLineOfXLength: SketchLineHelper = {
|
||||
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
||||
const xLength = createLiteral(roundOff(Math.abs(from[0] - to[0]), 2) || 0.1)
|
||||
const newLine = createCallback
|
||||
? createCallback([angle, xLength]).callExp
|
||||
? createCallback(
|
||||
[angle, xLength],
|
||||
arrOrObjectRawValuesHelper([
|
||||
[angle, 'angle', 'angle'],
|
||||
[xLength, 'xRelative', 'length'],
|
||||
])
|
||||
).callExp
|
||||
: createCallExpression('angledLineOfXLength', [
|
||||
createArrayExpression([angle, xLength]),
|
||||
createPipeSubstitution(),
|
||||
@ -675,6 +1030,17 @@ export const angledLineOfXLength: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
getConstraintInfo: (callExp, ...args) =>
|
||||
commonConstraintInfoHelper(
|
||||
callExp,
|
||||
['angle', 'xRelative'],
|
||||
'angledLineOfXLength',
|
||||
[
|
||||
{ arrayInput: 0, objInput: 'angle' },
|
||||
{ arrayInput: 1, objInput: 'length' },
|
||||
],
|
||||
...args
|
||||
),
|
||||
}
|
||||
|
||||
export const angledLineOfYLength: SketchLineHelper = {
|
||||
@ -705,7 +1071,13 @@ export const angledLineOfYLength: SketchLineHelper = {
|
||||
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
||||
const yLength = createLiteral(roundOff(Math.abs(from[1] - to[1]), 2) || 0.1)
|
||||
const newLine = createCallback
|
||||
? createCallback([angle, yLength]).callExp
|
||||
? createCallback(
|
||||
[angle, yLength],
|
||||
arrOrObjectRawValuesHelper([
|
||||
[angle, 'angle', 'angle'],
|
||||
[yLength, 'yRelative', 'length'],
|
||||
])
|
||||
).callExp
|
||||
: createCallExpression('angledLineOfYLength', [
|
||||
createArrayExpression([angle, yLength]),
|
||||
createPipeSubstitution(),
|
||||
@ -749,6 +1121,17 @@ export const angledLineOfYLength: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
getConstraintInfo: (callExp, ...args) =>
|
||||
commonConstraintInfoHelper(
|
||||
callExp,
|
||||
['angle', 'yRelative'],
|
||||
'angledLineOfYLength',
|
||||
[
|
||||
{ arrayInput: 0, objInput: 'angle' },
|
||||
{ arrayInput: 1, objInput: 'length' },
|
||||
],
|
||||
...args
|
||||
),
|
||||
}
|
||||
|
||||
export const angledLineToX: SketchLineHelper = {
|
||||
@ -772,6 +1155,10 @@ export const angledLineToX: SketchLineHelper = {
|
||||
if (replaceExisting && createCallback) {
|
||||
const { callExp, valueUsedInTransform } = createCallback(
|
||||
[angle, xArg],
|
||||
arrOrObjectRawValuesHelper([
|
||||
[angle, 'angle', 'angle'],
|
||||
[xArg, 'xAbsolute', 'to'],
|
||||
]),
|
||||
referencedSegment
|
||||
)
|
||||
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
||||
@ -818,6 +1205,17 @@ export const angledLineToX: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
getConstraintInfo: (callExp, ...args) =>
|
||||
commonConstraintInfoHelper(
|
||||
callExp,
|
||||
['angle', 'xAbsolute'],
|
||||
'angledLineToX',
|
||||
[
|
||||
{ arrayInput: 0, objInput: 'angle' },
|
||||
{ arrayInput: 1, objInput: 'to' },
|
||||
],
|
||||
...args
|
||||
),
|
||||
}
|
||||
|
||||
export const angledLineToY: SketchLineHelper = {
|
||||
@ -842,6 +1240,10 @@ export const angledLineToY: SketchLineHelper = {
|
||||
if (replaceExisting && createCallback) {
|
||||
const { callExp, valueUsedInTransform } = createCallback(
|
||||
[angle, yArg],
|
||||
arrOrObjectRawValuesHelper([
|
||||
[angle, 'angle', 'angle'],
|
||||
[yArg, 'yAbsolute', 'to'],
|
||||
]),
|
||||
referencedSegment
|
||||
)
|
||||
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
||||
@ -888,6 +1290,17 @@ export const angledLineToY: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
getConstraintInfo: (callExp, ...args) =>
|
||||
commonConstraintInfoHelper(
|
||||
callExp,
|
||||
['angle', 'yAbsolute'],
|
||||
'angledLineToY',
|
||||
[
|
||||
{ arrayInput: 0, objInput: 'angle' },
|
||||
{ arrayInput: 1, objInput: 'to' },
|
||||
],
|
||||
...args
|
||||
),
|
||||
}
|
||||
|
||||
export const angledLineThatIntersects: SketchLineHelper = {
|
||||
@ -921,7 +1334,23 @@ export const angledLineThatIntersects: SketchLineHelper = {
|
||||
)
|
||||
|
||||
if (replaceExisting && createCallback) {
|
||||
const { callExp, valueUsedInTransform } = createCallback([angle, offset])
|
||||
const { callExp, valueUsedInTransform } = createCallback(
|
||||
[angle, offset],
|
||||
[
|
||||
{
|
||||
type: 'objectProperty',
|
||||
key: 'angle',
|
||||
value: angle,
|
||||
argType: 'angle',
|
||||
},
|
||||
{
|
||||
type: 'objectProperty',
|
||||
key: 'offset',
|
||||
value: offset,
|
||||
argType: 'intersectionOffset',
|
||||
},
|
||||
]
|
||||
)
|
||||
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
||||
pipe.body[callIndex] = callExp
|
||||
return {
|
||||
@ -976,7 +1405,86 @@ export const angledLineThatIntersects: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTag(), // TODO might be wrong
|
||||
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) {
|
||||
const tag = firstArg.properties[intersectTag]?.value
|
||||
const pathToTagProp: PathToNode = [
|
||||
...pathToObjectExp,
|
||||
[intersectTag, 'index'],
|
||||
['value', 'Property'],
|
||||
]
|
||||
returnVal.push(
|
||||
constrainInfo(
|
||||
'intersectionTag',
|
||||
isNotLiteralArrayOrStatic(tag),
|
||||
code.slice(tag.start, tag.end),
|
||||
'angledLineThatIntersects',
|
||||
'intersectTag',
|
||||
[tag.start, tag.end],
|
||||
pathToTagProp
|
||||
)
|
||||
)
|
||||
}
|
||||
return returnVal
|
||||
},
|
||||
}
|
||||
|
||||
export const updateStartProfileAtArgs: SketchLineHelper['updateArgs'] = ({
|
||||
@ -1048,6 +1556,20 @@ export function changeSketchArguments(
|
||||
throw new Error(`not a sketch line helper: ${callExpression?.callee?.name}`)
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
export function compareVec2Epsilon(
|
||||
vec1: [number, number],
|
||||
vec2: [number, number],
|
||||
@ -1162,7 +1684,7 @@ export function addCloseToPipe({
|
||||
export function replaceSketchLine({
|
||||
node,
|
||||
programMemory,
|
||||
sourceRange,
|
||||
pathToNode: _pathToNode,
|
||||
fnName,
|
||||
to,
|
||||
from,
|
||||
@ -1171,7 +1693,7 @@ export function replaceSketchLine({
|
||||
}: {
|
||||
node: Program
|
||||
programMemory: ProgramMemory
|
||||
sourceRange: SourceRange
|
||||
pathToNode: PathToNode
|
||||
fnName: ToolTip
|
||||
to: [number, number]
|
||||
from: [number, number]
|
||||
@ -1185,13 +1707,12 @@ export function replaceSketchLine({
|
||||
if (![...toolTips, 'intersect'].includes(fnName))
|
||||
throw new Error('not a tooltip')
|
||||
const _node = { ...node }
|
||||
const thePath = getNodePathFromSourceRange(_node, sourceRange)
|
||||
|
||||
const { add } = sketchLineHelperMap[fnName]
|
||||
const { modifiedAst, valueUsedInTransform, pathToNode } = add({
|
||||
node: _node,
|
||||
previousProgramMemory: programMemory,
|
||||
pathToNode: thePath,
|
||||
pathToNode: _pathToNode,
|
||||
referencedSegment,
|
||||
to,
|
||||
from,
|
||||
@ -1406,5 +1927,5 @@ export function getFirstArg(callExp: CallExpression): {
|
||||
// TODO probably needs it's own implementation
|
||||
return getFirstArgValuesForXYFns(callExp)
|
||||
}
|
||||
throw new Error('unexpected call expression')
|
||||
throw new Error('unexpected call expression: ' + name)
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { getNodeFromPath } from 'lang/queryAst'
|
||||
import { ToolTip, toolTips } from '../../useStore'
|
||||
import {
|
||||
Program,
|
||||
@ -6,8 +7,27 @@ import {
|
||||
SketchGroup,
|
||||
SourceRange,
|
||||
Path,
|
||||
PathToNode,
|
||||
Value,
|
||||
} from '../wasm'
|
||||
|
||||
export function getSketchSegmentFromPathToNode(
|
||||
sketchGroup: SketchGroup,
|
||||
ast: Program,
|
||||
pathToNode: PathToNode
|
||||
): {
|
||||
segment: SketchGroup['value'][number]
|
||||
index: number
|
||||
} {
|
||||
// TODO: once pathTodNode is stored on program memory as part of execution,
|
||||
// we can check if the pathToNode matches the pathToNode of the sketchGroup.
|
||||
// For now we fall back to the sourceRange
|
||||
const node = getNodeFromPath<Value>(ast, pathToNode).node
|
||||
if (!node || typeof node.start !== 'number' || !node.end)
|
||||
throw new Error('no node found')
|
||||
const sourceRange: SourceRange = [node.start, node.end]
|
||||
return getSketchSegmentFromSourceRange(sketchGroup, sourceRange)
|
||||
}
|
||||
export function getSketchSegmentFromSourceRange(
|
||||
sketchGroup: SketchGroup,
|
||||
[rangeStart, rangeEnd]: SourceRange
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { TransformCallback } from './stdTypes'
|
||||
import { TransformCallback, VarValues } from './stdTypes'
|
||||
import { toolTips, ToolTip } from '../../useStore'
|
||||
import { Selections, Selection } from 'lib/selections'
|
||||
import {
|
||||
@ -17,6 +17,7 @@ import {
|
||||
isValueZero,
|
||||
} from '../queryAst'
|
||||
import {
|
||||
createArrayExpression,
|
||||
createBinaryExpression,
|
||||
createBinaryExpressionWithUnary,
|
||||
createCallExpression,
|
||||
@ -27,17 +28,27 @@ import {
|
||||
createUnaryExpression,
|
||||
giveSketchFnCallTag,
|
||||
} from '../modifyAst'
|
||||
import { createFirstArg, getFirstArg, replaceSketchLine } from './sketch'
|
||||
import { getSketchSegmentFromSourceRange } from './sketchConstraints'
|
||||
import {
|
||||
createFirstArg,
|
||||
getConstraintInfo,
|
||||
getFirstArg,
|
||||
replaceSketchLine,
|
||||
} from './sketch'
|
||||
import {
|
||||
getSketchSegmentFromPathToNode,
|
||||
getSketchSegmentFromSourceRange,
|
||||
} from './sketchConstraints'
|
||||
import { getAngle, roundOff, normaliseAngle } from '../../lib/utils'
|
||||
|
||||
type LineInputsType =
|
||||
export type LineInputsType =
|
||||
| 'xAbsolute'
|
||||
| 'yAbsolute'
|
||||
| 'xRelative'
|
||||
| 'yRelative'
|
||||
| 'angle'
|
||||
| 'length'
|
||||
| 'intersectionOffset'
|
||||
| 'intersectionTag'
|
||||
|
||||
export type ConstraintType =
|
||||
| 'equalLength'
|
||||
@ -70,6 +81,31 @@ function createCallWrapper(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
}
|
||||
}
|
||||
|
||||
function intersectCallWrapper({
|
||||
fnName,
|
||||
angleVal,
|
||||
@ -106,6 +142,7 @@ function intersectCallWrapper({
|
||||
export type TransformInfo = {
|
||||
tooltip: ToolTip
|
||||
createNode: (a: {
|
||||
varValues: VarValues
|
||||
varValA: Value // x / angle
|
||||
varValB: Value // y / length or x y for angledLineOfXlength etc
|
||||
referenceSegName: string
|
||||
@ -145,7 +182,7 @@ const basicAngledLineCreateNode =
|
||||
varValToUse: 'ang' | 'len' | 'none' = 'none'
|
||||
): TransformInfo['createNode'] =>
|
||||
({ referenceSegName, tag, forceValueUsedInTransform, varValA, varValB }) =>
|
||||
(args, path) => {
|
||||
(args, _, path) => {
|
||||
const refAng = path ? getAngle(path?.from, path?.to) : 0
|
||||
const nonForcedAng =
|
||||
varValToUse === 'ang'
|
||||
@ -252,7 +289,7 @@ const setHorzVertDistanceCreateNode =
|
||||
index = xOrY === 'x' ? 0 : 1
|
||||
): TransformInfo['createNode'] =>
|
||||
({ referenceSegName, tag, forceValueUsedInTransform }) => {
|
||||
return (args, referencedSegment) => {
|
||||
return (args, _, referencedSegment) => {
|
||||
const valueUsedInTransform = roundOff(
|
||||
getArgLiteralVal(args?.[index]) - (referencedSegment?.to?.[index] || 0),
|
||||
2
|
||||
@ -279,7 +316,7 @@ const setHorzVertDistanceForAngleLineCreateNode =
|
||||
index = xOrY === 'x' ? 0 : 1
|
||||
): TransformInfo['createNode'] =>
|
||||
({ referenceSegName, tag, forceValueUsedInTransform, varValA }) => {
|
||||
return (args, referencedSegment) => {
|
||||
return (args, _, referencedSegment) => {
|
||||
const valueUsedInTransform = roundOff(
|
||||
getArgLiteralVal(args?.[1]) - (referencedSegment?.to?.[index] || 0),
|
||||
2
|
||||
@ -305,7 +342,7 @@ const setAbsDistanceCreateNode =
|
||||
index = xOrY === 'x' ? 0 : 1
|
||||
): TransformInfo['createNode'] =>
|
||||
({ tag, forceValueUsedInTransform }) => {
|
||||
return (args, referencedSegment) => {
|
||||
return (args, _, referencedSegment) => {
|
||||
const valueUsedInTransform = roundOff(
|
||||
getArgLiteralVal(args?.[index]) - (referencedSegment?.to?.[index] || 0),
|
||||
2
|
||||
@ -335,7 +372,7 @@ const setAbsDistanceForAngleLineCreateNode =
|
||||
index = xOrY === 'x' ? 0 : 1
|
||||
): TransformInfo['createNode'] =>
|
||||
({ tag, forceValueUsedInTransform, varValA }) => {
|
||||
return (args, referencedSegment) => {
|
||||
return (args) => {
|
||||
const valueUsedInTransform = roundOff(getArgLiteralVal(args?.[1]), 2)
|
||||
const val =
|
||||
(forceValueUsedInTransform as BinaryPart) ||
|
||||
@ -352,7 +389,7 @@ const setAbsDistanceForAngleLineCreateNode =
|
||||
const setHorVertDistanceForXYLines =
|
||||
(xOrY: 'x' | 'y'): TransformInfo['createNode'] =>
|
||||
({ referenceSegName, tag, forceValueUsedInTransform }) => {
|
||||
return (args, referencedSegment) => {
|
||||
return (args, _, referencedSegment) => {
|
||||
const index = xOrY === 'x' ? 0 : 1
|
||||
const valueUsedInTransform = roundOff(
|
||||
getArgLiteralVal(args?.[index]) - (referencedSegment?.to?.[index] || 0),
|
||||
@ -381,7 +418,7 @@ const setHorzVertDistanceConstraintLineCreateNode =
|
||||
varVal,
|
||||
])
|
||||
|
||||
return (args, referencedSegment) => {
|
||||
return (args, _, referencedSegment) => {
|
||||
const makeBinExp = (index: 0 | 1) => {
|
||||
const arg = getArgLiteralVal(args?.[index])
|
||||
return createBinaryExpressionWithUnary([
|
||||
@ -449,7 +486,7 @@ const setAngledIntersectForAngledLines: TransformInfo['createNode'] =
|
||||
const setAngleBetweenCreateNode =
|
||||
(tranformToType: 'none' | 'xAbs' | 'yAbs'): TransformInfo['createNode'] =>
|
||||
({ referenceSegName, tag, forceValueUsedInTransform, varValA, varValB }) => {
|
||||
return (args, referencedSegment) => {
|
||||
return (args, _, referencedSegment) => {
|
||||
const refAngle = referencedSegment
|
||||
? getAngle(referencedSegment?.from, referencedSegment?.to)
|
||||
: 0
|
||||
@ -1168,6 +1205,92 @@ export function getRemoveConstraintsTransform(
|
||||
return false
|
||||
}
|
||||
|
||||
export function removeSingleConstraint({
|
||||
pathToCallExp,
|
||||
arrayIndex,
|
||||
objectProperty,
|
||||
ast,
|
||||
}: {
|
||||
pathToCallExp: PathToNode
|
||||
arrayIndex?: number
|
||||
objectProperty?: string
|
||||
ast: Program
|
||||
}): TransformInfo | false {
|
||||
const callExp = getNodeFromPath<CallExpression>(
|
||||
ast,
|
||||
pathToCallExp,
|
||||
'CallExpression'
|
||||
).node
|
||||
if (callExp.type !== 'CallExpression') throw new Error('Invalid node type')
|
||||
|
||||
const transform: TransformInfo = {
|
||||
tooltip: callExp.callee.name as any,
|
||||
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(
|
||||
callExp.callee.name as any,
|
||||
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(
|
||||
callExp.callee.name as any,
|
||||
createArrayExpression(values),
|
||||
tag
|
||||
)
|
||||
}
|
||||
|
||||
// if (typeof arrayIndex !== 'number' || !objectProperty) must be single value input xLine, yLineTo etc
|
||||
|
||||
return createCallWrapper(
|
||||
callExp.callee.name as any,
|
||||
rawValues[0].value,
|
||||
tag
|
||||
)
|
||||
},
|
||||
}
|
||||
return transform
|
||||
}
|
||||
|
||||
function getTransformMapPath(
|
||||
sketchFnExp: CallExpression,
|
||||
constraintType: ConstraintType
|
||||
@ -1392,7 +1515,7 @@ export function transformAstSketchLines({
|
||||
referencedSegmentRange,
|
||||
}: {
|
||||
ast: Program
|
||||
selectionRanges: Selections
|
||||
selectionRanges: Selections | PathToNode[]
|
||||
transformInfos: TransformInfo[]
|
||||
programMemory: ProgramMemory
|
||||
referenceSegName: string
|
||||
@ -1408,15 +1531,13 @@ export function transformAstSketchLines({
|
||||
let _valueUsedInTransform // TODO should this be an array?
|
||||
const pathToNodeMap: PathToNodeMap = {}
|
||||
|
||||
selectionRanges.codeBasedSelections.forEach(({ range }, index) => {
|
||||
const processSelection = (_pathToNode: PathToNode, index: number) => {
|
||||
const callBack = transformInfos?.[index].createNode
|
||||
const transformTo = transformInfos?.[index].tooltip
|
||||
|
||||
if (!callBack || !transformTo) throw new Error('no callback helper')
|
||||
|
||||
const getNode = getNodeFromPathCurry(
|
||||
node,
|
||||
getNodePathFromSourceRange(node, range)
|
||||
)
|
||||
const getNode = getNodeFromPathCurry(node, _pathToNode)
|
||||
|
||||
const callExp = getNode<CallExpression>('CallExpression')?.node
|
||||
const varDec = getNode<VariableDeclarator>('VariableDeclarator').node
|
||||
@ -1436,11 +1557,47 @@ export function transformAstSketchLines({
|
||||
''
|
||||
const [varValA, varValB] = Array.isArray(val) ? val : [val, val]
|
||||
|
||||
const varValues: VarValues = []
|
||||
|
||||
getConstraintInfo(callExp, '', _pathToNode).forEach((a) => {
|
||||
if (
|
||||
a.type === 'tangentialWithPrevious' ||
|
||||
a.type === 'horizontal' ||
|
||||
a.type === 'vertical'
|
||||
)
|
||||
return
|
||||
if (a?.argPosition?.type === 'arrayItem') {
|
||||
varValues.push({
|
||||
type: 'arrayItem',
|
||||
index: a.argPosition.index,
|
||||
value: getNodeFromPath<Value>(ast, a.pathToNode).node,
|
||||
argType: a.type,
|
||||
})
|
||||
} else if (a?.argPosition?.type === 'objectProperty') {
|
||||
varValues.push({
|
||||
type: 'objectProperty',
|
||||
key: a.argPosition.key,
|
||||
value: getNodeFromPath<Value>(ast, a.pathToNode).node,
|
||||
argType: a.type,
|
||||
})
|
||||
} else if (a?.argPosition?.type === 'singleValue') {
|
||||
varValues.push({
|
||||
type: 'singleValue',
|
||||
argType: a.type,
|
||||
value: getNodeFromPath<Value>(ast, a.pathToNode).node,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const varName = varDec.id.name
|
||||
const sketchGroup = programMemory.root?.[varName]
|
||||
if (!sketchGroup || sketchGroup.type !== 'SketchGroup')
|
||||
throw new Error('not a sketch group')
|
||||
const seg = getSketchSegmentFromSourceRange(sketchGroup, range).segment
|
||||
const seg = getSketchSegmentFromPathToNode(
|
||||
sketchGroup,
|
||||
ast,
|
||||
_pathToNode
|
||||
).segment
|
||||
const referencedSegment = referencedSegmentRange
|
||||
? getSketchSegmentFromSourceRange(sketchGroup, referencedSegmentRange)
|
||||
.segment
|
||||
@ -1450,13 +1607,14 @@ export function transformAstSketchLines({
|
||||
{
|
||||
node: node,
|
||||
programMemory,
|
||||
sourceRange: range,
|
||||
pathToNode: _pathToNode,
|
||||
referencedSegment,
|
||||
fnName: transformTo || (callExp.callee.name as ToolTip),
|
||||
to,
|
||||
from,
|
||||
createCallback: callBack({
|
||||
referenceSegName: _referencedSegmentName,
|
||||
varValues,
|
||||
varValA,
|
||||
varValB,
|
||||
tag: callBackTag,
|
||||
@ -1470,7 +1628,16 @@ export function transformAstSketchLines({
|
||||
if (typeof valueUsedInTransform === 'number') {
|
||||
_valueUsedInTransform = valueUsedInTransform
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if ('codeBasedSelections' in selectionRanges) {
|
||||
selectionRanges.codeBasedSelections.forEach(({ range }, index) =>
|
||||
processSelection(getNodePathFromSourceRange(node, range), index)
|
||||
)
|
||||
} else {
|
||||
selectionRanges.forEach(processSelection)
|
||||
}
|
||||
|
||||
return {
|
||||
modifiedAst: node,
|
||||
valueUsedInTransform: _valueUsedInTransform,
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { ToolTip } from 'useStore'
|
||||
import {
|
||||
ProgramMemory,
|
||||
Path,
|
||||
@ -5,9 +6,11 @@ import {
|
||||
Program,
|
||||
Value,
|
||||
PathToNode,
|
||||
CallExpression,
|
||||
Literal,
|
||||
} from '../wasm'
|
||||
import { ToolTip } from '../../useStore'
|
||||
import { EngineCommandManager } from './engineConnection'
|
||||
import { LineInputsType } from './sketchcombos'
|
||||
|
||||
export interface InternalFirstArg {
|
||||
programMemory: ProgramMemory
|
||||
@ -44,16 +47,70 @@ interface updateArgs extends ModifyAstBase {
|
||||
to: [number, number]
|
||||
}
|
||||
|
||||
export type VarValueKeys = 'angle' | 'offset' | 'length' | 'to' | 'intersectTag'
|
||||
export interface SingleValueInput<T> {
|
||||
type: 'singleValue'
|
||||
argType: LineInputsType
|
||||
value: T
|
||||
}
|
||||
export interface ArrayItemInput<T> {
|
||||
type: 'arrayItem'
|
||||
index: 0 | 1
|
||||
argType: LineInputsType
|
||||
value: T
|
||||
}
|
||||
export interface ObjectPropertyInput<T> {
|
||||
type: 'objectProperty'
|
||||
key: VarValueKeys
|
||||
argType: LineInputsType
|
||||
value: T
|
||||
}
|
||||
|
||||
export interface ArrayOrObjItemInput<T> {
|
||||
type: 'arrayOrObjItem'
|
||||
key: VarValueKeys
|
||||
index: 0 | 1
|
||||
argType: LineInputsType
|
||||
value: T
|
||||
}
|
||||
|
||||
export type _VarValue<T> =
|
||||
| SingleValueInput<T>
|
||||
| ArrayItemInput<T>
|
||||
| ObjectPropertyInput<T>
|
||||
| ArrayOrObjItemInput<T>
|
||||
|
||||
export type VarValue = _VarValue<Value>
|
||||
export type RawValue = _VarValue<Literal>
|
||||
|
||||
export type VarValues = Array<VarValue>
|
||||
export type RawValues = Array<RawValue>
|
||||
|
||||
type SimplifiedVarValue =
|
||||
| {
|
||||
type: 'singleValue'
|
||||
}
|
||||
| { type: 'arrayItem'; index: 0 | 1 }
|
||||
| { type: 'objectProperty'; key: VarValueKeys }
|
||||
|
||||
export type TransformCallback = (
|
||||
args: [Value, Value],
|
||||
literalValues: RawValues,
|
||||
referencedSegment?: Path
|
||||
) => {
|
||||
callExp: Value
|
||||
valueUsedInTransform?: number
|
||||
}
|
||||
|
||||
export type SketchCallTransfromMap = {
|
||||
[key in ToolTip]: TransformCallback
|
||||
export interface ConstrainInfo {
|
||||
stdLibFnName: ToolTip
|
||||
type: LineInputsType | 'vertical' | 'horizontal' | 'tangentialWithPrevious'
|
||||
isConstrained: boolean
|
||||
sourceRange: SourceRange
|
||||
pathToNode: PathToNode
|
||||
value: string
|
||||
calculatedValue?: any
|
||||
argPosition?: SimplifiedVarValue
|
||||
}
|
||||
|
||||
export interface SketchLineHelper {
|
||||
@ -70,4 +127,9 @@ export interface SketchLineHelper {
|
||||
modifiedAst: Program
|
||||
tag: string
|
||||
}
|
||||
getConstraintInfo: (
|
||||
callExp: CallExpression,
|
||||
code: string,
|
||||
pathToNode: PathToNode
|
||||
) => ConstrainInfo[]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user