added mesh surface arrows
This commit is contained in:
+72
-33
@@ -6,7 +6,7 @@ import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt5.QtCore import Qt, QTimer
|
||||
from PyQt5.QtCore import QSize, Qt, QTimer
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication,
|
||||
@@ -31,6 +31,7 @@ from .layout import (
|
||||
top_row_splitter_sizes,
|
||||
)
|
||||
from .styles import STYLE
|
||||
from .transport_icons import transport_icon
|
||||
from .widgets import (
|
||||
ArrowPanelWidget,
|
||||
ForceChartWidget,
|
||||
@@ -41,6 +42,15 @@ from .widgets import (
|
||||
)
|
||||
|
||||
|
||||
_PLAY_PAUSE_BUTTON_NAME = "btnPlayPause"
|
||||
_PLAY_PAUSE_ICON_PX = 18
|
||||
_PLAY_PAUSE_ICON_COLORS = {
|
||||
"run": "#4caf84",
|
||||
"starting": "#555555",
|
||||
"pause": "#ff9800",
|
||||
}
|
||||
|
||||
|
||||
class FingerDashboardWindow(QMainWindow):
|
||||
"""Single-window finger demo: 3D mesh | UV arrows | force charts."""
|
||||
|
||||
@@ -88,14 +98,14 @@ class FingerDashboardWindow(QMainWindow):
|
||||
bar = QHBoxLayout()
|
||||
bar.setSpacing(layout.toolbar_spacing_px)
|
||||
|
||||
self.btn_camera = QPushButton("摄像机")
|
||||
self.btn_camera = QPushButton("Sensor")
|
||||
self.btn_camera.clicked.connect(self._select_camera)
|
||||
bar.addWidget(self.btn_camera)
|
||||
self.camera_edit = QLineEdit("0")
|
||||
self.camera_edit.setPlaceholderText("摄像头编号 或 视频路径")
|
||||
self.camera_edit.setPlaceholderText("Camera ID or Video Path")
|
||||
bar.addWidget(self.camera_edit, 1)
|
||||
|
||||
self.btn_config = QPushButton("配置")
|
||||
self.btn_config = QPushButton("Config")
|
||||
self.btn_config.clicked.connect(self._select_config)
|
||||
bar.addWidget(self.btn_config)
|
||||
self.config_edit = QLineEdit("./config/dd02-ov.json")
|
||||
@@ -104,34 +114,38 @@ class FingerDashboardWindow(QMainWindow):
|
||||
self.cal_edit = QLineEdit("")
|
||||
bar.addWidget(self.cal_edit, 1)
|
||||
|
||||
self.btn_reset = QPushButton("重置")
|
||||
self.btn_reset = QPushButton("Reset")
|
||||
self.btn_reset.setEnabled(False)
|
||||
self.btn_reset.clicked.connect(self._on_reset)
|
||||
bar.addWidget(self.btn_reset)
|
||||
|
||||
self.btn_start = QPushButton("启动")
|
||||
self.btn_start.setObjectName("btnStart")
|
||||
self.btn_start.clicked.connect(self._on_start)
|
||||
bar.addWidget(self.btn_start)
|
||||
|
||||
self.btn_stop = QPushButton("暂停")
|
||||
self.btn_stop.setObjectName("btnStop")
|
||||
self.btn_stop.setEnabled(False)
|
||||
self.btn_stop.clicked.connect(self._on_stop)
|
||||
bar.addWidget(self.btn_stop)
|
||||
self.btn_play_pause = QPushButton()
|
||||
self.btn_play_pause.setObjectName(_PLAY_PAUSE_BUTTON_NAME)
|
||||
self.btn_play_pause.setFixedSize(36, 32)
|
||||
self.btn_play_pause.setIconSize(QSize(_PLAY_PAUSE_ICON_PX, _PLAY_PAUSE_ICON_PX))
|
||||
self.btn_play_pause.clicked.connect(self._on_play_pause_clicked)
|
||||
self._set_play_pause_button("run")
|
||||
bar.addWidget(self.btn_play_pause)
|
||||
|
||||
root_layout.addLayout(bar)
|
||||
|
||||
setup = layout.panel_setup
|
||||
self._panel_widgets: dict[str, QWidget] = {}
|
||||
|
||||
self.mesh_viewport = MeshViewportWidget(layout=layout)
|
||||
self.arrow_panel = ArrowPanelWidget(flow_threshold=layout.arrow_flow_threshold, layout=layout)
|
||||
arrows_slot = layout.slot("arrows")
|
||||
self.arrow_panel: ArrowPanelWidget | None = None
|
||||
if arrows_slot is not None and arrows_slot.enabled:
|
||||
self.arrow_panel = ArrowPanelWidget(
|
||||
flow_threshold=layout.arrow_flow_threshold,
|
||||
background=layout.arrow_background,
|
||||
layout=layout,
|
||||
)
|
||||
self.force_charts = ForceChartWidget(layout=layout, lowpass_cutoff_hz=self.config.lowpass_cutoff_hz)
|
||||
self.log_widget = make_log_widget(layout.log_config)
|
||||
|
||||
self._panel_widgets: dict[str, QWidget] = {}
|
||||
self._panel_widgets["mesh"] = self.mesh_viewport
|
||||
self._panel_widgets["arrows"] = self.arrow_panel
|
||||
if self.arrow_panel is not None:
|
||||
self._panel_widgets["arrows"] = self.arrow_panel
|
||||
self._panel_widgets["charts"] = self.force_charts.widget
|
||||
self._panel_widgets["log"] = self.log_widget
|
||||
|
||||
@@ -194,11 +208,40 @@ class FingerDashboardWindow(QMainWindow):
|
||||
sys.stdout = TeeStream(*streams)
|
||||
sys.stderr = sys.stdout
|
||||
|
||||
def _set_play_pause_button(self, state: str) -> None:
|
||||
"""``run`` = green play, ``starting`` = grey disabled play, ``pause`` = orange pause."""
|
||||
btn = self.btn_play_pause
|
||||
if state == "run":
|
||||
btn.setToolTip("Run")
|
||||
btn.setEnabled(True)
|
||||
elif state == "starting":
|
||||
btn.setToolTip("Starting…")
|
||||
btn.setEnabled(False)
|
||||
elif state == "pause":
|
||||
btn.setToolTip("Pause")
|
||||
btn.setEnabled(True)
|
||||
else:
|
||||
raise ValueError(f"unknown play/pause state: {state!r}")
|
||||
|
||||
kind = "pause" if state == "pause" else "play"
|
||||
btn.setText("")
|
||||
btn.setIcon(transport_icon(kind, _PLAY_PAUSE_ICON_COLORS[state]))
|
||||
btn.setProperty("playState", state)
|
||||
style = btn.style()
|
||||
style.unpolish(btn)
|
||||
style.polish(btn)
|
||||
btn.update()
|
||||
|
||||
def _on_play_pause_clicked(self) -> None:
|
||||
if self._running:
|
||||
self._on_stop()
|
||||
else:
|
||||
self._on_start()
|
||||
|
||||
def _on_start(self) -> None:
|
||||
if self._running:
|
||||
return
|
||||
self.btn_start.setText("启动中...")
|
||||
self.btn_start.setEnabled(False)
|
||||
self._set_play_pause_button("starting")
|
||||
QApplication.processEvents()
|
||||
|
||||
self.config.video = self.camera_edit.text().strip()
|
||||
@@ -214,8 +257,7 @@ class FingerDashboardWindow(QMainWindow):
|
||||
QTimer.singleShot(0, self._apply_panel_layout)
|
||||
except Exception as exc:
|
||||
self.mesh_viewport.close_renderer()
|
||||
self.btn_start.setText("启动")
|
||||
self.btn_start.setEnabled(True)
|
||||
self._set_play_pause_button("run")
|
||||
print(f"启动失败: {exc}")
|
||||
return
|
||||
|
||||
@@ -223,8 +265,7 @@ class FingerDashboardWindow(QMainWindow):
|
||||
self._frame_index = 0
|
||||
self._wall_fps = 0.0
|
||||
self.timer.start(self.layout.timer_interval_ms)
|
||||
self.btn_start.setText("启动")
|
||||
self.btn_stop.setEnabled(True)
|
||||
self._set_play_pause_button("pause")
|
||||
self.btn_reset.setEnabled(True)
|
||||
print(
|
||||
f"▶ 启动 — 摄像机={self.config.video}, 配置={self.config.config}, "
|
||||
@@ -237,17 +278,14 @@ class FingerDashboardWindow(QMainWindow):
|
||||
self._running = False
|
||||
self.timer.stop()
|
||||
self.log_handler.clear_status_line()
|
||||
self.btn_stop.setText("停止中...")
|
||||
self.btn_stop.setEnabled(False)
|
||||
self._set_play_pause_button("starting")
|
||||
QApplication.processEvents()
|
||||
|
||||
self.mesh_viewport.close_renderer()
|
||||
self.pipeline.close()
|
||||
|
||||
self.btn_start.setEnabled(True)
|
||||
self.btn_stop.setText("暂停")
|
||||
self._set_play_pause_button("run")
|
||||
self.btn_reset.setEnabled(False)
|
||||
print("⏸ 已暂停")
|
||||
|
||||
def _on_reset(self) -> None:
|
||||
if not self._running:
|
||||
@@ -278,9 +316,10 @@ class FingerDashboardWindow(QMainWindow):
|
||||
profile.record("mesh", mesh_ms)
|
||||
|
||||
arrows_ms = 0.0
|
||||
t0 = time.perf_counter()
|
||||
self.arrow_panel.update_frame(frame)
|
||||
arrows_ms = (time.perf_counter() - t0) * 1000.0
|
||||
if self.arrow_panel is not None:
|
||||
t0 = time.perf_counter()
|
||||
self.arrow_panel.update_frame(frame)
|
||||
arrows_ms = (time.perf_counter() - t0) * 1000.0
|
||||
if profile is not None:
|
||||
profile.record("arrows", arrows_ms)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user