PrimaryFlightDisplay.cc 53.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
#include "PrimaryFlightDisplay.h"
#include "UASManager.h"

//#include "ui_primaryflightdisplay.h"
#include <QDebug>
#include <QRectF>
#include <cmath>
#include <QPen>
#include <QPainter>
#include <QPainterPath>
#include <QResizeEvent>
dongfang's avatar
dongfang committed
12 13
#include <QtCore/qmath.h>
//#include <cmath>
14

15 16
#if 0
// Left in but ifdef'ed out since there is commented out code below that uses it
17
static const float SEPARATE_COMPASS_ASPECTRATIO = 3.0f/4.0f;
18
#endif
19 20 21 22
static const float LINEWIDTH = 0.0036f;
static const float SMALL_TEXT_SIZE = 0.028f;
static const float MEDIUM_TEXT_SIZE = SMALL_TEXT_SIZE*1.2f;
static const float LARGE_TEXT_SIZE = MEDIUM_TEXT_SIZE*1.2f;
23

24
static const bool SHOW_ZERO_ON_SCALES = true;
25 26

// all in units of display height
27 28 29 30
static const float ROLL_SCALE_RADIUS = 0.42f;
static const float ROLL_SCALE_TICKMARKLENGTH = 0.04f;
static const float ROLL_SCALE_MARKERWIDTH = 0.06f;
static const float ROLL_SCALE_MARKERHEIGHT = 0.04f;
31
// scale max. degrees
32
static const int ROLL_SCALE_RANGE = 60;
33 34

// fraction of height to translate for each degree of pitch.
35 36 37 38
static const float PITCHTRANSLATION = 65;
// 5 degrees for each line
static const int PITCH_SCALE_RESOLUTION = 5;
static const float PITCH_SCALE_MAJORWIDTH = 0.1f;
39
static const float PITCH_SCALE_MINORWIDTH = 0.066f;
40 41 42 43

// Beginning from PITCH_SCALE_WIDTHREDUCTION_FROM degrees of +/- pitch, the
// width of the lines is reduced, down to PITCH_SCALE_WIDTHREDUCTION times
// the normal width. This helps keep orientation in extreme attitudes.
44 45
static const int PITCH_SCALE_WIDTHREDUCTION_FROM = 30;
static const float PITCH_SCALE_WIDTHREDUCTION = 0.3f;
46

47
static const int PITCH_SCALE_HALFRANGE = 15;
48 49 50 51 52

// The number of degrees to either side of the heading to draw the compass disk.
// 180 is valid, this will draw a complete disk. If the disk is partly clipped
// away, less will do.

53 54 55
static const int  COMPASS_DISK_MAJORTICK = 10;
static const int  COMPASS_DISK_ARROWTICK = 45;
static const int  COMPASS_DISK_RESOLUTION = 10;
56 57
static const float COMPASS_DISK_MARKERWIDTH = 0.2f;
static const float COMPASS_DISK_MARKERHEIGHT = 0.133f;
58

59
static const int  CROSSTRACK_MAX = 1000;
60
static const float CROSSTRACK_RADIUS = 0.6f;
61

62 63
static const float TAPE_GAUGES_TICKWIDTH_MAJOR = 0.25f;
static const float TAPE_GAUGES_TICKWIDTH_MINOR = 0.15f;
64 65

// The altitude difference between top and bottom of scale
66
static const int ALTIMETER_LINEAR_SPAN = 50;
67
// every 5 meters there is a tick mark
68
static const int ALTIMETER_LINEAR_RESOLUTION = 5;
69
// every 10 meters there is a number
70
static const int ALTIMETER_LINEAR_MAJOR_RESOLUTION = 10;
71 72

// min. and max. vertical velocity
73 74
static const int ALTIMETER_VVI_SPAN = 5;
static const float ALTIMETER_VVI_WIDTH = 0.2f;
75 76

// Now the same thing for airspeed!
77 78 79
static const int AIRSPEED_LINEAR_SPAN = 15;
static const int AIRSPEED_LINEAR_RESOLUTION = 1;
static const int AIRSPEED_LINEAR_MAJOR_RESOLUTION = 5;
80

81 82
/*
 *@TODO:
dongfang's avatar
dongfang committed
83
 * global fixed pens (and painters too?)
84 85 86
 * repaint on demand multiple canvases
 * multi implementation with shared model class
 */
dongfang's avatar
dongfang committed
87
double PrimaryFlightDisplay_round(double value, int digits=0)
88
{
89
    return floor(value * pow(10.0, digits) + 0.5) / pow(10.0, digits);
90
}
91

92 93 94 95 96 97
qreal PrimaryFlightDisplay_constrain(qreal value, qreal min, qreal max) {
    if (value<min) value=min;
    else if(value>max) value=max;
    return value;
}

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
const int PrimaryFlightDisplay::tickValues[] = {10, 20, 30, 45, 60};
const QString PrimaryFlightDisplay::compassWindNames[] = {
    QString("N"),
    QString("NE"),
    QString("E"),
    QString("SE"),
    QString("S"),
    QString("SW"),
    QString("W"),
    QString("NW")
};

PrimaryFlightDisplay::PrimaryFlightDisplay(int width, int height, QWidget *parent) :
    QWidget(parent),

113 114 115
    _valuesChanged(false),
    _valuesLastPainted(QGC::groundTimeMilliseconds()),

116
    uas(NULL),
117

118 119 120
    roll(0),
    pitch(0),
    heading(0),
121

Don Gagne's avatar
Don Gagne committed
122 123
    altitudeAMSL(std::numeric_limits<double>::quiet_NaN()),
    altitudeRelative(std::numeric_limits<double>::quiet_NaN()),
124

Don Gagne's avatar
Don Gagne committed
125 126 127
    groundSpeed(std::numeric_limits<double>::quiet_NaN()),
    airSpeed(std::numeric_limits<double>::quiet_NaN()),
    climbRate(std::numeric_limits<double>::quiet_NaN()),
128

129
    navigationCrosstrackError(0),
Don Gagne's avatar
Don Gagne committed
130
    navigationTargetBearing(std::numeric_limits<double>::quiet_NaN()),
131

132 133
    layout(COMPASS_INTEGRATED),
    style(OVERLAY_HSI),
134

dongfang's avatar
dongfang committed
135
    redColor(QColor::fromHsvF(0, 0.75, 0.9)),
dongfang's avatar
dongfang committed
136 137 138 139 140 141 142
    amberColor(QColor::fromHsvF(0.12, 0.6, 1.0)),
    greenColor(QColor::fromHsvF(0.25, 0.8, 0.8)),

    lineWidth(2),
    fineLineWidth(1),

    instrumentEdgePen(QColor::fromHsvF(0, 0, 0.65, 0.5)),
dongfang's avatar
dongfang committed
143
    instrumentBackground(QColor::fromHsvF(0, 0, 0.3, 0.3)),
144 145 146
    instrumentOpagueBackground(QColor::fromHsvF(0, 0, 0.3, 1.0)),

    font("Bitstream Vera Sans"),
147
    refreshTimer(new QTimer(this))
dongfang's avatar
dongfang committed
148
{
149 150
    Q_UNUSED(width);
    Q_UNUSED(height);
151

152 153 154
    setMinimumSize(120, 80);
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

Lorenz Meier's avatar
Lorenz Meier committed
155 156
    setActiveUAS(UASManager::instance()->getActiveUAS());

157
    // Connect with UAS signal
158 159
    //connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(addUAS(UASInterface*)));
    connect(UASManager::instance(), SIGNAL(UASDeleted(UASInterface*)), this, SLOT(forgetUAS(UASInterface*)));
160
    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
161

162 163
    // Refresh timer
    refreshTimer->setInterval(updateInterval);
dongfang's avatar
dongfang committed
164
    //    connect(refreshTimer, SIGNAL(timeout()), this, SLOT(paintHUD()));
165
    connect(refreshTimer, SIGNAL(timeout()), this, SLOT(checkUpdate()));
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
}

PrimaryFlightDisplay::~PrimaryFlightDisplay()
{
    refreshTimer->stop();
}


QSize PrimaryFlightDisplay::sizeHint() const
{
    return QSize(width(), (width()*3.0f)/4);
}

void PrimaryFlightDisplay::showEvent(QShowEvent* event)
{
    // React only to internal (pre-display)
    // events
    QWidget::showEvent(event);
    refreshTimer->start(updateInterval);
    emit visibilityChanged(true);
}

void PrimaryFlightDisplay::hideEvent(QHideEvent* event)
{
    // React only to internal (pre-display)
    // events
    refreshTimer->stop();
    QWidget::hideEvent(event);
    emit visibilityChanged(false);
}

dongfang's avatar
dongfang committed
197 198 199 200
void PrimaryFlightDisplay::resizeEvent(QResizeEvent *e) {
    QWidget::resizeEvent(e);

    qreal size = e->size().width();
dongfang's avatar
dongfang committed
201
    //if(e->size().height()<size) size = e->size().height();
dongfang's avatar
dongfang committed
202

203 204
    lineWidth = PrimaryFlightDisplay_constrain(size*LINEWIDTH, 1, 6);
    fineLineWidth = PrimaryFlightDisplay_constrain(size*LINEWIDTH*2/3, 1, 2);
dongfang's avatar
dongfang committed
205 206 207 208

    instrumentEdgePen.setWidthF(fineLineWidth);
    //AIEdgePen.setWidthF(fineLineWidth);

209
    smallTextSize = size * SMALL_TEXT_SIZE;
dongfang's avatar
dongfang committed
210 211 212
    mediumTextSize = size * MEDIUM_TEXT_SIZE;
    largeTextSize = size * LARGE_TEXT_SIZE;

dongfang's avatar
dongfang committed
213 214
    /*
     * Try without layout Change-O-Matic. It was too complicated.
215 216
    qreal aspect = e->size().width() / e->size().height();
    if (aspect <= SEPARATE_COMPASS_ASPECTRATIO)
dongfang's avatar
dongfang committed
217 218
        layout = COMPASS_SEPARATED;
    else
219
        layout = COMPASS_INTEGRATED;
dongfang's avatar
dongfang committed
220
    */
221
    // qDebug("Width %d height %d decision %d", e->size().width(), e->size().height(), layout);
dongfang's avatar
dongfang committed
222
}
223

dongfang's avatar
dongfang committed
224 225 226 227 228
void PrimaryFlightDisplay::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    doPaint();
}
229

230 231 232 233 234 235 236 237 238
void PrimaryFlightDisplay::checkUpdate()
{
    if (uas && (_valuesChanged || (QGC::groundTimeMilliseconds() - _valuesLastPainted) > 260)) {
        update();
        _valuesChanged = false;
        _valuesLastPainted = QGC::groundTimeMilliseconds();
    }
}

239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
///*
// * Interface towards qgroundcontrol
// */
//void PrimaryFlightDisplay::addUAS(UASInterface* uas)
//{
//    if (uas)
//    {
//        if (!this->uas)
//        {
//            setActiveUAS(uas);
//        }
//    }
//}

void PrimaryFlightDisplay::forgetUAS(UASInterface* uas)
254
{
255
    if (this->uas != NULL && this->uas == uas) {
256
        // Disconnect any previously connected active MAV
257 258 259 260 261
        disconnect(this->uas, SIGNAL(attitudeChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateAttitude(UASInterface*, double, double, double, quint64)));
        disconnect(this->uas, SIGNAL(attitudeChanged(UASInterface*,int,double,double,double,quint64)), this, SLOT(updateAttitude(UASInterface*,int,double, double, double, quint64)));
        disconnect(this->uas, SIGNAL(speedChanged(UASInterface*, double, double, quint64)), this, SLOT(updateSpeed(UASInterface*, double, double, quint64)));
        disconnect(this->uas, SIGNAL(altitudeChanged(UASInterface*, double, double, double, quint64)), this, SLOT(updateAltitude(UASInterface*, double, double, double, quint64)));
        disconnect(this->uas, SIGNAL(navigationControllerErrorsChanged(UASInterface*, double, double, double)), this, SLOT(updateNavigationControllerErrors(UASInterface*, double, double, double)));
262
    }
263 264 265 266 267 268 269 270
}

/**
 *
 * @param uas the UAS/MAV to monitor/display with the HUD
 */
void PrimaryFlightDisplay::setActiveUAS(UASInterface* uas)
{
tstellanova's avatar
tstellanova committed
271 272 273
    if (uas == this->uas)
        return; //no need to rewire

274 275
    // Disconnect the previous one (if any)
    forgetUAS(this->uas);
276 277 278 279 280 281

    if (uas) {
        // Now connect the new UAS
        // Setup communication
        connect(uas, SIGNAL(attitudeChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateAttitude(UASInterface*, double, double, double, quint64)));
        connect(uas, SIGNAL(attitudeChanged(UASInterface*,int,double,double,double,quint64)), this, SLOT(updateAttitude(UASInterface*,int,double, double, double, quint64)));
282 283
        connect(uas, SIGNAL(speedChanged(UASInterface*, double, double, quint64)), this, SLOT(updateSpeed(UASInterface*, double, double, quint64)));
        connect(uas, SIGNAL(altitudeChanged(UASInterface*, double, double, double, quint64)), this, SLOT(updateAltitude(UASInterface*, double, double, double, quint64)));
284
        connect(uas, SIGNAL(navigationControllerErrorsChanged(UASInterface*, double, double, double)), this, SLOT(updateNavigationControllerErrors(UASInterface*, double, double, double)));
285 286 287 288 289 290 291 292 293 294

        // Set new UAS
        this->uas = uas;
    }
}

void PrimaryFlightDisplay::updateAttitude(UASInterface* uas, double roll, double pitch, double yaw, quint64 timestamp)
{
    Q_UNUSED(uas);
    Q_UNUSED(timestamp);
295

296
        // Called from UAS.cc l. 616
297
        if (isinf(roll)) {
Don Gagne's avatar
Don Gagne committed
298
            this->roll = std::numeric_limits<double>::quiet_NaN();
299
        } else {
300 301 302 303 304 305 306 307

            float rolldeg = roll * (180.0 / M_PI);

            if (fabsf(roll - rolldeg) > 2.5f) {
                _valuesChanged = true;
            }

            this->roll = rolldeg;
308
        }
309

310
        if (isinf(pitch)) {
Don Gagne's avatar
Don Gagne committed
311
            this->pitch = std::numeric_limits<double>::quiet_NaN();
312
        } else {
313 314 315 316 317 318 319 320

            float pitchdeg = pitch * (180.0 / M_PI);

            if (fabsf(pitch - pitchdeg) > 2.5f) {
                _valuesChanged = true;
            }

            this->pitch = pitchdeg;
321 322
        }

323
        if (isinf(yaw)) {
Don Gagne's avatar
Don Gagne committed
324
            this->heading = std::numeric_limits<double>::quiet_NaN();
325
        } else {
326

327 328
            yaw = yaw * (180.0 / M_PI);
            if (yaw<0) yaw+=360;
329 330 331 332 333

            if (fabsf(heading - yaw) > 10.0f) {
                _valuesChanged = true;
            }

334 335
            this->heading = yaw;
        }
Lorenz Meier's avatar
Lorenz Meier committed
336

337 338 339 340 341
}

void PrimaryFlightDisplay::updateAttitude(UASInterface* uas, int component, double roll, double pitch, double yaw, quint64 timestamp)
{
    Q_UNUSED(component);
342
    this->updateAttitude(uas, roll, pitch, yaw, timestamp);
343 344
}

345
void PrimaryFlightDisplay::updateSpeed(UASInterface* uas, double _groundSpeed, double _airSpeed, quint64 timestamp)
346 347 348 349
{
    Q_UNUSED(uas);
    Q_UNUSED(timestamp);

350 351 352 353 354 355 356 357
    if (fabsf(groundSpeed - _groundSpeed) > 0.5f) {
        _valuesChanged = true;
    }

    if (fabsf(airSpeed - _airSpeed) > 1.0f) {
        _valuesChanged = true;
    }

358 359
    groundSpeed = _groundSpeed;
    airSpeed = _airSpeed;
360
}
361

362
void PrimaryFlightDisplay::updateAltitude(UASInterface* uas, double _altitudeAMSL, double _altitudeRelative, double _climbRate, quint64 timestamp) {
363 364
    Q_UNUSED(uas);
    Q_UNUSED(timestamp);
365 366 367 368 369 370 371 372 373 374 375 376 377

    if (fabsf(altitudeAMSL - _altitudeAMSL) > 0.5f) {
        _valuesChanged = true;
    }

    if (fabsf(altitudeRelative - _altitudeRelative) > 0.5f) {
        _valuesChanged = true;
    }

    if (fabsf(climbRate - _climbRate) > 0.5f) {
        _valuesChanged = true;
    }

378 379 380
    altitudeAMSL = _altitudeAMSL;
    altitudeRelative = _altitudeRelative;
    climbRate = _climbRate;
381 382
}

383 384 385 386 387 388 389 390
void PrimaryFlightDisplay::updateNavigationControllerErrors(UASInterface* uas, double altitudeError, double speedError, double xtrackError) {
    Q_UNUSED(uas);
    this->navigationAltitudeError = altitudeError;
    this->navigationSpeedError = speedError;
    this->navigationCrosstrackError = xtrackError;
}


391 392 393
/*
 * Private and such
 */
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409

// TODO: Move to UAS. Real working implementation.
bool PrimaryFlightDisplay::isAirplane() {
    if (!this->uas)
        return false;
    switch(this->uas->getSystemType()) {
    case MAV_TYPE_GENERIC:
    case MAV_TYPE_FIXED_WING:
    case MAV_TYPE_AIRSHIP:
    case MAV_TYPE_FLAPPING_WING:
        return true;
    default:
        return false;
    }
}

410 411 412 413 414 415 416
// TODO: Implement. Should return true when navigating.
// That would be (APM) in AUTO and RTL modes.
// This could forward to a virtual on UAS bool isNavigatingAutonomusly() or whatever.
bool PrimaryFlightDisplay::shouldDisplayNavigationData() {
    return true;
}

417 418 419
void PrimaryFlightDisplay::drawTextCenter (
        QPainter& painter,
        QString text,
dongfang's avatar
dongfang committed
420
        float pixelSize,
421 422 423
        float x,
        float y)
{
dongfang's avatar
dongfang committed
424
    font.setPixelSize(pixelSize);
425 426 427 428 429 430 431 432 433 434 435
    painter.setFont(font);

    QFontMetrics metrics = QFontMetrics(font);
    QRect bounds = metrics.boundingRect(text);
    int flags = Qt::AlignCenter |  Qt::TextDontClip; // For some reason the bounds rect is too small!
    painter.drawText(x /*+bounds.x()*/ -bounds.width()/2, y /*+bounds.y()*/ -bounds.height()/2, bounds.width(), bounds.height(), flags, text);
}

void PrimaryFlightDisplay::drawTextLeftCenter (
        QPainter& painter,
        QString text,
dongfang's avatar
dongfang committed
436
        float pixelSize,
437 438 439
        float x,
        float y)
{
dongfang's avatar
dongfang committed
440
    font.setPixelSize(pixelSize);
441 442 443 444 445 446 447 448 449 450 451
    painter.setFont(font);

    QFontMetrics metrics = QFontMetrics(font);
    QRect bounds = metrics.boundingRect(text);
    int flags = Qt::AlignLeft | Qt::TextDontClip; // For some reason the bounds rect is too small!
    painter.drawText(x /*+bounds.x()*/, y /*+bounds.y()*/ -bounds.height()/2, bounds.width(), bounds.height(), flags, text);
}

void PrimaryFlightDisplay::drawTextRightCenter (
        QPainter& painter,
        QString text,
dongfang's avatar
dongfang committed
452
        float pixelSize,
453 454 455
        float x,
        float y)
{
dongfang's avatar
dongfang committed
456
    font.setPixelSize(pixelSize);
457 458 459 460 461 462 463 464 465 466 467
    painter.setFont(font);

    QFontMetrics metrics = QFontMetrics(font);
    QRect bounds = metrics.boundingRect(text);
    int flags = Qt::AlignRight | Qt::TextDontClip; // For some reason the bounds rect is too small!
    painter.drawText(x /*+bounds.x()*/ -bounds.width(), y /*+bounds.y()*/ -bounds.height()/2, bounds.width(), bounds.height(), flags, text);
}

void PrimaryFlightDisplay::drawTextCenterTop (
        QPainter& painter,
        QString text,
dongfang's avatar
dongfang committed
468
        float pixelSize,
469 470 471
        float x,
        float y)
{
dongfang's avatar
dongfang committed
472
    font.setPixelSize(pixelSize);
473 474 475 476 477 478 479 480 481 482 483
    painter.setFont(font);

    QFontMetrics metrics = QFontMetrics(font);
    QRect bounds = metrics.boundingRect(text);
    int flags = Qt::AlignCenter | Qt::TextDontClip; // For some reason the bounds rect is too small!
    painter.drawText(x /*+bounds.x()*/ -bounds.width()/2, y+bounds.height() /*+bounds.y()*/, bounds.width(), bounds.height(), flags, text);
}

void PrimaryFlightDisplay::drawTextCenterBottom (
        QPainter& painter,
        QString text,
dongfang's avatar
dongfang committed
484
        float pixelSize,
485 486 487
        float x,
        float y)
{
dongfang's avatar
dongfang committed
488
    font.setPixelSize(pixelSize);
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
    painter.setFont(font);

    QFontMetrics metrics = QFontMetrics(font);
    QRect bounds = metrics.boundingRect(text);
    int flags = Qt::AlignCenter;
    painter.drawText(x /*+bounds.x()*/ -bounds.width()/2, y /*+bounds.y()*/, bounds.width(), bounds.height(), flags, text);
}

void PrimaryFlightDisplay::drawInstrumentBackground(QPainter& painter, QRectF edge) {
    painter.setPen(instrumentEdgePen);
    painter.drawRect(edge);
}

void PrimaryFlightDisplay::fillInstrumentBackground(QPainter& painter, QRectF edge) {
    painter.setPen(instrumentEdgePen);
    painter.setBrush(instrumentBackground);
    painter.drawRect(edge);
    painter.setBrush(Qt::NoBrush);
}

dongfang's avatar
dongfang committed
509 510 511 512 513 514 515
void PrimaryFlightDisplay::fillInstrumentOpagueBackground(QPainter& painter, QRectF edge) {
    painter.setPen(instrumentEdgePen);
    painter.setBrush(instrumentOpagueBackground);
    painter.drawRect(edge);
    painter.setBrush(Qt::NoBrush);
}

516
qreal pitchAngleToTranslation(qreal viewHeight, float pitch) {
517
    if (isnan(pitch))
518
        return 0;
519
    return pitch * viewHeight / PITCHTRANSLATION;
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
}

void PrimaryFlightDisplay::drawAIAirframeFixedFeatures(QPainter& painter, QRectF area) {
    // red line from -7/10 to -5/10 half-width
    // red line from 7/10 to 5/10 half-width
    // red slanted line from -2/10 half-width to 0
    // red slanted line from 2/10 half-width to 0
    // red arrow thing under roll scale
    // prepareTransform(painter, width, height);
    painter.resetTransform();
    painter.translate(area.center());

    qreal w = area.width();
    qreal h = area.height();

dongfang's avatar
dongfang committed
535
    QPen pen;
536
    pen.setWidthF(lineWidth * 1.5f);
dongfang's avatar
dongfang committed
537 538
    pen.setColor(redColor);
    painter.setPen(pen);
539

540 541
    float length = 0.15f;
    float side = 0.5f;
dongfang's avatar
dongfang committed
542 543 544 545
    // The 2 lines at sides.
    painter.drawLine(QPointF(-side*w, 0), QPointF(-(side-length)*w, 0));
    painter.drawLine(QPointF(side*w, 0), QPointF((side-length)*w, 0));

546
    float rel = length/qSqrt(2.0f);
dongfang's avatar
dongfang committed
547 548 549 550 551 552 553 554
    // The gull
    painter.drawLine(QPointF(rel*w, rel*w/2), QPoint(0, 0));
    painter.drawLine(QPointF(-rel*w, rel*w/2), QPoint(0, 0));

    // The roll scale marker.
    QPainterPath markerPath(QPointF(0, -w*ROLL_SCALE_RADIUS+1));
    markerPath.lineTo(-h*ROLL_SCALE_MARKERWIDTH/2, -w*(ROLL_SCALE_RADIUS-ROLL_SCALE_MARKERHEIGHT)+1);
    markerPath.lineTo(h*ROLL_SCALE_MARKERWIDTH/2, -w*(ROLL_SCALE_RADIUS-ROLL_SCALE_MARKERHEIGHT)+1);
555 556 557 558
    markerPath.closeSubpath();
    painter.drawPath(markerPath);
}

559 560 561 562 563 564 565 566 567 568 569 570 571 572
inline qreal min4(qreal a, qreal b, qreal c, qreal d) {
    if(b<a) a=b;
    if(c<a) a=c;
    if(d<a) a=d;
    return a;
}

inline qreal max4(qreal a, qreal b, qreal c, qreal d) {
    if(b>a) a=b;
    if(c>a) a=c;
    if(d>a) a=d;
    return a;
}

573 574
void PrimaryFlightDisplay::drawAIGlobalFeatures(
        QPainter& painter,
575 576
        QRectF mainArea,
        QRectF paintArea) {
577

578
    float displayRoll = this->roll;
579
    if (isnan(displayRoll))
580 581
        displayRoll = 0;

582
    painter.resetTransform();
583
    painter.translate(mainArea.center());
584

585 586
    qreal pitchPixels = pitchAngleToTranslation(mainArea.height(), pitch);
    qreal gradientEnd = pitchAngleToTranslation(mainArea.height(), 60);
587

588 589
    //painter.rotate(-roll);
    //painter.translate(0, pitchPixels);
590

591 592
    //    QTransform forwardTransform;
    //forwardTransform.translate(mainArea.center().x(), mainArea.center().y());
593
    painter.rotate(-displayRoll);
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
    painter.translate(0, pitchPixels);

    // Calculate the radius of area we need to paint to cover all.
    QTransform rtx = painter.transform().inverted();

    QPointF topLeft = rtx.map(paintArea.topLeft());
    QPointF topRight = rtx.map(paintArea.topRight());
    QPointF bottomLeft = rtx.map(paintArea.bottomLeft());
    QPointF bottomRight = rtx.map(paintArea.bottomRight());
    // Just KISS... make a rectangluar basis.
    qreal minx = min4(topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x());
    qreal maxx = max4(topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x());
    qreal miny = min4(topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y());
    qreal maxy = max4(topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y());

    QPointF hzonLeft = QPoint(minx, 0);
    QPointF hzonRight = QPoint(maxx, 0);

    QPainterPath skyPath(hzonLeft);
    skyPath.lineTo(QPointF(minx, miny));
    skyPath.lineTo(QPointF(maxx, miny));
    skyPath.lineTo(hzonRight);
616 617
    skyPath.closeSubpath();

618
    QLinearGradient skyGradient(0, -gradientEnd, 0, 0);
619 620 621 622 623
    skyGradient.setColorAt(0, QColor::fromHsvF(0.6, 1.0, 0.7));
    skyGradient.setColorAt(1, QColor::fromHsvF(0.6, 0.25, 0.9));
    QBrush skyBrush(skyGradient);
    painter.fillPath(skyPath, skyBrush);

624 625 626 627
    QPainterPath groundPath(hzonRight);
    groundPath.lineTo(maxx, maxy);
    groundPath.lineTo(minx, maxy);
    groundPath.lineTo(hzonLeft);
628 629
    groundPath.closeSubpath();

630
    QLinearGradient groundGradient(0, gradientEnd, 0, 0);
631 632 633 634 635
    groundGradient.setColorAt(0, QColor::fromHsvF(0.25, 1, 0.5));
    groundGradient.setColorAt(1, QColor::fromHsvF(0.25, 0.25, 0.5));
    QBrush groundBrush(groundGradient);
    painter.fillPath(groundPath, groundBrush);

dongfang's avatar
dongfang committed
636 637 638 639 640
    QPen pen;
    pen.setWidthF(lineWidth);
    pen.setColor(greenColor);
    painter.setPen(pen);

641 642
    QPointF start(-mainArea.width(), 0);
    QPoint end(mainArea.width(), 0);
643 644 645 646 647 648
    painter.drawLine(start, end);
}

void PrimaryFlightDisplay::drawPitchScale(
        QPainter& painter,
        QRectF area,
dongfang's avatar
dongfang committed
649
        float intrusion,
650 651 652 653
        bool drawNumbersLeft,
        bool drawNumbersRight
        ) {

654 655
    Q_UNUSED(intrusion);
    
656
    float displayPitch = this->pitch;
657
    if (isnan(displayPitch))
658 659
        displayPitch = 0;

dongfang's avatar
dongfang committed
660 661 662
    // The area should be quadratic but if not width is the major size.
    qreal w = area.width();
    if (w<area.height()) w = area.height();
663

dongfang's avatar
dongfang committed
664 665 666 667
    QPen pen;
    pen.setWidthF(lineWidth);
    pen.setColor(Qt::white);
    painter.setPen(pen);
668 669 670 671

    QTransform savedTransform = painter.transform();

    // find the mark nearest center
672
    int snap = qRound((double)(displayPitch/PITCH_SCALE_RESOLUTION))*PITCH_SCALE_RESOLUTION;
673 674 675 676
    int _min = snap-PITCH_SCALE_HALFRANGE;
    int _max = snap+PITCH_SCALE_HALFRANGE;
    for (int degrees=_min; degrees<=_max; degrees+=PITCH_SCALE_RESOLUTION) {
        bool isMajor = degrees % (PITCH_SCALE_RESOLUTION*2) == 0;
677 678 679 680 681 682 683 684 685 686 687 688
        float linewidth =  isMajor ? PITCH_SCALE_MAJORWIDTH : PITCH_SCALE_MINORWIDTH;
        if (abs(degrees) > PITCH_SCALE_WIDTHREDUCTION_FROM) {
            // we want: 1 at PITCH_SCALE_WIDTHREDUCTION_FROM and PITCH_SCALE_WIDTHREDUCTION at 90.
            // That is PITCH_SCALE_WIDTHREDUCTION + (1-PITCH_SCALE_WIDTHREDUCTION) * f(pitch)
            // where f(90)=0 and f(PITCH_SCALE_WIDTHREDUCTION_FROM)=1
            // f(p) = (90-p) * 1/(90-PITCH_SCALE_WIDTHREDUCTION_FROM)
            // or PITCH_SCALE_WIDTHREDUCTION + f(pitch) - f(pitch) * PITCH_SCALE_WIDTHREDUCTION
            // or PITCH_SCALE_WIDTHREDUCTION (1-f(pitch)) + f(pitch)
            int fromVertical = abs(pitch>=0 ? 90-pitch : -90-pitch);
            float temp = fromVertical * 1/(90.0f-PITCH_SCALE_WIDTHREDUCTION_FROM);
            linewidth *= (PITCH_SCALE_WIDTHREDUCTION * (1-temp) + temp);
        }
dongfang's avatar
dongfang committed
689

690
        float shift = pitchAngleToTranslation(w, displayPitch-degrees);
dongfang's avatar
dongfang committed
691 692 693 694

        // TODO: Intrusion detection and evasion. That is, don't draw
        // where the compass has intruded.

695
        painter.translate(0, shift);
dongfang's avatar
dongfang committed
696 697
        QPointF start(-linewidth*w, 0);
        QPointF end(linewidth*w, 0);
698 699 700 701 702 703 704
        painter.drawLine(start, end);

        if (isMajor && (drawNumbersLeft||drawNumbersRight)) {
            int displayDegrees = degrees;
            if(displayDegrees>90) displayDegrees = 180-displayDegrees;
            else if (displayDegrees<-90) displayDegrees = -180 - displayDegrees;
            if (SHOW_ZERO_ON_SCALES || degrees) {
705
                QString s_number;
706
                if (isnan(this->pitch))
707 708 709
                    s_number.sprintf("-");
                else
                    s_number.sprintf("%d", displayDegrees);
dongfang's avatar
dongfang committed
710 711
                if (drawNumbersLeft)  drawTextRightCenter(painter, s_number, mediumTextSize, -PITCH_SCALE_MAJORWIDTH * w-10, 0);
                if (drawNumbersRight) drawTextLeftCenter(painter, s_number, mediumTextSize, PITCH_SCALE_MAJORWIDTH * w+10, 0);
712 713 714 715 716 717 718 719 720 721 722 723 724
            }
        }

        painter.setTransform(savedTransform);
    }
}

void PrimaryFlightDisplay::drawRollScale(
        QPainter& painter,
        QRectF area,
        bool drawTicks,
        bool drawNumbers) {

725
    qreal w = area.width();
dongfang's avatar
dongfang committed
726
    if (w<area.height()) w = area.height();
727

dongfang's avatar
dongfang committed
728 729 730 731
    QPen pen;
    pen.setWidthF(lineWidth);
    pen.setColor(Qt::white);
    painter.setPen(pen);
732 733 734 735 736 737

    // We should really do these transforms but they are assumed done by caller.
    // painter.resetTransform();
    // painter.translate(area.center());
    // painter.rotate(roll);

738
    qreal _size = w * ROLL_SCALE_RADIUS*2;
dongfang's avatar
dongfang committed
739
    QRectF arcArea(-_size/2, - _size/2, _size, _size);
740
    painter.drawArc(arcArea, (90-ROLL_SCALE_RANGE)*16, ROLL_SCALE_RANGE*2*16);
dongfang's avatar
dongfang committed
741
    // painter.drawEllipse(QPoint(0,0),200,200);
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
    if (drawTicks) {
        int length = sizeof(tickValues)/sizeof(int);
        qreal previousRotation = 0;
        for (int i=0; i<length*2+1; i++) {
            int degrees = (i==length) ? 0 : (i>length) ?-tickValues[i-length-1] : tickValues[i];
            //degrees = 180 - degrees;
            painter.rotate(degrees - previousRotation);
            previousRotation = degrees;

            QPointF start(0, -_size/2);
            QPointF end(0, -(1.0+ROLL_SCALE_TICKMARKLENGTH)*_size/2);

            painter.drawLine(start, end);

            QString s_number; //= QString("%d").arg(degrees);
            if (SHOW_ZERO_ON_SCALES || degrees)
                s_number.sprintf("%d", abs(degrees));

            if (drawNumbers) {
761
                drawTextCenterBottom(painter, s_number, mediumTextSize, 0, -(ROLL_SCALE_RADIUS+ROLL_SCALE_TICKMARKLENGTH*1.7)*w);
762 763 764 765 766 767 768
            }
        }
    }
}

void PrimaryFlightDisplay::drawAIAttitudeScales(
        QPainter& painter,
dongfang's avatar
dongfang committed
769 770
        QRectF area,
        float intrusion
dongfang's avatar
dongfang committed
771
        ) {
772
    float displayRoll = this->roll;
773
    if (isnan(displayRoll))
774
        displayRoll = 0;
775 776 777
    // To save computations, we do these transformations once for both scales:
    painter.resetTransform();
    painter.translate(area.center());
778
    painter.rotate(-displayRoll);
779 780 781 782
    QTransform saved = painter.transform();

    drawRollScale(painter, area, true, true);
    painter.setTransform(saved);
dongfang's avatar
dongfang committed
783
    drawPitchScale(painter, area, intrusion, true, true);
784 785
}

dongfang's avatar
dongfang committed
786
void PrimaryFlightDisplay::drawAICompassDisk(QPainter& painter, QRectF area, float halfspan) {
787
    float displayHeading = this->heading;
788
    if (isnan(displayHeading))
789 790 791 792
        displayHeading = 0;

    float start = displayHeading - halfspan;
    float end = displayHeading + halfspan;
dongfang's avatar
dongfang committed
793

dongfang's avatar
dongfang committed
794 795
    int firstTick = ceil(start / COMPASS_DISK_RESOLUTION) * COMPASS_DISK_RESOLUTION;
    int lastTick = floor(end / COMPASS_DISK_RESOLUTION) * COMPASS_DISK_RESOLUTION;
796 797 798 799

    float radius = area.width()/2;
    float innerRadius = radius * 0.96;
    painter.resetTransform();
dongfang's avatar
dongfang committed
800 801
    painter.setBrush(instrumentBackground);
    painter.setPen(instrumentEdgePen);
802 803 804
    painter.drawEllipse(area);
    painter.setBrush(Qt::NoBrush);

dongfang's avatar
dongfang committed
805 806
    QPen scalePen(Qt::black);
    scalePen.setWidthF(fineLineWidth);
807

dongfang's avatar
dongfang committed
808
    for (int tickYaw = firstTick; tickYaw <= lastTick; tickYaw += COMPASS_DISK_RESOLUTION) {
809 810 811 812 813
        int displayTick = tickYaw;
        if (displayTick < 0) displayTick+=360;
        else if (displayTick>=360) displayTick-=360;

        // yaw is in center.
814
        float off = tickYaw - displayHeading;
815
        // wrap that to ]-180..180]
dongfang's avatar
dongfang committed
816
        if (off<=-180) off+= 360; else if (off>180) off -= 360;
817 818 819 820

        painter.translate(area.center());
        painter.rotate(off);
        bool drewArrow = false;
dongfang's avatar
dongfang committed
821
        bool isMajor = displayTick % COMPASS_DISK_MAJORTICK == 0;
822

823
        // If heading unknown, still draw marks but no numbers.
824
        if (!isnan(this->heading) &&
825
                (displayTick==30 || displayTick==60 ||
dongfang's avatar
dongfang committed
826 827
                displayTick==120 || displayTick==150 ||
                displayTick==210 || displayTick==240 ||
828 829
                displayTick==300 || displayTick==330)
        ) {
830 831 832
            // draw a number
            QString s_number;
            s_number.sprintf("%d", displayTick/10);
dongfang's avatar
dongfang committed
833
            painter.setPen(scalePen);
834
            drawTextCenter(painter, s_number, smallTextSize, 0, -innerRadius*0.75);
835
        } else {
dongfang's avatar
dongfang committed
836
            if (displayTick % COMPASS_DISK_ARROWTICK == 0) {
837 838 839 840 841
                if (displayTick!=0) {
                    QPainterPath markerPath(QPointF(0, -innerRadius*(1-COMPASS_DISK_MARKERHEIGHT/2)));
                    markerPath.lineTo(innerRadius*COMPASS_DISK_MARKERWIDTH/4, -innerRadius);
                    markerPath.lineTo(-innerRadius*COMPASS_DISK_MARKERWIDTH/4, -innerRadius);
                    markerPath.closeSubpath();
dongfang's avatar
dongfang committed
842
                    painter.setPen(scalePen);
843 844 845 846 847
                    painter.setBrush(Qt::SolidPattern);
                    painter.drawPath(markerPath);
                    painter.setBrush(Qt::NoBrush);
                    drewArrow = true;
                }
848
                // If heading unknown, still draw marks but no N S E W.
849
                if (!isnan(this->heading) && displayTick%90 == 0) {
850
                    // Also draw a label
dongfang's avatar
dongfang committed
851 852 853
                    QString name = compassWindNames[displayTick / 45];
                    painter.setPen(scalePen);
                    drawTextCenter(painter, name, mediumTextSize, 0, -innerRadius*0.75);
854
                }
dongfang's avatar
dongfang committed
855
            }
856
        }
dongfang's avatar
dongfang committed
857
        // draw the scale lines. If an arrow was drawn, stay off from it.
858

dongfang's avatar
dongfang committed
859 860
        QPointF p_start = drewArrow ? QPoint(0, -innerRadius*0.94) : QPoint(0, -innerRadius);
        QPoint p_end = isMajor ? QPoint(0, -innerRadius*0.86) : QPoint(0, -innerRadius*0.90);
861

dongfang's avatar
dongfang committed
862
        painter.setPen(scalePen);
863 864 865 866
        painter.drawLine(p_start, p_end);
        painter.resetTransform();
    }

dongfang's avatar
dongfang committed
867
    painter.setPen(scalePen);
868 869 870 871 872 873 874 875
    //painter.setBrush(Qt::SolidPattern);
    painter.translate(area.center());
    QPainterPath markerPath(QPointF(0, -radius-2));
    markerPath.lineTo(radius*COMPASS_DISK_MARKERWIDTH/2,  -radius-radius*COMPASS_DISK_MARKERHEIGHT-2);
    markerPath.lineTo(-radius*COMPASS_DISK_MARKERWIDTH/2, -radius-radius*COMPASS_DISK_MARKERHEIGHT-2);
    markerPath.closeSubpath();
    painter.drawPath(markerPath);

dongfang's avatar
dongfang committed
876 877 878 879 880 881 882 883 884
    qreal digitalCompassYCenter = -radius*0.52;
    qreal digitalCompassHeight = radius*0.28;

    QPointF digitalCompassBottom(0, digitalCompassYCenter+digitalCompassHeight);
    QPointF  digitalCompassAbsoluteBottom = painter.transform().map(digitalCompassBottom);

    qreal digitalCompassUpshift = digitalCompassAbsoluteBottom.y()>height() ? digitalCompassAbsoluteBottom.y()-height() : 0;

    QRectF digitalCompassRect(-radius/3, -radius*0.52-digitalCompassUpshift, radius*2/3, radius*0.28);
885
    painter.setPen(instrumentEdgePen);
dongfang's avatar
dongfang committed
886
    painter.drawRoundedRect(digitalCompassRect, instrumentEdgePen.widthF()*2/3, instrumentEdgePen.widthF()*2/3);
887

dongfang's avatar
dongfang committed
888
    QString s_digitalCompass;
889

890
    if (isnan(this->heading))
891 892 893 894 895 896
        s_digitalCompass.sprintf("---");
    else {
    /* final safeguard for really stupid systems */
        int digitalCompassValue = static_cast<int>(qRound((double)heading)) % 360;
        s_digitalCompass.sprintf("%03d", digitalCompassValue);
    }
897

dongfang's avatar
dongfang committed
898 899 900 901
    QPen pen;
    pen.setWidthF(lineWidth);
    pen.setColor(Qt::white);
    painter.setPen(pen);
902

dongfang's avatar
dongfang committed
903
    drawTextCenter(painter, s_digitalCompass, largeTextSize, 0, -radius*0.38-digitalCompassUpshift);
904

905 906 907 908 909
//  dummy
//  navigationTargetBearing = 10;
//  navigationCrosstrackError = 500;

    // The CDI
910
    if (shouldDisplayNavigationData() && !isnan(navigationTargetBearing) && !isinf(navigationCrosstrackError)) {
911 912 913 914 915 916 917 918 919 920 921 922 923
        painter.resetTransform();
        painter.translate(area.center());
        // TODO : Sign might be wrong?
        // TODO : The case where error exceeds max. Truncate to max. and make that visible somehow.
        bool errorBeyondRadius = false;
        if (abs(navigationCrosstrackError) > CROSSTRACK_MAX) {
            errorBeyondRadius = true;
            navigationCrosstrackError = navigationCrosstrackError>0 ? CROSSTRACK_MAX : -CROSSTRACK_MAX;
        }

        float r = radius * CROSSTRACK_RADIUS;
        float x = navigationCrosstrackError / CROSSTRACK_MAX * r;
        float y = qSqrt(r*r - x*x); // the positive y, there is also a negative.
dongfang's avatar
dongfang committed
924

925 926 927 928 929 930 931
        float sillyHeading = 0;
        float angle = sillyHeading - navigationTargetBearing; // TODO: sign.
        painter.rotate(-angle);

        QPen pen;
        pen.setWidthF(lineWidth);
        pen.setColor(Qt::black);
932 933 934
        if(errorBeyondRadius) {
            pen.setStyle(Qt::DotLine);
        }
935 936 937 938 939 940
        painter.setPen(pen);

        painter.drawLine(QPointF(x, y), QPointF(x, -y));
    }
}

941 942
void PrimaryFlightDisplay::drawAltimeter(
        QPainter& painter,
943
        QRectF area
944
    ) {
945

946 947 948
    float primaryAltitude = altitudeAMSL;
    float secondaryAltitude = 0;

949
    painter.resetTransform();
950
    fillInstrumentBackground(painter, area);
951

dongfang's avatar
dongfang committed
952 953
    QPen pen;
    pen.setWidthF(lineWidth);
dongfang's avatar
dongfang committed
954

dongfang's avatar
dongfang committed
955 956
    pen.setColor(Qt::white);
    painter.setPen(pen);
957

dongfang's avatar
dongfang committed
958 959
    float h = area.height();
    float w = area.width();
960
    float secondaryAltitudeBoxHeight = mediumTextSize * 2;
dongfang's avatar
dongfang committed
961
    // The height where we being with new tickmarks.
dongfang's avatar
dongfang committed
962
    float effectiveHalfHeight = h*0.45;
963 964

    // not yet implemented: Display of secondary altitude.
965
    if (!isnan(secondaryAltitude)) {
966 967
        effectiveHalfHeight-= secondaryAltitudeBoxHeight;
    }
968

dongfang's avatar
dongfang committed
969 970 971 972 973 974
    float markerHalfHeight = mediumTextSize*0.8;
    float leftEdge = instrumentEdgePen.widthF()*2;
    float rightEdge = w-leftEdge;
    float tickmarkLeft = leftEdge;
    float tickmarkRightMajor = tickmarkLeft+TAPE_GAUGES_TICKWIDTH_MAJOR*w;
    float tickmarkRightMinor = tickmarkLeft+TAPE_GAUGES_TICKWIDTH_MINOR*w;
dongfang's avatar
dongfang committed
975
    float numbersLeft = 0.42*w;
dongfang's avatar
dongfang committed
976
    float markerTip = (tickmarkLeft*2+tickmarkRightMajor)/3;
977
    float scaleCenterAltitude = isnan(primaryAltitude) ? 0 : primaryAltitude;
978 979

    // altitude scale
dongfang's avatar
dongfang committed
980 981
    float start = scaleCenterAltitude - ALTIMETER_LINEAR_SPAN/2;
    float end = scaleCenterAltitude + ALTIMETER_LINEAR_SPAN/2;
982 983 984
    int firstTick = ceil(start / ALTIMETER_LINEAR_RESOLUTION) * ALTIMETER_LINEAR_RESOLUTION;
    int lastTick = floor(end / ALTIMETER_LINEAR_RESOLUTION) * ALTIMETER_LINEAR_RESOLUTION;
    for (int tickAlt = firstTick; tickAlt <= lastTick; tickAlt += ALTIMETER_LINEAR_RESOLUTION) {
dongfang's avatar
dongfang committed
985 986
        float y = (tickAlt-scaleCenterAltitude)*effectiveHalfHeight/(ALTIMETER_LINEAR_SPAN/2);
        bool isMajor = tickAlt % ALTIMETER_LINEAR_MAJOR_RESOLUTION == 0;
987

988 989
        painter.resetTransform();
        painter.translate(area.left(), area.center().y() - y);
dongfang's avatar
dongfang committed
990 991 992 993
        pen.setColor(tickAlt<0 ? redColor : Qt::white);
        painter.setPen(pen);
        if (isMajor) {
            painter.drawLine(tickmarkLeft, 0, tickmarkRightMajor, 0);
994
            QString s_alt;
dongfang's avatar
dongfang committed
995
            s_alt.sprintf("%d", abs(tickAlt));
dongfang's avatar
dongfang committed
996
            drawTextLeftCenter(painter, s_alt, mediumTextSize, numbersLeft, 0);
dongfang's avatar
dongfang committed
997 998
        } else {
            painter.drawLine(tickmarkLeft, 0, tickmarkRightMinor, 0);
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
        }
    }

    QPainterPath markerPath(QPoint(markerTip, 0));
    markerPath.lineTo(markerTip+markerHalfHeight, markerHalfHeight);
    markerPath.lineTo(rightEdge, markerHalfHeight);
    markerPath.lineTo(rightEdge, -markerHalfHeight);
    markerPath.lineTo(markerTip+markerHalfHeight, -markerHalfHeight);
    markerPath.closeSubpath();

    painter.resetTransform();
    painter.translate(area.left(), area.center().y());
dongfang's avatar
dongfang committed
1011

dongfang's avatar
dongfang committed
1012
    pen.setWidthF(lineWidth);
dongfang's avatar
dongfang committed
1013 1014 1015
    pen.setColor(Qt::white);
    painter.setPen(pen);

1016 1017 1018 1019
    painter.setBrush(Qt::SolidPattern);
    painter.drawPath(markerPath);
    painter.setBrush(Qt::NoBrush);

dongfang's avatar
dongfang committed
1020 1021
    pen.setColor(Qt::white);
    painter.setPen(pen);
dongfang's avatar
dongfang committed
1022

1023
    QString s_alt;
1024
    if (isnan(primaryAltitude))
dongfang's avatar
dongfang committed
1025 1026 1027 1028
        s_alt.sprintf("---");
    else
        s_alt.sprintf("%3.0f", primaryAltitude);

1029
    float xCenter = (markerTip+rightEdge)/2;
1030
    drawTextCenter(painter, s_alt, mediumTextSize, xCenter, 0);
dongfang's avatar
dongfang committed
1031

1032
    // draw simple in-tape VVI.
1033 1034 1035 1036
    if (!isnan(climbRate)) {
        float vvPixHeight = -climbRate/ALTIMETER_VVI_SPAN * effectiveHalfHeight;
        if (abs (vvPixHeight) < markerHalfHeight)
            return; // hidden behind marker.
dongfang's avatar
dongfang committed
1037

1038
        float vvSign = vvPixHeight>0 ? 1 : -1; // reverse y sign
dongfang's avatar
dongfang committed
1039

1040 1041 1042 1043
        // QRectF vvRect(rightEdge - w*ALTIMETER_VVI_WIDTH, markerHalfHeight*vvSign, w*ALTIMETER_VVI_WIDTH, abs(vvPixHeight)*vvSign);
        QPointF vvArrowBegin(rightEdge - w*ALTIMETER_VVI_WIDTH/2, markerHalfHeight*vvSign);
        QPointF vvArrowEnd(rightEdge - w*ALTIMETER_VVI_WIDTH/2, vvPixHeight);
        painter.drawLine(vvArrowBegin, vvArrowEnd);
dongfang's avatar
dongfang committed
1044

1045 1046 1047
        // Yeah this is a repitition of above code but we are goigd to trash it all anyway, so no fix.
        float vvArowHeadSize = abs(vvPixHeight - markerHalfHeight*vvSign);
        if (vvArowHeadSize > w*ALTIMETER_VVI_WIDTH/3) vvArowHeadSize = w*ALTIMETER_VVI_WIDTH/3;
1048

1049
        float xcenter = rightEdge-w*ALTIMETER_VVI_WIDTH/2;
1050

1051 1052
        QPointF vvArrowHead(xcenter+vvArowHeadSize, vvPixHeight - vvSign *vvArowHeadSize);
        painter.drawLine(vvArrowHead, vvArrowEnd);
dongfang's avatar
dongfang committed
1053

1054 1055
        vvArrowHead = QPointF(xcenter-vvArowHeadSize, vvPixHeight - vvSign * vvArowHeadSize);
        painter.drawLine(vvArrowHead, vvArrowEnd);
1056 1057 1058
    }

    // print secondary altitude
1059
    if (!isnan(secondaryAltitude)) {
1060 1061 1062 1063 1064 1065 1066 1067 1068
        QRectF saBox(area.x(), area.y()-secondaryAltitudeBoxHeight, w, secondaryAltitudeBoxHeight);
        painter.resetTransform();
        painter.translate(saBox.center());
        QString s_salt;
        s_salt.sprintf("%3.0f", secondaryAltitude);
        drawTextCenter(painter, s_salt, mediumTextSize, 0, 0);
    }

    // print target altitude (if applicable)
1069 1070
}

1071 1072
void PrimaryFlightDisplay::drawVelocityMeter(
        QPainter& painter,
1073
        QRectF area
1074 1075 1076
        ) {

    painter.resetTransform();
1077
    fillInstrumentBackground(painter, area);
1078 1079 1080 1081 1082 1083 1084

    QPen pen;
    pen.setWidthF(lineWidth);

    float h = area.height();
    float w = area.width();
    float effectiveHalfHeight = h*0.45;
dongfang's avatar
dongfang committed
1085
    float markerHalfHeight = mediumTextSize;
dongfang's avatar
dongfang committed
1086
    float leftEdge = instrumentEdgePen.widthF()*2;
dongfang's avatar
dongfang committed
1087 1088 1089 1090 1091 1092 1093
    float tickmarkRight = w-leftEdge;
    float tickmarkLeftMajor = tickmarkRight-w*TAPE_GAUGES_TICKWIDTH_MAJOR;
    float tickmarkLeftMinor = tickmarkRight-w*TAPE_GAUGES_TICKWIDTH_MINOR;
    float numbersRight = 0.42*w;
    float markerTip = (tickmarkLeftMajor+tickmarkRight*2)/3;

    // Select between air and ground speed:
1094
    float speed = (isAirplane() && !isnan(airSpeed)) ? airSpeed : groundSpeed;
1095
    float centerScaleSpeed = isnan(speed) ? 0 : speed;
dongfang's avatar
dongfang committed
1096 1097 1098

    float start = centerScaleSpeed - AIRSPEED_LINEAR_SPAN/2;
    float end = centerScaleSpeed + AIRSPEED_LINEAR_SPAN/2;
1099 1100 1101 1102

    int firstTick = ceil(start / AIRSPEED_LINEAR_RESOLUTION) * AIRSPEED_LINEAR_RESOLUTION;
    int lastTick = floor(end / AIRSPEED_LINEAR_RESOLUTION) * AIRSPEED_LINEAR_RESOLUTION;
    for (int tickSpeed = firstTick; tickSpeed <= lastTick; tickSpeed += AIRSPEED_LINEAR_RESOLUTION) {
dongfang's avatar
dongfang committed
1103 1104 1105 1106
        pen.setColor(tickSpeed<0 ? redColor : Qt::white);
        painter.setPen(pen);

        float y = (tickSpeed-centerScaleSpeed)*effectiveHalfHeight/(AIRSPEED_LINEAR_SPAN/2);
1107 1108
        bool hasText = tickSpeed % AIRSPEED_LINEAR_MAJOR_RESOLUTION == 0;
        painter.resetTransform();
dongfang's avatar
dongfang committed
1109

1110
        painter.translate(area.left(), area.center().y() - y);
dongfang's avatar
dongfang committed
1111

1112
        if (hasText) {
dongfang's avatar
dongfang committed
1113
            painter.drawLine(tickmarkLeftMajor, 0, tickmarkRight, 0);
1114
            QString s_speed;
dongfang's avatar
dongfang committed
1115
            s_speed.sprintf("%d", abs(tickSpeed));
dongfang's avatar
dongfang committed
1116
            drawTextRightCenter(painter, s_speed, mediumTextSize, numbersRight, 0);
dongfang's avatar
dongfang committed
1117 1118
        } else {
            painter.drawLine(tickmarkLeftMinor, 0, tickmarkRight, 0);
1119 1120 1121 1122
        }
    }

    QPainterPath markerPath(QPoint(markerTip, 0));
dongfang's avatar
dongfang committed
1123 1124 1125 1126
    markerPath.lineTo(markerTip-markerHalfHeight, markerHalfHeight);
    markerPath.lineTo(leftEdge, markerHalfHeight);
    markerPath.lineTo(leftEdge, -markerHalfHeight);
    markerPath.lineTo(markerTip-markerHalfHeight, -markerHalfHeight);
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
    markerPath.closeSubpath();

    painter.resetTransform();
    painter.translate(area.left(), area.center().y());

    pen.setWidthF(lineWidth);
    pen.setColor(Qt::white);
    painter.setPen(pen);

    painter.setBrush(Qt::SolidPattern);
    painter.drawPath(markerPath);
    painter.setBrush(Qt::NoBrush);

    pen.setColor(Qt::white);
    painter.setPen(pen);
    QString s_alt;
1143
    if (isnan(speed))
dongfang's avatar
dongfang committed
1144 1145
        s_alt.sprintf("---");
    else
1146
        s_alt.sprintf("%3.1f", speed);
dongfang's avatar
dongfang committed
1147
    float xCenter = (markerTip+leftEdge)/2;
1148 1149 1150
    drawTextCenter(painter, s_alt, /* TAPES_TEXT_SIZE*width()*/ mediumTextSize, xCenter, 0);
}

1151 1152 1153 1154
static const int TOP = (1<<0);
static const int BOTTOM = (1<<1);
static const int LEFT = (1<<2);
static const int RIGHT = (1<<3);
dongfang's avatar
dongfang committed
1155

1156 1157 1158 1159
static const int TOP_HALF = (1<<4);
static const int BOTTOM_HALF = (1<<5);
static const int LEFT_HALF = (1<<6);
static const int RIGHT_HALF = (1<<7);
dongfang's avatar
dongfang committed
1160 1161 1162 1163 1164 1165 1166 1167 1168

void applyMargin(QRectF& area, float margin, int where) {
    if (margin < 0.01) return;

    QRectF save(area);
    qreal consumed;

    if (where & LEFT) {
        area.setX(save.x() + (consumed = margin));
1169
    } else if (where & LEFT_HALF) {
dongfang's avatar
dongfang committed
1170 1171 1172 1173 1174 1175 1176
        area.setX(save.x() + (consumed = margin/2));
    } else {
        consumed = 0;
    }

    if (where & RIGHT) {
        area.setWidth(save.width()-consumed-margin);
1177
    } else if (where & RIGHT_HALF) {
dongfang's avatar
dongfang committed
1178 1179 1180 1181 1182 1183 1184
        area.setWidth(save.width()-consumed-margin/2);
    } else {
        area.setWidth(save.width()-consumed);
    }

    if (where & TOP) {
        area.setY(save.y() + (consumed = margin));
1185
    } else if (where & TOP_HALF) {
dongfang's avatar
dongfang committed
1186 1187 1188 1189 1190 1191 1192
        area.setY(save.y() + (consumed = margin/2));
    } else {
        consumed = 0;
    }

    if (where & BOTTOM) {
        area.setHeight(save.height()-consumed-margin);
1193
    } else if (where & BOTTOM_HALF) {
dongfang's avatar
dongfang committed
1194 1195 1196 1197 1198 1199 1200
        area.setHeight(save.height()-consumed-margin/2);
    } else {
        area.setHeight(save.height()-consumed);
    }
}

void setMarginsForInlineLayout(qreal margin, QRectF& panel1, QRectF& panel2, QRectF& panel3, QRectF& panel4) {
1201 1202 1203 1204
    applyMargin(panel1, margin, BOTTOM|LEFT|RIGHT_HALF);
    applyMargin(panel2, margin, BOTTOM|LEFT_HALF|RIGHT_HALF);
    applyMargin(panel3, margin, BOTTOM|LEFT_HALF|RIGHT_HALF);
    applyMargin(panel4, margin, BOTTOM|LEFT_HALF|RIGHT);
1205 1206
}

dongfang's avatar
dongfang committed
1207
void setMarginsForCornerLayout(qreal margin, QRectF& panel1, QRectF& panel2, QRectF& panel3, QRectF& panel4) {
1208 1209 1210 1211
    applyMargin(panel1, margin, BOTTOM|LEFT|RIGHT_HALF);
    applyMargin(panel2, margin, BOTTOM|LEFT_HALF|RIGHT_HALF);
    applyMargin(panel3, margin, BOTTOM|LEFT_HALF|RIGHT_HALF);
    applyMargin(panel4, margin, BOTTOM|LEFT_HALF|RIGHT);
dongfang's avatar
dongfang committed
1212 1213 1214 1215
}

inline qreal tapesGaugeWidthFor(qreal containerWidth, qreal preferredAIWidth) {
    qreal result = (containerWidth - preferredAIWidth) / 2.0f;
dongfang's avatar
dongfang committed
1216
    qreal minimum = containerWidth / 5.5f;
dongfang's avatar
dongfang committed
1217 1218 1219 1220 1221
    if (result < minimum) result = minimum;
    return result;
}

void PrimaryFlightDisplay::doPaint() {
1222 1223 1224 1225 1226
    QPainter painter;
    painter.begin(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setRenderHint(QPainter::HighQualityAntialiasing, true);

dongfang's avatar
dongfang committed
1227
    qreal margin = height()/100.0f;
1228

1229 1230 1231 1232 1233
    // The AI centers on this area.
    QRectF AIMainArea;
    // The AI paints on this area. It should contain the AIMainArea.
    QRectF AIPaintArea;

dongfang's avatar
dongfang committed
1234 1235 1236 1237 1238 1239 1240
    QRectF compassArea;
    QRectF altimeterArea;
    QRectF velocityMeterArea;
    QRectF sensorsStatsArea;
    QRectF linkStatsArea;
    QRectF sysStatsArea;
    QRectF missionStatsArea;
1241 1242

    painter.fillRect(rect(), Qt::black);
dongfang's avatar
dongfang committed
1243 1244
    qreal tapeGaugeWidth;

dongfang's avatar
dongfang committed
1245 1246 1247
    qreal compassHalfSpan = 180;
    float compassAIIntrusion = 0;

dongfang's avatar
dongfang committed
1248
    switch(layout) {
1249
    /*
dongfang's avatar
dongfang committed
1250 1251 1252 1253 1254 1255
    case FEATUREPANELS_IN_CORNERS: {
        tapeGaugeWidth = tapesGaugeWidthFor(width(), height());

        // A layout optimal for a container wider than it is high.
        // The AI gets full height and if tapes are transparent, also full width. If tapes are opague, then
        // the AI gets a width to be perfectly square.
1256 1257
        AIMainArea = QRectF(
                    style == NO_OVERLAYS ? tapeGaugeWidth : 0,
dongfang's avatar
dongfang committed
1258
                    0,
1259
                    style == NO_OVERLAYS ? width() - tapeGaugeWidth * 2: width(),
dongfang's avatar
dongfang committed
1260 1261
                    height());

1262 1263
        AIPaintArea = AIMainArea;

dongfang's avatar
dongfang committed
1264 1265 1266 1267
        // Tape gauges get so much width that the AI area not covered by them is perfectly square.

        qreal sidePanelsHeight = height();

1268
        altimeterArea = QRectF(AIMainArea.right(), height()/5, tapeGaugeWidth, sidePanelsHeight*3/5);
dongfang's avatar
dongfang committed
1269 1270 1271
        velocityMeterArea = QRectF (0, height()/5, tapeGaugeWidth, sidePanelsHeight*3/5);

        sensorsStatsArea = QRectF(0, 0, tapeGaugeWidth, sidePanelsHeight/5);
1272
        linkStatsArea = QRectF(AIMainArea.right(), 0, tapeGaugeWidth, sidePanelsHeight/5);
dongfang's avatar
dongfang committed
1273
        sysStatsArea = QRectF(0, sidePanelsHeight*4/5, tapeGaugeWidth, sidePanelsHeight/5);
1274
        missionStatsArea =QRectF(AIMainArea.right(), sidePanelsHeight*4/5, tapeGaugeWidth, sidePanelsHeight/5);
dongfang's avatar
dongfang committed
1275

1276 1277
        if (style == NO_OVERLAYS) {
            applyMargin(AIMainArea, margin, TOP|BOTTOM);
dongfang's avatar
dongfang committed
1278 1279 1280 1281
            applyMargin(altimeterArea, margin, TOP|BOTTOM|RIGHT);
            applyMargin(velocityMeterArea, margin, TOP|BOTTOM|LEFT);
            setMarginsForCornerLayout(margin, sensorsStatsArea, linkStatsArea, sysStatsArea, missionStatsArea);
        }
1282

dongfang's avatar
dongfang committed
1283
        // Compass is inside the AI ans within its margins also.
1284 1285
        compassArea = QRectF(AIMainArea.x()+AIMainArea.width()*0.60, AIMainArea.y()+AIMainArea.height()*0.80,
                             AIMainArea.width()/2, AIMainArea.width()/2);
dongfang's avatar
dongfang committed
1286 1287
        break;
    }
1288

dongfang's avatar
dongfang committed
1289 1290 1291 1292
    case FEATUREPANELS_AT_BOTTOM: {
        // A layout for containers with about the same width and height.
        // qreal minor = min(width(), height());
        // qreal major = max(width(), height());
1293

dongfang's avatar
dongfang committed
1294
        qreal aiheight = height()*4.0f/5;
1295

dongfang's avatar
dongfang committed
1296
        tapeGaugeWidth = tapesGaugeWidthFor(width(), aiheight);
1297

1298 1299
        AIMainArea = QRectF(
                    style == NO_OVERLAYS ? tapeGaugeWidth : 0,
dongfang's avatar
dongfang committed
1300
                    0,
1301
                    style == NO_OVERLAYS ? width() - tapeGaugeWidth*2 : width(),
dongfang's avatar
dongfang committed
1302
                    aiheight);
1303

1304 1305
        AIPaintArea = AIMainArea;

dongfang's avatar
dongfang committed
1306
        // Tape gauges get so much width that the AI area not covered by them is perfectly square.
1307
        altimeterArea = QRectF(AIMainArea.right(), 0, tapeGaugeWidth, aiheight);
dongfang's avatar
dongfang committed
1308
        velocityMeterArea = QRectF (0, 0, tapeGaugeWidth, aiheight);
1309

dongfang's avatar
dongfang committed
1310 1311
        qreal panelsHeight = height() / 5.0f;
        qreal panelsWidth = width() / 4.0f;
1312

1313 1314 1315 1316
        sensorsStatsArea = QRectF(0, AIMainArea.bottom(), panelsWidth, panelsHeight);
        linkStatsArea = QRectF(panelsWidth, AIMainArea.bottom(), panelsWidth, panelsHeight);
        sysStatsArea = QRectF(panelsWidth*2, AIMainArea.bottom(), panelsWidth, panelsHeight);
        missionStatsArea =QRectF(panelsWidth*3, AIMainArea.bottom(), panelsWidth, panelsHeight);
1317

1318 1319
        if (style == NO_OVERLAYS) {
            applyMargin(AIMainArea, margin, TOP|BOTTOM);
dongfang's avatar
dongfang committed
1320 1321 1322 1323
            applyMargin(altimeterArea, margin, TOP|BOTTOM|RIGHT);
            applyMargin(velocityMeterArea, margin, TOP|BOTTOM|LEFT);
            setMarginsForInlineLayout(margin, sensorsStatsArea, linkStatsArea, sysStatsArea, missionStatsArea);
        }
1324

dongfang's avatar
dongfang committed
1325
        // Compass is inside the AI ans within its margins also.
1326 1327
        compassArea = QRectF(AIMainArea.x()+AIMainArea.width()*0.60, AIMainArea.y()+AIMainArea.height()*0.80,
                             AIMainArea.width()/2, AIMainArea.width()/2);
dongfang's avatar
dongfang committed
1328 1329
        break;
    }
1330

1331 1332 1333
    */

    case COMPASS_INTEGRATED: {
dongfang's avatar
dongfang committed
1334
        tapeGaugeWidth = tapesGaugeWidthFor(width(), width());
1335
        qreal aiheight = height();
dongfang's avatar
dongfang committed
1336 1337
        qreal aiwidth = width()-tapeGaugeWidth*2;
        if (aiheight > aiwidth) aiheight = aiwidth;
1338 1339 1340 1341

        AIMainArea = QRectF(
                    tapeGaugeWidth,
                    0,
dongfang's avatar
dongfang committed
1342
                    aiwidth,
1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361
                    aiheight);

        AIPaintArea = QRectF(
                    0,
                    0,
                    width(),
                    height());

        // Tape gauges get so much width that the AI area not covered by them is perfectly square.
        velocityMeterArea = QRectF (0, 0, tapeGaugeWidth, aiheight);
        altimeterArea = QRectF(AIMainArea.right(), 0, tapeGaugeWidth, aiheight);

        if (style == NO_OVERLAYS) {
            applyMargin(AIMainArea, margin, TOP|BOTTOM);
            applyMargin(altimeterArea, margin, TOP|BOTTOM|RIGHT);
            applyMargin(velocityMeterArea, margin, TOP|BOTTOM|LEFT);
            setMarginsForInlineLayout(margin, sensorsStatsArea, linkStatsArea, sysStatsArea, missionStatsArea);
        }

dongfang's avatar
dongfang committed
1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389
        qreal compassRelativeWidth = 0.75;
        qreal compassBottomMargin = 0.78;

        qreal compassSize = compassRelativeWidth  * AIMainArea.width();  // Diameter is this times the width.

        qreal compassCenterY;
        //if (heightSurplus >= 0) compassCenterY =  AIMainArea.bottom() + compassSize/2;
        compassCenterY = AIMainArea.bottom() + compassSize / 4;

        if (height() - compassCenterY > AIMainArea.width()/2*compassBottomMargin)
            compassCenterY = height()-AIMainArea.width()/2*compassBottomMargin;

        // TODO: This is bad style...
        compassCenterY = (compassCenterY * 2 + AIMainArea.bottom() + compassSize / 4) / 3;

        compassArea = QRectF(AIMainArea.x()+(1-compassRelativeWidth)/2*AIMainArea.width(),
                             compassCenterY-compassSize/2,
                             compassSize,
                             compassSize);

        if (height()-compassCenterY < compassSize/2) {
            compassHalfSpan = acos((compassCenterY-height())*2/compassSize) * 180/M_PI + COMPASS_DISK_RESOLUTION;
            if (compassHalfSpan > 180) compassHalfSpan = 180;
        }

        compassAIIntrusion = compassSize/2 + AIMainArea.bottom() - compassCenterY;
        if (compassAIIntrusion<0) compassAIIntrusion = 0;

1390 1391
        break;
    }
dongfang's avatar
dongfang committed
1392 1393 1394 1395
    case COMPASS_SEPARATED: {
        // A layout for containers higher than their width.
        tapeGaugeWidth = tapesGaugeWidthFor(width(), width());

1396 1397
        qreal aiheight = width() - tapeGaugeWidth*2;
        qreal panelsHeight = 0;
dongfang's avatar
dongfang committed
1398

1399 1400
        AIMainArea = QRectF(
                    tapeGaugeWidth,
dongfang's avatar
dongfang committed
1401
                    0,
1402
                    width()-tapeGaugeWidth*2,
dongfang's avatar
dongfang committed
1403 1404
                    aiheight);

1405 1406 1407 1408 1409 1410 1411
        AIPaintArea = style == OVERLAY_HSI ?
                    QRectF(
                    0,
                    0,
                    width(),
                    height() - panelsHeight) : AIMainArea;

dongfang's avatar
dongfang committed
1412
        velocityMeterArea = QRectF (0, 0, tapeGaugeWidth, aiheight);
1413
        altimeterArea = QRectF(AIMainArea.right(), 0, tapeGaugeWidth, aiheight);
dongfang's avatar
dongfang committed
1414

1415
        /*
dongfang's avatar
dongfang committed
1416
        qreal panelsWidth = width() / 4.0f;
dongfang's avatar
dongfang committed
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426
        if(remainingHeight > width()) {
            // very tall layout, place panels below compass.
            sensorsStatsArea = QRectF(0, height()-panelsHeight, panelsWidth, panelsHeight);
            linkStatsArea = QRectF(panelsWidth, height()-panelsHeight, panelsWidth, panelsHeight);
            sysStatsArea = QRectF(panelsWidth*2, height()-panelsHeight, panelsWidth, panelsHeight);
            missionStatsArea =QRectF(panelsWidth*3, height()-panelsHeight, panelsWidth, panelsHeight);
            if (style == OPAGUE_TAPES) {
                setMarginsForInlineLayout(margin, sensorsStatsArea, linkStatsArea, sysStatsArea, missionStatsArea);
            }
            compassCenter = QPoint(width()/2, (AIArea.bottom()+height()-panelsHeight)/2);
dongfang's avatar
dongfang committed
1427
            maxCompassDiam = fmin(width(), height()-AIArea.height()-panelsHeight);
dongfang's avatar
dongfang committed
1428 1429
        } else {
            // Remaining part is wider than high; place panels in corners around compass
1430
            // Naaah it is really ugly, do not do that.
dongfang's avatar
dongfang committed
1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
            sensorsStatsArea = QRectF(0, AIArea.bottom(), panelsWidth, panelsHeight);
            linkStatsArea = QRectF(width()-panelsWidth, AIArea.bottom(), panelsWidth, panelsHeight);
            sysStatsArea = QRectF(0, height()-panelsHeight, panelsWidth, panelsHeight);
            missionStatsArea =QRectF(width()-panelsWidth, height()-panelsHeight, panelsWidth, panelsHeight);
            if (style == OPAGUE_TAPES) {
                setMarginsForCornerLayout(margin, sensorsStatsArea, linkStatsArea, sysStatsArea, missionStatsArea);
            }
            compassCenter = QPoint(width()/2, (AIArea.bottom()+height())/2);
            // diagonal between 2 panel corners
            qreal xd = width()-panelsWidth*2;
            qreal yd = height()-panelsHeight - AIArea.bottom();
dongfang's avatar
dongfang committed
1442 1443 1444 1445 1446 1447 1448 1449
            maxCompassDiam = qSqrt(xd*xd + yd*yd);
            if (maxCompassDiam > remainingHeight) {
                maxCompassDiam = width() - panelsWidth*2;
                if (maxCompassDiam > remainingHeight) {
                    // If still too large, lower.
                    // compassCenter.setY();
                }
            }
dongfang's avatar
dongfang committed
1450
        }
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460
        */
        /*
        sensorsStatsArea = QRectF(0, height()-panelsHeight, panelsWidth, panelsHeight);
        linkStatsArea = QRectF(panelsWidth, height()-panelsHeight, panelsWidth, panelsHeight);
        sysStatsArea = QRectF(panelsWidth*2, height()-panelsHeight, panelsWidth, panelsHeight);
        missionStatsArea =QRectF(panelsWidth*3, height()-panelsHeight, panelsWidth, panelsHeight);
        */

        QPoint compassCenter = QPoint(width()/2, AIMainArea.bottom()+width()/2);
        qreal compassDiam = width() * 0.8;
dongfang's avatar
dongfang committed
1461
        compassArea = QRectF(compassCenter.x()-compassDiam/2, compassCenter.y()-compassDiam/2, compassDiam, compassDiam);
dongfang's avatar
dongfang committed
1462 1463 1464
        break;
    }
    }
1465

dongfang's avatar
dongfang committed
1466
    bool hadClip = painter.hasClipping();
dongfang's avatar
dongfang committed
1467

dongfang's avatar
dongfang committed
1468
    painter.setClipping(true);
1469
    painter.setClipRect(AIPaintArea);
1470

1471
    drawAIGlobalFeatures(painter, AIMainArea, AIPaintArea);
dongfang's avatar
dongfang committed
1472
    drawAIAttitudeScales(painter, AIMainArea, compassAIIntrusion);
1473
    drawAIAirframeFixedFeatures(painter, AIMainArea);
1474

1475 1476 1477
   // if(layout ==COMPASS_SEPARATED)
        //drawSeparateCompassDisk(painter, compassArea);
   // else
dongfang's avatar
dongfang committed
1478
        drawAICompassDisk(painter, compassArea, compassHalfSpan);
1479

dongfang's avatar
dongfang committed
1480
    painter.setClipping(hadClip);
1481

1482
    drawAltimeter(painter, altimeterArea);
1483

1484
    drawVelocityMeter(painter, velocityMeterArea);
1485

1486
    /*
dongfang's avatar
dongfang committed
1487 1488 1489 1490
    drawSensorsStatsPanel(painter, sensorsStatsArea);
    drawLinkStatsPanel(painter, linkStatsArea);
    drawSysStatsPanel(painter, sysStatsArea);
    drawMissionStatsPanel(painter, missionStatsArea);
1491 1492
    */
    /*
dongfang's avatar
dongfang committed
1493 1494 1495
    if (style == OPAGUE_TAPES) {
        drawInstrumentBackground(painter, AIArea);
    }
1496
    */
dongfang's avatar
dongfang committed
1497

dongfang's avatar
dongfang committed
1498
    painter.end();
1499
}
1500 1501

void PrimaryFlightDisplay:: createActions() {}