Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
fc3ce4cda8 | |||
a7f5c56ba1 | |||
c8747bd55a | |||
e2fd3948f5 | |||
e960d4d8a4 | |||
1ccf8d4dd4 | |||
b65ea8e0a9 | |||
90cb26c6d9 | |||
3562076b83 | |||
6230747b51 |
2
Makefile
2
Makefile
@ -1,5 +1,5 @@
|
||||
.PHONY: all
|
||||
all: install build check
|
||||
all: install check build
|
||||
|
||||
###############################################################################
|
||||
# INSTALL
|
||||
|
@ -50,7 +50,7 @@ r = 10 // radius
|
||||
// Call `map`, using an anonymous function instead of a named one.
|
||||
circles = map(
|
||||
[1..3],
|
||||
f = fn(id) {
|
||||
f = fn(@id) {
|
||||
return startSketchOn(XY)
|
||||
|> circle(center = [id * 2 * r, 0], radius = r)
|
||||
},
|
||||
|
@ -34,8 +34,8 @@ reduce(
|
||||
|
||||
```kcl
|
||||
// This function adds two numbers.
|
||||
fn add(a, b) {
|
||||
return a + b
|
||||
fn add(@a, accum) {
|
||||
return a + accum
|
||||
}
|
||||
|
||||
// This function adds an array of numbers.
|
||||
@ -49,7 +49,7 @@ fn sum(@arr) {
|
||||
fn sum(arr):
|
||||
sumSoFar = 0
|
||||
for i in arr:
|
||||
sumSoFar = add(sumSoFar, i)
|
||||
sumSoFar = add(i, sumSoFar)
|
||||
return sumSoFar */
|
||||
|
||||
// We use `assert` to check that our `sum` function gives the
|
||||
@ -72,8 +72,8 @@ arr = [1, 2, 3]
|
||||
sum = reduce(
|
||||
arr,
|
||||
initial = 0,
|
||||
f = fn(i, result_so_far) {
|
||||
return i + result_so_far
|
||||
f = fn(@i, accum) {
|
||||
return i + accum
|
||||
},
|
||||
)
|
||||
|
||||
@ -105,11 +105,11 @@ fn decagon(@radius) {
|
||||
fullDecagon = reduce(
|
||||
[1..10],
|
||||
initial = startOfDecagonSketch,
|
||||
f = fn(i, partialDecagon) {
|
||||
f = fn(@i, accum) {
|
||||
// Draw one edge of the decagon.
|
||||
x = cos(stepAngle * i) * radius
|
||||
y = sin(stepAngle * i) * radius
|
||||
return line(partialDecagon, end = [x, y])
|
||||
return line(accum, end = [x, y])
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -133826,7 +133826,7 @@
|
||||
false
|
||||
],
|
||||
[
|
||||
"r = 10 // radius\n// Call `map`, using an anonymous function instead of a named one.\ncircles = map(\n [1..3],\n f = fn(id) {\n return startSketchOn(XY)\n |> circle(center = [id * 2 * r, 0], radius = r)\n },\n)",
|
||||
"r = 10 // radius\n// Call `map`, using an anonymous function instead of a named one.\ncircles = map(\n [1..3],\n f = fn(@id) {\n return startSketchOn(XY)\n |> circle(center = [id * 2 * r, 0], radius = r)\n },\n)",
|
||||
false
|
||||
]
|
||||
]
|
||||
@ -232586,15 +232586,15 @@
|
||||
"deprecated": false,
|
||||
"examples": [
|
||||
[
|
||||
"// This function adds two numbers.\nfn add(a, b) {\n return a + b\n}\n\n// This function adds an array of numbers.\n// It uses the `reduce` function, to call the `add` function on every\n// element of the `arr` parameter. The starting value is 0.\nfn sum(@arr) {\n return reduce(arr, initial = 0, f = add)\n}\n\n/* The above is basically like this pseudo-code:\nfn sum(arr):\n sumSoFar = 0\n for i in arr:\n sumSoFar = add(sumSoFar, i)\n return sumSoFar */\n\n// We use `assert` to check that our `sum` function gives the\n// expected result. It's good to check your work!\nassert(\n sum([1, 2, 3]),\n isEqualTo = 6,\n tolerance = 0.1,\n error = \"1 + 2 + 3 summed is 6\",\n)",
|
||||
"// This function adds two numbers.\nfn add(@a, accum) {\n return a + accum\n}\n\n// This function adds an array of numbers.\n// It uses the `reduce` function, to call the `add` function on every\n// element of the `arr` parameter. The starting value is 0.\nfn sum(@arr) {\n return reduce(arr, initial = 0, f = add)\n}\n\n/* The above is basically like this pseudo-code:\nfn sum(arr):\n sumSoFar = 0\n for i in arr:\n sumSoFar = add(i, sumSoFar)\n return sumSoFar */\n\n// We use `assert` to check that our `sum` function gives the\n// expected result. It's good to check your work!\nassert(\n sum([1, 2, 3]),\n isEqualTo = 6,\n tolerance = 0.1,\n error = \"1 + 2 + 3 summed is 6\",\n)",
|
||||
false
|
||||
],
|
||||
[
|
||||
"// This example works just like the previous example above, but it uses\n// an anonymous `add` function as its parameter, instead of declaring a\n// named function outside.\narr = [1, 2, 3]\nsum = reduce(\n arr,\n initial = 0,\n f = fn(i, result_so_far) {\n return i + result_so_far\n },\n)\n\n// We use `assert` to check that our `sum` function gives the\n// expected result. It's good to check your work!\nassert(\n sum,\n isEqualTo = 6,\n tolerance = 0.1,\n error = \"1 + 2 + 3 summed is 6\",\n)",
|
||||
"// This example works just like the previous example above, but it uses\n// an anonymous `add` function as its parameter, instead of declaring a\n// named function outside.\narr = [1, 2, 3]\nsum = reduce(\n arr,\n initial = 0,\n f = fn(@i, accum) {\n return i + accum\n },\n)\n\n// We use `assert` to check that our `sum` function gives the\n// expected result. It's good to check your work!\nassert(\n sum,\n isEqualTo = 6,\n tolerance = 0.1,\n error = \"1 + 2 + 3 summed is 6\",\n)",
|
||||
false
|
||||
],
|
||||
[
|
||||
"// Declare a function that sketches a decagon.\nfn decagon(@radius) {\n // Each side of the decagon is turned this many radians from the previous angle.\n stepAngle = (1 / 10 * TAU): number(rad)\n\n // Start the decagon sketch at this point.\n startOfDecagonSketch = startSketchOn(XY)\n |> startProfile(at = [cos(0) * radius, sin(0) * radius])\n\n // Use a `reduce` to draw the remaining decagon sides.\n // For each number in the array 1..10, run the given function,\n // which takes a partially-sketched decagon and adds one more edge to it.\n fullDecagon = reduce(\n [1..10],\n initial = startOfDecagonSketch,\n f = fn(i, partialDecagon) {\n // Draw one edge of the decagon.\n x = cos(stepAngle * i) * radius\n y = sin(stepAngle * i) * radius\n return line(partialDecagon, end = [x, y])\n },\n )\n\n return fullDecagon\n}\n\n/* The `decagon` above is basically like this pseudo-code:\nfn decagon(radius):\n stepAngle = ((1/10) * TAU): number(rad)\n plane = startSketchOn(XY)\n startOfDecagonSketch = startProfile(plane, at = [(cos(0)*radius), (sin(0) * radius)])\n\n // Here's the reduce part.\n partialDecagon = startOfDecagonSketch\n for i in [1..10]:\n x = cos(stepAngle * i) * radius\n y = sin(stepAngle * i) * radius\n partialDecagon = line(partialDecagon, end = [x, y])\n fullDecagon = partialDecagon // it's now full\n return fullDecagon */\n\n// Use the `decagon` function declared above, to sketch a decagon with radius 5.\ndecagon(5.0)\n |> close()",
|
||||
"// Declare a function that sketches a decagon.\nfn decagon(@radius) {\n // Each side of the decagon is turned this many radians from the previous angle.\n stepAngle = (1 / 10 * TAU): number(rad)\n\n // Start the decagon sketch at this point.\n startOfDecagonSketch = startSketchOn(XY)\n |> startProfile(at = [cos(0) * radius, sin(0) * radius])\n\n // Use a `reduce` to draw the remaining decagon sides.\n // For each number in the array 1..10, run the given function,\n // which takes a partially-sketched decagon and adds one more edge to it.\n fullDecagon = reduce(\n [1..10],\n initial = startOfDecagonSketch,\n f = fn(@i, accum) {\n // Draw one edge of the decagon.\n x = cos(stepAngle * i) * radius\n y = sin(stepAngle * i) * radius\n return line(accum, end = [x, y])\n },\n )\n\n return fullDecagon\n}\n\n/* The `decagon` above is basically like this pseudo-code:\nfn decagon(radius):\n stepAngle = ((1/10) * TAU): number(rad)\n plane = startSketchOn(XY)\n startOfDecagonSketch = startProfile(plane, at = [(cos(0)*radius), (sin(0) * radius)])\n\n // Here's the reduce part.\n partialDecagon = startOfDecagonSketch\n for i in [1..10]:\n x = cos(stepAngle * i) * radius\n y = sin(stepAngle * i) * radius\n partialDecagon = line(partialDecagon, end = [x, y])\n fullDecagon = partialDecagon // it's now full\n return fullDecagon */\n\n// Use the `decagon` function declared above, to sketch a decagon with radius 5.\ndecagon(5.0)\n |> close()",
|
||||
false
|
||||
]
|
||||
]
|
||||
|
@ -2321,11 +2321,12 @@ extrude001 = extrude(sketch001, length = -12)
|
||||
})
|
||||
})
|
||||
|
||||
test(`Fillet point-and-click edit rejected when not in pipe`, async ({
|
||||
test(`Fillet point-and-click edit standalone expression`, async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
editor,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
@ -2339,23 +2340,44 @@ profile001 = circle(
|
||||
extrude001 = extrude(profile001, length = 100)
|
||||
fillet001 = fillet(extrude001, radius = 5, tags = [getOppositeEdge(seg01)])
|
||||
`
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await test.step('Double-click in feature tree and expect error toast', async () => {
|
||||
await test.step(`Initial test setup`, async () => {
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.settled(cmdBar)
|
||||
})
|
||||
await test.step('Edit fillet', async () => {
|
||||
await toolbar.openPane('feature-tree')
|
||||
await toolbar.closePane('code')
|
||||
const operationButton = await toolbar.getFeatureTreeOperation('Fillet', 0)
|
||||
await operationButton.dblclick({ button: 'left' })
|
||||
await expect(
|
||||
page.getByText(
|
||||
'Only chamfer and fillet in pipe expressions are supported for edits'
|
||||
)
|
||||
).toBeVisible()
|
||||
await page.waitForTimeout(1000)
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Fillet',
|
||||
currentArgKey: 'radius',
|
||||
currentArgValue: '5',
|
||||
headerArguments: {
|
||||
Radius: '5',
|
||||
},
|
||||
highlightedHeaderArg: 'radius',
|
||||
stage: 'arguments',
|
||||
})
|
||||
await page.keyboard.insertText('20')
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
Radius: '20',
|
||||
},
|
||||
commandName: 'Fillet',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
})
|
||||
await test.step('Confirm changes', async () => {
|
||||
await toolbar.openPane('code')
|
||||
await toolbar.closePane('feature-tree')
|
||||
await editor.expectEditor.toContain('radius = 20')
|
||||
})
|
||||
})
|
||||
|
||||
|
43
e2e/playwright/share-link.spec.ts
Normal file
43
e2e/playwright/share-link.spec.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
const isWindows =
|
||||
navigator.platform === 'Windows' || navigator.platform === 'Win32'
|
||||
test.describe('Share link tests', () => {
|
||||
;[
|
||||
{
|
||||
codeLength: 1000,
|
||||
showsErrorOnWindows: false,
|
||||
},
|
||||
{
|
||||
codeLength: 2000,
|
||||
showsErrorOnWindows: true,
|
||||
},
|
||||
].forEach(({ codeLength, showsErrorOnWindows }) => {
|
||||
test(`Open in desktop app with ${codeLength}-long code ${isWindows && showsErrorOnWindows ? 'shows error' : "doesn't show error"}`, async ({
|
||||
page,
|
||||
}) => {
|
||||
if (process.env.PLATFORM !== 'web') {
|
||||
// This test is web-only
|
||||
// TODO: re-enable on CI as part of a new web test suite
|
||||
return
|
||||
}
|
||||
|
||||
const code = Array(codeLength).fill('0').join('')
|
||||
const targetURL = `?create-file=true&browser=test&code=${code}&ask-open-desktop=true`
|
||||
expect(targetURL.length).toEqual(codeLength + 58)
|
||||
await page.goto(page.url() + targetURL)
|
||||
expect(page.url()).toContain(targetURL)
|
||||
const button = page.getByRole('button', { name: 'Open in desktop app' })
|
||||
await button.click()
|
||||
const toastError = page.getByText(
|
||||
'The URL is too long to open in the desktop app on Windows'
|
||||
)
|
||||
if (isWindows && showsErrorOnWindows) {
|
||||
await expect(toastError).toBeVisible()
|
||||
} else {
|
||||
await expect(toastError).not.toBeVisible()
|
||||
// TODO: check if we could verify the deep link dialog shows up
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
@ -1,17 +1,8 @@
|
||||
import { spawn } from 'child_process'
|
||||
import path from 'path'
|
||||
import type { Models } from '@kittycad/lib'
|
||||
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
|
||||
import fsp from 'fs/promises'
|
||||
import JSZip from 'jszip'
|
||||
|
||||
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
|
||||
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
|
||||
import { secrets } from '@e2e/playwright/secrets'
|
||||
import { TEST_SETTINGS, TEST_SETTINGS_KEY } from '@e2e/playwright/storageStates'
|
||||
import type { Paths } from '@e2e/playwright/test-utils'
|
||||
import {
|
||||
doExport,
|
||||
getUtils,
|
||||
headerMasks,
|
||||
networkingMasks,
|
||||
@ -40,275 +31,6 @@ test.afterEach(async ({ page }) => {
|
||||
|
||||
test.setTimeout(60_000)
|
||||
|
||||
// We test this end to end already - getting this to work on web just to take
|
||||
// a snapshot of it feels weird. I'd rather our regular tests fail.
|
||||
// The primary failure is doExport now relies on the filesystem. We can follow
|
||||
// up with another PR if we want this back.
|
||||
test(
|
||||
'exports of each format should work',
|
||||
{ tag: ['@snapshot'] },
|
||||
async ({ page, context, scene, cmdBar, tronApp }) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
// FYI this test doesn't work with only engine running locally
|
||||
// And you will need to have the KittyCAD CLI installed
|
||||
const u = await getUtils(page)
|
||||
await context.addInitScript(async () => {
|
||||
;(window as any).playwrightSkipFilePicker = true
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`topAng = 25
|
||||
bottomAng = 35
|
||||
baseLen = 3.5
|
||||
baseHeight = 1
|
||||
totalHeightHalf = 2
|
||||
armThick = 0.5
|
||||
totalLen = 9.5
|
||||
part001 = startSketchOn(-XZ)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> yLine(length = baseHeight)
|
||||
|> xLine(length = baseLen)
|
||||
|> angledLine(
|
||||
angle = topAng,
|
||||
endAbsoluteY = totalHeightHalf,
|
||||
tag = $seg04,
|
||||
)
|
||||
|> xLine(endAbsolute = totalLen, tag = $seg03)
|
||||
|> yLine(length = -armThick, tag = $seg01)
|
||||
|> angledLineThatIntersects(angle = turns::HALF_TURN, offset = -armThick, intersectTag = seg04)
|
||||
|> angledLine(angle = segAng(seg04) + 180, endAbsoluteY = turns::ZERO)
|
||||
|> angledLine(
|
||||
angle = -bottomAng,
|
||||
endAbsoluteY = -totalHeightHalf - armThick,
|
||||
tag = $seg02,
|
||||
)
|
||||
|> xLine(length = endAbsolute = segEndX(seg03) + 0)
|
||||
|> yLine(length = -segLen(seg01))
|
||||
|> angledLineThatIntersects(angle = turns::HALF_TURN, offset = -armThick, intersectTag = seg02)
|
||||
|> angledLine(angle = segAng(seg02) + 180, endAbsoluteY = -baseHeight)
|
||||
|> xLine(endAbsolute = turns::ZERO)
|
||||
|> close()
|
||||
|> extrude(length = 4)`
|
||||
)
|
||||
})
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const axisDirectionPair: Models['AxisDirectionPair_type'] = {
|
||||
axis: 'z',
|
||||
direction: 'positive',
|
||||
}
|
||||
const sysType: Models['System_type'] = {
|
||||
forward: axisDirectionPair,
|
||||
up: axisDirectionPair,
|
||||
}
|
||||
|
||||
const exportLocations: Paths[] = []
|
||||
|
||||
// NOTE it was easiest to leverage existing types and have doExport take Models['OutputFormat_type'] as in input
|
||||
// just note that only `type` and `storage` are used for selecting the drop downs is the app
|
||||
// the rest are only there to make typescript happy
|
||||
|
||||
// TODO - failing because of an exporter issue, ADD BACK IN WHEN ITS FIXED
|
||||
// exportLocations.push(
|
||||
// await doExport(
|
||||
// {
|
||||
// type: 'step',
|
||||
// coords: sysType,
|
||||
// },
|
||||
// page
|
||||
// )
|
||||
// )
|
||||
exportLocations.push(
|
||||
await doExport(
|
||||
{
|
||||
type: 'ply',
|
||||
coords: sysType,
|
||||
selection: { type: 'default_scene' },
|
||||
storage: 'ascii',
|
||||
units: 'in',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport(
|
||||
{
|
||||
type: 'ply',
|
||||
storage: 'binary_little_endian',
|
||||
coords: sysType,
|
||||
selection: { type: 'default_scene' },
|
||||
units: 'in',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport(
|
||||
{
|
||||
type: 'ply',
|
||||
storage: 'binary_big_endian',
|
||||
coords: sysType,
|
||||
selection: { type: 'default_scene' },
|
||||
units: 'in',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport(
|
||||
{
|
||||
type: 'stl',
|
||||
storage: 'ascii',
|
||||
coords: sysType,
|
||||
units: 'in',
|
||||
selection: { type: 'default_scene' },
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport(
|
||||
{
|
||||
type: 'stl',
|
||||
storage: 'binary',
|
||||
coords: sysType,
|
||||
units: 'in',
|
||||
selection: { type: 'default_scene' },
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport(
|
||||
{
|
||||
// obj seems to be a little flaky, times out tests sometimes
|
||||
type: 'obj',
|
||||
coords: sysType,
|
||||
units: 'in',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport(
|
||||
{
|
||||
type: 'gltf',
|
||||
storage: 'embedded',
|
||||
presentation: 'pretty',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport(
|
||||
{
|
||||
type: 'gltf',
|
||||
storage: 'binary',
|
||||
presentation: 'pretty',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport(
|
||||
{
|
||||
type: 'gltf',
|
||||
storage: 'standard',
|
||||
presentation: 'pretty',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
|
||||
// close page to disconnect websocket since we can only have one open atm
|
||||
await page.close()
|
||||
|
||||
// snapshot exports, good compromise to capture that exports are healthy without getting bogged down in "did the formatting change" changes
|
||||
// context: https://github.com/KittyCAD/modeling-app/issues/1222
|
||||
for (let { modelPath, imagePath, outputType } of exportLocations) {
|
||||
// May change depending on the file being dealt with
|
||||
let cliCommand = `export ZOO_TOKEN=${secrets.snapshottoken} && zoo file snapshot --output-format=png --src-format=${outputType} ${modelPath} ${imagePath}`
|
||||
const fileSize = (await fsp.stat(modelPath)).size
|
||||
console.log(`Size of the file at ${modelPath}: ${fileSize} bytes`)
|
||||
|
||||
const parentPath = path.dirname(modelPath)
|
||||
|
||||
// This is actually a zip file.
|
||||
if (modelPath.includes('gltf-standard.gltf')) {
|
||||
console.log('Extracting files from archive')
|
||||
const readZipFile = fsp.readFile(modelPath)
|
||||
const unzip = (archive: any) =>
|
||||
Object.values(archive.files).map((file: any) => ({
|
||||
name: file.name,
|
||||
promise: file.async('nodebuffer'),
|
||||
}))
|
||||
const writeFiles = (files: any) =>
|
||||
Promise.all(
|
||||
files.map((file: any) =>
|
||||
file.promise.then((data: any) => {
|
||||
console.log(`Writing ${file.name}`)
|
||||
return fsp
|
||||
.writeFile(`${parentPath}/${file.name}`, data)
|
||||
.then(() => file.name)
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
const filenames = await readZipFile
|
||||
.then(JSZip.loadAsync)
|
||||
.then(unzip)
|
||||
.then(writeFiles)
|
||||
const gltfFilename = filenames.filter((t: string) =>
|
||||
t.includes('.gltf')
|
||||
)[0]
|
||||
if (!gltfFilename) throw new Error('No gLTF in this archive')
|
||||
cliCommand = `export ZOO_TOKEN=${secrets.snapshottoken} && zoo file snapshot --output-format=png --src-format=${outputType} ${parentPath}/${gltfFilename} ${imagePath}`
|
||||
}
|
||||
|
||||
console.log(cliCommand)
|
||||
|
||||
const child = spawn(cliCommand, { shell: true })
|
||||
const result = await new Promise<string>((resolve, reject) => {
|
||||
child.on('error', (code: any, msg: any) => {
|
||||
console.log('error', code, msg)
|
||||
reject('error')
|
||||
})
|
||||
child.on('exit', (code, msg) => {
|
||||
console.log('exit', code, msg)
|
||||
if (code !== 0) {
|
||||
reject(`exit code ${code} for model ${modelPath}`)
|
||||
} else {
|
||||
resolve('success')
|
||||
}
|
||||
})
|
||||
child.stderr.on('data', (data) => console.log(`stderr: ${data}`))
|
||||
child.stdout.on('data', (data) => console.log(`stdout: ${data}`))
|
||||
})
|
||||
expect(result).toBe('success')
|
||||
if (result === 'success') {
|
||||
console.log(`snapshot taken for ${modelPath}`)
|
||||
} else {
|
||||
console.log(`snapshot failed for ${modelPath}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const extrudeDefaultPlane = async (
|
||||
context: any,
|
||||
page: any,
|
||||
|
@ -52,7 +52,9 @@ test.describe('Testing loading external models', () => {
|
||||
name,
|
||||
})
|
||||
const warningText = page.getByText('Overwrite current file with sample?')
|
||||
const confirmButton = page.getByRole('button', { name: 'Submit command' })
|
||||
const confirmButton = page.getByRole('button', {
|
||||
name: 'Submit command',
|
||||
})
|
||||
|
||||
await test.step(`Precondition: check the initial code`, async () => {
|
||||
await u.openKclCodePanel()
|
||||
|
@ -51,7 +51,7 @@ faceRotations = [
|
||||
// Create faces by mapping over the rotations array
|
||||
dodecFaces = map(
|
||||
faceRotations,
|
||||
f = fn(rotation) {
|
||||
f = fn(@rotation) {
|
||||
return createFaceTemplate(rotation[3])
|
||||
|> rotate(
|
||||
pitch = rotation[0],
|
||||
@ -66,15 +66,15 @@ fn calculateArrayLength(@arr) {
|
||||
return reduce(
|
||||
arr,
|
||||
initial = 0,
|
||||
f = fn(item, accumulator) {
|
||||
return accumulator + 1
|
||||
f = fn(@item, accum) {
|
||||
return accum + 1
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn createIntersection(@solids) {
|
||||
fn reduceIntersect(previous, current) {
|
||||
return intersect([previous, current])
|
||||
fn reduceIntersect(@previous, accum) {
|
||||
return intersect([previous, accum])
|
||||
}
|
||||
lastIndex = calculateArrayLength(solids) - 1
|
||||
lastSolid = solids[lastIndex]
|
||||
|
@ -19,7 +19,7 @@ gearHeight = 3
|
||||
cmo = 101
|
||||
rs = map(
|
||||
[0..cmo],
|
||||
f = fn(i) {
|
||||
f = fn(@i) {
|
||||
return baseDiameter / 2 + i / cmo * (tipDiameter - baseDiameter) / 2
|
||||
},
|
||||
)
|
||||
@ -27,7 +27,7 @@ rs = map(
|
||||
// Calculate operating pressure angle
|
||||
angles = map(
|
||||
rs,
|
||||
f = fn(r) {
|
||||
f = fn(@r) {
|
||||
return units::toDegrees(acos(baseDiameter / 2 / r))
|
||||
},
|
||||
)
|
||||
@ -35,7 +35,7 @@ angles = map(
|
||||
// Calculate the involute function
|
||||
invas = map(
|
||||
angles,
|
||||
f = fn(a) {
|
||||
f = fn(@a) {
|
||||
return tan(a) - units::toRadians(a)
|
||||
},
|
||||
)
|
||||
@ -43,14 +43,14 @@ invas = map(
|
||||
// Map the involute curve
|
||||
xs = map(
|
||||
[0..cmo],
|
||||
f = fn(i) {
|
||||
f = fn(@i) {
|
||||
return rs[i] * cos(invas[i]: number(rad))
|
||||
},
|
||||
)
|
||||
|
||||
ys = map(
|
||||
[0..cmo],
|
||||
f = fn(i) {
|
||||
f = fn(@i) {
|
||||
return rs[i] * sin(invas[i]: number(rad))
|
||||
},
|
||||
)
|
||||
@ -63,15 +63,15 @@ body = startSketchOn(XY)
|
||||
toothAngle = 360 / nTeeth / 1.5
|
||||
|
||||
// Plot the involute curve
|
||||
fn leftInvolute(i, sg) {
|
||||
fn leftInvolute(@i, accum) {
|
||||
j = 100 - i // iterate backwards
|
||||
return line(sg, endAbsolute = [xs[j], ys[j]])
|
||||
return line(accum, endAbsolute = [xs[j], ys[j]])
|
||||
}
|
||||
|
||||
fn rightInvolute(i, sg) {
|
||||
fn rightInvolute(@i, accum) {
|
||||
x = rs[i] * cos(-toothAngle + units::toDegrees(atan(ys[i] / xs[i])))
|
||||
y = -rs[i] * sin(-toothAngle + units::toDegrees(atan(ys[i] / xs[i])))
|
||||
return line(sg, endAbsolute = [x, y])
|
||||
return line(accum, endAbsolute = [x, y])
|
||||
}
|
||||
|
||||
// Draw gear teeth
|
||||
|
@ -4,293 +4,450 @@
|
||||
"pathFromProjectDirectoryToFirstFile": "80-20-rail/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "80/20 Rail",
|
||||
"description": "An 80/20 extruded aluminum linear rail. T-slot profile adjustable by profile height, rail length, and origin position"
|
||||
"description": "An 80/20 extruded aluminum linear rail. T-slot profile adjustable by profile height, rail length, and origin position",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "axial-fan/main.kcl",
|
||||
"multipleFiles": true,
|
||||
"title": "PC Fan",
|
||||
"description": "A small axial fan, used to push or draw airflow over components to remove excess heat"
|
||||
"description": "A small axial fan, used to push or draw airflow over components to remove excess heat",
|
||||
"files": [
|
||||
"fan-housing.kcl",
|
||||
"fan.kcl",
|
||||
"main.kcl",
|
||||
"motor.kcl",
|
||||
"parameters.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "ball-bearing/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Ball Bearing",
|
||||
"description": "A ball bearing is a type of rolling-element bearing that uses balls to maintain the separation between the bearing races. The primary purpose of a ball bearing is to reduce rotational friction and support radial and axial loads."
|
||||
"description": "A ball bearing is a type of rolling-element bearing that uses balls to maintain the separation between the bearing races. The primary purpose of a ball bearing is to reduce rotational friction and support radial and axial loads.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "bench/main.kcl",
|
||||
"multipleFiles": true,
|
||||
"title": "Bench",
|
||||
"description": "This is a slight remix of Depep1's original 3D Boaty (https://www.printables.com/model/1141963-3d-boaty). This is a tool used for benchmarking 3D FDM printers for bed adhesion, overhangs, bridging and top surface quality. The name of this file is a bit of misnomer, the shape of the object is a typical park bench."
|
||||
"description": "This is a slight remix of Depep1's original 3D Boaty (https://www.printables.com/model/1141963-3d-boaty). This is a tool used for benchmarking 3D FDM printers for bed adhesion, overhangs, bridging and top surface quality. The name of this file is a bit of misnomer, the shape of the object is a typical park bench.",
|
||||
"files": [
|
||||
"bench-parts.kcl",
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "bottle/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Bottle",
|
||||
"description": "A simple bottle with a hollow, watertight interior"
|
||||
"description": "A simple bottle with a hollow, watertight interior",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "bracket/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Shelf Bracket",
|
||||
"description": "This is a bracket that holds a shelf. It is made of aluminum and is designed to hold a force of 300 lbs. The bracket is 6 inches wide and the force is applied at the end of the shelf, 12 inches from the wall. The bracket has a factor of safety of 1.2. The legs of the bracket are 5 inches and 2 inches long. The thickness of the bracket is calculated from the constraints provided."
|
||||
"description": "This is a bracket that holds a shelf. It is made of aluminum and is designed to hold a force of 300 lbs. The bracket is 6 inches wide and the force is applied at the end of the shelf, 12 inches from the wall. The bracket has a factor of safety of 1.2. The legs of the bracket are 5 inches and 2 inches long. The thickness of the bracket is calculated from the constraints provided.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "car-wheel-assembly/main.kcl",
|
||||
"multipleFiles": true,
|
||||
"title": "Car Wheel Assembly",
|
||||
"description": "A car wheel assembly with a rotor, tire, and lug nuts."
|
||||
"description": "A car wheel assembly with a rotor, tire, and lug nuts.",
|
||||
"files": [
|
||||
"brake-caliper.kcl",
|
||||
"car-rotor.kcl",
|
||||
"car-tire.kcl",
|
||||
"car-wheel.kcl",
|
||||
"lug-nut.kcl",
|
||||
"main.kcl",
|
||||
"parameters.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "color-cube/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Color Cube",
|
||||
"description": "This is a color cube centered about the origin. It is used to help determine orientation in the scene."
|
||||
"description": "This is a color cube centered about the origin. It is used to help determine orientation in the scene.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "cycloidal-gear/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Cycloidal Gear",
|
||||
"description": "A cycloidal gear is a gear with a continuous, curved tooth profile. They are used in watchmaking and high precision robotics actuation"
|
||||
"description": "A cycloidal gear is a gear with a continuous, curved tooth profile. They are used in watchmaking and high precision robotics actuation",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "dodecahedron/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Dodecahedron",
|
||||
"description": "A regular dodecahedron or pentagonal dodecahedron is a dodecahedron composed of regular pentagonal faces, three meeting at each vertex. This example shows constructing the a dodecahedron with a series of intersects."
|
||||
"description": "A regular dodecahedron or pentagonal dodecahedron is a dodecahedron composed of regular pentagonal faces, three meeting at each vertex. This example shows constructing the a dodecahedron with a series of intersects.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "dual-basin-utility-sink/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Dual-Basin Utility Sink",
|
||||
"description": "A stainless steel sink unit with dual rectangular basins and six under-counter storage compartments."
|
||||
"description": "A stainless steel sink unit with dual rectangular basins and six under-counter storage compartments.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "enclosure/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Enclosure",
|
||||
"description": "An enclosure body and sealing lid for storing items"
|
||||
"description": "An enclosure body and sealing lid for storing items",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "exhaust-manifold/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Exhaust Manifold",
|
||||
"description": "A welded exhaust header for an inline 4-cylinder engine"
|
||||
"description": "A welded exhaust header for an inline 4-cylinder engine",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "flange/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Flange",
|
||||
"description": "A flange is a flat rim, collar, or rib, typically forged or cast, that is used to strengthen an object, guide it, or attach it to another object. Flanges are known for their use in various applications, including piping, plumbing, and mechanical engineering, among others."
|
||||
"description": "A flange is a flat rim, collar, or rib, typically forged or cast, that is used to strengthen an object, guide it, or attach it to another object. Flanges are known for their use in various applications, including piping, plumbing, and mechanical engineering, among others.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "focusrite-scarlett-mounting-bracket/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "A mounting bracket for the Focusrite Scarlett Solo audio interface",
|
||||
"description": "This is a bracket that holds an audio device underneath a desk or shelf. The audio device has dimensions of 144mm wide, 80mm length and 45mm depth with fillets of 6mm. This mounting bracket is designed to be 3D printed with PLA material"
|
||||
"description": "This is a bracket that holds an audio device underneath a desk or shelf. The audio device has dimensions of 144mm wide, 80mm length and 45mm depth with fillets of 6mm. This mounting bracket is designed to be 3D printed with PLA material",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "food-service-spatula/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Food Service Spatula",
|
||||
"description": "Use these spatulas for mixing, flipping, and scraping."
|
||||
"description": "Use these spatulas for mixing, flipping, and scraping.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "french-press/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "French Press",
|
||||
"description": "A french press immersion coffee maker"
|
||||
"description": "A french press immersion coffee maker",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "gear/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Spur Gear",
|
||||
"description": "A rotating machine part having cut teeth or, in the case of a cogwheel, inserted teeth (called cogs), which mesh with another toothed part to transmit torque. Geared devices can change the speed, torque, and direction of a power source. The two elements that define a gear are its circular shape and the teeth that are integrated into its outer edge, which are designed to fit into the teeth of another gear."
|
||||
"description": "A rotating machine part having cut teeth or, in the case of a cogwheel, inserted teeth (called cogs), which mesh with another toothed part to transmit torque. Geared devices can change the speed, torque, and direction of a power source. The two elements that define a gear are its circular shape and the teeth that are integrated into its outer edge, which are designed to fit into the teeth of another gear.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "gear-rack/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "100mm Gear Rack",
|
||||
"description": "A flat bar or rail that is engraved with teeth along its length. These teeth are designed to mesh with the teeth of a gear, known as a pinion. When the pinion, a small cylindrical gear, rotates, its teeth engage with the teeth on the rack, causing the rack to move linearly. Conversely, linear motion applied to the rack will cause the pinion to rotate."
|
||||
"description": "A flat bar or rail that is engraved with teeth along its length. These teeth are designed to mesh with the teeth of a gear, known as a pinion. When the pinion, a small cylindrical gear, rotates, its teeth engage with the teeth on the rack, causing the rack to move linearly. Conversely, linear motion applied to the rack will cause the pinion to rotate.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "gridfinity-baseplate/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Gridfinity Baseplate",
|
||||
"description": "Gridfinity is a system to help you work more efficiently. This is a system invented by Zack Freedman. There are two main components the baseplate and the bins. The components are comprised of a matrix of squares. Allowing easy stacking and expansion"
|
||||
"description": "Gridfinity is a system to help you work more efficiently. This is a system invented by Zack Freedman. There are two main components the baseplate and the bins. The components are comprised of a matrix of squares. Allowing easy stacking and expansion",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "gridfinity-baseplate-magnets/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Gridfinity Baseplate With Magnets",
|
||||
"description": "Gridfinity is a system to help you work more efficiently. This is a system invented by Zack Freedman. There are two main components the baseplate and the bins. The components are comprised of a matrix of squares. Allowing easy stacking and expansion. This baseplate version includes holes for magnet placement"
|
||||
"description": "Gridfinity is a system to help you work more efficiently. This is a system invented by Zack Freedman. There are two main components the baseplate and the bins. The components are comprised of a matrix of squares. Allowing easy stacking and expansion. This baseplate version includes holes for magnet placement",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "gridfinity-bins/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Gridfinity Bins",
|
||||
"description": "Gridfinity is a system to help you work more efficiently. This is a system invented by Zack Freedman. There are two main components the baseplate and the bins. The components are comprised of a matrix of squares. Allowing easy stacking and expansion"
|
||||
"description": "Gridfinity is a system to help you work more efficiently. This is a system invented by Zack Freedman. There are two main components the baseplate and the bins. The components are comprised of a matrix of squares. Allowing easy stacking and expansion",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "gridfinity-bins-stacking-lip/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Gridfinity Bins With A Stacking Lip",
|
||||
"description": "Gridfinity is a system to help you work more efficiently. This is a system invented by Zack Freedman. There are two main components the baseplate and the bins. The components are comprised of a matrix of squares. Allowing easy stacking and expansion. This Gridfinity bins version includes a lip to allowable stacking Gridfinity bins"
|
||||
"description": "Gridfinity is a system to help you work more efficiently. This is a system invented by Zack Freedman. There are two main components the baseplate and the bins. The components are comprised of a matrix of squares. Allowing easy stacking and expansion. This Gridfinity bins version includes a lip to allowable stacking Gridfinity bins",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "hex-nut/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Hex Nut",
|
||||
"description": "A hex nut is a type of fastener with a threaded hole and a hexagonal outer shape, used in a wide variety of applications to secure parts together. The hexagonal shape allows for a greater torque to be applied with wrenches or tools, making it one of the most common nut types in hardware."
|
||||
"description": "A hex nut is a type of fastener with a threaded hole and a hexagonal outer shape, used in a wide variety of applications to secure parts together. The hexagonal shape allows for a greater torque to be applied with wrenches or tools, making it one of the most common nut types in hardware.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "i-beam/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "I-beam",
|
||||
"description": "A structural metal beam with an I shaped cross section. Often used in construction and architecture"
|
||||
"description": "A structural metal beam with an I shaped cross section. Often used in construction and architecture",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "keyboard/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Zoo Keyboard",
|
||||
"description": "A custom keyboard with Zoo brand lettering"
|
||||
"description": "A custom keyboard with Zoo brand lettering",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "kitt/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Kitt",
|
||||
"description": "The beloved KittyCAD mascot in a voxelized style."
|
||||
"description": "The beloved KittyCAD mascot in a voxelized style.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "lego/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Lego Brick",
|
||||
"description": "A standard Lego brick. This is a small, plastic construction block toy that can be interlocked with other blocks to build various structures, models, and figures. There are a lot of hacks used in this code."
|
||||
"description": "A standard Lego brick. This is a small, plastic construction block toy that can be interlocked with other blocks to build various structures, models, and figures. There are a lot of hacks used in this code.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "makeup-mirror/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Makeup Mirror",
|
||||
"description": "A circular vanity mirror mounted on a swiveling arm with pivot joints, used for personal grooming."
|
||||
"description": "A circular vanity mirror mounted on a swiveling arm with pivot joints, used for personal grooming.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "mounting-plate/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Mounting Plate",
|
||||
"description": "A flat piece of material, often metal or plastic, that serves as a support or base for attaching, securing, or mounting various types of equipment, devices, or components."
|
||||
"description": "A flat piece of material, often metal or plastic, that serves as a support or base for attaching, securing, or mounting various types of equipment, devices, or components.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "multi-axis-robot/main.kcl",
|
||||
"multipleFiles": true,
|
||||
"title": "Robot Arm",
|
||||
"description": "A 4 axis robotic arm for industrial use. These machines can be used for assembly, packaging, organization of goods, and quality inspection processes"
|
||||
"description": "A 4 axis robotic arm for industrial use. These machines can be used for assembly, packaging, organization of goods, and quality inspection processes",
|
||||
"files": [
|
||||
"globals.kcl",
|
||||
"main.kcl",
|
||||
"robot-arm-base.kcl",
|
||||
"robot-arm-j2.kcl",
|
||||
"robot-arm-j3.kcl",
|
||||
"robot-rotating-base.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "parametric-bearing-pillow-block/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Parametric Bearing Pillow Block",
|
||||
"description": "A bearing pillow block, also known as a plummer block or pillow block bearing, is a pedestal used to provide support for a rotating shaft with the help of compatible bearings and various accessories. Housing a bearing, the pillow block provides a secure and stable foundation that allows the shaft to rotate smoothly within its machinery setup. These components are essential in a wide range of mechanical systems and machinery, playing a key role in reducing friction and supporting radial and axial loads."
|
||||
"description": "A bearing pillow block, also known as a plummer block or pillow block bearing, is a pedestal used to provide support for a rotating shaft with the help of compatible bearings and various accessories. Housing a bearing, the pillow block provides a secure and stable foundation that allows the shaft to rotate smoothly within its machinery setup. These components are essential in a wide range of mechanical systems and machinery, playing a key role in reducing friction and supporting radial and axial loads.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "pipe/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Pipe",
|
||||
"description": "Piping for the pipe flange assembly"
|
||||
"description": "Piping for the pipe flange assembly",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "pipe-flange-assembly/main.kcl",
|
||||
"multipleFiles": true,
|
||||
"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."
|
||||
"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.",
|
||||
"files": [
|
||||
"1120t74-pipe.kcl",
|
||||
"68095k348-flange.kcl",
|
||||
"91251a404-bolt.kcl",
|
||||
"9472k188-gasket.kcl",
|
||||
"95479a127-hex-nut.kcl",
|
||||
"98017a257-washer.kcl",
|
||||
"main.kcl",
|
||||
"parameters.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "pipe-with-bend/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"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."
|
||||
"description": "A tubular section or hollow cylinder, usually but not necessarily of circular cross-section, used mainly to convey substances that can flow.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "poopy-shoe/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Poopy Shoe",
|
||||
"description": "poop shute for bambu labs printer - optimized for printing."
|
||||
"description": "poop shute for bambu labs printer - optimized for printing.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "router-template-cross-bar/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Router template for a cross bar",
|
||||
"description": "A guide for routing a notch into a cross bar."
|
||||
"description": "A guide for routing a notch into a cross bar.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "router-template-slate/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Router Template for a Slate",
|
||||
"description": "A guide for routing a slate for a cross bar."
|
||||
"description": "A guide for routing a slate for a cross bar.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "sheet-metal-bracket/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Sheet Metal Bracket",
|
||||
"description": "A component typically made from flat sheet metal through various manufacturing processes such as bending, punching, cutting, and forming. These brackets are used to support, attach, or mount other hardware components, often providing a structural or functional base for assembly."
|
||||
"description": "A component typically made from flat sheet metal through various manufacturing processes such as bending, punching, cutting, and forming. These brackets are used to support, attach, or mount other hardware components, often providing a structural or functional base for assembly.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "socket-head-cap-screw/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Socket Head Cap Screw",
|
||||
"description": "This is for a #10-24 screw that is 1.00 inches long. A socket head cap screw is a type of fastener that is widely used in a variety of applications requiring a high strength fastening solution. It is characterized by its cylindrical head and internal hexagonal drive, which allows for tightening with an Allen wrench or hex key."
|
||||
"description": "This is for a #10-24 screw that is 1.00 inches long. A socket head cap screw is a type of fastener that is widely used in a variety of applications requiring a high strength fastening solution. It is characterized by its cylindrical head and internal hexagonal drive, which allows for tightening with an Allen wrench or hex key.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "walkie-talkie/main.kcl",
|
||||
"multipleFiles": true,
|
||||
"title": "Walkie Talkie",
|
||||
"description": "A portable, handheld two-way radio device that allows users to communicate wirelessly over short to medium distances. It operates on specific radio frequencies and features a push-to-talk button for transmitting messages, making it ideal for quick and reliable communication in outdoor, work, or emergency settings."
|
||||
"description": "A portable, handheld two-way radio device that allows users to communicate wirelessly over short to medium distances. It operates on specific radio frequencies and features a push-to-talk button for transmitting messages, making it ideal for quick and reliable communication in outdoor, work, or emergency settings.",
|
||||
"files": [
|
||||
"antenna.kcl",
|
||||
"body.kcl",
|
||||
"button.kcl",
|
||||
"case.kcl",
|
||||
"knob.kcl",
|
||||
"main.kcl",
|
||||
"parameters.kcl",
|
||||
"talk-button.kcl",
|
||||
"zoo-logo.kcl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "washer/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Washer",
|
||||
"description": "A small, typically disk-shaped component with a hole in the middle, used in a wide range of applications, primarily in conjunction with fasteners like bolts and screws. Washers distribute the load of a fastener across a broader area. This is especially important when the fastening surface is soft or uneven, as it helps to prevent damage to the surface and ensures the load is evenly distributed, reducing the risk of the fastener becoming loose over time."
|
||||
"description": "A small, typically disk-shaped component with a hole in the middle, used in a wide range of applications, primarily in conjunction with fasteners like bolts and screws. Washers distribute the load of a fastener across a broader area. This is especially important when the fastening surface is soft or uneven, as it helps to prevent damage to the surface and ensures the load is evenly distributed, reducing the risk of the fastener becoming loose over time.",
|
||||
"files": [
|
||||
"main.kcl"
|
||||
]
|
||||
}
|
||||
]
|
Binary file not shown.
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
@ -18,10 +18,10 @@ screenSketch = startSketchOn(XZ)
|
||||
|> close()
|
||||
|
||||
// Create transform functions for the speaker grid pattern
|
||||
fn transformX(i) {
|
||||
fn transformX(@i) {
|
||||
return { translate = [.125 * i, 0] }
|
||||
}
|
||||
fn transformY(i) {
|
||||
fn transformY(@i) {
|
||||
return { translate = [0, -.125 * i] }
|
||||
}
|
||||
|
||||
|
20
rust/Cargo.lock
generated
20
rust/Cargo.lock
generated
@ -1815,7 +1815,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-bumper"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1826,7 +1826,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-derive-docs"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"anyhow",
|
||||
@ -1845,7 +1845,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-directory-test-macro"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1854,7 +1854,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-language-server"
|
||||
version = "0.2.67"
|
||||
version = "0.2.68"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1875,7 +1875,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-language-server-release"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1895,7 +1895,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.2.67"
|
||||
version = "0.2.68"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx 0.5.1",
|
||||
@ -1970,7 +1970,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-python-bindings"
|
||||
version = "0.3.67"
|
||||
version = "0.3.68"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"kcl-lib",
|
||||
@ -1985,7 +1985,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-test-server"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"hyper 0.14.32",
|
||||
@ -1998,7 +1998,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-to-core"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -2012,7 +2012,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-wasm-lib"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bson",
|
||||
|
@ -4,9 +4,9 @@ kcl_lib_flags := "-p kcl-lib --features artifact-graph"
|
||||
|
||||
# Run the same lint checks we run in CI.
|
||||
lint:
|
||||
cargo clippy --workspace --all-targets --tests --all-features --examples --benches -- -D warnings
|
||||
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
# Ensure we can build without extra feature flags.
|
||||
cargo clippy -p kcl-lib --tests --examples --benches -- -D warnings
|
||||
cargo clippy -p kcl-lib --all-targets -- -D warnings
|
||||
|
||||
# Run the stdlib docs generation
|
||||
redo-kcl-stdlib-docs-no-imgs:
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
[package]
|
||||
name = "kcl-bumper"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/KittyCAD/modeling-api"
|
||||
rust-version = "1.76"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-derive-docs"
|
||||
description = "A tool for generating documentation from Rust derive macros"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-directory-test-macro"
|
||||
description = "A tool for generating tests from a directory of kcl files"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kcl-language-server-release"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
edition = "2021"
|
||||
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
publish = false
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "kcl-language-server"
|
||||
description = "A language server for KCL."
|
||||
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
version = "0.2.67"
|
||||
version = "0.2.68"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-lib"
|
||||
description = "KittyCAD Language implementation and tools"
|
||||
version = "0.2.67"
|
||||
version = "0.2.68"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -46,7 +46,7 @@ shellExtrude = startSketchOn(s, "start")
|
||||
|> close()
|
||||
|> extrude(length = -(height - t))
|
||||
|
||||
fn tr(i) {
|
||||
fn tr(@i) {
|
||||
j = i + 1
|
||||
x = (j/wbumps) * pitch
|
||||
y = (j % wbumps) * pitch
|
||||
|
@ -1324,7 +1324,7 @@ impl Node<CallExpressionKw> {
|
||||
},
|
||||
self.into(),
|
||||
ctx.clone(),
|
||||
exec_state.mod_local.pipe_value.clone().map(|v| Arg::new(v, callsite)),
|
||||
exec_state.pipe_value().map(|v| Arg::new(v.clone(), callsite)),
|
||||
);
|
||||
match ctx.stdlib.get_either(fn_name) {
|
||||
FunctionKind::Core(func) => {
|
||||
@ -1835,89 +1835,6 @@ impl Node<PipeExpression> {
|
||||
}
|
||||
}
|
||||
|
||||
/// For each argument given,
|
||||
/// assign it to a parameter of the function, in the given block of function memory.
|
||||
/// Returns Err if too few/too many arguments were given for the function.
|
||||
fn assign_args_to_params(
|
||||
function_expression: NodeRef<'_, FunctionExpression>,
|
||||
args: Vec<Arg>,
|
||||
exec_state: &mut ExecState,
|
||||
) -> Result<(), KclError> {
|
||||
let num_args = function_expression.number_of_args();
|
||||
let (min_params, max_params) = num_args.into_inner();
|
||||
let n = args.len();
|
||||
|
||||
// Check if the user supplied too many arguments
|
||||
// (we'll check for too few arguments below).
|
||||
let err_wrong_number_args = KclError::Semantic(KclErrorDetails {
|
||||
message: if min_params == max_params {
|
||||
format!("Expected {min_params} arguments, got {n}")
|
||||
} else {
|
||||
format!("Expected {min_params}-{max_params} arguments, got {n}")
|
||||
},
|
||||
source_ranges: vec![function_expression.into()],
|
||||
});
|
||||
if n > max_params {
|
||||
return Err(err_wrong_number_args);
|
||||
}
|
||||
|
||||
// Add the arguments to the memory. A new call frame should have already
|
||||
// been created.
|
||||
for (index, param) in function_expression.params.iter().enumerate() {
|
||||
if let Some(arg) = args.get(index) {
|
||||
// Argument was provided.
|
||||
|
||||
if let Some(ty) = ¶m.type_ {
|
||||
let value = arg
|
||||
.value
|
||||
.coerce(
|
||||
&RuntimeType::from_parsed(ty.inner.clone(), exec_state, arg.source_range).unwrap(),
|
||||
exec_state,
|
||||
)
|
||||
.map_err(|e| {
|
||||
let mut message = format!(
|
||||
"Argument requires a value with type `{}`, but found {}",
|
||||
ty.inner,
|
||||
arg.value.human_friendly_type(),
|
||||
);
|
||||
if let Some(ty) = e.explicit_coercion {
|
||||
// TODO if we have access to the AST for the argument we could choose which example to suggest.
|
||||
message = format!("{message}\n\nYou may need to add information about the type of the argument, for example:\n using a numeric suffix: `42{ty}`\n or using type ascription: `foo(): number({ty})`");
|
||||
}
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
message,
|
||||
source_ranges: vec![arg.source_range],
|
||||
})
|
||||
})?;
|
||||
exec_state
|
||||
.mut_stack()
|
||||
.add(param.identifier.name.clone(), value, (¶m.identifier).into())?;
|
||||
} else {
|
||||
exec_state.mut_stack().add(
|
||||
param.identifier.name.clone(),
|
||||
arg.value.clone(),
|
||||
(¶m.identifier).into(),
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
// Argument was not provided.
|
||||
if let Some(ref default_val) = param.default_value {
|
||||
// If the corresponding parameter is optional,
|
||||
// then it's fine, the user doesn't need to supply it.
|
||||
let value = KclValue::from_default_param(default_val.clone(), exec_state);
|
||||
exec_state
|
||||
.mut_stack()
|
||||
.add(param.identifier.name.clone(), value, (¶m.identifier).into())?;
|
||||
} else {
|
||||
// But if the corresponding parameter was required,
|
||||
// then the user has called with too few arguments.
|
||||
return Err(err_wrong_number_args);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn type_check_params_kw(
|
||||
fn_name: Option<&str>,
|
||||
function_expression: NodeRef<'_, FunctionExpression>,
|
||||
@ -2102,42 +2019,6 @@ fn coerce_result_type(
|
||||
}
|
||||
}
|
||||
|
||||
async fn call_user_defined_function(
|
||||
args: Vec<Arg>,
|
||||
memory: EnvironmentRef,
|
||||
function_expression: NodeRef<'_, FunctionExpression>,
|
||||
exec_state: &mut ExecState,
|
||||
ctx: &ExecutorContext,
|
||||
) -> Result<Option<KclValue>, KclError> {
|
||||
// Create a new environment to execute the function body in so that local
|
||||
// variables shadow variables in the parent scope. The new environment's
|
||||
// parent should be the environment of the closure.
|
||||
exec_state.mut_stack().push_new_env_for_call(memory);
|
||||
if let Err(e) = assign_args_to_params(function_expression, args, exec_state) {
|
||||
exec_state.mut_stack().pop_env();
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
// Execute the function body using the memory we just created.
|
||||
let result = ctx
|
||||
.exec_block(&function_expression.body, exec_state, BodyType::Block)
|
||||
.await;
|
||||
let mut result = result.map(|_| {
|
||||
exec_state
|
||||
.stack()
|
||||
.get(memory::RETURN_NAME, function_expression.as_source_range())
|
||||
.ok()
|
||||
.cloned()
|
||||
});
|
||||
|
||||
result = coerce_result_type(result, function_expression, exec_state);
|
||||
|
||||
// Restore the previous memory.
|
||||
exec_state.mut_stack().pop_env();
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
async fn call_user_defined_function_kw(
|
||||
fn_name: Option<&str>,
|
||||
args: crate::std::args::KwArgs,
|
||||
@ -2176,41 +2057,6 @@ async fn call_user_defined_function_kw(
|
||||
}
|
||||
|
||||
impl FunctionSource {
|
||||
pub async fn call(
|
||||
&self,
|
||||
fn_name: Option<String>,
|
||||
exec_state: &mut ExecState,
|
||||
ctx: &ExecutorContext,
|
||||
mut args: Vec<Arg>,
|
||||
callsite: SourceRange,
|
||||
) -> Result<Option<KclValue>, KclError> {
|
||||
match self {
|
||||
FunctionSource::Std { props, .. } => {
|
||||
if args.len() <= 1 {
|
||||
let args = crate::std::Args::new_kw(
|
||||
KwArgs {
|
||||
unlabeled: args.pop(),
|
||||
labeled: IndexMap::new(),
|
||||
},
|
||||
callsite,
|
||||
ctx.clone(),
|
||||
exec_state.mod_local.pipe_value.clone().map(|v| Arg::new(v, callsite)),
|
||||
);
|
||||
self.call_kw(fn_name, exec_state, ctx, args, callsite).await
|
||||
} else {
|
||||
Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("{} requires its arguments to be labelled", props.name),
|
||||
source_ranges: vec![callsite],
|
||||
}))
|
||||
}
|
||||
}
|
||||
FunctionSource::User { ast, memory, .. } => {
|
||||
call_user_defined_function(args, *memory, ast, exec_state, ctx).await
|
||||
}
|
||||
FunctionSource::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn call_kw(
|
||||
&self,
|
||||
fn_name: Option<String>,
|
||||
@ -2404,7 +2250,7 @@ mod test {
|
||||
(
|
||||
"all params required, and all given, should be OK",
|
||||
vec![req_param("x")],
|
||||
vec![mem(1)],
|
||||
vec![("x", mem(1))],
|
||||
Ok(additional_program_memory(&[("x".to_owned(), mem(1))])),
|
||||
),
|
||||
(
|
||||
@ -2413,7 +2259,7 @@ mod test {
|
||||
vec![],
|
||||
Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![SourceRange::default()],
|
||||
message: "Expected 1 arguments, got 0".to_owned(),
|
||||
message: "This function requires a parameter x, but you haven't passed it one.".to_owned(),
|
||||
})),
|
||||
),
|
||||
(
|
||||
@ -2428,13 +2274,13 @@ mod test {
|
||||
vec![],
|
||||
Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![SourceRange::default()],
|
||||
message: "Expected 1-2 arguments, got 0".to_owned(),
|
||||
message: "This function requires a parameter x, but you haven't passed it one.".to_owned(),
|
||||
})),
|
||||
),
|
||||
(
|
||||
"mixed params, minimum given, should be OK",
|
||||
vec![req_param("x"), opt_param("y")],
|
||||
vec![mem(1)],
|
||||
vec![("x", mem(1))],
|
||||
Ok(additional_program_memory(&[
|
||||
("x".to_owned(), mem(1)),
|
||||
("y".to_owned(), KclValue::none()),
|
||||
@ -2443,21 +2289,12 @@ mod test {
|
||||
(
|
||||
"mixed params, maximum given, should be OK",
|
||||
vec![req_param("x"), opt_param("y")],
|
||||
vec![mem(1), mem(2)],
|
||||
vec![("x", mem(1)), ("y", mem(2))],
|
||||
Ok(additional_program_memory(&[
|
||||
("x".to_owned(), mem(1)),
|
||||
("y".to_owned(), mem(2)),
|
||||
])),
|
||||
),
|
||||
(
|
||||
"mixed params, too many given",
|
||||
vec![req_param("x"), opt_param("y")],
|
||||
vec![mem(1), mem(2), mem(3)],
|
||||
Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![SourceRange::default()],
|
||||
message: "Expected 1-2 arguments, got 3".to_owned(),
|
||||
})),
|
||||
),
|
||||
] {
|
||||
// Run each test.
|
||||
let func_expr = &Node::no_src(FunctionExpression {
|
||||
@ -2466,7 +2303,17 @@ mod test {
|
||||
return_type: None,
|
||||
digest: None,
|
||||
});
|
||||
let args = args.into_iter().map(Arg::synthetic).collect();
|
||||
let labeled = args
|
||||
.iter()
|
||||
.map(|(name, value)| {
|
||||
let arg = Arg::new(value.clone(), SourceRange::default());
|
||||
((*name).to_owned(), arg)
|
||||
})
|
||||
.collect::<IndexMap<_, _>>();
|
||||
let args = KwArgs {
|
||||
unlabeled: None,
|
||||
labeled,
|
||||
};
|
||||
let exec_ctxt = ExecutorContext {
|
||||
engine: Arc::new(Box::new(
|
||||
crate::engine::conn_mock::EngineConnection::new().await.unwrap(),
|
||||
@ -2478,7 +2325,8 @@ mod test {
|
||||
};
|
||||
let mut exec_state = ExecState::new(&exec_ctxt);
|
||||
exec_state.mod_local.stack = Stack::new_for_tests();
|
||||
let actual = assign_args_to_params(func_expr, args, &mut exec_state).map(|_| exec_state.mod_local.stack);
|
||||
let actual =
|
||||
assign_args_to_params_kw(None, func_expr, args, &mut exec_state).map(|_| exec_state.mod_local.stack);
|
||||
assert_eq!(
|
||||
actual, expected,
|
||||
"failed test '{test_name}':\ngot {actual:?}\nbut expected\n{expected:?}"
|
||||
|
@ -307,7 +307,7 @@ impl KclValue {
|
||||
} => "number(Angle)",
|
||||
KclValue::Number { .. } => "number",
|
||||
KclValue::String { .. } => "string (text)",
|
||||
KclValue::MixedArray { .. } => "array (list)",
|
||||
KclValue::MixedArray { .. } => "mixed array (list)",
|
||||
KclValue::HomArray { .. } => "array (list)",
|
||||
KclValue::Object { .. } => "object",
|
||||
KclValue::Module { .. } => "module",
|
||||
|
@ -1741,7 +1741,7 @@ foo
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_pattern_transform_function_cannot_access_future_definitions() {
|
||||
let ast = r#"
|
||||
fn transform(replicaId) {
|
||||
fn transform(@replicaId) {
|
||||
// x shouldn't be defined yet.
|
||||
scale = x
|
||||
return {
|
||||
@ -1932,7 +1932,7 @@ a = []
|
||||
notArray = !a";
|
||||
assert_eq!(
|
||||
parse_execute(code5).await.unwrap_err().message(),
|
||||
"Cannot apply unary operator ! to non-boolean value: array (list)",
|
||||
"Cannot apply unary operator ! to non-boolean value: mixed array (list)",
|
||||
);
|
||||
|
||||
let code6 = "
|
||||
|
@ -283,6 +283,10 @@ impl ExecState {
|
||||
source_ranges: vec![source_range],
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn pipe_value(&self) -> Option<&KclValue> {
|
||||
self.mod_local.pipe_value.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl GlobalState {
|
||||
|
@ -220,6 +220,7 @@ struct KclMetadata {
|
||||
multiple_files: bool,
|
||||
title: String,
|
||||
description: String,
|
||||
files: Vec<String>,
|
||||
}
|
||||
|
||||
// Function to read and parse .kcl files
|
||||
@ -263,12 +264,16 @@ fn get_kcl_metadata(project_path: &Path, files: &[String]) -> Option<KclMetadata
|
||||
primary_kcl_file.clone()
|
||||
};
|
||||
|
||||
let mut files = files.to_vec();
|
||||
files.sort();
|
||||
|
||||
Some(KclMetadata {
|
||||
file: primary_kcl_file,
|
||||
path_from_project_directory_to_first_file: path_from_project_dir,
|
||||
multiple_files: files.len() > 1,
|
||||
title,
|
||||
description,
|
||||
files,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
use indexmap::IndexMap;
|
||||
use kcl_derive_docs::stdlib;
|
||||
|
||||
use super::{args::Arg, Args};
|
||||
use super::{
|
||||
args::{Arg, KwArgs},
|
||||
Args,
|
||||
};
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{
|
||||
@ -44,7 +48,7 @@ pub async fn map(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
||||
/// // Call `map`, using an anonymous function instead of a named one.
|
||||
/// circles = map(
|
||||
/// [1..3],
|
||||
/// f = fn(id) {
|
||||
/// f = fn(@id) {
|
||||
/// return startSketchOn(XY)
|
||||
/// |> circle( center= [id * 2 * r, 0], radius= r)
|
||||
/// }
|
||||
@ -81,9 +85,17 @@ async fn call_map_closure(
|
||||
exec_state: &mut ExecState,
|
||||
ctxt: &ExecutorContext,
|
||||
) -> Result<KclValue, KclError> {
|
||||
let output = map_fn
|
||||
.call(None, exec_state, ctxt, vec![Arg::synthetic(input)], source_range)
|
||||
.await?;
|
||||
let kw_args = KwArgs {
|
||||
unlabeled: Some(Arg::new(input, source_range)),
|
||||
labeled: Default::default(),
|
||||
};
|
||||
let args = Args::new_kw(
|
||||
kw_args,
|
||||
source_range,
|
||||
ctxt.clone(),
|
||||
exec_state.pipe_value().map(|v| Arg::new(v.clone(), source_range)),
|
||||
);
|
||||
let output = map_fn.call_kw(None, exec_state, ctxt, args, source_range).await?;
|
||||
let source_ranges = vec![source_range];
|
||||
let output = output.ok_or_else(|| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
@ -106,7 +118,7 @@ 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, accum) { return a + accum }
|
||||
///
|
||||
/// // This function adds an array of numbers.
|
||||
/// // It uses the `reduce` function, to call the `add` function on every
|
||||
@ -118,7 +130,7 @@ pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// fn sum(arr):
|
||||
/// sumSoFar = 0
|
||||
/// for i in arr:
|
||||
/// sumSoFar = add(sumSoFar, i)
|
||||
/// sumSoFar = add(i, sumSoFar)
|
||||
/// return sumSoFar
|
||||
/// */
|
||||
///
|
||||
@ -131,7 +143,7 @@ pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// // an anonymous `add` function as its parameter, instead of declaring a
|
||||
/// // named function outside.
|
||||
/// arr = [1, 2, 3]
|
||||
/// sum = reduce(arr, initial = 0, f = fn (i, result_so_far) { return i + result_so_far })
|
||||
/// sum = reduce(arr, initial = 0, f = fn (@i, accum) { return i + accum })
|
||||
///
|
||||
/// // We use `assert` to check that our `sum` function gives the
|
||||
/// // expected result. It's good to check your work!
|
||||
@ -150,11 +162,11 @@ pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// // Use a `reduce` to draw the remaining decagon sides.
|
||||
/// // For each number in the array 1..10, run the given function,
|
||||
/// // which takes a partially-sketched decagon and adds one more edge to it.
|
||||
/// fullDecagon = reduce([1..10], initial = startOfDecagonSketch, f = fn(i, partialDecagon) {
|
||||
/// fullDecagon = reduce([1..10], initial = startOfDecagonSketch, f = fn(@i, accum) {
|
||||
/// // Draw one edge of the decagon.
|
||||
/// x = cos(stepAngle * i) * radius
|
||||
/// y = sin(stepAngle * i) * radius
|
||||
/// return line(partialDecagon, end = [x, y])
|
||||
/// return line(accum, end = [x, y])
|
||||
/// })
|
||||
///
|
||||
/// return fullDecagon
|
||||
@ -209,16 +221,27 @@ async fn inner_reduce<'a>(
|
||||
|
||||
async fn call_reduce_closure(
|
||||
elem: KclValue,
|
||||
start: KclValue,
|
||||
accum: KclValue,
|
||||
reduce_fn: &FunctionSource,
|
||||
source_range: SourceRange,
|
||||
exec_state: &mut ExecState,
|
||||
ctxt: &ExecutorContext,
|
||||
) -> Result<KclValue, KclError> {
|
||||
// Call the reduce fn for this repetition.
|
||||
let reduce_fn_args = vec![Arg::synthetic(elem), Arg::synthetic(start)];
|
||||
let mut labeled = IndexMap::with_capacity(1);
|
||||
labeled.insert("accum".to_string(), Arg::new(accum, source_range));
|
||||
let kw_args = KwArgs {
|
||||
unlabeled: Some(Arg::new(elem, source_range)),
|
||||
labeled,
|
||||
};
|
||||
let reduce_fn_args = Args::new_kw(
|
||||
kw_args,
|
||||
source_range,
|
||||
ctxt.clone(),
|
||||
exec_state.pipe_value().map(|v| Arg::new(v.clone(), source_range)),
|
||||
);
|
||||
let transform_fn_return = reduce_fn
|
||||
.call(None, exec_state, ctxt, reduce_fn_args, source_range)
|
||||
.call_kw(None, exec_state, ctxt, reduce_fn_args, source_range)
|
||||
.await?;
|
||||
|
||||
// Unpack the returned transform object.
|
||||
|
@ -16,7 +16,7 @@ use serde::Serialize;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{
|
||||
args::Arg,
|
||||
args::{Arg, KwArgs},
|
||||
utils::{point_3d_to_mm, point_to_mm},
|
||||
};
|
||||
use crate::{
|
||||
@ -427,9 +427,18 @@ async fn make_transform<T: GeometryTrait>(
|
||||
ty: NumericType::count(),
|
||||
meta: vec![source_range.into()],
|
||||
};
|
||||
let transform_fn_args = vec![Arg::synthetic(repetition_num)];
|
||||
let kw_args = KwArgs {
|
||||
unlabeled: Some(Arg::new(repetition_num, source_range)),
|
||||
labeled: Default::default(),
|
||||
};
|
||||
let transform_fn_args = Args::new_kw(
|
||||
kw_args,
|
||||
source_range,
|
||||
ctxt.clone(),
|
||||
exec_state.pipe_value().map(|v| Arg::new(v.clone(), source_range)),
|
||||
);
|
||||
let transform_fn_return = transform
|
||||
.call(None, exec_state, ctxt, transform_fn_args, source_range)
|
||||
.call_kw(None, exec_state, ctxt, transform_fn_args, source_range)
|
||||
.await?;
|
||||
|
||||
// Unpack the returned transform object.
|
||||
|
@ -2532,7 +2532,7 @@ sketch002 = startSketchOn({
|
||||
let input = r#"squares_out = reduce(
|
||||
arr,
|
||||
n = 0: number,
|
||||
f = fn(i, squares) {
|
||||
f = fn(@i, accum) {
|
||||
return 1
|
||||
},
|
||||
)
|
||||
|
@ -1,5 +1,150 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed double_map_fn.kcl
|
||||
---
|
||||
[]
|
||||
[
|
||||
{
|
||||
"type": "GroupBegin",
|
||||
"group": {
|
||||
"type": "FunctionCall",
|
||||
"name": null,
|
||||
"functionSourceRange": [],
|
||||
"unlabeledArg": {
|
||||
"value": {
|
||||
"type": "Number",
|
||||
"value": 0.0,
|
||||
"ty": {
|
||||
"type": "Known",
|
||||
"type": "Count"
|
||||
}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
"labeledArgs": {}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
{
|
||||
"type": "GroupBegin",
|
||||
"group": {
|
||||
"type": "FunctionCall",
|
||||
"name": null,
|
||||
"functionSourceRange": [],
|
||||
"unlabeledArg": {
|
||||
"value": {
|
||||
"type": "Number",
|
||||
"value": 1.0,
|
||||
"ty": {
|
||||
"type": "Known",
|
||||
"type": "Count"
|
||||
}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
"labeledArgs": {}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
{
|
||||
"type": "GroupBegin",
|
||||
"group": {
|
||||
"type": "FunctionCall",
|
||||
"name": null,
|
||||
"functionSourceRange": [],
|
||||
"unlabeledArg": {
|
||||
"value": {
|
||||
"type": "Number",
|
||||
"value": 2.0,
|
||||
"ty": {
|
||||
"type": "Known",
|
||||
"type": "Count"
|
||||
}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
"labeledArgs": {}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
{
|
||||
"type": "GroupBegin",
|
||||
"group": {
|
||||
"type": "FunctionCall",
|
||||
"name": null,
|
||||
"functionSourceRange": [],
|
||||
"unlabeledArg": {
|
||||
"value": {
|
||||
"type": "Number",
|
||||
"value": 1.0,
|
||||
"ty": {
|
||||
"type": "Known",
|
||||
"type": "Count"
|
||||
}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
"labeledArgs": {}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
{
|
||||
"type": "GroupBegin",
|
||||
"group": {
|
||||
"type": "FunctionCall",
|
||||
"name": null,
|
||||
"functionSourceRange": [],
|
||||
"unlabeledArg": {
|
||||
"value": {
|
||||
"type": "Number",
|
||||
"value": 2.0,
|
||||
"ty": {
|
||||
"type": "Known",
|
||||
"type": "Count"
|
||||
}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
"labeledArgs": {}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
{
|
||||
"type": "GroupBegin",
|
||||
"group": {
|
||||
"type": "FunctionCall",
|
||||
"name": null,
|
||||
"functionSourceRange": [],
|
||||
"unlabeledArg": {
|
||||
"value": {
|
||||
"type": "Number",
|
||||
"value": 3.0,
|
||||
"ty": {
|
||||
"type": "Known",
|
||||
"type": "Count"
|
||||
}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
"labeledArgs": {}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
{
|
||||
"type": "GroupEnd"
|
||||
},
|
||||
{
|
||||
"type": "GroupEnd"
|
||||
},
|
||||
{
|
||||
"type": "GroupEnd"
|
||||
},
|
||||
{
|
||||
"type": "GroupEnd"
|
||||
},
|
||||
{
|
||||
"type": "GroupEnd"
|
||||
},
|
||||
{
|
||||
"type": "GroupEnd"
|
||||
}
|
||||
]
|
||||
|
@ -1,235 +1,235 @@
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph path5 [Path]
|
||||
5["Path<br>[1091, 1141, 0]"]
|
||||
8["Segment<br>[1091, 1141, 0]"]
|
||||
5["Path<br>[1096, 1146, 0]"]
|
||||
8["Segment<br>[1096, 1146, 0]"]
|
||||
220[Solid2d]
|
||||
end
|
||||
subgraph path6 [Path]
|
||||
6["Path<br>[1610, 1647, 0]"]
|
||||
9["Segment<br>[1306, 1344, 0]"]
|
||||
10["Segment<br>[1306, 1344, 0]"]
|
||||
11["Segment<br>[1306, 1344, 0]"]
|
||||
12["Segment<br>[1306, 1344, 0]"]
|
||||
13["Segment<br>[1306, 1344, 0]"]
|
||||
14["Segment<br>[1306, 1344, 0]"]
|
||||
15["Segment<br>[1306, 1344, 0]"]
|
||||
16["Segment<br>[1306, 1344, 0]"]
|
||||
17["Segment<br>[1306, 1344, 0]"]
|
||||
18["Segment<br>[1306, 1344, 0]"]
|
||||
19["Segment<br>[1306, 1344, 0]"]
|
||||
20["Segment<br>[1306, 1344, 0]"]
|
||||
21["Segment<br>[1306, 1344, 0]"]
|
||||
22["Segment<br>[1306, 1344, 0]"]
|
||||
23["Segment<br>[1306, 1344, 0]"]
|
||||
24["Segment<br>[1306, 1344, 0]"]
|
||||
25["Segment<br>[1306, 1344, 0]"]
|
||||
26["Segment<br>[1306, 1344, 0]"]
|
||||
27["Segment<br>[1306, 1344, 0]"]
|
||||
28["Segment<br>[1306, 1344, 0]"]
|
||||
29["Segment<br>[1306, 1344, 0]"]
|
||||
30["Segment<br>[1306, 1344, 0]"]
|
||||
31["Segment<br>[1306, 1344, 0]"]
|
||||
32["Segment<br>[1306, 1344, 0]"]
|
||||
33["Segment<br>[1306, 1344, 0]"]
|
||||
34["Segment<br>[1306, 1344, 0]"]
|
||||
35["Segment<br>[1306, 1344, 0]"]
|
||||
36["Segment<br>[1306, 1344, 0]"]
|
||||
37["Segment<br>[1306, 1344, 0]"]
|
||||
38["Segment<br>[1306, 1344, 0]"]
|
||||
39["Segment<br>[1306, 1344, 0]"]
|
||||
40["Segment<br>[1306, 1344, 0]"]
|
||||
41["Segment<br>[1306, 1344, 0]"]
|
||||
42["Segment<br>[1306, 1344, 0]"]
|
||||
43["Segment<br>[1306, 1344, 0]"]
|
||||
44["Segment<br>[1306, 1344, 0]"]
|
||||
45["Segment<br>[1306, 1344, 0]"]
|
||||
46["Segment<br>[1306, 1344, 0]"]
|
||||
47["Segment<br>[1306, 1344, 0]"]
|
||||
48["Segment<br>[1306, 1344, 0]"]
|
||||
49["Segment<br>[1306, 1344, 0]"]
|
||||
50["Segment<br>[1306, 1344, 0]"]
|
||||
51["Segment<br>[1306, 1344, 0]"]
|
||||
52["Segment<br>[1306, 1344, 0]"]
|
||||
53["Segment<br>[1306, 1344, 0]"]
|
||||
54["Segment<br>[1306, 1344, 0]"]
|
||||
55["Segment<br>[1306, 1344, 0]"]
|
||||
56["Segment<br>[1306, 1344, 0]"]
|
||||
57["Segment<br>[1306, 1344, 0]"]
|
||||
58["Segment<br>[1306, 1344, 0]"]
|
||||
59["Segment<br>[1306, 1344, 0]"]
|
||||
60["Segment<br>[1306, 1344, 0]"]
|
||||
61["Segment<br>[1306, 1344, 0]"]
|
||||
62["Segment<br>[1306, 1344, 0]"]
|
||||
63["Segment<br>[1306, 1344, 0]"]
|
||||
64["Segment<br>[1306, 1344, 0]"]
|
||||
65["Segment<br>[1306, 1344, 0]"]
|
||||
66["Segment<br>[1306, 1344, 0]"]
|
||||
67["Segment<br>[1306, 1344, 0]"]
|
||||
68["Segment<br>[1306, 1344, 0]"]
|
||||
69["Segment<br>[1306, 1344, 0]"]
|
||||
70["Segment<br>[1306, 1344, 0]"]
|
||||
71["Segment<br>[1306, 1344, 0]"]
|
||||
72["Segment<br>[1306, 1344, 0]"]
|
||||
73["Segment<br>[1306, 1344, 0]"]
|
||||
74["Segment<br>[1306, 1344, 0]"]
|
||||
75["Segment<br>[1306, 1344, 0]"]
|
||||
76["Segment<br>[1306, 1344, 0]"]
|
||||
77["Segment<br>[1306, 1344, 0]"]
|
||||
78["Segment<br>[1306, 1344, 0]"]
|
||||
79["Segment<br>[1306, 1344, 0]"]
|
||||
80["Segment<br>[1306, 1344, 0]"]
|
||||
81["Segment<br>[1306, 1344, 0]"]
|
||||
82["Segment<br>[1306, 1344, 0]"]
|
||||
83["Segment<br>[1306, 1344, 0]"]
|
||||
84["Segment<br>[1306, 1344, 0]"]
|
||||
85["Segment<br>[1306, 1344, 0]"]
|
||||
86["Segment<br>[1306, 1344, 0]"]
|
||||
87["Segment<br>[1306, 1344, 0]"]
|
||||
88["Segment<br>[1306, 1344, 0]"]
|
||||
89["Segment<br>[1306, 1344, 0]"]
|
||||
90["Segment<br>[1306, 1344, 0]"]
|
||||
91["Segment<br>[1306, 1344, 0]"]
|
||||
92["Segment<br>[1306, 1344, 0]"]
|
||||
93["Segment<br>[1306, 1344, 0]"]
|
||||
94["Segment<br>[1306, 1344, 0]"]
|
||||
95["Segment<br>[1306, 1344, 0]"]
|
||||
96["Segment<br>[1306, 1344, 0]"]
|
||||
97["Segment<br>[1306, 1344, 0]"]
|
||||
98["Segment<br>[1306, 1344, 0]"]
|
||||
99["Segment<br>[1306, 1344, 0]"]
|
||||
100["Segment<br>[1306, 1344, 0]"]
|
||||
101["Segment<br>[1306, 1344, 0]"]
|
||||
102["Segment<br>[1306, 1344, 0]"]
|
||||
103["Segment<br>[1306, 1344, 0]"]
|
||||
104["Segment<br>[1306, 1344, 0]"]
|
||||
105["Segment<br>[1306, 1344, 0]"]
|
||||
106["Segment<br>[1306, 1344, 0]"]
|
||||
107["Segment<br>[1306, 1344, 0]"]
|
||||
108["Segment<br>[1306, 1344, 0]"]
|
||||
109["Segment<br>[1306, 1344, 0]"]
|
||||
110["Segment<br>[1526, 1556, 0]"]
|
||||
111["Segment<br>[1526, 1556, 0]"]
|
||||
112["Segment<br>[1526, 1556, 0]"]
|
||||
113["Segment<br>[1526, 1556, 0]"]
|
||||
114["Segment<br>[1526, 1556, 0]"]
|
||||
115["Segment<br>[1526, 1556, 0]"]
|
||||
116["Segment<br>[1526, 1556, 0]"]
|
||||
117["Segment<br>[1526, 1556, 0]"]
|
||||
118["Segment<br>[1526, 1556, 0]"]
|
||||
119["Segment<br>[1526, 1556, 0]"]
|
||||
120["Segment<br>[1526, 1556, 0]"]
|
||||
121["Segment<br>[1526, 1556, 0]"]
|
||||
122["Segment<br>[1526, 1556, 0]"]
|
||||
123["Segment<br>[1526, 1556, 0]"]
|
||||
124["Segment<br>[1526, 1556, 0]"]
|
||||
125["Segment<br>[1526, 1556, 0]"]
|
||||
126["Segment<br>[1526, 1556, 0]"]
|
||||
127["Segment<br>[1526, 1556, 0]"]
|
||||
128["Segment<br>[1526, 1556, 0]"]
|
||||
129["Segment<br>[1526, 1556, 0]"]
|
||||
130["Segment<br>[1526, 1556, 0]"]
|
||||
131["Segment<br>[1526, 1556, 0]"]
|
||||
132["Segment<br>[1526, 1556, 0]"]
|
||||
133["Segment<br>[1526, 1556, 0]"]
|
||||
134["Segment<br>[1526, 1556, 0]"]
|
||||
135["Segment<br>[1526, 1556, 0]"]
|
||||
136["Segment<br>[1526, 1556, 0]"]
|
||||
137["Segment<br>[1526, 1556, 0]"]
|
||||
138["Segment<br>[1526, 1556, 0]"]
|
||||
139["Segment<br>[1526, 1556, 0]"]
|
||||
140["Segment<br>[1526, 1556, 0]"]
|
||||
141["Segment<br>[1526, 1556, 0]"]
|
||||
142["Segment<br>[1526, 1556, 0]"]
|
||||
143["Segment<br>[1526, 1556, 0]"]
|
||||
144["Segment<br>[1526, 1556, 0]"]
|
||||
145["Segment<br>[1526, 1556, 0]"]
|
||||
146["Segment<br>[1526, 1556, 0]"]
|
||||
147["Segment<br>[1526, 1556, 0]"]
|
||||
148["Segment<br>[1526, 1556, 0]"]
|
||||
149["Segment<br>[1526, 1556, 0]"]
|
||||
150["Segment<br>[1526, 1556, 0]"]
|
||||
151["Segment<br>[1526, 1556, 0]"]
|
||||
152["Segment<br>[1526, 1556, 0]"]
|
||||
153["Segment<br>[1526, 1556, 0]"]
|
||||
154["Segment<br>[1526, 1556, 0]"]
|
||||
155["Segment<br>[1526, 1556, 0]"]
|
||||
156["Segment<br>[1526, 1556, 0]"]
|
||||
157["Segment<br>[1526, 1556, 0]"]
|
||||
158["Segment<br>[1526, 1556, 0]"]
|
||||
159["Segment<br>[1526, 1556, 0]"]
|
||||
160["Segment<br>[1526, 1556, 0]"]
|
||||
161["Segment<br>[1526, 1556, 0]"]
|
||||
162["Segment<br>[1526, 1556, 0]"]
|
||||
163["Segment<br>[1526, 1556, 0]"]
|
||||
164["Segment<br>[1526, 1556, 0]"]
|
||||
165["Segment<br>[1526, 1556, 0]"]
|
||||
166["Segment<br>[1526, 1556, 0]"]
|
||||
167["Segment<br>[1526, 1556, 0]"]
|
||||
168["Segment<br>[1526, 1556, 0]"]
|
||||
169["Segment<br>[1526, 1556, 0]"]
|
||||
170["Segment<br>[1526, 1556, 0]"]
|
||||
171["Segment<br>[1526, 1556, 0]"]
|
||||
172["Segment<br>[1526, 1556, 0]"]
|
||||
173["Segment<br>[1526, 1556, 0]"]
|
||||
174["Segment<br>[1526, 1556, 0]"]
|
||||
175["Segment<br>[1526, 1556, 0]"]
|
||||
176["Segment<br>[1526, 1556, 0]"]
|
||||
177["Segment<br>[1526, 1556, 0]"]
|
||||
178["Segment<br>[1526, 1556, 0]"]
|
||||
179["Segment<br>[1526, 1556, 0]"]
|
||||
180["Segment<br>[1526, 1556, 0]"]
|
||||
181["Segment<br>[1526, 1556, 0]"]
|
||||
182["Segment<br>[1526, 1556, 0]"]
|
||||
183["Segment<br>[1526, 1556, 0]"]
|
||||
184["Segment<br>[1526, 1556, 0]"]
|
||||
185["Segment<br>[1526, 1556, 0]"]
|
||||
186["Segment<br>[1526, 1556, 0]"]
|
||||
187["Segment<br>[1526, 1556, 0]"]
|
||||
188["Segment<br>[1526, 1556, 0]"]
|
||||
189["Segment<br>[1526, 1556, 0]"]
|
||||
190["Segment<br>[1526, 1556, 0]"]
|
||||
191["Segment<br>[1526, 1556, 0]"]
|
||||
192["Segment<br>[1526, 1556, 0]"]
|
||||
193["Segment<br>[1526, 1556, 0]"]
|
||||
194["Segment<br>[1526, 1556, 0]"]
|
||||
195["Segment<br>[1526, 1556, 0]"]
|
||||
196["Segment<br>[1526, 1556, 0]"]
|
||||
197["Segment<br>[1526, 1556, 0]"]
|
||||
198["Segment<br>[1526, 1556, 0]"]
|
||||
199["Segment<br>[1526, 1556, 0]"]
|
||||
200["Segment<br>[1526, 1556, 0]"]
|
||||
201["Segment<br>[1526, 1556, 0]"]
|
||||
202["Segment<br>[1526, 1556, 0]"]
|
||||
203["Segment<br>[1526, 1556, 0]"]
|
||||
204["Segment<br>[1526, 1556, 0]"]
|
||||
205["Segment<br>[1526, 1556, 0]"]
|
||||
206["Segment<br>[1526, 1556, 0]"]
|
||||
207["Segment<br>[1526, 1556, 0]"]
|
||||
208["Segment<br>[1526, 1556, 0]"]
|
||||
209["Segment<br>[1526, 1556, 0]"]
|
||||
210["Segment<br>[1526, 1556, 0]"]
|
||||
211["Segment<br>[1713, 1811, 0]"]
|
||||
212["Segment<br>[1871, 1878, 0]"]
|
||||
6["Path<br>[1629, 1666, 0]"]
|
||||
9["Segment<br>[1315, 1356, 0]"]
|
||||
10["Segment<br>[1315, 1356, 0]"]
|
||||
11["Segment<br>[1315, 1356, 0]"]
|
||||
12["Segment<br>[1315, 1356, 0]"]
|
||||
13["Segment<br>[1315, 1356, 0]"]
|
||||
14["Segment<br>[1315, 1356, 0]"]
|
||||
15["Segment<br>[1315, 1356, 0]"]
|
||||
16["Segment<br>[1315, 1356, 0]"]
|
||||
17["Segment<br>[1315, 1356, 0]"]
|
||||
18["Segment<br>[1315, 1356, 0]"]
|
||||
19["Segment<br>[1315, 1356, 0]"]
|
||||
20["Segment<br>[1315, 1356, 0]"]
|
||||
21["Segment<br>[1315, 1356, 0]"]
|
||||
22["Segment<br>[1315, 1356, 0]"]
|
||||
23["Segment<br>[1315, 1356, 0]"]
|
||||
24["Segment<br>[1315, 1356, 0]"]
|
||||
25["Segment<br>[1315, 1356, 0]"]
|
||||
26["Segment<br>[1315, 1356, 0]"]
|
||||
27["Segment<br>[1315, 1356, 0]"]
|
||||
28["Segment<br>[1315, 1356, 0]"]
|
||||
29["Segment<br>[1315, 1356, 0]"]
|
||||
30["Segment<br>[1315, 1356, 0]"]
|
||||
31["Segment<br>[1315, 1356, 0]"]
|
||||
32["Segment<br>[1315, 1356, 0]"]
|
||||
33["Segment<br>[1315, 1356, 0]"]
|
||||
34["Segment<br>[1315, 1356, 0]"]
|
||||
35["Segment<br>[1315, 1356, 0]"]
|
||||
36["Segment<br>[1315, 1356, 0]"]
|
||||
37["Segment<br>[1315, 1356, 0]"]
|
||||
38["Segment<br>[1315, 1356, 0]"]
|
||||
39["Segment<br>[1315, 1356, 0]"]
|
||||
40["Segment<br>[1315, 1356, 0]"]
|
||||
41["Segment<br>[1315, 1356, 0]"]
|
||||
42["Segment<br>[1315, 1356, 0]"]
|
||||
43["Segment<br>[1315, 1356, 0]"]
|
||||
44["Segment<br>[1315, 1356, 0]"]
|
||||
45["Segment<br>[1315, 1356, 0]"]
|
||||
46["Segment<br>[1315, 1356, 0]"]
|
||||
47["Segment<br>[1315, 1356, 0]"]
|
||||
48["Segment<br>[1315, 1356, 0]"]
|
||||
49["Segment<br>[1315, 1356, 0]"]
|
||||
50["Segment<br>[1315, 1356, 0]"]
|
||||
51["Segment<br>[1315, 1356, 0]"]
|
||||
52["Segment<br>[1315, 1356, 0]"]
|
||||
53["Segment<br>[1315, 1356, 0]"]
|
||||
54["Segment<br>[1315, 1356, 0]"]
|
||||
55["Segment<br>[1315, 1356, 0]"]
|
||||
56["Segment<br>[1315, 1356, 0]"]
|
||||
57["Segment<br>[1315, 1356, 0]"]
|
||||
58["Segment<br>[1315, 1356, 0]"]
|
||||
59["Segment<br>[1315, 1356, 0]"]
|
||||
60["Segment<br>[1315, 1356, 0]"]
|
||||
61["Segment<br>[1315, 1356, 0]"]
|
||||
62["Segment<br>[1315, 1356, 0]"]
|
||||
63["Segment<br>[1315, 1356, 0]"]
|
||||
64["Segment<br>[1315, 1356, 0]"]
|
||||
65["Segment<br>[1315, 1356, 0]"]
|
||||
66["Segment<br>[1315, 1356, 0]"]
|
||||
67["Segment<br>[1315, 1356, 0]"]
|
||||
68["Segment<br>[1315, 1356, 0]"]
|
||||
69["Segment<br>[1315, 1356, 0]"]
|
||||
70["Segment<br>[1315, 1356, 0]"]
|
||||
71["Segment<br>[1315, 1356, 0]"]
|
||||
72["Segment<br>[1315, 1356, 0]"]
|
||||
73["Segment<br>[1315, 1356, 0]"]
|
||||
74["Segment<br>[1315, 1356, 0]"]
|
||||
75["Segment<br>[1315, 1356, 0]"]
|
||||
76["Segment<br>[1315, 1356, 0]"]
|
||||
77["Segment<br>[1315, 1356, 0]"]
|
||||
78["Segment<br>[1315, 1356, 0]"]
|
||||
79["Segment<br>[1315, 1356, 0]"]
|
||||
80["Segment<br>[1315, 1356, 0]"]
|
||||
81["Segment<br>[1315, 1356, 0]"]
|
||||
82["Segment<br>[1315, 1356, 0]"]
|
||||
83["Segment<br>[1315, 1356, 0]"]
|
||||
84["Segment<br>[1315, 1356, 0]"]
|
||||
85["Segment<br>[1315, 1356, 0]"]
|
||||
86["Segment<br>[1315, 1356, 0]"]
|
||||
87["Segment<br>[1315, 1356, 0]"]
|
||||
88["Segment<br>[1315, 1356, 0]"]
|
||||
89["Segment<br>[1315, 1356, 0]"]
|
||||
90["Segment<br>[1315, 1356, 0]"]
|
||||
91["Segment<br>[1315, 1356, 0]"]
|
||||
92["Segment<br>[1315, 1356, 0]"]
|
||||
93["Segment<br>[1315, 1356, 0]"]
|
||||
94["Segment<br>[1315, 1356, 0]"]
|
||||
95["Segment<br>[1315, 1356, 0]"]
|
||||
96["Segment<br>[1315, 1356, 0]"]
|
||||
97["Segment<br>[1315, 1356, 0]"]
|
||||
98["Segment<br>[1315, 1356, 0]"]
|
||||
99["Segment<br>[1315, 1356, 0]"]
|
||||
100["Segment<br>[1315, 1356, 0]"]
|
||||
101["Segment<br>[1315, 1356, 0]"]
|
||||
102["Segment<br>[1315, 1356, 0]"]
|
||||
103["Segment<br>[1315, 1356, 0]"]
|
||||
104["Segment<br>[1315, 1356, 0]"]
|
||||
105["Segment<br>[1315, 1356, 0]"]
|
||||
106["Segment<br>[1315, 1356, 0]"]
|
||||
107["Segment<br>[1315, 1356, 0]"]
|
||||
108["Segment<br>[1315, 1356, 0]"]
|
||||
109["Segment<br>[1315, 1356, 0]"]
|
||||
110["Segment<br>[1542, 1575, 0]"]
|
||||
111["Segment<br>[1542, 1575, 0]"]
|
||||
112["Segment<br>[1542, 1575, 0]"]
|
||||
113["Segment<br>[1542, 1575, 0]"]
|
||||
114["Segment<br>[1542, 1575, 0]"]
|
||||
115["Segment<br>[1542, 1575, 0]"]
|
||||
116["Segment<br>[1542, 1575, 0]"]
|
||||
117["Segment<br>[1542, 1575, 0]"]
|
||||
118["Segment<br>[1542, 1575, 0]"]
|
||||
119["Segment<br>[1542, 1575, 0]"]
|
||||
120["Segment<br>[1542, 1575, 0]"]
|
||||
121["Segment<br>[1542, 1575, 0]"]
|
||||
122["Segment<br>[1542, 1575, 0]"]
|
||||
123["Segment<br>[1542, 1575, 0]"]
|
||||
124["Segment<br>[1542, 1575, 0]"]
|
||||
125["Segment<br>[1542, 1575, 0]"]
|
||||
126["Segment<br>[1542, 1575, 0]"]
|
||||
127["Segment<br>[1542, 1575, 0]"]
|
||||
128["Segment<br>[1542, 1575, 0]"]
|
||||
129["Segment<br>[1542, 1575, 0]"]
|
||||
130["Segment<br>[1542, 1575, 0]"]
|
||||
131["Segment<br>[1542, 1575, 0]"]
|
||||
132["Segment<br>[1542, 1575, 0]"]
|
||||
133["Segment<br>[1542, 1575, 0]"]
|
||||
134["Segment<br>[1542, 1575, 0]"]
|
||||
135["Segment<br>[1542, 1575, 0]"]
|
||||
136["Segment<br>[1542, 1575, 0]"]
|
||||
137["Segment<br>[1542, 1575, 0]"]
|
||||
138["Segment<br>[1542, 1575, 0]"]
|
||||
139["Segment<br>[1542, 1575, 0]"]
|
||||
140["Segment<br>[1542, 1575, 0]"]
|
||||
141["Segment<br>[1542, 1575, 0]"]
|
||||
142["Segment<br>[1542, 1575, 0]"]
|
||||
143["Segment<br>[1542, 1575, 0]"]
|
||||
144["Segment<br>[1542, 1575, 0]"]
|
||||
145["Segment<br>[1542, 1575, 0]"]
|
||||
146["Segment<br>[1542, 1575, 0]"]
|
||||
147["Segment<br>[1542, 1575, 0]"]
|
||||
148["Segment<br>[1542, 1575, 0]"]
|
||||
149["Segment<br>[1542, 1575, 0]"]
|
||||
150["Segment<br>[1542, 1575, 0]"]
|
||||
151["Segment<br>[1542, 1575, 0]"]
|
||||
152["Segment<br>[1542, 1575, 0]"]
|
||||
153["Segment<br>[1542, 1575, 0]"]
|
||||
154["Segment<br>[1542, 1575, 0]"]
|
||||
155["Segment<br>[1542, 1575, 0]"]
|
||||
156["Segment<br>[1542, 1575, 0]"]
|
||||
157["Segment<br>[1542, 1575, 0]"]
|
||||
158["Segment<br>[1542, 1575, 0]"]
|
||||
159["Segment<br>[1542, 1575, 0]"]
|
||||
160["Segment<br>[1542, 1575, 0]"]
|
||||
161["Segment<br>[1542, 1575, 0]"]
|
||||
162["Segment<br>[1542, 1575, 0]"]
|
||||
163["Segment<br>[1542, 1575, 0]"]
|
||||
164["Segment<br>[1542, 1575, 0]"]
|
||||
165["Segment<br>[1542, 1575, 0]"]
|
||||
166["Segment<br>[1542, 1575, 0]"]
|
||||
167["Segment<br>[1542, 1575, 0]"]
|
||||
168["Segment<br>[1542, 1575, 0]"]
|
||||
169["Segment<br>[1542, 1575, 0]"]
|
||||
170["Segment<br>[1542, 1575, 0]"]
|
||||
171["Segment<br>[1542, 1575, 0]"]
|
||||
172["Segment<br>[1542, 1575, 0]"]
|
||||
173["Segment<br>[1542, 1575, 0]"]
|
||||
174["Segment<br>[1542, 1575, 0]"]
|
||||
175["Segment<br>[1542, 1575, 0]"]
|
||||
176["Segment<br>[1542, 1575, 0]"]
|
||||
177["Segment<br>[1542, 1575, 0]"]
|
||||
178["Segment<br>[1542, 1575, 0]"]
|
||||
179["Segment<br>[1542, 1575, 0]"]
|
||||
180["Segment<br>[1542, 1575, 0]"]
|
||||
181["Segment<br>[1542, 1575, 0]"]
|
||||
182["Segment<br>[1542, 1575, 0]"]
|
||||
183["Segment<br>[1542, 1575, 0]"]
|
||||
184["Segment<br>[1542, 1575, 0]"]
|
||||
185["Segment<br>[1542, 1575, 0]"]
|
||||
186["Segment<br>[1542, 1575, 0]"]
|
||||
187["Segment<br>[1542, 1575, 0]"]
|
||||
188["Segment<br>[1542, 1575, 0]"]
|
||||
189["Segment<br>[1542, 1575, 0]"]
|
||||
190["Segment<br>[1542, 1575, 0]"]
|
||||
191["Segment<br>[1542, 1575, 0]"]
|
||||
192["Segment<br>[1542, 1575, 0]"]
|
||||
193["Segment<br>[1542, 1575, 0]"]
|
||||
194["Segment<br>[1542, 1575, 0]"]
|
||||
195["Segment<br>[1542, 1575, 0]"]
|
||||
196["Segment<br>[1542, 1575, 0]"]
|
||||
197["Segment<br>[1542, 1575, 0]"]
|
||||
198["Segment<br>[1542, 1575, 0]"]
|
||||
199["Segment<br>[1542, 1575, 0]"]
|
||||
200["Segment<br>[1542, 1575, 0]"]
|
||||
201["Segment<br>[1542, 1575, 0]"]
|
||||
202["Segment<br>[1542, 1575, 0]"]
|
||||
203["Segment<br>[1542, 1575, 0]"]
|
||||
204["Segment<br>[1542, 1575, 0]"]
|
||||
205["Segment<br>[1542, 1575, 0]"]
|
||||
206["Segment<br>[1542, 1575, 0]"]
|
||||
207["Segment<br>[1542, 1575, 0]"]
|
||||
208["Segment<br>[1542, 1575, 0]"]
|
||||
209["Segment<br>[1542, 1575, 0]"]
|
||||
210["Segment<br>[1542, 1575, 0]"]
|
||||
211["Segment<br>[1732, 1830, 0]"]
|
||||
212["Segment<br>[1890, 1897, 0]"]
|
||||
219[Solid2d]
|
||||
end
|
||||
subgraph path7 [Path]
|
||||
7["Path<br>[2359, 2438, 0]"]
|
||||
213["Segment<br>[2444, 2471, 0]"]
|
||||
214["Segment<br>[2477, 2505, 0]"]
|
||||
215["Segment<br>[2511, 2539, 0]"]
|
||||
216["Segment<br>[2545, 2668, 0]"]
|
||||
217["Segment<br>[2674, 2786, 0]"]
|
||||
218["Segment<br>[2792, 2799, 0]"]
|
||||
7["Path<br>[2378, 2457, 0]"]
|
||||
213["Segment<br>[2463, 2490, 0]"]
|
||||
214["Segment<br>[2496, 2524, 0]"]
|
||||
215["Segment<br>[2530, 2558, 0]"]
|
||||
216["Segment<br>[2564, 2687, 0]"]
|
||||
217["Segment<br>[2693, 2805, 0]"]
|
||||
218["Segment<br>[2811, 2818, 0]"]
|
||||
221[Solid2d]
|
||||
end
|
||||
1["Plane<br>[168, 185, 0]"]
|
||||
2["Plane<br>[1068, 1085, 0]"]
|
||||
3["Plane<br>[1587, 1604, 0]"]
|
||||
4["StartSketchOnFace<br>[2322, 2353, 0]"]
|
||||
222["Sweep Extrusion<br>[1147, 1175, 0]"]
|
||||
223["Sweep Extrusion<br>[1884, 1912, 0]"]
|
||||
224["Sweep Extrusion<br>[2805, 2834, 0]"]
|
||||
2["Plane<br>[1073, 1090, 0]"]
|
||||
3["Plane<br>[1606, 1623, 0]"]
|
||||
4["StartSketchOnFace<br>[2341, 2372, 0]"]
|
||||
222["Sweep Extrusion<br>[1152, 1180, 0]"]
|
||||
223["Sweep Extrusion<br>[1903, 1931, 0]"]
|
||||
224["Sweep Extrusion<br>[2824, 2853, 0]"]
|
||||
225[Wall]
|
||||
226[Wall]
|
||||
227[Wall]
|
||||
|
@ -857,7 +857,8 @@ description: Result of parsing import_async.kcl
|
||||
"name": "i",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
}
|
||||
],
|
||||
"start": 0,
|
||||
@ -1093,7 +1094,8 @@ description: Result of parsing import_async.kcl
|
||||
"name": "r",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
}
|
||||
],
|
||||
"start": 0,
|
||||
@ -1324,7 +1326,8 @@ description: Result of parsing import_async.kcl
|
||||
"name": "a",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
}
|
||||
],
|
||||
"start": 0,
|
||||
@ -1526,7 +1529,8 @@ description: Result of parsing import_async.kcl
|
||||
"name": "i",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
}
|
||||
],
|
||||
"start": 0,
|
||||
@ -1748,7 +1752,8 @@ description: Result of parsing import_async.kcl
|
||||
"name": "i",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
}
|
||||
],
|
||||
"start": 0,
|
||||
@ -2308,7 +2313,7 @@ description: Result of parsing import_async.kcl
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "sg",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
@ -2358,14 +2363,15 @@ description: Result of parsing import_async.kcl
|
||||
"name": "i",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
},
|
||||
{
|
||||
"type": "Parameter",
|
||||
"identifier": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "sg",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
@ -2924,7 +2930,7 @@ description: Result of parsing import_async.kcl
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "sg",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
@ -2956,14 +2962,15 @@ description: Result of parsing import_async.kcl
|
||||
"name": "i",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
},
|
||||
{
|
||||
"type": "Parameter",
|
||||
"identifier": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "sg",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
|
@ -22,26 +22,26 @@ gearHeight = 3
|
||||
|
||||
// Interpolate points along the involute curve
|
||||
cmo = 101
|
||||
rs = map([0..cmo], f = fn(i) {
|
||||
rs = map([0..cmo], f = fn(@i) {
|
||||
return baseDiameter / 2 + i / cmo * (tipDiameter - baseDiameter) / 2
|
||||
})
|
||||
|
||||
// Calculate operating pressure angle
|
||||
angles = map(rs, f = fn(r) {
|
||||
angles = map(rs, f = fn(@r) {
|
||||
return units::toDegrees( acos(baseDiameter / 2 / r))
|
||||
})
|
||||
|
||||
// Calculate the involute function
|
||||
invas = map(angles, f = fn(a) {
|
||||
invas = map(angles, f = fn(@a) {
|
||||
return tan(units::toRadians(a)) - units::toRadians(a)
|
||||
})
|
||||
|
||||
// Map the involute curve
|
||||
xs = map([0..cmo], f = fn(i) {
|
||||
xs = map([0..cmo], f = fn(@i) {
|
||||
return rs[i] * cos(invas[i]: number(rad))
|
||||
})
|
||||
|
||||
ys = map([0..cmo], f = fn(i) {
|
||||
ys = map([0..cmo], f = fn(@i) {
|
||||
return rs[i] * sin(invas[i]: number(rad))
|
||||
})
|
||||
|
||||
@ -53,15 +53,15 @@ body = startSketchOn(XY)
|
||||
toothAngle = 360 / nTeeth / 1.5
|
||||
|
||||
// Plot the involute curve
|
||||
fn leftInvolute(i, sg) {
|
||||
fn leftInvolute(@i, accum) {
|
||||
j = 100 - i // iterate backwards
|
||||
return line(sg, endAbsolute = [xs[j], ys[j]])
|
||||
return line(accum, endAbsolute = [xs[j], ys[j]])
|
||||
}
|
||||
|
||||
fn rightInvolute(i, sg) {
|
||||
fn rightInvolute(@i, accum) {
|
||||
x = rs[i] * cos(-toothAngle + units::toDegrees(atan(ys[i] / xs[i])))
|
||||
y = -rs[i] * sin(-toothAngle + units::toDegrees(atan(ys[i] / xs[i])))
|
||||
return line(sg, endAbsolute = [x, y])
|
||||
return line(accum, endAbsolute = [x, y])
|
||||
}
|
||||
|
||||
// Draw gear teeth
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,7 @@ gearHeight = 3
|
||||
cmo = 101
|
||||
rs = map(
|
||||
[0..cmo],
|
||||
f = fn(i) {
|
||||
f = fn(@i) {
|
||||
return baseDiameter / 2 + i / cmo * (tipDiameter - baseDiameter) / 2
|
||||
},
|
||||
)
|
||||
@ -35,7 +35,7 @@ rs = map(
|
||||
// Calculate operating pressure angle
|
||||
angles = map(
|
||||
rs,
|
||||
f = fn(r) {
|
||||
f = fn(@r) {
|
||||
return units::toDegrees(acos(baseDiameter / 2 / r))
|
||||
},
|
||||
)
|
||||
@ -43,7 +43,7 @@ angles = map(
|
||||
// Calculate the involute function
|
||||
invas = map(
|
||||
angles,
|
||||
f = fn(a) {
|
||||
f = fn(@a) {
|
||||
return tan(units::toRadians(a)) - units::toRadians(a)
|
||||
},
|
||||
)
|
||||
@ -51,14 +51,14 @@ invas = map(
|
||||
// Map the involute curve
|
||||
xs = map(
|
||||
[0..cmo],
|
||||
f = fn(i) {
|
||||
f = fn(@i) {
|
||||
return rs[i] * cos(invas[i]: number(rad))
|
||||
},
|
||||
)
|
||||
|
||||
ys = map(
|
||||
[0..cmo],
|
||||
f = fn(i) {
|
||||
f = fn(@i) {
|
||||
return rs[i] * sin(invas[i]: number(rad))
|
||||
},
|
||||
)
|
||||
@ -71,15 +71,15 @@ body = startSketchOn(XY)
|
||||
toothAngle = 360 / nTeeth / 1.5
|
||||
|
||||
// Plot the involute curve
|
||||
fn leftInvolute(i, sg) {
|
||||
fn leftInvolute(@i, accum) {
|
||||
j = 100 - i // iterate backwards
|
||||
return line(sg, endAbsolute = [xs[j], ys[j]])
|
||||
return line(accum, endAbsolute = [xs[j], ys[j]])
|
||||
}
|
||||
|
||||
fn rightInvolute(i, sg) {
|
||||
fn rightInvolute(@i, accum) {
|
||||
x = rs[i] * cos(-toothAngle + units::toDegrees(atan(ys[i] / xs[i])))
|
||||
y = -rs[i] * sin(-toothAngle + units::toDegrees(atan(ys[i] / xs[i])))
|
||||
return line(sg, endAbsolute = [x, y])
|
||||
return line(accum, endAbsolute = [x, y])
|
||||
}
|
||||
|
||||
// Draw gear teeth
|
||||
|
@ -120,17 +120,17 @@ flowchart LR
|
||||
94["Sweep Extrusion<br>[771, 821, 0]"]
|
||||
95["Sweep Extrusion<br>[771, 821, 0]"]
|
||||
96["Sweep Extrusion<br>[771, 821, 0]"]
|
||||
97["CompositeSolid Intersect<br>[2018, 2048, 0]"]
|
||||
98["CompositeSolid Intersect<br>[2018, 2048, 0]"]
|
||||
99["CompositeSolid Intersect<br>[2018, 2048, 0]"]
|
||||
100["CompositeSolid Intersect<br>[2018, 2048, 0]"]
|
||||
101["CompositeSolid Intersect<br>[2018, 2048, 0]"]
|
||||
102["CompositeSolid Intersect<br>[2018, 2048, 0]"]
|
||||
103["CompositeSolid Intersect<br>[2018, 2048, 0]"]
|
||||
104["CompositeSolid Intersect<br>[2018, 2048, 0]"]
|
||||
105["CompositeSolid Intersect<br>[2018, 2048, 0]"]
|
||||
106["CompositeSolid Intersect<br>[2018, 2048, 0]"]
|
||||
107["CompositeSolid Intersect<br>[2018, 2048, 0]"]
|
||||
97["CompositeSolid Intersect<br>[2007, 2035, 0]"]
|
||||
98["CompositeSolid Intersect<br>[2007, 2035, 0]"]
|
||||
99["CompositeSolid Intersect<br>[2007, 2035, 0]"]
|
||||
100["CompositeSolid Intersect<br>[2007, 2035, 0]"]
|
||||
101["CompositeSolid Intersect<br>[2007, 2035, 0]"]
|
||||
102["CompositeSolid Intersect<br>[2007, 2035, 0]"]
|
||||
103["CompositeSolid Intersect<br>[2007, 2035, 0]"]
|
||||
104["CompositeSolid Intersect<br>[2007, 2035, 0]"]
|
||||
105["CompositeSolid Intersect<br>[2007, 2035, 0]"]
|
||||
106["CompositeSolid Intersect<br>[2007, 2035, 0]"]
|
||||
107["CompositeSolid Intersect<br>[2007, 2035, 0]"]
|
||||
108[Wall]
|
||||
109[Wall]
|
||||
110[Wall]
|
||||
|
@ -2249,7 +2249,8 @@ description: Result of parsing dodecahedron.kcl
|
||||
"name": "rotation",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
}
|
||||
],
|
||||
"start": 0,
|
||||
@ -2372,7 +2373,7 @@ description: Result of parsing dodecahedron.kcl
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "accumulator",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
@ -2420,14 +2421,15 @@ description: Result of parsing dodecahedron.kcl
|
||||
"name": "item",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
},
|
||||
{
|
||||
"type": "Parameter",
|
||||
"identifier": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "accumulator",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
@ -2593,7 +2595,7 @@ description: Result of parsing dodecahedron.kcl
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "current",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
@ -2631,14 +2633,15 @@ description: Result of parsing dodecahedron.kcl
|
||||
"name": "previous",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
},
|
||||
{
|
||||
"type": "Parameter",
|
||||
"identifier": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "current",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,234 +1,234 @@
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph path4 [Path]
|
||||
4["Path<br>[1431, 1481, 0]"]
|
||||
7["Segment<br>[1431, 1481, 0]"]
|
||||
4["Path<br>[1436, 1486, 0]"]
|
||||
7["Segment<br>[1436, 1486, 0]"]
|
||||
219[Solid2d]
|
||||
end
|
||||
subgraph path5 [Path]
|
||||
5["Path<br>[1950, 1987, 0]"]
|
||||
8["Segment<br>[1646, 1684, 0]"]
|
||||
9["Segment<br>[1646, 1684, 0]"]
|
||||
10["Segment<br>[1646, 1684, 0]"]
|
||||
11["Segment<br>[1646, 1684, 0]"]
|
||||
12["Segment<br>[1646, 1684, 0]"]
|
||||
13["Segment<br>[1646, 1684, 0]"]
|
||||
14["Segment<br>[1646, 1684, 0]"]
|
||||
15["Segment<br>[1646, 1684, 0]"]
|
||||
16["Segment<br>[1646, 1684, 0]"]
|
||||
17["Segment<br>[1646, 1684, 0]"]
|
||||
18["Segment<br>[1646, 1684, 0]"]
|
||||
19["Segment<br>[1646, 1684, 0]"]
|
||||
20["Segment<br>[1646, 1684, 0]"]
|
||||
21["Segment<br>[1646, 1684, 0]"]
|
||||
22["Segment<br>[1646, 1684, 0]"]
|
||||
23["Segment<br>[1646, 1684, 0]"]
|
||||
24["Segment<br>[1646, 1684, 0]"]
|
||||
25["Segment<br>[1646, 1684, 0]"]
|
||||
26["Segment<br>[1646, 1684, 0]"]
|
||||
27["Segment<br>[1646, 1684, 0]"]
|
||||
28["Segment<br>[1646, 1684, 0]"]
|
||||
29["Segment<br>[1646, 1684, 0]"]
|
||||
30["Segment<br>[1646, 1684, 0]"]
|
||||
31["Segment<br>[1646, 1684, 0]"]
|
||||
32["Segment<br>[1646, 1684, 0]"]
|
||||
33["Segment<br>[1646, 1684, 0]"]
|
||||
34["Segment<br>[1646, 1684, 0]"]
|
||||
35["Segment<br>[1646, 1684, 0]"]
|
||||
36["Segment<br>[1646, 1684, 0]"]
|
||||
37["Segment<br>[1646, 1684, 0]"]
|
||||
38["Segment<br>[1646, 1684, 0]"]
|
||||
39["Segment<br>[1646, 1684, 0]"]
|
||||
40["Segment<br>[1646, 1684, 0]"]
|
||||
41["Segment<br>[1646, 1684, 0]"]
|
||||
42["Segment<br>[1646, 1684, 0]"]
|
||||
43["Segment<br>[1646, 1684, 0]"]
|
||||
44["Segment<br>[1646, 1684, 0]"]
|
||||
45["Segment<br>[1646, 1684, 0]"]
|
||||
46["Segment<br>[1646, 1684, 0]"]
|
||||
47["Segment<br>[1646, 1684, 0]"]
|
||||
48["Segment<br>[1646, 1684, 0]"]
|
||||
49["Segment<br>[1646, 1684, 0]"]
|
||||
50["Segment<br>[1646, 1684, 0]"]
|
||||
51["Segment<br>[1646, 1684, 0]"]
|
||||
52["Segment<br>[1646, 1684, 0]"]
|
||||
53["Segment<br>[1646, 1684, 0]"]
|
||||
54["Segment<br>[1646, 1684, 0]"]
|
||||
55["Segment<br>[1646, 1684, 0]"]
|
||||
56["Segment<br>[1646, 1684, 0]"]
|
||||
57["Segment<br>[1646, 1684, 0]"]
|
||||
58["Segment<br>[1646, 1684, 0]"]
|
||||
59["Segment<br>[1646, 1684, 0]"]
|
||||
60["Segment<br>[1646, 1684, 0]"]
|
||||
61["Segment<br>[1646, 1684, 0]"]
|
||||
62["Segment<br>[1646, 1684, 0]"]
|
||||
63["Segment<br>[1646, 1684, 0]"]
|
||||
64["Segment<br>[1646, 1684, 0]"]
|
||||
65["Segment<br>[1646, 1684, 0]"]
|
||||
66["Segment<br>[1646, 1684, 0]"]
|
||||
67["Segment<br>[1646, 1684, 0]"]
|
||||
68["Segment<br>[1646, 1684, 0]"]
|
||||
69["Segment<br>[1646, 1684, 0]"]
|
||||
70["Segment<br>[1646, 1684, 0]"]
|
||||
71["Segment<br>[1646, 1684, 0]"]
|
||||
72["Segment<br>[1646, 1684, 0]"]
|
||||
73["Segment<br>[1646, 1684, 0]"]
|
||||
74["Segment<br>[1646, 1684, 0]"]
|
||||
75["Segment<br>[1646, 1684, 0]"]
|
||||
76["Segment<br>[1646, 1684, 0]"]
|
||||
77["Segment<br>[1646, 1684, 0]"]
|
||||
78["Segment<br>[1646, 1684, 0]"]
|
||||
79["Segment<br>[1646, 1684, 0]"]
|
||||
80["Segment<br>[1646, 1684, 0]"]
|
||||
81["Segment<br>[1646, 1684, 0]"]
|
||||
82["Segment<br>[1646, 1684, 0]"]
|
||||
83["Segment<br>[1646, 1684, 0]"]
|
||||
84["Segment<br>[1646, 1684, 0]"]
|
||||
85["Segment<br>[1646, 1684, 0]"]
|
||||
86["Segment<br>[1646, 1684, 0]"]
|
||||
87["Segment<br>[1646, 1684, 0]"]
|
||||
88["Segment<br>[1646, 1684, 0]"]
|
||||
89["Segment<br>[1646, 1684, 0]"]
|
||||
90["Segment<br>[1646, 1684, 0]"]
|
||||
91["Segment<br>[1646, 1684, 0]"]
|
||||
92["Segment<br>[1646, 1684, 0]"]
|
||||
93["Segment<br>[1646, 1684, 0]"]
|
||||
94["Segment<br>[1646, 1684, 0]"]
|
||||
95["Segment<br>[1646, 1684, 0]"]
|
||||
96["Segment<br>[1646, 1684, 0]"]
|
||||
97["Segment<br>[1646, 1684, 0]"]
|
||||
98["Segment<br>[1646, 1684, 0]"]
|
||||
99["Segment<br>[1646, 1684, 0]"]
|
||||
100["Segment<br>[1646, 1684, 0]"]
|
||||
101["Segment<br>[1646, 1684, 0]"]
|
||||
102["Segment<br>[1646, 1684, 0]"]
|
||||
103["Segment<br>[1646, 1684, 0]"]
|
||||
104["Segment<br>[1646, 1684, 0]"]
|
||||
105["Segment<br>[1646, 1684, 0]"]
|
||||
106["Segment<br>[1646, 1684, 0]"]
|
||||
107["Segment<br>[1646, 1684, 0]"]
|
||||
108["Segment<br>[1646, 1684, 0]"]
|
||||
109["Segment<br>[1866, 1896, 0]"]
|
||||
110["Segment<br>[1866, 1896, 0]"]
|
||||
111["Segment<br>[1866, 1896, 0]"]
|
||||
112["Segment<br>[1866, 1896, 0]"]
|
||||
113["Segment<br>[1866, 1896, 0]"]
|
||||
114["Segment<br>[1866, 1896, 0]"]
|
||||
115["Segment<br>[1866, 1896, 0]"]
|
||||
116["Segment<br>[1866, 1896, 0]"]
|
||||
117["Segment<br>[1866, 1896, 0]"]
|
||||
118["Segment<br>[1866, 1896, 0]"]
|
||||
119["Segment<br>[1866, 1896, 0]"]
|
||||
120["Segment<br>[1866, 1896, 0]"]
|
||||
121["Segment<br>[1866, 1896, 0]"]
|
||||
122["Segment<br>[1866, 1896, 0]"]
|
||||
123["Segment<br>[1866, 1896, 0]"]
|
||||
124["Segment<br>[1866, 1896, 0]"]
|
||||
125["Segment<br>[1866, 1896, 0]"]
|
||||
126["Segment<br>[1866, 1896, 0]"]
|
||||
127["Segment<br>[1866, 1896, 0]"]
|
||||
128["Segment<br>[1866, 1896, 0]"]
|
||||
129["Segment<br>[1866, 1896, 0]"]
|
||||
130["Segment<br>[1866, 1896, 0]"]
|
||||
131["Segment<br>[1866, 1896, 0]"]
|
||||
132["Segment<br>[1866, 1896, 0]"]
|
||||
133["Segment<br>[1866, 1896, 0]"]
|
||||
134["Segment<br>[1866, 1896, 0]"]
|
||||
135["Segment<br>[1866, 1896, 0]"]
|
||||
136["Segment<br>[1866, 1896, 0]"]
|
||||
137["Segment<br>[1866, 1896, 0]"]
|
||||
138["Segment<br>[1866, 1896, 0]"]
|
||||
139["Segment<br>[1866, 1896, 0]"]
|
||||
140["Segment<br>[1866, 1896, 0]"]
|
||||
141["Segment<br>[1866, 1896, 0]"]
|
||||
142["Segment<br>[1866, 1896, 0]"]
|
||||
143["Segment<br>[1866, 1896, 0]"]
|
||||
144["Segment<br>[1866, 1896, 0]"]
|
||||
145["Segment<br>[1866, 1896, 0]"]
|
||||
146["Segment<br>[1866, 1896, 0]"]
|
||||
147["Segment<br>[1866, 1896, 0]"]
|
||||
148["Segment<br>[1866, 1896, 0]"]
|
||||
149["Segment<br>[1866, 1896, 0]"]
|
||||
150["Segment<br>[1866, 1896, 0]"]
|
||||
151["Segment<br>[1866, 1896, 0]"]
|
||||
152["Segment<br>[1866, 1896, 0]"]
|
||||
153["Segment<br>[1866, 1896, 0]"]
|
||||
154["Segment<br>[1866, 1896, 0]"]
|
||||
155["Segment<br>[1866, 1896, 0]"]
|
||||
156["Segment<br>[1866, 1896, 0]"]
|
||||
157["Segment<br>[1866, 1896, 0]"]
|
||||
158["Segment<br>[1866, 1896, 0]"]
|
||||
159["Segment<br>[1866, 1896, 0]"]
|
||||
160["Segment<br>[1866, 1896, 0]"]
|
||||
161["Segment<br>[1866, 1896, 0]"]
|
||||
162["Segment<br>[1866, 1896, 0]"]
|
||||
163["Segment<br>[1866, 1896, 0]"]
|
||||
164["Segment<br>[1866, 1896, 0]"]
|
||||
165["Segment<br>[1866, 1896, 0]"]
|
||||
166["Segment<br>[1866, 1896, 0]"]
|
||||
167["Segment<br>[1866, 1896, 0]"]
|
||||
168["Segment<br>[1866, 1896, 0]"]
|
||||
169["Segment<br>[1866, 1896, 0]"]
|
||||
170["Segment<br>[1866, 1896, 0]"]
|
||||
171["Segment<br>[1866, 1896, 0]"]
|
||||
172["Segment<br>[1866, 1896, 0]"]
|
||||
173["Segment<br>[1866, 1896, 0]"]
|
||||
174["Segment<br>[1866, 1896, 0]"]
|
||||
175["Segment<br>[1866, 1896, 0]"]
|
||||
176["Segment<br>[1866, 1896, 0]"]
|
||||
177["Segment<br>[1866, 1896, 0]"]
|
||||
178["Segment<br>[1866, 1896, 0]"]
|
||||
179["Segment<br>[1866, 1896, 0]"]
|
||||
180["Segment<br>[1866, 1896, 0]"]
|
||||
181["Segment<br>[1866, 1896, 0]"]
|
||||
182["Segment<br>[1866, 1896, 0]"]
|
||||
183["Segment<br>[1866, 1896, 0]"]
|
||||
184["Segment<br>[1866, 1896, 0]"]
|
||||
185["Segment<br>[1866, 1896, 0]"]
|
||||
186["Segment<br>[1866, 1896, 0]"]
|
||||
187["Segment<br>[1866, 1896, 0]"]
|
||||
188["Segment<br>[1866, 1896, 0]"]
|
||||
189["Segment<br>[1866, 1896, 0]"]
|
||||
190["Segment<br>[1866, 1896, 0]"]
|
||||
191["Segment<br>[1866, 1896, 0]"]
|
||||
192["Segment<br>[1866, 1896, 0]"]
|
||||
193["Segment<br>[1866, 1896, 0]"]
|
||||
194["Segment<br>[1866, 1896, 0]"]
|
||||
195["Segment<br>[1866, 1896, 0]"]
|
||||
196["Segment<br>[1866, 1896, 0]"]
|
||||
197["Segment<br>[1866, 1896, 0]"]
|
||||
198["Segment<br>[1866, 1896, 0]"]
|
||||
199["Segment<br>[1866, 1896, 0]"]
|
||||
200["Segment<br>[1866, 1896, 0]"]
|
||||
201["Segment<br>[1866, 1896, 0]"]
|
||||
202["Segment<br>[1866, 1896, 0]"]
|
||||
203["Segment<br>[1866, 1896, 0]"]
|
||||
204["Segment<br>[1866, 1896, 0]"]
|
||||
205["Segment<br>[1866, 1896, 0]"]
|
||||
206["Segment<br>[1866, 1896, 0]"]
|
||||
207["Segment<br>[1866, 1896, 0]"]
|
||||
208["Segment<br>[1866, 1896, 0]"]
|
||||
209["Segment<br>[1866, 1896, 0]"]
|
||||
210["Segment<br>[2053, 2122, 0]"]
|
||||
211["Segment<br>[2182, 2189, 0]"]
|
||||
5["Path<br>[1969, 2006, 0]"]
|
||||
8["Segment<br>[1655, 1696, 0]"]
|
||||
9["Segment<br>[1655, 1696, 0]"]
|
||||
10["Segment<br>[1655, 1696, 0]"]
|
||||
11["Segment<br>[1655, 1696, 0]"]
|
||||
12["Segment<br>[1655, 1696, 0]"]
|
||||
13["Segment<br>[1655, 1696, 0]"]
|
||||
14["Segment<br>[1655, 1696, 0]"]
|
||||
15["Segment<br>[1655, 1696, 0]"]
|
||||
16["Segment<br>[1655, 1696, 0]"]
|
||||
17["Segment<br>[1655, 1696, 0]"]
|
||||
18["Segment<br>[1655, 1696, 0]"]
|
||||
19["Segment<br>[1655, 1696, 0]"]
|
||||
20["Segment<br>[1655, 1696, 0]"]
|
||||
21["Segment<br>[1655, 1696, 0]"]
|
||||
22["Segment<br>[1655, 1696, 0]"]
|
||||
23["Segment<br>[1655, 1696, 0]"]
|
||||
24["Segment<br>[1655, 1696, 0]"]
|
||||
25["Segment<br>[1655, 1696, 0]"]
|
||||
26["Segment<br>[1655, 1696, 0]"]
|
||||
27["Segment<br>[1655, 1696, 0]"]
|
||||
28["Segment<br>[1655, 1696, 0]"]
|
||||
29["Segment<br>[1655, 1696, 0]"]
|
||||
30["Segment<br>[1655, 1696, 0]"]
|
||||
31["Segment<br>[1655, 1696, 0]"]
|
||||
32["Segment<br>[1655, 1696, 0]"]
|
||||
33["Segment<br>[1655, 1696, 0]"]
|
||||
34["Segment<br>[1655, 1696, 0]"]
|
||||
35["Segment<br>[1655, 1696, 0]"]
|
||||
36["Segment<br>[1655, 1696, 0]"]
|
||||
37["Segment<br>[1655, 1696, 0]"]
|
||||
38["Segment<br>[1655, 1696, 0]"]
|
||||
39["Segment<br>[1655, 1696, 0]"]
|
||||
40["Segment<br>[1655, 1696, 0]"]
|
||||
41["Segment<br>[1655, 1696, 0]"]
|
||||
42["Segment<br>[1655, 1696, 0]"]
|
||||
43["Segment<br>[1655, 1696, 0]"]
|
||||
44["Segment<br>[1655, 1696, 0]"]
|
||||
45["Segment<br>[1655, 1696, 0]"]
|
||||
46["Segment<br>[1655, 1696, 0]"]
|
||||
47["Segment<br>[1655, 1696, 0]"]
|
||||
48["Segment<br>[1655, 1696, 0]"]
|
||||
49["Segment<br>[1655, 1696, 0]"]
|
||||
50["Segment<br>[1655, 1696, 0]"]
|
||||
51["Segment<br>[1655, 1696, 0]"]
|
||||
52["Segment<br>[1655, 1696, 0]"]
|
||||
53["Segment<br>[1655, 1696, 0]"]
|
||||
54["Segment<br>[1655, 1696, 0]"]
|
||||
55["Segment<br>[1655, 1696, 0]"]
|
||||
56["Segment<br>[1655, 1696, 0]"]
|
||||
57["Segment<br>[1655, 1696, 0]"]
|
||||
58["Segment<br>[1655, 1696, 0]"]
|
||||
59["Segment<br>[1655, 1696, 0]"]
|
||||
60["Segment<br>[1655, 1696, 0]"]
|
||||
61["Segment<br>[1655, 1696, 0]"]
|
||||
62["Segment<br>[1655, 1696, 0]"]
|
||||
63["Segment<br>[1655, 1696, 0]"]
|
||||
64["Segment<br>[1655, 1696, 0]"]
|
||||
65["Segment<br>[1655, 1696, 0]"]
|
||||
66["Segment<br>[1655, 1696, 0]"]
|
||||
67["Segment<br>[1655, 1696, 0]"]
|
||||
68["Segment<br>[1655, 1696, 0]"]
|
||||
69["Segment<br>[1655, 1696, 0]"]
|
||||
70["Segment<br>[1655, 1696, 0]"]
|
||||
71["Segment<br>[1655, 1696, 0]"]
|
||||
72["Segment<br>[1655, 1696, 0]"]
|
||||
73["Segment<br>[1655, 1696, 0]"]
|
||||
74["Segment<br>[1655, 1696, 0]"]
|
||||
75["Segment<br>[1655, 1696, 0]"]
|
||||
76["Segment<br>[1655, 1696, 0]"]
|
||||
77["Segment<br>[1655, 1696, 0]"]
|
||||
78["Segment<br>[1655, 1696, 0]"]
|
||||
79["Segment<br>[1655, 1696, 0]"]
|
||||
80["Segment<br>[1655, 1696, 0]"]
|
||||
81["Segment<br>[1655, 1696, 0]"]
|
||||
82["Segment<br>[1655, 1696, 0]"]
|
||||
83["Segment<br>[1655, 1696, 0]"]
|
||||
84["Segment<br>[1655, 1696, 0]"]
|
||||
85["Segment<br>[1655, 1696, 0]"]
|
||||
86["Segment<br>[1655, 1696, 0]"]
|
||||
87["Segment<br>[1655, 1696, 0]"]
|
||||
88["Segment<br>[1655, 1696, 0]"]
|
||||
89["Segment<br>[1655, 1696, 0]"]
|
||||
90["Segment<br>[1655, 1696, 0]"]
|
||||
91["Segment<br>[1655, 1696, 0]"]
|
||||
92["Segment<br>[1655, 1696, 0]"]
|
||||
93["Segment<br>[1655, 1696, 0]"]
|
||||
94["Segment<br>[1655, 1696, 0]"]
|
||||
95["Segment<br>[1655, 1696, 0]"]
|
||||
96["Segment<br>[1655, 1696, 0]"]
|
||||
97["Segment<br>[1655, 1696, 0]"]
|
||||
98["Segment<br>[1655, 1696, 0]"]
|
||||
99["Segment<br>[1655, 1696, 0]"]
|
||||
100["Segment<br>[1655, 1696, 0]"]
|
||||
101["Segment<br>[1655, 1696, 0]"]
|
||||
102["Segment<br>[1655, 1696, 0]"]
|
||||
103["Segment<br>[1655, 1696, 0]"]
|
||||
104["Segment<br>[1655, 1696, 0]"]
|
||||
105["Segment<br>[1655, 1696, 0]"]
|
||||
106["Segment<br>[1655, 1696, 0]"]
|
||||
107["Segment<br>[1655, 1696, 0]"]
|
||||
108["Segment<br>[1655, 1696, 0]"]
|
||||
109["Segment<br>[1882, 1915, 0]"]
|
||||
110["Segment<br>[1882, 1915, 0]"]
|
||||
111["Segment<br>[1882, 1915, 0]"]
|
||||
112["Segment<br>[1882, 1915, 0]"]
|
||||
113["Segment<br>[1882, 1915, 0]"]
|
||||
114["Segment<br>[1882, 1915, 0]"]
|
||||
115["Segment<br>[1882, 1915, 0]"]
|
||||
116["Segment<br>[1882, 1915, 0]"]
|
||||
117["Segment<br>[1882, 1915, 0]"]
|
||||
118["Segment<br>[1882, 1915, 0]"]
|
||||
119["Segment<br>[1882, 1915, 0]"]
|
||||
120["Segment<br>[1882, 1915, 0]"]
|
||||
121["Segment<br>[1882, 1915, 0]"]
|
||||
122["Segment<br>[1882, 1915, 0]"]
|
||||
123["Segment<br>[1882, 1915, 0]"]
|
||||
124["Segment<br>[1882, 1915, 0]"]
|
||||
125["Segment<br>[1882, 1915, 0]"]
|
||||
126["Segment<br>[1882, 1915, 0]"]
|
||||
127["Segment<br>[1882, 1915, 0]"]
|
||||
128["Segment<br>[1882, 1915, 0]"]
|
||||
129["Segment<br>[1882, 1915, 0]"]
|
||||
130["Segment<br>[1882, 1915, 0]"]
|
||||
131["Segment<br>[1882, 1915, 0]"]
|
||||
132["Segment<br>[1882, 1915, 0]"]
|
||||
133["Segment<br>[1882, 1915, 0]"]
|
||||
134["Segment<br>[1882, 1915, 0]"]
|
||||
135["Segment<br>[1882, 1915, 0]"]
|
||||
136["Segment<br>[1882, 1915, 0]"]
|
||||
137["Segment<br>[1882, 1915, 0]"]
|
||||
138["Segment<br>[1882, 1915, 0]"]
|
||||
139["Segment<br>[1882, 1915, 0]"]
|
||||
140["Segment<br>[1882, 1915, 0]"]
|
||||
141["Segment<br>[1882, 1915, 0]"]
|
||||
142["Segment<br>[1882, 1915, 0]"]
|
||||
143["Segment<br>[1882, 1915, 0]"]
|
||||
144["Segment<br>[1882, 1915, 0]"]
|
||||
145["Segment<br>[1882, 1915, 0]"]
|
||||
146["Segment<br>[1882, 1915, 0]"]
|
||||
147["Segment<br>[1882, 1915, 0]"]
|
||||
148["Segment<br>[1882, 1915, 0]"]
|
||||
149["Segment<br>[1882, 1915, 0]"]
|
||||
150["Segment<br>[1882, 1915, 0]"]
|
||||
151["Segment<br>[1882, 1915, 0]"]
|
||||
152["Segment<br>[1882, 1915, 0]"]
|
||||
153["Segment<br>[1882, 1915, 0]"]
|
||||
154["Segment<br>[1882, 1915, 0]"]
|
||||
155["Segment<br>[1882, 1915, 0]"]
|
||||
156["Segment<br>[1882, 1915, 0]"]
|
||||
157["Segment<br>[1882, 1915, 0]"]
|
||||
158["Segment<br>[1882, 1915, 0]"]
|
||||
159["Segment<br>[1882, 1915, 0]"]
|
||||
160["Segment<br>[1882, 1915, 0]"]
|
||||
161["Segment<br>[1882, 1915, 0]"]
|
||||
162["Segment<br>[1882, 1915, 0]"]
|
||||
163["Segment<br>[1882, 1915, 0]"]
|
||||
164["Segment<br>[1882, 1915, 0]"]
|
||||
165["Segment<br>[1882, 1915, 0]"]
|
||||
166["Segment<br>[1882, 1915, 0]"]
|
||||
167["Segment<br>[1882, 1915, 0]"]
|
||||
168["Segment<br>[1882, 1915, 0]"]
|
||||
169["Segment<br>[1882, 1915, 0]"]
|
||||
170["Segment<br>[1882, 1915, 0]"]
|
||||
171["Segment<br>[1882, 1915, 0]"]
|
||||
172["Segment<br>[1882, 1915, 0]"]
|
||||
173["Segment<br>[1882, 1915, 0]"]
|
||||
174["Segment<br>[1882, 1915, 0]"]
|
||||
175["Segment<br>[1882, 1915, 0]"]
|
||||
176["Segment<br>[1882, 1915, 0]"]
|
||||
177["Segment<br>[1882, 1915, 0]"]
|
||||
178["Segment<br>[1882, 1915, 0]"]
|
||||
179["Segment<br>[1882, 1915, 0]"]
|
||||
180["Segment<br>[1882, 1915, 0]"]
|
||||
181["Segment<br>[1882, 1915, 0]"]
|
||||
182["Segment<br>[1882, 1915, 0]"]
|
||||
183["Segment<br>[1882, 1915, 0]"]
|
||||
184["Segment<br>[1882, 1915, 0]"]
|
||||
185["Segment<br>[1882, 1915, 0]"]
|
||||
186["Segment<br>[1882, 1915, 0]"]
|
||||
187["Segment<br>[1882, 1915, 0]"]
|
||||
188["Segment<br>[1882, 1915, 0]"]
|
||||
189["Segment<br>[1882, 1915, 0]"]
|
||||
190["Segment<br>[1882, 1915, 0]"]
|
||||
191["Segment<br>[1882, 1915, 0]"]
|
||||
192["Segment<br>[1882, 1915, 0]"]
|
||||
193["Segment<br>[1882, 1915, 0]"]
|
||||
194["Segment<br>[1882, 1915, 0]"]
|
||||
195["Segment<br>[1882, 1915, 0]"]
|
||||
196["Segment<br>[1882, 1915, 0]"]
|
||||
197["Segment<br>[1882, 1915, 0]"]
|
||||
198["Segment<br>[1882, 1915, 0]"]
|
||||
199["Segment<br>[1882, 1915, 0]"]
|
||||
200["Segment<br>[1882, 1915, 0]"]
|
||||
201["Segment<br>[1882, 1915, 0]"]
|
||||
202["Segment<br>[1882, 1915, 0]"]
|
||||
203["Segment<br>[1882, 1915, 0]"]
|
||||
204["Segment<br>[1882, 1915, 0]"]
|
||||
205["Segment<br>[1882, 1915, 0]"]
|
||||
206["Segment<br>[1882, 1915, 0]"]
|
||||
207["Segment<br>[1882, 1915, 0]"]
|
||||
208["Segment<br>[1882, 1915, 0]"]
|
||||
209["Segment<br>[1882, 1915, 0]"]
|
||||
210["Segment<br>[2072, 2141, 0]"]
|
||||
211["Segment<br>[2201, 2208, 0]"]
|
||||
218[Solid2d]
|
||||
end
|
||||
subgraph path6 [Path]
|
||||
6["Path<br>[2670, 2770, 0]"]
|
||||
212["Segment<br>[2776, 2803, 0]"]
|
||||
213["Segment<br>[2809, 2837, 0]"]
|
||||
214["Segment<br>[2843, 2871, 0]"]
|
||||
215["Segment<br>[2877, 2971, 0]"]
|
||||
216["Segment<br>[2977, 3060, 0]"]
|
||||
217["Segment<br>[3066, 3073, 0]"]
|
||||
6["Path<br>[2689, 2789, 0]"]
|
||||
212["Segment<br>[2795, 2822, 0]"]
|
||||
213["Segment<br>[2828, 2856, 0]"]
|
||||
214["Segment<br>[2862, 2890, 0]"]
|
||||
215["Segment<br>[2896, 2990, 0]"]
|
||||
216["Segment<br>[2996, 3079, 0]"]
|
||||
217["Segment<br>[3085, 3092, 0]"]
|
||||
220[Solid2d]
|
||||
end
|
||||
1["Plane<br>[1408, 1425, 0]"]
|
||||
2["Plane<br>[1927, 1944, 0]"]
|
||||
3["StartSketchOnFace<br>[2633, 2664, 0]"]
|
||||
221["Sweep Extrusion<br>[1487, 1515, 0]"]
|
||||
222["Sweep Extrusion<br>[2195, 2223, 0]"]
|
||||
223["Sweep Extrusion<br>[3079, 3108, 0]"]
|
||||
1["Plane<br>[1413, 1430, 0]"]
|
||||
2["Plane<br>[1946, 1963, 0]"]
|
||||
3["StartSketchOnFace<br>[2652, 2683, 0]"]
|
||||
221["Sweep Extrusion<br>[1492, 1520, 0]"]
|
||||
222["Sweep Extrusion<br>[2214, 2242, 0]"]
|
||||
223["Sweep Extrusion<br>[3098, 3127, 0]"]
|
||||
224[Wall]
|
||||
225[Wall]
|
||||
226[Wall]
|
||||
|
@ -698,7 +698,8 @@ description: Result of parsing gear.kcl
|
||||
"name": "i",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
}
|
||||
],
|
||||
"start": 0,
|
||||
@ -934,7 +935,8 @@ description: Result of parsing gear.kcl
|
||||
"name": "r",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
}
|
||||
],
|
||||
"start": 0,
|
||||
@ -1135,7 +1137,8 @@ description: Result of parsing gear.kcl
|
||||
"name": "a",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
}
|
||||
],
|
||||
"start": 0,
|
||||
@ -1337,7 +1340,8 @@ description: Result of parsing gear.kcl
|
||||
"name": "i",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
}
|
||||
],
|
||||
"start": 0,
|
||||
@ -1559,7 +1563,8 @@ description: Result of parsing gear.kcl
|
||||
"name": "i",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
}
|
||||
],
|
||||
"start": 0,
|
||||
@ -2119,7 +2124,7 @@ description: Result of parsing gear.kcl
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "sg",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
@ -2169,14 +2174,15 @@ description: Result of parsing gear.kcl
|
||||
"name": "i",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
},
|
||||
{
|
||||
"type": "Parameter",
|
||||
"identifier": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "sg",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
@ -2735,7 +2741,7 @@ description: Result of parsing gear.kcl
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "sg",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
@ -2767,14 +2773,15 @@ description: Result of parsing gear.kcl
|
||||
"name": "i",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
},
|
||||
{
|
||||
"type": "Parameter",
|
||||
"identifier": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "sg",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -47,23 +47,23 @@ flowchart LR
|
||||
142[Solid2d]
|
||||
end
|
||||
subgraph path23 [Path]
|
||||
23["Path<br>[998, 1045, 3]"]
|
||||
64["Segment<br>[1051, 1092, 3]"]
|
||||
65["Segment<br>[1098, 1140, 3]"]
|
||||
66["Segment<br>[1146, 1188, 3]"]
|
||||
67["Segment<br>[1194, 1201, 3]"]
|
||||
23["Path<br>[1000, 1047, 3]"]
|
||||
64["Segment<br>[1053, 1094, 3]"]
|
||||
65["Segment<br>[1100, 1142, 3]"]
|
||||
66["Segment<br>[1148, 1190, 3]"]
|
||||
67["Segment<br>[1196, 1203, 3]"]
|
||||
150[Solid2d]
|
||||
end
|
||||
subgraph path24 [Path]
|
||||
24["Path<br>[1459, 1610, 3]"]
|
||||
68["Segment<br>[1616, 1692, 3]"]
|
||||
69["Segment<br>[1698, 1851, 3]"]
|
||||
70["Segment<br>[1857, 1933, 3]"]
|
||||
71["Segment<br>[1939, 2095, 3]"]
|
||||
72["Segment<br>[2101, 2178, 3]"]
|
||||
73["Segment<br>[2184, 2339, 3]"]
|
||||
74["Segment<br>[2345, 2421, 3]"]
|
||||
75["Segment<br>[2427, 2434, 3]"]
|
||||
24["Path<br>[1461, 1612, 3]"]
|
||||
68["Segment<br>[1618, 1694, 3]"]
|
||||
69["Segment<br>[1700, 1853, 3]"]
|
||||
70["Segment<br>[1859, 1935, 3]"]
|
||||
71["Segment<br>[1941, 2097, 3]"]
|
||||
72["Segment<br>[2103, 2180, 3]"]
|
||||
73["Segment<br>[2186, 2341, 3]"]
|
||||
74["Segment<br>[2347, 2423, 3]"]
|
||||
75["Segment<br>[2429, 2436, 3]"]
|
||||
139[Solid2d]
|
||||
end
|
||||
subgraph path25 [Path]
|
||||
@ -181,13 +181,13 @@ flowchart LR
|
||||
end
|
||||
1["Plane<br>[386, 403, 2]"]
|
||||
2["Plane<br>[473, 490, 3]"]
|
||||
3["Plane<br>[975, 992, 3]"]
|
||||
4["Plane<br>[1436, 1453, 3]"]
|
||||
5["Plane<br>[2585, 2602, 3]"]
|
||||
6["Plane<br>[2682, 2699, 3]"]
|
||||
7["Plane<br>[2781, 2798, 3]"]
|
||||
8["Plane<br>[2879, 2896, 3]"]
|
||||
9["Plane<br>[2977, 2994, 3]"]
|
||||
3["Plane<br>[977, 994, 3]"]
|
||||
4["Plane<br>[1438, 1455, 3]"]
|
||||
5["Plane<br>[2587, 2604, 3]"]
|
||||
6["Plane<br>[2684, 2701, 3]"]
|
||||
7["Plane<br>[2783, 2800, 3]"]
|
||||
8["Plane<br>[2881, 2898, 3]"]
|
||||
9["Plane<br>[2979, 2996, 3]"]
|
||||
10["Plane<br>[325, 342, 5]"]
|
||||
11["Plane<br>[553, 592, 5]"]
|
||||
12["Plane<br>[256, 273, 6]"]
|
||||
@ -200,7 +200,7 @@ flowchart LR
|
||||
158["Sweep Extrusion<br>[1767, 1810, 2]"]
|
||||
159["Sweep Extrusion<br>[2169, 2212, 2]"]
|
||||
160["Sweep Extrusion<br>[2464, 2497, 2]"]
|
||||
161["Sweep Extrusion<br>[3035, 3066, 3]"]
|
||||
161["Sweep Extrusion<br>[3037, 3068, 3]"]
|
||||
162["Sweep Loft<br>[932, 975, 5]"]
|
||||
163["Sweep Extrusion<br>[609, 661, 6]"]
|
||||
164["Sweep Revolve<br>[540, 557, 7]"]
|
||||
|
@ -2,60 +2,60 @@
|
||||
flowchart LR
|
||||
subgraph path2 [Path]
|
||||
2["Path<br>[733, 769, 0]"]
|
||||
3["Segment<br>[923, 987, 0]"]
|
||||
4["Segment<br>[923, 987, 0]"]
|
||||
5["Segment<br>[923, 987, 0]"]
|
||||
6["Segment<br>[923, 987, 0]"]
|
||||
7["Segment<br>[923, 987, 0]"]
|
||||
8["Segment<br>[923, 987, 0]"]
|
||||
9["Segment<br>[923, 987, 0]"]
|
||||
10["Segment<br>[923, 987, 0]"]
|
||||
11["Segment<br>[923, 987, 0]"]
|
||||
12["Segment<br>[923, 987, 0]"]
|
||||
13["Segment<br>[923, 987, 0]"]
|
||||
14["Segment<br>[923, 987, 0]"]
|
||||
15["Segment<br>[923, 987, 0]"]
|
||||
16["Segment<br>[923, 987, 0]"]
|
||||
17["Segment<br>[923, 987, 0]"]
|
||||
18["Segment<br>[923, 987, 0]"]
|
||||
19["Segment<br>[923, 987, 0]"]
|
||||
20["Segment<br>[923, 987, 0]"]
|
||||
21["Segment<br>[923, 987, 0]"]
|
||||
22["Segment<br>[923, 987, 0]"]
|
||||
23["Segment<br>[923, 987, 0]"]
|
||||
24["Segment<br>[923, 987, 0]"]
|
||||
25["Segment<br>[923, 987, 0]"]
|
||||
26["Segment<br>[923, 987, 0]"]
|
||||
27["Segment<br>[923, 987, 0]"]
|
||||
28["Segment<br>[923, 987, 0]"]
|
||||
29["Segment<br>[923, 987, 0]"]
|
||||
30["Segment<br>[923, 987, 0]"]
|
||||
31["Segment<br>[923, 987, 0]"]
|
||||
32["Segment<br>[923, 987, 0]"]
|
||||
33["Segment<br>[923, 987, 0]"]
|
||||
34["Segment<br>[923, 987, 0]"]
|
||||
35["Segment<br>[923, 987, 0]"]
|
||||
36["Segment<br>[923, 987, 0]"]
|
||||
37["Segment<br>[923, 987, 0]"]
|
||||
38["Segment<br>[923, 987, 0]"]
|
||||
39["Segment<br>[923, 987, 0]"]
|
||||
40["Segment<br>[923, 987, 0]"]
|
||||
41["Segment<br>[923, 987, 0]"]
|
||||
42["Segment<br>[923, 987, 0]"]
|
||||
43["Segment<br>[923, 987, 0]"]
|
||||
44["Segment<br>[923, 987, 0]"]
|
||||
45["Segment<br>[923, 987, 0]"]
|
||||
46["Segment<br>[923, 987, 0]"]
|
||||
47["Segment<br>[923, 987, 0]"]
|
||||
48["Segment<br>[923, 987, 0]"]
|
||||
49["Segment<br>[923, 987, 0]"]
|
||||
50["Segment<br>[923, 987, 0]"]
|
||||
51["Segment<br>[923, 987, 0]"]
|
||||
52["Segment<br>[1051, 1069, 0]"]
|
||||
3["Segment<br>[923, 986, 0]"]
|
||||
4["Segment<br>[923, 986, 0]"]
|
||||
5["Segment<br>[923, 986, 0]"]
|
||||
6["Segment<br>[923, 986, 0]"]
|
||||
7["Segment<br>[923, 986, 0]"]
|
||||
8["Segment<br>[923, 986, 0]"]
|
||||
9["Segment<br>[923, 986, 0]"]
|
||||
10["Segment<br>[923, 986, 0]"]
|
||||
11["Segment<br>[923, 986, 0]"]
|
||||
12["Segment<br>[923, 986, 0]"]
|
||||
13["Segment<br>[923, 986, 0]"]
|
||||
14["Segment<br>[923, 986, 0]"]
|
||||
15["Segment<br>[923, 986, 0]"]
|
||||
16["Segment<br>[923, 986, 0]"]
|
||||
17["Segment<br>[923, 986, 0]"]
|
||||
18["Segment<br>[923, 986, 0]"]
|
||||
19["Segment<br>[923, 986, 0]"]
|
||||
20["Segment<br>[923, 986, 0]"]
|
||||
21["Segment<br>[923, 986, 0]"]
|
||||
22["Segment<br>[923, 986, 0]"]
|
||||
23["Segment<br>[923, 986, 0]"]
|
||||
24["Segment<br>[923, 986, 0]"]
|
||||
25["Segment<br>[923, 986, 0]"]
|
||||
26["Segment<br>[923, 986, 0]"]
|
||||
27["Segment<br>[923, 986, 0]"]
|
||||
28["Segment<br>[923, 986, 0]"]
|
||||
29["Segment<br>[923, 986, 0]"]
|
||||
30["Segment<br>[923, 986, 0]"]
|
||||
31["Segment<br>[923, 986, 0]"]
|
||||
32["Segment<br>[923, 986, 0]"]
|
||||
33["Segment<br>[923, 986, 0]"]
|
||||
34["Segment<br>[923, 986, 0]"]
|
||||
35["Segment<br>[923, 986, 0]"]
|
||||
36["Segment<br>[923, 986, 0]"]
|
||||
37["Segment<br>[923, 986, 0]"]
|
||||
38["Segment<br>[923, 986, 0]"]
|
||||
39["Segment<br>[923, 986, 0]"]
|
||||
40["Segment<br>[923, 986, 0]"]
|
||||
41["Segment<br>[923, 986, 0]"]
|
||||
42["Segment<br>[923, 986, 0]"]
|
||||
43["Segment<br>[923, 986, 0]"]
|
||||
44["Segment<br>[923, 986, 0]"]
|
||||
45["Segment<br>[923, 986, 0]"]
|
||||
46["Segment<br>[923, 986, 0]"]
|
||||
47["Segment<br>[923, 986, 0]"]
|
||||
48["Segment<br>[923, 986, 0]"]
|
||||
49["Segment<br>[923, 986, 0]"]
|
||||
50["Segment<br>[923, 986, 0]"]
|
||||
51["Segment<br>[923, 986, 0]"]
|
||||
52["Segment<br>[1050, 1068, 0]"]
|
||||
53[Solid2d]
|
||||
end
|
||||
1["Plane<br>[710, 727, 0]"]
|
||||
54["Sweep Extrusion<br>[1123, 1161, 0]"]
|
||||
54["Sweep Extrusion<br>[1122, 1160, 0]"]
|
||||
55[Wall]
|
||||
56[Wall]
|
||||
57[Wall]
|
||||
|
@ -801,7 +801,7 @@ description: Result of parsing loop_tag.kcl
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "sketch",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
@ -833,14 +833,15 @@ description: Result of parsing loop_tag.kcl
|
||||
"name": "index",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
"labeled": false
|
||||
},
|
||||
{
|
||||
"type": "Parameter",
|
||||
"identifier": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "sketch",
|
||||
"name": "accum",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ initialSketch = startSketchOn(XY)
|
||||
finalSketch = reduce(
|
||||
[1..numSides-1],
|
||||
initial = initialSketch,
|
||||
f = fn(index, sketch) {
|
||||
return line(sketch, end = calculatePoint(index), tag = $problematicTag)
|
||||
f = fn(@index, accum) {
|
||||
return line(accum, end = calculatePoint(index), tag = $problematicTag)
|
||||
}
|
||||
)
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -34,8 +34,8 @@ initialSketch = startSketchOn(XY)
|
||||
finalSketch = reduce(
|
||||
[1 .. numSides - 1],
|
||||
initial = initialSketch,
|
||||
f = fn(index, sketch) {
|
||||
return line(sketch, end = calculatePoint(index), tag = $problematicTag)
|
||||
f = fn(@index, accum) {
|
||||
return line(accum, end = calculatePoint(index), tag = $problematicTag)
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -48,6 +48,48 @@ description: Operations executed multi_transform.kcl
|
||||
"sourceRange": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "GroupBegin",
|
||||
"group": {
|
||||
"type": "FunctionCall",
|
||||
"name": null,
|
||||
"functionSourceRange": [],
|
||||
"unlabeledArg": {
|
||||
"value": {
|
||||
"type": "Number",
|
||||
"value": 1.0,
|
||||
"ty": {
|
||||
"type": "Known",
|
||||
"type": "Count"
|
||||
}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
"labeledArgs": {}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
{
|
||||
"type": "GroupBegin",
|
||||
"group": {
|
||||
"type": "FunctionCall",
|
||||
"name": null,
|
||||
"functionSourceRange": [],
|
||||
"unlabeledArg": {
|
||||
"value": {
|
||||
"type": "Number",
|
||||
"value": 2.0,
|
||||
"ty": {
|
||||
"type": "Known",
|
||||
"type": "Count"
|
||||
}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
"labeledArgs": {}
|
||||
},
|
||||
"sourceRange": []
|
||||
},
|
||||
{
|
||||
"labeledArgs": {
|
||||
"instances": {
|
||||
@ -85,5 +127,11 @@ description: Operations executed multi_transform.kcl
|
||||
},
|
||||
"sourceRange": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "GroupEnd"
|
||||
},
|
||||
{
|
||||
"type": "GroupEnd"
|
||||
}
|
||||
]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kcl-python-bindings"
|
||||
version = "0.3.67"
|
||||
version = "0.3.68"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/kittycad/modeling-app"
|
||||
exclude = ["tests/*", "files/*", "venv/*"]
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-test-server"
|
||||
description = "A test server for KCL"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-to-core"
|
||||
description = "Utility methods to convert kcl to engine core executable tests"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kcl-wasm-lib"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
rust-version = "1.83"
|
||||
|
@ -9,6 +9,8 @@ import {
|
||||
} from '@src/lib/constants'
|
||||
import { isDesktop } from '@src/lib/isDesktop'
|
||||
import { Themes, getSystemTheme } from '@src/lib/theme'
|
||||
import toast from 'react-hot-toast'
|
||||
import { platform } from '@src/lib/utils'
|
||||
|
||||
/**
|
||||
* This component is a handler that checks if a certain query parameter
|
||||
@ -35,11 +37,24 @@ export const OpenInDesktopAppHandler = (props: React.PropsWithChildren) => {
|
||||
*/
|
||||
function onOpenInDesktopApp() {
|
||||
const newSearchParams = new URLSearchParams(globalThis.location.search)
|
||||
newSearchParams.delete(ASK_TO_OPEN_QUERY_PARAM)
|
||||
const newURL = `${ZOO_STUDIO_PROTOCOL}://${globalThis.location.pathname.replace(
|
||||
'/',
|
||||
''
|
||||
)}${searchParams.size > 0 ? `?${newSearchParams.toString()}` : ''}`
|
||||
|
||||
// TODO: find a way to workaround this limitation, modeling-app#6200
|
||||
// Electron issue: https://github.com/electron/electron/issues/40776
|
||||
// This 2046 value comes from https://issues.chromium.org/issues/41322340#comment3
|
||||
// and empirical testing on Chrome and Windows 11
|
||||
const MAX_URL_LENGTH = 2046
|
||||
if (platform() === 'windows' && newURL.length > MAX_URL_LENGTH) {
|
||||
toast.error(
|
||||
'The URL is too long to open in the desktop app on Windows. Try another platform or use the web app.'
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
newSearchParams.delete(ASK_TO_OPEN_QUERY_PARAM)
|
||||
globalThis.location.href = newURL
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,14 @@ function ProjectCard({
|
||||
const imageData = await window.electron.readFile(projectImagePath)
|
||||
const blob = new Blob([imageData], { type: 'image/png' })
|
||||
const imageUrl = URL.createObjectURL(blob)
|
||||
setImageUrl(imageUrl)
|
||||
|
||||
if (blob.size > 0) {
|
||||
/**
|
||||
* Off chance that a thumbnail.png is cancelled writing and ends up writing 0 bytes
|
||||
* We do not want to load a 0 byte image
|
||||
*/
|
||||
setImageUrl(imageUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,7 +371,7 @@ const runModifyAstCloneWithEdgeTreatmentAndTag = async (
|
||||
}
|
||||
|
||||
// apply edge treatment to selection
|
||||
const result = modifyAstWithEdgeTreatmentAndTag(
|
||||
const result = await modifyAstWithEdgeTreatmentAndTag(
|
||||
ast,
|
||||
selection,
|
||||
parameters,
|
||||
|
@ -12,7 +12,6 @@ import {
|
||||
createLocalName,
|
||||
createPipeExpression,
|
||||
} from '@src/lang/create'
|
||||
import { updateModelingState } from '@src/lang/modelingWorkflows'
|
||||
import {
|
||||
getNodeFromPath,
|
||||
hasSketchPipeBeenExtruded,
|
||||
@ -39,7 +38,6 @@ import type {
|
||||
VariableDeclarator,
|
||||
} from '@src/lang/wasm'
|
||||
import type { KclCommandValue } from '@src/lib/commandTypes'
|
||||
import { EXECUTION_TYPE_REAL } from '@src/lib/constants'
|
||||
import type { Selection, Selections } from '@src/lib/selections'
|
||||
import { err } from '@src/lib/trap'
|
||||
import { isArray } from '@src/lib/utils'
|
||||
@ -65,43 +63,7 @@ export interface FilletParameters {
|
||||
export type EdgeTreatmentParameters = ChamferParameters | FilletParameters
|
||||
|
||||
// Apply Edge Treatment (Fillet or Chamfer) To Selection
|
||||
export async function applyEdgeTreatmentToSelection(
|
||||
ast: Node<Program>,
|
||||
selection: Selections,
|
||||
parameters: EdgeTreatmentParameters,
|
||||
dependencies: {
|
||||
kclManager: KclManager
|
||||
engineCommandManager: EngineCommandManager
|
||||
editorManager: EditorManager
|
||||
codeManager: CodeManager
|
||||
}
|
||||
): Promise<void | Error> {
|
||||
// 1. clone and modify with edge treatment and tag
|
||||
const result = modifyAstWithEdgeTreatmentAndTag(
|
||||
ast,
|
||||
selection,
|
||||
parameters,
|
||||
dependencies
|
||||
)
|
||||
if (err(result)) return result
|
||||
const { modifiedAst, pathToEdgeTreatmentNode } = result
|
||||
|
||||
// 2. update ast
|
||||
await updateModelingState(
|
||||
modifiedAst,
|
||||
EXECUTION_TYPE_REAL,
|
||||
{
|
||||
kclManager: dependencies.kclManager,
|
||||
editorManager: dependencies.editorManager,
|
||||
codeManager: dependencies.codeManager,
|
||||
},
|
||||
{
|
||||
focusPath: pathToEdgeTreatmentNode,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export function modifyAstWithEdgeTreatmentAndTag(
|
||||
export async function modifyAstWithEdgeTreatmentAndTag(
|
||||
ast: Node<Program>,
|
||||
selections: Selections,
|
||||
parameters: EdgeTreatmentParameters,
|
||||
@ -111,9 +73,9 @@ export function modifyAstWithEdgeTreatmentAndTag(
|
||||
editorManager: EditorManager
|
||||
codeManager: CodeManager
|
||||
}
|
||||
):
|
||||
| { modifiedAst: Node<Program>; pathToEdgeTreatmentNode: Array<PathToNode> }
|
||||
| Error {
|
||||
): Promise<
|
||||
{ modifiedAst: Node<Program>; pathToEdgeTreatmentNode: PathToNode[] } | Error
|
||||
> {
|
||||
let clonedAst = structuredClone(ast)
|
||||
const clonedAstForGetExtrude = structuredClone(ast)
|
||||
|
||||
@ -784,3 +746,47 @@ export async function deleteEdgeTreatment(
|
||||
|
||||
return Error('Delete fillets not implemented')
|
||||
}
|
||||
|
||||
// Edit Edge Treatment
|
||||
export async function editEdgeTreatment(
|
||||
ast: Node<Program>,
|
||||
selection: Selection,
|
||||
parameters: EdgeTreatmentParameters
|
||||
): Promise<
|
||||
{ modifiedAst: Node<Program>; pathToEdgeTreatmentNode: PathToNode } | Error
|
||||
> {
|
||||
// 1. clone and modify with new value
|
||||
const modifiedAst = structuredClone(ast)
|
||||
|
||||
// find the edge treatment call
|
||||
const edgeTreatmentCall = getNodeFromPath<CallExpressionKw>(
|
||||
modifiedAst,
|
||||
selection?.codeRef?.pathToNode,
|
||||
'CallExpressionKw'
|
||||
)
|
||||
if (err(edgeTreatmentCall)) return edgeTreatmentCall
|
||||
|
||||
// edge treatment parameter
|
||||
const parameterResult = getParameterNameAndValue(parameters)
|
||||
if (err(parameterResult)) return parameterResult
|
||||
const { parameterName, parameterValue } = parameterResult
|
||||
|
||||
// find the index of an argument to update
|
||||
const index = edgeTreatmentCall.node.arguments.findIndex(
|
||||
(arg) => arg.label.name === parameterName
|
||||
)
|
||||
|
||||
// create a new argument with the updated value
|
||||
const newArg = createLabeledArg(parameterName, parameterValue)
|
||||
|
||||
// if the parameter doesn't exist, add it; otherwise replace it
|
||||
if (index === -1) {
|
||||
edgeTreatmentCall.node.arguments.push(newArg)
|
||||
} else {
|
||||
edgeTreatmentCall.node.arguments[index] = newArg
|
||||
}
|
||||
|
||||
let pathToEdgeTreatmentNode = selection?.codeRef?.pathToNode
|
||||
|
||||
return { modifiedAst, pathToEdgeTreatmentNode }
|
||||
}
|
||||
|
@ -1,19 +1,100 @@
|
||||
import type { systemIOMachine } from '@src/machines/systemIO/systemIOMachine'
|
||||
import type { ActorRefFrom } from 'xstate'
|
||||
import type { Command, CommandArgumentOption } from '@src/lib/commandTypes'
|
||||
import type { RequestedKCLFile } from '@src/machines/systemIO/utils'
|
||||
import { SystemIOMachineEvents } from '@src/machines/systemIO/utils'
|
||||
import { isDesktop } from '@src/lib/isDesktop'
|
||||
import { kclSamplesManifestWithNoMultipleFiles } from '@src/lib/kclSamples'
|
||||
import { getUniqueProjectName } from '@src/lib/desktopFS'
|
||||
import {
|
||||
FILE_EXT,
|
||||
IS_ML_EXPERIMENTAL,
|
||||
ML_EXPERIMENTAL_MESSAGE,
|
||||
} from '@src/lib/constants'
|
||||
everyKclSample,
|
||||
findKclSample,
|
||||
kclSamplesManifestWithNoMultipleFiles,
|
||||
} from '@src/lib/kclSamples'
|
||||
import { getUniqueProjectName } from '@src/lib/desktopFS'
|
||||
import { IS_ML_EXPERIMENTAL, ML_EXPERIMENTAL_MESSAGE } from '@src/lib/constants'
|
||||
import toast from 'react-hot-toast'
|
||||
import { reportRejection } from '@src/lib/trap'
|
||||
import { relevantFileExtensions } from '@src/lang/wasmUtils'
|
||||
import { getStringAfterLastSeparator, webSafePathSplit } from '@src/lib/paths'
|
||||
import { FILE_EXT } from '@src/lib/constants'
|
||||
|
||||
function onSubmitKCLSampleCreation({
|
||||
sample,
|
||||
kclSample,
|
||||
uniqueNameIfNeeded,
|
||||
systemIOActor,
|
||||
}: {
|
||||
sample: any
|
||||
kclSample: ReturnType<typeof findKclSample>
|
||||
uniqueNameIfNeeded: any
|
||||
systemIOActor: ActorRefFrom<typeof systemIOMachine>
|
||||
}) {
|
||||
if (!kclSample) {
|
||||
toast.error('The command could not be submitted, unable to find Zoo sample')
|
||||
return
|
||||
}
|
||||
const pathParts = webSafePathSplit(sample)
|
||||
const projectPathPart = pathParts[0]
|
||||
const files = kclSample.files
|
||||
|
||||
const filePromises = files.map((file) => {
|
||||
const sampleCodeUrl =
|
||||
(isDesktop() ? '.' : '') +
|
||||
`/kcl-samples/${encodeURIComponent(
|
||||
projectPathPart
|
||||
)}/${encodeURIComponent(file)}`
|
||||
return fetch(sampleCodeUrl).then((response) => {
|
||||
return {
|
||||
response,
|
||||
file,
|
||||
projectName: projectPathPart,
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const requestedFiles: RequestedKCLFile[] = []
|
||||
// If any fetches fail from the KCL Code download we will instantly reject
|
||||
// No cleanup required since the fetch response is in memory
|
||||
// TODO: Try to catch if there is a failure then delete the root folder and show error
|
||||
Promise.all(filePromises)
|
||||
.then(async (responses) => {
|
||||
for (let i = 0; i < responses.length; i++) {
|
||||
const response = responses[i]
|
||||
const code = await response.response.text()
|
||||
requestedFiles.push({
|
||||
requestedCode: code,
|
||||
requestedFileName: response.file,
|
||||
requestedProjectName: uniqueNameIfNeeded,
|
||||
})
|
||||
}
|
||||
|
||||
if (requestedFiles.length === 1) {
|
||||
/**
|
||||
* Navigates to the single file that could be renamed on disk for duplicates
|
||||
*/
|
||||
const folderNameBecomesKCLFileName = projectPathPart + FILE_EXT
|
||||
systemIOActor.send({
|
||||
type: SystemIOMachineEvents.importFileFromURL,
|
||||
data: {
|
||||
requestedProjectName: requestedFiles[0].requestedProjectName,
|
||||
requestedFileNameWithExtension: folderNameBecomesKCLFileName,
|
||||
requestedCode: requestedFiles[0].requestedCode,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
/**
|
||||
* Bulk create the assembly and navigate to the project
|
||||
*/
|
||||
systemIOActor.send({
|
||||
type: SystemIOMachineEvents.bulkCreateKCLFilesAndNavigateToProject,
|
||||
data: {
|
||||
files: requestedFiles,
|
||||
requestedProjectName: uniqueNameIfNeeded,
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(reportError)
|
||||
}
|
||||
|
||||
export function createApplicationCommands({
|
||||
systemIOActor,
|
||||
@ -115,39 +196,18 @@ export function createApplicationCommands({
|
||||
? getUniqueProjectName(requestedProjectName, folders)
|
||||
: requestedProjectName
|
||||
|
||||
if (data.source === 'kcl-samples' && data.sample) {
|
||||
// This is web safe because the values are taken from manifest.json not from the disk when selecting
|
||||
const pathParts = webSafePathSplit(data.sample)
|
||||
const projectPathPart = pathParts[0]
|
||||
const primaryKclFile = pathParts[1]
|
||||
const folderNameBecomesKCLFileName = projectPathPart + FILE_EXT
|
||||
|
||||
const sampleCodeUrl =
|
||||
(isDesktop() ? '.' : '') +
|
||||
`/kcl-samples/${encodeURIComponent(
|
||||
projectPathPart
|
||||
)}/${encodeURIComponent(primaryKclFile)}`
|
||||
|
||||
fetch(sampleCodeUrl)
|
||||
.then(async (codeResponse) => {
|
||||
if (!codeResponse.ok) {
|
||||
console.error(
|
||||
'Failed to fetch sample code:',
|
||||
codeResponse.statusText
|
||||
)
|
||||
return Promise.reject(new Error('Failed to fetch sample code'))
|
||||
}
|
||||
const code = await codeResponse.text()
|
||||
systemIOActor.send({
|
||||
type: SystemIOMachineEvents.importFileFromURL,
|
||||
data: {
|
||||
requestedProjectName: uniqueNameIfNeeded,
|
||||
requestedFileNameWithExtension: folderNameBecomesKCLFileName,
|
||||
requestedCode: code,
|
||||
},
|
||||
})
|
||||
})
|
||||
.catch(reportError)
|
||||
const kclSample = findKclSample(data.sample)
|
||||
if (
|
||||
data.source === 'kcl-samples' &&
|
||||
kclSample &&
|
||||
kclSample.files.length >= 1
|
||||
) {
|
||||
onSubmitKCLSampleCreation({
|
||||
sample: data.sample,
|
||||
kclSample,
|
||||
uniqueNameIfNeeded,
|
||||
systemIOActor,
|
||||
})
|
||||
} else if (data.source === 'local' && data.path) {
|
||||
const clonePath = data.path
|
||||
const fileNameWithExtension = getStringAfterLastSeparator(clonePath)
|
||||
@ -193,16 +253,57 @@ export function createApplicationCommands({
|
||||
]
|
||||
},
|
||||
},
|
||||
sample: {
|
||||
inputType: 'options',
|
||||
required: (commandContext) =>
|
||||
!['local'].includes(
|
||||
commandContext.argumentsToSubmit.source as string
|
||||
),
|
||||
hidden: (commandContext) =>
|
||||
['local'].includes(commandContext.argumentsToSubmit.source as string),
|
||||
valueSummary(value) {
|
||||
const MAX_LENGTH = 12
|
||||
if (typeof value === 'string') {
|
||||
return value.length > MAX_LENGTH
|
||||
? value.substring(0, MAX_LENGTH) + '...'
|
||||
: value
|
||||
}
|
||||
return value
|
||||
},
|
||||
options: ({ argumentsToSubmit }) => {
|
||||
const samples =
|
||||
isDesktop() && argumentsToSubmit.method !== 'existingProject'
|
||||
? everyKclSample
|
||||
: kclSamplesManifestWithNoMultipleFiles
|
||||
return samples.map((sample) => {
|
||||
return {
|
||||
value: sample.pathFromProjectDirectoryToFirstFile,
|
||||
name: sample.title,
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
method: {
|
||||
inputType: 'options',
|
||||
required: true,
|
||||
skip: true,
|
||||
options: isDesktop()
|
||||
? [
|
||||
{ name: 'New project', value: 'newProject', isCurrent: true },
|
||||
{ name: 'Existing project', value: 'existingProject' },
|
||||
]
|
||||
: [{ name: 'Overwrite', value: 'existingProject' }],
|
||||
options: ({ argumentsToSubmit }, _) => {
|
||||
if (isDesktop() && typeof argumentsToSubmit.sample === 'string') {
|
||||
const kclSample = findKclSample(argumentsToSubmit.sample)
|
||||
if (kclSample && kclSample.files.length > 1) {
|
||||
return [
|
||||
{ name: 'New project', value: 'newProject', isCurrent: true },
|
||||
]
|
||||
} else {
|
||||
return [
|
||||
{ name: 'New project', value: 'newProject', isCurrent: true },
|
||||
{ name: 'Existing project', value: 'existingProject' },
|
||||
]
|
||||
}
|
||||
} else {
|
||||
return [{ name: 'Overwrite', value: 'existingProject' }]
|
||||
}
|
||||
},
|
||||
valueSummary(value) {
|
||||
return isDesktop()
|
||||
? value === 'newProject'
|
||||
@ -237,30 +338,6 @@ export function createApplicationCommands({
|
||||
commandsContext.argumentsToSubmit.method === 'newProject',
|
||||
skip: true,
|
||||
},
|
||||
sample: {
|
||||
inputType: 'options',
|
||||
required: (commandContext) =>
|
||||
!['local'].includes(
|
||||
commandContext.argumentsToSubmit.source as string
|
||||
),
|
||||
hidden: (commandContext) =>
|
||||
['local'].includes(commandContext.argumentsToSubmit.source as string),
|
||||
valueSummary(value) {
|
||||
const MAX_LENGTH = 12
|
||||
if (typeof value === 'string') {
|
||||
return value.length > MAX_LENGTH
|
||||
? value.substring(0, MAX_LENGTH) + '...'
|
||||
: value
|
||||
}
|
||||
return value
|
||||
},
|
||||
options: kclSamplesManifestWithNoMultipleFiles.map((sample) => {
|
||||
return {
|
||||
value: sample.pathFromProjectDirectoryToFirstFile,
|
||||
name: sample.title,
|
||||
}
|
||||
}),
|
||||
},
|
||||
path: {
|
||||
inputType: 'path',
|
||||
skip: true,
|
||||
@ -282,7 +359,78 @@ export function createApplicationCommands({
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks similar to Add file to project but more data is hard coded for the home page button
|
||||
* to direct the user in a more seamless method.
|
||||
*
|
||||
* This will always create a new folder on disk does not import into existing projects.
|
||||
* Desktop only command for now!
|
||||
*/
|
||||
const createASampleDesktopOnly: Command = {
|
||||
name: 'create-a-sample',
|
||||
displayName: 'Create a sample',
|
||||
description: 'Create a new project from a Zoo Sample',
|
||||
needsReview: false,
|
||||
icon: 'importFile',
|
||||
groupId: 'application',
|
||||
hideFromSearch: true,
|
||||
onSubmit: (data) => {
|
||||
if (data) {
|
||||
const folders = systemIOActor.getSnapshot().context.folders
|
||||
const kclSample = findKclSample(data.sample)
|
||||
if (!kclSample) {
|
||||
toast.error(
|
||||
'The command could not be submitted, unable to find Zoo sample'
|
||||
)
|
||||
return
|
||||
}
|
||||
const pathParts = webSafePathSplit(
|
||||
kclSample.pathFromProjectDirectoryToFirstFile
|
||||
)
|
||||
const folderNameBecomesSampleName = pathParts[0]
|
||||
const uniqueNameIfNeeded = getUniqueProjectName(
|
||||
folderNameBecomesSampleName,
|
||||
folders
|
||||
)
|
||||
onSubmitKCLSampleCreation({
|
||||
sample: data.sample,
|
||||
kclSample,
|
||||
uniqueNameIfNeeded,
|
||||
systemIOActor,
|
||||
})
|
||||
}
|
||||
},
|
||||
args: {
|
||||
source: {
|
||||
inputType: 'text',
|
||||
required: true,
|
||||
skip: false,
|
||||
defaultValue: 'kcl-samples',
|
||||
hidden: true,
|
||||
},
|
||||
sample: {
|
||||
inputType: 'options',
|
||||
required: true,
|
||||
valueSummary(value) {
|
||||
const MAX_LENGTH = 12
|
||||
if (typeof value === 'string') {
|
||||
return value.length > MAX_LENGTH
|
||||
? value.substring(0, MAX_LENGTH) + '...'
|
||||
: value
|
||||
}
|
||||
return value
|
||||
},
|
||||
options: everyKclSample.map((sample) => {
|
||||
return {
|
||||
value: sample.pathFromProjectDirectoryToFirstFile,
|
||||
name: sample.title,
|
||||
}
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return isDesktop()
|
||||
? [textToCADCommand, addKCLFileToProject]
|
||||
? [textToCADCommand, addKCLFileToProject, createASampleDesktopOnly]
|
||||
: [textToCADCommand, addKCLFileToProject]
|
||||
}
|
||||
|
@ -746,8 +746,6 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
||||
multiple: true,
|
||||
required: true,
|
||||
skip: false,
|
||||
warningMessage:
|
||||
'Fillets cannot touch other fillets yet. This is under development.',
|
||||
hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit),
|
||||
},
|
||||
radius: {
|
||||
|
@ -1,7 +1,14 @@
|
||||
import kclSamplesManifest from '@public/kcl-samples/manifest.json'
|
||||
|
||||
const kclSamplesManifestWithNoMultipleFiles = kclSamplesManifest.filter(
|
||||
export const kclSamplesManifestWithNoMultipleFiles = kclSamplesManifest.filter(
|
||||
(file) => !file.multipleFiles
|
||||
)
|
||||
export const everyKclSample = kclSamplesManifest
|
||||
|
||||
export { kclSamplesManifest, kclSamplesManifestWithNoMultipleFiles }
|
||||
export const findKclSample = (pathFromProjectDirectoryToFirstFile: string) => {
|
||||
return everyKclSample.find(
|
||||
(sample) =>
|
||||
sample.pathFromProjectDirectoryToFirstFile ===
|
||||
pathFromProjectDirectoryToFirstFile
|
||||
)
|
||||
}
|
||||
|
@ -166,15 +166,6 @@ const prepareToEditEdgeTreatment: PrepareToEditCallback = async ({
|
||||
kclManager.ast,
|
||||
sourceRangeFromRust(operation.sourceRange)
|
||||
)
|
||||
const isPipeExpression = nodeToEdit.some(
|
||||
([_, type]) => type === 'PipeExpression'
|
||||
)
|
||||
if (!isPipeExpression) {
|
||||
return {
|
||||
reason:
|
||||
'Only chamfer and fillet in pipe expressions are supported for edits',
|
||||
}
|
||||
}
|
||||
|
||||
let argDefaultValues:
|
||||
| ModelingCommandSchema['Chamfer']
|
||||
|
@ -58,7 +58,8 @@ import type {
|
||||
} from '@src/lang/modifyAst/addEdgeTreatment'
|
||||
import {
|
||||
EdgeTreatmentType,
|
||||
applyEdgeTreatmentToSelection,
|
||||
modifyAstWithEdgeTreatmentAndTag,
|
||||
editEdgeTreatment,
|
||||
getPathToExtrudeForSegmentSelection,
|
||||
mutateAstWithTagForSketchSegment,
|
||||
} from '@src/lang/modifyAst/addEdgeTreatment'
|
||||
@ -133,7 +134,6 @@ import {
|
||||
import type { ToolbarModeName } from '@src/lib/toolbar'
|
||||
import { err, reportRejection, trap } from '@src/lib/trap'
|
||||
import { uuidv4 } from '@src/lib/utils'
|
||||
import { deleteNodeInExtrudePipe } from '@src/lang/modifyAst/deleteNodeInExtrudePipe'
|
||||
import type { ImportStatement } from '@rust/kcl-lib/bindings/ImportStatement'
|
||||
|
||||
export type SetSelections =
|
||||
@ -2311,18 +2311,107 @@ export const modelingMachine = setup({
|
||||
|
||||
// Extract inputs
|
||||
const ast = kclManager.ast
|
||||
let modifiedAst = structuredClone(ast)
|
||||
let focusPath: PathToNode[] = []
|
||||
const { nodeToEdit, selection, radius } = input
|
||||
|
||||
// If this is an edit flow, first we're going to remove the old node
|
||||
if (nodeToEdit) {
|
||||
const oldNodeDeletion = deleteNodeInExtrudePipe(nodeToEdit, ast)
|
||||
if (err(oldNodeDeletion)) return oldNodeDeletion
|
||||
}
|
||||
|
||||
const parameters: FilletParameters = {
|
||||
type: EdgeTreatmentType.Fillet,
|
||||
radius,
|
||||
}
|
||||
|
||||
const dependencies = {
|
||||
kclManager,
|
||||
engineCommandManager,
|
||||
editorManager,
|
||||
codeManager,
|
||||
}
|
||||
|
||||
// Apply or edit fillet
|
||||
if (nodeToEdit) {
|
||||
// Edit existing fillet
|
||||
// selection is not the edge treatment itself,
|
||||
// but just the first edge in the fillet expression >
|
||||
// we need to find the edgeCut artifact
|
||||
// and build a new selection from it
|
||||
// TODO: this is a bit of a hack, we should be able
|
||||
// to get the edgeCut artifact from the selection
|
||||
const firstSelection = selection.graphSelections[0]
|
||||
const edgeCutArtifact = Array.from(
|
||||
kclManager.artifactGraph.values()
|
||||
).find(
|
||||
(artifact) =>
|
||||
artifact.type === 'edgeCut' &&
|
||||
artifact.consumedEdgeId === firstSelection.artifact?.id
|
||||
)
|
||||
if (!edgeCutArtifact || edgeCutArtifact.type !== 'edgeCut') {
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
'Failed to retrieve edgeCut artifact from sweepEdge selection'
|
||||
)
|
||||
)
|
||||
}
|
||||
const edgeTreatmentSelection = {
|
||||
artifact: edgeCutArtifact,
|
||||
codeRef: edgeCutArtifact.codeRef,
|
||||
}
|
||||
|
||||
const editResult = await editEdgeTreatment(
|
||||
ast,
|
||||
edgeTreatmentSelection,
|
||||
parameters
|
||||
)
|
||||
if (err(editResult)) return Promise.reject(editResult)
|
||||
|
||||
modifiedAst = editResult.modifiedAst
|
||||
focusPath = [editResult.pathToEdgeTreatmentNode]
|
||||
} else {
|
||||
// Apply fillet to selection
|
||||
const filletResult = await modifyAstWithEdgeTreatmentAndTag(
|
||||
ast,
|
||||
selection,
|
||||
parameters,
|
||||
dependencies
|
||||
)
|
||||
if (err(filletResult)) return Promise.reject(filletResult)
|
||||
modifiedAst = filletResult.modifiedAst
|
||||
focusPath = filletResult.pathToEdgeTreatmentNode
|
||||
}
|
||||
|
||||
await updateModelingState(
|
||||
modifiedAst,
|
||||
EXECUTION_TYPE_REAL,
|
||||
{
|
||||
kclManager,
|
||||
editorManager,
|
||||
codeManager,
|
||||
},
|
||||
{
|
||||
focusPath: focusPath,
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
chamferAstMod: fromPromise(
|
||||
async ({
|
||||
input,
|
||||
}: {
|
||||
input: ModelingCommandSchema['Chamfer'] | undefined
|
||||
}) => {
|
||||
if (!input) {
|
||||
return Promise.reject(new Error('No input provided'))
|
||||
}
|
||||
|
||||
// Extract inputs
|
||||
const ast = kclManager.ast
|
||||
let modifiedAst = structuredClone(ast)
|
||||
let focusPath: PathToNode[] = []
|
||||
const { nodeToEdit, selection, length } = input
|
||||
|
||||
const parameters: ChamferParameters = {
|
||||
type: EdgeTreatmentType.Chamfer,
|
||||
length,
|
||||
}
|
||||
const dependencies = {
|
||||
kclManager,
|
||||
engineCommandManager,
|
||||
@ -2330,14 +2419,69 @@ export const modelingMachine = setup({
|
||||
codeManager,
|
||||
}
|
||||
|
||||
// Apply fillet to selection
|
||||
const filletResult = await applyEdgeTreatmentToSelection(
|
||||
ast,
|
||||
selection,
|
||||
parameters,
|
||||
dependencies
|
||||
// Apply or edit chamfer
|
||||
if (nodeToEdit) {
|
||||
// Edit existing chamfer
|
||||
// selection is not the edge treatment itself,
|
||||
// but just the first edge in the chamfer expression >
|
||||
// we need to find the edgeCut artifact
|
||||
// and build a new selection from it
|
||||
// TODO: this is a bit of a hack, we should be able
|
||||
// to get the edgeCut artifact from the selection
|
||||
const firstSelection = selection.graphSelections[0]
|
||||
const edgeCutArtifact = Array.from(
|
||||
kclManager.artifactGraph.values()
|
||||
).find(
|
||||
(artifact) =>
|
||||
artifact.type === 'edgeCut' &&
|
||||
artifact.consumedEdgeId === firstSelection.artifact?.id
|
||||
)
|
||||
if (!edgeCutArtifact || edgeCutArtifact.type !== 'edgeCut') {
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
'Failed to retrieve edgeCut artifact from sweepEdge selection'
|
||||
)
|
||||
)
|
||||
}
|
||||
const edgeTreatmentSelection = {
|
||||
artifact: edgeCutArtifact,
|
||||
codeRef: edgeCutArtifact.codeRef,
|
||||
}
|
||||
|
||||
const editResult = await editEdgeTreatment(
|
||||
ast,
|
||||
edgeTreatmentSelection,
|
||||
parameters
|
||||
)
|
||||
if (err(editResult)) return Promise.reject(editResult)
|
||||
|
||||
modifiedAst = editResult.modifiedAst
|
||||
focusPath = [editResult.pathToEdgeTreatmentNode]
|
||||
} else {
|
||||
// Apply chamfer to selection
|
||||
const chamferResult = await modifyAstWithEdgeTreatmentAndTag(
|
||||
ast,
|
||||
selection,
|
||||
parameters,
|
||||
dependencies
|
||||
)
|
||||
if (err(chamferResult)) return Promise.reject(chamferResult)
|
||||
modifiedAst = chamferResult.modifiedAst
|
||||
focusPath = chamferResult.pathToEdgeTreatmentNode
|
||||
}
|
||||
|
||||
await updateModelingState(
|
||||
modifiedAst,
|
||||
EXECUTION_TYPE_REAL,
|
||||
{
|
||||
kclManager,
|
||||
editorManager,
|
||||
codeManager,
|
||||
},
|
||||
{
|
||||
focusPath: focusPath,
|
||||
}
|
||||
)
|
||||
if (err(filletResult)) return filletResult
|
||||
}
|
||||
),
|
||||
'actor.parameter.create': fromPromise(
|
||||
@ -2461,47 +2605,6 @@ export const modelingMachine = setup({
|
||||
return {} as SketchDetailsUpdate
|
||||
}
|
||||
),
|
||||
chamferAstMod: fromPromise(
|
||||
async ({
|
||||
input,
|
||||
}: {
|
||||
input: ModelingCommandSchema['Chamfer'] | undefined
|
||||
}) => {
|
||||
if (!input) {
|
||||
return new Error('No input provided')
|
||||
}
|
||||
|
||||
// Extract inputs
|
||||
const ast = kclManager.ast
|
||||
const { nodeToEdit, selection, length } = input
|
||||
|
||||
// If this is an edit flow, first we're going to remove the old node
|
||||
if (nodeToEdit) {
|
||||
const oldNodeDeletion = deleteNodeInExtrudePipe(nodeToEdit, ast)
|
||||
if (err(oldNodeDeletion)) return oldNodeDeletion
|
||||
}
|
||||
|
||||
const parameters: ChamferParameters = {
|
||||
type: EdgeTreatmentType.Chamfer,
|
||||
length,
|
||||
}
|
||||
const dependencies = {
|
||||
kclManager,
|
||||
engineCommandManager,
|
||||
editorManager,
|
||||
codeManager,
|
||||
}
|
||||
|
||||
// Apply chamfer to selection
|
||||
const chamferResult = await applyEdgeTreatmentToSelection(
|
||||
ast,
|
||||
selection,
|
||||
parameters,
|
||||
dependencies
|
||||
)
|
||||
if (err(chamferResult)) return chamferResult
|
||||
}
|
||||
),
|
||||
'submit-prompt-edit': fromPromise(
|
||||
async ({
|
||||
input,
|
||||
|
@ -332,12 +332,9 @@ const Home = () => {
|
||||
type: 'Find and select command',
|
||||
data: {
|
||||
groupId: 'application',
|
||||
name: 'add-kcl-file-to-project',
|
||||
name: 'create-a-sample',
|
||||
argDefaultValues: {
|
||||
source: 'kcl-samples',
|
||||
method: 'newProject',
|
||||
newProjectName:
|
||||
settings.projects.defaultProjectName.current,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
Reference in New Issue
Block a user