diff --git a/e2e/playwright/flow-tests.spec.ts b/e2e/playwright/flow-tests.spec.ts index b25da46c1..506d78aba 100644 --- a/e2e/playwright/flow-tests.spec.ts +++ b/e2e/playwright/flow-tests.spec.ts @@ -3,6 +3,7 @@ import { secrets } from './secrets' import { getUtils } from './test-utils' import waitOn from 'wait-on' 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 @@ -15,9 +16,9 @@ document.addEventListener('mousemove', (e) => */ const commonPoints = { - startAt: '[26.38, -35.59]', - num1: 26.63, - num2: 53.01, + startAt: '[0.93, -1.26]', + num1: 0.95, + num2: 1.88, } test.beforeEach(async ({ context, page }) => { @@ -101,13 +102,13 @@ test('Basic sketch', async ({ page }) => { .toHaveText(`const part001 = startSketchOn('-XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %) - |> line([0, ${commonPoints.num1}], %)`) + |> line([0, ${commonPoints.num1 - 0.01}], %)`) await page.mouse.click(startXPx, 500 - PUR * 20) await expect(page.locator('.cm-content')) .toHaveText(`const part001 = startSketchOn('-XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %) - |> line([0, ${commonPoints.num1}], %) + |> line([0, ${commonPoints.num1 - 0.01}], %) |> line([-${commonPoints.num2}, 0], %)`) // deselect line tool @@ -132,7 +133,7 @@ test('Basic sketch', async ({ page }) => { .toHaveText(`const part001 = startSketchOn('-XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line({ to: [${commonPoints.num1}, 0], tag: 'seg01' }, %) - |> line([0, ${commonPoints.num1}], %) + |> line([0, ${commonPoints.num1 - 0.01}], %) |> 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.updateCamPosition(viewCmd) - await u.clearCommandLogs() await page.getByRole('button', { name: 'Start Sketch' }).click() + await u.updateCamPosition(viewCmd) await u.closeDebugPanel() 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 = ( plane = 'XY' ) => `const part001 = startSketchOn('${plane}') - |> startProfileAt([32.13, -43.34], %)` + |> startProfileAt([1.14, -1.54], %)` await TestSinglePlane({ viewCmd: camPos, expectedCode: codeTemplate('XY'), @@ -325,7 +325,7 @@ test('Can create sketches on all planes and their back sides', async ({ await TestSinglePlane({ viewCmd: camPos, expectedCode: codeTemplate('YZ'), - clickCoords: { x: 700, y: 300 }, // green plane + clickCoords: { x: 700, y: 250 }, // green plane }) await TestSinglePlane({ viewCmd: camPos, @@ -488,13 +488,13 @@ test('Selections work on fresh and edited sketch', async ({ page }) => { .toHaveText(`const part001 = startSketchOn('-XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %) - |> line([0, ${commonPoints.num1}], %)`) + |> line([0, ${commonPoints.num1 - 0.01}], %)`) await page.mouse.click(startXPx, 500 - PUR * 20) await expect(page.locator('.cm-content')) .toHaveText(`const part001 = startSketchOn('-XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %) - |> line([0, ${commonPoints.num1}], %) + |> line([0, ${commonPoints.num1 - 0.01}], %) |> line([-${commonPoints.num2}, 0], %)`) // deselect line tool @@ -765,12 +765,12 @@ test('Can add multiple sketches', async ({ page }) => { .toHaveText(`const part001 = startSketchOn('-XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %) - |> line([0, ${commonPoints.num1}], %)`) + |> line([0, ${commonPoints.num1 - 0.01}], %)`) await page.mouse.click(startXPx, 500 - PUR * 20) const finalCodeFirstSketch = `const part001 = startSketchOn('-XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %) - |> line([0, ${commonPoints.num1}], %) + |> line([0, ${commonPoints.num1 - 0.01}], %) |> line([-${commonPoints.num2}, 0], %)` await expect(page.locator('.cm-content')).toHaveText(finalCodeFirstSketch) @@ -793,7 +793,7 @@ test('Can add multiple sketches', async ({ page }) => { await u.clearAndCloseDebugPanel() 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 page.locator('.cm-content').innerText()).replace(/\s/g, '') ).toBe( @@ -807,7 +807,7 @@ const part002 = startSketchOn('XY') await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10) await page.waitForTimeout(100) - const num2 = 26.48 + const num2 = 0.94 await expect( (await page.locator('.cm-content').innerText()).replace(/\s/g, '') ).toBe( @@ -825,7 +825,7 @@ const part002 = startSketchOn('XY') const part002 = startSketchOn('XY') |> startProfileAt(${startAt2}, %) |> 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 expect( @@ -835,8 +835,8 @@ const part002 = startSketchOn('XY') const part002 = startSketchOn('XY') |> startProfileAt(${startAt2}, %) |> line([${num2}, 0], %) - |> line([0, ${num2}], %) - |> line([-52.71, 0], %)`.replace(/\s/g, '') + |> line([0, ${roundOff(num2 - 0.01)}], %) + |> line([-1.87, 0], %)`.replace(/\s/g, '') ) }) diff --git a/e2e/playwright/snapshot-tests.spec.ts b/e2e/playwright/snapshot-tests.spec.ts index 6a511876b..0103e0cbd 100644 --- a/e2e/playwright/snapshot-tests.spec.ts +++ b/e2e/playwright/snapshot-tests.spec.ts @@ -435,7 +435,23 @@ test('extrude on each default plane should be stable', async ({ 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) await page.setViewportSize({ width: 1200, height: 500 }) 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 expect(page.locator('.cm-content')) .toHaveText(`const part001 = startSketchOn('-XZ') - |> startProfileAt(${commonPoints.startAt}, %)`) + |> startProfileAt([0.93, -1.26], %)`) await page.waitForTimeout(100) await u.closeDebugPanel() @@ -482,8 +498,8 @@ test('Draft segments should look right', async ({ page }) => { await expect(page.locator('.cm-content')) .toHaveText(`const part001 = startSketchOn('-XZ') - |> startProfileAt(${commonPoints.startAt}, %) - |> line([${commonPoints.num1}, 0], %)`) + |> startProfileAt([0.93, -1.26], %) + |> line([0.95, 0], %)`) await page.getByRole('button', { name: 'Tangential Arc' }).click() @@ -493,3 +509,195 @@ test('Draft segments should look right', async ({ page }) => { 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, + }) +}) diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-inch-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-inch-1-Google-Chrome-linux.png new file mode 100644 index 000000000..ba2985bfa Binary files /dev/null and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-inch-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-inch-2-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-inch-2-Google-Chrome-linux.png new file mode 100644 index 000000000..d80ca8617 Binary files /dev/null and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-inch-2-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-mm-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-mm-1-Google-Chrome-linux.png new file mode 100644 index 000000000..a99173532 Binary files /dev/null and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-mm-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-mm-2-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-mm-2-Google-Chrome-linux.png new file mode 100644 index 000000000..ba9676a6d Binary files /dev/null and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-mm-2-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-1-Google-Chrome-linux.png index 6685980c8..77867c447 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-2-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-2-Google-Chrome-linux.png index f30ea08d1..36bd375f2 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-2-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-2-Google-Chrome-linux.png differ diff --git a/src/clientSideScene/CameraControls.ts b/src/clientSideScene/CameraControls.ts index 92988c9b0..f79070d9b 100644 --- a/src/clientSideScene/CameraControls.ts +++ b/src/clientSideScene/CameraControls.ts @@ -220,6 +220,7 @@ export class CameraControls { this.onWindowResize() this.update() + this._usePerspectiveCamera() } private _isCamMovingCallback: (isMoving: boolean, isTween: boolean) => void = @@ -373,7 +374,7 @@ export class CameraControls { return this.camera } - usePerspectiveCamera = () => { + _usePerspectiveCamera = () => { const { x: px, y: py, z: pz } = this.camera.position const { x: qx, y: qy, z: qz, w: qw } = this.camera.quaternion const zoom = this.camera.zoom @@ -389,14 +390,17 @@ export class CameraControls { ) direction.normalize() this.camera.position.copy(this.target).addScaledVector(direction, distance) - + } + usePerspectiveCamera = () => { + this._usePerspectiveCamera() engineCommandManager.sendSceneCommand({ type: 'modeling_cmd_req', cmd_id: uuidv4(), cmd: { type: 'default_camera_set_perspective', parameters: { - fov_y: this.camera.fov, + fov_y: + this.camera instanceof PerspectiveCamera ? this.camera.fov : 45, ...calculateNearFarFromFOV(this.lastPerspectiveFov), }, }, diff --git a/src/clientSideScene/sceneEntities.ts b/src/clientSideScene/sceneEntities.ts index 38578aa00..c7a1cdd22 100644 --- a/src/clientSideScene/sceneEntities.ts +++ b/src/clientSideScene/sceneEntities.ts @@ -106,9 +106,10 @@ class SceneEntities { Object.values(this.activeSegments).forEach((segment) => { const factor = - sceneInfra.camControls.camera instanceof OrthographicCamera + (sceneInfra.camControls.camera instanceof OrthographicCamera ? orthoFactor - : perspScale(sceneInfra.camControls.camera, segment) + : perspScale(sceneInfra.camControls.camera, segment)) / + sceneInfra._baseUnitMultiplier if ( segment.userData.from && segment.userData.to && @@ -143,9 +144,9 @@ class SceneEntities { ? orthoFactor : perspScale(sceneInfra.camControls.camera, this.axisGroup) 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) - 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) } createSketchAxis(sketchPathToNode: PathToNode) { + const orthoFactor = orthoScale(sceneInfra.camControls.camera) const baseXColor = 0x000055 const baseYColor = 0x550000 const xAxisGeometry = new BoxGeometry(100000, 0.3, 0.01) @@ -208,6 +210,14 @@ class SceneEntities { sceneInfra.camControls.target ) 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.currentSketchQuaternion && this.axisGroup.setRotationFromQuaternion(this.currentSketchQuaternion) @@ -279,9 +289,10 @@ class SceneEntities { ) const orthoFactor = orthoScale(sceneInfra.camControls.camera) const factor = - sceneInfra.camControls.camera instanceof OrthographicCamera + (sceneInfra.camControls.camera instanceof OrthographicCamera ? orthoFactor - : perspScale(sceneInfra.camControls.camera, dummy) + : perspScale(sceneInfra.camControls.camera, dummy)) / + sceneInfra._baseUnitMultiplier sketchGroup.value.forEach((segment, index) => { let segPathToNode = getNodePathFromSourceRange( draftSegment ? truncatedAst : kclManager.ast, @@ -404,7 +415,7 @@ class SceneEntities { const isClosingSketch = compareVec2Epsilon2( firstSeg.from, [intersection2d.x, intersection2d.y], - 1 + 0.5 ) let modifiedAst if (isClosingSketch) { @@ -567,9 +578,10 @@ class SceneEntities { // const prevSegment = sketchGroup.slice(index - 1)[0] const type = group?.userData?.type const factor = - sceneInfra.camControls.camera instanceof OrthographicCamera + (sceneInfra.camControls.camera instanceof OrthographicCamera ? orthoFactor - : perspScale(sceneInfra.camControls.camera, group) + : perspScale(sceneInfra.camControls.camera, group)) / + sceneInfra._baseUnitMultiplier if (type === TANGENTIAL_ARC_TO_SEGMENT) { this.updateTangentialArcToSegment({ prevSegment: sketchGroup[index - 1], diff --git a/src/clientSideScene/sceneInfra.ts b/src/clientSideScene/sceneInfra.ts index d0fe71b7d..a880dc534 100644 --- a/src/clientSideScene/sceneInfra.ts +++ b/src/clientSideScene/sceneInfra.ts @@ -18,9 +18,8 @@ import { Intersection, Object3D, Object3DEventMap, - BoxGeometry, } from 'three' -import { compareVec2Epsilon2 } from 'lang/std/sketch' +import { Coords2d, compareVec2Epsilon2 } from 'lang/std/sketch' import { useModelingContext } from 'hooks/useModelingContext' import * as TWEEN from '@tweenjs/tween.js' import { SourceRange } from 'lang/wasm' @@ -88,6 +87,8 @@ class SceneInfra { fov = 45 fovBeforeAnimate = 45 isFovAnimationInProgress = false + _baseUnit: BaseUnit = 'mm' + _baseUnitMultiplier = 1 onDragCallback: (arg: OnDragCallbackArgs) => void = () => {} onMoveCallback: (arg: onMoveCallbackArgs) => void = () => {} onClickCallback: (arg?: OnClickCallbackArgs) => void = () => {} @@ -107,6 +108,15 @@ class SceneInfra { this.onMouseLeave = callbacks.onMouseLeave || this.onMouseLeave 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 = () => { sceneInfra.setCallbacks({ onDrag: () => {}, @@ -202,7 +212,12 @@ class SceneInfra { const axisGroup = this.scene .getObjectByName(AXIS_GROUP) ?.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) } @@ -270,8 +285,11 @@ class SceneInfra { } return { - intersection2d: new Vector2(transformedPoint.x, transformedPoint.y), // z should be 0 - intersectPoint, + intersection2d: new Vector2( + transformedPoint.x / this._baseUnitMultiplier, + transformedPoint.y / this._baseUnitMultiplier + ), // z should be 0 + intersectPoint: intersectPoint.divideScalar(this._baseUnitMultiplier), intersection: planeIntersects[0], } } @@ -483,7 +501,11 @@ class SceneInfra { this.camControls.camera, 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) } removeDefaultPlanes() { diff --git a/src/components/GlobalStateProvider.tsx b/src/components/GlobalStateProvider.tsx index e31035adf..e1b7b02dd 100644 --- a/src/components/GlobalStateProvider.tsx +++ b/src/components/GlobalStateProvider.tsx @@ -18,6 +18,7 @@ import { import { isTauri } from 'lib/isTauri' import { settingsCommandBarConfig } from 'lib/commandBarConfigs/settingsCommandConfig' import { authCommandBarConfig } from 'lib/commandBarConfigs/authCommandConfig' +import { sceneInfra } from 'clientSideScene/sceneInfra' type MachineContext = { state: StateFrom @@ -97,6 +98,7 @@ export const GlobalStateProvider = ({ if (settingsState.context.theme !== 'system') return setThemeClass(e.matches ? Themes.Dark : Themes.Light) } + sceneInfra.baseUnit = settingsState?.context?.baseUnit || 'mm' matcher.addEventListener('change', listener) return () => matcher.removeEventListener('change', listener)