feat: 完善 STEP/B-Rep 一级关系参数化编辑

This commit is contained in:
2026-08-07 18:08:32 +08:00
parent eef9efcc1e
commit 12250603dd
26 changed files with 4254 additions and 1270 deletions
+104 -3
View File
@@ -135,6 +135,18 @@ class WindowCoreMixin:
def _should_suppress_transient_tooltip(self, watched) -> bool:
if not isinstance(watched, QWidget):
return False
property_table = getattr(self, "property_table", None)
if isinstance(property_table, QWidget):
widget = watched
while widget is not None:
if widget is property_table:
return False
widget = widget.parentWidget()
try:
if watched is property_table.viewport():
return False
except Exception:
pass
suppressed_roots = (
getattr(self, "vtk_widget", None),
getattr(self, "object_edit_box", None),
@@ -1791,6 +1803,8 @@ class WindowCoreMixin:
self.pointer_button_down = True
self.left_button_press_position = (int(x), int(y))
self.left_button_dragged = False
self.left_button_press_camera_state = self._camera_state_signature()
self.left_button_press_target = self._selection_target_at_position(x, y)
self.pending_hover_position = None
self.last_hover_pick_position = None
self.hover_timer.stop()
@@ -1812,16 +1826,55 @@ class WindowCoreMixin:
def _handle_left_button_release(self, x: int, y: int) -> None:
self._update_left_button_drag_state(x, y)
was_dragged = bool(getattr(self, "left_button_dragged", False))
camera_changed = self._left_button_camera_changed()
self.pointer_button_down = False
press_target = getattr(self, "left_button_press_target", None)
self.left_button_press_position = None
self.left_button_dragged = False
self.left_button_press_camera_state = None
self.left_button_press_target = None
self.pending_hover_position = None
self.last_hover_pick_position = None
if getattr(self, "camera_interaction_active", False):
self._end_camera_interaction()
if was_dragged:
if was_dragged or camera_changed or self._selection_target_signature(press_target) is None:
return
self._handle_left_click(x, y)
self._handle_left_click(x, y, required_press_target=press_target)
def _camera_state_signature(self) -> tuple[float, ...] | None:
renderer = getattr(self, "renderer", None)
if renderer is None:
return None
try:
camera = renderer.GetActiveCamera()
except Exception:
return None
if camera is None:
return None
values: list[float] = []
for getter in (
"GetPosition",
"GetFocalPoint",
"GetViewUp",
):
try:
values.extend(float(item) for item in getattr(camera, getter)())
except Exception:
return None
for getter in ("GetParallelScale", "GetDistance", "GetViewAngle"):
try:
values.append(float(getattr(camera, getter)()))
except Exception:
pass
return tuple(values)
def _left_button_camera_changed(self) -> bool:
before = getattr(self, "left_button_press_camera_state", None)
after = self._camera_state_signature()
if before is None or after is None or len(before) != len(after):
return False
tolerance = float(getattr(self, "left_click_camera_tolerance", 1e-7) or 1e-7)
return any(abs(float(a) - float(b)) > tolerance for a, b in zip(before, after))
def _update_left_button_drag_state(self, x: int, y: int) -> None:
press_position = getattr(self, "left_button_press_position", None)
@@ -1833,7 +1886,33 @@ class WindowCoreMixin:
if max(dx, dy) > threshold:
self.left_button_dragged = True
def _handle_left_click(self, x: int, y: int) -> None:
def _selection_target_signature(self, target: dict[str, object] | None) -> tuple[str, int] | None:
if not isinstance(target, dict):
return None
try:
return str(target["kind"]), int(target["target_id"])
except (KeyError, TypeError, ValueError):
return None
def _selection_target_at_position(self, x: int, y: int) -> dict[str, object] | None:
if (
getattr(self, "load_in_progress", False)
or getattr(self, "operation_in_progress", False)
or getattr(self, "scan_in_progress", False)
or getattr(self, "model", None) is None
):
return None
try:
return self._pick_selection_target(self._current_selection_mode(), int(x), int(y))
except Exception:
return None
def _handle_left_click(
self,
x: int,
y: int,
required_press_target: dict[str, object] | None = None,
) -> None:
self.pending_hover_position = None
self.last_hover_pick_position = None
self.hover_timer.stop()
@@ -1850,6 +1929,16 @@ class WindowCoreMixin:
return
mode = self._current_selection_mode()
target = self._pick_selection_target(mode, x, y)
if required_press_target is not None:
press_signature = self._selection_target_signature(required_press_target)
release_signature = self._selection_target_signature(target)
if press_signature is None or release_signature != press_signature:
self._cancel_hover_tracking(render=False)
if hasattr(self, "render_window"):
self.render_window.Render()
if self.selected_kind is not None:
self.statusBar().showMessage("左键按下和松开未命中同一对象,已保持当前选择")
return
if target is None:
self._cancel_hover_tracking(render=False)
if hasattr(self, "render_window"):
@@ -1871,6 +1960,7 @@ class WindowCoreMixin:
def _handle_pointer_button_press(self) -> None:
self.pointer_button_down = True
self.left_button_press_target = None
self.pending_hover_position = None
self.last_hover_pick_position = None
self.hover_timer.stop()
@@ -1884,6 +1974,7 @@ class WindowCoreMixin:
def _handle_pointer_button_release(self) -> None:
self.pointer_button_down = False
self.left_button_press_target = None
self.pending_hover_position = None
self.last_hover_pick_position = None
self._end_camera_interaction()
@@ -2279,6 +2370,14 @@ class WindowCoreMixin:
self._set_selection_mode("Edge")
self.select_edge(int(target_id))
self.statusBar().showMessage(f"已选择可尝试调整长度的Edge {target_id}")
elif action == "resize_ellipse_edge_major_radius":
self._set_selection_mode("Edge")
self.select_edge(int(target_id))
self.statusBar().showMessage(f"已选择可调整椭圆主半径的Edge {target_id}")
elif action == "resize_ellipse_edge_minor_radius":
self._set_selection_mode("Edge")
self.select_edge(int(target_id))
self.statusBar().showMessage(f"已选择可调整椭圆小半径的Edge {target_id}")
elif target_kind == "edge":
self._set_selection_mode("Edge")
self.select_edge(int(target_id))
@@ -2439,6 +2538,8 @@ class WindowCoreMixin:
self._sync_id_picker("Feature", logical_id)
self.set_info(self._with_pick_info(info, pick_position))
feature_type = str(info.get("feature_type", "特征候选"))
if hasattr(self, "_feature_display_label"):
feature_type = self._feature_display_label(feature_type)
self._update_action_states()
raw_note = f"(当前拓扑 Face {face_id}" if logical_id != face_id else ""
self.statusBar().showMessage(self._selection_status(f"已选择 {feature_type},来源 Face {logical_id}{raw_note}", pick_position))