diff --git a/docs/FreeCAD 3D自动布线设计方案.md b/docs/FreeCAD 3D自动布线设计方案.md index 50ac511..2965f04 100644 --- a/docs/FreeCAD 3D自动布线设计方案.md +++ b/docs/FreeCAD 3D自动布线设计方案.md @@ -195,8 +195,11 @@ QetAutoRouteDiagnosticsJson QetRoutingSourceKind = "WireDuct" QetRoutingObstacleMode = "PassThrough" QetRouteCarrierName = +QetWireDuctEndMarginMm = 20.0 ``` +`QetWireDuctEndMarginMm` 表示自动生成的线槽中心线距离线槽两端缩进多少毫米。默认值用于避开线槽端盖/端部开口;如果某个线槽很短,或现场希望中心路径更靠近端部,可以在 FreeCAD 属性面板中按对象调整。 + ## 4. 算法设计 ### 4.1 路由网络构建 @@ -425,6 +428,7 @@ tests/python/freecad_exchange_auto_routing_test.py 25. `WiringCutOut` 会在穿孔方向外扩虚拟路径,用于桥接开孔两侧附近的线槽或支撑面网络,并支持通过 `QetWiringCutOutBridgeExtensionMm` 按对象调整外扩距离。 26. `QetRouteTrackJson` 会在 carrier 有源对象元数据时保存 `source_name`、`source_label`、`source_kind`,方便核对导线实际走过的线槽、过线孔或支撑面。 27. 批量布线报告会显示一条路径示例,列出首条可追踪导线经过的源对象标签。 +28. 线槽源对象支持通过 `QetWireDuctEndMarginMm` 按对象调整中心路径端部缩进距离。 已完成 FreeCAD smoke: diff --git a/src/Mod/FreeCADExchange/RoutingNetwork.py b/src/Mod/FreeCADExchange/RoutingNetwork.py index bbe6427..26da3be 100644 --- a/src/Mod/FreeCADExchange/RoutingNetwork.py +++ b/src/Mod/FreeCADExchange/RoutingNetwork.py @@ -502,7 +502,17 @@ def _route_carrier_capacity_value(obj, default=1): return int(default or 1) -def _set_wire_duct_source_semantics(source): +def _wire_duct_end_margin_value(source, default=DEFAULT_WIRE_DUCT_MARGIN): + try: + value = float(getattr(source, "QetWireDuctEndMarginMm", default) or 0.0) + except Exception: + value = float(default or 0.0) + if value < 0.0: + return 0.0 + return value + + +def _set_wire_duct_source_semantics(source, end_margin=DEFAULT_WIRE_DUCT_MARGIN): if source is None: return TerminalObjects.ensure_string_property( @@ -525,6 +535,12 @@ def _set_wire_duct_source_semantics(source): "How many routed wires can reuse generated wire duct segments before detouring is preferred", _route_carrier_capacity_value(source, default=1), ) + _ensure_float_property( + source, + "QetWireDuctEndMarginMm", + "How far generated wire duct centerlines stay inside each duct end", + _wire_duct_end_margin_value(source, default=end_margin), + ) def _set_support_surface_source_semantics(source): @@ -1463,7 +1479,14 @@ def _wire_duct_centerline_from_bbox(bbox, margin=DEFAULT_WIRE_DUCT_MARGIN, min_a ).get("centerline", []) -def _sync_wire_duct_source_carriers(doc, source, spec, project_uuid="", capacity=1): +def _sync_wire_duct_source_carriers( + doc, + source, + spec, + project_uuid="", + capacity=1, + end_margin=DEFAULT_WIRE_DUCT_MARGIN, +): carriers = _live_source_carriers(doc, source) if not carriers: return False @@ -1489,7 +1512,7 @@ def _sync_wire_duct_source_carriers(doc, source, spec, project_uuid="", capacity updated.append(carrier) if updated: - _mark_wire_duct_source(source, updated[0], updated) + _mark_wire_duct_source(source, updated[0], updated, end_margin=end_margin) try: doc.recompute() except Exception: @@ -1627,11 +1650,11 @@ def _remember_source_carriers(source, carriers): ) -def _mark_wire_duct_source(source, carrier, carriers=None): +def _mark_wire_duct_source(source, carrier, carriers=None, end_margin=DEFAULT_WIRE_DUCT_MARGIN): if source is None: return try: - _set_wire_duct_source_semantics(source) + _set_wire_duct_source_semantics(source, end_margin=end_margin) if carrier is not None: TerminalObjects.ensure_string_property( source, @@ -1876,9 +1899,10 @@ def create_wire_duct_carriers_from_document( bbox = _bound_box_from_object(source) if bbox is None: continue + source_margin = _wire_duct_end_margin_value(source, default=margin) spec = _wire_duct_centerline_spec_from_bbox( bbox, - margin=margin, + margin=source_margin, min_aspect=min_aspect, ) points = spec.get("centerline", []) @@ -1892,6 +1916,7 @@ def create_wire_duct_carriers_from_document( spec, project_uuid=project_uuid, capacity=capacity, + end_margin=source_margin, ): continue carrier = create_route_carrier( @@ -1917,7 +1942,7 @@ def create_wire_duct_carriers_from_document( ) source_created.append(open_end_carrier) created.append(open_end_carrier) - _mark_wire_duct_source(source, carrier, source_created) + _mark_wire_duct_source(source, carrier, source_created, end_margin=source_margin) return created @@ -2247,9 +2272,10 @@ def create_wire_duct_carriers_from_selection( bbox = _bound_box_from_object(source) if bbox is None: continue + source_margin = _wire_duct_end_margin_value(source, default=margin) spec = _wire_duct_centerline_spec_from_bbox( bbox, - margin=margin, + margin=source_margin, min_aspect=min_aspect, ) points = spec.get("centerline", []) @@ -2263,6 +2289,7 @@ def create_wire_duct_carriers_from_selection( spec, project_uuid=project_uuid, capacity=capacity, + end_margin=source_margin, ): continue carrier = create_route_carrier( @@ -2288,7 +2315,7 @@ def create_wire_duct_carriers_from_selection( ) source_created.append(open_end_carrier) created.append(open_end_carrier) - _mark_wire_duct_source(source, carrier, source_created) + _mark_wire_duct_source(source, carrier, source_created, end_margin=source_margin) return created diff --git a/tests/python/freecad_exchange_auto_routing_test.py b/tests/python/freecad_exchange_auto_routing_test.py index 1cf7c64..b2ab08d 100644 --- a/tests/python/freecad_exchange_auto_routing_test.py +++ b/tests/python/freecad_exchange_auto_routing_test.py @@ -1648,6 +1648,26 @@ class AutoRoutingTest(unittest.TestCase): self.assertEqual("PassThrough", duct.QetRoutingObstacleMode) self.assertEqual([(20.0, 0.0, 15.0), (100.0, 0.0, 15.0)], [(p.x, p.y, p.z) for p in carrier.Points]) + def test_wire_duct_source_end_margin_controls_generated_centerline_length(self): + _install_fake_freecad() + terminal_objects, _wiring_objects, routing_network, _auto_routing = _reload_modules() + doc = FakeDocument() + terminal_objects.ensure_root_group(doc, "project-1") + duct = doc.addObject("Part::Feature", "WireDuctA") + duct.Label = "线槽A" + duct.Shape = FakeShape(FakeBoundBox(0, 120, -10, 10, 5, 25)) + duct.QetWireDuctEndMarginMm = 5.0 + + created = routing_network.create_wire_duct_carriers_from_document( + doc, + project_uuid="project-1", + ) + + carrier = [item for item in created if item.QetRouteCarrierKind == "WireDuct"][0] + self.assertIn("QetWireDuctEndMarginMm", duct.PropertiesList) + self.assertEqual(5.0, duct.QetWireDuctEndMarginMm) + self.assertEqual([(5.0, 0.0, 15.0), (115.0, 0.0, 15.0)], [(p.x, p.y, p.z) for p in carrier.Points]) + def test_wire_duct_source_capacity_is_copied_to_generated_carriers(self): _install_fake_freecad() terminal_objects, _wiring_objects, routing_network, _auto_routing = _reload_modules()