Parcourir la source

added explode-units anim and removed old anim behavior

Alexander Rose il y a 6 ans
Parent
commit
a0583118c9

+ 0 - 2
src/mol-plugin/behavior.ts

@@ -14,7 +14,6 @@ import * as StaticMisc from './behavior/static/misc'
 import * as DynamicRepresentation from './behavior/dynamic/representation'
 import * as DynamicCamera from './behavior/dynamic/camera'
 import * as DynamicCustomProps from './behavior/dynamic/custom-props'
-import * as DynamicAnimation from './behavior/dynamic/animation'
 import * as DynamicLabels from './behavior/dynamic/labels'
 
 export const BuiltInPluginBehaviors = {
@@ -28,6 +27,5 @@ export const PluginBehaviors = {
     Representation: DynamicRepresentation,
     Camera: DynamicCamera,
     CustomProps: DynamicCustomProps,
-    Animation: DynamicAnimation,
     Labels: DynamicLabels
 }

+ 0 - 190
src/mol-plugin/behavior/dynamic/animation.ts

@@ -1,190 +0,0 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
-
-import { PluginContext } from 'mol-plugin/context';
-import { PluginBehavior } from '../behavior';
-import { ParamDefinition as PD } from 'mol-util/param-definition'
-import { degToRad } from 'mol-math/misc';
-import { Mat4, Vec3 } from 'mol-math/linear-algebra';
-import { PluginStateObject as SO, PluginStateObject } from '../../state/objects';
-import { StateObjectCell, State, StateSelection } from 'mol-state';
-import { StructureUnitTransforms } from 'mol-model/structure/structure/util/unit-transforms';
-import { UUID } from 'mol-util';
-
-const StructureAnimationParams = {
-    rotate: PD.Boolean(false),
-    rotateValue: PD.Numeric(0, { min: 0, max: 360, step: 0.1 }),
-    explode: PD.Boolean(false),
-    explodeValue: PD.Numeric(0, { min: 0, max: 100, step: 0.1 }),
-}
-type StructureAnimationProps = PD.Values<typeof StructureAnimationParams>
-
-/**
- * TODO
- * - animation class is just for testing purposes, needs better API
- */
-export const StructureAnimation = PluginBehavior.create<StructureAnimationProps>({
-    name: 'structure-animation',
-    category: 'representation',
-    display: { name: 'Structure Animation' },
-    canAutoUpdate: () => true,
-    ctor: class extends PluginBehavior.Handler<StructureAnimationProps> {
-        private tmpMat = Mat4.identity()
-        private rotMat = Mat4.identity()
-        private transMat = Mat4.identity()
-        private animMat = Mat4.identity()
-        private transVec = Vec3.zero()
-        private rotVec = Vec3.create(0, 1, 0)
-        private centerVec = Vec3.zero()
-
-        private rotateAnimHandle = -1
-        private explodeAnimHandle = -1
-
-        private updatedUnitTransforms = new Set<SO.Molecule.Structure>()
-        private structureUnitTransforms = new Map<UUID, StructureUnitTransforms>()
-
-        constructor(protected ctx: PluginContext, protected params: StructureAnimationProps) {
-            super(ctx, params)
-            this.update(params)
-        }
-
-        private getUnitTransforms(structure: SO.Molecule.Structure) {
-            let unitTransforms = this.structureUnitTransforms.get(structure.id)
-            if (!unitTransforms) {
-                unitTransforms = new StructureUnitTransforms(structure.data)
-                this.structureUnitTransforms.set(structure.id, unitTransforms)
-            }
-            return unitTransforms
-        }
-
-        rotate(rad: number) {
-            this.updatedUnitTransforms.clear()
-            const state = this.ctx.state.dataState
-            const reprs = state.selectQ(q => q.rootsOfType(PluginStateObject.Molecule.Structure.Representation3D))
-            Mat4.rotate(this.rotMat, this.tmpMat, rad, this.rotVec)
-            for (const r of reprs) {
-                if (!SO.isRepresentation3D(r.obj)) return
-                const structure = getRootStructure(r, state)
-                if (!structure || !SO.Molecule.Structure.is(structure.obj)) continue
-
-                const unitTransforms = this.getUnitTransforms(structure.obj)
-
-                if (!this.updatedUnitTransforms.has(structure.obj)) {
-                    for (let i = 0, il = structure.obj.data.units.length; i < il; ++i) {
-                        const u = structure.obj.data.units[i]
-                        Vec3.transformMat4(this.centerVec, u.lookup3d.boundary.sphere.center, u.conformation.operator.matrix)
-
-                        Vec3.negate(this.transVec, Vec3.copy(this.transVec, this.centerVec))
-                        Mat4.fromTranslation(this.transMat, this.transVec)
-                        Mat4.mul(this.animMat, this.rotMat, this.transMat)
-
-                        Vec3.copy(this.transVec, this.centerVec)
-                        Mat4.fromTranslation(this.transMat, this.transVec)
-                        Mat4.mul(this.animMat, this.transMat, this.animMat)
-
-                        unitTransforms.setTransform(this.animMat, u)
-                    }
-                    this.updatedUnitTransforms.add(structure.obj)
-                }
-
-                r.obj.data.repr.setState({ unitTransforms })
-                this.ctx.canvas3d.add(r.obj.data.repr)
-            }
-            this.ctx.canvas3d.requestDraw(true)
-        }
-
-        animateRotate(play: boolean) {
-            if (play) {
-                const animateRotate = (t: number) => {
-                    this.rotate(degToRad((t / 10) % 360))
-                    this.rotateAnimHandle = requestAnimationFrame(animateRotate)
-                }
-                this.rotateAnimHandle = requestAnimationFrame(animateRotate)
-            } else {
-                cancelAnimationFrame(this.rotateAnimHandle)
-            }
-        }
-
-        explode(p: number) {
-            this.updatedUnitTransforms.clear()
-            const state = this.ctx.state.dataState
-            const reprs = state.selectQ(q => q.rootsOfType(PluginStateObject.Molecule.Structure.Representation3D));
-            for (const r of reprs) {
-                if (!SO.isRepresentation3D(r.obj)) return
-                const structure = getRootStructure(r, state)
-                if (!structure || !SO.Molecule.Structure.is(structure.obj)) continue
-
-                const unitTransforms = this.getUnitTransforms(structure.obj)
-                const d = structure.obj.data.boundary.sphere.radius * (p / 100)
-
-                if (!this.updatedUnitTransforms.has(structure.obj)) {
-                    for (let i = 0, il = structure.obj.data.units.length; i < il; ++i) {
-                        const u = structure.obj.data.units[i]
-                        Vec3.transformMat4(this.centerVec, u.lookup3d.boundary.sphere.center, u.conformation.operator.matrix)
-
-                        Vec3.sub(this.transVec, this.centerVec, structure.obj.data.boundary.sphere.center)
-                        Vec3.setMagnitude(this.transVec, this.transVec, d)
-                        Mat4.fromTranslation(this.animMat, this.transVec)
-
-                        unitTransforms.setTransform(this.animMat, u)
-                    }
-                    this.updatedUnitTransforms.add(structure.obj)
-                }
-
-                r.obj.data.repr.setState({ unitTransforms })
-                this.ctx.canvas3d.add(r.obj.data.repr)
-            }
-            this.ctx.canvas3d.requestDraw(true)
-        }
-
-        animateExplode(play: boolean) {
-            if (play) {
-                const animateExplode = (t: number) => {
-                    this.explode((Math.sin(t * 0.001) + 1) * 50)
-                    this.explodeAnimHandle = requestAnimationFrame(animateExplode)
-                }
-                this.explodeAnimHandle = requestAnimationFrame(animateExplode)
-            } else {
-                cancelAnimationFrame(this.explodeAnimHandle)
-            }
-        }
-
-        register(): void { }
-
-        update(p: StructureAnimationProps) {
-            let updated = !PD.areEqual(StructureAnimationParams, this.params, p)
-            if (this.params.rotate !== p.rotate) {
-                this.params.rotate = p.rotate
-                this.animateRotate(this.params.rotate)
-            }
-            if (this.params.explode !== p.explode) {
-                this.params.explode = p.explode
-                this.animateExplode(this.params.explode)
-            }
-            if (this.params.rotateValue !== p.rotateValue) {
-                this.params.rotateValue = p.rotateValue
-                this.rotate(degToRad(this.params.rotateValue))
-            }
-            if (this.params.explodeValue !== p.explodeValue) {
-                this.params.explodeValue = p.explodeValue
-                this.explode(this.params.explodeValue)
-            }
-            return updated;
-        }
-
-        unregister() {
-            cancelAnimationFrame(this.rotateAnimHandle)
-            cancelAnimationFrame(this.explodeAnimHandle)
-        }
-    },
-    params: () => StructureAnimationParams
-});
-
-//
-
-function getRootStructure(root: StateObjectCell, state: State) {
-    return state.select(StateSelection.Generators.byValue(root).rootOfType([PluginStateObject.Molecule.Structure]))[0];
-}

+ 3 - 3
src/mol-plugin/index.ts

@@ -12,7 +12,7 @@ import * as ReactDOM from 'react-dom';
 import { PluginSpec } from './spec';
 import { StateTransforms } from './state/transforms';
 import { PluginBehaviors } from './behavior';
-import { AnimateModelIndex, AnimateAssemblyUnwind } from './state/animation/built-in';
+import { AnimateModelIndex, AnimateAssemblyUnwind, AnimateUnitsExplode } from './state/animation/built-in';
 import { StateActions } from './state/actions';
 import { InitVolumeStreaming, BoxifyVolumeStreaming, CreateVolumeStreamingBehavior } from './behavior/dynamic/volume-streaming/transformers';
 import { StructureRepresentationInteraction } from './behavior/dynamic/selection/structure-representation-interaction';
@@ -58,7 +58,6 @@ export const DefaultPluginSpec: PluginSpec = {
         PluginSpec.Behavior(PluginBehaviors.Representation.SelectLoci),
         PluginSpec.Behavior(PluginBehaviors.Representation.DefaultLociLabelProvider),
         PluginSpec.Behavior(PluginBehaviors.Camera.FocusLociOnSelect, { minRadius: 20, extraRadius: 4 }),
-        PluginSpec.Behavior(PluginBehaviors.Animation.StructureAnimation, { rotate: false, rotateValue: 0, explode: false, explodeValue: 0 }),
         // PluginSpec.Behavior(PluginBehaviors.Labels.SceneLabels),
         PluginSpec.Behavior(PluginBehaviors.CustomProps.PDBeStructureQualityReport, { autoAttach: true }),
         PluginSpec.Behavior(PluginBehaviors.CustomProps.RCSBAssemblySymmetry, { autoAttach: true }),
@@ -66,7 +65,8 @@ export const DefaultPluginSpec: PluginSpec = {
     ],
     animations: [
         AnimateModelIndex,
-        AnimateAssemblyUnwind
+        AnimateAssemblyUnwind,
+        AnimateUnitsExplode,
     ]
 }
 

+ 32 - 0
src/mol-plugin/state/animation/built-in.ts

@@ -111,6 +111,38 @@ export const AnimateAssemblyUnwind = PluginStateAnimation.create({
 
         await PluginCommands.State.Update.dispatch(ctx.plugin, { state, tree: update, options: { doNotLogTiming: true } });
 
+        return { kind: 'next', state: { t: newTime } };
+    }
+})
+
+export const AnimateUnitsExplode = PluginStateAnimation.create({
+    name: 'built-in.animate-units-explode',
+    display: { name: 'Explode Units' },
+    params: () => ({
+        durationInMs: PD.Numeric(3000, { min: 100, max: 10000, step: 100})
+    }),
+    initialState: () => ({ t: 0 }),
+    async apply(animState, t, ctx) {
+        const state = ctx.plugin.state.dataState;
+        const anims = state.selectQ(q => q.rootsOfType(PluginStateObject.Molecule.Structure.Representation3DState)
+            .filter(c => c.transform.transformer === StateTransforms.Representation.ExplodeStructureRepresentation3D));
+
+        if (anims.length === 0) {
+            // nothing more to do here
+            return { kind: 'finished' };
+        }
+
+        const update = state.build();
+
+        const d = (t.current - t.lastApplied) / ctx.params.durationInMs;
+        const newTime = (animState.t + d) % 1;
+
+        for (const m of anims) {
+            update.to(m.transform.ref).update(StateTransforms.Representation.ExplodeStructureRepresentation3D, _ => ({ t: newTime }));
+        }
+
+        await PluginCommands.State.Update.dispatch(ctx.plugin, { state, tree: update, options: { doNotLogTiming: true } });
+
         return { kind: 'next', state: { t: newTime } };
     }
 })