diff --git a/src/mol-model/structure/query/queries/internal.ts b/src/mol-model/structure/query/queries/internal.ts index eba048265c342b9b1363859ce40395669471076a..23b495f72a26920add9f871533c740b841b7242d 100644 --- a/src/mol-model/structure/query/queries/internal.ts +++ b/src/mol-model/structure/query/queries/internal.ts @@ -105,4 +105,4 @@ export function spheres(): StructureQuery { } return StructureSelection.Singletons(inputStructure, new Structure(units, { parent: inputStructure })); }; -} +} \ No newline at end of file diff --git a/src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts b/src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts index 951ec3946342d207d28d3f0dd001d69adcac0485..8a5da762cb8ce85f352247902ac3f62f2c0940d4 100644 --- a/src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts +++ b/src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts @@ -212,7 +212,7 @@ export namespace VolumeStreaming { }); this.subscribeObservable(this.plugin.behaviors.interaction.click, ({ current, buttons, modifiers }) => { - if (!Binding.match(this.params.bindings.clickVolumeAroundOnly, buttons, modifiers)) return; + if (!Binding.match(this.params.bindings.clickVolumeAroundOnly || DefaultBindings.clickVolumeAroundOnly, buttons, modifiers)) return; if (this.params.view.name !== 'selection-box') { this.lastLoci = current; } else { diff --git a/src/mol-plugin/state/actions/structure.ts b/src/mol-plugin/state/actions/structure.ts index 7cfa14dd6e73f839576efd7e4165edb99dfbd9ff..8ad9d2cbd9a85dbc065737a2007ed2a044b23bc0 100644 --- a/src/mol-plugin/state/actions/structure.ts +++ b/src/mol-plugin/state/actions/structure.ts @@ -17,6 +17,7 @@ import { DataFormatProvider, guessCifVariant, DataFormatBuilderOptions } from '. import { FileInfo } from '../../../mol-util/file-info'; import { Task } from '../../../mol-task'; import { StructureElement } from '../../../mol-model/structure'; +import { createDefaultStructureComplex } from '../../util/structure-comlex-helper'; export const MmcifProvider: DataFormatProvider<any> = { label: 'mmCIF', @@ -251,7 +252,7 @@ function createStructureTree(ctx: PluginContext, b: StateBuilder.To<PluginStateO root = root.apply(StateTransforms.Model.CustomModelProperties); } const structure = root.apply(StateTransforms.Model.StructureAssemblyFromModel); - complexRepresentation(ctx, structure); + createDefaultStructureComplex(ctx, structure); return root; } @@ -287,7 +288,7 @@ export const CreateComplexRepresentation = StateAction.build({ from: PluginStateObject.Molecule.Structure })(({ ref, state }, ctx: PluginContext) => { const root = state.build().to(ref); - complexRepresentation(ctx, root); + createDefaultStructureComplex(ctx, root); return state.updateTree(root); }); diff --git a/src/mol-plugin/state/transforms/model.ts b/src/mol-plugin/state/transforms/model.ts index 5bc63f833d33c86bf468ac312c43e1c4e72d8275..6f749464e6e05b893cc0b243c58fe879f68915fc 100644 --- a/src/mol-plugin/state/transforms/model.ts +++ b/src/mol-plugin/state/transforms/model.ts @@ -28,6 +28,7 @@ import { ensureSecondaryStructure } from './helpers'; import { Script } from '../../../mol-script/script'; import { parse3DG } from '../../../mol-io/reader/3dg/parser'; import { trajectoryFrom3DG } from '../../../mol-model-formats/structure/3dg'; +import { CompiledStructureSelectionQueries } from '../../util/structure-selection-helper'; export { TrajectoryFromBlob }; export { TrajectoryFromMmCif }; @@ -425,7 +426,7 @@ const StructureSelectionFromScript = PluginStateTransform.BuiltIn({ return new SO.Molecule.Structure(s, props); }, update: ({ a, b, oldParams, newParams, cache }) => { - if (Script.areEqual(oldParams.script, newParams.script)) { + if (!Script.areEqual(oldParams.script, newParams.script)) { return StateTransformer.UpdateResult.Recreate; } @@ -502,27 +503,58 @@ const StructureSelectionFromBundle = PluginStateTransform.BuiltIn({ } }); -namespace StructureComplexElement { - export type Types = 'atomic-sequence' | 'water' | 'atomic-het' | 'spheres' -} -const StructureComplexElementTypes: [StructureComplexElement.Types, StructureComplexElement.Types][] = ['atomic-sequence', 'water', 'atomic-het', 'spheres'].map(t => [t, t] as any); +export const StructureComplexElementTypes = { + 'protein-and-nucleic': 'protein-and-nucleic', + + 'protein': 'protein', + 'nucleic': 'nucleic', + 'water': 'water', + + 'branched': 'branched', // = carbs + 'ligand': 'ligand', + 'modified': 'modified', + + 'coarse': 'coarse', + + // Legacy + 'atomic-sequence': 'atomic-sequence', + 'atomic-het': 'atomic-het', + 'spheres': 'spheres' +} as const +export type StructureComplexElementTypes = keyof typeof StructureComplexElementTypes + +const StructureComplexElementTypeTuples = Object.keys(StructureComplexElementTypes).map(t => [t, t] as any); + type StructureComplexElement = typeof StructureComplexElement const StructureComplexElement = PluginStateTransform.BuiltIn({ name: 'structure-complex-element', display: { name: 'Complex Element', description: 'Create a molecular structure from the specified model.' }, from: SO.Molecule.Structure, to: SO.Molecule.Structure, - params: { type: PD.Select<StructureComplexElement.Types>('atomic-sequence', StructureComplexElementTypes, { isHidden: true }) } + params: { type: PD.Select<StructureComplexElementTypes>('atomic-sequence', StructureComplexElementTypeTuples, { isHidden: true }) } })({ apply({ a, params }) { // TODO: update function. let query: StructureQuery, label: string; switch (params.type) { - case 'atomic-sequence': query = Queries.internal.atomicSequence(); label = 'Sequence'; break; + case 'protein-and-nucleic': query = CompiledStructureSelectionQueries.proteinAndNucleic; label = 'Sequence'; break; + + case 'protein': query = CompiledStructureSelectionQueries.protein; label = 'Protein'; break; + case 'nucleic': query = CompiledStructureSelectionQueries.nucleic; label = 'Nucleic'; break; case 'water': query = Queries.internal.water(); label = 'Water'; break; + + case 'branched': query = CompiledStructureSelectionQueries.branchedPlusConnected; label = 'Branched'; break; + case 'ligand': query = CompiledStructureSelectionQueries.ligandPlusConnected; label = 'Ligand'; break; + + case 'modified': query = CompiledStructureSelectionQueries.modified; label = 'Modified'; break; + + case 'coarse': query = CompiledStructureSelectionQueries.coarse; label = 'Coarse'; break; + + case 'atomic-sequence': query = Queries.internal.atomicSequence(); label = 'Sequence'; break; case 'atomic-het': query = Queries.internal.atomicHet(); label = 'HET Groups/Ligands'; break; case 'spheres': query = Queries.internal.spheres(); label = 'Coarse Spheres'; break; + default: throw new Error(`${params.type} is a not valid complex element.`); } diff --git a/src/mol-plugin/util/structure-comlex-helper.ts b/src/mol-plugin/util/structure-comlex-helper.ts new file mode 100644 index 0000000000000000000000000000000000000000..d22d839774cba29b3b71b2154dd99f745a1b10c7 --- /dev/null +++ b/src/mol-plugin/util/structure-comlex-helper.ts @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { PluginContext } from '../context'; +import { StateBuilder } from '../../mol-state'; +import { PluginStateObject } from '../state/objects'; +import { StateTransforms } from '../state/transforms'; +import { StructureRepresentation3DHelpers } from '../state/transforms/representation'; +import { StructureComplexElementTypes } from '../state/transforms/model'; + +export function createDefaultStructureComplex( + ctx: PluginContext, root: StateBuilder.To<PluginStateObject.Molecule.Structure> +) { + root.apply(StateTransforms.Model.StructureComplexElement, { type: 'protein-and-nucleic' }, { tags: StructureComplexElementTypes['protein-and-nucleic'] }) + .apply(StateTransforms.Representation.StructureRepresentation3D, + StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'cartoon')); + + root.apply(StateTransforms.Model.StructureComplexElement, { type: 'ligand' }, { tags: StructureComplexElementTypes.ligand }) + .apply(StateTransforms.Representation.StructureRepresentation3D, + StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick')); + + root.apply(StateTransforms.Model.StructureComplexElement, { type: 'modified' }, { tags: StructureComplexElementTypes.modified }) + .apply(StateTransforms.Representation.StructureRepresentation3D, + StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', void 0, 'polymer-id')); + + const branched = root.apply(StateTransforms.Model.StructureComplexElement, { type: 'branched' }, { tags: StructureComplexElementTypes.branched }) + + branched.apply(StateTransforms.Representation.StructureRepresentation3D, + StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', { alpha: 0.15 })); + branched.apply(StateTransforms.Representation.StructureRepresentation3D, + StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'carbohydrate')); + + root.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' }, { tags: StructureComplexElementTypes.water }) + .apply(StateTransforms.Representation.StructureRepresentation3D, + StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', { alpha: 0.51 })); + + root.apply(StateTransforms.Model.StructureComplexElement, { type: 'coarse' }, { tags: StructureComplexElementTypes.coarse }) + .apply(StateTransforms.Representation.StructureRepresentation3D, + StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'spacefill', {}, 'polymer-id')); +} \ No newline at end of file diff --git a/src/mol-plugin/util/structure-selection-helper.ts b/src/mol-plugin/util/structure-selection-helper.ts index e06e9c50ae4770227ce3fc87b693e9d299bbd595..db342c603b2ab8c5f4ec92e68c4ebb05518bced1 100644 --- a/src/mol-plugin/util/structure-selection-helper.ts +++ b/src/mol-plugin/util/structure-selection-helper.ts @@ -7,7 +7,7 @@ import { MolScriptBuilder as MS } from '../../mol-script/language/builder'; import { StateSelection } from '../../mol-state'; import { PluginStateObject } from '../state/objects'; -import { QueryContext, StructureSelection } from '../../mol-model/structure'; +import { QueryContext, StructureSelection, StructureQuery } from '../../mol-model/structure'; import { compile } from '../../mol-script/runtime/query/compiler'; import { Loci } from '../../mol-model/loci'; import { PluginContext } from '../context'; @@ -65,6 +65,18 @@ const nucleic = MS.struct.modifier.union([ }) ]) +const proteinAndNucleic = MS.struct.modifier.union([ + MS.struct.generator.atomGroups({ + 'entity-test': MS.core.logic.and([ + MS.core.rel.eq([MS.ammp('entityType'), 'polymer']), + MS.core.str.match([ + MS.re('(polypeptide|cyclic-pseudo-peptide|nucleotide|peptide nucleic acid)', 'i'), + MS.ammp('entitySubtype') + ]) + ]) + }) +]) + const water = MS.struct.modifier.union([ MS.struct.generator.atomGroups({ 'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'water']) @@ -118,6 +130,12 @@ const ligandPlusConnected = MS.struct.modifier.union([ }) ]) +const modified = MS.struct.modifier.union([ + MS.struct.generator.atomGroups({ + 'residue-test': MS.ammp('isModified') + }) +]) + const coarse = MS.struct.modifier.union([ MS.struct.generator.atomGroups({ 'chain-test': MS.core.set.has([ @@ -132,15 +150,25 @@ export const StructureSelectionQueries = { trace, protein, nucleic, + proteinAndNucleic, water, branched, branchedPlusConnected, branchedConnectedOnly, ligand, ligandPlusConnected, + modified, coarse, } +export const CompiledStructureSelectionQueries = (function () { + const ret: { [K in keyof typeof StructureSelectionQueries]: StructureQuery } = Object.create(null); + for (const k of Object.keys(StructureSelectionQueries)) { + (ret as any)[k] = compile<StructureSelection>((StructureSelectionQueries as any)[k]); + } + return ret; +})(); + // export type SelectionModifier = 'add' | 'remove' | 'only'