diff --git a/src/common/dem.cpp b/src/common/dem.cpp index a45c3b7f..6cc8f644 100644 --- a/src/common/dem.cpp +++ b/src/common/dem.cpp @@ -20,12 +20,16 @@ #include "rectc.h" #include "dem.h" -#define SRTM3_SAMPLES 1201 -#define SRTM1_SAMPLES 3601 -#define SRTM05_SAMPLES 7201 -#define SRTM_SIZE(samples) \ - ((samples) * (samples) * 2) +static unsigned int isqrt(unsigned int x) +{ + unsigned int r = 0; + + while ((r + 1) * (r + 1) <= x) + r++; + + return r; +} static double interpolate(double dx, double dy, double p0, double p1, double p2, double p3) @@ -34,42 +38,21 @@ static double interpolate(double dx, double dy, double p0, double p1, double p2, + p2 * dy * (1.0 - dx) + p3 * dx * dy; } -static double value(int col, int row, int samples, const QByteArray *data) +static double value(int col, int row, int samples, const QByteArray &data) { int pos = ((samples - 1 - row) * samples + col) * 2; - qint16 val = qFromBigEndian(*((const qint16*)(data->constData() + pos))); + qint16 val = qFromBigEndian(*((const qint16*)(data.constData() + pos))); return (val == -32768) ? NAN : val; } -static double height(const Coordinates &c, const QByteArray *data) -{ - int samples; - - if (data->size() == SRTM_SIZE(SRTM3_SAMPLES)) - samples = SRTM3_SAMPLES; - else if (data->size() == SRTM_SIZE(SRTM1_SAMPLES)) - samples = SRTM1_SAMPLES; - else if (data->size() == SRTM_SIZE(SRTM05_SAMPLES)) - samples = SRTM05_SAMPLES; - else - return NAN; - - double lat = (c.lat() - floor(c.lat())) * (samples - 1); - double lon = (c.lon() - floor(c.lon())) * (samples - 1); - int row = (int)lat; - int col = (int)lon; - - double p0 = value(col, row, samples, data); - double p1 = value(col + 1, row, samples, data); - double p2 = value(col, row + 1, samples, data); - double p3 = value(col + 1, row + 1, samples, data); - - return interpolate(lon - col, lat - row, p0, p1, p2, p3); -} - QMutex DEM::_lock; +DEM::Entry::Entry(const QByteArray &data) : _data(data) +{ + _samples = isqrt(_data.size() / 2); +} + QString DEM::Tile::latStr() const { const char ns = (_lat >= 0) ? 'N' : 'S'; @@ -105,7 +88,25 @@ void DEM::clearCache() _data.clear(); } -QByteArray *DEM::loadTile(const Tile &tile) +double DEM::height(const Coordinates &c, const Entry *e) +{ + if (!e->samples()) + return NAN; + + double lat = (c.lat() - floor(c.lat())) * (e->samples() - 1); + double lon = (c.lon() - floor(c.lon())) * (e->samples() - 1); + int row = (int)lat; + int col = (int)lon; + + double p0 = value(col, row, e->samples(), e->data()); + double p1 = value(col + 1, row, e->samples(), e->data()); + double p2 = value(col, row + 1, e->samples(), e->data()); + double p3 = value(col + 1, row + 1, e->samples(), e->data()); + + return interpolate(lon - col, lat - row, p0, p1, p2, p3); +} + +DEM::Entry *DEM::loadTile(const Tile &tile) { QString bn(tile.baseName()); QString fn(QDir(_dir).absoluteFilePath(bn)); @@ -113,15 +114,15 @@ QByteArray *DEM::loadTile(const Tile &tile) if (QFileInfo::exists(zn)) { QZipReader zip(zn, QIODevice::ReadOnly); - return new QByteArray(zip.fileData(bn)); + return new Entry(zip.fileData(bn)); } else { QFile file(fn); if (!file.open(QIODevice::ReadOnly)) { qWarning("%s: %s", qPrintable(file.fileName()), qPrintable(file.errorString())); - return new QByteArray(); + return new Entry(); } else - return new QByteArray(file.readAll()); + return new Entry(file.readAll()); } } @@ -131,15 +132,15 @@ double DEM::elevation(const Coordinates &c) return NAN; Tile tile(floor(c.lon()), floor(c.lat())); - QByteArray *ba = _data.object(tile); + Entry *e = _data.object(tile); double ele; - if (!ba) { - ba = loadTile(tile); - ele = height(c, ba); - _data.insert(tile, ba, ba->size()); + if (!e) { + e = loadTile(tile); + ele = height(c, e); + _data.insert(tile, e, e->data().size()); } else - ele = height(c, ba); + ele = height(c, e); return ele; } diff --git a/src/common/dem.h b/src/common/dem.h index bccee11f..a0747ddd 100644 --- a/src/common/dem.h +++ b/src/common/dem.h @@ -44,9 +44,23 @@ public: static QList tiles(); private: - typedef QCache TileCache; + class Entry { + public: + Entry() : _samples(0) {} + Entry(const QByteArray &data); - static QByteArray *loadTile(const Tile &tile); + const QByteArray &data() const {return _data;} + int samples() const {return _samples;} + + private: + unsigned int _samples; + QByteArray _data; + }; + + typedef QCache TileCache; + + static double height(const Coordinates &c, const Entry *e); + static Entry *loadTile(const Tile &tile); static QString _dir; static TileCache _data;