Commit 855da00e authored by DonLakeFlyer's avatar DonLakeFlyer

Major work on GeoFence, clear mission on flight end

parent a25626fd
......@@ -27,7 +27,6 @@
<file alias="FlightDisplayViewUVC.qml">src/FlightDisplay/FlightDisplayViewUVC.qml</file>
<file alias="FlightModesComponentSummary.qml">src/AutoPilotPlugins/PX4/FlightModesComponentSummary.qml</file>
<file alias="GeneralSettings.qml">src/ui/preferences/GeneralSettings.qml</file>
<file alias="GeoFenceEditor.qml">src/MissionEditor/GeoFenceEditor.qml</file>
<file alias="GeoTagPage.qml">src/AnalyzeView/GeoTagPage.qml</file>
<file alias="JoystickConfig.qml">src/VehicleSetup/JoystickConfig.qml</file>
<file alias="LinkSettings.qml">src/ui/preferences/LinkSettings.qml</file>
......@@ -57,6 +56,8 @@
<file alias="QGroundControl/Controls/FlightModeDropdown.qml">src/QmlControls/FlightModeDropdown.qml</file>
<file alias="QGroundControl/Controls/FlightModeMenu.qml">src/QmlControls/FlightModeMenu.qml</file>
<file alias="QGroundControl/Controls/FWLandingPatternMapVisual.qml">src/MissionEditor/FWLandingPatternMapVisual.qml</file>
<file alias="QGroundControl/Controls/GeoFenceEditor.qml">src/MissionEditor/GeoFenceEditor.qml</file>
<file alias="QGroundControl/Controls/GeoFenceMapVisuals.qml">src/MissionEditor/GeoFenceMapVisuals.qml</file>
<file alias="QGroundControl/Controls/GuidedBar.qml">src/QmlControls/GuidedBar.qml</file>
<file alias="QGroundControl/Controls/IndicatorButton.qml">src/QmlControls/IndicatorButton.qml</file>
<file alias="QGroundControl/Controls/JoystickThumbPad.qml">src/QmlControls/JoystickThumbPad.qml</file>
......
......@@ -13,6 +13,8 @@
#include "MAVLinkProtocol.h"
#include "QGCApplication.h"
#include "ParameterManager.h"
#include "QmlObjectListModel.h"
#include "QGCQGeoCoordinate.h"
const char* APMGeoFenceManager::_fenceTotalParam = "FENCE_TOTAL";
const char* APMGeoFenceManager::_fenceActionParam = "FENCE_ACTION";
......@@ -44,7 +46,7 @@ APMGeoFenceManager::~APMGeoFenceManager()
}
void APMGeoFenceManager::sendToVehicle(const QGeoCoordinate& breachReturn, const QList<QGeoCoordinate>& polygon)
void APMGeoFenceManager::sendToVehicle(const QGeoCoordinate& breachReturn, QmlObjectListModel& polygon)
{
if (_vehicle->isOfflineEditingVehicle()) {
return;
......@@ -61,21 +63,20 @@ void APMGeoFenceManager::sendToVehicle(const QGeoCoordinate& breachReturn, const
// Validate
int validatedPolygonCount = 0;
if (polygonEnabled()) {
if (polygon.count() >= 3) {
validatedPolygonCount = polygon.count();
}
if (polygon.count() > std::numeric_limits<uint8_t>::max()) {
_sendError(TooManyPoints, QStringLiteral("Geo-Fence polygon has too many points: %1.").arg(_polygon.count()));
validatedPolygonCount = 0;
}
if (polygon.count() >= 3) {
validatedPolygonCount = polygon.count();
}
if (polygon.count() > std::numeric_limits<uint8_t>::max()) {
_sendError(TooManyPoints, QStringLiteral("Geo-Fence polygon has too many points: %1.").arg(_polygon.count()));
validatedPolygonCount = 0;
}
_breachReturnPoint = breachReturn;
_polygon.clear();
if (validatedPolygonCount) {
_polygon = polygon;
} else {
_polygon.clear();
for (int i=0; i<polygon.count(); i++) {
_polygon.append(polygon.value<QGCQGeoCoordinate*>(i)->coordinate());
}
}
// Total point count, +1 polygon close in last index, +1 for breach in index 0
......@@ -306,7 +307,7 @@ void APMGeoFenceManager::_parametersReady(void)
float APMGeoFenceManager::circleRadius(void) const
{
if (_circleEnabled) {
if (_circleRadiusFact) {
return _circleRadiusFact->rawValue().toFloat();
} else {
return 0.0;
......@@ -328,3 +329,10 @@ QString APMGeoFenceManager::editorQml(void) const
return QStringLiteral("qrc:/FirmwarePlugin/NoGeoFenceEditor.qml");
}
}
void APMGeoFenceManager::removeAll(void)
{
QmlObjectListModel emptyPolygon;
sendToVehicle(_breachReturnPoint, emptyPolygon);
}
......@@ -14,6 +14,8 @@
#include "QGCMAVLink.h"
#include "FactSystem.h"
class QmlObjectListModel;
class APMGeoFenceManager : public GeoFenceManager
{
Q_OBJECT
......@@ -25,7 +27,7 @@ public:
// Overrides from GeoFenceManager
bool inProgress (void) const final;
void loadFromVehicle (void) final;
void sendToVehicle (const QGeoCoordinate& breachReturn, const QList<QGeoCoordinate>& polygon) final;
void sendToVehicle (const QGeoCoordinate& breachReturn, QmlObjectListModel& polygon) final;
bool circleEnabled (void) const final { return _circleEnabled; }
bool polygonEnabled (void) const final { return _polygonEnabled; }
bool breachReturnEnabled (void) const final { return _breachReturnEnabled; }
......@@ -33,6 +35,7 @@ public:
QVariantList params (void) const final { return _params; }
QStringList paramLabels (void) const final { return _paramLabels; }
QString editorQml (void) const final;
void removeAll (void) final;
private slots:
void _mavlinkMessageReceived(const mavlink_message_t& message);
......
......@@ -149,3 +149,10 @@ bool APMRallyPointManager::rallyPointsSupported(void) const
{
return _vehicle->parameterManager()->parameterExists(_vehicle->defaultComponentId(), _rallyTotalParam);
}
void APMRallyPointManager::removeAll(void)
{
QList<QGeoCoordinate> noRallyPoints;
sendToVehicle(noRallyPoints);
}
......@@ -27,6 +27,8 @@ public:
void sendToVehicle (const QList<QGeoCoordinate>& rgPoints) final;
bool rallyPointsSupported (void) const final;
void removeAll (void);
QString editorQml(void) const final { return QStringLiteral("qrc:/FirmwarePlugin/APM/APMRallyPointEditor.qml"); }
private slots:
......
......@@ -24,7 +24,6 @@ Column {
anchors.right: parent.right
wrapMode: Text.WordWrap
text: qsTr("Click in map to set breach return point.")
visible: geoFenceController.breachReturnSupported
}
QGCLabel { text: qsTr("Fence Settings:") }
......@@ -73,14 +72,15 @@ Column {
}
}
QGCMapPolygonControls {
anchors.left: parent.left
anchors.right: parent.right
flightMap: editorMap
polygon: geoFenceController.polygon
sectionLabel: qsTr("Fence Polygon:")
visible: geoFenceController.polygonSupported
QGCButton {
text: qsTr("Add fence")
visible: geoFenceController.mapPolygon.count < 3
onClicked: geoFenceController.addFence()
}
onPolygonEditCompleted: geoFenceController.validateBreachReturn()
QGCButton {
text: qsTr("Remove fence")
visible: geoFenceController.mapPolygon.count >= 3
onClicked: geoFenceController.removeFence()
}
}
......@@ -196,13 +196,15 @@ Column {
FENCE_RET_RALLY - if set to 1 the aircraft will head to the nearest Rally Point rather than the fence return point when the fence is breached. Note that the loiter altitude of the Rally Point is used as the return altitude.
*/
QGCMapPolygonControls {
anchors.left: parent.left
anchors.right: parent.right
flightMap: editorMap
polygon: geoFenceController.polygon
sectionLabel: qsTr("Fence Polygon:")
QGCButton {
text: qsTr("Add fence")
visible: geoFenceController.mapPolygon.count < 3
onClicked: geoFenceController.addFence()
}
onPolygonEditCompleted: geoFenceController.validateBreachReturn()
QGCButton {
text: qsTr("Remove fence")
visible: geoFenceController.mapPolygon.count >= 3
onClicked: geoFenceController.removeFence()
}
}
......@@ -80,3 +80,7 @@ void PX4GeoFenceManager::_circleRadiusRawValueChanged(QVariant value)
emit circleRadiusChanged(value.toFloat());
}
void PX4GeoFenceManager::removeAll(void)
{
// Only params so nothing to do
}
......@@ -28,6 +28,7 @@ public:
QVariantList params (void) const final { return _params; }
QStringList paramLabels (void) const final { return _paramLabels; }
QString editorQml (void) const final { return QStringLiteral("qrc:/FirmwarePlugin/PX4/PX4GeoFenceEditor.qml"); }
void removeAll (void) final;
private slots:
void _circleRadiusRawValueChanged(QVariant value);
......
......@@ -148,6 +148,7 @@ QGCView {
anchors.fill: parent
flightWidgets: flightDisplayViewWidgets
rightPanelWidth: ScreenTools.defaultFontPixelHeight * 9
qgcView: root
}
}
......
......@@ -8,10 +8,11 @@
****************************************************************************/
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtLocation 5.3
import QtPositioning 5.3
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtLocation 5.3
import QtPositioning 5.3
import QtQuick.Dialogs 1.2
import QGroundControl 1.0
import QGroundControl.FlightDisplay 1.0
......@@ -34,6 +35,7 @@ FlightMap {
property alias missionController: missionController
property var flightWidgets
property var rightPanelWidth
property var qgcView ///< QGCView control which contains this map
property bool _followVehicle: true
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
......@@ -77,6 +79,49 @@ FlightMap {
Component.onCompleted: start(false /* editMode */)
}
// The following code is used to track vehicle states such that we prompt to remove mission from vehicle when mission completes
property bool vehicleArmed: _activeVehicle ? _activeVehicle.armed : false
property bool vehicleWasArmed: false
property bool vehicleInMissionFlightMode: _activeVehicle ? (_activeVehicle.flightMode === _activeVehicle.missionFlightMode) : false
property bool promptForMissionRemove: false
onVehicleArmedChanged: {
if (vehicleArmed) {
if (!promptForMissionRemove) {
promptForMissionRemove = vehicleInMissionFlightMode
vehicleWasArmed = true
}
} else {
if (promptForMissionRemove && (missionController.containsItems || geoFenceController.containsItems || rallyPointController.containsItems)) {
qgcView.showDialog(removeMissionDialogComponent, qsTr("Flight complete"), showDialogDefaultWidth, StandardButton.No | StandardButton.Yes)
}
promptForMissionRemove = false
}
}
onVehicleInMissionFlightModeChanged: {
if (!promptForMissionRemove && vehicleArmed) {
promptForMissionRemove = true
}
}
Component {
id: removeMissionDialogComponent
QGCViewMessage {
message: qsTr("Do you want to remove the mission from the vehicle?")
function accept() {
missionController.removeAllFromVehicle()
geoFenceController.removeAllFromVehicle()
rallyPointController.removeAllFromVehicle()
hideDialog()
}
}
}
ExclusiveGroup {
id: _mapTypeButtonsExclusiveGroup
}
......@@ -224,32 +269,11 @@ FlightMap {
model: _mainIsMap ? missionController.waypointLines : 0
}
// GeoFence polygon
MapPolygon {
border.color: "#80FF0000"
border.width: 3
path: geoFenceController.polygon.path
visible: geoFenceController.polygonEnabled
}
// GeoFence circle
MapCircle {
border.color: "#80FF0000"
border.width: 3
center: missionController.plannedHomePosition
radius: geoFenceController.circleRadius
z: QGroundControl.zOrderMapItems
visible: geoFenceController.circleEnabled
}
// GeoFence breach return point
MapQuickItem {
anchorPoint.x: sourceItem.anchorPointX
anchorPoint.y: sourceItem.anchorPointY
coordinate: geoFenceController.breachReturnPoint
visible: geoFenceController.breachReturnEnabled
sourceItem: MissionItemIndexLabel { label: "F" }
z: QGroundControl.zOrderMapItems
GeoFenceMapVisuals {
map: flightMap
myGeoFenceController: geoFenceController
interactive: false
homePosition: _activeVehicle && _activeVehicle.homePositionAvailable ? _activeVehicle.homePosition : undefined
}
// Rally points on map
......
......@@ -113,9 +113,9 @@ Item {
coordList.push(edgeCoordinate)
}
}
if (mapGeoFenceController.polygonEnabled && mapGeoFenceController.polygon.count() > 2) {
for (var i=0; i<mapGeoFenceController.polygon.count(); i++) {
coordList.push(mapGeoFenceController.polygon.path[i])
if (mapGeoFenceController.polygonEnabled && mapGeoFenceController.mapPolygon.path.count > 2) {
for (var i=0; i<mapGeoFenceController.mapPolygon.path.count; i++) {
coordList.push(mapGeoFenceController.mapPolygon.path[i])
}
}
}
......
......@@ -7,8 +7,9 @@
*
****************************************************************************/
#include "JsonHelper.h"
#include "QGCQGeoCoordinate.h"
#include "QmlObjectListModel.h"
#include <QJsonArray>
#include <QJsonParseError>
......@@ -308,3 +309,30 @@ QString JsonHelper::_jsonValueTypeToString(QJsonValue::Type type)
return QObject::tr("Unknown type: %1").arg(type);
}
bool JsonHelper::loadPolygon(const QJsonArray& polygonArray, QmlObjectListModel& list, QObject* parent, QString& errorString)
{
for (int i=0; i<polygonArray.count(); i++) {
const QJsonValue& pointValue = polygonArray[i];
QGeoCoordinate pointCoord;
if (!JsonHelper::loadGeoCoordinate(pointValue, false /* altitudeRequired */, pointCoord, errorString)) {
list.clearAndDeleteContents();
return false;
}
list.append(new QGCQGeoCoordinate(pointCoord, parent));
}
return true;
}
void JsonHelper::savePolygon(QmlObjectListModel& list, QJsonArray& polygonArray)
{
for (int i=0; i<list.count(); i++) {
QGeoCoordinate vertex = list.value<QGCQGeoCoordinate*>(i)->coordinate();
QJsonValue jsonValue;
JsonHelper::saveGeoCoordinate(vertex, false /* writeAltitude */, jsonValue);
polygonArray.append(jsonValue);
}
}
......@@ -14,6 +14,8 @@
#include <QVariantList>
#include <QGeoCoordinate>
class QmlObjectListModel;
class JsonHelper
{
public:
......@@ -52,6 +54,12 @@ public:
QGeoCoordinate& coordinate, ///< returned QGeoCordinate
QString& errorString); ///< returned error string if load failure
/// Loads a polygon from an array
static bool loadPolygon(const QJsonArray& polygonArray, ///< Array of coordinates
QmlObjectListModel& list, ///< Empty list to add vertices to
QObject* parent, ///< parent for newly allocated QGCQGeoCoordinates
QString& errorString); ///< returned error string if load failure
/// Saves a QGeoCoordinate
static void saveGeoCoordinate(const QGeoCoordinate& coordinate, ///< QGeoCoordinate to save
bool writeAltitude, ///< true: write altitude to json
......@@ -76,6 +84,10 @@ public:
bool writeAltitude, ///< true: write altitide value
QJsonValue& jsonValue); ///< json value to save to
/// Saves a polygon to a json array
static void savePolygon(QmlObjectListModel& list, ///< List which contains vertices
QJsonArray& polygonArray); ///< Array to save into
static bool parseEnum(const QJsonObject& jsonObject, QStringList& enumStrings, QStringList& enumValues, QString& errorString);
......
......@@ -12,11 +12,16 @@ QGCFlickable {
contentHeight: geoFenceEditorRect.height
clip: true
property real availableWidth
property real availableHeight
property var myGeoFenceController
property var flightMap
readonly property real _editFieldWidth: Math.min(width - _margin * 2, ScreenTools.defaultFontPixelWidth * 15)
readonly property real _margin: ScreenTools.defaultFontPixelWidth / 2
readonly property real _radius: ScreenTools.defaultFontPixelWidth / 2
property var polygon: geoFenceController.polygon
property var polygon: myGeoFenceController.polygon
Rectangle {
id: geoFenceEditorRect
......@@ -60,9 +65,11 @@ QGCFlickable {
anchors.margins: _margin
anchors.top: geoLabel.bottom
anchors.left: parent.left
source: geoFenceController.editorQml
source: myGeoFenceController.editorQml
property real availableWidth: parent.width - (_margin * 2)
property real availableWidth: parent.width - (_margin * 2)
property var geoFenceController: myGeoFenceController
property var myFlightMap: flightMap
}
}
}
......
This diff is collapsed.
......@@ -129,9 +129,7 @@ QGCView {
mapFitFunctions.fitMapViewportToMissionItems()
}
onVisualItemsChanged: {
itemDragger.clearItem()
}
onVisualItemsChanged: itemDragger.clearItem()
onNewItemsFromVehicle: {
if (_visualItems && _visualItems.count != 1) {
......@@ -165,17 +163,6 @@ QGCView {
}
}
function validateBreachReturn() {
if (geoFenceController.polygon.path.length > 0) {
if (!geoFenceController.polygon.containsCoordinate(geoFenceController.breachReturnPoint)) {
geoFenceController.breachReturnPoint = geoFenceController.polygon.center()
}
if (!geoFenceController.polygon.containsCoordinate(geoFenceController.breachReturnPoint)) {
geoFenceController.breachReturnPoint = geoFenceController.polygon.path[0]
}
}
}
function fitViewportToItems() {
mapFitFunctions.fitMapViewportToFenceItems()
}
......@@ -393,12 +380,6 @@ QGCView {
insertSimpleMissionItem(coordinate, missionController.visualItems.count)
}
break
case _layerGeoFence:
if (geoFenceController.breachReturnEnabled) {
geoFenceController.breachReturnPoint = coordinate
geoFenceController.validateBreachReturn()
}
break
case _layerRallyPoints:
if (rallyPointController.rallyPointsSupported) {
rallyPointController.addPoint(coordinate)
......@@ -492,6 +473,7 @@ QGCView {
anchors.top: parent.top
anchors.leftMargin: parent.width - _rightPanelWidth
anchors.left: parent.left
z: QGroundControl.zOrderWidgets
spacing: _horizontalMargin
visible: QGroundControl.corePlugin.options.enablePlanViewSelector
......@@ -613,40 +595,20 @@ QGCView {
anchors.top: planElementSelectorRow.bottom
anchors.right: parent.right
opacity: _rightPanelOpacity
z: QGroundControl.zOrderTopMost
source: _editingLayer == _layerGeoFence ? "qrc:/qml/GeoFenceEditor.qml" : ""
property real availableWidth: _rightPanelWidth
property real availableHeight: ScreenTools.availableHeight
}
// GeoFence polygon
MapPolygon {
border.color: "#80FF0000"
border.width: 3
path: geoFenceController.polygon.path
z: QGroundControl.zOrderMapItems
visible: geoFenceController.polygonEnabled
}
z: QGroundControl.zOrderWidgets
sourceComponent: _editingLayer == _layerGeoFence ? geoFenceEditorComponent : undefined
// GeoFence circle
MapCircle {
border.color: "#80FF0000"
border.width: 3
center: missionController.plannedHomePosition
radius: geoFenceController.circleRadius
z: QGroundControl.zOrderMapItems
visible: geoFenceController.circleEnabled
property real availableWidth: _rightPanelWidth
property real availableHeight: ScreenTools.availableHeight
property var myGeoFenceController: geoFenceController
}
// GeoFence breach return point
MapQuickItem {
anchorPoint.x: sourceItem.anchorPointX
anchorPoint.y: sourceItem.anchorPointY
coordinate: geoFenceController.breachReturnPoint
visible: geoFenceController.breachReturnEnabled
sourceItem: MissionItemIndexLabel { label: "F" }
z: QGroundControl.zOrderMapItems
GeoFenceMapVisuals {
map: editorMap
myGeoFenceController: geoFenceController
interactive: _editingLayer == _layerGeoFence
homePosition: missionController.plannedHomePosition
planView: true
}
// Rally Point Editor
......@@ -997,4 +959,15 @@ QGCView {
}
} // Column
}
Component {
id: geoFenceEditorComponent
GeoFenceEditor {
availableWidth: _rightPanelWidth
availableHeight: ScreenTools.availableHeight
myGeoFenceController: geoFenceController
flightMap: editorMap
}
}
} // QGCVIew
......@@ -18,6 +18,7 @@
#include "QGCApplication.h"
#include "ParameterManager.h"
#include "JsonHelper.h"
#include "QGCQGeoCoordinate.h"
#ifndef __mobile__
#include "MainWindow.h"
......@@ -25,6 +26,7 @@
#endif
#include <QJsonDocument>
#include <QJsonArray>
QGC_LOGGING_CATEGORY(GeoFenceControllerLog, "GeoFenceControllerLog")
......@@ -34,8 +36,10 @@ const char* GeoFenceController::_jsonBreachReturnKey = "breachReturn";
GeoFenceController::GeoFenceController(QObject* parent)
: PlanElementController(parent)
, _dirty(false)
, _mapPolygon(this)
{
connect(_mapPolygon.qmlPathModel(), &QmlObjectListModel::countChanged, this, &GeoFenceController::_updateContainsItems);
connect(_mapPolygon.qmlPathModel(), &QmlObjectListModel::dirtyChanged, this, &GeoFenceController::_polygonDirtyChanged);
}
GeoFenceController::~GeoFenceController()
......@@ -61,7 +65,7 @@ void GeoFenceController::startStaticActiveVehicle(Vehicle* vehicle)
void GeoFenceController::_init(void)
{
connect(&_polygon, &QGCMapPolygon::dirtyChanged, this, &GeoFenceController::_polygonDirtyChanged);
}
void GeoFenceController::setBreachReturnPoint(const QGeoCoordinate& breachReturnPoint)
......@@ -139,13 +143,11 @@ bool GeoFenceController::_loadJsonFile(QJsonDocument& jsonDoc, QString& errorStr
}
if (polygonEnabled()) {
if (!_polygon.loadFromJson(json, false /* reauired */, errorString)) {
if (!_mapPolygon.loadFromJson(json, true, errorString)) {
return false;
}
} else {
_polygon.clear();
}
_polygon.setDirty(false);
_mapPolygon.setDirty(false);
return true;
}
......@@ -289,7 +291,7 @@ void GeoFenceController::saveToFile(const QString& filename)
}
if (polygonEnabled()) {
_polygon.saveToJson(fenceFileObject);
_mapPolygon.saveToJson(fenceFileObject);
}
QJsonDocument saveDoc(fenceFileObject);
......@@ -314,7 +316,7 @@ void GeoFenceController::saveToFilePicker(void)
void GeoFenceController::removeAll(void)
{
setBreachReturnPoint(QGeoCoordinate());
_polygon.clear();
_mapPolygon.clear();
}
void GeoFenceController::loadFromVehicle(void)
......@@ -329,8 +331,8 @@ void GeoFenceController::loadFromVehicle(void)
void GeoFenceController::sendToVehicle(void)
{
if (_activeVehicle->parameterManager()->parametersReady() && !syncInProgress()) {
_activeVehicle->geoFenceManager()->sendToVehicle(_breachReturnPoint, _polygon.coordinateList());
_polygon.setDirty(false);
_activeVehicle->geoFenceManager()->sendToVehicle(_breachReturnPoint, _mapPolygon.pathModel());
_mapPolygon.setDirty(false);
setDirty(false);
} else {
qCWarning(GeoFenceControllerLog) << "GeoFenceController::loadFromVehicle call at wrong time" << _activeVehicle->parameterManager()->parametersReady() << syncInProgress();
......@@ -344,7 +346,7 @@ bool GeoFenceController::syncInProgress(void) const
bool GeoFenceController::dirty(void) const
{
return _dirty | _polygon.dirty();
return _dirty;
}
......@@ -353,7 +355,7 @@ void GeoFenceController::setDirty(bool dirty)
if (dirty != _dirty) {
_dirty = dirty;
if (!dirty) {
_polygon.setDirty(dirty);
_mapPolygon.setDirty(dirty);
}
emit dirtyChanged(dirty);
}
......@@ -388,9 +390,11 @@ void GeoFenceController::_setDirty(void)
void GeoFenceController::_setPolygonFromManager(const QList<QGeoCoordinate>& polygon)
{
_polygon.setPath(polygon);
_polygon.setDirty(false);
emit polygonPathChanged(_polygon.path());
_mapPolygon.clear();
for (int i=0; i<polygon.count(); i++) {
_mapPolygon.appendVertex(polygon[i]);
}
_mapPolygon.setDirty(false);
}
void GeoFenceController::_setReturnPointFromManager(QGeoCoordinate breachReturnPoint)
......@@ -431,3 +435,30 @@ QString GeoFenceController::fileExtension(void) const
{
return QGCApplication::fenceFileExtension;
}
bool GeoFenceController::containsItems(void) const
{
return _mapPolygon.count() > 2;
}
void GeoFenceController::_updateContainsItems(void)
{
emit containsItemsChanged(containsItems());
}
void GeoFenceController::removeAllFromVehicle(void)
{
_activeVehicle->geoFenceManager()->removeAll();
}
void GeoFenceController::addFence(void)
{
// GeoFenceMapVisuals control is resposible for this
emit addFencePolygon();
}
void GeoFenceController::removeFence(void)
{
_mapPolygon.clear();
}
......@@ -28,27 +28,22 @@ class GeoFenceController : public PlanElementController
public:
GeoFenceController(QObject* parent = NULL);
~GeoFenceController();
Q_PROPERTY(bool circleEnabled READ circleEnabled NOTIFY circleEnabledChanged)
Q_PROPERTY(float circleRadius READ circleRadius NOTIFY circleRadiusChanged)
Q_PROPERTY(bool polygonEnabled READ polygonEnabled NOTIFY polygonEnabledChanged)
Q_PROPERTY(QGCMapPolygon* polygon READ polygon CONSTANT)
Q_PROPERTY(bool circleEnabled READ circleEnabled NOTIFY circleEnabledChanged)
Q_PROPERTY(float circleRadius READ circleRadius NOTIFY circleRadiusChanged)
Q_PROPERTY(bool breachReturnEnabled READ breachReturnEnabled NOTIFY breachReturnEnabledChanged)
Q_PROPERTY(QGeoCoordinate breachReturnPoint READ breachReturnPoint WRITE setBreachReturnPoint NOTIFY breachReturnPointChanged)
Q_PROPERTY(bool polygonEnabled READ polygonEnabled NOTIFY polygonEnabledChanged)
Q_PROPERTY(QGCMapPolygon* mapPolygon READ mapPolygon CONSTANT)
Q_PROPERTY(QVariantList params READ params NOTIFY paramsChanged)
Q_PROPERTY(QStringList paramLabels READ paramLabels NOTIFY paramLabelsChanged)
Q_PROPERTY(QString editorQml READ editorQml NOTIFY editorQmlChanged)
Q_PROPERTY(bool breachReturnEnabled READ breachReturnEnabled NOTIFY breachReturnEnabledChanged)
Q_PROPERTY(QGeoCoordinate breachReturnPoint READ breachReturnPoint WRITE setBreachReturnPoint NOTIFY breachReturnPointChanged)
#if 0
Q_PROPERTY(bool fenceSupported READ fenceSupported NOTIFY fenceSupportedChanged)
Q_PROPERTY(bool fenceEnabled READ fenceEnabled NOTIFY fenceEnabledChanged)
Q_PROPERTY(bool circleSupported READ circleSupported NOTIFY circleSupportedChanged)
Q_PROPERTY(bool polygonSupported READ polygonSupported NOTIFY polygonSupportedChanged)
Q_PROPERTY(bool breachReturnSupported READ breachReturnSupported NOTIFY breachReturnSupportedChanged)
#endif
Q_PROPERTY(QVariantList params READ params NOTIFY paramsChanged)
Q_PROPERTY(QStringList paramLabels READ paramLabels NOTIFY paramLabelsChanged)
Q_PROPERTY(QString editorQml READ editorQml NOTIFY editorQmlChanged)
Q_INVOKABLE void addFence(void);
Q_INVOKABLE void removeFence(void);
void start (bool editMode) final;
void startStaticActiveVehicle (Vehicle* vehicle) final;
......@@ -59,9 +54,11 @@ public:
void saveToFilePicker (void) final;
void saveToFile (const QString& filename) final;
void removeAll (void) final;
void removeAllFromVehicle (void) final;
bool syncInProgress (void) const final;
bool dirty (void) const final;
void setDirty (bool dirty) final;
bool containsItems (void) const final;
QString fileExtension(void) const final;
......@@ -69,7 +66,7 @@ public:
bool polygonEnabled (void) const;
bool breachReturnEnabled (void) const;
float circleRadius (void) const;
QGCMapPolygon* polygon (void) { return &_polygon; }
QGCMapPolygon* mapPolygon (void) { return &_mapPolygon; }
QGeoCoordinate breachReturnPoint (void) const { return _breachReturnPoint; }
QVariantList params (void) const;
QStringList paramLabels (void) const;
......@@ -78,11 +75,11 @@ public:
void setBreachReturnPoint(const QGeoCoordinate& breachReturnPoint);
signals:
void addFencePolygon (void);
void circleEnabledChanged (bool circleEnabled);
void polygonEnabledChanged (bool polygonEnabled);
void breachReturnEnabledChanged (bool breachReturnEnabled);
void circleRadiusChanged (float circleRadius);
void polygonPathChanged (const QVariantList& polygonPath);
void breachReturnPointChanged (QGeoCoordinate breachReturnPoint);
void paramsChanged (QVariantList params);
void paramLabelsChanged (QStringList paramLabels);
......@@ -95,6 +92,7 @@ private slots:
void _setPolygonFromManager(const QList<QGeoCoordinate>& polygon);
void _setReturnPointFromManager(QGeoCoordinate breachReturnPoint);
void _loadComplete(const QGeoCoordinate& breachReturn, const QList<QGeoCoordinate>& polygon);
void _updateContainsItems(void);
private:
void _init(void);
......@@ -105,7 +103,7 @@ private:
void _activeVehicleSet(void) final;
bool _dirty;
QGCMapPolygon _polygon;
QGCMapPolygon _mapPolygon;
QGeoCoordinate _breachReturnPoint;
QVariantList _params;
......
......@@ -9,6 +9,7 @@
#include "GeoFenceManager.h"
#include "Vehicle.h"
#include "QmlObjectListModel.h"
QGC_LOGGING_CATEGORY(GeoFenceManagerLog, "GeoFenceManagerLog")
......@@ -37,7 +38,7 @@ void GeoFenceManager::loadFromVehicle(void)
emit loadComplete(QGeoCoordinate(), QList<QGeoCoordinate>());
}
void GeoFenceManager::sendToVehicle(const QGeoCoordinate& breachReturn, const QList<QGeoCoordinate>& polygon)
void GeoFenceManager::sendToVehicle(const QGeoCoordinate& breachReturn, QmlObjectListModel& polygon)
{
Q_UNUSED(breachReturn);
Q_UNUSED(polygon);
......
......@@ -16,6 +16,7 @@
#include "QGCLoggingCategory.h"
class Vehicle;
class QmlObjectListModel;
Q_DECLARE_LOGGING_CATEGORY(GeoFenceManagerLog)
......@@ -36,7 +37,9 @@ public:
virtual void loadFromVehicle(void);
/// Send the current settings to the vehicle
virtual void sendToVehicle(const QGeoCoordinate& breachReturn, const QList<QGeoCoordinate>& polygon);
virtual void sendToVehicle(const QGeoCoordinate& breachReturn, QmlObjectListModel& polygon);
virtual void removeAll(void) { };
virtual bool circleEnabled (void) const { return false; }
virtual bool polygonEnabled (void) const { return false; }
......
......@@ -95,27 +95,41 @@ void MissionController::_init(void)
}
// Called when new mission items have completed downloading from Vehicle
void MissionController::_newMissionItemsAvailableFromVehicle(void)
void MissionController::_newMissionItemsAvailableFromVehicle(bool removeAllRequested)
{
qCDebug(MissionControllerLog) << "_newMissionItemsAvailableFromVehicle";
if (!_editMode || _missionItemsRequested || _visualItems->count() == 1) {
// Fly Mode:
if (!_editMode || removeAllRequested || _missionItemsRequested || _visualItems->count() == 1) {
// Fly Mode (accept if):
// - Always accepts new items from the vehicle so Fly view is kept up to date
// Edit Mode:
// Edit Mode (accept if):
// - Either a load from vehicle was manually requested or
// - The initial automatic load from a vehicle completed and the current editor is empty
// - Remove all way requested from Fly view (clear mission on flight end)
QmlObjectListModel* newControllerMissionItems = new QmlObjectListModel(this);
const QList<MissionItem*>& newMissionItems = _activeVehicle->missionManager()->missionItems();
qCDebug(MissionControllerLog) << "loading from vehicle: count"<< newMissionItems.count();
int i = 0;
if (_activeVehicle->firmwarePlugin()->sendHomePositionToVehicle() && newMissionItems.count() != 0) {
// First item is fake home position
_addMissionSettings(_activeVehicle, newControllerMissionItems, false /* addToCenter */);
MissionSettingsComplexItem* settingsItem = newControllerMissionItems->value<MissionSettingsComplexItem*>(0);
if (!settingsItem) {
qWarning() << "First item is not settings item";
return;
}
settingsItem->setCoordinate(newMissionItems[0]->coordinate());
i = 1;
}
qCDebug(MissionControllerLog) << "loading from vehicle: count"<< _visualItems->count();
foreach(const MissionItem* missionItem, newMissionItems) {
for (; i<newMissionItems.count(); i++) {
const MissionItem* missionItem = newMissionItems[i];
newControllerMissionItems->append(new SimpleMissionItem(_activeVehicle, *missionItem, this));
}
_deinitAllVisualItems();
_visualItems->deleteLater();
_visualItems = newControllerMissionItems;
......@@ -1112,9 +1126,10 @@ void MissionController::_initAllVisualItems(void)
_recalcAll();
emit visualItemsChanged();
connect(_visualItems, &QmlObjectListModel::dirtyChanged, this, &MissionController::dirtyChanged);
connect(_visualItems, &QmlObjectListModel::countChanged, this, &MissionController::_updateContainsItems);
emit visualItemsChanged();
_visualItems->setDirty(false);
}
......@@ -1126,6 +1141,7 @@ void MissionController::_deinitAllVisualItems(void)
}
disconnect(_visualItems, &QmlObjectListModel::dirtyChanged, this, &MissionController::dirtyChanged);
disconnect(_visualItems, &QmlObjectListModel::countChanged, this, &MissionController::_updateContainsItems);
}
void MissionController::_initVisualItem(VisualMissionItem* visualItem)
......@@ -1494,3 +1510,19 @@ void MissionController::_scanForAdditionalSettings(QmlObjectListModel* visualIte
scanIndex++;
}
}
void MissionController::_updateContainsItems(void)
{
emit containsItemsChanged(containsItems());
}
bool MissionController::containsItems(void) const
{
return _visualItems ? _visualItems->count() > 1 : false;
}
void MissionController::removeAllFromVehicle(void)
{
_missionItemsRequested = true;
_activeVehicle->missionManager()->removeAll();
}
......@@ -82,9 +82,11 @@ public:
void saveToFilePicker (void) final;
void saveToFile (const QString& filename) final;
void removeAll (void) final;
void removeAllFromVehicle (void) final;
bool syncInProgress (void) const final;
bool dirty (void) const final;
void setDirty (bool dirty) final;
bool containsItems (void) const final;
QString fileExtension(void) const final;
......@@ -122,7 +124,7 @@ signals:
void hoverSpeedChanged(double hoverSpeed);
private slots:
void _newMissionItemsAvailableFromVehicle();
void _newMissionItemsAvailableFromVehicle(bool removeAllRequested);
void _itemCommandChanged(void);
void _activeVehicleHomePositionAvailableChanged(bool homePositionAvailable);
void _activeVehicleHomePositionChanged(const QGeoCoordinate& homePosition);
......@@ -131,6 +133,7 @@ private slots:
void _recalcWaypointLines(void);
void _recalcAltitudeRangeBearing(void);
void _homeCoordinateChanged(void);
void _updateContainsItems(void);
private:
void _init(void);
......
......@@ -73,7 +73,7 @@ void MissionManager::writeMissionItems(const QList<MissionItem*>& missionItems)
}
}
}
emit newMissionItemsAvailable();
emit newMissionItemsAvailable(missionItems.count() == 0);
qCDebug(MissionManagerLog) << "writeMissionItems count:" << _missionItems.count();
......@@ -306,7 +306,7 @@ void MissionManager::_readTransactionComplete(void)
_vehicle->sendMessageOnLink(_dedicatedLink, message);
_finishTransaction(true);
emit newMissionItemsAvailable();
emit newMissionItemsAvailable(false);
}
void MissionManager::_handleMissionCount(const mavlink_message_t& message)
......@@ -737,7 +737,7 @@ void MissionManager::_finishTransaction(bool success)
if (!success && _readTransactionInProgress) {
// Read from vehicle failed, clear partial list
_missionItems.clear();
emit newMissionItemsAvailable();
emit newMissionItemsAvailable(false);
}
_itemIndicesToRead.clear();
......@@ -767,3 +767,10 @@ void MissionManager::_handleMissionCurrent(const mavlink_message_t& message)
emit currentItemChanged(_currentMissionItem);
}
}
void MissionManager::removeAll(void)
{
QList<MissionItem*> emptyList;
writeMissionItems(emptyList);
}
......@@ -49,6 +49,9 @@ public:
/// @param altChangeOnly true: only altitude change, false: lat/lon/alt change
void writeArduPilotGuidedMissionItem(const QGeoCoordinate& gotoCoord, bool altChangeOnly);
/// Removes all mission items from vehicle
void removeAll(void);
/// Error codes returned in error signal
typedef enum {
InternalError,
......@@ -66,7 +69,7 @@ public:
static const int _maxRetryCount = 5;
signals:
void newMissionItemsAvailable(void);
void newMissionItemsAvailable(bool removeAllRequested);
void inProgressChanged(bool inProgress);
void error(int errorCode, const QString& errorMsg);
void currentItemChanged(int currentItem);
......
......@@ -25,17 +25,14 @@ public:
PlanElementController(QObject* parent = NULL);
~PlanElementController();
/// true: information is currently being saved/sent, false: no active save/send in progress
Q_PROPERTY(bool syncInProgress READ syncInProgress NOTIFY syncInProgressChanged)
Q_PROPERTY(bool containsItems READ containsItems NOTIFY containsItemsChanged) ///< true: Elemement is non-empty
Q_PROPERTY(bool syncInProgress READ syncInProgress NOTIFY syncInProgressChanged) ///< true: information is currently being saved/sent, false: no active save/send in progress
Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged) ///< true: unsaved/sent changes are present, false: no changes since last save/send
Q_PROPERTY(QString fileExtension READ fileExtension CONSTANT) ///< Returns the file extention for plan element file type.
Q_PROPERTY(Vehicle* vehicle READ vehicle NOTIFY vehicleChanged)
/// true: unsaved/sent changes are present, false: no changes since last save/send
Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged)
/// Returns the file extention for plan element file type.
Q_PROPERTY(QString fileExtension READ fileExtension CONSTANT)
virtual QString fileExtension(void) const = 0;
Q_PROPERTY(Vehicle* vehicle READ vehicle NOTIFY vehicleChanged)
/// Should be called immediately upon Component.onCompleted.
/// @param editMode true: controller being used in Plan view, false: controller being used in Fly view
......@@ -51,8 +48,10 @@ public:
Q_INVOKABLE virtual void loadFromFile(const QString& filename) = 0;
Q_INVOKABLE virtual void saveToFilePicker(void) = 0;
Q_INVOKABLE virtual void saveToFile(const QString& filename) = 0;
Q_INVOKABLE virtual void removeAll(void) = 0;
Q_INVOKABLE virtual void removeAll(void) = 0; ///< Removes all from controller only, synce required to remove from vehicle
Q_INVOKABLE virtual void removeAllFromVehicle(void) = 0; ///< Removes all from vehicle and controller
virtual bool containsItems (void) const = 0;
virtual bool syncInProgress (void) const = 0;
virtual bool dirty (void) const = 0;
virtual void setDirty (bool dirty) = 0;
......@@ -60,6 +59,7 @@ public:
Vehicle* vehicle(void) { return _activeVehicle; }
signals:
void containsItemsChanged (bool containsItems);
void syncInProgressChanged (bool syncInProgress);
void dirtyChanged (bool dirty);
void vehicleChanged (Vehicle* vehicle);
......
......@@ -10,6 +10,7 @@
#include "QGCMapPolygon.h"
#include "QGCGeo.h"
#include "JsonHelper.h"
#include "QGCQGeoCoordinate.h"
#include <QGeoRectangle>
#include <QDebug>
......@@ -17,21 +18,13 @@
const char* QGCMapPolygon::_jsonPolygonKey = "polygon";
QGCMapPolygon::QGCMapPolygon(QObject* parent)
QGCMapPolygon::QGCMapPolygon(QObject* newCoordParent, QObject* parent)
: QObject(parent)
, _newCoordParent(newCoordParent)
, _dirty(false)
{
}
const QGCMapPolygon& QGCMapPolygon::operator=(const QGCMapPolygon& other)
{
_polygonPath = other._polygonPath;
setDirty(true);
emit pathChanged();
return *this;
connect(&_polygonModel, &QmlObjectListModel::dirtyChanged, this, &QGCMapPolygon::_polygonModelDirtyChanged);
connect(&_polygonModel, &QmlObjectListModel::countChanged, this, &QGCMapPolygon::_polygonModelCountChanged);
}
void QGCMapPolygon::clear(void)
......@@ -48,13 +41,18 @@ void QGCMapPolygon::clear(void)
// will cause the polygon to go away.
_polygonPath.clear();
_polygonModel.clearAndDeleteContents();
setDirty(true);
}
void QGCMapPolygon::adjustCoordinate(int vertexIndex, const QGeoCoordinate coordinate)
void QGCMapPolygon::adjustVertex(int vertexIndex, const QGeoCoordinate coordinate)
{
_polygonPath[vertexIndex] = QVariant::fromValue(coordinate);
emit pathChanged();
_polygonModel.value<QGCQGeoCoordinate*>(vertexIndex)->setCoordinate(coordinate);
setDirty(true);
}
......@@ -126,9 +124,12 @@ QGeoCoordinate QGCMapPolygon::center(void) const
void QGCMapPolygon::setPath(const QList<QGeoCoordinate>& path)
{
_polygonPath.clear();
_polygonModel.clearAndDeleteContents();
foreach(const QGeoCoordinate& coord, path) {
_polygonPath << QVariant::fromValue(coord);
_polygonPath.append(QVariant::fromValue(coord));
_polygonModel.append(new QGCQGeoCoordinate(coord, _newCoordParent));
}
setDirty(true);
emit pathChanged();
}
......@@ -136,6 +137,12 @@ void QGCMapPolygon::setPath(const QList<QGeoCoordinate>& path)
void QGCMapPolygon::setPath(const QVariantList& path)
{
_polygonPath = path;
_polygonModel.clearAndDeleteContents();
for (int i=0; i<_polygonPath.count(); i++) {
_polygonModel.append(new QGCQGeoCoordinate(_polygonPath[i].value<QGeoCoordinate>(), _newCoordParent));
}
setDirty(true);
emit pathChanged();
}
......@@ -175,9 +182,70 @@ QList<QGeoCoordinate> QGCMapPolygon::coordinateList(void) const
{
QList<QGeoCoordinate> coords;
for (int i=0; i<count(); i++) {
coords.append((*this)[i]);
for (int i=0; i<_polygonPath.count(); i++) {
coords.append(_polygonPath[i].value<QGeoCoordinate>());
}
return coords;
}
void QGCMapPolygon::splitPolygonSegment(int vertexIndex)
{
int nextIndex = vertexIndex + 1;
if (nextIndex > _polygonPath.length() - 1) {
nextIndex = 0;
}
QGeoCoordinate firstVertex = _polygonPath[vertexIndex].value<QGeoCoordinate>();
QGeoCoordinate nextVertex = _polygonPath[nextIndex].value<QGeoCoordinate>();
double distance = firstVertex.distanceTo(nextVertex);
double azimuth = firstVertex.azimuthTo(nextVertex);
QGeoCoordinate newVertex = firstVertex.atDistanceAndAzimuth(distance / 2, azimuth);
if (nextIndex == 0) {
appendVertex(newVertex);
} else {
_polygonModel.insert(nextIndex, new QGCQGeoCoordinate(newVertex, this));
_polygonPath.insert(nextIndex, QVariant::fromValue(newVertex));
emit pathChanged();
}
}
void QGCMapPolygon::appendVertex(const QGeoCoordinate& coordinate)
{
_polygonPath.append(QVariant::fromValue(coordinate));
_polygonModel.append(new QGCQGeoCoordinate(coordinate, _newCoordParent));
emit pathChanged();
}
void QGCMapPolygon::_polygonModelDirtyChanged(bool dirty)
{
if (dirty) {
setDirty(true);
}
}
void QGCMapPolygon::removeVertex(int vertexIndex)
{
if (vertexIndex < 0 && vertexIndex > _polygonPath.length() - 1) {
qWarning() << "Call to removePolygonCoordinate with bad vertexIndex:count" << vertexIndex << _polygonPath.length();
return;
}
if (_polygonPath.length() <= 3) {
// Don't allow the user to trash the polygon
return;
}
QObject* coordObj = _polygonModel.removeAt(vertexIndex);
coordObj->deleteLater();
_polygonPath.removeAt(vertexIndex);
emit pathChanged();
}
void QGCMapPolygon::_polygonModelCountChanged(int count)
{
emit countChanged(count);
}
......@@ -15,33 +15,33 @@
#include <QVariantList>
#include <QPolygon>
/// The QGCMapPolygon class provides a polygon which can be displayed on a map using a MapPolygon control.
/// It works in conjunction with the QGCMapPolygonControls control which provides the UI for drawing and
/// editing map polygons.
#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
public:
QGCMapPolygon(QObject* parent = NULL);
const QGCMapPolygon& operator=(const QGCMapPolygon& other);
QGeoCoordinate operator[](int index) const { return _polygonPath[index].value<QGeoCoordinate>(); }
/// The polygon path to be bound to the MapPolygon.path property
Q_PROPERTY(QVariantList path READ path WRITE setPath NOTIFY pathChanged)
QGCMapPolygon(QObject* newCoordParent, QObject* parent = NULL);
/// true: Polygon has changed since last time dirty was false
Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged)
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)
/// Remove all points from polygon
Q_INVOKABLE void clear(void);
Q_INVOKABLE void appendVertex(const QGeoCoordinate& coordinate);
Q_INVOKABLE void removeVertex(int vertexIndex);
/// 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 adjustCoordinate(int vertexIndex, const QGeoCoordinate coordinate);
Q_INVOKABLE void adjustVertex(int vertexIndex, const QGeoCoordinate coordinate);
/// Splits the segment comprised of vertextIndex -> vertexIndex + 1
Q_INVOKABLE void splitPolygonSegment(int vertexIndex);
/// Returns the center point coordinate for the polygon
Q_INVOKABLE QGeoCoordinate center(void) const;
......@@ -49,9 +49,6 @@ public:
/// Returns true if the specified coordinate is within the polygon
Q_INVOKABLE bool containsCoordinate(const QGeoCoordinate& coordinate) const;
/// Returns the number of points in the polygon
Q_INVOKABLE int count(void) const { return _polygonPath.count(); }
/// Returns the path in a list of QGeoCoordinate's format
QList<QGeoCoordinate> coordinateList(void) const;
......@@ -68,24 +65,35 @@ public:
// Property methods
bool dirty(void) const { return _dirty; }
void setDirty(bool dirty);
int count (void) const { return _polygonPath.count(); }
bool dirty (void) const { return _dirty; }
void setDirty(bool dirty);
QVariantList path (void) const { return _polygonPath; }
QmlObjectListModel* qmlPathModel(void) { return &_polygonModel; }
QmlObjectListModel& pathModel (void) { return _polygonModel; }
QVariantList path(void) const { return _polygonPath; }
void setPath(const QList<QGeoCoordinate>& path);
void setPath(const QVariantList& path);
signals:
void countChanged(int count);
void pathChanged(void);
void dirtyChanged(bool dirty);
private slots:
void _polygonModelCountChanged(int count);
void _polygonModelDirtyChanged(bool dirty);
private:
QPolygonF _toPolygonF(void) const;
QGeoCoordinate _coordFromPointF(const QPointF& point) const;
QPointF _pointFFromCoord(const QGeoCoordinate& coordinate) const;
QVariantList _polygonPath;
bool _dirty;
QObject* _newCoordParent;
QVariantList _polygonPath;
QmlObjectListModel _polygonModel;
bool _dirty;
static const char* _jsonPolygonKey;
};
......
......@@ -40,7 +40,7 @@ RallyPointController::RallyPointController(QObject* parent)
, _dirty(false)
, _currentRallyPoint(NULL)
{
connect(&_points, &QmlObjectListModel::countChanged, this, &RallyPointController::_updateContainsItems);
}
RallyPointController::~RallyPointController()
......@@ -313,3 +313,18 @@ void RallyPointController::_setFirstPointCurrent(void)
{
setCurrentRallyPoint(_points.count() ? _points[0] : NULL);
}
bool RallyPointController::containsItems(void) const
{
return _points.count() > 0;
}
void RallyPointController::_updateContainsItems(void)
{
emit containsItemsChanged(containsItems());
}
void RallyPointController::removeAllFromVehicle(void)
{
_activeVehicle->rallyPointManager()->removeAll();
}
......@@ -37,16 +37,18 @@ public:
Q_INVOKABLE void addPoint(QGeoCoordinate point);
Q_INVOKABLE void removePoint(QObject* rallyPoint);
void loadFromVehicle (void) final;
void sendToVehicle (void) final;
void loadFromFilePicker (void) final;
void loadFromFile (const QString& filename) final;
void saveToFilePicker (void) final;
void saveToFile (const QString& filename) final;
void removeAll (void) final;
bool syncInProgress (void) const final;
bool dirty (void) const final { return _dirty; }
void setDirty (bool dirty) final;
void loadFromVehicle (void) final;
void sendToVehicle (void) final;
void loadFromFilePicker (void) final;
void loadFromFile (const QString& filename) final;
void saveToFilePicker (void) final;
void saveToFile (const QString& filename) final;
void removeAll (void) final;
void removeAllFromVehicle (void) final;
bool syncInProgress (void) const final;
bool dirty (void) const final { return _dirty; }
void setDirty (bool dirty) final;
bool containsItems (void) const final;
QString fileExtension(void) const final;
......@@ -65,6 +67,7 @@ signals:
private slots:
void _loadComplete(const QList<QGeoCoordinate> rgPoints);
void _setFirstPointCurrent(void);
void _updateContainsItems(void);
private:
bool _loadJsonFile(QJsonDocument& jsonDoc, QString& errorString);
......
......@@ -38,6 +38,8 @@ public:
/// Send the current settings to the vehicle
virtual void sendToVehicle(const QList<QGeoCoordinate>& rgPoints);
virtual void removeAll(void) { };
virtual bool rallyPointsSupported(void) const { return false; }
QList<QGeoCoordinate> points(void) const { return _rgPoints; }
......
......@@ -335,17 +335,8 @@ void SurveyMissionItem::save(QJsonArray& missionItems)
}
// Polygon shape
QJsonArray polygonArray;
for (int i=0; i<_polygonPath.count(); i++) {
const QVariant& polyVar = _polygonPath[i];
QJsonValue jsonValue;
JsonHelper::saveGeoCoordinate(polyVar.value<QGeoCoordinate>(), false /* writeAltitude */, jsonValue);
polygonArray += jsonValue;
}
JsonHelper::savePolygon(_polygonModel, polygonArray);
saveObject[_jsonPolygonObjectKey] = polygonArray;
missionItems.append(saveObject);
......@@ -494,16 +485,12 @@ bool SurveyMissionItem::load(const QJsonObject& complexObject, int sequenceNumbe
// Polygon shape
QJsonArray polygonArray(v2Object[_jsonPolygonObjectKey].toArray());
for (int i=0; i<polygonArray.count(); i++) {
const QJsonValue& pointValue = polygonArray[i];
QGeoCoordinate pointCoord;
if (!JsonHelper::loadGeoCoordinate(pointValue, false /* altitudeRequired */, pointCoord, errorString)) {
_clear();
return false;
}
_polygonPath << QVariant::fromValue(pointCoord);
_polygonModel.append(new QGCQGeoCoordinate(pointCoord, this));
if (!JsonHelper::loadPolygon(polygonArray, _polygonModel, this, errorString)) {
_clear();
return false;
}
for (int i=0; i<_polygonModel.count(); i++) {
_polygonPath << QVariant::fromValue(_polygonModel.value<QGCQGeoCoordinate*>(i)->coordinate());
}
_generateGrid();
......
......@@ -10,6 +10,8 @@ ExclusiveGroupItem 1.0 ExclusiveGroupItem.qml
FactSliderPanel 1.0 FactSliderPanel.qml
FlightModeDropdown 1.0 FlightModeDropdown.qml
FlightModeMenu 1.0 FlightModeMenu.qml
GeoFenceEditor 1.0 GeoFenceEditor.qml
GeoFenceMapVisuals 1.0 GeoFenceMapVisuals.qml
GuidedBar 1.0 GuidedBar.qml
IndicatorButton 1.0 IndicatorButton.qml
JoystickThumbPad 1.0 JoystickThumbPad.qml
......
......@@ -33,7 +33,7 @@ public:
int count(void) const;
bool dirty(void) { return _dirty; }
bool dirty(void) const { return _dirty; }
void setDirty(bool dirty);
void append(QObject* object);
......
......@@ -166,6 +166,7 @@ Vehicle::Vehicle(LinkInterface* link,
connect(this, &Vehicle::_sendMessageOnLinkOnThread, this, &Vehicle::_sendMessageOnLink, Qt::QueuedConnection);
connect(this, &Vehicle::flightModeChanged, this, &Vehicle::_handleFlightModeChanged);
connect(this, &Vehicle::armedChanged, this, &Vehicle::_announceArmedChanged);
_uas = new UAS(_mavlink, this, _firmwarePluginManager);
connect(_uas, &UAS::imageReady, this, &Vehicle::_imageReady);
......@@ -317,14 +318,16 @@ void Vehicle::_commonInit(void)
_firmwarePlugin = _firmwarePluginManager->firmwarePluginForAutopilot(_firmwareType, _vehicleType);
_missionManager = new MissionManager(this);
connect(_missionManager, &MissionManager::error, this, &Vehicle::_missionManagerError);
connect(_missionManager, &MissionManager::error, this, &Vehicle::_missionManagerError);
connect(_missionManager, &MissionManager::newMissionItemsAvailable, this, &Vehicle::_newMissionItemsAvailable);
_parameterManager = new ParameterManager(this);
connect(_parameterManager, &ParameterManager::parametersReadyChanged, this, &Vehicle::_parametersReady);
// GeoFenceManager needs to access ParameterManager so make sure to create after
_geoFenceManager = _firmwarePlugin->newGeoFenceManager(this);
connect(_geoFenceManager, &GeoFenceManager::error, this, &Vehicle::_geoFenceManagerError);
connect(_geoFenceManager, &GeoFenceManager::error, this, &Vehicle::_geoFenceManagerError);
connect(_geoFenceManager, &GeoFenceManager::loadComplete, this, &Vehicle::_newGeoFenceAvailable);
_rallyPointManager = _firmwarePlugin->newRallyPointManager(this);
connect(_rallyPointManager, &RallyPointManager::error, this, &Vehicle::_rallyPointManagerError);
......
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