UNPKG

molstar

Version:

A comprehensive macromolecular library.

213 lines 9.89 kB
/** * Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { __assign } from "tslib"; import produce from 'immer'; import { Interval } from '../../mol-data/int/interval'; import { addCylinder } from '../../mol-geo/geometry/mesh/builder/cylinder'; import { addSphere } from '../../mol-geo/geometry/mesh/builder/sphere'; import { Mesh } from '../../mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from '../../mol-geo/geometry/mesh/mesh-builder'; import { Scene } from '../../mol-gl/scene'; import { Sphere3D } from '../../mol-math/geometry'; import { Mat4, Vec3 } from '../../mol-math/linear-algebra'; import { DataLoci, EmptyLoci } from '../../mol-model/loci'; import { Shape } from '../../mol-model/shape'; import { Visual } from '../../mol-repr/visual'; import { ColorNames } from '../../mol-util/color/names'; import { MarkerActions } from '../../mol-util/marker-action'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { Camera } from '../camera'; // TODO add scale line/grid var AxesParams = __assign(__assign({}, Mesh.Params), { alpha: __assign(__assign({}, Mesh.Params.alpha), { defaultValue: 0.51 }), ignoreLight: __assign(__assign({}, Mesh.Params.ignoreLight), { defaultValue: true }), colorX: PD.Color(ColorNames.red, { isEssential: true }), colorY: PD.Color(ColorNames.green, { isEssential: true }), colorZ: PD.Color(ColorNames.blue, { isEssential: true }), scale: PD.Numeric(0.33, { min: 0.1, max: 2, step: 0.1 }, { isEssential: true }) }); export var CameraHelperParams = { axes: PD.MappedStatic('on', { on: PD.Group(AxesParams), off: PD.Group({}) }, { cycle: true, description: 'Show camera orientation axes' }), }; var CameraHelper = /** @class */ (function () { function CameraHelper(webgl, props) { var _this = this; if (props === void 0) { props = {}; } this.webgl = webgl; this.props = { axes: { name: 'off', params: {} } }; this.eachGroup = function (loci, apply) { if (!_this.renderObject) return false; if (!isCameraAxesLoci(loci)) return false; var changed = false; var groupCount = _this.renderObject.values.uGroupCount.ref.value; var elements = loci.elements; for (var _i = 0, elements_1 = elements; _i < elements_1.length; _i++) { var _a = elements_1[_i], groupId = _a.groupId, instanceId = _a.instanceId; var idx = instanceId * groupCount + groupId; if (apply(Interval.ofSingleton(idx))) changed = true; } return changed; }; this.scene = Scene.create(webgl); this.camera = new Camera(); Vec3.set(this.camera.up, 0, 1, 0); Vec3.set(this.camera.target, 0, 0, 0); this.setProps(props); } CameraHelper.prototype.setProps = function (props) { var _this = this; this.props = produce(this.props, function (p) { if (props.axes !== undefined) { p.axes.name = props.axes.name; if (props.axes.name === 'on') { _this.scene.clear(); var params = __assign(__assign({}, props.axes.params), { scale: props.axes.params.scale * _this.webgl.pixelRatio }); _this.renderObject = createAxesRenderObject(params); _this.renderObject.state.noClip = true; _this.scene.add(_this.renderObject); _this.scene.commit(); Vec3.set(_this.camera.position, 0, 0, params.scale * 200); Mat4.lookAt(_this.camera.view, _this.camera.position, _this.camera.target, _this.camera.up); p.axes.params = __assign({}, props.axes.params); } } }); }; Object.defineProperty(CameraHelper.prototype, "isEnabled", { get: function () { return this.props.axes.name === 'on'; }, enumerable: false, configurable: true }); CameraHelper.prototype.getLoci = function (pickingId) { var objectId = pickingId.objectId, groupId = pickingId.groupId, instanceId = pickingId.instanceId; if (!this.renderObject || objectId !== this.renderObject.id || groupId === 0 /* None */) return EmptyLoci; return CameraAxesLoci(this, groupId, instanceId); }; CameraHelper.prototype.mark = function (loci, action) { if (!MarkerActions.is(MarkerActions.Highlighting, action)) return false; if (!isCameraAxesLoci(loci)) return false; if (loci.data !== this) return false; return Visual.mark(this.renderObject, loci, action, this.eachGroup); }; CameraHelper.prototype.update = function (camera) { if (!this.renderObject) return; updateCamera(this.camera, camera.viewport, camera.viewOffset); Mat4.extractRotation(this.scene.view, camera.view); var r = this.renderObject.values.boundingSphere.ref.value.radius; Mat4.setTranslation(this.scene.view, Vec3.create(-camera.viewport.width / 2 + r, -camera.viewport.height / 2 + r, 0)); }; return CameraHelper; }()); export { CameraHelper }; function getAxisLabel(axis) { switch (axis) { case 1 /* X */: return 'X Axis'; case 2 /* Y */: return 'Y Axis'; case 3 /* Z */: return 'Z Axis'; case 4 /* XY */: return 'XY Plane'; case 5 /* XZ */: return 'XZ Plane'; case 6 /* YZ */: return 'YZ Plane'; default: return 'Axes'; } } function CameraAxesLoci(cameraHelper, groupId, instanceId) { return DataLoci('camera-axes', cameraHelper, [{ groupId: groupId, instanceId: instanceId }], void 0 /** bounding sphere */, function () { return getAxisLabel(groupId); }); } export function isCameraAxesLoci(x) { return x.kind === 'data-loci' && x.tag === 'camera-axes'; } function updateCamera(camera, viewport, viewOffset) { var near = camera.near, far = camera.far; var fullLeft = -viewport.width / 2; var fullRight = viewport.width / 2; var fullTop = viewport.height / 2; var fullBottom = -viewport.height / 2; var dx = (fullRight - fullLeft) / 2; var dy = (fullTop - fullBottom) / 2; var cx = (fullRight + fullLeft) / 2; var cy = (fullTop + fullBottom) / 2; var left = cx - dx; var right = cx + dx; var top = cy + dy; var bottom = cy - dy; if (viewOffset.enabled) { var scaleW = (fullRight - fullLeft) / viewOffset.width; var scaleH = (fullTop - fullBottom) / viewOffset.height; left += scaleW * viewOffset.offsetX; right = left + scaleW * viewOffset.width; top -= scaleH * viewOffset.offsetY; bottom = top - scaleH * viewOffset.height; } Mat4.ortho(camera.projection, left, right, top, bottom, near, far); } function createAxesMesh(scale, mesh) { var state = MeshBuilder.createState(512, 256, mesh); var radius = 0.075 * scale; var x = Vec3.scale(Vec3(), Vec3.unitX, scale); var y = Vec3.scale(Vec3(), Vec3.unitY, scale); var z = Vec3.scale(Vec3(), Vec3.unitZ, scale); var cylinderProps = { radiusTop: radius, radiusBottom: radius, radialSegments: 32 }; state.currentGroup = 0 /* None */; addSphere(state, Vec3.origin, radius, 2); state.currentGroup = 1 /* X */; addSphere(state, x, radius, 2); addCylinder(state, Vec3.origin, x, 1, cylinderProps); state.currentGroup = 2 /* Y */; addSphere(state, y, radius, 2); addCylinder(state, Vec3.origin, y, 1, cylinderProps); state.currentGroup = 3 /* Z */; addSphere(state, z, radius, 2); addCylinder(state, Vec3.origin, z, 1, cylinderProps); Vec3.scale(x, x, 0.5); Vec3.scale(y, y, 0.5); Vec3.scale(z, z, 0.5); state.currentGroup = 4 /* XY */; MeshBuilder.addTriangle(state, Vec3.origin, x, y); MeshBuilder.addTriangle(state, Vec3.origin, y, x); var xy = Vec3.add(Vec3(), x, y); MeshBuilder.addTriangle(state, xy, x, y); MeshBuilder.addTriangle(state, xy, y, x); state.currentGroup = 5 /* XZ */; MeshBuilder.addTriangle(state, Vec3.origin, x, z); MeshBuilder.addTriangle(state, Vec3.origin, z, x); var xz = Vec3.add(Vec3(), x, z); MeshBuilder.addTriangle(state, xz, x, z); MeshBuilder.addTriangle(state, xz, z, x); state.currentGroup = 6 /* YZ */; MeshBuilder.addTriangle(state, Vec3.origin, y, z); MeshBuilder.addTriangle(state, Vec3.origin, z, y); var yz = Vec3.add(Vec3(), y, z); MeshBuilder.addTriangle(state, yz, y, z); MeshBuilder.addTriangle(state, yz, z, y); return MeshBuilder.getMesh(state); } function getAxesShape(props, shape) { var scale = 100 * props.scale; var mesh = createAxesMesh(scale, shape === null || shape === void 0 ? void 0 : shape.geometry); mesh.setBoundingSphere(Sphere3D.create(Vec3.create(scale / 2, scale / 2, scale / 2), scale + scale / 4)); var getColor = function (groupId) { switch (groupId) { case 1: return props.colorX; case 2: return props.colorY; case 3: return props.colorZ; default: return ColorNames.grey; } }; return Shape.create('axes', {}, mesh, getColor, function () { return 1; }, function () { return ''; }); } function createAxesRenderObject(props) { var shape = getAxesShape(props); return Shape.createRenderObject(shape, props); } //# sourceMappingURL=camera-helper.js.map