StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics
https://doi.org/10.1109/TVCG.2020.3030352
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.
179 lines
5.9 KiB
179 lines
5.9 KiB
/*jshint unused:true*/
|
|
/*
|
|
Input: matrix ; a 4x4 matrix
|
|
Output: translation ; a 3 component vector
|
|
scale ; a 3 component vector
|
|
skew ; skew factors XY,XZ,YZ represented as a 3 component vector
|
|
perspective ; a 4 component vector
|
|
quaternion ; a 4 component vector
|
|
Returns false if the matrix cannot be decomposed, true if it can
|
|
|
|
|
|
References:
|
|
https://github.com/kamicane/matrix3d/blob/master/lib/Matrix3d.js
|
|
https://github.com/ChromiumWebApps/chromium/blob/master/ui/gfx/transform_util.cc
|
|
http://www.w3.org/TR/css3-transforms/#decomposing-a-3d-matrix
|
|
*/
|
|
|
|
var normalize = require('./normalize')
|
|
|
|
var create = require('gl-mat4/create')
|
|
var clone = require('gl-mat4/clone')
|
|
var determinant = require('gl-mat4/determinant')
|
|
var invert = require('gl-mat4/invert')
|
|
var transpose = require('gl-mat4/transpose')
|
|
var vec3 = {
|
|
length: require('gl-vec3/length'),
|
|
normalize: require('gl-vec3/normalize'),
|
|
dot: require('gl-vec3/dot'),
|
|
cross: require('gl-vec3/cross')
|
|
}
|
|
|
|
var tmp = create()
|
|
var perspectiveMatrix = create()
|
|
var tmpVec4 = [0, 0, 0, 0]
|
|
var row = [ [0,0,0], [0,0,0], [0,0,0] ]
|
|
var pdum3 = [0,0,0]
|
|
|
|
module.exports = function decomposeMat4(matrix, translation, scale, skew, perspective, quaternion) {
|
|
if (!translation) translation = [0,0,0]
|
|
if (!scale) scale = [0,0,0]
|
|
if (!skew) skew = [0,0,0]
|
|
if (!perspective) perspective = [0,0,0,1]
|
|
if (!quaternion) quaternion = [0,0,0,1]
|
|
|
|
//normalize, if not possible then bail out early
|
|
if (!normalize(tmp, matrix))
|
|
return false
|
|
|
|
// perspectiveMatrix is used to solve for perspective, but it also provides
|
|
// an easy way to test for singularity of the upper 3x3 component.
|
|
clone(perspectiveMatrix, tmp)
|
|
|
|
perspectiveMatrix[3] = 0
|
|
perspectiveMatrix[7] = 0
|
|
perspectiveMatrix[11] = 0
|
|
perspectiveMatrix[15] = 1
|
|
|
|
// If the perspectiveMatrix is not invertible, we are also unable to
|
|
// decompose, so we'll bail early. Constant taken from SkMatrix44::invert.
|
|
if (Math.abs(determinant(perspectiveMatrix) < 1e-8))
|
|
return false
|
|
|
|
var a03 = tmp[3], a13 = tmp[7], a23 = tmp[11],
|
|
a30 = tmp[12], a31 = tmp[13], a32 = tmp[14], a33 = tmp[15]
|
|
|
|
// First, isolate perspective.
|
|
if (a03 !== 0 || a13 !== 0 || a23 !== 0) {
|
|
tmpVec4[0] = a03
|
|
tmpVec4[1] = a13
|
|
tmpVec4[2] = a23
|
|
tmpVec4[3] = a33
|
|
|
|
// Solve the equation by inverting perspectiveMatrix and multiplying
|
|
// rightHandSide by the inverse.
|
|
// resuing the perspectiveMatrix here since it's no longer needed
|
|
var ret = invert(perspectiveMatrix, perspectiveMatrix)
|
|
if (!ret) return false
|
|
transpose(perspectiveMatrix, perspectiveMatrix)
|
|
|
|
//multiply by transposed inverse perspective matrix, into perspective vec4
|
|
vec4multMat4(perspective, tmpVec4, perspectiveMatrix)
|
|
} else {
|
|
//no perspective
|
|
perspective[0] = perspective[1] = perspective[2] = 0
|
|
perspective[3] = 1
|
|
}
|
|
|
|
// Next take care of translation
|
|
translation[0] = a30
|
|
translation[1] = a31
|
|
translation[2] = a32
|
|
|
|
// Now get scale and shear. 'row' is a 3 element array of 3 component vectors
|
|
mat3from4(row, tmp)
|
|
|
|
// Compute X scale factor and normalize first row.
|
|
scale[0] = vec3.length(row[0])
|
|
vec3.normalize(row[0], row[0])
|
|
|
|
// Compute XY shear factor and make 2nd row orthogonal to 1st.
|
|
skew[0] = vec3.dot(row[0], row[1])
|
|
combine(row[1], row[1], row[0], 1.0, -skew[0])
|
|
|
|
// Now, compute Y scale and normalize 2nd row.
|
|
scale[1] = vec3.length(row[1])
|
|
vec3.normalize(row[1], row[1])
|
|
skew[0] /= scale[1]
|
|
|
|
// Compute XZ and YZ shears, orthogonalize 3rd row
|
|
skew[1] = vec3.dot(row[0], row[2])
|
|
combine(row[2], row[2], row[0], 1.0, -skew[1])
|
|
skew[2] = vec3.dot(row[1], row[2])
|
|
combine(row[2], row[2], row[1], 1.0, -skew[2])
|
|
|
|
// Next, get Z scale and normalize 3rd row.
|
|
scale[2] = vec3.length(row[2])
|
|
vec3.normalize(row[2], row[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.
|
|
vec3.cross(pdum3, row[1], row[2])
|
|
if (vec3.dot(row[0], pdum3) < 0) {
|
|
for (var 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]
|
|
return true
|
|
}
|
|
|
|
//will be replaced by gl-vec4 eventually
|
|
function vec4multMat4(out, a, m) {
|
|
var x = a[0], y = a[1], z = a[2], w = a[3];
|
|
out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
|
|
out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
|
|
out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
|
|
out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
|
|
return out;
|
|
}
|
|
|
|
//gets upper-left of a 4x4 matrix into a 3x3 of vectors
|
|
function mat3from4(out, mat4x4) {
|
|
out[0][0] = mat4x4[0]
|
|
out[0][1] = mat4x4[1]
|
|
out[0][2] = mat4x4[2]
|
|
|
|
out[1][0] = mat4x4[4]
|
|
out[1][1] = mat4x4[5]
|
|
out[1][2] = mat4x4[6]
|
|
|
|
out[2][0] = mat4x4[8]
|
|
out[2][1] = mat4x4[9]
|
|
out[2][2] = mat4x4[10]
|
|
}
|
|
|
|
function combine(out, a, b, scale1, scale2) {
|
|
out[0] = a[0] * scale1 + b[0] * scale2
|
|
out[1] = a[1] * scale1 + b[1] * scale2
|
|
out[2] = a[2] * scale1 + b[2] * scale2
|
|
} |