# 插入符号

> 示例：
> - `vjcad/example/insert/symbol/03insertbasic.js` — 基础（指定参数插入）
> - `vjcad/example/insert/symbol/04insertinteractive.js` — 交互式（getPoint）
> - `vjcad/example/insert/symbol/07insertmodify.js` — 修改属性后插入（颜色 / 固定缩放）

## 1. 三种插入路径

| 场景 | API |
|---|---|
| 已知插入点 / 缩放 / 旋转 | `mergeSymbolToDocument(symbolDoc, insertPoint, basePoint, scale, rotation, clearSourceInfo)` |
| 让用户依次拾取插入点 / 缩放 / 旋转 | `insertSymbolInteractive(vcadData, basePoint, options)` |
| 修改实体属性后再插入（固定/不固定参数） | `parseSymbolVcadData(vcadData)` → 改实体 → `new SymbolInteractiveInserter(...).execute()` |

## 2. 基础：API 方式插入到固定位置

```js
const localService = getLocalStorageService();
const cats = await localService.getLocalSymbolCategories();
const symbolMeta = (await localService.getLocalSymbolList(cats[0].id))[0];
const detail     = await localService.getLocalSymbol(symbolMeta.id);

const symbolDoc = await parseSymbolVcadData(detail.vcadData);   // detail = { record, vcadData }

const insertPoint = new Point2D(50, 50);
Engine.startUndoMark('插入符号');      // mergeSymbolToDocument 本身不记 undo
const addedEntities = mergeSymbolToDocument(
    symbolDoc,
    insertPoint,
    symbolMeta.basePoint,    // [x, y]
    1.5,                     // 缩放
    45,                      // 旋转角度（度，不是弧度）
    false                    // clearSourceInfo: 是否清空来源图信息
);
if (addedEntities.length) Engine.undoManager.added_undoMark(addedEntities);
Engine.endUndoMark();
Engine.regen();
```

服务端符号则需要先解压：

```js
const fullSymbol = await Engine.service.getSymbol(metaId);
const vcadData   = await decompressSymbolData(fullSymbol.data);
const symbolDoc  = await parseSymbolVcadData(vcadData);
mergeSymbolToDocument(symbolDoc, new Point2D(150, 50), fullSymbol.basePoint, 1, 0, false);
```

> 完整代码：`vjcad/example/insert/symbol/03insertbasic.js`

## 3. 交互式插入（getPoint 拾取）

```js
class InsertSymbolCommand {
    async main() {
        // ...拿到 vcadData / basePoint...
        const entities = await insertSymbolInteractive(vcadData, basePoint, {
            allowScale:    true,    // 提示输入缩放
            allowRotation: true,    // 提示输入旋转
            clearSourceInfo: false,
        });
        if (entities) {
            message.info("已插入 " + entities.length + " 个实体");
            Engine.zoomExtents();
        }
    }
}
CommandRegistry.regist(new CommandDefinition('MYINSERTSYMBOL', '插入符号', InsertSymbolCommand, new CommandOptions()));
await Engine.editor.executerWithOp('MYINSERTSYMBOL');
```

`insertSymbolInteractive` 内部依次提示：
1. 指定插入点
2. （`allowScale` 时）输入缩放
3. （`allowRotation` 时）输入旋转角度

> 完整代码：`vjcad/example/insert/symbol/04insertinteractive.js`

## 4. 修改属性后插入

如果要在插入前批量调整符号实体（例如统一改颜色），用 `parseSymbolVcadData` 取出 `*Model` 块，改 items，再用 `SymbolInteractiveInserter`：

```js
const symbolDoc = await parseSymbolVcadData(vcadData);
const modelBlock = symbolDoc.blocks.itemByName("*Model");
for (const e of modelBlock.items) e.color = 1;     // 改成红色

const inserter = new SymbolInteractiveInserter(
    symbolDoc,
    symbolMeta.basePoint,
    /* allowScale */    false,
    /* allowRotation */ false,
    /* clearSourceInfo */ false,
    /* initialScale */  2,
    /* initialRotation */ 30
);
const entities = await inserter.execute();
```

参数 `allowScale=false` + `initialScale=2` 表示 **强制 2 倍**，用户无法修改。同理 `allowRotation=false` + `initialRotation=30` 表示 **强制旋转 30°**。

> 完整代码：`vjcad/example/insert/symbol/07insertmodify.js`

## 5. mergeSymbolToDocument 参数

| 位置 | 参数 | 类型 | 说明 |
|---|---|---|---|
| 1 | `symbolDoc` | `CadDocument` | `parseSymbolVcadData` 的产物 |
| 2 | `insertPoint` | `Point2D` | 当前文档中的插入点 |
| 3 | `basePoint` | `[x, y]` | 符号的基点（来自 symbolMeta） |
| 4 | `scale` | number | 缩放倍数（1 = 原大小） |
| 5 | `rotation` | number | **角度（度）**，0 = 不旋转 |
| 6 | `clearSourceInfo` | boolean | 是否清空实体溯源信息（来源 `objectId`，默认 false） |

返回值：插入后的实体数组（已入当前空间——内部走 `Engine.pcanvas.addEntity` 逐个克隆插入，不是 `Engine.addEntities`，因此**不记录 undo**；内置 SYMBOL 命令是外包 `startUndoMark` + `added_undoMark(entities)` + `endUndoMark` + `regen` 实现可撤销的）。

**变换顺序**：对每个克隆实体依次 `move(basePoint→原点)` → `scale(原点, scale)` → `rotate(原点, rotation弧度)` → `move(原点→insertPoint)`。即"先归基点、再缩放旋转、再落插入点"。例：基点 (10,10) 处圆心 (15,10) r=5 的圆，`mergeSymbolToDocument(doc, Point2D(100,100), [10,10], 2, 90)` 后落在 **(100,110) r=10**。

## 红旗

- 旋转角度全是 **度**，不是弧度
- `mergeSymbolToDocument` 内部已把实体加进当前空间，**不要再 `addEntities` 一次**
- 服务端符号必须 `decompressSymbolData` 才能给 `parseSymbolVcadData`
- `parseSymbolVcadData` 是 async
- 插入大量符号（几百个）时：`suspendEvents()` / `resumeEvents()` 只静默（默认直接丢弃）事件，**不会合并重绘**；批量请包在一个 undo 组里（`startUndoMark` + `added_undoMark` + `endUndoMark`），最后 `Engine.regen()` 一次

## 参考（官方文档 MCP）

- 示例：
- `vjcad/example/insert/symbol/03insertbasic.js` — 基础（指定参数插入）
- `vjcad/example/insert/symbol/04insertinteractive.js` — 交互式（getPoint）
- `vjcad/example/insert/symbol/07insertmodify.js` — 修改属性后插入（颜色 / 固定缩放）
