Matrix3D(JavaScript)
Vector3D
class Vector3D {
constructor(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
static get Zero() {
return new Vector3D(0, 0, 0);
}
get(i) {
if (i === 0) return this.x;
if (i === 1) return this.y;
if (i === 2) return this.z;
throw new Error("Index out of range");
}
set(i, value) {
if (i === 0) this.x = value;
else if (i === 1) this.y = value;
else if (i === 2) this.z = value;
else throw new Error("Index out of range");
}
}
データ構造とコンストラクタ
class Matrix3D {
constructor(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
this.M00 = m00;
this.M01 = m01;
this.M02 = m02;
this.M10 = m10;
this.M11 = m11;
this.M12 = m12;
this.M20 = m20;
this.M21 = m21;
this.M22 = m22;
}
static MakeFromRow(row1, row2, row3) {
return new Matrix3D(
row1.x, row1.y, row1.z,
row2.x, row2.y, row2.z,
row3.x, row3.y, row3.z
);
}
static MakeFromColumn(col1, col2, col3) {
return new Matrix3D(
col1.x, col2.x, col3.x,
col1.y, col2.y, col3.y,
col1.z, col2.z, col3.z
);
}
get(i, j) {
if (i === 0 && j === 0) return this.M00;
if (i === 0 && j === 1) return this.M01;
if (i === 0 && j === 2) return this.M02;
if (i === 1 && j === 0) return this.M10;
if (i === 1 && j === 1) return this.M11;
if (i === 1 && j === 2) return this.M12;
if (i === 2 && j === 0) return this.M20;
if (i === 2 && j === 1) return this.M21;
if (i === 2 && j === 2) return this.M22;
throw new Error("Index out of range");
}
getRow(index) {
return new Vector3D(this.get(index, 0), this.get(index, 1), this.get(index, 2));
}
getCol(index) {
return new Vector3D(this.get(0, index), this.get(1, index), this.get(2, index));
}
get Row0() {
return new Vector3D(this.M00, this.M01, this.M02);
}
get Row1() {
return new Vector3D(this.M10, this.M11, this.M12);
}
get Row2() {
return new Vector3D(this.M20, this.M21, this.M22);
}
get Column0() {
return new Vector3D(this.M00, this.M10, this.M20);
}
get Column1() {
return new Vector3D(this.M01, this.M11, this.M21);
}
get Column2() {
return new Vector3D(this.M02, this.M12, this.M22);
}
}
基本操作
class Matrix3D {
constructor(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
this.M00 = m00;
this.M01 = m01;
this.M02 = m02;
this.M10 = m10;
this.M11 = m11;
this.M12 = m12;
this.M20 = m20;
this.M21 = m21;
this.M22 = m22;
}
static get Unit() {
return new Matrix3D(
1, 0, 0,
0, 1, 0,
0, 0, 1
);
}
get Transpose() {
return new Matrix3D(
this.M00, this.M10, this.M20,
this.M01, this.M11, this.M21,
this.M02, this.M12, this.M22
);
}
get Determinant() {
return this.M00 * (this.M11 * this.M22 - this.M12 * this.M21) +
this.M01 * (this.M12 * this.M20 - this.M10 * this.M22) +
this.M02 * (this.M10 * this.M21 - this.M11 * this.M20);
}
get Inverse() {
const determinant = this.Determinant;
if (determinant === 0) {
throw new Error("Matrix is singular and cannot be inverted.");
}
return this.Adjoint.Scale(1 / determinant);
}
SubMatrix(i, j) {
let ms = [];
for (let k = 0; k < 3; k++) {
if (i !== k) {
for (let l = 0; l < 3; l++) {
if (j !== l) {
ms.push(this.get(k, l));
}
}
}
}
return new Matrix2D(ms[0], ms[1], ms[2], ms[3]);
}
GetCofactor(i, j) {
const sign = (i + j) % 2 === 0 ? 1 : -1;
return sign * this.SubMatrix(i, j).Determinant;
}
get Cofactor() {
return new Matrix3D(
this.GetCofactor(0, 0), this.GetCofactor(0, 1), this.GetCofactor(0, 2),
this.GetCofactor(1, 0), this.GetCofactor(1, 1), this.GetCofactor(1, 2),
this.GetCofactor(2, 0), this.GetCofactor(2, 1), this.GetCofactor(2, 2)
);
}
get Adjoint() {
return this.Cofactor.Transpose;
}
Scale(scalar) {
return new Matrix3D(
this.M00 * scalar, this.M01 * scalar, this.M02 * scalar,
this.M10 * scalar, this.M11 * scalar, this.M12 * scalar,
this.M20 * scalar, this.M21 * scalar, this.M22 * scalar
);
}
get(i, j) {
if (i === 0 && j === 0) return this.M00;
if (i === 0 && j === 1) return this.M01;
if (i === 0 && j === 2) return this.M02;
if (i === 1 && j === 0) return this.M10;
if (i === 1 && j === 1) return this.M11;
if (i === 1 && j === 2) return this.M12;
if (i === 2 && j === 0) return this.M20;
if (i === 2 && j === 1) return this.M21;
if (i === 2 && j === 2) return this.M22;
throw new Error("Index out of range");
}
}
// ヘルパー関数
function sin(radian) {
return Math.sin(radian);
}
function cos(radian) {
return Math.cos(radian);
}
基本演算
class Matrix3D {
constructor(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
this.M00 = m00;
this.M01 = m01;
this.M02 = m02;
this.M10 = m10;
this.M11 = m11;
this.M12 = m12;
this.M20 = m20;
this.M21 = m21;
this.M22 = m22;
}
// 加算
static add(m1, m2) {
return new Matrix3D(
m1.M00 + m2.M00, m1.M01 + m2.M01, m1.M02 + m2.M02,
m1.M10 + m2.M10, m1.M11 + m2.M11, m1.M12 + m2.M12,
m1.M20 + m2.M20, m1.M21 + m2.M21, m1.M22 + m2.M22
);
}
// 減算
static subtract(m1, m2) {
return new Matrix3D(
m1.M00 - m2.M00, m1.M01 - m2.M01, m1.M02 - m2.M02,
m1.M10 - m2.M10, m1.M11 - m2.M11, m1.M12 - m2.M12,
m1.M20 - m2.M20, m1.M21 - m2.M21, m1.M22 - m2.M22
);
}
// スカラー乗算
static multiplyScalar(m, f) {
return new Matrix3D(
m.M00 * f, m.M01 * f, m.M02 * f,
m.M10 * f, m.M11 * f, m.M12 * f,
m.M20 * f, m.M21 * f, m.M22 * f
);
}
// 行列乗算
static multiply(m1, m2) {
return new Matrix3D(
// 1行目
m1.M00 * m2.M00 + m1.M01 * m2.M10 + m1.M02 * m2.M20,
m1.M00 * m2.M01 + m1.M01 * m2.M11 + m1.M02 * m2.M21,
m1.M00 * m2.M02 + m1.M01 * m2.M12 + m1.M02 * m2.M22,
// 2行目
m1.M10 * m2.M00 + m1.M11 * m2.M10 + m1.M12 * m2.M20,
m1.M10 * m2.M01 + m1.M11 * m2.M11 + m1.M12 * m2.M21,
m1.M10 * m2.M02 + m1.M11 * m2.M12 + m1.M12 * m2.M22,
// 3行目
m1.M20 * m2.M00 + m1.M21 * m2.M10 + m1.M22 * m2.M20,
m1.M20 * m2.M01 + m1.M21 * m2.M11 + m1.M22 * m2.M21,
m1.M20 * m2.M02 + m1.M21 * m2.M12 + m1.M22 * m2.M22
);
}
// スカラー除算
static divideScalar(m, f) {
return new Matrix3D(
m.M00 / f, m.M01 / f, m.M02 / f,
m.M10 / f, m.M11 / f, m.M12 / f,
m.M20 / f, m.M21 / f, m.M22 / f
);
}
// Vector2Dとの乗算
static multiplyVector2D(m, v) {
return new Vector2D(
v.x * m.M00 + v.y * m.M01 + 1 * m.M02,
v.x * m.M10 + v.y * m.M11 + 1 * m.M12
);
}
static multiplyVector2DLeft(v, m) {
return new Vector2D(
v.x * m.M00 + v.y * m.M10 + 1 * m.M20,
v.x * m.M01 + v.y * m.M11 + 1 * m.M21
);
}
// Vector3Dとの乗算
static multiplyVector3D(m, v) {
return new Vector3D(
v.x * m.M00 + v.y * m.M01 + v.z * m.M02,
v.x * m.M10 + v.y * m.M11 + v.z * m.M12,
v.x * m.M20 + v.y * m.M21 + v.z * m.M22
);
}
static multiplyVector3DLeft(v, m) {
let result = new Vector3D(0, 0, 0);
for (let i = 0; i < 3; i++) {
result[i] = Vector3D.dot(m.getRow(i), v);
}
return result;
}
// 等価チェック
equals(m) {
return (
this.M00 === m.M00 && this.M01 === m.M01 && this.M02 === m.M02 &&
this.M10 === m.M10 && this.M11 === m.M11 && this.M12 === m.M12 &&
this.M20 === m.M20 && this.M21 === m.M21 && this.M22 === m.M22
);
}
static equals(m1, m2) {
if (m1 === m2) return true;
if (m1 === null || m2 === null) return false;
return m1.equals(m2);
}
static notEquals(m1, m2) {
return !Matrix3D.equals(m1, m2);
}
}
アフィン2D(同時座標)
2Dの同時座標用行列は省略する。
アフィン3D
class Matrix3D {
constructor(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
this.M00 = m00;
this.M01 = m01;
this.M02 = m02;
this.M10 = m10;
this.M11 = m11;
this.M12 = m12;
this.M20 = m20;
this.M21 = m21;
this.M22 = m22;
}
// スケール
static createScale3D(scale) {
return Matrix3D.createScale3DComponents(scale, scale, scale);
}
static createScale3DComponents(sx, sy, sz) {
return new Matrix3D(
sx, 0, 0,
0, sy, 0,
0, 0, sz
);
}
static createScale3DFromDirection(direction, scale) {
const k = scale;
const x = direction.x;
const y = direction.y;
const z = direction.z;
return new Matrix3D(
1 + (k - 1) * x * x, (k - 1) * x * y, (k - 1) * x * z,
(k - 1) * x * y, 1 + (k - 1) * y * y, (k - 1) * y * z,
(k - 1) * x * z, (k - 1) * y * z, 1 + (k - 1) * z * z
);
}
// 回転
static createRotation3D_XV(degree) {
const radian = degree * (Math.PI / 180);
return new Matrix3D(
1, 0, 0,
0, Math.cos(radian), Math.sin(radian),
0, -Math.sin(radian), Math.cos(radian)
);
}
static createRotation3D_XH(degree) {
const radian = degree * (Math.PI / 180);
return new Matrix3D(
1, 0, 0,
0, Math.cos(radian), -Math.sin(radian),
0, Math.sin(radian), Math.cos(radian)
);
}
static createRotation3D_YV(degree) {
const radian = degree * (Math.PI / 180);
return new Matrix3D(
Math.cos(radian), 0, -Math.sin(radian),
0, 1, 0,
Math.sin(radian), 0, Math.cos(radian)
);
}
static createRotation3D_YH(degree) {
const radian = degree * (Math.PI / 180);
return new Matrix3D(
Math.cos(radian), 0, Math.sin(radian),
0, 1, 0,
-Math.sin(radian), 0, Math.cos(radian)
);
}
static createRotation3D_ZV(degree) {
const radian = degree * (Math.PI / 180);
return new Matrix3D(
Math.cos(radian), Math.sin(radian), 0,
-Math.sin(radian), Math.cos(radian), 0,
0, 0, 1
);
}
static createRotation3D_ZH(degree) {
const radian = degree * (Math.PI / 180);
return new Matrix3D(
Math.cos(radian), -Math.sin(radian), 0,
Math.sin(radian), Math.cos(radian), 0,
0, 0, 1
);
}
static createRotation3D_N(degree, axis) {
const r = degree * (Math.PI / 180);
const x = axis.x;
const y = axis.y;
const z = axis.z;
const cos = Math.cos(r);
const sin = Math.sin(r);
return new Matrix3D(
x * x * (1 - cos) + cos, x * y * (1 - cos) + z * sin, x * z * (1 - cos) - y * sin,
x * y * (1 - cos) - z * sin, y * y * (1 - cos) + cos, y * z * (1 - cos) + x * sin,
x * z * (1 - cos) + y * sin, y * z * (1 - cos) - x * sin, z * z * (1 - cos) + cos
);
}
// 投影
static createProjection3D_XY() {
return Matrix3D.createScale3DFromDirection(new Vector3D(0, 0, 1), 0);
}
static createProjection3D_XZ() {
return Matrix3D.createScale3DFromDirection(new Vector3D(0, 1, 0), 0);
}
static createProjection3D_YZ() {
return Matrix3D.createScale3DFromDirection(new Vector3D(1, 0, 0), 0);
}
static createProjection3D_N(n) {
return Matrix3D.createScale3DFromDirection(n, 0);
}
// 反射
static createReflection3D_XY() {
return Matrix3D.createScale3DFromDirection(new Vector3D(0, 0, 1), -1);
}
static createReflection3D_XZ() {
return Matrix3D.createScale3DFromDirection(new Vector3D(0, 1, 0), -1);
}
static createReflection3D_YZ() {
return Matrix3D.createScale3DFromDirection(new Vector3D(1, 0, 0), -1);
}
static createReflection3D_N(n) {
return Matrix3D.createScale3DFromDirection(n, -1);
}
// スキュー(せん断)
static createSkew3D_XY(skew1, skew2) {
return new Matrix3D(
1, 0, 0,
0, 1, 0,
skew1, skew2, 1
);
}
static createSkew3D_XZ(skew1, skew2) {
return new Matrix3D(
1, 0, 0,
skew1, 1, skew2,
0, 0, 1
);
}
static createSkew3D_YZ(skew1, skew2) {
return new Matrix3D(
1, skew1, skew2,
0, 1, 0,
0, 0, 1
);
}
}
この記事が気に入ったらサポートをしてみませんか?