Matrix2D(数式およびC#)



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

データ構造はdoubleを4つとする。

    public class Matrix2D
    {
        public double this[int i, int j]
        {
            get
            {
                if (i == 0 && j == 0) { return M00; }
                if (i == 0 && j == 1) { return M01; }

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

                throw new IndexOutOfRangeException();
            }
        }

        public double M00;
        public double M01;

        public double M10;
        public double M11;

        //行
        public Vector2D RowVector(int i)
        {
            if (i == 0) { return Row0; }
            if (i == 1) { return Row1; }

            throw new IndexOutOfRangeException();
        }
        public Vector2D Row0
        {
            get
            {
                return new Vector2D(M00, M01);
            }
        }
        public Vector2D Row1
        {
            get
            {
                return new Vector2D(M10, M11);
            }
        }

        //列
        public Vector2D ColumnVector(int j)
        {
            if (j == 0) { return Column0; }
            if (j == 1) { return Column1; }

            throw new IndexOutOfRangeException();
        }
        public Vector2D Column0
        {
            get
            {
                return new Vector2D(M00, M10);
            }
        }
        public Vector2D Column1
        {
            get
            {
                return new Vector2D(M01, M11);
            }
        }

        #region コンストラクタ

        public Matrix2D(double m00, double m01, double m10, double m11)
        {
            M00 = m00;
            M01 = m01;

            M10 = m10;
            M11 = m11;
        }

        public Matrix2D(Vector2D row1, Vector2D row2)
            : this(row1.X, row1.Y, row2.X, row2.Y) { }

        public static Matrix2D MakeFromRow(Vector2D row1, Vector2D row2)
        {
            Matrix2D ret = new Matrix2D(row1.X, row1.Y, row2.X, row2.Y);
            return ret;
        }
        public static Matrix2D MakeFromColumn(Vector2D col1, Vector2D col2)
        {
            Matrix2D ret = new Matrix2D(col1.X, col2.X, col1.Y, col2.Y);
            return ret;
        }

        #endregion
}

基本操作

2x2行列

$$
\begin{bmatrix} a & b \\ c & d \end{bmatrix}
$$

に対して

単位行列

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

転置

$$
\begin{bmatrix} a & c \\ b & d \end{bmatrix}
$$

行列式(determinant)

$$
ad-bc
$$

逆行列(inverse)

随伴行列割ることの行列式。

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

すなわち

$$
\frac{1}{ad-bc}\begin{bmatrix} d & -b \\ -c & a \end{bmatrix}
$$

余因子行列(cofactor)

2x2行列についての余因子行列は、元の行列の各要素に対応する余因子を要素として持つ行列です。

$$
\begin{bmatrix} d & -c \\ -b & a \end{bmatrix}
$$

となります。ここで、各要素は元の行列の対応する位置の余因子です。2x2行列の場合、各要素の余因子は単にその要素を除いた残りの要素の行列式(この場合、ただの数)になります。

随伴行列(adjugate)

余因子行列の転置

$$
\begin{bmatrix} d & -b \\ -c & a \end{bmatrix}
$$

基本操作(コード)

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

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

            get
            {
                return new Matrix2D(
                    M00, M10,
                    M01, M11);
            }
        }
        //2次行列式
        public double Determinant
        {
            get
            {
                return M00 * M11 - M01 * M10;
            }
        }

        
        //余因子行列
        public Matrix2D CofactorMatrix
        {
            get
            {
                return new Matrix2D(
                    M11, -M10,
                    -M01, M00);
            }
        }
        //随伴行列
        public Matrix2D AdjugateMatrix
        {
            get
            {
                return this.CofactorMatrix.Transpose;
            }
        }
        //逆行列
        public Matrix2D Inverse
        {
            get
            {
                double det = this.Determinant;
                if (det == 0)
                {
                    throw new InvalidOperationException("This matrix cannot be inverted because its determinant is zero.");
                }
                else
                {
                    Matrix2D adj = this.AdjugateMatrix;
                    return new Matrix2D(adj.M00 / det, adj.M01 / det, adj.M10 / det, adj.M11 / det);
                }
            }
        }



        //同時座標
        public Matrix3D Homogeneous
        {
            get
            {
                return new Matrix3D(
                    M00, M01, 0,
                    M10, M11, 0,
                    0, 0, 1
                );
            }
        }


演算子のオーバーロード


行列を右からしか受けていないし
ベクトルも受けていない

        #region Operator

        public static Matrix2D operator +(Matrix2D m1, Matrix2D m2)
        {
            return new Matrix2D(
                m1.M00 + m2.M00,
                m1.M01 + m2.M01,

                m1.M10 + m2.M10,
                m1.M11 + m2.M11
                );
        }

        public static Matrix2D operator -(Matrix2D m1, Matrix2D m2)
        {
            return new Matrix2D(
                m1.M00 - m2.M00,
                m1.M01 - m2.M01,

                m1.M10 - m2.M10,
                m1.M11 - m2.M11
                );
        }

        public static Matrix2D operator *(Matrix2D m, double f)
        {
            return new Matrix2D(
                m.M00 * f, m.M01 * f,
                m.M10 * f, m.M11 * f
                );
        }

        public static Matrix2D operator *(double f, Matrix2D m)
        {
            return new Matrix2D(
                m.M00 * f, m.M01 * f,
                m.M10 * f, m.M11 * f
                );
        }

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

            //左項は行ベクトルなのでそのまま
            //右項は列ベクトルなので鏡像反転からの回転=転置
            //(m00,m01,m02)   (m00,m10,m20)
            //(m10,m11,m12)   (m01,m11,m21)
            //(m20,m21,m22)   (m02,m12,m22)

            return new Matrix2D(
                //1行目
                m1.M00 * m2.M00 + m1.M01 * m2.M10,
                m1.M00 * m2.M01 + m1.M01 * m2.M11,
                //2行目
                m1.M10 * m2.M00 + m1.M11 * m2.M10,
                m1.M10 * m2.M01 + m1.M11 * m2.M11
                );
        }

        public static Matrix2D operator /(Matrix2D m, double f)
        {
            return new Matrix2D(
                m.M00 / f, m.M01 / f,
                m.M10 / f, m.M11 / f
                );
        }

        public static Matrix2D operator /(double f, Matrix2D m)
        {
            return new Matrix2D(
                m.M00 / f, m.M01 / f,
                m.M10 / f, m.M11 / f
                );
        }

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

            Matrix2D m = (Matrix2D)obj;
            return (this.M00 == m.M00) && (this.M01 == m.M01)
                && (this.M10 == m.M10) && (this.M11 == m.M11);

        }

        public override int GetHashCode()
        {
            return this.M00.GetHashCode() ^ this.M01.GetHashCode()
                 ^ this.M10.GetHashCode() ^ this.M11.GetHashCode();

        }

        public static bool operator ==(Matrix2D m1, Matrix2D 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 !=(Matrix2D m1, Matrix2D m2)
        {
            return !(m1 == m2);
        }

        #endregion

        #endregion


アフィン変換2D(数式)

平行移動

2*2行列の平行移動行列は2*2行列では表現できない。

$$
\begin{bmatrix}
x \\ y \end{bmatrix} \rightarrow \begin{bmatrix} x \\ y \end{bmatrix} + \begin{bmatrix} t_x \\ t_y
\end{bmatrix}
$$

同時座標の場合

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

使う時は右から縦ベクトルをひっかけて

$$
\begin{bmatrix}
1 & 0 & t_x \\
0 & 1 & t_y \\
0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
x\\
y\\
1
\end{bmatrix}
=
\begin{bmatrix}
x+t_x\\
y+t_y\\
1
\end{bmatrix}
$$

あるいは左から横ベクトルをひっかけるなら
平行移動行列は転置して

$$
\begin{bmatrix}
x, y, 1
\end{bmatrix}
\begin{bmatrix}
1 & 0 & 0 \\
0 & 1 & 0 \\
t_x & t_y & 1
\end{bmatrix}
=
\begin{bmatrix}
x+t_x, y+t_y, 1
\end{bmatrix}
$$

スケール

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

右から縦ベクトル

$$
\begin{bmatrix}
s_x & 0 \\
0 & s_y
\end{bmatrix}
\begin{bmatrix}
x\\
y
\end{bmatrix}
=
\begin{bmatrix}
s_xx \\
s_yy
\end{bmatrix}
$$

左から横ベクトル

$$
\begin{bmatrix}
x, y
\end{bmatrix}
\begin{bmatrix}
s_x & 0 \\
0 & s_y
\end{bmatrix}
=
\begin{bmatrix}
s_xx, s_yy
\end{bmatrix}
$$

回転

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

右から縦ベクトル

$$
\begin{bmatrix}
\cos \theta & -\sin \theta \\
\sin \theta & \cos \theta
\end{bmatrix}
\begin{bmatrix}
x\\
y
\end{bmatrix}
=
\begin{bmatrix}
x\cos\theta-y\sin\theta\\
x\sin\theta+y\cos\theta
\end{bmatrix}
$$

左から横ベクトル

$$
\begin{bmatrix}
x,y
\end{bmatrix}
\begin{bmatrix}
\cos \theta & \sin \theta \\
-\sin \theta & \cos \theta
\end{bmatrix}
=
\begin{bmatrix}
x\cos\theta-y\sin\theta, x\sin\theta+y\cos\theta
\end{bmatrix}
$$


スキュ

$$
\text{x軸方向のスキュー:} \begin{bmatrix} 1 & s_x \\ 0 & 1 \end{bmatrix}\\
\text{y軸方向のスキュー:} \begin{bmatrix} 1 & 0 \\ s_y & 1 \end{bmatrix}
$$

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

鏡映

$$
\text{x軸に対する鏡映:} \begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix} \\ \text{y軸に対する鏡映:} \begin{bmatrix} -1 & 0 \\ 0 & 1 \end{bmatrix}
$$

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

       #region アフィン変換
        // スケール行列を作成
        public static Matrix2D Scale(double scaleX, double scaleY)
        {
            return new Matrix2D(
                scaleX, 0,
                0, scaleY);
        }

        // 回転行列を作成
        public static Matrix2D Rotate(double radians)
        {
            double cos = Math.Cos(radians);
            double sin = Math.Sin(radians);
            return new Matrix2D(
                cos, -sin,
                sin, cos);
        }

        public static Matrix2D ReflectX()
        {
            return new Matrix2D(
                1, 0,
                0, -1
                );
        }

        public static Matrix2D ReflectY()
        {
            return new Matrix2D(
                -1, 0,
                0, 1
                );
        }

        public static Matrix2D Skew(double sx, double sy)
        {
            return new Matrix2D(
                1, sx,
                sy, 1
                );
        }

        #endregion

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