Files
modeling-app/src/clientSideScene/CameraControls.ts

1316 lines
42 KiB
TypeScript
Raw Normal View History

import { cameraMouseDragGuards, MouseGuard } from 'lib/cameraControls'
import {
Euler,
MathUtils,
Matrix4,
OrthographicCamera,
PerspectiveCamera,
Quaternion,
Spherical,
Vector2,
Vector3,
} from 'three'
import {
DEBUG_SHOW_INTERSECTION_PLANE,
INTERSECTION_PLANE_LAYER,
SKETCH_LAYER,
ZOOM_MAGIC_NUMBER,
} from './sceneInfra'
2024-03-02 08:20:50 +11:00
import {
Subscription,
EngineCommandManager,
UnreliableSubscription,
2024-03-02 08:20:50 +11:00
} from 'lang/std/engineConnection'
import { EngineCommand } from 'lang/std/artifactGraph'
import { toSync, uuidv4 } from 'lib/utils'
import { deg2Rad } from 'lib/utils2d'
import { isReducedMotion, roundOff, throttle } from 'lib/utils'
import * as TWEEN from '@tweenjs/tween.js'
import { isQuaternionVertical } from './helpers'
import { reportRejection } from 'lib/trap'
Add a user-level projection setting, command, and toggle (#3983) * Add cameraProjection setting * Add UI to toggle the user-level projection setting. * Make cameraProjection setting respected at startup * Add an E2E test for the perspective toggle * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * Don't force user back into perspective when exiting sketch * Make the projection setting more searchable * Make `current` label apply to the default option if not set * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * Re-run CI * Ohh *cargo fmt* * @lf94 feedback, fix found toggling bug, make command bar instantly toggle setting * Roll back the instant toggling behavior, it breaks the tests * Make ortho the default, keep tests using perspective * Move projection below camera controls setting * Fix up gizmo tests, which broke because the gizmo moved * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * Look at this (photo)Graph *in the voice of Nickelback* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: 49fl <ircsurfer33@gmail.com>
2024-09-30 11:40:00 -04:00
import { CameraProjectionType } from 'wasm-lib/kcl/bindings/CameraProjectionType'
const ORTHOGRAPHIC_CAMERA_SIZE = 20
const FRAMES_TO_ANIMATE_IN = 30
const ORTHOGRAPHIC_MAGIC_FOV = 4
const tempQuaternion = new Quaternion() // just used for maths
2024-03-02 08:20:50 +11:00
type interactionType = 'pan' | 'rotate' | 'zoom'
interface ThreeCamValues {
position: Vector3
quaternion: Quaternion
zoom: number
isPerspective: boolean
target: Vector3
}
export type ReactCameraProperties =
| {
type: 'perspective'
fov?: number
position: [number, number, number]
2024-06-05 14:43:12 +02:00
target: [number, number, number]
quaternion: [number, number, number, number]
}
| {
type: 'orthographic'
zoom?: number
position: [number, number, number]
2024-06-05 14:43:12 +02:00
target: [number, number, number]
quaternion: [number, number, number, number]
}
const lastCmdDelay = 50
export class CameraControls {
engineCommandManager: EngineCommandManager
2024-03-02 08:20:50 +11:00
syncDirection: 'clientToEngine' | 'engineToClient' = 'engineToClient'
camera: PerspectiveCamera | OrthographicCamera
target: Vector3
domElement: HTMLCanvasElement
isDragging: boolean
mouseDownPosition: Vector2
mouseNewPosition: Vector2
rotationSpeed = 0.3
enableRotate = true
enablePan = true
enableZoom = true
zoomDataFromLastFrame?: number = undefined
// holds coordinates, and interaction
moveDataFromLastFrame?: [number, number, string] = undefined
lastPerspectiveFov: number = 45
pendingZoom: number | null = null
pendingRotation: Vector2 | null = null
pendingPan: Vector2 | null = null
interactionGuards: MouseGuard = cameraMouseDragGuards.KittyCAD
isFovAnimationInProgress = false
perspectiveFovBeforeOrtho = 45
get isPerspective() {
return this.camera instanceof PerspectiveCamera
}
Add a user-level projection setting, command, and toggle (#3983) * Add cameraProjection setting * Add UI to toggle the user-level projection setting. * Make cameraProjection setting respected at startup * Add an E2E test for the perspective toggle * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * Don't force user back into perspective when exiting sketch * Make the projection setting more searchable * Make `current` label apply to the default option if not set * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * Re-run CI * Ohh *cargo fmt* * @lf94 feedback, fix found toggling bug, make command bar instantly toggle setting * Roll back the instant toggling behavior, it breaks the tests * Make ortho the default, keep tests using perspective * Move projection below camera controls setting * Fix up gizmo tests, which broke because the gizmo moved * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * Look at this (photo)Graph *in the voice of Nickelback* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: 49fl <ircsurfer33@gmail.com>
2024-09-30 11:40:00 -04:00
setEngineCameraProjection(projection: CameraProjectionType) {
if (projection === 'orthographic') {
this.useOrthographicCamera()
} else {
this.usePerspectiveCamera(true).catch(reportRejection)
}
}
handleStart = () => {
this._isCamMovingCallback(true, false)
}
handleEnd = () => {
this._isCamMovingCallback(false, false)
}
setCam = (camProps: ReactCameraProperties) => {
if (
camProps.type === 'perspective' &&
this.camera instanceof OrthographicCamera
) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.usePerspectiveCamera()
} else if (
camProps.type === 'orthographic' &&
this.camera instanceof PerspectiveCamera
) {
this.useOrthographicCamera()
}
this.camera.position.set(...camProps.position)
this.camera.quaternion.set(...camProps.quaternion)
if (
camProps.type === 'perspective' &&
this.camera instanceof PerspectiveCamera
) {
// not sure what to do here, calling dollyZoom here is buggy because it updates the position
// at the same time
} else if (
camProps.type === 'orthographic' &&
this.camera instanceof OrthographicCamera
) {
this.camera.zoom = camProps.zoom || 1
}
this.camera.updateProjectionMatrix()
console.log('doing this thing', camProps)
this.update(true)
}
throttledEngCmd = throttle((cmd: EngineCommand) => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.engineCommandManager.sendSceneCommand(cmd)
}, 1000 / 30)
throttledUpdateEngineCamera = throttle((threeValues: ThreeCamValues) => {
const cmd: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_look_at',
...convertThreeCamValuesToEngineCam(threeValues),
},
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.engineCommandManager.sendSceneCommand(cmd)
}, 1000 / 15)
lastPerspectiveCmd: EngineCommand | null = null
lastPerspectiveCmdTime: number = Date.now()
lastPerspectiveCmdTimeoutId: number | null = null
sendLastPerspectiveReliableChannel = () => {
if (
this.lastPerspectiveCmd &&
Date.now() - this.lastPerspectiveCmdTime >= lastCmdDelay
) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.engineCommandManager.sendSceneCommand(this.lastPerspectiveCmd, true)
this.lastPerspectiveCmdTime = Date.now()
}
}
constructor(
isOrtho = false,
domElement: HTMLCanvasElement,
engineCommandManager: EngineCommandManager
) {
this.engineCommandManager = engineCommandManager
this.camera = isOrtho ? new OrthographicCamera() : new PerspectiveCamera()
this.camera.up.set(0, 0, 1)
this.camera.far = 20000
this.target = new Vector3()
this.domElement = domElement
this.isDragging = false
this.mouseDownPosition = new Vector2()
this.mouseNewPosition = new Vector2()
this.domElement.addEventListener('pointerdown', this.onMouseDown)
this.domElement.addEventListener('pointermove', this.onMouseMove)
this.domElement.addEventListener('pointerup', this.onMouseUp)
this.domElement.addEventListener('wheel', this.onMouseWheel)
window.addEventListener('resize', this.onWindowResize)
this.onWindowResize()
this.update()
this._usePerspectiveCamera()
2024-03-02 08:20:50 +11:00
type CallBackParam = Parameters<
(
| Subscription<
| 'default_camera_zoom'
| 'camera_drag_end'
| 'default_camera_get_settings'
| 'zoom_to_fit'
>
| UnreliableSubscription<'camera_drag_move'>
)['callback']
>[0]
const cb = ({ data, type }: CallBackParam) => {
2024-03-02 08:20:50 +11:00
const camSettings = data.settings
this.camera.position.set(
camSettings.pos.x,
camSettings.pos.y,
camSettings.pos.z
)
this.target.set(
camSettings.center.x,
camSettings.center.y,
camSettings.center.z
)
const quat = new Quaternion(
camSettings.orientation.x,
camSettings.orientation.y,
camSettings.orientation.z,
camSettings.orientation.w
).invert()
this.camera.up.copy(new Vector3(0, 1, 0).applyQuaternion(quat))
if (this.camera instanceof PerspectiveCamera && camSettings.ortho) {
this.useOrthographicCamera()
}
if (this.camera instanceof OrthographicCamera && !camSettings.ortho) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.usePerspectiveCamera()
}
2024-03-02 08:20:50 +11:00
if (this.camera instanceof PerspectiveCamera && camSettings.fov_y) {
this.camera.fov = camSettings.fov_y
} else if (
this.camera instanceof OrthographicCamera &&
camSettings.ortho_scale
) {
const distanceToTarget = new Vector3(
camSettings.pos.x,
camSettings.pos.y,
camSettings.pos.z
).distanceTo(
new Vector3(
camSettings.center.x,
camSettings.center.y,
camSettings.center.z
)
)
this.camera.zoom = (camSettings.ortho_scale * 40) / distanceToTarget
2024-03-02 08:20:50 +11:00
}
this.onCameraChange()
}
// Our stream is never more than 60fps.
// We can get away with capping our "virtual fps" to 60 then.
const FPS_VIRTUAL = 60
const doZoom = () => {
if (this.zoomDataFromLastFrame !== undefined) {
this.handleStart()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd: {
type: 'default_camera_zoom',
magnitude:
(-1 * this.zoomDataFromLastFrame) / window.devicePixelRatio,
},
cmd_id: uuidv4(),
})
this.handleEnd()
}
this.zoomDataFromLastFrame = undefined
}
setInterval(doZoom, 1000 / FPS_VIRTUAL)
const doMove = () => {
if (this.moveDataFromLastFrame !== undefined) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd: {
type: 'camera_drag_move',
interaction: this.moveDataFromLastFrame[2] as any,
window: {
x: this.moveDataFromLastFrame[0],
y: this.moveDataFromLastFrame[1],
},
},
cmd_id: uuidv4(),
})
}
this.moveDataFromLastFrame = undefined
}
setInterval(doMove, 1000 / FPS_VIRTUAL)
2024-03-02 08:20:50 +11:00
setTimeout(() => {
this.engineCommandManager.subscribeTo({
2024-03-02 08:20:50 +11:00
event: 'camera_drag_end',
callback: cb,
})
this.engineCommandManager.subscribeTo({
2024-03-02 08:20:50 +11:00
event: 'default_camera_zoom',
callback: cb,
})
this.engineCommandManager.subscribeTo({
2024-03-02 08:20:50 +11:00
event: 'default_camera_get_settings',
callback: cb,
})
this.engineCommandManager.subscribeTo({
event: 'zoom_to_fit',
callback: cb,
})
this.engineCommandManager.subscribeToUnreliable({
event: 'camera_drag_move',
callback: cb,
})
2024-03-02 08:20:50 +11:00
})
}
private _isCamMovingCallback: (isMoving: boolean, isTween: boolean) => void =
() => {}
setIsCamMovingCallback(cb: (isMoving: boolean, isTween: boolean) => void) {
this._isCamMovingCallback = cb
}
private _camChangeCallbacks: { [key: string]: () => void } = {}
subscribeToCamChange(cb: () => void) {
const cbId = uuidv4()
this._camChangeCallbacks[cbId] = cb
const unsubscribe = () => {
delete this._camChangeCallbacks[cbId]
}
return unsubscribe
}
onWindowResize = () => {
if (this.camera instanceof PerspectiveCamera) {
this.camera.aspect = window.innerWidth / window.innerHeight
} else if (this.camera instanceof OrthographicCamera) {
const aspect = window.innerWidth / window.innerHeight
this.camera.left = -ORTHOGRAPHIC_CAMERA_SIZE * aspect
this.camera.right = ORTHOGRAPHIC_CAMERA_SIZE * aspect
this.camera.top = ORTHOGRAPHIC_CAMERA_SIZE
this.camera.bottom = -ORTHOGRAPHIC_CAMERA_SIZE
}
this.camera.updateProjectionMatrix()
}
onMouseDown = (event: PointerEvent) => {
this.domElement.setPointerCapture(event.pointerId)
this.isDragging = true
this.mouseDownPosition.set(event.clientX, event.clientY)
2024-03-02 08:20:50 +11:00
let interaction = this.getInteractionType(event)
if (interaction === 'none') return
this.handleStart()
2024-03-02 08:20:50 +11:00
if (this.syncDirection === 'engineToClient') {
void this.engineCommandManager.sendSceneCommand({
2024-03-02 08:20:50 +11:00
type: 'modeling_cmd_req',
cmd: {
type: 'camera_drag_start',
interaction,
window: { x: event.clientX, y: event.clientY },
},
cmd_id: uuidv4(),
})
}
}
onMouseMove = (event: PointerEvent) => {
if (this.isDragging) {
this.mouseNewPosition.set(event.clientX, event.clientY)
const deltaMove = this.mouseNewPosition
.clone()
.sub(this.mouseDownPosition)
this.mouseDownPosition.copy(this.mouseNewPosition)
2024-03-02 08:20:50 +11:00
const interaction = this.getInteractionType(event)
if (interaction === 'none') return
if (this.syncDirection === 'engineToClient') {
this.moveDataFromLastFrame = [event.clientX, event.clientY, interaction]
return
}
// Implement camera movement logic here based on deltaMove
// For example, for rotating the camera around the target:
2024-03-02 08:20:50 +11:00
if (interaction === 'rotate') {
this.pendingRotation = this.pendingRotation
? this.pendingRotation
: new Vector2()
this.pendingRotation.x += deltaMove.x
this.pendingRotation.y += deltaMove.y
2024-03-02 08:20:50 +11:00
} else if (interaction === 'zoom') {
this.pendingZoom = this.pendingZoom ? this.pendingZoom : 1
this.pendingZoom *= 1 + deltaMove.y * 0.01
2024-03-02 08:20:50 +11:00
} else if (interaction === 'pan') {
this.pendingPan = this.pendingPan ? this.pendingPan : new Vector2()
let distance = this.camera.position.distanceTo(this.target)
if (this.camera instanceof OrthographicCamera) {
const zoomFudgeFactor = 2280
distance = zoomFudgeFactor / (this.camera.zoom * 45)
}
const panSpeed = (distance / 1000 / 45) * this.perspectiveFovBeforeOrtho
this.pendingPan.x += -deltaMove.x * panSpeed
this.pendingPan.y += deltaMove.y * panSpeed
}
} else {
/**
* If we're not in sketch mode and not dragging, we can highlight entities
* under the cursor. This recently moved from being handled in App.tsx.
* This might not be the right spot, but it is more consolidated.
*/
if (this.syncDirection === 'engineToClient') {
const newCmdId = uuidv4()
this.throttledEngCmd({
type: 'modeling_cmd_req',
cmd: {
type: 'highlight_set_entity',
selected_at_window: { x: event.clientX, y: event.clientY },
},
cmd_id: newCmdId,
})
}
}
}
onMouseUp = (event: PointerEvent) => {
this.domElement.releasePointerCapture(event.pointerId)
this.isDragging = false
this.handleEnd()
2024-03-02 08:20:50 +11:00
if (this.syncDirection === 'engineToClient') {
const interaction = this.getInteractionType(event)
if (interaction === 'none') return
void this.engineCommandManager.sendSceneCommand({
2024-03-02 08:20:50 +11:00
type: 'modeling_cmd_req',
cmd: {
type: 'camera_drag_end',
interaction,
window: { x: event.clientX, y: event.clientY },
},
cmd_id: uuidv4(),
})
}
}
onMouseWheel = (event: WheelEvent) => {
const interaction = this.getInteractionType(event)
if (interaction === 'none') return
event.preventDefault()
2024-03-02 08:20:50 +11:00
if (this.syncDirection === 'engineToClient') {
if (interaction === 'zoom') {
this.zoomDataFromLastFrame = event.deltaY
} else {
// This case will get handled when we add pan and rotate using Apple trackpad.
console.error(
`Unexpected interaction type for engineToClient wheel event: ${interaction}`
)
}
2024-03-02 08:20:50 +11:00
return
}
// else "clientToEngine" (Sketch Mode) or forceUpdate
// We need to simulate similar behavior as when we send
// zoom commands to engine. This means dropping some zoom
// commands too.
// From onMouseMove zoom handling which seems to be really smooth
this.handleStart()
if (interaction === 'zoom') {
this.pendingZoom = 1 + (event.deltaY / window.devicePixelRatio) * 0.001
} else {
// This case will get handled when we add pan and rotate using Apple trackpad.
console.error(
`Unexpected interaction type for wheel event: ${interaction}`
)
}
this.handleEnd()
}
useOrthographicCamera = () => {
if (this.camera instanceof OrthographicCamera) return
const { x: px, y: py, z: pz } = this.camera.position
const { x: qx, y: qy, z: qz, w: qw } = this.camera.quaternion
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
const oldCamUp = this.camera.up.clone()
const aspect = window.innerWidth / window.innerHeight
this.lastPerspectiveFov = this.camera.fov
const { z_near, z_far } = calculateNearFarFromFOV(this.lastPerspectiveFov)
this.camera = new OrthographicCamera(
-ORTHOGRAPHIC_CAMERA_SIZE * aspect,
ORTHOGRAPHIC_CAMERA_SIZE * aspect,
ORTHOGRAPHIC_CAMERA_SIZE,
-ORTHOGRAPHIC_CAMERA_SIZE,
z_near,
z_far
)
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
this.camera.up.copy(oldCamUp)
this.camera.layers.enable(SKETCH_LAYER)
if (DEBUG_SHOW_INTERSECTION_PLANE)
this.camera.layers.enable(INTERSECTION_PLANE_LAYER)
this.camera.position.set(px, py, pz)
const distance = this.camera.position.distanceTo(this.target.clone())
const fovFactor = 45 / this.lastPerspectiveFov
this.camera.zoom = (ZOOM_MAGIC_NUMBER * fovFactor * 0.8) / distance
this.camera.quaternion.set(qx, qy, qz, qw)
this.camera.updateProjectionMatrix()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_set_orthographic',
},
})
this.onCameraChange()
}
private createPerspectiveCamera = () => {
const { z_near, z_far } = calculateNearFarFromFOV(this.lastPerspectiveFov)
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
const previousCamUp = this.camera.up.clone()
this.camera = new PerspectiveCamera(
this.lastPerspectiveFov,
window.innerWidth / window.innerHeight,
z_near,
z_far
)
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
this.camera.up.copy(previousCamUp)
this.camera.layers.enable(SKETCH_LAYER)
if (DEBUG_SHOW_INTERSECTION_PLANE)
this.camera.layers.enable(INTERSECTION_PLANE_LAYER)
return this.camera
}
_usePerspectiveCamera = () => {
const { x: px, y: py, z: pz } = this.camera.position
const { x: qx, y: qy, z: qz, w: qw } = this.camera.quaternion
this.camera = this.createPerspectiveCamera()
this.camera.position.set(px, py, pz)
this.camera.quaternion.set(qx, qy, qz, qw)
const direction = new Vector3().subVectors(
this.camera.position,
this.target
)
direction.normalize()
}
usePerspectiveCamera = async (forceSend = false) => {
this._usePerspectiveCamera()
if (forceSend || this.syncDirection === 'clientToEngine') {
await this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_set_perspective',
parameters: {
fov_y:
this.camera instanceof PerspectiveCamera ? this.camera.fov : 45,
},
},
})
}
this.onCameraChange()
this.update()
return this.camera
}
dollyZoom = async (newFov: number, splitEngineCalls = false) => {
if (!(this.camera instanceof PerspectiveCamera)) {
console.warn('Dolly zoom is only applicable to perspective cameras.')
return
}
this.lastPerspectiveFov = newFov
// Calculate the direction vector from the camera towards the controls target
const direction = new Vector3()
.subVectors(this.target, this.camera.position)
.normalize()
// Calculate the distance to the controls target before changing the FOV
const distanceBefore = this.camera.position.distanceTo(this.target)
// Calculate the scale factor for the new FOV compared to the old one
// This needs to be calculated before updating the camera's FOV
const oldFov = this.camera.fov
const viewHeightFactor = (fov: number) => {
/* *
/|
/ |
/ |
/ |
/ | viewHeight/2
/ |
/ |
/fov/2 |
/________|
\ |
\._._._.|
*/
return Math.tan(deg2Rad(fov / 2))
}
const scaleFactor = viewHeightFactor(oldFov) / viewHeightFactor(newFov)
this.camera.fov = newFov
this.camera.updateProjectionMatrix()
const distanceAfter = distanceBefore * scaleFactor
const newPosition = this.target
.clone()
.add(direction.multiplyScalar(-distanceAfter))
this.camera.position.copy(newPosition)
if (splitEngineCalls) {
await this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_look_at',
...convertThreeCamValuesToEngineCam({
isPerspective: true,
position: newPosition,
quaternion: this.camera.quaternion,
zoom: this.camera.zoom,
target: this.target,
}),
},
})
await this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_set_perspective',
parameters: {
fov_y: newFov,
},
},
})
} else {
await this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_perspective_settings',
...convertThreeCamValuesToEngineCam({
isPerspective: true,
position: newPosition,
quaternion: this.camera.quaternion,
zoom: this.camera.zoom,
target: this.target,
}),
fov_y: newFov,
},
})
}
}
update = (forceUpdate = false) => {
// If there are any changes that need to be applied to the camera, apply them here.
let didChange = false
if (this.pendingRotation) {
this.rotateCamera(this.pendingRotation.x, this.pendingRotation.y)
this.pendingRotation = null // Clear the pending rotation after applying it
didChange = true
}
if (this.pendingZoom) {
if (this.camera instanceof PerspectiveCamera) {
// move camera towards or away from the target
const distance = this.camera.position.distanceTo(this.target)
const newDistance = distance * this.pendingZoom
const direction = this.camera.position
.clone()
.sub(this.target)
.normalize()
const newPosition = this.target
.clone()
.add(direction.multiplyScalar(newDistance))
this.camera.position.copy(newPosition)
this.camera.updateProjectionMatrix()
this.pendingZoom = null // Clear the pending zoom after applying it
} else {
// TODO change ortho zoom
this.camera.zoom = this.camera.zoom / this.pendingZoom
this.pendingZoom = null
}
didChange = true
}
if (this.pendingPan) {
// move camera left/right and up/down
const offset = this.camera.position.clone().sub(this.target)
const direction = offset.clone().normalize()
const cameraQuaternion = this.camera.quaternion
const up = new Vector3(0, 1, 0).applyQuaternion(cameraQuaternion)
const right = new Vector3().crossVectors(up, direction)
right.multiplyScalar(this.pendingPan.x)
up.multiplyScalar(this.pendingPan.y)
const newPosition = this.camera.position.clone().add(right).add(up)
this.target.add(right)
this.target.add(up)
this.camera.position.copy(newPosition)
this.pendingPan = null
didChange = true
}
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
this.safeLookAtTarget(this.camera.up)
// Update the camera's matrices
this.camera.updateMatrixWorld()
if (didChange || forceUpdate) {
this.onCameraChange(forceUpdate)
}
// damping would be implemented here in update if we choose to add it.
}
rotateCamera = (deltaX: number, deltaY: number) => {
const quat = new Quaternion().setFromUnitVectors(
new Vector3(0, 0, 1),
new Vector3(0, 1, 0)
)
const quatInverse = quat.clone().invert()
const angleX = deltaX * this.rotationSpeed // rotationSpeed is a constant that defines how fast the camera rotates
const angleY = deltaY * this.rotationSpeed
// Convert angles to radians
const radianX = MathUtils.degToRad(angleX)
const radianY = MathUtils.degToRad(angleY)
// Get the offset from the camera to the target
const offset = new Vector3().subVectors(this.camera.position, this.target)
// spherical is a y-up paradigm, need to conform to that for now
offset.applyQuaternion(quat)
// Convert offset to spherical coordinates
const spherical = new Spherical().setFromVector3(offset)
// Apply the rotations
spherical.theta -= radianX
spherical.phi -= radianY
// Restrict the phi angle to avoid the camera flipping at the poles
spherical.phi = Math.max(0.1, Math.min(Math.PI - 0.1, spherical.phi))
// Convert back to Cartesian coordinates
offset.setFromSpherical(spherical)
// put the offset back into the z-up paradigm
offset.applyQuaternion(quatInverse)
// Update the camera's position
this.camera.position.copy(this.target).add(offset)
// Look at the target
this.camera.updateMatrixWorld()
}
safeLookAtTarget(up = new Vector3(0, 0, 1)) {
const quaternion = _lookAt(this.camera.position, this.target, up)
this.camera.quaternion.copy(quaternion)
this.camera.updateMatrixWorld()
}
tweenCamToNegYAxis(
// -90 degrees from the x axis puts the camera on the negative y axis
targetAngle = -Math.PI / 2,
duration = 500
): Promise<void> {
return new Promise((resolve) => {
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
// should tween the camera so that it has an xPosition of 0, and forcing it's yPosition to be negative
// zPosition should stay the same
const xyRadius = Math.sqrt(
(this.target.x - this.camera.position.x) ** 2 +
(this.target.y - this.camera.position.y) ** 2
)
const xyAngle = Math.atan2(
this.camera.position.y - this.target.y,
this.camera.position.x - this.target.x
)
const camAtTime = (obj: { angle: number }) => {
const x = xyRadius * Math.cos(obj.angle)
const y = xyRadius * Math.sin(obj.angle)
this.camera.position.set(
this.target.x + x,
this.target.y + y,
this.camera.position.z
)
this.update()
this.onCameraChange()
}
const onComplete = (obj: { angle: number }) => {
camAtTime(obj)
this._isCamMovingCallback(false, true)
// resolve after a couple of frames
requestAnimationFrame(() => {
requestAnimationFrame(() => resolve())
})
}
this._isCamMovingCallback(true, true)
if (isReducedMotion()) {
onComplete({ angle: targetAngle })
return
}
new TWEEN.Tween({ angle: xyAngle })
.to({ angle: targetAngle }, duration)
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
.onUpdate(camAtTime)
.onComplete(onComplete)
.start()
})
}
2024-06-05 14:43:12 +02:00
async updateCameraToAxis(
axis: 'x' | 'y' | 'z' | '-x' | '-y' | '-z'
): Promise<void> {
const distance = this.camera.position.distanceTo(this.target)
const vantage = this.target.clone()
let up = { x: 0, y: 0, z: 1 }
if (axis === 'x') {
vantage.x += distance
} else if (axis === 'y') {
vantage.y += distance
} else if (axis === 'z') {
vantage.z += distance
up = { x: -1, y: 0, z: 0 }
} else if (axis === '-x') {
vantage.x -= distance
} else if (axis === '-y') {
vantage.y -= distance
} else if (axis === '-z') {
vantage.z -= distance
up = { x: -1, y: 0, z: 0 }
}
await this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_look_at',
center: this.target,
vantage: vantage,
up: up,
},
})
await this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_get_settings',
},
})
}
async resetCameraPosition(): Promise<void> {
await this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_look_at',
center: this.target,
vantage: {
x: this.target.x,
y: this.target.y - 128,
z: this.target.z + 64,
},
up: { x: 0, y: 0, z: 1 },
},
})
await this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'zoom_to_fit',
object_ids: [], // leave empty to zoom to all objects
padding: 0.2, // padding around the objects
},
})
}
async tweenCameraToQuaternion(
targetQuaternion: Quaternion,
targetPosition = new Vector3(),
duration = 500,
toOrthographic = true
): Promise<void> {
2024-03-02 08:20:50 +11:00
if (this.syncDirection === 'engineToClient')
console.warn(
'tweenCameraToQuaternion not design to work with engineToClient syncDirection.'
)
const isVertical = isQuaternionVertical(targetQuaternion)
let remainingDuration = duration
if (isVertical) {
remainingDuration = duration * 0.5
const orbitRotationDuration = duration * 0.65
let targetAngle = -Math.PI / 2
const v = new Vector3(0, 0, 1).applyQuaternion(targetQuaternion)
if (v.z < 0) targetAngle = Math.PI / 2
await this.tweenCamToNegYAxis(targetAngle, orbitRotationDuration)
}
await this._tweenCameraToQuaternion(
targetQuaternion,
targetPosition,
remainingDuration,
toOrthographic
)
}
_tweenCameraToQuaternion(
targetQuaternion: Quaternion,
targetPosition: Vector3,
duration = 500,
toOrthographic = false
): Promise<void> {
return new Promise((resolve) => {
const camera = this.camera
this._isCamMovingCallback(true, true)
const initialQuaternion = camera.quaternion.clone()
const initialTarget = this.target.clone()
const isVertical = isQuaternionVertical(targetQuaternion)
let tweenEnd = isVertical ? 0.99 : 1
const tempVec = new Vector3()
const initialDistance = initialTarget.distanceTo(camera.position.clone())
const cameraAtTime = (animationProgress: number /* 0 - 1 */) => {
const currentQ = tempQuaternion.slerpQuaternions(
initialQuaternion,
targetQuaternion,
animationProgress
)
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
const up = new Vector3(0, 0, 1).applyQuaternion(currentQ)
this.camera.up.copy(up)
const currentTarget = tempVec.lerpVectors(
initialTarget,
targetPosition,
animationProgress
)
if (this.camera instanceof PerspectiveCamera)
// changing the camera position back when it's orthographic doesn't do anything
// and it messes up animating back to perspective later
this.camera.position
.set(0, 0, 1)
.applyQuaternion(currentQ)
.multiplyScalar(initialDistance)
.add(currentTarget)
this.camera.up.set(0, 1, 0).applyQuaternion(currentQ).normalize()
this.camera.quaternion.copy(currentQ)
this.target.copy(currentTarget)
this.camera.updateProjectionMatrix()
this.update()
this.onCameraChange()
}
const onComplete = async () => {
if (isReducedMotion() && toOrthographic) {
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
cameraAtTime(0.9999)
this.useOrthographicCamera()
} else if (toOrthographic) {
await this.animateToOrthographic()
}
this.enableRotate = false
this._isCamMovingCallback(false, true)
resolve()
}
if (isReducedMotion()) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
onComplete()
return
}
new TWEEN.Tween({ t: 0 })
.to({ t: tweenEnd }, duration)
.easing(TWEEN.Easing.Quadratic.InOut)
.onUpdate(({ t }) => cameraAtTime(t))
.onComplete(toSync(onComplete, reportRejection))
.start()
})
}
animateToOrthographic = () =>
new Promise((resolve) => {
2024-03-02 08:20:50 +11:00
if (this.syncDirection === 'engineToClient')
console.warn(
'animate To Orthographic not design to work with engineToClient syncDirection.'
)
this.isFovAnimationInProgress = true
let currentFov = this.lastPerspectiveFov
this.perspectiveFovBeforeOrtho = currentFov
const targetFov = ORTHOGRAPHIC_MAGIC_FOV
const fovAnimationStep = (currentFov - targetFov) / FRAMES_TO_ANIMATE_IN
let frameWaitOnFinish = 10
const animateFovChange = () => {
if (this.camera instanceof PerspectiveCamera) {
if (this.camera.fov > targetFov) {
// Decrease the FOV
currentFov = Math.max(currentFov - fovAnimationStep, targetFov)
this.camera.updateProjectionMatrix()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.dollyZoom(currentFov)
requestAnimationFrame(animateFovChange) // Continue the animation
} else if (frameWaitOnFinish > 0) {
frameWaitOnFinish--
requestAnimationFrame(animateFovChange) // Continue the animation
} else {
// Once the target FOV is reached, switch to the orthographic camera
// Needs to wait a couple frames after the FOV animation is complete
this.useOrthographicCamera()
this.isFovAnimationInProgress = false
resolve(true)
}
}
}
animateFovChange() // Start the animation
})
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
animateToPerspective = (targetCamUp = new Vector3(0, 0, 1)) =>
new Promise((resolve) => {
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
if (this.syncDirection === 'engineToClient') {
2024-03-02 08:20:50 +11:00
console.warn(
'animate To Perspective not design to work with engineToClient syncDirection.'
)
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
}
this.isFovAnimationInProgress = true
const targetFov = this.perspectiveFovBeforeOrtho // Target FOV for perspective
this.lastPerspectiveFov = ORTHOGRAPHIC_MAGIC_FOV
let currentFov = ORTHOGRAPHIC_MAGIC_FOV
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
const initialCameraUp = this.camera.up.clone()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.usePerspectiveCamera()
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
const tempVec = new Vector3()
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
const cameraAtTime = (t: number) => {
currentFov =
this.lastPerspectiveFov + (targetFov - this.lastPerspectiveFov) * t
const currentUp = tempVec.lerpVectors(initialCameraUp, targetCamUp, t)
this.camera.up.copy(currentUp)
// eslint-disable-next-line @typescript-eslint/no-floating-promises
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
this.dollyZoom(currentFov)
}
SketchOnFace UI (#1664) * always enter edit mode * initial blocking of extra code-mirror updates * dry out code * rejig selections * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * clean up * stream clean up * update export * sketch mode can be entered and exited for extrude faces But has bugs * startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit 406fca4c553681fbad882167a9c1ab380af52899. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * remove comment * add sketch on face e2e test * tweenCamToNegYAxis should respect reduced motion * initial sketch on face working with test * remove temporary toolbar button and xState flow * un-used vars * snapshot test tweak * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * type tidy up * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit c39b8ebf954fa63556e21da081031b8acd77c909. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" This reverts commit fecf6f490af6ced34959653984108958fb504f82. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * rename * sketch on sketch on sketch * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * typo * startSketchOn Endcaps end works, start is weird still * clear selections for entity_ids that are not recognised * fix sketch on end cap of second order extrustion * tiny clean up * fix sketch on close segment/face * clean up 'lastCodeMirrorSelectionUpdatedFromScene' * add code mode test for sketchOnExtrudedFace * make end cap selection more robust * update js artifacts for extrudes * update kcl docs * clean up --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
const onComplete = () => {
this.isFovAnimationInProgress = false
resolve(true)
}
new TWEEN.Tween({ t: 0 })
.to({ t: 1 }, isReducedMotion() ? 50 : FRAMES_TO_ANIMATE_IN * 16) // Assuming 60fps, hence 16ms per frame
.easing(TWEEN.Easing.Quadratic.InOut)
.onUpdate(({ t }) => cameraAtTime(t))
.onComplete(onComplete)
.start()
})
snapToPerspectiveBeforeHandingBackControlToEngine = async (
targetCamUp = new Vector3(0, 0, 1)
) => {
if (this.syncDirection === 'engineToClient') {
console.warn(
'animate To Perspective not design to work with engineToClient syncDirection.'
)
}
this.isFovAnimationInProgress = true
const targetFov = this.perspectiveFovBeforeOrtho // Target FOV for perspective
let currentFov = ORTHOGRAPHIC_MAGIC_FOV
const initialCameraUp = this.camera.up.clone()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.usePerspectiveCamera()
const tempVec = new Vector3()
currentFov = this.lastPerspectiveFov + (targetFov - this.lastPerspectiveFov)
const currentUp = tempVec.lerpVectors(initialCameraUp, targetCamUp, 1)
this.camera.up.copy(currentUp)
await this.dollyZoom(currentFov, true)
this.isFovAnimationInProgress = false
}
Migrate to new split sidebar from accordion-like panes (#2063) * Split ModelingSidebar out into own component * Consolidate all ModelingPane components and config * Make ModelingSidebar a directory of components and config * Remove unused components * Proper pane styling * Make tooltip configurable to visually appear on hover only * Remove debug panel from App * Fix current tests * Rename to more intuitive names * Fix useEffect loop bug with showDebugPanel * Fix snapshot tests * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Merge branch 'main' into franknoirot/sidebar * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * Maybe some flakiness in the validation initScripts? * Avoid test flakiness by waiting for more signals that loading is completed * Don't assert, just wait for the element to be enabled * Don't let users accidentally click the gap between the pane and the side of the window * Firm up extrude from command bar test * Get rid of unused imports * Add setting to disable blinking cursor (#2065) * Add support for "current" marker in command bar for boolean settings * Add a cursorBlinking setting * Rename setting to blinkingCursor, honor it in the UI * Fix scroll layout bug in settings modal * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * CSS tweaks * Allow settings hotkey within KclEditorPane * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Rerun CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * Ensure the KCL code panel is closed for camera movement test * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Make sure that the camera position inputs are ready to be read from * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Remove repeat awaits * Make camera position fields in debug pane update when the pane is initialized * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Undo that CameraControls change because it made other things weird * retry fixing camera move test * Fix race condition where cam setting cam position parts were overwriting each other * Rerun CI * Rerun CI --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-04-15 12:04:17 -04:00
get reactCameraProperties(): ReactCameraProperties {
return {
type: this.isPerspective ? 'perspective' : 'orthographic',
[this.isPerspective ? 'fov' : 'zoom']:
this.camera instanceof PerspectiveCamera
? this.camera.fov
: this.camera.zoom,
position: [
roundOff(this.camera.position.x, 2),
roundOff(this.camera.position.y, 2),
roundOff(this.camera.position.z, 2),
],
2024-06-05 14:43:12 +02:00
target: [
roundOff(this.target.x, 2),
roundOff(this.target.y, 2),
roundOff(this.target.z, 2),
],
Migrate to new split sidebar from accordion-like panes (#2063) * Split ModelingSidebar out into own component * Consolidate all ModelingPane components and config * Make ModelingSidebar a directory of components and config * Remove unused components * Proper pane styling * Make tooltip configurable to visually appear on hover only * Remove debug panel from App * Fix current tests * Rename to more intuitive names * Fix useEffect loop bug with showDebugPanel * Fix snapshot tests * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Merge branch 'main' into franknoirot/sidebar * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * Maybe some flakiness in the validation initScripts? * Avoid test flakiness by waiting for more signals that loading is completed * Don't assert, just wait for the element to be enabled * Don't let users accidentally click the gap between the pane and the side of the window * Firm up extrude from command bar test * Get rid of unused imports * Add setting to disable blinking cursor (#2065) * Add support for "current" marker in command bar for boolean settings * Add a cursorBlinking setting * Rename setting to blinkingCursor, honor it in the UI * Fix scroll layout bug in settings modal * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * CSS tweaks * Allow settings hotkey within KclEditorPane * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Rerun CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * Ensure the KCL code panel is closed for camera movement test * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Make sure that the camera position inputs are ready to be read from * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Remove repeat awaits * Make camera position fields in debug pane update when the pane is initialized * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Undo that CameraControls change because it made other things weird * retry fixing camera move test * Fix race condition where cam setting cam position parts were overwriting each other * Rerun CI * Rerun CI --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-04-15 12:04:17 -04:00
quaternion: [
roundOff(this.camera.quaternion.x, 2),
roundOff(this.camera.quaternion.y, 2),
roundOff(this.camera.quaternion.z, 2),
roundOff(this.camera.quaternion.w, 2),
],
}
}
reactCameraPropertiesCallback: (a: ReactCameraProperties) => void = () => {}
setReactCameraPropertiesCallback = (
cb: (a: ReactCameraProperties) => void
) => {
this.reactCameraPropertiesCallback = cb
}
deferReactUpdate = throttle((a: ReactCameraProperties) => {
this.reactCameraPropertiesCallback(a)
}, 200)
onCameraChange = (forceUpdate = false) => {
const distance = this.target.distanceTo(this.camera.position)
if (this.camera.far / 2.1 < distance || this.camera.far / 1.9 > distance) {
this.camera.far = distance * 2
this.camera.near = distance / 10
this.camera.updateProjectionMatrix()
}
if (this.syncDirection === 'clientToEngine' || forceUpdate)
this.throttledUpdateEngineCamera({
2024-03-02 08:20:50 +11:00
quaternion: this.camera.quaternion,
position: this.camera.position,
zoom: this.camera.zoom,
isPerspective: this.isPerspective,
target: this.target,
})
Migrate to new split sidebar from accordion-like panes (#2063) * Split ModelingSidebar out into own component * Consolidate all ModelingPane components and config * Make ModelingSidebar a directory of components and config * Remove unused components * Proper pane styling * Make tooltip configurable to visually appear on hover only * Remove debug panel from App * Fix current tests * Rename to more intuitive names * Fix useEffect loop bug with showDebugPanel * Fix snapshot tests * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Merge branch 'main' into franknoirot/sidebar * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * Maybe some flakiness in the validation initScripts? * Avoid test flakiness by waiting for more signals that loading is completed * Don't assert, just wait for the element to be enabled * Don't let users accidentally click the gap between the pane and the side of the window * Firm up extrude from command bar test * Get rid of unused imports * Add setting to disable blinking cursor (#2065) * Add support for "current" marker in command bar for boolean settings * Add a cursorBlinking setting * Rename setting to blinkingCursor, honor it in the UI * Fix scroll layout bug in settings modal * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * CSS tweaks * Allow settings hotkey within KclEditorPane * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Rerun CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * Ensure the KCL code panel is closed for camera movement test * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Make sure that the camera position inputs are ready to be read from * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Remove repeat awaits * Make camera position fields in debug pane update when the pane is initialized * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Undo that CameraControls change because it made other things weird * retry fixing camera move test * Fix race condition where cam setting cam position parts were overwriting each other * Rerun CI * Rerun CI --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-04-15 12:04:17 -04:00
this.deferReactUpdate(this.reactCameraProperties)
Object.values(this._camChangeCallbacks).forEach((cb) => cb())
}
getInteractionType = (event: MouseEvent) =>
2024-03-02 08:20:50 +11:00
_getInteractionType(
this.interactionGuards,
event,
this.enablePan,
this.enableRotate,
this.enableZoom
)
}
2024-03-02 08:20:50 +11:00
// Pure function helpers
function calculateNearFarFromFOV(fov: number) {
// const nearFarRatio = (fov - 3) / (45 - 3)
// const z_near = 0.1 + nearFarRatio * (5 - 0.1)
// const z_far = 1000 + nearFarRatio * (100000 - 1000)
return { z_near: 0.01, z_far: 1000 }
}
function convertThreeCamValuesToEngineCam({
target,
position,
quaternion,
zoom,
isPerspective,
}: ThreeCamValues): {
center: Vector3
up: Vector3
vantage: Vector3
} {
const euler = new Euler().setFromQuaternion(quaternion, 'XYZ')
const upVector = new Vector3(0, 1, 0).applyEuler(euler).normalize()
if (isPerspective) {
return {
center: target,
up: upVector,
vantage: position,
}
}
// re-implementing stuff here, though this is a bunch of Mike's code
// if we need to pull him in again, at least it will be familiar to him
// and it's all simple functions.
interface Coord3d {
x: number
y: number
z: number
}
function buildLookAt(distance: number, center: Coord3d, eye: Coord3d) {
const eyeVector = normalized(sub(eye, center))
return { center: center, eye: add(center, mult(eyeVector, distance)) }
}
function mult(vecA: Coord3d, sc: number): Coord3d {
return { x: vecA.x * sc, y: vecA.y * sc, z: vecA.z * sc }
}
function add(vecA: Coord3d, vecB: Coord3d): Coord3d {
return { x: vecA.x + vecB.x, y: vecA.y + vecB.y, z: vecA.z + vecB.z }
}
function sub(vecA: Coord3d, vecB: Coord3d): Coord3d {
return { x: vecA.x - vecB.x, y: vecA.y - vecB.y, z: vecA.z - vecB.z }
}
function dot(vecA: Coord3d, vecB: Coord3d) {
return vecA.x * vecB.x + vecA.y * vecB.y + vecA.z * vecB.z
}
function length(vecA: Coord3d) {
return Math.sqrt(dot(vecA, vecA))
}
function normalized(vecA: Coord3d) {
return mult(vecA, 1.0 / length(vecA))
}
const lookAt = buildLookAt(64 / zoom, target, position)
return {
center: new Vector3(lookAt.center.x, lookAt.center.y, lookAt.center.z),
up: new Vector3(upVector.x, upVector.y, upVector.z),
vantage: new Vector3(lookAt.eye.x, lookAt.eye.y, lookAt.eye.z),
}
}
function _lookAt(position: Vector3, target: Vector3, up: Vector3): Quaternion {
// Direction from position to target, normalized.
let direction = new Vector3().subVectors(target, position).normalize()
// Calculate a new "effective" up vector that is orthogonal to the direction.
// This step ensures that the up vector does not affect the direction the camera is looking.
let right = new Vector3().crossVectors(direction, up).normalize()
let orthogonalUp = new Vector3().crossVectors(right, direction).normalize()
// Create a lookAt matrix using the position, and the recalculated orthogonal up vector.
let lookAtMatrix = new Matrix4()
lookAtMatrix.lookAt(position, target, orthogonalUp)
// Create a quaternion from the lookAt matrix.
let quaternion = new Quaternion().setFromRotationMatrix(lookAtMatrix)
return quaternion
}
2024-03-02 08:20:50 +11:00
function _getInteractionType(
interactionGuards: MouseGuard,
event: MouseEvent | WheelEvent,
2024-03-02 08:20:50 +11:00
enablePan: boolean,
enableRotate: boolean,
enableZoom: boolean
): interactionType | 'none' {
if (event instanceof WheelEvent) {
if (enableZoom && interactionGuards.zoom.scrollCallback(event))
return 'zoom'
} else {
if (enablePan && interactionGuards.pan.callback(event)) return 'pan'
if (enableRotate && interactionGuards.rotate.callback(event))
return 'rotate'
if (enableZoom && interactionGuards.zoom.dragCallback(event)) return 'zoom'
}
return 'none'
2024-03-02 08:20:50 +11:00
}
/**
* Tells the engine to fire it's animation waits for it to finish and then requests camera settings
* to ensure the client-side camera is synchronized with the engine's camera state.
*
* @param engineCommandManager Our websocket singleton
* @param entityId - The ID of face or sketchPlane.
*/
export async function letEngineAnimateAndSyncCamAfter(
engineCommandManager: EngineCommandManager,
entityId: string
) {
await engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'enable_sketch_mode',
adjust_camera: true,
animated: !isReducedMotion(),
ortho: true,
entity_id: entityId,
},
})
// wait 600ms (animation takes 500, + 100 for safety)
await new Promise((resolve) =>
setTimeout(resolve, isReducedMotion() ? 100 : 600)
)
await engineCommandManager.sendSceneCommand({
// CameraControls subscribes to default_camera_get_settings response events
// firing this at connection ensure the camera's are synced initially
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_get_settings',
},
})
}