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.
199 lines
4.7 KiB
199 lines
4.7 KiB
4 years ago
|
'use strict'
|
||
|
|
||
|
var bsearch = require('binary-search-bounds')
|
||
|
var m4interp = require('mat4-interpolate')
|
||
|
var invert44 = require('gl-mat4/invert')
|
||
|
var rotateX = require('gl-mat4/rotateX')
|
||
|
var rotateY = require('gl-mat4/rotateY')
|
||
|
var rotateZ = require('gl-mat4/rotateZ')
|
||
|
var lookAt = require('gl-mat4/lookAt')
|
||
|
var translate = require('gl-mat4/translate')
|
||
|
var scale = require('gl-mat4/scale')
|
||
|
var normalize = require('gl-vec3/normalize')
|
||
|
|
||
|
var DEFAULT_CENTER = [0,0,0]
|
||
|
|
||
|
module.exports = createMatrixCameraController
|
||
|
|
||
|
function MatrixCameraController(initialMatrix) {
|
||
|
this._components = initialMatrix.slice()
|
||
|
this._time = [0]
|
||
|
this.prevMatrix = initialMatrix.slice()
|
||
|
this.nextMatrix = initialMatrix.slice()
|
||
|
this.computedMatrix = initialMatrix.slice()
|
||
|
this.computedInverse = initialMatrix.slice()
|
||
|
this.computedEye = [0,0,0]
|
||
|
this.computedUp = [0,0,0]
|
||
|
this.computedCenter = [0,0,0]
|
||
|
this.computedRadius = [0]
|
||
|
this._limits = [-Infinity, Infinity]
|
||
|
}
|
||
|
|
||
|
var proto = MatrixCameraController.prototype
|
||
|
|
||
|
proto.recalcMatrix = function(t) {
|
||
|
var time = this._time
|
||
|
var tidx = bsearch.le(time, t)
|
||
|
var mat = this.computedMatrix
|
||
|
if(tidx < 0) {
|
||
|
return
|
||
|
}
|
||
|
var comps = this._components
|
||
|
if(tidx === time.length-1) {
|
||
|
var ptr = 16*tidx
|
||
|
for(var i=0; i<16; ++i) {
|
||
|
mat[i] = comps[ptr++]
|
||
|
}
|
||
|
} else {
|
||
|
var dt = (time[tidx+1] - time[tidx])
|
||
|
var ptr = 16*tidx
|
||
|
var prev = this.prevMatrix
|
||
|
var allEqual = true
|
||
|
for(var i=0; i<16; ++i) {
|
||
|
prev[i] = comps[ptr++]
|
||
|
}
|
||
|
var next = this.nextMatrix
|
||
|
for(var i=0; i<16; ++i) {
|
||
|
next[i] = comps[ptr++]
|
||
|
allEqual = allEqual && (prev[i] === next[i])
|
||
|
}
|
||
|
if(dt < 1e-6 || allEqual) {
|
||
|
for(var i=0; i<16; ++i) {
|
||
|
mat[i] = prev[i]
|
||
|
}
|
||
|
} else {
|
||
|
m4interp(mat, prev, next, (t - time[tidx])/dt)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var up = this.computedUp
|
||
|
up[0] = mat[1]
|
||
|
up[1] = mat[5]
|
||
|
up[2] = mat[9]
|
||
|
normalize(up, up)
|
||
|
|
||
|
var imat = this.computedInverse
|
||
|
invert44(imat, mat)
|
||
|
var eye = this.computedEye
|
||
|
var w = imat[15]
|
||
|
eye[0] = imat[12]/w
|
||
|
eye[1] = imat[13]/w
|
||
|
eye[2] = imat[14]/w
|
||
|
|
||
|
var center = this.computedCenter
|
||
|
var radius = Math.exp(this.computedRadius[0])
|
||
|
for(var i=0; i<3; ++i) {
|
||
|
center[i] = eye[i] - mat[2+4*i] * radius
|
||
|
}
|
||
|
}
|
||
|
|
||
|
proto.idle = function(t) {
|
||
|
if(t < this.lastT()) {
|
||
|
return
|
||
|
}
|
||
|
var mc = this._components
|
||
|
var ptr = mc.length-16
|
||
|
for(var i=0; i<16; ++i) {
|
||
|
mc.push(mc[ptr++])
|
||
|
}
|
||
|
this._time.push(t)
|
||
|
}
|
||
|
|
||
|
proto.flush = function(t) {
|
||
|
var idx = bsearch.gt(this._time, t) - 2
|
||
|
if(idx < 0) {
|
||
|
return
|
||
|
}
|
||
|
this._time.splice(0, idx)
|
||
|
this._components.splice(0, 16*idx)
|
||
|
}
|
||
|
|
||
|
proto.lastT = function() {
|
||
|
return this._time[this._time.length-1]
|
||
|
}
|
||
|
|
||
|
proto.lookAt = function(t, eye, center, up) {
|
||
|
this.recalcMatrix(t)
|
||
|
eye = eye || this.computedEye
|
||
|
center = center || DEFAULT_CENTER
|
||
|
up = up || this.computedUp
|
||
|
this.setMatrix(t, lookAt(this.computedMatrix, eye, center, up))
|
||
|
var d2 = 0.0
|
||
|
for(var i=0; i<3; ++i) {
|
||
|
d2 += Math.pow(center[i] - eye[i], 2)
|
||
|
}
|
||
|
d2 = Math.log(Math.sqrt(d2))
|
||
|
this.computedRadius[0] = d2
|
||
|
}
|
||
|
|
||
|
proto.rotate = function(t, yaw, pitch, roll) {
|
||
|
this.recalcMatrix(t)
|
||
|
var mat = this.computedInverse
|
||
|
if(yaw) rotateY(mat, mat, yaw)
|
||
|
if(pitch) rotateX(mat, mat, pitch)
|
||
|
if(roll) rotateZ(mat, mat, roll)
|
||
|
this.setMatrix(t, invert44(this.computedMatrix, mat))
|
||
|
}
|
||
|
|
||
|
var tvec = [0,0,0]
|
||
|
|
||
|
proto.pan = function(t, dx, dy, dz) {
|
||
|
tvec[0] = -(dx || 0.0)
|
||
|
tvec[1] = -(dy || 0.0)
|
||
|
tvec[2] = -(dz || 0.0)
|
||
|
this.recalcMatrix(t)
|
||
|
var mat = this.computedInverse
|
||
|
translate(mat, mat, tvec)
|
||
|
this.setMatrix(t, invert44(mat, mat))
|
||
|
}
|
||
|
|
||
|
proto.translate = function(t, dx, dy, dz) {
|
||
|
tvec[0] = dx || 0.0
|
||
|
tvec[1] = dy || 0.0
|
||
|
tvec[2] = dz || 0.0
|
||
|
this.recalcMatrix(t)
|
||
|
var mat = this.computedMatrix
|
||
|
translate(mat, mat, tvec)
|
||
|
this.setMatrix(t, mat)
|
||
|
}
|
||
|
|
||
|
proto.setMatrix = function(t, mat) {
|
||
|
if(t < this.lastT()) {
|
||
|
return
|
||
|
}
|
||
|
this._time.push(t)
|
||
|
for(var i=0; i<16; ++i) {
|
||
|
this._components.push(mat[i])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
proto.setDistance = function(t, d) {
|
||
|
this.computedRadius[0] = d
|
||
|
}
|
||
|
|
||
|
proto.setDistanceLimits = function(a,b) {
|
||
|
var lim = this._limits
|
||
|
lim[0] = a
|
||
|
lim[1] = b
|
||
|
}
|
||
|
|
||
|
proto.getDistanceLimits = function(out) {
|
||
|
var lim = this._limits
|
||
|
if(out) {
|
||
|
out[0] = lim[0]
|
||
|
out[1] = lim[1]
|
||
|
return out
|
||
|
}
|
||
|
return lim
|
||
|
}
|
||
|
|
||
|
function createMatrixCameraController(options) {
|
||
|
options = options || {}
|
||
|
var matrix = options.matrix ||
|
||
|
[1,0,0,0,
|
||
|
0,1,0,0,
|
||
|
0,0,1,0,
|
||
|
0,0,0,1]
|
||
|
return new MatrixCameraController(matrix)
|
||
|
}
|