sync: HP_BOWEI 2026-10-15
This commit is contained in:
@@ -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()
|
||||
Reference in New Issue
Block a user