diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index 224ec2f084f6ad0519d11d66c442f13d239181b7..d4e76255bbccc94bb56e78155ddfd51fad43b24a 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -21,7 +21,7 @@ import StructureProperties from './properties'; import { ResidueIndex, ChainIndex, EntityIndex } from '../model/indexing'; import { Carbohydrates } from './carbohydrates/data'; import { computeCarbohydrates } from './carbohydrates/compute'; -import { Vec3 } from 'mol-math/linear-algebra'; +import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { idFactory } from 'mol-util/id-factory'; import { GridLookup3D } from 'mol-math/geometry'; import { UUID } from 'mol-util'; @@ -344,6 +344,20 @@ namespace Structure { } } + export function transform(s: Structure, transform: Mat4) { + if (Mat4.isIdentity(transform)) return s; + if (!Mat4.isRotationAndTranslation(transform)) throw new Error('Only rotation/translation combination can be applied.'); + + const units: Unit[] = []; + for (const u of s.units) { + const old = u.conformation.operator; + const op = SymmetryOperator.create(old.name, transform, old.hkl); + units.push(u.applyOperator(u.id, op)); + } + + return new Structure(units); + } + export class StructureBuilder { private units: Unit[] = []; private invariantId = idFactory() diff --git a/src/mol-plugin/state/transforms/model.ts b/src/mol-plugin/state/transforms/model.ts index 535003639479689f9088f7a919060139f1addffb..1ebe478e28a9ffcd0dff29c587c5aac811bb401d 100644 --- a/src/mol-plugin/state/transforms/model.ts +++ b/src/mol-plugin/state/transforms/model.ts @@ -11,6 +11,7 @@ import { Model, Format, Structure, ModelSymmetry, StructureSymmetry, QueryContex import { ParamDefinition as PD } from 'mol-util/param-definition'; import Expression from 'mol-script/language/expression'; import { compile } from 'mol-script/runtime/query/compiler'; +import { Mat4 } from 'mol-math/linear-algebra'; export { ParseModelsFromMmCif } namespace ParseModelsFromMmCif { export interface Params { blockHeader?: string } } @@ -46,7 +47,7 @@ const ParseModelsFromMmCif = PluginStateTransform.Create<SO.Data.Cif, SO.Models, }); export { CreateStructureFromModel } -namespace CreateStructureFromModel { export interface Params { modelIndex: number } } +namespace CreateStructureFromModel { export interface Params { modelIndex: number, transform3d?: Mat4 } } const CreateStructureFromModel = PluginStateTransform.Create<SO.Models, SO.Structure, CreateStructureFromModel.Params>({ name: 'create-structure-from-model', display: { @@ -59,9 +60,11 @@ const CreateStructureFromModel = PluginStateTransform.Create<SO.Models, SO.Struc default: () => ({ modelIndex: 0 }), controls: a => ({ modelIndex: PD.Range('Model Index', 'Model Index', 0, 0, Math.max(0, a.data.length - 1), 1) }) }, + isApplicable: a => a.data.length > 0, apply({ a, params }) { if (params.modelIndex < 0 || params.modelIndex >= a.data.length) throw new Error(`Invalid modelIndex ${params.modelIndex}`); - const s = Structure.ofModel(a.data[params.modelIndex]); + let s = Structure.ofModel(a.data[params.modelIndex]); + if (params.transform3d) s = Structure.transform(s, params.transform3d); return new SO.Structure({ label: `Model ${s.models[0].modelNum}`, description: s.elementCount === 1 ? '1 element' : `${s.elementCount} elements` }, s); } });