diff --git a/package.json b/package.json index 278dbff2a..350dff978 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "react-json-view": "^1.21.3", "react-modal-promise": "^1.0.2", "react-scripts": "5.0.1", + "sketch-helpers": "^0.0.1", "swr": "^2.0.4", "three": "^0.146.0", "typescript": "^4.4.2", diff --git a/src/lang/executor.ts b/src/lang/executor.ts index f4907949f..24f01e999 100644 --- a/src/lang/executor.ts +++ b/src/lang/executor.ts @@ -477,8 +477,24 @@ function executePipeBody( function executeObjectExpression( _programMemory: ProgramMemory, - objExp: ObjectExpression + objExp: ObjectExpression, + pipeInfo: { + isInPipe: boolean + previousResults: any[] + expressionIndex: number + body: PipeExpression['body'] + sourceRangeOverride?: SourceRange + } = { + isInPipe: false, + previousResults: [], + expressionIndex: 0, + body: [], + } ) { + const _pipeInfo = { + ...pipeInfo, + isInPipe: false, + } const obj: { [key: string]: any } = {} objExp.properties.forEach((property) => { if (property.type === 'ObjectProperty') { @@ -504,6 +520,18 @@ function executeObjectExpression( } else if (property.value.type === 'ArrayExpression') { const result = executeArrayExpression(_programMemory, property.value) obj[property.key.name] = result + } else if (property.value.type === 'CallExpression') { + obj[property.key.name] = executeCallExpression( + _programMemory, + property.value, + [], + _pipeInfo + ) + } else if (property.value.type === 'UnaryExpression') { + obj[property.key.name] = getUnaryExpressionResult( + property.value, + _programMemory + ) } else { throw new Error( `Unexpected property type ${property.value.type} in object expression` @@ -613,7 +641,7 @@ function executeCallExpression( ) return result } else if (arg.type === 'ObjectExpression') { - return executeObjectExpression(programMemory, arg) + return executeObjectExpression(programMemory, arg, _pipeInfo) } else if (arg.type === 'UnaryExpression') { return getUnaryExpressionResult(arg, programMemory, _pipeInfo) } else if (arg.type === 'BinaryExpression') { diff --git a/src/lang/std/std.test.ts b/src/lang/std/std.test.ts new file mode 100644 index 000000000..3f1015509 --- /dev/null +++ b/src/lang/std/std.test.ts @@ -0,0 +1,26 @@ +import { abstractSyntaxTree } from '../abstractSyntaxTree' +import { executor } from '../executor' +import { lexer } from '../tokeniser' +import { initPromise } from '../rust' + +beforeAll(() => initPromise) + +describe('testing angledLineThatIntersects', () => { + it('angledLineThatIntersects should intersect with another line', () => { + const code = (offset: string) => `const part001 = startSketchAt([0, 0]) + |> lineTo({to:[2, 2], tag: "yo"}, %) + |> lineTo([3, 1], %) + |> angledLineThatIntersects({ + angle: 180, + intersectTag: 'yo', + offset: ${offset}, + tag: "yo2" +}, %) +const intersect = segEndX('yo2', part001) +show(part001)` + const { root } = executor(abstractSyntaxTree(lexer(code('-1')))) + expect(root.intersect.value).toBe(1 + Math.sqrt(2)) + const { root: noOffset } = executor(abstractSyntaxTree(lexer(code('0')))) + expect(noOffset.intersect.value).toBeCloseTo(1) + }) +}) diff --git a/src/lang/std/std.ts b/src/lang/std/std.ts index 0d4edc41b..0689af36f 100644 --- a/src/lang/std/std.ts +++ b/src/lang/std/std.ts @@ -12,6 +12,7 @@ import { angledLineToY, closee, startSketchAt, + getCoordsFromPaths, } from './sketch' import { segLen, @@ -27,6 +28,7 @@ import { Quaternion, Vector3 } from 'three' import { SketchGroup, ExtrudeGroup, Position, Rotation } from '../executor' import { InternalFn, InternalFnNames, InternalFirstArg } from './stdTypes' +import { intersectionWithParallelLine } from 'sketch-helpers' const transform: InternalFn = ( { sourceRange }: InternalFirstArg, @@ -79,6 +81,38 @@ const translate: InternalFn = ( } } +const angledLineThatIntersects: InternalFn = ( + { sourceRange, programMemory }, + data: { + angle: number + intersectTag: string + offset?: number + tag?: string + }, + previousSketch: SketchGroup +) => { + if (!previousSketch) throw new Error('lineTo must be called after lineTo') + const intersectPath = previousSketch.value.find( + ({ name }) => name === data.intersectTag + ) + if (!intersectPath) throw new Error('intersectTag must match a line') + const from = getCoordsFromPaths( + previousSketch, + previousSketch.value.length - 1 + ) + const to = intersectionWithParallelLine({ + line1: [intersectPath.from, intersectPath.to], + line1Offset: data.offset || 0, + line2Point: from, + line2Angle: data.angle, + }) + return lineTo.fn( + { sourceRange, programMemory }, + { to, tag: data.tag }, + previousSketch + ) +} + const min: InternalFn = (_, a: number, b: number): number => Math.min(a, b) const legLen: InternalFn = (_, hypotenuse: number, leg: number): number => @@ -122,6 +156,7 @@ export const internalFns: { [key in InternalFnNames]: InternalFn } = { angledLineToX: angledLineToX.fn, angledLineOfYLength: angledLineOfYLength.fn, angledLineToY: angledLineToY.fn, + angledLineThatIntersects, startSketchAt, closee, } diff --git a/src/lang/std/stdTypes.ts b/src/lang/std/stdTypes.ts index a2bd72550..f2f5672ed 100644 --- a/src/lang/std/stdTypes.ts +++ b/src/lang/std/stdTypes.ts @@ -47,6 +47,7 @@ export type InternalFnNames = | 'angledLineToY' | 'startSketchAt' | 'closee' + | 'angledLineThatIntersects' export interface ModifyAstBase { node: Program diff --git a/yarn.lock b/yarn.lock index 806d73f4e..91d298667 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9360,6 +9360,11 @@ sisteransi@^1.0.4, sisteransi@^1.0.5: resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== +sketch-helpers@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/sketch-helpers/-/sketch-helpers-0.0.1.tgz#637ead1f6e39276408d2c2e2a48dfefe13dc0cb0" + integrity sha512-ePn4nTA5sVNR6+8JalyCPQ+K7tpuYtCrccw2QGL6H2N3JRq6bO8x9RmZpyjTe/+T0uSrd2+F41d+ibsrjHHSFg== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"