練習用その2 アフィン変換に対応した2×2(実際は3×3)行列クラス

前回を踏まえて新しく実装。

大分マシになってきた。

#include <cmath>
#include "vector2.h"

// アフィン変換に対応した2×2(実際は3×3)行列クラス

namespace ddp {
    static const float PI = 6*static_cast<float>(asin( 0.5 ));
    
    class Matrix2 {
    private:
    
    public:
        float m[3][3];
        
        // 恒等行列として初期化する
        Matrix2 () {
            m[0][0] = 1; m[0][1] = 0; m[0][2] = 0;
            m[1][0] = 0; m[1][1] = 1; m[1][2] = 0;
            m[2][0] = 0; m[2][1] = 0; m[2][2] = 1;
        }
        
        // 値を指定する
        Matrix2 (float m11,float m12,float m21,float m22,float tx,float ty) {
            m[0][0] = m11; m[0][1] = m12; m[0][2] = 0;
            m[1][0] = m21; m[1][1] = m22; m[1][2] = 0;
            m[2][0] = tx;  m[2][1] = ty;  m[2][2] = 1;
        }
        
        // コピーコンストラクタ
        Matrix2(const Matrix2 &mat) {
            m[0][0] = mat.m[0][0]; m[0][1] = mat.m[0][1]; m[0][2] = mat.m[0][2];
            m[1][0] = mat.m[1][0]; m[1][1] = mat.m[1][1]; m[1][2] = mat.m[1][2];
            m[2][0] = mat.m[2][0]; m[2][1] = mat.m[2][1]; m[2][2] = mat.m[2][2];
        }
        
        // 自身のクローンの生成
        Matrix2 clone () const {
            return Matrix2(
                m[0][0],m[0][1],
                m[1][0],m[1][1],
                m[2][0],m[2][1]
            );
        }
        
        // 行列同士の掛け算
        Matrix2 operator*(const Matrix2 &mat) const {
            return Matrix2(
                m[0][0] * mat.m[0][0] + m[0][1] * mat.m[1][0] + m[0][2] * mat.m[2][0],
                m[0][0] * mat.m[0][1] + m[0][1] * mat.m[1][1] + m[0][2] * mat.m[2][1],
                m[1][0] * mat.m[0][0] + m[1][1] * mat.m[1][0] + m[1][2] * mat.m[2][0],
                m[1][0] * mat.m[0][1] + m[1][1] * mat.m[1][1] + m[1][2] * mat.m[2][1],
                m[2][0] * mat.m[0][0] + m[2][1] * mat.m[1][0] + m[2][2] * mat.m[2][0],
                m[2][0] * mat.m[0][1] + m[2][1] * mat.m[1][1] + m[2][2] * mat.m[2][1]
            ); 
        }
        
        Matrix2& operator*=(const Matrix2 &mat) {
            // m13,m23,m33はアフィン変換用の0,0,1固定なので計算する必要が無いのでコメントアウトしておく
            
            float m11 = m[0][0] * mat.m[0][0] + m[0][1] * mat.m[1][0] + m[0][2] * mat.m[2][0];
            float m12 = m[0][0] * mat.m[0][1] + m[0][1] * mat.m[1][1] + m[0][2] * mat.m[2][1];
            //float m13 = m[0][0] * mat.m[0][2] + m[0][1] * mat.m[1][2] + m[0][2] * mat.m[2][2];
            
            float m21 = m[1][0] * mat.m[0][0] + m[1][1] * mat.m[1][0] + m[1][2] * mat.m[2][0];
            float m22 = m[1][0] * mat.m[0][1] + m[1][1] * mat.m[1][1] + m[1][2] * mat.m[2][1];
            //float m23 = m[1][0] * mat.m[0][2] + m[1][1] * mat.m[1][2] + m[1][2] * mat.m[2][2];
            
            float m31 = m[2][0] * mat.m[0][0] + m[2][1] * mat.m[1][0] + m[2][2] * mat.m[2][0];
            float m32 = m[2][0] * mat.m[0][1] + m[2][1] * mat.m[1][1] + m[2][2] * mat.m[2][1];
            //float m33 = m[2][0] * mat.m[0][2] + m[2][1] * mat.m[1][2] + m[2][2] * mat.m[2][2];
            
            m[0][0] = m11; m[0][1] = m12; // m[0][2] = m13;
            m[1][0] = m21; m[1][1] = m22; // m[1][2] = m23;
            m[2][0] = m31; m[2][1] = m32; // m[2][2] = m33;
            
            return *this;
        }
        
        // 回転(ラジアン指定)
        Matrix2& rotate_rad (float rot) {
            float cos = cosf(rot);
            float sin = sinf(rot);
            
            // 回転行列
            return *this *= Matrix2(
                 cos,sin,
                -sin,cos,
                0,0
            );
        }
        
        // 回転(度数指定)
        Matrix2& rotate_deg (float rot) {
            return rotate_rad( rot * PI / 180.0f );
        }
        
        // スケール
        Matrix2& scale (float x,float y) {
            return *this *= Matrix2(
                x,0,
                0,y,
                0,0
            );
        }
        
        // 平行移動
        Matrix2& translate(float x,float y) {
            return *this *= Matrix2(
                1,0,
                0,1,
                x,y
            );
        }
    };
};
#include <iostream>
#include "matrix2.h"
using std::cout;
using std::endl;

int main () {
    
    ddp::Matrix2 mat1;
    
    mat1.rotate_deg(30.0f).scale(1,2).translate(5,0);
    
    cout << mat1.m[0][0] << "," << mat1.m[0][1] <<  "," << mat1.m[0][2] << endl;
    cout << mat1.m[1][0] << "," << mat1.m[1][1] <<  "," << mat1.m[1][2] << endl;
    cout << mat1.m[2][0] << "," << mat1.m[2][1] <<  "," << mat1.m[2][2] << endl;
    
    return 0;
}
$ main
0.866025,1,0
-0.5,1.73205,0
5,0,1

やはり、floatで持つ方が色々と扱いやすい。

今は3×3固定の行列だけど汎用的に作ろうと思ったらかなり大変な気がする。とりあえず一旦このくらいで。