molstar
Version:
A comprehensive macromolecular library.
122 lines (121 loc) • 4.97 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.pcaFocus = pcaFocus;
exports.getPcaTransform = getPcaTransform;
const vec3_1 = require("../../..//mol-math/linear-algebra/3d/vec3");
const principal_axes_1 = require("../../../mol-math/linear-algebra/matrix/principal-axes");
const camera_1 = require("../../../mol-canvas3d/camera");
function getPolymerResiduePositions(structure) {
if (structure.atomicResidueCount === 1)
return undefined;
const { polymerResidueCount } = structure;
if (polymerResidueCount <= 1)
return undefined;
const stride = 2 ** Math.max(Math.ceil(Math.log10(polymerResidueCount / 1000)), 0);
const size = stride === 1
? polymerResidueCount
: Math.ceil(polymerResidueCount / stride) + structure.units.length;
const tmpPos = (0, vec3_1.Vec3)();
const positions = new Float32Array(3 * size);
let o = 0;
for (const unit of structure.units) {
const { polymerElements } = unit.props;
const { conformation } = unit;
if (polymerElements) {
for (let i = 0; i < polymerElements.length; i += stride) {
conformation.position(polymerElements[i], tmpPos);
vec3_1.Vec3.toArray(tmpPos, positions, 3 * o);
o++;
}
}
}
return positions.length !== o ? positions.slice(0, 3 * o) : positions;
}
function calculateDisplacement(position, origin, normalDir) {
const A = normalDir[0];
const B = normalDir[1];
const C = normalDir[2];
const D = -A * origin[0] - B * origin[1] - C * origin[2];
const x = position[0];
const y = position[1];
const z = position[2];
const displacement = (A * x + B * y + C * z + D) / Math.sqrt(A * A + B * B + C * C);
return displacement;
}
function getAxesToFlip(position, origin, up, normalDir) {
const toYAxis = calculateDisplacement(position, origin, normalDir);
const toXAxis = calculateDisplacement(position, origin, up);
return {
aroundX: toXAxis < 0,
aroundY: toYAxis < 0,
};
}
function getFirstResidueOrAveragePosition(structure, polymerPositions) {
if (structure.units.length === 1) {
// if only one chain, return the coordinates of the first residue
return vec3_1.Vec3.create(polymerPositions[0], polymerPositions[1], polymerPositions[2]);
}
else {
// if more than one chain, return average of the coordinates of the first polymer chain
const firstPolymerUnit = structure.units.find(u => u.props.polymerElements);
if (firstPolymerUnit) {
const pos = (0, vec3_1.Vec3)();
const center = (0, vec3_1.Vec3)();
const { polymerElements, conformation } = firstPolymerUnit;
for (let i = 0, il = polymerElements.length; i < il; i++) {
conformation.position(polymerElements[i], pos);
vec3_1.Vec3.add(center, center, pos);
}
return vec3_1.Vec3.scale(center, center, 1 / polymerElements.length);
}
else {
return vec3_1.Vec3.create(polymerPositions[0], polymerPositions[1], polymerPositions[2]);
}
}
}
function pcaFocus(plugin, radius, options) {
if (!plugin.canvas3d)
return;
const { origin, dirA, dirB, dirC } = options.principalAxes.boxAxes;
const up = vec3_1.Vec3.clone(dirA);
const dir = vec3_1.Vec3.clone(dirC);
if (options.positionToFlip) {
const { aroundX, aroundY } = getAxesToFlip(options.positionToFlip, origin, up, dirB);
if (aroundX) {
vec3_1.Vec3.negate(dir, dir);
vec3_1.Vec3.negate(up, up);
}
if (aroundY) {
vec3_1.Vec3.negate(dir, dir);
}
}
const position = vec3_1.Vec3.scale((0, vec3_1.Vec3)(), origin, -100);
if (vec3_1.Vec3.dot(position, up) <= 0) {
vec3_1.Vec3.negate(dir, dir);
}
if (vec3_1.Vec3.dot(vec3_1.Vec3.unitY, dir) <= 0) {
vec3_1.Vec3.negate(up, up);
}
return plugin.canvas3d.camera.getFocus(origin, radius, up, dir, camera_1.Camera.createDefaultSnapshot());
}
function getPcaTransform(group) {
var _a;
const structure = (_a = group[0].cell.obj) === null || _a === void 0 ? void 0 : _a.data;
if (!structure)
return undefined;
if ('_pcaTransformData' in structure.currentPropertyData) {
return structure.currentPropertyData._pcaTransformData;
}
const positions = getPolymerResiduePositions(structure);
if (!positions) {
structure.currentPropertyData._pcaTransformData = undefined;
return undefined;
}
const positionToFlip = getFirstResidueOrAveragePosition(structure, positions);
const pcaTransfromData = {
principalAxes: principal_axes_1.PrincipalAxes.ofPositions(positions),
positionToFlip
};
structure.currentPropertyData._pcaTransformData = pcaTransfromData;
return pcaTransfromData;
}