diff --git a/docs/FreeCAD 3D自动布线设计方案.md b/docs/FreeCAD 3D自动布线设计方案.md index f723d4a..0ca4427 100644 --- a/docs/FreeCAD 3D自动布线设计方案.md +++ b/docs/FreeCAD 3D自动布线设计方案.md @@ -91,7 +91,7 @@ FreeCAD 的 `3D 布线连接` 面板提供“线槽桥接容差 mm”数值框 同一面板还提供“端子接入最大距离 mm”和“端子出线长度 mm”。前者用于控制端子距离最近路由网络超过多少毫米时不再生成 `TerminalAccess`,避免设备还没摆放好时生成超长悬空接入线;后者用于控制端子沿 LCS 出线方向先走出的短线长度,避免导线从设备壳体内部或端子原点直接折返。 -面板还提供“并行线间距 mm”,用于控制多根导线共用同一路径时的可视 lane 偏移距离。它只影响 3D 显示上导线之间的错位间距,不代表真实线槽截面内的排布位置。 +面板还提供“并行线间距 mm”和“并行线方向”,用于控制多根导线共用同一路径时的可视 lane 偏移。方向默认 `auto`,也可以手动指定 `x`、`y`、`z`。这些设置只影响 3D 显示上导线之间的错位方式,不代表真实线槽截面内的排布位置。 ### 2.1 路由优先级 @@ -462,7 +462,7 @@ tests/python/freecad_exchange_auto_routing_test.py 34. 批量布线报告会显示最大 lane 编号和 lane 间距,方便确认多根线共路时是否发生了可视错位。 35. `QetRouteTrackJson` 的 carrier payload 会记录 `capacity`,方便后续分析线槽容量偏好和共路绕行。 36. 批量布线报告会在最大并行线数超过路径最小容量时显示容量提示,但当前仍不做真实填充率计算。 -37. `3D 布线连接` 面板提供“并行线间距 mm”设置,用于调整多线共路时的可视 lane 偏移距离。 +37. `3D 布线连接` 面板提供“并行线间距 mm”和“并行线方向”设置,用于调整多线共路时的可视 lane 偏移。 已完成 FreeCAD smoke: diff --git a/src/Mod/FreeCADExchange/AutoRoutingPanel.py b/src/Mod/FreeCADExchange/AutoRoutingPanel.py index 858e5f2..97e444f 100644 --- a/src/Mod/FreeCADExchange/AutoRoutingPanel.py +++ b/src/Mod/FreeCADExchange/AutoRoutingPanel.py @@ -106,6 +106,12 @@ class AutoRoutingController: lane_spacing = AutoRouting.DEFAULT_OPTIONS["lane_spacing"] self.options["lane_spacing"] = max(lane_spacing, 0.0) + def set_lane_axis(self, value): + lane_axis = str(value or "").strip().lower() + if lane_axis not in {"auto", "x", "y", "z"}: + lane_axis = AutoRouting.DEFAULT_OPTIONS["lane_axis"] + self.options["lane_axis"] = lane_axis + def summary(self): doc = _active_document() terminal_count = len(AutoRouting.index_terminals(doc)) @@ -288,6 +294,19 @@ class AutoRoutingTaskPanel: ) ) options_layout.addWidget(self.lane_spacing_spin) + options_layout.addWidget(QtWidgets.QLabel("并行线方向")) + self.lane_axis_combo = QtWidgets.QComboBox() + self.lane_axis_combo.addItems(["auto", "x", "y", "z"]) + lane_axis = str( + self.controller.routing_options().get( + "lane_axis", + AutoRouting.DEFAULT_OPTIONS["lane_axis"], + ) + or "auto" + ).lower() + axis_index = self.lane_axis_combo.findText(lane_axis) + self.lane_axis_combo.setCurrentIndex(axis_index if axis_index >= 0 else 0) + options_layout.addWidget(self.lane_axis_combo) self.generate_layout_button = QtWidgets.QPushButton("准备布线布局空间") self.generate_layout_button.setToolTip( @@ -359,6 +378,7 @@ class AutoRoutingTaskPanel: 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()) + self.controller.set_lane_axis(self.lane_axis_combo.currentText()) 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 91c27a2..923a858 100644 --- a/tests/python/freecad_exchange_auto_routing_test.py +++ b/tests/python/freecad_exchange_auto_routing_test.py @@ -1771,6 +1771,49 @@ class AutoRoutingTest(unittest.TestCase): self.assertEqual(14.0, report["routes"][1]["lane"]["spacing_mm"]) self.assertEqual(14.0, report["routes"][1]["lane"]["offset_mm"]) + def test_auto_routing_controller_exposes_lane_axis(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(0, 100, 0)) + _terminal(doc, terminal_objects, "TerminalStartB", "terminal-start-b", app.Vector(0, 0, 0)) + _terminal(doc, terminal_objects, "TerminalEndB", "terminal-end-b", app.Vector(0, 100, 0)) + routing_network.create_route_carrier( + doc, + [app.Vector(0, 0, 20), app.Vector(0, 100, 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(8.0) + controller.set_lane_axis("z") + report = controller.route_eplan_connections() + + self.assertEqual("z", controller.routing_options()["lane_axis"]) + self.assertEqual("z", report["routes"][1]["lane"]["axis"]) + self.assertEqual(8.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()