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
この記事が気に入ったらサポートをしてみませんか?