From 71e2fec765189bf8304cf0790b5d3267d09526bf Mon Sep 17 00:00:00 2001 From: Zhaowenlong Date: Mon, 1 Jun 2026 17:25:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=9D=A2=E6=9D=BF=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=B9=B6=E8=A1=8C=E7=BA=BF=E9=97=B4=E8=B7=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/FreeCAD 3D自动布线设计方案.md | 3 ++ src/Mod/FreeCADExchange/AutoRoutingPanel.py | 22 ++++++++++ .../freecad_exchange_auto_routing_test.py | 42 +++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/docs/FreeCAD 3D自动布线设计方案.md b/docs/FreeCAD 3D自动布线设计方案.md index 8d6ab5b..f723d4a 100644 --- a/docs/FreeCAD 3D自动布线设计方案.md +++ b/docs/FreeCAD 3D自动布线设计方案.md @@ -91,6 +91,8 @@ FreeCAD 的 `3D 布线连接` 面板提供“线槽桥接容差 mm”数值框 同一面板还提供“端子接入最大距离 mm”和“端子出线长度 mm”。前者用于控制端子距离最近路由网络超过多少毫米时不再生成 `TerminalAccess`,避免设备还没摆放好时生成超长悬空接入线;后者用于控制端子沿 LCS 出线方向先走出的短线长度,避免导线从设备壳体内部或端子原点直接折返。 +面板还提供“并行线间距 mm”,用于控制多根导线共用同一路径时的可视 lane 偏移距离。它只影响 3D 显示上导线之间的错位间距,不代表真实线槽截面内的排布位置。 + ### 2.1 路由优先级 当前版本按下面优先级处理: @@ -460,6 +462,7 @@ tests/python/freecad_exchange_auto_routing_test.py 34. 批量布线报告会显示最大 lane 编号和 lane 间距,方便确认多根线共路时是否发生了可视错位。 35. `QetRouteTrackJson` 的 carrier payload 会记录 `capacity`,方便后续分析线槽容量偏好和共路绕行。 36. 批量布线报告会在最大并行线数超过路径最小容量时显示容量提示,但当前仍不做真实填充率计算。 +37. `3D 布线连接` 面板提供“并行线间距 mm”设置,用于调整多线共路时的可视 lane 偏移距离。 已完成 FreeCAD smoke: diff --git a/src/Mod/FreeCADExchange/AutoRoutingPanel.py b/src/Mod/FreeCADExchange/AutoRoutingPanel.py index 5d8dbcd..858e5f2 100644 --- a/src/Mod/FreeCADExchange/AutoRoutingPanel.py +++ b/src/Mod/FreeCADExchange/AutoRoutingPanel.py @@ -99,6 +99,13 @@ class AutoRoutingController: exit_length = AutoRouting.DEFAULT_OPTIONS["terminal_exit_length"] self.options["terminal_exit_length"] = max(exit_length, 0.0) + def set_lane_spacing(self, value): + try: + lane_spacing = float(value) + except Exception: + lane_spacing = AutoRouting.DEFAULT_OPTIONS["lane_spacing"] + self.options["lane_spacing"] = max(lane_spacing, 0.0) + def summary(self): doc = _active_document() terminal_count = len(AutoRouting.index_terminals(doc)) @@ -267,6 +274,20 @@ class AutoRoutingTaskPanel: ) ) options_layout.addWidget(self.terminal_exit_length_spin) + options_layout.addWidget(QtWidgets.QLabel("并行线间距 mm")) + self.lane_spacing_spin = QtWidgets.QDoubleSpinBox() + self.lane_spacing_spin.setRange(0.0, 1000.0) + self.lane_spacing_spin.setDecimals(1) + self.lane_spacing_spin.setSingleStep(1.0) + self.lane_spacing_spin.setValue( + float( + self.controller.routing_options().get( + "lane_spacing", + AutoRouting.DEFAULT_OPTIONS["lane_spacing"], + ) + ) + ) + options_layout.addWidget(self.lane_spacing_spin) self.generate_layout_button = QtWidgets.QPushButton("准备布线布局空间") self.generate_layout_button.setToolTip( @@ -337,6 +358,7 @@ class AutoRoutingTaskPanel: self.controller.set_adjoining_duct_tolerance(self.adjoining_duct_tolerance_spin.value()) self.controller.set_terminal_access_max_distance(self.terminal_access_max_distance_spin.value()) self.controller.set_terminal_exit_length(self.terminal_exit_length_spin.value()) + self.controller.set_lane_spacing(self.lane_spacing_spin.value()) def generate_routing_paths(self): try: diff --git a/tests/python/freecad_exchange_auto_routing_test.py b/tests/python/freecad_exchange_auto_routing_test.py index aacca32..91c27a2 100644 --- a/tests/python/freecad_exchange_auto_routing_test.py +++ b/tests/python/freecad_exchange_auto_routing_test.py @@ -1729,6 +1729,48 @@ class AutoRoutingTest(unittest.TestCase): self.assertIn("桥接:1", summary) + def test_auto_routing_controller_exposes_lane_spacing(self): + _install_fake_freecad() + terminal_objects, _wiring_objects, routing_network, _auto_routing = _reload_modules() + auto_routing_panel = importlib.import_module("AutoRoutingPanel") + app = sys.modules["FreeCAD"] + doc = FakeDocument() + app.ActiveDocument = doc + terminal_objects.ensure_root_group(doc, "project-1") + _terminal(doc, terminal_objects, "TerminalStartA", "terminal-start-a", app.Vector(0, 0, 0)) + _terminal(doc, terminal_objects, "TerminalEndA", "terminal-end-a", app.Vector(100, 0, 0)) + _terminal(doc, terminal_objects, "TerminalStartB", "terminal-start-b", app.Vector(0, 0, 0)) + _terminal(doc, terminal_objects, "TerminalEndB", "terminal-end-b", app.Vector(100, 0, 0)) + routing_network.create_route_carrier( + doc, + [app.Vector(0, 0, 20), app.Vector(100, 0, 20)], + project_uuid="project-1", + kind="WireDuct", + ) + app._qet_exchange_payload = { + "project_uuid": "project-1", + "wires": [ + { + "wire_id": "wire-a", + "start_terminal_uuid": "terminal-start-a", + "end_terminal_uuid": "terminal-end-a", + }, + { + "wire_id": "wire-b", + "start_terminal_uuid": "terminal-start-b", + "end_terminal_uuid": "terminal-end-b", + }, + ], + } + + controller = auto_routing_panel.AutoRoutingController() + controller.set_lane_spacing(14.0) + report = controller.route_eplan_connections() + + self.assertEqual(14.0, controller.routing_options()["lane_spacing"]) + self.assertEqual(14.0, report["routes"][1]["lane"]["spacing_mm"]) + self.assertEqual(14.0, report["routes"][1]["lane"]["offset_mm"]) + def test_eplan_connection_route_rejects_far_network_entry_to_avoid_huge_render_bbox(self): _install_fake_freecad() terminal_objects, _wiring_objects, routing_network, auto_routing = _reload_modules()