This repository has been archived on 2023-03-25. You can view files and clone it, but cannot push or open issues or pull requests.
mightyscape-1.1-deprecated/extensions/fablabchemnitz/papercraft/openjscad/node_modules/@jscad/csg/src/math/Matrix4.js

285 lines
10 KiB
JavaScript

const Vector3D = require('./Vector3')
const Vector2D = require('./Vector2')
const OrthoNormalBasis = require('./OrthoNormalBasis')
const Plane = require('./Plane')
// # class Matrix4x4:
// Represents a 4x4 matrix. Elements are specified in row order
const Matrix4x4 = function (elements) {
if (arguments.length >= 1) {
this.elements = elements
} else {
// if no arguments passed: create unity matrix
this.elements = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
}
}
Matrix4x4.prototype = {
plus: function (m) {
var r = []
for (var i = 0; i < 16; i++) {
r[i] = this.elements[i] + m.elements[i]
}
return new Matrix4x4(r)
},
minus: function (m) {
var r = []
for (var i = 0; i < 16; i++) {
r[i] = this.elements[i] - m.elements[i]
}
return new Matrix4x4(r)
},
// right multiply by another 4x4 matrix:
multiply: function (m) {
// cache elements in local variables, for speedup:
var this0 = this.elements[0]
var this1 = this.elements[1]
var this2 = this.elements[2]
var this3 = this.elements[3]
var this4 = this.elements[4]
var this5 = this.elements[5]
var this6 = this.elements[6]
var this7 = this.elements[7]
var this8 = this.elements[8]
var this9 = this.elements[9]
var this10 = this.elements[10]
var this11 = this.elements[11]
var this12 = this.elements[12]
var this13 = this.elements[13]
var this14 = this.elements[14]
var this15 = this.elements[15]
var m0 = m.elements[0]
var m1 = m.elements[1]
var m2 = m.elements[2]
var m3 = m.elements[3]
var m4 = m.elements[4]
var m5 = m.elements[5]
var m6 = m.elements[6]
var m7 = m.elements[7]
var m8 = m.elements[8]
var m9 = m.elements[9]
var m10 = m.elements[10]
var m11 = m.elements[11]
var m12 = m.elements[12]
var m13 = m.elements[13]
var m14 = m.elements[14]
var m15 = m.elements[15]
var result = []
result[0] = this0 * m0 + this1 * m4 + this2 * m8 + this3 * m12
result[1] = this0 * m1 + this1 * m5 + this2 * m9 + this3 * m13
result[2] = this0 * m2 + this1 * m6 + this2 * m10 + this3 * m14
result[3] = this0 * m3 + this1 * m7 + this2 * m11 + this3 * m15
result[4] = this4 * m0 + this5 * m4 + this6 * m8 + this7 * m12
result[5] = this4 * m1 + this5 * m5 + this6 * m9 + this7 * m13
result[6] = this4 * m2 + this5 * m6 + this6 * m10 + this7 * m14
result[7] = this4 * m3 + this5 * m7 + this6 * m11 + this7 * m15
result[8] = this8 * m0 + this9 * m4 + this10 * m8 + this11 * m12
result[9] = this8 * m1 + this9 * m5 + this10 * m9 + this11 * m13
result[10] = this8 * m2 + this9 * m6 + this10 * m10 + this11 * m14
result[11] = this8 * m3 + this9 * m7 + this10 * m11 + this11 * m15
result[12] = this12 * m0 + this13 * m4 + this14 * m8 + this15 * m12
result[13] = this12 * m1 + this13 * m5 + this14 * m9 + this15 * m13
result[14] = this12 * m2 + this13 * m6 + this14 * m10 + this15 * m14
result[15] = this12 * m3 + this13 * m7 + this14 * m11 + this15 * m15
return new Matrix4x4(result)
},
clone: function () {
var elements = this.elements.map(function (p) {
return p
})
return new Matrix4x4(elements)
},
// Right multiply the matrix by a Vector3D (interpreted as 3 row, 1 column)
// (result = M*v)
// Fourth element is taken as 1
rightMultiply1x3Vector: function (v) {
var v0 = v._x
var v1 = v._y
var v2 = v._z
var v3 = 1
var x = v0 * this.elements[0] + v1 * this.elements[1] + v2 * this.elements[2] + v3 * this.elements[3]
var y = v0 * this.elements[4] + v1 * this.elements[5] + v2 * this.elements[6] + v3 * this.elements[7]
var z = v0 * this.elements[8] + v1 * this.elements[9] + v2 * this.elements[10] + v3 * this.elements[11]
var w = v0 * this.elements[12] + v1 * this.elements[13] + v2 * this.elements[14] + v3 * this.elements[15]
// scale such that fourth element becomes 1:
if (w !== 1) {
var invw = 1.0 / w
x *= invw
y *= invw
z *= invw
}
return new Vector3D(x, y, z)
},
// Multiply a Vector3D (interpreted as 3 column, 1 row) by this matrix
// (result = v*M)
// Fourth element is taken as 1
leftMultiply1x3Vector: function (v) {
var v0 = v._x
var v1 = v._y
var v2 = v._z
var v3 = 1
var x = v0 * this.elements[0] + v1 * this.elements[4] + v2 * this.elements[8] + v3 * this.elements[12]
var y = v0 * this.elements[1] + v1 * this.elements[5] + v2 * this.elements[9] + v3 * this.elements[13]
var z = v0 * this.elements[2] + v1 * this.elements[6] + v2 * this.elements[10] + v3 * this.elements[14]
var w = v0 * this.elements[3] + v1 * this.elements[7] + v2 * this.elements[11] + v3 * this.elements[15]
// scale such that fourth element becomes 1:
if (w !== 1) {
var invw = 1.0 / w
x *= invw
y *= invw
z *= invw
}
return new Vector3D(x, y, z)
},
// Right multiply the matrix by a Vector2D (interpreted as 2 row, 1 column)
// (result = M*v)
// Fourth element is taken as 1
rightMultiply1x2Vector: function (v) {
var v0 = v.x
var v1 = v.y
var v2 = 0
var v3 = 1
var x = v0 * this.elements[0] + v1 * this.elements[1] + v2 * this.elements[2] + v3 * this.elements[3]
var y = v0 * this.elements[4] + v1 * this.elements[5] + v2 * this.elements[6] + v3 * this.elements[7]
var z = v0 * this.elements[8] + v1 * this.elements[9] + v2 * this.elements[10] + v3 * this.elements[11]
var w = v0 * this.elements[12] + v1 * this.elements[13] + v2 * this.elements[14] + v3 * this.elements[15]
// scale such that fourth element becomes 1:
if (w !== 1) {
var invw = 1.0 / w
x *= invw
y *= invw
z *= invw
}
return new Vector2D(x, y)
},
// Multiply a Vector2D (interpreted as 2 column, 1 row) by this matrix
// (result = v*M)
// Fourth element is taken as 1
leftMultiply1x2Vector: function (v) {
var v0 = v.x
var v1 = v.y
var v2 = 0
var v3 = 1
var x = v0 * this.elements[0] + v1 * this.elements[4] + v2 * this.elements[8] + v3 * this.elements[12]
var y = v0 * this.elements[1] + v1 * this.elements[5] + v2 * this.elements[9] + v3 * this.elements[13]
var z = v0 * this.elements[2] + v1 * this.elements[6] + v2 * this.elements[10] + v3 * this.elements[14]
var w = v0 * this.elements[3] + v1 * this.elements[7] + v2 * this.elements[11] + v3 * this.elements[15]
// scale such that fourth element becomes 1:
if (w !== 1) {
var invw = 1.0 / w
x *= invw
y *= invw
z *= invw
}
return new Vector2D(x, y)
},
// determine whether this matrix is a mirroring transformation
isMirroring: function () {
var u = new Vector3D(this.elements[0], this.elements[4], this.elements[8])
var v = new Vector3D(this.elements[1], this.elements[5], this.elements[9])
var w = new Vector3D(this.elements[2], this.elements[6], this.elements[10])
// for a true orthogonal, non-mirrored base, u.cross(v) == w
// If they have an opposite direction then we are mirroring
var mirrorvalue = u.cross(v).dot(w)
var ismirror = (mirrorvalue < 0)
return ismirror
}
}
// return the unity matrix
Matrix4x4.unity = function () {
return new Matrix4x4()
}
// Create a rotation matrix for rotating around the x axis
Matrix4x4.rotationX = function (degrees) {
var radians = degrees * Math.PI * (1.0 / 180.0)
var cos = Math.cos(radians)
var sin = Math.sin(radians)
var els = [
1, 0, 0, 0, 0, cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1
]
return new Matrix4x4(els)
}
// Create a rotation matrix for rotating around the y axis
Matrix4x4.rotationY = function (degrees) {
var radians = degrees * Math.PI * (1.0 / 180.0)
var cos = Math.cos(radians)
var sin = Math.sin(radians)
var els = [
cos, 0, -sin, 0, 0, 1, 0, 0, sin, 0, cos, 0, 0, 0, 0, 1
]
return new Matrix4x4(els)
}
// Create a rotation matrix for rotating around the z axis
Matrix4x4.rotationZ = function (degrees) {
var radians = degrees * Math.PI * (1.0 / 180.0)
var cos = Math.cos(radians)
var sin = Math.sin(radians)
var els = [
cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
]
return new Matrix4x4(els)
}
// Matrix for rotation about arbitrary point and axis
Matrix4x4.rotation = function (rotationCenter, rotationAxis, degrees) {
rotationCenter = new Vector3D(rotationCenter)
rotationAxis = new Vector3D(rotationAxis)
var rotationPlane = Plane.fromNormalAndPoint(rotationAxis, rotationCenter)
var orthobasis = new OrthoNormalBasis(rotationPlane)
var transformation = Matrix4x4.translation(rotationCenter.negated())
transformation = transformation.multiply(orthobasis.getProjectionMatrix())
transformation = transformation.multiply(Matrix4x4.rotationZ(degrees))
transformation = transformation.multiply(orthobasis.getInverseProjectionMatrix())
transformation = transformation.multiply(Matrix4x4.translation(rotationCenter))
return transformation
}
// Create an affine matrix for translation:
Matrix4x4.translation = function (v) {
// parse as Vector3D, so we can pass an array or a Vector3D
var vec = new Vector3D(v)
var els = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, vec.x, vec.y, vec.z, 1]
return new Matrix4x4(els)
}
// Create an affine matrix for mirroring into an arbitrary plane:
Matrix4x4.mirroring = function (plane) {
var nx = plane.normal.x
var ny = plane.normal.y
var nz = plane.normal.z
var w = plane.w
var els = [
(1.0 - 2.0 * nx * nx), (-2.0 * ny * nx), (-2.0 * nz * nx), 0,
(-2.0 * nx * ny), (1.0 - 2.0 * ny * ny), (-2.0 * nz * ny), 0,
(-2.0 * nx * nz), (-2.0 * ny * nz), (1.0 - 2.0 * nz * nz), 0,
(2.0 * nx * w), (2.0 * ny * w), (2.0 * nz * w), 1
]
return new Matrix4x4(els)
}
// Create an affine matrix for scaling:
Matrix4x4.scaling = function (v) {
// parse as Vector3D, so we can pass an array or a Vector3D
var vec = new Vector3D(v)
var els = [
vec.x, 0, 0, 0, 0, vec.y, 0, 0, 0, 0, vec.z, 0, 0, 0, 0, 1
]
return new Matrix4x4(els)
}
module.exports = Matrix4x4