# 機能設計書: Matrix3（3x3行列）

## 1. 機能概要

### 1.1 機能の目的
Matrix3は、3x3行列を表現するためのクラスである。2D変換（平行移動、回転、スケール）、UV変換、法線行列の計算など、3x3行列を必要とする様々な操作に使用される。

### 1.2 主な機能
- 3x3行列の基本操作（設定、コピー、転置）
- 行列の乗算
- 逆行列の計算
- 行列式の計算
- 4x4行列からの抽出
- 法線行列の生成
- 2D変換行列の生成（平行移動、回転、スケール）
- UV変換の設定

### 1.3 関連する画面/コンポーネント
- テクスチャUV変換
- 法線変換
- 2Dグラフィックス変換
- シェーダーユニフォーム

## 2. 機能仕様

### 2.1 データ構造

```javascript
class Matrix3 {
    elements: Array<number>;  // 列優先の9要素配列
    isMatrix3: boolean;       // 型判定フラグ
}
```

### 2.2 行列の格納形式
```
行優先表記（コンストラクタ/set引数）:
| n11  n12  n13 |
| n21  n22  n23 |
| n31  n32  n33 |

列優先格納（elements配列）:
elements = [n11, n21, n31, n12, n22, n32, n13, n23, n33]
           [0]   [1]  [2]  [3]  [4]  [5]  [6]  [7]  [8]
```

### 2.3 プロパティ詳細

| プロパティ名 | 型 | 説明 | デフォルト値 |
|-------------|-----|------|-------------|
| elements | Array<number> | 列優先の行列要素（9要素） | 単位行列 |
| isMatrix3 | boolean | 型判定フラグ（読み取り専用） | true |

### 2.4 メソッド詳細

#### 2.4.1 基本操作
| メソッド | 説明 |
|---------|------|
| set(n11, n12, n13, n21, n22, n23, n31, n32, n33) | 行優先で要素を設定 |
| identity() | 単位行列に設定 |
| clone() | 複製を作成 |
| copy(m) | 他の行列をコピー |

#### 2.4.2 行列演算
| メソッド | 説明 |
|---------|------|
| multiply(m) | 後置乗算 (this * m) |
| premultiply(m) | 前置乗算 (m * this) |
| multiplyMatrices(a, b) | a * b の結果を格納 |
| multiplyScalar(s) | 全要素をスカラー乗算 |
| determinant() | 行列式を計算 |
| invert() | 逆行列を計算 |
| transpose() | 転置行列を計算 |

#### 2.4.3 変換
| メソッド | 説明 |
|---------|------|
| setFromMatrix4(m) | 4x4行列の左上3x3を抽出 |
| getNormalMatrix(m4) | 法線行列を計算（逆転置） |
| extractBasis(xAxis, yAxis, zAxis) | 基底ベクトルを抽出 |

#### 2.4.4 2D変換行列生成
| メソッド | 説明 |
|---------|------|
| makeTranslation(x, y) | 平行移動行列を生成 |
| makeRotation(theta) | 回転行列を生成 |
| makeScale(x, y) | スケール行列を生成 |
| setUvTransform(...) | UV変換行列を設定 |

#### 2.4.5 その他
| メソッド | 説明 |
|---------|------|
| scale(sx, sy) | 現在の行列にスケールを適用 |
| rotate(theta) | 現在の行列に回転を適用 |
| translate(tx, ty) | 現在の行列に平行移動を適用 |
| equals(m) | 等値比較 |
| fromArray(array, offset) | 配列から設定 |
| toArray(array, offset) | 配列に出力 |
| transposeIntoArray(r) | 転置して配列に出力 |

### 2.5 ビジネスルール
- 行列演算は元の行列を変更する（ミュータブル）
- コンストラクタとset()は行優先、内部格納は列優先
- 行列式が0の場合、invert()はゼロ行列を返す

## 3. 処理フロー

### 3.1 行列乗算フロー
```
[multiplyMatrices(a, b)]
        |
        v
[a, bの要素を取得]
ae = a.elements
be = b.elements
        |
        v
[3x3行列乗算計算]
結果[i,j] = Σ(a[i,k] * b[k,j]) for k=1,2,3
        |
        v
[this.elementsに格納]
        |
        v
[自身を返却]
```

### 3.2 逆行列計算フロー
```
[invert()]
      |
      v
[余因子行列の計算]
t11 = n33*n22 - n32*n23
t12 = n32*n13 - n33*n12
t13 = n23*n12 - n22*n13
      |
      v
[行列式の計算]
det = n11*t11 + n21*t12 + n31*t13
      |
      v
[det == 0?]
   Yes |         No
       v          |
[ゼロ行列設定]     |
       |          v
       |   [1/det * 余因子行列^T]
       |          |
       v          v
[自身を返却]<-----'
```

### 3.3 法線行列計算フロー
```
[getNormalMatrix(matrix4)]
        |
        v
[setFromMatrix4(matrix4)]
4x4行列の左上3x3を抽出
        |
        v
[invert()]
逆行列を計算
        |
        v
[transpose()]
転置行列を計算
        |
        v
[自身を返却]
```

## 4. コードリーディングガイド

### 4.1 推奨読解順序
1. **Matrix3.js** - クラス定義とプロパティ（1-76行目）
2. set()とidentity()メソッド（78-122行目）
3. 行列乗算（188-243行目）
4. 逆行列計算（287-319行目）
5. 2D変換生成（410-527行目）

### 4.2 重要な処理の詳細

#### コンストラクタ（46-76行目）
```javascript
constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
    Matrix3.prototype.isMatrix3 = true;

    this.elements = [
        1, 0, 0,
        0, 1, 0,
        0, 0, 1
    ];

    if ( n11 !== undefined ) {
        this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 );
    }
}
```
**62-68行目**: 単位行列で初期化（列優先格納）

#### set()（93-103行目）
```javascript
set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
    const te = this.elements;

    te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
    te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
    te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;

    return this;
}
```
行優先引数を列優先に変換して格納

#### multiplyMatrices()（215-243行目）
```javascript
multiplyMatrices( a, b ) {
    const ae = a.elements;
    const be = b.elements;
    const te = this.elements;

    const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
    const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
    const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];

    const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
    const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
    const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];

    te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
    // ... 残りの8要素
    return this;
}
```

#### invert()（287-319行目）
```javascript
invert() {
    const te = this.elements,
        n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ],
        // ...

        t11 = n33 * n22 - n32 * n23,
        t12 = n32 * n13 - n33 * n12,
        t13 = n23 * n12 - n22 * n13,

        det = n11 * t11 + n21 * t12 + n31 * t13;

    if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 );

    const detInv = 1 / det;
    // 余因子行列の転置をdetで割る
    return this;
}
```
解析的方法による逆行列計算

#### getNormalMatrix()（346-350行目）
```javascript
getNormalMatrix( matrix4 ) {
    return this.setFromMatrix4( matrix4 ).invert().transpose();
}
```
法線行列 = (ModelView行列の左上3x3)^(-1)^T

### 4.3 プログラム呼び出し階層図
```
Matrix3
├── 基本操作
│   ├── set()
│   ├── identity()
│   ├── clone() / copy()
│   └── extractBasis()
├── 行列演算
│   ├── multiply() → multiplyMatrices()
│   ├── premultiply() → multiplyMatrices()
│   ├── multiplyMatrices()
│   ├── multiplyScalar()
│   ├── determinant()
│   ├── invert()
│   └── transpose()
├── 変換
│   ├── setFromMatrix4()
│   ├── getNormalMatrix()
│   │   ├── setFromMatrix4()
│   │   ├── invert()
│   │   └── transpose()
│   └── transposeIntoArray()
├── 2D変換生成
│   ├── makeTranslation()
│   ├── makeRotation()
│   ├── makeScale()
│   ├── scale() → premultiply(makeScale())
│   ├── rotate() → premultiply(makeRotation())
│   ├── translate() → premultiply(makeTranslation())
│   └── setUvTransform()
└── 配列変換
    ├── fromArray()
    ├── toArray()
    └── equals()
```

### 4.4 データフロー図
```
[入力値 (n11-n33)]
      |
      v
[Matrix3インスタンス]
      |
      +---> [行列乗算] ---> [積行列]
      |
      +---> [逆行列] ---> [逆Matrix3]
      |
      +---> [法線行列] ---> [法線用Matrix3]
      |
      +---> [2D変換] ---> [変換Matrix3]
      |
      +---> [配列変換] ---> [number[9]]
```

### 4.5 関連ファイル一覧
| ファイルパス | 種別 | 役割 |
|-------------|------|------|
| src/math/Matrix3.js | メイン | Matrix3クラスの実装 |
| src/math/Matrix4.js | 関連 | 4x4行列（抽出元） |
| src/math/Vector2.js | 関連 | 2D変換での使用 |
| src/math/Vector3.js | 関連 | 基底ベクトル抽出 |
| src/textures/Texture.js | 関連 | UV変換での使用 |

## 5. 使用例

### 5.1 基本的な使用例
```javascript
// 行列の作成（行優先で指定）
const m = new THREE.Matrix3();
m.set(
    1, 2, 3,
    4, 5, 6,
    7, 8, 9
);

// 単位行列
m.identity();

// 行列乗算
const a = new THREE.Matrix3();
const b = new THREE.Matrix3();
m.multiplyMatrices(a, b);  // m = a * b
```

### 5.2 法線行列の計算
```javascript
const modelViewMatrix = new THREE.Matrix4();
// ... modelViewMatrixを設定

const normalMatrix = new THREE.Matrix3();
normalMatrix.getNormalMatrix(modelViewMatrix);

// シェーダーに渡す
material.uniforms.normalMatrix = { value: normalMatrix };
```

### 5.3 UV変換
```javascript
const uvTransform = new THREE.Matrix3();

// オフセット(0.5, 0.5)、繰り返し(2, 2)、回転45度、中心(0.5, 0.5)
uvTransform.setUvTransform(
    0.5, 0.5,  // tx, ty
    2, 2,      // sx, sy
    Math.PI / 4,  // rotation
    0.5, 0.5   // cx, cy
);

texture.matrix.copy(uvTransform);
```

### 5.4 2D変換の合成
```javascript
const transform = new THREE.Matrix3();
transform.identity();

// 変換を順番に適用（premultiplyなので逆順で適用される）
transform.translate(100, 50);  // 3. 平行移動
transform.rotate(Math.PI / 4); // 2. 回転
transform.scale(2, 2);         // 1. スケール
```

### 5.5 逆行列
```javascript
const m = new THREE.Matrix3();
m.set(
    2, 0, 0,
    0, 3, 0,
    0, 0, 1
);

const det = m.determinant();  // 6
m.invert();  // 逆行列を計算
```

## 6. 備考

### 6.1 行優先 vs 列優先
- **引数**: コンストラクタ、set()は行優先（人間が読みやすい）
- **格納**: elements配列は列優先（GPU/OpenGLに最適化）
- **注意**: ソースコードを読む際は転置が必要

### 6.2 パフォーマンス考慮事項
- 逆行列計算は比較的高コスト
- 頻繁に必要な場合はキャッシュを検討
- モジュールスコープの`_m3`で一時行列を再利用

### 6.3 精度の注意
- 行列式が0に近い場合、逆行列の精度が低下
- det === 0 の場合はゼロ行列が返る（エラーではない）

### 6.4 法線変換の数学的背景
法線は方向ベクトルだが、非一様スケールがある場合、単純な行列変換では正しく変換されない。法線行列（逆転置行列）を使用することで、正しい法線方向が得られる。
