Compare commits

...

20 Commits

Author SHA1 Message Date
ccaff0b3c6 Rust: migrate arc/arcTo to kwargs 2025-04-14 17:03:47 -05:00
45e906f8c7 Fix order of constraints in unit test 2025-04-14 16:50:27 -04:00
25ec74fc46 Fix e2e test expectation
App was working as expected, but the e2e test was
expecting the old code, not the new code.
2025-04-14 15:36:36 -05:00
05432b2ba4 Fix selections e2e test 2025-04-14 16:21:40 -04:00
699ce799b9 Fix to use labeledArg constraints and use the correct order of args 2025-04-14 16:17:24 -04:00
bb0ba6ed0b Fix adding constraint from UI to work 2025-04-14 15:33:50 -04:00
c1d0d8a762 tiny lint 2025-04-14 14:02:48 -05:00
639f2a583f Fix e2e tests to use new kw args 2025-04-14 14:48:19 -04:00
153da3312b Fix bench test 2025-04-14 14:42:44 -04:00
a91261be3e Fix more unit tests 2025-04-14 14:31:45 -04:00
d40f70ccb9 Fix to not have extra docs 2025-04-14 14:12:55 -04:00
255b88de4f Fix std unit tests 2025-04-14 14:02:26 -04:00
73d7d93a3d Fix sketch unit tests 2025-04-14 14:00:21 -04:00
d135cc7c55 Fix modifyAst unit tests 2025-04-14 13:57:21 -04:00
9cda90144c Fix missing cases 2025-04-14 13:49:51 -04:00
e8c391ea18 Fix tsc and lint errors 2025-04-14 13:38:24 -04:00
10e389bc38 Merge branch 'main' into achalmers/angle-line-intersects 2025-04-14 11:40:08 -05:00
a4f090e49d WIP 2025-04-11 16:16:00 -05:00
5e226b5573 Update KCL tests and samples 2025-04-11 16:15:53 -05:00
5cfeca0f69 KCL: Convert angledLineThatIntersects to use kwargs 2025-04-11 16:13:49 -05:00
26 changed files with 549 additions and 745 deletions

View File

@ -77,11 +77,7 @@ part001 = startSketchOn(-XZ)
) )
|> xLine(endAbsolute = totalLen, tag = $seg03) |> xLine(endAbsolute = totalLen, tag = $seg03)
|> yLine(length = -armThick, tag = $seg01) |> yLine(length = -armThick, tag = $seg01)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = turns::HALF_TURN, offset = -armThick, intersectTag = seg04)
angle = turns::HALF_TURN,
offset = -armThick,
intersectTag = seg04
}, %)
|> angledLine(angle = segAng(seg04, %) + 180, endAbsoluteY = turns::ZERO) |> angledLine(angle = segAng(seg04, %) + 180, endAbsoluteY = turns::ZERO)
|> angledLine( |> angledLine(
angle = -bottomAng, angle = -bottomAng,
@ -90,11 +86,7 @@ part001 = startSketchOn(-XZ)
) )
|> xLine(length = endAbsolute = segEndX(seg03) + 0) |> xLine(length = endAbsolute = segEndX(seg03) + 0)
|> yLine(length = -segLen(seg01, %)) |> yLine(length = -segLen(seg01, %))
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = turns::HALF_TURN, offset = -armThick, intersectTag = seg02)
angle = turns::HALF_TURN,
offset = -armThick,
intersectTag = seg02
}, %)
|> angledLine(angle = segAng(seg02, %) + 180, endAbsoluteY = -baseHeight) |> angledLine(angle = segAng(seg02, %) + 180, endAbsoluteY = -baseHeight)
|> xLine(endAbsolute = turns::ZERO) |> xLine(endAbsolute = turns::ZERO)
|> close() |> close()

View File

@ -93,11 +93,7 @@ part001 = startSketchOn(XZ)
|> angledLine(angle = 30, lengthY = 3 + 0 ) |> angledLine(angle = 30, lengthY = 3 + 0 )
|> angledLine(angle = 22.14 + 0, endAbsoluteX = 12) |> angledLine(angle = 22.14 + 0, endAbsoluteX = 12)
|> angledLine(angle = 30, endAbsoluteY = 11.14) |> angledLine(angle = 30, endAbsoluteY = 11.14)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = 3.14, intersectTag = a, offset = 0)
angle: 3.14,
intersectTag: a,
offset: 0
}, %)
|> tangentialArc(endAbsolute = [13.14 + 0, 13.14]) |> tangentialArc(endAbsolute = [13.14 + 0, 13.14])
|> close() |> close()
|> extrude(length = 5 + 7) |> extrude(length = 5 + 7)

View File

@ -219,7 +219,9 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await expect(activeLinesContent[0]).toHaveText( await expect(activeLinesContent[0]).toHaveText(
`|> line(end = [74.36, 130.4], tag = $seg01)` `|> line(end = [74.36, 130.4], tag = $seg01)`
) )
await expect(activeLinesContent[1]).toHaveText(`}, %)`) await expect(activeLinesContent[1]).toHaveText(
` |> angledLineThatIntersects(angle = -57, offset = ${offset}, intersectTag = seg01)`
)
// checking the count of the overlays is a good proxy check that the client sketch scene is in a good state // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state
await expect(page.getByTestId('segment-overlay')).toHaveCount(4) await expect(page.getByTestId('segment-overlay')).toHaveCount(4)

View File

@ -224,11 +224,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|> angledLine(angle = -91, lengthY = 19 + 0) |> angledLine(angle = -91, lengthY = 19 + 0)
|> angledLine(angle = 3 + 0, endAbsoluteX = 5 + 26) |> angledLine(angle = 3 + 0, endAbsoluteX = 5 + 26)
|> angledLine(angle = 89, endAbsoluteY = 20 + 9.14 + 0) |> angledLine(angle = 89, endAbsoluteY = 20 + 9.14 + 0)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
angle = 4.14,
intersectTag = a,
offset = 9
}, %)
|> tangentialArc(endAbsolute = [5 + 3.14 + 13, 20 + 3.14]) |> tangentialArc(endAbsolute = [5 + 3.14 + 13, 20 + 3.14])
` `
) )
@ -472,11 +468,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|> angledLine(angle = -91, lengthY = 19 + 0) |> angledLine(angle = -91, lengthY = 19 + 0)
|> angledLine(angle = 3 + 0, endAbsoluteX = 26) |> angledLine(angle = 3 + 0, endAbsoluteX = 26)
|> angledLine(angle = 89, endAbsoluteY = 9.14 + 0) |> angledLine(angle = 89, endAbsoluteY = 9.14 + 0)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
angle = 4.14,
intersectTag = a,
offset = 9
}, %)
|> tangentialArc(endAbsolute = [3.14 + 13, 3.14]) |> tangentialArc(endAbsolute = [3.14 + 13, 3.14])
` `
) )
@ -597,11 +589,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|> angledLine(angle = -91, lengthY = 19 + 0) |> angledLine(angle = -91, lengthY = 19 + 0)
|> angledLine(angle = 3 + 0, endAbsoluteX = 26) |> angledLine(angle = 3 + 0, endAbsoluteX = 26)
|> angledLine(angle = 89, endAbsoluteY = 9.14 + 0) |> angledLine(angle = 89, endAbsoluteY = 9.14 + 0)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
angle = 4.14,
intersectTag = a,
offset = 9
}, %)
|> tangentialArc(endAbsolute = [3.14 + 13, 1.14]) |> tangentialArc(endAbsolute = [3.14 + 13, 1.14])
` `
) )
@ -691,21 +679,9 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
y: angledLineThatIntersects.y, y: angledLineThatIntersects.y,
}, },
constraintType: 'angle', constraintType: 'angle',
expectBeforeUnconstrained: `angledLineThatIntersects({ expectBeforeUnconstrained: `angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)`,
angle = 4.14, expectAfterUnconstrained: `angledLineThatIntersects(angle = angle003, intersectTag = a,offset = 9)`,
intersectTag = a, expectFinal: `angledLineThatIntersects(angle = -176, offset = 9, intersectTag = a)`,
offset = 9
}, %)`,
expectAfterUnconstrained: `angledLineThatIntersects({
angle = angle003,
intersectTag = a,
offset = 9
}, %)`,
expectFinal: `angledLineThatIntersects({
angle = -176,
offset = 9,
intersectTag = a
}, %)`,
ang: ang + 180, ang: ang + 180,
locator: '[data-overlay-toolbar-index="11"]', locator: '[data-overlay-toolbar-index="11"]',
}) })
@ -716,21 +692,9 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
y: angledLineThatIntersects.y, y: angledLineThatIntersects.y,
}, },
constraintType: 'intersectionOffset', constraintType: 'intersectionOffset',
expectBeforeUnconstrained: `angledLineThatIntersects({ expectBeforeUnconstrained: `angledLineThatIntersects(angle = -176, offset = 9, intersectTag = a)`,
angle = -176, expectAfterUnconstrained: `angledLineThatIntersects(angle = -176, offset = perpDist001, intersectTag = a)`,
offset = 9, expectFinal: `angledLineThatIntersects(angle = -176, offset = 9, intersectTag = a)`,
intersectTag = a
}, %)`,
expectAfterUnconstrained: `angledLineThatIntersects({
angle = -176,
offset = perpDist001,
intersectTag = a
}, %)`,
expectFinal: `angledLineThatIntersects({
angle = -176,
offset = 9,
intersectTag = a
}, %)`,
ang: ang + 180, ang: ang + 180,
locator: '[data-overlay-toolbar-index="11"]', locator: '[data-overlay-toolbar-index="11"]',
}) })
@ -753,11 +717,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|> angledLine(angle = -91, lengthY = 19 + 0) |> angledLine(angle = -91, lengthY = 19 + 0)
|> angledLine(angle = 3 + 0, endAbsoluteX = 26) |> angledLine(angle = 3 + 0, endAbsoluteX = 26)
|> angledLine(angle = 89, endAbsoluteY = 9.14 + 0) |> angledLine(angle = 89, endAbsoluteY = 9.14 + 0)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
angle = 4.14,
intersectTag = a,
offset = 9
}, %)
|> tangentialArc(endAbsolute = [3.14 + 13, -3.14]) |> tangentialArc(endAbsolute = [3.14 + 13, -3.14])
` `
) )
@ -1083,11 +1043,7 @@ part001 = startSketchOn(XZ)
|> angledLine(angle = -91, lengthY = 19 + 0) |> angledLine(angle = -91, lengthY = 19 + 0)
|> angledLine(angle = 3 + 0, endAbsoluteX = 26) |> angledLine(angle = 3 + 0, endAbsoluteX = 26)
|> angledLine(angle = 89, endAbsoluteY = 9.14 + 0) |> angledLine(angle = 89, endAbsoluteY = 9.14 + 0)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
angle = 4.14,
intersectTag = a,
offset = 9
}, %)
|> tangentialArc(endAbsolute = [3.14 + 13, 1.14]) |> tangentialArc(endAbsolute = [3.14 + 13, 1.14])
|> arcTo({ |> arcTo({
interior = [16.25, 5.12], interior = [16.25, 5.12],
@ -1169,11 +1125,7 @@ part001 = startSketchOn(XZ)
ang = await u.getAngle('[data-overlay-index="11"]') ang = await u.getAngle('[data-overlay-index="11"]')
await deleteSegmentSequence({ await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y }, hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: `angledLineThatIntersects({ codeToBeDeleted: `angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)`,
angle = 4.14,
intersectTag = a,
offset = 9
}, %)`,
stdLibFnName: 'angledLineThatIntersects', stdLibFnName: 'angledLineThatIntersects',
ang: ang + 180, ang: ang + 180,
steps: 7, steps: 7,

View File

@ -524,11 +524,7 @@ part001 = startSketchOn(XZ)
|> angledLine(angle = 30, lengthY = 3 + 0) |> angledLine(angle = 30, lengthY = 3 + 0)
|> angledLine(angle = 22.14 + 0, endAbsoluteX = 12) |> angledLine(angle = 22.14 + 0, endAbsoluteX = 12)
|> angledLine(angle = 30, endAbsoluteY = 11.14) |> angledLine(angle = 30, endAbsoluteY = 11.14)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = 3.14, intersectTag = a, offset = 0)
angle = 3.14,
intersectTag = a,
offset = 0
}, %)
|> tangentialArc(endAbsolute = [13.14 + 0, 13.14]) |> tangentialArc(endAbsolute = [13.14 + 0, 13.14])
|> close() |> close()
|> extrude(length = 5 + 7) |> extrude(length = 5 + 7)
@ -660,8 +656,8 @@ part001 = startSketchOn(XZ)
await checkCodeAtHoverPosition( await checkCodeAtHoverPosition(
'flatExtrusionFace', 'flatExtrusionFace',
flatExtrusionFace, flatExtrusionFace,
`angledLineThatIntersects({angle=3.14,intersectTag=a,offset=0},%)extrude(length=5+7)`, `angledLineThatIntersects(angle=3.14,intersectTag=a,offset=0)extrude(length=5+7)`,
'}, %)' 'angledLineThatIntersects(angle = 3.14, intersectTag = a, offset = 0)'
) )
await checkCodeAtHoverPosition( await checkCodeAtHoverPosition(
@ -724,8 +720,8 @@ part001 = startSketchOn(XZ)
await checkCodeAtHoverPosition( await checkCodeAtHoverPosition(
'straightSegmentAdjacentEdge', 'straightSegmentAdjacentEdge',
straightSegmentAdjacentEdge, straightSegmentAdjacentEdge,
`angledLineThatIntersects({angle=3.14,intersectTag=a,offset=0},%)`, `angledLineThatIntersects(angle=3.14,intersectTag=a,offset=0)`,
'}, %)' 'angledLineThatIntersects(angle = 3.14, intersectTag = a, offset = 0)'
) )
await page.waitForTimeout(200) await page.waitForTimeout(200)

View File

@ -66,11 +66,7 @@ part001 = startSketchOn(-XZ)
) )
|> xLine(endAbsolute = totalLen, tag = $seg03) |> xLine(endAbsolute = totalLen, tag = $seg03)
|> yLine(length = -armThick, tag = $seg01) |> yLine(length = -armThick, tag = $seg01)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = turns::HALF_TURN, offset = -armThick, intersectTag = seg04)
angle = turns::HALF_TURN,
offset = -armThick,
intersectTag = seg04
}, %)
|> angledLine(angle = segAng(seg04) + 180, endAbsoluteY = turns::ZERO) |> angledLine(angle = segAng(seg04) + 180, endAbsoluteY = turns::ZERO)
|> angledLine( |> angledLine(
angle = -bottomAng, angle = -bottomAng,
@ -79,11 +75,7 @@ part001 = startSketchOn(-XZ)
) )
|> xLine(endAbsolute = segEndX(seg03) + 0) |> xLine(endAbsolute = segEndX(seg03) + 0)
|> yLine(length = -segLen(seg01)) |> yLine(length = -segLen(seg01))
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = turns::HALF_TURN, offset = -armThick, intersectTag = seg02)
angle = turns::HALF_TURN,
offset = -armThick,
intersectTag = seg02
}, %)
|> angledLine(angle = segAng(seg02) + 180, endAbsoluteY = -baseHeight) |> angledLine(angle = segAng(seg02) + 180, endAbsoluteY = -baseHeight)
|> xLine(endAbsolute = turns::ZERO) |> xLine(endAbsolute = turns::ZERO)
|> close() |> close()

View File

@ -153,11 +153,7 @@ fn z(origin, scale, depth) {
|> yLine(length = segLen(seg3)) |> yLine(length = segLen(seg3))
|> xLine(endAbsolute = 0 + origin[0]) |> xLine(endAbsolute = 0 + origin[0])
|> yLine(length = -0.225 * scale) |> yLine(length = -0.225 * scale)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = 0, intersectTag = seg2, offset = 0)
angle = 0,
intersectTag = seg2,
offset = 0
}, %)
|> close() |> close()
|> extrude(length = -depth) |> extrude(length = -depth)
|> appearance(color = baseColor) |> appearance(color = baseColor)

View File

@ -21,11 +21,11 @@ export fn zLogo(surface, origin, scale) {
|> yLine(length = segLen(seg3)) |> yLine(length = segLen(seg3))
|> xLine(endAbsolute = 0 + origin[0]) |> xLine(endAbsolute = 0 + origin[0])
|> yLine(length = -0.225 * scale) |> yLine(length = -0.225 * scale)
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle = 0, angle = 0,
intersectTag = seg2, intersectTag = seg2,
offset = 0 offset = 0,
}, %) )
|> close() |> close()
return zSketch return zSketch
} }

View File

@ -152,11 +152,11 @@ const extrude005l = extrude(sketch005l, length = 1)
const sketch006l = startSketchOn(plane001) const sketch006l = startSketchOn(plane001)
|> startProfileAt([1, 1], %) |> startProfileAt([1, 1], %)
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle: 70, angle = 70,
intersectTag: lineToIntersect4, intersectTag = lineToIntersect4,
offset: 0 offset = 0,
}, %) )
|> angledLine(angle = -70, length = 1.414 ) |> angledLine(angle = -70, length = 1.414 )
|> angledLine(angle = 70 + 180, endAbsoluteY = 2 - 1) |> angledLine(angle = 70 + 180, endAbsoluteY = 2 - 1)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -168,11 +168,11 @@ const sketch007l = startSketchOn(plane001)
serverDepth - 1.2, serverDepth - 1.2,
railHeight * 1.75 + 1 railHeight * 1.75 + 1
], %) ], %)
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle: 70, angle = 70,
intersectTag: lineToIntersect5, intersectTag = lineToIntersect5,
offset: 0 offset = 0,
}, %) )
|> angledLine(angle = -70, length = 1.414 ) |> angledLine(angle = -70, length = 1.414 )
|> angledLine(angle = 70 + 180, endAbsoluteY = railHeight * 1.75 + 1) |> angledLine(angle = 70 + 180, endAbsoluteY = railHeight * 1.75 + 1)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -243,11 +243,12 @@ const sketch006w = startSketchOn(plane002)
], %) ], %)
|> angledLine(angle = -23 + 90, endAbsoluteX = depth - 1) |> angledLine(angle = -23 + 90, endAbsoluteX = depth - 1)
|> yLine(length = 2.56) |> yLine(length = 2.56)
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle: -23 + 90 + 180, angle = -23 + 90 + 180,
intersectTag: lineToIntersect, intersectTag = lineToIntersect,
offset: 0 offset = 0,
}, %, $lineToIntersect2) tag = $lineToIntersect2,
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
const extrude006w = extrude(sketch006w, length = 1) const extrude006w = extrude(sketch006w, length = 1)
@ -256,28 +257,28 @@ const sketch007w = startSketchOn(plane002)
|> startProfileAt([depth - 1, 60.65 + 1.75 / 2], %) |> startProfileAt([depth - 1, 60.65 + 1.75 / 2], %)
|> angledLine(angle = -23 + 180, length = 34.93 , tag = $lineToIntersect3) |> angledLine(angle = -23 + 180, length = 34.93 , tag = $lineToIntersect3)
|> angledLine(angle = 23 - 90, length = 1.414 ) |> angledLine(angle = 23 - 90, length = 1.414 )
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle: -23 + 180, angle = -23 + 180,
intersectTag: lineToIntersect2, intersectTag = lineToIntersect2,
offset: 0 offset = 0,
}, %) )
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
const extrude007w = extrude(sketch007w, length = 1) const extrude007w = extrude(sketch007w, length = 1)
const sketch008w = startSketchOn(plane002) const sketch008w = startSketchOn(plane002)
|> startProfileAt([1, 41.7 + 1.75 / 2], %) |> startProfileAt([1, 41.7 + 1.75 / 2], %)
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle: -23 + 90, angle = -23 + 90,
intersectTag: lineToIntersect3, intersectTag = lineToIntersect3,
offset: 0 offset = 0,
}, %) )
|> angledLine(angle = -23 - 45, length = 1.414 ) |> angledLine(angle = -23 - 45, length = 1.414 )
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle: -23 - 90, angle = -23 - 90,
intersectTag: lineToIntersect, intersectTag = lineToIntersect,
offset: 0 offset = 0,
}, %) )
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
const extrude008w = extrude(sketch008w, length = 1) const extrude008w = extrude(sketch008w, length = 1)

View File

@ -150,11 +150,7 @@ const extrude005l = extrude(sketch005l, length = 1)
const sketch006l = startSketchOn(plane001) const sketch006l = startSketchOn(plane001)
|> startProfileAt([1, 1], %) |> startProfileAt([1, 1], %)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = 70, intersectTag = lineToIntersect4, offset = 0)
angle: 70,
intersectTag: lineToIntersect4,
offset: 0
}, %)
|> angledLine(angle = -70, length = 1.414 ) |> angledLine(angle = -70, length = 1.414 )
|> angledLine(angle = 70 + 180, endAbsoluteY = 2 - 1) |> angledLine(angle = 70 + 180, endAbsoluteY = 2 - 1)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -166,11 +162,7 @@ const sketch007l = startSketchOn(plane001)
serverDepth - 1.2, serverDepth - 1.2,
railHeight * 1.75 + 1 railHeight * 1.75 + 1
], %) ], %)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = 70, intersectTag = lineToIntersect5, offset = 0)
angle: 70,
intersectTag: lineToIntersect5,
offset: 0
}, %)
|> angledLine(angle = -70, length = 1.414 ) |> angledLine(angle = -70, length = 1.414 )
|> angledLine(angle = 70 + 180, endAbsoluteY = railHeight * 1.75 + 1) |> angledLine(angle = 70 + 180, endAbsoluteY = railHeight * 1.75 + 1)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -241,11 +233,12 @@ const sketch006w = startSketchOn(plane002)
], %) ], %)
|> angledLine(angle = -23 + 90, endAbsoluteX = depth - 1) |> angledLine(angle = -23 + 90, endAbsoluteX = depth - 1)
|> yLine(length = 2.56) |> yLine(length = 2.56)
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle: -23 + 90 + 180, angle = -23 + 90 + 180,
intersectTag: lineToIntersect, intersectTag = lineToIntersect,
offset: 0 offset = 0,
}, %, $lineToIntersect2) tag = $lineToIntersect2,
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
const extrude006w = extrude(sketch006w, length = 1) const extrude006w = extrude(sketch006w, length = 1)
@ -254,28 +247,28 @@ const sketch007w = startSketchOn(plane002)
|> startProfileAt([depth - 1, 60.65 + 1.75 / 2], %) |> startProfileAt([depth - 1, 60.65 + 1.75 / 2], %)
|> angledLine(angle = -23 + 180, length = 34.93 , tag = $lineToIntersect3) |> angledLine(angle = -23 + 180, length = 34.93 , tag = $lineToIntersect3)
|> angledLine(angle = 23 - 90, length = 1.414 ) |> angledLine(angle = 23 - 90, length = 1.414 )
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle: -23 + 180, angle = -23 + 180,
intersectTag: lineToIntersect2, intersectTag = lineToIntersect2,
offset: 0 offset = 0,
}, %) )
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
const extrude007w = extrude(sketch007w, length = 1) const extrude007w = extrude(sketch007w, length = 1)
const sketch008w = startSketchOn(plane002) const sketch008w = startSketchOn(plane002)
|> startProfileAt([1, 41.7 + 1.75 / 2], %) |> startProfileAt([1, 41.7 + 1.75 / 2], %)
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle: -23 + 90, angle = -23 + 90,
intersectTag: lineToIntersect3, intersectTag = lineToIntersect3,
offset: 0 offset = 0,
}, %) )
|> angledLine(angle = -23 - 45, length = 1.414 ) |> angledLine(angle = -23 - 45, length = 1.414 )
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle: -23 - 90, angle = -23 - 90,
intersectTag: lineToIntersect, intersectTag = lineToIntersect,
offset: 0 offset = 0,
}, %) )
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
const extrude008w = extrude(sketch008w, length = 1) const extrude008w = extrude(sketch008w, length = 1)

View File

@ -991,20 +991,6 @@ macro_rules! let_field_of {
}; };
} }
impl<'a> FromKclValue<'a> for super::sketch::AngledLineThatIntersectsData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?;
let_field_of!(obj, angle);
let_field_of!(obj, intersect_tag "intersectTag");
let_field_of!(obj, offset?);
Some(Self {
angle,
intersect_tag,
offset,
})
}
}
impl<'a> FromKclValue<'a> for super::shapes::PolygonData { impl<'a> FromKclValue<'a> for super::shapes::PolygonData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?; let obj = arg.as_object()?;
@ -1128,39 +1114,6 @@ impl<'a> FromKclValue<'a> for FaceTag {
} }
} }
impl<'a> FromKclValue<'a> for super::sketch::ArcData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?;
let case1 = || {
let angle_start = obj.get("angleStart")?.as_ty_f64()?;
let angle_end = obj.get("angleEnd")?.as_ty_f64()?;
let_field_of!(obj, radius, TyF64);
Some(Self::AnglesAndRadius {
angle_start,
angle_end,
radius,
})
};
let case2 = || {
let obj = arg.as_object()?;
let_field_of!(obj, to);
let_field_of!(obj, center);
let_field_of!(obj, radius, TyF64);
Some(Self::CenterToRadius { center, to, radius })
};
case1().or_else(case2)
}
}
impl<'a> FromKclValue<'a> for super::sketch::ArcToData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?;
let_field_of!(obj, end);
let_field_of!(obj, interior);
Some(Self { end, interior })
}
}
impl<'a> FromKclValue<'a> for super::sketch::TangentialArcData { impl<'a> FromKclValue<'a> for super::sketch::TangentialArcData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?; let obj = arg.as_object()?;

View File

@ -84,7 +84,6 @@ lazy_static! {
Box::new(crate::std::sketch::ProfileStart), Box::new(crate::std::sketch::ProfileStart),
Box::new(crate::std::sketch::Close), Box::new(crate::std::sketch::Close),
Box::new(crate::std::sketch::Arc), Box::new(crate::std::sketch::Arc),
Box::new(crate::std::sketch::ArcTo),
Box::new(crate::std::sketch::TangentialArc), Box::new(crate::std::sketch::TangentialArc),
Box::new(crate::std::sketch::BezierCurve), Box::new(crate::std::sketch::BezierCurve),
Box::new(crate::std::sketch::Hole), Box::new(crate::std::sketch::Hole),

View File

@ -24,7 +24,7 @@ use crate::{
std::{ std::{
args::{Args, TyF64}, args::{Args, TyF64},
utils::{ utils::{
arc_angles, arc_center_and_end, get_tangential_arc_to_info, get_x_component, get_y_component, arc_center_and_end, get_tangential_arc_to_info, get_x_component, get_y_component,
intersection_with_parallel_line, TangentialArcInfoInput, intersection_with_parallel_line, TangentialArcInfoInput,
}, },
}, },
@ -104,7 +104,7 @@ pub async fn involute_circular(exec_state: &mut ExecState, args: Args) -> Result
let end_radius: TyF64 = args.get_kw_arg_typed("endRadius", &RuntimeType::length(), exec_state)?; let end_radius: TyF64 = args.get_kw_arg_typed("endRadius", &RuntimeType::length(), exec_state)?;
let angle: TyF64 = args.get_kw_arg_typed("angle", &RuntimeType::angle(), exec_state)?; let angle: TyF64 = args.get_kw_arg_typed("angle", &RuntimeType::angle(), exec_state)?;
let reverse = args.get_kw_arg_opt("reverse")?; let reverse = args.get_kw_arg_opt("reverse")?;
let tag = args.get_kw_arg_opt("tag")?; let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
let new_sketch = inner_involute_circular( let new_sketch = inner_involute_circular(
sketch, sketch,
start_radius.n, start_radius.n,
@ -871,25 +871,16 @@ async fn inner_angled_line_to_y(
Ok(new_sketch) Ok(new_sketch)
} }
/// Data for drawing an angled line that intersects with a given line.
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
// TODO: make sure the docs on the args below are correct.
pub struct AngledLineThatIntersectsData {
/// The angle of the line.
pub angle: TyF64,
/// The tag of the line to intersect with.
pub intersect_tag: TagIdentifier,
/// The offset from the intersecting line.
pub offset: Option<TyF64>,
}
/// Draw an angled line that intersects with a given line. /// Draw an angled line that intersects with a given line.
pub async fn angled_line_that_intersects(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn angled_line_that_intersects(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, sketch, tag): (AngledLineThatIntersectsData, Sketch, Option<TagNode>) = let sketch =
args.get_data_and_sketch_and_tag(exec_state)?; args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let new_sketch = inner_angled_line_that_intersects(data, sketch, tag, exec_state, args).await?; let angle: TyF64 = args.get_kw_arg("angle")?;
let intersect_tag: TagIdentifier = args.get_kw_arg("intersectTag")?;
let offset: Option<TyF64> = args.get_kw_arg_opt("offset")?;
let tag: Option<TagNode> = args.get_kw_arg_opt("tag")?;
let new_sketch =
inner_angled_line_that_intersects(sketch, angle, intersect_tag, offset, tag, exec_state, args).await?;
Ok(KclValue::Sketch { Ok(KclValue::Sketch {
value: Box::new(new_sketch), value: Box::new(new_sketch),
}) })
@ -905,26 +896,37 @@ pub async fn angled_line_that_intersects(exec_state: &mut ExecState, args: Args)
/// |> line(endAbsolute = [5, 10]) /// |> line(endAbsolute = [5, 10])
/// |> line(endAbsolute = [-10, 10], tag = $lineToIntersect) /// |> line(endAbsolute = [-10, 10], tag = $lineToIntersect)
/// |> line(endAbsolute = [0, 20]) /// |> line(endAbsolute = [0, 20])
/// |> angledLineThatIntersects({ /// |> angledLineThatIntersects(
/// angle = 80, /// angle = 80,
/// intersectTag = lineToIntersect, /// intersectTag = lineToIntersect,
/// offset = 10 /// offset = 10,
/// }, %) /// )
/// |> close() /// |> close()
/// ///
/// example = extrude(exampleSketch, length = 10) /// example = extrude(exampleSketch, length = 10)
/// ``` /// ```
#[stdlib { #[stdlib {
name = "angledLineThatIntersects", name = "angledLineThatIntersects",
keywords = true,
unlabeled_first = true,
args = {
sketch = { docs = "Which sketch should this path be added to?"},
angle = { docs = "Which angle should the line be drawn at?" },
intersect_tag = { docs = "The tag of the line to intersect with" },
offset = { docs = "The offset from the intersecting line. Defaults to 0." },
tag = { docs = "Create a new tag which refers to this line"},
}
}] }]
pub async fn inner_angled_line_that_intersects( pub async fn inner_angled_line_that_intersects(
data: AngledLineThatIntersectsData,
sketch: Sketch, sketch: Sketch,
angle: TyF64,
intersect_tag: TagIdentifier,
offset: Option<TyF64>,
tag: Option<TagNode>, tag: Option<TagNode>,
exec_state: &mut ExecState, exec_state: &mut ExecState,
args: Args, args: Args,
) -> Result<Sketch, KclError> { ) -> Result<Sketch, KclError> {
let intersect_path = args.get_tag_engine_info(exec_state, &data.intersect_tag)?; let intersect_path = args.get_tag_engine_info(exec_state, &intersect_tag)?;
let path = intersect_path.path.clone().ok_or_else(|| { let path = intersect_path.path.clone().ok_or_else(|| {
KclError::Type(KclErrorDetails { KclError::Type(KclErrorDetails {
message: format!("Expected an intersect path with a path, found `{:?}`", intersect_path), message: format!("Expected an intersect path with a path, found `{:?}`", intersect_path),
@ -935,13 +937,12 @@ pub async fn inner_angled_line_that_intersects(
let from = sketch.current_pen_position()?; let from = sketch.current_pen_position()?;
let to = intersection_with_parallel_line( let to = intersection_with_parallel_line(
&[untype_point(path.get_from()).0, untype_point(path.get_to()).0], &[untype_point(path.get_from()).0, untype_point(path.get_to()).0],
data.offset.map(|t| t.n).unwrap_or_default(), offset.map(|t| t.n).unwrap_or_default(),
data.angle.n, angle.n,
from.into(), from.into(),
); );
let new_sketch = straight_line(StraightLineParams::absolute(to, sketch, tag), exec_state, args).await?; straight_line(StraightLineParams::absolute(to, sketch, tag), exec_state, args).await
Ok(new_sketch)
} }
/// Data for start sketch on. /// Data for start sketch on.
@ -1635,51 +1636,30 @@ pub(crate) async fn inner_close(
Ok(new_sketch) Ok(new_sketch)
} }
/// Data to draw an arc.
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase", untagged)]
pub enum ArcData {
/// Angles and radius with an optional tag.
AnglesAndRadius {
/// The start angle.
#[serde(rename = "angleStart")]
#[schemars(range(min = -360.0, max = 360.0))]
angle_start: TyF64,
/// The end angle.
#[serde(rename = "angleEnd")]
#[schemars(range(min = -360.0, max = 360.0))]
angle_end: TyF64,
/// The radius.
radius: TyF64,
},
/// Center, to and radius with an optional tag.
CenterToRadius {
/// The center.
center: [TyF64; 2],
/// The to point.
to: [TyF64; 2],
/// The radius.
radius: TyF64,
},
}
/// Data to draw a three point arc (arcTo).
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct ArcToData {
/// End point of the arc. A point in 3D space
pub end: [TyF64; 2],
/// Interior point of the arc. A point in 3D space
pub interior: [TyF64; 2],
}
/// Draw an arc. /// Draw an arc.
pub async fn arc(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn arc(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, sketch, tag): (ArcData, Sketch, Option<TagNode>) = args.get_data_and_sketch_and_tag(exec_state)?; let sketch =
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let new_sketch = inner_arc(data, sketch, tag, exec_state, args).await?; let angle_start: Option<TyF64> = args.get_kw_arg_opt_typed("angleStart", &RuntimeType::degrees(), exec_state)?;
let angle_end: Option<TyF64> = args.get_kw_arg_opt_typed("angleEnd", &RuntimeType::degrees(), exec_state)?;
let radius: Option<TyF64> = args.get_kw_arg_opt_typed("radius", &RuntimeType::length(), exec_state)?;
let end_absolute: Option<[TyF64; 2]> =
args.get_kw_arg_opt_typed("endAbsolute", &RuntimeType::point2d(), exec_state)?;
let interior: Option<[TyF64; 2]> = args.get_kw_arg_opt_typed("interior", &RuntimeType::point2d(), exec_state)?;
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
let new_sketch = inner_arc(
sketch,
angle_start,
angle_end,
radius,
end_absolute,
interior,
tag,
exec_state,
args,
)
.await?;
Ok(KclValue::Sketch { Ok(KclValue::Sketch {
value: Box::new(new_sketch), value: Box::new(new_sketch),
}) })
@ -1700,74 +1680,181 @@ pub async fn arc(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
/// exampleSketch = startSketchOn(XZ) /// exampleSketch = startSketchOn(XZ)
/// |> startProfileAt([0, 0], %) /// |> startProfileAt([0, 0], %)
/// |> line(end = [10, 0]) /// |> line(end = [10, 0])
/// |> arc({ /// |> arc(
/// angleStart = 0, /// angleStart = 0,
/// angleEnd = 280, /// angleEnd = 280,
/// radius = 16 /// radius = 16
/// }, %) /// )
/// |> close()
/// example = extrude(exampleSketch, length = 10)
/// ```
/// ```no_run
/// exampleSketch = startSketchOn(XZ)
/// |> startProfileAt([0, 0], %)
/// |> arc(
/// end = [10,0],
/// interior = [5,5]
/// )
/// |> close() /// |> close()
/// example = extrude(exampleSketch, length = 10) /// example = extrude(exampleSketch, length = 10)
/// ``` /// ```
#[stdlib { #[stdlib {
name = "arc", name = "arc",
keywords = true,
unlabeled_first = true,
args = {
sketch = { docs = "Which sketch should this path be added to?" },
angle_start = { docs = "Where along the circle should this arc start?" },
angle_end = { docs = "Where along the circle should this arc end?" },
radius = { docs = "How large should the circle be?" },
end_absolute = { docs = "Where should this arc end? Requires `interior`. Incompatible with `angleStart` or `angleEnd`" },
interior = { docs = "Any point between the arc's start and end? Requires `endAbsolute`. Incompatible with `angleStart` or `angleEnd`" },
tag = { docs = "Create a new tag which refers to this line"},
}
}] }]
#[allow(clippy::too_many_arguments)]
pub(crate) async fn inner_arc( pub(crate) async fn inner_arc(
data: ArcData,
sketch: Sketch, sketch: Sketch,
angle_start: Option<TyF64>,
angle_end: Option<TyF64>,
radius: Option<TyF64>,
end_absolute: Option<[TyF64; 2]>,
interior: Option<[TyF64; 2]>,
tag: Option<TagNode>, tag: Option<TagNode>,
exec_state: &mut ExecState, exec_state: &mut ExecState,
args: Args, args: Args,
) -> Result<Sketch, KclError> { ) -> Result<Sketch, KclError> {
let from: Point2d = sketch.current_pen_position()?; let from: Point2d = sketch.current_pen_position()?;
let id = exec_state.next_uuid();
let (center, angle_start, angle_end, radius, end) = match &data { // Relative case
ArcData::AnglesAndRadius { match (angle_start, angle_end, radius, end_absolute, interior) {
angle_start, (Some(angle_start), Some(angle_end), Some(radius), None, None) => {
angle_end, relative_arc(&args, id, exec_state, sketch, from, angle_start, angle_end, radius, tag).await
radius, }
} => { (None, None, None, Some(interior), Some(end_absolute)) => {
absolute_arc(&args, id, exec_state, sketch, from, interior, end_absolute,tag).await
}
_ => {
Err(KclError::Type(KclErrorDetails {
message:
"Invalid combination of arguments. Either provide (angleStart, angleEnd, radius) or (endAbsolute, interior)"
.to_string(),
source_ranges: vec![args.source_range],
}))
}
}
}
#[allow(clippy::too_many_arguments)]
pub async fn absolute_arc(
args: &Args,
id: uuid::Uuid,
exec_state: &mut ExecState,
sketch: Sketch,
from: Point2d,
interior: [TyF64; 2],
end_absolute: [TyF64; 2],
tag: Option<TagNode>,
) -> Result<Sketch, KclError> {
// The start point is taken from the path you are extending.
args.batch_modeling_cmd(
id,
ModelingCmd::from(mcmd::ExtendPath {
path: sketch.id.into(),
segment: PathSegment::ArcTo {
end: kcmc::shared::Point3d {
x: LengthUnit(end_absolute[0].n),
y: LengthUnit(end_absolute[1].n),
z: LengthUnit(0.0),
},
interior: kcmc::shared::Point3d {
x: LengthUnit(interior[0].n),
y: LengthUnit(interior[1].n),
z: LengthUnit(0.0),
},
relative: false,
},
}),
)
.await?;
let start = [from.x, from.y];
let end = end_absolute.clone();
let untyped_end = untype_point(end);
let current_path = Path::ArcThreePoint {
base: BasePath {
from: from.into(),
to: untyped_end.0,
tag: tag.clone(),
units: sketch.units,
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
},
},
p1: start,
p2: untype_point(interior).0,
p3: untyped_end.0,
};
let mut new_sketch = sketch.clone();
if let Some(tag) = &tag {
new_sketch.add_tag(tag, &current_path, exec_state);
}
new_sketch.paths.push(current_path);
Ok(new_sketch)
}
#[allow(clippy::too_many_arguments)]
pub async fn relative_arc(
args: &Args,
id: uuid::Uuid,
exec_state: &mut ExecState,
sketch: Sketch,
from: Point2d,
angle_start: TyF64,
angle_end: TyF64,
radius: TyF64,
tag: Option<TagNode>,
) -> Result<Sketch, KclError> {
let a_start = Angle::from_degrees(angle_start.n); let a_start = Angle::from_degrees(angle_start.n);
let a_end = Angle::from_degrees(angle_end.n); let a_end = Angle::from_degrees(angle_end.n);
let (center, end) = arc_center_and_end(from.into(), a_start, a_end, radius.n); let (center, end) = arc_center_and_end(from.into(), a_start, a_end, radius.n);
(center, a_start, a_end, radius.n, end)
}
ArcData::CenterToRadius { center, to, radius } => {
let (angle_start, angle_end) = arc_angles(
from.into(),
untype_point(to.clone()).0,
untype_point(center.clone()).0,
radius.n,
args.source_range,
)?;
(
untype_point(center.clone()).0,
angle_start,
angle_end,
radius.n,
untype_point(to.clone()).0,
)
}
};
if angle_start == angle_end { if angle_start == angle_end {
return Err(KclError::Type(KclErrorDetails { return Err(KclError::Type(KclErrorDetails {
message: "Arc start and end angles must be different".to_string(), message: "Arc start and end angles must be different".to_string(),
source_ranges: vec![args.source_range], source_ranges: vec![args.source_range],
})); }));
} }
let ccw = angle_start < angle_end; if a_start.to_degrees() > 360.0 || a_start.to_degrees() < -360.0 {
return Err(KclError::Type(KclErrorDetails {
let id = exec_state.next_uuid(); message: "Start angle must be between ±360 degrees.".to_string(),
// TODO: This source range should be specifically on the `angleStart` arg, not the entire arg list.
source_ranges: vec![args.source_range],
}));
}
if a_end.to_degrees() > 360.0 || a_end.to_degrees() < -360.0 {
return Err(KclError::Type(KclErrorDetails {
message: "End angle must be between ±360 degrees.".to_string(),
// TODO: This source range should be specifically on the `angleEnd` arg, not the entire arg list.
source_ranges: vec![args.source_range],
}));
}
let ccw = angle_start.n < angle_end.n;
args.batch_modeling_cmd( args.batch_modeling_cmd(
id, id,
ModelingCmd::from(mcmd::ExtendPath { ModelingCmd::from(mcmd::ExtendPath {
path: sketch.id.into(), path: sketch.id.into(),
segment: PathSegment::Arc { segment: PathSegment::Arc {
start: angle_start, start: a_start,
end: angle_end, end: a_end,
center: KPoint2d::from(center).map(LengthUnit), center: KPoint2d::from(center).map(LengthUnit),
radius: LengthUnit(radius), radius: LengthUnit(radius.n),
relative: false, relative: false,
}, },
}), }),
@ -1786,7 +1873,7 @@ pub(crate) async fn inner_arc(
}, },
}, },
center, center,
radius, radius: radius.n,
ccw, ccw,
}; };
@ -1799,98 +1886,6 @@ pub(crate) async fn inner_arc(
Ok(new_sketch) Ok(new_sketch)
} }
/// Draw a three point arc.
pub async fn arc_to(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, sketch, tag): (ArcToData, Sketch, Option<TagNode>) = args.get_data_and_sketch_and_tag(exec_state)?;
let new_sketch = inner_arc_to(data, sketch, tag, exec_state, args).await?;
Ok(KclValue::Sketch {
value: Box::new(new_sketch),
})
}
/// Draw a three point arc.
///
/// The arc is constructed such that the start point is the current position of the sketch and two more points defined as the end and interior point.
/// The interior point is placed between the start point and end point. The radius of the arc will be controlled by how far the interior point is placed from
/// the start and end.
///
/// ```no_run
/// exampleSketch = startSketchOn(XZ)
/// |> startProfileAt([0, 0], %)
/// |> arcTo({
/// end = [10,0],
/// interior = [5,5]
/// }, %)
/// |> close()
/// example = extrude(exampleSketch, length = 10)
/// ```
#[stdlib {
name = "arcTo",
}]
pub(crate) async fn inner_arc_to(
data: ArcToData,
sketch: Sketch,
tag: Option<TagNode>,
exec_state: &mut ExecState,
args: Args,
) -> Result<Sketch, KclError> {
let from: Point2d = sketch.current_pen_position()?;
let id = exec_state.next_uuid();
// The start point is taken from the path you are extending.
args.batch_modeling_cmd(
id,
ModelingCmd::from(mcmd::ExtendPath {
path: sketch.id.into(),
segment: PathSegment::ArcTo {
end: kcmc::shared::Point3d {
x: LengthUnit(data.end[0].n),
y: LengthUnit(data.end[1].n),
z: LengthUnit(0.0),
},
interior: kcmc::shared::Point3d {
x: LengthUnit(data.interior[0].n),
y: LengthUnit(data.interior[1].n),
z: LengthUnit(0.0),
},
relative: false,
},
}),
)
.await?;
let start = [from.x, from.y];
let interior = data.interior;
let end = data.end.clone();
let current_path = Path::ArcThreePoint {
base: BasePath {
from: from.into(),
to: untype_point(data.end).0,
tag: tag.clone(),
units: sketch.units,
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
},
},
p1: start,
p2: untype_point(interior).0,
p3: untype_point(end).0,
};
let mut new_sketch = sketch.clone();
if let Some(tag) = &tag {
new_sketch.add_tag(tag, &current_path, exec_state);
}
new_sketch.paths.push(current_path);
Ok(new_sketch)
}
/// Draw a tangential arc to a specific point. /// Draw a tangential arc to a specific point.
pub async fn tangential_arc(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn tangential_arc(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch = let sketch =

View File

@ -2141,11 +2141,11 @@ mySk1 = startSketchOn(XY)
|> startProfileAt([-0.01, -0.08], %) |> startProfileAt([-0.01, -0.08], %)
|> line([0.62, 4.15], %, $seg01) |> line([0.62, 4.15], %, $seg01)
|> line([2.77, -1.24], %) |> line([2.77, -1.24], %)
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle = 201, angle = 201,
offset = -1.35, offset = -1.35,
intersectTag = seg01 intersectTag = seg01
}, %) )
|> line([-0.42, -1.72], %)"#; |> line([-0.42, -1.72], %)"#;
let program = crate::parsing::top_level_parse(some_program_string).unwrap(); let program = crate::parsing::top_level_parse(some_program_string).unwrap();

View File

@ -318,40 +318,40 @@ flowchart LR
892["Segment<br>[5591, 5619, 0]"] 892["Segment<br>[5591, 5619, 0]"]
893["Segment<br>[5627, 5661, 0]"] 893["Segment<br>[5627, 5661, 0]"]
894["Segment<br>[5669, 5699, 0]"] 894["Segment<br>[5669, 5699, 0]"]
895["Segment<br>[5707, 5816, 0]"] 895["Segment<br>[5707, 5812, 0]"]
896["Segment<br>[5824, 5831, 0]"] 896["Segment<br>[5820, 5827, 0]"]
897[Solid2d] 897[Solid2d]
end end
subgraph path950 [Path] subgraph path950 [Path]
950["Path<br>[6031, 6129, 0]"] 950["Path<br>[6027, 6125, 0]"]
951["Segment<br>[6137, 6256, 0]"] 951["Segment<br>[6133, 6252, 0]"]
952["Segment<br>[6264, 6311, 0]"] 952["Segment<br>[6260, 6307, 0]"]
953["Segment<br>[6319, 6440, 0]"] 953["Segment<br>[6315, 6436, 0]"]
954["Segment<br>[6448, 6455, 0]"] 954["Segment<br>[6444, 6451, 0]"]
955[Solid2d] 955[Solid2d]
end end
subgraph path972 [Path] subgraph path972 [Path]
972["Path<br>[6563, 6660, 0]"] 972["Path<br>[6559, 6656, 0]"]
973["Segment<br>[6668, 6787, 0]"] 973["Segment<br>[6664, 6783, 0]"]
974["Segment<br>[6795, 6843, 0]"] 974["Segment<br>[6791, 6839, 0]"]
975["Segment<br>[6851, 6972, 0]"] 975["Segment<br>[6847, 6968, 0]"]
976["Segment<br>[6980, 6987, 0]"] 976["Segment<br>[6976, 6983, 0]"]
977[Solid2d] 977[Solid2d]
end end
subgraph path994 [Path] subgraph path994 [Path]
994["Path<br>[6031, 6129, 0]"] 994["Path<br>[6027, 6125, 0]"]
995["Segment<br>[6137, 6256, 0]"] 995["Segment<br>[6133, 6252, 0]"]
996["Segment<br>[6264, 6311, 0]"] 996["Segment<br>[6260, 6307, 0]"]
997["Segment<br>[6319, 6440, 0]"] 997["Segment<br>[6315, 6436, 0]"]
998["Segment<br>[6448, 6455, 0]"] 998["Segment<br>[6444, 6451, 0]"]
999[Solid2d] 999[Solid2d]
end end
subgraph path1016 [Path] subgraph path1016 [Path]
1016["Path<br>[6563, 6660, 0]"] 1016["Path<br>[6559, 6656, 0]"]
1017["Segment<br>[6668, 6787, 0]"] 1017["Segment<br>[6664, 6783, 0]"]
1018["Segment<br>[6795, 6843, 0]"] 1018["Segment<br>[6791, 6839, 0]"]
1019["Segment<br>[6851, 6972, 0]"] 1019["Segment<br>[6847, 6968, 0]"]
1020["Segment<br>[6980, 6987, 0]"] 1020["Segment<br>[6976, 6983, 0]"]
1021[Solid2d] 1021[Solid2d]
end end
1["Plane<br>[532, 549, 0]"] 1["Plane<br>[532, 549, 0]"]
@ -983,7 +983,7 @@ flowchart LR
877["SweepEdge Opposite"] 877["SweepEdge Opposite"]
878["SweepEdge Adjacent"] 878["SweepEdge Adjacent"]
879["Plane<br>[4924, 4947, 0]"] 879["Plane<br>[4924, 4947, 0]"]
898["Sweep Extrusion<br>[5839, 5863, 0]"] 898["Sweep Extrusion<br>[5835, 5859, 0]"]
899[Wall] 899[Wall]
900[Wall] 900[Wall]
901[Wall] 901[Wall]
@ -1034,8 +1034,8 @@ flowchart LR
946["SweepEdge Adjacent"] 946["SweepEdge Adjacent"]
947["SweepEdge Opposite"] 947["SweepEdge Opposite"]
948["SweepEdge Adjacent"] 948["SweepEdge Adjacent"]
949["Plane<br>[6000, 6023, 0]"] 949["Plane<br>[5996, 6019, 0]"]
956["Sweep Extrusion<br>[6463, 6487, 0]"] 956["Sweep Extrusion<br>[6459, 6483, 0]"]
957[Wall] 957[Wall]
958[Wall] 958[Wall]
959[Wall] 959[Wall]
@ -1050,8 +1050,8 @@ flowchart LR
968["SweepEdge Adjacent"] 968["SweepEdge Adjacent"]
969["SweepEdge Opposite"] 969["SweepEdge Opposite"]
970["SweepEdge Adjacent"] 970["SweepEdge Adjacent"]
971["Plane<br>[6532, 6555, 0]"] 971["Plane<br>[6528, 6551, 0]"]
978["Sweep Extrusion<br>[6995, 7019, 0]"] 978["Sweep Extrusion<br>[6991, 7015, 0]"]
979[Wall] 979[Wall]
980[Wall] 980[Wall]
981[Wall] 981[Wall]
@ -1066,8 +1066,8 @@ flowchart LR
990["SweepEdge Adjacent"] 990["SweepEdge Adjacent"]
991["SweepEdge Opposite"] 991["SweepEdge Opposite"]
992["SweepEdge Adjacent"] 992["SweepEdge Adjacent"]
993["Plane<br>[6000, 6023, 0]"] 993["Plane<br>[5996, 6019, 0]"]
1000["Sweep Extrusion<br>[6463, 6487, 0]"] 1000["Sweep Extrusion<br>[6459, 6483, 0]"]
1001[Wall] 1001[Wall]
1002[Wall] 1002[Wall]
1003[Wall] 1003[Wall]
@ -1082,8 +1082,8 @@ flowchart LR
1012["SweepEdge Adjacent"] 1012["SweepEdge Adjacent"]
1013["SweepEdge Opposite"] 1013["SweepEdge Opposite"]
1014["SweepEdge Adjacent"] 1014["SweepEdge Adjacent"]
1015["Plane<br>[6532, 6555, 0]"] 1015["Plane<br>[6528, 6551, 0]"]
1022["Sweep Extrusion<br>[6995, 7019, 0]"] 1022["Sweep Extrusion<br>[6991, 7015, 0]"]
1023[Wall] 1023[Wall]
1024[Wall] 1024[Wall]
1025[Wall] 1025[Wall]

View File

@ -9548,22 +9548,15 @@ description: Result of parsing keyboard.kcl
{ {
"arguments": [ "arguments": [
{ {
"commentStart": 0, "type": "LabeledArg",
"end": 0, "label": {
"properties": [
{
"commentStart": 0,
"end": 0,
"key": {
"commentStart": 0, "commentStart": 0,
"end": 0, "end": 0,
"name": "angle", "name": "angle",
"start": 0, "start": 0,
"type": "Identifier" "type": "Identifier"
}, },
"start": 0, "arg": {
"type": "ObjectProperty",
"value": {
"commentStart": 0, "commentStart": 0,
"end": 0, "end": 0,
"raw": "0", "raw": "0",
@ -9577,18 +9570,15 @@ description: Result of parsing keyboard.kcl
} }
}, },
{ {
"commentStart": 0, "type": "LabeledArg",
"end": 0, "label": {
"key": {
"commentStart": 0, "commentStart": 0,
"end": 0, "end": 0,
"name": "intersectTag", "name": "intersectTag",
"start": 0, "start": 0,
"type": "Identifier" "type": "Identifier"
}, },
"start": 0, "arg": {
"type": "ObjectProperty",
"value": {
"abs_path": false, "abs_path": false,
"commentStart": 0, "commentStart": 0,
"end": 0, "end": 0,
@ -9606,18 +9596,15 @@ description: Result of parsing keyboard.kcl
} }
}, },
{ {
"commentStart": 0, "type": "LabeledArg",
"end": 0, "label": {
"key": {
"commentStart": 0, "commentStart": 0,
"end": 0, "end": 0,
"name": "offset", "name": "offset",
"start": 0, "start": 0,
"type": "Identifier" "type": "Identifier"
}, },
"start": 0, "arg": {
"type": "ObjectProperty",
"value": {
"commentStart": 0, "commentStart": 0,
"end": 0, "end": 0,
"raw": "0", "raw": "0",
@ -9631,18 +9618,6 @@ description: Result of parsing keyboard.kcl
} }
} }
], ],
"start": 0,
"type": "ObjectExpression",
"type": "ObjectExpression"
},
{
"commentStart": 0,
"end": 0,
"start": 0,
"type": "PipeSubstitution",
"type": "PipeSubstitution"
}
],
"callee": { "callee": {
"abs_path": false, "abs_path": false,
"commentStart": 0, "commentStart": 0,
@ -9661,8 +9636,9 @@ description: Result of parsing keyboard.kcl
"commentStart": 0, "commentStart": 0,
"end": 0, "end": 0,
"start": 0, "start": 0,
"type": "CallExpression", "type": "CallExpressionKw",
"type": "CallExpression" "type": "CallExpressionKw",
"unlabeled": null
}, },
{ {
"arguments": [], "arguments": [],

View File

@ -7202,7 +7202,7 @@ description: Operations executed keyboard.kcl
"name": "z", "name": "z",
"functionSourceRange": [ "functionSourceRange": [
4893, 4893,
5913, 5909,
0 0
], ],
"unlabeledArg": null, "unlabeledArg": null,
@ -7438,8 +7438,8 @@ description: Operations executed keyboard.kcl
"type": "FunctionCall", "type": "FunctionCall",
"name": "o", "name": "o",
"functionSourceRange": [ "functionSourceRange": [
5960, 5956,
7069, 7065,
0 0
], ],
"unlabeledArg": null, "unlabeledArg": null,
@ -7894,8 +7894,8 @@ description: Operations executed keyboard.kcl
"type": "FunctionCall", "type": "FunctionCall",
"name": "o", "name": "o",
"functionSourceRange": [ "functionSourceRange": [
5960, 5956,
7069, 7065,
0 0
], ],
"unlabeledArg": null, "unlabeledArg": null,

View File

@ -94,40 +94,40 @@ flowchart LR
168["Segment<br>[759, 787, 12]"] 168["Segment<br>[759, 787, 12]"]
169["Segment<br>[795, 829, 12]"] 169["Segment<br>[795, 829, 12]"]
170["Segment<br>[837, 867, 12]"] 170["Segment<br>[837, 867, 12]"]
171["Segment<br>[875, 984, 12]"] 171["Segment<br>[875, 980, 12]"]
172["Segment<br>[992, 999, 12]"] 172["Segment<br>[988, 995, 12]"]
173[Solid2d] 173[Solid2d]
end end
subgraph path175 [Path] subgraph path175 [Path]
175["Path<br>[1133, 1231, 12]"] 175["Path<br>[1129, 1227, 12]"]
176["Segment<br>[1239, 1358, 12]"] 176["Segment<br>[1235, 1354, 12]"]
177["Segment<br>[1366, 1413, 12]"] 177["Segment<br>[1362, 1409, 12]"]
178["Segment<br>[1421, 1542, 12]"] 178["Segment<br>[1417, 1538, 12]"]
179["Segment<br>[1550, 1557, 12]"] 179["Segment<br>[1546, 1553, 12]"]
180[Solid2d] 180[Solid2d]
end end
subgraph path182 [Path] subgraph path182 [Path]
182["Path<br>[1654, 1751, 12]"] 182["Path<br>[1650, 1747, 12]"]
183["Segment<br>[1759, 1878, 12]"] 183["Segment<br>[1755, 1874, 12]"]
184["Segment<br>[1886, 1934, 12]"] 184["Segment<br>[1882, 1930, 12]"]
185["Segment<br>[1942, 2063, 12]"] 185["Segment<br>[1938, 2059, 12]"]
186["Segment<br>[2071, 2078, 12]"] 186["Segment<br>[2067, 2074, 12]"]
187[Solid2d] 187[Solid2d]
end end
subgraph path189 [Path] subgraph path189 [Path]
189["Path<br>[1133, 1231, 12]"] 189["Path<br>[1129, 1227, 12]"]
190["Segment<br>[1239, 1358, 12]"] 190["Segment<br>[1235, 1354, 12]"]
191["Segment<br>[1366, 1413, 12]"] 191["Segment<br>[1362, 1409, 12]"]
192["Segment<br>[1421, 1542, 12]"] 192["Segment<br>[1417, 1538, 12]"]
193["Segment<br>[1550, 1557, 12]"] 193["Segment<br>[1546, 1553, 12]"]
194[Solid2d] 194[Solid2d]
end end
subgraph path196 [Path] subgraph path196 [Path]
196["Path<br>[1654, 1751, 12]"] 196["Path<br>[1650, 1747, 12]"]
197["Segment<br>[1759, 1878, 12]"] 197["Segment<br>[1755, 1874, 12]"]
198["Segment<br>[1886, 1934, 12]"] 198["Segment<br>[1882, 1930, 12]"]
199["Segment<br>[1942, 2063, 12]"] 199["Segment<br>[1938, 2059, 12]"]
200["Segment<br>[2071, 2078, 12]"] 200["Segment<br>[2067, 2074, 12]"]
201[Solid2d] 201[Solid2d]
end end
subgraph path230 [Path] subgraph path230 [Path]

View File

@ -1512,7 +1512,7 @@ description: Operations executed walkie-talkie.kcl
"name": "zLogo", "name": "zLogo",
"functionSourceRange": [ "functionSourceRange": [
69, 69,
1018, 1014,
12 12
], ],
"unlabeledArg": null, "unlabeledArg": null,
@ -1570,8 +1570,8 @@ description: Operations executed walkie-talkie.kcl
"type": "FunctionCall", "type": "FunctionCall",
"name": "oLogo", "name": "oLogo",
"functionSourceRange": [ "functionSourceRange": [
1076, 1072,
1579, 1575,
12 12
], ],
"unlabeledArg": null, "unlabeledArg": null,
@ -1629,8 +1629,8 @@ description: Operations executed walkie-talkie.kcl
"type": "FunctionCall", "type": "FunctionCall",
"name": "oLogo2", "name": "oLogo2",
"functionSourceRange": [ "functionSourceRange": [
1597, 1593,
2100, 2096,
12 12
], ],
"unlabeledArg": null, "unlabeledArg": null,
@ -1688,8 +1688,8 @@ description: Operations executed walkie-talkie.kcl
"type": "FunctionCall", "type": "FunctionCall",
"name": "oLogo", "name": "oLogo",
"functionSourceRange": [ "functionSourceRange": [
1076, 1072,
1579, 1575,
12 12
], ],
"unlabeledArg": null, "unlabeledArg": null,
@ -1747,8 +1747,8 @@ description: Operations executed walkie-talkie.kcl
"type": "FunctionCall", "type": "FunctionCall",
"name": "oLogo2", "name": "oLogo2",
"functionSourceRange": [ "functionSourceRange": [
1597, 1593,
2100, 2096,
12 12
], ],
"unlabeledArg": null, "unlabeledArg": null,

View File

@ -8,5 +8,7 @@ export const DETERMINING_ARGS = [ARG_LENGTH, ARG_END, ARG_END_ABSOLUTE]
export const ARG_LENGTH_X = 'lengthX' export const ARG_LENGTH_X = 'lengthX'
export const ARG_LENGTH_Y = 'lengthY' export const ARG_LENGTH_Y = 'lengthY'
export const ARG_ANGLE = 'angle' export const ARG_ANGLE = 'angle'
export const ARG_OFFSET = 'offset'
export const ARG_END_ABSOLUTE_X = 'endAbsoluteX' export const ARG_END_ABSOLUTE_X = 'endAbsoluteX'
export const ARG_END_ABSOLUTE_Y = 'endAbsoluteY' export const ARG_END_ABSOLUTE_Y = 'endAbsoluteY'
export const ARG_INTERSECT_TAG = 'intersectTag'

View File

@ -642,7 +642,7 @@ ${!replace1 ? ` |> ${line}\n` : ''} |> angledLine(angle = -65, length = ${
], ],
[ [
'angledLineThatIntersects', 'angledLineThatIntersects',
`angledLineThatIntersects({ angle = 45.5, intersectTag = b, offset = 198.85 }, %, $a)`, `angledLineThatIntersects(angle = 45.5, intersectTag = b, offset = 198.85, tag = $a)`,
['918.4', '45.5'], ['918.4', '45.5'],
], ],
])(`%s`, async (_, line, [replace1, replace2]) => { ])(`%s`, async (_, line, [replace1, replace2]) => {
@ -684,11 +684,7 @@ describe('Testing removeSingleConstraintInfo', () => {
|> /*2*/ angledLine(angle = 30 + 0, lengthY = 3 + 0) |> /*2*/ angledLine(angle = 30 + 0, lengthY = 3 + 0)
|> /*3*/ angledLine(angle = 12.14 + 0, endAbsoluteX = 12 + 0) |> /*3*/ angledLine(angle = 12.14 + 0, endAbsoluteX = 12 + 0)
|> /*4*/ angledLine(angle = 30 + 0, endAbsoluteY = 10.14 + 0) |> /*4*/ angledLine(angle = 30 + 0, endAbsoluteY = 10.14 + 0)
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = 3.14 + 0, intersectTag = a, offset = 0 + 0)
angle = 3.14 + 0,
intersectTag = a,
offset = 0 + 0
}, %)
|> tangentialArc(endAbsolute = [3.14 + 0, 13.14 + 0])` |> tangentialArc(endAbsolute = [3.14 + 0, 13.14 + 0])`
test.each([ test.each([
[' line(end = [3 + 0, 4])', 'arrayIndex', 1, ''], [' line(end = [3 + 0, 4])', 'arrayIndex', 1, ''],
@ -728,12 +724,8 @@ describe('Testing removeSingleConstraintInfo', () => {
'', '',
], ],
[ [
`angledLineThatIntersects({ `angledLineThatIntersects(angle = 3.14 + 0, intersectTag = a, offset = 0)`,
angle = 3.14 + 0, 'labeledArg',
offset = 0,
intersectTag = a
}, %)`,
'objectProperty',
'offset', 'offset',
'', '',
], ],
@ -762,11 +754,6 @@ describe('Testing removeSingleConstraintInfo', () => {
type: 'arrayItem', type: 'arrayItem',
index: value === 0 ? 0 : 1, index: value === 0 ? 0 : 1,
} }
} else if (key === 'objectProperty' && typeof value === 'string') {
argPosition = {
type: 'objectProperty',
key: value,
}
} else if (key === '') { } else if (key === '') {
argPosition = { argPosition = {
type: 'singleValue', type: 'singleValue',

View File

@ -337,11 +337,7 @@ describe('it recasts wrapped object expressions in pipe bodies with correct inde
|> startProfileAt([-0.01, -0.08], %) |> startProfileAt([-0.01, -0.08], %)
|> line(end = [0.62, 4.15], tag = $seg01) |> line(end = [0.62, 4.15], tag = $seg01)
|> line(end = [2.77, -1.24]) |> line(end = [2.77, -1.24])
|> angledLineThatIntersects({ |> angledLineThatIntersects(angle = 201, offset = -1.35, intersectTag = $seg01)
angle = 201,
offset = -1.35,
intersectTag = $seg01
}, %)
|> line(end = [-0.42, -1.72]) |> line(end = [-0.42, -1.72])
` `
const { ast } = code2ast(code) const { ast } = code2ast(code)
@ -350,11 +346,7 @@ describe('it recasts wrapped object expressions in pipe bodies with correct inde
expect(recasted).toBe(code) expect(recasted).toBe(code)
}) })
it('recasts wrapped object expressions NOT in pipe body correctly', () => { it('recasts wrapped object expressions NOT in pipe body correctly', () => {
const code = `angledLineThatIntersects({ const code = `angledLineThatIntersects(angle = 201, offset = -1.35, intersectTag = $seg01)
angle = 201,
offset = -1.35,
intersectTag = $seg01
}, %)
` `
const { ast } = code2ast(code) const { ast } = code2ast(code)
const recasted = recast(ast) const recasted = recast(ast)

View File

@ -330,11 +330,11 @@ describe('testing getConstraintInfo', () => {
|> angledLine(angle = 30, lengthY = 3) |> angledLine(angle = 30, lengthY = 3)
|> angledLine(angle = 12.14, endAbsoluteX = 12) |> angledLine(angle = 12.14, endAbsoluteX = 12)
|> angledLine(angle = 30, endAbsoluteY = 10.14) |> angledLine(angle = 30, endAbsoluteY = 10.14)
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle = 3.14, angle = 3.14,
intersectTag = a, intersectTag = a,
offset = 0 offset = 0,
}, %) )
|> tangentialArc(endAbsolute = [3.14, 13.14])` |> tangentialArc(endAbsolute = [3.14, 13.14])`
test.each([ test.each([
[ [
@ -598,16 +598,7 @@ describe('testing getConstraintInfo', () => {
isConstrained: false, isConstrained: false,
value: '3.14', value: '3.14',
sourceRange: [expect.any(Number), expect.any(Number), 0], sourceRange: [expect.any(Number), expect.any(Number), 0],
argPosition: { type: 'objectProperty', key: 'angle' }, argPosition: { type: 'labeledArg', key: 'angle' },
pathToNode: expect.any(Array),
stdLibFnName: 'angledLineThatIntersects',
},
{
type: 'intersectionOffset',
isConstrained: false,
value: '0',
sourceRange: [expect.any(Number), expect.any(Number), 0],
argPosition: { type: 'objectProperty', key: 'offset' },
pathToNode: expect.any(Array), pathToNode: expect.any(Array),
stdLibFnName: 'angledLineThatIntersects', stdLibFnName: 'angledLineThatIntersects',
}, },
@ -618,11 +609,20 @@ describe('testing getConstraintInfo', () => {
sourceRange: [expect.any(Number), expect.any(Number), 0], sourceRange: [expect.any(Number), expect.any(Number), 0],
argPosition: { argPosition: {
key: 'intersectTag', key: 'intersectTag',
type: 'objectProperty', type: 'labeledArg',
}, },
pathToNode: expect.any(Array), pathToNode: expect.any(Array),
stdLibFnName: 'angledLineThatIntersects', stdLibFnName: 'angledLineThatIntersects',
}, },
{
type: 'intersectionOffset',
isConstrained: false,
value: '0',
sourceRange: [expect.any(Number), expect.any(Number), 0],
argPosition: { type: 'labeledArg', key: 'offset' },
pathToNode: expect.any(Array),
stdLibFnName: 'angledLineThatIntersects',
},
], ],
], ],
[ [
@ -696,11 +696,11 @@ describe('testing getConstraintInfo', () => {
|> angledLine(angle = 30, lengthY = 3) |> angledLine(angle = 30, lengthY = 3)
|> angledLine(angle = 12, endAbsoluteX = 12) |> angledLine(angle = 12, endAbsoluteX = 12)
|> angledLine(angle = 30, endAbsoluteY = 10) |> angledLine(angle = 30, endAbsoluteY = 10)
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle = 3.14, angle = 3.14,
intersectTag = a, intersectTag = a,
offset = 0 offset = 0,
}, %) )
|> tangentialArc(endAbsolute = [3.14, 13.14])` |> tangentialArc(endAbsolute = [3.14, 13.14])`
test.each([ test.each([
[ [
@ -857,11 +857,11 @@ describe('testing getConstraintInfo', () => {
|> angledLine(angle = 30 + 0, lengthY = 3 + 0) |> angledLine(angle = 30 + 0, lengthY = 3 + 0)
|> angledLine(angle = 12.14 + 0, endAbsoluteX = 12 + 0) |> angledLine(angle = 12.14 + 0, endAbsoluteX = 12 + 0)
|> angledLine(angle = 30 + 0, endAbsoluteY = 10.14 + 0) |> angledLine(angle = 30 + 0, endAbsoluteY = 10.14 + 0)
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle = 3.14 + 0, angle = 3.14 + 0,
intersectTag = a, intersectTag = a,
offset = 0 + 0 offset = 0 + 0,
}, %) )
|> tangentialArc(endAbsolute = [3.14 + 0, 13.14 + 0])` |> tangentialArc(endAbsolute = [3.14 + 0, 13.14 + 0])`
test.each([ test.each([
[ [
@ -1125,16 +1125,7 @@ describe('testing getConstraintInfo', () => {
isConstrained: true, isConstrained: true,
value: '3.14 + 0', value: '3.14 + 0',
sourceRange: [expect.any(Number), expect.any(Number), 0], sourceRange: [expect.any(Number), expect.any(Number), 0],
argPosition: { type: 'objectProperty', key: 'angle' }, argPosition: { type: 'labeledArg', key: 'angle' },
pathToNode: expect.any(Array),
stdLibFnName: 'angledLineThatIntersects',
},
{
type: 'intersectionOffset',
isConstrained: true,
value: '0 + 0',
sourceRange: [expect.any(Number), expect.any(Number), 0],
argPosition: { type: 'objectProperty', key: 'offset' },
pathToNode: expect.any(Array), pathToNode: expect.any(Array),
stdLibFnName: 'angledLineThatIntersects', stdLibFnName: 'angledLineThatIntersects',
}, },
@ -1143,7 +1134,16 @@ describe('testing getConstraintInfo', () => {
isConstrained: false, isConstrained: false,
value: 'a', value: 'a',
sourceRange: [expect.any(Number), expect.any(Number), 0], sourceRange: [expect.any(Number), expect.any(Number), 0],
argPosition: { key: 'intersectTag', type: 'objectProperty' }, argPosition: { key: 'intersectTag', type: 'labeledArg' },
pathToNode: expect.any(Array),
stdLibFnName: 'angledLineThatIntersects',
},
{
type: 'intersectionOffset',
isConstrained: true,
value: '0 + 0',
sourceRange: [expect.any(Number), expect.any(Number), 0],
argPosition: { type: 'labeledArg', key: 'offset' },
pathToNode: expect.any(Array), pathToNode: expect.any(Array),
stdLibFnName: 'angledLineThatIntersects', stdLibFnName: 'angledLineThatIntersects',
}, },

View File

@ -1,6 +1,5 @@
import { perpendicularDistance } from 'sketch-helpers' import { perpendicularDistance } from 'sketch-helpers'
import type { Name } from '@rust/kcl-lib/bindings/Name'
import type { Node } from '@rust/kcl-lib/bindings/Node' import type { Node } from '@rust/kcl-lib/bindings/Node'
import type { TagDeclarator } from '@rust/kcl-lib/bindings/TagDeclarator' import type { TagDeclarator } from '@rust/kcl-lib/bindings/TagDeclarator'
@ -12,9 +11,11 @@ import {
ARG_END_ABSOLUTE, ARG_END_ABSOLUTE,
ARG_END_ABSOLUTE_X, ARG_END_ABSOLUTE_X,
ARG_END_ABSOLUTE_Y, ARG_END_ABSOLUTE_Y,
ARG_INTERSECT_TAG,
ARG_LENGTH, ARG_LENGTH,
ARG_LENGTH_X, ARG_LENGTH_X,
ARG_LENGTH_Y, ARG_LENGTH_Y,
ARG_OFFSET,
ARG_TAG, ARG_TAG,
DETERMINING_ARGS, DETERMINING_ARGS,
} from '@src/lang/constants' } from '@src/lang/constants'
@ -128,15 +129,10 @@ export function createFirstArg(
'angledLineOfYLength', 'angledLineOfYLength',
'angledLineToX', 'angledLineToX',
'angledLineToY', 'angledLineToY',
'angledLineThatIntersects',
].includes(sketchFn) ].includes(sketchFn)
) )
return createArrayExpression(val) return createArrayExpression(val)
if (['angledLineThatIntersects'].includes(sketchFn) && val[2])
return createObjectExpression({
angle: val[0],
offset: val[1],
intersectTag: val[2],
})
} else { } else {
if (['xLine', 'xLineTo', 'yLine', 'yLineTo'].includes(sketchFn)) return val if (['xLine', 'xLineTo', 'yLine', 'yLineTo'].includes(sketchFn)) return val
} }
@ -2819,7 +2815,7 @@ export const angledLineToY: SketchLineHelperKw = {
), ),
} }
export const angledLineThatIntersects: SketchLineHelper = { export const angledLineThatIntersects: SketchLineHelperKw = {
add: ({ add: ({
node, node,
pathToNode, pathToNode,
@ -2858,13 +2854,13 @@ export const angledLineThatIntersects: SketchLineHelper = {
if (replaceExistingCallback) { if (replaceExistingCallback) {
const result = replaceExistingCallback([ const result = replaceExistingCallback([
{ {
type: 'objectProperty', type: 'labeledArg',
key: 'angle', key: 'angle',
argType: 'angle', argType: 'angle',
expr: angle, expr: angle,
}, },
{ {
type: 'objectProperty', type: 'labeledArg',
key: 'offset', key: 'offset',
argType: 'intersectionOffset', argType: 'intersectionOffset',
expr: offset, expr: offset,
@ -2886,18 +2882,18 @@ export const angledLineThatIntersects: SketchLineHelper = {
if (input.type !== 'straight-segment') return STRAIGHT_SEGMENT_ERR if (input.type !== 'straight-segment') return STRAIGHT_SEGMENT_ERR
const { to, from } = input const { to, from } = input
const _node = { ...node } const _node = { ...node }
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode) const nodeMeta = getNodeFromPath<CallExpressionKw>(_node, pathToNode)
if (err(nodeMeta)) return nodeMeta if (err(nodeMeta)) return nodeMeta
const { node: callExpression } = nodeMeta const { node: callExpression } = nodeMeta
const angle = roundOff(getAngle(from, to), 0) const angle = roundOff(getAngle(from, to), 0)
const firstArg = callExpression.arguments?.[0] const intersectTag = findKwArg(ARG_INTERSECT_TAG, callExpression)
const intersectTag = if (intersectTag === undefined) {
firstArg.type === 'ObjectExpression' return new Error(
? firstArg.properties.find((p) => p.key.name === 'intersectTag') `no ${ARG_INTERSECT_TAG} argument found in angledLineThatIntersect call, which requires it`
?.value || createLiteral('') )
: createLiteral('') }
const intersectTagName = const intersectTagName =
intersectTag.type === 'Name' ? intersectTag.name.name : '' intersectTag.type === 'Name' ? intersectTag.name.name : ''
const nodeMeta2 = getNodeFromPath<VariableDeclaration>( const nodeMeta2 = getNodeFromPath<VariableDeclaration>(
@ -2922,94 +2918,79 @@ export const angledLineThatIntersects: SketchLineHelper = {
) )
} }
const angleLit = createLiteral(angle) mutateKwArg(ARG_ANGLE, callExpression, createLiteral(angle))
mutateKwArg(ARG_OFFSET, callExpression, createLiteral(offset))
mutateObjExpProp(firstArg, angleLit, 'angle')
mutateObjExpProp(firstArg, createLiteral(offset), 'offset')
return { return {
modifiedAst: _node, modifiedAst: _node,
pathToNode, pathToNode,
} }
}, },
getTag: getTag(), getTag: getTagKwArg(),
addTag: addTag(), addTag: addTagKw(),
getConstraintInfo: (callExp: CallExpression, code, pathToNode) => { getConstraintInfo: (callExp: CallExpressionKw, code, pathToNode) => {
if (callExp.type !== 'CallExpression') return [] if (callExp.type !== 'CallExpressionKw') return []
const firstArg = callExp.arguments?.[0] const angle = findKwArgWithIndex(ARG_ANGLE, callExp)
if (firstArg.type !== 'ObjectExpression') return [] const offset = findKwArgWithIndex(ARG_OFFSET, callExp)
const angleIndex = firstArg.properties.findIndex( const intersectTag = findKwArgWithIndex(ARG_INTERSECT_TAG, callExp)
(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 returnVal = []
const pathToObjectExp: PathToNode = [ const pathToBase: PathToNode = [
...pathToNode, ...pathToNode,
['arguments', 'CallExpression'], ['arguments', 'CallExpressionKw'],
[0, 'index'],
['properties', 'ObjectExpression'],
] ]
if (angleIndex !== -1) { if (angle !== undefined) {
const angle = firstArg.properties[angleIndex]?.value
const pathToAngleProp: PathToNode = [ const pathToAngleProp: PathToNode = [
...pathToObjectExp, ...pathToBase,
[angleIndex, 'index'], [angle.argIndex, ARG_INDEX_FIELD],
['value', 'Property'], ['arg', LABELED_ARG_FIELD],
] ]
returnVal.push( returnVal.push(
constrainInfo( constrainInfo(
'angle', 'angle',
isNotLiteralArrayOrStatic(angle), isNotLiteralArrayOrStatic(angle.expr),
code.slice(angle.start, angle.end), code.slice(angle.expr.start, angle.expr.end),
'angledLineThatIntersects', 'angledLineThatIntersects',
'angle', { type: 'labeledArg', key: 'angle' },
topLevelRange(angle.start, angle.end), topLevelRange(angle.expr.start, angle.expr.end),
pathToAngleProp pathToAngleProp
) )
) )
} }
if (offsetIndex !== -1) { if (intersectTag !== undefined) {
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',
topLevelRange(offset.start, offset.end),
pathToOffsetProp
)
)
}
if (intersectTag !== -1) {
const tag = firstArg.properties[intersectTag]?.value as Node<Name>
const pathToTagProp: PathToNode = [ const pathToTagProp: PathToNode = [
...pathToObjectExp, ...pathToBase,
[intersectTag, 'index'], [intersectTag.argIndex, ARG_INDEX_FIELD],
['value', 'Property'], ['arg', LABELED_ARG_FIELD],
] ]
const info = constrainInfo( const info = constrainInfo(
'intersectionTag', 'intersectionTag',
// This will always be a tag identifier. // This will always be a tag identifier.
false, false,
code.slice(tag.start, tag.end), code.slice(intersectTag.expr.start, intersectTag.expr.end),
'angledLineThatIntersects', 'angledLineThatIntersects',
'intersectTag', { type: 'labeledArg', key: 'intersectTag' },
topLevelRange(tag.start, tag.end), topLevelRange(intersectTag.expr.start, intersectTag.expr.end),
pathToTagProp pathToTagProp
) )
returnVal.push(info) returnVal.push(info)
} }
if (offset !== undefined) {
const pathToOffsetProp: PathToNode = [
...pathToBase,
[offset.argIndex, ARG_INDEX_FIELD],
['arg', LABELED_ARG_FIELD],
]
returnVal.push(
constrainInfo(
'intersectionOffset',
isNotLiteralArrayOrStatic(offset.expr),
code.slice(offset.expr.start, offset.expr.end),
'angledLineThatIntersects',
{ type: 'labeledArg', key: 'offset' },
topLevelRange(offset.expr.start, offset.expr.end),
pathToOffsetProp
)
)
}
return returnVal return returnVal
}, },
} }
@ -3064,7 +3045,6 @@ export const updateStartProfileAtArgs: SketchLineHelper['updateArgs'] = ({
} }
export const sketchLineHelperMap: { [key: string]: SketchLineHelper } = { export const sketchLineHelperMap: { [key: string]: SketchLineHelper } = {
angledLineThatIntersects,
arc, arc,
arcTo, arcTo,
} as const } as const
@ -3081,6 +3061,7 @@ export const sketchLineHelperMapKw: { [key: string]: SketchLineHelperKw } = {
angledLine, angledLine,
angledLineOfXLength, angledLineOfXLength,
angledLineOfYLength, angledLineOfYLength,
angledLineThatIntersects,
angledLineToX, angledLineToX,
angledLineToY, angledLineToY,
tangentialArc, tangentialArc,
@ -3173,6 +3154,7 @@ export function fnNameToTooltip(
return isAbsolute ? 'xLineTo' : 'xLine' return isAbsolute ? 'xLineTo' : 'xLine'
case 'yLine': case 'yLine':
return isAbsolute ? 'yLineTo' : 'yLine' return isAbsolute ? 'yLineTo' : 'yLine'
case 'angledLineThatIntersects':
case 'circleThreePoint': case 'circleThreePoint':
case 'circle': case 'circle':
case 'tangentialArc': case 'tangentialArc':
@ -3191,7 +3173,7 @@ export function fnNameToTooltip(
return tooltip return tooltip
} }
} }
const err = `Unknown angledline arguments, could not map to tooltip. Args were ${argLabels}` const err = `Unknown angledLine arguments, could not map to tooltip. Args were ${argLabels}`
console.error(err) console.error(err)
return new Error(err) return new Error(err)
} }
@ -3893,29 +3875,24 @@ export const getCircle = (
return new Error('expected the arguments to be for a circle') return new Error('expected the arguments to be for a circle')
} }
const getAngledLineThatIntersects = ( export const getAngledLineThatIntersects = (
callExp: CallExpression callExp: CallExpressionKw
): ):
| { | {
val: [Expr, Expr, Expr] val: [Expr, Expr, Expr]
tag?: Expr tag?: Expr
} }
| Error => { | Error => {
const firstArg = callExp.arguments[0] const angle = findKwArg(ARG_ANGLE, callExp)
if (firstArg.type === 'ObjectExpression') { const intersectTag = findKwArg(ARG_INTERSECT_TAG, callExp)
const tag = firstArg.properties.find((p) => p.key.name === 'tag')?.value const offset = findKwArg(ARG_OFFSET, callExp)
const angle = firstArg.properties.find((p) => p.key.name === 'angle')?.value if (!angle || !intersectTag || !offset) {
const offset = firstArg.properties.find( return new Error(
(p) => p.key.name === 'offset' `angledLineThatIntersects call needs angle, intersectTag, and offset args`
)?.value )
const intersectTag = firstArg.properties.find(
(p) => p.key.name === 'intersectTag'
)?.value
if (angle && offset && intersectTag) {
return { val: [angle, offset, intersectTag], tag }
} }
} const tag = findKwArg(ARG_TAG, callExp)
return new Error('expected ArrayExpression or ObjectExpression') return { val: [angle, intersectTag, offset], tag }
} }
/** /**
@ -3946,6 +3923,7 @@ export function isAbsoluteLine(lineCall: CallExpressionKw): boolean | Error {
return new Error( return new Error(
`${name} call has neither ${ARG_END} nor ${ARG_END_ABSOLUTE} params` `${name} call has neither ${ARG_END} nor ${ARG_END_ABSOLUTE} params`
) )
case 'angledLineThatIntersects':
case 'circle': case 'circle':
case 'circleThreePoint': case 'circleThreePoint':
return false return false
@ -3980,6 +3958,8 @@ export function getArgForEnd(lineCall: CallExpressionKw):
} }
return getValuesForXYFns(arg) return getValuesForXYFns(arg)
} }
case 'angledLineThatIntersects':
return getAngledLineThatIntersects(lineCall)
case 'yLine': case 'yLine':
case 'xLine': { case 'xLine': {
const arg = findKwArgAny(DETERMINING_ARGS, lineCall) const arg = findKwArgAny(DETERMINING_ARGS, lineCall)
@ -4039,9 +4019,6 @@ export function getFirstArg(callExp: CallExpression):
if (['xLine', 'yLine', 'xLineTo', 'yLineTo'].includes(name)) { if (['xLine', 'yLine', 'xLineTo', 'yLineTo'].includes(name)) {
return getFirstArgValuesForXYLineFns(callExp) return getFirstArgValuesForXYLineFns(callExp)
} }
if (['angledLineThatIntersects'].includes(name)) {
return getAngledLineThatIntersects(callExp)
}
if (['tangentialArc'].includes(name)) { if (['tangentialArc'].includes(name)) {
// TODO probably needs it's own implementation // TODO probably needs it's own implementation
return getFirstArgValuesForXYFns(callExp) return getFirstArgValuesForXYFns(callExp)

View File

@ -7,9 +7,11 @@ import {
ARG_END_ABSOLUTE, ARG_END_ABSOLUTE,
ARG_END_ABSOLUTE_X, ARG_END_ABSOLUTE_X,
ARG_END_ABSOLUTE_Y, ARG_END_ABSOLUTE_Y,
ARG_INTERSECT_TAG,
ARG_LENGTH, ARG_LENGTH,
ARG_LENGTH_X, ARG_LENGTH_X,
ARG_LENGTH_Y, ARG_LENGTH_Y,
ARG_OFFSET,
ARG_TAG, ARG_TAG,
DETERMINING_ARGS, DETERMINING_ARGS,
} from '@src/lang/constants' } from '@src/lang/constants'
@ -36,6 +38,7 @@ import {
createFirstArg, createFirstArg,
fnNameToTooltip, fnNameToTooltip,
getAngledLine, getAngledLine,
getAngledLineThatIntersects,
getArgForEnd, getArgForEnd,
getCircle, getCircle,
getConstraintInfo, getConstraintInfo,
@ -345,20 +348,16 @@ function intersectCallWrapper({
tag?: Expr tag?: Expr
valueUsedInTransform?: number valueUsedInTransform?: number
}): CreatedSketchExprResult { }): CreatedSketchExprResult {
const firstArg: any = { const args: LabeledArg[] = [
angle: angleVal, createLabeledArg(ARG_ANGLE, angleVal),
offset: offsetVal, createLabeledArg(ARG_OFFSET, offsetVal),
intersectTag, createLabeledArg(ARG_INTERSECT_TAG, intersectTag),
}
const args: Expr[] = [
createObjectExpression(firstArg),
createPipeSubstitution(),
] ]
if (tag) { if (tag) {
args.push(tag) args.push(createLabeledArg(ARG_TAG, tag))
} }
return { return {
callExp: createCallExpression(fnName, args), callExp: createCallExpressionStdLibKw(fnName, null, args),
valueUsedInTransform, valueUsedInTransform,
} }
} }
@ -2335,6 +2334,9 @@ export function getConstraintLevelFromSourceRange(
) { ) {
return getAngledLine(nodeMeta.node) return getAngledLine(nodeMeta.node)
} }
if (name === 'angledLineThatIntersects') {
return getAngledLineThatIntersects(nodeMeta.node)
}
const arg = findKwArgAny(DETERMINING_ARGS, nodeMeta.node) const arg = findKwArgAny(DETERMINING_ARGS, nodeMeta.node)
if (arg === undefined) { if (arg === undefined) {
const argStr = nodeMeta.node.arguments.map((a) => a.label.name) const argStr = nodeMeta.node.arguments.map((a) => a.label.name)

View File

@ -12,11 +12,12 @@ describe('testing angledLineThatIntersects', () => {
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(endAbsolute = [2, 2], tag = $yo) |> line(endAbsolute = [2, 2], tag = $yo)
|> line(endAbsolute = [3, 1]) |> line(endAbsolute = [3, 1])
|> angledLineThatIntersects({ |> angledLineThatIntersects(
angle: 180, angle = 180,
intersectTag: yo, intersectTag = yo,
offset: ${offset}, offset = ${offset},
}, %, $yo2) tag = $yo2,
)
intersect = segEndX(yo2)` intersect = segEndX(yo2)`
const execState = await enginelessExecutor(assertParse(code('-1'))) const execState = await enginelessExecutor(assertParse(code('-1')))
expect(execState.variables['intersect']?.value).toBe(1 + Math.sqrt(2)) expect(execState.variables['intersect']?.value).toBe(1 + Math.sqrt(2))