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


#include "ComplexMissionItem.h"
12 13
#include "JsonHelper.h"
#include "MissionController.h"
14
#include "QGCGeo.h"
15

Don Gagne's avatar
Don Gagne committed
16 17
#include <QPolygonF>

Don Gagne's avatar
Don Gagne committed
18 19 20 21 22 23 24 25 26 27 28
QGC_LOGGING_CATEGORY(ComplexMissionItemLog, "ComplexMissionItemLog")

const char* ComplexMissionItem::_jsonVersionKey =               "version";
const char* ComplexMissionItem::_jsonTypeKey =                  "type";
const char* ComplexMissionItem::_jsonPolygonKey =               "polygon";
const char* ComplexMissionItem::_jsonIdKey =                    "id";
const char* ComplexMissionItem::_jsonGridAltitudeKey =          "gridAltitude";
const char* ComplexMissionItem::_jsonGridAltitudeRelativeKey =  "gridAltitudeRelative";
const char* ComplexMissionItem::_jsonGridAngleKey =             "gridAngle";
const char* ComplexMissionItem::_jsonGridSpacingKey =           "gridSpacing";
const char* ComplexMissionItem::_jsonCameraTriggerKey =         "cameraTrigger";
Don Gagne's avatar
Don Gagne committed
29
const char* ComplexMissionItem::_jsonCameraTriggerDistanceKey = "cameraTriggerDistance";
30 31

const char* ComplexMissionItem::_complexType = "survey";
32 33

ComplexMissionItem::ComplexMissionItem(Vehicle* vehicle, QObject* parent)
34
    : VisualMissionItem(vehicle, parent)
35
    , _sequenceNumber(0)
36
    , _dirty(false)
Don Gagne's avatar
Don Gagne committed
37
    , _cameraTrigger(false)
Don Gagne's avatar
Don Gagne committed
38
    , _gridAltitudeRelative(true)
39
    , _surveyDistance(0.0)
40 41
    , _cameraShots(0)
    , _coveredArea(0.0)
42 43 44
    , _gridAltitudeFact (0, "Altitude:",        FactMetaData::valueTypeDouble)
    , _gridAngleFact    (0, "Grid angle:",      FactMetaData::valueTypeDouble)
    , _gridSpacingFact  (0, "Grid spacing:",    FactMetaData::valueTypeDouble)
Don Gagne's avatar
Don Gagne committed
45
    , _cameraTriggerDistanceFact(0, "Camera trigger distance", FactMetaData::valueTypeDouble)
46
{
47
    _gridAltitudeFact.setRawValue(25);
Don Gagne's avatar
Don Gagne committed
48 49
    _gridSpacingFact.setRawValue(10);
    _cameraTriggerDistanceFact.setRawValue(25);
50

51 52
    connect(&_gridSpacingFact,  &Fact::valueChanged, this, &ComplexMissionItem::_generateGrid);
    connect(&_gridAngleFact,    &Fact::valueChanged, this, &ComplexMissionItem::_generateGrid);
53
    connect(&_cameraTriggerDistanceFact,    &Fact::valueChanged, this, &ComplexMissionItem::_generateGrid);
54 55

    connect(this, &ComplexMissionItem::cameraTriggerChanged, this, &ComplexMissionItem::_cameraTriggerChanged);
56 57
}

58 59 60 61 62 63 64 65 66 67
const ComplexMissionItem& ComplexMissionItem::operator=(const ComplexMissionItem& other)
{
    _vehicle = other._vehicle;

    setIsCurrentItem(other._isCurrentItem);
    setDirty(other._dirty);
    setAltDifference(other._altDifference);
    setAltPercent(other._altPercent);
    setAzimuth(other._azimuth);
    setDistance(other._distance);
68
    setSurveyDistance(other._surveyDistance);
69 70 71 72 73 74
    setCameraShots(other._cameraShots);
    setCoveredArea(other._coveredArea);

    return *this;
}

75 76 77 78 79 80 81 82
void ComplexMissionItem::setSurveyDistance(double surveyDistance)
{
    if (!qFuzzyCompare(_surveyDistance, surveyDistance)) {
        _surveyDistance = surveyDistance;
        emit surveyDistanceChanged(_surveyDistance);
    }
}

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
void ComplexMissionItem::setCameraShots(int cameraShots)
{
    if (_cameraShots != cameraShots) {
        _cameraShots = cameraShots;
        emit cameraShotsChanged(_cameraShots);
    }
}

void ComplexMissionItem::setCoveredArea(double coveredArea)
{
    if (!qFuzzyCompare(_coveredArea, coveredArea)) {
        _coveredArea = coveredArea;
        emit coveredAreaChanged(_coveredArea);
    }
}


100 101
void ComplexMissionItem::clearPolygon(void)
{
102 103 104 105
    // Bug workaround, see below
    while (_polygonPath.count() > 1) {
        _polygonPath.takeLast();
    }
106
    emit polygonPathChanged();
107 108 109

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

    _clearGrid();
115
    setDirty(true);
116

117
    emit specifiesCoordinateChanged();
118
    emit lastSequenceNumberChanged(lastSequenceNumber());
119 120 121 122 123 124
}

void ComplexMissionItem::addPolygonCoordinate(const QGeoCoordinate coordinate)
{
    _polygonPath << QVariant::fromValue(coordinate);
    emit polygonPathChanged();
125

126
    int pointCount = _polygonPath.count();
127 128 129 130 131
    if (pointCount >= 3) {
        if (pointCount == 3) {
            emit specifiesCoordinateChanged();
        }
        _generateGrid();
132
    }
133
    setDirty(true);
134
}
135

136 137 138 139 140 141 142 143
void ComplexMissionItem::adjustPolygonCoordinate(int vertexIndex, const QGeoCoordinate coordinate)
{
    _polygonPath[vertexIndex] = QVariant::fromValue(coordinate);
    emit polygonPathChanged();
    _generateGrid();
    setDirty(true);
}

144
int ComplexMissionItem::lastSequenceNumber(void) const
145
{
146 147 148 149
    int lastSeq = _sequenceNumber;

    if (_gridPoints.count()) {
        lastSeq += _gridPoints.count() - 1;
150 151 152 153
        if (_cameraTrigger) {
            // Account for two trigger messages
            lastSeq += 2;
        }
Don Gagne's avatar
Don Gagne committed
154 155
    }

156
    return lastSeq;
157 158 159 160 161 162 163 164 165 166 167 168
}

void ComplexMissionItem::setCoordinate(const QGeoCoordinate& coordinate)
{
    if (_coordinate != coordinate) {
        _coordinate = coordinate;
        emit coordinateChanged(_coordinate);
    }
}

void ComplexMissionItem::setDirty(bool dirty)
{
169 170 171 172
    if (_dirty != dirty) {
        _dirty = dirty;
        emit dirtyChanged(_dirty);
    }
173 174
}

175 176
void ComplexMissionItem::save(QJsonObject& saveObject) const
{
Don Gagne's avatar
Don Gagne committed
177 178 179 180 181 182 183 184
    saveObject[_jsonVersionKey] =               1;
    saveObject[_jsonTypeKey] =                  _complexType;
    saveObject[_jsonIdKey] =                    sequenceNumber();
    saveObject[_jsonGridAltitudeKey] =          _gridAltitudeFact.rawValue().toDouble();
    saveObject[_jsonGridAltitudeRelativeKey] =  _gridAltitudeRelative;
    saveObject[_jsonGridAngleKey] =             _gridAngleFact.rawValue().toDouble();
    saveObject[_jsonGridSpacingKey] =           _gridSpacingFact.rawValue().toDouble();
    saveObject[_jsonCameraTriggerKey] =         _cameraTrigger;
Don Gagne's avatar
Don Gagne committed
185
    saveObject[_jsonCameraTriggerDistanceKey] = _cameraTriggerDistanceFact.rawValue().toDouble();
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203

    // Polygon shape

    QJsonArray polygonArray;

    for (int i=0; i<_polygonPath.count(); i++) {
        const QVariant& polyVar = _polygonPath[i];

        QJsonValue jsonValue;
        JsonHelper::writeQGeoCoordinate(jsonValue, polyVar.value<QGeoCoordinate>(), false /* writeAltitude */);
        polygonArray += jsonValue;
    }

    saveObject[_jsonPolygonKey] = polygonArray;
}

void ComplexMissionItem::setSequenceNumber(int sequenceNumber)
{
204 205 206
    if (_sequenceNumber != sequenceNumber) {
        _sequenceNumber = sequenceNumber;
        emit sequenceNumberChanged(sequenceNumber);
207
        emit lastSequenceNumberChanged(lastSequenceNumber());
208 209 210 211
    }
}

void ComplexMissionItem::_clear(void)
212
{
213 214
    clearPolygon();
    _clearGrid();
215 216 217 218 219 220 221 222 223
}


bool ComplexMissionItem::load(const QJsonObject& complexObject, QString& errorString)
{
    _clear();

    // Validate requires keys
    QStringList requiredKeys;
Don Gagne's avatar
Don Gagne committed
224
    requiredKeys << _jsonVersionKey << _jsonTypeKey << _jsonIdKey << _jsonPolygonKey << _jsonGridAltitudeKey << _jsonGridAngleKey << _jsonGridSpacingKey <<
Don Gagne's avatar
Don Gagne committed
225
                    _jsonCameraTriggerKey << _jsonCameraTriggerDistanceKey << _jsonGridAltitudeRelativeKey;
226 227 228 229 230 231 232 233
    if (!JsonHelper::validateRequiredKeys(complexObject, requiredKeys, errorString)) {
        _clear();
        return false;
    }

    // Validate types
    QStringList keyList;
    QList<QJsonValue::Type> typeList;
Don Gagne's avatar
Don Gagne committed
234
    keyList << _jsonVersionKey << _jsonTypeKey << _jsonIdKey << _jsonPolygonKey << _jsonGridAltitudeKey << _jsonGridAngleKey << _jsonGridSpacingKey <<
Don Gagne's avatar
Don Gagne committed
235
               _jsonCameraTriggerKey << _jsonCameraTriggerDistanceKey << _jsonGridAltitudeRelativeKey;
Don Gagne's avatar
Don Gagne committed
236
    typeList << QJsonValue::Double << QJsonValue::String << QJsonValue::Double << QJsonValue::Array << QJsonValue::Double << QJsonValue::Double<< QJsonValue::Double <<
Don Gagne's avatar
Don Gagne committed
237
                QJsonValue::Bool << QJsonValue::Double << QJsonValue::Bool;
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    if (!JsonHelper::validateKeyTypes(complexObject, keyList, typeList, errorString)) {
        _clear();
        return false;
    }

    // Version check
    if (complexObject[_jsonVersionKey].toInt() != 1) {
        errorString = tr("QGroundControl does not support this version of survey items");
        _clear();
        return false;
    }
    QString complexType = complexObject[_jsonTypeKey].toString();
    if (complexType != _complexType) {
        errorString = tr("QGroundControl does not support loading this complex mission item type: %1").arg(complexType);
        _clear();
        return false;
    }

    setSequenceNumber(complexObject[_jsonIdKey].toInt());
Don Gagne's avatar
Don Gagne committed
257 258 259 260 261 262 263 264

    _cameraTrigger =        complexObject[_jsonCameraTriggerKey].toBool();
    _gridAltitudeRelative = complexObject[_jsonGridAltitudeRelativeKey].toBool();

    _gridAltitudeFact.setRawValue           (complexObject[_jsonGridAltitudeKey].toDouble());
    _gridAngleFact.setRawValue              (complexObject[_jsonGridAngleKey].toDouble());
    _gridSpacingFact.setRawValue            (complexObject[_jsonGridSpacingKey].toDouble());
    _cameraTriggerDistanceFact.setRawValue  (complexObject[_jsonCameraTriggerDistanceKey].toDouble());
265 266 267 268 269 270 271 272 273 274 275 276 277 278

    // Polygon shape
    QJsonArray polygonArray(complexObject[_jsonPolygonKey].toArray());
    for (int i=0; i<polygonArray.count(); i++) {
        const QJsonValue& pointValue = polygonArray[i];

        QGeoCoordinate pointCoord;
        if (!JsonHelper::toQGeoCoordinate(pointValue, pointCoord, false /* altitudeRequired */, errorString)) {
            _clear();
            return false;
        }
        _polygonPath << QVariant::fromValue(pointCoord);
    }

279
    _generateGrid();
280

281 282
    return true;
}
283

284 285 286 287 288 289 290 291 292 293 294 295 296
double ComplexMissionItem::greatestDistanceTo(const QGeoCoordinate &other) const
{
    double greatestDistance = 0.0;
    for (int i=0; i<_gridPoints.count(); i++) {
        QGeoCoordinate currentCoord = _gridPoints[i].value<QGeoCoordinate>();
        double distance = currentCoord.distanceTo(other);
        if (distance > greatestDistance) {
            greatestDistance = distance;
        }
    }
    return greatestDistance;
}

297 298 299 300 301
void ComplexMissionItem::_setExitCoordinate(const QGeoCoordinate& coordinate)
{
    if (_exitCoordinate != coordinate) {
        _exitCoordinate = coordinate;
        emit exitCoordinateChanged(coordinate);
302
    }
303
}
304

305 306 307 308 309 310 311 312 313 314
bool ComplexMissionItem::specifiesCoordinate(void) const
{
    return _polygonPath.count() > 2;
}

void ComplexMissionItem::_clearGrid(void)
{
    // Bug workaround
    while (_gridPoints.count() > 1) {
        _gridPoints.takeLast();
315
    }
316 317 318 319 320 321 322 323 324 325 326 327 328
    emit gridPointsChanged();
    _gridPoints.clear();
}

void ComplexMissionItem::_generateGrid(void)
{
    if (_polygonPath.count() < 3) {
        _clearGrid();
        return;
    }

    _gridPoints.clear();

Don Gagne's avatar
Don Gagne committed
329 330
    QList<QPointF> polygonPoints;
    QList<QPointF> gridPoints;
331

Don Gagne's avatar
Don Gagne committed
332
    // Convert polygon to Qt coordinate system (y positive is down)
Don Gagne's avatar
Don Gagne committed
333
    qCDebug(ComplexMissionItemLog) << "Convert polygon";
334 335
    QGeoCoordinate tangentOrigin = _polygonPath[0].value<QGeoCoordinate>();
    for (int i=0; i<_polygonPath.count(); i++) {
Don Gagne's avatar
Don Gagne committed
336 337 338
        double y, x, down;
        convertGeoToNed(_polygonPath[i].value<QGeoCoordinate>(), tangentOrigin, &y, &x, &down);
        polygonPoints += QPointF(x, -y);
Don Gagne's avatar
Don Gagne committed
339
        qCDebug(ComplexMissionItemLog) << _polygonPath[i].value<QGeoCoordinate>() << polygonPoints.last().x() << polygonPoints.last().y();
340 341
    }

342 343 344 345 346 347 348 349 350 351
    double coveredArea = 0.0;
    for (int i=0; i<polygonPoints.count(); i++) {
        if (i != 0) {
            coveredArea += polygonPoints[i - 1].x() * polygonPoints[i].y() - polygonPoints[i].x() * polygonPoints[i -1].y();
        } else {
            coveredArea += polygonPoints.last().x() * polygonPoints[i].y() - polygonPoints[i].x() * polygonPoints.last().y();
        }
    }
    setCoveredArea(0.5 * fabs(coveredArea));

352 353 354
    // Generate grid
    _gridGenerator(polygonPoints, gridPoints);

355
    double surveyDistance = 0.0;
356 357
    // Convert to Geo and set altitude
    for (int i=0; i<gridPoints.count(); i++) {
Don Gagne's avatar
Don Gagne committed
358
        QPointF& point = gridPoints[i];
359

360 361 362 363
        if (i != 0) {
            surveyDistance += sqrt(pow((gridPoints[i] - gridPoints[i - 1]).x(),2.0) + pow((gridPoints[i] - gridPoints[i - 1]).y(),2.0));
        }

364
        QGeoCoordinate geoCoord;
Don Gagne's avatar
Don Gagne committed
365
        convertNedToGeo(-point.y(), point.x(), 0, tangentOrigin, &geoCoord);
366 367
        _gridPoints += QVariant::fromValue(geoCoord);
    }
368
    setSurveyDistance(surveyDistance);
369 370
    setCameraShots((int)floor(surveyDistance / _cameraTriggerDistanceFact.rawValue().toDouble()));

371 372 373 374 375 376 377
    emit gridPointsChanged();
    emit lastSequenceNumberChanged(lastSequenceNumber());

    if (_gridPoints.count()) {
        setCoordinate(_gridPoints.first().value<QGeoCoordinate>());
        _setExitCoordinate(_gridPoints.last().value<QGeoCoordinate>());
    }
Don Gagne's avatar
Don Gagne committed
378 379 380 381 382 383
}

QPointF ComplexMissionItem::_rotatePoint(const QPointF& point, const QPointF& origin, double angle)
{
    QPointF rotated;
    double radians = (M_PI / 180.0) * angle;
384

Don Gagne's avatar
Don Gagne committed
385 386 387 388
    rotated.setX(((point.x() - origin.x()) * cos(radians)) - ((point.y() - origin.y()) * sin(radians)) + origin.x());
    rotated.setY(((point.x() - origin.x()) * sin(radians)) + ((point.y() - origin.y()) * cos(radians)) + origin.y());

    return rotated;
389 390
}

Don Gagne's avatar
Don Gagne committed
391
void ComplexMissionItem::_intersectLinesWithRect(const QList<QLineF>& lineList, const QRectF& boundRect, QList<QLineF>& resultLines)
392
{
Don Gagne's avatar
Don Gagne committed
393 394 395 396
    QLineF topLine      (boundRect.topLeft(),       boundRect.topRight());
    QLineF bottomLine   (boundRect.bottomLeft(),    boundRect.bottomRight());
    QLineF leftLine     (boundRect.topLeft(),       boundRect.bottomLeft());
    QLineF rightLine    (boundRect.topRight(),      boundRect.bottomRight());
397

Don Gagne's avatar
Don Gagne committed
398 399 400 401 402 403 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
    for (int i=0; i<lineList.count(); i++) {
        QPointF intersectPoint;
        QLineF intersectLine;
        const QLineF& line = lineList[i];

        int foundCount = 0;
        if (line.intersect(topLine, &intersectPoint) == QLineF::BoundedIntersection) {
            intersectLine.setP1(intersectPoint);
            foundCount++;
        }
        if (line.intersect(rightLine, &intersectPoint) == QLineF::BoundedIntersection) {
            if (foundCount == 0) {
                intersectLine.setP1(intersectPoint);
            } else {
                if (foundCount != 1) {
                    qWarning() << "Found more than two intersecting points";
                }
                intersectLine.setP2(intersectPoint);
            }
            foundCount++;
        }
        if (line.intersect(bottomLine, &intersectPoint) == QLineF::BoundedIntersection) {
            if (foundCount == 0) {
                intersectLine.setP1(intersectPoint);
            } else {
                if (foundCount != 1) {
                    qWarning() << "Found more than two intersecting points";
                }
                intersectLine.setP2(intersectPoint);
            }
            foundCount++;
        }
        if (line.intersect(leftLine, &intersectPoint) == QLineF::BoundedIntersection) {
            if (foundCount == 0) {
                intersectLine.setP1(intersectPoint);
            } else {
                if (foundCount != 1) {
                    qWarning() << "Found more than two intersecting points";
                }
                intersectLine.setP2(intersectPoint);
            }
            foundCount++;
        }
441

Don Gagne's avatar
Don Gagne committed
442 443 444 445 446
        if (foundCount == 2) {
            resultLines += intersectLine;
        }
    }
}
447

Don Gagne's avatar
Don Gagne committed
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
void ComplexMissionItem::_intersectLinesWithPolygon(const QList<QLineF>& lineList, const QPolygonF& polygon, QList<QLineF>& resultLines)
{
    for (int i=0; i<lineList.count(); i++) {
        int foundCount = 0;
        QLineF intersectLine;
        const QLineF& line = lineList[i];

        for (int j=0; j<polygon.count()-1; j++) {
            QPointF intersectPoint;
            QLineF polygonLine = QLineF(polygon[j], polygon[j+1]);
            if (line.intersect(polygonLine, &intersectPoint) == QLineF::BoundedIntersection) {
                if (foundCount == 0) {
                    foundCount++;
                    intersectLine.setP1(intersectPoint);
                } else {
                    foundCount++;
                    intersectLine.setP2(intersectPoint);
                    break;
                }
            }
        }
469

Don Gagne's avatar
Don Gagne committed
470 471 472
        if (foundCount == 2) {
            resultLines += intersectLine;
        }
473
    }
Don Gagne's avatar
Don Gagne committed
474
}
475

476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
/// Adjust the line segments such that they are all going the same direction with respect to going from P1->P2
void ComplexMissionItem::_adjustLineDirection(const QList<QLineF>& lineList, QList<QLineF>& resultLines)
{
    for (int i=0; i<lineList.count(); i++) {
        const QLineF& line = lineList[i];
        QLineF adjustedLine;

        if (line.angle() > 180.0) {
            adjustedLine.setP1(line.p2());
            adjustedLine.setP2(line.p1());
        } else {
            adjustedLine = line;
        }

        resultLines += adjustedLine;
    }
}

Don Gagne's avatar
Don Gagne committed
494 495 496
void ComplexMissionItem::_gridGenerator(const QList<QPointF>& polygonPoints,  QList<QPointF>& gridPoints)
{
    double gridAngle = _gridAngleFact.rawValue().toDouble();
497

Don Gagne's avatar
Don Gagne committed
498
    gridPoints.clear();
499

Don Gagne's avatar
Don Gagne committed
500
    // Convert polygon to bounding rect
501

Don Gagne's avatar
Don Gagne committed
502
    qCDebug(ComplexMissionItemLog) << "Polygon";
Don Gagne's avatar
Don Gagne committed
503 504
    QPolygonF polygon;
    for (int i=0; i<polygonPoints.count(); i++) {
Don Gagne's avatar
Don Gagne committed
505
        qCDebug(ComplexMissionItemLog) << polygonPoints[i];
Don Gagne's avatar
Don Gagne committed
506 507 508 509 510
        polygon << polygonPoints[i];
    }
    polygon << polygonPoints[0];
    QRectF smallBoundRect = polygon.boundingRect();
    QPointF center = smallBoundRect.center();
Don Gagne's avatar
Don Gagne committed
511
    qCDebug(ComplexMissionItemLog) << "Bounding rect" << smallBoundRect.topLeft().x() << smallBoundRect.topLeft().y() << smallBoundRect.bottomRight().x() << smallBoundRect.bottomRight().y();
Don Gagne's avatar
Don Gagne committed
512 513 514 515 516 517 518 519 520

    // Rotate the bounding rect around it's center to generate the larger bounding rect
    QPolygonF boundPolygon;
    boundPolygon << _rotatePoint(smallBoundRect.topLeft(),       center, gridAngle);
    boundPolygon << _rotatePoint(smallBoundRect.topRight(),      center, gridAngle);
    boundPolygon << _rotatePoint(smallBoundRect.bottomRight(),   center, gridAngle);
    boundPolygon << _rotatePoint(smallBoundRect.bottomLeft(),    center, gridAngle);
    boundPolygon << boundPolygon[0];
    QRectF largeBoundRect = boundPolygon.boundingRect();
Don Gagne's avatar
Don Gagne committed
521
    qCDebug(ComplexMissionItemLog) << "Rotated bounding rect" << largeBoundRect.topLeft().x() << largeBoundRect.topLeft().y() << largeBoundRect.bottomRight().x() << largeBoundRect.bottomRight().y();
Don Gagne's avatar
Don Gagne committed
522 523 524 525 526 527 528 529 530 531 532

    // Create set of rotated parallel lines within the expanded bounding rect. Make the lines larger than the
    // bounding box to guarantee intersection.
    QList<QLineF> lineList;
    float x = largeBoundRect.topLeft().x();
    float gridSpacing = _gridSpacingFact.rawValue().toDouble();
    while (x < largeBoundRect.bottomRight().x()) {
        float yTop =    largeBoundRect.topLeft().y() - 100.0;
        float yBottom = largeBoundRect.bottomRight().y() + 100.0;

        lineList += QLineF(_rotatePoint(QPointF(x, yTop), center, gridAngle), _rotatePoint(QPointF(x, yBottom), center, gridAngle));
533
        qCDebug(ComplexMissionItemLog) << "line(" << lineList.last().x1() << ", " << lineList.last().y1() << ")-(" << lineList.last().x2() <<", " << lineList.last().y2() << ")";
534 535 536 537

        x += gridSpacing;
    }

538 539 540 541 542 543 544 545 546 547 548
    // Now intersect the lines with the polygon
    QList<QLineF> intersectLines;
#if 1
    _intersectLinesWithPolygon(lineList, polygon, intersectLines);
#else
    // This is handy for debugging grid problems, not for release
    intersectLines = lineList;
#endif

    // Make sure all lines are going to same direction. Polygon intersection leads to line which
    // can be in varied directions depending on the order of the intesecting sides.
Don Gagne's avatar
Don Gagne committed
549
    QList<QLineF> resultLines;
550
    _adjustLineDirection(intersectLines, resultLines);
551

Don Gagne's avatar
Don Gagne committed
552 553 554
    // Turn into a path
    for (int i=0; i<resultLines.count(); i++) {
        const QLineF& line = resultLines[i];
555 556

        if (i & 1) {
Don Gagne's avatar
Don Gagne committed
557
            gridPoints << line.p2() << line.p1();
558
        } else {
Don Gagne's avatar
Don Gagne committed
559
            gridPoints << line.p1() << line.p2();
560 561
        }
    }
562
}
563

Don Gagne's avatar
Don Gagne committed
564
QmlObjectListModel* ComplexMissionItem::getMissionItems(void) const
565
{
566 567 568 569 570 571 572 573 574
    QmlObjectListModel* pMissionItems = new QmlObjectListModel;

    int seqNum = _sequenceNumber;
    for (int i=0; i<_gridPoints.count(); i++) {
        QGeoCoordinate coord = _gridPoints[i].value<QGeoCoordinate>();
        double altitude = _gridAltitudeFact.rawValue().toDouble();

        MissionItem* item = new MissionItem(seqNum++,                       // sequence number
                                            MAV_CMD_NAV_WAYPOINT,           // MAV_CMD
Don Gagne's avatar
Don Gagne committed
575
                                            _gridAltitudeRelative ? MAV_FRAME_GLOBAL_RELATIVE_ALT : MAV_FRAME_GLOBAL,  // MAV_FRAME
576 577 578 579 580 581 582 583
                                            0.0, 0.0, 0.0, 0.0,             // param 1-4
                                            coord.latitude(),
                                            coord.longitude(),
                                            altitude,
                                            true,                           // autoContinue
                                            false,                          // isCurrentItem
                                            pMissionItems);                 // parent - allow delete on pMissionItems to delete everthing
        pMissionItems->append(item);
Don Gagne's avatar
Don Gagne committed
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607

        if (_cameraTrigger && i == 0) {
            MissionItem* item = new MissionItem(seqNum++,                       // sequence number
                                                MAV_CMD_DO_SET_CAM_TRIGG_DIST,  // MAV_CMD
                                                MAV_FRAME_MISSION,              // MAV_FRAME
                                                _cameraTriggerDistanceFact.rawValue().toDouble(),   // trigger distance
                                                0.0, 0.0, 0.0, 0.0, 0.0, 0.0,   // param 2-7
                                                true,                           // autoContinue
                                                false,                          // isCurrentItem
                                                pMissionItems);                 // parent - allow delete on pMissionItems to delete everthing
            pMissionItems->append(item);
        }
    }

    if (_cameraTrigger) {
        MissionItem* item = new MissionItem(seqNum++,                       // sequence number
                                            MAV_CMD_DO_SET_CAM_TRIGG_DIST,  // MAV_CMD
                                            MAV_FRAME_MISSION,              // MAV_FRAME
                                            0.0,                            // trigger distance
                                            0.0, 0.0, 0.0, 0.0, 0.0, 0.0,   // param 2-7
                                            true,                           // autoContinue
                                            false,                          // isCurrentItem
                                            pMissionItems);                 // parent - allow delete on pMissionItems to delete everthing
        pMissionItems->append(item);
608 609 610
    }

    return pMissionItems;
611
}
Don Gagne's avatar
Don Gagne committed
612

613
void ComplexMissionItem::_cameraTriggerChanged(void)
Don Gagne's avatar
Don Gagne committed
614
{
615 616 617 618 619
    setDirty(true);
    if (_gridPoints.count()) {
        // If we have grid turn on/off camera trigger will add/remove two camera trigger mission items
        emit lastSequenceNumberChanged(lastSequenceNumber());
    }
Don Gagne's avatar
Don Gagne committed
620
}