表格提取
从 CAD 图纸中自动识别并提取表格数据。
概念
extractTables() 函数可以自动识别图纸中由直线和文字构成的表格,提取表格结构和单元格数据。
支持识别:
- 由 Line/Polyline 构成的表格边框
- 单元格中的 Text/MText 内容
- 合并单元格
基本用法
全图提取
const { extractTables } = vjcad;
// 全图提取(最简单)
const result = extractTables();
if (result.error) {
console.error("提取失败:", result.error);
} else if (result.tables.length === 0) {
console.log("未识别到表格数据");
} else {
console.log(`识别到 ${result.tables.length} 个表格`);
result.tables.forEach((table, index) => {
console.log(`=== 表格 ${index + 1} ===`);
console.log(`行数: ${table.rowCount}, 列数: ${table.colCount}`);
// 打印表格数据
for (let r = 0; r < table.rowCount; r++) {
const row = table.datas[r] || [];
console.log(`第${r + 1}行:`, row.join(' | '));
}
});
}
指定区域提取
const result = extractTables({
bounds: {
minX: 0,
minY: -200,
maxX: 500,
maxY: 100
}
});
指定图层提取
const result = extractTables({
layers: ['表格图层', '标注层']
});
完整参数
const result = extractTables({
// 提取范围(可选)
bounds: { minX: 0, minY: -200, maxX: 500, maxY: 100 },
// 指定图层(可选)
layers: ['图层1', '图层2'],
// 包含的实体类型
includeLine: true, // 包含直线(默认 true)
includePolyline: true, // 包含多段线(默认 true)
includeText: true, // 包含单行文字(默认 true)
includeMText: true, // 包含多行文字(默认 true)
includeBlocks: true, // 包含块中实体(默认 true)
includeGroups: true, // 包含组中实体(默认 true)
// 识别参数
digit: 4, // 小数精度(默认 4)
tol: 0, // 误差值(0 为自动)
tableEdgeMinPoint: 12, // 表格边线最少端点数(默认 12)
tableTextMinCount: 4, // 表格最少文字数(默认 4)
cellEmptyRatio: 90, // 空值所占最大比例(默认 90)
// 调试
debug: false // 调试模式
});
返回数据结构
返回值
interface TableExtractResult {
tables: TableData[]; // 表格数组
tol: number; // 实际使用的误差值
error?: string; // 错误信息
debug_table_lines?: string; // 调试数据(debug=true 时)
debug_table_bounds?: string;
debug_table_posflag?: string;
debug_table_corner?: string;
}
表格数据
interface TableData {
rowCount: number; // 行数
colCount: number; // 列数
rect: string; // 表格范围(字符串形式边界)
rows: string[]; // 行位置信息
cols: string[]; // 列位置信息
spans: Record<string, string>; // 合并单元格信息(键→字符串编码)
datas: string[][]; // 单元格数据 [行][列]
attr: TableAttr; // 识别过程属性
}
interface TableAttr {
cellEmptyRatio: number;
tableTextCount: number;
tableCellMaxCount: number;
unLinkLineRatio: number;
}
示例:绘制并提取表格
const {
MainView, initCadContainer,
LineEnt, TextEnt, TextAlignmentEnum,
Engine, extractTables, 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();
// === 1. 绘制表格 ===
const tableStartX = 0;
const tableStartY = 0;
const cellWidth = 100;
const cellHeight = 40;
const rows = 3;
const cols = 4;
// 表格数据
const tableData = [
['序号', '名称', '数量', '单位'],
['1', '钢筋', '100', '吨'],
['2', '混凝土', '500', '立方米']
];
// 绘制水平线
for (let r = 0; r <= rows; r++) {
const y = tableStartY - r * cellHeight;
const line = new LineEnt(
[tableStartX, y],
[tableStartX + cols * cellWidth, y]
);
line.setDefaults();
Engine.addEntities(line);
}
// 绘制垂直线
for (let c = 0; c <= cols; c++) {
const x = tableStartX + c * cellWidth;
const line = new LineEnt(
[x, tableStartY],
[x, tableStartY - rows * cellHeight]
);
line.setDefaults();
Engine.addEntities(line);
}
// 填充文字内容
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const text = new TextEnt();
text.text = tableData[r][c];
text.insertionPoint = [
tableStartX + c * cellWidth + cellWidth / 2,
tableStartY - r * cellHeight - cellHeight / 2
];
text.height = 15;
text.textAlignment = TextAlignmentEnum.MidCenter;
text.setDefaults();
Engine.addEntities(text);
}
}
Engine.zoomExtents();
message.info("表格已绘制完成");
// === 2. 提取表格 ===
const result = extractTables();
if (result.tables.length > 0) {
const table = result.tables[0];
message.info(`识别到表格: ${table.rowCount}行 x ${table.colCount}列`);
// 打印表头
if (table.datas && table.datas[0]) {
message.info("表头: " + table.datas[0].join(', '));
}
// 遍历数据
for (let r = 0; r < table.rowCount; r++) {
const row = table.datas[r] || [];
console.log(`第${r + 1}行:`, row);
}
}
处理合并单元格
const result = extractTables();
result.tables.forEach(table => {
// 检查合并单元格
if (table.spans && Object.keys(table.spans).length > 0) {
console.log("合并单元格信息:", table.spans);
// spans 类型为 Record<string, string>——键为单元格标识,值为合并信息字符串
for (const [key, span] of Object.entries(table.spans)) {
console.log(`单元格 ${key} 合并信息:`, span);
}
}
});
导出为 JSON/CSV
导出为 JSON
const result = extractTables();
if (result.tables.length > 0) {
const table = result.tables[0];
const json = JSON.stringify(table.datas, null, 2);
console.log(json);
}
导出为 CSV
const result = extractTables();
if (result.tables.length > 0) {
const table = result.tables[0];
const csv = table.datas.map(row => row.join(',')).join('\n');
console.log(csv);
// 下载 CSV 文件
const blob = new Blob([csv], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'table.csv';
a.click();
URL.revokeObjectURL(url);
}
注意事项
- 表格结构:函数只能识别由直线/多段线构成的规则表格
- 文字位置:文字必须在单元格范围内才能被正确归类
- 误差容限:复杂图纸可能需要调整
tol参数 - 性能:大型图纸建议使用
bounds或layers限制范围
API 参考
extractTables(options?)
| 参数 | 类型 | 说明 |
|---|---|---|
bounds |
Bounds | 提取范围 {minX, minY, maxX, maxY} |
layers |
string[] | 指定图层 |
includeLine |
boolean | 包含直线(默认 true) |
includePolyline |
boolean | 包含多段线(默认 true) |
includeText |
boolean | 包含单行文字(默认 true) |
includeMText |
boolean | 包含多行文字(默认 true) |
includeBlocks |
boolean | 包含块中实体(默认 true) |
includeGroups |
boolean | 包含组中实体(默认 true) |
digit |
number | 小数精度(默认 4) |
tol |
number | 误差值(0 为自动) |
tableEdgeMinPoint |
number | 表格边线最少端点数(默认 12) |
tableTextMinCount |
number | 表格最少文字数(默认 4) |
cellEmptyRatio |
number | 空值所占最大比例(默认 90) |
debug |
boolean | 调试模式 |
返回值
| 字段 | 类型 | 说明 |
|---|---|---|
error |
string | 错误信息(可选) |
tables |
TableData[] | 表格数据数组 |
TableData
| 字段 | 类型 | 说明 |
|---|---|---|
rowCount |
number | 行数 |
colCount |
number | 列数 |
rect |
string | 表格范围(字符串形式) |
rows |
string[] | 行位置信息 |
cols |
string[] | 列位置信息 |
datas |
string[][] | 单元格数据 [行][列] |
spans |
Record<string, string> | 合并单元格信息 |
attr |
TableAttr | 识别过程属性 |