feat: 刷新线槽源对应布线路径

dev
Zhaowenlong 3 weeks ago
parent 9318562065
commit ba9d971ef5

@ -588,11 +588,7 @@ def _create_carrier_geometry(doc, name, points):
return obj
def create_route_carrier(doc, points, label="", project_uuid="", kind=ROUTE_CARRIER_KIND, capacity=1):
"""Create a routable carrier from ordered 3D points."""
if doc is None:
raise RoutingNetworkError("No FreeCAD document is available.")
def _normalized_route_points(points):
normalized = []
for point in points or []:
vector = _vector(point)
@ -600,19 +596,47 @@ def create_route_carrier(doc, points, label="", project_uuid="", kind=ROUTE_CARR
continue
if not normalized or _distance(normalized[-1], vector) > DEFAULT_NODE_TOLERANCE:
normalized.append(vector)
return normalized
if len(normalized) < 2:
raise RoutingNetworkError("A route carrier requires at least two distinct points.")
name = _unique_name(doc, "QETRouteCarrier")
carrier = _create_carrier_geometry(doc, name, normalized)
carrier.Label = label or "QET Route Carrier"
def _set_route_carrier_points(carrier, points):
_ensure_vector_list_property(
carrier,
"Points",
"Ordered centerline points used by the 3D router",
)
carrier.Points = list(normalized)
carrier.Points = list(points)
try:
import Part
carrier.Shape = Part.makePolygon(points)
except Exception:
pass
def _update_route_carrier(carrier, points, project_uuid="", kind=ROUTE_CARRIER_KIND, capacity=1):
normalized = _normalized_route_points(points)
if len(normalized) < 2:
return False
_set_route_carrier_points(carrier, normalized)
_set_route_carrier_semantics(carrier, project_uuid=project_uuid, kind=kind, capacity=capacity)
_style_route_carrier(carrier, kind)
return True
def create_route_carrier(doc, points, label="", project_uuid="", kind=ROUTE_CARRIER_KIND, capacity=1):
"""Create a routable carrier from ordered 3D points."""
if doc is None:
raise RoutingNetworkError("No FreeCAD document is available.")
normalized = _normalized_route_points(points)
if len(normalized) < 2:
raise RoutingNetworkError("A route carrier requires at least two distinct points.")
name = _unique_name(doc, "QETRouteCarrier")
carrier = _create_carrier_geometry(doc, name, normalized)
carrier.Label = label or "QET Route Carrier"
_set_route_carrier_points(carrier, normalized)
_set_route_carrier_semantics(carrier, project_uuid=project_uuid, kind=kind, capacity=capacity)
group = WiringObjects.ensure_carrier_group(doc, project_uuid)
@ -1396,6 +1420,40 @@ 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):
carriers = _live_source_carriers(doc, source)
if not carriers:
return False
desired = [
(spec.get("centerline", []), ROUTE_CARRIER_KIND_WIRE_DUCT),
]
desired.extend(
(points, ROUTE_CARRIER_KIND_WIRE_DUCT_OPEN_END)
for points in (spec.get("open_ends", []) or [])
)
updated = []
for carrier, desired_item in zip(carriers, desired):
points, kind = desired_item
if _update_route_carrier(
carrier,
points,
project_uuid=project_uuid,
kind=kind,
capacity=capacity,
):
updated.append(carrier)
if updated:
_mark_wire_duct_source(source, updated[0], updated)
try:
doc.recompute()
except Exception:
pass
return True
def _wiring_cut_out_points_from_bbox(bbox):
extents = _bbox_extents(bbox)
if not extents:
@ -1436,7 +1494,57 @@ def _wire_duct_sources_from_selection(selection_ex):
return sources
def _mark_wire_duct_source(source, carrier):
def _route_source_carrier_names(source):
names = []
try:
raw = (getattr(source, "QetRouteCarrierNamesJson", "") or "").strip()
if raw:
parsed = json.loads(raw)
if isinstance(parsed, list):
names.extend(str(item).strip() for item in parsed if str(item).strip())
except Exception:
names = []
carrier_name = (getattr(source, "QetRouteCarrierName", "") or "").strip()
if carrier_name:
names.insert(0, carrier_name)
result = []
seen = set()
for name in names:
if name in seen:
continue
seen.add(name)
result.append(name)
return result
def _live_source_carriers(doc, source):
if doc is None or source is None:
return []
carriers = []
for carrier_name in _route_source_carrier_names(source):
carrier = doc.getObject(carrier_name)
if carrier is not None and is_route_carrier(carrier):
carriers.append(carrier)
return carriers
def _remember_source_carriers(source, carriers):
live_names = [
getattr(carrier, "Name", "")
for carrier in (carriers or [])
if carrier is not None and getattr(carrier, "Name", "")
]
if live_names:
TerminalObjects.ensure_string_property(
source,
"QetRouteCarrierNamesJson",
PROPERTY_GROUP,
"Generated route carriers for this source",
json.dumps(live_names, ensure_ascii=False),
)
def _mark_wire_duct_source(source, carrier, carriers=None):
if source is None:
return
try:
@ -1449,6 +1557,7 @@ def _mark_wire_duct_source(source, carrier):
"Generated route carrier for this source",
getattr(carrier, "Name", ""),
)
_remember_source_carriers(source, carriers or ([carrier] if carrier is not None else []))
except Exception:
pass
@ -1508,13 +1617,8 @@ def _mark_terminal_access_source(source, carrier):
def _live_source_carrier(doc, source):
carrier_name = (getattr(source, "QetRouteCarrierName", "") or "").strip()
if not carrier_name or doc is None:
return None
carrier = doc.getObject(carrier_name)
if carrier is not None and is_route_carrier(carrier):
return carrier
return None
carriers = _live_source_carriers(doc, source)
return carriers[0] if carriers else None
def detect_wire_duct_sources(doc, min_aspect=DEFAULT_AUTO_WIRE_DUCT_MIN_ASPECT):
@ -1610,8 +1714,6 @@ def create_wire_duct_carriers_from_document(
"""Auto-detect wire duct objects in the document and create WireDuct centerlines."""
created = []
for index, source in enumerate(detect_wire_duct_sources(doc, min_aspect=min_aspect), start=1):
if _live_source_carrier(doc, source) is not None:
continue
bbox = _bound_box_from_object(source)
if bbox is None:
continue
@ -1625,6 +1727,14 @@ def create_wire_duct_carriers_from_document(
continue
label = getattr(source, "Label", "") or getattr(source, "Name", "") or "Wire Duct"
capacity = _route_carrier_capacity_value(source, default=1)
if _sync_wire_duct_source_carriers(
doc,
source,
spec,
project_uuid=project_uuid,
capacity=capacity,
):
continue
carrier = create_route_carrier(
doc,
points,
@ -1633,21 +1743,22 @@ def create_wire_duct_carriers_from_document(
kind=ROUTE_CARRIER_KIND_WIRE_DUCT,
capacity=capacity,
)
_mark_wire_duct_source(source, carrier)
source_created = [carrier]
created.append(carrier)
for end_index, open_end_points in enumerate(spec.get("open_ends", []) or [], start=1):
if len(open_end_points) < 2:
continue
created.append(
create_route_carrier(
doc,
open_end_points,
label="QET Auto Wire Duct Open End {0} {1}".format(label, end_index),
project_uuid=project_uuid,
kind=ROUTE_CARRIER_KIND_WIRE_DUCT_OPEN_END,
capacity=capacity,
)
open_end_carrier = create_route_carrier(
doc,
open_end_points,
label="QET Auto Wire Duct Open End {0} {1}".format(label, end_index),
project_uuid=project_uuid,
kind=ROUTE_CARRIER_KIND_WIRE_DUCT_OPEN_END,
capacity=capacity,
)
source_created.append(open_end_carrier)
created.append(open_end_carrier)
_mark_wire_duct_source(source, carrier, source_created)
return created
@ -1916,8 +2027,6 @@ def create_wire_duct_carriers_from_selection(
"""Create WireDuct centerline carriers from selected duct-like solids."""
created = []
for index, source in enumerate(_wire_duct_sources_from_selection(selection_ex), start=1):
if _live_source_carrier(doc, source) is not None:
continue
bbox = _bound_box_from_object(source)
if bbox is None:
continue
@ -1931,6 +2040,14 @@ def create_wire_duct_carriers_from_selection(
continue
label = getattr(source, "Label", "") or getattr(source, "Name", "") or "Wire Duct"
capacity = _route_carrier_capacity_value(source, default=1)
if _sync_wire_duct_source_carriers(
doc,
source,
spec,
project_uuid=project_uuid,
capacity=capacity,
):
continue
carrier = create_route_carrier(
doc,
points,
@ -1939,21 +2056,22 @@ def create_wire_duct_carriers_from_selection(
kind=ROUTE_CARRIER_KIND_WIRE_DUCT,
capacity=capacity,
)
_mark_wire_duct_source(source, carrier)
source_created = [carrier]
created.append(carrier)
for end_index, open_end_points in enumerate(spec.get("open_ends", []) or [], start=1):
if len(open_end_points) < 2:
continue
created.append(
create_route_carrier(
doc,
open_end_points,
label="QET Wire Duct Open End {0} {1}".format(label, end_index),
project_uuid=project_uuid,
kind=ROUTE_CARRIER_KIND_WIRE_DUCT_OPEN_END,
capacity=capacity,
)
open_end_carrier = create_route_carrier(
doc,
open_end_points,
label="QET Wire Duct Open End {0} {1}".format(label, end_index),
project_uuid=project_uuid,
kind=ROUTE_CARRIER_KIND_WIRE_DUCT_OPEN_END,
capacity=capacity,
)
source_created.append(open_end_carrier)
created.append(open_end_carrier)
_mark_wire_duct_source(source, carrier, source_created)
return created

@ -947,6 +947,38 @@ class AutoRoutingTest(unittest.TestCase):
len([item for item in carriers if item.QetRouteCarrierKind == "WireDuctOpenEnd"]),
)
def test_generate_routing_paths_refreshes_selected_wire_duct_geometry(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"]
gui = sys.modules["FreeCADGui"]
doc = FakeDocument()
app.ActiveDocument = doc
terminal_objects.ensure_root_group(doc, "project-1")
duct = doc.addObject("Part::Feature", "UnlabeledLongDuct")
duct.Shape = FakeShape(FakeBoundBox(0, 160, -10, 10, 0, 20))
gui.Selection = types.SimpleNamespace(
getSelection=lambda: [],
getSelectionEx=lambda: [FakeSelectionItem(obj=duct)],
)
auto_routing_panel.AutoRoutingController().generate_routing_paths()
duct.Shape = FakeShape(FakeBoundBox(0, 220, -10, 10, 0, 20))
second = auto_routing_panel.AutoRoutingController().generate_routing_paths()
carriers = routing_network.collect_route_carriers(doc)
main = [item for item in carriers if item.QetRouteCarrierKind == "WireDuct"][0]
open_end_x_values = sorted(
point.x
for item in carriers
if item.QetRouteCarrierKind == "WireDuctOpenEnd"
for point in item.Points
)
self.assertEqual(0, second["selected_wire_duct_carriers"])
self.assertEqual([(20.0, 0.0, 10.0), (200.0, 0.0, 10.0)], [(p.x, p.y, p.z) for p in main.Points])
self.assertEqual([20.0, 20.0, 200.0, 200.0], open_end_x_values)
def test_prepare_layout_space_uses_whole_document_not_selected_face_workflow(self):
_install_fake_freecad()
terminal_objects, _wiring_objects, _routing_network, _auto_routing = _reload_modules()

Loading…
Cancel
Save