diff --git a/src/MissionManager/QGCMapPolygon.h b/src/MissionManager/QGCMapPolygon.h index 803cf70ad63647a37e41573ee6b9315cdaa1d016..fdee3f39182fc600aeb1fd90729d4314ed8356b1 100644 --- a/src/MissionManager/QGCMapPolygon.h +++ b/src/MissionManager/QGCMapPolygon.h @@ -10,139 +10,145 @@ #ifndef QGCMapPolygon_H #define QGCMapPolygon_H -#include #include -#include +#include #include +#include #include "QmlObjectListModel.h" -/// The QGCMapPolygon class provides a polygon which can be displayed on a map using a map visuals control. -/// It maintains a representation of the polygon on QVariantList and QmlObjectListModel format. -class QGCMapPolygon : public QObject -{ - Q_OBJECT +/// The QGCMapPolygon class provides a polygon which can be displayed on a map +/// using a map visuals control. It maintains a representation of the polygon on +/// QVariantList and QmlObjectListModel format. +class QGCMapPolygon : public QObject { + Q_OBJECT public: - QGCMapPolygon(QObject* parent = nullptr); - QGCMapPolygon(const QGCMapPolygon& other, QObject* parent = nullptr); - - const QGCMapPolygon& operator=(const QGCMapPolygon& other); - - Q_PROPERTY(int count READ count NOTIFY countChanged) - Q_PROPERTY(QVariantList path READ path NOTIFY pathChanged) - Q_PROPERTY(QmlObjectListModel* pathModel READ qmlPathModel CONSTANT) - Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged) - Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged) - Q_PROPERTY(bool centerDrag READ centerDrag WRITE setCenterDrag NOTIFY centerDragChanged) - Q_PROPERTY(bool interactive READ interactive WRITE setInteractive NOTIFY interactiveChanged) - Q_PROPERTY(double area READ area NOTIFY areaChanged) - - Q_INVOKABLE void clear(void); - Q_INVOKABLE void appendVertex(const QGeoCoordinate& coordinate); - Q_INVOKABLE void removeVertex(int vertexIndex); - Q_INVOKABLE void appendVertices(const QList& coordinates); - - /// Adjust the value for the specified coordinate - /// @param vertexIndex Polygon point index to modify (0-based) - /// @param coordinate New coordinate for point - Q_INVOKABLE void adjustVertex(int vertexIndex, const QGeoCoordinate coordinate); - - /// Splits the segment comprised of vertextIndex -> vertexIndex + 1 - Q_INVOKABLE void splitPolygonSegment(int vertexIndex); - - /// Returns true if the specified coordinate is within the polygon - Q_INVOKABLE bool containsCoordinate(const QGeoCoordinate& coordinate) const; - - /// Offsets the current polygon edges by the specified distance in meters - Q_INVOKABLE void offset(double distance); - - /// Loads a polygon from a KML/SH{ file - /// @return true: success - Q_INVOKABLE bool loadKMLOrSHPFile(const QString& file); - - /// Returns the path in a list of QGeoCoordinate's format - QList coordinateList(void) const; - - /// Returns the QGeoCoordinate for the vertex specified - Q_INVOKABLE QGeoCoordinate vertexCoordinate(int vertex) const; - - /// Adjust polygon winding order to be clockwise (if needed) - Q_INVOKABLE void verifyClockwiseWinding(void); - - /// Saves the polygon to the json object. - /// @param json Json object to save to - void saveToJson(QJsonObject& json); - - /// Load a polygon from json - /// @param json Json object to load from - /// @param required true: no polygon in object will generate error - /// @param errorString Error string if return is false - /// @return true: success, false: failure (errorString set) - bool loadFromJson(const QJsonObject& json, bool required, QString& errorString); - - /// Convert polygon to NED and return (D is ignored) - QList nedPolygon(void) const; - - /// Returns the area of the polygon in meters squared - double area(void) const; - - // Property methods - - int count (void) const { return _polygonPath.count(); } - bool dirty (void) const { return _dirty; } - void setDirty (bool dirty); - QGeoCoordinate center (void) const { return _center; } - bool centerDrag (void) const { return _centerDrag; } - bool interactive (void) const { return _interactive; } - - QVariantList path (void) const { return _polygonPath; } - QmlObjectListModel* qmlPathModel(void) { return &_polygonModel; } - QmlObjectListModel& pathModel (void) { return _polygonModel; } - - // Friends - friend void print(const QGCMapPolygon& poly, QString& outputString); - friend void print(const QGCMapPolygon& poly); - - // static Variables - static const char* jsonPolygonKey; + QGCMapPolygon(QObject *parent = nullptr); + QGCMapPolygon(const QGCMapPolygon &other, QObject *parent = nullptr); + + const QGCMapPolygon &operator=(const QGCMapPolygon &other); + + Q_PROPERTY(int count READ count NOTIFY countChanged) + Q_PROPERTY(QVariantList path READ path NOTIFY pathChanged) + Q_PROPERTY(QmlObjectListModel *pathModel READ qmlPathModel CONSTANT) + Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged) + Q_PROPERTY( + QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged) + Q_PROPERTY(bool centerDrag READ centerDrag WRITE setCenterDrag NOTIFY + centerDragChanged) + Q_PROPERTY(bool interactive READ interactive WRITE setInteractive NOTIFY + interactiveChanged) + Q_PROPERTY(double area READ area NOTIFY areaChanged) + + Q_INVOKABLE void clear(void); + Q_INVOKABLE void appendVertex(const QGeoCoordinate &coordinate); + Q_INVOKABLE void removeVertex(int vertexIndex); + Q_INVOKABLE void appendVertices(const QList &coordinates); + + /// Adjust the value for the specified coordinate + /// @param vertexIndex Polygon point index to modify (0-based) + /// @param coordinate New coordinate for point + Q_INVOKABLE void adjustVertex(int vertexIndex, + const QGeoCoordinate coordinate); + + /// Splits the segment comprised of vertextIndex -> vertexIndex + 1 + Q_INVOKABLE void splitPolygonSegment(int vertexIndex); + + /// Returns true if the specified coordinate is within the polygon + Q_INVOKABLE bool containsCoordinate(const QGeoCoordinate &coordinate) const; + + /// Offsets the current polygon edges by the specified distance in meters + Q_INVOKABLE void offset(double distance); + + /// Loads a polygon from a KML/SH{ file + /// @return true: success + Q_INVOKABLE bool loadKMLOrSHPFile(const QString &file); + + /// Returns the path in a list of QGeoCoordinate's format + QList coordinateList(void) const; + + /// Returns the QGeoCoordinate for the vertex specified + Q_INVOKABLE QGeoCoordinate vertexCoordinate(int vertex) const; + + /// Adjust polygon winding order to be clockwise (if needed) + Q_INVOKABLE void verifyClockwiseWinding(void); + + /// Saves the polygon to the json object. + /// @param json Json object to save to + void saveToJson(QJsonObject &json); + + /// Load a polygon from json + /// @param json Json object to load from + /// @param required true: no polygon in object will generate error + /// @param errorString Error string if return is false + /// @return true: success, false: failure (errorString set) + bool loadFromJson(const QJsonObject &json, bool required, + QString &errorString); + + /// Convert polygon to NED and return (D is ignored) + QList nedPolygon(void) const; + + /// Returns the area of the polygon in meters squared + double area(void) const; + + // Property methods + + int count(void) const { return _polygonPath.count(); } + bool dirty(void) const { return _dirty; } + void setDirty(bool dirty); + QGeoCoordinate center(void) const { return _center; } + bool centerDrag(void) const { return _centerDrag; } + bool interactive(void) const { return _interactive; } + + QVariantList path(void) const { return _polygonPath; } + const QVariantList &pathReference(void) const { return _polygonPath; } + QmlObjectListModel *qmlPathModel(void) { return &_polygonModel; } + QmlObjectListModel &pathModel(void) { return _polygonModel; } + + // Friends + friend void print(const QGCMapPolygon &poly, QString &outputString); + friend void print(const QGCMapPolygon &poly); + + // static Variables + static const char *jsonPolygonKey; signals: - void countChanged (int count); - void pathChanged (void); - void dirtyChanged (bool dirty); - void cleared (void); - void centerChanged (QGeoCoordinate center); - void centerDragChanged (bool centerDrag); - void interactiveChanged (bool interactive); - void areaChanged (void); + void countChanged(int count); + void pathChanged(void); + void dirtyChanged(bool dirty); + void cleared(void); + void centerChanged(QGeoCoordinate center); + void centerDragChanged(bool centerDrag); + void interactiveChanged(bool interactive); + void areaChanged(void); public slots: - void setPath (const QList& path); - void setPath (const QVector& path); - void setPath (const QVariantList& path); - void setCenter (QGeoCoordinate newCenter); - void setCenterDrag (bool centerDrag); - void setInteractive (bool interactive); + void setPath(const QList &path); + void setPath(const QVector &path); + void setPath(const QVariantList &path); + void setCenter(QGeoCoordinate newCenter); + void setCenterDrag(bool centerDrag); + void setInteractive(bool interactive); private slots: - void _polygonModelCountChanged (int count); - void _polygonModelDirtyChanged (bool dirty); - void _updateCenter (void); + void _polygonModelCountChanged(int count); + void _polygonModelDirtyChanged(bool dirty); + void _updateCenter(void); private: - void _init(void); - QPolygonF _toPolygonF(void) const; - QGeoCoordinate _coordFromPointF(const QPointF& point) const; - QPointF _pointFFromCoord(const QGeoCoordinate& coordinate) const; - - QVariantList _polygonPath; - QmlObjectListModel _polygonModel; - bool _dirty; - QGeoCoordinate _center; - bool _centerDrag; - bool _ignoreCenterUpdates; - bool _interactive; + void _init(void); + QPolygonF _toPolygonF(void) const; + QGeoCoordinate _coordFromPointF(const QPointF &point) const; + QPointF _pointFFromCoord(const QGeoCoordinate &coordinate) const; + + QVariantList _polygonPath; + QmlObjectListModel _polygonModel; + bool _dirty; + QGeoCoordinate _center; + bool _centerDrag; + bool _ignoreCenterUpdates; + bool _interactive; }; #endif diff --git a/src/Wima/Geometry/WimaServiceArea.cc b/src/Wima/Geometry/WimaServiceArea.cc index 0a482e0c1e9de30c2d99fce05959b6d13e54590f..a1b58314d3059bf4f7026f664fe8200be94ad917 100644 --- a/src/Wima/Geometry/WimaServiceArea.cc +++ b/src/Wima/Geometry/WimaServiceArea.cc @@ -23,10 +23,16 @@ WimaServiceArea &WimaServiceArea::operator=(const WimaServiceArea &other) { return *this; } +const QGeoCoordinate &WimaServiceArea::depot() const { return _depot; } + +QGeoCoordinate WimaServiceArea::depotQml() const { return _depot; } + bool WimaServiceArea::setDepot(const QGeoCoordinate &coordinate) { - if (_depot != coordinate) { + if (_depot.latitude() != coordinate.latitude() || + _depot.longitude() != coordinate.longitude()) { if (this->containsCoordinate(coordinate)) { _depot = coordinate; + _depot.setAltitude(0); emit depotChanged(); return true; } @@ -90,7 +96,27 @@ void WimaServiceArea::init() { this->setObjectName(wimaServiceAreaName); connect(this, &WimaArea::pathChanged, [this] { if (!this->_depot.isValid() || !this->containsCoordinate(this->_depot)) { - this->setDepot(this->center()); + if (this->containsCoordinate(this->center())) { + // Use center. + this->setDepot(this->center()); + } else if (this->_depot.isValid()) { + // Use nearest coordinate. + auto minDist = std::numeric_limits::infinity(); + auto minIt = this->pathReference().begin(); + for (auto it = this->pathReference().begin(); + it < this->pathReference().end(); ++it) { + const auto vertex = it->value(); + auto d = vertex.distanceTo(this->_depot); + if (d < minDist) { + minDist = d; + minIt = it; + } + } + this->setDepot(minIt->value()); + } else if (this->pathReference().size() > 0) { + // Use first coordinate. + this->setDepot(this->pathReference().value(0).value()); + } } }); } diff --git a/src/Wima/Geometry/WimaServiceArea.h b/src/Wima/Geometry/WimaServiceArea.h index 283aa9fa58c51b61eeaf99995dd276253be4a390..6bbb615bfca4c1c079b93bfede5f13b1c3146478 100644 --- a/src/Wima/Geometry/WimaServiceArea.h +++ b/src/Wima/Geometry/WimaServiceArea.h @@ -11,14 +11,16 @@ public: WimaServiceArea(const WimaServiceArea &other, QObject *parent); WimaServiceArea &operator=(const WimaServiceArea &other); - Q_PROPERTY(QGeoCoordinate depot READ depot WRITE setDepot NOTIFY depotChanged) + Q_PROPERTY( + QGeoCoordinate depot READ depotQml WRITE setDepot NOTIFY depotChanged) // Overrides from WimaPolygon QString mapVisualQML(void) const { return "WimaServiceAreaMapVisual.qml"; } QString editorQML(void) const { return "WimaServiceAreaEditor.qml"; } // Property acessors - const QGeoCoordinate &depot(void) const { return _depot; } + const QGeoCoordinate &depot(void) const; + QGeoCoordinate depotQml(void) const; // Member Methodes void saveToJson(QJsonObject &json); diff --git a/src/Wima/WaypointManager/EmptyManager.cpp b/src/Wima/WaypointManager/EmptyManager.cpp index c892c0f997f5211b6fe4b5f27dcefc630cc763ba..60a84ce533e3e46973d9efc58c48f07399c26754 100644 --- a/src/Wima/WaypointManager/EmptyManager.cpp +++ b/src/Wima/WaypointManager/EmptyManager.cpp @@ -7,12 +7,12 @@ WaypointManager::EmptyManager::EmptyManager(Settings &settings, AreaInterface &) void WaypointManager::EmptyManager::clear() {} -bool WaypointManager::EmptyManager::update() {} +bool WaypointManager::EmptyManager::update() { return true; } -bool WaypointManager::EmptyManager::next() {} +bool WaypointManager::EmptyManager::next() { return true; } -bool WaypointManager::EmptyManager::previous() {} +bool WaypointManager::EmptyManager::previous() { return true; } -bool WaypointManager::EmptyManager::reset() {} +bool WaypointManager::EmptyManager::reset() { return true; } } // namespace WaypointManager diff --git a/src/WimaView/DragCoordinate.qml b/src/WimaView/DragCoordinate.qml index 0d9b95694f70c7935750c6432f24ccd865411a56..265923188051ad810439c4e12af68176791aafc9 100644 --- a/src/WimaView/DragCoordinate.qml +++ b/src/WimaView/DragCoordinate.qml @@ -29,10 +29,8 @@ Item { property bool checked property string label: "Reference" - property var _itemVisual - property bool _itemVisualShowing: false - property var _dragArea - property bool _dragAreaShowing: false + property var _itemVisual: undefined + property var _dragArea: undefined signal clicked() signal released() @@ -45,31 +43,30 @@ Item { signal dragReleased() function hideItemVisuals() { - if (_itemVisualShowing) { + if (_itemVisual) { + map.removeMapItem(_itemVisual) _itemVisual.destroy() - _itemVisualShowing = false + _itemVisual = undefined } } function showItemVisuals() { - if (!_itemVisualShowing) { + if (!_itemVisual) { _itemVisual = indicatorComponent.createObject(map) map.addMapItem(_itemVisual) - _itemVisualShowing = true } } function hideDragArea() { - if (_dragAreaShowing) { + if (_dragArea) { _dragArea.destroy() - _dragAreaShowing = false + _dragArea = undefined } } function showDragArea() { - if (!_dragAreaShowing) { + if (!_dragArea) { _dragArea = dragAreaComponent.createObject(map) - _dragAreaShowing = true } } @@ -102,7 +99,9 @@ Item { itemIndicator: _itemVisual Component.onCompleted: itemCoordinate = _root.coordinate - onItemCoordinateChanged: _root.coordinate = itemCoordinate + onItemCoordinateChanged: { + _root.coordinate = itemCoordinate + } onDragStart: _root.dragStart() onDragStop: _root.dragStop() diff --git a/src/WimaView/WimaServiceAreaMapVisual.qml b/src/WimaView/WimaServiceAreaMapVisual.qml index 69f006a505c9891523720b2aa30d6b71d217e1b3..2fc0f94a3e122ee15efe890b1a48ec362ea4ecaa 100644 --- a/src/WimaView/WimaServiceAreaMapVisual.qml +++ b/src/WimaView/WimaServiceAreaMapVisual.qml @@ -26,35 +26,32 @@ Item { property var areaItem: object property var _polygon: areaItem - property var _depot - property bool showDepot: areaItem.interactive || areaItem.borderPolygon.interactive - property bool _depotVisible: false - - onShowDepotChanged: { - if (showDepot){ - if (!_depotVisible){ - _addDepot() - } + property var _depot: undefined + property bool _showDepot: areaItem.interactive || areaItem.borderPolygon.interactive + + on_ShowDepotChanged: { + if (_showDepot){ + _addDepot() } else { - if (_depotVisible){ - _destroyDepot() - } + _destroyDepot() } } signal clicked(int sequenceNumber) function _addDepot() { - _depot = depotPointComponent.createObject(map) - map.addMapItem(_depot) - _depotVisible = true + if (!_depot){ + _depot = depotPointComponent.createObject(_root) + map.addMapItem(_depot) + } } function _destroyDepot() { if (_depot){ + map.removeMapItem(_depot) _depot.destroy() + _depot = undefined } - _depotVisible = false } /// Add an initial 4 sided polygon if there is none @@ -104,7 +101,7 @@ Item { Component.onCompleted: { _addInitialPolygon() - if (showDepot){ + if (_showDepot){ _addDepot() } } @@ -137,21 +134,33 @@ Item { Component { id: depotPointComponent DragCoordinate { - property var depot: areaItem.depot + property var depot: _root.areaItem.depot map: _root.map qgcView: _root.qgcView z: QGroundControl.zOrderMapItems - checked: showDepot - coordinate: depot + checked: _root._showDepot + coordinate: _root.areaItem.depot label: "Depot" - onDragReleased: { - if (areaItem.containsCoordinate(coordinate)){ - areaItem.depot = coordinate + function syncAndBind(){ + if (coordinate.latitude !== depot.latitude || + coordinate.longitude !== depot.longitude){ + if (_root.areaItem.containsCoordinate(coordinate)){ + _root.areaItem.depot = coordinate + } } - coordinate = Qt.binding(function() { return areaItem.depot; }) + coordinate = Qt.binding(function(){return _root.areaItem.depot}) } + + onDragReleased: { + syncAndBind() + } + + Component.onCompleted: { + syncAndBind() + } + } }