Explorar o código

Merge pull request #474 from molstar/composable-superposition

coordinate system support for superposition
David Sehnal %!s(int64=2) %!d(string=hai) anos
pai
achega
80d1986c61

+ 1 - 0
CHANGELOG.md

@@ -11,6 +11,7 @@ Note that since we don't clearly distinguish between a public and private interf
     - Use instancing to create DNA/RNA curves to save memory
     - Enable ``instanceGranularity`` by default
     - Add ``adjustStyle`` option to LoadCellPackModel action (stylized, no multi-sample, no far clipping, chain picking)
+- Structure Superposition now respects pivot's coordinate system
 
 ## [v3.10.2] - 2022-06-26
 

+ 14 - 0
src/mol-plugin-state/manager/structure/hierarchy.ts

@@ -5,6 +5,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
+import { Structure } from '../../../mol-model/structure';
 import { setSubtreeVisibility } from '../../../mol-plugin/behavior/static/state';
 import { PluginCommands } from '../../../mol-plugin/commands';
 import { PluginContext } from '../../../mol-plugin/context';
@@ -12,6 +13,7 @@ import { StateTransform, StateTree } from '../../../mol-state';
 import { SetUtils } from '../../../mol-util/set';
 import { TrajectoryHierarchyPresetProvider } from '../../builder/structure/hierarchy-preset';
 import { PluginComponent } from '../../component';
+import { PluginStateObject } from '../../objects';
 import { buildStructureHierarchy, StructureHierarchyRef, ModelRef, StructureComponentRef, StructureHierarchy, StructureRef, TrajectoryRef } from './hierarchy-state';
 
 export class StructureHierarchyManager extends PluginComponent {
@@ -79,6 +81,18 @@ export class StructureHierarchyManager extends PluginComponent {
         return ret;
     }
 
+    findStructure(structure: Structure | undefined): StructureRef | undefined {
+        if (!structure) return undefined;
+
+        const parent = this.plugin.helpers.substructureParent.get(structure);
+        if (!parent) return undefined;
+
+        const root = this.plugin.state.data.selectQ(q => q.byValue(parent).rootOfType(PluginStateObject.Molecule.Structure))[0];
+        if (!root) return undefined;
+
+        return this.behaviors.selection.value.structures.find(s => s.cell === root);
+    }
+
     private syncCurrent<T extends StructureHierarchyRef>(all: ReadonlyArray<T>, added: Set<StateTransform.Ref>): T[] {
         const current = this.seletionSet;
         const newCurrent: T[] = [];

+ 28 - 18
src/mol-plugin-ui/structure/superposition.tsx

@@ -24,6 +24,7 @@ import { ToggleSelectionModeButton } from './selection';
 import { alignAndSuperposeWithSIFTSMapping } from '../../mol-model/structure/structure/util/superposition-sifts-mapping';
 import { PluginCommands } from '../../mol-plugin/commands';
 import { SIFTSMapping } from '../../mol-model-props/sequence/sifts-mapping';
+import { SymmetryOperator } from '../../mol-math/geometry';
 
 export class StructureSuperpositionControls extends CollapsableControls {
     defaultState() {
@@ -104,19 +105,21 @@ export class SuperpositionControls extends PurePluginUIComponent<{ }, Superposit
         return this.plugin.managers.structure.selection;
     }
 
-    async transform(s: StateObjectRef<PluginStateObject.Molecule.Structure>, matrix: Mat4) {
+    async transform(s: StateObjectRef<PluginStateObject.Molecule.Structure>, matrix: Mat4, coordinateSystem?: SymmetryOperator) {
         const r = StateObjectRef.resolveAndCheck(this.plugin.state.data, s);
         if (!r) return;
-        // TODO should find any TransformStructureConformation decorator instance
-        const o = StateSelection.findTagInSubtree(this.plugin.state.data.tree, r.transform.ref, SuperpositionTag);
+        const o = this.plugin.state.data.selectQ(q => q.byRef(r.transform.ref).subtree().withTransformer(StateTransforms.Model.TransformStructureConformation))[0];
+
+        const transform = coordinateSystem && !Mat4.isIdentity(coordinateSystem.matrix)
+            ? Mat4.mul(Mat4(), coordinateSystem.matrix, matrix)
+            : matrix;
 
         const params = {
             transform: {
                 name: 'matrix' as const,
-                params: { data: matrix, transpose: false }
+                params: { data: transform, transpose: false }
             }
         };
-        // TODO add .insertOrUpdate to StateBuilder?
         const b = o
             ? this.plugin.state.data.build().to(o).update(params)
             : this.plugin.state.data.build().to(s)
@@ -124,19 +127,24 @@ export class SuperpositionControls extends PurePluginUIComponent<{ }, Superposit
         await this.plugin.runTask(this.plugin.state.data.updateTree(b));
     }
 
+    private getRootStructure(s: Structure) {
+        const parent = this.plugin.helpers.substructureParent.get(s)!;
+        return this.plugin.state.data.selectQ(q => q.byValue(parent).rootOfType(PluginStateObject.Molecule.Structure))[0].obj?.data!;
+    }
+
     superposeChains = async () => {
         const { query } = this.state.options.traceOnly ? StructureSelectionQueries.trace : StructureSelectionQueries.polymer;
         const entries = this.chainEntries;
 
-        const locis = entries.map((e, i) => {
+        const locis = entries.map(e => {
             const s = StructureElement.Loci.toStructure(e.loci);
             const loci = StructureSelection.toLociWithSourceUnits(query(new QueryContext(s)));
-            return StructureElement.Loci.remap(loci, i === 0
-                ? this.plugin.helpers.substructureParent.get(e.loci.structure.root)!.obj!.data
-                : loci.structure.root
-            );
+            return StructureElement.Loci.remap(loci, this.getRootStructure(e.loci.structure));
         });
 
+        const pivot = this.plugin.managers.structure.hierarchy.findStructure(locis[0]?.structure);
+        const coordinateSystem = pivot?.transform?.cell.obj?.data.coordinateSystem;
+
         const transforms = this.state.options.alignSequences
             ? alignAndSuperpose(locis)
             : superpose(locis);
@@ -145,7 +153,7 @@ export class SuperpositionControls extends PurePluginUIComponent<{ }, Superposit
         for (let i = 1, il = locis.length; i < il; ++i) {
             const eB = entries[i];
             const { bTransform, rmsd } = transforms[i - 1];
-            await this.transform(eB.cell, bTransform);
+            await this.transform(eB.cell, bTransform, coordinateSystem);
             const labelA = stripTags(eA.label);
             const labelB = stripTags(eB.label);
             this.plugin.log.info(`Superposed [${labelA}] and [${labelB}] with RMSD ${rmsd.toFixed(2)}.`);
@@ -156,19 +164,19 @@ export class SuperpositionControls extends PurePluginUIComponent<{ }, Superposit
     superposeAtoms = async () => {
         const entries = this.atomEntries;
 
-        const atomLocis = entries.map((e, i) => {
-            return StructureElement.Loci.remap(e.loci, i === 0
-                ? this.plugin.helpers.substructureParent.get(e.loci.structure.root)!.obj!.data
-                : e.loci.structure.root
-            );
+        const atomLocis = entries.map(e => {
+            return StructureElement.Loci.remap(e.loci, this.getRootStructure(e.loci.structure));
         });
         const transforms = superpose(atomLocis);
 
+        const pivot = this.plugin.managers.structure.hierarchy.findStructure(atomLocis[0]?.structure);
+        const coordinateSystem = pivot?.transform?.cell.obj?.data.coordinateSystem;
+
         const eA = entries[0];
         for (let i = 1, il = atomLocis.length; i < il; ++i) {
             const eB = entries[i];
             const { bTransform, rmsd } = transforms[i - 1];
-            await this.transform(eB.cell, bTransform);
+            await this.transform(eB.cell, bTransform, coordinateSystem);
             const labelA = stripTags(eA.label);
             const labelB = stripTags(eB.label);
             const count = entries[i].atoms.length;
@@ -184,10 +192,12 @@ export class SuperpositionControls extends PurePluginUIComponent<{ }, Superposit
         const structures = input.map(s => s.cell.obj?.data!);
         const { entries, failedPairs, zeroOverlapPairs } = alignAndSuperposeWithSIFTSMapping(structures, { traceOnly });
 
+        const coordinateSystem = input[0]?.transform?.cell.obj?.data.coordinateSystem;
+
         let rmsd = 0;
 
         for (const xform of entries) {
-            await this.transform(input[xform.other].cell, xform.transform.bTransform);
+            await this.transform(input[xform.other].cell, xform.transform.bTransform, coordinateSystem);
             rmsd += xform.transform.rmsd;
         }