diff --git a/src/examples/alpha-orbitals/index.ts b/src/examples/alpha-orbitals/index.ts index d10e5234fb839560ea76aabea49625274f6ab223..c9fa0ca36f5876b0cb19f7f50aa019347ad0a873 100644 --- a/src/examples/alpha-orbitals/index.ts +++ b/src/examples/alpha-orbitals/index.ts @@ -36,7 +36,8 @@ interface DemoInput { interface Params { orbitalIndex: number, - isoValue: number + isoValue: number, + staticIsovalues: boolean } export class AlphaOrbitalsExample { @@ -71,7 +72,7 @@ export class AlphaOrbitalsExample { } readonly params = new BehaviorSubject<ParamDefinition.For<Params>>({ } as any); - readonly state = new BehaviorSubject<Params>({ orbitalIndex: 32, isoValue: 1 }); + readonly state = new BehaviorSubject<Params>({ orbitalIndex: 32, isoValue: 1, staticIsovalues: true }); private volume?: StateObjectSelector<PluginStateObject.Volume.Data, typeof CreateOrbitalVolume>; private positive?: StateObjectSelector<PluginStateObject.Volume.Representation3D, typeof StateTransforms.Representation.VolumeRepresentation3D>; @@ -84,13 +85,19 @@ export class AlphaOrbitalsExample { 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(); + this.currentParams.staticIsovalues = this.state.value.staticIsovalues; + this.currentParams.isoValue = this.state.value.isoValue; + + if (!state.staticIsovalues) { + 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; + this.currentParams.staticIsovalues = this.state.value.staticIsovalues; 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)); @@ -100,14 +107,14 @@ export class AlphaOrbitalsExample { private volumeParams(value: number | undefined, color: Color) { return createVolumeRepresentationParams(this.plugin, this.volume!.data!, { // type: 'isosurface', - // typeParams: { isoValue: { kind: 'absolute', absoluteValue: positive } }, + // typeParams: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * this.state.value.isoValue } }, // 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 } + params: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * this.state.value.isoValue }, singleLayer: true } } }, color: 'uniform', @@ -151,12 +158,13 @@ export class AlphaOrbitalsExample { 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 }) + orbitalIndex: ParamDefinition.Numeric(this.currentParams.orbitalIndex, { min: 0, max: input.orbitals.length - 1 }, { immediateUpdate: true, isEssential: true }), + isoValue: ParamDefinition.Numeric(this.currentParams.isoValue, { min: 0.5, max: 3, step: 0.1 }, { immediateUpdate: true, isEssential: false }), + staticIsovalues: ParamDefinition.Boolean(this.currentParams.staticIsovalues) }); - this.state.pipe(skip(1), debounceTime(1000 / 30)).subscribe(async params => { - if (params.orbitalIndex !== this.currentParams.orbitalIndex) { + this.state.pipe(skip(1), debounceTime(1000 / 24)).subscribe(async params => { + if (params.orbitalIndex !== this.currentParams.orbitalIndex || params.staticIsovalues !== this.currentParams.staticIsovalues) { this.setIndex(); } else if (params.isoValue !== this.currentParams.isoValue) { this.setIsovalue(); diff --git a/src/examples/alpha-orbitals/transforms.ts b/src/examples/alpha-orbitals/transforms.ts index 2185352228f97d7b97ffdd1e73d4bd9347cb6777..d0344f7a60446c4ceb88a09c269e82fc01d3627b 100644 --- a/src/examples/alpha-orbitals/transforms.ts +++ b/src/examples/alpha-orbitals/transforms.ts @@ -61,6 +61,7 @@ export const CreateOrbitalVolume = PluginStateTransform.BuiltIn({ [25, 0.4], [0, 0.35], ], + doNotComputeIsovalues: true }, plugin.canvas3d?.webgl).runInContext(ctx); const volume: Volume = { grid: data.grid, diff --git a/src/extensions/alpha-orbitals/cubes.ts b/src/extensions/alpha-orbitals/cubes.ts index e6ada49eeb14cb7845365469aacf674bb6f3f936..0b36df06397258fe98a7f070e25275c7e4335e26 100644 --- a/src/extensions/alpha-orbitals/cubes.ts +++ b/src/extensions/alpha-orbitals/cubes.ts @@ -27,7 +27,7 @@ export interface CubeGridInfo { export interface CubeGrid { grid: Grid; - isovalues: { negative?: number; positive?: number }; + isovalues?: { negative?: number; positive?: number }; } export interface Basis { @@ -59,6 +59,7 @@ export interface SphericalCollocationParams { boxExpand: number; gridSpacing: number | [atomCountThreshold: number, spacing: number][]; alphaOrbitals: number[]; + doNotComputeIsovalues?: boolean } export function createSphericalCollocationGrid( @@ -106,13 +107,13 @@ export function createSphericalCollocationGrid( // } // } - return createCubeGrid(cParams.grid, matrixGL, [0, 1, 2]); + return createCubeGrid(cParams.grid, matrixGL, [0, 1, 2], !params.doNotComputeIsovalues); }); } const BohrToAngstromFactor = 0.529177210859; -function createCubeGrid(gridInfo: CubeGridInfo, values: Float32Array, axisOrder: number[]) { +function createCubeGrid(gridInfo: CubeGridInfo, values: Float32Array, axisOrder: number[], computeIsovalues: boolean) { const boxSize = Box3D.size(Vec3(), gridInfo.box); const boxOrigin = Vec3.clone(gridInfo.box.min); @@ -146,11 +147,16 @@ function createCubeGrid(gridInfo: CubeGridInfo, values: Float32Array, axisOrder: // TODO: when using GPU rendering, the cumulative sum can be computed // along the ray on the fly - console.time('iso'); - const isovalues = computeIsocontourValues(values, 0.85); - console.timeEnd('iso'); - console.log(isovalues); + let isovalues: { negative?: number, positive?: number } | undefined; + + if (computeIsovalues) { + console.time('iso'); + const isovalues = computeIsocontourValues(values, 0.85); + console.timeEnd('iso'); + console.log(isovalues); + } + return { grid, isovalues }; } diff --git a/src/mol-plugin-ui/controls/parameters.tsx b/src/mol-plugin-ui/controls/parameters.tsx index 9fa7379e51932239e0f032c90b586432d7d42b47..c21ac30f1d7e65a4abd617df1bae3898976ae49e 100644 --- a/src/mol-plugin-ui/controls/parameters.tsx +++ b/src/mol-plugin-ui/controls/parameters.tsx @@ -368,7 +368,8 @@ export class NumberRangeControl extends SimpleParam<PD.Numeric> { renderControl() { const value = typeof this.props.value === 'undefined' ? this.props.param.defaultValue : this.props.value; return <Slider value={value} min={this.props.param.min!} max={this.props.param.max!} - step={this.props.param.step} onChange={this.onChange} disabled={this.props.isDisabled} onEnter={this.props.onEnter} />; + step={this.props.param.step} onChange={this.onChange} onChangeImmediate={this.props.param.immediateUpdate ? this.onChange : void 0} + disabled={this.props.isDisabled} onEnter={this.props.onEnter} />; } } diff --git a/src/mol-plugin-ui/controls/slider.tsx b/src/mol-plugin-ui/controls/slider.tsx index 4daa902544ccaca9c166eda393eda7e0d288f626..7051acb8e2f99ff2968bfea80cdbf1473dd384c1 100644 --- a/src/mol-plugin-ui/controls/slider.tsx +++ b/src/mol-plugin-ui/controls/slider.tsx @@ -15,6 +15,7 @@ export class Slider extends React.Component<{ value: number, step?: number, onChange: (v: number) => void, + onChangeImmediate?: (v: number) => void, disabled?: boolean, onEnter?: () => void }, { isChanging: boolean, current: number }> { @@ -37,6 +38,7 @@ export class Slider extends React.Component<{ updateCurrent = (current: number) => { this.setState({ current }); + this.props.onChangeImmediate?.(current); } updateManually = (v: number) => { diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index cdd4cee2798764cd64d04e6e0abb749e22871e72..1a441a9d8120c7ddb39518b0ea2258f1ea514e75 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -199,10 +199,13 @@ export namespace ParamDefinition { } export interface Numeric extends Base<number>, Range { - type: 'number' + type: 'number', + immediateUpdate?: boolean } - export function Numeric(defaultValue: number, range?: { min?: number, max?: number, step?: number }, info?: Info): Numeric { - return setInfo<Numeric>(setRange({ type: 'number', defaultValue }, range), info); + export function Numeric(defaultValue: number, range?: { min?: number, max?: number, step?: number }, info?: Info & { immediateUpdate?: boolean }): Numeric { + const ret = setInfo<Numeric>(setRange({ type: 'number', defaultValue }, range), info); + if (info?.immediateUpdate) ret.immediateUpdate = true; + return ret; } export interface Interval extends Base<[number, number]>, Range {