This commit is contained in:
Kurt Hutten Irev-Dev
2024-08-14 14:05:22 +10:00
parent c17f0ab04f
commit 7e0efaa254
4 changed files with 335 additions and 2 deletions

View File

@ -0,0 +1,150 @@
// A mounting bracket for the Focusrite Scarlett Solo audio interface
// This is a bracket that holds an audio device underneath a desk or shelf. The audio device has dimensions of 144mm wide, 80mm length and 45mm depth with fillets of 6mm. This mounting bracket is designed to be 3D printed with PLA material
// define constants in mm
const radius = 6.0
const width = 144.0
const length = 80.0
const depth = 45.0
const thk = 4
const holeDiam = 5
const tabLength = 25
const tabWidth = 12
const tabThk = 4
// define a rectangular shape func
fn rectShape = (pos, w, l) => {
const rr = startSketchOn('xy')
|> startProfileAt([pos[0] - (w / 2), pos[1] - (l / 2)], %)
|> lineTo([pos[0] + w / 2, pos[1] - (l / 2)], %, $edge01)
|> lineTo([pos[0] + w / 2, pos[1] + l / 2], %, $edge02)
|> lineTo([pos[0] - (w / 2), pos[1] + l / 2], %, $edge03)
|> close(%, $edge04)
return rr
}
// define the bracket plane
const bracketPlane = {
plane: {
origin: { x: 0, y: length / 2 + thk, z: 0 },
xAxis: { x: 1, y: 0, z: 0 },
yAxis: { x: 0, y: 0, z: 1 },
zAxis: { x: 0, y: -1, z: 0 }
}
}
// build the bracket sketch around the body
fn bracketSketch = (w, d, t) => {
const s = startSketchOn(bracketPlane)
|> startProfileAt([-w / 2 - t, d + t], %)
|> lineTo([-w / 2 - t, -t], %, $edge1)
|> lineTo([w / 2 + t, -t], %, $edge2)
|> lineTo([w / 2 + t, d + t], %, $edge3)
|> lineTo([w / 2, d + t], %, $edge4)
|> lineTo([w / 2, 0], %, $edge5)
|> lineTo([-w / 2, 0], %, $edge6)
|> lineTo([-w / 2, d + t], %, $edge7)
|> close(%, $edge8)
return s
}
// build the body of the bracket
const bs = bracketSketch(width, depth, thk)
const bracketBody = bs
|> extrude(length + 2 * thk, %)
|> fillet({
radius: radius,
tags: [
getNextAdjacentEdge(bs.tags.edge7),
getNextAdjacentEdge(bs.tags.edge2),
getNextAdjacentEdge(bs.tags.edge3),
getNextAdjacentEdge(bs.tags.edge6)
]
}, %)
// define the tab plane
const tabPlane = {
plane: {
origin: { x: 0, y: 0, z: depth + thk },
xAxis: { x: 1, y: 0, z: 0 },
yAxis: { x: 0, y: 1, z: 0 },
zAxis: { x: 0, y: 0, z: 1 }
}
}
// build the tabs of the mounting bracket (right side)
const tabsR = startSketchOn(tabPlane)
|> startProfileAt([width / 2 + thk, length / 2 + thk], %)
|> line([tabWidth, -tabLength / 3], %, $edge11)
|> line([0, -tabLength / 3 * 2], %, $edge12)
|> line([-tabWidth, -tabLength / 3], %, $edge13)
|> close(%, $edge14)
|> hole(circle([
width / 2 + thk + tabWidth / 2,
length / 2 + thk - (tabLength / (3 / 2))
], holeDiam / 2, %), %)
|> extrude(-tabThk, %)
|> fillet({
radius: holeDiam / 2,
tags: [
getNextAdjacentEdge(edge12),
getNextAdjacentEdge(edge13)
]
}, %)
|> patternLinear3d({
axis: [0, -1, 0],
repetitions: 1,
distance: length + 2 * thk - (tabLength * 4 / 3)
}, %)
// build the tabs of the mounting bracket (left side)
const tabsL = startSketchOn(tabPlane)
|> startProfileAt([-width / 2 - thk, length / 2 + thk], %)
|> line([-tabWidth, -tabLength / 3], %, $edge21)
|> line([0, -tabLength / 3 * 2], %, $edge22)
|> line([tabWidth, -tabLength / 3], %, $edge23)
|> close(%, $edge24)
|> hole(circle([
-width / 2 - thk - (tabWidth / 2),
length / 2 + thk - (tabLength / (3 / 2))
], holeDiam / 2, %), %)
|> extrude(-tabThk, %)
|> fillet({
radius: holeDiam / 2,
tags: [
getNextAdjacentEdge(edge21),
getNextAdjacentEdge(edge22)
]
}, %)
|> patternLinear3d({
axis: [0, -1, 0],
repetitions: 1,
distance: length + 2 * thk - (tabLength * 4 / 3)
}, %)
// define a plane for retention bumps
const retPlane = {
plane: {
origin: { x: -width / 2 + 20, y: 0, z: 0 },
xAxis: { x: 0, y: 1, z: 0 },
yAxis: { x: 0, y: 0, z: 1 },
zAxis: { x: 1, y: 0, z: 0 }
}
}
// build the retention bump in the front
const retFront = startSketchOn(retPlane)
|> startProfileAt([-length / 2 - thk, 0], %)
|> line([0, thk], %)
|> line([thk, -thk], %)
|> close(%)
|> extrude(width - 40, %)
// build the retention bump in the back
const retBack = startSketchOn(retPlane)
|> startProfileAt([length / 2 + thk, 0], %)
|> line([0, thk], %)
|> line([-thk, 0], %)
|> line([0, -thk], %)
|> close(%)
|> extrude(width - 40, %)

View File

@ -0,0 +1,70 @@
const routerDiameter = 12.7
const mmInInch = 25.4
const templateDiameter = mmInInch * 11 / 16
const templateGap = ((templateDiameter - routerDiameter) / 2) -0.5
const slateWidthHalf = 41.5 / 2
const minClampingDistance = 50 + 30
const templateThickness = 10
const radius = 10
const depth = 30
const length001 = slateWidthHalf - radius
const length002 = depth + minClampingDistance
const sketch001 = startSketchOn('XZ')
|> startProfileAt([0, depth - templateGap], %)
|> xLine(length001, %, $seg01)
|> arc({
angle_end: 0,
angle_start: 90,
radius: radius - templateGap
}, %)
|> yLineTo(-templateGap * 2 - (templateDiameter / 2), %, $seg05)
|> xLineTo(slateWidthHalf + templateThickness, %, $seg04)
|> yLine(-length002, %, $seg03)
|> xLineTo(0, %, $seg02)
// |> line([7.78, 11.16], %)
|> xLine(-segLen(seg02, %), %)
|> yLine(segLen(seg03, %), %)
|> xLine(segLen(seg04, %), %)
|> yLine(segLen(seg05, %), %)
|> arc({
angle_end: 90,
angle_start: 180,
radius: radius - templateGap
}, %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
const extrude001 = extrude(5, sketch001)
const sketch002 = startSketchOn(extrude001, 'START')
|> startProfileAt([
-slateWidthHalf,
-templateGap * 2 - (templateDiameter / 2)
], %)
|> xLine(-7, %, $rectangleSegmentA001)
|> angledLine([
segAng(rectangleSegmentA001, %) + 90,
minClampingDistance
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001, %),
-segLen(rectangleSegmentA001, %)
], %, $rectangleSegmentC001)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
const extrude002 = extrude(7.5, sketch002)
const sketch003 = startSketchOn(extrude001, 'START')
|> startProfileAt([
slateWidthHalf,
-templateGap * 2 - (templateDiameter / 2)
], %)
|> xLine(7, %, $rectangleSegmentA002)
|> angledLine([
segAng(rectangleSegmentA002, %) - 90,
minClampingDistance
], %)
|> angledLine([
segAng(rectangleSegmentA002, %),
-segLen(rectangleSegmentA002, %)
], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
const extrude003 = extrude(7.5, sketch003)

View File

@ -1,5 +1,6 @@
import { test, expect } from '@playwright/test' import { test, expect } from '@playwright/test'
import { getUtils, setupElectron, tearDown } from './test-utils' import { getUtils, setupElectron, tearDown } from './test-utils'
import fsp from 'fs/promises'
test.afterEach(async ({ page }, testInfo) => { test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo) await tearDown(page, testInfo)
@ -55,7 +56,8 @@ const extrude001 = extrude(200, sketch001)`)
const pointOnModel = { x: 660, y: 250 } const pointOnModel = { x: 660, y: 250 }
// check the model loaded by checking it's grey // gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [132, 132, 132]), { .poll(() => u.getGreatestPixDiff(pointOnModel, [132, 132, 132]), {
timeout: 10_000, timeout: 10_000,
@ -92,3 +94,114 @@ const extrude001 = extrude(200, sketch001)`)
await electronApp.close() await electronApp.close()
} }
) )
test(
'Check you can go home with two different methods, and that switching between projects does not harm the stream',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
browserName === 'webkit',
'Skip on Safari because `window.tearDown` does not work'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await Promise.all([
fsp.mkdir(`${dir}/router-template-slate`, { recursive: true }),
fsp.mkdir(`${dir}/bracket`, { recursive: true }),
])
await Promise.all([
fsp.copyFile(
'e2e/playwright/kcl-samples/router-template-slate.kcl',
`${dir}/router-template-slate/main.kcl`
),
fsp.copyFile(
'e2e/playwright/kcl-samples/bracket.kcl',
`${dir}/bracket/main.kcl`
),
])
},
})
const u = await getUtils(page)
await page.goto('http://localhost:3000/')
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
const pointOnModel = { x: 630, y: 280 }
await test.step('Opening the bracket project should load the stream', async () => {
// expect to see the text bracket
await expect(page.getByText('bracket')).toBeVisible()
await page.getByText('bracket').click()
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [75, 75, 75]), {
timeout: 10_000,
})
.toBeLessThan(10)
})
await test.step('Clicking the logo takes us back to the projects page / home', async () => {
await page.getByTestId('app-logo').click()
await expect(page.getByText('bracket')).toBeVisible()
await expect(page.getByText('router-template-slate')).toBeVisible()
await expect(page.getByText('New Project')).toBeVisible()
})
await test.step('Opening the router-template project should load the stream', async () => {
// expect to see the text bracket
await expect(page.getByText('router-template-slate')).toBeVisible()
await page.getByText('router-template-slate').click()
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [132, 132, 132]), {
timeout: 10_000,
})
.toBeLessThan(10)
})
await test.step('Opening the router-template project should load the stream', async () => {
await page.getByTestId('project-sidebar-toggle').click()
await expect(
page.getByRole('button', { name: 'Go to Home' })
).toBeVisible()
await page.getByRole('button', { name: 'Go to Home' }).click()
await expect(page.getByText('bracket')).toBeVisible()
await expect(page.getByText('router-template-slate')).toBeVisible()
await expect(page.getByText('New Project')).toBeVisible()
})
await electronApp.close()
}
)

View File

@ -714,7 +714,7 @@ export async function setupElectron({
}) })
await fsp.writeFile(tempSettingsFilePath, settingsOverrides) await fsp.writeFile(tempSettingsFilePath, settingsOverrides)
await folderSetupFn?.(tempSettingsFilePath) await folderSetupFn?.(projectDirName)
await setup(context, page, projectDirName) await setup(context, page, projectDirName)