molstar
Version:
A comprehensive macromolecular library.
131 lines • 5.55 kB
JavaScript
/**
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Matrix } from './matrix';
import { Vec3 } from '../3d/vec3';
import { svd } from './svd';
import { Axes3D } from '../../geometry';
export { PrincipalAxes };
var PrincipalAxes;
(function (PrincipalAxes) {
function ofPositions(positions) {
var momentsAxes = calculateMomentsAxes(positions);
var boxAxes = calculateBoxAxes(positions, momentsAxes);
return { momentsAxes: momentsAxes, boxAxes: boxAxes };
}
PrincipalAxes.ofPositions = ofPositions;
function calculateMomentsAxes(positions) {
if (positions.length === 3) {
return Axes3D.create(Vec3.fromArray(Vec3(), positions, 0), Vec3.create(1, 0, 0), Vec3.create(0, 1, 0), Vec3.create(0, 1, 0));
}
var points = Matrix.fromArray(positions, 3, positions.length / 3);
var n = points.rows;
var n3 = n / 3;
var A = Matrix.create(3, 3);
var W = Matrix.create(1, 3);
var U = Matrix.create(3, 3);
var V = Matrix.create(3, 3);
// calculate
var mean = Matrix.meanRows(points);
var pointsM = Matrix.subRows(Matrix.clone(points), mean);
var pointsT = Matrix.transpose(Matrix.create(n, 3), pointsM);
Matrix.multiplyABt(A, pointsT, pointsT);
svd(A, W, U, V);
// origin
var origin = Vec3.create(mean[0], mean[1], mean[2]);
// directions
var dirA = Vec3.create(U.data[0], U.data[3], U.data[6]);
var dirB = Vec3.create(U.data[1], U.data[4], U.data[7]);
var dirC = Vec3.create(U.data[2], U.data[5], U.data[8]);
Vec3.scale(dirA, dirA, Math.sqrt(W.data[0] / n3));
Vec3.scale(dirB, dirB, Math.sqrt(W.data[1] / n3));
Vec3.scale(dirC, dirC, Math.sqrt(W.data[2] / n3));
return Axes3D.create(origin, dirA, dirB, dirC);
}
PrincipalAxes.calculateMomentsAxes = calculateMomentsAxes;
var tmpBoxVec = Vec3();
var tmpBoxVecA = Vec3();
var tmpBoxVecB = Vec3();
var tmpBoxVecC = Vec3();
/**
* Get the scale/length for each dimension for a box around the axes
* to enclose the given positions
*/
function calculateBoxAxes(positions, momentsAxes) {
if (positions.length === 3) {
return Axes3D.clone(momentsAxes);
}
var d1a = -Infinity;
var d1b = -Infinity;
var d2a = -Infinity;
var d2b = -Infinity;
var d3a = -Infinity;
var d3b = -Infinity;
var p = Vec3();
var t = Vec3();
var center = momentsAxes.origin;
var normVecA = Vec3.normalize(tmpBoxVecA, momentsAxes.dirA);
var normVecB = Vec3.normalize(tmpBoxVecB, momentsAxes.dirB);
var normVecC = Vec3.normalize(tmpBoxVecC, momentsAxes.dirC);
for (var i = 0, il = positions.length; i < il; i += 3) {
Vec3.projectPointOnVector(p, Vec3.fromArray(p, positions, i), normVecA, center);
var dp1 = Vec3.dot(normVecA, Vec3.normalize(t, Vec3.sub(t, p, center)));
var dt1 = Vec3.distance(p, center);
if (dp1 > 0) {
if (dt1 > d1a)
d1a = dt1;
}
else {
if (dt1 > d1b)
d1b = dt1;
}
Vec3.projectPointOnVector(p, Vec3.fromArray(p, positions, i), normVecB, center);
var dp2 = Vec3.dot(normVecB, Vec3.normalize(t, Vec3.sub(t, p, center)));
var dt2 = Vec3.distance(p, center);
if (dp2 > 0) {
if (dt2 > d2a)
d2a = dt2;
}
else {
if (dt2 > d2b)
d2b = dt2;
}
Vec3.projectPointOnVector(p, Vec3.fromArray(p, positions, i), normVecC, center);
var dp3 = Vec3.dot(normVecC, Vec3.normalize(t, Vec3.sub(t, p, center)));
var dt3 = Vec3.distance(p, center);
if (dp3 > 0) {
if (dt3 > d3a)
d3a = dt3;
}
else {
if (dt3 > d3b)
d3b = dt3;
}
}
var dirA = Vec3.setMagnitude(Vec3(), normVecA, (d1a + d1b) / 2);
var dirB = Vec3.setMagnitude(Vec3(), normVecB, (d2a + d2b) / 2);
var dirC = Vec3.setMagnitude(Vec3(), normVecC, (d3a + d3b) / 2);
var origin = Vec3();
var addCornerHelper = function (d1, d2, d3) {
Vec3.copy(tmpBoxVec, center);
Vec3.scaleAndAdd(tmpBoxVec, tmpBoxVec, normVecA, d1);
Vec3.scaleAndAdd(tmpBoxVec, tmpBoxVec, normVecB, d2);
Vec3.scaleAndAdd(tmpBoxVec, tmpBoxVec, normVecC, d3);
Vec3.add(origin, origin, tmpBoxVec);
};
addCornerHelper(d1a, d2a, d3a);
addCornerHelper(d1a, d2a, -d3b);
addCornerHelper(d1a, -d2b, -d3b);
addCornerHelper(d1a, -d2b, d3a);
addCornerHelper(-d1b, -d2b, -d3b);
addCornerHelper(-d1b, -d2b, d3a);
addCornerHelper(-d1b, d2a, d3a);
addCornerHelper(-d1b, d2a, -d3b);
Vec3.scale(origin, origin, 1 / 8);
return Axes3D.create(origin, dirA, dirB, dirC);
}
PrincipalAxes.calculateBoxAxes = calculateBoxAxes;
})(PrincipalAxes || (PrincipalAxes = {}));
//# sourceMappingURL=principal-axes.js.map