MeasurementComplexItem.cc 40.2 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";
Valentin Platzgummer's avatar
Valentin Platzgummer committed
44
const char *connectionsStringKey = "ConnectionString";
45
} // namespace
Valentin Platzgummer's avatar
Valentin Platzgummer committed
46 47 48 49

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

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
  // 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);

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

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

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

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

105
  // Connect isIncomplete.
Valentin Platzgummer's avatar
Valentin Platzgummer committed
106
  connect(this, &MeasurementComplexItem::idleChanged, this, [this] {
107 108 109 110 111 112 113 114 115 116 117 118
    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();
      }
    }
  });
119 120

  // Connect readyForSave
121 122 123
  connect(this, &MeasurementComplexItem::idleChanged, this,
          &MeasurementComplexItem::readyForSaveStateChanged);

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

128
  // Connect complexDistance.
Valentin Platzgummer's avatar
Valentin Platzgummer committed
129
  connect(this, &MeasurementComplexItem::routeChanged, this,
130 131
          [this] { emit this->complexDistanceChanged(); });

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

  // connect to nemo interface
Valentin Platzgummer's avatar
Valentin Platzgummer committed
136
  connect(pNemoInterface, &Nemointerface::progressChanged, this,
Valentin Platzgummer's avatar
Valentin Platzgummer committed
137
          &MeasurementComplexItem::_onNewProgress);
138 139
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
140
MeasurementComplexItem::~MeasurementComplexItem() {}
141

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

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

148
AreaData *MeasurementComplexItem::areaData() { return this->_pCurrentData; }
149

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

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

Valentin Platzgummer's avatar
Valentin Platzgummer committed
156 157
bool MeasurementComplexItem::load(const QJsonObject &complexObject,
                                  int sequenceNumber, QString &errorString) {
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
  // 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;
  }

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

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

184 185 186 187 188 189 190 191 192 193 194 195
    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;
    }
196 197 198
  }

  setSequenceNumber(sequenceNumber);
199 200
  startEditing();

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

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

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

228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
    } 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.
243 244
  if (complexObject.contains(generatorArrayKey) &&
      complexObject[generatorArrayKey].isArray()) {
245 246 247 248

    QVector<PtrGenerator> generatorList;
    QObject parent;

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

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

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

        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");
276
          if (!pGeneratorFactory->registered(
277 278 279 280 281 282 283 284 285 286
                  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";
          }
287 288
          abortEditing();
          return false;
289 290 291
        }

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

      // insert generators
      for (const auto gen : generatorList) {
        gen->setParent(this);
300
        addGenerator(gen);
301 302 303 304 305
      }
    }
  } else {
    errorString.append(
        tr("No generators found in file. Leaving generators unchanged.\n"));
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
    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);
322 323 324
  }

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

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

357 358 359 360 361 362 363 364 365 366
    // 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;
      }
    }

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

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

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

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

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

407
      for (const auto &name : complexObject[variantNamesKey].toArray()) {
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
        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();
    }

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

    _changeVariantIndex();
  } else {
    stopEditing(); // stop editing and trigger update
452
  }
453

454
  return true;
455 456
}

457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
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
475 476 477 478 479 480 481 482
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");
483 484
}

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

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

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

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

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

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

530
    // generator index
531
    saveObject[generatorIndexKey] = generatorIndex();
532

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

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

Valentin Platzgummer's avatar
Valentin Platzgummer committed
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
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();
}

569 570 571 572 573 574 575 576 577 578 579 580
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
581 582 583 584 585 586 587
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
588 589
  return this->_route.size() > 0 ? _route.first().value<QGeoCoordinate>()
                                 : QGeoCoordinate();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
590 591 592
}

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

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
613

614
  if (idle()) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
    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
639 640 641 642 643 644
  }
}

void MeasurementComplexItem::setMissionFlightStatus(
    const MissionController::MissionFlightStatus_t &missionFlightStatus) {
  ComplexMissionItem::setMissionFlightStatus(missionFlightStatus);
645 646
}

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

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

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

    this->_pGenerator = newG;
661 662 663 664 665 666

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

667 668
    emit generatorChanged();

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

    return true;
  } else {
    return false;
  }
}

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

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

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

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

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

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

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

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

  _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();

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

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

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();
  }
}
777

Valentin Platzgummer's avatar
Valentin Platzgummer committed
778 779 780 781 782 783 784 785 786 787 788
QString MeasurementComplexItem::nemoError() const { return _nemoError; }

void MeasurementComplexItem::_setNemoError(const QString &nemoError) {
  if (_nemoError != nemoError) {
    _nemoError = nemoError;
    emit nemoErrorChanged();
  }
}

Fact *MeasurementComplexItem::nemoCString() { return &_nemoCString; }

789 790 791 792 793 794 795 796
bool MeasurementComplexItem::holdProgress() const { return _holdProgress; }

void MeasurementComplexItem::setHoldProgress(bool holdProgress) {
  if (_holdProgress != holdProgress) {
    _holdProgress = holdProgress;
    emit holdProgressChanged();

    if (_holdProgress) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
797
      disconnect(pNemoInterface, &Nemointerface::progressChanged, this,
798 799
                 &MeasurementComplexItem::_onNewProgress);
    } else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
800
      connect(pNemoInterface, &Nemointerface::progressChanged, this,
801 802 803 804 805
              &MeasurementComplexItem::_onNewProgress);
      _onNewProgress(pNemoInterface->getProgress());
    }
  }
}
Valentin Platzgummer's avatar
Valentin Platzgummer committed
806 807
void MeasurementComplexItem::_setAreaData(
    MeasurementComplexItem::PtrAreaData data) {
808 809
  if (_pCurrentData != data) {
    _pCurrentData = data;
810 811 812 813
    emit areaDataChanged();
  }
}

814 815 816 817
void MeasurementComplexItem::_updateRoute() {
  if (!editing()) {
    // Reset data.
    this->_route.clear();
818
    emit routeChanged();
819 820 821 822 823 824
    this->_variantVector.clear();
    this->_variantNames.clear();
    emit variantNamesChanged();

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

825 826 827 828 829 830 831 832 833 834 835 836 837 838
      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;
      }

839 840 841 842
      // Prepare data.
      auto origin = this->_pAreaData->origin();
      origin.setAltitude(0);
      if (!origin.isValid()) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
843
        qCDebug(MeasurementComplexItemLog)
844 845
            << "_updateWorker(): origin invalid." << origin;
        return;
846 847
      }

848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
      // 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;
        }
      }
867

868 869 870 871
      // Routing par.
      RoutingParameter par;
      par.numSolutions = 5;
      auto &safeAreaENU = par.safeArea;
872
      geometry::areaToEnu(origin, geoSafeArea, safeAreaENU);
873 874 875

      // Create generator.
      if (this->_pGenerator != nullptr) {
876
        routing::GeneratorBase::Work g; // Transect generator.
877 878 879 880 881 882 883 884 885 886
        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;
        }
887
      } else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
888
        qCDebug(MeasurementComplexItemLog)
889 890 891 892
            << "_updateWorker(): pGenerator == nullptr, number of registered "
               "generators: "
            << this->_generatorList.size();
        return;
893 894
      }
    } else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
895
      qCDebug(MeasurementComplexItemLog)
896
          << "_updateWorker(): area data invalid.";
897
      return;
898 899 900 901
    }
  }
}

902
void MeasurementComplexItem::_changeVariantIndex() {
903
  if (idle()) {
904
    auto variant = this->_variantIndex.rawValue().toUInt();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
905

906
    // Find old variant. Old variant corresponts with empty list.
Valentin Platzgummer's avatar
Valentin Platzgummer committed
907 908 909 910 911 912 913
    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;
      }
914 915
    }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
916 917 918 919 920 921 922
    // 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
923 924
          auto &oldRoute = this->_variantVector[old_variant];
          oldRoute.swap(this->_route);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
925
        }
926 927
        auto &newRoute = this->_variantVector[variant];
        this->_route.swap(newRoute);
928
        emit routeChanged();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
929 930 931 932
      } else { // error
        qCDebug(MeasurementComplexItemLog)
            << "Variant out of bounds (variant =" << variant << ").";
        qCDebug(MeasurementComplexItemLog) << "Resetting variant to zero.";
933

934 935 936 937 938
        disconnect(&this->_variantIndex, &Fact::rawValueChanged, this,
                   &MeasurementComplexItem::_changeVariantIndex);
        this->_variantIndex.setCookedValue(QVariant(0));
        connect(&this->_variantIndex, &Fact::rawValueChanged, this,
                &MeasurementComplexItem::_changeVariantIndex);
939

Valentin Platzgummer's avatar
Valentin Platzgummer committed
940
        if (this->_variantVector.size() > 0) {
941
          this->_changeVariantIndex();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
942
        }
943 944 945 946 947
      }
    }
  }
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
948
void MeasurementComplexItem::_reverseRoute() {
949
  if (idle()) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
950 951 952 953
    if (this->_route.size() > 0) {
      auto &t = this->_route;
      std::reverse(t.begin(), t.end());
    }
954
    emit routeChanged();
955 956 957
  }
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
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) {
974 975 976
      (void)pNemoInterface->clearTiles();
      (void)pNemoInterface->addTiles(tilePtrArray);
      return;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
977 978 979 980 981 982 983 984
    } else {
      clear = true;
    }
  } else {
    clear = true;
  }

  if (clear) {
985
    (void)pNemoInterface->clearTiles();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
986 987 988 989 990 991 992 993 994 995 996 997
  }
}

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
998
ComplexMissionItem::ReadyForSaveState
Valentin Platzgummer's avatar
Valentin Platzgummer committed
999
MeasurementComplexItem::readyForSaveState() const {
1000
  if (idle()) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1001
    return ReadyForSaveState::ReadyForSave;
1002
  } else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1003
    return ReadyForSaveState::NotReadyForSaveData;
1004 1005 1006
  }
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1007 1008 1009 1010
bool MeasurementComplexItem::exitCoordinateSameAsEntry() const {
  return this->_route.size() > 0 ? this->_route.first() == this->_route.last()
                                 : false;
}
1011

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1012 1013 1014 1015 1016 1017
void MeasurementComplexItem::setDirty(bool dirty) {
  if (this->_dirty != dirty) {
    this->_dirty = dirty;
    emit dirtyChanged(this->_dirty);
  }
}
1018

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
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; }

1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
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);
}

1050
bool MeasurementComplexItem::addGenerator(routing::GeneratorBase *g) {
1051

1052
  if (g == nullptr) {
1053
    qCDebug(MeasurementComplexItemLog) << "addGenerator(): empty generator.";
1054
    Q_ASSERT(g != nullptr);
1055 1056 1057
    return false;
  }

1058 1059 1060 1061 1062 1063 1064
  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;
1065
    }
1066
  }
1067

1068 1069 1070
  this->_generatorList.push_back(g);
  if (this->_generatorList.size() == 1) {
    _setGenerator(g);
1071
  }
1072 1073 1074

  emit generatorListChanged();
  return true;
1075 1076
}

1077
bool MeasurementComplexItem::removeGenerator(const QString &name) {
1078 1079 1080 1081 1082
  return removeGenerator(generatorIndex(name));
}

bool MeasurementComplexItem::removeGenerator(int index) {
  if (index >= 0 && index < this->_generatorList.size()) {
1083 1084 1085 1086
    // Is this the current generator?
    const auto &g = this->_generatorList.at(index);
    if (g == this->_pGenerator) {
      if (index > 0) {
1087
        _setGenerator(this->_generatorList.at(index - 1));
1088 1089
      } else if (index + 1 < _generatorList.size()) {
        _setGenerator(this->_generatorList.at(index + 1));
1090
      } else {
1091
        _setGenerator(nullptr);
1092 1093 1094
      }
    }

1095
    auto gen = this->_generatorList.takeAt(index);
1096

1097 1098 1099 1100
    // Should the generator be deleted?
    if (gen->parent() == this || gen->parent() == nullptr) {
      gen->deleteLater();
    }
1101

1102 1103
    emit generatorListChanged();
    return true;
1104
  } else {
1105 1106 1107 1108
    qCDebug(MeasurementComplexItemLog) << "removeGenerator(): index (" << index
                                       << ") out"
                                          "of bounds ( "
                                       << this->_generatorList.size() << " ).";
1109 1110 1111 1112
    return false;
  }
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1113
bool MeasurementComplexItem::switchToGenerator(const QString &name) {
1114
  return switchToGenerator(generatorIndex(name));
1115 1116
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1117
bool MeasurementComplexItem::switchToGenerator(int index) {
1118
  if (index >= 0 && index < _generatorList.size()) {
1119
    _setGenerator(this->_generatorList.at(index));
1120 1121
    return true;
  } else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1122
    qCDebug(MeasurementComplexItemLog)
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1123
        << "switchToGenerator(): index (" << index
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1124 1125
        << ") out"
           "of bounds ( "
1126
        << this->_generatorList.size() << " ).";
1127 1128 1129 1130
    return false;
  }
}

1131 1132 1133 1134
void MeasurementComplexItem::resetGenerators() {
  while (_generatorList.size() > 0) {
    removeGenerator(0);
  }
1135

1136 1137
  auto lg =
      pGeneratorFactory->create(routing::LinearGenerator::typeString, this);
1138 1139 1140
  lg->setData(this->_pAreaData);
  addGenerator(lg);

1141 1142
  auto cg =
      pGeneratorFactory->create(routing::CircularGenerator::typeString, this);
1143 1144 1145 1146 1147 1148 1149
  cg->setData(this->_pAreaData);
  addGenerator(cg);
}

QList<MeasurementComplexItem::PtrGenerator>
MeasurementComplexItem::generatorList() const {
  return _generatorList;
1150 1151
}

1152
QStringList MeasurementComplexItem::generatorNameList() const {
1153 1154 1155 1156 1157
  QStringList list;
  for (const auto gen : _generatorList) {
    list.append(gen->name());
  }
  return list;
1158 1159
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1160 1161 1162
routing::GeneratorBase *MeasurementComplexItem::generator() {
  return _pGenerator;
}
1163

1164 1165 1166 1167 1168 1169
const routing::GeneratorBase *MeasurementComplexItem::generator() const {
  return _pGenerator;
}

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

routing::GeneratorBase *MeasurementComplexItem::generator(int index) {
1178
  if (index >= 0 && index < _generatorList.size()) {
1179 1180 1181 1182 1183 1184 1185
    return _generatorList[index];
  } else {
    return nullptr;
  }
}

int MeasurementComplexItem::generatorIndex() const {
1186 1187 1188
  return this->_generatorList.indexOf(this->_pGenerator);
}

1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
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;
}

1201 1202
void MeasurementComplexItem::startEditing() {
  if (!editing()) {
1203 1204
    *_pEditorData = *_pAreaData;
    _setAreaData(_pEditorData);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1205
    _setState(STATE::EDITING);
1206 1207 1208
  }
}

1209
bool MeasurementComplexItem::stopEditing(bool doUpdate) {
1210
  if (editing()) {
1211
    bool isDifferent = *_pEditorData != *_pAreaData;
1212 1213
    bool correct = _pEditorData->isCorrect();
    if (correct) {
1214
      *_pAreaData = *_pEditorData;
1215
    }
1216
    _setAreaData(_pAreaData);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1217
    _setState(STATE::IDLE);
1218 1219 1220
    bool updated = false;
    if (doUpdate && correct && isDifferent) {
      updated = true;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1221
      _updateRoute();
1222
    }
1223

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1224 1225 1226 1227
    if (correct && isDifferent) {
      _syncTiles();
    }

1228
    return updated;
1229
  }
1230
  return false;
1231 1232
}

1233 1234 1235
void MeasurementComplexItem::abortEditing() {
  if (editing()) {
    _setAreaData(_pAreaData);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1236
    _syncTiles();
1237 1238 1239 1240
    _setState(STATE::IDLE);
  }
}

1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
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
1259
void MeasurementComplexItem::_storeRoutingData(
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1260
    MeasurementComplexItem::PtrRoutingData pRoute) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1261 1262
  if (this->_state == STATE::ROUTING) {
    // Store solutions.
1263
    auto ori = this->_pAreaData->origin();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1264 1265
    ori.setAltitude(0);
    QVector<Variant> variantVector;
1266
    const std::size_t nSolutions = pRoute->solutionVector.size();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1267 1268 1269 1270 1271 1272 1273

    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;
1274 1275 1276 1277 1278

        // Convert to geo coordinates.

        for (const auto &vertex : path) {
          QGeoCoordinate c;
1279
          geometry::fromENU(ori, vertex, c);
1280
          var.append(QVariant::fromValue(c));
1281 1282
        }
      } else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1283
        qCDebug(MeasurementComplexItemLog)
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1284
            << "_setTransects(): solution.size() == 0";
1285 1286
      }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1287 1288 1289
      if (var.size() > 0) {
        variantVector.push_back(std::move(var));
      }
1290 1291
    }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1292 1293 1294 1295
    // Assign routes if no error occured.
    if (variantVector.size() > 0) {
      // Swap first route to _route.
      this->_variantVector.swap(variantVector);
1296

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1297 1298 1299 1300 1301 1302 1303
      // 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();
1304

1305
      // Set variant to 0.
1306 1307 1308 1309 1310
      disconnect(&this->_variantIndex, &Fact::rawValueChanged, this,
                 &MeasurementComplexItem::_changeVariantIndex);
      this->_variantIndex.setCookedValue(QVariant(0));
      connect(&this->_variantIndex, &Fact::rawValueChanged, this,
              &MeasurementComplexItem::_changeVariantIndex);
1311

1312
      // Select first variant as route.
1313
      this->_route.swap(this->_variantVector.first());
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1314
      emit routeChanged();
1315 1316

      this->_setState(STATE::IDLE);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1317 1318 1319 1320 1321
    } else {
      qCDebug(MeasurementComplexItemLog)
          << "_setTransects(): failed, variantVector empty.";
      this->_setState(STATE::IDLE);
    }
1322 1323 1324
  }
}

1325
Fact *MeasurementComplexItem::variantIndex() { return &_variantIndex; }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1326 1327

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

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1329
bool MeasurementComplexItem::calculating() const {
1330 1331 1332
  return this->_calculating(this->_state);
}

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

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

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