diff --git a/src/mol-plugin/behavior/dynamic/representation.ts b/src/mol-plugin/behavior/dynamic/representation.ts index 12e7a4222f2da0bcbe7ee049aa5d3045515757e3..686965d2ae1ec12d60860cf65f3633258465a75a 100644 --- a/src/mol-plugin/behavior/dynamic/representation.ts +++ b/src/mol-plugin/behavior/dynamic/representation.ts @@ -6,26 +6,24 @@ */ import { MarkerAction } from 'mol-geo/geometry/marker-data'; -import { Mat4, Vec3 } from 'mol-math/linear-algebra'; import { EmptyLoci, EveryLoci } from 'mol-model/loci'; -import { StructureUnitTransforms } from 'mol-model/structure/structure/util/unit-transforms'; +import { QueryContext, StructureElement, StructureSelection } from 'mol-model/structure'; import { PluginContext } from 'mol-plugin/context'; import { PluginStateObject } from 'mol-plugin/state/objects'; -import { StateObjectTracker, StateSelection } from 'mol-state'; -import { labelFirst } from 'mol-theme/label'; -import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { PluginBehavior } from '../behavior'; import { Representation } from 'mol-repr/representation'; -import { ButtonsType } from 'mol-util/input/input-observer'; -import { StructureElement, StructureSelection, QueryContext } from 'mol-model/structure'; -import { ColorNames } from 'mol-util/color/tables'; // import { MolScriptBuilder as MS } from 'mol-script/language/builder'; import Expression from 'mol-script/language/expression'; -import { Color } from 'mol-util/color'; -import { compile } from 'mol-script/runtime/query/compiler'; -import { Overpaint } from 'mol-theme/overpaint'; import { parseMolScript } from 'mol-script/language/parser'; +import { compile } from 'mol-script/runtime/query/compiler'; import { transpileMolScript } from 'mol-script/script/mol-script/symbols'; +import { StateObjectTracker, StateSelection } from 'mol-state'; +import { labelFirst } from 'mol-theme/label'; +import { Overpaint } from 'mol-theme/overpaint'; +import { Color } from 'mol-util/color'; +import { ColorNames } from 'mol-util/color/tables'; +import { ButtonsType } from 'mol-util/input/input-observer'; +import { ParamDefinition as PD } from 'mol-util/param-definition'; +import { PluginBehavior } from '../behavior'; export const HighlightLoci = PluginBehavior.create({ name: 'representation-highlight-loci', @@ -128,84 +126,6 @@ export const DefaultLociLabelProvider = PluginBehavior.create({ display: { name: 'Provide Default Loci Label' } }); -export namespace ExplodeRepresentation3D { - export const Params = { - t: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }) - } - export type Params = PD.Values<typeof Params> - - export class Behavior implements PluginBehavior<Params> { - private currentT = 0; - private repr: StateObjectTracker<PluginStateObject.Molecule.Structure.Representation3D>; - private structure: StateObjectTracker<PluginStateObject.Molecule.Structure>; - private transforms: StructureUnitTransforms; - - private updateData() { - const reprUpdated = this.repr.update(); - const strUpdated = this.structure.update(); - if (strUpdated && this.structure.data) { - this.transforms = new StructureUnitTransforms(this.structure.data); - } - return reprUpdated || strUpdated; - } - - register(ref: string): void { - this.repr.setQuery(StateSelection.Generators.byRef(ref).ancestorOfType([PluginStateObject.Molecule.Structure.Representation3D])); - this.structure.setQuery(StateSelection.Generators.byRef(ref).rootOfType([PluginStateObject.Molecule.Structure])); - this.update(this.params); - } - - private centerVec = Vec3.zero(); - private transVec = Vec3.zero(); - private transMat = Mat4.zero(); - - update(params: Params): boolean | Promise<boolean> { - if (!this.updateData() && params.t === this.currentT) return false; - this.currentT = params.t; - if (!this.structure.data || !this.repr.data) return true; - - const structure = this.structure.data; - const boundary = structure.boundary.sphere; - const d = boundary.radius * params.t; - - for (let i = 0, _i = structure.units.length; i < _i; i++) { - const u = structure.units[i]; - - Vec3.transformMat4(this.centerVec, u.lookup3d.boundary.sphere.center, u.conformation.operator.matrix); - Vec3.sub(this.transVec, this.centerVec, boundary.center); - Vec3.setMagnitude(this.transVec, this.transVec, d); - Mat4.fromTranslation(this.transMat, this.transVec) - - this.transforms.setTransform(this.transMat, u); - } - - // TODO: should be be "auto updated"? - // perhaps have Representation3D.setState(state, autoSync = false)? - - // TODO: where to handle unitTransforms composition? - // Manually or inside the representation? "inside" would better compose with future additions. - this.repr.data.repr.setState({ unitTransforms: this.transforms }); - this.ctx.canvas3d.add(this.repr.data.repr); - this.ctx.canvas3d.requestDraw(true); - - return true; - } - - unregister(): void { - this.update({ t: 0 }) - this.repr.cell = void 0; - this.structure.cell = void 0; - } - - constructor(private ctx: PluginContext, private params: Params) { - this.repr = new StateObjectTracker(ctx.state.dataState); - this.structure = new StateObjectTracker(ctx.state.dataState); - } - } - - export class Obj extends PluginStateObject.CreateBehavior<Behavior>({ name: 'Explode Representation3D Behavior' }) { } -} - type ColorMappings = { query: Expression, color: Color }[] namespace ColorMappings { export function areEqual(colorMappingsA: ColorMappings, colorMappingsB: ColorMappings) { diff --git a/src/mol-plugin/state/animation/helpers.ts b/src/mol-plugin/state/animation/helpers.ts index af25641fb6352041b3ac40e84a8f69ea68a6157b..cf83143f16707f7effb6819f17a81887d1f91181 100644 --- a/src/mol-plugin/state/animation/helpers.ts +++ b/src/mol-plugin/state/animation/helpers.ts @@ -6,15 +6,31 @@ import { SymmetryOperator } from 'mol-math/geometry'; -import { Mat4 } from 'mol-math/linear-algebra'; +import { Mat4, Vec3 } from 'mol-math/linear-algebra'; import { Structure } from 'mol-model/structure'; import { StructureUnitTransforms } from 'mol-model/structure/structure/util/unit-transforms'; const _unwindMatrix = Mat4.zero(); -export function unwindStructureAssebmly(structure: Structure, unitTransforms: StructureUnitTransforms, t: number) { +export function unwindStructureAssembly(structure: Structure, unitTransforms: StructureUnitTransforms, t: number) { for (let i = 0, _i = structure.units.length; i < _i; i++) { const u = structure.units[i]; SymmetryOperator.lerpFromIdentity(_unwindMatrix, u.conformation.operator, t); unitTransforms.setTransform(_unwindMatrix, u); } +} + +const _centerVec = Vec3.zero(), _transVec = Vec3.zero(), _transMat = Mat4.zero(); +export function explodeStructure(structure: Structure, unitTransforms: StructureUnitTransforms, t: number) { + const boundary = structure.boundary.sphere; + const d = boundary.radius * t; + + for (let i = 0, _i = structure.units.length; i < _i; i++) { + const u = structure.units[i]; + Vec3.transformMat4(_centerVec, u.lookup3d.boundary.sphere.center, u.conformation.operator.matrix); + Vec3.sub(_transVec, _centerVec, boundary.center); + Vec3.setMagnitude(_transVec, _transVec, d); + Mat4.fromTranslation(_transMat, _transVec); + + unitTransforms.setTransform(_transMat, u); + } } \ No newline at end of file diff --git a/src/mol-plugin/state/transforms/representation.ts b/src/mol-plugin/state/transforms/representation.ts index 467b20ce502a1f969f442ff4395f2e5b06f9dffa..d4bba69643e0e65643da8ed51532092e2f88e140 100644 --- a/src/mol-plugin/state/transforms/representation.ts +++ b/src/mol-plugin/state/transforms/representation.ts @@ -7,7 +7,7 @@ import { Structure } from 'mol-model/structure'; import { VolumeData, VolumeIsoValue } from 'mol-model/volume'; -import { ExplodeRepresentation3D, ColorRepresentation3D } from 'mol-plugin/behavior/dynamic/representation'; +import { ColorRepresentation3D } from 'mol-plugin/behavior/dynamic/representation'; import { PluginContext } from 'mol-plugin/context'; import { RepresentationProvider } from 'mol-repr/representation'; import { BuiltInStructureRepresentationsName } from 'mol-repr/structure/registry'; @@ -26,7 +26,7 @@ import { ColorNames } from 'mol-util/color/tables'; import { getLabelRepresentation } from 'mol-plugin/util/structure-labels'; import { ShapeRepresentation } from 'mol-repr/shape/representation'; import { StructureUnitTransforms } from 'mol-model/structure/structure/util/unit-transforms'; -import { unwindStructureAssebmly } from '../animation/helpers'; +import { unwindStructureAssembly, explodeStructure } from '../animation/helpers'; export { StructureRepresentation3D } export { StructureRepresentation3DHelpers } @@ -243,10 +243,10 @@ const UnwindStructureAssemblyRepresentation3D = PluginStateTransform.BuiltIn({ canAutoUpdate() { return true; }, - apply({ a, params }, plugin: PluginContext) { + apply({ a, params }) { const structure = a.data.source.data; const unitTransforms = new StructureUnitTransforms(structure); - unwindStructureAssebmly(structure, unitTransforms, params.t); + unwindStructureAssembly(structure, unitTransforms, params.t); return new SO.Molecule.Structure.Representation3DState({ state: { unitTransforms }, info: structure, source: a }, { label: `Unwind T = ${params.t.toFixed(2)}` }); }, update({ a, b, newParams, oldParams }) { @@ -254,7 +254,7 @@ const UnwindStructureAssemblyRepresentation3D = PluginStateTransform.BuiltIn({ if (a.data.source.data !== structure) return StateTransformer.UpdateResult.Recreate; if (oldParams.t === newParams.t) return StateTransformer.UpdateResult.Unchanged; const unitTransforms = b.data.state.unitTransforms!; - unwindStructureAssebmly(structure, unitTransforms, newParams.t); + unwindStructureAssembly(structure, unitTransforms, newParams.t); b.label = `Unwind T = ${newParams.t.toFixed(2)}`; b.data.source = a; return StateTransformer.UpdateResult.Updated; @@ -267,21 +267,28 @@ const ExplodeStructureRepresentation3D = PluginStateTransform.BuiltIn({ name: 'explode-structure-representation-3d', display: 'Explode 3D Representation', from: SO.Molecule.Structure.Representation3D, - to: ExplodeRepresentation3D.Obj, - params: ExplodeRepresentation3D.Params + to: SO.Molecule.Structure.Representation3DState, + params: { t: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }) } })({ canAutoUpdate() { return true; }, - apply({ params }, plugin: PluginContext) { - return new ExplodeRepresentation3D.Obj(new ExplodeRepresentation3D.Behavior(plugin, params), { label: `Explosion T = ${params.t.toFixed(2)}` }); + apply({ a, params, spine }) { + const srcStructure = spine.getRootOfType(SO.Molecule.Structure)!.data; + const unitTransforms = new StructureUnitTransforms(srcStructure); + explodeStructure(srcStructure, unitTransforms, params.t); + return new SO.Molecule.Structure.Representation3DState({ state: { unitTransforms }, info: srcStructure, source: a }, { label: `Explode T = ${params.t.toFixed(2)}` }); }, - update({ b, newParams }) { - return Task.create('Update Explosion', async () => { - const updated = await b.data.update(newParams); - b.label = `Explosion T = ${newParams.t.toFixed(2)}`; - return updated ? StateTransformer.UpdateResult.Updated : StateTransformer.UpdateResult.Unchanged; - }); + update({ a, b, newParams, oldParams, spine }) { + const srcStructure = spine.getRootOfType(SO.Molecule.Structure)!.data; + const structure = b.data.info as Structure; + if (srcStructure !== structure) return StateTransformer.UpdateResult.Recreate; + if (oldParams.t === newParams.t) return StateTransformer.UpdateResult.Unchanged; + const unitTransforms = b.data.state.unitTransforms!; + explodeStructure(structure, unitTransforms, newParams.t); + b.label = `Explode T = ${newParams.t.toFixed(2)}`; + b.data.source = a; + return StateTransformer.UpdateResult.Updated; } });