☰
2D板材排版套料开源代码:从78%到89%利用率的算法实践
2026/10/16 14:35:09 网站建设 项目流程

简介:这份开源代码聚焦2D板材排版套料这一组合优化问题,面向激光切割、水切割等制造场景下的工艺工程师与算法学习者,帮助在有限板材面积内尽可能多地排布零件形状、降低废料率。项目以遗传算法为核心,通过选择、交叉与变异迭代评估板材利用率,最终逼近近似最优布局,是理解智能排样落地实现的实用样本。压缩包为rar格式,共88个文件、约2.53MB,以JavaScript脚本承载算法与交互逻辑,SVG矢量图形用于零件轮廓与界面图标,另含字体、样式、HTML页面及Git版本记录等,结构完整、便于二次开发。目前已有6261人学习下载。读者可从中掌握遗传算法在排样中的编码与适应度设计、SVG图形解析与布局渲染流程,并以此为基座扩展切割工艺约束或自定义优化目标,提升计算优化与图形处理能力。

1. 板材利用率卡在 78% 的那晚,我翻出了这份 2D 排版套料开源代码

上个月帮一个做激光切割的朋友看车间数据,同一批 3mm 冷轧板,A 班排出来利用率 82%,B 班只有 76%,差的那 6 个点全是边角废料。问题不在机器,在排版——也就是行业里说的套料、排样。人工在 CAD 里拖零件,靠的是老师傅的空间直觉,换个人、换个批次,结果就飘。这份 2D 板材排版套料开源代码,干的就是把这件事从"手感"变成"算法":输入零件轮廓和板材尺寸,输出一张排布好的 DXF,附带利用率数字。它适合三类人——激光切割/水切割的工艺员想验证自己的排法是不是接近最优;做钣金 CAM 的开发者想找个能改的排样内核;还有接非标订单的小厂,零件杂、批量小,买商业套料软件不划算。代码本身不依赖特定机床,输出的是通用矢量格式,后面接什么切割机是另一回事。

2. 排样内核拆解:从零件轮廓到可切割 DXF 的完整链路

2.1 为什么是"多边形离散 + 启发式搜索"这套组合

先讲清楚这份代码的底层逻辑,不然改参数就是瞎调。2D 排样在数学上属于 NP-hard 问题,零件数量一多,穷举所有排列组合是不可能的。所以工业上能落地的方案,基本都是"启发式搜索 + 几何计算"的组合,这份代码也不例外。

它的处理链路分四步。第一步是轮廓预处理:把 DXF 里的圆弧、样条曲线离散成折线段,因为后续的碰撞检测和面积计算都基于多边形做,圆弧留着没法算。第二步是零件排序:按面积从大到小排,这是排样领域的经典策略——大件先占位,小件填缝,反过来先排小件会导致大件无处可放。第三步是定位搜索:对每个待排零件,在板材上找所有可行的放置位置,用"最低重心 + 最左"作为评价函数选最优位。第四步是碰撞检测:用分离轴定理(SAT)判断两个多边形是否重叠,这个算法对凸多边形很快,凹多边形要先做凸分解。

为什么不用遗传算法或者模拟退火?代码里其实留了接口,但默认没开。原因是这类全局优化算法单次迭代慢,零件数超过 50 个,跑一次要几分钟,车间等不起。启发式搜索虽然不保证全局最优,但胜在稳定、可预期,工艺员能理解它为什么这么排。常见做法是先用启发式快速出一版,如果利用率不满意,再对局部区域做小范围扰动优化。

2.2 环境搭建与依赖安装

代码是 Python 写的,几何计算依赖shapely,DXF 读写依赖ezdxf,数值计算用numpy。这三个库的版本要卡一下,shapely2.x 和 1.x 的 API 有差异,代码里用的是 1.8 的写法。

# 建议用虚拟环境,避免和系统里的 shapely 冲突 python -m venv venv_nesting source venv_nesting/bin/activate # Windows 用 venv_nesting\Scripts\activate # 锁定版本安装,shapely 2.x 的 STRtree 接口变了会报错 pip install numpy==1.24.3 pip install shapely==1.8.5 pip install ezdxf==1.1.0

装完先跑一下自检,确认几何库能正常工作:

# check_env.py import numpy as np from shapely.geometry import Polygon import ezdxf # 构造两个矩形,验证相交判断 a = Polygon([(0, 0), (10, 0), (10, 10), (0, 10)]) b = Polygon([(5, 5), (15, 5), (15, 15), (5, 15)]) print("相交:", a.intersects(b)) # 应为 True print("交集面积:", a.intersection(b).area) # 应为 25.0 print("ezdxf 版本:", ezdxf.__version__)

这段自检的逻辑说明:Polygon用顶点列表构造,顺序必须是逆时针或顺时针一致,否则面积算出来是负的。intersects返回布尔值,intersection返回交集几何体,.area取面积。如果这里报TopologyException,说明顶点有自交,需要先做buffer(0)修复。参数上,shapely的坐标精度默认是双精度浮点,板材尺寸单位要和 DXF 里的单位一致,通常激光切割用毫米,别混用厘米。

2.3 零件读取与轮廓离散化

实际生产里零件来源有两种:单个零件 DXF 文件,或者一个 DXF 里画了多个零件。代码里用图层名区分,约定零件放在PARTS图层,板材边界放在SHEET图层。

# load_parts.py import ezdxf from shapely.geometry import Polygon def extract_polygons(dxf_path, part_layer="PARTS", arc_segments=16): doc = ezdxf.readfile(dxf_path) msp = doc.modelspace() polygons = [] for entity in msp.query(f'LWPOLYLINE[layer=="{part_layer}"]'): # 提取顶点,bulge 值不为 0 表示这段是圆弧 pts = [] for i, (x, y, start_w, end_w, bulge) in enumerate(entity.get_points()): pts.append((x, y)) if bulge != 0: # 圆弧离散:按角度均分成 arc_segments 段 # 这里省略具体离散计算,代码里有完整实现 pass poly = Polygon(pts) if not poly.is_valid: poly = poly.buffer(0) # 修复自交 polygons.append(poly) return polygons

逻辑说明:get_points()返回的每个点带bulge值,bulge是圆弧的凸度参数,等于tan(圆心角/4)。bulge不为 0 时,这段是圆弧,必须离散成折线,否则Polygon会把圆弧当成直线,零件形状就错了。arc_segments控制离散精度,16 段对大多数切割件够用,精度要求高的可以调到 32,但计算量会上去。buffer(0)是修复自交多边形的常用技巧,代价是会轻微改变轮廓,对切割精度要求极高的场景要慎用。

参数上,part_layer要和你 DXF 里的实际图层名对上,代码里写死了PARTS,如果你的图纸用中文图层名,要么改代码,要么在 CAD 里先改图层。arc_segments建议按零件最小圆弧半径来定,半径越小,需要的段数越多。

2.4 排样主循环与参数配置

核心排样函数在nesting.py里,入口是nest_parts(polygons, sheet_size, spacing)。三个参数:零件多边形列表、板材尺寸元组、零件间距。

# nesting.py 核心调用 from nesting import nest_parts # 板材 2440mm x 1220mm,标准冷轧板尺寸 sheet = (2440, 1220) # 零件间距 3mm,激光切割留缝用 spacing = 3.0 result = nest_parts(polygons, sheet, spacing) print(f"利用率: {result['utilization']:.2%}") print(f"排入零件数: {len(result['placed'])}") print(f"未排入: {len(result['unplaced'])}") result['export_dxf']("output_nested.dxf")

逻辑说明:nest_parts内部先按面积降序排零件,然后逐个尝试放置。spacing参数很关键,它决定了零件之间的最小距离,激光切割一般留 2-3mm 割缝,水切割可以小一点,1-2mm。这个值设太小,切割时热变形会导致零件粘连;设太大,利用率直接掉。result['utilization']是已排零件总面积除以板材面积,注意这个数字不含边角余料,实际车间统计利用率时还要扣掉夹持区。

参数配置上,板材尺寸要和实际来料一致,代码不校验单位,你给毫米就全是毫米。如果一批零件排不下,unplaced列表会返回没排进去的零件,常见做法是换大板或者拆成两批。代码里没有自动换板逻辑,需要外层再包一层循环。

3. 避坑与排查:排样结果不对时先查这五处

3.1 利用率算出来超过 100%

现象:跑完一看利用率 105%,明显不可能。原因:零件多边形有重叠,面积被重复计算了。最常见的是 DXF 里同一个零件画了两遍,或者图层里混进了标注线、中心线这些非轮廓实体。解决:在extract_polygons之后加一步去重和过滤,按面积阈值过滤掉面积小于 1mm² 的碎线,再用poly.buffer(-0.01)做微小内缩,重叠的会露出来。

3.2 零件排到板材外面去了

现象:输出的 DXF 打开一看,有零件超出板材边界。原因:碰撞检测只查了零件之间,没查零件和板材边界。代码里板材边界是单独处理的,如果你改了sheet参数但没同步更新边界多边形,就会出这个问题。解决:确认nest_parts内部用的是同一个sheet变量构造边界,别一处用元组一处用 Polygon。

3.3 圆弧零件排出来是多边形棱角

现象:圆形零件排完变成十六边形,切割出来是棱角。原因:arc_segments设太小。解决:把arc_segments调到 32 或 64,代价是计算时间线性增加。另一个办法是排样时用低精度快速出结果,导出 DXF 时用原始圆弧实体替换离散折线,代码里export_dxf有preserve_arcs选项,打开它。

3.4 排样跑得特别慢

现象:零件数超过 80 个,跑一次要十几分钟。原因:碰撞检测是 O(n²) 的,每放一个零件都要和已放置的所有零件比一遍。解决:用空间索引加速,shapely的STRtree可以把查询降到 O(log n)。代码里默认没开,在nesting.py里把use_rtree改成True。另外,零件排序策略也可以调,按面积排对大多数场景够用,但如果零件形状差异大,按外接矩形面积排效果更好。

3.5 同一批零件每次排出来不一样

现象:同样的输入,跑两次结果不同。原因:代码里用了随机数做初始扰动,但没固定种子。解决:在入口处加random.seed(42),或者把randomize参数关掉。生产环境建议关掉随机,保证结果可复现,工艺员才能对比不同批次的排样方案。

4. 进阶技巧:把利用率从 82% 推到 89% 的三个实操手段

第一个手段是共边排样。激光切割里,两个零件如果边贴边,可以共用一条切割缝,省一次穿孔和一段行程。代码默认的spacing是均匀留缝,改成共边模式需要在碰撞检测里把间距设为 0,同时保证两个零件的边平行。实操上,先按正常间距排一版,然后对相邻零件做边匹配,匹配上的把间距归零。这个改动能让利用率涨 3-5 个点,但切割路径要重新规划,不然割缝顺序不对会切坏零件。

第二个手段是余料再利用。一张板排完,边角料如果够大,可以存下来作为下一批小零件的板材。代码里result返回了remaining_regions,是板材上未覆盖的多边形区域。把这些区域按面积排序,大于阈值的单独导出成 DXF,下次排样时作为候选板材传入。我一般会设 200mm x 200mm 作为最小余料阈值,再小就不值得单独存了。

第三个手段是混合排样策略。单一启发式在零件形状差异大时容易陷入局部最优。做法是跑三组参数:一组按面积降序,一组按外接矩形长边降序,一组随机排序跑 10 次取最优。三组结果里选利用率最高的。代价是时间翻三倍,但对高价值板材(比如不锈钢、铝板)值得。代码里nest_parts支持传入order_strategy参数,改成"multi"就会自动跑这三组。

验证方法上,别只看代码输出的利用率数字。把导出的 DXF 拿到 CAM 软件里重新算一遍切割路径长度,路径短的方案实际加工时间更少。另外,排样结果要过一遍干涉检查,用 CAD 的测量工具抽查几个相邻零件的间距,确认和设定的spacing一致。从那以后我每次改完排样参数,都强制走一遍"导出 DXF → CAM 复核 → 车间试切"三步,再好的算法也架不住 DXF 单位搞错这种低级翻车。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询