QGCMapPolygon.cc 18.8 KB
Newer Older
1 2
/****************************************************************************
 *
Gus Grubba's avatar
Gus Grubba committed
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8 9 10 11
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

#include "QGCMapPolygon.h"
#include "QGCGeo.h"
12
#include "JsonHelper.h"
13
#include "QGCQGeoCoordinate.h"
DonLakeFlyer's avatar
DonLakeFlyer committed
14
#include "QGCApplication.h"
15
#include "ShapeFileHelper.h"
16
#include "QGCLoggingCategory.h"
17 18 19

#include <QGeoRectangle>
#include <QDebug>
20
#include <QJsonArray>
21
#include <QLineF>
DonLakeFlyer's avatar
DonLakeFlyer committed
22 23
#include <QFile>
#include <QDomDocument>
24

25
const char* QGCMapPolygon::jsonPolygonKey = "polygon";
26

27 28 29 30 31 32
QGCMapPolygon::QGCMapPolygon(QObject* parent)
    : QObject               (parent)
    , _dirty                (false)
    , _centerDrag           (false)
    , _ignoreCenterUpdates  (false)
    , _interactive          (false)
Don Gagne's avatar
Don Gagne committed
33
    , _resetActive          (false)
34 35 36 37 38 39 40 41 42 43
{
    _init();
}

QGCMapPolygon::QGCMapPolygon(const QGCMapPolygon& other, QObject* parent)
    : QObject               (parent)
    , _dirty                (false)
    , _centerDrag           (false)
    , _ignoreCenterUpdates  (false)
    , _interactive          (false)
Don Gagne's avatar
Don Gagne committed
44
    , _resetActive          (false)
45 46 47 48 49 50 51
{
    *this = other;

    _init();
}

void QGCMapPolygon::_init(void)
52
{
53 54
    connect(&_polygonModel, &QmlObjectListModel::dirtyChanged, this, &QGCMapPolygon::_polygonModelDirtyChanged);
    connect(&_polygonModel, &QmlObjectListModel::countChanged, this, &QGCMapPolygon::_polygonModelCountChanged);
DonLakeFlyer's avatar
DonLakeFlyer committed
55 56 57 58

    connect(this, &QGCMapPolygon::pathChanged,  this, &QGCMapPolygon::_updateCenter);
    connect(this, &QGCMapPolygon::countChanged, this, &QGCMapPolygon::isValidChanged);
    connect(this, &QGCMapPolygon::countChanged, this, &QGCMapPolygon::isEmptyChanged);
59 60
}

61 62 63 64 65
const QGCMapPolygon& QGCMapPolygon::operator=(const QGCMapPolygon& other)
{
    clear();

    QVariantList vertices = other.path();
DonLakeFlyer's avatar
DonLakeFlyer committed
66
    QList<QGeoCoordinate> rgCoord;
67
    for (const QVariant& vertexVar: vertices) {
DonLakeFlyer's avatar
DonLakeFlyer committed
68
        rgCoord.append(vertexVar.value<QGeoCoordinate>());
69
    }
DonLakeFlyer's avatar
DonLakeFlyer committed
70
    appendVertices(rgCoord);
71 72 73 74 75 76

    setDirty(true);

    return *this;
}

77 78 79 80 81 82 83 84 85 86 87 88 89 90
void QGCMapPolygon::clear(void)
{
    // Bug workaround, see below
    while (_polygonPath.count() > 1) {
        _polygonPath.takeLast();
    }
    emit pathChanged();

    // Although this code should remove the polygon from the map it doesn't. There appears
    // to be a bug in QGCMapPolygon which causes it to not be redrawn if the list is empty. So
    // we work around it by using the code above to remove all but the last point which in turn
    // will cause the polygon to go away.
    _polygonPath.clear();

91 92
    _polygonModel.clearAndDeleteContents();

93 94
    emit cleared();

95 96 97
    setDirty(true);
}

98
void QGCMapPolygon::adjustVertex(int vertexIndex, const QGeoCoordinate coordinate)
99 100
{
    _polygonPath[vertexIndex] = QVariant::fromValue(coordinate);
101
    _polygonModel.value<QGCQGeoCoordinate*>(vertexIndex)->setCoordinate(coordinate);
DonLakeFlyer's avatar
DonLakeFlyer committed
102
    if (!_centerDrag) {
103
        // When dragging center we don't signal path changed until all vertices are updated
DonLakeFlyer's avatar
DonLakeFlyer committed
104 105
        emit pathChanged();
    }
106 107 108 109 110 111 112
    setDirty(true);
}

void QGCMapPolygon::setDirty(bool dirty)
{
    if (_dirty != dirty) {
        _dirty = dirty;
113 114 115
        if (!dirty) {
            _polygonModel.setDirty(false);
        }
116 117 118 119
        emit dirtyChanged(dirty);
    }
}

120
QGeoCoordinate QGCMapPolygon::_coordFromPointF(const QPointF& point) const
121
{
122 123 124 125 126 127
    QGeoCoordinate coord;

    if (_polygonPath.count() > 0) {
        QGeoCoordinate tangentOrigin = _polygonPath[0].value<QGeoCoordinate>();
        convertNedToGeo(-point.y(), point.x(), 0, tangentOrigin, &coord);
    }
128

129 130
    return coord;
}
131

132 133 134
QPointF QGCMapPolygon::_pointFFromCoord(const QGeoCoordinate& coordinate) const
{
    if (_polygonPath.count() > 0) {
135
        double y, x, down;
136
        QGeoCoordinate tangentOrigin = _polygonPath[0].value<QGeoCoordinate>();
137

138 139
        convertGeoToNed(coordinate, tangentOrigin, &y, &x, &down);
        return QPointF(x, -y);
140 141
    }

142 143
    return QPointF();
}
144

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
QPolygonF QGCMapPolygon::_toPolygonF(void) const
{
    QPolygonF polygon;

    if (_polygonPath.count() > 2) {
        for (int i=0; i<_polygonPath.count(); i++) {
            polygon.append(_pointFFromCoord(_polygonPath[i].value<QGeoCoordinate>()));
        }
    }

    return polygon;
}

bool QGCMapPolygon::containsCoordinate(const QGeoCoordinate& coordinate) const
{
    if (_polygonPath.count() > 2) {
        return _toPolygonF().containsPoint(_pointFFromCoord(coordinate), Qt::OddEvenFill);
    } else {
        return false;
    }
}

167 168 169
void QGCMapPolygon::setPath(const QList<QGeoCoordinate>& path)
{
    _polygonPath.clear();
170
    _polygonModel.clearAndDeleteContents();
171
    for(const QGeoCoordinate& coord: path) {
172
        _polygonPath.append(QVariant::fromValue(coord));
173
        _polygonModel.append(new QGCQGeoCoordinate(coord, this));
174
    }
175

176 177 178 179 180 181 182
    setDirty(true);
    emit pathChanged();
}

void QGCMapPolygon::setPath(const QVariantList& path)
{
    _polygonPath = path;
183 184 185

    _polygonModel.clearAndDeleteContents();
    for (int i=0; i<_polygonPath.count(); i++) {
186
        _polygonModel.append(new QGCQGeoCoordinate(_polygonPath[i].value<QGeoCoordinate>(), this));
187 188
    }

189 190 191
    setDirty(true);
    emit pathChanged();
}
192 193 194

void QGCMapPolygon::saveToJson(QJsonObject& json)
{
195
    QJsonValue jsonValue;
196

197
    JsonHelper::saveGeoCoordinateArray(_polygonPath, false /* writeAltitude*/, jsonValue);
198
    json.insert(jsonPolygonKey, jsonValue);
199 200 201 202 203 204 205 206 207
    setDirty(false);
}

bool QGCMapPolygon::loadFromJson(const QJsonObject& json, bool required, QString& errorString)
{
    errorString.clear();
    clear();

    if (required) {
208
        if (!JsonHelper::validateRequiredKeys(json, QStringList(jsonPolygonKey), errorString)) {
209 210
            return false;
        }
211
    } else if (!json.contains(jsonPolygonKey)) {
212 213 214
        return true;
    }

215
    if (!JsonHelper::loadGeoCoordinateArray(json[jsonPolygonKey], false /* altitudeRequired */, _polygonPath, errorString)) {
216 217
        return false;
    }
218 219

    for (int i=0; i<_polygonPath.count(); i++) {
220
        _polygonModel.append(new QGCQGeoCoordinate(_polygonPath[i].value<QGeoCoordinate>(), this));
221 222
    }

223
    setDirty(false);
224
    emit pathChanged();
225 226 227 228

    return true;
}

229 230 231 232
QList<QGeoCoordinate> QGCMapPolygon::coordinateList(void) const
{
    QList<QGeoCoordinate> coords;

233 234
    for (int i=0; i<_polygonPath.count(); i++) {
        coords.append(_polygonPath[i].value<QGeoCoordinate>());
235 236 237 238
    }

    return coords;
}
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265

void QGCMapPolygon::splitPolygonSegment(int vertexIndex)
{
    int nextIndex = vertexIndex + 1;
    if (nextIndex > _polygonPath.length() - 1) {
        nextIndex = 0;
    }

    QGeoCoordinate firstVertex = _polygonPath[vertexIndex].value<QGeoCoordinate>();
    QGeoCoordinate nextVertex = _polygonPath[nextIndex].value<QGeoCoordinate>();

    double distance = firstVertex.distanceTo(nextVertex);
    double azimuth = firstVertex.azimuthTo(nextVertex);
    QGeoCoordinate newVertex = firstVertex.atDistanceAndAzimuth(distance / 2, azimuth);

    if (nextIndex == 0) {
        appendVertex(newVertex);
    } else {
        _polygonModel.insert(nextIndex, new QGCQGeoCoordinate(newVertex, this));
        _polygonPath.insert(nextIndex, QVariant::fromValue(newVertex));
        emit pathChanged();
    }
}

void QGCMapPolygon::appendVertex(const QGeoCoordinate& coordinate)
{
    _polygonPath.append(QVariant::fromValue(coordinate));
266
    _polygonModel.append(new QGCQGeoCoordinate(coordinate, this));
267 268 269
    emit pathChanged();
}

270 271 272 273
void QGCMapPolygon::appendVertices(const QList<QGeoCoordinate>& coordinates)
{
    QList<QObject*> objects;

Don Gagne's avatar
Don Gagne committed
274
    _beginResetIfNotActive();
275
    for (const QGeoCoordinate& coordinate: coordinates) {
276 277 278 279
        objects.append(new QGCQGeoCoordinate(coordinate, this));
        _polygonPath.append(QVariant::fromValue(coordinate));
    }
    _polygonModel.append(objects);
Don Gagne's avatar
Don Gagne committed
280 281
    _endResetIfNotActive();

282 283 284
    emit pathChanged();
}

285 286 287 288 289 290 291 292 293
void QGCMapPolygon::appendVertices(const QVariantList& varCoords)
{
    QList<QGeoCoordinate> rgCoords;
    for (const QVariant& varCoord: varCoords) {
        rgCoords.append(varCoord.value<QGeoCoordinate>());
    }
    appendVertices(rgCoords);
}

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
void QGCMapPolygon::_polygonModelDirtyChanged(bool dirty)
{
    if (dirty) {
        setDirty(true);
    }
}

void QGCMapPolygon::removeVertex(int vertexIndex)
{
    if (vertexIndex < 0 && vertexIndex > _polygonPath.length() - 1) {
        qWarning() << "Call to removePolygonCoordinate with bad vertexIndex:count" << vertexIndex << _polygonPath.length();
        return;
    }

    if (_polygonPath.length() <= 3) {
        // Don't allow the user to trash the polygon
        return;
    }

    QObject* coordObj = _polygonModel.removeAt(vertexIndex);
    coordObj->deleteLater();
315 316 317 318 319
    if(vertexIndex == _selectedVertexIndex) {
        selectVertex(-1);
    } else if (vertexIndex < _selectedVertexIndex) {
        selectVertex(_selectedVertexIndex - 1);
    } // else do nothing - keep current selected vertex
320 321 322 323 324 325 326 327 328

    _polygonPath.removeAt(vertexIndex);
    emit pathChanged();
}

void QGCMapPolygon::_polygonModelCountChanged(int count)
{
    emit countChanged(count);
}
329 330 331 332 333 334

void QGCMapPolygon::_updateCenter(void)
{
    if (!_ignoreCenterUpdates) {
        QGeoCoordinate center;

335
        if (_polygonPath.count() > 2) {
Don Gagne's avatar
Don Gagne committed
336 337 338 339 340 341
            QPointF centroid(0, 0);
            QPolygonF polygonF = _toPolygonF();
            for (int i=0; i<polygonF.count(); i++) {
                centroid += polygonF[i];
            }
            center = _coordFromPointF(QPointF(centroid.x() / polygonF.count(), centroid.y() / polygonF.count()));
342
        }
Don Gagne's avatar
Don Gagne committed
343 344 345 346
        if (_center != center) {
            _center = center;
            emit centerChanged(center);
        }
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
    }
}

void QGCMapPolygon::setCenter(QGeoCoordinate newCenter)
{
    if (newCenter != _center) {
        _ignoreCenterUpdates = true;

        // Adjust polygon vertices to new center
        double distance = _center.distanceTo(newCenter);
        double azimuth = _center.azimuthTo(newCenter);

        for (int i=0; i<count(); i++) {
            QGeoCoordinate oldVertex = _polygonPath[i].value<QGeoCoordinate>();
            QGeoCoordinate newVertex = oldVertex.atDistanceAndAzimuth(distance, azimuth);
            adjustVertex(i, newVertex);
        }

DonLakeFlyer's avatar
DonLakeFlyer committed
365
        if (_centerDrag) {
366
            // When center dragging, signals from adjustVertext are not sent. So we need to signal here when all adjusting is complete.
DonLakeFlyer's avatar
DonLakeFlyer committed
367 368 369
            emit pathChanged();
        }

370
        _ignoreCenterUpdates = false;
DonLakeFlyer's avatar
DonLakeFlyer committed
371 372 373 374 375 376 377 378 379 380 381

        _center = newCenter;
        emit centerChanged(newCenter);
    }
}

void QGCMapPolygon::setCenterDrag(bool centerDrag)
{
    if (centerDrag != _centerDrag) {
        _centerDrag = centerDrag;
        emit centerDragChanged(centerDrag);
382 383
    }
}
384 385 386 387 388 389 390 391

void QGCMapPolygon::setInteractive(bool interactive)
{
    if (_interactive != interactive) {
        _interactive = interactive;
        emit interactiveChanged(interactive);
    }
}
392 393 394 395 396 397

QGeoCoordinate QGCMapPolygon::vertexCoordinate(int vertex) const
{
    if (vertex >= 0 && vertex < _polygonPath.count()) {
        return _polygonPath[vertex].value<QGeoCoordinate>();
    } else {
DonLakeFlyer's avatar
DonLakeFlyer committed
398
        qWarning() << "QGCMapPolygon::vertexCoordinate bad vertex requested:count" << vertex << _polygonPath.count();
399 400 401
        return QGeoCoordinate();
    }
}
402

403
QList<QPointF> QGCMapPolygon::nedPolygon(void) const
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
{
    QList<QPointF>  nedPolygon;

    if (count() > 0) {
        QGeoCoordinate  tangentOrigin = vertexCoordinate(0);

        for (int i=0; i<_polygonModel.count(); i++) {
            double y, x, down;
            QGeoCoordinate vertex = vertexCoordinate(i);
            if (i == 0) {
                // This avoids a nan calculation that comes out of convertGeoToNed
                x = y = 0;
            } else {
                convertGeoToNed(vertex, tangentOrigin, &y, &x, &down);
            }
            nedPolygon += QPointF(x, y);
        }
    }

    return nedPolygon;
}


void QGCMapPolygon::offset(double distance)
{
    QList<QGeoCoordinate> rgNewPolygon;

    // I'm sure there is some beautiful famous algorithm to do this, but here is a brute force method

    if (count() > 2) {
        // Convert the polygon to NED
        QList<QPointF> rgNedVertices = nedPolygon();

        // Walk the edges, offsetting by the specified distance
        QList<QLineF> rgOffsetEdges;
        for (int i=0; i<rgNedVertices.count(); i++) {
            int     lastIndex = i == rgNedVertices.count() - 1 ? 0 : i + 1;
            QLineF  offsetEdge;
            QLineF  originalEdge(rgNedVertices[i], rgNedVertices[lastIndex]);

            QLineF workerLine = originalEdge;
            workerLine.setLength(distance);
            workerLine.setAngle(workerLine.angle() - 90.0);
            offsetEdge.setP1(workerLine.p2());

            workerLine.setPoints(originalEdge.p2(), originalEdge.p1());
            workerLine.setLength(distance);
            workerLine.setAngle(workerLine.angle() + 90.0);
            offsetEdge.setP2(workerLine.p2());

            rgOffsetEdges.append(offsetEdge);
        }

        // Intersect the offset edges to generate new vertices
        QPointF         newVertex;
        QGeoCoordinate  tangentOrigin = vertexCoordinate(0);
        for (int i=0; i<rgOffsetEdges.count(); i++) {
            int prevIndex = i == 0 ? rgOffsetEdges.count() - 1 : i - 1;
462 463 464 465 466 467
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
            auto intersect = rgOffsetEdges[prevIndex].intersect(rgOffsetEdges[i], &newVertex);
#else
            auto intersect = rgOffsetEdges[prevIndex].intersects(rgOffsetEdges[i], &newVertex);
#endif
            if (intersect == QLineF::NoIntersection) {
468 469 470 471 472 473 474 475 476 477 478
                // FIXME: Better error handling?
                qWarning("Intersection failed");
                return;
            }
            QGeoCoordinate coord;
            convertNedToGeo(newVertex.y(), newVertex.x(), 0, tangentOrigin, &coord);
            rgNewPolygon.append(coord);
        }
    }

    // Update internals
Don Gagne's avatar
Don Gagne committed
479
    _beginResetIfNotActive();
480
    clear();
DonLakeFlyer's avatar
DonLakeFlyer committed
481
    appendVertices(rgNewPolygon);
Don Gagne's avatar
Don Gagne committed
482
    _endResetIfNotActive();
483
}
DonLakeFlyer's avatar
DonLakeFlyer committed
484

485
bool QGCMapPolygon::loadKMLOrSHPFile(const QString& file)
DonLakeFlyer's avatar
DonLakeFlyer committed
486
{
487
    QString errorString;
DonLakeFlyer's avatar
DonLakeFlyer committed
488
    QList<QGeoCoordinate> rgCoords;
489
    if (!ShapeFileHelper::loadPolygonFromFile(file, rgCoords, errorString)) {
490
        qgcApp()->showAppMessage(errorString);
491
        return false;
DonLakeFlyer's avatar
DonLakeFlyer committed
492 493
    }

Don Gagne's avatar
Don Gagne committed
494
    _beginResetIfNotActive();
DonLakeFlyer's avatar
DonLakeFlyer committed
495
    clear();
496
    appendVertices(rgCoords);
Don Gagne's avatar
Don Gagne committed
497
    _endResetIfNotActive();
DonLakeFlyer's avatar
DonLakeFlyer committed
498 499 500

    return true;
}
501 502 503 504 505

double QGCMapPolygon::area(void) const
{
    // https://www.mathopenref.com/coordpolygonarea2.html

DonLakeFlyer's avatar
DonLakeFlyer committed
506 507 508 509
    if (_polygonPath.count() < 3) {
        return 0;
    }

510 511 512 513 514 515 516 517 518 519 520
    double coveredArea = 0.0;
    QList<QPointF> nedVertices = nedPolygon();
    for (int i=0; i<nedVertices.count(); i++) {
        if (i != 0) {
            coveredArea += nedVertices[i - 1].x() * nedVertices[i].y() - nedVertices[i].x() * nedVertices[i -1].y();
        } else {
            coveredArea += nedVertices.last().x() * nedVertices[i].y() - nedVertices[i].x() * nedVertices.last().y();
        }
    }
    return 0.5 * fabs(coveredArea);
}
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543

void QGCMapPolygon::verifyClockwiseWinding(void)
{
    if (_polygonPath.count() <= 2) {
        return;
    }

    double sum = 0;
    for (int i=0; i<_polygonPath.count(); i++) {
        QGeoCoordinate coord1 = _polygonPath[i].value<QGeoCoordinate>();
        QGeoCoordinate coord2 = (i == _polygonPath.count() - 1) ? _polygonPath[0].value<QGeoCoordinate>() : _polygonPath[i+1].value<QGeoCoordinate>();

        sum += (coord2.longitude() - coord1.longitude()) * (coord2.latitude() + coord1.latitude());
    }

    if (sum < 0.0) {
        // Winding is counter-clockwise and needs reversal

        QList<QGeoCoordinate> rgReversed;
        for (const QVariant& varCoord: _polygonPath) {
            rgReversed.prepend(varCoord.value<QGeoCoordinate>());
        }

Don Gagne's avatar
Don Gagne committed
544
        _beginResetIfNotActive();
545 546
        clear();
        appendVertices(rgReversed);
Don Gagne's avatar
Don Gagne committed
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
        _endResetIfNotActive();
    }
}

void QGCMapPolygon::beginReset(void)
{
    _resetActive = true;
    _polygonModel.beginReset();
}

void QGCMapPolygon::endReset(void)
{
    _resetActive = false;
    _polygonModel.endReset();
    emit pathChanged();
    emit centerChanged(_center);
}

void QGCMapPolygon::_beginResetIfNotActive(void)
{
    if (!_resetActive) {
        beginReset();
    }
}

void QGCMapPolygon::_endResetIfNotActive(void)
{
    if (!_resetActive) {
        endReset();
576 577
    }
}
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620

QDomElement QGCMapPolygon::kmlPolygonElement(KMLDomDocument& domDocument)
{
#if 0
    <Polygon id="ID">
      <!-- specific to Polygon -->
      <extrude>0</extrude>                       <!-- boolean -->
      <tessellate>0</tessellate>                 <!-- boolean -->
      <altitudeMode>clampToGround</altitudeMode>
            <!-- kml:altitudeModeEnum: clampToGround, relativeToGround, or absolute -->
            <!-- or, substitute gx:altitudeMode: clampToSeaFloor, relativeToSeaFloor -->
      <outerBoundaryIs>
        <LinearRing>
          <coordinates>...</coordinates>         <!-- lon,lat[,alt] -->
        </LinearRing>
      </outerBoundaryIs>
      <innerBoundaryIs>
        <LinearRing>
          <coordinates>...</coordinates>         <!-- lon,lat[,alt] -->
        </LinearRing>
      </innerBoundaryIs>
    </Polygon>
#endif

    QDomElement polygonElement = domDocument.createElement("Polygon");

    domDocument.addTextElement(polygonElement, "altitudeMode", "clampToGround");

    QDomElement outerBoundaryIsElement = domDocument.createElement("outerBoundaryIs");
    QDomElement linearRingElement = domDocument.createElement("LinearRing");

    outerBoundaryIsElement.appendChild(linearRingElement);
    polygonElement.appendChild(outerBoundaryIsElement);

    QString coordString;
    for (const QVariant& varCoord : _polygonPath) {
        coordString += QStringLiteral("%1\n").arg(domDocument.kmlCoordString(varCoord.value<QGeoCoordinate>()));
    }
    coordString += QStringLiteral("%1\n").arg(domDocument.kmlCoordString(_polygonPath.first().value<QGeoCoordinate>()));
    domDocument.addTextElement(linearRingElement, "coordinates", coordString);

    return polygonElement;
}
DoinLakeFlyer's avatar
DoinLakeFlyer committed
621 622 623 624 625 626 627 628

void QGCMapPolygon::setTraceMode(bool traceMode)
{
    if (traceMode != _traceMode) {
        _traceMode = traceMode;
        emit traceModeChanged(traceMode);
    }
}
629 630 631 632 633 634 635

void QGCMapPolygon::setShowAltColor(bool showAltColor){
    if (showAltColor != _showAltColor) {
        _showAltColor = showAltColor;
        emit showAltColorChanged(showAltColor);
    }
}
636 637 638

void QGCMapPolygon::selectVertex(int index)
{
639 640
    if(index == _selectedVertexIndex) return;   // do nothing

641
    if(-1 <= index && index < count()) {
642 643
        _selectedVertexIndex = index;
    } else {
644 645 646 647 648
        if (!qgcApp()->runningUnitTests()) {
            qCWarning(ParameterManagerLog)
                    << QString("QGCMapPolygon: Selected vertex index (%1) is out of bounds! "
                               "Polygon vertices indexes range is [%2..%3].").arg(index).arg(0).arg(count()-1);
        }
649 650 651 652 653
        _selectedVertexIndex = -1;   // deselect vertex
    }

    emit selectedVertexChanged(_selectedVertexIndex);
}