From fa63209384d37eb17aa7c75e450045629533af3d Mon Sep 17 00:00:00 2001 From: dsehnal Date: Sat, 30 May 2026 17:02:09 +0200 Subject: [PATCH] refactoring --- src/mol-canvas3d/camera/transition.ts | 8 ++++-- src/mol-math/linear-algebra/3d/mat3.ts | 4 +++ src/mol-math/linear-algebra/3d/mat4.ts | 4 +++ src/mol-math/linear-algebra/3d/quat.ts | 4 +++ src/mol-math/linear-algebra/3d/vec2.ts | 4 +++ src/mol-math/linear-algebra/3d/vec3.ts | 4 +++ src/mol-math/linear-algebra/3d/vec4.ts | 4 +++ src/mol-plugin-state/manager/camera.ts | 38 +++++++++++++++----------- 8 files changed, 51 insertions(+), 19 deletions(-) diff --git a/src/mol-canvas3d/camera/transition.ts b/src/mol-canvas3d/camera/transition.ts index e1c74b82a..44ddac0cb 100644 --- a/src/mol-canvas3d/camera/transition.ts +++ b/src/mol-canvas3d/camera/transition.ts @@ -13,7 +13,9 @@ import { EasingFunction, getEasingFn } from '../../mol-math/easing'; export { CameraTransitionManager }; export interface CameraTransitionOptions { + /** If present, approximates the transion between, [current] -> [keyframes] -> -> [target] */ keyframes?: CameraTransitionManager.TransitionKeyframes, + /** Global easing, if easing is specified for keyframes, the "end" frame value is used */ easing?: EasingFunction } @@ -123,7 +125,7 @@ namespace CameraTransitionManager { let tStart = 0; let tEnd = 1; - let easingKindStart = options?.easing; + let easingKind = options?.easing; const keyframes = options?.keyframes; if (keyframes && keyframes.length > 0) { @@ -132,7 +134,6 @@ namespace CameraTransitionManager { if (t_ >= keyframe.t) { sourcePartial = keyframe.snapshot; tStart = keyframe.t; - easingKindStart = keyframe.easing ?? easingKindStart; break; } } @@ -141,12 +142,13 @@ namespace CameraTransitionManager { if (keyframe.t >= t_) { targetPartial = keyframe.snapshot; tEnd = keyframe.t; + easingKind = keyframe.easing ?? easingKind; break; } } } - const easing = getEasingFn(easingKindStart); + const easing = getEasingFn(easingKind); const t = easing((t_ - tStart) / (tEnd - tStart)); if (!_tempSource) _tempSource = Camera.createDefaultSnapshot(); diff --git a/src/mol-math/linear-algebra/3d/mat3.ts b/src/mol-math/linear-algebra/3d/mat3.ts index 46bff09a1..61c11014d 100644 --- a/src/mol-math/linear-algebra/3d/mat3.ts +++ b/src/mol-math/linear-algebra/3d/mat3.ts @@ -150,6 +150,10 @@ namespace Mat3 { return areEqual(m, _id, typeof eps === 'undefined' ? EPSILON : eps); } + export function is(a: any): a is Mat3 { + return Array.isArray(a) && a.length === 9; + } + export function hasNaN(m: Mat3) { for (let i = 0; i < 9; i++) if (Number.isNaN(m[i])) return true; return false; diff --git a/src/mol-math/linear-algebra/3d/mat4.ts b/src/mol-math/linear-algebra/3d/mat4.ts index eca0d0747..4166bf981 100644 --- a/src/mol-math/linear-algebra/3d/mat4.ts +++ b/src/mol-math/linear-algebra/3d/mat4.ts @@ -110,6 +110,10 @@ namespace Mat4 { return areEqual(m, _id, typeof eps === 'undefined' ? EPSILON : eps); } + export function is(a: any): a is Mat4 { + return Array.isArray(a) && a.length === 16; + } + export function hasNaN(m: Mat4) { for (let i = 0; i < 16; i++) if (Number.isNaN(m[i])) return true; return false; diff --git a/src/mol-math/linear-algebra/3d/quat.ts b/src/mol-math/linear-algebra/3d/quat.ts index 32f766d50..a119f8a11 100644 --- a/src/mol-math/linear-algebra/3d/quat.ts +++ b/src/mol-math/linear-algebra/3d/quat.ts @@ -71,6 +71,10 @@ namespace Quat { return out; } + export function is(a: any): a is Quat { + return Array.isArray(a) && a.length === 4; + } + export function setAxisAngle(out: Quat, axis: Vec3, rad: number) { rad = rad * 0.5; const s = Math.sin(rad); diff --git a/src/mol-math/linear-algebra/3d/vec2.ts b/src/mol-math/linear-algebra/3d/vec2.ts index 258170e63..3f9e8ce1a 100644 --- a/src/mol-math/linear-algebra/3d/vec2.ts +++ b/src/mol-math/linear-algebra/3d/vec2.ts @@ -58,6 +58,10 @@ namespace Vec2 { return Number.isNaN(a[0]) || Number.isNaN(a[1]); } + export function is(a: any): a is Vec2 { + return Array.isArray(a) && a.length === 2; + } + export function toArray(a: Vec2, out: T, offset: number) { out[offset + 0] = a[0]; out[offset + 1] = a[1]; diff --git a/src/mol-math/linear-algebra/3d/vec3.ts b/src/mol-math/linear-algebra/3d/vec3.ts index 2bfe05fb9..6a5969461 100644 --- a/src/mol-math/linear-algebra/3d/vec3.ts +++ b/src/mol-math/linear-algebra/3d/vec3.ts @@ -48,6 +48,10 @@ export namespace Vec3 { return out; } + export function is(a: any): a is Vec3 { + return Array.isArray(a) && a.length === 3; + } + export function isFinite(a: Vec3): boolean { return _isFinite(a[0]) && _isFinite(a[1]) && _isFinite(a[2]); } diff --git a/src/mol-math/linear-algebra/3d/vec4.ts b/src/mol-math/linear-algebra/3d/vec4.ts index 1e0e844ba..90a64be0c 100644 --- a/src/mol-math/linear-algebra/3d/vec4.ts +++ b/src/mol-math/linear-algebra/3d/vec4.ts @@ -71,6 +71,10 @@ namespace Vec4 { return Number.isNaN(a[0]) || Number.isNaN(a[1]) || Number.isNaN(a[2]) || Number.isNaN(a[3]); } + export function is(a: any): a is Vec4 { + return Array.isArray(a) && a.length === 4; + } + export function toArray(a: Vec4, out: T, offset: number) { out[offset + 0] = a[0]; out[offset + 1] = a[1]; diff --git a/src/mol-plugin-state/manager/camera.ts b/src/mol-plugin-state/manager/camera.ts index dd0dc785c..5fccee993 100644 --- a/src/mol-plugin-state/manager/camera.ts +++ b/src/mol-plugin-state/manager/camera.ts @@ -35,12 +35,14 @@ export const DefaultCameraFocusOptions = { } }; -export type CameraFocusOptions = typeof DefaultCameraFocusOptions -export type CameraFocusLociOptions = CameraFocusOptions & { - optimizeDirection?: boolean, - optimizeDirectionUp?: Vec3, -} +export const DefaultCameraFocusLociOptions = { + ...DefaultCameraFocusOptions, + optimizeDirection: false, + optimizeDirectionUp: 'current' as 'current' | 'default' | Vec3, +}; +export type CameraFocusOptions = typeof DefaultCameraFocusOptions; +export type CameraFocusLociOptions = typeof DefaultCameraFocusLociOptions; export class CameraManager { private boundaryHelper = new BoundaryHelper('98'); @@ -97,7 +99,7 @@ export class CameraManager { return sphere; } - private focusLociOptimized(loci: Loci | Loci[], options?: Partial) { + private focusLociOptimized(loci: Loci | Loci[], options?: Partial) { const { canvas3d } = this.plugin; if (!canvas3d) return; @@ -144,7 +146,13 @@ export class CameraManager { } Vec3.negate(direction, direction); - return canvas3d.camera.getInvariantFocus(sphere.center, radius, options?.up ?? Vec3.unitY, direction); + const upVector = options?.optimizeDirectionUp === 'default' + ? Vec3.unitY + : Vec3.is(options?.optimizeDirectionUp) ? options.optimizeDirectionUp : undefined; + if (upVector) { + return canvas3d.camera.getInvariantFocus(sphere.center, radius, upVector as Vec3, direction); + } + return canvas3d.camera.getFocus(sphere.center, radius, undefined, direction); } private focusLociBase(loci: Loci | Loci[], options?: Partial) { @@ -157,17 +165,15 @@ export class CameraManager { focusLoci(loci: Loci | Loci[], options?: Partial) { if (!this.plugin.canvas3d) return; + const options_ = { ...DefaultCameraFocusLociOptions, ...options }; let snapshot: Partial | undefined; - if (options?.optimizeDirection) { - snapshot = this.focusLociOptimized(loci, { - ...options, - up: options.optimizeDirectionUp, - }); + if (options_.optimizeDirection) { + snapshot = this.focusLociOptimized(loci, options_); } else { - snapshot = this.focusLociBase(loci, options); + snapshot = this.focusLociBase(loci, options_); } - this.focusSnapshot(snapshot, options); + this.focusSnapshot(snapshot, options_); } focusSpheres(xs: ReadonlyArray, sphere: (t: T) => Sphere3D | undefined, options?: Partial & { principalAxes?: PrincipalAxes, positionToFlip?: Vec3 }) { @@ -229,9 +235,9 @@ export class CameraManager { this.plugin.canvas3d.requestCameraReset({ snapshot, durationMs: df * durationMs, - easing: 'cubic-out', keyframes: t > 0.05 ? [ - { t, snapshot: zoomOut, easing: 'cubic-in' }, + { t, snapshot: zoomOut, easing: 'cubic-out' }, + { t: 1, snapshot, easing: 'cubic-in' }, ] : undefined }); }