diff --git a/main.js b/main.js index a0c8b87..e7efecb 100644 --- a/main.js +++ b/main.js @@ -1,6 +1,6 @@ import { interpolate, turboColormapData } from "./colormap.js" import { bowyerWatson, Vertex } from "./delaunay.js" -import { Mat4, Quat, Vector3 } from "./math.js" +import { Mat4, Quat, Vector3, Vector4 } from "./math.js" import { getNumberOfStations, MoodyReport, SurfacePlate, roundTo } from "./moody.js" import WebGLDebugUtils from "./webgl-debug.js" @@ -264,12 +264,17 @@ let buffers = null let showLines = true let showHeatmap = true let lightingOn = true +// Saves the absolute transformations applied to the table already by user actions (from the start state that roughly centers the table view). let tableRotationMatrix = Mat4.create() let tableScaleMatrix = Mat4.create() let tableTranslateMatrix = Mat4.create() +// The view matrix is set when a new table is created via initialize3DTableGraphic - it does not change between frames. let viewMatrix = Mat4.create() +// The projection matrix is set when a new table is created via initialize3DTableGraphic and if the canvas is resized. let projectionMatrix = Mat4.create() +let tableModelMatrix = Mat4.create() + /** * Converts a canvas-relative position (mouse coordinates) to clip space coordinates * normalized by the maximum dimension of the canvas's bounding rectangle. @@ -398,7 +403,7 @@ function initialize3DTableGraphic(moodyReport) { } document.onmouseup = () => { - startVectorMapped = null + startVectorMapped = null tableRotationMatrix = Mat4.create() } @@ -418,7 +423,7 @@ function initialize3DTableGraphic(moodyReport) { rotationQuat = new Quat(startVectorMapped.dot(currentVectorMapped), axis[0], -axis[1], 0) } - tableRotationMatrix = Mat4.create() + // tableRotationMatrix = Mat4.create() // We want rotation to be centered on the center of the table. tableRotationMatrix.translate([(boundingBoxCache[zMultiplier].maxX - boundingBoxCache[zMultiplier].minX) / 2, (boundingBoxCache[zMultiplier].maxY - boundingBoxCache[zMultiplier].minY) / 2, @@ -427,6 +432,8 @@ function initialize3DTableGraphic(moodyReport) { tableRotationMatrix.translate([-((boundingBoxCache[zMultiplier].maxX - boundingBoxCache[zMultiplier].minX) / 2), -((boundingBoxCache[zMultiplier].maxY - boundingBoxCache[zMultiplier].minY) / 2), -((boundingBoxCache[zMultiplier].maxZ - boundingBoxCache[zMultiplier].minZ) / 2)]) + startVectorMapped = mapToSphere(event.clientX, event.clientY, canvas) + } } @@ -531,6 +538,9 @@ function initialize3DTableGraphic(moodyReport) { now = updateFps(now) drawTableSurface(moodyReport, gl, programInfo, buffers, texture) + tableRotationMatrix = Mat4.create() + tableScaleMatrix = Mat4.create() + tableTranslateMatrix = Mat4.create() requestAnimationFrame(render) } requestAnimationFrame(render) @@ -572,7 +582,7 @@ function drawTableSurface(moodyReport, gl, programInfo, buffers, texture) { // We must set the model matrix to identity here because we are using relative (incremental) transforms. // We need to make it so that all of our event handlers only mess with currentTransformMatrix, and then that // will be applied to the model matrix. - const tableModelMatrix = Mat4.create() + // const tableModelMatrix = Mat4.create() tableModelMatrix.multiply(tableScaleMatrix) tableModelMatrix.multiply(tableTranslateMatrix) tableModelMatrix.multiply(tableRotationMatrix) diff --git a/math.js b/math.js index b7caefe..fab92e0 100644 --- a/math.js +++ b/math.js @@ -58,6 +58,11 @@ class Vector3 extends Float32Array { } } + // Creates a new (0, 0, 0) vector. + static create() { + return new Vector3() + } + equals(b) { return Vector3.equals(this, this, b) } @@ -158,8 +163,94 @@ class Vector3 extends Float32Array { get magnitude() { return Vector3.magnitude(this) } + + // Method to transform the vector with a 4x4 matrix + transformMat4(matrix) { + return Vector3.transformMat4(new Vector3(), this, matrix) + } + + // Static method to transform a vector with a 4x4 matrix + static transformMat4(out, a, matrix) { + if (matrix.length !== 16) { + throw new Error("Matrix must be a 4x4 (16 elements).") + } + + const x = a.x + const y = a.y + const z = a.z + + out[0] = matrix[0] * x + matrix[4] * y + matrix[8] * z + matrix[12] + out[1] = matrix[1] * x + matrix[5] * y + matrix[9] * z + matrix[13] + out[2] = matrix[2] * x + matrix[6] * y + matrix[10] * z + matrix[14] + + return out + } +} + +class Vector4 extends Float32Array { + constructor(...values) { + switch (values.length) { + case 4: + super(values); + break; + case 3: + super([...values, 1]); // Default w to 1 if not provided + break; + case 2: + super([...values, 0, 1]); // Default z to 0, w to 1 + break; + case 1: { + const v = values[0]; + if (typeof v === 'number') { + super([v, v, v, 1]); // Default w to 1 for scalar initialization + } else { + super([...v, ...Array(4 - v.length).fill(1)]); + } + break; + } + default: + super(4); // Default to a zero vector of size 4 + break; + } + } + + // Creates a new (0, 0, 0, 0) vector. + static create() { + return new Vector4() + } + + get w() { return this[0] } + get x() { return this[1] } + get y() { return this[2] } + get z() { return this[3] } + + // Method to transform the vector with a 4x4 matrix + transformMat4(matrix) { + return Vector4.transformMat4(this, this, matrix); + } + + // Static method to transform a vector with a 4x4 matrix + static transformMat4(out, a, matrix) { + if (matrix.length !== 16) { + throw new Error("Matrix must be a 4x4 (16 elements)."); + } + + const x = a[0], y = a[1], z = a[2], w = a[3]; + + out[0] = matrix[0] * x + matrix[4] * y + matrix[8] * z + matrix[12] * w; + out[1] = matrix[1] * x + matrix[5] * y + matrix[9] * z + matrix[13] * w; + out[2] = matrix[2] * x + matrix[6] * y + matrix[10] * z + matrix[14] * w; + out[3] = matrix[3] * x + matrix[7] * y + matrix[11] * z + matrix[15] * w; + + return out; + } + + toString() { + return `[${this[0]}, ${this[1]}, ${this[2]}, ${this[3]}]`; + } } + const IDENTITY_4X4 = new Float32Array([ 1, 0, 0, 0, 0, 1, 0, 0, @@ -620,4 +711,4 @@ class Quat extends Float32Array { tmpVec3 = new Float32Array(3) } -export { Mat4, Quat, Vector3 } +export { Mat4, Quat, Vector3, Vector4 }