# 图层与属性

图层管理、颜色、线型、扩展数据等。

## 图层管理

### 创建图层

```javascript
const { Engine } = vjcad;

// 方式1：使用 Engine.createLayer（推荐）
const layer = Engine.createLayer("标注层", {
    color: 1,              // 颜色索引
    lineType: "CONTINUOUS",
    layerOn: true,         // 是否显示
    isFrozen: false,       // 是否冻结
    isLocked: false        // 是否锁定
});

// 方式2：使用 doc.layers.addlayer
const doc = Engine.currentDoc;
if (!doc.layers.itemByName("辅助线层")) {
    doc.layers.addlayer("辅助线层", true, 3);  // 名称, 是否显示, 颜色
}

// 方式3：自动命名图层
const autoLayer = Engine.createLayer();  // 自动命名为 "图层1", "图层2" 等
```

### 切换图层

```javascript
// 获取当前图层
const currentLayer = Engine.getCurrentLayer();

// 切换到指定图层
Engine.setCurrentLayer("图层A");

// 访问当前图层名称
const layerName = Engine.currentDoc.CLAYER;
```

### 获取图层

```javascript
// 获取所有图层
const layerArr = Engine.getLayers();  // Layer[] 数组
layerArr.forEach(layer => {
    console.log(`${layer.name}: 颜色=${layer.color}, 可见=${layer.layerOn}`);
});

// 根据名称获取图层
const layer = Engine.getLayerByName("标注层");

// 检查图层是否存在
const exists = !!Engine.currentDoc.layers.itemByName("建筑层");
```

### 图层可见性

```javascript
const layer = Engine.getLayerByName("图层名");

// 关闭/打开图层
layer.layerOn = false;   // 关闭（不可见，但参与重生成）
layer.layerOn = true;    // 打开
Engine.regen(true);      // 必须重新渲染
```

### 图层冻结

```javascript
const layer = Engine.getLayerByName("图层名");

// 冻结/解冻图层
layer.isFrozen = true;   // 冻结（不可见，不参与重生成）
layer.isFrozen = false;  // 解冻
Engine.regen(true);

// 注意："0 图层和当前图层不能冻结"只是图层面板 UI 的拦截；
// isFrozen setter 不做任何校验，代码里需自行避开这两种图层
```

### 图层锁定

```javascript
const layer = Engine.getLayerByName("图层名");

// 锁定/解锁图层
layer.isLocked = true;   // 锁定（可见但不可选择、不可编辑）
layer.isLocked = false;  // 解锁
```

### 图层状态对比

| 状态 | 可见 | 可选择 | 可编辑 | 参与重生成 |
|------|------|--------|--------|------------|
| 正常 | ✓ | ✓ | ✓ | ✓ |
| 关闭 (`layerOn=false`) | ✗ | ✗ | ✗ | ✓ |
| 冻结 (`isFrozen=true`) | ✗ | ✗ | ✗ | ✗ |
| 锁定 (`isLocked=true`) | ✓ | ✗ | ✗ | ✓ |

### 按图层获取实体

```javascript
// 获取指定图层的所有实体（getEntities 含已删除实体，条件里带上 isAlive）
const buildingEntities = Engine.getEntities(ent => ent.isAlive && ent.layer === "建筑层");

// 获取多个图层的实体
const multiLayerEntities = Engine.getEntities(ent => 
    ent.isAlive && (ent.layer === "建筑层" || ent.layer === "标注层")
);
```

---

## 颜色设置

### 颜色索引

```javascript
const line = new LineEnt([0, 0], [100, 0]);
line.setDefaults();  // 必须先调用

// ACI 颜色索引
line.color = 1;      // 红色
line.color = 2;      // 黄色
line.color = 3;      // 绿色
line.color = 4;      // 青色
line.color = 5;      // 蓝色
line.color = 6;      // 洋红
line.color = 7;      // 白色

// 特殊值
line.color = 256;    // 随层 (ByLayer)
line.color = 0;      // 随块 (ByBlock)

Engine.addEntities(line);
```

修改**已加入图纸**的实体时，直接赋 `color`/`layer`/`lineType` 不记录撤销；要可撤销用 `Engine.setEntityColor(ents, 1)` / `Engine.setEntityLayer(ents, "图层名")`（单个或数组均可）、`Engine.setEntityLineType` / `setEntityLineTypeScale` / `setEntityTransparency`（**只收数组**）。

### RGB 真彩色

```javascript
const { ColorConverter } = vjcad;

// 方式1：直接使用十六进制（需要加标记位）
line.color = 0x1000000 + 0xFF8000;  // 橙色

// 方式2：使用 ColorConverter
line.color = ColorConverter.createRgbColorIndex(0x800080);  // 紫色

// 方式3：使用 RGB 分量
line.color = ColorConverter.createRgbColorIndexFromComponents(255, 192, 203);  // 粉色

// 方式4：使用十六进制字符串
line.color = ColorConverter.createRgbColorIndexFromHexStr("#FFD700");  // 金色
```

### 系统当前颜色

```javascript
// 设置当前绘图颜色
Engine.CECOLOR = 1;  // 红色

// 实体使用当前颜色
const line = new LineEnt([0, 0], [100, 0]);
line.setDefaults();
line.color = Engine.CECOLOR;
```

---

## 线型设置

### 常用线型

```javascript
const line = new LineEnt([0, 0], [100, 0]);
line.setDefaults();

line.lineType = "CONTINUOUS";  // 实线（默认）
line.lineType = "HIDDEN";      // 虚线
line.lineType = "CENTER";      // 中心线
line.lineType = "PHANTOM";     // 幻影线
line.lineType = "DASHED";      // 别名：按 Hidden 绘制（DASHED/DASHED1-3/DOT 都映射为 Hidden）
// 内置只有 Continuous/Hidden/Center/Phantom；其他名称（DASHDOT 等）须先加载线型定义，否则画成实线

// 线型比例
line.lineTypeScale = 1.0;      // 默认
line.lineTypeScale = 0.5;      // 更密
line.lineTypeScale = 2.0;      // 更稀
```

### 系统当前线型

```javascript
// 设置当前线型
Engine.CELTYPE = "HIDDEN";

// 设置当前线型比例
Engine.CELTSCALE = 1.5;
```

---

## 线宽设置

```javascript
const line = new LineEnt([0, 0], [100, 0]);
line.setDefaults();

// 线宽值（单位：0.01mm）；新建实体默认 -1（随层），setDefaults() 不改线宽
line.lineWeight = 0;    // 0.00mm
line.lineWeight = 15;   // 0.15mm
line.lineWeight = 30;   // 0.30mm
line.lineWeight = 50;   // 0.50mm
line.lineWeight = 100;  // 1.00mm

// 特殊值
line.lineWeight = -1;   // 随层 (ByLayer)
line.lineWeight = -2;   // 随块 (ByBlock)
```

---

## 透明度设置

```javascript
const circle = new CircleEnt([50, 50], 25);
circle.setDefaults();

// 设置透明度（0-100，0=不透明；超过 90 会被钳到 90，不能完全透明）
circle.transpMgr.setTp100(50);

// 随层透明度
circle.transpMgr.setValue(-1);
```

---

## 默认属性

### 设置系统默认属性

```javascript
// 设置默认值
Engine.CECOLOR = 1;            // 当前颜色
Engine.CELTYPE = "HIDDEN";     // 当前线型
Engine.CELTSCALE = 1.5;        // 当前线型比例
```

### 应用默认属性到实体

```javascript
// setDefaults() 会应用以下系统默认值：
// - 图层 (CLAYER)
// - 颜色 (CECOLOR)
// - 线型 (CELTYPE)
// - 线型比例 (CELTSCALE)

const line = new LineEnt([0, 0], [100, 0]);
line.setDefaults();  // 应用系统默认值

// 重要：在 setDefaults() 之后设置自定义属性
line.color = 3;      // 覆盖默认颜色

Engine.addEntities(line);
```

---

## 扩展数据 (XData)

存储自定义数据到实体。

### 设置扩展数据

```javascript
const line = new LineEnt([0, 0], [100, 0]);
line.setDefaults();

// 设置扩展数据（支持任意 JSON 对象）
line.setExtData("SENSOR_DATA", {
    name: "温度传感器",
    value: 25.5,
    unit: "℃",
    isActive: true,
    lastUpdate: "2026-01-29",
    config: {
        minValue: 0,
        maxValue: 100
    }
});

Engine.addEntities(line);
```

### 读取扩展数据

```javascript
// 检查是否有扩展数据
if (line.hasExtData()) {
    // 获取应用程序名
    const appName = line.extDataAppName;  // "SENSOR_DATA"
    
    // 获取扩展数据对象（已自动解析 JSON）
    const data = line.extData;
    console.log(data.name);   // "温度传感器"
    console.log(data.value);  // 25.5
}
```

### 修改扩展数据

```javascript
// 方式1：完整替换
line.setExtData("SENSOR_DATA", {
    name: "温度传感器",
    value: 30.2,
    unit: "℃"
});

// 方式2：基于现有数据修改
const currentData = line.extData;
if (currentData) {
    currentData.value = 30.2;
    currentData.lastUpdate = "2026-01-30";
    line.setExtData("SENSOR_DATA", currentData);
}
```

### 清除扩展数据

```javascript
line.clearExtData();
```

### 批量查询带扩展数据的实体

```javascript
// 查询所有带扩展数据的实体（getEntities 含已删除实体，先滤掉）
const allEntities = Engine.getEntities(ent => ent.isAlive);
const entitiesWithXData = allEntities.filter(ent => ent.hasExtData?.());

// 按 AppName 分类
const byAppName = {};
entitiesWithXData.forEach(ent => {
    const appName = ent.extDataAppName;
    if (!byAppName[appName]) byAppName[appName] = [];
    byAppName[appName].push(ent);
});

// 查询特定 AppName 的实体
const sensorEntities = allEntities.filter(
    ent => ent.hasExtData?.() && ent.extDataAppName === "SENSOR_DATA"
);
```

### 原始 XData 格式

```javascript
// 获取原始格式（用于调试）
const rawXData = line.xdataRaw;
// 返回格式: { "1001": "AppName", "1000": "JSON字符串" }
```

**注意**：扩展数据支持导出到 DWG 并重新加载，数据会保留。

---

## 文件操作

### 打开本地文件

```javascript
// 执行命令
await Engine.editor.executerWithOp('OPENFROMLOCAL');
```

### 保存本地文件

```javascript
// 保存到 IndexedDB
await Engine.editor.executerWithOp('SAVELOCAL');

// 快速保存下载 .vcad 文件
await Engine.editor.executerWithOp('QSAVE');

// 另存为
await Engine.editor.executerWithOp('SAVEAS');
```

### 打开服务器文件

```javascript
await Engine.editor.executerWithOp('OPENFROMSERVER');
```

### 保存服务器文件

```javascript
await Engine.editor.executerWithOp('SAVESERVER');
```

### 导入/导出 DWG

```javascript
// 导入 DWG
await Engine.editor.executerWithOp('IMPORTDWG');

// 导出 DWG
await Engine.editor.executerWithOp('EXPORTDWG');
```
