UNPKG

molstar

Version:

A comprehensive macromolecular library.

195 lines 9.15 kB
/** * 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