HSIDisplay.cc 47.2 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
    // FIXME hardcode yaw to current value
625
    //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 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
void HSIDisplay::drawWaypoint(QPainter& painter, const QColor& color, float width, const QVector<Waypoint*>& list, int i, const QPointF& p)
{
    painter.setBrush(Qt::NoBrush);

    // Setup pen for foreground
    QPen pen(color);
    pen.setWidthF(width);

    // 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()));

    float radius = (waypointSize/2.0f) * 0.8 * (1/sqrt(2.0f));
    float acceptRadius = list.at(i)->getAcceptanceRadius();

    // Draw background
    pen.setColor(Qt::black);
1143 1144
    painter.setPen(pen);
    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*3.0f), Qt::black, &painter);
1145
    drawPolygon(poly, &painter);
1146
    drawCircle(p.x(), p.y(), metricToRef(acceptRadius), 3.0, Qt::black, &painter);
1147 1148 1149 1150 1151 1152 1153 1154 1155

    // Draw foreground
    pen.setColor(color);
    painter.setPen(pen);
    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);
    drawPolygon(poly, &painter);
    drawCircle(p.x(), p.y(), metricToRef(acceptRadius), 1.0, Qt::green, &painter);
}

1156 1157
void HSIDisplay::drawWaypoints(QPainter& painter)
{
1158 1159
    if (uas)
    {
pixhawk's avatar
pixhawk committed
1160
        const QVector<Waypoint*>& list = uas->getWaypointManager()->getWaypointEditableList();
1161

1162 1163 1164
        // Do not work on empty lists
        if (list.size() == 0) return;

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

1168 1169
        // XXX Ugly hacks, needs rewrite

1170
        QPointF lastWaypoint;
1171 1172
        QPointF currentWaypoint;
        int currentIndex = 0;
pixhawk's avatar
pixhawk committed
1173

1174 1175
        for (int i = 0; i < list.size(); i++)
        {
1176
            QPointF in;
1177 1178
            if (list.at(i)->getFrame() == MAV_FRAME_LOCAL_NED)
            {
1179 1180
                // Do not transform
                in = QPointF(list.at(i)->getX(), list.at(i)->getY());
1181
            } else {
1182 1183 1184 1185 1186
                // Transform to local coordinates first
                double x = list.at(i)->getX();
                double y = list.at(i)->getY();
                in = QPointF(x, y);
            }
1187 1188 1189 1190 1191 1192
            // Transform from world to body coordinates
            in = metricWorldToBody(in);
            // Scale from metric to screen reference coordinates
            QPointF p = metricBodyToRef(in);

            // Select color based on if this is the current waypoint
1193 1194 1195 1196 1197 1198 1199 1200
            if (list.at(i)->getCurrent())
            {
                currentIndex = i;
                currentWaypoint = p;
            }
            else
            {
                drawWaypoint(painter, QGC::colorCyan, refLineWidthToPen(0.4f), list, i, p);
1201 1202
            }

1203
            // DRAW CONNECTING LINE
1204
            // Draw line from last waypoint to this one
1205 1206
            if (!lastWaypoint.isNull())
            {
1207 1208
                drawLine(lastWaypoint.x(), lastWaypoint.y(), p.x(), p.y(), refLineWidthToPen(0.4f*2.0f), Qt::black, &painter);
                drawLine(lastWaypoint.x(), lastWaypoint.y(), p.x(), p.y(), refLineWidthToPen(0.4f), QGC::colorCyan, &painter);
1209 1210
            }
            lastWaypoint = p;
pixhawk's avatar
pixhawk committed
1211
        }
1212 1213

        drawWaypoint(painter, QGC::colorYellow, refLineWidthToPen(0.8f), list, currentIndex, currentWaypoint);
pixhawk's avatar
pixhawk committed
1214
    }
1215 1216
}

1217 1218 1219 1220 1221
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);
1222
    pen.setBrush(Qt::NoBrush);
1223
    painter.setPen(pen);
1224
    painter.drawRect(QRectF(metricBodyToScreen(metricWorldToBody(topLeft)), metricBodyToScreen(metricWorldToBody(bottomRight))));
1225
}
lm's avatar
lm committed
1226

1227 1228 1229 1230
void HSIDisplay::drawGPS(QPainter &painter)
{
    float xCenter = xCenterPos;
    float yCenter = xCenterPos;
lm's avatar
lm committed
1231 1232
    // Max satellite circle radius

lm's avatar
lm committed
1233 1234 1235
    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
1236

pixhawk's avatar
pixhawk committed
1237 1238 1239 1240 1241
    // 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
1242
    QMapIterator<int, GPSSatellite*> i(gpsSatellites);
1243
    while (i.hasNext()) {
lm's avatar
lm committed
1244 1245 1246
        i.next();
        GPSSatellite* sat = i.value();

1247 1248
        // Check if update is not older than 10 seconds, else delete satellite
        if (sat->lastUpdate + 10000000 < currTime) {
lm's avatar
lm committed
1249 1250
            // Delete and go to next satellite
            gpsSatellites.remove(i.key());
1251
            if (i.hasNext()) {
lm's avatar
lm committed
1252 1253
                i.next();
                sat = i.value();
1254
            } else {
lm's avatar
lm committed
1255 1256 1257 1258
                continue;
            }
        }

1259
        if (sat) {
lm's avatar
lm committed
1260 1261 1262 1263
            // Draw satellite
            QBrush brush;
            QColor color = getColorForSNR(sat->snr);
            brush.setColor(color);
1264
            if (sat->used) {
lm's avatar
lm committed
1265
                brush.setStyle(Qt::SolidPattern);
1266
            } else {
lm's avatar
lm committed
1267 1268 1269 1270 1271 1272
                brush.setStyle(Qt::NoBrush);
            }
            painter.setPen(Qt::SolidLine);
            painter.setPen(color);
            painter.setBrush(brush);

lm's avatar
lm committed
1273 1274
            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
1275

1276
            // Draw circle for satellite, filled for used satellites
lm's avatar
lm committed
1277
            drawCircle(xPos, yPos, vwidth*0.02f, 1.0f, color, &painter);
1278
            // Draw satellite PRN
lm's avatar
lm committed
1279
            paintText(QString::number(sat->id), QColor(255, 255, 255), 2.9f, xPos+1.7f, yPos+2.0f, &painter);
lm's avatar
lm committed
1280 1281
        }
    }
1282 1283
}

1284
void HSIDisplay::drawObjects(QPainter &painter)
1285
{
1286
    Q_UNUSED(painter);
1287 1288
}

1289
void HSIDisplay::drawPositionDirection(float xRef, float yRef, float radius, const QColor& color, QPainter* painter)
1290
{
1291
    if (xyControlKnown && xyControlEnabled) {
1292
        // Draw the needle
1293
        const float maxWidth = radius / 5.0f;
1294
        const float minWidth = maxWidth * 0.3f;
1295

1296
        float angle = atan2(posXSet, -posYSet);
1297
        angle -= (float)M_PI/2.0f;
1298

1299
        QPolygonF p(6);
1300

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

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

1305 1306 1307 1308 1309 1310
        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));
1311

1312
        rotatePolygonClockWiseRad(p, angle, QPointF(xRef, yRef));
1313

1314 1315 1316 1317 1318 1319 1320
        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
1321

1322 1323
        //qDebug() << "DRAWING POS SETPOINT X:" << posXSet << "Y:" << posYSet << angle;
    }
1324 1325
}

1326
void HSIDisplay::drawAttitudeDirection(float xRef, float yRef, float radius, const QColor& color, QPainter* painter)
1327
{
1328
    if (attControlKnown && attControlEnabled) {
1329 1330 1331
        // Draw the needle
        const float maxWidth = radius / 10.0f;
        const float minWidth = maxWidth * 0.3f;
1332

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

1335
        radius *= sqrt(attXSet*attXSet + attYSet*attYSet) / sqrt(attXSaturation*attXSaturation + attYSaturation*attYSaturation);
1336

1337
        QPolygonF p(6);
1338

1339 1340 1341 1342 1343 1344
        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));
1345

1346
        rotatePolygonClockWiseRad(p, angle, QPointF(xRef, yRef));
1347

1348 1349 1350 1351 1352 1353 1354
        QBrush indexBrush;
        indexBrush.setColor(color);
        indexBrush.setStyle(Qt::SolidPattern);
        painter->setPen(Qt::SolidLine);
        painter->setPen(color);
        painter->setBrush(indexBrush);
        drawPolygon(p, painter);
1355

1356
        // TODO Draw Yaw indicator
lm's avatar
lm committed
1357

1358 1359
        //qDebug() << "DRAWING ATT SETPOINT X:" << attXSet << "Y:" << attYSet << angle;
    }
1360 1361 1362 1363
}

void HSIDisplay::drawAltitudeSetpoint(float xRef, float yRef, float radius, const QColor& color, QPainter* painter)
{
1364
    if (zControlKnown && zControlEnabled) {
1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378
        // 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);
    }
1379
}
1380

1381 1382 1383
void HSIDisplay::wheelEvent(QWheelEvent* event)
{
    double zoomScale = 0.005; // Scaling of zoom value
1384
    if(event->delta() > 0) {
1385 1386
        // Reduce width -> Zoom in
        metricWidth -= event->delta() * zoomScale;
1387
    } else {
1388 1389 1390
        // Increase width -> Zoom out
        metricWidth -= event->delta() * zoomScale;
    }
1391
    metricWidth = qBound(0.5, metricWidth, 9999.0);
1392 1393
    emit metricWidthChanged(metricWidth);
}
pixhawk's avatar
pixhawk committed
1394

1395 1396 1397 1398
void HSIDisplay::showEvent(QShowEvent* event)
{
    // React only to internal (pre-display)
    // events
1399
    Q_UNUSED(event) {
1400 1401 1402 1403 1404 1405 1406 1407
        refreshTimer->start(updateInterval);
    }
}

void HSIDisplay::hideEvent(QHideEvent* event)
{
    // React only to internal (post-display)
    // events
1408
    Q_UNUSED(event) {
1409
        refreshTimer->stop();
1410 1411 1412
    }
}

1413 1414
void HSIDisplay::updateJoystick(double roll, double pitch, double yaw, double thrust, int xHat, int yHat)
{
1415 1416 1417 1418 1419 1420
    Q_UNUSED(roll);
    Q_UNUSED(pitch);
    Q_UNUSED(yaw);
    Q_UNUSED(thrust);
    Q_UNUSED(xHat);
    Q_UNUSED(yHat);
1421 1422 1423 1424
}

void HSIDisplay::pressKey(int key)
{
1425
    Q_UNUSED(key);
1426
}
pixhawk's avatar
pixhawk committed
1427 1428