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

first implementation of binary representation of elevation data

parent 32a35ac9
......@@ -51,6 +51,10 @@
#include <QtLocation/private/qgeotilespec_p.h>
#include <QtNetwork/QNetworkAccessManager>
#include <QFile>
#include "TerrainTile.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
int QGeoTiledMapReplyQGC::_requestCount = 0;
......@@ -121,8 +125,24 @@ QGeoTiledMapReplyQGC::networkReplyFinished()
return;
}
QByteArray a = _reply->readAll();
setMapImageData(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()) {
setMapImageFormat(format);
getQGCMapEngine()->cacheTile((UrlFactory::MapType)tileSpec().mapId(), tileSpec().x(), tileSpec().y(), tileSpec().zoom(), a, format);
......
......@@ -128,17 +128,7 @@ void TerrainBatchManager::_fetchedTile()
// parse received data and insert into hash table
QByteArray responseBytes = reply->mapImageData();
QJsonParseError parseError;
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);
TerrainTile* terrainTile = new TerrainTile(responseBytes);
if (terrainTile->isValid()) {
_tilesMutex.lock();
if (!_tiles.contains(hash)) {
......
......@@ -5,6 +5,7 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDataStream>
QGC_LOGGING_CATEGORY(TerrainTileLog, "TerrainTileLog")
......@@ -42,15 +43,83 @@ TerrainTile::~TerrainTile()
}
}
TerrainTile::TerrainTile(QJsonDocument document)
TerrainTile::TerrainTile(QByteArray byteArray)
: _minElevation(-1.0)
, _maxElevation(-1.0)
, _avgElevation(-1.0)
, _data(NULL)
, _gridSizeLat(-1)
, _gridSizeLon(-1)
, _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()) {
qCDebug(TerrainTileLog) << "Terrain tile json doc is no object";
return;
QByteArray emptyArray;
return emptyArray;
}
QJsonObject rootObject = document.object();
......@@ -61,12 +130,14 @@ TerrainTile::TerrainTile(QJsonDocument document)
};
if (!JsonHelper::validateKeys(rootObject, rootVersionKeyInfoList, errorString)) {
qCDebug(TerrainTileLog) << "Error in reading json: " << errorString;
return;
QByteArray emptyArray;
return emptyArray;
}
if (rootObject[_jsonStatusKey].toString() != "success") {
qCDebug(TerrainTileLog) << "Invalid terrain tile.";
return;
QByteArray emptyArray;
return emptyArray;
}
const QJsonObject& dataObject = rootObject[_jsonDataKey].toObject();
QList<JsonHelper::KeyValidateInfo> dataVersionKeyInfoList = {
......@@ -76,7 +147,8 @@ TerrainTile::TerrainTile(QJsonDocument document)
};
if (!JsonHelper::validateKeys(dataObject, dataVersionKeyInfoList, errorString)) {
qCDebug(TerrainTileLog) << "Error in reading json: " << errorString;
return;
QByteArray emptyArray;
return emptyArray;
}
// Bounds
......@@ -87,18 +159,18 @@ TerrainTile::TerrainTile(QJsonDocument document)
};
if (!JsonHelper::validateKeys(boundsObject, boundsVersionKeyInfoList, errorString)) {
qCDebug(TerrainTileLog) << "Error in reading json: " << errorString;
return;
QByteArray emptyArray;
return emptyArray;
}
const QJsonArray& swArray = boundsObject[_jsonSouthWestKey].toArray();
const QJsonArray& neArray = boundsObject[_jsonNorthEastKey].toArray();
if (swArray.count() < 2 || neArray.count() < 2 ) {
qCDebug(TerrainTileLog) << "Incomplete bounding location";
return;
QByteArray emptyArray;
return emptyArray;
}
_southWest.setLatitude(swArray[0].toDouble());
_southWest.setLongitude(swArray[1].toDouble());
_northEast.setLatitude(neArray[0].toDouble());
_northEast.setLongitude(neArray[1].toDouble());
stream << QGeoCoordinate(swArray[0].toDouble(), swArray[1].toDouble());
stream << QGeoCoordinate(neArray[0].toDouble(), neArray[1].toDouble());
// Stats
const QJsonObject& statsObject = dataObject[_jsonStatsKey].toObject();
......@@ -109,70 +181,39 @@ TerrainTile::TerrainTile(QJsonDocument document)
};
if (!JsonHelper::validateKeys(statsObject, statsVersionKeyInfoList, errorString)) {
qCDebug(TerrainTileLog) << "Error in reading json: " << errorString;
return;
QByteArray emptyArray;
return emptyArray;
}
_maxElevation = statsObject[_jsonMaxElevationKey].toInt();
_minElevation = statsObject[_jsonMinElevationKey].toInt();
_avgElevation = statsObject[_jsonAvgElevationKey].toInt();
stream << statsObject[_jsonMaxElevationKey].toInt();
stream << statsObject[_jsonMinElevationKey].toInt();
stream << statsObject[_jsonAvgElevationKey].toDouble();
// Carpet
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();
for (int i = 0; i < _gridSizeLat; i++) {
for (int i = 0; i < gridSizeLat; i++) {
const QJsonArray& row = carpetArray[i].toArray();
if (i == 0) {
_gridSizeLon = row.count();
gridSizeLon = row.count();
stream << gridSizeLon;
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) {
qCDebug(TerrainTileLog) << "Expected row array of " << _gridSizeLon << ", instead got " << row.count();
return;
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++) {
_data[i][j] = row[j].toDouble();
for (int j = 0; j < gridSizeLon; j++) {
stream << row[j].toDouble();
}
}
_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;
return byteArray;
}
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
{
......
......@@ -26,6 +26,13 @@ public:
*/
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
*
......@@ -77,6 +84,13 @@ public:
*/
QGeoCoordinate centerCoordinate(void) const;
/**
* Serialize data
*
* @return serialized data
*/
static QByteArray serialize(QJsonDocument document);
private:
inline int _latToDataIndex(double latitude) const;
inline int _lonToDataIndex(double longitude) const;
......@@ -84,11 +98,11 @@ private:
QGeoCoordinate _southWest; /// South west corner of the tile
QGeoCoordinate _northEast; /// North east corner of the tile
float _minElevation; /// Minimum elevation in tile
float _maxElevation; /// Maximum elevation in tile
float _avgElevation; /// Average elevation of the tile
int _minElevation; /// Minimum elevation in tile
int _maxElevation; /// Maximum elevation in 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 _gridSizeLon; /// data grid size in longitude direction
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