Compare commits
17 Commits
kcl-55
...
nrc-std-ax
Author | SHA1 | Date | |
---|---|---|---|
87dfda28a9 | |||
42f44e11f5 | |||
16ad7ff77a | |||
71b9e40bd9 | |||
4f35197a96 | |||
40b0cf5fd3 | |||
355e6acf0d | |||
4ff38e7f44 | |||
1dcd3b84b7 | |||
2957216bd3 | |||
11160f0b40 | |||
4b2c745db5 | |||
bb983021b1 | |||
d27b8871bc | |||
1753047d87 | |||
fa16fcedff | |||
0677474097 |
@ -1,5 +1,6 @@
|
||||
NODE_ENV=development
|
||||
DEV=true
|
||||
|
||||
VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands
|
||||
VITE_KC_API_BASE_URL=https://api.dev.zoo.dev
|
||||
VITE_KC_SITE_BASE_URL=https://dev.zoo.dev
|
||||
@ -8,3 +9,5 @@ VITE_KC_SKIP_AUTH=false
|
||||
VITE_KC_CONNECTION_TIMEOUT_MS=5000
|
||||
# ONLY add your token in .env.development.local if you want to skip auth, otherwise this token takes precedence!
|
||||
#VITE_KC_DEV_TOKEN="your token from dev.zoo.dev should go in .env.development.local"
|
||||
|
||||
FAIL_ON_CONSOLE_ERRORS=true
|
||||
|
10
.envrc
@ -1,3 +1,13 @@
|
||||
# Load optional shared environment variables
|
||||
source_up_if_exists
|
||||
|
||||
# Load default development environment variables
|
||||
dotenv .env.development
|
||||
|
||||
# Load optional environment variables overrides
|
||||
dotenv_if_exists .env.development.local
|
||||
|
||||
# Load optional testing environment variables
|
||||
dotenv_if_exists e2e/playwright/playwright-secrets.env
|
||||
|
||||
use flake .
|
||||
|
@ -20,6 +20,7 @@
|
||||
"plugin:react-hooks/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-empty-object-type": "error",
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-misused-promises": "error",
|
||||
"@typescript-eslint/no-unused-vars": ["error", {
|
||||
|
16
.github/workflows/update-e2e-branch.yml
vendored
@ -28,14 +28,18 @@ jobs:
|
||||
|
||||
- name: Sync with main
|
||||
run: |
|
||||
# checkout our branch
|
||||
# Create the branch
|
||||
git checkout all-e2e || git checkout -b all-e2e
|
||||
# fetch origin
|
||||
|
||||
# Reset to main
|
||||
git fetch origin
|
||||
# reset to main
|
||||
git reset --hard origin/main
|
||||
# get a new SHA to prevent overwriting the commit status on main
|
||||
git commit --amend --message="[all-e2e] $(git log --max-count=1 --pretty=%B)"
|
||||
# force push it
|
||||
|
||||
# Get a new SHA to prevent overwriting the commit status on main
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git commit --allow-empty --message="[all-e2e] $(git log --max-count=1 --pretty=%B)"
|
||||
|
||||
# Overwrite the branch
|
||||
git remote set-url origin https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/${{ github.repository }}.git
|
||||
git push --force origin all-e2e
|
||||
|
@ -54,7 +54,7 @@ example = extrude(exampleSketch, length = 5)
|
||||
// Add color to a revolved solid.
|
||||
sketch001 = startSketchOn(XY)
|
||||
|> circle(center = [15, 0], radius = 5)
|
||||
|> revolve(angle = 360, axis = 'y')
|
||||
|> revolve(angle = 360, axis = Y)
|
||||
|> appearance(color = '#ff0000', metalness = 90, roughness = 90)
|
||||
```
|
||||
|
||||
|
@ -9,13 +9,12 @@ layout: manual
|
||||
|
||||
### `std`
|
||||
|
||||
- [`HALF_TURN`](/docs/kcl/consts/std-HALF_TURN)
|
||||
- [`QUARTER_TURN`](/docs/kcl/consts/std-QUARTER_TURN)
|
||||
- [`THREE_QUARTER_TURN`](/docs/kcl/consts/std-THREE_QUARTER_TURN)
|
||||
- [`X`](/docs/kcl/consts/std-X)
|
||||
- [`XY`](/docs/kcl/consts/std-XY)
|
||||
- [`XZ`](/docs/kcl/consts/std-XZ)
|
||||
- [`Y`](/docs/kcl/consts/std-Y)
|
||||
- [`YZ`](/docs/kcl/consts/std-YZ)
|
||||
- [`ZERO`](/docs/kcl/consts/std-ZERO)
|
||||
- [`Z`](/docs/kcl/consts/std-Z)
|
||||
|
||||
### `std::math`
|
||||
|
||||
@ -23,3 +22,10 @@ layout: manual
|
||||
- [`PI`](/docs/kcl/consts/std-math-PI)
|
||||
- [`TAU`](/docs/kcl/consts/std-math-TAU)
|
||||
|
||||
### `std::turns`
|
||||
|
||||
- [`HALF_TURN`](/docs/kcl/consts/std-turns-HALF_TURN)
|
||||
- [`QUARTER_TURN`](/docs/kcl/consts/std-turns-QUARTER_TURN)
|
||||
- [`THREE_QUARTER_TURN`](/docs/kcl/consts/std-turns-THREE_QUARTER_TURN)
|
||||
- [`ZERO`](/docs/kcl/consts/std-turns-ZERO)
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
---
|
||||
title: "std::HALF_TURN"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```js
|
||||
std::HALF_TURN: number(deg) = 180deg
|
||||
```
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
---
|
||||
title: "std::QUARTER_TURN"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```js
|
||||
std::QUARTER_TURN: number(deg) = 90deg
|
||||
```
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
---
|
||||
title: "std::THREE_QUARTER_TURN"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```js
|
||||
std::THREE_QUARTER_TURN: number(deg) = 270deg
|
||||
```
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: "std::ZERO"
|
||||
title: "std::X"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
@ -9,7 +9,7 @@ layout: manual
|
||||
|
||||
|
||||
```js
|
||||
std::ZERO: number = 0
|
||||
std::X
|
||||
```
|
||||
|
||||
|
15
docs/kcl/consts/std-Y.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
title: "std::Y"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```js
|
||||
std::Y
|
||||
```
|
||||
|
||||
|
15
docs/kcl/consts/std-Z.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
title: "std::Z"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```js
|
||||
std::Z
|
||||
```
|
||||
|
||||
|
15
docs/kcl/consts/std-turns-HALF_TURN.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
title: "std::turns::HALF_TURN"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```js
|
||||
std::turns::HALF_TURN: number(deg) = 180deg
|
||||
```
|
||||
|
||||
|
15
docs/kcl/consts/std-turns-QUARTER_TURN.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
title: "std::turns::QUARTER_TURN"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```js
|
||||
std::turns::QUARTER_TURN: number(deg) = 90deg
|
||||
```
|
||||
|
||||
|
15
docs/kcl/consts/std-turns-THREE_QUARTER_TURN.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
title: "std::turns::THREE_QUARTER_TURN"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```js
|
||||
std::turns::THREE_QUARTER_TURN: number(deg) = 270deg
|
||||
```
|
||||
|
||||
|
15
docs/kcl/consts/std-turns-ZERO.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
title: "std::turns::ZERO"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```js
|
||||
std::turns::ZERO: number = 0
|
||||
```
|
||||
|
||||
|
@ -22,20 +22,22 @@ layout: manual
|
||||
* [`string`](kcl/types/string)
|
||||
* [`tag`](kcl/types/tag)
|
||||
* **std**
|
||||
* [`Axis2d`](kcl/types/Axis2d)
|
||||
* [`Axis3d`](kcl/types/Axis3d)
|
||||
* [`Edge`](kcl/types/Edge)
|
||||
* [`Face`](kcl/types/Face)
|
||||
* [`HALF_TURN`](kcl/consts/std-HALF_TURN)
|
||||
* [`Helix`](kcl/types/Helix)
|
||||
* [`Plane`](kcl/types/Plane)
|
||||
* [`Point2d`](kcl/types/Point2d)
|
||||
* [`Point3d`](kcl/types/Point3d)
|
||||
* [`QUARTER_TURN`](kcl/consts/std-QUARTER_TURN)
|
||||
* [`Sketch`](kcl/types/Sketch)
|
||||
* [`Solid`](kcl/types/Solid)
|
||||
* [`THREE_QUARTER_TURN`](kcl/consts/std-THREE_QUARTER_TURN)
|
||||
* [`X`](kcl/consts/std-X)
|
||||
* [`XY`](kcl/consts/std-XY)
|
||||
* [`XZ`](kcl/consts/std-XZ)
|
||||
* [`Y`](kcl/consts/std-Y)
|
||||
* [`YZ`](kcl/consts/std-YZ)
|
||||
* [`ZERO`](kcl/consts/std-ZERO)
|
||||
* [`Z`](kcl/consts/std-Z)
|
||||
* [`abs`](kcl/abs)
|
||||
* [`acos`](kcl/acos)
|
||||
* [`angleToMatchLengthX`](kcl/angleToMatchLengthX)
|
||||
@ -72,7 +74,7 @@ layout: manual
|
||||
* [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge)
|
||||
* [`getOppositeEdge`](kcl/getOppositeEdge)
|
||||
* [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge)
|
||||
* [`helix`](kcl/helix)
|
||||
* [`helix`](kcl/std-helix)
|
||||
* [`hole`](kcl/hole)
|
||||
* [`hollow`](kcl/hollow)
|
||||
* [`inch`](kcl/inch)
|
||||
@ -91,7 +93,6 @@ layout: manual
|
||||
* [`map`](kcl/map)
|
||||
* [`max`](kcl/max)
|
||||
* [`min`](kcl/min)
|
||||
* [`mirror2d`](kcl/mirror2d)
|
||||
* [`mm`](kcl/mm)
|
||||
* [`offsetPlane`](kcl/offsetPlane)
|
||||
* [`patternCircular2d`](kcl/patternCircular2d)
|
||||
@ -110,7 +111,7 @@ layout: manual
|
||||
* [`push`](kcl/push)
|
||||
* [`reduce`](kcl/reduce)
|
||||
* [`rem`](kcl/rem)
|
||||
* [`revolve`](kcl/revolve)
|
||||
* [`revolve`](kcl/std-revolve)
|
||||
* [`rotate`](kcl/rotate)
|
||||
* [`round`](kcl/round)
|
||||
* [`scale`](kcl/scale)
|
||||
@ -146,3 +147,9 @@ layout: manual
|
||||
* [`tan`](kcl/std-math-tan)
|
||||
* **std::sketch**
|
||||
* [`circle`](kcl/std-sketch-circle)
|
||||
* [`mirror2d`](kcl/std-sketch-mirror2d)
|
||||
* **std::turns**
|
||||
* [`turns::HALF_TURN`](kcl/consts/std-turns-HALF_TURN)
|
||||
* [`turns::QUARTER_TURN`](kcl/consts/std-turns-QUARTER_TURN)
|
||||
* [`turns::THREE_QUARTER_TURN`](kcl/consts/std-turns-THREE_QUARTER_TURN)
|
||||
* [`turns::ZERO`](kcl/consts/std-turns-ZERO)
|
||||
|
@ -146,7 +146,7 @@ exampleSketch = startSketchOn(XY)
|
||||
|> line(end = [-2, 0])
|
||||
|> close()
|
||||
|
||||
example = revolve(exampleSketch, axis = 'y', angle = 180)
|
||||
example = revolve(exampleSketch, axis = Y, angle = 180)
|
||||
|
||||
exampleSketch002 = startSketchOn(example, 'end')
|
||||
|> startProfileAt([4.5, -5], %)
|
||||
@ -177,7 +177,7 @@ exampleSketch = startSketchOn(XY)
|
||||
|
||||
example = revolve(
|
||||
exampleSketch,
|
||||
axis = 'y',
|
||||
axis = Y,
|
||||
angle = 180,
|
||||
tagEnd = $end01,
|
||||
)
|
||||
|
116
docs/kcl/std-helix.md
Normal file
246
docs/kcl/std-revolve.md
Normal file
98
docs/kcl/std-sketch-mirror2d.md
Normal file
17412
docs/kcl/std.json
@ -74,7 +74,7 @@ helixPath = helix(
|
||||
revolutions = 4,
|
||||
length = 10,
|
||||
radius = 5,
|
||||
axis = 'Z',
|
||||
axis = Z,
|
||||
)
|
||||
|
||||
// Create a spring by sweeping around the helix path.
|
||||
|
12
docs/kcl/types/Axis2d.md
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
title: "std::Axis2d"
|
||||
excerpt: "An infinte line in 2d space."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
An infinte line in 2d space.
|
||||
|
||||
|
||||
|
||||
|
||||
|
12
docs/kcl/types/Axis3d.md
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
title: "std::Axis3d"
|
||||
excerpt: "An infinte line in 3d space."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
An infinte line in 3d space.
|
||||
|
||||
|
||||
|
||||
|
||||
|
12
docs/kcl/types/Edge.md
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
title: "std::Edge"
|
||||
excerpt: "The edge of a solid."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
The edge of a solid.
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -21,7 +21,7 @@ sketch001 = startSketchOn(XZ)
|
||||
|> angledLine([-45, length001], %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
revolve001 = revolve(sketch001, axis = "X")
|
||||
revolve001 = revolve(sketch001, axis = X)
|
||||
triangle()
|
||||
|> extrude(length = 30)
|
||||
plane001 = offsetPlane(XY, offset = 10)
|
||||
@ -126,7 +126,7 @@ test.describe('Feature Tree pane', () => {
|
||||
await testViewSource({
|
||||
operationName: 'Revolve',
|
||||
operationIndex: 0,
|
||||
expectedActiveLine: 'revolve001 = revolve(sketch001, axis = "X")',
|
||||
expectedActiveLine: 'revolve001 = revolve(sketch001, axis = X)',
|
||||
})
|
||||
await testViewSource({
|
||||
operationName: 'Triangle',
|
||||
|
@ -257,6 +257,46 @@ export const isErrorWhitelisted = (exception: Error) => {
|
||||
project: 'Google Chrome',
|
||||
foundInSpec: 'e2e/playwright/testing-settings.spec.ts',
|
||||
},
|
||||
// TODO: fix this error in the code
|
||||
{
|
||||
name: 'TypeError',
|
||||
message: "Cannot read properties of undefined (reading 'length')",
|
||||
stack: '',
|
||||
project: 'Google Chrome',
|
||||
foundInSpec: '', // many tests are impacted by this error
|
||||
},
|
||||
// TODO: fix this error in the code
|
||||
{
|
||||
name: 'ReferenceError',
|
||||
message: '_testUtils is not defined',
|
||||
stack: '',
|
||||
project: 'Google Chrome',
|
||||
foundInSpec: 'e2e/playwright/snapshot-tests.spec.ts',
|
||||
},
|
||||
// TODO: fix this error in the code
|
||||
{
|
||||
name: 'TypeError',
|
||||
message: 'Failed to fetch',
|
||||
stack: '',
|
||||
project: 'Google Chrome',
|
||||
foundInSpec: 'e2e/playwright/snapshot-tests.spec.ts',
|
||||
},
|
||||
// TODO: fix this error in the code
|
||||
{
|
||||
name: 'ReferenceError',
|
||||
message: 'originalCode is not defined',
|
||||
stack: '',
|
||||
project: 'Google Chrome',
|
||||
foundInSpec: 'e2e/playwright/onboarding-tests.spec.ts',
|
||||
},
|
||||
// TODO: fix this error in the code
|
||||
{
|
||||
name: 'ReferenceError',
|
||||
message: 'createNewVariableCheckbox is not defined',
|
||||
stack: '',
|
||||
project: 'Google Chrome',
|
||||
foundInSpec: 'e2e/playwright/testing-constraints.spec.ts',
|
||||
},
|
||||
]
|
||||
|
||||
const cleanString = (str: string) => str.replace(/[`"]/g, '')
|
||||
|
292
e2e/playwright/named-views.spec.ts
Normal file
@ -0,0 +1,292 @@
|
||||
import { test, expect } from './zoo-test'
|
||||
import { PROJECT_SETTINGS_FILE_NAME } from 'lib/constants'
|
||||
import * as fsp from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
import {
|
||||
createProject,
|
||||
tomlToPerProjectSettings,
|
||||
perProjectsettingsToToml,
|
||||
} from './test-utils'
|
||||
import { NamedView } from '@rust/kcl-lib/bindings/NamedView'
|
||||
|
||||
// Helper function to determine if the file path on disk exists
|
||||
// Specifically this is used to check if project.toml exists on disk
|
||||
const fileExists = async (path: string) => {
|
||||
return !!(await fsp
|
||||
.stat(path)
|
||||
.then((_) => true)
|
||||
.catch((_) => false))
|
||||
}
|
||||
|
||||
// Here are a few uuids.
|
||||
// When created named views rust will auto generate uuids and they will
|
||||
// never match the snapshots. Overwrite them in memory to these
|
||||
// values to have them match the snapshots.
|
||||
const uuid1: string = '0656fb1a-9640-473e-b334-591dc70c0138'
|
||||
const uuid2: string = 'c810cf04-c6cc-4a4a-8b11-17bf445dcab7'
|
||||
const uuid3: string = 'cfecbfee-48a6-4561-b96d-ffbe5678bb7d'
|
||||
|
||||
// Look up the named view by name and then rewrite it with the same uuid each time
|
||||
const nameToUuid: Map<string, string> = new Map()
|
||||
nameToUuid.set('uuid1', uuid1)
|
||||
nameToUuid.set('uuid2', uuid2)
|
||||
nameToUuid.set('uuid3', uuid3)
|
||||
|
||||
/**
|
||||
* Given the project.toml string, overwrite the named views to be the constant uuid
|
||||
* values to match the snapshots. The uuids are randomly generated
|
||||
*/
|
||||
function tomlStringOverWriteNamedViewUuids(toml: string): string {
|
||||
const settings = tomlToPerProjectSettings(toml)
|
||||
const namedViews = settings.settings?.app?.named_views
|
||||
if (namedViews) {
|
||||
const entries = Object.entries(namedViews)
|
||||
const remappedNamedViews: { [key: string]: NamedView } = {}
|
||||
entries.forEach(([_, value]) => {
|
||||
if (value) {
|
||||
// {name:'uuid1'} -> uuid1 lookup
|
||||
const staticUuid = nameToUuid.get(value.name)
|
||||
if (staticUuid) {
|
||||
remappedNamedViews[staticUuid] = value
|
||||
}
|
||||
}
|
||||
})
|
||||
if (settings && settings.settings && settings.settings.app) {
|
||||
settings.settings.app.named_views = remappedNamedViews
|
||||
}
|
||||
}
|
||||
return perProjectsettingsToToml(settings)
|
||||
}
|
||||
|
||||
test.describe('Named view tests', () => {
|
||||
test('Verify project.toml is not created', async ({ page }, testInfo) => {
|
||||
// Create project and load it
|
||||
const projectName = 'named-views'
|
||||
await createProject({ name: projectName, page })
|
||||
|
||||
// Generate file paths for project.toml
|
||||
const projectDirName = testInfo.outputPath('electron-test-projects-dir')
|
||||
const tempProjectSettingsFilePath = join(
|
||||
projectDirName,
|
||||
projectName,
|
||||
PROJECT_SETTINGS_FILE_NAME
|
||||
)
|
||||
|
||||
// project.toml should not exist on initial project creation
|
||||
let exists = await fileExists(tempProjectSettingsFilePath)
|
||||
expect(exists).toBe(false)
|
||||
})
|
||||
test('Verify named view gets created', async ({
|
||||
cmdBar,
|
||||
scene,
|
||||
page,
|
||||
}, testInfo) => {
|
||||
const projectName = 'named-views'
|
||||
const myNamedView = 'uuid1'
|
||||
|
||||
// Create and load project
|
||||
await createProject({ name: projectName, page })
|
||||
await scene.waitForExecutionDone()
|
||||
|
||||
// Create named view
|
||||
const projectDirName = testInfo.outputPath('electron-test-projects-dir')
|
||||
await cmdBar.openCmdBar()
|
||||
await cmdBar.chooseCommand('create named view')
|
||||
await cmdBar.argumentInput.fill(myNamedView)
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
// Generate paths for the project.toml
|
||||
const tempProjectSettingsFilePath = join(
|
||||
projectDirName,
|
||||
projectName,
|
||||
PROJECT_SETTINGS_FILE_NAME
|
||||
)
|
||||
|
||||
// Expect project.toml to be generated on disk since a named view was created
|
||||
await expect(async () => {
|
||||
let exists = await fileExists(tempProjectSettingsFilePath)
|
||||
expect(exists).toBe(true)
|
||||
}).toPass()
|
||||
|
||||
// Read project.toml into memory
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
|
||||
})
|
||||
test('Verify named view gets deleted', async ({
|
||||
cmdBar,
|
||||
scene,
|
||||
page,
|
||||
}, testInfo) => {
|
||||
const projectName = 'named-views'
|
||||
const myNamedView1 = 'uuid1'
|
||||
const myNamedView2 = 'uuid2'
|
||||
|
||||
// Create project and go into the project
|
||||
await createProject({ name: projectName, page })
|
||||
await scene.waitForExecutionDone()
|
||||
|
||||
// Create a new named view
|
||||
await cmdBar.openCmdBar()
|
||||
await cmdBar.chooseCommand('create named view')
|
||||
await cmdBar.argumentInput.fill(myNamedView1)
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
// Generate file paths for project.toml
|
||||
const projectDirName = testInfo.outputPath('electron-test-projects-dir')
|
||||
const tempProjectSettingsFilePath = join(
|
||||
projectDirName,
|
||||
projectName,
|
||||
PROJECT_SETTINGS_FILE_NAME
|
||||
)
|
||||
|
||||
// Except the project.toml to be written to disk since a named view was created
|
||||
await expect(async () => {
|
||||
let exists = await fileExists(tempProjectSettingsFilePath)
|
||||
expect(exists).toBe(true)
|
||||
}).toPass()
|
||||
|
||||
// Read project.toml into memory
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
|
||||
|
||||
// Delete a named view
|
||||
await cmdBar.openCmdBar()
|
||||
await cmdBar.chooseCommand('delete named view')
|
||||
cmdBar.selectOption({ name: myNamedView2 })
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
// Read project.toml into memory again since we deleted a named view
|
||||
tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
|
||||
// // Write the entire tomlString to a snapshot.
|
||||
// // There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-deleted')
|
||||
})
|
||||
test('Verify named view gets loaded', async ({
|
||||
cmdBar,
|
||||
scene,
|
||||
page,
|
||||
}, testInfo) => {
|
||||
const projectName = 'named-views'
|
||||
const myNamedView = 'uuid1'
|
||||
|
||||
// Create project and go into the project
|
||||
await createProject({ name: projectName, page })
|
||||
await scene.waitForExecutionDone()
|
||||
|
||||
// Create a new named view
|
||||
await cmdBar.openCmdBar()
|
||||
await cmdBar.chooseCommand('create named view')
|
||||
await cmdBar.argumentInput.fill(myNamedView)
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
// Generate file paths for project.toml
|
||||
const projectDirName = testInfo.outputPath('electron-test-projects-dir')
|
||||
const tempProjectSettingsFilePath = join(
|
||||
projectDirName,
|
||||
projectName,
|
||||
PROJECT_SETTINGS_FILE_NAME
|
||||
)
|
||||
|
||||
// Except the project.toml to be written to disk since a named view was created
|
||||
await expect(async () => {
|
||||
let exists = await fileExists(tempProjectSettingsFilePath)
|
||||
expect(exists).toBe(true)
|
||||
}).toPass()
|
||||
|
||||
// Read project.toml into memory
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
|
||||
|
||||
// Create a load a named view
|
||||
await cmdBar.openCmdBar()
|
||||
await cmdBar.chooseCommand('load named view')
|
||||
await cmdBar.argumentInput.fill(myNamedView)
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
// Check the toast appeared
|
||||
await expect(
|
||||
page.getByText(`Named view ${myNamedView} loaded.`)
|
||||
).toBeVisible()
|
||||
})
|
||||
test('Verify two named views get created', async ({
|
||||
cmdBar,
|
||||
scene,
|
||||
page,
|
||||
}, testInfo) => {
|
||||
const projectName = 'named-views'
|
||||
const myNamedView1 = 'uuid1'
|
||||
const myNamedView2 = 'uuid2'
|
||||
|
||||
// Create and load project
|
||||
await createProject({ name: projectName, page })
|
||||
await scene.waitForExecutionDone()
|
||||
|
||||
// Create named view
|
||||
const projectDirName = testInfo.outputPath('electron-test-projects-dir')
|
||||
await cmdBar.openCmdBar()
|
||||
await cmdBar.chooseCommand('create named view')
|
||||
await cmdBar.argumentInput.fill(myNamedView1)
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
const orbitMouseStart = { x: 800, y: 130 }
|
||||
const orbitMouseEnd = { x: 0, y: 130 }
|
||||
await page.mouse.move(orbitMouseStart.x, orbitMouseStart.y)
|
||||
await page.mouse.down({ button: 'middle' })
|
||||
await page.mouse.move(orbitMouseEnd.x, orbitMouseEnd.y, {
|
||||
steps: 3,
|
||||
})
|
||||
await page.mouse.up({ button: 'middle' })
|
||||
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
await cmdBar.openCmdBar()
|
||||
await cmdBar.chooseCommand('create named view')
|
||||
await cmdBar.argumentInput.fill(myNamedView2)
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
// Wait a moment for the project.toml to get written to disk with the new view point
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
// Generate paths for the project.toml
|
||||
const tempProjectSettingsFilePath = join(
|
||||
projectDirName,
|
||||
projectName,
|
||||
PROJECT_SETTINGS_FILE_NAME
|
||||
)
|
||||
|
||||
// Expect project.toml to be generated on disk since a named view was created
|
||||
await expect(async () => {
|
||||
let exists = await fileExists(tempProjectSettingsFilePath)
|
||||
expect(exists).toBe(true)
|
||||
}).toPass()
|
||||
|
||||
// Read project.toml into memory
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-two-named-view-gets-created')
|
||||
})
|
||||
})
|
@ -0,0 +1,16 @@
|
||||
[settings]
|
||||
modeling = { }
|
||||
text_editor = { }
|
||||
command_bar = { }
|
||||
|
||||
[settings.app.named_views.0656fb1a-9640-473e-b334-591dc70c0138]
|
||||
name = "uuid1"
|
||||
eye_offset = 1_378.0059
|
||||
fov_y = 45
|
||||
is_ortho = false
|
||||
ortho_scale_enabled = true
|
||||
ortho_scale_factor = 1.6
|
||||
pivot_position = [ 0, 0, 0 ]
|
||||
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
|
||||
world_coord_system = "right_handed_up_z"
|
||||
version = 1
|
@ -0,0 +1,16 @@
|
||||
[settings]
|
||||
modeling = { }
|
||||
text_editor = { }
|
||||
command_bar = { }
|
||||
|
||||
[settings.app.named_views.0656fb1a-9640-473e-b334-591dc70c0138]
|
||||
name = "uuid1"
|
||||
eye_offset = 1_378.0059
|
||||
fov_y = 45
|
||||
is_ortho = false
|
||||
ortho_scale_enabled = true
|
||||
ortho_scale_factor = 1.6
|
||||
pivot_position = [ 0, 0, 0 ]
|
||||
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
|
||||
world_coord_system = "right_handed_up_z"
|
||||
version = 1
|
@ -0,0 +1,28 @@
|
||||
[settings]
|
||||
modeling = { }
|
||||
text_editor = { }
|
||||
command_bar = { }
|
||||
|
||||
[settings.app.named_views.0656fb1a-9640-473e-b334-591dc70c0138]
|
||||
name = "uuid1"
|
||||
eye_offset = 1_378.0059
|
||||
fov_y = 45
|
||||
is_ortho = false
|
||||
ortho_scale_enabled = true
|
||||
ortho_scale_factor = 1.6
|
||||
pivot_position = [ 0, 0, 0 ]
|
||||
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
|
||||
world_coord_system = "right_handed_up_z"
|
||||
version = 1
|
||||
|
||||
[settings.app.named_views.c810cf04-c6cc-4a4a-8b11-17bf445dcab7]
|
||||
name = "uuid2"
|
||||
eye_offset = 1_378.0059
|
||||
fov_y = 45
|
||||
is_ortho = false
|
||||
ortho_scale_enabled = true
|
||||
ortho_scale_factor = 1.6
|
||||
pivot_position = [ 1_826.5239, 0.0, 0.0 ]
|
||||
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
|
||||
world_coord_system = "right_handed_up_z"
|
||||
version = 1
|
312
e2e/playwright/native-file-menu.spec.ts
Normal file
@ -0,0 +1,312 @@
|
||||
import { test, expect } from './zoo-test'
|
||||
|
||||
/**
|
||||
* Not all menu actions are tested. Some are default electron menu actions.
|
||||
* Test file menu actions that trigger something in the frontend
|
||||
*/
|
||||
test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
test.describe('Home page', () => {
|
||||
test.describe('File role', () => {
|
||||
test('File.Create project', async ({ tronApp, cmdBar, page }) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const newProject =
|
||||
app.applicationMenu.getMenuItemById('File.New project')
|
||||
if (!newProject) fail()
|
||||
newProject.click()
|
||||
})
|
||||
// Check that the command bar is opened
|
||||
await expect(cmdBar.cmdBarElement).toBeVisible()
|
||||
// Check the placeholder project name exists
|
||||
const actualArgument = await cmdBar.cmdBarElement
|
||||
.getByTestId('cmd-bar-arg-value')
|
||||
.inputValue()
|
||||
const expectedArgument = 'project-$nnn'
|
||||
expect(actualArgument).toBe(expectedArgument)
|
||||
})
|
||||
test('File.Open project', async ({ tronApp, cmdBar, page }) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const openProject =
|
||||
app.applicationMenu.getMenuItemById('File.Open project')
|
||||
if (!openProject) fail()
|
||||
openProject.click()
|
||||
})
|
||||
// Check that the command bar is opened
|
||||
await expect(cmdBar.cmdBarElement).toBeVisible()
|
||||
// Check the placeholder project name exists
|
||||
const actual = await cmdBar.cmdBarElement
|
||||
.getByTestId('command-name')
|
||||
.textContent()
|
||||
const expected = 'Open project'
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
test('File.Preferences.User settings', async ({
|
||||
tronApp,
|
||||
cmdBar,
|
||||
page,
|
||||
}) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const userSettings = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.User settings'
|
||||
)
|
||||
if (!userSettings) fail()
|
||||
userSettings.click()
|
||||
})
|
||||
const settings = page.getByTestId('settings-dialog-panel')
|
||||
await expect(settings).toBeVisible()
|
||||
// You are viewing the user tab
|
||||
const actualText = settings.getByText(
|
||||
'The overall appearance of the app'
|
||||
)
|
||||
await expect(actualText).toBeVisible()
|
||||
})
|
||||
test('File.Preferences.Keybindings', async ({
|
||||
tronApp,
|
||||
cmdBar,
|
||||
page,
|
||||
}) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const keybindings = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.Keybindings'
|
||||
)
|
||||
if (!keybindings) fail()
|
||||
keybindings.click()
|
||||
})
|
||||
const settings = page.getByTestId('settings-dialog-panel')
|
||||
await expect(settings).toBeVisible()
|
||||
// You are viewing the keybindings tab
|
||||
const enterSketchMode = settings.locator('#enter-sketch-mode')
|
||||
await expect(enterSketchMode).toBeVisible()
|
||||
})
|
||||
test('File.Preferences.User default units', async ({
|
||||
tronApp,
|
||||
cmdBar,
|
||||
page,
|
||||
}) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.User default units'
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
const settings = page.getByTestId('settings-dialog-panel')
|
||||
await expect(settings).toBeVisible()
|
||||
const defaultUnit = settings.locator('#defaultUnit')
|
||||
await expect(defaultUnit).toBeVisible()
|
||||
})
|
||||
test('File.Preferences.Theme', async ({ tronApp, cmdBar, page }) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.Theme'
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
// Check that the command bar is opened
|
||||
await expect(cmdBar.cmdBarElement).toBeVisible()
|
||||
// Check the placeholder project name exists
|
||||
const actual = await cmdBar.cmdBarElement
|
||||
.getByTestId('command-name')
|
||||
.textContent()
|
||||
const expected = 'Settings · app · theme'
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
test('File.Preferences.Theme color', async ({
|
||||
tronApp,
|
||||
cmdBar,
|
||||
page,
|
||||
}) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.Theme color'
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
const settings = page.getByTestId('settings-dialog-panel')
|
||||
await expect(settings).toBeVisible()
|
||||
const defaultUnit = settings.locator('#themeColor')
|
||||
await expect(defaultUnit).toBeVisible()
|
||||
})
|
||||
test('File.Preferences.Sign out', async ({ tronApp, cmdBar, page }) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById('File.Sign out')
|
||||
if (!menu) fail()
|
||||
// FIXME: Add back when you can actually sign out
|
||||
// menu.click()
|
||||
})
|
||||
// FIXME: When signing out during E2E the page is not bound correctly.
|
||||
// It cannot find the button
|
||||
// const signIn = page.getByTestId('sign-in-button')
|
||||
// await expect(signIn).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Edit role', () => {
|
||||
test('Edit.Rename project', async ({ tronApp, cmdBar, page }) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Edit.Rename project'
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
// Check the placeholder project name exists
|
||||
const actual = await cmdBar.cmdBarElement
|
||||
.getByTestId('command-name')
|
||||
.textContent()
|
||||
const expected = 'Rename project'
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
test('Edit.Delete project', async ({ tronApp, cmdBar, page }) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Edit.Delete project'
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
// Check the placeholder project name exists
|
||||
const actual = await cmdBar.cmdBarElement
|
||||
.getByTestId('command-name')
|
||||
.textContent()
|
||||
const expected = 'Delete project'
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
test('Edit.Change project directory', async ({
|
||||
tronApp,
|
||||
cmdBar,
|
||||
page,
|
||||
}) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Edit.Change project directory'
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
const settings = page.getByTestId('settings-dialog-panel')
|
||||
await expect(settings).toBeVisible()
|
||||
const projectDirectory = settings.locator('#projectDirectory')
|
||||
await expect(projectDirectory).toBeVisible()
|
||||
})
|
||||
})
|
||||
test.describe('View role', () => {
|
||||
test('View.Command Palette...', async ({ tronApp, cmdBar, page }) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'View.Command Palette...'
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
// Check the placeholder project name exists
|
||||
const actual = cmdBar.cmdBarElement.getByTestId('cmd-bar-search')
|
||||
await expect(actual).toBeVisible()
|
||||
})
|
||||
})
|
||||
test.describe('Help role', () => {
|
||||
test('Help.Show all commands', async ({ tronApp, cmdBar, page }) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Show all commands'
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
// Check the placeholder project name exists
|
||||
const actual = cmdBar.cmdBarElement.getByTestId('cmd-bar-search')
|
||||
await expect(actual).toBeVisible()
|
||||
})
|
||||
test('Help.KCL code samples', async ({ tronApp, cmdBar, page }) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.KCL code samples'
|
||||
)
|
||||
if (!menu) fail()
|
||||
})
|
||||
})
|
||||
test('Help.Refresh and report a bug', async ({
|
||||
tronApp,
|
||||
cmdBar,
|
||||
page,
|
||||
}) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Refresh and report a bug'
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
// Core dump and refresh magic number timeout
|
||||
await page.waitForTimeout(7000)
|
||||
const actual = page.getByText(
|
||||
'No Projects found, ready to make your first one?'
|
||||
)
|
||||
await expect(actual).toBeVisible()
|
||||
})
|
||||
test('Help.Reset onboarding', async ({ tronApp, cmdBar, page }) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Reset onboarding'
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
|
||||
const actual = page.getByText(
|
||||
`This is a hardware design tool that lets you edit visually, with code, or both. It's powered by the KittyCAD Design API, the first API created for anyone to build hardware design tools.`
|
||||
)
|
||||
await expect(actual).toBeVisible()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
@ -1082,8 +1082,8 @@ openSketch = startSketchOn(XY)
|
||||
}) => {
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 620, y: 257 }
|
||||
const expectedOutput = `helix001 = helix( revolutions = 1, angleStart = 360, ccw = false, radius = 5, axis = 'X', length = 5,)`
|
||||
const expectedLine = `revolutions=1,`
|
||||
const expectedOutput = `helix001 = helix( axis = 'X', radius = 5, length = 5, revolutions = 1, angleStart = 360, ccw = false,)`
|
||||
const expectedLine = `axis='X',`
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
@ -1091,17 +1091,17 @@ openSketch = startSketchOn(XY)
|
||||
await toolbar.helixButton.click()
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'axisOrEdge',
|
||||
currentArgKey: 'mode',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Mode: '',
|
||||
AngleStart: '',
|
||||
AxisOrEdge: '',
|
||||
CounterClockWise: '',
|
||||
Revolutions: '',
|
||||
Length: '',
|
||||
Radius: '',
|
||||
Revolutions: '',
|
||||
CounterClockWise: '',
|
||||
},
|
||||
highlightedHeaderArg: 'axisOrEdge',
|
||||
highlightedHeaderArg: 'mode',
|
||||
commandName: 'Helix',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
@ -1110,7 +1110,19 @@ openSketch = startSketchOn(XY)
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
Mode: 'Axis',
|
||||
Axis: 'X',
|
||||
AngleStart: '360',
|
||||
Revolutions: '1',
|
||||
Length: '5',
|
||||
Radius: '5',
|
||||
CounterClockWise: '',
|
||||
},
|
||||
commandName: 'Helix',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
})
|
||||
|
||||
@ -1134,30 +1146,31 @@ openSketch = startSketchOn(XY)
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Helix',
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'length',
|
||||
currentArgValue: initialInput,
|
||||
currentArgKey: 'CounterClockWise',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
AngleStart: '360',
|
||||
Axis: 'X',
|
||||
CounterClockWise: '',
|
||||
Length: initialInput,
|
||||
Radius: '5',
|
||||
AngleStart: '360',
|
||||
Revolutions: '1',
|
||||
Radius: '5',
|
||||
Length: initialInput,
|
||||
CounterClockWise: '',
|
||||
},
|
||||
highlightedHeaderArg: 'length',
|
||||
highlightedHeaderArg: 'CounterClockWise',
|
||||
})
|
||||
await page.keyboard.press('Shift+Backspace')
|
||||
await expect(cmdBar.currentArgumentInput).toBeVisible()
|
||||
await cmdBar.currentArgumentInput.locator('.cm-content').fill(newInput)
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
AngleStart: '360',
|
||||
Axis: 'X',
|
||||
CounterClockWise: '',
|
||||
Length: newInput,
|
||||
Radius: '5',
|
||||
AngleStart: '360',
|
||||
Revolutions: '1',
|
||||
Radius: '5',
|
||||
Length: newInput,
|
||||
CounterClockWise: '',
|
||||
},
|
||||
commandName: 'Helix',
|
||||
})
|
||||
@ -1181,14 +1194,14 @@ openSketch = startSketchOn(XY)
|
||||
{
|
||||
selectionType: 'segment',
|
||||
testPoint: { x: 513, y: 221 },
|
||||
expectedOutput: `helix001 = helix( revolutions = 20, angleStart = 0, ccw = true, radius = 1, axis = seg01, length = 100,)`,
|
||||
expectedEditedOutput: `helix001 = helix( revolutions = 20, angleStart = 0, ccw = true, radius = 1, axis = seg01, length = 50,)`,
|
||||
expectedOutput: `helix001 = helix( axis = seg01, radius = 1, length = 100, revolutions = 20, angleStart = 0, ccw = false,)`,
|
||||
expectedEditedOutput: `helix001 = helix( axis = seg01, radius = 1, length = 50, revolutions = 20, angleStart = 0, ccw = false,)`,
|
||||
},
|
||||
{
|
||||
selectionType: 'sweepEdge',
|
||||
testPoint: { x: 564, y: 364 },
|
||||
expectedOutput: `helix001 = helix( revolutions = 20, angleStart = 0, ccw = true, radius = 1, axis = getOppositeEdge(seg01), length = 100,)`,
|
||||
expectedEditedOutput: `helix001 = helix( revolutions = 20, angleStart = 0, ccw = true, radius = 1, axis = getOppositeEdge(seg01), length = 50,)`,
|
||||
expectedOutput: `helix001 = helix( axis = getOppositeEdge(seg01), radius = 1, length = 100, revolutions = 20, angleStart = 0, ccw = false,)`,
|
||||
expectedEditedOutput: `helix001 = helix( axis = getOppositeEdge(seg01), radius = 1, length = 50, revolutions = 20, angleStart = 0, ccw = false,)`,
|
||||
},
|
||||
]
|
||||
helixCases.map(
|
||||
@ -1225,17 +1238,17 @@ openSketch = startSketchOn(XY)
|
||||
await toolbar.helixButton.click()
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'axisOrEdge',
|
||||
currentArgKey: 'mode',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
AngleStart: '',
|
||||
AxisOrEdge: '',
|
||||
Mode: '',
|
||||
CounterClockWise: '',
|
||||
Length: '',
|
||||
Radius: '',
|
||||
Revolutions: '',
|
||||
},
|
||||
highlightedHeaderArg: 'axisOrEdge',
|
||||
highlightedHeaderArg: 'mode',
|
||||
commandName: 'Helix',
|
||||
})
|
||||
await cmdBar.selectOption({ name: 'Edge' }).click()
|
||||
@ -1246,7 +1259,6 @@ openSketch = startSketchOn(XY)
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.keyboard.insertText('0')
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.selectOption({ name: 'True' }).click()
|
||||
await page.keyboard.insertText('1')
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.keyboard.insertText('100')
|
||||
@ -1254,13 +1266,13 @@ openSketch = startSketchOn(XY)
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
AngleStart: '0',
|
||||
AxisOrEdge: 'Edge',
|
||||
Mode: 'Edge',
|
||||
Edge: `1 ${selectionType}`,
|
||||
CounterClockWise: '',
|
||||
Length: '100',
|
||||
Radius: '1',
|
||||
AngleStart: '0',
|
||||
Revolutions: '20',
|
||||
Radius: '1',
|
||||
Length: '100',
|
||||
CounterClockWise: '',
|
||||
},
|
||||
commandName: 'Helix',
|
||||
})
|
||||
@ -1285,17 +1297,18 @@ openSketch = startSketchOn(XY)
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Helix',
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'length',
|
||||
currentArgValue: initialInput,
|
||||
currentArgKey: 'CounterClockWise',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
AngleStart: '0',
|
||||
CounterClockWise: '',
|
||||
Length: initialInput,
|
||||
Radius: '1',
|
||||
Revolutions: '20',
|
||||
Radius: '1',
|
||||
Length: initialInput,
|
||||
CounterClockWise: '',
|
||||
},
|
||||
highlightedHeaderArg: 'length',
|
||||
highlightedHeaderArg: 'CounterClockWise',
|
||||
})
|
||||
await page.keyboard.press('Shift+Backspace')
|
||||
await expect(cmdBar.currentArgumentInput).toBeVisible()
|
||||
await cmdBar.currentArgumentInput
|
||||
.locator('.cm-content')
|
||||
@ -1305,10 +1318,10 @@ openSketch = startSketchOn(XY)
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
AngleStart: '0',
|
||||
CounterClockWise: '',
|
||||
Length: newInput,
|
||||
Radius: '1',
|
||||
Revolutions: '20',
|
||||
Radius: '1',
|
||||
Length: newInput,
|
||||
CounterClockWise: '',
|
||||
},
|
||||
commandName: 'Helix',
|
||||
})
|
||||
@ -1336,6 +1349,141 @@ openSketch = startSketchOn(XY)
|
||||
}
|
||||
)
|
||||
|
||||
test('Helix point-and-click on cylinder', async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
editor,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const initialCode = `sketch001 = startSketchOn(XY)
|
||||
profile001 = circle(
|
||||
sketch001,
|
||||
center = [0, 0],
|
||||
radius = 100,
|
||||
tag = $seg01,
|
||||
)
|
||||
extrude001 = extrude(profile001, length = 100)
|
||||
`
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 620, y: 257 }
|
||||
const [clickOnWall] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
||||
const expectedOutput = `helix001 = helix( cylinder = extrude001, revolutions = 1, angleStart = 360, ccw = false,)`
|
||||
const expectedLine = `cylinder = extrude001,`
|
||||
const expectedEditedOutput = `helix001 = helix( cylinder = extrude001, revolutions = 1, angleStart = 360, ccw = true,)`
|
||||
|
||||
await test.step(`Go through the command bar flow`, async () => {
|
||||
await toolbar.helixButton.click()
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'mode',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Mode: '',
|
||||
AngleStart: '',
|
||||
Revolutions: '',
|
||||
Length: '',
|
||||
Radius: '',
|
||||
CounterClockWise: '',
|
||||
},
|
||||
highlightedHeaderArg: 'mode',
|
||||
commandName: 'Helix',
|
||||
})
|
||||
await cmdBar.selectOption({ name: 'Cylinder' }).click()
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'cylinder',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Mode: 'Cylinder',
|
||||
Cylinder: '',
|
||||
AngleStart: '',
|
||||
Revolutions: '',
|
||||
CounterClockWise: '',
|
||||
},
|
||||
highlightedHeaderArg: 'cylinder',
|
||||
commandName: 'Helix',
|
||||
})
|
||||
await clickOnWall()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
Mode: 'Cylinder',
|
||||
Cylinder: '1 face',
|
||||
AngleStart: '360',
|
||||
Revolutions: '1',
|
||||
CounterClockWise: '',
|
||||
},
|
||||
commandName: 'Helix',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
})
|
||||
|
||||
await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
|
||||
await editor.expectEditor.toContain(expectedOutput)
|
||||
await editor.expectState({
|
||||
diagnostics: [],
|
||||
activeLines: [expectedLine],
|
||||
highlightedCode: '',
|
||||
})
|
||||
})
|
||||
|
||||
await test.step(`Edit helix through the feature tree`, async () => {
|
||||
await editor.closePane()
|
||||
const operationButton = await toolbar.getFeatureTreeOperation('Helix', 0)
|
||||
await operationButton.dblclick()
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Helix',
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'CounterClockWise',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
AngleStart: '360',
|
||||
Revolutions: '1',
|
||||
CounterClockWise: '',
|
||||
},
|
||||
highlightedHeaderArg: 'CounterClockWise',
|
||||
})
|
||||
await cmdBar.selectOption({ name: 'True' }).click()
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
AngleStart: '360',
|
||||
Revolutions: '1',
|
||||
CounterClockWise: 'true',
|
||||
},
|
||||
commandName: 'Helix',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
await toolbar.closePane('feature-tree')
|
||||
await toolbar.openPane('code')
|
||||
await editor.expectEditor.toContain(expectedEditedOutput)
|
||||
await editor.closePane()
|
||||
})
|
||||
|
||||
await test.step('Delete helix via feature tree selection', async () => {
|
||||
await toolbar.openPane('feature-tree')
|
||||
const operationButton = await toolbar.getFeatureTreeOperation('Helix', 0)
|
||||
await operationButton.click({ button: 'left' })
|
||||
await page.keyboard.press('Delete')
|
||||
await toolbar.closePane('feature-tree')
|
||||
await toolbar.openPane('code')
|
||||
await editor.expectEditor.not.toContain(expectedEditedOutput)
|
||||
})
|
||||
})
|
||||
|
||||
const loftPointAndClickCases = [
|
||||
{ shouldPreselect: true },
|
||||
{ shouldPreselect: false },
|
||||
@ -3321,7 +3469,7 @@ segAng(rectangleSegmentA002),
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.progressCmdBar()
|
||||
|
||||
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = 'X')`
|
||||
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = X)`
|
||||
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
|
||||
})
|
||||
test('revolve surface around edge from an extruded solid2d', async ({
|
||||
|
@ -473,6 +473,9 @@ test.describe('Can export from electron app', () => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
if (runningOnWindows()) {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
}
|
||||
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'bracket')
|
||||
|
@ -778,6 +778,19 @@ plane002 = offsetPlane(XZ, offset = -2 * x)`
|
||||
await editor.expectEditor.not.toContain(`plane002`)
|
||||
})
|
||||
})
|
||||
|
||||
test.fail(
|
||||
'Console errors cause tests to fail',
|
||||
async ({ page, homePage }) => {
|
||||
const u = await getUtils(page)
|
||||
await homePage.goToModelingScene()
|
||||
await u.openAndClearDebugPanel()
|
||||
|
||||
await page.getByTestId('custom-cmd-input').fill('foobar')
|
||||
await page.getByTestId('custom-cmd-send-button').scrollIntoViewIfNeeded()
|
||||
await page.getByTestId('custom-cmd-send-button').click()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
async function clickExportButton(page: Page) {
|
||||
|
@ -674,7 +674,7 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
|
||||
|> line(end = [12.73, -0.09])
|
||||
|> tangentialArcTo([24.95, -5.38], %)
|
||||
|> close()
|
||||
|> revolve(axis = "X")`
|
||||
|> revolve(axis = X)`
|
||||
)
|
||||
})
|
||||
|
||||
@ -761,7 +761,7 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
|
||||
|> tangentialArcTo([24.95, -5.38], %)
|
||||
|> line(end = [1.97, 2.06])
|
||||
|> close()
|
||||
|> revolve(axis = "X")`)
|
||||
|> revolve(axis = X)`)
|
||||
})
|
||||
test('Can add multiple sketches', async ({ page, homePage }) => {
|
||||
const u = await getUtils(page)
|
||||
@ -1209,7 +1209,7 @@ profile001 = startProfileAt([${roundOff(scale * 69.6)}, ${roundOff(
|
||||
|> xLine(endAbsolute = 0 + .001)
|
||||
|> yLine(endAbsolute = 0)
|
||||
|> close()
|
||||
|> revolve(axis = "Y")
|
||||
|> revolve(axis = Y)
|
||||
|
||||
return lugSketch
|
||||
}
|
||||
|
@ -76,11 +76,11 @@ part001 = startSketchOn(-XZ)
|
||||
|> xLine(endAbsolute = totalLen, tag = $seg03)
|
||||
|> yLine(length = -armThick, tag = $seg01)
|
||||
|> angledLineThatIntersects({
|
||||
angle = HALF_TURN,
|
||||
angle = turns::HALF_TURN,
|
||||
offset = -armThick,
|
||||
intersectTag = seg04
|
||||
}, %)
|
||||
|> angledLineToY([segAng(seg04, %) + 180, ZERO], %)
|
||||
|> angledLineToY([segAng(seg04, %) + 180, turns::ZERO], %)
|
||||
|> angledLineToY({
|
||||
angle = -bottomAng,
|
||||
to = -totalHeightHalf - armThick,
|
||||
@ -88,12 +88,12 @@ part001 = startSketchOn(-XZ)
|
||||
|> xLine(length = endAbsolute = segEndX(seg03) + 0)
|
||||
|> yLine(length = -segLen(seg01, %))
|
||||
|> angledLineThatIntersects({
|
||||
angle = HALF_TURN,
|
||||
angle = turns::HALF_TURN,
|
||||
offset = -armThick,
|
||||
intersectTag = seg02
|
||||
}, %)
|
||||
|> angledLineToY([segAng(seg02, %) + 180, -baseHeight], %)
|
||||
|> xLine(endAbsolute = ZERO)
|
||||
|> xLine(endAbsolute = turns::ZERO)
|
||||
|> close()
|
||||
|> extrude(length = 4)`
|
||||
)
|
||||
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
@ -26,6 +26,7 @@ import { isArray } from 'lib/utils'
|
||||
import { reportRejection } from 'lib/trap'
|
||||
import { DeepPartial } from 'lib/types'
|
||||
import { Configuration } from 'lang/wasm'
|
||||
import { ProjectConfiguration } from '@rust/kcl-lib/bindings/ProjectConfiguration'
|
||||
|
||||
const toNormalizedCode = (text: string) => {
|
||||
return text.replace(/\s+/g, '')
|
||||
@ -761,7 +762,7 @@ export interface Paths {
|
||||
}
|
||||
|
||||
export const doExport = async (
|
||||
output: Models['OutputFormat_type'],
|
||||
output: Models['OutputFormat3d_type'],
|
||||
rootDir: string,
|
||||
page: Page,
|
||||
exportFrom: 'dropdown' | 'sidebarButton' | 'commandBar' = 'dropdown'
|
||||
@ -934,47 +935,39 @@ export async function setup(
|
||||
}
|
||||
|
||||
function failOnConsoleErrors(page: Page, testInfo?: TestInfo) {
|
||||
// enabled for chrome for now
|
||||
if (page.context().browser()?.browserType().name() === 'chromium') {
|
||||
// No idea wtf exception is
|
||||
page.on('pageerror', (exception: any) => {
|
||||
if (isErrorWhitelisted(exception)) {
|
||||
return
|
||||
}
|
||||
page.on('pageerror', (exception: any) => {
|
||||
if (isErrorWhitelisted(exception)) {
|
||||
return
|
||||
}
|
||||
// Only disable this environment variable if you want to collect console errors
|
||||
if (process.env.FAIL_ON_CONSOLE_ERRORS !== 'false') {
|
||||
// Use expect to prevent page from closing and not cleaning up
|
||||
expect(`An error was detected in the console: \r\n message:${exception.message} \r\n name:${exception.name} \r\n stack:${exception.stack}
|
||||
|
||||
// only set this env var to false if you want to collect console errors
|
||||
// This can be configured in the GH workflow. This should be set to true by default (we want tests to fail when
|
||||
// unwhitelisted console errors are detected).
|
||||
if (process.env.FAIL_ON_CONSOLE_ERRORS === 'true') {
|
||||
// Fail when running on CI and FAIL_ON_CONSOLE_ERRORS is set
|
||||
// use expect to prevent page from closing and not cleaning up
|
||||
expect(`An error was detected in the console: \r\n message:${exception.message} \r\n name:${exception.name} \r\n stack:${exception.stack}
|
||||
|
||||
*Either fix the console error or add it to the whitelist defined in ./lib/console-error-whitelist.ts (if the error can be safely ignored)
|
||||
`).toEqual('Console error detected')
|
||||
} else {
|
||||
// the (test-results/exceptions.txt) file will be uploaded as part of an upload artifact in GH
|
||||
fsp
|
||||
.appendFile(
|
||||
'./test-results/exceptions.txt',
|
||||
[
|
||||
'~~~',
|
||||
`triggered_by_test:${
|
||||
testInfo?.file + ' ' + (testInfo?.title || ' ')
|
||||
}`,
|
||||
`name:${exception.name}`,
|
||||
`message:${exception.message}`,
|
||||
`stack:${exception.stack}`,
|
||||
`project:${testInfo?.project.name}`,
|
||||
'~~~',
|
||||
].join('\n')
|
||||
)
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
*Either fix the console error or add it to the whitelist defined in ./lib/console-error-whitelist.ts (if the error can be safely ignored)
|
||||
`).toEqual('Console error detected')
|
||||
} else {
|
||||
// Add errors to `test-results/exceptions.txt` as a test artifact
|
||||
fsp
|
||||
.appendFile(
|
||||
'./test-results/exceptions.txt',
|
||||
[
|
||||
'~~~',
|
||||
`triggered_by_test:${
|
||||
testInfo?.file + ' ' + (testInfo?.title || ' ')
|
||||
}`,
|
||||
`name:${exception.name}`,
|
||||
`message:${exception.message}`,
|
||||
`stack:${exception.stack}`,
|
||||
`project:${testInfo?.project.name}`,
|
||||
'~~~',
|
||||
].join('\n')
|
||||
)
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
export async function isOutOfViewInScrollContainer(
|
||||
element: Locator,
|
||||
@ -1125,3 +1118,15 @@ export function settingsToToml(settings: DeepPartial<Configuration>) {
|
||||
export function tomlToSettings(toml: string): DeepPartial<Configuration> {
|
||||
return TOML.parse(toml)
|
||||
}
|
||||
|
||||
export function tomlToPerProjectSettings(
|
||||
toml: string
|
||||
): DeepPartial<ProjectConfiguration> {
|
||||
return TOML.parse(toml)
|
||||
}
|
||||
|
||||
export function perProjectsettingsToToml(
|
||||
settings: DeepPartial<ProjectConfiguration>
|
||||
) {
|
||||
return TOML.stringify(settings as any)
|
||||
}
|
||||
|
@ -486,13 +486,13 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
testName: 'Add variable, selecting axis',
|
||||
addVariable: true,
|
||||
axisSelect: true,
|
||||
value: 'QUARTER_TURN - angle001',
|
||||
value: 'turns::QUARTER_TURN - angle001',
|
||||
},
|
||||
{
|
||||
testName: 'No variable, selecting axis',
|
||||
addVariable: false,
|
||||
axisSelect: true,
|
||||
value: 'QUARTER_TURN - 7',
|
||||
value: 'turns::QUARTER_TURN - 7',
|
||||
},
|
||||
] as const
|
||||
for (const { testName, addVariable, value, axisSelect } of cases) {
|
||||
@ -935,12 +935,12 @@ part002 = startSketchOn(XZ)
|
||||
test.describe('Axis & segment - no modal constraints', () => {
|
||||
const cases = [
|
||||
{
|
||||
codeAfter: `|> line(endAbsolute = [154.9, ZERO])`,
|
||||
codeAfter: `|> line(endAbsolute = [154.9, turns::ZERO])`,
|
||||
axisClick: { x: 950, y: 250 },
|
||||
constraintName: 'Snap To X',
|
||||
},
|
||||
{
|
||||
codeAfter: `|> line(endAbsolute = [ZERO, 61.34])`,
|
||||
codeAfter: `|> line(endAbsolute = [turns::ZERO, 61.34])`,
|
||||
axisClick: { x: 600, y: 150 },
|
||||
constraintName: 'Snap To Y',
|
||||
},
|
||||
|
@ -319,7 +319,7 @@ part009 = startSketchOn(XY)
|
||||
|> line(end = [0, pipeLength])
|
||||
|> angledLineToX({ angle = 60, to = pipeLargeDia }, %)
|
||||
|> close()
|
||||
rev = revolve(part009, axis = 'y')
|
||||
rev = revolve(part009, axis = Y)
|
||||
sketch006 = startSketchOn(XY)
|
||||
profile001 = circle(
|
||||
sketch006,
|
||||
@ -376,7 +376,7 @@ profile003 = startProfileAt([40.16, -120.48], sketch006)
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
await expect(u.codeLocator).not.toContainText(
|
||||
`rev = revolve(part009, axis: 'y')`
|
||||
`rev = revolve(part009, axis: Y)`
|
||||
)
|
||||
|
||||
// FIXME (commented section below), this test would select a wall that had a sketch on it, and delete the underlying extrude
|
||||
|
@ -67,11 +67,11 @@ part001 = startSketchOn(-XZ)
|
||||
|> xLine(endAbsolute = totalLen, tag = $seg03)
|
||||
|> yLine(length = -armThick, tag = $seg01)
|
||||
|> angledLineThatIntersects({
|
||||
angle = HALF_TURN,
|
||||
angle = turns::HALF_TURN,
|
||||
offset = -armThick,
|
||||
intersectTag = seg04
|
||||
}, %)
|
||||
|> angledLineToY([segAng(seg04) + 180, ZERO], %)
|
||||
|> angledLineToY([segAng(seg04) + 180, turns::ZERO], %)
|
||||
|> angledLineToY({
|
||||
angle = -bottomAng,
|
||||
to = -totalHeightHalf - armThick,
|
||||
@ -79,12 +79,12 @@ part001 = startSketchOn(-XZ)
|
||||
|> xLine(endAbsolute = segEndX(seg03) + 0)
|
||||
|> yLine(length = -segLen(seg01))
|
||||
|> angledLineThatIntersects({
|
||||
angle = HALF_TURN,
|
||||
angle = turns::HALF_TURN,
|
||||
offset = -armThick,
|
||||
intersectTag = seg02
|
||||
}, %)
|
||||
|> angledLineToY([segAng(seg02) + 180, -baseHeight], %)
|
||||
|> xLine(endAbsolute = ZERO)
|
||||
|> xLine(endAbsolute = turns::ZERO)
|
||||
|> close()
|
||||
|> extrude(length = 4)`
|
||||
)
|
||||
|
20
interface.d.ts
vendored
@ -3,6 +3,18 @@ import fsSync from 'node:fs'
|
||||
import path from 'path'
|
||||
import { dialog, shell } from 'electron'
|
||||
import { MachinesListing } from 'components/MachineManagerProvider'
|
||||
import type { Channel } from 'src/menu/channels'
|
||||
import { Menu, WebContents } from 'electron'
|
||||
import { ZooLabel, ZooMenuEvents } from 'menu/roles'
|
||||
import type { MenuActionIPC } from 'menu/rules'
|
||||
import type { WebContentSendPayload } from 'menu/channels'
|
||||
|
||||
// Extend the interface with additional custom properties
|
||||
declare module 'electron' {
|
||||
interface Menu {
|
||||
label?: ZooLabel
|
||||
}
|
||||
}
|
||||
|
||||
type EnvFn = (value?: string) => string
|
||||
|
||||
@ -94,6 +106,14 @@ export interface IElectronAPI {
|
||||
appCheckForUpdates: () => Promise<unknown>
|
||||
getArgvParsed: () => any
|
||||
getAppTestProperty: (propertyName: string) => any
|
||||
|
||||
// Helper functions to create application Menus
|
||||
createHomePageMenu: () => Promise<any>
|
||||
createModelingPageMenu: () => Promise<any>
|
||||
createFallbackMenu: () => Promise<any>
|
||||
enableMenu(menuId: string): Promise<any>
|
||||
disableMenu(menuId: string): Promise<any>
|
||||
menuOn: (callback: (payload: WebContentSendPayload) => void) => any
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -26,7 +26,7 @@
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@headlessui/react": "^1.7.19",
|
||||
"@headlessui/tailwindcss": "^0.2.0",
|
||||
"@kittycad/lib": "2.0.17",
|
||||
"@kittycad/lib": "2.0.21",
|
||||
"@lezer/highlight": "^1.2.1",
|
||||
"@lezer/lr": "^1.4.1",
|
||||
"@react-hook/resize-observer": "^2.0.1",
|
||||
|
@ -7,7 +7,7 @@
|
||||
// Define function
|
||||
fn rail8020(originStart, railHeight, railLength) {
|
||||
// Sketch side 1 of profile
|
||||
sketch001 = startSketchOn('-XZ')
|
||||
sketch001 = startSketchOn(-XZ)
|
||||
|> startProfileAt([
|
||||
originStart[0],
|
||||
0.1 * railHeight + originStart[1]
|
||||
@ -194,7 +194,7 @@ fn rail8020(originStart, railHeight, railLength) {
|
||||
.5 * railHeight + originStart[0],
|
||||
.5 * railHeight + originStart[1]
|
||||
],
|
||||
radius = .205 * railHeight / 2
|
||||
radius = .205 * railHeight / 2,
|
||||
), %)
|
||||
|> extrude(length = railLength)
|
||||
|> fillet(
|
||||
@ -216,7 +216,7 @@ fn rail8020(originStart, railHeight, railLength) {
|
||||
getNextAdjacentEdge(edge28),
|
||||
getNextAdjacentEdge(edge29),
|
||||
getNextAdjacentEdge(edge30)
|
||||
]
|
||||
],
|
||||
)
|
||||
|> fillet(
|
||||
radius = 0.03,
|
||||
@ -237,7 +237,7 @@ fn rail8020(originStart, railHeight, railLength) {
|
||||
getNextAdjacentEdge(edge26),
|
||||
getNextAdjacentEdge(edge31),
|
||||
getNextAdjacentEdge(edge32)
|
||||
]
|
||||
],
|
||||
)
|
||||
return sketch001
|
||||
}
|
||||
|
@ -41,6 +41,8 @@ When you submit a PR to add or modify KCL samples, images and STEP files will be
|
||||
[](cycloidal-gear/main.kcl)
|
||||
#### [dodecahedron](dodecahedron/main.kcl) ([screenshot](screenshots/dodecahedron.png))
|
||||
[](dodecahedron/main.kcl)
|
||||
#### [dual-basin-utility-sink](dual-basin-utility-sink/main.kcl) ([screenshot](screenshots/dual-basin-utility-sink.png))
|
||||
[](dual-basin-utility-sink/main.kcl)
|
||||
#### [enclosure](enclosure/main.kcl) ([screenshot](screenshots/enclosure.png))
|
||||
[](enclosure/main.kcl)
|
||||
#### [exhaust-manifold](exhaust-manifold/main.kcl) ([screenshot](screenshots/exhaust-manifold.png))
|
||||
@ -75,6 +77,8 @@ When you submit a PR to add or modify KCL samples, images and STEP files will be
|
||||
[](kitt/main.kcl)
|
||||
#### [lego](lego/main.kcl) ([screenshot](screenshots/lego.png))
|
||||
[](lego/main.kcl)
|
||||
#### [makeup-mirror](makeup-mirror/main.kcl) ([screenshot](screenshots/makeup-mirror.png))
|
||||
[](makeup-mirror/main.kcl)
|
||||
#### [mounting-plate](mounting-plate/main.kcl) ([screenshot](screenshots/mounting-plate.png))
|
||||
[](mounting-plate/main.kcl)
|
||||
#### [multi-axis-robot](multi-axis-robot/main.kcl) ([screenshot](screenshots/multi-axis-robot.png))
|
||||
|
@ -15,57 +15,37 @@ padding = 1.5
|
||||
bearingDia = 3
|
||||
|
||||
// (Needs to be updated). Sketch the block and extrude up to where the counterbore diameter starts.
|
||||
extrude001 = startSketchOn('XY')
|
||||
extrude001 = startSketchOn(XY)
|
||||
|> startProfileAt([-width / 2, -length / 2], %)
|
||||
|> line(endAbsolute = [width / 2, -length / 2])
|
||||
|> line(endAbsolute = [width / 2, length / 2])
|
||||
|> line(endAbsolute = [-width / 2, length / 2])
|
||||
|> close()
|
||||
|> extrude(length = height)
|
||||
|
||||
extrude002 = startSketchOn(extrude001, 'end')
|
||||
|> circle(
|
||||
center = [
|
||||
center = [
|
||||
-(width / 2 - (padding / 2)),
|
||||
-(length / 2 - (padding / 2))
|
||||
],
|
||||
radius = cbDia / 2,
|
||||
],
|
||||
radius = cbDia / 2,
|
||||
)
|
||||
|> patternLinear2d(
|
||||
instances = 2,
|
||||
distance = length - padding,
|
||||
axis = [0, 1],
|
||||
)
|
||||
|> patternLinear2d(
|
||||
instances = 2,
|
||||
distance = width - padding,
|
||||
axis = [1, 0],
|
||||
)
|
||||
|> patternLinear2d(instances = 2, distance = length - padding, axis = [0, 1])
|
||||
|> patternLinear2d(instances = 2, distance = width - padding, axis = [1, 0])
|
||||
|> extrude(%, length = -cbDepth)
|
||||
|
||||
extrude003 = startSketchOn(extrude001, 'start')
|
||||
|> circle(
|
||||
center = [
|
||||
-(width / 2 - (padding / 2)),
|
||||
-(length / 2 - (padding / 2))
|
||||
],
|
||||
radius = holeDia / 2,
|
||||
center = [
|
||||
-(width / 2 - (padding / 2)),
|
||||
-(length / 2 - (padding / 2))
|
||||
],
|
||||
radius = holeDia / 2,
|
||||
)
|
||||
|> patternLinear2d(
|
||||
instances = 2,
|
||||
distance = length - padding,
|
||||
axis = [0, 1],
|
||||
)
|
||||
|> patternLinear2d(
|
||||
instances = 2,
|
||||
distance = width - padding,
|
||||
axis = [1, 0],
|
||||
)
|
||||
|> patternLinear2d(instances = 2, distance = length - padding, axis = [0, 1])
|
||||
|> patternLinear2d(instances = 2, distance = width - padding, axis = [1, 0])
|
||||
|> extrude(length = -height + cbDepth)
|
||||
|
||||
extrude004 = startSketchOn(extrude001, 'end')
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = bearingDia/2,
|
||||
)
|
||||
|> extrude(length = -height)
|
||||
|> circle(center = [0, 0], radius = bearingDia / 2)
|
||||
|> extrude(length = -height)
|
||||
|
@ -17,21 +17,15 @@ chainThickness = sphereDia / 8
|
||||
linkDiameter = sphereDia / 4
|
||||
|
||||
// Sketch the inside bearing piece
|
||||
insideWallSketch = startSketchOn(offsetPlane("XY", offset = -overallThickness / 2))
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = shaftDia / 2 + wallThickness
|
||||
)
|
||||
|> hole(circle(
|
||||
center = [0, 0],
|
||||
radius = shaftDia / 2
|
||||
), %)
|
||||
insideWallSketch = startSketchOn(offsetPlane(XY, offset = -overallThickness / 2))
|
||||
|> circle(center = [0, 0], radius = shaftDia / 2 + wallThickness)
|
||||
|> hole(circle(center = [0, 0], radius = shaftDia / 2), %)
|
||||
|
||||
// Extrude the inside bearing piece
|
||||
insideWall = extrude(insideWallSketch, length = overallThickness)
|
||||
|
||||
// Create the sketch of one of the balls
|
||||
ballsSketch = startSketchOn("XY")
|
||||
ballsSketch = startSketchOn(XY)
|
||||
|> startProfileAt([shaftDia / 2 + wallThickness, 0.001], %)
|
||||
|> arc({
|
||||
angleEnd = 0,
|
||||
@ -41,17 +35,17 @@ ballsSketch = startSketchOn("XY")
|
||||
|> close()
|
||||
|
||||
// Revolve the ball to make a sphere and pattern around the inside wall
|
||||
balls = revolve(ballsSketch, axis = "X")
|
||||
balls = revolve(ballsSketch, axis = X)
|
||||
|> patternCircular3d(
|
||||
arcDegrees = 360,
|
||||
axis = [0, 0, 1],
|
||||
center = [0, 0, 0],
|
||||
instances = nBalls,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Create the sketch for the chain around the balls
|
||||
chainSketch = startSketchOn("XY")
|
||||
chainSketch = startSketchOn(XY)
|
||||
|> startProfileAt([
|
||||
shaftDia / 2 + wallThickness + sphereDia / 2 - (chainWidth / 2),
|
||||
0.125 * sin(toRadians(60))
|
||||
@ -66,45 +60,39 @@ chainSketch = startSketchOn("XY")
|
||||
|> close()
|
||||
|
||||
// Revolve the chain sketch
|
||||
chainHead = revolve(chainSketch, axis = "X")
|
||||
chainHead = revolve(chainSketch, axis = X)
|
||||
|> patternCircular3d(
|
||||
arcDegrees = 360,
|
||||
axis = [0, 0, 1],
|
||||
center = [0, 0, 0],
|
||||
instances = nBalls,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Create the sketch for the links in between the chains
|
||||
linkSketch = startSketchOn("XZ")
|
||||
linkSketch = startSketchOn(XZ)
|
||||
|> circle(
|
||||
center = [
|
||||
shaftDia / 2 + wallThickness + sphereDia / 2,
|
||||
0
|
||||
],
|
||||
radius = linkDiameter / 2
|
||||
radius = linkDiameter / 2,
|
||||
)
|
||||
|
||||
// Revolve the link sketch
|
||||
linkRevolve = revolve(linkSketch, axis = 'Y', angle = 360 / nBalls)
|
||||
linkRevolve = revolve(linkSketch, axis = Y, angle = 360 / nBalls)
|
||||
|> patternCircular3d(
|
||||
arcDegrees = 360,
|
||||
axis = [0, 0, 1],
|
||||
center = [0, 0, 0],
|
||||
instances = nBalls,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Create the sketch for the outside walls
|
||||
outsideWallSketch = startSketchOn(offsetPlane("XY", offset = -overallThickness / 2))
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = outsideDiameter / 2
|
||||
)
|
||||
|> hole(circle(
|
||||
center = [0, 0],
|
||||
radius = shaftDia / 2 + wallThickness + sphereDia
|
||||
), %)
|
||||
outsideWallSketch = startSketchOn(offsetPlane(XY, offset = -overallThickness / 2))
|
||||
|> circle(center = [0, 0], radius = outsideDiameter / 2)
|
||||
|> hole(circle(center = [0, 0], radius = shaftDia / 2 + wallThickness + sphereDia), %)
|
||||
|
||||
outsideWall = extrude(outsideWallSketch, length = overallThickness)
|
||||
|
||||
|
@ -130,7 +130,7 @@ fn armRestProfile(plane, offset) {
|
||||
|
||||
export fn armRest(plane, offset) {
|
||||
path = armRestPath( offsetPlane(plane, offset = offset))
|
||||
profile = armRestProfile( offsetPlane("-XZ", offset = 20), offset)
|
||||
profile = armRestProfile( offsetPlane(-XZ, offset = 20), offset)
|
||||
sweep(profile, path = path)
|
||||
return 0
|
||||
}
|
||||
|
@ -16,19 +16,19 @@ import backSlats from "bench-parts.kcl"
|
||||
import armRest from "bench-parts.kcl"
|
||||
|
||||
// Create the dividers, these hold the seat and back slats
|
||||
divider("YZ")
|
||||
divider(offsetPlane("-YZ", offset = benchLength / 2))
|
||||
divider(offsetPlane("YZ", offset = benchLength / 2))
|
||||
divider(YZ)
|
||||
divider(offsetPlane(-YZ, offset = benchLength / 2))
|
||||
divider(offsetPlane(YZ, offset = benchLength / 2))
|
||||
|
||||
// Create the connectors to join the dividers
|
||||
connector(offsetPlane("YZ", offset = -benchLength / 2), benchLength)
|
||||
connector(offsetPlane(YZ, offset = -benchLength / 2), benchLength)
|
||||
|
||||
// Create the seat slats
|
||||
seatSlats(offsetPlane("YZ", offset = -benchLength / 2 - dividerThickness / 2), benchLength + dividerThickness)
|
||||
seatSlats(offsetPlane(YZ, offset = -benchLength / 2 - (dividerThickness / 2)), benchLength + dividerThickness)
|
||||
|
||||
// Create the back slats
|
||||
backSlats(offsetPlane("YZ", offset = -benchLength / 2 - dividerThickness / 2), benchLength + dividerThickness)
|
||||
backSlats(offsetPlane(YZ, offset = -benchLength / 2 - (dividerThickness / 2)), benchLength + dividerThickness)
|
||||
|
||||
// Create the arm rests
|
||||
armRest("-YZ", benchLength / 2)
|
||||
armRest("-YZ", -benchLength / 2)
|
||||
armRest(-YZ, benchLength / 2)
|
||||
armRest(-YZ, -benchLength / 2)
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Shelf Bracket
|
||||
// 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.
|
||||
|
||||
|
||||
// Define constants
|
||||
sigmaAllow = 35000 // psi (6061-T6 aluminum)
|
||||
width = 6 // inch
|
||||
@ -12,14 +11,16 @@ wallMountL = 2 // inches
|
||||
shelfDepth = 12 // Shelf is 12 inches in depth from the wall
|
||||
moment = shelfDepth * p // assume the force is applied at the end of the shelf to be conservative (lb-in)
|
||||
|
||||
|
||||
// Calculate required thickness of bracket
|
||||
thickness = sqrt(moment * factorOfSafety * 6 / (sigmaAllow * width)) // this is the calculation of two brackets holding up the shelf (inches)
|
||||
|
||||
|
||||
filletRadius = .25
|
||||
extFilletRadius = filletRadius + thickness
|
||||
mountingHoleDiameter = 0.5
|
||||
|
||||
sketch001 = startSketchOn('XZ')
|
||||
sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> xLine(length = shelfMountL - thickness, tag = $seg01)
|
||||
|> yLine(length = thickness, tag = $seg02)
|
||||
@ -29,48 +30,18 @@ sketch001 = startSketchOn('XZ')
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg06)
|
||||
|> close()
|
||||
|> extrude(%, length = width)
|
||||
|> fillet(
|
||||
radius = extFilletRadius,
|
||||
tags = [getNextAdjacentEdge(seg03)],
|
||||
)
|
||||
|> fillet(
|
||||
radius = filletRadius,
|
||||
tags = [getNextAdjacentEdge(seg06)],
|
||||
)
|
||||
|> fillet(
|
||||
radius = filletRadius,
|
||||
tags = [seg02, getOppositeEdge(seg02)],
|
||||
)
|
||||
|> fillet(
|
||||
radius = filletRadius,
|
||||
tags = [seg05, getOppositeEdge(seg05)],
|
||||
)
|
||||
|> fillet(radius = extFilletRadius, tags = [getNextAdjacentEdge(seg03)])
|
||||
|> fillet(radius = filletRadius, tags = [getNextAdjacentEdge(seg06)])
|
||||
|> fillet(radius = filletRadius, tags = [seg02, getOppositeEdge(seg02)])
|
||||
|> fillet(radius = filletRadius, tags = [seg05, getOppositeEdge(seg05)])
|
||||
|
||||
sketch002 = startSketchOn(sketch001, seg03)
|
||||
|> circle(
|
||||
center = [-1.25, 1],
|
||||
radius = mountingHoleDiameter / 2,
|
||||
)
|
||||
|> patternLinear2d(
|
||||
instances = 2,
|
||||
distance = 2.5,
|
||||
axis = [-1, 0],
|
||||
)
|
||||
|> patternLinear2d(
|
||||
instances = 2,
|
||||
distance = 4,
|
||||
axis = [0, 1],
|
||||
)
|
||||
|> extrude(%, length = -thickness-.01)
|
||||
|> circle(center = [-1.25, 1], radius = mountingHoleDiameter / 2)
|
||||
|> patternLinear2d(instances = 2, distance = 2.5, axis = [-1, 0])
|
||||
|> patternLinear2d(instances = 2, distance = 4, axis = [0, 1])
|
||||
|> extrude(%, length = -thickness - .01)
|
||||
|
||||
sketch003 = startSketchOn(sketch001, seg04)
|
||||
|> circle(
|
||||
center = [1, -1],
|
||||
radius = mountingHoleDiameter / 2,
|
||||
)
|
||||
|> patternLinear2d(
|
||||
instances = 2,
|
||||
distance = 4,
|
||||
axis = [1, 0],
|
||||
)
|
||||
|> extrude(%, length = -thickness-0.1)
|
||||
|> circle(center = [1, -1], radius = mountingHoleDiameter / 2)
|
||||
|> patternLinear2d(instances = 2, distance = 4, axis = [1, 0])
|
||||
|> extrude(%, length = -thickness - 0.1)
|
||||
|
@ -1,16 +1,14 @@
|
||||
// Brake Caliper
|
||||
// Brake calipers are used to squeeze the brake pads against the rotor, causing larger and larger amounts of friction depending on how hard the brakes are pressed.
|
||||
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Import Constants
|
||||
import caliperTolerance, caliperPadLength, caliperThickness, caliperOuterEdgeRadius, caliperInnerEdgeRadius, rotorDiameter, rotorTotalThickness, yAxisOffset from "globals.kcl"
|
||||
|
||||
// Sketch the brake caliper profile
|
||||
brakeCaliperSketch = startSketchOn('XY')
|
||||
brakeCaliperSketch = startSketchOn(XY)
|
||||
|> startProfileAt([
|
||||
rotorDiameter / 2 + caliperTolerance,
|
||||
0
|
||||
@ -82,5 +80,5 @@ brakeCaliperSketch = startSketchOn('XY')
|
||||
|> close()
|
||||
|
||||
// Revolve the brake caliper sketch
|
||||
revolve(brakeCaliperSketch, axis = "Y", angle = -70)
|
||||
revolve(brakeCaliperSketch, axis = Y, angle = -70)
|
||||
|> appearance(color = "#c82d2d", metalness = 90, roughness = 90)
|
||||
|
@ -1,39 +1,28 @@
|
||||
// Wheel rotor
|
||||
// A component of a disc brake system. It provides a surface for brake pads to press against, generating the friction needed to slow or stop the vehicle.
|
||||
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Import Constants
|
||||
import rotorDiameter, rotorInnerDiameter, rotorSinglePlateThickness, rotorInnerDiameterThickness, lugHolePatternDia, lugSpacing, rotorTotalThickness, spacerPatternDiameter, spacerDiameter, spacerLength, spacerCount, wheelDiameter, lugCount, yAxisOffset, drillAndSlotCount from "globals.kcl"
|
||||
|
||||
rotorSketch = startSketchOn('XZ')
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = rotorDiameter / 2
|
||||
)
|
||||
rotorSketch = startSketchOn(XZ)
|
||||
|> circle(center = [0, 0], radius = rotorDiameter / 2)
|
||||
rotor = extrude(rotorSketch, length = rotorSinglePlateThickness)
|
||||
|> appearance(color = "#dbcd70", roughness = 90, metalness = 90)
|
||||
|
||||
rotorBumpSketch = startSketchOn(rotor, 'end')
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = rotorInnerDiameter / 2
|
||||
)
|
||||
|> circle(center = [0, 0], radius = rotorInnerDiameter / 2)
|
||||
rotorBump = extrude(rotorBumpSketch, length = rotorInnerDiameterThickness)
|
||||
|
||||
lugHoles = startSketchOn(rotorBump, 'end')
|
||||
|> circle(
|
||||
center = [-lugSpacing / 2, 0],
|
||||
radius = 0.315
|
||||
)
|
||||
|> circle(center = [-lugSpacing / 2, 0], radius = 0.315)
|
||||
|> patternCircular2d(
|
||||
arcDegrees = 360,
|
||||
center = [0, 0],
|
||||
instances = lugCount,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|> extrude(%, length = -(rotorInnerDiameterThickness + rotorSinglePlateThickness))
|
||||
|> appearance(color = "#dbcd70", roughness = 90, metalness = 90)
|
||||
@ -44,35 +33,26 @@ centerSpacer = startSketchOn(rotor, 'start')
|
||||
|> extrude(%, length = spacerLength)
|
||||
|
||||
secondaryRotorSketch = startSketchOn(centerSpacer, 'end')
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = rotorDiameter / 2
|
||||
)
|
||||
|> circle(center = [0, 0], radius = rotorDiameter / 2)
|
||||
secondRotor = extrude(secondaryRotorSketch, length = rotorSinglePlateThickness)
|
||||
|
||||
lugHoles2 = startSketchOn(secondRotor, 'end')
|
||||
|> circle(
|
||||
center = [-lugSpacing / 2, 0],
|
||||
radius = 0.315
|
||||
)
|
||||
|> circle(center = [-lugSpacing / 2, 0], radius = 0.315)
|
||||
|> patternCircular2d(
|
||||
arcDegrees = 360,
|
||||
center = [0, 0],
|
||||
instances = lugCount,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|> extrude(length = -rotorSinglePlateThickness)
|
||||
|
||||
spacerSketch = startSketchOn(rotor, 'start')
|
||||
|> circle(
|
||||
center = [spacerPatternDiameter / 2, 0],
|
||||
radius = spacerDiameter
|
||||
)
|
||||
|> circle(center = [spacerPatternDiameter / 2, 0], radius = spacerDiameter)
|
||||
|> patternCircular2d(
|
||||
arcDegrees = 360,
|
||||
center = [0, 0],
|
||||
instances = spacerCount,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
spacers = extrude(spacerSketch, length = spacerLength)
|
||||
|
||||
@ -87,7 +67,7 @@ rotorSlottedSketch = startSketchOn(rotor, 'START')
|
||||
center = [0, 0],
|
||||
instances = drillAndSlotCount,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
rotorSlotted = extrude(rotorSlottedSketch, length = -rotorSinglePlateThickness / 2)
|
||||
|
||||
@ -102,7 +82,7 @@ secondRotorSlottedSketch = startSketchOn(secondRotor, 'END')
|
||||
center = [0, 0],
|
||||
instances = drillAndSlotCount,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
extrude(secondRotorSlottedSketch, length = -rotorSinglePlateThickness / 2)
|
||||
|
@ -1,21 +1,22 @@
|
||||
// Tire
|
||||
// A tire is a critical component of a vehicle that provides the necessary traction and grip between the car and the road. It supports the vehicle's weight and absorbs shocks from road irregularities.
|
||||
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Import Constants
|
||||
import tireInnerDiameter, tireOuterDiameter, tireDepth, bendRadius, tireTreadWidth, tireTreadDepth, tireTreadOffset from "globals.kcl"
|
||||
|
||||
// Create the sketch of the tire
|
||||
tireSketch = startSketchOn("XY")
|
||||
tireSketch = startSketchOn(XY)
|
||||
|> startProfileAt([tireInnerDiameter / 2, tireDepth / 2], %)
|
||||
|> line(endAbsolute = [
|
||||
tireOuterDiameter / 2 - bendRadius,
|
||||
tireDepth / 2
|
||||
], tag = $edge1)
|
||||
|> line(
|
||||
endAbsolute = [
|
||||
tireOuterDiameter / 2 - bendRadius,
|
||||
tireDepth / 2
|
||||
],
|
||||
tag = $edge1,
|
||||
)
|
||||
|> tangentialArc({ offset = -90, radius = bendRadius }, %)
|
||||
|> line(endAbsolute = [
|
||||
tireOuterDiameter / 2,
|
||||
@ -40,5 +41,5 @@ tireSketch = startSketchOn("XY")
|
||||
|> close()
|
||||
|
||||
// Revolve the sketch to create the tire
|
||||
revolve(tireSketch, axis = "Y")
|
||||
revolve(tireSketch, axis = Y)
|
||||
|> appearance(color = "#0f0f0f", roughness = 80)
|
||||
|
@ -1,69 +1,49 @@
|
||||
// Car Wheel
|
||||
// A sports car wheel with a circular lug pattern and spokes.
|
||||
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Import Constants
|
||||
import lugCount, lugSpacing, offset, backSpacing, wheelWidth, wheelDiameter, spokeCount, spokeGap, spokeAngle, spokeThickness from "globals.kcl"
|
||||
|
||||
// Create the wheel center
|
||||
lugBase = startSketchOn('XZ')
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = (lugSpacing + 1.5) / 2
|
||||
)
|
||||
|> hole(circle(
|
||||
center = [0, 0],
|
||||
radius = (lugSpacing - 1.5) / 2
|
||||
), %)
|
||||
lugBase = startSketchOn(XZ)
|
||||
|> circle(center = [0, 0], radius = (lugSpacing + 1.5) / 2)
|
||||
|> hole(circle(center = [0, 0], radius = (lugSpacing - 1.5) / 2), %)
|
||||
|> extrude(length = wheelWidth / 20)
|
||||
|
||||
// Extend the wheel center and bore holes to accomidate the lug heads
|
||||
lugExtrusion = startSketchOn(lugBase, 'END')
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = (lugSpacing + 1.5) / 2
|
||||
)
|
||||
|> hole(circle(
|
||||
center = [0, 0],
|
||||
radius = (lugSpacing - 1.5) / 2
|
||||
), %)
|
||||
|> circle(center = [0, 0], radius = (lugSpacing + 1.5) / 2)
|
||||
|> hole(circle(center = [0, 0], radius = (lugSpacing - 1.5) / 2), %)
|
||||
|> extrude(length = wheelWidth / 10)
|
||||
|
||||
// Create the circular pattern for the lugs
|
||||
lugClearance = startSketchOn(lugExtrusion, 'END')
|
||||
|> circle(
|
||||
center = [lugSpacing / 2, 0],
|
||||
radius = 1.2 / 2
|
||||
)
|
||||
|> circle(center = [lugSpacing / 2, 0], radius = 1.2 / 2)
|
||||
|> patternCircular2d(
|
||||
arcDegrees = 360,
|
||||
center = [0, 0],
|
||||
instances = lugCount,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|> extrude(length = -wheelWidth / 10)
|
||||
|
||||
// Create the circular pattern for the lug holes
|
||||
lugHoles = startSketchOn(lugBase, 'END')
|
||||
|> circle(
|
||||
center = [lugSpacing / 2, 0],
|
||||
radius = 16 * mm() / 2
|
||||
)
|
||||
|> circle(center = [lugSpacing / 2, 0], radius = 16 * mm() / 2)
|
||||
|> patternCircular2d(
|
||||
arcDegrees = 360,
|
||||
center = [0, 0],
|
||||
instances = lugCount,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|> extrude(length = -wheelWidth / 20)
|
||||
|> appearance(color = "#ffffff", metalness = 0, roughness = 0)
|
||||
|
||||
// Add detail to the wheel center by revolving curved edge profiles
|
||||
wheelCenterInner = startSketchOn('XY')
|
||||
wheelCenterInner = startSketchOn(XY)
|
||||
|> startProfileAt([(lugSpacing - 1.5) / 2, 0], %)
|
||||
|> yLine(length = -wheelWidth / 10 - (wheelWidth / 20))
|
||||
|> bezierCurve({
|
||||
@ -74,10 +54,10 @@ wheelCenterInner = startSketchOn('XY')
|
||||
|> yLine(endAbsolute = 0)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> revolve(axis = 'y')
|
||||
|> revolve(axis = Y)
|
||||
|> appearance(color = "#ffffff", metalness = 0, roughness = 0)
|
||||
|
||||
wheelCenterOuter = startSketchOn('XY')
|
||||
wheelCenterOuter = startSketchOn(XY)
|
||||
|> startProfileAt([(lugSpacing + 1.5) / 2, 0], %)
|
||||
|> yLine(length = -wheelWidth / 10 - (wheelWidth / 20))
|
||||
|> bezierCurve({
|
||||
@ -88,7 +68,7 @@ wheelCenterOuter = startSketchOn('XY')
|
||||
|> yLine(endAbsolute = -wheelWidth / 20)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> revolve(axis = 'y')
|
||||
|> revolve(axis = Y)
|
||||
|> appearance(color = "#ffffff", metalness = 0, roughness = 0)
|
||||
|
||||
// Write a function that defines the spoke geometry, patterns and extrudes it
|
||||
@ -145,7 +125,7 @@ fn spoke(spokeGap, spokeAngle, spokeThickness) {
|
||||
center = [0, -2000, 0],
|
||||
instances = spokeCount,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|> appearance(color = "#ffffff", metalness = 0, roughness = 0)
|
||||
return spokePattern
|
||||
@ -155,7 +135,7 @@ spoke(spokeGap, spokeAngle, spokeThickness)
|
||||
spoke(-spokeGap, -spokeAngle, -spokeThickness)
|
||||
|
||||
// Define and revolve wheel exterior
|
||||
startSketchOn('XY')
|
||||
startSketchOn(XY)
|
||||
|> startProfileAt([
|
||||
wheelDiameter / 2,
|
||||
-wheelWidth + backSpacing + offset
|
||||
@ -193,5 +173,5 @@ startSketchOn('XY')
|
||||
|> xLine(length = wheelWidth * 0.03)
|
||||
|> yLine(length = wheelWidth * 0.05)
|
||||
|> close()
|
||||
|> revolve(axis = 'y')
|
||||
|> revolve(axis = Y)
|
||||
|> appearance(color = "#ffffff", metalness = 0, roughness = 0)
|
||||
|
@ -20,7 +20,7 @@ export lugDiameter = 24 * mm()
|
||||
export lugHeadLength = lugDiameter * .5
|
||||
export lugThreadDiameter = lugDiameter / 2 * .85
|
||||
export lugLength = 30 * mm()
|
||||
export lugThreadDepth = lugLength - 12.7 * mm()
|
||||
export lugThreadDepth = lugLength - (12.7 * mm())
|
||||
|
||||
// Car Rotor
|
||||
export rotorDiameter = 12
|
||||
@ -50,4 +50,4 @@ export caliperTolerance = 0.050
|
||||
export caliperPadLength = 1.6
|
||||
export caliperThickness = 0.39
|
||||
export caliperOuterEdgeRadius = 0.39
|
||||
export caliperInnerEdgeRadius = 0.12
|
||||
export caliperInnerEdgeRadius = 0.12
|
||||
|
@ -1,11 +1,9 @@
|
||||
// Lug Nut
|
||||
// lug Nuts are essential components used to create secure connections, whether for electrical purposes, like terminating wires or grounding, or for mechanical purposes, such as providing mounting points or reinforcing structural joints.
|
||||
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Import Constants
|
||||
import lugDiameter, lugHeadLength, lugThreadDiameter, lugLength, lugThreadDepth, lugSpacing from "globals.kcl"
|
||||
|
||||
@ -34,7 +32,7 @@ fn lug(plane, length, diameter) {
|
||||
|> xLine(endAbsolute = lugThreadDiameter)
|
||||
|> yLine(endAbsolute = 0)
|
||||
|> close()
|
||||
|> revolve(axis = "Y")
|
||||
|> revolve(axis = Y)
|
||||
|> appearance(color = "#dbcd70", roughness = 90, metalness = 90)
|
||||
return lugSketch
|
||||
}
|
||||
|
@ -4,24 +4,24 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
import 'car-wheel.kcl' as carWheel
|
||||
import 'car-rotor.kcl' as carRotor
|
||||
import "car-wheel.kcl" as carWheel
|
||||
import "car-rotor.kcl" as carRotor
|
||||
import "brake-caliper.kcl" as brakeCaliper
|
||||
import 'lug-nut.kcl' as lugNut
|
||||
import 'car-tire.kcl' as carTire
|
||||
import lugCount from 'globals.kcl'
|
||||
import "lug-nut.kcl" as lugNut
|
||||
import "car-tire.kcl" as carTire
|
||||
import lugCount from "globals.kcl"
|
||||
|
||||
carRotor
|
||||
|> translate(translate = [0, 0.5, 0])
|
||||
carWheel
|
||||
lugNut
|
||||
|> patternCircular3d(
|
||||
arcDegrees = 360,
|
||||
axis = [0, 1, 0],
|
||||
center = [0, 0, 0],
|
||||
instances = lugCount,
|
||||
rotateDuplicates = false
|
||||
)
|
||||
arcDegrees = 360,
|
||||
axis = [0, 1, 0],
|
||||
center = [0, 0, 0],
|
||||
instances = lugCount,
|
||||
rotateDuplicates = false,
|
||||
)
|
||||
brakeCaliper
|
||||
|> translate(translate = [0, 0.5, 0])
|
||||
carTire
|
||||
|
@ -6,42 +6,42 @@
|
||||
|
||||
// Globals referenced in drawRectangle
|
||||
size = 100
|
||||
halfSize = size/2
|
||||
halfSize = size / 2
|
||||
extrudeLength = 1.0
|
||||
metalConstant = 50
|
||||
roughnessConstant = 50
|
||||
|
||||
// Create planes for 6 sides of a cube
|
||||
bluePlane = offsetPlane('XY', offset = halfSize)
|
||||
yellowPlane = offsetPlane('XY', offset = -halfSize)
|
||||
greenPlane = offsetPlane('XZ', offset = -halfSize)
|
||||
purplePlane = offsetPlane('-XZ', offset = -halfSize)
|
||||
redPlane = offsetPlane('YZ', offset = halfSize - extrudeLength)
|
||||
tealPlane = offsetPlane('YZ', offset = -halfSize)
|
||||
bluePlane = offsetPlane(XY, offset = halfSize)
|
||||
yellowPlane = offsetPlane(XY, offset = -halfSize)
|
||||
greenPlane = offsetPlane(XZ, offset = -halfSize)
|
||||
purplePlane = offsetPlane(-XZ, offset = -halfSize)
|
||||
redPlane = offsetPlane(YZ, offset = halfSize - extrudeLength)
|
||||
tealPlane = offsetPlane(YZ, offset = -halfSize)
|
||||
|
||||
// Sketch a rectangle centered at the origin of the profile
|
||||
fn sketchRectangle (profile, color) {
|
||||
fn sketchRectangle(profile, color) {
|
||||
return profile
|
||||
|> startProfileAt([-halfSize, halfSize], %)
|
||||
|> angledLine([0, size], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001) - 90,
|
||||
size
|
||||
], %, $rectangleSegmentB001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001),
|
||||
-segLen(rectangleSegmentA001)
|
||||
], %, $rectangleSegmentC001)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> extrude(%, length = extrudeLength)
|
||||
|> appearance(color = color, metalness = metalConstant, roughness = roughnessConstant)
|
||||
|> startProfileAt([-halfSize, halfSize], %)
|
||||
|> angledLine([0, size], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001) - 90,
|
||||
size
|
||||
], %, $rectangleSegmentB001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001),
|
||||
-segLen(rectangleSegmentA001)
|
||||
], %, $rectangleSegmentC001)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> extrude(%, length = extrudeLength)
|
||||
|> appearance(color = color, metalness = metalConstant, roughness = roughnessConstant)
|
||||
}
|
||||
|
||||
// Sketch each side of the cube
|
||||
sketchRectangle(bluePlane,'#0000FF')
|
||||
sketchRectangle(yellowPlane,'#FFFF00')
|
||||
sketchRectangle(greenPlane,'#00FF00')
|
||||
sketchRectangle(redPlane,'#FF0000')
|
||||
sketchRectangle(tealPlane,'#00FFFF')
|
||||
sketchRectangle(purplePlane,'#FF00FF')
|
||||
sketchRectangle(bluePlane, '#0000FF')
|
||||
sketchRectangle(yellowPlane, '#FFFF00')
|
||||
sketchRectangle(greenPlane, '#00FF00')
|
||||
sketchRectangle(redPlane, '#FF0000')
|
||||
sketchRectangle(tealPlane, '#00FFFF')
|
||||
sketchRectangle(purplePlane, '#FF00FF')
|
||||
|
@ -4,12 +4,11 @@
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
fn cycloidalGear(gearPitch, gearHeight, holeDiameter, helixAngle) {
|
||||
// Create a function to draw the gear profile as a sketch. Rotate each profile about the gear's axis by an helix angle proportional to the total gear height
|
||||
fn gearSketch(gHeight) {
|
||||
helixAngleP = helixAngle * gHeight / gearHeight
|
||||
gearProfile = startSketchOn(offsetPlane("XY", offset = gHeight))
|
||||
gearProfile = startSketchOn(offsetPlane(XY, offset = gHeight))
|
||||
|> startProfileAt([
|
||||
gearPitch * 1.55 * cos(toRadians(helixAngleP)) + gearPitch * sin(toRadians(-helixAngleP)),
|
||||
gearPitch * 1.55 * sin(toRadians(helixAngleP)) + gearPitch * cos(toRadians(-helixAngleP))
|
||||
@ -31,10 +30,7 @@ fn cycloidalGear(gearPitch, gearHeight, holeDiameter, helixAngle) {
|
||||
|> tangentialArc({ radius = gearPitch, offset = -180 }, %)
|
||||
|> tangentialArcTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
|> hole(circle(
|
||||
center = [0, 0],
|
||||
radius = holeDiameter / 2
|
||||
), %)
|
||||
|> hole(circle(center = [0, 0], radius = holeDiameter / 2), %)
|
||||
return gearProfile
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ plane = {
|
||||
}
|
||||
|
||||
// Create a regular pentagon inscribed in a circle of radius pentR
|
||||
bottomFace = startSketchOn('XY')
|
||||
bottomFace = startSketchOn(XY)
|
||||
|> polygon({
|
||||
radius = pentR,
|
||||
numSides = 5,
|
||||
@ -66,7 +66,7 @@ bottomBowl = patternCircular3d(
|
||||
axis = [0, 0, 1],
|
||||
center = [0, 0, 0],
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// pattern the bottom to create the top face
|
||||
@ -76,7 +76,7 @@ patternCircular3d(
|
||||
axis = [0, 1, 0],
|
||||
center = [0, 0, inscR],
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// pattern the bottom angled faces to create the top
|
||||
@ -86,5 +86,5 @@ patternCircular3d(
|
||||
axis = [0, 1, 0],
|
||||
center = [0, 0, inscR],
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
200
public/kcl-samples/dual-basin-utility-sink/main.kcl
Normal file
@ -0,0 +1,200 @@
|
||||
// Dual-Basin Utility Sink
|
||||
// A stainless steel sink unit with dual rectangular basins and six under-counter storage compartments.
|
||||
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// globals
|
||||
tableHeight = 850
|
||||
tableWidth = 3400
|
||||
tableDepth = 400
|
||||
|
||||
profileThickness = 13
|
||||
metalThickness = 2
|
||||
|
||||
blockCount = 3
|
||||
blockWidth = (tableWidth-profileThickness) / 3
|
||||
blockHeight = tableHeight - metalThickness - 0.5
|
||||
blockDepth = tableDepth - profileThickness
|
||||
|
||||
blockSubdivisionCount = 2
|
||||
blockSubdivisionWidth = blockWidth / blockSubdivisionCount
|
||||
|
||||
// Geometry
|
||||
floorPlane = startSketchOn(XY)
|
||||
|
||||
// legs
|
||||
legHeight = blockHeight - profileThickness
|
||||
legCount = blockCount + 1
|
||||
|
||||
legBody = startProfileAt([0, 0], floorPlane)
|
||||
|> yLine(length=profileThickness)
|
||||
|> xLine(length=profileThickness)
|
||||
|> yLine(length=-profileThickness)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(axis = [1, 0], instances = legCount, distance = blockWidth)
|
||||
|> patternLinear2d(axis = [0, 1], instances = 2, distance = blockDepth)
|
||||
|> extrude(length = legHeight)
|
||||
|
||||
// lower belt
|
||||
lowerBeltHeightAboveTheFloor = 150
|
||||
lowerBeltLengthX = blockWidth - profileThickness
|
||||
|
||||
lowerBeltPlane = startSketchOn(offsetPlane(XY, offset = lowerBeltHeightAboveTheFloor))
|
||||
lowerBeltBodyX = startProfileAt([profileThickness, 0], lowerBeltPlane)
|
||||
|> yLine(length=profileThickness)
|
||||
|> xLine(length=lowerBeltLengthX)
|
||||
|> yLine(length=-profileThickness)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(axis = [1, 0], instances = blockCount, distance = blockWidth)
|
||||
|> patternLinear2d(axis = [0, 1], instances = 2, distance = blockDepth)
|
||||
|> extrude(length = profileThickness)
|
||||
|
||||
lowerBeltLengthY = blockDepth - profileThickness
|
||||
lowerBeltBodyY = startProfileAt([0, profileThickness], lowerBeltPlane)
|
||||
|> yLine(length=lowerBeltLengthY)
|
||||
|> xLine(length=profileThickness)
|
||||
|> yLine(length=-lowerBeltLengthY)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(axis = [1, 0], instances = 2, distance = tableWidth-profileThickness)
|
||||
|> extrude(length = profileThickness)
|
||||
|
||||
// pillars
|
||||
pillarHeightAboveTheFloor = lowerBeltHeightAboveTheFloor + profileThickness
|
||||
pillarPlane = startSketchOn(offsetPlane(XY, offset = pillarHeightAboveTheFloor))
|
||||
pillarTotalHeight = blockHeight - profileThickness - pillarHeightAboveTheFloor
|
||||
|
||||
pillarBody = startProfileAt([blockSubdivisionWidth, 0], pillarPlane)
|
||||
|> yLine(length=profileThickness)
|
||||
|> xLine(length=profileThickness)
|
||||
|> yLine(length=-profileThickness)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(axis = [1, 0], instances = blockCount, distance = blockWidth)
|
||||
|> patternLinear2d(axis = [0, 1], instances = 2, distance = blockDepth)
|
||||
|> extrude(length = pillarTotalHeight)
|
||||
|
||||
// upper belt
|
||||
upperBeltPlane = startSketchOn(offsetPlane(XY, offset = blockHeight))
|
||||
|
||||
upperBeltBodyX = startProfileAt([0, 0], upperBeltPlane)
|
||||
|> yLine(length=profileThickness)
|
||||
|> xLine(length=tableWidth)
|
||||
|> yLine(length=-profileThickness)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(axis = [0, 1], instances = 2, distance = blockDepth)
|
||||
|> extrude(length = -profileThickness)
|
||||
|
||||
upperBeltLengthY = blockDepth - profileThickness
|
||||
upperBeltBodyY = startProfileAt([0, profileThickness], upperBeltPlane)
|
||||
|> yLine(length=upperBeltLengthY)
|
||||
|> xLine(length=profileThickness)
|
||||
|> yLine(length=-upperBeltLengthY)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(axis = [1, 0], instances = 2, distance = tableWidth-profileThickness)
|
||||
|> extrude(length = -profileThickness)
|
||||
|
||||
// sink
|
||||
tableTopPlane = startSketchOn(offsetPlane(XY, offset = tableHeight))
|
||||
tableTopBody = startProfileAt([0, 0], tableTopPlane)
|
||||
|> yLine(length=tableDepth)
|
||||
|> xLine(length=tableWidth)
|
||||
|> yLine(length=-tableDepth)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> extrude(length = -metalThickness)
|
||||
|
||||
sinkCount = 2
|
||||
sinkWidth = 1000
|
||||
sinkLength = 250
|
||||
sinkDepth = 200
|
||||
sinkOffsetFront = 40
|
||||
sinkOffsetLeft = 350
|
||||
sinkSpacing = tableWidth - sinkWidth - sinkOffsetLeft*2
|
||||
|
||||
sinkPlaneOutside = startSketchOn(tableTopBody, 'START')
|
||||
sinkBodyOutside = startProfileAt([-sinkOffsetLeft, sinkOffsetFront], sinkPlaneOutside)
|
||||
|> yLine(length=sinkLength)
|
||||
|> xLine(length=-sinkWidth)
|
||||
|> yLine(length=-sinkLength)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(axis = [-1, 0], instances = sinkCount, distance = sinkSpacing)
|
||||
|> extrude(length = sinkDepth)
|
||||
|
||||
sinkPlaneInside = startSketchOn(tableTopBody, 'END')
|
||||
sinkBodyInside = startProfileAt([sinkOffsetLeft+metalThickness, sinkOffsetFront+metalThickness], sinkPlaneInside)
|
||||
|> yLine(length=sinkLength-metalThickness*2)
|
||||
|> xLine(length=sinkWidth-metalThickness*2)
|
||||
|> yLine(length=-sinkLength+metalThickness*2)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(axis = [1, 0], instances = sinkCount, distance = sinkSpacing)
|
||||
|> extrude(length = -sinkDepth)
|
||||
|
||||
// door panels
|
||||
doorGap = 2
|
||||
doorWidth = blockSubdivisionWidth - profileThickness - doorGap*2
|
||||
doorStart = profileThickness+doorGap
|
||||
doorHeightAboveTheFloor = pillarHeightAboveTheFloor + doorGap
|
||||
doorHeight = blockHeight - doorHeightAboveTheFloor - profileThickness - doorGap
|
||||
doorCount = blockCount * blockSubdivisionCount
|
||||
|
||||
doorPlane = startSketchOn(offsetPlane(XY, offset = doorHeightAboveTheFloor))
|
||||
doorBody = startProfileAt([doorStart, 0], doorPlane)
|
||||
|> yLine(length=profileThickness)
|
||||
|> xLine(length=doorWidth)
|
||||
|> yLine(length=-profileThickness)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(axis = [1, 0], instances = doorCount, distance = blockSubdivisionWidth)
|
||||
|> extrude(length = doorHeight)
|
||||
|
||||
// side panels
|
||||
panelWidth = blockDepth - profileThickness - doorGap*2
|
||||
panelCount = doorCount + 1
|
||||
panelSpacing = tableWidth - profileThickness
|
||||
panelBody = startProfileAt([0, doorStart], doorPlane)
|
||||
|> yLine(length=panelWidth)
|
||||
|> xLine(length=profileThickness)
|
||||
|> yLine(length=-panelWidth)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> patternLinear2d(axis = [1, 0], instances = 2, distance = panelSpacing)
|
||||
|> extrude(length = doorHeight)
|
||||
|
||||
// handle
|
||||
handleDepth = 40
|
||||
handleWidth = 120
|
||||
handleFillet = 20
|
||||
handleHeightAboveTheFloor = 780
|
||||
handleOffset = doorStart + doorWidth / 2 - (handleWidth / 2)
|
||||
handleLengthSegmentA = handleDepth - handleFillet
|
||||
handleLengthSegmentB = handleWidth - (handleFillet * 2)
|
||||
|
||||
handlePlane = startSketchOn(offsetPlane(XY, offset = handleHeightAboveTheFloor))
|
||||
|
||||
handleProfilePath = startProfileAt([0 + handleOffset, 0], handlePlane)
|
||||
|> yLine(length=-handleLengthSegmentA)
|
||||
|> tangentialArcTo([
|
||||
handleFillet + handleOffset,
|
||||
-handleDepth
|
||||
], %)
|
||||
|> xLine(length=handleLengthSegmentB)
|
||||
|> tangentialArcTo([
|
||||
handleOffset + handleWidth,
|
||||
-handleLengthSegmentA
|
||||
], %)
|
||||
|> yLine(length=handleLengthSegmentA)
|
||||
handleSectionPlane = startSketchOn(XZ)
|
||||
handleProfileSection = circle(
|
||||
handleSectionPlane,
|
||||
center = [handleOffset, handleHeightAboveTheFloor],
|
||||
radius = 2)
|
||||
|
||||
handleBody = sweep(handleProfileSection, path = handleProfilePath)
|
||||
|> patternLinear3d(axis = [1, 0, 0], instances = doorCount, distance = blockSubdivisionWidth)
|
@ -11,7 +11,7 @@ wallThickness = 3
|
||||
holeDia = 4
|
||||
|
||||
// Model a box with base enclosure dimensions
|
||||
sketch001 = startSketchOn('XY')
|
||||
sketch001 = startSketchOn(XY)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> angledLine([0, width], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
@ -32,14 +32,11 @@ extrude001 = extrude(sketch001, length = height)
|
||||
getNextAdjacentEdge(rectangleSegmentB001),
|
||||
getNextAdjacentEdge(rectangleSegmentC001),
|
||||
getNextAdjacentEdge(rectangleSegmentD001)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
// Apply a shell to the enclosure base to create the internal storage
|
||||
|> shell(
|
||||
faces = ["end"],
|
||||
thickness = wallThickness
|
||||
)
|
||||
|> shell(faces = ["end"], thickness = wallThickness)
|
||||
|
||||
// Define a function to create the internal structure to secure a fastener at each corner
|
||||
fn function001(originStart) {
|
||||
@ -55,14 +52,8 @@ fn function001(originStart) {
|
||||
|
||||
// Create a pillar with a fasterner hole at the center
|
||||
sketch002 = startSketchOn(plane001)
|
||||
|> circle(
|
||||
center = [originStart[0], originStart[1]],
|
||||
radius = holeDia + wallThickness
|
||||
)
|
||||
|> hole(circle(
|
||||
center = [originStart[0], originStart[1]],
|
||||
radius = holeDia
|
||||
), %)
|
||||
|> circle(center = [originStart[0], originStart[1]], radius = holeDia + wallThickness)
|
||||
|> hole(circle(center = [originStart[0], originStart[1]], radius = holeDia), %)
|
||||
extrude002 = extrude(sketch002, length = height - wallThickness)
|
||||
|
||||
return extrude002
|
||||
@ -87,7 +78,7 @@ function001([
|
||||
])
|
||||
|
||||
// Define lid position and outer surface
|
||||
sketch003 = startSketchOn('XY')
|
||||
sketch003 = startSketchOn(XY)
|
||||
|> startProfileAt([width * 1.2, 0], %)
|
||||
|> angledLine([0, width], %, $rectangleSegmentA002)
|
||||
|> angledLine([
|
||||
@ -105,28 +96,28 @@ sketch003 = startSketchOn('XY')
|
||||
width * 1.2 + wallThickness * 3 + holeDia,
|
||||
wallThickness * 3 + holeDia
|
||||
],
|
||||
radius = holeDia
|
||||
radius = holeDia,
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [
|
||||
width * 1.2 + wallThickness * 3 + holeDia,
|
||||
length - (wallThickness * 3 + holeDia)
|
||||
],
|
||||
radius = holeDia
|
||||
radius = holeDia,
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [
|
||||
width * 2.2 - (wallThickness * 3 + holeDia),
|
||||
wallThickness * 3 + holeDia
|
||||
],
|
||||
radius = holeDia
|
||||
radius = holeDia,
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [
|
||||
width * 2.2 - (wallThickness * 3 + holeDia),
|
||||
length - (wallThickness * 3 + holeDia)
|
||||
],
|
||||
radius = holeDia
|
||||
radius = holeDia,
|
||||
), %)
|
||||
extrude003 = extrude(sketch003, length = wallThickness)
|
||||
|> fillet(
|
||||
@ -136,7 +127,7 @@ extrude003 = extrude(sketch003, length = wallThickness)
|
||||
getNextAdjacentEdge(rectangleSegmentB002),
|
||||
getNextAdjacentEdge(rectangleSegmentC002),
|
||||
getNextAdjacentEdge(rectangleSegmentD002)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
// Define lid inner and sealing surfaces
|
||||
@ -161,28 +152,28 @@ sketch004 = startSketchOn(extrude003, 'END')
|
||||
width * 1.2 + wallThickness * 3 + holeDia,
|
||||
wallThickness * 3 + holeDia
|
||||
],
|
||||
radius = holeDia + wallThickness
|
||||
radius = holeDia + wallThickness,
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [
|
||||
width * 1.2 + wallThickness * 3 + holeDia,
|
||||
length - (wallThickness * 3 + holeDia)
|
||||
],
|
||||
radius = holeDia + wallThickness
|
||||
radius = holeDia + wallThickness,
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [
|
||||
width * 2.2 - (wallThickness * 3 + holeDia),
|
||||
wallThickness * 3 + holeDia
|
||||
],
|
||||
radius = holeDia + wallThickness
|
||||
radius = holeDia + wallThickness,
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [
|
||||
width * 2.2 - (wallThickness * 3 + holeDia),
|
||||
length - (wallThickness * 3 + holeDia)
|
||||
],
|
||||
radius = holeDia + wallThickness
|
||||
radius = holeDia + wallThickness,
|
||||
), %)
|
||||
extrude004 = extrude(sketch004, length = wallThickness)
|
||||
|> fillet(
|
||||
@ -192,5 +183,5 @@ extrude004 = extrude(sketch004, length = wallThickness)
|
||||
getNextAdjacentEdge(rectangleSegmentB003),
|
||||
getNextAdjacentEdge(rectangleSegmentC003),
|
||||
getNextAdjacentEdge(rectangleSegmentD003)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
@ -45,15 +45,9 @@ fn primaryTube(n, angle001, length001, length002, length003) {
|
||||
}, %)
|
||||
|
||||
// Create the cross section of each tube and sweep them
|
||||
sweepProfile = startSketchOn('XY')
|
||||
|> circle(
|
||||
center = [pos001, 0],
|
||||
radius = primaryTubeDiameter / 2
|
||||
)
|
||||
|> hole(circle(
|
||||
center = [pos001, 0],
|
||||
radius = primaryTubeDiameter / 2 - wallThickness
|
||||
), %)
|
||||
sweepProfile = startSketchOn(XY)
|
||||
|> circle(center = [pos001, 0], radius = primaryTubeDiameter / 2)
|
||||
|> hole(circle(center = [pos001, 0], radius = primaryTubeDiameter / 2 - wallThickness), %)
|
||||
|> sweep(path = sweepPath)
|
||||
|
||||
return { }
|
||||
@ -66,7 +60,7 @@ primaryTube(2, 24.3, 5, 5, 3)
|
||||
primaryTube(3, 25.2, 5, 5, 3)
|
||||
|
||||
// Create the mounting flange for the header
|
||||
flangeSketch = startSketchOn('XY')
|
||||
flangeSketch = startSketchOn(XY)
|
||||
|> startProfileAt([3 + 1.3, -1.25], %)
|
||||
|> xLine(length = -2.6, tag = $seg01)
|
||||
|> tangentialArc({ radius = .3, offset = -40 }, %)
|
||||
@ -87,22 +81,10 @@ flangeSketch = startSketchOn('XY')
|
||||
|> close()
|
||||
|
||||
// Create openings in the flange to accommodate each tube
|
||||
|> hole(circle(
|
||||
center = [0, 0],
|
||||
radius = primaryTubeDiameter / 2 - wallThickness
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [2, 0],
|
||||
radius = primaryTubeDiameter / 2 - wallThickness
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [4, 0],
|
||||
radius = primaryTubeDiameter / 2 - wallThickness
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [6, 0],
|
||||
radius = primaryTubeDiameter / 2 - wallThickness
|
||||
), %)
|
||||
|> hole(circle(center = [0, 0], radius = primaryTubeDiameter / 2 - wallThickness), %)
|
||||
|> hole(circle(center = [2, 0], radius = primaryTubeDiameter / 2 - wallThickness), %)
|
||||
|> hole(circle(center = [4, 0], radius = primaryTubeDiameter / 2 - wallThickness), %)
|
||||
|> hole(circle(center = [6, 0], radius = primaryTubeDiameter / 2 - wallThickness), %)
|
||||
|
||||
// Add mounting holes to the flange
|
||||
|> hole(circle(
|
||||
@ -110,28 +92,28 @@ flangeSketch = startSketchOn('XY')
|
||||
-primaryTubeDiameter * .6,
|
||||
-primaryTubeDiameter * .6
|
||||
],
|
||||
radius = 0.25 / 2
|
||||
radius = 0.25 / 2,
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [
|
||||
primaryTubeDiameter * .6,
|
||||
primaryTubeDiameter * .6
|
||||
],
|
||||
radius = 0.25 / 2
|
||||
radius = 0.25 / 2,
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [
|
||||
3 * 2 - (primaryTubeDiameter * .6),
|
||||
primaryTubeDiameter * .6
|
||||
],
|
||||
radius = 0.25 / 2
|
||||
radius = 0.25 / 2,
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [
|
||||
3 * 2 + primaryTubeDiameter * .6,
|
||||
-primaryTubeDiameter * .6
|
||||
],
|
||||
radius = 0.25 / 2
|
||||
radius = 0.25 / 2,
|
||||
), %)
|
||||
|
||||
// Extrude the flange and fillet the edges
|
||||
@ -141,12 +123,12 @@ flangeSketch = startSketchOn('XY')
|
||||
tags = [
|
||||
getNextAdjacentEdge(seg04),
|
||||
getNextAdjacentEdge(seg07)
|
||||
]
|
||||
],
|
||||
)
|
||||
|> fillet(
|
||||
radius = .25,
|
||||
tags = [
|
||||
getNextAdjacentEdge(seg03),
|
||||
getNextAdjacentEdge(seg08)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
@ -21,44 +21,32 @@ nHoles = 4
|
||||
assertGreaterThan(nHoles, 1, "nHoles must be greater than 1")
|
||||
|
||||
// Create the circular pattern for the mounting holes
|
||||
circles = startSketchOn('XY')
|
||||
|> circle(
|
||||
center = [mountingHolePlacementDiameter / 2, 0],
|
||||
radius = mountingHoleDia / 2
|
||||
)
|
||||
circles = startSketchOn(XY)
|
||||
|> circle(center = [mountingHolePlacementDiameter / 2, 0], radius = mountingHoleDia / 2)
|
||||
|> patternCircular2d(
|
||||
arcDegrees = 360,
|
||||
center = [0, 0],
|
||||
instances = nHoles,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Create the base of the flange and add the mounting holes
|
||||
flangeBase = startSketchOn('XY')
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = baseDia / 2
|
||||
)
|
||||
flangeBase = startSketchOn(XY)
|
||||
|> circle(center = [0, 0], radius = baseDia / 2)
|
||||
|> hole(circles, %)
|
||||
|> extrude(length = baseThickness)
|
||||
|
||||
// Create the extrusion on the top of the flange base
|
||||
topExtrusion = startSketchOn(flangeBase, 'end')
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = topTotalDiameter / 2
|
||||
)
|
||||
|> circle(center = [0, 0], radius = topTotalDiameter / 2)
|
||||
|> extrude(length = topTotalThickness)
|
||||
|
||||
// Create the extrusion on the bottom of the flange base
|
||||
bottomExtrusion = startSketchOn(flangeBase, 'start')
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = bottomTotalDiameter / 2
|
||||
)
|
||||
|> circle(center = [0, 0], radius = bottomTotalDiameter / 2)
|
||||
|> extrude(length = bottomThickness)
|
||||
|
||||
// Cut a hole through the entire body
|
||||
pipeHole = startSketchOn(topExtrusion, 'end')
|
||||
|> circle(center = [0, 0], radius = pipeDia/2)
|
||||
|> circle(center = [0, 0], radius = pipeDia / 2)
|
||||
|> extrude(%, length = -(topTotalThickness + baseThickness + bottomThickness))
|
||||
|
@ -62,7 +62,7 @@ bracketBody = bs
|
||||
getPreviousAdjacentEdge(bs.tags.edge2),
|
||||
getPreviousAdjacentEdge(bs.tags.edge3),
|
||||
getPreviousAdjacentEdge(bs.tags.edge6)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
// define the tab plane
|
||||
@ -87,7 +87,7 @@ tabsR = startSketchOn(tabPlane)
|
||||
width / 2 + thk + tabWidth / 2,
|
||||
length / 2 + thk - (tabLength / (3 / 2))
|
||||
],
|
||||
radius = holeDiam / 2
|
||||
radius = holeDiam / 2,
|
||||
), %)
|
||||
|> extrude(length = -tabThk)
|
||||
|> fillet(
|
||||
@ -95,13 +95,9 @@ tabsR = startSketchOn(tabPlane)
|
||||
tags = [
|
||||
getNextAdjacentEdge(edge11),
|
||||
getNextAdjacentEdge(edge12)
|
||||
]
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0, -1, 0],
|
||||
instances = 2,
|
||||
distance = length + 2 * thk - (tabLength * 4 / 3)
|
||||
],
|
||||
)
|
||||
|> patternLinear3d(axis = [0, -1, 0], instances = 2, distance = length + 2 * thk - (tabLength * 4 / 3))
|
||||
|
||||
// build the tabs of the mounting bracket (left side)
|
||||
tabsL = startSketchOn(tabPlane)
|
||||
@ -115,7 +111,7 @@ tabsL = startSketchOn(tabPlane)
|
||||
-width / 2 - thk - (tabWidth / 2),
|
||||
length / 2 + thk - (tabLength / (3 / 2))
|
||||
],
|
||||
radius = holeDiam / 2
|
||||
radius = holeDiam / 2,
|
||||
), %)
|
||||
|> extrude(length = -tabThk)
|
||||
|> fillet(
|
||||
@ -123,13 +119,9 @@ tabsL = startSketchOn(tabPlane)
|
||||
tags = [
|
||||
getNextAdjacentEdge(edge21),
|
||||
getNextAdjacentEdge(edge22)
|
||||
]
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0, -1, 0],
|
||||
instances = 2,
|
||||
distance = length + 2 * thk - (tabLength * 4 / 3)
|
||||
],
|
||||
)
|
||||
|> patternLinear3d(axis = [0, -1, 0], instances = 2, distance = length + 2 * thk - (tabLength * 4 / 3))
|
||||
|
||||
// define a plane for retention bumps
|
||||
retPlane = {
|
||||
|
@ -44,7 +44,7 @@ fn slot(sketch1, start, end, width) {
|
||||
}
|
||||
|
||||
// create a sketch on the "XY" plane
|
||||
sketch000 = startSketchOn('XY')
|
||||
sketch000 = startSketchOn(XY)
|
||||
|
||||
// create a profile of the flipper
|
||||
flipperProfile = startProfileAt([-flipperLength, -32.0], sketch000)
|
||||
@ -83,11 +83,11 @@ fillet(
|
||||
tags = [
|
||||
getNextAdjacentEdge(backEdge),
|
||||
getPreviousAdjacentEdge(backEdge)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
// create a sketch on the "XZ" plane offset by half the thickness
|
||||
sketch001 = startSketchOn(offsetPlane("XZ", offset = -handleWidth / 2))
|
||||
sketch001 = startSketchOn(offsetPlane(XZ, offset = -handleWidth / 2))
|
||||
|
||||
// create a profile of the spatula handle
|
||||
handleProfile = startProfileAt([0.0, flipperThickness], sketch001)
|
||||
@ -109,7 +109,7 @@ fillet(
|
||||
tags = [
|
||||
getNextAdjacentEdge(handleBottomEdge),
|
||||
getNextAdjacentEdge(handleTopEdge)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
// define a plane which is at the end of the handle
|
||||
@ -163,4 +163,4 @@ sketch003 = startSketchOn(grip, gripEdgeTop)
|
||||
gripHoleProfile = slot(sketch003, [0, 200], [0, 210], gripSlotWidth)
|
||||
|
||||
// cut a hole in the grip
|
||||
extrude(gripHoleProfile, length = -gripWidth-20)
|
||||
extrude(gripHoleProfile, length = -gripWidth - 20)
|
||||
|
@ -10,7 +10,7 @@ carafeHeight = 7.32
|
||||
handleThickness = 0.65
|
||||
|
||||
// Upper ring of the metal structure
|
||||
sketch001 = startSketchOn('XZ')
|
||||
sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([carafeDiameter / 2, 5.7], %)
|
||||
|> angledLine([0, 0.1], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
@ -23,7 +23,7 @@ sketch001 = startSketchOn('XZ')
|
||||
], %, $rectangleSegmentC001)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> revolve(angle = 360, axis = 'Y')
|
||||
|> revolve(angle = 360, axis = Y)
|
||||
|
||||
// Create an angled plane to sketch the supports
|
||||
plane001 = {
|
||||
@ -91,15 +91,12 @@ sketch002 = startSketchOn(plane001)
|
||||
center = [0, 0, 0],
|
||||
instances = 4,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Cross plate
|
||||
sketch003 = startSketchOn(offsetPlane('XY', offset = 1))
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = carafeDiameter / 2 - 0.15
|
||||
)
|
||||
sketch003 = startSketchOn(offsetPlane(XY, offset = 1))
|
||||
|> circle(center = [0, 0], radius = carafeDiameter / 2 - 0.15)
|
||||
|
||||
extrude001 = extrude(sketch003, length = 0.050)
|
||||
|
||||
@ -117,13 +114,13 @@ sketch004 = startSketchOn(extrude001, 'END')
|
||||
center = [0, 0],
|
||||
instances = 3,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
extrude002 = extrude(sketch004, length = -0.050)
|
||||
|
||||
// Filter screen
|
||||
sketch005 = startSketchOn('XZ')
|
||||
sketch005 = startSketchOn(XZ)
|
||||
|> startProfileAt([0.15, 1.11], %)
|
||||
|> xLine(endAbsolute = carafeDiameter / 2 - 0.2)
|
||||
|> angledLineToX({
|
||||
@ -135,10 +132,10 @@ sketch005 = startSketchOn('XZ')
|
||||
|> xLine(endAbsolute = 0.15)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> revolve(axis = 'y')
|
||||
|> revolve(axis = Y)
|
||||
|
||||
// Plunger and stem
|
||||
sketch006 = startSketchOn('XZ')
|
||||
sketch006 = startSketchOn(XZ)
|
||||
|> startProfileAt([0.1, 1], %)
|
||||
|> line(end = [0.1, 0])
|
||||
|> angledLineToX({ angle = 10, to = 0.05 }, %)
|
||||
@ -148,14 +145,11 @@ sketch006 = startSketchOn('XZ')
|
||||
|> tangentialArc({ radius = 0.6, offset = -90 }, %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> revolve(axis = 'y')
|
||||
|> revolve(axis = Y)
|
||||
|
||||
// Spiral plate
|
||||
sketch007 = startSketchOn(offsetPlane('XY', offset = 1.12))
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = carafeDiameter / 2 - 0.24
|
||||
)
|
||||
sketch007 = startSketchOn(offsetPlane(XY, offset = 1.12))
|
||||
|> circle(center = [0, 0], radius = carafeDiameter / 2 - 0.24)
|
||||
|> hole(circle(center = [0, 0], radius = .15), %)
|
||||
|
||||
extrude003 = extrude(sketch007, length = 0.050)
|
||||
@ -167,7 +161,7 @@ sketch008 = startSketchOn(extrude003, 'END')
|
||||
center = [0, 0],
|
||||
instances = 8,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
extrude004 = extrude(sketch008, length = -0.050)
|
||||
@ -179,24 +173,21 @@ sketch009 = startSketchOn(extrude003, 'END')
|
||||
center = [0, 0],
|
||||
instances = 4,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
extrude005 = extrude(sketch009, length = -0.050)
|
||||
|
||||
// Extrude a glass carafe body
|
||||
sketch010 = startSketchOn("XY")
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = carafeDiameter / 2
|
||||
)
|
||||
sketch010 = startSketchOn(XY)
|
||||
|> circle(center = [0, 0], radius = carafeDiameter / 2)
|
||||
|
||||
// Perform a shell operation to hollow the carafe body with the top face removed
|
||||
extrude006 = extrude(sketch010, length = carafeHeight)
|
||||
|> shell(faces = ["end"], thickness = .07)
|
||||
|
||||
// Draw and revolve the lid
|
||||
sketch011 = startSketchOn('XZ')
|
||||
sketch011 = startSketchOn(XZ)
|
||||
|> startProfileAt([0.2, carafeHeight - 0.7], %)
|
||||
|> xLine(length = carafeDiameter / 2 - 0.3)
|
||||
|> yLine(length = 0.7)
|
||||
@ -210,10 +201,10 @@ sketch011 = startSketchOn('XZ')
|
||||
}, %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|> revolve(axis = 'y')
|
||||
|> revolve(axis = Y)
|
||||
|
||||
// Draw and extrude handle
|
||||
sketch012 = startSketchOn(offsetPlane('XZ', offset = handleThickness / 2))
|
||||
sketch012 = startSketchOn(offsetPlane(XZ, offset = handleThickness / 2))
|
||||
|> startProfileAt([2.3, 6.4], %)
|
||||
|> line(end = [0.56, 0])
|
||||
|> tangentialArcTo([4.1, 5.26], %)
|
||||
|
@ -12,7 +12,7 @@ height = 12
|
||||
minHeight = 10.875
|
||||
|
||||
// Create the body of the rack
|
||||
rackBody = startSketchOn('XY')
|
||||
rackBody = startSketchOn(XY)
|
||||
|> startProfileAt([-length / 2, 0], %)
|
||||
|> line(end = [length, 0])
|
||||
|> line(end = [0, minHeight])
|
||||
@ -22,7 +22,7 @@ rackBody = startSketchOn('XY')
|
||||
|
||||
// Create a function for sketch of a single tooth
|
||||
fn tooth() {
|
||||
toothSketch = startSketchOn('XY')
|
||||
toothSketch = startSketchOn(XY)
|
||||
|> startProfileAt([-length / 2 + 0.567672, minHeight], %)
|
||||
|> tangentialArcToRelative([0.157636, 0.110378], %)
|
||||
|> line(end = [0.329118, 0.904244])
|
||||
@ -38,14 +38,10 @@ fn tooth() {
|
||||
|
||||
// Pattern the single tooth over the length of the rack body
|
||||
teeth = tooth()
|
||||
|> patternLinear3d(
|
||||
axis = [10, 0, 0],
|
||||
distance = 1.570796,
|
||||
instances = 63
|
||||
)
|
||||
|> patternLinear3d(axis = [10, 0, 0], distance = 1.570796, instances = 63)
|
||||
|
||||
// Sketch and extrude the first end cap. This is a partial tooth
|
||||
endCapTooth = startSketchOn('XY')
|
||||
endCapTooth = startSketchOn(XY)
|
||||
|> startProfileAt([-length / 2, 11.849525], %)
|
||||
|> line(end = [0.314524, -0.864147])
|
||||
|> tangentialArcToRelative([0.157636, -0.110378], %)
|
||||
@ -54,7 +50,7 @@ endCapTooth = startSketchOn('XY')
|
||||
|> extrude(length = width)
|
||||
|
||||
// Sketch and extrude the second end cap. This is a partial tooth
|
||||
endCapTooth2 = startSketchOn('XY')
|
||||
endCapTooth2 = startSketchOn(XY)
|
||||
|> startProfileAt([length / 2, 11.849525], %)
|
||||
|> line(end = [-0.314524, -0.864147])
|
||||
|> tangentialArcToRelative([-0.157636, -0.110378], %)
|
||||
|
@ -17,35 +17,32 @@ gearHeight = 3
|
||||
|
||||
// Interpolate points along the involute curve
|
||||
cmo = 101
|
||||
rs = map([0..cmo], fn (i) {
|
||||
rs = map([0..cmo], fn(i) {
|
||||
return baseDiameter / 2 + i / cmo * (tipDiameter - baseDiameter) / 2
|
||||
})
|
||||
|
||||
// Calculate operating pressure angle
|
||||
angles = map(rs, fn (r) {
|
||||
angles = map(rs, fn(r) {
|
||||
return toDegrees( acos(baseDiameter / 2 / r))
|
||||
})
|
||||
|
||||
// Calculate the involute function
|
||||
invas = map(angles, fn (a) {
|
||||
invas = map(angles, fn(a) {
|
||||
return tan(toRadians(a)) - toRadians(a)
|
||||
})
|
||||
|
||||
// Map the involute curve
|
||||
xs = map([0..cmo], fn (i) {
|
||||
xs = map([0..cmo], fn(i) {
|
||||
return rs[i] * cos(invas[i])
|
||||
})
|
||||
|
||||
ys = map([0..cmo], fn (i) {
|
||||
ys = map([0..cmo], fn(i) {
|
||||
return rs[i] * sin(invas[i])
|
||||
})
|
||||
|
||||
// Extrude the gear body
|
||||
body = startSketchOn('XY')
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = baseDiameter / 2
|
||||
)
|
||||
body = startSketchOn(XY)
|
||||
|> circle(center = [0, 0], radius = baseDiameter / 2)
|
||||
|> extrude(length = gearHeight)
|
||||
|
||||
toothAngle = 360 / nTeeth / 1.5
|
||||
@ -63,7 +60,7 @@ fn rightInvolute(i, sg) {
|
||||
}
|
||||
|
||||
// Draw gear teeth
|
||||
start = startSketchOn('XY')
|
||||
start = startSketchOn(XY)
|
||||
|> startProfileAt([xs[101], ys[101]], %)
|
||||
teeth = reduce([0..100], start, leftInvolute)
|
||||
|> arc({
|
||||
@ -79,7 +76,7 @@ teeth = reduce([0..100], start, leftInvolute)
|
||||
center = [0, 0, 0],
|
||||
instances = nTeeth,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Define the constants of the keyway and the bore hole
|
||||
|
@ -34,7 +34,7 @@ fn face(plane) {
|
||||
}
|
||||
|
||||
// extrude a single side of the bin
|
||||
singleSide = extrude(face(offsetPlane("YZ", offset = cornerRadius)), length = binLength - (cornerRadius * 2), )
|
||||
singleSide = extrude(face(offsetPlane(YZ, offset = cornerRadius)), length = binLength - (cornerRadius * 2))
|
||||
|
||||
// create the other sides of the bin by using a circular pattern
|
||||
sides = patternCircular3d(
|
||||
@ -43,19 +43,17 @@ sides = patternCircular3d(
|
||||
axis = [0, 0, 1],
|
||||
center = [binLength / 2, binLength / 2, 0],
|
||||
instances = 4,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// define an axis axis000
|
||||
axis000 = {
|
||||
custom = {
|
||||
axis = [0.0, 1.0],
|
||||
origin = [cornerRadius, cornerRadius]
|
||||
}
|
||||
direction = [0.0, 1.0],
|
||||
origin = [cornerRadius, cornerRadius]
|
||||
}
|
||||
|
||||
// create a single corner of the bin
|
||||
singleCorner = revolve(face(offsetPlane("YZ", offset = cornerRadius)), angle = -90, axis = axis000)
|
||||
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius)), angle = -90, axis = axis000)
|
||||
|
||||
// create the corners of the bin
|
||||
corners = patternCircular3d(
|
||||
@ -64,7 +62,7 @@ corners = patternCircular3d(
|
||||
axis = [0, 0, 1],
|
||||
center = [binLength / 2, binLength / 2, 0],
|
||||
instances = 4,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// create the baseplate by patterning sides
|
||||
@ -72,26 +70,18 @@ basePlateSides = patternLinear3d(
|
||||
sides,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
instances = countBinWidth,
|
||||
distance = binLength
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0.0, 1.0, 0.0],
|
||||
instances = countBinLength,
|
||||
distance = binLength
|
||||
distance = binLength,
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength)
|
||||
|
||||
// create the corners of the baseplate by patterning the corners
|
||||
basePlateCorners = patternLinear3d(
|
||||
corners,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
instances = countBinWidth,
|
||||
distance = binLength
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0.0, 1.0, 0.0],
|
||||
instances = countBinLength,
|
||||
distance = binLength
|
||||
distance = binLength,
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength)
|
||||
|
||||
// create the center cutout for the magnet profile
|
||||
fn magnetCenterCutout(plane) {
|
||||
@ -149,20 +139,17 @@ fn magnetBase(plane) {
|
||||
}
|
||||
|
||||
// create sketch profile sketch000Profile002
|
||||
magnetsSketch = startSketchOn('XY')
|
||||
|> circle(
|
||||
center = [cornerRadius * 2, cornerRadius * 2],
|
||||
radius = magOuterDiam / 2
|
||||
)
|
||||
magnetsSketch = startSketchOn(XY)
|
||||
|> circle(center = [cornerRadius * 2, cornerRadius * 2], radius = magOuterDiam / 2)
|
||||
|> patternCircular2d(
|
||||
center = [binLength / 2, binLength / 2],
|
||||
instances = 4,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// create a profile with holes for the magnets
|
||||
magnetProfile = magnetBase("XY")
|
||||
magnetProfile = magnetBase(XY)
|
||||
|> hole(magnetsSketch, %)
|
||||
|
||||
// create an extrusion of the magnet cutout with holes
|
||||
@ -177,11 +164,11 @@ magnetHolesExtrudeFillets = fillet(
|
||||
getPreviousAdjacentEdge(magnetHolesExtrude.sketch.tags.line001),
|
||||
getNextAdjacentEdge(magnetHolesExtrude.sketch.tags.line003),
|
||||
getPreviousAdjacentEdge(magnetHolesExtrude.sketch.tags.line003)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
// create a profile without the holes for the magnets
|
||||
magnetProfileNoMagnets = magnetBase(offsetPlane("XY", offset = -magDepth))
|
||||
magnetProfileNoMagnets = magnetBase(offsetPlane(XY, offset = -magDepth))
|
||||
|
||||
// create an extrusion of the magnet cutout without holes
|
||||
magnetCutoutExtrude = extrude(magnetProfileNoMagnets, length = -magDepth)
|
||||
@ -195,7 +182,7 @@ magnetCutoutExtrudeFillets = fillet(
|
||||
getPreviousAdjacentEdge(magnetCutoutExtrude.sketch.tags.line001),
|
||||
getNextAdjacentEdge(magnetCutoutExtrude.sketch.tags.line003),
|
||||
getPreviousAdjacentEdge(magnetCutoutExtrude.sketch.tags.line003)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
// pattern the magnet cutouts with holes
|
||||
@ -203,23 +190,15 @@ patternLinear3d(
|
||||
magnetHolesExtrudeFillets,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
instances = countBinWidth,
|
||||
distance = binLength
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0.0, 1.0, 0.0],
|
||||
instances = countBinLength,
|
||||
distance = binLength
|
||||
distance = binLength,
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength)
|
||||
|
||||
// pattern the magnet cutouts without holes
|
||||
patternLinear3d(
|
||||
magnetCutoutExtrudeFillets,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
instances = countBinWidth,
|
||||
distance = binLength
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0.0, 1.0, 0.0],
|
||||
instances = countBinLength,
|
||||
distance = binLength
|
||||
distance = binLength,
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength)
|
||||
|
@ -31,7 +31,7 @@ fn face(plane) {
|
||||
}
|
||||
|
||||
// extrude a single side of the bin
|
||||
singleSide = extrude(face(offsetPlane("YZ", offset = cornerRadius)), length = binLength - (cornerRadius * 2))
|
||||
singleSide = extrude(face(offsetPlane(YZ, offset = cornerRadius)), length = binLength - (cornerRadius * 2))
|
||||
|
||||
// create the other sides of the bin by using a circular pattern
|
||||
sides = patternCircular3d(
|
||||
@ -40,19 +40,17 @@ sides = patternCircular3d(
|
||||
axis = [0, 0, 1],
|
||||
center = [binLength / 2, binLength / 2, 0],
|
||||
instances = 4,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// define an axis axis000
|
||||
axis000 = {
|
||||
custom = {
|
||||
axis = [0.0, 1.0],
|
||||
origin = [cornerRadius, cornerRadius]
|
||||
}
|
||||
direction = [0.0, 1.0],
|
||||
origin = [cornerRadius, cornerRadius]
|
||||
}
|
||||
|
||||
// create a single corner of the bin
|
||||
singleCorner = revolve(face(offsetPlane("YZ", offset = cornerRadius)), angle = -90, axis = axis000)
|
||||
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius)), angle = -90, axis = axis000)
|
||||
|
||||
// create the corners of the bin
|
||||
corners = patternCircular3d(
|
||||
@ -61,7 +59,7 @@ corners = patternCircular3d(
|
||||
axis = [0, 0, 1],
|
||||
center = [binLength / 2, binLength / 2, 0],
|
||||
instances = 4,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// create the baseplate by patterning sides
|
||||
@ -69,23 +67,15 @@ basePlateSides = patternLinear3d(
|
||||
sides,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
instances = countBinWidth,
|
||||
distance = binLength
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0.0, 1.0, 0.0],
|
||||
instances = countBinLength,
|
||||
distance = binLength
|
||||
distance = binLength,
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength)
|
||||
|
||||
// create the corners of the baseplate by patterning the corners
|
||||
basePlateCorners = patternLinear3d(
|
||||
corners,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
instances = countBinWidth,
|
||||
distance = binLength
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0.0, 1.0, 0.0],
|
||||
instances = countBinLength,
|
||||
distance = binLength
|
||||
distance = binLength,
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength)
|
||||
|
@ -47,7 +47,7 @@ fn face(plane) {
|
||||
}
|
||||
|
||||
// extrude a single side of the bin
|
||||
singleSide = extrude(face(offsetPlane("YZ", offset = cornerRadius + binTol)), length = binLength - (cornerRadius * 2))
|
||||
singleSide = extrude(face(offsetPlane(YZ, offset = cornerRadius + binTol)), length = binLength - (cornerRadius * 2))
|
||||
|
||||
// create the other sides of the bin by using a circular pattern
|
||||
sides = patternCircular3d(
|
||||
@ -60,22 +60,20 @@ sides = patternCircular3d(
|
||||
0
|
||||
],
|
||||
instances = 4,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// define an axis axis000
|
||||
axis000 = {
|
||||
custom = {
|
||||
axis = [0.0, 1.0],
|
||||
origin = [
|
||||
cornerRadius + binTol,
|
||||
cornerRadius + binTol
|
||||
]
|
||||
}
|
||||
direction = [0.0, 1.0],
|
||||
origin = [
|
||||
cornerRadius + binTol,
|
||||
cornerRadius + binTol
|
||||
]
|
||||
}
|
||||
|
||||
// create a single corner of the bin
|
||||
singleCorner = revolve(face(offsetPlane("YZ", offset = cornerRadius + binTol)), angle = -90, axis = axis000)
|
||||
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius + binTol)), angle = -90, axis = axis000)
|
||||
|
||||
// create the corners of the bin
|
||||
corners = patternCircular3d(
|
||||
@ -88,10 +86,10 @@ corners = patternCircular3d(
|
||||
0
|
||||
],
|
||||
instances = 4,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
singleBinFill = startSketchOn("XY")
|
||||
singleBinFill = startSketchOn(XY)
|
||||
|> startProfileAt([
|
||||
binBaseLength + binTol,
|
||||
binBaseLength + binTol
|
||||
@ -108,7 +106,7 @@ singleBinFill = startSketchOn("XY")
|
||||
getPreviousAdjacentEdge(line000),
|
||||
getNextAdjacentEdge(line002),
|
||||
getPreviousAdjacentEdge(line002)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
magCutout000 = startSketchOn(singleBinFill, "start")
|
||||
@ -117,7 +115,7 @@ magCutout000 = startSketchOn(singleBinFill, "start")
|
||||
-magOffset - binBaseLength - binTol,
|
||||
magOffset + binBaseLength + binTol
|
||||
],
|
||||
radius = magOuterDiam / 2
|
||||
radius = magOuterDiam / 2,
|
||||
)
|
||||
|> patternCircular2d(
|
||||
arcDegrees = 360,
|
||||
@ -126,7 +124,7 @@ magCutout000 = startSketchOn(singleBinFill, "start")
|
||||
(binLength + 2 * binTol) / 2
|
||||
],
|
||||
instances = 4,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|> extrude(length = -magDepth)
|
||||
|
||||
@ -135,42 +133,30 @@ binSides = patternLinear3d(
|
||||
sides,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
instances = countBinWidth,
|
||||
distance = binLength + binTol * 2
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0.0, 1.0, 0.0],
|
||||
instances = countBinLength,
|
||||
distance = binLength + binTol * 2
|
||||
distance = binLength + binTol * 2,
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength + binTol * 2)
|
||||
|
||||
// create the corners of the baseplate by patterning the corners
|
||||
binCorners = patternLinear3d(
|
||||
corners,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
instances = countBinWidth,
|
||||
distance = binLength + binTol * 2
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0.0, 1.0, 0.0],
|
||||
instances = countBinLength,
|
||||
distance = binLength + binTol * 2
|
||||
distance = binLength + binTol * 2,
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength + binTol * 2)
|
||||
|
||||
// create the fill of the bin by patterning the corners
|
||||
binFill = patternLinear3d(
|
||||
singleBinFill,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
instances = countBinWidth,
|
||||
distance = binLength + binTol * 2
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0.0, 1.0, 0.0],
|
||||
instances = countBinLength,
|
||||
distance = binLength + binTol * 2
|
||||
distance = binLength + binTol * 2,
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength + binTol * 2)
|
||||
|
||||
//
|
||||
binTop = startSketchOn(offsetPlane("XY", offset = height))
|
||||
binTop = startSketchOn(offsetPlane(XY, offset = height))
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> xLine(length = (binLength + 2 * binTol) * countBinWidth, tag = $line010)
|
||||
|> yLine(length = (binLength + 2 * binTol) * countBinLength, tag = $line011)
|
||||
@ -184,7 +170,7 @@ binTop = startSketchOn(offsetPlane("XY", offset = height))
|
||||
getPreviousAdjacentEdge(line010),
|
||||
getNextAdjacentEdge(line012),
|
||||
getPreviousAdjacentEdge(line012)
|
||||
]
|
||||
],
|
||||
)
|
||||
|> shell(faces = ["end"], thickness = binThk)
|
||||
|
||||
@ -265,7 +251,7 @@ lipLengths = patternCircular3d(
|
||||
0
|
||||
],
|
||||
instances = 2,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// create the other sides of the lips by using a circular pattern
|
||||
@ -279,15 +265,13 @@ lipWidths = patternCircular3d(
|
||||
0
|
||||
],
|
||||
instances = 2,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// define an axis axis000
|
||||
axis001 = {
|
||||
custom = {
|
||||
axis = [0.0, 1.0],
|
||||
origin = [cornerRadius, cornerRadius]
|
||||
}
|
||||
direction = [0.0, 1.0],
|
||||
origin = [cornerRadius, cornerRadius]
|
||||
}
|
||||
|
||||
// create a single corner of the bin
|
||||
@ -307,7 +291,7 @@ lipCorners000 = patternCircular3d(
|
||||
0
|
||||
],
|
||||
instances = 2,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// create the corners of the bin
|
||||
@ -321,5 +305,5 @@ lipCorners001 = patternCircular3d(
|
||||
0
|
||||
],
|
||||
instances = 2,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
@ -40,7 +40,7 @@ fn face(plane) {
|
||||
}
|
||||
|
||||
// extrude a single side of the bin
|
||||
singleSide = extrude(face(offsetPlane("YZ", offset = cornerRadius + binTol)), length = binLength - (cornerRadius * 2), )
|
||||
singleSide = extrude(face(offsetPlane(YZ, offset = cornerRadius + binTol)), length = binLength - (cornerRadius * 2))
|
||||
|
||||
// create the other sides of the bin by using a circular pattern
|
||||
sides = patternCircular3d(
|
||||
@ -53,22 +53,20 @@ sides = patternCircular3d(
|
||||
0
|
||||
],
|
||||
instances = 4,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// define an axis axis000
|
||||
axis000 = {
|
||||
custom = {
|
||||
axis = [0.0, 1.0],
|
||||
origin = [
|
||||
cornerRadius + binTol,
|
||||
cornerRadius + binTol
|
||||
]
|
||||
}
|
||||
direction = [0.0, 1.0],
|
||||
origin = [
|
||||
cornerRadius + binTol,
|
||||
cornerRadius + binTol
|
||||
]
|
||||
}
|
||||
|
||||
// create a single corner of the bin
|
||||
singleCorner = revolve(face(offsetPlane("YZ", offset = cornerRadius + binTol)), angle = -90, axis = axis000)
|
||||
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius + binTol)), angle = -90, axis = axis000)
|
||||
|
||||
// create the corners of the bin
|
||||
corners = patternCircular3d(
|
||||
@ -81,10 +79,10 @@ corners = patternCircular3d(
|
||||
0
|
||||
],
|
||||
instances = 4,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
singleBinFill = startSketchOn("XY")
|
||||
singleBinFill = startSketchOn(XY)
|
||||
|> startProfileAt([
|
||||
binBaseLength + binTol,
|
||||
binBaseLength + binTol
|
||||
@ -101,7 +99,7 @@ singleBinFill = startSketchOn("XY")
|
||||
getPreviousAdjacentEdge(line000),
|
||||
getNextAdjacentEdge(line002),
|
||||
getPreviousAdjacentEdge(line002)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
magCutout000 = startSketchOn(singleBinFill, "start")
|
||||
@ -110,7 +108,7 @@ magCutout000 = startSketchOn(singleBinFill, "start")
|
||||
-magOffset - binBaseLength - binTol,
|
||||
magOffset + binBaseLength + binTol
|
||||
],
|
||||
radius = magOuterDiam / 2
|
||||
radius = magOuterDiam / 2,
|
||||
)
|
||||
|> patternCircular2d(
|
||||
arcDegrees = 360,
|
||||
@ -119,7 +117,7 @@ magCutout000 = startSketchOn(singleBinFill, "start")
|
||||
(binLength + 2 * binTol) / 2
|
||||
],
|
||||
instances = 4,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|> extrude(length = -magDepth)
|
||||
|
||||
@ -128,42 +126,30 @@ binSides = patternLinear3d(
|
||||
sides,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
instances = countBinWidth,
|
||||
distance = binLength + binTol * 2
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0.0, 1.0, 0.0],
|
||||
instances = countBinLength,
|
||||
distance = binLength + binTol * 2
|
||||
distance = binLength + binTol * 2,
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength + binTol * 2)
|
||||
|
||||
// create the corners of the baseplate by patterning the corners
|
||||
binCorners = patternLinear3d(
|
||||
corners,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
instances = countBinWidth,
|
||||
distance = binLength + binTol * 2
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0.0, 1.0, 0.0],
|
||||
instances = countBinLength,
|
||||
distance = binLength + binTol * 2
|
||||
distance = binLength + binTol * 2,
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength + binTol * 2)
|
||||
|
||||
// create the fill of the bin by patterning the corners
|
||||
binFill = patternLinear3d(
|
||||
singleBinFill,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
instances = countBinWidth,
|
||||
distance = binLength + binTol * 2
|
||||
)
|
||||
|> patternLinear3d(
|
||||
axis = [0.0, 1.0, 0.0],
|
||||
instances = countBinLength,
|
||||
distance = binLength + binTol * 2
|
||||
distance = binLength + binTol * 2,
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength + binTol * 2)
|
||||
|
||||
// create the top of the bin
|
||||
binTop = startSketchOn(offsetPlane("XY", offset = height))
|
||||
binTop = startSketchOn(offsetPlane(XY, offset = height))
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> xLine(length = (binLength + 2 * binTol) * countBinWidth, tag = $line010)
|
||||
|> yLine(length = (binLength + 2 * binTol) * countBinLength, tag = $line011)
|
||||
@ -177,6 +163,6 @@ binTop = startSketchOn(offsetPlane("XY", offset = height))
|
||||
getPreviousAdjacentEdge(line010),
|
||||
getNextAdjacentEdge(line012),
|
||||
getPreviousAdjacentEdge(line012)
|
||||
]
|
||||
],
|
||||
)
|
||||
|> shell(faces = ["end"], thickness = binThk)
|
||||
|
@ -11,7 +11,7 @@ diameter = 0.3125
|
||||
|
||||
// Define a function for the hex nut
|
||||
fn hexNut(start, thk, innerDia) {
|
||||
hexNutSketch = startSketchOn('-XZ')
|
||||
hexNutSketch = startSketchOn(-XZ)
|
||||
|> startProfileAt([start[0] + innerDia, start[1]], %)
|
||||
|> angledLine({ angle = 240, length = innerDia }, %)
|
||||
|> angledLine({ angle = 180, length = innerDia }, %)
|
||||
@ -19,10 +19,7 @@ fn hexNut(start, thk, innerDia) {
|
||||
|> angledLine({ angle = 60, length = innerDia }, %)
|
||||
|> angledLine({ angle = 0, length = innerDia * .90 }, %)
|
||||
|> close()
|
||||
|> hole(circle(
|
||||
center = [start[0], start[1]],
|
||||
radius = innerDia / 2
|
||||
), %)
|
||||
|> hole(circle(center = [start[0], start[1]], radius = innerDia / 2), %)
|
||||
|> extrude(length = thk)
|
||||
return hexNutSketch
|
||||
}
|
||||
|
@ -20,6 +20,6 @@ sketch001 = startSketchOn(-XZ)
|
||||
|> xLine(endAbsolute = webThickness / 2 + rootRadius)
|
||||
|> tangentialArc({ radius = rootRadius, offset = 90 }, %)
|
||||
|> yLine(endAbsolute = 0)
|
||||
|> mirror2d({ axis = 'X' }, %)
|
||||
|> mirror2d({ axis = 'Y' }, %)
|
||||
|> mirror2d(axis = X)
|
||||
|> mirror2d(axis = Y)
|
||||
|> extrude(length = beamLength)
|
||||
|
@ -19,7 +19,7 @@ row5 = row4 + keyHeight + spacing
|
||||
row6 = row5 + keyHeight + spacing
|
||||
|
||||
// Sketch the side profile of the keyboard base and extrude to total width
|
||||
sketch001 = startSketchOn('YZ')
|
||||
sketch001 = startSketchOn(YZ)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line(end = [-0.14, 0.68], tag = $seg01)
|
||||
|> angledLine([7, row6 + 3 * spacing + keyHeight], %, $seg02)
|
||||
@ -89,7 +89,7 @@ fn keyFn(originStart, keyWidth, keyHeight, repeats, color) {
|
||||
|> close()
|
||||
|> extrude(length = keyDepth)
|
||||
|> appearance(color = color)
|
||||
// Repeat key when desired. This will default to zero
|
||||
// Repeat key when desired. This will default to zero
|
||||
|> patternLinear3d(
|
||||
%,
|
||||
instances = repeats + 1,
|
||||
|
@ -20,7 +20,7 @@ kitBodyWidth = 26
|
||||
kitBodyHeight = 25
|
||||
kitBodyDepth = 18
|
||||
|
||||
kitBody = startSketchOn('XZ')
|
||||
kitBody = startSketchOn(XZ)
|
||||
|> startProfileAt([-kitBodyWidth / 2, kitBodyElevation], %)
|
||||
|> line(end = [0, kitBodyHeight])
|
||||
|> line(end = [kitBodyWidth, 0], tag = $seg01)
|
||||
@ -159,7 +159,7 @@ kitShoeHeight = 3
|
||||
fn kitLeg(offsetFront, offsetSide) {
|
||||
kitShoeOffsetFront = kitShoeLength / 2 - (kitBodyDepth / 2) - offsetFront
|
||||
|
||||
kitFootPrint = startSketchOn('XY')
|
||||
kitFootPrint = startSketchOn(XY)
|
||||
|> startProfileAt([offsetSide, kitShoeOffsetFront], %)
|
||||
|> line(end = [kitShoeWidth, 0])
|
||||
|> line(end = [0, -kitShoeLength])
|
||||
|
@ -26,7 +26,7 @@ assertGreaterThan(lbumps, 1, "lbumps must be greater than 1")
|
||||
assertGreaterThan(wbumps, 1, "wbumps must be greater than 1")
|
||||
|
||||
// Make the base
|
||||
base = startSketchOn('XY')
|
||||
base = startSketchOn(XY)
|
||||
|> startProfileAt([-totalWidth / 2, -totalLength / 2], %)
|
||||
|> line(end = [totalWidth, 0])
|
||||
|> line(end = [0, totalLength])
|
||||
@ -53,18 +53,10 @@ peg = startSketchOn(base, 'end')
|
||||
-(pitch * (wbumps - 1) / 2),
|
||||
-(pitch * (lbumps - 1) / 2)
|
||||
],
|
||||
radius = bumpDiam / 2
|
||||
)
|
||||
|> patternLinear2d(
|
||||
axis = [1, 0],
|
||||
instances = wbumps,
|
||||
distance = pitch
|
||||
)
|
||||
|> patternLinear2d(
|
||||
axis = [0, 1],
|
||||
instances = lbumps,
|
||||
distance = pitch
|
||||
radius = bumpDiam / 2,
|
||||
)
|
||||
|> patternLinear2d(axis = [1, 0], instances = wbumps, distance = pitch)
|
||||
|> patternLinear2d(axis = [0, 1], instances = lbumps, distance = pitch)
|
||||
|> extrude(length = bumpHeight)
|
||||
|
||||
// Create the pegs on the bottom of the base
|
||||
@ -74,16 +66,8 @@ tubePattern = startSketchOn(shellExtrude, 'start')
|
||||
-(pitch * (wbumps - 1) / 2 - (pitch / 2)),
|
||||
-(pitch * (lbumps - 1) / 2 - (pitch / 2))
|
||||
],
|
||||
radius = bumpDiam / 2
|
||||
)
|
||||
|> patternLinear2d(
|
||||
axis = [1, 0],
|
||||
instances = wbumps - 1,
|
||||
distance = pitch
|
||||
)
|
||||
|> patternLinear2d(
|
||||
axis = [0, 1],
|
||||
instances = lbumps - 1,
|
||||
distance = pitch
|
||||
radius = bumpDiam / 2,
|
||||
)
|
||||
|> patternLinear2d(axis = [1, 0], instances = wbumps - 1, distance = pitch)
|
||||
|> patternLinear2d(axis = [0, 1], instances = lbumps - 1, distance = pitch)
|
||||
|> extrude(length = bumpHeight)
|
||||
|
75
public/kcl-samples/makeup-mirror/main.kcl
Normal file
@ -0,0 +1,75 @@
|
||||
// Makeup Mirror
|
||||
// A circular vanity mirror mounted on a swiveling arm with pivot joints, used for personal grooming.
|
||||
|
||||
// Settings
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// hinge
|
||||
hingeRadius = 8
|
||||
hingeHeight = hingeRadius * 3
|
||||
hingeGap = 0.5
|
||||
|
||||
// arm
|
||||
armLength = 170
|
||||
armRadius = 5
|
||||
|
||||
// mirror
|
||||
mirrorRadius = 170 / 2
|
||||
mirrorThickness = 10
|
||||
archToMirrorGap = 5
|
||||
archThickness = 1
|
||||
archRadius = mirrorRadius + archToMirrorGap
|
||||
|
||||
// Geometry
|
||||
// hinge
|
||||
fn hingeFn(x, y, z) {
|
||||
hingeBody = startSketchOn(offsetPlane(XY, offset = z))
|
||||
|> circle(center = [x, y], radius = hingeRadius)
|
||||
|> extrude(length = hingeHeight)
|
||||
return hingeBody
|
||||
}
|
||||
|
||||
hingePartA1 = hingeFn(0, 0, 0)
|
||||
hingePartA2 = hingeFn(0, 0, hingeHeight + hingeGap)
|
||||
hingePartA3 = hingeFn(0, 0, hingeHeight * 2 + hingeGap * 2)
|
||||
|
||||
hingePartB2 = hingeFn(armLength, 0, hingeHeight + hingeGap)
|
||||
hingePartB3 = hingeFn(armLength, 0, hingeHeight * 2 + hingeGap * 2)
|
||||
|
||||
hingePartC2 = hingeFn(armLength, -armLength, hingeHeight * 2 + hingeGap * 2)
|
||||
hingePartC3 = hingeFn(armLength, -armLength, hingeHeight * 3 + hingeGap * 3)
|
||||
|
||||
// arm
|
||||
fn armFn(plane, offset, altitude) {
|
||||
armBody = startSketchOn(plane)
|
||||
|> circle(center = [offset, altitude], radius = armRadius)
|
||||
|> extrude(length = armLength)
|
||||
return armBody
|
||||
}
|
||||
|
||||
armPartA = armFn(YZ, 0, hingeHeight * 1.5 + hingeGap)
|
||||
armPartB = armFn(XZ, armLength, hingeHeight * 2.5 + hingeGap * 2)
|
||||
|
||||
// mirror
|
||||
fn mirrorFn(plane, offsetX, offsetY, altitude, radius, tiefe, gestellR, gestellD) {
|
||||
armPlane = startSketchOn(offsetPlane(plane, offset = offsetY - (tiefe / 2)))
|
||||
armBody = circle(armPlane, center = [offsetX, altitude], radius = radius)
|
||||
|> extrude(length = tiefe)
|
||||
|
||||
archBody = startProfileAt([offsetX-gestellR, altitude], armPlane)
|
||||
|> xLine(length = gestellD)
|
||||
|> arcTo({
|
||||
interior = [offsetX, altitude-gestellR],
|
||||
end = [offsetX+gestellR, altitude]
|
||||
}, %)
|
||||
|> xLine(length = gestellD)
|
||||
|> arcTo({
|
||||
interior = [offsetX, altitude-gestellR-gestellD],
|
||||
end = [profileStartX(%), profileStartY(%)]
|
||||
}, %)
|
||||
|> close()
|
||||
|> extrude(length = tiefe)
|
||||
return armBody
|
||||
}
|
||||
|
||||
mirror = mirrorFn(XZ, armLength, armLength, hingeHeight * 4 + hingeGap * 3 + mirrorRadius+archToMirrorGap+archThickness, mirrorRadius, mirrorThickness, archRadius, archThickness)
|
@ -62,6 +62,13 @@
|
||||
"title": "Hollow 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 individual faces of the dodecahedron and extruding inwards."
|
||||
},
|
||||
{
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "enclosure/main.kcl",
|
||||
@ -181,6 +188,13 @@
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "mounting-plate/main.kcl",
|
||||
|
@ -13,7 +13,7 @@ centerHoleDiameter = 2
|
||||
|
||||
// Create a function that defines the body width and length of the mounting plate. Tag the corners so they can be passed through the fillet function.
|
||||
fn rectShape(pos, w, l) {
|
||||
rr = startSketchOn('XY')
|
||||
rr = startSketchOn(XY)
|
||||
|> startProfileAt([pos[0] - (w / 2), pos[1] - (l / 2)], %)
|
||||
|> line(endAbsolute = [pos[0] + w / 2, pos[1] - (l / 2)], tag = $edge1)
|
||||
|> line(endAbsolute = [pos[0] + w / 2, pos[1] + l / 2], tag = $edge2)
|
||||
@ -34,33 +34,30 @@ part = rs
|
||||
-plateWidth / 2 + holeIndex,
|
||||
plateLength / 2 - holeIndex
|
||||
],
|
||||
radius = holeRadius
|
||||
radius = holeRadius,
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [
|
||||
plateWidth / 2 - holeIndex,
|
||||
plateLength / 2 - holeIndex
|
||||
],
|
||||
radius = holeRadius
|
||||
radius = holeRadius,
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [
|
||||
-plateWidth / 2 + holeIndex,
|
||||
-plateLength / 2 + holeIndex
|
||||
],
|
||||
radius = holeRadius
|
||||
radius = holeRadius,
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [
|
||||
plateWidth / 2 - holeIndex,
|
||||
-plateLength / 2 + holeIndex
|
||||
],
|
||||
radius = holeRadius
|
||||
), %)
|
||||
|> hole(circle(
|
||||
center = [0, 0],
|
||||
radius = centerHoleDiameter
|
||||
radius = holeRadius,
|
||||
), %)
|
||||
|> hole(circle(center = [0, 0], radius = centerHoleDiameter), %)
|
||||
|> extrude(length = plateThickness)
|
||||
|> fillet(
|
||||
radius = filletRadius,
|
||||
@ -69,5 +66,5 @@ part = rs
|
||||
getPreviousAdjacentEdge(rs.tags.edge2),
|
||||
getPreviousAdjacentEdge(rs.tags.edge3),
|
||||
getPreviousAdjacentEdge(rs.tags.edge4)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
@ -28,37 +28,37 @@ export axisJ3CArmThickness = 2.5
|
||||
|
||||
// Planes
|
||||
export plane001 = {
|
||||
plane = {
|
||||
origin = [0.0, 0.0, baseHeight - 1.5 + 0.1],
|
||||
xAxis = [1.0, 0.0, 0.0],
|
||||
yAxis = [0.0, 1.0, 0.0],
|
||||
zAxis = [0.0, 0.0, 1.0]
|
||||
}
|
||||
plane = {
|
||||
origin = [0.0, 0.0, baseHeight - 1.5 + 0.1],
|
||||
xAxis = [1.0, 0.0, 0.0],
|
||||
yAxis = [0.0, 1.0, 0.0],
|
||||
zAxis = [0.0, 0.0, 1.0]
|
||||
}
|
||||
}
|
||||
|
||||
export plane002 = {
|
||||
plane = {
|
||||
origin = [0.0, 0.0, 0.0],
|
||||
xAxis = [
|
||||
sin(toRadians(axisJ1)),
|
||||
cos(toRadians(axisJ1)),
|
||||
0.0
|
||||
],
|
||||
yAxis = [0.0, 0.0, 1.0],
|
||||
zAxis = [1.0, 0.0, 0.0]
|
||||
}
|
||||
plane = {
|
||||
origin = [0.0, 0.0, 0.0],
|
||||
xAxis = [
|
||||
sin(toRadians(axisJ1)),
|
||||
cos(toRadians(axisJ1)),
|
||||
0.0
|
||||
],
|
||||
yAxis = [0.0, 0.0, 1.0],
|
||||
zAxis = [1.0, 0.0, 0.0]
|
||||
}
|
||||
}
|
||||
|
||||
// Define Plane to Move J2 Axis Robot Arm
|
||||
export plane003 = {
|
||||
plane = {
|
||||
origin = [-0.1, 0.0, 0.0],
|
||||
xAxis = [
|
||||
sin(toRadians(axisJ1)),
|
||||
cos(toRadians(axisJ1)),
|
||||
0.0
|
||||
],
|
||||
yAxis = [0.0, 0.0, 1.0],
|
||||
zAxis = [1.0, 0.0, 0.0]
|
||||
}
|
||||
}
|
||||
plane = {
|
||||
origin = [-0.1, 0.0, 0.0],
|
||||
xAxis = [
|
||||
sin(toRadians(axisJ1)),
|
||||
cos(toRadians(axisJ1)),
|
||||
0.0
|
||||
],
|
||||
yAxis = [0.0, 0.0, 1.0],
|
||||
zAxis = [1.0, 0.0, 0.0]
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,10 @@
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
import 'robot-arm-base.kcl' as robotArmBase
|
||||
import 'robot-rotating-base.kcl' as rotatingBase
|
||||
import 'robot-arm-j2.kcl' as j2RobotArm
|
||||
import 'robot-arm-j3.kcl' as j3RobotArm
|
||||
import "robot-arm-base.kcl" as robotArmBase
|
||||
import "robot-rotating-base.kcl" as rotatingBase
|
||||
import "robot-arm-j2.kcl" as j2RobotArm
|
||||
import "robot-arm-j3.kcl" as j3RobotArm
|
||||
|
||||
robotArmBase
|
||||
rotatingBase
|
||||
|
@ -1,15 +1,13 @@
|
||||
// Robot Arm Base
|
||||
|
||||
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Import Constants
|
||||
import basePlateRadius, basePlateThickness, baseChamfer, baseHeight from "globals.kcl"
|
||||
|
||||
// Base Plate
|
||||
sketch001 = startSketchOn('XY')
|
||||
sketch001 = startSketchOn(XY)
|
||||
|> startProfileAt([-basePlateRadius, -basePlateRadius], %)
|
||||
|> angledLine([0, 2 * basePlateRadius], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
@ -30,17 +28,14 @@ extrude001 = extrude(sketch001, length = basePlateThickness)
|
||||
getNextAdjacentEdge(rectangleSegmentB001),
|
||||
getNextAdjacentEdge(rectangleSegmentC001),
|
||||
getNextAdjacentEdge(rectangleSegmentD001)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
// Base Motor for actuating first joint
|
||||
sketch002 = startSketchOn(extrude001, 'END')
|
||||
|> circle(center = [0, 0], radius = 4, tag = $referenceEdge)
|
||||
extrude002 = extrude(sketch002, length = baseHeight - basePlateThickness - 1.5)
|
||||
|> fillet(
|
||||
radius = 0.1,
|
||||
tags = [getOppositeEdge(referenceEdge)]
|
||||
)
|
||||
|> fillet(radius = 0.1, tags = [getOppositeEdge(referenceEdge)])
|
||||
sketch003 = startSketchOn(extrude002, 'END')
|
||||
|> circle(center = [0, 0], radius = 0.5)
|
||||
extrude003 = extrude(sketch003, length = 1)
|
||||
@ -52,13 +47,13 @@ sketch4A = startSketchOn(extrude001, 'END')
|
||||
-basePlateRadius + 1,
|
||||
-basePlateRadius + baseChamfer + 0.5
|
||||
],
|
||||
radius = 0.4
|
||||
radius = 0.4,
|
||||
)
|
||||
|> patternCircular2d(
|
||||
arcDegrees = 360,
|
||||
center = [0, 0],
|
||||
instances = 4,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
extrude4A = extrude(sketch4A, length = -basePlateThickness)
|
||||
@ -69,13 +64,13 @@ sketch4B = startSketchOn(extrude001, 'END')
|
||||
-basePlateRadius + 0.5 + baseChamfer,
|
||||
-basePlateRadius + 1
|
||||
],
|
||||
radius = 0.4
|
||||
radius = 0.4,
|
||||
)
|
||||
|> patternCircular2d(
|
||||
arcDegrees = 360,
|
||||
center = [0, 0],
|
||||
instances = 4,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
extrude(sketch4B, length = -basePlateThickness)
|
||||
|
@ -1,10 +1,8 @@
|
||||
// J2 Axis for Robot Arm
|
||||
|
||||
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
import axisJ1, axisJ2, axisJ2ArmWidth, axisJ2ArmLength, axisJ2ArmThickness, plane003 from "globals.kcl"
|
||||
|
||||
// Create Body of J2 Robot Arm
|
||||
@ -35,24 +33,19 @@ sketch012 = startSketchOn(extrude011, 'START')
|
||||
|> circle(center = [-1.75, 8], radius = 1.9, tag = $referenceEdge4)
|
||||
|
||||
extrude012 = extrude(sketch012, length = 0.15)
|
||||
|> fillet(
|
||||
radius = 0.1,
|
||||
tags = [getOppositeEdge(referenceEdge4)]
|
||||
)
|
||||
|> fillet(radius = 0.1, tags = [getOppositeEdge(referenceEdge4)])
|
||||
sketch013 = startSketchOn(extrude011, 'START')
|
||||
|> circle(
|
||||
center = [
|
||||
center = [
|
||||
-1.75 - (axisJ2ArmLength * cos(toRadians(axisJ2))),
|
||||
8 + axisJ2ArmLength * sin(toRadians(axisJ2))
|
||||
],
|
||||
radius = 1.9,
|
||||
tag = $referenceEdge5)
|
||||
radius = 1.9,
|
||||
tag = $referenceEdge5,
|
||||
)
|
||||
|
||||
extrude013 = extrude(sketch013, length = 1)
|
||||
|> fillet(
|
||||
radius = 0.1,
|
||||
tags = [getOppositeEdge(referenceEdge5)]
|
||||
)
|
||||
|> fillet(radius = 0.1, tags = [getOppositeEdge(referenceEdge5)])
|
||||
|
||||
// Draw Bolt Patterns on J2 Robot Arm
|
||||
sketch014 = startSketchOn(extrude012, 'END')
|
||||
@ -61,7 +54,7 @@ sketch014 = startSketchOn(extrude012, 'END')
|
||||
center = [-1.75, 8],
|
||||
instances = 8,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
extrude014 = extrude(sketch014, length = 0.15)
|
||||
@ -72,7 +65,7 @@ sketch015 = startSketchOn(extrude013, 'END')
|
||||
-1.75 - ((axisJ2ArmLength - 1) * cos(toRadians(axisJ2))),
|
||||
8 + (axisJ2ArmLength - 1.5) * sin(toRadians(axisJ2))
|
||||
],
|
||||
radius = 0.2
|
||||
radius = 0.2,
|
||||
)
|
||||
|> patternCircular2d(
|
||||
center = [
|
||||
@ -81,7 +74,7 @@ sketch015 = startSketchOn(extrude013, 'END')
|
||||
],
|
||||
instances = 4,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
extrude015 = extrude(sketch015, length = 0.15)
|
||||
@ -92,7 +85,7 @@ sketch016 = startSketchOn(extrude011, 'END')
|
||||
1.75 + axisJ2ArmLength * cos(toRadians(axisJ2)),
|
||||
8 + axisJ2ArmLength * sin(toRadians(axisJ2))
|
||||
],
|
||||
radius = 0.3
|
||||
radius = 0.3,
|
||||
)
|
||||
|
||||
extrude(sketch016, length = 1)
|
||||
|
@ -1,10 +1,8 @@
|
||||
// J3 Robot Arm
|
||||
|
||||
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
import plane002, axisJ2, axisJ3C, axisJ4, axisJ2ArmLength, axisJ3CArmLength, axisJ3CArmWidth, axisJ3CArmThickness from "globals.kcl"
|
||||
|
||||
// Create Body of J3 Robot Arm
|
||||
@ -38,13 +36,11 @@ sketch018 = startSketchOn(extrude017, 'END')
|
||||
8 + axisJ2ArmLength * sin(toRadians(axisJ2))
|
||||
],
|
||||
radius = 3.7 / 2,
|
||||
tag = $referenceEdge6)
|
||||
tag = $referenceEdge6,
|
||||
)
|
||||
|
||||
extrude018 = extrude(sketch018, length = 0.15)
|
||||
|> fillet(
|
||||
radius = 0.1,
|
||||
tags = [getOppositeEdge(referenceEdge6)]
|
||||
)
|
||||
|> fillet(radius = 0.1, tags = [getOppositeEdge(referenceEdge6)])
|
||||
|
||||
// Draw Bolt Pattern on J3 Robot Arm
|
||||
sketch019 = startSketchOn(extrude018, 'END')
|
||||
@ -53,7 +49,7 @@ sketch019 = startSketchOn(extrude018, 'END')
|
||||
1.75 + (axisJ2ArmLength - 1) * cos(toRadians(axisJ2)),
|
||||
8 + (axisJ2ArmLength - 1.5) * sin(toRadians(axisJ2))
|
||||
],
|
||||
radius = 0.2
|
||||
radius = 0.2,
|
||||
)
|
||||
|> patternCircular2d(
|
||||
center = [
|
||||
@ -62,7 +58,7 @@ sketch019 = startSketchOn(extrude018, 'END')
|
||||
],
|
||||
instances = 8,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
extrude019 = extrude(sketch019, length = 0.15)
|
||||
@ -74,7 +70,7 @@ sketch020 = startSketchOn(extrude017, 'START')
|
||||
-1.75 - (axisJ2ArmLength * cos(toRadians(axisJ2))) - (axisJ3CArmLength * cos(toRadians(axisJ3C))),
|
||||
8 + axisJ2ArmLength * sin(toRadians(axisJ2)) + axisJ3CArmLength * sin(toRadians(axisJ3C))
|
||||
],
|
||||
radius = axisJ3CArmWidth / 2
|
||||
radius = axisJ3CArmWidth / 2,
|
||||
)
|
||||
extrude020 = extrude(sketch020, length = -0.5)
|
||||
|
||||
@ -84,7 +80,7 @@ sketch021 = startSketchOn(extrude017, 'END')
|
||||
1.75 + axisJ2ArmLength * cos(toRadians(axisJ2)) + axisJ3CArmLength * cos(toRadians(axisJ3C)),
|
||||
8 + axisJ2ArmLength * sin(toRadians(axisJ2)) + axisJ3CArmLength * sin(toRadians(axisJ3C))
|
||||
],
|
||||
radius = axisJ3CArmWidth / 2.01
|
||||
radius = axisJ3CArmWidth / 2.01,
|
||||
)
|
||||
|
||||
extrude021 = extrude(sketch021, length = -0.5)
|
||||
|
@ -1,20 +1,15 @@
|
||||
// Robot Rotating Base
|
||||
|
||||
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
import axisJ1, baseHeight, plane001, plane002 from "globals.kcl"
|
||||
|
||||
// Create Rotating Base
|
||||
sketch005 = startSketchOn(plane001)
|
||||
|> circle(center = [0, 0], radius = 3.9, tag = $referenceEdge1)
|
||||
extrude005 = extrude(sketch005, length = 1.5 - 0.1)
|
||||
|> fillet(
|
||||
radius = 0.1,
|
||||
tags = [getOppositeEdge(referenceEdge1)]
|
||||
)
|
||||
|> fillet(radius = 0.1, tags = [getOppositeEdge(referenceEdge1)])
|
||||
|> appearance(color = "#4f7d54", metalness = 90, roughness = 90)
|
||||
|
||||
sketch006 = startSketchOn(plane002)
|
||||
@ -38,12 +33,10 @@ sketch007 = startSketchOn(extrude006, 'END')
|
||||
8
|
||||
],
|
||||
radius = 2.75,
|
||||
tag = $referenceEdge2)
|
||||
extrude007 = extrude(sketch007, length = 1.5)
|
||||
|> fillet(
|
||||
radius = 0.1,
|
||||
tags = [getOppositeEdge(referenceEdge2)]
|
||||
tag = $referenceEdge2,
|
||||
)
|
||||
extrude007 = extrude(sketch007, length = 1.5)
|
||||
|> fillet(radius = 0.1, tags = [getOppositeEdge(referenceEdge2)])
|
||||
|
||||
// Draw Bolt Pattern on Rotating Base
|
||||
sketch008 = startSketchOn(extrude007, 'END')
|
||||
@ -52,7 +45,7 @@ sketch008 = startSketchOn(extrude007, 'END')
|
||||
1.75 * cos(toRadians(axisJ1)) / abs(cos(toRadians(axisJ1))),
|
||||
6.75
|
||||
],
|
||||
radius = 0.2
|
||||
radius = 0.2,
|
||||
)
|
||||
|> patternCircular2d(
|
||||
center = [
|
||||
@ -61,7 +54,7 @@ sketch008 = startSketchOn(extrude007, 'END')
|
||||
],
|
||||
instances = 4,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
extrude008 = extrude(sketch008, length = 0.2)
|
||||
|
||||
@ -72,12 +65,10 @@ sketch009 = startSketchOn(extrude007, 'END')
|
||||
8
|
||||
],
|
||||
radius = 0.5,
|
||||
tag = $referenceEdge3)
|
||||
extrude009 = extrude(sketch009, length = 0.15)
|
||||
|> fillet(
|
||||
radius = 0.1,
|
||||
tags = [getOppositeEdge(referenceEdge3)]
|
||||
tag = $referenceEdge3,
|
||||
)
|
||||
extrude009 = extrude(sketch009, length = 0.15)
|
||||
|> fillet(radius = 0.1, tags = [getOppositeEdge(referenceEdge3)])
|
||||
|> appearance(color = "#4f7d54", metalness = 90, roughness = 90)
|
||||
|
||||
sketch010 = startSketchOn(plane002)
|
||||
|
@ -1,16 +1,16 @@
|
||||
// 1120t74 Pipe
|
||||
|
||||
// import constants
|
||||
import pipeInnerDiameter, pipeOuterDiameter, pipeLength from "globals.kcl"
|
||||
// Pipe
|
||||
// piping for the pipe flange assembly
|
||||
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// import constants
|
||||
import pipeInnerDiameter, pipeOuterDiameter, pipeLength from "globals.kcl"
|
||||
|
||||
// create a function to make the pipe
|
||||
export fn pipe() {
|
||||
|
||||
// create the pipe base
|
||||
pipeBase = startSketchOn('XZ')
|
||||
pipeBase = startSketchOn(XZ)
|
||||
|> circle(%, center = [0, 0], radius = pipeOuterDiameter / 2)
|
||||
|> extrude(%, length = pipeLength)
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
// 68095k348 flange
|
||||
|
||||
// import constants
|
||||
import pipeDiameter, mountingHoleDiameter, mountingHolePlacementDiameter, flangeDiameter, flangeTotalThickness, flangeBackHeight, flangeFrontHeight, flangeBaseThickness, flangeBackDiameter, flangeFrontDiameter from "globals.kcl"
|
||||
// flange used for mating two pipes together in the pipe flange assembly.
|
||||
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// import constants
|
||||
import pipeDiameter, mountingHoleDiameter, mountingHolePlacementDiameter, flangeDiameter, flangeTotalThickness, flangeBackHeight, flangeFrontHeight, flangeBaseThickness, flangeBackDiameter, flangeFrontDiameter from "globals.kcl"
|
||||
|
||||
// create a function to create the flange
|
||||
export fn flange() {
|
||||
|
||||
// sketch the mounting hole pattern
|
||||
mountingHoles = startSketchOn("XY")
|
||||
mountingHoles = startSketchOn(XY)
|
||||
|> circle(%, center = [0, mountingHolePlacementDiameter / 2], radius = mountingHoleDiameter / 2)
|
||||
|> patternCircular2d(
|
||||
%,
|
||||
@ -21,7 +21,7 @@ export fn flange() {
|
||||
)
|
||||
|
||||
// create the flange base
|
||||
flangeBase = startSketchOn("XY")
|
||||
flangeBase = startSketchOn(XY)
|
||||
|> circle(%, center = [0, 0], radius = flangeDiameter / 2)
|
||||
|> hole(mountingHoles, %)
|
||||
|> extrude(%, length = flangeBaseThickness)
|
||||
|
@ -1,16 +1,17 @@
|
||||
// 91251A404 Socket Head Cap Screw
|
||||
|
||||
// import constants
|
||||
import boltDiameter, boltLength, boltHeadLength, boltHeadDiameter, boltHexDrive, boltHexFlatLength, boltThreadLength from "globals.kcl"
|
||||
// screw for mating the flanges together in the pipe flange assembly
|
||||
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// import constants
|
||||
import boltDiameter, boltLength, boltHeadLength, boltHeadDiameter, boltHexDrive, boltHexFlatLength, boltThreadLength from "globals.kcl"
|
||||
|
||||
// create a function to make a the bolt
|
||||
export fn bolt() {
|
||||
|
||||
// Create the head of the cap screw
|
||||
boltHead = startSketchOn('XZ')
|
||||
boltHead = startSketchOn(XZ)
|
||||
|> circle(center = [0, 0], radius = boltHeadDiameter / 2, tag = $topEdge)
|
||||
|> extrude(length = -boltHeadLength)
|
||||
|> fillet(radius = 0.020, tags = [topEdge, getOppositeEdge(topEdge)])
|
||||
|
@ -1,16 +1,16 @@
|
||||
// 9472K188 Gasket
|
||||
|
||||
// import constants
|
||||
import gasketOutsideDiameter, gasketInnerDiameter, gasketThickness from "globals.kcl"
|
||||
// gasket for the pipe flange assembly. A gasket is a mechanical seal that fills the space between two or more mating surfaces, preventing leaks of liquids or gases under compression
|
||||
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// import constants
|
||||
import gasketOutsideDiameter, gasketInnerDiameter, gasketThickness from "globals.kcl"
|
||||
|
||||
// create a function to make the gasket
|
||||
export fn gasket() {
|
||||
|
||||
// create the base of the gasket
|
||||
gasketBase = startSketchOn("XY")
|
||||
gasketBase = startSketchOn(XY)
|
||||
|> circle(%, center = [0, 0], radius = gasketOutsideDiameter / 2)
|
||||
|> extrude(%, length = gasketThickness)
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
// 95479A127 Hex Nut
|
||||
|
||||
// import constants
|
||||
import hexNutDiameter, hexNutFlatToFlat, hexNutThickness, hexNutFlatLength from "globals.kcl"
|
||||
// hex nut for the screws in the pipe flange assembly.
|
||||
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// import constants
|
||||
import hexNutDiameter, hexNutFlatToFlat, hexNutThickness, hexNutFlatLength from "globals.kcl"
|
||||
|
||||
// create a function to make the hex nut
|
||||
export fn hexNut() {
|
||||
|
||||
// create the base of the hex nut
|
||||
hexNutBase = startSketchOn('XY')
|
||||
hexNutBase = startSketchOn(XY)
|
||||
|> startProfileAt([
|
||||
hexNutFlatToFlat / 2,
|
||||
hexNutFlatLength / 2
|
||||
|