Commit 1b05f323 authored by Valentin Platzgummer's avatar Valentin Platzgummer

MeasurementItemEditor improved

parent 31d4efc3
...@@ -34,14 +34,13 @@ DebugBuild { ...@@ -34,14 +34,13 @@ DebugBuild {
DEFINES += DEBUG DEFINES += DEBUG
#DEFINES += SNAKE_SHOW_TIME #DEFINES += SNAKE_SHOW_TIME
#DEFINES += SNAKE_DEBUG #DEFINES += SNAKE_DEBUG
DEFINES += SNAKE_SHOW_TIME #DEFINES += SNAKE_SHOW_TIME
DEFINES += DEBUG_CIRCULAR_SURVEY
DEFINES += ROS_BRIDGE_DEBUG DEFINES += ROS_BRIDGE_DEBUG
} }
else { else {
DESTDIR = $${OUT_PWD}/release DESTDIR = $${OUT_PWD}/release
#DEFINES += ROS_BRIDGE_DEBUG #DEFINES += ROS_BRIDGE_DEBUG
DEFINES += SNAKE_SHOW_TIME #DEFINES += SNAKE_SHOW_TIME
#DEFINES += SNAKE_DEBUG #DEFINES += SNAKE_DEBUG
DEFINES += NDEBUG DEFINES += NDEBUG
} }
......
...@@ -18,8 +18,7 @@ AreaData::AreaData(QObject *parent) : QObject(parent) {} ...@@ -18,8 +18,7 @@ AreaData::AreaData(QObject *parent) : QObject(parent) {}
AreaData::~AreaData() {} AreaData::~AreaData() {}
AreaData::AreaData(const AreaData &other, QObject *parent) AreaData::AreaData(const AreaData &other, QObject *parent) : QObject(parent) {
: QObject(parent), _showErrorMessages(true) {
*this = other; *this = other;
} }
...@@ -93,21 +92,21 @@ const QmlObjectListModel *AreaData::areaList() const { return &_areaList; } ...@@ -93,21 +92,21 @@ const QmlObjectListModel *AreaData::areaList() const { return &_areaList; }
QGeoCoordinate AreaData::origin() const { return _origin; } QGeoCoordinate AreaData::origin() const { return _origin; }
bool AreaData::isCorrect() { bool AreaData::isCorrect(bool showError) {
if (!initialized()) { if (!initialized()) {
qCWarning(AreaDataLog) << "isCorrect(): not initialized"; qCWarning(AreaDataLog) << "isCorrect(): not initialized";
return false; return false;
} }
// Check if areas are correct // Check if areas are correct
if (!_areasCorrect()) { if (!_areasCorrect(showError)) {
return false; return false;
} }
// Check if areas where added. // Check if areas where added.
MeasurementArea *measurementArea = nullptr; MeasurementArea *measurementArea = nullptr;
SafeArea *safeArea = nullptr; SafeArea *safeArea = nullptr;
if (!_getAreas(&measurementArea, &safeArea)) { if (!_getAreas(&measurementArea, &safeArea, showError)) {
return false; return false;
} }
...@@ -128,7 +127,8 @@ bool AreaData::isCorrect() { ...@@ -128,7 +127,8 @@ bool AreaData::isCorrect() {
// qDebug() << ss.str().c_str(); // qDebug() << ss.str().c_str();
if (!bg::covered_by(measurementAreaENU, safeAreaENU)) { if (!bg::covered_by(measurementAreaENU, safeAreaENU)) {
_processError(tr("Measurement Area not inside Safe Area. Please adjust " _processError(tr("Measurement Area not inside Safe Area. Please adjust "
"the Measurement Area.\n")); "the Measurement Area.\n"),
showError);
return false; return false;
} }
...@@ -209,11 +209,11 @@ bool AreaData::initialized() { ...@@ -209,11 +209,11 @@ bool AreaData::initialized() {
measurementArea->count() >= 3 && safeArea->count() >= 3; measurementArea->count() >= 3 && safeArea->count() >= 3;
} }
void AreaData::intersection() { void AreaData::intersection(bool showError) {
if (initialized() && _areasCorrect()) { if (initialized() && _areasCorrect(showError)) {
MeasurementArea *measurementArea = nullptr; MeasurementArea *measurementArea = nullptr;
SafeArea *safeArea = nullptr; SafeArea *safeArea = nullptr;
if (_getAreas(&measurementArea, &safeArea)) { if (_getAreas(&measurementArea, &safeArea, showError)) {
// convert to ENU // convert to ENU
const auto origin = this->origin(); const auto origin = this->origin();
...@@ -230,7 +230,8 @@ void AreaData::intersection() { ...@@ -230,7 +230,8 @@ void AreaData::intersection() {
if (outputENU.size() < 1 || outputENU[0].outer().size() < 4) { if (outputENU.size() < 1 || outputENU[0].outer().size() < 4) {
_processError( _processError(
"Intersection did't deliver any result. Measurement Area and " "Intersection did't deliver any result. Measurement Area and "
"Safe Area must touch each other."); "Safe Area must touch each other.",
showError);
return; return;
} }
...@@ -238,7 +239,8 @@ void AreaData::intersection() { ...@@ -238,7 +239,8 @@ void AreaData::intersection() {
_processError( _processError(
"Hint: Only simple polygons can be displayed. If Intersection" "Hint: Only simple polygons can be displayed. If Intersection"
"produces polygons with holes or multi polygons, only " "produces polygons with holes or multi polygons, only "
"partial information can be displayed."); "partial information can be displayed.",
showError);
} }
// Shrink the result if safeAreaENU doesn't cover it. // Shrink the result if safeAreaENU doesn't cover it.
...@@ -247,16 +249,18 @@ void AreaData::intersection() { ...@@ -247,16 +249,18 @@ void AreaData::intersection() {
while (!bg::covered_by(large, safeAreaENU)) { while (!bg::covered_by(large, safeAreaENU)) {
snake::offsetPolygon(large, small, -0.1); snake::offsetPolygon(large, small, -0.1);
large = std::move(small); large = std::move(small);
qDebug() << "intersection(): shrink";
} }
// Convert. // Check if result is different from input.
measurementArea->clear(); if (!bg::equals(large, measurementAreaENU)) {
for (auto it = large.outer().begin(); it != large.outer().end() - 1; // Convert.
++it) { measurementArea->clear();
QGeoCoordinate c; for (auto it = large.outer().begin(); it != large.outer().end() - 1;
snake::fromENU(origin, *it, c); ++it) {
measurementArea->appendVertex(c); QGeoCoordinate c;
snake::fromENU(origin, *it, c);
measurementArea->appendVertex(c);
}
} }
} }
} }
...@@ -302,7 +306,7 @@ bool AreaData::load(const QJsonObject &obj, QString &errorString) { ...@@ -302,7 +306,7 @@ bool AreaData::load(const QJsonObject &obj, QString &errorString) {
// load MeasurementArea // load MeasurementArea
if (jsonArea[GeoArea::areaTypeKey].toString() == if (jsonArea[GeoArea::areaTypeKey].toString() ==
MeasurementArea::name) { MeasurementArea::nameString) {
auto area = getGeoArea<MeasurementArea *>(_areaList); auto area = getGeoArea<MeasurementArea *>(_areaList);
...@@ -325,7 +329,8 @@ bool AreaData::load(const QJsonObject &obj, QString &errorString) { ...@@ -325,7 +329,8 @@ bool AreaData::load(const QJsonObject &obj, QString &errorString) {
} }
} }
// load SafeArea // load SafeArea
else if (jsonArea[GeoArea::areaTypeKey].toString() == SafeArea::name) { else if (jsonArea[GeoArea::areaTypeKey].toString() ==
SafeArea::nameString) {
auto area = getGeoArea<SafeArea *>(_areaList); auto area = getGeoArea<SafeArea *>(_areaList);
if (area == nullptr) { if (area == nullptr) {
...@@ -394,7 +399,6 @@ bool AreaData::save(QJsonObject &obj) { ...@@ -394,7 +399,6 @@ bool AreaData::save(QJsonObject &obj) {
} else { } else {
qDebug(AreaDataLog) << "save(): not able to save area: " qDebug(AreaDataLog) << "save(): not able to save area: "
<< area->objectName(); << area->objectName();
_processError(tr("Not able to save area: ") + area->objectName());
return false; return false;
} }
} }
...@@ -411,21 +415,21 @@ void AreaData::_setOrigin(const QGeoCoordinate &origin) { ...@@ -411,21 +415,21 @@ void AreaData::_setOrigin(const QGeoCoordinate &origin) {
} }
} }
void AreaData::_processError(const QString &str) { void AreaData::_processError(const QString &str, bool showError) {
this->_errorString = str; this->_errorString = str;
emit error(); emit error();
if (_showErrorMessages) { if (showError) {
qgcApp()->informationMessageBoxOnMainThread(tr("Area Editor"), qgcApp()->informationMessageBoxOnMainThread(tr("Area Editor"),
this->errorString()); this->errorString());
} }
} }
bool AreaData::_areasCorrect() { bool AreaData::_areasCorrect(bool showError) {
// Check if areas are correct. // Check if areas are correct.
for (int i = 0; i < _areaList.count(); ++i) { for (int i = 0; i < _areaList.count(); ++i) {
auto *area = _areaList.value<GeoArea *>(0); auto *area = _areaList.value<GeoArea *>(i);
if (!area->isCorrect()) { if (!area->isCorrect()) {
_processError(area->errorString()); _processError(area->errorString(), showError);
return false; return false;
} }
} }
...@@ -433,30 +437,25 @@ bool AreaData::_areasCorrect() { ...@@ -433,30 +437,25 @@ bool AreaData::_areasCorrect() {
return true; return true;
} }
bool AreaData::_getAreas(MeasurementArea **measurementArea, bool AreaData::_getAreas(MeasurementArea **measurementArea, SafeArea **safeArea,
SafeArea **safeArea) { bool showError) {
*measurementArea = getGeoArea<MeasurementArea *>(_areaList); *measurementArea = getGeoArea<MeasurementArea *>(_areaList);
if (*measurementArea == nullptr) { if (*measurementArea == nullptr) {
_processError( _processError(
tr("Measurement Area missing. Please define a measurement area.")); tr("Measurement Area missing. Please define a measurement area."),
showError);
return false; return false;
} }
*safeArea = getGeoArea<SafeArea *>(_areaList); *safeArea = getGeoArea<SafeArea *>(_areaList);
if (*safeArea == nullptr) { if (*safeArea == nullptr) {
_processError(tr("Safe Area missing. Please define a safe area.")); _processError(tr("Safe Area missing. Please define a safe area."),
showError);
return false; return false;
} }
return true; return true;
} }
void AreaData::setShowErrorMessages(bool showErrorMessages) {
if (showErrorMessages != _showErrorMessages) {
_showErrorMessages = showErrorMessages;
emit showErrorMessagesChanged();
}
}
void AreaData::_updateOrigin() { void AreaData::_updateOrigin() {
auto *measurementArea = getGeoArea<MeasurementArea *>(_areaList); auto *measurementArea = getGeoArea<MeasurementArea *>(_areaList);
if (measurementArea != nullptr) { if (measurementArea != nullptr) {
...@@ -464,6 +463,4 @@ void AreaData::_updateOrigin() { ...@@ -464,6 +463,4 @@ void AreaData::_updateOrigin() {
} }
} }
bool AreaData::showErrorMessages() const { return _showErrorMessages; }
QString AreaData::errorString() const { return _errorString; } QString AreaData::errorString() const { return _errorString; }
...@@ -20,8 +20,7 @@ public: ...@@ -20,8 +20,7 @@ public:
AreaData &operator=(const AreaData &other); AreaData &operator=(const AreaData &other);
Q_PROPERTY(QmlObjectListModel *areaList READ areaList NOTIFY areaListChanged) Q_PROPERTY(QmlObjectListModel *areaList READ areaList NOTIFY areaListChanged)
Q_PROPERTY(bool showErrorMessages READ showErrorMessages WRITE Q_PROPERTY(QString errorString READ errorString NOTIFY error)
setShowErrorMessages NOTIFY showErrorMessagesChanged)
// Member Methodes // Member Methodes
//! //!
...@@ -51,7 +50,7 @@ public: ...@@ -51,7 +50,7 @@ public:
//! \note Origin might change if the list of areas changes. //! \note Origin might change if the list of areas changes.
QGeoCoordinate origin() const; QGeoCoordinate origin() const;
Q_INVOKABLE bool isCorrect(); Q_INVOKABLE bool isCorrect(bool showError = true);
//! //!
//! \brief initialize Initializes the areas in a valid way, such that they //! \brief initialize Initializes the areas in a valid way, such that they
//! area inside the bounding box. \param bottomLeft bottom left corner of the //! area inside the bounding box. \param bottomLeft bottom left corner of the
...@@ -69,7 +68,7 @@ public: ...@@ -69,7 +68,7 @@ public:
//! either. //! either.
//! //!
Q_INVOKABLE bool initialized(); Q_INVOKABLE bool initialized();
Q_INVOKABLE void intersection(); Q_INVOKABLE void intersection(bool showError = true);
Q_INVOKABLE MeasurementArea *measurementArea(); Q_INVOKABLE MeasurementArea *measurementArea();
Q_INVOKABLE SafeArea *safeArea(); Q_INVOKABLE SafeArea *safeArea();
...@@ -82,25 +81,21 @@ public: ...@@ -82,25 +81,21 @@ public:
QString errorString() const; // Contains a message about the last error. QString errorString() const; // Contains a message about the last error.
bool showErrorMessages() const;
void setShowErrorMessages(bool showErrorMessages);
signals: signals:
void areaListChanged(); void areaListChanged();
void originChanged(); void originChanged();
void error(); // Emitted if errorString() contains a new message. void error(); // Emitted if errorString() contains a new message.
void showErrorMessagesChanged();
private slots: private slots:
void _updateOrigin(); void _updateOrigin();
private: private:
void _setOrigin(const QGeoCoordinate &origin); void _setOrigin(const QGeoCoordinate &origin);
void _processError(const QString &str); void _processError(const QString &str, bool showError);
bool _areasCorrect(); bool _areasCorrect(bool showError);
bool _getAreas(MeasurementArea **measurementArea, SafeArea **safeArea); bool _getAreas(MeasurementArea **measurementArea, SafeArea **safeArea,
bool showError);
QGeoCoordinate _origin; QGeoCoordinate _origin;
QmlObjectListModel _areaList; QmlObjectListModel _areaList;
QString _errorString; QString _errorString;
bool _showErrorMessages;
}; };
...@@ -406,6 +406,7 @@ void CircularGenerator::setMeasurementArea(MeasurementArea *area) { ...@@ -406,6 +406,7 @@ void CircularGenerator::setMeasurementArea(MeasurementArea *area) {
&CircularGenerator::resetReferenceIfInvalid); &CircularGenerator::resetReferenceIfInvalid);
connect(_measurementArea, &MeasurementArea::pathChanged, this, connect(_measurementArea, &MeasurementArea::pathChanged, this,
&GeneratorBase::generatorChanged); &GeneratorBase::generatorChanged);
resetReferenceIfInvalid();
} }
emit generatorChanged(); emit generatorChanged();
...@@ -438,16 +439,13 @@ bool circularTransects(const snake::FPoint &reference, ...@@ -438,16 +439,13 @@ bool circularTransects(const snake::FPoint &reference,
distances.reserve(polygon.outer().size()); distances.reserve(polygon.outer().size());
std::vector<snake::Angle> angles; std::vector<snake::Angle> angles;
angles.reserve(polygon.outer().size()); angles.reserve(polygon.outer().size());
//#ifdef DEBUG_CIRCULAR_SURVEY
// qCDebug(CircularGeneratorLog) << "circularTransects():"; // qCDebug(CircularGeneratorLog) << "circularTransects():";
//#endif
for (const auto &p : polygon.outer()) { for (const auto &p : polygon.outer()) {
snake::Length distance = bg::distance(reference, p) * si::meter; snake::Length distance = bg::distance(reference, p) * si::meter;
distances.push_back(distance); distances.push_back(distance);
snake::Angle alpha = (std::atan2(p.get<1>(), p.get<0>())) * si::radian; snake::Angle alpha = (std::atan2(p.get<1>(), p.get<0>())) * si::radian;
alpha = alpha < 0 * si::radian ? alpha + 2 * M_PI * si::radian : alpha; alpha = alpha < 0 * si::radian ? alpha + 2 * M_PI * si::radian : alpha;
angles.push_back(alpha); angles.push_back(alpha);
//#ifdef DEBUG_CIRCULAR_SURVEY
// qCDebug(CircularGeneratorLog) << "distances, angles, // qCDebug(CircularGeneratorLog) << "distances, angles,
// coordinates:"; qCDebug(CircularGeneratorLog) << // coordinates:"; qCDebug(CircularGeneratorLog) <<
// to_string(distance).c_str(); qCDebug(CircularGeneratorLog) // to_string(distance).c_str(); qCDebug(CircularGeneratorLog)
...@@ -455,7 +453,6 @@ bool circularTransects(const snake::FPoint &reference, ...@@ -455,7 +453,6 @@ bool circularTransects(const snake::FPoint &reference,
// qCDebug(CircularGeneratorLog) << "x = " << p.get<0>() << "y // qCDebug(CircularGeneratorLog) << "x = " << p.get<0>() << "y
// = " // = "
// << p.get<1>(); // << p.get<1>();
//#endif
} }
auto rMin = deltaR; // minimal circle radius auto rMin = deltaR; // minimal circle radius
...@@ -484,7 +481,6 @@ bool circularTransects(const snake::FPoint &reference, ...@@ -484,7 +481,6 @@ bool circularTransects(const snake::FPoint &reference,
vector<ClipperLib::Path> sectors(nTran, ClipperLib::Path()); vector<ClipperLib::Path> sectors(nTran, ClipperLib::Path());
const auto nSectors = const auto nSectors =
long(std::round(((alpha2 - alpha1) / deltaAlpha).value())); long(std::round(((alpha2 - alpha1) / deltaAlpha).value()));
//#ifdef DEBUG_CIRCULAR_SURVEY
// qCDebug(CircularGeneratorLog) << "circularTransects(): sector // qCDebug(CircularGeneratorLog) << "circularTransects(): sector
// parameres:"; qCDebug(CircularGeneratorLog) << "alpha1: " << // parameres:"; qCDebug(CircularGeneratorLog) << "alpha1: " <<
// to_string(snake::Degree(alpha1)).c_str(); // to_string(snake::Degree(alpha1)).c_str();
...@@ -499,7 +495,6 @@ bool circularTransects(const snake::FPoint &reference, ...@@ -499,7 +495,6 @@ bool circularTransects(const snake::FPoint &reference,
// qCDebug(CircularGeneratorLog) // qCDebug(CircularGeneratorLog)
// << "rMax: " << to_string(rMax).c_str(); // << "rMax: " << to_string(rMax).c_str();
// qCDebug(CircularGeneratorLog) << "nTran: " << nTran; // qCDebug(CircularGeneratorLog) << "nTran: " << nTran;
//#endif
using ClipperCircle = using ClipperCircle =
GenericCircle<ClipperLib::cInt, ClipperLib::IntPoint>; GenericCircle<ClipperLib::cInt, ClipperLib::IntPoint>;
for (auto &sector : sectors) { for (auto &sector : sectors) {
......
...@@ -67,6 +67,7 @@ bool GeneratorFactory::registerGenerator(const QString &type, ...@@ -67,6 +67,7 @@ bool GeneratorFactory::registerGenerator(const QString &type,
GeneratorFactory::Creator creator) { GeneratorFactory::Creator creator) {
const auto pair = _creatorMap.insert(std::make_pair(type, creator)); const auto pair = _creatorMap.insert(std::make_pair(type, creator));
auto success = pair.second; auto success = pair.second;
Q_ASSERT(success);
return success; return success;
} }
......
...@@ -34,12 +34,12 @@ public: ...@@ -34,12 +34,12 @@ public:
const QString &kmlOrShpFile, QObject *parent); const QString &kmlOrShpFile, QObject *parent);
~MeasurementComplexItem(); ~MeasurementComplexItem();
Q_PROPERTY(Fact *variant READ variant CONSTANT) Q_PROPERTY(Fact *variantIndex READ variantIndex CONSTANT)
Q_PROPERTY(Fact *altitude READ variant CONSTANT) Q_PROPERTY(Fact *altitude READ altitude CONSTANT)
Q_PROPERTY( Q_PROPERTY(
QStringList variantNames READ variantNames NOTIFY variantNamesChanged) QStringList variantNames READ variantNames NOTIFY variantNamesChanged)
Q_PROPERTY(QStringList generatorNameList READ generatorNameList NOTIFY Q_PROPERTY(QStringList generatorNameList READ generatorNameList NOTIFY
generatorNameListChanged) generatorListChanged)
Q_PROPERTY(bool calculating READ calculating NOTIFY calculatingChanged) Q_PROPERTY(bool calculating READ calculating NOTIFY calculatingChanged)
Q_PROPERTY(bool editing READ editing NOTIFY editingChanged) Q_PROPERTY(bool editing READ editing NOTIFY editingChanged)
Q_PROPERTY(bool idle READ idle NOTIFY idleChanged) Q_PROPERTY(bool idle READ idle NOTIFY idleChanged)
...@@ -95,18 +95,56 @@ public: ...@@ -95,18 +95,56 @@ public:
virtual QString abbreviation(void) const override final; virtual QString abbreviation(void) const override final;
// Generator // Generator
bool addGenerator(const QString &name, routing::GeneratorBase *g); //!
//! \brief addGenerator Adds a generator.
//!
//! Adds a generator. The generator will be added to the generatorList() and
//! it's name to the generatorNameList(). Generators are identified by index
//! or name(), hence their name must be unique. A generator can not be added
//! if name() is already inside generatorNameList(). \param g Pointer to a
//! generator. \return Returns true if the generator was addes successfully,
//! false either.
//!
bool addGenerator(routing::GeneratorBase *g);
//!
//! \brief removeGenerator Removes the generator.
//! \param name The name of the generator to be removed.
//! \return Returns true if the generator was removed successfully.
//! \note The generator will be deleted if this or nullptr is it's parent.
bool removeGenerator(const QString &name); bool removeGenerator(const QString &name);
//!
//! \brief removeGenerator Removes the generator.
//! \param index The index of the generator to be removed
//! \return Returns true if the generator was removed successfully.
//! \note See above.
bool removeGenerator(int index); bool removeGenerator(int index);
Q_INVOKABLE bool switchToGenerator(const QString &name); Q_INVOKABLE bool switchToGenerator(const QString &name);
Q_INVOKABLE bool switchToGenerator(int index); Q_INVOKABLE bool switchToGenerator(int index);
//!
//! \brief resetGenerators Resets the generators as they where after creation
//! of this object.
//!
Q_INVOKABLE void resetGenerators(); Q_INVOKABLE void resetGenerators();
QList<PtrGenerator> generatorList() const;
QStringList generatorNameList() const; QStringList generatorNameList() const;
routing::GeneratorBase *generator(); routing::GeneratorBase *generator();
const routing::GeneratorBase *generator() const; const routing::GeneratorBase *generator() const;
routing::GeneratorBase *generator(int index); routing::GeneratorBase *generator(int index);
const routing::GeneratorBase *generator(int index) const; const routing::GeneratorBase *generator(int index) const;
//!
//! \brief generatorIndex
//! \return Returns the index of the current generator.
int generatorIndex() const; int generatorIndex() const;
//!
//! \brief generatorIndex
//! \param name
//! \return Returns the index of the generator with the name \p name, or -1 if
//! the generator is unknown.
//!
int generatorIndex(const QString &name);
// Editing. // Editing.
//! //!
...@@ -142,9 +180,9 @@ public: ...@@ -142,9 +180,9 @@ public:
AreaData *areaData(); AreaData *areaData();
QVariantList route(); QVariantList route();
Fact *variant(); Fact *variantIndex();
Fact *altitude();
QStringList variantNames() const; QStringList variantNames() const;
Fact *altitude();
bool calculating() const; bool calculating() const;
bool editing() const; // set to true on creation bool editing() const; // set to true on creation
...@@ -158,7 +196,7 @@ public: ...@@ -158,7 +196,7 @@ public:
signals: signals:
void variantNamesChanged(); void variantNamesChanged();
void generatorNameListChanged(); void generatorListChanged();
void generatorChanged(); void generatorChanged();
void calculatingChanged(); void calculatingChanged();
...@@ -173,7 +211,7 @@ private slots: ...@@ -173,7 +211,7 @@ private slots:
// Worker functions. // Worker functions.
void _storeRoutingData(PtrRoutingData pRoute); void _storeRoutingData(PtrRoutingData pRoute);
void _updateRoute(); void _updateRoute();
void _changeVariant(); void _changeVariantIndex();
void _reverseRoute(); void _reverseRoute();
private: private:
...@@ -184,6 +222,7 @@ private: ...@@ -184,6 +222,7 @@ private:
static bool _editing(STATE state); static bool _editing(STATE state);
static bool _idle(STATE state); static bool _idle(STATE state);
void _updateFlightpathSegments(); void _updateFlightpathSegments();
void _onAltitudeChanged();
// Hirarcical stuff. // Hirarcical stuff.
int _sequenceNumber; int _sequenceNumber;
...@@ -195,7 +234,7 @@ private: ...@@ -195,7 +234,7 @@ private:
// Facts // Facts
QMap<QString, FactMetaData *> _metaDataMap; QMap<QString, FactMetaData *> _metaDataMap;
SettingsFact _altitude; SettingsFact _altitude;
SettingsFact _variant; SettingsFact _variantIndex;
QStringList _variantNames; QStringList _variantNames;
// Area data // Area data
...@@ -205,7 +244,6 @@ private: ...@@ -205,7 +244,6 @@ private:
// Generators // Generators
QList<PtrGenerator> _generatorList; QList<PtrGenerator> _generatorList;
QStringList _generatorNameList;
PtrGenerator _pGenerator; PtrGenerator _pGenerator;
// Routing. // Routing.
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
QGC_LOGGING_CATEGORY(GeoAreaLog, "GeoAreaLog") QGC_LOGGING_CATEGORY(GeoAreaLog, "GeoAreaLog")
const char *GeoArea::name = "GeoArea"; const char *GeoArea::nameString = "GeoArea";
const char *GeoArea::areaTypeKey = "AreaType"; const char *GeoArea::areaTypeKey = "AreaType";
const char *GeoArea::settingsGroup = "GeoArea"; const char *GeoArea::settingsGroup = "GeoArea";
...@@ -59,7 +59,7 @@ bool GeoArea::isCorrect() { ...@@ -59,7 +59,7 @@ bool GeoArea::isCorrect() {
std::stringstream ss; std::stringstream ss;
ss << bg::wkt(polygonENU); ss << bg::wkt(polygonENU);
qCWarning(GeoAreaLog) << "polygonENU: " << ss.str().c_str(); qCWarning(GeoAreaLog) << "polygonENU: " << ss.str().c_str();
setErrorString(tr("Area invalid. Area must be a simple polygon.")); setErrorString(this->objectName() + tr(" must be a simple polygon."));
} }
} }
return false; return false;
...@@ -81,7 +81,7 @@ bool GeoArea::covers(const QGeoCoordinate &c) { ...@@ -81,7 +81,7 @@ bool GeoArea::covers(const QGeoCoordinate &c) {
} }
void GeoArea::init() { void GeoArea::init() {
this->setObjectName(name); this->setObjectName(nameString);
// connect(this, &GeoArea::pathChanged, [this] { // connect(this, &GeoArea::pathChanged, [this] {
// if (this->objectName() != "Tile") { // if (this->objectName() != "Tile") {
// qDebug() << this->objectName() << " path: " << this->path() << "\n"; // qDebug() << this->objectName() << " path: " << this->path() << "\n";
......
...@@ -30,12 +30,13 @@ public: ...@@ -30,12 +30,13 @@ public:
//! //!
//! \brief covers Checks if GeoArea covers c. //! \brief covers Checks if GeoArea covers c.
//! \param c //! \param c
//! \return Returns true if c is inside, or on the border of GeoArea. //! \return Returns true if c is inside, or on the border of GeoArea, false
//! either.
//! //!
Q_INVOKABLE bool covers(const QGeoCoordinate &c); Q_INVOKABLE bool covers(const QGeoCoordinate &c);
// static Members // static Members
static const char *name; static const char *nameString;
static const char *areaTypeKey; static const char *areaTypeKey;
static const char *settingsGroup; static const char *settingsGroup;
......
...@@ -5,14 +5,22 @@ ...@@ -5,14 +5,22 @@
#include <boost/units/systems/si.hpp> #include <boost/units/systems/si.hpp>
#include "JsonHelper.h"
#include "QGCLoggingCategory.h" #include "QGCLoggingCategory.h"
#include <QJsonArray>
#ifndef SNAKE_MAX_TILES #ifndef SNAKE_MAX_TILES
#define SNAKE_MAX_TILES 1000 #define SNAKE_MAX_TILES 1000
#endif #endif
QGC_LOGGING_CATEGORY(MeasurementAreaLog, "MeasurementAreaLog") QGC_LOGGING_CATEGORY(MeasurementAreaLog, "MeasurementAreaLog")
namespace {
const char *tileCenterPointsKey = "TileCenterPoints";
const char *tileArrayKey = "TileArray";
} // namespace
TileData::TileData() : tiles(this) {} TileData::TileData() : tiles(this) {}
TileData::~TileData() { tiles.clearAndDeleteContents(); } TileData::~TileData() { tiles.clearAndDeleteContents(); }
...@@ -50,6 +58,82 @@ bool TileData::operator!=(const TileData &other) const { ...@@ -50,6 +58,82 @@ bool TileData::operator!=(const TileData &other) const {
return !this->operator==(other); return !this->operator==(other);
} }
void TileData::saveToJson(QJsonObject &json) {
// save center points
QJsonValue jsonCenterPoints;
JsonHelper::saveGeoCoordinateArray(tileCenterPoints, false, jsonCenterPoints);
json[tileCenterPointsKey] = std::move(jsonCenterPoints);
// save tiles
QJsonArray jsonTiles;
for (int i = 0; i < tiles.count(); ++i) {
auto tile = tiles.value<SnakeTile *>(i);
if (tile != nullptr) {
QJsonObject jsonTile;
tile->saveToJson(jsonTile);
jsonTiles.append(jsonTile);
} else {
qCritical() << "TileData::saveToJson(): Object other than SnakeTile "
"inside tiles (QmlObjectListModel))";
Q_ASSERT(tile != nullptr);
}
}
json[tileArrayKey] = std::move(jsonTiles);
}
bool TileData::loadFromJson(const QJsonObject &json, QString &errorString) {
clear();
// load tiles
if (json.contains(tileArrayKey) && json[tileArrayKey].isArray()) {
QString e;
for (const auto &jsonTile : json[tileArrayKey].toArray()) {
auto tile = new SnakeTile(this);
if (tile->loadFromJson(jsonTile.toObject(), e)) {
tiles.append(tile);
} else {
tile->deleteLater();
errorString.append(e);
return false;
}
}
} else {
errorString.append(tr("Not able to load tiles.\n"));
qCWarning(MeasurementAreaLog)
<< "Not able to load tiles. tileArrayKey missing or wrong type.";
if (json.contains(tileArrayKey)) {
qCWarning(MeasurementAreaLog)
<< "tile array type: " << json[tileArrayKey].type();
}
return false;
}
// load center points
if (json.contains(tileCenterPointsKey) &&
json[tileCenterPointsKey].isArray()) {
QString e;
if (!JsonHelper::loadGeoCoordinateArray(json[tileCenterPointsKey], false,
tileCenterPoints, e)) {
errorString.append(e);
errorString.append("\n");
return false;
}
} else {
errorString.append(tr("Not able to load center points.\n"));
qCWarning(MeasurementAreaLog)
<< "Not able to load center points. tileCenterPointsKey missing or "
"wrong type.";
if (json.contains(tileCenterPointsKey)) {
qCWarning(MeasurementAreaLog)
<< "center points type: " << json[tileCenterPointsKey].type();
}
return false;
}
return true;
}
void TileData::clear() { void TileData::clear() {
this->tiles.clearAndDeleteContents(); this->tiles.clearAndDeleteContents();
this->tileCenterPoints.clear(); this->tileCenterPoints.clear();
...@@ -68,7 +152,9 @@ const char *tileHeightKey = "TileHeight"; ...@@ -68,7 +152,9 @@ const char *tileHeightKey = "TileHeight";
const char *tileWidthName = "TileWidth"; const char *tileWidthName = "TileWidth";
const char *minTileAreaKey = "MinTileAreaPercent"; const char *minTileAreaKey = "MinTileAreaPercent";
const char *showTilesKey = "ShowTiles"; const char *showTilesKey = "ShowTiles";
const char *MeasurementArea::name = "Measurement Area"; const char *progressKey = "Progress";
const char *tileKey = "Tiles";
const char *MeasurementArea::nameString = "Measurement Area";
MeasurementArea::MeasurementArea(QObject *parent) MeasurementArea::MeasurementArea(QObject *parent)
: GeoArea(parent), : GeoArea(parent),
...@@ -193,7 +279,20 @@ bool MeasurementArea::saveToJson(QJsonObject &json) { ...@@ -193,7 +279,20 @@ bool MeasurementArea::saveToJson(QJsonObject &json) {
json[tileWidthName] = _tileWidth.rawValue().toDouble(); json[tileWidthName] = _tileWidth.rawValue().toDouble();
json[minTileAreaKey] = _minTileAreaPercent.rawValue().toDouble(); json[minTileAreaKey] = _minTileAreaPercent.rawValue().toDouble();
json[showTilesKey] = _showTiles.rawValue().toBool(); json[showTilesKey] = _showTiles.rawValue().toBool();
json[areaTypeKey] = name; json[areaTypeKey] = nameString;
// save progess
QJsonArray jsonProgess;
for (const auto &p : _progress) {
jsonProgess.append(p);
}
json[progressKey] = std::move(jsonProgess);
// save tiles
QJsonObject jsonTiles;
_tileData.saveToJson(jsonTiles);
json[tileKey] = std::move(jsonTiles);
return true; return true;
} else { } else {
qCDebug(MeasurementAreaLog) qCDebug(MeasurementAreaLog)
...@@ -211,6 +310,7 @@ bool MeasurementArea::loadFromJson(const QJsonObject &json, ...@@ -211,6 +310,7 @@ bool MeasurementArea::loadFromJson(const QJsonObject &json,
disableUpdate(); disableUpdate();
bool retVal = true; bool retVal = true;
// load parameters necessary for tile calculation.
if (!json.contains(tileHeightKey) || !json[tileHeightKey].isDouble()) { if (!json.contains(tileHeightKey) || !json[tileHeightKey].isDouble()) {
errorString.append(tr("Could not load tile height!\n")); errorString.append(tr("Could not load tile height!\n"));
retVal = false; retVal = false;
...@@ -232,15 +332,59 @@ bool MeasurementArea::loadFromJson(const QJsonObject &json, ...@@ -232,15 +332,59 @@ bool MeasurementArea::loadFromJson(const QJsonObject &json,
_minTileAreaPercent.setRawValue(json[minTileAreaKey].toDouble()); _minTileAreaPercent.setRawValue(json[minTileAreaKey].toDouble());
} }
if (!json.contains(showTilesKey) || !json[showTilesKey].isBool()) { // load less important parameters
errorString.append(tr("Could not load show tiles !\n")); if (json.contains(showTilesKey) || !json[showTilesKey].isBool()) {
retVal = false;
} else {
_showTiles.setRawValue(json[showTilesKey].toBool()); _showTiles.setRawValue(json[showTilesKey].toBool());
} }
// load tiles and progress
bool tileError = false;
if (json.contains(tileKey) && json[tileKey].isObject()) {
QString e;
if (!_tileData.loadFromJson(json[tileKey].toObject(), e)) {
qCWarning(MeasurementAreaLog) << "TileData::loadFromJson(): " << e;
tileError = true;
} else {
progressChanged();
}
} else {
tileError = true;
}
bool progressError = false;
QVector<int> prog;
if (json.contains(progressKey) && json[progressKey].isArray()) {
for (const auto &p : json[progressKey].toArray()) {
if (p.isDouble()) {
prog.append(p.toDouble());
} else {
progressError = true;
break;
}
}
// check if entries are in range
if (!progressError) {
for (const auto &p : prog) {
if (p < 0 || p > 100) {
progressError = true;
break;
}
}
}
} else {
progressError = true;
}
if (!progressError) {
_progress.swap(prog);
progressChanged();
}
// do update if error occurred.
enableUpdate(); enableUpdate();
doUpdate(); if (progressError || tileError) {
doUpdate();
}
return retVal; return retVal;
} else { } else {
...@@ -408,7 +552,7 @@ void MeasurementArea::enableUpdate() { ...@@ -408,7 +552,7 @@ void MeasurementArea::enableUpdate() {
} }
void MeasurementArea::init() { void MeasurementArea::init() {
this->setObjectName(name); this->setObjectName(nameString);
connect(&this->_tileHeight, &Fact::rawValueChanged, this, connect(&this->_tileHeight, &Fact::rawValueChanged, this,
&MeasurementArea::deferUpdate); &MeasurementArea::deferUpdate);
connect(&this->_tileWidth, &Fact::rawValueChanged, this, connect(&this->_tileWidth, &Fact::rawValueChanged, this,
......
...@@ -21,6 +21,9 @@ public: ...@@ -21,6 +21,9 @@ public:
bool operator==(const TileData &other) const; bool operator==(const TileData &other) const;
bool operator!=(const TileData &other) const; bool operator!=(const TileData &other) const;
void saveToJson(QJsonObject &json);
bool loadFromJson(const QJsonObject &json, QString &errorString);
void clear(); void clear();
std::size_t size() const; std::size_t size() const;
}; };
...@@ -68,7 +71,7 @@ public: ...@@ -68,7 +71,7 @@ public:
// Static Variables // Static Variables
static const char *settingsGroup; static const char *settingsGroup;
static const char *name; static const char *nameString;
signals: signals:
void tilesChanged(); void tilesChanged();
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
QGC_LOGGING_CATEGORY(SafeAreaLog, "SafeAreaLog") QGC_LOGGING_CATEGORY(SafeAreaLog, "SafeAreaLog")
const char *SafeArea::name = "Safe Area"; const char *SafeArea::nameString = "Safe Area";
const char *depotKey = "Depot Point"; const char *depotKey = "Depot Point";
SafeArea::SafeArea(QObject *parent) : GeoArea(parent) { init(); } SafeArea::SafeArea(QObject *parent) : GeoArea(parent) { init(); }
...@@ -84,7 +84,7 @@ bool SafeArea::setDepot(const QGeoCoordinate &newDepot) { ...@@ -84,7 +84,7 @@ bool SafeArea::setDepot(const QGeoCoordinate &newDepot) {
bool SafeArea::saveToJson(QJsonObject &json) { bool SafeArea::saveToJson(QJsonObject &json) {
if (this->GeoArea::saveToJson(json)) { if (this->GeoArea::saveToJson(json)) {
json[areaTypeKey] = name; json[areaTypeKey] = nameString;
QJsonValue jsonDepot; QJsonValue jsonDepot;
JsonHelper::saveGeoCoordinate(_depot, false, jsonDepot); JsonHelper::saveGeoCoordinate(_depot, false, jsonDepot);
...@@ -135,6 +135,6 @@ bool SafeArea::isCorrect() { ...@@ -135,6 +135,6 @@ bool SafeArea::isCorrect() {
} }
void SafeArea::init() { void SafeArea::init() {
this->setObjectName(name); this->setObjectName(nameString);
connect(this, &GeoArea::pathChanged, this, &SafeArea::putDepotInside); connect(this, &GeoArea::pathChanged, this, &SafeArea::putDepotInside);
} }
...@@ -27,7 +27,7 @@ public: ...@@ -27,7 +27,7 @@ public:
QGeoCoordinate depotQml(void) const; QGeoCoordinate depotQml(void) const;
// static Members // static Members
static const char *name; static const char *nameString;
signals: signals:
void depotChanged(void); void depotChanged(void);
......
...@@ -4,14 +4,14 @@ ...@@ -4,14 +4,14 @@
"QGC.MetaData.Facts": "QGC.MetaData.Facts":
[ [
{ {
"name": "Variant", "name": "VariantIndex",
"shrotDesc": "Route variant.", "shrotDesc": "Route variant index.",
"type": "uint64", "type": "uint64",
"default": 0 "default": 0
}, },
{ {
"name": "Altitude", "name": "Altitude",
"shrotDesc": "Altitude", "shrotDesc": "Altitude.",
"type": "double", "type": "double",
"units": "m", "units": "m",
"min": 1, "min": 1,
......
...@@ -4,29 +4,56 @@ import QtQuick.Layouts 1.11 ...@@ -4,29 +4,56 @@ import QtQuick.Layouts 1.11
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QGroundControl.Controls 1.0 import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0 import QGroundControl.FactControls 1.0
import QGroundControl.ScreenTools 1.0 import QGroundControl.ScreenTools 1.0
GridLayout { GridLayout {
id:_root id: _root
property bool checked: true property bool checked: true
property var missionItem: undefined property var missionItem: undefined
property int availableWidth: 300 property int availableWidth: 300
property bool areasCorrect: false
property string errorString: ""
signal abort
property var _areaData: missionItem.areaData property var _areaData: missionItem.areaData
property real _margin: ScreenTools.defaultFontPixelWidth / 2 property real _margin: ScreenTools.defaultFontPixelWidth / 2
columnSpacing: _margin columnSpacing: _margin
rowSpacing: _margin rowSpacing: _margin
columns: 2 columns: 2
Component.onCompleted: { Component.onCompleted: {
console.assert(missionItem !== undefined, "please set the missionItem property") console.assert(missionItem !== undefined,
"please set the missionItem property")
if (checked) {
areasCorrectTimer.start()
}
} }
ExclusiveGroup{id:areaGroup} onCheckedChanged: {
if (checked) {
areasCorrectTimer.start()
} else {
areasCorrectTimer.stop()
}
}
Repeater{ ExclusiveGroup {
id: areaGroup
}
QGCLabel {
id: tipLabel
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
text: qsTr("Use the Area Editor to modify areas.")
Layout.fillWidth: true
Layout.columnSpan: parent.columns
}
Repeater {
id: areaSelector id: areaSelector
property int selectedIndex: -1 property int selectedIndex: -1
...@@ -39,36 +66,37 @@ GridLayout { ...@@ -39,36 +66,37 @@ GridLayout {
Layout.columnSpan: 2 Layout.columnSpan: 2
onCheckedChanged: { onCheckedChanged: {
if (checked){ if (checked) {
areaSelector.selectedIndex = index areaSelector.selectedIndex = index
} }
} }
Component.onCompleted: { Component.onCompleted: {
if (index === 0){ if (index === 0) {
checked = true checked = true
} }
object.interactive = Qt.binding(function(){return checked && _root.checked}) object.interactive = Qt.binding(function () {
return checked && _root.checked
})
} }
} }
} // area Repeater } // area Repeater
ColumnLayout { ColumnLayout {
id:editorParent id: editorParent
Layout.fillWidth: true Layout.fillWidth: true
Layout.maximumWidth: parent.width Layout.maximumWidth: parent.width
Layout.columnSpan: 2 Layout.columnSpan: 2
} }
Repeater{ Repeater {
id:areaEditorRepeater id: areaEditorRepeater
Layout.maximumWidth: parent.width Layout.maximumWidth: parent.width
model: _missionItem.areaData.areaList model: _missionItem.areaData.areaList
delegate: Item{ delegate: Item {
id:editor id: editor
visible: index == areaSelector.selectedIndex visible: index == areaSelector.selectedIndex
property var _visualItem: undefined property var _visualItem: undefined
...@@ -78,12 +106,19 @@ GridLayout { ...@@ -78,12 +106,19 @@ GridLayout {
if (geoArea.editorQML && !_visualItem) { if (geoArea.editorQML && !_visualItem) {
var component = Qt.createComponent(geoArea.editorQML) var component = Qt.createComponent(geoArea.editorQML)
if (component.status === Component.Error) { if (component.status === Component.Error) {
console.log("Error loading Qml: ", geoArea.editorQML, component.errorString()) console.log("Error loading Qml: ", geoArea.editorQML,
component.errorString())
} else { } else {
_visualItem = component.createObject(editorParent, { _visualItem = component.createObject(editorParent, {
geoArea: editor.geoArea, "geoArea": editor.geoArea,
visible: Qt.binding(function(){return editor.visible}), "visible": Qt.binding(function () {
availableWidth: Qt.binding(function(){return editorParent.width})}) return editor.visible
}),
"availableWidth": Qt.binding(
function () {
return editorParent.width
})
})
} }
} }
} }
...@@ -96,23 +131,66 @@ GridLayout { ...@@ -96,23 +131,66 @@ GridLayout {
} // editor } // editor
} // areaEditorRepeater } // areaEditorRepeater
SectionHeader {
id: commandsHeader
Layout.fillWidth: true
Layout.columnSpan: parent.columns
text: qsTr("Commands and Errors")
}
QGCButton{ GridLayout {
text: "Check Rules" columnSpacing: _margin
enabled: _root.checked rowSpacing: _margin
columns: 2
Layout.columnSpan: 2
Layout.fillWidth: true Layout.fillWidth: true
onClicked: { visible: commandsHeader.checked
_areaData.isCorrect()
QGCLabel {
text: qsTr("Message: ") + _root.errorString
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
color: "orange"
Layout.columnSpan: parent.columns
Layout.fillWidth: true
visible: !_root.areasCorrect
}
QGCButton {
text: "Intersection"
enabled: _root.checked
Layout.fillWidth: true
Layout.columnSpan: parent.columns
onClicked: {
_areaData.intersection()
}
}
QGCButton {
text: "Reset"
onClicked: {
_root.abort()
}
Layout.fillWidth: true
Layout.columnSpan: parent.columns
} }
} }
QGCButton{ Timer {
text: "Intersection" id: areasCorrectTimer
enabled: _root.checked running: false
Layout.fillWidth: true interval: 100
onClicked: { repeat: true
_areaData.intersection()
onTriggered: {
_root.areasCorrect = _missionItem.areaData.isCorrect(
false /*show gui message*/
)
if (!_root.areasCorrect) {
_root.errorString = _missionItem.areaData.errorString
} else {
_root.errorString = ""
}
} }
} }
} }
...@@ -41,7 +41,7 @@ GridLayout { ...@@ -41,7 +41,7 @@ GridLayout {
} }
QGCButton { QGCButton {
text: qsTr("Reset Ref.") text: qsTr("Reset Reference")
onClicked: generator.resetReference(); onClicked: generator.resetReference();
Layout.fillWidth: true Layout.fillWidth: true
Layout.columnSpan: 2 Layout.columnSpan: 2
......
import QtQuick 2.3 import QtQuick 2.3
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Styles 1.4
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import QtQuick.Extras 1.4 import QtQuick.Extras 1.4
import QtQuick.Layouts 1.2 import QtQuick.Layouts 1.3
import QGroundControl 1.0 import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0 import QGroundControl.ScreenTools 1.0
import QGroundControl.Vehicle 1.0 import QGroundControl.Vehicle 1.0
import QGroundControl.Controls 1.0 import QGroundControl.Controls 1.0
import QGroundControl.FactSystem 1.0 import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0 import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0 import QGroundControl.Palette 1.0
import QGroundControl.FlightMap 1.0 import QGroundControl.FlightMap 1.0
import MeasurementComplexItem 1.0 as MCI import MeasurementComplexItem 1.0 as MCI
Rectangle { Rectangle {
id: _root id: _root
height: visible ? (mainColumn.height + (_margin * 2)) : 0 height: visible ? (mainColumn.height + (_margin * 2)) : 0
width: availableWidth width: availableWidth
color: qgcPal.windowShadeDark color: qgcPal.windowShadeDark
radius: _radius radius: _radius
// The following properties must be available up the hierarchy chain // The following properties must be available up the hierarchy chain
//property real availableWidth ///< Width for control //property real availableWidth ///< Width for control
//property var missionItem ///< Mission Item for editor //property var missionItem ///< Mission Item for editor
property real _margin: ScreenTools.defaultFontPixelWidth / 2
property real _margin: ScreenTools.defaultFontPixelWidth / 2 property real _fieldWidth: ScreenTools.defaultFontPixelWidth * 10.5
property real _fieldWidth: ScreenTools.defaultFontPixelWidth * 10.5 property var _vehicle: QGroundControl.multiVehicleManager.activeVehicle ? QGroundControl.multiVehicleManager.activeVehicle : QGroundControl.multiVehicleManager.offlineEditingVehicle
property var _vehicle: QGroundControl.multiVehicleManager.activeVehicle ?
QGroundControl.multiVehicleManager.activeVehicle :
QGroundControl.multiVehicleManager.offlineEditingVehicle
property var _missionItem: missionItem property var _missionItem: missionItem
property var _areaData: missionItem.areaData property var _areaData: missionItem.areaData
QGCPalette { id: qgcPal; colorGroupEnabled: true } QGCPalette {
id: qgcPal
ColumnLayout { // main Column colorGroupEnabled: true
id: mainColumn }
anchors.margins: _margin
anchors.top: parent.top Column {
anchors.left: parent.left // main Column
anchors.right: parent.right id: mainColumn
anchors.margins: _margin
anchors.top: parent.top
QGCLabel { anchors.left: parent.left
id: tipLabel anchors.right: parent.right
Layout.fillWidth: true
wrapMode: Text.WordWrap QGCTabBar {
horizontalAlignment: Text.AlignHCenter id: tabBar
text: qsTr("Use the Area Editor to modify areas.") anchors.left: parent.left
visible: areaDataEditor.visible anchors.right: parent.right
}
enabled: !editing || editing && correct
readonly property int areaEditorIndex: 0
readonly property int parameterEditorIndex: 1
readonly property int nemoControlsIndex: 2
property bool editing: _missionItem.editing
property bool correct: false
Component.onCompleted: currentIndex = editing ? areaEditorIndex : parameterEditorIndex
QGCTabButton {
icon.source: "/qmlimages/PatternCamera.png"
icon.height: ScreenTools.defaultFontPixelHeight
}
QGCTabButton {
icon.source: "/qmlimages/PatternGrid.png"
icon.height: ScreenTools.defaultFontPixelHeight
}
QGCTabButton {
icon.source: "/qmlimages/PatternPresets.png"
icon.height: ScreenTools.defaultFontPixelHeight
}
GridLayout { onEditingChanged: {
id: editorSelector if (editing) {
Layout.fillWidth: true areasCorrectTimer.start()
columnSpacing: _margin } else {
rowSpacing: _margin areasCorrectTimer.stop()
QGCButton{
text: "Open Area Editor"
visible: parameterEditor.visible
Layout.fillWidth: true
Layout.columnSpan: 2
onClicked:{
_missionItem.startEditing()
} }
} }
QGCButton{ onCurrentIndexChanged: {
text: "Done" if (currentIndex === areaEditorIndex) {
Layout.fillWidth: true _missionItem.startEditing()
visible: areaDataEditor.visible } else {
onClicked: { _missionItem.stopEditing()
if (_areaData.isCorrect()){
_missionItem.stopEditing()
}
} }
} }
QGCButton{ Timer {
text: "Abort" id: areasCorrectTimer
visible: areaDataEditor.visible running: false
Layout.fillWidth: true interval: 100
onClicked:{ repeat: true
missionItem.abortEditing()
onTriggered: {
tabBar.correct = _missionItem.areaData.isCorrect(
false /*show gui message*/
)
} }
} }
}
} // editorSelector StackLayout {
width: parent.width
MCI.ParameterEditor{ currentIndex: tabBar.currentIndex
id:parameterEditor
missionItem: _root._missionItem MCI.AreaDataEditor {
availableWidth: mainColumn.width id: areaEditor
checked: !_missionItem.editing checked: visible
visible: checked missionItem: _root._missionItem
} availableWidth: parent.width
onAbort: {
missionItem.abortEditing()
tabBar.currentIndex = tabBar.parameterEditorIndex
}
}
MCI.AreaDataEditor{ MCI.ParameterEditor {
id:areaDataEditor id: parameterEditor
missionItem: _root._missionItem checked: visible
availableWidth: mainColumn.width missionItem: _root._missionItem
checked: _missionItem.editing availableWidth: mainColumn.width
visible: checked }
} }
} // main Column } // main Column
} // Rectangle } // Rectangle
...@@ -85,6 +85,7 @@ GridLayout { ...@@ -85,6 +85,7 @@ GridLayout {
GridLayout{ GridLayout{
Layout.columnSpan: parent.columns Layout.columnSpan: parent.columns
Layout.maximumWidth: parent.width Layout.maximumWidth: parent.width
columns: 3
columnSpacing: _margin columnSpacing: _margin
rowSpacing: _margin rowSpacing: _margin
...@@ -99,6 +100,7 @@ GridLayout { ...@@ -99,6 +100,7 @@ GridLayout {
delegate: QGCRadioButton { delegate: QGCRadioButton {
checked: index === variantIndex checked: index === variantIndex
text: variantRepeater.names[index] ? variantRepeater.names[index]: "" text: variantRepeater.names[index] ? variantRepeater.names[index]: ""
Layout.fillWidth: true
property int variantIndex: missionItem.variantIndex.value property int variantIndex: missionItem.variantIndex.value
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment