From ed75fe54cc06380361cdb0e3b2ce704e4eb64531 Mon Sep 17 00:00:00 2001
From: Alexander Rose <alex.rose@rcsb.org>
Date: Wed, 12 Dec 2018 16:08:33 -0800
Subject: [PATCH] structure animation tweaks

---
 package-lock.json                            | Bin 485094 -> 485088 bytes
 src/mol-plugin/behavior/dynamic/animation.ts |  71 ++++++++++++-------
 src/mol-plugin/index.ts                      |   2 +-
 3 files changed, 46 insertions(+), 27 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 4d591a55215d505271ecf6a6c0714d886142aa28..8dd941ab943fd2727d03938f79af7d152d4c532c 100644
GIT binary patch
delta 326
zcmaEMR`$VJ*@i8Qrz0jCbc;>?vz>GM>j*}(u*nDb#HZgWW|5kHSc+9+d*ymY&-c?4
z4zr3+w`XEuonD~CCN%lMtF6-~m@!MV@0-uGecya$j(O7^QrX0}-?L@$WCAg#OrG#Y
zV*3>bmMLanz1thgS=t3a7ER}mW#rqg)4>uY1eQUVy7|GY4UE$TxEcATzq-xL+uksT
zWqZRM)@@86ZQFh4vu<TV(=qwMtAo=|C9(5QpJ&g`IXzE}No4wgxvb{XU)i(EOn=nN
zs<D0MV%D$x5N+{F%$(cTZ)TOqn4X}<CcWLypIw7-x`PNC`*s0YHd$$qHSI1IY};Kd
e*vpte!La>;6?;A}T(u_S_9jpEO{{Q%8R7taV|C;J

delta 285
zcmaEGR`%Ih*@i8Qrz56s@L`mk{BJw^_E!;%W?_>Jy2Ym7EM}3KEVNT&d*ymY&-c?e
zd}WoK?hwxYxP9+@rtN#@Gjq(FuHeKXx&5v!iwD#650Na|+x;C_#LTB3*vBlfy{4R{
zT>xaP#B}~xM&9imGAv1q(`&@p)wgfxWVt8+H}CXxg{zD_?FF-0winE1J-|F&VIzyg
zcK7+LTbR()Y=5<gb&deYc*W`e-m?g7-?o{RBLnQ#{qGnRw&!`U^Ds_t6=mb!E+ES$
uDm{HdD4RsPjRo6w8w>VQCXmAIC#=}>c|ok{FfIGpP`JE|+Y1BO^ThzMacrUh

diff --git a/src/mol-plugin/behavior/dynamic/animation.ts b/src/mol-plugin/behavior/dynamic/animation.ts
index b3696db3f..e79562ce6 100644
--- a/src/mol-plugin/behavior/dynamic/animation.ts
+++ b/src/mol-plugin/behavior/dynamic/animation.ts
@@ -11,74 +11,93 @@ import { degToRad } from 'mol-math/misc';
 import { Mat4, Vec3 } from 'mol-math/linear-algebra';
 import { PluginStateObject as SO, PluginStateObject } from '../../state/objects';
 import { StateSelection } from 'mol-state/state/selection';
+import { StateObjectCell, State } from 'mol-state';
+
+const StructureAnimationParams = {
+    rotate: PD.Boolean(false)
+}
+type StructureAnimationProps = PD.Values<typeof StructureAnimationParams>
+
+function getRootStructure(root: StateObjectCell, state: State) {
+    let parent: StateObjectCell | undefined
+    while (true) {
+        const _parent = StateSelection.findAncestorOfType(state.tree, state.cells, root.transform.ref, [PluginStateObject.Molecule.Structure])
+        if (_parent) {
+            parent = _parent
+            root = _parent
+        } else {
+            break
+        }
+    }
+    if (!parent || !parent.obj) return
+    return parent.obj as PluginStateObject.Molecule.Structure
+}
 
 // TODO this is just for testing purposes
-export const Animation = PluginBehavior.create<{ play: boolean }>({
-    name: 'animation',
-    display: { name: 'Animation', group: 'Animation' },
-    ctor: class extends PluginBehavior.Handler<{ play: boolean }> {
+export const StructureAnimation = PluginBehavior.create<StructureAnimationProps>({
+    name: 'structure-animation',
+    display: { name: 'Structure Animation', group: 'Animation' },
+    ctor: class extends PluginBehavior.Handler<StructureAnimationProps> {
         private tmpMat = Mat4.identity()
         private rotMat = Mat4.identity()
         private transMat = Mat4.identity()
-        private animMat = Mat4.identity()
+        private rotAnimMat = Mat4.identity()
         private transVec = Vec3.zero()
         private rotVec = Vec3.create(0, 1, 0)
-        private animHandle = -1
 
-        constructor(protected ctx: PluginContext, protected params: { play: boolean }) {
+        private rotateAnimHandle = -1
+
+        constructor(protected ctx: PluginContext, protected params: StructureAnimationProps) {
             super(ctx, params)
             this.update(params)
         }
 
-        animate(play: boolean) {
+        rotate(play: boolean) {
             if (play) {
                 const state = this.ctx.state.dataState
                 const reprs = state.select(q => q.rootsOfType(PluginStateObject.Molecule.Representation3D));
-                const anim = (t: number) => {
+                const rotate = (t: number) => {
                     const rad = degToRad((t / 10) % 360)
                     Mat4.rotate(this.rotMat, this.tmpMat, rad, this.rotVec)
                     for (const r of reprs) {
                         if (!SO.isRepresentation3D(r.obj)) return
-                        const parent = StateSelection.findAncestorOfType(state.tree, state.cells, r.transform.ref, [PluginStateObject.Molecule.Structure])
-                        if (!parent || !parent.obj) continue
-                        const structure = parent.obj as PluginStateObject.Molecule.Structure
+                        const structure = getRootStructure(r, state)
+                        if (!structure) continue
 
                         Vec3.negate(this.transVec, Vec3.copy(this.transVec, structure.data.boundary.sphere.center))
                         Mat4.fromTranslation(this.transMat, this.transVec)
-                        Mat4.mul(this.animMat, this.rotMat, this.transMat)
+                        Mat4.mul(this.rotAnimMat, this.rotMat, this.transMat)
 
                         Vec3.copy(this.transVec, structure.data.boundary.sphere.center)
                         Mat4.fromTranslation(this.transMat, this.transVec)
-                        Mat4.mul(this.animMat, this.transMat, this.animMat)
+                        Mat4.mul(this.rotAnimMat, this.transMat, this.rotAnimMat)
 
-                        r.obj.data.setState({ transform: this.animMat })
+                        r.obj.data.setState({ transform: this.rotAnimMat })
                         this.ctx.canvas3d.add(r.obj.data)
                         this.ctx.canvas3d.requestDraw(true)
                     }
-                    this.animHandle = requestAnimationFrame(anim)
+                    this.rotateAnimHandle = requestAnimationFrame(rotate)
                 }
-                this.animHandle = requestAnimationFrame(anim)
+                this.rotateAnimHandle = requestAnimationFrame(rotate)
             } else {
-                cancelAnimationFrame(this.animHandle)
+                cancelAnimationFrame(this.rotateAnimHandle)
             }
         }
 
         register(): void { }
 
-        update(p: { play: boolean }) {
-            let updated = this.params.play !== p.play
-            this.params.play = p.play
+        update(p: StructureAnimationProps) {
+            let updated = this.params.rotate !== p.rotate
+            this.params.rotate = p.rotate
             if (updated) {
-                this.animate(this.params.play)
+                this.rotate(this.params.rotate)
             }
             return updated;
         }
 
         unregister() {
-            cancelAnimationFrame(this.animHandle)
+            cancelAnimationFrame(this.rotateAnimHandle)
         }
     },
-    params: () => ({
-        play: PD.Boolean(false)
-    })
+    params: () => StructureAnimationParams
 });
\ No newline at end of file
diff --git a/src/mol-plugin/index.ts b/src/mol-plugin/index.ts
index cf3507b2a..a22b53ddb 100644
--- a/src/mol-plugin/index.ts
+++ b/src/mol-plugin/index.ts
@@ -37,7 +37,7 @@ const DefaultSpec: PluginSpec = {
         PluginSpec.Behavior(PluginBehaviors.Representation.SelectLoci),
         PluginSpec.Behavior(PluginBehaviors.Representation.DefaultLociLabelProvider),
         PluginSpec.Behavior(PluginBehaviors.Camera.FocusLociOnSelect, { minRadius: 20, extraRadius: 4 }),
-        PluginSpec.Behavior(PluginBehaviors.Animation.Animation, { play: false }),
+        PluginSpec.Behavior(PluginBehaviors.Animation.StructureAnimation, { rotate: false }),
         PluginSpec.Behavior(PluginBehaviors.CustomProps.PDBeStructureQualityReport, { autoAttach: true }),
         PluginSpec.Behavior(PluginBehaviors.CustomProps.RCSBAssemblySymmetry, { autoAttach: true }),
     ]
-- 
GitLab