QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
TerrainTile.cc
Go to the documentation of this file.
1#include "TerrainTile.h"
3
4#include <QtCore/QtNumeric>
5#include <QtPositioning/QGeoCoordinate>
6
7QGC_LOGGING_CATEGORY(TerrainTileLog, "Terrain.terraintile");
8
9TerrainTile::TerrainTile(const QByteArray &byteArray)
10{
11 qCDebug(TerrainTileLog) << this;
12
13 constexpr int cTileHeaderBytes = static_cast<int>(sizeof(TileInfo_t));
14 const int cTileBytesAvailable = byteArray.size();
15
16 if (cTileBytesAvailable < cTileHeaderBytes) {
17 qCWarning(TerrainTileLog) << "Terrain tile binary data too small for TileInfo_t header";
18 return;
19 }
20
21 _tileInfo = *reinterpret_cast<const TileInfo_t*>(byteArray.constData());
22
23 if (_tileInfo.gridSizeLat <= 0 || _tileInfo.gridSizeLon <= 0) {
24 qCWarning(TerrainTileLog) << "Invalid grid dimensions:" << _tileInfo.gridSizeLat << _tileInfo.gridSizeLon;
25 return;
26 }
27
28 constexpr int16_t kMaxGridSize = 10000;
29 if (_tileInfo.gridSizeLat > kMaxGridSize || _tileInfo.gridSizeLon > kMaxGridSize) {
30 qCWarning(TerrainTileLog) << "Grid dimensions exceed safety limits:" << _tileInfo.gridSizeLat << _tileInfo.gridSizeLon;
31 return;
32 }
33
34 const int cTileDataBytes = static_cast<int>(sizeof(int16_t)) * _tileInfo.gridSizeLat * _tileInfo.gridSizeLon;
35 if (cTileBytesAvailable < cTileHeaderBytes + cTileDataBytes) {
36 qCWarning(TerrainTileLog) << "Terrain tile binary data too small for tile data";
37 return;
38 }
39
40 if (((_tileInfo.neLon - _tileInfo.swLon) < 0.0) || ((_tileInfo.neLat - _tileInfo.swLat) < 0.0)) {
41 qCWarning(TerrainTileLog) << this << "Tile extent is infeasible";
42 return;
43 }
44
45 _cellSizeLat = (_tileInfo.neLat - _tileInfo.swLat) / _tileInfo.gridSizeLat;
46 _cellSizeLon = (_tileInfo.neLon - _tileInfo.swLon) / _tileInfo.gridSizeLon;
47
48 qCDebug(TerrainTileLog) << this << "TileInfo: south west:" << _tileInfo.swLat << _tileInfo.swLon;
49 qCDebug(TerrainTileLog) << this << "TileInfo: north east:" << _tileInfo.neLat << _tileInfo.neLon;
50 qCDebug(TerrainTileLog) << this << "TileInfo: dimensions:" << _tileInfo.gridSizeLat << "by" << _tileInfo.gridSizeLon;
51 qCDebug(TerrainTileLog) << this << "TileInfo: min, max, avg:" << _tileInfo.minElevation << _tileInfo.maxElevation << _tileInfo.avgElevation;
52 qCDebug(TerrainTileLog) << this << "TileInfo: cell size:" << _cellSizeLat << _cellSizeLon;
53
54 _elevationData.resize(_tileInfo.gridSizeLat);
55 for (int k = 0; k < _tileInfo.gridSizeLat; k++) {
56 _elevationData[k].resize(_tileInfo.gridSizeLon);
57 }
58
59 int valueIndex = 0;
60 const int16_t* const pTileData = reinterpret_cast<const int16_t*>(&reinterpret_cast<const uint8_t*>(byteArray.constData())[cTileHeaderBytes]);
61 for (int i = 0; i < _tileInfo.gridSizeLat; i++) {
62 for (int j = 0; j < _tileInfo.gridSizeLon; j++) {
63 _elevationData[i][j] = pTileData[valueIndex++];
64 }
65 }
66
67 _isValid = true;
68}
69
71{
72 qCDebug(TerrainTileLog) << this;
73}
74
75double TerrainTile::elevation(const QGeoCoordinate &coordinate) const
76{
77 if (!_isValid) {
78 qCWarning(TerrainTileLog) << this << "Request for elevation, but tile is invalid.";
79 return qQNaN();
80 }
81
82 const double latDeltaSw = coordinate.latitude() - _tileInfo.swLat;
83 const double lonDeltaSw = coordinate.longitude() - _tileInfo.swLon;
84
85 const int16_t latIndex = qFloor(latDeltaSw / _cellSizeLat);
86 const int16_t lonIndex = qFloor(lonDeltaSw / _cellSizeLon);
87
88 const bool latIndexInvalid = (latIndex < 0) || (latIndex > (_tileInfo.gridSizeLat - 1));
89 const bool lonIndexInvalid = (lonIndex < 0) || (lonIndex > (_tileInfo.gridSizeLon - 1));
90
91 if (latIndexInvalid || lonIndexInvalid) {
92 qCWarning(TerrainTileLog) << this << "Internal error: coordinate" << coordinate << "outside tile bounds";
93 return qQNaN();
94 }
95
96 if ((latIndex >= _elevationData.size()) || (lonIndex >= _elevationData[latIndex].size())) {
97 qCWarning(TerrainTileLog).noquote() << this << "Internal error: _elevationData size inconsistent _tileInfo << coordinate" << coordinate
98 << "\n\t_tileInfo.gridSizeLat:" << _tileInfo.gridSizeLat << "_tileInfo.gridSizeLon:" << _tileInfo.gridSizeLon
99 << "\n\t_data.size():" << _elevationData.size() << "_elevationData[latIndex].size():" << _elevationData[latIndex].size();
100 return qQNaN();
101 }
102
103 const int16_t elevation = _elevationData[latIndex][lonIndex];
104 if (elevation < _tileInfo.minElevation) {
105 qCWarning(TerrainTileLog) << this << "Warning: elevation read is below min elevation in tile:" << elevation << "<" << _tileInfo.minElevation;
106 } else if (elevation > _tileInfo.maxElevation) {
107 qCWarning(TerrainTileLog) << this << "Warning: elevation read is above max elevation in tile:" << elevation << ">" << _tileInfo.maxElevation;
108 }
109
110 qCDebug(TerrainTileLog) << this << "latIndex, lonIndex:" << latIndex << lonIndex << "elevation:" << elevation;
111
112 return static_cast<double>(elevation);
113}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
double elevation(const QGeoCoordinate &coordinate) const
virtual ~TerrainTile()
TerrainTile(const QByteArray &byteArray)
Definition TerrainTile.cc:9