Skip to content
Snippets Groups Projects
HSIDisplay.cc 37.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*=====================================================================
    
    
    QGroundControl Open Source Ground Control Station
    
    (c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
    
    This file is part of the QGROUNDCONTROL project
    
        QGROUNDCONTROL is free software: you can redistribute it and/or modify
    
        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.
    
    
        QGROUNDCONTROL is distributed in the hope that it will be useful,
    
        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
    
        along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
    
    
    ======================================================================*/
    
    /**
     * @file
     *   @brief Implementation of Horizontal Situation Indicator class
     *
     *   @author Lorenz Meier <mavteam@student.ethz.ch>
     *
     */
    
    #include <QFile>
    #include <QStringList>
    
    #include <QPainter>
    
    #include <QGraphicsScene>
    #include <QHBoxLayout>
    #include <QDoubleSpinBox>
    
    #include "UASManager.h"
    #include "HSIDisplay.h"
    
    #include "QGC.h"
    
    pixhawk's avatar
    pixhawk committed
    #include "Waypoint.h"
    
    lm's avatar
    lm committed
    //#include "Waypoint2DIcon.h"
    //#include "MAV2DIcon.h"
    
    HSIDisplay::HSIDisplay(QWidget *parent) :
    
        HDDisplay(NULL, "HSI", parent),
        gpsSatellites(),
        satellitesUsed(0),
        attXSet(0.0f),
        attYSet(0.0f),
        attYawSet(0.0f),
        altitudeSet(1.0f),
        posXSet(0.0f),
        posYSet(0.0f),
        posZSet(0.0f),
    
        attXSaturation(0.2f),
        attYSaturation(0.2f),
    
        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),
        uiZSetCoordinate(0.0f),
        uiYawSet(0.0f),
        metricWidth(4.0),
        positionLock(false),
        attControlEnabled(false),
        xyControlEnabled(false),
        zControlEnabled(false),
        yawControlEnabled(false),
        positionFix(0),
        gpsFix(0),
        visionFix(0),
        laserFix(0),
        mavInitialized(false),
        bottomMargin(10.0f),
        topMargin(12.0f),
        userSetPointSet(false)
    
        refreshTimer->setInterval(updateInterval);
    
    pixhawk's avatar
    pixhawk committed
        columns = 1;
    
        this->setAutoFillBackground(true);
    
        QPalette pal = palette();
        pal.setColor(backgroundRole(), QGC::colorBlack);
        setPalette(pal);
    
        vwidth = 80.0f;
        vheight = 80.0f;
    
        xCenterPos = vwidth/2.0f;
    
    pixhawk's avatar
    pixhawk committed
        yCenterPos = vheight/2.0f + topMargin - bottomMargin;
    
        //qDebug() << "CENTER" << xCenterPos << yCenterPos;
    
    
        // Add interaction elements
        QHBoxLayout* layout = new QHBoxLayout(this);
    
        layout->setMargin(0);
        layout->setSpacing(12);
    
        QDoubleSpinBox* spinBox = new QDoubleSpinBox(this);
        spinBox->setMinimum(0.1);
        spinBox->setMaximum(9999);
    
        spinBox->setMaximumWidth(50);
    
        spinBox->setValue(metricWidth);
        spinBox->setToolTip(tr("Ground width in meters shown on instrument"));
        spinBox->setStatusTip(tr("Ground width in meters shown on instrument"));
    
        connect(spinBox, SIGNAL(valueChanged(double)), this, SLOT(setMetricWidth(double)));
        connect(this, SIGNAL(metricWidthChanged(double)), spinBox, SLOT(setValue(double)));
        layout->addWidget(spinBox);
    
        layout->setAlignment(spinBox, Qt::AlignBottom | Qt::AlignRight);
    
        uas = NULL;
        resetMAVState();
    
    
        // Do first update
        setMetricWidth(metricWidth);
    
    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;
    
    
        // Setpoints
        positionSetPointKnown = false;
        setPointKnown = false;
    
    lm's avatar
    lm committed
    void HSIDisplay::paintEvent(QPaintEvent * event)
    {
        Q_UNUSED(event);
        //paintGL();
    
    //    static quint64 interval = 0;
    //    //qDebug() << "INTERVAL:" << MG::TIME::getGroundTimeNow() - interval << __FILE__ << __LINE__;
    //    interval = MG::TIME::getGroundTimeNow();
    
    lm's avatar
    lm committed
    }
    
    
    #if (QGC_EVENTLOOP_DEBUG)
        qDebug() << "EVENTLOOP:" << __FILE__ << __LINE__;
    #endif
    
        // Center location of the HSI gauge items
    
    
        //float bottomMargin = 3.0f;
    
    
        // Size of the ring instrument
    
        //const float margin = 0.1f;  // 10% margin of total width on each side
    
    pixhawk's avatar
    pixhawk committed
        float baseRadius = (vheight - topMargin - bottomMargin) / 2.0f - bottomMargin / 2.0f;
    
        // 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;
    
    
        painter.setRenderHint(QPainter::Antialiasing, true);
        painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
    
        // Draw base instrument
        // ----------------------
    
    lm's avatar
    lm committed
        painter.setBrush(Qt::NoBrush);
    
        const QColor ringColor = QColor(200, 250, 200);
    
    lm's avatar
    lm committed
        QPen pen;
        pen.setColor(ringColor);
        pen.setWidth(refLineWidthToPen(0.1f));
        painter.setPen(pen);
    
    lm's avatar
    lm committed
        const int ringCount = 2;
    
        for (int i = 0; i < ringCount; i++) {
    
            float radius = (vwidth - (topMargin + bottomMargin)*0.3f) / (1.3f * i+1) / 2.0f - bottomMargin / 2.0f;
    
            drawCircle(xCenterPos, yCenterPos, radius, 0.1f, ringColor, &painter);
    
    lm's avatar
    lm committed
        }
    
    
        // Draw orientation labels
        // Translate and rotate coordinate frame
        painter.translate((xCenterPos)*scalingFactor, (yCenterPos)*scalingFactor);
    
        const float yawDeg = ((yaw/M_PI)*180.0f);
        int yawRotate = static_cast<int>(yawDeg) % 360;
        painter.rotate(-yawRotate);
    
        paintText(tr("N"), ringColor, 3.5f, - 1.0f, - baseRadius - 5.5f, &painter);
        paintText(tr("S"), ringColor, 3.5f, - 1.0f, + baseRadius + 1.5f, &painter);
    
        paintText(tr("E"), ringColor, 3.5f, + baseRadius + 3.0f, - 1.25f, &painter);
    
        paintText(tr("W"), ringColor, 3.5f, - baseRadius - 5.5f, - 1.75f, &painter);
    
        painter.rotate(+yawRotate);
    
        painter.translate(-(xCenterPos)*scalingFactor, -(yCenterPos)*scalingFactor);
    
    
    lm's avatar
    lm committed
        // Draw center indicator
    
    //    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);
    
    
            // Translate to center
            painter.translate((xCenterPos)*scalingFactor, (yCenterPos)*scalingFactor);
            QColor uasColor = uas->getColor();
    
    lm's avatar
    lm committed
            //MAV2DIcon::drawAirframePolygon(uas->getAirframe(), painter, static_cast<int>((vwidth/4.0f)*scalingFactor*1.1f), uasColor, 0.0f);
    
            // Translate back
            painter.translate(-(xCenterPos)*scalingFactor, -(yCenterPos)*scalingFactor);
        }
    
    
        // ----------------------
    
        // Draw satellites
        drawGPS(painter);
    
    
        // Draw state indicator
    
        // Draw position
    
        QColor positionColor(20, 20, 200);
    
        drawPositionDirection(xCenterPos, yCenterPos, baseRadius, positionColor, &painter);
    
    
        // Draw attitude
        QColor attitudeColor(200, 20, 20);
    
        drawAttitudeDirection(xCenterPos, yCenterPos, baseRadius, attitudeColor, &painter);
    
        // Draw position setpoints in body coordinates
    
    lm's avatar
    lm committed
    
    
        if (userSetPointSet) {
    
            QColor spColor(150, 150, 150);
            drawSetpointXY(uiXSetCoordinate, uiYSetCoordinate, uiYawSet, spColor, painter);
        }
    
    
        if (positionSetPointKnown) {
    
            // Draw setpoint
    
            drawSetpointXY(bodyXSetCoordinate, bodyYSetCoordinate, bodyYawSet, QGC::colorCyan, painter);
    
            // Draw travel direction line
            QPointF m(bodyXSetCoordinate, bodyYSetCoordinate);
    
    lm's avatar
    lm committed
            // Transform from body to world coordinates
            m = metricWorldToBody(m);
            // Scale from metric body to screen reference units
    
    pixhawk's avatar
    pixhawk committed
            QPointF s = metricBodyToRef(m);
    
            drawLine(s.x(), s.y(), xCenterPos, yCenterPos, 1.5f, QGC::colorCyan, &painter);
    
        }
    
        // Labels on outer part and bottom
    
        // Draw waypoints
        drawWaypoints(painter);
    
        // Draw status flags
    
        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);
    
        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);
    
    
        // Draw speed to top left
        paintText(tr("SPEED"), QGC::colorCyan, 2.2f, 2, 11, &painter);
    
    pixhawk's avatar
    pixhawk committed
        paintText(tr("%1 m/s").arg(speed, 5, 'f', 2, '0'), Qt::white, 2.2f, 12, 11, &painter);
    
    
        // Draw crosstrack error to top right
        float crossTrackError = 0;
    
    pixhawk's avatar
    pixhawk committed
        paintText(tr("XTRACK"), QGC::colorCyan, 2.2f, 57, 11, &painter);
        paintText(tr("%1 m").arg(crossTrackError, 5, 'f', 2, '0'), Qt::white, 2.2f, 70, 11, &painter);
    
    
        // Draw position to bottom left
    
        if (localAvailable > 0 && globalAvailable == 0) {
    
            // Position
            QString str;
            str.sprintf("%05.2f %05.2f %05.2f m", x, y, z);
            paintText(tr("POS"), QGC::colorCyan, 2.6f, 2, vheight- 5.0f, &painter);
            paintText(str, Qt::white, 2.6f, 10, vheight - 5.0f, &painter);
        }
    
    
        if (globalAvailable > 0) {
    
            str.sprintf("lat: %05.2f lon: %06.2f alt: %06.2f", lat, lon, alt);
    
            paintText(tr("GPS"), QGC::colorCyan, 2.6f, 2, vheight- 5.0f, &painter);
            paintText(str, Qt::white, 2.6f, 10, vheight - 5.0f, &painter);
        }
    
        // Draw Field of view to bottom right
        paintText(tr("FOV"), QGC::colorCyan, 2.6f, 62, vheight- 5.0f, &painter);
    
    void HSIDisplay::drawStatusFlag(float x, float y, QString label, bool status, bool known, QPainter& painter)
    
        paintText(label, QGC::colorCyan, 2.6f, x, y+0.8f, &painter);
    
        QColor statusColor(250, 250, 250);
    
        if(status) {
    
    pixhawk's avatar
    pixhawk committed
            painter.setBrush(QGC::colorGreen);
    
            painter.setBrush(QGC::colorDarkYellow);
    
        }
        painter.setPen(Qt::NoPen);
    
    
        float indicatorWidth = refToScreenX(7.0f);
        float indicatorHeight = refToScreenY(4.0f);
    
        painter.drawRect(QRect(refToScreenX(x+7.3f), refToScreenY(y+0.05), indicatorWidth, indicatorHeight));
    
        paintText((status) ? tr("ON") : tr("OFF"), 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);
        }
    
    void HSIDisplay::drawPositionLock(float x, float y, QString label, int status, bool known, QPainter& painter)
    
        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);
        }
    
        // 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;
        }
    
        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);
        }
    
    lm's avatar
    lm committed
    void HSIDisplay::updatePositionLock(UASInterface* uas, bool lock)
    {
    
        Q_UNUSED(uas);
    
    lm's avatar
    lm committed
        positionLock = lock;
    }
    
    
    pixhawk's avatar
    pixhawk committed
    void HSIDisplay::updateAttitudeControllerEnabled(bool enabled)
    
    lm's avatar
    lm committed
    {
        attControlEnabled = enabled;
    
        attControlKnown = true;
    
    lm's avatar
    lm committed
    }
    
    
    pixhawk's avatar
    pixhawk committed
    void HSIDisplay::updatePositionXYControllerEnabled(bool enabled)
    
    lm's avatar
    lm committed
    {
        xyControlEnabled = enabled;
    
        xyControlKnown = true;
    
    lm's avatar
    lm committed
    }
    
    
    pixhawk's avatar
    pixhawk committed
    void HSIDisplay::updatePositionZControllerEnabled(bool enabled)
    
    lm's avatar
    lm committed
    {
        zControlEnabled = enabled;
    
        zControlKnown = true;
    
    lm's avatar
    lm committed
    }
    
    
    LM's avatar
    LM committed
    void HSIDisplay::updateObjectPosition(unsigned int time, int id, int type, const QString& name, int quality, float bearing, float distance)
    {
        // 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
    QPointF HSIDisplay::metricWorldToBody(QPointF world)
    {
        // First translate to body-centered coordinates
        // Rotate around -yaw
    
        float angle = -yaw - M_PI;
    
        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
        return result;
    }
    
    QPointF HSIDisplay::metricBodyToWorld(QPointF body)
    {
        // First rotate into world coordinates
        // then translate to world position
    
        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
        return result;
    
    QPointF HSIDisplay::screenToMetricBody(QPointF ref)
    {
    
    lm's avatar
    lm committed
        return QPointF(-((screenToRefY(ref.y()) - yCenterPos)/ vwidth) * metricWidth - x, ((screenToRefX(ref.x()) - xCenterPos) / vwidth) * metricWidth - y);
    
    }
    
    QPointF HSIDisplay::refToMetricBody(QPointF &ref)
    {
    
    lm's avatar
    lm committed
        return QPointF(-((ref.y() - yCenterPos)/ vwidth) * metricWidth - x, ((ref.x() - xCenterPos) / vwidth) * metricWidth - y);
    
    }
    
    /**
     * @see refToScreenX()
     */
    
    pixhawk's avatar
    pixhawk committed
    QPointF HSIDisplay::metricBodyToRef(QPointF &metric)
    
    {
        return QPointF(((metric.y())/ metricWidth) * vwidth + xCenterPos, ((-metric.x()) / metricWidth) * vwidth + yCenterPos);
    }
    
    
    pixhawk's avatar
    pixhawk committed
    QPointF HSIDisplay::metricBodyToScreen(QPointF metric)
    {
        QPointF ref = metricBodyToRef(metric);
        ref.setX(refToScreenX(ref.x()));
        ref.setY(refToScreenY(ref.y()));
        return ref;
    }
    
    
    void HSIDisplay::mouseDoubleClickEvent(QMouseEvent * event)
    {
        static bool dragStarted;
        static float startX;
    
    
        if (event->MouseButtonDblClick) {
    
            //setBodySetpointCoordinateXY(-refToMetric(screenToRefY(event->y()) - yCenterPos), refToMetric(screenToRefX(event->x()) - xCenterPos));
    
            QPointF p = screenToMetricBody(event->posF());
            setBodySetpointCoordinateXY(p.x(), p.y());
            qDebug() << "Double click at x: " << screenToRefX(event->x()) - xCenterPos << "y:" << screenToRefY(event->y()) - yCenterPos;
    
        } else if (event->MouseButtonPress) {
    
            startX = event->globalX();
    
            if (event->button() == Qt::RightButton) {
    
                // Start tracking mouse move
                dragStarted = true;
    
            } else if (event->button() == Qt::LeftButton) {
    
        } else if (event->MouseButtonRelease) {
    
            dragStarted = false;
    
        } else if (event->MouseMove) {
    
            if (dragStarted) uiYawSet += (startX - event->globalX()) / this->frameSize().width();
    
    pixhawk's avatar
    pixhawk committed
        }
    
    void HSIDisplay::setMetricWidth(double width)
    {
    
        if (width != metricWidth) {
    
            metricWidth = width;
            emit metricWidthChanged(metricWidth);
        }
    }
    
    
    /**
     *
     * @param uas the UAS/MAV to monitor/display with the HUD
     */
    void HSIDisplay::setActiveUAS(UASInterface* uas)
    {
    
        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)));
            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
            disconnect(this->uas, SIGNAL(objectDetected(uint,int,int,QString,int,float,float)), this, SLOT(updateObjectPosition(uint,int,int,QString,int,float,float)));
    
        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)));
        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)));
    
        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)));
    
        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
        connect(uas, SIGNAL(objectDetected(uint,int,int,QString,int,float,float)), this, SLOT(updateObjectPosition(uint,int,int,QString,int,float,float)));
    
        this->uas = uas;
    
        resetMAVState();
    
    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;
    
        this->speed = sqrt(pow(vx, 2.0) + pow(vy, 2.0) + pow(vz, 2.0));
    
    }
    
    void HSIDisplay::setBodySetpointCoordinateXY(double x, double y)
    {
        // Set coordinates and send them out to MAV
    
    
    lm's avatar
    lm committed
        QPointF sp(x, y);
        sp = metricBodyToWorld(sp);
        uiXSetCoordinate = sp.x();
        uiYSetCoordinate = sp.y();
    
    
    pixhawk's avatar
    pixhawk committed
        qDebug() << "Attempting to set new setpoint at x: " << x << "metric y:" << y;
    
    
        if (uas && mavInitialized) {
    
    pixhawk's avatar
    pixhawk committed
            uas->setLocalPositionSetpoint(uiXSetCoordinate, uiYSetCoordinate, uiZSetCoordinate, uiYawSet);
            qDebug() << "Setting new setpoint at x: " << x << "metric y:" << y;
        }
    
    }
    
    void HSIDisplay::setBodySetpointCoordinateZ(double z)
    {
        // Set coordinates and send them out to MAV
        uiZSetCoordinate = z;
    }
    
    void HSIDisplay::sendBodySetPointCoordinates()
    {
        // Send the coordinates to the MAV
    }
    
    
    void HSIDisplay::updateAttitudeSetpoints(UASInterface* uas, double rollDesired, double pitchDesired, double yawDesired, double thrustDesired, quint64 usec)
    
        Q_UNUSED(uas);
        Q_UNUSED(usec);
        attXSet = pitchDesired;
        attYSet = rollDesired;
        attYawSet = yawDesired;
        altitudeSet = thrustDesired;
    
    lm's avatar
    lm committed
    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;
    }
    
    
    lm's avatar
    lm committed
    void HSIDisplay::updatePositionSetpoints(int uasid, float xDesired, float yDesired, float zDesired, float yawDesired, quint64 usec)
    
        Q_UNUSED(usec);
        Q_UNUSED(uasid);
    
        bodyXSetCoordinate = xDesired;
        bodyYSetCoordinate = yDesired;
        bodyZSetCoordinate = zDesired;
        bodyYawSet = yawDesired;
    
    pixhawk's avatar
    pixhawk committed
        mavInitialized = true;
    
        setPointKnown = true;
    
        positionSetPointKnown = true;
    
        //    qDebug() << "Received setpoint at x: " << x << "metric y:" << y;
        //    posXSet = xDesired;
        //    posYSet = yDesired;
        //    posZSet = zDesired;
        //    posYawSet = yawDesired;
    
    }
    
    void HSIDisplay::updateLocalPosition(UASInterface*, double x, double y, double z, quint64 usec)
    {
    
        this->x = x;
        this->y = y;
        this->z = z;
        localAvailable = usec;
    
    }
    
    void HSIDisplay::updateGlobalPosition(UASInterface*, double lat, double lon, double alt, quint64 usec)
    {
    
        this->lat = lat;
        this->lon = lon;
        this->alt = alt;
        globalAvailable = usec;
    
    lm's avatar
    lm committed
    void HSIDisplay::updateSatellite(int uasid, int satid, float elevation, float azimuth, float snr, bool used)
    
    lm's avatar
    lm committed
    {
        Q_UNUSED(uasid);
    
    lm's avatar
    lm committed
        //qDebug() << "UPDATED SATELLITE";
    
    lm's avatar
    lm committed
        // If slot is empty, insert object
    
        if (gpsSatellites.contains(satid)) {
    
    lm's avatar
    lm committed
            gpsSatellites.value(satid)->update(satid, elevation, azimuth, snr, used);
    
    lm's avatar
    lm committed
            gpsSatellites.insert(satid, new GPSSatellite(satid, elevation, azimuth, snr, used));
    
    lm's avatar
    lm committed
        }
    }
    
    
    void HSIDisplay::updatePositionYawControllerEnabled(bool enabled)
    {
        yawControlEnabled = enabled;
    
        yawControlKnown = true;
    
    }
    
    /**
     * @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;
    
        positionFixKnown = true;
    
        //qDebug() << "LOCALIZATION FIX CALLED";
    
    }
    /**
     * @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;
    
        gpsFixKnown = true;
    
    }
    /**
     * @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;
    
        visionFixKnown = true;
    
        //qDebug() << "VISION FIX GOT CALLED";
    
    /**
     * @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;
    
        iruFixKnown = true;
    
    lm's avatar
    lm committed
    QColor HSIDisplay::getColorForSNR(float snr)
    {
    
    lm's avatar
    lm committed
        QColor color;
    
        if (snr > 0 && snr < 30) {
    
    lm's avatar
    lm committed
            color = QColor(250, 10, 10);
    
        } else if (snr >= 30 && snr < 35) {
    
    lm's avatar
    lm committed
            color = QColor(230, 230, 10);
    
        } else if (snr >= 35 && snr < 40) {
    
    lm's avatar
    lm committed
            color = QColor(90, 200, 90);
    
        } else if (snr >= 40) {
    
    lm's avatar
    lm committed
            color = QColor(20, 200, 20);
    
    lm's avatar
    lm committed
            color = QColor(180, 180, 180);
        }
        return color;
    
    lm's avatar
    lm committed
    }
    
    
    void HSIDisplay::drawSetpointXY(float x, float y, float yaw, const QColor &color, QPainter &painter)
    
        if (setPointKnown) {
    
            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(x, y);
            // Transform from body to world coordinates
            in = metricWorldToBody(in);
            // Scale from metric to screen reference coordinates
            QPointF p = metricBodyToRef(in);
            drawCircle(p.x(), p.y(), radius, 0.4f, color, &painter);
    
            drawLine(p.x(), p.y(), p.x()+sin(yaw) * radius, p.y()-cos(yaw) * radius, refLineWidthToPen(0.4f), color, &painter);
            painter.setBrush(color);
            drawCircle(p.x(), p.y(), radius * 0.1f, 0.1f, color, &painter);
        }
    
    void HSIDisplay::drawWaypoints(QPainter& painter)
    {
    
        if (uas) {
            const QVector<Waypoint*>& list = uas->getWaypointManager()->getWaypointList();
    
            //        for (int i = 0; i < list.size(); i++)
            //        {
            //            QPointF in(list.at(i)->getX(), list.at(i)->getY());
            //            // Transform from world to body coordinates
            //            in = metricWorldToBody(in);
            //            // Scale from metric to screen reference coordinates
            //            QPointF p = metricBodyToRef(in);
            //            Waypoint2DIcon* wp = new Waypoint2DIcon();
            //            wp->setLocalPosition(list.at(i)->getX(), list.at(i)->getY());
            //            wp->setPos(0, 0);
            //            scene()->addItem(wp);
            //        }
    
    
            QColor color;
            painter.setBrush(Qt::NoBrush);
    
            for (int i = 0; i < list.size(); i++) {
    
                QPointF in;
    
                if (list.at(i)->getFrame() == MAV_FRAME_LOCAL_NED)
                {
    
                    // Do not transform
                    in = QPointF(list.at(i)->getX(), list.at(i)->getY());
    
                    // Transform to local coordinates first
                    double x = list.at(i)->getX();
                    double y = list.at(i)->getY();
                    in = QPointF(x, y);
                }
    
                // Transform from world to body coordinates
                in = metricWorldToBody(in);
                // Scale from metric to screen reference coordinates
                QPointF p = metricBodyToRef(in);
    
    
                // Setup pen
                QPen pen(color);
                painter.setBrush(Qt::NoBrush);
    
                // DRAW WAYPOINT
                //drawCircle(p.x(), p.y(), radius, 0.4f, color, &painter);
                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()));
    
    
                // Select color based on if this is the current waypoint
    
                if (list.at(i)->getCurrent()) {
    
                    color = QGC::colorCyan;//uas->getColor();
                    pen.setWidthF(refLineWidthToPen(0.8f));
    
                    color = uas->getColor();
    
                    pen.setWidthF(refLineWidthToPen(0.4f));
    
                float radius = (waypointSize/2.0f) * 0.8 * (1/sqrt(2.0f));
    
                drawLine(p.x(), p.y(), p.x()+sin(list.at(i)->getYaw()+yaw) * radius, p.y()-cos(list.at(i)->getYaw()+yaw) * radius, refLineWidthToPen(0.4f), color, &painter);
    
                // Draw line from last waypoint to this one
    
                if (!lastWaypoint.isNull()) {
    
                    pen.setWidthF(refLineWidthToPen(0.4f));
                    painter.setPen(pen);
                    color = uas->getColor();
    
                    drawLine(lastWaypoint.x(), lastWaypoint.y(), p.x(), p.y(), refLineWidthToPen(0.4f), color, &painter);
                }
                lastWaypoint = p;
    
    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);
        painter.setPen(pen);
    
    pixhawk's avatar
    pixhawk committed
        painter.drawRect(QRectF(metricBodyToScreen(metricWorldToBody(topLeft)), metricBodyToScreen(metricWorldToBody(bottomRight))));
    
    lm's avatar
    lm committed
    
    
    void HSIDisplay::drawGPS(QPainter &painter)
    {
        float xCenter = xCenterPos;
        float yCenter = xCenterPos;
    
    lm's avatar
    lm committed
        // Max satellite circle radius
    
    
    lm's avatar
    lm committed
        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
    
    
    pixhawk's avatar
    pixhawk committed
        // 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
        QMapIterator<int, GPSSatellite*> i(gpsSatellites);
    
        while (i.hasNext()) {
    
    lm's avatar
    lm committed
            i.next();
            GPSSatellite* sat = i.value();
    
            // Check if update is not older than 5 seconds, else delete satellite
    
            if (sat->lastUpdate + 1000000 < currTime) {
    
    lm's avatar
    lm committed
                // Delete and go to next satellite
                gpsSatellites.remove(i.key());
    
                if (i.hasNext()) {
    
    lm's avatar
    lm committed
                    i.next();
                    sat = i.value();
    
    lm's avatar
    lm committed
                    continue;
                }
            }
    
    
    lm's avatar
    lm committed
                // Draw satellite
                QBrush brush;
                QColor color = getColorForSNR(sat->snr);
                brush.setColor(color);
    
                if (sat->used) {
    
    lm's avatar
    lm committed
                    brush.setStyle(Qt::SolidPattern);
    
    lm's avatar
    lm committed
                    brush.setStyle(Qt::NoBrush);
                }
                painter.setPen(Qt::SolidLine);
                painter.setPen(color);
                painter.setBrush(brush);
    
    
    lm's avatar
    lm committed
                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
    
    
                // Draw circle for satellite, filled for used satellites
    
    lm's avatar
    lm committed
                drawCircle(xPos, yPos, vwidth*0.02f, 1.0f, color, &painter);
    
                // Draw satellite PRN
    
    lm's avatar
    lm committed
                paintText(QString::number(sat->id), QColor(255, 255, 255), 2.9f, xPos+1.7f, yPos+2.0f, &painter);
    
    lm's avatar
    lm committed
            }
        }
    
    void HSIDisplay::drawObjects(QPainter &painter)
    
        Q_UNUSED(painter);
    
    void HSIDisplay::drawPositionDirection(float xRef, float yRef, float radius, const QColor& color, QPainter* painter)
    
        if (xyControlKnown && xyControlEnabled) {
    
            const float maxWidth = radius / 5.0f;
    
            const float minWidth = maxWidth * 0.3f;
    
            float angle = atan2(posXSet, -posYSet);
    
            angle -= (float)M_PI/2.0f;
    
            //radius *= ((posXSaturation + posYSaturation) - sqrt(pow(posXSet, 2), pow(posYSet, 2))) / (2*posXSaturation);
    
    lm's avatar
    lm committed
    
    
            radius *= sqrt(pow(posXSet, 2) + pow(posYSet, 2)) / sqrt(posXSaturation + posYSaturation);
    
    lm's avatar
    lm committed
    
    
            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));
    
            rotatePolygonClockWiseRad(p, angle, QPointF(xRef, yRef));
    
            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
    
    
            //qDebug() << "DRAWING POS SETPOINT X:" << posXSet << "Y:" << posYSet << angle;
        }
    
    void HSIDisplay::drawAttitudeDirection(float xRef, float yRef, float radius, const QColor& color, QPainter* painter)
    
        if (attControlKnown && attControlEnabled) {
    
            // Draw the needle
            const float maxWidth = radius / 10.0f;
            const float minWidth = maxWidth * 0.3f;
    
            float angle = atan2(attYSet, -attXSet);
    
    lm's avatar
    lm committed
    
    
            radius *= sqrt(attXSet*attXSet + attYSet*attYSet) / sqrt(attXSaturation*attXSaturation + attYSaturation*attYSaturation);
    
            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));