SafeArea.cc 3.66 KB
Newer Older
1
#include "SafeArea.h"
2

3
#include "JsonHelper.h"
4 5 6
#include "QGCLoggingCategory.h"
#include "QGCQGeoCoordinate.h"

7
#include <QJsonObject>
8

9
QGC_LOGGING_CATEGORY(SafeAreaLog, "SafeAreaLog")
10

11
const char *SafeArea::name = "Safe Area";
12
const char *depotKey = "Depot Point";
13

14 15 16 17
SafeArea::SafeArea(QObject *parent) : GeoArea(parent) { init(); }

SafeArea::SafeArea(const SafeArea &other, QObject *parent)
    : GeoArea(other, parent), _depot(other.depot()) {
18 19 20
  init();
}

21 22
SafeArea &SafeArea::operator=(const SafeArea &other) {
  GeoArea::operator=(other);
23 24 25 26
  this->setDepot(other.depot());
  return *this;
}

27 28 29 30
QString SafeArea::mapVisualQML() const {
  return "SafeAreaMapVisual.qml";
  // return "";
}
31 32 33 34 35 36 37 38

QString SafeArea::editorQML() const { return "SafeAreaEditor.qml"; }

SafeArea *SafeArea::clone(QObject *parent) const {
  return new SafeArea(*this, parent);
}

const QGeoCoordinate &SafeArea::depot() const { return _depot; }
39

40
QGeoCoordinate SafeArea::depotQml() const { return _depot; }
41

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
void SafeArea::putDepotInside() {
  if (!this->containsCoordinate(this->_depot) &&
      this->pathModel().count() > 0) {
    if (this->_depot.isValid()) {
      // Use nearest coordinate.
      auto minDist = std::numeric_limits<double>::infinity();
      int minIndex = 0;
      for (int idx = 0; idx < this->pathModel().count(); ++idx) {
        const QObject *obj = this->pathModel()[idx];
        const auto *vertex = qobject_cast<const QGCQGeoCoordinate *>(obj);
        if (vertex != nullptr) {
          auto d = vertex->coordinate().distanceTo(this->_depot);
          if (d < minDist) {
            minDist = d;
            minIndex = idx;
          }
        } else {
          qCCritical(SafeAreaLog) << "init(): nullptr catched!";
        }
      }
      this->setDepot(
          this->pathModel().value<QGCQGeoCoordinate *>(minIndex)->coordinate());
    } else {
      // Use first coordinate.
      this->setDepot(
          this->pathModel().value<QGCQGeoCoordinate *>(0)->coordinate());
    }
  }
}

bool SafeArea::setDepot(const QGeoCoordinate &newDepot) {
  if (_depot.latitude() != newDepot.latitude() ||
      _depot.longitude() != newDepot.longitude()) {
75
    if (this->covers(newDepot)) {
76
      _depot = newDepot;
77 78 79 80 81 82 83 84
      _depot.setAltitude(0);
      emit depotChanged();
      return true;
    }
  }
  return false;
}

85 86 87 88 89 90 91 92 93 94 95 96 97
bool SafeArea::saveToJson(QJsonObject &json) {
  if (this->GeoArea::saveToJson(json)) {
    json[areaTypeKey] = name;

    QJsonValue jsonDepot;
    JsonHelper::saveGeoCoordinate(_depot, false, jsonDepot);
    json[depotKey] = jsonDepot;

    return true;
  } else {
    qCDebug(SafeAreaLog) << "saveToJson(): error in GeoArea::safeToJson()";
  }
  return false;
98 99
}

100
bool SafeArea::loadFromJson(const QJsonObject &json, QString &errorString) {
101 102 103 104 105 106 107 108 109
  bool returnValue = true;

  if (!this->GeoArea::loadFromJson(json, errorString)) {
    returnValue = false;
  }

  QList<JsonHelper::KeyValidateInfo> versionKeyInfoList = {
      {depotKey, QJsonValue::Array, true},
  };
110
  if (!JsonHelper::validateKeys(json, versionKeyInfoList, errorString)) {
111 112 113 114 115
    returnValue = false;
  } else {
    const auto &jsonDepot = json[depotKey];
    if (!JsonHelper::loadGeoCoordinate(jsonDepot, false, _depot, errorString)) {
      returnValue = false;
116 117
    }
  }
118 119

  return returnValue;
120 121
}

122 123 124
bool SafeArea::isCorrect() {
  if (GeoArea::isCorrect()) {
    if (this->_depot.isValid()) {
125
      if (this->covers(this->_depot)) {
126 127 128
        return true;
      } else {
        setErrorString(tr("Depot outside Safe Area"));
129
      }
130 131
    } else {
      qCritical(SafeAreaLog) << "Depot invalid " << _depot;
132
    }
133 134 135 136 137
  }
  return false;
}

void SafeArea::init() {
138
  this->setObjectName(name);
139
  connect(this, &GeoArea::pathChanged, this, &SafeArea::putDepotInside);
140
}