Waypoint2DIcon.cc 11.8 KB
Newer Older
1 2
#include "Waypoint2DIcon.h"
#include <QPainter>
3
#include "opmapcontrol.h"
lm's avatar
lm committed
4
#include "QGC.h"
5

Don Gagne's avatar
Don Gagne committed
6 7
Waypoint2DIcon::Waypoint2DIcon(mapcontrol::MapGraphicItem* map, mapcontrol::OPMapWidget* parent, qreal latitude, qreal longitude, qreal altitude, int listindex, QString name, int radius)
    : mapcontrol::WayPointItem(internals::PointLatLng(latitude, longitude), altitude, QString(), map),
8
    parent(parent),
9
    waypoint(),
10 11 12 13
    radius(radius),
    showAcceptanceRadius(true),
    showOrbit(false),
    color(Qt::red)
14
{
LM's avatar
LM committed
15 16
    Q_UNUSED(name);

17 18 19 20
    SetHeading(0);
    SetNumber(listindex);
    this->setFlag(QGraphicsItem::ItemIgnoresTransformations,true);
    picture = QPixmap(radius+1, radius+1);
lm's avatar
lm committed
21 22 23
    autoreachedEnabled = false; // In contrast to the use in OpenPilot, we don't
                                // want to let the map interfere with the actual mission logic
                                // wether a WP is reached depends solely on the UAV's state machine
24
    drawIcon();
25 26
}

27
Waypoint2DIcon::Waypoint2DIcon(mapcontrol::MapGraphicItem* map, mapcontrol::OPMapWidget* parent, MissionItem* wp, const QColor& color, int listindex, int radius)
Don Gagne's avatar
Don Gagne committed
28
    : mapcontrol::WayPointItem(internals::PointLatLng(wp->latitude(), wp->longitude()), wp->altitude(), QString(), map),
29 30 31 32 33 34
    parent(parent),
    waypoint(wp),
    radius(radius),
    showAcceptanceRadius(true),
    showOrbit(false),
    color(color)
35
{
Don Gagne's avatar
Don Gagne committed
36
    SetHeading(wp->yawRadians());
37 38 39
    SetNumber(listindex);
    this->setFlag(QGraphicsItem::ItemIgnoresTransformations,true);
    picture = QPixmap(radius+1, radius+1);
lm's avatar
lm committed
40 41 42
    autoreachedEnabled = false; // In contrast to the use in OpenPilot, we don't
                                // want to let the map interfere with the actual mission logic
                                // wether a WP is reached depends solely on the UAV's state machine
43
    updateWaypoint();
44 45
}

46
Waypoint2DIcon::~Waypoint2DIcon()
47 48 49
{
}

50
void Waypoint2DIcon::SetHeading(float heading)
51
{
52 53
    mapcontrol::WayPointItem::SetHeading(heading);
    drawIcon();
54 55
}

56 57
void Waypoint2DIcon::updateWaypoint()
{
58
    if (!waypoint.isNull()) {
59 60 61
        // Store old size
        static QRectF oldSize;

Don Gagne's avatar
Don Gagne committed
62
        SetHeading(waypoint->yawRadians());
Don Gagne's avatar
Don Gagne committed
63
        SetCoord(internals::PointLatLng(waypoint->latitude(), waypoint->longitude()));
64

Don Gagne's avatar
Don Gagne committed
65
        // qDebug() << "UPDATING WP:" << waypoint->sequenceNumber() << "LAT:" << waypoint->latitude() << "LON:" << waypoint->longitude();
66

Don Gagne's avatar
Don Gagne committed
67
        SetAltitude(waypoint->altitude());
68 69
        // FIXME Add SetNumber (currently needs a separate call)
        drawIcon();
70 71
        QRectF newSize = boundingRect();

72
        // qDebug() << "WIDTH" << newSize.width() << "<" << oldSize.width();
73 74 75 76 77 78 79 80 81

        // If new size is smaller than old size, update surrounding
        if ((newSize.width() <= oldSize.width()) || (newSize.height() <= oldSize.height()))
        {
            // If the symbol size was reduced, enforce an update of the environment
//            update(oldSize);
            int oldWidth = oldSize.width() + 20;
            int oldHeight = oldSize.height() + 20;
            map->update(this->x()-10, this->y()-10, oldWidth, oldHeight);
82 83
            //// qDebug() << "UPDATING DUE TO SMALLER SIZE";
            //// qDebug() << "X:" << this->x()-1 << "Y:" << this->y()-1 << "WIDTH:" << oldWidth << "HEIGHT:" << oldHeight;
84 85 86 87 88 89 90
        }
        else
        {
            // Symbol size stayed constant or increased, use new size for update
            this->update();
        }
        oldSize = boundingRect();
91 92 93 94 95 96 97 98
    }
}

QRectF Waypoint2DIcon::boundingRect() const
{
    int loiter = 0;
    int acceptance = 0;
    internals::PointLatLng coord = (internals::PointLatLng)Coord();
99 100

    if (!waypoint.isNull()) {
Don Gagne's avatar
Don Gagne committed
101
        if (showAcceptanceRadius && (waypoint->command() == (int)MAV_CMD_NAV_WAYPOINT))
102
        {
Don Gagne's avatar
Don Gagne committed
103
            acceptance = map->metersToPixels(waypoint->acceptanceRadius(), coord);
104
        }
Don Gagne's avatar
Don Gagne committed
105
        if (((waypoint->command() == (int)MAV_CMD_NAV_LOITER_UNLIM) || (waypoint->command() == (int)MAV_CMD_NAV_LOITER_TIME) || (waypoint->command() == (int)MAV_CMD_NAV_LOITER_TURNS)))
106
        {
Don Gagne's avatar
Don Gagne committed
107
            loiter = map->metersToPixels(waypoint->loiterOrbitRadius(), coord);
108
        }
109 110 111 112 113 114
    }

    int width = qMax(picture.width()/2, qMax(loiter, acceptance));
    int height = qMax(picture.height()/2, qMax(loiter, acceptance));

    return QRectF(-width,-height,2*width,2*height);
115 116
}

117
void Waypoint2DIcon::drawIcon()
118
{
119 120
    picture.fill(Qt::transparent);
    QPainter painter(&picture);
121 122 123
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setRenderHint(QPainter::HighQualityAntialiasing, true);

lm's avatar
lm committed
124 125 126 127 128 129 130 131 132 133 134
    QFont font("Bitstream Vera Sans");
    int fontSize = picture.height()*0.8f;
    font.setPixelSize(fontSize);

    QFontMetrics metrics = QFontMetrics(font);
    int border = qMax(4, metrics.leading());
    painter.setFont(font);
    painter.setRenderHint(QPainter::TextAntialiasing);



135 136 137 138 139
    QPen pen1(Qt::black);
    pen1.setWidth(4);
    QPen pen2(color);
    pen2.setWidth(2);
    painter.setBrush(Qt::NoBrush);
140

lm's avatar
lm committed
141 142
    int penWidth = pen1.width();

143
    // DRAW WAYPOINT
144
    QPointF p(picture.width()/2, picture.height()/2);
145 146 147

    QPolygonF poly(4);
    // Top point
lm's avatar
lm committed
148
    poly.replace(0, QPointF(p.x(), p.y()-picture.height()/2.0f+penWidth/2));
149
    // Right point
lm's avatar
lm committed
150
    poly.replace(1, QPointF(p.x()+picture.width()/2.0f-penWidth/2, p.y()));
151
    // Bottom point
lm's avatar
lm committed
152 153
    poly.replace(2, QPointF(p.x(), p.y() + picture.height()/2.0f-penWidth/2));
    poly.replace(3, QPointF(p.x() - picture.width()/2.0f+penWidth/2, p.y()));
154

155
    int waypointSize = qMin(picture.width(), picture.height());
156
    float rad = (waypointSize/2.0f) * 0.7f * (1/sqrt(2.0f));
157 158 159 160

    // If this is not a waypoint (only the default representation)
    // or it is a waypoint, but not one where direction has no meaning
    // then draw the heading indicator
161
    if (waypoint.isNull() || (waypoint && (
Don Gagne's avatar
Don Gagne committed
162 163 164 165 166 167
            (waypoint->command() != (int)MAV_CMD_NAV_TAKEOFF) &&
            (waypoint->command() != (int)MAV_CMD_NAV_LAND) &&
            (waypoint->command() != (int)MAV_CMD_NAV_LOITER_UNLIM) &&
            (waypoint->command() != (int)MAV_CMD_NAV_LOITER_TIME) &&
            (waypoint->command() != (int)MAV_CMD_NAV_LOITER_TURNS) &&
            (waypoint->command() != (int)MAV_CMD_NAV_RETURN_TO_LAUNCH)
168 169
            )))
    {
170 171 172 173
        painter.setPen(pen1);
        painter.drawLine(p.x(), p.y(), p.x()+sin(Heading()/180.0f*M_PI) * rad, p.y()-cos(Heading()/180.0f*M_PI) * rad);
        painter.setPen(pen2);
        painter.drawLine(p.x(), p.y(), p.x()+sin(Heading()/180.0f*M_PI) * rad, p.y()-cos(Heading()/180.0f*M_PI) * rad);
174 175
    }

Don Gagne's avatar
Don Gagne committed
176
    if (((!waypoint.isNull())) && (waypoint->command() == (int)MAV_CMD_NAV_TAKEOFF))
177 178
    {
        // Takeoff waypoint
lm's avatar
lm committed
179 180 181 182 183 184 185 186 187 188 189 190
        int width = picture.width()-penWidth;
        int height = picture.height()-penWidth;

        painter.setPen(pen1);
        painter.drawRect(penWidth/2, penWidth/2, width, height);
        painter.setPen(pen2);
        painter.drawRect(penWidth/2, penWidth/2, width, height);

        painter.setPen(pen1);
        painter.drawRect(width*0.3, height*0.3f, width*0.6f, height*0.6f);
        painter.setPen(pen2);
        painter.drawRect(width*0.3, height*0.3f, width*0.6f, height*0.6f);
191
    }
Don Gagne's avatar
Don Gagne committed
192
    else if (((!waypoint.isNull())) && (waypoint->command() == (int)MAV_CMD_NAV_LAND))
193 194
    {
        // Landing waypoint
lm's avatar
lm committed
195 196
        int width = (picture.width())/2-penWidth;
        int height = (picture.height())/2-penWidth;
197 198
        painter.setPen(pen1);
        painter.drawEllipse(p, width, height);
lm's avatar
lm committed
199
        painter.drawLine(p.x()-width/2, p.y()-height/2, 2*width, 2*height);
200
        painter.setPen(pen2);
201
        painter.drawEllipse(p, width, height);
lm's avatar
lm committed
202
        painter.drawLine(p.x()-width/2, p.y()-height/2, 2*width, 2*height);
203
    }
Don Gagne's avatar
Don Gagne committed
204
    else if (((!waypoint.isNull())) && ((waypoint->command() == (int)MAV_CMD_NAV_LOITER_UNLIM) || (waypoint->command() == (int)MAV_CMD_NAV_LOITER_TIME) || (waypoint->command() == (int)MAV_CMD_NAV_LOITER_TURNS)))
205 206
    {
        // Loiter waypoint
lm's avatar
lm committed
207 208
        int width = (picture.width()-penWidth)/2;
        int height = (picture.height()-penWidth)/2;
209 210 211 212
        painter.setPen(pen1);
        painter.drawEllipse(p, width, height);
        painter.drawPoint(p);
        painter.setPen(pen2);
213
        painter.drawEllipse(p, width, height);
214 215
        painter.drawPoint(p);
    }
Don Gagne's avatar
Don Gagne committed
216
    else if (((!waypoint.isNull())) && (waypoint->command() == (int)MAV_CMD_NAV_RETURN_TO_LAUNCH))
217 218
    {
        // Return to launch waypoint
lm's avatar
lm committed
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
        int width = picture.width()-penWidth;
        int height = picture.height()-penWidth;
        painter.setPen(pen1);
        painter.drawRect(penWidth/2, penWidth/2, width, height);
        painter.setPen(pen2);
        painter.drawRect(penWidth/2, penWidth/2, width, height);

        QString text("R");

        painter.setPen(pen1);
        QRect rect = metrics.boundingRect(0, 0, width - 2*border, height, Qt::AlignLeft | Qt::TextWordWrap, text);
        painter.drawText(width/4, height/6, rect.width(), rect.height(),
                          Qt::AlignCenter | Qt::TextWordWrap, text);
        painter.setPen(pen2);

        font.setPixelSize(fontSize*0.85f);
        painter.setFont(font);
        painter.drawText(width/4, height/6, rect.width(), rect.height(), Qt::AlignCenter | Qt::TextWordWrap, text);
237 238 239 240
    }
    else
    {
        // Navigation waypoint
241 242 243
        painter.setPen(pen1);
        painter.drawPolygon(poly);
        painter.setPen(pen2);
244 245 246 247
        painter.drawPolygon(poly);
    }
}

lm's avatar
lm committed
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
void Waypoint2DIcon::SetShowNumber(const bool &value)
{
    shownumber=value;
    if((numberI==0) && value)
    {
        numberI=new QGraphicsSimpleTextItem(this);
        numberIBG=new QGraphicsRectItem(this);
        numberIBG->setBrush(Qt::black);
        numberIBG->setOpacity(0.5);
        numberI->setZValue(3);
        numberI->setPen(QPen(QGC::colorCyan));
        numberI->setPos(5,-picture.height());
        numberIBG->setPos(5,-picture.height());
        numberI->setText(QString::number(number));
        numberIBG->setRect(numberI->boundingRect().adjusted(-2,0,1,0));
    }
    else if (!value && numberI)
    {
        delete numberI;
        delete numberIBG;
    }
    this->update();
}

272 273 274 275
void Waypoint2DIcon::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
276 277
    QPen pen = painter->pen();
    pen.setWidth(2);
278 279 280
    painter->drawPixmap(-picture.width()/2,-picture.height()/2,picture);
    if (this->isSelected())
    {
281
        pen.setColor(Qt::yellow);
282 283 284
        painter->drawRect(QRectF(-picture.width()/2,-picture.height()/2,picture.width()-1,picture.height()-1));
    }

285 286
    QPen penBlack(Qt::black);
    penBlack.setWidth(4);
287 288
    pen.setColor(color);

Don Gagne's avatar
Don Gagne committed
289
    if ((!waypoint.isNull()) && (waypoint->command() == (int)MAV_CMD_NAV_WAYPOINT) && showAcceptanceRadius)
290 291
    {
        QPen redPen = QPen(pen);
292
        redPen.setColor(Qt::yellow);
lm's avatar
lm committed
293
        redPen.setWidth(1);
294
        painter->setPen(redPen);
Don Gagne's avatar
Don Gagne committed
295
        const int acceptance = map->metersToPixels(waypoint->acceptanceRadius(), Coord());
296 297 298 299 300 301
        if (acceptance > 0) {
            painter->setPen(penBlack);
            painter->drawEllipse(QPointF(0, 0), acceptance, acceptance);
            painter->setPen(redPen);
            painter->drawEllipse(QPointF(0, 0), acceptance, acceptance);
        }
302
    }
Don Gagne's avatar
Don Gagne committed
303
    if ((!waypoint.isNull()) && ((waypoint->command() == (int)MAV_CMD_NAV_LOITER_UNLIM) || (waypoint->command() == (int)MAV_CMD_NAV_LOITER_TIME) || (waypoint->command() == (int)MAV_CMD_NAV_LOITER_TURNS)))
304
    {
305 306 307
        QPen penDash(color);
        penDash.setWidth(1);
        //penDash.setStyle(Qt::DotLine);
Lorenz Meier's avatar
Lorenz Meier committed
308
        // A negative radius indicates counter-clockwise rotation, but we still want to draw it positive
Don Gagne's avatar
Don Gagne committed
309
        const int loiter = map->metersToPixels(fabs(waypoint->loiterOrbitRadius()), Coord());
310 311 312 313 314 315 316
        if (loiter > picture.width()/2)
        {
            painter->setPen(penBlack);
            painter->drawEllipse(QPointF(0, 0), loiter, loiter);
            painter->setPen(penDash);
            painter->drawEllipse(QPointF(0, 0), loiter, loiter);
        }
317
    }
318
}