Skip to content
Snippets Groups Projects
Commit e31f0f76 authored by Alexander Rose's avatar Alexander Rose
Browse files

basic spin-structure animation

parent 35862079
No related branches found
No related tags found
No related merge requests found
......@@ -34,6 +34,7 @@ import { CustomStructureProperty } from '../../../mol-model-props/common/custom-
import { Trajectory } from '../trajectory';
import { RuntimeContext, Task } from '../../../mol-task';
import { computeStructureBoundary } from './util/boundary';
import { PrincipalAxes } from '../../../mol-math/linear-algebra/matrix/principal-axes';
/** Internal structure state */
type State = {
......@@ -1290,6 +1291,14 @@ namespace Structure {
export type Index = number;
export const Index = CustomStructureProperty.createSimple<Index>('index', 'root');
const PrincipalAxesProp = '__PrincipalAxes__';
export function getPrincipalAxes(structure: Structure): PrincipalAxes {
if (structure.currentPropertyData[PrincipalAxesProp]) return structure.currentPropertyData[PrincipalAxesProp];
const principalAxes = StructureElement.Loci.getPrincipalAxes(Structure.toStructureElementLoci(structure));
structure.currentPropertyData[PrincipalAxesProp] = principalAxes;
return principalAxes;
}
}
export { Structure };
\ No newline at end of file
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { PluginCommands } from '../../../mol-plugin/commands';
import { StateSelection } from '../../../mol-state';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { PluginStateObject } from '../../objects';
import { StateTransforms } from '../../transforms';
import { PluginStateAnimation } from '../model';
export const AnimateStructureSpin = PluginStateAnimation.create({
name: 'built-in.animate-structure-spin',
display: { name: 'Spin Structure' },
isExportable: true,
params: () => ({
durationInMs: PD.Numeric(3000, { min: 100, max: 10000, step: 100})
}),
initialState: () => ({ t: 0 }),
getDuration: p => ({ kind: 'fixed', durationMs: p.durationInMs }),
async setup(_, __, plugin) {
const state = plugin.state.data;
const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3D));
const update = state.build();
let changed = false;
for (const r of reprs) {
const spins = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Representation.SpinStructureRepresentation3D, r.transform.ref));
if (spins.length > 0) continue;
changed = true;
update.to(r.transform.ref)
.apply(StateTransforms.Representation.SpinStructureRepresentation3D, { t: 0 }, { tags: 'animate-structure-spin' });
}
if (!changed) return;
return update.commit({ doNotUpdateCurrent: true });
},
teardown(_, __, plugin) {
const state = plugin.state.data;
const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3DState)
.withTag('animate-structure-spin'));
if (reprs.length === 0) return;
const update = state.build();
for (const r of reprs) update.delete(r.transform.ref);
return update.commit();
},
async apply(animState, t, ctx) {
const state = ctx.plugin.state.data;
const anims = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Representation.SpinStructureRepresentation3D));
if (anims.length === 0) {
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).update({ ...m.params?.values, t: newTime });
}
await PluginCommands.State.Update(ctx.plugin, { state, tree: update, options: { doNotLogTiming: true } });
return { kind: 'next', state: { t: newTime } };
}
});
\ No newline at end of file
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { SymmetryOperator } from '../../mol-math/geometry';
import { Mat4, Vec3 } from '../../mol-math/linear-algebra';
import { Structure } from '../../mol-model/structure';
......@@ -33,3 +35,59 @@ export function explodeStructure(structure: Structure, unitTransforms: Structure
unitTransforms.setTransform(_transMat, u);
}
}
//
export const SpinStructureParams = {
axis: PD.MappedStatic('custom', {
structure: PD.Group({
principalAxis: PD.Select('dirA', [['dirA', 'A'], ['dirB', 'B'], ['dirC', 'C']] as const)
}),
custom: PD.Group({
vector: PD.Vec3(Vec3.create(0, 0, 1))
})
}),
origin: PD.MappedStatic('structure', {
structure: PD.Group({}),
custom: PD.Group({
vector: PD.Vec3(Vec3.create(0, 0, 0))
})
}),
};
export type SpinStructureProps = PD.Values<typeof SpinStructureParams>
export function getSpinStructureAxisAndOrigin(structure: Structure, props: SpinStructureProps) {
let axis: Vec3, origin: Vec3;
if (props.axis.name === 'custom') {
axis = props.axis.params.vector;
} else {
const pa = Structure.getPrincipalAxes(structure);
axis = pa.momentsAxes[props.axis.params.principalAxis];
}
if (props.origin.name === 'custom') {
origin = props.origin.params.vector;
} else {
const pa = Structure.getPrincipalAxes(structure);
origin = pa.momentsAxes.origin;
}
return { axis, origin };
}
const _rotMat = Mat4();
const _transMat2 = Mat4();
const _t = Mat4();
export function spinStructure(structure: Structure, unitTransforms: StructureUnitTransforms, t: number, axis: Vec3, origin: Vec3) {
for (let i = 0, _i = structure.units.length; i < _i; i++) {
const u = structure.units[i];
Vec3.negate(_transVec, origin);
Mat4.fromTranslation(_transMat, _transVec);
Mat4.fromRotation(_rotMat, Math.PI * t * 2, axis);
Mat4.fromTranslation(_transMat2, origin);
Mat4.mul(_t, _rotMat, _transMat);
Mat4.mul(_t, _transMat2, _t);
unitTransforms.setTransform(_t, u);
}
}
\ No newline at end of file
......@@ -20,7 +20,7 @@ import { PluginStateObject as SO, PluginStateTransform } from '../objects';
import { ColorNames } from '../../mol-util/color/names';
import { ShapeRepresentation } from '../../mol-repr/shape/representation';
import { StructureUnitTransforms } from '../../mol-model/structure/structure/util/unit-transforms';
import { unwindStructureAssembly, explodeStructure } from '../animation/helpers';
import { unwindStructureAssembly, explodeStructure, spinStructure, SpinStructureParams, getSpinStructureAxisAndOrigin } from '../animation/helpers';
import { Color } from '../../mol-util/color';
import { Overpaint } from '../../mol-theme/overpaint';
import { Transparency } from '../../mol-theme/transparency';
......@@ -43,6 +43,7 @@ import { Box3D } from '../../mol-math/geometry';
export { StructureRepresentation3D };
export { ExplodeStructureRepresentation3D };
export { SpinStructureRepresentation3D };
export { UnwindStructureAssemblyRepresentation3D };
export { OverpaintStructureRepresentation3DFromScript };
export { OverpaintStructureRepresentation3DFromBundle };
......@@ -222,7 +223,6 @@ const UnwindStructureAssemblyRepresentation3D = PluginStateTransform.BuiltIn({
}
});
type ExplodeStructureRepresentation3D = typeof ExplodeStructureRepresentation3D
const ExplodeStructureRepresentation3D = PluginStateTransform.BuiltIn({
name: 'explode-structure-representation-3d',
......@@ -259,6 +259,49 @@ const ExplodeStructureRepresentation3D = PluginStateTransform.BuiltIn({
}
});
type SpinStructureRepresentation3D = typeof SpinStructureRepresentation3D
const SpinStructureRepresentation3D = PluginStateTransform.BuiltIn({
name: 'spin-structure-representation-3d',
display: 'Spin 3D Representation',
from: SO.Molecule.Structure.Representation3D,
to: SO.Molecule.Structure.Representation3DState,
params: {
t: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }),
...SpinStructureParams
}
})({
canAutoUpdate() {
return true;
},
apply({ a, params }) {
const structure = a.data.sourceData;
const unitTransforms = new StructureUnitTransforms(structure.root);
const { axis, origin } = getSpinStructureAxisAndOrigin(structure.root, params);
spinStructure(structure, unitTransforms, params.t, axis, origin);
return new SO.Molecule.Structure.Representation3DState({
state: { unitTransforms },
initialState: { unitTransforms: new StructureUnitTransforms(structure.root) },
info: structure.root,
repr: a.data.repr
}, { label: `Spin T = ${params.t.toFixed(2)}` });
},
update({ a, b, newParams, oldParams }) {
const structure = a.data.sourceData;
if (b.data.info !== structure.root) return StateTransformer.UpdateResult.Recreate;
if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate;
if (oldParams.t === newParams.t && oldParams.axis === newParams.axis && oldParams.origin === newParams.origin) return StateTransformer.UpdateResult.Unchanged;
const unitTransforms = b.data.state.unitTransforms!;
const { axis, origin } = getSpinStructureAxisAndOrigin(structure.root, newParams);
spinStructure(structure.root, unitTransforms, newParams.t, axis, origin);
b.label = `Spin T = ${newParams.t.toFixed(2)}`;
b.data.repr = a.data.repr;
return StateTransformer.UpdateResult.Updated;
}
});
type OverpaintStructureRepresentation3DFromScript = typeof OverpaintStructureRepresentation3DFromScript
const OverpaintStructureRepresentation3DFromScript = PluginStateTransform.BuiltIn({
name: 'overpaint-structure-representation-3d-from-script',
......
......@@ -22,6 +22,7 @@ import { AssignColorVolume } from '../mol-plugin-state/actions/volume';
import { StateTransforms } from '../mol-plugin-state/transforms';
import { BoxifyVolumeStreaming, CreateVolumeStreamingBehavior, InitVolumeStreaming } from '../mol-plugin/behavior/dynamic/volume-streaming/transformers';
import { AnimateStateInterpolation } from '../mol-plugin-state/animation/built-in/state-interpolation';
import { AnimateStructureSpin } from '../mol-plugin-state/animation/built-in/spin-structure';
export { PluginSpec };
......@@ -96,6 +97,7 @@ export const DefaultPluginSpec = (): PluginSpec => ({
PluginSpec.Action(StateTransforms.Representation.ModelUnitcell3D),
PluginSpec.Action(StateTransforms.Representation.StructureBoundingBox3D),
PluginSpec.Action(StateTransforms.Representation.ExplodeStructureRepresentation3D),
PluginSpec.Action(StateTransforms.Representation.SpinStructureRepresentation3D),
PluginSpec.Action(StateTransforms.Representation.UnwindStructureAssemblyRepresentation3D),
PluginSpec.Action(StateTransforms.Representation.OverpaintStructureRepresentation3DFromScript),
PluginSpec.Action(StateTransforms.Representation.TransparencyStructureRepresentation3DFromScript),
......@@ -128,6 +130,7 @@ export const DefaultPluginSpec = (): PluginSpec => ({
AnimateCameraSpin,
AnimateStateSnapshots,
AnimateAssemblyUnwind,
AnimateStructureSpin,
AnimateStateInterpolation
]
});
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment