UNPKG

molstar

Version:

A comprehensive macromolecular library.

257 lines 16.1 kB
"use strict"; /** * Copyright (c) 2018-2021 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> */ Object.defineProperty(exports, "__esModule", { value: true }); exports.IsosurfaceRepresentationProvider = exports.IsosurfaceRepresentation = exports.getIsosurfaceParams = exports.IsosurfaceParams = exports.IsosurfaceWireframeVisual = exports.IsosurfaceWireframeParams = exports.createVolumeIsosurfaceWireframe = exports.IsosurfaceTextureMeshVisual = exports.IsosurfaceMeshVisual = exports.IsosurfaceMeshParams = exports.createVolumeIsosurfaceMesh = exports.eachIsosurface = exports.IsosurfaceVisual = exports.VolumeIsosurfaceParams = void 0; var tslib_1 = require("tslib"); var param_definition_1 = require("../../mol-util/param-definition"); var volume_1 = require("../../mol-model/volume"); var mesh_1 = require("../../mol-geo/geometry/mesh/mesh"); var algorithm_1 = require("../../mol-geo/util/marching-cubes/algorithm"); var representation_1 = require("./representation"); var location_iterator_1 = require("../../mol-geo/util/location-iterator"); var location_1 = require("../../mol-model/location"); var lines_1 = require("../../mol-geo/geometry/lines/lines"); var representation_2 = require("../representation"); var loci_1 = require("../../mol-model/loci"); var int_1 = require("../../mol-data/int"); var linear_algebra_1 = require("../../mol-math/linear-algebra"); var array_1 = require("../../mol-util/array"); var util_1 = require("./util"); var texture_mesh_1 = require("../../mol-geo/geometry/texture-mesh/texture-mesh"); var isosurface_1 = require("../../mol-gl/compute/marching-cubes/isosurface"); var custom_property_1 = require("../../mol-model/custom-property"); exports.VolumeIsosurfaceParams = { isoValue: volume_1.Volume.IsoValueParam }; function gpuSupport(webgl) { return webgl.extensions.colorBufferFloat && webgl.extensions.textureFloat && webgl.extensions.drawBuffers; } var Padding = 1; function suitableForGpu(volume, webgl) { var gridDim = volume.grid.cells.space.dimensions; var powerOfTwoSize = (0, util_1.getVolumeTexture2dLayout)(gridDim, Padding).powerOfTwoSize; return powerOfTwoSize <= webgl.maxTextureSize / 2; } function IsosurfaceVisual(materialId, volume, props, webgl) { if (props.tryUseGpu && webgl && gpuSupport(webgl) && suitableForGpu(volume, webgl)) { return IsosurfaceTextureMeshVisual(materialId); } return IsosurfaceMeshVisual(materialId); } exports.IsosurfaceVisual = IsosurfaceVisual; function getLoci(volume, props) { return volume_1.Volume.Isosurface.Loci(volume, props.isoValue); } function getIsosurfaceLoci(pickingId, volume, props, id) { var objectId = pickingId.objectId, groupId = pickingId.groupId; if (id === objectId) { return volume_1.Volume.Cell.Loci(volume, int_1.Interval.ofSingleton(groupId)); } return loci_1.EmptyLoci; } function eachIsosurface(loci, volume, props, apply) { return (0, util_1.eachVolumeLoci)(loci, volume, props.isoValue, apply); } exports.eachIsosurface = eachIsosurface; // function createVolumeIsosurfaceMesh(ctx, volume, theme, props, mesh) { return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { var ids, surface, transform; return (0, tslib_1.__generator)(this, function (_a) { switch (_a.label) { case 0: ctx.runtime.update({ message: 'Marching cubes...' }); ids = (0, array_1.fillSerial)(new Int32Array(volume.grid.cells.data.length)); return [4 /*yield*/, (0, algorithm_1.computeMarchingCubesMesh)({ isoLevel: volume_1.Volume.IsoValue.toAbsolute(props.isoValue, volume.grid.stats).absoluteValue, scalarField: volume.grid.cells, idField: linear_algebra_1.Tensor.create(volume.grid.cells.space, linear_algebra_1.Tensor.Data1(ids)) }, mesh).runAsChild(ctx.runtime)]; case 1: surface = _a.sent(); transform = volume_1.Grid.getGridToCartesianTransform(volume.grid); mesh_1.Mesh.transform(surface, transform); if (ctx.webgl && !ctx.webgl.isWebGL2) { // 2nd arg means not to split triangles based on group id. Splitting triangles // is too expensive if each cell has its own group id as is the case here. mesh_1.Mesh.uniformTriangleGroup(surface, false); } surface.setBoundingSphere(volume_1.Volume.getBoundingSphere(volume)); return [2 /*return*/, surface]; } }); }); } exports.createVolumeIsosurfaceMesh = createVolumeIsosurfaceMesh; exports.IsosurfaceMeshParams = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, mesh_1.Mesh.Params), texture_mesh_1.TextureMesh.Params), exports.VolumeIsosurfaceParams), { quality: (0, tslib_1.__assign)((0, tslib_1.__assign)({}, mesh_1.Mesh.Params.quality), { isEssential: false }), tryUseGpu: param_definition_1.ParamDefinition.Boolean(true) }); function IsosurfaceMeshVisual(materialId) { return (0, representation_1.VolumeVisual)({ defaultProps: param_definition_1.ParamDefinition.getDefaultValues(exports.IsosurfaceMeshParams), createGeometry: createVolumeIsosurfaceMesh, createLocationIterator: function (volume) { return (0, location_iterator_1.LocationIterator)(volume.grid.cells.data.length, 1, 1, function () { return location_1.NullLocation; }); }, getLoci: getIsosurfaceLoci, eachLocation: eachIsosurface, setUpdateState: function (state, volume, newProps, currentProps) { if (!volume_1.Volume.IsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.grid.stats)) state.createGeometry = true; }, geometryUtils: mesh_1.Mesh.Utils, mustRecreate: function (volume, props, webgl) { return props.tryUseGpu && !!webgl && suitableForGpu(volume, webgl); } }, materialId); } exports.IsosurfaceMeshVisual = IsosurfaceMeshVisual; // var VolumeIsosurfaceTexture; (function (VolumeIsosurfaceTexture) { var name = 'volume-isosurface-texture'; VolumeIsosurfaceTexture.descriptor = (0, custom_property_1.CustomPropertyDescriptor)({ name: name }); function get(volume, webgl) { var resources = webgl.resources; var transform = volume_1.Grid.getGridToCartesianTransform(volume.grid); var gridDimension = linear_algebra_1.Vec3.clone(volume.grid.cells.space.dimensions); var _a = (0, util_1.getVolumeTexture2dLayout)(gridDimension, Padding), width = _a.width, height = _a.height, texDim = _a.powerOfTwoSize; var gridTexDim = linear_algebra_1.Vec3.create(width, height, 0); var gridTexScale = linear_algebra_1.Vec2.create(width / texDim, height / texDim); // console.log({ texDim, width, height, gridDimension }); if (texDim > webgl.maxTextureSize / 2) { throw new Error('volume too large for gpu isosurface extraction'); } if (!volume._propertyData[name]) { volume._propertyData[name] = resources.texture('image-uint8', 'alpha', 'ubyte', 'linear'); var texture_1 = volume._propertyData[name]; texture_1.define(texDim, texDim); // load volume into sub-section of texture texture_1.load((0, util_1.createVolumeTexture2d)(volume, 'data', Padding), true); volume.customProperties.add(VolumeIsosurfaceTexture.descriptor); volume.customProperties.assets(VolumeIsosurfaceTexture.descriptor, [{ dispose: function () { return texture_1.destroy(); } }]); } gridDimension[0] += Padding; gridDimension[1] += Padding; return { texture: volume._propertyData[name], transform: transform, gridDimension: gridDimension, gridTexDim: gridTexDim, gridTexScale: gridTexScale }; } VolumeIsosurfaceTexture.get = get; })(VolumeIsosurfaceTexture || (VolumeIsosurfaceTexture = {})); function createVolumeIsosurfaceTextureMesh(ctx, volume, theme, props, textureMesh) { return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { var _a, max, min, diff, value, isoLevel, _b, texture, gridDimension, gridTexDim, gridTexScale, transform, buffer, gv, surface; return (0, tslib_1.__generator)(this, function (_c) { if (!ctx.webgl) throw new Error('webgl context required to create volume isosurface texture-mesh'); _a = volume.grid.stats, max = _a.max, min = _a.min; diff = max - min; value = volume_1.Volume.IsoValue.toAbsolute(props.isoValue, volume.grid.stats).absoluteValue; isoLevel = ((value - min) / diff); _b = VolumeIsosurfaceTexture.get(volume, ctx.webgl), texture = _b.texture, gridDimension = _b.gridDimension, gridTexDim = _b.gridTexDim, gridTexScale = _b.gridTexScale, transform = _b.transform; buffer = textureMesh === null || textureMesh === void 0 ? void 0 : textureMesh.doubleBuffer.get(); gv = (0, isosurface_1.extractIsosurface)(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, value < 0, false, buffer === null || buffer === void 0 ? void 0 : buffer.vertex, buffer === null || buffer === void 0 ? void 0 : buffer.group, buffer === null || buffer === void 0 ? void 0 : buffer.normal); surface = texture_mesh_1.TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, volume_1.Volume.getBoundingSphere(volume), textureMesh); return [2 /*return*/, surface]; }); }); } function IsosurfaceTextureMeshVisual(materialId) { return (0, representation_1.VolumeVisual)({ defaultProps: param_definition_1.ParamDefinition.getDefaultValues(exports.IsosurfaceMeshParams), createGeometry: createVolumeIsosurfaceTextureMesh, createLocationIterator: function (volume) { return (0, location_iterator_1.LocationIterator)(volume.grid.cells.data.length, 1, 1, function () { return location_1.NullLocation; }); }, getLoci: getIsosurfaceLoci, eachLocation: eachIsosurface, setUpdateState: function (state, volume, newProps, currentProps) { if (!volume_1.Volume.IsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.grid.stats)) state.createGeometry = true; }, geometryUtils: texture_mesh_1.TextureMesh.Utils, mustRecreate: function (volume, props, webgl) { return !props.tryUseGpu || !webgl || !suitableForGpu(volume, webgl); }, dispose: function (geometry) { geometry.vertexTexture.ref.value.destroy(); geometry.groupTexture.ref.value.destroy(); geometry.normalTexture.ref.value.destroy(); geometry.doubleBuffer.destroy(); } }, materialId); } exports.IsosurfaceTextureMeshVisual = IsosurfaceTextureMeshVisual; // function createVolumeIsosurfaceWireframe(ctx, volume, theme, props, lines) { return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { var ids, wireframe, transform; return (0, tslib_1.__generator)(this, function (_a) { switch (_a.label) { case 0: ctx.runtime.update({ message: 'Marching cubes...' }); ids = (0, array_1.fillSerial)(new Int32Array(volume.grid.cells.data.length)); return [4 /*yield*/, (0, algorithm_1.computeMarchingCubesLines)({ isoLevel: volume_1.Volume.IsoValue.toAbsolute(props.isoValue, volume.grid.stats).absoluteValue, scalarField: volume.grid.cells, idField: linear_algebra_1.Tensor.create(volume.grid.cells.space, linear_algebra_1.Tensor.Data1(ids)) }, lines).runAsChild(ctx.runtime)]; case 1: wireframe = _a.sent(); transform = volume_1.Grid.getGridToCartesianTransform(volume.grid); lines_1.Lines.transform(wireframe, transform); wireframe.setBoundingSphere(volume_1.Volume.getBoundingSphere(volume)); return [2 /*return*/, wireframe]; } }); }); } exports.createVolumeIsosurfaceWireframe = createVolumeIsosurfaceWireframe; exports.IsosurfaceWireframeParams = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, lines_1.Lines.Params), exports.VolumeIsosurfaceParams), { quality: (0, tslib_1.__assign)((0, tslib_1.__assign)({}, lines_1.Lines.Params.quality), { isEssential: false }), sizeFactor: param_definition_1.ParamDefinition.Numeric(3, { min: 0, max: 10, step: 0.1 }) }); function IsosurfaceWireframeVisual(materialId) { return (0, representation_1.VolumeVisual)({ defaultProps: param_definition_1.ParamDefinition.getDefaultValues(exports.IsosurfaceWireframeParams), createGeometry: createVolumeIsosurfaceWireframe, createLocationIterator: function (volume) { return (0, location_iterator_1.LocationIterator)(volume.grid.cells.data.length, 1, 1, function () { return location_1.NullLocation; }); }, getLoci: getIsosurfaceLoci, eachLocation: eachIsosurface, setUpdateState: function (state, volume, newProps, currentProps) { if (!volume_1.Volume.IsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.grid.stats)) state.createGeometry = true; }, geometryUtils: lines_1.Lines.Utils }, materialId); } exports.IsosurfaceWireframeVisual = IsosurfaceWireframeVisual; // var IsosurfaceVisuals = { 'solid': function (ctx, getParams) { return (0, representation_1.VolumeRepresentation)('Isosurface mesh', ctx, getParams, IsosurfaceVisual, getLoci); }, 'wireframe': function (ctx, getParams) { return (0, representation_1.VolumeRepresentation)('Isosurface wireframe', ctx, getParams, IsosurfaceWireframeVisual, getLoci); }, }; exports.IsosurfaceParams = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, exports.IsosurfaceMeshParams), exports.IsosurfaceWireframeParams), { visuals: param_definition_1.ParamDefinition.MultiSelect(['solid'], param_definition_1.ParamDefinition.objectToOptions(IsosurfaceVisuals)) }); function getIsosurfaceParams(ctx, volume) { var p = param_definition_1.ParamDefinition.clone(exports.IsosurfaceParams); p.isoValue = volume_1.Volume.createIsoValueParam(volume_1.Volume.IsoValue.relative(2), volume.grid.stats); return p; } exports.getIsosurfaceParams = getIsosurfaceParams; function IsosurfaceRepresentation(ctx, getParams) { return representation_2.Representation.createMulti('Isosurface', ctx, getParams, representation_2.Representation.StateBuilder, IsosurfaceVisuals); } exports.IsosurfaceRepresentation = IsosurfaceRepresentation; exports.IsosurfaceRepresentationProvider = (0, representation_1.VolumeRepresentationProvider)({ name: 'isosurface', label: 'Isosurface', description: 'Displays a triangulated isosurface of volumetric data.', factory: IsosurfaceRepresentation, getParams: getIsosurfaceParams, defaultValues: param_definition_1.ParamDefinition.getDefaultValues(exports.IsosurfaceParams), defaultColorTheme: { name: 'uniform' }, defaultSizeTheme: { name: 'uniform' }, isApplicable: function (volume) { return !volume_1.Volume.isEmpty(volume); } }); //# sourceMappingURL=isosurface.js.map