Commit fa7c9122 authored by Don Gagne's avatar Don Gagne

Merge branch 'Stable_V3.4' of https://github.com/mavlink/qgroundcontrol into UpstreamStableMerge

parents 16c7249a b4fed39b
...@@ -5,10 +5,10 @@ if [ ! -d /Volumes/RAMDisk ] ; then ...@@ -5,10 +5,10 @@ if [ ! -d /Volumes/RAMDisk ] ; then
exit 1 exit 1
fi fi
#-- Set to my local installation #-- Set to my local installation
QMAKE=/Users/gus/Applications/Qt/5.7/ios/bin/qmake QMAKE=/Users/gus/Applications/Qt/5.11.0/ios/bin/qmake
#-- Using Travis variables as this will eventually live there #-- Using Travis variables as this will eventually live there
SHADOW_BUILD_DIR=/Volumes/RAMDisk/build-qgroundcontrol-iOS-Release SHADOW_BUILD_DIR=/Volumes/RAMDisk/build-qgroundcontrol-iOS-Release
TRAVIS_BUILD_DIR=/Users/gus/github/work/qgroundcontrol TRAVIS_BUILD_DIR=/Users/gus/github/work/UpstreamQGC
#-- Build it #-- Build it
mkdir -p ${SHADOW_BUILD_DIR} && mkdir -p ${SHADOW_BUILD_DIR} &&
cd ${SHADOW_BUILD_DIR} && cd ${SHADOW_BUILD_DIR} &&
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
<file alias="GeneralSettings.qml">src/ui/preferences/GeneralSettings.qml</file> <file alias="GeneralSettings.qml">src/ui/preferences/GeneralSettings.qml</file>
<file alias="GeoTagPage.qml">src/AnalyzeView/GeoTagPage.qml</file> <file alias="GeoTagPage.qml">src/AnalyzeView/GeoTagPage.qml</file>
<file alias="HealthPageWidget.qml">src/FlightMap/Widgets/HealthPageWidget.qml</file> <file alias="HealthPageWidget.qml">src/FlightMap/Widgets/HealthPageWidget.qml</file>
<file alias="HelpSettings.qml">src/ui/preferences/HelpSettings.qml</file>
<file alias="JoystickConfig.qml">src/VehicleSetup/JoystickConfig.qml</file> <file alias="JoystickConfig.qml">src/VehicleSetup/JoystickConfig.qml</file>
<file alias="LinkSettings.qml">src/ui/preferences/LinkSettings.qml</file> <file alias="LinkSettings.qml">src/ui/preferences/LinkSettings.qml</file>
<file alias="LogDownloadPage.qml">src/AnalyzeView/LogDownloadPage.qml</file> <file alias="LogDownloadPage.qml">src/AnalyzeView/LogDownloadPage.qml</file>
......
...@@ -122,6 +122,9 @@ QString AudioOutput::fixTextMessageForAudio(const QString& string) { ...@@ -122,6 +122,9 @@ QString AudioOutput::fixTextMessageForAudio(const QString& string) {
if(result.contains(" EKF ", Qt::CaseInsensitive)) { if(result.contains(" EKF ", Qt::CaseInsensitive)) {
result.replace(" EKF ", " Eee Kay Eff ", Qt::CaseInsensitive); result.replace(" EKF ", " Eee Kay Eff ", Qt::CaseInsensitive);
} }
if(result.contains("PREARM", Qt::CaseInsensitive)) {
result.replace("PREARM", "pre arm", Qt::CaseInsensitive);
}
// Convert negative numbers // Convert negative numbers
QRegularExpression re(QStringLiteral("(-)[0-9]*\\.?[0-9]")); QRegularExpression re(QStringLiteral("(-)[0-9]*\\.?[0-9]"));
......
...@@ -128,9 +128,7 @@ SetupPage { ...@@ -128,9 +128,7 @@ SetupPage {
onWaitingForCancelChanged: { onWaitingForCancelChanged: {
if (controller.waitingForCancel) { if (controller.waitingForCancel) {
showMessage(qsTr("Calibration Cancel"), qsTr("Waiting for Vehicle to response to Cancel. This may take a few seconds."), 0) showDialog(waitForCancelDialogComponent, qsTr("Calibration Cancel"), qgcView.showDialogDefaultWidth, 0)
} else {
hideDialog()
} }
} }
...@@ -163,6 +161,24 @@ SetupPage { ...@@ -163,6 +161,24 @@ SetupPage {
QGCPalette { id: qgcPal; colorGroupEnabled: true } QGCPalette { id: qgcPal; colorGroupEnabled: true }
Component {
id: waitForCancelDialogComponent
QGCViewMessage {
message: qsTr("Waiting for Vehicle to response to Cancel. This may take a few seconds.")
Connections {
target: controller
onWaitingForCancelChanged: {
if (!controller.waitingForCancel) {
hideDialog()
}
}
}
}
}
Component { Component {
id: singleCompassOnboardResultsComponent id: singleCompassOnboardResultsComponent
...@@ -265,7 +281,10 @@ SetupPage { ...@@ -265,7 +281,10 @@ SetupPage {
QGCButton { QGCButton {
text: qsTr("Reboot Vehicle") text: qsTr("Reboot Vehicle")
onClicked: controller.vehicle.reboot() onClicked: {
controller.vehicle.rebootVehicle()
hideDialog()
}
} }
} }
} }
...@@ -290,8 +309,11 @@ SetupPage { ...@@ -290,8 +309,11 @@ SetupPage {
QGCButton { QGCButton {
text: qsTr("Reboot Vehicle") text: qsTr("Reboot Vehicle")
onClicked: controller.vehicle.rebootVehicle() onClicked: {
} controller.vehicle.rebootVehicle()
hideDialog()
}
}
} }
} }
} }
......
...@@ -167,7 +167,7 @@ void SensorsComponentController::_stopCalibration(SensorsComponentController::St ...@@ -167,7 +167,7 @@ void SensorsComponentController::_stopCalibration(SensorsComponentController::St
emit resetStatusTextArea(); emit resetStatusTextArea();
} }
if (_magCalInProgress) { if (_magCalInProgress) {
emit setCompassRotations(); emit magCalComplete();
} }
break; break;
......
...@@ -92,7 +92,7 @@ signals: ...@@ -92,7 +92,7 @@ signals:
void orientationCalSidesRotateChanged(void); void orientationCalSidesRotateChanged(void);
void resetStatusTextArea(void); void resetStatusTextArea(void);
void waitingForCancelChanged(void); void waitingForCancelChanged(void);
void setCompassRotations(void); void magCalComplete(void);
private slots: private slots:
void _handleUASTextMessage(int uasId, int compId, int severity, QString text); void _handleUASTextMessage(int uasId, int compId, int severity, QString text);
......
...@@ -131,11 +131,11 @@ Item { ...@@ -131,11 +131,11 @@ Item {
onResetStatusTextArea: statusLog.text = statusTextAreaDefaultText onResetStatusTextArea: statusLog.text = statusTextAreaDefaultText
onSetCompassRotations: { onMagCalComplete: {
if (!_sensorsHaveFixedOrientation && (showCompass0Rot || showCompass1Rot || showCompass2Rot)) { //if (!_sensorsHaveFixedOrientation && (showCompass0Rot || showCompass1Rot || showCompass2Rot)) {
setOrientationsDialogShowBoardOrientation = false setOrientationsDialogShowBoardOrientation = false
showDialog(setOrientationsDialogComponent, qsTr("Set Compass Rotation(s)"), qgcView.showDialogDefaultWidth, StandardButton.Ok) showDialog(setOrientationsDialogComponent, qsTr("Compass Calibration Complete"), qgcView.showDialogDefaultWidth, StandardButton.Ok)
} //}
} }
onWaitingForCancelChanged: { onWaitingForCancelChanged: {
...@@ -252,6 +252,20 @@ Item { ...@@ -252,6 +252,20 @@ Item {
anchors.top: parent.top anchors.top: parent.top
spacing: ScreenTools.defaultFontPixelHeight spacing: ScreenTools.defaultFontPixelHeight
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
text: qsTr("Set your compass orientations below and the make sure to reboot the vehicle prior to flight.")
}
QGCButton {
text: qsTr("Reboot Vehicle")
onClicked: {
controller.vehicle.rebootVehicle()
hideDialog()
}
}
QGCLabel { QGCLabel {
width: parent.width width: parent.width
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
......
...@@ -71,7 +71,8 @@ Rectangle { ...@@ -71,7 +71,8 @@ Rectangle {
id: editDialogComponent id: editDialogComponent
ParameterEditorDialog { ParameterEditorDialog {
fact: _fact fact: _fact
setFocus: ScreenTools.isMobile ? false : true // Works around strange android bug where wrong virtual keyboard is displayed
} }
} }
......
...@@ -27,7 +27,7 @@ FactValueSliderListModel::FactValueSliderListModel(Fact& fact, QObject* parent) ...@@ -27,7 +27,7 @@ FactValueSliderListModel::FactValueSliderListModel(Fact& fact, QObject* parent)
, _cPrevValues (0) , _cPrevValues (0)
, _cNextValues (0) , _cNextValues (0)
, _initialValue (0) , _initialValue (0)
, _initialValueRounded (0) , _initialValueAtPrecision (0)
, _increment (0) , _increment (0)
{ {
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
...@@ -47,14 +47,14 @@ int FactValueSliderListModel::resetInitialValue(void) ...@@ -47,14 +47,14 @@ int FactValueSliderListModel::resetInitialValue(void)
} }
_initialValue = _fact.cookedValue().toDouble(); _initialValue = _fact.cookedValue().toDouble();
_initialValueRounded = qRound(_initialValue); _initialValueAtPrecision = _valueAtPrecision(_initialValue);
if (qRound(_fact.rawIncrement()) == _fact.rawIncrement()) { if (qRound(_fact.rawIncrement()) == _fact.rawIncrement()) {
_increment = qRound(_fact.cookedIncrement()); _increment = qRound(_fact.cookedIncrement());
} else { } else {
_increment = _fact.cookedIncrement(); _increment = _fact.cookedIncrement();
} }
_cPrevValues = qMin((_initialValue - _fact.cookedMin().toDouble()), 100.0) / _increment; _cPrevValues = qMin((_initialValue - _fact.cookedMin().toDouble()) / _increment, 100.0);
_cNextValues = qMin((_fact.cookedMax().toDouble() - _initialValue), 100.0) / _increment; _cNextValues = qMin((_fact.cookedMax().toDouble() - _initialValue) / _increment, 100.0);
_initialValueIndex = _cPrevValues; _initialValueIndex = _cPrevValues;
int totalValueCount = _cPrevValues + 1 + _cNextValues; int totalValueCount = _cPrevValues + 1 + _cNextValues;
...@@ -93,12 +93,9 @@ QVariant FactValueSliderListModel::data(const QModelIndex &index, int role) cons ...@@ -93,12 +93,9 @@ QVariant FactValueSliderListModel::data(const QModelIndex &index, int role) cons
if (cIncrementCount == 0) { if (cIncrementCount == 0) {
value = _initialValue; value = _initialValue;
} else { } else {
value = _initialValueRounded + (cIncrementCount * _increment); value = initialValueAtPrecision() + (cIncrementCount * _increment);
} }
double precision = qPow(10, _fact.decimalPlaces()); return QVariant(_valueAtPrecision(value));
double atPrecision = qRound(value * precision) / precision;
//qDebug() << value << precision << atPrecision << _fact.decimalPlaces() << _fact.name();
return QVariant(atPrecision);
} else if (role == _valueIndexRole) { } else if (role == _valueIndexRole) {
return QVariant::fromValue(valueIndex); return QVariant::fromValue(valueIndex);
} else { } else {
...@@ -129,8 +126,8 @@ int FactValueSliderListModel::valueIndexAtModelIndex(int index) ...@@ -129,8 +126,8 @@ int FactValueSliderListModel::valueIndexAtModelIndex(int index)
return data(createIndex(index, 0), _valueIndexRole).toInt(); return data(createIndex(index, 0), _valueIndexRole).toInt();
} }
double FactValueSliderListModel::initialValueAtPrecision(void) double FactValueSliderListModel::_valueAtPrecision(double value) const
{ {
double precision = qPow(10, _fact.decimalPlaces()); double precision = qPow(10, _fact.decimalPlaces());
return qRound(_initialValue * precision) / precision; return qRound(value * precision) / precision;
} }
...@@ -25,7 +25,7 @@ public: ...@@ -25,7 +25,7 @@ public:
/// The initial value of the Fact at the meta data specified decimal place precision /// The initial value of the Fact at the meta data specified decimal place precision
Q_PROPERTY(double initialValueAtPrecision READ initialValueAtPrecision NOTIFY initialValueAtPrecisionChanged) Q_PROPERTY(double initialValueAtPrecision READ initialValueAtPrecision NOTIFY initialValueAtPrecisionChanged)
double initialValueAtPrecision(void); double initialValueAtPrecision(void) const { return _initialValueAtPrecision; }
Q_INVOKABLE int resetInitialValue(void); Q_INVOKABLE int resetInitialValue(void);
Q_INVOKABLE double valueAtModelIndex(int index); Q_INVOKABLE double valueAtModelIndex(int index);
...@@ -35,6 +35,8 @@ signals: ...@@ -35,6 +35,8 @@ signals:
void initialValueAtPrecisionChanged(void); void initialValueAtPrecisionChanged(void);
private: private:
double _valueAtPrecision(double value) const;
// Overrides from QAbstractListModel // Overrides from QAbstractListModel
int rowCount(const QModelIndex & parent = QModelIndex()) const override; int rowCount(const QModelIndex & parent = QModelIndex()) const override;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
...@@ -48,7 +50,7 @@ private: ...@@ -48,7 +50,7 @@ private:
int _cNextValues; int _cNextValues;
int _windowSize; int _windowSize;
double _initialValue; double _initialValue;
double _initialValueRounded; double _initialValueAtPrecision;
double _increment; double _increment;
static const int _valueRole; static const int _valueRole;
......
...@@ -505,6 +505,30 @@ const QVariantList& FirmwarePlugin::cameraList(const Vehicle* vehicle) ...@@ -505,6 +505,30 @@ const QVariantList& FirmwarePlugin::cameraList(const Vehicle* vehicle)
0, // minTriggerInterval 0, // minTriggerInterval
this); this);
_cameraList.append(QVariant::fromValue(metaData)); _cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(tr("Sentera NDVI Single Sensor"),
4.68, // sensorWidth
3.56, // sendsorHeight
1248, // imageWidth
952, // imageHeight
4.14, // focalLength
true, // landscape
false, // fixedOrientation
0, // minTriggerInterval
this);
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(tr("Sentera Double 4K Sensor"),
6.2, // sensorWidth
4.65, // sendsorHeight
4000, // imageWidth
3000, // imageHeight
5.4, // focalLength
true, // landscape
false, // fixedOrientation
0, // minTriggerInterval
this);
_cameraList.append(QVariant::fromValue(metaData));
} }
return _cameraList; return _cameraList;
......
...@@ -65,7 +65,7 @@ Item { ...@@ -65,7 +65,7 @@ Item {
readonly property string changeAltMessage: qsTr("Change the altitude of the vehicle up or down.") readonly property string changeAltMessage: qsTr("Change the altitude of the vehicle up or down.")
readonly property string gotoMessage: qsTr("Move the vehicle to the specified location.") readonly property string gotoMessage: qsTr("Move the vehicle to the specified location.")
property string setWaypointMessage: qsTr("Adjust current waypoint to %1.").arg(_actionData) property string setWaypointMessage: qsTr("Adjust current waypoint to %1.").arg(_actionData)
readonly property string orbitMessage: qsTr("Orbit the vehicle around the specified location. Warning: WORK IN PROGRESS!") readonly property string orbitMessage: qsTr("Orbit the vehicle around the specified location.")
readonly property string landAbortMessage: qsTr("Abort the landing sequence.") readonly property string landAbortMessage: qsTr("Abort the landing sequence.")
readonly property string pauseMessage: qsTr("Pause the vehicle at it's current position, adjusting altitude up or down as needed.") readonly property string pauseMessage: qsTr("Pause the vehicle at it's current position, adjusting altitude up or down as needed.")
readonly property string mvPauseMessage: qsTr("Pause all vehicles at their current position.") readonly property string mvPauseMessage: qsTr("Pause all vehicles at their current position.")
......
...@@ -65,7 +65,7 @@ Map { ...@@ -65,7 +65,7 @@ Map {
} }
function centerToSpecifiedLocation() { function centerToSpecifiedLocation() {
qgcView.showDialog(specifyMapPositionDialog, qsTr("Specify Position"), qgcView.showDialogDefaultWidth, StandardButton.Cancel) qgcView.showDialog(specifyMapPositionDialog, qsTr("Specify Position"), qgcView.showDialogDefaultWidth, StandardButton.Close)
} }
......
...@@ -26,8 +26,8 @@ const char* CameraCalc::adjustedFootprintSideName = "AdjustedFootprintSi ...@@ -26,8 +26,8 @@ const char* CameraCalc::adjustedFootprintSideName = "AdjustedFootprintSi
const char* CameraCalc::_jsonCameraSpecTypeKey = "CameraSpecType"; const char* CameraCalc::_jsonCameraSpecTypeKey = "CameraSpecType";
CameraCalc::CameraCalc(Vehicle* vehicle, QString settingsGroup, QObject* parent) CameraCalc::CameraCalc(Vehicle* vehicle, const QString& settingsGroup, QObject* parent)
: CameraSpec (parent) : CameraSpec (settingsGroup, parent)
, _vehicle (vehicle) , _vehicle (vehicle)
, _dirty (false) , _dirty (false)
, _disableRecalc (false) , _disableRecalc (false)
......
...@@ -19,7 +19,7 @@ class CameraCalc : public CameraSpec ...@@ -19,7 +19,7 @@ class CameraCalc : public CameraSpec
Q_OBJECT Q_OBJECT
public: public:
CameraCalc(Vehicle* vehicle, QString settingsGroup, QObject* parent = NULL); CameraCalc(Vehicle* vehicle, const QString& settingsGroup, QObject* parent = NULL);
Q_PROPERTY(QString customCameraName READ customCameraName CONSTANT) ///< Camera name for custom camera setting Q_PROPERTY(QString customCameraName READ customCameraName CONSTANT) ///< Camera name for custom camera setting
Q_PROPERTY(QString manualCameraName READ manualCameraName CONSTANT) ///< Camera name for manual camera setting Q_PROPERTY(QString manualCameraName READ manualCameraName CONSTANT) ///< Camera name for manual camera setting
......
...@@ -21,38 +21,20 @@ const char* CameraSpec::_landscapeName = "Landscape"; ...@@ -21,38 +21,20 @@ const char* CameraSpec::_landscapeName = "Landscape";
const char* CameraSpec::_fixedOrientationName = "FixedOrientation"; const char* CameraSpec::_fixedOrientationName = "FixedOrientation";
const char* CameraSpec::_minTriggerIntervalName = "MinTriggerInterval"; const char* CameraSpec::_minTriggerIntervalName = "MinTriggerInterval";
CameraSpec::CameraSpec(QObject* parent) CameraSpec::CameraSpec(const QString& settingsGroup, QObject* parent)
: QObject (parent) : QObject (parent)
, _dirty (false) , _dirty (false)
, _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraSpec.FactMetaData.json"), this)) , _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraSpec.FactMetaData.json"), this))
, _sensorWidthFact (0, _sensorWidthName, FactMetaData::valueTypeDouble) , _sensorWidthFact (settingsGroup, _metaDataMap[_sensorWidthName])
, _sensorHeightFact (0, _sensorHeightName, FactMetaData::valueTypeDouble) , _sensorHeightFact (settingsGroup, _metaDataMap[_sensorHeightName])
, _imageWidthFact (0, _imageWidthName, FactMetaData::valueTypeUint32) , _imageWidthFact (settingsGroup, _metaDataMap[_imageWidthName])
, _imageHeightFact (0, _imageHeightName, FactMetaData::valueTypeUint32) , _imageHeightFact (settingsGroup, _metaDataMap[_imageHeightName])
, _focalLengthFact (0, _focalLengthName, FactMetaData::valueTypeDouble) , _focalLengthFact (settingsGroup, _metaDataMap[_focalLengthName])
, _landscapeFact (0, _landscapeName, FactMetaData::valueTypeBool) , _landscapeFact (settingsGroup, _metaDataMap[_landscapeName])
, _fixedOrientationFact (0, _fixedOrientationName, FactMetaData::valueTypeBool) , _fixedOrientationFact (settingsGroup, _metaDataMap[_fixedOrientationName])
, _minTriggerIntervalFact (0, _minTriggerIntervalName, FactMetaData::valueTypeDouble) , _minTriggerIntervalFact (settingsGroup, _metaDataMap[_minTriggerIntervalName])
{ {
_init(true); QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
}
CameraSpec::CameraSpec(const CameraSpec& other, QObject* parent)
: QObject (parent)
, _dirty (false)
, _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraSpec.FactMetaData.json"), this))
, _sensorWidthFact (0, _sensorWidthName, FactMetaData::valueTypeDouble)
, _sensorHeightFact (0, _sensorHeightName, FactMetaData::valueTypeDouble)
, _imageWidthFact (0, _imageWidthName, FactMetaData::valueTypeUint32)
, _imageHeightFact (0, _imageHeightName, FactMetaData::valueTypeUint32)
, _focalLengthFact (0, _focalLengthName, FactMetaData::valueTypeDouble)
, _landscapeFact (0, _landscapeName, FactMetaData::valueTypeBool)
, _fixedOrientationFact (0, _fixedOrientationName, FactMetaData::valueTypeBool)
, _minTriggerIntervalFact (0, _minTriggerIntervalName, FactMetaData::valueTypeDouble)
{
_init(false);
*this = other;
} }
const CameraSpec& CameraSpec::operator=(const CameraSpec& other) const CameraSpec& CameraSpec::operator=(const CameraSpec& other)
...@@ -69,20 +51,6 @@ const CameraSpec& CameraSpec::operator=(const CameraSpec& other) ...@@ -69,20 +51,6 @@ const CameraSpec& CameraSpec::operator=(const CameraSpec& other)
return *this; return *this;
} }
void CameraSpec::_init(bool setDefaults)
{
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
_sensorWidthFact.setMetaData (_metaDataMap[_sensorWidthName], setDefaults);
_sensorHeightFact.setMetaData (_metaDataMap[_sensorHeightName], setDefaults);
_imageWidthFact.setMetaData (_metaDataMap[_imageWidthName], setDefaults);
_imageHeightFact.setMetaData (_metaDataMap[_imageHeightName], setDefaults);
_focalLengthFact.setMetaData (_metaDataMap[_focalLengthName], setDefaults);
_landscapeFact.setMetaData (_metaDataMap[_landscapeName], setDefaults);
_fixedOrientationFact.setMetaData (_metaDataMap[_fixedOrientationName], setDefaults);
_minTriggerIntervalFact.setMetaData (_metaDataMap[_minTriggerIntervalName], setDefaults);
}
void CameraSpec::setDirty(bool dirty) void CameraSpec::setDirty(bool dirty)
{ {
if (_dirty != dirty) { if (_dirty != dirty) {
......
...@@ -9,15 +9,14 @@ ...@@ -9,15 +9,14 @@
#pragma once #pragma once
#include "Fact.h" #include "SettingsFact.h"
class CameraSpec : public QObject class CameraSpec : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
CameraSpec(QObject* parent = NULL); CameraSpec(const QString& settingsGroup, QObject* parent = NULL);
CameraSpec(const CameraSpec& other, QObject* parent);
const CameraSpec& operator=(const CameraSpec& other); const CameraSpec& operator=(const CameraSpec& other);
...@@ -31,14 +30,14 @@ public: ...@@ -31,14 +30,14 @@ public:
Q_PROPERTY(Fact* fixedOrientation READ fixedOrientation CONSTANT) ///< true: camera is in fixed orientation Q_PROPERTY(Fact* fixedOrientation READ fixedOrientation CONSTANT) ///< true: camera is in fixed orientation
Q_PROPERTY(Fact* minTriggerInterval READ minTriggerInterval CONSTANT) ///< Minimum time in seconds between each photo taken, 0 for not specified Q_PROPERTY(Fact* minTriggerInterval READ minTriggerInterval CONSTANT) ///< Minimum time in seconds between each photo taken, 0 for not specified
Fact* sensorWidth (void) { return &_sensorWidthFact; } SettingsFact* sensorWidth (void) { return &_sensorWidthFact; }
Fact* sensorHeight (void) { return &_sensorHeightFact; } SettingsFact* sensorHeight (void) { return &_sensorHeightFact; }
Fact* imageWidth (void) { return &_imageWidthFact; } SettingsFact* imageWidth (void) { return &_imageWidthFact; }
Fact* imageHeight (void) { return &_imageHeightFact; } SettingsFact* imageHeight (void) { return &_imageHeightFact; }
Fact* focalLength (void) { return &_focalLengthFact; } SettingsFact* focalLength (void) { return &_focalLengthFact; }
Fact* landscape (void) { return &_landscapeFact; } SettingsFact* landscape (void) { return &_landscapeFact; }
Fact* fixedOrientation (void) { return &_fixedOrientationFact; } SettingsFact* fixedOrientation (void) { return &_fixedOrientationFact; }
Fact* minTriggerInterval(void) { return &_minTriggerIntervalFact; } SettingsFact* minTriggerInterval(void) { return &_minTriggerIntervalFact; }
bool dirty (void) const { return _dirty; } bool dirty (void) const { return _dirty; }
void setDirty (bool dirty); void setDirty (bool dirty);
...@@ -50,20 +49,18 @@ signals: ...@@ -50,20 +49,18 @@ signals:
void dirtyChanged(bool dirty); void dirtyChanged(bool dirty);
private: private:
void _init(bool setDefaults);
bool _dirty; bool _dirty;
QMap<QString, FactMetaData*> _metaDataMap; QMap<QString, FactMetaData*> _metaDataMap;
Fact _sensorWidthFact; SettingsFact _sensorWidthFact;
Fact _sensorHeightFact; SettingsFact _sensorHeightFact;
Fact _imageWidthFact; SettingsFact _imageWidthFact;
Fact _imageHeightFact; SettingsFact _imageHeightFact;
Fact _focalLengthFact; SettingsFact _focalLengthFact;
Fact _landscapeFact; SettingsFact _landscapeFact;
Fact _fixedOrientationFact; SettingsFact _fixedOrientationFact;
Fact _minTriggerIntervalFact; SettingsFact _minTriggerIntervalFact;
static const char* _sensorWidthName; static const char* _sensorWidthName;
static const char* _sensorHeightName; static const char* _sensorHeightName;
......
...@@ -225,7 +225,9 @@ bool FixedWingLandingComplexItem::load(const QJsonObject& complexObject, int seq ...@@ -225,7 +225,9 @@ bool FixedWingLandingComplexItem::load(const QJsonObject& complexObject, int seq
_landingCoordSet = true; _landingCoordSet = true;
_ignoreRecalcSignals = false; _ignoreRecalcSignals = false;
_recalcFromCoordinateChange(); _recalcFromCoordinateChange();
emit coordinateChanged(this->coordinate()); // This will kick off terrain query
return true; return true;
} }
......
...@@ -123,7 +123,6 @@ Item { ...@@ -123,7 +123,6 @@ Item {
_circle = false _circle = false
} }
/// Reset polygon to a circle which fits within initial polygon
function setCircleRadius(center, radius) { function setCircleRadius(center, radius) {
var unboundCenter = center.atDistanceAndAzimuth(0, 0) var unboundCenter = center.atDistanceAndAzimuth(0, 0)
_circleRadius = radius _circleRadius = radius
...@@ -231,7 +230,7 @@ Item { ...@@ -231,7 +230,7 @@ Item {
MenuItem { MenuItem {
text: qsTr("Edit position..." ) text: qsTr("Edit position..." )
enabled: _circle enabled: _circle
onTriggered: qgcView.showDialog(editPositionDialog, qsTr("Edit Position"), qgcView.showDialogDefaultWidth, StandardButton.Cancel) onTriggered: qgcView.showDialog(editPositionDialog, qsTr("Edit Position"), qgcView.showDialogDefaultWidth, StandardButton.Close)
} }
MenuItem { MenuItem {
...@@ -460,7 +459,8 @@ Item { ...@@ -460,7 +459,8 @@ Item {
} }
function setRadiusFromDialog() { function setRadiusFromDialog() {
setCircleRadius(mapPolygon.center, radiusField.text) var radius = QGroundControl.appSettingsDistanceUnitsToMeters(radiusField.text)
setCircleRadius(mapPolygon.center, radius)
_editCircleRadius = false _editCircleRadius = false
} }
...@@ -484,7 +484,9 @@ Item { ...@@ -484,7 +484,9 @@ Item {
QGCTextField { QGCTextField {
id: radiusField id: radiusField
text: _circleRadius.toFixed(2) showUnits: true
unitsLabel: QGroundControl.appSettingsDistanceUnitsString
text: QGroundControl.metersToAppSettingsDistanceUnits(_circleRadius).toFixed(2)
onEditingFinished: setRadiusFromDialog() onEditingFinished: setRadiusFromDialog()
inputMethodHints: Qt.ImhFormattedNumbersOnly inputMethodHints: Qt.ImhFormattedNumbersOnly
} }
......
...@@ -173,6 +173,10 @@ void VisualMissionItem::setMissionVehicleYaw(double vehicleYaw) ...@@ -173,6 +173,10 @@ void VisualMissionItem::setMissionVehicleYaw(double vehicleYaw)
void VisualMissionItem::_updateTerrainAltitude(void) void VisualMissionItem::_updateTerrainAltitude(void)
{ {
if (coordinate().latitude() == 0 && coordinate().longitude() == 0) {
// This is an intermediate state we don't react to
return;
}
if (!_flyView && coordinate().isValid()) { if (!_flyView && coordinate().isValid()) {
// We use a timer so that any additional requests before the timer fires result in only a single request // We use a timer so that any additional requests before the timer fires result in only a single request
_updateTerrainTimer.start(); _updateTerrainTimer.start();
...@@ -195,9 +199,7 @@ void VisualMissionItem::_reallyUpdateTerrainAltitude(void) ...@@ -195,9 +199,7 @@ void VisualMissionItem::_reallyUpdateTerrainAltitude(void)
void VisualMissionItem::_terrainDataReceived(bool success, QList<double> heights) void VisualMissionItem::_terrainDataReceived(bool success, QList<double> heights)
{ {
if (success) { _terrainAltitude = success ? heights[0] : qQNaN();
_terrainAltitude = heights[0]; emit terrainAltitudeChanged(_terrainAltitude);
emit terrainAltitudeChanged(_terrainAltitude); sender()->deleteLater();
sender()->deleteLater();
}
} }
...@@ -31,8 +31,12 @@ Rectangle { ...@@ -31,8 +31,12 @@ Rectangle {
//property real availableWidth ///< Width for control //property real availableWidth ///< Width for control
//property var missionItem ///< Mission Item for editor //property var missionItem ///< Mission Item for editor
property real _margin: ScreenTools.defaultFontPixelWidth / 2 property real _margin: ScreenTools.defaultFontPixelWidth / 2
property real _spacer: ScreenTools.defaultFontPixelWidth / 2 property real _spacer: ScreenTools.defaultFontPixelWidth / 2
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
property string _setToVehicleHeadingStr: qsTr("Set to vehicle heading")
property string _setToVehicleLocationStr: qsTr("Set to vehicle location")
ExclusiveGroup { id: distanceGlideGroup } ExclusiveGroup { id: distanceGlideGroup }
...@@ -45,34 +49,57 @@ Rectangle { ...@@ -45,34 +49,57 @@ Rectangle {
visible: missionItem.landingCoordSet visible: missionItem.landingCoordSet
SectionHeader { SectionHeader {
text: qsTr("Loiter point") id: loiterPointSection
text: qsTr("Loiter point")
} }
Item { width: 1; height: _spacer } Column {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
visible: loiterPointSection.checked
FactTextFieldGrid { Item { width: 1; height: _spacer }
anchors.left: parent.left
anchors.right: parent.right
factList: [ missionItem.loiterAltitude, missionItem.loiterRadius ]
factLabels: [ qsTr("Altitude"), qsTr("Radius") ]
}
Item { width: 1; height: _spacer } FactTextFieldGrid {
anchors.left: parent.left
anchors.right: parent.right
factList: [ missionItem.loiterAltitude, missionItem.loiterRadius ]
factLabels: [ qsTr("Altitude"), qsTr("Radius") ]
}
QGCCheckBox { Item { width: 1; height: _spacer }
text: qsTr("Loiter clockwise")
checked: missionItem.loiterClockwise QGCCheckBox {
onClicked: missionItem.loiterClockwise = checked text: qsTr("Loiter clockwise")
checked: missionItem.loiterClockwise
onClicked: missionItem.loiterClockwise = checked
}
QGCButton {
text: _setToVehicleHeadingStr
visible: _activeVehicle
onClicked: missionItem.landingHeading.rawValue = _activeVehicle.heading.rawValue
}
} }
SectionHeader { text: qsTr("Landing point") } SectionHeader {
id: landingPointSection
text: qsTr("Landing point")
}
Item { width: 1; height: _spacer } Column {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
visible: landingPointSection.checked
Item { width: 1; height: _spacer }
GridLayout { GridLayout {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
columns: 2 columns: 2
QGCLabel { text: qsTr("Heading") } QGCLabel { text: qsTr("Heading") }
...@@ -88,34 +115,42 @@ Rectangle { ...@@ -88,34 +115,42 @@ Rectangle {
fact: missionItem.landingAltitude fact: missionItem.landingAltitude
} }
QGCRadioButton { QGCRadioButton {
id: specifyLandingDistance id: specifyLandingDistance
text: qsTr("Landing Dist") text: qsTr("Landing Dist")
checked: missionItem.valueSetIsDistance checked: missionItem.valueSetIsDistance
exclusiveGroup: distanceGlideGroup exclusiveGroup: distanceGlideGroup
onClicked: missionItem.valueSetIsDistance = checked onClicked: missionItem.valueSetIsDistance = checked
Layout.fillWidth: true Layout.fillWidth: true
} }
FactTextField { FactTextField {
fact: missionItem.landingDistance fact: missionItem.landingDistance
enabled: specifyLandingDistance.checked enabled: specifyLandingDistance.checked
Layout.fillWidth: true Layout.fillWidth: true
} }
QGCRadioButton { QGCRadioButton {
id: specifyGlideSlope id: specifyGlideSlope
text: qsTr("Glide Slope") text: qsTr("Glide Slope")
checked: !missionItem.valueSetIsDistance checked: !missionItem.valueSetIsDistance
exclusiveGroup: distanceGlideGroup exclusiveGroup: distanceGlideGroup
onClicked: missionItem.valueSetIsDistance = !checked onClicked: missionItem.valueSetIsDistance = !checked
Layout.fillWidth: true Layout.fillWidth: true
} }
FactTextField {
fact: missionItem.glideSlope
enabled: specifyGlideSlope.checked
Layout.fillWidth: true
}
FactTextField { QGCButton {
fact: missionItem.glideSlope text: _setToVehicleLocationStr
enabled: specifyGlideSlope.checked visible: _activeVehicle
Layout.fillWidth: true Layout.columnSpan: 2
onClicked: missionItem.landingCoordinate = _activeVehicle.coordinate
}
} }
} }
...@@ -140,10 +175,30 @@ Rectangle { ...@@ -140,10 +175,30 @@ Rectangle {
spacing: ScreenTools.defaultFontPixelHeight spacing: ScreenTools.defaultFontPixelHeight
QGCLabel { QGCLabel {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: qsTr("Click in map to set landing point.") horizontalAlignment: Text.AlignHCenter
text: qsTr("Click in map to set landing point.")
}
QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
horizontalAlignment: Text.AlignHCenter
text: qsTr("- or -")
visible: _activeVehicle
}
QGCButton {
anchors.horizontalCenter: parent.horizontalCenter
text: _setToVehicleLocationStr
visible: _activeVehicle
onClicked: {
missionItem.landingCoordinate = _activeVehicle.coordinate
missionItem.landingHeading.rawValue = _activeVehicle.heading.rawValue
}
} }
} }
} }
...@@ -142,13 +142,13 @@ Rectangle { ...@@ -142,13 +142,13 @@ Rectangle {
MenuItem { MenuItem {
text: qsTr("Change command...") text: qsTr("Change command...")
onTriggered: commandPicker.clicked() onTriggered: commandPicker.clicked()
visible: !_waypointsOnlyMode visible: missionItem.isSimpleItem && !_waypointsOnlyMode
} }
MenuItem { MenuItem {
text: qsTr("Edit position...") text: qsTr("Edit position...")
visible: missionItem.specifiesCoordinate visible: missionItem.specifiesCoordinate
onTriggered: qgcView.showDialog(editPositionDialog, qsTr("Edit Position"), qgcView.showDialogDefaultWidth, StandardButton.Cancel) onTriggered: qgcView.showDialog(editPositionDialog, qsTr("Edit Position"), qgcView.showDialogDefaultWidth, StandardButton.Close)
} }
MenuSeparator { MenuSeparator {
......
...@@ -299,8 +299,13 @@ QGCView { ...@@ -299,8 +299,13 @@ QGCView {
if (retList[0] == KMLFileHelper.Error) { if (retList[0] == KMLFileHelper.Error) {
_qgcView.showMessage("Error", retList[1], StandardButton.Ok) _qgcView.showMessage("Error", retList[1], StandardButton.Ok)
} else if (retList[0] == KMLFileHelper.Polygon) { } else if (retList[0] == KMLFileHelper.Polygon) {
kmlPolygonSelectDialogKMLFile = file var editVehicle = _activeVehicle ? _activeVehicle : QGroundControl.multiVehicleManager.offlineEditingVehicle
_qgcView.showDialog(kmlPolygonSelectDialog, fileDialog.title, _qgcView.showDialogDefaultWidth, StandardButton.Ok | StandardButton.Cancel) if (editVehicle.fixedWing) {
insertComplexMissionItemFromKML(_missionController.surveyComplexItemName, file, -1)
} else {
kmlPolygonSelectDialogKMLFile = file
_qgcView.showDialog(kmlPolygonSelectDialog, fileDialog.title, _qgcView.showDialogDefaultWidth, StandardButton.Ok | StandardButton.Cancel)
}
} else if (retList[0] == KMLFileHelper.Polyline) { } else if (retList[0] == KMLFileHelper.Polyline) {
insertComplexMissionItemFromKML(_missionController.corridorScanComplexItemName, file, -1) insertComplexMissionItemFromKML(_missionController.corridorScanComplexItemName, file, -1)
} }
...@@ -314,8 +319,6 @@ QGCView { ...@@ -314,8 +319,6 @@ QGCView {
id: kmlPolygonSelectDialog id: kmlPolygonSelectDialog
QGCViewDialog { QGCViewDialog {
property var editVehicle: _activeVehicle ? _activeVehicle : QGroundControl.multiVehicleManager.offlineEditingVehicle
function accept() { function accept() {
var complexItemName var complexItemName
if (surveyRadio.checked) { if (surveyRadio.checked) {
...@@ -327,13 +330,6 @@ QGCView { ...@@ -327,13 +330,6 @@ QGCView {
hideDialog() hideDialog()
} }
Component.onCompleted: {
if (editVehicle.fixedWing) {
// Only Survey available
accept()
}
}
ExclusiveGroup { ExclusiveGroup {
id: radioGroup id: radioGroup
} }
...@@ -360,7 +356,6 @@ QGCView { ...@@ -360,7 +356,6 @@ QGCView {
QGCRadioButton { QGCRadioButton {
text: qsTr("Structure Scan") text: qsTr("Structure Scan")
exclusiveGroup: radioGroup exclusiveGroup: radioGroup
visible: !editVehicle.fixedWing
} }
} }
} }
......
...@@ -74,17 +74,18 @@ Rectangle { ...@@ -74,17 +74,18 @@ Rectangle {
} }
SectionHeader { SectionHeader {
id: corridorHeader id: transectsHeader
text: qsTr("Transects") text: qsTr("Transects")
} }
GridLayout { GridLayout {
id: transectsGrid
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
columnSpacing: _margin columnSpacing: _margin
rowSpacing: _margin rowSpacing: _margin
columns: 2 columns: 2
visible: corridorHeader.checked visible: transectsHeader.checked
QGCLabel { text: qsTr("Angle") } QGCLabel { text: qsTr("Angle") }
FactTextField { FactTextField {
...@@ -108,8 +109,8 @@ Rectangle { ...@@ -108,8 +109,8 @@ Rectangle {
QGCLabel { text: qsTr("Turnaround dist") } QGCLabel { text: qsTr("Turnaround dist") }
FactTextField { FactTextField {
fact: missionItem.turnAroundDistance fact: missionItem.turnAroundDistance
Layout.fillWidth: true Layout.fillWidth: true
} }
QGCButton { QGCButton {
...@@ -132,14 +133,14 @@ Rectangle { ...@@ -132,14 +133,14 @@ Rectangle {
} }
FactCheckBox { FactCheckBox {
text: qsTr("Refly at 90 degree offset") text: qsTr("Refly at 90 deg offset")
fact: missionItem.refly90Degrees fact: missionItem.refly90Degrees
enabled: !missionItem.followTerrain enabled: !missionItem.followTerrain
Layout.columnSpan: 2 Layout.columnSpan: 2
} }
FactCheckBox { FactCheckBox {
text: qsTr("Take images in turnarounds") text: qsTr("Images in turnarounds")
fact: missionItem.cameraTriggerInTurnAround fact: missionItem.cameraTriggerInTurnAround
enabled: missionItem.hoverAndCaptureAllowed ? !missionItem.hoverAndCapture.rawValue : true enabled: missionItem.hoverAndCaptureAllowed ? !missionItem.hoverAndCapture.rawValue : true
Layout.columnSpan: 2 Layout.columnSpan: 2
......
...@@ -33,6 +33,7 @@ QGCView { ...@@ -33,6 +33,7 @@ QGCView {
property var _searchResults ///< List of parameter names from search results property var _searchResults ///< List of parameter names from search results
property bool _showRCToParam: !ScreenTools.isMobile && QGroundControl.multiVehicleManager.activeVehicle.px4Firmware property bool _showRCToParam: !ScreenTools.isMobile && QGroundControl.multiVehicleManager.activeVehicle.px4Firmware
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
property var _appSettings: QGroundControl.settingsManager.appSettings
ParameterEditorController { ParameterEditorController {
id: controller; id: controller;
...@@ -112,28 +113,18 @@ QGCView { ...@@ -112,28 +113,18 @@ QGCView {
MenuItem { MenuItem {
text: qsTr("Load from file...") text: qsTr("Load from file...")
onTriggered: { onTriggered: {
var appSettings = QGroundControl.settingsManager.appSettings
fileDialog.qgcView = qgcView fileDialog.qgcView = qgcView
fileDialog.title = qsTr("Select Parameter File") fileDialog.title = qsTr("Load Parameters")
fileDialog.selectExisting = true fileDialog.selectExisting = true
fileDialog.folder = appSettings.parameterSavePath
fileDialog.fileExtension = appSettings.parameterFileExtension
fileDialog.nameFilters = [ qsTr("Parameter Files (*.%1)").arg(appSettings.parameterFileExtension) , qsTr("All Files (*.*)") ]
fileDialog.openForLoad() fileDialog.openForLoad()
} }
} }
MenuItem { MenuItem {
text: qsTr("Save to file...") text: qsTr("Save to file...")
onTriggered: { onTriggered: {
var appSettings = QGroundControl.settingsManager.appSettings
fileDialog.qgcView = qgcView fileDialog.qgcView = qgcView
fileDialog.title = qsTr("Save Parameters") fileDialog.title = qsTr("Save Parameters")
fileDialog.selectExisting = false fileDialog.selectExisting = false
fileDialog.folder = appSettings.parameterSavePath
fileDialog.fileExtension = appSettings.parameterFileExtension
fileDialog.nameFilters = [ qsTr("Parameter Files (*.%1)").arg(appSettings.parameterFileExtension) , qsTr("All Files (*.*)") ]
fileDialog.openForSave() fileDialog.openForSave()
} }
} }
...@@ -292,7 +283,10 @@ QGCView { ...@@ -292,7 +283,10 @@ QGCView {
} // QGCViewPanel } // QGCViewPanel
QGCFileDialog { QGCFileDialog {
id: fileDialog id: fileDialog
folder: _appSettings.parameterSavePath
fileExtension: _appSettings.parameterFileExtension
nameFilters: [ qsTr("Parameter Files (*.%1)").arg(_appSettings.parameterFileExtension) , qsTr("All Files (*.*)") ]
onAcceptedForSave: { onAcceptedForSave: {
controller.saveToFile(file) controller.saveToFile(file)
......
...@@ -98,10 +98,15 @@ void ParameterEditorController::clearRCToParam(void) ...@@ -98,10 +98,15 @@ void ParameterEditorController::clearRCToParam(void)
void ParameterEditorController::saveToFile(const QString& filename) void ParameterEditorController::saveToFile(const QString& filename)
{ {
if (!filename.isEmpty()) { if (!filename.isEmpty()) {
QFile file(filename); QString parameterFilename = filename;
if (!QFileInfo(filename).fileName().contains(".")) {
parameterFilename += QString(".%1").arg(AppSettings::parameterFileExtension);
}
QFile file(parameterFilename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qgcApp()->showMessage(tr("Unable to create file: %1").arg(filename)); qgcApp()->showMessage(tr("Unable to create file: %1").arg(parameterFilename));
return; return;
} }
......
...@@ -27,6 +27,7 @@ QGCViewDialog { ...@@ -27,6 +27,7 @@ QGCViewDialog {
property bool showRCToParam: false property bool showRCToParam: false
property bool validate: false property bool validate: false
property string validateValue property string validateValue
property bool setFocus: true ///< true: focus is set to text field on display, false: focus not set (works around strange virtual keyboard bug with FactValueSlider
signal valueChanged signal valueChanged
...@@ -122,7 +123,7 @@ QGCViewDialog { ...@@ -122,7 +123,7 @@ QGCViewDialog {
unitsLabel: fact.units unitsLabel: fact.units
showUnits: fact.units != "" showUnits: fact.units != ""
Layout.fillWidth: true Layout.fillWidth: true
focus: true focus: setFocus
inputMethodHints: (fact.typeIsString || ScreenTools.isiOS) ? inputMethodHints: (fact.typeIsString || ScreenTools.isiOS) ?
Qt.ImhNone : // iOS numeric keyboard has no done button, we can't use it Qt.ImhNone : // iOS numeric keyboard has no done button, we can't use it
Qt.ImhFormattedNumbersOnly // Forces use of virtual numeric keyboard Qt.ImhFormattedNumbersOnly // Forces use of virtual numeric keyboard
......
...@@ -20,9 +20,16 @@ import QGroundControl.Palette 1.0 ...@@ -20,9 +20,16 @@ import QGroundControl.Palette 1.0
QGCViewDialog { QGCViewDialog {
property string message property string message
QGCLabel { QGCFlickable {
anchors.fill: parent anchors.fill: parent
wrapMode: Text.WordWrap contentHeight: label.contentHeight
text: message
QGCLabel {
id: label
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: message
}
} }
} }
...@@ -79,7 +79,7 @@ public: ...@@ -79,7 +79,7 @@ public:
EsriWorldSatellite = 7001, EsriWorldSatellite = 7001,
EsriTerrain = 7002, EsriTerrain = 7002,
AirmapElevation = 8000 AirmapElevation = 8001
}; };
UrlFactory (); UrlFactory ();
......
...@@ -286,7 +286,12 @@ QGCView { ...@@ -286,7 +286,12 @@ QGCView {
Item { width: 1; height: 1 } Item { width: 1; height: 1 }
QGCLabel { text: qsTr("Max Cache Memory Size (MB):") } QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: qsTr("Max Cache Memory Size (MB):")
}
QGCTextField { QGCTextField {
id: maxCacheMemSize id: maxCacheMemSize
...@@ -297,6 +302,9 @@ QGCView { ...@@ -297,6 +302,9 @@ QGCView {
} }
QGCLabel { QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
font.pointSize: _adjustableFontPointSize font.pointSize: _adjustableFontPointSize
text: qsTr("Memory cache changes require a restart to take effect.") text: qsTr("Memory cache changes require a restart to take effect.")
} }
...@@ -310,6 +318,9 @@ QGCView { ...@@ -310,6 +318,9 @@ QGCView {
width: ScreenTools.defaultFontPixelWidth * 30 width: ScreenTools.defaultFontPixelWidth * 30
} }
QGCLabel { QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: qsTr("To enable Mapbox maps, enter your access token.") text: qsTr("To enable Mapbox maps, enter your access token.")
visible: _mapboxFact ? _mapboxFact.visible : false visible: _mapboxFact ? _mapboxFact.visible : false
font.pointSize: _adjustableFontPointSize font.pointSize: _adjustableFontPointSize
...@@ -324,6 +335,9 @@ QGCView { ...@@ -324,6 +335,9 @@ QGCView {
width: ScreenTools.defaultFontPixelWidth * 30 width: ScreenTools.defaultFontPixelWidth * 30
} }
QGCLabel { QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: qsTr("To enable Esri maps, enter your access token.") text: qsTr("To enable Esri maps, enter your access token.")
visible: _esriFact ? _esriFact.visible : false visible: _esriFact ? _esriFact.visible : false
font.pointSize: _adjustableFontPointSize font.pointSize: _adjustableFontPointSize
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
{ {
"name": "OfflineEditingCruiseSpeed", "name": "OfflineEditingCruiseSpeed",
"shortDescription": "Offline editing cruise speed", "shortDescription": "Offline editing cruise speed",
"longDescription": "This value defines the cruising speed for forward flight vehicles for use in calculating mission duration.", "longDescription": "This value defines the default cruising speed for forward flight vehicles for use in calculating mission statistics. It does not modify the flight speed for a specific flight plan.",
"type": "double", "type": "double",
"defaultValue": 15.0, "defaultValue": 15.0,
"min": 1.0, "min": 1.0,
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
{ {
"name": "OfflineEditingHoverSpeed", "name": "OfflineEditingHoverSpeed",
"shortDescription": "Offline editing hover speed", "shortDescription": "Offline editing hover speed",
"longDescription": "This value defines the cruising speed for multi-rotor vehicles for use in calculating mission duration.", "longDescription": "This value defines the default cruising speed for multi-rotor vehicles for use in calculating mission statistics. It does not modify the flight speed for a specific flight plan.",
"type": "double", "type": "double",
"defaultValue": 5.0, "defaultValue": 5.0,
"min": 1.0, "min": 1.0,
......
...@@ -338,16 +338,24 @@ void TerrainTileManager::addCoordinateQuery(TerrainOfflineAirMapQuery* terrainQu ...@@ -338,16 +338,24 @@ void TerrainTileManager::addCoordinateQuery(TerrainOfflineAirMapQuery* terrainQu
qCDebug(TerrainQueryLog) << "TerrainTileManager::addCoordinateQuery count" << coordinates.count(); qCDebug(TerrainQueryLog) << "TerrainTileManager::addCoordinateQuery count" << coordinates.count();
if (coordinates.length() > 0) { if (coordinates.length() > 0) {
bool error;
QList<double> altitudes; QList<double> altitudes;
if (!_getAltitudesForCoordinates(coordinates, altitudes)) { if (!_getAltitudesForCoordinates(coordinates, altitudes, error)) {
qCDebug(TerrainQueryLog) << "TerrainTileManager::addPathQuery queue count" << _requestQueue.count();
QueuedRequestInfo_t queuedRequestInfo = { terrainQueryInterface, QueryMode::QueryModeCoordinates, 0, 0, coordinates }; QueuedRequestInfo_t queuedRequestInfo = { terrainQueryInterface, QueryMode::QueryModeCoordinates, 0, 0, coordinates };
_requestQueue.append(queuedRequestInfo); _requestQueue.append(queuedRequestInfo);
return; return;
} }
qCDebug(TerrainQueryLog) << "All altitudes taken from cached data"; if (error) {
terrainQueryInterface->_signalCoordinateHeights(coordinates.count() == altitudes.count(), altitudes); QList<double> noAltitudes;
qCWarning(TerrainQueryLog) << "addCoordinateQuery: signalling failure due to internal error";
terrainQueryInterface->_signalCoordinateHeights(false, noAltitudes);
} else {
qCDebug(TerrainQueryLog) << "addCoordinateQuery: All altitudes taken from cached data";
terrainQueryInterface->_signalCoordinateHeights(coordinates.count() == altitudes.count(), altitudes);
}
} }
} }
...@@ -370,28 +378,56 @@ void TerrainTileManager::addPathQuery(TerrainOfflineAirMapQuery* terrainQueryInt ...@@ -370,28 +378,56 @@ void TerrainTileManager::addPathQuery(TerrainOfflineAirMapQuery* terrainQueryInt
qCDebug(TerrainQueryLog) << "TerrainTileManager::addPathQuery start:end:coordCount" << startPoint << endPoint << coordinates.count(); qCDebug(TerrainQueryLog) << "TerrainTileManager::addPathQuery start:end:coordCount" << startPoint << endPoint << coordinates.count();
bool error;
QList<double> altitudes; QList<double> altitudes;
if (!_getAltitudesForCoordinates(coordinates, altitudes)) { if (!_getAltitudesForCoordinates(coordinates, altitudes, error)) {
qCDebug(TerrainQueryLog) << "TerrainTileManager::addPathQuery queue count" << _requestQueue.count();
QueuedRequestInfo_t queuedRequestInfo = { terrainQueryInterface, QueryMode::QueryModePath, latStep, lonStep, coordinates }; QueuedRequestInfo_t queuedRequestInfo = { terrainQueryInterface, QueryMode::QueryModePath, latStep, lonStep, coordinates };
_requestQueue.append(queuedRequestInfo); _requestQueue.append(queuedRequestInfo);
return; return;
} }
qCDebug(TerrainQueryLog) << "All altitudes taken from cached data"; if (error) {
terrainQueryInterface->_signalPathHeights(coordinates.count() == altitudes.count(), latStep, lonStep, altitudes); QList<double> noAltitudes;
qCWarning(TerrainQueryLog) << "addPathQuery: signalling failure due to internal error";
terrainQueryInterface->_signalPathHeights(false, latStep, lonStep, noAltitudes);
} else {
qCDebug(TerrainQueryLog) << "addPathQuery: All altitudes taken from cached data";
terrainQueryInterface->_signalPathHeights(coordinates.count() == altitudes.count(), latStep, lonStep, altitudes);
}
} }
bool TerrainTileManager::_getAltitudesForCoordinates(const QList<QGeoCoordinate>& coordinates, QList<double>& altitudes) /// Either returns altitudes from cache or queues database request
/// @param[out] error true: altitude not returned due to error, false: altitudes returned
/// @return true: altitude returned (check error as well), false: database query queued (altitudes not returned)
bool TerrainTileManager::_getAltitudesForCoordinates(const QList<QGeoCoordinate>& coordinates, QList<double>& altitudes, bool& error)
{ {
error = false;
foreach (const QGeoCoordinate& coordinate, coordinates) { foreach (const QGeoCoordinate& coordinate, coordinates) {
QString tileHash = _getTileHash(coordinate); QString tileHash = _getTileHash(coordinate);
_tilesMutex.lock(); qCDebug(TerrainQueryLog) << "TerrainTileManager::_getAltitudesForCoordinates hash:coordinate" << tileHash << coordinate;
if (!_tiles.contains(tileHash)) {
qCDebug(TerrainQueryLog) << "Need to download tile " << tileHash;
// Schedule the fetch task _tilesMutex.lock();
if (_tiles.contains(tileHash)) {
if (_tiles[tileHash].isIn(coordinate)) {
double elevation = _tiles[tileHash].elevation(coordinate);
if (qIsNaN(elevation)) {
error = true;
qCWarning(TerrainQueryLog) << "TerrainTileManager::_getAltitudesForCoordinates Internal Error: negative elevation in tile cache";
} else {
qCWarning(TerrainQueryLog) << "TerrainTileManager::_getAltitudesForCoordinates returning elevation from tile cache" << elevation;
}
altitudes.push_back(elevation);
} else {
qCWarning(TerrainQueryLog) << "TerrainTileManager::_getAltitudesForCoordinates Internal Error: coordinate not in tile region";
altitudes.push_back(qQNaN());
error = true;
}
} else {
if (_state != State::Downloading) { if (_state != State::Downloading) {
QNetworkRequest request = getQGCMapEngine()->urlFactory()->getTileURL(UrlFactory::AirmapElevation, QGCMapEngine::long2elevationTileX(coordinate.longitude(), 1), QGCMapEngine::lat2elevationTileY(coordinate.latitude(), 1), 1, &_networkManager); QNetworkRequest request = getQGCMapEngine()->urlFactory()->getTileURL(UrlFactory::AirmapElevation, QGCMapEngine::long2elevationTileX(coordinate.longitude(), 1), QGCMapEngine::lat2elevationTileY(coordinate.latitude(), 1), 1, &_networkManager);
qCDebug(TerrainQueryLog) << "TerrainTileManager::_getAltitudesForCoordinates query from database" << request.url();
QGeoTileSpec spec; QGeoTileSpec spec;
spec.setX(QGCMapEngine::long2elevationTileX(coordinate.longitude(), 1)); spec.setX(QGCMapEngine::long2elevationTileX(coordinate.longitude(), 1));
spec.setY(QGCMapEngine::lat2elevationTileY(coordinate.latitude(), 1)); spec.setY(QGCMapEngine::lat2elevationTileY(coordinate.latitude(), 1));
...@@ -404,16 +440,10 @@ bool TerrainTileManager::_getAltitudesForCoordinates(const QList<QGeoCoordinate> ...@@ -404,16 +440,10 @@ bool TerrainTileManager::_getAltitudesForCoordinates(const QList<QGeoCoordinate>
_tilesMutex.unlock(); _tilesMutex.unlock();
return false; return false;
} else {
if (_tiles[tileHash].isIn(coordinate)) {
altitudes.push_back(_tiles[tileHash].elevation(coordinate));
} else {
qCWarning(TerrainQueryLog) << "Error: coordinate not in tile region";
altitudes.push_back(-1.0);
}
} }
_tilesMutex.unlock(); _tilesMutex.unlock();
} }
return true; return true;
} }
...@@ -477,14 +507,29 @@ void TerrainTileManager::_terrainDone(QByteArray responseBytes, QNetworkReply::N ...@@ -477,14 +507,29 @@ void TerrainTileManager::_terrainDone(QByteArray responseBytes, QNetworkReply::N
// now try to query the data again // now try to query the data again
for (int i = _requestQueue.count() - 1; i >= 0; i--) { for (int i = _requestQueue.count() - 1; i >= 0; i--) {
bool error;
QList<double> altitudes; QList<double> altitudes;
QueuedRequestInfo_t& requestInfo = _requestQueue[i]; QueuedRequestInfo_t& requestInfo = _requestQueue[i];
if (_getAltitudesForCoordinates(requestInfo.coordinates, altitudes)) { if (_getAltitudesForCoordinates(requestInfo.coordinates, altitudes, error)) {
if (requestInfo.queryMode == QueryMode::QueryModeCoordinates) { if (requestInfo.queryMode == QueryMode::QueryModeCoordinates) {
requestInfo.terrainQueryInterface->_signalCoordinateHeights(requestInfo.coordinates.count() == altitudes.count(), altitudes); if (error) {
QList<double> noAltitudes;
qCWarning(TerrainQueryLog) << "_terrainDone(coordinateQuery): signalling failure due to internal error";
requestInfo.terrainQueryInterface->_signalCoordinateHeights(false, noAltitudes);
} else {
qCDebug(TerrainQueryLog) << "_terrainDone(coordinateQuery): All altitudes taken from cached data";
requestInfo.terrainQueryInterface->_signalCoordinateHeights(requestInfo.coordinates.count() == altitudes.count(), altitudes);
}
} else if (requestInfo.queryMode == QueryMode::QueryModePath) { } else if (requestInfo.queryMode == QueryMode::QueryModePath) {
requestInfo.terrainQueryInterface->_signalPathHeights(requestInfo.coordinates.count() == altitudes.count(), requestInfo.latStep, requestInfo.lonStep, altitudes); if (error) {
QList<double> noAltitudes;
qCWarning(TerrainQueryLog) << "_terrainDone(coordinateQuery): signalling failure due to internal error";
requestInfo.terrainQueryInterface->_signalPathHeights(false, requestInfo.latStep, requestInfo.lonStep, noAltitudes);
} else {
qCDebug(TerrainQueryLog) << "_terrainDone(coordinateQuery): All altitudes taken from cached data";
requestInfo.terrainQueryInterface->_signalPathHeights(requestInfo.coordinates.count() == altitudes.count(), requestInfo.latStep, requestInfo.lonStep, altitudes);
}
} }
_requestQueue.removeAt(i); _requestQueue.removeAt(i);
} }
...@@ -525,7 +570,7 @@ void TerrainAtCoordinateBatchManager::_sendNextBatch(void) ...@@ -525,7 +570,7 @@ void TerrainAtCoordinateBatchManager::_sendNextBatch(void)
if (_state != State::Idle) { if (_state != State::Idle) {
// Waiting for last download the complete, wait some more // Waiting for last download the complete, wait some more
qCDebug(TerrainQueryLog) << "_sendNextBatch restarting timer"; qCDebug(TerrainQueryLog) << "TerrainAtCoordinateBatchManager::_sendNextBatch waiting for current batch, restarting timer";
_batchTimer.start(); _batchTimer.start();
return; return;
} }
...@@ -549,7 +594,7 @@ void TerrainAtCoordinateBatchManager::_sendNextBatch(void) ...@@ -549,7 +594,7 @@ void TerrainAtCoordinateBatchManager::_sendNextBatch(void)
} }
} }
_requestQueue = _requestQueue.mid(requestQueueAdded); _requestQueue = _requestQueue.mid(requestQueueAdded);
qCDebug(TerrainQueryLog) << "_sendNextBatch - batch count:request queue count" << coords.count() << _requestQueue.count(); qCDebug(TerrainQueryLog) << "TerrainAtCoordinateBatchManager::_sendNextBatch requesting next batch _state:_requestQueue.count:_sentRequests.count" << _stateToString(_state) << _requestQueue.count() << _sentRequests.count();
_state = State::Downloading; _state = State::Downloading;
_terrainQuery.requestCoordinateHeights(coords); _terrainQuery.requestCoordinateHeights(coords);
...@@ -610,7 +655,7 @@ void TerrainAtCoordinateBatchManager::_coordinateHeights(bool success, QList<dou ...@@ -610,7 +655,7 @@ void TerrainAtCoordinateBatchManager::_coordinateHeights(bool success, QList<dou
{ {
_state = State::Idle; _state = State::Idle;
qCDebug(TerrainQueryLog) << "TerrainAtCoordinateBatchManager::_coordinateHeights success:count" << success << heights.count(); qCDebug(TerrainQueryLog) << "TerrainAtCoordinateBatchManager::_coordinateHeights signalled success:count" << success << heights.count();
if (!success) { if (!success) {
_batchFailed(); _batchFailed();
......
...@@ -140,9 +140,9 @@ private: ...@@ -140,9 +140,9 @@ private:
QList<QGeoCoordinate> coordinates; QList<QGeoCoordinate> coordinates;
} QueuedRequestInfo_t; } QueuedRequestInfo_t;
void _tileFailed(void); void _tileFailed (void);
bool _getAltitudesForCoordinates(const QList<QGeoCoordinate>& coordinates, QList<double>& altitudes); bool _getAltitudesForCoordinates (const QList<QGeoCoordinate>& coordinates, QList<double>& altitudes, bool& error);
QString _getTileHash(const QGeoCoordinate& coordinate); /// Method to create a unique string for each tile QString _getTileHash (const QGeoCoordinate& coordinate);
QList<QueuedRequestInfo_t> _requestQueue; QList<QueuedRequestInfo_t> _requestQueue;
State _state = State::Idle; State _state = State::Idle;
......
...@@ -53,88 +53,57 @@ TerrainTile::TerrainTile(QByteArray byteArray) ...@@ -53,88 +53,57 @@ TerrainTile::TerrainTile(QByteArray byteArray)
, _gridSizeLon(-1) , _gridSizeLon(-1)
, _isValid(false) , _isValid(false)
{ {
QDataStream stream(byteArray); int cTileHeaderBytes = static_cast<int>(sizeof(TileInfo_t));
int cTileBytesAvailable = byteArray.size();
float lat,lon; if (cTileBytesAvailable < cTileHeaderBytes) {
if (stream.atEnd()) { qWarning() << "Terrain tile binary data too small for TileInfo_s header";
qWarning() << "Terrain tile binary data does not contain all data";
return; return;
} }
stream >> lat;
if (stream.atEnd()) {
qWarning() << "Terrain tile binary data does not contain all data";
return;
}
stream >> lon;
_southWest.setLatitude(lat);
_southWest.setLongitude(lon);
if (stream.atEnd()) { const TileInfo_t* tileInfo = reinterpret_cast<const TileInfo_t*>(byteArray.constData());
qWarning() << "Terrain tile binary data does not contain all data"; _southWest.setLatitude(tileInfo->swLat);
return; _southWest.setLongitude(tileInfo->swLon);
} _northEast.setLatitude(tileInfo->neLat);
stream >> lat; _northEast.setLongitude(tileInfo->neLon);
if (stream.atEnd()) { _minElevation = tileInfo->minElevation;
qWarning() << "Terrain tile binary data does not contain all data"; _maxElevation = tileInfo->maxElevation;
return; _avgElevation = tileInfo->avgElevation;
} _gridSizeLat = tileInfo->gridSizeLat;
stream >> lon; _gridSizeLon = tileInfo->gridSizeLon;
_northEast.setLatitude(lat);
_northEast.setLongitude(lon);
if (stream.atEnd()) { qCDebug(TerrainTileLog) << "Loading terrain tile: " << _southWest << " - " << _northEast;
qWarning() << "Terrain tile binary data does not contain all data"; qCDebug(TerrainTileLog) << "min:max:avg:sizeLat:sizeLon" << _minElevation << _maxElevation << _avgElevation << _gridSizeLat << _gridSizeLon;
return;
} int cTileDataBytes = static_cast<int>(sizeof(int16_t)) * _gridSizeLat * _gridSizeLon;
stream >> _minElevation; if (cTileBytesAvailable < cTileHeaderBytes + cTileDataBytes) {
if (stream.atEnd()) { qWarning() << "Terrain tile binary data too small for tile data";
qWarning() << "Terrain tile binary data does not contain all data";
return;
}
stream >> _maxElevation;
if (stream.atEnd()) {
qWarning() << "Terrain tile binary data does not contain all data";
return;
}
stream >> _avgElevation;
if (stream.atEnd()) {
qWarning() << "Terrain tile binary data does not contain all data";
return;
}
stream >> _gridSizeLat;
if (stream.atEnd()) {
qWarning() << "Terrain tile binary data does not contain all data";
return; return;
} }
stream >> _gridSizeLon;
qCDebug(TerrainTileLog) << "Loading terrain tile: " << _southWest << " - " << _northEast; _data = new int16_t*[_gridSizeLat];
qCDebug(TerrainTileLog) << "min:max:avg:sizeLat:sizeLon" << _minElevation << _maxElevation << _avgElevation << _gridSizeLat << _gridSizeLon; for (int k = 0; k < _gridSizeLat; k++) {
_data[k] = new int16_t[_gridSizeLon];
}
int valueIndex = 0;
const int16_t* pTileData = reinterpret_cast<const int16_t*>(&reinterpret_cast<const uint8_t*>(byteArray.constData())[cTileHeaderBytes]);
for (int i = 0; i < _gridSizeLat; i++) { for (int i = 0; i < _gridSizeLat; i++) {
if (i == 0) {
_data = new int16_t*[_gridSizeLat];
for (int k = 0; k < _gridSizeLat; k++) {
_data[k] = new int16_t[_gridSizeLon];
}
}
for (int j = 0; j < _gridSizeLon; j++) { for (int j = 0; j < _gridSizeLon; j++) {
if (stream.atEnd()) { _data[i][j] = pTileData[valueIndex++];
qWarning() << "Terrain tile binary data does not contain all data";
return;
}
stream >> _data[i][j];
} }
} }
_isValid = true; _isValid = true;
return;
} }
bool TerrainTile::isIn(const QGeoCoordinate& coordinate) const bool TerrainTile::isIn(const QGeoCoordinate& coordinate) const
{ {
if (!_isValid) { if (!_isValid) {
qCDebug(TerrainTileLog) << "isIn requested, but tile not valid"; qCWarning(TerrainTileLog) << "isIn requested, but tile not valid";
return false; return false;
} }
bool ret = coordinate.latitude() >= _southWest.latitude() && coordinate.longitude() >= _southWest.longitude() && bool ret = coordinate.latitude() >= _southWest.latitude() && coordinate.longitude() >= _southWest.longitude() &&
...@@ -152,13 +121,13 @@ double TerrainTile::elevation(const QGeoCoordinate& coordinate) const ...@@ -152,13 +121,13 @@ double TerrainTile::elevation(const QGeoCoordinate& coordinate) const
int indexLon = _lonToDataIndex(coordinate.longitude()); int indexLon = _lonToDataIndex(coordinate.longitude());
if (indexLat == -1 || indexLon == -1) { if (indexLat == -1 || indexLon == -1) {
qCWarning(TerrainTileLog) << "Internal error indexLat:indexLon == -1" << indexLat << indexLon; qCWarning(TerrainTileLog) << "Internal error indexLat:indexLon == -1" << indexLat << indexLon;
return -1.0; return qQNaN();
} }
qCDebug(TerrainTileLog) << "indexLat:indexLon" << indexLat << indexLon << "elevation" << _data[indexLat][indexLon]; qCDebug(TerrainTileLog) << "indexLat:indexLon" << indexLat << indexLon << "elevation" << _data[indexLat][indexLon];
return static_cast<double>(_data[indexLat][indexLon]); return static_cast<double>(_data[indexLat][indexLon]);
} else { } else {
qCDebug(TerrainTileLog) << "Asking for elevation, but no valid data."; qCWarning(TerrainTileLog) << "Asking for elevation, but no valid data.";
return -1.0; return qQNaN();
} }
} }
...@@ -176,8 +145,6 @@ QByteArray TerrainTile::serialize(QByteArray input) ...@@ -176,8 +145,6 @@ QByteArray TerrainTile::serialize(QByteArray input)
return emptyArray; return emptyArray;
} }
QByteArray byteArray;
QDataStream stream(&byteArray, QIODevice::WriteOnly);
if (!document.isObject()) { if (!document.isObject()) {
qCDebug(TerrainTileLog) << "Terrain tile json doc is no object"; qCDebug(TerrainTileLog) << "Terrain tile json doc is no object";
QByteArray emptyArray; QByteArray emptyArray;
...@@ -231,10 +198,6 @@ QByteArray TerrainTile::serialize(QByteArray input) ...@@ -231,10 +198,6 @@ QByteArray TerrainTile::serialize(QByteArray input)
QByteArray emptyArray; QByteArray emptyArray;
return emptyArray; return emptyArray;
} }
stream << static_cast<float>(swArray[0].toDouble());
stream << static_cast<float>(swArray[1].toDouble());
stream << static_cast<float>(neArray[0].toDouble());
stream << static_cast<float>(neArray[1].toDouble());
// Stats // Stats
const QJsonObject& statsObject = dataObject[_jsonStatsKey].toObject(); const QJsonObject& statsObject = dataObject[_jsonStatsKey].toObject();
...@@ -248,30 +211,46 @@ QByteArray TerrainTile::serialize(QByteArray input) ...@@ -248,30 +211,46 @@ QByteArray TerrainTile::serialize(QByteArray input)
QByteArray emptyArray; QByteArray emptyArray;
return emptyArray; return emptyArray;
} }
stream << static_cast<int16_t>(statsObject[_jsonMinElevationKey].toInt());
stream << static_cast<int16_t>(statsObject[_jsonMaxElevationKey].toInt());
stream << static_cast<float>(statsObject[_jsonAvgElevationKey].toDouble());
// Carpet // Carpet
const QJsonArray& carpetArray = dataObject[_jsonCarpetKey].toArray(); const QJsonArray& carpetArray = dataObject[_jsonCarpetKey].toArray();
int gridSizeLat = carpetArray.count(); int gridSizeLat = carpetArray.count();
stream << static_cast<int16_t>(gridSizeLat); int gridSizeLon = carpetArray[0].toArray().count();
int gridSizeLon = 0; qCDebug(TerrainTileLog) << "Received tile has size in latitude direction: " << gridSizeLat;
qCDebug(TerrainTileLog) << "Received tile has size in latitude direction: " << carpetArray.count(); qCDebug(TerrainTileLog) << "Received tile has size in longitued direction: " << gridSizeLon;
TileInfo_t tileInfo;
tileInfo.swLat = swArray[0].toDouble();
tileInfo.swLon = swArray[1].toDouble();
tileInfo.neLat = neArray[0].toDouble();
tileInfo.neLon = neArray[1].toDouble();
tileInfo.minElevation = static_cast<int16_t>(statsObject[_jsonMinElevationKey].toInt());
tileInfo.maxElevation = static_cast<int16_t>(statsObject[_jsonMaxElevationKey].toInt());
tileInfo.avgElevation = statsObject[_jsonAvgElevationKey].toDouble();
tileInfo.gridSizeLat = static_cast<int16_t>(gridSizeLat);
tileInfo.gridSizeLon = static_cast<int16_t>(gridSizeLon);
int cTileHeaderBytes = static_cast<int>(sizeof(TileInfo_t));
int cTileDataBytes = static_cast<int>(sizeof(int16_t)) * gridSizeLat * gridSizeLon;
QByteArray byteArray(cTileHeaderBytes + cTileDataBytes, 0);
TileInfo_t* pTileInfo = reinterpret_cast<TileInfo_t*>(byteArray.data());
int16_t* pTileData = reinterpret_cast<int16_t*>(&reinterpret_cast<uint8_t*>(byteArray.data())[cTileHeaderBytes]);
*pTileInfo = tileInfo;
int valueIndex = 0;
for (int i = 0; i < gridSizeLat; i++) { for (int i = 0; i < gridSizeLat; i++) {
const QJsonArray& row = carpetArray[i].toArray(); const QJsonArray& row = carpetArray[i].toArray();
if (i == 0) {
gridSizeLon = row.count();
stream << static_cast<int16_t>(gridSizeLon);
qCDebug(TerrainTileLog) << "Received tile has size in longitued direction: " << row.count();
}
if (row.count() < gridSizeLon) { if (row.count() < gridSizeLon) {
qCDebug(TerrainTileLog) << "Expected row array of " << gridSizeLon << ", instead got " << row.count(); qCDebug(TerrainTileLog) << "Expected row array of " << gridSizeLon << ", instead got " << row.count();
QByteArray emptyArray; QByteArray emptyArray;
return emptyArray; return emptyArray;
} }
for (int j = 0; j < gridSizeLon; j++) { for (int j = 0; j < gridSizeLon; j++) {
stream << static_cast<int16_t>(row[j].toDouble()); pTileData[valueIndex++] = static_cast<int16_t>(row[j].toDouble());
} }
} }
...@@ -284,6 +263,7 @@ int TerrainTile::_latToDataIndex(double latitude) const ...@@ -284,6 +263,7 @@ int TerrainTile::_latToDataIndex(double latitude) const
if (isValid() && _southWest.isValid() && _northEast.isValid()) { if (isValid() && _southWest.isValid() && _northEast.isValid()) {
return qRound((latitude - _southWest.latitude()) / (_northEast.latitude() - _southWest.latitude()) * (_gridSizeLat - 1)); return qRound((latitude - _southWest.latitude()) / (_northEast.latitude() - _southWest.latitude()) * (_gridSizeLat - 1));
} else { } else {
qCWarning(TerrainTileLog) << "TerrainTile::_latToDataIndex internal error" << isValid() << _southWest.isValid() << _northEast.isValid();
return -1; return -1;
} }
} }
...@@ -293,6 +273,7 @@ int TerrainTile::_lonToDataIndex(double longitude) const ...@@ -293,6 +273,7 @@ int TerrainTile::_lonToDataIndex(double longitude) const
if (isValid() && _southWest.isValid() && _northEast.isValid()) { if (isValid() && _southWest.isValid() && _northEast.isValid()) {
return qRound((longitude - _southWest.longitude()) / (_northEast.longitude() - _southWest.longitude()) * (_gridSizeLon - 1)); return qRound((longitude - _southWest.longitude()) / (_northEast.longitude() - _southWest.longitude()) * (_gridSizeLon - 1));
} else { } else {
qCWarning(TerrainTileLog) << "TerrainTile::_lonToDataIndex internal error" << isValid() << _southWest.isValid() << _northEast.isValid();
return -1; return -1;
} }
} }
...@@ -95,6 +95,15 @@ public: ...@@ -95,6 +95,15 @@ public:
static constexpr double terrainAltitudeSpacing = 30.0; static constexpr double terrainAltitudeSpacing = 30.0;
private: private:
typedef struct {
double swLat,swLon, neLat, neLon;
int16_t minElevation;
int16_t maxElevation;
double avgElevation;
int16_t gridSizeLat;
int16_t gridSizeLon;
} TileInfo_t;
inline int _latToDataIndex(double latitude) const; inline int _latToDataIndex(double latitude) const;
inline int _lonToDataIndex(double longitude) const; inline int _lonToDataIndex(double longitude) const;
...@@ -103,7 +112,7 @@ private: ...@@ -103,7 +112,7 @@ private:
int16_t _minElevation; /// Minimum elevation in tile int16_t _minElevation; /// Minimum elevation in tile
int16_t _maxElevation; /// Maximum elevation in tile int16_t _maxElevation; /// Maximum elevation in tile
float _avgElevation; /// Average elevation of the tile double _avgElevation; /// Average elevation of the tile
int16_t** _data; /// 2D elevation data array int16_t** _data; /// 2D elevation data array
int16_t _gridSizeLat; /// data grid size in latitude direction int16_t _gridSizeLat; /// data grid size in latitude direction
......
...@@ -1259,6 +1259,10 @@ void Vehicle::_handleWindCov(mavlink_message_t& message) ...@@ -1259,6 +1259,10 @@ void Vehicle::_handleWindCov(mavlink_message_t& message)
float direction = qRadiansToDegrees(qAtan2(wind.wind_y, wind.wind_x)); float direction = qRadiansToDegrees(qAtan2(wind.wind_y, wind.wind_x));
float speed = qSqrt(qPow(wind.wind_x, 2) + qPow(wind.wind_y, 2)); float speed = qSqrt(qPow(wind.wind_x, 2) + qPow(wind.wind_y, 2));
if (direction < 0) {
direction += 360;
}
_windFactGroup.direction()->setRawValue(direction); _windFactGroup.direction()->setRawValue(direction);
_windFactGroup.speed()->setRawValue(speed); _windFactGroup.speed()->setRawValue(speed);
_windFactGroup.verticalSpeed()->setRawValue(0); _windFactGroup.verticalSpeed()->setRawValue(0);
......
...@@ -33,6 +33,7 @@ public: ...@@ -33,6 +33,7 @@ public:
, pOfflineMaps (NULL) , pOfflineMaps (NULL)
, pMAVLink (NULL) , pMAVLink (NULL)
, pConsole (NULL) , pConsole (NULL)
, pHelp (NULL)
#if defined(QT_DEBUG) #if defined(QT_DEBUG)
, pMockLink (NULL) , pMockLink (NULL)
, pDebug (NULL) , pDebug (NULL)
...@@ -73,6 +74,7 @@ public: ...@@ -73,6 +74,7 @@ public:
QmlComponentInfo* pOfflineMaps; QmlComponentInfo* pOfflineMaps;
QmlComponentInfo* pMAVLink; QmlComponentInfo* pMAVLink;
QmlComponentInfo* pConsole; QmlComponentInfo* pConsole;
QmlComponentInfo* pHelp;
#if defined(QT_DEBUG) #if defined(QT_DEBUG)
QmlComponentInfo* pMockLink; QmlComponentInfo* pMockLink;
QmlComponentInfo* pDebug; QmlComponentInfo* pDebug;
...@@ -135,6 +137,9 @@ QVariantList &QGCCorePlugin::settingsPages() ...@@ -135,6 +137,9 @@ QVariantList &QGCCorePlugin::settingsPages()
_p->pConsole = new QmlComponentInfo(tr("Console"), _p->pConsole = new QmlComponentInfo(tr("Console"),
QUrl::fromUserInput("qrc:/qml/QGroundControl/Controls/AppMessages.qml")); QUrl::fromUserInput("qrc:/qml/QGroundControl/Controls/AppMessages.qml"));
_p->settingsList.append(QVariant::fromValue((QmlComponentInfo*)_p->pConsole)); _p->settingsList.append(QVariant::fromValue((QmlComponentInfo*)_p->pConsole));
_p->pHelp = new QmlComponentInfo(tr("Help"),
QUrl::fromUserInput("qrc:/qml/HelpSettings.qml"));
_p->settingsList.append(QVariant::fromValue((QmlComponentInfo*)_p->pHelp));
#if defined(QT_DEBUG) #if defined(QT_DEBUG)
//-- These are always present on Debug builds //-- These are always present on Debug builds
_p->pMockLink = new QmlComponentInfo(tr("Mock Link"), _p->pMockLink = new QmlComponentInfo(tr("Mock Link"),
......
/****************************************************************************
*
* (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.
*
****************************************************************************/
import QtQuick 2.3
import QtQuick.Layouts 1.11
import QGroundControl 1.0
import QGroundControl.Controls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
Rectangle {
color: qgcPal.window
anchors.fill: parent
readonly property real _margins: ScreenTools.defaultFontPixelHeight
QGCPalette { id: qgcPal; colorGroupEnabled: true }
QGCFlickable {
anchors.margins: _margins
anchors.fill: parent
contentWidth: grid.width
contentHeight: grid.height
clip: true
GridLayout {
id: grid
columns: 2
QGCLabel { text: qsTr("QGroundControl User Guide") }
QGCLabel {
linkColor: qgcPal.text
text: "<a href=\"https://docs.qgroundcontrol.com\">https://docs.qgroundcontrol.com</a>"
onLinkActivated: Qt.openUrlExternally(link)
}
QGCLabel { text: qsTr("PX4 Users Discussion Forum") }
QGCLabel {
linkColor: qgcPal.text
text: "<a href=\"http://discuss.px4.io/c/qgroundcontrol\">http://discuss.px4.io/c/qgroundcontrol</a>"
onLinkActivated: Qt.openUrlExternally(link)
}
QGCLabel { text: qsTr("ArduPilot Users Discussion Forum") }
QGCLabel {
linkColor: qgcPal.text
text: "<a href=\"https://discuss.ardupilot.org/c/ground-control-software/qgroundcontrol\">https://discuss.ardupilot.org/c/ground-control-software/qgroundcontrol</a>"
onLinkActivated: Qt.openUrlExternally(link)
}
}
}
}
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