Skip to content
Snippets Groups Projects
Commit 1b382653 authored by dsehnal's avatar dsehnal
Browse files

add volume controls to Volseg extension

parent c7cee63c
No related branches found
No related tags found
No related merge requests found
...@@ -8,7 +8,7 @@ Note that since we don't clearly distinguish between a public and private interf ...@@ -8,7 +8,7 @@ Note that since we don't clearly distinguish between a public and private interf
- Show histogram in direct volume control point settings - Show histogram in direct volume control point settings
- Add `solidInterior` parameter to sphere/cylinder impostors - Add `solidInterior` parameter to sphere/cylinder impostors
- Add `meshes` and `volseg` extensions - Add `meshes` and `volumes-and-segmentations` extensions
## [v3.27.0] - 2022-12-15 ## [v3.27.0] - 2022-12-15
......
...@@ -27,11 +27,12 @@ import { VolsegMeshSegmentationData } from './entry-meshes'; ...@@ -27,11 +27,12 @@ import { VolsegMeshSegmentationData } from './entry-meshes';
import { VolsegModelData } from './entry-models'; import { VolsegModelData } from './entry-models';
import { VolsegLatticeSegmentationData } from './entry-segmentation'; import { VolsegLatticeSegmentationData } from './entry-segmentation';
import { VolsegState, VolsegStateData, VolsegStateParams } from './entry-state'; import { VolsegState, VolsegStateData, VolsegStateParams } from './entry-state';
import { VolsegVolumeData, SimpleVolumeParamValues } from './entry-volume'; import { VolsegVolumeData, SimpleVolumeParamValues, VOLUME_VISUAL_TAG } from './entry-volume';
import * as ExternalAPIs from './external-api'; import * as ExternalAPIs from './external-api';
import { VolsegGlobalStateData } from './global-state'; import { VolsegGlobalStateData } from './global-state';
import { applyEllipsis, Choice, isDefined, lazyGetter, splitEntryId } from './helpers'; import { applyEllipsis, Choice, isDefined, lazyGetter, splitEntryId } from './helpers';
import { type VolsegStateFromEntry } from './transformers'; import { type VolsegStateFromEntry } from './transformers';
import { StateTransforms } from '../../mol-plugin-state/transforms';
export const MAX_VOXELS = 10 ** 7; export const MAX_VOXELS = 10 ** 7;
...@@ -90,6 +91,7 @@ export namespace VolsegEntryParamValues { ...@@ -90,6 +91,7 @@ export namespace VolsegEntryParamValues {
export class VolsegEntry extends PluginStateObject.CreateBehavior<VolsegEntryData>({ name: 'Vol & Seg Entry' }) { } export class VolsegEntry extends PluginStateObject.CreateBehavior<VolsegEntryData>({ name: 'Vol & Seg Entry' }) { }
type VolRepr3DT = typeof StateTransforms.Representation.VolumeRepresentation3D
export class VolsegEntryData extends PluginBehavior.WithSubscribers<VolsegEntryParamValues> { export class VolsegEntryData extends PluginBehavior.WithSubscribers<VolsegEntryParamValues> {
plugin: PluginContext; plugin: PluginContext;
...@@ -111,6 +113,7 @@ export class VolsegEntryData extends PluginBehavior.WithSubscribers<VolsegEntryP ...@@ -111,6 +113,7 @@ export class VolsegEntryData extends PluginBehavior.WithSubscribers<VolsegEntryP
private getStateNode = lazyGetter(() => this.plugin.state.data.selectQ(q => q.byRef(this.ref).subtree().ofType(VolsegState))[0] as StateObjectCell<VolsegState, StateTransform<typeof VolsegStateFromEntry>>, 'Missing VolsegState node. Must first create VolsegState for this VolsegEntry.'); private getStateNode = lazyGetter(() => this.plugin.state.data.selectQ(q => q.byRef(this.ref).subtree().ofType(VolsegState))[0] as StateObjectCell<VolsegState, StateTransform<typeof VolsegStateFromEntry>>, 'Missing VolsegState node. Must first create VolsegState for this VolsegEntry.');
public currentState = new BehaviorSubject(ParamDefinition.getDefaultValues(VolsegStateParams)); public currentState = new BehaviorSubject(ParamDefinition.getDefaultValues(VolsegStateParams));
public currentVolume = new BehaviorSubject<StateTransform<VolRepr3DT> | undefined>(undefined);
private constructor(plugin: PluginContext, params: VolsegEntryParamValues) { private constructor(plugin: PluginContext, params: VolsegEntryParamValues) {
...@@ -158,6 +161,14 @@ export class VolsegEntryData extends PluginBehavior.WithSubscribers<VolsegEntryP ...@@ -158,6 +161,14 @@ export class VolsegEntryData extends PluginBehavior.WithSubscribers<VolsegEntryP
} }
}); });
this.subscribeObservable(this.plugin.state.data.events.cell.stateUpdated, e => {
// TODO: subscribe cell.removed event as well to set the current volume to undefined
if (e.cell.transform.tags?.includes(VOLUME_VISUAL_TAG)) {
// TODO: make sure this belongs to the "current entry subtree"
this.currentVolume.next(e.cell.transform);
}
});
this.subscribeObservable(this.plugin.behaviors.interaction.click, async e => { this.subscribeObservable(this.plugin.behaviors.interaction.click, async e => {
const loci = e.current.loci; const loci = e.current.loci;
const clickedSegment = this.getSegmentIdFromLoci(loci); const clickedSegment = this.getSegmentIdFromLoci(loci);
......
...@@ -24,7 +24,7 @@ import { VolsegGlobalStateData } from './global-state'; ...@@ -24,7 +24,7 @@ import { VolsegGlobalStateData } from './global-state';
const GROUP_TAG = 'volume-group'; const GROUP_TAG = 'volume-group';
const VOLUME_VISUAL_TAG = 'volume-visual'; export const VOLUME_VISUAL_TAG = 'volume-visual';
const DIRECT_VOLUME_RELATIVE_PEAK_HALFWIDTH = 0.5; const DIRECT_VOLUME_RELATIVE_PEAK_HALFWIDTH = 0.5;
......
...@@ -12,6 +12,7 @@ import * as Icons from '../../mol-plugin-ui/controls/icons'; ...@@ -12,6 +12,7 @@ import * as Icons from '../../mol-plugin-ui/controls/icons';
import { ParameterControls } from '../../mol-plugin-ui/controls/parameters'; import { ParameterControls } from '../../mol-plugin-ui/controls/parameters';
import { Slider } from '../../mol-plugin-ui/controls/slider'; import { Slider } from '../../mol-plugin-ui/controls/slider';
import { useBehavior } from '../../mol-plugin-ui/hooks/use-behavior'; import { useBehavior } from '../../mol-plugin-ui/hooks/use-behavior';
import { UpdateTransformControl } from '../../mol-plugin-ui/state/update-transform';
import { PluginContext } from '../../mol-plugin/context'; import { PluginContext } from '../../mol-plugin/context';
import { shallowEqualArrays } from '../../mol-util'; import { shallowEqualArrays } from '../../mol-util';
import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { ParamDefinition as PD } from '../../mol-util/param-definition';
...@@ -117,11 +118,6 @@ function VolsegEntryControls({ entryData }: { entryData: VolsegEntryData }) { ...@@ -117,11 +118,6 @@ function VolsegEntryControls({ entryData }: { entryData: VolsegEntryData }) {
const visibleModels = state.visibleModels.map(model => model.pdbId); const visibleModels = state.visibleModels.map(model => model.pdbId);
const allPdbs = entryData.pdbs; const allPdbs = entryData.pdbs;
const volumeValues: SimpleVolumeParamValues = {
volumeType: state.volumeType,
opacity: state.volumeOpacity,
};
return <> return <>
{/* Title */} {/* Title */}
<div style={{ fontWeight: 'bold', padding: 8, paddingTop: 6, paddingBottom: 4, overflow: 'hidden' }}> <div style={{ fontWeight: 'bold', padding: 8, paddingTop: 6, paddingBottom: 4, overflow: 'hidden' }}>
...@@ -139,10 +135,7 @@ function VolsegEntryControls({ entryData }: { entryData: VolsegEntryData }) { ...@@ -139,10 +135,7 @@ function VolsegEntryControls({ entryData }: { entryData: VolsegEntryData }) {
</ExpandGroup>} </ExpandGroup>}
{/* Volume */} {/* Volume */}
<ExpandGroup header='Volume data' initiallyExpanded> <VolumeControls entryData={entryData} />
<WaitingParameterControls params={SimpleVolumeParams} values={volumeValues} onChangeValues={async next => { await sleep(20); await entryData.actionUpdateVolumeVisual(next); }} />
</ExpandGroup>
<ExpandGroup header='Segmentation data' initiallyExpanded> <ExpandGroup header='Segmentation data' initiallyExpanded>
{/* Segment opacity slider */} {/* Segment opacity slider */}
<ControlRow label='Opacity' control={ <ControlRow label='Opacity' control={
...@@ -189,6 +182,23 @@ function VolsegEntryControls({ entryData }: { entryData: VolsegEntryData }) { ...@@ -189,6 +182,23 @@ function VolsegEntryControls({ entryData }: { entryData: VolsegEntryData }) {
</>; </>;
} }
function VolumeControls({ entryData }: { entryData: VolsegEntryData }) {
const vol = useBehavior(entryData.currentVolume);
if (!vol) return null;
const volumeValues: SimpleVolumeParamValues = {
volumeType: vol.state.isHidden ? 'off' : vol.params?.type.name as any,
opacity: vol.params?.type.params.alpha,
};
return <ExpandGroup header='Volume data' initiallyExpanded>
<WaitingParameterControls params={SimpleVolumeParams} values={volumeValues} onChangeValues={async next => { await sleep(20); await entryData.actionUpdateVolumeVisual(next); }} />
<ExpandGroup header='Detailed Volume Params' headerStyle={{ marginTop: 1 }}>
<UpdateTransformControl state={entryData.plugin.state.data} transform={vol} customHeader='none' />
</ExpandGroup>
</ExpandGroup>;
}
type ComponentParams<T extends React.Component<any, any, any> | ((props: any) => JSX.Element)> = type ComponentParams<T extends React.Component<any, any, any> | ((props: any) => JSX.Element)> =
T extends React.Component<infer P, any, any> ? P : T extends (props: infer P) => JSX.Element ? P : never; T extends React.Component<infer P, any, any> ? P : T extends (props: infer P) => JSX.Element ? P : never;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment