# 瓦片模式

大型图纸的瓦片方式打开和编辑指南。

## 概念

### 瓦片模式 vs 矢量模式

| 特性 | 矢量模式 | 瓦片模式 |
|------|---------|---------|
| 数据加载 | 完整加载到前端 | 按需加载可视区域 |
| 适用场景 | 中小型图纸（<50MB）| 大型图纸（数GB）|
| 初始状态 | 可直接编辑 | 只读，需选择编辑区域 |
| 渲染方式 | 实时矢量渲染 | WMS 瓦片图层 |
| 内存占用 | 与图纸大小相关 | 固定较低 |

### 编辑模式

| 模式 | 命令 | 说明 |
|------|------|------|
| 区域编辑 | `TILEEDITAREA` | 选择矩形区域内的实体 |
| 图层编辑 | `TILEEDITLAYER` | 选择指定图层的所有实体 |

两种模式是「或」的关系，可以同时使用。

---

## 瓦片打开图纸

### 命令方式

```javascript
// 打开图纸浏览器，选择「瓦片打开」
await Engine.editor.executerWithOp('OPENFROMSERVER');
```

### API 方式

```javascript
const { 
    DrawingManagerService, Engine, 
    GeoBounds, Point2D 
} = vjcad;

const drawingManager = new DrawingManagerService();
const service = drawingManager.getService();

const mapid = 'drawing-123';
const version = 'v1';

// 1. 获取图纸元数据
const metadata = await service.metadata(mapid, version);
const bounds = GeoBounds.fromString(metadata.bounds);

// 2. 创建空白文档
Engine.view.newDocument();
Engine.currentDoc.name = `${mapid}_${version}_tile`;

// 3. 配置瓦片图层
const pcanvas = Engine.pcanvas;
const tileConfig = {
    mapid: mapid,
    version: version,
    layers: metadata.styles?.[0]?.layername,
    tileSize: 256,
    maxZoom: 20,
    minZoom: 0,
    transparent: true,
    preloadBuffer: 1,     // 预加载缓冲区
    maxConcurrent: 6,     // 最大并发请求数
    cacheSize: 200        // 缓存大小
};

// 4. 启用 WMS 瓦片图层
pcanvas.enableWmsTileLayer(service, tileConfig);

// 5. 设置视口
const centerX = (bounds.min.x + bounds.max.x) / 2;
const centerY = (bounds.min.y + bounds.max.y) / 2;
const width = bounds.max.x - bounds.min.x;
const height = bounds.max.y - bounds.min.y;

const zoom = Math.min(
    pcanvas.div.clientWidth / width,
    pcanvas.div.clientHeight / height
) * 0.9;

Engine.currentSpace.setZoom(zoom);
Engine.currentSpace.lookPt = new Point2D(centerX * zoom, centerY * zoom);
pcanvas.setCenter(new Point2D(centerX, centerY), true);

// 6. 标记只读（与 OPENFROMSERVER 瓦片打开一致；isReadOnly 只是状态标记，本身不阻止编辑）
Engine.currentDoc.isReadOnly = true;

// 7. 保存来源信息
Engine.currentDoc.serverSource = {
    type: 'imports',
    mapid: mapid,
    version: version,
    branchName: 'main',
    lastPatchId: 'base'
};
```

---

## 区域编辑

选择矩形区域内的实体进行编辑。

### 命令方式

```javascript
// 在瓦片模式下执行
await Engine.editor.executerWithOp('TILEEDITAREA');
// 操作：指定第一个角点 → 指定对角点 → 加载区域数据
```

### API 方式

```javascript
const { TileEditAreaCommand, DrawingManagerService, Engine } = vjcad;

const drawingManager = new DrawingManagerService();
const pcanvas = Engine.pcanvas;

// 定义编辑区域
const editArea = {
    minX: 1000,
    minY: 1000,
    maxX: 2000,
    maxY: 2000
};

// 加载编辑区域
const loadResult = await TileEditAreaCommand.loadEditArea(
    editArea,
    Engine.currentDoc.serverSource,
    pcanvas,
    Engine.currentDoc,
    drawingManager
);

if (loadResult.success) {
    Engine.currentDoc.isReadOnly = false;
    console.log(`加载完成: ${loadResult.loadedCount} 个可编辑实体`);
}
```

### 区域编辑特点

- 支持多次选择不同区域（累积模式）
- 添加遮盖层覆盖瓦片内容
- 实体和块定义自动合并去重
- 保存时只保存编辑区域的变更

---

## 图层编辑

选择指定图层的所有实体进行编辑。

### 命令方式

```javascript
// 在瓦片模式下执行
await Engine.editor.executerWithOp('TILEEDITLAYER');
// 操作：在对话框中选择图层 → 加载图层数据
```

### API 方式

```javascript
const { TileEditLayerCommand, DrawingManagerService, Engine } = vjcad;

const drawingManager = new DrawingManagerService();
const pcanvas = Engine.pcanvas;

const mapid = Engine.currentDoc.serverSource.mapid;
const version = Engine.currentDoc.serverSource.version;

// 1. 获取图层列表
const layerInfos = await TileEditLayerCommand.getLayerListFromService(mapid, version);
const layerNames = layerInfos.map(l => l.name);
console.log('可用图层:', layerNames);

// 2. 选择要编辑的图层
const selectedLayers = ['0', '标注层'];

// 3. 加载编辑图层
const loadResult = await TileEditLayerCommand.loadEditLayers(
    selectedLayers,
    Engine.currentDoc.serverSource,
    pcanvas,
    Engine.currentDoc,
    drawingManager
);

if (loadResult.success) {
    Engine.currentDoc.isReadOnly = false;
    console.log(`加载完成: ${loadResult.layersCount} 个图层，共 ${loadResult.totalLoadedCount} 个实体`);
}
```

### 图层编辑特点

- 支持多选图层
- 图层范围不固定，不添加遮盖层
- 实体和块定义自动合并去重

---

## 透明度设置

### 瓦片图层透明度

```javascript
// 命令方式
await Engine.editor.executerWithOp('TILEALPHA');

// API 方式
const pcanvas = Engine.pcanvas;

// 获取当前透明度
const currentAlpha = pcanvas.getWmsTileAlpha();
console.log(`当前透明度: ${Math.round(currentAlpha * 100)}%`);

// 设置透明度（0-1）
pcanvas.setWmsTileAlpha(0.5);  // 50%
pcanvas.redraw();
```

| 值 | 效果 |
|----|------|
| 0 | 完全透明 |
| 0.5 | 半透明 |
| 1 | 完全不透明（默认）|

### 遮盖层透明度

```javascript
// 命令方式
await Engine.editor.executerWithOp('TILEMASKALPHA');

// API 方式
const pcanvas = Engine.pcanvas;

// 设置遮盖层透明度
pcanvas.tileMaskContainer.alpha = 0.8;   // PixiJS Container 透明度
pcanvas.redraw();
```

使用场景：
- 对比编辑区域与底图的差异
- 降低底图干扰，专注编辑区域
- 检查编辑内容与原图的对齐

---

## 相关命令

| 命令 | 说明 |
|------|------|
| `OPENFROMSERVER` | 打开图纸（可选瓦片模式）|
| `TILEEDITAREA` | 选择矩形区域编辑 |
| `TILEEDITLAYER` | 选择图层编辑 |
| `TILEALPHA` | 设置瓦片图层透明度 |
| `TILEMASKALPHA` | 设置遮盖层透明度 |
| `SAVESERVER` | 保存（只保存编辑区域的变更）|

---

## 瓦片配置参数

| 参数 | 说明 | 默认值 |
|------|------|--------|
| `mapid` | 图纸 ID | - |
| `version` | 版本号 | - |
| `layers` | 图层名称 | 全部图层 |
| `tileSize` | 瓦片大小（像素）| 256 |
| `maxZoom` | 最大缩放级别 | 20 |
| `minZoom` | 最小缩放级别 | 0 |
| `transparent` | 是否透明 | true |
| `preloadBuffer` | 预加载缓冲区 | 1 |
| `maxConcurrent` | 最大并发请求数 | 6 |
| `cacheSize` | 缓存大小 | 200 |

---

## 完整示例

```javascript
const { 
    MainView, initCadContainer, Engine,
    DrawingManagerService, TileEditAreaCommand, TileEditLayerCommand,
    GeoBounds, Point2D, LineEnt, message
} = vjcad;

// 初始化
const cadView = new MainView({
    appname: "唯杰CAD",
    version: "v1.0.0",
    serviceUrl: env.serviceUrl,
    accessToken: env.accessToken,
    sidebarStyle: "none"
});

initCadContainer("map", cadView);
await cadView.onLoad();

const drawingManager = new DrawingManagerService();
const service = drawingManager.getService();

const mapid = 'large-drawing';
const version = 'v1';

// === 1. 瓦片打开图纸 ===
const metadata = await service.metadata(mapid, version);
const bounds = GeoBounds.fromString(metadata.bounds);

Engine.view.newDocument();
Engine.currentDoc.name = `${mapid}_tile`;

const pcanvas = Engine.pcanvas;
pcanvas.enableWmsTileLayer(service, {
    mapid, version,
    tileSize: 256,
    transparent: true
});

const centerX = (bounds.min.x + bounds.max.x) / 2;
const centerY = (bounds.min.y + bounds.max.y) / 2;
pcanvas.setCenter(new Point2D(centerX, centerY), true);

Engine.currentDoc.isReadOnly = true;
Engine.currentDoc.serverSource = {
    type: 'imports', mapid, version,
    branchName: 'main', lastPatchId: 'base'
};

message.info('瓦片模式已启用');

// === 2. 加载编辑区域 ===
const width = bounds.max.x - bounds.min.x;
const height = bounds.max.y - bounds.min.y;

const editArea = {
    minX: centerX - width * 0.1,
    minY: centerY - height * 0.1,
    maxX: centerX + width * 0.1,
    maxY: centerY + height * 0.1
};

const loadResult = await TileEditAreaCommand.loadEditArea(
    editArea,
    Engine.currentDoc.serverSource,
    pcanvas,
    Engine.currentDoc,
    drawingManager
);

if (loadResult.success) {
    Engine.currentDoc.isReadOnly = false;
    message.info(`已加载 ${loadResult.loadedCount} 个实体`);
}

// === 3. 编辑图纸 ===
const line = new LineEnt([centerX - 50, centerY], [centerX + 50, centerY]);
line.setDefaults();
line.color = 1;
Engine.addEntities(line);

// === 4. 设置透明度便于对比 ===
pcanvas.setWmsTileAlpha(0.5);
pcanvas.redraw();

// === 5. 保存（只保存编辑区域的变更）===
// await Engine.editor.executerWithOp('SAVESERVER');
```
