# 機能設計書 166-Shape

## 概要

本ドキュメントは、Three.jsライブラリにおけるShape機能の設計仕様を記述する。Shapeは、穴（hole）を含むことができる塗りつぶし可能な2Dシェイプを定義するクラスである。

### 本機能の処理概要

Shapeクラスは、Pathを継承し、穴（hole）の定義機能を追加した2Dシェイプを表現する。ExtrudeGeometryやShapeGeometryの入力として使用され、複雑な2D形状を3Dジオメトリに変換するための基盤となる。

**業務上の目的・背景**：ロゴ、文字、複雑な図形など、穴を含む2D形状は現実のグラフィックスで頻繁に使用される。例えば、「O」や「A」などの文字は外形と穴から構成される。Shapeクラスは、このような複雑な形状を統一的なインターフェースで表現し、3Dジオメトリへの変換を可能にする。

**機能の利用シーン**：
- フォントグリフの3D化
- ロゴや記号の押し出し
- 複雑な2D形状の3Dモデル化
- 建築図面の3D可視化
- ゲームやUIの2Dシェイプ

**主要な処理内容**：
1. holes - 穴の定義（Path配列）
2. getPointsHoles() - 各穴のポイント配列を取得
3. extractPoints() - シェイプと穴のポイントをまとめて取得
4. uuid - シェイプの一意識別子

**関連システム・外部連携**：ExtrudeGeometry、ShapeGeometry、ShapePath、フォントシステムと連携。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 直接的な画面関連なし（基盤クラス） |

## 機能種別

計算処理 / データ構造

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| points | Array<Vector2> | No | 初期化用の点配列 | Vector2の配列 |
| divisions | number | Yes | サンプリング分割数 | 正の整数 |

### 入力データソース

コンストラクタ引数またはPathから継承したメソッドで構築。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Shape | Shape | 構築されたシェイプオブジェクト |
| holes | Array<Path> | 穴を定義するパスの配列 |
| uuid | string | シェイプの一意識別子 |

### 出力先

メモリ上に保持され、extractPoints()等でジオメトリ生成に使用。

## 処理フロー

### 処理シーケンス

```
1. Shapeインスタンス生成
   └─ Pathコンストラクタを呼び出し
   └─ UUIDを生成
   └─ holes配列を空で初期化
2. シェイプの輪郭を定義
   └─ Path継承メソッド（moveTo, lineTo, bezierCurveTo等）
3. 穴を定義
   └─ Pathインスタンスを作成
   └─ holes配列に追加
4. extractPoints()で出力
   └─ シェイプのgetPoints()
   └─ getPointsHoles()で穴のポイント
```

### フローチャート

```mermaid
flowchart TD
    A[Shape生成] --> B[UUID生成]
    B --> C[holes配列初期化]
    C --> D[外形定義]
    D --> E{穴が必要?}
    E -->|Yes| F[Pathで穴を定義]
    F --> G[holes.push]
    G --> E
    E -->|No| H[extractPoints呼び出し]
    H --> I[getPoints - 外形]
    H --> J[getPointsHoles - 穴]
    I --> K[結果オブジェクト返却]
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 巻き方向 | 穴は外形と逆の巻き方向（CW/CCW）で定義 | 常時 |
| BR-002 | UUID生成 | 各Shapeに一意のUUIDを自動生成 | コンストラクタ |
| BR-003 | 穴の独立性 | 各穴はPathインスタンスとして独立 | 常時 |

### 計算ロジック

extractPoints(): `{ shape: this.getPoints(divisions), holes: this.getPointsHoles(divisions) }`形式でオブジェクトを返却。

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 特になし | - |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- 穴の数に比例したメモリ使用
- extractPoints()は外形と穴の点数に比例した計算時間

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

特になし

## 備考

- 巻き方向（時計回り/反時計回り）は正しく設定する必要がある
- ShapeUtilsで巻き方向の判定が可能

---

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

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

### 推奨読解順序

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

ShapeはPathを継承し、holesプロパティで穴を管理する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Shape.js | `src/extras/core/Shape.js` | クラス定義とプロパティ構造（35-65行目） |

**読解のコツ**: uuidは一意識別子として使用され、holesはPath配列として穴を保持する。Pathの全メソッドが外形定義に使用可能。

#### Step 2: コンストラクタを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Shape.js | `src/extras/core/Shape.js` | constructor (42-65行目) |

**主要処理フロー**:
1. **44行目**: super(points)でPathを初期化
2. **52行目**: generateUUID()でuuidを生成
3. **54行目**: type = 'Shape'
4. **63行目**: holes = []で空配列初期化

#### Step 3: ポイント取得メソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Shape.js | `src/extras/core/Shape.js` | getPointsHoles (74-86行目) |
| 3-2 | Shape.js | `src/extras/core/Shape.js` | extractPoints (97-106行目) |

**主要処理フロー**:
- **76-82行目**: 各穴についてgetPoints(divisions)を呼び出し
- **99-103行目**: シェイプと穴のポイントをオブジェクトにまとめて返却

#### Step 4: シリアライゼーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Shape.js | `src/extras/core/Shape.js` | copy (108-124行目) |
| 4-2 | Shape.js | `src/extras/core/Shape.js` | toJSON (126-142行目) |
| 4-3 | Shape.js | `src/extras/core/Shape.js` | fromJSON (144-160行目) |

**主要処理フロー**:
- **112-118行目**: holesを深くクローン
- **130-136行目**: holesを各々toJSON()
- **148-154行目**: holesをPathとして復元

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

```
Shape extends Path
    │
    ├─ constructor(points)
    │      ├─ super(points)
    │      ├─ generateUUID()
    │      └─ holes = []
    │
    ├─ getPointsHoles(divisions)
    │      └─ holes[i].getPoints(divisions) [繰り返し]
    │
    ├─ extractPoints(divisions)
    │      ├─ this.getPoints(divisions) [外形]
    │      └─ this.getPointsHoles(divisions) [穴]
    │
    ├─ copy(source)
    │      ├─ super.copy(source)
    │      └─ holes[i].clone() [繰り返し]
    │
    ├─ toJSON()
    │      ├─ super.toJSON()
    │      └─ holes[i].toJSON() [繰り返し]
    │
    └─ fromJSON(json)
           ├─ super.fromJSON(json)
           └─ new Path().fromJSON(hole) [繰り返し]
```

### データフロー図

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

points ────────────────▶ constructor ─────────────────▶ Shape
                           ├─ Path初期化                  - uuid
                           ├─ UUID生成                    - holes[]
                           └─ holes初期化

Path ──────────────────▶ holes.push ──────────────────▶ holes配列更新

divisions ─────────────▶ extractPoints ───────────────▶ {shape, holes}
                           ├─ getPoints()
                           └─ getPointsHoles()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Shape.js | `src/extras/core/Shape.js` | ソース | 本機能のメイン実装 |
| Path.js | `src/extras/core/Path.js` | ソース | 基底クラス |
| CurvePath.js | `src/extras/core/CurvePath.js` | ソース | Pathの基底 |
| ShapePath.js | `src/extras/core/ShapePath.js` | ソース | 複合シェイプ |
| MathUtils.js | `src/math/MathUtils.js` | ソース | generateUUID |
| ShapeUtils.js | `src/extras/ShapeUtils.js` | ソース | 巻き方向判定等 |
| ShapeGeometry.js | `src/geometries/ShapeGeometry.js` | ソース | シェイプジオメトリ |
| ExtrudeGeometry.js | `src/geometries/ExtrudeGeometry.js` | ソース | 押し出しジオメトリ |
