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
exit 1
fi
#-- 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
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
mkdir -p ${SHADOW_BUILD_DIR} &&
cd ${SHADOW_BUILD_DIR} &&
......
......@@ -39,6 +39,7 @@
<file alias="GeneralSettings.qml">src/ui/preferences/GeneralSettings.qml</file>
<file alias="GeoTagPage.qml">src/AnalyzeView/GeoTagPage.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="LinkSettings.qml">src/ui/preferences/LinkSettings.qml</file>
<file alias="LogDownloadPage.qml">src/AnalyzeView/LogDownloadPage.qml</file>
......
......@@ -122,6 +122,9 @@ QString AudioOutput::fixTextMessageForAudio(const QString& string) {
if(result.contains(" EKF ", 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
QRegularExpression re(QStringLiteral("(-)[0-9]*\\.?[0-9]"));
......
......@@ -128,9 +128,7 @@ SetupPage {
onWaitingForCancelChanged: {
if (controller.waitingForCancel) {
showMessage(qsTr("Calibration Cancel"), qsTr("Waiting for Vehicle to response to Cancel. This may take a few seconds."), 0)
} else {
hideDialog()
showDialog(waitForCancelDialogComponent, qsTr("Calibration Cancel"), qgcView.showDialogDefaultWidth, 0)
}
}
......@@ -163,6 +161,24 @@ SetupPage {
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 {
id: singleCompassOnboardResultsComponent
......@@ -265,7 +281,10 @@ SetupPage {
QGCButton {
text: qsTr("Reboot Vehicle")
onClicked: controller.vehicle.reboot()
onClicked: {
controller.vehicle.rebootVehicle()
hideDialog()
}
}
}
}
......@@ -290,8 +309,11 @@ SetupPage {
QGCButton {
text: qsTr("Reboot Vehicle")
onClicked: controller.vehicle.rebootVehicle()
}
onClicked: {
controller.vehicle.rebootVehicle()
hideDialog()
}
}
}
}
}
......
......@@ -167,7 +167,7 @@ void SensorsComponentController::_stopCalibration(SensorsComponentController::St
emit resetStatusTextArea();
}
if (_magCalInProgress) {
emit setCompassRotations();
emit magCalComplete();
}
break;
......
......@@ -92,7 +92,7 @@ signals:
void orientationCalSidesRotateChanged(void);
void resetStatusTextArea(void);
void waitingForCancelChanged(void);
void setCompassRotations(void);
void magCalComplete(void);
private slots:
void _handleUASTextMessage(int uasId, int compId, int severity, QString text);
......
......@@ -131,11 +131,11 @@ Item {
onResetStatusTextArea: statusLog.text = statusTextAreaDefaultText
onSetCompassRotations: {
if (!_sensorsHaveFixedOrientation && (showCompass0Rot || showCompass1Rot || showCompass2Rot)) {
onMagCalComplete: {
//if (!_sensorsHaveFixedOrientation && (showCompass0Rot || showCompass1Rot || showCompass2Rot)) {
setOrientationsDialogShowBoardOrientation = false
showDialog(setOrientationsDialogComponent, qsTr("Set Compass Rotation(s)"), qgcView.showDialogDefaultWidth, StandardButton.Ok)
}
showDialog(setOrientationsDialogComponent, qsTr("Compass Calibration Complete"), qgcView.showDialogDefaultWidth, StandardButton.Ok)
//}
}
onWaitingForCancelChanged: {
......@@ -252,6 +252,20 @@ Item {
anchors.top: parent.top
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 {
width: parent.width
wrapMode: Text.WordWrap
......
......@@ -71,7 +71,8 @@ Rectangle {
id: editDialogComponent
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)
, _cPrevValues (0)
, _cNextValues (0)
, _initialValue (0)
, _initialValueRounded (0)
, _initialValueAtPrecision (0)
, _increment (0)
{
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
......@@ -47,14 +47,14 @@ int FactValueSliderListModel::resetInitialValue(void)
}
_initialValue = _fact.cookedValue().toDouble();
_initialValueRounded = qRound(_initialValue);
_initialValueAtPrecision = _valueAtPrecision(_initialValue);
if (qRound(_fact.rawIncrement()) == _fact.rawIncrement()) {
_increment = qRound(_fact.cookedIncrement());
} else {
_increment = _fact.cookedIncrement();
}
_cPrevValues = qMin((_initialValue - _fact.cookedMin().toDouble()), 100.0) / _increment;
_cNextValues = qMin((_fact.cookedMax().toDouble() - _initialValue), 100.0) / _increment;
_cPrevValues = qMin((_initialValue - _fact.cookedMin().toDouble()) / _increment, 100.0);
_cNextValues = qMin((_fact.cookedMax().toDouble() - _initialValue) / _increment, 100.0);
_initialValueIndex = _cPrevValues;
int totalValueCount = _cPrevValues + 1 + _cNextValues;
......@@ -93,12 +93,9 @@ QVariant FactValueSliderListModel::data(const QModelIndex &index, int role) cons
if (cIncrementCount == 0) {
value = _initialValue;
} else {
value = _initialValueRounded + (cIncrementCount * _increment);
value = initialValueAtPrecision() + (cIncrementCount * _increment);
}
double precision = qPow(10, _fact.decimalPlaces());
double atPrecision = qRound(value * precision) / precision;
//qDebug() << value << precision << atPrecision << _fact.decimalPlaces() << _fact.name();
return QVariant(atPrecision);
return QVariant(_valueAtPrecision(value));
} else if (role == _valueIndexRole) {
return QVariant::fromValue(valueIndex);
} else {
......@@ -129,8 +126,8 @@ int FactValueSliderListModel::valueIndexAtModelIndex(int index)
return data(createIndex(index, 0), _valueIndexRole).toInt();
}
double FactValueSliderListModel::initialValueAtPrecision(void)
double FactValueSliderListModel::_valueAtPrecision(double value) const
{
double precision = qPow(10, _fact.decimalPlaces());
return qRound(_initialValue * precision) / precision;
return qRound(value * precision) / precision;
}
......@@ -25,7 +25,7 @@ public:
/// The initial value of the Fact at the meta data specified decimal place precision
Q_PROPERTY(double initialValueAtPrecision READ initialValueAtPrecision NOTIFY initialValueAtPrecisionChanged)
double initialValueAtPrecision(void);
double initialValueAtPrecision(void) const { return _initialValueAtPrecision; }
Q_INVOKABLE int resetInitialValue(void);
Q_INVOKABLE double valueAtModelIndex(int index);
......@@ -35,6 +35,8 @@ signals:
void initialValueAtPrecisionChanged(void);
private:
double _valueAtPrecision(double value) const;
// Overrides from QAbstractListModel
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
......@@ -48,7 +50,7 @@ private:
int _cNextValues;
int _windowSize;
double _initialValue;
double _initialValueRounded;
double _initialValueAtPrecision;
double _increment;
static const int _valueRole;
......
......@@ -505,6 +505,30 @@ const QVariantList& FirmwarePlugin::cameraList(const Vehicle* vehicle)
0, // minTriggerInterval
this);
_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;
......
......@@ -65,7 +65,7 @@ Item {
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.")
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 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.")
......
......@@ -65,7 +65,7 @@ Map {
}
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
const char* CameraCalc::_jsonCameraSpecTypeKey = "CameraSpecType";
CameraCalc::CameraCalc(Vehicle* vehicle, QString settingsGroup, QObject* parent)
: CameraSpec (parent)
CameraCalc::CameraCalc(Vehicle* vehicle, const QString& settingsGroup, QObject* parent)
: CameraSpec (settingsGroup, parent)
, _vehicle (vehicle)
, _dirty (false)
, _disableRecalc (false)
......
......@@ -19,7 +19,7 @@ class CameraCalc : public CameraSpec
Q_OBJECT
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 manualCameraName READ manualCameraName CONSTANT) ///< Camera name for manual camera setting
......
......@@ -21,38 +21,20 @@ const char* CameraSpec::_landscapeName = "Landscape";
const char* CameraSpec::_fixedOrientationName = "FixedOrientation";
const char* CameraSpec::_minTriggerIntervalName = "MinTriggerInterval";
CameraSpec::CameraSpec(QObject* parent)
CameraSpec::CameraSpec(const QString& settingsGroup, 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)
, _sensorWidthFact (settingsGroup, _metaDataMap[_sensorWidthName])
, _sensorHeightFact (settingsGroup, _metaDataMap[_sensorHeightName])
, _imageWidthFact (settingsGroup, _metaDataMap[_imageWidthName])
, _imageHeightFact (settingsGroup, _metaDataMap[_imageHeightName])
, _focalLengthFact (settingsGroup, _metaDataMap[_focalLengthName])
, _landscapeFact (settingsGroup, _metaDataMap[_landscapeName])
, _fixedOrientationFact (settingsGroup, _metaDataMap[_fixedOrientationName])
, _minTriggerIntervalFact (settingsGroup, _metaDataMap[_minTriggerIntervalName])
{
_init(true);
}
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;
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
}
const CameraSpec& CameraSpec::operator=(const CameraSpec& other)
......@@ -69,20 +51,6 @@ const CameraSpec& CameraSpec::operator=(const CameraSpec& other)
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)
{
if (_dirty != dirty) {
......
......@@ -9,15 +9,14 @@
#pragma once
#include "Fact.h"
#include "SettingsFact.h"
class CameraSpec : public QObject
{
Q_OBJECT
public:
CameraSpec(QObject* parent = NULL);
CameraSpec(const CameraSpec& other, QObject* parent);
CameraSpec(const QString& settingsGroup, QObject* parent = NULL);
const CameraSpec& operator=(const CameraSpec& other);
......@@ -31,14 +30,14 @@ public:
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
Fact* sensorWidth (void) { return &_sensorWidthFact; }
Fact* sensorHeight (void) { return &_sensorHeightFact; }
Fact* imageWidth (void) { return &_imageWidthFact; }
Fact* imageHeight (void) { return &_imageHeightFact; }
Fact* focalLength (void) { return &_focalLengthFact; }
Fact* landscape (void) { return &_landscapeFact; }
Fact* fixedOrientation (void) { return &_fixedOrientationFact; }
Fact* minTriggerInterval(void) { return &_minTriggerIntervalFact; }
SettingsFact* sensorWidth (void) { return &_sensorWidthFact; }
SettingsFact* sensorHeight (void) { return &_sensorHeightFact; }
SettingsFact* imageWidth (void) { return &_imageWidthFact; }
SettingsFact* imageHeight (void) { return &_imageHeightFact; }
SettingsFact* focalLength (void) { return &_focalLengthFact; }
SettingsFact* landscape (void) { return &_landscapeFact; }
SettingsFact* fixedOrientation (void) { return &_fixedOrientationFact; }
SettingsFact* minTriggerInterval(void) { return &_minTriggerIntervalFact; }
bool dirty (void) const { return _dirty; }
void setDirty (bool dirty);
......@@ -50,20 +49,18 @@ signals:
void dirtyChanged(bool dirty);
private:
void _init(bool setDefaults);
bool _dirty;
QMap<QString, FactMetaData*> _metaDataMap;
Fact _sensorWidthFact;
Fact _sensorHeightFact;
Fact _imageWidthFact;
Fact _imageHeightFact;
Fact _focalLengthFact;
Fact _landscapeFact;
Fact _fixedOrientationFact;
Fact _minTriggerIntervalFact;
SettingsFact _sensorWidthFact;
SettingsFact _sensorHeightFact;
SettingsFact _imageWidthFact;
SettingsFact _imageHeightFact;
SettingsFact _focalLengthFact;
SettingsFact _landscapeFact;
SettingsFact _fixedOrientationFact;
SettingsFact _minTriggerIntervalFact;
static const char* _sensorWidthName;
static const char* _sensorHeightName;
......
......@@ -225,7 +225,9 @@ bool FixedWingLandingComplexItem::load(const QJsonObject& complexObject, int seq
_landingCoordSet = true;
_ignoreRecalcSignals = false;
_recalcFromCoordinateChange();
emit coordinateChanged(this->coordinate()); // This will kick off terrain query
return true;
}
......
......@@ -123,7 +123,6 @@ Item {
_circle = false
}
/// Reset polygon to a circle which fits within initial polygon
function setCircleRadius(center, radius) {
var unboundCenter = center.atDistanceAndAzimuth(0, 0)
_circleRadius = radius
......@@ -231,7 +230,7 @@ Item {
MenuItem {
text: qsTr("Edit position..." )
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 {
......@@ -460,7 +459,8 @@ Item {
}
function setRadiusFromDialog() {
setCircleRadius(mapPolygon.center, radiusField.text)
var radius = QGroundControl.appSettingsDistanceUnitsToMeters(radiusField.text)
setCircleRadius(mapPolygon.center, radius)
_editCircleRadius = false
}
......@@ -484,7 +484,9 @@ Item {
QGCTextField {
id: radiusField
text: _circleRadius.toFixed(2)
showUnits: true
unitsLabel: QGroundControl.appSettingsDistanceUnitsString
text: QGroundControl.metersToAppSettingsDistanceUnits(_circleRadius).toFixed(2)
onEditingFinished: setRadiusFromDialog()
inputMethodHints: Qt.ImhFormattedNumbersOnly
}
......
......@@ -173,6 +173,10 @@ void VisualMissionItem::setMissionVehicleYaw(double vehicleYaw)
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()) {
// We use a timer so that any additional requests before the timer fires result in only a single request
_updateTerrainTimer.start();
......@@ -195,9 +199,7 @@ void VisualMissionItem::_reallyUpdateTerrainAltitude(void)
void VisualMissionItem::_terrainDataReceived(bool success, QList<double> heights)
{
if (success) {
_terrainAltitude = heights[0];
emit terrainAltitudeChanged(_terrainAltitude);
sender()->deleteLater();
}
_terrainAltitude = success ? heights[0] : qQNaN();
emit terrainAltitudeChanged(_terrainAltitude);
sender()->deleteLater();
}
......@@ -31,8 +31,12 @@ Rectangle {
//property real availableWidth ///< Width for control
//property var missionItem ///< Mission Item for editor
property real _margin: ScreenTools.defaultFontPixelWidth / 2
property real _spacer: ScreenTools.defaultFontPixelWidth / 2
property real _margin: 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 }
......@@ -45,34 +49,57 @@ Rectangle {
visible: missionItem.landingCoordSet
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 {
anchors.left: parent.left
anchors.right: parent.right
factList: [ missionItem.loiterAltitude, missionItem.loiterRadius ]
factLabels: [ qsTr("Altitude"), qsTr("Radius") ]
}
Item { width: 1; height: _spacer }
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 {
text: qsTr("Loiter clockwise")
checked: missionItem.loiterClockwise
onClicked: missionItem.loiterClockwise = checked
Item { width: 1; height: _spacer }
QGCCheckBox {
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 {
anchors.left: parent.left
anchors.right: parent.right
columns: 2
GridLayout {
anchors.left: parent.left
anchors.right: parent.right
columns: 2
QGCLabel { text: qsTr("Heading") }
......@@ -88,34 +115,42 @@ Rectangle {
fact: missionItem.landingAltitude
}
QGCRadioButton {
id: specifyLandingDistance
text: qsTr("Landing Dist")
checked: missionItem.valueSetIsDistance
exclusiveGroup: distanceGlideGroup
onClicked: missionItem.valueSetIsDistance = checked
Layout.fillWidth: true
}
QGCRadioButton {
id: specifyLandingDistance
text: qsTr("Landing Dist")
checked: missionItem.valueSetIsDistance
exclusiveGroup: distanceGlideGroup
onClicked: missionItem.valueSetIsDistance = checked
Layout.fillWidth: true
}
FactTextField {
fact: missionItem.landingDistance
enabled: specifyLandingDistance.checked
Layout.fillWidth: true
}
FactTextField {
fact: missionItem.landingDistance
enabled: specifyLandingDistance.checked
Layout.fillWidth: true
}
QGCRadioButton {
id: specifyGlideSlope
text: qsTr("Glide Slope")
checked: !missionItem.valueSetIsDistance
exclusiveGroup: distanceGlideGroup
onClicked: missionItem.valueSetIsDistance = !checked
Layout.fillWidth: true
}
QGCRadioButton {
id: specifyGlideSlope
text: qsTr("Glide Slope")
checked: !missionItem.valueSetIsDistance
exclusiveGroup: distanceGlideGroup
onClicked: missionItem.valueSetIsDistance = !checked
Layout.fillWidth: true
}
FactTextField {
fact: missionItem.glideSlope
enabled: specifyGlideSlope.checked
Layout.fillWidth: true
}
FactTextField {
fact: missionItem.glideSlope
enabled: specifyGlideSlope.checked
Layout.fillWidth: true
QGCButton {
text: _setToVehicleLocationStr
visible: _activeVehicle
Layout.columnSpan: 2
onClicked: missionItem.landingCoordinate = _activeVehicle.coordinate
}
}
}
......@@ -140,10 +175,30 @@ Rectangle {
spacing: ScreenTools.defaultFontPixelHeight
QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: qsTr("Click in map to set landing point.")
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
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 {
MenuItem {
text: qsTr("Change command...")
onTriggered: commandPicker.clicked()
visible: !_waypointsOnlyMode
visible: missionItem.isSimpleItem && !_waypointsOnlyMode
}
MenuItem {
text: qsTr("Edit position...")
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 {
......
......@@ -299,8 +299,13 @@ QGCView {
if (retList[0] == KMLFileHelper.Error) {
_qgcView.showMessage("Error", retList[1], StandardButton.Ok)
} else if (retList[0] == KMLFileHelper.Polygon) {
kmlPolygonSelectDialogKMLFile = file
_qgcView.showDialog(kmlPolygonSelectDialog, fileDialog.title, _qgcView.showDialogDefaultWidth, StandardButton.Ok | StandardButton.Cancel)
var editVehicle = _activeVehicle ? _activeVehicle : QGroundControl.multiVehicleManager.offlineEditingVehicle
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) {
insertComplexMissionItemFromKML(_missionController.corridorScanComplexItemName, file, -1)
}
......@@ -314,8 +319,6 @@ QGCView {
id: kmlPolygonSelectDialog
QGCViewDialog {
property var editVehicle: _activeVehicle ? _activeVehicle : QGroundControl.multiVehicleManager.offlineEditingVehicle
function accept() {
var complexItemName
if (surveyRadio.checked) {
......@@ -327,13 +330,6 @@ QGCView {
hideDialog()
}
Component.onCompleted: {
if (editVehicle.fixedWing) {
// Only Survey available
accept()
}
}
ExclusiveGroup {
id: radioGroup
}
......@@ -360,7 +356,6 @@ QGCView {
QGCRadioButton {
text: qsTr("Structure Scan")
exclusiveGroup: radioGroup
visible: !editVehicle.fixedWing
}
}
}
......
......@@ -74,17 +74,18 @@ Rectangle {
}
SectionHeader {
id: corridorHeader
id: transectsHeader
text: qsTr("Transects")
}
GridLayout {
id: transectsGrid
anchors.left: parent.left
anchors.right: parent.right
columnSpacing: _margin
rowSpacing: _margin
columns: 2
visible: corridorHeader.checked
visible: transectsHeader.checked
QGCLabel { text: qsTr("Angle") }
FactTextField {
......@@ -108,8 +109,8 @@ Rectangle {
QGCLabel { text: qsTr("Turnaround dist") }
FactTextField {
fact: missionItem.turnAroundDistance
Layout.fillWidth: true
fact: missionItem.turnAroundDistance
Layout.fillWidth: true
}
QGCButton {
......@@ -132,14 +133,14 @@ Rectangle {
}
FactCheckBox {
text: qsTr("Refly at 90 degree offset")
text: qsTr("Refly at 90 deg offset")
fact: missionItem.refly90Degrees
enabled: !missionItem.followTerrain
Layout.columnSpan: 2
}
FactCheckBox {
text: qsTr("Take images in turnarounds")
text: qsTr("Images in turnarounds")
fact: missionItem.cameraTriggerInTurnAround
enabled: missionItem.hoverAndCaptureAllowed ? !missionItem.hoverAndCapture.rawValue : true
Layout.columnSpan: 2
......
......@@ -33,6 +33,7 @@ QGCView {
property var _searchResults ///< List of parameter names from search results
property bool _showRCToParam: !ScreenTools.isMobile && QGroundControl.multiVehicleManager.activeVehicle.px4Firmware
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
property var _appSettings: QGroundControl.settingsManager.appSettings
ParameterEditorController {
id: controller;
......@@ -112,28 +113,18 @@ QGCView {
MenuItem {
text: qsTr("Load from file...")
onTriggered: {
var appSettings = QGroundControl.settingsManager.appSettings
fileDialog.qgcView = qgcView
fileDialog.title = qsTr("Select Parameter File")
fileDialog.title = qsTr("Load Parameters")
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()
}
}
MenuItem {
text: qsTr("Save to file...")
onTriggered: {
var appSettings = QGroundControl.settingsManager.appSettings
fileDialog.qgcView = qgcView
fileDialog.title = qsTr("Save Parameters")
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()
}
}
......@@ -292,7 +283,10 @@ QGCView {
} // QGCViewPanel
QGCFileDialog {
id: fileDialog
id: fileDialog
folder: _appSettings.parameterSavePath
fileExtension: _appSettings.parameterFileExtension
nameFilters: [ qsTr("Parameter Files (*.%1)").arg(_appSettings.parameterFileExtension) , qsTr("All Files (*.*)") ]
onAcceptedForSave: {
controller.saveToFile(file)
......
......@@ -98,10 +98,15 @@ void ParameterEditorController::clearRCToParam(void)
void ParameterEditorController::saveToFile(const QString& filename)
{
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)) {
qgcApp()->showMessage(tr("Unable to create file: %1").arg(filename));
qgcApp()->showMessage(tr("Unable to create file: %1").arg(parameterFilename));
return;
}
......
......@@ -27,6 +27,7 @@ QGCViewDialog {
property bool showRCToParam: false
property bool validate: false
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
......@@ -122,7 +123,7 @@ QGCViewDialog {
unitsLabel: fact.units
showUnits: fact.units != ""
Layout.fillWidth: true
focus: true
focus: setFocus
inputMethodHints: (fact.typeIsString || ScreenTools.isiOS) ?
Qt.ImhNone : // iOS numeric keyboard has no done button, we can't use it
Qt.ImhFormattedNumbersOnly // Forces use of virtual numeric keyboard
......
......@@ -20,9 +20,16 @@ import QGroundControl.Palette 1.0
QGCViewDialog {
property string message
QGCLabel {
QGCFlickable {
anchors.fill: parent
wrapMode: Text.WordWrap
text: message
contentHeight: label.contentHeight
QGCLabel {
id: label
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: message
}
}
}
......@@ -79,7 +79,7 @@ public:
EsriWorldSatellite = 7001,
EsriTerrain = 7002,
AirmapElevation = 8000
AirmapElevation = 8001
};
UrlFactory ();
......
......@@ -286,7 +286,12 @@ QGCView {
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 {
id: maxCacheMemSize
......@@ -297,6 +302,9 @@ QGCView {
}
QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
font.pointSize: _adjustableFontPointSize
text: qsTr("Memory cache changes require a restart to take effect.")
}
......@@ -310,6 +318,9 @@ QGCView {
width: ScreenTools.defaultFontPixelWidth * 30
}
QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: qsTr("To enable Mapbox maps, enter your access token.")
visible: _mapboxFact ? _mapboxFact.visible : false
font.pointSize: _adjustableFontPointSize
......@@ -324,6 +335,9 @@ QGCView {
width: ScreenTools.defaultFontPixelWidth * 30
}
QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: qsTr("To enable Esri maps, enter your access token.")
visible: _esriFact ? _esriFact.visible : false
font.pointSize: _adjustableFontPointSize
......
......@@ -18,7 +18,7 @@
{
"name": "OfflineEditingCruiseSpeed",
"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",
"defaultValue": 15.0,
"min": 1.0,
......@@ -28,7 +28,7 @@
{
"name": "OfflineEditingHoverSpeed",
"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",
"defaultValue": 5.0,
"min": 1.0,
......
......@@ -338,16 +338,24 @@ void TerrainTileManager::addCoordinateQuery(TerrainOfflineAirMapQuery* terrainQu
qCDebug(TerrainQueryLog) << "TerrainTileManager::addCoordinateQuery count" << coordinates.count();
if (coordinates.length() > 0) {
bool error;
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 };
_requestQueue.append(queuedRequestInfo);
return;
}
qCDebug(TerrainQueryLog) << "All altitudes taken from cached data";
terrainQueryInterface->_signalCoordinateHeights(coordinates.count() == altitudes.count(), altitudes);
if (error) {
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
qCDebug(TerrainQueryLog) << "TerrainTileManager::addPathQuery start:end:coordCount" << startPoint << endPoint << coordinates.count();
bool error;
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 };
_requestQueue.append(queuedRequestInfo);
return;
}
qCDebug(TerrainQueryLog) << "All altitudes taken from cached data";
terrainQueryInterface->_signalPathHeights(coordinates.count() == altitudes.count(), latStep, lonStep, altitudes);
if (error) {
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) {
QString tileHash = _getTileHash(coordinate);
_tilesMutex.lock();
if (!_tiles.contains(tileHash)) {
qCDebug(TerrainQueryLog) << "Need to download tile " << tileHash;
qCDebug(TerrainQueryLog) << "TerrainTileManager::_getAltitudesForCoordinates hash:coordinate" << tileHash << coordinate;
// 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) {
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;
spec.setX(QGCMapEngine::long2elevationTileX(coordinate.longitude(), 1));
spec.setY(QGCMapEngine::lat2elevationTileY(coordinate.latitude(), 1));
......@@ -404,16 +440,10 @@ bool TerrainTileManager::_getAltitudesForCoordinates(const QList<QGeoCoordinate>
_tilesMutex.unlock();
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();
}
return true;
}
......@@ -477,14 +507,29 @@ void TerrainTileManager::_terrainDone(QByteArray responseBytes, QNetworkReply::N
// now try to query the data again
for (int i = _requestQueue.count() - 1; i >= 0; i--) {
bool error;
QList<double> altitudes;
QueuedRequestInfo_t& requestInfo = _requestQueue[i];
if (_getAltitudesForCoordinates(requestInfo.coordinates, altitudes)) {
if (_getAltitudesForCoordinates(requestInfo.coordinates, altitudes, error)) {
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) {
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);
}
......@@ -525,7 +570,7 @@ void TerrainAtCoordinateBatchManager::_sendNextBatch(void)
if (_state != State::Idle) {
// 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();
return;
}
......@@ -549,7 +594,7 @@ void TerrainAtCoordinateBatchManager::_sendNextBatch(void)
}
}
_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;
_terrainQuery.requestCoordinateHeights(coords);
......@@ -610,7 +655,7 @@ void TerrainAtCoordinateBatchManager::_coordinateHeights(bool success, QList<dou
{
_state = State::Idle;
qCDebug(TerrainQueryLog) << "TerrainAtCoordinateBatchManager::_coordinateHeights success:count" << success << heights.count();
qCDebug(TerrainQueryLog) << "TerrainAtCoordinateBatchManager::_coordinateHeights signalled success:count" << success << heights.count();
if (!success) {
_batchFailed();
......
......@@ -140,9 +140,9 @@ private:
QList<QGeoCoordinate> coordinates;
} QueuedRequestInfo_t;
void _tileFailed(void);
bool _getAltitudesForCoordinates(const QList<QGeoCoordinate>& coordinates, QList<double>& altitudes);
QString _getTileHash(const QGeoCoordinate& coordinate); /// Method to create a unique string for each tile
void _tileFailed (void);
bool _getAltitudesForCoordinates (const QList<QGeoCoordinate>& coordinates, QList<double>& altitudes, bool& error);
QString _getTileHash (const QGeoCoordinate& coordinate);
QList<QueuedRequestInfo_t> _requestQueue;
State _state = State::Idle;
......
......@@ -53,88 +53,57 @@ TerrainTile::TerrainTile(QByteArray byteArray)
, _gridSizeLon(-1)
, _isValid(false)
{
QDataStream stream(byteArray);
int cTileHeaderBytes = static_cast<int>(sizeof(TileInfo_t));
int cTileBytesAvailable = byteArray.size();
float lat,lon;
if (stream.atEnd()) {
qWarning() << "Terrain tile binary data does not contain all data";
if (cTileBytesAvailable < cTileHeaderBytes) {
qWarning() << "Terrain tile binary data too small for TileInfo_s header";
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()) {
qWarning() << "Terrain tile binary data does not contain all data";
return;
}
stream >> lat;
if (stream.atEnd()) {
qWarning() << "Terrain tile binary data does not contain all data";
return;
}
stream >> lon;
_northEast.setLatitude(lat);
_northEast.setLongitude(lon);
const TileInfo_t* tileInfo = reinterpret_cast<const TileInfo_t*>(byteArray.constData());
_southWest.setLatitude(tileInfo->swLat);
_southWest.setLongitude(tileInfo->swLon);
_northEast.setLatitude(tileInfo->neLat);
_northEast.setLongitude(tileInfo->neLon);
_minElevation = tileInfo->minElevation;
_maxElevation = tileInfo->maxElevation;
_avgElevation = tileInfo->avgElevation;
_gridSizeLat = tileInfo->gridSizeLat;
_gridSizeLon = tileInfo->gridSizeLon;
if (stream.atEnd()) {
qWarning() << "Terrain tile binary data does not contain all data";
return;
}
stream >> _minElevation;
if (stream.atEnd()) {
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";
qCDebug(TerrainTileLog) << "Loading terrain tile: " << _southWest << " - " << _northEast;
qCDebug(TerrainTileLog) << "min:max:avg:sizeLat:sizeLon" << _minElevation << _maxElevation << _avgElevation << _gridSizeLat << _gridSizeLon;
int cTileDataBytes = static_cast<int>(sizeof(int16_t)) * _gridSizeLat * _gridSizeLon;
if (cTileBytesAvailable < cTileHeaderBytes + cTileDataBytes) {
qWarning() << "Terrain tile binary data too small for tile data";
return;
}
stream >> _gridSizeLon;
qCDebug(TerrainTileLog) << "Loading terrain tile: " << _southWest << " - " << _northEast;
qCDebug(TerrainTileLog) << "min:max:avg:sizeLat:sizeLon" << _minElevation << _maxElevation << _avgElevation << _gridSizeLat << _gridSizeLon;
_data = new int16_t*[_gridSizeLat];
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++) {
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++) {
if (stream.atEnd()) {
qWarning() << "Terrain tile binary data does not contain all data";
return;
}
stream >> _data[i][j];
_data[i][j] = pTileData[valueIndex++];
}
}
_isValid = true;
return;
}
bool TerrainTile::isIn(const QGeoCoordinate& coordinate) const
{
if (!_isValid) {
qCDebug(TerrainTileLog) << "isIn requested, but tile not valid";
qCWarning(TerrainTileLog) << "isIn requested, but tile not valid";
return false;
}
bool ret = coordinate.latitude() >= _southWest.latitude() && coordinate.longitude() >= _southWest.longitude() &&
......@@ -152,13 +121,13 @@ double TerrainTile::elevation(const QGeoCoordinate& coordinate) const
int indexLon = _lonToDataIndex(coordinate.longitude());
if (indexLat == -1 || indexLon == -1) {
qCWarning(TerrainTileLog) << "Internal error indexLat:indexLon == -1" << indexLat << indexLon;
return -1.0;
return qQNaN();
}
qCDebug(TerrainTileLog) << "indexLat:indexLon" << indexLat << indexLon << "elevation" << _data[indexLat][indexLon];
return static_cast<double>(_data[indexLat][indexLon]);
} else {
qCDebug(TerrainTileLog) << "Asking for elevation, but no valid data.";
return -1.0;
qCWarning(TerrainTileLog) << "Asking for elevation, but no valid data.";
return qQNaN();
}
}
......@@ -176,8 +145,6 @@ QByteArray TerrainTile::serialize(QByteArray input)
return emptyArray;
}
QByteArray byteArray;
QDataStream stream(&byteArray, QIODevice::WriteOnly);
if (!document.isObject()) {
qCDebug(TerrainTileLog) << "Terrain tile json doc is no object";
QByteArray emptyArray;
......@@ -231,10 +198,6 @@ QByteArray TerrainTile::serialize(QByteArray input)
QByteArray 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
const QJsonObject& statsObject = dataObject[_jsonStatsKey].toObject();
......@@ -248,30 +211,46 @@ QByteArray TerrainTile::serialize(QByteArray input)
QByteArray 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
const QJsonArray& carpetArray = dataObject[_jsonCarpetKey].toArray();
int gridSizeLat = carpetArray.count();
stream << static_cast<int16_t>(gridSizeLat);
int gridSizeLon = 0;
qCDebug(TerrainTileLog) << "Received tile has size in latitude direction: " << carpetArray.count();
int gridSizeLon = carpetArray[0].toArray().count();
qCDebug(TerrainTileLog) << "Received tile has size in latitude direction: " << gridSizeLat;
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++) {
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) {
qCDebug(TerrainTileLog) << "Expected row array of " << gridSizeLon << ", instead got " << row.count();
QByteArray emptyArray;
return emptyArray;
}
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
if (isValid() && _southWest.isValid() && _northEast.isValid()) {
return qRound((latitude - _southWest.latitude()) / (_northEast.latitude() - _southWest.latitude()) * (_gridSizeLat - 1));
} else {
qCWarning(TerrainTileLog) << "TerrainTile::_latToDataIndex internal error" << isValid() << _southWest.isValid() << _northEast.isValid();
return -1;
}
}
......@@ -293,6 +273,7 @@ int TerrainTile::_lonToDataIndex(double longitude) const
if (isValid() && _southWest.isValid() && _northEast.isValid()) {
return qRound((longitude - _southWest.longitude()) / (_northEast.longitude() - _southWest.longitude()) * (_gridSizeLon - 1));
} else {
qCWarning(TerrainTileLog) << "TerrainTile::_lonToDataIndex internal error" << isValid() << _southWest.isValid() << _northEast.isValid();
return -1;
}
}
......@@ -95,6 +95,15 @@ public:
static constexpr double terrainAltitudeSpacing = 30.0;
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 _lonToDataIndex(double longitude) const;
......@@ -103,7 +112,7 @@ private:
int16_t _minElevation; /// Minimum 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 _gridSizeLat; /// data grid size in latitude direction
......
......@@ -1259,6 +1259,10 @@ void Vehicle::_handleWindCov(mavlink_message_t& message)
float direction = qRadiansToDegrees(qAtan2(wind.wind_y, wind.wind_x));
float speed = qSqrt(qPow(wind.wind_x, 2) + qPow(wind.wind_y, 2));
if (direction < 0) {
direction += 360;
}
_windFactGroup.direction()->setRawValue(direction);
_windFactGroup.speed()->setRawValue(speed);
_windFactGroup.verticalSpeed()->setRawValue(0);
......
......@@ -33,6 +33,7 @@ public:
, pOfflineMaps (NULL)
, pMAVLink (NULL)
, pConsole (NULL)
, pHelp (NULL)
#if defined(QT_DEBUG)
, pMockLink (NULL)
, pDebug (NULL)
......@@ -73,6 +74,7 @@ public:
QmlComponentInfo* pOfflineMaps;
QmlComponentInfo* pMAVLink;
QmlComponentInfo* pConsole;
QmlComponentInfo* pHelp;
#if defined(QT_DEBUG)
QmlComponentInfo* pMockLink;
QmlComponentInfo* pDebug;
......@@ -135,6 +137,9 @@ QVariantList &QGCCorePlugin::settingsPages()
_p->pConsole = new QmlComponentInfo(tr("Console"),
QUrl::fromUserInput("qrc:/qml/QGroundControl/Controls/AppMessages.qml"));
_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)
//-- These are always present on Debug builds
_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