型材切割优化软件是一款专为优化线性材料(如管道、棒材或型材)切割设计的工具,旨在最小化材料浪费并最大化利用率。该软件基于 C++ 和 Microsoft Foundation Class (MFC) 框架开发,采用模块化设计,提供用户友好的界面和强大的优化算法。本文按照用户界面、数据管理、优化引擎、方案管理和辅助工具的模块划分,详细介绍软件框架、使用方法和核心原理,并嵌入关键代码片段说明实现细节。此外,还将介绍两款基于贪心法实现的 Excel 插件(基于 VBA 的“下料优化EXCEL专业版”和基于 VSTO 的“ProfileCuttingExcel”),并进行性能对比,最后提供资源分享链接。
一、软件框架结构
软件采用模块化设计,主要分为以下几个核心模块:
1. 用户界面模块
- 功能:提供交互式图形界面,接收用户输入(零件/原料数据、参数配置),展示优化结果和日志信息,发送控制指令(如启动、暂停优化)。
- 核心组件:
- CGridCtrl (m_ItemGrid, m_BinGrid):用于显示和编辑零件(Items)和原料(Bins)数据,支持插入、删除、导入和导出操作。
- CListCtrl (m_SolutionList):展示优化结果,包括原料用量、利用率等。
- CEdit (m_TraceWnd):显示实时计算日志。
- 实现细节:
- 主对话框基于 MFC 的 CDialogEx 实现,负责控件初始化、事件处理和数据绑定。
- 支持右键菜单操作(如插入行、删除行、导入/导出数据)。
- 参数配置(如锯缝宽度 m_Kerf、快速模式 m_QuickMode)通过界面输入,传递给数据管理和优化引擎模块。
- 关键代码:
BOOL OnInitDialog() { CDialogEx::OnInitDialog(); SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // 设置 SolutionList 样式 DWORD dwStyle = m_SolutionList.GetExtendedStyle(); dwStyle |= LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES; m_SolutionList.SetExtendedStyle(dwStyle); m_SolutionList.InsertColumn(0, _T("序号"), LVCFMT_CENTER); m_SolutionList.InsertColumn(1, _T("迭次"), LVCFMT_CENTER); m_SolutionList.InsertColumn(2, _T("原料用量"), LVCFMT_CENTER); m_SolutionList.InsertColumn(3, _T("原料总长"), LVCFMT_CENTER); m_SolutionList.InsertColumn(4, _T("模数"), LVCFMT_CENTER); m_SolutionList.InsertColumn(5, _T("利用率(%)"), LVCFMT_CENTER); m_SolutionList.InsertColumn(6, _T("实际利用率(%)"), LVCFMT_CENTER); m_SolutionList.InsertColumn(7, _T("时间(ms)"), LVCFMT_CENTER); // 初始化 BinGrid m_BinGrid.SetHeaderSort(TRUE); m_BinGrid.EnableDragAndDrop(TRUE); m_BinGrid.SetEditable(TRUE); m_BinGrid.SetColumnCount(3); m_BinGrid.SetRowCount(1); m_BinGrid.SetFixedRowCount(1); m_BinGrid.SetFixedColumnCount(1); m_BinGrid.SetItemText(0, 0, _T("序号")); m_BinGrid.SetItemText(0, 1, _T("长度")); m_BinGrid.SetItemText(0, 2, _T("数量")); m_BinGrid.SetCompareFunction(CGridCtrl::pfnCellNumericCompare); m_BinGrid.ExpandColumnsToFit(); // 初始化 ItemGrid m_ItemGrid.SetHeaderSort(TRUE); m_ItemGrid.EnableDragAndDrop(TRUE); m_ItemGrid.SetEditable(TRUE); m_ItemGrid.SetColumnCount(4); m_ItemGrid.SetRowCount(1); m_ItemGrid.SetFixedRowCount(1); m_ItemGrid.SetFixedColumnCount(1); m_ItemGrid.SetItemText(0, 0, _T("序号")); m_ItemGrid.SetItemText(0, 1, _T("长度")); m_ItemGrid.SetItemText(0, 2, _T("数量")); m_ItemGrid.SetItemText(0, 3, _T("备注")); m_ItemGrid.SetCompareFunction(CGridCtrl::pfnCellNumericCompare); initRandom(); OnBnClickedButtonGenerateitem(); m_ItemGrid.ExpandColumnsToFit(); OnEnChangeEditValue(); return TRUE; }
2. 数据管理模块
- 功能:管理零件(ItemVec)和原料(BinVec)数据,包括输入、验证、存储、导入导出和过滤,为优化引擎提供输入。
- 核心功能:
- GetItemGridData / SetItemGridData:从/向 m_ItemGrid 读取/写入零件数据。
- GetBinGridData / SetBinGridData:从/向 m_BinGrid 读取/写入原料数据。
- OnBnClickedButtonGenerateitem:生成随机零件数据,基于原料长度范围。
- OnBnClickedButtonImportdata / OnBnClickedButtonExportdata:支持 CSV 格式的数据导入和导出。
- 实现细节:
- 使用 rapidcsv 库处理 CSV 文件的读写。
- 数据存储在 ItemVec 和 BinVec(std::vector 类型)中。
- 数据过滤功能移除无效数据(长度或数量小于等于 0)。
- 关键代码:
void OnBnClickedButtonGenerateitem() { UpdateData(TRUE); GetBinGridData(m_BinGrid, m_Bins); if (m_Bins.empty()) { AppendBinData({ 6000, 10000 }); m_MaxBinLength = m_MinBinLength = 6000; } else { auto sortedLengths = from(m_Bins) .select([](const auto& bin) { return bin.length; }) .orderBy() .toStdVector(); m_MinBinLength = sortedLengths[0]; m_MaxBinLength = sortedLengths.back(); } m_ItemGrid.DeleteNonFixedRows(); Length length = (m_MinBinLength + m_MaxBinLength) / 2; Length top = 3 * length / 5; Length bottom = length / 5 + 1; if (top == bottom || bottom < 1) { AfxMessageBox(L"原料长度设置不合理,请重新设置!"); return; } m_ItemCount = 0; m_TotalItemLength = 0; int quantity = 0; initRandom(); std::uniform_int_distribution<Length> distLength(bottom, top - 1); std::uniform_int_distribution<int> distQuantity(5, 100); for (int i = 0; i < 100; i++) { AppendRow(m_ItemGrid); length = distLength(rng); m_ItemGrid.SetItemText(i + 1, 1, CCommonUtils::ToString(length)); quantity = distQuantity(rng); m_ItemGrid.SetItemText(i + 1, 2, CCommonUtils::ToString(quantity)); m_ItemCount += quantity; m_TotalItemLength += length * quantity; } AppendRow(m_ItemGrid); UpdateFixedColumnNumbers(m_ItemGrid); UpdateData(FALSE); } - 关键代码:
void OnBnClickedButtonImportdata() { std::vector<CString> vecFileType = { L"csv" }; CString filePath; if (CCommonUtils::SelectFile(vecFileType, filePath)) { if (CCommonUtils::IsFileExist(filePath)) { using namespace rapidcsv; Document doc(CCommonUtils::UTF2ASCII(CCommonUtils::WCharToChar(filePath))); if (doc.GetColumnCount() > 3 || doc.GetColumnCount() < 2) { AfxMessageBox(L"型材库文件数据文件格式错误,请保持和界面一致!"); return; } ItemVec items; items.reserve(doc.GetRowCount()); m_ItemCount = 0; m_TotalItemLength = 0; for (size_t i = 0, row = doc.GetRowCount(); i < row; ++i) { Item item; item.length = doc.GetCell<Length>(0, i); item.quantity = doc.GetCell<Quantity>(1, i); if (item.length > 0 && item.quantity > 0) { items.push_back(item); m_ItemCount += item.quantity; m_TotalItemLength += item.length * item.quantity; } } if (items.empty()) AfxMessageBox(L"无可用数据!"); else { SetItemGridData(m_ItemGrid, items); CString message; message.Format(L"导入成功,导入数据 %lld 条。 ", items.size()); AfxMessageBox(message); } } else AfxMessageBox(L"选择文件失败!"); } UpdateData(FALSE); }
3. 优化引擎模块
- 功能:执行型材切割优化算法,生成最优切割方案。
- 核心组件:
- pc_handle_t (pCut_):优化算法的核心句柄,调用外部库 ProfileCuttingPL 执行计算。
- Solution (pc_solution_t):存储优化结果,包括原料数量、利用率等。
- Parameters (pc_parameters_t):配置优化参数,如锯缝宽度 (m_Kerf)、快速模式 (m_QuickMode)。
- 实现细节:
- 支持多线程计算,异步执行优化任务,避免界面卡顿。
- 依赖外部库(如 columngenerationsolver、Knapsack、treesearchsolver)实现列生成和动态规划算法。
- 支持快速模式(忽略锯缝)和时间限制。
- 关键代码:
void UpdateSolution(const Solution& sol) { if (!solutions_.empty()) { if (m_FilterSolution) { const auto& last = solutions_.back(); if (last.binCount == sol.binCount && sol.actualUtilization - last.actualUtilization < 1e-8 && last.solutionBinCount == sol.solutionBinCount) return; } } if (solutions_.size() >= MAX_SOLUTIONS) { pc_free_solution(&solutions_.front()); solutions_.pop_front(); m_SolutionList.DeleteItem(0); } pc_solution_t sol_copy = {}; pc_copy_solution(&sol_copy, &sol); solutions_.push_back(sol_copy); int nItem = m_SolutionList.GetItemCount(); m_SolutionList.InsertItem(nItem, CCommonUtils::ToString(nItem + 1)); m_SolutionList.SetItemText(nItem, 1, CCommonUtils::ToString(m_IterationCount)); m_SolutionList.SetItemText(nItem, 2, CCommonUtils::ToString(sol.binCount)); m_SolutionList.SetItemText(nItem, 3, CCommonUtils::ToString(1.0 * m_TotalBinLength, 0)); m_SolutionList.SetItemText(nItem, 4, CCommonUtils::ToString(sol.solutionBinCount)); m_SolutionList.SetItemText(nItem, 5, CCommonUtils::ToString(100.0 * m_UsedBinLength / m_TotalBinLength, 3)); m_SolutionList.SetItemText(nItem, 6, CCommonUtils::ToString(100.0 * m_TotalItemLength / m_TotalBinLength, 3)); m_SolutionList.SetItemText(nItem, 7, CCommonUtils::ToString(pc_get_elapsed_time(pCut_) * 1000.0, 3)); for (int i = 0; i < nItem; ++i) m_SolutionList.SetItemText(i, 0, CCommonUtils::ToString(i + 1)); if (!m_runCallback) return; CString message; message.Format(_T("第 %d 代:原料数量: %d,原料总长:%lld,模式数量:%d,利用率: %.3f %%,实际利用率: %.3f %%"), m_IterationCount++, sol.binCount, m_TotalBinLength, sol.solutionBinCount, 100.0 * m_UsedBinLength / m_TotalBinLength, 100.0 * m_TotalItemLength / m_TotalBinLength); SendTrace(message); }
4. 方案管理模块
- 功能:存储、过滤和可视化优化引擎生成的切割方案,供用户查看和导出。
- 核心功能:
- UpdateSolution:更新和存储优化方案,显示在 m_SolutionList。
- GetSolutionDetails:生成详细的切割方案描述。
- OnSolutionExportToCSV / OnSolutionExportToTXT:导出优化方案到 CSV 或 TXT 文件。
- 实现细节:
- 使用 std::deque 存储最多 50 个优化方案(MAX_SOLUTIONS)。
- 支持方案过滤(m_FilterSolution),去除重复或相似方案。
- 优化结果通过 m_SolutionList 展示,支持点击查看详细信息。
- 关键代码:
void UpdateSolution(const Solution& sol) { if (!solutions_.empty()) { if (m_FilterSolution) { const auto& last = solutions_.back(); if (last.binCount == sol.binCount && sol.actualUtilization - last.actualUtilization < 1e-8 && last.solutionBinCount == sol.solutionBinCount) return; } } if (solutions_.size() >= MAX_SOLUTIONS) { pc_free_solution(&solutions_.front()); solutions_.pop_front(); m_SolutionList.DeleteItem(0); } pc_solution_t sol_copy = {}; pc_copy_solution(&sol_copy, &sol); solutions_.push_back(sol_copy); int nItem = m_SolutionList.GetItemCount(); m_SolutionList.InsertItem(nItem, CCommonUtils::ToString(nItem + 1)); m_SolutionList.SetItemText(nItem, 1, CCommonUtils::ToString(m_IterationCount)); m_SolutionList.SetItemText(nItem, 2, CCommonUtils::ToString(sol.binCount)); m_SolutionList.SetItemText(nItem, 3, CCommonUtils::ToString(1.0 * m_TotalBinLength, 0)); m_SolutionList.SetItemText(nItem, 4, CCommonUtils::ToString(sol.solutionBinCount)); m_SolutionList.SetItemText(nItem, 5, CCommonUtils::ToString(100.0 * m_UsedBinLength / m_TotalBinLength, 3)); m_SolutionList.SetItemText(nItem, 6, CCommonUtils::ToString(100.0 * m_TotalItemLength / m_TotalBinLength, 3)); m_SolutionList.SetItemText(nItem, 7, CCommonUtils::ToString(pc_get_elapsed_time(pCut_) * 1000.0, 3)); for (int i = 0; i < nItem; ++i) m_SolutionList.SetItemText(i, 0, CCommonUtils::ToString(i + 1)); if (!m_runCallback) return; CString message; message.Format(_T("第 %d 代:原料数量: %d,原料总长:%lld,模式数量:%d,利用率: %.3f %%,实际利用率: %.3f %%"), m_IterationCount++, sol.binCount, m_TotalBinLength, sol.solutionBinCount, 100.0 * m_UsedBinLength / m_TotalBinLength, 100.0 * m_TotalItemLength / m_TotalBinLength); SendTrace(message); }
5. 辅助工具模块
-
功能:提供随机数据生成、日志输出和配置管理等支持功能。
-
核心功能:
- initRandom / OnBnClickedButtonGenerateitem:生成随机零件数据,基于梅森旋转算法(std::mt19937)。
- SendTrace / OnUpdateTrace:实时更新计算日志。
- SaveConfiguration / LoadConfiguration:保存和加载用户配置。
-
实现细节:
- 使用 MFC 注册表操作存储配置(如 m_runCallback、m_FilterSolution、m_Kerf)。
- 自动调整表格列宽(ExpandColumnsToFit)。
-
关键代码:
void SaveConfiguration() { AfxGetApp()->WriteProfileStringW(_T("ProfileCutting"), _T("RunCallback"), CCommonUtils::ToString(m_runCallback)); AfxGetApp()->WriteProfileStringW(_T("ProfileCutting"), _T("FilterSolution"), CCommonUtils::ToString(m_FilterSolution)); AfxGetApp()->WriteProfileStringW(_T("ProfileCutting"), _T("QuickMode"), CCommonUtils::ToString(m_QuickMode)); AfxGetApp()->WriteProfileStringW(_T("ProfileCutting"), _T("SetTimer"), CCommonUtils::ToString(m_SetTimer)); AfxGetApp()->WriteProfileStringW(_T("ProfileCutting"), _T("LimitTime"), CCommonUtils::ToString(m_LimitTime)); AfxGetApp()->WriteProfileStringW(_T("ProfileCutting"), _T("Kerf"), CCommonUtils::ToString(m_Kerf)); } void LoadConfiguration() { CString strValue; strValue = AfxGetApp()->GetProfileStringW(_T("ProfileCutting"), _T("RunCallback"), _T("1")); m_runCallback = (_ttoi(strValue) != 0); strValue = AfxGetApp()->GetProfileStringW(_T("ProfileCutting"), _T("FilterSolution"), _T("1")); m_FilterSolution = (_ttoi(strValue) != 0); strValue = AfxGetApp()->GetProfileStringW(_T("ProfileCutting"), _T("QuickMode"), _T("0")); m_QuickMode = (_ttoi(strValue) != 0); strValue = AfxGetApp()->GetProfileStringW(_T("ProfileCutting"), _T("SetTimer"), _T("0")); m_SetTimer = (_ttoi(strValue) != 0); strValue = AfxGetApp()->GetProfileStringW(_T("ProfileCutting"), _T("LimitTime"), _T("2.0")); m_LimitTime = _tcstod(strValue, nullptr); strValue = AfxGetApp()->GetProfileStringW(_T("ProfileCutting"), _T("Kerf"), _T("0")); m_Kerf = static_cast<Length>(_ttoi64(strValue)); if (isTrial) { m_QuickMode = FALSE; GetDlgItem(IDC_CHECK_QuickMode)->EnableWindow(FALSE); } UpdateData(FALSE); }
二、Excel插件介绍
除了上述独立型材切割优化软件,我们还开发了两款基于 Excel 的插件,用于类似场景的切割优化。这两款插件基于贪心法实现,适合快速处理中小规模的切割任务。以下是它们的详细介绍:
1. 下料优化EXCEL专业版(基于 VBA)
-
功能:
- 提供 Excel 原生的界面,通过 VBA 宏实现切割优化。
- 支持用户在 Excel 表格中输入零件和原料数据,自动生成优化切割方案。
-
核心组件:
- 输入表格:用户在指定工作表(如“零件”和“原料”)中输入长度和数量。
- 优化按钮:通过 VBA 宏触发贪心法优化,基于“首次适应”(First-Fit)算法。
- 结果表格:在新的工作表中显示切割方案,包括每根原料的零件分配和利用率。
-
交互使用方法 :
- 打开 Excel 文件,启用宏(确保宏安全性设置为“启用所有宏”)。
- 在“零件”工作表中输入零件长度和数量(格式:A 列为长度,B 列为数量)。
- 在“原料”工作表中输入原料长度和数量(负值表示无限供应)。
- 点击工具栏中的“优化”按钮,运行 VBA 宏生成切割方案。
- 查看“结果”工作表,检查每根原料的零件分配和利用率。
-
特点:
- 轻量级,无需额外安装,适合熟悉 Excel 的用户。
- 算法简单,适合中小规模数据(零件数量 < 1000)。
- 支持快速修改数据和重新优化。
2. ProfileCuttingExcel(基于 VSTO)
功能和下料优化EXCEL专业版类似,插件通过 VSTO 开发,插件提供
三种计算模式:FFD,BFD,BFD2(改进算法)。
两种输出模式:型材索引和型材长度
核心算法 FFD与BFD启发式算法(采用开源项目的框架,资源分享连接可以获取压缩包),由于效率不如预期因此 FFD 和 BFD 模式在当前框架下进行了一些优化,但是发现凡是不如预期,因此根据计算原理重写了 BFD 得到了 BDF2.
三、性能对比
为了帮助用户选择适合的工具,我们对型材切割优化软件和两款 Excel 插件进行了性能对比,测试基于以下条件:
- 测试数据:custom_items.csv,原料长度 6000 mm(无限供应),锯缝宽度 5 mm。
- 测试环境:Windows 11,Intel Core i9-11900K 3.50GHz,32 GB RAM。
- 指标:优化时间、原料用量、材料利用率。
| 名称 | 用料量 | 用料总长 | 模数 | 利用率 | 实际利用率 | 时间(S) |
|---|---|---|---|---|---|---|
| pfc | 29593 | 177558000 | 291 | 100 | 99.508 | 143 |
| pfc速 | 29593 | 177558000 | 310 | 100 | 99.508 | 1.2 |
| excel | 29800 | 178800000 | 352 | 99.37 | 98.82 | 6.0 |
| excel2 | 29800 | 178800000 | 352 | 99.37 | 98.82 | 0.04 |
| 专业版 | 29800 | 178800000 | 352 | 99.37 | 98.82 | 380 |
四、资源分享
所有相关资源(型材切割优化软件可执行文件、VBA 插件 Excel 文件、VSTO 插件安装包及示例数据)已打包并上传至 OneDrive 云盘,供用户下载和测试:
- 下载链接:公众号【橡皮的CAD开发】回复【一维下料】获取
- 内容:
- 型材切割优化软件(ProfileCuttingPL.exe)
- 下料优化EXCEL专业版(CuttingOptimizationPro.xlsm)
- ProfileCuttingExcel 插件(ProfileCuttingExcel.vsto)
- 示例数据(sample_items.csv, sample_bins.csv)
- 使用说明文档(UserGuide.pdf)
- 使用说明:
- 解压后运行型材切割优化软件,需 Windows 系统支持 MFC。
- VBA 插件需启用 Excel 宏,VSTO 插件需安装 .NET Framework。
- 示例数据可直接导入软件或插件进行测试。
由于上传图片总是失败,可以一维下料软件分享阅读完整原文
168

被折叠的 条评论
为什么被折叠?



