QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
TerrainTileCopernicus.cc
Go to the documentation of this file.
2
3#include <QtCore/QJsonArray>
4#include <QtCore/QJsonDocument>
5#include <QtCore/QJsonObject>
6
7#include "JsonHelper.h"
9#include "QGCNetworkHelper.h"
10
11QGC_LOGGING_CATEGORY(TerrainTileCopernicusLog, "Terrain.TerrainTileCopernicus");
12
13TerrainTileCopernicus::TerrainTileCopernicus(const QByteArray& byteArray) : TerrainTile(byteArray)
14{
15 qCDebug(TerrainTileCopernicusLog) << this;
16}
17
19{
20 qCDebug(TerrainTileCopernicusLog) << this;
21}
22
23QJsonValue TerrainTileCopernicus::getJsonFromData(const QByteArray& input)
24{
25 QJsonParseError parseError;
26 const QJsonDocument document = QGCNetworkHelper::parseCompressedJson(input, &parseError);
27 if (parseError.error != QJsonParseError::NoError) {
28 qCWarning(TerrainTileCopernicusLog)
29 << "Terrain tile json doc parse error" << parseError.errorString();
30 return QJsonValue();
31 }
32
33 if (!document.isObject()) {
34 qCWarning(TerrainTileCopernicusLog) << "Terrain tile json doc is no object";
35 return QJsonValue();
36 }
37
38 const QJsonObject rootObject = document.object();
39
40 static const QList<JsonHelper::KeyValidateInfo> rootVersionKeyInfoList = {
41 {_jsonStatusKey, QJsonValue::String, true},
42 {_jsonDataKey, QJsonValue::Object, true},
43 };
44 QString errorString;
45 if (!JsonHelper::validateKeys(rootObject, rootVersionKeyInfoList, errorString)) {
46 qCWarning(TerrainTileCopernicusLog) << "Error in reading json: " << errorString;
47 return QJsonValue();
48 }
49
50 if (rootObject[_jsonStatusKey].toString() != "success") {
51 qCWarning(TerrainTileCopernicusLog) << "Invalid terrain tile.";
52 return QJsonValue();
53 }
54
55 const QJsonValue& jsonData = rootObject[_jsonDataKey];
56 const QJsonObject& dataObject = jsonData.toObject();
57
58 QList<JsonHelper::KeyValidateInfo> dataVersionKeyInfoList = {
59 {_jsonBoundsKey, QJsonValue::Object, true},
60 {_jsonStatsKey, QJsonValue::Object, true},
61 {_jsonCarpetKey, QJsonValue::Array, true},
62 };
63
64 if (!JsonHelper::validateKeys(dataObject, dataVersionKeyInfoList, errorString)) {
65 qCWarning(TerrainTileCopernicusLog) << "Error in reading json: " << errorString;
66 return QJsonValue();
67 }
68
69 return jsonData;
70}
71
72QByteArray TerrainTileCopernicus::serializeFromData(const QByteArray& input)
73{
74 const QJsonValue& jsonData = getJsonFromData(input);
75 if (jsonData.isNull()) {
76 return QByteArray();
77 }
78
79 const QJsonObject& dataObject = jsonData.toObject();
80
81 const QJsonObject& boundsObject = dataObject[_jsonBoundsKey].toObject();
82 static const QList<JsonHelper::KeyValidateInfo> boundsVersionKeyInfoList = {
83 {_jsonSouthWestKey, QJsonValue::Array, true},
84 {_jsonNorthEastKey, QJsonValue::Array, true},
85 };
86 QString errorString;
87 if (!JsonHelper::validateKeys(boundsObject, boundsVersionKeyInfoList, errorString)) {
88 qCWarning(TerrainTileCopernicusLog) << "Error in reading json: " << errorString;
89 return QByteArray();
90 }
91
92 const QJsonArray& swArray = boundsObject[_jsonSouthWestKey].toArray();
93 const QJsonArray& neArray = boundsObject[_jsonNorthEastKey].toArray();
94 if ((swArray.count() < 2) || (neArray.count() < 2)) {
95 qCWarning(TerrainTileCopernicusLog) << "Incomplete bounding location";
96 return QByteArray();
97 }
98
99 const QJsonObject& statsObject = dataObject[_jsonStatsKey].toObject();
100 static const QList<JsonHelper::KeyValidateInfo> statsVersionKeyInfoList = {
101 {_jsonMinElevationKey, QJsonValue::Double, true},
102 {_jsonMaxElevationKey, QJsonValue::Double, true},
103 {_jsonAvgElevationKey, QJsonValue::Double, true},
104 };
105 if (!JsonHelper::validateKeys(statsObject, statsVersionKeyInfoList, errorString)) {
106 qCWarning(TerrainTileCopernicusLog) << "Error in reading json: " << errorString;
107 return QByteArray();
108 }
109
110 const QJsonArray& carpetArray = dataObject[_jsonCarpetKey].toArray();
111
112 if (carpetArray.isEmpty()) {
113 qCWarning(TerrainTileCopernicusLog) << "Empty carpet array in terrain data";
114 return QByteArray();
115 }
116
117 const QJsonArray& firstRow = carpetArray[0].toArray();
118 if (firstRow.isEmpty()) {
119 qCWarning(TerrainTileCopernicusLog) << "Empty first row in carpet array";
120 return QByteArray();
121 }
122
124 tileInfo.swLat = swArray[0].toDouble();
125 tileInfo.swLon = swArray[1].toDouble();
126 tileInfo.neLat = neArray[0].toDouble();
127 tileInfo.neLon = neArray[1].toDouble();
128 tileInfo.minElevation = static_cast<int16_t>(statsObject[_jsonMinElevationKey].toInt());
129 tileInfo.maxElevation = static_cast<int16_t>(statsObject[_jsonMaxElevationKey].toInt());
130 tileInfo.avgElevation = statsObject[_jsonAvgElevationKey].toDouble();
131 tileInfo.gridSizeLat = static_cast<int16_t>(carpetArray.count());
132 tileInfo.gridSizeLon = static_cast<int16_t>(firstRow.count());
133
134 qCDebug(TerrainTileCopernicusLog) << "Serialize: TileInfo: south west:" << tileInfo.swLat << tileInfo.swLon;
135 qCDebug(TerrainTileCopernicusLog) << "Serialize: TileInfo: north east:" << tileInfo.neLat << tileInfo.neLon;
136
137 constexpr int cTileNumHeaderBytes = static_cast<int>(sizeof(TileInfo_t));
138 const int cTileNumDataBytes = static_cast<int>(sizeof(int16_t)) * tileInfo.gridSizeLat * tileInfo.gridSizeLon;
139
140 QByteArray result(cTileNumHeaderBytes + cTileNumDataBytes, Qt::Uninitialized);
141 TileInfo_t* pTileInfo = reinterpret_cast<TileInfo_t*>(result.data());
142 int16_t* const pTileData =
143 reinterpret_cast<int16_t*>(&reinterpret_cast<uint8_t*>(result.data())[cTileNumHeaderBytes]);
144
145 *pTileInfo = tileInfo;
146
147 int valueIndex = 0;
148 for (qsizetype i = 0; i < static_cast<qsizetype>(tileInfo.gridSizeLat); i++) {
149 const QJsonArray& row = carpetArray[i].toArray();
150 if (row.count() < tileInfo.gridSizeLon) {
151 qCDebug(TerrainTileCopernicusLog)
152 << "Expected row array of" << tileInfo.gridSizeLon << ", instead got" << row.count();
153 return QByteArray();
154 }
155
156 for (qsizetype j = 0; j < static_cast<qsizetype>(tileInfo.gridSizeLon); j++) {
157 pTileData[valueIndex++] = static_cast<int16_t>(row[j].toDouble());
158 }
159 }
160
161 return result;
162}
QString errorString
#define QGC_LOGGING_CATEGORY(name, categoryStr)
static QByteArray serializeFromData(const QByteArray &input)
TerrainTileCopernicus(const QByteArray &byteArray)
static QJsonValue getJsonFromData(const QByteArray &input)
bool validateKeys(const QJsonObject &jsonObject, const QList< KeyValidateInfo > &keyInfo, QString &errorString)
QJsonDocument parseCompressedJson(const QByteArray &data, QJsonParseError *error)