sync: HP_BOWEI 2026-10-15

This commit is contained in:
Myfro9
2026-10-15 01:59:40 +08:00
parent 771acd4171
commit a0a3445bfd
21 changed files with 3042 additions and 16 deletions
+115
View File
@@ -0,0 +1,115 @@
"""占位登记与重叠检测。
原理图上画的每一样东西都登记成一个矩形,最后逐对相交检查。
要拦的是三类:文字压文字、文字压器件/走线、器件压器件。
走线之间相交是正常的(交叉不等于连接),不算错。
"""
PAPER = {"A4": (297.0, 210.0), "A3": (420.0, 297.0), "A2": (594.0, 420.0), "A1": (841.0, 594.0)}
CH_W = 1.20 # 1.27 号字下 ASCII 单字符宽度(mm)。原来用 0.90 会漏报:DVBS2_dmod 的
# C405 "22u/35V" 实际压到隔壁 C406 的极板上而没报;1.10 又漏过 C412。宁可误报(G-0034)
CJK_W = 1.30 # 中文/全角字符宽度。KiCad 的笔画字体里全角字宽约等于字号,
# 按 ASCII 的 0.90 算会低估近 40% —— 09 RF 页就漏检过一处
# 中文说明压住端接电阻的重叠,所以按字符类型分别估(G-0034)。
def strw(s, size=1.27):
"""按字符类型估算字符串宽度(mm)"""
k = size / 1.27
return sum((CJK_W if ord(c) > 0x2E80 else CH_W) for c in s) * k
CH_H = 1.70 # 单行文字高度
LBL_PAD = 3.0 # 全局标签外框比文字多出来的量(箭头/边框)
def cat(what):
return what.split(":", 1)[0]
class Canvas:
def __init__(self, paper="A3", name=""):
w, h = PAPER[paper]
# KiCad 图框内沿约在四边 10mm 处;左边还有行号栏,底部整条留给标题栏
self.x0, self.y0 = 22.0, 14.0
self.x1, self.y1 = w - 14.0, h - 36.0
self.name, self.paper = name, paper
self.boxes = []
# ---- 登记 ----
def add(self, x0, y0, x1, y1, what):
if x1 < x0: x0, x1 = x1, x0
if y1 < y0: y0, y1 = y1, y0
self.boxes.append((x0, y0, x1, y1, what))
def add_sym(self, cx, cy, bbox, what, pad=0.0):
"""bbox 为符号坐标系(y 向上,已按放置角度旋转过)。"""
bx0, by0, bx1, by1 = bbox
self.add(cx + bx0 - pad, cy - by1 - pad, cx + bx1 + pad, cy - by0 + pad, what)
def add_text(self, x, y, s, justify="left", size=1.27, what=None):
k = size / 1.27
w = strw(s, size)
h = CH_H * k
if justify == "left":
x0, x1 = x, x + w
elif justify == "right":
x0, x1 = x - w, x
else:
x0, x1 = x - w / 2.0, x + w / 2.0
self.add(x0, y - h * 0.8, x1, y + h * 0.4, what or ("text:" + s[:18]))
def add_label(self, x, y, s, lrot, what=None):
"""全局标签:锚点在 (x,y),标签体朝 lrot 指定的方向伸出。
0=向右 180=向左 90=向上 270=向下(KiCad 文字角度约定)。"""
w = strw(s) + LBL_PAD
t = 1.15 # 标签体半高(1.27 号字 + 边框,实测约 2.1~2.4mm 高;排针 2.54 行距刚好放得下)
d = 0.4 # 标签体把锚点包在里面,这一小段不算和自己的引线冲突
if lrot == 0:
self.add(x + d, y - t, x + w, y + t, what)
elif lrot == 180:
self.add(x - w, y - t, x - d, y + t, what)
elif lrot == 90:
self.add(x - t, y - w, x + t, y - d, what)
else:
self.add(x - t, y + d, x + t, y + w, what)
def add_wire(self, x1, y1, x2, y2, what="wire"):
t = 0.25
self.add(min(x1, x2) - t, min(y1, y2) - t, max(x1, x2) + t, max(y1, y2) + t, what)
# ---- 检查 ----
def outside(self):
bad = []
for b in self.boxes:
if b[0] < self.x0 - 0.01 or b[1] < self.y0 - 0.01 or \
b[2] > self.x1 + 0.01 or b[3] > self.y1 + 0.01:
bad.append(b)
return bad
@staticmethod
def _care(a, b):
ca, cb = cat(a), cat(b)
txt = ("text", "lbl", "ref")
# 断路标记画在引脚端点上,本来就贴着符号和走线,只管它别压着文字
if "nc" in (ca, cb) or "jct" in (ca, cb):
return ca in txt or cb in txt
if ca in txt or cb in txt:
return True
return ca == "sym" and cb == "sym"
def overlaps(self):
res, bs = [], self.boxes
for i in range(len(bs)):
ax0, ay0, ax1, ay1, aw = bs[i]
for j in range(i + 1, len(bs)):
bx0, by0, bx1, by1, bw = bs[j]
if ax1 <= bx0 + 0.01 or bx1 <= ax0 + 0.01 or \
ay1 <= by0 + 0.01 or by1 <= ay0 + 0.01:
continue
if not self._care(aw, bw):
continue
res.append((aw, bw, round(ax0, 1), round(ay0, 1)))
return res
def report(self):
return self.outside(), self.overlaps()