Commit 5f9f30c2 authored by Valentin Platzgummer's avatar Valentin Platzgummer

generators fixed, _isIncomplete stuff added to MeasurementComplexItem

parent 8da5e19a
...@@ -39,7 +39,7 @@ bool AreaData::insert(GeoArea *areaData) { ...@@ -39,7 +39,7 @@ bool AreaData::insert(GeoArea *areaData) {
if (areaData != nullptr) { if (areaData != nullptr) {
if (Q_LIKELY(!this->_areaList.contains(areaData))) { if (Q_LIKELY(!this->_areaList.contains(areaData))) {
_areaList.append(areaData); _areaList.append(areaData);
emit areaList(); emit areaListChanged();
auto *measurementArea = qobject_cast<MeasurementArea *>(areaData); auto *measurementArea = qobject_cast<MeasurementArea *>(areaData);
if (measurementArea != nullptr) { if (measurementArea != nullptr) {
...@@ -88,7 +88,7 @@ QmlObjectListModel *AreaData::areaList() { return &_areaList; } ...@@ -88,7 +88,7 @@ QmlObjectListModel *AreaData::areaList() { return &_areaList; }
const QmlObjectListModel *AreaData::areaList() const { return &_areaList; } const QmlObjectListModel *AreaData::areaList() const { return &_areaList; }
const QGeoCoordinate &AreaData::origin() const { return _origin; } QGeoCoordinate AreaData::origin() const { return _origin; }
bool AreaData::isCorrect() { bool AreaData::isCorrect() {
if (!initialized()) { if (!initialized()) {
......
...@@ -47,7 +47,7 @@ public: ...@@ -47,7 +47,7 @@ public:
//! \brief origin //! \brief origin
//! \return Returns an origin near one of the areas. //! \return Returns an origin near one of the areas.
//! \note Origin might change if the list of areas changes. //! \note Origin might change if the list of areas changes.
const QGeoCoordinate &origin() const; QGeoCoordinate origin() const;
Q_INVOKABLE bool isCorrect(); Q_INVOKABLE bool isCorrect();
//! //!
......
...@@ -37,13 +37,21 @@ CircularGenerator::CircularGenerator(QObject *parent) ...@@ -37,13 +37,21 @@ CircularGenerator::CircularGenerator(QObject *parent)
: CircularGenerator(nullptr, parent) {} : CircularGenerator(nullptr, parent) {}
CircularGenerator::CircularGenerator(GeneratorBase::Data d, QObject *parent) CircularGenerator::CircularGenerator(GeneratorBase::Data d, QObject *parent)
: GeneratorBase(d, parent), _connectionsEstablished(false), : GeneratorBase(d, parent),
_metaDataMap(FactMetaData::createMapFromJsonFile( _metaDataMap(FactMetaData::createMapFromJsonFile(
QStringLiteral(":/json/CircularGenerator.SettingsGroup.json"), this)), QStringLiteral(":/json/CircularGenerator.SettingsGroup.json"), this)),
_distance(settingsGroup, _metaDataMap[distanceName]), _distance(settingsGroup, _metaDataMap[distanceName]),
_deltaAlpha(settingsGroup, _metaDataMap[deltaAlphaName]), _deltaAlpha(settingsGroup, _metaDataMap[deltaAlphaName]),
_minLength(settingsGroup, _metaDataMap[minLengthName]) { _minLength(settingsGroup, _metaDataMap[minLengthName]),
establishConnections(); _measurementArea(nullptr) {
connect(this->distance(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->deltaAlpha(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->minLength(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this, &CircularGenerator::referenceChanged, this,
&GeneratorBase::generatorChanged);
} }
QString CircularGenerator::editorQml() { QString CircularGenerator::editorQml() {
...@@ -199,77 +207,47 @@ void CircularGenerator::resetReference() { ...@@ -199,77 +207,47 @@ void CircularGenerator::resetReference() {
} }
} }
void CircularGenerator::establishConnections() { Fact *CircularGenerator::distance() { return &_distance; }
if (this->_d != nullptr && !this->_connectionsEstablished) {
auto measurementArea =
getGeoArea<const MeasurementArea *>(*this->_d->areaList());
auto serviceArea = getGeoArea<const SafeArea *>(*this->_d->areaList());
if (measurementArea != nullptr && serviceArea != nullptr) {
GeneratorBase::establishConnections();
connect(this->_d, &AreaData::originChanged, this, Fact *CircularGenerator::deltaAlpha() { return &_deltaAlpha; }
&GeneratorBase::generatorChanged);
connect(measurementArea, &MeasurementArea::progressChanged, this, Fact *CircularGenerator::minLength() { return &_minLength; }
&GeneratorBase::generatorChanged);
connect(measurementArea, &MeasurementArea::tilesChanged, this, void CircularGenerator::onAreaListChanged() {
&GeneratorBase::generatorChanged); auto *measurementArea = getGeoArea<MeasurementArea *>(*this->_d->areaList());
connect(measurementArea, &MeasurementArea::centerChanged, this, setMeasurementArea(measurementArea);
&CircularGenerator::resetReferenceIfInvalid);
connect(measurementArea, &MeasurementArea::pathChanged, this,
&GeneratorBase::generatorChanged);
connect(serviceArea, &SafeArea::depotChanged, this,
&GeneratorBase::generatorChanged);
connect(this->distance(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->deltaAlpha(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->minLength(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this, &CircularGenerator::referenceChanged, this,
&GeneratorBase::generatorChanged);
this->_connectionsEstablished = true;
}
}
} }
void CircularGenerator::deleteConnections() { void CircularGenerator::setMeasurementArea(MeasurementArea *area) {
if (this->_d != nullptr && this->_connectionsEstablished) { if (_measurementArea != area) {
auto measurementArea =
getGeoArea<const MeasurementArea *>(*this->_d->areaList());
auto serviceArea = getGeoArea<const SafeArea *>(*this->_d->areaList());
if (measurementArea != nullptr && serviceArea != nullptr) {
GeneratorBase::deleteConnections();
disconnect(this->_d, &AreaData::originChanged, this, if (_measurementArea != nullptr) {
&GeneratorBase::generatorChanged); disconnect(_measurementArea, &MeasurementArea::progressChanged, this,
disconnect(measurementArea, &MeasurementArea::progressChanged, this,
&GeneratorBase::generatorChanged); &GeneratorBase::generatorChanged);
disconnect(measurementArea, &MeasurementArea::tilesChanged, this, disconnect(_measurementArea, &MeasurementArea::tilesChanged, this,
&GeneratorBase::generatorChanged); &GeneratorBase::generatorChanged);
disconnect(measurementArea, &MeasurementArea::centerChanged, this, disconnect(_measurementArea, &MeasurementArea::centerChanged, this,
&CircularGenerator::resetReferenceIfInvalid); &CircularGenerator::resetReferenceIfInvalid);
disconnect(measurementArea, &MeasurementArea::pathChanged, this, disconnect(_measurementArea, &MeasurementArea::pathChanged, this,
&GeneratorBase::generatorChanged); &GeneratorBase::generatorChanged);
disconnect(serviceArea, &SafeArea::depotChanged, this,
&GeneratorBase::generatorChanged);
disconnect(this->distance(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
disconnect(this->deltaAlpha(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
disconnect(this->minLength(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
disconnect(this, &CircularGenerator::referenceChanged, this,
&GeneratorBase::generatorChanged);
this->_connectionsEstablished = true;
} }
}
}
Fact *CircularGenerator::distance() { return &_distance; } _measurementArea = area;
Fact *CircularGenerator::deltaAlpha() { return &_deltaAlpha; } if (_measurementArea != nullptr) {
connect(_measurementArea, &MeasurementArea::progressChanged, this,
&GeneratorBase::generatorChanged);
connect(_measurementArea, &MeasurementArea::tilesChanged, this,
&GeneratorBase::generatorChanged);
connect(_measurementArea, &MeasurementArea::centerChanged, this,
&CircularGenerator::resetReferenceIfInvalid);
connect(_measurementArea, &MeasurementArea::pathChanged, this,
&GeneratorBase::generatorChanged);
}
Fact *CircularGenerator::minLength() { return &_minLength; } emit generatorChanged();
}
}
bool circularTransects(const snake::FPoint &reference, bool circularTransects(const snake::FPoint &reference,
const snake::FPolygon &polygon, const snake::FPolygon &polygon,
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "SettingsFact.h" #include "SettingsFact.h"
class MeasurementArea;
namespace routing { namespace routing {
class CircularGenerator : public GeneratorBase { class CircularGenerator : public GeneratorBase {
...@@ -48,18 +50,16 @@ public slots: ...@@ -48,18 +50,16 @@ public slots:
Q_INVOKABLE void resetReferenceIfInvalid(); Q_INVOKABLE void resetReferenceIfInvalid();
Q_INVOKABLE void resetReference(); Q_INVOKABLE void resetReference();
protected:
virtual void establishConnections() override;
virtual void deleteConnections() override;
private: private:
bool _connectionsEstablished; void onAreaListChanged();
void setMeasurementArea(MeasurementArea *area);
QGeoCoordinate _reference; QGeoCoordinate _reference;
QMap<QString, FactMetaData *> _metaDataMap; QMap<QString, FactMetaData *> _metaDataMap;
SettingsFact _distance; SettingsFact _distance;
SettingsFact _deltaAlpha; SettingsFact _deltaAlpha;
SettingsFact _minLength; SettingsFact _minLength;
MeasurementArea *_measurementArea;
}; };
} // namespace routing } // namespace routing
...@@ -8,8 +8,6 @@ GeneratorBase::GeneratorBase(QObject *parent) ...@@ -8,8 +8,6 @@ GeneratorBase::GeneratorBase(QObject *parent)
GeneratorBase::GeneratorBase(GeneratorBase::Data d, QObject *parent) GeneratorBase::GeneratorBase(GeneratorBase::Data d, QObject *parent)
: QObject(parent), _d(d) { : QObject(parent), _d(d) {
establishConnections(); establishConnections();
connect(_d, &AreaData::areaListChanged, this,
&GeneratorBase::_areaListChangedHandler);
} }
GeneratorBase::~GeneratorBase() {} GeneratorBase::~GeneratorBase() {}
...@@ -17,27 +15,15 @@ GeneratorBase::~GeneratorBase() {} ...@@ -17,27 +15,15 @@ GeneratorBase::~GeneratorBase() {}
GeneratorBase::Data GeneratorBase::data() const { return _d; } GeneratorBase::Data GeneratorBase::data() const { return _d; }
void GeneratorBase::setData(Data d) { void GeneratorBase::setData(Data d) {
if (d != nullptr) { if (d != _d && d != nullptr) {
if (_d != nullptr) {
disconnect(_d, &AreaData::areaListChanged, this,
&GeneratorBase::_areaListChangedHandler);
}
deleteConnections(); deleteConnections();
_d = d; _d = d;
establishConnections(); establishConnections();
connect(_d, &AreaData::areaListChanged, this, emit dataChanged();
&GeneratorBase::_areaListChangedHandler);
} }
} }
void GeneratorBase::establishConnections() {} void GeneratorBase::establishConnections() {}
void GeneratorBase::deleteConnections() {} void GeneratorBase::deleteConnections() {}
void GeneratorBase::_areaListChangedHandler() {
deleteConnections();
establishConnections();
emit generatorChanged();
}
} // namespace routing } // namespace routing
...@@ -37,6 +37,7 @@ public: ...@@ -37,6 +37,7 @@ public:
signals: signals:
void generatorChanged(); void generatorChanged();
void dataChanged();
protected: protected:
virtual void establishConnections(); virtual void establishConnections();
...@@ -44,7 +45,6 @@ protected: ...@@ -44,7 +45,6 @@ protected:
Data _d; Data _d;
private: private:
void _areaListChangedHandler();
}; };
} // namespace routing } // namespace routing
...@@ -32,8 +32,16 @@ LinearGenerator::LinearGenerator(GeneratorBase::Data d, QObject *parent) ...@@ -32,8 +32,16 @@ LinearGenerator::LinearGenerator(GeneratorBase::Data d, QObject *parent)
QStringLiteral(":/json/LinearGenerator.SettingsGroup.json"), this)), QStringLiteral(":/json/LinearGenerator.SettingsGroup.json"), this)),
_distance(settingsGroup, _metaDataMap[distanceName]), _distance(settingsGroup, _metaDataMap[distanceName]),
_alpha(settingsGroup, _metaDataMap[alphaName]), _alpha(settingsGroup, _metaDataMap[alphaName]),
_minLength(settingsGroup, _metaDataMap[minLengthName]) { _minLength(settingsGroup, _metaDataMap[minLengthName]),
establishConnections(); _measurementArea(nullptr), _safeArea(nullptr) {
connect(this->distance(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->alpha(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->minLength(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->_d, &AreaData::areaListChanged, this,
&LinearGenerator::onAreaListChanged);
} }
QString LinearGenerator::editorQml() { QString LinearGenerator::editorQml() {
...@@ -147,63 +155,35 @@ Fact *LinearGenerator::alpha() { return &_alpha; } ...@@ -147,63 +155,35 @@ Fact *LinearGenerator::alpha() { return &_alpha; }
Fact *LinearGenerator::minLength() { return &_minLength; } Fact *LinearGenerator::minLength() { return &_minLength; }
void LinearGenerator::establishConnections() { void LinearGenerator::onAreaListChanged() {
if (this->_d != nullptr && !this->_connectionsEstablished) { auto *measurementArea = getGeoArea<MeasurementArea *>(*this->_d->areaList());
auto measurementArea = setMeasurementArea(measurementArea);
getGeoArea<const MeasurementArea *>(*this->_d->areaList());
auto serviceArea = getGeoArea<const SafeArea *>(*this->_d->areaList());
if (measurementArea != nullptr && serviceArea != nullptr) {
GeneratorBase::establishConnections();
connect(this->_d, &AreaData::originChanged, this,
&GeneratorBase::generatorChanged);
connect(measurementArea, &MeasurementArea::progressChanged, this,
&GeneratorBase::generatorChanged);
connect(measurementArea, &MeasurementArea::tilesChanged, this,
&GeneratorBase::generatorChanged);
connect(measurementArea, &MeasurementArea::pathChanged, this,
&GeneratorBase::generatorChanged);
connect(serviceArea, &SafeArea::depotChanged, this,
&GeneratorBase::generatorChanged);
connect(this->distance(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->alpha(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->minLength(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
this->_connectionsEstablished = true;
}
}
} }
void LinearGenerator::deleteConnections() { void LinearGenerator::setMeasurementArea(MeasurementArea *area) {
if (this->_d != nullptr && this->_connectionsEstablished) { if (_measurementArea != area) {
auto measurementArea =
getGeoArea<const MeasurementArea *>(*this->_d->areaList());
auto serviceArea = getGeoArea<const SafeArea *>(*this->_d->areaList());
if (measurementArea != nullptr && serviceArea != nullptr) {
GeneratorBase::deleteConnections();
disconnect(this->_d, &AreaData::originChanged, this, if (_measurementArea != nullptr) {
disconnect(_measurementArea, &MeasurementArea::progressChanged, this,
&GeneratorBase::generatorChanged); &GeneratorBase::generatorChanged);
disconnect(measurementArea, &MeasurementArea::progressChanged, this, disconnect(_measurementArea, &MeasurementArea::tilesChanged, this,
&GeneratorBase::generatorChanged); &GeneratorBase::generatorChanged);
disconnect(measurementArea, &MeasurementArea::tilesChanged, this, disconnect(_measurementArea, &MeasurementArea::pathChanged, this,
&GeneratorBase::generatorChanged); &GeneratorBase::generatorChanged);
disconnect(measurementArea, &MeasurementArea::pathChanged, this,
&GeneratorBase::generatorChanged);
disconnect(serviceArea, &SafeArea::depotChanged, this,
&GeneratorBase::generatorChanged);
disconnect(this->distance(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
disconnect(this->alpha(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
disconnect(this->minLength(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
this->_connectionsEstablished = true;
} }
_measurementArea = area;
if (_measurementArea != nullptr) {
connect(_measurementArea, &MeasurementArea::progressChanged, this,
&GeneratorBase::generatorChanged);
connect(_measurementArea, &MeasurementArea::tilesChanged, this,
&GeneratorBase::generatorChanged);
connect(_measurementArea, &MeasurementArea::pathChanged, this,
&GeneratorBase::generatorChanged);
}
emit generatorChanged();
} }
} }
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#include "SettingsFact.h" #include "SettingsFact.h"
class MeasurementArea;
class SafeArea;
namespace routing { namespace routing {
class LinearGenerator : public GeneratorBase { class LinearGenerator : public GeneratorBase {
...@@ -33,17 +36,16 @@ public: ...@@ -33,17 +36,16 @@ public:
static const char *alphaName; static const char *alphaName;
static const char *minLengthName; static const char *minLengthName;
protected:
virtual void establishConnections() override;
virtual void deleteConnections() override;
private: private:
bool _connectionsEstablished; void onAreaListChanged();
void setMeasurementArea(MeasurementArea *area);
QMap<QString, FactMetaData *> _metaDataMap; QMap<QString, FactMetaData *> _metaDataMap;
SettingsFact _distance; SettingsFact _distance;
SettingsFact _alpha; SettingsFact _alpha;
SettingsFact _minLength; SettingsFact _minLength;
MeasurementArea *_measurementArea;
SafeArea *_safeArea;
}; };
} // namespace routing } // namespace routing
...@@ -72,15 +72,32 @@ MeasurementComplexItem::MeasurementComplexItem( ...@@ -72,15 +72,32 @@ MeasurementComplexItem::MeasurementComplexItem(
this->exitCoordinateSameAsEntry()); this->exitCoordinateSameAsEntry());
}); });
// Connect isIncomplete.
connect(this, &MeasurementComplexItem::idleChanged, [this] {
if (this->idle()) {
if (this->route().size() > 0 && this->_isIncomplete == true) {
this->_isIncomplete = false;
emit this->isIncompleteChanged();
}
} else {
if (this->_isIncomplete == false) {
this->_isIncomplete = true;
emit this->isIncompleteChanged();
}
}
});
connect(this, &MeasurementComplexItem::idleChanged, this,
&MeasurementComplexItem::readyForSaveStateChanged);
// Connect complexDistance. // Connect complexDistance.
connect(this, &MeasurementComplexItem::routeChanged, connect(this, &MeasurementComplexItem::routeChanged,
[this] { emit this->complexDistanceChanged(); }); [this] { emit this->complexDistanceChanged(); });
// Register Generators. // Register Generators.
auto lg = new routing::LinearGenerator(this->_pAreaData, this); auto lg = new routing::LinearGenerator(this->_pAreaData, this);
registerGenerator(lg->name(), lg); addGenerator(lg->name(), lg);
auto cg = new routing::CircularGenerator(this->_pAreaData, this); auto cg = new routing::CircularGenerator(this->_pAreaData, this);
registerGenerator(cg->name(), cg); addGenerator(cg->name(), cg);
qCritical() << "ToDo: _altitude connections missing."; qCritical() << "ToDo: _altitude connections missing.";
qCritical() << "ToDo: add generator saveing."; qCritical() << "ToDo: add generator saveing.";
...@@ -192,7 +209,7 @@ void MeasurementComplexItem::save(QJsonArray &planItems) { ...@@ -192,7 +209,7 @@ void MeasurementComplexItem::save(QJsonArray &planItems) {
qWarning() << "MeasurementComplexItem::save(): area data save missing."; qWarning() << "MeasurementComplexItem::save(): area data save missing.";
qWarning() << "MeasurementComplexItem::save(): mission item save missing."; qWarning() << "MeasurementComplexItem::save(): mission item save missing.";
if (ready()) { if (idle()) {
QJsonObject saveObject; QJsonObject saveObject;
saveObject[JsonHelper::jsonVersionKey] = 1; saveObject[JsonHelper::jsonVersionKey] = 1;
...@@ -270,7 +287,7 @@ double MeasurementComplexItem::specifiedGimbalPitch() { ...@@ -270,7 +287,7 @@ double MeasurementComplexItem::specifiedGimbalPitch() {
void MeasurementComplexItem::appendMissionItems(QList<MissionItem *> &items, void MeasurementComplexItem::appendMissionItems(QList<MissionItem *> &items,
QObject *missionItemParent) { QObject *missionItemParent) {
if (ready()) { if (idle()) {
qCDebug(MeasurementComplexItemLog) << "appendMissionItems()"; qCDebug(MeasurementComplexItemLog) << "appendMissionItems()";
int seqNum = this->_sequenceNumber; int seqNum = this->_sequenceNumber;
...@@ -350,8 +367,8 @@ void MeasurementComplexItem::_setState(MeasurementComplexItem::STATE state) { ...@@ -350,8 +367,8 @@ void MeasurementComplexItem::_setState(MeasurementComplexItem::STATE state) {
emit editingChanged(); emit editingChanged();
} }
if (_ready(oldState) != _ready(state)) { if (_idle(oldState) != _idle(state)) {
emit readyChanged(); emit idleChanged();
} }
} }
} }
...@@ -364,7 +381,7 @@ bool MeasurementComplexItem::_editing(MeasurementComplexItem::STATE state) { ...@@ -364,7 +381,7 @@ bool MeasurementComplexItem::_editing(MeasurementComplexItem::STATE state) {
return state == STATE::EDITING; return state == STATE::EDITING;
} }
bool MeasurementComplexItem::_ready(MeasurementComplexItem::STATE state) { bool MeasurementComplexItem::_idle(MeasurementComplexItem::STATE state) {
return state == STATE::IDLE; return state == STATE::IDLE;
} }
...@@ -380,6 +397,7 @@ void MeasurementComplexItem::_updateRoute() { ...@@ -380,6 +397,7 @@ void MeasurementComplexItem::_updateRoute() {
if (!editing()) { if (!editing()) {
// Reset data. // Reset data.
this->_route.clear(); this->_route.clear();
emit routeChanged();
this->_variantVector.clear(); this->_variantVector.clear();
this->_variantNames.clear(); this->_variantNames.clear();
emit variantNamesChanged(); emit variantNamesChanged();
...@@ -443,14 +461,14 @@ void MeasurementComplexItem::_updateRoute() { ...@@ -443,14 +461,14 @@ void MeasurementComplexItem::_updateRoute() {
} }
} else { } else {
qCDebug(MeasurementComplexItemLog) qCDebug(MeasurementComplexItemLog)
<< "_updateWorker(): plan data invalid."; << "_updateWorker(): area data invalid.";
return; return;
} }
} }
} }
void MeasurementComplexItem::_changeVariant() { void MeasurementComplexItem::_changeVariant() {
if (ready()) { if (idle()) {
auto variant = this->_variant.rawValue().toUInt(); auto variant = this->_variant.rawValue().toUInt();
// Find old variant and run. Old run corresponts with empty list. // Find old variant and run. Old run corresponts with empty list.
...@@ -470,11 +488,11 @@ void MeasurementComplexItem::_changeVariant() { ...@@ -470,11 +488,11 @@ void MeasurementComplexItem::_changeVariant() {
if (old_variant != std::numeric_limits<std::size_t>::max()) { if (old_variant != std::numeric_limits<std::size_t>::max()) {
// this->_route containes a route, swap it back to // this->_route containes a route, swap it back to
// this->_solutionVector // this->_solutionVector
auto &oldVariantCoordinates = this->_variantVector[old_variant]; auto &oldRoute = this->_variantVector[old_variant];
oldVariantCoordinates.swap(this->_route); oldRoute.swap(this->_route);
} }
auto &newVariantCoordinates = this->_variantVector[variant]; auto &newRoute = this->_variantVector[variant];
this->_route.swap(newVariantCoordinates); this->_route.swap(newRoute);
emit routeChanged(); emit routeChanged();
} else { // error } else { // error
qCDebug(MeasurementComplexItemLog) qCDebug(MeasurementComplexItemLog)
...@@ -496,7 +514,7 @@ void MeasurementComplexItem::_changeVariant() { ...@@ -496,7 +514,7 @@ void MeasurementComplexItem::_changeVariant() {
} }
void MeasurementComplexItem::_reverseRoute() { void MeasurementComplexItem::_reverseRoute() {
if (ready()) { if (idle()) {
if (this->_route.size() > 0) { if (this->_route.size() > 0) {
auto &t = this->_route; auto &t = this->_route;
std::reverse(t.begin(), t.end()); std::reverse(t.begin(), t.end());
...@@ -507,7 +525,7 @@ void MeasurementComplexItem::_reverseRoute() { ...@@ -507,7 +525,7 @@ void MeasurementComplexItem::_reverseRoute() {
ComplexMissionItem::ReadyForSaveState ComplexMissionItem::ReadyForSaveState
MeasurementComplexItem::readyForSaveState() const { MeasurementComplexItem::readyForSaveState() const {
if (ready()) { if (idle()) {
return ReadyForSaveState::ReadyForSave; return ReadyForSaveState::ReadyForSave;
} else { } else {
return ReadyForSaveState::NotReadyForSaveData; return ReadyForSaveState::NotReadyForSaveData;
...@@ -557,8 +575,8 @@ int MeasurementComplexItem::lastSequenceNumber() const { ...@@ -557,8 +575,8 @@ int MeasurementComplexItem::lastSequenceNumber() const {
return _sequenceNumber + std::max(0, this->_route.size() - 1); return _sequenceNumber + std::max(0, this->_route.size() - 1);
} }
bool MeasurementComplexItem::registerGenerator(const QString &name, bool MeasurementComplexItem::addGenerator(const QString &name,
routing::GeneratorBase *g) { routing::GeneratorBase *g) {
if (name.isEmpty()) { if (name.isEmpty()) {
qCDebug(MeasurementComplexItemLog) qCDebug(MeasurementComplexItemLog)
<< "registerGenerator(): empty name string."; << "registerGenerator(): empty name string.";
...@@ -587,7 +605,7 @@ bool MeasurementComplexItem::registerGenerator(const QString &name, ...@@ -587,7 +605,7 @@ bool MeasurementComplexItem::registerGenerator(const QString &name,
} }
} }
bool MeasurementComplexItem::unregisterGenerator(const QString &name) { bool MeasurementComplexItem::removeGenerator(const QString &name) {
auto index = this->_generatorNameList.indexOf(name); auto index = this->_generatorNameList.indexOf(name);
if (index >= 0) { if (index >= 0) {
// Is this the current generator? // Is this the current generator?
...@@ -615,9 +633,9 @@ bool MeasurementComplexItem::unregisterGenerator(const QString &name) { ...@@ -615,9 +633,9 @@ bool MeasurementComplexItem::unregisterGenerator(const QString &name) {
} }
} }
bool MeasurementComplexItem::unregisterGenerator(int index) { bool MeasurementComplexItem::removeGenerator(int index) {
if (index > 0 && index < this->_generatorNameList.size()) { if (index > 0 && index < this->_generatorNameList.size()) {
return unregisterGenerator(this->_generatorNameList.at(index)); return removeGenerator(this->_generatorNameList.at(index));
} else { } else {
qCDebug(MeasurementComplexItemLog) qCDebug(MeasurementComplexItemLog)
<< "unregisterGenerator(): index (" << index << "unregisterGenerator(): index (" << index
...@@ -701,7 +719,6 @@ void MeasurementComplexItem::_storeRoutingData( ...@@ -701,7 +719,6 @@ void MeasurementComplexItem::_storeRoutingData(
// Store solutions. // Store solutions.
auto ori = this->_pAreaData->origin(); auto ori = this->_pAreaData->origin();
ori.setAltitude(0); ori.setAltitude(0);
const auto &transectsENU = pRoute->transects;
QVector<Variant> variantVector; QVector<Variant> variantVector;
const auto nSolutions = pRoute->solutionVector.size(); const auto nSolutions = pRoute->solutionVector.size();
...@@ -711,60 +728,13 @@ void MeasurementComplexItem::_storeRoutingData( ...@@ -711,60 +728,13 @@ void MeasurementComplexItem::_storeRoutingData(
if (solution.size() > 0) { if (solution.size() > 0) {
const auto &route = solution.at(0); const auto &route = solution.at(0);
const auto &path = route.path; const auto &path = route.path;
const auto &info = route.info;
if (info.size() > 1) { // Convert to geo coordinates.
// Find index of first waypoint.
std::size_t idxFirst = 0; for (const auto &vertex : path) {
const auto &infoFirst = info.at(1); QGeoCoordinate c;
const auto &firstTransect = transectsENU[infoFirst.index]; snake::fromENU(ori, vertex, c);
if (firstTransect.size() > 0) { var.append(QVariant::fromValue(c));
const auto &firstWaypoint = infoFirst.reversed
? firstTransect.back()
: firstTransect.front();
double th = 0.01;
for (std::size_t i = 0; i < path.size(); ++i) {
auto dist = bg::distance(path[i], firstWaypoint);
if (dist < th) {
idxFirst = i;
break;
}
}
// Find index of last waypoint.
std::size_t idxLast = path.size() - 1;
const auto &infoLast = info.at(info.size() - 2);
const auto &lastTransect = transectsENU[infoLast.index];
if (lastTransect.size() > 0) {
const auto &lastWaypoint = infoLast.reversed
? lastTransect.front()
: lastTransect.back();
for (long i = path.size() - 1; i >= 0; --i) {
auto dist = bg::distance(path[i], lastWaypoint);
if (dist < th) {
idxLast = i;
break;
}
}
// Convert to geo coordinates.
for (std::size_t i = idxFirst; i <= idxLast; ++i) {
auto &vertex = path[i];
QGeoCoordinate c;
snake::fromENU(ori, vertex, c);
var.append(QVariant::fromValue(c));
}
} else {
qCDebug(MeasurementComplexItemLog)
<< "_setTransects(): lastTransect.size() == 0";
}
} else {
qCDebug(MeasurementComplexItemLog)
<< "_setTransects(): firstTransect.size() == 0";
}
} else {
qCDebug(MeasurementComplexItemLog)
<< "_setTransects(): transectsInfo.size() <= 1";
} }
} else { } else {
qCDebug(MeasurementComplexItemLog) qCDebug(MeasurementComplexItemLog)
...@@ -789,12 +759,14 @@ void MeasurementComplexItem::_storeRoutingData( ...@@ -789,12 +759,14 @@ void MeasurementComplexItem::_storeRoutingData(
} }
emit variantNamesChanged(); emit variantNamesChanged();
// Set variant to 0.
disconnect(&this->_variant, &Fact::rawValueChanged, this, disconnect(&this->_variant, &Fact::rawValueChanged, this,
&MeasurementComplexItem::_changeVariant); &MeasurementComplexItem::_changeVariant);
this->_variant.setCookedValue(QVariant(0)); this->_variant.setCookedValue(QVariant(0));
connect(&this->_variant, &Fact::rawValueChanged, this, connect(&this->_variant, &Fact::rawValueChanged, this,
&MeasurementComplexItem::_changeVariant); &MeasurementComplexItem::_changeVariant);
// Select first variant as route.
this->_route.swap(this->_variantVector.first()); this->_route.swap(this->_variantVector.first());
emit routeChanged(); emit routeChanged();
...@@ -817,6 +789,6 @@ bool MeasurementComplexItem::calculating() const { ...@@ -817,6 +789,6 @@ bool MeasurementComplexItem::calculating() const {
bool MeasurementComplexItem::editing() const { return _editing(this->_state); } bool MeasurementComplexItem::editing() const { return _editing(this->_state); }
bool MeasurementComplexItem::ready() const { return _ready(this->_state); } bool MeasurementComplexItem::idle() const { return _idle(this->_state); }
bool MeasurementComplexItem::followTerrain() const { return _followTerrain; } bool MeasurementComplexItem::followTerrain() const { return _followTerrain; }
...@@ -41,7 +41,7 @@ public: ...@@ -41,7 +41,7 @@ public:
generatorNameListChanged) generatorNameListChanged)
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 ready READ ready NOTIFY readyChanged) Q_PROPERTY(bool idle READ idle NOTIFY idleChanged)
Q_PROPERTY( Q_PROPERTY(
routing::GeneratorBase *generator READ generator NOTIFY generatorChanged) routing::GeneratorBase *generator READ generator NOTIFY generatorChanged)
Q_PROPERTY(int generatorIndex READ generatorIndex NOTIFY generatorChanged) Q_PROPERTY(int generatorIndex READ generatorIndex NOTIFY generatorChanged)
...@@ -94,9 +94,9 @@ public: ...@@ -94,9 +94,9 @@ public:
virtual QString abbreviation(void) const override final; virtual QString abbreviation(void) const override final;
// Generator // Generator
bool registerGenerator(const QString &name, routing::GeneratorBase *g); bool addGenerator(const QString &name, routing::GeneratorBase *g);
bool unregisterGenerator(const QString &name); bool removeGenerator(const QString &name);
bool unregisterGenerator(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);
QStringList generatorNameList(); QStringList generatorNameList();
...@@ -137,7 +137,7 @@ public: ...@@ -137,7 +137,7 @@ public:
bool calculating() const; bool calculating() const;
bool editing() const; bool editing() const;
bool ready() const; bool idle() const;
bool followTerrain() const; bool followTerrain() const;
static const char *settingsGroup; static const char *settingsGroup;
...@@ -154,7 +154,7 @@ signals: ...@@ -154,7 +154,7 @@ signals:
void calculatingChanged(); void calculatingChanged();
void editingChanged(); void editingChanged();
void readyChanged(); void idleChanged();
void areaDataChanged(); void areaDataChanged();
void routeChanged(); void routeChanged();
...@@ -173,7 +173,7 @@ private: ...@@ -173,7 +173,7 @@ private:
void _setAreaData(PtrAreaData data); void _setAreaData(PtrAreaData data);
static bool _calculating(STATE state); static bool _calculating(STATE state);
static bool _editing(STATE state); static bool _editing(STATE state);
static bool _ready(STATE state); static bool _idle(STATE state);
// Hirarcical stuff. // Hirarcical stuff.
PlanMasterController *_masterController; PlanMasterController *_masterController;
......
...@@ -17,13 +17,16 @@ const char *GeoArea::settingsGroup = "GeoArea"; ...@@ -17,13 +17,16 @@ const char *GeoArea::settingsGroup = "GeoArea";
GeoArea::GeoArea(QObject *parent) : QGCMapPolygon(parent) { init(); } GeoArea::GeoArea(QObject *parent) : QGCMapPolygon(parent) { init(); }
GeoArea::GeoArea(const GeoArea &other, QObject *parent) GeoArea::GeoArea(const GeoArea &other, QObject *parent)
: QGCMapPolygon(other, parent), _errorString(other._errorString) { : QGCMapPolygon(other, parent) {
init(); init();
_errorString = other._errorString;
} }
GeoArea &GeoArea::operator=(const GeoArea &other) { GeoArea &GeoArea::operator=(const GeoArea &other) {
QGCMapPolygon::operator=(other); QGCMapPolygon::operator=(other);
_errorString = other._errorString;
return *this; return *this;
} }
...@@ -63,7 +66,33 @@ bool GeoArea::isCorrect() { ...@@ -63,7 +66,33 @@ bool GeoArea::isCorrect() {
QString GeoArea::errorString() const { return this->_errorString; } QString GeoArea::errorString() const { return this->_errorString; }
void GeoArea::init() { this->setObjectName(wimaAreaName); } bool GeoArea::covers(const QGeoCoordinate &c) {
if (GeoArea::isCorrect()) {
auto origin = this->pathModel().value<QGCQGeoCoordinate *>(0)->coordinate();
snake::FPolygon polygonENU;
snake::areaToEnu(origin, this->pathModel(), polygonENU);
snake::FPoint cENU;
snake::toENU(origin, c, cENU);
return bg::covered_by(cENU, polygonENU);
} else {
return false;
}
}
void GeoArea::init() {
this->setObjectName(wimaAreaName);
// connect(this, &GeoArea::pathChanged, [this] {
// if (this->objectName() != "Tile") {
// qDebug() << this->objectName() << " path: " << this->path() << "\n";
// }
// });
// connect(this, &GeoArea::centerChanged, [this] {
// if (this->objectName() != "Tile") {
// qDebug() << this->objectName() << " center: " << this->center() <<
// "\n";
// }
// });
}
void GeoArea::setErrorString(const QString &str) { void GeoArea::setErrorString(const QString &str) {
this->_errorString = str; this->_errorString = str;
......
...@@ -27,6 +27,13 @@ public: ...@@ -27,6 +27,13 @@ public:
Q_INVOKABLE virtual bool isCorrect(); Q_INVOKABLE virtual bool isCorrect();
Q_INVOKABLE QString errorString() const; Q_INVOKABLE QString errorString() const;
//!
//! \brief covers Checks if GeoArea covers c.
//! \param c
//! \return Returns true if c is inside, or on the border of GeoArea.
//!
Q_INVOKABLE bool covers(const QGeoCoordinate &c);
// static Members // static Members
static const char *wimaAreaName; static const char *wimaAreaName;
static const char *areaTypeName; static const char *areaTypeName;
......
...@@ -23,7 +23,7 @@ TileData &TileData::operator=(const TileData &other) { ...@@ -23,7 +23,7 @@ TileData &TileData::operator=(const TileData &other) {
const auto *obj = other.tiles[i]; const auto *obj = other.tiles[i];
const auto *tile = qobject_cast<const SnakeTile *>(obj); const auto *tile = qobject_cast<const SnakeTile *>(obj);
if (tile != nullptr) { if (tile != nullptr) {
this->tiles.append(new SnakeTile(*tile, this)); this->tiles.append(tile->clone(this));
} else { } else {
qCWarning(MeasurementAreaLog) << "TileData::operator=: nullptr"; qCWarning(MeasurementAreaLog) << "TileData::operator=: nullptr";
} }
...@@ -103,18 +103,41 @@ MeasurementArea::MeasurementArea(const MeasurementArea &other, QObject *parent) ...@@ -103,18 +103,41 @@ MeasurementArea::MeasurementArea(const MeasurementArea &other, QObject *parent)
_showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName], _showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName],
this /* QObject parent */)), this /* QObject parent */)),
_state(STATE::IDLE) { _state(STATE::IDLE) {
init();
disableUpdate();
_tileHeight = other._tileHeight; _tileHeight = other._tileHeight;
_tileWidth = other._tileWidth; _tileWidth = other._tileWidth;
_minTileAreaPercent = other._minTileAreaPercent; _minTileAreaPercent = other._minTileAreaPercent;
_showTiles = other._showTiles; _showTiles = other._showTiles;
_progress = other._progress;
_tileData = other._tileData;
init(); if (other.ready()) {
_progress = other._progress;
_tileData = other._tileData;
enableUpdate();
} else {
enableUpdate();
doUpdate();
}
} }
MeasurementArea &MeasurementArea::operator=(const MeasurementArea &other) { MeasurementArea &MeasurementArea::operator=(const MeasurementArea &other) {
GeoArea::operator=(other); GeoArea::operator=(other);
disableUpdate();
_tileHeight = other._tileHeight;
_tileWidth = other._tileWidth;
_minTileAreaPercent = other._minTileAreaPercent;
_showTiles = other._showTiles;
if (other.ready()) {
_progress = other._progress;
_tileData = other._tileData;
enableUpdate();
} else {
enableUpdate();
doUpdate();
}
return *this; return *this;
} }
......
...@@ -73,7 +73,7 @@ void SafeArea::putDepotInside() { ...@@ -73,7 +73,7 @@ void SafeArea::putDepotInside() {
bool SafeArea::setDepot(const QGeoCoordinate &newDepot) { bool SafeArea::setDepot(const QGeoCoordinate &newDepot) {
if (_depot.latitude() != newDepot.latitude() || if (_depot.latitude() != newDepot.latitude() ||
_depot.longitude() != newDepot.longitude()) { _depot.longitude() != newDepot.longitude()) {
if (this->containsCoordinate(newDepot)) { if (this->covers(newDepot)) {
_depot = newDepot; _depot = newDepot;
_depot.setAltitude(0); _depot.setAltitude(0);
emit depotChanged(); emit depotChanged();
...@@ -125,7 +125,7 @@ bool SafeArea::loadFromJson(const QJsonObject &json, QString &errorString) { ...@@ -125,7 +125,7 @@ bool SafeArea::loadFromJson(const QJsonObject &json, QString &errorString) {
bool SafeArea::isCorrect() { bool SafeArea::isCorrect() {
if (GeoArea::isCorrect()) { if (GeoArea::isCorrect()) {
if (this->_depot.isValid()) { if (this->_depot.isValid()) {
if (this->containsCoordinate(this->_depot)) { if (this->covers(this->_depot)) {
return true; return true;
} else { } else {
setErrorString(tr("Depot outside Safe Area")); setErrorString(tr("Depot outside Safe Area"));
......
#include "SnakeTile.h" #include "SnakeTile.h"
SnakeTile::SnakeTile(QObject *parent) : GeoArea(parent) {} SnakeTile::SnakeTile(QObject *parent) : GeoArea(parent) { init(); }
SnakeTile::SnakeTile(const SnakeTile &other, QObject *parent) SnakeTile::SnakeTile(const SnakeTile &other, QObject *parent)
: GeoArea(parent) { : GeoArea(other, parent) {
*this = other; init();
} }
SnakeTile::~SnakeTile() {} SnakeTile::~SnakeTile() {}
...@@ -18,3 +18,5 @@ SnakeTile *SnakeTile::clone(QObject *parent) const { ...@@ -18,3 +18,5 @@ SnakeTile *SnakeTile::clone(QObject *parent) const {
} }
void SnakeTile::push_back(const QGeoCoordinate &c) { this->appendVertex(c); } void SnakeTile::push_back(const QGeoCoordinate &c) { this->appendVertex(c); }
void SnakeTile::init() { this->setObjectName("Tile"); }
...@@ -16,4 +16,7 @@ public: ...@@ -16,4 +16,7 @@ public:
virtual SnakeTile *clone(QObject *parent) const; virtual SnakeTile *clone(QObject *parent) const;
void push_back(const QGeoCoordinate &c); void push_back(const QGeoCoordinate &c);
private:
void init();
}; };
import QtQuick 2.0 import QtQuick 2.0
import QGroundControl 1.0 import QGroundControl 1.0
import QtLocation 5.11
Item { Item {
id: _root id: _root
...@@ -11,74 +12,53 @@ Item { ...@@ -11,74 +12,53 @@ Item {
property var generator property var generator
property bool checked: false property bool checked: false
property var _referenceComponent: undefined
signal clicked() signal clicked()
onVisibleChanged: { Item {
if (visible){ id: refPointItem
_addRefPoint()
} else {
_destroyRefPoint()
}
}
Component.onCompleted: {
if (visible){
_addRefPoint()
}
}
Component.onDestruction: { property var reference: generator.reference
_destroyRefPoint()
}
function _addRefPoint(){ onReferenceChanged: {
if (!_referenceComponent){ if (mapItem.coordinate !== reference){
_referenceComponent = refPointComponent.createObject(_root) mapItem.coordinate = reference
map.addMapItem(_referenceComponent) }
} }
}
function _destroyRefPoint(){ MapQuickItem {
if (_referenceComponent){ id: mapItem
map.removeMapItem(_referenceComponent)
_referenceComponent.destroy()
_referenceComponent = undefined
}
}
// Ref. point (Base Station)
Component {
id: refPointComponent
DragCoordinate { coordinate: _root.generator.reference
id: dragCoordinate anchorPoint.x: sourceItem.anchorPointX
anchorPoint.y: sourceItem.anchorPointY
visible: refPointItem.visible
z: QGroundControl.zOrderMapItems
property var ref: _root.generator.reference sourceItem:
MissionItemIndexLabel {
checked: true
label: qsTr("Reference")
highlightSelected: true
onClicked: _root.clicked(0)
visible: mapItem.visible
z: mapItem.z
}
}
map: _root.map ItemDragger {
z: QGroundControl.zOrderMapItems anchor: mapItem
checked: _root.checked z: QGroundControl.zOrderMapItems+1
coordinate: ref draggable: true
onDragReleased: { onDragStop:{
syncAndBind() _root.generator.reference = mapItem.coordinate
}
Component.onCompleted: {
syncAndBind()
}
onClicked: {
_root.clicked()
} }
}
function syncAndBind(){ Component.onCompleted: {
if (coordinate.latitude !== ref.latitude || _root.map.addMapItem(mapItem)
coordinate.longitude !== ref.longitude){
_root.generator.reference = coordinate
}
coordinate = Qt.binding(function(){return _root.generator.reference})
}
} }
} }
} }
...@@ -28,10 +28,12 @@ Item { ...@@ -28,10 +28,12 @@ Item {
property bool _editing: _missionItem.editing property bool _editing: _missionItem.editing
property var _generator: _missionItem.generator property var _generator: _missionItem.generator
property var _transectsComponent: undefined property var _routeObject: undefined
property var _entryCoordinate: undefined property var _entryCoordinateObject: undefined
property var _exitCoordinate: undefined property var _exitCoordinateObject: undefined
property var _generatorVisuals: undefined property var _generatorObject: undefined
property var _entryArrowObject: undefined
property var _exitArrowObject: undefined
property bool _isCurrentItem: _missionItem.isCurrentItem property bool _isCurrentItem: _missionItem.isCurrentItem
...@@ -53,19 +55,23 @@ Item { ...@@ -53,19 +55,23 @@ Item {
Component.onCompleted: { Component.onCompleted: {
console.assert(map != undefined, "please set the map property") console.assert(map != undefined, "please set the map property")
_addEntryCoordinate()
_addExitCoordinate()
_addTransectsComponent()
_addGeneratorVisuals()
var bbox = boundingBox() var bbox = boundingBox()
_missionItem.areaData.initialize(bbox[0], bbox[1]) _missionItem.areaData.initialize(bbox[0], bbox[1])
// _addEntryCoordinate()
// _addExitCoordinate()
_addTransects()
_addGeneratorVisuals()
_addEntryArrow()
_addExitArrow()
} }
Component.onDestruction: { Component.onDestruction: {
_destroyEntryCoordinate() // _destroyEntryCoordinate()
_destroyExitCoordinate() // _destroyExitCoordinate()
_destroyTransectsComponent() _destroyTransects()
_destroyGeneratorVisuals() _destroyGeneratorVisuals()
_destroyEntryArrow()
_destroyExitArrow()
} }
on_GeneratorChanged: { on_GeneratorChanged: {
...@@ -78,11 +84,10 @@ Item { ...@@ -78,11 +84,10 @@ Item {
id: visualTransectsComponent id: visualTransectsComponent
MapPolyline { MapPolyline {
visible: !_missionItem.editing
line.color: "white" line.color: "white"
line.width: 2 line.width: 2
path: _missionItem.route path: _missionItem.route
onPathChanged: console.log("path:" + path)
} }
} }
...@@ -126,6 +131,37 @@ Item { ...@@ -126,6 +131,37 @@ Item {
} }
} }
// Entry arrow
Component {
id: entryArrowComponent
MapLineArrow {
property int length: _missionItem.route.length
property var route: _missionItem.route
fromCoord: length > 1 ? route[0] : QtPositioning.coordinate()
toCoord: length > 1 ? route[1] : QtPositioning.coordinate()
arrowPosition: 2
visible: length > 1 && !_missionItem.editing
opacity: _root.opacity
}
}
// Exit arrow
Component {
id: exitArrowComponent
MapLineArrow {
property int length: _missionItem.route.length
property var route: _missionItem.route
fromCoord: length > 3 ? route[length-2] : QtPositioning.coordinate()
toCoord: length > 3 ? route[length-1] : QtPositioning.coordinate()
arrowPosition: 2
visible: length > 3 && !_missionItem.editing
opacity: _root.opacity
}
}
// GeoAreas // GeoAreas
Repeater { Repeater {
...@@ -138,76 +174,101 @@ Item { ...@@ -138,76 +174,101 @@ Item {
// Generator visuals // Generator visuals
function _addGeneratorVisuals(){ function _addGeneratorVisuals(){
if (_generator.mapVisualQml && !_generatorVisuals) { if (_generator.mapVisualQml && !_generatorObject) {
var component = Qt.createComponent(_generator.mapVisualQml) var component = Qt.createComponent(_generator.mapVisualQml)
if (component.status === Component.Error) { if (component.status === Component.Error) {
console.log("Error loading Qml: ", console.log("Error loading Qml: ",
_generator.mapVisualQml, component.errorString()) _generator.mapVisualQml, component.errorString())
} else { } else {
_generatorVisuals = _generatorObject = component.createObject(_root, {
component.createObject(_root, { "map": _root.map,
"map": _root.map, "generator": _root._generator,
"generator": _root._generator, "checked": Qt.binding(function(){return _root._isCurrentItem})
"checked": Qt.binding( })
function(){ _generatorObject.clicked.connect(
return _root._isCurrentItem
})
})
_generatorVisuals.clicked.connect(
function(){_root.clicked(_missionItem.sequenceNumber)}) function(){_root.clicked(_missionItem.sequenceNumber)})
} }
} }
} }
function _destroyGeneratorVisuals(){ function _destroyGeneratorVisuals(){
if(_generatorVisuals){ if(_generatorObject){
_generatorVisuals.destroy() _generatorObject.destroy()
_generatorVisuals = undefined _generatorObject = undefined
} }
} }
function _addTransectsComponent(){ function _addTransects(){
if (!_transectsComponent){ if (!_routeObject){
_transectsComponent = visualTransectsComponent.createObject(_root) _routeObject= visualTransectsComponent.createObject(_root)
map.addMapItem(_transectsComponent) map.addMapItem(_routeObject)
} }
} }
function _addExitCoordinate(){ function _addExitCoordinate(){
if (!_exitCoordinate){ if (!_exitCoordinateObject){
_exitCoordinate = exitPointComponent.createObject(_root) _exitCoordinateObject = exitPointComponent.createObject(_root)
map.addMapItem(_exitCoordinate) map.addMapItem(_exitCoordinateObject)
} }
} }
function _addEntryCoordinate(){ function _addEntryCoordinate(){
if (!_entryCoordinate){ if (!_entryCoordinateObject){
_entryCoordinate = entryPointComponent.createObject(_root) _entryCoordinateObject = entryPointComponent.createObject(_root)
map.addMapItem(_entryCoordinate) map.addMapItem(_entryCoordinateObject)
}
}
function _addEntryArrow(){
if (!_entryArrowObject){
_entryArrowObject = entryArrowComponent.createObject(_root)
map.addMapItem(_entryArrowObject)
} }
} }
function _addExitArrow(){
if (!_exitArrowObject){
_exitArrowObject = exitArrowComponent.createObject(_root)
map.addMapItem(_exitArrowObject)
}
}
function _destroyEntryCoordinate(){ function _destroyEntryCoordinate(){
if (_entryCoordinate){ if (_entryCoordinateObject){
map.removeMapItem(_entryCoordinate) map.removeMapItem(_entryCoordinateObject)
_entryCoordinate.destroy() _entryCoordinateObject.destroy()
_entryCoordinate = undefined _entryCoordinateObject = undefined
} }
} }
function _destroyExitCoordinate(){ function _destroyExitCoordinate(){
if (_exitCoordinate){ if (_exitCoordinateObject){
map.removeMapItem(_exitCoordinate) map.removeMapItem(_exitCoordinateObject)
_exitCoordinate.destroy() _exitCoordinateObject.destroy()
_exitCoordinate = undefined _exitCoordinateObject = undefined
}
}
function _destroyTransects(){
if (_routeObject){
map.removeMapItem(_routeObject)
_routeObject.destroy()
_routeObject= undefined
}
}
function _destroyEntryArrow(){
if (_entryArrowObject){
map.removeMapItem(_entryArrowObject)
_entryArrowObject.destroy()
_entryArrowObject = undefined
} }
} }
function _destroyTransectsComponent(){ function _destroyExitArrow(){
if (_transectsComponent){ if (_exitArrowObject){
map.removeMapItem(_transectsComponent) map.removeMapItem(_exitArrowObject)
_transectsComponent.destroy() _exitArrowObject.destroy()
_transectsComponent = undefined _exitArrowObject = undefined
} }
} }
......
...@@ -68,29 +68,36 @@ ColumnLayout { ...@@ -68,29 +68,36 @@ ColumnLayout {
} }
GridLayout{ GridLayout{
Layout.columnSpan: 2 Layout.columnSpan: 2
Layout.fillWidth: true
Layout.maximumWidth: parent.width
columnSpacing: _margin columnSpacing: _margin
rowSpacing: _margin rowSpacing: _margin
columns: 6
ExclusiveGroup{id:variantGroup}
Repeater{ Repeater{
id: variantRepeater id: variantRepeater
property var fact: missionItem.variant
property int variant: fact.value
property var names: missionItem.variantNames property var names: missionItem.variantNames
property int len: missionItem.variantNames.length property int len: missionItem.variantNames.length
model: len model: len
delegate: QGCRadioButton { delegate: QGCRadioButton {
checked: index === variantRepeater.variant checked: index === variant
text: variantRepeater.names[index] ? variantRepeater.names[index]: "" text: variantRepeater.names[index] ? variantRepeater.names[index]: ""
property int variant: missionItem.variant.value
onVariantChanged: {
if (variant === index){
checked = true
}
}
onCheckedChanged: { onCheckedChanged: {
if (checked){ if (checked && variant !== index){
missionItem.variant.value = index missionItem.variant.value = index
} }
checked = Qt.binding(function(){ return index === variantRepeater.variant})
} }
} }
} // variant repeater } // variant repeater
...@@ -135,6 +142,13 @@ ColumnLayout { ...@@ -135,6 +142,13 @@ ColumnLayout {
visible: generatorHeader.checked visible: generatorHeader.checked
} }
QGCButton{
text:qsTr("Reverse")
onClicked: missionItem.reverseRoute()
Layout.columnSpan: 2
Layout.fillWidth: true
}
// bussy indicator // bussy indicator
ColumnLayout{ ColumnLayout{
Layout.fillWidth: true Layout.fillWidth: true
......
...@@ -46,57 +46,47 @@ Item { ...@@ -46,57 +46,47 @@ Item {
interiorOpacity: 0.3 interiorOpacity: 0.3
} }
Loader { Item {
id:depotLoader id: depotMapItem
sourceComponent: depotComponent
}
// Depot Point.
Component {
id: depotComponent
Item {
id: depotMapItem
MapQuickItem { MapQuickItem {
id: mapItem id: mapItem
coordinate: _root.geoArea.depot coordinate: _root.geoArea.depot
anchorPoint.x: sourceItem.anchorPointX anchorPoint.x: sourceItem.anchorPointX
anchorPoint.y: sourceItem.anchorPointY anchorPoint.y: sourceItem.anchorPointY
visible: true visible: depotMapItem.visible
z: QGroundControl.zOrderMapItems z: QGroundControl.zOrderMapItems
Component.onCompleted: { Component.onCompleted: {
coordinate = Qt.binding(function(){return _root.geoArea.depot}) coordinate = Qt.binding(function(){return _root.geoArea.depot})
} }
sourceItem: sourceItem:
MissionItemIndexLabel { MissionItemIndexLabel {
checked: true checked: true
label: qsTr("Depot") label: qsTr("Depot")
highlightSelected: true highlightSelected: true
onClicked: _root.clicked(0) onClicked: _root.clicked(0)
visible: mapItem.visible visible: mapItem.visible
z: mapItem.z z: mapItem.z
}
} }
}
ItemDragger { ItemDragger {
anchor: mapItem anchor: mapItem
z: QGroundControl.zOrderMapItems+1 z: QGroundControl.zOrderMapItems+1
draggable: _root.geoArea.interactive draggable: _root.geoArea.interactive
onDragStop:{ onDragStop:{
_root.geoArea.depot = mapItem.coordinate _root.geoArea.depot = mapItem.coordinate
mapItem.coordinate = Qt.binding(function(){return _root.geoArea.depot}) mapItem.coordinate = Qt.binding(function(){return _root.geoArea.depot})
}
} }
}
Component.onCompleted: { Component.onCompleted: {
_root.map.addMapItem(mapItem) _root.map.addMapItem(mapItem)
}
} }
} }
} }
...@@ -8,576 +8,560 @@ ...@@ -8,576 +8,560 @@
****************************************************************************/ ****************************************************************************/
#include "QGCMapPolygon.h" #include "QGCMapPolygon.h"
#include "QGCGeo.h"
#include "JsonHelper.h" #include "JsonHelper.h"
#include "QGCQGeoCoordinate.h"
#include "QGCApplication.h" #include "QGCApplication.h"
#include "ShapeFileHelper.h" #include "QGCGeo.h"
#include "QGCLoggingCategory.h" #include "QGCLoggingCategory.h"
#include "QGCQGeoCoordinate.h"
#include "ShapeFileHelper.h"
#include <QGeoRectangle>
#include <QDebug> #include <QDebug>
#include <QDomDocument>
#include <QFile>
#include <QGeoRectangle>
#include <QJsonArray> #include <QJsonArray>
#include <QLineF> #include <QLineF>
#include <QFile>
#include <QDomDocument>
const char* QGCMapPolygon::jsonPolygonKey = "polygon"; const char *QGCMapPolygon::jsonPolygonKey = "polygon";
QGCMapPolygon::QGCMapPolygon(QObject* parent) QGCMapPolygon::QGCMapPolygon(QObject *parent)
: QObject (parent) : QObject(parent), _dirty(false), _centerDrag(false),
, _dirty (false) _ignoreCenterUpdates(false), _interactive(false), _resetActive(false) {
, _centerDrag (false) _init();
, _ignoreCenterUpdates (false)
, _interactive (false)
, _resetActive (false)
{
_init();
} }
QGCMapPolygon::QGCMapPolygon(const QGCMapPolygon& other, QObject* parent) QGCMapPolygon::QGCMapPolygon(const QGCMapPolygon &other, QObject *parent)
: QObject (parent) : QObject(parent), _dirty(false), _centerDrag(false),
, _dirty (false) _ignoreCenterUpdates(false), _interactive(false), _resetActive(false) {
, _centerDrag (false) _init();
, _ignoreCenterUpdates (false) *this = other;
, _interactive (false)
, _resetActive (false)
{
*this = other;
_init();
} }
void QGCMapPolygon::_init(void) void QGCMapPolygon::_init(void) {
{ connect(&_polygonModel, &QmlObjectListModel::dirtyChanged, this,
connect(&_polygonModel, &QmlObjectListModel::dirtyChanged, this, &QGCMapPolygon::_polygonModelDirtyChanged); &QGCMapPolygon::_polygonModelDirtyChanged);
connect(&_polygonModel, &QmlObjectListModel::countChanged, this, &QGCMapPolygon::_polygonModelCountChanged); connect(&_polygonModel, &QmlObjectListModel::countChanged, this,
&QGCMapPolygon::_polygonModelCountChanged);
connect(this, &QGCMapPolygon::pathChanged, this, &QGCMapPolygon::_updateCenter); connect(this, &QGCMapPolygon::pathChanged, this,
connect(this, &QGCMapPolygon::countChanged, this, &QGCMapPolygon::isValidChanged); &QGCMapPolygon::_updateCenter);
connect(this, &QGCMapPolygon::countChanged, this, &QGCMapPolygon::isEmptyChanged); connect(this, &QGCMapPolygon::countChanged, this,
&QGCMapPolygon::isValidChanged);
connect(this, &QGCMapPolygon::countChanged, this,
&QGCMapPolygon::isEmptyChanged);
} }
const QGCMapPolygon& QGCMapPolygon::operator=(const QGCMapPolygon& other) const QGCMapPolygon &QGCMapPolygon::operator=(const QGCMapPolygon &other) {
{ clear();
clear();
QVariantList vertices = other.path(); QVariantList vertices = other.path();
QList<QGeoCoordinate> rgCoord; QList<QGeoCoordinate> rgCoord;
for (const QVariant& vertexVar: vertices) { for (const QVariant &vertexVar : vertices) {
rgCoord.append(vertexVar.value<QGeoCoordinate>()); rgCoord.append(vertexVar.value<QGeoCoordinate>());
} }
appendVertices(rgCoord); appendVertices(rgCoord);
setDirty(true); setDirty(true);
return *this; return *this;
} }
void QGCMapPolygon::clear(void) void QGCMapPolygon::clear(void) {
{ // Bug workaround, see below
// Bug workaround, see below while (_polygonPath.count() > 1) {
while (_polygonPath.count() > 1) { _polygonPath.takeLast();
_polygonPath.takeLast(); }
} emit pathChanged();
emit pathChanged();
// Although this code should remove the polygon from the map it doesn't. There appears // Although this code should remove the polygon from the map it doesn't. There
// to be a bug in QGCMapPolygon which causes it to not be redrawn if the list is empty. So // appears to be a bug in QGCMapPolygon which causes it to not be redrawn if
// we work around it by using the code above to remove all but the last point which in turn // the list is empty. So we work around it by using the code above to remove
// will cause the polygon to go away. // all but the last point which in turn will cause the polygon to go away.
_polygonPath.clear(); _polygonPath.clear();
_polygonModel.clearAndDeleteContents(); _polygonModel.clearAndDeleteContents();
emit cleared(); emit cleared();
setDirty(true); setDirty(true);
} }
void QGCMapPolygon::adjustVertex(int vertexIndex, const QGeoCoordinate coordinate) void QGCMapPolygon::adjustVertex(int vertexIndex,
{ const QGeoCoordinate coordinate) {
_polygonPath[vertexIndex] = QVariant::fromValue(coordinate); _polygonPath[vertexIndex] = QVariant::fromValue(coordinate);
_polygonModel.value<QGCQGeoCoordinate*>(vertexIndex)->setCoordinate(coordinate); _polygonModel.value<QGCQGeoCoordinate *>(vertexIndex)
if (!_centerDrag) { ->setCoordinate(coordinate);
// When dragging center we don't signal path changed until all vertices are updated if (!_centerDrag) {
emit pathChanged(); // When dragging center we don't signal path changed until all vertices are
} // updated
setDirty(true); emit pathChanged();
}
setDirty(true);
} }
void QGCMapPolygon::setDirty(bool dirty) void QGCMapPolygon::setDirty(bool dirty) {
{ if (_dirty != dirty) {
if (_dirty != dirty) { _dirty = dirty;
_dirty = dirty; if (!dirty) {
if (!dirty) { _polygonModel.setDirty(false);
_polygonModel.setDirty(false);
}
emit dirtyChanged(dirty);
} }
emit dirtyChanged(dirty);
}
} }
QGeoCoordinate QGCMapPolygon::_coordFromPointF(const QPointF& point) const QGeoCoordinate QGCMapPolygon::_coordFromPointF(const QPointF &point) const {
{ QGeoCoordinate coord;
QGeoCoordinate coord;
if (_polygonPath.count() > 0) { if (_polygonPath.count() > 0) {
QGeoCoordinate tangentOrigin = _polygonPath[0].value<QGeoCoordinate>(); QGeoCoordinate tangentOrigin = _polygonPath[0].value<QGeoCoordinate>();
convertNedToGeo(-point.y(), point.x(), 0, tangentOrigin, &coord); convertNedToGeo(-point.y(), point.x(), 0, tangentOrigin, &coord);
} }
return coord; return coord;
} }
QPointF QGCMapPolygon::_pointFFromCoord(const QGeoCoordinate& coordinate) const QPointF
{ QGCMapPolygon::_pointFFromCoord(const QGeoCoordinate &coordinate) const {
if (_polygonPath.count() > 0) { if (_polygonPath.count() > 0) {
double y, x, down; double y, x, down;
QGeoCoordinate tangentOrigin = _polygonPath[0].value<QGeoCoordinate>(); QGeoCoordinate tangentOrigin = _polygonPath[0].value<QGeoCoordinate>();
convertGeoToNed(coordinate, tangentOrigin, &y, &x, &down); convertGeoToNed(coordinate, tangentOrigin, &y, &x, &down);
return QPointF(x, -y); return QPointF(x, -y);
} }
return QPointF(); return QPointF();
} }
QPolygonF QGCMapPolygon::_toPolygonF(void) const QPolygonF QGCMapPolygon::_toPolygonF(void) const {
{ QPolygonF polygon;
QPolygonF polygon;
if (_polygonPath.count() > 2) { if (_polygonPath.count() > 2) {
for (int i=0; i<_polygonPath.count(); i++) { for (int i = 0; i < _polygonPath.count(); i++) {
polygon.append(_pointFFromCoord(_polygonPath[i].value<QGeoCoordinate>())); polygon.append(_pointFFromCoord(_polygonPath[i].value<QGeoCoordinate>()));
}
} }
}
return polygon; return polygon;
} }
bool QGCMapPolygon::containsCoordinate(const QGeoCoordinate& coordinate) const bool QGCMapPolygon::containsCoordinate(const QGeoCoordinate &coordinate) const {
{ if (_polygonPath.count() > 2) {
if (_polygonPath.count() > 2) { return _toPolygonF().containsPoint(_pointFFromCoord(coordinate),
return _toPolygonF().containsPoint(_pointFFromCoord(coordinate), Qt::OddEvenFill); Qt::OddEvenFill);
} else { } else {
return false; return false;
} }
} }
void QGCMapPolygon::setPath(const QList<QGeoCoordinate>& path) void QGCMapPolygon::setPath(const QList<QGeoCoordinate> &path) {
{ _polygonPath.clear();
_polygonPath.clear(); _polygonModel.clearAndDeleteContents();
_polygonModel.clearAndDeleteContents(); for (const QGeoCoordinate &coord : path) {
for(const QGeoCoordinate& coord: path) { _polygonPath.append(QVariant::fromValue(coord));
_polygonPath.append(QVariant::fromValue(coord)); _polygonModel.append(new QGCQGeoCoordinate(coord, this));
_polygonModel.append(new QGCQGeoCoordinate(coord, this)); }
}
setDirty(true); setDirty(true);
emit pathChanged(); emit pathChanged();
} }
void QGCMapPolygon::setPath(const QVariantList& path) void QGCMapPolygon::setPath(const QVariantList &path) {
{ _polygonPath = path;
_polygonPath = path;
_polygonModel.clearAndDeleteContents(); _polygonModel.clearAndDeleteContents();
for (int i=0; i<_polygonPath.count(); i++) { for (int i = 0; i < _polygonPath.count(); i++) {
_polygonModel.append(new QGCQGeoCoordinate(_polygonPath[i].value<QGeoCoordinate>(), this)); _polygonModel.append(
} new QGCQGeoCoordinate(_polygonPath[i].value<QGeoCoordinate>(), this));
}
setDirty(true); setDirty(true);
emit pathChanged(); emit pathChanged();
} }
void QGCMapPolygon::saveToJson(QJsonObject& json) void QGCMapPolygon::saveToJson(QJsonObject &json) {
{ QJsonValue jsonValue;
QJsonValue jsonValue;
JsonHelper::saveGeoCoordinateArray(_polygonPath, false /* writeAltitude*/, jsonValue); JsonHelper::saveGeoCoordinateArray(_polygonPath, false /* writeAltitude*/,
json.insert(jsonPolygonKey, jsonValue); jsonValue);
setDirty(false); json.insert(jsonPolygonKey, jsonValue);
setDirty(false);
} }
bool QGCMapPolygon::loadFromJson(const QJsonObject& json, bool required, QString& errorString) bool QGCMapPolygon::loadFromJson(const QJsonObject &json, bool required,
{ QString &errorString) {
errorString.clear(); errorString.clear();
clear(); clear();
if (required) { if (required) {
if (!JsonHelper::validateRequiredKeys(json, QStringList(jsonPolygonKey), errorString)) { if (!JsonHelper::validateRequiredKeys(json, QStringList(jsonPolygonKey),
return false; errorString)) {
} return false;
} else if (!json.contains(jsonPolygonKey)) {
return true;
} }
} else if (!json.contains(jsonPolygonKey)) {
return true;
}
if (!JsonHelper::loadGeoCoordinateArray(json[jsonPolygonKey], false /* altitudeRequired */, _polygonPath, errorString)) { if (!JsonHelper::loadGeoCoordinateArray(json[jsonPolygonKey],
return false; false /* altitudeRequired */,
} _polygonPath, errorString)) {
return false;
}
for (int i=0; i<_polygonPath.count(); i++) { for (int i = 0; i < _polygonPath.count(); i++) {
_polygonModel.append(new QGCQGeoCoordinate(_polygonPath[i].value<QGeoCoordinate>(), this)); _polygonModel.append(
} new QGCQGeoCoordinate(_polygonPath[i].value<QGeoCoordinate>(), this));
}
setDirty(false); setDirty(false);
emit pathChanged(); emit pathChanged();
return true; return true;
} }
QList<QGeoCoordinate> QGCMapPolygon::coordinateList(void) const QList<QGeoCoordinate> QGCMapPolygon::coordinateList(void) const {
{ QList<QGeoCoordinate> coords;
QList<QGeoCoordinate> coords;
for (int i=0; i<_polygonPath.count(); i++) { for (int i = 0; i < _polygonPath.count(); i++) {
coords.append(_polygonPath[i].value<QGeoCoordinate>()); coords.append(_polygonPath[i].value<QGeoCoordinate>());
} }
return coords; return coords;
} }
void QGCMapPolygon::splitPolygonSegment(int vertexIndex) void QGCMapPolygon::splitPolygonSegment(int vertexIndex) {
{ int nextIndex = vertexIndex + 1;
int nextIndex = vertexIndex + 1; if (nextIndex > _polygonPath.length() - 1) {
if (nextIndex > _polygonPath.length() - 1) { nextIndex = 0;
nextIndex = 0; }
}
QGeoCoordinate firstVertex = _polygonPath[vertexIndex].value<QGeoCoordinate>(); QGeoCoordinate firstVertex =
QGeoCoordinate nextVertex = _polygonPath[nextIndex].value<QGeoCoordinate>(); _polygonPath[vertexIndex].value<QGeoCoordinate>();
QGeoCoordinate nextVertex = _polygonPath[nextIndex].value<QGeoCoordinate>();
double distance = firstVertex.distanceTo(nextVertex); double distance = firstVertex.distanceTo(nextVertex);
double azimuth = firstVertex.azimuthTo(nextVertex); double azimuth = firstVertex.azimuthTo(nextVertex);
QGeoCoordinate newVertex = firstVertex.atDistanceAndAzimuth(distance / 2, azimuth); QGeoCoordinate newVertex =
firstVertex.atDistanceAndAzimuth(distance / 2, azimuth);
if (nextIndex == 0) { if (nextIndex == 0) {
appendVertex(newVertex); appendVertex(newVertex);
} else { } else {
_polygonModel.insert(nextIndex, new QGCQGeoCoordinate(newVertex, this)); _polygonModel.insert(nextIndex, new QGCQGeoCoordinate(newVertex, this));
_polygonPath.insert(nextIndex, QVariant::fromValue(newVertex)); _polygonPath.insert(nextIndex, QVariant::fromValue(newVertex));
emit pathChanged(); emit pathChanged();
} }
} }
void QGCMapPolygon::appendVertex(const QGeoCoordinate& coordinate) void QGCMapPolygon::appendVertex(const QGeoCoordinate &coordinate) {
{ _polygonPath.append(QVariant::fromValue(coordinate));
_polygonPath.append(QVariant::fromValue(coordinate)); _polygonModel.append(new QGCQGeoCoordinate(coordinate, this));
_polygonModel.append(new QGCQGeoCoordinate(coordinate, this)); emit pathChanged();
emit pathChanged();
} }
void QGCMapPolygon::appendVertices(const QList<QGeoCoordinate>& coordinates) void QGCMapPolygon::appendVertices(const QList<QGeoCoordinate> &coordinates) {
{ QList<QObject *> objects;
QList<QObject*> objects;
_beginResetIfNotActive(); _beginResetIfNotActive();
for (const QGeoCoordinate& coordinate: coordinates) { for (const QGeoCoordinate &coordinate : coordinates) {
objects.append(new QGCQGeoCoordinate(coordinate, this)); objects.append(new QGCQGeoCoordinate(coordinate, this));
_polygonPath.append(QVariant::fromValue(coordinate)); _polygonPath.append(QVariant::fromValue(coordinate));
} }
_polygonModel.append(objects); _polygonModel.append(objects);
_endResetIfNotActive(); _endResetIfNotActive();
emit pathChanged(); emit pathChanged();
} }
void QGCMapPolygon::appendVertices(const QVariantList& varCoords) void QGCMapPolygon::appendVertices(const QVariantList &varCoords) {
{ QList<QGeoCoordinate> rgCoords;
QList<QGeoCoordinate> rgCoords; for (const QVariant &varCoord : varCoords) {
for (const QVariant& varCoord: varCoords) { rgCoords.append(varCoord.value<QGeoCoordinate>());
rgCoords.append(varCoord.value<QGeoCoordinate>()); }
} appendVertices(rgCoords);
appendVertices(rgCoords);
} }
void QGCMapPolygon::_polygonModelDirtyChanged(bool dirty) void QGCMapPolygon::_polygonModelDirtyChanged(bool dirty) {
{ if (dirty) {
if (dirty) { setDirty(true);
setDirty(true); }
}
} }
void QGCMapPolygon::removeVertex(int vertexIndex) void QGCMapPolygon::removeVertex(int vertexIndex) {
{ if (vertexIndex < 0 && vertexIndex > _polygonPath.length() - 1) {
if (vertexIndex < 0 && vertexIndex > _polygonPath.length() - 1) { qWarning() << "Call to removePolygonCoordinate with bad vertexIndex:count"
qWarning() << "Call to removePolygonCoordinate with bad vertexIndex:count" << vertexIndex << _polygonPath.length(); << vertexIndex << _polygonPath.length();
return; return;
} }
if (_polygonPath.length() <= 3) { if (_polygonPath.length() <= 3) {
// Don't allow the user to trash the polygon // Don't allow the user to trash the polygon
return; return;
} }
QObject* coordObj = _polygonModel.removeAt(vertexIndex); QObject *coordObj = _polygonModel.removeAt(vertexIndex);
coordObj->deleteLater(); coordObj->deleteLater();
if(vertexIndex == _selectedVertexIndex) { if (vertexIndex == _selectedVertexIndex) {
selectVertex(-1); selectVertex(-1);
} else if (vertexIndex < _selectedVertexIndex) { } else if (vertexIndex < _selectedVertexIndex) {
selectVertex(_selectedVertexIndex - 1); selectVertex(_selectedVertexIndex - 1);
} // else do nothing - keep current selected vertex } // else do nothing - keep current selected vertex
_polygonPath.removeAt(vertexIndex); _polygonPath.removeAt(vertexIndex);
emit pathChanged(); emit pathChanged();
} }
void QGCMapPolygon::_polygonModelCountChanged(int count) void QGCMapPolygon::_polygonModelCountChanged(int count) {
{ emit countChanged(count);
emit countChanged(count);
}
void QGCMapPolygon::_updateCenter(void)
{
if (!_ignoreCenterUpdates) {
QGeoCoordinate center;
if (_polygonPath.count() > 2) {
QPointF centroid(0, 0);
QPolygonF polygonF = _toPolygonF();
for (int i=0; i<polygonF.count(); i++) {
centroid += polygonF[i];
}
center = _coordFromPointF(QPointF(centroid.x() / polygonF.count(), centroid.y() / polygonF.count()));
}
if (_center != center) {
_center = center;
emit centerChanged(center);
}
}
} }
void QGCMapPolygon::setCenter(QGeoCoordinate newCenter) void QGCMapPolygon::_updateCenter(void) {
{ if (!_ignoreCenterUpdates) {
if (newCenter != _center) { QGeoCoordinate center;
_ignoreCenterUpdates = true;
// Adjust polygon vertices to new center if (_polygonPath.count() > 2) {
double distance = _center.distanceTo(newCenter); QPointF centroid(0, 0);
double azimuth = _center.azimuthTo(newCenter); QPolygonF polygonF = _toPolygonF();
for (int i = 0; i < polygonF.count(); i++) {
centroid += polygonF[i];
}
center = _coordFromPointF(QPointF(centroid.x() / polygonF.count(),
centroid.y() / polygonF.count()));
}
if (_center != center) {
_center = center;
emit centerChanged(center);
}
}
}
for (int i=0; i<count(); i++) { void QGCMapPolygon::setCenter(QGeoCoordinate newCenter) {
QGeoCoordinate oldVertex = _polygonPath[i].value<QGeoCoordinate>(); if (newCenter != _center) {
QGeoCoordinate newVertex = oldVertex.atDistanceAndAzimuth(distance, azimuth); _ignoreCenterUpdates = true;
adjustVertex(i, newVertex);
}
if (_centerDrag) { // Adjust polygon vertices to new center
// When center dragging, signals from adjustVertext are not sent. So we need to signal here when all adjusting is complete. double distance = _center.distanceTo(newCenter);
emit pathChanged(); double azimuth = _center.azimuthTo(newCenter);
}
_ignoreCenterUpdates = false; for (int i = 0; i < count(); i++) {
QGeoCoordinate oldVertex = _polygonPath[i].value<QGeoCoordinate>();
QGeoCoordinate newVertex =
oldVertex.atDistanceAndAzimuth(distance, azimuth);
adjustVertex(i, newVertex);
}
_center = newCenter; if (_centerDrag) {
emit centerChanged(newCenter); // When center dragging, signals from adjustVertext are not sent. So we
// need to signal here when all adjusting is complete.
emit pathChanged();
} }
_ignoreCenterUpdates = false;
_center = newCenter;
emit centerChanged(newCenter);
}
} }
void QGCMapPolygon::setCenterDrag(bool centerDrag) void QGCMapPolygon::setCenterDrag(bool centerDrag) {
{ if (centerDrag != _centerDrag) {
if (centerDrag != _centerDrag) { _centerDrag = centerDrag;
_centerDrag = centerDrag; emit centerDragChanged(centerDrag);
emit centerDragChanged(centerDrag); }
}
} }
void QGCMapPolygon::setInteractive(bool interactive) void QGCMapPolygon::setInteractive(bool interactive) {
{ if (_interactive != interactive) {
if (_interactive != interactive) { _interactive = interactive;
_interactive = interactive; emit interactiveChanged(interactive);
emit interactiveChanged(interactive); }
}
} }
QGeoCoordinate QGCMapPolygon::vertexCoordinate(int vertex) const QGeoCoordinate QGCMapPolygon::vertexCoordinate(int vertex) const {
{ if (vertex >= 0 && vertex < _polygonPath.count()) {
if (vertex >= 0 && vertex < _polygonPath.count()) { return _polygonPath[vertex].value<QGeoCoordinate>();
return _polygonPath[vertex].value<QGeoCoordinate>(); } else {
} else { qWarning() << "QGCMapPolygon::vertexCoordinate bad vertex requested:count"
qWarning() << "QGCMapPolygon::vertexCoordinate bad vertex requested:count" << vertex << _polygonPath.count(); << vertex << _polygonPath.count();
return QGeoCoordinate(); return QGeoCoordinate();
} }
} }
QList<QPointF> QGCMapPolygon::nedPolygon(void) const QList<QPointF> QGCMapPolygon::nedPolygon(void) const {
{ QList<QPointF> nedPolygon;
QList<QPointF> nedPolygon;
if (count() > 0) {
if (count() > 0) { QGeoCoordinate tangentOrigin = vertexCoordinate(0);
QGeoCoordinate tangentOrigin = vertexCoordinate(0);
for (int i = 0; i < _polygonModel.count(); i++) {
for (int i=0; i<_polygonModel.count(); i++) { double y, x, down;
double y, x, down; QGeoCoordinate vertex = vertexCoordinate(i);
QGeoCoordinate vertex = vertexCoordinate(i); if (i == 0) {
if (i == 0) { // This avoids a nan calculation that comes out of convertGeoToNed
// This avoids a nan calculation that comes out of convertGeoToNed x = y = 0;
x = y = 0; } else {
} else { convertGeoToNed(vertex, tangentOrigin, &y, &x, &down);
convertGeoToNed(vertex, tangentOrigin, &y, &x, &down); }
} nedPolygon += QPointF(x, y);
nedPolygon += QPointF(x, y);
}
} }
}
return nedPolygon; return nedPolygon;
} }
void QGCMapPolygon::offset(double distance) {
QList<QGeoCoordinate> rgNewPolygon;
void QGCMapPolygon::offset(double distance) // I'm sure there is some beautiful famous algorithm to do this, but here is a
{ // brute force method
QList<QGeoCoordinate> rgNewPolygon;
// I'm sure there is some beautiful famous algorithm to do this, but here is a brute force method if (count() > 2) {
// Convert the polygon to NED
QList<QPointF> rgNedVertices = nedPolygon();
if (count() > 2) { // Walk the edges, offsetting by the specified distance
// Convert the polygon to NED QList<QLineF> rgOffsetEdges;
QList<QPointF> rgNedVertices = nedPolygon(); for (int i = 0; i < rgNedVertices.count(); i++) {
int lastIndex = i == rgNedVertices.count() - 1 ? 0 : i + 1;
QLineF offsetEdge;
QLineF originalEdge(rgNedVertices[i], rgNedVertices[lastIndex]);
// Walk the edges, offsetting by the specified distance QLineF workerLine = originalEdge;
QList<QLineF> rgOffsetEdges; workerLine.setLength(distance);
for (int i=0; i<rgNedVertices.count(); i++) { workerLine.setAngle(workerLine.angle() - 90.0);
int lastIndex = i == rgNedVertices.count() - 1 ? 0 : i + 1; offsetEdge.setP1(workerLine.p2());
QLineF offsetEdge;
QLineF originalEdge(rgNedVertices[i], rgNedVertices[lastIndex]);
QLineF workerLine = originalEdge; workerLine.setPoints(originalEdge.p2(), originalEdge.p1());
workerLine.setLength(distance); workerLine.setLength(distance);
workerLine.setAngle(workerLine.angle() - 90.0); workerLine.setAngle(workerLine.angle() + 90.0);
offsetEdge.setP1(workerLine.p2()); offsetEdge.setP2(workerLine.p2());
workerLine.setPoints(originalEdge.p2(), originalEdge.p1()); rgOffsetEdges.append(offsetEdge);
workerLine.setLength(distance); }
workerLine.setAngle(workerLine.angle() + 90.0);
offsetEdge.setP2(workerLine.p2());
rgOffsetEdges.append(offsetEdge);
}
// Intersect the offset edges to generate new vertices // Intersect the offset edges to generate new vertices
QPointF newVertex; QPointF newVertex;
QGeoCoordinate tangentOrigin = vertexCoordinate(0); QGeoCoordinate tangentOrigin = vertexCoordinate(0);
for (int i=0; i<rgOffsetEdges.count(); i++) { for (int i = 0; i < rgOffsetEdges.count(); i++) {
int prevIndex = i == 0 ? rgOffsetEdges.count() - 1 : i - 1; int prevIndex = i == 0 ? rgOffsetEdges.count() - 1 : i - 1;
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
auto intersect = rgOffsetEdges[prevIndex].intersect(rgOffsetEdges[i], &newVertex); auto intersect =
rgOffsetEdges[prevIndex].intersect(rgOffsetEdges[i], &newVertex);
#else #else
auto intersect = rgOffsetEdges[prevIndex].intersects(rgOffsetEdges[i], &newVertex); auto intersect =
rgOffsetEdges[prevIndex].intersects(rgOffsetEdges[i], &newVertex);
#endif #endif
if (intersect == QLineF::NoIntersection) { if (intersect == QLineF::NoIntersection) {
// FIXME: Better error handling? // FIXME: Better error handling?
qWarning("Intersection failed"); qWarning("Intersection failed");
return; return;
} }
QGeoCoordinate coord; QGeoCoordinate coord;
convertNedToGeo(newVertex.y(), newVertex.x(), 0, tangentOrigin, &coord); convertNedToGeo(newVertex.y(), newVertex.x(), 0, tangentOrigin, &coord);
rgNewPolygon.append(coord); rgNewPolygon.append(coord);
}
} }
}
// Update internals // Update internals
_beginResetIfNotActive(); _beginResetIfNotActive();
clear(); clear();
appendVertices(rgNewPolygon); appendVertices(rgNewPolygon);
_endResetIfNotActive(); _endResetIfNotActive();
} }
bool QGCMapPolygon::loadKMLOrSHPFile(const QString& file) bool QGCMapPolygon::loadKMLOrSHPFile(const QString &file) {
{ QString errorString;
QString errorString; QList<QGeoCoordinate> rgCoords;
QList<QGeoCoordinate> rgCoords; if (!ShapeFileHelper::loadPolygonFromFile(file, rgCoords, errorString)) {
if (!ShapeFileHelper::loadPolygonFromFile(file, rgCoords, errorString)) { qgcApp()->showAppMessage(errorString);
qgcApp()->showAppMessage(errorString); return false;
return false; }
}
_beginResetIfNotActive(); _beginResetIfNotActive();
clear(); clear();
appendVertices(rgCoords); appendVertices(rgCoords);
_endResetIfNotActive(); _endResetIfNotActive();
return true; return true;
} }
double QGCMapPolygon::area(void) const double QGCMapPolygon::area(void) const {
{ // https://www.mathopenref.com/coordpolygonarea2.html
// https://www.mathopenref.com/coordpolygonarea2.html
if (_polygonPath.count() < 3) { if (_polygonPath.count() < 3) {
return 0; return 0;
} }
double coveredArea = 0.0; double coveredArea = 0.0;
QList<QPointF> nedVertices = nedPolygon(); QList<QPointF> nedVertices = nedPolygon();
for (int i=0; i<nedVertices.count(); i++) { for (int i = 0; i < nedVertices.count(); i++) {
if (i != 0) { if (i != 0) {
coveredArea += nedVertices[i - 1].x() * nedVertices[i].y() - nedVertices[i].x() * nedVertices[i -1].y(); coveredArea += nedVertices[i - 1].x() * nedVertices[i].y() -
} else { nedVertices[i].x() * nedVertices[i - 1].y();
coveredArea += nedVertices.last().x() * nedVertices[i].y() - nedVertices[i].x() * nedVertices.last().y(); } else {
} coveredArea += nedVertices.last().x() * nedVertices[i].y() -
nedVertices[i].x() * nedVertices.last().y();
} }
return 0.5 * fabs(coveredArea); }
return 0.5 * fabs(coveredArea);
} }
void QGCMapPolygon::verifyClockwiseWinding(void) void QGCMapPolygon::verifyClockwiseWinding(void) {
{ if (_polygonPath.count() <= 2) {
if (_polygonPath.count() <= 2) { return;
return; }
}
double sum = 0; double sum = 0;
for (int i=0; i<_polygonPath.count(); i++) { for (int i = 0; i < _polygonPath.count(); i++) {
QGeoCoordinate coord1 = _polygonPath[i].value<QGeoCoordinate>(); QGeoCoordinate coord1 = _polygonPath[i].value<QGeoCoordinate>();
QGeoCoordinate coord2 = (i == _polygonPath.count() - 1) ? _polygonPath[0].value<QGeoCoordinate>() : _polygonPath[i+1].value<QGeoCoordinate>(); QGeoCoordinate coord2 = (i == _polygonPath.count() - 1)
? _polygonPath[0].value<QGeoCoordinate>()
: _polygonPath[i + 1].value<QGeoCoordinate>();
sum += (coord2.longitude() - coord1.longitude()) * (coord2.latitude() + coord1.latitude()); sum += (coord2.longitude() - coord1.longitude()) *
} (coord2.latitude() + coord1.latitude());
}
if (sum < 0.0) { if (sum < 0.0) {
// Winding is counter-clockwise and needs reversal // Winding is counter-clockwise and needs reversal
QList<QGeoCoordinate> rgReversed; QList<QGeoCoordinate> rgReversed;
for (const QVariant& varCoord: _polygonPath) { for (const QVariant &varCoord : _polygonPath) {
rgReversed.prepend(varCoord.value<QGeoCoordinate>()); rgReversed.prepend(varCoord.value<QGeoCoordinate>());
}
_beginResetIfNotActive();
clear();
appendVertices(rgReversed);
_endResetIfNotActive();
} }
_beginResetIfNotActive();
clear();
appendVertices(rgReversed);
_endResetIfNotActive();
}
} }
void QGCMapPolygon::beginReset(void) void QGCMapPolygon::beginReset(void) {
{ _resetActive = true;
_resetActive = true; _polygonModel.beginReset();
_polygonModel.beginReset();
} }
void QGCMapPolygon::endReset(void) void QGCMapPolygon::endReset(void) {
{ _resetActive = false;
_resetActive = false; _polygonModel.endReset();
_polygonModel.endReset(); emit pathChanged();
emit pathChanged(); emit centerChanged(_center);
emit centerChanged(_center);
} }
void QGCMapPolygon::_beginResetIfNotActive(void) void QGCMapPolygon::_beginResetIfNotActive(void) {
{ if (!_resetActive) {
if (!_resetActive) { beginReset();
beginReset(); }
}
} }
void QGCMapPolygon::_endResetIfNotActive(void) void QGCMapPolygon::_endResetIfNotActive(void) {
{ if (!_resetActive) {
if (!_resetActive) { endReset();
endReset(); }
}
} }
QDomElement QGCMapPolygon::kmlPolygonElement(KMLDomDocument& domDocument) QDomElement QGCMapPolygon::kmlPolygonElement(KMLDomDocument &domDocument) {
{
#if 0 #if 0
<Polygon id="ID"> <Polygon id="ID">
<!-- specific to Polygon --> <!-- specific to Polygon -->
...@@ -599,55 +583,61 @@ QDomElement QGCMapPolygon::kmlPolygonElement(KMLDomDocument& domDocument) ...@@ -599,55 +583,61 @@ QDomElement QGCMapPolygon::kmlPolygonElement(KMLDomDocument& domDocument)
</Polygon> </Polygon>
#endif #endif
QDomElement polygonElement = domDocument.createElement("Polygon"); QDomElement polygonElement = domDocument.createElement("Polygon");
domDocument.addTextElement(polygonElement, "altitudeMode", "clampToGround"); domDocument.addTextElement(polygonElement, "altitudeMode", "clampToGround");
QDomElement outerBoundaryIsElement = domDocument.createElement("outerBoundaryIs"); QDomElement outerBoundaryIsElement =
QDomElement linearRingElement = domDocument.createElement("LinearRing"); domDocument.createElement("outerBoundaryIs");
QDomElement linearRingElement = domDocument.createElement("LinearRing");
outerBoundaryIsElement.appendChild(linearRingElement); outerBoundaryIsElement.appendChild(linearRingElement);
polygonElement.appendChild(outerBoundaryIsElement); polygonElement.appendChild(outerBoundaryIsElement);
QString coordString; QString coordString;
for (const QVariant& varCoord : _polygonPath) { for (const QVariant &varCoord : _polygonPath) {
coordString += QStringLiteral("%1\n").arg(domDocument.kmlCoordString(varCoord.value<QGeoCoordinate>())); coordString += QStringLiteral("%1\n").arg(
} domDocument.kmlCoordString(varCoord.value<QGeoCoordinate>()));
coordString += QStringLiteral("%1\n").arg(domDocument.kmlCoordString(_polygonPath.first().value<QGeoCoordinate>())); }
domDocument.addTextElement(linearRingElement, "coordinates", coordString); coordString += QStringLiteral("%1\n").arg(
domDocument.kmlCoordString(_polygonPath.first().value<QGeoCoordinate>()));
domDocument.addTextElement(linearRingElement, "coordinates", coordString);
return polygonElement; return polygonElement;
} }
void QGCMapPolygon::setTraceMode(bool traceMode) void QGCMapPolygon::setTraceMode(bool traceMode) {
{ if (traceMode != _traceMode) {
if (traceMode != _traceMode) { _traceMode = traceMode;
_traceMode = traceMode; emit traceModeChanged(traceMode);
emit traceModeChanged(traceMode); }
}
} }
void QGCMapPolygon::setShowAltColor(bool showAltColor){ void QGCMapPolygon::setShowAltColor(bool showAltColor) {
if (showAltColor != _showAltColor) { if (showAltColor != _showAltColor) {
_showAltColor = showAltColor; _showAltColor = showAltColor;
emit showAltColorChanged(showAltColor); emit showAltColorChanged(showAltColor);
} }
} }
void QGCMapPolygon::selectVertex(int index) void QGCMapPolygon::selectVertex(int index) {
{ if (index == _selectedVertexIndex)
if(index == _selectedVertexIndex) return; // do nothing return; // do nothing
if(-1 <= index && index < count()) { if (-1 <= index && index < count()) {
_selectedVertexIndex = index; _selectedVertexIndex = index;
} else { } else {
if (!qgcApp()->runningUnitTests()) { if (!qgcApp()->runningUnitTests()) {
qCWarning(ParameterManagerLog) qCWarning(ParameterManagerLog)
<< QString("QGCMapPolygon: Selected vertex index (%1) is out of bounds! " << QString(
"Polygon vertices indexes range is [%2..%3].").arg(index).arg(0).arg(count()-1); "QGCMapPolygon: Selected vertex index (%1) is out of bounds! "
} "Polygon vertices indexes range is [%2..%3].")
_selectedVertexIndex = -1; // deselect vertex .arg(index)
.arg(0)
.arg(count() - 1);
} }
_selectedVertexIndex = -1; // deselect vertex
}
emit selectedVertexChanged(_selectedVertexIndex); emit selectedVertexChanged(_selectedVertexIndex);
} }
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