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
        );
    }
}




この記事が気に入ったらサポートをしてみませんか?