Browse Source

wip isovalue param

Alexander Rose 6 years ago
parent
commit
624dce3b69

+ 36 - 0
src/mol-plugin/ui/controls/parameters.tsx

@@ -47,6 +47,7 @@ function controlFor(param: PD.Any): ParamControl | undefined {
         case 'number': return typeof param.min !== 'undefined' && typeof param.max !== 'undefined'
             ? NumberRangeControl : NumberInputControl;
         case 'converted': return ConvertedControl;
+        case 'conditioned': return ConditionedControl;
         case 'multi-select': return MultiSelectControl;
         case 'color': return ColorControl;
         case 'color-scale': return ColorScaleControl;
@@ -456,6 +457,41 @@ export class MappedControl extends React.PureComponent<ParamProps<PD.Mapped<any>
     }
 }
 
+export class ConditionedControl extends React.PureComponent<ParamProps<PD.Conditioned<any, any, any>>> {
+    change(value: PD.Conditioned<any, any, any>['defaultValue'] ) {
+        this.props.onChange({ name: this.props.name, param: this.props.param, value });
+    }
+
+    onChangeCondition: ParamOnChange = e => {
+        this.change(this.props.param.conditionedValue(this.props.value, e.value));
+    }
+
+    onChangeParam: ParamOnChange = e => {
+        this.change(e.value);
+    }
+
+    render() {
+        const value = this.props.value;
+        const condition = this.props.param.conditionForValue(value) as string
+        const param = this.props.param.conditionParams[condition];
+        const label = this.props.param.label || camelCaseToWords(this.props.name);
+        const Conditioned = controlFor(param);
+
+        const select = <SelectControl param={this.props.param.select}
+            isDisabled={this.props.isDisabled} onChange={this.onChangeCondition} onEnter={this.props.onEnter}
+            name={`${label} Kind`} value={condition} />
+
+        if (!Conditioned) {
+            return select;
+        }
+
+        return <div>
+            {select}
+            <Conditioned param={param} value={value} name={label} onChange={this.onChangeParam} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} />
+        </div>
+    }
+}
+
 export class ConvertedControl extends React.PureComponent<ParamProps<PD.Converted<any, any>>> {
     onChange: ParamOnChange = e => {
         this.props.onChange({

+ 50 - 11
src/mol-repr/volume/isosurface-mesh.ts

@@ -5,7 +5,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { VolumeData } from 'mol-model/volume'
+import { VolumeData, VolumeIsoValue } from 'mol-model/volume'
 import { VolumeVisual, VolumeRepresentation, VolumeRepresentationProvider } from './representation';
 import { EmptyLoci } from 'mol-model/loci';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
@@ -19,9 +19,30 @@ import { VisualContext } from 'mol-repr/visual';
 import { NullLocation } from 'mol-model/location';
 import { Lines } from 'mol-geo/geometry/lines/lines';
 
-interface VolumeIsosurfaceProps {
-    isoValue: number
+const IsoValueParam = PD.Conditioned(
+    VolumeIsoValue.relative(VolumeData.Empty.dataStats, 2),
+    {
+        'absolute': PD.Converted(
+            (v: VolumeIsoValue) => VolumeIsoValue.toAbsolute(v).absoluteValue,
+            (v: number) => VolumeIsoValue.absolute(VolumeData.Empty.dataStats, v),
+            PD.Numeric(0, { min: -1, max: 1, step: 0.01 })
+        ),
+        'relative': PD.Converted(
+            (v: VolumeIsoValue) => VolumeIsoValue.toRelative(v).relativeValue,
+            (v: number) => VolumeIsoValue.relative(VolumeData.Empty.dataStats, v),
+            PD.Numeric(0, { min: -1, max: 1, step: 0.01 })
+        )
+    },
+    (v: VolumeIsoValue) => v.kind === 'absolute' ? 'absolute' : 'relative',
+    (v: VolumeIsoValue, c: 'absolute' | 'relative') => c === 'absolute' ? VolumeIsoValue.toAbsolute(v) : VolumeIsoValue.toRelative(v)
+)
+type IsoValueParam = typeof IsoValueParam
+
+export const VolumeIsosurfaceParams = {
+    isoValue: IsoValueParam
 }
+export type VolumeIsosurfaceParams = typeof VolumeIsosurfaceParams
+export type VolumeIsosurfaceProps = PD.Values<VolumeIsosurfaceParams>
 
 //
 
@@ -29,7 +50,7 @@ export async function createVolumeIsosurfaceMesh(ctx: VisualContext, volume: Vol
     ctx.runtime.update({ message: 'Marching cubes...' });
 
     const surface = await computeMarchingCubesMesh({
-        isoLevel: props.isoValue,
+        isoLevel: VolumeIsoValue.toAbsolute(props.isoValue).absoluteValue,
         scalarField: volume.data
     }, mesh).runAsChild(ctx.runtime);
 
@@ -43,7 +64,7 @@ export async function createVolumeIsosurfaceMesh(ctx: VisualContext, volume: Vol
 
 export const IsosurfaceMeshParams = {
     ...Mesh.Params,
-    isoValue: PD.Numeric(0.22, { min: -1, max: 1, step: 0.01 }),
+    ...VolumeIsosurfaceParams
 }
 export type IsosurfaceMeshParams = typeof IsosurfaceMeshParams
 
@@ -66,11 +87,10 @@ export function IsosurfaceMeshVisual(): VolumeVisual<IsosurfaceMeshParams> {
 export async function createVolumeIsosurfaceWireframe(ctx: VisualContext, volume: VolumeData, theme: Theme, props: VolumeIsosurfaceProps, lines?: Lines) {
     ctx.runtime.update({ message: 'Marching cubes...' });
 
-    const params = {
-        isoLevel: props.isoValue,
+    const wireframe = await computeMarchingCubesLines({
+        isoLevel: VolumeIsoValue.toAbsolute(props.isoValue).absoluteValue,
         scalarField: volume.data
-    }
-    const wireframe = await computeMarchingCubesLines(params, lines).runAsChild(ctx.runtime)
+    }, lines).runAsChild(ctx.runtime)
 
     const transform = VolumeData.getGridToCartesianTransform(volume);
     Lines.transformImmediate(wireframe, transform)
@@ -80,7 +100,7 @@ export async function createVolumeIsosurfaceWireframe(ctx: VisualContext, volume
 
 export const IsosurfaceWireframeParams = {
     ...Lines.Params,
-    isoValue: PD.Numeric(0.22, { min: -1, max: 1, step: 0.01 }),
+    ...VolumeIsosurfaceParams
 }
 export type IsosurfaceWireframeParams = typeof IsosurfaceWireframeParams
 
@@ -114,7 +134,26 @@ export const IsosurfaceParams = {
 }
 export type IsosurfaceParams = typeof IsosurfaceParams
 export function getIsosurfaceParams(ctx: ThemeRegistryContext, volume: VolumeData) {
-    return PD.clone(IsosurfaceParams)
+    const p = PD.clone(IsosurfaceParams)
+    const { min, max, mean, sigma } = volume.dataStats
+    p.isoValue = PD.Conditioned(
+        VolumeIsoValue.relative(volume.dataStats, 2),
+        {
+            'absolute': PD.Converted(
+                (v: VolumeIsoValue) => VolumeIsoValue.toAbsolute(v).absoluteValue,
+                (v: number) => VolumeIsoValue.absolute(volume.dataStats, v),
+                PD.Numeric(mean, { min, max, step: sigma / 100 })
+            ),
+            'relative': PD.Converted(
+                (v: VolumeIsoValue) => VolumeIsoValue.toRelative(v).relativeValue,
+                (v: number) => VolumeIsoValue.relative(volume.dataStats, v),
+                PD.Numeric(2, { min: -10, max: 10, step: 0.001 })
+            )
+        },
+        (v: VolumeIsoValue) => v.kind === 'absolute' ? 'absolute' : 'relative',
+        (v: VolumeIsoValue, c: 'absolute' | 'relative') => c === 'absolute' ? VolumeIsoValue.toAbsolute(v) : VolumeIsoValue.toRelative(v)
+    )
+    return p
 }
 
 export type IsosurfaceRepresentation = VolumeRepresentation<IsosurfaceParams>

+ 0 - 1
src/mol-repr/volume/representation.ts

@@ -205,7 +205,6 @@ export type VolumeRepresentationProvider<P extends VolumeParams> = Representatio
 
 export const VolumeParams = {
     ...BaseGeometry.Params,
-    isoValue: PD.Numeric(0.22, { min: -1, max: 1, step: 0.01 }),
 }
 export type VolumeParams = typeof VolumeParams
 

+ 14 - 2
src/mol-util/param-definition.ts

@@ -190,7 +190,7 @@ export namespace ParamDefinition {
     export interface Converted<T, C> extends Base<T> {
         type: 'converted',
         converted: Any,
-        /** converts from props value to display value */
+        /** converts from prop value to display value */
         fromValue(v: T): C,
         /** converts from display value to prop value */
         toValue(v: C): T
@@ -199,7 +199,19 @@ export namespace ParamDefinition {
         return { type: 'converted', defaultValue: toValue(converted.defaultValue), converted, fromValue, toValue };
     }
 
-    export type Any = Value<any> | Select<any> | MultiSelect<any> | Boolean | Text | Color | Vec3 | Numeric | FileParam | Interval | LineGraph | ColorScale<any> | Group<any> | Mapped<any> | Converted<any, any>
+    export interface Conditioned<T, P extends Base<T>, C = { [k: string]: P }> extends Base<T> {
+        type: 'conditioned',
+        select: Select<string>,
+        conditionParams: C
+        conditionForValue(v: T): keyof C 
+        conditionedValue(v: T, condition: keyof C): T,
+    }
+    export function Conditioned<T, P extends Base<T>, C = { [k: string]: P }>(defaultValue: T, conditionParams: C, conditionForValue: (v: T) => keyof C, conditionedValue: (v: T, condition: keyof C) => T): Conditioned<T, P, C> {
+        const options = Object.keys(conditionParams).map(k => [k, k]) as [string, string][];
+        return { type: 'conditioned', select: Select<string>(conditionForValue(defaultValue) as string, options), defaultValue, conditionParams, conditionForValue, conditionedValue };
+    }
+
+    export type Any = Value<any> | Select<any> | MultiSelect<any> | Boolean | Text | Color | Vec3 | Numeric | FileParam | Interval | LineGraph | ColorScale<any> | Group<any> | Mapped<any> | Converted<any, any> | Conditioned<any, any, any>
 
     export type Params = { [k: string]: Any }
     export type Values<T extends Params> = { [k in keyof T]: T[k]['defaultValue'] }