TerrainTile.cc 6.36 KB
Newer Older
Andreas Bircher's avatar
Andreas Bircher committed
1 2 3 4 5 6 7 8 9
#include "TerrainTile.h"
#include "JsonHelper.h"

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>

QGC_LOGGING_CATEGORY(TerrainTileLog, "TerrainTileLog")

Andreas Bircher's avatar
Andreas Bircher committed
10
const double TerrainTile::_srtm1TileSize        = 0.025;
Andreas Bircher's avatar
Andreas Bircher committed
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
const char*  TerrainTile::_jsonStatusKey        = "status";
const char*  TerrainTile::_jsonDataKey          = "data";
const char*  TerrainTile::_jsonBoundsKey        = "bounds";
const char*  TerrainTile::_jsonSouthWestKey     = "sw";
const char*  TerrainTile::_jsonNorthEastKey     = "ne";
const char*  TerrainTile::_jsonStatsKey         = "stats";
const char*  TerrainTile::_jsonMaxElevationKey  = "max";
const char*  TerrainTile::_jsonMinElevationKey  = "min";
const char*  TerrainTile::_jsonAvgElevationKey  = "avg";
const char*  TerrainTile::_jsonCarpetKey        = "carpet";

TerrainTile::TerrainTile()
    : _minElevation(-1.0)
    , _maxElevation(-1.0)
    , _avgElevation(-1.0)
    , _isValid(false)
{

}

TerrainTile::~TerrainTile()
{
}

Andreas Bircher's avatar
Andreas Bircher committed
35
TerrainTile::TerrainTile(QJsonDocument document)
Andreas Bircher's avatar
Andreas Bircher committed
36 37 38 39 40
    : _minElevation(-1.0)
    , _maxElevation(-1.0)
    , _avgElevation(-1.0)
    , _isValid(false)
{
Andreas Bircher's avatar
Andreas Bircher committed
41
    if (!document.isObject()) {
Andreas Bircher's avatar
Andreas Bircher committed
42 43 44
        qCDebug(TerrainTileLog) << "Terrain tile json doc is no object";
        return;
    }
Andreas Bircher's avatar
Andreas Bircher committed
45
    QJsonObject rootObject = document.object();
Andreas Bircher's avatar
Andreas Bircher committed
46 47 48 49 50 51 52 53

    QString errorString;
    QList<JsonHelper::KeyValidateInfo> rootVersionKeyInfoList = {
        { _jsonStatusKey, QJsonValue::String, true },
        { _jsonDataKey, QJsonValue::String, true },
    };
    if (!JsonHelper::validateKeys(rootObject, rootVersionKeyInfoList, errorString)) {
        qCDebug(TerrainTileLog) << "Error in reading json: " << errorString;
Andreas Bircher's avatar
Andreas Bircher committed
54
        return;
Andreas Bircher's avatar
Andreas Bircher committed
55 56 57 58 59 60 61 62 63 64 65 66 67 68
    }

    if (rootObject[_jsonStatusKey].toString() != "success") {
        qCDebug(TerrainTileLog) << "Invalid terrain tile.";
        return;
    }
    const QJsonObject& dataObject = rootObject[_jsonDataKey].toObject();
    QList<JsonHelper::KeyValidateInfo> dataVersionKeyInfoList = {
        { _jsonBoundsKey, QJsonValue::Object, true },
        { _jsonStatsKey, QJsonValue::Object, true },
        { _jsonCarpetKey, QJsonValue::Array, true },
    };
    if (!JsonHelper::validateKeys(dataObject, dataVersionKeyInfoList, errorString)) {
        qCDebug(TerrainTileLog) << "Error in reading json: " << errorString;
Andreas Bircher's avatar
Andreas Bircher committed
69
        return;
Andreas Bircher's avatar
Andreas Bircher committed
70 71 72 73 74 75 76 77 78 79
    }

    // Bounds
    const QJsonObject& boundsObject = dataObject[_jsonBoundsKey].toObject();
    QList<JsonHelper::KeyValidateInfo> boundsVersionKeyInfoList = {
        { _jsonSouthWestKey, QJsonValue::Array, true },
        { _jsonNorthEastKey, QJsonValue::Array, true },
    };
    if (!JsonHelper::validateKeys(boundsObject, boundsVersionKeyInfoList, errorString)) {
        qCDebug(TerrainTileLog) << "Error in reading json: " << errorString;
Andreas Bircher's avatar
Andreas Bircher committed
80
        return;
Andreas Bircher's avatar
Andreas Bircher committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
    }
    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;
    }
    _southWest.setLatitude(swArray[0].toDouble());
    _southWest.setLongitude(swArray[1].toDouble());
    _northEast.setLatitude(neArray[0].toDouble());
    _northEast.setLongitude(neArray[1].toDouble());

    // Stats
    const QJsonObject& statsObject = dataObject[_jsonBoundsKey].toObject();
    QList<JsonHelper::KeyValidateInfo> statsVersionKeyInfoList = {
        { _jsonMaxElevationKey, QJsonValue::Double, true },
        { _jsonMinElevationKey, QJsonValue::Double, true },
        { _jsonAvgElevationKey, QJsonValue::Double, true },
    };
    if (!JsonHelper::validateKeys(statsObject, statsVersionKeyInfoList, errorString)) {
        qCDebug(TerrainTileLog) << "Error in reading json: " << errorString;
Andreas Bircher's avatar
Andreas Bircher committed
102
        return;
Andreas Bircher's avatar
Andreas Bircher committed
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
    }
    _maxElevation = statsObject[_jsonMaxElevationKey].toInt();
    _minElevation = statsObject[_jsonMinElevationKey].toInt();
    _avgElevation = statsObject[_jsonAvgElevationKey].toInt();

    // Carpet
    const QJsonArray& carpetArray = dataObject[_jsonCarpetKey].toArray();
    if (carpetArray.count() != _gridSize) {
        qCDebug(TerrainTileLog) << "Expected array of " << _gridSize << ", instead got " << carpetArray.count();
        return;
    }
    for (int i = 0; i < _gridSize; i++) {
        const QJsonArray& row = carpetArray[i].toArray();
        if (row.count() != _gridSize) {
            qCDebug(TerrainTileLog) << "Expected row array of " << _gridSize << ", instead got " << row.count();
            return;
        }
        for (int j = 0; j < _gridSize; j++) {
            _data[i][j] = row[j].toDouble();
        }
    }
    _isValid = true;
}

Andreas Bircher's avatar
Andreas Bircher committed
127
bool TerrainTile::isIn(const QGeoCoordinate& coordinate) const
Andreas Bircher's avatar
Andreas Bircher committed
128 129 130 131 132
{
    if (!_isValid) {
        qCDebug(TerrainTileLog) << "isIn requested, but tile not valid";
        return false;
    }
Andreas Bircher's avatar
Andreas Bircher committed
133 134 135
    bool ret = coordinate.latitude() >= _southWest.longitude() && coordinate.longitude() >= _southWest.longitude() &&
               coordinate.latitude() <= _northEast.longitude() && coordinate.longitude() <= _northEast.longitude();
    qCDebug(TerrainTileLog) << "Checking isIn: " << coordinate << " , in sw " << _southWest << " , ne " << _northEast << ": " << ret;
Andreas Bircher's avatar
Andreas Bircher committed
136 137 138
    return ret;
}

Andreas Bircher's avatar
Andreas Bircher committed
139
float TerrainTile::elevation(const QGeoCoordinate& coordinate) const
Andreas Bircher's avatar
Andreas Bircher committed
140 141
{
    if (_isValid) {
Andreas Bircher's avatar
Andreas Bircher committed
142
        qCDebug(TerrainTileLog) << "elevation: " << coordinate << " , in sw " << _southWest << " , ne " << _northEast;
Andreas Bircher's avatar
Andreas Bircher committed
143
        // Get the index at resolution of 1 arc second
Andreas Bircher's avatar
Andreas Bircher committed
144 145 146
        int indexLat = std::round((coordinate.latitude() - _southWest.latitude()) * _gridSize / _srtm1TileSize);
        int indexLon = std::round((coordinate.longitude() - _southWest.longitude()) * _gridSize / _srtm1TileSize);
        qCDebug(TerrainTileLog) << "indexLat:indexLon" << indexLat << indexLon; // TODO (birchera): Move this down to the next debug output, once this is all properly working.
Andreas Bircher's avatar
Andreas Bircher committed
147 148 149 150
        Q_ASSERT(indexLat >= 0);
        Q_ASSERT(indexLat < _gridSize);
        Q_ASSERT(indexLon >= 0);
        Q_ASSERT(indexLon < _gridSize);
Andreas Bircher's avatar
Andreas Bircher committed
151
        qCDebug(TerrainTileLog) << "elevation" << _data[indexLat][indexLon];
Andreas Bircher's avatar
Andreas Bircher committed
152 153 154 155 156 157
        return _data[indexLat][indexLon];
    } else {
        qCDebug(TerrainTileLog) << "Asking for elevation, but no valid data.";
        return -1.0;
    }
}
Andreas Bircher's avatar
Andreas Bircher committed
158 159 160 161 162

QGeoCoordinate TerrainTile::centerCoordinate(void) const
{
    return _southWest.atDistanceAndAzimuth(_southWest.distanceTo(_northEast) / 2.0, _southWest.azimuthTo(_northEast));
}