# 多 Work (沙盘) 场景 (Multi-Work / Sandbox)

- Summary: 在同一个 Five 实例中加载和管理多个 Work 数据（如沙盘场景），实现多楼盘/多户型的同屏展示与切换。
- Schema: `Work[]`, `LooseWorkWithExtrinsics`, `FiveLoadOptions`.
- Concepts: WorkCode, Works Collection, Coordinate Transform.
- Configuration: `five.load()` 参数配置。
- Examples: 加载多个 Work、动态添加 Work、Work 间切换。

## Schema

> Definition: FiveLoadOptions, LooseWorkWithExtrinsics

### 核心类型定义

    // 输入数据类型
    type FiveLoadInput =
      | Work[]
      | LooseWorkWithExtrinsics[]
      | string[]; // JSON Strings

    // 带位姿信息的 LooseWork (用于调整模型在场景中的位置)
    interface LooseWorkWithExtrinsics {
      work: LooseWork;      // Work 数据内容
      transform?: number[]; // 4x4 变换矩阵 (数组格式), 用于整体偏移/旋转该 Work
      workCode?: string;    // 强制指定 WorkCode (覆盖数据中的默认值)
    }

    // 加载选项
    interface FiveLoadOptions {
      mode?: "replace" | "add"; // 替换当前场景 vs 追加到当前场景
      // ... 其他常规选项
    }

## Concepts

### 1. Works Collection (数据集)

当 Five 加载多个 Work 时，它们被存储在 `five.works` 集合中。

- `five.works` 是一个增强的只读数组 (`ReadonlyArray<Work>`)。
- 提供了 `getWork(workCode)` 和 `getObserver(panoId)` 等辅助方法。

### 2. WorkCode (唯一标识)

在多 Work 场景中，`workCode` 是区分不同 Work 的关键。

- 必须唯一: 加载的每个 Work 必须有唯一的 `workCode`。如果数据中重复，建议在加载时通过 `ParseOptions` 重写。
- 状态索引: `five.state` 和 `five.setState` 中需要通过 `workCode` 来指定目标 Work。

### 3. Coordinate Alignment (坐标对齐)

不同 Work 的原始模型可能位于其各自的坐标系原点。为了在沙盘中正确排列它们（避免重叠），需要使用 `transform` 矩阵对每个 Work 进行空间变换（平移、旋转）。

## Configuration

`five.load(input, state, options)` 是入口方法。

参数 | 类型 | 说明
--- | --- | ---
`input` | `FiveLoadInput` | Work 数据数组。
`options.mode` | `"replace" | "add"` | 默认为 `"replace"` (清空当前场景)。设为 `"add"` 可保留现有场景并追加新 Work。

## Examples

### 1. 基础加载 (Basic Loading)

一次性加载两个 Work。

    const works = [workDataA, workDataB];

    five.load(works).then(() => {
      console.log("所有 Work 加载完成");
      console.log("当前 Works:", five.works);
    });

### 2. 沙盘排布 (Sandbox Layout)

使用 `transform` 将两个户型并排摆放。

    import * as THREE from "three";

    // 创建变换矩阵：向 X 轴正方向平移 20 米
    const matrixB = new THREE.Matrix4().makeTranslation(20, 0, 0);

    const input = [
      // Work A: 保持在原点
      { work: workDataA },
      // Work B: 偏移位置
      {
        work: workDataB,
        transform: matrixB.toArray()
      }
    ];

    five.load(input);

### 3. 动态添加 (Dynamic Add)

在不销毁当前场景的情况下，追加一个新的 Work。

    // 假设当前已经加载了 Work A
    // 追加 Work C
    five.load(workDataC, undefined, {
      mode: "add" // 关键参数
    }).then(() => {
      console.log("Work C 已加入场景");
    });

### 4. Work 间切换 (Switching Works)

跳转到指定 Work 的特定点位。

    const targetWorkCode = "work-id-b";

    // 方式一：指定点位索引
    five.setState({
      workCode: targetWorkCode,
      panoIndex: 0, // 目标 Work 的第 0 个点位
      mode: "Panorama"
    });

    // 方式二：查找特定 Work
    const targetWork = five.works.getWork(targetWorkCode);
    if (targetWork) {
      // 你的业务逻辑
    }

## Common Pitfalls

1. WorkCode 冲突: 如果加载的两个 Work 拥有相同的 `workCode`，SDK 行为可能不可预期。务必确保唯一性。
   - 解决: 在构造 `LooseWorkWithExtrinsics` 时传入 `workCode` 字段强制覆盖。
2. 资源隔离: 每个 Work 的纹理/模型请求是独立的。如果 Work A 和 Work B 引用了相同的 URL 资源，浏览器缓存会生效，但 SDK 内部逻辑仍视为独立资源。
3. 内存压力: 同时加载多个大型模型会显著增加显存占用。建议根据设备性能限制同时加载的 Work 数量。
4. 坐标系混淆: `transform` 仅影响 3D 模型的渲染位置。Work 内部的点位坐标 (`observer.position`) 也会自动应用此变换，但开发者在进行手动射线检测或计算时，需注意区分原始坐标和世界坐标。

## Related

- Five: Five 核心类说明。
- State: 状态管理说明。
- Work: Work 数据结构详解。

    tags: [多场景, 沙盘, 多户型, 拼接, 追加, 切换场景, 多楼盘, multi-work, sandbox, works, load, transform, workCode]