UNPKG

molstar

Version:

A comprehensive macromolecular library.

975 lines 63.1 kB
/** * Copyright (c) 2018-2024 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 { Structure, StructureElement } from '../../mol-model/structure'; import { Volume } from '../../mol-model/volume'; import { StateTransformer, StateObject } from '../../mol-state'; import { Task } from '../../mol-task'; import { Theme } from '../../mol-theme/theme'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; 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, spinStructure, SpinStructureParams, getSpinStructureAxisAndOrigin } from '../animation/helpers'; import { Color } from '../../mol-util/color'; import { Overpaint } from '../../mol-theme/overpaint'; import { Transparency } from '../../mol-theme/transparency'; import { BaseGeometry, hasColorSmoothingProp } from '../../mol-geo/geometry/base'; import { Script } from '../../mol-script/script'; import { UnitcellParams, UnitcellRepresentation, getUnitcellData } from '../../mol-repr/shape/model/unitcell'; import { DistanceParams, DistanceRepresentation } from '../../mol-repr/shape/loci/distance'; import { getDistanceDataFromStructureSelections, getLabelDataFromStructureSelections, getOrientationDataFromStructureSelections, getAngleDataFromStructureSelections, getDihedralDataFromStructureSelections, getPlaneDataFromStructureSelections } from './helpers'; import { LabelParams, LabelRepresentation } from '../../mol-repr/shape/loci/label'; import { OrientationRepresentation, OrientationParams } from '../../mol-repr/shape/loci/orientation'; import { AngleParams, AngleRepresentation } from '../../mol-repr/shape/loci/angle'; import { DihedralParams, DihedralRepresentation } from '../../mol-repr/shape/loci/dihedral'; import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry'; import { Clipping } from '../../mol-theme/clipping'; import { ObjectKeys } from '../../mol-util/type-helpers'; import { Mesh } from '../../mol-geo/geometry/mesh/mesh'; import { getBoxMesh } from './shape'; import { Shape } from '../../mol-model/shape'; import { PlaneParams, PlaneRepresentation } from '../../mol-repr/shape/loci/plane'; import { Substance } from '../../mol-theme/substance'; import { Material } from '../../mol-util/material'; import { lerp } from '../../mol-math/interpolate'; import { MarkerAction, MarkerActions } from '../../mol-util/marker-action'; import { Emissive } from '../../mol-theme/emissive'; export { StructureRepresentation3D }; export { ExplodeStructureRepresentation3D }; export { SpinStructureRepresentation3D }; export { UnwindStructureAssemblyRepresentation3D }; export { OverpaintStructureRepresentation3DFromScript }; export { OverpaintStructureRepresentation3DFromBundle }; export { TransparencyStructureRepresentation3DFromScript }; export { TransparencyStructureRepresentation3DFromBundle }; export { EmissiveStructureRepresentation3DFromScript }; export { EmissiveStructureRepresentation3DFromBundle }; export { SubstanceStructureRepresentation3DFromScript }; export { SubstanceStructureRepresentation3DFromBundle }; export { ClippingStructureRepresentation3DFromScript }; export { ClippingStructureRepresentation3DFromBundle }; export { ThemeStrengthRepresentation3D }; export { VolumeRepresentation3D }; const StructureRepresentation3D = PluginStateTransform.BuiltIn({ name: 'structure-representation-3d', display: '3D Representation', from: SO.Molecule.Structure, to: SO.Molecule.Structure.Representation3D, params: (a, ctx) => { const { registry, themes: themeCtx } = ctx.representation.structure; const type = registry.get(registry.default.name); if (!a) { const colorThemeInfo = { help: (value) => { const { name, params } = value; const p = themeCtx.colorThemeRegistry.get(name); const ct = p.factory({}, params); return { description: ct.description, legend: ct.legend }; } }; return { type: PD.Mapped(registry.default.name, registry.types, name => PD.Group(registry.get(name).getParams(themeCtx, Structure.Empty))), colorTheme: PD.Mapped(type.defaultColorTheme.name, themeCtx.colorThemeRegistry.types, name => PD.Group(themeCtx.colorThemeRegistry.get(name).getParams({ structure: Structure.Empty })), colorThemeInfo), sizeTheme: PD.Mapped(type.defaultSizeTheme.name, themeCtx.sizeThemeRegistry.types, name => PD.Group(themeCtx.sizeThemeRegistry.get(name).getParams({ structure: Structure.Empty }))) }; } const dataCtx = { structure: a.data }; const colorThemeInfo = { help: (value) => { const { name, params } = value; const p = themeCtx.colorThemeRegistry.get(name); const ct = p.factory(dataCtx, params); return { description: ct.description, legend: ct.legend }; } }; return ({ type: PD.Mapped(registry.default.name, registry.getApplicableTypes(a.data), name => PD.Group(registry.get(name).getParams(themeCtx, a.data))), colorTheme: PD.Mapped(type.defaultColorTheme.name, themeCtx.colorThemeRegistry.getApplicableTypes(dataCtx), name => PD.Group(themeCtx.colorThemeRegistry.get(name).getParams(dataCtx)), colorThemeInfo), sizeTheme: PD.Mapped(type.defaultSizeTheme.name, themeCtx.sizeThemeRegistry.getApplicableTypes(dataCtx), name => PD.Group(themeCtx.sizeThemeRegistry.get(name).getParams(dataCtx))) }); } })({ canAutoUpdate({ a, oldParams, newParams }) { // TODO: other criteria as well? return a.data.elementCount < 10000 || (oldParams.type.name === newParams.type.name && newParams.type.params.quality !== 'custom'); }, apply({ a, params, cache }, plugin) { return Task.create('Structure Representation', async (ctx) => { var _a, _b; const propertyCtx = { runtime: ctx, assetManager: plugin.managers.asset, errorContext: plugin.errorContext }; const provider = plugin.representation.structure.registry.get(params.type.name); const data = ((_a = provider.getData) === null || _a === void 0 ? void 0 : _a.call(provider, a.data, params.type.params)) || a.data; if (provider.ensureCustomProperties) await provider.ensureCustomProperties.attach(propertyCtx, data); const repr = provider.factory({ webgl: (_b = plugin.canvas3d) === null || _b === void 0 ? void 0 : _b.webgl, ...plugin.representation.structure.themes }, provider.getParams); await Theme.ensureDependencies(propertyCtx, plugin.representation.structure.themes, { structure: data }, params); repr.setTheme(Theme.create(plugin.representation.structure.themes, { structure: data }, params)); const props = params.type.params || {}; await repr.createOrUpdate(props, data).runInContext(ctx); return new SO.Molecule.Structure.Representation3D({ repr, sourceData: a.data }, { label: provider.label }); }); }, update({ a, b, oldParams, newParams, cache }, plugin) { return Task.create('Structure Representation', async (ctx) => { var _a, _b; if (newParams.type.name !== oldParams.type.name) return StateTransformer.UpdateResult.Recreate; const provider = plugin.representation.structure.registry.get(newParams.type.name); if ((_a = provider.mustRecreate) === null || _a === void 0 ? void 0 : _a.call(provider, oldParams.type.params, newParams.type.params)) return StateTransformer.UpdateResult.Recreate; const data = ((_b = provider.getData) === null || _b === void 0 ? void 0 : _b.call(provider, a.data, newParams.type.params)) || a.data; const propertyCtx = { runtime: ctx, assetManager: plugin.managers.asset, errorContext: plugin.errorContext }; if (provider.ensureCustomProperties) await provider.ensureCustomProperties.attach(propertyCtx, data); // TODO: if themes had a .needsUpdate method the following block could // be optimized and only executed conditionally Theme.releaseDependencies(plugin.representation.structure.themes, { structure: b.data.sourceData }, oldParams); await Theme.ensureDependencies(propertyCtx, plugin.representation.structure.themes, { structure: data }, newParams); b.data.repr.setTheme(Theme.create(plugin.representation.structure.themes, { structure: data }, newParams)); const props = { ...b.data.repr.props, ...newParams.type.params }; await b.data.repr.createOrUpdate(props, data).runInContext(ctx); b.data.sourceData = a.data; return StateTransformer.UpdateResult.Updated; }); }, dispose({ b, params }, plugin) { if (!b || !params) return; const structure = b.data.sourceData; const provider = plugin.representation.structure.registry.get(params.type.name); if (provider.ensureCustomProperties) provider.ensureCustomProperties.detach(structure); Theme.releaseDependencies(plugin.representation.structure.themes, { structure }, params); }, interpolate(src, tar, t) { if (src.colorTheme.name !== 'uniform' || tar.colorTheme.name !== 'uniform') { return t <= 0.5 ? src : tar; } const from = src.colorTheme.params.value, to = tar.colorTheme.params.value; const value = Color.interpolate(from, to, t); return { type: t <= 0.5 ? src.type : tar.type, colorTheme: { name: 'uniform', params: { value } }, sizeTheme: t <= 0.5 ? src.sizeTheme : tar.sizeTheme, }; } }); const UnwindStructureAssemblyRepresentation3D = PluginStateTransform.BuiltIn({ name: 'unwind-structure-assembly-representation-3d', display: 'Unwind Assembly 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: { t: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }) } })({ canAutoUpdate() { return true; }, apply({ a, params }) { const structure = a.data.sourceData; const unitTransforms = new StructureUnitTransforms(structure); unwindStructureAssembly(structure, unitTransforms, params.t); return new SO.Molecule.Structure.Representation3DState({ state: { unitTransforms }, initialState: { unitTransforms: new StructureUnitTransforms(structure) }, info: structure, repr: a.data.repr }, { label: `Unwind T = ${params.t.toFixed(2)}` }); }, update({ a, b, newParams, oldParams }) { const structure = b.data.info; if (a.data.sourceData !== structure) return StateTransformer.UpdateResult.Recreate; if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate; if (oldParams.t === newParams.t) return StateTransformer.UpdateResult.Unchanged; const unitTransforms = b.data.state.unitTransforms; unwindStructureAssembly(structure, unitTransforms, newParams.t); b.label = `Unwind T = ${newParams.t.toFixed(2)}`; b.data.repr = a.data.repr; return StateTransformer.UpdateResult.Updated; } }); const ExplodeStructureRepresentation3D = PluginStateTransform.BuiltIn({ name: 'explode-structure-representation-3d', display: 'Explode 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: { t: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }) } })({ canAutoUpdate() { return true; }, apply({ a, params }) { const structure = a.data.sourceData; const unitTransforms = new StructureUnitTransforms(structure); explodeStructure(structure, unitTransforms, params.t, structure.root.boundary.sphere); return new SO.Molecule.Structure.Representation3DState({ state: { unitTransforms }, initialState: { unitTransforms: new StructureUnitTransforms(structure) }, info: structure, repr: a.data.repr }, { label: `Explode T = ${params.t.toFixed(2)}` }); }, update({ a, b, newParams, oldParams }) { const structure = a.data.sourceData; if (b.data.info !== structure) return StateTransformer.UpdateResult.Recreate; if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate; if (oldParams.t === newParams.t) return StateTransformer.UpdateResult.Unchanged; const unitTransforms = b.data.state.unitTransforms; explodeStructure(structure, unitTransforms, newParams.t, structure.root.boundary.sphere); b.label = `Explode T = ${newParams.t.toFixed(2)}`; b.data.repr = a.data.repr; return StateTransformer.UpdateResult.Updated; } }); 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); 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) }, info: structure, 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) 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, unitTransforms, newParams.t, axis, origin); b.label = `Spin T = ${newParams.t.toFixed(2)}`; b.data.repr = a.data.repr; return StateTransformer.UpdateResult.Updated; } }); const OverpaintStructureRepresentation3DFromScript = PluginStateTransform.BuiltIn({ name: 'overpaint-structure-representation-3d-from-script', display: 'Overpaint 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: () => ({ layers: PD.ObjectList({ script: PD.Script(Script('(sel.atom.all)', 'mol-script')), color: PD.Color(ColorNames.blueviolet), clear: PD.Boolean(false) }, e => `${e.clear ? 'Clear' : Color.toRgbString(e.color)}`, { defaultValue: [{ script: Script('(sel.atom.all)', 'mol-script'), color: ColorNames.blueviolet, clear: false }] }), }) })({ canAutoUpdate() { return true; }, apply({ a, params }) { const structure = a.data.sourceData; const geometryVersion = a.data.repr.geometryVersion; const overpaint = Overpaint.ofScript(params.layers, structure); return new SO.Molecule.Structure.Representation3DState({ state: { overpaint }, initialState: { overpaint: Overpaint.Empty }, info: { structure, geometryVersion }, repr: a.data.repr }, { label: `Overpaint (${overpaint.layers.length} Layers)` }); }, update({ a, b, newParams, oldParams }) { const info = b.data.info; const newStructure = a.data.sourceData; if (newStructure !== info.structure) return StateTransformer.UpdateResult.Recreate; if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate; const newGeometryVersion = a.data.repr.geometryVersion; // smoothing needs to be re-calculated when geometry changes if (newGeometryVersion !== info.geometryVersion && hasColorSmoothingProp(a.data.repr.props)) return StateTransformer.UpdateResult.Recreate; const oldOverpaint = b.data.state.overpaint; const newOverpaint = Overpaint.ofScript(newParams.layers, newStructure); if (Overpaint.areEqual(oldOverpaint, newOverpaint)) return StateTransformer.UpdateResult.Unchanged; info.geometryVersion = newGeometryVersion; b.data.state.overpaint = newOverpaint; b.data.repr = a.data.repr; b.label = `Overpaint (${newOverpaint.layers.length} Layers)`; return StateTransformer.UpdateResult.Updated; } }); const OverpaintStructureRepresentation3DFromBundle = PluginStateTransform.BuiltIn({ name: 'overpaint-structure-representation-3d-from-bundle', display: 'Overpaint 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: () => ({ layers: PD.ObjectList({ bundle: PD.Value(StructureElement.Bundle.Empty), color: PD.Color(ColorNames.blueviolet), clear: PD.Boolean(false) }, e => `${e.clear ? 'Clear' : Color.toRgbString(e.color)}`, { defaultValue: [{ bundle: StructureElement.Bundle.Empty, color: ColorNames.blueviolet, clear: false }], isHidden: true }), }) })({ canAutoUpdate() { return true; }, apply({ a, params }) { const structure = a.data.sourceData; const geometryVersion = a.data.repr.geometryVersion; const overpaint = Overpaint.ofBundle(params.layers, structure); return new SO.Molecule.Structure.Representation3DState({ state: { overpaint }, initialState: { overpaint: Overpaint.Empty }, info: { structure, geometryVersion }, repr: a.data.repr }, { label: `Overpaint (${overpaint.layers.length} Layers)` }); }, update({ a, b, newParams, oldParams }) { const info = b.data.info; const newStructure = a.data.sourceData; if (newStructure !== info.structure) return StateTransformer.UpdateResult.Recreate; if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate; const newGeometryVersion = a.data.repr.geometryVersion; // smoothing needs to be re-calculated when geometry changes if (newGeometryVersion !== info.geometryVersion && hasColorSmoothingProp(a.data.repr.props)) return StateTransformer.UpdateResult.Recreate; const oldOverpaint = b.data.state.overpaint; const newOverpaint = Overpaint.ofBundle(newParams.layers, newStructure); if (Overpaint.areEqual(oldOverpaint, newOverpaint)) return StateTransformer.UpdateResult.Unchanged; info.geometryVersion = newGeometryVersion; b.data.state.overpaint = newOverpaint; b.data.repr = a.data.repr; b.label = `Overpaint (${newOverpaint.layers.length} Layers)`; return StateTransformer.UpdateResult.Updated; } }); const TransparencyStructureRepresentation3DFromScript = PluginStateTransform.BuiltIn({ name: 'transparency-structure-representation-3d-from-script', display: 'Transparency 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: () => ({ layers: PD.ObjectList({ script: PD.Script(Script('(sel.atom.all)', 'mol-script')), value: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }, { label: 'Transparency' }), }, e => `Transparency (${e.value})`, { defaultValue: [{ script: Script('(sel.atom.all)', 'mol-script'), value: 0.5, }] }) }) })({ canAutoUpdate() { return true; }, apply({ a, params }) { const structure = a.data.sourceData; const geometryVersion = a.data.repr.geometryVersion; const transparency = Transparency.ofScript(params.layers, structure); return new SO.Molecule.Structure.Representation3DState({ state: { transparency }, initialState: { transparency: Transparency.Empty }, info: { structure, geometryVersion }, repr: a.data.repr }, { label: `Transparency (${transparency.layers.length} Layers)` }); }, update({ a, b, newParams, oldParams }) { const info = b.data.info; const newStructure = a.data.sourceData; if (newStructure !== info.structure) return StateTransformer.UpdateResult.Recreate; if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate; const newGeometryVersion = a.data.repr.geometryVersion; // smoothing needs to be re-calculated when geometry changes if (newGeometryVersion !== info.geometryVersion && hasColorSmoothingProp(a.data.repr.props)) return StateTransformer.UpdateResult.Recreate; const oldTransparency = b.data.state.transparency; const newTransparency = Transparency.ofScript(newParams.layers, newStructure); if (Transparency.areEqual(oldTransparency, newTransparency)) return StateTransformer.UpdateResult.Unchanged; info.geometryVersion = newGeometryVersion; b.data.state.transparency = newTransparency; b.data.repr = a.data.repr; b.label = `Transparency (${newTransparency.layers.length} Layers)`; return StateTransformer.UpdateResult.Updated; } }); const TransparencyStructureRepresentation3DFromBundle = PluginStateTransform.BuiltIn({ name: 'transparency-structure-representation-3d-from-bundle', display: 'Transparency 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: () => ({ layers: PD.ObjectList({ bundle: PD.Value(StructureElement.Bundle.Empty), value: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }, { label: 'Transparency' }), }, e => `Transparency (${e.value})`, { defaultValue: [{ bundle: StructureElement.Bundle.Empty, value: 0.5, }], isHidden: true }) }) })({ canAutoUpdate() { return true; }, apply({ a, params }) { const structure = a.data.sourceData; const geometryVersion = a.data.repr.geometryVersion; const transparency = Transparency.ofBundle(params.layers, structure); return new SO.Molecule.Structure.Representation3DState({ state: { transparency }, initialState: { transparency: Transparency.Empty }, info: { structure, geometryVersion }, repr: a.data.repr }, { label: `Transparency (${transparency.layers.length} Layers)` }); }, update({ a, b, newParams, oldParams }) { const info = b.data.info; const newStructure = a.data.sourceData; if (newStructure !== info.structure) return StateTransformer.UpdateResult.Recreate; if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate; const newGeometryVersion = a.data.repr.geometryVersion; // smoothing needs to be re-calculated when geometry changes if (newGeometryVersion !== info.geometryVersion && hasColorSmoothingProp(a.data.repr.props)) return StateTransformer.UpdateResult.Recreate; const oldTransparency = b.data.state.transparency; const newTransparency = Transparency.ofBundle(newParams.layers, newStructure); if (Transparency.areEqual(oldTransparency, newTransparency)) return StateTransformer.UpdateResult.Unchanged; info.geometryVersion = newGeometryVersion; b.data.state.transparency = newTransparency; b.data.repr = a.data.repr; b.label = `Transparency (${newTransparency.layers.length} Layers)`; return StateTransformer.UpdateResult.Updated; } }); const EmissiveStructureRepresentation3DFromScript = PluginStateTransform.BuiltIn({ name: 'emissive-structure-representation-3d-from-script', display: 'Emissive 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: () => ({ layers: PD.ObjectList({ script: PD.Script(Script('(sel.atom.all)', 'mol-script')), value: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }, { label: 'Emissive' }), }, e => `Emissive (${e.value})`, { defaultValue: [{ script: Script('(sel.atom.all)', 'mol-script'), value: 0.5, }] }) }) })({ canAutoUpdate() { return true; }, apply({ a, params }) { const structure = a.data.sourceData; const geometryVersion = a.data.repr.geometryVersion; const emissive = Emissive.ofScript(params.layers, structure); return new SO.Molecule.Structure.Representation3DState({ state: { emissive }, initialState: { emissive: Emissive.Empty }, info: { structure, geometryVersion }, repr: a.data.repr }, { label: `Emissive (${emissive.layers.length} Layers)` }); }, update({ a, b, newParams, oldParams }) { const info = b.data.info; const newStructure = a.data.sourceData; if (newStructure !== info.structure) return StateTransformer.UpdateResult.Recreate; if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate; const newGeometryVersion = a.data.repr.geometryVersion; // smoothing needs to be re-calculated when geometry changes if (newGeometryVersion !== info.geometryVersion && hasColorSmoothingProp(a.data.repr.props)) return StateTransformer.UpdateResult.Recreate; const oldEmissive = b.data.state.emissive; const newEmissive = Emissive.ofScript(newParams.layers, newStructure); if (Emissive.areEqual(oldEmissive, newEmissive)) return StateTransformer.UpdateResult.Unchanged; info.geometryVersion = newGeometryVersion; b.data.state.emissive = newEmissive; b.data.repr = a.data.repr; b.label = `Emissive (${newEmissive.layers.length} Layers)`; return StateTransformer.UpdateResult.Updated; } }); const EmissiveStructureRepresentation3DFromBundle = PluginStateTransform.BuiltIn({ name: 'emissive-structure-representation-3d-from-bundle', display: 'Emissive 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: () => ({ layers: PD.ObjectList({ bundle: PD.Value(StructureElement.Bundle.Empty), value: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }, { label: 'Emissive' }), }, e => `Emissive (${e.value})`, { defaultValue: [{ bundle: StructureElement.Bundle.Empty, value: 0.5, }], isHidden: true }) }) })({ canAutoUpdate() { return true; }, apply({ a, params }) { const structure = a.data.sourceData; const geometryVersion = a.data.repr.geometryVersion; const emissive = Emissive.ofBundle(params.layers, structure); return new SO.Molecule.Structure.Representation3DState({ state: { emissive }, initialState: { emissive: Emissive.Empty }, info: { structure, geometryVersion }, repr: a.data.repr }, { label: `Emissive (${emissive.layers.length} Layers)` }); }, update({ a, b, newParams, oldParams }) { const info = b.data.info; const newStructure = a.data.sourceData; if (newStructure !== info.structure) return StateTransformer.UpdateResult.Recreate; if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate; const newGeometryVersion = a.data.repr.geometryVersion; // smoothing needs to be re-calculated when geometry changes if (newGeometryVersion !== info.geometryVersion && hasColorSmoothingProp(a.data.repr.props)) return StateTransformer.UpdateResult.Recreate; const oldEmissive = b.data.state.emissive; const newEmissive = Emissive.ofBundle(newParams.layers, newStructure); if (Emissive.areEqual(oldEmissive, newEmissive)) return StateTransformer.UpdateResult.Unchanged; info.geometryVersion = newGeometryVersion; b.data.state.emissive = newEmissive; b.data.repr = a.data.repr; b.label = `Emissive (${newEmissive.layers.length} Layers)`; return StateTransformer.UpdateResult.Updated; } }); const SubstanceStructureRepresentation3DFromScript = PluginStateTransform.BuiltIn({ name: 'substance-structure-representation-3d-from-script', display: 'Substance 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: () => ({ layers: PD.ObjectList({ script: PD.Script(Script('(sel.atom.all)', 'mol-script')), material: Material.getParam(), clear: PD.Boolean(false) }, e => `${e.clear ? 'Clear' : Material.toString(e.material)}`, { defaultValue: [{ script: Script('(sel.atom.all)', 'mol-script'), material: Material({ roughness: 1 }), clear: false }] }), }) })({ canAutoUpdate() { return true; }, apply({ a, params }) { const structure = a.data.sourceData; const geometryVersion = a.data.repr.geometryVersion; const substance = Substance.ofScript(params.layers, structure); return new SO.Molecule.Structure.Representation3DState({ state: { substance }, initialState: { substance: Substance.Empty }, info: { structure, geometryVersion }, repr: a.data.repr }, { label: `Substance (${substance.layers.length} Layers)` }); }, update({ a, b, newParams, oldParams }) { const info = b.data.info; const newStructure = a.data.sourceData; if (newStructure !== info.structure) return StateTransformer.UpdateResult.Recreate; if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate; const newGeometryVersion = a.data.repr.geometryVersion; // smoothing needs to be re-calculated when geometry changes if (newGeometryVersion !== info.geometryVersion && hasColorSmoothingProp(a.data.repr.props)) return StateTransformer.UpdateResult.Recreate; const oldSubstance = b.data.state.substance; const newSubstance = Substance.ofScript(newParams.layers, newStructure); if (Substance.areEqual(oldSubstance, newSubstance)) return StateTransformer.UpdateResult.Unchanged; info.geometryVersion = newGeometryVersion; b.data.state.substance = newSubstance; b.data.repr = a.data.repr; b.label = `Substance (${newSubstance.layers.length} Layers)`; return StateTransformer.UpdateResult.Updated; } }); const SubstanceStructureRepresentation3DFromBundle = PluginStateTransform.BuiltIn({ name: 'substance-structure-representation-3d-from-bundle', display: 'Substance 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: () => ({ layers: PD.ObjectList({ bundle: PD.Value(StructureElement.Bundle.Empty), material: Material.getParam(), clear: PD.Boolean(false) }, e => `${e.clear ? 'Clear' : Material.toString(e.material)}`, { defaultValue: [{ bundle: StructureElement.Bundle.Empty, material: Material({ roughness: 1 }), clear: false }], isHidden: true }), }) })({ canAutoUpdate() { return true; }, apply({ a, params }) { const structure = a.data.sourceData; const geometryVersion = a.data.repr.geometryVersion; const substance = Substance.ofBundle(params.layers, structure); return new SO.Molecule.Structure.Representation3DState({ state: { substance }, initialState: { substance: Substance.Empty }, info: { structure, geometryVersion }, repr: a.data.repr }, { label: `Substance (${substance.layers.length} Layers)` }); }, update({ a, b, newParams, oldParams }) { const info = b.data.info; const newStructure = a.data.sourceData; if (newStructure !== info.structure) return StateTransformer.UpdateResult.Recreate; if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate; const newGeometryVersion = a.data.repr.geometryVersion; // smoothing needs to be re-calculated when geometry changes if (newGeometryVersion !== info.geometryVersion && hasColorSmoothingProp(a.data.repr.props)) return StateTransformer.UpdateResult.Recreate; const oldSubstance = b.data.state.substance; const newSubstance = Substance.ofBundle(newParams.layers, newStructure); if (Substance.areEqual(oldSubstance, newSubstance)) return StateTransformer.UpdateResult.Unchanged; info.geometryVersion = newGeometryVersion; b.data.state.substance = newSubstance; b.data.repr = a.data.repr; b.label = `Substance (${newSubstance.layers.length} Layers)`; return StateTransformer.UpdateResult.Updated; } }); const ClippingStructureRepresentation3DFromScript = PluginStateTransform.BuiltIn({ name: 'clipping-structure-representation-3d-from-script', display: 'Clipping 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: () => ({ layers: PD.ObjectList({ script: PD.Script(Script('(sel.atom.all)', 'mol-script')), groups: PD.Converted((g) => Clipping.Groups.toNames(g), n => Clipping.Groups.fromNames(n), PD.MultiSelect(ObjectKeys(Clipping.Groups.Names), PD.objectToOptions(Clipping.Groups.Names))), }, e => `${Clipping.Groups.toNames(e.groups).length} group(s)`, { defaultValue: [{ script: Script('(sel.atom.all)', 'mol-script'), groups: Clipping.Groups.Flag.None, }] }), }) })({ canAutoUpdate() { return true; }, apply({ a, params }) { const structure = a.data.sourceData; const clipping = Clipping.ofScript(params.layers, structure); return new SO.Molecule.Structure.Representation3DState({ state: { clipping }, initialState: { clipping: Clipping.Empty }, info: structure, repr: a.data.repr }, { label: `Clipping (${clipping.layers.length} Layers)` }); }, update({ a, b, newParams, oldParams }) { const structure = b.data.info; if (a.data.sourceData !== structure) return StateTransformer.UpdateResult.Recreate; if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate; const oldClipping = b.data.state.clipping; const newClipping = Clipping.ofScript(newParams.layers, structure); if (Clipping.areEqual(oldClipping, newClipping)) return StateTransformer.UpdateResult.Unchanged; b.data.state.clipping = newClipping; b.data.repr = a.data.repr; b.label = `Clipping (${newClipping.layers.length} Layers)`; return StateTransformer.UpdateResult.Updated; } }); const ClippingStructureRepresentation3DFromBundle = PluginStateTransform.BuiltIn({ name: 'clipping-structure-representation-3d-from-bundle', display: 'Clipping 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: () => ({ layers: PD.ObjectList({ bundle: PD.Value(StructureElement.Bundle.Empty), groups: PD.Converted((g) => Clipping.Groups.toNames(g), n => Clipping.Groups.fromNames(n), PD.MultiSelect(ObjectKeys(Clipping.Groups.Names), PD.objectToOptions(Clipping.Groups.Names))), }, e => `${Clipping.Groups.toNames(e.groups).length} group(s)`, { defaultValue: [{ bundle: StructureElement.Bundle.Empty, groups: Clipping.Groups.Flag.None, }], isHidden: true }), }) })({ canAutoUpdate() { return true; }, apply({ a, params }) { const structure = a.data.sourceData; const clipping = Clipping.ofBundle(params.layers, structure); return new SO.Molecule.Structure.Representation3DState({ state: { clipping }, initialState: { clipping: Clipping.Empty }, info: structure, repr: a.data.repr }, { label: `Clipping (${clipping.layers.length} Layers)` }); }, update({ a, b, newParams, oldParams }) { const structure = b.data.info; if (a.data.sourceData !== structure) return StateTransformer.UpdateResult.Recreate; if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate; const oldClipping = b.data.state.clipping; const newClipping = Clipping.ofBundle(newParams.layers, structure); if (Clipping.areEqual(oldClipping, newClipping)) return StateTransformer.UpdateResult.Unchanged; b.data.state.clipping = newClipping; b.data.repr = a.data.repr; b.label = `Clipping (${newClipping.layers.length} Layers)`; return StateTransformer.UpdateResult.Updated; } }); const ThemeStrengthRepresentation3D = PluginStateTransform.BuiltIn({ name: 'theme-strength-representation-3d', display: 'Theme Strength 3D Representation', from: SO.Molecule.Structure.Representation3D, to: SO.Molecule.Structure.Representation3DState, params: () => ({ overpaintStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }), transparencyStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }), emissiveStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }), substanceStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }), }) })({ canAutoUpdate() { return true; }, apply({ a, params }) { return new SO.Molecule.Structure.Representation3DState({ state: { themeStrength: { overpaint: params.overpaintStrength, transparency: params.transparencyStrength, emissive: params.emissiveStrength, substance: params.substanceStrength }, }, initialState: { themeStrength: { overpaint: 1, transparency: 1, emissive: 1, substance: 1 }, }, info: {}, repr: a.data.repr }, { label: 'Theme Strength', description: `${params.overpaintStrength.toFixed(2)}, ${params.transparencyStrength.toFixed(2)}, ${params.emissiveStrength.toFixed(2)}, ${params.substanceStrength.toFixed(2)}` }); }, update({ a, b, newParams, oldParams }) { var _a, _b, _c, _d; if (newParams.overpaintStrength === ((_a = b.data.state.themeStrength) === null || _a === void 0 ? void 0 : _a.overpaint) && newParams.transparencyStrength === ((_b = b.data.state.themeStrength) === null || _b === void 0 ? void 0 : _b.transparency) && newParams.emissiveStrength === ((_c = b.data.state.themeStrength) === null || _c === void 0 ? void 0 : _c.emissive) && newParams.substanceStrength === ((_d = b.data.state.themeStrength) === null || _d === void 0 ? void 0 : _d.substance)) return StateTransformer.UpdateResult.Unchanged; b.data.state.themeStrength = { overpaint: newParams.overpaintStrength, transparency: newParams.transparencyStrength, emissive: newParams.emissiveStrength, substance: newParams.substanceStrength, }; b.data.repr = a.data.repr; b.label = 'Theme Strength'; b.description = `${newParams.overpaintStrength.toFixed(2)}, ${newParams.transparencyStrength.toFixed(2)}, ${newParams.emissiveStrength.toFixed(2)}, ${newParams.substanceStrength.toFixed(2)}`; return StateTransformer.UpdateResult.Updated; }, interpolate(src, tar, t) { return { overpaintStrength: lerp(src.overpaintStrength, tar.overpaintStrength, t), transparencyStrength: lerp(src.transparencyStrength, tar.transparencyStrength, t), emissiveStrength: lerp(src.emissiveStrength, tar.emissiveStrength, t), substanceStrength: lerp(src.substanceStrength, tar.substanceStrength, t), }; } }); // export var VolumeRepresentation3DHelpers; (function (VolumeRepresentation3DHelpers) { function getDefaultParams(ctx, name, volume, volumeParams, colorName, colorParams, sizeName, sizeParams) { const type = ctx.representation.volume.registry.get(name); const colorType = ctx.representation.volume.themes.colorThemeRegistry.get(colorName || type.defaultColorTheme.name); const sizeType = ctx.representation.volume.themes.sizeThemeRegistry.get(sizeName || type.defaultSizeTheme.name); const volumeDefaultParams = PD.getDefaultValues(type.getParams(ctx.representation.volume.themes, volume)); return ({ type: { name, params: volumeParams ? { ...volumeDefaultParams, ...volumeParams } : volumeDefaultParams }, colorTheme: { name: colorType.name, params: colorParams ? { ...colorType.defaultValues, ...colorParams } : colorType.defaultValues }, sizeTheme: { name: sizeType.name, params: sizeParams ? { ...sizeType.defaultValues, ...sizeParams } : sizeType.defaultValues } }); } VolumeRepresentation3DHelpers.getDefaultParams = getDefaultParams; function getDefaultParamsStatic(ctx, name, volumeParams, colorName, colorParams, sizeName, sizeParams) { const type = ctx.representation.volume.registry.get(name); const colorType = ctx.representation.volume.themes.colorThemeRegistry.get(colorName || type.defaultColorTheme.name); const sizeType = ctx.representation.volume.themes.sizeThemeRegistry.get(sizeName || type.defaultSizeTheme.name); return ({ type: { name, params: volumeParams ? { ...type.defaultValues, ...volumeParams } : type.defaultValues }, colorTheme: { name: type.defaultColorTheme.name, params: colorParams ? { ...colorType.defaultValues, ...colorParams } : colorType.defaultValues }, sizeTheme: { name: type.defaultSizeTheme.name, params: sizeParams ? { ...sizeType.defaultValues, ...sizeParams } : sizeType.defaultValues } }); } VolumeRepresentation3DHelpers.getDefaultParamsStatic = getDefaultParamsStatic; function getDescription(props) { var _a, _b, _c, _d; if (props.isoValue) { return Volume.IsoValue.toString(props.isoValue); } else if ((_b = (_a = props.renderMode) === null || _a === void 0 ? void 0 : _a.params) === null || _b === void 0 ? void 0 : _b.isoValue) { return Volume.IsoValue.toString((_d = (_c = props.renderMode) === null || _c === void 0 ? void 0 : _c.params) === null || _d === void 0 ? void 0 : _d.isoValue); } } VolumeRepresentation3DHelpers.getDescription = getDescription; })(VolumeRepresentation3DHelpers || (VolumeRepresentation3DHelpers = {})); const VolumeRepresentation3D = PluginStateTransform.BuiltIn({ name: 'volume-representation-3d', display: '3D Representation', from: SO.Volume.Data, to: SO.Volume.Representation3D, params: (a, ctx) => { const { registry, themes: themeCtx } = ctx.representation.volume; const type = registry.get(registry.default.name); if (!a) { return { type: PD.Mapped(registry.default.name, registry.types, name => PD.Group(registry.get(name).getParams(themeCtx, Volume.One))), colorTheme: PD.Mapped(type.defaultColorTheme.name, themeCtx.colorThemeRegistry.types, name => PD.Group(themeCtx.colorThemeRegistry.get(name).getParams({ volume: Volume.One }))), sizeTheme: PD.Mapped(type.defaultSizeTheme.name, themeCtx.sizeThemeRegistry.types, name => PD.Group(themeCtx.sizeThemeRegistry.get(name).getParams({ volume: Volume.One }))) }; } const dataCtx = { volume: a.data }; return ({ type: PD.Mapped(registry.default.name, registry.types, name => PD.Group(registry.get(name).getParams(themeCtx, a.data))), colorTheme: PD.Mapped(type.defaultColorTheme.name, themeCtx.colorThemeRegistry.getApplicableTypes(dataCtx), name => PD.Group(themeCtx.colorThemeRegistry.get(name).getParams(dataCtx))), sizeTheme: PD.Mapped(type.defaultSizeTheme.name, themeCtx.sizeThemeRegistry.getApplicableTypes(dataCtx), name => PD.Group(themeCtx.sizeThemeRegistry.get(name).getParams(dataCtx))) }); } })({ canAutoUpdate({ oldParams, newParams }) { return oldParams.type.name === newParams.type.name; }, apply({ a, params }, plugin) { return Task.create('Volume Representation', async (ctx) => { var _a; const propertyCtx = { runtime: ctx, assetManager: plugin.managers.asset, errorContext: plugin.errorContext }; const provider = plugin.representation.volume.registry.get(params.type.name); if (provider.ensureCustomProperties) await provider.ensureCustomProperties.attach(propertyCtx, a.data); const repr = provider.factory({ webgl: (_a = plugin.canvas3d) === null || _a === void 0 ? void 0 : _a.webgl, ...plugin.representation.volume.themes }, provider.getParams); repr.setTheme(Theme.create(plugin.representation.volume.themes, { volume: a.data, locationKinds: provider.locationKinds }, params)); const props = params.type.params || {}; await repr.createOrUpdate(props, a.data).runInContext(ctx); return new SO.Volume.Representation3D({ repr, sourceData: a.data }, { label: provider.label, description: VolumeRepresentation3DHelpers.getDescription(props) }); }); }, update({ a, b, oldParams, newParams }, plugin) { return Task.create('Volume Representation', async (ctx) => { var _a; const oldProvider = plugin.representation.volume.registry.get(oldParams.type.name); if (newParams.type.name !== oldParams.type.name) { (_a = oldProvider.ensureCustomProperties) === null || _a === void 0 ? void 0 : _a.detach(a.data); return StateTransformer.UpdateResult.Recreate; } const props = { ...b.data.repr.props, ...newParams.type.params }; b.data.repr.setTheme(Theme.create(plugin.representation.volume.themes, { volume: a.data, locationKinds: oldProvider.locationKinds }, newParams)); await b.data.repr.createOrUpdate(props, a.data).runInContext(ctx); b.data.sourceData = a.data; b.description = VolumeRepresentation3DHelpers.getDescription(props); return StateTransformer.UpdateResult.Updated; }); } }); // export { ShapeRepresentation3D }; const ShapeRepresentation3D = PluginStateTransform.BuiltIn({ name: 'shape-representation-3d', display: '3D Representation', from: SO.Shape.Provider, to: SO.Shape.Representation3D, params: (a, ctx) => { return a ? a.data.params : BaseGeometry.Params; } })({ canAutoUpdate() { return true; }, apply({ a, params }, plugin) { return Task.create('Shape Representation', async (ctx) => { const props = { ...PD.getDefaultValues(a.data.params), ...params }; const repr = ShapeRepresentation(a.data.getShape, a.data.geometryUtils); await rep