Browse Source

simplify superposition presets

Yana Rose 4 years ago
parent
commit
0ee3f32298
1 changed files with 93 additions and 78 deletions
  1. 93 78
      src/viewer/helpers/preset.ts

+ 93 - 78
src/viewer/helpers/preset.ts

@@ -83,22 +83,15 @@ type PropSet = {
     positions: number[]
 };
 
-type SubsetProps = {
-    kind: 'subset'
-    blocks: {
-        asymId: string
-        matrix: Mat4,
-        selection?: {
-            beg: number
-            end: number
-        }[],
-        propset: PropSet[]
-    }[]
-} & BaseProps
-
 type PropsetProps = {
-    kind: 'prop-set'
-    blocks: {
+    kind: 'prop-set',
+    selection?: {
+        asymId: string,
+        beg?: number,
+        end?: number,
+        matrix?: Mat4
+    }[],
+    representation: {
         asymId: string,
         propset: PropSet[]
     }[]
@@ -128,7 +121,7 @@ type DensityProps = {
     kind: 'density'
 } & BaseProps
 
-export type PresetProps = ValidationProps | StandardProps | SymmetryProps | FeatureProps | DensityProps | SubsetProps | PropsetProps
+export type PresetProps = ValidationProps | StandardProps | SymmetryProps | FeatureProps | DensityProps | PropsetProps
 
 const RcsbParams = (a: PluginStateObject.Molecule.Trajectory | undefined, plugin: PluginContext) => ({
     preset: PD.Value<PresetProps>({ kind: 'standard', assemblyId: '' }, { isHidden: true })
@@ -163,80 +156,55 @@ export const RcsbPreset = TrajectoryHierarchyPresetProvider({
 
         const unitcell = await builder.tryCreateUnitcell(modelProperties, undefined, { isHidden: true });
 
-        let representation: StructureRepresentationPresetProvider.Result | undefined = undefined
+        let representation: StructureRepresentationPresetProvider.Result | undefined = undefined;
 
         if (p.kind === 'prop-set') {
 
             const entryId = model.data?.entryId;
 
             const selections = new Array();
-            const _sele = plugin.state.data.build().to(structureProperties).apply(StructureSelectionFromExpression, {
-                expression: MS.struct.generator.all(),
-                label: `${entryId}`
-            });
-            const sele = await _sele.commit();
-            selections.push(sele);
-
-            sele.data!.inheritedPropertyData.colors = {};
-
-            const representations = new Array();
-            p.blocks.forEach( async block => {
-                let colorLookup = new Map();
-                block.propset.forEach(prop => {
-                    if (prop.args.name === 'color') {
-                        for (let i = 0; i < prop.positions.length; i++) {
-                            colorLookup.set(prop.positions[i], prop.args.value);
-                        }
+            if (p.selection) {
+                for (const s of p.selection) {
+                    const range = {asymId:s.asymId, beg:s.beg, end:s.end};
+                    let _sele = plugin.state.data.build().to(structureProperties)
+                        .apply(StructureSelectionFromExpression, generateSelection(entryId, range));
+                    if (s.matrix) {
+                        _sele.apply(TransformStructureConformation, {transform: { name: 'matrix', params: { data: s.matrix, transpose: false }}});
                     }
-                });
-                sele.data!.inheritedPropertyData.colors[block.asymId] = colorLookup;
-            });
-
-            const repr = await plugin.builders.structure.representation.applyPreset(sele, 'polymer-cartoon', {
-                theme: { globalName: 'superpose' }
-            });
-            representations.push(repr);
-
-        } else if (p.kind === 'subset') {
-
-            const entryId = model.data?.entryId;
-
-            const selections = new Array();
-            const representations = new Array();
-
-            p.blocks.forEach( async block => {
-
-                structureProperties.data!.inheritedPropertyData.colors = {};
-
-                const _sele = plugin.state.data.build().to(structureProperties).apply(StructureSelectionFromExpression, {
-                    expression: MS.struct.generator.atomGroups({
-                        'chain-test': MS.core.rel.eq([MS.ammp('label_asym_id'), block.asymId]),
-                    }),
-                    label: `${entryId}.${block.asymId}`
-                }).apply(TransformStructureConformation, {
-                    transform: { name: 'matrix', params: { data: block.matrix, transpose: false } }
-                });
+                    const sele = await _sele.commit();
+                    selections.push(sele);
+                }
+            } else {
+                const _sele = plugin.state.data.build().to(structureProperties)
+                    .apply(StructureSelectionFromExpression, generateSelection(entryId));
                 const sele = await _sele.commit();
                 selections.push(sele);
+            }
 
-                let colorLookup = new Map();
-                block.propset.forEach(prop => {
-                    if (prop.args.name === 'color') {
-                        for (let i = 0; i < prop.positions.length; i++) {
-                            colorLookup.set(prop.positions[i], prop.args.value);
-                        }
+            const representations = new Array();
+            for (const r of p.representation) {
+                for (const sele of selections) {
+                    if(!sele.data!.inheritedPropertyData.colors) {
+                        sele.data!.inheritedPropertyData.colors = {};
                     }
-                });
-                sele.data!.inheritedPropertyData.colors[block.asymId] = colorLookup;
-
-                const repr = await plugin.builders.structure.representation.applyPreset(sele, 'polymer-cartoon', {
-                    theme: { globalName: 'superpose' }
-                });
-                representations.push(repr);
-            });
-
+                    let colorLookup = sele.data!.inheritedPropertyData.colors[r.asymId] || new Map();
+                    r.propset.forEach(prop => {
+                        if (prop.args.name === 'color') {
+                            for (let i = 0; i < prop.positions.length; i++) {
+                                colorLookup.set(prop.positions[i], prop.args.value);
+                            }
+                        }
+                    });
+                    sele.data!.inheritedPropertyData.colors[r.asymId] = colorLookup;
+                    const repr = await plugin.builders.structure.representation.applyPreset(sele, 'polymer-cartoon', {
+                        theme: { globalName: 'superpose' }
+                    });
+                    representations.push(repr);
+                }
+            }
         } else if (p.kind === 'validation') {
             representation = await plugin.builders.structure.representation.applyPreset(structureProperties, ValidationReportGeometryQualityPreset);
+
         } else if (p.kind === 'symmetry') {
             representation = await plugin.builders.structure.representation.applyPreset<any>(structureProperties, AssemblySymmetryPreset, { symmetryIndex: p.symmetryIndex });
 
@@ -279,4 +247,51 @@ export const RcsbPreset = TrajectoryHierarchyPresetProvider({
             representation
         };
     }
-});
+});
+
+function generateSelection(entryId: string | undefined, range?: {asymId: string, beg: number | undefined, end: number | undefined}) {
+
+    if (!entryId) return {};
+
+    if (range) {
+        const residues: number[] = (range.beg && range.end) ? createRange(range.beg, range.end) : [];
+        const test = createTest(range.asymId, residues);
+        const label = createLabel(entryId, range);
+        return {
+            expression: MS.struct.generator.atomGroups(test),
+            label: `${label}`
+        }
+    } else {
+        return {
+            expression: MS.struct.generator.all(),
+            label: `${entryId}`
+        }
+    }
+}
+
+const createTest = (asymId: string, residues: number[]) => {
+    if (residues.length > 0) {
+        return {
+            'chain-test': testChain(asymId),
+            'residue-test': testResidues(residues)
+        };
+    } else {
+        return {'chain-test': testChain(asymId)};
+    }
+}
+
+const testChain = (asymId: string) => {
+    return MS.core.rel.eq([MS.ammp('label_asym_id'), asymId]);
+}
+
+const testResidues = (residueSet: number[]) => {
+    return MS.core.set.has([MS.set(...residueSet), MS.ammp('label_seq_id')]);
+}
+
+const createRange = (start: number, end: number) => [...Array(end - start + 1)].map((_, i) => start + i);
+
+const createLabel = (entryId: string, range: {asymId: string, beg: number | undefined, end: number | undefined}) => {
+    let label = ''.concat(entryId, '.', range.asymId);
+    if ( ! (range.beg && range.end) ) return label;
+    return ''.concat(label, ':', ''.concat(range.beg.toString(),'-',range.end.toString()))
+}