2D Nesting排样零件CSV文件:从字段设计到避坑指南

发布时间:2026/10/3 16:06:01
2D Nesting排样零件CSV文件:从字段设计到避坑指南 1. 2D Nesting 排样到底在解决什么问题做钣金加工、激光切割、 CNC 铣削或者家具板材开料的朋友对 2D Nesting二维排样/套料一定不陌生。说得直白点就是给定一堆形状各异的零件要求把它们尽量紧密地摆放在一张固定尺寸的板材上让边角料最少、材料利用率最高。这不是一个拍脑袋就能解决的问题——同一批零件摆放方式不同可能一张板能装下换一种排法就要多开两张板成本差距立刻显现。我最早接触这个概念是在做激光切割的工艺排料时。当时接到一批订单几十种不同尺寸的矩形件加异形件要在 1220×2440 的标准板上排出来。刚开始用 CAD 手动摆一块板一块板地对图脑子完全不够用尤其零件数量多、角度还不固定时手工排料的效率低到令人崩溃。后来引入自动排样工具核心输入就是一份描述所有零件几何信息和数量的文件——最常见的格式就是 CSV。CSV 之所以受欢迎是因为它足够简单。纯文本、每行一条记录、字段用逗号分隔任何语言都能读取甚至用 Excel 打开也能直接编辑。对于排样软件来说CSV 文件其实就是“零件订单”的数字化表达告诉软件有哪些零件、每个零件什么形状、需要几个、材质和厚度是什么。文件里数据规范不规范直接决定后续自动排样能不能跑通、跑得好。这篇文章就围绕“如何定义一份合格的零件数据 CSV”来展开。你会看到字段怎么设计、坐标系怎么约定、单位怎么统一以及规避开源排样工具里那些“看着没问题但一跑就报错”的坑。顺便预告一个很多人都会踩的问题明明给的是 CSV软件却提示 “the supplied data appears to be in the ole2 format. you are calling the part”这种报错十有八九不是排样算法的问题而是文件本身被 Excel 偷偷改了格式。2. 零件数据 CSV 的字段设计与核心约定2.1 一个最小可用的 CSV 应该包含什么先说我自己的经验结论一个能让排样工具正常工作的零件 CSV不需要一开始就设计得很复杂但核心几何字段必须齐全。以目前主流开源排样库比如深蓝的 nesting 库、SVG Nest、以及各类基于 Python 的排样实现的通用约定为例最少需要这几列字段名含义说明示例值是否必填part_id零件唯一标识P001建议quantity需要排样的数量12必填width外接矩形宽度单位与板材一致120.5必填height外接矩形高度单位与板材一致80必填shape_type零件形状类型rectangle选填material材质描述steel_q235选填thickness板材厚度2.0建议angle允许旋转的角度增量0/90/180/270选填看到这里你可能会问宽度高度只能描述矩形件异形件怎么办答案是这样对于 2D 排样中的异形件最通用的做法不是直接在 CSV 里写复杂轮廓坐标而是通过“外接矩形 轮廓文件路径”的方式提供。也就是说CSV 记录零件的外接矩形尺寸用于快速粗排和边界计算真正的轮廓形状保存在独立的 CAD 文件如 DXF中在排样软件里把两者关联起来。如果排样工具支持直接在 CSV 里内嵌轮廓多边形坐标那么可以增加两个字段points 和 tolerance。points 的格式一般是坐标对列表比如 [(0,0),(100,0),(100,50),(50,50),(50,80),(0,80)]表示零件轮廓端点坐标依次连接形成的封闭多边形。tolerance 表示轮廓拟合的精度控制导入时对曲线的离散化程度值越小轮廓越精细但计算量越大。我一般取 0.05mm 到 0.1mm 之间切割场景下足够平滑又不至于让顶点数量爆炸。2.2 单位、坐标系和旋转规则必须统一单位不统一是 CSV 定义里最阴间的坑。有人在 CSV 里写毫米有人在 DXF 里画的是英寸排样工具按照同一个毫米数值处理最后切割出来的零件尺寸差了 25.4 倍。这个错误放到生产上就是直接批量报废。所以我的建议是在 CSV 的头部用注释行或者单独一个字段声明单位比如unitmm或者# unit: mm。虽然标准 CSV 没有官方注释行的说法但大多数排样工具会忽略以#开头的行或者通过读取第一行元数据来识别。如果工具不识别注释那就专门设一个unit列每条记录都填mm物理上冗余但能剁掉单位转换的隐患。坐标系约定同样关键。排样软件通常把板材左下角作为坐标原点 (0,0)X 轴向右、Y 轴向上。而 CAD 图纸的坐标系不一定如此——有些 DXF 从 AutoCAD 导出后坐标系乱七八糟甚至有人直接在模型空间里把图纸画得离原点十万八千里。这份 CSV 里所有零件坐标都应该基于统一的全局坐标系否则排样时零件会飞出板材边界。实操中的解决办法在生成 CSV 前先对 DXF 做一次“移动到原点”的批量操作确保所有零件轮廓的最小外包框左下方贴着坐标原点。写代码时也可以用一行 Python 把坐标偏移统一归零后面我会给一个参考脚本。旋转规则也是定义文件时容易被忽视的点。2D 排样的本质就是通过旋转和移动零件来优化布局。如果某些零件因为纹理方向、材料轧制方向、甚至印刷图案方向不允许旋转或者只允许 90° 倍数旋转CSV 里必须记录清楚。常见做法是rotation_rule字段值可以是free任意角度、orthogonal仅 0/90/180/270、none不许旋转。如果你不写程序默认按 free 处理一旦木材有纹理方向却按任意角度排了切出来的工件表面效果完全没法接受。2.3 零件编号与批量数据的组织方式工业场景下零件种类多、数量大CSV 文件动辄几千行。这时候零件编号规范就特别重要。我建议采用“系列流水号”的方式比如BRACKET-A-001、PLATE-90X40-002这样排完后生成报表时每个零件都能快速追溯到源数据和图纸。这里还有一个批量组织的小技巧如果有多个不同厚度的零件不要混合在一个 CSV 里。排样软件通常一次处理一种厚度的材料混着写会让工具要么忽略 thickness 字段要么把它当成分组条件但不同工具的行为不一致容易出问题。更稳妥的做法是“一份 CSV 一种板材规格 一种材质厚度”例如parts_2mm_steel.csv、parts_3mm_aluminum.csv分得清清楚楚。哪怕工具支持多厚度混排我也不会这么做因为切割参数、引线补偿、共边切割策略都跟厚度强相关混在一起后续处理会很麻烦。3. 从零件 CSV 到排样结果的完整流程3.1 数据准备阶段的三个关键动作真正进入排样算法前数据准备阶段往往决定了整个流程的天花板。我总结出三个关键动作每个都能让你少走大量弯路。第一个动作是清洗 CSV。别以为从 ERP 导出的数据就能直接用。我碰过太多次数量字段里带空格、材料列里有换行符、宽度高度填了中文全角逗号的情况。解析 CSV 的时候一旦某个字段解析类型失败整行数据可能被静默跳过最后排出来的零件数量不对你根本察觉不到。所以写完 CSV 后第一件事就是写个小脚本做数据校验import csv import sys required_fields {part_id, quantity, width, height} with open(parts.csv, r, encodingutf-8) as f: reader csv.DictReader(f) rows list(reader) for i, row in enumerate(rows, start2): missing required_fields - set(row.keys()) if missing: print(f第 {i} 行缺少字段: {missing}) sys.exit(1) try: qty int(row[quantity]) w float(row[width]) h float(row[height]) except ValueError as e: print(f第 {i} 行存在非数字数据: {e}) sys.exit(1) if qty 0 or w 0 or h 0: print(f第 {i} 行数据必须为正数) sys.exit(1) total_parts sum(int(r[quantity]) for r in rows) print(f校验通过零件总数为: {total_parts})这段脚本每次换新 CSV 都跑一遍不然后续排完发现数量对不上返工成本远高于写脚本的那几分钟。第二个动作是坐标归一化。很多开源排样库要求零件轮廓在导入前移动过否则旋转计算时中心点会跑偏。我一般直接用 Python 做一次批量处理读取 DXF 里所有多段线和圆弧算出整体最小外包框把外包框左下角平移到原点。这样无论原图在什么位置归一化后所有零件都规规矩矩贴原点排列。第三个动作是重复零件去重。如果有 1000 个完全相同的零件排样算法其实只需要排一个“代表零件”然后乘以数量即可不需要把 1000 个一模一样的外接矩形全部塞进算法里。去重后计算量大幅下降尤其是异形件轮廓参与精确碰撞检测时这个优化能省出不少时间。CSV 里把同种零件合并成一行、数量累加效果一样但数据体积缩小好几倍。3.2 把 CSV 数据喂给排样引擎的代码示例不同的排样引擎 API 不一样但思路是共通的。下面以 Python 中比较常见的 nest 库为例展示标准的接入过程。这是一个基于矩形包络和遗传算法的嵌套库对 CSV 输入的支持非常直观import pandas as pd from shapely.geometry import Polygon from shapely.affinity import rotate, translate # 从 CSV 读取零件数据 df pd.read_csv(parts.csv) parts [] for _, row in df.iterrows(): pid row[part_id] qty int(row[quantity]) w float(row[width]) h float(row[height]) for _ in range(qty): # 用外接矩形创建初始几何体更精确的场景下从 DXF 加载轮廓 rect Polygon([(0, 0), (w, 0), (w, h), (0, h)]) parts.append({ id: pid, geometry: rect, width: w, height: h, quantity: qty }) # 传给排样引擎前先按面积降序排列 parts.sort(keylambda p: p[geometry].area, reverseTrue) print(f共加载 {len(parts)} 个零件实例)需要说明的是这段代码只是把 CSV 变成排样引擎需要的数据结构。实际的排样过程涉及矩形碰撞检测、旋转搜索、启发式布局等一系列复杂计算最终输出的是一组“零件多边形 摆放位置 旋转角度”的组合。把这些结果导出成新的 CSV 时我建议至少包含这几列输出字段说明part_id零件编号bin_index第几块板x零件左下角的 X 坐标y零件左下角的 Y 坐标rotation最终旋转角度quantity_placed该零件已排放数量有了输出 CSV就可以用 Python 的 matplotlib 画排样预览图或者直接转成 DXF 下发到切割机。整个流程从读入到出图核心就是把 CSV 当成零件的唯一事实来源所有下游环节都围绕这份文件展开。3.3 材料利用率的计算方法和判断标准排样排得好不好有一个硬指标叫材料利用率material utilization rate公式很简单[ 利用率 \frac{所有零件的实际面积总和}{板材总面积} \times 100% ]注意这里的面积是零件真实轮廓的面积而不是外接矩形的面积。用外接矩形算出来的数字比真实值高不少会自我安慰到失去改进动力。举例来说一块 1220×2440 的板总面积 2.9768 平方米。如果排了 10 个零件每个零件真实面积是 0.12 平方米那真实利用面积是 1.2 平方米利用率就是 40.3%。而如果用外接矩形算可能每个外接矩形是 0.15 平方米算出来 50.4%差了整整 10 个百分点。实际生产中钣金切割的利用率通常在 65%-85% 之间。低于 65% 说明排样方案有较大优化空间高于 85% 说明这批零件形状规整且排样策略得当很难再挤。如果零件里含大量圆形利用率会低一些因为圆与圆之间天然存在空隙如果是矩形件理论上可以做 100% 铺满但考虑切割缝隙kerf和零件间距实际也到不了。所以判断标准要结合零件形状来定盲盯一个数字没有意义。提高利用率的一些常见手段包括允许零件旋转、引入共边切割两个零件共用同一条切割路径省出切缝距离、把异形件两两配对互补排列。这些策略都可以在 CSV 的字段设计阶段预留接口来支持比如增加pair_group字段让两个零件进入同一个配对组参与排样。4. 定义零件 CSV 时容易踩的坑与排查技巧4.1 OLE2 格式报错的真相与修复流程文章开头提到过那个让人头大的报错“the supplied data appears to be in the ole2 format. you are calling the part”。这个报错表面上像是软件在抱怨 CSV 里的数据格式但真相往往藏在文件本身。先解释 OLE2 是什么它是一种复合文档二进制格式Microsoft Office 系列包括 Excel默认保存的.xls文件就是 OLE2 格式。而 CSV 原本应该是纯文本。那么问题来了你明明给的是 CSV为什么会变成 OLE2最常见的原因是你在 Excel 里编辑了一个 CSV 文件然后直接点保存。Excel 的“另存为 CSV”其实有各种小脾气如果你不仔细选择“CSV UTF-8逗号分隔”这个保存类型——尤其是某些版本的 Excel 默认保存成.xls或者“带格式的 CSV”那后缀虽然是.csv但文件内部已经是 OLE2 二进制结构了。排样程序用纯文本方式解析时读到文件头是二进制魔数就会直接抛出这个提示而不会进一步去读取数据。碰到这个问题修复流程比想象中简单。第一步用任何一款纯文本编辑器记事本、VS Code、Notepad打开那个 CSV。如果能正常打开看到逗号分隔的文本说明文件本身没问题。如果打开全是乱码或者连编辑器都无法识别说明它确实是二进制格式。第二步不要直接在 Excel 里修改保存而是用文本编辑器打开后另存为纯文本 CSV。或者回到 Excel选择“另存为”文件类型明确选“CSV UTF-8”不要选“Excel 工作簿”。第三步保存后再用文本编辑器打开验证一次确保文件头是可读的文本而不是乱码再交给排样程序。还有一个顺便沾边的坑编码问题。CSV 用 Excel 保存时默认是 ANSI 编码如果里面有中文零件名其他程序按 UTF-8 读取就会出现乱码或者解析失败。现在我的习惯是所有 CSV 一律保存为 UTF-8 不带 BOM 的格式。带 BOM 的话有些工具会把\ufeff当做第一个字段名的一部分导致列名匹配不上排样软件读到part_id字段时提示缺失。4.2 数据解析类问题的系统排查方法除了 OLE2 这个“硬错误”实际项目里更常见的是“软错误”——解析能过但结果不对。我整理过一套排查清单按顺序检查基本能定位 90% 的问题第一检查表头是否完全匹配。排样软件通常规定必须包含part_id,quantity,width,height这些字段名大小写是否敏感、是否允许空格每种工具都不同。最狠的坑是从 Excel 导出的 CSV 表头可能自动带了隐藏空格比如width这种程序如果按精确字符串匹配就识别不了。用代码检查时把字段名都 strip 一下即可new_headers [h.strip() for h in reader.fieldnames]第二检查空行和空字段。CSV 允许行与行之间有空行但有些排样工具不处理空行直接尝试解析就会报越界或者类型错误。我处理的方式是读取时跳过空白行with open(parts.csv, r) as f: for line in f: line line.strip() if not line or line.startswith(#): continue # 继续解析第三检查逗号冲突。如果零件名称或备注里包含英文逗号就会把一行拆成多列导致列数错位。解决方式有三个给字段值加引号、避免在名称中用逗号、或者切割时用csv.reader而不是简单split(,)。csv库的标准解析器能正确处理带引号字段所以我在生产环境永远用标准库而不自己写分割逻辑。第四检查数量与几何是否匹配。此类问题最隐蔽。举例某个零件在 CSV 里quantity0解析不报错但排样结果里看不到它或者某个零件 width 填的是实际长度的两倍排样结果会多出大片空白区域但又不报错。我的经验是写完 CSV 后先用脚本画一个简单的分布图把所有零件的外接矩形按比例画出来肉眼扫一遍有没有异常尺寸比直接丢进排样引擎高效得多。4.3 关于 CSV 格式细节的四个补充建议第一个补充建议是表头行统一使用英文命名。虽然中文字段名在本地单机使用没问题但一旦涉及跨平台、跨软件传输编码稍微一乱就是灾难。固定字段统一英文备注类信息可以放中文至少解析逻辑稳定。第二个建议是数值精度要有意识控制。排样算法对浮点数精度敏感宽度高度写 120.500000000001 和写 120.5 在视觉上没区别但在碰撞检测的浮点比较里就可能差出 0.000000001 的误差导致两个零件判定为“轻微重叠”。我一般统一保留三位小数既保证精度又不至于让文件体积变大。第三个建议是每份 CSV 都配一个 README 或者元数据块。把单位、坐标系约定、板材尺寸、设计者、版本号写清楚。一份零件数据文件可能会在不同部门之间流传两周后你自己回来改数据都未必记得当初的约定更别说别人接手了。第四个建议是零件很多时把 CSV 按零件类型拆分缩小数据规模。一次性导入几万行 CSV排样引擎会在初始排序和碰撞检测阶段花费大量时间。拆成多份后逐份排样、最后拼板可以显著缩短计算时间而且可以利用多线程并行处理。某些排样任务从单线程跑 30 分钟缩短到并行跑 5 分钟是非常可观的效率提升。5. 实操记录一份真实零件 CSV 的生成与排样跑通5.1 从 CAD 图纸到 CSV 的批量转换讲再多理论不如看一次完整的实操。我接过的某个小批量加工订单零件种类约 20 种总共 480 件材质是 2mm 冷轧钢板板材规格 1500×3000。源文件是 AutoCAD 导出的 DXF每个零件一个图层。下面这段脚本是我当时用来把 DXF 里的图元提取为零件数据并生成 CSV 的简化版本import ezdxf import csv from shapely.geometry import Polygon from shapely.ops import unary_union doc ezdxf.readfile(parts_source.dxf) msp doc.modelspace() parts [] for entity in msp: if entity.dxftype() LWPOLYLINE: points [(p[0], p[1]) for p in entity.get_points()] if len(points) 3: continue poly Polygon(points) if not poly.is_valid: poly poly.buffer(0) # 计算外接矩形尺寸 minx, miny, maxx, maxy poly.bounds w round(maxx - minx, 3) h round(maxy - miny, 3) parts.append({ part_id: entity.dxf.layer _ str(entity.handle), quantity: 1, width: w, height: h })实际使用时我会先人工在 CAD 里确认每个零件的图层命名比如BRACKET_A、BRACKET_B然后脚本自动按图层归并数量。这样生成的 CSV 已经包含去重后的零件列表和数量统计比手工输入高效且不易出错。导出后用前面提到的校验脚本跑一遍确认完再把 CSV 喂给排样引擎。5.2 排样引擎输出的判定与后处理排样完成后我会导出每条零件记录的摆放信息再用 matplotlib 画出整个板材的布局预览图。预览图上有每个零件的外轮廓、零件编号、旋转角度。我习惯把坐标和旋转角度同时输出到一份新的 CSV 里这份“排样结果 CSV”直接交给切割机操作员或者用于生成 NC 代码。这一步要注意的是排样引擎给出的坐标往往是零件局部坐标系下的原点位置。不同引擎约定的原点不同——有的用外接矩形左下角有的用轮廓质心有的用第一个顶点位置。如果不确认清楚直接拿渲染图对一下位置还好拿去切就会整体偏移甚至翻转。我在导出结果时都会写一段后处理脚本把坐标原点统一转换成板材左下角为基准检查逻辑就是所有零件的坐标加上自身最小 x/y 偏移后必须落在 [0, 板材宽度] 和 [0, 板材高度] 之间。5.3 小批量零件 CSV 手工微调的最优顺序虽然自动排样已经很强大但遇到小批量订单——比如就 8 个零件、1 张板能装完——手工调整反而更快更优。我的做法是自动排样跑一版看结果如果零件数量少直接手动微调位置或旋转。这里的顺序也很有讲究。我优先调整数量多、面积大的零件因为它们对利用率影响最大。面积大的零件一旦移动周围空隙变化会牵动周边四五个小零件的布局调整收益立竿见影反过来先微调小零件挪了半天对大零件毫无影响纯属浪费时间。另外还有一个经验如果零件里存在大量相同尺寸的矩形件手工排样的最优方案大概率是整整齐齐地横竖对齐排而不是复杂的交错排。这是因为共边切割能节省切缝同尺寸矩形件整齐排列后相邻零件之间的共边可以用一条路径切出切割时间缩短、板材利用率和设备效率双提升。自动排样引擎不一定能意识到这一点它往往为了追求面积利用率最大化把零件排得歪歪扭扭结果面积节约了 2%切割时间却增加了 15%。所以最终方案的判定标准不只有面积利用率还要综合切割路径长度这一点 CSV 的字段设计阶段可预留preferred_orientation字段告诉引擎这些零件尽量沿着哪个方向排布。6. 实际运用中值得留意的经验清单排样这个事听起来简单做深入了全是细节。我在多个项目里反复踩坑之后整理了一份经验清单每条都是真金白银换来的现在分享出来。第一CSV 的列顺序尽量不要随意调整。虽然标准 CSV 靠表头定位字段但很多半吊子工具完全没有对表头做解析它默认第一列是零件编号、第二列是数量、第三列是宽度、第四列是高度。你在 Excel 里把列挪个位置可能工具瞬间全部读错。稳妥起见严格按照工具文档里的列顺序来表头顺序和文档一致最安全。第二不要用 Excel 直接打开 CSV 然后保存。Excel 的编码和格式处理是出了名的自作主张保存后极可能引入 BOM 头或把数据转换成 OLE2。如果只是查看数据用文本编辑器如果必须用 Excel 编辑编辑完另存时千万选“CSV UTF-8”保存后再用记事本确认一次。第三零件数量超过 5000 件时先抽样小规模试跑。全量数据直接丢进排样引擎一旦参数设置错误排到一半发现方向不对白白浪费几小时。我先随机抽 100 个零件试跑确认输出能正常渲染、没有重叠、没有零件飞出板材边界再跑全量。第四涉及异形件时外接矩形信息只能用于粗排和快速预测最终精度要依赖精确轮廓。所以 CSV 里除了写width/height最好同时记录contour_file字段指向对应的 DXF并且 DXF 文件名与 part_id 形成强关联。这样粗排阶段用矩形估算精排阶段加载真实轮廓做碰撞检测兼顾效率与精度。第五版本管理。这是最容易被忽略、但长期来看受益最大的一点。零件数据每天都在改今天加一个件、明天改个尺寸CSV 文件最好纳入版本管理或者至少在文件头记录修改时间和版本号。否则排样结果出了问题连是哪一版零件数据导出的都说不清排查起来极其痛苦。我的习惯是文件名带上日期和版本例如parts_20240518_v3.csv配合 README 记录修改历史两个月后回头找数据也一目了然。7. 结语与排样流程后续优化方向写到这里2D Nesting 中 CSV 零件数据定义的完整链路基本讲完了。从字段设计、数据校验、格式约定到排样流程、结果输出再到各种反直觉的报错和处理办法每一环都是实际生产中真实存在的关卡。CSV 看起来简单但它作为排样流程的“源头数据”质量直接决定后端的效率和正确性。我个人的体会是在做排样优化之前先把数据质量做好很多软件操作层面的问题根本不会出现——这句话适用于所有工业软件不只排样。最后再分享一个后续可以尝试的方向目前的 2D 排样大多是离线批处理把一份零件 CSV 丢进去出一份排样方案。如果未来把 CSV 数据接到实时排样内核上配合工厂的 MES 系统自动读取当天订单动态生成排样方案整条产线的材料利用率还能再上一个台阶。CSV 作为接口协议的轻量性在这种场景下反而超越了很多花哨的数据格式——这大概也是它长盛不衰的原因。