Skip to content
CircularSurvey.cc 40.2 KiB
Newer Older
#include "CircularSurvey.h"
#include "RoutingThread.h"
#include "JsonHelper.h"
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include "snake.h"
#define CLIPPER_SCALE 1000000
#include "clipper/clipper.hpp"

#include "Geometry/GenericCircle.h"
#include "Snake/SnakeTile.h"

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

Valentin Platzgummer's avatar
Valentin Platzgummer committed
#include "CircularGenerator.h"
#include "LinearGenerator.h"

QGC_LOGGING_CATEGORY(CircularSurveyLog, "CircularSurveyLog")

Valentin Platzgummer's avatar
Valentin Platzgummer committed
template <typename T>
constexpr typename std::underlying_type<T>::type integral(T value) {
  return static_cast<typename std::underlying_type<T>::type>(value);
}

const char *CircularSurvey::settingsGroup = "CircularSurvey";
Valentin Platzgummer's avatar
Valentin Platzgummer committed
const char *CircularSurvey::typeName = "Type";
const char *CircularSurvey::CircularSurveyName = "CircularSurvey";
const char *CircularSurvey::variantName = "Variant";

CircularSurvey::CircularSurvey(Vehicle *vehicle, bool flyView,
                               const QString &kmlOrShpFile, QObject *parent)
    : TransectStyleComplexItem(vehicle, flyView, settingsGroup, parent),
Valentin Platzgummer's avatar
Valentin Platzgummer committed
      _state(STATE::IDLE),
      _metaDataMap(FactMetaData::createMapFromJsonFile(
          QStringLiteral(":/json/CircularSurvey.SettingsGroup.json"), this)),
Valentin Platzgummer's avatar
Valentin Platzgummer committed
      _type(settingsGroup, _metaDataMap[typeName]),
      _variant(settingsGroup, _metaDataMap[variantName]),
Valentin Platzgummer's avatar
Valentin Platzgummer committed
      _areaData(std::make_shared<WimaPlanData>()),
      _pWorker(std::make_unique<RoutingThread>()) {

  Q_UNUSED(kmlOrShpFile)
  _editorQml = "qrc:/qml/CircularSurveyItemEditor.qml";

  // Connect facts.
Valentin Platzgummer's avatar
Valentin Platzgummer committed
  connect(&this->_type, &Fact::rawValueChanged, this,
          &CircularSurvey::_rebuildTransects);
  connect(&this->_variant, &Fact::rawValueChanged, this,
          &CircularSurvey::_changeVariant);
  // Connect worker.
  connect(this->_pWorker.get(), &RoutingThread::result, this,
          &CircularSurvey::_setTransects);
  connect(this->_pWorker.get(), &RoutingThread::calculatingChanged, this,
          &CircularSurvey::calculatingChanged);
  this->_transectsDirty = true;

  // Altitude
  connect(&_cameraCalc, &CameraCalc::distanceToSurfaceRelativeChanged, this,
          &CircularSurvey::coordinateHasRelativeAltitudeChanged);
  connect(&_cameraCalc, &CameraCalc::distanceToSurfaceRelativeChanged, this,
          &CircularSurvey::exitCoordinateHasRelativeAltitudeChanged);
Valentin Platzgummer's avatar
Valentin Platzgummer committed

  // Register Generators.
  auto cg = std::make_shared<routing::CircularGenerator>(this->_areaData);
  registerGenerator(cg->name(), cg);
  auto lg = std::make_shared<routing::LinearGenerator>(this->_areaData);
  registerGenerator(lg->name(), lg);
CircularSurvey::~CircularSurvey() {}

void CircularSurvey::reverse() {
  this->_state = STATE::REVERSE;
  this->_rebuildTransects();
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
void CircularSurvey::setPlanData(const WimaPlanData &d) {
  *this->_areaData = d;
QList<QString> CircularSurvey::variantNames() const { return _variantNames; }

bool CircularSurvey::load(const QJsonObject &complexObject, int sequenceNumber,
                          QString &errorString) {
  // 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;
  }

  QList<JsonHelper::KeyValidateInfo> keyInfoList = {
      {VisualMissionItem::jsonTypeKey, QJsonValue::String, true},
      {ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true},
Valentin Platzgummer's avatar
Valentin Platzgummer committed
      {transectDistanceName, QJsonValue::Double, true},
      {alphaName, QJsonValue::Double, true},
      {minLengthName, QJsonValue::Double, true},
      {typeName, QJsonValue::Double, true},
      {variantName, QJsonValue::Double, false},
      {numRunsName, QJsonValue::Double, false},
      {runName, QJsonValue::Double, false},
      {refPointLatitudeName, QJsonValue::Double, true},
      {refPointLongitudeName, QJsonValue::Double, true},
      {refPointAltitudeName, QJsonValue::Double, true},
  };

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

  QString itemType = complexObject[VisualMissionItem::jsonTypeKey].toString();
  QString complexType =
      complexObject[ComplexMissionItem::jsonComplexItemTypeKey].toString();
  if (itemType != VisualMissionItem::jsonTypeComplexItemValue ||
      complexType != CircularSurveyName) {
    errorString = tr("%1 does not support loading this complex mission item "
                     "type: %2:%3")
                      .arg(qgcApp()->applicationName())
                      .arg(itemType)
                      .arg(complexType);
    return false;
  }

  _ignoreRecalc = true;

  setSequenceNumber(sequenceNumber);

  if (!_surveyAreaPolygon.loadFromJson(complexObject, true /* required */,
                                       errorString)) {
    _surveyAreaPolygon.clear();
    return false;
  }

  if (!_load(complexObject, errorString)) {
    _ignoreRecalc = false;
    return false;
  }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
  _type.setRawValue(complexObject[typeName].toInt());
  _variant.setRawValue(complexObject[variantName].toInt());
  _numRuns.setRawValue(complexObject[numRunsName].toInt());
  _run.setRawValue(complexObject[runName].toInt());
  _referencePoint.setLongitude(complexObject[refPointLongitudeName].toDouble());
  _referencePoint.setLatitude(complexObject[refPointLatitudeName].toDouble());
  _referencePoint.setAltitude(complexObject[refPointAltitudeName].toDouble());

  _ignoreRecalc = false;

  _recalcComplexDistance();
  if (_cameraShots == 0) {
    // Shot count was possibly not available from plan file
    _recalcCameraShots();
  }

  return true;
}

QString CircularSurvey::mapVisualQML() const {
  return QStringLiteral("CircularSurveyMapVisual.qml");
}

void CircularSurvey::save(QJsonArray &planItems) {
  QJsonObject saveObject;

  _save(saveObject);

  saveObject[JsonHelper::jsonVersionKey] = 1;
  saveObject[VisualMissionItem::jsonTypeKey] =
      VisualMissionItem::jsonTypeComplexItemValue;
  saveObject[ComplexMissionItem::jsonComplexItemTypeKey] = CircularSurveyName;

Valentin Platzgummer's avatar
Valentin Platzgummer committed
  saveObject[typeName] = double(_type.rawValue().toUInt());
  saveObject[variantName] = double(_variant.rawValue().toUInt());
  saveObject[numRunsName] = double(_numRuns.rawValue().toUInt());
  saveObject[runName] = double(_numRuns.rawValue().toUInt());
  saveObject[refPointLongitudeName] = _referencePoint.longitude();
  saveObject[refPointLatitudeName] = _referencePoint.latitude();
  saveObject[refPointAltitudeName] = _referencePoint.altitude();

  // Polygon shape
  _surveyAreaPolygon.saveToJson(saveObject);

  planItems.append(saveObject);
}

bool CircularSurvey::specifiesCoordinate() const { return true; }

Loading
Loading full blame...