client side sketch scene not respecting base-unit-scale (#1576)

* client side sketch scene not respecting base-unit-scale

* test tweak

* remove dead code

* fix test

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* test fix up

* trigger ci

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* trigger ci

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Kurt Hutten
2024-03-01 06:55:49 +11:00
committed by GitHub
parent 2ca6ba52b6
commit 1cab3e628f
12 changed files with 289 additions and 41 deletions

View File

@ -3,6 +3,7 @@ import { secrets } from './secrets'
import { getUtils } from './test-utils' import { getUtils } from './test-utils'
import waitOn from 'wait-on' import waitOn from 'wait-on'
import { Themes } from '../../src/lib/theme' import { Themes } from '../../src/lib/theme'
import { roundOff } from 'lib/utils'
/* /*
debug helper: unfortunately we do rely on exact coord mouse clicks in a few places debug helper: unfortunately we do rely on exact coord mouse clicks in a few places
@ -15,9 +16,9 @@ document.addEventListener('mousemove', (e) =>
*/ */
const commonPoints = { const commonPoints = {
startAt: '[26.38, -35.59]', startAt: '[0.93, -1.26]',
num1: 26.63, num1: 0.95,
num2: 53.01, num2: 1.88,
} }
test.beforeEach(async ({ context, page }) => { test.beforeEach(async ({ context, page }) => {
@ -101,13 +102,13 @@ test('Basic sketch', async ({ page }) => {
.toHaveText(`const part001 = startSketchOn('-XZ') .toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %) |> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %) |> line([${commonPoints.num1}, 0], %)
|> line([0, ${commonPoints.num1}], %)`) |> line([0, ${commonPoints.num1 - 0.01}], %)`)
await page.mouse.click(startXPx, 500 - PUR * 20) await page.mouse.click(startXPx, 500 - PUR * 20)
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ') .toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %) |> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %) |> line([${commonPoints.num1}, 0], %)
|> line([0, ${commonPoints.num1}], %) |> line([0, ${commonPoints.num1 - 0.01}], %)
|> line([-${commonPoints.num2}, 0], %)`) |> line([-${commonPoints.num2}, 0], %)`)
// deselect line tool // deselect line tool
@ -132,7 +133,7 @@ test('Basic sketch', async ({ page }) => {
.toHaveText(`const part001 = startSketchOn('-XZ') .toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %) |> startProfileAt(${commonPoints.startAt}, %)
|> line({ to: [${commonPoints.num1}, 0], tag: 'seg01' }, %) |> line({ to: [${commonPoints.num1}, 0], tag: 'seg01' }, %)
|> line([0, ${commonPoints.num1}], %) |> line([0, ${commonPoints.num1 - 0.01}], %)
|> angledLine([180, segLen('seg01', %)], %)`) |> angledLine([180, segLen('seg01', %)], %)`)
}) })
@ -284,10 +285,9 @@ test('Can create sketches on all planes and their back sides', async ({
}) => { }) => {
await u.openDebugPanel() await u.openDebugPanel()
await u.updateCamPosition(viewCmd)
await u.clearCommandLogs() await u.clearCommandLogs()
await page.getByRole('button', { name: 'Start Sketch' }).click() await page.getByRole('button', { name: 'Start Sketch' }).click()
await u.updateCamPosition(viewCmd)
await u.closeDebugPanel() await u.closeDebugPanel()
await page.mouse.click(clickCoords.x, clickCoords.y) await page.mouse.click(clickCoords.x, clickCoords.y)
@ -315,7 +315,7 @@ test('Can create sketches on all planes and their back sides', async ({
const codeTemplate = ( const codeTemplate = (
plane = 'XY' plane = 'XY'
) => `const part001 = startSketchOn('${plane}') ) => `const part001 = startSketchOn('${plane}')
|> startProfileAt([32.13, -43.34], %)` |> startProfileAt([1.14, -1.54], %)`
await TestSinglePlane({ await TestSinglePlane({
viewCmd: camPos, viewCmd: camPos,
expectedCode: codeTemplate('XY'), expectedCode: codeTemplate('XY'),
@ -325,7 +325,7 @@ test('Can create sketches on all planes and their back sides', async ({
await TestSinglePlane({ await TestSinglePlane({
viewCmd: camPos, viewCmd: camPos,
expectedCode: codeTemplate('YZ'), expectedCode: codeTemplate('YZ'),
clickCoords: { x: 700, y: 300 }, // green plane clickCoords: { x: 700, y: 250 }, // green plane
}) })
await TestSinglePlane({ await TestSinglePlane({
viewCmd: camPos, viewCmd: camPos,
@ -488,13 +488,13 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
.toHaveText(`const part001 = startSketchOn('-XZ') .toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %) |> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %) |> line([${commonPoints.num1}, 0], %)
|> line([0, ${commonPoints.num1}], %)`) |> line([0, ${commonPoints.num1 - 0.01}], %)`)
await page.mouse.click(startXPx, 500 - PUR * 20) await page.mouse.click(startXPx, 500 - PUR * 20)
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ') .toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %) |> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %) |> line([${commonPoints.num1}, 0], %)
|> line([0, ${commonPoints.num1}], %) |> line([0, ${commonPoints.num1 - 0.01}], %)
|> line([-${commonPoints.num2}, 0], %)`) |> line([-${commonPoints.num2}, 0], %)`)
// deselect line tool // deselect line tool
@ -765,12 +765,12 @@ test('Can add multiple sketches', async ({ page }) => {
.toHaveText(`const part001 = startSketchOn('-XZ') .toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %) |> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %) |> line([${commonPoints.num1}, 0], %)
|> line([0, ${commonPoints.num1}], %)`) |> line([0, ${commonPoints.num1 - 0.01}], %)`)
await page.mouse.click(startXPx, 500 - PUR * 20) await page.mouse.click(startXPx, 500 - PUR * 20)
const finalCodeFirstSketch = `const part001 = startSketchOn('-XZ') const finalCodeFirstSketch = `const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %) |> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %) |> line([${commonPoints.num1}, 0], %)
|> line([0, ${commonPoints.num1}], %) |> line([0, ${commonPoints.num1 - 0.01}], %)
|> line([-${commonPoints.num2}, 0], %)` |> line([-${commonPoints.num2}, 0], %)`
await expect(page.locator('.cm-content')).toHaveText(finalCodeFirstSketch) await expect(page.locator('.cm-content')).toHaveText(finalCodeFirstSketch)
@ -793,7 +793,7 @@ test('Can add multiple sketches', async ({ page }) => {
await u.clearAndCloseDebugPanel() await u.clearAndCloseDebugPanel()
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
const startAt2 = '[26.23, -35.39]' const startAt2 = '[0.93,-1.25]'
await expect( await expect(
(await page.locator('.cm-content').innerText()).replace(/\s/g, '') (await page.locator('.cm-content').innerText()).replace(/\s/g, '')
).toBe( ).toBe(
@ -807,7 +807,7 @@ const part002 = startSketchOn('XY')
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10) await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(100) await page.waitForTimeout(100)
const num2 = 26.48 const num2 = 0.94
await expect( await expect(
(await page.locator('.cm-content').innerText()).replace(/\s/g, '') (await page.locator('.cm-content').innerText()).replace(/\s/g, '')
).toBe( ).toBe(
@ -825,7 +825,7 @@ const part002 = startSketchOn('XY')
const part002 = startSketchOn('XY') const part002 = startSketchOn('XY')
|> startProfileAt(${startAt2}, %) |> startProfileAt(${startAt2}, %)
|> line([${num2}, 0], %) |> line([${num2}, 0], %)
|> line([0, ${num2}], %)`.replace(/\s/g, '') |> line([0, ${roundOff(num2 - 0.01)}], %)`.replace(/\s/g, '')
) )
await page.mouse.click(startXPx, 500 - PUR * 20) await page.mouse.click(startXPx, 500 - PUR * 20)
await expect( await expect(
@ -835,8 +835,8 @@ const part002 = startSketchOn('XY')
const part002 = startSketchOn('XY') const part002 = startSketchOn('XY')
|> startProfileAt(${startAt2}, %) |> startProfileAt(${startAt2}, %)
|> line([${num2}, 0], %) |> line([${num2}, 0], %)
|> line([0, ${num2}], %) |> line([0, ${roundOff(num2 - 0.01)}], %)
|> line([-52.71, 0], %)`.replace(/\s/g, '') |> line([-1.87, 0], %)`.replace(/\s/g, '')
) )
}) })

View File

@ -435,7 +435,23 @@ test('extrude on each default plane should be stable', async ({
await runSnapshotsForOtherPlanes('-YZ') await runSnapshotsForOtherPlanes('-YZ')
}) })
test('Draft segments should look right', async ({ page }) => { test('Draft segments should look right', async ({ page, context }) => {
await context.addInitScript(async () => {
localStorage.setItem(
'SETTINGS_PERSIST_KEY',
JSON.stringify({
baseUnit: 'in',
cameraControls: 'KittyCAD',
defaultDirectory: '',
defaultProjectName: 'project-$nnn',
onboardingStatus: 'dismissed',
showDebugPanel: true,
textWrapping: 'On',
theme: 'system',
unitSystem: 'imperial',
})
)
})
const u = getUtils(page) const u = getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setViewportSize({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio const PUR = 400 / 37.5 //pixeltoUnitRatio
@ -468,7 +484,7 @@ test('Draft segments should look right', async ({ page }) => {
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ') .toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)`) |> startProfileAt([0.93, -1.26], %)`)
await page.waitForTimeout(100) await page.waitForTimeout(100)
await u.closeDebugPanel() await u.closeDebugPanel()
@ -482,8 +498,8 @@ test('Draft segments should look right', async ({ page }) => {
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ') .toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %) |> startProfileAt([0.93, -1.26], %)
|> line([${commonPoints.num1}, 0], %)`) |> line([0.95, 0], %)`)
await page.getByRole('button', { name: 'Tangential Arc' }).click() await page.getByRole('button', { name: 'Tangential Arc' }).click()
@ -493,3 +509,195 @@ test('Draft segments should look right', async ({ page }) => {
maxDiffPixels: 100, maxDiffPixels: 100,
}) })
}) })
test('Client side scene scale should match engine scale inch', async ({
page,
context,
}) => {
await context.addInitScript(async () => {
localStorage.setItem(
'SETTINGS_PERSIST_KEY',
JSON.stringify({
baseUnit: 'in',
cameraControls: 'KittyCAD',
defaultDirectory: '',
defaultProjectName: 'project-$nnn',
onboardingStatus: 'dismissed',
showDebugPanel: true,
textWrapping: 'On',
theme: 'system',
unitSystem: 'imperial',
})
)
})
const u = getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.goto('/')
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await expect(page.getByRole('button', { name: 'Start Sketch' })).toBeVisible()
// click on "Start Sketch" button
await u.clearCommandLogs()
await u.doAndWaitForImageDiff(
() => page.getByRole('button', { name: 'Start Sketch' }).click(),
200
)
// select a plane
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`const part001 = startSketchOn('-XZ')`
)
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([0.93, -1.26], %)`)
await page.waitForTimeout(100)
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(100)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([0.93, -1.26], %)
|> line([0.95, 0], %)`)
await page.getByRole('button', { name: 'Tangential Arc' }).click()
await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([0.93, -1.26], %)
|> line([0.95, 0], %)
|> tangentialArcTo([2.82, -0.32], %)`)
// screen shot should show the sketch
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
})
// exit sketch
await u.openAndClearDebugPanel()
await page.getByRole('button', { name: 'Exit Sketch' }).click()
// wait for execution done
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.clearAndCloseDebugPanel()
await page.waitForTimeout(200)
// second screen shot should look almost identical, i.e. scale should be the same.
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
})
})
test('Client side scene scale should match engine scale mm', async ({
page,
context,
}) => {
await context.addInitScript(async () => {
localStorage.setItem(
'SETTINGS_PERSIST_KEY',
JSON.stringify({
baseUnit: 'mm',
cameraControls: 'KittyCAD',
defaultDirectory: '',
defaultProjectName: 'project-$nnn',
onboardingStatus: 'dismissed',
showDebugPanel: true,
textWrapping: 'On',
theme: 'system',
unitSystem: 'metric',
})
)
})
const u = getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.goto('/')
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await expect(page.getByRole('button', { name: 'Start Sketch' })).toBeVisible()
// click on "Start Sketch" button
await u.clearCommandLogs()
await u.doAndWaitForImageDiff(
() => page.getByRole('button', { name: 'Start Sketch' }).click(),
200
)
// select a plane
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`const part001 = startSketchOn('-XZ')`
)
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([0.93, -1.26], %)`)
await page.waitForTimeout(100)
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(100)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([0.93, -1.26], %)
|> line([0.95, 0], %)`)
await page.getByRole('button', { name: 'Tangential Arc' }).click()
await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([0.93, -1.26], %)
|> line([0.95, 0], %)
|> tangentialArcTo([2.82, -0.32], %)`)
// screen shot should show the sketch
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
})
// exit sketch
await u.openAndClearDebugPanel()
await page.getByRole('button', { name: 'Exit Sketch' }).click()
// wait for execution done
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.clearAndCloseDebugPanel()
await page.waitForTimeout(200)
// second screen shot should look almost identical, i.e. scale should be the same.
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
})
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -220,6 +220,7 @@ export class CameraControls {
this.onWindowResize() this.onWindowResize()
this.update() this.update()
this._usePerspectiveCamera()
} }
private _isCamMovingCallback: (isMoving: boolean, isTween: boolean) => void = private _isCamMovingCallback: (isMoving: boolean, isTween: boolean) => void =
@ -373,7 +374,7 @@ export class CameraControls {
return this.camera return this.camera
} }
usePerspectiveCamera = () => { _usePerspectiveCamera = () => {
const { x: px, y: py, z: pz } = this.camera.position const { x: px, y: py, z: pz } = this.camera.position
const { x: qx, y: qy, z: qz, w: qw } = this.camera.quaternion const { x: qx, y: qy, z: qz, w: qw } = this.camera.quaternion
const zoom = this.camera.zoom const zoom = this.camera.zoom
@ -389,14 +390,17 @@ export class CameraControls {
) )
direction.normalize() direction.normalize()
this.camera.position.copy(this.target).addScaledVector(direction, distance) this.camera.position.copy(this.target).addScaledVector(direction, distance)
}
usePerspectiveCamera = () => {
this._usePerspectiveCamera()
engineCommandManager.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
type: 'default_camera_set_perspective', type: 'default_camera_set_perspective',
parameters: { parameters: {
fov_y: this.camera.fov, fov_y:
this.camera instanceof PerspectiveCamera ? this.camera.fov : 45,
...calculateNearFarFromFOV(this.lastPerspectiveFov), ...calculateNearFarFromFOV(this.lastPerspectiveFov),
}, },
}, },

View File

@ -106,9 +106,10 @@ class SceneEntities {
Object.values(this.activeSegments).forEach((segment) => { Object.values(this.activeSegments).forEach((segment) => {
const factor = const factor =
sceneInfra.camControls.camera instanceof OrthographicCamera (sceneInfra.camControls.camera instanceof OrthographicCamera
? orthoFactor ? orthoFactor
: perspScale(sceneInfra.camControls.camera, segment) : perspScale(sceneInfra.camControls.camera, segment)) /
sceneInfra._baseUnitMultiplier
if ( if (
segment.userData.from && segment.userData.from &&
segment.userData.to && segment.userData.to &&
@ -143,9 +144,9 @@ class SceneEntities {
? orthoFactor ? orthoFactor
: perspScale(sceneInfra.camControls.camera, this.axisGroup) : perspScale(sceneInfra.camControls.camera, this.axisGroup)
const x = this.axisGroup.getObjectByName(X_AXIS) const x = this.axisGroup.getObjectByName(X_AXIS)
x?.scale.set(1, factor, 1) x?.scale.set(1, factor / sceneInfra._baseUnitMultiplier, 1)
const y = this.axisGroup.getObjectByName(Y_AXIS) const y = this.axisGroup.getObjectByName(Y_AXIS)
y?.scale.set(factor, 1, 1) y?.scale.set(factor / sceneInfra._baseUnitMultiplier, 1, 1)
} }
} }
@ -169,6 +170,7 @@ class SceneEntities {
this.scene.add(this.intersectionPlane) this.scene.add(this.intersectionPlane)
} }
createSketchAxis(sketchPathToNode: PathToNode) { createSketchAxis(sketchPathToNode: PathToNode) {
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
const baseXColor = 0x000055 const baseXColor = 0x000055
const baseYColor = 0x550000 const baseYColor = 0x550000
const xAxisGeometry = new BoxGeometry(100000, 0.3, 0.01) const xAxisGeometry = new BoxGeometry(100000, 0.3, 0.01)
@ -208,6 +210,14 @@ class SceneEntities {
sceneInfra.camControls.target sceneInfra.camControls.target
) )
gridHelper.scale.set(sceneScale, sceneScale, sceneScale) gridHelper.scale.set(sceneScale, sceneScale, sceneScale)
const factor =
sceneInfra.camControls.camera instanceof OrthographicCamera
? orthoFactor
: perspScale(sceneInfra.camControls.camera, this.axisGroup)
xAxisMesh?.scale.set(1, factor / sceneInfra._baseUnitMultiplier, 1)
yAxisMesh?.scale.set(factor / sceneInfra._baseUnitMultiplier, 1, 1)
this.axisGroup.add(xAxisMesh, yAxisMesh, gridHelper) this.axisGroup.add(xAxisMesh, yAxisMesh, gridHelper)
this.currentSketchQuaternion && this.currentSketchQuaternion &&
this.axisGroup.setRotationFromQuaternion(this.currentSketchQuaternion) this.axisGroup.setRotationFromQuaternion(this.currentSketchQuaternion)
@ -279,9 +289,10 @@ class SceneEntities {
) )
const orthoFactor = orthoScale(sceneInfra.camControls.camera) const orthoFactor = orthoScale(sceneInfra.camControls.camera)
const factor = const factor =
sceneInfra.camControls.camera instanceof OrthographicCamera (sceneInfra.camControls.camera instanceof OrthographicCamera
? orthoFactor ? orthoFactor
: perspScale(sceneInfra.camControls.camera, dummy) : perspScale(sceneInfra.camControls.camera, dummy)) /
sceneInfra._baseUnitMultiplier
sketchGroup.value.forEach((segment, index) => { sketchGroup.value.forEach((segment, index) => {
let segPathToNode = getNodePathFromSourceRange( let segPathToNode = getNodePathFromSourceRange(
draftSegment ? truncatedAst : kclManager.ast, draftSegment ? truncatedAst : kclManager.ast,
@ -404,7 +415,7 @@ class SceneEntities {
const isClosingSketch = compareVec2Epsilon2( const isClosingSketch = compareVec2Epsilon2(
firstSeg.from, firstSeg.from,
[intersection2d.x, intersection2d.y], [intersection2d.x, intersection2d.y],
1 0.5
) )
let modifiedAst let modifiedAst
if (isClosingSketch) { if (isClosingSketch) {
@ -567,9 +578,10 @@ class SceneEntities {
// const prevSegment = sketchGroup.slice(index - 1)[0] // const prevSegment = sketchGroup.slice(index - 1)[0]
const type = group?.userData?.type const type = group?.userData?.type
const factor = const factor =
sceneInfra.camControls.camera instanceof OrthographicCamera (sceneInfra.camControls.camera instanceof OrthographicCamera
? orthoFactor ? orthoFactor
: perspScale(sceneInfra.camControls.camera, group) : perspScale(sceneInfra.camControls.camera, group)) /
sceneInfra._baseUnitMultiplier
if (type === TANGENTIAL_ARC_TO_SEGMENT) { if (type === TANGENTIAL_ARC_TO_SEGMENT) {
this.updateTangentialArcToSegment({ this.updateTangentialArcToSegment({
prevSegment: sketchGroup[index - 1], prevSegment: sketchGroup[index - 1],

View File

@ -18,9 +18,8 @@ import {
Intersection, Intersection,
Object3D, Object3D,
Object3DEventMap, Object3DEventMap,
BoxGeometry,
} from 'three' } from 'three'
import { compareVec2Epsilon2 } from 'lang/std/sketch' import { Coords2d, compareVec2Epsilon2 } from 'lang/std/sketch'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import * as TWEEN from '@tweenjs/tween.js' import * as TWEEN from '@tweenjs/tween.js'
import { SourceRange } from 'lang/wasm' import { SourceRange } from 'lang/wasm'
@ -88,6 +87,8 @@ class SceneInfra {
fov = 45 fov = 45
fovBeforeAnimate = 45 fovBeforeAnimate = 45
isFovAnimationInProgress = false isFovAnimationInProgress = false
_baseUnit: BaseUnit = 'mm'
_baseUnitMultiplier = 1
onDragCallback: (arg: OnDragCallbackArgs) => void = () => {} onDragCallback: (arg: OnDragCallbackArgs) => void = () => {}
onMoveCallback: (arg: onMoveCallbackArgs) => void = () => {} onMoveCallback: (arg: onMoveCallbackArgs) => void = () => {}
onClickCallback: (arg?: OnClickCallbackArgs) => void = () => {} onClickCallback: (arg?: OnClickCallbackArgs) => void = () => {}
@ -107,6 +108,15 @@ class SceneInfra {
this.onMouseLeave = callbacks.onMouseLeave || this.onMouseLeave this.onMouseLeave = callbacks.onMouseLeave || this.onMouseLeave
this.selected = null // following selections between callbacks being set is too tricky this.selected = null // following selections between callbacks being set is too tricky
} }
set baseUnit(unit: BaseUnit) {
this._baseUnit = unit
this._baseUnitMultiplier = baseUnitTomm(unit)
this.scene.scale.set(
this._baseUnitMultiplier,
this._baseUnitMultiplier,
this._baseUnitMultiplier
)
}
resetMouseListeners = () => { resetMouseListeners = () => {
sceneInfra.setCallbacks({ sceneInfra.setCallbacks({
onDrag: () => {}, onDrag: () => {},
@ -202,7 +212,12 @@ class SceneInfra {
const axisGroup = this.scene const axisGroup = this.scene
.getObjectByName(AXIS_GROUP) .getObjectByName(AXIS_GROUP)
?.getObjectByName('gridHelper') ?.getObjectByName('gridHelper')
planesGroup && planesGroup.scale.set(scale, scale, scale) planesGroup &&
planesGroup.scale.set(
scale / sceneInfra._baseUnitMultiplier,
scale / sceneInfra._baseUnitMultiplier,
scale / sceneInfra._baseUnitMultiplier
)
axisGroup?.name === 'gridHelper' && axisGroup.scale.set(scale, scale, scale) axisGroup?.name === 'gridHelper' && axisGroup.scale.set(scale, scale, scale)
} }
@ -270,8 +285,11 @@ class SceneInfra {
} }
return { return {
intersection2d: new Vector2(transformedPoint.x, transformedPoint.y), // z should be 0 intersection2d: new Vector2(
intersectPoint, transformedPoint.x / this._baseUnitMultiplier,
transformedPoint.y / this._baseUnitMultiplier
), // z should be 0
intersectPoint: intersectPoint.divideScalar(this._baseUnitMultiplier),
intersection: planeIntersects[0], intersection: planeIntersects[0],
} }
} }
@ -483,7 +501,11 @@ class SceneInfra {
this.camControls.camera, this.camControls.camera,
this.camControls.target this.camControls.target
) )
planesGroup.scale.set(sceneScale, sceneScale, sceneScale) planesGroup.scale.set(
sceneScale / sceneInfra._baseUnitMultiplier,
sceneScale / sceneInfra._baseUnitMultiplier,
sceneScale / sceneInfra._baseUnitMultiplier
)
this.scene.add(planesGroup) this.scene.add(planesGroup)
} }
removeDefaultPlanes() { removeDefaultPlanes() {

View File

@ -18,6 +18,7 @@ import {
import { isTauri } from 'lib/isTauri' import { isTauri } from 'lib/isTauri'
import { settingsCommandBarConfig } from 'lib/commandBarConfigs/settingsCommandConfig' import { settingsCommandBarConfig } from 'lib/commandBarConfigs/settingsCommandConfig'
import { authCommandBarConfig } from 'lib/commandBarConfigs/authCommandConfig' import { authCommandBarConfig } from 'lib/commandBarConfigs/authCommandConfig'
import { sceneInfra } from 'clientSideScene/sceneInfra'
type MachineContext<T extends AnyStateMachine> = { type MachineContext<T extends AnyStateMachine> = {
state: StateFrom<T> state: StateFrom<T>
@ -97,6 +98,7 @@ export const GlobalStateProvider = ({
if (settingsState.context.theme !== 'system') return if (settingsState.context.theme !== 'system') return
setThemeClass(e.matches ? Themes.Dark : Themes.Light) setThemeClass(e.matches ? Themes.Dark : Themes.Light)
} }
sceneInfra.baseUnit = settingsState?.context?.baseUnit || 'mm'
matcher.addEventListener('change', listener) matcher.addEventListener('change', listener)
return () => matcher.removeEventListener('change', listener) return () => matcher.removeEventListener('change', listener)