summaryrefslogtreecommitdiff
path: root/plugins/motion_capture/device.py
blob: f0d082cd06dc1b40e1b3409b3888e5b294fa0a83 (plain)
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