David Sehnal 6 роки тому
батько
коміт
5b2108747e

+ 0 - 149
src/mol-plugin/behavior/dynamic/volume.ts

@@ -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' }) { }
-}

+ 1 - 22
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);
-});
+}));

+ 1 - 104
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 };
-}
+});