diff --git a/src/mol-plugin/behavior/dynamic/volume.ts b/src/mol-plugin/behavior/dynamic/volume.ts deleted file mode 100644 index 9808a806afb4a1d402cac2274eb90593b789421b..0000000000000000000000000000000000000000 --- a/src/mol-plugin/behavior/dynamic/volume.ts +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author David Sehnal <david.sehnal@gmail.com> - */ - -import CIF from 'mol-io/reader/cif'; -import { Box3D } from 'mol-math/geometry'; -import { Vec3 } from 'mol-math/linear-algebra'; -import { volumeFromDensityServerData } from 'mol-model-formats/volume/density-server'; -import { VolumeData, VolumeIsoValue } from 'mol-model/volume'; -import { PluginContext } from 'mol-plugin/context'; -import { PluginStateObject } from 'mol-plugin/state/objects'; -import { createIsoValueParam } from 'mol-repr/volume/isosurface'; -import { Color } from 'mol-util/color'; -import { LRUCache } from 'mol-util/lru-cache'; -import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { PluginBehavior } from '../behavior'; -import { Structure } from 'mol-model/structure'; - -export namespace VolumeStreaming { - function channelParam(label: string, color: Color, defaultValue: number) { - return PD.Group({ - color: PD.Color(color), - isoValue: createIsoValueParam(VolumeIsoValue.relative(defaultValue)) - }, { label }); - } - - export const Params = { - id: PD.Text('1tqn'), - levels: PD.MappedStatic('x-ray', { - 'em': channelParam('EM', Color(0x638F8F), 1.5), - 'x-ray': PD.Group({ - '2fo-fc': channelParam('2Fo-Fc', Color(0x3362B2), 1.5), - 'fo-fc(+ve)': channelParam('Fo-Fc(+ve)', Color(0x33BB33), 3), - 'fo-fc(-ve)': channelParam('Fo-Fc(-ve)', Color(0xBB3333), -3), - }) - }), - box: PD.MappedStatic('static-box', { - 'static-box': PD.Group({ - bottomLeft: PD.Vec3(Vec3.create(-22.4, -33.4, -21.6)), - topRight: PD.Vec3(Vec3.create(-7.1, -10, -0.9)) - }, { description: 'Static box defined by cartesian coords.' }), - // 'around-selection': PD.Group({ radius: PD.Numeric(5, { min: 0, max: 10 }) }), - 'cell': PD.Group({ }), - // 'auto': PD.Group({ }), // based on camera distance/active selection/whatever, show whole structure or slice. - }), - detailLevel: PD.Numeric(3, { min: 0, max: 7 }), - serverUrl: PD.Text('https://webchem.ncbr.muni.cz/DensityServer'), - } - export type Params = PD.Values<typeof Params> - - export type ChannelData = { [name in 'EM' | '2FO-FC' | 'FO-FC']?: VolumeData } - export type LevelType = 'em' | '2fo-fc' | 'fo-fc(+ve)' | 'fo-fc(-ve)' - - export class Behavior implements PluginBehavior<Params> { - // TODO: have special value for "cell"? - private cache = LRUCache.create<ChannelData>(25); - // private ref: string = ''; - - currentData: ChannelData = { } - - private async queryData(box?: Box3D) { - let url = `${this.params.serverUrl}/${this.params.levels.name}/${this.params.id}` - - if (box) { - const { min: a, max: b } = box; - url += `/box` - + `/${a.map(v => Math.round(1000 * v) / 1000).join(',')}` - + `/${b.map(v => Math.round(1000 * v) / 1000).join(',')}`; - } else { - url += `/cell`; - } - url += `?detail=${this.params.detailLevel}`; - - let data = LRUCache.get(this.cache, url); - if (data) { - return data; - } - - const cif = await this.ctx.runTask(this.ctx.fetch({ url, type: 'binary' })); - data = await this.parseCif(cif as Uint8Array); - if (!data) { - return; - } - - LRUCache.set(this.cache, url, data); - return data; - } - - private async parseCif(data: Uint8Array): Promise<ChannelData | undefined> { - const parsed = await this.ctx.runTask(CIF.parseBinary(data)); - if (parsed.isError) { - this.ctx.log.error('VolumeStreaming, parsing CIF: ' + parsed.toString()); - return; - } - if (parsed.result.blocks.length < 2) { - this.ctx.log.error('VolumeStreaming: Invalid data.'); - return; - } - - const ret: ChannelData = { }; - for (let i = 1; i < parsed.result.blocks.length; i++) { - const block = parsed.result.blocks[i]; - - const densityServerCif = CIF.schema.densityServer(block); - const volume = await this.ctx.runTask(await volumeFromDensityServerData(densityServerCif)); - (ret as any)[block.header as any] = volume; - } - return ret; - } - - register(ref: string): void { - // TODO: register camera movement/loci so that "around selection box works" - // alternatively, and maybe a better solution, write a global behavior that modifies this node from the outside - } - - async update(params: Params): Promise<boolean> { - this.params = params; - - let box: Box3D | undefined = void 0; - - switch (params.box.name) { - case 'static-box': - box = Box3D.create(params.box.params.bottomLeft, params.box.params.topRight); - break; - case 'cell': - box = this.params.levels.name === 'x-ray' - ? this.structure.boundary.box - : void 0; - break; - } - - const data = await this.queryData(box); - this.currentData = data || { }; - - return true; - } - - unregister(): void { - // TODO unsubscribe to events - } - - constructor(public ctx: PluginContext, public params: Params, private structure: Structure) { - } - } - - export class Obj extends PluginStateObject.CreateBehavior<Behavior>({ name: 'Volume Streaming' }) { } -} \ No newline at end of file diff --git a/src/mol-plugin/state/actions/volume.ts b/src/mol-plugin/state/actions/volume.ts index ab07fd80a3098c5d9b303dbcb1fa4d26a1148ee7..baf6e0ded64d08c380cf907bd4a671302cbeac5a 100644 --- a/src/mol-plugin/state/actions/volume.ts +++ b/src/mol-plugin/state/actions/volume.ts @@ -16,7 +16,6 @@ import { PluginStateObject } from '../objects'; import { StateTransforms } from '../transforms'; import { Download } from '../transforms/data'; import { VolumeRepresentation3DHelpers } from '../transforms/representation'; -import { VolumeStreaming } from 'mol-plugin/behavior/dynamic/volume'; import { DataFormatProvider } from './data-format'; export const Ccp4Provider: DataFormatProvider<any> = { @@ -201,24 +200,4 @@ const DownloadDensity = StateAction.build({ const b = state.build().to(data.ref); await provider.getDefaultBuilder(ctx, b, state).runInContext(taskCtx) -})); - -export const InitVolumeStreaming = StateAction.build({ - display: { name: 'Volume Streaming' }, - from: PluginStateObject.Molecule.Structure, - params: VolumeStreaming.Params -})(({ ref, state, params }, ctx: PluginContext) => { - // TODO: specify simpler params - // TODO: try to determine if the input is x-ray or emd (in params provider) - // TODO: for EMD, use PDBe API to determine controur level https://github.com/dsehnal/LiteMol/blob/master/src/Viewer/Extensions/DensityStreaming/Entity.ts#L168 - // TODO: custom react view for this and the VolumeStreamingBehavior transformer - - const root = state.build().to(ref) - .apply(StateTransforms.Volume.VolumeStreamingBehavior, params); - - root.apply(StateTransforms.Volume.VolumeStreamingVisual, { channel: '2FO-FC', level: '2fo-fc' }, { props: { isGhost: true } }); - root.apply(StateTransforms.Volume.VolumeStreamingVisual, { channel: 'FO-FC', level: 'fo-fc(+ve)' }, { props: { isGhost: true } }); - root.apply(StateTransforms.Volume.VolumeStreamingVisual, { channel: 'FO-FC', level: 'fo-fc(-ve)' }, { props: { isGhost: true } }); - - return state.updateTree(root); -}); \ No newline at end of file +})); \ No newline at end of file diff --git a/src/mol-plugin/state/transforms/volume.ts b/src/mol-plugin/state/transforms/volume.ts index 6c682e4a13cc9df01cea36e51391ae1e832e8259..2401cb0cf18fa0bff435a1e8a430841d65a1f2f9 100644 --- a/src/mol-plugin/state/transforms/volume.ts +++ b/src/mol-plugin/state/transforms/volume.ts @@ -13,14 +13,6 @@ import { volumeFromDsn6 } from 'mol-model-formats/volume/dsn6'; import { Task } from 'mol-task'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { PluginStateObject as SO, PluginStateTransform } from '../objects'; -import { VolumeStreaming } from 'mol-plugin/behavior/dynamic/volume'; -import { PluginContext } from 'mol-plugin/context'; -import { StateTransformer } from 'mol-state'; -import { VolumeData, VolumeIsoValue } from 'mol-model/volume'; -import { BuiltInVolumeRepresentations } from 'mol-repr/volume/registry'; -import { createTheme } from 'mol-theme/theme'; -import { VolumeRepresentation3DHelpers } from './representation'; -import { Color } from 'mol-util/color'; export { VolumeFromCcp4 }; export { VolumeFromDsn6 }; @@ -97,99 +89,4 @@ const VolumeFromDensityServerCif = PluginStateTransform.BuiltIn({ return new SO.Volume.Data(volume, props); }); } -}); - -export { VolumeStreamingBehavior } -type VolumeStreamingBehavior = typeof VolumeStreamingBehavior -const VolumeStreamingBehavior = PluginStateTransform.BuiltIn({ - name: 'volume-streaming-behavior', - display: { name: 'Volume Streaming Behavior', description: 'Create Volume Streaming behavior.' }, - from: SO.Molecule.Structure, - to: VolumeStreaming.Obj, - params: VolumeStreaming.Params -})({ - canAutoUpdate: ({ oldParams, newParams }) => oldParams.serverUrl === newParams.serverUrl && oldParams.id === newParams.id, - apply: ({ a, params }, plugin: PluginContext) => Task.create('Volume Streaming', async ctx => { - const behavior = new VolumeStreaming.Behavior(plugin, params, a.data); - // get the initial data now so that the child projections dont get empty volumes. - await behavior.update(behavior.params); - return new VolumeStreaming.Obj(behavior, { label: 'Volume Streaming' }); - }), - update({ b, newParams }) { - return Task.create('Update Volume Streaming', async _ => { - await b.data.update(newParams); - return StateTransformer.UpdateResult.Updated; - }); - } -}); - -// export { VolumeStreamingData } -// type VolumeStreamingData = typeof VolumeStreamingData -// const VolumeStreamingData = PluginStateTransform.BuiltIn({ -// name: 'volume-streaming-data', -// display: { name: 'Volume Streaming Data' }, -// from: VolumeStreaming.Obj, -// to: SO.Volume.Data, -// params: { -// channel: PD.Select<keyof VolumeStreaming.ChannelData>('EM', [['EM', 'EM'], ['FO-FC', 'Fo-Fc'], ['2FO-FC', '2Fo-Fc']], { isHidden: true }), -// level: PD.Text<VolumeStreaming.LevelType>('em') -// } -// })({ -// apply({ a, params }, plugin: PluginContext) { -// const data = a.data.currentData[params.channel] || VolumeData.Empty; -// console.log({ data }); -// return new SO.Volume.Data(a.data.currentData[params.channel] || VolumeData.Empty, { label: params.level }); -// } -// }); - -export { VolumeStreamingVisual } -type VolumeStreamingVisual = typeof VolumeStreamingVisual -const VolumeStreamingVisual = PluginStateTransform.BuiltIn({ - name: 'volume-streaming-visual', - display: { name: 'Volume Streaming Visual' }, - from: VolumeStreaming.Obj, - to: SO.Volume.Representation3D, - params: { - channel: PD.Select<keyof VolumeStreaming.ChannelData>('EM', [['EM', 'EM'], ['FO-FC', 'Fo-Fc'], ['2FO-FC', '2Fo-Fc']], { isHidden: true }), - level: PD.Text<VolumeStreaming.LevelType>('em') - } -})({ - apply: ({ a, params: srcParams }, plugin: PluginContext) => Task.create('Volume Representation', async ctx => { - const { data, params } = createVolumeProps(a.data, srcParams.channel, srcParams.level); - - const provider = BuiltInVolumeRepresentations.isosurface; - const props = params.type.params || {} - const repr = provider.factory({ webgl: plugin.canvas3d.webgl, ...plugin.volumeRepresentation.themeCtx }, provider.getParams) - repr.setTheme(createTheme(plugin.volumeRepresentation.themeCtx, { volume: data }, params)) - await repr.createOrUpdate(props, data).runInContext(ctx); - return new SO.Volume.Representation3D(repr, { label: srcParams.level, description: VolumeRepresentation3DHelpers.getDescription(props) }); - }), - update: ({ a, b, oldParams, newParams }, plugin: PluginContext) => Task.create('Volume Representation', async ctx => { - // TODO : check if params/underlying data/etc have changed; maybe will need to export "data" or some other "tag" in the Representation for this to work - const { data, params } = createVolumeProps(a.data, newParams.channel, newParams.level); - const props = { ...b.data.props, ...params.type.params }; - b.data.setTheme(createTheme(plugin.volumeRepresentation.themeCtx, { volume: data }, params)) - await b.data.createOrUpdate(props, data).runInContext(ctx); - return StateTransformer.UpdateResult.Updated; - }) -}); - -function createVolumeProps(streaming: VolumeStreaming.Behavior, channel: keyof VolumeStreaming.ChannelData, level: VolumeStreaming.LevelType) { - const data = streaming.currentData[channel] || VolumeData.One; - // TODO: createTheme fails when VolumeData.Empty is used for some reason. - - let isoValue: VolumeIsoValue, color: Color; - - if (level === 'em' && streaming.params.levels.name === 'em') { - isoValue = streaming.params.levels.params.isoValue; - color = streaming.params.levels.params.color; - } else if (level !== 'em' && streaming.params.levels.name === 'x-ray') { - isoValue = streaming.params.levels.params[level].isoValue; - color = streaming.params.levels.params[level].color; - } else { - throw new Error(`Unsupported iso level ${level}.`); - } - - const params = VolumeRepresentation3DHelpers.getDefaultParamsStatic(streaming.ctx, 'isosurface', { isoValue, alpha: 0.3 }, 'uniform', { value: color }); - return { data, params }; -} \ No newline at end of file +}); \ No newline at end of file