|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
|
|
|
*
|
|
|
|
* QGroundControl is licensed according to the terms in the file
|
|
|
|
* COPYING.md in the root of the source code directory.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
#include <QStringList>
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
#include "SimpleMissionItem.h"
|
|
|
|
#include "FirmwarePluginManager.h"
|
|
|
|
#include "QGCApplication.h"
|
|
|
|
#include "JsonHelper.h"
|
|
|
|
#include "MissionCommandTree.h"
|
|
|
|
#include "MissionCommandUIInfo.h"
|
|
|
|
#include "QGroundControlQmlGlobal.h"
|
|
|
|
#include "SettingsManager.h"
|
|
|
|
|
|
|
|
FactMetaData* SimpleMissionItem::_altitudeMetaData = NULL;
|
|
|
|
FactMetaData* SimpleMissionItem::_commandMetaData = NULL;
|
|
|
|
FactMetaData* SimpleMissionItem::_defaultParamMetaData = NULL;
|
|
|
|
FactMetaData* SimpleMissionItem::_frameMetaData = NULL;
|
|
|
|
FactMetaData* SimpleMissionItem::_latitudeMetaData = NULL;
|
|
|
|
FactMetaData* SimpleMissionItem::_longitudeMetaData = NULL;
|
|
|
|
|
|
|
|
const char* SimpleMissionItem::_jsonAltitudeModeKey = "AltitudeMode";
|
|
|
|
const char* SimpleMissionItem::_jsonAltitudeKey = "Altitude";
|
|
|
|
const char* SimpleMissionItem::_jsonAMSLAltAboveTerrainKey = "AMSLAltAboveTerrain";
|
|
|
|
|
|
|
|
struct EnumInfo_s {
|
|
|
|
const char * label;
|
|
|
|
MAV_FRAME frame;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct EnumInfo_s _rgMavFrameInfo[] = {
|
|
|
|
{ "MAV_FRAME_GLOBAL", MAV_FRAME_GLOBAL },
|
|
|
|
{ "MAV_FRAME_LOCAL_NED", MAV_FRAME_LOCAL_NED },
|
|
|
|
{ "MAV_FRAME_MISSION", MAV_FRAME_MISSION },
|
|
|
|
{ "MAV_FRAME_GLOBAL_RELATIVE_ALT", MAV_FRAME_GLOBAL_RELATIVE_ALT },
|
|
|
|
{ "MAV_FRAME_LOCAL_ENU", MAV_FRAME_LOCAL_ENU },
|
|
|
|
{ "MAV_FRAME_GLOBAL_INT", MAV_FRAME_GLOBAL_INT },
|
|
|
|
{ "MAV_FRAME_GLOBAL_RELATIVE_ALT_INT", MAV_FRAME_GLOBAL_RELATIVE_ALT_INT },
|
|
|
|
{ "MAV_FRAME_LOCAL_OFFSET_NED", MAV_FRAME_LOCAL_OFFSET_NED },
|
|
|
|
{ "MAV_FRAME_BODY_NED", MAV_FRAME_BODY_NED },
|
|
|
|
{ "MAV_FRAME_BODY_OFFSET_NED", MAV_FRAME_BODY_OFFSET_NED },
|
|
|
|
{ "MAV_FRAME_GLOBAL_TERRAIN_ALT", MAV_FRAME_GLOBAL_TERRAIN_ALT },
|
|
|
|
{ "MAV_FRAME_GLOBAL_TERRAIN_ALT_INT", MAV_FRAME_GLOBAL_TERRAIN_ALT_INT },
|
|
|
|
};
|
|
|
|
|
|
|
|
SimpleMissionItem::SimpleMissionItem(Vehicle* vehicle, bool flyView, QObject* parent)
|
|
|
|
: VisualMissionItem (vehicle, flyView, parent)
|
|
|
|
, _rawEdit (false)
|
|
|
|
, _dirty (false)
|
|
|
|
, _ignoreDirtyChangeSignals (false)
|
|
|
|
, _speedSection (NULL)
|
|
|
|
, _cameraSection (NULL)
|
|
|
|
, _commandTree (qgcApp()->toolbox()->missionCommandTree())
|
|
|
|
, _supportedCommandFact (0, "Command:", FactMetaData::valueTypeUint32)
|
|
|
|
, _altitudeMode (AltitudeRelative)
|
|
|
|
, _altitudeFact (0, "Altitude", FactMetaData::valueTypeDouble)
|
|
|
|
, _amslAltAboveTerrainFact (0, "Alt above terrain", FactMetaData::valueTypeDouble)
|
|
|
|
, _param1MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param2MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param3MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param4MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param5MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param6MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param7MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _syncingHeadingDegreesAndParam4 (false)
|
|
|
|
{
|
|
|
|
_editorQml = QStringLiteral("qrc:/qml/SimpleItemEditor.qml");
|
|
|
|
|
|
|
|
_setupMetaData();
|
|
|
|
_connectSignals();
|
|
|
|
_updateOptionalSections();
|
|
|
|
|
|
|
|
setDefaultsForCommand();
|
|
|
|
_rebuildFacts();
|
|
|
|
|
|
|
|
setDirty(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
SimpleMissionItem::SimpleMissionItem(Vehicle* vehicle, bool flyView, const MissionItem& missionItem, QObject* parent)
|
|
|
|
: VisualMissionItem (vehicle, flyView, parent)
|
|
|
|
, _missionItem (missionItem)
|
|
|
|
, _rawEdit (false)
|
|
|
|
, _dirty (false)
|
|
|
|
, _ignoreDirtyChangeSignals (false)
|
|
|
|
, _speedSection (NULL)
|
|
|
|
, _cameraSection (NULL)
|
|
|
|
, _commandTree (qgcApp()->toolbox()->missionCommandTree())
|
|
|
|
, _supportedCommandFact (0, "Command:", FactMetaData::valueTypeUint32)
|
|
|
|
, _altitudeFact (0, "Altitude", FactMetaData::valueTypeDouble)
|
|
|
|
, _amslAltAboveTerrainFact (0, "Alt above terrain", FactMetaData::valueTypeDouble)
|
|
|
|
, _param1MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param2MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param3MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param4MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param5MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param6MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param7MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _syncingHeadingDegreesAndParam4 (false)
|
|
|
|
{
|
|
|
|
_editorQml = QStringLiteral("qrc:/qml/SimpleItemEditor.qml");
|
|
|
|
|
|
|
|
struct MavFrame2AltMode_s {
|
|
|
|
MAV_FRAME mavFrame;
|
|
|
|
AltitudeMode altMode;
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct MavFrame2AltMode_s rgMavFrame2AltMode[] = {
|
|
|
|
{ MAV_FRAME_GLOBAL_TERRAIN_ALT, AltitudeTerrainFrame },
|
|
|
|
{ MAV_FRAME_GLOBAL, AltitudeAbsolute },
|
|
|
|
{ MAV_FRAME_GLOBAL_RELATIVE_ALT, AltitudeRelative },
|
|
|
|
};
|
|
|
|
_altitudeMode = AltitudeRelative;
|
|
|
|
for (size_t i=0; i<sizeof(rgMavFrame2AltMode)/sizeof(rgMavFrame2AltMode[0]); i++) {
|
|
|
|
const MavFrame2AltMode_s& pMavFrame2AltMode = rgMavFrame2AltMode[i];
|
|
|
|
if (pMavFrame2AltMode.mavFrame == missionItem.frame()) {
|
|
|
|
_altitudeMode = pMavFrame2AltMode.altMode;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_isCurrentItem = missionItem.isCurrentItem();
|
|
|
|
_altitudeFact.setRawValue(specifiesCoordinate() ? _missionItem._param7Fact.rawValue() : qQNaN());
|
|
|
|
_amslAltAboveTerrainFact.setRawValue(qQNaN());
|
|
|
|
|
|
|
|
// In flyView we skip some of the intialization to save memory
|
|
|
|
if (!_flyView) {
|
|
|
|
_setupMetaData();
|
|
|
|
}
|
|
|
|
_connectSignals();
|
|
|
|
_updateOptionalSections();
|
|
|
|
if (!_flyView) {
|
|
|
|
_rebuildFacts();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Signal coordinate changed to kick off terrain query
|
|
|
|
emit coordinateChanged(coordinate());
|
|
|
|
|
|
|
|
setDirty(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
SimpleMissionItem::SimpleMissionItem(const SimpleMissionItem& other, bool flyView, QObject* parent)
|
|
|
|
: VisualMissionItem (other, flyView, parent)
|
|
|
|
, _missionItem (other._vehicle)
|
|
|
|
, _rawEdit (false)
|
|
|
|
, _dirty (false)
|
|
|
|
, _ignoreDirtyChangeSignals (false)
|
|
|
|
, _speedSection (NULL)
|
|
|
|
, _cameraSection (NULL)
|
|
|
|
, _commandTree (qgcApp()->toolbox()->missionCommandTree())
|
|
|
|
, _supportedCommandFact (0, "Command:", FactMetaData::valueTypeUint32)
|
|
|
|
, _altitudeMode (other._altitudeMode)
|
|
|
|
, _altitudeFact (0, "Altitude", FactMetaData::valueTypeDouble)
|
|
|
|
, _amslAltAboveTerrainFact (qQNaN(), "Alt above terrain", FactMetaData::valueTypeDouble)
|
|
|
|
, _param1MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param2MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param3MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _param4MetaData (FactMetaData::valueTypeDouble)
|
|
|
|
, _syncingHeadingDegreesAndParam4 (false)
|
|
|
|
{
|
|
|
|
_editorQml = QStringLiteral("qrc:/qml/SimpleItemEditor.qml");
|
|
|
|
|
|
|
|
_altitudeFact.setRawValue(other._altitudeFact.rawValue());
|
|
|
|
_amslAltAboveTerrainFact.setRawValue(other._amslAltAboveTerrainFact.rawValue());
|
|
|
|
|
|
|
|
_setupMetaData();
|
|
|
|
_connectSignals();
|
|
|
|
_updateOptionalSections();
|
|
|
|
_rebuildFacts();
|
|
|
|
setDirty(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_connectSignals(void)
|
|
|
|
{
|
|
|
|
// Connect to change signals to track dirty state
|
|
|
|
connect(&_missionItem._param1Fact, &Fact::valueChanged, this, &SimpleMissionItem::_setDirty);
|
|
|
|
connect(&_missionItem._param2Fact, &Fact::valueChanged, this, &SimpleMissionItem::_setDirty);
|
|
|
|
connect(&_missionItem._param3Fact, &Fact::valueChanged, this, &SimpleMissionItem::_setDirty);
|
|
|
|
connect(&_missionItem._param4Fact, &Fact::valueChanged, this, &SimpleMissionItem::_setDirty);
|
|
|
|
connect(&_missionItem._param5Fact, &Fact::valueChanged, this, &SimpleMissionItem::_setDirty);
|
|
|
|
connect(&_missionItem._param6Fact, &Fact::valueChanged, this, &SimpleMissionItem::_setDirty);
|
|
|
|
connect(&_missionItem._param7Fact, &Fact::valueChanged, this, &SimpleMissionItem::_setDirty);
|
|
|
|
connect(&_missionItem._frameFact, &Fact::valueChanged, this, &SimpleMissionItem::_setDirty);
|
|
|
|
connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::_setDirty);
|
|
|
|
connect(&_missionItem, &MissionItem::sequenceNumberChanged, this, &SimpleMissionItem::_setDirty);
|
|
|
|
connect(this, &SimpleMissionItem::altitudeModeChanged,this, &SimpleMissionItem::_setDirty);
|
|
|
|
|
|
|
|
connect(&_altitudeFact, &Fact::valueChanged, this, &SimpleMissionItem::_altitudeChanged);
|
|
|
|
connect(this, &SimpleMissionItem::altitudeModeChanged,this, &SimpleMissionItem::_altitudeModeChanged);
|
|
|
|
connect(this, &SimpleMissionItem::terrainAltitudeChanged,this, &SimpleMissionItem::_terrainAltChanged);
|
|
|
|
|
|
|
|
connect(this, &SimpleMissionItem::sequenceNumberChanged, this, &SimpleMissionItem::lastSequenceNumberChanged);
|
|
|
|
connect(this, &SimpleMissionItem::cameraSectionChanged, this, &SimpleMissionItem::_setDirty);
|
|
|
|
connect(this, &SimpleMissionItem::cameraSectionChanged, this, &SimpleMissionItem::_updateLastSequenceNumber);
|
|
|
|
|
|
|
|
// These are coordinate parameters, they must emit coordinateChanged signal
|
|
|
|
connect(&_missionItem._param5Fact, &Fact::valueChanged, this, &SimpleMissionItem::_sendCoordinateChanged);
|
|
|
|
connect(&_missionItem._param6Fact, &Fact::valueChanged, this, &SimpleMissionItem::_sendCoordinateChanged);
|
|
|
|
connect(&_missionItem._param7Fact, &Fact::valueChanged, this, &SimpleMissionItem::_sendCoordinateChanged);
|
|
|
|
|
|
|
|
// The following changes may also change friendlyEditAllowed
|
|
|
|
connect(&_missionItem._autoContinueFact, &Fact::valueChanged, this, &SimpleMissionItem::_sendFriendlyEditAllowedChanged);
|
|
|
|
connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::_sendFriendlyEditAllowedChanged);
|
|
|
|
connect(&_missionItem._frameFact, &Fact::valueChanged, this, &SimpleMissionItem::_sendFriendlyEditAllowedChanged);
|
|
|
|
|
|
|
|
// A command change triggers a number of other changes as well.
|
|
|
|
connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::setDefaultsForCommand);
|
|
|
|
connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::commandNameChanged);
|
|
|
|
connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::commandDescriptionChanged);
|
|
|
|
connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::abbreviationChanged);
|
|
|
|
connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::specifiesCoordinateChanged);
|
|
|
|
connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::specifiesAltitudeOnlyChanged);
|
|
|
|
connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::isStandaloneCoordinateChanged);
|
|
|
|
|
|
|
|
// Whenever these properties change the ui model changes as well
|
|
|
|
connect(this, &SimpleMissionItem::commandChanged, this, &SimpleMissionItem::_rebuildFacts);
|
|
|
|
connect(this, &SimpleMissionItem::rawEditChanged, this, &SimpleMissionItem::_rebuildFacts);
|
|
|
|
|
|
|
|
// These fact signals must alway signal out through SimpleMissionItem signals
|
|
|
|
connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::_sendCommandChanged);
|
|
|
|
|
|
|
|
// Propogate signals from MissionItem up to SimpleMissionItem
|
|
|
|
connect(&_missionItem, &MissionItem::sequenceNumberChanged, this, &SimpleMissionItem::sequenceNumberChanged);
|
|
|
|
connect(&_missionItem, &MissionItem::specifiedFlightSpeedChanged, this, &SimpleMissionItem::specifiedFlightSpeedChanged);
|
|
|
|
|
|
|
|
// Firmware type change can affect supportsTerrainFrame
|
|
|
|
connect(_vehicle, &Vehicle::firmwareTypeChanged, this, &SimpleMissionItem::supportsTerrainFrameChanged);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_setupMetaData(void)
|
|
|
|
{
|
|
|
|
QStringList enumStrings;
|
|
|
|
QVariantList enumValues;
|
|
|
|
|
|
|
|
if (!_altitudeMetaData) {
|
|
|
|
_altitudeMetaData = new FactMetaData(FactMetaData::valueTypeDouble);
|
|
|
|
_altitudeMetaData->setRawUnits("m");
|
|
|
|
_altitudeMetaData->setRawIncrement(1);
|
|
|
|
_altitudeMetaData->setDecimalPlaces(2);
|
|
|
|
|
|
|
|
enumStrings.clear();
|
|
|
|
enumValues.clear();
|
|
|
|
MissionCommandTree* commandTree = qgcApp()->toolbox()->missionCommandTree();
|
|
|
|
foreach (const MAV_CMD command, commandTree->allCommandIds()) {
|
|
|
|
enumStrings.append(commandTree->rawName(command));
|
|
|
|
enumValues.append(QVariant((int)command));
|
|
|
|
}
|
|
|
|
_commandMetaData = new FactMetaData(FactMetaData::valueTypeUint32);
|
|
|
|
_commandMetaData->setEnumInfo(enumStrings, enumValues);
|
|
|
|
|
|
|
|
_defaultParamMetaData = new FactMetaData(FactMetaData::valueTypeDouble);
|
|
|
|
_defaultParamMetaData->setDecimalPlaces(7);
|
|
|
|
|
|
|
|
enumStrings.clear();
|
|
|
|
enumValues.clear();
|
|
|
|
for (size_t i=0; i<sizeof(_rgMavFrameInfo)/sizeof(_rgMavFrameInfo[0]); i++) {
|
|
|
|
const struct EnumInfo_s* mavFrameInfo = &_rgMavFrameInfo[i];
|
|
|
|
|
|
|
|
enumStrings.append(mavFrameInfo->label);
|
|
|
|
enumValues.append(QVariant(mavFrameInfo->frame));
|
|
|
|
}
|
|
|
|
_frameMetaData = new FactMetaData(FactMetaData::valueTypeUint32);
|
|
|
|
_frameMetaData->setEnumInfo(enumStrings, enumValues);
|
|
|
|
|
|
|
|
_latitudeMetaData = new FactMetaData(FactMetaData::valueTypeDouble);
|
|
|
|
_latitudeMetaData->setRawUnits("deg");
|
|
|
|
_latitudeMetaData->setDecimalPlaces(7);
|
|
|
|
|
|
|
|
_longitudeMetaData = new FactMetaData(FactMetaData::valueTypeDouble);
|
|
|
|
_longitudeMetaData->setRawUnits("deg");
|
|
|
|
_longitudeMetaData->setDecimalPlaces(7);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
_missionItem._commandFact.setMetaData(_commandMetaData);
|
|
|
|
_missionItem._frameFact.setMetaData(_frameMetaData);
|
|
|
|
_altitudeFact.setMetaData(_altitudeMetaData);
|
|
|
|
_amslAltAboveTerrainFact.setMetaData(_altitudeMetaData);
|
|
|
|
}
|
|
|
|
|
|
|
|
SimpleMissionItem::~SimpleMissionItem()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::save(QJsonArray& missionItems)
|
|
|
|
{
|
|
|
|
QList<MissionItem*> items;
|
|
|
|
|
|
|
|
appendMissionItems(items, this);
|
|
|
|
|
|
|
|
for (int i=0; i<items.count(); i++) {
|
|
|
|
MissionItem* item = items[i];
|
|
|
|
QJsonObject saveObject;
|
|
|
|
item->save(saveObject);
|
|
|
|
if (i == 0) {
|
|
|
|
// This is the main simple item, save the alt/terrain data
|
|
|
|
if (specifiesCoordinate()) {
|
|
|
|
saveObject[_jsonAltitudeModeKey] = _altitudeMode;
|
|
|
|
saveObject[_jsonAltitudeKey] = _altitudeFact.rawValue().toDouble();
|
|
|
|
saveObject[_jsonAMSLAltAboveTerrainKey] = _amslAltAboveTerrainFact.rawValue().toDouble();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
missionItems.append(saveObject);
|
|
|
|
item->deleteLater();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SimpleMissionItem::load(QTextStream &loadStream)
|
|
|
|
{
|
|
|
|
bool success;
|
|
|
|
if ((success = _missionItem.load(loadStream))) {
|
|
|
|
if (specifiesCoordinate()) {
|
|
|
|
_altitudeMode = _missionItem.relativeAltitude() ? AltitudeRelative : AltitudeAbsolute;
|
|
|
|
_altitudeFact.setRawValue(_missionItem._param7Fact.rawValue());
|
|
|
|
_amslAltAboveTerrainFact.setRawValue(qQNaN());
|
|
|
|
}
|
|
|
|
_updateOptionalSections();
|
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SimpleMissionItem::load(const QJsonObject& json, int sequenceNumber, QString& errorString)
|
|
|
|
{
|
|
|
|
if (!_missionItem.load(json, sequenceNumber, errorString)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (specifiesCoordinate()) {
|
|
|
|
if (json.contains(_jsonAltitudeModeKey) || json.contains(_jsonAltitudeKey) || json.contains(_jsonAMSLAltAboveTerrainKey)) {
|
|
|
|
QList<JsonHelper::KeyValidateInfo> keyInfoList = {
|
|
|
|
{ _jsonAltitudeModeKey, QJsonValue::Double, true },
|
|
|
|
{ _jsonAltitudeKey, QJsonValue::Double, true },
|
|
|
|
{ _jsonAMSLAltAboveTerrainKey, QJsonValue::Double, true },
|
|
|
|
};
|
|
|
|
if (!JsonHelper::validateKeys(json, keyInfoList, errorString)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
_altitudeMode = (AltitudeMode)(int)json[_jsonAltitudeModeKey].toDouble();
|
|
|
|
_altitudeFact.setRawValue(JsonHelper::possibleNaNJsonValue(json[_jsonAltitudeKey]));
|
|
|
|
_amslAltAboveTerrainFact.setRawValue(JsonHelper::possibleNaNJsonValue(json[_jsonAltitudeKey]));
|
|
|
|
} else {
|
|
|
|
_altitudeMode = _missionItem.relativeAltitude() ? AltitudeRelative : AltitudeAbsolute;
|
|
|
|
_altitudeFact.setRawValue(_missionItem._param7Fact.rawValue());
|
|
|
|
_amslAltAboveTerrainFact.setRawValue(qQNaN());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_updateOptionalSections();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SimpleMissionItem::isStandaloneCoordinate(void) const
|
|
|
|
{
|
|
|
|
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
|
|
|
|
if (uiInfo) {
|
|
|
|
return uiInfo->isStandaloneCoordinate();
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SimpleMissionItem::specifiesCoordinate(void) const
|
|
|
|
{
|
|
|
|
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
|
|
|
|
if (uiInfo) {
|
|
|
|
return uiInfo->specifiesCoordinate();
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SimpleMissionItem::specifiesAltitudeOnly(void) const
|
|
|
|
{
|
|
|
|
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
|
|
|
|
if (uiInfo) {
|
|
|
|
return uiInfo->specifiesAltitudeOnly();
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SimpleMissionItem::commandDescription(void) const
|
|
|
|
{
|
|
|
|
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
|
|
|
|
if (uiInfo) {
|
|
|
|
return uiInfo->description();
|
|
|
|
} else {
|
|
|
|
qWarning() << "Should not ask for command description on unknown command";
|
|
|
|
return commandName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SimpleMissionItem::commandName(void) const
|
|
|
|
{
|
|
|
|
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
|
|
|
|
if (uiInfo) {
|
|
|
|
return uiInfo->friendlyName();
|
|
|
|
} else {
|
|
|
|
qWarning() << "Request for command name on unknown command";
|
|
|
|
return tr("Unknown: %1").arg(command());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SimpleMissionItem::abbreviation() const
|
|
|
|
{
|
|
|
|
if (homePosition())
|
|
|
|
return tr("H");
|
|
|
|
|
|
|
|
switch(command()) {
|
|
|
|
case MAV_CMD_NAV_TAKEOFF:
|
|
|
|
return tr("Takeoff");
|
|
|
|
case MAV_CMD_NAV_LAND:
|
|
|
|
return tr("Land");
|
|
|
|
case MAV_CMD_NAV_VTOL_TAKEOFF:
|
|
|
|
return tr("VTOL Takeoff");
|
|
|
|
case MAV_CMD_NAV_VTOL_LAND:
|
|
|
|
return tr("VTOL Land");
|
|
|
|
case MAV_CMD_DO_SET_ROI:
|
|
|
|
return tr("ROI");
|
|
|
|
default:
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_rebuildTextFieldFacts(void)
|
|
|
|
{
|
|
|
|
_textFieldFacts.clear();
|
|
|
|
|
|
|
|
if (rawEdit()) {
|
|
|
|
_missionItem._param1Fact._setName("Param1");
|
|
|
|
_missionItem._param1Fact.setMetaData(_defaultParamMetaData);
|
|
|
|
_textFieldFacts.append(&_missionItem._param1Fact);
|
|
|
|
_missionItem._param2Fact._setName("Param2");
|
|
|
|
_missionItem._param2Fact.setMetaData(_defaultParamMetaData);
|
|
|
|
_textFieldFacts.append(&_missionItem._param2Fact);
|
|
|
|
_missionItem._param3Fact._setName("Param3");
|
|
|
|
_missionItem._param3Fact.setMetaData(_defaultParamMetaData);
|
|
|
|
_textFieldFacts.append(&_missionItem._param3Fact);
|
|
|
|
_missionItem._param4Fact._setName("Param4");
|
|
|
|
_missionItem._param4Fact.setMetaData(_defaultParamMetaData);
|
|
|
|
_textFieldFacts.append(&_missionItem._param4Fact);
|
|
|
|
_missionItem._param5Fact._setName("Lat/X");
|
|
|
|
_missionItem._param5Fact.setMetaData(_defaultParamMetaData);
|
|
|
|
_textFieldFacts.append(&_missionItem._param5Fact);
|
|
|
|
_missionItem._param6Fact._setName("Lon/Y");
|
|
|
|
_missionItem._param6Fact.setMetaData(_defaultParamMetaData);
|
|
|
|
_textFieldFacts.append(&_missionItem._param6Fact);
|
|
|
|
_missionItem._param7Fact._setName("Alt/Z");
|
|
|
|
_missionItem._param7Fact.setMetaData(_defaultParamMetaData);
|
|
|
|
_textFieldFacts.append(&_missionItem._param7Fact);
|
|
|
|
} else {
|
|
|
|
_ignoreDirtyChangeSignals = true;
|
|
|
|
|
|
|
|
MAV_CMD command;
|
|
|
|
if (_homePositionSpecialCase) {
|
|
|
|
command = MAV_CMD_NAV_LAST;
|
|
|
|
} else {
|
|
|
|
command = _missionItem.command();
|
|
|
|
}
|
|
|
|
|
|
|
|
Fact* rgParamFacts[7] = { &_missionItem._param1Fact, &_missionItem._param2Fact, &_missionItem._param3Fact, &_missionItem._param4Fact, &_missionItem._param5Fact, &_missionItem._param6Fact, &_missionItem._param7Fact };
|
|
|
|
FactMetaData* rgParamMetaData[7] = { &_param1MetaData, &_param2MetaData, &_param3MetaData, &_param4MetaData, &_param5MetaData, &_param6MetaData, &_param7MetaData };
|
|
|
|
|
|
|
|
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, command);
|
|
|
|
|
|
|
|
for (int i=1; i<=7; i++) {
|
|
|
|
bool showUI;
|
|
|
|
const MissionCmdParamInfo* paramInfo = uiInfo->getParamInfo(i, showUI);
|
|
|
|
|
|
|
|
if (showUI && paramInfo && paramInfo->enumStrings().count() == 0 && !paramInfo->nanUnchanged()) {
|
|
|
|
Fact* paramFact = rgParamFacts[i-1];
|
|
|
|
FactMetaData* paramMetaData = rgParamMetaData[i-1];
|
|
|
|
|
|
|
|
paramFact->_setName(paramInfo->label());
|
|
|
|
paramMetaData->setDecimalPlaces(paramInfo->decimalPlaces());
|
|
|
|
paramMetaData->setRawUnits(paramInfo->units());
|
|
|
|
paramFact->setMetaData(paramMetaData);
|
|
|
|
_textFieldFacts.append(paramFact);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_ignoreDirtyChangeSignals = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_rebuildNaNFacts(void)
|
|
|
|
{
|
|
|
|
_nanFacts.clear();
|
|
|
|
|
|
|
|
if (!rawEdit()) {
|
|
|
|
_ignoreDirtyChangeSignals = true;
|
|
|
|
|
|
|
|
MAV_CMD command;
|
|
|
|
if (_homePositionSpecialCase) {
|
|
|
|
command = MAV_CMD_NAV_LAST;
|
|
|
|
} else {
|
|
|
|
command = _missionItem.command();
|
|
|
|
}
|
|
|
|
|
|
|
|
Fact* rgParamFacts[7] = { &_missionItem._param1Fact, &_missionItem._param2Fact, &_missionItem._param3Fact, &_missionItem._param4Fact, &_missionItem._param5Fact, &_missionItem._param6Fact, &_missionItem._param7Fact };
|
|
|
|
FactMetaData* rgParamMetaData[7] = { &_param1MetaData, &_param2MetaData, &_param3MetaData, &_param4MetaData, &_param5MetaData, &_param6MetaData, &_param7MetaData };
|
|
|
|
|
|
|
|
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, command);
|
|
|
|
|
|
|
|
for (int i=1; i<=7; i++) {
|
|
|
|
bool showUI;
|
|
|
|
const MissionCmdParamInfo* paramInfo = uiInfo->getParamInfo(i, showUI);
|
|
|
|
|
|
|
|
if (showUI && paramInfo && paramInfo->nanUnchanged()) {
|
|
|
|
// Show hide Heading field on waypoint based on vehicle yaw to next waypoint setting. This needs to come from the actual vehicle if it exists
|
|
|
|
// and not _vehicle which is always offline.
|
|
|
|
Vehicle* firmwareVehicle = qgcApp()->toolbox()->multiVehicleManager()->activeVehicle();
|
|
|
|
if (!firmwareVehicle) {
|
|
|
|
firmwareVehicle = _vehicle;
|
|
|
|
}
|
|
|
|
bool hideWaypointHeading = (command == MAV_CMD_NAV_WAYPOINT || command == MAV_CMD_NAV_TAKEOFF) && (i == 4) && firmwareVehicle->firmwarePlugin()->vehicleYawsToNextWaypointInMission(firmwareVehicle);
|
|
|
|
if (hideWaypointHeading) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Fact* paramFact = rgParamFacts[i-1];
|
|
|
|
FactMetaData* paramMetaData = rgParamMetaData[i-1];
|
|
|
|
|
|
|
|
paramFact->_setName(paramInfo->label());
|
|
|
|
paramMetaData->setDecimalPlaces(paramInfo->decimalPlaces());
|
|
|
|
paramMetaData->setRawUnits(paramInfo->units());
|
|
|
|
paramFact->setMetaData(paramMetaData);
|
|
|
|
_nanFacts.append(paramFact);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_ignoreDirtyChangeSignals = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SimpleMissionItem::specifiesAltitude(void) const
|
|
|
|
{
|
|
|
|
return specifiesCoordinate() || specifiesAltitudeOnly();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_rebuildComboBoxFacts(void)
|
|
|
|
{
|
|
|
|
_comboboxFacts.clear();
|
|
|
|
|
|
|
|
if (rawEdit()) {
|
|
|
|
_comboboxFacts.append(&_missionItem._commandFact);
|
|
|
|
_comboboxFacts.append(&_missionItem._frameFact);
|
|
|
|
} else {
|
|
|
|
Fact* rgParamFacts[7] = { &_missionItem._param1Fact, &_missionItem._param2Fact, &_missionItem._param3Fact, &_missionItem._param4Fact, &_missionItem._param5Fact, &_missionItem._param6Fact, &_missionItem._param7Fact };
|
|
|
|
FactMetaData* rgParamMetaData[7] = { &_param1MetaData, &_param2MetaData, &_param3MetaData, &_param4MetaData, &_param5MetaData, &_param6MetaData, &_param7MetaData };
|
|
|
|
|
|
|
|
MAV_CMD command;
|
|
|
|
if (_homePositionSpecialCase) {
|
|
|
|
command = MAV_CMD_NAV_LAST;
|
|
|
|
} else {
|
|
|
|
command = (MAV_CMD)this->command();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i=1; i<=7; i++) {
|
|
|
|
bool showUI;
|
|
|
|
const MissionCmdParamInfo* paramInfo = _commandTree->getUIInfo(_vehicle, command)->getParamInfo(i, showUI);
|
|
|
|
|
|
|
|
if (showUI && paramInfo && paramInfo->enumStrings().count() != 0) {
|
|
|
|
Fact* paramFact = rgParamFacts[i-1];
|
|
|
|
FactMetaData* paramMetaData = rgParamMetaData[i-1];
|
|
|
|
|
|
|
|
paramFact->_setName(paramInfo->label());
|
|
|
|
paramMetaData->setDecimalPlaces(paramInfo->decimalPlaces());
|
|
|
|
paramMetaData->setEnumInfo(paramInfo->enumStrings(), paramInfo->enumValues());
|
|
|
|
paramMetaData->setRawUnits(paramInfo->units());
|
|
|
|
paramFact->setMetaData(paramMetaData);
|
|
|
|
_comboboxFacts.append(paramFact);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_rebuildFacts(void)
|
|
|
|
{
|
|
|
|
_rebuildTextFieldFacts();
|
|
|
|
_rebuildNaNFacts();
|
|
|
|
_rebuildComboBoxFacts();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SimpleMissionItem::friendlyEditAllowed(void) const
|
|
|
|
{
|
|
|
|
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
|
|
|
|
if (uiInfo && uiInfo->friendlyEdit()) {
|
|
|
|
if (!_missionItem.autoContinue()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (specifiesCoordinate() || specifiesAltitudeOnly()) {
|
|
|
|
MAV_FRAME frame = _missionItem.frame();
|
|
|
|
switch (frame) {
|
|
|
|
case MAV_FRAME_GLOBAL:
|
|
|
|
case MAV_FRAME_GLOBAL_RELATIVE_ALT:
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAV_FRAME_GLOBAL_TERRAIN_ALT:
|
|
|
|
return supportsTerrainFrame();
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SimpleMissionItem::rawEdit(void) const
|
|
|
|
{
|
|
|
|
return _rawEdit || !friendlyEditAllowed();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::setRawEdit(bool rawEdit)
|
|
|
|
{
|
|
|
|
if (this->rawEdit() != rawEdit) {
|
|
|
|
_rawEdit = rawEdit;
|
|
|
|
emit rawEditChanged(this->rawEdit());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::setDirty(bool dirty)
|
|
|
|
{
|
|
|
|
if (!_homePositionSpecialCase || (_dirty != dirty)) {
|
|
|
|
_dirty = dirty;
|
|
|
|
if (!dirty) {
|
|
|
|
_cameraSection->setDirty(false);
|
|
|
|
_speedSection->setDirty(false);
|
|
|
|
}
|
|
|
|
emit dirtyChanged(dirty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_setDirty(void)
|
|
|
|
{
|
|
|
|
if (!_ignoreDirtyChangeSignals) {
|
|
|
|
setDirty(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_sendCoordinateChanged(void)
|
|
|
|
{
|
|
|
|
emit coordinateChanged(coordinate());
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_altitudeModeChanged(void)
|
|
|
|
{
|
|
|
|
switch (_altitudeMode) {
|
|
|
|
case AltitudeTerrainFrame:
|
|
|
|
_missionItem.setFrame(MAV_FRAME_GLOBAL_TERRAIN_ALT);
|
|
|
|
break;
|
|
|
|
case AltitudeAboveTerrain:
|
|
|
|
// Terrain altitudes are Absolute
|
|
|
|
_missionItem.setFrame(MAV_FRAME_GLOBAL);
|
|
|
|
// Clear any old calculated values
|
|
|
|
_missionItem._param7Fact.setRawValue(qQNaN());
|
|
|
|
_amslAltAboveTerrainFact.setRawValue(qQNaN());
|
|
|
|
break;
|
|
|
|
case AltitudeAbsolute:
|
|
|
|
_missionItem.setFrame(MAV_FRAME_GLOBAL);
|
|
|
|
break;
|
|
|
|
case AltitudeRelative:
|
|
|
|
_missionItem.setFrame(MAV_FRAME_GLOBAL_RELATIVE_ALT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We always call _altitudeChanged to make sure that param7 is always setup correctly on mode change
|
|
|
|
_altitudeChanged();
|
|
|
|
|
|
|
|
emit coordinateHasRelativeAltitudeChanged(_altitudeMode == AltitudeRelative);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_altitudeChanged(void)
|
|
|
|
{
|
|
|
|
if (!specifiesAltitude()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_altitudeMode == AltitudeAboveTerrain) {
|
|
|
|
_amslAltAboveTerrainFact.setRawValue(qQNaN());
|
|
|
|
_terrainAltChanged();
|
|
|
|
} else {
|
|
|
|
_missionItem._param7Fact.setRawValue(_altitudeFact.rawValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_terrainAltChanged(void)
|
|
|
|
{
|
|
|
|
if (!specifiesAltitude() || _altitudeMode != AltitudeAboveTerrain) {
|
|
|
|
// We don't need terrain data
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qIsNaN(terrainAltitude())) {
|
|
|
|
// Set NaNs to signal we are waiting on terrain data
|
|
|
|
_missionItem._param7Fact.setRawValue(qQNaN());
|
|
|
|
_amslAltAboveTerrainFact.setRawValue(qQNaN());
|
|
|
|
} else {
|
|
|
|
double newAboveTerrain = terrainAltitude() + _altitudeFact.rawValue().toDouble();
|
|
|
|
double oldAboveTerrain = _amslAltAboveTerrainFact.rawValue().toDouble();
|
|
|
|
if (qIsNaN(oldAboveTerrain) || !qFuzzyCompare(newAboveTerrain, oldAboveTerrain)) {
|
|
|
|
_missionItem._param7Fact.setRawValue(newAboveTerrain);
|
|
|
|
_amslAltAboveTerrainFact.setRawValue(newAboveTerrain);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SimpleMissionItem::readyForSave(void) const
|
|
|
|
{
|
|
|
|
return !specifiesAltitude() || !qIsNaN(_missionItem._param7Fact.rawValue().toDouble());
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::setDefaultsForCommand(void)
|
|
|
|
{
|
|
|
|
// We set these global defaults first, then if there are param defaults they will get reset
|
|
|
|
_altitudeMode = AltitudeRelative;
|
|
|
|
double defaultAlt = qgcApp()->toolbox()->settingsManager()->appSettings()->defaultMissionItemAltitude()->rawValue().toDouble();
|
|
|
|
_altitudeFact.setRawValue(defaultAlt);
|
|
|
|
_missionItem._param7Fact.setRawValue(defaultAlt);
|
|
|
|
_amslAltAboveTerrainFact.setRawValue(qQNaN());
|
|
|
|
|
|
|
|
MAV_CMD command = (MAV_CMD)this->command();
|
|
|
|
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, command);
|
|
|
|
if (uiInfo) {
|
|
|
|
for (int i=1; i<=7; i++) {
|
|
|
|
bool showUI;
|
|
|
|
const MissionCmdParamInfo* paramInfo = uiInfo->getParamInfo(i, showUI);
|
|
|
|
if (paramInfo) {
|
|
|
|
Fact* rgParamFacts[7] = { &_missionItem._param1Fact, &_missionItem._param2Fact, &_missionItem._param3Fact, &_missionItem._param4Fact, &_missionItem._param5Fact, &_missionItem._param6Fact, &_missionItem._param7Fact };
|
|
|
|
rgParamFacts[paramInfo->param()-1]->setRawValue(paramInfo->defaultValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (command) {
|
|
|
|
case MAV_CMD_NAV_WAYPOINT:
|
|
|
|
// We default all acceptance radius to 0. This allows flight controller to be in control of
|
|
|
|
// accept radius.
|
|
|
|
_missionItem.setParam2(0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAV_CMD_NAV_LAND:
|
|
|
|
case MAV_CMD_NAV_VTOL_LAND:
|
|
|
|
_missionItem.setParam7(0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
_missionItem.setAutoContinue(true);
|
|
|
|
_missionItem.setFrame((specifiesCoordinate() || specifiesAltitudeOnly()) ? MAV_FRAME_GLOBAL_RELATIVE_ALT : MAV_FRAME_MISSION);
|
|
|
|
setRawEdit(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_sendCommandChanged(void)
|
|
|
|
{
|
|
|
|
emit commandChanged(command());
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_sendFriendlyEditAllowedChanged(void)
|
|
|
|
{
|
|
|
|
emit friendlyEditAllowedChanged(friendlyEditAllowed());
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SimpleMissionItem::category(void) const
|
|
|
|
{
|
|
|
|
return _commandTree->getUIInfo(_vehicle, (MAV_CMD)command())->category();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::setCommand(int command)
|
|
|
|
{
|
|
|
|
if ((MAV_CMD)command != _missionItem.command()) {
|
|
|
|
_missionItem.setCommand((MAV_CMD)command);
|
|
|
|
_updateOptionalSections();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::setCoordinate(const QGeoCoordinate& coordinate)
|
|
|
|
{
|
|
|
|
if (_missionItem.coordinate() != coordinate) {
|
|
|
|
_missionItem.setCoordinate(coordinate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::setSequenceNumber(int sequenceNumber)
|
|
|
|
{
|
|
|
|
if (_missionItem.sequenceNumber() != sequenceNumber) {
|
|
|
|
_missionItem.setSequenceNumber(sequenceNumber);
|
|
|
|
emit sequenceNumberChanged(sequenceNumber);
|
|
|
|
// This is too likely to ignore
|
|
|
|
emit abbreviationChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double SimpleMissionItem::specifiedFlightSpeed(void)
|
|
|
|
{
|
|
|
|
if (_speedSection->specifyFlightSpeed()) {
|
|
|
|
return _speedSection->flightSpeed()->rawValue().toDouble();
|
|
|
|
} else {
|
|
|
|
return missionItem().specifiedFlightSpeed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double SimpleMissionItem::specifiedGimbalYaw(void)
|
|
|
|
{
|
|
|
|
return _cameraSection->available() ? _cameraSection->specifiedGimbalYaw() : missionItem().specifiedGimbalYaw();
|
|
|
|
}
|
|
|
|
|
|
|
|
double SimpleMissionItem::specifiedGimbalPitch(void)
|
|
|
|
{
|
|
|
|
return _cameraSection->available() ? _cameraSection->specifiedGimbalPitch() : missionItem().specifiedGimbalPitch();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SimpleMissionItem::scanForSections(QmlObjectListModel* visualItems, int scanIndex, Vehicle* vehicle)
|
|
|
|
{
|
|
|
|
bool sectionFound = false;
|
|
|
|
|
|
|
|
Q_UNUSED(vehicle);
|
|
|
|
|
|
|
|
if (_cameraSection->available()) {
|
|
|
|
sectionFound |= _cameraSection->scanForSection(visualItems, scanIndex);
|
|
|
|
}
|
|
|
|
if (_speedSection->available()) {
|
|
|
|
sectionFound |= _speedSection->scanForSection(visualItems, scanIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sectionFound;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_updateOptionalSections(void)
|
|
|
|
{
|
|
|
|
// Remove previous sections
|
|
|
|
if (_cameraSection) {
|
|
|
|
_cameraSection->deleteLater();
|
|
|
|
_cameraSection = NULL;
|
|
|
|
}
|
|
|
|
if (_speedSection) {
|
|
|
|
_speedSection->deleteLater();
|
|
|
|
_speedSection = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add new sections
|
|
|
|
|
|
|
|
_cameraSection = new CameraSection(_vehicle, this);
|
|
|
|
_speedSection = new SpeedSection(_vehicle, this);
|
|
|
|
if ((MAV_CMD)command() == MAV_CMD_NAV_WAYPOINT) {
|
|
|
|
_cameraSection->setAvailable(true);
|
|
|
|
_speedSection->setAvailable(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
connect(_cameraSection, &CameraSection::dirtyChanged, this, &SimpleMissionItem::_sectionDirtyChanged);
|
|
|
|
connect(_cameraSection, &CameraSection::itemCountChanged, this, &SimpleMissionItem::_updateLastSequenceNumber);
|
|
|
|
connect(_cameraSection, &CameraSection::availableChanged, this, &SimpleMissionItem::specifiedGimbalYawChanged);
|
|
|
|
connect(_cameraSection, &CameraSection::availableChanged, this, &SimpleMissionItem::specifiedGimbalPitchChanged);
|
|
|
|
connect(_cameraSection, &CameraSection::specifiedGimbalPitchChanged, this, &SimpleMissionItem::specifiedGimbalPitchChanged);
|
|
|
|
connect(_cameraSection, &CameraSection::specifiedGimbalYawChanged, this, &SimpleMissionItem::specifiedGimbalYawChanged);
|
|
|
|
|
|
|
|
connect(_speedSection, &SpeedSection::dirtyChanged, this, &SimpleMissionItem::_sectionDirtyChanged);
|
|
|
|
connect(_speedSection, &SpeedSection::itemCountChanged, this, &SimpleMissionItem::_updateLastSequenceNumber);
|
|
|
|
connect(_speedSection, &SpeedSection::specifiedFlightSpeedChanged, this, &SimpleMissionItem::specifiedFlightSpeedChanged);
|
|
|
|
|
|
|
|
emit cameraSectionChanged(_cameraSection);
|
|
|
|
emit speedSectionChanged(_speedSection);
|
|
|
|
emit lastSequenceNumberChanged(lastSequenceNumber());
|
|
|
|
}
|
|
|
|
|
|
|
|
int SimpleMissionItem::lastSequenceNumber(void) const
|
|
|
|
{
|
|
|
|
return sequenceNumber() + (_cameraSection ? _cameraSection->itemCount() : 0) + (_speedSection ? _speedSection->itemCount() : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_updateLastSequenceNumber(void)
|
|
|
|
{
|
|
|
|
emit lastSequenceNumberChanged(lastSequenceNumber());
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::_sectionDirtyChanged(bool dirty)
|
|
|
|
{
|
|
|
|
if (dirty) {
|
|
|
|
setDirty(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::appendMissionItems(QList<MissionItem*>& items, QObject* missionItemParent)
|
|
|
|
{
|
|
|
|
int seqNum = sequenceNumber();
|
|
|
|
|
|
|
|
items.append(new MissionItem(missionItem(), missionItemParent));
|
|
|
|
seqNum++;
|
|
|
|
|
|
|
|
_cameraSection->appendSectionItems(items, missionItemParent, seqNum);
|
|
|
|
_speedSection->appendSectionItems(items, missionItemParent, seqNum);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::applyNewAltitude(double newAltitude)
|
|
|
|
{
|
|
|
|
MAV_CMD command = (MAV_CMD)this->command();
|
|
|
|
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, command);
|
|
|
|
|
|
|
|
if (uiInfo->specifiesCoordinate() || uiInfo->specifiesAltitudeOnly()) {
|
|
|
|
switch ((MAV_CMD)this->command()) {
|
|
|
|
case MAV_CMD_NAV_LAND:
|
|
|
|
case MAV_CMD_NAV_VTOL_LAND:
|
|
|
|
// Leave alone
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
_altitudeFact.setRawValue(newAltitude);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::setMissionFlightStatus(MissionController::MissionFlightStatus_t& missionFlightStatus)
|
|
|
|
{
|
|
|
|
// If user has not already set speed/gimbal, set defaults from previous items.
|
|
|
|
VisualMissionItem::setMissionFlightStatus(missionFlightStatus);
|
|
|
|
if (_speedSection->available() && !_speedSection->specifyFlightSpeed() && !qFuzzyCompare(_speedSection->flightSpeed()->rawValue().toDouble(), missionFlightStatus.vehicleSpeed)) {
|
|
|
|
_speedSection->flightSpeed()->setRawValue(missionFlightStatus.vehicleSpeed);
|
|
|
|
}
|
|
|
|
if (_cameraSection->available() && !_cameraSection->specifyGimbal()) {
|
|
|
|
if (!qIsNaN(missionFlightStatus.gimbalYaw) && !qFuzzyCompare(_cameraSection->gimbalYaw()->rawValue().toDouble(), missionFlightStatus.gimbalYaw)) {
|
|
|
|
_cameraSection->gimbalYaw()->setRawValue(missionFlightStatus.gimbalYaw);
|
|
|
|
}
|
|
|
|
if (!qIsNaN(missionFlightStatus.gimbalPitch) && !qFuzzyCompare(_cameraSection->gimbalPitch()->rawValue().toDouble(), missionFlightStatus.gimbalPitch)) {
|
|
|
|
_cameraSection->gimbalPitch()->setRawValue(missionFlightStatus.gimbalPitch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleMissionItem::setAltitudeMode(AltitudeMode altitudeMode)
|
|
|
|
{
|
|
|
|
if (altitudeMode != _altitudeMode) {
|
|
|
|
_altitudeMode = altitudeMode;
|
|
|
|
emit altitudeModeChanged();
|
|
|
|
}
|
|
|
|
}
|