# 帳票設計書 3-STLExporter

## 概要

本ドキュメントは、Three.jsライブラリにおけるSTLExporterの帳票設計書である。STLExporterは3DオブジェクトをSTL（Stereolithography）形式でエクスポートするためのモジュールであり、ASCIIおよびバイナリ形式の両方に対応する。

### 本帳票の処理概要

STLExporterは、Three.jsのMeshオブジェクトの表面ジオメトリをSTL形式に変換してエクスポートする機能を提供する。STL形式は三角形メッシュの集合として表面を記述し、各三角形は法線ベクトルと3つの頂点座標で定義される。

**業務上の目的・背景**：STL形式は3Dプリンティングの標準フォーマットとして広く採用されており、CAD/CAMシステムとの連携に不可欠である。表面ジオメトリのみを扱うシンプルな構造のため、製造業における試作品作成、医療分野でのインプラント設計、建築模型の出力など、物理的な造形物を生成するワークフローで必要となる。

**帳票の利用シーン**：3Dプリンタへのモデル出力、CNCマシニング用データ生成、ラピッドプロトタイピング、CADソフトウェアへのデータ移行、表面解析ツールへの入力時に利用される。

**主要な出力内容**：
1. ファイルヘッダー（ASCII: "solid exported"、バイナリ: 80バイト空ヘッダー）
2. 三角形数（バイナリのみ、4バイト整数）
3. 各三角形の法線ベクトル（3つのfloat値）
4. 各三角形の3頂点座標（各頂点3つのfloat値）
5. 属性バイトカウント（バイナリのみ、2バイト、常に0）
6. ファイルフッター（ASCII: "endsolid exported"）

**帳票の出力タイミング**：ユーザーがエクスポート操作を実行した時点でparseメソッドを呼び出すことで出力される。オプションによりASCII文字列またはArrayBufferとして即座に返却される。

**帳票の利用者**：3Dプリント技術者、製造エンジニア、プロダクトデザイナー、医療機器開発者、建築設計者が主な利用者である。

## 帳票種別

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

## 利用画面

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

## 出力形式

### 基本仕様

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

### STL固有設定

| 項目 | 内容 |
|-----|------|
| binary | true: バイナリ形式、false: ASCII形式（デフォルト: false） |

## 帳票レイアウト

### レイアウト概要

STLファイルは三角形のリストで構成され、各三角形は法線と3頂点を持つ。

```
┌─────────────────────────────────────┐
│       ヘッダー部（ASCIIまたは80バイト） │
├─────────────────────────────────────┤
│        三角形数（バイナリのみ）         │
├─────────────────────────────────────┤
│           三角形データ               │
│  ┌───────────────────────────────┐  │
│  │ 法線ベクトル (nx, ny, nz)      │  │
│  │ 頂点A (x, y, z)               │  │
│  │ 頂点B (x, y, z)               │  │
│  │ 頂点C (x, y, z)               │  │
│  │ 属性バイトカウント（バイナリ）   │  │
│  └───────────────────────────────┘  │
│           ... 繰り返し ...           │
├─────────────────────────────────────┤
│       フッター（ASCIIのみ）           │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | header (ASCII) | ファイル開始宣言 | 固定値 | "solid exported\n" |
| 1 | header (Binary) | 80バイトヘッダー | スキップ | 0x00 × 80 |
| 2 | triangles (Binary) | 三角形総数 | 計算値 | Uint32 LE |

### 明細部（三角形データ）

#### ASCII形式

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | facet normal | 法線ベクトル | 計算（外積） | facet normal {nx} {ny} {nz} | 可変 |
| 2 | outer loop | ループ開始 | 固定値 | outer loop | 固定 |
| 3 | vertex | 頂点A座標 | position属性 | vertex {x} {y} {z} | 可変 |
| 4 | vertex | 頂点B座標 | position属性 | vertex {x} {y} {z} | 可変 |
| 5 | vertex | 頂点C座標 | position属性 | vertex {x} {y} {z} | 可変 |
| 6 | endloop | ループ終了 | 固定値 | endloop | 固定 |
| 7 | endfacet | 面終了 | 固定値 | endfacet | 固定 |

#### バイナリ形式

| No | 項目名 | 説明 | データ取得元 | 表示形式 | サイズ |
|----|-------|------|-------------|---------|-------|
| 1 | normal | 法線ベクトル | 計算（外積） | Float32 LE × 3 | 12バイト |
| 2 | vertex1 | 頂点A座標 | position属性 | Float32 LE × 3 | 12バイト |
| 3 | vertex2 | 頂点B座標 | position属性 | Float32 LE × 3 | 12バイト |
| 4 | vertex3 | 頂点C座標 | position属性 | Float32 LE × 3 | 12バイト |
| 5 | attribute | 属性バイトカウント | 固定値 0 | Uint16 LE | 2バイト |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | footer (ASCII) | ファイル終了宣言 | 固定値 | "endsolid exported\n" |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| scene | エクスポート対象のシーンまたはオブジェクト | Yes |
| options.binary | バイナリ形式で出力するかどうか | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | オブジェクトtraverse順 | 深さ優先 |
| 2 | 三角形インデックス順 | 昇順 |

### 改ページ条件

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

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

### 参照テーブル一覧

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

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

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

#### BufferGeometry

| 参照項目（属性名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| position | vertex（頂点座標） | 必須 | fromBufferAttribute で取得 |
| index | 三角形インデックス | 存在時 | null時は連番 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| 三角形数 | index ? index.count / 3 : position.count / 3 | 切り捨て | 全オブジェクトの合計 |
| 法線ベクトル | cb.subVectors(vC, vB).cross(ab.subVectors(vA, vB)).normalize() | なし | 外積による面法線計算 |
| ワールド座標 | vertex.applyMatrix4(object.matrixWorld) | なし | ローカル→ワールド変換 |
| スキニング適用 | object.applyBoneTransform(index, vertex) | なし | SkinnedMesh時 |
| バッファ長 | triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4 | なし | バイナリ全体サイズ |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[parse呼び出し] --> B[オプション設定]
    B --> C[scene.traverse]
    C --> D{isMesh?}
    D -->|No| C
    D -->|Yes| E[ジオメトリ取得]
    E --> F[三角形数カウント]
    F --> G[objects配列に追加]
    G --> C
    C --> H{binary?}
    H -->|true| I[ArrayBuffer確保]
    H -->|false| J[文字列初期化]
    I --> K[ヘッダー出力]
    J --> L[solid exported出力]
    K --> M[三角形ループ]
    L --> M
    M --> N[writeFace呼び出し]
    N --> O[法線計算・出力]
    O --> P[頂点出力×3]
    P --> Q{全三角形完了?}
    Q -->|No| M
    Q -->|Yes| R{binary?}
    R -->|true| S[ArrayBuffer返却]
    R -->|false| T[endsolid出力]
    T --> U[文字列返却]
    S --> V[終了]
    U --> V
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| ジオメトリなし | position属性が未定義 | - | 該当オブジェクトをスキップ |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 三角形数: 〜数百万 |
| 目標出力時間 | 同期処理のため大規模データでは数秒かかる場合あり |
| 同時出力数上限 | 1（同期処理） |

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

- STL形式はジオメトリのみを含み、メタデータや識別情報は含まれない
- バイナリ形式のヘッダー80バイトは空で出力されるため、ファイル識別情報は含まれない
- 出力ファイルへのアクセス制御はアプリケーション側の責務

## 備考

- 色、テクスチャ、その他の属性情報は出力されない（表面ジオメトリのみ）
- スケール情報やインデックスは含まれず、単位は任意
- SkinnedMeshの場合、ボーントランスフォームが適用された状態で出力
- 複数オブジェクトは単一の連続した三角形リストとして出力

---

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

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

### 推奨読解順序

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

STL形式のシンプルな構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | STLExporter.js | `examples/jsm/exporters/STLExporter.js` | 1-17行目: インポートとJSDocコメントでSTL形式の特性を確認 |

**読解のコツ**: STLは「三角形の集合」という単純な概念を理解すれば、コード全体が理解しやすくなる。

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

parseメソッドの全体構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | STLExporter.js | `examples/jsm/exporters/STLExporter.js` | 18-34行目: STLExporterクラスとparseメソッドのシグネチャ |

**主要処理フロー**:
1. **29-33行**: オプションのデフォルト値設定（binary: false）
2. **39-60行**: scene.traverseでメッシュを収集し、三角形数をカウント
3. **62-77行**: 出力バッファの初期化（バイナリまたはASCII）
4. **86-124行**: オブジェクトループと三角形出力

#### Step 3: 三角形出力処理を理解する

writeFace、writeNormal、writeVertex関数を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | STLExporter.js | `examples/jsm/exporters/STLExporter.js` | 134-169行目: writeFace関数 |
| 3-2 | STLExporter.js | `examples/jsm/exporters/STLExporter.js` | 171-191行目: writeNormal関数 |
| 3-3 | STLExporter.js | `examples/jsm/exporters/STLExporter.js` | 193-208行目: writeVertex関数 |

**主要処理フロー**:
- **136-138行**: 頂点座標をBufferAttributeから取得
- **140-146行**: SkinnedMeshの場合、ボーントランスフォームを適用
- **148-150行**: ワールド座標に変換
- **152行**: 法線計算・出力
- **154-156行**: 3頂点出力
- **173-175行**: 法線計算（vC-vBとvA-vBの外積）
- **177行**: 法線の正規化

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

```
STLExporter.parse(scene, options)
    │
    ├─ オプション初期化
    │      └─ binary: false (デフォルト)
    │
    ├─ scene.traverse(object)
    │      └─ isMesh判定 → objects配列に追加、triangles累計
    │
    ├─ 出力バッファ初期化
    │      ├─ binary: ArrayBuffer確保
    │      └─ ASCII: 'solid exported\n'
    │
    └─ オブジェクトループ
           │
           └─ 三角形ループ
                  │
                  └─ writeFace(a, b, c, positionAttribute, object)
                         │
                         ├─ vA/vB/vC取得（fromBufferAttribute）
                         │
                         ├─ SkinnedMesh: applyBoneTransform
                         │
                         ├─ applyMatrix4（ワールド変換）
                         │
                         ├─ writeNormal(vA, vB, vC)
                         │      └─ 外積→正規化→出力
                         │
                         └─ writeVertex × 3
                                └─ Float32/テキスト出力
```

### データフロー図

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

Scene ──────────────▶ traverse() ──────────────▶ objects配列
      │                                               │
      ▼                                               ▼
   Mesh ────────────▶ geometry取得 ────────────▶ triangles数計算
      │                                               │
      ▼                                               ▼
BufferGeometry ─────▶ positionAttribute ───────▶ 頂点データ
      │                     │
      ▼                     ▼
   index ──────────▶ 三角形インデックス ────────▶ a, b, c
      │                     │
      ▼                     ▼
頂点座標 ──────────▶ writeFace() ───────────────▶ 三角形データ
      │                     │
      ├─ SkinnedMesh ─▶ applyBoneTransform()     ├─ normal (12B)
      │                     │                     ├─ vertex1 (12B)
      └─ 通常Mesh ────▶ applyMatrix4()           ├─ vertex2 (12B)
                            │                     ├─ vertex3 (12B)
                            ▼                     └─ attribute (2B)
                      外積・正規化
                            │
                            ▼
                    ASCII文字列 / ArrayBuffer
```

### 関連ファイル一覧

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