做暖通施工图的人应该都有这种经历:风管系统图画完,自己检查两遍也没问题,结果一到加工交底阶段,工厂师傅一句话就把我问住了——“这根管子你要我分几节做?”我早期都是手动处理:算长度、定节距、在图中找断点、打断、补法兰标记、再编节号。一套小系统的风管就有几十根,每次交底前都得耗掉大半个晚上。
后来我写了一个 AutoCAD 风管分节插件,把整个过程压缩成两步:选中要分节的管道,输入节长和起始偏移,程序自动完成断点定位、法兰短线绘制、节号标注,顺带生成工程量清单。这篇博文我会从分节规则怎么定、算法怎么算,到 .NET API 具体代码怎么写,再到项目里踩过的几个坑,把整个插件的实现逻辑完整理一遍。适合准备自己写小工具的工程师,也适合想给插件提需求的同行参考。
1. 先把“分节”拆明白:从加工习惯到算法边界
1.1 分节到底分的是什么
风管在加工厂里是一节一节做出来的,不是一整根直接卷出来。拿最常见的镀锌钢板矩形风管来说,原材料是卷板,加工时先按周长展开下料,再通过咬口机咬合成型。卷板宽度有限,加上咬口、折边要占用尺寸,所以单节长度天然有个上限。
从图纸角度看,分节就是把一条连续的中心线(通常是一条 Polyline 或 Line)按加工要求切成若干段。但这里有个容易被忽略的关键点:分节不是简单把线等分成几段,而是要和加工工艺对齐。比如共板法兰风管,一节管两端都要翻边、装法兰角码,如果分节位置离管端太近,法兰和角码装不上,整节就废了。
这个插件的核心价值,就是把这些工艺规则变成一组可配置参数,而不是让工程师每次手工去判断。
1.2 直线段、弧线段、变径段的边界各不相同
拿到一条风管中心线,不能无脑按统一算法分。至少要先区分三种情况:
- 直线段:最常见,直接按节长等分。
- 弧线段(弯头):弯头通常单独下料,不分节。分节时要把弯头完整保留,两边的直管段重新起算。
- 变径段(渐缩管):变径管多数也单独制作,或者和相邻直管合并成一段,很少在变径中间打断。
所以分节插件的第一步,不是计算,而是识别几何边界。用 .NET API 实现时,要遍历 Polyline 的每一段,判断是 LineSegment 还是 ArcSegment,弧段直接跳过,只对直线段做等分。
弯头段还有个细节:圆弧长度要用弧长计算,不能用弦长。比如一个 90° 弯头,内弧半径 300mm,外弧半径 500mm,中心线弧长大概是 628mm,如果按弦长 400mm 处理,分节位置会整体偏移,后面标记法兰短线时方向也会错。
1.3 中心线长度不等于展开尺寸
这是新手最容易混淆的点。分节是在中心线上做等分,这个是给加工定位用的;但采购镀锌板时用的是展开面积,展开面积是周长乘以实际展开长度。
举个例子,一根 500×400 的矩形风管,中心线长度 10m,按节长 1.25m 分节能分 8 节,每节的展开面积是(500+400)*2/1000 × 1.25 = 2.25m²。这个面积计算要独立做,不能拿中心线长度直接去乘周长,因为单节之间还有咬口搭接量和法兰翻边量,别把工艺余量算进净面积。
我的做法是:分节插件只输出每节中心线的长度、起终点坐标、节号,面积统计放在单独的工程量输出模块里,避免把两个算法混在一起。
2. 分节规则定得好不好,直接决定插件好不好用
2.1 节长怎么定?先和加工厂对齐工艺
很多工程师觉得节长随便填,默认填 1.25m 就行。实际上节长的选择受好几个因素约束,不能拍脑袋。
| 影响因素 | 典型取值 | 原因 |
|---|---|---|
| 卷板宽度 | 1250mm、1500mm | 常规镀锌板卷宽 |
| 咬口损耗 | 每节减少 30~50mm | 咬口搭接占用展开宽度 |
| 法兰翻边 | 每端 20~30mm | 共板法兰需要折边 |
| 运输尺寸 | 单节不宜超过 3m | 现场搬运和吊装限制 |
| 板材厚度 | 厚板可以更长 | 强度允许,减少焊缝 |
实际项目中,直管节长常见范围在 1160~1240mm。如果加工厂用的是 1250mm 卷板,扣除咬口后做成 1200mm 左右的成品节是比较稳妥的。大管径风管用钢板拼焊时,单节可以做到 2m 甚至更长,因为不需要咬口成型,焊接反而希望节数越少越好。
我做插件时把节长设计成了可配置参数,默认 1.2m,但会在界面上提示“请与加工厂确认实际工艺节长”。这个提示很重要,我有一次按默认值分完,加工厂说他们的咬口机每节只能做 1.1m,整层返工,很痛。
2.2 起算点不能总从管口开始
从管口直接起算等分,代码最简单,但加工现场会出问题。风管两端通常要对接设备、法兰、弯头,如果分节缝正好落在接口附近,法兰就不好装。
更合理的做法是允许设置起始偏移量。偏移量一般取 300~500mm,把第一节适当缩短或加长,让分节缝避开管口区域。还有一种情况是错缝布置,相邻的两根平行风管如果分节缝在同一个横断面上,吊架不好生根,这时候要给第二条管设置不同的起始偏移,让接缝错开。
代码实现上,等分循环从offset开始,而不是从 0 开始:
for (double dist = offset; dist < totalLength - minTailLength; dist += segmentLength) { // 在 dist 位置生成断点 }起点偏移还有一个妙用:当风管端头刚好接一个弯头时,把偏移量设成弯头切点后的距离,第一节直管就能避开弯头焊缝。
2.3 分到最后剩个短尾巴怎么办
按固定节长等分,最后一段经常不够一整节。这时候不能简单把短尾巴单独作为一节,因为工厂下料是按板幅来的,为了 200mm 的一小节开一张板,浪费巨大。
我常用的策略是:
- 尾段长度小于
0.3 × 节长时,并入前一节,等于最后一节略长。比如节长 1.2m,尾段只有 0.3m,那倒数第二节做成 1.5m。 - 尾段长度在
0.3~0.8 倍节长之间,单独成节,但要在节号里加标记,方便加工时注意。 - 尾段长度大于
0.8 倍节长,重新从这个位置往前推,倒数第二节缩短,让尾段尽量接近整数节。
这里我给代码里设了一个minTailLength参数,0.3 × 节长,小于这个值就并节。实际跑下来,大部分风管系统能自动消掉短尾巴,人工二次调整的工作量小很多。
3. 在 .NET API 里落地:取长度、找断点、画标记的核心代码思路
3.1 开发环境准备
分节插件我用的 C# + AutoCAD .NET API,开发环境是 Visual Studio,引用三个核心程序集:
AcDbMgd.dll:数据库操作AcMgd.dll:命令注册、文档操作AcCoreMgd.dll:高版本提供的一些通用 API
命令注册用 CommandMethod 特性,编译成 DLL 后在 AutoCAD 里netload加载即可。有个需要注意的点:AutoCAD 每次升级,.NET Runtime 版本要求可能不一致,比如 2025 版本要求 .NET 8,生成目标平台要对应,否则加载时报错,最常见的就是“程序集初始化失败”。
3.2 主流程:选择、取长度、找断点
核心流程分四步:选择对象 → 判断类型 → 计算总长 → 按节长循环找断点。
选择对象时用 SelectionFilter 过滤掉非曲线类型:
var filter = new SelectionFilter(new[] { new TypedValue(0, "LINE,LWPOLYLINE,POLYLINE,ARC") });拿到曲线对象后,统一转成Curve基类,这样不管原来是 Line 还是 Polyline,都能用同一套方法取参数和长度:
double totalLength = curve.GetDistanceAtParameter(curve.EndParam);找断点的核心是GetPointAtDist和GetFirstDerivative两个方法。前者按距离取点,后者取该点处的切线方向。为什么一定要取切线方向?因为法兰短线必须垂直于风管中心线,而风管在弯头处是拐弯的,每个断点处的垂直方向都不一样。
Point3d point = curve.GetPointAtDist(dist); double param = curve.GetParameterAtDistance(dist); Vector3d tangent = curve.GetFirstDerivative(param).GetNormal(); Vector3d normal = tangent.GetPerpendicularVector();GetPerpendicularVector()返回的向量在 XY 平面内垂直于切线,这就是法兰短线的方向基准。
3.3 打断与保留:建议不要真把原图打断
我自己写第一版时,直接在断点处调用curve.GetSplitCurves()把 Polyline 打断成多段。功能是正常的,但用了一个月就发现新问题:打断之后,每节变成了独立图元,后续如果要调整风管走向,拖动一个顶点,旁边的节不会联动,图纸改起来特别费劲。
后来我改成两图层方案:
- 原始风管中心线保留在原来图层,不动。
- 分节标记(法兰短线、节号)画在一个独立的“风管分节”图层。
这样做有几个好处:原始图纸始终可编辑;分节结果不想要了直接删掉整个分节图层,不影响底图;节号和管线各管各的,打印时也可以选择关闭分节层。
当然,如果加工图确实需要把每节变成独立图元,也可以用GetSplitCurves实现。我这里有了教训之后都会提醒一句:真打断之前先复制一份原图,放后退图层。
3.4 画法兰短线和节号
断点位置确定后,沿着法线方向两侧偏移,画一条短线做法兰接头标记。短线的长度通常比风管边长多出 200~300mm,这样在图上能明显看出分节位置,不至于和别的管线标记混淆。
节号用 MText 放在断点旁边,插入点要稍微偏移,不能让文字压到管线。我习惯把节号的文字插入点设成point + normal * offset + Vector3D.XAxis * textOffset,让文字统一落在风管的一侧,图纸整体比较整齐。
如果要求更高一点,可以把节号做成块引用,因为块的属性值可以提取出来做统计,后面算量的时候能直接拿到每节的信息。不过块引用会增加一些开发量,前期用 MText 加唯一的句柄对应关系也能撑住。
4. 落地一定会碰到的几个“脏”情况:图层、方向与性能
4.1 图层和颜色不能写死
插件第一次做出来,我直接在代码里写死了“分节”图层,结果交付到一个团队时被打了回来。对方的所有风管都在“V-DUCT”层,出图时图层状态已经按专业设置好了,我多了一个“分节”层出来,他们每张图都要手动处理图层打印开关。
现在我的做法是:界面上允许选择分节标记的目标图层,默认沿用风管所在图层,也可以手动指定。颜色同理,不要用固定颜色,继承源对象或者按当前图层颜色随层即可。插件的职责是分节,不是改变图纸的图层体系。
4.2 法线方向反了:短线画到哪一侧
GetPerpendicularVector()有一个特性:它只保证垂直,不保证方向。同一个断点,切线方向是固定的,但垂直方向有两个,一个指向风管左侧,一个指向右侧。如果不做处理,标记短线一会画上面一会画下面,图纸非常乱。
我的规则是:统一取法线向量的 X 分量为正的方向。如果normal.X < 0,就取反。这样所有断线都朝向图纸右侧,配合节号文字统一在断线右上方,整张图看下来很整齐。如果风管本身是竖直走向,X 分量可能为 0,这时再按 Y 分量取正方向。
写的时候要考虑到各种走向的管道,不能只测水平管。我第一次只测了水平管线,交给现场后发现竖直风管全部反向,尴尬。
4.3 脏数据比算法更容易出 bug
分节算法本身并不复杂,真正让插件崩溃的是图纸里的脏数据。最典型的是:
- 重复线:同一条风管中心线画了两遍,分节时短线和节号叠在一起。
- 零长度对象:线段长度小于 0.01mm,
GetFirstDerivative直接抛异常。 - 自相交 Polyline:分节点在交点附近,方向向量突变。
我处理这些问题的策略是,在分节前先做一次数据体检:
遇到零长度对象直接跳过并记录;重复线提示用户先执行 OVERKILL 清理;自相交对象给出警告但不中断,把该段排除出分节范围,让用户手工处理。
软件工具的稳定性不在算法复杂,而在边界情况的处理。我后来的每个插件都先统计图纸里有多少“异常对象”,再决定是否继续。
4.4 大批量分节时的性能优化
一次选中整层几十条风管,分下来可能有几千节,生成的短线、文字就上万了。如果每个图元都单独开一个事务提交,AutoCAD 会明显卡顿。
我实测过一组数据:某通风项目里一次处理约 3000 节,生成大约 2 万个图元。第一版每生成一个图元就Commit一次,耗时 20 多秒;改成整个命令一个事务,图元全部加入同一事务后统一提交,耗时降到 2 秒左右。
using (Transaction tr = db.TransactionManager.StartTransaction()) { // 循环生成所有短线、节号 tr.Commit(); }还有一个性能技巧:循环中不要频繁调用ed.WriteMessage输出进度,写个 500 条中间刷一次就够了,频繁刷新 UI 也会吃掉不少时间。
5. 分节之后:编号、工程量统计与图纸变更
5.1 节号不要用流水号
一开始我用的是 1、2、3 这种流水号,现场反馈根本对不上。一节一节的管子在图上没有规律,工人拿着加工单对着图纸找“第 47 节”,找半天。
现在用“系统-管段-节号”三层结构,比如F-101-03,意思是 F 系统、第 101 根管、第 3 节。配合图层里另外写一套管段编号,工人在图上可以按系统筛选、按管段定位、再按节号下料,效率高很多。
如果想要更稳一点,把编号写成属性附加到分节短线上,后期用属性提取导出到 Excel,数据就不会因为文字被移动而错乱。我在插件里用的是扩展数据方式,把SYSTEM_ID、DUCT_ID、SECTION_NO都存在扩展数据里,统计时通过 API 读取。
5.2 工程量统计:把每节变成一条数据
有了节号,下一步就是统计。每节至少需要记录:
- 节号
- 所属系统和管段
- 中心线长度
- 断面宽高(从关联的风管标注或图层属性读取)
- 周长
- 展开面积
面积公式统一为2 × (宽 + 高) × 长度。这里要特别说明,算出来的面积是理论净面积,不含咬口和法兰翻边量。做材料采购时,建议乘以 1.05~1.1 的损耗系数,这个系数每个加工厂不一样。
统计输出我的做法直接生成 tsv 文件,Excel 能直接打开,也可以导入到表格控件。如果想让结果直接显示在图纸里,用 AutoCAD 自带的 Table 对象,把数据逐行写入单元格,效果也不错,就是代码稍微多一点。
5.3 图纸变更之后的重跑策略
施工图极少有不改的。改一次风管走向,之前的所有节号都得重新刷。每次都手动删旧标记再重跑,很痛苦。
我的处理方案是:每次运行分节命令前,先检查目标图层里有没有旧的分节标记,如果有,询问用户是否删除后重新生成。并且比较关键的一点,重跑之后要保持编号规则不变,同一根管子在修改后尽量不要改变管段号,否则现场拿着旧加工单对不上。
还有个小原则:分节标记不要手动去改。哪怕你只是想把一个节号往前挪一点,都建议重新编辑管段后再跑一次分节。手工改多了,编号逻辑就会乱,后面统计出来的数据也没法追溯。
5.4 可以继续扩展的方向
分节插件解决的只是“一段线分成多段线”的问题,往上走还有几个方向:
- 自动生成弯头展开图:从中心线圆弧段提取参数,直接展开成矩形板材下料图。
- 三维风管模型分节:基于 Solids 或 3D Polyline 做分节,配合 BIM 出图。
- BOM 自动归类:同一规格、同一长度的节归并,形成批量下料清单。
- PDF 分节图自动打印:按加工单逐节插图框、打印。
我自己目前已经做了前两个扩展方向,最实用的还是 BOM 归并,加工厂拿到的不再是一张几千条的清单,而是“800×400 规格、1.2m 节长、共 45 节”,采购和排产都轻松很多。
最后再说一句经验:分节插件本质上就是个参数化工具,算法不复杂,复杂的是让它在真实图纸上稳定工作。只要风管中心线画得干净规范、图层统一、没有重复线,插件跑起来基本不会出问题。这也是做 AutoCAD 二次开发最值得投入的部分——让工具适应工程师的习惯,而不是反过来让工程师迁就工具。