molstar
Version:
A comprehensive macromolecular library.
219 lines (218 loc) • 11.9 kB
JavaScript
"use strict";
/**
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.isCameraAxesLoci = exports.CameraHelper = exports.CameraHelperParams = void 0;
var tslib_1 = require("tslib");
var immer_1 = tslib_1.__importDefault(require("immer"));
var interval_1 = require("../../mol-data/int/interval");
var cylinder_1 = require("../../mol-geo/geometry/mesh/builder/cylinder");
var sphere_1 = require("../../mol-geo/geometry/mesh/builder/sphere");
var mesh_1 = require("../../mol-geo/geometry/mesh/mesh");
var mesh_builder_1 = require("../../mol-geo/geometry/mesh/mesh-builder");
var scene_1 = require("../../mol-gl/scene");
var render_item_1 = require("../../mol-gl/webgl/render-item");
var geometry_1 = require("../../mol-math/geometry");
var linear_algebra_1 = require("../../mol-math/linear-algebra");
var loci_1 = require("../../mol-model/loci");
var shape_1 = require("../../mol-model/shape");
var visual_1 = require("../../mol-repr/visual");
var names_1 = require("../../mol-util/color/names");
var marker_action_1 = require("../../mol-util/marker-action");
var param_definition_1 = require("../../mol-util/param-definition");
var camera_1 = require("../camera");
// TODO add scale line/grid
var AxesParams = tslib_1.__assign(tslib_1.__assign({}, mesh_1.Mesh.Params), { alpha: tslib_1.__assign(tslib_1.__assign({}, mesh_1.Mesh.Params.alpha), { defaultValue: 0.51 }), ignoreLight: tslib_1.__assign(tslib_1.__assign({}, mesh_1.Mesh.Params.ignoreLight), { defaultValue: true }), colorX: param_definition_1.ParamDefinition.Color(names_1.ColorNames.red, { isEssential: true }), colorY: param_definition_1.ParamDefinition.Color(names_1.ColorNames.green, { isEssential: true }), colorZ: param_definition_1.ParamDefinition.Color(names_1.ColorNames.blue, { isEssential: true }), scale: param_definition_1.ParamDefinition.Numeric(0.33, { min: 0.1, max: 2, step: 0.1 }, { isEssential: true }) });
exports.CameraHelperParams = {
axes: param_definition_1.ParamDefinition.MappedStatic('on', {
on: param_definition_1.ParamDefinition.Group(AxesParams),
off: param_definition_1.ParamDefinition.Group({})
}, { cycle: true, description: 'Show camera orientation axes' }),
};
var CameraHelper = /** @class */ (function () {
function CameraHelper(webgl, props) {
if (props === void 0) { props = {}; }
var _this = this;
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_1.Interval.ofSingleton(idx)))
changed = true;
}
return changed;
};
this.scene = scene_1.Scene.create(webgl, render_item_1.GraphicsRenderVariantsBlended);
this.camera = new camera_1.Camera();
linear_algebra_1.Vec3.set(this.camera.up, 0, 1, 0);
linear_algebra_1.Vec3.set(this.camera.target, 0, 0, 0);
this.setProps(props);
}
CameraHelper.prototype.setProps = function (props) {
var _this = this;
this.props = (0, immer_1.default)(this.props, function (p) {
if (props.axes !== undefined) {
p.axes.name = props.axes.name;
if (props.axes.name === 'on') {
_this.scene.clear();
var params = tslib_1.__assign(tslib_1.__assign({}, props.axes.params), { scale: props.axes.params.scale * _this.webgl.pixelRatio });
_this.renderObject = createAxesRenderObject(params);
_this.scene.add(_this.renderObject);
_this.scene.commit();
linear_algebra_1.Vec3.set(_this.camera.position, 0, 0, params.scale * 200);
linear_algebra_1.Mat4.lookAt(_this.camera.view, _this.camera.position, _this.camera.target, _this.camera.up);
p.axes.params = tslib_1.__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 /* CameraHelperAxis.None */)
return loci_1.EmptyLoci;
return CameraAxesLoci(this, groupId, instanceId);
};
CameraHelper.prototype.mark = function (loci, action) {
if (!marker_action_1.MarkerActions.is(marker_action_1.MarkerActions.Highlighting, action))
return false;
if (!(0, loci_1.isEveryLoci)(loci)) {
if (!isCameraAxesLoci(loci))
return false;
if (loci.data !== this)
return false;
}
return visual_1.Visual.mark(this.renderObject, loci, action, this.eachGroup);
};
CameraHelper.prototype.update = function (camera) {
if (!this.renderObject)
return;
updateCamera(this.camera, camera.viewport, camera.viewOffset);
linear_algebra_1.Mat4.extractRotation(this.scene.view, camera.view);
var r = this.renderObject.values.boundingSphere.ref.value.radius;
linear_algebra_1.Mat4.setTranslation(this.scene.view, linear_algebra_1.Vec3.create(-camera.viewport.width / 2 + r, -camera.viewport.height / 2 + r, 0));
};
return CameraHelper;
}());
exports.CameraHelper = CameraHelper;
function getAxisLabel(axis) {
switch (axis) {
case 1 /* CameraHelperAxis.X */: return 'X Axis';
case 2 /* CameraHelperAxis.Y */: return 'Y Axis';
case 3 /* CameraHelperAxis.Z */: return 'Z Axis';
case 4 /* CameraHelperAxis.XY */: return 'XY Plane';
case 5 /* CameraHelperAxis.XZ */: return 'XZ Plane';
case 6 /* CameraHelperAxis.YZ */: return 'YZ Plane';
default: return 'Axes';
}
}
function CameraAxesLoci(cameraHelper, groupId, instanceId) {
return (0, loci_1.DataLoci)('camera-axes', cameraHelper, [{ groupId: groupId, instanceId: instanceId }], void 0 /** bounding sphere */, function () { return getAxisLabel(groupId); });
}
function isCameraAxesLoci(x) {
return x.kind === 'data-loci' && x.tag === 'camera-axes';
}
exports.isCameraAxesLoci = isCameraAxesLoci;
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;
}
linear_algebra_1.Mat4.ortho(camera.projection, left, right, top, bottom, near, far);
}
function createAxesMesh(scale, mesh) {
var state = mesh_builder_1.MeshBuilder.createState(512, 256, mesh);
var radius = 0.075 * scale;
var x = linear_algebra_1.Vec3.scale((0, linear_algebra_1.Vec3)(), linear_algebra_1.Vec3.unitX, scale);
var y = linear_algebra_1.Vec3.scale((0, linear_algebra_1.Vec3)(), linear_algebra_1.Vec3.unitY, scale);
var z = linear_algebra_1.Vec3.scale((0, linear_algebra_1.Vec3)(), linear_algebra_1.Vec3.unitZ, scale);
var cylinderProps = { radiusTop: radius, radiusBottom: radius, radialSegments: 32 };
state.currentGroup = 0 /* CameraHelperAxis.None */;
(0, sphere_1.addSphere)(state, linear_algebra_1.Vec3.origin, radius, 2);
state.currentGroup = 1 /* CameraHelperAxis.X */;
(0, sphere_1.addSphere)(state, x, radius, 2);
(0, cylinder_1.addCylinder)(state, linear_algebra_1.Vec3.origin, x, 1, cylinderProps);
state.currentGroup = 2 /* CameraHelperAxis.Y */;
(0, sphere_1.addSphere)(state, y, radius, 2);
(0, cylinder_1.addCylinder)(state, linear_algebra_1.Vec3.origin, y, 1, cylinderProps);
state.currentGroup = 3 /* CameraHelperAxis.Z */;
(0, sphere_1.addSphere)(state, z, radius, 2);
(0, cylinder_1.addCylinder)(state, linear_algebra_1.Vec3.origin, z, 1, cylinderProps);
linear_algebra_1.Vec3.scale(x, x, 0.5);
linear_algebra_1.Vec3.scale(y, y, 0.5);
linear_algebra_1.Vec3.scale(z, z, 0.5);
state.currentGroup = 4 /* CameraHelperAxis.XY */;
mesh_builder_1.MeshBuilder.addTriangle(state, linear_algebra_1.Vec3.origin, x, y);
mesh_builder_1.MeshBuilder.addTriangle(state, linear_algebra_1.Vec3.origin, y, x);
var xy = linear_algebra_1.Vec3.add((0, linear_algebra_1.Vec3)(), x, y);
mesh_builder_1.MeshBuilder.addTriangle(state, xy, x, y);
mesh_builder_1.MeshBuilder.addTriangle(state, xy, y, x);
state.currentGroup = 5 /* CameraHelperAxis.XZ */;
mesh_builder_1.MeshBuilder.addTriangle(state, linear_algebra_1.Vec3.origin, x, z);
mesh_builder_1.MeshBuilder.addTriangle(state, linear_algebra_1.Vec3.origin, z, x);
var xz = linear_algebra_1.Vec3.add((0, linear_algebra_1.Vec3)(), x, z);
mesh_builder_1.MeshBuilder.addTriangle(state, xz, x, z);
mesh_builder_1.MeshBuilder.addTriangle(state, xz, z, x);
state.currentGroup = 6 /* CameraHelperAxis.YZ */;
mesh_builder_1.MeshBuilder.addTriangle(state, linear_algebra_1.Vec3.origin, y, z);
mesh_builder_1.MeshBuilder.addTriangle(state, linear_algebra_1.Vec3.origin, z, y);
var yz = linear_algebra_1.Vec3.add((0, linear_algebra_1.Vec3)(), y, z);
mesh_builder_1.MeshBuilder.addTriangle(state, yz, y, z);
mesh_builder_1.MeshBuilder.addTriangle(state, yz, z, y);
return mesh_builder_1.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(geometry_1.Sphere3D.create(linear_algebra_1.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 names_1.ColorNames.grey;
}
};
return shape_1.Shape.create('axes', {}, mesh, getColor, function () { return 1; }, function () { return ''; });
}
function createAxesRenderObject(props) {
var shape = getAxesShape(props);
return shape_1.Shape.createRenderObject(shape, props);
}