# Managers API

`u-space` 使用专用管理器来处理特定领域的逻辑，例如用于缓存和注册 3D 对象的 `ObjectManager`。

## ObjectManager

`ObjectManager` 提供了一个集中式字典/映射层，让你无需递归遍历 Three.js 场景图，就能通过字符串 ID 或字符串名称轻松检索复杂模型或特定网格。

默认实例可通过 `viewer.objectManager` 访问。

### 添加对象

向管理器添加对象时，必须提供唯一标识符。

```typescript
const myModel = new Model();
// ... 加载逻辑

// 用指定的唯一 ID 添加
viewer.objectManager.add('my-unique-car-id', myModel);

// 一个对象可以注册多个 ID
viewer.objectManager.add('player-vehicle', myModel);
```

### 检索对象

管理器提供快速访问对象的方法。

#### `getById(id: string)`

精确检索与指定 ID 匹配的一个对象（或 `undefined`）。

```typescript
const car = viewer.objectManager.getById('my-unique-car-id');
```

#### `getByName(name: string)`

由于 Three.js 对象可以共享同一个 `.name` 属性，此方法返回一个 `Set<Object3D>`，包含所有与指定名称匹配的已注册对象。

```typescript
// 假设 myModel.name = 'sedan'
const sedans = viewer.objectManager.getByName('sedan');

sedans.forEach((vehicle) => {
  vehicle.position.y += 10;
});
```

#### `getByType(type: string)`

返回一个 `Set<Object3D>`，包含所有 `object.type` 与指定类型匹配的已注册对象。

```typescript
const models = viewer.objectManager.getByType('Model');
```

#### `getObjectIds(object: Object3D)`

返回给定对象已注册的所有 ID 的 `Set<string>`。

```typescript
const ids = viewer.objectManager.getObjectIds(myModel);
```

### 移除对象

#### `remove(object: Object3D)`

从所有内部映射中移除该对象及其所有关联 ID。

```typescript
viewer.objectManager.remove(myModel);
```

#### `removeById(id: string)`

移除注册在指定 ID 下的对象。

```typescript
viewer.objectManager.removeById('my-unique-car-id');
```

#### `removeByName(name: string)`

移除所有具有指定 `.name` 的对象。

```typescript
viewer.objectManager.removeByName('sedan');
```

#### `removeByType(type: string)`

移除所有具有指定 `.type` 的对象。

```typescript
viewer.objectManager.removeByType('Model');
```

### 显隐控制

#### `show(id: string)` / `hide(id: string)`

控制对象的可见性。

```typescript
viewer.objectManager.hide('car-01');
viewer.objectManager.show('car-01');
```

#### `isolate(ids: string[])`

孤立显示：仅显示指定 ID 的对象，隐藏其余所有。

```typescript
viewer.objectManager.isolate(['car-01', 'car-02']);
```

#### `showAll()`

恢复显示所有已管理对象。

```typescript
viewer.objectManager.showAll();
```

### 材质操作

#### `setOpacity(id: string, opacity: number)`

设置指定对象所有材质的透明度。对于 `InstanceObject`（例如 `SceneInstanceObject`、`FacilityInstanceObject` 或 `FloorSemanticInstanceObject`），会调用 `setInstanceOpacity()` 写入该实例的透明度，而不会影响同一模型 path 或同一楼层内的其他实例。

```typescript
viewer.objectManager.setOpacity('building-01', 0.3);
viewer.objectManager.setOpacity('building-01', 1.0); // 恢复不透明
```

### 空间查询

#### `getBoundingBox(id?: string)`

获取指定对象的包围盒，不传 `id` 则返回所有已管理对象的包围盒。

```typescript
const box = viewer.objectManager.getBoundingBox('car-01');
const allBox = viewer.objectManager.getBoundingBox(); // 全部对象
```

### 遍历与过滤

#### `forEach(callback)`

遍历所有已管理对象。

```typescript
viewer.objectManager.forEach((object, ids) => {
  console.log(`对象: ${object.name}, IDs: ${Array.from(ids).join(', ')}`);
});
```

#### `filter(predicate)`

按条件过滤对象，返回匹配的数组。

```typescript
const cars = viewer.objectManager.filter((obj) => obj.name.startsWith('car'));
```

### 工具方法

- `getAll()`：返回所有已跟踪对象的 `Set<Object3D>`。
- `clear()`：从所有内部映射中移除所有对象。
- `size`：返回当前管理器跟踪的唯一对象总数。

---

## SceneManager

`SceneManager` 用于管理多个场景的创建、注册、切换和序列化。

```typescript
import { SceneManager } from 'u-space';

const sceneManager = new SceneManager();
```

### 方法

#### `create(key, options?)`

创建并注册一个新场景。

```typescript
const scene = sceneManager.create('indoor', { background: 0x333333 });
```

#### `add(key, scene)` / `get(key)` / `remove(key)`

手动注册、获取或移除场景。

```typescript
sceneManager.add('outdoor', existingScene);
const scene = sceneManager.get('outdoor');
sceneManager.remove('outdoor');
```

#### `serialize(key)`

将场景元数据序列化为 JSON 快照。

```typescript
const snapshot = sceneManager.serialize('indoor');
// { name, background, environmentRotation, children }
```

#### `keys()` / `size` / `clear()`

列出所有场景 key、获取场景数量或清空。

---

## LightManager

`LightManager` 提供灯光的便捷创建、预设和 Helper 可视化。

```typescript
import { LightManager } from 'u-space';

const lightManager = new LightManager(viewer.scene);
```

### 灯光创建

```typescript
lightManager.addAmbient('ambient', { color: 0xffffff, intensity: 0.5 });
lightManager.addDirectional('sun', { position: { x: 5, y: 10, z: 5 }, castShadow: true });
lightManager.addPoint('bulb', { position: { x: 0, y: 3, z: 0 }, intensity: 2 });
lightManager.addSpot('spot', { position: { x: 0, y: 10, z: 0 }, angle: Math.PI / 6 });
lightManager.addHemisphere('hemi', { skyColor: 0x87ceeb, groundColor: 0x362907 });
```

### 灯光预设

一键应用常见场景的灯光配置：

```typescript
lightManager.applyPreset('indoor');     // 室内：环境光 + 顶部点光源
lightManager.applyPreset('outdoor');    // 室外：半球光 + 方向光（阳光）
lightManager.applyPreset('studio');     // 摄影棚：三点布光
lightManager.applyPreset('warehouse');  // 仓库：多点光源照明
```

| 预设        | 配置                                    |
| :---------- | :-------------------------------------- |
| `indoor`    | 环境光 + 2 个点光源                     |
| `outdoor`   | 半球光 + 方向光（带阴影）               |
| `studio`    | 环境光 + 主光 + 补光 + 轮廓光           |
| `warehouse` | 环境光 + 4 个点光源（四角分布）         |

### Helper 可视化

```typescript
lightManager.showHelper('sun');              // 显示单个灯光 Helper（默认 size=5, color=0xff0000）
lightManager.showHelper('sun', 2, 0x00ff00); // 自定义尺寸和颜色
lightManager.showAllHelpers();               // 显示所有灯光 Helper
lightManager.hideHelper('sun');              // 隐藏单个
lightManager.hideAllHelpers();               // 隐藏所有
```

#### `showHelper(id, size?, color?)`

| 参数    | 类型                  | 默认值      | 说明              |
| :------ | :-------------------- | :---------- | :---------------- |
| `id`    | `string`              | —           | 灯光 ID。         |
| `size`  | `number`              | `5`         | Helper 尺寸。     |
| `color` | `ColorRepresentation` | `0xff0000`  | Helper 颜色。     |

### 管理

```typescript
lightManager.get('sun');     // 获取灯光
lightManager.remove('sun');  // 移除灯光
lightManager.removeAll();    // 移除所有
lightManager.dispose();      // 清理
```
