HSIDisplay.cc 46.5 KB
Newer Older
1 2
/*=====================================================================

3
QGroundControl Open Source Ground Control Station
4

5
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
6

7
This file is part of the QGROUNDCONTROL project
8

9
    QGROUNDCONTROL is free software: you can redistribute it and/or modify
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,
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/>.
21 22 23 24 25 26 27 28 29 30 31 32 33

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

/**
 * @file
 *   @brief Implementation of Horizontal Situation Indicator class
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QFile>
#include <QStringList>
34
#include <QPainter>
35 36 37
#include <QGraphicsScene>
#include <QHBoxLayout>
#include <QDoubleSpinBox>
38 39
#include "UASManager.h"
#include "HSIDisplay.h"
40
#include "QGC.h"
pixhawk's avatar
pixhawk committed
41
#include "Waypoint.h"
42
#include "UASWaypointManager.h"
43
#include <qmath.h>
lm's avatar
lm committed
44
//#include "Waypoint2DIcon.h"
45
#include "MAV2DIcon.h"
46 47 48

#include <QDebug>

49

50
HSIDisplay::HSIDisplay(QWidget *parent) :
51
    HDDisplay(NULL, "HSI", parent),
52 53 54 55 56 57 58
    dragStarted(false),
    leftDragStarted(false),
    mouseHasMoved(false),
    startX(0.0f),
    startY(0.0f),
    actionPending(false),
    directSending(false),
59 60 61 62 63 64 65 66 67
    gpsSatellites(),
    satellitesUsed(0),
    attXSet(0.0f),
    attYSet(0.0f),
    attYawSet(0.0f),
    altitudeSet(1.0f),
    posXSet(0.0f),
    posYSet(0.0f),
    posZSet(0.0f),
68 69
    attXSaturation(0.2f),
    attYSaturation(0.2f),
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
    attYawSaturation(0.5f),
    posXSaturation(0.05f),
    posYSaturation(0.05f),
    altitudeSaturation(1.0f),
    lat(0.0f),
    lon(0.0f),
    alt(0.0f),
    globalAvailable(0),
    x(0.0f),
    y(0.0f),
    z(0.0f),
    vx(0.0f),
    vy(0.0f),
    vz(0.0f),
    speed(0.0f),
    localAvailable(0),
    roll(0.0f),
    pitch(0.0f),
    yaw(0.0f),
    bodyXSetCoordinate(0.0f),
    bodyYSetCoordinate(0.0f),
    bodyZSetCoordinate(0.0f),
    bodyYawSet(0.0f),
    uiXSetCoordinate(0.0f),
    uiYSetCoordinate(0.0f),
LM's avatar
LM committed
95
    uiZSetCoordinate(0.0f),
96 97
    uiYawSet(0.0f),
    metricWidth(4.0),
98 99
    xCenterPos(0),
    yCenterPos(0),
100 101 102 103 104 105 106 107 108
    positionLock(false),
    attControlEnabled(false),
    xyControlEnabled(false),
    zControlEnabled(false),
    yawControlEnabled(false),
    positionFix(0),
    gpsFix(0),
    visionFix(0),
    laserFix(0),
109
    iruFix(0),
110
    mavInitialized(false),
111
    topMargin(12.0f),
112 113 114 115 116 117 118 119 120 121 122
    bottomMargin(10.0f),
    attControlKnown(false),
    xyControlKnown(false),
    zControlKnown(false),
    yawControlKnown(false),
    positionFixKnown(false),
    visionFixKnown(false),
    gpsFixKnown(false),
    iruFixKnown(false),
    setPointKnown(false),
    positionSetPointKnown(false),
123
    userSetPointSet(false),
LM's avatar
LM committed
124 125 126
    userXYSetPointSet(false),
    userZSetPointSet(false),
    userYawSetPointSet(false)
127
{
128
    refreshTimer->setInterval(updateInterval);
129

pixhawk's avatar
pixhawk committed
130
    columns = 1;
131
    this->setAutoFillBackground(true);
132 133 134
    QPalette pal = palette();
    pal.setColor(backgroundRole(), QGC::colorBlack);
    setPalette(pal);
135

136 137
    vwidth = 80.0f;
    vheight = 80.0f;
pixhawk's avatar
pixhawk committed
138

139
    xCenterPos = vwidth/2.0f;
pixhawk's avatar
pixhawk committed
140
    yCenterPos = vheight/2.0f + topMargin - bottomMargin;
141

142 143 144
    uas = NULL;
    resetMAVState();

145 146
    // Do first update
    setMetricWidth(metricWidth);
147 148 149
    // Set tooltip
    setToolTip(tr("View from top in body frame. Scroll with mouse wheel to change the horizontal field of view of the widget."));
    setStatusTip(tr("View from top in body frame. Scroll with mouse wheel to change the horizontal field of view of the widget."));
150 151

    connect(&statusClearTimer, SIGNAL(timeout()), this, SLOT(clearStatusMessage()));
152 153 154
    statusClearTimer.start(3000);

    setFocusPolicy(Qt::StrongFocus);
155 156
}

157 158 159 160 161
HSIDisplay::~HSIDisplay()
{

}

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
void HSIDisplay::resetMAVState()
{
    mavInitialized = false;
    attControlKnown = false;
    attControlEnabled = false;
    xyControlKnown = false;
    xyControlEnabled = false;
    zControlKnown = false;
    zControlEnabled = false;
    yawControlKnown = false;
    yawControlEnabled = false;

    // Draw position lock indicators
    positionFixKnown = false;
    positionFix = 0;
    visionFixKnown = false;
    visionFix = 0;
    gpsFixKnown = false;
    gpsFix = 0;
    iruFixKnown = false;
    iruFix = 0;

    // Data
    setPointKnown = false;
    localAvailable = 0;
    globalAvailable = 0;
188 189 190 191

    // Setpoints
    positionSetPointKnown = false;
    setPointKnown = false;
192 193
}

lm's avatar
lm committed
194 195 196 197
void HSIDisplay::paintEvent(QPaintEvent * event)
{
    Q_UNUSED(event);
    //paintGL();
198 199 200
    //    static quint64 interval = 0;
    //    //qDebug() << "INTERVAL:" << MG::TIME::getGroundTimeNow() - interval << __FILE__ << __LINE__;
    //    interval = MG::TIME::getGroundTimeNow();
201
    renderOverlay();
lm's avatar
lm committed
202 203
}

204
void HSIDisplay::renderOverlay()
205
{
206
    if (!isVisible()) return;
207 208 209
#if (QGC_EVENTLOOP_DEBUG)
    qDebug() << "EVENTLOOP:" << __FILE__ << __LINE__;
#endif
210 211
    // Center location of the HSI gauge items

212
    //float bottomMargin = 3.0f;
213 214

    // Size of the ring instrument
215
    //const float margin = 0.1f;  // 10% margin of total width on each side
pixhawk's avatar
pixhawk committed
216
    float baseRadius = (vheight - topMargin - bottomMargin) / 2.0f - bottomMargin / 2.0f;
217

218 219 220 221 222 223 224 225
    // Draw instruments
    // TESTING THIS SHOULD BE MOVED INTO A QGRAPHICSVIEW
    // 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;

226
    QPainter painter(viewport());
227 228
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
229

230 231
    // Draw base instrument
    // ----------------------
lm's avatar
lm committed
232
    painter.setBrush(Qt::NoBrush);
233
    const QColor ringColor = QColor(200, 250, 200);
lm's avatar
lm committed
234 235 236 237
    QPen pen;
    pen.setColor(ringColor);
    pen.setWidth(refLineWidthToPen(0.1f));
    painter.setPen(pen);
lm's avatar
lm committed
238
    const int ringCount = 2;
239 240
    for (int i = 0; i < ringCount; i++)
    {
241
        float radius = (vwidth - (topMargin + bottomMargin)*0.3f) / (1.35f * i+1) / 2.0f - bottomMargin / 2.0f;
242
        drawCircle(xCenterPos, yCenterPos, radius, 0.1f, ringColor, &painter);
243
        paintText(tr("%1 m").arg(refToMetric(radius), 5, 'f', 1, ' '), QGC::colorCyan, 1.6f, vwidth/2-4, vheight/2+radius+2.2, &painter);
lm's avatar
lm committed
244 245
    }

246 247 248
    // Draw orientation labels
    // Translate and rotate coordinate frame
    painter.translate((xCenterPos)*scalingFactor, (yCenterPos)*scalingFactor);
249 250 251
    const float yawDeg = ((yaw/M_PI)*180.0f);
    int yawRotate = static_cast<int>(yawDeg) % 360;
    painter.rotate(-yawRotate);
252 253
    paintText(tr("N"), ringColor, 3.5f, - 1.0f, - baseRadius - 5.5f, &painter);
    paintText(tr("S"), ringColor, 3.5f, - 1.0f, + baseRadius + 1.5f, &painter);
254
    paintText(tr("E"), ringColor, 3.5f, + baseRadius + 3.0f, - 1.25f, &painter);
255
    paintText(tr("W"), ringColor, 3.5f, - baseRadius - 5.5f, - 1.75f, &painter);
256
    painter.rotate(+yawRotate);
257 258
    painter.translate(-(xCenterPos)*scalingFactor, -(yCenterPos)*scalingFactor);

259
    // Draw trail
260 261 262 263 264 265
    //    QPointF m(bodyXSetCoordinate, bodyYSetCoordinate);
    //    // Transform from body to world coordinates
    //    m = metricWorldToBody(m);
    //    // Scale from metric body to screen reference units
    //    QPointF s = metricBodyToRef(m);
    //    drawLine(s.x(), s.y(), xCenterPos, yCenterPos, 1.5f, uas->getColor(), &painter);
266 267


lm's avatar
lm committed
268
    // Draw center indicator
269 270 271 272 273
    //    QPolygonF p(3);
    //    p.replace(0, QPointF(xCenterPos, yCenterPos-4.0f));
    //    p.replace(1, QPointF(xCenterPos-4.0f, yCenterPos+3.5f));
    //    p.replace(2, QPointF(xCenterPos+4.0f, yCenterPos+3.5f));
    //    drawPolygon(p, &painter);
274

275 276
    if (uas)
    {
277 278 279
        // Translate to center
        painter.translate((xCenterPos)*scalingFactor, (yCenterPos)*scalingFactor);
        QColor uasColor = uas->getColor();
280
        MAV2DIcon::drawAirframePolygon(uas->getAirframe(), painter, static_cast<int>((vwidth/4.0f)*scalingFactor*1.1f), uasColor, 0.0f);
lm's avatar
lm committed
281
        //MAV2DIcon::drawAirframePolygon(uas->getAirframe(), painter, static_cast<int>((vwidth/4.0f)*scalingFactor*1.1f), uasColor, 0.0f);
282 283 284
        // Translate back
        painter.translate(-(xCenterPos)*scalingFactor, -(yCenterPos)*scalingFactor);
    }
285 286

    // ----------------------
287

288 289 290
    // Draw satellites
    drawGPS(painter);

291 292 293
    // Draw state indicator

    // Draw position
294
    QColor positionColor(20, 20, 200);
295
    drawPositionDirection(xCenterPos, yCenterPos, baseRadius, positionColor, &painter);
296 297 298

    // Draw attitude
    QColor attitudeColor(200, 20, 20);
299
    drawAttitudeDirection(xCenterPos, yCenterPos, baseRadius, attitudeColor, &painter);
300 301


302
    // Draw position setpoints in body coordinates
lm's avatar
lm committed
303

304 305 306 307 308 309
    float xSpDiff = uiXSetCoordinate - bodyXSetCoordinate;
    float ySpDiff = uiYSetCoordinate - bodyYSetCoordinate;
    float zSpDiff = uiZSetCoordinate - bodyZSetCoordinate;

    float setPointDist = sqrt(xSpDiff*xSpDiff + ySpDiff*ySpDiff + zSpDiff*zSpDiff);

310 311 312 313
    float angleDiff = uiYawSet - bodyYawSet;

    float normAngleDiff = fabs(atan2(sin(angleDiff), cos(angleDiff)));

314 315
    //if (((userSetPointSet) || (normAngleDiff > 0.05f) || dragStarted) && !(setPointDist < 0.08f && mavInitialized))

316

317 318 319 320 321
    // Labels on outer part and bottom

    // Draw waypoints
    drawWaypoints(painter);

322
    // Draw status flags
323 324 325 326
    drawStatusFlag(2,  1, tr("ATT"), attControlEnabled, attControlKnown, painter);
    drawStatusFlag(22, 1, tr("PXY"), xyControlEnabled,  xyControlKnown,  painter);
    drawStatusFlag(44, 1, tr("PZ"),  zControlEnabled,   zControlKnown,   painter);
    drawStatusFlag(66, 1, tr("YAW"), yawControlEnabled, yawControlKnown, painter);
327

328
    // Draw position lock indicators
329 330 331 332
    drawPositionLock(2,  5, tr("POS"), positionFix, positionFixKnown, painter);
    drawPositionLock(22, 5, tr("VIS"), visionFix,   visionFixKnown,   painter);
    drawPositionLock(44, 5, tr("GPS"), gpsFix,      gpsFixKnown,      painter);
    drawPositionLock(66, 5, tr("IRU"), iruFix,      iruFixKnown,      painter);
333 334 335

    // Draw speed to top left
    paintText(tr("SPEED"), QGC::colorCyan, 2.2f, 2, 11, &painter);
336
    paintText(tr("%1 m/s").arg(speed, 5, 'f', 2, '0'), Qt::white, 2.2f, 12, 11, &painter);
337 338 339

    // Draw crosstrack error to top right
    float crossTrackError = 0;
340 341
    paintText(tr("XTRACK"), QGC::colorCyan, 2.2f, 54, 11, &painter);
    paintText(tr("%1 m").arg(crossTrackError, 5, 'f', 2, '0'), Qt::white, 2.2f, 67, 11, &painter);
342 343

    // Draw position to bottom left
344 345
    if (localAvailable > 0)
    {
346 347
        // Position
        QString str;
348
        float offset = (globalAvailable > 0) ? -3.0f : 0.0f;
349
        str.sprintf("%05.2f %05.2f %05.2f m", x, y, z);
350 351
        paintText(tr("POS"), QGC::colorCyan, 2.6f, 2, vheight - offset - 2.0f, &painter);
        paintText(str, Qt::white, 2.6f, 10, vheight - offset - 2.0f, &painter);
352 353
    }

354 355
    if (globalAvailable > 0)
    {
356 357
        // Position
        QString str;
358
        str.sprintf("lat: %05.2f lon: %06.2f alt: %06.2f", lat, lon, alt);
359 360
        paintText(tr("GPS"), QGC::colorCyan, 2.6f, 2, vheight- 2.0f, &painter);
        paintText(str, Qt::white, 2.6f, 10, vheight - 2.0f, &painter);
361 362
    }

363 364 365
    // Draw Safety
    double x1, y1, z1, x2, y2, z2;
    UASManager::instance()->getLocalNEDSafetyLimits(&x1, &y1, &z1, &x2, &y2, &z2);
366
    //    drawSafetyArea(QPointF(x1, y1), QPointF(x2, y2), QGC::colorYellow, painter);
367 368

    // Draw status message
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
    paintText(statusMessage, QGC::colorOrange, 2.8f, 8, 15, &painter);

    // Draw setpoint over waypoints
    if (positionSetPointKnown || setPointKnown)
    {
        // Draw setpoint
        drawSetpointXYZYaw(bodyXSetCoordinate, bodyYSetCoordinate, bodyZSetCoordinate, bodyYawSet, QGC::colorYellow, painter);
        // Draw travel direction line
        QPointF m(bodyXSetCoordinate, bodyYSetCoordinate);
        // Transform from body to world coordinates
        m = metricWorldToBody(m);
        // Scale from metric body to screen reference units
        QPointF s = metricBodyToRef(m);
        drawLine(s.x(), s.y(), xCenterPos, yCenterPos, 1.5f, QGC::colorYellow, &painter);
    }

    if ((userSetPointSet || dragStarted) && ((normAngleDiff > 0.05f) || !(setPointDist < 0.08f && mavInitialized)))
    {
        QColor spColor(150, 250, 150);
        drawSetpointXYZYaw(uiXSetCoordinate, uiYSetCoordinate, uiZSetCoordinate, uiYawSet, spColor, painter);
    }
390
}
391

392
void HSIDisplay::drawStatusFlag(float x, float y, QString label, bool status, bool known, QPainter& painter)
393
{
394
    paintText(label, QGC::colorCyan, 2.6f, x, y+0.8f, &painter);
395
    QColor statusColor(250, 250, 250);
396
    if(status) {
pixhawk's avatar
pixhawk committed
397
        painter.setBrush(QGC::colorGreen);
398
    } else {
399
        painter.setBrush(QGC::colorDarkYellow);
400 401
    }
    painter.setPen(Qt::NoPen);
402 403 404 405 406

    float indicatorWidth = refToScreenX(7.0f);
    float indicatorHeight = refToScreenY(4.0f);

    painter.drawRect(QRect(refToScreenX(x+7.3f), refToScreenY(y+0.05), indicatorWidth, indicatorHeight));
407
    paintText((status) ? tr("ON") : tr("OFF"), statusColor, 2.6f, x+7.9f, y+0.8f, &painter);
408
    // Cross out instrument if state unknown
409 410
    if (!known)
    {
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
        QPen pen(Qt::yellow);
        pen.setWidth(2);
        painter.setPen(pen);
        // Top left to bottom right
        QPointF p1, p2, p3, p4;
        p1.setX(refToScreenX(x));
        p1.setY(refToScreenX(y));
        p2.setX(p1.x()+indicatorWidth+refToScreenX(7.3f));
        p2.setY(p1.y()+indicatorHeight);
        painter.drawLine(p1, p2);
        // Bottom left to top right
        p3.setX(refToScreenX(x));
        p3.setY(refToScreenX(y)+indicatorHeight);
        p4.setX(p1.x()+indicatorWidth+refToScreenX(7.3f));
        p4.setY(p1.y());
        painter.drawLine(p3, p4);
    }
428 429
}

430
void HSIDisplay::drawPositionLock(float x, float y, QString label, int status, bool known, QPainter& painter)
431
{
432 433 434 435 436 437 438 439 440 441 442 443
    paintText(label, QGC::colorCyan, 2.6f, x, y+0.8f, &painter);
    QColor negStatusColor(200, 20, 20);
    QColor intermediateStatusColor (Qt::yellow);
    QColor posStatusColor(20, 200, 20);
    QColor statusColor(250, 250, 250);
    if (status == 3) {
        painter.setBrush(posStatusColor);
    } else if (status == 2) {
        painter.setBrush(intermediateStatusColor.dark(150));
    } else {
        painter.setBrush(negStatusColor);
    }
444

445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
    // Lock text
    QString lockText;
    switch (status) {
    case 1:
        lockText = tr("LOC");
        break;
    case 2:
        lockText = tr("2D");
        break;
    case 3:
        lockText = tr("3D");
        break;
    default:
        lockText = tr("NO");
        break;
    }
461

462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
    float indicatorWidth = refToScreenX(7.0f);
    float indicatorHeight = refToScreenY(4.0f);

    painter.setPen(Qt::NoPen);
    painter.drawRect(QRect(refToScreenX(x+7.3f), refToScreenY(y+0.05), refToScreenX(7.0f), refToScreenY(4.0f)));
    paintText(lockText, statusColor, 2.6f, x+7.9f, y+0.8f, &painter);
    // Cross out instrument if state unknown
    if (!known) {
        QPen pen(Qt::yellow);
        pen.setWidth(2);
        painter.setPen(pen);
        // Top left to bottom right
        QPointF p1, p2, p3, p4;
        p1.setX(refToScreenX(x));
        p1.setY(refToScreenX(y));
        p2.setX(p1.x()+indicatorWidth+refToScreenX(7.3f));
        p2.setY(p1.y()+indicatorHeight);
        painter.drawLine(p1, p2);
        // Bottom left to top right
        p3.setX(refToScreenX(x));
        p3.setY(refToScreenX(y)+indicatorHeight);
        p4.setX(p1.x()+indicatorWidth+refToScreenX(7.3f));
        p4.setY(p1.y());
        painter.drawLine(p3, p4);
    }
487 488
}

lm's avatar
lm committed
489 490
void HSIDisplay::updatePositionLock(UASInterface* uas, bool lock)
{
491
    Q_UNUSED(uas);
492
    bool changed = positionLock != lock;
lm's avatar
lm committed
493
    positionLock = lock;
494 495 496 497
    if (changed)
    {
        update();
    }
lm's avatar
lm committed
498 499
}

pixhawk's avatar
pixhawk committed
500
void HSIDisplay::updateAttitudeControllerEnabled(bool enabled)
lm's avatar
lm committed
501
{
502
    bool changed = attControlEnabled != enabled;
lm's avatar
lm committed
503
    attControlEnabled = enabled;
504
    attControlKnown = true;
505 506 507 508
    if (changed)
    {
        update();
    }
lm's avatar
lm committed
509 510
}

pixhawk's avatar
pixhawk committed
511
void HSIDisplay::updatePositionXYControllerEnabled(bool enabled)
lm's avatar
lm committed
512
{
513
    bool changed = xyControlEnabled != enabled;
lm's avatar
lm committed
514
    xyControlEnabled = enabled;
515
    xyControlKnown = true;
516 517 518 519
    if (changed)
    {
        update();
    }
lm's avatar
lm committed
520 521
}

pixhawk's avatar
pixhawk committed
522
void HSIDisplay::updatePositionZControllerEnabled(bool enabled)
lm's avatar
lm committed
523
{
524
    bool changed = zControlEnabled != enabled;
lm's avatar
lm committed
525
    zControlEnabled = enabled;
526
    zControlKnown = true;
527 528 529 530
    if (changed)
    {
        update();
    }
lm's avatar
lm committed
531 532
}

LM's avatar
LM committed
533 534
void HSIDisplay::updateObjectPosition(unsigned int time, int id, int type, const QString& name, int quality, float bearing, float distance)
{
535 536 537 538 539
    Q_UNUSED(quality);
    Q_UNUSED(name);
    Q_UNUSED(type);
    Q_UNUSED(id);
    Q_UNUSED(time);
LM's avatar
LM committed
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
    // FIXME add multi-object support
    QPainter painter(this);
    QColor color(Qt::yellow);
    float radius = vwidth / 20.0f;
    QPen pen(color);
    pen.setWidthF(refLineWidthToPen(0.4f));
    pen.setColor(color);
    painter.setPen(pen);
    painter.setBrush(Qt::NoBrush);
    QPointF in(cos(bearing)-sin(bearing)*distance, sin(bearing)+cos(bearing)*distance);
    // Scale from metric to screen reference coordinates
    QPointF p = metricBodyToRef(in);
    drawCircle(p.x(), p.y(), radius, 0.4f, color, &painter);
}

pixhawk's avatar
pixhawk committed
555 556 557 558
QPointF HSIDisplay::metricWorldToBody(QPointF world)
{
    // First translate to body-centered coordinates
    // Rotate around -yaw
559
    float angle = -yaw - M_PI;
560
    QPointF result(cos(angle) * (x - world.x()) - sin(angle) * (y - world.y()), sin(angle) * (x - world.x()) + cos(angle) * (y - world.y()));
pixhawk's avatar
pixhawk committed
561 562 563 564 565 566 567
    return result;
}

QPointF HSIDisplay::metricBodyToWorld(QPointF body)
{
    // First rotate into world coordinates
    // then translate to world position
568
    QPointF result((cos(-yaw) * body.x()) + (sin(-yaw) * body.y()) + x, (-sin(-yaw) * body.x()) + (cos(-yaw) * body.y()) + y);
pixhawk's avatar
pixhawk committed
569
    return result;
570
}
571

572 573
QPointF HSIDisplay::screenToMetricBody(QPointF ref)
{
574
    return QPointF(-((screenToRefY(ref.y()) - yCenterPos)/ vwidth) * metricWidth, ((screenToRefX(ref.x()) - xCenterPos) / vwidth) * metricWidth);
575 576 577 578
}

QPointF HSIDisplay::refToMetricBody(QPointF &ref)
{
lm's avatar
lm committed
579
    return QPointF(-((ref.y() - yCenterPos)/ vwidth) * metricWidth - x, ((ref.x() - xCenterPos) / vwidth) * metricWidth - y);
580 581 582 583 584
}

/**
 * @see refToScreenX()
 */
585
QPointF HSIDisplay::metricBodyToRef(QPointF &metric)
586 587 588 589
{
    return QPointF(((metric.y())/ metricWidth) * vwidth + xCenterPos, ((-metric.x()) / metricWidth) * vwidth + yCenterPos);
}

590 591 592 593 594 595 596 597 598 599
double HSIDisplay::metricToRef(double metric)
{
    return (metric / metricWidth) * vwidth;
}

double HSIDisplay::refToMetric(double ref)
{
    return (ref/vwidth) * metricWidth;
}

600 601 602 603 604 605 606 607
QPointF HSIDisplay::metricBodyToScreen(QPointF metric)
{
    QPointF ref = metricBodyToRef(metric);
    ref.setX(refToScreenX(ref.x()));
    ref.setY(refToScreenY(ref.y()));
    return ref;
}

608 609
void HSIDisplay::mouseDoubleClickEvent(QMouseEvent * event)
{
610 611
    if (event->type() == QMouseEvent::MouseButtonDblClick)
    {
612
        QPointF p = screenToMetricBody(event->posF());
pixhawk's avatar
pixhawk committed
613 614 615 616 617
        if (!directSending)
        {
            setBodySetpointCoordinateXY(p.x(), p.y());
            if (!userZSetPointSet) setBodySetpointCoordinateZ(0.0);
        }
618
        //        qDebug() << "Double click at x: " << screenToRefX(event->x()) - xCenterPos << "y:" << screenToRefY(event->y()) - yCenterPos;
619 620 621 622 623
    }
}

void HSIDisplay::mouseReleaseEvent(QMouseEvent * event)
{
LM's avatar
LM committed
624 625
    // FIXME hardcode yaw to current value
    setBodySetpointCoordinateYaw(0);
626
    if (mouseHasMoved)
627
    {
628 629 630 631
        if (event->type() == QMouseEvent::MouseButtonRelease && event->button() == Qt::RightButton)
        {
            if (dragStarted)
            {
LM's avatar
LM committed
632
                if (!directSending) setBodySetpointCoordinateYaw(uiYawSet);
633 634 635 636 637 638 639
                dragStarted = false;
            }
        }
        if (event->type() == QMouseEvent::MouseButtonRelease && event->button() == Qt::LeftButton)
        {
            if (leftDragStarted)
            {
LM's avatar
LM committed
640
                if (!directSending) setBodySetpointCoordinateZ(uiZSetCoordinate);
641
                leftDragStarted = false;
642 643
            }
        }
644
    }
645
    mouseHasMoved = false;
646 647 648 649 650 651 652 653 654
}

void HSIDisplay::mousePressEvent(QMouseEvent * event)
{
    if (event->type() == QMouseEvent::MouseButtonPress)
    {
        if (event->button() == Qt::RightButton)
        {
            startX = event->x();
655 656
            // Start tracking mouse move
            dragStarted = true;
657 658 659
        }
        else if (event->button() == Qt::LeftButton)
        {
660 661
            startY = event->y();
            leftDragStarted = true;
662
        }
pixhawk's avatar
pixhawk committed
663
    }
664
    mouseHasMoved = false;
665
}
666

667 668 669 670
void HSIDisplay::mouseMoveEvent(QMouseEvent * event)
{
    if (event->type() == QMouseEvent::MouseMove)
    {
671
        if (dragStarted) uiYawSet -= 0.06f*(startX - event->x()) / this->frameSize().width();
672 673 674

        if (leftDragStarted)
        {
675 676
            //            uiZSetCoordinate -= 0.06f*(startY - event->y()) / this->frameSize().height();
            //            setBodySetpointCoordinateZ(uiZSetCoordinate);
677
        }
678 679

        if (leftDragStarted || dragStarted) mouseHasMoved = true;
pixhawk's avatar
pixhawk committed
680
    }
681 682
}

pixhawk's avatar
pixhawk committed
683 684
void HSIDisplay::keyPressEvent(QKeyEvent* event)
{
685 686
    QPointF bodySP = metricWorldToBody(QPointF(uiXSetCoordinate, uiYSetCoordinate));

687
    if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) && actionPending)
pixhawk's avatar
pixhawk committed
688 689 690 691 692 693
    {
        actionPending = false;
        statusMessage = "SETPOINT SENT";
        statusClearTimer.start();
        sendBodySetPointCoordinates();
    }
LM's avatar
LM committed
694
    else
695
    {
LM's avatar
LM committed
696 697 698 699 700 701 702
        // FIXME hardcode yaw to current value
        setBodySetpointCoordinateYaw(0);


        // Reset setpoints to current position / orientation
        // if not initialized
        if (!userYawSetPointSet)
703
        {
LM's avatar
LM committed
704
            setBodySetpointCoordinateYaw(0);
705
        }
LM's avatar
LM committed
706 707

        if (!userZSetPointSet)
708
        {
LM's avatar
LM committed
709
            setBodySetpointCoordinateZ(0);
710 711
        }

LM's avatar
LM committed
712
        if (!userXYSetPointSet)
713
        {
LM's avatar
LM committed
714
            setBodySetpointCoordinateXY(0, 0);
715
        }
LM's avatar
LM committed
716 717

        if ((event->key() ==  Qt::Key_W))
718
        {
LM's avatar
LM committed
719
            setBodySetpointCoordinateXY(qBound(-1.5, bodySP.x()+0.2, +1.5), bodySP.y());
720 721
        }

LM's avatar
LM committed
722
        if ((event->key() ==  Qt::Key_S))
723
        {
LM's avatar
LM committed
724
            setBodySetpointCoordinateXY(qBound(-1.5, bodySP.x()-0.2, +1.5), bodySP.y());
725
        }
LM's avatar
LM committed
726 727

        if ((event->key() ==  Qt::Key_A))
728 729 730 731
        {
            setBodySetpointCoordinateXY(bodySP.x(), qBound(-1.5, bodySP.y()-0.2, +1.5));
        }

LM's avatar
LM committed
732
        if ((event->key() ==  Qt::Key_D))
733 734 735 736
        {
            setBodySetpointCoordinateXY(bodySP.x(), qBound(-1.5, bodySP.y()+0.2, +1.5));
        }

LM's avatar
LM committed
737
        if ((event->key() ==  Qt::Key_Up))
738
        {
pixhawk's avatar
pixhawk committed
739
            setBodySetpointCoordinateZ(-0.2);
740 741
        }

LM's avatar
LM committed
742
        if ((event->key() ==  Qt::Key_Down))
743
        {
pixhawk's avatar
pixhawk committed
744
            setBodySetpointCoordinateZ(+0.2);
745 746
        }

LM's avatar
LM committed
747
        if ((event->key() ==  Qt::Key_Left))
748
        {
LM's avatar
LM committed
749
            setBodySetpointCoordinateYaw(-0.2);
750 751
        }

LM's avatar
LM committed
752
        if ((event->key() ==  Qt::Key_Right))
753
        {
LM's avatar
LM committed
754
            setBodySetpointCoordinateYaw(0.2);
755
        }
PIXHAWK Team's avatar
PIXHAWK Team committed
756
    }
757 758


LM's avatar
LM committed
759 760 761
    // Overwrite any existing non-zero body setpoints
    // for escape
    if ((event->key() == Qt::Key_Escape) || (event->key() == Qt::Key_R))
PIXHAWK Team's avatar
PIXHAWK Team committed
762
    {
LM's avatar
LM committed
763
        setBodySetpointCoordinateXY(0, 0);
764 765 766
        setBodySetpointCoordinateZ(0);
        setBodySetpointCoordinateYaw(0);
        statusMessage = "CANCELLED, PRESS <ENTER> TO SEND";
PIXHAWK Team's avatar
PIXHAWK Team committed
767
    }
768 769

    if ((event->key() == Qt::Key_T))
PIXHAWK Team's avatar
PIXHAWK Team committed
770
    {
771 772 773
        directSending = !directSending;
        statusMessage = (directSending) ? "DIRECT SEND ON" : "DIRECT SEND OFF";
        statusClearTimer.start();
PIXHAWK Team's avatar
PIXHAWK Team committed
774
    }
775 776

    if (actionPending && (directSending || (event->key() == Qt::Key_Escape)))
PIXHAWK Team's avatar
PIXHAWK Team committed
777
    {
778 779 780 781
        actionPending = false;
        statusMessage = "SETPOINT SENT";
        statusClearTimer.start();
        sendBodySetPointCoordinates();
PIXHAWK Team's avatar
PIXHAWK Team committed
782
    }
783 784

    HDDisplay::keyPressEvent(event);
pixhawk's avatar
pixhawk committed
785 786
}

787 788 789 790 791
void HSIDisplay::contextMenuEvent (QContextMenuEvent* event)
{
    event->ignore();
}

792 793
void HSIDisplay::setMetricWidth(double width)
{
794
    if (width != metricWidth) {
795 796 797 798 799
        metricWidth = width;
        emit metricWidthChanged(metricWidth);
    }
}

800 801 802 803 804 805
/**
 *
 * @param uas the UAS/MAV to monitor/display with the HUD
 */
void HSIDisplay::setActiveUAS(UASInterface* uas)
{
806 807 808 809 810 811
    if (this->uas != NULL) {
        disconnect(this->uas, SIGNAL(gpsSatelliteStatusChanged(int,int,float,float,float,bool)), this, SLOT(updateSatellite(int,int,float,float,float,bool)));
        disconnect(this->uas, SIGNAL(localPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateLocalPosition(UASInterface*,double,double,double,quint64)));
        disconnect(this->uas, SIGNAL(globalPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateGlobalPosition(UASInterface*,double,double,double,quint64)));
        disconnect(this->uas, SIGNAL(attitudeThrustSetPointChanged(UASInterface*,double,double,double,double,quint64)), this, SLOT(updateAttitudeSetpoints(UASInterface*,double,double,double,double,quint64)));
        disconnect(this->uas, SIGNAL(positionSetPointsChanged(int,float,float,float,float,quint64)), this, SLOT(updatePositionSetpoints(int,float,float,float,float,quint64)));
812
        disconnect(uas, SIGNAL(userPositionSetPointsChanged(int,float,float,float,float)), this, SLOT(updateUserPositionSetpoints(int,float,float,float,float)));
813 814 815 816 817 818 819 820 821 822 823 824
        disconnect(this->uas, SIGNAL(speedChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateSpeed(UASInterface*,double,double,double,quint64)));
        disconnect(this->uas, SIGNAL(attitudeChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateAttitude(UASInterface*,double,double,double,quint64)));

        disconnect(this->uas, SIGNAL(attitudeControlEnabled(bool)), this, SLOT(updateAttitudeControllerEnabled(bool)));
        disconnect(this->uas, SIGNAL(positionXYControlEnabled(bool)), this, SLOT(updatePositionXYControllerEnabled(bool)));
        disconnect(this->uas, SIGNAL(positionZControlEnabled(bool)), this, SLOT(updatePositionZControllerEnabled(bool)));
        disconnect(this->uas, SIGNAL(positionYawControlEnabled(bool)), this, SLOT(updatePositionYawControllerEnabled(bool)));

        disconnect(this->uas, SIGNAL(localizationChanged(UASInterface*,int)), this, SLOT(updateLocalization(UASInterface*,int)));
        disconnect(this->uas, SIGNAL(visionLocalizationChanged(UASInterface*,int)), this, SLOT(updateVisionLocalization(UASInterface*,int)));
        disconnect(this->uas, SIGNAL(gpsLocalizationChanged(UASInterface*,int)), this, SLOT(updateGpsLocalization(UASInterface*,int)));
        disconnect(this->uas, SIGNAL(irUltraSoundLocalizationChanged(UASInterface*,int)), this, SLOT(updateInfraredUltrasoundLocalization(UASInterface*,int)));
LM's avatar
LM committed
825
        disconnect(this->uas, SIGNAL(objectDetected(uint,int,int,QString,int,float,float)), this, SLOT(updateObjectPosition(uint,int,int,QString,int,float,float)));
826
    }
827

828 829 830 831 832
    connect(uas, SIGNAL(gpsSatelliteStatusChanged(int,int,float,float,float,bool)), this, SLOT(updateSatellite(int,int,float,float,float,bool)));
    connect(uas, SIGNAL(localPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateLocalPosition(UASInterface*,double,double,double,quint64)));
    connect(uas, SIGNAL(globalPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateGlobalPosition(UASInterface*,double,double,double,quint64)));
    connect(uas, SIGNAL(attitudeThrustSetPointChanged(UASInterface*,double,double,double,double,quint64)), this, SLOT(updateAttitudeSetpoints(UASInterface*,double,double,double,double,quint64)));
    connect(uas, SIGNAL(positionSetPointsChanged(int,float,float,float,float,quint64)), this, SLOT(updatePositionSetpoints(int,float,float,float,float,quint64)));
833
    connect(uas, SIGNAL(userPositionSetPointsChanged(int,float,float,float,float)), this, SLOT(updateUserPositionSetpoints(int,float,float,float,float)));
834 835
    connect(uas, SIGNAL(speedChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateSpeed(UASInterface*,double,double,double,quint64)));
    connect(uas, SIGNAL(attitudeChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateAttitude(UASInterface*,double,double,double,quint64)));
836

837 838 839 840
    connect(uas, SIGNAL(attitudeControlEnabled(bool)), this, SLOT(updateAttitudeControllerEnabled(bool)));
    connect(uas, SIGNAL(positionXYControlEnabled(bool)), this, SLOT(updatePositionXYControllerEnabled(bool)));
    connect(uas, SIGNAL(positionZControlEnabled(bool)), this, SLOT(updatePositionZControllerEnabled(bool)));
    connect(uas, SIGNAL(positionYawControlEnabled(bool)), this, SLOT(updatePositionYawControllerEnabled(bool)));
841

842 843 844 845
    connect(uas, SIGNAL(localizationChanged(UASInterface*,int)), this, SLOT(updateLocalization(UASInterface*,int)));
    connect(uas, SIGNAL(visionLocalizationChanged(UASInterface*,int)), this, SLOT(updateVisionLocalization(UASInterface*,int)));
    connect(uas, SIGNAL(gpsLocalizationChanged(UASInterface*,int)), this, SLOT(updateGpsLocalization(UASInterface*,int)));
    connect(uas, SIGNAL(irUltraSoundLocalizationChanged(UASInterface*,int)), this, SLOT(updateInfraredUltrasoundLocalization(UASInterface*,int)));
LM's avatar
LM committed
846
    connect(uas, SIGNAL(objectDetected(uint,int,int,QString,int,float,float)), this, SLOT(updateObjectPosition(uint,int,int,QString,int,float,float)));
847

848
    this->uas = uas;
849

850
    resetMAVState();
851 852
}

853 854 855 856 857 858 859
void HSIDisplay::updateSpeed(UASInterface* uas, double vx, double vy, double vz, quint64 time)
{
    Q_UNUSED(uas);
    Q_UNUSED(time);
    this->vx = vx;
    this->vy = vy;
    this->vz = vz;
860
    this->speed = sqrt(pow(vx, 2.0) + pow(vy, 2.0) + pow(vz, 2.0));
861 862 863 864
}

void HSIDisplay::setBodySetpointCoordinateXY(double x, double y)
{
865 866 867 868 869
    if (uas)
    {
        userSetPointSet = true;
        userXYSetPointSet = true;
        // Set coordinates and send them out to MAV
870

871 872 873 874 875 876
        QPointF sp(x, y);
        sp = metricBodyToWorld(sp);
        uiXSetCoordinate = sp.x();
        uiYSetCoordinate = sp.y();

        qDebug() << "Attempting to set new setpoint at x: " << x << "metric y:" << y;
lm's avatar
lm committed
877

pixhawk's avatar
pixhawk committed
878

pixhawk's avatar
pixhawk committed
879 880 881 882
        //sendBodySetPointCoordinates();
        statusMessage = "POSITION SET, PRESS <ENTER> TO SEND";
        actionPending = true;
        statusClearTimer.start();
pixhawk's avatar
pixhawk committed
883
    }
884 885 886 887
}

void HSIDisplay::setBodySetpointCoordinateZ(double z)
{
888 889 890
    if (uas)
    {
        userSetPointSet = true;
LM's avatar
LM committed
891
        userZSetPointSet = true;
892 893 894 895 896 897
        // Set coordinates and send them out to MAV
        uiZSetCoordinate = z+uas->getLocalZ();
        statusMessage = "Z SET, PRESS <ENTER> TO SEND";
        actionPending = true;
        statusClearTimer.start();
    }
pixhawk's avatar
pixhawk committed
898
    //sendBodySetPointCoordinates();
899 900 901 902
}

void HSIDisplay::setBodySetpointCoordinateYaw(double yaw)
{
903
    if (uas)
904
    {
905 906 907 908 909 910 911 912 913 914 915 916
        if (!userXYSetPointSet && setPointKnown)
        {
            uiXSetCoordinate = bodyXSetCoordinate;
            uiYSetCoordinate = bodyYSetCoordinate;
        }
        else if (!userXYSetPointSet && mavInitialized)
        {
            QPointF coord = metricBodyToWorld(QPointF(0.0, 0.0));
            uiXSetCoordinate = coord.x();
            uiYSetCoordinate = coord.y();
        }
        userSetPointSet = true;
LM's avatar
LM committed
917
        userYawSetPointSet = true;
918 919 920 921 922
        // Set coordinates and send them out to MAV
        uiYawSet = atan2(sin(yaw+uas->getYaw()), cos(yaw+uas->getYaw()));
        statusMessage = "YAW SET, PRESS <ENTER> TO SEND";
        statusClearTimer.start();
        actionPending = true;
923
    }
pixhawk's avatar
pixhawk committed
924
    //sendBodySetPointCoordinates();
925 926 927 928 929
}

void HSIDisplay::sendBodySetPointCoordinates()
{
    // Send the coordinates to the MAV
930
    if (uas)
931
    {
932
        uas->setLocalPositionSetpoint(uiXSetCoordinate, uiYSetCoordinate, uiZSetCoordinate, uiYawSet);
933
    }
934 935
}

936
void HSIDisplay::updateAttitudeSetpoints(UASInterface* uas, double rollDesired, double pitchDesired, double yawDesired, double thrustDesired, quint64 usec)
937
{
938 939 940 941 942 943
    Q_UNUSED(uas);
    Q_UNUSED(usec);
    attXSet = pitchDesired;
    attYSet = rollDesired;
    attYawSet = yawDesired;
    altitudeSet = thrustDesired;
944 945
}

lm's avatar
lm committed
946 947 948 949 950 951 952 953 954
void HSIDisplay::updateAttitude(UASInterface* uas, double roll, double pitch, double yaw, quint64 time)
{
    Q_UNUSED(uas);
    Q_UNUSED(time);
    this->roll = roll;
    this->pitch = pitch;
    this->yaw = yaw;
}

955 956
void HSIDisplay::updateUserPositionSetpoints(int uasid, float xDesired, float yDesired, float zDesired, float yawDesired)
{
957
	Q_UNUSED(uasid);
958 959 960 961 962
    uiXSetCoordinate = xDesired;
    uiYSetCoordinate = yDesired;
    uiZSetCoordinate = zDesired;
    uiYawSet = yawDesired;
    userXYSetPointSet = true;
LM's avatar
LM committed
963 964
    userZSetPointSet = true;
    userYawSetPointSet = true;
965 966 967
    userSetPointSet = true;
}

lm's avatar
lm committed
968
void HSIDisplay::updatePositionSetpoints(int uasid, float xDesired, float yDesired, float zDesired, float yawDesired, quint64 usec)
969
{
970
    Q_UNUSED(uasid);
971
    Q_UNUSED(usec);
972 973 974 975
    bodyXSetCoordinate = xDesired;
    bodyYSetCoordinate = yDesired;
    bodyZSetCoordinate = zDesired;
    bodyYawSet = yawDesired;
pixhawk's avatar
pixhawk committed
976
    mavInitialized = true;
977
    setPointKnown = true;
978
    positionSetPointKnown = true;
pixhawk's avatar
pixhawk committed
979

980 981 982 983
    if (!userSetPointSet && !dragStarted)
    {
        uiXSetCoordinate = bodyXSetCoordinate;
        uiYSetCoordinate = bodyYSetCoordinate;
984
        //        uiZSetCoordinate = bodyZSetCoordinate;
985 986
        uiYawSet= bodyYawSet;
    }
987 988 989 990
}

void HSIDisplay::updateLocalPosition(UASInterface*, double x, double y, double z, quint64 usec)
{
991 992 993 994
    this->x = x;
    this->y = y;
    this->z = z;
    localAvailable = usec;
995 996 997 998
}

void HSIDisplay::updateGlobalPosition(UASInterface*, double lat, double lon, double alt, quint64 usec)
{
999 1000 1001 1002
    this->lat = lat;
    this->lon = lon;
    this->alt = alt;
    globalAvailable = usec;
1003 1004
}

lm's avatar
lm committed
1005
void HSIDisplay::updateSatellite(int uasid, int satid, float elevation, float azimuth, float snr, bool used)
lm's avatar
lm committed
1006 1007 1008
{
    Q_UNUSED(uasid);
    // If slot is empty, insert object
1009
    if (satid != 0) // Satellite PRNs currently range from 1-32, but are never zero
1010
    if (gpsSatellites.contains(satid)) {
lm's avatar
lm committed
1011
        gpsSatellites.value(satid)->update(satid, elevation, azimuth, snr, used);
1012
    } else {
lm's avatar
lm committed
1013
        gpsSatellites.insert(satid, new GPSSatellite(satid, elevation, azimuth, snr, used));
lm's avatar
lm committed
1014 1015 1016
    }
}

1017 1018 1019
void HSIDisplay::updatePositionYawControllerEnabled(bool enabled)
{
    yawControlEnabled = enabled;
1020
    yawControlKnown = true;
1021 1022 1023 1024 1025 1026 1027 1028 1029
}

/**
 * @param fix 0: lost, 1: 2D local position hold, 2: 2D localization, 3: 3D localization
 */
void HSIDisplay::updateLocalization(UASInterface* uas, int fix)
{
    Q_UNUSED(uas);
    positionFix = fix;
1030
    positionFixKnown = true;
1031
    //qDebug() << "LOCALIZATION FIX CALLED";
1032 1033 1034 1035 1036 1037 1038 1039
}
/**
 * @param fix 0: lost, 1: at least one satellite, but no GPS fix, 2: 2D localization, 3: 3D localization
 */
void HSIDisplay::updateGpsLocalization(UASInterface* uas, int fix)
{
    Q_UNUSED(uas);
    gpsFix = fix;
1040
    gpsFixKnown = true;
1041 1042 1043 1044 1045 1046 1047 1048
}
/**
 * @param fix 0: lost, 1: 2D local position hold, 2: 2D localization, 3: 3D localization
 */
void HSIDisplay::updateVisionLocalization(UASInterface* uas, int fix)
{
    Q_UNUSED(uas);
    visionFix = fix;
1049
    visionFixKnown = true;
1050
    //qDebug() << "VISION FIX GOT CALLED";
1051 1052
}

1053 1054 1055 1056 1057 1058 1059
/**
 * @param fix 0: lost, 1-N: Localized with N ultrasound or infrared sensors
 */
void HSIDisplay::updateInfraredUltrasoundLocalization(UASInterface* uas, int fix)
{
    Q_UNUSED(uas);
    iruFix = fix;
1060
    iruFixKnown = true;
1061 1062
}

lm's avatar
lm committed
1063 1064
QColor HSIDisplay::getColorForSNR(float snr)
{
lm's avatar
lm committed
1065
    QColor color;
1066
    if (snr > 0 && snr < 30) {
lm's avatar
lm committed
1067
        color = QColor(250, 10, 10);
1068
    } else if (snr >= 30 && snr < 35) {
lm's avatar
lm committed
1069
        color = QColor(230, 230, 10);
1070
    } else if (snr >= 35 && snr < 40) {
lm's avatar
lm committed
1071
        color = QColor(90, 200, 90);
1072
    } else if (snr >= 40) {
lm's avatar
lm committed
1073
        color = QColor(20, 200, 20);
1074
    } else {
lm's avatar
lm committed
1075 1076 1077
        color = QColor(180, 180, 180);
    }
    return color;
lm's avatar
lm committed
1078 1079
}

1080
void HSIDisplay::drawSetpointXYZYaw(float x, float y, float z, float yaw, const QColor &color, QPainter &painter)
1081
{
1082 1083
    if (uas)
    {
1084
        float radius = vwidth / 18.0f;
1085
        QPen pen(color);
1086
        pen.setWidthF(refLineWidthToPen(1.6f));
1087 1088 1089 1090 1091 1092 1093 1094
        pen.setColor(color);
        painter.setPen(pen);
        painter.setBrush(Qt::NoBrush);
        QPointF in(x, y);
        // Transform from body to world coordinates
        in = metricWorldToBody(in);
        // Scale from metric to screen reference coordinates
        QPointF p = metricBodyToRef(in);
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104

        QPolygonF poly(4);
        // Top point
        poly.replace(0, QPointF(p.x()-radius, p.y()-radius));
        // Right point
        poly.replace(1, QPointF(p.x()+radius, p.y()-radius));
        // Bottom point
        poly.replace(2, QPointF(p.x()+radius, p.y()+radius));
        poly.replace(3, QPointF(p.x()-radius, p.y()+radius));

1105
        // Label
pixhawk's avatar
pixhawk committed
1106
        paintText(QString("z: %1").arg(z, 3, 'f', 1, QChar(' ')), color, 2.1f, p.x()-radius, p.y()-radius-3.5f, &painter);
1107

1108 1109
        drawPolygon(poly, &painter);

1110
        radius *= 0.8f;
1111
        drawLine(p.x(), p.y(), p.x()+sin(-yaw + uas->getYaw() + M_PI) * radius, p.y()+cos(-yaw + uas->getYaw() + M_PI) * radius, refLineWidthToPen(0.6f), color, &painter);
1112 1113

        // Draw center dot
1114 1115 1116
        painter.setBrush(color);
        drawCircle(p.x(), p.y(), radius * 0.1f, 0.1f, color, &painter);
    }
1117 1118
}

1119 1120
void HSIDisplay::drawWaypoints(QPainter& painter)
{
1121 1122
    if (uas)
    {
pixhawk's avatar
pixhawk committed
1123
        const QVector<Waypoint*>& list = uas->getWaypointManager()->getWaypointEditableList();
1124 1125 1126

        QColor color;
        painter.setBrush(Qt::NoBrush);
pixhawk's avatar
pixhawk committed
1127

1128
        QPointF lastWaypoint;
pixhawk's avatar
pixhawk committed
1129

1130
        for (int i = 0; i < list.size(); i++) {
1131
            QPointF in;
1132 1133
            if (list.at(i)->getFrame() == MAV_FRAME_LOCAL_NED)
            {
1134 1135
                // Do not transform
                in = QPointF(list.at(i)->getX(), list.at(i)->getY());
1136
            } else {
1137 1138 1139 1140 1141
                // Transform to local coordinates first
                double x = list.at(i)->getX();
                double y = list.at(i)->getY();
                in = QPointF(x, y);
            }
1142 1143 1144 1145 1146
            // Transform from world to body coordinates
            in = metricWorldToBody(in);
            // Scale from metric to screen reference coordinates
            QPointF p = metricBodyToRef(in);

1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
            // Setup pen
            QPen pen(color);
            painter.setBrush(Qt::NoBrush);

            // DRAW WAYPOINT
            float waypointSize = vwidth / 20.0f * 2.0f;
            QPolygonF poly(4);
            // Top point
            poly.replace(0, QPointF(p.x(), p.y()-waypointSize/2.0f));
            // Right point
            poly.replace(1, QPointF(p.x()+waypointSize/2.0f, p.y()));
            // Bottom point
            poly.replace(2, QPointF(p.x(), p.y() + waypointSize/2.0f));
            poly.replace(3, QPointF(p.x() - waypointSize/2.0f, p.y()));

1162
            // Select color based on if this is the current waypoint
1163
            if (list.at(i)->getCurrent()) {
1164
                color = QGC::colorYellow;//uas->getColor();
1165
                pen.setWidthF(refLineWidthToPen(0.8f));
1166
            } else {
1167
                color = QGC::colorCyan;
1168
                pen.setWidthF(refLineWidthToPen(0.4f));
1169 1170
            }

1171
            pen.setColor(color);
1172
            painter.setPen(pen);
1173
            float radius = (waypointSize/2.0f) * 0.8 * (1/sqrt(2.0f));
1174
            drawLine(p.x(), p.y(), p.x()+sin(list.at(i)->getYaw()/180.0*M_PI-yaw) * radius, p.y()-cos(list.at(i)->getYaw()/180.0*M_PI-yaw) * radius, refLineWidthToPen(0.4f), color, &painter);
1175
            drawPolygon(poly, &painter);
1176 1177
            float acceptRadius = list.at(i)->getAcceptanceRadius();
            drawCircle(p.x(), p.y(), metricToRef(acceptRadius), 1.0, Qt::green, &painter);
1178

1179
            // DRAW CONNECTING LINE
1180
            // Draw line from last waypoint to this one
1181 1182
            if (!lastWaypoint.isNull())
            {
1183 1184
                pen.setWidthF(refLineWidthToPen(0.4f));
                painter.setPen(pen);
1185
                color = QGC::colorCyan;
1186 1187 1188
                drawLine(lastWaypoint.x(), lastWaypoint.y(), p.x(), p.y(), refLineWidthToPen(0.4f), color, &painter);
            }
            lastWaypoint = p;
pixhawk's avatar
pixhawk committed
1189 1190
        }
    }
1191 1192
}

1193 1194 1195 1196 1197
void HSIDisplay::drawSafetyArea(const QPointF &topLeft, const QPointF &bottomRight, const QColor &color, QPainter &painter)
{
    QPen pen(color);
    pen.setWidthF(refLineWidthToPen(0.1f));
    pen.setColor(color);
1198
    pen.setBrush(Qt::NoBrush);
1199
    painter.setPen(pen);
1200
    painter.drawRect(QRectF(metricBodyToScreen(metricWorldToBody(topLeft)), metricBodyToScreen(metricWorldToBody(bottomRight))));
1201
}
lm's avatar
lm committed
1202

1203 1204 1205 1206
void HSIDisplay::drawGPS(QPainter &painter)
{
    float xCenter = xCenterPos;
    float yCenter = xCenterPos;
lm's avatar
lm committed
1207 1208
    // Max satellite circle radius

lm's avatar
lm committed
1209 1210 1211
    const float margin = 0.15f;  // 20% margin of total width on each side
    float radius = (vwidth - vwidth * 2.0f * margin) / 2.0f;
    quint64 currTime = MG::TIME::getGroundTimeNowUsecs();
lm's avatar
lm committed
1212

pixhawk's avatar
pixhawk committed
1213 1214 1215 1216 1217
    // Draw satellite labels
    //    QString label;
    //    label.sprintf("%05.1f", value);
    //    paintText(label, color, 4.5f, xRef-7.5f, yRef-2.0f, painter);

lm's avatar
lm committed
1218
    QMapIterator<int, GPSSatellite*> i(gpsSatellites);
1219
    while (i.hasNext()) {
lm's avatar
lm committed
1220 1221 1222
        i.next();
        GPSSatellite* sat = i.value();

1223 1224
        // Check if update is not older than 10 seconds, else delete satellite
        if (sat->lastUpdate + 10000000 < currTime) {
lm's avatar
lm committed
1225 1226
            // Delete and go to next satellite
            gpsSatellites.remove(i.key());
1227
            if (i.hasNext()) {
lm's avatar
lm committed
1228 1229
                i.next();
                sat = i.value();
1230
            } else {
lm's avatar
lm committed
1231 1232 1233 1234
                continue;
            }
        }

1235
        if (sat) {
lm's avatar
lm committed
1236 1237 1238 1239
            // Draw satellite
            QBrush brush;
            QColor color = getColorForSNR(sat->snr);
            brush.setColor(color);
1240
            if (sat->used) {
lm's avatar
lm committed
1241
                brush.setStyle(Qt::SolidPattern);
1242
            } else {
lm's avatar
lm committed
1243 1244 1245 1246 1247 1248
                brush.setStyle(Qt::NoBrush);
            }
            painter.setPen(Qt::SolidLine);
            painter.setPen(color);
            painter.setBrush(brush);

lm's avatar
lm committed
1249 1250
            float xPos = xCenter + (sin(((sat->azimuth/255.0f)*360.0f)/180.0f * M_PI) * cos(sat->elevation/180.0f * M_PI)) * radius;
            float yPos = yCenter - (cos(((sat->azimuth/255.0f)*360.0f)/180.0f * M_PI) * cos(sat->elevation/180.0f * M_PI)) * radius;
lm's avatar
lm committed
1251

1252
            // Draw circle for satellite, filled for used satellites
lm's avatar
lm committed
1253
            drawCircle(xPos, yPos, vwidth*0.02f, 1.0f, color, &painter);
1254
            // Draw satellite PRN
lm's avatar
lm committed
1255
            paintText(QString::number(sat->id), QColor(255, 255, 255), 2.9f, xPos+1.7f, yPos+2.0f, &painter);
lm's avatar
lm committed
1256 1257
        }
    }
1258 1259
}

1260
void HSIDisplay::drawObjects(QPainter &painter)
1261
{
1262
    Q_UNUSED(painter);
1263 1264
}

1265
void HSIDisplay::drawPositionDirection(float xRef, float yRef, float radius, const QColor& color, QPainter* painter)
1266
{
1267
    if (xyControlKnown && xyControlEnabled) {
1268
        // Draw the needle
1269
        const float maxWidth = radius / 5.0f;
1270
        const float minWidth = maxWidth * 0.3f;
1271

1272
        float angle = atan2(posXSet, -posYSet);
1273
        angle -= (float)M_PI/2.0f;
1274

1275
        QPolygonF p(6);
1276

1277
        //radius *= ((posXSaturation + posYSaturation) - sqrt(pow(posXSet, 2), pow(posYSet, 2))) / (2*posXSaturation);
lm's avatar
lm committed
1278

1279
        radius *= sqrt(pow(posXSet, 2) + pow(posYSet, 2)) / sqrt(posXSaturation + posYSaturation);
lm's avatar
lm committed
1280

1281 1282 1283 1284 1285 1286
        p.replace(0, QPointF(xRef-maxWidth/2.0f, yRef-radius * 0.4f));
        p.replace(1, QPointF(xRef-minWidth/2.0f, yRef-radius * 0.9f));
        p.replace(2, QPointF(xRef+minWidth/2.0f, yRef-radius * 0.9f));
        p.replace(3, QPointF(xRef+maxWidth/2.0f, yRef-radius * 0.4f));
        p.replace(4, QPointF(xRef,               yRef-radius * 0.36f));
        p.replace(5, QPointF(xRef-maxWidth/2.0f, yRef-radius * 0.4f));
1287

1288
        rotatePolygonClockWiseRad(p, angle, QPointF(xRef, yRef));
1289

1290 1291 1292 1293 1294 1295 1296
        QBrush indexBrush;
        indexBrush.setColor(color);
        indexBrush.setStyle(Qt::SolidPattern);
        painter->setPen(Qt::SolidLine);
        painter->setPen(color);
        painter->setBrush(indexBrush);
        drawPolygon(p, painter);
lm's avatar
lm committed
1297

1298 1299
        //qDebug() << "DRAWING POS SETPOINT X:" << posXSet << "Y:" << posYSet << angle;
    }
1300 1301
}

1302
void HSIDisplay::drawAttitudeDirection(float xRef, float yRef, float radius, const QColor& color, QPainter* painter)
1303
{
1304
    if (attControlKnown && attControlEnabled) {
1305 1306 1307
        // Draw the needle
        const float maxWidth = radius / 10.0f;
        const float minWidth = maxWidth * 0.3f;
1308

1309
        float angle = atan2(attYSet, -attXSet);
lm's avatar
lm committed
1310

1311
        radius *= sqrt(attXSet*attXSet + attYSet*attYSet) / sqrt(attXSaturation*attXSaturation + attYSaturation*attYSaturation);
1312

1313
        QPolygonF p(6);
1314

1315 1316 1317 1318 1319 1320
        p.replace(0, QPointF(xRef-maxWidth/2.0f, yRef-radius * 0.4f));
        p.replace(1, QPointF(xRef-minWidth/2.0f, yRef-radius * 0.9f));
        p.replace(2, QPointF(xRef+minWidth/2.0f, yRef-radius * 0.9f));
        p.replace(3, QPointF(xRef+maxWidth/2.0f, yRef-radius * 0.4f));
        p.replace(4, QPointF(xRef,               yRef-radius * 0.36f));
        p.replace(5, QPointF(xRef-maxWidth/2.0f, yRef-radius * 0.4f));
1321

1322
        rotatePolygonClockWiseRad(p, angle, QPointF(xRef, yRef));
1323

1324 1325 1326 1327 1328 1329 1330
        QBrush indexBrush;
        indexBrush.setColor(color);
        indexBrush.setStyle(Qt::SolidPattern);
        painter->setPen(Qt::SolidLine);
        painter->setPen(color);
        painter->setBrush(indexBrush);
        drawPolygon(p, painter);
1331

1332
        // TODO Draw Yaw indicator
lm's avatar
lm committed
1333

1334 1335
        //qDebug() << "DRAWING ATT SETPOINT X:" << attXSet << "Y:" << attYSet << angle;
    }
1336 1337 1338 1339
}

void HSIDisplay::drawAltitudeSetpoint(float xRef, float yRef, float radius, const QColor& color, QPainter* painter)
{
1340
    if (zControlKnown && zControlEnabled) {
1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354
        // Draw the circle
        QPen circlePen(Qt::SolidLine);
        circlePen.setWidth(refLineWidthToPen(0.5f));
        circlePen.setColor(color);
        painter->setBrush(Qt::NoBrush);
        painter->setPen(circlePen);
        drawCircle(xRef, yRef, radius, 200.0f, color, painter);
        //drawCircle(xRef, yRef, radius, 200.0f, 170.0f, 1.0f, color, painter);

        //    // Draw the value
        //    QString label;
        //    label.sprintf("%05.1f", value);
        //    paintText(label, color, 4.5f, xRef-7.5f, yRef-2.0f, painter);
    }
1355
}
1356

1357 1358 1359
void HSIDisplay::wheelEvent(QWheelEvent* event)
{
    double zoomScale = 0.005; // Scaling of zoom value
1360
    if(event->delta() > 0) {
1361 1362
        // Reduce width -> Zoom in
        metricWidth -= event->delta() * zoomScale;
1363
    } else {
1364 1365 1366
        // Increase width -> Zoom out
        metricWidth -= event->delta() * zoomScale;
    }
1367
    metricWidth = qBound(0.5, metricWidth, 9999.0);
1368 1369
    emit metricWidthChanged(metricWidth);
}
pixhawk's avatar
pixhawk committed
1370

1371 1372 1373 1374
void HSIDisplay::showEvent(QShowEvent* event)
{
    // React only to internal (pre-display)
    // events
1375
    Q_UNUSED(event) {
1376 1377 1378 1379 1380 1381 1382 1383
        refreshTimer->start(updateInterval);
    }
}

void HSIDisplay::hideEvent(QHideEvent* event)
{
    // React only to internal (post-display)
    // events
1384
    Q_UNUSED(event) {
1385
        refreshTimer->stop();
1386 1387 1388
    }
}

1389 1390
void HSIDisplay::updateJoystick(double roll, double pitch, double yaw, double thrust, int xHat, int yHat)
{
1391 1392 1393 1394 1395 1396
    Q_UNUSED(roll);
    Q_UNUSED(pitch);
    Q_UNUSED(yaw);
    Q_UNUSED(thrust);
    Q_UNUSED(xHat);
    Q_UNUSED(yHat);
1397 1398 1399 1400
}

void HSIDisplay::pressKey(int key)
{
1401
    Q_UNUSED(key);
1402
}
pixhawk's avatar
pixhawk committed
1403 1404