fix: 优化端子复用和手动布线导入

dev
Zhaowenlong 20 hours ago
parent 44c2e448b5
commit 20bcaf18e4

@ -149,18 +149,14 @@ def _orthogonal_segment_points(start_point, end_point, preferred_axis=None):
if _vector_close(start_point, end_point):
return [start_point]
axis_order = []
if preferred_axis in {"x", "y", "z"}:
axis_order.append(preferred_axis)
remaining = sorted(
axis_order = sorted(
("x", "y", "z"),
key=lambda axis: abs(_axis_value(end_point, axis) - _axis_value(start_point, axis)),
reverse=True,
)
for axis in remaining:
if axis not in axis_order:
axis_order.append(axis)
if preferred_axis in {"x", "y", "z"} and preferred_axis in axis_order:
axis_order = [axis for axis in axis_order if axis != preferred_axis]
axis_order.append(preferred_axis)
points = [start_point]
current = start_point
@ -220,6 +216,24 @@ def _manual_waypoints_payload(waypoints):
return payload
def _append_unique_point(points, point):
if not points or not _vector_close(points[-1], point):
points.append(point)
def _append_orthogonal_segment(points, target_point, preferred_axis=None):
if not points:
points.append(target_point)
return
segment = _orthogonal_segment_points(
points[-1],
target_point,
preferred_axis=preferred_axis,
)
for point in segment[1:]:
_append_unique_point(points, point)
def _terminal_points(start_terminal, end_terminal, waypoints=None, terminal_exit_length=0.0):
start_origin = TerminalObjects.terminal_origin(start_terminal)
end_origin = TerminalObjects.terminal_origin(end_terminal)
@ -228,7 +242,8 @@ def _terminal_points(start_terminal, end_terminal, waypoints=None, terminal_exit
points = [start_origin]
normalized_waypoints = []
if exit_length > 0:
points.append(
_append_unique_point(
points,
_offset_point(
start_origin,
_terminal_exit_direction(start_terminal),
@ -241,8 +256,11 @@ def _terminal_points(start_terminal, end_terminal, waypoints=None, terminal_exit
if waypoint is None:
continue
normalized_waypoints.append(waypoint)
if not _vector_close(points[-1], waypoint["point"]):
points.append(waypoint["point"])
_append_orthogonal_segment(
points,
waypoint["point"],
preferred_axis=waypoint.get("support_axis"),
)
if exit_length > 0:
end_exit = _offset_point(
@ -250,10 +268,10 @@ def _terminal_points(start_terminal, end_terminal, waypoints=None, terminal_exit
_terminal_exit_direction(end_terminal),
exit_length,
)
if not _vector_close(points[-1], end_exit):
points.append(end_exit)
if len(points) < 2 or not _vector_close(points[-1], end_origin):
points.append(end_origin)
_append_orthogonal_segment(points, end_exit)
_append_unique_point(points, end_origin)
else:
_append_orthogonal_segment(points, end_origin)
return points, normalized_waypoints
@ -374,6 +392,17 @@ def _wire_parent_group(doc, project_uuid, start_terminal, end_terminal, fallback
return fallback_group
def _is_legacy_wire_group(group):
if group is None:
return False
if getattr(group, "Name", "").startswith(TerminalObjects.WIRE_GROUP_PREFIX):
return True
return (
(getattr(group, "QetGroupKind", "") or "").strip()
== TerminalObjects.WIRE_GROUP_KIND
)
def create_manual_wire(
doc,
start_terminal,
@ -437,10 +466,6 @@ def create_manual_wire(
manual_waypoints=normalized_waypoints,
)
routed_group = WiringObjects.ensure_routed_group(doc, project_uuid)
if wire_obj not in getattr(routed_group, "Group", []):
routed_group.addObject(wire_obj)
if parent_group is None:
try:
parent_group = _wire_parent_group(
@ -452,25 +477,33 @@ def create_manual_wire(
)
except Exception:
parent_group = None
if parent_group is not None and wire_obj not in getattr(parent_group, "Group", []):
if parent_group is not None and not _is_legacy_wire_group(parent_group):
parent_group.addObject(wire_obj)
if parent_group is not None:
elif parent_group is not None:
try:
if (
getattr(parent_group, "Name", "").startswith(TerminalObjects.WIRE_GROUP_PREFIX)
or (getattr(parent_group, "QetGroupKind", "") or "").strip()
== TerminalObjects.WIRE_GROUP_KIND
):
parent_group.ViewObject.Visibility = False
parent_group.ViewObject.Visibility = False
except Exception:
pass
routed_group = WiringObjects.ensure_routed_group(doc, project_uuid)
if wire_obj not in getattr(routed_group, "Group", []):
routed_group.addObject(wire_obj)
try:
wire_obj.ViewObject.Visibility = True
except Exception:
pass
try:
routed_group.ViewObject.Visibility = True
except Exception:
pass
try:
wire_obj.ViewObject.LineWidth = 2.0
except Exception:
pass
try:
wire_obj.ViewObject.LineColor = (0.0, 0.6, 1.0)
wire_obj.ViewObject.LineColor = (1.0, 0.1, 0.0)
except Exception:
pass

@ -381,6 +381,10 @@ class ManualWiringController:
self.preview_objects = []
self.last_wire = None
def set_terminal_exit_length(self, value):
self.terminal_exit_length = max(float(value or 0.0), 0.0)
return self.terminal_exit_length
def _clear_preview_objects(self):
doc = getattr(App, "ActiveDocument", None)
if doc is None:
@ -523,9 +527,10 @@ class ManualWiringController:
)
if len(self.waypoints) > 3:
waypoint_text += "..."
return "任务:{0};起点:{1}折点:{2} 个;最近导线:{3};折点明细:{4}".format(
return "任务:{0};起点:{1}出线:{2:.1f} mm折点{3} 个;最近导线:{4};折点明细:{5}".format(
task_text,
start_text,
self.terminal_exit_length,
len(self.waypoints),
wire_text,
waypoint_text,
@ -546,6 +551,12 @@ class ManualWiringTaskPanel:
self.task_list = QtWidgets.QListWidget()
self.use_task_button = QtWidgets.QPushButton("选择导线任务")
self.reload_tasks_button = QtWidgets.QPushButton("刷新任务")
self.exit_length_input = QtWidgets.QDoubleSpinBox()
self.exit_length_input.setRange(0.0, 1000.0)
self.exit_length_input.setDecimals(1)
self.exit_length_input.setSingleStep(5.0)
self.exit_length_input.setSuffix(" mm")
self.exit_length_input.setValue(self.controller.terminal_exit_length)
self.start_button = QtWidgets.QPushButton("设为起点")
self.waypoint_button = QtWidgets.QPushButton("添加折点")
self.delete_waypoint_button = QtWidgets.QPushButton("删除最后折点")
@ -556,6 +567,10 @@ class ManualWiringTaskPanel:
layout.addWidget(self.task_list)
layout.addWidget(self.use_task_button)
layout.addWidget(self.reload_tasks_button)
exit_layout = QtWidgets.QHBoxLayout()
exit_layout.addWidget(QtWidgets.QLabel("端子出线长度"))
exit_layout.addWidget(self.exit_length_input)
layout.addLayout(exit_layout)
layout.addWidget(self.start_button)
layout.addWidget(self.waypoint_button)
layout.addWidget(self.delete_waypoint_button)
@ -573,6 +588,7 @@ class ManualWiringTaskPanel:
self.task_objects = []
self.use_task_button.clicked.connect(self.use_selected_task)
self.reload_tasks_button.clicked.connect(self._refresh_task_list)
self.exit_length_input.valueChanged.connect(self.set_exit_length)
self.start_button.clicked.connect(self.set_start)
self.waypoint_button.clicked.connect(self.add_waypoint)
self.delete_waypoint_button.clicked.connect(self.delete_last_waypoint)
@ -636,6 +652,13 @@ class ManualWiringTaskPanel:
except Exception as exc:
self._set_error(str(exc))
def set_exit_length(self, value):
try:
self.controller.set_terminal_exit_length(value)
self._set_status(self.controller.state_text())
except Exception as exc:
self._set_error(str(exc))
def set_start(self):
try:
terminal = self.controller.set_start_from_selection()
@ -665,6 +688,10 @@ class ManualWiringTaskPanel:
def set_end_and_generate(self):
try:
try:
self.controller.set_terminal_exit_length(self.exit_length_input.value())
except Exception:
pass
wire = self.controller.set_end_from_selection_and_generate()
self._refresh_task_list()
self._set_status("已生成导线:{0}".format(getattr(wire, "Name", "")))

@ -109,6 +109,18 @@ def _terminal_existing_index(container):
return index
def _terminal_existing_local_by_slot(container):
index = {}
for obj in TerminalObjects.collect_terminal_objects(container):
terminal_uuid = getattr(obj, "QetTerminalUuid", "").strip()
if not TerminalObjects.is_local_terminal_uuid(terminal_uuid):
continue
slot_name = _normalize_slot_name(getattr(obj, "QetTemplateSlotName", ""))
if slot_name and slot_name not in index:
index[slot_name] = obj
return index
def _device_key(device_group):
return getattr(device_group, "QetInstanceId", "").strip() or getattr(
device_group, "QetElementUuid", ""
@ -331,7 +343,9 @@ def import_terminals_from_payload(payload, scene_path=""):
terminal_group = _terminal_container_for_device(doc, device_group, project_uuid)
existing_by_uuid = _terminal_existing_index(terminal_group)
existing_local_by_slot = _terminal_existing_local_by_slot(terminal_group)
used_uuids = set()
used_objects = set()
used_slot_names = set()
template_slots = TemplateSemantics.collect_terminal_hints(device_group)
fallback_slots = TemplateSemantics.resolve_terminal_slots(
@ -379,16 +393,34 @@ def import_terminals_from_payload(payload, scene_path=""):
terminal_obj = existing_by_uuid.get(terminal_uuid)
if terminal_obj is None:
terminal_obj = _create_terminal_object(
doc,
terminal_uuid,
slot,
terminal_group,
project_uuid,
device_element_uuid,
device_instance_id,
)
report["imported_terminals"] += 1
terminal_obj = existing_local_by_slot.get(slot_name)
if terminal_obj is not None:
TerminalObjects.set_terminal_semantics(
terminal_obj,
project_uuid,
device_element_uuid,
terminal_uuid,
device_instance_id,
label=_terminal_slot_label(slot, terminal_uuid),
slot_name=slot.get("name", ""),
)
try:
terminal_obj.Placement = _slot_placement(slot)
except Exception:
pass
_ensure_visible(terminal_obj)
report["updated_terminals"] += 1
else:
terminal_obj = _create_terminal_object(
doc,
terminal_uuid,
slot,
terminal_group,
project_uuid,
device_element_uuid,
device_instance_id,
)
report["imported_terminals"] += 1
else:
TerminalObjects.set_terminal_semantics(
terminal_obj,
@ -410,6 +442,7 @@ def import_terminals_from_payload(payload, scene_path=""):
terminal_group.addObject(terminal_obj)
used_uuids.add(terminal_uuid)
used_objects.add(terminal_obj)
source_obj = slot.get("source_object")
if source_obj is not None:
_hide_object(source_obj)
@ -418,6 +451,8 @@ def import_terminals_from_payload(payload, scene_path=""):
for terminal_uuid, terminal_obj in list(existing_by_uuid.items()):
if terminal_uuid in used_uuids:
continue
if terminal_obj in used_objects:
continue
report["warnings"].append(
"Removed stale terminal {0} from device {1}.".format(
terminal_uuid, device_element_uuid

@ -32,10 +32,30 @@ def _conductor_uuids(item):
return [str(value).strip() for value in values if str(value).strip()]
def _normalize_wire_entry(item, index):
def _device_display_map(payload):
labels = {}
for item in payload.get("devices", []) or []:
if not isinstance(item, dict):
continue
element_uuid = _string_value(item, "element_uuid")
display_tag = _string_value(item, "display_tag")
if element_uuid and display_tag:
labels[element_uuid] = display_tag
return labels
def _endpoint_text(device_label, terminal_display, terminal_uuid):
terminal = terminal_display or terminal_uuid
if device_label and terminal:
return "{0}:{1}".format(device_label, terminal)
return device_label or terminal or "未命名端子"
def _normalize_wire_entry(item, index, device_labels=None):
if not isinstance(item, dict):
raise WiringImportError("Wire entry #{0} must be an object.".format(index))
device_labels = device_labels or {}
wire_uuid = (
_string_value(item, "wire_id")
or _string_value(item, "wire_uuid")
@ -55,6 +75,16 @@ def _normalize_wire_entry(item, index):
wire_mark = _string_value(item, "wire_mark")
wire_label = _string_value(item, "wire_label") or wire_mark or wire_uuid
start_element_uuid = _string_value(item, "start_element_uuid")
end_element_uuid = _string_value(item, "end_element_uuid")
start_terminal_display = _string_value(item, "start_terminal_display")
end_terminal_display = _string_value(item, "end_terminal_display")
start_device_label = device_labels.get(start_element_uuid, "")
end_device_label = device_labels.get(end_element_uuid, "")
endpoint_label = "{0} -> {1}".format(
_endpoint_text(start_device_label, start_terminal_display, start_terminal_uuid),
_endpoint_text(end_device_label, end_terminal_display, end_terminal_uuid),
)
return {
"wire_uuid": wire_uuid,
"wire_label": wire_label,
@ -62,14 +92,17 @@ def _normalize_wire_entry(item, index):
"group_uuid": _string_value(item, "group_uuid"),
"wire_mark": wire_mark,
"wire_mark_is_manual": _bool_value(item, "wire_mark_is_manual"),
"start_element_uuid": _string_value(item, "start_element_uuid"),
"start_element_uuid": start_element_uuid,
"start_terminal_uuid": start_terminal_uuid,
"start_instance_id": _string_value(item, "start_instance_id"),
"start_terminal_display": _string_value(item, "start_terminal_display"),
"end_element_uuid": _string_value(item, "end_element_uuid"),
"start_terminal_display": start_terminal_display,
"start_device_label": start_device_label,
"end_element_uuid": end_element_uuid,
"end_terminal_uuid": end_terminal_uuid,
"end_instance_id": _string_value(item, "end_instance_id"),
"end_terminal_display": _string_value(item, "end_terminal_display"),
"end_terminal_display": end_terminal_display,
"end_device_label": end_device_label,
"endpoint_label": endpoint_label,
"conductor_uuids": _conductor_uuids(item),
}
@ -86,9 +119,7 @@ def _unique_object_name(doc, base_name):
def _task_label(entry):
mark = entry["wire_mark"] or entry["wire_label"] or entry["wire_uuid"]
start = entry["start_terminal_display"] or entry["start_terminal_uuid"]
end = entry["end_terminal_display"] or entry["end_terminal_uuid"]
return "{0} {1} -> {2}".format(mark, start, end)
return "{0} {1}".format(mark, entry["endpoint_label"])
def _find_task_by_wire_uuid(task_group, wire_uuid):
@ -116,6 +147,9 @@ def _set_task_extra_properties(task, entry):
_ensure_string_property(task, "QetEndElementUuid", entry["end_element_uuid"])
_ensure_string_property(task, "QetStartTerminalDisplay", entry["start_terminal_display"])
_ensure_string_property(task, "QetEndTerminalDisplay", entry["end_terminal_display"])
_ensure_string_property(task, "QetStartDeviceLabel", entry["start_device_label"])
_ensure_string_property(task, "QetEndDeviceLabel", entry["end_device_label"])
_ensure_string_property(task, "QetEndpointLabel", entry["endpoint_label"])
_ensure_string_property(
task,
"QetConductorUuidsJson",
@ -191,9 +225,10 @@ def import_wire_tasks_from_payload(payload, doc=None):
"warnings": [],
}
device_labels = _device_display_map(payload)
for index, item in enumerate(wires):
try:
entry = _normalize_wire_entry(item, index)
entry = _normalize_wire_entry(item, index, device_labels=device_labels)
except WiringImportError as exc:
report["skipped_invalid"] += 1
report["warnings"].append(str(exc))

@ -351,18 +351,20 @@ class ManualWiringPanelTest(unittest.TestCase):
self.assertIn(wire, routed_group.Group)
self.assertEqual("terminal-start", getattr(wire, "QetStartTerminalUuid", ""))
self.assertEqual("terminal-end", getattr(wire, "QetEndTerminalUuid", ""))
self.assertEqual(5, len(getattr(wire, "Points", [])))
self.assertEqual(
(1.0, 12.0, 3.0),
(
wire.Points[1].x,
wire.Points[1].y,
wire.Points[1].z,
),
[
(1.0, 2.0, 3.0),
(1.0, 12.0, 3.0),
(1.0, 12.0, 30.0),
(1.0, 20.0, 30.0),
(10.0, 20.0, 30.0),
(10.0, 20.0, 17.0),
(10.0, 8.0, 17.0),
(9.0, 8.0, 17.0),
(9.0, 8.0, 7.0),
],
[(point.x, point.y, point.z) for point in getattr(wire, "Points", [])],
)
self.assertEqual((10.0, 20.0, 30.0), (wire.Points[2].x, wire.Points[2].y, wire.Points[2].z))
self.assertEqual((9.0, 8.0, 17.0), (wire.Points[3].x, wire.Points[3].y, wire.Points[3].z))
self.assertEqual((9.0, 8.0, 7.0), (wire.Points[4].x, wire.Points[4].y, wire.Points[4].z))
def test_controller_generates_wire_from_selected_task(self):
selection_state = _install_fake_freecad()

@ -200,9 +200,116 @@ class ManualWiringGroupTest(unittest.TestCase):
self.assertEqual(110.0, wire.Shape[0].x)
self.assertEqual(320.0, wire.Shape[-1].x)
def test_manual_wire_is_added_to_device_wire_group(self):
def test_manual_wire_routes_orthogonally_between_terminal_exit_points(self):
_install_fake_freecad()
device_import, manual_wiring, terminal_objects = _reload_modules()
_device_import, manual_wiring, terminal_objects = _reload_modules()
app = sys.modules["FreeCAD"]
doc = FakeDocument()
terminal_objects.ensure_root_group(doc, "project-1")
start_terminal = doc.addObject("Part::LocalCoordinateSystem", "TerminalStart")
start_terminal.Placement = app.Placement(app.Vector(0, 0, 0), app.Rotation())
terminal_objects.set_terminal_semantics(
start_terminal,
"project-1",
"device-start",
"terminal-start",
"instance-start",
label="Start",
)
end_terminal = doc.addObject("Part::LocalCoordinateSystem", "TerminalEnd")
end_terminal.Placement = app.Placement(app.Vector(10, 20, 30), app.Rotation())
terminal_objects.set_terminal_semantics(
end_terminal,
"project-1",
"device-end",
"terminal-end",
"instance-end",
label="End",
)
wire = manual_wiring.create_manual_wire(
doc,
start_terminal,
end_terminal,
terminal_exit_length=10.0,
)
points = [(point.x, point.y, point.z) for point in wire.Shape]
self.assertEqual(
[
(0.0, 0.0, 0.0),
(0.0, 0.0, 10.0),
(0.0, 0.0, 40.0),
(0.0, 20.0, 40.0),
(10.0, 20.0, 40.0),
(10.0, 20.0, 30.0),
],
points,
)
def test_manual_wire_reaches_face_anchor_normal_axis_last(self):
_install_fake_freecad()
_device_import, manual_wiring, terminal_objects = _reload_modules()
app = sys.modules["FreeCAD"]
doc = FakeDocument()
terminal_objects.ensure_root_group(doc, "project-1")
start_terminal = doc.addObject("Part::LocalCoordinateSystem", "TerminalStart")
start_terminal.Placement = app.Placement(app.Vector(0, 0, 0), app.Rotation())
terminal_objects.set_terminal_semantics(
start_terminal,
"project-1",
"device-start",
"terminal-start",
"instance-start",
label="Start",
)
end_terminal = doc.addObject("Part::LocalCoordinateSystem", "TerminalEnd")
end_terminal.Placement = app.Placement(app.Vector(100, 0, 0), app.Rotation())
terminal_objects.set_terminal_semantics(
end_terminal,
"project-1",
"device-end",
"terminal-end",
"instance-end",
label="End",
)
wire = manual_wiring.create_manual_wire(
doc,
start_terminal,
end_terminal,
waypoints=[
{
"point": app.Vector(40, 20, -100),
"support_axis": "z",
"anchor_kind": "face",
}
],
terminal_exit_length=20.0,
)
points = [(point.x, point.y, point.z) for point in wire.Shape]
self.assertEqual(
[
(0.0, 0.0, 0.0),
(0.0, 0.0, 20.0),
(40.0, 0.0, 20.0),
(40.0, 20.0, 20.0),
(40.0, 20.0, -100.0),
],
points[:5],
)
def test_manual_wire_is_visible_in_routed_group_not_hidden_legacy_group(self):
_install_fake_freecad()
_device_import, manual_wiring, terminal_objects = _reload_modules()
wiring_objects = __import__("WiringObjects")
doc = FakeDocument()
root = terminal_objects.ensure_root_group(doc, "project-1")
@ -240,6 +347,10 @@ class ManualWiringGroupTest(unittest.TestCase):
label="Start",
)
end_terminal = FakeObject("TerminalEnd", "Part::LocalCoordinateSystem")
end_terminal.Placement = sys.modules["FreeCAD"].Placement(
sys.modules["FreeCAD"].Vector(10, 0, 0),
sys.modules["FreeCAD"].Rotation(),
)
terminal_objects.set_terminal_semantics(
end_terminal,
"project-1",
@ -255,9 +366,13 @@ class ManualWiringGroupTest(unittest.TestCase):
device_group,
terminal_objects.WIRE_GROUP_KIND,
)
routed_group = wiring_objects.ensure_routed_group(doc, "project-1")
self.assertIsNotNone(wire_group)
self.assertIn(wire, wire_group.Group)
self.assertFalse(wire_group.ViewObject.Visibility)
self.assertIn(wire, routed_group.Group)
self.assertTrue(wire.ViewObject.Visibility)
self.assertNotIn(wire, wire_group.Group)
self.assertNotIn(wire, root.Group)

@ -285,6 +285,101 @@ class TerminalImportTemplateSlotPolicyTest(unittest.TestCase):
self.assertEqual(20.0, terminals["terminal-p2"].Placement.Base.x)
self.assertEqual(10.0, terminals["terminal-p1"].Placement.Base.x)
def test_import_rebinds_existing_local_terminal_on_matching_template_slot(self):
_install_fake_freecad()
terminal_import, terminal_objects, device_import = _reload_modules()
app = sys.modules["FreeCAD"]
doc = FakeDocument()
device_import._ensure_document = lambda scene_path: doc
root = device_import._ensure_root_group(doc, project_uuid="project-1")
device = doc.addObject("App::Part", "QETDevice_device_a")
root.addObject(device)
terminal_objects.ensure_string_property(
device,
"QetProjectUuid",
"QET Exchange",
"Project UUID",
"project-1",
)
terminal_objects.ensure_string_property(
device,
"QetElementUuid",
"QET Exchange",
"Element UUID",
"device-a",
)
terminal_objects.ensure_string_property(
device,
"QetInstanceId",
"QET Exchange",
"Instance ID",
"instance-a",
)
slot = doc.addObject("Part::LocalCoordinateSystem", "Terminal_P1")
slot.Placement = app.Placement(app.Vector(15, 0, 0), app.Rotation())
slot.addProperty("App::PropertyString", "Role", "QET Template", "")
slot.Role = "Terminal"
slot.addProperty("App::PropertyBool", "CanWire", "QET Template", "")
slot.CanWire = True
slot.addProperty("App::PropertyString", "QetTemplateSlotName", "QET Template", "")
slot.QetTemplateSlotName = "P1"
device.addObject(slot)
terminal_group = terminal_objects.ensure_terminal_group(
doc,
device,
project_uuid="project-1",
instance_id="instance-a",
)
local_terminal = terminal_objects.create_lcs_object(
doc,
"QETTerminal_instance_a_P1",
placement=app.Placement(app.Vector(1, 0, 0), app.Rotation()),
label="P1",
)
terminal_group.addObject(local_terminal)
terminal_objects.set_terminal_semantics(
local_terminal,
"project-1",
"device-a",
"local:instance-a:P1",
"instance-a",
label="P1",
slot_name="P1",
)
report = terminal_import.import_terminals_from_payload(
{
"project_uuid": "project-1",
"devices": [
{
"element_uuid": "device-a",
"instance_id": "instance-a",
}
],
"terminals": [
{
"terminal_uuid": "terminal-real-p1",
"element_uuid": "device-a",
"instance_id": "instance-a",
"slot_name_hint": "P1",
}
],
}
)
terminals = terminal_objects.collect_terminal_objects(terminal_group)
self.assertEqual(0, report["imported_terminals"])
self.assertEqual(1, report["updated_terminals"])
self.assertEqual(1, len(terminals))
self.assertIs(local_terminal, terminals[0])
self.assertEqual("terminal-real-p1", local_terminal.QetTerminalUuid)
self.assertEqual("instance-a", local_terminal.QetInstanceId)
self.assertEqual(15.0, local_terminal.Placement.Base.x)
if __name__ == "__main__":
unittest.main()

@ -103,6 +103,10 @@ class WiringImportTest(unittest.TestCase):
terminal_objects.ensure_root_group(doc, "project-1")
payload = {
"project_uuid": "project-1",
"devices": [
{"element_uuid": "device-a", "display_tag": "TAa"},
{"element_uuid": "device-b", "display_tag": "PEN001"},
],
"wires": [
{
"wire_id": "wire-1",
@ -140,6 +144,8 @@ class WiringImportTest(unittest.TestCase):
self.assertEqual("device-b", task.QetEndElementUuid)
self.assertEqual("A1", task.QetStartTerminalDisplay)
self.assertEqual("B1", task.QetEndTerminalDisplay)
self.assertEqual("TAa:A1 -> PEN001:B1", task.QetEndpointLabel)
self.assertIn("TAa:A1 -> PEN001:B1", task.Label)
self.assertIn("conductor-1", task.QetConductorUuidsJson)
self.assertEqual("Task", task.RouteType)
self.assertEqual("Task", task.RouteStatus)

@ -204,7 +204,7 @@ class WiringTest(unittest.TestCase):
self.assertIsNotNone(doc.getObject("QETWiring_04_Routed"))
self.assertFalse(legacy_group.ViewObject.Visibility)
def test_create_manual_wire_preserves_manual_waypoints_as_direct_segments(self):
def test_create_manual_wire_preserves_manual_waypoints_as_orthogonal_segments(self):
_install_fake_freecad()
terminal_objects, wiring_objects, manual_wiring, _write_back = _reload_modules()
app = sys.modules["FreeCAD"]
@ -313,12 +313,21 @@ class WiringTest(unittest.TestCase):
self.assertEqual("Manual", getattr(wire, "RouteType", ""))
self.assertEqual("terminal-start", getattr(wire, "QetStartTerminalUuid", ""))
self.assertEqual("terminal-end", getattr(wire, "QetEndTerminalUuid", ""))
self.assertEqual(5, len(getattr(wire, "Points", [])))
self.assertEqual((1.0, 22.0, 3.0), (wire.Points[1].x, wire.Points[1].y, wire.Points[1].z))
self.assertEqual(
[
(1.0, 2.0, 3.0),
(1.0, 22.0, 3.0),
(1.0, 5.0, 3.0),
(1.0, 5.0, 6.0),
(4.0, 5.0, 6.0),
(4.0, 5.0, 27.0),
(9.0, 5.0, 27.0),
(9.0, 8.0, 27.0),
(9.0, 8.0, 7.0),
],
[(point.x, point.y, point.z) for point in getattr(wire, "Points", [])],
)
self.assertTrue(any(point.x == 4.0 and point.y == 5.0 and point.z == 6.0 for point in wire.Points))
self.assertEqual((4.0, 5.0, 6.0), (wire.Points[2].x, wire.Points[2].y, wire.Points[2].z))
self.assertEqual((9.0, 8.0, 27.0), (wire.Points[3].x, wire.Points[3].y, wire.Points[3].z))
self.assertEqual((9.0, 8.0, 7.0), (wire.Points[4].x, wire.Points[4].y, wire.Points[4].z))
self.assertIn("QetManualWaypointsJson", getattr(wire, "PropertiesList", []))
self.assertIn('"support_axis": "x"', getattr(wire, "QetManualWaypointsJson", ""))

Loading…
Cancel
Save