# 帳票設計書 4-PLYExporter

## 概要

本ドキュメントは、Three.jsライブラリにおけるPLYExporterの帳票設計書である。PLYExporterは3DオブジェクトをPLY（Polygon File Format / Stanford Triangle Format）形式でエクスポートするためのモジュールであり、頂点位置、色、法線、UV座標を保持し、ASCIIおよびバイナリ形式に対応する。

### 本帳票の処理概要

PLYExporterは、Three.jsのMeshおよびPointsオブジェクトをPLY形式に変換してエクスポートする機能を提供する。PLY形式は頂点ごとの属性（位置、法線、色、UV）と面インデックスを効率的に格納できるフォーマットである。

**業務上の目的・背景**：PLY形式はスタンフォード大学で開発された3Dスキャンデータの標準フォーマットであり、点群データや3Dスキャン結果の保存に広く使用されている。頂点カラーをネイティブにサポートするため、フォトグラメトリやLiDARスキャンデータの交換、科学研究用の3Dデータ保存、点群処理ソフトウェアとの連携に必要となる。

**帳票の利用シーン**：3Dスキャンデータの保存、点群データの出力、MeshLab等の点群処理ソフトへの入力、学術研究用データの保存、色付き3Dモデルの交換時に利用される。

**主要な出力内容**：
1. PLYヘッダー（format、element vertex、property定義、element face）
2. 頂点位置データ（x, y, z）
3. 法線ベクトル（nx, ny, nz）- オプション
4. UV座標（s, t）- オプション
5. 頂点カラー（red, green, blue）- オプション、0-255の整数値
6. 面インデックス（vertex_index）- Meshの場合

**帳票の出力タイミング**：ユーザーがエクスポート操作を実行した時点でparseメソッドを呼び出すことで出力される。コールバック関数を指定した場合は非同期で結果を受け取ることも可能。

**帳票の利用者**：3Dスキャン技術者、フォトグラメトリ専門家、点群処理エンジニア、科学研究者、コンピュータグラフィックス研究者が主な利用者である。

## 帳票種別

3Dモデルデータ出力（テキスト/バイナリファイル）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | Three.js アプリケーション | N/A（ライブラリ使用） | PLYExporter.parse() メソッド呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | PLY ASCII (.ply) / PLY Binary (.ply) |
| 用紙サイズ | N/A（バイナリ/テキストファイル） |
| 向き | N/A |
| ファイル名 | 任意（アプリケーション側で指定） |
| 出力方法 | 文字列（ASCII）またはArrayBuffer（バイナリ）として返却 |
| 文字コード | ASCII |

### PLY固有設定

| 項目 | 内容 |
|-----|------|
| binary | true: バイナリ形式、false: ASCII形式（デフォルト: false） |
| excludeAttributes | 除外する属性配列（'normal', 'uv', 'color', 'index'） |
| littleEndian | バイナリ形式のエンディアン（デフォルト: false = ビッグエンディアン） |

## 帳票レイアウト

### レイアウト概要

PLYファイルはヘッダー部と頂点データ、面データで構成される。

```
┌─────────────────────────────────────┐
│             ヘッダー部               │
│  ply                                │
│  format ascii/binary 1.0            │
│  element vertex N                   │
│  property float x/y/z               │
│  property float nx/ny/nz (optional) │
│  property float s/t (optional)      │
│  property uchar red/green/blue (opt)│
│  element face M (optional)          │
│  property list ... vertex_index     │
│  end_header                         │
├─────────────────────────────────────┤
│            頂点データ                │
│  x y z [nx ny nz] [s t] [r g b]     │
│            ... × N                  │
├─────────────────────────────────────┤
│          面データ（任意）             │
│  3 v1 v2 v3                         │
│            ... × M                  │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | ply | マジック識別子 | 固定値 | "ply\n" |
| 2 | format | フォーマット指定 | オプション | "format ascii/binary_little_endian/binary_big_endian 1.0\n" |
| 3 | element vertex | 頂点数 | 計算値 | "element vertex N\n" |
| 4 | property float x/y/z | 位置属性定義 | 固定 | 各行 |
| 5 | property float nx/ny/nz | 法線属性定義 | 存在時 | 各行 |
| 6 | property float s/t | UV属性定義 | 存在時 | 各行 |
| 7 | property uchar red/green/blue | カラー属性定義 | 存在時 | 各行 |
| 8 | element face | 面数 | 計算値 | "element face M\n" |
| 9 | property list | 面インデックス定義 | 固定 | "property list uchar int vertex_index\n" |
| 10 | end_header | ヘッダー終了 | 固定値 | "end_header\n" |

### 明細部（頂点データ）

| No | 項目名 | 説明 | データ取得元 | 表示形式 | サイズ |
|----|-------|------|-------------|---------|-------|
| 1 | x, y, z | 頂点位置 | position属性 | float32 | 12バイト |
| 2 | nx, ny, nz | 法線ベクトル | normal属性 | float32（存在時） | 12バイト |
| 3 | s, t | UV座標 | uv属性 | float32（存在時） | 8バイト |
| 4 | red, green, blue | 頂点カラー | color属性 | uint8（存在時） | 3バイト |

### フッター部（面データ）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | face | 面定義 | index属性または連番 | "3 {v1} {v2} {v3}" |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| object | エクスポート対象のObject3D | Yes |
| onDone | 完了コールバック関数 | No |
| options | エクスポートオプション | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | traverse順 | 深さ優先 |
| 2 | 頂点インデックス | 昇順 |
| 3 | 面インデックス | 昇順 |

### 改ページ条件

N/A（単一ファイル出力）

## データベース参照仕様

### 参照テーブル一覧

本エクスポーターはデータベースを使用せず、Three.jsオブジェクトのメモリ上のデータを直接参照する。

| データソース | 用途 | 参照方法 |
|-------------|------|---------|
| Object3D | オブジェクト走査 | traverse メソッド |
| Mesh | メッシュデータ | isMesh プロパティで判定 |
| Points | 点群データ | isPoints プロパティで判定 |
| BufferGeometry | ジオメトリデータ | geometry プロパティ |

### テーブル別参照項目詳細

#### BufferGeometry

| 参照項目（属性名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| position | x, y, z（頂点位置） | 必須 | ワールド座標に変換 |
| normal | nx, ny, nz（法線） | 存在時かつ未除外 | ワールド空間に変換 |
| uv | s, t（テクスチャ座標） | 存在時かつ未除外 | Meshのみ |
| color | red, green, blue | 存在時かつ未除外 | sRGB変換、0-255 |
| index | vertex_index | 存在時かつ未除外 | Meshのみ |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| 頂点数 | vertices.count の総和 | なし | 全Mesh/Pointsの合計 |
| 面数 | index ? index.count / 3 : vertices.count / 3 | 切り捨て | Meshのみ |
| ワールド頂点位置 | vertex.applyMatrix4(mesh.matrixWorld) | なし | 座標変換 |
| ワールド法線 | normal.applyMatrix3(normalMatrixWorld).normalize() | なし | 法線行列変換 |
| 頂点カラー(sRGB) | ColorManagement.workingToColorSpace(color, SRGBColorSpace) | なし | 作業色空間→sRGB |
| カラー値(0-255) | Math.floor(color.r * 255) | 切り捨て | 浮動小数点→整数 |
| バイナリ頂点サイズ | 4*3 + (法線?4*3:0) + (色?3:0) + (UV?4*2:0) | なし | 1頂点あたりのバイト数 |
| バイナリ面サイズ | indexByteCount * 3 + 1 | なし | 1面あたり（4*3+1=13バイト） |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[parse呼び出し] --> B[オプション設定]
    B --> C[属性フラグ計算]
    C --> D[object.traverse]
    D --> E{Mesh/Points?}
    E -->|Yes| F[頂点数・面数カウント]
    E -->|No| D
    F --> G[属性有無フラグ更新]
    G --> D
    D --> H[ヘッダー生成]
    H --> I{binary?}
    I -->|true| J[バイナリバッファ確保]
    I -->|false| K[ASCII文字列初期化]
    J --> L[traverseMeshes]
    K --> L
    L --> M[頂点データ出力]
    M --> N{includeIndices?}
    N -->|Yes| O[面データ出力]
    N -->|No| P[完了]
    O --> P
    P --> Q{onDone指定?}
    Q -->|Yes| R[requestAnimationFrame]
    Q -->|No| S[結果返却]
    R --> T[コールバック呼び出し]
    S --> U[終了]
    T --> U
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 頂点数不正 | 三角形分割不可能な頂点数 | "Failed to generate a valid PLY file with triangle indices because the number of indices is not divisible by 3" | console.error出力、null返却 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 頂点数: 〜数百万 |
| 目標出力時間 | 同期処理メイン、大規模データでは数秒かかる場合あり |
| 同時出力数上限 | 1（基本同期処理） |

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

- PLY形式はジオメトリと頂点属性のみを含み、実行可能コードは含まれない
- 出力ファイルへのアクセス制御はアプリケーション側の責務
- 頂点カラーのsRGB変換により、意図しない色空間の問題を防止

## 備考

- テクスチャ画像はエクスポートされない（頂点カラーのみ）
- Pointsオブジェクトの場合、面データは出力されない（点群のみ）
- excludeAttributesで特定の属性を除外可能
- onDoneコールバックはrequestAnimationFrameで非同期呼び出し

---

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

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

### 推奨読解順序

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

PLY形式のヘッダー構造と属性定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PLYExporter.js | `examples/jsm/exporters/PLYExporter.js` | 9-23行目: JSDocとPLY形式の説明 |

**読解のコツ**: PLYはヘッダーで属性を自由に定義できる柔軟なフォーマット。ヘッダー生成部分を先に理解する。

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

parseメソッドの全体構造とオプション処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | PLYExporter.js | `examples/jsm/exporters/PLYExporter.js` | 36-69行目: parseメソッドとオプション設定 |

**主要処理フロー**:
1. **36行**: parseメソッドのシグネチャ（object, onDone, options）
2. **63-67行**: デフォルトオプション（binary: false, excludeAttributes: [], littleEndian: false）
3. **71-75行**: include系フラグの初期化

#### Step 3: 属性収集と検証を理解する

traverseによる属性存在チェックとカウント処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PLYExporter.js | `examples/jsm/exporters/PLYExporter.js` | 82-129行目: traverse処理と属性フラグ |

**主要処理フロー**:
- **84-109行**: Mesh処理（頂点数、面数、属性フラグ）
- **110-127行**: Points処理（頂点数、属性フラグ、インデックスなし）
- **132-135行**: excludeAttributesによるフラグ上書き
- **138-152行**: 三角形数検証とエラー処理

#### Step 4: ヘッダー生成を理解する

PLYヘッダーの動的構築を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | PLYExporter.js | `examples/jsm/exporters/PLYExporter.js` | 156-204行目: ヘッダー生成 |

**主要処理フロー**:
- **156-164行**: format行とelement vertex行
- **166-173行**: 法線property（存在時）
- **176-182行**: UV property（存在時）
- **185-191行**: カラーproperty（存在時）
- **195-201行**: 面element（存在時）

#### Step 5: データ出力を理解する

バイナリ/ASCII両形式のデータ出力処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | PLYExporter.js | `examples/jsm/exporters/PLYExporter.js` | 212-402行目: バイナリ出力 |
| 5-2 | PLYExporter.js | `examples/jsm/exporters/PLYExporter.js` | 404-532行目: ASCII出力 |

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

```
PLYExporter.parse(object, onDone, options)
    │
    ├─ オプション初期化
    │      ├─ binary: false
    │      ├─ excludeAttributes: []
    │      └─ littleEndian: false
    │
    ├─ object.traverse() [第1パス: カウント]
    │      ├─ isMesh判定 → 頂点数、面数、属性フラグ
    │      └─ isPoints判定 → 頂点数、属性フラグ
    │
    ├─ excludeAttributes適用
    │
    ├─ 三角形数検証
    │      └─ 不正時: console.error → return null
    │
    ├─ ヘッダー生成
    │      ├─ format行
    │      ├─ element vertex行
    │      ├─ property行（位置/法線/UV/カラー）
    │      ├─ element face行
    │      └─ end_header行
    │
    ├─ traverseMeshes() [第2パス: データ出力]
    │      │
    │      ├─ バイナリモード
    │      │      ├─ Float32: 位置、法線、UV
    │      │      └─ Uint8: カラー
    │      │
    │      └─ ASCIIモード
    │             └─ 文字列連結
    │
    └─ onDone呼び出し（requestAnimationFrame）
```

### データフロー図

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

Object3D ───────────▶ traverse() [カウント] ────▶ vertexCount, faceCount
      │                     │
      ▼                     ▼
 Mesh/Points ──────▶ 属性存在チェック ─────────▶ include*フラグ
      │                     │
      ▼                     ▼
BufferGeometry ────▶ excludeAttributes適用 ───▶ 最終フラグ
      │                     │
      ▼                     ▼
position ──────────▶ ヘッダー生成 ─────────────▶ "ply\nformat...\n"
normal                      │
uv                          ▼
color ─────────────▶ traverseMeshes() ─────────▶ 頂点データ
index                       │
      │                     │
      ├─ applyMatrix4 ──────┤
      ├─ applyMatrix3 ──────┤
      └─ sRGB変換 ──────────┤
                            ▼
                      面データ（インデックス）
                            │
                            ▼
                    ASCII文字列 / ArrayBuffer
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PLYExporter.js | `examples/jsm/exporters/PLYExporter.js` | ソース | メインエクスポーター実装 |
| three.module.js | `build/three.module.js` | ソース | Three.jsコアライブラリ（Matrix3, Vector3, Color等） |
