# 機能設計書 133-Sphere

## 概要

本ドキュメントは、Three.jsの数学ライブラリにおける3D球体を表現するSphereクラスの機能設計書である。

### 本機能の処理概要

Sphereクラスは、3D空間における解析的な球体を表現するためのクラスである。中心点（center）と半径（radius）によって球体を定義し、主に3Dオブジェクトの境界球（Bounding Sphere）として使用される。AABBよりも回転に対して安定した境界判定を提供する。

**業務上の目的・背景**：3Dグラフィックスにおいて、境界球はAABB（Box3）と並ぶ重要な境界ボリュームである。球体は回転に対して不変であるため、回転するオブジェクトの高速な衝突検出や、視錐台カリングの事前判定に適している。また、点群の最小外接球の計算など、幾何学的な計算にも使用される。

**機能の利用シーン**：
- 3Dオブジェクトの境界球計算（BufferGeometryのboundingSphere）
- 視錐台カリングの高速事前判定
- 球-球、球-平面、球-ボックスの衝突検出
- カメラのフレーミング（オブジェクトを画面に収める）
- LOD（Level of Detail）の距離計算
- 点群の包含球計算

**主要な処理内容**：
1. 境界球の生成と初期化（中心と半径の設定）
2. 点群からの最小包含球の計算
3. 点・球・平面・ボックスとの包含・交差判定
4. 境界ボックスへの変換
5. 球の拡張・合成
6. Matrix4による変換（中心の移動と半径のスケーリング）
7. JSONシリアライズ/デシリアライズ

**関連システム・外部連携**：BufferGeometry、Frustum、Raycaster、Box3などと連携。

**権限による制御**：なし（純粋な数学ユーティリティクラス）

## 関連画面

本機能は数学ユーティリティであり、直接的な画面との関連はない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 内部計算処理として使用 |

## 機能種別

計算処理 / ジオメトリ演算

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| center | Vector3 | No | 球の中心座標 | デフォルト: (0, 0, 0) |
| radius | number | No | 球の半径 | デフォルト: -1（空の球） |

### 入力データソース

コンストラクタ引数、メソッド呼び出し、または点群からの自動計算

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| isSphere | boolean | Sphereインスタンス識別フラグ（常にtrue） |
| center | Vector3 | 球の中心座標 |
| radius | number | 球の半径（負の値は空の球） |

### 出力先

メモリ上のオブジェクトとして保持、またはJSONへのシリアライズ

## 処理フロー

### 処理シーケンス

```
1. 境界球の初期化
   └─ center=(0,0,0), radius=-1で初期化（空の球）
2. データソースからの境界設定
   ├─ set: 直接設定
   └─ setFromPoints: 点群からの最小包含球計算
       ├─ 中心点の計算（指定またはAABBから算出）
       └─ 最大距離を半径として設定
3. 包含・交差判定
   ├─ containsPoint
   ├─ intersectsSphere
   ├─ intersectsBox
   └─ intersectsPlane
4. 球の操作
   ├─ applyMatrix4: 行列変換（中心移動+スケール）
   ├─ expandByPoint: 点を含むように拡張
   └─ union: 2つの球を包含する最小球
5. シリアライズ
   └─ toJSON/fromJSON
```

### フローチャート

```mermaid
flowchart TD
    A[Sphereインスタンス生成] --> B{初期化方法}
    B -->|set| C[中心と半径を直接設定]
    B -->|setFromPoints| D[点群から計算]
    D --> D1[中心点決定]
    D1 --> D2[最大距離を半径に]
    C --> E[境界球確定]
    D2 --> E
    E --> F{操作種別}
    F -->|包含判定| G[containsPoint]
    F -->|交差判定| H[intersects系]
    F -->|変換| I[applyMatrix4]
    F -->|拡張| J[expandByPoint/union]
    F -->|変換| K[getBoundingBox]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 空の球表現 | radius < 0の場合、球は空とみなされる | isEmpty()判定時 |
| BR-002 | 点の球 | radius == 0の場合、中心点のみを含む | containsPoint判定時 |
| BR-003 | スケール適用 | applyMatrix4は最大スケール軸を半径に適用 | 非一様スケール時 |

### 計算ロジック

**点との距離計算**:
```javascript
distanceToPoint = length(point - center) - radius
// 負の値 = 点は球の内部
```

**球同士の交差判定**:
```javascript
radiusSum = sphere1.radius + sphere2.radius
intersects = distanceSq(center1, center2) <= radiusSum * radiusSum
```

**Matrix4適用時のスケーリング**:
```javascript
newRadius = radius * matrix.getMaxScaleOnAxis()
// 最大スケール軸を使用して保守的に拡大
```

**点を含む最小球への拡張**:
```javascript
if (point outside sphere) {
  delta = (distance - radius) * 0.5
  center += normalize(point - center) * delta
  radius += delta
}
```

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

該当なし（純粋な計算処理クラス）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 空の球 | radius < 0の状態で演算 | isEmpty()で事前チェック |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- 基本メソッドはO(1)の計算量
- setFromPointsはO(n)（nは点の数）
- メモリ使用量: Vector3 + number = 28バイト程度

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

該当なし（純粋な数学計算）

## 備考

- BufferGeometry.computeBoundingSphere()で自動計算されboundingSphereプロパティに格納
- Frustum.intersectsSphere()で視錐台カリングの事前判定に使用
- Box3.getBoundingSphere()でAABBから境界球を取得可能
- 回転に対して不変という特性から、回転するオブジェクトに適している

---

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

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

### 推奨読解順序

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

Sphereクラスはcenter（Vector3）とradius（number）で球を表現する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Vector3.js | `src/math/Vector3.js` | Sphereが依存する3Dベクトルクラス |
| 1-2 | Sphere.js | `src/math/Sphere.js` | クラスのプロパティ定義（center, radius, isSphere） |

**読解のコツ**: radius=-1が「空の球」を表す規約を理解する。radius=0は中心点のみを含む有効な球。

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

Sphereクラスのコンストラクタとsetterを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Sphere.js | `src/math/Sphere.js` | コンストラクタとsetFromPoints |

**主要処理フロー**:
1. **20-45行目**: コンストラクタでcenter/radiusを初期化
2. **54-61行目**: set() - 直接設定
3. **73-99行目**: setFromPoints() - 点群からの最小包含球計算

#### Step 3: setFromPointsの詳細を理解する

点群から境界球を計算するロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Sphere.js | `src/math/Sphere.js` | setFromPoints()の実装（73-99行目） |

**主要処理フロー**:
- **77-85行目**: 中心点の決定（指定がなければAABBの中心を使用）
- **87-95行目**: 各点との距離の二乗を計算し、最大値を保持
- **95行目**: sqrt(maxRadiusSq)を半径として設定

#### Step 4: 交差判定を理解する

各種オブジェクトとの交差判定ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Sphere.js | `src/math/Sphere.js` | intersects系メソッド群 |

**主要処理フロー**:
- **177-183行目**: intersectsSphere() - 半径の合計と中心間距離の比較
- **191-195行目**: intersectsBox() - Box3.intersectsSphere()に委譲
- **203-207行目**: intersectsPlane() - 中心と平面の距離 <= 半径

#### Step 5: expandByPointとunionを理解する

球を拡張するロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Sphere.js | `src/math/Sphere.js` | expandByPoint()とunion()の実装 |

**主要処理フロー**:
- **293-325行目**: expandByPoint() - 点が外部にある場合のみ拡張
  - **313-319行目**: 中心を点の方向に移動し、半径を増加
- **333-365行目**: union() - 2つの球を包含する最小球を計算

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

```
Sphere
    │
    ├─ setFromPoints(points, optionalCenter)
    │      ├─ Box3.setFromPoints() [centerが未指定の場合]
    │      │      └─ Box3.getCenter()
    │      └─ center.distanceToSquared() [loop]
    │             └─ Math.sqrt() for radius
    │
    ├─ intersectsSphere(sphere)
    │      └─ center.distanceToSquared()
    │
    ├─ intersectsBox(box)
    │      └─ Box3.intersectsSphere(this)
    │
    ├─ applyMatrix4(matrix)
    │      ├─ center.applyMatrix4()
    │      └─ matrix.getMaxScaleOnAxis()
    │
    ├─ expandByPoint(point)
    │      ├─ center.distanceToSquared()
    │      ├─ _v1.subVectors() / normalize()
    │      └─ center.addScaledVector()
    │
    └─ union(sphere)
           ├─ isEmpty() check
           └─ expandByPoint() [2回]
```

### データフロー図

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

Vector3[] ─────────▶ setFromPoints() ──────▶ Sphere {center, radius}
(点群)                 (AABB中心 + 最大距離)

Sphere ────────────▶ intersectsSphere() ───▶ boolean
(他の球)              (半径和 vs 距離)

Matrix4 ───────────▶ applyMatrix4() ────────▶ Sphere {center, radius}
(変換行列)            (中心移動 + 最大スケール)  (変換後)

Sphere ────────────▶ getBoundingBox() ─────▶ Box3 {min, max}
                     (center ± radius)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Sphere.js | `src/math/Sphere.js` | ソース | 境界球クラス本体 |
| Vector3.js | `src/math/Vector3.js` | ソース | 3Dベクトルクラス（依存） |
| Box3.js | `src/math/Box3.js` | ソース | 3D境界ボックス（相互参照） |
| Plane.js | `src/math/Plane.js` | ソース | 平面クラス（交差判定で使用） |
| Matrix4.js | `src/math/Matrix4.js` | ソース | 変換行列（applyMatrix4で使用） |
| BufferGeometry.js | `src/core/BufferGeometry.js` | ソース | boundingSphere計算で使用 |
| Frustum.js | `src/math/Frustum.js` | ソース | 視錐台カリングで使用 |
