diff --git a/src/mol-plugin/ui/custom/volume.tsx b/src/mol-plugin/ui/custom/volume.tsx index 72dc9d5f3ad7ef0e78bc5bc8bec3506b3b78d670..5b2696fb8e591297e84a69ea86abc0c96d1dc8e2 100644 --- a/src/mol-plugin/ui/custom/volume.tsx +++ b/src/mol-plugin/ui/custom/volume.tsx @@ -15,6 +15,7 @@ import { Slider } from '../controls/slider'; import { VolumeIsoValue, VolumeData } from '../../../mol-model/volume'; import { Vec3 } from '../../../mol-math/linear-algebra'; import { ColorNames } from '../../../mol-util/color/names'; +import { toPrecision } from '../../../mol-util/number'; const ChannelParams = { color: PD.Color(ColorNames.black, { description: 'Display color of the volume.' }), @@ -40,12 +41,12 @@ function Channel(props: { const value = channel.isoValue.kind === 'relative' ? channel.isoValue.relativeValue : channel.isoValue.absoluteValue; const relMin = (min - mean) / sigma; const relMax = (max - mean) / sigma; + const step = toPrecision(isRelative ? Math.round(((max - min) / sigma)) / 100 : sigma / 100, 2) return <ExpandableGroup label={props.label + (props.isRelative ? ' \u03C3' : '')} colorStripe={channel.color} - pivot={<Slider value={value} min={isRelative ? relMin : min} max={isRelative ? relMax : max} - step={isRelative ? sigma / 100 : Math.round(((max - min) / sigma)) / 100} + pivot={<Slider value={value} min={isRelative ? relMin : min} max={isRelative ? relMax : max} step={step} onChange={v => props.changeIso(props.name, v, isRelative)} disabled={props.params.isDisabled} onEnter={props.params.events.onEnter} />} controls={<ParameterControls onChange={({ name, value }) => props.changeParams(props.name, name, value)} params={ChannelParams} values={channel} onEnter={props.params.events.onEnter} />} />; diff --git a/src/mol-repr/volume/isosurface.ts b/src/mol-repr/volume/isosurface.ts index b0e6b5bff08bd6e1c00be5e7fee03c8f4740c34c..5cdda54def4278b14bc5ad46dd5e4a90faa969f6 100644 --- a/src/mol-repr/volume/isosurface.ts +++ b/src/mol-repr/volume/isosurface.ts @@ -18,6 +18,7 @@ import { EmptyLoci } from '../../mol-model/loci'; import { VisualUpdateState } from '../util'; import { Lines } from '../../mol-geo/geometry/lines/lines'; import { RepresentationContext, RepresentationParamsGetter, Representation } from '../representation'; +import { toPrecision } from '../../mol-util/number'; const defaultStats: VolumeData['dataStats'] = { min: -1, max: 1, mean: 0, sigma: 0.1 }; export function createIsoValueParam(defaultValue: VolumeIsoValue, stats?: VolumeData['dataStats']) { @@ -43,12 +44,12 @@ export function createIsoValueParam(defaultValue: VolumeIsoValue, stats?: Volume 'absolute': PD.Converted( (v: VolumeIsoValue) => VolumeIsoValue.toAbsolute(v, VolumeData.One.dataStats).absoluteValue, (v: number) => VolumeIsoValue.absolute(v), - PD.Numeric(mean, { min, max, step: sigma / 100 }) + PD.Numeric(mean, { min, max, step: toPrecision(sigma / 100, 2) }) ), 'relative': PD.Converted( (v: VolumeIsoValue) => VolumeIsoValue.toRelative(v, VolumeData.One.dataStats).relativeValue, (v: number) => VolumeIsoValue.relative(v), - PD.Numeric(Math.min(1, relMax), { min: relMin, max: relMax, step: Math.round(((max - min) / sigma)) / 100 }) + PD.Numeric(Math.min(1, relMax), { min: relMin, max: relMax, step: toPrecision(Math.round(((max - min) / sigma)) / 100, 2) }) ) }, (v: VolumeIsoValue) => v.kind === 'absolute' ? 'absolute' : 'relative', diff --git a/src/mol-util/number.ts b/src/mol-util/number.ts index 58bcc2aef649da7119337be0373b00b12e1c6a69..d9c4adf3d5ef301c5d9d5a8d6c676fa6039b3a1d 100644 --- a/src/mol-util/number.ts +++ b/src/mol-util/number.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ /** @@ -52,4 +53,19 @@ export function isInteger(s: string) { s = s.trim() const n = parseInt(s, 10) return isNaN(n) ? false : n.toString() === s +} + +export function getPrecision(v: number) { + if (!isFinite(v)) return 0 + let e = 1 + let p = 0 + while (Math.round(v * e) / e !== v) { + e *= 10 + ++p + } + return p +} + +export function toPrecision(v: number, precision: number) { + return parseFloat(v.toPrecision(precision)) } \ No newline at end of file