MeasurementComplexItem.cc 39.6 KB
Newer Older
1
#include "MeasurementComplexItem.h"
2 3 4

#include "CircularGenerator.h"
#include "LinearGenerator.h"
Valentin Platzgummer's avatar
Valentin Platzgummer committed
5
#include "NemoInterface.h"
6
#include "RoutingThread.h"
7 8 9 10
#include "geometry/GenericCircle.h"
#include "geometry/MeasurementArea.h"
#include "geometry/SafeArea.h"
#include "geometry/clipper/clipper.hpp"
11
#include "geometry/geometry.h"
12
#include "nemo_interface/MeasurementTile.h"
13

14 15
// QGC
#include "JsonHelper.h"
Valentin Platzgummer's avatar
Valentin Platzgummer committed
16
#include "PlanMasterController.h"
17 18 19 20 21 22 23
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"

// boost
#include <boost/units/io.hpp>
#include <boost/units/systems/si.hpp>

Valentin Platzgummer's avatar
Valentin Platzgummer committed
24
QGC_LOGGING_CATEGORY(MeasurementComplexItemLog, "MeasurementComplexItemLog")
25 26 27 28 29 30

template <typename T>
constexpr typename std::underlying_type<T>::type integral(T value) {
  return static_cast<typename std::underlying_type<T>::type>(value);
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
31 32 33 34
const char *MeasurementComplexItem::settingsGroup = "MeasurementComplexItem";
const char *MeasurementComplexItem::jsonComplexItemTypeValue =
    "MeasurementComplexItem";
const QString MeasurementComplexItem::name(tr("Measurement"));
35 36

namespace {
37
const char *variantIndexKey = "VariantIndex";
38 39 40
const char *altitudeKey = "Altitude";
const char *areaDataKey = "AreaData";
const char *variantNamesKey = "VariantNames";
41 42
const char *generatorArrayKey = "GeneratorArray";
const char *variantArrayKey = "VariantArray";
43
const char *generatorIndexKey = "GeneratorIndex";
44
} // namespace
Valentin Platzgummer's avatar
Valentin Platzgummer committed
45 46 47 48

MeasurementComplexItem::MeasurementComplexItem(
    PlanMasterController *masterController, bool flyView,
    const QString &kmlOrShpFile, QObject *parent)
49
    : ComplexMissionItem(masterController, flyView, parent), _sequenceNumber(0),
50
      _followTerrain(false), _state(STATE::IDLE),
51
      _metaDataMap(FactMetaData::createMapFromJsonFile(
Valentin Platzgummer's avatar
Valentin Platzgummer committed
52 53
          QStringLiteral(":/json/MeasurementComplexItem.SettingsGroup.json"),
          this)),
54
      _altitude(settingsGroup, _metaDataMap[altitudeKey]),
55
      _variantIndex(settingsGroup, _metaDataMap[variantIndexKey]),
56 57 58
      _pAreaData(new AreaData(this)), _pEditorData(new AreaData(this)),
      _pCurrentData(_pAreaData), _pGenerator(nullptr),
      _pWorker(new RoutingThread(this)) {
59

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
  // Setup altitude.
  _altitude.setRawValue(qgcApp()
                            ->toolbox()
                            ->settingsManager()
                            ->appSettings()
                            ->defaultMissionItemAltitude()
                            ->rawValue());
  connect(&_altitude, &SettingsFact::rawValueChanged, [this] {
    emit this->minAMSLAltitudeChanged(this->_altitude.rawValue().toDouble());
  });
  connect(&_altitude, &SettingsFact::rawValueChanged, [this] {
    emit this->maxAMSLAltitudeChanged(this->_altitude.rawValue().toDouble());
  });
  connect(&_altitude, &SettingsFact::rawValueChanged, [this] {
    emit this->amslEntryAltChanged(this->_altitude.rawValue().toDouble());
  });
  connect(&_altitude, &SettingsFact::rawValueChanged, [this] {
    emit this->amslExitAltChanged(this->_altitude.rawValue().toDouble());
  });
  connect(&_altitude, &SettingsFact::rawValueChanged, this,
          &MeasurementComplexItem::_onAltitudeChanged);

82
  Q_UNUSED(kmlOrShpFile)
Valentin Platzgummer's avatar
Valentin Platzgummer committed
83
  _editorQml = "qrc:/qml/MeasurementItemEditor.qml";
84 85

  // Connect facts.
86 87
  connect(&this->_variantIndex, &Fact::rawValueChanged, this,
          &MeasurementComplexItem::_changeVariantIndex);
88 89

  // Connect worker.
90
  connect(this->_pWorker, &RoutingThread::result, this,
Valentin Platzgummer's avatar
Valentin Platzgummer committed
91 92
          &MeasurementComplexItem::_storeRoutingData);

93
  // Connect coordinate and exitCoordinate.
Valentin Platzgummer's avatar
Valentin Platzgummer committed
94 95 96 97 98 99 100 101
  connect(this, &MeasurementComplexItem::routeChanged,
          [this] { emit this->coordinateChanged(this->coordinate()); });
  connect(this, &MeasurementComplexItem::routeChanged,
          [this] { emit this->exitCoordinateChanged(this->exitCoordinate()); });
  connect(this, &MeasurementComplexItem::routeChanged, [this] {
    emit this->exitCoordinateSameAsEntryChanged(
        this->exitCoordinateSameAsEntry());
  });
102

103 104 105 106 107 108 109 110 111 112 113 114 115 116
  // Connect isIncomplete.
  connect(this, &MeasurementComplexItem::idleChanged, [this] {
    if (this->idle()) {
      if (this->route().size() > 0 && this->_isIncomplete == true) {
        this->_isIncomplete = false;
        emit this->isIncompleteChanged();
      }
    } else {
      if (this->_isIncomplete == false) {
        this->_isIncomplete = true;
        emit this->isIncompleteChanged();
      }
    }
  });
117 118

  // Connect readyForSave
119 120 121
  connect(this, &MeasurementComplexItem::idleChanged, this,
          &MeasurementComplexItem::readyForSaveStateChanged);

122 123 124 125
  // Connect flightPathSegments
  connect(this, &MeasurementComplexItem::routeChanged, this,
          &MeasurementComplexItem::_updateFlightpathSegments);

126 127 128 129
  // Connect complexDistance.
  connect(this, &MeasurementComplexItem::routeChanged,
          [this] { emit this->complexDistanceChanged(); });

130
  resetGenerators();
131
  startEditing();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
132 133 134 135

  // connect to nemo interface
  connect(pNemoInterface, &NemoInterface::progressChanged, this,
          &MeasurementComplexItem::_onNewProgress);
136 137
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
138
MeasurementComplexItem::~MeasurementComplexItem() {}
139

Valentin Platzgummer's avatar
Valentin Platzgummer committed
140
void MeasurementComplexItem::reverseRoute() { _reverseRoute(); }
141

Valentin Platzgummer's avatar
Valentin Platzgummer committed
142
const AreaData *MeasurementComplexItem::areaData() const {
143
  return this->_pCurrentData;
144 145
}

146
AreaData *MeasurementComplexItem::areaData() { return this->_pCurrentData; }
147

Valentin Platzgummer's avatar
Valentin Platzgummer committed
148 149
QVariantList MeasurementComplexItem::route() { return _route; }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
150 151 152
QStringList MeasurementComplexItem::variantNames() const {
  return _variantNames;
}
153

Valentin Platzgummer's avatar
Valentin Platzgummer committed
154 155
bool MeasurementComplexItem::load(const QJsonObject &complexObject,
                                  int sequenceNumber, QString &errorString) {
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
  // We need to pull version first to determine what validation/conversion
  // needs to be performed
  QList<JsonHelper::KeyValidateInfo> versionKeyInfoList = {
      {JsonHelper::jsonVersionKey, QJsonValue::Double, true},
  };
  if (!JsonHelper::validateKeys(complexObject, versionKeyInfoList,
                                errorString)) {
    return false;
  }

  int version = complexObject[JsonHelper::jsonVersionKey].toInt();
  if (version != 1) {
    errorString = tr("Survey items do not support version %1").arg(version);
    return false;
  }

172 173 174 175 176 177 178 179 180
  {
    QList<JsonHelper::KeyValidateInfo> keyInfoList = {
        {VisualMissionItem::jsonTypeKey, QJsonValue::String, true},
        {ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true},
    };

    if (!JsonHelper::validateKeys(complexObject, keyInfoList, errorString)) {
      return false;
    }
181

182 183 184 185 186 187 188 189 190 191 192 193
    QString itemType = complexObject[VisualMissionItem::jsonTypeKey].toString();
    QString complexType =
        complexObject[ComplexMissionItem::jsonComplexItemTypeKey].toString();
    if (itemType != VisualMissionItem::jsonTypeComplexItemValue ||
        complexType != jsonComplexItemTypeValue) {
      errorString = tr("%1 does not support loading this complex mission item "
                       "type: %2:%3")
                        .arg(qgcApp()->applicationName())
                        .arg(itemType)
                        .arg(complexType);
      return false;
    }
194 195 196
  }

  setSequenceNumber(sequenceNumber);
197 198
  startEditing();

199 200 201 202
  // load variant index
  if (complexObject.contains(variantIndexKey) &&
      complexObject[variantIndexKey].isDouble()) {
    _variantIndex.setRawValue(complexObject[variantIndexKey].toInt());
203 204 205
  }

  // load altitude
206 207 208 209 210
  if (complexObject.contains(altitudeKey) &&
      complexObject[altitudeKey].isDouble()) {
    _altitude.setRawValue(complexObject[altitudeKey].toDouble());
  } else {
    errorString.append(tr("No altitude found in file.\n"));
211 212
    abortEditing();
    return false;
213 214 215 216 217 218 219
  }

  // load AreaData.
  if (complexObject.contains(areaDataKey) &&
      complexObject[areaDataKey].isObject()) {
    QString e;
    if (_pCurrentData->load(complexObject[areaDataKey].toObject(), e)) {
220
      if (!_pCurrentData->isCorrect(false /*don't show gui message*/)) {
221
        errorString.append(_pCurrentData->errorString());
222 223 224
        abortEditing();
        return false;
      }
225

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    } else {
      // this is critical, proceeding is not
      // reasonable.
      errorString.append(e);
      abortEditing();
      return false;
    }
  } else {
    // this is critical, if no area data present, proceeding is not reasonable.
    errorString.append(tr("No area data found in file. Abort loading.\n"));
    abortEditing();
    return false;
  }

  // load Generators.
241 242
  if (complexObject.contains(generatorArrayKey) &&
      complexObject[generatorArrayKey].isArray()) {
243 244 245 246

    QVector<PtrGenerator> generatorList;
    QObject parent;

247
    for (const auto valueRef : complexObject[generatorArrayKey].toArray()) {
248 249 250 251 252 253 254
      const auto jsonGen = valueRef.toObject();

      if (jsonGen.contains(routing::GeneratorBase::typeKey) &&
          jsonGen[routing::GeneratorBase::typeKey].isString()) {
        QString e;

        // create generator
255
        auto gen = pGeneratorFactory->create(jsonGen, e, &parent /*parent*/);
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273

        if (gen != nullptr) {
          // remove generators of same type and insert this generator.
          for (int i = 0; i < _generatorList.size();) {
            auto otherGen = generator(i);
            if (gen->type() == otherGen->type()) {
              removeGenerator(i);
            } else {
              ++i;
            }
          }
          gen->setData(this->_pAreaData);
          generatorList.append(gen);
        } else {
          // error loading generator.
          errorString.append(
              tr("Error loading generator of type ") +
              jsonGen[routing::GeneratorBase::typeKey].toString() + ".\n");
274
          if (!pGeneratorFactory->registered(
275 276 277 278 279 280 281 282 283 284
                  jsonGen[routing::GeneratorBase::typeKey].toString())) {
            errorString.append(tr("This type is unknown.\n"));
            qCritical()
                << "MeasurementComplexItem::load(): generator of type :"
                << jsonGen[routing::GeneratorBase::typeKey]
                << " not registered with the GeneratorFactory. This can either "
                   "mean that the file contains a invalid entry or "
                   "that the generator was not registered. In the latter case "
                   "use the REGISTER_GENERATOR() for registration";
          }
285 286
          abortEditing();
          return false;
287 288 289
        }

      } else {
290 291 292
        errorString.append(tr("Can not determine type of generator.\n"));
        abortEditing();
        return false;
293 294 295 296 297
      }

      // insert generators
      for (const auto gen : generatorList) {
        gen->setParent(this);
298
        addGenerator(gen);
299 300 301 302 303
      }
    }
  } else {
    errorString.append(
        tr("No generators found in file. Leaving generators unchanged.\n"));
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
    abortEditing();
    return false;
  }

  // load generator index
  bool indexLoaded = false;
  if (complexObject.contains(generatorIndexKey) &&
      complexObject[generatorIndexKey].isDouble()) {
    int index = complexObject[generatorIndexKey].toDouble();
    if (index >= 0 && index < _generatorList.size()) {
      indexLoaded = true;
      switchToGenerator(index);
    }
  }
  if (!indexLoaded) {
    switchToGenerator(0);
320 321 322
  }

  // load Route Variants
323 324
  bool variantsSuccess = true;
  QVector<Variant> variantVector;
325 326
  if (complexObject.contains(variantArrayKey) &&
      complexObject[variantArrayKey].isArray()) {
327 328

    // load variants to variantVector for further processing.
329
    for (const auto valueRef : complexObject[variantArrayKey].toArray()) {
330
      if (valueRef.isArray()) {
331
        const auto jsonVariant = valueRef.toArray();
332 333
        Variant variant;
        QString e;
334
        if (JsonHelper::loadGeoCoordinateArray(jsonVariant, false, variant,
335 336 337 338
                                               e)) {
          if (variant.size() > 0) {
            variantVector.append(std::move(variant));
          } else {
339 340 341
            qCDebug(MeasurementComplexItemLog)
                << "Empty route variant skipped.\n"
                << valueRef.type();
342 343
          }
        } else {
344 345 346
          qCDebug(MeasurementComplexItemLog)
              << "Error loading route variant: " << e;
          variantsSuccess = false;
347 348 349 350
        }
      } else {
        qCDebug(MeasurementComplexItemLog)
            << "json variant is not an array but of type: " << valueRef.type();
351
        variantsSuccess = false;
352 353 354
      }
    }

355 356 357 358 359 360 361 362 363 364
    // Check if variantVector and variants are non empty
    if (variantVector.size() == 0) {
      variantsSuccess = false;
    }
    for (const auto &var : variantVector) {
      if (var.size() == 0) {
        variantsSuccess = false;
      }
    }

365
    // Check if variants are covered by safe area.
366
    if (variantsSuccess) {
367 368 369 370
      auto safeAreaArray = _pCurrentData->safeAreaArray();

      if (safeAreaArray.size() > 0 && safeAreaArray.at(0) != nullptr) {
        auto safeArea = safeAreaArray[0];
371 372
        QGeoCoordinate origin =
            safeArea->pathModel().value<QGCQGeoCoordinate *>(0)->coordinate();
373 374
        geometry::FPolygon safeAreaENU;
        geometry::areaToEnu(origin, safeArea->coordinateList(), safeAreaENU);
375
        for (const auto &variant : variantVector) {
376
          geometry::FLineString varENU;
377
          for (const auto &vertex : variant) {
378 379
            geometry::FPoint vertexENU;
            geometry::toENU(origin, vertex.value<QGeoCoordinate>(), vertexENU);
380 381 382 383 384 385 386 387 388 389 390 391
            varENU.push_back(vertexENU);
          }

          if (!bg::covered_by(varENU, safeAreaENU)) {
            variantsSuccess = false;
            break;
          }
        }
      } else {
        variantsSuccess = false;
      }
    }
392
  } else {
393
    variantsSuccess = false;
394
  }
395

396
  if (variantsSuccess) {
397
    _variantVector.swap(variantVector);
398 399 400 401 402 403 404

    // load variant names
    bool variantNamesLoaded = true;
    if (complexObject.contains(variantNamesKey) &&
        complexObject[variantNamesKey].isArray()) {
      QStringList variantNames;

405
      for (const auto &name : complexObject[variantNamesKey].toArray()) {
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
        if (name.isString()) {
          variantNames.append(name.toString());
        } else {
          variantNamesLoaded = false;
          break;
        }
      }

      if (variantNames.size() != _variantVector.size()) {
        variantNamesLoaded = false;
      }

      if (variantNamesLoaded) {
        _variantNames.swap(variantNames);
        emit variantNamesChanged();
      }
    } else {
      qCWarning(MeasurementComplexItemLog)
          << "Not able to load variant names. variantNamesKey missing or wrong "
             "type";
      if (complexObject.contains(variantNamesKey)) {
        qCWarning(MeasurementComplexItemLog)
            << "variantNamesKey type: "
            << complexObject[variantNamesKey].type();
      }
    }

    // create std. variant names if loading failed
    if (!variantNamesLoaded) {
      qCWarning(MeasurementComplexItemLog) << "Creating std. variant names.";
      this->_variantNames.clear();
      for (std::size_t i = 1; i <= std::size_t(this->_variantVector.size());
           ++i) {
        this->_variantNames.append(QString::number(i));
      }
      emit variantNamesChanged();
    }

444 445
    stopEditing(
        false /*doUpdate*/); // does noting if editing was already stopped
446 447 448 449

    _changeVariantIndex();
  } else {
    stopEditing(); // stop editing and trigger update
450
  }
451

452
  return true;
453 454
}

455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
double
MeasurementComplexItem::greatestDistanceTo(const QGeoCoordinate &other) const {
  double d = -1 * std::numeric_limits<double>::infinity();
  if (other.isValid()) {
    if (this->_route.size() > 0) {
      std::for_each(this->_route.cbegin(), this->_route.cend(),
                    [&d, &other](const QVariant &variant) {
                      auto vertex = variant.value<QGeoCoordinate>();
                      d = std::max(d, vertex.distanceTo(other));
                    });
    }
  } else {
    qCDebug(MeasurementComplexItemLog)
        << "greatestDistanceTo(): invalid QGeoCoordinate: " << other;
  }
  return d;
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
473 474 475 476 477 478 479 480
bool MeasurementComplexItem::dirty() const { return _dirty; }

bool MeasurementComplexItem::isSimpleItem() const { return false; }

bool MeasurementComplexItem::isStandaloneCoordinate() const { return false; }

QString MeasurementComplexItem::mapVisualQML() const {
  return QStringLiteral("MeasurementItemMapVisual.qml");
481 482
}

483
void MeasurementComplexItem::save(QJsonArray &planItems) {
484
  if (idle()) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
485
    QJsonObject saveObject;
486

Valentin Platzgummer's avatar
Valentin Platzgummer committed
487 488 489 490 491
    saveObject[JsonHelper::jsonVersionKey] = 1;
    saveObject[VisualMissionItem::jsonTypeKey] =
        VisualMissionItem::jsonTypeComplexItemValue;
    saveObject[ComplexMissionItem::jsonComplexItemTypeKey] =
        jsonComplexItemTypeValue;
492

493
    // Variant and altitude.
494
    saveObject[variantIndexKey] = double(_variantIndex.rawValue().toUInt());
495
    saveObject[altitudeKey] = double(_altitude.rawValue().toUInt());
496

497
    // Variant names.
498
    QJsonArray jsonVariantNames;
499 500 501
    for (auto const &name : _variantNames) {
      jsonVariantNames.append(name);
    }
502
    saveObject[variantNamesKey] = jsonVariantNames;
503 504

    // AreaData.
505 506 507 508 509 510
    QJsonObject jsonAreaData;
    if (!_pAreaData->save(jsonAreaData)) {
      qCDebug(MeasurementComplexItemLog)
          << "save(): not able to save area data";
      return;
    }
511
    saveObject[areaDataKey] = jsonAreaData;
512 513

    // Generators.
514 515 516
    QJsonArray generatorArray;
    for (int i = 0; i < _generatorList.size(); ++i) {
      auto const gen = _generatorList[i];
517 518
      QJsonObject obj;
      if (!gen->save(obj)) {
519
        qCDebug(MeasurementComplexItemLog)
520
            << "save(): not able to save generator with name: " << gen->name();
521 522
        return;
      } else {
523
        generatorArray.append(obj);
524 525
      }
    }
526
    saveObject[generatorArrayKey] = generatorArray;
527

528
    // generator index
529
    saveObject[generatorIndexKey] = generatorIndex();
530

531
    // Route Variants
532
    QJsonArray variantsArray;
533 534
    for (auto const &route : _variantVector) {
      QJsonValue variant;
535
      if (route.size() > 0) {
536
        JsonHelper::saveGeoCoordinateArray(route, false, variant);
537
      } else {
538
        JsonHelper::saveGeoCoordinateArray(_route, false, variant);
539 540 541
      }
      variantsArray.append(variant);
    }
542
    saveObject[variantArrayKey] = variantsArray;
543

Valentin Platzgummer's avatar
Valentin Platzgummer committed
544
    planItems.append(saveObject);
545 546
  } else {
    qCDebug(MeasurementComplexItemLog) << "save(): called while not idle.";
Valentin Platzgummer's avatar
Valentin Platzgummer committed
547
  }
548 549
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
double MeasurementComplexItem::amslEntryAlt() const {
  return _altitude.rawValue().toDouble() +
         this->_masterController->missionController()
             ->plannedHomePosition()
             .altitude();
}

double MeasurementComplexItem::amslExitAlt() const { return amslEntryAlt(); }

double MeasurementComplexItem::minAMSLAltitude() const {
  return amslEntryAlt();
}

double MeasurementComplexItem::maxAMSLAltitude() const {
  return amslEntryAlt();
}

567 568 569 570 571 572 573 574 575 576 577 578
QString MeasurementComplexItem::commandDescription() const {
  return QStringLiteral("Measurement");
}

QString MeasurementComplexItem::commandName() const {
  return QStringLiteral("Measurement");
}

QString MeasurementComplexItem::abbreviation() const {
  return QStringLiteral("M");
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
579 580 581 582 583 584 585
bool MeasurementComplexItem::specifiesCoordinate() const {
  return _route.count() > 0;
}

bool MeasurementComplexItem::specifiesAltitudeOnly() const { return false; }

QGeoCoordinate MeasurementComplexItem::coordinate() const {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
586 587
  return this->_route.size() > 0 ? _route.first().value<QGeoCoordinate>()
                                 : QGeoCoordinate();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
588 589 590
}

QGeoCoordinate MeasurementComplexItem::exitCoordinate() const {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
591 592
  return this->_route.size() > 0 ? _route.last().value<QGeoCoordinate>()
                                 : QGeoCoordinate();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
}

int MeasurementComplexItem::sequenceNumber() const { return _sequenceNumber; }

double MeasurementComplexItem::specifiedFlightSpeed() {
  return std::numeric_limits<double>::quiet_NaN();
}

double MeasurementComplexItem::specifiedGimbalYaw() {
  return std::numeric_limits<double>::quiet_NaN();
}

double MeasurementComplexItem::specifiedGimbalPitch() {
  return std::numeric_limits<double>::quiet_NaN();
}

void MeasurementComplexItem::appendMissionItems(QList<MissionItem *> &items,
                                                QObject *missionItemParent) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
611

612
  if (idle()) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
    qCDebug(MeasurementComplexItemLog) << "appendMissionItems()";

    int seqNum = this->_sequenceNumber;

    MAV_FRAME mavFrame =
        followTerrain() ? MAV_FRAME_GLOBAL : MAV_FRAME_GLOBAL_RELATIVE_ALT;

    for (const auto &variant : this->_route) {
      auto vertex = variant.value<QGeoCoordinate>();
      MissionItem *item = new MissionItem(
          seqNum++, MAV_CMD_NAV_WAYPOINT, mavFrame,
          0,   // hold time
          0.0, // No acceptance radius specified
          0.0, // Pass through waypoint
          std::numeric_limits<double>::quiet_NaN(), // Yaw unchanged
          vertex.latitude(), vertex.longitude(), vertex.altitude(),
          true,  // autoContinue
          false, // isCurrentItem
          missionItemParent);
      items.append(item);
    }
  } else {
    qCDebug(MeasurementComplexItemLog)
        << "appendMissionItems(): called while not ready().";
Valentin Platzgummer's avatar
Valentin Platzgummer committed
637 638 639 640 641 642
  }
}

void MeasurementComplexItem::setMissionFlightStatus(
    const MissionController::MissionFlightStatus_t &missionFlightStatus) {
  ComplexMissionItem::setMissionFlightStatus(missionFlightStatus);
643 644
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
645
void MeasurementComplexItem::applyNewAltitude(double newAltitude) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
646
  this->_altitude.setRawValue(newAltitude);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
647 648 649 650 651
}

double MeasurementComplexItem::additionalTimeDelay() const { return 0; }

bool MeasurementComplexItem::_setGenerator(PtrGenerator newG) {
652 653
  if (this->_pGenerator != newG) {
    if (this->_pGenerator != nullptr) {
654
      disconnect(this->_pGenerator, &routing::GeneratorBase::generatorChanged,
Valentin Platzgummer's avatar
Valentin Platzgummer committed
655
                 this, &MeasurementComplexItem::_updateRoute);
656 657 658
    }

    this->_pGenerator = newG;
659 660 661 662 663 664

    if (this->_pGenerator != nullptr) {
      connect(this->_pGenerator, &routing::GeneratorBase::generatorChanged,
              this, &MeasurementComplexItem::_updateRoute);
    }

665 666
    emit generatorChanged();

Valentin Platzgummer's avatar
Valentin Platzgummer committed
667 668 669 670
    if (!editing()) {
      this->_setState(STATE::IDLE);
      _updateRoute();
    }
671 672 673 674 675 676 677

    return true;
  } else {
    return false;
  }
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
678
void MeasurementComplexItem::_setState(MeasurementComplexItem::STATE state) {
679 680 681
  if (this->_state != state) {
    auto oldState = this->_state;
    this->_state = state;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
682

683 684 685
    if (_calculating(oldState) != _calculating(state)) {
      emit calculatingChanged();
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
686 687 688 689

    if (_editing(oldState) != _editing(state)) {
      emit editingChanged();
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
690

691 692
    if (_idle(oldState) != _idle(state)) {
      emit idleChanged();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
693
    }
694 695 696
  }
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
697
bool MeasurementComplexItem::_calculating(MeasurementComplexItem::STATE state) {
698 699 700
  return state == STATE::ROUTING;
}

701 702 703 704
bool MeasurementComplexItem::_editing(MeasurementComplexItem::STATE state) {
  return state == STATE::EDITING;
}

705
bool MeasurementComplexItem::_idle(MeasurementComplexItem::STATE state) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
706 707 708
  return state == STATE::IDLE;
}

709
void MeasurementComplexItem::_updateFlightpathSegments() {
710 711
  bool hasCollisionOld = _cTerrainCollisionSegments > 0;
  _cTerrainCollisionSegments = 0;
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736

  _flightPathSegments.beginReset();
  _flightPathSegments.clearAndDeleteContents();

  if (_route.size() > 2) {
    bool ok = false;
    double alt = _altitude.rawValue().toDouble(&ok) +
                 _masterController->missionController()
                     ->plannedHomePosition()
                     .altitude();
    if (ok) {
      auto prev = _route.cbegin();
      for (auto next = _route.cbegin() + 1; next != _route.end(); ++next) {
        auto v1 = prev->value<QGeoCoordinate>();
        auto v2 = next->value<QGeoCoordinate>();
        _appendFlightPathSegment(v1, alt, v2, alt);
        prev = next;
      }
    } else {
      qCCritical(MeasurementComplexItemLog) << "_altitude fact not ok.";
    }
  }

  _flightPathSegments.endReset();

737 738 739 740 741
  // Terrain collsision.
  bool hasCollision = _cTerrainCollisionSegments > 0;
  if (hasCollisionOld != hasCollision) {
    emit terrainCollisionChanged(hasCollision);
  }
742 743 744 745 746
  auto measurementAreaArray = _pAreaData->measurementAreaArray();
  for (auto area : measurementAreaArray) {
    if (area != nullptr) {
      area->setShowAltColor(hasCollision);
    }
747 748 749 750
  }

  _masterController->missionController()->recalcTerrainProfile();
}
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774

void MeasurementComplexItem::_onAltitudeChanged() {
  // Apply altitude to variants and route.
  auto alt = _altitude.rawValue().toDouble();
  for (auto &var : _variantVector) {

    Variant *pVar;
    if (var.size() > 0) {
      pVar = &var;
    } else {
      pVar = &_route;
    }

    for (auto &qVariant : *pVar) {
      auto vertex = qVariant.value<QGeoCoordinate>();
      vertex.setAltitude(alt);
      qVariant = QVariant::fromValue(vertex);
    }
  }

  if (_route.size() > 0) {
    emit routeChanged();
  }
}
Valentin Platzgummer's avatar
Valentin Platzgummer committed
775 776
void MeasurementComplexItem::_setAreaData(
    MeasurementComplexItem::PtrAreaData data) {
777 778
  if (_pCurrentData != data) {
    _pCurrentData = data;
779 780 781 782
    emit areaDataChanged();
  }
}

783 784 785 786
void MeasurementComplexItem::_updateRoute() {
  if (!editing()) {
    // Reset data.
    this->_route.clear();
787
    emit routeChanged();
788 789 790 791 792 793
    this->_variantVector.clear();
    this->_variantNames.clear();
    emit variantNamesChanged();

    if (this->_pAreaData->isCorrect()) {

794 795 796 797 798 799 800 801 802 803 804 805 806 807
      auto measurmentAreaArray = _pAreaData->measurementAreaArray();
      bool measurementComplete = true;
      for (const auto &area : measurmentAreaArray) {
        if (!area->measurementCompleted()) {
          measurementComplete = false;
        }
      }

      if (measurementComplete) {
        qCDebug(MeasurementComplexItemLog)
            << "_updateWorker(): measurement complete!";
        return;
      }

808 809 810 811
      // Prepare data.
      auto origin = this->_pAreaData->origin();
      origin.setAltitude(0);
      if (!origin.isValid()) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
812
        qCDebug(MeasurementComplexItemLog)
813 814
            << "_updateWorker(): origin invalid." << origin;
        return;
815 816
      }

817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
      // Convert safe area.
      auto serviceArea =
          getGeoArea<const SafeArea *>(*this->_pAreaData->areaList());
      auto geoSafeArea = serviceArea->coordinateList();
      if (!(geoSafeArea.size() >= 3)) {
        qCDebug(MeasurementComplexItemLog)
            << "_updateWorker(): safe area invalid." << geoSafeArea;
        return;
      }
      for (auto &v : geoSafeArea) {
        if (v.isValid()) {
          v.setAltitude(0);
        } else {
          qCDebug(MeasurementComplexItemLog)
              << "_updateWorker(): safe area contains invalid coordinate."
              << geoSafeArea;
          return;
        }
      }
836

837 838 839 840
      // Routing par.
      RoutingParameter par;
      par.numSolutions = 5;
      auto &safeAreaENU = par.safeArea;
841
      geometry::areaToEnu(origin, geoSafeArea, safeAreaENU);
842 843 844

      // Create generator.
      if (this->_pGenerator != nullptr) {
845
        routing::GeneratorBase::Work g; // Transect generator.
846 847 848 849 850 851 852 853 854 855
        if (this->_pGenerator->get(g)) {
          // Start/Restart routing worker.
          this->_pWorker->route(par, g);
          _setState(STATE::ROUTING);
          return;
        } else {
          qCDebug(MeasurementComplexItemLog)
              << "_updateWorker(): generator creation failed.";
          return;
        }
856
      } else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
857
        qCDebug(MeasurementComplexItemLog)
858 859 860 861
            << "_updateWorker(): pGenerator == nullptr, number of registered "
               "generators: "
            << this->_generatorList.size();
        return;
862 863
      }
    } else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
864
      qCDebug(MeasurementComplexItemLog)
865
          << "_updateWorker(): area data invalid.";
866
      return;
867 868 869 870
    }
  }
}

871
void MeasurementComplexItem::_changeVariantIndex() {
872
  if (idle()) {
873
    auto variant = this->_variantIndex.rawValue().toUInt();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
874

875
    // Find old variant. Old variant corresponts with empty list.
Valentin Platzgummer's avatar
Valentin Platzgummer committed
876 877 878 879 880 881 882
    std::size_t old_variant = std::numeric_limits<std::size_t>::max();
    for (std::size_t i = 0; i < std::size_t(this->_variantVector.size()); ++i) {
      const auto &variantCoordinates = this->_variantVector.at(i);
      if (variantCoordinates.isEmpty()) {
        old_variant = i;
        break;
      }
883 884
    }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
885 886 887 888 889 890 891
    // Swap route.
    if (variant != old_variant) {
      // Swap in new variant.
      if (variant < std::size_t(this->_variantVector.size())) {
        if (old_variant != std::numeric_limits<std::size_t>::max()) {
          // this->_route containes a route, swap it back to
          // this->_solutionVector
892 893
          auto &oldRoute = this->_variantVector[old_variant];
          oldRoute.swap(this->_route);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
894
        }
895 896
        auto &newRoute = this->_variantVector[variant];
        this->_route.swap(newRoute);
897
        emit routeChanged();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
898 899 900 901
      } else { // error
        qCDebug(MeasurementComplexItemLog)
            << "Variant out of bounds (variant =" << variant << ").";
        qCDebug(MeasurementComplexItemLog) << "Resetting variant to zero.";
902

903 904 905 906 907
        disconnect(&this->_variantIndex, &Fact::rawValueChanged, this,
                   &MeasurementComplexItem::_changeVariantIndex);
        this->_variantIndex.setCookedValue(QVariant(0));
        connect(&this->_variantIndex, &Fact::rawValueChanged, this,
                &MeasurementComplexItem::_changeVariantIndex);
908

Valentin Platzgummer's avatar
Valentin Platzgummer committed
909
        if (this->_variantVector.size() > 0) {
910
          this->_changeVariantIndex();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
911
        }
912 913 914 915 916
      }
    }
  }
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
917
void MeasurementComplexItem::_reverseRoute() {
918
  if (idle()) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
919 920 921 922
    if (this->_route.size() > 0) {
      auto &t = this->_route;
      std::reverse(t.begin(), t.end());
    }
923
    emit routeChanged();
924 925 926
  }
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
void MeasurementComplexItem::_syncTiles() {
  auto areaArray = _pAreaData->measurementAreaArray();
  bool clear = false;
  if (areaArray.size() > 0) {

    // create tile ptr array
    TilePtrArray tilePtrArray;
    auto *pMeasurementArea = areaArray[0];
    auto pTiles = pMeasurementArea->tiles();
    for (int i = 0; i < pTiles->count(); ++i) {
      auto *tile = pTiles->value<MeasurementTile *>(i);
      Q_ASSERT(tile != nullptr);
      tilePtrArray.push_back(tile);
    }

    if (tilePtrArray.size() > 0) {

      // create id array
      IDArray idArray;
      for (const auto *pTile : tilePtrArray) {
        idArray.push_back(pTile->id());
      }

      // sync. necessary?
      bool doSync = false;
      auto contains = pNemoInterface->containsTiles(idArray);
      for (auto &&logical : contains) {
        if (logical == false) {
          doSync = true;
          break;
        }
      }

      if (doSync) {
        if (!pNemoInterface->empty()) {
          (void)pNemoInterface->clearTiles();
        }
        (void)pNemoInterface->addTiles(tilePtrArray);
        return;
      }
    } else {
      clear = true;
    }
  } else {
    clear = true;
  }

  if (clear) {
    if (!pNemoInterface->empty()) {
      (void)pNemoInterface->clearTiles();
    }
  }
}

void MeasurementComplexItem::_onNewProgress(const ProgressArray &array) {
  auto areaArray = this->_pAreaData->measurementAreaArray();
  if (areaArray.size() > 0) {
    for (auto &area : areaArray) {
      area->updateProgress(array);
    }
  }
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
990
ComplexMissionItem::ReadyForSaveState
Valentin Platzgummer's avatar
Valentin Platzgummer committed
991
MeasurementComplexItem::readyForSaveState() const {
992
  if (idle()) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
993
    return ReadyForSaveState::ReadyForSave;
994
  } else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
995
    return ReadyForSaveState::NotReadyForSaveData;
996 997 998
  }
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
999 1000 1001 1002
bool MeasurementComplexItem::exitCoordinateSameAsEntry() const {
  return this->_route.size() > 0 ? this->_route.first() == this->_route.last()
                                 : false;
}
1003

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1004 1005 1006 1007 1008 1009
void MeasurementComplexItem::setDirty(bool dirty) {
  if (this->_dirty != dirty) {
    this->_dirty = dirty;
    emit dirtyChanged(this->_dirty);
  }
}
1010

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
void MeasurementComplexItem::setCoordinate(const QGeoCoordinate &coordinate) {
  Q_UNUSED(coordinate);
}

void MeasurementComplexItem::setSequenceNumber(int sequenceNumber) {
  if (this->_sequenceNumber != sequenceNumber) {
    this->_sequenceNumber = sequenceNumber;
    emit sequenceNumberChanged(this->_sequenceNumber);
  }
}

QString MeasurementComplexItem::patternName() const { return name; }

1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
double MeasurementComplexItem::complexDistance() const {
  double d = 0;
  if (this->_route.size() > 1) {
    auto vertex = _route.first().value<QGeoCoordinate>();
    std::for_each(this->_route.cbegin() + 1, this->_route.cend(),
                  [&vertex, &d](const QVariant &variant) {
                    auto otherVertex = variant.value<QGeoCoordinate>();
                    d += vertex.distanceTo(otherVertex);
                    vertex = otherVertex;
                  });
  }
  return d;
}

int MeasurementComplexItem::lastSequenceNumber() const {
  return _sequenceNumber + std::max(0, this->_route.size() - 1);
}

1042
bool MeasurementComplexItem::addGenerator(routing::GeneratorBase *g) {
1043

1044
  if (g == nullptr) {
1045
    qCDebug(MeasurementComplexItemLog) << "addGenerator(): empty generator.";
1046
    Q_ASSERT(g != nullptr);
1047 1048 1049
    return false;
  }

1050 1051 1052 1053 1054 1055 1056
  for (const auto &otherGenerator : _generatorList) {
    if (otherGenerator->name() == g->name()) {
      qCDebug(MeasurementComplexItemLog)
          << "addGenerator(): generator with name " << g->name()
          << " already added.";
      Q_ASSERT(otherGenerator->name() == g->name());
      return false;
1057
    }
1058
  }
1059

1060 1061 1062
  this->_generatorList.push_back(g);
  if (this->_generatorList.size() == 1) {
    _setGenerator(g);
1063
  }
1064 1065 1066

  emit generatorListChanged();
  return true;
1067 1068
}

1069
bool MeasurementComplexItem::removeGenerator(const QString &name) {
1070 1071 1072 1073 1074
  return removeGenerator(generatorIndex(name));
}

bool MeasurementComplexItem::removeGenerator(int index) {
  if (index >= 0 && index < this->_generatorList.size()) {
1075 1076 1077 1078
    // Is this the current generator?
    const auto &g = this->_generatorList.at(index);
    if (g == this->_pGenerator) {
      if (index > 0) {
1079
        _setGenerator(this->_generatorList.at(index - 1));
1080 1081
      } else if (index + 1 < _generatorList.size()) {
        _setGenerator(this->_generatorList.at(index + 1));
1082
      } else {
1083
        _setGenerator(nullptr);
1084 1085 1086
      }
    }

1087
    auto gen = this->_generatorList.takeAt(index);
1088

1089 1090 1091 1092
    // Should the generator be deleted?
    if (gen->parent() == this || gen->parent() == nullptr) {
      gen->deleteLater();
    }
1093

1094 1095
    emit generatorListChanged();
    return true;
1096
  } else {
1097 1098 1099 1100
    qCDebug(MeasurementComplexItemLog) << "removeGenerator(): index (" << index
                                       << ") out"
                                          "of bounds ( "
                                       << this->_generatorList.size() << " ).";
1101 1102 1103 1104
    return false;
  }
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1105
bool MeasurementComplexItem::switchToGenerator(const QString &name) {
1106
  return switchToGenerator(generatorIndex(name));
1107 1108
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1109
bool MeasurementComplexItem::switchToGenerator(int index) {
1110
  if (index >= 0 && index < _generatorList.size()) {
1111
    _setGenerator(this->_generatorList.at(index));
1112 1113
    return true;
  } else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1114
    qCDebug(MeasurementComplexItemLog)
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1115
        << "switchToGenerator(): index (" << index
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1116 1117
        << ") out"
           "of bounds ( "
1118
        << this->_generatorList.size() << " ).";
1119 1120 1121 1122
    return false;
  }
}

1123 1124 1125 1126
void MeasurementComplexItem::resetGenerators() {
  while (_generatorList.size() > 0) {
    removeGenerator(0);
  }
1127

1128 1129
  auto lg =
      pGeneratorFactory->create(routing::LinearGenerator::typeString, this);
1130 1131 1132
  lg->setData(this->_pAreaData);
  addGenerator(lg);

1133 1134
  auto cg =
      pGeneratorFactory->create(routing::CircularGenerator::typeString, this);
1135 1136 1137 1138 1139 1140 1141
  cg->setData(this->_pAreaData);
  addGenerator(cg);
}

QList<MeasurementComplexItem::PtrGenerator>
MeasurementComplexItem::generatorList() const {
  return _generatorList;
1142 1143
}

1144
QStringList MeasurementComplexItem::generatorNameList() const {
1145 1146 1147 1148 1149
  QStringList list;
  for (const auto gen : _generatorList) {
    list.append(gen->name());
  }
  return list;
1150 1151
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1152 1153 1154
routing::GeneratorBase *MeasurementComplexItem::generator() {
  return _pGenerator;
}
1155

1156 1157 1158 1159 1160 1161
const routing::GeneratorBase *MeasurementComplexItem::generator() const {
  return _pGenerator;
}

const routing::GeneratorBase *
MeasurementComplexItem::generator(int index) const {
1162
  if (index >= 0 && index < _generatorList.size()) {
1163 1164 1165 1166 1167 1168 1169
    return _generatorList[index];
  } else {
    return nullptr;
  }
}

routing::GeneratorBase *MeasurementComplexItem::generator(int index) {
1170
  if (index >= 0 && index < _generatorList.size()) {
1171 1172 1173 1174 1175 1176 1177
    return _generatorList[index];
  } else {
    return nullptr;
  }
}

int MeasurementComplexItem::generatorIndex() const {
1178 1179 1180
  return this->_generatorList.indexOf(this->_pGenerator);
}

1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
int MeasurementComplexItem::generatorIndex(const QString &name) {
  int index = -1;
  for (int i = 0; i < _generatorList.size(); ++i) {
    const auto gen = _generatorList[i];
    if (gen->name() == name) {
      index = i;
      break;
    }
  }
  return index;
}

1193 1194
void MeasurementComplexItem::startEditing() {
  if (!editing()) {
1195 1196
    *_pEditorData = *_pAreaData;
    _setAreaData(_pEditorData);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1197
    _setState(STATE::EDITING);
1198 1199 1200
  }
}

1201
bool MeasurementComplexItem::stopEditing(bool doUpdate) {
1202
  if (editing()) {
1203
    bool isDifferent = *_pEditorData != *_pAreaData;
1204 1205
    bool correct = _pEditorData->isCorrect();
    if (correct) {
1206
      *_pAreaData = *_pEditorData;
1207
    }
1208
    _setAreaData(_pAreaData);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1209
    _setState(STATE::IDLE);
1210 1211 1212
    bool updated = false;
    if (doUpdate && correct && isDifferent) {
      updated = true;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1213
      _updateRoute();
1214
    }
1215

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1216 1217 1218 1219
    if (correct && isDifferent) {
      _syncTiles();
    }

1220
    return updated;
1221
  }
1222
  return false;
1223 1224
}

1225 1226 1227
void MeasurementComplexItem::abortEditing() {
  if (editing()) {
    _setAreaData(_pAreaData);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1228
    _syncTiles();
1229 1230 1231 1232
    _setState(STATE::IDLE);
  }
}

1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
void MeasurementComplexItem::reset() {
  if (editing()) {
    *_pEditorData = *_pAreaData;
  }
}

bool MeasurementComplexItem::initialize(const QGeoCoordinate &bottomLeft,
                                        const QGeoCoordinate &topRight) {
  bool r1 = _pAreaData->initialize(bottomLeft, topRight);
  bool r2 = _pEditorData->initialize(bottomLeft, topRight);

  return r1 && r2;
}

bool MeasurementComplexItem::initialized() {
  return _pCurrentData->initialized();
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1251
void MeasurementComplexItem::_storeRoutingData(
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1252
    MeasurementComplexItem::PtrRoutingData pRoute) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1253 1254
  if (this->_state == STATE::ROUTING) {
    // Store solutions.
1255
    auto ori = this->_pAreaData->origin();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1256 1257
    ori.setAltitude(0);
    QVector<Variant> variantVector;
1258
    const std::size_t nSolutions = pRoute->solutionVector.size();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1259 1260 1261 1262 1263 1264 1265

    for (std::size_t j = 0; j < nSolutions; ++j) {
      Variant var;
      const auto &solution = pRoute->solutionVector.at(j);
      if (solution.size() > 0) {
        const auto &route = solution.at(0);
        const auto &path = route.path;
1266 1267 1268 1269 1270

        // Convert to geo coordinates.

        for (const auto &vertex : path) {
          QGeoCoordinate c;
1271
          geometry::fromENU(ori, vertex, c);
1272
          var.append(QVariant::fromValue(c));
1273 1274
        }
      } else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1275
        qCDebug(MeasurementComplexItemLog)
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1276
            << "_setTransects(): solution.size() == 0";
1277 1278
      }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1279 1280 1281
      if (var.size() > 0) {
        variantVector.push_back(std::move(var));
      }
1282 1283
    }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1284 1285 1286 1287
    // Assign routes if no error occured.
    if (variantVector.size() > 0) {
      // Swap first route to _route.
      this->_variantVector.swap(variantVector);
1288

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1289 1290 1291 1292 1293 1294 1295
      // Add route variant names.
      this->_variantNames.clear();
      for (std::size_t i = 1; i <= std::size_t(this->_variantVector.size());
           ++i) {
        this->_variantNames.append(QString::number(i));
      }
      emit variantNamesChanged();
1296

1297
      // Set variant to 0.
1298 1299 1300 1301 1302
      disconnect(&this->_variantIndex, &Fact::rawValueChanged, this,
                 &MeasurementComplexItem::_changeVariantIndex);
      this->_variantIndex.setCookedValue(QVariant(0));
      connect(&this->_variantIndex, &Fact::rawValueChanged, this,
              &MeasurementComplexItem::_changeVariantIndex);
1303

1304
      // Select first variant as route.
1305
      this->_route.swap(this->_variantVector.first());
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1306
      emit routeChanged();
1307 1308

      this->_setState(STATE::IDLE);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1309 1310 1311 1312 1313
    } else {
      qCDebug(MeasurementComplexItemLog)
          << "_setTransects(): failed, variantVector empty.";
      this->_setState(STATE::IDLE);
    }
1314 1315 1316
  }
}

1317
Fact *MeasurementComplexItem::variantIndex() { return &_variantIndex; }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1318 1319

Fact *MeasurementComplexItem::altitude() { return &this->_altitude; }
1320

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1321
bool MeasurementComplexItem::calculating() const {
1322 1323 1324
  return this->_calculating(this->_state);
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1325 1326
bool MeasurementComplexItem::editing() const { return _editing(this->_state); }

1327
bool MeasurementComplexItem::idle() const { return _idle(this->_state); }
1328

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1329
bool MeasurementComplexItem::followTerrain() const { return _followTerrain; }