压力容器 / 压力管道检测布点图 CAD 自动绘制 v5.3
⚠️ 付费技能说明(Pay Skill · 支付宝 AI 按量付费)
本技能是付费技能(PAYSKILL),每次调用需支付 ¥5.00。 按次计费,基于支付宝 AI 按量付费
(Machine Pay / A2M)协议返回结果;支付能力由支付宝官方链路承担,本 Skill 不接触支付密钥、
不自行实现付款或签名。
调用遵循支付宝 A2M 契约,由平台调度层执行 probe → pay → complete → ack 流程:
用户调用 → 平台 probe →
未付费:下发 402 Payment-Needed → 支付宝 pay → complete → 下发 Payment-Proof
已付费/携带 Proof:脚本 ack 验签 → 放行主流程(开始出图)
付费链路自检(与平台五项自查一一对应)
| 平台自查项 | 本 Skill 的实现 |
|---|---|
| 402 账单 | 未付款时请求业务资源端点返回 HTTP 402 Payment Required;响应头 Payment-Needed 携带账单,响应体含 payment_needed / amount / out_trade_no。 |
| 凭证重试 | 支付后携带请求头 Payment-Proof: <凭证> 重发同一个请求(URL、请求方法、请求体与原请求保持一致),服务端校验通过后返回 200,结果在 content.data 内。 |
| 服务端验付 | 服务端调用支付宝 AI 按量付费凭证校验接口 alipay.aipay.agent.payment.verify 验签并核对订单、金额与服务标识;凭证无效或已过期时不交付任何资源,只回 402 账单让用户重新支付。 |
| 商家履约 | 资源交付后由服务端调用 alipay.aipay.agent.fulfillment.confirm 上报履约确认;上报失败可对同一订单重试,重试幂等,不会产生第二次扣费。 |
| 订单与幂等 | 每笔订单以唯一 out_trade_no 持久化于服务端订单库(本地对应 scripts/payment_gate.py 的 .pay_cache/orders.json),状态可恢复;同一订单重复请求只履约一次、不重复扣费。 |
> 本地闸口 scripts/payment_gate.py 只处理 402 / 验签 / 订单持久化 三环节;付费本体交给支付宝。
> 付费声明见同目录 skillhub.pay.yaml。
支付依赖包声明
| 依赖 | 用途 | 安装 |
|---|---|---|
@alipay/alipay-aipay |
卖家侧:为业务 API 接入支付宝 AI 按量付费 | npx -y @alipay/alipay-aipay@latest install |
@alipay/agent-payment |
买家侧:提供 alipay-payment-skill 与 alipay-bot 支付能力 |
npx -y @alipay/agent-payment@latest install |
scripts/payment_gate.py |
本地付费闸口:处理 402 / 验签 / 订单持久化三环节 | 随包提供,零第三方依赖 |
> 买家侧若已装 alipay-payment-skill 并使用 alipay-bot,支付与结果交付由官方支付能力承担;
> 本 Skill 只负责发起请求、调用官方支付能力并展示结果,不接触支付密钥、不自行实现付款或签名。
付费后的执行顺序
出图与支付解耦——支付只决定"能不能开始出图",一旦放行,后续所有 CAD 绘制步骤(分流、
标定、出图、核验、导出)与免费版本完全一致,见下方工作流。
> v5.3 新增:草图先叠加复核再出图(spec 红绿叠加到草图 PNG 比对,HoughLinesP 精测坐标);
> 管道文字支持 沿管线书写(模型角=草图角取反),preview_dwg.py 同步渲染旋转文字;
> connect() 无文档自动新建、free 额外层自动建层、audit_iso 跳过 GRID/EQUIP 层。
>
> v5.2 新增:多条管道在同一 DWG 里用方格分开、按管线号区分(draw_grid.py 自动分派容器/管道)、
> 多图产出即截图模式(layout.json 写 "shots": true)、
> learn_dwg.py 深度学习既有 CAD(编号体系 / 轴系 / 线宽 / 多图布局)。
> 并修掉 5 个会导致返工的坑(清空在编图纸、水平管段被拉直、SaveAs 到已打开文档、RPC 拒答、mtime 误判)。
用途
把手绘检测布点草图先分流:
| 分支 | 判出来是 | 引擎 | 参考文档 |
|---|---|---|---|
| 容器 | 立式 / 卧式压力容器 | scripts/vessel_cad.py |
references/spec-format.md |
| 管道 | 管道单线轴测图 | scripts/pipe_cad.py |
references/pipe-format.md |
两条 branch 的图元体系没有交集,不要试图用一套参数通吃:
- 容器 = 壳体轮廓(双线筒体 + 椭圆封头)+ 环缝/纵缝 + NDT 加粗段 + 测点 + 接管
- 管道 = 中心线单线图(open tree,不封闭)+ 焊口实心点 + 阀门/法兰/方位标
都支持画进已运行的 AutoCAD;容器额外支持多台方格排在同一张 DWG。
> 立式 与 卧式 是两套几何,由 spec 的 orient 字段切换(缺省 vertical):
>
> | | 立式 vertical | 卧式 horizontal |
> |---|---|---|
> | 坐标原点 | 筒体下端面中心 | 左封头环缝与容器轴线交点 |
> | 筒体几何 | geometry.H = 直边高(竖向) | geometry.L = 直边长(横向) |
> | 环缝 | 上下两条横向线 | 多条竖向线(welds.rings 给 x 列表) |
> | 纵缝 | 中间一条竖向线 | 多条横向线(welds.longs 给 x0/x1/y) |
> | 接管 | nozzles 是对象 {top,bottom,side} | nozzles 是数组,每项带 x/dir |
> | 方位箭头 | 上 / 北 | 上 / 东(按草图,arrow.right_text 可改) |
第 0 步:先分流(拿到草图第一件事,不许跳过)
python scripts/classify_sketch.py 草图.jpg --json cls.json --plot cls.png
输出示例(约 10 s):
[管道 +3 ] 自封闭轮廓占比 0.0029(单线图不封闭,1143 像素只来自字腔)
[管道 +2 ] 无长平行线对(单线图没有双线筒体)
判定:管道轴测单线图 (管道分 5 : 容器分 0,置信度 1.00)
判据是实测出来的(1 张管道 + 4 张容器,5/5 判对),阈值写在 classify_sketch.py 文件头:
| 判据 | 管道 pipe.jpg | 容器(4 张) | 门限 |
|---|---|---|---|
| ① 自封闭轮廓占比 填充面积 / 主连通域包围盒面积 | 0.0029 | 0.692 ~ 0.742 | >0.15 容器 / <0.05 管道 |
| ② 长平行线对(筒体两道母线) | 0 对 | 3 ~ 16 对 | ≥1 容器 |
| ③ 方位标(软证据) | 有 | 无 | +1 管道,检测不到不影响结论 |
> 为什么判据 ① 这么灵:容器画的是壳体,binary_fill_holes 之后会围出一整块内部面积;
> 单线轴测图永远不封闭,那点面积只来自汉字笔画围出的字腔。两者差 240 倍。
已经证伪、千万别捡回来的判据(实测过,没有区分力):
- ~~骨架直线占比~~:管道 0.68,容器 0.57~0.69,完全重叠。
- ~~孤立实心点数量~~:管道 0 个,容器 0~17 个。管道焊口点不是孤立点,
它是骑在管线上加粗的疙瘩,和管线连成一个连通域。 - ~~主图形长宽比~~:卧式容器 2.36 vs 管道 2.51,重叠。
判成 unknown(分差 ≤1)时人工确认:看主图形有没有成形壳体轮廓(有=容器,无=管道)。
⚡ 快车道(默认按这一条走:简单 + 省时间)
> 用户明确要求:"我要的是个简单的绘制图,不要弄复杂了,要有时间效率。"
> 所以下面的慢环节默认全部跳过,除非用户明确说"这个符号的尺寸要和草图一模一样"。
管道:三步出图
python classify_sketch.py 草图.jpg # ① 分流(容器 or 管道)
python pipe_cad.py spec.json --emit # ② 空跑核对坐标(秒回,不出图)
python pipe_cad.py spec.json # ③ 出图
python audit_iso.py # ④ 方向核验(管道必做)
python export_devices.py --open 出图.dwg --out 成果目录/单台图 --index # ⑤ 按单台出图
第 ⑤ 步:图上有方格(GRID 图层)时自动逐格切成"一个设备一张图",
设备名取格内字最大的那条标题(方格图的标题就是它);没有方格就整幅一张。
加 --full 可同时出一张合成总图。
多条管道 / 多台容器要合成一张 DWG:同一个思路,加一步排版
python draw_grid.py layout.json # ⑥ 方格排版:容器 / 管道可混排,按 spec["kind"] 自动分派
draw_grid.py 干三件事,一步到位:
| 它做什么 | 怎么做的 |
|---|---|
| 分派 | 读 spec["kind"];没写就看有没有 lines —— 有走 pipe_cad.build,没有走 vessel_cad.build |
| 分格区分 | 容器格标题用设备名;管道格标题用管线号(pipe_no,如 L0104 / LD0201)→ 这就是"用管道编号区别每条管" |
| 截图模式 | layout.json 里写 "shots": true,出图后自动跑 export_devices.py --full --index,产出整幅总图 + 每格单张(按管线号命名)+ index.md |
⚠ 出图脚本一律先新建空白文档再画(vc.new_doc())。绝不在用户当前打开的图纸上
clear_modelspace —— 那等于清空别人的成果。
⚠ 轴测图里没有"水平管线":三条主轴只有 上(90°)、北(+30°)、东(−30°)。
照平面图的习惯在 spec 里写一段水平折线,会被 regularize 吸到 30° 上、整条管被拉直。
写 pts 时必须按三轴的向量给(草图 y 向下,故北向 = 草图 y 减小)。
省掉什么(以前每样都要写一堆脚本做凸包/游程测量,几小时;现在全不用):
| 以前 | 现在 |
|---|---|
| 逐个管件像素实测尺寸(三角的底高、领结的长宽、梯形的两端宽、软管的振幅波数…) | 一律用默认值:pipe_cad.py 里所有尺寸都按 line_width 推导(lw*0.63、lw*1.79…) |
| 担心默认值会画出歪角度 | 不会:iso=True 自动归位,legal_apex / legal_pair_delta 保证每一笔都落在六合法方向上 |
| 反复调 Smith 参数直到看着像 | 不用调,出图即合规(实测:极简 spec → 7 秒出图,51/51 段 100.0% 合规,57 图元,与逐像素实测绘的完全一致) |
只保留必须精确的:位置。 折点、测点、焊口坐标仍然要用 trace_lines.py + 标定来定,
这部分不能省 —— 用户铁律第 1 条就是"位置必须和草图一致"。
极简 spec 只写三样东西:lines(折点)+ 每个管件的 x/y/ang/snap + 文字。
尺寸字段一个都不写 —— 参照 references/pipe-format.md §9 极简模板。
容器:同理,唯一省不掉的是测点标定(probe→frame→dots→calib),
其余默认 R=1000 / H=3.5R / hd=R/2,有设备档案就用档案。
标准依据(引用时照抄这 5 条,完整版见 references/standards.md)
| 我们的画法 | 可引用的出处 |
|---|---|
| 管道轴测只走三轴 + 三个断面方向 | GB/T 6567.5-2008 4.1~4.2(正等轴测投影;平行于坐标轴的管段沿轴测轴画) |
| NDT 检测段用双倍粗实线 | DB41/T 1116-2015 4.2.2.1("已检测焊缝用双倍粗实线或粗实线表示");T/SXHJ 0003-2022 4.3.5 同 |
| 焊口画实心圆点、直径取线宽 3~5 倍 | GB/T 6567.2-2008(焊点符号);HG 20519.13-92 1.0.7("环焊缝以圆点表示") |
| 管路粗线、管件/阀门细线(2:1) | GB/T 6567.5-2008 3.1;GB/T 4457.4-2002(粗:细 = 2:1);DB21/T 3485-2021 附录 B |
封头 hd = R/2 |
GB/T 25198-2023 EHA(2:1 椭圆封头,内高 = Di/4)⚠ R 必须是筒体内半径 Di/2 |
⚠ 旧编号别再用:JB/T 4730 → NB/T 47013;GB/T 20801-2020 → GB/T 20801.1-2025(2026-05-01 实施);GB/T 150.1-2011 → GB/T 150.1-2024。
⚠ 与标准不一致、但必须照草图画的(铁律第 1 条优先,改之前先问业主):
测点标准体系是"圆点 + 数字"(DB21/T 3485-2021 4.3.2.1),本厂草图画的是十字 ×;
焊缝编号标准是 A/B/C/D/E(GB/T 150.1 4.5.1),本厂记录用的是 H(环缝)/ Z(纵缝)。
一句话:从输入直接找到路径
| 你手上有什么 | 走这条路径 |
|---|---|
| 任意草图,还不知道是容器还是管道 | 先跑 classify_sketch.py(第 0 步) |
| 判为容器,测点是十字 × | measure_sketch.py 标定 → 写 spec → vessel_cad.py |
| 判为容器,测点是实心小圆点 | sketch_calib.py probe→frame→dots→calib → 写 spec → vessel_cad.py |
| 判为容器,草图 + 该草图对应的正确 CAD 出图 | 优先用 calibrate_from_ref.py 反标定(比读草图准得多) |
| 判为容器,多台要合成一张 DWG | 每台各出一份 spec → 写 layout.json → draw_grid.py |
| 判为管道,手绘单线轴测图 | trace_lines.py 提折线 → 写 spec → pipe_cad.py(见 references/pipe-format.md) |
| 判为管道,多条管要合成一张 DWG | 每条一份 spec(各写 pipe_no)→ 写 layout.json → draw_grid.py(混排容器也行) |
| 上面任一种,用户要"看到绘制过程" | 出图那步换成 record_process.py / record_grid.py |
容器草图看不出测点是 × 还是实心点?先跑 sketch_calib.py probe <图>,它会直接告诉你走哪条。
⚠ 三条前置约束(不先确认就开工,必定返工)
- 先确认能不能"看"图。
用 Read 打开草图,若返回 "the current model does not support images",
则禁止任何"我看了图觉得……"的判断——你没看到。
所有几何判断必须由脚本量化输出(probe/frame/dots/calib/inspect_texts.py/
draw_grid.verify())。这条不遵守,后面每一步都在猜。 - 优先取设备档案里的真实尺寸(通常是同目录的
.docx登记表)。
内径 / 直边高 / 长度以档案为准,草图比例只用来核对,绝不用来反推 H。
没有档案才用缺省 R=1000。 - 标定前先
probe。 实心点草图跑去用measure_sketch.py(× 专用)只会得到一堆废点,
这是本次浪费时间最多的一处试错。
容器分支工作流(最优路径,九步)
> 以下 9 步是 classify_sketch.py 判为 vessel 之后的流程。判为 pipe 请跳到下一节。
1. 拿真实尺寸
优先从设备档案取。做法通用且零依赖:
import zipfile, re
x = zipfile.ZipFile("设备档案.docx").read("word/document.xml").decode("utf8")
t = re.sub(r"<[^>]+>", "", re.sub(r"</w:tc>", "|", x)) # 单元格分隔符 → 竖线
for row in re.split(r"[|\n]{2,}", t):
if any(k in row for k in ("内径", "容积", "长度", "高度", "壁厚")):
print(row.strip()[:120])
2. 形态探测(必须先做)
python scripts/sketch_calib.py probe 草图.jpg --expect 12
输出会直接给出两种走向之一:
→ 测点形态:**实心点**→ 继续本路径(步骤 3~5)→ 测点形态:**十字 ×**→ 转measure_sketch.py,跳过 3~5
--expect 填你在草图上数出来的点个数,脚本会顺带告诉你自动抓取齐不齐。
> 不要用 × 候选数判断形态:detect_x 在实心点草图上会命中草图自身的线条交叉
> (实测某张 1098×1090 草图给出 23 个高分候选,而实际测点只有十几个)。
3. 取控制框(frame)
python scripts/sketch_calib.py frame 草图.jpg
打印列剖面(找竖向壁线/环缝)与行剖面(找横向环缝)的强峰,并出 _frame.png。
手绘壁线是斜的,控制框必须是四边形(8 个数),不能用矩形。
--frame 244,258, 666,268, 203,838.5, 660,838.5 # 四点 TL,TR,BL,BR(推荐)
--frame 157,422,170,633 # 矩形 左,右,上,下(仅当确实正交)
4. 提取测点(dots)
python scripts/sketch_calib.py dots 草图.jpg --frame "<第 3 步得到的框>"
出 _dots.png(红圈 + 编号)与 _dots.json(含 fill / ring / u / v)。
判据是实测出来的,不要改:真实测点 填充率 0.64~0.77、
孤立环带密度 ring ≈ 0、× 模板零响应;线条交叉与数字笔画的 ring 都在 0.15 以上。
召回率不是 100%:总有 1~2 个点与其它笔画粘连而抓不到。这时用 zoom 裁图放大定位:
python scripts/sketch_calib.py zoom 草图.jpg --region x0 y0 x1 y1 --z 4
5. 反解成模型坐标(calib)
python scripts/sketch_calib.py calib 草图.jpg --frame "..." --dots 草图_dots.json --orient vertical --R 1000
四点双线性反解。这一步是纯数学,结果可信(实测与手工核对的坐标差 ≤7 模型单位)。
同时会按草图比例推算出 H 或 L 并取整到 10(用 --SH 覆盖为档案里的真实值)。
6. 写 spec
字段见 references/spec-format.md,直接复制 assets/specs/ 下已核对过的实例改。
7. 出图
python scripts/vessel_cad.py spec.json # 单台
python scripts/draw_grid.py layout.json # 多台 → 一张 DWG
8. 核验(用数据,不要看缩略图)
python scripts/preview_dwg.py --out 预览.png # 1:1 预览
python scripts/inspect_texts.py # 文字包围盒,查串格/越界
draw_grid.py 跑完会自行打印 校验通过:所有图元均在各自方格内,没有这句就是有问题。
> 预览能不能信:preview_dwg.py 默认已按 AutoCAD 实测包围盒铺排文字,
> 可以直接当排版校验用;但若加了 --loose-text(按字号自行排版)就与 CAD 不一致,
> 那张图不能用来判断串格。
9. 录制过程(用户要求"看到绘制过程"时)
python scripts/record_process.py spec.json # 单台(容器/管道都走这条)
python scripts/record_grid.py layout.json # 方格合成图
远程/锁屏会话没有交互桌面,加 --no-screen 走离线渲染(详见下方管道分支第 6 步)。
管道分支工作流(最优路径,七步)
> classify_sketch.py 判为 pipe 时走这里。字段与符号详解见 references/pipe-format.md。
1. 自动提折线(不要肉眼看图读坐标)
python scripts/trace_lines.py 草图.jpg --min-area 800 --tol 2.5
→ _trace.json(像素坐标顶点)+ _trace.png(每条折线一色,端点标 E、交点标 J)。
Zhang-Suen 细化 + 骨架走链 + Douglas-Peucker 简化,零新增依赖。
上次容器草图肉眼读数错了 4 个点,机器提取不会。
2. 写 spec
照 assets/specs/example-pipe-FG0302.json 改。必填:kind:"pipe"、origin、scale、
lines;其余按草图上实际存在的符号填。
3. 空跑核对(--emit,这一步不能省)
python scripts/pipe_cad.py spec.json --emit
打印每条管线折点的 raw → iso 坐标与位移 d,以及每个图元的 snap 位移。
同一张图里若出现上百的漂移,说明 snap_to 指错了管线,回去改。这一步不出图、秒回。
4. 出图
python scripts/pipe_cad.py spec.json --new-doc
--new-doc 新建图纸,绝不动用户当前打开的图。
5. 预览核对
python scripts/preview_dwg.py --out 预览.png --dpi 150
preview_dwg.py 读的是当前活动文档(没有 --dwg 参数),所以先把要核对的图
变成 AutoCAD 的活动文档即可;默认 --out 省略时输出到文档同目录同名 .png。
与第 1 步的 trace 图排成对照,逐个图元打勾。
顺带跑一遍自动核对(强烈推荐,能抓到"方向画反"这类肉眼易漏的错):
python scripts/verify_symbols.py spec.json
它会列出 SYMBOL 层每个多边形的分类与边长——梯形/三角形一眼可辨,
并对照 spec 点名(编号有没有漏、异径管几个、安全阀该有几枚三角、锯齿几条)。
本次就是靠它发现安全阀的三角②和排放管被画到了阀体左边。
6. 录制过程
python scripts/record_process.py spec.json [--no-screen] [--delay 0.3]
产出固定写到 spec["out"] 同目录:<name>_绘制过程.gif + <name>_绘制过程_分镜.png
(没有 --gif/--story 这两个参数)。
record_process.py 已按 spec["kind"] 自动分派到 pipe_cad,不用额外开关。
取帧有两种方式,自动切换:
| 方式 | 触发条件 | 画面 |
|---|---|---|
| ① 屏幕抓帧 | 有可用的交互桌面 | 含 AutoCAD 菜单栏/命令行 |
| ② 离线渲染 | ImageGrab 报 screen grab failed(远程/锁屏/无头会话) |
只有图面(用 preview_dwg 的实体解析逐帧重绘) |
远程/无人值守时不要指望能抓到 AutoCAD 窗口,直接加 --no-screen 走离线渲染,
GIF 与分镜照样出,且画面边界与屏幕模式一致。
7. 交付前跑自检清单
见 references/pipe-format.md 第 7 节。重点四条:
- 焊口点是实心的;
- 中文没有
?; - 编号没和焊口脱节;
python audit_iso.py—— 全图每一笔落在六合法方向上,平行族唯一、偏差 0.000°。
python verify_symbols.py spec.json # 几何核对:实心点 / 梯形 / 两枚三角 / 中文?
python audit_iso.py # 方向核对:野角度 / 平行族 / 逐图层合规
管道图元速查
| 草图形态 | spec 段 | 关键点 |
|---|---|---|
| 管线主线 / 虚线续段 / 加粗段 | lines(dash_seg / bold) |
虚线是短划拼的,不用 linetype |
| 焊口 H× | welds |
实心点 + 编号,编号要 shift(w, True) |
| 现场焊口斜杠 | hatches |
60° 短斜杠横跨管线(与波纹软管是两回事) |
| 异径管(大小头) | reducers |
梯形:两条端面垂直于管轴、宽度不等;别画成三角形阀门 |
| 波纹软管 | hoses |
沿管轴来回摆动的连笔对称波形(风箱形),不是几根互不相连的斜杠;amp 只是选θ的参考值 |
| 安全阀 | safety_valves |
支管 + 两枚并排正立三角 + 自第二枚右腰 40% 处引出的排放管;不是"支管顶个箭头" |
| 闸阀/截止阀 | valves |
三角形底边骑管线、顶点垂直翘起 |
| 蝶阀 ⧖ | butterflies |
两三角形对顶 + 阀杆 + 手轮,side 控阀杆伸向 |
| 法兰 / 单横杠 | flanges / crossbars |
两道横线 vs 一道横线,别混 |
| 开口箭头 / 三角 | arrows(closed) |
Λ 开口 vs △ 闭合 |
| 方位标 上/北/东 | compass |
90° / +30° / −30° |
| 任意手绘笔画 | free |
用 strokes 分组,同样支持 snap |
⚠ 编号字母先认字,再猜图形
管道轴测图的编号是有语义的,看到一个字母就该知道那是什么件,
不要凭"它看着像个三角"就当成阀门:
| 字母 | 含义 |
|---|---|
| H | 焊口(weld joint) |
| Y | 异径管(大小头 reducer)—— 不是阀门 |
| S / D | 设备接管 / 管口编号 |
| W | 焊缝代号(一组焊口的总称) |
踩过的坑:Y1 被画成三角形闸阀 —— 实际是梯形异径管;
W1 左边的焊口被写成 M1 —— 实际是 H1;
波浪线被画成焊口斜杠 —— 实际是波纹软管;
支管顶端被画成开口箭头 —— 实际是安全阀。
轴测方向合法性(每一笔都要有空间归属)
用户原话:"轴测图是个三维的,所以要线条空间感要统一,要和方向表示一致"
轴测图是三维的:只有与方位标(上 / 北 / 东)一致的方向,读图人才知道这根线在空间里朝哪儿。
所以全图每一笔都必须落在下列六条线上(mod 180°):
| 家族 | 方向 | 含义 |
|---|---|---|
| 三轴 | 90° / 30° / −30° | 上 / 北 / 东 —— 管道实际走向 |
| 横断面 ⊥轴 | 0° / 120° / 60° | 垂直于某根轴:法兰面、单横杠、端面截面 |
这六条等价于一句话:平行于某根管轴,或垂直于某根管轴。
其余任何角度(43.78°、−47.68°、49.03° …)都读不出所属轴,看上去就是"歪的"。
为什么自定的尺寸比一定越界
符号的斜边方向不是自由参数,它由尺寸比决定:
| 符号 | 决定斜边的量 | 合法取值 |
|---|---|---|
| 阀门 / 蝶阀 / 安全阀三角 | height : base_half |
tan30° 或 tan60° |
| 异径管梯形 | (w_large − w_small) : len |
tan30° 或 tan60° |
| 波纹软管两笔 | 半波长 a、振幅 h |
h = a·tan30° 或 a·tan60° |
因为交于一点的两条边,只有轴 ±30° / 轴 ±60° 才可能同时合法
(合法方向彼此正好差 30°)。所以做法是 "先定方向,再定尺寸",
而不是"先画出来,再看看斜边歪不歪"。
具体怎么办
vessel_cad.py 里的三个工具,pipe_cad.py 的四个符号构造器已默认 iso=True 全部接上:
| 工具 | 用途 | 保什么不变 |
|---|---|---|
vc.snap_dir(deg) |
把任意角吸到最近合法方向(偏差 >0.25° 才动) | — |
vc.legal_apex(half_base, height, theta) |
三角 / 领结归位 | 腰长 |
vc.legal_pair_delta(length, dw) |
梯形归位 | 平均半宽 |
波纹软管是重写过的:给定 length 与 periods,振幅自动算
(a = length/(4·periods),h = a·tanθ,θ 由 amp 在 30°/60° 里挑更接近的一支)。
amp 不是自由参数 —— 直接拿它当偏移量,就会算出 49.03°/70.97° 的野角度(踩过)。
核验
python audit_iso.py # 豁免圆拟合短弦,按图层给野角度清单
报告要同时看三件事:
- 每段的最大偏差必须是 0.000°(不是"接近",是精确);
- 平行族必须精确到同一个角度 —— 手绘转出来的"35.1° 和 33.7° 都算北"
会让整张图糊掉,这是最隐蔽的一种"空间感不统一"; - 逐图层不合规数必须是 0(
PIPE和SYMBOL都要 √)。
⚠ 不要被 WELD 层的假警报吓到:焊口实心点是用多段线拟合的圆,
它的短弦不代表任何方向。脚本已按"闭合 + 顶点多 + 半径一致"自动豁免,别去"修"它。
铁律(违反即返工)
- 测点与草图逐点一致:数量、方位、左右关系都不得改。禁止为了"好看"均分或对齐。
- NDT 只用加粗实线:
AddLightWeightPolyline+ConstantWidth(默认 65)。
严禁波浪线、锯齿线、虚线、双线。 全图唯一的加粗处就是 NDT 段。 - 焊缝用普通细线,与轮廓同宽。虚线只用于"错开布置的隐藏纵缝",它不是 NDT。
- 封头用多段线拟合椭圆弧(40 段),不要用
AddEllipse(COM 参数格式易错)。 - 不使用
Linewidth属性(依赖线宽显示开关),一律用ConstantWidth。 - 只连接已运行的 AutoCAD 实例,绝不重复启动(会弹移植对话框)。
- 画图前先清空模型空间(倒序删除),视野用
ZoomWindow锁定,避免镜头跳动。 - 多图排版时,图形放进格子的公式必须对齐"顶边"而不是"底边"。
图形自身 y 向上,而方格的行向下延伸,居中偏移要写
oy = 格内上沿 − (可用高 − 图高)/2 − y1(用 y1)。
写成− y0会让整张图跑到格子外面去。 - 格宽不能只按图形包围盒算,必须容下标题,且标题宽度要用
GetBoundingBox()实测。
不要按「CJK 1.0 / ASCII 0.55 字宽」估算——中文 SHX 下数字与符号常是全角,
估算偏小 30%~70%,标题会直接压到邻格。 - 判断几何一律依据脚本输出,不靠看图说话(尤其当前模型读不了图时)。
- 拿到草图先跑
classify_sketch.py分流,不许凭感觉选引擎。
容器与管道的图元体系没有交集,选错引擎画出来"看着像"但每处细节都错。 - 管道出图前必须
--emit空跑一遍:打印raw → iso坐标与每个图元的 snap 位移。
这步秒回、不出图,能拦下绝大多数"图元没钉到管线上"的错误。 - 管道图先认编号字母,再认图形:
H=焊口、Y=异径管、W=焊缝、S/D=接管。
不许凭"它看着像三角形"就归类成阀门 —— 用户已就Y1(异径管而非闸阀)、
M1(应为H1)、波浪线(波纹软管而非焊口斜杠)、支管顶端(安全阀而非箭头)
四次纠正过。拿不准就先做凸包/游程测量证伪,再落 spec。 - 轴测图每一笔都必须落在六合法方向上(90/30/−30/0/120/60,mod 180)。
斜边方向由尺寸比决定,不能"先画再修角度"——必须"先定方向、再定尺寸"。
出图后必跑audit_iso.py,要求 每段偏差 0.000°、平行族唯一、逐图层不合规 0。
详见上方《轴测方向合法性》一节。⚠ 别去驯服WELD层的圆拟合短弦(假警报)。
禁止走的死路(最容易返工的 10 条,完整表见 references/pitfalls.md)
| 死路 | 为什么不行 | 改用什么 |
|---|---|---|
在用户当前打开的图纸上 clear_modelspace 出图 |
一清空就是别人的成果,不可逆 | 先 vc.new_doc(acad) 新建空白文档(draw_grid.py 默认如此) |
| 按平面图习惯在管道 spec 里写"水平"管段 | 轴测没有 0° 轴,会被吸到 30°,整条管子拉直 | pts 按三轴向量给:E=(300,173) N=(300,-173) U=(0,-280) |
| 靠肉眼读图判断几何 | 当前模型读不了图,Read 图片会被过滤 | 脚本量化输出(probe / calib / inspect_texts.py / audit_iso.py) |
用 doc.Export("BMP") 出预览/单台图 |
按视口长宽比拉伸,不是 1:1 | preview_dwg.py / export_devices.py |
| 用默认文字样式写中文 | 默认 Standard = txt.shx,没有大字体,中文全变 ??? |
建 HZ-GB(gbenor.shx + gbcbig.shx),逐文档设 StyleName |
AddHatch(...).AppendOuterLoop([pl]) 直接传 list |
静默失败不报错,实心点画成空心圈 | VARIANT(VT_ARRAY\|VT_DISPATCH, [pl]),成功后 pl.ConstantWidth = 0 |
给用了 snap 的图元写编号时用 shift(w) |
默认 dft=False,编号留在原地、焊口点却被钉走 |
编号处必须 shift(w, True) |
把 Y× 按"三角形阀门"画 |
管道编号 Y = 异径管,形态是梯形 | reducers |
| 逐管件做像素实测再定尺寸(除非业主要求复刻) | 慢,而且 iso=True 会自动归位,量了也白量 |
用默认值,直接出图 |
| 拿"看上去平行"当通过(容差 2~3°) | 35.1° 与 33.7° 都自称"北",整图视觉糊掉 | audit_iso.py 看平行族,要求偏差 0.000° |
图纸约定(速查,详解见 references/conventions.md)
| 项 | 约定 |
|---|---|
| 图层 | 容器 OUTLINE=轮廓+焊缝、NDT=加粗段、TEXT=文字、XPOINT=测点,颜色均为 7;多图排版另有 GRID=方格线;LWDISPLAY=1。管道用 PIPE / WELD / SYMBOL / TEXT |
| 线宽 | 轮廓/焊缝细线;NDT ConstantWidth = 65 |
| 字高 | 测点编号 90;焊缝标注 120;方位 110;多图格标题 240~260 |
| 测点 | 十字 × ,半臂 40 |
| 编号偏移 | 紧贴 × ,一般 60~150 单位,常用 (−115,+55) / (+60,−75) / (−100,−95) |
| 接管编号 | J1、J2…(右侧接管常用 J1) |
| 焊缝标注 | 立式:H1 下环缝、H2 纵缝;卧式:H1/H4 两端环缝、H2/H3 两条纵缝 |
| 方位箭头 | 立式 上/北;卧式 上/东(以草图为准);管道用方位标 上/北/东 |
| 管道编号 | 管线号 pipe_no 形如 L0104 / LD0201(学自既有工程图,见 references/learned-from-samples.md);焊口 H1、H2…;异径管 Y1;接管 D231/S1 |
| 封头 | hd = R/2(标准椭圆封头)——手绘草图一律把封头画圆约 1.5 倍,不要照抄 |
| 默认几何 | 立式 R=1000,H=3500(H=3.5R);卧式 R=1000,L=3870 |
| 输出 | 单台 <设备名>_检测布点图.dwg;多台由 layout.json 的 out 指定唯一文件名 |
封头深度:手绘会画圆,不要照抄
| 图 | 封头深度 / R |
|---|---|
4 草图.jpg(手绘) |
0.71 |
d120d6e…jpg 贮氨器(手绘) |
0.74 |
4 CAD.png(既有出图) |
0.47 |
| 试验图 CAD 参考 | 0.50 |
出图一律用 hd = R/2(GB/T 25198 标准椭圆封头 h = Di/4 = R/2)。
已确认的布点惯例
- 立式·上封头:编号沿封头左侧半弧从低到高排到顶部接管左侧。
- 立式·筒体:紧贴上环缝下方一排,从左壁到右壁依次编号,纵缝两侧各一点。
- 立式·侧接管 J1:4 个测点共用一条引线 + 1 个 ×,编号 2×2 环绕。
- 卧式:由 2~3 个筒节组成 → 3~4 条竖向环缝。每条端部环缝周围一组 6 个测点,
围绕"环缝 × 纵缝"交叉点布置;中间环缝两侧各 2 个。 - 编号与方位没有通用规律,完全由草图决定。本 skill 只保证"按给定坐标落点"。
卧式三条关键规律:
- 环缝 NDT 加粗段以「环缝 × 纵缝」交点为中点上下各 500 —— 不是绕轴线对称。
- 纵缝 NDT:从环缝向筒内延伸一段加粗,其余部分用细线画到下一道环缝。
- 中间筒节的纵缝与两侧错开布置 → 画成虚线,画在轴线上方的镜像高度。
虚线只表示"隐藏的另一侧焊缝",不是 NDT。
封头角度约定(易错)
- 上封头:
x = R·cosθ,y = H + hd·sinθ,θ ∈ (0°, 180°) - 下封头:
x = R·cosθ,y = −hd·sinθ,θ 同样取 (0°, 180°)
> 坑:下封头若误用 θ ∈ (180°, 360°),−hd·sinθ 会变正号,测点全部跑到封头上方。
NDT 丁字口位置由草图决定(易漏)
默认的丁字口在底部(ndt.ring_y = 0)。草图上画在顶部时必须显式指定:
"ndt": { "ring_y": 2510, "long_y0": 2190, "long_y1": 2510 } // 顶部丁字口
"ndt": { "ring_y": 0, "long_h": 760 } // 底部丁字口(缺省行为)
校验清单
通用
- [ ]
classify_sketch.py已跑过,分支选对了(容器 / 管道) - [ ] 覆盖既有 DWG 前已备份,并在回复里说明备份位置
容器
- [ ]
probe判定的形态与实际情况一致(× 还是实心点) - [ ]
calib输出的 H/R(或 L/R)与设备档案核对过 - [ ] 测点数量与草图一致;抓不到的点已用
zoom补上 - [ ] 封头上的点落在椭圆弧上
- [ ] NDT 是全图唯一加粗处,且没有波浪线
- [ ] 编号紧贴标记,无重叠、无跑出图面
- [ ] 卧式:环缝 NDT 段绕"环缝×纵缝"交点对称;错开纵缝为虚线
- [ ]
draw_grid.py打印了校验通过:所有图元均在各自方格内 - [ ] 出图后看
preview_dwg.py的 1:1 预览(默认模式)
管道(详见 references/pipe-format.md 第 7 节)
- [ ]
pipe_cad.py --emit里每个图元的 snap 位移都在合理范围 - [ ] 焊口点是实心的(预览 PNG 里确认)
- [ ] 中文没有
?(inspect_texts.py查StyleName) - [ ] 每个焊口/阀门都真的落在管线上(与 trace 核对图对照)
- [ ] 编号没和焊口点脱节(
shift(w, True)) - [ ] 蝶阀阀杆方向与草图一致(
side);法兰是两道横线不是一道
环境
Windows + 已运行的 AutoCAD(COM 接口)。
python -m pip install pywin32 # 出图必需
python -m pip install pillow numpy scipy matplotlib # 标定/预览/录制必需
python scripts/vessel_cad.py --check # 容器分支自检
python scripts/pipe_cad.py --check # 管道分支自检
常见坑
被呼叫方拒绝接收呼叫/<unknown>.Item是 AutoCAD 忙,不是代码错:
几百个图元连续创建时必然偶发,不重试整张图就废。
所有实体创建走vessel_cad.retry()与vc._ms(doc, "AddLine", ...)
(不要直接写doc.ModelSpace.AddLine(...));SaveAs/SetVariable/Regen同样要包retry。
并且创建完实体后一律再补obj.Layer = name(vc._on_layer)兜底——
doc.ActiveLayer = doc.Layers.Item(name)这个查表本身也会偶发失败。- 截图 AutoCAD 窗口前必须
ctypes.windll.user32.SetProcessDPIAware(),否则高 DPI 下坐标错位。 - 录屏前必须把窗口挪进屏幕:用
win32gui.MoveWindow(hwnd, 8, 4, W, H)并先SW_RESTORE
解除最大化(最大化状态下改不了尺寸);acad.Left/Top是只读属性。 - PIL 存 GIF 时
optimize=True会合并相邻相同帧,帧数会少于预期。 - 手绘草图的壁线是斜的,找墙要用"最左/最右的强列",不能用"最强列"(会取到墙上某一段)。
- 卧式草图的轴线是斜的,换算 y 要按 x 线性插值出该处轴线高度,不能用一个全局常数,
否则两端测点整体偏移 100~200 单位。 - matplotlib 画中文必须指定
family="Microsoft YaHei",否则出方框。 - 覆盖既有 DWG 前先备份,并在回复里说明备份位置。
参考文件
references/conventions.md—— 图纸约定、图层、线宽、字高、编号体系(容器)references/spec-format.md—— 容器 spec.json 与 layout.json 全部字段 + 标定方法 + 已核对实例references/standards.md—— 标准依据:GB/T 6567、HG 20519.13、DB41/T 1116、DB21/T 3485、GB/T 25198 等可引用条款与旧编号更正references/pitfalls.md—— 完整死路表(37 条,排查疑难杂症时再查;主文件只留 10 条)references/pipe-format.md—— 管道全流程 + 图元字典 + spec 字段 + 定位机制 + 极简模板 + §10 多条管道方格合成 + 自检清单references/learned-from-samples.md—— 从既有工程图里学到的(编号体系 D0101/L0104/W1…W20、管名格式、斜轴测 0/90/135 与我们的正等轴测之别、线宽 2:1)。换厂换项目先重跑learn_dwg.pyassets/specs/example-testfig.json—— 立式·试验图(1~14 点,J1 侧接管)assets/specs/example-1.json—— 立式·1#assets/specs/example-zhuanganqi.json—— 卧式·贮氨器(三段筒节、22 点、J1 顶部接管)assets/specs/xintianjiu/—— 多图方格合成实例(1#/2#/12# 立式、4#/贮氨器 卧式 + 图例,
3 列 × 2 行),含layout.json与1/2/12/4.jsonassets/specs/example-pipe-FG0302.json—— 管道实例:FG0302 完整 spec
(57 图元:线 40 / 文字 13 / SOLID 填充 4),含异径管Y1、波纹软管hose1、
安全阀SV1、蝶阀、法兰横线、方位标,可作管道模板assets/specs/multi-pipe/—— 多条管道方格合成实例(L0101 上→东→北 / L0102 北→上→北 /
LD0201 东→上→东 + 图例格,2 列 × 2 行),含layout.json与生成器gen.py。
实测 113 图元、77/77 段方向 100% 合规(最大偏差 0.000°)、零越界、截图 5 张
脚本一览
| 脚本 | 作用 | 依赖 |
|---|---|---|
classify_sketch.py |
第 0 步分流:判草图是容器还是管道(5/5 实测判对) | numpy scipy pillow |
trace_lines.py |
手绘单线图 → 折线矢量 + 端点/交点 + 彩色核对图(管道第 1 步) | numpy scipy pillow |
vessel_cad.py |
容器核心:按 spec 出图(立式/卧式),可作库 import;--check 自检 |
pywin32 |
pipe_cad.py |
管道核心:按 spec 出单线轴测图;--emit 空跑核对坐标 |
pywin32 |
verify_symbols.py |
出图后自动核对(几何):图层分布 / 文字含 ? / SYMBOL 多边形分类(三角/梯形)/ 焊口实心点 / 对照 spec 点名 |
pywin32 |
audit_iso.py |
出图后自动核对(方向):全图每段的轴测合法性。豁免圆拟合短弦;输出六方向分布、平行族、擦边/野角度清单、逐图层合规率。要求 偏差 0.000° 且不合规 0 | pywin32 |
sketch_calib.py |
草图标定统一入口:probe / frame / zoom / dots / calib |
numpy scipy pillow |
measure_sketch.py |
仅用于十字 × 草图的标定 | numpy scipy pillow |
calibrate_from_ref.py |
有"草图 + 对应 CAD 出图"时反标定 × 坐标(优先推荐) | numpy scipy pillow |
draw_grid.py |
多图方格合成到一张 DWG(容器/管道混排,按 kind 自动分派)+ 越界自动校验;--shots 出图后直接进截图模式;先新建空白文档、绝不碰在编图纸 |
pywin32 |
learn_dwg.py |
深度学习一份既有 CAD:图层/图元分布、全部文字(含字高/图层)、加粗段线宽体系、块参照、线方向直方图(判断它用哪套轴测轴系)、图幅与文字空间簇(判断多图布局与编号体系)。仿绘/接活前先跑它 | pywin32 |
record_grid.py |
方格合成图的分步录制(GIF + 分镜) | pillow |
record_process.py |
单台的分步录制(GIF + 分镜);按 spec["kind"] 自动分派容器/管道 |
pillow |
export_devices.py |
按单个设备导出成图:有 GRID 图层就按方格逐格切(设备名取格内字最大的标题),没有就整幅导一张;--full 可同时出一张合成总图 |
pywin32 matplotlib |
inspect_texts.py |
读回 DWG 打印文字内容/字高/包围盒 + 整图范围(查串格) | pywin32 |