Compare commits
17 Commits
move-tests
...
nightly-v2
Author | SHA1 | Date | |
---|---|---|---|
ac60082e67 | |||
d44dc1b21a | |||
813962ea4c | |||
738443a6ab | |||
4b6bbbe2c5 | |||
6ff8addc8b | |||
da05c38b9e | |||
191b9b71fd | |||
05163fdded | |||
7ed26e21c6 | |||
c668d40efc | |||
f38c6b90b7 | |||
7bc8bae0ec | |||
3804aca27e | |||
b127680f2f | |||
b7de8e60cf | |||
058fccb5e1 |
2
.github/workflows/cargo-test.yml
vendored
@ -71,7 +71,7 @@ jobs:
|
||||
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
|
||||
RUST_MIN_STACK: 10485760000
|
||||
- name: Upload to codecov.io
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
token: ${{secrets.CODECOV_TOKEN}}
|
||||
fail_ci_if_error: true
|
||||
|
49
docs/kcl/atan2.md
Normal file
@ -30,6 +30,7 @@ layout: manual
|
||||
* [`assertLessThan`](kcl/assertLessThan)
|
||||
* [`assertLessThanOrEq`](kcl/assertLessThanOrEq)
|
||||
* [`atan`](kcl/atan)
|
||||
* [`atan2`](kcl/atan2)
|
||||
* [`bezierCurve`](kcl/bezierCurve)
|
||||
* [`ceil`](kcl/ceil)
|
||||
* [`chamfer`](kcl/chamfer)
|
||||
@ -102,6 +103,7 @@ layout: manual
|
||||
* [`startProfileAt`](kcl/startProfileAt)
|
||||
* [`startSketchAt`](kcl/startSketchAt)
|
||||
* [`startSketchOn`](kcl/startSketchOn)
|
||||
* [`sweep`](kcl/sweep)
|
||||
* [`tan`](kcl/tan)
|
||||
* [`tangentToEnd`](kcl/tangentToEnd)
|
||||
* [`tangentialArc`](kcl/tangentialArc)
|
||||
|
@ -43,7 +43,7 @@ fn sum(arr) {
|
||||
|
||||
/* The above is basically like this pseudo-code:
|
||||
fn sum(arr):
|
||||
let sumSoFar = 0
|
||||
sumSoFar = 0
|
||||
for i in arr:
|
||||
sumSoFar = add(sumSoFar, i)
|
||||
return sumSoFar */
|
||||
@ -96,14 +96,14 @@ fn decagon(radius) {
|
||||
|
||||
/* The `decagon` above is basically like this pseudo-code:
|
||||
fn decagon(radius):
|
||||
let stepAngle = (1/10) * tau()
|
||||
let startOfDecagonSketch = startSketchAt([(cos(0)*radius), (sin(0) * radius)])
|
||||
stepAngle = (1/10) * tau()
|
||||
startOfDecagonSketch = startSketchAt([(cos(0)*radius), (sin(0) * radius)])
|
||||
|
||||
// Here's the reduce part.
|
||||
let partialDecagon = startOfDecagonSketch
|
||||
partialDecagon = startOfDecagonSketch
|
||||
for i in [1..10]:
|
||||
let x = cos(stepAngle * i) * radius
|
||||
let y = sin(stepAngle * i) * radius
|
||||
x = cos(stepAngle * i) * radius
|
||||
y = sin(stepAngle * i) * radius
|
||||
partialDecagon = lineTo([x, y], partialDecagon)
|
||||
fullDecagon = partialDecagon // it's now full
|
||||
return fullDecagon */
|
||||
|
4335
docs/kcl/std.json
55
docs/kcl/sweep.md
Normal file
@ -12,5 +12,10 @@ KCL value for an optional parameter which was not given an argument. (remember,
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
||||
|
||||
|
||||
|
23
docs/kcl/types/SweepData.md
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
title: "SweepData"
|
||||
excerpt: "Data for a sweep."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
Data for a sweep.
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `path` |[`Sketch`](/docs/kcl/types/Sketch)| The path to sweep along. | No |
|
||||
| `sectional` |`boolean`| If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components. | No |
|
||||
| `tolerance` |`number`| Tolerance for the sweep operation. | No |
|
||||
|
||||
|
@ -94,6 +94,51 @@ test.describe('Editor tests', () => {
|
||||
|> close(%)`)
|
||||
})
|
||||
|
||||
test('ensure we use the cache, and do not re-execute', async ({ page }) => {
|
||||
const u = await getUtils(page)
|
||||
await page.setViewportSize({ width: 1000, height: 500 })
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await u.codeLocator.click()
|
||||
await page.keyboard.type(`sketch001 = startSketchOn('XY')
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %)
|
||||
|> line([0, 20], %)
|
||||
|> line([-20, 0], %)
|
||||
|> close(%)`)
|
||||
|
||||
// Ensure we execute the first time.
|
||||
await u.openDebugPanel()
|
||||
await expect(
|
||||
page.locator('[data-receive-command-type="scene_clear_all"]')
|
||||
).toHaveCount(2)
|
||||
await expect(
|
||||
page.locator('[data-message-type="execution-done"]')
|
||||
).toHaveCount(2)
|
||||
|
||||
// Add whitespace to the end of the code.
|
||||
await u.codeLocator.click()
|
||||
await page.keyboard.press('ArrowUp')
|
||||
await page.keyboard.press('ArrowUp')
|
||||
await page.keyboard.press('ArrowUp')
|
||||
await page.keyboard.press('ArrowUp')
|
||||
await page.keyboard.press('Home')
|
||||
await page.keyboard.type(' ')
|
||||
await page.keyboard.press('Enter')
|
||||
await page.keyboard.type(' ')
|
||||
|
||||
// Ensure we don't execute the second time.
|
||||
await u.openDebugPanel()
|
||||
// Make sure we didn't clear the scene.
|
||||
await expect(
|
||||
page.locator('[data-message-type="execution-done"]')
|
||||
).toHaveCount(3)
|
||||
await expect(
|
||||
page.locator('[data-receive-command-type="scene_clear_all"]')
|
||||
).toHaveCount(2)
|
||||
})
|
||||
|
||||
test('if you click the format button it formats your code and executes so lints are still there', async ({
|
||||
page,
|
||||
}) => {
|
||||
|
@ -1164,3 +1164,109 @@ test.fixme('theme persists', async ({ page, context }) => {
|
||||
maxDiffPixels: 100,
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('code color goober', { tag: '@snapshot' }, () => {
|
||||
test('code color goober', async ({ page, context }) => {
|
||||
const u = await getUtils(page)
|
||||
await context.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`// Create a pipe using a sweep.
|
||||
|
||||
// Create a path for the sweep.
|
||||
sweepPath = startSketchOn('XZ')
|
||||
|> startProfileAt([0.05, 0.05], %)
|
||||
|> line([0, 7], %)
|
||||
|> tangentialArc({ offset = 90, radius = 5 }, %)
|
||||
|> line([-3, 0], %)
|
||||
|> tangentialArc({ offset = -90, radius = 5 }, %)
|
||||
|> line([0, 7], %)
|
||||
|
||||
sweepSketch = startSketchOn('XY')
|
||||
|> startProfileAt([2, 0], %)
|
||||
|> arc({
|
||||
angleEnd = 360,
|
||||
angleStart = 0,
|
||||
radius = 2
|
||||
}, %)
|
||||
|> sweep({
|
||||
path = sweepPath,
|
||||
}, %)
|
||||
|> appearance({
|
||||
color = "#bb00ff",
|
||||
metalness = 90,
|
||||
roughness = 90
|
||||
}, %)
|
||||
`
|
||||
)
|
||||
})
|
||||
|
||||
await page.setViewportSize({ width: 1200, height: 1000 })
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await u.openDebugPanel()
|
||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||
await u.clearAndCloseDebugPanel()
|
||||
|
||||
await expect(page, 'expect small color widget').toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
})
|
||||
})
|
||||
|
||||
test('code color goober opening window', async ({ page, context }) => {
|
||||
const u = await getUtils(page)
|
||||
await context.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`// Create a pipe using a sweep.
|
||||
|
||||
// Create a path for the sweep.
|
||||
sweepPath = startSketchOn('XZ')
|
||||
|> startProfileAt([0.05, 0.05], %)
|
||||
|> line([0, 7], %)
|
||||
|> tangentialArc({ offset = 90, radius = 5 }, %)
|
||||
|> line([-3, 0], %)
|
||||
|> tangentialArc({ offset = -90, radius = 5 }, %)
|
||||
|> line([0, 7], %)
|
||||
|
||||
sweepSketch = startSketchOn('XY')
|
||||
|> startProfileAt([2, 0], %)
|
||||
|> arc({
|
||||
angleEnd = 360,
|
||||
angleStart = 0,
|
||||
radius = 2
|
||||
}, %)
|
||||
|> sweep({
|
||||
path = sweepPath,
|
||||
}, %)
|
||||
|> appearance({
|
||||
color = "#bb00ff",
|
||||
metalness = 90,
|
||||
roughness = 90
|
||||
}, %)
|
||||
`
|
||||
)
|
||||
})
|
||||
|
||||
await page.setViewportSize({ width: 1200, height: 1000 })
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await u.openDebugPanel()
|
||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||
await u.clearAndCloseDebugPanel()
|
||||
|
||||
await expect(page.locator('.cm-css-color-picker-wrapper')).toBeVisible()
|
||||
|
||||
// Click the color widget
|
||||
await page.locator('.cm-css-color-picker-wrapper input').click()
|
||||
|
||||
await expect(
|
||||
page,
|
||||
'expect small color widget to have window open'
|
||||
).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 144 KiB |
After Width: | Height: | Size: 130 KiB |
After Width: | Height: | Size: 139 KiB |
After Width: | Height: | Size: 124 KiB |
@ -14,7 +14,7 @@ export const TEST_SETTINGS = {
|
||||
},
|
||||
modeling: {
|
||||
defaultUnit: 'in',
|
||||
mouseControls: 'KittyCAD',
|
||||
mouseControls: 'Zoo',
|
||||
cameraProjection: 'perspective',
|
||||
showDebugPanel: true,
|
||||
},
|
||||
|
@ -479,4 +479,26 @@ test.describe('Testing Camera Movement', () => {
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('Right-click opens context menu when not dragged', async ({ page }) => {
|
||||
const u = await getUtils(page)
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await test.step(`The menu should not show if we drag the mouse`, async () => {
|
||||
await page.mouse.move(900, 200)
|
||||
await page.mouse.down({ button: 'right' })
|
||||
await page.mouse.move(900, 300)
|
||||
await page.mouse.up({ button: 'right' })
|
||||
|
||||
await expect(page.getByTestId('view-controls-menu')).not.toBeVisible()
|
||||
})
|
||||
|
||||
await test.step(`The menu should show if we don't drag the mouse`, async () => {
|
||||
await page.mouse.move(900, 200)
|
||||
await page.mouse.down({ button: 'right' })
|
||||
await page.mouse.up({ button: 'right' })
|
||||
|
||||
await expect(page.getByTestId('view-controls-menu')).toBeVisible()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -119,6 +119,11 @@
|
||||
"title": "Pipe and Flange Assembly",
|
||||
"description": "A crucial component in various piping systems, designed to facilitate the connection, disconnection, and access to piping for inspection, cleaning, and modifications. This assembly combines pipes (long cylindrical conduits) with flanges (plate-like fittings) to create a secure yet detachable joint."
|
||||
},
|
||||
{
|
||||
"file": "pipe-with-bend.kcl",
|
||||
"title": "Pipe with bend",
|
||||
"description": "A tubular section or hollow cylinder, usually but not necessarily of circular cross-section, used mainly to convey substances that can flow."
|
||||
},
|
||||
{
|
||||
"file": "poopy-shoe.kcl",
|
||||
"title": "Poopy Shoe",
|
||||
|
@ -105,7 +105,7 @@ export class CameraControls {
|
||||
pendingZoom: number | null = null
|
||||
pendingRotation: Vector2 | null = null
|
||||
pendingPan: Vector2 | null = null
|
||||
interactionGuards: MouseGuard = cameraMouseDragGuards.KittyCAD
|
||||
interactionGuards: MouseGuard = cameraMouseDragGuards.Zoo
|
||||
isFovAnimationInProgress = false
|
||||
perspectiveFovBeforeOrtho = 45
|
||||
get isPerspective() {
|
||||
|
@ -1,13 +1,23 @@
|
||||
import toast from 'react-hot-toast'
|
||||
import { ActionIcon, ActionIconProps } from './ActionIcon'
|
||||
import { RefObject, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import {
|
||||
MouseEvent,
|
||||
RefObject,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useHotkeys } from 'react-hotkeys-hook'
|
||||
import { Dialog } from '@headlessui/react'
|
||||
|
||||
interface ContextMenuProps
|
||||
export interface ContextMenuProps
|
||||
extends Omit<React.HTMLAttributes<HTMLUListElement>, 'children'> {
|
||||
items?: React.ReactElement[]
|
||||
menuTargetElement?: RefObject<HTMLElement>
|
||||
guard?: (e: globalThis.MouseEvent) => boolean
|
||||
event?: 'contextmenu' | 'mouseup'
|
||||
}
|
||||
|
||||
const DefaultContextMenuItems = [
|
||||
@ -20,6 +30,8 @@ export function ContextMenu({
|
||||
items = DefaultContextMenuItems,
|
||||
menuTargetElement,
|
||||
className,
|
||||
guard,
|
||||
event = 'contextmenu',
|
||||
...props
|
||||
}: ContextMenuProps) {
|
||||
const dialogRef = useRef<HTMLDivElement>(null)
|
||||
@ -32,6 +44,15 @@ export function ContextMenu({
|
||||
useHotkeys('esc', () => setOpen(false), {
|
||||
enabled: open,
|
||||
})
|
||||
const handleContextMenu = useCallback(
|
||||
(e: globalThis.MouseEvent) => {
|
||||
if (guard && !guard(e)) return
|
||||
e.preventDefault()
|
||||
setPosition({ x: e.clientX, y: e.clientY })
|
||||
setOpen(true)
|
||||
},
|
||||
[guard, setPosition, setOpen]
|
||||
)
|
||||
|
||||
const dialogPositionStyle = useMemo(() => {
|
||||
if (!dialogRef.current)
|
||||
@ -78,21 +99,9 @@ export function ContextMenu({
|
||||
|
||||
// Add context menu listener to target once mounted
|
||||
useEffect(() => {
|
||||
const handleContextMenu = (e: MouseEvent) => {
|
||||
console.log('context menu', e)
|
||||
e.preventDefault()
|
||||
setPosition({ x: e.x, y: e.y })
|
||||
setOpen(true)
|
||||
}
|
||||
menuTargetElement?.current?.addEventListener(
|
||||
'contextmenu',
|
||||
handleContextMenu
|
||||
)
|
||||
menuTargetElement?.current?.addEventListener(event, handleContextMenu)
|
||||
return () => {
|
||||
menuTargetElement?.current?.removeEventListener(
|
||||
'contextmenu',
|
||||
handleContextMenu
|
||||
)
|
||||
menuTargetElement?.current?.removeEventListener(event, handleContextMenu)
|
||||
}
|
||||
}, [menuTargetElement?.current])
|
||||
|
||||
@ -100,7 +109,10 @@ export function ContextMenu({
|
||||
<Dialog open={open} onClose={() => setOpen(false)}>
|
||||
<div
|
||||
className="fixed inset-0 z-50 w-screen h-screen"
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault()
|
||||
setPosition({ x: e.clientX, y: e.clientY })
|
||||
}}
|
||||
>
|
||||
<Dialog.Backdrop className="fixed z-10 inset-0" />
|
||||
<Dialog.Panel
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { SceneInfra } from 'clientSideScene/sceneInfra'
|
||||
import { sceneInfra } from 'lib/singletons'
|
||||
import { MutableRefObject, useEffect, useMemo, useRef } from 'react'
|
||||
import { MutableRefObject, useEffect, useRef } from 'react'
|
||||
import {
|
||||
WebGLRenderer,
|
||||
Scene,
|
||||
@ -19,16 +19,14 @@ import {
|
||||
Intersection,
|
||||
Object3D,
|
||||
} from 'three'
|
||||
import {
|
||||
ContextMenu,
|
||||
ContextMenuDivider,
|
||||
ContextMenuItem,
|
||||
ContextMenuItemRefresh,
|
||||
} from './ContextMenu'
|
||||
import { Popover } from '@headlessui/react'
|
||||
import { CustomIcon } from './CustomIcon'
|
||||
import { reportRejection } from 'lib/trap'
|
||||
import { useModelingContext } from 'hooks/useModelingContext'
|
||||
import {
|
||||
useViewControlMenuItems,
|
||||
ViewControlContextMenu,
|
||||
} from './ViewControlMenu'
|
||||
import { AxisNames } from 'lib/constants'
|
||||
|
||||
const CANVAS_SIZE = 80
|
||||
const FRUSTUM_SIZE = 0.5
|
||||
@ -40,64 +38,14 @@ enum AxisColors {
|
||||
Z = '#6689ef',
|
||||
Gray = '#c6c7c2',
|
||||
}
|
||||
enum AxisNames {
|
||||
X = 'x',
|
||||
Y = 'y',
|
||||
Z = 'z',
|
||||
NEG_X = '-x',
|
||||
NEG_Y = '-y',
|
||||
NEG_Z = '-z',
|
||||
}
|
||||
const axisNamesSemantic: Record<AxisNames, string> = {
|
||||
[AxisNames.X]: 'Right',
|
||||
[AxisNames.Y]: 'Back',
|
||||
[AxisNames.Z]: 'Top',
|
||||
[AxisNames.NEG_X]: 'Left',
|
||||
[AxisNames.NEG_Y]: 'Front',
|
||||
[AxisNames.NEG_Z]: 'Bottom',
|
||||
}
|
||||
|
||||
export default function Gizmo() {
|
||||
const menuItems = useViewControlMenuItems()
|
||||
const wrapperRef = useRef<HTMLDivElement | null>(null)
|
||||
const canvasRef = useRef<HTMLCanvasElement | null>(null)
|
||||
const raycasterIntersect = useRef<Intersection<Object3D> | null>(null)
|
||||
const cameraPassiveUpdateTimer = useRef(0)
|
||||
const raycasterPassiveUpdateTimer = useRef(0)
|
||||
const { send: modelingSend } = useModelingContext()
|
||||
const menuItems = useMemo(
|
||||
() => [
|
||||
...Object.entries(axisNamesSemantic).map(([axisName, axisSemantic]) => (
|
||||
<ContextMenuItem
|
||||
key={axisName}
|
||||
onClick={() => {
|
||||
sceneInfra.camControls
|
||||
.updateCameraToAxis(axisName as AxisNames)
|
||||
.catch(reportRejection)
|
||||
}}
|
||||
>
|
||||
{axisSemantic} view
|
||||
</ContextMenuItem>
|
||||
)),
|
||||
<ContextMenuDivider />,
|
||||
<ContextMenuItem
|
||||
onClick={() => {
|
||||
sceneInfra.camControls.resetCameraPosition().catch(reportRejection)
|
||||
}}
|
||||
>
|
||||
Reset view
|
||||
</ContextMenuItem>,
|
||||
<ContextMenuItem
|
||||
onClick={() => {
|
||||
modelingSend({ type: 'Center camera on selection' })
|
||||
}}
|
||||
>
|
||||
Center view on selection
|
||||
</ContextMenuItem>,
|
||||
<ContextMenuDivider />,
|
||||
<ContextMenuItemRefresh />,
|
||||
],
|
||||
[axisNamesSemantic]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!canvasRef.current) return
|
||||
@ -161,7 +109,7 @@ export default function Gizmo() {
|
||||
className="grid place-content-center rounded-full overflow-hidden border border-solid border-primary/50 pointer-events-auto bg-chalkboard-10/70 dark:bg-chalkboard-100/80 backdrop-blur-sm"
|
||||
>
|
||||
<canvas ref={canvasRef} />
|
||||
<ContextMenu menuTargetElement={wrapperRef} items={menuItems} />
|
||||
<ViewControlContextMenu menuTargetElement={wrapperRef} />
|
||||
</div>
|
||||
<GizmoDropdown items={menuItems} />
|
||||
</div>
|
||||
|
@ -20,6 +20,7 @@ import { IndexLoaderData } from 'lib/types'
|
||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||
import { err, reportRejection } from 'lib/trap'
|
||||
import { getArtifactOfTypes } from 'lang/std/artifactGraph'
|
||||
import { ViewControlContextMenu } from './ViewControlMenu'
|
||||
|
||||
enum StreamState {
|
||||
Playing = 'playing',
|
||||
@ -30,6 +31,7 @@ enum StreamState {
|
||||
|
||||
export const Stream = () => {
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const videoWrapperRef = useRef<HTMLDivElement>(null)
|
||||
const videoRef = useRef<HTMLVideoElement>(null)
|
||||
const { settings } = useSettingsAuthContext()
|
||||
const { state, send } = useModelingContext()
|
||||
@ -258,7 +260,7 @@ export const Stream = () => {
|
||||
setIsLoading(false)
|
||||
}, [mediaStream])
|
||||
|
||||
const handleMouseUp: MouseEventHandler<HTMLDivElement> = (e) => {
|
||||
const handleClick: MouseEventHandler<HTMLDivElement> = (e) => {
|
||||
// If we've got no stream or connection, don't do anything
|
||||
if (!isNetworkOkay) return
|
||||
if (!videoRef.current) return
|
||||
@ -320,10 +322,11 @@ export const Stream = () => {
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={videoWrapperRef}
|
||||
className="absolute inset-0 z-0"
|
||||
id="stream"
|
||||
data-testid="stream"
|
||||
onClick={handleMouseUp}
|
||||
onClick={handleClick}
|
||||
onDoubleClick={enterSketchModeIfSelectingSketch}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
onContextMenuCapture={(e) => e.preventDefault()}
|
||||
@ -384,6 +387,14 @@ export const Stream = () => {
|
||||
</Loading>
|
||||
</div>
|
||||
)}
|
||||
<ViewControlContextMenu
|
||||
event="mouseup"
|
||||
guard={(e) =>
|
||||
sceneInfra.camControls.wasDragging === false &&
|
||||
btnName(e).right === true
|
||||
}
|
||||
menuTargetElement={videoWrapperRef}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
66
src/components/ViewControlMenu.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import { reportRejection } from 'lib/trap'
|
||||
import {
|
||||
ContextMenu,
|
||||
ContextMenuDivider,
|
||||
ContextMenuItem,
|
||||
ContextMenuItemRefresh,
|
||||
ContextMenuProps,
|
||||
} from './ContextMenu'
|
||||
import { AxisNames, VIEW_NAMES_SEMANTIC } from 'lib/constants'
|
||||
import { useModelingContext } from 'hooks/useModelingContext'
|
||||
import { useMemo } from 'react'
|
||||
import { sceneInfra } from 'lib/singletons'
|
||||
|
||||
export function useViewControlMenuItems() {
|
||||
const { send: modelingSend } = useModelingContext()
|
||||
const menuItems = useMemo(
|
||||
() => [
|
||||
...Object.entries(VIEW_NAMES_SEMANTIC).map(([axisName, axisSemantic]) => (
|
||||
<ContextMenuItem
|
||||
key={axisName}
|
||||
onClick={() => {
|
||||
sceneInfra.camControls
|
||||
.updateCameraToAxis(axisName as AxisNames)
|
||||
.catch(reportRejection)
|
||||
}}
|
||||
>
|
||||
{axisSemantic} view
|
||||
</ContextMenuItem>
|
||||
)),
|
||||
<ContextMenuDivider />,
|
||||
<ContextMenuItem
|
||||
onClick={() => {
|
||||
sceneInfra.camControls.resetCameraPosition().catch(reportRejection)
|
||||
}}
|
||||
>
|
||||
Reset view
|
||||
</ContextMenuItem>,
|
||||
<ContextMenuItem
|
||||
onClick={() => {
|
||||
modelingSend({ type: 'Center camera on selection' })
|
||||
}}
|
||||
>
|
||||
Center view on selection
|
||||
</ContextMenuItem>,
|
||||
<ContextMenuDivider />,
|
||||
<ContextMenuItemRefresh />,
|
||||
],
|
||||
[VIEW_NAMES_SEMANTIC]
|
||||
)
|
||||
return menuItems
|
||||
}
|
||||
|
||||
export function ViewControlContextMenu({
|
||||
menuTargetElement: wrapperRef,
|
||||
...props
|
||||
}: ContextMenuProps) {
|
||||
const menuItems = useViewControlMenuItems()
|
||||
return (
|
||||
<ContextMenu
|
||||
data-testid="view-controls-menu"
|
||||
menuTargetElement={wrapperRef}
|
||||
items={menuItems}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
327
src/editor/plugins/lsp/kcl/colors.ts
Normal file
@ -0,0 +1,327 @@
|
||||
import {
|
||||
EditorView,
|
||||
WidgetType,
|
||||
ViewUpdate,
|
||||
ViewPlugin,
|
||||
DecorationSet,
|
||||
Decoration,
|
||||
} from '@codemirror/view'
|
||||
import { Range, Extension, Text } from '@codemirror/state'
|
||||
import { NodeProp, Tree } from '@lezer/common'
|
||||
import { language, syntaxTree } from '@codemirror/language'
|
||||
|
||||
interface PickerState {
|
||||
from: number
|
||||
to: number
|
||||
alpha: string
|
||||
colorType: ColorType
|
||||
}
|
||||
|
||||
export interface WidgetOptions extends PickerState {
|
||||
color: string
|
||||
}
|
||||
|
||||
export type ColorData = Omit<WidgetOptions, 'from' | 'to'>
|
||||
|
||||
const pickerState = new WeakMap<HTMLInputElement, PickerState>()
|
||||
|
||||
export enum ColorType {
|
||||
hex = 'HEX',
|
||||
}
|
||||
|
||||
const hexRegex = /(^|\b)(#[0-9a-f]{3,9})(\b|$)/i
|
||||
|
||||
function discoverColorsInKCL(
|
||||
syntaxTree: Tree,
|
||||
from: number,
|
||||
to: number,
|
||||
typeName: string,
|
||||
doc: Text,
|
||||
language?: string
|
||||
): WidgetOptions | Array<WidgetOptions> | null {
|
||||
switch (typeName) {
|
||||
case 'Program':
|
||||
case 'VariableDeclaration':
|
||||
case 'CallExpression':
|
||||
case 'ObjectExpression':
|
||||
case 'ObjectProperty':
|
||||
case 'ArgumentList':
|
||||
case 'PipeExpression': {
|
||||
let innerTree = syntaxTree.resolveInner(from, 0).tree
|
||||
|
||||
if (!innerTree) {
|
||||
innerTree = syntaxTree.resolveInner(from, 1).tree
|
||||
if (!innerTree) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const overlayTree = innerTree.prop(NodeProp.mounted)?.tree
|
||||
|
||||
if (overlayTree?.type.name !== 'Styles') {
|
||||
return null
|
||||
}
|
||||
|
||||
const ret: Array<WidgetOptions> = []
|
||||
overlayTree.iterate({
|
||||
from: 0,
|
||||
to: overlayTree.length,
|
||||
enter: ({ type, from: overlayFrom, to: overlayTo }) => {
|
||||
const maybeWidgetOptions = discoverColorsInKCL(
|
||||
syntaxTree,
|
||||
// We add one because the tree doesn't include the
|
||||
// quotation mark from the style tag
|
||||
from + 1 + overlayFrom,
|
||||
from + 1 + overlayTo,
|
||||
type.name,
|
||||
doc,
|
||||
language
|
||||
)
|
||||
|
||||
if (maybeWidgetOptions) {
|
||||
if (Array.isArray(maybeWidgetOptions)) {
|
||||
console.error('Unexpected nested overlays')
|
||||
ret.push(...maybeWidgetOptions)
|
||||
} else {
|
||||
ret.push(maybeWidgetOptions)
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
case 'String': {
|
||||
const result = parseColorLiteral(doc.sliceString(from, to))
|
||||
if (!result) {
|
||||
return null
|
||||
}
|
||||
return {
|
||||
...result,
|
||||
from,
|
||||
to,
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function parseColorLiteral(colorLiteral: string): ColorData | null {
|
||||
const literal = colorLiteral.replace(/"/g, '')
|
||||
const match = hexRegex.exec(literal)
|
||||
if (!match) {
|
||||
return null
|
||||
}
|
||||
const [color, alpha] = toFullHex(literal)
|
||||
|
||||
return {
|
||||
colorType: ColorType.hex,
|
||||
color,
|
||||
alpha,
|
||||
}
|
||||
}
|
||||
|
||||
function colorPickersDecorations(
|
||||
view: EditorView,
|
||||
discoverColors: typeof discoverColorsInKCL
|
||||
) {
|
||||
const widgets: Array<Range<Decoration>> = []
|
||||
|
||||
const st = syntaxTree(view.state)
|
||||
|
||||
for (const range of view.visibleRanges) {
|
||||
st.iterate({
|
||||
from: range.from,
|
||||
to: range.to,
|
||||
enter: ({ type, from, to }) => {
|
||||
const maybeWidgetOptions = discoverColors(
|
||||
st,
|
||||
from,
|
||||
to,
|
||||
type.name,
|
||||
view.state.doc,
|
||||
view.state.facet(language)?.name
|
||||
)
|
||||
|
||||
if (!maybeWidgetOptions) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!Array.isArray(maybeWidgetOptions)) {
|
||||
widgets.push(
|
||||
Decoration.widget({
|
||||
widget: new ColorPickerWidget(maybeWidgetOptions),
|
||||
side: 1,
|
||||
}).range(maybeWidgetOptions.from)
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
for (const wo of maybeWidgetOptions) {
|
||||
widgets.push(
|
||||
Decoration.widget({
|
||||
widget: new ColorPickerWidget(wo),
|
||||
side: 1,
|
||||
}).range(wo.from)
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return Decoration.set(widgets)
|
||||
}
|
||||
|
||||
function toFullHex(color: string): string[] {
|
||||
if (color.length === 4) {
|
||||
// 3-char hex
|
||||
return [
|
||||
`#${color[1].repeat(2)}${color[2].repeat(2)}${color[3].repeat(2)}`,
|
||||
'',
|
||||
]
|
||||
}
|
||||
|
||||
if (color.length === 5) {
|
||||
// 4-char hex (alpha)
|
||||
return [
|
||||
`#${color[1].repeat(2)}${color[2].repeat(2)}${color[3].repeat(2)}`,
|
||||
color[4].repeat(2),
|
||||
]
|
||||
}
|
||||
|
||||
if (color.length === 9) {
|
||||
// 8-char hex (alpha)
|
||||
return [`#${color.slice(1, -2)}`, color.slice(-2)]
|
||||
}
|
||||
|
||||
return [color, '']
|
||||
}
|
||||
|
||||
export const wrapperClassName = 'cm-css-color-picker-wrapper'
|
||||
|
||||
class ColorPickerWidget extends WidgetType {
|
||||
private readonly state: PickerState
|
||||
private readonly color: string
|
||||
|
||||
constructor({ color, ...state }: WidgetOptions) {
|
||||
super()
|
||||
this.state = state
|
||||
this.color = color
|
||||
}
|
||||
|
||||
eq(other: ColorPickerWidget) {
|
||||
return (
|
||||
other.state.colorType === this.state.colorType &&
|
||||
other.color === this.color &&
|
||||
other.state.from === this.state.from &&
|
||||
other.state.to === this.state.to &&
|
||||
other.state.alpha === this.state.alpha
|
||||
)
|
||||
}
|
||||
|
||||
toDOM() {
|
||||
const picker = document.createElement('input')
|
||||
pickerState.set(picker, this.state)
|
||||
picker.type = 'color'
|
||||
picker.value = this.color
|
||||
|
||||
const wrapper = document.createElement('span')
|
||||
wrapper.appendChild(picker)
|
||||
wrapper.className = wrapperClassName
|
||||
|
||||
return wrapper
|
||||
}
|
||||
|
||||
ignoreEvent() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export const colorPickerTheme = EditorView.baseTheme({
|
||||
[`.${wrapperClassName}`]: {
|
||||
display: 'inline-block',
|
||||
outline: '1px solid #eee',
|
||||
marginRight: '0.6ch',
|
||||
height: '1em',
|
||||
width: '1em',
|
||||
transform: 'translateY(1px)',
|
||||
},
|
||||
[`.${wrapperClassName} input[type="color"]`]: {
|
||||
cursor: 'pointer',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
padding: 0,
|
||||
border: 'none',
|
||||
'&::-webkit-color-swatch-wrapper': {
|
||||
padding: 0,
|
||||
},
|
||||
'&::-webkit-color-swatch': {
|
||||
border: 'none',
|
||||
},
|
||||
'&::-moz-color-swatch': {
|
||||
border: 'none',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
interface IFactoryOptions {
|
||||
discoverColors: typeof discoverColorsInKCL
|
||||
}
|
||||
|
||||
export const makeColorPicker = (options: IFactoryOptions) =>
|
||||
ViewPlugin.fromClass(
|
||||
class ColorPickerViewPlugin {
|
||||
decorations: DecorationSet
|
||||
|
||||
constructor(view: EditorView) {
|
||||
this.decorations = colorPickersDecorations(view, options.discoverColors)
|
||||
}
|
||||
|
||||
update(update: ViewUpdate) {
|
||||
if (update.docChanged || update.viewportChanged) {
|
||||
this.decorations = colorPickersDecorations(
|
||||
update.view,
|
||||
options.discoverColors
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
decorations: (v) => v.decorations,
|
||||
eventHandlers: {
|
||||
change: (e, view) => {
|
||||
const target = e.target as HTMLInputElement
|
||||
if (
|
||||
target.nodeName !== 'INPUT' ||
|
||||
!target.parentElement ||
|
||||
!target.parentElement.classList.contains(wrapperClassName)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
const data = pickerState.get(target)!
|
||||
|
||||
let converted = '"' + target.value + data.alpha + '"'
|
||||
|
||||
view.dispatch({
|
||||
changes: {
|
||||
from: data.from,
|
||||
to: data.to,
|
||||
insert: converted,
|
||||
},
|
||||
})
|
||||
|
||||
return true
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export const colorPicker: Extension = [
|
||||
makeColorPicker({ discoverColors: discoverColorsInKCL }),
|
||||
colorPickerTheme,
|
||||
]
|
@ -17,6 +17,7 @@ import { kclPlugin } from '.'
|
||||
import type * as LSP from 'vscode-languageserver-protocol'
|
||||
// @ts-ignore: No types available
|
||||
import { parser } from './kcl.grammar'
|
||||
import { colorPicker } from './colors'
|
||||
|
||||
export interface LanguageOptions {
|
||||
workspaceFolders: LSP.WorkspaceFolder[]
|
||||
@ -54,14 +55,14 @@ export const KclLanguage = LRLanguage.define({
|
||||
})
|
||||
|
||||
export function kcl(options: LanguageOptions) {
|
||||
return new LanguageSupport(
|
||||
KclLanguage,
|
||||
return new LanguageSupport(KclLanguage, [
|
||||
colorPicker,
|
||||
kclPlugin({
|
||||
documentUri: options.documentUri,
|
||||
workspaceFolders: options.workspaceFolders,
|
||||
allowHTMLContent: true,
|
||||
client: options.client,
|
||||
processLspNotification: options.processLspNotification,
|
||||
})
|
||||
)
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
@ -311,8 +311,6 @@ export class KclManager {
|
||||
// Do not send send scene commands if the program was interrupted, go to clean up
|
||||
if (!isInterrupted) {
|
||||
this.addDiagnostics(await lintAst({ ast: ast }))
|
||||
|
||||
sceneInfra.modelingSend({ type: 'code edit during sketch' })
|
||||
setSelectionFilterToDefault(execState.memory, this.engineCommandManager)
|
||||
|
||||
if (args.zoomToFit) {
|
||||
@ -358,7 +356,13 @@ export class KclManager {
|
||||
this.lastSuccessfulProgramMemory = execState.memory
|
||||
}
|
||||
this.ast = { ...ast }
|
||||
// updateArtifactGraph relies on updated executeState/programMemory
|
||||
await this.engineCommandManager.updateArtifactGraph(this.ast)
|
||||
this._executeCallback()
|
||||
if (!isInterrupted) {
|
||||
sceneInfra.modelingSend({ type: 'code edit during sketch' })
|
||||
}
|
||||
|
||||
this.engineCommandManager.addCommandLog({
|
||||
type: 'execution-done',
|
||||
data: null,
|
||||
|
@ -66,9 +66,7 @@ export async function executeAst({
|
||||
? enginelessExecutor(ast, programMemoryOverride)
|
||||
: _executor(ast, engineCommandManager))
|
||||
|
||||
await engineCommandManager.waitForAllCommands(
|
||||
programMemoryOverride !== undefined
|
||||
)
|
||||
await engineCommandManager.waitForAllCommands()
|
||||
|
||||
return {
|
||||
logs: [],
|
||||
|
@ -247,7 +247,7 @@ extrude003 = extrude(-15, sketch003)`
|
||||
selectedSegmentSnippet,
|
||||
expectedExtrudeSnippet
|
||||
)
|
||||
})
|
||||
}, 5_000)
|
||||
})
|
||||
|
||||
const runModifyAstCloneWithEdgeTreatmentAndTag = async (
|
||||
@ -477,7 +477,7 @@ extrude001 = extrude(-15, sketch001)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
extrude001 = extrude(-15, sketch001)
|
||||
|> chamfer({ length: 5, tags: [seg01] }, %)`
|
||||
|> chamfer({ length = 5, tags = [seg01] }, %)`
|
||||
const segmentSnippets = ['line([-20, 0], %)']
|
||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||
|> startProfileAt([-10, 10], %)
|
||||
@ -487,8 +487,8 @@ extrude001 = extrude(-15, sketch001)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
extrude001 = extrude(-15, sketch001)
|
||||
|> chamfer({ length: 5, tags: [seg01] }, %)
|
||||
|> ${edgeTreatmentType}({ ${parameterName}: 3, tags: [seg02] }, %)`
|
||||
|> chamfer({ length = 5, tags = [seg01] }, %)
|
||||
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg02] }, %)`
|
||||
|
||||
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||
code,
|
||||
|
@ -871,15 +871,3 @@ export function codeRefFromRange(range: SourceRange, ast: Program): CodeRef {
|
||||
pathToNode: getNodePathFromSourceRange(ast, range),
|
||||
}
|
||||
}
|
||||
|
||||
export function isSolid2D(artifact: Artifact): artifact is solid2D {
|
||||
return (artifact as solid2D).pathId !== undefined
|
||||
}
|
||||
|
||||
export function isSegment(artifact: Artifact): artifact is SegmentArtifact {
|
||||
return (artifact as SegmentArtifact).pathId !== undefined
|
||||
}
|
||||
|
||||
export function isSweep(artifact: Artifact): artifact is SweepArtifact {
|
||||
return (artifact as SweepArtifact).pathId !== undefined
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { defaultSourceRange, SourceRange } from 'lang/wasm'
|
||||
import { defaultSourceRange, Program, SourceRange } from 'lang/wasm'
|
||||
import { VITE_KC_API_WS_MODELING_URL, VITE_KC_DEV_TOKEN } from 'env'
|
||||
import { Models } from '@kittycad/lib'
|
||||
import { exportSave } from 'lib/exportSave'
|
||||
@ -2099,30 +2099,23 @@ export class EngineCommandManager extends EventTarget {
|
||||
* When an execution takes place we want to wait until we've got replies for all of the commands
|
||||
* When this is done when we build the artifact map synchronously.
|
||||
*/
|
||||
async waitForAllCommands(useFakeExecutor = false) {
|
||||
await Promise.all(Object.values(this.pendingCommands).map((a) => a.promise))
|
||||
setTimeout(() => {
|
||||
// the ast is wrong without this one tick timeout.
|
||||
// an example is `Solids should be select and deletable` e2e test will fail
|
||||
// because the out of date ast messes with selections
|
||||
// TODO: race condition
|
||||
if (!this?.kclManager) return
|
||||
this.artifactGraph = createArtifactGraph({
|
||||
orderedCommands: this.orderedCommands,
|
||||
responseMap: this.responseMap,
|
||||
ast: this.kclManager.ast,
|
||||
})
|
||||
if (useFakeExecutor) {
|
||||
// mock executions don't produce an artifactGraph, so this will always be empty
|
||||
// skipping the below logic to wait for the next real execution
|
||||
return
|
||||
}
|
||||
if (this.artifactGraph.size) {
|
||||
this.deferredArtifactEmptied(null)
|
||||
} else {
|
||||
this.deferredArtifactPopulated(null)
|
||||
}
|
||||
waitForAllCommands() {
|
||||
return Promise.all(
|
||||
Object.values(this.pendingCommands).map((a) => a.promise)
|
||||
)
|
||||
}
|
||||
updateArtifactGraph(ast: Program) {
|
||||
this.artifactGraph = createArtifactGraph({
|
||||
orderedCommands: this.orderedCommands,
|
||||
responseMap: this.responseMap,
|
||||
ast,
|
||||
})
|
||||
// TODO check if these still need to be deferred once e2e tests are working again.
|
||||
if (this.artifactGraph.size) {
|
||||
this.deferredArtifactEmptied(null)
|
||||
} else {
|
||||
this.deferredArtifactPopulated(null)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,7 +10,7 @@ const noModifiersPressed = (e: MouseEvent) =>
|
||||
!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey
|
||||
|
||||
export type CameraSystem =
|
||||
| 'KittyCAD'
|
||||
| 'Zoo'
|
||||
| 'OnShape'
|
||||
| 'Trackpad Friendly'
|
||||
| 'Solidworks'
|
||||
@ -19,7 +19,7 @@ export type CameraSystem =
|
||||
| 'AutoCAD'
|
||||
|
||||
export const cameraSystems: CameraSystem[] = [
|
||||
'KittyCAD',
|
||||
'Zoo',
|
||||
'OnShape',
|
||||
'Trackpad Friendly',
|
||||
'Solidworks',
|
||||
@ -34,9 +34,8 @@ export function mouseControlsToCameraSystem(
|
||||
switch (mouseControl) {
|
||||
// TODO: understand why the values come back without underscores and fix the root cause
|
||||
// @ts-ignore: TS2678
|
||||
case 'kittycad':
|
||||
case 'kitty_cad':
|
||||
return 'KittyCAD'
|
||||
case 'zoo':
|
||||
return 'Zoo'
|
||||
// TODO: understand why the values come back without underscores and fix the root cause
|
||||
// @ts-ignore: TS2678
|
||||
case 'onshape':
|
||||
@ -86,7 +85,7 @@ export const btnName = (e: MouseEvent) => ({
|
||||
})
|
||||
|
||||
export const cameraMouseDragGuards: Record<CameraSystem, MouseGuard> = {
|
||||
KittyCAD: {
|
||||
Zoo: {
|
||||
pan: {
|
||||
description: 'Shift + Right click drag or middle click drag',
|
||||
callback: (e) =>
|
||||
|
@ -3,7 +3,6 @@ import { engineCommandManager } from 'lib/singletons'
|
||||
import { uuidv4 } from 'lib/utils'
|
||||
import { CommandBarContext } from 'machines/commandBarMachine'
|
||||
import { Selections } from 'lib/selections'
|
||||
import { isSolid2D, isSegment, isSweep } from 'lang/std/artifactGraph'
|
||||
|
||||
export const disableDryRunWithRetry = async (numberOfRetries = 3) => {
|
||||
for (let tries = 0; tries < numberOfRetries; tries++) {
|
||||
@ -64,7 +63,7 @@ export const revolveAxisValidator = async ({
|
||||
return 'Unable to revolve, sketch not found'
|
||||
}
|
||||
|
||||
if (!(isSolid2D(artifact) || isSegment(artifact) || isSweep(artifact))) {
|
||||
if (!('pathId' in artifact)) {
|
||||
return 'Unable to revolve, sketch has no path'
|
||||
}
|
||||
|
||||
|
@ -118,3 +118,21 @@ export const KCL_AXIS_Y = 'Y'
|
||||
export const KCL_AXIS_NEG_X = '-X'
|
||||
export const KCL_AXIS_NEG_Y = '-Y'
|
||||
export const KCL_DEFAULT_AXIS = 'X'
|
||||
|
||||
export enum AxisNames {
|
||||
X = 'x',
|
||||
Y = 'y',
|
||||
Z = 'z',
|
||||
NEG_X = '-x',
|
||||
NEG_Y = '-y',
|
||||
NEG_Z = '-z',
|
||||
}
|
||||
/** Semantic names of views from AxisNames */
|
||||
export const VIEW_NAMES_SEMANTIC = {
|
||||
[AxisNames.X]: 'Right',
|
||||
[AxisNames.Y]: 'Back',
|
||||
[AxisNames.Z]: 'Top',
|
||||
[AxisNames.NEG_X]: 'Left',
|
||||
[AxisNames.NEG_Y]: 'Front',
|
||||
[AxisNames.NEG_Z]: 'Bottom',
|
||||
} as const
|
||||
|
@ -283,7 +283,7 @@ export function createSettings() {
|
||||
* The controls for how to navigate the 3D view
|
||||
*/
|
||||
mouseControls: new Setting<CameraSystem>({
|
||||
defaultValue: 'KittyCAD',
|
||||
defaultValue: 'Zoo',
|
||||
description: 'The controls for how to navigate the 3D view',
|
||||
validate: (v) => cameraSystems.includes(v as CameraSystem),
|
||||
hideOnLevel: 'project',
|
||||
|
35
src/wasm-lib/Cargo.lock
generated
@ -1674,10 +1674,11 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.72"
|
||||
version = "0.3.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
|
||||
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@ -4235,9 +4236,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.95"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
|
||||
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
@ -4246,13 +4247,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.95"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
|
||||
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.87",
|
||||
@ -4261,22 +4261,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.44"
|
||||
version = "0.4.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65471f79c1022ffa5291d33520cbbb53b7687b01c2f8e83b57d102eed7ed479d"
|
||||
checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.95"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
|
||||
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@ -4284,9 +4285,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.95"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
|
||||
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -4297,9 +4298,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.95"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
||||
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-lib"
|
||||
@ -4361,9 +4362,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.72"
|
||||
version = "0.3.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
|
||||
checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
@ -20,8 +20,8 @@ serde_json = "1.0.128"
|
||||
tokio = { version = "1.41.1", features = ["sync"] }
|
||||
toml = "0.8.19"
|
||||
uuid = { version = "1.11.0", features = ["v4", "js", "serde"] }
|
||||
wasm-bindgen = "0.2.91"
|
||||
wasm-bindgen-futures = "0.4.44"
|
||||
wasm-bindgen = "0.2.99"
|
||||
wasm-bindgen-futures = "0.4.49"
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1"
|
||||
@ -43,7 +43,7 @@ wasm-bindgen-futures = { version = "0.4.44", features = ["futures-core-03-stream
|
||||
wasm-streams = "0.4.1"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys]
|
||||
version = "0.3.72"
|
||||
version = "0.3.76"
|
||||
features = [
|
||||
"console",
|
||||
"HtmlTextAreaElement",
|
||||
|
@ -82,9 +82,9 @@ tokio = { version = "1.41.1", features = ["sync", "time"] }
|
||||
tower-lsp = { version = "0.20.0", default-features = false, features = [
|
||||
"runtime-agnostic",
|
||||
] }
|
||||
wasm-bindgen = "0.2.91"
|
||||
wasm-bindgen-futures = "0.4.44"
|
||||
web-sys = { version = "0.3.72", features = ["console"] }
|
||||
wasm-bindgen = "0.2.99"
|
||||
wasm-bindgen-futures = "0.4.49"
|
||||
web-sys = { version = "0.3.76", features = ["console"] }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
approx = "0.5"
|
||||
|
@ -597,6 +597,8 @@ fn clean_function_name(name: &str) -> String {
|
||||
fn_name = fn_name.replace("seg_", "segment_");
|
||||
} else if fn_name.starts_with("log_") {
|
||||
fn_name = fn_name.replace("log_", "log");
|
||||
} else if fn_name.ends_with("tan_2") {
|
||||
fn_name = fn_name.replace("tan_2", "tan2");
|
||||
}
|
||||
|
||||
fn_name
|
||||
|
@ -13,6 +13,8 @@ use tower_lsp::lsp_types::{
|
||||
MarkupKind, ParameterInformation, ParameterLabel, SignatureHelp, SignatureInformation,
|
||||
};
|
||||
|
||||
use crate::execution::Sketch;
|
||||
|
||||
use crate::std::Primitive;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, ts_rs::TS)]
|
||||
@ -232,6 +234,11 @@ pub trait StdLibFn: std::fmt::Debug + Send + Sync {
|
||||
}
|
||||
|
||||
fn to_autocomplete_snippet(&self) -> Result<String> {
|
||||
if self.name() == "loft" {
|
||||
return Ok("loft([${0:sketch000}, ${1:sketch001}])${}".to_string());
|
||||
} else if self.name() == "hole" {
|
||||
return Ok("hole(${0:holeSketch}, ${1:%})${}".to_string());
|
||||
}
|
||||
let mut args = Vec::new();
|
||||
let mut index = 0;
|
||||
for arg in self.args(true).iter() {
|
||||
@ -451,6 +458,16 @@ fn get_autocomplete_snippet_from_schema(
|
||||
) -> Result<Option<(usize, String)>> {
|
||||
match schema {
|
||||
schemars::schema::Schema::Object(o) => {
|
||||
// Check if the schema is the same as a Sketch.
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
// We set this so we can recurse them later.
|
||||
settings.inline_subschemas = true;
|
||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||
let sketch_schema = generator.root_schema_for::<Sketch>().schema;
|
||||
if sketch_schema.object == o.object {
|
||||
return Ok(Some((index, format!("${{{}:sketch{}}}", index, "000"))));
|
||||
}
|
||||
|
||||
if let Some(serde_json::Value::Bool(nullable)) = o.extensions.get("nullable") {
|
||||
if *nullable {
|
||||
return Ok(None);
|
||||
@ -967,6 +984,32 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_autocomplete_snippet_loft() {
|
||||
let loft_fn: Box<dyn StdLibFn> = Box::new(crate::std::loft::Loft);
|
||||
let snippet = loft_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"loft([${0:sketch000}, ${1:sketch001}])${}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_autocomplete_snippet_sweep() {
|
||||
let sweep_fn: Box<dyn StdLibFn> = Box::new(crate::std::sweep::Sweep);
|
||||
let snippet = sweep_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(
|
||||
snippet,
|
||||
r#"sweep({
|
||||
path: ${0:sketch000},
|
||||
}, ${1:%})${}"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_autocomplete_snippet_hole() {
|
||||
let hole_fn: Box<dyn StdLibFn> = Box::new(crate::std::sketch::Hole);
|
||||
let snippet = hole_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"hole(${0:holeSketch}, ${1:%})${}"#);
|
||||
}
|
||||
|
||||
// We want to test the snippets we compile at lsp start.
|
||||
#[test]
|
||||
fn get_all_stdlib_autocomplete_snippets() {
|
||||
|
@ -1895,11 +1895,19 @@ impl ExecutorContext {
|
||||
};
|
||||
|
||||
if cache_result.clear_scene && !self.is_mock() {
|
||||
// Pop the execution state, since we are starting fresh.
|
||||
let mut id_generator = exec_state.id_generator.clone();
|
||||
// We do not pop the ids, since we want to keep the same id generator.
|
||||
// This is for the front end to keep track of the ids.
|
||||
id_generator.next_id = 0;
|
||||
*exec_state = ExecState {
|
||||
id_generator,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// We don't do this in mock mode since there is no engine connection
|
||||
// anyways and from the TS side we override memory and don't want to clear it.
|
||||
self.reset_scene(exec_state, Default::default()).await?;
|
||||
// Pop the execution state, since we are starting fresh.
|
||||
*exec_state = Default::default();
|
||||
}
|
||||
|
||||
// TODO: Use the top-level file's path.
|
||||
@ -3497,12 +3505,7 @@ shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#;
|
||||
})
|
||||
.await;
|
||||
|
||||
assert!(result.is_some());
|
||||
|
||||
let result = result.unwrap();
|
||||
|
||||
assert_eq!(result.program, program_new.ast);
|
||||
assert!(result.clear_scene);
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
// Changing the units with the exact same file should bust the cache.
|
||||
|
@ -3,11 +3,10 @@ use sha2::{Digest as DigestTrait, Sha256};
|
||||
use super::types::{DefaultParamVal, ItemVisibility, LabelledExpression, VariableKind};
|
||||
use crate::parsing::ast::types::{
|
||||
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryPart, BodyItem, CallExpression, CallExpressionKw,
|
||||
CommentStyle, ElseIf, Expr, ExpressionStatement, FnArgType, FunctionExpression, Identifier, IfExpression,
|
||||
ImportItem, ImportSelector, ImportStatement, Literal, LiteralIdentifier, MemberExpression, MemberObject,
|
||||
NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression, ObjectProperty, Parameter, PipeExpression,
|
||||
PipeSubstitution, Program, ReturnStatement, TagDeclarator, UnaryExpression, VariableDeclaration,
|
||||
VariableDeclarator,
|
||||
ElseIf, Expr, ExpressionStatement, FnArgType, FunctionExpression, Identifier, IfExpression, ImportItem,
|
||||
ImportSelector, ImportStatement, KclNone, Literal, LiteralIdentifier, MemberExpression, MemberObject,
|
||||
ObjectExpression, ObjectProperty, Parameter, PipeExpression, PipeSubstitution, Program, ReturnStatement,
|
||||
TagDeclarator, UnaryExpression, VariableDeclaration, VariableDeclarator,
|
||||
};
|
||||
|
||||
/// Position-independent digest of the AST node.
|
||||
@ -82,7 +81,6 @@ impl Program {
|
||||
if let Some(shebang) = &slf.shebang {
|
||||
hasher.update(&shebang.inner.content);
|
||||
}
|
||||
hasher.update(slf.non_code_meta.compute_digest());
|
||||
});
|
||||
}
|
||||
|
||||
@ -203,6 +201,12 @@ impl Parameter {
|
||||
});
|
||||
}
|
||||
|
||||
impl KclNone {
|
||||
compute_digest!(|slf, hasher| {
|
||||
hasher.update(b"KclNone");
|
||||
});
|
||||
}
|
||||
|
||||
impl FunctionExpression {
|
||||
compute_digest!(|slf, hasher| {
|
||||
hasher.update(slf.params.len().to_ne_bytes());
|
||||
@ -228,53 +232,6 @@ impl ReturnStatement {
|
||||
});
|
||||
}
|
||||
|
||||
impl CommentStyle {
|
||||
fn digestable_id(&self) -> [u8; 2] {
|
||||
match &self {
|
||||
CommentStyle::Line => *b"//",
|
||||
CommentStyle::Block => *b"/*",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NonCodeNode {
|
||||
compute_digest!(|slf, hasher| {
|
||||
match &slf.value {
|
||||
NonCodeValue::InlineComment { value, style } => {
|
||||
hasher.update(value);
|
||||
hasher.update(style.digestable_id());
|
||||
}
|
||||
NonCodeValue::BlockComment { value, style } => {
|
||||
hasher.update(value);
|
||||
hasher.update(style.digestable_id());
|
||||
}
|
||||
NonCodeValue::NewLineBlockComment { value, style } => {
|
||||
hasher.update(value);
|
||||
hasher.update(style.digestable_id());
|
||||
}
|
||||
NonCodeValue::NewLine => {
|
||||
hasher.update(b"\r\n");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
impl NonCodeMeta {
|
||||
compute_digest!(|slf, hasher| {
|
||||
let mut keys = slf.non_code_nodes.keys().copied().collect::<Vec<_>>();
|
||||
keys.sort();
|
||||
|
||||
for key in keys.into_iter() {
|
||||
hasher.update(key.to_ne_bytes());
|
||||
let nodes = slf.non_code_nodes.get_mut(&key).unwrap();
|
||||
hasher.update(nodes.len().to_ne_bytes());
|
||||
for node in nodes.iter_mut() {
|
||||
hasher.update(node.compute_digest());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
impl ExpressionStatement {
|
||||
compute_digest!(|slf, hasher| {
|
||||
hasher.update(slf.expression.compute_digest());
|
||||
@ -410,7 +367,6 @@ impl PipeExpression {
|
||||
for value in slf.body.iter_mut() {
|
||||
hasher.update(value.compute_digest());
|
||||
}
|
||||
hasher.update(slf.non_code_meta.compute_digest());
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::Node;
|
||||
use super::{super::digest::Digest, Node};
|
||||
use crate::{execution::KclValue, parsing::ast::types::ConstraintLevel};
|
||||
|
||||
const KCL_NONE_ID: &str = "KCL_NONE_ID";
|
||||
@ -19,11 +19,18 @@ pub struct KclNone {
|
||||
#[ts(skip)]
|
||||
#[schemars(skip)]
|
||||
__private: Private,
|
||||
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub digest: Option<Digest>,
|
||||
}
|
||||
|
||||
impl KclNone {
|
||||
pub fn new() -> Self {
|
||||
Self { __private: Private {} }
|
||||
Self {
|
||||
__private: Private {},
|
||||
digest: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2256,12 +2256,16 @@ fn arguments(i: &mut TokenSlice) -> PResult<Vec<Expr>> {
|
||||
}
|
||||
|
||||
fn labeled_argument(i: &mut TokenSlice) -> PResult<LabeledArg> {
|
||||
separated_pair(identifier, (one_of(TokenType::Colon), opt(whitespace)), expression)
|
||||
.map(|(label, arg)| LabeledArg {
|
||||
label: label.inner,
|
||||
arg,
|
||||
})
|
||||
.parse_next(i)
|
||||
separated_pair(
|
||||
terminated(identifier, opt(whitespace)),
|
||||
terminated(one_of((TokenType::Operator, "=")), opt(whitespace)),
|
||||
expression,
|
||||
)
|
||||
.map(|(label, arg)| LabeledArg {
|
||||
label: label.inner,
|
||||
arg,
|
||||
})
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
/// Arguments are passed into a function,
|
||||
@ -4057,7 +4061,7 @@ let myBox = box([0,0], -3, -16, -10)
|
||||
|
||||
#[test]
|
||||
fn kw_fn() {
|
||||
for input in ["val = foo(x, y: z)", "val = foo(y: z)"] {
|
||||
for input in ["val = foo(x, y = z)", "val = foo(y = z)"] {
|
||||
let module_id = ModuleId::default();
|
||||
let tokens = crate::parsing::token::lex(input, module_id).unwrap();
|
||||
super::program.parse(tokens.as_slice()).unwrap();
|
||||
@ -4497,8 +4501,8 @@ my14 = 4 ^ 2 - 3 ^ 2 * 2
|
||||
r#"x = 3
|
||||
obj = { x, y: 4}"#
|
||||
);
|
||||
snapshot_test!(kw_function_unnamed_first, r#"val = foo(x, y: z)"#);
|
||||
snapshot_test!(kw_function_all_named, r#"val = foo(x: a, y: b)"#);
|
||||
snapshot_test!(kw_function_unnamed_first, r#"val = foo(x, y = z)"#);
|
||||
snapshot_test!(kw_function_all_named, r#"val = foo(x = a, y = b)"#);
|
||||
snapshot_test!(kw_function_decl_all_labeled, r#"fn foo(x, y) { return 1 }"#);
|
||||
snapshot_test!(kw_function_decl_first_unlabeled, r#"fn foo(@x, y) { return 1 }"#);
|
||||
snapshot_test!(kw_function_decl_with_default_no_type, r#"fn foo(x? = 2) { return 1 }"#);
|
||||
|
@ -1,12 +1,13 @@
|
||||
---
|
||||
source: kcl/src/parsing/parser.rs
|
||||
expression: actual
|
||||
snapshot_kind: text
|
||||
---
|
||||
{
|
||||
"body": [
|
||||
{
|
||||
"declaration": {
|
||||
"end": 21,
|
||||
"end": 23,
|
||||
"id": {
|
||||
"end": 3,
|
||||
"name": "val",
|
||||
@ -22,9 +23,9 @@ expression: actual
|
||||
"name": "x"
|
||||
},
|
||||
"arg": {
|
||||
"end": 14,
|
||||
"end": 15,
|
||||
"name": "a",
|
||||
"start": 13,
|
||||
"start": 14,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
@ -36,9 +37,9 @@ expression: actual
|
||||
"name": "y"
|
||||
},
|
||||
"arg": {
|
||||
"end": 20,
|
||||
"end": 22,
|
||||
"name": "b",
|
||||
"start": 19,
|
||||
"start": 21,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
@ -50,7 +51,7 @@ expression: actual
|
||||
"start": 6,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 21,
|
||||
"end": 23,
|
||||
"start": 6,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
@ -59,13 +60,13 @@ expression: actual
|
||||
"start": 0,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 21,
|
||||
"end": 23,
|
||||
"kind": "const",
|
||||
"start": 0,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
}
|
||||
],
|
||||
"end": 21,
|
||||
"end": 23,
|
||||
"start": 0
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
---
|
||||
source: kcl/src/parsing/parser.rs
|
||||
expression: actual
|
||||
snapshot_kind: text
|
||||
---
|
||||
{
|
||||
"body": [
|
||||
{
|
||||
"declaration": {
|
||||
"end": 18,
|
||||
"end": 19,
|
||||
"id": {
|
||||
"end": 3,
|
||||
"name": "val",
|
||||
@ -22,9 +23,9 @@ expression: actual
|
||||
"name": "y"
|
||||
},
|
||||
"arg": {
|
||||
"end": 17,
|
||||
"end": 18,
|
||||
"name": "z",
|
||||
"start": 16,
|
||||
"start": 17,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
@ -36,7 +37,7 @@ expression: actual
|
||||
"start": 6,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 18,
|
||||
"end": 19,
|
||||
"start": 6,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
@ -51,13 +52,13 @@ expression: actual
|
||||
"start": 0,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 18,
|
||||
"end": 19,
|
||||
"kind": "const",
|
||||
"start": 0,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
}
|
||||
],
|
||||
"end": 18,
|
||||
"end": 19,
|
||||
"start": 0
|
||||
}
|
||||
|
@ -380,9 +380,9 @@ impl From<UnitLength> for kittycad_modeling_cmds::units::UnitLength {
|
||||
#[display(style = "snake_case")]
|
||||
pub enum MouseControlType {
|
||||
#[default]
|
||||
#[display("kittycad")]
|
||||
#[serde(rename = "kittycad", alias = "KittyCAD")]
|
||||
KittyCad,
|
||||
#[display("zoo")]
|
||||
#[serde(rename = "zoo", alias = "Zoo", alias = "KittyCAD")]
|
||||
Zoo,
|
||||
#[display("onshape")]
|
||||
#[serde(rename = "onshape", alias = "OnShape")]
|
||||
OnShape,
|
||||
|
@ -65,7 +65,7 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
///
|
||||
/// This will work on any solid, including extruded solids, revolved solids, and shelled solids.
|
||||
/// ```no_run
|
||||
/// /// Add color to an extruded solid.
|
||||
/// // Add color to an extruded solid.
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> lineTo([10, 0], %)
|
||||
@ -78,7 +78,7 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// /// Add color to a revolved solid.
|
||||
/// // Add color to a revolved solid.
|
||||
/// sketch001 = startSketchOn('XY')
|
||||
/// |> circle({ center = [15, 0], radius = 5 }, %)
|
||||
/// |> revolve({ angle = 360, axis = 'y' }, %)
|
||||
@ -90,7 +90,7 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// /// Add color to different solids.
|
||||
/// // Add color to different solids.
|
||||
/// fn cube(center) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> startProfileAt([center[0] - 10, center[1] - 10], %)
|
||||
@ -110,8 +110,8 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// /// You can set the appearance before or after you shell it will yield the same result.
|
||||
/// /// This example shows setting the appearance _after_ the shell.
|
||||
/// // You can set the appearance before or after you shell it will yield the same result.
|
||||
/// // This example shows setting the appearance _after_ the shell.
|
||||
/// firstSketch = startSketchOn('XY')
|
||||
/// |> startProfileAt([-12, 12], %)
|
||||
/// |> line([24, 0], %)
|
||||
@ -132,8 +132,8 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// /// You can set the appearance before or after you shell it will yield the same result.
|
||||
/// /// This example shows setting the appearance _before_ the shell.
|
||||
/// // You can set the appearance before or after you shell it will yield the same result.
|
||||
/// // This example shows setting the appearance _before_ the shell.
|
||||
/// firstSketch = startSketchOn('XY')
|
||||
/// |> startProfileAt([-12, 12], %)
|
||||
/// |> line([24, 0], %)
|
||||
@ -154,8 +154,8 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// /// Setting the appearance of a 3D pattern can be done _before_ or _after_ the pattern.
|
||||
/// /// This example shows _before_ the pattern.
|
||||
/// // Setting the appearance of a 3D pattern can be done _before_ or _after_ the pattern.
|
||||
/// // This example shows _before_ the pattern.
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([0, 2], %)
|
||||
@ -177,8 +177,8 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// /// Setting the appearance of a 3D pattern can be done _before_ or _after_ the pattern.
|
||||
/// /// This example shows _after_ the pattern.
|
||||
/// // Setting the appearance of a 3D pattern can be done _before_ or _after_ the pattern.
|
||||
/// // This example shows _after_ the pattern.
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([0, 2], %)
|
||||
@ -200,7 +200,7 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// /// Color the result of a 2D pattern that was extruded.
|
||||
/// // Color the result of a 2D pattern that was extruded.
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([.5, 25], %)
|
||||
/// |> line([0, 5], %)
|
||||
@ -221,6 +221,46 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// roughness = 90
|
||||
/// }, %)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Color the result of a sweep.
|
||||
///
|
||||
/// // Create a path for the sweep.
|
||||
/// sweepPath = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0.05, 0.05], %)
|
||||
/// |> line([0, 7], %)
|
||||
/// |> tangentialArc({
|
||||
/// offset: 90,
|
||||
/// radius: 5
|
||||
/// }, %)
|
||||
/// |> line([-3, 0], %)
|
||||
/// |> tangentialArc({
|
||||
/// offset: -90,
|
||||
/// radius: 5
|
||||
/// }, %)
|
||||
/// |> line([0, 7], %)
|
||||
///
|
||||
/// pipeHole = startSketchOn('XY')
|
||||
/// |> circle({
|
||||
/// center = [0, 0],
|
||||
/// radius = 1.5,
|
||||
/// }, %)
|
||||
///
|
||||
/// sweepSketch = startSketchOn('XY')
|
||||
/// |> circle({
|
||||
/// center = [0, 0],
|
||||
/// radius = 2,
|
||||
/// }, %)
|
||||
/// |> hole(pipeHole, %)
|
||||
/// |> sweep({
|
||||
/// path: sweepPath,
|
||||
/// }, %)
|
||||
/// |> appearance({
|
||||
/// color: "#ff0000",
|
||||
/// metalness: 50,
|
||||
/// roughness: 50
|
||||
/// }, %)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "appearance",
|
||||
}]
|
||||
|
@ -1096,6 +1096,20 @@ impl<'a> FromKclValue<'a> for super::fillet::FilletData {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromKclValue<'a> for super::sweep::SweepData {
|
||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||
let obj = arg.as_object()?;
|
||||
let_field_of!(obj, path);
|
||||
let_field_of!(obj, sectional?);
|
||||
let_field_of!(obj, tolerance?);
|
||||
Some(Self {
|
||||
path,
|
||||
sectional,
|
||||
tolerance,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromKclValue<'a> for super::appearance::AppearanceData {
|
||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||
let obj = arg.as_object()?;
|
||||
|
@ -30,7 +30,7 @@ pub async fn map(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
||||
/// Given a list like `[a, b, c]`, and a function like `f`, returns
|
||||
/// `[f(a), f(b), f(c)]`
|
||||
/// ```no_run
|
||||
/// const r = 10 // radius
|
||||
/// r = 10 // radius
|
||||
/// fn drawCircle(id) {
|
||||
/// return startSketchOn("XY")
|
||||
/// |> circle({ center: [id * 2 * r, 0], radius: r}, %)
|
||||
@ -39,15 +39,15 @@ pub async fn map(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
||||
/// // Call `drawCircle`, passing in each element of the array.
|
||||
/// // The outputs from each `drawCircle` form a new array,
|
||||
/// // which is the return value from `map`.
|
||||
/// const circles = map(
|
||||
/// circles = map(
|
||||
/// [1..3],
|
||||
/// drawCircle
|
||||
/// )
|
||||
/// ```
|
||||
/// ```no_run
|
||||
/// const r = 10 // radius
|
||||
/// r = 10 // radius
|
||||
/// // Call `map`, using an anonymous function instead of a named one.
|
||||
/// const circles = map(
|
||||
/// circles = map(
|
||||
/// [1..3],
|
||||
/// fn(id) {
|
||||
/// return startSketchOn("XY")
|
||||
@ -106,17 +106,17 @@ pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// using the previous value and the element.
|
||||
/// ```no_run
|
||||
/// // This function adds two numbers.
|
||||
/// fn add = (a, b) => { return a + b }
|
||||
/// fn add(a, b) { return a + b }
|
||||
///
|
||||
/// // This function adds an array of numbers.
|
||||
/// // It uses the `reduce` function, to call the `add` function on every
|
||||
/// // element of the `arr` parameter. The starting value is 0.
|
||||
/// fn sum = (arr) => { return reduce(arr, 0, add) }
|
||||
/// fn sum(arr) { return reduce(arr, 0, add) }
|
||||
///
|
||||
/// /*
|
||||
/// The above is basically like this pseudo-code:
|
||||
/// fn sum(arr):
|
||||
/// let sumSoFar = 0
|
||||
/// sumSoFar = 0
|
||||
/// for i in arr:
|
||||
/// sumSoFar = add(sumSoFar, i)
|
||||
/// return sumSoFar
|
||||
@ -139,7 +139,7 @@ pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// ```
|
||||
/// ```no_run
|
||||
/// // Declare a function that sketches a decagon.
|
||||
/// fn decagon = (radius) => {
|
||||
/// fn decagon(radius) {
|
||||
/// // Each side of the decagon is turned this many degrees from the previous angle.
|
||||
/// stepAngle = (1/10) * tau()
|
||||
///
|
||||
@ -151,8 +151,8 @@ pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// // which takes a partially-sketched decagon and adds one more edge to it.
|
||||
/// fullDecagon = reduce([1..10], startOfDecagonSketch, fn(i, partialDecagon) {
|
||||
/// // Draw one edge of the decagon.
|
||||
/// let x = cos(stepAngle * i) * radius
|
||||
/// let y = sin(stepAngle * i) * radius
|
||||
/// x = cos(stepAngle * i) * radius
|
||||
/// y = sin(stepAngle * i) * radius
|
||||
/// return lineTo([x, y], partialDecagon)
|
||||
/// })
|
||||
///
|
||||
@ -163,14 +163,14 @@ pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// /*
|
||||
/// The `decagon` above is basically like this pseudo-code:
|
||||
/// fn decagon(radius):
|
||||
/// let stepAngle = (1/10) * tau()
|
||||
/// let startOfDecagonSketch = startSketchAt([(cos(0)*radius), (sin(0) * radius)])
|
||||
/// stepAngle = (1/10) * tau()
|
||||
/// startOfDecagonSketch = startSketchAt([(cos(0)*radius), (sin(0) * radius)])
|
||||
///
|
||||
/// // Here's the reduce part.
|
||||
/// let partialDecagon = startOfDecagonSketch
|
||||
/// partialDecagon = startOfDecagonSketch
|
||||
/// for i in [1..10]:
|
||||
/// let x = cos(stepAngle * i) * radius
|
||||
/// let y = sin(stepAngle * i) * radius
|
||||
/// x = cos(stepAngle * i) * radius
|
||||
/// y = sin(stepAngle * i) * radius
|
||||
/// partialDecagon = lineTo([x, y], partialDecagon)
|
||||
/// fullDecagon = partialDecagon // it's now full
|
||||
/// return fullDecagon
|
||||
@ -224,8 +224,8 @@ async fn call_reduce_closure<'a>(
|
||||
/// Returns a new array with the element appended.
|
||||
///
|
||||
/// ```no_run
|
||||
/// let arr = [1, 2, 3]
|
||||
/// let new_arr = push(arr, 4)
|
||||
/// arr = [1, 2, 3]
|
||||
/// new_arr = push(arr, 4)
|
||||
/// assertEqual(new_arr[3], 4, 0.00001, "4 was added to the end of the array")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
|
@ -31,7 +31,7 @@ pub async fn assert(_exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// is false.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const myVar = true
|
||||
/// myVar = true
|
||||
/// assert(myVar, "should always be true")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
@ -70,8 +70,8 @@ pub async fn assert_gt(_exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
||||
/// otherwise raise an error.
|
||||
///
|
||||
/// ```no_run
|
||||
/// let n = 1.0285
|
||||
/// let o = 1.0286
|
||||
/// n = 1.0285
|
||||
/// o = 1.0286
|
||||
/// assertEqual(n, o, 0.01, "n is within the given tolerance for o")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
|
@ -43,19 +43,19 @@ pub async fn chamfer(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Chamfer a mounting plate.
|
||||
/// const width = 20
|
||||
/// const length = 10
|
||||
/// const thickness = 1
|
||||
/// const chamferLength = 2
|
||||
/// width = 20
|
||||
/// length = 10
|
||||
/// thickness = 1
|
||||
/// chamferLength = 2
|
||||
///
|
||||
/// const mountingPlateSketch = startSketchOn("XY")
|
||||
/// mountingPlateSketch = startSketchOn("XY")
|
||||
/// |> startProfileAt([-width/2, -length/2], %)
|
||||
/// |> lineTo([width/2, -length/2], %, $edge1)
|
||||
/// |> lineTo([width/2, length/2], %, $edge2)
|
||||
/// |> lineTo([-width/2, length/2], %, $edge3)
|
||||
/// |> close(%, $edge4)
|
||||
///
|
||||
/// const mountingPlate = extrude(thickness, mountingPlateSketch)
|
||||
/// mountingPlate = extrude(thickness, mountingPlateSketch)
|
||||
/// |> chamfer({
|
||||
/// length = chamferLength,
|
||||
/// tags = [
|
||||
@ -69,8 +69,8 @@ pub async fn chamfer(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Sketch on the face of a chamfer.
|
||||
/// fn cube = (pos, scale) => {
|
||||
/// const sg = startSketchOn('XY')
|
||||
/// fn cube(pos, scale) {
|
||||
/// sg = startSketchOn('XY')
|
||||
/// |> startProfileAt(pos, %)
|
||||
/// |> line([0, scale], %)
|
||||
/// |> line([scale, 0], %)
|
||||
@ -79,7 +79,7 @@ pub async fn chamfer(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// return sg
|
||||
/// }
|
||||
///
|
||||
/// const part001 = cube([0,0], 20)
|
||||
/// part001 = cube([0,0], 20)
|
||||
/// |> close(%, $line1)
|
||||
/// |> extrude(20, %)
|
||||
/// |> chamfer({
|
||||
@ -87,7 +87,7 @@ pub async fn chamfer(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// tags = [getOppositeEdge(line1)]
|
||||
/// }, %, $chamfer1) // We tag the chamfer to reference it later.
|
||||
///
|
||||
/// const sketch001 = startSketchOn(part001, chamfer1)
|
||||
/// sketch001 = startSketchOn(part001, chamfer1)
|
||||
/// |> startProfileAt([10, 10], %)
|
||||
/// |> line([2, 0], %)
|
||||
/// |> line([0, 2], %)
|
||||
|
@ -21,7 +21,7 @@ pub async fn int(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// DEPRECATED use floor(), ceil(), or round().
|
||||
///
|
||||
/// ```no_run
|
||||
/// let n = int(ceil(5/2))
|
||||
/// n = int(ceil(5/2))
|
||||
/// assertEqual(n, 3, 0.0001, "5/2 = 2.5, rounded up makes 3")
|
||||
/// // Draw n cylinders.
|
||||
/// startSketchOn('XZ')
|
||||
|
@ -33,7 +33,7 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// cut into an existing solid.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const example = startSketchOn('XZ')
|
||||
/// example = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> arc({
|
||||
@ -54,7 +54,7 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([-10, 0], %)
|
||||
/// |> arc({
|
||||
/// angleStart = 120,
|
||||
@ -72,7 +72,7 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> line([-5, -2], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "extrude"
|
||||
|
@ -68,19 +68,19 @@ pub async fn fillet(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// will smoothly blend the transition.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const width = 20
|
||||
/// const length = 10
|
||||
/// const thickness = 1
|
||||
/// const filletRadius = 2
|
||||
/// width = 20
|
||||
/// length = 10
|
||||
/// thickness = 1
|
||||
/// filletRadius = 2
|
||||
///
|
||||
/// const mountingPlateSketch = startSketchOn("XY")
|
||||
/// mountingPlateSketch = startSketchOn("XY")
|
||||
/// |> startProfileAt([-width/2, -length/2], %)
|
||||
/// |> lineTo([width/2, -length/2], %, $edge1)
|
||||
/// |> lineTo([width/2, length/2], %, $edge2)
|
||||
/// |> lineTo([-width/2, length/2], %, $edge3)
|
||||
/// |> close(%, $edge4)
|
||||
///
|
||||
/// const mountingPlate = extrude(thickness, mountingPlateSketch)
|
||||
/// mountingPlate = extrude(thickness, mountingPlateSketch)
|
||||
/// |> fillet({
|
||||
/// radius = filletRadius,
|
||||
/// tags = [
|
||||
@ -93,19 +93,19 @@ pub async fn fillet(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const width = 20
|
||||
/// const length = 10
|
||||
/// const thickness = 1
|
||||
/// const filletRadius = 1
|
||||
/// width = 20
|
||||
/// length = 10
|
||||
/// thickness = 1
|
||||
/// filletRadius = 1
|
||||
///
|
||||
/// const mountingPlateSketch = startSketchOn("XY")
|
||||
/// mountingPlateSketch = startSketchOn("XY")
|
||||
/// |> startProfileAt([-width/2, -length/2], %)
|
||||
/// |> lineTo([width/2, -length/2], %, $edge1)
|
||||
/// |> lineTo([width/2, length/2], %, $edge2)
|
||||
/// |> lineTo([-width/2, length/2], %, $edge3)
|
||||
/// |> close(%, $edge4)
|
||||
///
|
||||
/// const mountingPlate = extrude(thickness, mountingPlateSketch)
|
||||
/// mountingPlate = extrude(thickness, mountingPlateSketch)
|
||||
/// |> fillet({
|
||||
/// radius = filletRadius,
|
||||
/// tolerance = 0.000001,
|
||||
@ -195,7 +195,7 @@ pub async fn get_opposite_edge(exec_state: &mut ExecState, args: Args) -> Result
|
||||
/// Get the opposite edge to the edge given.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> angledLine({
|
||||
@ -213,7 +213,7 @@ pub async fn get_opposite_edge(exec_state: &mut ExecState, args: Args) -> Result
|
||||
/// }, %, $referenceEdge)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// |> fillet({
|
||||
/// radius = 3,
|
||||
/// tags = [getOppositeEdge(referenceEdge)],
|
||||
@ -268,7 +268,7 @@ pub async fn get_next_adjacent_edge(exec_state: &mut ExecState, args: Args) -> R
|
||||
/// Get the next adjacent edge to the edge given.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> angledLine({
|
||||
@ -286,7 +286,7 @@ pub async fn get_next_adjacent_edge(exec_state: &mut ExecState, args: Args) -> R
|
||||
/// }, %, $referenceEdge)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// |> fillet({
|
||||
/// radius = 3,
|
||||
/// tags = [getNextAdjacentEdge(referenceEdge)],
|
||||
@ -353,7 +353,7 @@ pub async fn get_previous_adjacent_edge(exec_state: &mut ExecState, args: Args)
|
||||
/// Get the previous adjacent edge to the edge given.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> angledLine({
|
||||
@ -371,7 +371,7 @@ pub async fn get_previous_adjacent_edge(exec_state: &mut ExecState, args: Args)
|
||||
/// }, %, $referenceEdge)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// |> fillet({
|
||||
/// radius = 3,
|
||||
/// tags = [getPreviousAdjacentEdge(referenceEdge)],
|
||||
|
@ -42,7 +42,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// Create a helix on a cylinder.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const part001 = startSketchOn('XY')
|
||||
/// part001 = startSketchOn('XY')
|
||||
/// |> circle({ center: [5, 5], radius: 10 }, %)
|
||||
/// |> extrude(10, %)
|
||||
/// |> helix({
|
||||
|
@ -148,23 +148,23 @@ pub async fn import(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// [KCL modules](/docs/kcl/modules).
|
||||
///
|
||||
/// ```no_run
|
||||
/// const model = import("tests/inputs/cube.obj")
|
||||
/// model = import("tests/inputs/cube.obj")
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const model = import("tests/inputs/cube.obj", {format: "obj", units: "m"})
|
||||
/// model = import("tests/inputs/cube.obj", {format: "obj", units: "m"})
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const model = import("tests/inputs/cube.gltf")
|
||||
/// model = import("tests/inputs/cube.gltf")
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const model = import("tests/inputs/cube.sldprt")
|
||||
/// model = import("tests/inputs/cube.sldprt")
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const model = import("tests/inputs/cube.step")
|
||||
/// model = import("tests/inputs/cube.step")
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
|
@ -63,7 +63,7 @@ pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Loft a square and a triangle.
|
||||
/// const squareSketch = startSketchOn('XY')
|
||||
/// squareSketch = startSketchOn('XY')
|
||||
/// |> startProfileAt([-100, 200], %)
|
||||
/// |> line([200, 0], %)
|
||||
/// |> line([0, -200], %)
|
||||
@ -71,7 +71,7 @@ pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// |> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const triangleSketch = startSketchOn(offsetPlane('XY', 75))
|
||||
/// triangleSketch = startSketchOn(offsetPlane('XY', 75))
|
||||
/// |> startProfileAt([0, 125], %)
|
||||
/// |> line([-15, -30], %)
|
||||
/// |> line([30, 0], %)
|
||||
@ -83,7 +83,7 @@ pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Loft a square, a circle, and another circle.
|
||||
/// const squareSketch = startSketchOn('XY')
|
||||
/// squareSketch = startSketchOn('XY')
|
||||
/// |> startProfileAt([-100, 200], %)
|
||||
/// |> line([200, 0], %)
|
||||
/// |> line([0, -200], %)
|
||||
@ -91,10 +91,10 @@ pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// |> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const circleSketch0 = startSketchOn(offsetPlane('XY', 75))
|
||||
/// circleSketch0 = startSketchOn(offsetPlane('XY', 75))
|
||||
/// |> circle({ center = [0, 100], radius = 50 }, %)
|
||||
///
|
||||
/// const circleSketch1 = startSketchOn(offsetPlane('XY', 150))
|
||||
/// circleSketch1 = startSketchOn(offsetPlane('XY', 150))
|
||||
/// |> circle({ center = [0, 100], radius = 20 }, %)
|
||||
///
|
||||
/// loft([squareSketch, circleSketch0, circleSketch1])
|
||||
@ -102,7 +102,7 @@ pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Loft a square, a circle, and another circle with options.
|
||||
/// const squareSketch = startSketchOn('XY')
|
||||
/// squareSketch = startSketchOn('XY')
|
||||
/// |> startProfileAt([-100, 200], %)
|
||||
/// |> line([200, 0], %)
|
||||
/// |> line([0, -200], %)
|
||||
@ -110,10 +110,10 @@ pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// |> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const circleSketch0 = startSketchOn(offsetPlane('XY', 75))
|
||||
/// circleSketch0 = startSketchOn(offsetPlane('XY', 75))
|
||||
/// |> circle({ center = [0, 100], radius = 50 }, %)
|
||||
///
|
||||
/// const circleSketch1 = startSketchOn(offsetPlane('XY', 150))
|
||||
/// circleSketch1 = startSketchOn(offsetPlane('XY', 150))
|
||||
/// |> circle({ center = [0, 100], radius = 20 }, %)
|
||||
///
|
||||
/// loft([squareSketch, circleSketch0, circleSketch1], {
|
||||
|
@ -9,6 +9,8 @@ use crate::{
|
||||
std::Args,
|
||||
};
|
||||
|
||||
use super::args::FromArgs;
|
||||
|
||||
/// Compute the remainder after dividing `num` by `div`.
|
||||
/// If `num` is negative, the result will be too.
|
||||
pub async fn rem(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
@ -23,9 +25,9 @@ pub async fn rem(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// If `num` is negative, the result will be too.
|
||||
///
|
||||
/// ```no_run
|
||||
/// assertEqual(rem(7, divisor: 4), 3, 0.01, "remainder is 3")
|
||||
/// assertEqual(rem(-7, divisor: 4), -3, 0.01, "remainder is 3")
|
||||
/// assertEqual(rem(7, divisor: -4), 3, 0.01, "remainder is 3")
|
||||
/// assertEqual(rem( 7, divisor = 4), 3, 0.01, "remainder is 3" )
|
||||
/// assertEqual(rem(-7, divisor = 4), -3, 0.01, "remainder is -3")
|
||||
/// assertEqual(rem( 7, divisor = -4), 3, 0.01, "remainder is 3" )
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "rem",
|
||||
@ -48,7 +50,7 @@ pub async fn cos(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// Compute the cosine of a number (in radians).
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 30,
|
||||
@ -57,7 +59,7 @@ pub async fn cos(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "cos",
|
||||
@ -78,7 +80,7 @@ pub async fn sin(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// Compute the sine of a number (in radians).
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 50,
|
||||
@ -87,7 +89,7 @@ pub async fn sin(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "sin",
|
||||
@ -108,7 +110,7 @@ pub async fn tan(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// Compute the tangent of a number (in radians).
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 50,
|
||||
@ -117,7 +119,7 @@ pub async fn tan(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "tan",
|
||||
@ -137,12 +139,12 @@ pub async fn pi(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
||||
/// Return the value of `pi`. Archimedes’ constant (π).
|
||||
///
|
||||
/// ```no_run
|
||||
/// const circumference = 70
|
||||
/// circumference = 70
|
||||
///
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> circle({ center = [0, 0], radius = circumference/ (2 * pi()) }, %)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "pi",
|
||||
@ -163,7 +165,7 @@ pub async fn sqrt(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// Compute the square root of a number.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 50,
|
||||
@ -172,7 +174,7 @@ pub async fn sqrt(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "sqrt",
|
||||
@ -193,9 +195,9 @@ pub async fn abs(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// Compute the absolute value of a number.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const myAngle = -120
|
||||
/// myAngle = -120
|
||||
///
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([8, 0], %)
|
||||
/// |> angledLine({
|
||||
@ -209,7 +211,7 @@ pub async fn abs(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// }, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const baseExtrusion = extrude(5, sketch001)
|
||||
/// baseExtrusion = extrude(5, sketch001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "abs",
|
||||
@ -230,14 +232,14 @@ pub async fn round(_exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// Round a number to the nearest integer.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> lineTo([12, 10], %)
|
||||
/// |> line([round(7.02986), 0], %)
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const extrude001 = extrude(5, sketch001)
|
||||
/// extrude001 = extrude(5, sketch001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "round",
|
||||
@ -258,14 +260,14 @@ pub async fn floor(_exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// Compute the largest integer less than or equal to a number.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> lineTo([12, 10], %)
|
||||
/// |> line([floor(7.02986), 0], %)
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const extrude001 = extrude(5, sketch001)
|
||||
/// extrude001 = extrude(5, sketch001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "floor",
|
||||
@ -286,14 +288,14 @@ pub async fn ceil(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// Compute the smallest integer greater than or equal to a number.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> lineTo([12, 10], %)
|
||||
/// |> line([ceil(7.02986), 0], %)
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const extrude001 = extrude(5, sketch001)
|
||||
/// extrude001 = extrude(5, sketch001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "ceil",
|
||||
@ -314,7 +316,7 @@ pub async fn min(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// Compute the minimum of the given arguments.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 70,
|
||||
@ -323,7 +325,7 @@ pub async fn min(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// |> line([20, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "min",
|
||||
@ -351,7 +353,7 @@ pub async fn max(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// Compute the maximum of the given arguments.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 70,
|
||||
@ -360,7 +362,7 @@ pub async fn max(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// |> line([20, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "max",
|
||||
@ -402,7 +404,7 @@ pub async fn pow(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// Compute the number to a power.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 50,
|
||||
@ -411,7 +413,7 @@ pub async fn pow(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "pow",
|
||||
@ -432,7 +434,7 @@ pub async fn acos(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// Compute the arccosine of a number (in radians).
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = toDegrees(acos(0.5)),
|
||||
@ -442,7 +444,7 @@ pub async fn acos(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// |> lineTo([12, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const extrude001 = extrude(5, sketch001)
|
||||
/// extrude001 = extrude(5, sketch001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "acos",
|
||||
@ -463,7 +465,7 @@ pub async fn asin(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// Compute the arcsine of a number (in radians).
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = toDegrees(asin(0.5)),
|
||||
@ -472,7 +474,7 @@ pub async fn asin(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const extrude001 = extrude(5, sketch001)
|
||||
/// extrude001 = extrude(5, sketch001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "asin",
|
||||
@ -493,7 +495,7 @@ pub async fn atan(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// Compute the arctangent of a number (in radians).
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = toDegrees(atan(1.25)),
|
||||
@ -502,7 +504,7 @@ pub async fn atan(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const extrude001 = extrude(5, sketch001)
|
||||
/// extrude001 = extrude(5, sketch001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "atan",
|
||||
@ -512,6 +514,36 @@ fn inner_atan(num: f64) -> Result<f64, KclError> {
|
||||
Ok(num.atan())
|
||||
}
|
||||
|
||||
/// Compute the four quadrant arctangent of Y and X (in radians).
|
||||
pub async fn atan2(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (y, x) = FromArgs::from_args(&args, 0)?;
|
||||
let result = inner_atan2(y, x)?;
|
||||
|
||||
Ok(args.make_user_val_from_f64(result))
|
||||
}
|
||||
|
||||
/// Compute the four quadrant arctangent of Y and X (in radians).
|
||||
///
|
||||
/// ```no_run
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = toDegrees(atan2(1.25, 2)),
|
||||
/// length = 20,
|
||||
/// }, %)
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// extrude001 = extrude(5, sketch001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "atan2",
|
||||
tags = ["math"],
|
||||
}]
|
||||
fn inner_atan2(y: f64, x: f64) -> Result<f64, KclError> {
|
||||
Ok(y.atan2(x))
|
||||
}
|
||||
|
||||
/// Compute the logarithm of the number with respect to an arbitrary base.
|
||||
///
|
||||
/// The result might not be correctly rounded owing to implementation
|
||||
@ -544,14 +576,14 @@ pub async fn log(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// and `log10()` can produce more accurate results for base 10.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([log(100, 5), 0], %)
|
||||
/// |> line([5, 8], %)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "log",
|
||||
@ -572,14 +604,14 @@ pub async fn log2(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// Compute the base 2 logarithm of the number.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([log2(100), 0], %)
|
||||
/// |> line([5, 8], %)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "log2",
|
||||
@ -600,14 +632,14 @@ pub async fn log10(_exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// Compute the base 10 logarithm of the number.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([log10(100), 0], %)
|
||||
/// |> line([5, 8], %)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "log10",
|
||||
@ -628,14 +660,14 @@ pub async fn ln(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
||||
/// Compute the natural logarithm of the number.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([ln(100), 15], %)
|
||||
/// |> line([5, -6], %)
|
||||
/// |> line([-10, -10], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "ln",
|
||||
@ -655,7 +687,7 @@ pub async fn e(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclE
|
||||
/// Return the value of Euler’s number `e`.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 30,
|
||||
@ -664,7 +696,7 @@ pub async fn e(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclE
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "e",
|
||||
@ -684,7 +716,7 @@ pub async fn tau(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// Return the value of `tau`. The full circle constant (τ). Equal to 2π.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 50,
|
||||
@ -693,7 +725,7 @@ pub async fn tau(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "tau",
|
||||
@ -714,7 +746,7 @@ pub async fn to_radians(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// Converts a number from degrees to radians.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 50,
|
||||
@ -723,7 +755,7 @@ pub async fn to_radians(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "toRadians",
|
||||
@ -744,7 +776,7 @@ pub async fn to_degrees(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// Converts a number from radians to degrees.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 50,
|
||||
@ -753,7 +785,7 @@ pub async fn to_degrees(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "toDegrees",
|
||||
|
@ -40,7 +40,7 @@ pub async fn mirror_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Mirror an un-closed sketch across the Y axis.
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 10], %)
|
||||
/// |> line([15, 0], %)
|
||||
/// |> line([-7, -3], %)
|
||||
@ -52,38 +52,38 @@ pub async fn mirror_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
/// |> line([-19, -0], %)
|
||||
/// |> mirror2d({axis = 'Y'}, %)
|
||||
///
|
||||
/// const example = extrude(10, sketch001)
|
||||
/// example = extrude(10, sketch001)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Mirror a un-closed sketch across the Y axis.
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 8.5], %)
|
||||
/// |> line([20, -8.5], %)
|
||||
/// |> line([-20, -8.5], %)
|
||||
/// |> mirror2d({axis = 'Y'}, %)
|
||||
///
|
||||
/// const example = extrude(10, sketch001)
|
||||
/// example = extrude(10, sketch001)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Mirror a un-closed sketch across an edge.
|
||||
/// const helper001 = startSketchOn('XZ')
|
||||
/// helper001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([0, 10], %, $edge001)
|
||||
///
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 8.5], %)
|
||||
/// |> line([20, -8.5], %)
|
||||
/// |> line([-20, -8.5], %)
|
||||
/// |> mirror2d({axis = edge001}, %)
|
||||
///
|
||||
/// const example = extrude(10, sketch001)
|
||||
/// example = extrude(10, sketch001)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Mirror an un-closed sketch across a custom axis.
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 8.5], %)
|
||||
/// |> line([20, -8.5], %)
|
||||
/// |> line([-20, -8.5], %)
|
||||
@ -96,7 +96,7 @@ pub async fn mirror_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
/// }
|
||||
/// }, %)
|
||||
///
|
||||
/// const example = extrude(10, sketch001)
|
||||
/// example = extrude(10, sketch001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "mirror2d",
|
||||
|
@ -21,6 +21,7 @@ pub mod segment;
|
||||
pub mod shapes;
|
||||
pub mod shell;
|
||||
pub mod sketch;
|
||||
pub mod sweep;
|
||||
pub mod types;
|
||||
pub mod units;
|
||||
pub mod utils;
|
||||
@ -114,6 +115,7 @@ lazy_static! {
|
||||
Box::new(crate::std::shell::Shell),
|
||||
Box::new(crate::std::shell::Hollow),
|
||||
Box::new(crate::std::revolve::Revolve),
|
||||
Box::new(crate::std::sweep::Sweep),
|
||||
Box::new(crate::std::loft::Loft),
|
||||
Box::new(crate::std::planes::OffsetPlane),
|
||||
Box::new(crate::std::import::Import),
|
||||
@ -123,6 +125,7 @@ lazy_static! {
|
||||
Box::new(crate::std::math::Acos),
|
||||
Box::new(crate::std::math::Asin),
|
||||
Box::new(crate::std::math::Atan),
|
||||
Box::new(crate::std::math::Atan2),
|
||||
Box::new(crate::std::math::Pi),
|
||||
Box::new(crate::std::math::E),
|
||||
Box::new(crate::std::math::Tau),
|
||||
|
@ -146,12 +146,12 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Each instance will be shifted along the X axis.
|
||||
/// fn transform = (id) => {
|
||||
/// fn transform(id) {
|
||||
/// return { translate = [4 * id, 0, 0] }
|
||||
/// }
|
||||
///
|
||||
/// // Sketch 4 cylinders.
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> circle({ center = [0, 0], radius = 2 }, %)
|
||||
/// |> extrude(5, %)
|
||||
/// |> patternTransform(4, transform, %)
|
||||
@ -160,24 +160,24 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
|
||||
/// // Each instance will be shifted along the X axis,
|
||||
/// // with a gap between the original (at x = 0) and the first replica
|
||||
/// // (at x = 8). This is because `id` starts at 1.
|
||||
/// fn transform = (id) => {
|
||||
/// fn transform(id) {
|
||||
/// return { translate: [4 * (1+id), 0, 0] }
|
||||
/// }
|
||||
///
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> circle({ center = [0, 0], radius = 2 }, %)
|
||||
/// |> extrude(5, %)
|
||||
/// |> patternTransform(4, transform, %)
|
||||
/// ```
|
||||
/// ```no_run
|
||||
/// fn cube = (length, center) => {
|
||||
/// let l = length/2
|
||||
/// let x = center[0]
|
||||
/// let y = center[1]
|
||||
/// let p0 = [-l + x, -l + y]
|
||||
/// let p1 = [-l + x, l + y]
|
||||
/// let p2 = [ l + x, l + y]
|
||||
/// let p3 = [ l + x, -l + y]
|
||||
/// fn cube(length, center) {
|
||||
/// l = length/2
|
||||
/// x = center[0]
|
||||
/// y = center[1]
|
||||
/// p0 = [-l + x, -l + y]
|
||||
/// p1 = [-l + x, l + y]
|
||||
/// p2 = [ l + x, l + y]
|
||||
/// p3 = [ l + x, -l + y]
|
||||
///
|
||||
/// return startSketchAt(p0)
|
||||
/// |> lineTo(p1, %)
|
||||
@ -188,8 +188,8 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
|
||||
/// |> extrude(length, %)
|
||||
/// }
|
||||
///
|
||||
/// let width = 20
|
||||
/// fn transform = (i) => {
|
||||
/// width = 20
|
||||
/// fn transform(i) {
|
||||
/// return {
|
||||
/// // Move down each time.
|
||||
/// translate = [0, 0, -i * width],
|
||||
@ -203,20 +203,20 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let myCubes =
|
||||
/// myCubes =
|
||||
/// cube(width, [100,0])
|
||||
/// |> patternTransform(25, transform, %)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// fn cube = (length, center) => {
|
||||
/// let l = length/2
|
||||
/// let x = center[0]
|
||||
/// let y = center[1]
|
||||
/// let p0 = [-l + x, -l + y]
|
||||
/// let p1 = [-l + x, l + y]
|
||||
/// let p2 = [ l + x, l + y]
|
||||
/// let p3 = [ l + x, -l + y]
|
||||
/// fn cube(length, center) {
|
||||
/// l = length/2
|
||||
/// x = center[0]
|
||||
/// y = center[1]
|
||||
/// p0 = [-l + x, -l + y]
|
||||
/// p1 = [-l + x, l + y]
|
||||
/// p2 = [ l + x, l + y]
|
||||
/// p3 = [ l + x, -l + y]
|
||||
///
|
||||
/// return startSketchAt(p0)
|
||||
/// |> lineTo(p1, %)
|
||||
@ -227,8 +227,8 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
|
||||
/// |> extrude(length, %)
|
||||
/// }
|
||||
///
|
||||
/// let width = 20
|
||||
/// fn transform = (i) => {
|
||||
/// width = 20
|
||||
/// fn transform(i) {
|
||||
/// return {
|
||||
/// translate = [0, 0, -i * width],
|
||||
/// rotation = {
|
||||
@ -238,36 +238,36 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// let myCubes =
|
||||
/// myCubes =
|
||||
/// cube(width, [100,100])
|
||||
/// |> patternTransform(4, transform, %)
|
||||
/// ```
|
||||
/// ```no_run
|
||||
/// // Parameters
|
||||
/// const r = 50 // base radius
|
||||
/// const h = 10 // layer height
|
||||
/// const t = 0.005 // taper factor [0-1)
|
||||
/// r = 50 // base radius
|
||||
/// h = 10 // layer height
|
||||
/// t = 0.005 // taper factor [0-1)
|
||||
/// // Defines how to modify each layer of the vase.
|
||||
/// // Each replica is shifted up the Z axis, and has a smoothly-varying radius
|
||||
/// fn transform = (replicaId) => {
|
||||
/// let scale = r * abs(1 - (t * replicaId)) * (5 + cos(replicaId / 8))
|
||||
/// fn transform(replicaId) {
|
||||
/// scale = r * abs(1 - (t * replicaId)) * (5 + cos(replicaId / 8))
|
||||
/// return {
|
||||
/// translate = [0, 0, replicaId * 10],
|
||||
/// scale = [scale, scale, 0],
|
||||
/// }
|
||||
/// }
|
||||
/// // Each layer is just a pretty thin cylinder.
|
||||
/// fn layer = () => {
|
||||
/// fn layer() {
|
||||
/// return startSketchOn("XY") // or some other plane idk
|
||||
/// |> circle({ center = [0, 0], radius = 1 }, %, $tag1)
|
||||
/// |> extrude(h, %)
|
||||
/// }
|
||||
/// // The vase is 100 layers tall.
|
||||
/// // The 100 layers are replica of each other, with a slight transformation applied to each.
|
||||
/// let vase = layer() |> patternTransform(100, transform, %)
|
||||
/// vase = layer() |> patternTransform(100, transform, %)
|
||||
/// ```
|
||||
/// ```
|
||||
/// fn transform = (i) => {
|
||||
/// fn transform(i) {
|
||||
/// // Transform functions can return multiple transforms. They'll be applied in order.
|
||||
/// return [
|
||||
/// { translate: [30 * i, 0, 0] },
|
||||
@ -312,7 +312,7 @@ async fn inner_pattern_transform<'a>(
|
||||
/// Just like patternTransform, but works on 2D sketches not 3D solids.
|
||||
/// ```no_run
|
||||
/// // Each instance will be shifted along the X axis.
|
||||
/// fn transform = (id) => {
|
||||
/// fn transform(id) {
|
||||
/// return { translate: [4 * id, 0] }
|
||||
/// }
|
||||
///
|
||||
@ -689,7 +689,7 @@ pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result
|
||||
/// of distance between each repetition, some specified number of times.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> circle({ center = [0, 0], radius = 1 }, %)
|
||||
/// |> patternLinear2d({
|
||||
/// axis = [1, 0],
|
||||
@ -697,7 +697,7 @@ pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result
|
||||
/// distance = 4
|
||||
/// }, %)
|
||||
///
|
||||
/// const example = extrude(1, exampleSketch)
|
||||
/// example = extrude(1, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "patternLinear2d",
|
||||
@ -746,14 +746,14 @@ pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result
|
||||
/// of distance between each repetition, some specified number of times.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([0, 2], %)
|
||||
/// |> line([3, 1], %)
|
||||
/// |> line([0, -4], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(1, exampleSketch)
|
||||
/// example = extrude(1, exampleSketch)
|
||||
/// |> patternLinear3d({
|
||||
/// axis = [1, 0, 1],
|
||||
/// instances = 7,
|
||||
@ -900,7 +900,7 @@ pub async fn pattern_circular_2d(exec_state: &mut ExecState, args: Args) -> Resu
|
||||
/// solid with respect to the center of the circle is maintained.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([.5, 25], %)
|
||||
/// |> line([0, 5], %)
|
||||
/// |> line([-1, 0], %)
|
||||
@ -913,7 +913,7 @@ pub async fn pattern_circular_2d(exec_state: &mut ExecState, args: Args) -> Resu
|
||||
/// rotateDuplicates = true
|
||||
/// }, %)
|
||||
///
|
||||
/// const example = extrude(1, exampleSketch)
|
||||
/// example = extrude(1, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "patternCircular2d",
|
||||
@ -967,10 +967,10 @@ pub async fn pattern_circular_3d(exec_state: &mut ExecState, args: Args) -> Resu
|
||||
/// solid with respect to the center of the circle is maintained.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> circle({ center = [0, 0], radius = 1 }, %)
|
||||
///
|
||||
/// const example = extrude(-5, exampleSketch)
|
||||
/// example = extrude(-5, exampleSketch)
|
||||
/// |> patternCircular3d({
|
||||
/// axis = [1, -1, 0],
|
||||
/// center = [10, -20, 0],
|
||||
|
@ -65,7 +65,7 @@ pub async fn offset_plane(exec_state: &mut ExecState, args: Args) -> Result<KclV
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Loft a square and a circle on the `XY` plane using offset.
|
||||
/// const squareSketch = startSketchOn('XY')
|
||||
/// squareSketch = startSketchOn('XY')
|
||||
/// |> startProfileAt([-100, 200], %)
|
||||
/// |> line([200, 0], %)
|
||||
/// |> line([0, -200], %)
|
||||
@ -73,7 +73,7 @@ pub async fn offset_plane(exec_state: &mut ExecState, args: Args) -> Result<KclV
|
||||
/// |> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const circleSketch = startSketchOn(offsetPlane('XY', 150))
|
||||
/// circleSketch = startSketchOn(offsetPlane('XY', 150))
|
||||
/// |> circle({ center = [0, 100], radius = 50 }, %)
|
||||
///
|
||||
/// loft([squareSketch, circleSketch])
|
||||
@ -81,7 +81,7 @@ pub async fn offset_plane(exec_state: &mut ExecState, args: Args) -> Result<KclV
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Loft a square and a circle on the `XZ` plane using offset.
|
||||
/// const squareSketch = startSketchOn('XZ')
|
||||
/// squareSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([-100, 200], %)
|
||||
/// |> line([200, 0], %)
|
||||
/// |> line([0, -200], %)
|
||||
@ -89,7 +89,7 @@ pub async fn offset_plane(exec_state: &mut ExecState, args: Args) -> Result<KclV
|
||||
/// |> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const circleSketch = startSketchOn(offsetPlane('XZ', 150))
|
||||
/// circleSketch = startSketchOn(offsetPlane('XZ', 150))
|
||||
/// |> circle({ center = [0, 100], radius = 50 }, %)
|
||||
///
|
||||
/// loft([squareSketch, circleSketch])
|
||||
@ -97,7 +97,7 @@ pub async fn offset_plane(exec_state: &mut ExecState, args: Args) -> Result<KclV
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Loft a square and a circle on the `YZ` plane using offset.
|
||||
/// const squareSketch = startSketchOn('YZ')
|
||||
/// squareSketch = startSketchOn('YZ')
|
||||
/// |> startProfileAt([-100, 200], %)
|
||||
/// |> line([200, 0], %)
|
||||
/// |> line([0, -200], %)
|
||||
@ -105,7 +105,7 @@ pub async fn offset_plane(exec_state: &mut ExecState, args: Args) -> Result<KclV
|
||||
/// |> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const circleSketch = startSketchOn(offsetPlane('YZ', 150))
|
||||
/// circleSketch = startSketchOn(offsetPlane('YZ', 150))
|
||||
/// |> circle({ center = [0, 100], radius = 50 }, %)
|
||||
///
|
||||
/// loft([squareSketch, circleSketch])
|
||||
@ -113,7 +113,7 @@ pub async fn offset_plane(exec_state: &mut ExecState, args: Args) -> Result<KclV
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Loft a square and a circle on the `-XZ` plane using offset.
|
||||
/// const squareSketch = startSketchOn('-XZ')
|
||||
/// squareSketch = startSketchOn('-XZ')
|
||||
/// |> startProfileAt([-100, 200], %)
|
||||
/// |> line([200, 0], %)
|
||||
/// |> line([0, -200], %)
|
||||
@ -121,7 +121,7 @@ pub async fn offset_plane(exec_state: &mut ExecState, args: Args) -> Result<KclV
|
||||
/// |> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const circleSketch = startSketchOn(offsetPlane('-XZ', -150))
|
||||
/// circleSketch = startSketchOn(offsetPlane('-XZ', -150))
|
||||
/// |> circle({ center = [0, 100], radius = 50 }, %)
|
||||
///
|
||||
/// loft([squareSketch, circleSketch])
|
||||
|
@ -34,7 +34,7 @@ pub async fn polar(_exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// cartesian (x/y/z grid) coordinates.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line(polar({angle: 30, length: 5}), %, $thing)
|
||||
/// |> line([0, 5], %)
|
||||
@ -42,7 +42,7 @@ pub async fn polar(_exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> line([-20, 10], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "polar",
|
||||
|
@ -113,7 +113,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// Revolve occurs around a local sketch axis rather than a global axis.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const part001 = startSketchOn('XY')
|
||||
/// part001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([4, 12], %)
|
||||
/// |> line([2, 0], %)
|
||||
/// |> line([0, -6], %)
|
||||
@ -128,7 +128,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
///
|
||||
/// ```no_run
|
||||
/// // A donut shape.
|
||||
/// const sketch001 = startSketchOn('XY')
|
||||
/// sketch001 = startSketchOn('XY')
|
||||
/// |> circle({ center = [15, 0], radius = 5 }, %)
|
||||
/// |> revolve({
|
||||
/// angle = 360,
|
||||
@ -137,7 +137,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const part001 = startSketchOn('XY')
|
||||
/// part001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([4, 12], %)
|
||||
/// |> line([2, 0], %)
|
||||
/// |> line([0, -6], %)
|
||||
@ -151,7 +151,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const part001 = startSketchOn('XY')
|
||||
/// part001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([4, 12], %)
|
||||
/// |> line([2, 0], %)
|
||||
/// |> line([0, -6], %)
|
||||
@ -162,7 +162,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> line([-2, 0], %)
|
||||
/// |> close(%)
|
||||
/// |> revolve({axis = 'y', angle = 180}, %)
|
||||
/// const part002 = startSketchOn(part001, 'end')
|
||||
/// part002 = startSketchOn(part001, 'end')
|
||||
/// |> startProfileAt([4.5, -5], %)
|
||||
/// |> line([0, 5], %)
|
||||
/// |> line([5, 0], %)
|
||||
@ -172,7 +172,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const box = startSketchOn('XY')
|
||||
/// box = startSketchOn('XY')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([0, 20], %)
|
||||
/// |> line([20, 0], %)
|
||||
@ -180,7 +180,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> close(%)
|
||||
/// |> extrude(20, %)
|
||||
///
|
||||
/// const sketch001 = startSketchOn(box, "END")
|
||||
/// sketch001 = startSketchOn(box, "END")
|
||||
/// |> circle({ center = [10,10], radius = 4 }, %)
|
||||
/// |> revolve({
|
||||
/// angle = -90,
|
||||
@ -189,7 +189,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const box = startSketchOn('XY')
|
||||
/// box = startSketchOn('XY')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([0, 20], %)
|
||||
/// |> line([20, 0], %)
|
||||
@ -197,7 +197,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> close(%)
|
||||
/// |> extrude(20, %)
|
||||
///
|
||||
/// const sketch001 = startSketchOn(box, "END")
|
||||
/// sketch001 = startSketchOn(box, "END")
|
||||
/// |> circle({ center = [10,10], radius = 4 }, %)
|
||||
/// |> revolve({
|
||||
/// angle = 90,
|
||||
@ -206,7 +206,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const box = startSketchOn('XY')
|
||||
/// box = startSketchOn('XY')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([0, 20], %)
|
||||
/// |> line([20, 0], %)
|
||||
@ -214,7 +214,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> close(%)
|
||||
/// |> extrude(20, %)
|
||||
///
|
||||
/// const sketch001 = startSketchOn(box, "END")
|
||||
/// sketch001 = startSketchOn(box, "END")
|
||||
/// |> circle({ center = [10,10], radius = 4 }, %)
|
||||
/// |> revolve({
|
||||
/// angle = 90,
|
||||
@ -224,14 +224,14 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XY')
|
||||
/// sketch001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([10, 0], %)
|
||||
/// |> line([5, -5], %)
|
||||
/// |> line([5, 5], %)
|
||||
/// |> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const part001 = revolve({
|
||||
/// part001 = revolve({
|
||||
/// axis = {
|
||||
/// custom: {
|
||||
/// axis = [0.0, 1.0],
|
||||
|
@ -30,7 +30,7 @@ pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// |> close(%)
|
||||
/// |> extrude(5, %)
|
||||
///
|
||||
/// fn cylinder = (radius, tag) => {
|
||||
/// fn cylinder(radius, tag) {
|
||||
/// return startSketchAt([0, 0])
|
||||
/// |> circle({ radius = radius, center = segEnd(tag) }, %)
|
||||
/// |> extrude(radius, %)
|
||||
@ -67,7 +67,7 @@ pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
||||
/// Compute the ending point of the provided line segment along the 'x' axis.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([20, 0], %, $thing)
|
||||
/// |> line([0, 5], %)
|
||||
@ -75,7 +75,7 @@ pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
||||
/// |> line([-20, 10], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "segEndX",
|
||||
@ -103,7 +103,7 @@ pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
||||
/// Compute the ending point of the provided line segment along the 'y' axis.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([20, 0], %)
|
||||
/// |> line([0, 3], %, $thing)
|
||||
@ -112,7 +112,7 @@ pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "segEndY",
|
||||
@ -149,7 +149,7 @@ pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
||||
/// |> close(%)
|
||||
/// |> extrude(5, %)
|
||||
///
|
||||
/// fn cylinder = (radius, tag) => {
|
||||
/// fn cylinder(radius, tag) {
|
||||
/// return startSketchAt([0, 0])
|
||||
/// |> circle({ radius = radius, center = segStart(tag) }, %)
|
||||
/// |> extrude(radius, %)
|
||||
@ -186,7 +186,7 @@ pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// Compute the starting point of the provided line segment along the 'x' axis.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([20, 0], %, $thing)
|
||||
/// |> line([0, 5], %)
|
||||
@ -194,7 +194,7 @@ pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// |> line([-20, 10], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "segStartX",
|
||||
@ -222,7 +222,7 @@ pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// Compute the starting point of the provided line segment along the 'y' axis.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([20, 0], %)
|
||||
/// |> line([0, 3], %, $thing)
|
||||
@ -231,7 +231,7 @@ pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "segStartY",
|
||||
@ -259,7 +259,7 @@ pub async fn last_segment_x(_exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// sketch.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([5, 0], %)
|
||||
/// |> line([20, 5], %)
|
||||
@ -267,7 +267,7 @@ pub async fn last_segment_x(_exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// |> line([-15, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "lastSegX",
|
||||
@ -299,7 +299,7 @@ pub async fn last_segment_y(_exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// sketch.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([5, 0], %)
|
||||
/// |> line([20, 5], %)
|
||||
@ -307,7 +307,7 @@ pub async fn last_segment_y(_exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// |> line([-15, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "lastSegY",
|
||||
@ -337,7 +337,7 @@ pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<Kc
|
||||
/// Compute the length of the provided line segment.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 60,
|
||||
@ -353,7 +353,7 @@ pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<Kc
|
||||
/// }, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "segLen",
|
||||
@ -383,7 +383,7 @@ pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
||||
/// Compute the angle (in degrees) of the provided line segment.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line([5, 10], %, $seg01)
|
||||
@ -393,7 +393,7 @@ pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
||||
/// |> angledLine([segAng(seg01), -15], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(4, exampleSketch)
|
||||
/// example = extrude(4, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "segAng",
|
||||
@ -528,7 +528,7 @@ pub async fn angle_to_match_length_x(exec_state: &mut ExecState, args: Args) ->
|
||||
/// Returns the angle to match the given length for x.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([2, 5], %, $seg01)
|
||||
/// |> angledLineToX([
|
||||
@ -537,7 +537,7 @@ pub async fn angle_to_match_length_x(exec_state: &mut ExecState, args: Args) ->
|
||||
/// ], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const extrusion = extrude(5, sketch001)
|
||||
/// extrusion = extrude(5, sketch001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "angleToMatchLengthX",
|
||||
@ -591,7 +591,7 @@ pub async fn angle_to_match_length_y(exec_state: &mut ExecState, args: Args) ->
|
||||
/// Returns the angle to match the given length for y.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([1, 2], %, $seg01)
|
||||
/// |> angledLine({
|
||||
@ -601,7 +601,7 @@ pub async fn angle_to_match_length_y(exec_state: &mut ExecState, args: Args) ->
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const extrusion = extrude(5, sketch001)
|
||||
/// extrusion = extrude(5, sketch001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "angleToMatchLengthY",
|
||||
|
@ -56,14 +56,14 @@ pub async fn circle(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// the provided (x, y) origin point.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("-XZ")
|
||||
/// exampleSketch = startSketchOn("-XZ")
|
||||
/// |> circle({ center = [0, 0], radius = 10 }, %)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([-15, 0], %)
|
||||
/// |> line([30, 0], %)
|
||||
/// |> line([0, 30], %)
|
||||
@ -71,7 +71,7 @@ pub async fn circle(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> close(%)
|
||||
/// |> hole(circle({ center = [0, 15], radius = 5 }, %), %)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "circle",
|
||||
|
@ -38,7 +38,7 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Remove the end face for the extrusion.
|
||||
/// const firstSketch = startSketchOn('XY')
|
||||
/// firstSketch = startSketchOn('XY')
|
||||
/// |> startProfileAt([-12, 12], %)
|
||||
/// |> line([24, 0], %)
|
||||
/// |> line([0, -24], %)
|
||||
@ -55,7 +55,7 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Remove the start face for the extrusion.
|
||||
/// const firstSketch = startSketchOn('-XZ')
|
||||
/// firstSketch = startSketchOn('-XZ')
|
||||
/// |> startProfileAt([-12, 12], %)
|
||||
/// |> line([24, 0], %)
|
||||
/// |> line([0, -24], %)
|
||||
@ -72,7 +72,7 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Remove a tagged face and the end face for the extrusion.
|
||||
/// const firstSketch = startSketchOn('XY')
|
||||
/// firstSketch = startSketchOn('XY')
|
||||
/// |> startProfileAt([-12, 12], %)
|
||||
/// |> line([24, 0], %)
|
||||
/// |> line([0, -24], %)
|
||||
@ -89,7 +89,7 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Remove multiple faces at once.
|
||||
/// const firstSketch = startSketchOn('XY')
|
||||
/// firstSketch = startSketchOn('XY')
|
||||
/// |> startProfileAt([-12, 12], %)
|
||||
/// |> line([24, 0], %)
|
||||
/// |> line([0, -24], %)
|
||||
@ -106,8 +106,8 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Shell a sketch on face.
|
||||
/// let size = 100
|
||||
/// const case = startSketchOn('-XZ')
|
||||
/// size = 100
|
||||
/// case = startSketchOn('-XZ')
|
||||
/// |> startProfileAt([-size, -size], %)
|
||||
/// |> line([2 * size, 0], %)
|
||||
/// |> line([0, 2 * size], %)
|
||||
@ -115,11 +115,11 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// |> close(%)
|
||||
/// |> extrude(65, %)
|
||||
///
|
||||
/// const thing1 = startSketchOn(case, 'end')
|
||||
/// thing1 = startSketchOn(case, 'end')
|
||||
/// |> circle({ center = [-size / 2, -size / 2], radius = 25 }, %)
|
||||
/// |> extrude(50, %)
|
||||
///
|
||||
/// const thing2 = startSketchOn(case, 'end')
|
||||
/// thing2 = startSketchOn(case, 'end')
|
||||
/// |> circle({ center = [size / 2, -size / 2], radius = 25 }, %)
|
||||
/// |> extrude(50, %)
|
||||
///
|
||||
@ -129,8 +129,8 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Shell a sketch on face object on the end face.
|
||||
/// let size = 100
|
||||
/// const case = startSketchOn('XY')
|
||||
/// size = 100
|
||||
/// case = startSketchOn('XY')
|
||||
/// |> startProfileAt([-size, -size], %)
|
||||
/// |> line([2 * size, 0], %)
|
||||
/// |> line([0, 2 * size], %)
|
||||
@ -138,11 +138,11 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// |> close(%)
|
||||
/// |> extrude(65, %)
|
||||
///
|
||||
/// const thing1 = startSketchOn(case, 'end')
|
||||
/// thing1 = startSketchOn(case, 'end')
|
||||
/// |> circle({ center = [-size / 2, -size / 2], radius = 25 }, %)
|
||||
/// |> extrude(50, %)
|
||||
///
|
||||
/// const thing2 = startSketchOn(case, 'end')
|
||||
/// thing2 = startSketchOn(case, 'end')
|
||||
/// |> circle({ center = [size / 2, -size / 2], radius = 25 }, %)
|
||||
/// |> extrude(50, %)
|
||||
///
|
||||
@ -154,8 +154,8 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// // Shell sketched on face objects on the end face, include all sketches to shell
|
||||
/// // the entire object.
|
||||
///
|
||||
/// let size = 100
|
||||
/// const case = startSketchOn('XY')
|
||||
/// size = 100
|
||||
/// case = startSketchOn('XY')
|
||||
/// |> startProfileAt([-size, -size], %)
|
||||
/// |> line([2 * size, 0], %)
|
||||
/// |> line([0, 2 * size], %)
|
||||
@ -163,11 +163,11 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// |> close(%)
|
||||
/// |> extrude(65, %)
|
||||
///
|
||||
/// const thing1 = startSketchOn(case, 'end')
|
||||
/// thing1 = startSketchOn(case, 'end')
|
||||
/// |> circle({ center = [-size / 2, -size / 2], radius = 25 }, %)
|
||||
/// |> extrude(50, %)
|
||||
///
|
||||
/// const thing2 = startSketchOn(case, 'end')
|
||||
/// thing2 = startSketchOn(case, 'end')
|
||||
/// |> circle({ center = [size / 2, -size / 2], radius = 25 }, %)
|
||||
/// |> extrude(50, %)
|
||||
///
|
||||
@ -257,7 +257,7 @@ pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Hollow a basic sketch.
|
||||
/// const firstSketch = startSketchOn('XY')
|
||||
/// firstSketch = startSketchOn('XY')
|
||||
/// |> startProfileAt([-12, 12], %)
|
||||
/// |> line([24, 0], %)
|
||||
/// |> line([0, -24], %)
|
||||
@ -269,7 +269,7 @@ pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Hollow a basic sketch.
|
||||
/// const firstSketch = startSketchOn('-XZ')
|
||||
/// firstSketch = startSketchOn('-XZ')
|
||||
/// |> startProfileAt([-12, 12], %)
|
||||
/// |> line([24, 0], %)
|
||||
/// |> line([0, -24], %)
|
||||
@ -281,8 +281,8 @@ pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Hollow a sketch on face object.
|
||||
/// let size = 100
|
||||
/// const case = startSketchOn('-XZ')
|
||||
/// size = 100
|
||||
/// case = startSketchOn('-XZ')
|
||||
/// |> startProfileAt([-size, -size], %)
|
||||
/// |> line([2 * size, 0], %)
|
||||
/// |> line([0, 2 * size], %)
|
||||
@ -290,11 +290,11 @@ pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> close(%)
|
||||
/// |> extrude(65, %)
|
||||
///
|
||||
/// const thing1 = startSketchOn(case, 'end')
|
||||
/// thing1 = startSketchOn(case, 'end')
|
||||
/// |> circle({ center = [-size / 2, -size / 2], radius = 25 }, %)
|
||||
/// |> extrude(50, %)
|
||||
///
|
||||
/// const thing2 = startSketchOn(case, 'end')
|
||||
/// thing2 = startSketchOn(case, 'end')
|
||||
/// |> circle({ center = [size / 2, -size / 2], radius = 25 }, %)
|
||||
/// |> extrude(50, %)
|
||||
///
|
||||
|
@ -104,14 +104,14 @@ pub async fn line_to(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// Draw a line from the current origin to some absolute (x, y) point.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> lineTo([10, 0], %)
|
||||
/// |> lineTo([0, 10], %)
|
||||
/// |> lineTo([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "lineTo",
|
||||
@ -175,7 +175,7 @@ pub async fn x_line_to(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
/// then xLineTo(4) draws a line from (1, 1) to (4, 1)
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> xLineTo(15, %)
|
||||
/// |> angledLine({
|
||||
@ -191,7 +191,7 @@ pub async fn x_line_to(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
/// |> xLineTo(10, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "xLineTo",
|
||||
@ -225,7 +225,7 @@ pub async fn y_line_to(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
/// then yLineTo(4) draws a line from (1, 1) to (1, 4)
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 50,
|
||||
@ -234,7 +234,7 @@ pub async fn y_line_to(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "yLineTo",
|
||||
@ -266,25 +266,25 @@ pub async fn line(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// from the current position.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([25, 15], %)
|
||||
/// |> line([5, -6], %)
|
||||
/// |> line([-10, -10], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XZ")
|
||||
/// exampleSketch = startSketchOn("XZ")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "line",
|
||||
@ -349,7 +349,7 @@ pub async fn x_line(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// from the current position along the 'x' axis.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> xLine(15, %)
|
||||
/// |> angledLine({
|
||||
@ -365,7 +365,7 @@ pub async fn x_line(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> xLine(-15, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "xLine",
|
||||
@ -394,7 +394,7 @@ pub async fn y_line(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// from the current position along the 'y' axis.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> yLine(15, %)
|
||||
/// |> angledLine({
|
||||
@ -405,7 +405,7 @@ pub async fn y_line(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> yLine(-5, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "yLine",
|
||||
@ -450,7 +450,7 @@ pub async fn angled_line(exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// measure of some angle and distance.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> yLineTo(15, %)
|
||||
/// |> angledLine({
|
||||
@ -461,7 +461,7 @@ pub async fn angled_line(exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
/// |> yLineTo(0, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "angledLine",
|
||||
@ -537,14 +537,14 @@ pub async fn angled_line_of_x_length(exec_state: &mut ExecState, args: Args) ->
|
||||
/// along some angle (in degrees) for some relative length in the 'x' dimension.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// sketch001 = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLineOfXLength({ angle = 45, length = 10 }, %, $edge1)
|
||||
/// |> angledLineOfXLength({ angle = -15, length = 20 }, %, $edge2)
|
||||
/// |> line([0, -5], %)
|
||||
/// |> close(%, $edge3)
|
||||
///
|
||||
/// const extrusion = extrude(10, sketch001)
|
||||
/// extrusion = extrude(10, sketch001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "angledLineOfXLength",
|
||||
@ -608,14 +608,14 @@ pub async fn angled_line_to_x(exec_state: &mut ExecState, args: Args) -> Result<
|
||||
/// in the 'x' dimension.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLineToX({ angle = 30, to = 10 }, %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "angledLineToX",
|
||||
@ -667,7 +667,7 @@ pub async fn angled_line_of_y_length(exec_state: &mut ExecState, args: Args) ->
|
||||
/// along some angle (in degrees) for some relative length in the 'y' dimension.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> angledLineOfYLength({ angle = 45, length = 10 }, %)
|
||||
@ -676,7 +676,7 @@ pub async fn angled_line_of_y_length(exec_state: &mut ExecState, args: Args) ->
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> line([0, -30], %)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "angledLineOfYLength",
|
||||
@ -729,14 +729,14 @@ pub async fn angled_line_to_y(exec_state: &mut ExecState, args: Args) -> Result<
|
||||
/// in the 'y' dimension.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLineToY({ angle = 60, to = 20 }, %)
|
||||
/// |> line([-20, 0], %)
|
||||
/// |> angledLineToY({ angle = 70, to = 10 }, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "angledLineToY",
|
||||
@ -802,7 +802,7 @@ pub async fn angled_line_that_intersects(exec_state: &mut ExecState, args: Args)
|
||||
/// segment.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> lineTo([5, 10], %)
|
||||
/// |> lineTo([-10, 10], %, $lineToIntersect)
|
||||
@ -814,7 +814,7 @@ pub async fn angled_line_that_intersects(exec_state: &mut ExecState, args: Args)
|
||||
/// }, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "angledLineThatIntersects",
|
||||
@ -859,33 +859,33 @@ pub async fn start_sketch_at(exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// Start a new 2-dimensional sketch at a given point on the 'XY' plane.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchAt([0, 0])
|
||||
/// exampleSketch = startSketchAt([0, 0])
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchAt([10, 10])
|
||||
/// exampleSketch = startSketchAt([10, 10])
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchAt([-10, 23])
|
||||
/// exampleSketch = startSketchAt([-10, 23])
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "startSketchAt",
|
||||
@ -961,65 +961,65 @@ pub async fn start_sketch_on(exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// Start a new 2-dimensional sketch on a specific plane or face.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XY")
|
||||
/// exampleSketch = startSketchOn("XY")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
///
|
||||
/// const exampleSketch002 = startSketchOn(example, 'end')
|
||||
/// exampleSketch002 = startSketchOn(example, 'end')
|
||||
/// |> startProfileAt([1, 1], %)
|
||||
/// |> line([8, 0], %)
|
||||
/// |> line([0, 8], %)
|
||||
/// |> line([-8, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example002 = extrude(5, exampleSketch002)
|
||||
/// example002 = extrude(5, exampleSketch002)
|
||||
///
|
||||
/// const exampleSketch003 = startSketchOn(example002, 'end')
|
||||
/// exampleSketch003 = startSketchOn(example002, 'end')
|
||||
/// |> startProfileAt([2, 2], %)
|
||||
/// |> line([6, 0], %)
|
||||
/// |> line([0, 6], %)
|
||||
/// |> line([-6, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example003 = extrude(5, exampleSketch003)
|
||||
/// example003 = extrude(5, exampleSketch003)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn("XY")
|
||||
/// exampleSketch = startSketchOn("XY")
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line([0, 10], %, $sketchingFace)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
///
|
||||
/// const exampleSketch002 = startSketchOn(example, sketchingFace)
|
||||
/// exampleSketch002 = startSketchOn(example, sketchingFace)
|
||||
/// |> startProfileAt([1, 1], %)
|
||||
/// |> line([8, 0], %)
|
||||
/// |> line([0, 8], %)
|
||||
/// |> line([-8, 0], %)
|
||||
/// |> close(%, $sketchingFace002)
|
||||
///
|
||||
/// const example002 = extrude(10, exampleSketch002)
|
||||
/// example002 = extrude(10, exampleSketch002)
|
||||
///
|
||||
/// const exampleSketch003 = startSketchOn(example002, sketchingFace002)
|
||||
/// exampleSketch003 = startSketchOn(example002, sketchingFace002)
|
||||
/// |> startProfileAt([-8, 12], %)
|
||||
/// |> line([0, 6], %)
|
||||
/// |> line([6, 0], %)
|
||||
/// |> line([0, -6], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example003 = extrude(5, exampleSketch003)
|
||||
/// example003 = extrude(5, exampleSketch003)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XY')
|
||||
/// exampleSketch = startSketchOn('XY')
|
||||
/// |> startProfileAt([4, 12], %)
|
||||
/// |> line([2, 0], %)
|
||||
/// |> line([0, -6], %)
|
||||
@ -1030,20 +1030,20 @@ pub async fn start_sketch_on(exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// |> line([-2, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = revolve({ axis: 'y', angle: 180 }, exampleSketch)
|
||||
/// example = revolve({ axis: 'y', angle: 180 }, exampleSketch)
|
||||
///
|
||||
/// const exampleSketch002 = startSketchOn(example, 'end')
|
||||
/// exampleSketch002 = startSketchOn(example, 'end')
|
||||
/// |> startProfileAt([4.5, -5], %)
|
||||
/// |> line([0, 5], %)
|
||||
/// |> line([5, 0], %)
|
||||
/// |> line([0, -5], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example002 = extrude(5, exampleSketch002)
|
||||
/// example002 = extrude(5, exampleSketch002)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const a1 = startSketchOn({
|
||||
/// a1 = startSketchOn({
|
||||
/// plane: {
|
||||
/// origin = { x = 0, y = 0, z = 0 },
|
||||
/// xAxis = { x = 1, y = 0, z = 0 },
|
||||
@ -1177,36 +1177,36 @@ pub async fn start_profile_at(exec_state: &mut ExecState, args: Args) -> Result<
|
||||
/// Start a new profile at a given point.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('-XZ')
|
||||
/// exampleSketch = startSketchOn('-XZ')
|
||||
/// |> startProfileAt([10, 10], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('-XZ')
|
||||
/// exampleSketch = startSketchOn('-XZ')
|
||||
/// |> startProfileAt([-10, 23], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
/// example = extrude(5, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "startProfileAt",
|
||||
@ -1320,7 +1320,7 @@ pub async fn profile_start_x(_exec_state: &mut ExecState, args: Args) -> Result<
|
||||
/// value.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XY')
|
||||
/// sketch001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([5, 2], %)
|
||||
/// |> angledLine([-26.6, 50], %)
|
||||
/// |> angledLine([90, 50], %)
|
||||
@ -1344,7 +1344,7 @@ pub async fn profile_start_y(_exec_state: &mut ExecState, args: Args) -> Result<
|
||||
/// value.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XY')
|
||||
/// sketch001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([5, 2], %)
|
||||
/// |> angledLine({ angle = -60, length = 14 }, %)
|
||||
/// |> angledLineToY({ angle = 30, to = profileStartY(%) }, %)
|
||||
@ -1367,7 +1367,7 @@ pub async fn profile_start(_exec_state: &mut ExecState, args: Args) -> Result<Kc
|
||||
/// value.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XY')
|
||||
/// sketch001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([5, 2], %)
|
||||
/// |> angledLine({ angle = 120, length = 50 }, %, $seg01)
|
||||
/// |> angledLine({ angle = segAng(seg01) + 120, length = 50 }, %)
|
||||
@ -1406,13 +1406,13 @@ pub async fn close(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('-XZ')
|
||||
/// exampleSketch = startSketchOn('-XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "close",
|
||||
@ -1524,7 +1524,7 @@ pub async fn arc(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
||||
/// for to construct your shape, you're likely looking for tangentialArc.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([10, 0], %)
|
||||
/// |> arc({
|
||||
@ -1533,7 +1533,7 @@ pub async fn arc(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
||||
/// radius = 16
|
||||
/// }, %)
|
||||
/// |> close(%)
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "arc",
|
||||
@ -1631,14 +1631,14 @@ pub async fn arc_to(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// the start and end.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> arcTo({
|
||||
/// end = [10,0],
|
||||
/// interior = [5,5]
|
||||
/// }, %)
|
||||
/// |> close(%)
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "arcTo",
|
||||
@ -1767,7 +1767,7 @@ pub async fn tangential_arc(exec_state: &mut ExecState, args: Args) -> Result<Kc
|
||||
/// degrees along the imaginary circle.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 60,
|
||||
@ -1780,7 +1780,7 @@ pub async fn tangential_arc(exec_state: &mut ExecState, args: Args) -> Result<Kc
|
||||
/// }, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "tangentialArc",
|
||||
@ -1900,7 +1900,7 @@ pub async fn tangential_arc_to_relative(exec_state: &mut ExecState, args: Args)
|
||||
/// coordinates.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 60,
|
||||
@ -1910,7 +1910,7 @@ pub async fn tangential_arc_to_relative(exec_state: &mut ExecState, args: Args)
|
||||
/// |> line([10, -15], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "tangentialArcTo",
|
||||
@ -1966,7 +1966,7 @@ async fn inner_tangential_arc_to(
|
||||
/// distance away.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> angledLine({
|
||||
/// angle = 45,
|
||||
@ -1976,7 +1976,7 @@ async fn inner_tangential_arc_to(
|
||||
/// |> line([-10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "tangentialArcToRelative",
|
||||
@ -2108,7 +2108,7 @@ pub async fn bezier_curve(exec_state: &mut ExecState, args: Args) -> Result<KclV
|
||||
/// shape.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XZ')
|
||||
/// exampleSketch = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([0, 10], %)
|
||||
/// |> bezierCurve({
|
||||
@ -2119,7 +2119,7 @@ pub async fn bezier_curve(exec_state: &mut ExecState, args: Args) -> Result<KclV
|
||||
/// |> lineTo([10, 0], %)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// const example = extrude(10, exampleSketch)
|
||||
/// example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "bezierCurve",
|
||||
@ -2188,7 +2188,7 @@ pub async fn hole(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// Use a 2-dimensional sketch to cut a hole in another 2-dimensional sketch.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const exampleSketch = startSketchOn('XY')
|
||||
/// exampleSketch = startSketchOn('XY')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
/// |> line([0, 5], %)
|
||||
/// |> line([5, 0], %)
|
||||
@ -2197,24 +2197,24 @@ pub async fn hole(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// |> hole(circle({ center = [1, 1], radius = .25 }, %), %)
|
||||
/// |> hole(circle({ center = [1, 4], radius = .25 }, %), %)
|
||||
///
|
||||
/// const example = extrude(1, exampleSketch)
|
||||
/// example = extrude(1, exampleSketch)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// fn squareHoleSketch = () => {
|
||||
/// const squareSketch = startSketchOn('-XZ')
|
||||
/// |> startProfileAt([-1, -1], %)
|
||||
/// |> line([2, 0], %)
|
||||
/// |> line([0, 2], %)
|
||||
/// |> line([-2, 0], %)
|
||||
/// |> close(%)
|
||||
/// return squareSketch
|
||||
/// }
|
||||
/// fn squareHoleSketch() {
|
||||
/// squareSketch = startSketchOn('-XZ')
|
||||
/// |> startProfileAt([-1, -1], %)
|
||||
/// |> line([2, 0], %)
|
||||
/// |> line([0, 2], %)
|
||||
/// |> line([-2, 0], %)
|
||||
/// |> close(%)
|
||||
/// return squareSketch
|
||||
/// }
|
||||
///
|
||||
/// const exampleSketch = startSketchOn('-XZ')
|
||||
/// exampleSketch = startSketchOn('-XZ')
|
||||
/// |> circle({ center = [0, 0], radius = 3 }, %)
|
||||
/// |> hole(squareHoleSketch(), %)
|
||||
/// const example = extrude(1, exampleSketch)
|
||||
/// example = extrude(1, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "hole",
|
||||
|
102
src/wasm-lib/kcl/src/std/sweep.rs
Normal file
@ -0,0 +1,102 @@
|
||||
//! Standard library sweep.
|
||||
|
||||
use anyhow::Result;
|
||||
use derive_docs::stdlib;
|
||||
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, ModelingCmd};
|
||||
use kittycad_modeling_cmds::{self as kcmc};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::KclError,
|
||||
execution::{ExecState, KclValue, Sketch, Solid},
|
||||
std::{extrude::do_post_extrude, fillet::default_tolerance, Args},
|
||||
};
|
||||
|
||||
/// Data for a sweep.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
pub struct SweepData {
|
||||
/// The path to sweep along.
|
||||
pub path: Sketch,
|
||||
/// If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components.
|
||||
pub sectional: Option<bool>,
|
||||
/// Tolerance for the sweep operation.
|
||||
#[serde(default)]
|
||||
pub tolerance: Option<f64>,
|
||||
}
|
||||
|
||||
/// Extrude a sketch along a path.
|
||||
pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch): (SweepData, Sketch) = args.get_data_and_sketch()?;
|
||||
|
||||
let solid = inner_sweep(data, sketch, exec_state, args).await?;
|
||||
Ok(KclValue::Solid(solid))
|
||||
}
|
||||
|
||||
/// Extrude a sketch along a path.
|
||||
///
|
||||
/// This, like extrude, is able to create a 3-dimensional solid from a
|
||||
/// 2-dimensional sketch. However, unlike extrude, this creates a solid
|
||||
/// by using the extent of the sketch as its path. This is useful for
|
||||
/// creating more complex shapes that can't be created with a simple
|
||||
/// extrusion.
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Create a pipe using a sweep.
|
||||
///
|
||||
/// // Create a path for the sweep.
|
||||
/// sweepPath = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0.05, 0.05], %)
|
||||
/// |> line([0, 7], %)
|
||||
/// |> tangentialArc({
|
||||
/// offset: 90,
|
||||
/// radius: 5
|
||||
/// }, %)
|
||||
/// |> line([-3, 0], %)
|
||||
/// |> tangentialArc({
|
||||
/// offset: -90,
|
||||
/// radius: 5
|
||||
/// }, %)
|
||||
/// |> line([0, 7], %)
|
||||
///
|
||||
/// // Create a hole for the pipe.
|
||||
/// pipeHole = startSketchOn('XY')
|
||||
/// |> circle({
|
||||
/// center = [0, 0],
|
||||
/// radius = 1.5,
|
||||
/// }, %)
|
||||
///
|
||||
/// sweepSketch = startSketchOn('XY')
|
||||
/// |> circle({
|
||||
/// center = [0, 0],
|
||||
/// radius = 2,
|
||||
/// }, %)
|
||||
/// |> hole(pipeHole, %)
|
||||
/// |> sweep({
|
||||
/// path: sweepPath,
|
||||
/// }, %)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "sweep",
|
||||
}]
|
||||
async fn inner_sweep(
|
||||
data: SweepData,
|
||||
sketch: Sketch,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Box<Solid>, KclError> {
|
||||
let id = exec_state.id_generator.next_uuid();
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::from(mcmd::Sweep {
|
||||
target: sketch.id.into(),
|
||||
trajectory: data.path.id.into(),
|
||||
sectional: data.sectional.unwrap_or(false),
|
||||
tolerance: LengthUnit(data.tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
do_post_extrude(sketch, 0.0, exec_state, args).await
|
||||
}
|
@ -34,7 +34,7 @@ pub async fn mm(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
||||
/// `10 * (1/25.4)`, if the project settings are in inches.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const totalWidth = 10 * mm()
|
||||
/// totalWidth = 10 * mm()
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "mm",
|
||||
@ -75,7 +75,7 @@ pub async fn inch(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// `10 * 25.4`, if the project settings are in millimeters.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const totalWidth = 10 * inch()
|
||||
/// totalWidth = 10 * inch()
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "inch",
|
||||
@ -117,7 +117,7 @@ pub async fn ft(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
||||
/// `10 * 304.8`, if the project settings are in millimeters.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const totalWidth = 10 * ft()
|
||||
/// totalWidth = 10 * ft()
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "ft",
|
||||
@ -159,7 +159,7 @@ pub async fn m(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclE
|
||||
/// `10 * 1000`, if the project settings are in millimeters.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const totalWidth = 10 * m()
|
||||
/// totalWidth = 10 * m()
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "m",
|
||||
@ -201,7 +201,7 @@ pub async fn cm(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
||||
/// `10 * 10`, if the project settings are in millimeters.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const totalWidth = 10 * cm()
|
||||
/// totalWidth = 10 * cm()
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "cm",
|
||||
@ -243,7 +243,7 @@ pub async fn yd(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
||||
/// `10 * 914.4`, if the project settings are in millimeters.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const totalWidth = 10 * yd()
|
||||
/// totalWidth = 10 * yd()
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "yd",
|
||||
|
@ -69,7 +69,7 @@ async fn do_execute_and_snapshot(
|
||||
Ok((exec_state, img))
|
||||
}
|
||||
|
||||
async fn new_context(
|
||||
pub async fn new_context(
|
||||
units: UnitLength,
|
||||
with_auth: bool,
|
||||
project_directory: Option<PathBuf>,
|
||||
|
@ -272,7 +272,7 @@ impl LabeledArg {
|
||||
fn recast(&self, options: &FormatOptions, indentation_level: usize, ctxt: ExprContext) -> String {
|
||||
let label = &self.label.name;
|
||||
let arg = self.arg.recast(options, indentation_level, ctxt);
|
||||
format!("{label}: {arg}")
|
||||
format!("{label} = {arg}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,12 +38,46 @@ pub enum Node<'a> {
|
||||
|
||||
ObjectProperty(NodeRef<'a, types::ObjectProperty>),
|
||||
|
||||
MemberObject(&'a types::MemberObject),
|
||||
LiteralIdentifier(&'a types::LiteralIdentifier),
|
||||
|
||||
KclNone(&'a types::KclNone),
|
||||
}
|
||||
|
||||
impl Node<'_> {
|
||||
/// Return the digest of the [Node], pulling the underlying Digest from
|
||||
/// the AST types.
|
||||
///
|
||||
/// The Digest type may change over time.
|
||||
pub fn digest(&self) -> Option<[u8; 32]> {
|
||||
match self {
|
||||
Node::Program(n) => n.digest,
|
||||
Node::ImportStatement(n) => n.digest,
|
||||
Node::ExpressionStatement(n) => n.digest,
|
||||
Node::VariableDeclaration(n) => n.digest,
|
||||
Node::ReturnStatement(n) => n.digest,
|
||||
Node::VariableDeclarator(n) => n.digest,
|
||||
Node::Literal(n) => n.digest,
|
||||
Node::TagDeclarator(n) => n.digest,
|
||||
Node::Identifier(n) => n.digest,
|
||||
Node::BinaryExpression(n) => n.digest,
|
||||
Node::FunctionExpression(n) => n.digest,
|
||||
Node::CallExpression(n) => n.digest,
|
||||
Node::CallExpressionKw(n) => n.digest,
|
||||
Node::PipeExpression(n) => n.digest,
|
||||
Node::PipeSubstitution(n) => n.digest,
|
||||
Node::ArrayExpression(n) => n.digest,
|
||||
Node::ArrayRangeExpression(n) => n.digest,
|
||||
Node::ObjectExpression(n) => n.digest,
|
||||
Node::MemberExpression(n) => n.digest,
|
||||
Node::UnaryExpression(n) => n.digest,
|
||||
Node::Parameter(p) => p.digest,
|
||||
Node::ObjectProperty(n) => n.digest,
|
||||
Node::IfExpression(n) => n.digest,
|
||||
Node::ElseIf(n) => n.digest,
|
||||
Node::KclNone(n) => n.digest,
|
||||
Node::LabelledExpression(n) => n.digest,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returned during source_range conversion.
|
||||
#[derive(Debug)]
|
||||
pub enum AstNodeError {
|
||||
@ -78,10 +112,8 @@ impl TryFrom<&Node<'_>> for SourceRange {
|
||||
Node::UnaryExpression(n) => SourceRange::from(*n),
|
||||
Node::Parameter(p) => SourceRange::from(&p.identifier),
|
||||
Node::ObjectProperty(n) => SourceRange::from(*n),
|
||||
Node::MemberObject(m) => SourceRange::new(m.start(), m.end(), m.module_id()),
|
||||
Node::IfExpression(n) => SourceRange::from(*n),
|
||||
Node::LabelledExpression(n) => SourceRange::from(*n),
|
||||
Node::LiteralIdentifier(l) => SourceRange::new(l.start(), l.end(), l.module_id()),
|
||||
|
||||
// This is broken too
|
||||
Node::ElseIf(n) => SourceRange::new(n.cond.start(), n.cond.end(), n.cond.module_id()),
|
||||
@ -143,6 +175,24 @@ impl<'tree> From<&'tree types::BinaryPart> for Node<'tree> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tree> From<&'tree types::MemberObject> for Node<'tree> {
|
||||
fn from(node: &'tree types::MemberObject) -> Self {
|
||||
match node {
|
||||
types::MemberObject::MemberExpression(me) => me.as_ref().into(),
|
||||
types::MemberObject::Identifier(id) => id.as_ref().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tree> From<&'tree types::LiteralIdentifier> for Node<'tree> {
|
||||
fn from(node: &'tree types::LiteralIdentifier) -> Self {
|
||||
match node {
|
||||
types::LiteralIdentifier::Identifier(id) => id.as_ref().into(),
|
||||
types::LiteralIdentifier::Literal(lit) => lit.as_ref().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from {
|
||||
($node:ident, $t: ident) => {
|
||||
impl<'a> From<NodeRef<'a, types::$t>> for Node<'a> {
|
||||
@ -185,9 +235,7 @@ impl_from!(Node, MemberExpression);
|
||||
impl_from!(Node, UnaryExpression);
|
||||
impl_from!(Node, ObjectProperty);
|
||||
impl_from_ref!(Node, Parameter);
|
||||
impl_from_ref!(Node, MemberObject);
|
||||
impl_from!(Node, IfExpression);
|
||||
impl_from!(Node, ElseIf);
|
||||
impl_from!(Node, LabelledExpression);
|
||||
impl_from_ref!(Node, LiteralIdentifier);
|
||||
impl_from!(Node, KclNone);
|
||||
|
@ -134,8 +134,6 @@ impl<'tree> Visitable<'tree> for Node<'tree> {
|
||||
| Node::TagDeclarator(_)
|
||||
| Node::Identifier(_)
|
||||
| Node::ImportStatement(_)
|
||||
| Node::MemberObject(_)
|
||||
| Node::LiteralIdentifier(_)
|
||||
| Node::KclNone(_)
|
||||
| Node::Literal(_) => vec![],
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ snapshot_kind: text
|
||||
},
|
||||
{
|
||||
"declaration": {
|
||||
"end": 122,
|
||||
"end": 123,
|
||||
"id": {
|
||||
"end": 103,
|
||||
"name": "three",
|
||||
@ -212,9 +212,9 @@ snapshot_kind: text
|
||||
"name": "delta"
|
||||
},
|
||||
"arg": {
|
||||
"end": 121,
|
||||
"end": 122,
|
||||
"raw": "2",
|
||||
"start": 120,
|
||||
"start": 121,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": 2.0
|
||||
@ -227,7 +227,7 @@ snapshot_kind: text
|
||||
"start": 106,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 122,
|
||||
"end": 123,
|
||||
"start": 106,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
@ -243,14 +243,14 @@ snapshot_kind: text
|
||||
"start": 98,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 122,
|
||||
"end": 123,
|
||||
"kind": "const",
|
||||
"start": 98,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
}
|
||||
],
|
||||
"end": 123,
|
||||
"end": 124,
|
||||
"nonCodeMeta": {
|
||||
"nonCodeNodes": {
|
||||
"0": [
|
||||
|
@ -7,4 +7,4 @@ fn add(@x, delta) {
|
||||
}
|
||||
|
||||
two = increment(1)
|
||||
three = add(1, delta: 2)
|
||||
three = add(1, delta = 2)
|
||||
|
@ -330,8 +330,8 @@ snapshot_kind: text
|
||||
},
|
||||
{
|
||||
"sourceRange": [
|
||||
120,
|
||||
121,
|
||||
122,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ snapshot_kind: text
|
||||
},
|
||||
{
|
||||
"declaration": {
|
||||
"end": 50,
|
||||
"end": 51,
|
||||
"id": {
|
||||
"end": 38,
|
||||
"name": "three",
|
||||
@ -101,9 +101,9 @@ snapshot_kind: text
|
||||
"name": "x"
|
||||
},
|
||||
"arg": {
|
||||
"end": 49,
|
||||
"end": 50,
|
||||
"raw": "1",
|
||||
"start": 48,
|
||||
"start": 49,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": 1.0
|
||||
@ -116,7 +116,7 @@ snapshot_kind: text
|
||||
"start": 41,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 50,
|
||||
"end": 51,
|
||||
"start": 41,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
@ -125,14 +125,14 @@ snapshot_kind: text
|
||||
"start": 33,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 50,
|
||||
"end": 51,
|
||||
"kind": "const",
|
||||
"start": 33,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
}
|
||||
],
|
||||
"end": 51,
|
||||
"end": 52,
|
||||
"nonCodeMeta": {
|
||||
"nonCodeNodes": {
|
||||
"0": [
|
||||
|
@ -12,6 +12,6 @@ KCL Semantic error
|
||||
2 │ │ return x + y
|
||||
3 │ ╰─▶ }
|
||||
4 │
|
||||
5 │ three = add(x: 1)
|
||||
· ─────────
|
||||
5 │ three = add(x = 1)
|
||||
· ──────────
|
||||
╰────
|
||||
|
@ -2,4 +2,4 @@ fn add(x, y) {
|
||||
return x + y
|
||||
}
|
||||
|
||||
three = add(x: 1)
|
||||
three = add(x = 1)
|
||||
|
@ -78,7 +78,7 @@ snapshot_kind: text
|
||||
},
|
||||
{
|
||||
"declaration": {
|
||||
"end": 46,
|
||||
"end": 47,
|
||||
"id": {
|
||||
"end": 34,
|
||||
"name": "two",
|
||||
@ -94,9 +94,9 @@ snapshot_kind: text
|
||||
"name": "x"
|
||||
},
|
||||
"arg": {
|
||||
"end": 45,
|
||||
"end": 46,
|
||||
"raw": "1",
|
||||
"start": 44,
|
||||
"start": 45,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": 1.0
|
||||
@ -109,7 +109,7 @@ snapshot_kind: text
|
||||
"start": 37,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 46,
|
||||
"end": 47,
|
||||
"start": 37,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
@ -118,14 +118,14 @@ snapshot_kind: text
|
||||
"start": 31,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 46,
|
||||
"end": 47,
|
||||
"kind": "const",
|
||||
"start": 31,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
}
|
||||
],
|
||||
"end": 47,
|
||||
"end": 48,
|
||||
"nonCodeMeta": {
|
||||
"nonCodeNodes": {
|
||||
"0": [
|
||||
|
@ -12,6 +12,6 @@ KCL Semantic error
|
||||
2 │ │ return x + 1
|
||||
3 │ ╰─▶ }
|
||||
4 │
|
||||
5 │ two = add(x: 1)
|
||||
· ─────────
|
||||
5 │ two = add(x = 1)
|
||||
· ──────────
|
||||
╰────
|
||||
|
@ -2,4 +2,4 @@ fn add(@x) {
|
||||
return x + 1
|
||||
}
|
||||
|
||||
two = add(x: 1)
|
||||
two = add(x = 1)
|
||||
|
@ -132,7 +132,7 @@ snapshot_kind: text
|
||||
},
|
||||
{
|
||||
"declaration": {
|
||||
"end": 98,
|
||||
"end": 99,
|
||||
"id": {
|
||||
"end": 75,
|
||||
"name": "twentyOne",
|
||||
@ -148,9 +148,9 @@ snapshot_kind: text
|
||||
"name": "by"
|
||||
},
|
||||
"arg": {
|
||||
"end": 97,
|
||||
"end": 98,
|
||||
"raw": "20",
|
||||
"start": 95,
|
||||
"start": 96,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": 20.0
|
||||
@ -163,7 +163,7 @@ snapshot_kind: text
|
||||
"start": 78,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 98,
|
||||
"end": 99,
|
||||
"start": 78,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
@ -179,14 +179,14 @@ snapshot_kind: text
|
||||
"start": 66,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 98,
|
||||
"end": 99,
|
||||
"kind": "const",
|
||||
"start": 66,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
}
|
||||
],
|
||||
"end": 99,
|
||||
"end": 100,
|
||||
"nonCodeMeta": {
|
||||
"nonCodeNodes": {
|
||||
"0": [
|
||||
|
@ -3,4 +3,4 @@ fn increment(@x, by? = 1) {
|
||||
}
|
||||
|
||||
two = increment(1)
|
||||
twentyOne = increment(1, by: 20)
|
||||
twentyOne = increment(1, by = 20)
|
||||
|
@ -148,8 +148,8 @@ snapshot_kind: text
|
||||
},
|
||||
{
|
||||
"sourceRange": [
|
||||
95,
|
||||
97,
|
||||
96,
|
||||
98,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 74 KiB |
BIN
src/wasm-lib/kcl/tests/outputs/serial_test_example_atan20.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
src/wasm-lib/kcl/tests/outputs/serial_test_example_sweep0.png
Normal file
After Width: | Height: | Size: 73 KiB |
@ -77,8 +77,8 @@ fn setLength = (state, _q) => {
|
||||
|
||||
fn Gt2 = (state) => { return setLength(state, state.currentLength * state.factor) }
|
||||
fn Lt2 = (state) => { return setLength(state, state.currentLength / state.factor) }
|
||||
fn Add = (state) => { return setAngle(state, rem(int(state.currentAngle - state.angle), divisor: 360)) }
|
||||
fn Sub = (state) => { return setAngle(state, rem(int(state.currentAngle + state.angle), divisor: 360)) }
|
||||
fn Add = (state) => { return setAngle(state, rem(int(state.currentAngle - state.angle), divisor = 360)) }
|
||||
fn Sub = (state) => { return setAngle(state, rem(int(state.currentAngle + state.angle), divisor = 360)) }
|
||||
|
||||
// Only necessary to get around recursion limitations...
|
||||
fn F = (state, F) => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
mod cache;
|
||||
|
||||
use kcl_lib::{
|
||||
test_server::{execute_and_snapshot, execute_and_snapshot_no_auth},
|
||||
test_server::{execute_and_snapshot, execute_and_snapshot_no_auth, new_context},
|
||||
UnitLength,
|
||||
};
|
||||
|
||||
@ -2001,3 +2001,62 @@ async fn kcl_test_error_no_auth_websocket() {
|
||||
.to_string()
|
||||
.contains("Please send the following object over this websocket"));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_ids_stable_between_executions() {
|
||||
let code = r#"sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt([61.74, 206.13], %)
|
||||
|> xLine(305.11, %, $seg01)
|
||||
|> yLine(-291.85, %)
|
||||
|> xLine(-segLen(seg01), %)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
|> extrude(40.14, %)
|
||||
|> shell({
|
||||
faces: [seg01],
|
||||
thickness: 3.14,
|
||||
}, %)
|
||||
"#;
|
||||
|
||||
let ctx = new_context(UnitLength::Mm, true, None).await.unwrap();
|
||||
let old_program = kcl_lib::Program::parse_no_errs(code).unwrap();
|
||||
// Execute the program.
|
||||
let mut exec_state = Default::default();
|
||||
let cache_info = kcl_lib::CacheInformation {
|
||||
old: None,
|
||||
new_ast: old_program.ast.clone(),
|
||||
};
|
||||
ctx.run(cache_info, &mut exec_state).await.unwrap();
|
||||
|
||||
// Get the id_generator from the first execution.
|
||||
let id_generator = exec_state.id_generator.clone();
|
||||
|
||||
let code = r#"sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt([62.74, 206.13], %)
|
||||
|> xLine(305.11, %, $seg01)
|
||||
|> yLine(-291.85, %)
|
||||
|> xLine(-segLen(seg01), %)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
|> extrude(40.14, %)
|
||||
|> shell({
|
||||
faces: [seg01],
|
||||
thickness: 3.14,
|
||||
}, %)
|
||||
"#;
|
||||
|
||||
// Execute a slightly different program again.
|
||||
let program = kcl_lib::Program::parse_no_errs(code).unwrap();
|
||||
let cache_info = kcl_lib::CacheInformation {
|
||||
old: Some(kcl_lib::OldAstState {
|
||||
ast: old_program.ast.clone(),
|
||||
exec_state: exec_state.clone(),
|
||||
settings: ctx.settings.clone(),
|
||||
}),
|
||||
new_ast: program.ast.clone(),
|
||||
};
|
||||
// Execute the program.
|
||||
ctx.run(cache_info, &mut exec_state).await.unwrap();
|
||||
|
||||
assert_eq!(id_generator, exec_state.id_generator);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 35 KiB |