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.
StackGenVis/frontend/node_modules/gl-error3d/errorbars.js

250 lines
6.3 KiB

4 years ago
'use strict'
module.exports = createErrorBars
var createBuffer = require('gl-buffer')
var createVAO = require('gl-vao')
var createShader = require('./shaders/index')
var IDENTITY = [1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1]
function ErrorBars(gl, buffer, vao, shader) {
this.gl = gl
this.shader = shader
this.buffer = buffer
this.vao = vao
this.pixelRatio = 1
this.bounds = [[ Infinity, Infinity, Infinity], [-Infinity,-Infinity,-Infinity]]
this.clipBounds = [[-Infinity,-Infinity,-Infinity], [ Infinity, Infinity, Infinity]]
this.lineWidth = [1,1,1]
this.capSize = [10,10,10]
this.lineCount = [0,0,0]
this.lineOffset = [0,0,0]
this.opacity = 1
this.hasAlpha = false
}
var proto = ErrorBars.prototype
proto.isOpaque = function() {
return !this.hasAlpha
}
proto.isTransparent = function() {
return this.hasAlpha
}
proto.drawTransparent = proto.draw = function(cameraParams) {
var gl = this.gl
var uniforms = this.shader.uniforms
this.shader.bind()
var view = uniforms.view = cameraParams.view || IDENTITY
var projection = uniforms.projection = cameraParams.projection || IDENTITY
uniforms.model = cameraParams.model || IDENTITY
uniforms.clipBounds = this.clipBounds
uniforms.opacity = this.opacity
var cx = view[12]
var cy = view[13]
var cz = view[14]
var cw = view[15]
var isOrtho = cameraParams._ortho || false
var orthoFix = (isOrtho) ? 2 : 1 // double up padding for orthographic ticks & labels
var pixelScaleF = orthoFix * this.pixelRatio * (projection[3]*cx + projection[7]*cy + projection[11]*cz + projection[15]*cw) / gl.drawingBufferHeight
this.vao.bind()
for(var i=0; i<3; ++i) {
gl.lineWidth(this.lineWidth[i] * this.pixelRatio)
uniforms.capSize = this.capSize[i] * pixelScaleF
if (this.lineCount[i]) {
gl.drawArrays(gl.LINES, this.lineOffset[i], this.lineCount[i])
}
}
this.vao.unbind()
}
function updateBounds(bounds, point) {
for(var i=0; i<3; ++i) {
bounds[0][i] = Math.min(bounds[0][i], point[i])
bounds[1][i] = Math.max(bounds[1][i], point[i])
}
}
var FACE_TABLE = (function(){
var table = new Array(3)
for(var d=0; d<3; ++d) {
var row = []
for(var j=1; j<=2; ++j) {
for(var s=-1; s<=1; s+=2) {
var u = (j+d) % 3
var y = [0,0,0]
y[u] = s
row.push(y)
}
}
table[d] = row
}
return table
})()
function emitFace(verts, x, c, d) {
var offsets = FACE_TABLE[d]
for(var i=0; i<offsets.length; ++i) {
var o = offsets[i]
verts.push(x[0], x[1], x[2],
c[0], c[1], c[2], c[3],
o[0], o[1], o[2])
}
return offsets.length
}
proto.update = function(options) {
options = options || {}
if('lineWidth' in options) {
this.lineWidth = options.lineWidth
if(!Array.isArray(this.lineWidth)) {
this.lineWidth = [this.lineWidth, this.lineWidth, this.lineWidth]
}
}
if('capSize' in options) {
this.capSize = options.capSize
if(!Array.isArray(this.capSize)) {
this.capSize = [this.capSize, this.capSize, this.capSize]
}
}
this.hasAlpha = false // default to no transparent draw
if('opacity' in options) {
this.opacity = +options.opacity
if(this.opacity < 1) {
this.hasAlpha = true;
}
}
var color = options.color || [[0,0,0],[0,0,0],[0,0,0]]
var position = options.position
var error = options.error
if(!Array.isArray(color[0])) {
color = [color,color,color]
}
if(position && error) {
var verts = []
var n = position.length
var vertexCount = 0
this.bounds = [[ Infinity, Infinity, Infinity],
[-Infinity,-Infinity,-Infinity]]
this.lineCount = [0,0,0]
//Build geometry for lines
for(var j=0; j<3; ++j) {
this.lineOffset[j] = vertexCount
i_loop:
for(var i=0; i<n; ++i) {
var p = position[i]
for(var k=0; k<3; ++k) {
if(isNaN(p[k]) || !isFinite(p[k])) {
continue i_loop
}
}
var e = error[i]
var c = color[j]
if(Array.isArray(c[0])) {
c = color[i]
}
if(c.length === 3) {
c = [c[0], c[1], c[2], 1]
} else if(c.length === 4) {
c = [c[0], c[1], c[2], c[3]]
if(!this.hasAlpha && c[3] < 1) this.hasAlpha = true
}
if(isNaN(e[0][j]) || isNaN(e[1][j])) {
continue
}
if(e[0][j] < 0) {
var x = p.slice()
x[j] += e[0][j]
verts.push(p[0], p[1], p[2],
c[0], c[1], c[2], c[3],
0, 0, 0,
x[0], x[1], x[2],
c[0], c[1], c[2], c[3],
0, 0, 0)
updateBounds(this.bounds, x)
vertexCount += 2 + emitFace(verts, x, c, j)
}
if(e[1][j] > 0) {
var x = p.slice()
x[j] += e[1][j]
verts.push(p[0], p[1], p[2],
c[0], c[1], c[2], c[3],
0, 0, 0,
x[0], x[1], x[2],
c[0], c[1], c[2], c[3],
0, 0, 0)
updateBounds(this.bounds, x)
vertexCount += 2 + emitFace(verts, x, c, j)
}
}
this.lineCount[j] = vertexCount - this.lineOffset[j]
}
this.buffer.update(verts)
}
}
proto.dispose = function() {
this.shader.dispose()
this.buffer.dispose()
this.vao.dispose()
}
function createErrorBars(options) {
var gl = options.gl
var buffer = createBuffer(gl)
var vao = createVAO(gl, [
{
buffer: buffer,
type: gl.FLOAT,
size: 3,
offset: 0,
stride: 40
},
{
buffer: buffer,
type: gl.FLOAT,
size: 4,
offset: 12,
stride: 40
},
{
buffer: buffer,
type: gl.FLOAT,
size: 3,
offset: 28,
stride: 40
}
])
var shader = createShader(gl)
shader.attributes.position.location = 0
shader.attributes.color.location = 1
shader.attributes.offset.location = 2
var result = new ErrorBars(gl, buffer, vao, shader)
result.update(options)
return result
}