| name | easyeda-draw-checking |
| description | Schematic verification and quality checking for EasyEDA Pro. Invoke when verifying layout, checking for overlaps, validating designators, or running design rule checks. |
原理图检查
布局验证、重叠检测、位号检查、DRC 的完整指南。
⚠️ 重要:所有检查必须通过 CLI 执行,禁止使用 curl 直接调用 API。
0. 快捷入口:CLI 一键检查
按绘制阶段使用不同的检查命令:
./scripts/draw_cli.py verify-placement
./scripts/draw_cli.py verify-wiring
./scripts/draw_cli.py check-all
./scripts/draw_cli.py drc --show-ui
1. DRC 检查(Design Rule Check)
1.0 DRC API 限制(重要)
⚠️ EasyEDA SCH_Drc API 只返回聚合统计:
[{ type: "fatalError", count: 1 }, { type: "warn", count: 11 }]
不返回每个错误的具体信息(器件名、引脚号、错误描述等)。
查看逐项详细错误的唯一方式:
./scripts/draw_cli.py drc --show-ui
这会呼出 EasyEDA 底部的 DRC 面板,面板中可看到每个错误的器件、引脚、具体描述。
1.1 基础 DRC
const passed = await eda.sch_Drc.check(true, false, false);
const errors = await eda.sch_Drc.check(true, false, true);
1.2 DRC 问题排查流程
DRC 不通过
│
├─ fatalError(致命错误)
│ ├─ 未连接引脚 → 补全连线 或 添加 NC 标记
│ ├─ 网络短路 → 检查同一网络是否有不该连接的引脚
│ └─ 缺失网络标签 → 添加 NetFlag / NetPort
│
└─ warn(警告)
├─ 空网络导线 → 为导线设置网络名
├─ 未使用引脚 → 确认是否需要 NC 标记
└─ 去耦电容缺失 → 在 IC 电源引脚附近补充
1.3 使用 easyeda-draw 函数
import utils from './scripts/draw-utils.js';
const result = await utils.runDrc();
2. 重复标签检测
2.1 检测原理
遍历所有 NetFlag/NetPort 图元,按坐标分组,找出同一位置放置多次的图元。
2.2 使用函数
import utils from './scripts/draw-utils.js';
const result = await utils.detectDuplicateLabels();
const cleanup = await utils.cleanupDuplicateLabels();
2.3 手动检测
const allComps = await eda.sch_PrimitiveComponent.getAll();
const posMap = new Map();
for (const c of allComps || []) {
if (c.designator && c.designator !== '?') continue;
const key = `${c.x},${c.y}`;
if (!posMap.has(key)) posMap.set(key, []);
posMap.get(key).push({
id: c.primitiveId,
type: c.net ? 'NetFlag' : 'NetPort',
net: c.net,
rotation: c.rotation,
});
}
const duplicates = [];
for (const [pos, items] of posMap) {
if (items.length > 1) duplicates.push({ position: pos, items });
}
3. 导线网络名完整性检查
3.1 检测原理
遍历所有导线,检查网络名是否为空。
3.2 使用函数
import utils from './scripts/draw-utils.js';
const result = await utils.checkWireNets();
3.3 修复导线网络名
const w = await eda.sch_Primitive.getPrimitiveByPrimitiveId(wireId);
const aw = w.toAsync();
aw.setState_Net("NET_NAME");
aw.done();
4. 未连接引脚检测
4.1 检测原理
对每个真实器件(有设计位号的),检查各引脚是否被导线可达或连接了网络标签。
改进点(与旧版本差异):
| 特性 | 旧版本 | 新版本 |
|---|
| 4PIN 轻触开关 | 所有引脚都检查 | PIN1↔PIN2 内部短接,PIN3↔PIN4 内部短接,只接一对即可 |
| NC 标记 | 不识别 | 有 NC 标记的引脚不算未连接 |
| 分级 | 全部报 error | 区分 error (应连接) 和 warning (4PIN 冗余引脚,正常) |
4.2 使用 CLI
./scripts/draw_cli.py check-unconnected
4.3 输出解读
errorCount > 0 → 有引脚应连接但未连接,必须修复
warningCount > 0 且 errorCount = 0 → 4PIN 开关冗余引脚,正常无需修复
- 4PIN 开关判断: 器件有 4 个引脚且符号名包含 SWITCH/轻触/4PIN/SMD_4
4.5 短路检测(NEW)
原理
用并查集 (union-find) 合并物理上相连的连接点,如果同一个连通分量中有 2+ 个不同网络名 → 短路。
使用 CLI
./scripts/draw_cli.py check-shorts
典型短路场景
- VCC 和 GND 通过导线直接连通
- ROW0 和 ROW1 通过同一连接点误连
- 两个不同信号通过 NetPort 标签放在同一坐标
4.7 冗余导线检测(NEW)
原理
检查同两个物理点之间是否有多条导线。冗余导线不会引起电气错误,但让原理图凌乱。
使用 CLI
./scripts/draw_cli.py check-redundant-wires
5. 布局验证(重叠检测)
检测所有器件重叠
import utils from './scripts/draw-utils.js';
const { overlaps } = await utils.checkOverlaps();
手动检测
const compIds = await eda.sch_PrimitiveComponent.getAllPrimitiveId();
const bboxes = [];
for (const id of compIds) {
const comps = await eda.sch_PrimitiveComponent.get([id]);
if (!comps || comps.length === 0) continue;
const c = comps[0];
const pins = await eda.sch_PrimitiveComponent.getAllPinsByPrimitiveId(id);
if (pins && pins.length > 0) {
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
for (const p of pins) {
minX = Math.min(minX, p.x);
maxX = Math.max(maxX, p.x);
minY = Math.min(minY, p.y);
maxY = Math.max(maxY, p.y);
}
bboxes.push({
id,
designator: c.designator,
name: c.name,
: [minX, minY, maxX, maxY],
: (maxX - minX) * (maxY - minY),
});
}
}
overlaps = [];
( i = ; i < bboxes.; i++) {
( j = i + ; j < bboxes.; j++) {
a = bboxes[i].;
b = bboxes[j].;
(a[] < b[] && a[] > b[] && a[] < b[] && a[] > b[]) {
overlaps.({
: bboxes[i].,
: bboxes[j].,
});
}
}
}
间距检查
const minSpacing = 40;
const tooClose = [];
for (let i = 0; i < bboxes.length; i++) {
for (let j = i + 1; j < bboxes.length; j++) {
const a = bboxes[i].bbox;
const b = bboxes[j].bbox;
const ax = (a[0] + a[2]) / 2;
const ay = (a[1] + a[3]) / 2;
const bx = (b[0] + b[2]) / 2;
const by = (b[1] + b[3]) / 2;
const dist = Math.sqrt((ax - bx) ** 2 + (ay - by) ** 2);
if (dist < minSpacing) {
tooClose.push({
comp1: bboxes[i].designator,
comp2: bboxes[j].designator,
distance: dist,
minRequired: minSpacing,
});
}
}
}
6. 位号检查
检查缺失或异常位号
const compIds = await eda.sch_PrimitiveComponent.getAllPrimitiveId();
const issues = [];
for (const id of compIds) {
const comps = await eda.sch_PrimitiveComponent.get([id]);
if (!comps || comps.length === 0) continue;
const c = comps[0];
if (!c.designator) {
issues.push({ id, type: "missing_designator", name: c.name });
continue;
}
if (c.designator.includes("?")) {
issues.push({ id, type: "unassigned_designator", designator: c.designator, name: c.name });
}
if (!/^[A-Z]+\d+$/.test(c.designator)) {
issues.push({ id, type: "invalid_format", designator: c.designator, name: c.name });
}
}
位号重复检查
const designatorMap = new Map();
const duplicates = [];
for (const id of compIds) {
const comps = await eda.sch_PrimitiveComponent.get([id]);
const c = comps[0];
if (c.designator) {
if (designatorMap.has(c.designator)) {
duplicates.push({
designator: c.designator,
ids: [designatorMap.get(c.designator), id],
});
} else {
designatorMap.set(c.designator, id);
}
}
}
7. 文本标注检查
检测重复文本
const textIds = await eda.sch_PrimitiveText.getAllPrimitiveId();
const textMap = new Map();
for (const tid of textIds) {
const t = await eda.sch_PrimitiveText.get([tid]);
if (t && t[0]) {
const key = `${t[0].x},${t[0].y}`;
if (!textMap.has(key)) textMap.set(key, []);
textMap.get(key).push({ id: tid, content: t[0].content, fontSize: t[0].fontSize });
}
}
const duplicateTexts = [];
for (const [pos, items] of textMap) {
if (items.length > 1) duplicateTexts.push({ position: pos, items });
}
检查文本位置是否合理
const textOverlaps = [];
for (const t of texts) {
for (const b of bboxes) {
if (t.x > b.bbox[0] && t.x < b.bbox[2] && t.y > b.bbox[1] && t.y < b.bbox[3]) {
textOverlaps.push({
text: t.content,
component: b.designator,
});
}
}
}
8. 导线穿过器件检测(NEW)
8.1 检测原理
遍历所有导线的每个线段,与所有真实器件的 BBox(边界框)做交叉检测:
- 若导线端点在器件 BBox 内部(排除 ±3 容差的引脚边缘)→ 报出
- 若线段与器件 BBox 相交,且交叉长度 > 5 单位 → 报出
这能发现像 R7、R8 被 ROW 网络导线直接穿过的问题。
8.2 使用 CLI
./scripts/draw_cli.py check-wire-through
8.3 使用函数
import utils from './scripts/draw-utils.js';
const result = await utils.checkWireThroughComponent();
9. 完整检查流程(一键检查,7 步)
使用 CLI
./scripts/draw_cli.py check-all
7 步检查清单
| 步骤 | 检查项 | CLI 命令 | 说明 |
|---|
| 1 | 重复标签 | check-duplicates | 同一坐标多个 NetFlag/NetPort |
| 2 | 导线网络名 | check-wire-nets | 无网络名的导线 |
| 3 | 未连接引脚 | check-unconnected | 4PIN 开关感知 + NC 标记感知 |
| 4 | 短路检测 | check-shorts | 不同网络名导线连接在一起 |
| 5 | 冗余导线 | check-redundant-wires | 同两点间多条导线 |
| 6 | 导线穿器件 | check-wire-through | 导线穿过元器件本体 |
| 7 | DRC | drc | EasyEDA 内置设计规则检查 |
10. 检查清单
布局检查
位号检查
网络检查
NC 检查
电气检查
DRC 检查
文档检查