# recognition / 智能识别总览

> 文档：`vjcad/doc/recognition/index.md`、`vjcad/doc/recognition/table-extract.md`
> 示例：`vjcad/example/recognition/01extracttable.js`

`recognition` 是 vjcad 的**结构识别**模块，目前只有一个核心能力：**表格识别**——把图纸里"由直线 / 多段线 + 文字组合而成"的表格，还原成有行列结构的 `TableData[]`。

## 1. 解决的问题

CAD 里的"表格"实际上是 **直线 + 文字** 的拼接，没有结构化数据。`extractTables` 帮你把：

- 多段线 / 直线 围成的矩形网格 → 行列单元
- 落在单元格内的文字 → 单元值
- 跨多列 / 跨多行的合并单元格 → `spans` 信息
- 嵌套图块 / 组合内的同类内容 → 可选展开

转换为：

```ts
interface TableData {
    rect: string;                       // 两对角点逗号串 "x1,y1,x2,y2"（无方括号，不保证 min/max 顺序）
    rowCount: number;
    colCount: number;
    rows: string[];                     // 各行分隔线 y 坐标，数字字符串数组（自上而下）
    cols: string[];                     // 各列分隔线 x 坐标，数字字符串数组
    spans: Record<string, string>;      // 合并单元格（已是对象）"row_col"（1 起算）-> "rowSpan,colSpan"
    datas: string[][];                  // [row][col] 单元格文本
    attr: TableAttr;                    // 识别统计（cellEmptyRatio/tableTextCount/...）
}
```

> 这些字段都**不能** `JSON.parse`：`rect` 用 `t.rect.split(',').map(Number)` 得 `[x1,y1,x2,y2]`（自己取 min/max）；`rows`/`cols` 用 `.map(Number)`；`spans` 已经是对象，值 `"2,1"` 再 `split(',')`。`datas` 是直接可读的单元格文本矩阵。

## 2. 核心 API（一个）

```ts
function extractTables(
    options?: TableExtractOptions
): TableExtractResult;
```

返回：

```ts
interface TableExtractResult {
    tables: TableData[];
    tol: number;        // 实际使用的距离容差
    error?: string;     // 失败原因
}
```

辅助：

```ts
function getTableExtractLayers(): string[];   // 全部实体出现过的图层名（去重排序）
```

## 3. 高频选项（TableExtractOptions）

| 选项 | 默认 | 说明 |
|---|---|---|
| `bounds` | `null` | `{ minX, minY, maxX, maxY }` 对象（`Bounds`），限定识别范围；不传则全图 |
| `layers` | 全部图层 | 字符串数组，限定参与识别的图层（大小写不敏感） |
| `includeLine` / `includePolyline` | `true` | 是否计入直线 / 多段线 |
| `includeText` / `includeMText` | `true` | 是否计入单行 / 多行文本 |
| `includeBlocks` / `includeGroups` | `true`（运行时） | 是否展开图块 / 组合内实体 |
| `digit` | 4 | 几何比较精度（小数位） |
| `tol` | 0（自动） | 端点对齐容差（`number`），0 / 不传则根据图纸自适应 |
| `tableEdgeMinPoint` | 12 | 表格边框最少顶点数（过滤小图形） |
| `tableTextMinCount` | 4 | 表格内最少文字数（过滤误识别） |
| `cellEmptyRatio` | 90 | 允许的最大空单元**百分比**（0–100）；有字单元占比 `< 100 - cellEmptyRatio` 时**整表丢弃**。切勿按 0~1 填，`0.5` 会丢弃几乎所有表 |
| `debug` | `false` | 控制台输出识别中间过程 |

## 4. 三种典型用法

```js
// 1) 全图识别（最简）
const r = extractTables();

// 2) 限定矩形 + 限定图层
const r2 = extractTables({
    bounds: { minX: 0, minY: 0, maxX: 1000, maxY: 800 },
    layers: ['表格', '0'],
});

// 3) 全配置
const r3 = extractTables({
    bounds:  { minX: 0, minY: 0, maxX: 200, maxY: 100 },
    layers:  ['表格'],
    includeLine: true, includePolyline: true,
    includeText: true, includeMText: true,
    includeBlocks: false, includeGroups: false,
    digit: 4, tol: 2,
    tableEdgeMinPoint: 12, tableTextMinCount: 4,
    cellEmptyRatio: 90, debug: false,   // cellEmptyRatio 是百分比（0–100），不是 0~1
});
```

## 5. 子文档

- 表格识别细节、TableData 结构、调优建议 → [table-extract](table-extract.md)

## 红旗

- 表格的"边"必须是 **闭合或近闭合** 的直线 / 多段线，光看着像表格但端点不对齐 → 加大 `tol`
- 文字可能因 `INSERT` 嵌套在图块内，找不到 → 打开 `includeBlocks: true`
- 调优阶段打开 `debug: true`：**不会往控制台打印**，而是在返回结果里多出 `debug_table_lines` / `debug_table_bounds` / `debug_table_posflag` / `debug_table_corner` 几个字符串字段（表格线、表格边界、位置标识、角点），需要自己解析后画到图上核对
- 返回的 `rect` 是 WCS（世界坐标）的逗号串 `"x1,y1,x2,y2"`（两对角点，无方括号、不能 `JSON.parse`，用 `split(',').map(Number)`），不是屏幕坐标，也不是 `BoundingBox` 对象
- `extractTables` 取实体走 `Engine.getEntities()`，**包含已 erase 的实体**（`isAlive=false`，软删除仍留在 `items` 里），识别结果可能含已删内容

## 参考（官方文档 MCP）

- 文档：`vjcad/doc/recognition/index.md`、`vjcad/doc/recognition/table-extract.md`
- 示例：`vjcad/example/recognition/01extracttable.js`
