Alexander Rose 6 rokov pred
rodič
commit
1574ad5e9e

+ 15 - 4
src/mol-canvas3d/camera.ts

@@ -42,6 +42,8 @@ class Camera implements Object3D {
 
     private prevProjection = Mat4.identity();
     private prevView = Mat4.identity();
+    private deltaDirection = Vec3.zero();
+    private newPosition = Vec3.zero();
 
     updateMatrices() {
         const snapshot = this.state as Camera.Snapshot;
@@ -83,10 +85,19 @@ class Camera implements Object3D {
     }
 
     focus(target: Vec3, radius: number) {
-        const position = Vec3.zero();
-        Vec3.scale(position, this.state.direction, -radius);
-        Vec3.add(position, position, target);
-        this.setState({ target, position });
+        const fov = this.state.fov
+        const { width, height } = this.viewport
+        const aspect = width / height
+        const aspectFactor = (height < width ? 1 : aspect)
+        const currentDistance = Vec3.distance(this.state.position, target)
+        const targetDistance = Math.abs((radius / aspectFactor) / Math.sin(fov / 2))
+        const deltaDistance = Math.abs(currentDistance - targetDistance)
+
+        Vec3.sub(this.deltaDirection, this.state.position, target)
+        Vec3.setMagnitude(this.deltaDirection, this.state.direction, deltaDistance)
+        if (currentDistance < targetDistance) Vec3.negate(this.deltaDirection, this.deltaDirection)
+        Vec3.add(this.newPosition, this.state.position, this.deltaDirection)
+        this.setState({ target, position: this.newPosition })
     }
 
     // lookAt(target: Vec3) {

+ 1 - 1
src/mol-canvas3d/camera/util.ts

@@ -42,7 +42,7 @@ export namespace Viewport {
 
 const tmpVec3 = Vec3.zero()
 
-/** Modifies the direction & up vectors in place */
+/** Modifies the direction & up vectors in place, both are normalized */
 export function cameraLookAt(position: Vec3, up: Vec3, direction: Vec3, target: Vec3) {
     Vec3.sub(tmpVec3, target, position)
     Vec3.normalize(tmpVec3, tmpVec3)

+ 3 - 3
src/mol-canvas3d/canvas3d.ts

@@ -62,6 +62,7 @@ interface Canvas3D {
     readonly didDraw: BehaviorSubject<now.Timestamp>
 
     handleResize: () => void
+    /** Focuses camera on scene's bounding sphere, centered and zoomed. */
     resetCamera: () => void
     readonly camera: Camera
     downloadScreenshot: () => void
@@ -220,8 +221,6 @@ namespace Canvas3D {
             if (drawPending) return
             drawPending = true
             forceNextDraw = !!force;
-            // The animation frame is being requested by animate already.
-            // window.requestAnimationFrame(() => draw(force))
         }
 
         function animate() {
@@ -344,7 +343,8 @@ namespace Canvas3D {
 
             handleResize,
             resetCamera: () => {
-                // TODO
+                camera.focus(scene.boundingSphere.center, scene.boundingSphere.radius)
+                requestDraw(true);
             },
             camera,
             downloadScreenshot: () => {

+ 12 - 11
src/mol-gl/scene.ts

@@ -12,9 +12,9 @@ import { Object3D } from './object3d';
 import { Sphere3D } from 'mol-math/geometry';
 import { Vec3 } from 'mol-math/linear-algebra';
 
-function calculateBoundingSphere(renderableMap: Map<RenderObject, Renderable<RenderableValues & BaseValues>>): Sphere3D {
+function calculateBoundingSphere(renderableMap: Map<RenderObject, Renderable<RenderableValues & BaseValues>>, boundingSphere: Sphere3D): Sphere3D {
     let count = 0
-    const center = Vec3.zero()
+    const center = Vec3.set(boundingSphere.center, 0, 0, 0)
     renderableMap.forEach(r => {
         if (r.boundingSphere.radius) {
             Vec3.add(center, center, r.boundingSphere.center)
@@ -31,8 +31,9 @@ function calculateBoundingSphere(renderableMap: Map<RenderObject, Renderable<Ren
             radius = Math.max(radius, Vec3.distance(center, r.boundingSphere.center) + r.boundingSphere.radius)
         }
     })
+    boundingSphere.radius = radius
 
-    return { center, radius };
+    return boundingSphere;
 }
 
 interface Scene extends Object3D {
@@ -51,7 +52,8 @@ interface Scene extends Object3D {
 namespace Scene {
     export function create(ctx: WebGLContext): Scene {
         const renderableMap = new Map<RenderObject, Renderable<RenderableValues & BaseValues>>()
-        let boundingSphere: Sphere3D | undefined
+        const boundingSphere = Sphere3D.zero()
+        let boundingSphereDirty = true
 
         const object3d = Object3D.create()
 
@@ -64,13 +66,13 @@ namespace Scene {
             update: () => {
                 Object3D.update(object3d)
                 renderableMap.forEach(r => r.update())
-                boundingSphere = undefined
+                boundingSphereDirty = true
             },
 
             add: (o: RenderObject) => {
                 if (!renderableMap.has(o)) {
                     renderableMap.set(o, createRenderable(ctx, o))
-                    boundingSphere = undefined
+                    boundingSphereDirty = true
                 } else {
                     console.warn(`RenderObject with id '${o.id}' already present`)
                 }
@@ -80,13 +82,13 @@ namespace Scene {
                 if (renderable) {
                     renderable.dispose()
                     renderableMap.delete(o)
-                    boundingSphere = undefined
+                    boundingSphereDirty = true
                 }
             },
             clear: () => {
                 renderableMap.forEach(renderable => renderable.dispose())
                 renderableMap.clear()
-                boundingSphere = undefined
+                boundingSphereDirty = true
             },
             forEach: (callbackFn: (value: Renderable<any>, key: RenderObject) => void) => {
                 renderableMap.forEach(callbackFn)
@@ -105,9 +107,8 @@ namespace Scene {
                 return renderableMap.size
             },
             get boundingSphere() {
-                if (boundingSphere) return boundingSphere
-                // TODO avoid object creation
-                boundingSphere = calculateBoundingSphere(renderableMap)
+                if (boundingSphereDirty) calculateBoundingSphere(renderableMap, boundingSphere)
+                boundingSphereDirty = false
                 return boundingSphere
             }
         }

+ 7 - 0
src/mol-math/geometry/primitives/box3d.ts

@@ -15,6 +15,13 @@ namespace Box3D {
     export function create(min: Vec3, max: Vec3): Box3D { return { min, max }; }
     export function empty(): Box3D { return { min: Vec3.zero(), max: Vec3.zero() }; }
 
+    export function clone(a: Box3D): Box3D {
+        const out = empty();
+        Vec3.copy(out.min, a.min);
+        Vec3.copy(out.max, a.max);
+        return out;
+    }
+
     export function computeBounding(data: PositionData): Box3D {
         const min = Vec3.create(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
         const max = Vec3.create(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);

+ 7 - 0
src/mol-math/geometry/primitives/sphere3d.ts

@@ -15,6 +15,13 @@ namespace Sphere3D {
     export function create(center: Vec3, radius: number): Sphere3D { return { center, radius }; }
     export function zero(): Sphere3D { return { center: Vec3.zero(), radius: 0 }; }
 
+    export function clone(a: Sphere3D): Sphere3D {
+        const out = zero();
+        Vec3.copy(out.center, a.center);
+        out.radius = a.radius
+        return out;
+    }
+
     export function copy(out: Sphere3D, a: Sphere3D) {
         Vec3.copy(out.center, a.center)
         out.radius = a.radius

+ 1 - 10
src/mol-plugin/behavior/static/camera.ts

@@ -6,7 +6,6 @@
 
 import { PluginContext } from 'mol-plugin/context';
 import { PluginCommands } from 'mol-plugin/command';
-import { PluginStateObject as SO } from '../../state/objects';
 import { CameraSnapshotManager } from 'mol-plugin/state/camera';
 
 export function registerDefault(ctx: PluginContext) {
@@ -17,15 +16,7 @@ export function registerDefault(ctx: PluginContext) {
 
 export function Reset(ctx: PluginContext) {
     PluginCommands.Camera.Reset.subscribe(ctx, () => {
-        const sel = ctx.state.dataState.select(q => q.root.subtree().ofType(SO.Molecule.Structure));
-        if (!sel.length) return;
-
-        const center = (sel[0].obj! as SO.Molecule.Structure).data.boundary.sphere.center;
-        ctx.canvas3d.camera.setState({ target: center });
-        ctx.canvas3d.requestDraw(true);
-
-        // TODO
-        // ctx.canvas3d.resetCamera();
+        ctx.canvas3d.resetCamera();
     })
 }