# 機能設計書 46-EdgesGeometry

## 概要

本ドキュメントは、Three.jsライブラリにおけるエッジ（輪郭線）ジオメトリを生成するEdgesGeometryクラスの機能設計を記述する。

### 本機能の処理概要

EdgesGeometryは、既存のジオメトリからエッジ（辺）を抽出してLineSegmentsで描画可能な形式に変換するクラスである。隣接する面の法線角度が閾値を超える場合のみエッジを表示するため、オブジェクトの輪郭やハードエッジのみを強調表示することができる。

**業務上の目的・背景**：3Dモデルのエッジ表示は、CADビューア、テクニカルイラストレーション、NPR（非フォトリアリスティック）レンダリングにおいて重要な機能である。単純にすべてのエッジを表示するのではなく、面の角度に基づいてフィルタリングすることで、視覚的に意味のある輪郭線のみを抽出できる。これにより、オブジェクトの形状を効果的に強調したり、CAD図面のような表現を実現できる。

**機能の利用シーン**：
- CADビューアでのエッジ表示
- テクニカルイラストレーション
- NPR（非フォトリアリスティック）レンダリング
- デバッグ目的でのジオメトリ形状確認
- ゲームにおけるアウトライン効果

**主要な処理内容**：
1. 入力ジオメトリから三角形面を反復処理
2. 各エッジの両側の面の法線ベクトルを計算
3. 法線間の角度が閾値を超えるエッジのみを抽出
4. 境界エッジ（片側のみに面がある）も含める
5. 抽出したエッジを頂点配列として出力

**関連システム・外部連携**：BufferGeometry、Float32BufferAttribute、Vector3、Triangle、LineSegmentsなど

**権限による制御**：なし（クライアントサイドのJavaScriptライブラリのため）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに関連画面の定義なし |

## 機能種別

計算処理 / ジオメトリ生成

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| geometry | BufferGeometry | No | エッジを抽出する元のジオメトリ | デフォルト: null |
| thresholdAngle | number | No | エッジを表示する最小角度（度） | デフォルト: 1 |

### 入力データソース

コンストラクタ引数として直接渡される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| position属性 | Float32BufferAttribute | エッジの頂点位置データ（3成分/頂点、2頂点/エッジ） |
| parameters | Object | コンストラクタパラメータの保存（geometry, thresholdAngle） |

### 出力先

BufferGeometryの属性として格納され、LineSegmentsオブジェクトで使用される。

## 処理フロー

### 処理シーケンス

```
1. BufferGeometryの初期化
   └─ super()を呼び出し、基底クラスを初期化
2. パラメータの保存
   └─ this.parametersにgeometry, thresholdAngleを格納
3. 角度閾値の計算
   └─ thresholdDot = cos(DEG2RAD * thresholdAngle)
4. 入力ジオメトリの属性取得
   └─ インデックス属性、位置属性を取得
5. 三角形面の反復処理
   └─ 各面について法線を計算
6. エッジのハッシュ化と照合
   └─ 各エッジを順方向・逆方向ハッシュで管理
7. 角度判定とエッジ抽出
   └─ 法線の内積が閾値以下の場合のみエッジを追加
8. 未マッチエッジの追加
   └─ 境界エッジ（片側のみ面がある）を追加
9. position属性の設定
   └─ Float32BufferAttributeとして設定
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[BufferGeometry初期化]
    B --> C[パラメータ保存]
    C --> D{geometry !== null?}
    D -->|No| K[終了]
    D -->|Yes| E[角度閾値を計算]
    E --> F[三角形面を反復]
    F --> G[各面の法線を計算]
    G --> H[エッジをハッシュ化]
    H --> I{逆ハッシュが存在?}
    I -->|Yes| J{法線角度 > 閾値?}
    J -->|Yes| L[エッジを追加]
    J -->|No| M[エッジをスキップ]
    I -->|No| N[エッジデータを登録]
    L --> O{次のエッジ}
    M --> O
    N --> O
    O -->|あり| H
    O -->|なし| P[未マッチエッジを追加]
    P --> Q[position属性を設定]
    Q --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 角度閾値判定 | 隣接面の法線内積が閾値以下の場合のみエッジを表示 | 常時 |
| BR-002 | 境界エッジ | 片側のみに面があるエッジは常に表示 | 常時 |
| BR-003 | 縮退三角形スキップ | 同一頂点を含む三角形は処理をスキップ | 常時 |
| BR-004 | 頂点ハッシュ精度 | 頂点座標を10^4の精度で丸めてハッシュ化 | 常時 |
| BR-005 | 双方向ハッシュ | 各エッジを正方向・逆方向の両方でハッシュ管理 | 常時 |

### 計算ロジック

**角度閾値の計算**:
- thresholdDot = Math.cos(DEG2RAD * thresholdAngle)
- DEG2RAD = Math.PI / 180

**頂点ハッシュ**:
- precision = 10^4
- hash = `${Math.round(x * precision)},${Math.round(y * precision)},${Math.round(z * precision)}`

**エッジハッシュ**:
- hash = `${vertexHash0}_${vertexHash1}`
- reverseHash = `${vertexHash1}_${vertexHash0}`

**角度判定**:
- エッジ表示条件: normal1.dot(normal2) <= thresholdDot

## データベース操作仕様

該当なし（クライアントサイド処理のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 正常動作 | geometryがnullの場合 | 空のジオメトリが生成される |
| - | 暗黙的エラー | 無効なジオメトリの場合 | 予期しない結果の可能性 |

### リトライ仕様

該当なし

## トランザクション仕様

該当なし（クライアントサイド処理のみ）

## パフォーマンス要件

- 処理時間は入力ジオメトリの三角形面数に比例
- ハッシュテーブルを使用してエッジ照合を高速化

## セキュリティ考慮事項

該当なし（クライアントサイドのジオメトリ生成処理）

## 備考

- シリアライズ/デシリアライズには非対応（公式ドキュメントに記載）
- LineSegmentsと組み合わせて使用
- thresholdAngle=1がデフォルト（ほぼ平面でない限りエッジを表示）

---

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

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、EdgesGeometryが依存するコアクラスの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | BufferGeometry.js | `src/core/BufferGeometry.js` | getIndex, getAttribute の動作を理解 |
| 1-2 | Triangle.js | `src/math/Triangle.js` | getNormal メソッドを理解 |
| 1-3 | Vector3.js | `src/math/Vector3.js` | dot, fromBufferAttribute メソッドを理解 |

**読解のコツ**: EdgesGeometryはハッシュテーブルを用いたエッジ管理が核心。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | EdgesGeometry.js | `src/geometries/EdgesGeometry.js` | コンストラクタの全体フローを把握 |

**主要処理フロー**:
1. **35-51行目**: 初期化とパラメータ保存
2. **55-57行目**: precisionPoints, precision, thresholdDot計算
3. **59-61行目**: インデックス・位置属性の取得
4. **69-101行目**: 三角形面の反復と法線計算
5. **104-140行目**: エッジのハッシュ照合と角度判定
6. **146-160行目**: 未マッチエッジの追加
7. **162行目**: position属性の設定

#### Step 3: エッジ判定アルゴリズムを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | EdgesGeometry.js | `src/geometries/EdgesGeometry.js` | エッジハッシュと角度判定 |

**主要処理フロー**:
- **91-94行目**: 頂点ハッシュの生成
- **96-101行目**: 縮退三角形のスキップ
- **104-140行目**: エッジの照合ループ
- **113-114行目**: 正方向・逆方向ハッシュの生成
- **116-127行目**: 逆ハッシュが存在する場合の処理
- **120行目**: 法線内積による角度判定

### プログラム呼び出し階層図

```
EdgesGeometry.constructor(geometry, thresholdAngle)
    │
    ├─ geometry.getIndex()
    │      └─ インデックス属性を取得
    │
    ├─ geometry.getAttribute('position')
    │      └─ 位置属性を取得
    │
    ├─ Triangle.getNormal()
    │      └─ 三角形の法線を計算
    │
    ├─ Vector3.dot()
    │      └─ 法線間の内積計算
    │
    └─ setAttribute('position')
           └─ Float32BufferAttribute設定
```

### データフロー図

```
[入力]                      [処理]                           [出力]

BufferGeometry ──────────▶ EdgesGeometry
thresholdAngle                 │
                               │ 三角形反復
                               │ 法線計算
                               │ エッジハッシュ
                               │ 角度判定
                               ▼
                    ┌─────────────────────┐
                    │ BufferGeometry      │
                    │  - position属性     │ ────▶ LineSegmentsで使用
                    │  - parameters       │
                    └─────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EdgesGeometry.js | `src/geometries/EdgesGeometry.js` | ソース | エッジジオメトリクラス |
| BufferGeometry.js | `src/core/BufferGeometry.js` | ソース | ジオメトリ基底クラス |
| BufferAttribute.js | `src/core/BufferAttribute.js` | ソース | 頂点属性データ管理 |
| Triangle.js | `src/math/Triangle.js` | ソース | 三角形演算 |
| Vector3.js | `src/math/Vector3.js` | ソース | 3次元ベクトル演算 |
| MathUtils.js | `src/math/MathUtils.js` | ソース | DEG2RAD定数 |
| LineSegments.js | `src/objects/LineSegments.js` | ソース | エッジ描画オブジェクト |
