|
@@ -6,7 +6,7 @@
|
|
|
*/
|
|
|
|
|
|
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
|
|
-import { VolumeData, VolumeIsoValue } from '../../mol-model/volume';
|
|
|
+import { Grid, Volume } from '../../mol-model/volume';
|
|
|
import { VisualContext } from '../visual';
|
|
|
import { Theme, ThemeRegistryContext } from '../../mol-theme/theme';
|
|
|
import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
|
|
@@ -18,15 +18,14 @@ import { VisualUpdateState } from '../util';
|
|
|
import { Lines } from '../../mol-geo/geometry/lines/lines';
|
|
|
import { RepresentationContext, RepresentationParamsGetter, Representation } from '../representation';
|
|
|
import { toPrecision } from '../../mol-util/number';
|
|
|
-import { Volume } from '../../mol-model/volume/volume';
|
|
|
import { PickingId } from '../../mol-geo/geometry/picking';
|
|
|
import { EmptyLoci, Loci } from '../../mol-model/loci';
|
|
|
import { Interval, OrderedSet } from '../../mol-data/int';
|
|
|
import { Tensor } from '../../mol-math/linear-algebra';
|
|
|
import { fillSerial } from '../../mol-util/array';
|
|
|
|
|
|
-const defaultStats: VolumeData['dataStats'] = { min: -1, max: 1, mean: 0, sigma: 0.1 };
|
|
|
-export function createIsoValueParam(defaultValue: VolumeIsoValue, stats?: VolumeData['dataStats']) {
|
|
|
+const defaultStats: Grid['stats'] = { min: -1, max: 1, mean: 0, sigma: 0.1 };
|
|
|
+export function createIsoValueParam(defaultValue: Volume.IsoValue, stats?: Grid['stats']) {
|
|
|
const sts = stats || defaultStats;
|
|
|
const { min, max, mean, sigma } = sts;
|
|
|
|
|
@@ -36,34 +35,34 @@ export function createIsoValueParam(defaultValue: VolumeIsoValue, stats?: Volume
|
|
|
|
|
|
let def = defaultValue;
|
|
|
if (defaultValue.kind === 'absolute') {
|
|
|
- if (defaultValue.absoluteValue < min) def = VolumeIsoValue.absolute(min);
|
|
|
- else if (defaultValue.absoluteValue > max) def = VolumeIsoValue.absolute(max);
|
|
|
+ if (defaultValue.absoluteValue < min) def = Volume.IsoValue.absolute(min);
|
|
|
+ else if (defaultValue.absoluteValue > max) def = Volume.IsoValue.absolute(max);
|
|
|
} else {
|
|
|
- if (defaultValue.relativeValue < relMin) def = VolumeIsoValue.relative(relMin);
|
|
|
- else if (defaultValue.relativeValue > relMax) def = VolumeIsoValue.relative(relMax);
|
|
|
+ if (defaultValue.relativeValue < relMin) def = Volume.IsoValue.relative(relMin);
|
|
|
+ else if (defaultValue.relativeValue > relMax) def = Volume.IsoValue.relative(relMax);
|
|
|
}
|
|
|
|
|
|
return PD.Conditioned(
|
|
|
def,
|
|
|
{
|
|
|
'absolute': PD.Converted(
|
|
|
- (v: VolumeIsoValue) => VolumeIsoValue.toAbsolute(v, VolumeData.One.dataStats).absoluteValue,
|
|
|
- (v: number) => VolumeIsoValue.absolute(v),
|
|
|
+ (v: Volume.IsoValue) => Volume.IsoValue.toAbsolute(v, Grid.One.stats).absoluteValue,
|
|
|
+ (v: number) => Volume.IsoValue.absolute(v),
|
|
|
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),
|
|
|
+ (v: Volume.IsoValue) => Volume.IsoValue.toRelative(v, Grid.One.stats).relativeValue,
|
|
|
+ (v: number) => Volume.IsoValue.relative(v),
|
|
|
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',
|
|
|
- (v: VolumeIsoValue, c: 'absolute' | 'relative') => c === 'absolute' ? VolumeIsoValue.toAbsolute(v, sts) : VolumeIsoValue.toRelative(v, sts),
|
|
|
+ (v: Volume.IsoValue) => v.kind === 'absolute' ? 'absolute' : 'relative',
|
|
|
+ (v: Volume.IsoValue, c: 'absolute' | 'relative') => c === 'absolute' ? Volume.IsoValue.toAbsolute(v, sts) : Volume.IsoValue.toRelative(v, sts),
|
|
|
{ isEssential: true }
|
|
|
);
|
|
|
}
|
|
|
|
|
|
-export const IsoValueParam = createIsoValueParam(VolumeIsoValue.relative(2));
|
|
|
+export const IsoValueParam = createIsoValueParam(Volume.IsoValue.relative(2));
|
|
|
type IsoValueParam = typeof IsoValueParam
|
|
|
|
|
|
export const VolumeIsosurfaceParams = {
|
|
@@ -72,11 +71,11 @@ export const VolumeIsosurfaceParams = {
|
|
|
export type VolumeIsosurfaceParams = typeof VolumeIsosurfaceParams
|
|
|
export type VolumeIsosurfaceProps = PD.Values<VolumeIsosurfaceParams>
|
|
|
|
|
|
-function getLoci(volume: VolumeData, props: VolumeIsosurfaceProps) {
|
|
|
+function getLoci(volume: Volume, props: VolumeIsosurfaceProps) {
|
|
|
return Volume.Isosurface.Loci(volume, props.isoValue);
|
|
|
}
|
|
|
|
|
|
-function getIsosurfaceLoci(pickingId: PickingId, volume: VolumeData, props: VolumeIsosurfaceProps, id: number) {
|
|
|
+function getIsosurfaceLoci(pickingId: PickingId, volume: Volume, props: VolumeIsosurfaceProps, id: number) {
|
|
|
const { objectId, groupId } = pickingId;
|
|
|
if (id === objectId) {
|
|
|
return Volume.Cell.Loci(volume, Interval.ofSingleton(groupId as Volume.CellIndex));
|
|
@@ -84,17 +83,17 @@ function getIsosurfaceLoci(pickingId: PickingId, volume: VolumeData, props: Volu
|
|
|
return EmptyLoci;
|
|
|
}
|
|
|
|
|
|
-function eachIsosurface(loci: Loci, volume: VolumeData, props: VolumeIsosurfaceProps, apply: (interval: Interval) => boolean) {
|
|
|
+function eachIsosurface(loci: Loci, volume: Volume, props: VolumeIsosurfaceProps, apply: (interval: Interval) => boolean) {
|
|
|
let changed = false;
|
|
|
if (Volume.isLoci(loci)) {
|
|
|
- if (!VolumeData.areEquivalent(loci.volume, volume)) return false;
|
|
|
- if (apply(Interval.ofLength(volume.data.data.length))) changed = true;
|
|
|
+ if (!Volume.areEquivalent(loci.volume, volume)) return false;
|
|
|
+ if (apply(Interval.ofLength(volume.grid.cells.data.length))) changed = true;
|
|
|
} else if (Volume.Isosurface.isLoci(loci)) {
|
|
|
- if (!VolumeData.areEquivalent(loci.volume, volume)) return false;
|
|
|
- if (!VolumeIsoValue.areSame(loci.isoValue, props.isoValue, volume.dataStats)) return false;
|
|
|
- if (apply(Interval.ofLength(volume.data.data.length))) changed = true;
|
|
|
+ if (!Volume.areEquivalent(loci.volume, volume)) return false;
|
|
|
+ if (!Volume.IsoValue.areSame(loci.isoValue, props.isoValue, volume.grid.stats)) return false;
|
|
|
+ if (apply(Interval.ofLength(volume.grid.cells.data.length))) changed = true;
|
|
|
} else if (Volume.Cell.isLoci(loci)) {
|
|
|
- if (!VolumeData.areEquivalent(loci.volume, volume)) return false;
|
|
|
+ if (!Volume.areEquivalent(loci.volume, volume)) return false;
|
|
|
if (Interval.is(loci.indices)) {
|
|
|
if (apply(loci.indices)) changed = true;
|
|
|
} else {
|
|
@@ -108,18 +107,18 @@ function eachIsosurface(loci: Loci, volume: VolumeData, props: VolumeIsosurfaceP
|
|
|
|
|
|
//
|
|
|
|
|
|
-export async function createVolumeIsosurfaceMesh(ctx: VisualContext, volume: VolumeData, theme: Theme, props: VolumeIsosurfaceProps, mesh?: Mesh) {
|
|
|
+export async function createVolumeIsosurfaceMesh(ctx: VisualContext, volume: Volume, theme: Theme, props: VolumeIsosurfaceProps, mesh?: Mesh) {
|
|
|
ctx.runtime.update({ message: 'Marching cubes...' });
|
|
|
|
|
|
- const ids = fillSerial(new Int32Array(volume.data.data.length));
|
|
|
+ const ids = fillSerial(new Int32Array(volume.grid.cells.data.length));
|
|
|
|
|
|
const surface = await computeMarchingCubesMesh({
|
|
|
- isoLevel: VolumeIsoValue.toAbsolute(props.isoValue, volume.dataStats).absoluteValue,
|
|
|
- scalarField: volume.data,
|
|
|
- idField: Tensor.create(volume.data.space, Tensor.Data1(ids))
|
|
|
+ isoLevel: Volume.IsoValue.toAbsolute(props.isoValue, volume.grid.stats).absoluteValue,
|
|
|
+ scalarField: volume.grid.cells,
|
|
|
+ idField: Tensor.create(volume.grid.cells.space, Tensor.Data1(ids))
|
|
|
}, mesh).runAsChild(ctx.runtime);
|
|
|
|
|
|
- const transform = VolumeData.getGridToCartesianTransform(volume);
|
|
|
+ const transform = Grid.getGridToCartesianTransform(volume.grid);
|
|
|
ctx.runtime.update({ message: 'Transforming mesh...' });
|
|
|
Mesh.transform(surface, transform);
|
|
|
return surface;
|
|
@@ -136,11 +135,11 @@ export function IsosurfaceMeshVisual(materialId: number): VolumeVisual<Isosurfac
|
|
|
return VolumeVisual<Mesh, IsosurfaceMeshParams>({
|
|
|
defaultProps: PD.getDefaultValues(IsosurfaceMeshParams),
|
|
|
createGeometry: createVolumeIsosurfaceMesh,
|
|
|
- createLocationIterator: (volume: VolumeData) => LocationIterator(volume.data.data.length, 1, () => NullLocation),
|
|
|
+ createLocationIterator: (volume: Volume) => LocationIterator(volume.grid.cells.data.length, 1, () => NullLocation),
|
|
|
getLoci: getIsosurfaceLoci,
|
|
|
eachLocation: eachIsosurface,
|
|
|
- setUpdateState: (state: VisualUpdateState, volume: VolumeData, newProps: PD.Values<IsosurfaceMeshParams>, currentProps: PD.Values<IsosurfaceMeshParams>) => {
|
|
|
- if (!VolumeIsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.dataStats)) state.createGeometry = true;
|
|
|
+ setUpdateState: (state: VisualUpdateState, volume: Volume, newProps: PD.Values<IsosurfaceMeshParams>, currentProps: PD.Values<IsosurfaceMeshParams>) => {
|
|
|
+ if (!Volume.IsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.grid.stats)) state.createGeometry = true;
|
|
|
},
|
|
|
geometryUtils: Mesh.Utils
|
|
|
}, materialId);
|
|
@@ -148,18 +147,18 @@ export function IsosurfaceMeshVisual(materialId: number): VolumeVisual<Isosurfac
|
|
|
|
|
|
//
|
|
|
|
|
|
-export async function createVolumeIsosurfaceWireframe(ctx: VisualContext, volume: VolumeData, theme: Theme, props: VolumeIsosurfaceProps, lines?: Lines) {
|
|
|
+export async function createVolumeIsosurfaceWireframe(ctx: VisualContext, volume: Volume, theme: Theme, props: VolumeIsosurfaceProps, lines?: Lines) {
|
|
|
ctx.runtime.update({ message: 'Marching cubes...' });
|
|
|
|
|
|
- const ids = fillSerial(new Int32Array(volume.data.data.length));
|
|
|
+ const ids = fillSerial(new Int32Array(volume.grid.cells.data.length));
|
|
|
|
|
|
const wireframe = await computeMarchingCubesLines({
|
|
|
- isoLevel: VolumeIsoValue.toAbsolute(props.isoValue, volume.dataStats).absoluteValue,
|
|
|
- scalarField: volume.data,
|
|
|
- idField: Tensor.create(volume.data.space, Tensor.Data1(ids))
|
|
|
+ isoLevel: Volume.IsoValue.toAbsolute(props.isoValue, volume.grid.stats).absoluteValue,
|
|
|
+ scalarField: volume.grid.cells,
|
|
|
+ idField: Tensor.create(volume.grid.cells.space, Tensor.Data1(ids))
|
|
|
}, lines).runAsChild(ctx.runtime);
|
|
|
|
|
|
- const transform = VolumeData.getGridToCartesianTransform(volume);
|
|
|
+ const transform = Grid.getGridToCartesianTransform(volume.grid);
|
|
|
Lines.transform(wireframe, transform);
|
|
|
|
|
|
return wireframe;
|
|
@@ -177,11 +176,11 @@ export function IsosurfaceWireframeVisual(materialId: number): VolumeVisual<Isos
|
|
|
return VolumeVisual<Lines, IsosurfaceWireframeParams>({
|
|
|
defaultProps: PD.getDefaultValues(IsosurfaceWireframeParams),
|
|
|
createGeometry: createVolumeIsosurfaceWireframe,
|
|
|
- createLocationIterator: (volume: VolumeData) => LocationIterator(volume.data.data.length, 1, () => NullLocation),
|
|
|
+ createLocationIterator: (volume: Volume) => LocationIterator(volume.grid.cells.data.length, 1, () => NullLocation),
|
|
|
getLoci: getIsosurfaceLoci,
|
|
|
eachLocation: eachIsosurface,
|
|
|
- setUpdateState: (state: VisualUpdateState, volume: VolumeData, newProps: PD.Values<IsosurfaceWireframeParams>, currentProps: PD.Values<IsosurfaceWireframeParams>) => {
|
|
|
- if (!VolumeIsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.dataStats)) state.createGeometry = true;
|
|
|
+ setUpdateState: (state: VisualUpdateState, volume: Volume, newProps: PD.Values<IsosurfaceWireframeParams>, currentProps: PD.Values<IsosurfaceWireframeParams>) => {
|
|
|
+ if (!Volume.IsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.grid.stats)) state.createGeometry = true;
|
|
|
},
|
|
|
geometryUtils: Lines.Utils
|
|
|
}, materialId);
|
|
@@ -190,8 +189,8 @@ export function IsosurfaceWireframeVisual(materialId: number): VolumeVisual<Isos
|
|
|
//
|
|
|
|
|
|
const IsosurfaceVisuals = {
|
|
|
- 'solid': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<VolumeData, IsosurfaceMeshParams>) => VolumeRepresentation('Isosurface mesh', ctx, getParams, IsosurfaceMeshVisual, getLoci),
|
|
|
- 'wireframe': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<VolumeData, IsosurfaceWireframeParams>) => VolumeRepresentation('Isosurface wireframe', ctx, getParams, IsosurfaceWireframeVisual, getLoci),
|
|
|
+ 'solid': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, IsosurfaceMeshParams>) => VolumeRepresentation('Isosurface mesh', ctx, getParams, IsosurfaceMeshVisual, getLoci),
|
|
|
+ 'wireframe': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, IsosurfaceWireframeParams>) => VolumeRepresentation('Isosurface wireframe', ctx, getParams, IsosurfaceWireframeVisual, getLoci),
|
|
|
};
|
|
|
|
|
|
export const IsosurfaceParams = {
|
|
@@ -200,15 +199,15 @@ export const IsosurfaceParams = {
|
|
|
visuals: PD.MultiSelect(['solid'], PD.objectToOptions(IsosurfaceVisuals)),
|
|
|
};
|
|
|
export type IsosurfaceParams = typeof IsosurfaceParams
|
|
|
-export function getIsosurfaceParams(ctx: ThemeRegistryContext, volume: VolumeData) {
|
|
|
+export function getIsosurfaceParams(ctx: ThemeRegistryContext, volume: Volume) {
|
|
|
const p = PD.clone(IsosurfaceParams);
|
|
|
- p.isoValue = createIsoValueParam(VolumeIsoValue.relative(2), volume.dataStats);
|
|
|
+ p.isoValue = createIsoValueParam(Volume.IsoValue.relative(2), volume.grid.stats);
|
|
|
return p;
|
|
|
}
|
|
|
|
|
|
export type IsosurfaceRepresentation = VolumeRepresentation<IsosurfaceParams>
|
|
|
-export function IsosurfaceRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<VolumeData, IsosurfaceParams>): IsosurfaceRepresentation {
|
|
|
- return Representation.createMulti('Isosurface', ctx, getParams, Representation.StateBuilder, IsosurfaceVisuals as unknown as Representation.Def<VolumeData, IsosurfaceParams>);
|
|
|
+export function IsosurfaceRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, IsosurfaceParams>): IsosurfaceRepresentation {
|
|
|
+ return Representation.createMulti('Isosurface', ctx, getParams, Representation.StateBuilder, IsosurfaceVisuals as unknown as Representation.Def<Volume, IsosurfaceParams>);
|
|
|
}
|
|
|
|
|
|
export const IsosurfaceRepresentationProvider = VolumeRepresentationProvider({
|
|
@@ -220,5 +219,5 @@ export const IsosurfaceRepresentationProvider = VolumeRepresentationProvider({
|
|
|
defaultValues: PD.getDefaultValues(IsosurfaceParams),
|
|
|
defaultColorTheme: { name: 'uniform' },
|
|
|
defaultSizeTheme: { name: 'uniform' },
|
|
|
- isApplicable: (volume: VolumeData) => volume.data.data.length > 0
|
|
|
+ isApplicable: (volume: Volume) => !Volume.isEmpty(volume)
|
|
|
});
|