This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
604 lines
18 KiB
604 lines
18 KiB
/** |
|
* Copyright (c) 2015-present, Facebook, Inc. |
|
* |
|
* This source code is licensed under the MIT license found in the |
|
* LICENSE file in the root directory of this source tree. |
|
* |
|
* @providesModule MatrixMath |
|
* @noflow |
|
*/ |
|
/* eslint-disable space-infix-ops */ |
|
'use strict'; |
|
|
|
var invariant = require('fbjs/lib/invariant'); |
|
|
|
/** |
|
* Memory conservative (mutative) matrix math utilities. Uses "command" |
|
* matrices, which are reusable. |
|
*/ |
|
var MatrixMath = { |
|
createIdentityMatrix: function() { |
|
return [ |
|
1,0,0,0, |
|
0,1,0,0, |
|
0,0,1,0, |
|
0,0,0,1 |
|
]; |
|
}, |
|
|
|
createCopy: function(m) { |
|
return [ |
|
m[0], m[1], m[2], m[3], |
|
m[4], m[5], m[6], m[7], |
|
m[8], m[9], m[10], m[11], |
|
m[12], m[13], m[14], m[15], |
|
]; |
|
}, |
|
|
|
createOrthographic: function(left, right, bottom, top, near, far) { |
|
var a = 2 / (right - left); |
|
var b = 2 / (top - bottom); |
|
var c = -2 / (far - near); |
|
|
|
var tx = -(right + left) / (right - left); |
|
var ty = -(top + bottom) / (top - bottom); |
|
var tz = -(far + near) / (far - near); |
|
|
|
return [ |
|
a, 0, 0, 0, |
|
0, b, 0, 0, |
|
0, 0, c, 0, |
|
tx, ty, tz, 1 |
|
]; |
|
}, |
|
|
|
createFrustum: function(left, right, bottom, top, near, far) { |
|
var r_width = 1 / (right - left); |
|
var r_height = 1 / (top - bottom); |
|
var r_depth = 1 / (near - far); |
|
var x = 2 * (near * r_width); |
|
var y = 2 * (near * r_height); |
|
var A = (right + left) * r_width; |
|
var B = (top + bottom) * r_height; |
|
var C = (far + near) * r_depth; |
|
var D = 2 * (far * near * r_depth); |
|
return [ |
|
x, 0, 0, 0, |
|
0, y, 0, 0, |
|
A, B, C,-1, |
|
0, 0, D, 0, |
|
]; |
|
}, |
|
|
|
/** |
|
* This create a perspective projection towards negative z |
|
* Clipping the z range of [-near, -far] |
|
* |
|
* @param fovInRadians - field of view in randians |
|
*/ |
|
createPerspective: function(fovInRadians, aspect, near, far) { |
|
var h = 1 / Math.tan(fovInRadians / 2); |
|
var r_depth = 1 / (near - far); |
|
var C = (far + near) * r_depth; |
|
var D = 2 * (far * near * r_depth); |
|
return [ |
|
h/aspect, 0, 0, 0, |
|
0, h, 0, 0, |
|
0, 0, C,-1, |
|
0, 0, D, 0, |
|
]; |
|
}, |
|
|
|
createTranslate2d: function(x, y) { |
|
var mat = MatrixMath.createIdentityMatrix(); |
|
MatrixMath.reuseTranslate2dCommand(mat, x, y); |
|
return mat; |
|
}, |
|
|
|
reuseTranslate2dCommand: function(matrixCommand, x, y) { |
|
matrixCommand[12] = x; |
|
matrixCommand[13] = y; |
|
}, |
|
|
|
reuseTranslate3dCommand: function(matrixCommand, x, y, z) { |
|
matrixCommand[12] = x; |
|
matrixCommand[13] = y; |
|
matrixCommand[14] = z; |
|
}, |
|
|
|
createScale: function(factor) { |
|
var mat = MatrixMath.createIdentityMatrix(); |
|
MatrixMath.reuseScaleCommand(mat, factor); |
|
return mat; |
|
}, |
|
|
|
reuseScaleCommand: function(matrixCommand, factor) { |
|
matrixCommand[0] = factor; |
|
matrixCommand[5] = factor; |
|
}, |
|
|
|
reuseScale3dCommand: function(matrixCommand, x, y, z) { |
|
matrixCommand[0] = x; |
|
matrixCommand[5] = y; |
|
matrixCommand[10] = z; |
|
}, |
|
|
|
reusePerspectiveCommand: function(matrixCommand, p) { |
|
matrixCommand[11] = -1 / p; |
|
}, |
|
|
|
reuseScaleXCommand(matrixCommand, factor) { |
|
matrixCommand[0] = factor; |
|
}, |
|
|
|
reuseScaleYCommand(matrixCommand, factor) { |
|
matrixCommand[5] = factor; |
|
}, |
|
|
|
reuseScaleZCommand(matrixCommand, factor) { |
|
matrixCommand[10] = factor; |
|
}, |
|
|
|
reuseRotateXCommand: function(matrixCommand, radians) { |
|
matrixCommand[5] = Math.cos(radians); |
|
matrixCommand[6] = Math.sin(radians); |
|
matrixCommand[9] = -Math.sin(radians); |
|
matrixCommand[10] = Math.cos(radians); |
|
}, |
|
|
|
reuseRotateYCommand: function(matrixCommand, amount) { |
|
matrixCommand[0] = Math.cos(amount); |
|
matrixCommand[2] = -Math.sin(amount); |
|
matrixCommand[8] = Math.sin(amount); |
|
matrixCommand[10] = Math.cos(amount); |
|
}, |
|
|
|
// http://www.w3.org/TR/css3-transforms/#recomposing-to-a-2d-matrix |
|
reuseRotateZCommand: function(matrixCommand, radians) { |
|
matrixCommand[0] = Math.cos(radians); |
|
matrixCommand[1] = Math.sin(radians); |
|
matrixCommand[4] = -Math.sin(radians); |
|
matrixCommand[5] = Math.cos(radians); |
|
}, |
|
|
|
createRotateZ: function(radians) { |
|
var mat = MatrixMath.createIdentityMatrix(); |
|
MatrixMath.reuseRotateZCommand(mat, radians); |
|
return mat; |
|
}, |
|
|
|
reuseSkewXCommand: function(matrixCommand, radians) { |
|
matrixCommand[4] = Math.tan(radians); |
|
}, |
|
|
|
reuseSkewYCommand: function(matrixCommand, radians) { |
|
matrixCommand[1] = Math.tan(radians); |
|
}, |
|
|
|
multiplyInto: function(out, a, b) { |
|
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], |
|
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], |
|
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], |
|
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; |
|
|
|
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; |
|
out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; |
|
out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; |
|
out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; |
|
out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; |
|
|
|
b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; |
|
out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; |
|
out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; |
|
out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; |
|
out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; |
|
|
|
b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; |
|
out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; |
|
out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; |
|
out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; |
|
out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; |
|
|
|
b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; |
|
out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; |
|
out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; |
|
out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; |
|
out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; |
|
}, |
|
|
|
determinant(matrix: Array<number>): number { |
|
var [ |
|
m00, m01, m02, m03, |
|
m10, m11, m12, m13, |
|
m20, m21, m22, m23, |
|
m30, m31, m32, m33 |
|
] = matrix; |
|
return ( |
|
m03 * m12 * m21 * m30 - m02 * m13 * m21 * m30 - |
|
m03 * m11 * m22 * m30 + m01 * m13 * m22 * m30 + |
|
m02 * m11 * m23 * m30 - m01 * m12 * m23 * m30 - |
|
m03 * m12 * m20 * m31 + m02 * m13 * m20 * m31 + |
|
m03 * m10 * m22 * m31 - m00 * m13 * m22 * m31 - |
|
m02 * m10 * m23 * m31 + m00 * m12 * m23 * m31 + |
|
m03 * m11 * m20 * m32 - m01 * m13 * m20 * m32 - |
|
m03 * m10 * m21 * m32 + m00 * m13 * m21 * m32 + |
|
m01 * m10 * m23 * m32 - m00 * m11 * m23 * m32 - |
|
m02 * m11 * m20 * m33 + m01 * m12 * m20 * m33 + |
|
m02 * m10 * m21 * m33 - m00 * m12 * m21 * m33 - |
|
m01 * m10 * m22 * m33 + m00 * m11 * m22 * m33 |
|
); |
|
}, |
|
|
|
/** |
|
* Inverse of a matrix. Multiplying by the inverse is used in matrix math |
|
* instead of division. |
|
* |
|
* Formula from: |
|
* http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm |
|
*/ |
|
inverse(matrix: Array<number>): Array<number> { |
|
var det = MatrixMath.determinant(matrix); |
|
if (!det) { |
|
return matrix; |
|
} |
|
var [ |
|
m00, m01, m02, m03, |
|
m10, m11, m12, m13, |
|
m20, m21, m22, m23, |
|
m30, m31, m32, m33 |
|
] = matrix; |
|
return [ |
|
(m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33) / det, |
|
(m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33) / det, |
|
(m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33) / det, |
|
(m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23) / det, |
|
(m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33) / det, |
|
(m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33) / det, |
|
(m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33) / det, |
|
(m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23) / det, |
|
(m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33) / det, |
|
(m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33) / det, |
|
(m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33) / det, |
|
(m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23) / det, |
|
(m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32) / det, |
|
(m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32) / det, |
|
(m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32) / det, |
|
(m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22) / det |
|
]; |
|
}, |
|
|
|
/** |
|
* Turns columns into rows and rows into columns. |
|
*/ |
|
transpose(m: Array<number>): Array<number> { |
|
return [ |
|
m[0], m[4], m[8], m[12], |
|
m[1], m[5], m[9], m[13], |
|
m[2], m[6], m[10], m[14], |
|
m[3], m[7], m[11], m[15] |
|
]; |
|
}, |
|
|
|
/** |
|
* Based on: http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c |
|
*/ |
|
multiplyVectorByMatrix( |
|
v: Array<number>, |
|
m: Array<number> |
|
): Array<number> { |
|
var [vx, vy, vz, vw] = v; |
|
return [ |
|
vx * m[0] + vy * m[4] + vz * m[8] + vw * m[12], |
|
vx * m[1] + vy * m[5] + vz * m[9] + vw * m[13], |
|
vx * m[2] + vy * m[6] + vz * m[10] + vw * m[14], |
|
vx * m[3] + vy * m[7] + vz * m[11] + vw * m[15] |
|
]; |
|
}, |
|
|
|
/** |
|
* From: https://code.google.com/p/webgl-mjs/source/browse/mjs.js |
|
*/ |
|
v3Length(a: Array<number>): number { |
|
return Math.sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); |
|
}, |
|
|
|
/** |
|
* Based on: https://code.google.com/p/webgl-mjs/source/browse/mjs.js |
|
*/ |
|
v3Normalize( |
|
vector: Array<number>, |
|
v3Length: number |
|
): Array<number> { |
|
var im = 1 / (v3Length || MatrixMath.v3Length(vector)); |
|
return [ |
|
vector[0] * im, |
|
vector[1] * im, |
|
vector[2] * im |
|
]; |
|
}, |
|
|
|
/** |
|
* The dot product of a and b, two 3-element vectors. |
|
* From: https://code.google.com/p/webgl-mjs/source/browse/mjs.js |
|
*/ |
|
v3Dot(a, b) { |
|
return a[0] * b[0] + |
|
a[1] * b[1] + |
|
a[2] * b[2]; |
|
}, |
|
|
|
/** |
|
* From: |
|
* http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp |
|
*/ |
|
v3Combine( |
|
a: Array<number>, |
|
b: Array<number>, |
|
aScale: number, |
|
bScale: number |
|
): Array<number> { |
|
return [ |
|
aScale * a[0] + bScale * b[0], |
|
aScale * a[1] + bScale * b[1], |
|
aScale * a[2] + bScale * b[2] |
|
]; |
|
}, |
|
|
|
/** |
|
* From: |
|
* http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp |
|
*/ |
|
v3Cross(a: Array<number>, b: Array<number>): Array<number> { |
|
return [ |
|
a[1] * b[2] - a[2] * b[1], |
|
a[2] * b[0] - a[0] * b[2], |
|
a[0] * b[1] - a[1] * b[0] |
|
]; |
|
}, |
|
|
|
/** |
|
* Based on: |
|
* http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/ |
|
* and: |
|
* http://quat.zachbennett.com/ |
|
* |
|
* Note that this rounds degrees to the thousandth of a degree, due to |
|
* floating point errors in the creation of the quaternion. |
|
* |
|
* Also note that this expects the qw value to be last, not first. |
|
* |
|
* Also, when researching this, remember that: |
|
* yaw === heading === z-axis |
|
* pitch === elevation/attitude === y-axis |
|
* roll === bank === x-axis |
|
*/ |
|
quaternionToDegreesXYZ(q: Array<number>, matrix, row): Array<number> { |
|
var [qx, qy, qz, qw] = q; |
|
var qw2 = qw * qw; |
|
var qx2 = qx * qx; |
|
var qy2 = qy * qy; |
|
var qz2 = qz * qz; |
|
var test = qx * qy + qz * qw; |
|
var unit = qw2 + qx2 + qy2 + qz2; |
|
var conv = 180 / Math.PI; |
|
|
|
if (test > 0.49999 * unit) { |
|
return [0, 2 * Math.atan2(qx, qw) * conv, 90]; |
|
} |
|
if (test < -0.49999 * unit) { |
|
return [0, -2 * Math.atan2(qx, qw) * conv, -90]; |
|
} |
|
|
|
return [ |
|
MatrixMath.roundTo3Places( |
|
Math.atan2(2*qx*qw-2*qy*qz,1-2*qx2-2*qz2) * conv |
|
), |
|
MatrixMath.roundTo3Places( |
|
Math.atan2(2*qy*qw-2*qx*qz,1-2*qy2-2*qz2) * conv |
|
), |
|
MatrixMath.roundTo3Places( |
|
Math.asin(2*qx*qy+2*qz*qw) * conv |
|
) |
|
]; |
|
}, |
|
|
|
/** |
|
* Based on: |
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round |
|
*/ |
|
roundTo3Places(n: number): number { |
|
var arr = n.toString().split('e'); |
|
return Math.round(arr[0] + 'e' + (arr[1] ? (+arr[1] - 3) : 3)) * 0.001; |
|
}, |
|
|
|
/** |
|
* Decompose a matrix into separate transform values, for use on platforms |
|
* where applying a precomposed matrix is not possible, and transforms are |
|
* applied in an inflexible ordering (e.g. Android). |
|
* |
|
* Implementation based on |
|
* http://www.w3.org/TR/css3-transforms/#decomposing-a-2d-matrix |
|
* http://www.w3.org/TR/css3-transforms/#decomposing-a-3d-matrix |
|
* which was based on |
|
* http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c |
|
*/ |
|
decomposeMatrix(transformMatrix: Array<number>): ?Object { |
|
|
|
invariant( |
|
transformMatrix.length === 16, |
|
'Matrix decomposition needs a list of 3d matrix values, received %s', |
|
transformMatrix |
|
); |
|
|
|
// output values |
|
var perspective = []; |
|
var quaternion = []; |
|
var scale = []; |
|
var skew = []; |
|
var translation = []; |
|
|
|
// create normalized, 2d array matrix |
|
// and normalized 1d array perspectiveMatrix with redefined 4th column |
|
if (!transformMatrix[15]) { |
|
return; |
|
} |
|
var matrix = []; |
|
var perspectiveMatrix = []; |
|
for (var i = 0; i < 4; i++) { |
|
matrix.push([]); |
|
for (var j = 0; j < 4; j++) { |
|
var value = transformMatrix[(i * 4) + j] / transformMatrix[15]; |
|
matrix[i].push(value); |
|
perspectiveMatrix.push(j === 3 ? 0 : value); |
|
} |
|
} |
|
perspectiveMatrix[15] = 1; |
|
|
|
// test for singularity of upper 3x3 part of the perspective matrix |
|
if (!MatrixMath.determinant(perspectiveMatrix)) { |
|
return; |
|
} |
|
|
|
// isolate perspective |
|
if (matrix[0][3] !== 0 || matrix[1][3] !== 0 || matrix[2][3] !== 0) { |
|
// rightHandSide is the right hand side of the equation. |
|
// rightHandSide is a vector, or point in 3d space relative to the origin. |
|
var rightHandSide = [ |
|
matrix[0][3], |
|
matrix[1][3], |
|
matrix[2][3], |
|
matrix[3][3] |
|
]; |
|
|
|
// Solve the equation by inverting perspectiveMatrix and multiplying |
|
// rightHandSide by the inverse. |
|
var inversePerspectiveMatrix = MatrixMath.inverse( |
|
perspectiveMatrix |
|
); |
|
var transposedInversePerspectiveMatrix = MatrixMath.transpose( |
|
inversePerspectiveMatrix |
|
); |
|
var perspective = MatrixMath.multiplyVectorByMatrix( |
|
rightHandSide, |
|
transposedInversePerspectiveMatrix |
|
); |
|
} else { |
|
// no perspective |
|
perspective[0] = perspective[1] = perspective[2] = 0; |
|
perspective[3] = 1; |
|
} |
|
|
|
// translation is simple |
|
for (var i = 0; i < 3; i++) { |
|
translation[i] = matrix[3][i]; |
|
} |
|
|
|
// Now get scale and shear. |
|
// 'row' is a 3 element array of 3 component vectors |
|
var row = []; |
|
for (i = 0; i < 3; i++) { |
|
row[i] = [ |
|
matrix[i][0], |
|
matrix[i][1], |
|
matrix[i][2] |
|
]; |
|
} |
|
|
|
// Compute X scale factor and normalize first row. |
|
scale[0] = MatrixMath.v3Length(row[0]); |
|
row[0] = MatrixMath.v3Normalize(row[0], scale[0]); |
|
|
|
// Compute XY shear factor and make 2nd row orthogonal to 1st. |
|
skew[0] = MatrixMath.v3Dot(row[0], row[1]); |
|
row[1] = MatrixMath.v3Combine(row[1], row[0], 1.0, -skew[0]); |
|
|
|
// Compute XY shear factor and make 2nd row orthogonal to 1st. |
|
skew[0] = MatrixMath.v3Dot(row[0], row[1]); |
|
row[1] = MatrixMath.v3Combine(row[1], row[0], 1.0, -skew[0]); |
|
|
|
// Now, compute Y scale and normalize 2nd row. |
|
scale[1] = MatrixMath.v3Length(row[1]); |
|
row[1] = MatrixMath.v3Normalize(row[1], scale[1]); |
|
skew[0] /= scale[1]; |
|
|
|
// Compute XZ and YZ shears, orthogonalize 3rd row |
|
skew[1] = MatrixMath.v3Dot(row[0], row[2]); |
|
row[2] = MatrixMath.v3Combine(row[2], row[0], 1.0, -skew[1]); |
|
skew[2] = MatrixMath.v3Dot(row[1], row[2]); |
|
row[2] = MatrixMath.v3Combine(row[2], row[1], 1.0, -skew[2]); |
|
|
|
// Next, get Z scale and normalize 3rd row. |
|
scale[2] = MatrixMath.v3Length(row[2]); |
|
row[2] = MatrixMath.v3Normalize(row[2], scale[2]); |
|
skew[1] /= scale[2]; |
|
skew[2] /= scale[2]; |
|
|
|
// At this point, the matrix (in rows) is orthonormal. |
|
// Check for a coordinate system flip. If the determinant |
|
// is -1, then negate the matrix and the scaling factors. |
|
var pdum3 = MatrixMath.v3Cross(row[1], row[2]); |
|
if (MatrixMath.v3Dot(row[0], pdum3) < 0) { |
|
for (i = 0; i < 3; i++) { |
|
scale[i] *= -1; |
|
row[i][0] *= -1; |
|
row[i][1] *= -1; |
|
row[i][2] *= -1; |
|
} |
|
} |
|
|
|
// Now, get the rotations out |
|
quaternion[0] = |
|
0.5 * Math.sqrt(Math.max(1 + row[0][0] - row[1][1] - row[2][2], 0)); |
|
quaternion[1] = |
|
0.5 * Math.sqrt(Math.max(1 - row[0][0] + row[1][1] - row[2][2], 0)); |
|
quaternion[2] = |
|
0.5 * Math.sqrt(Math.max(1 - row[0][0] - row[1][1] + row[2][2], 0)); |
|
quaternion[3] = |
|
0.5 * Math.sqrt(Math.max(1 + row[0][0] + row[1][1] + row[2][2], 0)); |
|
|
|
if (row[2][1] > row[1][2]) { |
|
quaternion[0] = -quaternion[0]; |
|
} |
|
if (row[0][2] > row[2][0]) { |
|
quaternion[1] = -quaternion[1]; |
|
} |
|
if (row[1][0] > row[0][1]) { |
|
quaternion[2] = -quaternion[2]; |
|
} |
|
|
|
// correct for occasional, weird Euler synonyms for 2d rotation |
|
var rotationDegrees; |
|
if ( |
|
quaternion[0] < 0.001 && quaternion[0] >= 0 && |
|
quaternion[1] < 0.001 && quaternion[1] >= 0 |
|
) { |
|
// this is a 2d rotation on the z-axis |
|
rotationDegrees = [0, 0, MatrixMath.roundTo3Places( |
|
Math.atan2(row[0][1], row[0][0]) * 180 / Math.PI |
|
)]; |
|
} else { |
|
rotationDegrees = MatrixMath.quaternionToDegreesXYZ(quaternion, matrix, row); |
|
} |
|
|
|
// expose both base data and convenience names |
|
return { |
|
rotationDegrees, |
|
perspective, |
|
quaternion, |
|
scale, |
|
skew, |
|
translation, |
|
|
|
rotate: rotationDegrees[2], |
|
rotateX: rotationDegrees[0], |
|
rotateY: rotationDegrees[1], |
|
scaleX: scale[0], |
|
scaleY: scale[1], |
|
translateX: translation[0], |
|
translateY: translation[1], |
|
}; |
|
}, |
|
|
|
}; |
|
|
|
module.exports = MatrixMath;
|
|
|