# 機能設計書 139-Spherical

## 概要

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

### 本機能の処理概要

Sphericalクラスは、3D空間における点を[球面座標系](https://en.wikipedia.org/wiki/Spherical_coordinate_system)で表現するためのクラスである。原点からの距離（radius）、Y軸（上方向）からの極角（phi）、Y軸周りの方位角（theta）の3つのパラメータで位置を定義する。カメラのオービットコントロールなど、極座標的な操作に適している。

**業務上の目的・背景**：3Dグラフィックスにおいて、球面座標はカメラの回転操作、天球の位置計算、放射状のパターン配置など、デカルト座標よりも自然に表現できる操作に使用される。特にOrbitControlsでは、ユーザーのマウス操作を球面座標の角度変化として扱うことで、直感的なカメラ操作を実現する。

**機能の利用シーン**：
- OrbitControlsでのカメラ回転操作
- ターゲット周りのカメラ配置
- 天球上の位置計算（太陽、月、星など）
- 球面上への点の配置
- 極座標グラフの描画
- 球面状のパーティクル配置

**主要な処理内容**：
1. 球面座標の生成と初期化（radius, phi, theta）
2. Vector3（デカルト座標）からの変換
3. デカルト座標への逆変換（Vector3.setFromSpherical）
4. phi値の安全範囲へのクランプ（makeSafe）

**関連システム・外部連携**：Vector3、OrbitControls、CameraControlsなどと連携。

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

## 関連画面

本機能は数学ユーティリティであり、直接的な画面との関連はないが、カメラコントロールで間接的に使用される。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | カメラコントロール（OrbitControls等）で内部使用 |

## 機能種別

計算処理 / 座標変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| radius | number | No | 原点からの距離 | デフォルト: 1 |
| phi | number | No | Y軸からの極角（ラジアン） | デフォルト: 0 |
| theta | number | No | Y軸周りの方位角（ラジアン） | デフォルト: 0 |

### 入力データソース

コンストラクタ引数、メソッド呼び出し、またはVector3からの変換

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| radius | number | 原点からの距離 |
| phi | number | Y軸からの極角（ラジアン、0〜PI） |
| theta | number | Y軸周りの方位角（ラジアン） |

### 出力先

メモリ上のオブジェクトとして保持

## 処理フロー

### 処理シーケンス

```
1. 球面座標の初期化
   └─ radius=1, phi=0, theta=0で初期化
2. 座標の設定
   ├─ set: 直接設定
   ├─ setFromVector3: デカルト座標から変換
   └─ setFromCartesianCoords: x,y,zから変換
3. 安全範囲へのクランプ
   └─ makeSafe: phiを(EPS, PI-EPS)にクランプ
4. 利用側での変換
   └─ Vector3.setFromSpherical: デカルト座標へ変換
```

### フローチャート

```mermaid
flowchart TD
    A[Sphericalインスタンス生成] --> B{設定方法}
    B -->|set| C[radius/phi/thetaを直接設定]
    B -->|setFromVector3| D[Vector3から変換]
    B -->|setFromCartesianCoords| E[x,y,zから変換]
    D --> F[radiusを計算]
    E --> F
    F --> G{radius == 0?}
    G -->|Yes| H[theta=0, phi=0]
    G -->|No| I[theta=atan2/x,z/, phi=acos/y/radius/]
    C --> J[球面座標確定]
    H --> J
    I --> J
    J --> K{makeSafe?}
    K -->|Yes| L[phiをEPS〜PI-EPSにクランプ]
    K -->|No| M[そのまま使用]
    L --> N[カメラ操作等で使用]
    M --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | Y-up座標系 | Y軸が上方向として扱われる | 全操作 |
| BR-002 | 角度の範囲 | phi: 0〜PI、theta: -PI〜PI | setFromCartesianCoords |
| BR-003 | 特異点回避 | makeSafe()でphi=0やphi=PIの特異点を回避 | カメラ操作時 |
| BR-004 | radius=0 | 原点の場合、phi=0, theta=0とする | setFromCartesianCoords |

### 計算ロジック

**デカルト座標から球面座標への変換**:
```javascript
radius = sqrt(x*x + y*y + z*z)
if (radius == 0) {
  theta = 0
  phi = 0
} else {
  theta = atan2(x, z)  // X-Z平面での角度
  phi = acos(clamp(y / radius, -1, 1))  // Y軸からの角度
}
```

**球面座標からデカルト座標への変換**（Vector3.setFromSpherical）:
```javascript
sinPhiRadius = sin(phi) * radius
x = sinPhiRadius * sin(theta)
y = cos(phi) * radius
z = sinPhiRadius * cos(theta)
```

**makeSafe()のクランプ**:
```javascript
EPS = 0.000001
phi = clamp(phi, EPS, PI - EPS)
// phi=0（真上）やphi=PI（真下）での特異点を回避
```

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 特異点 | phi=0またはphi=PIでジンバルロック的な問題 | makeSafe()を使用 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- 全メソッドO(1)の計算量
- メモリ使用量: number x 3 = 24バイト程度

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

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

## 備考

- OrbitControlsで最も頻繁に使用される
- phi=0は真上（Y軸正方向）、phi=PIは真下（Y軸負方向）
- theta=0はZ軸正方向、theta=PI/2はX軸正方向
- Cylindrical（円筒座標）は同様のコンセプトで別の座標系を提供

---

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

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

### 推奨読解順序

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

Sphericalクラスはradius, phi, thetaの3つの数値で球面座標を表現する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Spherical.js | `src/math/Spherical.js` | クラスのプロパティ定義（radius, phi, theta） |
| 1-2 | Vector3.js | `src/math/Vector3.js` | setFromSphericalでの逆変換を確認 |

**読解のコツ**: Three.jsはY-up座標系を採用。phiはY軸（上下）からの角度、thetaはY軸周り（左右）の角度。

#### Step 2: 基本操作を理解する

Sphericalクラスの基本的な操作メソッドを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Spherical.js | `src/math/Spherical.js` | set, copy, makeSafe |

**主要処理フロー**:
1. **16-42行目**: コンストラクタでradius/phi/thetaを初期化
2. **52-60行目**: set() - 値を直接設定
3. **68-76行目**: copy() - 他のSphericalからコピー
4. **84-91行目**: makeSafe() - phiを安全範囲にクランプ

#### Step 3: 座標変換を理解する

デカルト座標との相互変換を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Spherical.js | `src/math/Spherical.js` | setFromVector3, setFromCartesianCoords |
| 3-2 | Vector3.js | `src/math/Vector3.js` | setFromSpherical |

**主要処理フロー**:
- **100-104行目**: setFromVector3() - Vector3からの変換
- **114-132行目**: setFromCartesianCoords() - x,y,zからの変換
  - **116行目**: radiusの計算（sqrt(x*x + y*y + z*z)）
  - **118-122行目**: radius=0の場合の処理
  - **125-126行目**: theta=atan2(x,z), phi=acos(y/radius)

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

```
Spherical
    │
    ├─ set(radius, phi, theta)
    │      └─ 直接プロパティに設定
    │
    ├─ setFromVector3(v)
    │      └─ setFromCartesianCoords(v.x, v.y, v.z)
    │
    ├─ setFromCartesianCoords(x, y, z)
    │      ├─ radius = sqrt(x*x + y*y + z*z)
    │      ├─ if (radius == 0) theta=0, phi=0
    │      ├─ theta = atan2(x, z)
    │      └─ phi = acos(clamp(y/radius, -1, 1))
    │
    ├─ makeSafe()
    │      └─ phi = clamp(phi, EPS, PI - EPS)
    │
    └─ clone()
           └─ new Spherical().copy(this)

Vector3.setFromSpherical(spherical)
    ├─ sinPhiRadius = sin(phi) * radius
    ├─ x = sinPhiRadius * sin(theta)
    ├─ y = cos(phi) * radius
    └─ z = sinPhiRadius * cos(theta)
```

### データフロー図

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

Vector3 ───────────▶ setFromVector3() ─────────▶ Spherical
(デカルト座標)          setFromCartesianCoords()   {radius, phi, theta}
                        ↓
                        radius = sqrt(x*x+y*y+z*z)
                        theta = atan2(x, z)
                        phi = acos(y / radius)

Spherical ─────────▶ makeSafe() ───────────────▶ Spherical
                     clamp(phi, EPS, PI-EPS)      (安全な範囲)

Spherical ─────────▶ Vector3.setFromSpherical() ▶ Vector3
                     (逆変換)                     (デカルト座標)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Spherical.js | `src/math/Spherical.js` | ソース | 球面座標クラス本体 |
| MathUtils.js | `src/math/MathUtils.js` | ソース | clamp関数 |
| Vector3.js | `src/math/Vector3.js` | ソース | setFromSphericalで使用 |
| Cylindrical.js | `src/math/Cylindrical.js` | ソース | 類似の円筒座標クラス |
