# VjCAD SDK 绘图指南

## 标准工作流程

所有绘图任务都遵循以下模式：

```javascript
const { Engine, LineEnt, CircleEnt, PolylineEnt, TextEnt, MTextEnt, ArcEnt, SplineEnt, Point2D } = vjcad;

Engine.undoManager.start_undoMark();
try {
    const entities = [];

    // 1. 创建实体 —— 必须先调用 setDefaults()，再设置属性
    const line = new LineEnt([0, 0], [100, 50]);
    line.setDefaults();
    line.color = 1;
    entities.push(line);

    // 2. 批量添加并刷新视图
    Engine.addEntities(entities);
    Engine.zoomExtents();
} finally {
    Engine.undoManager.end_undoMark();
}
```

---

## 创建实体

| 实体 | 构造方式 | 关键属性 |
|------|---------|---------|
| `LineEnt` | `new LineEnt([x1,y1], [x2,y2])` | `startPoint`, `endPoint`, `Length` |
| `CircleEnt` | `new CircleEnt([cx,cy], radius)` | `center`, `radius`, `area` |
| `ArcEnt` | `new ArcEnt([cx,cy], r, 起始角, 终止角)` | 角度单位**弧度**，逆时针为正；也可用 `initBy3Pt(p1,p2,p3)` 三点定弧 |
| `PolylineEnt` | `new PolylineEnt()` 然后 `setPoints(pts)` | `isClosed`；支持 `addPoint([x,y], bulge?)` 链式调用 |
| `TextEnt` | `new TextEnt()` | `insertionPoint`, `text`, `height`, `textAlignment`（1-9） |
| `MTextEnt` | `new MTextEnt()` | `insertionPoint`, `text`, `height`, `maxWidth`；用 `\n` 换行 |
| `SplineEnt` | `new SplineEnt()` 然后 `setFitPoints(pts)` | `isClosed`（只读，首尾点重合即闭合；赋值会抛 TypeError） |

### 综合示例

```javascript
const { Engine, LineEnt, CircleEnt, ArcEnt, PolylineEnt, TextEnt, MTextEnt, SplineEnt, Point2D } = vjcad;

Engine.undoManager.start_undoMark();
try {
    const entities = [];

    // 直线
    const line = new LineEnt([0, 0], [100, 0]);
    line.setDefaults(); line.color = 1;
    entities.push(line);

    // 圆
    const circle = new CircleEnt([50, 50], 30);
    circle.setDefaults();
    entities.push(circle);

    // 圆弧 —— 从 0° 到 90°，逆时针绘制
    const arc = new ArcEnt([50, 50], 30, 0, Math.PI / 2);
    arc.setDefaults();
    entities.push(arc);

    // 闭合多段线（矩形）
    const rect = new PolylineEnt();
    rect.setPoints([[0, 0], [100, 0], [100, 60], [0, 60]]);
    rect.isClosed = true;
    rect.setDefaults();
    entities.push(rect);

    // 带圆弧段的多段线 —— 凸度 bulge = tan(圆心角 / 4)
    const pline = new PolylineEnt();
    pline.setPoints([
        [0, -20],
        [[50, -20], 0.4142],   // 90° 圆角
        [100, -20]
    ]);
    pline.setDefaults();
    entities.push(pline);

    // 单行文字
    const text = new TextEnt();
    text.insertionPoint = [0, 80];
    text.text = "Hello VjCAD";
    text.height = 10;
    text.textAlignment = 5; // 居中
    text.setDefaults();
    entities.push(text);

    // 多行文字
    const mtext = new MTextEnt();
    mtext.insertionPoint = [0, 100];
    mtext.text = "第一行\n第二行";
    mtext.height = 8;
    mtext.maxWidth = 80;
    mtext.setDefaults();
    entities.push(mtext);

    // 样条曲线
    const spline = new SplineEnt();
    spline.setFitPoints([[0, -40], [30, -10], [60, -30], [100, -15]]);
    spline.setDefaults();
    entities.push(spline);

    Engine.addEntities(entities);
    Engine.zoomExtents();
} finally {
    Engine.undoManager.end_undoMark();
}
```

---

## 关键规则

1. **先调用 `setDefaults()`** —— 必须在设置 `color`、`layer` 等属性之前调用，否则属性可能被覆盖。

2. **撤销包裹** —— 一次操作的多条撤销记录放在 `start_undoMark()` / `end_undoMark()` 之间才会合并成一步（不包裹也能撤销，只是逐条退）。使用 `try/finally` 确保 `end_undoMark()` 一定执行。`Engine.addEntities / eraseEntities` 已自带撤销记录，勿再手动 `added_undoMark / erased_undoMark`。

3. **角度单位是弧度** —— `Math.PI / 2` = 90度。圆弧方向为逆时针（CCW）。0 = 正右方（3点钟方向），`Math.PI / 2` = 正上方。

4. **`Point2D` 与 `[x,y]` 的区别** —— 基础实体（Line/Circle/Arc/Pline/Text…）的 `move()`、`rotate()`、`scale()`、`mirror()` 点参数是 `PointInput`（`Point2D` 或 `[x,y]` 数组均可）；**标注族与 `MLeaderEnt` 的这四个方法只收 `Point2D`**，标注构造、`initBy3Pt` 等也只收 `Point2D`（传数组会 NaN）。

5. **多段线凸度（bulge）** —— `bulge = tan(圆心角 / 4)`。常用值：`0.4142` = 90° 圆角，`1.0` = 半圆（180°），负值 = 顺时针。格式：`[[x, y], bulge]`。

6. **批量添加** —— 将实体收集到数组中，一次调用 `Engine.addEntities(entities)`，不要逐个添加。

7. **变换后刷新** —— 执行 `move/rotate/scale/mirror` 后需调用 `Engine.regen()`。添加实体后 `zoomExtents()` 即可。

---

## 颜色

| 代码 | 颜色 | 代码 | 颜色 |
|------|------|------|------|
| 1 | 红色 | 5 | 蓝色 |
| 2 | 黄色 | 6 | 洋红 |
| 3 | 绿色 | 7 | 白色 |
| 4 | 青色 | 8 | 灰色 |
| 256 | 随层 | 0 | 随块 |

RGB 真彩色：`entity.color = ColorConverter.createRgbColorIndexFromHexStr("#FF8000");`（从 vjcad 导入 `ColorConverter`）。

---

## 修改实体

```javascript
const { Point2D, Engine } = vjcad;

entity.move([0, 0], [50, 30]);                              // 移动（PointInput：数组或 Point2D 均可）
entity.rotate(new Point2D(0, 0), Math.PI / 4);              // 旋转 45°
entity.scale(new Point2D(0, 0), 2.0);                       // 缩放 2 倍
entity.mirror(new Point2D(100, 0), new Point2D(100, 100));   // 沿 x=100 镜像

const copy = entity.clone();                                 // 深拷贝
copy.move([0, 0], [200, 0]);
Engine.addEntities(copy);

Engine.eraseEntities(entity);                                // 删除单个
Engine.eraseEntities([ent1, ent2]);                          // 批量删除

Engine.regen();                                              // 变换后刷新
```

修改已有实体时，先调用 `Engine.markModified(entity)` 记录修改前状态，修改完毕后调用 `entity.setModified()`，并用 `start_undoMark()` / `end_undoMark()` 包裹。

---

## 查询实体

```javascript
const all = Engine.getEntities(e => e.isAlive);                      // 存活实体（不带过滤会含已删除实体；也可用 Engine.currentSpace.aliveItems）
const lines = Engine.getEntitiesByType('LINE');                      // 按类型：LINE, CIRCLE, ARC, PLINE, TEXT, MTEXT, INSERT, HATCH
const red = Engine.getEntities(ent => ent.color === 1);              // 按颜色
const layerA = Engine.getEntities(ent => ent.layer === "图层A");     // 按图层
const bbox = entity.boundingBox();                                   // { pt1, pt2, width, height, center }
const combined = Engine.getBoundsByEntities([e1, e2], "WCS");        // 组合范围

// 选择集
Engine.ssSetFirst([entity1, entity2]);   // 设置选择集
const selected = Engine.ssGetFirst();    // 获取选择集
```

### 文本对齐方式（textAlignment）

```
7=左上     8=中上     9=右上
4=左中     5=中心     6=右中
1=左下     2=中下     3=右下
```

---

## 参考文档索引

需要更详细的信息时，请查阅对应的参考文档：

| 需要... | 查阅 |
|---------|------|
| 完整实体目录（椭圆、实体填充、射线、点、贝塞尔、图片等） | [reference/entity-catalog.md](entity-catalog.md) |
| 移动、复制、旋转、缩放、镜像、删除的详细用法 | [reference/editing-transforms.md](editing-transforms.md) |
| 查询、过滤、选择集、边界框 | [reference/query-selection.md](query-selection.md) |
| 颜色（RGB）、图层、线型、透明度、扩展数据 XData | [reference/styling.md](styling.md) |
| 标注实体（线性、对齐、半径、角度、弧长、坐标标注） | [reference/dimensions.md](dimensions.md) |
| 填充（80+ 内置图案、自定义图案、边界设置） | [reference/hatch-fill.md](hatch-fill.md) |
| 块定义、块插入 InsertEnt、符号管理、组 GroupEnt | [reference/blocks-symbols.md](blocks-symbols.md) |
| 撤销/重做系统、撤销标记、嵌套撤销 | [reference/undo-patterns.md](undo-patterns.md) |
| 自定义命令、用户输入（getPoint、getEntity 等）、事件系统 | [reference/commands-input.md](commands-input.md) |
| 距离、角度、交点、面积、空间索引 | [reference/geometry.md](geometry.md) |
| 打开/保存文件、DWG 导入导出、服务端操作 | [reference/file-operations.md](file-operations.md) |
