1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-30 22:51:16 +01:00

Use a QCache rather than a QMap to prevent memory exhaustion

This commit is contained in:
Martin Tůma 2019-01-22 23:00:02 +01:00
parent 87f0448ac7
commit 98c4fb2037
2 changed files with 41 additions and 34 deletions

View File

@ -4,13 +4,13 @@
#include "common/coordinates.h" #include "common/coordinates.h"
#include "dem.h" #include "dem.h"
#define SRTM3_SAMPLES 1201 #define SRTM3_SAMPLES 1201
#define SRTM1_SAMPLES 3601 #define SRTM1_SAMPLES 3601
#define SRTM_SIZE(samples) \ #define SRTM_SIZE(samples) \
((samples) * (samples) * 2) ((samples) * (samples) * 2)
static qreal interpolate(qreal dx, qreal dy, qreal p0, qreal p1, qreal p2, static qreal interpolate(qreal dx, qreal dy, qreal p0, qreal p1, qreal p2,
qreal p3) qreal p3)
{ {
@ -18,21 +18,21 @@ static qreal interpolate(qreal dx, qreal dy, qreal p0, qreal p1, qreal p2,
+ p3 * dx * dy; + p3 * dx * dy;
} }
static qreal value(int col, int row, int samples, const QByteArray data) static qreal value(int col, int row, int samples, const QByteArray *data)
{ {
int pos = ((samples - 1 - row) * samples + col) * 2; 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; return (val == -32768) ? NAN : val;
} }
static qreal height(const Coordinates &c, const QByteArray data) static qreal height(const Coordinates &c, const QByteArray *data)
{ {
int samples; int samples;
if (data.size() == SRTM_SIZE(SRTM3_SAMPLES)) if (data->size() == SRTM_SIZE(SRTM3_SAMPLES))
samples = SRTM3_SAMPLES; samples = SRTM3_SAMPLES;
else if (data.size() == SRTM_SIZE(SRTM1_SAMPLES)) else if (data->size() == SRTM_SIZE(SRTM1_SAMPLES))
samples = SRTM1_SAMPLES; samples = SRTM1_SAMPLES;
else else
return NAN; return NAN;
@ -52,16 +52,16 @@ static qreal height(const Coordinates &c, const QByteArray data)
QString DEM::_dir; QString DEM::_dir;
QMap<DEM::Key, QByteArray> DEM::_data; QCache<DEM::Key, QByteArray> DEM::_data;
QString DEM::fileName(const Key &key) QString DEM::fileName(const Key &key)
{ {
const char ns = (key.lat >= 0) ? 'N' : 'S'; const char ns = (key.lat() >= 0) ? 'N' : 'S';
const char ew = (key.lon >= 0) ? 'E' : 'W'; const char ew = (key.lon() >= 0) ? 'E' : 'W';
QString basename = QString("%1%2%3%4.hgt").arg(ns) QString basename = QString("%1%2%3%4.hgt").arg(ns)
.arg(qAbs(key.lat), 2, 10, QChar('0')).arg(ew) .arg(qAbs(key.lat()), 2, 10, QChar('0')).arg(ew)
.arg(qAbs(key.lon), 3, 10, QChar('0')); .arg(qAbs(key.lon()), 3, 10, QChar('0'));
return QDir(_dir).absoluteFilePath(basename); return QDir(_dir).absoluteFilePath(basename);
} }
@ -77,18 +77,19 @@ qreal DEM::elevation(const Coordinates &c)
Key k((int)c.lon(), (int)c.lat()); Key k((int)c.lon(), (int)c.lat());
QMap<Key, QByteArray>::const_iterator it(_data.find(k)); QByteArray *ba = _data[k];
if (it == _data.constEnd()) { if (!ba) {
QFile file(fileName(k)); QFile file(fileName(k));
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly)) {
qWarning("%s: %s", qPrintable(file.fileName()), qWarning("%s: %s", qPrintable(file.fileName()),
qPrintable(file.errorString())); qPrintable(file.errorString()));
_data.insert(k, QByteArray()); _data.insert(k, new QByteArray());
return NAN; return NAN;
} else { } else {
it = _data.insert(k, file.readAll()); ba = new QByteArray(file.readAll());
return height(c, *it); _data.insert(k, ba);
return height(c, ba);
} }
} else } else
return height(c, *it); return height(c, ba);
} }

View File

@ -2,7 +2,7 @@
#define DEM_H #define DEM_H
#include <QString> #include <QString>
#include <QMap> #include <QCache>
#include <QByteArray> #include <QByteArray>
class QString; class QString;
@ -10,32 +10,38 @@ class Coordinates;
class DEM class DEM
{ {
public:
static void setDir(const QString &path);
static qreal elevation(const Coordinates &c);
private: private:
struct Key { class Key {
int lon; public:
int lat; Key(int lon, int lat) : _lon(lon), _lat(lat) {}
Key(int lon, int lat) : lon(lon), lat(lat) {} int lon() const {return _lon;}
int lat() const {return _lat;}
bool operator<(const Key &other) const bool operator==(const Key &other) const
{ {
if (lon < other.lon) return (_lon == other._lon && _lat == other._lat);
return true;
else if (lon > other.lon)
return false;
else
return (lat < other.lat);
} }
private:
int _lon, _lat;
}; };
static QString fileName(const Key &key); static QString fileName(const Key &key);
static QString _dir; static QString _dir;
static QMap<Key, QByteArray> _data; static QCache<Key, QByteArray> _data;
public:
static void setDir(const QString &path);
static qreal elevation(const Coordinates &c);
friend uint qHash(const Key &key);
}; };
inline uint qHash(const DEM::Key &key)
{
return (key.lon() ^ key.lat());
}
#endif // DEM_H #endif // DEM_H