molstar
Version:
A comprehensive macromolecular library.
363 lines • 18.4 kB
JavaScript
"use strict";
/**
* Copyright (c) 2018-2020 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.AssemblySymmetryRepresentation = exports.AssemblySymmetryParams = void 0;
var tslib_1 = require("tslib");
var param_definition_1 = require("../../../mol-util/param-definition");
var prop_1 = require("./prop");
var mesh_builder_1 = require("../../../mol-geo/geometry/mesh/mesh-builder");
var linear_algebra_1 = require("../../../mol-math/linear-algebra");
var cylinder_1 = require("../../../mol-geo/geometry/mesh/builder/cylinder");
var mesh_1 = require("../../../mol-geo/geometry/mesh/mesh");
var shape_1 = require("../../../mol-model/shape");
var names_1 = require("../../../mol-util/color/names");
var representation_1 = require("../../../mol-repr/shape/representation");
var marker_action_1 = require("../../../mol-util/marker-action");
var prism_1 = require("../../../mol-geo/primitive/prism");
var wedge_1 = require("../../../mol-geo/primitive/wedge");
var primitive_1 = require("../../../mol-geo/primitive/primitive");
var memoize_1 = require("../../../mol-util/memoize");
var polygon_1 = require("../../../mol-geo/primitive/polygon");
var color_1 = require("../../../mol-util/color");
var legend_1 = require("../../../mol-util/legend");
var representation_2 = require("../../../mol-repr/representation");
var cage_1 = require("../../../mol-geo/primitive/cage");
var octahedron_1 = require("../../../mol-geo/primitive/octahedron");
var tetrahedron_1 = require("../../../mol-geo/primitive/tetrahedron");
var icosahedron_1 = require("../../../mol-geo/primitive/icosahedron");
var misc_1 = require("../../../mol-math/misc");
var common_1 = require("../../../mol-math/linear-algebra/3d/common");
var number_1 = require("../../../mol-util/number");
var geometry_1 = require("../../../mol-math/geometry");
var OrderColors = (0, color_1.ColorMap)({
'2': names_1.ColorNames.deepskyblue,
'3': names_1.ColorNames.lime,
'N': names_1.ColorNames.red,
});
var OrderColorsLegend = (0, legend_1.TableLegend)(Object.keys(OrderColors).map(function (name) {
return [name, OrderColors[name]];
}));
function axesColorHelp(value) {
return value.name === 'byOrder'
? { description: 'Color axes by their order', legend: OrderColorsLegend }
: {};
}
var SharedParams = (0, tslib_1.__assign)((0, tslib_1.__assign)({}, mesh_1.Mesh.Params), { scale: param_definition_1.ParamDefinition.Numeric(2, { min: 0.1, max: 5, step: 0.1 }) });
var AxesParams = (0, tslib_1.__assign)((0, tslib_1.__assign)({}, SharedParams), { axesColor: param_definition_1.ParamDefinition.MappedStatic('byOrder', {
byOrder: param_definition_1.ParamDefinition.EmptyGroup(),
uniform: param_definition_1.ParamDefinition.Group({
colorValue: param_definition_1.ParamDefinition.Color(names_1.ColorNames.orange),
}, { isFlat: true })
}, { help: axesColorHelp }) });
var CageParams = (0, tslib_1.__assign)((0, tslib_1.__assign)({}, SharedParams), { cageColor: param_definition_1.ParamDefinition.Color(names_1.ColorNames.orange) });
var AssemblySymmetryVisuals = {
// cage should come before 'axes' so that the representative loci uses the cage shape
'cage': function (ctx, getParams) { return (0, representation_1.ShapeRepresentation)(getCageShape, mesh_1.Mesh.Utils, { modifyState: function (s) { return ((0, tslib_1.__assign)((0, tslib_1.__assign)({}, s), { markerActions: marker_action_1.MarkerActions.Highlighting })); } }); },
'axes': function (ctx, getParams) { return (0, representation_1.ShapeRepresentation)(getAxesShape, mesh_1.Mesh.Utils, { modifyState: function (s) { return ((0, tslib_1.__assign)((0, tslib_1.__assign)({}, s), { markerActions: marker_action_1.MarkerActions.Highlighting })); } }); },
};
exports.AssemblySymmetryParams = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, AxesParams), CageParams), { visuals: param_definition_1.ParamDefinition.MultiSelect(['axes', 'cage'], param_definition_1.ParamDefinition.objectToOptions(AssemblySymmetryVisuals)) });
//
function getAssemblyName(s) {
var _a;
var id = ((_a = s.units[0].conformation.operator.assembly) === null || _a === void 0 ? void 0 : _a.id) || '';
return (0, number_1.isInteger)(id) ? "Assembly " + id : id;
}
var t = linear_algebra_1.Mat4.identity();
var tmpV = (0, linear_algebra_1.Vec3)();
var tmpCenter = (0, linear_algebra_1.Vec3)();
var tmpScale = (0, linear_algebra_1.Vec3)();
var getOrderPrimitive = (0, memoize_1.memoize1)(function (order) {
if (order < 2) {
return (0, prism_1.Prism)((0, polygon_1.polygon)(48, false));
}
else if (order === 2) {
var lens = (0, prism_1.Prism)((0, polygon_1.polygon)(48, false));
var m = linear_algebra_1.Mat4.identity();
linear_algebra_1.Mat4.scale(m, m, linear_algebra_1.Vec3.create(1, 0.35, 1));
(0, primitive_1.transformPrimitive)(lens, m);
return lens;
}
else if (order === 3) {
return (0, wedge_1.Wedge)();
}
else {
return (0, prism_1.Prism)((0, polygon_1.polygon)(order, false));
}
});
function getAxesMesh(data, props, mesh) {
var scale = props.scale;
var rotation_axes = data.rotation_axes;
if (!prop_1.AssemblySymmetry.isRotationAxes(rotation_axes))
return mesh_1.Mesh.createEmpty(mesh);
var _a = rotation_axes[0], start = _a.start, end = _a.end;
var radius = (linear_algebra_1.Vec3.distance(start, end) / 500) * scale;
linear_algebra_1.Vec3.set(tmpScale, radius * 7, radius * 7, radius * 0.4);
var cylinderProps = { radiusTop: radius, radiusBottom: radius };
var builderState = mesh_builder_1.MeshBuilder.createState(256, 128, mesh);
builderState.currentGroup = 0;
linear_algebra_1.Vec3.scale(tmpCenter, linear_algebra_1.Vec3.add(tmpCenter, start, end), 0.5);
for (var i = 0, il = rotation_axes.length; i < il; ++i) {
var _b = rotation_axes[i], order = _b.order, start_1 = _b.start, end_1 = _b.end;
builderState.currentGroup = i;
(0, cylinder_1.addCylinder)(builderState, start_1, end_1, 1, cylinderProps);
var primitive = getOrderPrimitive(order);
if (primitive) {
linear_algebra_1.Vec3.scale(tmpCenter, linear_algebra_1.Vec3.add(tmpCenter, start_1, end_1), 0.5);
if (linear_algebra_1.Vec3.dot(linear_algebra_1.Vec3.unitY, linear_algebra_1.Vec3.sub(tmpV, start_1, tmpCenter)) === 0) {
linear_algebra_1.Mat4.targetTo(t, start_1, tmpCenter, linear_algebra_1.Vec3.unitY);
}
else {
linear_algebra_1.Mat4.targetTo(t, start_1, tmpCenter, linear_algebra_1.Vec3.unitX);
}
linear_algebra_1.Mat4.scale(t, t, tmpScale);
linear_algebra_1.Mat4.setTranslation(t, start_1);
mesh_builder_1.MeshBuilder.addPrimitive(builderState, t, primitive);
linear_algebra_1.Mat4.setTranslation(t, end_1);
mesh_builder_1.MeshBuilder.addPrimitive(builderState, t, primitive);
}
}
return mesh_builder_1.MeshBuilder.getMesh(builderState);
}
function getAxesShape(ctx, data, props, shape) {
var assemblySymmetry = prop_1.AssemblySymmetryProvider.get(data).value;
var geo = getAxesMesh(assemblySymmetry, props, shape && shape.geometry);
var getColor = function (groupId) {
var _a;
if (props.axesColor.name === 'byOrder') {
var rotation_axes = assemblySymmetry.rotation_axes;
var order = (_a = rotation_axes[groupId]) === null || _a === void 0 ? void 0 : _a.order;
if (order === 2)
return OrderColors[2];
else if (order === 3)
return OrderColors[3];
else
return OrderColors.N;
}
else {
return props.axesColor.params.colorValue;
}
};
var getLabel = function (groupId) {
var _a;
var type = assemblySymmetry.type, symbol = assemblySymmetry.symbol, kind = assemblySymmetry.kind, rotation_axes = assemblySymmetry.rotation_axes;
var order = (_a = rotation_axes[groupId]) === null || _a === void 0 ? void 0 : _a.order;
return [
"<small>" + data.model.entryId + "</small>",
"<small>" + getAssemblyName(data) + "</small>",
"Axis " + (groupId + 1) + " with Order " + order + " of " + type + " " + kind + " (" + symbol + ")"
].join(' | ');
};
return shape_1.Shape.create('Axes', data, geo, getColor, function () { return 1; }, getLabel);
}
//
var getSymbolCage = (0, memoize_1.memoize1)(function (symbol) {
if (symbol.startsWith('D') || symbol.startsWith('C')) {
// z axis is prism axis, x/y axes cut through edge midpoints
var fold = parseInt(symbol.substr(1));
var cage = void 0;
if (fold === 2) {
cage = (0, prism_1.PrismCage)((0, polygon_1.polygon)(4, false));
}
else if (fold === 3) {
cage = (0, wedge_1.WedgeCage)();
}
else if (fold > 3) {
cage = (0, prism_1.PrismCage)((0, polygon_1.polygon)(fold, false));
}
else {
return;
}
if (fold % 2 === 0) {
return cage;
}
else {
var m = linear_algebra_1.Mat4.identity();
linear_algebra_1.Mat4.rotate(m, m, 1 / fold * Math.PI / 2, linear_algebra_1.Vec3.unitZ);
return (0, cage_1.transformCage)((0, cage_1.cloneCage)(cage), m);
}
}
else if (symbol === 'O') {
// x/y/z axes cut through order 4 vertices
return (0, octahedron_1.OctahedronCage)();
}
else if (symbol === 'I') {
// z axis cut through order 5 vertex
// x axis cut through edge midpoint
var cage = (0, icosahedron_1.IcosahedronCage)();
var m = linear_algebra_1.Mat4.identity();
linear_algebra_1.Mat4.rotate(m, m, (0, misc_1.degToRad)(31.7), linear_algebra_1.Vec3.unitX);
return (0, cage_1.transformCage)((0, cage_1.cloneCage)(cage), m);
}
else if (symbol === 'T') {
// x/y/z axes cut through edge midpoints
return (0, tetrahedron_1.TetrahedronCage)();
}
});
function getSymbolScale(symbol) {
if (symbol.startsWith('D') || symbol.startsWith('C')) {
return 0.75;
}
else if (symbol === 'O') {
return 1.2;
}
else if (symbol === 'I') {
return 0.25;
}
else if (symbol === 'T') {
return 0.8;
}
return 1;
}
function setSymbolTransform(t, symbol, axes, size, structure) {
var eye = (0, linear_algebra_1.Vec3)();
var target = (0, linear_algebra_1.Vec3)();
var dir = (0, linear_algebra_1.Vec3)();
var up = (0, linear_algebra_1.Vec3)();
var pair = undefined;
if (symbol.startsWith('C')) {
pair = [axes[0]];
}
else if (symbol.startsWith('D')) {
var fold_1 = parseInt(symbol.substr(1));
if (fold_1 === 2) {
pair = axes.filter(function (a) { return a.order === 2; });
}
else if (fold_1 >= 3) {
var aN = axes.filter(function (a) { return a.order === fold_1; })[0];
var a2 = axes.filter(function (a) { return a.order === 2; })[1];
pair = [aN, a2];
}
}
else if (symbol === 'O') {
pair = axes.filter(function (a) { return a.order === 4; });
}
else if (symbol === 'I') {
var a5 = axes.filter(function (a) { return a.order === 5; })[0];
var a5dir = linear_algebra_1.Vec3.sub((0, linear_algebra_1.Vec3)(), a5.end, a5.start);
pair = [a5];
for (var _i = 0, _a = axes.filter(function (a) { return a.order === 3; }); _i < _a.length; _i++) {
var a = _a[_i];
var d = (0, misc_1.radToDeg)(linear_algebra_1.Vec3.angle(linear_algebra_1.Vec3.sub(up, a.end, a.start), a5dir));
if (!pair[1] && ((0, common_1.equalEps)(d, 100.81, 0.1) || (0, common_1.equalEps)(d, 79.19, 0.1))) {
pair[1] = a;
break;
}
}
}
else if (symbol === 'T') {
pair = axes.filter(function (a) { return a.order === 2; });
}
linear_algebra_1.Mat4.setIdentity(t);
if (pair) {
var aA = pair[0], aB = pair[1];
linear_algebra_1.Vec3.scale(eye, linear_algebra_1.Vec3.add(eye, aA.end, aA.start), 0.5);
linear_algebra_1.Vec3.copy(target, aA.end);
if (aB) {
linear_algebra_1.Vec3.sub(up, aB.end, aB.start);
linear_algebra_1.Vec3.sub(dir, eye, target);
if (linear_algebra_1.Vec3.dot(dir, up) < 0)
linear_algebra_1.Vec3.negate(up, up);
linear_algebra_1.Mat4.targetTo(t, eye, target, up);
if (symbol.startsWith('D')) {
var sphere = structure.lookup3d.boundary.sphere;
var sizeXY = (sphere.radius * 2) * 0.8; // fallback for missing extrema
if (geometry_1.Sphere3D.hasExtrema(sphere)) {
var n_1 = linear_algebra_1.Mat3.directionTransform((0, linear_algebra_1.Mat3)(), t);
var dirs = unitCircleDirections.map(function (d) { return linear_algebra_1.Vec3.transformMat3((0, linear_algebra_1.Vec3)(), d, n_1); });
sizeXY = getMaxProjectedDistance(sphere.extrema, dirs, sphere.center) * 1.6;
}
linear_algebra_1.Mat4.scale(t, t, linear_algebra_1.Vec3.create(sizeXY, sizeXY, linear_algebra_1.Vec3.distance(aA.start, aA.end) * 0.9));
}
else {
linear_algebra_1.Mat4.scaleUniformly(t, t, size * getSymbolScale(symbol));
}
}
else {
if (linear_algebra_1.Vec3.dot(linear_algebra_1.Vec3.unitY, linear_algebra_1.Vec3.sub(tmpV, aA.end, aA.start)) === 0) {
linear_algebra_1.Vec3.copy(up, linear_algebra_1.Vec3.unitY);
}
else {
linear_algebra_1.Vec3.copy(up, linear_algebra_1.Vec3.unitX);
}
linear_algebra_1.Mat4.targetTo(t, eye, target, up);
var sphere = structure.lookup3d.boundary.sphere;
var sizeXY = (sphere.radius * 2) * 0.8; // fallback for missing extrema
if (geometry_1.Sphere3D.hasExtrema(sphere)) {
var n_2 = linear_algebra_1.Mat3.directionTransform((0, linear_algebra_1.Mat3)(), t);
var dirs = unitCircleDirections.map(function (d) { return linear_algebra_1.Vec3.transformMat3((0, linear_algebra_1.Vec3)(), d, n_2); });
sizeXY = getMaxProjectedDistance(sphere.extrema, dirs, sphere.center);
}
linear_algebra_1.Mat4.scale(t, t, linear_algebra_1.Vec3.create(sizeXY, sizeXY, size * 0.9));
}
}
}
var unitCircleDirections = (function () {
var dirs = [];
var circle = (0, polygon_1.polygon)(12, false, 1);
for (var i = 0, il = circle.length; i < il; i += 3) {
dirs.push(linear_algebra_1.Vec3.fromArray((0, linear_algebra_1.Vec3)(), circle, i));
}
return dirs;
})();
var tmpProj = (0, linear_algebra_1.Vec3)();
function getMaxProjectedDistance(points, directions, center) {
var maxDist = 0;
for (var _i = 0, points_1 = points; _i < points_1.length; _i++) {
var p = points_1[_i];
for (var _a = 0, directions_1 = directions; _a < directions_1.length; _a++) {
var d = directions_1[_a];
linear_algebra_1.Vec3.projectPointOnVector(tmpProj, p, d, center);
var dist = linear_algebra_1.Vec3.distance(tmpProj, center);
if (dist > maxDist)
maxDist = dist;
}
}
return maxDist;
}
function getCageMesh(data, props, mesh) {
var assemblySymmetry = prop_1.AssemblySymmetryProvider.get(data).value;
var scale = props.scale;
var rotation_axes = assemblySymmetry.rotation_axes, symbol = assemblySymmetry.symbol;
if (!prop_1.AssemblySymmetry.isRotationAxes(rotation_axes))
return mesh_1.Mesh.createEmpty(mesh);
var structure = prop_1.AssemblySymmetry.getStructure(data, assemblySymmetry);
var cage = getSymbolCage(symbol);
if (!cage)
return mesh_1.Mesh.createEmpty(mesh);
var _a = rotation_axes[0], start = _a.start, end = _a.end;
var size = linear_algebra_1.Vec3.distance(start, end);
var radius = (size / 500) * scale;
var builderState = mesh_builder_1.MeshBuilder.createState(256, 128, mesh);
builderState.currentGroup = 0;
setSymbolTransform(t, symbol, rotation_axes, size, structure);
linear_algebra_1.Vec3.scale(tmpCenter, linear_algebra_1.Vec3.add(tmpCenter, start, end), 0.5);
linear_algebra_1.Mat4.setTranslation(t, tmpCenter);
mesh_builder_1.MeshBuilder.addCage(builderState, t, cage, radius, 1, 8);
return mesh_builder_1.MeshBuilder.getMesh(builderState);
}
function getCageShape(ctx, data, props, shape) {
var assemblySymmetry = prop_1.AssemblySymmetryProvider.get(data).value;
var geo = getCageMesh(data, props, shape && shape.geometry);
var getColor = function (groupId) {
return props.cageColor;
};
var getLabel = function (groupId) {
var type = assemblySymmetry.type, symbol = assemblySymmetry.symbol, kind = assemblySymmetry.kind;
data.model.entryId;
return [
"<small>" + data.model.entryId + "</small>",
"<small>" + getAssemblyName(data) + "</small>",
"Cage of " + type + " " + kind + " (" + symbol + ")"
].join(' | ');
};
return shape_1.Shape.create('Cage', data, geo, getColor, function () { return 1; }, getLabel);
}
function AssemblySymmetryRepresentation(ctx, getParams) {
return representation_2.Representation.createMulti('Assembly Symmetry', ctx, getParams, representation_2.Representation.StateBuilder, AssemblySymmetryVisuals);
}
exports.AssemblySymmetryRepresentation = AssemblySymmetryRepresentation;
//# sourceMappingURL=representation.js.map