Skip to content
Snippets Groups Projects
Commit 871f9635 authored by David Sehnal's avatar David Sehnal
Browse files

alpha-orbitals: controls

parent aae9a117
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.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import * as React from 'react';
import { useEffect, useState } from 'react';
import * as ReactDOM from 'react-dom';
import { AlphaOrbitalsExample } from '.';
import { ParameterControls } from '../../mol-plugin-ui/controls/parameters';
import { PluginContextContainer } from '../../mol-plugin-ui/plugin';
export function mountControls(orbitals: AlphaOrbitalsExample, parent: Element) {
ReactDOM.render(<PluginContextContainer plugin={orbitals.plugin}>
<Controls orbitals={orbitals} />
</PluginContextContainer>, parent);
}
function Controls({ orbitals }: { orbitals: AlphaOrbitalsExample }) {
const params = useBehavior(orbitals.params);
const values = useBehavior(orbitals.state);
return <ParameterControls params={params as any} values={values} onChangeValues={(vs: any) => orbitals.state.next(vs)} />;
}
interface Behavior<T> {
value: T;
subscribe(f: (v: T) => void): { unsubscribe(): void };
}
export function useBehavior<T>(s: Behavior<T>): T;
// eslint-disable-next-line
export function useBehavior<T>(s: Behavior<T> | undefined): T | undefined;
// eslint-disable-next-line
export function useBehavior<T>(s: Behavior<T> | undefined): T | undefined {
const [value, setValue] = useState(s?.value);
useEffect(() => {
if (!s) return;
let fst = true;
const sub = s.subscribe((v) => {
if (fst) {
fst = false;
if (v !== value) setValue(v);
} else setValue(v);
});
return () => {
sub.unsubscribe();
};
// eslint-disable-next-line
}, [s]);
return value;
}
\ No newline at end of file
......@@ -12,19 +12,24 @@
}
#app {
position: absolute;
left: 160px;
top: 100px;
width: 800px;
height: 800px;
border: 1px solid #ccc;
left: 0;
top: 0;
bottom: 0;
right: 0;
}
#controls {
position: absolute;
left: 8px;
top: 8px;
width: 300px;
}
</style>
<link rel="stylesheet" type="text/css" href="molstar.css" />
<script type="text/javascript" src="./index.js"></script>
</head>
<body>
<div id='controls'></div>
<div id="app"></div>
<div id='controls'></div>
<script>
AlphaOrbitalsExample.init('app')
</script>
......
import { BehaviorSubject } from 'rxjs';
import { debounceTime, skip } from 'rxjs/operators';
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
......@@ -8,9 +10,15 @@ import { Basis, computeIsocontourValues } from '../../extensions/alpha-orbitals/
import { SphericalBasisOrder } from '../../extensions/alpha-orbitals/orbitals';
import { createPluginAsync, DefaultPluginSpec } from '../../mol-plugin';
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
import { PluginStateObject } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { PluginConfig } from '../../mol-plugin/config';
import { PluginContext } from '../../mol-plugin/context';
import { StateObjectSelector } from '../../mol-state';
import { Color } from '../../mol-util/color';
import { ColorNames } from '../../mol-util/color/names';
import { ParamDefinition } from '../../mol-util/param-definition';
import { mountControls } from './controls';
import { DemoMoleculeSDF, DemoOrbitals } from './example-data';
import './index.html';
import { CreateOrbitalVolume, StaticBasisAndOrbitals } from './transforms';
......@@ -26,7 +34,12 @@ interface DemoInput {
}[]
}
class AlphaOrbitalsExample {
interface Params {
orbitalIndex: number,
isoValue: number
}
export class AlphaOrbitalsExample {
plugin: PluginContext;
async init(target: string | HTMLElement) {
......@@ -37,8 +50,14 @@ class AlphaOrbitalsExample {
isExpanded: false,
showControls: false
},
controls: { left: 'none', right: 'none', top: 'none', bottom: 'none' }
}
controls: { left: 'none', right: 'none', top: 'none', bottom: 'none' },
},
config: [
[PluginConfig.Viewport.ShowExpand, false],
[PluginConfig.Viewport.ShowControls, false],
[PluginConfig.Viewport.ShowSelectionMode, false],
[PluginConfig.Viewport.ShowAnimation, false],
]
});
this.plugin.managers.interactivity.setProps({ granularity: 'element' });
......@@ -47,6 +66,53 @@ class AlphaOrbitalsExample {
moleculeSdf: DemoMoleculeSDF,
...DemoOrbitals
});
mountControls(this, document.getElementById('controls')!);
}
readonly params = new BehaviorSubject<ParamDefinition.For<Params>>({ } as any);
readonly state = new BehaviorSubject<Params>({ orbitalIndex: 32, isoValue: 1 });
private volume?: StateObjectSelector<PluginStateObject.Volume.Data, typeof CreateOrbitalVolume>;
private positive?: StateObjectSelector<PluginStateObject.Volume.Representation3D, typeof StateTransforms.Representation.VolumeRepresentation3D>;
private negative?: StateObjectSelector<PluginStateObject.Volume.Representation3D, typeof StateTransforms.Representation.VolumeRepresentation3D>;
private isovalues: { negative?: number, positive?: number } = { negative: void 0, positive: void 0 }
private currentParams: Params = { ...this.state.value };
private async setIndex() {
if (!this.volume?.isOk) return;
const state = this.state.value;
await this.plugin.build().to(this.volume).update(CreateOrbitalVolume, () => ({ index: state.orbitalIndex })).commit();
this.currentParams.orbitalIndex = this.state.value.orbitalIndex;
this.isovalues = computeIsocontourValues(this.volume.data!.grid.cells.data as any, 0.85);
await this.setIsovalue();
}
private setIsovalue() {
const { positive, negative } = this.isovalues;
this.currentParams.isoValue = this.state.value.isoValue;
const update = this.plugin.build();
update.to(this.positive!).update(this.volumeParams(positive, ColorNames.blue));
update.to(this.negative!).update(this.volumeParams(negative, ColorNames.red));
return update.commit();
}
private volumeParams(value: number | undefined, color: Color) {
return createVolumeRepresentationParams(this.plugin, this.volume!.data!, {
// type: 'isosurface',
// typeParams: { isoValue: { kind: 'absolute', absoluteValue: positive } },
// color: 'uniform',
// colorParams: { value: ColorNames.blue }
type: 'direct-volume',
typeParams: {
renderMode: {
name: 'isosurface',
params: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * this.state.value.isoValue }, singleLayer: false }
}
},
color: 'uniform',
colorParams: { value: color }
});
}
async load(input: DemoInput) {
......@@ -60,38 +126,42 @@ class AlphaOrbitalsExample {
const all = await this.plugin.builders.structure.tryCreateComponentStatic(structure, 'all');
if (all) await this.plugin.builders.structure.representation.addRepresentation(all, { type: 'ball-and-stick', color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } });
const volumeRef = await this.plugin.build().toRoot()
const state = this.state.value;
this.volume = await this.plugin.build().toRoot()
.apply(StaticBasisAndOrbitals, { basis: input.basis, order: input.order, orbitals: input.orbitals })
.apply(CreateOrbitalVolume, { index: 32 })
.apply(CreateOrbitalVolume, { index: state.orbitalIndex })
.commit();
if (!volumeRef.isOk) return;
if (!this.volume.isOk) {
this.volume = void 0;
return;
}
// TODO: the isovalues are being computed twice. Need to add more flexible support to Volume object
// for controlling them
const { negative, positive } = computeIsocontourValues(volumeRef.data!.grid.cells.data as any, 0.85);
this.isovalues = computeIsocontourValues(this.volume.data!.grid.cells.data as any, 0.85);
const { positive, negative } = this.isovalues;
const repr = this.plugin.build().to(volumeRef);
const repr = this.plugin.build().to(this.volume);
if (positive !== void 0) {
repr.apply(StateTransforms.Representation.VolumeRepresentation3D, createVolumeRepresentationParams(this.plugin, volumeRef.data!, {
type: 'isosurface',
typeParams: { isoValue: { kind: 'absolute', absoluteValue: positive } },
color: 'uniform',
colorParams: { value: ColorNames.blue }
}));
}
if (negative !== void 0) {
repr.apply(StateTransforms.Representation.VolumeRepresentation3D, createVolumeRepresentationParams(this.plugin, volumeRef.data!, {
type: 'isosurface',
typeParams: { isoValue: { kind: 'absolute', absoluteValue: negative } },
color: 'uniform',
colorParams: { value: ColorNames.red }
}));
}
this.positive = repr.apply(StateTransforms.Representation.VolumeRepresentation3D, this.volumeParams(positive, ColorNames.blue)).selector;
this.negative = repr.apply(StateTransforms.Representation.VolumeRepresentation3D, this.volumeParams(negative, ColorNames.red)).selector;
await repr.commit();
this.params.next({
orbitalIndex: ParamDefinition.Numeric(this.currentParams.orbitalIndex, { min: 0, max: input.orbitals.length - 1 }),
isoValue: ParamDefinition.Numeric(1, { min: 0.5, max: 3, step: 0.1 })
});
this.state.pipe(skip(1), debounceTime(1000 / 30)).subscribe(async params => {
if (params.orbitalIndex !== this.currentParams.orbitalIndex) {
this.setIndex();
} else if (params.isoValue !== this.currentParams.isoValue) {
this.setIsovalue();
}
});
}
}
......
......@@ -51,7 +51,7 @@ export const CreateOrbitalVolume = PluginStateTransform.BuiltIn({
return Task.create('Orbital Volume', async ctx => {
const data = await createSphericalCollocationGrid({
basis: a.data.basis,
cutoffThreshold: 0.0075,
cutoffThreshold: 0.0015,
alphaOrbitals: a.data.orbitals[params.index].alpha,
sphericalOrder: a.data.order,
boxExpand: 4.5,
......
......@@ -75,7 +75,7 @@ export function createSphericalCollocationGrid(
sphericalOrder: params.sphericalOrder
};
console.log(cParams);
// console.log(cParams);
console.time('gpu');
const pass = new AlphaOrbitalsPass(webgl!, cParams);
......@@ -83,10 +83,10 @@ export function createSphericalCollocationGrid(
console.timeEnd('gpu');
// TODO: remove the 2nd run
console.time('gpu');
const pass0 = new AlphaOrbitalsPass(webgl!, cParams);
pass0.getData();
console.timeEnd('gpu');
// console.time('gpu');
// const pass0 = new AlphaOrbitalsPass(webgl!, cParams);
// pass0.getData();
// console.timeEnd('gpu');
// if (false && webgl) {
// } else {
......@@ -95,7 +95,7 @@ export function createSphericalCollocationGrid(
// console.timeEnd('cpu');
// // }
console.log(matrixGL);
// console.log(matrixGL);
// console.log(matrix);
// for (let i = 0; i < matrixGL.length; i++) {
......
......@@ -108,7 +108,7 @@ function createTextureData({
function getPostprocessingRenderable(ctx: WebGLContext, params: CollocationParams): AlphaOrbitalsRenderable {
const data = createTextureData(params);
console.log(data);
// console.log(data);
const values: Values<typeof AlphaOrbitalsSchema> = {
...QuadValues,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment