HUD.cc 48.8 KB
Newer Older
pixhawk's avatar
pixhawk committed
1
2
/*=====================================================================

3
QGroundControl Open Source Ground Control Station
pixhawk's avatar
pixhawk committed
4

5
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
pixhawk's avatar
pixhawk committed
6

7
This file is part of the QGROUNDCONTROL project
pixhawk's avatar
pixhawk committed
8

9
    QGROUNDCONTROL is free software: you can redistribute it and/or modify
pixhawk's avatar
pixhawk committed
10
11
12
13
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

14
    QGROUNDCONTROL is distributed in the hope that it will be useful,
pixhawk's avatar
pixhawk committed
15
16
17
18
19
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
20
    along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
pixhawk's avatar
pixhawk committed
21
22
23
24
25
26
27
28
29
30
31

======================================================================*/

/**
 * @file
 *   @brief Head Up Display (HUD)
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

32
#include <QShowEvent>
33
34
#include <QContextMenuEvent>
#include <QMenu>
35
#include <QStandardPaths>
36
#include <QPaintEvent>
pixhawk's avatar
pixhawk committed
37
#include <QDebug>
38

pixhawk's avatar
pixhawk committed
39
#include <cmath>
pixhawk's avatar
pixhawk committed
40
#include <qmath.h>
pixhawk's avatar
pixhawk committed
41
#include <limits>
pixhawk's avatar
pixhawk committed
42

43
#include "UAS.h"
pixhawk's avatar
pixhawk committed
44
#include "HUD.h"
45
#include "QGC.h"
46
#include "QGCApplication.h"
Don Gagne's avatar
Don Gagne committed
47
#include "QGCFileDialog.h"
48
#include "MultiVehicleManager.h"
pixhawk's avatar
pixhawk committed
49
50
51
52
53
54
55
56
57
58

/**
 * @warning The HUD widget will not start painting its content automatically
 *          to update the view, start the auto-update by calling HUD::start().
 *
 * @param width
 * @param height
 * @param parent
 */
HUD::HUD(int width, int height, QWidget* parent)
59
    : QLabel(parent),
Don Gagne's avatar
Don Gagne committed
60
      image(NULL),
61
62
63
64
65
66
67
68
69
      uas(NULL),
      yawInt(0.0f),
      mode(tr("UNKNOWN MODE")),
      state(tr("UNKNOWN STATE")),
      fuelStatus(tr("00.0V (00m:00s)")),
      xCenterOffset(0.0f),
      yCenterOffset(0.0f),
      vwidth(200.0f),
      vheight(150.0f),
70
      vGaugeSpacing(65.0f),
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
      vPitchPerDeg(6.0f), ///< 4 mm y translation per degree)
      rawBuffer1(NULL),
      rawBuffer2(NULL),
      rawImage(NULL),
      rawLastIndex(0),
      rawExpectedBytes(0),
      bytesPerLine(1),
      imageStarted(false),
      receivedDepth(8),
      receivedChannels(1),
      receivedWidth(640),
      receivedHeight(480),
      warningBlinkRate(5),
      refreshTimer(new QTimer(this)),
      noCamera(true),
      hardwareAcceleration(true),
      strongStrokeWidth(1.5f),
      normalStrokeWidth(1.0f),
      fineStrokeWidth(0.5f),
      waypointName(""),
      roll(0.0f),
      pitch(0.0f),
      yaw(0.0f),
      rollLP(0.0f),
      pitchLP(0.0f),
      yawLP(0.0f),
      yawDiff(0.0f),
      xPos(0.0),
      yPos(0.0),
      zPos(0.0),
      xSpeed(0.0),
      ySpeed(0.0),
      zSpeed(0.0),
      lastSpeedUpdate(0),
      totalSpeed(0.0),
      totalAcc(0.0),
      lat(0.0),
      lon(0.0),
      alt(0.0),
      load(0.0f),
      offlineDirectory(""),
      nextOfflineImage(""),
113
      HUDInstrumentsEnabled(false),
114
      videoEnabled(true),
Don Gagne's avatar
Don Gagne committed
115
      imageLoggingEnabled(false),
116
      xImageFactor(1.0),
117
      yImageFactor(1.0),
Don Gagne's avatar
Don Gagne committed
118
      imageRequested(false)
pixhawk's avatar
pixhawk committed
119
{
120
121
    Q_UNUSED(width);
    Q_UNUSED(height);
Helen Oleynikova's avatar
Helen Oleynikova committed
122

pixhawk's avatar
pixhawk committed
123
124
125
    // Set auto fill to false
    setAutoFillBackground(false);

126
127
    // Set minimum size
    setMinimumSize(80, 60);
128
129
    // Set preferred size
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
LM's avatar
LM committed
130
    scalingFactor = this->width()/vwidth;
131

132
133
    // Set up the initial color theme. This can be updated by a styleChanged
    // signal from MainWindow.
134
    styleChanged(qgcApp()->styleIsDark());
pixhawk's avatar
pixhawk committed
135
136

    // Refresh timer
137
    refreshTimer->setInterval(updateInterval);
138
    connect(refreshTimer, SIGNAL(timeout()), this, SLOT(repaint()));
pixhawk's avatar
pixhawk committed
139
140

    // Resize to correct size and fill with image
141
    QWidget::resize(this->width(), this->height());
pixhawk's avatar
pixhawk committed
142
143

    fontDatabase = QFontDatabase();
Don Gagne's avatar
Don Gagne committed
144
    const QString fontFileName = ":/res/fonts/vera.ttf"; ///< Font file is part of the QRC file and compiled into the app
pixhawk's avatar
pixhawk committed
145
146
147
148
    const QString fontFamilyName = "Bitstream Vera Sans";
    if(!QFile::exists(fontFileName)) qDebug() << "ERROR! font file: " << fontFileName << " DOES NOT EXIST!";

    fontDatabase.addApplicationFont(fontFileName);
lm's avatar
lm committed
149
150
    font = fontDatabase.font(fontFamilyName, "Roman", qMax(5,(int)(10.0f*scalingFactor*1.2f+0.5f)));
    QFont* fontPtr = &font;
151
    if (!fontPtr) {
lm's avatar
lm committed
152
        qDebug() << "ERROR! FONT NOT LOADED!";
153
    } else {
lm's avatar
lm committed
154
155
        if (font.family() != fontFamilyName) qDebug() << "ERROR! WRONG FONT LOADED: " << fontFamilyName;
    }
pixhawk's avatar
pixhawk committed
156

157
158
    // Connect the themeChanged signal from the MainWindow to this widget, so it
    // can change it's styling accordingly.
159
    connect(qgcApp(), &QGCApplication::styleChanged, this, &HUD::styleChanged);
160

pixhawk's avatar
pixhawk committed
161
    // Connect with UAS
162
    connect(MultiVehicleManager::instance(), &MultiVehicleManager::activeVehicleChanged, this, &HUD::_activeVehicleChanged);
163

164
    createActions();
165
166
    
    _activeVehicleChanged(MultiVehicleManager::instance()->activeVehicle());
pixhawk's avatar
pixhawk committed
167
168
169
170
}

HUD::~HUD()
{
pixhawk's avatar
pixhawk committed
171
    refreshTimer->stop();
pixhawk's avatar
pixhawk committed
172
173
}

174
175
QSize HUD::sizeHint() const
{
176
    return QSize(width(), (width()*3.0f)/4);
177
178
}

179
void HUD::styleChanged(bool styleIsDark)
180
181
182
{
    // Generate a background image that's dependent on the current color scheme.
    QImage fill = QImage(width(), height(), QImage::Format_Indexed8);
183
    fill.fill(styleIsDark ? 0 : 255);
184
185
186
    glImage = QGLWidget::convertToGLFormat(fill);

    // Now set the other default colors based on the current color scheme.
187
    if (styleIsDark)
188
189
190
191
192
193
194
195
    {
        defaultColor = QColor(70, 200, 70);
        setPointColor = QColor(200, 20, 200);
        warningColor = Qt::yellow;
        criticalColor = Qt::red;
        infoColor = QColor(20, 200, 20);
        fuelColor = criticalColor;
    }
196
197
198
199
200
201
202
203
204
    else
    {
        defaultColor = QColor(0x01, 0x47, 0x01);
        setPointColor = QColor(0x82, 0x17, 0x82);
        warningColor = Qt::darkYellow;
        criticalColor = Qt::darkRed;
        infoColor = QColor(0x07, 0x82, 0x07);
        fuelColor = criticalColor;
    }
205
206
}

207
208
void HUD::showEvent(QShowEvent* event)
{
209
210
    // React only to internal (pre-display)
    // events
211
    QWidget::showEvent(event);
212
    refreshTimer->start(updateInterval);
LM's avatar
LM committed
213
    emit visibilityChanged(true);
214
215
216
217
218
219
}

void HUD::hideEvent(QHideEvent* event)
{
    // React only to internal (pre-display)
    // events
220
    refreshTimer->stop();
221
    QWidget::hideEvent(event);
LM's avatar
LM committed
222
    emit visibilityChanged(false);
pixhawk's avatar
pixhawk committed
223
224
}

225
226
227
void HUD::contextMenuEvent (QContextMenuEvent* event)
{
    QMenu menu(this);
228
    // Update actions
229
    enableHUDAction->setChecked(HUDInstrumentsEnabled);
230
231
    enableVideoAction->setChecked(videoEnabled);

232
233
234
235
    menu.addAction(enableHUDAction);
    //menu.addAction(selectHUDColorAction);
    menu.addAction(enableVideoAction);
    menu.addAction(selectOfflineDirectoryAction);
236
    menu.addAction(selectSaveDirectoryAction);
237
238
239
240
241
242
243
244
    menu.exec(event->globalPos());
}

void HUD::createActions()
{
    enableHUDAction = new QAction(tr("Enable HUD"), this);
    enableHUDAction->setStatusTip(tr("Show the HUD instruments in this window"));
    enableHUDAction->setCheckable(true);
245
    enableHUDAction->setChecked(HUDInstrumentsEnabled);
246
247
248
249
250
251
252
253
    connect(enableHUDAction, SIGNAL(triggered(bool)), this, SLOT(enableHUDInstruments(bool)));

    enableVideoAction = new QAction(tr("Enable Video Live feed"), this);
    enableVideoAction->setStatusTip(tr("Show the video live feed"));
    enableVideoAction->setCheckable(true);
    enableVideoAction->setChecked(videoEnabled);
    connect(enableVideoAction, SIGNAL(triggered(bool)), this, SLOT(enableVideo(bool)));

254
    selectOfflineDirectoryAction = new QAction(tr("Load image log"), this);
255
256
    selectOfflineDirectoryAction->setStatusTip(tr("Load previously logged images into simulation / replay"));
    connect(selectOfflineDirectoryAction, SIGNAL(triggered()), this, SLOT(selectOfflineDirectory()));
257
258
259
260
261

    selectSaveDirectoryAction = new QAction(tr("Save images to directory"), this);
    selectSaveDirectoryAction->setStatusTip(tr("Save images from image stream to a directory"));
    selectSaveDirectoryAction->setCheckable(true);
    connect(selectSaveDirectoryAction, SIGNAL(triggered(bool)), this, SLOT(saveImages(bool)));
262
263
}

pixhawk's avatar
pixhawk committed
264
265
266
267
/**
 *
 * @param uas the UAS/MAV to monitor/display with the HUD
 */
268
void HUD::_activeVehicleChanged(Vehicle* vehicle)
pixhawk's avatar
pixhawk committed
269
{
270
    if (this->uas != NULL) {
pixhawk's avatar
pixhawk committed
271
        // Disconnect any previously connected active MAV
dongfang's avatar
dongfang committed
272
273
274
        disconnect(this->uas, SIGNAL(attitudeChanged(UASInterface*, double, double, double, quint64)), this, SLOT(updateAttitude(UASInterface*, double, double, double, quint64)));
        disconnect(this->uas, SIGNAL(attitudeChanged(UASInterface*,int, double, double, double, quint64)), this, SLOT(updateAttitude(UASInterface*,int,double, double, double, quint64)));
        disconnect(this->uas, SIGNAL(batteryChanged(UASInterface*, double, double, double, int)), this, SLOT(updateBattery(UASInterface*, double, double, double, int)));
275
276
277
        disconnect(this->uas, SIGNAL(statusChanged(UASInterface*,QString,QString)), this, SLOT(updateState(UASInterface*,QString)));
        disconnect(this->uas, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int,QString,QString)));
        disconnect(this->uas, SIGNAL(heartbeat(UASInterface*)), this, SLOT(receiveHeartbeat(UASInterface*)));
278

279
        disconnect(this->uas, SIGNAL(localPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateLocalPosition(UASInterface*,double,double,double,quint64)));
280
        disconnect(this->uas, SIGNAL(globalPositionChanged(UASInterface*,double,double,double,double,quint64)), this, SLOT(updateGlobalPosition(UASInterface*,double,double,double,double,quint64)));
Don Gagne's avatar
Don Gagne committed
281
        disconnect(this->uas, SIGNAL(velocityChanged_NED(UASInterface*,double,double,double,quint64)), this, SLOT(updateSpeed(UASInterface*,double,double,double,quint64)));
282
        disconnect(this->uas, SIGNAL(waypointSelected(int,int)), this, SLOT(selectWaypoint(int, int)));
pixhawk's avatar
pixhawk committed
283

284
        // Try to disconnect the image link
285
        UAS* u = dynamic_cast<UAS*>(this->uas);
286
        if (u) {
Lorenz Meier's avatar
Lorenz Meier committed
287
            disconnect(u, SIGNAL(imageReady(UASInterface*)), this, SLOT(copyImage(UASInterface*)));
288
289
        }
    }
pixhawk's avatar
pixhawk committed
290

291
292
293
294
    this->uas = NULL;
    
    if (vehicle) {
        this->uas = vehicle->uas();
295
296
297
        // Now connect the new UAS
        // Setup communication
        connect(uas, SIGNAL(attitudeChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateAttitude(UASInterface*, double, double, double, quint64)));
298
        connect(uas, SIGNAL(attitudeChanged(UASInterface*,int,double,double,double,quint64)), this, SLOT(updateAttitude(UASInterface*,int,double, double, double, quint64)));
dongfang's avatar
dongfang committed
299
        connect(uas, SIGNAL(batteryChanged(UASInterface*, double, double, double, int)), this, SLOT(updateBattery(UASInterface*, double, double, double, int)));
300
301
302
303
304
        connect(uas, SIGNAL(statusChanged(UASInterface*,QString,QString)), this, SLOT(updateState(UASInterface*,QString)));
        connect(uas, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int,QString,QString)));
        connect(uas, SIGNAL(heartbeat(UASInterface*)), this, SLOT(receiveHeartbeat(UASInterface*)));

        connect(uas, SIGNAL(localPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateLocalPosition(UASInterface*,double,double,double,quint64)));
305
        connect(uas, SIGNAL(globalPositionChanged(UASInterface*,double,double,double,double,quint64)), this, SLOT(updateGlobalPosition(UASInterface*,double,double,double,double,quint64)));
306
        connect(uas, SIGNAL(velocityChanged_NED(UASInterface*,double,double,double,quint64)), this, SLOT(updateSpeed(UASInterface*,double,double,double,quint64)));
307
308
309
        connect(uas, SIGNAL(waypointSelected(int,int)), this, SLOT(selectWaypoint(int, int)));

        // Try to connect the image link
Lorenz Meier's avatar
Lorenz Meier committed
310
        UAS* u = qobject_cast<UAS*>(uas);
311
        if (u) {
Lorenz Meier's avatar
Lorenz Meier committed
312
            connect(u, SIGNAL(imageReady(UASInterface*)), this, SLOT(copyImage(UASInterface*)));
313
314
        }
    }
315

pixhawk's avatar
pixhawk committed
316
317
}

318
319
320
321
322
323
324
//void HUD::updateAttitudeThrustSetPoint(UASInterface* uas, double rollDesired, double pitchDesired, double yawDesired, double thrustDesired, quint64 msec)
//{
////    updateValue(uas, "roll desired", rollDesired, msec);
////    updateValue(uas, "pitch desired", pitchDesired, msec);
////    updateValue(uas, "yaw desired", yawDesired, msec);
////    updateValue(uas, "thrust desired", thrustDesired, msec);
//}
pixhawk's avatar
pixhawk committed
325
326
327

void HUD::updateAttitude(UASInterface* uas, double roll, double pitch, double yaw, quint64 timestamp)
{
328
329
    Q_UNUSED(uas);
    Q_UNUSED(timestamp);
Lorenz Meier's avatar
Lorenz Meier committed
330
331
332
333
334
335
    if (!isnan(roll) && !isinf(roll) && !isnan(pitch) && !isinf(pitch) && !isnan(yaw) && !isinf(yaw))
    {
        this->roll = roll;
        this->pitch = pitch*3.35f; // Constant here is the 'focal length' of the projection onto the plane
        this->yaw = yaw;
    }
pixhawk's avatar
pixhawk committed
336
337
}

338
339
340
341
void HUD::updateAttitude(UASInterface* uas, int component, double roll, double pitch, double yaw, quint64 timestamp)
{
    Q_UNUSED(uas);
    Q_UNUSED(timestamp);
Lorenz Meier's avatar
Lorenz Meier committed
342
343
344
345
    if (!isnan(roll) && !isinf(roll) && !isnan(pitch) && !isinf(pitch) && !isnan(yaw) && !isinf(yaw))
    {
        attitudes.insert(component, QVector3D(roll, pitch*3.35f, yaw)); // Constant here is the 'focal length' of the projection onto the plane
    }
346
347
}

dongfang's avatar
dongfang committed
348
void HUD::updateBattery(UASInterface* uas, double voltage, double current, double percent, int seconds)
pixhawk's avatar
pixhawk committed
349
{
350
    Q_UNUSED(uas);
351
    Q_UNUSED(seconds);
dongfang's avatar
dongfang committed
352
    Q_UNUSED(current);
353
    fuelStatus = tr("BAT [%1% | %2V]").arg(percent, 2, 'f', 0, QChar('0')).arg(voltage, 4, 'f', 1, QChar('0'));
354
    if (percent < 20.0f) {
pixhawk's avatar
pixhawk committed
355
        fuelColor = warningColor;
356
    } else if (percent < 10.0f) {
pixhawk's avatar
pixhawk committed
357
        fuelColor = criticalColor;
358
    } else {
pixhawk's avatar
pixhawk committed
359
360
361
362
363
364
365
366
        fuelColor = infoColor;
    }
}

void HUD::receiveHeartbeat(UASInterface*)
{
}

367
void HUD::updateThrust(UASInterface* uas, double thrust)
pixhawk's avatar
pixhawk committed
368
{
369
370
371
    Q_UNUSED(uas);
    Q_UNUSED(thrust);
//    updateValue(uas, "thrust", thrust, MG::TIME::getGroundTimeNow());
pixhawk's avatar
pixhawk committed
372
373
374
375
}

void HUD::updateLocalPosition(UASInterface* uas,double x,double y,double z,quint64 timestamp)
{
376
377
378
379
380
    Q_UNUSED(uas);
    Q_UNUSED(timestamp);
    this->xPos = x;
    this->yPos = y;
    this->zPos = z;
pixhawk's avatar
pixhawk committed
381
382
}

383
void HUD::updateGlobalPosition(UASInterface* uas,double lat, double lon, double altitudeAMSL, double altitudeWGS84, quint64 timestamp)
pixhawk's avatar
pixhawk committed
384
{
385
    Q_UNUSED(uas);
386
    Q_UNUSED(altitudeAMSL);
387
388
389
    Q_UNUSED(timestamp);
    this->lat = lat;
    this->lon = lon;
390
    this->alt = altitudeWGS84;
pixhawk's avatar
pixhawk committed
391
392
393
394
}

void HUD::updateSpeed(UASInterface* uas,double x,double y,double z,quint64 timestamp)
{
395
396
397
398
399
    Q_UNUSED(uas);
    Q_UNUSED(timestamp);
    this->xSpeed = x;
    this->ySpeed = y;
    this->zSpeed = z;
pixhawk's avatar
pixhawk committed
400
401
402
    double newTotalSpeed = sqrt(xSpeed*xSpeed + ySpeed*ySpeed + zSpeed*zSpeed);
    totalAcc = (newTotalSpeed - totalSpeed) / ((double)(lastSpeedUpdate - timestamp)/1000.0);
    totalSpeed = newTotalSpeed;
pixhawk's avatar
pixhawk committed
403
404
405
406
407
408
409
410
}

/**
 * Updates the current system state, but only if the uas matches the currently monitored uas.
 *
 * @param uas the system the state message originates from
 * @param state short state text, displayed in HUD
 */
411
void HUD::updateState(UASInterface* uas,QString state)
pixhawk's avatar
pixhawk committed
412
{
413
414
    // Only one UAS is connected at a time
    Q_UNUSED(uas);
415
416
417
418
419
420
421
422
423
    this->state = state;
}

/**
 * Updates the current system mode, but only if the uas matches the currently monitored uas.
 *
 * @param uas the system the state message originates from
 * @param mode short mode text, displayed in HUD
 */
424
void HUD::updateMode(int id,QString mode, QString description)
425
{
426
    // Only one UAS is connected at a time
427
428
    Q_UNUSED(id);
    Q_UNUSED(description);
429
    this->mode = mode;
pixhawk's avatar
pixhawk committed
430
431
432
433
}

void HUD::updateLoad(UASInterface* uas, double load)
{
434
435
436
    Q_UNUSED(uas);
    this->load = load;
    //updateValue(uas, "load", load, MG::TIME::getGroundTimeNow());
pixhawk's avatar
pixhawk committed
437
438
439
440
441
442
443
444
}

/**
 * @param y coordinate in pixels to be converted to reference mm units
 * @return the screen coordinate relative to the QGLWindow origin
 */
float HUD::refToScreenX(float x)
{
445
    //qDebug() << "sX: " << (scalingFactor * x) << "Orig:" << x;
pixhawk's avatar
pixhawk committed
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
    return (scalingFactor * x);
}
/**
 * @param x coordinate in pixels to be converted to reference mm units
 * @return the screen coordinate relative to the QGLWindow origin
 */
float HUD::refToScreenY(float y)
{
    //qDebug() << "sY: " << (scalingFactor * y);
    return (scalingFactor * y);
}

/**
 * Paint text on top of the image and OpenGL drawings
 *
 * @param text chars to write
 * @param color text color
 * @param fontSize text size in mm
 * @param refX position in reference units (mm of the real instrument). This is relative to the measurement unit position, NOT in pixels.
 * @param refY position in reference units (mm of the real instrument). This is relative to the measurement unit position, NOT in pixels.
 */
void HUD::paintText(QString text, QColor color, float fontSize, float refX, float refY, QPainter* painter)
{
    QPen prevPen = painter->pen();
    float pPositionX = refToScreenX(refX) - (fontSize*scalingFactor*0.072f);
    float pPositionY = refToScreenY(refY) - (fontSize*scalingFactor*0.212f);

473
474
    QFont font("Bitstream Vera Sans");
    // Enforce minimum font size of 5 pixels
475
    int fSize = qMax(5, (int)(fontSize*scalingFactor*1.26f));
476
    font.setPixelSize(fSize);
pixhawk's avatar
pixhawk committed
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498

    QFontMetrics metrics = QFontMetrics(font);
    int border = qMax(4, metrics.leading());
    QRect rect = metrics.boundingRect(0, 0, width() - 2*border, int(height()*0.125),
                                      Qt::AlignLeft | Qt::TextWordWrap, text);
    painter->setPen(color);
    painter->setFont(font);
    painter->setRenderHint(QPainter::TextAntialiasing);
    painter->drawText(pPositionX, pPositionY,
                      rect.width(), rect.height(),
                      Qt::AlignCenter | Qt::TextWordWrap, text);
    painter->setPen(prevPen);
}

/**
 * @param referencePositionX horizontal position in the reference mm-unit space
 * @param referencePositionY horizontal position in the reference mm-unit space
 * @param referenceWidth width in the reference mm-unit space
 * @param referenceHeight width in the reference mm-unit space
 */
void HUD::setupGLView(float referencePositionX, float referencePositionY, float referenceWidth, float referenceHeight)
{
499
500
501
502
503
504
    Q_UNUSED(referencePositionX);
    Q_UNUSED(referencePositionY);
    Q_UNUSED(referenceWidth);
    Q_UNUSED(referenceHeight);
#if 0
    // code ifdef'ed out but left in to silence warnings
pixhawk's avatar
pixhawk committed
505
506
507
508
509
    int pixelWidth  = (int)(referenceWidth * scalingFactor);
    int pixelHeight = (int)(referenceHeight * scalingFactor);
    // Translate and scale the GL view in the virtual reference coordinate units on the screen
    int pixelPositionX = (int)((referencePositionX * scalingFactor) + xCenterOffset);
    int pixelPositionY = this->height() - (referencePositionY * scalingFactor) + yCenterOffset - pixelHeight;
510
#endif
pixhawk's avatar
pixhawk committed
511
512
513
514
515
516
517
}

void HUD::paintRollPitchStrips()
{
}


pixhawk's avatar
pixhawk committed
518
void HUD::paintEvent(QPaintEvent *event)
pixhawk's avatar
pixhawk committed
519
{
520
    Q_UNUSED(event);
521
    paintHUD();
522
523
524
525
}

void HUD::paintHUD()
{
526
    if (isVisible()) {
pixhawk's avatar
pixhawk committed
527
528
529
        //    static quint64 interval = 0;
        //    qDebug() << "INTERVAL:" << MG::TIME::getGroundTimeNow() - interval << __FILE__ << __LINE__;
        //    interval = MG::TIME::getGroundTimeNow();
lm's avatar
lm committed
530

531
#if (QGC_EVENTLOOP_DEBUG)
pixhawk's avatar
pixhawk committed
532
        qDebug() << "EVENTLOOP:" << __FILE__ << __LINE__;
533
534
#endif

pixhawk's avatar
pixhawk committed
535
536
        // Read out most important values to limit hash table lookups
        // Low-pass roll, pitch and yaw
537
538
        rollLP = roll;//rollLP * 0.2f + 0.8f * roll;
        pitchLP = pitch;//pitchLP * 0.2f + 0.8f * pitch;
539
        yawLP = (!isinf(yaw) && !isnan(yaw)) ? yaw : yawLP;//yawLP * 0.2f + 0.8f * yaw;
pixhawk's avatar
pixhawk committed
540

pixhawk's avatar
pixhawk committed
541
542
        // Translate for yaw
        const float maxYawTrans = 60.0f;
pixhawk's avatar
pixhawk committed
543

pixhawk's avatar
pixhawk committed
544
545
546
        float newYawDiff = yawDiff;
        if (isinf(newYawDiff)) newYawDiff = yawDiff;
        if (newYawDiff > M_PI) newYawDiff = newYawDiff - M_PI;
547

pixhawk's avatar
pixhawk committed
548
        if (newYawDiff < -M_PI) newYawDiff = newYawDiff + M_PI;
549

pixhawk's avatar
pixhawk committed
550
        newYawDiff = yawDiff * 0.8 + newYawDiff * 0.2;
551

pixhawk's avatar
pixhawk committed
552
        yawDiff = newYawDiff;
553

pixhawk's avatar
pixhawk committed
554
        yawInt += newYawDiff;
555

556
557
        if (yawInt > M_PI) yawInt = (float)M_PI;
        if (yawInt < -M_PI) yawInt = (float)-M_PI;
558

559
        float yawTrans = yawInt * (float)maxYawTrans;
pixhawk's avatar
pixhawk committed
560
        yawInt *= 0.6f;
lm's avatar
lm committed
561

pixhawk's avatar
pixhawk committed
562
        if ((yawTrans < 5.0) && (yawTrans > -5.0)) yawTrans = 0;
lm's avatar
lm committed
563

pixhawk's avatar
pixhawk committed
564
565
        // Negate to correct direction
        yawTrans = -yawTrans;
lm's avatar
lm committed
566

567
568
        yawTrans = 0;

pixhawk's avatar
pixhawk committed
569
        //qDebug() << "yaw translation" << yawTrans << "integral" << yawInt << "difference" << yawDiff << "yaw" << yaw;
570

pixhawk's avatar
pixhawk committed
571
572
573
574
575
        // Update scaling factor
        // adjust scaling to fit both horizontally and vertically
        scalingFactor = this->width()/vwidth;
        double scalingFactorH = this->height()/vheight;
        if (scalingFactorH < scalingFactor) scalingFactor = scalingFactorH;
pixhawk's avatar
pixhawk committed
576

Bryant's avatar
Bryant committed
577
        // And if either video or the data stream is enabled, draw the next frame.
578
        if (videoEnabled)
pixhawk's avatar
pixhawk committed
579
        {
LM's avatar
LM committed
580
581
            xImageFactor = width() / (float)glImage.width();
            yImageFactor = height() / (float)glImage.height();
582
        }
pixhawk's avatar
pixhawk committed
583

584
585
586
587
588
589
590
        QPainter painter;
        painter.begin(this);
        painter.setRenderHint(QPainter::Antialiasing, true);
        painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
        QPixmap pmap = QPixmap::fromImage(glImage).scaledToWidth(width());
        painter.drawPixmap(0, (height() - pmap.height()) / 2, pmap);

pixhawk's avatar
pixhawk committed
591
592
        // END OF OPENGL PAINTING

593
        if (HUDInstrumentsEnabled)
Bryant's avatar
Bryant committed
594
        {
pixhawk's avatar
pixhawk committed
595

596
597
598
599
            //glEnable(GL_MULTISAMPLE);

            // QT PAINTING
            //makeCurrent();
600

601
602
603
604
605
606
            painter.translate((this->vwidth/2.0+xCenterOffset)*scalingFactor, (this->vheight/2.0+yCenterOffset)*scalingFactor);

            // COORDINATE FRAME IS NOW (0,0) at CENTER OF WIDGET

            // Draw all fixed indicators
            // BATTERY
607
            paintText(fuelStatus, fuelColor, 6.0f, (-vwidth/2.0) + 10, -vheight/2.0 + 6, &painter);
608
            // Waypoint
609
610
611
612
613
614
615
            paintText(waypointName, defaultColor, 6.0f, (-vwidth/3.0) + 10, +vheight/3.0 + 15, &painter);

            QPen linePen(Qt::SolidLine);
            linePen.setWidth(refLineWidthToPen(1.0f));
            linePen.setColor(defaultColor);
            painter.setBrush(Qt::NoBrush);
            painter.setPen(linePen);
pixhawk's avatar
pixhawk committed
616

617
618
619
620
621
622
            // YAW INDICATOR
            //
            //      .
            //    .   .
            //   .......
            //
623
624
            const float yawIndicatorWidth = 12.0f;
            const float yawIndicatorY = vheight/2.0f - 15.0f;
625
626
627
628
629
630
            QPolygon yawIndicator(4);
            yawIndicator.setPoint(0, QPoint(refToScreenX(0.0f), refToScreenY(yawIndicatorY)));
            yawIndicator.setPoint(1, QPoint(refToScreenX(yawIndicatorWidth/2.0f), refToScreenY(yawIndicatorY+yawIndicatorWidth)));
            yawIndicator.setPoint(2, QPoint(refToScreenX(-yawIndicatorWidth/2.0f), refToScreenY(yawIndicatorY+yawIndicatorWidth)));
            yawIndicator.setPoint(3, QPoint(refToScreenX(0.0f), refToScreenY(yawIndicatorY)));
            painter.drawPolyline(yawIndicator);
631
            painter.setPen(linePen);
pixhawk's avatar
pixhawk committed
632

633
            // CENTER
pixhawk's avatar
pixhawk committed
634

635
636
637
638
639
            // HEADING INDICATOR
            //
            //    __      __
            //       \/\/
            //
640
            const float hIndicatorWidth = 20.0f;
641
642
643
644
645
646
647
648
649
650
651
652
            const float hIndicatorY = -25.0f;
            const float hIndicatorYLow = hIndicatorY + hIndicatorWidth / 6.0f;
            const float hIndicatorSegmentWidth = hIndicatorWidth / 7.0f;
            QPolygon hIndicator(7);
            hIndicator.setPoint(0, QPoint(refToScreenX(0.0f-hIndicatorWidth/2.0f), refToScreenY(hIndicatorY)));
            hIndicator.setPoint(1, QPoint(refToScreenX(0.0f-hIndicatorWidth/2.0f+hIndicatorSegmentWidth*1.75f), refToScreenY(hIndicatorY)));
            hIndicator.setPoint(2, QPoint(refToScreenX(0.0f-hIndicatorSegmentWidth*1.0f), refToScreenY(hIndicatorYLow)));
            hIndicator.setPoint(3, QPoint(refToScreenX(0.0f), refToScreenY(hIndicatorY)));
            hIndicator.setPoint(4, QPoint(refToScreenX(0.0f+hIndicatorSegmentWidth*1.0f), refToScreenY(hIndicatorYLow)));
            hIndicator.setPoint(5, QPoint(refToScreenX(0.0f+hIndicatorWidth/2.0f-hIndicatorSegmentWidth*1.75f), refToScreenY(hIndicatorY)));
            hIndicator.setPoint(6, QPoint(refToScreenX(0.0f+hIndicatorWidth/2.0f), refToScreenY(hIndicatorY)));
            painter.drawPolyline(hIndicator);
pixhawk's avatar
pixhawk committed
653
654


655
            // SETPOINT
656
            const float centerWidth = 8.0f;
657
658
            // TODO
            //painter.drawEllipse(QPointF(refToScreenX(qMin(10.0f, values.value("roll desired", 0.0f) * 10.0f)), refToScreenY(qMin(10.0f, values.value("pitch desired", 0.0f) * 10.0f))), refToScreenX(centerWidth/2.0f), refToScreenX(centerWidth/2.0f));
pixhawk's avatar
pixhawk committed
659

660
            const float centerCrossWidth = 20.0f;
661
662
663
664
665
666
            // left
            painter.drawLine(QPointF(refToScreenX(-centerWidth / 2.0f), refToScreenY(0.0f)), QPointF(refToScreenX(-centerCrossWidth / 2.0f), refToScreenY(0.0f)));
            // right
            painter.drawLine(QPointF(refToScreenX(centerWidth / 2.0f), refToScreenY(0.0f)), QPointF(refToScreenX(centerCrossWidth / 2.0f), refToScreenY(0.0f)));
            // top
            painter.drawLine(QPointF(refToScreenX(0.0f), refToScreenY(-centerWidth / 2.0f)), QPointF(refToScreenX(0.0f), refToScreenY(-centerCrossWidth / 2.0f)));
pixhawk's avatar
pixhawk committed
667

668

pixhawk's avatar
pixhawk committed
669

670
            // COMPASS
671
672
            const float compassY = -vheight/2.0f + 6.0f;
            QRectF compassRect(QPointF(refToScreenX(-12.0f), refToScreenY(compassY)), QSizeF(refToScreenX(24.0f), refToScreenY(12.0f)));
673
            painter.setBrush(Qt::NoBrush);
674
675
            painter.setPen(linePen);
            painter.drawRoundedRect(compassRect, 3, 3);
676
            QString yawAngle;
pixhawk's avatar
pixhawk committed
677

678
            //    const float yawDeg = ((values.value("yaw", 0.0f)/M_PI)*180.0f)+180.f;
pixhawk's avatar
pixhawk committed
679

Lorenz Meier's avatar
Lorenz Meier committed
680
            // YAW is in compass-human readable format, so 0 .. 360 deg.
barthess's avatar
barthess committed
681
            float yawDeg = (yawLP / M_PI) * 180.0f;
Lorenz Meier's avatar
Lorenz Meier committed
682
683
684
            if (yawDeg < 0) yawDeg += 360;
            if (yawDeg > 360) yawDeg -= 360;
            /* final safeguard for really stupid systems */
685
686
            int yawCompass = static_cast<int>(yawDeg) % 360;
            yawAngle.sprintf("%03d", yawCompass);
687
688
689
690
            paintText(yawAngle, defaultColor,8.5f, -9.8f, compassY+ 1.7f, &painter);

            painter.setBrush(Qt::NoBrush);
            painter.setPen(linePen);
pixhawk's avatar
pixhawk committed
691

692
            // CHANGE RATE STRIPS
693
            drawChangeRateStrip(-95.0f, -60.0f, 40.0f, -10.0f, 10.0f, -zSpeed, &painter);
pixhawk's avatar
pixhawk committed
694

695
            // CHANGE RATE STRIPS
696
            drawChangeRateStrip(95.0f, -60.0f, 40.0f, -10.0f, 10.0f, totalAcc, &painter,true);
697
698

            // GAUGES
pixhawk's avatar
pixhawk committed
699

700
            // Left altitude gauge
pixhawk's avatar
pixhawk committed
701
702
            float gaugeAltitude;

703
            if (this->alt != 0) {
pixhawk's avatar
pixhawk committed
704
                gaugeAltitude = alt;
705
            } else {
pixhawk's avatar
pixhawk committed
706
707
708
                gaugeAltitude = -zPos;
            }

709
710
711
            painter.setBrush(Qt::NoBrush);
            painter.setPen(linePen);

712
            drawChangeIndicatorGauge(-vGaugeSpacing, 35.0f, 15.0f, 10.0f, gaugeAltitude, defaultColor, &painter, false);
713
            paintText("alt m", defaultColor, 5.5f, -73.0f, 50, &painter);
714

715
            // Right speed gauge
716
            drawChangeIndicatorGauge(vGaugeSpacing, 35.0f, 15.0f, 10.0f, totalSpeed, defaultColor, &painter, false);
717
            paintText("v m/s", defaultColor, 5.5f, 55.0f, 50, &painter);
pixhawk's avatar
pixhawk committed
718
719


720
721
722
723
724
725
726
727
            // Waypoint name
            if (waypointName != "") paintText(waypointName, defaultColor, 2.0f, (-vwidth/3.0) + 10, +vheight/3.0 + 15, &painter);

            // MOVING PARTS


            painter.translate(refToScreenX(yawTrans), 0);

728
729
730
731
732
733
734
            // Old single-component pitch drawing
//            // Rotate view and draw all roll-dependent indicators
//            painter.rotate((rollLP/M_PI)* -180.0f);

//            painter.translate(0, (-pitchLP/(float)M_PI)* -180.0f * refToScreenY(1.8f));

//            //qDebug() << "ROLL" << roll << "PITCH" << pitch << "YAW DIFF" << valuesDot.value("roll", 0.0f);
735

736
//            // PITCH
737

738
//            paintPitchLines(pitchLP, &painter);
739

740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
            QColor attColor = painter.pen().color();

            // Draw multi-component attitude
            foreach (QVector3D att, attitudes.values())
            {
                attColor = attColor.darker(200);
                painter.setPen(attColor);
                // Rotate view and draw all roll-dependent indicators
                painter.rotate((att.x()/M_PI)* -180.0f);

                painter.translate(0, (-att.y()/(float)M_PI)* -180.0f * refToScreenY(1.8f));

                //qDebug() << "ROLL" << roll << "PITCH" << pitch << "YAW DIFF" << valuesDot.value("roll", 0.0f);

                // PITCH

                paintPitchLines(att.y(), &painter);
757
758
                painter.translate(0, -(-att.y()/(float)M_PI)* -180.0f * refToScreenY(1.8f));
                painter.rotate(-(att.x()/M_PI)* -180.0f);
759
            }
pixhawk's avatar
pixhawk committed
760

761

762
        }
763
764

        painter.end();
pixhawk's avatar
pixhawk committed
765
    }
766

pixhawk's avatar
pixhawk committed
767
768
}

pixhawk's avatar
pixhawk committed
769
770
771
772
773
774
775
776
777
778
779
780

/**
 * @param pitch pitch angle in degrees (-180 to 180)
 */
void HUD::paintPitchLines(float pitch, QPainter* painter)
{
    QString label;

    const float yDeg = vPitchPerDeg;
    const float lineDistance = 5.0f; ///< One pitch line every 10 degrees
    const float posIncrement = yDeg * lineDistance;
    float posY = posIncrement;
781
    const float posLimit = sqrt(pow(vwidth, 2.0f) + pow(vheight, 2.0f))*3.0f;
pixhawk's avatar
pixhawk committed
782
783
784
785
786
787

    const float offsetAbs = pitch * yDeg;

    float offset = pitch;
    if (offset < 0) offset = -offset;
    int offsetCount = 0;
788
789
790
791
    while (offset > lineDistance) {
        offset -= lineDistance;
        offsetCount++;
    }
pixhawk's avatar
pixhawk committed
792
793
794
795
796
797
798
799
800
801
802

    int iPos = (int)(0.5f + lineDistance); ///< The first line
    int iNeg = (int)(-0.5f - lineDistance); ///< The first line

    offset *= yDeg;


    painter->setPen(defaultColor);

    posY = -offsetAbs + posIncrement; //+ 100;// + lineDistance;

803
    while (posY < posLimit) {
pixhawk's avatar
pixhawk committed
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
        paintPitchLinePos(label.sprintf("%3d", iPos), 0.0f, -posY, painter);
        posY += posIncrement;
        iPos += (int)lineDistance;
    }



    // HORIZON
    //
    //    ------------    ------------
    //
    const float pitchWidth = 30.0f;
    const float pitchGap = pitchWidth / 2.5f;
    const QColor horizonColor = defaultColor;
    const float diagonal = sqrt(pow(vwidth, 2.0f) + pow(vheight, 2.0f));
    const float lineWidth = refLineWidthToPen(0.5f);

    // Left horizon
    drawLine(0.0f-diagonal, offsetAbs, 0.0f-pitchGap/2.0f, offsetAbs, lineWidth, horizonColor, painter);
    // Right horizon
    drawLine(0.0f+pitchGap/2.0f, offsetAbs, 0.0f+diagonal, offsetAbs, lineWidth, horizonColor, painter);



    label.clear();

    posY = offsetAbs  + posIncrement;


833
    while (posY < posLimit) {
pixhawk's avatar
pixhawk committed
834
835
836
837
838
839
840
841
842
843
844
845
846
        paintPitchLineNeg(label.sprintf("%3d", iNeg), 0.0f, posY, painter);
        posY += posIncrement;
        iNeg -= (int)lineDistance;
    }
}

void HUD::paintPitchLinePos(QString text, float refPosX, float refPosY, QPainter* painter)
{
    //painter->setPen(QPen(QBrush, normalStrokeWidth));

    const float pitchWidth = 30.0f;
    const float pitchGap = pitchWidth / 2.5f;
    const float pitchHeight = pitchWidth / 12.0f;
847
848
    const float textSize = pitchHeight * 1.6f;
    const float lineWidth = 1.5f;
pixhawk's avatar
pixhawk committed
849
850
851
852
853
854
855
856
857
858
859
860

    // Positive pitch indicator:
    //
    //      _______      _______
    //     |10                  |
    //

    // Left vertical line
    drawLine(refPosX-pitchWidth/2.0f, refPosY, refPosX-pitchWidth/2.0f, refPosY+pitchHeight, lineWidth, defaultColor, painter);
    // Left horizontal line
    drawLine(refPosX-pitchWidth/2.0f, refPosY, refPosX-pitchGap/2.0f, refPosY, lineWidth, defaultColor, painter);
    // Text left
861
    paintText(text, defaultColor, textSize, refPosX-pitchWidth/2.0 + 0.75f, refPosY + pitchHeight - 1.3f, painter);
pixhawk's avatar
pixhawk committed
862
863
864
865
866
867
868
869
870
871
872
873

    // Right vertical line
    drawLine(refPosX+pitchWidth/2.0f, refPosY, refPosX+pitchWidth/2.0f, refPosY+pitchHeight, lineWidth, defaultColor, painter);
    // Right horizontal line
    drawLine(refPosX+pitchWidth/2.0f, refPosY, refPosX+pitchGap/2.0f, refPosY, lineWidth, defaultColor, painter);
}

void HUD::paintPitchLineNeg(QString text, float refPosX, float refPosY, QPainter* painter)
{
    const float pitchWidth = 30.0f;
    const float pitchGap = pitchWidth / 2.5f;
    const float pitchHeight = pitchWidth / 12.0f;
874
    const float textSize = pitchHeight * 1.6f;
pixhawk's avatar
pixhawk committed
875
876
    const float segmentWidth = ((pitchWidth - pitchGap)/2.0f) / 7.0f; ///< Four lines and three gaps -> 7 segments

877
    const float lineWidth = 1.5f;
pixhawk's avatar
pixhawk committed
878
879
880
881
882
883
884
885
886
887
888

    // Negative pitch indicator:
    //
    //      -10
    //     _ _ _ _|     |_ _ _ _
    //
    //

    // Left vertical line
    drawLine(refPosX-pitchGap/2.0, refPosY, refPosX-pitchGap/2.0, refPosY-pitchHeight, lineWidth, defaultColor, painter);
    // Left horizontal line with four segments
889
    for (int i = 0; i < 7; i+=2) {
pixhawk's avatar
pixhawk committed
890
891
892
        drawLine(refPosX-pitchWidth/2.0+(i*segmentWidth), refPosY, refPosX-pitchWidth/2.0+(i*segmentWidth)+segmentWidth, refPosY, lineWidth, defaultColor, painter);
    }
    // Text left
893
    paintText(text, defaultColor, textSize, refPosX-pitchWidth/2.0f + 0.75f, refPosY + pitchHeight - 1.3f, painter);
pixhawk's avatar
pixhawk committed
894
895
896
897

    // Right vertical line
    drawLine(refPosX+pitchGap/2.0, refPosY, refPosX+pitchGap/2.0, refPosY-pitchHeight, lineWidth, defaultColor, painter);
    // Right horizontal line with four segments
898
    for (int i = 0; i < 7; i+=2) {
pixhawk's avatar
pixhawk committed
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
        drawLine(refPosX+pitchWidth/2.0f-(i*segmentWidth), refPosY, refPosX+pitchWidth/2.0f-(i*segmentWidth)-segmentWidth, refPosY, lineWidth, defaultColor, painter);
    }
}

void rotatePointClockWise(QPointF& p, float angle)
{
    // Standard 2x2 rotation matrix, counter-clockwise
    //
    //   |  cos(phi)   sin(phi) |
    //   | -sin(phi)   cos(phi) |
    //

    //p.setX(cos(angle) * p.x() + sin(angle) * p.y());
    //p.setY(-sin(angle) * p.x() + cos(angle) * p.y());


    p.setX(cos(angle) * p.x() + sin(angle)* p.y());
    p.setY((-1.0f * sin(angle) * p.x()) + cos(angle) * p.y());
}

float HUD::refLineWidthToPen(float line)
{
    return line * 2.50f;
}

/**
 * Rotate a polygon around a point
 *
 * @param p polygon to rotate
 * @param origin the rotation center
 * @param angle rotation angle, in radians
 * @return p Polygon p rotated by angle around the origin point
 */
void HUD::rotatePolygonClockWiseRad(QPolygonF& p, float angle, QPointF origin)
{
    // Standard 2x2 rotation matrix, counter-clockwise
    //
    //   |  cos(phi)   sin(phi) |
    //   | -sin(phi)   cos(phi) |
    //
939
    for (int i = 0; i < p.size(); i++) {
pixhawk's avatar
pixhawk committed
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
        QPointF curr = p.at(i);

        const float x = curr.x();
        const float y = curr.y();

        curr.setX(((cos(angle) * (x-origin.x())) + (-sin(angle) * (y-origin.y()))) + origin.x());
        curr.setY(((sin(angle) * (x-origin.x())) + (cos(angle) * (y-origin.y()))) + origin.y());
        p.replace(i, curr);
    }
}

void HUD::drawPolygon(QPolygonF refPolygon, QPainter* painter)
{
    // Scale coordinates
    QPolygonF draw(refPolygon.size());
955
    for (int i = 0; i < refPolygon.size(); i++) {
pixhawk's avatar
pixhawk committed
956
957
958
959
960
961
962
963
        QPointF curr;
        curr.setX(refToScreenX(refPolygon.at(i).x()));
        curr.setY(refToScreenY(refPolygon.at(i).y()));
        draw.replace(i, curr);
    }
    painter->drawPolygon(draw);
}

964
void HUD::drawChangeRateStrip(float xRef, float yRef, float height, float minRate, float maxRate, float value, QPainter* painter,bool reverse)
pixhawk's avatar
pixhawk committed
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
{
    float scaledValue = value;

    // Saturate value
    if (value > maxRate) scaledValue = maxRate;
    if (value < minRate) scaledValue = minRate;

    //           x (Origin: xRef, yRef)
    //           -
    //           |
    //           |
    //           |
    //           =
    //           |
    //   -0.005 >|
    //           |
    //           -

    const float width = height / 8.0f;
984
    const float lineWidth = 1.5f;
pixhawk's avatar
pixhawk committed
985
986
987

    // Indicator lines
    // Top horizontal line
988
989
990
991
992
993
994
995
996
997
998
999
1000
    if (reverse)
    {
        drawLine(xRef, yRef, xRef-width, yRef, lineWidth, defaultColor, painter);
        // Vertical main line
        drawLine(xRef-width/2.0f, yRef, xRef-width/2.0f, yRef+height, lineWidth, defaultColor, painter);
        // Zero mark
        drawLine(xRef, yRef+height/2.0f, xRef-width, yRef+height/2.0f, lineWidth, defaultColor, painter);
        // Horizontal bottom line
        drawLine(xRef, yRef+height, xRef-width, yRef+height, lineWidth, defaultColor, painter);

        // Text
        QString label;
        label.sprintf("%+06.2f >", value);
For faster browsing, not all history is shown. View entire blame