Commit 612d219d authored by Sebastian Verling's avatar Sebastian Verling

first implementation of binary representation of elevation data

parent 32a35ac9
...@@ -51,6 +51,10 @@ ...@@ -51,6 +51,10 @@
#include <QtLocation/private/qgeotilespec_p.h> #include <QtLocation/private/qgeotilespec_p.h>
#include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkAccessManager>
#include <QFile> #include <QFile>
#include "TerrainTile.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
int QGeoTiledMapReplyQGC::_requestCount = 0; int QGeoTiledMapReplyQGC::_requestCount = 0;
...@@ -121,8 +125,24 @@ QGeoTiledMapReplyQGC::networkReplyFinished() ...@@ -121,8 +125,24 @@ QGeoTiledMapReplyQGC::networkReplyFinished()
return; return;
} }
QByteArray a = _reply->readAll(); QByteArray a = _reply->readAll();
setMapImageData(a);
QString format = getQGCMapEngine()->urlFactory()->getImageFormat((UrlFactory::MapType)tileSpec().mapId(), a); QString format = getQGCMapEngine()->urlFactory()->getImageFormat((UrlFactory::MapType)tileSpec().mapId(), a);
// convert "a" to binary in case we have elevation data
if ((UrlFactory::MapType)tileSpec().mapId() == UrlFactory::MapType::AirmapElevation) {
QJsonParseError parseError;
QJsonDocument json = QJsonDocument::fromJson(a, &parseError);
if (parseError.error != QJsonParseError::NoError) {
emit aborted();
return;
} else {
a = TerrainTile::serialize(json);
if (a.isEmpty()) {
emit aborted();
return;
}
}
}
setMapImageData(a);
if(!format.isEmpty()) { if(!format.isEmpty()) {
setMapImageFormat(format); setMapImageFormat(format);
getQGCMapEngine()->cacheTile((UrlFactory::MapType)tileSpec().mapId(), tileSpec().x(), tileSpec().y(), tileSpec().zoom(), a, format); getQGCMapEngine()->cacheTile((UrlFactory::MapType)tileSpec().mapId(), tileSpec().x(), tileSpec().y(), tileSpec().zoom(), a, format);
......
...@@ -128,17 +128,7 @@ void TerrainBatchManager::_fetchedTile() ...@@ -128,17 +128,7 @@ void TerrainBatchManager::_fetchedTile()
// parse received data and insert into hash table // parse received data and insert into hash table
QByteArray responseBytes = reply->mapImageData(); QByteArray responseBytes = reply->mapImageData();
QJsonParseError parseError; TerrainTile* terrainTile = new TerrainTile(responseBytes);
QJsonDocument responseJson = QJsonDocument::fromJson(responseBytes, &parseError);
if (parseError.error != QJsonParseError::NoError) {
qCDebug(ElevationProviderLog) << "Could not parse terrain tile " << parseError.errorString();
qCDebug(ElevationProviderLog) << responseBytes;
_tileFailed();
reply->deleteLater();
return;
}
TerrainTile* terrainTile = new TerrainTile(responseJson);
if (terrainTile->isValid()) { if (terrainTile->isValid()) {
_tilesMutex.lock(); _tilesMutex.lock();
if (!_tiles.contains(hash)) { if (!_tiles.contains(hash)) {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QJsonArray> #include <QJsonArray>
#include <QDataStream>
QGC_LOGGING_CATEGORY(TerrainTileLog, "TerrainTileLog") QGC_LOGGING_CATEGORY(TerrainTileLog, "TerrainTileLog")
...@@ -42,15 +43,83 @@ TerrainTile::~TerrainTile() ...@@ -42,15 +43,83 @@ TerrainTile::~TerrainTile()
} }
} }
TerrainTile::TerrainTile(QJsonDocument document)
TerrainTile::TerrainTile(QByteArray byteArray)
: _minElevation(-1.0) : _minElevation(-1.0)
, _maxElevation(-1.0) , _maxElevation(-1.0)
, _avgElevation(-1.0) , _avgElevation(-1.0)
, _data(NULL)
, _gridSizeLat(-1)
, _gridSizeLon(-1)
, _isValid(false) , _isValid(false)
{ {
QDataStream stream(byteArray);
stream >> _southWest
>> _northEast
>> _minElevation
>> _maxElevation
>> _avgElevation
>> _gridSizeLat
>> _gridSizeLon;
for (int i = 0; i < _gridSizeLat; i++) {
if (i == 0) {
_data = new double*[_gridSizeLat];
for (int k = 0; k < _gridSizeLat; k++) {
_data[k] = new double[_gridSizeLon];
}
}
for (int j = 0; j < _gridSizeLon; j++) {
stream >> _data[i][j];
}
}
_isValid = true;
}
bool TerrainTile::isIn(const QGeoCoordinate& coordinate) const
{
if (!_isValid) {
qCDebug(TerrainTileLog) << "isIn requested, but tile not valid";
return false;
}
bool ret = coordinate.latitude() >= _southWest.latitude() && coordinate.longitude() >= _southWest.longitude() &&
coordinate.latitude() <= _northEast.latitude() && coordinate.longitude() <= _northEast.longitude();
qCDebug(TerrainTileLog) << "Checking isIn: " << coordinate << " , in sw " << _southWest << " , ne " << _northEast << ": " << ret;
return ret;
}
float TerrainTile::elevation(const QGeoCoordinate& coordinate) const
{
if (_isValid) {
qCDebug(TerrainTileLog) << "elevation: " << coordinate << " , in sw " << _southWest << " , ne " << _northEast;
// Get the index at resolution of 1 arc second
int indexLat = _latToDataIndex(coordinate.latitude());
int indexLon = _lonToDataIndex(coordinate.longitude());
qCDebug(TerrainTileLog) << "indexLat:indexLon" << indexLat << indexLon << "elevation" << _data[indexLat][indexLon];
return _data[indexLat][indexLon];
} else {
qCDebug(TerrainTileLog) << "Asking for elevation, but no valid data.";
return -1.0;
}
}
QGeoCoordinate TerrainTile::centerCoordinate(void) const
{
return _southWest.atDistanceAndAzimuth(_southWest.distanceTo(_northEast) / 2.0, _southWest.azimuthTo(_northEast));
}
QByteArray TerrainTile::serialize(QJsonDocument document)
{
QByteArray byteArray;
QIODevice::OpenMode writeonly = QIODevice::WriteOnly;
QDataStream stream(&byteArray, writeonly);
if (!document.isObject()) { if (!document.isObject()) {
qCDebug(TerrainTileLog) << "Terrain tile json doc is no object"; qCDebug(TerrainTileLog) << "Terrain tile json doc is no object";
return; QByteArray emptyArray;
return emptyArray;
} }
QJsonObject rootObject = document.object(); QJsonObject rootObject = document.object();
...@@ -61,12 +130,14 @@ TerrainTile::TerrainTile(QJsonDocument document) ...@@ -61,12 +130,14 @@ TerrainTile::TerrainTile(QJsonDocument document)
}; };
if (!JsonHelper::validateKeys(rootObject, rootVersionKeyInfoList, errorString)) { if (!JsonHelper::validateKeys(rootObject, rootVersionKeyInfoList, errorString)) {
qCDebug(TerrainTileLog) << "Error in reading json: " << errorString; qCDebug(TerrainTileLog) << "Error in reading json: " << errorString;
return; QByteArray emptyArray;
return emptyArray;
} }
if (rootObject[_jsonStatusKey].toString() != "success") { if (rootObject[_jsonStatusKey].toString() != "success") {
qCDebug(TerrainTileLog) << "Invalid terrain tile."; qCDebug(TerrainTileLog) << "Invalid terrain tile.";
return; QByteArray emptyArray;
return emptyArray;
} }
const QJsonObject& dataObject = rootObject[_jsonDataKey].toObject(); const QJsonObject& dataObject = rootObject[_jsonDataKey].toObject();
QList<JsonHelper::KeyValidateInfo> dataVersionKeyInfoList = { QList<JsonHelper::KeyValidateInfo> dataVersionKeyInfoList = {
...@@ -76,7 +147,8 @@ TerrainTile::TerrainTile(QJsonDocument document) ...@@ -76,7 +147,8 @@ TerrainTile::TerrainTile(QJsonDocument document)
}; };
if (!JsonHelper::validateKeys(dataObject, dataVersionKeyInfoList, errorString)) { if (!JsonHelper::validateKeys(dataObject, dataVersionKeyInfoList, errorString)) {
qCDebug(TerrainTileLog) << "Error in reading json: " << errorString; qCDebug(TerrainTileLog) << "Error in reading json: " << errorString;
return; QByteArray emptyArray;
return emptyArray;
} }
// Bounds // Bounds
...@@ -87,18 +159,18 @@ TerrainTile::TerrainTile(QJsonDocument document) ...@@ -87,18 +159,18 @@ TerrainTile::TerrainTile(QJsonDocument document)
}; };
if (!JsonHelper::validateKeys(boundsObject, boundsVersionKeyInfoList, errorString)) { if (!JsonHelper::validateKeys(boundsObject, boundsVersionKeyInfoList, errorString)) {
qCDebug(TerrainTileLog) << "Error in reading json: " << errorString; qCDebug(TerrainTileLog) << "Error in reading json: " << errorString;
return; QByteArray emptyArray;
return emptyArray;
} }
const QJsonArray& swArray = boundsObject[_jsonSouthWestKey].toArray(); const QJsonArray& swArray = boundsObject[_jsonSouthWestKey].toArray();
const QJsonArray& neArray = boundsObject[_jsonNorthEastKey].toArray(); const QJsonArray& neArray = boundsObject[_jsonNorthEastKey].toArray();
if (swArray.count() < 2 || neArray.count() < 2 ) { if (swArray.count() < 2 || neArray.count() < 2 ) {
qCDebug(TerrainTileLog) << "Incomplete bounding location"; qCDebug(TerrainTileLog) << "Incomplete bounding location";
return; QByteArray emptyArray;
return emptyArray;
} }
_southWest.setLatitude(swArray[0].toDouble()); stream << QGeoCoordinate(swArray[0].toDouble(), swArray[1].toDouble());
_southWest.setLongitude(swArray[1].toDouble()); stream << QGeoCoordinate(neArray[0].toDouble(), neArray[1].toDouble());
_northEast.setLatitude(neArray[0].toDouble());
_northEast.setLongitude(neArray[1].toDouble());
// Stats // Stats
const QJsonObject& statsObject = dataObject[_jsonStatsKey].toObject(); const QJsonObject& statsObject = dataObject[_jsonStatsKey].toObject();
...@@ -109,70 +181,39 @@ TerrainTile::TerrainTile(QJsonDocument document) ...@@ -109,70 +181,39 @@ TerrainTile::TerrainTile(QJsonDocument document)
}; };
if (!JsonHelper::validateKeys(statsObject, statsVersionKeyInfoList, errorString)) { if (!JsonHelper::validateKeys(statsObject, statsVersionKeyInfoList, errorString)) {
qCDebug(TerrainTileLog) << "Error in reading json: " << errorString; qCDebug(TerrainTileLog) << "Error in reading json: " << errorString;
return; QByteArray emptyArray;
return emptyArray;
} }
_maxElevation = statsObject[_jsonMaxElevationKey].toInt(); stream << statsObject[_jsonMaxElevationKey].toInt();
_minElevation = statsObject[_jsonMinElevationKey].toInt(); stream << statsObject[_jsonMinElevationKey].toInt();
_avgElevation = statsObject[_jsonAvgElevationKey].toInt(); stream << statsObject[_jsonAvgElevationKey].toDouble();
// Carpet // Carpet
const QJsonArray& carpetArray = dataObject[_jsonCarpetKey].toArray(); const QJsonArray& carpetArray = dataObject[_jsonCarpetKey].toArray();
_gridSizeLat = carpetArray.count(); int gridSizeLat = carpetArray.count();
stream << gridSizeLat;
int gridSizeLon = 0;
qCDebug(TerrainTileLog) << "Received tile has size in latitude direction: " << carpetArray.count(); qCDebug(TerrainTileLog) << "Received tile has size in latitude direction: " << carpetArray.count();
for (int i = 0; i < _gridSizeLat; i++) { for (int i = 0; i < gridSizeLat; i++) {
const QJsonArray& row = carpetArray[i].toArray(); const QJsonArray& row = carpetArray[i].toArray();
if (i == 0) { if (i == 0) {
_gridSizeLon = row.count(); gridSizeLon = row.count();
stream << gridSizeLon;
qCDebug(TerrainTileLog) << "Received tile has size in longitued direction: " << row.count(); qCDebug(TerrainTileLog) << "Received tile has size in longitued direction: " << row.count();
if (_gridSizeLon > 0) {
_data = new float*[_gridSizeLat];
}
for (int k = 0; k < _gridSizeLat; k++) {
_data[k] = new float[_gridSizeLon];
}
} }
if (row.count() < _gridSizeLon) { if (row.count() < gridSizeLon) {
qCDebug(TerrainTileLog) << "Expected row array of " << _gridSizeLon << ", instead got " << row.count(); qCDebug(TerrainTileLog) << "Expected row array of " << gridSizeLon << ", instead got " << row.count();
return; QByteArray emptyArray;
return emptyArray;
} }
for (int j = 0; j < _gridSizeLon; j++) { for (int j = 0; j < gridSizeLon; j++) {
_data[i][j] = row[j].toDouble(); stream << row[j].toDouble();
} }
} }
_isValid = true;
}
bool TerrainTile::isIn(const QGeoCoordinate& coordinate) const return byteArray;
{
if (!_isValid) {
qCDebug(TerrainTileLog) << "isIn requested, but tile not valid";
return false;
}
bool ret = coordinate.latitude() >= _southWest.latitude() && coordinate.longitude() >= _southWest.longitude() &&
coordinate.latitude() <= _northEast.latitude() && coordinate.longitude() <= _northEast.longitude();
qCDebug(TerrainTileLog) << "Checking isIn: " << coordinate << " , in sw " << _southWest << " , ne " << _northEast << ": " << ret;
return ret;
} }
float TerrainTile::elevation(const QGeoCoordinate& coordinate) const
{
if (_isValid) {
qCDebug(TerrainTileLog) << "elevation: " << coordinate << " , in sw " << _southWest << " , ne " << _northEast;
// Get the index at resolution of 1 arc second
int indexLat = _latToDataIndex(coordinate.latitude());
int indexLon = _lonToDataIndex(coordinate.longitude());
qCDebug(TerrainTileLog) << "indexLat:indexLon" << indexLat << indexLon << "elevation" << _data[indexLat][indexLon];
return _data[indexLat][indexLon];
} else {
qCDebug(TerrainTileLog) << "Asking for elevation, but no valid data.";
return -1.0;
}
}
QGeoCoordinate TerrainTile::centerCoordinate(void) const
{
return _southWest.atDistanceAndAzimuth(_southWest.distanceTo(_northEast) / 2.0, _southWest.azimuthTo(_northEast));
}
int TerrainTile::_latToDataIndex(double latitude) const int TerrainTile::_latToDataIndex(double latitude) const
{ {
......
...@@ -26,6 +26,13 @@ public: ...@@ -26,6 +26,13 @@ public:
*/ */
TerrainTile(QJsonDocument document); TerrainTile(QJsonDocument document);
/**
* Constructor from serialized elevation data (either from file or web)
*
* @param document
*/
TerrainTile(QByteArray byteArray);
/** /**
* Check for whether a coordinate lies within this tile * Check for whether a coordinate lies within this tile
* *
...@@ -77,6 +84,13 @@ public: ...@@ -77,6 +84,13 @@ public:
*/ */
QGeoCoordinate centerCoordinate(void) const; QGeoCoordinate centerCoordinate(void) const;
/**
* Serialize data
*
* @return serialized data
*/
static QByteArray serialize(QJsonDocument document);
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;
...@@ -84,11 +98,11 @@ private: ...@@ -84,11 +98,11 @@ private:
QGeoCoordinate _southWest; /// South west corner of the tile QGeoCoordinate _southWest; /// South west corner of the tile
QGeoCoordinate _northEast; /// North east corner of the tile QGeoCoordinate _northEast; /// North east corner of the tile
float _minElevation; /// Minimum elevation in tile int _minElevation; /// Minimum elevation in tile
float _maxElevation; /// Maximum elevation in tile int _maxElevation; /// Maximum elevation in tile
float _avgElevation; /// Average elevation of the tile double _avgElevation; /// Average elevation of the tile
float** _data; /// 2D elevation data array double** _data; /// 2D elevation data array
int _gridSizeLat; /// data grid size in latitude direction int _gridSizeLat; /// data grid size in latitude direction
int _gridSizeLon; /// data grid size in longitude direction int _gridSizeLon; /// data grid size in longitude direction
bool _isValid; /// data loaded is valid bool _isValid; /// data loaded is valid
......
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