1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
"""
motion_capture/device.py
BaseDevice that reads x/y position from CameraTracker.
Channels:
x_pos — horizontal position [px] (left=0, right=frame_width)
y_pos — vertical position [px] (top=0, bottom=frame_height)
Apply the pixel_to_mm filter in Signals → Channels to convert to mm.
"""
from __future__ import annotations
import threading
from typing import Any, Dict
from devices.base_device import (
BaseDevice, ChannelConfig, DeviceInfo, DeviceStatus,
)
class MotionCaptureDevice(BaseDevice):
def __init__(self, tracker, device_id: str = "motion_capture"):
super().__init__(DeviceInfo(
device_id = device_id,
name = "Motion Capture",
device_type = "virtual",
description = "Camera point-tracking — x/y position in pixels.",
icon = "🎥",
channels = [
ChannelConfig(
channel_id = "x_pos",
name = "X Position",
unit = "px",
min_value = 0.0,
max_value = 1920.0,
color = "#00d4ff",
),
ChannelConfig(
channel_id = "y_pos",
name = "Y Position",
unit = "px",
min_value = 0.0,
max_value = 1080.0,
color = "#f72585",
),
],
))
self._tracker = tracker
self._lock = threading.Lock()
self._last = (0.0, 0.0)
# ── BaseDevice interface ──────────────────────────────────────────────
def connect(self) -> bool:
self.status = DeviceStatus.SIMULATED
return True
def disconnect(self) -> None:
self.status = DeviceStatus.DISCONNECTED
def read_channels(self) -> Dict[str, float]:
pos = self._tracker.get_position()
if pos is not None:
with self._lock:
self._last = pos
with self._lock:
x, y = self._last
return {"x_pos": x, "y_pos": y}
def write_channel(self, channel_id: str, value: Any) -> bool:
return False
def get_config_widget(self):
from PyQt6.QtWidgets import QLabel
lbl = QLabel(
"Configure via the Motion Capture toolbar window.\n\n"
"Apply 'pixel_to_mm' filter in Signals → Channels\n"
"to convert pixel coordinates to millimetres."
)
lbl.setObjectName("traceSource")
lbl.setWordWrap(True)
return lbl
|