Matrix3D(数式およびC#)



Matrix3D

データ構造とコンストラクタ

    public class Matrix3D
    {
        #region データ
        public double this[int i, int j]
        {
            get
            {
                if (i == 0 && j == 0) { return M00; }
                if (i == 0 && j == 1) { return M01; }
                if (i == 0 && j == 2) { return M02; }

                if (i == 1 && j == 0) { return M10; }
                if (i == 1 && j == 1) { return M11; }
                if (i == 1 && j == 2) { return M12; }

                if (i == 2 && j == 0) { return M20; }
                if (i == 2 && j == 1) { return M21; }
                if (i == 2 && j == 2) { return M22; }

                throw new IndexOutOfRangeException();
            }
        }

        public double M00;
        public double M01;
        public double M02;

        public double M10;
        public double M11;
        public double M12;

        public double M20;
        public double M21;
        public double M22;


        public Vector3D GetRow(int index)
        {
            Vector3D ret = Vector3D.Zero;
            for (int i = 0; i < 3; i++)
            {
                ret[i] = this[index, i];
            }
            return ret;
        }
        public Vector3D GetCol(int index)
        {
            Vector3D ret = Vector3D.Zero;
            for (int i = 0; i < 3; i++)
            {
                ret[i] = this[i, index];
            }
            return ret;
        }

        public Vector3D Row0
        {
            get
            {
                return new Vector3D(M00, M01, M02);
            }
        }
        public Vector3D Row1
        {
            get
            {
                return new Vector3D(M10, M11, M12);
            }
        }
        public Vector3D Row2
        {
            get
            {
                return new Vector3D(M20, M21, M22);
            }
        }

        public Vector3D Column0
        {
            get
            {
                return new Vector3D(M00, M10, M20);
            }
        }
        public Vector3D Column1
        {
            get
            {
                return new Vector3D(M01, M11, M21);
            }
        }
        public Vector3D Column2
        {
            get
            {
                return new Vector3D(M02, M12, M22);
            }
        }

        #endregion

        #region コンストラクタ

        public Matrix3D(double m00, double m01, double m02, double m10, double m11, double m12, double m20, double m21, double m22)
        {
            M00 = m00;
            M01 = m01;
            M02 = m02;

            M10 = m10;
            M11 = m11;
            M12 = m12;

            M20 = m20;
            M21 = m21;
            M22 = m22;
        }

        public Matrix3D(Vector3D row1, Vector3D row2, Vector3D row3)
            : this(row1.X, row1.Y, row1.Z, row2.X, row2.Y, row2.Z, row3.X, row3.Y, row3.Z) { }

        public static Matrix3D MakeFromRow(Vector3D row1, Vector3D row2, Vector3D row3)
        {
            Matrix3D ret = new Matrix3D(
                row1.X, row1.Y, row1.Z,
                row2.X, row2.Y, row2.Z,
                row3.X, row3.Y, row3.Z);
            return ret;
        }
        //コンストラクタに転置ブチ込めるようになるまでのつなぎ
        public static Matrix3D MakeFromColumn(Vector3D col1, Vector3D col2, Vector3D col3)
        {
            Matrix3D ret = new Matrix3D(
                col1.X, col2.X, col3.X,
                col1.Y, col2.Y, col3.Y,
                col1.Z, col2.Z, col3.Z);
            return ret;
        }

        #endregion
}

基本操作

$$
\begin{bmatrix}
a & b & c \\
d & e & f \\
g & h & i
\end{bmatrix}
$$

に対して

単位行列(unit)

$$
\begin{bmatrix}
1 & 0 & 0 \\
0 & 1 & 0 \\
0 & 0 & 1
\end{bmatrix}
$$

転置(transpose)

$$
\begin{bmatrix}
a & d & g \\
b & e & h \\
c & f & i
\end{bmatrix}
$$

行列式(determinant)

$$
a(ei - fh) - b(di - fg) + c(dh - eg)
$$

逆行列(inverse)

$$
\frac{1}{det}adj
$$

すなわち

$$
\frac{1}{\text{det}}\begin{bmatrix}
ei-fh & ch-bi & bf-ce \\
fg-di & ai-cg & cd-af \\
dh-ge & bg-ah & ae-bd
\end{bmatrix}
$$

余因子行列(cofactor)

$$
\begin{bmatrix}
ei-fh & fg-di & dh-ge \\
ch-bi & ai-cg & bg-ah \\
bf-ce & cd-af & ae-bd
\end{bmatrix}
$$

随伴行列(adjoint)

余因子行列の転置

$$
\begin{bmatrix}
ei-fh & ch-bi & bf-ce \\
fg-di & ai-cg & cd-af \\
dh-ge & bg-ah & ae-bd
\end{bmatrix}
$$

基本操作(コード)

       #region 基本操作

        public static Matrix3D Unit
        {
            get
            {
                return new Matrix3D(
                    1, 0, 0,
                    0, 1, 0,
                    0, 0, 1
                    );
            }
        }

        //転置
        public Matrix3D Transpose
        {
            //(m00,m01,m02)    (m00,m10,m20)
            //(m10,m11,m12) -> (m01,m11,m21)
            //(m20,m21,m22)    (m02,m12,m22)

            get
            {
                return new Matrix3D(
                    M00, M10, M20,
                    M01, M11, M21,
                    M02, M12, M22);
            }
        }
        //行列式
        public double Determinant
        {
            get
            {
                //m00,m01,m02
                //m10,m11,m12
                //m20,m21,m22

                //return M00 * M11 * M22 + M01 * M12 * M20 + M02 * M10 * M21
                //    - M02 * M11 * M20 - M01 * M10 * M22 - M00 * M12 * M21;

                //これでもいいのか?
                //Vector3.Dot(this.Row1, (Vector3.Cross(this.Row2, this.Row3)));

                return M00 * (M11 * M22 - M12 * M21) + M01 * (M12 * M20 - M10 * M22) + M02 * (M10 * M21 - M11 * M20);

            }
        }
        //逆行列
        public Matrix3D Inverse
        {
            get
            {
                return Adjoint / Determinant;
            }
        }
        //小行列:thisからi行j列を省いたもの
        public Matrix2D SubMatrix(int i, int j)
        {
            List<double> ms = new List<double>();

            for (int k = 0; k < 3; k++)
            {
                if (i != k)
                {
                    for (int l = 0; l < 3; l++)
                    {
                        if (j != l) { ms.Add(this[k, l]); }
                    }
                }
            }

            return new Matrix2D(ms[0], ms[1], ms[2], ms[3]);
        }
        //余因子:対応する小行列に対応する符号を付けたもの
        public double GetCofactor(int i, int j)
        {
            int sign;
            if ((i + j) % 2 == 0) { sign = 1; }
            else { sign = -1; }

            return sign * (SubMatrix(i, j).Determinant);
        }
        //余因子行列
        public Matrix3D Cofactor
        {
            get
            {
                double c00 = GetCofactor(0, 0);
                double c01 = GetCofactor(0, 1);
                double c02 = GetCofactor(0, 2);
                double c10 = GetCofactor(1, 0);
                double c11 = GetCofactor(1, 1);
                double c12 = GetCofactor(1, 2);
                double c20 = GetCofactor(2, 0);
                double c21 = GetCofactor(2, 1);
                double c22 = GetCofactor(2, 2);

                return new Matrix3D(c00, c01, c02, c10, c11, c12, c20, c21, c22);
            }
        }
        //随伴行列:余因子行列の転置
        public Matrix3D Adjoint
        {
            get
            {
                double c00 = GetCofactor(0, 0);
                double c01 = GetCofactor(0, 1);
                double c02 = GetCofactor(0, 2);
                double c10 = GetCofactor(1, 0);
                double c11 = GetCofactor(1, 1);
                double c12 = GetCofactor(1, 2);
                double c20 = GetCofactor(2, 0);
                double c21 = GetCofactor(2, 1);
                double c22 = GetCofactor(2, 2);

                return new Matrix3D(c00, c01, c02, c10, c11, c12, c20, c21, c22).Transpose;
            }
        }


        //見栄え用ヘルパー
        private static double sin(double radian)
        {
            return Math.Sin(radian);
        }
        private static double cos(double radian)
        {
            return Math.Cos(radian);
        }

        #endregion

演算子のオーバーロード

        #region Operator

        public static Matrix3D operator +(Matrix3D m1, Matrix3D 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
                );
        }

        public static Matrix3D operator -(Matrix3D m1, Matrix3D 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
                );
        }

        public static Matrix3D operator *(Matrix3D m, double 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);
        }

        public static Matrix3D operator *(double f, Matrix3D m)
        {
            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);
        }


        #region Vector2D

        //逆の演算はベクトルが転置しないと無理
        //Matrix3の演算が右側に転置ベクトルを受ける形式になっているので
        public static Vector2D operator *(Vector2D v, Matrix3D m)
        {
            //(x,y,1)* M00 M01 M02
            //         M10 M11 M12
            //         M20 M21 M22

            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
                );
        }
        //通常ベクトルを右に受けたら自動的に転置
        public static Vector2D operator *(Matrix3D m, Vector2D v)
        {
            //         M00 M01 M02 : x
            //         M10 M11 M12 : y
            //         M20 M21 M22 : 1

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

        #endregion

        #region Vector3D

        //Vector3Dは他のプロジェクトに良くコピペするので
        //余計な演算を実装しないようにしておく
        public static Vector3D operator *(Vector3D v, Matrix3D m1)
        {
            Vector3D ret = Vector3D.Zero;
            for (int i = 0; i < 3; i++)
            {
                ret[i] = Vector3D.Dot(m1.GetCol(i), v);
            }

            return ret;
        }
        public static Vector3D operator *(Matrix3D m1, Vector3D v)
        {
            //         M00 M01 M02 : x
            //         M10 M11 M12 : y
            //         M20 M21 M22 : z

            Vector3D ret = Vector3D.Zero;
            for (int i = 0; i < 3; i++)
            {
                ret[i] = Vector3D.Dot(m1.GetRow(i), v);
            }

            return ret;
        } 

        #endregion


        public static Matrix3D operator *(Matrix3D m1, Matrix3D m2)
        {
            //左項行ベクトルと右項列ベクトルの内積→出力の成分

            //左項は行ベクトルなのでそのまま
            //右項は列ベクトルなので鏡像反転からの回転=転置

            //(m00,m01,m02)   (m00,m01,m02) 
            //(m10,m11,m12)   (m10,m11,m12) 
            //(m20,m21,m22)   (m20,m21,m22) 
            //↓
            //行:(m00,m01,m02)   列:(m00,m10,m20)
            //行:(m10,m11,m12)   列:(m01,m11,m21)
            //行:(m20,m21,m22)   列:(m02,m12,m22)

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

        public static Matrix3D operator /(Matrix3D m, double 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);
        }


        //値の等価を調べる
        public override bool Equals(System.Object obj)
        {
            //どちらかnullないし型違いならfalse
            if (obj == null || this.GetType() != obj.GetType())
            {
                return false;
            }

            Matrix3D m = (Matrix3D)obj;
            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);
        }

        public override int GetHashCode()
        {
            return this.M00.GetHashCode() ^ this.M01.GetHashCode() ^ this.M02.GetHashCode()
                 ^ this.M10.GetHashCode() ^ this.M11.GetHashCode() ^ this.M12.GetHashCode()
                 ^ this.M20.GetHashCode() ^ this.M21.GetHashCode() ^ this.M22.GetHashCode();
        }

        public static bool operator ==(Matrix3D m1, Matrix3D m2)
        {
            //参照が等しいなら必ず等しい
            //両方ともnullないし両方とも同じ参照ならreturn true
            if (System.Object.ReferenceEquals(m1, m2))
            {
                return true;
            }

            //片方だけがnullならばreturn false
            if (((object)m1 == null) || ((object)m2 == null))
            {
                return false;
            }

            //値のチェック
            return m1.Equals(m2);
        }

        public static bool operator !=(Matrix3D m1, Matrix3D m2)
        {
            return !(m1 == m2);
        }

        #endregion

アフィン変換2D(同次座標)


平行移動

        #region Translation2D

        public static Matrix3D CreateTranslateMatrixV(int dx, int dy)
        {
            //Vector2Dを転置して縦ベクトルを右から受ける場合
            return new Matrix3D(
               1, 0, dx,
               0, 1, dy,
               0, 0, 1);
        }

        public static Matrix3D CreateTranslateMatrixH(int dx, int dy)
        {
            //転置せず横ベクトルを左から受ける場合
            return new Matrix3D(
                1, 0, 0,
                0, 1, 0,
                dx, dy, 1);
        }

        public static Matrix3D CreateTranslateMatrixV(double dx, double dy)
        {
            //Vector2Dを転置して縦ベクトルを右から受ける場合
            return new Matrix3D(
               1, 0, dx,
               0, 1, dy,
               0, 0, 1);
        }

        public static Matrix3D CreateTranslateMatrixH(double dx, double dy)
        {
            //転置せず横ベクトルを左から受ける場合
            return new Matrix3D(
                1, 0, 0,
                0, 1, 0,
                dx, dy, 1);
        }

        public static Matrix3D CreateTranslateMatrixV(Vector2D delta)
        {
            //Vector2Dを転置して縦ベクトルを右から受ける場合
            return new Matrix3D(
                1, 0, delta.X,
                0, 1, delta.Y,
                0, 0, 1);
        }

        public static Matrix3D CreateTranslateMatrixH(Vector2D delta)
        {
            //転置せず横ベクトルを左から受ける場合
            return new Matrix3D(
                1, 0, 0,
                0, 1, 0,
                delta.X, delta.Y, 1);
        }

        public void Translate(ref Vector2D v, Vector2D delta)
        {
            //1,0,dx    x
            //0,1,dy    y
            //0,0, 1    1

            double dx = 1 * v.X + 0 * v.Y + delta.X * 1;
            double dy = 0 * v.X + 1 * v.Y + delta.Y * 1;
            //double dz = 0 * v.X + 0 * v.Y + 1 * 1;

            v.Set_Val(dx, dy);
        }

        #endregion

スケール

        #region Scale2D

        public static Matrix3D CreateScaleMatrix(double scale)
        {
            return CreateScaleMatrix(scale, scale);
        }

        public static Matrix3D CreateScaleMatrix(double sx, double sy)
        {
            //通常ベクトルだろうが転置ベクトルだろうが出力変わらず
            return new Matrix3D(
                sx, 0, 0,
                0, sy, 0,
                0, 0, 1);
        }

        public void Scale(ref Vector2D v, double scale)
        {
            this.Scale(ref v, scale, scale);
        }

        public void Scale(ref Vector2D v, double sx, double sy)
        {
            //sx,0,0    x
            //0,sy,0    y
            //0,0, 1    1

            double dx = sx * v.X + 0 * v.Y + 0 * 1;
            double dy = 0 * v.X + sy * v.Y + 0 * 1;
            double dz = 0 * v.X + 0 * v.Y + 1 * 1;

            v.Set_Val(dx, dy);

        }

        //任意向きスケール
        public static Matrix3D CreateScaleMatrix(Vector2D direction, double scale)
        {
            double k = scale;
            double x = direction.X;
            double y = direction.Y;

            return new Matrix3D(
                 1 + (k - 1) * x * x, (k - 1) * x * y, 0,
                 (k - 1) * x * y, 1 + (k - 1) * y * y, 0,
                 0, 0, 1);
        }

        //ピボット
        public static Matrix3D CreatePivotScaleMatrix(Vector2D pivot, double scale)
        {
            Matrix3D T = CreateTranslateMatrixV(pivot.X, pivot.Y);
            Matrix3D S = CreateScaleMatrix(scale);
            Matrix3D TR = CreateTranslateMatrixV(-pivot.X, -pivot.Y);

            return T * S * TR;
        }
        public static Matrix3D CreatePivotScaleMatrix(Vector2D pivot, double sx, double sy)
        {
            Matrix3D T = CreateTranslateMatrixV(pivot.X, pivot.Y);
            Matrix3D S = CreateScaleMatrix(sx, sy);
            Matrix3D TR = CreateTranslateMatrixV(-pivot.X, -pivot.Y);

            return T * S * TR;
        }
        public static Matrix3D CreatePivotScaleMatrix(Vector2D pivot, Vector2D direction, double scale)
        {
            Matrix3D T = CreateTranslateMatrixV(pivot.X, pivot.Y);
            Matrix3D S = CreateScaleMatrix(direction, scale);
            Matrix3D TR = CreateTranslateMatrixV(-pivot.X, -pivot.Y);

            return T * S * TR;
        }

        #endregion

回転

        #region Rotation2D

        //角度渡し
        //2D
        public static Matrix3D CreateRotationMatrixV_Degree(double degree)
        {
            //スクリーン座標において以下は時計回転
            //デカルト座標においては反時計回りとなる
            //xが縮み、yが伸びる、すなわちy+に向かって回転する
            //double dx = v.X * Math.Cos(radian) - v.Y * Math.Sin(radian);
            //double dy = v.X * Math.Sin(radian) + v.Y * Math.Cos(radian);

            double radian = degree * (Math.PI / 180);

            //縦ベクトルを右から掛けるならy+に向かって回転する
            //横ベクトルを左から掛けるならx+に向かって回転する
            return new Matrix3D(
               cos(radian), -sin(radian), 0,
               sin(radian), cos(radian), 0,
               0, 0, 1
               );
        }
        public static Matrix3D CreateRotationMatrixH_Degree(double degree)
        {
            double radian = degree * (Math.PI / 180);

            //縦ベクトルを右から掛けるならx+に向かって回転する
            //横ベクトルを左から掛けるならy+に向かって回転する
            return new Matrix3D(
               cos(radian), sin(radian), 0,
               -sin(radian), cos(radian), 0,
               0, 0, 1
               );
        }
        public static Matrix3D CreateRotationMatrixV(double radian)
        {
            //縦ベクトルを右から掛けるならy+に向かって回転する
            //横ベクトルを左から掛けるならx+に向かって回転する
            return new Matrix3D(
               cos(radian), -sin(radian), 0,
               sin(radian), cos(radian), 0,
               0, 0, 1
               );
        }
        public static Matrix3D CreateRotationMatrixH(double radian)
        {
            //縦ベクトルを右から掛けるならx+に向かって回転する
            //横ベクトルを左から掛けるならy+に向かって回転する
            return new Matrix3D(
               cos(radian), sin(radian), 0,
               -sin(radian), cos(radian), 0,
               0, 0, 1
               );
        }

        public void Rotate_Degree(ref Vector2D v, double angle)
        {
            double radian = angle * (Math.PI / 180);

            //cosθ,-sinθ,0    x
            //sinθ, cosθ,0    y
            //    0,     0,1    1

            //縦ベクトルを右から掛けるならy+に向かって回転する
            //横ベクトルを左から掛けるならx+に向かって回転する
            double dx = cos(radian) * v.X - sin(radian) * v.Y + 0 * 1;
            double dy = sin(radian) * v.X + cos(radian) * v.Y + 0 * 1;
            //double dz = 0 * v.X + 0 * v.Y + 1 * 1;

            v.Set_Val(dx, dy);
        }
        public void Rotate_Radian(ref Vector2D v, double radian)
        {
            //縦ベクトルを右から掛けるならy+に向かって回転する
            //横ベクトルを左から掛けるならx+に向かって回転する
            double dx = cos(radian) * v.X - sin(radian) * v.Y + 0 * 1;
            double dy = sin(radian) * v.X + cos(radian) * v.Y + 0 * 1;
            //double dz = 0 * v.X + 0 * v.Y + 1 * 1;

            v.Set_Val(dx, dy);
        }

        //ピボット
        public static Matrix3D CreatePivotRotationMatrixV_Degree(Vector2D pivot, double degree)
        {
            Matrix3D T = CreateTranslateMatrixV(pivot.X, pivot.Y);
            Matrix3D S = CreateRotationMatrixV_Degree(degree);
            Matrix3D TR = CreateTranslateMatrixV(-pivot.X, -pivot.Y);

            return T * S * TR;
        }
        public static Matrix3D CreatePivotRotationMatrixV(Vector2D pivot, double radian)
        {
            Matrix3D T = CreateTranslateMatrixV(pivot.X, pivot.Y);
            Matrix3D S = CreateRotationMatrixV(radian);
            Matrix3D TR = CreateTranslateMatrixV(-pivot.X, -pivot.Y);

            return T * S * TR;
        }

        //ピボット
        public static Matrix3D CreatePivotRotationMatrixH_Degree(Vector2D pivot, double degree)
        {
            Matrix3D T = CreateTranslateMatrixV(pivot.X, pivot.Y);
            Matrix3D S = CreateRotationMatrixH_Degree(degree);
            Matrix3D TR = CreateTranslateMatrixV(-pivot.X, -pivot.Y);

            return T * S * TR;
        }
        public static Matrix3D CreatePivotRotationMatrixH(Vector2D pivot, double radian)
        {
            Matrix3D T = CreateTranslateMatrixV(pivot.X, pivot.Y);
            Matrix3D S = CreateRotationMatrixH(radian);
            Matrix3D TR = CreateTranslateMatrixV(-pivot.X, -pivot.Y);

            return T * S * TR;
        }


        #endregion

射影、鏡映、スキュ



        #region Projection2D
        //X軸へのProjection
        public static Matrix3D CreateProjection2D_X()
        {
            return CreateScaleMatrix(new Vector2D(0, 1), 0);
        }
        //Y軸へのProjection
        public static Matrix3D CreateProjection2D_Y()
        {
            return CreateScaleMatrix(new Vector2D(1, 0), 0);
        }
        //任意軸にProjection
        public static Matrix3D CreateProjection2D_N(Vector2D n)
        {
            return CreateScaleMatrix(n, 0);
        }

        #endregion

        #region Reflection2D
        //X軸へのReflection
        public static Matrix3D CreateReflection2D_X()
        {
            return CreateScaleMatrix(new Vector2D(0, 1), -1);
        }
        //Y軸へのReflection
        public static Matrix3D CreateReflection2D_Y()
        {
            return CreateScaleMatrix(new Vector2D(1, 0), -1);
        }
        //任意軸にReflection
        public static Matrix3D CreateReflection2D_N(Vector2D n)
        {
            return CreateScaleMatrix(n, -1);
        }
        #endregion

        #region スキュー(せん断)2D
        public static Matrix3D CreateSkew2D_X(double skewScale)
        {
            //X座標をY座標でせん断する

            double s = skewScale;
            return new Matrix3D(
                 1, 0, 0,
                 s, 1, 0,
                 0, 0, 1
                 );
        }

        public static Matrix3D CreateSkew2D_Y(double skewScale)
        {
            //Y座標をX座標でせん断する

            double s = skewScale;
            return new Matrix3D(
                 1, s, 0,
                 0, 1, 0,
                 0, 0, 1
                 );
        }
        #endregion

        #endregion


アフィン変換3D(コード)

        #region アフィン3D変換

        #region Scale3D
        public static Matrix3D CreateScale3D(double scale)
        {
            return CreateScale3D(scale, scale, scale);
        }

        public static Matrix3D CreateScale3D(double sx, double sy, double sz)
        {
            //通常ベクトルだろうが転置ベクトルだろうが出力変わらず
            return new Matrix3D(
                sx, 0, 0,
                0, sy, 0,
                0, 0, sz);
        }
        //任意向きスケール
        public static Matrix3D CreateScale3D(Vector3D direction, double scale)
        {
            double k = scale;
            double x = direction.X;
            double y = direction.Y;
            double 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);
        }
        #endregion

        #region  Rotation3D

        //角度渡し
        //軸を基準とした回転
        public static Matrix3D CreateRotation3D_XV(double degree)
        {
            //右から縦ベクトルを掛けると
            //x軸を回転の基準としてz+からy+に向かって回転する
            //左から横ベクトルを掛けると
            //x軸を回転の基準としてy+からz+に向かって回転する
            double radian = degree * (Math.PI / 180);
            return new Matrix3D(
                1, 0, 0,
                0, cos(radian), sin(radian),
                0, -sin(radian), cos(radian)
                          );
        }
        public static Matrix3D CreateRotation3D_XH(double degree)
        {            
            double radian = degree * (Math.PI / 180);
            return new Matrix3D(
                1, 0, 0,
                0, cos(radian), -sin(radian),
                0, sin(radian), cos(radian)
                          );
        }
        public static Matrix3D CreateRotation3D_YV(double degree)
        {
            //右から縦ベクトルを掛けると
            //y軸を回転の基準としてx+からz+に向かって回転する
            //左から横ベクトルを掛けると
            //y軸を回転の基準としてz+からx+に向かって回転する
            double radian = degree * (Math.PI / 180);
            return new Matrix3D(
                cos(radian), 0, -sin(radian),
                0, 1, 0,
                sin(radian), 0, cos(radian)
                );
        }
        public static Matrix3D CreateRotation3D_YH(double degree)
        {
            double radian = degree * (Math.PI / 180);
            return new Matrix3D(
                cos(radian), 0, sin(radian),
                0, 1, 0,
                -sin(radian), 0, cos(radian)
                );
        }
        public static Matrix3D CreateRotation3D_ZV(double degree)
        {
            //右から縦ベクトルを掛けると
            //z軸を回転の基準としてy+からx+に向かって回転する
            //左から横ベクトルを掛けると
            //z軸を回転の基準としてx+からy+に向かって回転する
            double radian = degree * (Math.PI / 180);
            return new Matrix3D(
                cos(radian), sin(radian), 0,
                 -sin(radian), cos(radian), 0,
                0, 0, 1
                );
        }
        public static Matrix3D CreateRotation3D_ZH(double degree)
        {
            double radian = degree * (Math.PI / 180);
            return new Matrix3D(
                cos(radian), -sin(radian), 0,
                 sin(radian), cos(radian), 0,
                0, 0, 1
                );
        }
        //任意軸回転
        public static Matrix3D CreateRotation3D_N(double degree, Vector3D axis)
        {
            double r = degree * (Math.PI / 180);
            double x = axis.X;
            double y = axis.Y;
            double z = axis.Z;
            double cos = Matrix3D.cos(r);
            double sin = Matrix3D.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) + z * sin,
                x * z * (1 - cos) + y * sin, y * z * (1 - cos) - x * sin, z * z * (1 - cos) + cos
                );
        }
        #endregion

        #region  Projection3D
        public static Matrix3D CreateProjection3D_XY()
        {
            //1,0,0
            //0,1,0
            //0,0,0

            return CreateScale3D(new Vector3D(0, 0, 1), 0);
        }
        public static Matrix3D CreateProjection3D_XZ()
        {
            //1,0,0
            //0,0,0
            //0,0,1

            return CreateScale3D(new Vector3D(0, 1, 0), 0);
        }
        public static Matrix3D CreateProjection3D_YZ()
        {
            //0,0,0
            //0,1,0
            //0,0,1

            return CreateScale3D(new Vector3D(1, 0, 0), 0);
        }
        public static Matrix3D CreateProjection3D_N(Vector3D n)
        {
            return CreateScale3D(n, 0);
        }
        #endregion

        #region  Reflection3D
        public static Matrix3D CreateReflection3D_XY()
        {
            return CreateScale3D(new Vector3D(0, 0, 1), -1);
        }
        public static Matrix3D CreateReflection3D_XZ()
        {
            return CreateScale3D(new Vector3D(0, 1, 0), -1);
        }
        public static Matrix3D CreateReflection3D_YZ()
        {
            return CreateScale3D(new Vector3D(1, 0, 0), -1);
        }
        public static Matrix3D CreateReflection3D_N(Vector3D n)
        {
            return CreateScale3D(n, -1);
        }
        #endregion

        #region  スキュー(せん断)3D
        public static Matrix3D CreateSkew3D_XY(double skew1, double skew2)
        {
            //XY平面をZ座標でせん断する

            double s = skew1;
            double t = skew2;

            return new Matrix3D(
                 1, 0, 0,
                 0, 1, 0,
                 s, t, 1
                 );
        }
        public static Matrix3D CreateSkew3D_XZ(double skew1, double skew2)
        {
            //XY平面をZ座標でせん断する

            double s = skew1;
            double t = skew2;

            return new Matrix3D(
                 1, 0, 0,
                 s, 1, t,
                 0, 0, 1
                 );
        }
        public static Matrix3D CreateSkew3D_YZ(double skew1, double skew2)
        {
            //XY平面をZ座標でせん断する

            double s = skew1;
            double t = skew2;

            return new Matrix3D(
                 1, s, t,
                 0, 1, 0,
                 0, 0, 1
                 );
        }
        #endregion

        #endregion


アフィン変換3D(同次座標の数式)

平行移動

$$
\begin{bmatrix}
1 & 0 & 0 & t_x \\
0 & 1 & 0 & t_y \\
0 & 0 & 1 & t_z \\
0 & 0 & 0 & 1 \end{bmatrix}
$$

スケール

$$
\begin{bmatrix}
s_x & 0 & 0 & 0 \\
0 & s_y & 0 & 0 \\
0 & 0 & s_z & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
$$

回転

X軸

$$
\begin{bmatrix}
1 & 0 & 0 & 0 \\
0 & \cos \theta & -\sin \theta & 0 \\
0 & \sin \theta & \cos \theta & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}
$$

Y軸

$$
\begin{bmatrix}
\cos \theta & 0 & \sin \theta & 0 \\
0 & 1 & 0 & 0 \\
-\sin \theta & 0 & \cos \theta & 0 \\
0 & 0 & 0 & 1 \end{bmatrix}
$$

Z軸

$$
\begin{bmatrix} \cos \theta & -\sin \theta & 0 & 0 \\
\sin \theta & \cos \theta & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1 \end{bmatrix}
$$

スキュ

X軸方向

$$
\begin{bmatrix}
1 & 0 & s_x & 0 \\
0 & 1 & s_y & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1 \end{bmatrix}
$$

Y軸方向

$$
\begin{bmatrix}
1 & s_x & 0 & 0 \\
s_y & 1 & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1 \end{bmatrix}
$$

鏡映

X軸

$$
\begin{bmatrix}
-1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}
$$

Y軸

$$
\begin{bmatrix}
1 & 0 & 0 & 0 \\
0 & -1 & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1 \end{bmatrix}
$$

Z軸

$$
\begin{bmatrix}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & -1 & 0 \\
0 & 0 & 0 & 1 \end{bmatrix}
$$


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