UNPKG

molstar

Version:

A comprehensive macromolecular library.

128 lines (127 loc) 5.72 kB
/** * Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { Mat4 } from '../../../../mol-math/linear-algebra/3d/mat4'; import { Structure, Unit } from '../../../../mol-model/structure'; import { PluginStateObject as SO, PluginStateTransform } from '../../../../mol-plugin-state/objects'; import { Task } from '../../../../mol-task'; import { StateObject, StateTransformer } from '../../../../mol-state'; import { ParamDefinition as PD } from '../../../../mol-util/param-definition'; import { SymmetryOperator } from '../../../../mol-math/geometry'; import { mergeUnits, partitionUnits } from '../util'; import { Symmetry } from '../../../../mol-model/structure/model/properties/symmetry'; import { ModelSymmetry } from '../../../../mol-model-formats/structure/property/symmetry'; import { SortedArray } from '../../../../mol-data/int'; import { getTransforms } from './preset'; import { deepEqual } from '../../../../mol-util'; function createModelChainMap(model) { const builder = new Structure.StructureBuilder(); const units = new Map(); const { label_asym_id, _rowCount } = model.atomicHierarchy.chains; const { offsets } = model.atomicHierarchy.chainAtomSegments; for (let i = 0; i < _rowCount; i++) { const elements = SortedArray.ofBounds(offsets[i], offsets[i + 1]); const unit = builder.addUnit(0 /* Unit.Kind.Atomic */, model, SymmetryOperator.Default, elements, Unit.Trait.FastBoundary); units.set(label_asym_id.value(i), unit); } return units; } function buildAssembly(model, assembly) { const coordinateSystem = SymmetryOperator.create(assembly.id, Mat4.identity(), { assembly: { id: assembly.id, operId: 0, operList: [] } }); const assembler = Structure.Builder({ coordinateSystem, label: model.label, }); const units = createModelChainMap(model); for (const g of assembly.operatorGroups) { for (const oper of g.operators) { for (const id of g.asymIds) { const u = units.get(id); if (u) { assembler.addWithOperator(u, oper); } else { console.log(`missing asymId '${id}'`); } } } } return assembler.getStructure(); } const EmptyInstances = { positions: { data: [] }, rotations: { variant: 'euler', data: [] } }; export { StructureFromGeneric }; const StructureFromGeneric = PluginStateTransform.BuiltIn({ name: 'structure-from-generic', display: { name: 'Structure from Generic', description: 'Create a molecular structure from Generic models.' }, from: SO.Molecule.Model, to: SO.Molecule.Structure, params: { instances: PD.Value(EmptyInstances), label: PD.Optional(PD.Text('')), description: PD.Optional(PD.Text('')), cellSize: PD.Numeric(500, { min: 0, max: 10000, step: 100 }), } })({ apply({ a, params }, plugin) { return Task.create('Build Structure', async (ctx) => { var _a; const transforms = await getTransforms(plugin, params.instances); if (transforms.length === 0) return StateObject.Null; const model = a.data; const label = params.label || model.label; const base = Structure.ofModel(a.data); let structure; if (transforms.length === 1 && Mat4.isIdentity(transforms[0])) { const symmetry = ModelSymmetry.Provider.get(model); const id = (_a = symmetry === null || symmetry === void 0 ? void 0 : symmetry.assemblies[0]) === null || _a === void 0 ? void 0 : _a.id; const asm = Symmetry.findAssembly(model, id || ''); if (asm) { structure = buildAssembly(model, asm); } else { const mergedUnits = partitionUnits(base.units, params.cellSize); structure = Structure.create(mergedUnits, { label }); } } else { const assembler = Structure.Builder({ label }); const unit = mergeUnits(base.units, 0); for (let i = 0, il = transforms.length; i < il; ++i) { const t = transforms[i]; const op = SymmetryOperator.create(`op-${i}`, t); assembler.addWithOperator(unit, op); } structure = assembler.getStructure(); } const props = { label, description: params.description || Structure.elementDescription(structure) }; return new SO.Molecule.Structure(structure, props); }); }, update({ newParams, oldParams }, plugin) { if (deepEqual(newParams, oldParams)) { return StateTransformer.UpdateResult.Unchanged; } if (oldParams.instances) releaseInstances(plugin, oldParams.instances); return StateTransformer.UpdateResult.Recreate; }, dispose({ b, params }, plugin) { b === null || b === void 0 ? void 0 : b.data.customPropertyDescriptors.dispose(); if (params === null || params === void 0 ? void 0 : params.instances) releaseInstances(plugin, params.instances); } }); function releaseInstances(plugin, instances) { if (!Array.isArray(instances.positions.data)) { plugin.managers.asset.release(instances.positions.data.file); } if (!Array.isArray(instances.rotations.data)) { plugin.managers.asset.release(instances.rotations.data.file); } }