QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
OnScreenCameraTrackingController.qml
Go to the documentation of this file.
1import QtQuick
2
3Item {
4 id: rootItem
5
6 required property var camera
7 required property real videoWidth
8 required property real videoHeight
9
10 // Drag origin in parent coordinates
11 property real _dragStartX: 0
12 property real _dragStartY: 0
13 property bool _dragging: false
14 property real _dragCurrentX: 0
15 property real _dragCurrentY: 0
16
17 readonly property bool _trackingEnabled: camera && camera.trackingEnabled
18 readonly property bool _canTrackPoint: _trackingEnabled && camera.supportsTrackingPoint
19 readonly property bool _canTrackRect: _trackingEnabled && camera.supportsTrackingRect
20
21 function mouseClicked(mouseX, mouseY) {
22 if (!_canTrackPoint) {
23 return
24 }
25 if (videoWidth <= 0 || videoHeight <= 0) {
26 return
27 }
28 // Click = point tracking
29 var marginH = (width - videoWidth) / 2
30 var marginV = (height - videoHeight) / 2
31 var nx = Math.max(Math.min((mouseX - marginH) / videoWidth, 1.0), 0.0)
32 var ny = Math.max(Math.min((mouseY - marginV) / videoHeight, 1.0), 0.0)
33 var pointRadius = 20
34 camera.startTrackingPoint(Qt.point(nx, ny), Math.min(pointRadius / videoWidth, 1.0))
35 }
36
37 function mouseDragStart(mouseX, mouseY) {
38 if (!_canTrackRect) {
39 return
40 }
41 _dragStartX = mouseX
42 _dragStartY = mouseY
43 _dragCurrentX = mouseX
44 _dragCurrentY = mouseY
45 _dragging = true
46 }
47
48 function mouseDragPositionChanged(mouseX, mouseY) {
49 if (!_dragging) {
50 return
51 }
52 _dragCurrentX = mouseX
53 _dragCurrentY = mouseY
54 }
55
56 function mouseDragEnd(mouseX, mouseY) {
57 _dragging = false
58
59 if (!_canTrackRect) {
60 return
61 }
62 if (videoWidth <= 0 || videoHeight <= 0) {
63 return
64 }
65
66 // Order coordinates: top-left and bottom-right
67 var x0 = Math.min(_dragStartX, mouseX)
68 var x1 = Math.max(_dragStartX, mouseX)
69 var y0 = Math.min(_dragStartY, mouseY)
70 var y1 = Math.max(_dragStartY, mouseY)
71
72 // Letterbox margins (black bars when aspect ratio doesn't match)
73 var marginH = (width - videoWidth) / 2
74 var marginV = (height - videoHeight) / 2
75
76 // Convert from view coordinates to video-relative coordinates
77 x0 = x0 - marginH
78 x1 = x1 - marginH
79 y0 = y0 - marginV
80 y1 = y1 - marginV
81
82 // Normalize to 0..1
83 x0 = Math.max(Math.min(x0 / videoWidth, 1.0), 0.0)
84 x1 = Math.max(Math.min(x1 / videoWidth, 1.0), 0.0)
85 y0 = Math.max(Math.min(y0 / videoHeight, 1.0), 0.0)
86 y1 = Math.max(Math.min(y1 / videoHeight, 1.0), 0.0)
87
88 var w = x1 - x0
89 var h = y1 - y0
90
91 // Ignore degenerate rectangles (e.g. mostly-horizontal/vertical drags)
92 if (w < 0.01 || h < 0.01) {
93 _dragStartX = 0
94 _dragStartY = 0
95 return
96 }
97
98 // Drag = rectangle tracking
99 camera.startTrackingRect(Qt.rect(x0, y0, w, h))
100
101 _dragStartX = 0
102 _dragStartY = 0
103 }
104
105 // --- ROI selection overlay (green rectangle while dragging) ---
106 Rectangle {
107 visible: _dragging
108 color: Qt.rgba(0.1, 0.85, 0.1, 0.25)
109 border.color: "green"
110 border.width: 1
111 x: Math.min(_dragStartX, _dragCurrentX)
112 y: Math.min(_dragStartY, _dragCurrentY)
113 width: Math.abs(_dragCurrentX - _dragStartX)
114 height: Math.abs(_dragCurrentY - _dragStartY)
115 }
116
117 // --- Tracking status overlay (red rectangle/circle from camera feedback) ---
118 // Coordinates are normalized to the video frame (0.0–1.0). Convert to screen
119 // pixels by scaling by the displayed video size and offsetting by letterbox margins.
120 readonly property bool _trackingActive: _trackingEnabled && camera.trackingImageIsActive
121 readonly property bool _isPoint: _trackingActive && camera.trackingImageIsPoint
122 readonly property real _marginH: (rootItem.width - videoWidth) / 2
123 readonly property real _marginV: (rootItem.height - videoHeight) / 2
124
125 Rectangle {
126 id: trackingStatusOverlay
127 color: "transparent"
128 border.color: "red"
129 border.width: 5
130 radius: rootItem._isPoint ? width / 2 : 5
131 visible: rootItem._trackingActive
132
133 x: rootItem._trackingActive
134 ? (rootItem._isPoint ? rootItem._marginH + videoWidth * (camera.trackingImagePoint.x - camera.trackingImageRadius)
135 : rootItem._marginH + videoWidth * camera.trackingImageRect.x)
136 : 0
137 y: rootItem._trackingActive
138 ? (rootItem._isPoint ? rootItem._marginV + videoHeight * (camera.trackingImagePoint.y - camera.trackingImageRadius)
139 : rootItem._marginV + videoHeight * camera.trackingImageRect.y)
140 : 0
141 width: rootItem._trackingActive
142 ? (rootItem._isPoint ? videoWidth * camera.trackingImageRadius * 2
143 : videoWidth * camera.trackingImageRect.width)
144 : 0
145 height: rootItem._trackingActive
146 ? (rootItem._isPoint ? width
147 : videoHeight * camera.trackingImageRect.height)
148 : 0
149 }
150}