molstar
Version:
A comprehensive macromolecular library.
195 lines • 9.15 kB
JavaScript
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { __assign, __awaiter, __generator } from "tslib";
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Image } from '../../mol-geo/geometry/image/image';
import { Grid, Volume } from '../../mol-model/volume';
import { VolumeVisual, VolumeRepresentation, VolumeRepresentationProvider } from './representation';
import { LocationIterator } from '../../mol-geo/util/location-iterator';
import { NullLocation } from '../../mol-model/location';
import { EmptyLoci } from '../../mol-model/loci';
import { Interval, SortedArray } from '../../mol-data/int';
import { transformPositionArray } from '../../mol-geo/util';
import { Color } from '../../mol-util/color';
import { ColorTheme } from '../../mol-theme/color';
import { encodeFloatRGBtoArray } from '../../mol-util/float-packing';
import { eachVolumeLoci } from './util';
export function createImage(ctx, volume, theme, props, image) {
return __awaiter(this, void 0, void 0, function () {
var dim, isoValue, _a, space, data, _b, min, max, isoVal, color, _c, r, g, b, _d, width, height, x, y, z, x0, y0, z0, nx, ny, nz, corners, imageArray, groupArray, i, iy, ix, iz, val, normVal, imageTexture, groupTexture, transform;
return __generator(this, function (_e) {
dim = props.dimension.name, isoValue = props.isoValue;
_a = volume.grid.cells, space = _a.space, data = _a.data;
_b = volume.grid.stats, min = _b.min, max = _b.max;
isoVal = Volume.IsoValue.toAbsolute(isoValue, volume.grid.stats).absoluteValue;
color = theme.color.color(NullLocation, false);
_c = Color.toRgbNormalized(color), r = _c[0], g = _c[1], b = _c[2];
_d = getSliceInfo(volume.grid, props), width = _d.width, height = _d.height, x = _d.x, y = _d.y, z = _d.z, x0 = _d.x0, y0 = _d.y0, z0 = _d.z0, nx = _d.nx, ny = _d.ny, nz = _d.nz;
corners = new Float32Array(dim === 'x' ? [x, 0, 0, x, y, 0, x, 0, z, x, y, z] :
dim === 'y' ? [0, y, 0, x, y, 0, 0, y, z, x, y, z] :
[0, 0, z, 0, y, z, x, 0, z, x, y, z]);
imageArray = new Uint8Array(width * height * 4);
groupArray = getPackedGroupArray(volume.grid, props);
i = 0;
for (iy = y0; iy < ny; ++iy) {
for (ix = x0; ix < nx; ++ix) {
for (iz = z0; iz < nz; ++iz) {
val = space.get(data, ix, iy, iz);
normVal = (val - min) / (max - min);
imageArray[i] = r * normVal * 2 * 255;
imageArray[i + 1] = g * normVal * 2 * 255;
imageArray[i + 2] = b * normVal * 2 * 255;
imageArray[i + 3] = val >= isoVal ? 255 : 0;
i += 4;
}
}
}
imageTexture = { width: width, height: height, array: imageArray, flipY: true };
groupTexture = { width: width, height: height, array: groupArray, flipY: true };
transform = Grid.getGridToCartesianTransform(volume.grid);
transformPositionArray(transform, corners, 0, 4);
return [2 /*return*/, Image.create(imageTexture, corners, groupTexture, image)];
});
});
}
function getSliceInfo(grid, props) {
var _a = props.dimension, dim = _a.name, index = _a.params;
var space = grid.cells.space;
var width, height;
var x, y, z;
var x0 = 0, y0 = 0, z0 = 0;
var _b = space.dimensions, nx = _b[0], ny = _b[1], nz = _b[2];
if (dim === 'x') {
x = index, y = ny - 1, z = nz - 1;
width = nz, height = ny;
x0 = x, nx = x0 + 1;
}
else if (dim === 'y') {
x = nx - 1, y = index, z = nz - 1;
width = nz, height = nx;
y0 = y, ny = y0 + 1;
}
else {
x = nx - 1, y = ny - 1, z = index;
width = nx, height = ny;
z0 = z, nz = z0 + 1;
}
return {
width: width,
height: height,
x: x,
y: y,
z: z,
x0: x0,
y0: y0,
z0: z0,
nx: nx,
ny: ny,
nz: nz
};
}
function getPackedGroupArray(grid, props) {
var space = grid.cells.space;
var _a = getSliceInfo(grid, props), width = _a.width, height = _a.height, x0 = _a.x0, y0 = _a.y0, z0 = _a.z0, nx = _a.nx, ny = _a.ny, nz = _a.nz;
var groupArray = new Uint8Array(width * height * 4);
var j = 0;
for (var iy = y0; iy < ny; ++iy) {
for (var ix = x0; ix < nx; ++ix) {
for (var iz = z0; iz < nz; ++iz) {
encodeFloatRGBtoArray(space.dataOffset(ix, iy, iz), groupArray, j);
j += 4;
}
}
}
return groupArray;
}
function getGroupArray(grid, props) {
var space = grid.cells.space;
var _a = getSliceInfo(grid, props), width = _a.width, height = _a.height, x0 = _a.x0, y0 = _a.y0, z0 = _a.z0, nx = _a.nx, ny = _a.ny, nz = _a.nz;
var groupArray = new Uint32Array(width * height);
var j = 0;
for (var iy = y0; iy < ny; ++iy) {
for (var ix = x0; ix < nx; ++ix) {
for (var iz = z0; iz < nz; ++iz) {
groupArray[j] = space.dataOffset(ix, iy, iz);
j += 1;
}
}
}
return groupArray;
}
function getLoci(volume, props) {
// TODO cache somehow?
var groupArray = getGroupArray(volume.grid, props);
return Volume.Cell.Loci(volume, SortedArray.ofUnsortedArray(groupArray));
}
function getSliceLoci(pickingId, volume, props, id) {
var objectId = pickingId.objectId, groupId = pickingId.groupId;
if (id === objectId) {
return Volume.Cell.Loci(volume, Interval.ofSingleton(groupId));
}
return EmptyLoci;
}
function eachSlice(loci, volume, props, apply) {
return eachVolumeLoci(loci, volume, undefined, apply);
}
//
export var SliceParams = __assign(__assign({}, Image.Params), { quality: __assign(__assign({}, Image.Params.quality), { isEssential: false }), dimension: PD.MappedStatic('x', {
x: PD.Numeric(0, { min: 0, max: 0, step: 1 }),
y: PD.Numeric(0, { min: 0, max: 0, step: 1 }),
z: PD.Numeric(0, { min: 0, max: 0, step: 1 }),
}, { isEssential: true }), isoValue: Volume.IsoValueParam });
export function getSliceParams(ctx, volume) {
var p = PD.clone(SliceParams);
var dim = volume.grid.cells.space.dimensions;
p.dimension = PD.MappedStatic('x', {
x: PD.Numeric(0, { min: 0, max: dim[0] - 1, step: 1 }),
y: PD.Numeric(0, { min: 0, max: dim[1] - 1, step: 1 }),
z: PD.Numeric(0, { min: 0, max: dim[2] - 1, step: 1 }),
}, { isEssential: true });
p.isoValue = Volume.createIsoValueParam(Volume.IsoValue.absolute(volume.grid.stats.min), volume.grid.stats);
return p;
}
export function SliceVisual(materialId) {
return VolumeVisual({
defaultProps: PD.getDefaultValues(SliceParams),
createGeometry: createImage,
createLocationIterator: function (volume) { return LocationIterator(volume.grid.cells.data.length, 1, 1, function () { return NullLocation; }); },
getLoci: getSliceLoci,
eachLocation: eachSlice,
setUpdateState: function (state, volume, newProps, currentProps, newTheme, currentTheme) {
state.createGeometry = (newProps.dimension.name !== currentProps.dimension.name ||
newProps.dimension.params !== currentProps.dimension.params ||
!Volume.IsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.grid.stats) ||
!ColorTheme.areEqual(newTheme.color, currentTheme.color));
},
geometryUtils: __assign(__assign({}, Image.Utils), { createRenderableState: function (props) {
var state = Image.Utils.createRenderableState(props);
updateRenderableState(state, props);
return state;
}, updateRenderableState: updateRenderableState })
}, materialId);
}
function updateRenderableState(state, props) {
Image.Utils.updateRenderableState(state, props);
state.opaque = false;
state.writeDepth = true;
}
export function SliceRepresentation(ctx, getParams) {
return VolumeRepresentation('Slice', ctx, getParams, SliceVisual, getLoci);
}
export var SliceRepresentationProvider = VolumeRepresentationProvider({
name: 'slice',
label: 'Slice',
description: 'Slice of volume rendered as image with interpolation.',
factory: SliceRepresentation,
getParams: getSliceParams,
defaultValues: PD.getDefaultValues(SliceParams),
defaultColorTheme: { name: 'uniform' },
defaultSizeTheme: { name: 'uniform' },
isApplicable: function (volume) { return !Volume.isEmpty(volume); }
});
//# sourceMappingURL=slice.js.map