Skip to content
Snippets Groups Projects
Commit b807dca2 authored by Alexander Rose's avatar Alexander Rose
Browse files

wip, StructureRepresentationHelper tweaks

parent 2cae6e3f
No related branches found
No related tags found
No related merge requests found
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
......@@ -13,8 +13,6 @@ import { Color } from '../../mol-util/color';
import { ButtonSelect, Options } from '../controls/common'
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { VisualQuality, VisualQualityOptions } from '../../mol-geo/geometry/base';
import { StructureRepresentationPresets as P } from '../../mol-plugin/util/structure-representation-helper';
import { camelCaseToWords } from '../../mol-util/string';
import { CollapsableControls } from '../base';
import { StateSelection, StateObject } from '../../mol-state';
import { PluginStateObject } from '../../mol-plugin/state/objects';
......@@ -133,13 +131,6 @@ export class StructureRepresentationControls extends CollapsableControls<Collaps
this.subscribe(this.plugin.state.dataState.events.isUpdating, v => this.setState({ isDisabled: v }))
}
preset = async (value: string) => {
const presetFn = P[value as keyof typeof P]
if (presetFn) {
await presetFn(this.plugin.helpers.structureRepresentation)
}
}
onChange = async (p: { param: PD.Base<any>, name: string, value: any }) => {
if (p.name === 'options') {
await this.plugin.helpers.structureRepresentation.setIgnoreHydrogens(!p.value.showHydrogens)
......@@ -178,15 +169,7 @@ export class StructureRepresentationControls extends CollapsableControls<Collaps
}
renderControls() {
const presets = PD.objectToOptions(P, camelCaseToWords);
return <div>
<div className='msp-control-row'>
<div className='msp-select-row'>
<ButtonSelect label='Preset' onChange={this.preset}>
<optgroup label='Preset'>{Options(presets)}</optgroup>
</ButtonSelect>
</div>
</div>
<EverythingStructureRepresentationControls />
<SelectionStructureRepresentationControls />
......
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
......@@ -12,8 +12,6 @@ import { PluginContext } from '../context';
import { StructureRepresentation3DHelpers } from '../state/transforms/representation';
import Expression from '../../mol-script/language/expression';
import { compile } from '../../mol-script/runtime/query/compiler';
import { StructureSelectionQueries as Q } from '../util/structure-selection-helper';
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { VisualQuality } from '../../mol-geo/geometry/base';
type StructureTransform = StateObjectCell<PSO.Molecule.Structure, StateTransform<StateTransformer<any, PSO.Molecule.Structure, any>>>
......@@ -34,6 +32,12 @@ function getCombinedLoci(mode: SelectionModifier, loci: StructureElement.Loci, c
type SelectionModifier = 'add' | 'remove' | 'only'
type ReprProps = {
repr?: {},
color?: string | [string, {}],
size?: string | [string, {}],
}
export class StructureRepresentationHelper {
getRepresentationStructure(rootRef: string, type: string) {
const state = this.plugin.state.dataState
......@@ -49,12 +53,52 @@ export class StructureRepresentationHelper {
return selections.length > 0 ? selections[0] : undefined
}
private async _set(modifier: SelectionModifier, type: string, loci: StructureElement.Loci, structure: StructureTransform, props = {}) {
private getRepresentationParams(structure: Structure, type: string, repr: RepresentationTransform | undefined, props: ReprProps = {}) {
const reprProps = {
...(repr?.params && repr.params.values.type.params),
ignoreHydrogens: this._ignoreHydrogens,
quality: this._quality,
...props.repr
}
const { themeCtx } = this.plugin.structureRepresentation
const p: StructureRepresentation3DHelpers.Props = {
repr: [
this.plugin.structureRepresentation.registry.get(type),
() => reprProps
]
}
if (props.color) {
const colorType = props.color instanceof Array ? props.color[0] : props.color
const colorTheme = themeCtx.colorThemeRegistry.get(colorType)
const colorProps = {
...(repr?.params && repr.params.values.colorTheme.params),
...(props.color instanceof Array ? props.color[1] : {})
}
p.color = [colorTheme, () => colorProps]
}
if (props.size) {
const sizeType = props.size instanceof Array ? props.size[0] : props.size
const sizeTheme = themeCtx.sizeThemeRegistry.get(sizeType)
const sizeProps = {
...(repr?.params && repr.params.values.sizeTheme.params),
...(props.size instanceof Array ? props.size[1] : {})
}
p.size = [sizeTheme, () => sizeProps]
}
if (props.size) p.size = props.size
return StructureRepresentation3DHelpers.createParams(this.plugin, structure, p)
}
private async _set(modifier: SelectionModifier, type: string, loci: StructureElement.Loci, structure: StructureTransform, props: ReprProps = {}) {
const state = this.plugin.state.dataState
const update = state.build()
const s = structure.obj!.data
const repr = this.getRepresentation(structure.transform.ref, type)
const reprStructure = this.getRepresentationStructure(structure.transform.ref, type)
const reprParams = this.getRepresentationParams(s, type, repr, props)
if (reprStructure) {
const currentLoci = StructureElement.Bundle.toLoci(reprStructure.params!.values.bundle, s)
......@@ -64,14 +108,9 @@ export class StructureRepresentationHelper {
...reprStructure.params!.values,
bundle: StructureElement.Bundle.fromLoci(combinedLoci)
})
if (repr) update.to(repr).update(reprParams)
} else {
const combinedLoci = getCombinedLoci(modifier, loci, StructureElement.Loci.none(s))
const params = StructureRepresentation3DHelpers.getDefaultParams(this.plugin, type as any, s)
const p = params.type.params
Object.assign(p, props)
if (p.ignoreHydrogens !== undefined) p.ignoreHydrogens = this._ignoreHydrogens
if (p.quality !== undefined) p.quality = this._quality
update.to(structure.transform.ref)
.apply(
......@@ -79,13 +118,13 @@ export class StructureRepresentationHelper {
{ bundle: StructureElement.Bundle.fromLoci(combinedLoci), label: type },
{ tags: [ RepresentationManagerTag, getRepresentationManagerTag(type) ] }
)
.apply( StateTransforms.Representation.StructureRepresentation3D, params)
.apply(StateTransforms.Representation.StructureRepresentation3D, reprParams)
}
await this.plugin.runTask(state.updateTree(update, { doNotUpdateCurrent: true }))
}
async set(modifier: SelectionModifier, type: string, lociGetter: (structure: Structure) => StructureElement.Loci, props = {}) {
async set(modifier: SelectionModifier, type: string, lociGetter: (structure: Structure) => StructureElement.Loci, props: ReprProps = {}) {
const state = this.plugin.state.dataState;
const structures = state.select(StateSelection.Generators.rootsOfType(PSO.Molecule.Structure))
......@@ -96,7 +135,7 @@ export class StructureRepresentationHelper {
}
}
async setFromExpression(modifier: SelectionModifier, type: string, expression: Expression, props = {}) {
async setFromExpression(modifier: SelectionModifier, type: string, expression: Expression, props: ReprProps = {}) {
return this.set(modifier, type, (structure) => {
const compiled = compile<StructureSelection>(expression)
const result = compiled(new QueryContext(structure))
......@@ -104,36 +143,68 @@ export class StructureRepresentationHelper {
}, props)
}
async clear() {
async eachStructure(callback: (structure: StructureTransform, type: string, update: StateBuilder.Root) => void) {
const { registry } = this.plugin.structureRepresentation
const state = this.plugin.state.dataState;
const update = state.build()
const structures = state.select(StateSelection.Generators.rootsOfType(PSO.Molecule.Structure))
const bundle = StructureElement.Bundle.Empty
for (const structure of structures) {
for (let i = 0, il = registry.types.length; i < il; ++i) {
const type = registry.types[i][0]
const reprStructure = this.getRepresentationStructure(structure.transform.ref, type)
if (reprStructure) {
update.to(reprStructure).update({ ...reprStructure.params!.values, bundle })
}
if (reprStructure) callback(reprStructure, type, update)
}
}
await this.plugin.runTask(state.updateTree(update, { doNotUpdateCurrent: true }))
}
async eachRepresentation(callback: (repr: RepresentationTransform, update: StateBuilder.Root) => void) {
async clear() {
const bundle = StructureElement.Bundle.Empty
await this.eachStructure((structure, type, update) => {
update.to(structure).update({ ...structure.params!.values, bundle })
})
}
async clearExcept(exceptTypes: string[]) {
const bundle = StructureElement.Bundle.Empty
await this.eachStructure((structure, type, update) => {
if (!exceptTypes.includes(type)) {
update.to(structure).update({ ...structure.params!.values, bundle })
}
})
}
async eachRepresentation(callback: (repr: RepresentationTransform, type: string, update: StateBuilder.Root) => void) {
const { registry } = this.plugin.structureRepresentation
const state = this.plugin.state.dataState;
const update = state.build()
const structures = state.select(StateSelection.Generators.rootsOfType(PSO.Molecule.Structure))
for (const structure of structures) {
for (let i = 0, il = registry.types.length; i < il; ++i) {
const repr = this.getRepresentation(structure.transform.ref, registry.types[i][0])
if (repr) callback(repr, update)
const type = registry.types[i][0]
const repr = this.getRepresentation(structure.transform.ref, type)
if (repr) callback(repr, type, update)
}
}
await this.plugin.runTask(state.updateTree(update, { doNotUpdateCurrent: true }))
}
setRepresentationParams(repr: RepresentationTransform, type: string, update: StateBuilder.Root, props: ReprProps) {
const state = this.plugin.state.dataState;
const structures = state.select(StateSelection.Generators.rootsOfType(PSO.Molecule.Structure))
for (const structure of structures) {
const s = structure.obj!.data
const reprParams = this.getRepresentationParams(s, type, repr, props)
update.to(repr).update(reprParams)
}
}
async updateRepresentation(repr: RepresentationTransform, type: string, props: ReprProps) {
const state = this.plugin.state.dataState;
const update = state.build()
this.setRepresentationParams(repr, type, update, props)
await this.plugin.runTask(state.updateTree(update, { doNotUpdateCurrent: true }))
}
......@@ -141,7 +212,7 @@ export class StructureRepresentationHelper {
get ignoreHydrogens () { return this._ignoreHydrogens }
async setIgnoreHydrogens(ignoreHydrogens: boolean) {
if (ignoreHydrogens === this._ignoreHydrogens) return
await this.eachRepresentation((repr, update) => {
await this.eachRepresentation((repr, type, update) => {
if (repr.params && repr.params.values.type.params.ignoreHydrogens !== undefined) {
const { name, params } = repr.params.values.type
update.to(repr.transform.ref).update(
......@@ -157,7 +228,7 @@ export class StructureRepresentationHelper {
get quality () { return this._quality }
async setQuality(quality: VisualQuality) {
if (quality === this._quality) return
await this.eachRepresentation((repr, update) => {
await this.eachRepresentation((repr, type, update) => {
if (repr.params && repr.params.values.type.params.quality !== undefined) {
const { name, params } = repr.params.values.type
update.to(repr.transform.ref).update(
......@@ -169,74 +240,7 @@ export class StructureRepresentationHelper {
this._quality = quality
}
async preset() {
// TODO option to limit to specific structure
const state = this.plugin.state.dataState;
const structures = state.select(StateSelection.Generators.rootsOfType(PSO.Molecule.Structure))
if (structures.length === 0) return
const s = structures[0].obj!.data
if (s.elementCount < 50000) {
await polymerAndLigand(this)
} else if (s.elementCount < 200000) {
await proteinAndNucleic(this)
} else {
if (s.unitSymmetryGroups[0].units.length > 10) {
await capsid(this)
} else {
await coarseCapsid(this)
}
}
}
constructor(private plugin: PluginContext) {
}
}
\ No newline at end of file
//
async function polymerAndLigand(r: StructureRepresentationHelper) {
await r.clear()
await r.setFromExpression('add', 'cartoon', Q.polymer.expression)
await r.setFromExpression('add', 'carbohydrate', Q.branchedPlusConnected.expression)
await r.setFromExpression('add', 'ball-and-stick', MS.struct.modifier.union([
MS.struct.combinator.merge([
Q.ligandPlusConnected.expression,
Q.branchedConnectedOnly.expression,
Q.disulfideBridges.expression,
Q.nonStandardPolymer.expression,
Q.water.expression
])
]))
}
async function proteinAndNucleic(r: StructureRepresentationHelper) {
await r.clear()
await r.setFromExpression('add', 'cartoon', Q.protein.expression)
await r.setFromExpression('add', 'gaussian-surface', Q.nucleic.expression)
}
async function capsid(r: StructureRepresentationHelper) {
await r.clear()
await r.setFromExpression('add', 'gaussian-surface', Q.polymer.expression, {
smoothness: 0.5,
})
}
async function coarseCapsid(r: StructureRepresentationHelper) {
await r.clear()
await r.setFromExpression('add', 'gaussian-surface', Q.trace.expression, {
radiusOffset: 1,
smoothness: 0.5,
visuals: ['structure-gaussian-surface-mesh']
})
}
export const StructureRepresentationPresets = {
polymerAndLigand,
proteinAndNucleic,
capsid,
coarseCapsid
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment