From 918fceeaa87f5667d674f9442f52c19f405b01e2 Mon Sep 17 00:00:00 2001 From: Alexander Rose <alex.rose@rcsb.org> Date: Fri, 2 Nov 2018 17:46:05 -0700 Subject: [PATCH] volume repr refactoring --- src/apps/structure-info/volume.ts | 4 +- src/mol-repr/structure/complex-visual.ts | 5 +- src/mol-repr/structure/index.ts | 23 --- src/mol-repr/structure/units-visual.ts | 5 +- .../visual/carbohydrate-link-cylinder.ts | 2 +- .../visual/carbohydrate-symbol-mesh.ts | 3 +- .../visual/cross-link-restraint-cylinder.ts | 3 +- .../structure/visual/element-point.ts | 3 +- .../structure/visual/element-sphere.ts | 3 +- .../visual/gaussian-density-point.ts | 3 +- .../visual/gaussian-density-volume.ts | 3 +- .../structure/visual/gaussian-surface-mesh.ts | 3 +- .../visual/gaussian-surface-wireframe.ts | 3 +- .../visual/inter-unit-link-cylinder.ts | 3 +- .../visual/intra-unit-link-cylinder.ts | 3 +- .../visual/polymer-backbone-cylinder.ts | 3 +- .../structure/visual/polymer-gap-cylinder.ts | 3 +- .../structure/visual/polymer-trace-mesh.ts | 3 +- src/mol-repr/structure/visual/util/common.ts | 17 --- src/mol-repr/util.ts | 44 +++++- src/mol-repr/volume/index.ts | 131 +++++++++++++++++- src/mol-repr/volume/isosurface-mesh.ts | 105 ++++---------- 22 files changed, 228 insertions(+), 147 deletions(-) diff --git a/src/apps/structure-info/volume.ts b/src/apps/structure-info/volume.ts index cef34b843..3b7d8cc3f 100644 --- a/src/apps/structure-info/volume.ts +++ b/src/apps/structure-info/volume.ts @@ -15,7 +15,7 @@ import { DensityServer_Data_Database } from 'mol-io/reader/cif/schema/density-se import { Table } from 'mol-data/db'; import { StringBuilder } from 'mol-util'; import { Task } from 'mol-task'; -import { createVolumeSurface } from 'mol-repr/volume/isosurface-mesh'; +import { createVolumeIsosurface } from 'mol-repr/volume/isosurface-mesh'; require('util.promisify').shim(); const writeFileAsync = util.promisify(fs.writeFile); @@ -38,7 +38,7 @@ function print(data: Volume) { } async function doMesh(data: Volume, filename: string) { - const mesh = await Task.create('', ctx => createVolumeSurface(ctx, data.volume, VolumeIsoValue.calcAbsolute(data.volume.dataStats, 1.5))).run(); + const mesh = await Task.create('', ctx => createVolumeIsosurface(ctx, data.volume, { isoValueAbsolute: VolumeIsoValue.calcAbsolute(data.volume.dataStats, 1.5) } )).run(); console.log({ vc: mesh.vertexCount, tc: mesh.triangleCount }); // Export the mesh in OBJ format. diff --git a/src/mol-repr/structure/complex-visual.ts b/src/mol-repr/structure/complex-visual.ts index a07cc0ded..4e7acbf75 100644 --- a/src/mol-repr/structure/complex-visual.ts +++ b/src/mol-repr/structure/complex-visual.ts @@ -8,8 +8,8 @@ import { Structure } from 'mol-model/structure'; import { Visual } from '..'; import { MeshRenderObject, LinesRenderObject, PointsRenderObject, DirectVolumeRenderObject } from 'mol-gl/render-object'; import { RuntimeContext } from 'mol-task'; -import { createComplexMeshRenderObject, sizeChanged, colorChanged, UnitKind, UnitKindOptions } from './visual/util/common'; -import { StructureProps, VisualUpdateState, StructureMeshParams, StructureParams } from './index'; +import { createComplexMeshRenderObject, UnitKind, UnitKindOptions } from './visual/util/common'; +import { StructureProps, StructureMeshParams, StructureParams } from './index'; import { deepEqual, ValueCell } from 'mol-util'; import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci'; import { Interval } from 'mol-data/int'; @@ -22,6 +22,7 @@ import { PickingId } from 'mol-geo/geometry/picking'; import { createColors } from 'mol-geo/geometry/color-data'; import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; +import { VisualUpdateState, colorChanged, sizeChanged } from 'mol-repr/util'; export interface ComplexVisual<P extends StructureProps> extends Visual<Structure, P> { } diff --git a/src/mol-repr/structure/index.ts b/src/mol-repr/structure/index.ts index 800c07203..03a58d51a 100644 --- a/src/mol-repr/structure/index.ts +++ b/src/mol-repr/structure/index.ts @@ -55,29 +55,6 @@ export const StructureDirectVolumeParams = { export const DefaultStructureDirectVolumeProps = paramDefaultValues(StructureDirectVolumeParams) export type StructureDirectVolumeProps = typeof DefaultStructureDirectVolumeProps -export interface VisualUpdateState { - updateTransform: boolean - updateColor: boolean - updateSize: boolean - createGeometry: boolean -} -export namespace VisualUpdateState { - export function create(): VisualUpdateState { - return { - updateTransform: false, - updateColor: false, - updateSize: false, - createGeometry: false - } - } - export function reset(state: VisualUpdateState) { - state.updateTransform = false - state.updateColor = false - state.updateSize = false - state.createGeometry = false - } -} - export { ComplexRepresentation } from './complex-representation' export { UnitsRepresentation } from './units-representation' export { ComplexVisual } from './complex-visual' diff --git a/src/mol-repr/structure/units-visual.ts b/src/mol-repr/structure/units-visual.ts index b79db06aa..641d232f6 100644 --- a/src/mol-repr/structure/units-visual.ts +++ b/src/mol-repr/structure/units-visual.ts @@ -6,11 +6,11 @@ import { Unit, Structure } from 'mol-model/structure'; import { RepresentationProps, Visual } from '../'; -import { VisualUpdateState, StructureMeshParams, StructurePointsParams, StructureLinesParams, StructureDirectVolumeParams, StructureParams } from './index'; +import { StructureMeshParams, StructurePointsParams, StructureLinesParams, StructureDirectVolumeParams, StructureParams } from './index'; import { RuntimeContext } from 'mol-task'; import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci'; import { MeshRenderObject, PointsRenderObject, LinesRenderObject, DirectVolumeRenderObject } from 'mol-gl/render-object'; -import { createUnitsMeshRenderObject, createUnitsPointsRenderObject, createUnitsTransform, createUnitsLinesRenderObject, createUnitsDirectVolumeRenderObject, UnitKind, UnitKindOptions, includesUnitKind, colorChanged, sizeChanged } from './visual/util/common'; +import { createUnitsMeshRenderObject, createUnitsPointsRenderObject, createUnitsTransform, createUnitsLinesRenderObject, createUnitsDirectVolumeRenderObject, UnitKind, UnitKindOptions, includesUnitKind } from './visual/util/common'; import { deepEqual, ValueCell, UUID } from 'mol-util'; import { Interval } from 'mol-data/int'; import { MultiSelectParam, paramDefaultValues } from 'mol-util/parameter'; @@ -25,6 +25,7 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { Points } from 'mol-geo/geometry/points/points'; import { Lines } from 'mol-geo/geometry/lines/lines'; import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume'; +import { VisualUpdateState, colorChanged, sizeChanged } from 'mol-repr/util'; export type StructureGroup = { structure: Structure, group: Unit.SymmetryGroup } diff --git a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts index fd904a280..8babf03f7 100644 --- a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts +++ b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts @@ -17,9 +17,9 @@ import { BitFlags } from 'mol-util'; import { UnitsMeshParams } from '../units-visual'; import { SelectParam, NumberParam, paramDefaultValues } from 'mol-util/parameter'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; -import { VisualUpdateState } from '../index'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; +import { VisualUpdateState } from '../../util'; // TODO create seperate visual // for (let i = 0, il = carbohydrates.terminalLinks.length; i < il; ++i) { diff --git a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts index 2e760c9a5..806fbd4dd 100644 --- a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts +++ b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts @@ -19,7 +19,8 @@ import { getSaccharideShape, SaccharideShapes } from 'mol-model/structure/struct import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere'; import { ComplexMeshParams, ComplexMeshVisual } from '../complex-visual'; import { SelectParam, NumberParam, paramDefaultValues } from 'mol-util/parameter'; -import { ComplexVisual, VisualUpdateState } from '../index'; +import { ComplexVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; import { OrderedSet, Interval } from 'mol-data/int'; diff --git a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts index c84541454..e71655c2a 100644 --- a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts +++ b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts @@ -5,7 +5,8 @@ */ import { Link, Structure, StructureElement } from 'mol-model/structure'; -import { ComplexVisual, VisualUpdateState } from '../index'; +import { ComplexVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { RuntimeContext } from 'mol-task' import { LinkCylinderProps, createLinkCylinderMesh, LinkCylinderParams } from './util/link'; import { Vec3 } from 'mol-math/linear-algebra'; diff --git a/src/mol-repr/structure/visual/element-point.ts b/src/mol-repr/structure/visual/element-point.ts index 09abfc3aa..d770bb0af 100644 --- a/src/mol-repr/structure/visual/element-point.ts +++ b/src/mol-repr/structure/visual/element-point.ts @@ -6,7 +6,8 @@ import { Unit, Structure } from 'mol-model/structure'; import { RuntimeContext } from 'mol-task' -import { UnitsVisual, VisualUpdateState } from '../index'; +import { UnitsVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { getElementLoci, StructureElementIterator, markElement } from './util/element'; import { Vec3 } from 'mol-math/linear-algebra'; import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size'; diff --git a/src/mol-repr/structure/visual/element-sphere.ts b/src/mol-repr/structure/visual/element-sphere.ts index 8be9d0086..abb930830 100644 --- a/src/mol-repr/structure/visual/element-sphere.ts +++ b/src/mol-repr/structure/visual/element-sphere.ts @@ -5,7 +5,8 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { UnitsVisual, VisualUpdateState } from '../index'; +import { UnitsVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { createElementSphereMesh, markElement, getElementLoci, StructureElementIterator } from './util/element'; import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; import { NumberParam, paramDefaultValues, SelectParam } from 'mol-util/parameter'; diff --git a/src/mol-repr/structure/visual/gaussian-density-point.ts b/src/mol-repr/structure/visual/gaussian-density-point.ts index 807469abc..c4bfbc402 100644 --- a/src/mol-repr/structure/visual/gaussian-density-point.ts +++ b/src/mol-repr/structure/visual/gaussian-density-point.ts @@ -6,7 +6,8 @@ import { Unit, Structure } from 'mol-model/structure'; import { RuntimeContext } from 'mol-task' -import { UnitsVisual, VisualUpdateState } from '../index'; +import { UnitsVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { StructureElementIterator } from './util/element'; import { EmptyLoci } from 'mol-model/loci'; import { Vec3 } from 'mol-math/linear-algebra'; diff --git a/src/mol-repr/structure/visual/gaussian-density-volume.ts b/src/mol-repr/structure/visual/gaussian-density-volume.ts index 00697e797..4179da8c1 100644 --- a/src/mol-repr/structure/visual/gaussian-density-volume.ts +++ b/src/mol-repr/structure/visual/gaussian-density-volume.ts @@ -5,7 +5,8 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual, VisualUpdateState } from '../index'; +import { UnitsVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { RuntimeContext } from 'mol-task' import { UnitsDirectVolumeVisual, UnitsDirectVolumeParams } from '../units-visual'; import { StructureElementIterator, getElementLoci, markElement } from './util/element'; diff --git a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts index ccbfab83e..7982008eb 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts @@ -5,7 +5,8 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual, VisualUpdateState } from '../index'; +import { UnitsVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { RuntimeContext } from 'mol-task' import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; import { StructureElementIterator, getElementLoci, markElement } from './util/element'; diff --git a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts index 56cc5b6cb..beb212437 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts @@ -5,7 +5,8 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual, VisualUpdateState } from '../index'; +import { UnitsVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { RuntimeContext } from 'mol-task' import { UnitsLinesVisual, UnitsLinesParams } from '../units-visual'; import { StructureElementIterator, getElementLoci, markElement } from './util/element'; diff --git a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts index 2f4abc282..4f2c95708 100644 --- a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts @@ -5,7 +5,8 @@ */ import { Link, Structure, StructureElement } from 'mol-model/structure'; -import { ComplexVisual, VisualUpdateState } from '../index'; +import { ComplexVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { RuntimeContext } from 'mol-task' import { LinkCylinderProps, createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util/link'; import { Vec3 } from 'mol-math/linear-algebra'; diff --git a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts index bb3c4898e..97179ec27 100644 --- a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts @@ -6,7 +6,8 @@ */ import { Unit, Link, StructureElement, Structure } from 'mol-model/structure'; -import { UnitsVisual, VisualUpdateState } from '../index'; +import { UnitsVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { RuntimeContext } from 'mol-task' import { LinkCylinderProps, createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util/link'; import { Vec3 } from 'mol-math/linear-algebra'; diff --git a/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts b/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts index ba556c24c..b43c0dfc2 100644 --- a/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts +++ b/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts @@ -5,7 +5,8 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual, VisualUpdateState } from '../index'; +import { UnitsVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { RuntimeContext } from 'mol-task' import { PolymerBackboneIterator } from './util/polymer'; import { getElementLoci, markElement, StructureElementIterator } from './util/element'; diff --git a/src/mol-repr/structure/visual/polymer-gap-cylinder.ts b/src/mol-repr/structure/visual/polymer-gap-cylinder.ts index 1e295ee14..389b494a2 100644 --- a/src/mol-repr/structure/visual/polymer-gap-cylinder.ts +++ b/src/mol-repr/structure/visual/polymer-gap-cylinder.ts @@ -5,7 +5,8 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual, VisualUpdateState } from '../index'; +import { UnitsVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { RuntimeContext } from 'mol-task' import { PolymerGapIterator, PolymerGapLocationIterator, markPolymerGapElement, getPolymerGapElementLoci } from './util/polymer'; import { Vec3 } from 'mol-math/linear-algebra'; diff --git a/src/mol-repr/structure/visual/polymer-trace-mesh.ts b/src/mol-repr/structure/visual/polymer-trace-mesh.ts index 47d0ca82c..910f59b26 100644 --- a/src/mol-repr/structure/visual/polymer-trace-mesh.ts +++ b/src/mol-repr/structure/visual/polymer-trace-mesh.ts @@ -5,7 +5,8 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual, VisualUpdateState } from '../index'; +import { UnitsVisual } from '../index'; +import { VisualUpdateState } from '../../util'; import { RuntimeContext } from 'mol-task' import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement } from './util/polymer'; import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types'; diff --git a/src/mol-repr/structure/visual/util/common.ts b/src/mol-repr/structure/visual/util/common.ts index 56e9f0e8e..33f226f22 100644 --- a/src/mol-repr/structure/visual/util/common.ts +++ b/src/mol-repr/structure/visual/util/common.ts @@ -9,8 +9,6 @@ import { StructureProps } from '../../index'; import { createMeshRenderObject, createPointsRenderObject, createLinesRenderObject, createDirectVolumeRenderObject } from 'mol-gl/render-object'; import { RuntimeContext } from 'mol-task'; import { Mat4 } from 'mol-math/linear-algebra'; -import { SizeProps } from 'mol-geo/geometry/size-data'; -import { ColorProps } from 'mol-geo/geometry/color-data'; import { TransformData, createTransform, createIdentityTransform } from 'mol-geo/geometry/transform-data'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { LocationIterator } from 'mol-geo/util/location-iterator'; @@ -47,21 +45,6 @@ export function includesUnitKind(unitKinds: UnitKind[], unit: Unit) { return false } -export function sizeChanged(oldProps: SizeProps, newProps: SizeProps) { - return ( - oldProps.sizeTheme !== newProps.sizeTheme || - oldProps.sizeValue !== newProps.sizeValue || - oldProps.sizeFactor !== newProps.sizeFactor - ) -} - -export function colorChanged(oldProps: ColorProps, newProps: ColorProps) { - return ( - oldProps.colorTheme !== newProps.colorTheme || - oldProps.colorValue !== newProps.colorValue - ) -} - // mesh type StructureMeshProps = Mesh.Props & StructureProps diff --git a/src/mol-repr/util.ts b/src/mol-repr/util.ts index e227c24f8..792e9ff05 100644 --- a/src/mol-repr/util.ts +++ b/src/mol-repr/util.ts @@ -6,7 +6,49 @@ import { defaults } from 'mol-util'; import { Structure } from 'mol-model/structure'; -import { VisualQuality } from '../mol-geo/geometry/geometry'; +import { VisualQuality } from 'mol-geo/geometry/geometry'; +import { SizeProps } from 'mol-geo/geometry/size-data'; +import { ColorProps } from 'mol-geo/geometry/color-data'; + +export interface VisualUpdateState { + updateTransform: boolean + updateColor: boolean + updateSize: boolean + createGeometry: boolean +} +export namespace VisualUpdateState { + export function create(): VisualUpdateState { + return { + updateTransform: false, + updateColor: false, + updateSize: false, + createGeometry: false + } + } + export function reset(state: VisualUpdateState) { + state.updateTransform = false + state.updateColor = false + state.updateSize = false + state.createGeometry = false + } +} + +export function sizeChanged(oldProps: SizeProps, newProps: SizeProps) { + return ( + oldProps.sizeTheme !== newProps.sizeTheme || + oldProps.sizeValue !== newProps.sizeValue || + oldProps.sizeFactor !== newProps.sizeFactor + ) +} + +export function colorChanged(oldProps: ColorProps, newProps: ColorProps) { + return ( + oldProps.colorTheme !== newProps.colorTheme || + oldProps.colorValue !== newProps.colorValue + ) +} + +// export interface QualityProps { quality: VisualQuality diff --git a/src/mol-repr/volume/index.ts b/src/mol-repr/volume/index.ts index 16192970f..49f6a31cb 100644 --- a/src/mol-repr/volume/index.ts +++ b/src/mol-repr/volume/index.ts @@ -4,21 +4,140 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Task } from 'mol-task' +import { Task, RuntimeContext } from 'mol-task' import { RepresentationProps, Representation, Visual } from '..'; -import { VolumeData } from 'mol-model/volume'; -import { Loci, EmptyLoci } from 'mol-model/loci'; -import { paramDefaultValues } from 'mol-util/parameter'; -import { Geometry } from 'mol-geo/geometry/geometry'; +import { VolumeData, VolumeIsoValue } from 'mol-model/volume'; +import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci'; +import { paramDefaultValues, RangeParam } from 'mol-util/parameter'; +import { Geometry, updateRenderableState } from 'mol-geo/geometry/geometry'; import { PickingId } from 'mol-geo/geometry/picking'; -import { MarkerAction } from 'mol-geo/geometry/marker-data'; +import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data'; +import { DirectVolumeRenderObject, PointsRenderObject, LinesRenderObject, MeshRenderObject } from 'mol-gl/render-object'; +import { Interval } from 'mol-data/int'; +import { RenderableValues } from 'mol-gl/renderable/schema'; +import { LocationIterator } from 'mol-geo/util/location-iterator'; +import { NullLocation } from 'mol-model/location'; +import { VisualUpdateState } from 'mol-repr/util'; +import { ValueCell } from 'mol-util'; export interface VolumeVisual<P extends RepresentationProps = {}> extends Visual<VolumeData, P> { } +type VolumeRenderObject = MeshRenderObject | LinesRenderObject | PointsRenderObject | DirectVolumeRenderObject + +interface VolumeVisualBuilder<P extends VolumeProps, G extends Geometry> { + defaultProps: P + createGeometry(ctx: RuntimeContext, volumeData: VolumeData, props: P, geometry?: G): Promise<G> + getLoci(pickingId: PickingId, id: number): Loci + mark(loci: Loci, apply: (interval: Interval) => boolean): boolean + setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P): void +} + +interface VolumeVisualGeometryBuilder<P extends VolumeProps, G extends Geometry> extends VolumeVisualBuilder<P, G> { + createRenderObject(ctx: RuntimeContext, geometry: G, locationIt: LocationIterator, currentProps: P): Promise<VolumeRenderObject> + updateValues(values: RenderableValues, newProps: P): void +} + +export function VolumeVisual<P extends VolumeProps>(builder: VolumeVisualGeometryBuilder<P, Geometry>) { + const { defaultProps, createGeometry, getLoci, mark, setUpdateState } = builder + const { createRenderObject, updateValues } = builder + const updateState = VisualUpdateState.create() + + let currentProps: P + let renderObject: VolumeRenderObject | undefined + let currentVolume: VolumeData + let geometry: Geometry + let locationIt: LocationIterator + + async function create(ctx: RuntimeContext, volume: VolumeData, props: Partial<VolumeProps> = {}) { + currentProps = Object.assign({}, defaultProps, props) + if (props.isoValueRelative) { + currentProps.isoValueAbsolute = VolumeIsoValue.calcAbsolute(currentVolume.dataStats, props.isoValueRelative) + console.log('create props.isoValueRelative', props.isoValueRelative, currentProps.isoValueAbsolute, currentVolume.dataStats) + } + + geometry = await createGeometry(ctx, volume, currentProps, geometry) + locationIt = LocationIterator(1, 1, () => NullLocation) + renderObject = await createRenderObject(ctx, geometry, locationIt, currentProps) + } + + async function update(ctx: RuntimeContext, props: Partial<VolumeProps> = {}) { + if (!renderObject) return + const newProps = Object.assign({}, currentProps, props) + + if (props.isoValueRelative) { + newProps.isoValueAbsolute = VolumeIsoValue.calcAbsolute(currentVolume.dataStats, props.isoValueRelative) + console.log('update props.isoValueRelative', props.isoValueRelative, newProps.isoValueAbsolute, currentVolume.dataStats) + } + + VisualUpdateState.reset(updateState) + setUpdateState(updateState, newProps, currentProps) + + if (updateState.createGeometry) { + geometry = await createGeometry(ctx, currentVolume, currentProps, geometry) + ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(geometry)) + } + + updateValues(renderObject.values, newProps) + updateRenderableState(renderObject.state, newProps) + + currentProps = newProps + } + + return { + get renderObject () { return renderObject }, + async createOrUpdate(ctx: RuntimeContext, props: Partial<VolumeProps> = {}, volume?: VolumeData) { + if (!volume && !currentVolume) { + throw new Error('missing volume') + } else if (volume && (!currentVolume || !renderObject)) { + currentVolume = volume + await create(ctx, volume, props) + } else if (volume && volume !== currentVolume) { + currentVolume = volume + await create(ctx, volume, props) + } else { + await update(ctx, props) + } + + currentProps = Object.assign({}, defaultProps, props) + }, + getLoci(pickingId: PickingId) { + return renderObject ? getLoci(pickingId, renderObject.id) : EmptyLoci + }, + mark(loci: Loci, action: MarkerAction) { + if (!renderObject) return false + const { tMarker } = renderObject.values + const { groupCount, instanceCount } = locationIt + + function apply(interval: Interval) { + const start = Interval.start(interval) + const end = Interval.end(interval) + return applyMarkerAction(tMarker.ref.value.array, start, end, action) + } + + let changed = false + if (isEveryLoci(loci)) { + changed = apply(Interval.ofBounds(0, groupCount * instanceCount)) + } else { + changed = mark(loci, apply) + } + if (changed) { + ValueCell.update(tMarker, tMarker.ref.value) + } + return changed + }, + destroy() { + // TODO + renderObject = undefined + } + } +} + export interface VolumeRepresentation<P extends RepresentationProps = {}> extends Representation<VolumeData, P> { } export const VolumeParams = { ...Geometry.Params, + isoValueAbsolute: RangeParam('Iso Value Absolute', '', 0.22, -1, 1, 0.01), + isoValueRelative: RangeParam('Iso Value Relative', '', 2, -10, 10, 0.1), } export const DefaultVolumeProps = paramDefaultValues(VolumeParams) export type VolumeProps = typeof DefaultVolumeProps diff --git a/src/mol-repr/volume/isosurface-mesh.ts b/src/mol-repr/volume/isosurface-mesh.ts index 152cb3a8b..0dd1b600d 100644 --- a/src/mol-repr/volume/isosurface-mesh.ts +++ b/src/mol-repr/volume/isosurface-mesh.ts @@ -5,27 +5,30 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { VolumeData, VolumeIsoValue } from 'mol-model/volume' +import { VolumeData } from 'mol-model/volume' import { RuntimeContext } from 'mol-task' import { VolumeVisual, VolumeRepresentation } from './index'; -import { createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object'; +import { createMeshRenderObject } from 'mol-gl/render-object'; import { Loci, EmptyLoci } from 'mol-model/loci'; -import { NullLocation } from 'mol-model/location'; import { paramDefaultValues, RangeParam } from 'mol-util/parameter'; -import { ValueCell } from 'mol-util'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { computeMarchingCubesMesh } from 'mol-geo/util/marching-cubes/algorithm'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { createIdentityTransform } from 'mol-geo/geometry/transform-data'; -import { createRenderableState, updateRenderableState } from 'mol-geo/geometry/geometry'; +import { createRenderableState } from 'mol-geo/geometry/geometry'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; +import { VisualUpdateState } from 'mol-repr/util'; -export async function createVolumeSurface(ctx: RuntimeContext, volume: VolumeData, isoValueAbsolute: number, mesh?: Mesh) { +interface VolumeIsosurfaceProps { + isoValueAbsolute: number +} + +export async function createVolumeIsosurface(ctx: RuntimeContext, volume: VolumeData, props: VolumeIsosurfaceProps, mesh?: Mesh) { ctx.update({ message: 'Marching cubes...' }); const surface = await computeMarchingCubesMesh({ - isoLevel: isoValueAbsolute, + isoLevel: props.isoValueAbsolute, scalarField: volume.data }, mesh).runAsChild(ctx); @@ -45,81 +48,23 @@ export const IsosurfaceParams = { export const DefaultIsosurfaceProps = paramDefaultValues(IsosurfaceParams) export type IsosurfaceProps = typeof DefaultIsosurfaceProps -export function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { - let currentProps = DefaultIsosurfaceProps - let renderObject: MeshRenderObject - let currentVolume: VolumeData - let mesh: Mesh - - async function create(ctx: RuntimeContext, volume: VolumeData, props: Partial<IsosurfaceProps> = {}) { - currentProps = { ...DefaultIsosurfaceProps, ...props } - if (props.isoValueRelative) { - currentProps.isoValueAbsolute = VolumeIsoValue.calcAbsolute(currentVolume.dataStats, props.isoValueRelative) - console.log('create props.isoValueRelative', props.isoValueRelative, currentProps.isoValueAbsolute, currentVolume.dataStats) - } - - mesh = await createVolumeSurface(ctx, volume, currentProps.isoValueAbsolute) - - const locationIt = LocationIterator(1, 1, () => NullLocation) - const transform = createIdentityTransform() - - const values = await Mesh.createValues(ctx, mesh, transform, locationIt, currentProps) - const state = createRenderableState(currentProps) - - renderObject = createMeshRenderObject(values, state) - } - - async function update(ctx: RuntimeContext, props: Partial<IsosurfaceProps> = {}) { - const newProps = { ...currentProps, ...props } - if (props.isoValueRelative) { - newProps.isoValueAbsolute = VolumeIsoValue.calcAbsolute(currentVolume.dataStats, props.isoValueRelative) - console.log('update props.isoValueRelative', props.isoValueRelative, newProps.isoValueAbsolute, currentVolume.dataStats) - } - - let createMesh = false - - if (newProps.isoValueAbsolute !== currentProps.isoValueAbsolute) createMesh = true - - if (createMesh) { - mesh = await createVolumeSurface(ctx, currentVolume, newProps.isoValueAbsolute, mesh) - ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3) - } - - Mesh.updateValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) - - currentProps = newProps - } - - return { - get renderObject () { return renderObject }, - async createOrUpdate(ctx: RuntimeContext, props: Partial<IsosurfaceProps> = {}, volume?: VolumeData) { - if (!volume && !currentVolume) { - throw new Error('missing volume') - } else if (volume && (!currentVolume || !renderObject)) { - currentVolume = volume - await create(ctx, volume, props) - } else if (volume && volume !== currentVolume) { - currentVolume = volume - await create(ctx, volume, props) - } else { - await update(ctx, props) - } - - currentProps = { ...DefaultIsosurfaceProps, ...props } - }, - getLoci(pickingId: PickingId) { - // TODO - return EmptyLoci +export function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { + return VolumeVisual<IsosurfaceProps>({ + defaultProps: DefaultIsosurfaceProps, + createGeometry: createVolumeIsosurface, + getLoci: () => EmptyLoci, + mark: () => false, + setUpdateState: (state: VisualUpdateState, newProps: IsosurfaceProps, currentProps: IsosurfaceProps) => { + if (newProps.isoValueAbsolute !== currentProps.isoValueAbsolute) state.createGeometry = true }, - mark(loci: Loci, action: MarkerAction) { - // TODO - return false + createRenderObject: async (ctx: RuntimeContext, geometry: Mesh, locationIt: LocationIterator, props: IsosurfaceProps) => { + const transform = createIdentityTransform() + const values = await Mesh.createValues(ctx, geometry, transform, locationIt, props) + const state = createRenderableState(props) + return createMeshRenderObject(values, state) }, - destroy() { - // TODO - } - } + updateValues: Mesh.updateValues + }) } export function IsosurfaceRepresentation(): VolumeRepresentation<IsosurfaceProps> { -- GitLab