Compare commits
30 Commits
mike/engin
...
achalmers/
Author | SHA1 | Date | |
---|---|---|---|
976d5d2b4f | |||
4925251c29 | |||
9772869545 | |||
a7e830cd02 | |||
ca102116b6 | |||
c2fba89e77 | |||
7e31678ba2 | |||
1140ced121 | |||
32b7ddaa7c | |||
2525f99515 | |||
4b8ce34b31 | |||
6617f72373 | |||
e9033e1754 | |||
9b697e30cf | |||
a70facdab4 | |||
4083f9f3dd | |||
7ead2bb875 | |||
19d01c563e | |||
dfe7cfc91c | |||
01443e445d | |||
e16eb49f51 | |||
5d5138e8e6 | |||
e1d6e29523 | |||
49657ad2e5 | |||
b40d353994 | |||
62ffa53add | |||
64dce4d8b1 | |||
02588b2672 | |||
3d1ac2ac0b | |||
ff5ce29fd7 |
@ -15,6 +15,7 @@ on:
|
||||
env:
|
||||
CUT_RELEASE_PR: ${{ github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }}
|
||||
BUILD_RELEASE: ${{ github.event_name == 'release' || github.event_name == 'schedule' || github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }}
|
||||
NOTES: ${{ github.event_name == 'release' && github.event.release.body || format('Non-release build, commit {0}', github.sha) }}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
@ -25,7 +26,6 @@ jobs:
|
||||
runs-on: ubuntu-22.04 # seperate job on Ubuntu for easy string manipulations (compared to Windows)
|
||||
outputs:
|
||||
version: ${{ steps.export_version.outputs.version }}
|
||||
notes: ${{ steps.export_version.outputs.notes }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@ -55,8 +55,6 @@ jobs:
|
||||
# TODO: see if we need to inject updater nightly URL here https://dl.zoo.dev/releases/modeling-app/nightly/last_update.json
|
||||
|
||||
- name: Generate release notes
|
||||
env:
|
||||
NOTES: ${{ github.event_name == 'release' && github.event.release.body || format('Non-release build, commit {0}', github.sha) }}
|
||||
run: |
|
||||
echo "$NOTES" > release-notes.md
|
||||
cat release-notes.md
|
||||
@ -84,9 +82,6 @@ jobs:
|
||||
path: |
|
||||
electron-builder.yml
|
||||
|
||||
- id: export_notes
|
||||
run: echo "notes=`cat release-notes.md'`" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Prepare electron-builder.yml file for updater test
|
||||
if: ${{ env.CUT_RELEASE_PR == 'true' }}
|
||||
run: |
|
||||
@ -262,7 +257,6 @@ jobs:
|
||||
VERSION_NO_V: ${{ needs.prepare-files.outputs.version }}
|
||||
VERSION: ${{ github.event_name == 'schedule' && needs.prepare-files.outputs.version || format('v{0}', needs.prepare-files.outputs.version) }}
|
||||
PUB_DATE: ${{ github.event_name == 'release' && github.event.release.created_at || github.event.repository.updated_at }}
|
||||
NOTES: ${{ needs.prepare-files.outputs.notes }}
|
||||
BUCKET_DIR: ${{ github.event_name == 'schedule' && 'dl.kittycad.io/releases/modeling-app/nightly' || 'dl.kittycad.io/releases/modeling-app' }}
|
||||
WEBSITE_DIR: ${{ github.event_name == 'schedule' && 'dl.zoo.dev/releases/modeling-app/nightly' || 'dl.zoo.dev/releases/modeling-app' }}
|
||||
URL_CODED_NAME: ${{ github.event_name == 'schedule' && 'Zoo%20Modeling%20App%20%28Nightly%29' || 'Zoo%20Modeling%20App' }}
|
||||
|
28722
docs/kcl/std.json
@ -16,8 +16,8 @@ A sketch is a collection of paths.
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `id` |`string`| The id of the sketch (this will change when the engine's reference to it changes. | No |
|
||||
| `value` |`[` [`Path`](/docs/kcl/types/Path) `]`| The paths in the sketch. | No |
|
||||
| `id` |`string`| The id of the sketch (this will change when the engine's reference to it changes). | No |
|
||||
| `paths` |`[` [`Path`](/docs/kcl/types/Path) `]`| The paths in the sketch. | No |
|
||||
| `on` |[`SketchSurface`](/docs/kcl/types/SketchSurface)| What the sketch is on (can be a plane or a face). | No |
|
||||
| `start` |[`BasePath`](/docs/kcl/types/BasePath)| The starting path. | No |
|
||||
| `tags` |`object`| Tag identifiers that have been declared in this sketch. | No |
|
||||
|
@ -25,8 +25,8 @@ A sketch is a collection of paths.
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `sketch`| | No |
|
||||
| `id` |`string`| The id of the sketch (this will change when the engine's reference to it changes. | No |
|
||||
| `value` |`[` [`Path`](/docs/kcl/types/Path) `]`| The paths in the sketch. | No |
|
||||
| `id` |`string`| The id of the sketch (this will change when the engine's reference to it changes). | No |
|
||||
| `paths` |`[` [`Path`](/docs/kcl/types/Path) `]`| The paths in the sketch. | No |
|
||||
| `on` |[`SketchSurface`](/docs/kcl/types/SketchSurface)| What the sketch is on (can be a plane or a face). | No |
|
||||
| `start` |[`BasePath`](/docs/kcl/types/BasePath)| The starting path. | No |
|
||||
| `tags` |`object`| Tag identifiers that have been declared in this sketch. | No |
|
||||
|
@ -18,7 +18,7 @@ Engine information for a tag.
|
||||
|----------|------|-------------|----------|
|
||||
| `id` |`string`| The id of the tagged object. | No |
|
||||
| `sketch` |`string`| The sketch the tag is on. | No |
|
||||
| `path` |[`BasePath`](/docs/kcl/types/BasePath)| The path the tag is on. | No |
|
||||
| `path` |[`Path`](/docs/kcl/types/Path)| The path the tag is on. | No |
|
||||
| `surface` |[`ExtrudeSurface`](/docs/kcl/types/ExtrudeSurface)| The surface information for the tag. | No |
|
||||
|
||||
|
||||
|
@ -55,6 +55,53 @@ test.describe('Onboarding tests', () => {
|
||||
await expect(page.locator('.cm-content')).toContainText('// Shelf Bracket')
|
||||
})
|
||||
|
||||
test(
|
||||
'Desktop: fresh onboarding executes and loads',
|
||||
{ tag: '@electron' },
|
||||
async ({ browserName: _ }, testInfo) => {
|
||||
const { electronApp, page } = await setupElectron({
|
||||
testInfo,
|
||||
appSettings: {
|
||||
app: {
|
||||
onboardingStatus: 'incomplete',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
})
|
||||
|
||||
const u = await getUtils(page)
|
||||
|
||||
const viewportSize = { width: 1200, height: 500 }
|
||||
await page.setViewportSize(viewportSize)
|
||||
|
||||
// Locators and constants
|
||||
const newProjectButton = page.getByRole('button', { name: 'New project' })
|
||||
const projectLink = page.getByTestId('project-link')
|
||||
|
||||
await test.step(`Create a project and open to the onboarding`, async () => {
|
||||
await newProjectButton.click()
|
||||
await projectLink.click()
|
||||
await test.step(`Ensure the engine connection works by testing the sketch button`, async () => {
|
||||
await u.waitForPageLoad()
|
||||
})
|
||||
})
|
||||
|
||||
await test.step(`Ensure we see the onboarding stuff`, async () => {
|
||||
// Test that the onboarding pane loaded
|
||||
await expect(
|
||||
page.getByText('Welcome to Modeling App! This')
|
||||
).toBeVisible()
|
||||
|
||||
// *and* that the code is shown in the editor
|
||||
await expect(page.locator('.cm-content')).toContainText(
|
||||
'// Shelf Bracket'
|
||||
)
|
||||
})
|
||||
|
||||
await electronApp.close()
|
||||
}
|
||||
)
|
||||
|
||||
test('Code resets after confirmation', async ({ page }) => {
|
||||
const initialCode = `sketch001 = startSketchOn('XZ')`
|
||||
|
||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 44 KiB |
@ -888,7 +888,17 @@ export async function setupElectron({
|
||||
const tempSettingsFilePath = join(projectDirName, SETTINGS_FILE_NAME)
|
||||
const settingsOverrides = TOML.stringify(
|
||||
appSettings
|
||||
? { settings: appSettings }
|
||||
? {
|
||||
settings: {
|
||||
...TEST_SETTINGS,
|
||||
...appSettings,
|
||||
app: {
|
||||
...TEST_SETTINGS.app,
|
||||
projectDirectory: projectDirName,
|
||||
...appSettings.app,
|
||||
},
|
||||
},
|
||||
}
|
||||
: {
|
||||
settings: {
|
||||
...TEST_SETTINGS,
|
||||
|
@ -292,7 +292,7 @@ test.describe(`Testing gizmo, fixture-based`, () => {
|
||||
await test.step(`Verify the camera moved`, async () => {
|
||||
await scene.expectState({
|
||||
camera: {
|
||||
position: [0, -23865.37, 11073.54],
|
||||
position: [0, -23865.37, 11073.53],
|
||||
target: [0, 0, 0],
|
||||
},
|
||||
})
|
||||
|
@ -430,7 +430,6 @@ test.describe('Testing settings', () => {
|
||||
await test.step('Check color of logo changed when in modeling view', async () => {
|
||||
await page.getByRole('button', { name: 'New project' }).click()
|
||||
await page.getByTestId('project-link').first().click()
|
||||
await page.getByRole('button', { name: 'Dismiss' }).click()
|
||||
await changeColor('58')
|
||||
await expect(logoLink).toHaveCSS('--primary-hue', '58')
|
||||
})
|
||||
|
@ -107,6 +107,13 @@
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"loaded_filament_idx": {
|
||||
"description": "The currently loaded filament index.",
|
||||
"format": "uint",
|
||||
"minimum": 0,
|
||||
"nullable": true,
|
||||
"type": "integer"
|
||||
},
|
||||
"nozzle_diameter": {
|
||||
"description": "Diameter of the extrusion nozzle, in mm.",
|
||||
"format": "double",
|
||||
@ -285,6 +292,21 @@
|
||||
"type"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"description": "Unknown material",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": [
|
||||
"unknown"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -974,7 +996,7 @@
|
||||
},
|
||||
"description": "",
|
||||
"title": "machine-api",
|
||||
"version": "0.1.0"
|
||||
"version": "0.1.1"
|
||||
},
|
||||
"openapi": "3.0.3",
|
||||
"paths": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "zoo-modeling-app",
|
||||
"version": "0.26.0",
|
||||
"version": "0.26.1",
|
||||
"private": true,
|
||||
"productName": "Zoo Modeling App",
|
||||
"author": {
|
||||
@ -161,7 +161,7 @@
|
||||
"@types/isomorphic-fetch": "^0.0.39",
|
||||
"@types/minimist": "^1.2.5",
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/node": "^22.5.0",
|
||||
"@types/node": "^22.7.8",
|
||||
"@types/pixelmatch": "^5.2.6",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
"@types/react": "^18.3.4",
|
||||
|
@ -92,6 +92,7 @@ export class CameraControls {
|
||||
target: Vector3
|
||||
domElement: HTMLCanvasElement
|
||||
isDragging: boolean
|
||||
wasDragging: boolean
|
||||
mouseDownPosition: Vector2
|
||||
mouseNewPosition: Vector2
|
||||
rotationSpeed = 0.3
|
||||
@ -233,6 +234,7 @@ export class CameraControls {
|
||||
this.target = new Vector3()
|
||||
this.domElement = domElement
|
||||
this.isDragging = false
|
||||
this.wasDragging = false
|
||||
this.mouseDownPosition = new Vector2()
|
||||
this.mouseNewPosition = new Vector2()
|
||||
|
||||
@ -363,6 +365,8 @@ export class CameraControls {
|
||||
onMouseDown = (event: PointerEvent) => {
|
||||
this.domElement.setPointerCapture(event.pointerId)
|
||||
this.isDragging = true
|
||||
// Reset the wasDragging flag to false when starting a new drag
|
||||
this.wasDragging = false
|
||||
this.mouseDownPosition.set(event.clientX, event.clientY)
|
||||
let interaction = this.getInteractionType(event)
|
||||
if (interaction === 'none') return
|
||||
@ -392,6 +396,10 @@ export class CameraControls {
|
||||
const interaction = this.getInteractionType(event)
|
||||
if (interaction === 'none') return
|
||||
|
||||
// If there's a valid interaction and the mouse is moving,
|
||||
// our past (and current) interaction was a drag.
|
||||
this.wasDragging = true
|
||||
|
||||
if (this.syncDirection === 'engineToClient') {
|
||||
this.moveSender.send(() => {
|
||||
this.doMove(interaction, [event.clientX, event.clientY])
|
||||
@ -399,6 +407,7 @@ export class CameraControls {
|
||||
return
|
||||
}
|
||||
|
||||
// else "clientToEngine" (Sketch Mode) or forceUpdate
|
||||
// Implement camera movement logic here based on deltaMove
|
||||
// For example, for rotating the camera around the target:
|
||||
if (interaction === 'rotate') {
|
||||
@ -427,6 +436,9 @@ export class CameraControls {
|
||||
* under the cursor. This recently moved from being handled in App.tsx.
|
||||
* This might not be the right spot, but it is more consolidated.
|
||||
*/
|
||||
|
||||
// Clear any previous drag state
|
||||
this.wasDragging = false
|
||||
if (this.syncDirection === 'engineToClient') {
|
||||
const newCmdId = uuidv4()
|
||||
|
||||
|
@ -338,6 +338,11 @@ export class SceneEntities {
|
||||
sceneInfra.setCallbacks({
|
||||
onClick: async (args) => {
|
||||
if (!args) return
|
||||
// If there is a valid camera interaction that matches, do that instead
|
||||
const interaction = sceneInfra.camControls.getInteractionType(
|
||||
args.mouseEvent
|
||||
)
|
||||
if (interaction !== 'none') return
|
||||
if (args.mouseEvent.which !== 1) return
|
||||
const { intersectionPoint } = args
|
||||
if (!intersectionPoint?.twoD || !sketchDetails?.sketchPathToNode) return
|
||||
@ -407,7 +412,7 @@ export class SceneEntities {
|
||||
if (err(sketch)) return Promise.reject(sketch)
|
||||
if (!sketch) return Promise.reject('sketch not found')
|
||||
|
||||
if (!isArray(sketch?.value))
|
||||
if (!isArray(sketch?.paths))
|
||||
return {
|
||||
truncatedAst,
|
||||
programMemoryOverride,
|
||||
@ -435,7 +440,7 @@ export class SceneEntities {
|
||||
maybeModdedAst,
|
||||
sketch.start.__geoMeta.sourceRange
|
||||
)
|
||||
if (sketch?.value?.[0]?.type !== 'Circle') {
|
||||
if (sketch?.paths?.[0]?.type !== 'Circle') {
|
||||
const _profileStart = createProfileStartHandle({
|
||||
from: sketch.start.from,
|
||||
id: sketch.start.__geoMeta.id,
|
||||
@ -451,16 +456,16 @@ export class SceneEntities {
|
||||
this.activeSegments[JSON.stringify(segPathToNode)] = _profileStart
|
||||
}
|
||||
const callbacks: (() => SegmentOverlayPayload | null)[] = []
|
||||
sketch.value.forEach((segment, index) => {
|
||||
sketch.paths.forEach((segment, index) => {
|
||||
let segPathToNode = getNodePathFromSourceRange(
|
||||
maybeModdedAst,
|
||||
segment.__geoMeta.sourceRange
|
||||
)
|
||||
if (
|
||||
draftExpressionsIndices &&
|
||||
(sketch.value[index - 1] || sketch.start)
|
||||
(sketch.paths[index - 1] || sketch.start)
|
||||
) {
|
||||
const previousSegment = sketch.value[index - 1] || sketch.start
|
||||
const previousSegment = sketch.paths[index - 1] || sketch.start
|
||||
const previousSegmentPathToNode = getNodePathFromSourceRange(
|
||||
maybeModdedAst,
|
||||
previousSegment.__geoMeta.sourceRange
|
||||
@ -511,7 +516,7 @@ export class SceneEntities {
|
||||
to: segment.to,
|
||||
}
|
||||
const result = initSegment({
|
||||
prevSegment: sketch.value[index - 1],
|
||||
prevSegment: sketch.paths[index - 1],
|
||||
callExpName,
|
||||
input,
|
||||
id: segment.__geoMeta.id,
|
||||
@ -610,9 +615,9 @@ export class SceneEntities {
|
||||
variableDeclarationName
|
||||
)
|
||||
if (err(sg)) return Promise.reject(sg)
|
||||
const lastSeg = sg?.value?.slice(-1)[0] || sg.start
|
||||
const lastSeg = sg?.paths?.slice(-1)[0] || sg.start
|
||||
|
||||
const index = sg.value.length // because we've added a new segment that's not in the memory yet, no need for `-1`
|
||||
const index = sg.paths.length // because we've added a new segment that's not in the memory yet, no need for `-1`
|
||||
const mod = addNewSketchLn({
|
||||
node: _ast,
|
||||
programMemory: kclManager.programMemory,
|
||||
@ -645,7 +650,13 @@ export class SceneEntities {
|
||||
sceneInfra.setCallbacks({
|
||||
onClick: async (args) => {
|
||||
if (!args) return
|
||||
// If there is a valid camera interaction that matches, do that instead
|
||||
const interaction = sceneInfra.camControls.getInteractionType(
|
||||
args.mouseEvent
|
||||
)
|
||||
if (interaction !== 'none') return
|
||||
if (args.mouseEvent.which !== 1) return
|
||||
|
||||
const { intersectionPoint } = args
|
||||
let intersection2d = intersectionPoint?.twoD
|
||||
const profileStart = args.intersects
|
||||
@ -654,7 +665,7 @@ export class SceneEntities {
|
||||
|
||||
let modifiedAst
|
||||
if (profileStart) {
|
||||
const lastSegment = sketch.value.slice(-1)[0]
|
||||
const lastSegment = sketch.paths.slice(-1)[0]
|
||||
modifiedAst = addCallExpressionsToPipe({
|
||||
node: kclManager.ast,
|
||||
programMemory: kclManager.programMemory,
|
||||
@ -686,7 +697,7 @@ export class SceneEntities {
|
||||
})
|
||||
if (trap(modifiedAst)) return Promise.reject(modifiedAst)
|
||||
} else if (intersection2d) {
|
||||
const lastSegment = sketch.value.slice(-1)[0]
|
||||
const lastSegment = sketch.paths.slice(-1)[0]
|
||||
const tmp = addNewSketchLn({
|
||||
node: kclManager.ast,
|
||||
programMemory: kclManager.programMemory,
|
||||
@ -735,7 +746,6 @@ export class SceneEntities {
|
||||
},
|
||||
})
|
||||
},
|
||||
...this.mouseEnterLeaveCallbacks(),
|
||||
})
|
||||
}
|
||||
setupDraftRectangle = async (
|
||||
@ -817,7 +827,7 @@ export class SceneEntities {
|
||||
variableDeclarationName
|
||||
)
|
||||
if (err(sketch)) return Promise.reject(sketch)
|
||||
const sgPaths = sketch.value
|
||||
const sgPaths = sketch.paths
|
||||
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
|
||||
|
||||
this.updateSegment(sketch.start, 0, 0, _ast, orthoFactor, sketch)
|
||||
@ -826,6 +836,11 @@ export class SceneEntities {
|
||||
)
|
||||
},
|
||||
onClick: async (args) => {
|
||||
// If there is a valid camera interaction that matches, do that instead
|
||||
const interaction = sceneInfra.camControls.getInteractionType(
|
||||
args.mouseEvent
|
||||
)
|
||||
if (interaction !== 'none') return
|
||||
// Commit the rectangle to the full AST/code and return to sketch.idle
|
||||
const cornerPoint = args.intersectionPoint?.twoD
|
||||
if (!cornerPoint || args.mouseEvent.button !== 0) return
|
||||
@ -868,7 +883,7 @@ export class SceneEntities {
|
||||
variableDeclarationName
|
||||
)
|
||||
if (err(sketch)) return
|
||||
const sgPaths = sketch.value
|
||||
const sgPaths = sketch.paths
|
||||
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
|
||||
|
||||
// Update the starting segment of the THREEjs scene
|
||||
@ -985,7 +1000,7 @@ export class SceneEntities {
|
||||
variableDeclarationName
|
||||
)
|
||||
if (err(sketch)) return
|
||||
const sgPaths = sketch.value
|
||||
const sgPaths = sketch.paths
|
||||
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
|
||||
|
||||
this.updateSegment(sketch.start, 0, 0, _ast, orthoFactor, sketch)
|
||||
@ -994,6 +1009,11 @@ export class SceneEntities {
|
||||
)
|
||||
},
|
||||
onClick: async (args) => {
|
||||
// If there is a valid camera interaction that matches, do that instead
|
||||
const interaction = sceneInfra.camControls.getInteractionType(
|
||||
args.mouseEvent
|
||||
)
|
||||
if (interaction !== 'none') return
|
||||
// Commit the rectangle to the full AST/code and return to sketch.idle
|
||||
const cornerPoint = args.intersectionPoint?.twoD
|
||||
if (!cornerPoint || args.mouseEvent.button !== 0) return
|
||||
@ -1105,7 +1125,7 @@ export class SceneEntities {
|
||||
|
||||
const pipeIndex = pathToNode[pathToNodeIndex + 1][0] as number
|
||||
if (addingNewSegmentStatus === 'nothing') {
|
||||
const prevSegment = sketch.value[pipeIndex - 2]
|
||||
const prevSegment = sketch.paths[pipeIndex - 2]
|
||||
const mod = addNewSketchLn({
|
||||
node: kclManager.ast,
|
||||
programMemory: kclManager.programMemory,
|
||||
@ -1157,6 +1177,11 @@ export class SceneEntities {
|
||||
},
|
||||
onMove: () => {},
|
||||
onClick: (args) => {
|
||||
// If there is a valid camera interaction that matches, do that instead
|
||||
const interaction = sceneInfra.camControls.getInteractionType(
|
||||
args.mouseEvent
|
||||
)
|
||||
if (interaction !== 'none') return
|
||||
if (args?.mouseEvent.which !== 1) return
|
||||
if (!args || !args.selected) {
|
||||
sceneInfra.modelingSend({
|
||||
@ -1345,7 +1370,7 @@ export class SceneEntities {
|
||||
}
|
||||
if (!sketch) return
|
||||
|
||||
const sgPaths = sketch.value
|
||||
const sgPaths = sketch.paths
|
||||
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
|
||||
|
||||
this.updateSegment(
|
||||
@ -1393,7 +1418,7 @@ export class SceneEntities {
|
||||
modifiedAst,
|
||||
segment.__geoMeta.sourceRange
|
||||
)
|
||||
const sgPaths = sketch.value
|
||||
const sgPaths = sketch.paths
|
||||
const originalPathToNodeStr = JSON.stringify(segPathToNode)
|
||||
segPathToNode[1][0] = varDecIndex
|
||||
const pathToNodeStr = JSON.stringify(segPathToNode)
|
||||
@ -1701,7 +1726,7 @@ function prepareTruncatedMemoryAndAst(
|
||||
variableDeclarationName
|
||||
)
|
||||
if (err(sg)) return sg
|
||||
const lastSeg = sg?.value.slice(-1)[0]
|
||||
const lastSeg = sg?.paths.slice(-1)[0]
|
||||
if (draftSegment) {
|
||||
// truncatedAst needs to setup with another segment at the end
|
||||
let newSegment
|
||||
|
@ -213,7 +213,7 @@ export class SceneInfra {
|
||||
to: Coords2d
|
||||
angle?: number
|
||||
}): SegmentOverlayPayload | null {
|
||||
if (group.userData.pathToNode && arrowGroup) {
|
||||
if (!group.userData.draft && group.userData.pathToNode && arrowGroup) {
|
||||
const vector = new Vector3(0, 0, 0)
|
||||
|
||||
// Get the position of the object3D in world space
|
||||
|
@ -58,7 +58,7 @@ import { err } from 'lib/trap'
|
||||
|
||||
interface CreateSegmentArgs {
|
||||
input: SegmentInputs
|
||||
prevSegment: Sketch['value'][number]
|
||||
prevSegment: Sketch['paths'][number]
|
||||
id: string
|
||||
pathToNode: PathToNode
|
||||
isDraftSegment?: boolean
|
||||
@ -72,7 +72,7 @@ interface CreateSegmentArgs {
|
||||
|
||||
interface UpdateSegmentArgs {
|
||||
input: SegmentInputs
|
||||
prevSegment: Sketch['value'][number]
|
||||
prevSegment: Sketch['paths'][number]
|
||||
group: Group
|
||||
sceneInfra: SceneInfra
|
||||
scale?: number
|
||||
@ -147,6 +147,7 @@ class StraightSegment implements SegmentUtils {
|
||||
segmentGroup.name = STRAIGHT_SEGMENT
|
||||
segmentGroup.userData = {
|
||||
type: STRAIGHT_SEGMENT,
|
||||
draft: isDraftSegment,
|
||||
id,
|
||||
from,
|
||||
to,
|
||||
@ -347,6 +348,7 @@ class TangentialArcToSegment implements SegmentUtils {
|
||||
mesh.name = meshName
|
||||
group.userData = {
|
||||
type: TANGENTIAL_ARC_TO_SEGMENT,
|
||||
draft: isDraftSegment,
|
||||
id,
|
||||
from,
|
||||
to,
|
||||
@ -515,11 +517,18 @@ class CircleSegment implements SegmentUtils {
|
||||
const meshType = isDraftSegment ? CIRCLE_SEGMENT_DASH : CIRCLE_SEGMENT_BODY
|
||||
const arrowGroup = createArrowhead(scale, theme, color)
|
||||
const circleCenterGroup = createCircleCenterHandle(scale, theme, color)
|
||||
// A radius indicator that appears from the center to the perimeter
|
||||
const radiusIndicatorGroup = createLengthIndicator({
|
||||
from: center,
|
||||
to: [center[0] + radius, center[1]],
|
||||
scale,
|
||||
})
|
||||
|
||||
arcMesh.userData.type = meshType
|
||||
arcMesh.name = meshType
|
||||
group.userData = {
|
||||
type: CIRCLE_SEGMENT,
|
||||
draft: isDraftSegment,
|
||||
id,
|
||||
from,
|
||||
radius,
|
||||
@ -532,7 +541,7 @@ class CircleSegment implements SegmentUtils {
|
||||
}
|
||||
group.name = CIRCLE_SEGMENT
|
||||
|
||||
group.add(arcMesh, arrowGroup, circleCenterGroup)
|
||||
group.add(arcMesh, arrowGroup, circleCenterGroup, radiusIndicatorGroup)
|
||||
const updateOverlaysCallback = this.update({
|
||||
prevSegment,
|
||||
input,
|
||||
@ -564,6 +573,9 @@ class CircleSegment implements SegmentUtils {
|
||||
group.userData.radius = radius
|
||||
group.userData.prevSegment = prevSegment
|
||||
const arrowGroup = group.getObjectByName(ARROWHEAD) as Group
|
||||
const radiusLengthIndicator = group.getObjectByName(
|
||||
SEGMENT_LENGTH_LABEL
|
||||
) as Group
|
||||
const circleCenterHandle = group.getObjectByName(
|
||||
CIRCLE_CENTER_HANDLE
|
||||
) as Group
|
||||
@ -581,11 +593,14 @@ class CircleSegment implements SegmentUtils {
|
||||
}
|
||||
|
||||
if (arrowGroup) {
|
||||
arrowGroup.position.set(
|
||||
center[0] + Math.cos(Math.PI / 4) * radius,
|
||||
center[1] + Math.sin(Math.PI / 4) * radius,
|
||||
0
|
||||
)
|
||||
// The arrowhead is placed at the perimeter of the circle,
|
||||
// pointing up and to the right
|
||||
const arrowPoint = {
|
||||
x: center[0] + Math.cos(Math.PI / 4) * radius,
|
||||
y: center[1] + Math.sin(Math.PI / 4) * radius,
|
||||
}
|
||||
|
||||
arrowGroup.position.set(arrowPoint.x, arrowPoint.y, 0)
|
||||
|
||||
const arrowheadAngle = Math.PI / 4
|
||||
arrowGroup.quaternion.setFromUnitVectors(
|
||||
@ -596,6 +611,31 @@ class CircleSegment implements SegmentUtils {
|
||||
arrowGroup.visible = isHandlesVisible
|
||||
}
|
||||
|
||||
if (radiusLengthIndicator) {
|
||||
// The radius indicator is placed at the midpoint of the radius,
|
||||
// at a 45 degree CCW angle from the positive X-axis
|
||||
const indicatorPoint = {
|
||||
x: center[0] + (Math.cos(Math.PI / 4) * radius) / 2,
|
||||
y: center[1] + (Math.sin(Math.PI / 4) * radius) / 2,
|
||||
}
|
||||
const labelWrapper = radiusLengthIndicator.getObjectByName(
|
||||
SEGMENT_LENGTH_LABEL_TEXT
|
||||
) as CSS2DObject
|
||||
const labelWrapperElem = labelWrapper.element as HTMLDivElement
|
||||
const label = labelWrapperElem.children[0] as HTMLParagraphElement
|
||||
label.innerText = `${roundOff(radius)}`
|
||||
label.classList.add(SEGMENT_LENGTH_LABEL_TEXT)
|
||||
const isPlaneBackFace = center[0] > indicatorPoint.x
|
||||
label.style.setProperty(
|
||||
'--degree',
|
||||
`${isPlaneBackFace ? '45' : '-45'}deg`
|
||||
)
|
||||
label.style.setProperty('--x', `0px`)
|
||||
label.style.setProperty('--y', `0px`)
|
||||
labelWrapper.position.set(indicatorPoint.x, indicatorPoint.y, 0)
|
||||
radiusLengthIndicator.visible = isHandlesVisible
|
||||
}
|
||||
|
||||
if (circleCenterHandle) {
|
||||
circleCenterHandle.position.set(center[0], center[1], 0)
|
||||
circleCenterHandle.scale.set(scale, scale, scale)
|
||||
|
@ -140,6 +140,13 @@ const FileTreeItem = ({
|
||||
async (eventType, path) => {
|
||||
// Don't try to read a file that was removed.
|
||||
if (isCurrentFile && eventType !== 'unlink') {
|
||||
// Prevents a cyclic read / write causing editor problems such as
|
||||
// misplaced cursor positions.
|
||||
if (codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher) {
|
||||
codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher = false
|
||||
return
|
||||
}
|
||||
|
||||
let code = await window.electron.readFile(path, { encoding: 'utf-8' })
|
||||
code = normalizeLineEndings(code)
|
||||
codeManager.updateCodeStateEditor(code)
|
||||
|
@ -644,6 +644,7 @@ export const ModelingMachineProvider = ({
|
||||
input.plane
|
||||
)
|
||||
await kclManager.updateAst(modifiedAst, false)
|
||||
sceneInfra.camControls.enableRotate = false
|
||||
sceneInfra.camControls.syncDirection = 'clientToEngine'
|
||||
|
||||
await letEngineAnimateAndSyncCamAfter(
|
||||
|
@ -95,7 +95,7 @@ export const processMemory = (programMemory: ProgramMemory) => {
|
||||
return rest
|
||||
})
|
||||
} else if (!err(sg)) {
|
||||
processedMemory[key] = sg.value.map(({ __geoMeta, ...rest }: Path) => {
|
||||
processedMemory[key] = sg.paths.map(({ __geoMeta, ...rest }: Path) => {
|
||||
return rest
|
||||
})
|
||||
} else if ((val.type as any) === 'Function') {
|
||||
|
@ -255,10 +255,14 @@ export const Stream = () => {
|
||||
}, [mediaStream])
|
||||
|
||||
const handleMouseUp: MouseEventHandler<HTMLDivElement> = (e) => {
|
||||
// If we've got no stream or connection, don't do anything
|
||||
if (!isNetworkOkay) return
|
||||
if (!videoRef.current) return
|
||||
// If we're in sketch mode, don't send a engine-side select event
|
||||
if (state.matches('Sketch')) return
|
||||
if (state.matches({ idle: 'showPlanes' })) return
|
||||
// If we're mousing up from a camera drag, don't send a select event
|
||||
if (sceneInfra.camControls.wasDragging === true) return
|
||||
|
||||
if (btnName(e.nativeEvent).left) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
|
@ -32,7 +32,7 @@ const mySketch001 = startSketchOn('XY')
|
||||
sourceRange: [46, 71],
|
||||
},
|
||||
},
|
||||
value: [
|
||||
paths: [
|
||||
{
|
||||
type: 'ToPoint',
|
||||
tag: null,
|
||||
@ -96,7 +96,7 @@ const mySketch001 = startSketchOn('XY')
|
||||
on: expect.any(Object),
|
||||
start: expect.any(Object),
|
||||
type: 'Sketch',
|
||||
value: [
|
||||
paths: [
|
||||
{
|
||||
type: 'ToPoint',
|
||||
from: [0, 0],
|
||||
@ -202,7 +202,7 @@ const sk2 = startSketchOn('XY')
|
||||
info: expect.any(Object),
|
||||
},
|
||||
},
|
||||
value: [
|
||||
paths: [
|
||||
{
|
||||
type: 'ToPoint',
|
||||
from: [0, 0],
|
||||
@ -294,7 +294,7 @@ const sk2 = startSketchOn('XY')
|
||||
info: expect.any(Object),
|
||||
},
|
||||
},
|
||||
value: [
|
||||
paths: [
|
||||
{
|
||||
type: 'ToPoint',
|
||||
from: [0, 0],
|
||||
|
@ -20,6 +20,8 @@ export default class CodeManager {
|
||||
private _hotkeys: { [key: string]: () => void } = {}
|
||||
private timeoutWriter: ReturnType<typeof setTimeout> | undefined = undefined
|
||||
|
||||
public writeCausedByAppCheckedInFileTreeFileSystemWatcher = false
|
||||
|
||||
constructor() {
|
||||
if (isDesktop()) {
|
||||
this.code = ''
|
||||
@ -120,6 +122,7 @@ export default class CodeManager {
|
||||
// and file-system watchers which read, will receive empty data during
|
||||
// writes.
|
||||
clearTimeout(this.timeoutWriter)
|
||||
this.writeCausedByAppCheckedInFileTreeFileSystemWatcher = true
|
||||
this.timeoutWriter = setTimeout(() => {
|
||||
// Wait one event loop to give a chance for params to be set
|
||||
// Save the file to disk
|
||||
|
@ -58,7 +58,7 @@ const newVar = myVar + 1`
|
||||
`
|
||||
const mem = await exe(code)
|
||||
// geo is three js buffer geometry and is very bloated to have in tests
|
||||
const minusGeo = mem.get('mySketch')?.value?.value
|
||||
const minusGeo = mem.get('mySketch')?.value?.paths
|
||||
expect(minusGeo).toEqual([
|
||||
{
|
||||
type: 'ToPoint',
|
||||
@ -175,7 +175,7 @@ const newVar = myVar + 1`
|
||||
info: expect.any(Object),
|
||||
},
|
||||
},
|
||||
value: [
|
||||
paths: [
|
||||
{
|
||||
type: 'ToPoint',
|
||||
to: [1, 1],
|
||||
@ -367,7 +367,7 @@ describe('testing math operators', () => {
|
||||
const mem = await exe(code)
|
||||
const sketch = sketchFromKclValue(mem.get('part001'), 'part001')
|
||||
// result of `-legLen(5, min(3, 999))` should be -4
|
||||
const yVal = (sketch as Sketch).value?.[0]?.to?.[1]
|
||||
const yVal = (sketch as Sketch).paths?.[0]?.to?.[1]
|
||||
expect(yVal).toBe(-4)
|
||||
})
|
||||
it('test that % substitution feeds down CallExp->ArrExp->UnaryExp->CallExp', async () => {
|
||||
@ -385,8 +385,8 @@ describe('testing math operators', () => {
|
||||
const mem = await exe(code)
|
||||
const sketch = sketchFromKclValue(mem.get('part001'), 'part001')
|
||||
// expect -legLen(segLen('seg01'), myVar) to equal -4 setting the y value back to 0
|
||||
expect((sketch as Sketch).value?.[1]?.from).toEqual([3, 4])
|
||||
expect((sketch as Sketch).value?.[1]?.to).toEqual([6, 0])
|
||||
expect((sketch as Sketch).paths?.[1]?.from).toEqual([3, 4])
|
||||
expect((sketch as Sketch).paths?.[1]?.to).toEqual([6, 0])
|
||||
const removedUnaryExp = code.replace(
|
||||
`-legLen(segLen(seg01), myVar)`,
|
||||
`legLen(segLen(seg01), myVar)`
|
||||
@ -398,7 +398,7 @@ describe('testing math operators', () => {
|
||||
)
|
||||
|
||||
// without the minus sign, the y value should be 8
|
||||
expect((removedUnaryExpMemSketch as Sketch).value?.[1]?.to).toEqual([6, 8])
|
||||
expect((removedUnaryExpMemSketch as Sketch).paths?.[1]?.to).toEqual([6, 8])
|
||||
})
|
||||
it('with nested callExpression and binaryExpression', async () => {
|
||||
const code = 'const myVar = 2 + min(100, -1 + legLen(5, 3))'
|
||||
|
@ -717,7 +717,7 @@ export function isLinesParallelAndConstrained(
|
||||
constraintType === 'angle' || constraintLevel === 'full'
|
||||
|
||||
// get the previous segment
|
||||
const prevSegment = sg.value[secondaryIndex - 1]
|
||||
const prevSegment = sg.paths[secondaryIndex - 1]
|
||||
const prevSourceRange = prevSegment.__geoMeta.sourceRange
|
||||
|
||||
const isParallelAndConstrained =
|
||||
|
@ -64,7 +64,7 @@ const ARC_SEGMENT_ERR = new Error('Invalid input, expected "arc-segment"')
|
||||
export type Coords2d = [number, number]
|
||||
|
||||
export function getCoordsFromPaths(skGroup: Sketch, index = 0): Coords2d {
|
||||
const currentPath = skGroup?.value?.[index]
|
||||
const currentPath = skGroup?.paths?.[index]
|
||||
if (!currentPath && skGroup?.start) {
|
||||
return skGroup.start.to
|
||||
} else if (!currentPath) {
|
||||
@ -1704,7 +1704,7 @@ export const angledLineThatIntersects: SketchLineHelper = {
|
||||
varName
|
||||
)
|
||||
if (err(sketch)) return sketch
|
||||
const intersectPath = sketch.value.find(
|
||||
const intersectPath = sketch.paths.find(
|
||||
({ tag }: Path) => tag && tag.value === intersectTagName
|
||||
)
|
||||
let offset = 0
|
||||
|
@ -18,7 +18,7 @@ export function getSketchSegmentFromPathToNode(
|
||||
pathToNode: PathToNode
|
||||
):
|
||||
| {
|
||||
segment: Sketch['value'][number]
|
||||
segment: Sketch['paths'][number]
|
||||
index: number
|
||||
}
|
||||
| Error {
|
||||
@ -39,15 +39,15 @@ export function getSketchSegmentFromSourceRange(
|
||||
[rangeStart, rangeEnd]: SourceRange
|
||||
):
|
||||
| {
|
||||
segment: Sketch['value'][number]
|
||||
segment: Sketch['paths'][number]
|
||||
index: number
|
||||
}
|
||||
| Error {
|
||||
const lineIndex = sketch.value.findIndex(
|
||||
const lineIndex = sketch.paths.findIndex(
|
||||
({ __geoMeta: { sourceRange } }: Path) =>
|
||||
sourceRange[0] <= rangeStart && sourceRange[1] >= rangeEnd
|
||||
)
|
||||
const line = sketch.value[lineIndex]
|
||||
const line = sketch.paths[lineIndex]
|
||||
if (line) {
|
||||
return {
|
||||
segment: line,
|
||||
|
@ -1732,7 +1732,7 @@ export function transformAstSketchLines({
|
||||
if (err(_segment)) return _segment
|
||||
referencedSegment = _segment.segment
|
||||
} else {
|
||||
referencedSegment = sketch.value.find(
|
||||
referencedSegment = sketch.paths.find(
|
||||
(path) => path.tag?.value === _referencedSegmentName
|
||||
)
|
||||
}
|
||||
|
9
src/lib/machine-api.d.ts
vendored
@ -138,6 +138,11 @@ export interface components {
|
||||
FdmHardwareConfiguration: {
|
||||
/** @description The filaments the printer has access to. */
|
||||
filaments: components['schemas']['Filament'][]
|
||||
/**
|
||||
* Format: uint
|
||||
* @description The currently loaded filament index.
|
||||
*/
|
||||
loaded_filament_idx?: number | null
|
||||
/**
|
||||
* Format: double
|
||||
* @description Diameter of the extrusion nozzle, in mm.
|
||||
@ -191,6 +196,10 @@ export interface components {
|
||||
/** @enum {string} */
|
||||
type: 'composite'
|
||||
}
|
||||
| {
|
||||
/** @enum {string} */
|
||||
type: 'unknown'
|
||||
}
|
||||
/** @description The hardware configuration of a machine. */
|
||||
HardwareConfiguration:
|
||||
| {
|
||||
|
@ -23,6 +23,9 @@ import { codeManager, editorManager, kclManager } from 'lib/singletons'
|
||||
import { bracket } from 'lib/exampleKcl'
|
||||
import { toSync } from 'lib/utils'
|
||||
import { reportRejection } from 'lib/trap'
|
||||
import { useNetworkContext } from 'hooks/useNetworkContext'
|
||||
import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
||||
import { EngineConnectionStateType } from 'lang/std/engineConnection'
|
||||
|
||||
export const kbdClasses =
|
||||
'py-0.5 px-1 text-sm rounded bg-chalkboard-10 dark:bg-chalkboard-100 border border-chalkboard-50 border-b-2'
|
||||
@ -80,8 +83,20 @@ export const onboardingRoutes = [
|
||||
]
|
||||
|
||||
export function useDemoCode() {
|
||||
const { overallState, immediateState } = useNetworkContext()
|
||||
|
||||
useEffect(() => {
|
||||
if (!editorManager.editorView || codeManager.code === bracket) return
|
||||
// Don't run if the editor isn't loaded or the code is already the bracket
|
||||
if (!editorManager.editorView || codeManager.code === bracket) {
|
||||
return
|
||||
}
|
||||
// Don't run if the network isn't healthy or the connection isn't established
|
||||
if (
|
||||
overallState !== NetworkHealthState.Ok ||
|
||||
immediateState.type !== EngineConnectionStateType.ConnectionEstablished
|
||||
) {
|
||||
return
|
||||
}
|
||||
setTimeout(
|
||||
toSync(async () => {
|
||||
codeManager.updateCodeStateEditor(bracket)
|
||||
@ -89,7 +104,7 @@ export function useDemoCode() {
|
||||
await codeManager.writeToFile()
|
||||
}, reportRejection)
|
||||
)
|
||||
}, [editorManager.editorView])
|
||||
}, [editorManager.editorView, immediateState, overallState])
|
||||
}
|
||||
|
||||
export function useNextClick(newStatus: string) {
|
||||
|
120
src/wasm-lib/Cargo.lock
generated
@ -121,9 +121,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.89"
|
||||
version = "1.0.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
|
||||
checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
@ -176,7 +176,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -187,7 +187,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -204,7 +204,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -465,7 +465,7 @@ dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -656,7 +656,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -667,7 +667,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -722,7 +722,7 @@ checksum = "4078275de501a61ceb9e759d37bdd3d7210e654dbc167ac1a3678ef4435ed57b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@ -751,7 +751,7 @@ dependencies = [
|
||||
"rustfmt-wrapper",
|
||||
"serde",
|
||||
"serde_tokenstream",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -762,7 +762,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -789,7 +789,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -827,7 +827,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -988,7 +988,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1084,7 +1084,7 @@ dependencies = [
|
||||
"inflections",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1612,7 +1612,7 @@ dependencies = [
|
||||
"pretty_assertions",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1684,9 +1684,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-modeling-cmds"
|
||||
version = "0.2.68"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e3aedfcc1d8ea9995ec3eb78a6743c585c9380475c48701797f107489b696aa"
|
||||
checksum = "c6d2160dcb0e5373b1242a760dbf17fb9c12de523c410c11b145381c852b377b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -1716,7 +1716,7 @@ dependencies = [
|
||||
"kittycad-modeling-cmds-macros-impl",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1727,7 +1727,7 @@ checksum = "6607507a8a0e4273b943179f0a3ef8e90712308d1d3095246040c29cfdbf985b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2112,7 +2112,7 @@ dependencies = [
|
||||
"regex",
|
||||
"regex-syntax 0.8.5",
|
||||
"structmeta",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2126,7 +2126,7 @@ dependencies = [
|
||||
"regex",
|
||||
"regex-syntax 0.8.5",
|
||||
"structmeta",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2166,7 +2166,7 @@ dependencies = [
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2224,7 +2224,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2337,9 +2337,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.88"
|
||||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9"
|
||||
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -2391,7 +2391,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"pyo3-macros-backend",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2404,7 +2404,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"pyo3-build-config",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2586,9 +2586,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.0"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@ -2925,7 +2925,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2965,9 +2965,9 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.210"
|
||||
version = "1.0.213"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@ -2983,13 +2983,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.210"
|
||||
version = "1.0.213"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3000,14 +3000,14 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.128"
|
||||
version = "1.0.132"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
||||
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
|
||||
dependencies = [
|
||||
"indexmap 2.6.0",
|
||||
"itoa",
|
||||
@ -3024,7 +3024,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3045,7 +3045,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3182,7 +3182,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta-derive",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3193,7 +3193,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3215,7 +3215,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3237,9 +3237,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.79"
|
||||
version = "2.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
|
||||
checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -3263,7 +3263,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3326,22 +3326,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.64"
|
||||
version = "1.0.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
|
||||
checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.64"
|
||||
version = "1.0.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
|
||||
checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3437,7 +3437,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3579,7 +3579,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3607,7 +3607,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3689,7 +3689,7 @@ checksum = "0ea0b99e8ec44abd6f94a18f28f7934437809dd062820797c52401298116f70e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
@ -3865,7 +3865,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3927,7 +3927,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@ -3962,7 +3962,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@ -4328,7 +4328,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
"syn 2.0.85",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -72,7 +72,7 @@ members = [
|
||||
[workspace.dependencies]
|
||||
http = "1"
|
||||
kittycad = { version = "0.3.23", default-features = false, features = ["js", "requests"] }
|
||||
kittycad-modeling-cmds = { version = "0.2.68", features = ["websocket"] }
|
||||
kittycad-modeling-cmds = { version = "0.2.71", features = ["websocket"] }
|
||||
|
||||
[[test]]
|
||||
name = "executor"
|
||||
@ -83,6 +83,6 @@ name = "modify"
|
||||
path = "tests/modify/main.rs"
|
||||
|
||||
# Example: how to point modeling-api at a different repo (e.g. a branch or a local clone)
|
||||
#[patch."https://github.com/KittyCAD/modeling-api"]
|
||||
#[patch.crates-io]
|
||||
#kittycad-modeling-cmds = { path = "../../../modeling-api/modeling-cmds" }
|
||||
#kittycad-modeling-session = { path = "../../../modeling-api/modeling-session" }
|
||||
|
@ -17,13 +17,13 @@ convert_case = "0.6.0"
|
||||
once_cell = "1.20.2"
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
regex = "1.10"
|
||||
serde = { version = "1.0.210", features = ["derive"] }
|
||||
regex = "1.11"
|
||||
serde = { version = "1.0.213", features = ["derive"] }
|
||||
serde_tokenstream = "0.2"
|
||||
syn = { version = "2.0.79", features = ["full"] }
|
||||
syn = { version = "2.0.85", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0.89"
|
||||
anyhow = "1.0.91"
|
||||
expectorate = "1.1.0"
|
||||
pretty_assertions = "1.4.1"
|
||||
rustfmt-wrapper = "0.2.1"
|
||||
|
@ -15,7 +15,7 @@ databake = "0.1.8"
|
||||
kcl-lib = { path = "../kcl" }
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = { version = "2.0.79", features = ["full"] }
|
||||
syn = { version = "2.0.85", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.4.1"
|
||||
|
@ -6,10 +6,10 @@ edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.89"
|
||||
anyhow = "1.0.91"
|
||||
hyper = { version = "0.14.29", features = ["http1", "server", "tcp"] }
|
||||
kcl-lib = { version = "0.2", path = "../kcl" }
|
||||
pico-args = "0.5.0"
|
||||
serde = { version = "1.0.210", features = ["derive"] }
|
||||
serde = { version = "1.0.213", features = ["derive"] }
|
||||
serde_json = "1.0.128"
|
||||
tokio = { version = "1.40.0", features = ["macros", "rt-multi-thread"] }
|
||||
|
@ -31,7 +31,7 @@ pub struct ServerArgs {
|
||||
/// Where to find the engine.
|
||||
/// If none, uses the prod engine.
|
||||
/// This is useful for testing a local engine instance.
|
||||
/// Overridden by the $LOCAL_ENGINE_ADDR environment variable.
|
||||
/// Overridden by the $ZOO_HOST environment variable.
|
||||
pub engine_address: Option<String>,
|
||||
}
|
||||
|
||||
@ -44,8 +44,8 @@ impl ServerArgs {
|
||||
num_engine_conns: pargs.opt_value_from_str("--num-engine-conns")?.unwrap_or(1),
|
||||
engine_address: pargs.opt_value_from_str("--engine-address")?,
|
||||
};
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
println!("Overriding engine address via $LOCAL_ENGINE_ADDR");
|
||||
if let Ok(addr) = std::env::var("ZOO_HOST") {
|
||||
println!("Overriding engine address via $ZOO_HOST");
|
||||
args.engine_address = Some(addr);
|
||||
}
|
||||
println!("Config is {args:?}");
|
||||
|
@ -11,7 +11,7 @@ keywords = ["kcl", "KittyCAD", "CAD"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.89", features = ["backtrace"] }
|
||||
anyhow = { version = "1.0.91", features = ["backtrace"] }
|
||||
async-recursion = "1.1.1"
|
||||
async-trait = "0.1.83"
|
||||
base64 = "0.22.1"
|
||||
@ -38,11 +38,11 @@ pyo3 = { version = "0.22.5", optional = true }
|
||||
reqwest = { version = "0.12", default-features = false, features = ["stream", "rustls-tls"] }
|
||||
ropey = "1.6.1"
|
||||
schemars = { version = "0.8.17", features = ["impl_json_schema", "url", "uuid1", "preserve_order"] }
|
||||
serde = { version = "1.0.210", features = ["derive"] }
|
||||
serde = { version = "1.0.213", features = ["derive"] }
|
||||
serde_json = "1.0.128"
|
||||
sha2 = "0.10.8"
|
||||
tabled = { version = "0.15.0", optional = true }
|
||||
thiserror = "1.0.64"
|
||||
thiserror = "1.0.65"
|
||||
toml = "0.8.19"
|
||||
ts-rs = { version = "10.0.0", features = ["uuid-impl", "url-impl", "chrono-impl", "no-serde-warnings", "serde-json-impl"] }
|
||||
url = { version = "2.5.2", features = ["serde"] }
|
||||
|
@ -1127,7 +1127,7 @@ pub struct TagEngineInfo {
|
||||
/// The sketch the tag is on.
|
||||
pub sketch: uuid::Uuid,
|
||||
/// The path the tag is on.
|
||||
pub path: Option<BasePath>,
|
||||
pub path: Option<Path>,
|
||||
/// The surface information for the tag.
|
||||
pub surface: Option<ExtrudeSurface>,
|
||||
}
|
||||
@ -1137,10 +1137,10 @@ pub struct TagEngineInfo {
|
||||
#[ts(export)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
pub struct Sketch {
|
||||
/// The id of the sketch (this will change when the engine's reference to it changes.
|
||||
/// The id of the sketch (this will change when the engine's reference to it changes).
|
||||
pub id: uuid::Uuid,
|
||||
/// The paths in the sketch.
|
||||
pub value: Vec<Path>,
|
||||
pub paths: Vec<Path>,
|
||||
/// What the sketch is on (can be a plane or a face).
|
||||
pub on: SketchSurface,
|
||||
/// The starting path.
|
||||
@ -1206,7 +1206,7 @@ impl Sketch {
|
||||
tag_identifier.info = Some(TagEngineInfo {
|
||||
id: base.geo_meta.id,
|
||||
sketch: self.id,
|
||||
path: Some(base.clone()),
|
||||
path: Some(current_path.clone()),
|
||||
surface: None,
|
||||
});
|
||||
|
||||
@ -1215,7 +1215,7 @@ impl Sketch {
|
||||
|
||||
/// Get the path most recently sketched.
|
||||
pub(crate) fn latest_path(&self) -> Option<&Path> {
|
||||
self.value.last()
|
||||
self.paths.last()
|
||||
}
|
||||
|
||||
/// The "pen" is an imaginary pen drawing the path.
|
||||
@ -1658,6 +1658,32 @@ pub enum Path {
|
||||
},
|
||||
}
|
||||
|
||||
/// What kind of path is this?
|
||||
#[derive(Display)]
|
||||
enum PathType {
|
||||
ToPoint,
|
||||
Base,
|
||||
TangentialArc,
|
||||
TangentialArcTo,
|
||||
Circle,
|
||||
Horizontal,
|
||||
AngledLineTo,
|
||||
}
|
||||
|
||||
impl From<Path> for PathType {
|
||||
fn from(value: Path) -> Self {
|
||||
match value {
|
||||
Path::ToPoint { .. } => Self::ToPoint,
|
||||
Path::TangentialArcTo { .. } => Self::TangentialArcTo,
|
||||
Path::TangentialArc { .. } => Self::TangentialArc,
|
||||
Path::Circle { .. } => Self::Circle,
|
||||
Path::Horizontal { .. } => Self::Horizontal,
|
||||
Path::AngledLineTo { .. } => Self::AngledLineTo,
|
||||
Path::Base { .. } => Self::Base,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Path {
|
||||
pub fn get_id(&self) -> uuid::Uuid {
|
||||
match self {
|
||||
@ -1695,6 +1721,21 @@ impl Path {
|
||||
}
|
||||
}
|
||||
|
||||
/// Where does this path segment start?
|
||||
pub fn get_from(&self) -> &[f64; 2] {
|
||||
&self.get_base().from
|
||||
}
|
||||
/// Where does this path segment end?
|
||||
pub fn get_to(&self) -> &[f64; 2] {
|
||||
&self.get_base().to
|
||||
}
|
||||
|
||||
/// Length of this path segment, in cartesian plane.
|
||||
pub fn length(&self) -> f64 {
|
||||
// TODO 4297: check what type of line this path is, don't assume linear.
|
||||
((self.get_from()[1] - self.get_to()[1]).powi(2) + (self.get_from()[0] - self.get_to()[0]).powi(2)).sqrt()
|
||||
}
|
||||
|
||||
pub fn get_base_mut(&mut self) -> Option<&mut BasePath> {
|
||||
match self {
|
||||
Path::ToPoint { base } => Some(base),
|
||||
@ -1962,7 +2003,7 @@ impl ExecutorContext {
|
||||
// Create the client.
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// Set a local engine address if it's set.
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
if let Ok(addr) = std::env::var("ZOO_HOST") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
if let Some(addr) = engine_addr {
|
||||
|
@ -24,7 +24,7 @@ fn new_zoo_client() -> kittycad::Client {
|
||||
// Create the client.
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// Set a local engine address if it's set.
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
if let Ok(addr) = std::env::var("ZOO_HOST") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
|
@ -141,14 +141,14 @@ pub(crate) async fn do_post_extrude(
|
||||
)
|
||||
.await?;
|
||||
|
||||
if sketch.value.is_empty() {
|
||||
if sketch.paths.is_empty() {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Expected a non-empty sketch".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
let edge_id = sketch.value.iter().find_map(|segment| match segment {
|
||||
let edge_id = sketch.paths.iter().find_map(|segment| match segment {
|
||||
Path::ToPoint { base } | Path::Circle { base, .. } => Some(base.geo_meta.id),
|
||||
_ => None,
|
||||
});
|
||||
@ -229,7 +229,7 @@ pub(crate) async fn do_post_extrude(
|
||||
} = analyze_faces(exec_state, &args, face_infos);
|
||||
// Iterate over the sketch.value array and add face_id to GeoMeta
|
||||
let new_value = sketch
|
||||
.value
|
||||
.paths
|
||||
.iter()
|
||||
.flat_map(|path| {
|
||||
if let Some(Some(actual_face_id)) = face_id_map.get(&path.get_base().geo_meta.id) {
|
||||
|
@ -42,7 +42,7 @@ fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
|
||||
})
|
||||
})?;
|
||||
|
||||
Ok(path.to[0])
|
||||
Ok(path.get_base().to[0])
|
||||
}
|
||||
|
||||
/// Returns the segment end of y.
|
||||
@ -79,7 +79,7 @@ fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
|
||||
})
|
||||
})?;
|
||||
|
||||
Ok(path.to[1])
|
||||
Ok(path.get_to()[1])
|
||||
}
|
||||
|
||||
/// Returns the last segment of x.
|
||||
@ -109,7 +109,7 @@ pub async fn last_segment_x(_exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
}]
|
||||
fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<f64, KclError> {
|
||||
let last_line = sketch
|
||||
.value
|
||||
.paths
|
||||
.last()
|
||||
.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
@ -149,7 +149,7 @@ pub async fn last_segment_y(_exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
}]
|
||||
fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<f64, KclError> {
|
||||
let last_line = sketch
|
||||
.value
|
||||
.paths
|
||||
.last()
|
||||
.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
@ -202,7 +202,7 @@ fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: A
|
||||
})
|
||||
})?;
|
||||
|
||||
let result = ((path.from[1] - path.to[1]).powi(2) + (path.from[0] - path.to[0]).powi(2)).sqrt();
|
||||
let result = path.length();
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
@ -242,7 +242,7 @@ fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
|
||||
})
|
||||
})?;
|
||||
|
||||
let result = between(path.from.into(), path.to.into());
|
||||
let result = between(path.get_from().into(), path.get_to().into());
|
||||
|
||||
Ok(result.to_degrees())
|
||||
}
|
||||
@ -286,10 +286,10 @@ fn inner_angle_to_match_length_x(
|
||||
})
|
||||
})?;
|
||||
|
||||
let length = ((path.from[1] - path.to[1]).powi(2) + (path.from[0] - path.to[0]).powi(2)).sqrt();
|
||||
let length = path.length();
|
||||
|
||||
let last_line = sketch
|
||||
.value
|
||||
.paths
|
||||
.last()
|
||||
.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
@ -350,10 +350,10 @@ fn inner_angle_to_match_length_y(
|
||||
})
|
||||
})?;
|
||||
|
||||
let length = ((path.from[1] - path.to[1]).powi(2) + (path.from[0] - path.to[0]).powi(2)).sqrt();
|
||||
let length = path.length();
|
||||
|
||||
let last_line = sketch
|
||||
.value
|
||||
.paths
|
||||
.last()
|
||||
.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
|
@ -134,7 +134,7 @@ async fn inner_circle(
|
||||
new_sketch.add_tag(tag, ¤t_path);
|
||||
}
|
||||
|
||||
new_sketch.value.push(current_path);
|
||||
new_sketch.paths.push(current_path);
|
||||
|
||||
args.batch_modeling_cmd(id, ModelingCmd::from(mcmd::ClosePath { path_id: new_sketch.id }))
|
||||
.await?;
|
||||
|
@ -154,7 +154,7 @@ async fn inner_line_to(
|
||||
new_sketch.add_tag(tag, ¤t_path);
|
||||
}
|
||||
|
||||
new_sketch.value.push(current_path);
|
||||
new_sketch.paths.push(current_path);
|
||||
|
||||
Ok(new_sketch)
|
||||
}
|
||||
@ -323,7 +323,7 @@ async fn inner_line(
|
||||
new_sketch.add_tag(tag, ¤t_path);
|
||||
}
|
||||
|
||||
new_sketch.value.push(current_path);
|
||||
new_sketch.paths.push(current_path);
|
||||
|
||||
Ok(new_sketch)
|
||||
}
|
||||
@ -506,7 +506,7 @@ async fn inner_angled_line(
|
||||
new_sketch.add_tag(tag, ¤t_path);
|
||||
}
|
||||
|
||||
new_sketch.value.push(current_path);
|
||||
new_sketch.paths.push(current_path);
|
||||
Ok(new_sketch)
|
||||
}
|
||||
|
||||
@ -813,7 +813,7 @@ async fn inner_angled_line_that_intersects(
|
||||
|
||||
let from = sketch.current_pen_position()?;
|
||||
let to = intersection_with_parallel_line(
|
||||
&[path.from.into(), path.to.into()],
|
||||
&[path.get_from().into(), path.get_to().into()],
|
||||
data.offset.unwrap_or_default(),
|
||||
data.angle,
|
||||
from,
|
||||
@ -1237,14 +1237,16 @@ pub(crate) async fn inner_start_profile_at(
|
||||
id: path_id,
|
||||
original_id: path_id,
|
||||
on: sketch_surface.clone(),
|
||||
value: vec![],
|
||||
paths: vec![],
|
||||
meta: vec![args.source_range.into()],
|
||||
tags: if let Some(tag) = &tag {
|
||||
let mut tag_identifier: TagIdentifier = tag.into();
|
||||
tag_identifier.info = Some(TagEngineInfo {
|
||||
id: current_path.geo_meta.id,
|
||||
sketch: path_id,
|
||||
path: Some(current_path.clone()),
|
||||
path: Some(Path::Base {
|
||||
base: current_path.clone(),
|
||||
}),
|
||||
surface: None,
|
||||
});
|
||||
HashMap::from([(tag.name.to_string(), tag_identifier)])
|
||||
@ -1411,7 +1413,7 @@ pub(crate) async fn inner_close(
|
||||
new_sketch.add_tag(tag, ¤t_path);
|
||||
}
|
||||
|
||||
new_sketch.value.push(current_path);
|
||||
new_sketch.paths.push(current_path);
|
||||
|
||||
Ok(new_sketch)
|
||||
}
|
||||
@ -1545,7 +1547,7 @@ pub(crate) async fn inner_arc(
|
||||
new_sketch.add_tag(tag, ¤t_path);
|
||||
}
|
||||
|
||||
new_sketch.value.push(current_path);
|
||||
new_sketch.paths.push(current_path);
|
||||
|
||||
Ok(new_sketch)
|
||||
}
|
||||
@ -1677,7 +1679,7 @@ async fn inner_tangential_arc(
|
||||
new_sketch.add_tag(tag, ¤t_path);
|
||||
}
|
||||
|
||||
new_sketch.value.push(current_path);
|
||||
new_sketch.paths.push(current_path);
|
||||
|
||||
Ok(new_sketch)
|
||||
}
|
||||
@ -1773,7 +1775,7 @@ async fn inner_tangential_arc_to(
|
||||
new_sketch.add_tag(tag, ¤t_path);
|
||||
}
|
||||
|
||||
new_sketch.value.push(current_path);
|
||||
new_sketch.paths.push(current_path);
|
||||
|
||||
Ok(new_sketch)
|
||||
}
|
||||
@ -1858,7 +1860,7 @@ async fn inner_tangential_arc_to_relative(
|
||||
new_sketch.add_tag(tag, ¤t_path);
|
||||
}
|
||||
|
||||
new_sketch.value.push(current_path);
|
||||
new_sketch.paths.push(current_path);
|
||||
|
||||
Ok(new_sketch)
|
||||
}
|
||||
@ -1951,7 +1953,7 @@ async fn inner_bezier_curve(
|
||||
new_sketch.add_tag(tag, ¤t_path);
|
||||
}
|
||||
|
||||
new_sketch.value.push(current_path);
|
||||
new_sketch.paths.push(current_path);
|
||||
|
||||
Ok(new_sketch)
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ async fn new_context(units: UnitLength, with_auth: bool) -> anyhow::Result<Execu
|
||||
// Create the client.
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// Set a local engine address if it's set.
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
if let Ok(addr) = std::env::var("ZOO_HOST") {
|
||||
if with_auth {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
exampleSketch = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, 2], %)
|
||||
|> line([3, 1], %)
|
||||
|> line([0, -4], %)
|
||||
|> close(%)
|
||||
|> extrude(1, %)
|
||||
|
||||
pattn1 = patternLinear3d({
|
||||
axis: [1, 0, 0],
|
||||
instances: 7,
|
||||
distance: 6
|
||||
}, exampleSketch)
|
||||
|
||||
pattn2 = patternCircular3d({axis: [0,0, 1], center: [-20, -20, -20], instances: 41, arcDegrees: 360, rotateDuplicates: false}, pattn1)
|
@ -0,0 +1,19 @@
|
||||
exampleSketch = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, 2], %)
|
||||
|> line([3, 1], %)
|
||||
|> line([0, -4], %)
|
||||
|> close(%)
|
||||
|> extrude(1, %)
|
||||
|
||||
pattn1 = patternLinear3d({
|
||||
axis: [1, 0, 0],
|
||||
instances: 7,
|
||||
distance: 6
|
||||
}, exampleSketch)
|
||||
|
||||
pattn2 = patternLinear3d({
|
||||
axis: [0, 0, 1],
|
||||
distance: 1,
|
||||
instances: 7
|
||||
}, pattn1)
|
@ -1,5 +1,5 @@
|
||||
fn cube = (pos, scale) => {
|
||||
const sg = startSketchOn('XY')
|
||||
fn square = (pos, scale) => {
|
||||
sg = startSketchOn('XY')
|
||||
|> startProfileAt(pos, %)
|
||||
|> line([0, scale], %)
|
||||
|> line([scale, 0], %)
|
||||
@ -9,9 +9,9 @@ fn cube = (pos, scale) => {
|
||||
return sg
|
||||
}
|
||||
|
||||
const b1 = cube([0,0], 10)
|
||||
const b2 = cube([3,3], 4)
|
||||
sq = square([0,0], 10)
|
||||
cb = square([3,3], 4)
|
||||
|> extrude(10, %)
|
||||
|
||||
const pt1 = b1.value[0]
|
||||
const pt2 = b2.value[0]
|
||||
pt1 = sq.paths[0]
|
||||
pt2 = cb.value[0]
|
||||
|
6
src/wasm-lib/tests/executor/inputs/neg_xz_plane.kcl
Normal file
@ -0,0 +1,6 @@
|
||||
part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo([100, 100], %)
|
||||
|> lineTo([100, 0], %)
|
||||
|> close(%)
|
||||
|> extrude(5 + 7, %)
|
@ -0,0 +1,55 @@
|
||||
// Shelf Bracket
|
||||
// This is a shelf bracket made out of 6061-T6 aluminum sheet metal. The required thickness is calculated based on a point load of 300 lbs applied to the end of the shelf. There are two brackets holding up the shelf, so the moment experienced is divided by 2. The shelf is 1 foot long from the wall.
|
||||
|
||||
|
||||
// Define our bracket feet lengths
|
||||
shelfMountL = 8 // The length of the bracket holding up the shelf is 6 inches
|
||||
wallMountL = 6 // the length of the bracket
|
||||
|
||||
|
||||
// Define constants required to calculate the thickness needed to support 300 lbs
|
||||
sigmaAllow = 35000 // psi
|
||||
width = 6 // inch
|
||||
p = 300 // Force on shelf - lbs
|
||||
L = 12 // inches
|
||||
M = L * p / 2 // Moment experienced at fixed end of bracket
|
||||
FOS = 2 // Factor of safety of 2 to be conservative
|
||||
|
||||
|
||||
// Calculate the thickness off the bending stress and factor of safety
|
||||
thickness = sqrt(6 * M * FOS / (width * sigmaAllow))
|
||||
|
||||
// 0.25 inch fillet radius
|
||||
filletR = 0.25
|
||||
|
||||
// Sketch the bracket and extrude with fillets
|
||||
bracket = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, wallMountL], %, $outerEdge)
|
||||
|> line([-shelfMountL, 0], %, $seg01)
|
||||
|> line([0, -thickness], %)
|
||||
|> line([shelfMountL - thickness, 0], %, $innerEdge)
|
||||
|> line([0, -wallMountL + thickness], %)
|
||||
|> close(%)
|
||||
|> extrude(width, %)
|
||||
|> fillet({
|
||||
radius: filletR,
|
||||
tags: [
|
||||
getNextAdjacentEdge(innerEdge)
|
||||
]
|
||||
}, %)
|
||||
|> fillet({
|
||||
radius: filletR + thickness,
|
||||
tags: [
|
||||
getNextAdjacentEdge(outerEdge)
|
||||
]
|
||||
}, %)
|
||||
|
||||
sketch001 = startSketchOn(bracket, seg01)
|
||||
|> startProfileAt([4.28, 3.83], %)
|
||||
|> line([2.17, -0.03], %)
|
||||
|> line([-0.07, -1.8], %)
|
||||
|> line([-2.07, 0.05], %)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
6
src/wasm-lib/tests/executor/inputs/xz_plane.kcl
Normal file
@ -0,0 +1,6 @@
|
||||
part001 = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo([100, 100], %)
|
||||
|> lineTo([100, 0], %)
|
||||
|> close(%)
|
||||
|> extrude(5 + 7, %)
|
@ -1389,84 +1389,6 @@ extrusion = startSketchOn('XY')
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_xz_plane() {
|
||||
let code = r#"part001 = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo([100, 100], %)
|
||||
|> lineTo([100, 0], %)
|
||||
|> close(%)
|
||||
|> extrude(5 + 7, %)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
assert_out("xz_plane", &result);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_neg_xz_plane() {
|
||||
let code = r#"part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo([100, 100], %)
|
||||
|> lineTo([100, 0], %)
|
||||
|> close(%)
|
||||
|> extrude(5 + 7, %)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
assert_out("neg_xz_plane", &result);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_linear_pattern3d_a_pattern() {
|
||||
let code = r#"exampleSketch = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, 2], %)
|
||||
|> line([3, 1], %)
|
||||
|> line([0, -4], %)
|
||||
|> close(%)
|
||||
|> extrude(1, %)
|
||||
|
||||
pattn1 = patternLinear3d({
|
||||
axis: [1, 0, 0],
|
||||
instances: 7,
|
||||
distance: 6
|
||||
}, exampleSketch)
|
||||
|
||||
pattn2 = patternLinear3d({
|
||||
axis: [0, 0, 1],
|
||||
distance: 1,
|
||||
instances: 7
|
||||
}, pattn1)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
assert_out("linear_pattern3d_a_pattern", &result);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_circular_pattern3d_a_pattern() {
|
||||
let code = r#"exampleSketch = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, 2], %)
|
||||
|> line([3, 1], %)
|
||||
|> line([0, -4], %)
|
||||
|> close(%)
|
||||
|> extrude(1, %)
|
||||
|
||||
pattn1 = patternLinear3d({
|
||||
axis: [1, 0, 0],
|
||||
instances: 7,
|
||||
distance: 6
|
||||
}, exampleSketch)
|
||||
|
||||
pattn2 = patternCircular3d({axis: [0,0, 1], center: [-20, -20, -20], instances: 41, arcDegrees: 360, rotateDuplicates: false}, pattn1)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
assert_out("circular_pattern3d_a_pattern", &result);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_array_of_sketches() {
|
||||
let code = r#"plane001 = startSketchOn('XZ')
|
||||
@ -1496,69 +1418,6 @@ extrude(10, sketch001)
|
||||
assert_out("array_of_sketches", &result);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_sketch_on_face_after_fillets_referencing_face() {
|
||||
let code = r#"// Shelf Bracket
|
||||
// This is a shelf bracket made out of 6061-T6 aluminum sheet metal. The required thickness is calculated based on a point load of 300 lbs applied to the end of the shelf. There are two brackets holding up the shelf, so the moment experienced is divided by 2. The shelf is 1 foot long from the wall.
|
||||
|
||||
|
||||
// Define our bracket feet lengths
|
||||
shelfMountL = 8 // The length of the bracket holding up the shelf is 6 inches
|
||||
wallMountL = 6 // the length of the bracket
|
||||
|
||||
|
||||
// Define constants required to calculate the thickness needed to support 300 lbs
|
||||
sigmaAllow = 35000 // psi
|
||||
width = 6 // inch
|
||||
p = 300 // Force on shelf - lbs
|
||||
L = 12 // inches
|
||||
M = L * p / 2 // Moment experienced at fixed end of bracket
|
||||
FOS = 2 // Factor of safety of 2 to be conservative
|
||||
|
||||
|
||||
// Calculate the thickness off the bending stress and factor of safety
|
||||
thickness = sqrt(6 * M * FOS / (width * sigmaAllow))
|
||||
|
||||
// 0.25 inch fillet radius
|
||||
filletR = 0.25
|
||||
|
||||
// Sketch the bracket and extrude with fillets
|
||||
bracket = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, wallMountL], %, $outerEdge)
|
||||
|> line([-shelfMountL, 0], %, $seg01)
|
||||
|> line([0, -thickness], %)
|
||||
|> line([shelfMountL - thickness, 0], %, $innerEdge)
|
||||
|> line([0, -wallMountL + thickness], %)
|
||||
|> close(%)
|
||||
|> extrude(width, %)
|
||||
|> fillet({
|
||||
radius: filletR,
|
||||
tags: [
|
||||
getNextAdjacentEdge(innerEdge)
|
||||
]
|
||||
}, %)
|
||||
|> fillet({
|
||||
radius: filletR + thickness,
|
||||
tags: [
|
||||
getNextAdjacentEdge(outerEdge)
|
||||
]
|
||||
}, %)
|
||||
|
||||
sketch001 = startSketchOn(bracket, seg01)
|
||||
|> startProfileAt([4.28, 3.83], %)
|
||||
|> line([2.17, -0.03], %)
|
||||
|> line([-0.07, -1.8], %)
|
||||
|> line([-2.07, 0.05], %)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
assert_out("sketch_on_face_after_fillets_referencing_face", &result);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_circular_pattern3d_array_of_extrudes() {
|
||||
let code = r#"plane001 = startSketchOn('XZ')
|
||||
|
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 33 KiB |
@ -19,6 +19,15 @@ macro_rules! kcl_test {
|
||||
}
|
||||
|
||||
kcl_test!("sketch_on_face", kcl_test_sketch_on_face);
|
||||
kcl_test!("neg_xz_plane", kcl_test_neg_xz_plane);
|
||||
kcl_test!("xz_plane", kcl_test_xz_plane);
|
||||
kcl_test!(
|
||||
"sketch_on_face_after_fillets_referencing_face",
|
||||
kcl_test_sketch_on_face_after_fillets_referencing_face
|
||||
);
|
||||
kcl_test!("circular_pattern3d_a_pattern", kcl_test_circular_pattern3d_a_pattern);
|
||||
kcl_test!("linear_pattern3d_a_pattern", kcl_test_linear_pattern3d_a_pattern);
|
||||
|
||||
kcl_test!("tangential_arc", kcl_test_tangential_arc);
|
||||
kcl_test!(
|
||||
"big_number_angle_to_match_length_x",
|
||||
|
@ -27,7 +27,7 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid
|
||||
// Create the client.
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// Set a local engine address if it's set.
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
if let Ok(addr) = std::env::var("ZOO_HOST") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
|
39
yarn.lock
@ -2597,10 +2597,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433"
|
||||
integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==
|
||||
|
||||
"@types/node@*", "@types/node@^22.5.0":
|
||||
version "22.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.0.tgz#10f01fe9465166b4cab72e75f60d8b99d019f958"
|
||||
integrity sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==
|
||||
"@types/node@*", "@types/node@^22.7.8":
|
||||
version "22.7.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.8.tgz#a1dbf0dc5f71bdd2642fc89caef65d58747ce825"
|
||||
integrity sha512-a922jJy31vqR5sk+kAdIENJjHblqcZ4RmERviFsER4WJcEONqxKcjNOlk0q7OUfrF5sddT+vng070cdfMlrPLg==
|
||||
dependencies:
|
||||
undici-types "~6.19.2"
|
||||
|
||||
@ -8785,7 +8785,16 @@ string-natural-compare@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
|
||||
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@ -8879,7 +8888,14 @@ string_decoder@~1.1.1:
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
@ -9753,7 +9769,16 @@ word-wrap@^1.2.3, word-wrap@^1.2.5:
|
||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
|
||||
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
|
||||
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
dependencies:
|
||||
ansi-styles "^4.0.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
|