# 機能設計書 39-ShapeGeometry

## 概要

本ドキュメントはThree.jsにおけるシェイプジオメトリ（ShapeGeometry）クラスの機能設計を記述する。ShapeGeometryはBufferGeometryを継承し、2Dシェイプから平面的な3Dジオメトリを生成するクラスである。

### 本機能の処理概要

ShapeGeometryは3Dグラフィックスにおいて2Dシェイプ（Shape）から平面的なメッシュを生成するためのジオメトリクラスである。ExtrudeGeometryと異なり、押し出しを行わず、2D形状をそのまま平面ジオメトリとして生成する。穴を含むシェイプの三角形分割にも対応している。

**業務上の目的・背景**：3Dグラフィックスにおいて、平面的な2D形状を表示する必要がある場面は多い。ロゴ、UI要素、地図、フロアプラン、デカールなど、厚みを持たない平面オブジェクトが必要になる。ShapeGeometryはこれらを効率的に生成し、穴を含む複雑な形状も正しく三角形分割する。

**機能の利用シーン**：2Dロゴの3D空間での表示、UI要素の配置、地図やフロアプランの表示、デカール（貼り付けテクスチャ）の基盤、平面的なカスタム形状の表示。

**主要な処理内容**：
1. Shape（2Dシェイプ）または配列を受け取る
2. 各シェイプからextractPointsで輪郭と穴を抽出
3. 巻き方向を反時計回りに統一
4. ShapeUtilsで三角形分割（Earcutアルゴリズム）
5. Z=0の平面上に頂点を配置、法線は(0,0,1)
6. 複数シェイプの場合はマテリアルグループを設定

**関連システム・外部連携**：レンダラー（WebGLRenderer、WebGPURenderer）と連携してメッシュを描画する。Shapeクラス、ShapeUtilsと連携する。

**権限による制御**：特になし。全てのユーザーが利用可能。

## 関連画面

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

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| shapes | Shape \| Array<Shape> | No | 2Dシェイプまたは配列（デフォルト: 三角形） | なし |
| curveSegments | number | No | 曲線の分割数（デフォルト: 12） | なし |

### 入力データソース

コンストラクタ引数として直接指定される。Shapeは通常ShapeクラスやPathクラスで定義される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| position | Float32BufferAttribute | 頂点の3D位置座標（z=0） |
| normal | Float32BufferAttribute | 頂点の法線ベクトル（すべて(0,0,1)） |
| uv | Float32BufferAttribute | テクスチャマッピング用UV座標（ワールド座標） |
| index | Uint16/Uint32BufferAttribute | 三角形面のインデックス |
| groups | Array | マテリアルグループ（複数シェイプ時） |

### 出力先

BufferGeometry属性として保持され、Meshオブジェクトを通じてGPUに送信される。

## 処理フロー

### 処理シーケンス

```
1. コンストラクタ呼び出し
   └─ shapes と curveSegments を受け取る
2. shapesを配列に変換
3. 各シェイプに対して addShape を実行
   └─ 輪郭と穴を抽出
4. 巻き方向を確認・修正
   └─ 反時計回りに統一
5. ShapeUtils.triangulateShape で三角形分割
6. 頂点・法線・UV生成
   └─ z=0、法線=(0,0,1)、UV=頂点座標
7. インデックス生成
8. マテリアルグループ設定（複数シェイプ時）
9. BufferGeometry属性を設定
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[shapes, curveSegmentsを受け取る]
    B --> C{配列?}
    C -->|No| D[単一シェイプ処理]
    C -->|Yes| E[配列ループ処理]
    D --> F[addShape呼び出し]
    E --> F
    F --> G[extractPointsで輪郭・穴を抽出]
    G --> H[isClockWiseで巻き方向確認]
    H --> I{反時計回り?}
    I -->|No| J[reverseで反転]
    I -->|Yes| K[そのまま]
    J --> L[穴の巻き方向も確認]
    K --> L
    L --> M[triangulateShapeで三角形分割]
    M --> N[頂点生成: x,y,0]
    N --> O[法線生成: 0,0,1]
    O --> P[UV生成: x,y]
    P --> Q[インデックス生成]
    Q --> R{複数シェイプ?}
    R -->|Yes| S[addGroupでマテリアルグループ設定]
    R -->|No| T[属性設定]
    S --> T
    T --> U[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-39-001 | 巻き方向 | 輪郭は反時計回り、穴は時計回りに統一 | 常時 |
| BR-39-002 | 平面配置 | すべての頂点のz座標は0 | 常時 |
| BR-39-003 | 法線方向 | すべての頂点の法線は(0, 0, 1) | 常時 |
| BR-39-004 | UV座標 | UV座標はワールド座標（頂点のx, y） | 常時 |
| BR-39-005 | マテリアルグループ | 複数シェイプ時は各シェイプにグループを設定 | 複数シェイプ時 |

### 計算ロジック

頂点生成:
- position = (vertex.x, vertex.y, 0)
- normal = (0, 0, 1)
- uv = (vertex.x, vertex.y)

三角形分割はShapeUtils.triangulateShape（Earcutアルゴリズム）を使用。

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

該当なし（クライアントサイドのみで動作）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 警告 | 自己交差シェイプ | 三角形分割が失敗する可能性 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- 頂点数はシェイプの複雑さに依存
- 穴を含む複雑なシェイプは三角形分割に時間がかかる
- curveSegmentsを増やすと曲線の分解能が上がるが頂点数も増加

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

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

## 備考

- ExtrudeGeometryのdepth=0と同等だが、より軽量
- 両面表示が必要な場合はMaterialのsideプロパティを設定
- toJSON/fromJSONでシリアライズ・デシリアライズ可能

---

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

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

### 推奨読解順序

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

Shapeクラスと三角形分割の仕組みを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Shape.js | `src/extras/core/Shape.js` | 2Dシェイプの定義方法、extractPoints |
| 1-2 | ShapeUtils.js | `src/extras/ShapeUtils.js` | triangulateShape関数、isClockWise関数 |

**読解のコツ**: ShapeGeometryはExtrudeGeometryより単純で、押し出し処理がなく平面上に頂点を配置するだけ。

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

ShapeGeometryクラスのコンストラクタが処理の起点。

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

**主要処理フロー**:
1. **32行目**: コンストラクタでshapes, curveSegmentsを受け取る
2. **64-81行目**: shapesが配列か単一かで処理を分岐
3. **93-159行目**: addShape関数で各シェイプを処理
4. **85-88行目**: BufferGeometry属性設定

#### Step 3: addShape関数の詳細を理解する

シェイプ処理の中核となるaddShape関数。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ShapeGeometry.js | `src/geometries/ShapeGeometry.js` | 93-159行目のaddShape関数 |

**主要処理フロー**:
- **95-96行目**: indexOffsetとextractPoints
- **101-107行目**: 輪郭の巻き方向確認と反転
- **109-119行目**: 穴の巻き方向確認と反転
- **121行目**: triangulateShapeで三角形分割
- **125-130行目**: 穴の頂点を輪郭に結合
- **134-142行目**: 頂点・法線・UV生成
- **146-157行目**: インデックス生成

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

```
ShapeGeometry.constructor()
    │
    ├─ BufferGeometry.constructor()
    │
    ├─ 配列チェック
    │      └─ Array.isArray(shapes)
    │
    └─ 各shapeに対してaddShape(shape)
           │
           ├─ shape.extractPoints(curveSegments)
           │      ├─ shapeVertices (輪郭)
           │      └─ shapeHoles (穴)
           │
           ├─ ShapeUtils.isClockWise(shapeVertices)
           │      └─ 反時計回りでなければreverse
           │
           ├─ 各穴に対してisClockWise確認
           │      └─ 時計回りでなければreverse
           │
           ├─ ShapeUtils.triangulateShape(shapeVertices, shapeHoles)
           │      └─ faces配列を取得
           │
           ├─ 穴の頂点を輪郭に結合
           │
           ├─ 頂点ループ
           │      ├─ vertices.push(vertex.x, vertex.y, 0)
           │      ├─ normals.push(0, 0, 1)
           │      └─ uvs.push(vertex.x, vertex.y)
           │
           └─ facesループ
                  └─ indices.push(a, b, c)
```

### データフロー図

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

Shape ───────▶ ShapeGeometry ───▶ BufferGeometry
(輪郭+穴)          │                 (position,
                   │                  normal,
curveSegments ─▶   │                  uv,
                   ▼                  index,
              extractPoints           groups)
                   │
                   ▼
              isClockWise
              (巻き方向確認)
                   │
                   ▼
              triangulateShape
              (三角形分割)
                   │
                   ▼
              頂点生成
              (z=0平面上)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ShapeGeometry.js | `src/geometries/ShapeGeometry.js` | ソース | シェイプジオメトリクラス定義 |
| Shape.js | `src/extras/core/Shape.js` | ソース | 2Dシェイプ定義 |
| ShapeUtils.js | `src/extras/ShapeUtils.js` | ソース | 三角形分割、巻き方向判定 |
| Earcut.js | `src/extras/Earcut.js` | ソース | 三角形分割アルゴリズム |
| BufferGeometry.js | `src/core/BufferGeometry.js` | ソース | 基底クラス |
| Vector2.js | `src/math/Vector2.js` | ソース | 2Dベクトル |
