Commit 5c72de31 authored by Andreas Bircher's avatar Andreas Bircher

Merge branch 'feature/offlineElevationData' into feature/offlineElevationDataBinary

Conflicts:
	src/Terrain.cc
	src/TerrainTile.cc
	src/TerrainTile.h
parents bdbe526f ac9fbc8a
...@@ -41,7 +41,7 @@ You **need to install Qt as described below** instead of using pre-built package ...@@ -41,7 +41,7 @@ You **need to install Qt as described below** instead of using pre-built package
* Windows: Make sure to install VS 2015 32 bit package. * Windows: Make sure to install VS 2015 32 bit package.
###### Install additional packages: ###### Install additional packages:
* Ubuntu: sudo apt-get install speech-dispatcher libudev-dev libsdl2-dev libgstreamer1.0-0 gstreamer1.0-plugins-base libgstreamer-plugins-base1.0-dev gstreamer1.0* * Ubuntu: sudo apt-get install speech-dispatcher libudev-dev libsdl2-dev
* Fedora: sudo dnf install speech-dispatcher SDL2-devel SDL2 systemd-devel * Fedora: sudo dnf install speech-dispatcher SDL2-devel SDL2 systemd-devel
* Arch Linux: pacman -Sy speech-dispatcher * Arch Linux: pacman -Sy speech-dispatcher
* Windows: [USB Driver](http://www.pixhawk.org/firmware/downloads) to connect to Pixhawk/PX4Flow/3DR Radio * Windows: [USB Driver](http://www.pixhawk.org/firmware/downloads) to connect to Pixhawk/PX4Flow/3DR Radio
......
...@@ -346,6 +346,7 @@ INCLUDEPATH += \ ...@@ -346,6 +346,7 @@ INCLUDEPATH += \
src/QtLocationPlugin \ src/QtLocationPlugin \
src/QtLocationPlugin/QMLControl \ src/QtLocationPlugin/QMLControl \
src/Settings \ src/Settings \
src/Terrain \
src/VehicleSetup \ src/VehicleSetup \
src/ViewWidgets \ src/ViewWidgets \
src/Audio \ src/Audio \
...@@ -586,7 +587,7 @@ HEADERS += \ ...@@ -586,7 +587,7 @@ HEADERS += \
src/Settings/SettingsManager.h \ src/Settings/SettingsManager.h \
src/Settings/UnitsSettings.h \ src/Settings/UnitsSettings.h \
src/Settings/VideoSettings.h \ src/Settings/VideoSettings.h \
src/Terrain.h \ src/Terrain/TerrainQuery.h \
src/TerrainTile.h \ src/TerrainTile.h \
src/Vehicle/MAVLinkLogManager.h \ src/Vehicle/MAVLinkLogManager.h \
src/VehicleSetup/JoystickConfigController.h \ src/VehicleSetup/JoystickConfigController.h \
...@@ -779,7 +780,7 @@ SOURCES += \ ...@@ -779,7 +780,7 @@ SOURCES += \
src/Settings/SettingsManager.cc \ src/Settings/SettingsManager.cc \
src/Settings/UnitsSettings.cc \ src/Settings/UnitsSettings.cc \
src/Settings/VideoSettings.cc \ src/Settings/VideoSettings.cc \
src/Terrain.cc \ src/Terrain/TerrainQuery.cc \
src/TerrainTile.cc\ src/TerrainTile.cc\
src/Vehicle/MAVLinkLogManager.cc \ src/Vehicle/MAVLinkLogManager.cc \
src/VehicleSetup/JoystickConfigController.cc \ src/VehicleSetup/JoystickConfigController.cc \
......
...@@ -36,18 +36,19 @@ public: ...@@ -36,18 +36,19 @@ public:
Q_INVOKABLE void rotateEntryPoint(void); Q_INVOKABLE void rotateEntryPoint(void);
// Overrides from ComplexMissionItem // Overrides from ComplexMissionItem
int lastSequenceNumber (void) const final; int lastSequenceNumber (void) const final;
bool load (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) final; bool load (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) final;
QString mapVisualQML (void) const final { return QStringLiteral("CorridorScanMapVisual.qml"); } QString mapVisualQML (void) const final { return QStringLiteral("CorridorScanMapVisual.qml"); }
// Overrides from TransectStyleComplexItem // Overrides from TransectStyleComplexItem
void save (QJsonArray& planItems) final;
void save (QJsonArray& missionItems) final;
bool specifiesCoordinate (void) const final; bool specifiesCoordinate (void) const final;
void appendMissionItems (QList<MissionItem*>& items, QObject* missionItemParent) final; void appendMissionItems (QList<MissionItem*>& items, QObject* missionItemParent) final;
void applyNewAltitude (double newAltitude) final; void applyNewAltitude (double newAltitude) final;
// Overrides from VisualMissionionItem
bool readyForSave (void) const;
static const char* jsonComplexItemTypeValue; static const char* jsonComplexItemTypeValue;
static const char* settingsGroup; static const char* settingsGroup;
...@@ -59,12 +60,14 @@ private slots: ...@@ -59,12 +60,14 @@ private slots:
void _rebuildCorridor (void); void _rebuildCorridor (void);
// Overrides from TransectStyleComplexItem // Overrides from TransectStyleComplexItem
virtual void _rebuildTransects (void) final; void _rebuildTransectsPhase1 (void) final;
void _rebuildTransectsPhase2 (void) final;
private: private:
int _transectCount (void) const; int _transectCount (void) const;
void _rebuildCorridorPolygon(void); void _rebuildCorridorPolygon (void);
void _buildAndAppendMissionItems(QList<MissionItem*>& items, QObject* missionItemParent);
void _appendLoadedMissionItems (QList<MissionItem*>& items, QObject* missionItemParent);
QGCMapPolyline _corridorPolyline; QGCMapPolyline _corridorPolyline;
QList<QList<QGeoCoordinate>> _transectSegments; ///< Internal transect segments including grid exit, turnaround and internal camera points QList<QList<QGeoCoordinate>> _transectSegments; ///< Internal transect segments including grid exit, turnaround and internal camera points
...@@ -75,5 +78,5 @@ private: ...@@ -75,5 +78,5 @@ private:
QMap<QString, FactMetaData*> _metaDataMap; QMap<QString, FactMetaData*> _metaDataMap;
SettingsFact _corridorWidthFact; SettingsFact _corridorWidthFact;
static const char* _entryPointName; static const char* _jsonEntryPointKey;
}; };
...@@ -134,13 +134,26 @@ void CorridorScanComplexItemTest::_testItemCount(void) ...@@ -134,13 +134,26 @@ void CorridorScanComplexItemTest::_testItemCount(void)
{ {
QList<MissionItem*> items; QList<MissionItem*> items;
_corridorItem->turnAroundDistance()->setRawValue(20);
_corridorItem->turnAroundDistance()->setRawValue(0);
_corridorItem->cameraTriggerInTurnAround()->setRawValue(false); _corridorItem->cameraTriggerInTurnAround()->setRawValue(false);
_corridorItem->appendMissionItems(items, this); _corridorItem->appendMissionItems(items, this);
QCOMPARE(items.count() - 1, _corridorItem->lastSequenceNumber()); QCOMPARE(items.count() - 1, _corridorItem->lastSequenceNumber());
items.clear(); items.clear();
_corridorItem->turnAroundDistance()->setRawValue(0);
_corridorItem->cameraTriggerInTurnAround()->setRawValue(true);
_corridorItem->appendMissionItems(items, this);
QCOMPARE(items.count() - 1, _corridorItem->lastSequenceNumber());
items.clear();
_corridorItem->turnAroundDistance()->setRawValue(20);
_corridorItem->cameraTriggerInTurnAround()->setRawValue(false);
_corridorItem->appendMissionItems(items, this);
QCOMPARE(items.count() - 1, _corridorItem->lastSequenceNumber());
items.clear();
_corridorItem->turnAroundDistance()->setRawValue(20);
_corridorItem->cameraTriggerInTurnAround()->setRawValue(true); _corridorItem->cameraTriggerInTurnAround()->setRawValue(true);
_corridorItem->appendMissionItems(items, this); _corridorItem->appendMissionItems(items, this);
QCOMPARE(items.count() - 1, _corridorItem->lastSequenceNumber()); QCOMPARE(items.count() - 1, _corridorItem->lastSequenceNumber());
......
...@@ -277,7 +277,7 @@ void MissionController::convertToKMLDocument(QDomDocument& document) ...@@ -277,7 +277,7 @@ void MissionController::convertToKMLDocument(QDomDocument& document)
return; return;
} }
float altitude = missionJson[_jsonPlannedHomePositionKey].toArray()[2].toDouble(); float homeAltitude = missionJson[_jsonPlannedHomePositionKey].toArray()[2].toDouble();
QString coord; QString coord;
QStringList coords; QStringList coords;
...@@ -292,11 +292,12 @@ void MissionController::convertToKMLDocument(QDomDocument& document) ...@@ -292,11 +292,12 @@ void MissionController::convertToKMLDocument(QDomDocument& document)
qgcApp()->toolbox()->missionCommandTree()->getUIInfo(_controllerVehicle, item->command()); qgcApp()->toolbox()->missionCommandTree()->getUIInfo(_controllerVehicle, item->command());
if (uiInfo && uiInfo->specifiesCoordinate() && !uiInfo->isStandaloneCoordinate()) { if (uiInfo && uiInfo->specifiesCoordinate() && !uiInfo->isStandaloneCoordinate()) {
double amslAltitude = item->param7() + (item->frame() == MAV_FRAME_GLOBAL ? 0 : homeAltitude);
coord = QString::number(item->param6(),'f',7) \ coord = QString::number(item->param6(),'f',7) \
+ "," \ + "," \
+ QString::number(item->param5(),'f',7) \ + QString::number(item->param5(),'f',7) \
+ "," \ + "," \
+ QString::number(item->param7() + altitude,'f',2); + QString::number(amslAltitude,'f',2);
coords.append(coord); coords.append(coord);
} }
} }
......
...@@ -34,5 +34,32 @@ ...@@ -34,5 +34,32 @@
"shortDescription": "Refly the pattern at a 90 degree angle", "shortDescription": "Refly the pattern at a 90 degree angle",
"type": "bool", "type": "bool",
"defaultValue": false "defaultValue": false
},
{
"name": "TerrainAdjustTolerance",
"shortDescription": "TerrainAdjustTolerance",
"type": "double",
"decimalPlaces": 2,
"min": 0,
"units": "m",
"defaultValue": 10
},
{
"name": "TerrainAdjustMaxClimbRate",
"shortDescription": "TerrainAdjustMaxClimbRate",
"type": "double",
"decimalPlaces": 2,
"min": 0,
"units": "m/s",
"defaultValue": 0
},
{
"name": "TerrainAdjustMaxDescentRate",
"shortDescription": "TerrainAdjustMaxDescentRate",
"type": "double",
"decimalPlaces": 2,
"min": 0,
"units": "m/s",
"defaultValue": 0
} }
] ]
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "QGCMapPolyline.h" #include "QGCMapPolyline.h"
#include "QGCMapPolygon.h" #include "QGCMapPolygon.h"
#include "CameraCalc.h" #include "CameraCalc.h"
#include "TerrainQuery.h"
Q_DECLARE_LOGGING_CATEGORY(TransectStyleComplexItemLog) Q_DECLARE_LOGGING_CATEGORY(TransectStyleComplexItemLog)
...@@ -40,6 +41,11 @@ public: ...@@ -40,6 +41,11 @@ public:
Q_PROPERTY(bool hoverAndCaptureAllowed READ hoverAndCaptureAllowed CONSTANT) Q_PROPERTY(bool hoverAndCaptureAllowed READ hoverAndCaptureAllowed CONSTANT)
Q_PROPERTY(QVariantList transectPoints READ transectPoints NOTIFY transectPointsChanged) Q_PROPERTY(QVariantList transectPoints READ transectPoints NOTIFY transectPointsChanged)
Q_PROPERTY(bool followTerrain READ followTerrain WRITE setFollowTerrain NOTIFY followTerrainChanged)
Q_PROPERTY(Fact* terrainAdjustTolerance READ terrainAdjustTolerance CONSTANT)
Q_PROPERTY(Fact* terrainAdjustMaxDescentRate READ terrainAdjustMaxDescentRate CONSTANT)
Q_PROPERTY(Fact* terrainAdjustMaxClimbRate READ terrainAdjustMaxClimbRate CONSTANT)
QGCMapPolygon* surveyAreaPolygon (void) { return &_surveyAreaPolygon; } QGCMapPolygon* surveyAreaPolygon (void) { return &_surveyAreaPolygon; }
CameraCalc* cameraCalc (void) { return &_cameraCalc; } CameraCalc* cameraCalc (void) { return &_cameraCalc; }
QVariantList transectPoints (void) { return _transectPoints; } QVariantList transectPoints (void) { return _transectPoints; }
...@@ -48,12 +54,18 @@ public: ...@@ -48,12 +54,18 @@ public:
Fact* cameraTriggerInTurnAround (void) { return &_cameraTriggerInTurnAroundFact; } Fact* cameraTriggerInTurnAround (void) { return &_cameraTriggerInTurnAroundFact; }
Fact* hoverAndCapture (void) { return &_hoverAndCaptureFact; } Fact* hoverAndCapture (void) { return &_hoverAndCaptureFact; }
Fact* refly90Degrees (void) { return &_refly90DegreesFact; } Fact* refly90Degrees (void) { return &_refly90DegreesFact; }
Fact* terrainAdjustTolerance (void) { return &_terrainAdjustToleranceFact; }
Fact* terrainAdjustMaxDescentRate (void) { return &_terrainAdjustMaxClimbRateFact; }
Fact* terrainAdjustMaxClimbRate (void) { return &_terrainAdjustMaxDescentRateFact; }
int cameraShots (void) const { return _cameraShots; } int cameraShots (void) const { return _cameraShots; }
double timeBetweenShots (void); double timeBetweenShots (void);
double coveredArea (void) const; double coveredArea (void) const;
double cameraMinTriggerInterval(void) const { return _cameraMinTriggerInterval; } double cameraMinTriggerInterval(void) const { return _cameraMinTriggerInterval; }
bool hoverAndCaptureAllowed (void) const; bool hoverAndCaptureAllowed (void) const;
bool followTerrain (void) const { return _followTerrain; }
void setFollowTerrain(bool followTerrain);
// Overrides from ComplexMissionItem // Overrides from ComplexMissionItem
...@@ -66,7 +78,7 @@ public: ...@@ -66,7 +78,7 @@ public:
// Overrides from VisualMissionItem // Overrides from VisualMissionItem
void save (QJsonArray& missionItems) override = 0; void save (QJsonArray& planItems) override = 0;
bool specifiesCoordinate (void) const override = 0; bool specifiesCoordinate (void) const override = 0;
void appendMissionItems (QList<MissionItem*>& items, QObject* missionItemParent) override = 0; void appendMissionItems (QList<MissionItem*>& items, QObject* missionItemParent) override = 0;
void applyNewAltitude (double newAltitude) override = 0; void applyNewAltitude (double newAltitude) override = 0;
...@@ -85,6 +97,7 @@ public: ...@@ -85,6 +97,7 @@ public:
double specifiedGimbalYaw (void) final { return std::numeric_limits<double>::quiet_NaN(); } double specifiedGimbalYaw (void) final { return std::numeric_limits<double>::quiet_NaN(); }
double specifiedGimbalPitch (void) final { return std::numeric_limits<double>::quiet_NaN(); } double specifiedGimbalPitch (void) final { return std::numeric_limits<double>::quiet_NaN(); }
void setMissionFlightStatus (MissionController::MissionFlightStatus_t& missionFlightStatus) final; void setMissionFlightStatus (MissionController::MissionFlightStatus_t& missionFlightStatus) final;
bool readyForSave (void) const override;
bool coordinateHasRelativeAltitude (void) const final { return true /*_altitudeRelative*/; } bool coordinateHasRelativeAltitude (void) const final { return true /*_altitudeRelative*/; }
bool exitCoordinateHasRelativeAltitude (void) const final { return true /*_altitudeRelative*/; } bool exitCoordinateHasRelativeAltitude (void) const final { return true /*_altitudeRelative*/; }
...@@ -99,6 +112,9 @@ public: ...@@ -99,6 +112,9 @@ public:
static const char* cameraTriggerInTurnAroundName; static const char* cameraTriggerInTurnAroundName;
static const char* hoverAndCaptureName; static const char* hoverAndCaptureName;
static const char* refly90DegreesName; static const char* refly90DegreesName;
static const char* terrainAdjustToleranceName;
static const char* terrainAdjustMaxClimbRateName;
static const char* terrainAdjustMaxDescentRateName;
signals: signals:
void cameraShotsChanged (void); void cameraShotsChanged (void);
...@@ -106,14 +122,17 @@ signals: ...@@ -106,14 +122,17 @@ signals:
void cameraMinTriggerIntervalChanged(double cameraMinTriggerInterval); void cameraMinTriggerIntervalChanged(double cameraMinTriggerInterval);
void transectPointsChanged (void); void transectPointsChanged (void);
void coveredAreaChanged (void); void coveredAreaChanged (void);
void followTerrainChanged (bool followTerrain);
protected slots: protected slots:
virtual void _rebuildTransects (void) = 0; virtual void _rebuildTransectsPhase1 (void) = 0;
virtual void _rebuildTransectsPhase2 (void) = 0;
void _setDirty (void); void _setDirty (void);
void _setIfDirty (bool dirty); void _setIfDirty (bool dirty);
void _updateCoordinateAltitudes (void); void _updateCoordinateAltitudes (void);
void _signalLastSequenceNumberChanged (void); void _signalLastSequenceNumberChanged (void);
void _polyPathTerrainData (bool success, const QList<TerrainPathQuery::PathHeightInfo_t>& rgPathHeightInfo);
protected: protected:
void _save (QJsonObject& saveObject); void _save (QJsonObject& saveObject);
...@@ -121,18 +140,23 @@ protected: ...@@ -121,18 +140,23 @@ protected:
void _setExitCoordinate (const QGeoCoordinate& coordinate); void _setExitCoordinate (const QGeoCoordinate& coordinate);
void _setCameraShots (int cameraShots); void _setCameraShots (int cameraShots);
double _triggerDistance (void) const; double _triggerDistance (void) const;
int _transectCount (void) const;
bool _hasTurnaround (void) const; bool _hasTurnaround (void) const;
double _turnaroundDistance (void) const; double _turnaroundDistance (void) const;
void _queryTransectsPathHeightInfo (void);
void _adjustTransectPointsForTerrain (void);
QString _settingsGroup; QString _settingsGroup;
int _sequenceNumber; int _sequenceNumber;
bool _dirty; bool _dirty;
QGeoCoordinate _coordinate; QGeoCoordinate _coordinate;
QGeoCoordinate _exitCoordinate; QGeoCoordinate _exitCoordinate;
QVariantList _transectPoints;
QGCMapPolygon _surveyAreaPolygon; QGCMapPolygon _surveyAreaPolygon;
QVariantList _transectPoints;
QList<TerrainPathQuery::PathHeightInfo_t> _transectsPathHeightInfo;
TerrainPolyPathQuery* _terrainPolyPathQuery;
QTimer _terrainQueryTimer;
bool _ignoreRecalc; bool _ignoreRecalc;
double _complexDistance; double _complexDistance;
int _cameraShots; int _cameraShots;
...@@ -140,6 +164,10 @@ protected: ...@@ -140,6 +164,10 @@ protected:
double _cameraMinTriggerInterval; double _cameraMinTriggerInterval;
double _cruiseSpeed; double _cruiseSpeed;
CameraCalc _cameraCalc; CameraCalc _cameraCalc;
bool _followTerrain;
QObject* _loadedMissionItemsParent; ///< Parent for all items in _loadedMissionItems for simpler delete
QList<MissionItem*> _loadedMissionItems; ///< Mission items loaded from plan file
QMap<QString, FactMetaData*> _metaDataMap; QMap<QString, FactMetaData*> _metaDataMap;
...@@ -147,6 +175,25 @@ protected: ...@@ -147,6 +175,25 @@ protected:
SettingsFact _cameraTriggerInTurnAroundFact; SettingsFact _cameraTriggerInTurnAroundFact;
SettingsFact _hoverAndCaptureFact; SettingsFact _hoverAndCaptureFact;
SettingsFact _refly90DegreesFact; SettingsFact _refly90DegreesFact;
SettingsFact _terrainAdjustToleranceFact;
SettingsFact _terrainAdjustMaxClimbRateFact;
SettingsFact _terrainAdjustMaxDescentRateFact;
static const char* _jsonCameraCalcKey; static const char* _jsonCameraCalcKey;
static const char* _jsonTransectStyleComplexItemKey;
static const char* _jsonTransectPointsKey;
static const char* _jsonItemsKey;
static const char* _jsonFollowTerrainKey;
static const int _terrainQueryTimeoutMsecs;
static const double _surveyEdgeIndicator; ///< Altitude value in _transectPoints which indicates survey entry
private slots:
void _rebuildTransects (void);
void _reallyQueryTransectsPathHeightInfo (void);
private:
void _addInterstitialTransectsForTerrain (void);
double _altitudeBetweenCoords (const QGeoCoordinate& fromCoord, const QGeoCoordinate& toCoord, double percentTowardsTo);
int _maxPathHeight (const TerrainPathQuery::PathHeightInfo_t& pathHeightInfo, int fromIndex, int toIndex, double& maxHeight);
}; };
...@@ -174,7 +174,12 @@ TransectStyleItem::TransectStyleItem(Vehicle* vehicle, QObject* parent) ...@@ -174,7 +174,12 @@ TransectStyleItem::TransectStyleItem(Vehicle* vehicle, QObject* parent)
} }
void TransectStyleItem::_rebuildTransects(void) void TransectStyleItem::_rebuildTransectsPhase1(void)
{ {
rebuildTransectsCalled = true; rebuildTransectsCalled = true;
} }
void TransectStyleItem::_rebuildTransectsPhase2(void)
{
}
...@@ -101,5 +101,6 @@ public: ...@@ -101,5 +101,6 @@ public:
private slots: private slots:
// Overrides from TransectStyleComplexItem // Overrides from TransectStyleComplexItem
void _rebuildTransects (void) final; void _rebuildTransectsPhase1(void) final;
void _rebuildTransectsPhase2(void) final;
}; };
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include "FirmwarePluginManager.h" #include "FirmwarePluginManager.h"
#include "QGCApplication.h" #include "QGCApplication.h"
#include "JsonHelper.h" #include "JsonHelper.h"
#include "Terrain.h" #include "TerrainQuery.h"
const char* VisualMissionItem::jsonTypeKey = "type"; const char* VisualMissionItem::jsonTypeKey = "type";
const char* VisualMissionItem::jsonTypeSimpleItemValue = "SimpleItem"; const char* VisualMissionItem::jsonTypeSimpleItemValue = "SimpleItem";
...@@ -172,18 +172,18 @@ void VisualMissionItem::_reallyUpdateTerrainAltitude(void) ...@@ -172,18 +172,18 @@ void VisualMissionItem::_reallyUpdateTerrainAltitude(void)
if (coord.isValid() && (qIsNaN(_terrainAltitude) || !qFuzzyCompare(_lastLatTerrainQuery, coord.latitude()) || qFuzzyCompare(_lastLonTerrainQuery, coord.longitude()))) { if (coord.isValid() && (qIsNaN(_terrainAltitude) || !qFuzzyCompare(_lastLatTerrainQuery, coord.latitude()) || qFuzzyCompare(_lastLonTerrainQuery, coord.longitude()))) {
_lastLatTerrainQuery = coord.latitude(); _lastLatTerrainQuery = coord.latitude();
_lastLonTerrainQuery = coord.longitude(); _lastLonTerrainQuery = coord.longitude();
ElevationProvider* terrain = new ElevationProvider(this); TerrainAtCoordinateQuery* terrain = new TerrainAtCoordinateQuery(this);
connect(terrain, &ElevationProvider::terrainData, this, &VisualMissionItem::_terrainDataReceived); connect(terrain, &TerrainAtCoordinateQuery::terrainData, this, &VisualMissionItem::_terrainDataReceived);
QList<QGeoCoordinate> rgCoord; QList<QGeoCoordinate> rgCoord;
rgCoord.append(coordinate()); rgCoord.append(coordinate());
terrain->queryTerrainData(rgCoord); terrain->requestData(rgCoord);
} }
} }
void VisualMissionItem::_terrainDataReceived(bool success, QList<float> altitudes) void VisualMissionItem::_terrainDataReceived(bool success, QList<double> heights)
{ {
if (success) { if (success) {
_terrainAltitude = altitudes[0]; _terrainAltitude = heights[0];
emit terrainAltitudeChanged(_terrainAltitude); emit terrainAltitudeChanged(_terrainAltitude);
sender()->deleteLater(); sender()->deleteLater();
} }
......
...@@ -211,7 +211,7 @@ protected: ...@@ -211,7 +211,7 @@ protected:
private slots: private slots:
void _updateTerrainAltitude (void); void _updateTerrainAltitude (void);
void _reallyUpdateTerrainAltitude (void); void _reallyUpdateTerrainAltitude (void);
void _terrainDataReceived (bool success, QList<float> altitudes); void _terrainDataReceived (bool success, QList<double> heights);
private: private:
QTimer _updateTerrainTimer; QTimer _updateTerrainTimer;
......
...@@ -56,6 +56,11 @@ Rectangle { ...@@ -56,6 +56,11 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
spacing: _margin spacing: _margin
QGCLabel {
text: "WIP: Careful!"
color: qgcPal.warningText
}
QGCLabel { QGCLabel {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
...@@ -126,6 +131,59 @@ Rectangle { ...@@ -126,6 +131,59 @@ Rectangle {
onClicked: missionItem.rotateEntryPoint() onClicked: missionItem.rotateEntryPoint()
} }
SectionHeader {
id: terrainHeader
text: qsTr("Terrain")
checked: false
}
ColumnLayout {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
visible: terrainHeader.checked
QGCCheckBox {
id: followsTerrainCheckBox
text: qsTr("Vehicle follows terrain")
checked: missionItem.followTerrain
onClicked: missionItem.followTerrain = checked
}
GridLayout {
anchors.left: parent.left
anchors.right: parent.right
columnSpacing: _margin
rowSpacing: _margin
columns: 2
visible: followsTerrainCheckBox.checked
QGCLabel {
text: "WIP: Careful!"
color: qgcPal.warningText
Layout.columnSpan: 2
}
QGCLabel { text: qsTr("Tolerance") }
FactTextField {
fact: missionItem.terrainAdjustTolerance
Layout.fillWidth: true
}
QGCLabel { text: qsTr("Max Climb Rate") }
FactTextField {
fact: missionItem.terrainAdjustMaxClimbRate
Layout.fillWidth: true
}
QGCLabel { text: qsTr("Max Descent Rate") }
FactTextField {
fact: missionItem.terrainAdjustMaxDescentRate
Layout.fillWidth: true
}
}
}
SectionHeader { SectionHeader {
id: statsHeader id: statsHeader
text: qsTr("Statistics") text: qsTr("Statistics")
......
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "Terrain.h"
#include "QGCMapEngine.h"
#include "QGeoMapReplyQGC.h"
#include <QUrl>
#include <QUrlQuery>
#include <QNetworkRequest>
#include <QNetworkProxy>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QTimer>
#include <QtLocation/private/qgeotilespec_p.h>
QGC_LOGGING_CATEGORY(ElevationProviderLog, "ElevationProviderLog")
Q_GLOBAL_STATIC(TerrainBatchManager, _terrainBatchManager)
TerrainBatchManager::TerrainBatchManager(void)
{
}
void TerrainBatchManager::addQuery(ElevationProvider* elevationProvider, const QList<QGeoCoordinate>& coordinates)
{
if (coordinates.length() > 0) {
QList<float> altitudes;
if (!_getAltitudesForCoordinates(coordinates, altitudes)) {
QueuedRequestInfo_t queuedRequestInfo = { elevationProvider, coordinates };
_requestQueue.append(queuedRequestInfo);
return;
}
qCDebug(ElevationProviderLog) << "All altitudes taken from cached data";
elevationProvider->_signalTerrainData(coordinates.count() == altitudes.count(), altitudes);
}
}
bool TerrainBatchManager::_getAltitudesForCoordinates(const QList<QGeoCoordinate>& coordinates, QList<float>& altitudes)
{
foreach (const QGeoCoordinate& coordinate, coordinates) {
QString tileHash = _getTileHash(coordinate);
_tilesMutex.lock();
if (!_tiles.contains(tileHash)) {
qCDebug(ElevationProviderLog) << "Need to download tile " << tileHash;
// Schedule the fetch task
if (_state != State::Downloading) {
QNetworkRequest request = getQGCMapEngine()->urlFactory()->getTileURL(UrlFactory::AirmapElevation, QGCMapEngine::long2elevationTileX(coordinate.longitude(), 1), QGCMapEngine::lat2elevationTileY(coordinate.latitude(), 1), 1, &_networkManager);
QGeoTileSpec spec;
spec.setX(QGCMapEngine::long2elevationTileX(coordinate.longitude(), 1));
spec.setY(QGCMapEngine::lat2elevationTileY(coordinate.latitude(), 1));
spec.setZoom(1);
spec.setMapId(UrlFactory::AirmapElevation);
QGeoTiledMapReplyQGC* reply = new QGeoTiledMapReplyQGC(&_networkManager, request, spec);
connect(reply, &QGeoTiledMapReplyQGC::finished, this, &TerrainBatchManager::_fetchedTile);
connect(reply, &QGeoTiledMapReplyQGC::aborted, this, &TerrainBatchManager::_fetchedTile);
_state = State::Downloading;
}
_tilesMutex.unlock();
return false;
} else {
if (_tiles[tileHash].isIn(coordinate)) {
altitudes.push_back(_tiles[tileHash].elevation(coordinate));
} else {
qCDebug(ElevationProviderLog) << "Error: coordinate not in tile region";
altitudes.push_back(-1.0);
}
}
_tilesMutex.unlock();
}
return true;
}
void TerrainBatchManager::_tileFailed(void)
{
QList<float> noAltitudes;
foreach (const QueuedRequestInfo_t& requestInfo, _requestQueue) {
requestInfo.elevationProvider->_signalTerrainData(false, noAltitudes);
}
_requestQueue.clear();
}
void TerrainBatchManager::_fetchedTile()
{
QGeoTiledMapReplyQGC* reply = qobject_cast<QGeoTiledMapReplyQGC*>(QObject::sender());
_state = State::Idle;
if (!reply) {
qCDebug(ElevationProviderLog) << "Elevation tile fetched but invalid reply data type.";
return;
}
// remove from download queue
QGeoTileSpec spec = reply->tileSpec();
QString hash = QGCMapEngine::getTileHash(UrlFactory::AirmapElevation, spec.x(), spec.y(), spec.zoom());
// handle potential errors
if (reply->error() != QGeoTiledMapReply::NoError) {
if (reply->error() == QGeoTiledMapReply::CommunicationError) {
qCDebug(ElevationProviderLog) << "Elevation tile fetching returned communication error. " << reply->errorString();
} else {
qCDebug(ElevationProviderLog) << "Elevation tile fetching returned error. " << reply->errorString();
}
_tileFailed();
reply->deleteLater();
return;
}
if (!reply->isFinished()) {
qCDebug(ElevationProviderLog) << "Error in fetching elevation tile. Not finished. " << reply->errorString();
_tileFailed();
reply->deleteLater();
return;
}
// parse received data and insert into hash table
QByteArray responseBytes = reply->mapImageData();
TerrainTile* terrainTile = new TerrainTile(responseBytes);
if (terrainTile->isValid()) {
_tilesMutex.lock();
if (!_tiles.contains(hash)) {
_tiles.insert(hash, *terrainTile);
} else {
delete terrainTile;
}
_tilesMutex.unlock();
} else {
qCDebug(ElevationProviderLog) << "Received invalid tile";
}
reply->deleteLater();
// now try to query the data again
for (int i = _requestQueue.count() - 1; i >= 0; i--) {
QList<float> altitudes;
if (_getAltitudesForCoordinates(_requestQueue[i].coordinates, altitudes)) {
_requestQueue[i].elevationProvider->_signalTerrainData(_requestQueue[i].coordinates.count() == altitudes.count(), altitudes);
_requestQueue.removeAt(i);
}
}
}
QString TerrainBatchManager::_getTileHash(const QGeoCoordinate& coordinate)
{
QString ret = QGCMapEngine::getTileHash(UrlFactory::AirmapElevation, QGCMapEngine::long2elevationTileX(coordinate.longitude(), 1), QGCMapEngine::lat2elevationTileY(coordinate.latitude(), 1), 1);
qCDebug(ElevationProviderLog) << "Computing unique tile hash for " << coordinate << ret;
return ret;
}
ElevationProvider::ElevationProvider(QObject* parent)
: QObject(parent)
{
}
bool ElevationProvider::queryTerrainData(const QList<QGeoCoordinate>& coordinates)
{
if (coordinates.length() == 0) {
return false;
}
_terrainBatchManager->addQuery(this, coordinates);
return false;
}
void ElevationProvider::_signalTerrainData(bool success, QList<float>& altitudes)
{
emit terrainData(success, altitudes);
}
/****************************************************************************
*
* (c) 2017 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.
*
****************************************************************************/
#pragma once
#include "TerrainTile.h"
#include "QGCMapEngineData.h"
#include "QGCLoggingCategory.h"
#include <QObject>
#include <QGeoCoordinate>
#include <QNetworkAccessManager>
#include <QHash>
#include <QMutex>
#include <QtLocation/private/qgeotiledmapreply_p.h>
Q_DECLARE_LOGGING_CATEGORY(ElevationProviderLog)
class ElevationProvider;
/// Used internally by ElevationProvider to batch requests together
class TerrainBatchManager : public QObject {
Q_OBJECT
public:
TerrainBatchManager(void);
void addQuery(ElevationProvider* elevationProvider, const QList<QGeoCoordinate>& coordinates);
private slots:
void _fetchedTile (void); /// slot to handle fetched elevation tiles
private:
typedef struct {
ElevationProvider* elevationProvider;
QList<QGeoCoordinate> coordinates;
} QueuedRequestInfo_t;
enum class State {
Idle,
Downloading,
};
void _tileFailed(void);
bool _getAltitudesForCoordinates(const QList<QGeoCoordinate>& coordinates, QList<float>& altitudes);
QString _getTileHash(const QGeoCoordinate& coordinate); /// Method to create a unique string for each tile
QList<QueuedRequestInfo_t> _requestQueue;
State _state = State::Idle;
QNetworkAccessManager _networkManager;
QMutex _tilesMutex;
QHash<QString, TerrainTile> _tiles;
};
class ElevationProvider : public QObject
{
Q_OBJECT
public:
ElevationProvider(QObject* parent = NULL);
/**
* Async elevation query for a list of lon,lat coordinates. When the query is done, the terrainData() signal
* is emitted. This call caches local elevation tables for faster lookup in the future.
* @param coordinates
* @return true on success
*/
bool queryTerrainData(const QList<QGeoCoordinate>& coordinates);
/// Internal method
void _signalTerrainData(bool success, QList<float>& altitudes);
signals:
/// signal returning requested elevation data
void terrainData(bool success, QList<float> altitudes);
};
This diff is collapsed.
This diff is collapsed.
...@@ -100,7 +100,7 @@ bool TerrainTile::isIn(const QGeoCoordinate& coordinate) const ...@@ -100,7 +100,7 @@ bool TerrainTile::isIn(const QGeoCoordinate& coordinate) const
return ret; return ret;
} }
float TerrainTile::elevation(const QGeoCoordinate& coordinate) const double TerrainTile::elevation(const QGeoCoordinate& coordinate) const
{ {
if (_isValid) { if (_isValid) {
qCDebug(TerrainTileLog) << "elevation: " << coordinate << " , in sw " << _southWest << " , ne " << _northEast; qCDebug(TerrainTileLog) << "elevation: " << coordinate << " , in sw " << _southWest << " , ne " << _northEast;
......
...@@ -54,28 +54,28 @@ public: ...@@ -54,28 +54,28 @@ public:
* @param coordinate * @param coordinate
* @return elevation * @return elevation
*/ */
float elevation(const QGeoCoordinate& coordinate) const; double elevation(const QGeoCoordinate& coordinate) const;
/** /**
* Accessor for the minimum elevation of the tile * Accessor for the minimum elevation of the tile
* *
* @return minimum elevation * @return minimum elevation
*/ */
float minElevation(void) const { return _minElevation; } double minElevation(void) const { return _minElevation; }
/** /**
* Accessor for the maximum elevation of the tile * Accessor for the maximum elevation of the tile
* *
* @return maximum elevation * @return maximum elevation
*/ */
float maxElevation(void) const { return _maxElevation; } double maxElevation(void) const { return _maxElevation; }
/** /**
* Accessor for the average elevation of the tile * Accessor for the average elevation of the tile
* *
* @return average elevation * @return average elevation
*/ */
float avgElevation(void) const { return _avgElevation; } double avgElevation(void) const { return _avgElevation; }
/** /**
* Accessor for the center coordinate * Accessor for the center coordinate
...@@ -91,6 +91,9 @@ public: ...@@ -91,6 +91,9 @@ public:
*/ */
static QByteArray serialize(QByteArray input); static QByteArray serialize(QByteArray input);
/// Approximate spacing of the elevation data measurement points
static constexpr double terrainAltitudeSpacing = 30.0;
private: private:
inline int _latToDataIndex(double latitude) const; inline int _latToDataIndex(double latitude) const;
inline int _lonToDataIndex(double longitude) const; inline int _lonToDataIndex(double longitude) const;
......
...@@ -40,6 +40,9 @@ list=$(apt-cache --names-only search ^gstreamer1.0-* | awk '{ print $1 }' | grep ...@@ -40,6 +40,9 @@ list=$(apt-cache --names-only search ^gstreamer1.0-* | awk '{ print $1 }' | grep
``` ```
sudo apt-get install $list sudo apt-get install $list
``` ```
```
sudo apt-get install libgstreamer-plugins-base1.0-dev
```
The build system is setup to use pkgconfig and it will find the necessary headers and libraries automatically. The build system is setup to use pkgconfig and it will find the necessary headers and libraries automatically.
......
...@@ -181,24 +181,7 @@ VideoEnabled { ...@@ -181,24 +181,7 @@ VideoEnabled {
} else { } else {
LinuxBuild|MacBuild|iOSBuild|WindowsBuild|AndroidBuild { LinuxBuild|MacBuild|iOSBuild|WindowsBuild|AndroidBuild {
message("Skipping support for video streaming (GStreamer libraries not installed)") message("Skipping support for video streaming (GStreamer libraries not installed)")
MacBuild { message("Installation instructions here: https://github.com/mavlink/qgroundcontrol/blob/master/src/VideoStreaming/README.md")
message(" You can download it from http://gstreamer.freedesktop.org/data/pkg/osx/")
message(" Select the devel package and install it (gstreamer-1.0-devel-1.x.x-x86_64.pkg)")
message(" It will be installed in /Libraries/Frameworks")
}
LinuxBuild {
message(" You can install it using apt-get")
message(" sudo apt-get install gstreamer1.0*")
}
WindowsBuild {
message(" You can download it from http://gstreamer.freedesktop.org/data/pkg/windows/")
message(" Select the devel AND runtime packages and install them (x86, not the 64-Bit)")
message(" It will be installed in C:/gstreamer. You need to update you PATH to point to the bin directory.")
}
AndroidBuild {
message(" You can download it from http://gstreamer.freedesktop.org/data/pkg/android/")
message(" Uncompress the archive into the qgc root source directory (same directory where qgroundcontrol.pro is found.")
}
} else { } else {
message("Skipping support for video streaming (Unsupported platform)") message("Skipping support for video streaming (Unsupported platform)")
} }
......
...@@ -35,9 +35,15 @@ QGC_LOGGING_CATEGORY(MockLinkVerboseLog, "MockLinkVerboseLog") ...@@ -35,9 +35,15 @@ QGC_LOGGING_CATEGORY(MockLinkVerboseLog, "MockLinkVerboseLog")
// Vehicle position is set close to default Gazebo vehicle location. This allows for multi-vehicle // Vehicle position is set close to default Gazebo vehicle location. This allows for multi-vehicle
// testing of a gazebo vehicle and a mocklink vehicle // testing of a gazebo vehicle and a mocklink vehicle
double MockLink::_defaultVehicleLatitude = 47.397f; #if 1
double MockLink::_defaultVehicleLongitude = 8.5455f; double MockLink::_defaultVehicleLatitude = 47.397;
double MockLink::_defaultVehicleAltitude = 488.056f; double MockLink::_defaultVehicleLongitude = 8.5455;
double MockLink::_defaultVehicleAltitude = 488.056;
#else
double MockLink::_defaultVehicleLatitude = 47.6333022928789;
double MockLink::_defaultVehicleLongitude = -122.08833157994995;
double MockLink::_defaultVehicleAltitude = 19.0;
#endif
int MockLink::_nextVehicleSystemId = 128; int MockLink::_nextVehicleSystemId = 128;
const char* MockLink::_failParam = "COM_FLTMODE6"; const char* MockLink::_failParam = "COM_FLTMODE6";
......
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