ecode-cutting 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ecode_cutting-0.2.3/CHANGELOG.md +48 -0
- ecode_cutting-0.2.3/MANIFEST.in +6 -0
- ecode_cutting-0.2.3/MIGRATION.md +121 -0
- ecode_cutting-0.2.3/PKG-INFO +190 -0
- ecode_cutting-0.2.3/README.md +182 -0
- ecode_cutting-0.2.3/VALIDATION.md +160 -0
- ecode_cutting-0.2.3/docs/API_AUDIT.md +105 -0
- ecode_cutting-0.2.3/docs/PORTFOLIO.md +62 -0
- ecode_cutting-0.2.3/docs/api_evidence_summary.json +119 -0
- ecode_cutting-0.2.3/docs/difference_review.json +206 -0
- ecode_cutting-0.2.3/docs/linear_fast_benchmark.json +68 -0
- ecode_cutting-0.2.3/docs/manual_api_inventory.json +9930 -0
- ecode_cutting-0.2.3/docs/quality_reference_replay.json +958 -0
- ecode_cutting-0.2.3/docs/refresh_api_evidence.py +119 -0
- ecode_cutting-0.2.3/examples/multiple_plans.py +34 -0
- ecode_cutting-0.2.3/examples/quickstart.py +25 -0
- ecode_cutting-0.2.3/examples/web_app.py +66 -0
- ecode_cutting-0.2.3/pyproject.toml +18 -0
- ecode_cutting-0.2.3/setup.cfg +4 -0
- ecode_cutting-0.2.3/src/ecode_cutting/USAGE.md +673 -0
- ecode_cutting-0.2.3/src/ecode_cutting/__init__.py +18 -0
- ecode_cutting-0.2.3/src/ecode_cutting/_common.py +158 -0
- ecode_cutting-0.2.3/src/ecode_cutting/_linear_fast.py +231 -0
- ecode_cutting-0.2.3/src/ecode_cutting/compat.py +659 -0
- ecode_cutting-0.2.3/src/ecode_cutting/engine.py +558 -0
- ecode_cutting-0.2.3/src/ecode_cutting/exporters.py +362 -0
- ecode_cutting-0.2.3/src/ecode_cutting/linear.py +532 -0
- ecode_cutting-0.2.3/src/ecode_cutting/models.py +230 -0
- ecode_cutting-0.2.3/src/ecode_cutting/portfolio.py +234 -0
- ecode_cutting-0.2.3/src/ecode_cutting/py.typed +0 -0
- ecode_cutting-0.2.3/src/ecode_cutting/rectangular.py +357 -0
- ecode_cutting-0.2.3/src/ecode_cutting/serialization.py +234 -0
- ecode_cutting-0.2.3/src/ecode_cutting/validation.py +234 -0
- ecode_cutting-0.2.3/src/ecode_cutting.egg-info/PKG-INFO +190 -0
- ecode_cutting-0.2.3/src/ecode_cutting.egg-info/SOURCES.txt +61 -0
- ecode_cutting-0.2.3/src/ecode_cutting.egg-info/dependency_links.txt +1 -0
- ecode_cutting-0.2.3/src/ecode_cutting.egg-info/top_level.txt +1 -0
- ecode_cutting-0.2.3/tests/fixtures/api_reference.json +1 -0
- ecode_cutting-0.2.3/tests/fixtures/document_api_sources.json +836 -0
- ecode_cutting-0.2.3/tests/fixtures/legacy_cases.json +1 -0
- ecode_cutting-0.2.3/tests/test_compatibility_exports.py +130 -0
- ecode_cutting-0.2.3/tests/test_corpus.py +58 -0
- ecode_cutting-0.2.3/tests/test_difference_review.py +244 -0
- ecode_cutting-0.2.3/tests/test_document_api_inventory.py +112 -0
- ecode_cutting-0.2.3/tests/test_document_exports.py +228 -0
- ecode_cutting-0.2.3/tests/test_document_remaining_contract.py +226 -0
- ecode_cutting-0.2.3/tests/test_engine.py +111 -0
- ecode_cutting-0.2.3/tests/test_exports.py +164 -0
- ecode_cutting-0.2.3/tests/test_fast_linear.py +103 -0
- ecode_cutting-0.2.3/tests/test_linear.py +195 -0
- ecode_cutting-0.2.3/tests/test_new_entry_invariants.py +288 -0
- ecode_cutting-0.2.3/tests/test_portfolio.py +184 -0
- ecode_cutting-0.2.3/tests/test_quality_reference.py +109 -0
- ecode_cutting-0.2.3/tests/test_rectangular.py +190 -0
- ecode_cutting-0.2.3/tests/test_reference_contract.py +331 -0
- ecode_cutting-0.2.3/tests/test_review_engine.py +123 -0
- ecode_cutting-0.2.3/tests/test_review_linear.py +70 -0
- ecode_cutting-0.2.3/tests/test_review_rectangular.py +85 -0
- ecode_cutting-0.2.3/tests/test_web.py +99 -0
- ecode_cutting-0.2.3/tools/benchmark_linear_fast.py +54 -0
- ecode_cutting-0.2.3/tools/verify_corpus.py +78 -0
- ecode_cutting-0.2.3/tools/verify_install.py +54 -0
- ecode_cutting-0.2.3/tools/verify_usage.py +27 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# 变更记录
|
|
2
|
+
|
|
3
|
+
## 0.2.3 — 2026-10-25
|
|
4
|
+
|
|
5
|
+
- docs:新增随依赖包安装的中文使用手册,覆盖公开入口、参数、结果与完整调用示例。
|
|
6
|
+
- docs:发布作者设为 Thorne,保持纯 Python、直接导入的交付方式。
|
|
7
|
+
- test:全新安装后实际执行手册中的 Python 示例,核验发布元数据和打包文档。
|
|
8
|
+
|
|
9
|
+
## 0.2.2 — 2026-10-25
|
|
10
|
+
|
|
11
|
+
- test:恢复 HTTP 示例及其 6 项集成测试,保留作为后续联调工具,依赖库交付方式不变。
|
|
12
|
+
- fix:补齐原卷尾段,统一余料计数、索引、材质、坐标和结果存档,独立校验锯缝及原料边界。
|
|
13
|
+
- fix:兼容 Clear 保留原版实测的尺寸精度,继续清除旧任务映射与计数。
|
|
14
|
+
- test:逐类审查680条已知查询差异,保留安全改善、等价排样和明确的工艺取舍。
|
|
15
|
+
- test:补齐9项接口行为证据,方向重载对照7条原版调用,覆盖卷材尾段及损坏结果反例。
|
|
16
|
+
|
|
17
|
+
## 0.2.1 — 2026-10-25
|
|
18
|
+
|
|
19
|
+
- fix:移除额外的 HTTP 服务示例及其适配层测试,交付聚焦可直接导入的依赖库。
|
|
20
|
+
- docs:明确安装、同进程调用和调用方自行开发服务的职责。
|
|
21
|
+
- test:全新环境离线安装后运行单方案、多方案及选中结果导出示例。
|
|
22
|
+
|
|
23
|
+
## 0.2.0 — 2026-10-25
|
|
24
|
+
|
|
25
|
+
- feat:新增一维容量索引快速入口,复杂工艺自动回退,保留原入口行为。
|
|
26
|
+
- feat:新增一维/二维多方案入口、真实方案去重、总利用率及候选比较指标。
|
|
27
|
+
- feat:新增快速计算和多方案 HTTP 示例接口,选择方案后可直接导出。
|
|
28
|
+
- perf:5000件直端基准中位1.688秒降至0.0629秒,标准化输出一致;不外推到其它工况。
|
|
29
|
+
- test:补充100组快速差分、独立方案验解、总预算/取消及手册特有角度重载。
|
|
30
|
+
|
|
31
|
+
## 0.1.1 — 2026-10-25
|
|
32
|
+
|
|
33
|
+
- fix:增加受预算约束的一维局部重排,修复五组升序订单多用一根原料的问题。
|
|
34
|
+
- feat:新增 `CutGLibEngine`/`Out` 文档兼容入口,保留现代结构化调用方式。
|
|
35
|
+
- fix:支持不限组合规格,修正布局分组条件、DXF版本/图层、PNG尺寸及PTX厚度缩放。
|
|
36
|
+
- test:新增28页手册逐项清单、原DLL公开API实测快照及文件/流重载回放。
|
|
37
|
+
- test:明确保留布局、实例顺序及更安全错误处理的差异,不宣称所有返回逐值相同。
|
|
38
|
+
|
|
39
|
+
## 0.1.0 — 2026-10-25
|
|
40
|
+
|
|
41
|
+
- feat:新增纯 Python 一维/二维切割求解、材料与库存、斜角、组合原料和卷材。
|
|
42
|
+
- feat:新增结构化结果、布局分组、加工刀序、预算及取消。
|
|
43
|
+
- feat:新增 CSV/DXF/PTX/PNG/SVG 与 JSON/XML 存档。
|
|
44
|
+
- feat:新增 Python Web 直接引入示例及自动化测试。
|
|
45
|
+
- fix:修正最终余料、量化斜角共切、末刀锯缝和回退后库存实例映射。
|
|
46
|
+
- fix:修正 PTX 修边/连续条带层级、输入边界、异常恢复和斜角利用率。
|
|
47
|
+
- test:纳入 120 组静态旧版语料及交叉审查反例,提供干净环境离线安装验收。
|
|
48
|
+
- 验证结果和实际限制见 MIGRATION.md;本版本尚未发布到 PyPI。
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
include README.md CHANGELOG.md MIGRATION.md VALIDATION.md
|
|
2
|
+
recursive-include src/ecode_cutting *.py *.md py.typed
|
|
3
|
+
recursive-include tests *.py *.json
|
|
4
|
+
recursive-include docs *.md *.json *.py
|
|
5
|
+
recursive-include examples *.py
|
|
6
|
+
include tools/verify_install.py tools/verify_usage.py tools/verify_corpus.py tools/benchmark_linear_fast.py
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# CutGLib 功能迁移与验收
|
|
2
|
+
|
|
3
|
+
参考范围为工作区已还原的 CutGLib 5.3.8 公开计算、查询、导出接口。
|
|
4
|
+
本包重新实现算法,不复制 DLL,不启动原程序,不调用 .NET。
|
|
5
|
+
`0.1.0` 为独立实现的首版;“功能有实现”与“已证明和原库所有行为完全相同”分别记录。
|
|
6
|
+
|
|
7
|
+
## 功能入口
|
|
8
|
+
|
|
9
|
+
- 一维:`add_linear_stock`、`add_linear_part`、`execute_linear`。
|
|
10
|
+
包含长度量化、直切与斜切、截面、旋转/翻转、相邻切口匹配、库存和材料、
|
|
11
|
+
原料组合、每棒零件规格种类及阈值、余料和排序。
|
|
12
|
+
- 二维:`add_stock`、`add_part`、`execute`。
|
|
13
|
+
使用整数二叉断头切割树,输出前序加工刀序;包含旋转、横/纵首刀、
|
|
14
|
+
换向层级、卷材净使用尺寸及从原卷切断、四边修边、锯缝和最终余料。
|
|
15
|
+
- 材料:`add_material`、`get_material` 及零件、原料、余料材料查询。
|
|
16
|
+
- 结果:逐件输入实例映射、原料实例/组合明细、余料、布局分组与利用率、
|
|
17
|
+
全局/逐原料/逐零件刀序、修边刀序、完成数及运行时间。
|
|
18
|
+
- 布局:`use_layout_minimization` 影响搜索偏好;`max_layout_size` 将相同布局
|
|
19
|
+
按最大张数分组,不限制一张板上的零件数。
|
|
20
|
+
- 控制:总时间预算、回调取消、固定随机种子、多次搜索及最佳已得方案。
|
|
21
|
+
- 输出:CSV、零件/切线 DXF、二维 PTX 1.08、PNG、SVG;文件与流均可用。
|
|
22
|
+
- 存档:任务和结果的版本化 JSON/XML;旧任务 XML 的尺寸、方向、库存、
|
|
23
|
+
零件、材料编号、修边、锯缝等属性导入,包含英尺英寸尺寸。
|
|
24
|
+
|
|
25
|
+
## Python 接口差异
|
|
26
|
+
|
|
27
|
+
`CutEngine` 保留主要 PascalCase 迁移别名,优先使用 snake_case 方法。
|
|
28
|
+
`execute*` 返回 `Result`;查询返回模型或 `(原料索引, 模型)`,不沿用 .NET
|
|
29
|
+
`out` 参数。非法索引抛 `IndexError`,非法输入抛 `ValidationError`。
|
|
30
|
+
`get_result_part` 按输入展开顺序查询,未放置返回 `None`。
|
|
31
|
+
|
|
32
|
+
结果仅列出实际使用的原料布局,有限/无限供应的原始清单可由 `engine.stocks` 查询。
|
|
33
|
+
`used_stock_count` 在组合模式统计真实原料组件数。
|
|
34
|
+
Python 的数量必须是非负整数;旧库某些负数量宽容行为不作为合法输入保留。
|
|
35
|
+
空需求返回完整空结果。
|
|
36
|
+
|
|
37
|
+
`fill_ratio` 使用实际凸多边形成品面积,`nominal_fill_ratio` 单独提供名义尺寸
|
|
38
|
+
指标;`get_layout_fill_ratio` 的截面模式保留原版按剩余有效长度计算的用棒率。
|
|
39
|
+
`MaxPartSizes`/`MaxSizeSizes` 返回 `None`,表示不设置原产品的规格类授权上限。
|
|
40
|
+
|
|
41
|
+
原产品 COM/Windows 注册、硬件绑定、旧产品授权密钥及注册表操作不迁移到
|
|
42
|
+
这个独立算法包。旧 XML 内部排除区域不是 `CutEngine` 公开输入接口,当前导入
|
|
43
|
+
遇到此扩展会明确拒绝,避免静默丢失几何约束。
|
|
44
|
+
|
|
45
|
+
## 算法及格式验收边界
|
|
46
|
+
|
|
47
|
+
装箱和切割优化属于组合优化,本实现采用时间预算内的多策略启发式,并对
|
|
48
|
+
不超过 16 件的一维小实例做有界搜索;不能据此承诺任意输入全局最优或
|
|
49
|
+
与原引擎逐坐标、逐字节一致。随机种子固定时搜索次序固定;时间预算仍可能
|
|
50
|
+
使不同设备在不同位置停止。
|
|
51
|
+
|
|
52
|
+
PTX 按实际几何重建 1.08 记录及相对分割尺寸,拒绝不可断头布局和一维任务;
|
|
53
|
+
每张布局独立输出模式,未复刻原库的所有模式合并启发式。机床软件的真实
|
|
54
|
+
导入加工验收需在目标控制器进行,单元测试通过不代表实机认证。
|
|
55
|
+
图形输出保留真实斜角轮廓,像素、字体和原库 Windows 图片不要求一致。
|
|
56
|
+
|
|
57
|
+
## 独立验证
|
|
58
|
+
|
|
59
|
+
`validation.assert_valid` 不复用求解器的放置条件,检查输入数量守恒、实例唯一、
|
|
60
|
+
库存不超用、材料匹配、成品尺寸、修边边界、凸多边形重叠与刀线穿件。
|
|
61
|
+
二维测试另将每条刀按前序在剩余子板上重演,检查它确实能够横贯该子板。
|
|
62
|
+
小规模一维使用已知最优 3 根例,规则网格二维使用面积下界验证 2 张最优。
|
|
63
|
+
|
|
64
|
+
回归还包含 5000 件一维、1000 件二维、1100 件 PTX 导出、取消/超时、重复
|
|
65
|
+
运行、并发独立任务、格式转义、PNG CRC、JSON/XML 往返及安装后直接导入调用。
|
|
66
|
+
已将工作区原有 120 组输入及已存原版摘要固化在 `tests/fixtures/legacy_cases.json`,
|
|
67
|
+
测试不会加载 DLL 或访问原来的报告目录。不会把历史摘要冒充本轮重新执行
|
|
68
|
+
原 DLL 的结果。
|
|
69
|
+
|
|
70
|
+
在每组 4 秒预算下,120 组中 104 组返回通过独立核验的结果,16 组明确拒绝。
|
|
71
|
+
旧报告成功的输入,除下面四个有意的输入/精度差异外,均达到原报告的放置件数:
|
|
72
|
+
|
|
73
|
+
- 原版会把 `MaxDecimalPoint=-1/9` 钳制到 0/6;Python 拒绝越界精度。
|
|
74
|
+
- 原版把负原料数量当无限供应;Python 仅以 `count=0` 表示无限。
|
|
75
|
+
- 原版曾将 `49.000001*2+2` 放进长度 100;Python 在 6 位精度下只放一件,
|
|
76
|
+
保持锯缝和原料上限成立。
|
|
77
|
+
|
|
78
|
+
`0.1.0` 曾有 5 组一维随机订单比原报告多用 1 根料。`0.1.1` 已修复升序重复
|
|
79
|
+
贪心缺少局部重排的问题。对未修改原版 5.3.8 的本轮现场重跑,五例在默认与
|
|
80
|
+
统一 1 秒预算下均达到相同件数、根数、总用料和利用率,独立几何核验通过。
|
|
81
|
+
这不证明其它任意输入的全局最优或逐坐标等价。
|
|
82
|
+
|
|
83
|
+
## 0.1.1 文档兼容入口
|
|
84
|
+
|
|
85
|
+
现代 `CutEngine` 的结构化返回保持不变,新增 `CutGLibEngine` 提供手册
|
|
86
|
+
`bool/out`、错误字符串、重载和未用库存查询。`Out.value` 表示引用输出和
|
|
87
|
+
取消标志,不依赖 CLR。`MaxSizePerStock=-1` 现在支持不限组合长度种类。
|
|
88
|
+
`MaxLayoutSize` 只在 `UseLayoutMinimization=True` 时限制分组大小。
|
|
89
|
+
|
|
90
|
+
已按 28 页 PDF 整理 139 项接口声明,并对未修改原 DLL 实际执行全部适用
|
|
91
|
+
方法重载、13 种状态的 9035 次查询、144 个文件/流变体、28 个 PNG 尺寸和
|
|
92
|
+
4 个 PTX 材料/单位样本。完整源快照、测试与逐项证据均在包工程中,离线
|
|
93
|
+
测试不需要 DLL 或原始 PDF。
|
|
94
|
+
|
|
95
|
+
9035 次逐字段查询中,8355 次相同,剩余 680 次差异明确分类为:401 次真实
|
|
96
|
+
布局或实例顺序不同,268 次更安全的异常处理,11 次清空后不泄露旧映射。
|
|
97
|
+
没有把不同方案的可行性检查冒充原版坐标/刀序完全相同。
|
|
98
|
+
DXF 已对齐 R12/Panel_N,PNG 对齐原 DLL 尺寸,PTX 厚度不随单位系数缩放;
|
|
99
|
+
只读 PNG 流写失败会抛异常,避免原版返回 true 的虚假成功。
|
|
100
|
+
|
|
101
|
+
详见 `docs/API_AUDIT.md`、`docs/manual_api_inventory.json` 和
|
|
102
|
+
`docs/api_evidence_summary.json`。原产品机器授权接口不适用于独立实现,
|
|
103
|
+
旧产品版本号、授权容量上限及图片逐像素/通用导出逐字节等价也未作保证。
|
|
104
|
+
|
|
105
|
+
最终 Windows/Linux 测试与干净安装验收见 `VALIDATION.md`。
|
|
106
|
+
|
|
107
|
+
## 0.2.2 差异取舍与修复
|
|
108
|
+
|
|
109
|
+
680 条已知查询差异已逐类审查:268 条明确失败替代原空引用异常,11 条清空旧
|
|
110
|
+
索引/计数,331 条为当前件数、用料和切数相同的合法排样,另 70 条为工艺取舍。
|
|
111
|
+
二维样例的刀线总长 225→220,但最大余料面积 7000→6400,总余料面积不变,
|
|
112
|
+
不能把它称为全面更优。审查仍保留原版逐字段差异,详见 `docs/difference_review.json`。
|
|
113
|
+
|
|
114
|
+
新补方向测试发现的原卷尾段漏报已修正。`Layout.roll_remnants` 单独记录净板以外
|
|
115
|
+
的原卷尾段,扣除截断锯缝并保留输入材料;`all_remnants` 及原有余料查询汇总板内
|
|
116
|
+
余料与尾段,JSON 结果存档完整保存。刀序、图像和 PTX 仍描述本次裁下的净板,
|
|
117
|
+
总利用率也使用净板尺寸。旧结果存档未提供该新增字段时按空元组读取。
|
|
118
|
+
原版方向快照只记录余料数量,未采集尾段坐标;坐标通过独立物理约束验证。
|
|
119
|
+
|
|
120
|
+
版本号标识独立 Python 包,耗时反映本次计算,旧授权规格上限返回 None。
|
|
121
|
+
这些显式适配及全部方向重载已有逐项回归,不伪装原产品版本或授权信息。
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ecode-cutting
|
|
3
|
+
Version: 0.2.3
|
|
4
|
+
Summary: 可直接导入调用的纯 Python 一维与二维切割排料依赖库
|
|
5
|
+
Author: Thorne
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
|
|
9
|
+
# ecode-cutting
|
|
10
|
+
|
|
11
|
+
作者:Thorne。
|
|
12
|
+
|
|
13
|
+
独立的纯 Python 切割排料依赖包,Python 3.11+,运行时只使用标准库。
|
|
14
|
+
安装到调用方项目后,通过 `import ecode_cutting` 在同一进程内计算。
|
|
15
|
+
调用方自行组织服务、路由、鉴权与任务调度;依赖库负责排料算法和结果导出。
|
|
16
|
+
|
|
17
|
+
## 安装与调用
|
|
18
|
+
|
|
19
|
+
在仓库根目录运行 `python -m pip install ./python`,也可以安装构建出的 wheel。
|
|
20
|
+
发布名称为 `ecode-cutting`,导入名称为 `ecode_cutting`。
|
|
21
|
+
当前可安装本地 wheel;发布到 PyPI 后可使用 `python -m pip install ecode-cutting`。
|
|
22
|
+
|
|
23
|
+
完整中文说明见 [使用手册](src/ecode_cutting/USAGE.md),包含参数、方法、结果字段、
|
|
24
|
+
多方案选择、斜角/卷材、导出、存档和兼容入口。手册也随 wheel 安装,可直接读取:
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from importlib.resources import files
|
|
28
|
+
|
|
29
|
+
manual = files("ecode_cutting").joinpath("USAGE.md").read_text(encoding="utf-8")
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from ecode_cutting import CutEngine
|
|
34
|
+
|
|
35
|
+
engine = CutEngine(saw_width=3, trim_left=5, trim_right=5)
|
|
36
|
+
engine.add_linear_stock(6000, 10, id="原料")
|
|
37
|
+
engine.add_linear_part(1200, 20, id="订单A")
|
|
38
|
+
result = engine.execute_linear()
|
|
39
|
+
response = result.to_dict() # JSON 可序列化,直接交给 Web 框架返回
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
二维使用 `add_stock(width, height, count)`、`add_part(width, height, count,
|
|
43
|
+
rotatable=True)` 和 `execute()`。斜角一维通过 `cross_section`、
|
|
44
|
+
`angle_start`、`angle_end` 设置;卷材使用 `set_vertical_cut_direction(True)`
|
|
45
|
+
或 `set_horizontal_cut_direction(True)`。每次请求创建自己的引擎。
|
|
46
|
+
|
|
47
|
+
## 新增快速计算和多方案入口
|
|
48
|
+
|
|
49
|
+
`0.2.0` 保留原来的单方案入口,另增加:
|
|
50
|
+
|
|
51
|
+
- `execute_linear_fast()`:直端大订单采用容量索引;复杂工艺自动回退完整算法。
|
|
52
|
+
- `optimize_linear_plans(...)`:返回多种真实不同的一维方案。
|
|
53
|
+
- `optimize_plans(...)`:返回多种真实不同的二维方案。
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
portfolio = engine.optimize_linear_plans(max_plans=3, time_limit=5, max_searches=12)
|
|
57
|
+
for plan in portfolio.plans:
|
|
58
|
+
m = plan.metrics
|
|
59
|
+
print(plan.id, plan.label, m.utilization_percent, m.used_stock_count, m.cut_count)
|
|
60
|
+
|
|
61
|
+
response = portfolio.to_dict() # 前端展示所有方案,再由客户选择 plan.id
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`metrics.utilization_percent` 是**总有效成品尺寸 / 总已用原料尺寸 × 100**,
|
|
65
|
+
不是各根/各张利用率的平均值。一维按有效长度,二维按真实轮廓面积;斜角
|
|
66
|
+
按多边形实际面积换算有效长度,名义长度指标仍可从原 Result 查询。卷材按
|
|
67
|
+
本次切下的净尺寸计算,不把未切下的整卷当成已耗原料。
|
|
68
|
+
每个方案另列完成率、未完成件数、根数/张数、含修边的切数和不同版式数。
|
|
69
|
+
|
|
70
|
+
返回方案在几何与刀序上去重,最多 `max_plans` 个;唯一方案不会伪造为多个。
|
|
71
|
+
只保留本次达到的最高完成件数,部分完成方案有明确标记。标签和 Pareto
|
|
72
|
+
标志仅比较本次候选,不声称全局最优。所有候选共享预算并保留已得到的
|
|
73
|
+
有效结果;物理工艺约束不放宽。该预算是合作式控制,不承诺硬实时中断。
|
|
74
|
+
|
|
75
|
+
多方案方法不会改写引擎原有输入、配置和已存结果。选择后可直接导出该方案:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from ecode_cutting.exporters import export_csv
|
|
79
|
+
|
|
80
|
+
chosen = portfolio.best # 也可按客户端选定的 id 从 portfolio.plans 中查找
|
|
81
|
+
if chosen is not None:
|
|
82
|
+
export_csv(chosen.result, "chosen.csv")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
快速入口的适用条件、实测性能和验收记录见 `docs/PORTFOLIO.md`。
|
|
86
|
+
|
|
87
|
+
## 按 CutGLib 手册迁移调用
|
|
88
|
+
|
|
89
|
+
原生 `CutEngine` 返回 Python 数据模型。需要手册中的大小写方法、错误字符串和
|
|
90
|
+
`bool/out` 返回契约时,使用同一纯 Python 内核的 `CutGLibEngine`:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from ecode_cutting import CutGLibEngine, Out
|
|
94
|
+
|
|
95
|
+
engine = CutGLibEngine()
|
|
96
|
+
engine.AddLinearStock(6000, 10, "原料")
|
|
97
|
+
engine.AddLinearPart(1200, 20, "订单A")
|
|
98
|
+
error = engine.ExecuteLinear() # 成功返回空字符串
|
|
99
|
+
if error:
|
|
100
|
+
raise RuntimeError(error)
|
|
101
|
+
|
|
102
|
+
stock, length, location, part_id = Out(), Out(), Out(), Out("")
|
|
103
|
+
ok = engine.GetResultLinearPart(0, stock, length, location, part_id)
|
|
104
|
+
print(ok, stock.value, length.value, location.value, part_id.value)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
不传 `Out` 时查询返回 `(成功标志, 输出值...)`,该元组的布尔判断使用成功标志。
|
|
108
|
+
回调的 `ref bool aStop` 写为 `def on_state(stop): stop.value = cancel_event.is_set()`。
|
|
109
|
+
`Clear()` 按原版重置输入和配置;原生 `clear()` 的配置保留行为继续不变。
|
|
110
|
+
兼容入口的库存查询包含未用原料,普通未组合原料的组合数为 0。
|
|
111
|
+
|
|
112
|
+
手册、原 DLL 和 Python 的逐项证据见 `docs/API_AUDIT.md`。版本/旧授权、
|
|
113
|
+
原版异常缺陷、不同排样坐标及导出字节的差异均有明确记录,不能理解为任意
|
|
114
|
+
输入的输出与原版完全相同。
|
|
115
|
+
|
|
116
|
+
## 由其他项目直接调用
|
|
117
|
+
|
|
118
|
+
调用方可以直接传入任务字典并取得计算结果:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from ecode_cutting import CutEngine
|
|
122
|
+
|
|
123
|
+
engine = CutEngine.from_dict({
|
|
124
|
+
"stocks": [{"width": 6000, "count": 10}],
|
|
125
|
+
"parts": [{"width": 1200, "count": 20, "id": "订单A"}],
|
|
126
|
+
"options": {"saw_width": 3, "time_limit": 5},
|
|
127
|
+
})
|
|
128
|
+
output = engine.execute_linear().to_dict()
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
多方案调用同一个引擎的 `optimize_linear_plans(max_plans=3, time_limit=5)`
|
|
132
|
+
或二维的 `optimize_plans(...)`。`output` 和 `portfolio.to_dict()` 均可由
|
|
133
|
+
调用方继续处理、存储或返回。每个独立任务创建自己的引擎。
|
|
134
|
+
|
|
135
|
+
`examples/quickstart.py` 和 `examples/multiple_plans.py` 演示直接导入调用。
|
|
136
|
+
|
|
137
|
+
## 可选的 HTTP 集成测试工具
|
|
138
|
+
|
|
139
|
+
`examples/web_app.py` 保留用于后续联调和测试,手动运行
|
|
140
|
+
`python python/examples/web_app.py` 后,在本机 `127.0.0.1:8000` 提供示例接口。
|
|
141
|
+
`tests/test_web.py` 使用临时端口执行真实 HTTP 测试,结束后自动关闭。
|
|
142
|
+
这些文件位于包源码之外,不进入 wheel;正式接入仍由其他项目直接导入依赖库。
|
|
143
|
+
|
|
144
|
+
## 输入与结果约定
|
|
145
|
+
|
|
146
|
+
- 所有尺寸使用同一种单位;`max_decimal_point` 为 0–6,默认 3。
|
|
147
|
+
内部用整数尺寸计算,舍入采用 ties-to-even。
|
|
148
|
+
- 原料 `count=0` 表示无限供应;零件 `count=0` 表示没有需求。有限库存不超用。
|
|
149
|
+
- 材料编号由 `add_material()` 返回。原料材料 `-1` 可匹配所有材料;
|
|
150
|
+
指定材料的原料不能接收未指定材料的零件。
|
|
151
|
+
- `complete_mode=True` 时,某种零件完全没有可容纳的原料会抛出 `ValidationError`;
|
|
152
|
+
库存数量不足返回部分结果,并在 `unplaced` 中报告全部未完成需求。
|
|
153
|
+
- `Result` 保留每个输入及每个实例的映射,不因布局合并丢失订单明细。
|
|
154
|
+
`fill_ratio` 使用真实成品轮廓面积;斜角共切不会因包围盒重叠而超过 100%。
|
|
155
|
+
`nominal_fill_ratio` 另保留名义长度/包围盒面积指标。旧查询
|
|
156
|
+
`get_layout_fill_ratio()` 在设置截面时按原库的用棒率语义返回。
|
|
157
|
+
- 卷材的 `Layout.remnants` 为净板内余料,`roll_remnants` 为原卷未消耗的尾段,
|
|
158
|
+
以原料坐标记录并扣除截断锯缝;`all_remnants` 和现有余料查询汇总两者。
|
|
159
|
+
总利用率仍按本次切下的净板计算,尾段可交由调用方回收入库。
|
|
160
|
+
- `cuts`、`trim_cuts` 表示锯缝中心线,切割顺序按实际加工前序输出。
|
|
161
|
+
- `time_limit` 为总搜索秒数,`None` 表示无时间限制;回调接收 `Progress`,
|
|
162
|
+
返回 `True` 即请求取消。取消或超时保留已有可行结果并设置标志。
|
|
163
|
+
- 采用有界多策略搜索,提供可行解和小实例优化,不承诺任意输入的全局最优。
|
|
164
|
+
|
|
165
|
+
## 导出与存档
|
|
166
|
+
|
|
167
|
+
`engine.export_csv(target)`、`export_dxf(target)`、`export_cuts_dxf(target)`、
|
|
168
|
+
`export_ptx(target)` 支持文件路径或流。
|
|
169
|
+
`create_stock_image(index, path)` 支持 PNG 和 SVG。
|
|
170
|
+
`to_json()/from_json()`、`to_xml()/from_xml()` 保存及恢复任务;
|
|
171
|
+
`ecode_cutting.serialization` 另提供结果往返。
|
|
172
|
+
|
|
173
|
+
PTX 使用 1.08 记录格式,仅支持二维断头切割,与原库一维 PTX 不支持的边界一致。
|
|
174
|
+
机床控制器的实际适配仍需使用目标设备软件验收。
|
|
175
|
+
Python 存档格式独立版本化;旧 XML 提供可识别任务属性的导入。
|
|
176
|
+
原产品的 COM 注册、Windows 注册表授权和硬件绑定不属于新算法包接口。
|
|
177
|
+
|
|
178
|
+
## 开发验证
|
|
179
|
+
|
|
180
|
+
```text
|
|
181
|
+
python -m pip install -e ./python
|
|
182
|
+
python -m unittest discover -s python/tests -v
|
|
183
|
+
python python/examples/quickstart.py
|
|
184
|
+
python -m pip wheel ./python --no-deps --wheel-dir ./python/dist
|
|
185
|
+
python python/tools/verify_install.py
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
测试包含独立几何与数量核验、断头切割顺序重演、小实例已知最优值、
|
|
189
|
+
斜角轮廓、材料/库存、预算/取消、批量输入、导出解析及独立项目安装调用。
|
|
190
|
+
功能对照与验证说明见 `MIGRATION.md`;变更按 Conventional Commits 本地提交。
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# ecode-cutting
|
|
2
|
+
|
|
3
|
+
作者:Thorne。
|
|
4
|
+
|
|
5
|
+
独立的纯 Python 切割排料依赖包,Python 3.11+,运行时只使用标准库。
|
|
6
|
+
安装到调用方项目后,通过 `import ecode_cutting` 在同一进程内计算。
|
|
7
|
+
调用方自行组织服务、路由、鉴权与任务调度;依赖库负责排料算法和结果导出。
|
|
8
|
+
|
|
9
|
+
## 安装与调用
|
|
10
|
+
|
|
11
|
+
在仓库根目录运行 `python -m pip install ./python`,也可以安装构建出的 wheel。
|
|
12
|
+
发布名称为 `ecode-cutting`,导入名称为 `ecode_cutting`。
|
|
13
|
+
当前可安装本地 wheel;发布到 PyPI 后可使用 `python -m pip install ecode-cutting`。
|
|
14
|
+
|
|
15
|
+
完整中文说明见 [使用手册](src/ecode_cutting/USAGE.md),包含参数、方法、结果字段、
|
|
16
|
+
多方案选择、斜角/卷材、导出、存档和兼容入口。手册也随 wheel 安装,可直接读取:
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from importlib.resources import files
|
|
20
|
+
|
|
21
|
+
manual = files("ecode_cutting").joinpath("USAGE.md").read_text(encoding="utf-8")
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from ecode_cutting import CutEngine
|
|
26
|
+
|
|
27
|
+
engine = CutEngine(saw_width=3, trim_left=5, trim_right=5)
|
|
28
|
+
engine.add_linear_stock(6000, 10, id="原料")
|
|
29
|
+
engine.add_linear_part(1200, 20, id="订单A")
|
|
30
|
+
result = engine.execute_linear()
|
|
31
|
+
response = result.to_dict() # JSON 可序列化,直接交给 Web 框架返回
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
二维使用 `add_stock(width, height, count)`、`add_part(width, height, count,
|
|
35
|
+
rotatable=True)` 和 `execute()`。斜角一维通过 `cross_section`、
|
|
36
|
+
`angle_start`、`angle_end` 设置;卷材使用 `set_vertical_cut_direction(True)`
|
|
37
|
+
或 `set_horizontal_cut_direction(True)`。每次请求创建自己的引擎。
|
|
38
|
+
|
|
39
|
+
## 新增快速计算和多方案入口
|
|
40
|
+
|
|
41
|
+
`0.2.0` 保留原来的单方案入口,另增加:
|
|
42
|
+
|
|
43
|
+
- `execute_linear_fast()`:直端大订单采用容量索引;复杂工艺自动回退完整算法。
|
|
44
|
+
- `optimize_linear_plans(...)`:返回多种真实不同的一维方案。
|
|
45
|
+
- `optimize_plans(...)`:返回多种真实不同的二维方案。
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
portfolio = engine.optimize_linear_plans(max_plans=3, time_limit=5, max_searches=12)
|
|
49
|
+
for plan in portfolio.plans:
|
|
50
|
+
m = plan.metrics
|
|
51
|
+
print(plan.id, plan.label, m.utilization_percent, m.used_stock_count, m.cut_count)
|
|
52
|
+
|
|
53
|
+
response = portfolio.to_dict() # 前端展示所有方案,再由客户选择 plan.id
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`metrics.utilization_percent` 是**总有效成品尺寸 / 总已用原料尺寸 × 100**,
|
|
57
|
+
不是各根/各张利用率的平均值。一维按有效长度,二维按真实轮廓面积;斜角
|
|
58
|
+
按多边形实际面积换算有效长度,名义长度指标仍可从原 Result 查询。卷材按
|
|
59
|
+
本次切下的净尺寸计算,不把未切下的整卷当成已耗原料。
|
|
60
|
+
每个方案另列完成率、未完成件数、根数/张数、含修边的切数和不同版式数。
|
|
61
|
+
|
|
62
|
+
返回方案在几何与刀序上去重,最多 `max_plans` 个;唯一方案不会伪造为多个。
|
|
63
|
+
只保留本次达到的最高完成件数,部分完成方案有明确标记。标签和 Pareto
|
|
64
|
+
标志仅比较本次候选,不声称全局最优。所有候选共享预算并保留已得到的
|
|
65
|
+
有效结果;物理工艺约束不放宽。该预算是合作式控制,不承诺硬实时中断。
|
|
66
|
+
|
|
67
|
+
多方案方法不会改写引擎原有输入、配置和已存结果。选择后可直接导出该方案:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from ecode_cutting.exporters import export_csv
|
|
71
|
+
|
|
72
|
+
chosen = portfolio.best # 也可按客户端选定的 id 从 portfolio.plans 中查找
|
|
73
|
+
if chosen is not None:
|
|
74
|
+
export_csv(chosen.result, "chosen.csv")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
快速入口的适用条件、实测性能和验收记录见 `docs/PORTFOLIO.md`。
|
|
78
|
+
|
|
79
|
+
## 按 CutGLib 手册迁移调用
|
|
80
|
+
|
|
81
|
+
原生 `CutEngine` 返回 Python 数据模型。需要手册中的大小写方法、错误字符串和
|
|
82
|
+
`bool/out` 返回契约时,使用同一纯 Python 内核的 `CutGLibEngine`:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from ecode_cutting import CutGLibEngine, Out
|
|
86
|
+
|
|
87
|
+
engine = CutGLibEngine()
|
|
88
|
+
engine.AddLinearStock(6000, 10, "原料")
|
|
89
|
+
engine.AddLinearPart(1200, 20, "订单A")
|
|
90
|
+
error = engine.ExecuteLinear() # 成功返回空字符串
|
|
91
|
+
if error:
|
|
92
|
+
raise RuntimeError(error)
|
|
93
|
+
|
|
94
|
+
stock, length, location, part_id = Out(), Out(), Out(), Out("")
|
|
95
|
+
ok = engine.GetResultLinearPart(0, stock, length, location, part_id)
|
|
96
|
+
print(ok, stock.value, length.value, location.value, part_id.value)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
不传 `Out` 时查询返回 `(成功标志, 输出值...)`,该元组的布尔判断使用成功标志。
|
|
100
|
+
回调的 `ref bool aStop` 写为 `def on_state(stop): stop.value = cancel_event.is_set()`。
|
|
101
|
+
`Clear()` 按原版重置输入和配置;原生 `clear()` 的配置保留行为继续不变。
|
|
102
|
+
兼容入口的库存查询包含未用原料,普通未组合原料的组合数为 0。
|
|
103
|
+
|
|
104
|
+
手册、原 DLL 和 Python 的逐项证据见 `docs/API_AUDIT.md`。版本/旧授权、
|
|
105
|
+
原版异常缺陷、不同排样坐标及导出字节的差异均有明确记录,不能理解为任意
|
|
106
|
+
输入的输出与原版完全相同。
|
|
107
|
+
|
|
108
|
+
## 由其他项目直接调用
|
|
109
|
+
|
|
110
|
+
调用方可以直接传入任务字典并取得计算结果:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from ecode_cutting import CutEngine
|
|
114
|
+
|
|
115
|
+
engine = CutEngine.from_dict({
|
|
116
|
+
"stocks": [{"width": 6000, "count": 10}],
|
|
117
|
+
"parts": [{"width": 1200, "count": 20, "id": "订单A"}],
|
|
118
|
+
"options": {"saw_width": 3, "time_limit": 5},
|
|
119
|
+
})
|
|
120
|
+
output = engine.execute_linear().to_dict()
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
多方案调用同一个引擎的 `optimize_linear_plans(max_plans=3, time_limit=5)`
|
|
124
|
+
或二维的 `optimize_plans(...)`。`output` 和 `portfolio.to_dict()` 均可由
|
|
125
|
+
调用方继续处理、存储或返回。每个独立任务创建自己的引擎。
|
|
126
|
+
|
|
127
|
+
`examples/quickstart.py` 和 `examples/multiple_plans.py` 演示直接导入调用。
|
|
128
|
+
|
|
129
|
+
## 可选的 HTTP 集成测试工具
|
|
130
|
+
|
|
131
|
+
`examples/web_app.py` 保留用于后续联调和测试,手动运行
|
|
132
|
+
`python python/examples/web_app.py` 后,在本机 `127.0.0.1:8000` 提供示例接口。
|
|
133
|
+
`tests/test_web.py` 使用临时端口执行真实 HTTP 测试,结束后自动关闭。
|
|
134
|
+
这些文件位于包源码之外,不进入 wheel;正式接入仍由其他项目直接导入依赖库。
|
|
135
|
+
|
|
136
|
+
## 输入与结果约定
|
|
137
|
+
|
|
138
|
+
- 所有尺寸使用同一种单位;`max_decimal_point` 为 0–6,默认 3。
|
|
139
|
+
内部用整数尺寸计算,舍入采用 ties-to-even。
|
|
140
|
+
- 原料 `count=0` 表示无限供应;零件 `count=0` 表示没有需求。有限库存不超用。
|
|
141
|
+
- 材料编号由 `add_material()` 返回。原料材料 `-1` 可匹配所有材料;
|
|
142
|
+
指定材料的原料不能接收未指定材料的零件。
|
|
143
|
+
- `complete_mode=True` 时,某种零件完全没有可容纳的原料会抛出 `ValidationError`;
|
|
144
|
+
库存数量不足返回部分结果,并在 `unplaced` 中报告全部未完成需求。
|
|
145
|
+
- `Result` 保留每个输入及每个实例的映射,不因布局合并丢失订单明细。
|
|
146
|
+
`fill_ratio` 使用真实成品轮廓面积;斜角共切不会因包围盒重叠而超过 100%。
|
|
147
|
+
`nominal_fill_ratio` 另保留名义长度/包围盒面积指标。旧查询
|
|
148
|
+
`get_layout_fill_ratio()` 在设置截面时按原库的用棒率语义返回。
|
|
149
|
+
- 卷材的 `Layout.remnants` 为净板内余料,`roll_remnants` 为原卷未消耗的尾段,
|
|
150
|
+
以原料坐标记录并扣除截断锯缝;`all_remnants` 和现有余料查询汇总两者。
|
|
151
|
+
总利用率仍按本次切下的净板计算,尾段可交由调用方回收入库。
|
|
152
|
+
- `cuts`、`trim_cuts` 表示锯缝中心线,切割顺序按实际加工前序输出。
|
|
153
|
+
- `time_limit` 为总搜索秒数,`None` 表示无时间限制;回调接收 `Progress`,
|
|
154
|
+
返回 `True` 即请求取消。取消或超时保留已有可行结果并设置标志。
|
|
155
|
+
- 采用有界多策略搜索,提供可行解和小实例优化,不承诺任意输入的全局最优。
|
|
156
|
+
|
|
157
|
+
## 导出与存档
|
|
158
|
+
|
|
159
|
+
`engine.export_csv(target)`、`export_dxf(target)`、`export_cuts_dxf(target)`、
|
|
160
|
+
`export_ptx(target)` 支持文件路径或流。
|
|
161
|
+
`create_stock_image(index, path)` 支持 PNG 和 SVG。
|
|
162
|
+
`to_json()/from_json()`、`to_xml()/from_xml()` 保存及恢复任务;
|
|
163
|
+
`ecode_cutting.serialization` 另提供结果往返。
|
|
164
|
+
|
|
165
|
+
PTX 使用 1.08 记录格式,仅支持二维断头切割,与原库一维 PTX 不支持的边界一致。
|
|
166
|
+
机床控制器的实际适配仍需使用目标设备软件验收。
|
|
167
|
+
Python 存档格式独立版本化;旧 XML 提供可识别任务属性的导入。
|
|
168
|
+
原产品的 COM 注册、Windows 注册表授权和硬件绑定不属于新算法包接口。
|
|
169
|
+
|
|
170
|
+
## 开发验证
|
|
171
|
+
|
|
172
|
+
```text
|
|
173
|
+
python -m pip install -e ./python
|
|
174
|
+
python -m unittest discover -s python/tests -v
|
|
175
|
+
python python/examples/quickstart.py
|
|
176
|
+
python -m pip wheel ./python --no-deps --wheel-dir ./python/dist
|
|
177
|
+
python python/tools/verify_install.py
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
测试包含独立几何与数量核验、断头切割顺序重演、小实例已知最优值、
|
|
181
|
+
斜角轮廓、材料/库存、预算/取消、批量输入、导出解析及独立项目安装调用。
|
|
182
|
+
功能对照与验证说明见 `MIGRATION.md`;变更按 Conventional Commits 本地提交。
|