Commit 404c65ce authored by Valentin Platzgummer's avatar Valentin Platzgummer

WimaMenu edited, upload progress bar added, guided action for override upload added.

parent 1f7fc4d2
This diff is collapsed.
This diff is collapsed.
......@@ -548,6 +548,7 @@ QGCView {
wimaController: wimaController
planMasterController: masterController
}
//-------------------------------------------------------------------------
......@@ -689,12 +690,21 @@ QGCView {
GuidedActionsController {
id: guidedActionsController
wimaController: wimaController
missionController: _missionController
confirmDialog: guidedActionConfirm
actionList: guidedActionList
altitudeSlider: _altitudeSlider
z: _flightVideoPipControl.z + 1
property bool uploadOverrideRequired: wimaController.uploadOverrideRequired
onUploadOverrideRequiredChanged: {
if (uploadOverrideRequired) {
confirmAction(actionOverrideUpload)
}
}
onShowStartMissionChanged: {
if (showStartMission) {
confirmAction(actionStartMission)
......
......@@ -23,6 +23,21 @@ Item {
width: 300
property var wimaController // must be provided by the user
property var planMasterController // must be provided by the user
property bool _controllerValid: planMasterController !== undefined
property real _controllerProgressPct: _controllerValid ? planMasterController.missionController.progressPct : 0
// Progress bar visibility
on_ControllerProgressPctChanged: {
if (_controllerProgressPct === 1) {
uploadCompleteText.visible = true
progressBar.visible = false
} else if (_controllerProgressPct > 0) {
progressBar.visible = true
uploadCompleteText.visible = false
}
}
// box containing all items
Rectangle {
......@@ -73,9 +88,12 @@ Item {
}
GridLayout {
columns: 2
rowSpacing: ScreenTools.defaultFontPixelHeight * 0.5
anchors.topMargin: ScreenTools.defaultFontPixelHeight * 0.25
visible: settingsHeader.checked
rowSpacing: ScreenTools.defaultFontPixelHeight * 0.5
columnSpacing: ScreenTools.defaultFontPixelHeight * 0.5
anchors.topMargin: ScreenTools.defaultFontPixelHeight * 0.5
anchors.left: parent.left
anchors.right: parent.right
visible: settingsHeader.checked
// Settings
QGCLabel { text: qsTr("Next Waypoint") }
......@@ -109,50 +127,90 @@ Item {
}
SectionHeader{
id: commandHeader
text: qsTr("Commands")
id: missionHeader
text: qsTr("Mission")
}
GridLayout {
columns: 2
rowSpacing: ScreenTools.defaultFontPixelHeight * 0.5
anchors.topMargin: ScreenTools.defaultFontPixelHeight * 0.25
visible: commandHeader.checked
columns: 2
rowSpacing: ScreenTools.defaultFontPixelHeight * 0.5
columnSpacing: ScreenTools.defaultFontPixelHeight * 0.5
anchors.topMargin: ScreenTools.defaultFontPixelHeight * 0.5
anchors.left: parent.left
anchors.right: parent.right
visible: missionHeader.checked
// Buttons
QGCButton {
id: buttonPreviousMissionPhase
text: qsTr("Reverse")
onClicked: wimaController.previousPhase();
text: qsTr("Reverse")
onClicked: wimaController.previousPhase();
Layout.fillWidth: true
}
QGCButton {
id: buttonNextMissionPhase
text: qsTr("Forward")
onClicked: wimaController.nextPhase();
text: qsTr("Forward")
onClicked: wimaController.nextPhase();
Layout.fillWidth: true
}
QGCButton {
id: buttonResetPhase
text: qsTr("Reset Phase")
onClicked: wimaController.resetPhase();
text: qsTr("Reset Phase")
onClicked: wimaController.resetPhase();
Layout.fillWidth: true
Layout.rowSpan: 2
}
}
SectionHeader{
id: vehicleHeader
text: qsTr("Vehicle")
}
GridLayout {
columns: 2
rowSpacing: ScreenTools.defaultFontPixelHeight * 0.5
columnSpacing: ScreenTools.defaultFontPixelHeight * 0.5
anchors.topMargin: ScreenTools.defaultFontPixelHeight * 0.5
anchors.left: parent.left
anchors.right: parent.right
visible: vehicleHeader.checked
QGCButton {
id: buttonUpload
text: qsTr("Upload")
onClicked: wimaController.uploadToVehicle();
text: qsTr("Upload")
onClicked: wimaController.uploadToVehicle();
Layout.fillWidth: true
}
QGCButton {
id: buttonRemoveFromVehicle
text: qsTr("Remove")
onClicked: wimaController.removeFromVehicle();
text: qsTr("Remove")
onClicked: wimaController.removeFromVehicle();
Layout.fillWidth: true
}
// progess bar
Rectangle {
id: progressBar
height: 4
width: _controllerProgressPct * parent.width
color: qgcPal.colorGreen
visible: false
}
QGCLabel {
id: uploadCompleteText
font.pointSize: ScreenTools.largeFontPointSize
Layout.columnSpan: 2
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: "Done"
visible: false
}
}
SectionHeader {
......@@ -166,8 +224,6 @@ Item {
visible: statsHeader.checked
QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
text: qsTr("Phase Length: ")
wrapMode: Text.WordWrap
font.pointSize: ScreenTools.smallFontPointSize
......
......@@ -27,6 +27,7 @@ import QGroundControl.FlightMap 1.0
Item {
id: _root
property var wimaController
property var missionController
property var confirmDialog
property var actionList
......@@ -50,7 +51,8 @@ Item {
readonly property string landAbortTitle: qsTr("Land Abort")
readonly property string setWaypointTitle: qsTr("Set Waypoint")
readonly property string gotoTitle: qsTr("Goto Location")
readonly property string vtolTransitionTitle: qsTr("VTOL Transition")
readonly property string vtolTransitionTitle: qsTr("VTOL Transition")
readonly property string overrideUploadTitle: qsTr("Override Lock")
readonly property string armMessage: qsTr("Arm the vehicle.")
readonly property string disarmMessage: qsTr("Disarm the vehicle")
......@@ -70,6 +72,7 @@ Item {
readonly property string mvPauseMessage: qsTr("Pause all vehicles at their current position.")
readonly property string vtolTransitionFwdMessage: qsTr("Transition VTOL to fixed wing flight.")
readonly property string vtolTransitionMRMessage: qsTr("Transition VTOL to multi-rotor flight.")
readonly property string overrideUploadMessage: qsTr("Vehicle is not inside service area. Override upload lock?")
readonly property int actionRTL: 1
readonly property int actionLand: 2
......@@ -92,6 +95,7 @@ Item {
readonly property int actionMVStartMission: 19
readonly property int actionVtolTransitionToFwdFlight: 20
readonly property int actionVtolTransitionToMRFlight: 21
readonly property int actionOverrideUpload: 22
property bool showEmergenyStop: _guidedActionsEnabled && !_hideEmergenyStop && _vehicleArmed && _vehicleFlying
property bool showArm: _guidedActionsEnabled && !_vehicleArmed
......@@ -331,6 +335,11 @@ Item {
confirmDialog.message = vtolTransitionMRMessage
confirmDialog.hideTrigger = true
break
case actionOverrideUpload:
confirmDialog.title = overrideUploadTitle
confirmDialog.message = overrideUploadMessage
confirmDialog.hideTrigger = true
break
default:
console.warn("Unknown actionCode", actionCode)
return
......@@ -406,6 +415,9 @@ Item {
case actionVtolTransitionToMRFlight:
_activeVehicle.vtolInFwdFlight = false
break
case actionOverrideUpload:
wimaController.forceUploadToVehicle()
break
default:
console.warn(qsTr("Internal error: unknown actionCode"), actionCode)
break
......
#include "WimaArea.h"
/*!
* \variable WimaArea::epsilonMeter
* \brief The accuracy used for distance calculations (unit: m).
......@@ -378,7 +377,7 @@ int WimaArea::previousVertexIndex(int index) const
* Returns \c true if the calling area is self intersecting, \c false else.
* \note If the calling area is self intersecting, it's not a \l {Simple Polygon}.
*/
bool WimaArea::isSimplePolygon()
bool WimaArea::isSimplePolygon() const
{
using namespace PolygonCalculus;
using namespace GeoUtilities;
......@@ -391,6 +390,19 @@ bool WimaArea::isSimplePolygon()
}
bool WimaArea::containsCoordinate(const QGeoCoordinate &coordinate) const
{
using namespace PlanimetryCalculus;
using namespace PolygonCalculus;
using namespace GeoUtilities;
if (this->count() > 2) {
QPolygonF polygon = toQPolygonF(toCartesian2D(this->coordinateList(), coordinate));
return PlanimetryCalculus::contains(polygon, QPointF(0,0));
} else
return false;
}
/*!
* \fn void WimaArea::saveToJson(QJsonObject &json)
* Saves the calling area to \c QJsonObject object and stores it inside \a json.
......
......@@ -13,6 +13,7 @@
#include "GeoUtilities.h"
#include "PolygonCalculus.h"
#include "PlanimetryCalculus.h"
class WimaArea : public QGCMapPolygon //abstract base class for all WimaAreas
{
......@@ -54,6 +55,8 @@ public:
bool join (WimaArea &area, QString &errorString);
int nextVertexIndex (int index) const;
int previousVertexIndex (int index) const;
bool isSimplePolygon () const;
bool containsCoordinate (const QGeoCoordinate &coordinate) const;
void saveToJson (QJsonObject& jsonObject);
......@@ -63,7 +66,7 @@ public:
static QGCMapPolygon toQGCPolygon (const WimaArea& area);
static bool join (const WimaArea &area1, const WimaArea &area2, WimaArea& joinedArea, QString &errorString);
static bool join (const WimaArea &area1, const WimaArea &area2, WimaArea& joinedArea);
bool isSimplePolygon ();
// Friends
friend void print(const WimaArea& area, QString& outputString);
......
......@@ -41,6 +41,20 @@ QList<QGeoCoordinate> WimaAreaData::coordinateList() const
return coordinateList;
}
bool WimaAreaData::containsCoordinate(const QGeoCoordinate &coordinate) const
{
using namespace PlanimetryCalculus;
using namespace PolygonCalculus;
using namespace GeoUtilities;
if (_path.size() > 2) {
QPolygonF polygon = toQPolygonF(toCartesian2D(this->coordinateList(), coordinate));
return PlanimetryCalculus::contains(polygon, QPointF(0,0));
} else
return false;
}
/*!
* \fn void WimaAreaData::setMaxAltitude(double maxAltitude)
*
......
......@@ -19,10 +19,11 @@ public:
//WimaAreaData(const WimaArea &other, QObject *parent = nullptr);
WimaAreaData& operator=(const WimaAreaData& otherData) = delete; // avoid slicing
double maxAltitude() const;
QVariantList path() const;
QGeoCoordinate center() const;
QList<QGeoCoordinate> coordinateList() const;
double maxAltitude() const;
QVariantList path() const;
QGeoCoordinate center() const;
QList<QGeoCoordinate> coordinateList() const;
bool containsCoordinate(const QGeoCoordinate &coordinate) const;
virtual QString type() const = 0;
......
......@@ -26,7 +26,10 @@ WimaController::WimaController(QObject *parent)
, _nextPhaseStartWaypointIndex (settingsGroup, _metaDataMap[startWaypointIndexName])
, _showAllMissionItems (settingsGroup, _metaDataMap[showAllMissionItemsName])
, _showCurrentMissionItems (settingsGroup, _metaDataMap[showCurrentMissionItemsName])
, _startWaypointIndex (0)
, _lastMissionPhaseReached (false)
, _uploadOverrideRequired (false)
{
_nextPhaseStartWaypointIndex.setRawValue(int(1));
_showAllMissionItems.setRawValue(true);
......@@ -108,6 +111,11 @@ Fact *WimaController::showCurrentMissionItems()
return &_showCurrentMissionItems;
}
bool WimaController::uploadOverrideRequired() const
{
return _uploadOverrideRequired;
}
Fact *WimaController::startWaypointIndex()
{
return &_nextPhaseStartWaypointIndex;
......@@ -145,6 +153,15 @@ void WimaController::setDataContainer(WimaDataContainer *container)
}
}
void WimaController::setUploadOverrideRequired(bool overrideRequired)
{
if (_uploadOverrideRequired != overrideRequired) {
_uploadOverrideRequired = overrideRequired;
emit uploadOverrideRequiredChanged();
}
}
void WimaController::nextPhase()
{
calcNextPhase();
......@@ -154,9 +171,9 @@ void WimaController::previousPhase()
{
if (_nextPhaseStartWaypointIndex.rawValue().toInt() > 0) {
_lastMissionPhaseReached = false;
_nextPhaseStartWaypointIndex.setRawValue( 1 + std::max(_startWaypointIndex
- _maxWaypointsPerPhase.rawValue().toInt()
+ _overlapWaypoints.rawValue().toInt(), 0));
_nextPhaseStartWaypointIndex.setRawValue(std::max(_startWaypointIndex
- _maxWaypointsPerPhase.rawValue().toInt()
+ _overlapWaypoints.rawValue().toInt(), 1));
}
}
......@@ -168,6 +185,18 @@ void WimaController::resetPhase()
bool WimaController::uploadToVehicle()
{
if (!_serviceArea.containsCoordinate(_masterController->managerVehicle()->coordinate())) {
qgcApp()->showMessage(tr("Vehicle is not inside service area."));
setUploadOverrideRequired(true);
return false;
}
return forceUploadToVehicle();
}
bool WimaController::forceUploadToVehicle()
{
setUploadOverrideRequired(false);
if (_currentMissionItems.count() < 1)
return false;
......@@ -187,23 +216,6 @@ bool WimaController::uploadToVehicle()
_missionController->insertSimpleMissionItem(*item, visuals->count());
}
// // set land command for last mission item
// SimpleMissionItem *landItem = visuals->value<SimpleMissionItem*>(visuals->count()-1);
// if (landItem == nullptr) {
// qWarning("WimaController::uploadToVehicle(): nullptr");
// _missionController->removeAll();
// return;
// }
// // check vehicle type, before setting land command
// Vehicle* controllerVehicle = _masterController->controllerVehicle();
// MAV_CMD landCmd = controllerVehicle->vtol() ? MAV_CMD_NAV_VTOL_LAND : MAV_CMD_NAV_LAND;
// if (controllerVehicle->firmwarePlugin()->supportedMissionCommands().contains(landCmd)) {
// landItem->setCommand(landCmd);
// } else {
// _missionController->removeAll();
// return;
// }
_masterController->sendToVehicle();
return true;
......@@ -584,7 +596,10 @@ void WimaController::updateNextWaypoint()
void WimaController::recalcCurrentPhase()
{
_lastMissionPhaseReached = false;
_nextPhaseStartWaypointIndex.setRawValue(_startWaypointIndex + 1);
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
_nextPhaseStartWaypointIndex.setRawValue(_startWaypointIndex + 1);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
calcNextPhase();
}
bool WimaController::setTakeoffLandPosition()
......
......@@ -51,6 +51,7 @@ public:
Q_PROPERTY(Fact* startWaypointIndex READ startWaypointIndex CONSTANT)
Q_PROPERTY(Fact* showAllMissionItems READ showAllMissionItems CONSTANT)
Q_PROPERTY(Fact* showCurrentMissionItems READ showCurrentMissionItems CONSTANT)
Q_PROPERTY(bool uploadOverrideRequired READ uploadOverrideRequired WRITE setUploadOverrideRequired NOTIFY uploadOverrideRequiredChanged)
......@@ -72,20 +73,23 @@ public:
Fact* overlapWaypoints (void);
Fact* maxWaypointsPerPhase (void);
Fact* startWaypointIndex (void);
Fact* showAllMissionItems (void);
Fact* showCurrentMissionItems (void);
Fact* showAllMissionItems (void);
Fact* showCurrentMissionItems(void);
bool uploadOverrideRequired (void) const;
// Property setters
void setMasterController (PlanMasterController* masterController);
void setMissionController (MissionController* missionController);
void setDataContainer (WimaDataContainer* container);
void setUploadOverrideRequired (bool overrideRequired);
// Member Methodes
Q_INVOKABLE void nextPhase();
Q_INVOKABLE void previousPhase();
Q_INVOKABLE void resetPhase();
Q_INVOKABLE bool uploadToVehicle();
Q_INVOKABLE bool forceUploadToVehicle();
Q_INVOKABLE void removeFromVehicle();
Q_INVOKABLE void saveToCurrent ();
......@@ -131,6 +135,7 @@ signals:
void currentMissionItemsChanged (void);
void waypointPathChanged (void);
void currentWaypointPathChanged (void);
void uploadOverrideRequiredChanged (void);
private slots:
bool fetchContainerData();
......@@ -175,4 +180,6 @@ private:
int _startWaypointIndex; // indes of the mission item stored in _missionItems defining the first element
// (which is not part of the arrival path) of _currentMissionItem
bool _lastMissionPhaseReached;
bool _uploadOverrideRequired; // Is set to true if uploadToVehicle() did not suceed because the vehicle is not inside the service area.
// The user can override the upload lock with a slider, this will reset this variable to false.
};
......@@ -19,12 +19,20 @@ WimaPlaner::WimaPlaner(QObject *parent)
, _corridor (this)
, _circularSurvey (nullptr)
, _surveyRefChanging (false)
, _measurementAreaChanging (false)
, _corridorChanging (false)
, _serviceAreaChanging (false)
, _syncronizedWithController (false)
, _readyForSync (false)
{
_lastMeasurementAreaPath = _measurementArea.path();
_lastServiceAreaPath = _serviceArea.path();
_lastCorridorPath = _corridor.path();
connect(this, &WimaPlaner::currentPolygonIndexChanged, this, &WimaPlaner::recalcPolygonInteractivity);
connect(&_updateTimer, &QTimer::timeout, this, &WimaPlaner::updateTimerSlot);
connect(this, &WimaPlaner::joinedAreaValidChanged, this, &WimaPlaner::updateMission);
_updateTimer.setInterval(500); // 250 ms means: max update time 2*250 ms
_updateTimer.start();
}
......@@ -199,11 +207,8 @@ bool WimaPlaner::updateMission()
setReadyForSync(false);
if ( !_joinedAreaValid) {
if (_joinedAreaErrorString.size() > 0)
qgcApp()->showMessage(_joinedAreaErrorString);
if ( !_joinedAreaValid)
return false;
}
// extract old survey data
......@@ -339,6 +344,7 @@ bool WimaPlaner::loadFromFile(const QString &filename)
return false;
}
_lastMeasurementAreaPath = _measurementArea.path(); // prevents error messages at this point
validAreaCounter++;
_visualItems.append(&_measurementArea);
emit visualItemsChanged();
......@@ -350,6 +356,7 @@ bool WimaPlaner::loadFromFile(const QString &filename)
return false;
}
_lastServiceAreaPath = _serviceArea.path(); // prevents error messages at this point
validAreaCounter++;
_visualItems.append(&_serviceArea);
emit visualItemsChanged();
......@@ -361,6 +368,7 @@ bool WimaPlaner::loadFromFile(const QString &filename)
return false;
}
_lastCorridorPath = _corridor.path(); // prevents error messages at this point
validAreaCounter++;
_visualItems.append(&_corridor);
emit visualItemsChanged();
......@@ -373,18 +381,12 @@ bool WimaPlaner::loadFromFile(const QString &filename)
errorString += QString(tr("Invalid or non existing entry for %s.\n").arg(WimaArea::areaTypeName));
return false;
}
}
}
recalcJoinedArea();
_currentFile.sprintf("%s/%s.%s", fileInfo.path().toLocal8Bit().data(), fileInfo.completeBaseName().toLocal8Bit().data(), wimaFileExtension);
emit currentFileChanged();
//recalcJoinedArea();
// MissionItems
// extrac MissionItems part
// bool ret = json.contains(missionItemsName);
// qWarning() << ret;
QJsonObject missionObject = json[missionItemsName].toObject();
......@@ -429,11 +431,6 @@ bool WimaPlaner::loadFromFile(const QString &filename)
_circularSurvey = missionItems->value<CircularSurveyComplexItem *>(i);
if (_circularSurvey != nullptr) {
if ( !recalcJoinedArea()) {
qgcApp()->showMessage(_joinedAreaErrorString);
return false;
}
_lastSurveyRefPoint = _circularSurvey->refPoint();
_surveyRefChanging = false;
_circularSurvey->setAutoGenerated(true); // prevents reinitialisation from gui
......@@ -445,16 +442,15 @@ bool WimaPlaner::loadFromFile(const QString &filename)
}
}
if (_circularSurvey == nullptr)
updateMission();
//if (_circularSurvey == nullptr)
updateMission();
// remove temporary file
if ( !temporaryFile.remove() ){
qWarning("WimaPlaner::loadFromFile(): not able to remove temporary file.");
}
_syncronizedWithController = false;
_readyForSync = false;
setSyncronizedWithController(false);
return true;
......@@ -465,7 +461,6 @@ bool WimaPlaner::loadFromFile(const QString &filename)
} else {
errorString += QString(tr("File extension not supported.\n"));
qgcApp()->showMessage(errorMessage.arg(errorString));
return false;
}
}
......@@ -600,31 +595,31 @@ bool WimaPlaner::calcArrivalAndReturnPath()
bool WimaPlaner::recalcJoinedArea()
{
_joinedAreaErrorString.clear();
setJoinedAreaValid(false);
// check if area paths form simple polygons
if ( !_serviceArea.isSimplePolygon() ) {
_joinedAreaErrorString.append(tr("Service area is self intersecting and thus not a simple polygon. Only simple polygons allowed.\n"));
qgcApp()->showMessage(tr("Service area is self intersecting and thus not a simple polygon. Only simple polygons allowed.\n"));
return false;
}
if ( !_corridor.isSimplePolygon() && _corridor.count() > 0) {
_joinedAreaErrorString.append(tr("Corridor is self intersecting and thus not a simple polygon. Only simple polygons allowed.\n"));
qgcApp()->showMessage(tr("Corridor is self intersecting and thus not a simple polygon. Only simple polygons allowed.\n"));
return false;
}
if ( !_measurementArea.isSimplePolygon() ) {
_joinedAreaErrorString.append(tr("Measurement area is self intersecting and thus not a simple polygon. Only simple polygons allowed.\n"));
qgcApp()->showMessage(tr("Measurement area is self intersecting and thus not a simple polygon. Only simple polygons allowed.\n"));
return false;
}
_joinedArea.setPath(_serviceArea.path());
_joinedArea.join(_corridor);
if ( !_joinedArea.join(_measurementArea) ) {
_joinedAreaErrorString.append(tr("Not able to join areas. Service area and measurement"
" must have a overlapping section, or be connected through a corridor."));
qgcApp()->showMessage(tr("Not able to join areas. Service area and measurement"
" must have a overlapping section, or be connected through a corridor."));
return false; // this happens if all areas are pairwise disjoint
}
// join service area, op area and corridor
setJoinedAreaValid(true);
return true;
......@@ -640,6 +635,8 @@ bool WimaPlaner::recalcJoinedArea()
void WimaPlaner::pushToContainer()
{
if (_container != nullptr) {
if (!_readyForSync)
return;
WimaPlanData planData = toPlanData();
_container->push(planData);
setSyncronizedWithController(true);
......
......@@ -151,7 +151,6 @@ private:
WimaDataContainer *_container; // container for data exchange with WimaController
QmlObjectListModel _visualItems; // contains all visible areas
WimaJoinedArea _joinedArea; // joined area fromed by _measurementArea, _serviceArea, _corridor
QString _joinedAreaErrorString; // contains errors which appeared in recalcJoinedArea
bool _joinedAreaValid;
WimaMeasurementArea _measurementArea; // measurement area
WimaServiceArea _serviceArea; // area for supplying
......
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